scout-ai 1.2.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +138 -50
  3. data/README.md +171 -290
  4. data/Rakefile +17 -1
  5. data/VERSION +1 -1
  6. data/doc/Improvements.md +325 -0
  7. data/doc/StartHere.md +110 -0
  8. data/doc/developer/Architecture.md +126 -0
  9. data/doc/developer/Backends.md +199 -0
  10. data/doc/developer/ChatLifecycle.md +183 -0
  11. data/doc/developer/DelegationInternals.md +295 -0
  12. data/doc/developer/DesignPrinciples.md +245 -0
  13. data/doc/developer/PromptProcessing.md +292 -0
  14. data/doc/developer/Provenance.md +317 -0
  15. data/doc/user/BuildingAgents.md +345 -0
  16. data/doc/user/Cookbook.md +333 -0
  17. data/doc/user/CoreConcepts.md +181 -0
  18. data/doc/user/Delegation.md +191 -0
  19. data/doc/user/GettingStarted.md +159 -0
  20. data/doc/user/ManagingContext.md +163 -0
  21. data/doc/user/MultiAgentWorkflows.md +256 -0
  22. data/doc/user/Python.md +159 -0
  23. data/doc/user/RunningInference.md +200 -0
  24. data/doc/user/ToolCalling.md +193 -0
  25. data/doc/user/WritingChats.md +197 -0
  26. data/lib/scout/llm/agent/chat.rb +61 -11
  27. data/lib/scout/llm/agent/delegate.rb +274 -65
  28. data/lib/scout/llm/agent/iterate.rb +2 -2
  29. data/lib/scout/llm/agent/save.rb +273 -0
  30. data/lib/scout/llm/agent/workflow.rb +164 -0
  31. data/lib/scout/llm/agent.rb +86 -61
  32. data/lib/scout/llm/ask.rb +62 -17
  33. data/lib/scout/llm/backends/anthropic.rb +9 -2
  34. data/lib/scout/llm/backends/bedrock.rb +15 -3
  35. data/lib/scout/llm/backends/default.rb +183 -99
  36. data/lib/scout/llm/backends/glm.rb +58 -0
  37. data/lib/scout/llm/backends/huggingface.rb +196 -26
  38. data/lib/scout/llm/backends/ollama.rb +13 -1
  39. data/lib/scout/llm/backends/openai.rb +0 -2
  40. data/lib/scout/llm/backends/openwebui.rb +20 -13
  41. data/lib/scout/llm/backends/relay.rb +22 -22
  42. data/lib/scout/llm/backends/responses.rb +1 -1
  43. data/lib/scout/llm/chat/agent_meta.rb +264 -0
  44. data/lib/scout/llm/chat/annotation.rb +39 -10
  45. data/lib/scout/llm/chat/parse.rb +28 -6
  46. data/lib/scout/llm/chat/persist.rb +25 -0
  47. data/lib/scout/llm/chat/process/clear.rb +41 -6
  48. data/lib/scout/llm/chat/process/files.rb +21 -6
  49. data/lib/scout/llm/chat/process/meta.rb +421 -34
  50. data/lib/scout/llm/chat/process/options.rb +21 -1
  51. data/lib/scout/llm/chat/process/tools.rb +56 -15
  52. data/lib/scout/llm/chat/process.rb +4 -0
  53. data/lib/scout/llm/chat/prompt/shorten_tools.rb +125 -0
  54. data/lib/scout/llm/chat/prompt/shorten_tools_epoch.rb +365 -0
  55. data/lib/scout/llm/chat/prompt.rb +48 -0
  56. data/lib/scout/llm/chat/provenance.rb +775 -0
  57. data/lib/scout/llm/chat/tool_calls.rb +76 -0
  58. data/lib/scout/llm/chat.rb +18 -2
  59. data/lib/scout/llm/embed.rb +11 -3
  60. data/lib/scout/llm/image.rb +86 -0
  61. data/lib/scout/llm/mcp.rb +10 -2
  62. data/lib/scout/llm/rag.rb +3 -3
  63. data/lib/scout/llm/tools/call.rb +160 -11
  64. data/lib/scout/llm/tools/knowledge_base.rb +1 -1
  65. data/lib/scout/llm/tools/workflow.rb +32 -16
  66. data/lib/scout/model/python/huggingface/causal.rb +23 -5
  67. data/lib/scout/model/python/huggingface.rb +2 -1
  68. data/lib/scout-ai.rb +1 -0
  69. data/python/README.md +197 -14
  70. data/python/scout_ai/huggingface/eval.py +245 -34
  71. data/python/tests/test_huggingface_eval.py +58 -0
  72. data/research/ChatAnalyst-required-changes.md +167 -0
  73. data/research/agent-delegation-analysis.md +810 -0
  74. data/research/agent-meta-provenance-integration-plan.md +622 -0
  75. data/research/agent-workflow-analysis.md +1120 -0
  76. data/research/backends-analysis.md +836 -0
  77. data/research/chat-core-analysis.md +946 -0
  78. data/research/chatanalyst-provenance/00-baseline.md +30 -0
  79. data/research/chatanalyst-provenance/01-repo-map.md +60 -0
  80. data/research/chatanalyst-provenance/02-event-reconstruction.md +55 -0
  81. data/research/chatanalyst-provenance/03-duplication-evidence.md +45 -0
  82. data/research/chatanalyst-provenance/04-tooling-root-cause.md +57 -0
  83. data/research/chatanalyst-provenance/05-fix-plan.md +46 -0
  84. data/research/chatanalyst-provenance/07-critic-review.md +25 -0
  85. data/research/chatanalyst-provenance/final-report.md +45 -0
  86. data/research/chatanalyst-provenance/resumption.md +37 -0
  87. data/research/coding-philosophy-analysis.md +928 -0
  88. data/research/commands-analysis.md +947 -0
  89. data/research/multi-agent-patterns-analysis.md +853 -0
  90. data/research/prompt-strategies-analysis.md +630 -0
  91. data/research/prov-verbosity-fix-notes.md +77 -0
  92. data/research/provenance-analysis.md +469 -0
  93. data/research/provenance-navigation-design.md +640 -0
  94. data/research/synthesis-report.md +487 -0
  95. data/research/tools-system-analysis.md +779 -0
  96. data/scout-ai.gemspec +100 -11
  97. data/scout_commands/agent/ask +13 -3
  98. data/scout_commands/agent/kb +2 -0
  99. data/scout_commands/llm/ask +11 -4
  100. data/scout_commands/llm/md +76 -0
  101. data/scout_commands/llm/process_queries +48 -0
  102. data/scout_commands/llm/prov +602 -0
  103. data/scout_commands/llm/word +71 -0
  104. data/scout_commands/workflow/mcp +43 -0
  105. data/share/word/reference.docx +0 -0
  106. data/test/etc/AI/mock.yaml +11 -0
  107. data/test/fixtures/backends/anthropic.json +19 -0
  108. data/test/fixtures/backends/anthropic_tool_use.json +24 -0
  109. data/test/fixtures/backends/bedrock.json +8 -0
  110. data/test/fixtures/backends/bedrock_embedding.json +3 -0
  111. data/test/fixtures/backends/bedrock_tool_use.json +17 -0
  112. data/test/fixtures/backends/ollama.json +16 -0
  113. data/test/fixtures/backends/ollama_tool_call.json +27 -0
  114. data/test/fixtures/backends/openai_chat.json +21 -0
  115. data/test/fixtures/backends/openai_chat_tool_call.json +31 -0
  116. data/test/fixtures/backends/responses.json +33 -0
  117. data/test/fixtures/backends/responses_tool_call.json +28 -0
  118. data/test/integration/README.md +32 -0
  119. data/test/integration/scout/llm/backends/test_endpoints.rb +34 -0
  120. data/test/integration/scout/llm/backends/test_openwebui.rb +61 -0
  121. data/test/integration/scout/llm/backends/test_relay.rb +52 -0
  122. data/test/integration/scout/llm/test_infrastructure.rb +74 -0
  123. data/test/{scout → integration/scout}/llm/test_mcp.rb +1 -1
  124. data/test/integration/scout/llm/tools/test_mcp.rb +42 -0
  125. data/test/integration/scout/model/test_base.rb +91 -0
  126. data/test/scout/llm/agent/test_chat.rb +8 -2
  127. data/test/scout/llm/agent/test_save.rb +413 -0
  128. data/test/scout/llm/agent/test_workflow.rb +110 -0
  129. data/test/scout/llm/backends/test_anthropic.rb +93 -10
  130. data/test/scout/llm/backends/test_bedrock.rb +118 -2
  131. data/test/scout/llm/backends/test_huggingface.rb +137 -42
  132. data/test/scout/llm/backends/test_ollama.rb +70 -20
  133. data/test/scout/llm/backends/test_openwebui.rb +42 -40
  134. data/test/scout/llm/backends/test_relay.rb +4 -2
  135. data/test/scout/llm/chat/agent_meta_fixtures.rb +131 -0
  136. data/test/scout/llm/chat/process/test_meta.rb +518 -0
  137. data/test/scout/llm/chat/process/test_normalize_usage.rb +183 -0
  138. data/test/scout/llm/chat/test_agent_meta.rb +357 -0
  139. data/test/scout/llm/chat/test_agent_meta_provenance.rb +467 -0
  140. data/test/scout/llm/chat/test_agent_meta_tokens.rb +594 -0
  141. data/test/scout/llm/chat/test_parse.rb +70 -15
  142. data/test/scout/llm/chat/test_prov_cli.rb +274 -0
  143. data/test/scout/llm/chat/test_provenance.rb +240 -0
  144. data/test/scout/llm/chat/test_tool_calls.rb +38 -0
  145. data/test/scout/llm/test_agent.rb +13 -36
  146. data/test/scout/llm/test_ask.rb +75 -52
  147. data/test/scout/llm/test_chat.rb +107 -13
  148. data/test/scout/llm/test_embed.rb +48 -0
  149. data/test/scout/llm/test_rag.rb +23 -16
  150. data/test/scout/llm/test_tools.rb +12 -1
  151. data/test/scout/llm/tools/test_knowledge_base.rb +0 -1
  152. data/test/scout/llm/tools/test_mcp.rb +5 -3
  153. data/test/scout/llm/tools/test_workflow.rb +23 -2
  154. data/test/scout/model/python/huggingface/causal/test_next_token.rb +11 -5
  155. data/test/scout/model/python/huggingface/test_causal.rb +9 -3
  156. data/test/scout/model/python/huggingface/test_classification.rb +11 -2
  157. data/test/scout/model/python/test_torch.rb +2 -0
  158. data/test/scout/model/python/torch/test_helpers.rb +4 -0
  159. data/test/scout/model/test_base.rb +4 -2
  160. data/test/support/availability.rb +231 -0
  161. data/test/support/fake_clients.rb +138 -0
  162. data/test/support/fixtures.rb +21 -0
  163. data/test/support/infrastructure_probes.rb +136 -0
  164. data/test/support/mock_backend.rb +215 -0
  165. data/test/test_helper.rb +32 -2
  166. metadata +99 -10
  167. data/doc/Agent.md +0 -327
  168. data/doc/Chat.md +0 -458
  169. data/doc/LLM.md +0 -340
  170. data/doc/RAG.md +0 -129
  171. data/scout_commands/documenter +0 -148
  172. data/test/scout/llm/backends/test_openai.rb +0 -192
  173. data/test/scout/llm/backends/test_responses.rb +0 -238
  174. data/test/scout/llm/test_parse.rb +0 -98
