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
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
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
name: Deploy
|
|
1
|
+
name: Deploy Documentation to GitHub Pages
|
|
2
2
|
on:
|
|
3
3
|
push:
|
|
4
4
|
branches:
|
|
@@ -41,12 +41,12 @@ jobs:
|
|
|
41
41
|
git config --local user.email "action@github.com"
|
|
42
42
|
git config --local user.name "GitHub Action"
|
|
43
43
|
|
|
44
|
+
- name: Build MkDocs site
|
|
45
|
+
run: mkdocs build
|
|
46
|
+
|
|
44
47
|
- name: Deploy to GitHub Pages
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
echo "Deploying from develop branch"
|
|
51
|
-
mkdocs gh-deploy --force --clean
|
|
52
|
-
fi
|
|
48
|
+
uses: peaceiris/actions-gh-pages@v4
|
|
49
|
+
with:
|
|
50
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
51
|
+
publish_dir: ./site
|
|
52
|
+
keep_files: true
|
data/.irbrc
ADDED
data/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,146 @@ 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
|
+
|
|
64
|
+
## [0.0.4] - 2026-02-16 [unreleased]
|
|
65
|
+
|
|
66
|
+
### Added
|
|
67
|
+
|
|
68
|
+
- **`AskUser` tool** for human-in-the-loop interactions
|
|
69
|
+
- Supports open-ended text, multiple choice, and default values
|
|
70
|
+
- IO sourced from `robot.input`/`robot.output` (defaults to `$stdin`/`$stdout`)
|
|
71
|
+
- Full test suite (`test/robot_lab/ask_user_test.rb`)
|
|
72
|
+
- **`Robot#input` / `Robot#output` accessors** for configurable IO streams
|
|
73
|
+
- **`reply` alias** for `RobotResult#last_text_content` — shorter, more natural API
|
|
74
|
+
- **`.irbrc`** for loading RobotLab in project-level IRB sessions
|
|
75
|
+
- **`wait_until` test helper** replacing flaky `sleep`-based assertions in async tests
|
|
76
|
+
- Documentation for AskUser tool across API reference, guides, and examples
|
|
77
|
+
|
|
78
|
+
### Changed
|
|
79
|
+
|
|
80
|
+
- Bumped version to 0.0.4
|
|
81
|
+
- **Made Rails dependencies optional** — removed `railties`, `activerecord`, `state_machines`, `state_machines-activemodel`, `state_machines-activerecord` from gemspec hard dependencies; moved to Gemfile `:test` group
|
|
82
|
+
- Replaced `require 'active_support'` with targeted `require 'active_support/core_ext/module/delegation'` — only loads what ruby_llm actually needs
|
|
83
|
+
- Added `activesupport >= 7.0` as explicit gemspec dependency with comment explaining it's required by ruby_llm (undeclared upstream)
|
|
84
|
+
- **Tool JSON schema keys are now symbolized** via `deep_symbolize_keys` in `Tool#to_json_schema`
|
|
85
|
+
- Updated all examples to use `reply` alias instead of `last_text_content`
|
|
86
|
+
- Replaced `sleep`-based test assertions with `wait_until` helper in memory, waiter, and robot tests
|
|
87
|
+
- Disabled branch coverage in SimpleCov except in CI
|
|
88
|
+
|
|
89
|
+
### Fixed
|
|
90
|
+
|
|
91
|
+
- Gem install conflict (`activesupport` version mismatch) when running outside Bundler
|
|
92
|
+
- IRB loading issue where `require_relative` was a no-op due to partial load in `$LOADED_FEATURES` — switched to `load`
|
|
93
|
+
- Robot tests for `send_message` now register a message handler on the receiver to avoid TypedBus warnings
|
|
94
|
+
|
|
95
|
+
## [0.0.3] - 2026-02-15 [unreleased]
|
|
96
|
+
|
|
97
|
+
### Added
|
|
98
|
+
|
|
99
|
+
- **Self-contained templates** with extended YAML front matter support
|
|
100
|
+
- `robot_name` — override robot name from template
|
|
101
|
+
- `description` — set robot description from template
|
|
102
|
+
- `tools` — declare tool class names (resolved via `Object.const_get` at build time)
|
|
103
|
+
- `mcp` — declare MCP server configurations
|
|
104
|
+
- Constructor-provided values always take precedence over front matter
|
|
105
|
+
- **Editorial pipeline example** (`15_memory_network_and_bus/`) demonstrating multi-stage workflow with network, memory, and bus coordination
|
|
106
|
+
- OS-specific writer robots, editor, and editor-in-chief roles
|
|
107
|
+
- New prompt templates: `os_advocate`, `os_editor`, `os_chief`
|
|
108
|
+
- Rakefile support for running subdirectory-based examples with `SUBDIR_ENTRY_POINTS` mapping
|
|
109
|
+
|
|
110
|
+
### Changed
|
|
111
|
+
|
|
112
|
+
- Bumped version to 0.0.3
|
|
113
|
+
- Refactored Comic and Scout classes to use `attr_accessor` instead of `instance_variable_set`/`instance_variable_get`
|
|
114
|
+
- Extensive documentation updates across README, guides, API reference, and examples for front matter extras
|
|
115
|
+
|
|
116
|
+
## [0.0.2] - 2026-02-15 (unreleased)
|
|
117
|
+
|
|
118
|
+
### Added
|
|
119
|
+
|
|
120
|
+
- **TypedBus message bus** for robot-to-robot communication
|
|
121
|
+
- `RobotMessage` immutable data class (`Data.define`) with `id`, `from`, `content`, `in_reply_to`
|
|
122
|
+
- Optional `bus:` parameter on Robot constructor — purely additive
|
|
123
|
+
- `on_message` handler with auto-ACK (1-arg block) and manual ACK/NACK (2-arg block)
|
|
124
|
+
- `publish_to_bus` with Async-aware fiber wrapping
|
|
125
|
+
- Typed channels accepting only `RobotMessage` objects
|
|
126
|
+
- **Dynamic robot spawning** via `Robot#spawn` method for creating child robots at runtime
|
|
127
|
+
- **`with_bus` configuration method** for connecting robots to a message bus after creation
|
|
128
|
+
- **Comic robot class** with dynamic comedy tools (`reinvent_style`, `adjust_energy`, `get_coaching`)
|
|
129
|
+
- New examples:
|
|
130
|
+
- `12_message_bus.rb` — two-robot joke critique workflow
|
|
131
|
+
- `13_spawn.rb` — dynamic robot spawning
|
|
132
|
+
- `14_rusty_circuit/` — multi-robot comedy open mic with bus-based coordination
|
|
133
|
+
- New prompt templates: `comedian`, `comedy_critic`, `dispatcher`, `open_mic_comic`, `open_mic_heckler`, `open_mic_scout`, `configurable`, `llm_config_demo`
|
|
134
|
+
- Rake tasks for building documentation sites
|
|
135
|
+
- GitHub Actions workflow for YARD documentation deployment
|
|
136
|
+
|
|
137
|
+
### Changed
|
|
138
|
+
|
|
139
|
+
- Bumped version to 0.0.2
|
|
140
|
+
- Replaced `ruby_llm-template` dependency with `prompt_manager` (~> 1.0)
|
|
141
|
+
- Updated `ruby_llm` dependency to ~> 1.12
|
|
142
|
+
- Added `typed_bus` as a core dependency
|
|
143
|
+
- Added `myway_config` (~> 0.1) dependency
|
|
144
|
+
- Added `amazing_print` and `hashdiff` as development dependencies
|
|
145
|
+
- Migrated all prompt templates from directory-based format (`system.txt.erb` / `user.txt.erb`) to single `.md` files with YAML front matter
|
|
146
|
+
- Refactored `Robot` class for simplified configuration
|
|
147
|
+
- Refactored `Config` class
|
|
148
|
+
- Extensive documentation updates across all guide, architecture, and API reference pages
|
|
149
|
+
|
|
150
|
+
### Fixed
|
|
151
|
+
|
|
152
|
+
- GitHub Actions platform limitation (`arm64-darwin` only in lockfile)
|
|
153
|
+
|
|
14
154
|
## [0.0.1] - 2026-01-16
|
|
15
155
|
|
|
16
156
|
- refactored the network concept
|
data/README.md
CHANGED
|
@@ -18,8 +18,10 @@ RobotLab enables you to build sophisticated AI applications using multiple speci
|
|
|
18
18
|
- <strong>Network Orchestration</strong> - Connect robots with flexible routing<br>
|
|
19
19
|
- <strong>Extensible Tools</strong> - Give robots custom capabilities<br>
|
|
20
20
|
- <strong>MCP Integration</strong> - Connect to external tool servers<br>
|
|
21
|
-
- <strong>Shared Memory</strong> -
|
|
21
|
+
- <strong>Shared Memory</strong> - Reactive key-value store with subscriptions<br>
|
|
22
22
|
- <strong>Conversation History</strong> - Persist and restore threads<br>
|
|
23
|
+
- <strong>Message Bus</strong> - Bidirectional robot communication via TypedBus<br>
|
|
24
|
+
- <strong>Dynamic Spawning</strong> - Robots create new robots at runtime<br>
|
|
23
25
|
- <strong>Streaming</strong> - Real-time event streaming<br>
|
|
24
26
|
- <strong>Rails Integration</strong> - Generators and ActiveRecord support
|
|
25
27
|
</td>
|
|
@@ -52,11 +54,6 @@ The simplest way to create a robot is with an inline `system_prompt`. This appro
|
|
|
52
54
|
```ruby
|
|
53
55
|
require "robot_lab"
|
|
54
56
|
|
|
55
|
-
# Configure RobotLab
|
|
56
|
-
RobotLab.configure do |config|
|
|
57
|
-
config.default_model = "claude-sonnet-4"
|
|
58
|
-
end
|
|
59
|
-
|
|
60
57
|
# Create a robot with an inline system prompt
|
|
61
58
|
robot = RobotLab.build(
|
|
62
59
|
name: "assistant",
|
|
@@ -64,66 +61,119 @@ robot = RobotLab.build(
|
|
|
64
61
|
)
|
|
65
62
|
|
|
66
63
|
# Run the robot
|
|
67
|
-
result = robot.run(
|
|
64
|
+
result = robot.run("What is the capital of France?")
|
|
68
65
|
|
|
69
|
-
puts result.
|
|
66
|
+
puts result.last_text_content
|
|
70
67
|
# => "The capital of France is Paris."
|
|
71
68
|
```
|
|
72
69
|
|
|
73
|
-
###
|
|
70
|
+
### Configuration
|
|
74
71
|
|
|
75
|
-
|
|
72
|
+
RobotLab uses [MywayConfig](https://github.com/MadBomber/myway_config) for layered configuration. There is no `configure` block. Configuration is loaded automatically from multiple sources in priority order:
|
|
76
73
|
|
|
77
|
-
|
|
78
|
-
-
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
1. Bundled defaults (`lib/robot_lab/config/defaults.yml`)
|
|
75
|
+
2. Environment-specific overrides (development, test, production)
|
|
76
|
+
3. XDG user config (`~/.config/robot_lab/config.yml`)
|
|
77
|
+
4. Project config (`./config/robot_lab.yml`)
|
|
78
|
+
5. Environment variables (`ROBOT_LAB_*` prefix)
|
|
81
79
|
|
|
82
|
-
|
|
80
|
+
```bash
|
|
81
|
+
# Set API keys via environment variables (double underscore for nesting)
|
|
82
|
+
export ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY=sk-ant-...
|
|
83
|
+
export ROBOT_LAB_RUBY_LLM__OPENAI_API_KEY=sk-...
|
|
84
|
+
export ROBOT_LAB_RUBY_LLM__MODEL=claude-sonnet-4
|
|
85
|
+
```
|
|
83
86
|
|
|
84
87
|
```ruby
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
# Access configuration values
|
|
89
|
+
RobotLab.config.ruby_llm.model #=> "claude-sonnet-4"
|
|
90
|
+
RobotLab.config.ruby_llm.request_timeout #=> 120
|
|
91
|
+
RobotLab.config.streaming_enabled #=> true
|
|
88
92
|
```
|
|
89
93
|
|
|
90
|
-
|
|
94
|
+
Or create a project config file at `./config/robot_lab.yml`:
|
|
91
95
|
|
|
96
|
+
```yaml
|
|
97
|
+
ruby_llm:
|
|
98
|
+
model: claude-sonnet-4
|
|
99
|
+
anthropic_api_key: sk-ant-...
|
|
100
|
+
request_timeout: 180
|
|
92
101
|
```
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
102
|
+
|
|
103
|
+
### Using Templates
|
|
104
|
+
|
|
105
|
+
For production applications, RobotLab supports a template system built on [PromptManager](https://github.com/MadBomber/prompt_manager). Templates allow you to:
|
|
106
|
+
|
|
107
|
+
- **Compose prompts** from reusable Markdown files
|
|
108
|
+
- **Inject dynamic context** at build-time
|
|
109
|
+
- **Version control** your prompts alongside your code
|
|
110
|
+
- **Share prompts** across multiple robots
|
|
111
|
+
|
|
112
|
+
Each template is a `.md` file with YAML front matter for metadata and parameters:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
prompts/
|
|
116
|
+
assistant.md
|
|
117
|
+
classifier.md
|
|
118
|
+
billing.md
|
|
99
119
|
```
|
|
100
120
|
|
|
101
|
-
Create
|
|
121
|
+
Create a template at `prompts/assistant.md`:
|
|
102
122
|
|
|
103
|
-
```
|
|
123
|
+
```markdown
|
|
124
|
+
---
|
|
125
|
+
description: A helpful assistant
|
|
126
|
+
parameters:
|
|
127
|
+
company_name: null
|
|
128
|
+
tone: friendly
|
|
129
|
+
---
|
|
104
130
|
You are a helpful assistant for <%= company_name %>.
|
|
105
131
|
|
|
132
|
+
Your communication style should be <%= tone %>.
|
|
133
|
+
|
|
106
134
|
Your responsibilities:
|
|
107
135
|
- Answer questions accurately and concisely
|
|
108
136
|
- Be friendly and professional
|
|
109
137
|
- Admit when you don't know something
|
|
110
|
-
|
|
111
|
-
<% if guidelines %>
|
|
112
|
-
Additional guidelines:
|
|
113
|
-
<%= guidelines %>
|
|
114
|
-
<% end %>
|
|
115
138
|
```
|
|
116
139
|
|
|
117
|
-
Reference the template
|
|
140
|
+
Reference the template by symbol:
|
|
118
141
|
|
|
119
142
|
```ruby
|
|
120
143
|
robot = RobotLab.build(
|
|
121
144
|
name: "assistant",
|
|
122
145
|
template: :assistant,
|
|
123
|
-
context: { company_name: "Acme Corp",
|
|
146
|
+
context: { company_name: "Acme Corp", tone: "professional" }
|
|
124
147
|
)
|
|
125
148
|
```
|
|
126
149
|
|
|
150
|
+
### Self-Contained Templates
|
|
151
|
+
|
|
152
|
+
Templates can declare tools, MCP servers, name, and description in front matter, making the `.md` file a complete robot definition:
|
|
153
|
+
|
|
154
|
+
```markdown
|
|
155
|
+
---
|
|
156
|
+
description: GitHub assistant with MCP tool access
|
|
157
|
+
robot_name: github_bot
|
|
158
|
+
tools:
|
|
159
|
+
- CodeSearchTool
|
|
160
|
+
mcp:
|
|
161
|
+
- name: github
|
|
162
|
+
transport: stdio
|
|
163
|
+
command: npx
|
|
164
|
+
args: ["-y", "@modelcontextprotocol/server-github"]
|
|
165
|
+
model: claude-sonnet-4
|
|
166
|
+
---
|
|
167
|
+
You are a GitHub assistant. Use available tools to help with repository tasks.
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
```ruby
|
|
171
|
+
# Template provides everything — minimal constructor call
|
|
172
|
+
robot = RobotLab.build(template: :github_assistant)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Front matter supports: `description`, `robot_name`, `tools`, `mcp`, `parameters`, and LLM config keys (`model`, `temperature`, `top_p`, `top_k`, `max_tokens`, `presence_penalty`, `frequency_penalty`, `stop`). Constructor-provided values always take precedence over front matter.
|
|
176
|
+
|
|
127
177
|
### Combining Templates with System Prompts
|
|
128
178
|
|
|
129
179
|
The `system_prompt` parameter can also be used alongside a template. When both are provided, the template renders first and the `system_prompt` is appended. This is particularly useful during development and testing when you want to add temporary instructions or context to an existing template:
|
|
@@ -132,11 +182,76 @@ The `system_prompt` parameter can also be used alongside a template. When both a
|
|
|
132
182
|
robot = RobotLab.build(
|
|
133
183
|
name: "assistant",
|
|
134
184
|
template: :assistant,
|
|
135
|
-
context: { company_name: "Acme Corp" },
|
|
185
|
+
context: { company_name: "Acme Corp", tone: "friendly" },
|
|
136
186
|
system_prompt: "DEBUG MODE: Log all tool calls. Today's date is #{Date.today}."
|
|
137
187
|
)
|
|
138
188
|
```
|
|
139
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
|
+
|
|
241
|
+
### Chaining Configuration
|
|
242
|
+
|
|
243
|
+
Robots support method chaining to adjust configuration after creation:
|
|
244
|
+
|
|
245
|
+
```ruby
|
|
246
|
+
robot = RobotLab.build(name: "writer", system_prompt: "You are a creative writer.")
|
|
247
|
+
|
|
248
|
+
result = robot
|
|
249
|
+
.with_temperature(0.9)
|
|
250
|
+
.with_model("claude-sonnet-4")
|
|
251
|
+
.with_max_tokens(2000)
|
|
252
|
+
.run("Write a haiku about Ruby programming")
|
|
253
|
+
```
|
|
254
|
+
|
|
140
255
|
## Creating a Robot with Tools
|
|
141
256
|
|
|
142
257
|
```ruby
|
|
@@ -163,14 +278,14 @@ class Magic8Ball < RubyLLM::Tool
|
|
|
163
278
|
end
|
|
164
279
|
end
|
|
165
280
|
|
|
166
|
-
# Create robot with tools
|
|
281
|
+
# Create robot with tools via local_tools: parameter
|
|
167
282
|
robot = RobotLab.build(
|
|
168
283
|
name: "oracle",
|
|
169
284
|
system_prompt: "You are a mystical oracle. Use the Magic 8-Ball to answer questions about the future.",
|
|
170
|
-
|
|
285
|
+
local_tools: [Magic8Ball]
|
|
171
286
|
)
|
|
172
287
|
|
|
173
|
-
result = robot.run(
|
|
288
|
+
result = robot.run("Should I start learning Rust?")
|
|
174
289
|
```
|
|
175
290
|
|
|
176
291
|
## Orchestrating Multiple Robots
|
|
@@ -181,7 +296,10 @@ Networks use [SimpleFlow](https://github.com/MadBomber/simple_flow) pipelines wi
|
|
|
181
296
|
# Custom classifier that activates the appropriate specialist
|
|
182
297
|
class ClassifierRobot < RobotLab::Robot
|
|
183
298
|
def call(result)
|
|
184
|
-
|
|
299
|
+
context = extract_run_context(result)
|
|
300
|
+
message = context.delete(:message)
|
|
301
|
+
|
|
302
|
+
robot_result = run(message, **context)
|
|
185
303
|
|
|
186
304
|
new_result = result
|
|
187
305
|
.with_context(@name.to_sym, robot_result)
|
|
@@ -228,15 +346,15 @@ Both robots and networks have inherent memory that persists across runs:
|
|
|
228
346
|
# Standalone robot with inherent memory
|
|
229
347
|
robot = RobotLab.build(name: "assistant", system_prompt: "You are helpful.")
|
|
230
348
|
|
|
231
|
-
robot.run(
|
|
232
|
-
robot.run(
|
|
349
|
+
robot.run("My name is Alice")
|
|
350
|
+
robot.run("What's my name?") # Memory persists automatically
|
|
233
351
|
|
|
234
352
|
# Access robot's memory
|
|
235
353
|
robot.memory[:user_id] = 123
|
|
236
354
|
robot.memory.data[:category] = "billing"
|
|
237
355
|
|
|
238
356
|
# Runtime memory injection
|
|
239
|
-
robot.run(
|
|
357
|
+
robot.run("Help me", memory: { session_id: "abc123", tier: "premium" })
|
|
240
358
|
|
|
241
359
|
# Reset memory when needed
|
|
242
360
|
robot.reset_memory
|
|
@@ -285,26 +403,123 @@ filesystem_server = {
|
|
|
285
403
|
robot = RobotLab.build(
|
|
286
404
|
name: "developer",
|
|
287
405
|
template: :developer,
|
|
288
|
-
|
|
406
|
+
mcp: [filesystem_server]
|
|
289
407
|
)
|
|
290
408
|
|
|
291
409
|
# Robot can now use filesystem tools
|
|
292
|
-
result = robot.run(
|
|
410
|
+
result = robot.run("List the files in the current directory")
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
## Message Bus
|
|
414
|
+
|
|
415
|
+
Robots can communicate bidirectionally via an optional message bus, independent of the Network pipeline. This enables negotiation loops, convergence patterns, and cyclic workflows.
|
|
416
|
+
|
|
417
|
+
Connect robots to a bus at construction time with `bus:`, or after creation with `with_bus`:
|
|
418
|
+
|
|
419
|
+
```ruby
|
|
420
|
+
require "robot_lab"
|
|
421
|
+
|
|
422
|
+
bus = TypedBus::MessageBus.new
|
|
423
|
+
|
|
424
|
+
class Comedian < RobotLab::Robot
|
|
425
|
+
def initialize(bus:)
|
|
426
|
+
super(name: "bob", template: :comedian, bus: bus)
|
|
427
|
+
on_message do |message|
|
|
428
|
+
joke = run(message.content.to_s).last_text_content.strip
|
|
429
|
+
send_reply(to: message.from.to_sym, content: joke, in_reply_to: message.key)
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
class ComedyCritic < RobotLab::Robot
|
|
435
|
+
def initialize(bus:)
|
|
436
|
+
super(name: "alice", template: :comedy_critic, bus: bus)
|
|
437
|
+
@accepted = false
|
|
438
|
+
on_message do |message|
|
|
439
|
+
verdict = run("Evaluate this joke:\n\n#{message.content}").last_text_content.strip
|
|
440
|
+
@accepted = verdict.start_with?("FUNNY")
|
|
441
|
+
send_message(to: :bob, content: "Try again.") unless @accepted
|
|
442
|
+
end
|
|
443
|
+
end
|
|
444
|
+
attr_reader :accepted
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
bob = Comedian.new(bus: bus)
|
|
448
|
+
alice = ComedyCritic.new(bus: bus)
|
|
449
|
+
alice.send_message(to: :bob, content: "Tell me a funny robot joke.")
|
|
293
450
|
```
|
|
294
451
|
|
|
452
|
+
Key features:
|
|
453
|
+
|
|
454
|
+
- **Typed channels** — only `RobotMessage` objects are accepted (type enforcement via `typed_bus`)
|
|
455
|
+
- **Auto-ACK** — `on_message { |message| }` auto-acknowledges; use `|delivery, message|` for manual ACK/NACK
|
|
456
|
+
- **Reply correlation** — `send_reply(to:, content:, in_reply_to:)` tracks conversation threads
|
|
457
|
+
- **Outbox tracking** — sent messages tracked in `robot.outbox` with status and replies
|
|
458
|
+
- **Independent of Network** — bus communication works without a Network pipeline
|
|
459
|
+
|
|
460
|
+
## Dynamic Robot Spawning
|
|
461
|
+
|
|
462
|
+
Robots can create new robots at runtime using `spawn`. The bus is created lazily — no upfront wiring required:
|
|
463
|
+
|
|
464
|
+
```ruby
|
|
465
|
+
require "robot_lab"
|
|
466
|
+
|
|
467
|
+
class Dispatcher < RobotLab::Robot
|
|
468
|
+
attr_reader :spawned
|
|
469
|
+
|
|
470
|
+
def initialize(bus: nil)
|
|
471
|
+
super(name: "dispatcher", system_prompt: "Decide which specialist to create.", bus: bus)
|
|
472
|
+
@spawned = {}
|
|
473
|
+
|
|
474
|
+
on_message do |message|
|
|
475
|
+
puts "Got reply from #{message.from}: #{message.content.to_s.lines.first&.strip}"
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
def dispatch(question)
|
|
480
|
+
# Spawn a specialist (reuse if already spawned)
|
|
481
|
+
specialist = @spawned["helper"] ||= spawn(
|
|
482
|
+
name: "helper",
|
|
483
|
+
system_prompt: "You answer questions concisely."
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
# Have the specialist work and reply
|
|
487
|
+
answer = specialist.run(question).last_text_content.strip
|
|
488
|
+
specialist.send_message(to: :dispatcher, content: answer)
|
|
489
|
+
end
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
dispatcher = Dispatcher.new
|
|
493
|
+
dispatcher.dispatch("What is the capital of France?")
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
Key features:
|
|
497
|
+
|
|
498
|
+
- **`spawn`** — creates a child robot on the same bus; creates a bus lazily if none exists
|
|
499
|
+
- **`with_bus`** — connect a robot to a bus after creation (`bot.with_bus(existing_bus)`)
|
|
500
|
+
- **Fan-out** — multiple robots with the same name all receive messages sent to that name
|
|
501
|
+
- **No setup required** — bus and channels are created automatically on first use
|
|
502
|
+
|
|
295
503
|
## Streaming
|
|
296
504
|
|
|
297
|
-
|
|
505
|
+
Use a `Streaming::Context` with a publish callback to receive real-time events:
|
|
298
506
|
|
|
299
507
|
```ruby
|
|
300
|
-
|
|
508
|
+
handler = lambda do |event|
|
|
301
509
|
case event[:event]
|
|
302
|
-
when
|
|
510
|
+
when RobotLab::Streaming::Events::TEXT_DELTA
|
|
303
511
|
print event[:data][:delta]
|
|
304
|
-
when
|
|
512
|
+
when RobotLab::Streaming::Events::RUN_COMPLETED
|
|
305
513
|
puts "\nDone!"
|
|
306
514
|
end
|
|
307
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
|
+
)
|
|
308
523
|
```
|
|
309
524
|
|
|
310
525
|
## Rails Integration
|