robot_lab 0.2.8 → 0.3.1

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.
Files changed (262) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +65 -0
  3. data/README.md +16 -18
  4. data/lib/robot_lab/ask_user.rb +3 -3
  5. data/lib/robot_lab/config/defaults.yml +5 -5
  6. data/lib/robot_lab/config.rb +2 -2
  7. data/lib/robot_lab/mcp/transports/streamable_http.rb +2 -4
  8. data/lib/robot_lab/memory.rb +16 -7
  9. data/lib/robot_lab/robot/hooking.rb +26 -0
  10. data/lib/robot_lab/robot/result_building.rb +119 -0
  11. data/lib/robot_lab/robot.rb +37 -120
  12. data/lib/robot_lab/run_config.rb +52 -20
  13. data/lib/robot_lab/tool.rb +7 -12
  14. data/lib/robot_lab/version.rb +1 -1
  15. data/lib/robot_lab.rb +3 -3
  16. metadata +15 -274
  17. data/.architecture/AGENTS.md +0 -32
  18. data/.architecture/config.yml +0 -8
  19. data/.architecture/members.yml +0 -60
  20. data/.architecture/reviews/feature-free-will.md +0 -490
  21. data/.architecture/reviews/overall-codebase.md +0 -427
  22. data/.claude/settings.local.json +0 -57
  23. data/.codex/config.toml +0 -2
  24. data/.envrc +0 -6
  25. data/.github/workflows/deploy-github-pages.yml +0 -52
  26. data/.irbrc +0 -6
  27. data/.loki +0 -65
  28. data/.quality/reek_baseline.txt +0 -43
  29. data/.rubocop.yml +0 -10
  30. data/Archspec.rb +0 -44
  31. data/CLAUDE.md +0 -139
  32. data/COMMITS.md +0 -196
  33. data/Rakefile +0 -193
  34. data/_typos.toml +0 -21
  35. data/agent2agent_review.md +0 -192
  36. data/agentf_improvements.md +0 -253
  37. data/agents.md +0 -14
  38. data/docs/api/core/index.md +0 -147
  39. data/docs/api/core/memory.md +0 -578
  40. data/docs/api/core/network.md +0 -553
  41. data/docs/api/core/result.md +0 -211
  42. data/docs/api/core/robot.md +0 -1667
  43. data/docs/api/core/state.md +0 -145
  44. data/docs/api/core/tool.md +0 -520
  45. data/docs/api/errors.md +0 -323
  46. data/docs/api/hooks.md +0 -469
  47. data/docs/api/index.md +0 -137
  48. data/docs/api/mcp/client.md +0 -387
  49. data/docs/api/mcp/index.md +0 -267
  50. data/docs/api/mcp/server.md +0 -252
  51. data/docs/api/mcp/transports.md +0 -339
  52. data/docs/api/messages/index.md +0 -126
  53. data/docs/api/messages/text-message.md +0 -170
  54. data/docs/api/messages/tool-call-message.md +0 -206
  55. data/docs/api/messages/tool-result-message.md +0 -242
  56. data/docs/api/messages/user-message.md +0 -232
  57. data/docs/api/skills.md +0 -423
  58. data/docs/api/streaming/context.md +0 -280
  59. data/docs/api/streaming/events.md +0 -185
  60. data/docs/api/streaming/index.md +0 -156
  61. data/docs/api/support.md +0 -846
  62. data/docs/architecture/core-concepts.md +0 -575
  63. data/docs/architecture/index.md +0 -252
  64. data/docs/architecture/message-flow.md +0 -366
  65. data/docs/architecture/network-orchestration.md +0 -478
  66. data/docs/architecture/robot-execution.md +0 -396
  67. data/docs/architecture/state-management.md +0 -410
  68. data/docs/assets/css/custom.css +0 -56
  69. data/docs/assets/images/robot_lab.jpg +0 -0
  70. data/docs/concepts.md +0 -641
  71. data/docs/examples/basic-chat.md +0 -258
  72. data/docs/examples/index.md +0 -425
  73. data/docs/examples/mcp-server.md +0 -403
  74. data/docs/examples/multi-robot-network.md +0 -476
  75. data/docs/examples/tool-usage.md +0 -468
  76. data/docs/getting-started/configuration.md +0 -645
  77. data/docs/getting-started/index.md +0 -56
  78. data/docs/getting-started/installation.md +0 -200
  79. data/docs/getting-started/quick-start.md +0 -293
  80. data/docs/guides/building-robots.md +0 -1187
  81. data/docs/guides/creating-networks.md +0 -736
  82. data/docs/guides/hooks.md +0 -1206
  83. data/docs/guides/index.md +0 -78
  84. data/docs/guides/knowledge.md +0 -219
  85. data/docs/guides/mcp-integration.md +0 -740
  86. data/docs/guides/memory.md +0 -458
  87. data/docs/guides/observability.md +0 -733
  88. data/docs/guides/streaming.md +0 -323
  89. data/docs/guides/using-tools.md +0 -780
  90. data/docs/index.md +0 -280
  91. data/docs/superpowers/plans/2026-05-06-agentskills.md +0 -1303
  92. data/docs/superpowers/specs/2026-05-06-agentskills-design.md +0 -247
  93. data/examples/.envrc +0 -1
  94. data/examples/01_simple_robot.rb +0 -31
  95. data/examples/02_tools.rb +0 -109
  96. data/examples/03_network.rb +0 -118
  97. data/examples/04_mcp.rb +0 -215
  98. data/examples/05_streaming.rb +0 -137
  99. data/examples/06_prompt_templates.rb +0 -325
  100. data/examples/07_network_memory.rb +0 -313
  101. data/examples/08_llm_config.rb +0 -162
  102. data/examples/09_chaining.rb +0 -251
  103. data/examples/10_memory.rb +0 -315
  104. data/examples/11_network_introspection.rb +0 -239
  105. data/examples/12_message_bus.rb +0 -67
  106. data/examples/13_spawn.rb +0 -85
  107. data/examples/14_rusty_circuit/.envrc +0 -1
  108. data/examples/14_rusty_circuit/.gitignore +0 -1
  109. data/examples/14_rusty_circuit/README.md +0 -1
  110. data/examples/14_rusty_circuit/comic.rb +0 -149
  111. data/examples/14_rusty_circuit/display.rb +0 -217
  112. data/examples/14_rusty_circuit/heckler.rb +0 -65
  113. data/examples/14_rusty_circuit/open_mic.rb +0 -132
  114. data/examples/14_rusty_circuit/prompts/open_mic_comic.md +0 -20
  115. data/examples/14_rusty_circuit/prompts/open_mic_heckler.md +0 -23
  116. data/examples/14_rusty_circuit/prompts/open_mic_scout.md +0 -20
  117. data/examples/14_rusty_circuit/scout.rb +0 -165
  118. data/examples/14_rusty_circuit/show.log +0 -234
  119. data/examples/15_memory_network_and_bus/.envrc +0 -1
  120. data/examples/15_memory_network_and_bus/editor_in_chief.rb +0 -24
  121. data/examples/15_memory_network_and_bus/editorial_pipeline.rb +0 -213
  122. data/examples/15_memory_network_and_bus/linux_writer.rb +0 -80
  123. data/examples/15_memory_network_and_bus/os_editor.rb +0 -48
  124. data/examples/15_memory_network_and_bus/os_writer.rb +0 -49
  125. data/examples/15_memory_network_and_bus/output/combined_article.md +0 -13
  126. data/examples/15_memory_network_and_bus/output/final_article.md +0 -13
  127. data/examples/15_memory_network_and_bus/output/linux_draft.md +0 -7
  128. data/examples/15_memory_network_and_bus/output/mac_draft.md +0 -7
  129. data/examples/15_memory_network_and_bus/output/memory.json +0 -13
  130. data/examples/15_memory_network_and_bus/output/revision_1.md +0 -18
  131. data/examples/15_memory_network_and_bus/output/revision_2.md +0 -13
  132. data/examples/15_memory_network_and_bus/output/windows_draft.md +0 -7
  133. data/examples/15_memory_network_and_bus/prompts/os_advocate.md +0 -13
  134. data/examples/15_memory_network_and_bus/prompts/os_chief.md +0 -13
  135. data/examples/15_memory_network_and_bus/prompts/os_editor.md +0 -13
  136. data/examples/16_writers_room/.envrc +0 -1
  137. data/examples/16_writers_room/display.rb +0 -158
  138. data/examples/16_writers_room/output/.gitignore +0 -4
  139. data/examples/16_writers_room/output/README.md +0 -69
  140. data/examples/16_writers_room/output/opus_001.md +0 -263
  141. data/examples/16_writers_room/output/opus_001_notes.log +0 -470
  142. data/examples/16_writers_room/output/opus_002.md +0 -245
  143. data/examples/16_writers_room/output/opus_002_notes.log +0 -546
  144. data/examples/16_writers_room/output/opus_002_screenplay.md +0 -7989
  145. data/examples/16_writers_room/output/opus_002_screenplay_notes.md +0 -993
  146. data/examples/16_writers_room/prompts/screenplay_writer.md +0 -66
  147. data/examples/16_writers_room/prompts/writer.md +0 -37
  148. data/examples/16_writers_room/room.rb +0 -186
  149. data/examples/16_writers_room/tools.rb +0 -173
  150. data/examples/16_writers_room/writer.rb +0 -121
  151. data/examples/16_writers_room/writers_room.rb +0 -256
  152. data/examples/17_skills.rb +0 -234
  153. data/examples/18_rails/.envrc +0 -3
  154. data/examples/18_rails/.gitignore +0 -5
  155. data/examples/18_rails/Gemfile +0 -11
  156. data/examples/18_rails/README.md +0 -67
  157. data/examples/18_rails/Rakefile +0 -4
  158. data/examples/18_rails/app/controllers/application_controller.rb +0 -4
  159. data/examples/18_rails/app/controllers/chat_controller.rb +0 -50
  160. data/examples/18_rails/app/jobs/application_job.rb +0 -4
  161. data/examples/18_rails/app/jobs/robot_run_job.rb +0 -25
  162. data/examples/18_rails/app/models/application_record.rb +0 -5
  163. data/examples/18_rails/app/models/robot_lab_result.rb +0 -36
  164. data/examples/18_rails/app/models/robot_lab_thread.rb +0 -23
  165. data/examples/18_rails/app/robots/chat_robot.rb +0 -25
  166. data/examples/18_rails/app/tools/time_tool.rb +0 -9
  167. data/examples/18_rails/app/views/chat/_user_message.html.erb +0 -1
  168. data/examples/18_rails/app/views/chat/index.html.erb +0 -67
  169. data/examples/18_rails/app/views/layouts/application.html.erb +0 -49
  170. data/examples/18_rails/bin/dev +0 -7
  171. data/examples/18_rails/bin/rails +0 -6
  172. data/examples/18_rails/bin/setup +0 -15
  173. data/examples/18_rails/config/application.rb +0 -33
  174. data/examples/18_rails/config/cable.yml +0 -2
  175. data/examples/18_rails/config/database.yml +0 -5
  176. data/examples/18_rails/config/environment.rb +0 -4
  177. data/examples/18_rails/config/initializers/robot_lab.rb +0 -11
  178. data/examples/18_rails/config/routes.rb +0 -6
  179. data/examples/18_rails/config.ru +0 -4
  180. data/examples/18_rails/db/migrate/001_create_robot_lab_tables.rb +0 -32
  181. data/examples/19_token_tracking.rb +0 -138
  182. data/examples/20_circuit_breaker.rb +0 -147
  183. data/examples/21_learning_loop.rb +0 -181
  184. data/examples/22_context_compression.rb +0 -172
  185. data/examples/23_convergence.rb +0 -133
  186. data/examples/24_structured_delegation.rb +0 -151
  187. data/examples/25_history_search/conversation.jsonl +0 -30
  188. data/examples/25_history_search.rb +0 -133
  189. data/examples/26_document_store/api_versioning_adr.md +0 -52
  190. data/examples/26_document_store/incident_postmortem.md +0 -46
  191. data/examples/26_document_store/postgres_runbook.md +0 -49
  192. data/examples/26_document_store/redis_caching_guide.md +0 -48
  193. data/examples/26_document_store/sidekiq_guide.md +0 -51
  194. data/examples/26_document_store.rb +0 -140
  195. data/examples/27_incident_response/incident_response.rb +0 -261
  196. data/examples/28_mcp_discovery.rb +0 -113
  197. data/examples/29_ractor_tools.rb +0 -240
  198. data/examples/30_ractor_network.rb +0 -252
  199. data/examples/31_launch_assessment.rb +0 -246
  200. data/examples/32_newsletter_reader.rb +0 -193
  201. data/examples/33_stock_generator.rb +0 -80
  202. data/examples/33_stock_predictor.rb +0 -327
  203. data/examples/34_agentskills.rb +0 -76
  204. data/examples/35_hooks.rb +0 -266
  205. data/examples/README.md +0 -533
  206. data/examples/common.rb +0 -148
  207. data/examples/prompts/assistant.md +0 -5
  208. data/examples/prompts/audit_trail.md +0 -8
  209. data/examples/prompts/billing.md +0 -10
  210. data/examples/prompts/classifier.md +0 -7
  211. data/examples/prompts/comedian.md +0 -6
  212. data/examples/prompts/comedy_critic.md +0 -10
  213. data/examples/prompts/configurable.md +0 -9
  214. data/examples/prompts/dispatcher.md +0 -12
  215. data/examples/prompts/entity_extractor.md +0 -14
  216. data/examples/prompts/escalation.md +0 -42
  217. data/examples/prompts/frontmatter_mcp_test.md +0 -9
  218. data/examples/prompts/frontmatter_named_test.md +0 -5
  219. data/examples/prompts/frontmatter_tools_test.md +0 -6
  220. data/examples/prompts/general.md +0 -7
  221. data/examples/prompts/github_assistant.md +0 -14
  222. data/examples/prompts/helper.md +0 -4
  223. data/examples/prompts/incident_responder.md +0 -18
  224. data/examples/prompts/keyword_extractor.md +0 -11
  225. data/examples/prompts/llm_config_demo.md +0 -20
  226. data/examples/prompts/order_support.md +0 -35
  227. data/examples/prompts/os_advocate.md +0 -13
  228. data/examples/prompts/os_chief.md +0 -13
  229. data/examples/prompts/os_editor.md +0 -13
  230. data/examples/prompts/parameterized_main_test.md +0 -6
  231. data/examples/prompts/pii_redactor.md +0 -7
  232. data/examples/prompts/product_support.md +0 -37
  233. data/examples/prompts/runbook_protocol.md +0 -12
  234. data/examples/prompts/sentiment_analyzer.md +0 -12
  235. data/examples/prompts/skill_a_test.md +0 -4
  236. data/examples/prompts/skill_b_test.md +0 -4
  237. data/examples/prompts/skill_config_test.md +0 -5
  238. data/examples/prompts/skill_cycle_a_test.md +0 -6
  239. data/examples/prompts/skill_cycle_b_test.md +0 -6
  240. data/examples/prompts/skill_description_test.md +0 -4
  241. data/examples/prompts/skill_leaf_test.md +0 -4
  242. data/examples/prompts/skill_nested_test.md +0 -6
  243. data/examples/prompts/skill_refs_main_test.md +0 -6
  244. data/examples/prompts/skill_self_ref_test.md +0 -6
  245. data/examples/prompts/skill_with_mcp_test.md +0 -9
  246. data/examples/prompts/skill_with_params_test.md +0 -6
  247. data/examples/prompts/skill_with_robot_name_test.md +0 -5
  248. data/examples/prompts/skill_with_tools_test.md +0 -6
  249. data/examples/prompts/sre_compliance.md +0 -10
  250. data/examples/prompts/structured_output.md +0 -7
  251. data/examples/prompts/synthesizer.md +0 -17
  252. data/examples/prompts/technical.md +0 -10
  253. data/examples/prompts/template_with_skills_test.md +0 -6
  254. data/examples/prompts/triage.md +0 -22
  255. data/examples/ruboruby.md +0 -423
  256. data/examples/xyzzy.rb +0 -97
  257. data/logfile +0 -8
  258. data/mkdocs.yml +0 -209
  259. data/robot_concurrency.md +0 -38
  260. data/simple_acp_review.md +0 -298
  261. data/temp.md +0 -6
  262. data/tool_manifest_plan.md +0 -155
