robot_lab 0.3.0 → 0.5.0

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 (274) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +60 -0
  3. data/README.md +29 -19
  4. data/lib/robot_lab/errors.rb +4 -0
  5. data/lib/robot_lab/hook_context.rb +9 -2
  6. data/lib/robot_lab/mcp/registry.rb +99 -0
  7. data/lib/robot_lab/mcp/server.rb +47 -83
  8. data/lib/robot_lab/mcp/server_discovery.rb +22 -9
  9. data/lib/robot_lab/mcp.rb +259 -0
  10. data/lib/robot_lab/robot/mcp_management.rb +159 -105
  11. data/lib/robot_lab/robot/tool_call_gating.rb +144 -0
  12. data/lib/robot_lab/robot.rb +72 -99
  13. data/lib/robot_lab/run_config.rb +3 -2
  14. data/lib/robot_lab/tool.rb +8 -23
  15. data/lib/robot_lab/version.rb +1 -1
  16. data/lib/robot_lab.rb +1 -4
  17. metadata +16 -292
  18. data/.architecture/AGENTS.md +0 -32
  19. data/.architecture/config.yml +0 -8
  20. data/.architecture/members.yml +0 -60
  21. data/.architecture/reviews/feature-free-will.md +0 -490
  22. data/.architecture/reviews/overall-codebase.md +0 -427
  23. data/.claude/settings.local.json +0 -57
  24. data/.codex/config.toml +0 -2
  25. data/.envrc +0 -6
  26. data/.github/workflows/deploy-github-pages.yml +0 -52
  27. data/.irbrc +0 -6
  28. data/.loki +0 -65
  29. data/.quality/reek_baseline.txt +0 -43
  30. data/.rubocop.yml +0 -10
  31. data/Archspec.rb +0 -44
  32. data/CLAUDE.md +0 -141
  33. data/COMMITS.md +0 -196
  34. data/Rakefile +0 -193
  35. data/_typos.toml +0 -21
  36. data/agent2agent_review.md +0 -192
  37. data/agentf_improvements.md +0 -253
  38. data/agents.md +0 -14
  39. data/docs/api/core/index.md +0 -147
  40. data/docs/api/core/memory.md +0 -578
  41. data/docs/api/core/network.md +0 -553
  42. data/docs/api/core/result.md +0 -211
  43. data/docs/api/core/robot.md +0 -1667
  44. data/docs/api/core/state.md +0 -145
  45. data/docs/api/core/tool.md +0 -520
  46. data/docs/api/errors.md +0 -323
  47. data/docs/api/hooks.md +0 -469
  48. data/docs/api/index.md +0 -137
  49. data/docs/api/mcp/client.md +0 -387
  50. data/docs/api/mcp/index.md +0 -267
  51. data/docs/api/mcp/server.md +0 -252
  52. data/docs/api/mcp/transports.md +0 -339
  53. data/docs/api/messages/index.md +0 -126
  54. data/docs/api/messages/text-message.md +0 -170
  55. data/docs/api/messages/tool-call-message.md +0 -206
  56. data/docs/api/messages/tool-result-message.md +0 -242
  57. data/docs/api/messages/user-message.md +0 -232
  58. data/docs/api/skills.md +0 -423
  59. data/docs/api/streaming/context.md +0 -280
  60. data/docs/api/streaming/events.md +0 -185
  61. data/docs/api/streaming/index.md +0 -156
  62. data/docs/api/support.md +0 -846
  63. data/docs/architecture/core-concepts.md +0 -575
  64. data/docs/architecture/index.md +0 -252
  65. data/docs/architecture/message-flow.md +0 -366
  66. data/docs/architecture/network-orchestration.md +0 -478
  67. data/docs/architecture/robot-execution.md +0 -396
  68. data/docs/architecture/state-management.md +0 -410
  69. data/docs/assets/css/custom.css +0 -56
  70. data/docs/assets/images/robot_lab.jpg +0 -0
  71. data/docs/concepts.md +0 -641
  72. data/docs/examples/basic-chat.md +0 -258
  73. data/docs/examples/index.md +0 -425
  74. data/docs/examples/mcp-server.md +0 -403
  75. data/docs/examples/multi-robot-network.md +0 -476
  76. data/docs/examples/tool-usage.md +0 -468
  77. data/docs/getting-started/configuration.md +0 -645
  78. data/docs/getting-started/index.md +0 -56
  79. data/docs/getting-started/installation.md +0 -197
  80. data/docs/getting-started/quick-start.md +0 -293
  81. data/docs/guides/building-robots.md +0 -1187
  82. data/docs/guides/creating-networks.md +0 -736
  83. data/docs/guides/hooks.md +0 -1206
  84. data/docs/guides/index.md +0 -78
  85. data/docs/guides/knowledge.md +0 -219
  86. data/docs/guides/mcp-integration.md +0 -740
  87. data/docs/guides/memory.md +0 -458
  88. data/docs/guides/observability.md +0 -733
  89. data/docs/guides/streaming.md +0 -323
  90. data/docs/guides/using-tools.md +0 -780
  91. data/docs/index.md +0 -280
  92. data/docs/superpowers/plans/2026-05-06-agentskills.md +0 -1303
  93. data/docs/superpowers/specs/2026-05-06-agentskills-design.md +0 -247
  94. data/examples/.envrc +0 -3
  95. data/examples/01_simple_robot.rb +0 -31
  96. data/examples/02_tools.rb +0 -109
  97. data/examples/03_network.rb +0 -118
  98. data/examples/04_mcp.rb +0 -217
  99. data/examples/05_streaming.rb +0 -137
  100. data/examples/06_prompt_templates.rb +0 -325
  101. data/examples/07_network_memory.rb +0 -313
  102. data/examples/08_llm_config.rb +0 -162
  103. data/examples/09_chaining.rb +0 -251
  104. data/examples/10_memory.rb +0 -315
  105. data/examples/11_network_introspection.rb +0 -239
  106. data/examples/12_message_bus.rb +0 -67
  107. data/examples/13_spawn.rb +0 -85
  108. data/examples/14_rusty_circuit/.envrc +0 -1
  109. data/examples/14_rusty_circuit/.gitignore +0 -1
  110. data/examples/14_rusty_circuit/README.md +0 -1
  111. data/examples/14_rusty_circuit/comic.rb +0 -149
  112. data/examples/14_rusty_circuit/display.rb +0 -217
  113. data/examples/14_rusty_circuit/heckler.rb +0 -65
  114. data/examples/14_rusty_circuit/open_mic.rb +0 -132
  115. data/examples/14_rusty_circuit/prompts/open_mic_comic.md +0 -20
  116. data/examples/14_rusty_circuit/prompts/open_mic_heckler.md +0 -23
  117. data/examples/14_rusty_circuit/prompts/open_mic_scout.md +0 -20
  118. data/examples/14_rusty_circuit/scout.rb +0 -165
  119. data/examples/14_rusty_circuit/show.log +0 -234
  120. data/examples/15_memory_network_and_bus/.envrc +0 -1
  121. data/examples/15_memory_network_and_bus/README.md +0 -66
  122. data/examples/15_memory_network_and_bus/editor_in_chief.rb +0 -24
  123. data/examples/15_memory_network_and_bus/editorial_pipeline.rb +0 -213
  124. data/examples/15_memory_network_and_bus/linux_writer.rb +0 -80
  125. data/examples/15_memory_network_and_bus/os_editor.rb +0 -48
  126. data/examples/15_memory_network_and_bus/os_writer.rb +0 -49
  127. data/examples/15_memory_network_and_bus/output/combined_article.md +0 -11
  128. data/examples/15_memory_network_and_bus/output/final_article.md +0 -8
  129. data/examples/15_memory_network_and_bus/output/linux_draft.md +0 -7
  130. data/examples/15_memory_network_and_bus/output/mac_draft.md +0 -7
  131. data/examples/15_memory_network_and_bus/output/memory.json +0 -13
  132. data/examples/15_memory_network_and_bus/output/revision_1.md +0 -29
  133. data/examples/15_memory_network_and_bus/output/revision_2.md +0 -50
  134. data/examples/15_memory_network_and_bus/output/revision_3.md +0 -8
  135. data/examples/15_memory_network_and_bus/output/windows_draft.md +0 -7
  136. data/examples/15_memory_network_and_bus/prompts/os_advocate.md +0 -13
  137. data/examples/15_memory_network_and_bus/prompts/os_chief.md +0 -13
  138. data/examples/15_memory_network_and_bus/prompts/os_editor.md +0 -13
  139. data/examples/16_writers_room/.envrc +0 -1
  140. data/examples/16_writers_room/display.rb +0 -158
  141. data/examples/16_writers_room/output/.gitignore +0 -4
  142. data/examples/16_writers_room/output/README.md +0 -69
  143. data/examples/16_writers_room/output/opus_001.md +0 -263
  144. data/examples/16_writers_room/output/opus_001_notes.log +0 -470
  145. data/examples/16_writers_room/output/opus_002.md +0 -245
  146. data/examples/16_writers_room/output/opus_002_notes.log +0 -546
  147. data/examples/16_writers_room/output/opus_002_screenplay.md +0 -7989
  148. data/examples/16_writers_room/output/opus_002_screenplay_notes.md +0 -993
  149. data/examples/16_writers_room/prompts/screenplay_writer.md +0 -66
  150. data/examples/16_writers_room/prompts/writer.md +0 -37
  151. data/examples/16_writers_room/room.rb +0 -186
  152. data/examples/16_writers_room/tools.rb +0 -173
  153. data/examples/16_writers_room/writer.rb +0 -121
  154. data/examples/16_writers_room/writers_room.rb +0 -256
  155. data/examples/17_skills.rb +0 -234
  156. data/examples/18_rails/.envrc +0 -3
  157. data/examples/18_rails/.gitignore +0 -5
  158. data/examples/18_rails/Gemfile +0 -11
  159. data/examples/18_rails/README.md +0 -67
  160. data/examples/18_rails/Rakefile +0 -4
  161. data/examples/18_rails/app/controllers/application_controller.rb +0 -4
  162. data/examples/18_rails/app/controllers/chat_controller.rb +0 -50
  163. data/examples/18_rails/app/jobs/application_job.rb +0 -4
  164. data/examples/18_rails/app/jobs/robot_run_job.rb +0 -25
  165. data/examples/18_rails/app/models/application_record.rb +0 -5
  166. data/examples/18_rails/app/models/robot_lab_result.rb +0 -36
  167. data/examples/18_rails/app/models/robot_lab_thread.rb +0 -23
  168. data/examples/18_rails/app/robots/chat_robot.rb +0 -25
  169. data/examples/18_rails/app/tools/time_tool.rb +0 -9
  170. data/examples/18_rails/app/views/chat/_user_message.html.erb +0 -1
  171. data/examples/18_rails/app/views/chat/index.html.erb +0 -67
  172. data/examples/18_rails/app/views/layouts/application.html.erb +0 -49
  173. data/examples/18_rails/bin/dev +0 -7
  174. data/examples/18_rails/bin/rails +0 -6
  175. data/examples/18_rails/bin/setup +0 -15
  176. data/examples/18_rails/config/application.rb +0 -33
  177. data/examples/18_rails/config/cable.yml +0 -2
  178. data/examples/18_rails/config/database.yml +0 -5
  179. data/examples/18_rails/config/environment.rb +0 -4
  180. data/examples/18_rails/config/initializers/robot_lab.rb +0 -11
  181. data/examples/18_rails/config/routes.rb +0 -6
  182. data/examples/18_rails/config.ru +0 -4
  183. data/examples/18_rails/db/migrate/001_create_robot_lab_tables.rb +0 -32
  184. data/examples/19_token_tracking.rb +0 -138
  185. data/examples/20_circuit_breaker.rb +0 -147
  186. data/examples/21_learning_loop.rb +0 -181
  187. data/examples/22_context_compression.rb +0 -172
  188. data/examples/23_convergence.rb +0 -133
  189. data/examples/24_structured_delegation.rb +0 -151
  190. data/examples/25_history_search/conversation.jsonl +0 -30
  191. data/examples/25_history_search.rb +0 -133
  192. data/examples/26_document_store/api_versioning_adr.md +0 -52
  193. data/examples/26_document_store/incident_postmortem.md +0 -46
  194. data/examples/26_document_store/postgres_runbook.md +0 -49
  195. data/examples/26_document_store/redis_caching_guide.md +0 -48
  196. data/examples/26_document_store/sidekiq_guide.md +0 -51
  197. data/examples/26_document_store.rb +0 -140
  198. data/examples/27_incident_response/README.md +0 -65
  199. data/examples/27_incident_response/incident_response.rb +0 -261
  200. data/examples/28_mcp_discovery.rb +0 -113
  201. data/examples/29_ractor_tools.rb +0 -240
  202. data/examples/30_ractor_network.rb +0 -252
  203. data/examples/31_launch_assessment.rb +0 -246
  204. data/examples/32_newsletter_reader.rb +0 -193
  205. data/examples/33_stock_generator.rb +0 -80
  206. data/examples/33_stock_predictor.rb +0 -327
  207. data/examples/34_agentskills.rb +0 -76
  208. data/examples/35_hooks.rb +0 -266
  209. data/examples/README.md +0 -550
  210. data/examples/common.rb +0 -180
  211. data/examples/prompts/assistant.md +0 -5
  212. data/examples/prompts/audit_trail.md +0 -8
  213. data/examples/prompts/billing.md +0 -10
  214. data/examples/prompts/classifier.md +0 -7
  215. data/examples/prompts/comedian.md +0 -6
  216. data/examples/prompts/comedy_critic.md +0 -10
  217. data/examples/prompts/configurable.md +0 -9
  218. data/examples/prompts/dispatcher.md +0 -12
  219. data/examples/prompts/entity_extractor.md +0 -14
  220. data/examples/prompts/escalation.md +0 -42
  221. data/examples/prompts/frontmatter_mcp_test.md +0 -9
  222. data/examples/prompts/frontmatter_named_test.md +0 -5
  223. data/examples/prompts/frontmatter_tools_test.md +0 -6
  224. data/examples/prompts/general.md +0 -7
  225. data/examples/prompts/github_assistant.md +0 -14
  226. data/examples/prompts/helper.md +0 -4
  227. data/examples/prompts/incident_responder.md +0 -18
  228. data/examples/prompts/keyword_extractor.md +0 -11
  229. data/examples/prompts/llm_config_demo.md +0 -20
  230. data/examples/prompts/order_support.md +0 -35
  231. data/examples/prompts/os_advocate.md +0 -13
  232. data/examples/prompts/os_chief.md +0 -13
  233. data/examples/prompts/os_editor.md +0 -13
  234. data/examples/prompts/parameterized_main_test.md +0 -6
  235. data/examples/prompts/pii_redactor.md +0 -7
  236. data/examples/prompts/product_support.md +0 -37
  237. data/examples/prompts/runbook_protocol.md +0 -12
  238. data/examples/prompts/sentiment_analyzer.md +0 -12
  239. data/examples/prompts/skill_a_test.md +0 -4
  240. data/examples/prompts/skill_b_test.md +0 -4
  241. data/examples/prompts/skill_config_test.md +0 -5
  242. data/examples/prompts/skill_cycle_a_test.md +0 -6
  243. data/examples/prompts/skill_cycle_b_test.md +0 -6
  244. data/examples/prompts/skill_description_test.md +0 -4
  245. data/examples/prompts/skill_leaf_test.md +0 -4
  246. data/examples/prompts/skill_nested_test.md +0 -6
  247. data/examples/prompts/skill_refs_main_test.md +0 -6
  248. data/examples/prompts/skill_self_ref_test.md +0 -6
  249. data/examples/prompts/skill_with_mcp_test.md +0 -9
  250. data/examples/prompts/skill_with_params_test.md +0 -6
  251. data/examples/prompts/skill_with_robot_name_test.md +0 -5
  252. data/examples/prompts/skill_with_tools_test.md +0 -6
  253. data/examples/prompts/sre_compliance.md +0 -10
  254. data/examples/prompts/structured_output.md +0 -7
  255. data/examples/prompts/synthesizer.md +0 -17
  256. data/examples/prompts/technical.md +0 -10
  257. data/examples/prompts/template_with_skills_test.md +0 -6
  258. data/examples/prompts/triage.md +0 -22
  259. data/examples/ruboruby.md +0 -423
  260. data/examples/run_all.rb +0 -60
  261. data/examples/xyzzy.rb +0 -97
  262. data/lib/robot_lab/mcp/client.rb +0 -223
  263. data/lib/robot_lab/mcp/connection_poller.rb +0 -195
  264. data/lib/robot_lab/mcp/transports/base.rb +0 -64
  265. data/lib/robot_lab/mcp/transports/sse.rb +0 -120
  266. data/lib/robot_lab/mcp/transports/stdio.rb +0 -170
  267. data/lib/robot_lab/mcp/transports/streamable_http.rb +0 -141
  268. data/lib/robot_lab/mcp/transports/websocket.rb +0 -111
  269. data/logfile +0 -8
  270. data/mkdocs.yml +0 -209
  271. data/robot_concurrency.md +0 -38
  272. data/simple_acp_review.md +0 -298
  273. data/temp.md +0 -6
  274. data/tool_manifest_plan.md +0 -155
