robot_lab 0.2.1 → 0.2.7

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 (236) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +1 -0
  3. data/.loki +60 -0
  4. data/.quality/reek_baseline.txt +43 -0
  5. data/.rubocop.yml +5 -167
  6. data/CHANGELOG.md +54 -0
  7. data/README.md +185 -64
  8. data/Rakefile +28 -12
  9. data/docs/api/core/index.md +41 -14
  10. data/docs/api/core/memory.md +247 -29
  11. data/docs/api/core/network.md +285 -33
  12. data/docs/api/core/result.md +120 -32
  13. data/docs/api/core/robot.md +636 -60
  14. data/docs/api/core/state.md +87 -197
  15. data/docs/api/core/tool.md +165 -20
  16. data/docs/api/errors.md +152 -14
  17. data/docs/api/hooks.md +469 -0
  18. data/docs/api/index.md +83 -7
  19. data/docs/api/mcp/client.md +129 -35
  20. data/docs/api/mcp/index.md +164 -23
  21. data/docs/api/mcp/server.md +27 -3
  22. data/docs/api/mcp/transports.md +94 -22
  23. data/docs/api/messages/index.md +26 -3
  24. data/docs/api/messages/text-message.md +33 -11
  25. data/docs/api/messages/tool-call-message.md +27 -4
  26. data/docs/api/messages/tool-result-message.md +23 -4
  27. data/docs/api/messages/user-message.md +45 -8
  28. data/docs/api/skills.md +519 -0
  29. data/docs/api/streaming/context.md +28 -5
  30. data/docs/api/streaming/index.md +57 -11
  31. data/docs/api/support.md +846 -0
  32. data/docs/architecture/core-concepts.md +118 -30
  33. data/docs/architecture/index.md +86 -11
  34. data/docs/architecture/message-flow.md +66 -29
  35. data/docs/architecture/network-orchestration.md +153 -38
  36. data/docs/architecture/robot-execution.md +173 -91
  37. data/docs/architecture/state-management.md +31 -12
  38. data/docs/concepts.md +176 -21
  39. data/docs/examples/basic-chat.md +72 -19
  40. data/docs/examples/index.md +117 -31
  41. data/docs/examples/mcp-server.md +154 -45
  42. data/docs/examples/multi-robot-network.md +91 -21
  43. data/docs/examples/tool-usage.md +104 -37
  44. data/docs/getting-started/configuration.md +299 -93
  45. data/docs/getting-started/installation.md +53 -41
  46. data/docs/getting-started/quick-start.md +51 -6
  47. data/docs/guides/building-robots.md +296 -50
  48. data/docs/guides/creating-networks.md +220 -31
  49. data/docs/guides/hooks.md +1084 -0
  50. data/docs/guides/index.md +5 -0
  51. data/docs/guides/knowledge.md +37 -6
  52. data/docs/guides/mcp-integration.md +211 -44
  53. data/docs/guides/memory.md +103 -12
  54. data/docs/guides/observability.md +166 -51
  55. data/docs/guides/streaming.md +184 -125
  56. data/docs/guides/using-tools.md +300 -11
  57. data/docs/index.md +37 -5
  58. data/examples/01_simple_robot.rb +2 -2
  59. data/examples/02_tools.rb +14 -4
  60. data/examples/03_network.rb +23 -9
  61. data/examples/04_mcp.rb +11 -4
  62. data/examples/05_streaming.rb +8 -5
  63. data/examples/06_prompt_templates.rb +13 -9
  64. data/examples/07_network_memory.rb +5 -5
  65. data/examples/08_llm_config.rb +20 -15
  66. data/examples/09_chaining.rb +4 -4
  67. data/examples/11_network_introspection.rb +4 -4
  68. data/examples/12_message_bus.rb +2 -2
  69. data/examples/13_spawn.rb +2 -2
  70. data/examples/14_rusty_circuit/README.md +1 -0
  71. data/examples/14_rusty_circuit/comic.rb +7 -3
  72. data/examples/14_rusty_circuit/display.rb +14 -0
  73. data/examples/14_rusty_circuit/heckler.rb +8 -6
  74. data/examples/14_rusty_circuit/open_mic.rb +17 -6
  75. data/examples/14_rusty_circuit/scout.rb +17 -10
  76. data/examples/15_memory_network_and_bus/editorial_pipeline.rb +14 -10
  77. data/examples/15_memory_network_and_bus/linux_writer.rb +2 -2
  78. data/examples/15_memory_network_and_bus/os_editor.rb +3 -1
  79. data/examples/15_memory_network_and_bus/os_writer.rb +4 -1
  80. data/examples/16_writers_room/writer.rb +22 -22
  81. data/examples/16_writers_room/writers_room.rb +2 -0
  82. data/examples/17_skills.rb +14 -13
  83. data/examples/18_rails/README.md +20 -1
  84. data/examples/18_rails/app/controllers/chat_controller.rb +5 -1
  85. data/examples/18_rails/app/jobs/robot_run_job.rb +11 -5
  86. data/examples/18_rails/app/robots/chat_robot.rb +11 -0
  87. data/examples/18_rails/config/initializers/robot_lab.rb +8 -0
  88. data/examples/19_token_tracking.rb +25 -9
  89. data/examples/20_circuit_breaker.rb +10 -7
  90. data/examples/21_learning_loop.rb +42 -16
  91. data/examples/22_context_compression.rb +23 -23
  92. data/examples/23_convergence.rb +24 -17
  93. data/examples/24_structured_delegation.rb +13 -8
  94. data/examples/25_history_search.rb +12 -8
  95. data/examples/27_incident_response/incident_response.rb +31 -13
  96. data/examples/28_mcp_discovery.rb +17 -13
  97. data/examples/29_ractor_tools.rb +4 -2
  98. data/examples/30_ractor_network.rb +22 -17
  99. data/examples/31_launch_assessment.rb +20 -9
  100. data/examples/32_newsletter_reader.rb +7 -2
  101. data/examples/33_stock_predictor.rb +34 -13
  102. data/examples/34_agentskills.rb +7 -3
  103. data/examples/35_hooks.rb +266 -0
  104. data/examples/README.md +203 -42
  105. data/examples/common.rb +79 -7
  106. data/examples/xyzzy.rb +97 -0
  107. data/lib/robot_lab/agent_skill.rb +5 -4
  108. data/lib/robot_lab/budget/ledger.rb +98 -0
  109. data/lib/robot_lab/capabilities.rb +84 -0
  110. data/lib/robot_lab/config/defaults.yml +10 -0
  111. data/lib/robot_lab/config.rb +14 -9
  112. data/lib/robot_lab/error.rb +34 -4
  113. data/lib/robot_lab/errors.rb +45 -0
  114. data/lib/robot_lab/hook.rb +79 -0
  115. data/lib/robot_lab/hook_context.rb +194 -0
  116. data/lib/robot_lab/hook_registry.rb +55 -0
  117. data/lib/robot_lab/hooks.rb +87 -0
  118. data/lib/robot_lab/mcp/connection_poller.rb +2 -2
  119. data/lib/robot_lab/names.rb +402 -0
  120. data/lib/robot_lab/narrator.rb +87 -0
  121. data/lib/robot_lab/network.rb +77 -20
  122. data/lib/robot_lab/robot/agent_skill_matching.rb +1 -3
  123. data/lib/robot_lab/robot/budget.rb +89 -0
  124. data/lib/robot_lab/robot/bus_messaging.rb +90 -18
  125. data/lib/robot_lab/robot/hooking.rb +56 -0
  126. data/lib/robot_lab/robot/mcp_management.rb +8 -2
  127. data/lib/robot_lab/robot/template_rendering.rb +18 -5
  128. data/lib/robot_lab/robot.rb +233 -89
  129. data/lib/robot_lab/run_config.rb +24 -5
  130. data/lib/robot_lab/runnable.rb +51 -0
  131. data/lib/robot_lab/sandbox/null.rb +13 -0
  132. data/lib/robot_lab/sandbox/seatbelt.rb +104 -0
  133. data/lib/robot_lab/sandbox.rb +52 -0
  134. data/lib/robot_lab/script_tool.rb +60 -2
  135. data/lib/robot_lab/task.rb +26 -20
  136. data/lib/robot_lab/tool.rb +52 -11
  137. data/lib/robot_lab/version.rb +1 -1
  138. data/lib/robot_lab.rb +70 -15
  139. data/mkdocs.yml +7 -1
  140. metadata +41 -99
  141. data/examples/temp.md +0 -51
  142. data/site/404.html +0 -2300
  143. data/site/api/core/index.html +0 -2706
  144. data/site/api/core/memory/index.html +0 -3793
  145. data/site/api/core/network/index.html +0 -3500
  146. data/site/api/core/robot/index.html +0 -4566
  147. data/site/api/core/state/index.html +0 -3390
  148. data/site/api/core/tool/index.html +0 -3843
  149. data/site/api/index.html +0 -2635
  150. data/site/api/mcp/client/index.html +0 -3435
  151. data/site/api/mcp/index.html +0 -2783
  152. data/site/api/mcp/server/index.html +0 -3252
  153. data/site/api/mcp/transports/index.html +0 -3352
  154. data/site/api/messages/index.html +0 -2641
  155. data/site/api/messages/text-message/index.html +0 -3087
  156. data/site/api/messages/tool-call-message/index.html +0 -3159
  157. data/site/api/messages/tool-result-message/index.html +0 -3252
  158. data/site/api/messages/user-message/index.html +0 -3212
  159. data/site/api/streaming/context/index.html +0 -3282
  160. data/site/api/streaming/events/index.html +0 -3347
  161. data/site/api/streaming/index.html +0 -2738
  162. data/site/architecture/core-concepts/index.html +0 -3757
  163. data/site/architecture/index.html +0 -2797
  164. data/site/architecture/message-flow/index.html +0 -3238
  165. data/site/architecture/network-orchestration/index.html +0 -3433
  166. data/site/architecture/robot-execution/index.html +0 -3140
  167. data/site/architecture/state-management/index.html +0 -3498
  168. data/site/assets/css/custom.css +0 -56
  169. data/site/assets/images/favicon.png +0 -0
  170. data/site/assets/images/robot_lab.jpg +0 -0
  171. data/site/assets/javascripts/bundle.79ae519e.min.js +0 -16
  172. data/site/assets/javascripts/bundle.79ae519e.min.js.map +0 -7
  173. data/site/assets/javascripts/lunr/min/lunr.ar.min.js +0 -1
  174. data/site/assets/javascripts/lunr/min/lunr.da.min.js +0 -18
  175. data/site/assets/javascripts/lunr/min/lunr.de.min.js +0 -18
  176. data/site/assets/javascripts/lunr/min/lunr.du.min.js +0 -18
  177. data/site/assets/javascripts/lunr/min/lunr.el.min.js +0 -1
  178. data/site/assets/javascripts/lunr/min/lunr.es.min.js +0 -18
  179. data/site/assets/javascripts/lunr/min/lunr.fi.min.js +0 -18
  180. data/site/assets/javascripts/lunr/min/lunr.fr.min.js +0 -18
  181. data/site/assets/javascripts/lunr/min/lunr.he.min.js +0 -1
  182. data/site/assets/javascripts/lunr/min/lunr.hi.min.js +0 -1
  183. data/site/assets/javascripts/lunr/min/lunr.hu.min.js +0 -18
  184. data/site/assets/javascripts/lunr/min/lunr.hy.min.js +0 -1
  185. data/site/assets/javascripts/lunr/min/lunr.it.min.js +0 -18
  186. data/site/assets/javascripts/lunr/min/lunr.ja.min.js +0 -1
  187. data/site/assets/javascripts/lunr/min/lunr.jp.min.js +0 -1
  188. data/site/assets/javascripts/lunr/min/lunr.kn.min.js +0 -1
  189. data/site/assets/javascripts/lunr/min/lunr.ko.min.js +0 -1
  190. data/site/assets/javascripts/lunr/min/lunr.multi.min.js +0 -1
  191. data/site/assets/javascripts/lunr/min/lunr.nl.min.js +0 -18
  192. data/site/assets/javascripts/lunr/min/lunr.no.min.js +0 -18
  193. data/site/assets/javascripts/lunr/min/lunr.pt.min.js +0 -18
  194. data/site/assets/javascripts/lunr/min/lunr.ro.min.js +0 -18
  195. data/site/assets/javascripts/lunr/min/lunr.ru.min.js +0 -18
  196. data/site/assets/javascripts/lunr/min/lunr.sa.min.js +0 -1
  197. data/site/assets/javascripts/lunr/min/lunr.stemmer.support.min.js +0 -1
  198. data/site/assets/javascripts/lunr/min/lunr.sv.min.js +0 -18
  199. data/site/assets/javascripts/lunr/min/lunr.ta.min.js +0 -1
  200. data/site/assets/javascripts/lunr/min/lunr.te.min.js +0 -1
  201. data/site/assets/javascripts/lunr/min/lunr.th.min.js +0 -1
  202. data/site/assets/javascripts/lunr/min/lunr.tr.min.js +0 -18
  203. data/site/assets/javascripts/lunr/min/lunr.vi.min.js +0 -1
  204. data/site/assets/javascripts/lunr/min/lunr.zh.min.js +0 -1
  205. data/site/assets/javascripts/lunr/tinyseg.js +0 -206
  206. data/site/assets/javascripts/lunr/wordcut.js +0 -6708
  207. data/site/assets/javascripts/workers/search.2c215733.min.js +0 -42
  208. data/site/assets/javascripts/workers/search.2c215733.min.js.map +0 -7
  209. data/site/assets/stylesheets/main.484c7ddc.min.css +0 -1
  210. data/site/assets/stylesheets/main.484c7ddc.min.css.map +0 -1
  211. data/site/assets/stylesheets/palette.ab4e12ef.min.css +0 -1
  212. data/site/assets/stylesheets/palette.ab4e12ef.min.css.map +0 -1
  213. data/site/concepts/index.html +0 -3455
  214. data/site/examples/basic-chat/index.html +0 -2880
  215. data/site/examples/index.html +0 -2907
  216. data/site/examples/mcp-server/index.html +0 -3018
  217. data/site/examples/multi-robot-network/index.html +0 -3131
  218. data/site/examples/rails-application/index.html +0 -3329
  219. data/site/examples/tool-usage/index.html +0 -3085
  220. data/site/getting-started/configuration/index.html +0 -3745
  221. data/site/getting-started/index.html +0 -2572
  222. data/site/getting-started/installation/index.html +0 -2981
  223. data/site/getting-started/quick-start/index.html +0 -2942
  224. data/site/guides/building-robots/index.html +0 -4290
  225. data/site/guides/creating-networks/index.html +0 -3858
  226. data/site/guides/index.html +0 -2586
  227. data/site/guides/mcp-integration/index.html +0 -3581
  228. data/site/guides/memory/index.html +0 -3586
  229. data/site/guides/rails-integration/index.html +0 -4019
  230. data/site/guides/streaming/index.html +0 -3157
  231. data/site/guides/using-tools/index.html +0 -3802
  232. data/site/index.html +0 -2671
  233. data/site/search/search_index.json +0 -1
  234. data/site/sitemap.xml +0 -183
  235. data/site/sitemap.xml.gz +0 -0
  236. data/site/tags.json +0 -1
