scout-ai 1.2.5 → 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 (164) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +111 -31
  3. data/README.md +171 -320
  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 +62 -12
  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 +36 -6
  33. data/lib/scout/llm/backends/anthropic.rb +9 -1
  34. data/lib/scout/llm/backends/bedrock.rb +15 -3
  35. data/lib/scout/llm/backends/default.rb +129 -89
  36. data/lib/scout/llm/backends/glm.rb +58 -0
  37. data/lib/scout/llm/backends/huggingface.rb +13 -1
  38. data/lib/scout/llm/backends/ollama.rb +13 -0
  39. data/lib/scout/llm/backends/openwebui.rb +8 -3
  40. data/lib/scout/llm/chat/agent_meta.rb +264 -0
  41. data/lib/scout/llm/chat/annotation.rb +37 -14
  42. data/lib/scout/llm/chat/parse.rb +28 -6
  43. data/lib/scout/llm/chat/persist.rb +25 -0
  44. data/lib/scout/llm/chat/process/clear.rb +19 -1
  45. data/lib/scout/llm/chat/process/files.rb +16 -1
  46. data/lib/scout/llm/chat/process/meta.rb +422 -32
  47. data/lib/scout/llm/chat/process/options.rb +21 -1
  48. data/lib/scout/llm/chat/process/tools.rb +49 -12
  49. data/lib/scout/llm/chat/process.rb +4 -0
  50. data/lib/scout/llm/chat/prompt/shorten_tools.rb +125 -0
  51. data/lib/scout/llm/chat/prompt/shorten_tools_epoch.rb +365 -0
  52. data/lib/scout/llm/chat/prompt.rb +48 -0
  53. data/lib/scout/llm/chat/provenance.rb +775 -0
  54. data/lib/scout/llm/chat/tool_calls.rb +76 -0
  55. data/lib/scout/llm/chat.rb +18 -2
  56. data/lib/scout/llm/embed.rb +8 -3
  57. data/lib/scout/llm/image.rb +86 -0
  58. data/lib/scout/llm/rag.rb +3 -3
  59. data/lib/scout/llm/tools/call.rb +159 -10
  60. data/lib/scout/llm/tools/knowledge_base.rb +1 -1
  61. data/lib/scout/llm/tools/workflow.rb +13 -5
  62. data/lib/scout-ai.rb +1 -0
  63. data/research/ChatAnalyst-required-changes.md +167 -0
  64. data/research/agent-delegation-analysis.md +810 -0
  65. data/research/agent-meta-provenance-integration-plan.md +622 -0
  66. data/research/agent-workflow-analysis.md +1120 -0
  67. data/research/backends-analysis.md +836 -0
  68. data/research/chat-core-analysis.md +946 -0
  69. data/research/chatanalyst-provenance/00-baseline.md +30 -0
  70. data/research/chatanalyst-provenance/01-repo-map.md +60 -0
  71. data/research/chatanalyst-provenance/02-event-reconstruction.md +55 -0
  72. data/research/chatanalyst-provenance/03-duplication-evidence.md +45 -0
  73. data/research/chatanalyst-provenance/04-tooling-root-cause.md +57 -0
  74. data/research/chatanalyst-provenance/05-fix-plan.md +46 -0
  75. data/research/chatanalyst-provenance/07-critic-review.md +25 -0
  76. data/research/chatanalyst-provenance/final-report.md +45 -0
  77. data/research/chatanalyst-provenance/resumption.md +37 -0
  78. data/research/coding-philosophy-analysis.md +928 -0
  79. data/research/commands-analysis.md +947 -0
  80. data/research/multi-agent-patterns-analysis.md +853 -0
  81. data/research/prompt-strategies-analysis.md +630 -0
  82. data/research/prov-verbosity-fix-notes.md +77 -0
  83. data/research/provenance-analysis.md +469 -0
  84. data/research/provenance-navigation-design.md +640 -0
  85. data/research/synthesis-report.md +487 -0
  86. data/research/tools-system-analysis.md +779 -0
  87. data/scout-ai.gemspec +97 -13
  88. data/scout_commands/agent/ask +13 -3
  89. data/scout_commands/agent/kb +2 -0
  90. data/scout_commands/llm/ask +11 -4
  91. data/scout_commands/llm/md +76 -0
  92. data/scout_commands/llm/prov +602 -0
  93. data/scout_commands/llm/word +71 -0
  94. data/share/word/reference.docx +0 -0
  95. data/test/etc/AI/mock.yaml +11 -0
  96. data/test/fixtures/backends/anthropic.json +19 -0
  97. data/test/fixtures/backends/anthropic_tool_use.json +24 -0
  98. data/test/fixtures/backends/bedrock.json +8 -0
  99. data/test/fixtures/backends/bedrock_embedding.json +3 -0
  100. data/test/fixtures/backends/bedrock_tool_use.json +17 -0
  101. data/test/fixtures/backends/ollama.json +16 -0
  102. data/test/fixtures/backends/ollama_tool_call.json +27 -0
  103. data/test/fixtures/backends/openai_chat.json +21 -0
  104. data/test/fixtures/backends/openai_chat_tool_call.json +31 -0
  105. data/test/fixtures/backends/responses.json +33 -0
  106. data/test/fixtures/backends/responses_tool_call.json +28 -0
  107. data/test/integration/README.md +32 -0
  108. data/test/integration/scout/llm/backends/test_endpoints.rb +34 -0
  109. data/test/integration/scout/llm/backends/test_openwebui.rb +61 -0
  110. data/test/integration/scout/llm/backends/test_relay.rb +52 -0
  111. data/test/integration/scout/llm/test_infrastructure.rb +74 -0
  112. data/test/{scout → integration/scout}/llm/test_mcp.rb +1 -1
  113. data/test/integration/scout/llm/tools/test_mcp.rb +42 -0
  114. data/test/integration/scout/model/test_base.rb +91 -0
  115. data/test/scout/llm/agent/test_chat.rb +8 -2
  116. data/test/scout/llm/agent/test_save.rb +413 -0
  117. data/test/scout/llm/agent/test_workflow.rb +110 -0
  118. data/test/scout/llm/backends/test_anthropic.rb +93 -10
  119. data/test/scout/llm/backends/test_bedrock.rb +118 -2
  120. data/test/scout/llm/backends/test_ollama.rb +70 -20
  121. data/test/scout/llm/backends/test_openwebui.rb +42 -40
  122. data/test/scout/llm/backends/test_relay.rb +4 -2
  123. data/test/scout/llm/chat/agent_meta_fixtures.rb +131 -0
  124. data/test/scout/llm/chat/process/test_meta.rb +518 -0
  125. data/test/scout/llm/chat/process/test_normalize_usage.rb +183 -0
  126. data/test/scout/llm/chat/test_agent_meta.rb +357 -0
  127. data/test/scout/llm/chat/test_agent_meta_provenance.rb +467 -0
  128. data/test/scout/llm/chat/test_agent_meta_tokens.rb +594 -0
  129. data/test/scout/llm/chat/test_parse.rb +70 -15
  130. data/test/scout/llm/chat/test_prov_cli.rb +274 -0
  131. data/test/scout/llm/chat/test_provenance.rb +240 -0
  132. data/test/scout/llm/chat/test_tool_calls.rb +38 -0
  133. data/test/scout/llm/test_agent.rb +13 -36
  134. data/test/scout/llm/test_ask.rb +75 -52
  135. data/test/scout/llm/test_chat.rb +107 -13
  136. data/test/scout/llm/test_embed.rb +48 -0
  137. data/test/scout/llm/test_rag.rb +23 -16
  138. data/test/scout/llm/test_tools.rb +12 -1
  139. data/test/scout/llm/tools/test_knowledge_base.rb +0 -1
  140. data/test/scout/llm/tools/test_mcp.rb +5 -3
  141. data/test/scout/llm/tools/test_workflow.rb +23 -2
  142. data/test/scout/model/python/huggingface/causal/test_next_token.rb +11 -5
  143. data/test/scout/model/python/huggingface/test_causal.rb +9 -3
  144. data/test/scout/model/python/huggingface/test_classification.rb +11 -2
  145. data/test/scout/model/python/test_torch.rb +2 -0
  146. data/test/scout/model/python/torch/test_helpers.rb +4 -0
  147. data/test/scout/model/test_base.rb +4 -2
  148. data/test/support/availability.rb +231 -0
  149. data/test/support/fake_clients.rb +138 -0
  150. data/test/support/fixtures.rb +21 -0
  151. data/test/support/infrastructure_probes.rb +136 -0
  152. data/test/support/mock_backend.rb +215 -0
  153. data/test/test_helper.rb +32 -2
  154. metadata +96 -12
  155. data/doc/Agent.md +0 -354
  156. data/doc/Chat.md +0 -481
  157. data/doc/LLM.md +0 -356
  158. data/doc/PythonAgentTasks.md +0 -333
  159. data/doc/RAG.md +0 -129
  160. data/doc/USER_GUIDE.md +0 -572
  161. data/scout_commands/documenter +0 -148
  162. data/test/scout/llm/backends/test_openai.rb +0 -192
  163. data/test/scout/llm/backends/test_responses.rb +0 -238
  164. 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.5
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Vazquez
@@ -97,22 +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/PythonAgentTasks.md
105
- - doc/RAG.md
106
- - doc/USER_GUIDE.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
107
121
  - lib/scout-ai.rb
