robot_lab 0.0.1 → 0.0.6
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/.github/workflows/deploy-github-pages.yml +9 -9
- data/.irbrc +6 -0
- data/CHANGELOG.md +140 -0
- data/README.md +263 -48
- data/Rakefile +71 -1
- data/docs/api/core/index.md +53 -46
- data/docs/api/core/memory.md +200 -154
- data/docs/api/core/network.md +13 -3
- data/docs/api/core/robot.md +490 -130
- data/docs/api/core/state.md +55 -73
- data/docs/api/core/tool.md +205 -209
- data/docs/api/index.md +7 -28
- data/docs/api/mcp/client.md +119 -48
- data/docs/api/mcp/index.md +75 -60
- data/docs/api/mcp/server.md +120 -136
- data/docs/api/mcp/transports.md +172 -184
- data/docs/api/messages/index.md +35 -20
- data/docs/api/messages/text-message.md +67 -21
- data/docs/api/messages/tool-call-message.md +80 -41
- data/docs/api/messages/tool-result-message.md +119 -50
- data/docs/api/messages/user-message.md +48 -24
- data/docs/api/streaming/context.md +157 -74
- data/docs/api/streaming/events.md +114 -166
- data/docs/api/streaming/index.md +74 -72
- data/docs/architecture/core-concepts.md +360 -116
- data/docs/architecture/index.md +97 -59
- data/docs/architecture/message-flow.md +138 -129
- data/docs/architecture/network-orchestration.md +197 -50
- data/docs/architecture/robot-execution.md +199 -146
- data/docs/architecture/state-management.md +255 -187
- data/docs/concepts.md +311 -49
- data/docs/examples/basic-chat.md +89 -77
- data/docs/examples/index.md +222 -47
- data/docs/examples/mcp-server.md +207 -203
- data/docs/examples/multi-robot-network.md +129 -35
- data/docs/examples/rails-application.md +159 -160
- data/docs/examples/tool-usage.md +295 -204
- data/docs/getting-started/configuration.md +347 -154
- data/docs/getting-started/index.md +1 -1
- data/docs/getting-started/installation.md +22 -13
- data/docs/getting-started/quick-start.md +166 -121
- data/docs/guides/building-robots.md +418 -212
- data/docs/guides/creating-networks.md +143 -24
- data/docs/guides/index.md +0 -5
- data/docs/guides/mcp-integration.md +152 -113
- data/docs/guides/memory.md +220 -164
- data/docs/guides/rails-integration.md +244 -162
- data/docs/guides/streaming.md +137 -187
- data/docs/guides/using-tools.md +259 -212
- data/docs/index.md +46 -41
- data/examples/01_simple_robot.rb +6 -9
- data/examples/02_tools.rb +6 -9
- data/examples/03_network.rb +19 -17
- data/examples/04_mcp.rb +5 -8
- data/examples/05_streaming.rb +5 -8
- data/examples/06_prompt_templates.rb +42 -37
- data/examples/07_network_memory.rb +13 -14
- data/examples/08_llm_config.rb +169 -0
- data/examples/09_chaining.rb +262 -0
- data/examples/10_memory.rb +331 -0
- data/examples/11_network_introspection.rb +253 -0
- data/examples/12_message_bus.rb +74 -0
- data/examples/13_spawn.rb +90 -0
- data/examples/14_rusty_circuit/comic.rb +143 -0
- data/examples/14_rusty_circuit/display.rb +203 -0
- data/examples/14_rusty_circuit/heckler.rb +63 -0
- data/examples/14_rusty_circuit/open_mic.rb +123 -0
- data/examples/14_rusty_circuit/prompts/open_mic_comic.md +20 -0
- data/examples/14_rusty_circuit/prompts/open_mic_heckler.md +23 -0
- data/examples/14_rusty_circuit/prompts/open_mic_scout.md +20 -0
- data/examples/14_rusty_circuit/scout.rb +156 -0
- data/examples/14_rusty_circuit/scout_notes.md +89 -0
- data/examples/14_rusty_circuit/show.log +234 -0
- data/examples/15_memory_network_and_bus/editor_in_chief.rb +24 -0
- data/examples/15_memory_network_and_bus/editorial_pipeline.rb +206 -0
- data/examples/15_memory_network_and_bus/linux_writer.rb +80 -0
- data/examples/15_memory_network_and_bus/os_editor.rb +46 -0
- data/examples/15_memory_network_and_bus/os_writer.rb +46 -0
- data/examples/15_memory_network_and_bus/output/combined_article.md +13 -0
- data/examples/15_memory_network_and_bus/output/final_article.md +15 -0
- data/examples/15_memory_network_and_bus/output/linux_draft.md +5 -0
- data/examples/15_memory_network_and_bus/output/mac_draft.md +7 -0
- data/examples/15_memory_network_and_bus/output/memory.json +13 -0
- data/examples/15_memory_network_and_bus/output/revision_1.md +19 -0
- data/examples/15_memory_network_and_bus/output/revision_2.md +15 -0
- data/examples/15_memory_network_and_bus/output/windows_draft.md +7 -0
- data/examples/15_memory_network_and_bus/prompts/os_advocate.md +13 -0
- data/examples/15_memory_network_and_bus/prompts/os_chief.md +13 -0
- data/examples/15_memory_network_and_bus/prompts/os_editor.md +13 -0
- data/examples/16_writers_room/display.rb +158 -0
- data/examples/16_writers_room/output/.gitignore +2 -0
- data/examples/16_writers_room/output/opus_001.md +263 -0
- data/examples/16_writers_room/output/opus_001_notes.log +470 -0
- data/examples/16_writers_room/prompts/writer.md +37 -0
- data/examples/16_writers_room/room.rb +150 -0
- data/examples/16_writers_room/tools.rb +162 -0
- data/examples/16_writers_room/writer.rb +121 -0
- data/examples/16_writers_room/writers_room.rb +162 -0
- data/examples/README.md +197 -0
- data/examples/prompts/{assistant/system.txt.erb → assistant.md} +3 -0
- data/examples/prompts/{billing/system.txt.erb → billing.md} +3 -0
- data/examples/prompts/{classifier/system.txt.erb → classifier.md} +3 -0
- data/examples/prompts/comedian.md +6 -0
- data/examples/prompts/comedy_critic.md +10 -0
- data/examples/prompts/configurable.md +9 -0
- data/examples/prompts/dispatcher.md +12 -0
- data/examples/prompts/{entity_extractor/system.txt.erb → entity_extractor.md} +3 -0
- data/examples/prompts/{escalation/system.txt.erb → escalation.md} +7 -0
- data/examples/prompts/frontmatter_mcp_test.md +9 -0
- data/examples/prompts/frontmatter_named_test.md +5 -0
- data/examples/prompts/frontmatter_tools_test.md +6 -0
- data/examples/prompts/{general/system.txt.erb → general.md} +3 -0
- data/examples/prompts/{github_assistant/system.txt.erb → github_assistant.md} +8 -0
- data/examples/prompts/{helper/system.txt.erb → helper.md} +3 -0
- data/examples/prompts/{keyword_extractor/system.txt.erb → keyword_extractor.md} +3 -0
- data/examples/prompts/llm_config_demo.md +20 -0
- data/examples/prompts/{order_support/system.txt.erb → order_support.md} +8 -0
- data/examples/prompts/os_advocate.md +13 -0
- data/examples/prompts/os_chief.md +13 -0
- data/examples/prompts/os_editor.md +13 -0
- data/examples/prompts/{product_support/system.txt.erb → product_support.md} +7 -0
- data/examples/prompts/{sentiment_analyzer/system.txt.erb → sentiment_analyzer.md} +3 -0
- data/examples/prompts/{synthesizer/system.txt.erb → synthesizer.md} +3 -0
- data/examples/prompts/{technical/system.txt.erb → technical.md} +3 -0
- data/examples/prompts/{triage/system.txt.erb → triage.md} +6 -0
- data/lib/generators/robot_lab/templates/initializer.rb.tt +0 -13
- data/lib/robot_lab/ask_user.rb +75 -0
- data/lib/robot_lab/config/defaults.yml +121 -0
- data/lib/robot_lab/config.rb +183 -0
- data/lib/robot_lab/error.rb +6 -0
- data/lib/robot_lab/mcp/client.rb +1 -1
- data/lib/robot_lab/memory.rb +10 -34
- data/lib/robot_lab/network.rb +13 -20
- data/lib/robot_lab/robot/bus_messaging.rb +239 -0
- data/lib/robot_lab/robot/mcp_management.rb +88 -0
- data/lib/robot_lab/robot/template_rendering.rb +130 -0
- data/lib/robot_lab/robot.rb +240 -330
- data/lib/robot_lab/robot_message.rb +44 -0
- data/lib/robot_lab/robot_result.rb +1 -0
- data/lib/robot_lab/run_config.rb +184 -0
- data/lib/robot_lab/state_proxy.rb +2 -12
- data/lib/robot_lab/streaming/context.rb +1 -1
- data/lib/robot_lab/task.rb +8 -1
- data/lib/robot_lab/tool.rb +108 -172
- data/lib/robot_lab/tool_config.rb +1 -1
- data/lib/robot_lab/tool_manifest.rb +2 -18
- data/lib/robot_lab/utils.rb +39 -0
- data/lib/robot_lab/version.rb +1 -1
- data/lib/robot_lab.rb +89 -57
- data/mkdocs.yml +0 -11
- metadata +121 -135
- data/docs/api/adapters/anthropic.md +0 -121
- data/docs/api/adapters/gemini.md +0 -133
- data/docs/api/adapters/index.md +0 -104
- data/docs/api/adapters/openai.md +0 -134
- data/docs/api/history/active-record-adapter.md +0 -195
- data/docs/api/history/config.md +0 -191
- data/docs/api/history/index.md +0 -132
- data/docs/api/history/thread-manager.md +0 -144
- data/docs/guides/history.md +0 -359
- data/examples/prompts/assistant/user.txt.erb +0 -1
- data/examples/prompts/billing/user.txt.erb +0 -1
- data/examples/prompts/classifier/user.txt.erb +0 -1
- data/examples/prompts/entity_extractor/user.txt.erb +0 -3
- data/examples/prompts/escalation/user.txt.erb +0 -34
- data/examples/prompts/general/user.txt.erb +0 -1
- data/examples/prompts/github_assistant/user.txt.erb +0 -1
- data/examples/prompts/helper/user.txt.erb +0 -1
- data/examples/prompts/keyword_extractor/user.txt.erb +0 -3
- data/examples/prompts/order_support/user.txt.erb +0 -22
- data/examples/prompts/product_support/user.txt.erb +0 -32
- data/examples/prompts/sentiment_analyzer/user.txt.erb +0 -3
- data/examples/prompts/synthesizer/user.txt.erb +0 -15
- data/examples/prompts/technical/user.txt.erb +0 -1
- data/examples/prompts/triage/user.txt.erb +0 -17
- data/lib/robot_lab/adapters/anthropic.rb +0 -163
- data/lib/robot_lab/adapters/base.rb +0 -85
- data/lib/robot_lab/adapters/gemini.rb +0 -193
- data/lib/robot_lab/adapters/openai.rb +0 -159
- data/lib/robot_lab/adapters/registry.rb +0 -81
- data/lib/robot_lab/configuration.rb +0 -143
- data/lib/robot_lab/errors.rb +0 -70
- data/lib/robot_lab/history/active_record_adapter.rb +0 -146
- data/lib/robot_lab/history/config.rb +0 -115
- data/lib/robot_lab/history/thread_manager.rb +0 -93
- data/lib/robot_lab/robotic_model.rb +0 -324
|
@@ -4,240 +4,293 @@ This page details how a robot processes messages and generates responses.
|
|
|
4
4
|
|
|
5
5
|
## Execution Overview
|
|
6
6
|
|
|
7
|
-
When you call `robot.run(
|
|
7
|
+
When you call `robot.run("message")`, several steps occur:
|
|
8
8
|
|
|
9
9
|
```mermaid
|
|
10
10
|
sequenceDiagram
|
|
11
11
|
participant App as Application
|
|
12
12
|
participant Robot
|
|
13
|
-
participant
|
|
14
|
-
participant
|
|
13
|
+
participant Memory
|
|
14
|
+
participant Chat as @chat (RubyLLM)
|
|
15
15
|
participant LLM
|
|
16
16
|
|
|
17
|
-
App->>Robot: run(
|
|
18
|
-
Robot->>
|
|
19
|
-
Robot->>
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
App->>Robot: run("message")
|
|
18
|
+
Robot->>Memory: resolve_active_memory()
|
|
19
|
+
Robot->>Robot: resolve_mcp_hierarchy()
|
|
20
|
+
Robot->>Robot: resolve_tools_hierarchy()
|
|
21
|
+
Robot->>Robot: ensure_mcp_clients()
|
|
22
|
+
Robot->>Robot: filtered_tools()
|
|
23
|
+
Robot->>Chat: with_tools(*filtered)
|
|
24
|
+
Robot->>Chat: ask("message")
|
|
25
|
+
Chat->>LLM: API Request
|
|
22
26
|
|
|
23
27
|
loop Tool Calls
|
|
24
|
-
LLM-->>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Model->>LLM: continue
|
|
28
|
+
LLM-->>Chat: tool_call response
|
|
29
|
+
Chat->>Chat: execute tool
|
|
30
|
+
Chat->>LLM: tool result
|
|
28
31
|
end
|
|
29
32
|
|
|
30
|
-
LLM-->>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
LLM-->>Chat: final response
|
|
34
|
+
Chat-->>Robot: RubyLLM::Response
|
|
35
|
+
Robot->>Robot: build_result(response)
|
|
33
36
|
Robot-->>App: RobotResult
|
|
34
37
|
```
|
|
35
38
|
|
|
36
39
|
## Step-by-Step Flow
|
|
37
40
|
|
|
38
|
-
### 1.
|
|
41
|
+
### 1. Memory Resolution
|
|
39
42
|
|
|
40
|
-
|
|
43
|
+
The robot determines which memory to use for this run:
|
|
41
44
|
|
|
42
45
|
```ruby
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
# Priority order:
|
|
47
|
+
# 1. Explicit network_memory: parameter
|
|
48
|
+
# 2. Network's memory (if running in a network)
|
|
49
|
+
# 3. Robot's inherent @memory (standalone mode)
|
|
50
|
+
run_memory = resolve_active_memory(network: network, network_memory: network_memory)
|
|
51
|
+
|
|
52
|
+
# Merge runtime memory if provided
|
|
53
|
+
case memory
|
|
54
|
+
when Memory then run_memory = memory
|
|
55
|
+
when Hash then run_memory.merge!(memory)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Track who is writing to memory
|
|
59
|
+
run_memory.current_writer = @name
|
|
48
60
|
```
|
|
49
61
|
|
|
50
|
-
### 2.
|
|
62
|
+
### 2. MCP Hierarchy Resolution
|
|
51
63
|
|
|
52
|
-
|
|
64
|
+
MCP servers are resolved through a hierarchy: **runtime > robot build-time > network > global config**.
|
|
53
65
|
|
|
54
66
|
```ruby
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
67
|
+
# Resolve build-time config against network/global
|
|
68
|
+
parent_value = network&.network&.mcp || RobotLab.config.mcp
|
|
69
|
+
build_resolved = ToolConfig.resolve_mcp(@mcp_config, parent_value: parent_value)
|
|
70
|
+
|
|
71
|
+
# Then resolve runtime override against build-time
|
|
72
|
+
resolved_mcp = ToolConfig.resolve_mcp(runtime_mcp, parent_value: build_resolved)
|
|
59
73
|
```
|
|
60
74
|
|
|
61
|
-
|
|
75
|
+
Values at each level:
|
|
62
76
|
|
|
63
|
-
|
|
77
|
+
- `:none` -- no MCP servers at this level
|
|
78
|
+
- `:inherit` -- use parent level's MCP config
|
|
79
|
+
- `Array` -- explicit list of server configurations
|
|
80
|
+
|
|
81
|
+
### 3. MCP Client Initialization
|
|
82
|
+
|
|
83
|
+
If MCP servers need to be connected (or reconnected), the robot initializes clients:
|
|
64
84
|
|
|
65
85
|
```ruby
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
86
|
+
# Connect to each MCP server
|
|
87
|
+
mcp_servers.each do |server_config|
|
|
88
|
+
client = MCP::Client.new(server_config)
|
|
89
|
+
client.connect
|
|
90
|
+
|
|
91
|
+
if client.connected?
|
|
92
|
+
@mcp_clients[client.server.name] = client
|
|
93
|
+
discover_mcp_tools(client, server_name) # Auto-discover tools
|
|
94
|
+
end
|
|
95
|
+
end
|
|
72
96
|
```
|
|
73
97
|
|
|
74
|
-
### 4.
|
|
98
|
+
### 4. Tools Resolution
|
|
75
99
|
|
|
76
|
-
|
|
100
|
+
Tools are resolved through the same hierarchy and filtered:
|
|
77
101
|
|
|
78
102
|
```ruby
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
break
|
|
88
|
-
end
|
|
89
|
-
end
|
|
103
|
+
# Collect all available tools
|
|
104
|
+
available = @local_tools + @mcp_tools
|
|
105
|
+
|
|
106
|
+
# Apply whitelist if specified
|
|
107
|
+
filtered = ToolConfig.filter_tools(available, allowed_names: resolved_tools)
|
|
108
|
+
|
|
109
|
+
# Apply tools to the persistent chat
|
|
110
|
+
@chat.with_tools(*filtered) if filtered.any?
|
|
90
111
|
```
|
|
91
112
|
|
|
92
|
-
### 5.
|
|
113
|
+
### 5. LLM Inference
|
|
93
114
|
|
|
94
|
-
|
|
115
|
+
The message is sent to the LLM via `Agent#ask`, which delegates to `@chat.ask`:
|
|
95
116
|
|
|
96
117
|
```ruby
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
)
|
|
118
|
+
# Robot#run calls Agent#ask
|
|
119
|
+
response = ask(message, **kwargs)
|
|
120
|
+
|
|
121
|
+
# Internally, Agent#ask calls:
|
|
122
|
+
# @chat.ask(message)
|
|
103
123
|
```
|
|
104
124
|
|
|
105
|
-
|
|
125
|
+
The persistent `@chat` (a `RubyLLM::Chat` instance) handles:
|
|
106
126
|
|
|
107
|
-
|
|
127
|
+
- Maintaining conversation history
|
|
128
|
+
- Sending the system prompt
|
|
129
|
+
- Formatting messages for the provider
|
|
130
|
+
- Executing the tool call loop automatically
|
|
108
131
|
|
|
109
|
-
|
|
132
|
+
### 6. Tool Execution Loop
|
|
110
133
|
|
|
111
|
-
|
|
112
|
-
2. **Validate Input**: Check parameters against schema
|
|
113
|
-
3. **Execute Handler**: Call the tool's handler function
|
|
114
|
-
4. **Capture Result**: Wrap response in ToolResultMessage
|
|
115
|
-
5. **Return to LLM**: Send result for continued processing
|
|
134
|
+
RubyLLM's `@chat` handles the tool loop automatically. When the LLM requests a tool call:
|
|
116
135
|
|
|
117
|
-
|
|
136
|
+
1. `@chat` identifies the tool from its registered tools
|
|
137
|
+
2. Calls the tool's `execute` method (for `RubyLLM::Tool` subclasses) or `call` method (for `RobotLab::Tool`)
|
|
138
|
+
3. Sends the result back to the LLM
|
|
139
|
+
4. Repeats until the LLM produces a final text response
|
|
118
140
|
|
|
119
|
-
|
|
141
|
+
The `on_tool_call` and `on_tool_result` callbacks fire during this loop if configured:
|
|
120
142
|
|
|
121
143
|
```ruby
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
network: network, # Network context
|
|
126
|
-
state: state # Current state
|
|
127
|
-
)
|
|
144
|
+
# These callbacks are registered on @chat during Robot#initialize
|
|
145
|
+
@chat.on_tool_call(&@on_tool_call) if @on_tool_call
|
|
146
|
+
@chat.on_tool_result(&@on_tool_result) if @on_tool_result
|
|
128
147
|
```
|
|
129
148
|
|
|
130
|
-
###
|
|
149
|
+
### 7. Result Construction
|
|
131
150
|
|
|
132
|
-
|
|
151
|
+
After the LLM responds, a `RobotResult` is built:
|
|
133
152
|
|
|
134
153
|
```ruby
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
154
|
+
def build_result(response, _memory)
|
|
155
|
+
output = if response.respond_to?(:content) && response.content
|
|
156
|
+
[TextMessage.new(role: 'assistant', content: response.content)]
|
|
157
|
+
else
|
|
158
|
+
[]
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
tool_calls = response.respond_to?(:tool_calls) ? (response.tool_calls || []) : []
|
|
162
|
+
|
|
163
|
+
RobotResult.new(
|
|
164
|
+
robot_name: @name,
|
|
165
|
+
output: output,
|
|
166
|
+
tool_calls: normalize_tool_calls(tool_calls),
|
|
167
|
+
stop_reason: response.respond_to?(:stop_reason) ? response.stop_reason : nil
|
|
168
|
+
)
|
|
140
169
|
end
|
|
141
170
|
```
|
|
142
171
|
|
|
143
|
-
##
|
|
172
|
+
## RobotResult
|
|
144
173
|
|
|
145
|
-
|
|
174
|
+
The result object from a `robot.run` call:
|
|
146
175
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
176
|
+
```ruby
|
|
177
|
+
result = robot.run("Hello!")
|
|
178
|
+
|
|
179
|
+
result.robot_name # => "assistant"
|
|
180
|
+
result.output # => [TextMessage, ...]
|
|
181
|
+
result.tool_calls # => [ToolResultMessage, ...]
|
|
182
|
+
result.stop_reason # => "stop" or nil
|
|
183
|
+
result.created_at # => Time
|
|
184
|
+
result.id # => UUID string
|
|
185
|
+
|
|
186
|
+
# Convenience methods
|
|
187
|
+
result.last_text_content # => "Hi there!" (last text message content)
|
|
188
|
+
result.has_tool_calls? # => false
|
|
189
|
+
result.stopped? # => true
|
|
190
|
+
```
|
|
152
191
|
|
|
153
192
|
## Streaming
|
|
154
193
|
|
|
155
|
-
Robots support streaming
|
|
194
|
+
Robots support streaming by passing a block to `run`:
|
|
156
195
|
|
|
157
196
|
```ruby
|
|
158
|
-
robot.run(
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
streaming: ->(event) {
|
|
162
|
-
case event.type
|
|
163
|
-
when :delta then print event.content
|
|
164
|
-
when :tool_call then puts "Calling: #{event.tool_name}"
|
|
165
|
-
end
|
|
166
|
-
}
|
|
167
|
-
)
|
|
197
|
+
result = robot.run("Tell me a story") do |event|
|
|
198
|
+
print event.text if event.respond_to?(:text)
|
|
199
|
+
end
|
|
168
200
|
```
|
|
169
201
|
|
|
170
|
-
|
|
202
|
+
The block is forwarded to `Agent#ask` which passes it to `@chat.ask`. Streaming events are provider-specific but typically include text deltas.
|
|
171
203
|
|
|
172
|
-
|
|
173
|
-
|------------|-------------|
|
|
174
|
-
| `run.started` | Robot execution began |
|
|
175
|
-
| `delta` | Text content chunk |
|
|
176
|
-
| `tool_call` | Tool execution starting |
|
|
177
|
-
| `tool_result` | Tool execution complete |
|
|
178
|
-
| `run.completed` | Robot execution finished |
|
|
179
|
-
| `run.failed` | Error occurred |
|
|
204
|
+
## Template Resolution
|
|
180
205
|
|
|
181
|
-
|
|
206
|
+
When a robot has a `template:`, it is resolved during initialization:
|
|
182
207
|
|
|
183
|
-
|
|
208
|
+
```ruby
|
|
209
|
+
# 1. Parse the template via prompt_manager
|
|
210
|
+
parsed = PM.parse(@template)
|
|
184
211
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
212
|
+
# 2. Extract and apply front matter config
|
|
213
|
+
# (model, temperature, top_p, etc.)
|
|
214
|
+
apply_front_matter_config(parsed.metadata)
|
|
188
215
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
model "claude-sonnet-4" # Takes precedence
|
|
192
|
-
end
|
|
216
|
+
# 3. Render the template body with context
|
|
217
|
+
rendered = parsed.to_s(**resolved_context)
|
|
193
218
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
end
|
|
219
|
+
# 4. Set as system instructions on @chat
|
|
220
|
+
@chat.with_instructions(rendered)
|
|
197
221
|
```
|
|
198
222
|
|
|
199
|
-
|
|
223
|
+
### Front Matter Config Keys
|
|
224
|
+
|
|
225
|
+
Templates can configure the chat via YAML front matter:
|
|
200
226
|
|
|
201
|
-
|
|
227
|
+
| Key | Effect |
|
|
228
|
+
|-----|--------|
|
|
229
|
+
| `model` | Sets the LLM model |
|
|
230
|
+
| `temperature` | Sets randomness |
|
|
231
|
+
| `top_p` | Sets nucleus sampling |
|
|
232
|
+
| `top_k` | Sets top-k sampling |
|
|
233
|
+
| `max_tokens` | Sets max response tokens |
|
|
234
|
+
| `presence_penalty` | Sets presence penalty |
|
|
235
|
+
| `frequency_penalty` | Sets frequency penalty |
|
|
236
|
+
| `stop` | Sets stop sequences |
|
|
202
237
|
|
|
203
|
-
|
|
204
|
-
|--------------|----------|
|
|
205
|
-
| `claude-*`, `anthropic-*` | `:anthropic` |
|
|
206
|
-
| `gpt-*`, `o1-*`, `chatgpt-*` | `:openai` |
|
|
207
|
-
| `gemini-*` | `:gemini` |
|
|
208
|
-
| `llama-*`, `mistral-*` | `:ollama` |
|
|
238
|
+
## Model Selection
|
|
209
239
|
|
|
210
|
-
|
|
240
|
+
The model is determined by:
|
|
211
241
|
|
|
212
|
-
|
|
242
|
+
1. Robot's explicit `model:` parameter
|
|
243
|
+
2. Front matter `model` from template
|
|
244
|
+
3. Global `RobotLab.config.ruby_llm.model`
|
|
213
245
|
|
|
214
246
|
```ruby
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
#
|
|
218
|
-
|
|
247
|
+
robot = RobotLab.build(
|
|
248
|
+
name: "bot",
|
|
249
|
+
model: "claude-sonnet-4" # Takes precedence
|
|
250
|
+
)
|
|
219
251
|
|
|
220
|
-
#
|
|
221
|
-
|
|
252
|
+
# Or configure globally via config files / environment variables
|
|
253
|
+
# ROBOT_LAB_RUBY_LLM__MODEL=gpt-4o
|
|
222
254
|
```
|
|
223
255
|
|
|
224
|
-
|
|
256
|
+
## SimpleFlow Integration
|
|
225
257
|
|
|
226
|
-
|
|
258
|
+
When a robot runs inside a network, the `call` method is invoked by SimpleFlow:
|
|
259
|
+
|
|
260
|
+
```mermaid
|
|
261
|
+
sequenceDiagram
|
|
262
|
+
participant SF as SimpleFlow
|
|
263
|
+
participant Task as Task Wrapper
|
|
264
|
+
participant Robot
|
|
265
|
+
participant Chat as @chat
|
|
266
|
+
|
|
267
|
+
SF->>Task: call(result)
|
|
268
|
+
Task->>Task: deep_merge(run_params, task_context)
|
|
269
|
+
Task->>Robot: call(enhanced_result)
|
|
270
|
+
Robot->>Robot: extract_run_context(result)
|
|
271
|
+
Robot->>Robot: message = context.delete(:message)
|
|
272
|
+
Robot->>Robot: run(message, **context)
|
|
273
|
+
Robot->>Chat: ask(message)
|
|
274
|
+
Chat-->>Robot: response
|
|
275
|
+
Robot-->>SF: result.continue(robot_result)
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
The `Task` wrapper deep-merges per-task configuration (context, mcp, tools) before delegating to the robot's `call`. The base `Robot#call` extracts the message and calls `run`:
|
|
227
279
|
|
|
228
280
|
```ruby
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
281
|
+
def call(result)
|
|
282
|
+
run_context = extract_run_context(result)
|
|
283
|
+
message = run_context.delete(:message)
|
|
284
|
+
robot_result = run(message, **run_context)
|
|
285
|
+
|
|
286
|
+
result
|
|
287
|
+
.with_context(@name.to_sym, robot_result)
|
|
288
|
+
.continue(robot_result)
|
|
289
|
+
end
|
|
237
290
|
```
|
|
238
291
|
|
|
239
292
|
## Next Steps
|
|
240
293
|
|
|
241
294
|
- [Network Orchestration](network-orchestration.md) - Multi-robot coordination
|
|
242
|
-
- [
|
|
295
|
+
- [Core Concepts](core-concepts.md) - Fundamental building blocks
|
|
243
296
|
- [Using Tools](../guides/using-tools.md) - Creating and using tools
|