@@ -0,0 +1,402 @@
1
+ # lib/robot_lab/names.rb
2
+
3
+ # A large curated word list, not application logic — kept as one inline
4
+ # module for lookup speed, so the size/length cops below are false positives.
5
+ # rubocop:disable Metrics/ModuleLength
6
+ module RobotLab
7
+ # Fictional robot names
8
+ # rubocop:disable Metrics/CollectionLiteralLength
9
+ NAMES = %w[
10
+ R_7723
11
+ R_790
12
+ AXL
13
+ Adam
14
+ Adam_Link
15
+ Alfie
16
+ Alojzy_Kukuryk
17
+ Alpha_5
18
+ Alpha_6
19
+ Alsatia_Zevo
20
+ AMEE
21
+ Ancient_Ore_Crusher
22
+ Andrew
23
+ Andrew_Martin
24
+ Andromon
25
+ Aniel
26
+ Aqua
27
+ Arbeitsmaschine
28
+ Arthur
29
+ Artificial_Friend
30
+ Ash
31
+ Astor
32
+ Astro_Boy
33
+ Athena
34
+ Atmophytes
35
+ AUTO
36
+ Ava
37
+ B_4
38
+ BATs
39
+ BEN
40
+ BOB
41
+ B166ER
42
+ Baymax
43
+ BB
44
+ BB_8
45
+ Becker
46
+ Bender
47
+ Bénédict_Masson
48
+ Bennie
49
+ Beta
50
+ Beta_Machine
51
+ Billybot
52
+ Bishop
53
+ Black_Beauty
54
+ Blue_Senturion
55
+ Boilerplate
56
+ Boppers
57
+ Bors
58
+ Box
59
+ Brackenridge
60
+ Brainbots
61
+ BRL_A
62
+ Bruno
63
+ Bubo
64
+ Buffybot
65
+ BURN_E
66
+ Byron
67
+ C_3PO
68
+ CHOMPS
69
+ Calculon
70
+ Caliban
71
+ Call
72
+ Cambot
73
+ Candy_Droober
74
+ Carl
75
+ Casandra_Kresnov
76
+ CASE
77
+ Cassandra_One
78
+ Chani
79
+ CHAPPiE
80
+ Charlie
81
+ Cherry_2000
82
+ Chip
83
+ CHIP
84
+ Chitti
85
+ Chuck_the_Robot
86
+ Chucky
87
+ Chumblies
88
+ Claire
89
+ Clamps
90
+ Clunk
91
+ Coconuts
92
+ Coldfire
93
+ Coldstone
94
+ Colossus
95
+ Conky_2000
96
+ Coppélia
97
+ Coyote
98
+ Crimson
99
+ Crow_T_Robot
100
+ Cutie
101
+ Cybots
102
+ Cylons
103
+ D_FIB
104
+ DARYL
105
+ Damon
106
+ Data
107
+ David
108
+ David_8
109
+ Dee_Model
110
+ Dewey
111
+ DOR_15
112
+ Dorfl
113
+ Dot_Matrix
114
+ DV_8
115
+ ED_209
116
+ EDI
117
+ Elio
118
+ Elle
119
+ Emma_2
120
+ Enforcer_Drone
121
+ Engimals
122
+ EVAs
123
+ Eve
124
+ EVE
125
+ Evolver
126
+ Ez_27
127
+ false_Maria
128
+ Fembots
129
+ Flexo
130
+ Frank_Saunders
131
+ Franklin_Droober
132
+ Freya
133
+ Freysa
134
+ Frost
135
+ G2
136
+ Galaxina
137
+ GERTY_3000
138
+ Giant_Robot
139
+ Giddy
140
+ Gigantor
141
+ Gnut
142
+ GO_4
143
+ Goddard
144
+ Gog
145
+ Gort
146
+ Gort
147
+ Gris
148
+ Grounder
149
+ Guardromon
150
+ Gypsy
151
+ Hadaly
152
+ HAN_S
153
+ Haro
154
+ HCR_328
155
+ Hector
156
+ Helen_OLoy
157
+ Helena
158
+ Hermes
159
+ Huey
160
+ Hymie
161
+ Ilia
162
+ Intergalactic_Advocate_Bob
163
+ Jaegers
164
+ Janice_Em
165
+ Jay_Score
166
+ Jay_Dub
167
+ Jenkins
168
+ Jenny_Wakeman
169
+ Jessica
170
+ Jet
171
+ Jet_Jaguar
172
+ Jinx
173
+ Johnny_5
174
+ Johnny_Cab
175
+ Juliana_Tainer
176
+ K
177
+ K_2SO
178
+ K9
179
+ Kampfmaschin
180
+ KARR
181
+ Kay_Em_14
182
+ Kei
183
+ Kikaider
184
+ Killbots
185
+ Kirby
186
+ Kit
187
+ KITT
188
+ Klapaucius
189
+ Kronos
190
+ Kryten
191
+ Kwanzaa_Bot
192
+ Kyoko
193
+ L_76
194
+ L3_37
195
+ Lal
196
+ Lenny
197
+ Leon_Kowalski
198
+ Lomax
199
+ Lore
200
+ Louie
201
+ Luv
202
+ M_O
203
+ M3GAN
204
+ Mac
205
+ Magog
206
+ Mami
207
+ Manders
208
+ Mandroid
209
+ Marcus_Wright
210
+ Maria
211
+ Mariette
212
+ Marius
213
+ Mark_1
214
+ MARK13
215
+ Marvin
216
+ Mary_25
217
+ Maschinenmensch
218
+ Mata_Nui
219
+ Maureen_Droober
220
+ MAX
221
+ Max_404
222
+ Maximillian
223
+ May
224
+ MD_63
225
+ Mech_Eagles
226
+ Mecha_King_Ghidorah
227
+ Mechagodzilla
228
+ Mechagodzilla
229
+ Mechani_Kong
230
+ Mechano
231
+ Mechonoids
232
+ Mec_Willy
233
+ Melfina
234
+ Merlin_Athrawes
235
+ Micro_Managers
236
+ MM7
237
+ Moguera
238
+ MOOSE
239
+ Moravecs
240
+ Mordel
241
+ Morgan
242
+ Mr_Split
243
+ Mr_Static
244
+ Muranian
245
+ Necron_99
246
+ Neotnia
247
+ Newman
248
+ Nimani
249
+ Nimue_Alban
250
+ Norby
251
+ NS4
252
+ Okra
253
+ Olimpia
254
+ Oliver
255
+ Olympia
256
+ Omega
257
+ Omnidroid
258
+ Otis
259
+ POPS
260
+ Paws
261
+ Peace
262
+ Phatasaur
263
+ Phil
264
+ Pino_Petto
265
+ PR_T
266
+ Primus
267
+ Pris
268
+ Project_2501
269
+ Proteus_IV
270
+ Quinn
271
+ R_Daneel_Olivaw
272
+ R_Giskard_Reventlov
273
+ RALF
274
+ ROTOR
275
+ R2_D2
276
+ R4_P17
277
+ Rabbot
278
+ Rachael
279
+ Radius
280
+ Rena
281
+ Replicators
282
+ Rex
283
+ RIA
284
+ Richard_Daniel
285
+ Rick_Deckard
286
+ Ro_Man_Extension_XJ_2
287
+ Rob_Monkey
288
+ Robbie
289
+ Robby
290
+ Robo
291
+ Robo_Clowns
292
+ RoboDoc
293
+ RoboGadget
294
+ Robot_7
295
+ Robot_B_9
296
+ Robot_Devil
297
+ Robot_Santa
298
+ Robot_ZX29B
299
+ Robotoid
300
+ Roderick
301
+ Rosie
302
+ Roy_Batty
303
+ Roz
304
+ ROZZUM_unit_7134
305
+ SAR_003
306
+ S1MONE
307
+ Samantha
308
+ Sapper_Morton
309
+ Sara
310
+ Scratch
311
+ Sentinels
312
+ Setaur
313
+ Sheen
314
+ Sheriff_Not_a_Robot
315
+ SHROUD
316
+ SI_9
317
+ Sico
318
+ SID_67
319
+ SIMON
320
+ Skutters
321
+ Solo
322
+ Sonny
323
+ Sox
324
+ Sparks
325
+ Speedy
326
+ Spofforth
327
+ Spot
328
+ Stitchpunks
329
+ Sulla
330
+ T_1000
331
+ T_600
332
+ T_800
333
+ T_850
334
+ T_Bob
335
+ T_X
336
+ Talkie_Toaster
337
+ TARS
338
+ Terminus
339
+ Tet
340
+ The_Automaton
341
+ The_Cast_Iron_Man
342
+ The_Electric_Grandmother
343
+ The_Fury
344
+ The_Golden_Army
345
+ The_Gunslinger
346
+ The_Hangman
347
+ The_Iron_Giant
348
+ The_Iron_Man
349
+ The_Juggernaut
350
+ The_Mechanical_Cow
351
+ The_Mechanical_Dummy
352
+ The_Mechanical_Horse
353
+ The_Mechanical_Hound
354
+ The_One_Who_Waits
355
+ Tin_Man
356
+ Tik_Tok
357
+ Tilk
358
+ Tilly
359
+ Tima
360
+ Toaster
361
+ Tobor
362
+ Tom
363
+ Tom_Servo
364
+ Tony
365
+ Torg
366
+ Trace_Mayter
367
+ Trurl
368
+ Twonky
369
+ Ultron
370
+ Ulyssses
371
+ UniBlab
372
+ US_47
373
+ VINCENT
374
+ Vahki
375
+ Val
376
+ Valerie_23
377
+ Vanessa_Kensington
378
+ VAQ_M
379
+ Victor
380
+ Vision
381
+ VN_GO
382
+ Voltron
383
+ WALL_E
384
+ Walter_One
385
+ Weebo
386
+ Wilmer
387
+ XJ_9
388
+ Yod
389
+ Z_1
390
+ Z_2
391
+ Z_3
392
+ Zane_Gort
393
+ Zat
394
+ Zhora
395
+ Zoromes
396
+ ].freeze
397
+ # rubocop:enable Metrics/CollectionLiteralLength
398
+
399
+ def self.name = names.first
400
+ def self.names(how_many = 1) = NAMES.sample(how_many).sort
401
+ end
402
+ # rubocop:enable Metrics/ModuleLength
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RobotLab
4
+ # Opt-in live observability hook: narrates what a robot is doing as it happens,
5
+ # so a run is never silent between events. Complements RobotLab::Audit (which
6
+ # records to a persistent store) with a human-facing console feed.
7
+ #
8
+ # Enable it globally (applies to every robot run, including networks):
9
+ #
10
+ # RobotLab::Narrator.enable! # narrate to $stderr
11
+ # RobotLab::Narrator.enable!(output: $stdout)
12
+ #
13
+ # or register like any hook for finer scope:
14
+ #
15
+ # robot.on(RobotLab::Narrator)
16
+ # network.on(RobotLab::Narrator)
17
+ #
18
+ # Output goes to $stderr by default and uses IO#puts (not Kernel#warn, which is
19
+ # silenced when Ruby warnings are disabled — i.e. $VERBOSE is nil, common under
20
+ # `bundle exec`).
21
+ class Narrator < RobotLab::Hook
22
+ self.namespace = :narrator
23
+
24
+ MAX = 80
25
+
26
+ class << self
27
+ attr_writer :output
28
+
29
+ # @return [IO] where narration is written (default $stderr)
30
+ def output
31
+ @output ||= $stderr
32
+ end
33
+
34
+ # Register the narrator globally and set its output.
35
+ #
36
+ # @param output [IO]
37
+ # @return [Class] self
38
+ def enable!(output: $stderr)
39
+ self.output = output
40
+ RobotLab.on(self)
41
+ self
42
+ end
43
+
44
+ # --- hooks ---------------------------------------------------------------
45
+
46
+ def before_llm_generation(ctx)
47
+ who = ctx.respond_to?(:robot) ? ctx.robot&.name : nil
48
+ say "#{"#{who}: " if who}thinking…"
49
+ rescue StandardError
50
+ nil
51
+ end
52
+
53
+ def before_tool_call(ctx)
54
+ say "→ #{ctx.tool_name}#{summarize(ctx.tool_args)}"
55
+ rescue StandardError
56
+ nil
57
+ end
58
+
59
+ def after_tool_call(ctx)
60
+ say " ✗ #{clip(ctx.tool_error.message)}" if ctx.tool_error
61
+ rescue StandardError
62
+ nil
63
+ end
64
+
65
+ private
66
+
67
+ def say(message)
68
+ output.puts(" · #{message}")
69
+ rescue StandardError
70
+ nil
71
+ end
72
+
73
+ # Compact one-line summary of the first tool argument, e.g. " path=\"a.rb\"".
74
+ def summarize(args)
75
+ return "" unless args.is_a?(Hash) && !args.empty?
76
+
77
+ key, value = args.first
78
+ " #{key}=#{clip(value).inspect}"
79
+ end
80
+
81
+ def clip(text)
82
+ line = text.to_s.lines.first.to_s.strip
83
+ line.length > MAX ? "#{line[0, MAX]}…" : line
84
+ end
85
+ end
86
+ end
87
+ end
@@ -59,6 +59,7 @@ module RobotLab
59
59
  #