data/docs/api/errors.md DELETED
@@ -1,323 +0,0 @@
1
- # Error Reference
2
-
3
- All RobotLab exceptions inherit from `RobotLab::Error`, which inherits from `StandardError`. Rescue `RobotLab::Error` to catch any framework exception in one clause, or rescue specific subclasses for targeted handling.
4
-
5
- ## Hierarchy
6
-
7
- ```
8
- StandardError
9
- └── RobotLab::Error
10
- ├── RobotLab::ConfigurationError
11
- │ └── RobotLab::DependencyError
12
- ├── RobotLab::InferenceError
13
- │ └── RobotLab::ToolLoopError
14
- ├── RobotLab::ToolNotFoundError
15
- ├── RobotLab::MCPError
16
- ├── RobotLab::BusError
17
- ├── RobotLab::RactorBoundaryError
18
- ├── RobotLab::ToolError
19
- ├── RobotLab::BudgetExceeded
20
- └── RobotLab::AwaitTimeout
21
- ```
22
-
23
- `AwaitTimeout` is defined in `lib/robot_lab/memory.rb` and raised by
24
- [`Memory#get`](core/memory.md#get) when a blocking read expires.
25
-
26
- Additionally, `DelegationFuture` defines its own scoped error:
27
-
28
- ```
29
- StandardError
30
- └── RobotLab::Error
31
- └── RobotLab::DelegationFuture::DelegationTimeout
32
- ```
33
-
34
- ---
35
-
36
- ## RobotLab::Error
37
-
38
- Base class for all RobotLab errors. Rescue this to catch any framework exception.
39
-
40
- ```ruby
41
- begin
42
- robot.run("hello")
43
- rescue RobotLab::Error => e
44
- puts "RobotLab error: #{e.message}"
45
- end
46
- ```
47
-
48
- ---
49
-
50
- ## RobotLab::ConfigurationError
51
-
52
- Raised when configuration is invalid or missing required values.
53
-
54
- ```ruby
55
- # Example: missing API key, invalid template path
56
- begin
57
- robot.run("hello")
58
- rescue RobotLab::ConfigurationError => e
59
- puts "Bad config: #{e.message}"
60
- end
61
- ```
62
-
63
- ---
64
-
65
- ## RobotLab::DependencyError < ConfigurationError
66
-
67
- Raised when a required optional gem dependency is not installed. There are three
68
- distinct raise sites in core, each with its own message:
69
-
70
- | Raised by | Missing dependency | Message |
71
- |-----------|--------------------|---------|
72
- | `TextAnalysis.require_classifier!` — reached from `Convergence`, `HistoryCompressor`, `Robot#compress_history`, `Robot#search_history` | `classifier` gem | `The 'classifier' gem is required for text analysis features. Add it to your Gemfile: gem 'classifier', '~> 2.3'` |
73
- | `Memory`'s document-store methods (`store_document`, `search_documents`, `document_keys`, `delete_document`) | `robot_lab-document_store` gem | `document storage requires the robot_lab-document_store gem. Add \`gem 'robot_lab-document_store'\` to your Gemfile.` |
74
- | `Network#run` under `parallel_mode: :ractor` | `robot_lab-ractor` gem | `parallel_mode: :ractor requires the robot_lab-ractor gem. Add \`gem 'robot_lab-ractor'\` to your Gemfile.` |
75
-
76
- ```ruby
77
- begin
78
- robot.compress_history
79
- rescue RobotLab::DependencyError => e
80
- warn e.message
81
- end
82
- ```
83
-
84
- Two places swallow it rather than propagate: `auto_compact: :context_window`
85
- logs the message at `:warn` and skips compaction, and
86
- `MCP::ServerDiscovery` rescues it and falls back.
87
-
88
- ---
89
-
90
- ## RobotLab::InferenceError
91
-
92
- Raised when LLM inference fails (API errors, timeouts, rate limits).
93
-
94
- ```ruby
95
- begin
96
- robot.run("hello")
97
- rescue RobotLab::InferenceError => e
98
- puts "LLM call failed: #{e.message}"
99
- end
100
- ```
101
-
102
- ---
103
-
104
- ## RobotLab::ToolLoopError < InferenceError
105
-
106
- Raised when a robot's tool call count exceeds `max_tool_rounds:`. The chat history will contain a dangling `tool_use` block with no matching `tool_result`; call `robot.clear_messages` before reusing the robot.
107
-
108
- ```ruby
109
- robot = RobotLab.build(
110
- name: "runner",
111
- system_prompt: "Execute every step.",
112
- local_tools: [StepTool],
113
- max_tool_rounds: 10
114
- )
115
-
116
- begin
117
- robot.run("Run all steps.", tools: :inherit)
118
- rescue RobotLab::ToolLoopError => e
119
- puts e.message
120
- # "Circuit breaker triggered: 11 tool calls exceeded max_tool_rounds (10)"
121
- robot.clear_messages # required before reuse
122
- end
123
- ```
124
-
125
- The message format is:
126
-
127
- ```
128
- Circuit breaker triggered: <N> tool calls exceeded max_tool_rounds (<M>)
129
- ```
130
-
131
- `N` is the call count that tripped the breaker (always `M + 1`); `M` is the configured limit.
132
-
133
- ---
134
-
135
- ## RobotLab::ToolNotFoundError
136
-
137
- Raised when a tool name is referenced but cannot be found in the `ToolManifest`.
138
-
139
- ---
140
-
141
- ## RobotLab::MCPError
142
-
143
- Raised when MCP server communication fails (connection refused, timeout, protocol error).
144
-
145
- ```ruby
146
- begin
147
- robot.run("hello", mcp: :inherit, tools: :inherit)
148
- rescue RobotLab::MCPError => e
149
- puts "MCP failed: #{e.message}"
150
- end
151
- ```
152
-
153
- `MCPError.new(message, retryable: true)` marks a specific instance as safe to retry (see [Retryable Errors](#retryable-errors) below). The connection-lost and timeout errors raised internally by `MCP::ConnectionPoller` are always constructed with `retryable: true`.
154
-
155
- ---
156
-
157
- ## RobotLab::BusError
158
-
159
- Raised when message bus communication fails (no bus configured, channel not found).
160
-
161
- ```ruby
162
- begin
163
- robot.send_message(to: :bob, content: "hi")
164
- rescue RobotLab::BusError => e
165
- puts "Bus error: #{e.message}"
166
- end
167
- ```
168
-
169
- ---
170
-
171
- ## RobotLab::RactorBoundaryError
172
-
173
- Raised when a value cannot be made Ractor-shareable before crossing a Ractor boundary (e.g., a live `IO` object, a `Proc`, or an object with mutable state).
174
-
175
- !!! note "The error class is core; the machinery that raises it is not"
176
- `RobotLab::RactorBoundaryError` is defined in core
177
- (`lib/robot_lab/error.rb`) so hosts can rescue it without loading anything
178
- extra. But `RactorBoundary`, `RactorWorkerPool`, and `RactorMemoryProxy` are
179
- **not defined in core** — they ship in the separate **`robot_lab-ractor`**
180
- gem. Core only *references* `RactorBoundary.freeze_deep` from
181
- `Network#build_robot_spec`, which is reachable only under
182
- `parallel_mode: :ractor`, which itself raises `DependencyError` unless that
183
- gem is loaded.
184
-
185
- ```ruby
186
- require "robot_lab"
187
- require "robot_lab/ractor" # provides RactorBoundary and the worker pool
188
-
189
- begin
190
- RobotLab::RactorBoundary.freeze_deep({ io: StringIO.new })
191
- rescue RobotLab::RactorBoundaryError => e
192
- puts e.message
193
- end
194
- ```
195
-
196
- ---
197
-
198
- ## RobotLab::ToolError
199
-
200
- An opt-in error type for tool failures. Core raises it nowhere itself — you raise
201
- it from your own `execute`, and the `robot_lab-ractor` worker pool raises it when
202
- unwrapping a failure that happened inside a Ractor.
203
-
204
- `ToolError.new(message, retryable: true)` marks a specific instance as retryable.
205
-
206
- When a tool raises inside `Tool#call`, the error is caught and returned to the
207
- LLM as text rather than propagating (unless the class sets
208
- `self.raise_on_error = true`). RobotLab appends `" (retryable)"` whenever
209
- `RobotLab::Errors.retryable?(error)` is true, so the model itself can see that
210
- another attempt is worth trying:
211
-
212
- ```ruby
213
- class Fetch < RobotLab::Tool
214
- description "Fetch a record"
215
- param :id, type: "string", desc: "record id"
216
-
217
- def execute(id:)
218
- raise RobotLab::ToolError.new("upstream unavailable", retryable: true)
219
- end
220
- end
221
-
222
- Fetch.new.call({ "id" => "1" })
223
- # => "Error (fetch): upstream unavailable (retryable)"
224
- ```
225
-
226
- Unlike the generic `StandardError` path, the `ToolError` path writes **nothing**
227
- to the logger. See [Tool#call](core/tool.md#call).
228
-
229
- ---
230
-
231
- ## RobotLab::BudgetExceeded
232
-
233
- Raised when a Robot's configured `token_budget` or `cost_budget` is already exhausted **before** an LLM call is attempted (see [Budgets](../guides/observability.md#budgets-token-cost) and `RobotLab::Budget::Ledger`). This is distinct from the pre-existing `InferenceError` "Token budget exceeded" message, which covers a call that *completed* but pushed cumulative usage over budget — `BudgetExceeded` means the call was refused outright, before any tokens were spent.
234
-
235
- ```ruby
236
- robot = RobotLab.build(name: "capped", system_prompt: "...", cost_budget: 0.50)
237
-
238
- begin
239
- robot.run("Do the expensive thing")
240
- rescue RobotLab::BudgetExceeded => e
241
- puts e.message # "budget exceeded for cost: 0.62 > 0.5"
242
- end
243
- ```
244
-
245
- Raised by `Budget::Ledger#reserve!`; the message format is
246
- `"budget exceeded for <dimension>: <committed + amount> > <limit>"` where
247
- `<dimension>` is `tokens` or `cost`.
248
-
249
- The post-call `InferenceError` messages are formatted differently:
250
-
251
- | Dimension | Message |
252
- |-----------|---------|
253
- | `token_budget` | `Token budget exceeded: <N> tokens used, budget is <M>` |
254
- | `cost_budget` | `Cost budget exceeded: $0.523100 used, budget is $0.500000` (both values via `%.6f`) |
255
-
256
- ---
257
-
258
- ## RobotLab::AwaitTimeout
259
-
260
- Raised by [`Memory#get`](core/memory.md#get) when a blocking read
261
- (`wait: true` or `wait: <seconds>`) expires before the key is written.
262
-
263
- ```ruby
264
- begin
265
- memory.get(:sentiment, wait: 30)
266
- rescue RobotLab::AwaitTimeout => e
267
- puts e.message # "Timeout waiting for :sentiment after 30 seconds"
268
- end
269
- ```
270
-
271
- With multiple keys the timeout is applied **per missing key**, so
272
- `get(:a, :b, wait: 30)` can block for up to 60 seconds before raising.
273
-
274
- Not retryable per `RobotLab::Errors.retryable?` — it falls into the
275
- "everything else" bucket.
276
-
277
- ---
278
-
279
- ## Retryable Errors
280
-
281
- `RobotLab::Errors.retryable?(error)` classifies whether a host (an ActiveJob `retry_on` list, `robot_lab-to`'s takeover loop, a custom retry wrapper) should retry the operation that raised `error`:
282
-
283
- | Error | Retryable? |
284
- |-------|------------|
285
- | `InferenceError` (and subclasses, except `ToolLoopError`) | Always |
286
- | `ToolLoopError` | Never — it's a circuit breaker; retrying immediately re-triggers the same loop |
287
- | `MCPError` / `ToolError` | Only when raised with `retryable: true` at the raise site |
288
- | Everything else (`ConfigurationError`, `ToolNotFoundError`, `DependencyError`, `RactorBoundaryError`, `BusError`, `BudgetExceeded`, `AwaitTimeout`, `DelegationTimeout`, non-RobotLab errors) | Never |
289
-
290
- ```ruby
291
- begin
292
- robot.run(task)
293
- rescue RobotLab::Error => e
294
- retry if RobotLab::Errors.retryable?(e)
295
- raise
296
- end
297
- ```
298
-
299
- `RobotLab::Errors.retryable_classes` returns `[RobotLab::InferenceError]` — an always-retryable allow-list for explicit ActiveJob-style `retry_on` declarations. It excludes `MCPError`/`ToolError` because their retryability is per-raise (via `retryable:`), not per-class.
300
-
301
- ---
302
-
303
- ## RobotLab::DelegationFuture::DelegationTimeout
304
-
305
- Raised by `DelegationFuture#value(timeout: N)` when the delegated task does not complete within `N` seconds.
306
-
307
- ```ruby
308
- future = manager.delegate(to: analyst, task: "...", async: true)
309
-
310
- begin
311
- result = future.value(timeout: 10)
312
- rescue RobotLab::DelegationFuture::DelegationTimeout => e
313
- puts e.message # "Delegation to 'analyst' timed out after 10s"
314
- end
315
- ```
316
-
317
- ---
318
-
319
- ## Related
320
-
321
- - [Building Robots](../guides/building-robots.md) — Tool loop circuit breaker, delegation
322
- - [Observability & Safety](../guides/observability.md) — circuit breaker and tool loop errors
323
- - [MCP Integration](../guides/mcp-integration.md) — MCP connection errors