@@ -0,0 +1,215 @@
1
+ # Test support: LLM::Mock, an offline scripted backend.
2
+ #
3
+ # Not named test_*.rb on purpose: the Rakefile test pattern
4
+ # ('test/**/test_*.rb') must not collect this file.
5
+ #
6
+ # Registered into LLM::BACKENDS so it is reachable from LLM.ask / LLM.embed
7
+ # once the endpoint yaml selects `backend: mock`.
8
+ #
9
+ # Scripting model
10
+ # ---------------
11
+ # LLM::Mock.responses = ['an answer']
12
+ # LLM::Mock.responses = [{role: 'assistant', content: 'an answer'}]
13
+ # LLM::Mock.responses = ['first', {tool_calls: [{name: 'f', arguments: {}}]}, 'final']
14
+ # LLM::Mock.script('a') { ... } # same, resetting first
15
+ #
16
+ # Each response entry may be:
17
+ # * a String -> plain answer
18
+ # * a Hash message (role/content) -> one message
19
+ # * an Array of Hash messages -> several messages at once
20
+ # * a Hash with :tool_calls -> tool call round: the calls are
21
+ # delegated to LLM.process_calls (using options[:tools]) so the
22
+ # function_call / function_call_output messages match the real backends
23
+ # * a Proc called with (messages, options) returning any of the above
24
+ # * an Exception instance -> raised
25
+ #
26
+ # Entries replay in order; when exhausted the last entry repeats.
27
+ #
28
+ # Tool loops: the real backends return output ending in a
29
+ # function_call_output message and then re-enter `ask` with
30
+ # messages + output (Backend#chain_tools). LLM.ask dispatches to the backend
31
+ # only once, so the mock drives the same rounds internally; to keep tests
32
+ # able to assert on what the model would see next, every round is recorded
33
+ # in `.calls` with the messages accumulated so far (round 1 = the original
34
+ # messages, round 2 = messages + marriages output, ...), matching the shape
35
+ # of the repeated asks of the real backends.
36
+ #
37
+ # ScoutCoder: IndiferentHash#pretty_print takes 0 args while Ruby's PP passes
38
+ # 1, so pp-ing one of these hashes inside a test failure (assertion diffs call
39
+ # PP) raises ArgumentError and hides the real failure. Use Log.fingerprint or
40
+ # .inspect when debugging IndiferentHash values in tests instead of pp.
41
+ module LLM
42
+ module Mock
43
+ DIMENSIONS = 64
44
+
45
+ class << self
46
+ attr_accessor :responses
47
+
48
+ def script(*responses, &block)
49
+ self.reset!
50
+ @responses = responses.flatten
51
+ @setup = block if block_given?
52
+ self
53
+ end
54
+
55
+ def reset!
56
+ @responses = []
57
+ @index = 0
58
+ @calls = []
59
+ @setup = nil
60
+ @tool_definitions = {}
61
+ self
62
+ end
63
+
64
+ def calls
65
+ @calls ||= []
66
+ end
67
+
68
+ def next_response(messages = nil, options = {})
69
+ @index ||= 0
70
+ @responses = [@responses].flatten.compact
71
+ entry = @responses[@index] || @responses.last
72
+ @index += 1
73
+
74
+ if Proc === entry
75
+ entry = entry.call(messages, options)
76
+ end
77
+ entry
78
+ end
79
+
80
+ def index
81
+ @index ||= 0
82
+ end
83
+
84
+ #{{{ ask
85
+
86
+ # Tool definitions resolved for the last ask (same {name => [obj, def]}
87
+ # shape the real backends build), for assertions.
88
+ def tool_definitions
89
+ @tool_definitions ||= {}
90
+ end
91
+
92
+ def ask(messages, options = {}, &block)
93
+ messages = Chat.setup(Chat.prepare_prompt(messages)) unless Array === messages
94
+ options = IndiferentHash.setup(options.dup)
95
+
96
+ # Mirror Backend::ClassMethods: resolve tool:/kb:/association:
97
+ # directives (and explicit options[:tools]) once per ask. LLM.tools
98
+ # consumes the directive messages, so resolve before recording.
99
+ @tool_definitions = LLM::Mock.tools(messages, options)
100
+
101
+ tool_calls, response = [], []
102
+ round_messages = messages
103
+
104
+ loop do
105
+ calls << [round_messages, options]
106
+
107
+ entry = next_response(round_messages, options)
108
+
109
+ case entry
110
+ when Hash
111
+ if entry[:tool_calls]
112
+ script_calls = entry[:tool_calls].collect do |info|
113
+ info = IndiferentHash.setup(info.dup)
114
+ { name: info[:name] || info.dig(:function, :name),
115
+ arguments: info[:arguments] || info.dig(:function, :arguments) || {},
116
+ id: info[:id] || info[:call_id] || "call_#{@index}" }
117
+ end
118
+
119
+ new_calls = LLM.process_calls(tool_definitions, script_calls, &block).flatten
120
+ tool_calls.concat new_calls
121
+ # next round sees the original messages plus the tool call
122
+ # round, exactly like Backend#chain_tools does
123
+ round_messages = Chat.setup(messages + tool_calls)
124
+ next
125
+ else
126
+ response << IndiferentHash.setup(entry.dup)
127
+ end
128
+ when Array
129
+ entry.each { |m| response << IndiferentHash.setup(m.dup) }
130
+ when String
131
+ response << IndiferentHash.setup(role: :assistant, content: entry)
132
+ when nil
133
+ response << IndiferentHash.setup(role: :assistant, content: '')
134
+ else
135
+ raise Exception, entry if Exception === entry
136
+ response << IndiferentHash.setup(role: :assistant, content: entry.to_s)
137
+ end
138
+
139
+ break
140
+ end
141
+
142
+ output = (tool_calls + response).flatten
143
+
144
+ if options[:return_messages]
145
+ Chat.setup output
146
+ else
147
+ Chat.setup(output)
148
+ cleaned = Chat.clean(output)
149
+ return '' if cleaned.nil? || cleaned.empty?
150
+ cleaned.last[:content]
151
+ end
152
+ end
153
+
154
+ # Mirrors Backend::ClassMethods#tools: explicit options[:tools] plus the
155
+ # tool:/kb:/association: directives resolved from the messages
156
+ # (LLM.tools / LLM.associations -> Chat.tools / Chat.associations), so a
157
+ # scripted tool-call round exercises the same object/definition pairing
158
+ # the real backends use ({name => [obj, definition]}).
159
+ #
160
+ # ScoutCoder: 'tool:'/'association:'/'kb:' chat directives are NOT
161
+ # resolved by LLM.ask itself; each backend's #tools(messages, options)
162
+ # does it, and it *deletes* options[:tools] while at it. A custom backend
163
+ # registered in LLM::BACKENDS therefore has to call LLM.tools /
164
+ # LLM.associations itself or the directives are silently dropped.
165
+ def tools(messages, options)
166
+ tools = options[:tools]
167
+
168
+ case tools
169
+ when Array
170
+ tools = tools.inject({}) do |acc, definition|
171
+ definition = definition[:function] if Hash === definition && definition[:function] && definition[:name].nil?
172
+ acc.merge(definition[:name] => [nil, definition])
173
+ end
174
+ when nil
175
+ tools = {}
176
+ end
177
+
178
+ tools.merge!(LLM.tools(messages))
179
+ tools.merge!(LLM.associations(messages))
180
+ tools
181
+ end
182
+
183
+ #{{{ embed
184
+
185
+ # Deterministic bag-of-words embedding: each downcased word is hashed to
186
+ # a dimension and counted, then L2-normalized, so identical texts yield
187
+ # identical vectors and texts sharing words land near each other
188
+ # (cosine) for RAG nearest-neighbour assertions.
189
+ def embed(text, _options = {})
190
+ case text
191
+ when Array
192
+ text.collect { |t| embed_one(t) }
193
+ else
194
+ embed_one(text)
195
+ end
196
+ end
197
+
198
+ def embed_one(text)
199
+ vector = Array.new(DIMENSIONS, 0.0)
200
+
201
+ text.to_s.downcase.split(/\W+/).each do |word|
202
+ next if word.empty?
203
+ position = word.sum % DIMENSIONS
204
+ vector[position] += 1.0
205
+ end
206
+
207
+ norm = Math.sqrt(vector.inject(0.0) { |acc, v| v * v })
208
+ return vector if norm.zero?
209
+ vector.collect { |v| v / norm }
210
+ end
211
+ end
212
+ end
213
+ end
214
+
215
+ LLM::BACKENDS[:mock] = LLM::Mock
data/test/test_helper.rb CHANGED
@@ -2,6 +2,36 @@ require 'test/unit'
2
2
  $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