60
60
  class Network
61
61
  include Utils
62
+ include Runnable
62
63
 
63
64
  # Reserved key for broadcast messages in memory
64
65
  BROADCAST_KEY = :_network_broadcast
@@ -71,7 +72,7 @@ module RobotLab
71
72
  # @return [Hash<String, Robot>] robots in this network, keyed by name
72
73
  # @!attribute [r] memory
73
74
  # @return [Memory] shared memory for all robots in the network
74
- attr_reader :name, :pipeline, :robots, :memory, :config, :parallel_mode
75
+ attr_reader :name, :pipeline, :robots, :memory, :config, :parallel_mode, :hooks
75
76
 
76
77
  # Creates a new Network instance.
77
78
  #
@@ -94,6 +95,7 @@ module RobotLab
94
95
  @memory = memory || Memory.new(network_name: @name)
95
96
  @config = config || RunConfig.new
96
97
  @parallel_mode = parallel_mode
98
+ @hooks = HookRegistry.new
97
99
  @broadcast_handlers = []
98
100
  @bus_poller = BusPoller.new.start
99
101
 
@@ -132,7 +134,8 @@ module RobotLab
132
134
  mcp: mcp,
133
135
  tools: tools,
134
136
  memory: memory,
135
- config: config
137
+ config: config,
138
+ network: self
136
139
  )
