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,333 @@
1
+ # Cookbook
2
+
3
+ This page collects small, ready-to-use examples for common Scout-AI tasks. It
4
+ is intended for workflow authors who want quick, practical patterns.
5
+
6
+ **You should read this if:** you want copy-paste examples for specific tasks.
7
+
8
+ ---
9
+
10
+ ## Quick one-shot question
11
+
12
+ ```bash
13
+ scout-ai llm ask "What is the capital of France?"
14
+ ```
15
+
16
+ ```ruby
17
+ agent = LLM.agent(endpoint: :openai)
18
+ agent.start
19
+ agent.user "What is the capital of France?"
20
+ puts agent.chat
21
+ ```
22
+
23
+ ---
24
+
25
+ ## Simple assistant with a system prompt
26
+
27
+ ```ruby
28
+ agent = LLM.agent(endpoint: :openai)
29
+ agent.start_chat.system "You are a helpful assistant. Answer concisely."
30
+ agent.start
31
+ agent.user "Explain recursion in one sentence."
32
+ puts agent.chat
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Chat file with endpoint and model
38
+
39
+ ```text
40
+ endpoint: anthropic
41
+ model: claude-sonnet-4-20250514
42
+
43
+ system:
44
+
45
+ You are a code reviewer.
46
+
47
+ user:
48
+
49
+ Review this function for bugs:
50
+
51
+ def add(a, b)
52
+ a + b
53
+ end
54
+ ```
55
+
56
+ Save as `review.chat` and run:
57
+
58
+ ```bash
59
+ scout-ai llm ask -c review.chat
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Agent with a workflow tool
65
+
66
+ ```ruby
67
+ agent = LLM.agent(endpoint: :openai)
68
+ agent.workflow do
69
+ task :search => :string do |query|
70
+ "Results for '#{query}': ..."
71
+ end
72
+ end
73
+ agent.start
74
+ agent.user "Search for Ruby tutorials."
75
+ puts agent.chat
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Agent from a directory
81
+
82
+ Directory layout:
83
+
84
+ ```
85
+ Agent/
86
+ Greeter/
87
+ start_chat
88
+ ```
89
+
90
+ `start_chat`:
91
+
92
+ ```text
93
+ system:
94
+
95
+ You are a friendly greeter. Always greet by name.
96
+
97
+ user:
98
+
99
+ Hello!
100
+ ```
101
+
102
+ Use it:
103
+
104
+ ```ruby
105
+ agent = LLM.load_agent('Greeter')
106
+ agent.start
107
+ agent.user "Hi, I'm Alice."
108
+ puts agent.chat
109
+ ```
110
+
111
+ From CLI:
112
+
113
+ ```bash
114
+ scout-ai agent ask Greeter "Hi, I'm Alice."
115
+ ```
116
+
117
+ ---
118
+
119
+ ## Structured JSON output
120
+
121
+ ```ruby
122
+ agent = LLM.agent(endpoint: :openai)
123
+ agent.start
124
+ agent.user 'Return a JSON object: {"name": "Ruby", "type": "language", "year": 1995}'
125
+ result = agent.json
126
+ puts result["name"] # => "Ruby"
127
+ ```
128
+
129
+ With a schema:
130
+
131
+ ```ruby
132
+ schema = {
133
+ name: 'evaluation',
134
+ type: 'object',
135
+ properties: {
136
+ score: { type: :integer },
137
+ feedback: { type: :string }
138
+ },
139
+ required: [:score, :feedback]
140
+ }
141
+
142
+ agent.json_format(schema)
143
+ ```
144
+
145
+ ---
146
+
147
+ ## Importing a file into the conversation
148
+
149
+ ```text
150
+ system:
151
+
152
+ You are a document analyzer.
153
+
154
+ file: report.pdf
155
+
156
+ user:
157
+
158
+ Summarize the key findings.
159
+ ```
160
+
161
+ ---
162
+
163
+ ## Multi-turn conversation
164
+
165
+ ```ruby
166
+ agent = LLM.agent(endpoint: :openai)
167
+ agent.start_chat.system "You are a patient tutor."
168
+ agent.start
169
+
170
+ agent.user "What is a variable?"
171
+ puts agent.chat
172
+
173
+ agent.user "How is it different from a constant?"
174
+ puts agent.chat # remembers the previous turn
175
+ ```
176
+
177
+ ---
178
+
179
+ ## Delegation: orchestrator with specialist
180
+
181
+ ```ruby
182
+ # Load a specialist
183
+ searcher = LLM.load_agent('Searcher')
184
+
185
+ # Set up the orchestrator
186
+ orchestrator = LLM.load_agent('Manager')
187
+ orchestrator.socialize # model can call ask(agent: 'Searcher', prompt: ...)
188
+
189
+ orchestrator.start
190
+ orchestrator.user "Research the latest advances in protein folding."
191
+ orchestrator.chat
192
+ ```
193
+
194
+ ---
195
+
196
+ ## Multi-agent pipeline in a workflow
197
+
198
+ ```ruby
199
+ module AnalysisPipeline
200
+ extend Workflow
201
+ include AgentWorkflow
202
+
203
+ chat_task :plan do |objective|
204
+ agent = self.agent('Planner', chat: chat)
205
+ agent.start
206
+ agent.user objective
207
+ agent.chat
208
+ end
209
+
210
+ chat_task :execute do |objective, plan|
211
+ agent = self.agent('Executor', chat: chat)
212
+ agent.start
213
+ agent.user "Objective: #{objective}\nPlan: #{plan}"
214
+ agent.chat
215
+ end
216
+
217
+ chat_task :review do |result|
218
+ agent = self.agent('Critic', chat: chat)
219
+ agent.start
220
+ agent.user "Review: #{result}"
221
+ agent.chat
222
+ end
223
+ end
224
+ ```
225
+
226
+ ---
227
+
228
+ ## Python task in an agent
229
+
230
+ ```text
231
+ MyAgent/
232
+ ├── start_chat
233
+ └── python/
234
+ └── analyze.py
235
+ ```
236
+
237
+ ```python
238
+ # python/analyze.py
239
+ import scout
240
+
241
+ def word_count(text: str) -> dict:
242
+ """
243
+ Count words in text.
244
+
245
+ Args:
246
+ text: Input text.
247
+
248
+ Returns:
249
+ Dictionary with word counts.
250
+ """
251
+ words = text.lower().split()
252
+ counts = {}
253
+ for w in words:
254
+ counts[w] = counts.get(w, 0) + 1
255
+ return counts
256
+
257
+ scout.task(word_count)
258
+ ```
259
+
260
+ ```ruby
261
+ agent = LLM::Agent.load_agent('MyAgent', endpoint: :openai)
262
+ agent.start
263
+ agent.user "Count the words in: the quick brown fox"
264
+ puts agent.chat
265
+ ```
266
+
267
+ ---
268
+
269
+ ## Error handling with retry
270
+
271
+ ```ruby
272
+ agent = LLM.agent(endpoint: :openai)
273
+ agent.process_exception = Proc.new do |e|
274
+ if e.message =~ /rate limit/i
275
+ sleep 10
276
+ true # retry
277
+ else
278
+ false # re-raise
279
+ end
280
+ end
281
+ ```
282
+
283
+ ---
284
+
285
+ ## Clearing context between phases
286
+
287
+ ```text
288
+ system:
289
+
290
+ You are a project manager.
291
+
292
+ user:
293
+
294
+ Phase 1: Analyze requirements.
295
+
296
+ clear:
297
+
298
+ user:
299
+
300
+ Phase 2: Design the system. (Phase 1 context is cleared)
301
+ ```
302
+
303
+ ---
304
+
305
+ ## Knowledge base tool
306
+
307
+ ```text
308
+ system:
309
+
310
+ You are a bioinformatics assistant.
311
+
312
+ kb: gene_db [genes proteins diseases]
313
+
314
+ user:
315
+
316
+ What proteins are associated with BRCA1?
317
+ ```
318
+
319
+ ---
320
+
321
+ ## MCP tool
322
+
323
+ ```text
324
+ system:
325
+
326
+ You have access to an external search service.
327
+
328
+ mcp: https://api.example.com/mcp/ [search]
329
+
330
+ user:
331
+
332
+ Search for recent papers on climate change.
333
+ ```
@@ -0,0 +1,181 @@
1
+ # Core Concepts
2
+
3
+ This page gives you a conceptual map of Scout-AI's main abstractions. It is
4
+ intended for workflow authors — both human developers and coding agents — who
5
+ want to understand what Scout-AI offers before diving into specifics.
6
+
7
+ **You should read this if:** you have installed Scout-AI and want a high-level
8
+ orientation before building anything.
9
+
10
+ ---
11
+
12
+ ## The big picture
13
+
14
+ Scout-AI sits between your application code and an LLM provider. It gives you
15
+ four building blocks:
16
+
17
+ | Concept | What it is | What problem it solves |
18
+ |---------|-----------|----------------------|
19
+ | **Chat** | A conversation format (plain text on disk, Array of hashes in memory) | Reproducibility: every conversation is inspectable, editable, and versionable |
20
+ | **Agent** | A stateful wrapper around a Chat with persistent defaults and tools | Persistence: your agent keeps its system prompt, tools, and options across conversations |
21
+ | **Tools** | Callable functions the LLM can invoke during inference | Grounding: the model can query real data and run real code instead of hallucinating |
22
+ | **Inference Endpoint** | A named configuration for a provider + model + credentials | Portability: switch between OpenAI, Anthropic, Ollama, etc. without changing application code |
23
+
24
+ These compose. An **Agent** has a **Chat** and a set of **Tools**, and it sends
25
+ the chat to an **Inference Endpoint** to get a response.
26
+
27
+ ---
28
+
29
+ ## Chat: the conversation format
30
+
31
+ A Chat is simultaneously two things:
32
+
33
+ 1. **On disk:** a plain-text file where each line block starts with a role
34
+ name and colon (`system:`, `user:`, `assistant:`, etc.).
35
+ 2. **In memory:** an Array of message hashes, each with `role:` and `content:`
36
+ keys.
37
+
38
+ This dual nature is the foundation of Scout-AI's reproducibility. You can
39
+ write a conversation by hand in a text editor, run it through the CLI, inspect
40
+ the output, and feed it back as input.
41
+
42
+ ```text
43
+ system:
44
+
45
+ You are a helpful assistant.
46
+
47
+ user:
48
+
49
+ Hello!
50
+
51
+ assistant:
52
+
53
+ Hi there! How can I help?
54
+ ```
55
+
56
+ **Key idea:** Every conversation — whether a one-shot CLI question, an agent
57
+ session, or the output of a workflow job — is serialized to the same
58
+ plain-text format. This means you can always inspect, edit, and reproduce
59
+ what happened.
60
+
61
+ → See [WritingChats.md](WritingChats.md) for the full format.
62
+
63
+ ---
64
+
65
+ ## Agent: the stateful wrapper
66
+
67
+ An Agent bundles a Chat with persistent configuration:
68
+
69
+ - **A start chat** — the system prompt, tool declarations, file imports, and
70
+ other seed messages that prefix every new conversation.
71
+ - **Tools** — workflows, knowledge bases, or MCP tools the agent can call.
72
+ - **Options** — endpoint, model, format, and other defaults.
73
+
74
+ Agents are **named directories**. You create an agent by making a directory
75
+ under your Scout Agent path and adding a `start_chat` file:
76
+
77
+ ```
78
+ Agent/
79
+ Researcher/
80
+ start_chat # system prompt + tool declarations
81
+ workflow.rb # optional: Scout workflow providing tools
82
+ ```
83
+
84
+ Once defined, an agent is invoked by name:
85
+
86
+ ```bash
87
+ scout-ai agent ask Researcher "Find papers about protein folding."
88
+ ```
89
+
90
+ Agents can also **delegate** to other agents — an orchestrator agent can hand
91
+ off sub-tasks to specialists, each with its own tools and persona.
92
+
93
+ → See [BuildingAgents.md](BuildingAgents.md) for agent lifecycle and DSL.
94
+ → See [Delegation.md](Delegation.md) for multi-agent delegation.
95
+
96
+ ---
97
+
98
+ ## Tools: grounding the model
99
+
100
+ Tools let the LLM call functions during inference. Scout-AI supports several
101
+ kinds:
102
+
103
+ | Tool source | How you declare it | What it gives the model |
104
+ |-------------|-------------------|----------------------|
105
+ | **Scout Workflow** | `tool:` or `introduce:` in chat, or auto-wired from agent workflow | Tasks with typed inputs/outputs become callable functions |
106
+ | **Knowledge Base** | `kb:` in chat | Database lookups (gene→protein, drug→disease, etc.) |
107
+ | **MCP Server** | `mcp:` in chat | Any MCP-compatible external tool |
108
+
109
+ The model sees a tool definition (name, description, JSON Schema parameters),
110
+ decides when to call it, and receives the result as a tool-return message that
111
+ is appended to the conversation.
112
+
113
+ → See [ToolCalling.md](ToolCalling.md) for the full tool system.
114
+
115
+ ---
116
+
117
+ ## Inference endpoint: provider abstraction
118
+
119
+ An **endpoint** is a named bundle of provider + model + credentials. You
120
+ configure endpoints once and reference them by name everywhere:
121
+
122
+ ```bash
123
+ # Use the 'anthropic' endpoint for this conversation
124
+ scout-ai llm ask -e anthropic "Hello"
125
+ ```
126
+
127
+ Scout-AI supports OpenAI, Anthropic, Ollama, vLLM, and other OpenAI-compatible
128
+ providers. Endpoints are provider-agnostic from the application's perspective —
129
+ you write your agent once and switch models by changing the endpoint name.
130
+
131
+ → See [RunningInference.md](RunningInference.md) for endpoint configuration
132
+ and CLI usage.
133
+
134
+ ---
135
+
136
+ ## How they compose
137
+
138
+ Here is the typical flow when an agent answers a question:
139
+
140
+ ```
141
+ User question
142
+ │
143
+ ▼
144
+ Agent receives question
145
+ │
146
+ ├── Appends to current_chat (a Chat object)
147
+ ├── Sends chat to inference endpoint
148
+ │ │
149
+ │ ├── Model responds with text → done
150
+ │ └── Model calls a tool → execute tool, append result, re-send
151
+ │
152
+ └── Returns final answer
153
+ ```
154
+
155
+ The tool-calling loop is automatic: if the model calls a tool, Scout-AI
156
+ executes it, append the result, and re-sends the conversation until the model
157
+ responds with plain text.
158
+
159
+ ---
160
+
161
+ ## When to use what
162
+
163
+ | If you want to... | Use... |
164
+ |-------------------|--------|
165
+ | Ask a one-off question | `scout-ai llm ask` |
166
+ | Run a saved conversation | `scout-ai llm ask -c file.chat` |
167
+ | Create a reusable persona with tools | An Agent (directory with `start_chat`) |
168
+ | Give the model data to query | Knowledge Base tools (`kb:`) |
169
+ | Give the model code to run | Workflow tools (`tool:` / `introduce:`) |
170
+ | Use external tools | MCP (`mcp:`) |
171
+ | Build multi-agent systems | Delegation (`socialize` / `delegate`) |
172
+ | Build reproducible pipelines | AgentWorkflow (Scout Workflow + Agent) |
173
+
174
+ ---
175
+
176
+ ## Next steps
177
+
178
+ - [WritingChats.md](WritingChats.md) — master the chat-file format.
179
+ - [BuildingAgents.md](BuildingAgents.md) — create your first agent.
180
+ - [ToolCalling.md](ToolCalling.md) — wire up tools.
181
+ - [Delegation.md](Delegation.md) — build multi-agent systems.
@@ -0,0 +1,191 @@
1
+ # Delegation
2
+
3
+ This page explains how one Scout-AI agent can delegate work to other agents.
4
+ It is intended for workflow authors building multi-agent systems.
5
+
6
+ **You should read this if:** you want an orchestrator agent to hand off
7
+ sub-tasks to specialist agents.
8
+
9
+ ---
10
+
11
+ ## What delegation is
12
+
13
+ Delegation lets one agent (the **caller**) invoke another agent (the
14
+ **specialist**) during inference. Each specialist has its own persona, tools,
15
+ and conversation history.
16
+
17
+ Scout-AI provides two delegation mechanisms:
18
+
19
+ | Mechanism | How it works | When to use |
20
+ |-----------|-------------|-------------|
21
+ | **`socialize` (the `ask` tool)** | Exposes a single generic `ask` tool. The model chooses which agent to call and what to ask. | When the model should decide when and whom to delegate to |
22
+ | **`delegate` (named hand-off tools)** | Pre-registers a `hand_off_to_<name>` tool for a specific agent. | When you want explicit, named delegation to specific agents |
23
+
24
+ Both mechanisms share a common concept: **inheritance modes** that control how
25
+ much context flows from caller to specialist.
26
+
27
+ ---
28
+
29
+ ## Inheritance modes
30
+
31
+ When a specialist is invoked, you control how much of the caller's context it
32
+ receives:
33
+
34
+ | Mode | What the specialist gets | Use case |
35
+ |------|------------------------|----------|
36
+ | **`none`** | Only its own system prompt | Fully isolated sub-agent |
37
+ | **`tools`** *(default)* | Its own prompt + the caller's tools (but not conversation history) | Same capabilities, private history |
38
+ | **`conversation`** | Its own prompt + the caller's entire current conversation | Deep collaboration with shared context |
39
+
40
+ The specialist always gets **its own** system prompt first. Inherited context
41
+ is appended after.
42
+
43
+ > **Important:** The inheritance mode only applies when a conversation is first
44
+ > created. Subsequent turns in the same conversation reuse the accumulated
45
+ > history regardless of the mode.
46
+
47
+ ---
48
+
49
+ ## The `ask` tool (socialize)
50
+
51
+ `socialize` registers a single tool called `ask`. When the LLM calls it, it
52
+ provides an agent name and a prompt. Scout-AI loads the specialist, sends the
53
+ prompt, and returns the text answer.
54
+
55
+ ### Enabling delegation
56
+
57
+ ```ruby
58
+ agent = LLM.load_agent('Orchestrator')
59
+ agent.socialize
60
+ ```
61
+
62
+ Now the model can call the `ask` tool during inference.
63
+
64
+ ### What the model sees
65
+
66
+ The model sees a tool with these parameters:
67
+
68
+ | Parameter | Required | Description |
69
+ |-----------|----------|-------------|
70
+ | `agent` | Yes | Name of the specialist agent |
71
+ | `prompt` | Yes | Plain-text prompt for the specialist |
72
+ | `conversation` | No | Named conversation. Omit for one-shot; reuse to continue |
73
+ | `inherit` | No (default `tools`) | Context policy for new conversations |
74
+
75
+ ### Conversation persistence
76
+
77
+ If the model provides a `conversation` name, the specialist keeps that
78
+ conversation across multiple calls:
79
+
80
+ ```
81
+ Call 1: ask(agent="Worker", prompt="Do X", conversation="task_1")
82
+ Call 2: ask(agent="Worker", prompt="Now do Y", conversation="task_1")
83
+ # Worker remembers the full conversation from task_1
84
+ ```
85
+
86
+ Without a `conversation` name, each call is one-shot (the specialist answers
87
+ and the conversation is not reused).
88
+
89
+ Each delegated call leaves provenance evidence in the parent chat: the
90
+ specialist's token usage is recorded next to the tool answer, so token costs
91
+ can be traced afterwards with `scout-ai llm prov --evidence`. See the
92
+ [developer provenance guide](../developer/Provenance.md) for details.
93
+
94
+ ---
95
+
96
+ ## Named hand-off tools (delegate)
97
+
98
+ `delegate` creates a specific tool for a pre-loaded agent:
99
+
100
+ ```ruby
101
+ worker = LLM.load_agent('Worker')
102
+ agent.delegate(worker, :worker, "Delegate work to the Worker agent")
103
+ ```
104
+
105
+ This creates a tool called `hand_off_to_worker`. The model calls it with a
106
+ `message` parameter.
107
+
108
+ ### Custom delegation blocks
109
+
110
+ You can customize what happens when the tool is called:
111
+
112
+ ```ruby
113
+ agent.delegate(worker, :worker, "Delegate to Worker") do |_name, params|
114
+ worker.start if params[:new_conversation]
115
+ worker.user params[:message]
116
+ worker.chat
117
+ end
118
+ ```
119
+
120
+ ---
121
+
122
+ ## `socialize` vs `delegate`
123
+
124
+ | Aspect | `socialize` | `delegate` |
125
+ |--------|------------|------------|
126
+ | Agent selection | Model chooses at call time | Hard-coded at registration |
127
+ | Tool count | One `ask` tool for all agents | One tool per agent |
128
+ | Conversation management | Named conversations via `conversation` param | Single conversation, resettable |
129
+ | Flexibility | High (model decides) | Controlled (you decide) |
130
+
131
+ **Rule of thumb:** Use `socialize` when the model should decide delegation
132
+ dynamically. Use `delegate` when you want explicit control over which agents
133
+ are available.
134
+
135
+ ---
136
+
137
+ ## Security: safe delegation
138
+
139
+ When the model delegates, it provides a prompt string. Scout-AI uses a safe
140
+ method to send this prompt to the specialist — it adds it as a plain user
141
+ message, not as chat-file syntax. This prevents the model from injecting
142
+ control directives (like `tool:` or `system:`) into the specialist's
143
+ conversation.
144
+
145
+ This is important: it means delegation is safe even if the model produces
146
+ untrusted output.
147
+
148
+ ---
149
+
150
+ ## Building a multi-agent system
151
+
152
+ A typical pattern:
153
+
154
+ 1. **Create specialist agents** — each in its own directory with a `start_chat`
155
+ and optional workflow.
156
+
157
+ 2. **Create an orchestrator agent** — its `start_chat` describes the task and
158
+ the available specialists.
159
+
160
+ 3. **Enable delegation** — call `socialize` or `delegate` on the orchestrator.
161
+
162
+ ```ruby
163
+ # Orchestrator
164
+ orchestrator = LLM.load_agent('Manager')
165
+ orchestrator.socialize
166
+ orchestrator.start
167
+ orchestrator.user "Plan and execute a data analysis pipeline."
168
+ orchestrator.chat
169
+ ```
170
+
171
+ The model can now delegate sub-tasks to any specialist by name.
172
+
173
+ ---
174
+
175
+ ## Common mistakes
176
+
177
+ - **Forgetting to call `socialize` or `delegate`**: Without one of these, the
178
+ model has no tool to delegate with.
179
+ - **Expecting specialists to share the orchestrator's tools by default**: Only
180
+ if `inherit` is `tools` or `conversation`. With `none`, specialists are
181
+ isolated.
182
+ - **Using `conversation: 'current'`**: This is a legacy value. Use explicit
183
+ conversation names or omit the parameter.
184
+
185
+ ---
186
+
187
+ ## Next steps
188
+
189
+ - [MultiAgentWorkflows.md](MultiAgentWorkflows.md) — orchestration patterns.
190
+ - [BuildingAgents.md](BuildingAgents.md) — creating agents.
191
+ - [ManagingContext.md](ManagingContext.md) — how delegation affects context.