3
3
  $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
4
4
  require 'scout'
5
+ require 'scout-ai'
6
+
7
+ # Offline test endpoints/fixtures support. Files under test/support are
8
+ # deliberately NOT named test_*.rb so the Rakefile pattern
9
+ # ('test/**/test_*.rb') does not collect them as tests.
10
+ require File.join(File.dirname(__FILE__), 'support', 'fixtures')
11
+ require File.join(File.dirname(__FILE__), 'support', 'mock_backend')
12
+ require File.join(File.dirname(__FILE__), 'support', 'fake_clients')
13
+ require File.join(File.dirname(__FILE__), 'support', 'availability')
14
+
15
+ # ScoutCoder: Scout.etc.AI['name'] resolves through the Scout path maps, and
16
+ # the first map in Scout.map_order wins. Scout.prepend_path(:name, map) adds
17
+ # the map AND unshifts it into map_order, which is what makes the repo-local
18
+ # test/etc tree take precedence over ~/.scout/etc. Note the map must include
19
+ # the literal '{TOPLEVEL}/{SUBPATH}' suffix and, because the path is 'etc/AI'
20
+ # (TOPLEVEL 'etc', SUBPATH 'AI'), the map root must be the test directory so
21
+ # it expands to <repo>/test/etc/AI/... .
22
+ #
23
+ # Only the offline 'mock' endpoint lives here. In particular the repo does
24
+ # NOT define a 'test' endpoint: 'test' is expected to be provided at
25
+ # installation level (~/.scout/etc/AI/test.yaml) and is consumed by the
26
+ # infrastructure suite (`rake test_infrastructure`), never by `rake test`.
27
+ Scout.prepend_path :test_etc, File.join(File.expand_path(File.dirname(__FILE__)), '{TOPLEVEL}/{SUBPATH}')
28
+
29
+ # Default offline LLM configuration for the unit tests: backend is the
30
+ # registered LLM::Mock (test/support/mock_backend.rb). No endpoint is set
31
+ # at all, so no endpoint yaml is ever resolved on the unit path and no real
32
+ # inference service can be reached from `rake test`.
33
+ Scout::Config.set({backend: :mock}, :ask, :llm)
34
+ Scout::Config.set({backend: :mock}, :embed, :llm)
5
35
 