108
122
  - lib/scout/llm/agent.rb
109
123
  - lib/scout/llm/agent/chat.rb
110
124
  - lib/scout/llm/agent/delegate.rb
111
125
  - lib/scout/llm/agent/iterate.rb
126
+ - lib/scout/llm/agent/save.rb
127
+ - lib/scout/llm/agent/workflow.rb
112
128
  - lib/scout/llm/ask.rb
113
129
  - lib/scout/llm/backends/anthropic.rb
114
130
  - lib/scout/llm/backends/bedrock.rb
115
131
  - lib/scout/llm/backends/default.rb
132
+ - lib/scout/llm/backends/glm.rb
116
133
  - lib/scout/llm/backends/huggingface.rb
117
134
  - lib/scout/llm/backends/ollama.rb
118
135
  - lib/scout/llm/backends/openai.rb
@@ -121,15 +138,23 @@ files:
121
138
  - lib/scout/llm/backends/responses.rb
122
139
  - lib/scout/llm/backends/vllm.rb
123
140
  - lib/scout/llm/chat.rb
141
+ - lib/scout/llm/chat/agent_meta.rb
124
142
  - lib/scout/llm/chat/annotation.rb
125
143
  - lib/scout/llm/chat/parse.rb
144
+ - lib/scout/llm/chat/persist.rb
126
145
  - lib/scout/llm/chat/process.rb
