robot_lab 0.2.8 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +65 -0
  3. data/README.md +16 -18
  4. data/lib/robot_lab/ask_user.rb +3 -3
  5. data/lib/robot_lab/config/defaults.yml +5 -5
  6. data/lib/robot_lab/config.rb +2 -2
  7. data/lib/robot_lab/mcp/transports/streamable_http.rb +2 -4
  8. data/lib/robot_lab/memory.rb +16 -7
  9. data/lib/robot_lab/robot/hooking.rb +26 -0
  10. data/lib/robot_lab/robot/result_building.rb +119 -0
  11. data/lib/robot_lab/robot.rb +37 -120
  12. data/lib/robot_lab/run_config.rb +52 -20
  13. data/lib/robot_lab/tool.rb +7 -12
  14. data/lib/robot_lab/version.rb +1 -1
  15. data/lib/robot_lab.rb +3 -3
  16. metadata +15 -274
  17. data/.architecture/AGENTS.md +0 -32
  18. data/.architecture/config.yml +0 -8
  19. data/.architecture/members.yml +0 -60
  20. data/.architecture/reviews/feature-free-will.md +0 -490
  21. data/.architecture/reviews/overall-codebase.md +0 -427
  22. data/.claude/settings.local.json +0 -57
  23. data/.codex/config.toml +0 -2
  24. data/.envrc +0 -6
  25. data/.github/workflows/deploy-github-pages.yml +0 -52
  26. data/.irbrc +0 -6
  27. data/.loki +0 -65
  28. data/.quality/reek_baseline.txt +0 -43
  29. data/.rubocop.yml +0 -10
  30. data/Archspec.rb +0 -44
  31. data/CLAUDE.md +0 -139
  32. data/COMMITS.md +0 -196
  33. data/Rakefile +0 -193
  34. data/_typos.toml +0 -21
  35. data/agent2agent_review.md +0 -192
  36. data/agentf_improvements.md +0 -253
  37. data/agents.md +0 -14
  38. data/docs/api/core/index.md +0 -147
  39. data/docs/api/core/memory.md +0 -578
  40. data/docs/api/core/network.md +0 -553
  41. data/docs/api/core/result.md +0 -211
  42. data/docs/api/core/robot.md +0 -1667
  43. data/docs/api/core/state.md +0 -145
  44. data/docs/api/core/tool.md +0 -520
  45. data/docs/api/errors.md +0 -323
  46. data/docs/api/hooks.md +0 -469
  47. data/docs/api/index.md +0 -137
  48. data/docs/api/mcp/client.md +0 -387
  49. data/docs/api/mcp/index.md +0 -267
  50. data/docs/api/mcp/server.md +0 -252
  51. data/docs/api/mcp/transports.md +0 -339
  52. data/docs/api/messages/index.md +0 -126
  53. data/docs/api/messages/text-message.md +0 -170
  54. data/docs/api/messages/tool-call-message.md +0 -206
  55. data/docs/api/messages/tool-result-message.md +0 -242
  56. data/docs/api/messages/user-message.md +0 -232
  57. data/docs/api/skills.md +0 -423
  58. data/docs/api/streaming/context.md +0 -280
  59. data/docs/api/streaming/events.md +0 -185
  60. data/docs/api/streaming/index.md +0 -156
  61. data/docs/api/support.md +0 -846
  62. data/docs/architecture/core-concepts.md +0 -575
  63. data/docs/architecture/index.md +0 -252
  64. data/docs/architecture/message-flow.md +0 -366
  65. data/docs/architecture/network-orchestration.md +0 -478
  66. data/docs/architecture/robot-execution.md +0 -396
  67. data/docs/architecture/state-management.md +0 -410
  68. data/docs/assets/css/custom.css +0 -56
  69. data/docs/assets/images/robot_lab.jpg +0 -0
  70. data/docs/concepts.md +0 -641
  71. data/docs/examples/basic-chat.md +0 -258
  72. data/docs/examples/index.md +0 -425
  73. data/docs/examples/mcp-server.md +0 -403
  74. data/docs/examples/multi-robot-network.md +0 -476
  75. data/docs/examples/tool-usage.md +0 -468
  76. data/docs/getting-started/configuration.md +0 -645
  77. data/docs/getting-started/index.md +0 -56
  78. data/docs/getting-started/installation.md +0 -200
  79. data/docs/getting-started/quick-start.md +0 -293
  80. data/docs/guides/building-robots.md +0 -1187
  81. data/docs/guides/creating-networks.md +0 -736
  82. data/docs/guides/hooks.md +0 -1206
  83. data/docs/guides/index.md +0 -78
  84. data/docs/guides/knowledge.md +0 -219
  85. data/docs/guides/mcp-integration.md +0 -740
  86. data/docs/guides/memory.md +0 -458
  87. data/docs/guides/observability.md +0 -733
  88. data/docs/guides/streaming.md +0 -323
  89. data/docs/guides/using-tools.md +0 -780
  90. data/docs/index.md +0 -280
  91. data/docs/superpowers/plans/2026-05-06-agentskills.md +0 -1303
  92. data/docs/superpowers/specs/2026-05-06-agentskills-design.md +0 -247
  93. data/examples/.envrc +0 -1
  94. data/examples/01_simple_robot.rb +0 -31
  95. data/examples/02_tools.rb +0 -109
  96. data/examples/03_network.rb +0 -118
  97. data/examples/04_mcp.rb +0 -215
  98. data/examples/05_streaming.rb +0 -137
  99. data/examples/06_prompt_templates.rb +0 -325
  100. data/examples/07_network_memory.rb +0 -313
  101. data/examples/08_llm_config.rb +0 -162
  102. data/examples/09_chaining.rb +0 -251
  103. data/examples/10_memory.rb +0 -315
  104. data/examples/11_network_introspection.rb +0 -239
  105. data/examples/12_message_bus.rb +0 -67
  106. data/examples/13_spawn.rb +0 -85
  107. data/examples/14_rusty_circuit/.envrc +0 -1
  108. data/examples/14_rusty_circuit/.gitignore +0 -1
  109. data/examples/14_rusty_circuit/README.md +0 -1
  110. data/examples/14_rusty_circuit/comic.rb +0 -149
  111. data/examples/14_rusty_circuit/display.rb +0 -217
  112. data/examples/14_rusty_circuit/heckler.rb +0 -65
  113. data/examples/14_rusty_circuit/open_mic.rb +0 -132
  114. data/examples/14_rusty_circuit/prompts/open_mic_comic.md +0 -20
  115. data/examples/14_rusty_circuit/prompts/open_mic_heckler.md +0 -23
  116. data/examples/14_rusty_circuit/prompts/open_mic_scout.md +0 -20
  117. data/examples/14_rusty_circuit/scout.rb +0 -165
  118. data/examples/14_rusty_circuit/show.log +0 -234
  119. data/examples/15_memory_network_and_bus/.envrc +0 -1
  120. data/examples/15_memory_network_and_bus/editor_in_chief.rb +0 -24
  121. data/examples/15_memory_network_and_bus/editorial_pipeline.rb +0 -213
  122. data/examples/15_memory_network_and_bus/linux_writer.rb +0 -80
  123. data/examples/15_memory_network_and_bus/os_editor.rb +0 -48
  124. data/examples/15_memory_network_and_bus/os_writer.rb +0 -49
  125. data/examples/15_memory_network_and_bus/output/combined_article.md +0 -13
  126. data/examples/15_memory_network_and_bus/output/final_article.md +0 -13
  127. data/examples/15_memory_network_and_bus/output/linux_draft.md +0 -7
  128. data/examples/15_memory_network_and_bus/output/mac_draft.md +0 -7
  129. data/examples/15_memory_network_and_bus/output/memory.json +0 -13
  130. data/examples/15_memory_network_and_bus/output/revision_1.md +0 -18
  131. data/examples/15_memory_network_and_bus/output/revision_2.md +0 -13
  132. data/examples/15_memory_network_and_bus/output/windows_draft.md +0 -7
  133. data/examples/15_memory_network_and_bus/prompts/os_advocate.md +0 -13
  134. data/examples/15_memory_network_and_bus/prompts/os_chief.md +0 -13
  135. data/examples/15_memory_network_and_bus/prompts/os_editor.md +0 -13
  136. data/examples/16_writers_room/.envrc +0 -1
  137. data/examples/16_writers_room/display.rb +0 -158
  138. data/examples/16_writers_room/output/.gitignore +0 -4
  139. data/examples/16_writers_room/output/README.md +0 -69
  140. data/examples/16_writers_room/output/opus_001.md +0 -263
  141. data/examples/16_writers_room/output/opus_001_notes.log +0 -470
  142. data/examples/16_writers_room/output/opus_002.md +0 -245
  143. data/examples/16_writers_room/output/opus_002_notes.log +0 -546
  144. data/examples/16_writers_room/output/opus_002_screenplay.md +0 -7989
  145. data/examples/16_writers_room/output/opus_002_screenplay_notes.md +0 -993
  146. data/examples/16_writers_room/prompts/screenplay_writer.md +0 -66
  147. data/examples/16_writers_room/prompts/writer.md +0 -37
  148. data/examples/16_writers_room/room.rb +0 -186
  149. data/examples/16_writers_room/tools.rb +0 -173
  150. data/examples/16_writers_room/writer.rb +0 -121
  151. data/examples/16_writers_room/writers_room.rb +0 -256
  152. data/examples/17_skills.rb +0 -234
  153. data/examples/18_rails/.envrc +0 -3
  154. data/examples/18_rails/.gitignore +0 -5
  155. data/examples/18_rails/Gemfile +0 -11
  156. data/examples/18_rails/README.md +0 -67
  157. data/examples/18_rails/Rakefile +0 -4
  158. data/examples/18_rails/app/controllers/application_controller.rb +0 -4
  159. data/examples/18_rails/app/controllers/chat_controller.rb +0 -50
  160. data/examples/18_rails/app/jobs/application_job.rb +0 -4
  161. data/examples/18_rails/app/jobs/robot_run_job.rb +0 -25
  162. data/examples/18_rails/app/models/application_record.rb +0 -5
  163. data/examples/18_rails/app/models/robot_lab_result.rb +0 -36
  164. data/examples/18_rails/app/models/robot_lab_thread.rb +0 -23
  165. data/examples/18_rails/app/robots/chat_robot.rb +0 -25
  166. data/examples/18_rails/app/tools/time_tool.rb +0 -9
  167. data/examples/18_rails/app/views/chat/_user_message.html.erb +0 -1
  168. data/examples/18_rails/app/views/chat/index.html.erb +0 -67
  169. data/examples/18_rails/app/views/layouts/application.html.erb +0 -49
  170. data/examples/18_rails/bin/dev +0 -7
  171. data/examples/18_rails/bin/rails +0 -6
  172. data/examples/18_rails/bin/setup +0 -15
  173. data/examples/18_rails/config/application.rb +0 -33
  174. data/examples/18_rails/config/cable.yml +0 -2
  175. data/examples/18_rails/config/database.yml +0 -5
  176. data/examples/18_rails/config/environment.rb +0 -4
  177. data/examples/18_rails/config/initializers/robot_lab.rb +0 -11
  178. data/examples/18_rails/config/routes.rb +0 -6
  179. data/examples/18_rails/config.ru +0 -4
  180. data/examples/18_rails/db/migrate/001_create_robot_lab_tables.rb +0 -32
  181. data/examples/19_token_tracking.rb +0 -138
  182. data/examples/20_circuit_breaker.rb +0 -147
  183. data/examples/21_learning_loop.rb +0 -181
  184. data/examples/22_context_compression.rb +0 -172
  185. data/examples/23_convergence.rb +0 -133
  186. data/examples/24_structured_delegation.rb +0 -151
  187. data/examples/25_history_search/conversation.jsonl +0 -30
  188. data/examples/25_history_search.rb +0 -133
  189. data/examples/26_document_store/api_versioning_adr.md +0 -52
  190. data/examples/26_document_store/incident_postmortem.md +0 -46
  191. data/examples/26_document_store/postgres_runbook.md +0 -49
  192. data/examples/26_document_store/redis_caching_guide.md +0 -48
  193. data/examples/26_document_store/sidekiq_guide.md +0 -51
  194. data/examples/26_document_store.rb +0 -140
  195. data/examples/27_incident_response/incident_response.rb +0 -261
  196. data/examples/28_mcp_discovery.rb +0 -113
  197. data/examples/29_ractor_tools.rb +0 -240
  198. data/examples/30_ractor_network.rb +0 -252
  199. data/examples/31_launch_assessment.rb +0 -246
  200. data/examples/32_newsletter_reader.rb +0 -193
  201. data/examples/33_stock_generator.rb +0 -80
  202. data/examples/33_stock_predictor.rb +0 -327
  203. data/examples/34_agentskills.rb +0 -76
  204. data/examples/35_hooks.rb +0 -266
  205. data/examples/README.md +0 -533
  206. data/examples/common.rb +0 -148
  207. data/examples/prompts/assistant.md +0 -5
  208. data/examples/prompts/audit_trail.md +0 -8
  209. data/examples/prompts/billing.md +0 -10
  210. data/examples/prompts/classifier.md +0 -7
  211. data/examples/prompts/comedian.md +0 -6
  212. data/examples/prompts/comedy_critic.md +0 -10
  213. data/examples/prompts/configurable.md +0 -9
  214. data/examples/prompts/dispatcher.md +0 -12
  215. data/examples/prompts/entity_extractor.md +0 -14
  216. data/examples/prompts/escalation.md +0 -42
  217. data/examples/prompts/frontmatter_mcp_test.md +0 -9
  218. data/examples/prompts/frontmatter_named_test.md +0 -5
  219. data/examples/prompts/frontmatter_tools_test.md +0 -6
  220. data/examples/prompts/general.md +0 -7
  221. data/examples/prompts/github_assistant.md +0 -14
  222. data/examples/prompts/helper.md +0 -4
  223. data/examples/prompts/incident_responder.md +0 -18
  224. data/examples/prompts/keyword_extractor.md +0 -11
  225. data/examples/prompts/llm_config_demo.md +0 -20
  226. data/examples/prompts/order_support.md +0 -35
  227. data/examples/prompts/os_advocate.md +0 -13
  228. data/examples/prompts/os_chief.md +0 -13
  229. data/examples/prompts/os_editor.md +0 -13
  230. data/examples/prompts/parameterized_main_test.md +0 -6
  231. data/examples/prompts/pii_redactor.md +0 -7
  232. data/examples/prompts/product_support.md +0 -37
  233. data/examples/prompts/runbook_protocol.md +0 -12
  234. data/examples/prompts/sentiment_analyzer.md +0 -12
  235. data/examples/prompts/skill_a_test.md +0 -4
  236. data/examples/prompts/skill_b_test.md +0 -4
  237. data/examples/prompts/skill_config_test.md +0 -5
  238. data/examples/prompts/skill_cycle_a_test.md +0 -6
  239. data/examples/prompts/skill_cycle_b_test.md +0 -6
  240. data/examples/prompts/skill_description_test.md +0 -4
  241. data/examples/prompts/skill_leaf_test.md +0 -4
  242. data/examples/prompts/skill_nested_test.md +0 -6
  243. data/examples/prompts/skill_refs_main_test.md +0 -6
  244. data/examples/prompts/skill_self_ref_test.md +0 -6
  245. data/examples/prompts/skill_with_mcp_test.md +0 -9
  246. data/examples/prompts/skill_with_params_test.md +0 -6
  247. data/examples/prompts/skill_with_robot_name_test.md +0 -5
  248. data/examples/prompts/skill_with_tools_test.md +0 -6
  249. data/examples/prompts/sre_compliance.md +0 -10
  250. data/examples/prompts/structured_output.md +0 -7
  251. data/examples/prompts/synthesizer.md +0 -17
  252. data/examples/prompts/technical.md +0 -10
  253. data/examples/prompts/template_with_skills_test.md +0 -6
  254. data/examples/prompts/triage.md +0 -22
  255. data/examples/ruboruby.md +0 -423
  256. data/examples/xyzzy.rb +0 -97
  257. data/logfile +0 -8
  258. data/mkdocs.yml +0 -209
  259. data/robot_concurrency.md +0 -38
  260. data/simple_acp_review.md +0 -298
  261. data/temp.md +0 -6
  262. data/tool_manifest_plan.md +0 -155
