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,159 @@
1
+ # Python Tasks for Agents
2
+
3
+ This page explains how to write agent tools in Python. It is intended for
4
+ workflow authors who want to use Python libraries for specific tasks while
5
+ keeping agent orchestration in Scout-AI.
6
+
7
+ **You should read this if:** you have Python code or libraries you want to
8
+ expose as agent tools.
9
+
10
+ ---
11
+
12
+ ## The idea
13
+
14
+ A Scout-AI agent is a directory. If that directory contains a `python/`
15
+ subdirectory with `.py` files, Scout-AI automatically loads those files as
16
+ workflow tasks — exactly like Ruby workflow tasks.
17
+
18
+ This lets you:
19
+ - Keep **agent orchestration** in Scout-AI and Ruby.
20
+ - Write **task logic** in Python with full access to Python libraries.
21
+
22
+ ---
23
+
24
+ ## Agent directory layout
25
+
26
+ ```text
27
+ MyAgent/
28
+ ├── start_chat # system prompt
29
+ └── python/
30
+ ├── search.py # Python tasks
31
+ └── summarize.py
32
+ ```
33
+
34
+ No `workflow.rb` file is needed if Python tasks are sufficient.
35
+
36
+ ---
37
+
38
+ ## Writing a Python task
39
+
40
+ Create a Python function with type hints and register it with `scout.task()`:
41
+
42
+ ```python
43
+ # python/greet.py
44
+ import scout
45
+
46
+ def greet(name: str, excited: bool = False) -> str:
47
+ """
48
+ Generate a greeting.
49
+
50
+ Args:
51
+ name: Name of the person to greet.
52
+ excited: Whether to add an exclamation mark.
53
+
54
+ Returns:
55
+ Greeting text.
56
+ """
57
+ return f"Hello, {name}{'!' if excited else ''}"
58
+
59
+ scout.task(greet)
60
+ ```
61
+
62
+ Each `.py` file directly under `python/` is auto-loaded. A single file can
63
+ register multiple functions.
64
+
65
+ ---
66
+
67
+ ## Using the agent
68
+
69
+ Once the directory is set up, load the agent normally:
70
+
71
+ ```ruby
72
+ require 'scout-ai'
73
+
74
+ agent = LLM::Agent.load_agent('MyAgent', endpoint: :openai)
75
+ agent.start
76
+ agent.user 'Greet Alice using your tool'
77
+ puts agent.chat
78
+ ```
79
+
80
+ The Python tasks are available as tools through the workflow auto-export
81
+ mechanism. The model can call them just like any other tool.
82
+
83
+ From the CLI:
84
+
85
+ ```bash
86
+ scout-ai agent ask MyAgent "Greet Alice"
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Guidelines for good Python tasks
92
+
93
+ A good Python task is a clean, standalone function:
94
+
95
+ - Use **explicit type hints** — they become the tool's parameter schema.
96
+ - Use **sensible defaults** for optional parameters.
97
+ - Write a **docstring** with an `Args:` section — it becomes the tool
98
+ description.
99
+ - Return **plain strings, lists, or JSON-serializable objects**.
100
+ - Keep **side effects explicit and minimal**.
101
+
102
+ Example:
103
+
104
+ ```python
105
+ import scout
106
+
107
+ def top_words(text: str, limit: int = 10) -> list[str]:
108
+ """
109
+ Return the most frequent words in a text.
110
+
111
+ Args:
112
+ text: Input text to analyze.
113
+ limit: Maximum number of words to return.
114
+
115
+ Returns:
116
+ A list of the most frequent words.
117
+ """
118
+ counts = {}
119
+ for word in text.lower().split():
120
+ counts[word] = counts.get(word, 0) + 1
121
+ return [w for w, _ in sorted(counts.items(), key=lambda kv: (-kv[1], kv[0]))[:limit]]
122
+
123
+ scout.task(top_words)
124
+ ```
125
+
126
+ ---
127
+
128
+ ## When to use Python tasks
129
+
130
+ Use Python when:
131
+ - The logic is **easier in Python** (data processing, ML, scientific computing).
132
+ - You need **specific Python libraries** (pandas, numpy, scikit-learn, etc.).
133
+ - The task is a **standalone function** with typed inputs and a structured
134
+ return.
135
+
136
+ Keep the **orchestration** (agent loops, delegation, conversation management)
137
+ in Ruby/Scout-AI. Use Python for the **leaf tasks** that benefit from Python
138
+ libraries.
139
+
140
+ ---
141
+
142
+ ## Common mistakes
143
+
144
+ - **Putting files in subdirectories**: Only `.py` files directly under
145
+ `python/` are auto-loaded. Don't nest them further.
146
+ - **Forgetting `scout.task()`**: Without registration, the function is not
147
+ exposed as a tool.
148
+ - **Missing type hints**: The model needs type information to know how to call
149
+ the tool. Without hints, parameters may not be properly described.
150
+ - **Not using docstrings**: The docstring becomes the tool description shown to
151
+ the model. Without it, the model doesn't know what the tool does.
152
+
153
+ ---
154
+
155
+ ## Next steps
156
+
157
+ - [BuildingAgents.md](BuildingAgents.md) — agent lifecycle and Ruby tools.
158
+ - [ToolCalling.md](ToolCalling.md) — how tools are declared and called.
159
+ - [WritingChats.md](WritingChats.md) — the chat file format.
@@ -0,0 +1,200 @@
1
+ # Running Inference
2
+
3
+ This page explains how to configure inference endpoints, choose models, and
4
+ run conversations from the CLI or Ruby. It is intended for workflow authors who
5
+ need to connect Scout-AI to LLM providers.
6
+
7
+ **You should read this if:** you want to configure which LLM provider and model
8
+ your agents and chats use.
9
+
10
+ ---
11
+
12
+ ## What an endpoint is
13
+
14
+ An **endpoint** is a named configuration that bundles a provider, a model, and
15
+ credentials. You configure endpoints once and reference them by name.
16
+
17
+ Endpoints solve a portability problem: your agent code and chat files stay the
18
+ same regardless of whether you're using OpenAI, Anthropic, or a local model.
19
+
20
+ ---
21
+
22
+ ## Configuring endpoints
23
+
24
+ Endpoints are stored in Scout config. The simplest way is the CLI:
25
+
26
+ ```bash
27
+ # OpenAI (uses OPENAI_API_KEY env var)
28
+ scout-ai config set openai model=gpt-4o
29
+
30
+ # Anthropic
31
+ scout-ai config set anthropic provider=anthropic model=claude-sonnet-4-20250514
32
+
33
+ # Local model via Ollama
34
+ scout-ai config set local ollama model=qwen2.5:14b url=http://localhost:11434/v1
35
+ ```
36
+
37
+ You can also edit the config file directly. Endpoint configs live under their
38
+ own section:
39
+
40
+ ```ini
41
+ [openai]
42
+ model = gpt-4o
43
+
44
+ [anthropic]
45
+ provider = anthropic
46
+ model = claude-sonnet-4-20250514
47
+
48
+ [local]
49
+ provider = ollama
50
+ model = qwen2.5:14b
51
+ url = http://localhost:11434/v1
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Using endpoints
57
+
58
+ ### From the CLI
59
+
60
+ ```bash
61
+ # Use the default endpoint
62
+ scout-ai llm ask "Hello"
63
+
64
+ # Use a specific endpoint
65
+ scout-ai llm ask -e anthropic "Hello"
66
+
67
+ # Use a specific model on an endpoint
68
+ scout-ai llm ask -e openai -m gpt-4o-mini "Hello"
69
+ ```
70
+
71
+ ### From Ruby
72
+
73
+ ```ruby
74
+ # Reference an endpoint by name
75
+ agent = LLM.agent(endpoint: :anthropic)
76
+
77
+ # Or set inline
78
+ agent = LLM.agent
79
+ agent.option :endpoint, :anthropic
80
+ agent.option :model, 'claude-sonnet-4-20250514'
81
+ ```
82
+
83
+ ### In chat files
84
+
85
+ ```text
86
+ endpoint: anthropic
87
+ model: claude-sonnet-4-20250514
88
+ ```
89
+
90
+ These are sticky options — they persist across the conversation.
91
+
92
+ ---
93
+
94
+ ## Supported providers
95
+
96
+ Scout-AI supports several providers out of the box:
97
+
98
+ | Provider | Key | Notes |
99
+ |----------|-----|-------|
100
+ | OpenAI | `openai` | GPT models, uses `OPENAI_API_KEY` |
101
+ | Anthropic | `anthropic` | Claude models, uses `ANTHROPIC_API_KEY` |
102
+ | Ollama | `ollama` | Local models via Ollama API |
103
+ | OpenAI-compatible | (custom) | Any server exposing the OpenAI API format (vLLM, etc.) |
104
+
105
+ ### Setting API keys
106
+
107
+ ```bash
108
+ export OPENAI_API_KEY="sk-..."
109
+ export ANTHROPIC_API_KEY="sk-ant-..."
110
+ ```
111
+
112
+ For local models (Ollama, vLLM), no API key is typically needed.
113
+
114
+ ---
115
+
116
+ ## Caching
117
+
118
+ By default, Scout-AI caches inference results. This means:
119
+
120
+ - Asking the same question twice returns the cached answer instantly.
121
+ - Workflow jobs that produce the same chat are not re-run.
122
+ - You can reproduce results deterministically.
123
+
124
+ To disable caching for a specific call:
125
+
126
+ ```ruby
127
+ agent.option :persist, false
128
+ ```
129
+
130
+ ---
131
+
132
+ ## Choosing the right model
133
+
134
+ | Use case | Suggested approach |
135
+ |----------|-------------------|
136
+ | Fast, cheap interactions | GPT-4o-mini, Claude Haiku, or a small local model |
137
+ | Complex reasoning | GPT-4o, Claude Sonnet/Opus |
138
+ | Code generation | GPT-4o, Claude Sonnet |
139
+ | Local / offline | Ollama with Qwen2.5 or Llama 3.1 |
140
+
141
+ The model is configured per-endpoint but can be overridden per-call:
142
+
143
+ ```bash
144
+ scout-ai llm ask -e openai -m gpt-4o-mini "Quick question"
145
+ ```
146
+
147
+ ---
148
+
149
+ ## The inference flow
150
+
151
+ When you call `agent.chat` or `scout-ai llm ask`, Scout-AI:
152
+
153
+ 1. Collects the messages (from the chat file or agent state).
154
+ 2. Applies any context management (see [ManagingContext.md](ManagingContext.md)).
155
+ 3. Formats the messages for the provider's API.
156
+ 4. Sends to the endpoint.
157
+ 5. If the model calls a tool, executes it and re-sends (automatic).
158
+ 6. Returns the final text response.
159
+
160
+ This is all automatic. You configure the endpoint and model; Scout-AI handles
161
+ the rest.
162
+
163
+ Persistence, however, differs slighly between the two CLIs:
164
+
165
+ - `scout-ai agent ask ... -c <chat>` sets the agent's `save_file` to
166
+ `<chat>.files/<name>.chat` (`agent.chat` by default; a named agent writes
167
+ `worker.chat`), runs the agent through `agent.chat` (so the
168
+ auto-save hook fires), and also appends the new messages to `<chat>`
169
+ itself — a dual write. The `agent.chat` should contain also the agent
170
+ instructions. Delegated society conversations, when they exist, are written
171
+ under `<chat>.files/<name>.society/<agent>/<conversation>/agent.chat`
172
+ (older versions used `<chat>.files/log/agent.chat` and
173
+ `<chat>.files/log/society/…`; those files are still read by provenance but
174
+ never written or migrated).
175
+ - `scout-ai llm ask ... -c <chat>` accepts an `agent_save_file:` option
176
+ internally, but `LLM.ask` currently extracts that option and drops it
177
+ without applying it, unless an agent is defined inside the chat, in which
178
+ case that agent will get configured with the `save_file`.
179
+
180
+ ---
181
+
182
+ ## Common mistakes
183
+
184
+ - **Forgetting to set the API key**: The most common error. Make sure the
185
+ environment variable matches your provider.
186
+ - **Using the wrong endpoint name**: Endpoint names are case-sensitive and must
187
+ match your config.
188
+ - **Expecting streaming by default**: Streaming is available but not enabled
189
+ by default. Check the CLI flags or Ruby options.
190
+ - **Not realizing caching is on**: If you're not seeing new responses to the
191
+ same question, it may be cached. Use `persist: false` to bypass.
192
+
193
+ ---
194
+
195
+ ## Next steps
196
+
197
+ - [ManagingContext.md](ManagingContext.md) — what happens when conversations
198
+ get long.
199
+ - [BuildingAgents.md](BuildingAgents.md) — agents with persistent endpoints.
200
+ - [ToolCalling.md](ToolCalling.md) — tools during inference.
@@ -0,0 +1,193 @@
1
+ # Tool Calling
2
+
3
+ This page explains how to give Scout-AI agents and chats access to callable
4
+ tools. It is intended for workflow authors who want the LLM to query data,
5
+ run code, or interact with external systems during inference.
6
+
7
+ **You should read this if:** you want the model to do more than generate text.
8
+
9
+ ---
10
+
11
+ ## What tools are
12
+
13
+ Tools are functions the LLM can call during inference. When a tool is
14
+ available, the model sees its name, description, and parameter schema. If the
15
+ model decides to call the tool, Scout-AI executes it, appends the result to the
16
+ conversation, and re-sends the conversation so the model can use the result.
17
+
18
+ Scout-AI supports three kinds of tools:
19
+
20
+ | Kind | How to declare | What it provides |
21
+ |------|---------------|-----------------|
22
+ | **Workflow tools** | `tool:` / `introduce:` in chat, or auto-wired from agent workflow | Typed tasks from a Scout Workflow |
23
+ | **Knowledge base tools** | `kb:` in chat | Database lookups |
24
+ | **MCP tools** | `mcp:` in chat | Any MCP-compatible external server |
25
+
26
+ ---
27
+
28
+ ## Workflow tools
29
+
30
+ A Scout Workflow is a module of tasks with typed inputs and outputs. When you
31
+ expose a workflow as tools, each task becomes a callable function.
32
+
33
+ ### Exposing an entire workflow
34
+
35
+ ```text
36
+ introduce: MyWorkflow
37
+ ```
38
+
39
+ This auto-generates a tool definition for every task in the workflow. The model
40
+ can call any task, providing inputs as arguments.
41
+
42
+ ### Exposing a specific task
43
+
44
+ ```text
45
+ tool: MyWorkflow my_task input1=value1 input2=value2
46
+ ```
47
+
48
+ This exposes only `my_task` from `MyWorkflow`, with some inputs pre-filled.
49
+
50
+ ### How it works
51
+
52
+ When the model calls a workflow tool:
53
+
54
+ 1. Scout-AI runs the task as a workflow job.
55
+ 2. The job goes through Scout's dependency resolution and caching.
56
+ 3. The result is converted to text and returned as a tool output message.
57
+ 4. The model sees the result and continues.
58
+
59
+ ### Inline workflow definition
60
+
61
+ In Ruby, you can define a workflow inline on an agent:
62
+
63
+ ```ruby
64
+ agent.workflow do
65
+ task :search => :string do |query|
66
+ # your search logic here
67
+ "Results for: #{query}"
68
+ end
69
+
70
+ task :save => :string do |path, content|
71
+ File.write(path, content)
72
+ "Saved to #{path}"
73
+ end
74
+ end
75
+ ```
76
+
77
+ The model can now call `search` and `save` as tools.
78
+
79
+ ---
80
+
81
+ ## Knowledge base tools
82
+
83
+ If your agent or chat has a knowledge base, its databases become tools the
84
+ model can query.
85
+
86
+ ```text
87
+ kb: my_database [genes proteins interactions]
88
+ ```
89
+
90
+ This exposes two tools per database:
91
+ - `my_database(entities: [...])` — find related entities.
92
+ - `my_database_association_details(entities: [...])` — get association details.
93
+
94
+ ### From an agent
95
+
96
+ ```ruby
97
+ agent = LLM::Agent.new(knowledge_base: 'my_kb')
98
+ ```
99
+
100
+ The KB's databases are automatically wired as tools.
101
+
102
+ ---
103
+
104
+ ## MCP tools
105
+
106
+ The Model Context Protocol (MCP) is an open standard for exposing tools to
107
+ LLMs. Scout-AI can connect to any MCP server.
108
+
109
+ ### HTTP MCP server
110
+
111
+ ```text
112
+ mcp: https://api.example.com/mcp/
113
+ ```
114
+
115
+ ### Stdio MCP server
116
+
117
+ ```text
118
+ mcp: stdio my-mcp-command arg1 arg2
119
+ ```
120
+
121
+ ### Selecting specific tools
122
+
123
+ ```text
124
+ mcp: https://api.example.com/mcp/ [search write_file]
125
+ ```
126
+
127
+ Only the named tools will be available.
128
+
129
+ ---
130
+
131
+ ## Tool calling in action
132
+
133
+ When a tool is called, the conversation grows with two messages:
134
+
135
+ ```text
136
+ function_call: {"name":"search","arguments":{"query":"ruby blocks"},"id":"call_1"}
137
+ function_call_output: {"id":"call_1","content":"Ruby blocks are..."}
138
+ ```
139
+
140
+ The tool-calling loop is automatic. If the model calls multiple tools in one
141
+ turn, or calls a tool and then needs to call another, Scout-AI handles the
142
+ iteration until the model responds with plain text.
143
+
144
+ ---
145
+
146
+ ## Controlling tool behavior
147
+
148
+ ### Forcing a tool call
149
+
150
+ ```ruby
151
+ agent.option :tool_choice, {type: 'function', function: {name: 'search'}}
152
+ ```
153
+
154
+ ### Clearing tools
155
+
156
+ ```text
157
+ clear_tools: true
158
+ ```
159
+
160
+ ---
161
+
162
+ ## When to use tools vs. direct code
163
+
164
+ Tools are for things the **model** should decide to do. If you know you need a
165
+ piece of data before inference, just put it in the chat as a file or user
166
+ message. Use tools when:
167
+
168
+ - The model needs to **decide** whether to look something up.
169
+ - The model needs to **iterate** — call a tool, see results, call another.
170
+ - The operation is **expensive** and should only run when needed.
171
+ - You want the **provenance** of tool calls recorded in the chat history.
172
+
173
+ ---
174
+
175
+ ## Common mistakes
176
+
177
+ - **Declaring tools but forgetting the workflow**: If you write
178
+ `introduce: MyWorkflow` but the workflow is not on the agent's load path,
179
+ the tools won't resolve.
180
+ - **Expecting tool results to be structured**: Tool results are always
181
+ converted to text before being shown to the model. If you need structured
182
+ data, use JSON format and tell the model to expect it.
183
+ - **Overloading the model with too many tools**: Each tool adds to the context
184
+ size. Introduce only the workflows relevant to the task.
185
+
186
+ ---
187
+
188
+ ## Next steps
189
+
190
+ - [BuildingAgents.md](BuildingAgents.md) — how agents auto-wire tools.
191
+ - [RunningInference.md](RunningInference.md) — endpoint and model configuration.
192
+ - [ManagingContext.md](ManagingContext.md) — what happens when tool calls
193
+ accumulate and the context gets long.