137
140
 
138
141
  # Register the group and assign the shared poller to the robot
@@ -177,24 +180,55 @@ module RobotLab
177
180
  # result.value # => RobotResult from last robot
178
181
  # result.context[:classifier] # => RobotResult from classifier
179
182
  #
180
- def run(**run_context)
183
+ def run(message = nil, **run_context)
184
+ # Runnable protocol: accept a positional message like Robot#run does, so
185
+ # callers can `run(msg, ...)` uniformly. `run(message: msg)` still works.
186
+ run_context[:message] = message unless message.nil?
187
+
181
188
  # Include shared memory in run params so robots can access it
182
189
  run_context[:network_memory] = @memory
190
+ run_context[:network] = self
183
191
 
184
192
  # Pass network's config so robots can inherit it
185
193
  run_context[:network_config] = @config unless @config.empty?
186
194
 
187
- if @parallel_mode == :ractor
188
- run_with_ractor_scheduler(run_context)
189
- else
190
- initial_result = SimpleFlow::Result.new(
191
- run_context,
192
- context: { run_params: run_context }
193
- )
194
- @pipeline.call_parallel(initial_result, max_concurrent: @config.max_concurrent_robots)
195
+ context = NetworkRunHookContext.new(
196
+ network: self,
197
+ context: run_context,
198
+ memory: @memory,
199
+ config: @config
200
+ )
201
+
202
+ RobotLab::Hooks.run(:network_run, context, registries: [RobotLab.hooks, @hooks]) do
203
+ if @parallel_mode == :ractor
204
+ run_with_ractor_scheduler(context.context)
205
+ else
206
+ initial_result = SimpleFlow::Result.new(
207
+ context.context,
208
+ context: { run_params: context.context }
209
+ )
210
+ @pipeline.call_parallel(initial_result, max_concurrent: @config.max_concurrent_robots)
211
+ end
195
212
  end
196
213
  end
197
214
 
215
+ # Runnable protocol: the network's robots as an Array (in pipeline order),
216
+ # and the network? predicate. (`robots` itself stays a name=>robot Hash.)
217
+ #
218
+ # @return [Array<Robot>]
219
+ def crew
220
+ robots.values
221
+ end
222
+
223
+ # @return [Boolean] always true for a Network
224
+ def network?
225
+ true
226
+ end
227
+
228
+ def on(handler_class, context: nil)
229
+ @hooks.on(handler_class, context: context)
230
+ end
231
+
198
232
  # Broadcast a message to all robots in the network.
199
233
  #
200
234
  # This sends a network-wide message that all robots subscribed via
@@ -303,6 +337,19 @@ module RobotLab
303
337
  self
304
338
  end
305
339
 
340
+ # Remove a dynamically-added robot from the network by name. Returns the
341
+ # removed robot, or nil if no robot by that name was present.
342
+ #
343
+ # Only removes the robot from the crew (`@robots`); it does not rewrite the
344
+ # pipeline, so callers should not remove a robot that is a pipeline task.
345
+ #
346
+ # @param name [String, Symbol] the robot's name
347
+ # @return [Robot, nil]
348
+ #
349
+ def remove_robot(name)
350
+ @robots.delete(name.to_s)
351
+ end
352
+
306
353
  # Visualize the pipeline as ASCII