6
36
  class Test::Unit::TestCase
7
37
 
@@ -27,8 +57,9 @@ class Test::Unit::TestCase
27
57
  Workflow.directory = tmpdir.var.jobs
28
58
  Workflow.workflows.each{|wf| wf.directory = Workflow.directory[wf.name] }
29
59
  Entity.entity_property_cache = tmpdir.entity_properties if defined?(Entity)
60
+ LLM::Mock.reset! if defined?(LLM::Mock)
30
61
  end
31
-
62
+
32
63
  teardown do
33
64
  Open.rm_rf tmpdir
34
65
  end
@@ -51,7 +82,6 @@ class Test::Unit::TestCase
51
82
 
52
83
  def agent(name = nil, options = {})
53
84
  require 'scout/llm/agent'
54
- options[:endpoint] = Scout::Config.get(:endpoint, :test)
55
85
  if name.nil?
56
86
  LLM::Agent.new(**options)
57
87
  else
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scout-ai
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Vazquez
@@ -97,20 +97,39 @@ files:
97
97
  - Rakefile
98
98
  - VERSION
99
99
  - bin/scout-ai
100
- - doc/Agent.md
101
- - doc/Chat.md
102
- - doc/LLM.md
100
+ - doc/Improvements.md
103
101
  - doc/Model.md