@@ -1,313 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Example 7: Network Memory with Concurrent Robots
5
- #
6
- # Demonstrates the reactive shared memory system where:
7
- # - Multiple robots run concurrently and write to shared memory
8
- # - Robots can wait for values written by other robots
9
- # - Subscriptions provide real-time notifications of memory changes
10
- # - Network broadcast sends messages to all robots
11
- #
12
- # Architecture:
13
- # ┌─────────────────────────────────────────────────────────────┐
14
- # │ PARALLEL ANALYSIS │
15
- # │ │
16
- # │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
17
- # │ │ Sentiment │ │ Entities │ │ Keywords │ │
18
- # │ │ Analyzer │ │ Extractor │ │ Extractor │ │
19
- # │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
20
- # │ │ │ │ │
21
- # │ ▼ ▼ ▼ │
22
- # │ memory.set( memory.set( memory.set( │
23
- # │ :sentiment) :entities) :keywords) │
24
- # │ │ │ │ │
25
- # │ └────────────────┼────────────────┘ │
26
- # │ ▼ │
27
- # │ ┌──────────────────────────────────────────────────────┐ │
28
- # │ │ SHARED MEMORY │ │
29
- # │ │ { sentiment: {...}, entities: {...}, keywords: {...} │ │
30
- # │ └──────────────────────────────────────────────────────┘ │
31
- # │ │ │
32
- # │ ▼ │
33
- # │ ┌──────────────────────────────────────────────────────┐ │
34
- # │ │ Synthesizer │ │
35
- # │ │ memory.get(:sentiment, :entities, :keywords, │ │
36
- # │ │ wait: true) │ │
37
- # │ └──────────────────────────────────────────────────────┘ │
38
- # │ │
39
- # └─────────────────────────────────────────────────────────────┘
40
- #
41
- # Usage:
42
- # ruby examples/07_network_memory.rb
43
-
44
- require_relative "common"
45
- require "json"
46
-
47
- banner "Network Memory with Concurrent Robots"
48
-
49
- # -----------------------------------------------------------------------------
50
- # Custom Robot Classes that Write to Shared Memory
51
- # -----------------------------------------------------------------------------
52
-
53
- # Base class for analysis robots that write results to memory
54
- class AnalysisRobot < RobotLab::Robot
55
- def initialize(memory_key:, **opts)
56
- super(**opts)
57
- @memory_key = memory_key
58
- end
59
-
60
- def call(result)
61
- run_context = extract_run_context(result)
62
- network_memory = run_context.delete(:network_memory)
63
- message = run_context.delete(:message)
64
-
65
- robot_result = run(message, network_memory: network_memory, **run_context)
66
-
67
- # Parse the JSON response and write to shared memory
68
- if network_memory
69
- content = robot_result.reply.to_s
70
-
71
- # Set writer before writing to memory
72
- network_memory.current_writer = @name
73
-
74
- begin
75
- parsed = JSON.parse(content)
76
- network_memory.set(@memory_key, parsed)
77
- puts " [#{@name}] Wrote JSON to memory[:#{@memory_key}]"
78
- rescue JSON::ParserError
79
- # If not valid JSON, store the raw text
80
- network_memory.set(@memory_key, content)
81
- puts " [#{@name}] Wrote text to memory[:#{@memory_key}]"
82
- end
83
- end
84
-
85
- result
86
- .with_context(@name.to_sym, robot_result)
87
- .continue(robot_result)
88
- end
89
- end
90
-
91
- # Synthesizer robot that reads from shared memory and synthesizes results
92
- class SynthesizerRobot < RobotLab::Robot
93
- def call(result)
94
- run_context = extract_run_context(result)
95
- network_memory = run_context.delete(:network_memory)
96
- message = run_context.delete(:message)
97
-
98
- puts " [#{@name}] Reading analysis results from memory..."
99
-
100
- if network_memory
101
- # Read results from memory - they should already be there since
102
- # SimpleFlow ensures our dependencies completed first
103
- sentiment = network_memory.get(:sentiment)
104
- entities = network_memory.get(:entities)
105
- keywords = network_memory.get(:keywords)
106
-
107
- puts " [#{@name}] Got sentiment: #{sentiment.nil? ? 'nil' : 'present'}"
108
- puts " [#{@name}] Got entities: #{entities.nil? ? 'nil' : 'present'}"
109
- puts " [#{@name}] Got keywords: #{keywords.nil? ? 'nil' : 'present'}"
110
-
111
- # Format for the template
112
- run_context[:sentiment] = format_for_template(sentiment)
113
- run_context[:entities] = format_for_template(entities)
114
- run_context[:keywords] = format_for_template(keywords)
115
- else
116
- run_context[:sentiment] = "Not available"
117
- run_context[:entities] = "Not available"
118
- run_context[:keywords] = "Not available"
119
- end
120
-
121
- robot_result = run(message, network_memory: network_memory, **run_context)
122
-
123
- result
124
- .with_context(@name.to_sym, robot_result)
125
- .continue(robot_result)
126
- end
127
-
128
- private
129
-
130
- def format_for_template(value)
131
- case value
132
- when Hash, Array
133
- JSON.pretty_generate(value)
134
- when nil
135
- "Not available"
136
- else
137
- value.to_s
138
- end
139
- end
140
- end
141
-
142
- # -----------------------------------------------------------------------------
143
- # Create the Robots
144
- # -----------------------------------------------------------------------------
145
-
146
- sentiment_robot = AnalysisRobot.new(
147
- name: "sentiment_analyzer",
148
- template: :sentiment_analyzer,
149
- memory_key: :sentiment,
150
- **llm_opts
151
- )
152
-
153
- entity_robot = AnalysisRobot.new(
154
- name: "entity_extractor",
155
- template: :entity_extractor,
156
- memory_key: :entities,
157
- **llm_opts
158
- )
159
-
160
- keyword_robot = AnalysisRobot.new(
161
- name: "keyword_extractor",
162
- template: :keyword_extractor,
163
- memory_key: :keywords,
164
- **llm_opts
165
- )
166
-
167
- synthesizer = SynthesizerRobot.new(
168
- name: "synthesizer",
169
- template: :synthesizer,
170
- **llm_opts
171
- )
172
-
173
- # -----------------------------------------------------------------------------
174
- # Create the Network with Shared Memory
175
- # -----------------------------------------------------------------------------
176
-
177
- network = RobotLab.create_network(name: "parallel_analysis") do
178
- # Three analysis robots run in parallel (all depend on nothing)
179
- task :sentiment, sentiment_robot, depends_on: :none
180
- task :entities, entity_robot, depends_on: :none
181
- task :keywords, keyword_robot, depends_on: :none
182
-
183
- # Synthesizer waits for all three to complete
184
- task :synthesize, synthesizer, depends_on: [:sentiment, :entities, :keywords]
185
- end
186
-
187
- # -----------------------------------------------------------------------------
188
- # Set Up Memory Subscriptions (for monitoring)
189
- # -----------------------------------------------------------------------------
190
-
191
- puts "Setting up memory subscriptions for monitoring..."
192
- puts
193
-
194
- # Note: In concurrent execution, change.writer may be unreliable due to race
195
- # conditions. For production use, consider including writer info in the value.
196
- network.memory.subscribe(:sentiment, :entities, :keywords) do |change|
197
- value_preview = case change.value
198
- when Hash then change.value.keys.join(", ")
199
- when String then change.value[0..50]
200
- else change.value.class.name
201
- end
202
- puts " [MONITOR] Memory[:#{change.key}] updated with keys: #{value_preview}"
203
- end
204
-
205
- # -----------------------------------------------------------------------------
206
- # Set Up Broadcast Handler
207
- # -----------------------------------------------------------------------------
208
-
209
- network.on_broadcast do |message|
210
- puts " [BROADCAST] #{message[:payload][:event]}: #{message[:payload][:details]}"
211
- end
212
-
213
- # -----------------------------------------------------------------------------
214
- # Run the Network
215
- # -----------------------------------------------------------------------------
216
-
217
- sample_text = <<~TEXT
218
- Apple Inc. announced today that CEO Tim Cook will be presenting the new iPhone 15
219
- at their headquarters in Cupertino, California on September 12th, 2024.
220
- Industry analysts are extremely excited about the new features, though some
221
- consumer advocates have expressed concerns about the expected price increase.
222
- Samsung and Google are reportedly preparing competitive responses for later this year.
223
- TEXT
224
-
225
- puts "Network structure:"
226
- puts network.visualize
227
- puts
228
- hr
229
- puts "Input text:"
230
- puts sample_text.strip
231
- hr
232
- puts
233
-
234
- # Send a broadcast before starting
235
- network.broadcast(event: "analysis_started", details: "Beginning parallel analysis")
236
-
237
- puts "Running parallel analysis..."
238
- puts
239
- start_time = Time.now
240
-
241
- result = network.run(message: sample_text)
242
-
243
- elapsed = Time.now - start_time
244
- puts
245
- hr
246
- puts "Analysis complete in #{elapsed.round(2)} seconds"
247
- hr
248
-
249
- # Send completion broadcast
250
- network.broadcast(event: "analysis_complete", details: "All robots finished")
251
-
252
- # -----------------------------------------------------------------------------
253
- # Display Results
254
- # -----------------------------------------------------------------------------
255
-
256
-
257
- section "Final Synthesis"
258
-
259
- if result.value.is_a?(RobotLab::RobotResult)
260
- puts result.value.reply
261
- end
262
-
263
-
264
- section "Memory State"
265
-
266
- # Show what's in shared memory
267
- memory = network.memory
268
- puts "Sentiment: #{memory.get(:sentiment)&.to_json}"
269
- puts
270
- puts "Entities: #{memory.get(:entities)&.to_json}"
271
- puts
272
- puts "Keywords: #{memory.get(:keywords)&.to_json}"
273
-
274
- # -----------------------------------------------------------------------------
275
- # Demonstrate Blocking Wait (without pipeline dependencies)
276
- # -----------------------------------------------------------------------------
277
-
278
-
279
- section "Demonstrating Blocking Wait"
280
-
281
- # Create a fresh memory for this demo
282
- demo_memory = RobotLab::Memory.new(network_name: "wait_demo")
283
-
284
- # Simulate a concurrent scenario where one thread waits for another
285
- puts "Starting writer thread (will write after 1 second)..."
286
- puts "Starting reader thread (will wait for value)..."
287
-
288
- reader_result = nil
289
- writer_done = false
290
-
291
- reader = Thread.new do
292
- start = Time.now
293
- puts " [reader] Waiting for :delayed_result..."
294
- value = demo_memory.get(:delayed_result, wait: 10)
295
- elapsed = Time.now - start
296
- reader_result = value
297
- puts " [reader] Got value after #{elapsed.round(2)}s: #{value}"
298
- end
299
-
300
- writer = Thread.new do
301
- sleep 1
302
- demo_memory.set(:delayed_result, { status: "complete", data: [1, 2, 3] })
303
- writer_done = true
304
- puts " [writer] Wrote :delayed_result to memory"
305
- end
306
-
307
- # Wait for both threads
308
- writer.join
309
- reader.join
310
-
311
- puts
312
- puts "Blocking wait demonstration complete!"
313
- puts "Reader received: #{reader_result.inspect}"
@@ -1,162 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Example 8: LLM Configuration via MywayConfig
5
- #
6
- # Demonstrates how RobotLab uses MywayConfig for environment-specific
7
- # configuration (similar to Rails database.yml).
8
- #
9
- # Configuration is loaded from multiple sources in priority order:
10
- # 1. Bundled defaults (lib/robot_lab/config/defaults.yml)
11
- # 2. Environment-specific overrides (development, test, production)
12
- # 3. XDG user config (~/.config/robot_lab/config.yml)
13
- # 4. Project config (./config/robot_lab.yml)
14
- # 5. Environment variables (ROBOT_LAB_*)
15
- # 6. Template front matter (model, temperature, etc. in .md YAML header)
16
- # 7. Constructor parameters (model:, temperature:, etc. passed to Robot.new)
17
- # 8. with_* methods (runtime chaining, e.g. robot.with_temperature(0.9))
18
- # 9. Run-time context (kwargs passed to robot.run that re-render the template)
19
- #
20
- # Environment is determined by ROBOT_LAB_ENV, RAILS_ENV, or RACK_ENV.
21
- #
22
- # Environment variable examples:
23
- # ROBOT_LAB_RUBY_LLM__MODEL=qwen3.6:latest
24
- # ROBOT_LAB_RUBY_LLM__REQUEST_TIMEOUT=180
25
- # OLLAMA_API_BASE=http://localhost:11434/v1
26
- #
27
- # Usage:
28
- # ruby examples/08_llm_config.rb
29
- # ROBOT_LAB_ENV=test ruby examples/08_llm_config.rb
30
- # ROBOT_LAB_ENV=production ruby examples/08_llm_config.rb
31
-
32
- require_relative "common"
33
-
34
- # =============================================================================
35
- # Demonstration
36
- # =============================================================================
37
-
38
- banner "LLM Configuration via MywayConfig"
39
-
40
- # --- Gather environment from the user via AskUser ---
41
- ask = RobotLab::AskUser.new
42
- env = ask.call(
43
- "question" => "Which environment should the demo run in?",
44
- "choices" => %w[development test production],
45
- "default" => ENV['ROBOT_LAB_ENV'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || "development"
46
- )
47
- puts
48
-
49
- # Display configuration values (hiding sensitive keys)
50
- config = RobotLab.config
51
-
52
- puts "Core Settings:"
53
- puts " max_iterations: #{config.max_iterations}"
54
- puts " streaming_enabled: #{config.streaming_enabled}"
55
- puts " template_path: #{config.template_path || '(default)'}"
56
- puts
57
-
58
- puts "RubyLLM Settings:"
59
- puts " model: #{config.ruby_llm.model}"
60
- puts " provider: #{config.ruby_llm.provider}"
61
- puts " request_timeout: #{config.ruby_llm.request_timeout}s"
62
- puts " max_retries: #{config.ruby_llm.max_retries}"
63
- puts " log_level: #{config.ruby_llm.log_level}"
64
-
65
- # Show where the LLM traffic actually goes
66
- puts " ollama_api_base: #{OLLAMA_API_BASE}"
67
- puts " (local inference — no API key in play)"
68
- puts
69
-
70
- section "Configuration Hierarchy (highest priority first)"
71
- puts
72
- puts " Per-Robot (override global settings for a specific robot):"
73
- puts " 11. Run-time context: kwargs to robot.run re-render template"
74
- puts " 10. with_* methods: robot.with_temperature(0.9).ask(...)"
75
- puts " 9. Constructor params: Robot.new(model: ..., temperature: ...)"
76
- puts " 8. Template front matter: model, temperature, etc. in .md YAML header"
77
- puts " 7. Robot RunConfig: config: passed to Robot constructor"
78
- puts
79
- puts " Network/Task (shared defaults for a group of robots):"
80
- puts " 6. Task RunConfig: config: passed to task() in network"
81
- puts " 5. Network RunConfig: config: passed to create_network()"
82
- puts
83
- puts " Global (apply to all robots unless overridden):"
84
- puts " 4. Environment variables: ROBOT_LAB_RUBY_LLM__MODEL, etc."
85
- puts " 3. Project config: ./config/robot_lab.yml"
86
- puts " 2. User config: ~/.config/robot_lab/config.yml"
87
- puts " 1. Bundled defaults: lib/robot_lab/config/defaults.yml + env overrides"
88
-
89
- section "RunConfig: Shared Operational Defaults"
90
-
91
- shared = RobotLab::RunConfig.new(model: LLM[:default].model, temperature: 0.5)
92
- puts " shared = RunConfig.new(model: #{LLM[:default].model.inspect}, temperature: 0.5)"
93
- puts " shared.to_h => #{shared.to_h.inspect}"
94
- puts
95
- puts " Note: RunConfig carries no `provider` field, so an Ollama model still"
96
- puts " needs provider: passed to each robot alongside the shared config."
97
- puts
98
-
99
- creative = RobotLab::RunConfig.new(temperature: 0.9)
100
- merged = shared.merge(creative)
101
- puts " creative = RunConfig.new(temperature: 0.9)"
102
- puts " merged = shared.merge(creative)"
103
- puts " merged.to_h => #{merged.to_h.inspect}"
104
- puts " (model inherited from shared, temperature overridden by creative)"
105
- puts
106
-
107
- # Create a robot using the configuration
108
- robot = RobotLab.build(
109
- **llm_opts,
110
- name: "config_demo",
111
- template: :llm_config_demo,
112
- local_tools: [RobotLab::AskUser],
113
- # These are TEMPLATE parameters, not robot kwargs — the template renders
114
- # them into its prompt text.
115
- context: {
116
- environment: env,
117
- model: LLM[:default].model,
118
- provider: LLM[:default].provider
119
- }
120
- )
121
-
122
- puts "Running robot with #{env} configuration..."
123
- puts "Model: #{robot.model}"
124
- puts
125
-
126
- # Run the robot
127
- result = robot.run(
128
- "Briefly explain how environment-specific LLM configuration works " \
129
- "and why it's useful."
130
- )
131
-
132
- # Display the result
133
- puts "Response:"
134
- result.output.each do |message|
135
- puts message.content if message.respond_to?(:content)
136
- end
137
-
138
- puts <<~FOOTER
139
-
140
- #{"=" * 70}
141
- Configuration demonstrated successfully!
142
-
143
- Configuration flows through three layers:
144
- Global (MywayConfig): YAML defaults, env overrides, XDG, env vars
145
- Network/Task (RunConfig): shared defaults for groups of robots
146
- Per-Robot: RunConfig, template front matter, constructor params, with_*
147
-
148
- RunConfig lets you express shared defaults that flow through the hierarchy:
149
- shared = RobotLab::RunConfig.new(model: #{LLM[:default].model.inspect}, temperature: 0.5)
150
- network = RobotLab.create_network(name: "team", config: shared) { ... }
151
- robot = RobotLab.build(name: "bot", config: shared, temperature: 0.9)
152
-
153
- Example environment variable overrides:
154
- ROBOT_LAB_RUBY_LLM__MODEL=#{LLM[:default].model}
155
- ROBOT_LAB_RUBY_LLM__REQUEST_TIMEOUT=180
156
- OLLAMA_API_BASE=http://localhost:11434/v1
157
-
158
- Try running with different environments:
159
- ROBOT_LAB_ENV=test ruby examples/08_llm_config.rb
160
- ROBOT_LAB_ENV=production ruby examples/08_llm_config.rb
161
- #{"=" * 70}
162
- FOOTER