127
146
  - lib/scout/llm/chat/process/clear.rb
128
147
  - lib/scout/llm/chat/process/files.rb
129
148
  - lib/scout/llm/chat/process/meta.rb
130
149
  - lib/scout/llm/chat/process/options.rb
131
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
132
156
  - lib/scout/llm/embed.rb
157
+ - lib/scout/llm/image.rb
133
158
  - lib/scout/llm/mcp.rb
134
159
  - lib/scout/llm/rag.rb
135
160
  - lib/scout/llm/tools.rb
@@ -174,42 +199,96 @@ files:
174
199
  - python/tests/test_chat_agent.py
175
200
  - python/tests/test_huggingface_eval.py
176
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
177
226
  - scout-ai.gemspec
178
227
  - scout_commands/agent/ask
179
228
  - scout_commands/agent/find
180
229
  - scout_commands/agent/kb
181
- - scout_commands/documenter
182
230
  - scout_commands/llm/ask
183
231
  - scout_commands/llm/json
232
+ - scout_commands/llm/md
184
233
  - scout_commands/llm/process
185
234
  - scout_commands/llm/process_queries
235
+ - scout_commands/llm/prov
186
236
  - scout_commands/llm/server
187
237
  - scout_commands/llm/template
238
+ - scout_commands/llm/word
188
239
  - scout_commands/workflow/mcp
189
240
  - share/server/chat.html
190
241
  - share/server/chat.js
242
+ - share/word/reference.docx
191
243
  - test/data/cat.jpg
192
244
  - test/data/person/brothers
193
245
  - test/data/person/identifiers
194
246
  - test/data/person/marriages
195
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
196
268
  - test/scout/llm/agent/test_chat.rb
269
+ - test/scout/llm/agent/test_save.rb
270
+ - test/scout/llm/agent/test_workflow.rb
197
271
  - test/scout/llm/backends/test_anthropic.rb
198
272
  - test/scout/llm/backends/test_bedrock.rb
199
273
  - test/scout/llm/backends/test_huggingface.rb
200
274
  - test/scout/llm/backends/test_ollama.rb
201
- - test/scout/llm/backends/test_openai.rb
202
275
  - test/scout/llm/backends/test_openwebui.rb
203
276
  - test/scout/llm/backends/test_relay.rb
204
- - 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
205
283
  - test/scout/llm/chat/test_parse.rb
206
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
207
288
  - test/scout/llm/test_agent.rb
208
289
  - test/scout/llm/test_ask.rb
209
290
  - test/scout/llm/test_chat.rb
210
291
  - test/scout/llm/test_embed.rb
211
- - test/scout/llm/test_mcp.rb
212
- - test/scout/llm/test_parse.rb
213
292
  - test/scout/llm/test_rag.rb
214
293
  - test/scout/llm/test_tools.rb
215
294
  - test/scout/llm/test_utils.rb
@@ -229,6 +308,11 @@ files:
229
308
  - test/scout/network/test_entity.rb
230
309
  - test/scout/network/test_knowledge_base.rb
231
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
232
316
  - test/test_helper.rb
233
317
  homepage: http://github.com/mikisvaz/scout-ai
234
318
  licenses: