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
data/docs/api/hooks.md DELETED
@@ -1,469 +0,0 @@
1
- # Hooks API
2
-
3
- Class-level reference for the hook system. For the conceptual walkthrough —
4
- families, firing order, registration levels, and worked examples — see the
5
- [Hook System guide](../guides/hooks.md). This page documents the public methods
6
- of the classes that implement it.
7
-
8
- ```mermaid
9
- classDiagram
10
- class Hook {
11
- <<abstract>>
12
- +namespace() Symbol
13
- +call(hook_name, ctx, block) Object
14
- }
15
-
16
- class HookRegistry {
17
- +on(handler_class, context) Registration
18
- +registrations_for(hook_name) Array
19
- +registrations() Array
20
- +clear() Array
21
- }
22
-
23
- class Registration {
24
- <<Data>>
25
- +handler_class Class
26
- +context Hash
27
- +namespace() Symbol
28
- }
29
-
30
- class Hooks {
31
- <<module>>
32
- +run(family, ctx, registries, per_run_hooks) Object
33
- +call(hook_name, ctx, registries, per_run_hooks) void
34
- +around(hook_name, ctx, registries, per_run_hooks) Object
35
- }
36
-
37
- class HookContext {
38
- +event Symbol
39
- +metadata ExtensionState
40
- +ext(name) DotState
41
- +local() DotState
42
- +with_namespace(ns) Object
43
- +to_h() Hash
44
- }
45
-
46
- HookContext <|-- RunHookContext
47
- RunHookContext <|-- LlmGenerationHookContext
48
- HookContext <|-- ToolCallHookContext
49
- HookContext <|-- NetworkRunHookContext
50
- HookContext <|-- TaskHookContext
51
- HookContext <|-- LearnHookContext
52
- HookContext <|-- CompactionHookContext
53
-
54
- HookRegistry --> Registration : builds
55
- Hooks --> HookRegistry : reads
56
- Hooks --> HookContext : namespaces
57
- Hook <|-- Narrator
58
- ```
59
-
60
- ---
61
-
62
- ## RobotLab::Hook
63
-
64
- Base class for hook handlers. Subclasses implement hook methods as **class**
65
- methods; any method a subclass does not define is silently skipped when that hook
66
- fires.
67
-
68
- ### namespace / namespace=
69
-
70
- ```ruby
71
- class TimerHook < RobotLab::Hook; end
72
- TimerHook.namespace # => :timer_hook
73
-
74
- class Tracer < RobotLab::Hook
75
- self.namespace = :trace
76
- end
77
- Tracer.namespace # => :trace
78
-
79
- RobotLab::Hook.namespace # => nil (the base class has none)
80
- ```
81
-
82
- The namespace isolates a handler's `ctx.local` scratchpad from every other
83
- handler. It defaults to the snake_case form of the **last** segment of the class
84
- name, so `MyExt::Tracer` becomes `:tracer`. `HookRegistry#on` raises
85
- `ArgumentError` when `namespace` is `nil`, which is why the base `Hook` class
86
- itself can never be registered.
87
-
88
- `inherited` resets `@namespace` to `nil` on each subclass, so a namespace set on
89
- a parent handler is **not** inherited by its subclasses — each re-derives its own.
90
-
91
- ### call
92
-
93
- ```ruby
94
- HandlerClass.call(hook_name, context) # point / before / after hook
95
- HandlerClass.call(hook_name, context) { ... } # around hook
96
- ```
97
-
98
- Dispatch one hook to this handler. This is the method `Hooks.call_registration`
99
- invokes; you rarely call it directly.
100
-
101
- | Case | Behavior |
102
- |------|----------|
103
- | Handler defines `hook_name` | Called with `context` (and the block, for around hooks) |
104
- | Handler does not define it, block given | The block is called directly — **around passthrough**, so the chain never breaks |
105
- | Handler does not define it, no block | Silent no-op |
106
-
107
- The check is `singleton_class.public_method_defined?(hook_name)`, so a hook
108
- defined as a *private* class method never fires.
109
-
110
- ---
111
-
112
- ## RobotLab::HookRegistry
113
-
114
- The store behind `RobotLab.hooks`, `network.hooks`, and `robot.hooks`. Each of
115
- those three is a separate instance; a run consults all three.
116
-
117
- ### on
118
-
119
- ```ruby
120
- registration = registry.on(HandlerClass, context: nil)
121
- # => RobotLab::HookRegistry::Registration
122
- ```
123
-
124
- Register a handler class.
125
-
126
- | Name | Type | Default | Description |
127
- |------|------|---------|-------------|
128
- | `handler_class` | `Class` | **required** | Must be a subclass of `RobotLab::Hook` |
129
- | `context` | `Hash`, `nil` | `nil` | Defaults merged into the handler's `ctx.local` before each callback (via `DotState#merge_defaults`, so an already-set key is not overwritten) |
130
-
131
- **Raises `ArgumentError`** when `handler_class` is not a `RobotLab::Hook`
132
- subclass, or when its `namespace` is `nil`.
133
-
134
- `RobotLab.on`, `network.on`, and `robot.on` are thin delegators to this method.
135
-
136
- ### registrations_for
137
-
138
- ```ruby
139
- registry.registrations_for(:before_run) # => Array<Registration>
140
- ```
141
-
142
- Only the registrations whose handler class actually implements `hook_name`. This
143
- is the filter that makes an unimplemented hook a no-op rather than an error, and
144
- it is what `Hooks.registrations` calls on each registry.
145
-
146
- ### registrations
147
-
148
- ```ruby
149
- registry.registrations # => Array<Registration>
150
- ```
151
-
152
- Every registration, as a defensive copy (`@registrations.dup`) — mutating the
153
- returned array does not affect the registry.
154
-
155
- Used by `Network#ractor_hook_classes_for` to collect the handler classes that
156
- must cross a Ractor boundary under `parallel_mode: :ractor`.
157
-
158
- ### clear
159
-
160
- ```ruby
161
- registry.clear # => the emptied internal array
162
- ```
163
-
164
- Remove every registration **in place**. Note the difference from
165
- `RobotLab.clear_hooks!`, which replaces the global registry object entirely
166
- rather than emptying it.
167
-
168
- ### HookRegistry::Registration
169
-
170
- A `Data` value object pairing a handler with its optional context.
171
-
172
- | Member / method | Type | Description |
173
- |-----------------|------|-------------|
174
- | `handler_class` | `Class` | The `RobotLab::Hook` subclass |
175
- | `context` | `Hash`, `nil` | Per-registration defaults (defaults to `nil`) |
176
- | `namespace` | `Symbol` | Delegates to `handler_class.namespace` |
177
-
178
- ---
179
-
180
- ## RobotLab::Hooks
181
-
182
- The dispatcher (`module_function`, so every method is called as
183
- `RobotLab::Hooks.foo`). Core calls into it; extension authors normally write
184
- handler classes instead. It is documented here because a host that drives
185
- RobotLab objects directly — or an extension that adds its own hook family — needs
186
- the contract.
187
-
188
- ### run
189
-
190
- ```ruby
191
- RobotLab::Hooks.run(family, context, registries:, per_run_hooks: nil) { core_work }
192
- # => the block's return value
193
- ```
194
-
195
- Execute a full hook family around a block. In order: every `before_<family>`,
196
- then the `around_<family>` chain wrapping the block, then
197
- [`set_result`](#set_result), then every `after_<family>`.
198
-
199
- | Name | Type | Description |
200
- |------|------|-------------|
201
- | `family` | `Symbol` | `:run`, `:llm_generation`, `:tool_call`, `:network_run`, `:task`, `:compaction`, `:learn` |
202
- | `context` | `HookContext` | The family's context object |
203
- | `registries` | `Array<HookRegistry, nil>` | Consulted in order; `nil` entries are compacted away |
204
- | `per_run_hooks` | `Class`, `Array<Class>`, `nil` | Handler classes active only for this call (`robot.run(..., hooks:)`) |
205
-
206
- **Error path:** `run` rescues `Exception` (not just `StandardError`, so
207
- `Timeout::Error` and `SignalException` are covered), assigns it to
208
- `context.error` when the context has an `error=` writer, fires `on_error`, and
209
- **re-raises**. Hooks never swallow an exception.
210
-
211
- ### call
212
-
213
- ```ruby
214
- RobotLab::Hooks.call(hook_name, context, registries:, per_run_hooks: nil)
215
- ```
216
-
217
- Fire one non-around hook across all matching registrations. This is how the point
218
- hooks `:on_compaction` and `:on_learn` are dispatched from inside the core block
219
- of their family — which is why they do not compose with `around_*` handlers and
220
- have no chainable result.
221
-
222
- ### around
223
-
224
- ```ruby
225
- RobotLab::Hooks.around(hook_name, context, registries:, per_run_hooks: nil) { ... }
226
- ```
227
-
228
- Build and invoke just the around chain for one hook name, without the
229
- before/after phases.
230
-
231
- ### registrations
232
-
233
- ```ruby
234
- RobotLab::Hooks.registrations(hook_name, registries, per_run_hooks)
235
- # => Array<Registration>
236
- ```
237
-
238
- The complete ordered list for one hook name: each registry's
239
- `registrations_for(hook_name)` concatenated in registry order, followed by the
240
- per-run entries. This ordering is what produces **global → network → robot →
241
- per-run** execution.
242
-
243
- ### error_registrations
244
-
245
- ```ruby
246
- RobotLab::Hooks.error_registrations(family, registries, per_run_hooks)
247
- # => Array<Registration>
248
- ```
249
-
250
- `on_error` registrations, but **only** for the `:run`, `:network_run`, and
251
- `:task` families — every other family returns `[]`. This is the mechanism behind
252
- the guide's statement that `:llm_generation`, `:tool_call`, `:compaction`, and
253
- `:learn` have no `on_error` variant.
254
-
255
- ### call_all
256
-
257
- ```ruby
258
- RobotLab::Hooks.call_all(registrations, hook_name, context)
259
- ```
260
-
261
- Invoke each registration in order for a non-around hook.
262
-
263
- ### call_around
264
-
265
- ```ruby
266
- RobotLab::Hooks.call_around(registrations, hook_name, context) { core_work }
267
- ```
268
-
269
- Fold the registrations into a nested chain and call it. The list is `reverse`d
270
- before folding, so the **first** registration ends up outermost — a global
271
- `around_run` wraps a robot-level one, not the other way round. A handler that
272
- does not implement the hook passes the block straight through.
273
-
274
- ### call_registration
275
-
276
- ```ruby
277
- RobotLab::Hooks.call_registration(registration, hook_name, context, &block)
278
- ```
279
-
280
- Invoke one registration with its namespace active. It wraps the call in
281
- `context.with_namespace(registration.namespace)` and, when the registration
282
- carries a `context:` hash, merges those values into
283
- `context.ext(namespace)` as defaults first. This is what makes `ctx.local`
284
- resolve to the *calling handler's* private `DotState`.
285
-
286
- ### per_run_entries
287
-
288
- ```ruby
289
- RobotLab::Hooks.per_run_entries(hook_name, hooks)
290
- # => Array<Registration>
291
- ```
292
-
293
- Turn `robot.run(msg, hooks: HandlerClass)` or `hooks: [A, B]` into
294
- `Registration`s, skipping any class that does not implement `hook_name`. Per-run
295
- registrations carry no `context:`.
296
-
297
- ### set_result
298
-
299
- ```ruby
300
- RobotLab::Hooks.set_result(context, family, result)
301
- ```
302
-
303
- Publish a family's return value onto its context so `after_*` handlers can read
304
- it. The mapping is fixed:
305
-
306
- | Family | Assigned to |
307
- |--------|-------------|
308
- | `:run` | `context.response` |
309
- | `:network_run`, `:task` | `context.result` |
310
- | `:llm_generation` | `context.generation_response` |
311
- | `:tool_call`, `:compaction`, `:learn` | *(nothing — those contexts carry their result in a family-specific accessor set by the core block)* |
312
-
313
- Each assignment is guarded by `respond_to?`, so a custom context lacking the
314
- writer is simply skipped.
315
-
316
- ---
317
-
318
- ## RobotLab::HookContext
319
-
320
- Base class for every hook context. The family-specific subclasses below add the
321
- accessors a handler actually reads.
322
-
323
- | Method | Returns | Description |
324
- |--------|---------|-------------|
325
- | `event` | `Symbol` | The family (`:run`, `:tool_call`, …), symbolized at construction |
326
- | `metadata` | `ExtensionState` | The per-run namespace store; defaults to a fresh `ExtensionState` |
327
- | `ext(name)` | `DotState` | Another handler's namespaced state — `ctx.ext(:timer).start_time` |
328
- | `local` | `DotState` | **This** handler's state. Raises `ArgumentError: No hook namespace active` outside a `with_namespace` block |
329
- | `with_namespace(ns) { \|ctx\| }` | block's value | Sets the active namespace for the duration of the block and restores the previous one in an `ensure`. Called by `Hooks.call_registration` |
330
- | `to_h` | `Hash` | Snapshot of every public reader (excluding `to_h` and `local`) plus `metadata: metadata.to_h` |
331
-
332
- !!! warning "`ctx.local` lives for exactly one run"
333
- `metadata` is a fresh `ExtensionState` per `HookContext`, and a new context is
334
- built per run. Use a class-level accessor on the handler for cross-run state.
335
-
336
- ### Context subclasses
337
-
338
- Readers are read-only unless marked **rw**.
339
-
340
- #### RunHookContext (`event: :run`)
341
-
342
- | Accessor | | Description |
343
- |----------|--|-------------|
344
- | `robot` | | The robot being run |
345
- | `network` | | Owning `Network`, or `nil` when standalone |
346
- | `task` | | The `Task` wrapper, when run from a pipeline |
347
- | `memory` | | The resolved run memory |
348
- | `config` | | The robot's effective `RunConfig` |
349
- | `request` | rw | The user message. **Writable** — assign in `before_run` to rewrite the prompt |
350
- | `response` | rw | The `RobotResult`; set by `Hooks.set_result` before `after_run` |
351
- | `error` | rw | Set by `Hooks.run` before `on_error` |
352
-
353
- #### LlmGenerationHookContext (`event: :run`) — subclass of `RunHookContext`
354
-
355
- Adds `iteration` (Integer, defaults to `0`) and `generation_response` (**rw**,
356
- set by `set_result`). Note it inherits `event: :run` from its parent; the family
357
- name comes from the hook method names, not from `event`.
358
-
359
- #### ToolCallHookContext (`event: :tool_call`)
360
-
361
- | Accessor | | Description |
362
- |----------|--|-------------|
363
- | `tool` | | The tool instance |
364
- | `tool_name` | | `tool.name`, falling back to `tool.class.name` |
365
- | `tool_args` | | Arguments the LLM supplied |
366
- | `robot` | | Owning robot, or `nil` |
367
- | `tool_result` | rw | The result. Assign it in `around_tool_call` **without** calling the block to block a tool |
368
- | `tool_error` | rw | Set by `Tool#call` when `execute` raised |
369
-
370
- #### NetworkRunHookContext (`event: :network_run`)
371
-
372
- `network`, `memory`, `config`; **rw**: `context` (the run params hash), `result`, `error`.
373
-
374
- #### TaskHookContext (`event: :task`)
375
-
376
- `network`, `task`, `task_name` (`task.name`), `robot` (falls back to
377
- `task.robot`), `memory`, `config`; **rw**: `result`, `error`.
378
-
379
- #### LearnHookContext (`event: :learn`)
380
-
381
- | Accessor | | Description |
382
- |----------|--|-------------|
383
- | `robot` | | The robot learning |
384
- | `text` | | The stripped learning text |
385
- | `learnings_before` | | Frozen copy of `robot.learnings` prior to the write |
386
- | `stored` | rw | Set `true` by core when the learning was actually appended (i.e. not deduplicated away) |
387
- | `error` | rw | |
388
-
389
- #### CompactionHookContext (`event: :compaction`)
390
-
391
- | Accessor | | Description |
392
- |----------|--|-------------|
393
- | `robot` | | |
394
- | `messages_before` | | Frozen copy of `chat.messages` before compaction |
395
- | `config` | | The effective `RunConfig` |
396
- | `strategy` | | `:context_window`, or `:custom` when `auto_compact` is a `Proc` |
397
- | `compacted_messages` | rw | Assign in `on_compaction` to **replace** the core algorithm |
398
- | `error` | rw | |
399
- | `handled?` | | `!compacted_messages.nil?` — core skips its own compaction when true |
400
-
401
- ---
402
-
403
- ## ExtensionState and DotState
404
-
405
- The two-level store behind `ctx.local` / `ctx.ext`.
406
-
407
- ### ExtensionState
408
-
409
- | Method | Returns | Description |
410
- |--------|---------|-------------|
411
- | `ext(name)` | `DotState` | The `DotState` for a namespace, auto-created on first access |
412
- | `to_h` | `Hash` | `{ namespace => state_hash }` for every namespace touched |
413
-
414
- ### DotState
415
-
416
- A schemaless dot-access bag.
417
-
418
- | Method | Returns | Description |
419
- |--------|---------|-------------|
420
- | `method_missing` | value / assigned value | `state.foo` reads, `state.foo = 1` writes. Any key is allowed |
421
- | `merge_defaults(hash)` | `self` | Writes each pair **only when the key is absent** — this is how a registration's `context:` becomes defaults rather than an override |
422
- | `to_h` | `Hash` | A `dup` of the backing hash |
423
-
424
- !!! warning "`DotState#respond_to_missing?` always returns true"
425
- `state.respond_to?(:anything)` is `true`, and reading a key that was never
426
- set returns `nil` instead of raising `NoMethodError`. A typo in a `ctx.local`
427
- reader fails silently.
428
-
429
- ---
430
-
431
- ## Module-level hook methods
432
-
433
- ```ruby
434
- RobotLab.hooks # => the global HookRegistry (memoized)
435
- RobotLab.on(HandlerClass, context: nil)
436
- RobotLab.clear_hooks! # => replaces the global registry with a new one
437
- ```
438
-
439
- `clear_hooks!` swaps in a brand-new `HookRegistry`; any `Registration` object you
440
- held from before is orphaned. Use it in test teardown to avoid leaking handlers
441
- between examples.
442
-
443
- ### with_hook_scope / current_hook_scope
444
-
445
- ```ruby
446
- RobotLab.with_hook_scope(registries, per_run_hooks) { ... }
447
- RobotLab.current_hook_scope # => { registries: [...], per_run_hooks: ... } or nil
448
- ```
449
-
450
- Publishes the active run's registries and per-run handlers in a
451
- `Thread.current` slot for the duration of the block, restoring the previous value
452
- in an `ensure`. `Robot::Hooking#run` opens the scope; `Tool#call` reads it so a
453
- tool invoked deep inside RubyLLM's tool loop still resolves the same registries
454
- (including the network's and any `hooks:` passed to that one `run`) instead of
455
- falling back to `[RobotLab.hooks, robot.hooks]`.
456
-
457
- !!! note "Thread-local, so it does not cross a thread boundary"
458
- A tool that executes on another thread — or a `delegate(async: true)` target —
459
- sees `current_hook_scope == nil` and falls back to the global + robot
460
- registries. Network-scoped and per-run hooks will not fire for it.
461
-
462
- ---
463
-
464
- ## See Also
465
-
466
- - [Hook System guide](../guides/hooks.md) — families, ordering, and applied patterns
467
- - [Observability & Safety](../guides/observability.md) — `Narrator`, budgets, doom-loop detection
468
- - [Support API](support.md) — `Narrator`, the one `Hook` subclass shipped in core
469
- - [Robot: on](core/robot.md#on) · [Network: on](core/network.md#on)
data/docs/api/index.md DELETED
@@ -1,137 +0,0 @@
1
- # API Reference
2
-
3
- Complete API documentation for RobotLab.
4
-
5
- ## Core Classes
6
-
7
- The fundamental building blocks of RobotLab:
8
-
9
- | Class | Description |
10
- |-------|-------------|
11
- | [Robot](core/robot.md) | LLM-powered agent with templates, tools, memory, and MCP |
12
- | [RobotResult](core/result.md) | Value object returned by every `robot.run()` |
13
- | [Network](core/network.md) | Orchestrates multiple robots as a SimpleFlow pipeline |
14
- | [Memory](core/memory.md) | Reactive key-value store for sharing data |
15
- | [StateProxy](core/state.md) | Hash/method-access wrapper returned by `memory.data` |
16
- | [Tool](core/tool.md) | Custom function robots can call |
17
- | `RunConfig` | Shared LLM / tool / infrastructure configuration — see [Robot: RunConfig](core/robot.md#runconfig) |
18
-
19
- There is **no** `RobotLab::State` class and no `RobotLab::NetworkRun` class. Runtime
20
- state lives in `Memory`; `memory.data` returns a `StateProxy`.
21
-
22
- ## Hooks
23
-
24
- The framework's extension seam — `Hooks.run` brackets every robot run, network
25
- run, task, LLM generation, tool call, compaction, and `learn` call:
26
-
27
- | Class | Description |
28
- |-------|-------------|
29
- | [Hook](hooks.md#robotlabhook) | Handler base class; subclasses implement hooks as class methods |
30
- | [HookRegistry](hooks.md#robotlabhookregistry) | The store behind `RobotLab.hooks`, `network.hooks`, `robot.hooks` |
31
- | [Hooks](hooks.md#robotlabhooks) | The dispatcher |
32
- | [HookContext](hooks.md#robotlabhookcontext) | Base context, plus one subclass per family |
33
-
34
- ## Skills
35
-
36
- `SKILL.md` bundles, the scripts they expose as tools, and the sandbox that
37
- confines them:
38
-
39
- | Class | Description |
40
- |-------|-------------|
41
- | [AgentSkill](skills.md#robotlabagentskill) | One skill bundle: instructions + `scripts/` |
42
- | [AgentSkillCatalog](skills.md#robotlabagentskillcatalog) | Lazy registry over `~/.prompts/skills/` |
43
- | [Capabilities](skills.md#robotlabcapabilities) | Declared vs. ceiling filesystem / network / timeout grant |
44
- | [ScriptTool](skills.md#robotlabscripttool) | Wraps an executable script as a `Tool`; `ScriptTool.executor` is the confinement extension point |
45
- | [Sandbox](skills.md#confinement-robot_lab-sandbox) | macOS Seatbelt confinement, or a passthrough — ships in the optional `robot_lab-sandbox` gem |
46
-
47
- ## Support Classes
48
-
49
- Everything else with a public surface — `Task`, `Runnable`, `ToolConfig`,
50
- `ToolManifest`, `Budget::Ledger`, `DoomLoopDetector`, `HistoryCompressor`,
51
- `Convergence`, `TextAnalysis`, `DelegationFuture`, `RobotMessage`, `BusPoller`,
52
- `Waiter`, `Narrator`, `Config`, `MCP::ServerDiscovery`,
53
- `MCP::ConnectionPoller`, and `Streaming::SequenceCounter` — is documented on the
54
- [Support Classes](support.md) page.
55
-
56
- ## Messages
57
-
58
- Message types for LLM communication:
59
-
60
- | Class | Description |
61
- |-------|-------------|
62
- | [UserMessage](messages/user-message.md) | User input with metadata |
63
- | [TextMessage](messages/text-message.md) | Text message with role |
64
- | [ToolCallMessage](messages/tool-call-message.md) | Tool execution request |
65
- | [ToolResultMessage](messages/tool-result-message.md) | Tool execution result |
66
-
67
- ## MCP (Model Context Protocol)
68
-
69
- Connect to external tool servers:
70
-
71
- | Class | Description |
72
- |-------|-------------|
73
- | [Client](mcp/client.md) | MCP server connection |
74
- | [Server](mcp/server.md) | Server configuration |
75
- | [Transports](mcp/transports.md) | Connection transports |
76
-
77
- ## Streaming
78
-
79
- Real-time response streaming:
80
-
81
- | Class | Description |
82
- |-------|-------------|
83
- | [Context](streaming/context.md) | Streaming context |
84
- | [Events](streaming/events.md) | Event utilities |
85
-
86
- ## Module Methods
87
-
88
- ### RobotLab
89
-
90
- ```ruby
91
- # Configuration
92
- RobotLab.config # => Config instance
93
- RobotLab.configure { |c| ... } # => yields the Config for mutation
94
- RobotLab.reload_config! # => reload from all sources
95
-
96
- # Building
97
- RobotLab.build(name: "robot", template: nil, system_prompt: nil, context: {},
98
- enable_cache: true, bus: nil, skills: nil, config: nil, **options)
99
- RobotLab.create_network(name:, concurrency: :auto, config: nil) { ... }
100
- RobotLab.create_memory(data: {}, enable_cache: true, **options)
101
-
102
- # Rendering a template to a String (not a robot) -- see Building Robots guide
103
- RobotLab.render_template(name, **context) # => String
104
-
105
- # Hooks -- see the Hooks API page
106
- RobotLab.hooks # => HookRegistry
107
- RobotLab.on(HandlerClass, context: nil)
108
- RobotLab.clear_hooks! # => replaces the global registry with a fresh one
109
-
110
- # Hook scope (internal plumbing; read by Tool#call)
111
- RobotLab.with_hook_scope(registries, per_run_hooks) { ... }
112
- RobotLab.current_hook_scope # => { registries:, per_run_hooks: } or nil
113
-
114
- # Extensions
115
- RobotLab.register_extension(name, mod)
116
- RobotLab.extension_loaded?(:ractor) # => Boolean
117
- RobotLab.extension(:ractor)
118
- RobotLab.loaded_extensions # => Array<Symbol>
119
- ```
120
-
121
- `with_hook_scope` publishes the active run's registries in a `Thread.current`
122
- slot so a tool executing deep inside RubyLLM's tool loop resolves the same
123
- registries — including the network's and any per-run `hooks:` — instead of
124
- falling back to `[RobotLab.hooks, robot.hooks]`. It is thread-local, so it does
125
- not reach a tool that runs on another thread. See
126
- [Hooks: with_hook_scope](hooks.md#with_hook_scope-current_hook_scope).
127
-
128
- !!! warning "Tools and MCP are opt-in per call"
129
- `Robot#run` defaults to `tools: :none, mcp: :none`. A bare `robot.run("...")`
130
- sends the LLM **zero** tools and connects **no** MCP servers, even when
131
- `local_tools:`/`mcp:` were supplied at build time. Pass `tools: :inherit`
132
- (and `mcp: :inherit`) at *run* time to use what is attached. For a standalone
133
- robot, do not pass `tools: :inherit` at *build* time — it resolves to an
134
- allowlist matching nothing. (Inside a network it is the required opt-in to a
135
- network `config:` list.) See [Robot: Configuration Hierarchy](core/robot.md#configuration-hierarchy).
136
-
137
- See individual class documentation for detailed method references.