104
- - doc/RAG.md
102
+ - doc/StartHere.md
103
+ - doc/developer/Architecture.md
104
+ - doc/developer/Backends.md
105
+ - doc/developer/ChatLifecycle.md
106
+ - doc/developer/DelegationInternals.md
107
+ - doc/developer/DesignPrinciples.md
108
+ - doc/developer/PromptProcessing.md
109
+ - doc/developer/Provenance.md
110
+ - doc/user/BuildingAgents.md
111
+ - doc/user/Cookbook.md
112
+ - doc/user/CoreConcepts.md
113
+ - doc/user/Delegation.md
114
+ - doc/user/GettingStarted.md
115
+ - doc/user/ManagingContext.md
116
+ - doc/user/MultiAgentWorkflows.md
117
+ - doc/user/Python.md
118
+ - doc/user/RunningInference.md
119
+ - doc/user/ToolCalling.md
120
+ - doc/user/WritingChats.md
105
121
  - lib/scout-ai.rb
106
122
  - lib/scout/llm/agent.rb
107
123
  - lib/scout/llm/agent/chat.rb
108
124
  - lib/scout/llm/agent/delegate.rb
109
125
  - lib/scout/llm/agent/iterate.rb
126
+ - lib/scout/llm/agent/save.rb
127
+ - lib/scout/llm/agent/workflow.rb
110
128
  - lib/scout/llm/ask.rb