307
354
  #
308
355
  # @return [String, nil]
@@ -363,15 +410,7 @@ module RobotLab
363
410
  specs_with_deps = @tasks.map do |task_name, task_wrapper|
364
411
  deps = dep_graph[task_name.to_sym] || []
365
412
  deps = deps.empty? ? :none : deps.map(&:to_s)
366
-
367
- spec = RobotSpec.new(
368
- name: task_wrapper.robot.name.freeze,
369
- template: task_wrapper.robot.template&.to_s&.freeze,
370
- system_prompt: task_wrapper.robot.system_prompt&.freeze,
371
- config_hash: RactorBoundary.freeze_deep(task_wrapper.robot.config.to_json_hash)
372
- )
373
-
374
- { spec: spec, depends_on: deps }
413
+ { spec: build_robot_spec(task_wrapper), depends_on: deps }
375
414
  end
376
415
 
377
416
  scheduler = RactorNetworkScheduler.new(memory: @memory)
@@ -379,5 +418,23 @@ module RobotLab
379
418
  scheduler.shutdown
380
419
  results
381
420
  end
421
+
422
+ def build_robot_spec(task_wrapper)
423
+ robot = task_wrapper.robot
424
+ RobotSpec.new(
425
+ name: robot.name.freeze,
426
+ template: robot.template&.to_s&.freeze,
427
+ system_prompt: robot.system_prompt&.freeze,
428
+ config_hash: RactorBoundary.freeze_deep(robot.config.to_json_hash),
429
+ hook_classes: ractor_hook_classes_for(robot)
430
+ )
431
+ end
432
+
433
+ def ractor_hook_classes_for(robot)
434
+ [RobotLab.hooks, @hooks, robot.hooks]
435
+ .flat_map { |registry| registry.registrations.map(&:handler_class) }
436
+ .uniq
437
+ .freeze
438
+ end
382
439
  end
383
440
  end
@@ -90,9 +90,7 @@ module RobotLab
90
90
  #
91
91
  # @return [String, nil]
92
92
  def current_agent_skill_instructions
93
- messages = @chat.instance_variable_get(:@messages)
94
- sys = messages&.find { |m| m.role.to_s == "system" }
95
- sys&.content
93
+ current_system_instructions
96
94
  end
97
95
  end
98
96
  end