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.
- checksums.yaml +4 -4
- data/.vimproject +138 -50
- data/README.md +171 -290
- data/Rakefile +17 -1
- data/VERSION +1 -1
- data/doc/Improvements.md +325 -0
- data/doc/StartHere.md +110 -0
- data/doc/developer/Architecture.md +126 -0
- data/doc/developer/Backends.md +199 -0
- data/doc/developer/ChatLifecycle.md +183 -0
- data/doc/developer/DelegationInternals.md +295 -0
- data/doc/developer/DesignPrinciples.md +245 -0
- data/doc/developer/PromptProcessing.md +292 -0
- data/doc/developer/Provenance.md +317 -0
- data/doc/user/BuildingAgents.md +345 -0
- data/doc/user/Cookbook.md +333 -0
- data/doc/user/CoreConcepts.md +181 -0
- data/doc/user/Delegation.md +191 -0
- data/doc/user/GettingStarted.md +159 -0
- data/doc/user/ManagingContext.md +163 -0
- data/doc/user/MultiAgentWorkflows.md +256 -0
- data/doc/user/Python.md +159 -0
- data/doc/user/RunningInference.md +200 -0
- data/doc/user/ToolCalling.md +193 -0
- data/doc/user/WritingChats.md +197 -0
- data/lib/scout/llm/agent/chat.rb +61 -11
- data/lib/scout/llm/agent/delegate.rb +274 -65
- data/lib/scout/llm/agent/iterate.rb +2 -2
- data/lib/scout/llm/agent/save.rb +273 -0
- data/lib/scout/llm/agent/workflow.rb +164 -0
- data/lib/scout/llm/agent.rb +86 -61
- data/lib/scout/llm/ask.rb +62 -17
- data/lib/scout/llm/backends/anthropic.rb +9 -2
- data/lib/scout/llm/backends/bedrock.rb +15 -3
- data/lib/scout/llm/backends/default.rb +183 -99
- data/lib/scout/llm/backends/glm.rb +58 -0
- data/lib/scout/llm/backends/huggingface.rb +196 -26
- data/lib/scout/llm/backends/ollama.rb +13 -1
- data/lib/scout/llm/backends/openai.rb +0 -2
- data/lib/scout/llm/backends/openwebui.rb +20 -13
- data/lib/scout/llm/backends/relay.rb +22 -22
- data/lib/scout/llm/backends/responses.rb +1 -1
- data/lib/scout/llm/chat/agent_meta.rb +264 -0
- data/lib/scout/llm/chat/annotation.rb +39 -10
- data/lib/scout/llm/chat/parse.rb +28 -6
- data/lib/scout/llm/chat/persist.rb +25 -0
- data/lib/scout/llm/chat/process/clear.rb +41 -6
- data/lib/scout/llm/chat/process/files.rb +21 -6
- data/lib/scout/llm/chat/process/meta.rb +421 -34
- data/lib/scout/llm/chat/process/options.rb +21 -1
- data/lib/scout/llm/chat/process/tools.rb +56 -15
- data/lib/scout/llm/chat/process.rb +4 -0
- data/lib/scout/llm/chat/prompt/shorten_tools.rb +125 -0
- data/lib/scout/llm/chat/prompt/shorten_tools_epoch.rb +365 -0
- data/lib/scout/llm/chat/prompt.rb +48 -0
- data/lib/scout/llm/chat/provenance.rb +775 -0
- data/lib/scout/llm/chat/tool_calls.rb +76 -0
- data/lib/scout/llm/chat.rb +18 -2
- data/lib/scout/llm/embed.rb +11 -3
- data/lib/scout/llm/image.rb +86 -0
- data/lib/scout/llm/mcp.rb +10 -2
- data/lib/scout/llm/rag.rb +3 -3
- data/lib/scout/llm/tools/call.rb +160 -11
- data/lib/scout/llm/tools/knowledge_base.rb +1 -1
- data/lib/scout/llm/tools/workflow.rb +32 -16
- data/lib/scout/model/python/huggingface/causal.rb +23 -5
- data/lib/scout/model/python/huggingface.rb +2 -1
- data/lib/scout-ai.rb +1 -0
- data/python/README.md +197 -14
- data/python/scout_ai/huggingface/eval.py +245 -34
- data/python/tests/test_huggingface_eval.py +58 -0
- data/research/ChatAnalyst-required-changes.md +167 -0
- data/research/agent-delegation-analysis.md +810 -0
- data/research/agent-meta-provenance-integration-plan.md +622 -0
- data/research/agent-workflow-analysis.md +1120 -0
- data/research/backends-analysis.md +836 -0
- data/research/chat-core-analysis.md +946 -0
- data/research/chatanalyst-provenance/00-baseline.md +30 -0
- data/research/chatanalyst-provenance/01-repo-map.md +60 -0
- data/research/chatanalyst-provenance/02-event-reconstruction.md +55 -0
- data/research/chatanalyst-provenance/03-duplication-evidence.md +45 -0
- data/research/chatanalyst-provenance/04-tooling-root-cause.md +57 -0
- data/research/chatanalyst-provenance/05-fix-plan.md +46 -0
- data/research/chatanalyst-provenance/07-critic-review.md +25 -0
- data/research/chatanalyst-provenance/final-report.md +45 -0
- data/research/chatanalyst-provenance/resumption.md +37 -0
- data/research/coding-philosophy-analysis.md +928 -0
- data/research/commands-analysis.md +947 -0
- data/research/multi-agent-patterns-analysis.md +853 -0
- data/research/prompt-strategies-analysis.md +630 -0
- data/research/prov-verbosity-fix-notes.md +77 -0
- data/research/provenance-analysis.md +469 -0
- data/research/provenance-navigation-design.md +640 -0
- data/research/synthesis-report.md +487 -0
- data/research/tools-system-analysis.md +779 -0
- data/scout-ai.gemspec +100 -11
- data/scout_commands/agent/ask +13 -3
- data/scout_commands/agent/kb +2 -0
- data/scout_commands/llm/ask +11 -4
- data/scout_commands/llm/md +76 -0
- data/scout_commands/llm/process_queries +48 -0
- data/scout_commands/llm/prov +602 -0
- data/scout_commands/llm/word +71 -0
- data/scout_commands/workflow/mcp +43 -0
- data/share/word/reference.docx +0 -0
- data/test/etc/AI/mock.yaml +11 -0
- data/test/fixtures/backends/anthropic.json +19 -0
- data/test/fixtures/backends/anthropic_tool_use.json +24 -0
- data/test/fixtures/backends/bedrock.json +8 -0
- data/test/fixtures/backends/bedrock_embedding.json +3 -0
- data/test/fixtures/backends/bedrock_tool_use.json +17 -0
- data/test/fixtures/backends/ollama.json +16 -0
- data/test/fixtures/backends/ollama_tool_call.json +27 -0
- data/test/fixtures/backends/openai_chat.json +21 -0
- data/test/fixtures/backends/openai_chat_tool_call.json +31 -0
- data/test/fixtures/backends/responses.json +33 -0
- data/test/fixtures/backends/responses_tool_call.json +28 -0
- data/test/integration/README.md +32 -0
- data/test/integration/scout/llm/backends/test_endpoints.rb +34 -0
- data/test/integration/scout/llm/backends/test_openwebui.rb +61 -0
- data/test/integration/scout/llm/backends/test_relay.rb +52 -0
- data/test/integration/scout/llm/test_infrastructure.rb +74 -0
- data/test/{scout → integration/scout}/llm/test_mcp.rb +1 -1
- data/test/integration/scout/llm/tools/test_mcp.rb +42 -0
- data/test/integration/scout/model/test_base.rb +91 -0
- data/test/scout/llm/agent/test_chat.rb +8 -2
- data/test/scout/llm/agent/test_save.rb +413 -0
- data/test/scout/llm/agent/test_workflow.rb +110 -0
- data/test/scout/llm/backends/test_anthropic.rb +93 -10
- data/test/scout/llm/backends/test_bedrock.rb +118 -2
- data/test/scout/llm/backends/test_huggingface.rb +137 -42
- data/test/scout/llm/backends/test_ollama.rb +70 -20
- data/test/scout/llm/backends/test_openwebui.rb +42 -40
- data/test/scout/llm/backends/test_relay.rb +4 -2
- data/test/scout/llm/chat/agent_meta_fixtures.rb +131 -0
- data/test/scout/llm/chat/process/test_meta.rb +518 -0
- data/test/scout/llm/chat/process/test_normalize_usage.rb +183 -0
- data/test/scout/llm/chat/test_agent_meta.rb +357 -0
- data/test/scout/llm/chat/test_agent_meta_provenance.rb +467 -0
- data/test/scout/llm/chat/test_agent_meta_tokens.rb +594 -0
- data/test/scout/llm/chat/test_parse.rb +70 -15
- data/test/scout/llm/chat/test_prov_cli.rb +274 -0
- data/test/scout/llm/chat/test_provenance.rb +240 -0
- data/test/scout/llm/chat/test_tool_calls.rb +38 -0
- data/test/scout/llm/test_agent.rb +13 -36
- data/test/scout/llm/test_ask.rb +75 -52
- data/test/scout/llm/test_chat.rb +107 -13
- data/test/scout/llm/test_embed.rb +48 -0
- data/test/scout/llm/test_rag.rb +23 -16
- data/test/scout/llm/test_tools.rb +12 -1
- data/test/scout/llm/tools/test_knowledge_base.rb +0 -1
- data/test/scout/llm/tools/test_mcp.rb +5 -3
- data/test/scout/llm/tools/test_workflow.rb +23 -2
- data/test/scout/model/python/huggingface/causal/test_next_token.rb +11 -5
- data/test/scout/model/python/huggingface/test_causal.rb +9 -3
- data/test/scout/model/python/huggingface/test_classification.rb +11 -2
- data/test/scout/model/python/test_torch.rb +2 -0
- data/test/scout/model/python/torch/test_helpers.rb +4 -0
- data/test/scout/model/test_base.rb +4 -2
- data/test/support/availability.rb +231 -0
- data/test/support/fake_clients.rb +138 -0
- data/test/support/fixtures.rb +21 -0
- data/test/support/infrastructure_probes.rb +136 -0
- data/test/support/mock_backend.rb +215 -0
- data/test/test_helper.rb +32 -2
- metadata +99 -10
- data/doc/Agent.md +0 -327
- data/doc/Chat.md +0 -458
- data/doc/LLM.md +0 -340
- data/doc/RAG.md +0 -129
- data/scout_commands/documenter +0 -148
- data/test/scout/llm/backends/test_openai.rb +0 -192
- data/test/scout/llm/backends/test_responses.rb +0 -238
- data/test/scout/llm/test_parse.rb +0 -98
data/doc/user/Python.md
ADDED
|
@@ -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.
|