111
129
  - lib/scout/llm/backends/anthropic.rb
112
130
  - lib/scout/llm/backends/bedrock.rb
113
131
  - lib/scout/llm/backends/default.rb
132
+ - lib/scout/llm/backends/glm.rb
114
133
  - lib/scout/llm/backends/huggingface.rb
115
134
  - lib/scout/llm/backends/ollama.rb
116
135
  - lib/scout/llm/backends/openai.rb
@@ -119,15 +138,23 @@ files:
119
138
  - lib/scout/llm/backends/responses.rb
120
139
  - lib/scout/llm/backends/vllm.rb
121
140
  - lib/scout/llm/chat.rb
141
+ - lib/scout/llm/chat/agent_meta.rb
122
142
  - lib/scout/llm/chat/annotation.rb
123
143
  - lib/scout/llm/chat/parse.rb
144
+ - lib/scout/llm/chat/persist.rb
124
145
  - lib/scout/llm/chat/process.rb
125
146
  - lib/scout/llm/chat/process/clear.rb
126
147
  - lib/scout/llm/chat/process/files.rb
127
148
  - lib/scout/llm/chat/process/meta.rb
128
149
  - lib/scout/llm/chat/process/options.rb
129
150
  - lib/scout/llm/chat/process/tools.rb
151
+ - lib/scout/llm/chat/prompt.rb
152
+ - lib/scout/llm/chat/prompt/shorten_tools.rb
153
+ - lib/scout/llm/chat/prompt/shorten_tools_epoch.rb
154
+ - lib/scout/llm/chat/provenance.rb
155
+ - lib/scout/llm/chat/tool_calls.rb
130
156
  - lib/scout/llm/embed.rb