@@ -1,200 +0,0 @@
1
- # Installation
2
-
3
- This guide covers installing RobotLab in your Ruby project.
4
-
5
- ## Requirements
6
-
7
- - **Ruby**: 3.2 or higher
8
- - **Bundler**: 2.0 or higher (recommended)
9
-
10
- ## Install via Bundler
11
-
12
- Add RobotLab to your `Gemfile`:
13
-
14
- ```ruby
15
- gem "robot_lab"
16
- ```
17
-
18
- Then install:
19
-
20
- ```bash
21
- bundle install
22
- ```
23
-
24
- ## Install via RubyGems
25
-
26
- Or install directly:
27
-
28
- ```bash
29
- gem install robot_lab
30
- ```
31
-
32
- ## Dependencies
33
-
34
- RobotLab automatically installs these core dependencies:
35
-
36
- | Gem | Purpose |
37
- |-----|---------|
38
- | `ruby_llm` (~> 1.12) | LLM provider integrations (Anthropic, OpenAI, Gemini, etc.) |
39
- | `prompt_manager` (~> 1.0) | Template-based prompt management with YAML front matter |
40
- | `simple_flow` (~> 0.4) | Pipeline workflow execution for networks |
41
- | `myway_config` (~> 0.1) | Layered configuration (defaults, env vars, config files) |
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
- | `zeitwerk` (~> 2.6) | Autoloading and eager loading |
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 |
51
-
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.
55
-
56
- ### Optional Dependencies
57
-
58
- Several features are gated behind gems the core gem does **not** install. Add
59
- whichever you need to your own `Gemfile`:
60
-
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` |
67
-
68
- ```ruby
69
- # Gemfile
70
- gem "classifier", "~> 2.3"
71
- gem "robot_lab-document_store"
72
- gem "redis"
73
- gem "robot_lab-ractor"
74
- ```
75
-
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.
81
-
82
- ## Verify Installation
83
-
84
- Create a test file to verify everything works:
85
-
86
- ```ruby
87
- # test_robot_lab.rb
88
- require "robot_lab"
89
-
90
- puts "RobotLab version: #{RobotLab::VERSION}"
91
- puts "Installation successful!"
92
- ```
93
-
94
- Run it:
95
-
96
- ```bash
97
- ruby test_robot_lab.rb
98
- # => RobotLab version: 0.2.6
99
- # => Installation successful!
100
- ```
101
-
102
- ## Rails Installation
103
-
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.
108
-
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.
112
-
113
- For generators, an `ActiveJob` base class, and Turbo Stream broadcasting, add the
114
- extension gem:
115
-
116
- ```ruby
117
- # Gemfile
118
- gem "robot_lab"
119
- gem "robot_lab-rails"
120
- ```
121
-
122
- Then follow that gem's own installation instructions for its generators and
123
- migrations.
124
-
125
- ## Environment Setup
126
-
127
- RobotLab uses a layered configuration system (see [Configuration](configuration.md) for full details). The simplest way to get started is with environment variables:
128
-
129
- === "Anthropic (Recommended)"
130
-
131
- ```bash
132
- export ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY="sk-ant-..."
133
- ```
134
-
135
- === "OpenAI"
136
-
137
- ```bash
138
- export ROBOT_LAB_RUBY_LLM__OPENAI_API_KEY="sk-..."
139
- ```
140
-
141
- === "Google Gemini"
142
-
143
- ```bash
144
- export ROBOT_LAB_RUBY_LLM__GEMINI_API_KEY="..."
145
- ```
146
-
147
- !!! tip "Using dotenv"
148
- For development, consider using the [dotenv](https://github.com/bkeepers/dotenv) gem to manage environment variables:
149
-
150
- ```ruby
151
- # Gemfile
152
- gem "dotenv", groups: [:development, :test]
153
- ```
154
-
155
- ```bash
156
- # .env
157
- ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY=sk-ant-...
158
- ```
159
-
160
- !!! info "Direct provider env vars"
161
- RubyLLM also reads provider-specific environment variables directly (e.g., `ANTHROPIC_API_KEY`). If you already have those set, they will be picked up automatically. The `ROBOT_LAB_RUBY_LLM__*` prefix gives you explicit control through RobotLab's config layer.
162
-
163
- ## Troubleshooting
164
-
165
- ### Gem Installation Fails
166
-
167
- If you encounter SSL or network errors:
168
-
169
- ```bash
170
- # Update RubyGems
171
- gem update --system
172
-
173
- # Try installing with verbose output
174
- gem install robot_lab --verbose
175
- ```
176
-
177
- ### Missing Dependencies
178
-
179
- If you see a `LoadError` (or a `RobotLab::DependencyError`) naming a gem RobotLab
180
- does not depend on, add it yourself:
181
-
182
- ```bash
183
- # e.g. compress_history / Convergence need the classifier gem
184
- bundle add classifier
185
- ```
186
-
187
- ### API Key Issues
188
-
189
- If you see authentication errors:
190
-
191
- 1. Verify your API key is set: `echo $ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY`
192
- 2. Check the key is valid in your provider's console
193
- 3. Ensure you're using the correct environment variable name
194
-
195
- ## Next Steps
196
-
197
- Now that RobotLab is installed:
198
-
199
- - [:octicons-arrow-right-24: Quick Start](quick-start.md) - Build your first robot
200
- - [:octicons-arrow-right-24: Configuration](configuration.md) - Configure defaults
@@ -1,293 +0,0 @@
1
- # Quick Start
2
-
3
- Build your first RobotLab application in 5 minutes.
4
-
5
- ## Step 1: Set Up API Keys
6
-
7
- RobotLab reads configuration from environment variables automatically. Set your API key before running any code:
8
-
9
- ```bash
10
- export ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY="sk-ant-..."
11
- ```
12
-
13
- Or create a config file at `./config/robot_lab.yml`:
14
-
15
- ```yaml
16
- ruby_llm:
17
- anthropic_api_key: <%= ENV['ANTHROPIC_API_KEY'] %>
18
- ```
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
-
25
- See [Configuration](configuration.md) for all configuration options.
26
-
27
- ## Step 2: Create a Robot
28
-
29
- Build a simple assistant robot using keyword arguments:
30
-
31
- ```ruby
32
- require "robot_lab"
33
-
34
- assistant = RobotLab.build(
35
- name: "assistant",
36
- system_prompt: "You are a helpful AI assistant. You provide clear, accurate, and concise answers."
37
- )
38
- ```
39
-
40
- ## Step 3: Run It
41
-
42
- Send a message and get a response:
43
-
44
- ```ruby
45
- result = assistant.run("What is Ruby on Rails?")
46
-
47
- puts result.last_text_content
48
- ```
49
-
50
- The `run` method takes a positional string message and returns a `RobotResult`. Use `last_text_content` to extract the response text.
51
-
52
- ## Complete Example
53
-
54
- Here is everything together in one file:
55
-
56
- ```ruby title="hello_robot.rb"
57
- require "robot_lab"
58
-
59
- # Build a robot with an inline system prompt
60
- assistant = RobotLab.build(
61
- name: "assistant",
62
- system_prompt: "You are a helpful AI assistant. Be concise and friendly."
63
- )
64
-
65
- # Run the robot with a message
66
- result = assistant.run("Hello! What can you help me with?")
67
-
68
- # Print the response
69
- puts result.last_text_content
70
- ```
71
-
72
- Run it:
73
-
74
- ```bash
75
- ruby hello_robot.rb
76
- ```
77
-
78
- ## Using Templates
79
-
80
- Instead of inline prompts, you can use template files managed by `prompt_manager`. Templates are `.md` files with YAML front matter:
81
-
82
- ```markdown title="prompts/helper.md"
83
- ---
84
- description: A helpful assistant
85
- parameters:
86
- company_name: null
87
- ---
88
- You are a helpful assistant for <%= company_name %>.
89
- Be concise and friendly in your responses.
90
- ```
91
-
92
- Create the robot with a template reference and context:
93
-
94
- ```ruby
95
- robot = RobotLab.build(
96
- name: "helper",
97
- template: :helper,
98
- context: { company_name: "Acme Corp" }
99
- )
100
-
101
- result = robot.run("What services do you offer?")
102
- puts result.last_text_content
103
- ```
104
-
105
- Templates are loaded from the `prompts/` directory by default (or `app/prompts/` in Rails). You can change this in your config.
106
-
107
- ## Adding a Tool
108
-
109
- Give your robot custom capabilities by defining a `RubyLLM::Tool` subclass:
110
-
111
- ```ruby title="hello_tools.rb"
112
- require "robot_lab"
113
-
114
- class CurrentTime < RubyLLM::Tool
115
- description "Get the current date and time"
116
-
117
- param :timezone,
118
- type: "string",
119
- desc: "Timezone name (e.g., 'UTC', 'US/Eastern')",
120
- required: false
121
-
122
- def execute(timezone: "UTC")
123
- Time.now.getlocal(timezone_offset(timezone)).strftime("%Y-%m-%d %H:%M:%S %Z")
124
- rescue => e
125
- Time.now.utc.strftime("%Y-%m-%d %H:%M:%S UTC")
126
- end
127
-
128
- private
129
-
130
- def timezone_offset(tz)
131
- case tz
132
- when "UTC" then "+00:00"
133
- when "US/Eastern" then "-05:00"
134
- when "US/Pacific" then "-08:00"
135
- else "+00:00"
136
- end
137
- end
138
- end
139
-
140
- # Pass tools via the local_tools: parameter
141
- assistant = RobotLab.build(
142
- name: "time_bot",
143
- system_prompt: "You are a helpful assistant. Use the current_time tool when users ask about the time.",
144
- local_tools: [CurrentTime]
145
- )
146
-
147
- # tools: :inherit is REQUIRED -- run() sends no tools without it
148
- result = assistant.run("What time is it right now?", tools: :inherit)
149
- puts result.last_text_content
150
- ```
151
-
152
- Tools are passed to the robot via the `local_tools:` keyword argument as an array of `RubyLLM::Tool` subclasses.
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
-
171
- ## Method Chaining
172
-
173
- Robots support a chaining API for runtime adjustments:
174
-
175
- ```ruby
176
- robot = RobotLab.build(name: "writer")
177
-
178
- result = robot
179
- .with_instructions("You are a creative fiction writer.")
180
- .with_temperature(0.9)
181
- .with_model("claude-sonnet-4")
182
- .run("Write a haiku about programming.")
183
-
184
- puts result.last_text_content
185
- ```
186
-
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
- > ```
201
-
202
- ## Multi-Robot Network
203
-
204
- Create a pipeline of robots using `RobotLab.create_network`. Networks use `SimpleFlow::Pipeline` under the hood with `task` definitions and dependency tracking:
205
-
206
- ```ruby title="hello_network.rb"
207
- require "robot_lab"
208
-
209
- # Build specialized robots
210
- analyst = RobotLab.build(
211
- name: "analyst",
212
- system_prompt: <<~PROMPT
213
- You are a text analyst. Analyze the given text and provide a brief
214
- summary of its key themes and sentiment. Be concise -- 2-3 sentences max.
215
- PROMPT
216
- )
217
-
218
- writer = RobotLab.build(
219
- name: "writer",
220
- system_prompt: <<~PROMPT
221
- You are a professional copywriter. Based on the analysis you receive,
222
- write a short, engaging summary suitable for a newsletter. Keep it
223
- to one paragraph.
224
- PROMPT
225
- )
226
-
227
- # Create a sequential pipeline
228
- network = RobotLab.create_network(name: "content_pipeline") do
229
- task :analyst, analyst, depends_on: :none
230
- task :writer, writer, depends_on: [:analyst]
231
- end
232
-
233
- # Run the network
234
- result = network.run(
235
- message: "Ruby 3.4 was released with significant performance improvements..."
236
- )
237
-
238
- # The final result is from the last robot in the pipeline
239
- if result.value.is_a?(RobotLab::RobotResult)
240
- puts result.value.last_text_content
241
- end
242
-
243
- # Access intermediate results by ROBOT name (see note below)
244
- if result.context[:analyst]
245
- puts "\nAnalysis: #{result.context[:analyst].last_text_content}"
246
- end
247
- ```
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
-
259
- ### Network Task Dependencies
260
-
261
- Tasks declare their dependencies to control execution order:
262
-
263
- | Dependency | Meaning |
264
- |-----------|---------|
265
- | `depends_on: :none` | Entry point -- runs first with no dependencies |
266
- | `depends_on: [:task_name]` | Runs after the named task(s) complete |
267
- | `depends_on: :optional` | Only runs if explicitly activated by a preceding task |
268
-
269
- Tasks with non-overlapping dependencies can execute in parallel automatically.
270
-
271
- ## What's Next?
272
-
273
- You have built your first RobotLab application. Here is where to go next:
274
-
275
- <div class="grid cards" markdown>
276
-
277
- - [:octicons-gear-24: **Configuration**](configuration.md)
278
-
279
- Learn all configuration options
280
-
281
- - [:octicons-cpu-24: **Building Robots**](../guides/building-robots.md)
282
-
283
- Deep dive into robot creation
284
-
285
- - [:octicons-tools-24: **Using Tools**](../guides/using-tools.md)
286
-
287
- Give robots custom capabilities
288
-
289
- - [:octicons-git-branch-24: **Creating Networks**](../guides/creating-networks.md)
290
-
291
- Advanced network patterns
292
-
293
- </div>