robot_lab 0.0.4 → 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/CHANGELOG.md +50 -0
- data/README.md +64 -6
- data/Rakefile +2 -1
- data/docs/api/core/index.md +41 -46
- data/docs/api/core/memory.md +200 -154
- data/docs/api/core/network.md +13 -3
- data/docs/api/core/robot.md +38 -26
- data/docs/api/core/state.md +55 -73
- data/docs/api/index.md +7 -28
- 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/architecture/core-concepts.md +10 -15
- data/docs/concepts.md +5 -7
- data/docs/examples/index.md +2 -2
- data/docs/getting-started/configuration.md +80 -0
- data/docs/guides/building-robots.md +10 -9
- data/docs/guides/creating-networks.md +49 -0
- data/docs/guides/index.md +0 -5
- data/docs/guides/rails-integration.md +244 -162
- data/docs/guides/streaming.md +118 -138
- data/docs/index.md +0 -8
- data/examples/03_network.rb +10 -7
- data/examples/08_llm_config.rb +40 -11
- data/examples/09_chaining.rb +45 -6
- data/examples/11_network_introspection.rb +30 -7
- data/examples/12_message_bus.rb +1 -1
- data/examples/14_rusty_circuit/heckler.rb +14 -8
- data/examples/14_rusty_circuit/open_mic.rb +5 -3
- data/examples/14_rusty_circuit/scout.rb +14 -31
- data/examples/15_memory_network_and_bus/editorial_pipeline.rb +1 -1
- 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/lib/generators/robot_lab/templates/initializer.rb.tt +0 -13
- data/lib/robot_lab/memory.rb +8 -32
- 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 +56 -420
- data/lib/robot_lab/run_config.rb +184 -0
- data/lib/robot_lab/state_proxy.rb +2 -12
- data/lib/robot_lab/task.rb +8 -1
- data/lib/robot_lab/utils.rb +39 -0
- data/lib/robot_lab/version.rb +1 -1
- data/lib/robot_lab.rb +29 -8
- data/mkdocs.yml +0 -11
- metadata +15 -20
- 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 -275
- data/docs/api/history/config.md +0 -284
- data/docs/api/history/index.md +0 -128
- data/docs/api/history/thread-manager.md +0 -194
- data/docs/guides/history.md +0 -359
- 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 -160
- data/lib/robot_lab/adapters/registry.rb +0 -81
- 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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: db26fa8aa3d47eb49face5b344cd1b41ed6e148a0460514b54913b5973ca9cc1
|
|
4
|
+
data.tar.gz: 79f2a71535ddaabd6f2a7c5dceaf3aefad10e3e51b4c0ccbd04fbe82c7804f57
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 832389808ec464678849736bb0d9fceca5dd67a5a3fa1e4c0486367bdf20a389257f4bfdeeb3afc9ca8619168274eb2a7cbed2c0376e358c902030ee26b105de
|
|
7
|
+
data.tar.gz: fb57b2e6cb329f6c116cbd7cb81a60bb68a9daeddc6e45a1f859690cc7f44ff3074eb4dfcdf0240b6a95f3786d992fc31c6edc3ed61fd2f838b435a19b550876
|
data/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,56 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [0.0.6] - 2026-02-17 [unreleased]
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **Writers' Room example** (`examples/16_writers_room/`) — Self-Organizing Group (SOG) demo where identical writer robots collaborate to produce a 10-chapter fiction novella
|
|
19
|
+
- Writer class with `fresh_chat!` pattern to prevent RubyLLM empty text content block corruption in bus-based robots
|
|
20
|
+
- 7 tools: Broadcast, DirectMessage, ReadMemory, WriteMemory, ListMemory, SpawnWriter, MarkComplete
|
|
21
|
+
- Room class with bus, shared memory, writer roster, heartbeat-based progress nudging, and structured logging
|
|
22
|
+
- Display class with color-coded terminal output, word wrapping, and optional log file
|
|
23
|
+
- CLI with `--premise`, `--writers`, `--log`, `--timeout`, `-h`/`--help` options
|
|
24
|
+
- Shared prompt template (`prompts/writer.md`) — all writers use the same instructions with no hierarchy
|
|
25
|
+
- **Network pipeline tests** (`test/robot_lab/network_pipeline_test.rb`) for sequential robot execution and memory sharing
|
|
26
|
+
- **`dispatch_async` error handling** — exceptions inside async dispatch are now logged and contained instead of propagating
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- Bumped version to 0.0.6
|
|
31
|
+
- **Removed `Errors` module** and related test file — unused error classes cleaned out
|
|
32
|
+
- **Zeitwerk autoloading optimized** — streamlined loader configuration in `lib/robot_lab.rb`
|
|
33
|
+
- Rakefile updated with `16_writers_room` entry point in `SUBDIR_ENTRY_POINTS`
|
|
34
|
+
|
|
35
|
+
## [0.0.5] - 2026-02-17 [unreleased]
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- **`RunConfig` class** (`lib/robot_lab/run_config.rb`) for shared operational defaults
|
|
40
|
+
- Field categories: LLM (`model`, `temperature`, `top_p`, `top_k`, `max_tokens`, `presence_penalty`, `frequency_penalty`, `stop`), tools (`mcp`, `tools`), callbacks (`on_tool_call`, `on_tool_result`), infrastructure (`bus`, `enable_cache`)
|
|
41
|
+
- Keyword construction, block DSL, and method chaining
|
|
42
|
+
- Merge semantics: more-specific config's non-nil values win
|
|
43
|
+
- `apply_to(chat)` applies LLM fields to a RubyLLM chat
|
|
44
|
+
- `from_front_matter(metadata)` extracts config from template YAML front matter
|
|
45
|
+
- `to_h`, `to_json_hash` (skips Procs/IO), `empty?`, `key?`, `==`, `inspect`
|
|
46
|
+
- Full test suite (`test/robot_lab/run_config_test.rb`, 39 tests)
|
|
47
|
+
- **`config:` parameter** on `Robot.new`, `Network.new`, `Network#task`, `RobotLab.build`, and `RobotLab.create_network` for passing RunConfig instances
|
|
48
|
+
- **Configuration inheritance chain**: `RobotLab.config` (global) -> `network.config` -> task `config:` -> `robot.config` -> template front matter -> constructor kwargs
|
|
49
|
+
- **`robot.config` / `network.config` accessors** (`attr_reader`) returning the effective RunConfig
|
|
50
|
+
- **`RobotLab.configure`** block-style configuration method yielding the config object
|
|
51
|
+
- **Bus processing guard** (`handle_incoming_delivery`) serializing message deliveries across bus-connected robots to prevent Async fiber re-entrancy corrupting chat message ordering
|
|
52
|
+
- Documentation for RunConfig across README, configuration guide, network guide, and API reference
|
|
53
|
+
- Updated examples (`03_network`, `08_llm_config`, `09_chaining`, `11_network_introspection`) demonstrating RunConfig usage
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- Bumped version to 0.0.5
|
|
58
|
+
- **Template rendering refactored** to use `RunConfig.from_front_matter` instead of `apply_front_matter_config` — front matter config is now merged with the robot's RunConfig before applying to chat
|
|
59
|
+
- **MCP/tools hierarchy resolution** now accepts `network_config:` parameter instead of directly accessing the network object, enabling RunConfig-driven configuration flow
|
|
60
|
+
- **`dispatch_async`** simplified to exclusively use Async fibers, removing Thread-based fallback
|
|
61
|
+
- **`Memory#get`** improved nil value handling — uses `@backend.key?()` instead of nil check for correct nil value storage and retrieval
|
|
62
|
+
- **`Memory#clone`** optimized — results and messages are referenced directly instead of duplicated
|
|
63
|
+
|
|
14
64
|
## [0.0.4] - 2026-02-16 [unreleased]
|
|
15
65
|
|
|
16
66
|
### Added
|
data/README.md
CHANGED
|
@@ -187,6 +187,57 @@ robot = RobotLab.build(
|
|
|
187
187
|
)
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
+
### Shared Configuration with RunConfig
|
|
191
|
+
|
|
192
|
+
`RunConfig` lets you define operational defaults that flow through the hierarchy: Network -> Robot -> Template -> Task -> Runtime. Use it to share LLM settings across multiple robots or an entire network.
|
|
193
|
+
|
|
194
|
+
```ruby
|
|
195
|
+
# Create a shared config
|
|
196
|
+
shared = RobotLab::RunConfig.new(
|
|
197
|
+
model: "claude-sonnet-4",
|
|
198
|
+
temperature: 0.7,
|
|
199
|
+
max_tokens: 2000
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
# Apply to individual robots
|
|
203
|
+
robot = RobotLab.build(
|
|
204
|
+
name: "writer",
|
|
205
|
+
system_prompt: "You are a creative writer.",
|
|
206
|
+
config: shared
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
# Apply to an entire network (all robots inherit these defaults)
|
|
210
|
+
network = RobotLab.create_network(name: "pipeline", config: shared) do
|
|
211
|
+
task :analyzer, analyzer_robot, depends_on: :none
|
|
212
|
+
task :writer, writer_robot, depends_on: [:analyzer]
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Robot-specific kwargs always override the shared config
|
|
216
|
+
robot = RobotLab.build(
|
|
217
|
+
name: "fast_bot",
|
|
218
|
+
system_prompt: "Be brief.",
|
|
219
|
+
config: shared,
|
|
220
|
+
temperature: 0.3 # overrides shared config's 0.7
|
|
221
|
+
)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
RunConfig supports keyword construction, block DSL, and merge semantics:
|
|
225
|
+
|
|
226
|
+
```ruby
|
|
227
|
+
# Block DSL
|
|
228
|
+
config = RobotLab::RunConfig.new do |c|
|
|
229
|
+
c.model "claude-sonnet-4"
|
|
230
|
+
c.temperature 0.7
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Merge (more-specific wins)
|
|
234
|
+
network_config = RobotLab::RunConfig.new(model: "claude-sonnet-4", temperature: 0.5)
|
|
235
|
+
robot_config = RobotLab::RunConfig.new(temperature: 0.9)
|
|
236
|
+
effective = network_config.merge(robot_config)
|
|
237
|
+
effective.temperature #=> 0.9
|
|
238
|
+
effective.model #=> "claude-sonnet-4"
|
|
239
|
+
```
|
|
240
|
+
|
|
190
241
|
### Chaining Configuration
|
|
191
242
|
|
|
192
243
|
Robots support method chaining to adjust configuration after creation:
|
|
@@ -375,7 +426,7 @@ class Comedian < RobotLab::Robot
|
|
|
375
426
|
super(name: "bob", template: :comedian, bus: bus)
|
|
376
427
|
on_message do |message|
|
|
377
428
|
joke = run(message.content.to_s).last_text_content.strip
|
|
378
|
-
|
|
429
|
+
send_reply(to: message.from.to_sym, content: joke, in_reply_to: message.key)
|
|
379
430
|
end
|
|
380
431
|
end
|
|
381
432
|
end
|
|
@@ -402,7 +453,7 @@ Key features:
|
|
|
402
453
|
|
|
403
454
|
- **Typed channels** — only `RobotMessage` objects are accepted (type enforcement via `typed_bus`)
|
|
404
455
|
- **Auto-ACK** — `on_message { |message| }` auto-acknowledges; use `|delivery, message|` for manual ACK/NACK
|
|
405
|
-
- **Reply correlation** — `
|
|
456
|
+
- **Reply correlation** — `send_reply(to:, content:, in_reply_to:)` tracks conversation threads
|
|
406
457
|
- **Outbox tracking** — sent messages tracked in `robot.outbox` with status and replies
|
|
407
458
|
- **Independent of Network** — bus communication works without a Network pipeline
|
|
408
459
|
|
|
@@ -451,17 +502,24 @@ Key features:
|
|
|
451
502
|
|
|
452
503
|
## Streaming
|
|
453
504
|
|
|
454
|
-
|
|
505
|
+
Use a `Streaming::Context` with a publish callback to receive real-time events:
|
|
455
506
|
|
|
456
507
|
```ruby
|
|
457
|
-
|
|
508
|
+
handler = lambda do |event|
|
|
458
509
|
case event[:event]
|
|
459
|
-
when
|
|
510
|
+
when RobotLab::Streaming::Events::TEXT_DELTA
|
|
460
511
|
print event[:data][:delta]
|
|
461
|
-
when
|
|
512
|
+
when RobotLab::Streaming::Events::RUN_COMPLETED
|
|
462
513
|
puts "\nDone!"
|
|
463
514
|
end
|
|
464
515
|
end
|
|
516
|
+
|
|
517
|
+
context = RobotLab::Streaming::Context.new(
|
|
518
|
+
run_id: SecureRandom.uuid,
|
|
519
|
+
message_id: SecureRandom.uuid,
|
|
520
|
+
scope: "robot",
|
|
521
|
+
publish: handler
|
|
522
|
+
)
|
|
465
523
|
```
|
|
466
524
|
|
|
467
525
|
## Rails Integration
|
data/Rakefile
CHANGED
|
@@ -48,7 +48,8 @@ namespace :examples do
|
|
|
48
48
|
# Map of subdirectory-based demos to their entry point scripts
|
|
49
49
|
SUBDIR_ENTRY_POINTS = {
|
|
50
50
|
"14_rusty_circuit" => "open_mic.rb",
|
|
51
|
-
"15_memory_network_and_bus" => "editorial_pipeline.rb"
|
|
51
|
+
"15_memory_network_and_bus" => "editorial_pipeline.rb",
|
|
52
|
+
"16_writers_room" => "writers_room.rb"
|
|
52
53
|
}.freeze
|
|
53
54
|
|
|
54
55
|
desc "Run all examples"
|
data/docs/api/core/index.md
CHANGED
|
@@ -12,21 +12,21 @@ classDiagram
|
|
|
12
12
|
+model: String
|
|
13
13
|
+template: String
|
|
14
14
|
+tools: Array~Tool~
|
|
15
|
-
+run(
|
|
15
|
+
+run(message) Message
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
class Network {
|
|
19
19
|
+name: String
|
|
20
20
|
+robots: Hash
|
|
21
|
-
+
|
|
22
|
-
+run(
|
|
21
|
+
+config: RunConfig
|
|
22
|
+
+run(message)
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
class
|
|
26
|
-
+
|
|
27
|
-
+
|
|
28
|
-
+
|
|
29
|
-
+
|
|
25
|
+
class RunConfig {
|
|
26
|
+
+model: String
|
|
27
|
+
+temperature: Float
|
|
28
|
+
+merge(other) RunConfig
|
|
29
|
+
+apply_to(chat)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
class Tool {
|
|
@@ -37,10 +37,13 @@ classDiagram
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
class Memory {
|
|
40
|
-
+
|
|
41
|
-
+
|
|
42
|
-
+
|
|
43
|
-
+
|
|
40
|
+
+set(key, value)
|
|
41
|
+
+get(key)
|
|
42
|
+
+delete(key)
|
|
43
|
+
+data: StateProxy
|
|
44
|
+
+results: Array
|
|
45
|
+
+messages: Array
|
|
46
|
+
+session_id: String
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
class RobotMessage {
|
|
@@ -53,9 +56,11 @@ classDiagram
|
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
Network --> Robot : contains
|
|
59
|
+
Network --> RunConfig : uses
|
|
60
|
+
Robot --> RunConfig : uses
|
|
56
61
|
Robot --> Tool : has
|
|
57
|
-
|
|
58
|
-
Network -->
|
|
62
|
+
Robot --> Memory : uses
|
|
63
|
+
Network --> Memory : uses
|
|
59
64
|
Robot ..> RobotMessage : sends/receives
|
|
60
65
|
```
|
|
61
66
|
|
|
@@ -65,10 +70,10 @@ classDiagram
|
|
|
65
70
|
|-------|---------|
|
|
66
71
|
| [Robot](robot.md) | LLM agent with personality, tools, and model configuration |
|
|
67
72
|
| [Network](network.md) | Container for robots with routing and orchestration |
|
|
68
|
-
|
|
|
73
|
+
| RunConfig | Shared configuration for LLM, tools, callbacks, and infrastructure |
|
|
69
74
|
| [Tool](tool.md) | Callable function with parameters and handler |
|
|
70
75
|
| [AskUser](tool.md#built-in-askuser) | Built-in tool for terminal-based user interaction |
|
|
71
|
-
| [Memory](memory.md) |
|
|
76
|
+
| [Memory](memory.md) | Reactive key-value store for sharing data |
|
|
72
77
|
| RobotMessage | Typed envelope for bus-based inter-robot communication |
|
|
73
78
|
|
|
74
79
|
## Quick Examples
|
|
@@ -76,50 +81,40 @@ classDiagram
|
|
|
76
81
|
### Robot
|
|
77
82
|
|
|
78
83
|
```ruby
|
|
79
|
-
robot = RobotLab.build
|
|
80
|
-
name "assistant"
|
|
81
|
-
model "claude-sonnet-4"
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
end
|
|
88
|
-
end
|
|
84
|
+
robot = RobotLab.build(
|
|
85
|
+
name: "assistant",
|
|
86
|
+
model: "claude-sonnet-4",
|
|
87
|
+
system_prompt: "You are helpful.",
|
|
88
|
+
local_tools: [greet_tool]
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
result = robot.run("Hello!")
|
|
89
92
|
```
|
|
90
93
|
|
|
91
94
|
### Network
|
|
92
95
|
|
|
93
96
|
```ruby
|
|
94
|
-
network = RobotLab.create_network do
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
router ->(args) { args.call_count.zero? ? :assistant : nil }
|
|
97
|
+
network = RobotLab.create_network(name: "my_network") do
|
|
98
|
+
step :analyzer, analyzer_robot, depends_on: :none
|
|
99
|
+
step :writer, writer_robot, depends_on: [:analyzer]
|
|
98
100
|
end
|
|
101
|
+
|
|
102
|
+
result = network.run(message: "Process this")
|
|
99
103
|
```
|
|
100
104
|
|
|
101
|
-
###
|
|
105
|
+
### Memory
|
|
102
106
|
|
|
103
107
|
```ruby
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
)
|
|
108
|
+
memory = RobotLab.create_memory(data: { user_id: "123" })
|
|
109
|
+
memory.set(:category, "billing")
|
|
110
|
+
memory.get(:category) # => "billing"
|
|
108
111
|
```
|
|
109
112
|
|
|
110
113
|
### Tool
|
|
111
114
|
|
|
112
115
|
```ruby
|
|
113
|
-
tool = RobotLab::Tool.
|
|
116
|
+
tool = RobotLab::Tool.create(
|
|
114
117
|
name: "get_time",
|
|
115
|
-
description: "Get current time"
|
|
116
|
-
|
|
117
|
-
)
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### Memory
|
|
121
|
-
|
|
122
|
-
```ruby
|
|
123
|
-
state.memory.remember("key", "value")
|
|
124
|
-
value = state.memory.recall("key")
|
|
118
|
+
description: "Get current time"
|
|
119
|
+
) { |**_| Time.now.to_s }
|
|
125
120
|
```
|