157
+ - lib/scout/llm/image.rb
131
158
  - lib/scout/llm/mcp.rb
132
159
  - lib/scout/llm/rag.rb
133
160
  - lib/scout/llm/tools.rb
@@ -170,41 +197,98 @@ files:
170
197
  - python/scout_ai/runner.py
171
198
  - python/scout_ai/util.py
172
199
  - python/tests/test_chat_agent.py
200
+ - python/tests/test_huggingface_eval.py
173
201
  - python/tests/test_runner.py
202
+ - research/ChatAnalyst-required-changes.md
203
+ - research/agent-delegation-analysis.md
204
+ - research/agent-meta-provenance-integration-plan.md
205
+ - research/agent-workflow-analysis.md
206
+ - research/backends-analysis.md
207
+ - research/chat-core-analysis.md
208
+ - research/chatanalyst-provenance/00-baseline.md
209
+ - research/chatanalyst-provenance/01-repo-map.md
210
+ - research/chatanalyst-provenance/02-event-reconstruction.md
211
+ - research/chatanalyst-provenance/03-duplication-evidence.md
212
+ - research/chatanalyst-provenance/04-tooling-root-cause.md
213
+ - research/chatanalyst-provenance/05-fix-plan.md
214
+ - research/chatanalyst-provenance/07-critic-review.md
215
+ - research/chatanalyst-provenance/final-report.md
216
+ - research/chatanalyst-provenance/resumption.md
217
+ - research/coding-philosophy-analysis.md
218
+ - research/commands-analysis.md
219
+ - research/multi-agent-patterns-analysis.md
220
+ - research/prompt-strategies-analysis.md
221
+ - research/prov-verbosity-fix-notes.md
222
+ - research/provenance-analysis.md
223
+ - research/provenance-navigation-design.md
224
+ - research/synthesis-report.md
225
+ - research/tools-system-analysis.md
174
226
  - scout-ai.gemspec
175
227
  - scout_commands/agent/ask
176
228
  - scout_commands/agent/find
177
229
  - scout_commands/agent/kb
178
- - scout_commands/documenter
179
230
  - scout_commands/llm/ask
180
231
  - scout_commands/llm/json
232
+ - scout_commands/llm/md
181
233
  - scout_commands/llm/process
234
+ - scout_commands/llm/process_queries
235
+ - scout_commands/llm/prov
182
236
  - scout_commands/llm/server
