robot_lab 0.2.6 → 0.2.7
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/README.md +124 -64
- data/docs/api/core/index.md +41 -15
- data/docs/api/core/memory.md +247 -29
- data/docs/api/core/network.md +255 -33
- data/docs/api/core/result.md +120 -32
- data/docs/api/core/robot.md +551 -61
- data/docs/api/core/state.md +87 -197
- data/docs/api/core/tool.md +165 -20
- data/docs/api/errors.md +110 -17
- data/docs/api/hooks.md +469 -0
- data/docs/api/index.md +80 -7
- data/docs/api/mcp/client.md +129 -35
- data/docs/api/mcp/index.md +164 -23
- data/docs/api/mcp/server.md +27 -3
- data/docs/api/mcp/transports.md +94 -22
- data/docs/api/messages/index.md +26 -3
- data/docs/api/messages/text-message.md +33 -11
- data/docs/api/messages/tool-call-message.md +27 -4
- data/docs/api/messages/tool-result-message.md +23 -4
- data/docs/api/messages/user-message.md +45 -8
- data/docs/api/skills.md +519 -0
- data/docs/api/streaming/context.md +28 -5
- data/docs/api/streaming/index.md +57 -11
- data/docs/api/support.md +846 -0
- data/docs/architecture/core-concepts.md +79 -31
- data/docs/architecture/index.md +86 -11
- data/docs/architecture/message-flow.md +66 -29
- data/docs/architecture/network-orchestration.md +145 -38
- data/docs/architecture/robot-execution.md +172 -90
- data/docs/architecture/state-management.md +31 -12
- data/docs/concepts.md +176 -21
- data/docs/examples/basic-chat.md +72 -19
- data/docs/examples/index.md +117 -31
- data/docs/examples/mcp-server.md +154 -45
- data/docs/examples/multi-robot-network.md +91 -21
- data/docs/examples/tool-usage.md +104 -37
- data/docs/getting-started/configuration.md +284 -97
- data/docs/getting-started/installation.md +53 -41
- data/docs/getting-started/quick-start.md +51 -6
- data/docs/guides/building-robots.md +258 -50
- data/docs/guides/creating-networks.md +214 -30
- data/docs/guides/hooks.md +141 -54
- data/docs/guides/knowledge.md +35 -4
- data/docs/guides/mcp-integration.md +211 -44
- data/docs/guides/memory.md +103 -12
- data/docs/guides/observability.md +95 -47
- data/docs/guides/streaming.md +184 -125
- data/docs/guides/using-tools.md +237 -17
- data/docs/index.md +36 -4
- data/examples/01_simple_robot.rb +2 -2
- data/examples/02_tools.rb +14 -4
- data/examples/03_network.rb +12 -7
- data/examples/04_mcp.rb +11 -4
- data/examples/05_streaming.rb +8 -5
- data/examples/06_prompt_templates.rb +13 -9
- data/examples/07_network_memory.rb +5 -5
- data/examples/08_llm_config.rb +20 -15
- data/examples/09_chaining.rb +4 -4
- data/examples/11_network_introspection.rb +4 -4
- data/examples/12_message_bus.rb +2 -2
- data/examples/13_spawn.rb +2 -2
- data/examples/14_rusty_circuit/README.md +1 -0
- data/examples/14_rusty_circuit/comic.rb +7 -3
- data/examples/14_rusty_circuit/display.rb +14 -0
- data/examples/14_rusty_circuit/heckler.rb +8 -6
- data/examples/14_rusty_circuit/open_mic.rb +17 -6
- data/examples/14_rusty_circuit/scout.rb +17 -10
- data/examples/15_memory_network_and_bus/editorial_pipeline.rb +14 -10
- data/examples/15_memory_network_and_bus/linux_writer.rb +2 -2
- data/examples/15_memory_network_and_bus/os_editor.rb +3 -1
- data/examples/15_memory_network_and_bus/os_writer.rb +4 -1
- data/examples/16_writers_room/writer.rb +22 -22
- data/examples/16_writers_room/writers_room.rb +2 -0
- data/examples/17_skills.rb +14 -13
- data/examples/18_rails/README.md +20 -1
- data/examples/18_rails/app/controllers/chat_controller.rb +5 -1
- data/examples/18_rails/app/jobs/robot_run_job.rb +11 -5
- data/examples/18_rails/app/robots/chat_robot.rb +11 -0
- data/examples/18_rails/config/initializers/robot_lab.rb +8 -0
- data/examples/19_token_tracking.rb +25 -9
- data/examples/20_circuit_breaker.rb +10 -7
- data/examples/21_learning_loop.rb +42 -16
- data/examples/22_context_compression.rb +23 -23
- data/examples/23_convergence.rb +24 -17
- data/examples/24_structured_delegation.rb +13 -8
- data/examples/25_history_search.rb +12 -8
- data/examples/27_incident_response/incident_response.rb +31 -13
- data/examples/28_mcp_discovery.rb +17 -13
- data/examples/29_ractor_tools.rb +4 -2
- data/examples/30_ractor_network.rb +22 -17
- data/examples/31_launch_assessment.rb +20 -9
- data/examples/32_newsletter_reader.rb +7 -2
- data/examples/33_stock_predictor.rb +34 -13
- data/examples/34_agentskills.rb +7 -3
- data/examples/35_hooks.rb +18 -8
- data/examples/README.md +199 -45
- data/examples/common.rb +79 -11
- data/examples/xyzzy.rb +8 -1
- data/lib/robot_lab/config.rb +10 -5
- data/lib/robot_lab/names.rb +402 -0
- data/lib/robot_lab/robot/agent_skill_matching.rb +1 -3
- data/lib/robot_lab/robot/bus_messaging.rb +16 -8
- data/lib/robot_lab/robot/template_rendering.rb +16 -3
- data/lib/robot_lab/robot.rb +23 -2
- data/lib/robot_lab/version.rb +1 -1
- data/lib/robot_lab.rb +21 -15
- data/mkdocs.yml +6 -1
- metadata +7 -2
|
@@ -37,36 +37,47 @@ RobotLab automatically installs these core dependencies:
|
|
|
37
37
|
|-----|---------|
|
|
38
38
|
| `ruby_llm` (~> 1.12) | LLM provider integrations (Anthropic, OpenAI, Gemini, etc.) |
|
|
39
39
|
| `prompt_manager` (~> 1.0) | Template-based prompt management with YAML front matter |
|
|
40
|
-
| `simple_flow` (~> 0.
|
|
40
|
+
| `simple_flow` (~> 0.4) | Pipeline workflow execution for networks |
|
|
41
41
|
| `myway_config` (~> 0.1) | Layered configuration (defaults, env vars, config files) |
|
|
42
|
-
| `ruby_llm-mcp` | Model Context Protocol client for external tool servers |
|
|
43
|
-
| `ruby_llm-schema` | Schema validation for structured outputs |
|
|
44
|
-
| `ruby_llm-semantic_cache` | Semantic caching for LLM responses |
|
|
42
|
+
| `ruby_llm-mcp` (~> 1.0) | Model Context Protocol client for external tool servers |
|
|
43
|
+
| `ruby_llm-schema` (~> 0.3) | Schema validation for structured outputs |
|
|
44
|
+
| `ruby_llm-semantic_cache` (~> 0.1) | Semantic caching for LLM responses |
|
|
45
45
|
| `zeitwerk` (~> 2.6) | Autoloading and eager loading |
|
|
46
46
|
| `async` (~> 2.0) | Fiber-based concurrency |
|
|
47
|
+
| `async-http` (~> 0.60) | MCP SSE and streamable-HTTP transports |
|
|
48
|
+
| `async-websocket` (~> 0.30) | MCP WebSocket transport |
|
|
49
|
+
| `typed_bus` (~> 0.0.1) | Typed message bus for robot-to-robot messaging |
|
|
50
|
+
| `ractor_queue` (~> 0.2) | Queue used by the Network bus poller |
|
|
47
51
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
=== "MCP WebSocket Transport"
|
|
52
|
+
> [!NOTE]
|
|
53
|
+
> `async-http` and `async-websocket` are hard runtime dependencies, not optional
|
|
54
|
+
> extras — they install with the gem whether or not you use MCP.
|
|
53
55
|
|
|
54
|
-
|
|
55
|
-
gem "async-websocket"
|
|
56
|
-
```
|
|
56
|
+
### Optional Dependencies
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
Several features are gated behind gems the core gem does **not** install. Add
|
|
59
|
+
whichever you need to your own `Gemfile`:
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
| Gem | Enables | Without it |
|
|
62
|
+
|-----|---------|------------|
|
|
63
|
+
| `classifier` (~> 2.3) | `robot.compress_history`, `RobotLab::Convergence` | `RobotLab::DependencyError` |
|
|
64
|
+
| `robot_lab-document_store` | `memory.store_document` / `search_documents` / `document_keys` / `delete_document`, and `AgentSkill` catalogs | `RobotLab::DependencyError` (skill catalogs raise `LoadError`) |
|
|
65
|
+
| `redis` | Redis-backed `Memory` | `Memory#redis?` is `false` and the store silently stays in-process |
|
|
66
|
+
| `robot_lab-ractor` | Ractor-parallel tool execution and `Network` ractor scheduling | tools run inline; a network run with `parallel_mode: :ractor` raises `RobotLab::DependencyError` |
|
|
63
67
|
|
|
64
|
-
|
|
68
|
+
```ruby
|
|
69
|
+
# Gemfile
|
|
70
|
+
gem "classifier", "~> 2.3"
|
|
71
|
+
gem "robot_lab-document_store"
|
|
72
|
+
gem "redis"
|
|
73
|
+
gem "robot_lab-ractor"
|
|
74
|
+
```
|
|
65
75
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
76
|
+
> [!NOTE]
|
|
77
|
+
> Several capabilities advertised on the [home page](../index.md) — embedding-based
|
|
78
|
+
> document retrieval, runtime skill matching, and CPU parallelism — depend on the
|
|
79
|
+
> gems above. They are genuinely optional, but the feature is unavailable until the
|
|
80
|
+
> gem is installed.
|
|
70
81
|
|
|
71
82
|
## Verify Installation
|
|
72
83
|
|
|
@@ -84,33 +95,33 @@ Run it:
|
|
|
84
95
|
|
|
85
96
|
```bash
|
|
86
97
|
ruby test_robot_lab.rb
|
|
87
|
-
# => RobotLab version: 0.
|
|
98
|
+
# => RobotLab version: 0.2.6
|
|
88
99
|
# => Installation successful!
|
|
89
100
|
```
|
|
90
101
|
|
|
91
102
|
## Rails Installation
|
|
92
103
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
rails
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
This creates:
|
|
104
|
+
> [!IMPORTANT]
|
|
105
|
+
> The core `robot_lab` gem ships **no Rails Engine, no Railtie, and no generators**.
|
|
106
|
+
> Rails integration lives in the separate
|
|
107
|
+
> [robot_lab-rails](https://github.com/MadBomber/robot_lab-rails) gem.
|
|
100
108
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
- `app/models/robot_lab_result.rb` - Result model
|
|
105
|
-
- `app/robots/` - Directory for robot definitions
|
|
106
|
-
- `app/tools/` - Directory for tool definitions
|
|
109
|
+
Core RobotLab only performs two bare `defined?(::Rails)` checks: it uses
|
|
110
|
+
`Rails.logger` as the default logger, and it resolves the template path to
|
|
111
|
+
`app/prompts` when `Rails.root` is present. Nothing else is Rails-aware.
|
|
107
112
|
|
|
108
|
-
|
|
113
|
+
For generators, an `ActiveJob` base class, and Turbo Stream broadcasting, add the
|
|
114
|
+
extension gem:
|
|
109
115
|
|
|
110
|
-
```
|
|
111
|
-
|
|
116
|
+
```ruby
|
|
117
|
+
# Gemfile
|
|
118
|
+
gem "robot_lab"
|
|
119
|
+
gem "robot_lab-rails"
|
|
112
120
|
```
|
|
113
121
|
|
|
122
|
+
Then follow that gem's own installation instructions for its generators and
|
|
123
|
+
migrations.
|
|
124
|
+
|
|
114
125
|
## Environment Setup
|
|
115
126
|
|
|
116
127
|
RobotLab uses a layered configuration system (see [Configuration](configuration.md) for full details). The simplest way to get started is with environment variables:
|
|
@@ -165,11 +176,12 @@ gem install robot_lab --verbose
|
|
|
165
176
|
|
|
166
177
|
### Missing Dependencies
|
|
167
178
|
|
|
168
|
-
If you see
|
|
179
|
+
If you see a `LoadError` (or a `RobotLab::DependencyError`) naming a gem RobotLab
|
|
180
|
+
does not depend on, add it yourself:
|
|
169
181
|
|
|
170
182
|
```bash
|
|
171
|
-
#
|
|
172
|
-
bundle add
|
|
183
|
+
# e.g. compress_history / Convergence need the classifier gem
|
|
184
|
+
bundle add classifier
|
|
173
185
|
```
|
|
174
186
|
|
|
175
187
|
### API Key Issues
|
|
@@ -13,11 +13,15 @@ export ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY="sk-ant-..."
|
|
|
13
13
|
Or create a config file at `./config/robot_lab.yml`:
|
|
14
14
|
|
|
15
15
|
```yaml
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
anthropic_api_key: <%= ENV['ANTHROPIC_API_KEY'] %>
|
|
16
|
+
ruby_llm:
|
|
17
|
+
anthropic_api_key: <%= ENV['ANTHROPIC_API_KEY'] %>
|
|
19
18
|
```
|
|
20
19
|
|
|
20
|
+
> [!IMPORTANT]
|
|
21
|
+
> Config files are **flat** — put the keys at the top level. Wrapping them in a
|
|
22
|
+
> `defaults:` key (as the gem's own bundled `defaults.yml` does) makes the whole
|
|
23
|
+
> file silently ignored.
|
|
24
|
+
|
|
21
25
|
See [Configuration](configuration.md) for all configuration options.
|
|
22
26
|
|
|
23
27
|
## Step 2: Create a Robot
|
|
@@ -140,12 +144,30 @@ assistant = RobotLab.build(
|
|
|
140
144
|
local_tools: [CurrentTime]
|
|
141
145
|
)
|
|
142
146
|
|
|
143
|
-
|
|
147
|
+
# tools: :inherit is REQUIRED -- run() sends no tools without it
|
|
148
|
+
result = assistant.run("What time is it right now?", tools: :inherit)
|
|
144
149
|
puts result.last_text_content
|
|
145
150
|
```
|
|
146
151
|
|
|
147
152
|
Tools are passed to the robot via the `local_tools:` keyword argument as an array of `RubyLLM::Tool` subclasses.
|
|
148
153
|
|
|
154
|
+
> [!WARNING]
|
|
155
|
+
> **Attaching a tool is not the same as sending it.** `Robot#run` defaults to
|
|
156
|
+
> `tools: :none`, which means "send zero tools this turn". Without
|
|
157
|
+
> `tools: :inherit` on the run, the example above builds fine, calls the LLM
|
|
158
|
+
> fine, and the model simply never sees `CurrentTime` — it will guess or say it
|
|
159
|
+
> cannot check the time. The same applies to MCP: pass
|
|
160
|
+
> `mcp: :inherit, tools: :inherit` to connect MCP servers and expose their tools.
|
|
161
|
+
>
|
|
162
|
+
> Do **not** try to fix this by passing `tools: :inherit` to `RobotLab.build` for
|
|
163
|
+
> a standalone robot like this one — at build time it resolves against the global
|
|
164
|
+
> `:none` and yields an allowlist matching nothing, suppressing the tools even
|
|
165
|
+
> when the run asks for them. Put it on the `run` call.
|
|
166
|
+
>
|
|
167
|
+
> (The one place build-time `:inherit` *is* correct is a robot in a network, where
|
|
168
|
+
> it opts into the network `config:`'s list — see
|
|
169
|
+
> [Creating Networks](../guides/creating-networks.md).)
|
|
170
|
+
|
|
149
171
|
## Method Chaining
|
|
150
172
|
|
|
151
173
|
Robots support a chaining API for runtime adjustments:
|
|
@@ -162,7 +184,20 @@ result = robot
|
|
|
162
184
|
puts result.last_text_content
|
|
163
185
|
```
|
|
164
186
|
|
|
165
|
-
|
|
187
|
+
The complete set of chaining methods is `with_context`, `with_headers`,
|
|
188
|
+
`with_instructions`, `with_model`, `with_params`, `with_schema`,
|
|
189
|
+
`with_temperature`, `with_thinking`, `with_tool`, `with_tools`, plus RobotLab's
|
|
190
|
+
own `with_template` and `with_bus`.
|
|
191
|
+
|
|
192
|
+
> [!NOTE]
|
|
193
|
+
> There is no `with_max_tokens`, `with_top_p`, `with_top_k`, `with_stop`,
|
|
194
|
+
> `with_presence_penalty`, or `with_frequency_penalty` — those raise
|
|
195
|
+
> `NoMethodError`. Set them as constructor keyword arguments
|
|
196
|
+
> (`RobotLab.build(..., max_tokens: 2000)`) or through `with_params`:
|
|
197
|
+
>
|
|
198
|
+
> ```ruby
|
|
199
|
+
> robot.with_params(max_tokens: 2000, top_p: 0.3).run("...")
|
|
200
|
+
> ```
|
|
166
201
|
|
|
167
202
|
## Multi-Robot Network
|
|
168
203
|
|
|
@@ -205,12 +240,22 @@ if result.value.is_a?(RobotLab::RobotResult)
|
|
|
205
240
|
puts result.value.last_text_content
|
|
206
241
|
end
|
|
207
242
|
|
|
208
|
-
# Access intermediate results by
|
|
243
|
+
# Access intermediate results by ROBOT name (see note below)
|
|
209
244
|
if result.context[:analyst]
|
|
210
245
|
puts "\nAnalysis: #{result.context[:analyst].last_text_content}"
|
|
211
246
|
end
|
|
212
247
|
```
|
|
213
248
|
|
|
249
|
+
> [!IMPORTANT]
|
|
250
|
+
> `result.context` is keyed by the **robot's** `name:`, not by the task name.
|
|
251
|
+
> Internally each robot writes `result.with_context(@name.to_sym, robot_result)`.
|
|
252
|
+
> The lookup above works only because the robot is named `"analyst"` *and* its
|
|
253
|
+
> task is named `:analyst`. If you register a robot under a different task name —
|
|
254
|
+
> `task :first_pass, analyst` — the result is still at
|
|
255
|
+
> `result.context[:analyst]`, not `result.context[:first_pass]`. Keeping the two
|
|
256
|
+
> names identical, as in this example, is the simplest way to avoid the
|
|
257
|
+
> surprise.
|
|
258
|
+
|
|
214
259
|
### Network Task Dependencies
|
|
215
260
|
|
|
216
261
|
Tasks declare their dependencies to control execution order:
|