183
237
  - scout_commands/llm/template
238
+ - scout_commands/llm/word
239
+ - scout_commands/workflow/mcp
184
240
  - share/server/chat.html
185
241
  - share/server/chat.js
242
+ - share/word/reference.docx
186
243
  - test/data/cat.jpg
187
244
  - test/data/person/brothers
188
245
  - test/data/person/identifiers
189
246
  - test/data/person/marriages
190
247
  - test/data/person/parents
248
+ - test/etc/AI/mock.yaml
249
+ - test/fixtures/backends/anthropic.json
250
+ - test/fixtures/backends/anthropic_tool_use.json
251
+ - test/fixtures/backends/bedrock.json
252
+ - test/fixtures/backends/bedrock_embedding.json
253
+ - test/fixtures/backends/bedrock_tool_use.json
254
+ - test/fixtures/backends/ollama.json
255
+ - test/fixtures/backends/ollama_tool_call.json
256
+ - test/fixtures/backends/openai_chat.json
257
+ - test/fixtures/backends/openai_chat_tool_call.json
258
+ - test/fixtures/backends/responses.json
259
+ - test/fixtures/backends/responses_tool_call.json
260
+ - test/integration/README.md
261
+ - test/integration/scout/llm/backends/test_endpoints.rb
262
+ - test/integration/scout/llm/backends/test_openwebui.rb
263
+ - test/integration/scout/llm/backends/test_relay.rb
264
+ - test/integration/scout/llm/test_infrastructure.rb
265
+ - test/integration/scout/llm/test_mcp.rb
266
+ - test/integration/scout/llm/tools/test_mcp.rb
267
+ - test/integration/scout/model/test_base.rb
191
268
  - test/scout/llm/agent/test_chat.rb
269
+ - test/scout/llm/agent/test_save.rb
270
+ - test/scout/llm/agent/test_workflow.rb
192
271
  - test/scout/llm/backends/test_anthropic.rb
193
272
  - test/scout/llm/backends/test_bedrock.rb
194
273
  - test/scout/llm/backends/test_huggingface.rb
195
274
  - test/scout/llm/backends/test_ollama.rb
196
- - test/scout/llm/backends/test_openai.rb
197
275
  - test/scout/llm/backends/test_openwebui.rb
198
276
  - test/scout/llm/backends/test_relay.rb
199
- - test/scout/llm/backends/test_responses.rb
277
+ - test/scout/llm/chat/agent_meta_fixtures.rb
278
+ - test/scout/llm/chat/process/test_meta.rb
279
+ - test/scout/llm/chat/process/test_normalize_usage.rb
280
+ - test/scout/llm/chat/test_agent_meta.rb
281
+ - test/scout/llm/chat/test_agent_meta_provenance.rb
282
+ - test/scout/llm/chat/test_agent_meta_tokens.rb
200
283
  - test/scout/llm/chat/test_parse.rb
201
284
  - test/scout/llm/chat/test_process.rb
285
+ - test/scout/llm/chat/test_prov_cli.rb
286
+ - test/scout/llm/chat/test_provenance.rb
287
+ - test/scout/llm/chat/test_tool_calls.rb
202
288
  - test/scout/llm/test_agent.rb
203
289
  - test/scout/llm/test_ask.rb
204
290
  - test/scout/llm/test_chat.rb
205
291
  - test/scout/llm/test_embed.rb
206
- - test/scout/llm/test_mcp.rb
207
- - test/scout/llm/test_parse.rb
208
292
  - test/scout/llm/test_rag.rb
209
293
  - test/scout/llm/test_tools.rb
210
294
  - test/scout/llm/test_utils.rb
@@ -224,6 +308,11 @@ files:
224
308
  - test/scout/network/test_entity.rb
225
309
  - test/scout/network/test_knowledge_base.rb
226
310
  - test/scout/network/test_paths.rb
311
+ - test/support/availability.rb
312
+ - test/support/fake_clients.rb
313
+ - test/support/fixtures.rb
314
+ - test/support/infrastructure_probes.rb
315
+ - test/support/mock_backend.rb
227
316
  - test/test_helper.rb
228
317
  homepage: http://github.com/mikisvaz/scout-ai
229
318
  licenses: