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,410 +0,0 @@
1
- # Memory Management
2
-
3
- Memory in RobotLab is a reactive key-value store that provides persistent storage for runtime data, conversation history, and arbitrary user-defined values. A single unified `Memory` class serves both standalone robot usage and shared network execution.
4
-
5
- ## Memory Structure
6
-
7
- The `Memory` class holds:
8
-
9
- ```ruby
10
- memory = RobotLab.create_memory(data: { user_id: "123" })
11
-
12
- memory.data # StateProxy - custom key-value data with method-style access
13
- memory.results # Array<RobotResult> - execution history
14
- memory.messages # Array<Message> - conversation history
15
- memory.session_id # String - optional persistence identifier
16
- memory.cache # RubyLLM::SemanticCache - semantic caching module
17
- ```
18
-
19
- ## Standalone Robot Memory
20
-
21
- Every robot has its own inherent memory instance, accessible via `robot.memory`:
22
-
23
- ```ruby
24
- robot = RobotLab.build(
25
- name: "assistant",
26
- system_prompt: "You are helpful."
27
- )
28
-
29
- # Access the robot's memory
30
- robot.memory[:user_name] = "Alice"
31
- robot.memory[:user_name] #=> "Alice"
32
-
33
- # Run the robot
34
- result = robot.run("Hello!")
35
-
36
- # Memory persists between runs on the same robot instance
37
- robot.memory[:preference] = "dark_mode"
38
- result2 = robot.run("What are my preferences?")
39
-
40
- # Reset memory to initial state
41
- robot.reset_memory
42
- ```
43
-
44
- `reset_memory` resets only the key-value store. It does **not** touch the robot's chat history — that is `robot.clear_messages(keep_system: true)`. The two are independent.
45
-
46
- ## Network Shared Memory
47
-
48
- When robots execute within a network, they share the network's memory instead of using their own inherent memory. This enables inter-robot communication.
49
-
50
- ```ruby
51
- classifier = RobotLab.build(name: "classifier", system_prompt: "Classify requests.")
52
- handler = RobotLab.build(name: "handler", system_prompt: "Handle requests.")
53
-
54
- network = RobotLab.create_network(name: "support") do
55
- task :classifier, classifier, depends_on: :none
56
- task :handler, handler, depends_on: [:classifier]
57
- end
58
-
59
- # The network has its own shared memory
60
- network.memory[:customer_tier] = "premium"
61
-
62
- # All robots in the network read/write from network.memory during execution
63
- result = network.run(message: "I need help with billing")
64
-
65
- # Reset network memory between runs if needed
66
- network.reset_memory
67
- ```
68
-
69
- The memory resolution logic is:
70
-
71
- 1. If `network_memory` is provided at runtime, use that
72
- 2. If the robot is in a network, use the network's shared memory
73
- 3. Otherwise, use the robot's own inherent memory (`robot.memory`)
74
-
75
- ## Creating Memory
76
-
77
- ### Basic Creation
78
-
79
- ```ruby
80
- memory = RobotLab.create_memory
81
- ```
82
-
83
- ### With Initial Data
84
-
85
- ```ruby
86
- memory = RobotLab.create_memory(
87
- data: {
88
- user_id: "user_123",
89
- order_id: "ord_456",
90
- priority: "high"
91
- }
92
- )
93
- ```
94
-
95
- ### With Caching Disabled
96
-
97
- ```ruby
98
- memory = RobotLab.create_memory(data: {}, enable_cache: false)
99
- ```
100
-
101
- ## Reserved Keys
102
-
103
- Memory has five reserved keys with special behavior and dedicated accessors:
104
-
105
- | Key | Type | Description |
106
- |-----|------|-------------|
107
- | `:data` | `StateProxy` | Runtime data with method-style access |
108
- | `:results` | `Array<RobotResult>` | Accumulated robot execution results |
109
- | `:messages` | `Array<Message>` | Conversation history |
110
- | `:session_id` | `String` | Conversation session identifier |
111
- | `:cache` | `RubyLLM::SemanticCache` | Semantic cache module (read-only after init) |
112
-
113
- Reserved keys are accessed through dedicated methods and are excluded from `memory.keys`:
114
-
115
- ```ruby
116
- memory.data[:category] = "billing"
117
- memory.data.category #=> "billing" (method-style via StateProxy)
118
-
119
- memory.results #=> []
120
- memory.session_id #=> nil
121
- memory.cache #=> RubyLLM::SemanticCache (the module itself), or nil when enable_cache: false
122
- ```
123
-
124
- ## StateProxy
125
-
126
- The `data` attribute is a `StateProxy` that provides convenient hash-style and method-style access:
127
-
128
- ```ruby
129
- memory.data[:user_id] # Hash-style access
130
- memory.data[:user_id] = "456" # Assignment
131
-
132
- memory.data.user_id # Method-style access
133
- memory.data.user_id = "456" # Method-style assignment
134
-
135
- memory.data.key?(:user_id) # Check existence
136
- memory.data.keys # Get all keys
137
- memory.data.to_h # Convert to plain hash
138
- ```
139
-
140
- ## Reactive Features
141
-
142
- Memory supports pub/sub semantics where robots can subscribe to key changes and optionally block until values become available.
143
-
144
- ### Setting Values
145
-
146
- Use `memory.set(key, value)` to write a value, wake any waiters, and notify subscribers. Subscriber callbacks are dispatched through `Async { }`: inside a running reactor they run as fibers, but **outside** one they run synchronously on the writer's thread.
147
-
148
- ```ruby
149
- memory.set(:sentiment, { score: 0.8, confidence: 0.95 })
150
- ```
151
-
152
- The `[]=` operator also triggers reactive notifications for non-reserved keys:
153
-
154
- ```ruby
155
- memory[:sentiment] = { score: 0.8 } # Equivalent to memory.set(:sentiment, ...)
156
- ```
157
-
158
- ### Blocking Reads
159
-
160
- Use `memory.get(key, wait:)` to block until a value becomes available. This is useful for concurrent pipeline execution where one robot needs to wait for another's output:
161
-
162
- ```ruby
163
- # Immediate read (returns nil if missing)
164
- memory.get(:sentiment)
165
-
166
- # Block indefinitely until value exists
167
- memory.get(:sentiment, wait: true)
168
-
169
- # Block up to 30 seconds, then raise RobotLab::AwaitTimeout
170
- memory.get(:sentiment, wait: 30)
171
-
172
- # Wait for multiple keys at once
173
- results = memory.get(:sentiment, :entities, :keywords, wait: 60)
174
- #=> { sentiment: {...}, entities: [...], keywords: [...] }
175
- ```
176
-
177
- Two things to be careful with:
178
-
179
- - On expiry a blocking read **raises** `RobotLab::AwaitTimeout`; it does not return `nil`. Rescue it if a missing value is acceptable.
180
- - With multiple keys the timeout is applied **per missing key**, not to the call as a whole. `get_multiple` waits on the missing keys one at a time in order, so the call raises as soon as the *first* one expires — it does not spend the full 60 s on each. The 180 s worst case is only reached when the earlier keys arrive just before their own deadlines.
181
-
182
- ### Subscriptions
183
-
184
- Subscribe to key changes with async callbacks. The callback receives a `MemoryChange` object:
185
-
186
- ```ruby
187
- memory.subscribe(:raw_data) do |change|
188
- puts "#{change.key} changed from #{change.previous} to #{change.value}"
189
- puts "Written by: #{change.writer} at #{change.timestamp}"
190
- end
191
-
192
- # Subscribe to multiple keys
193
- memory.subscribe(:sentiment, :entities) do |change|
194
- update_dashboard(change.key, change.value)
195
- end
196
-
197
- # Pattern-based subscriptions (glob-style matching)
198
- memory.subscribe_pattern("analysis:*") do |change|
199
- puts "Analysis key #{change.key} updated"
200
- end
201
-
202
- # Unsubscribe
203
- sub_id = memory.subscribe(:status) { |c| puts c.value }
204
- memory.unsubscribe(sub_id)
205
-
206
- # Check if key has subscribers
207
- memory.subscribed?(:status) #=> true/false
208
- ```
209
-
210
- ### MemoryChange
211
-
212
- The `MemoryChange` object provides context about what changed:
213
-
214
- ```ruby
215
- change.key #=> :sentiment
216
- change.value #=> { score: 0.8 }
217
- change.previous #=> nil (or previous value)
218
- change.writer #=> "classifier" (robot name)
219
- change.network_name #=> "support_pipeline"
220
- change.timestamp #=> Time
221
- change.created? #=> true (new key, no previous value)
222
- change.updated? #=> false
223
- change.deleted? #=> false
224
- ```
225
-
226
- ## Memory Lifecycle
227
-
228
- ### Results
229
-
230
- Results track the history of robot executions:
231
-
232
- ```ruby
233
- # Append a result
234
- memory.append_result(robot_result)
235
-
236
- # Get all results (returns a copy)
237
- memory.results
238
-
239
- # Get results from a specific index (for incremental persistence)
240
- memory.results_from(5)
241
- ```
242
-
243
- Each `RobotResult` contains:
244
-
245
- ```ruby
246
- result.robot_name # Which robot produced this
247
- result.output # [TextMessage] synthesized from the final response text
248
- result.tool_calls # Array<ToolResultMessage> - effectively always empty (see Message Flow)
249
- result.stop_reason # always nil for a robot.run result (see Message Flow)
250
- result.last_text_content # Convenience: last text content string
251
- result.input_tokens # Prompt tokens for the run
252
- result.output_tokens # Completion tokens for the run
253
- result.created_at # When it was created
254
- ```
255
-
256
- ### Format History
257
-
258
- The `format_history` method prepares messages for LLM consumption:
259
-
260
- ```ruby
261
- formatted = memory.format_history
262
- # Returns combined messages + formatted results
263
- ```
264
-
265
- ### Merge
266
-
267
- Merge additional values into memory:
268
-
269
- ```ruby
270
- memory.merge!(user_id: 123, category: "billing")
271
- ```
272
-
273
- ### Key Management
274
-
275
- ```ruby
276
- memory.key?(:user_id) # Check existence
277
- memory.keys # Get all non-reserved keys
278
- memory.all_keys # Get all keys including reserved
279
- memory.delete(:temp_data) # Delete a specific key
280
- memory.clear # Clear all non-reserved keys
281
- memory.reset # Reset to initial state (preserves cache)
282
- ```
283
-
284
- ## Cloning
285
-
286
- Create independent copies of memory for isolated execution. Subscriptions are not cloned:
287
-
288
- ```ruby
289
- original = RobotLab.create_memory(data: { count: 1 })
290
- cloned = original.clone
291
-
292
- cloned[:count] = 2
293
- original[:count] #=> still 1
294
- ```
295
-
296
- ## Serialization
297
-
298
- Convert memory to and from hash for persistence:
299
-
300
- ```ruby
301
- # To hash
302
- hash = memory.to_h
303
- #=> {
304
- # data: { ... },
305
- # results: [...],
306
- # messages: [...],
307
- # session_id: "abc123",
308
- # custom: { my_key: "value" }
309
- # }
310
-
311
- # To JSON
312
- json = memory.to_json
313
-
314
- # From hash
315
- memory = Memory.from_hash(hash)
316
- ```
317
-
318
- `to_h` is compacted, so nil-valued reserved keys (a missing `session_id`, for instance) are omitted entirely rather than serialized as `nil`.
319
-
320
- ## Semantic Cache
321
-
322
- Memory includes a semantic cache via `RubyLLM::SemanticCache` that reduces costs and latency by returning cached responses for semantically equivalent queries:
323
-
324
- ```ruby
325
- # Using the cache with fetch
326
- response = memory.cache.fetch("What is Ruby?") do
327
- RubyLLM.chat.ask("What is Ruby?")
328
- end
329
-
330
- # Wrapping a chat instance
331
- chat = memory.cache.wrap(RubyLLM.chat(model: "gpt-4o"))
332
- chat.ask("What is Ruby?") # Cached on semantic similarity
333
- ```
334
-
335
- Caching can be disabled per-memory or per-robot:
336
-
337
- ```ruby
338
- memory = RobotLab.create_memory(enable_cache: false)
339
- robot = RobotLab.build(name: "bot", system_prompt: "...", enable_cache: false)
340
- ```
341
-
342
- ## Backend Options
343
-
344
- Memory defaults to a Hash-based backend but can use Redis for distributed scenarios:
345
-
346
- ```ruby
347
- # Try Redis, fall back to Hash
348
- memory = Memory.new(backend: :auto)
349
-
350
- # Hash backend — the only value that is honoured literally
351
- memory = Memory.new(backend: :hash)
352
-
353
- # Same behaviour as :auto — try Redis, fall back to Hash
354
- memory = Memory.new(backend: :redis)
355
-
356
- # Check what you actually got
357
- memory.redis? #=> true/false
358
- ```
359
-
360
- !!! note "`backend: :redis` does not force Redis"
361
- `select_backend` special-cases only `:hash`; every other value (`:redis`,
362
- `:auto`, anything else) takes the same branch —
363
- `create_redis_backend || create_hash_backend`. `create_redis_backend`
364
- returns `nil` when `redis` is unavailable and rescues `StandardError` to
365
- `nil` on a connection failure, so an unreachable Redis silently downgrades
366
- to a Hash with no exception and no warning. Always check `memory.redis?` if
367
- the distinction matters.
368
-
369
- Redis is configured via `RobotLab.config.redis` or the `REDIS_URL` environment variable.
370
-
371
- ## Best Practices
372
-
373
- ### 1. Use Memory for Cross-Robot Data
374
-
375
- ```ruby
376
- # In a network, robots share memory automatically.
377
- # Robot A writes:
378
- memory.set(:classification, "billing")
379
-
380
- # Robot B reads:
381
- category = memory.get(:classification)
382
- ```
383
-
384
- ### 2. Use Blocking Reads for Concurrent Pipelines
385
-
386
- ```ruby
387
- # When robots run in parallel, use blocking reads
388
- # to synchronize on shared data:
389
- results = memory.get(:sentiment, :entities, wait: 60)
390
- ```
391
-
392
- ### 3. Keep Data Minimal
393
-
394
- ```ruby
395
- # Store references instead of large objects
396
- memory[:response_id] = response.id # Preferred
397
- # memory[:huge_response] = api_response # Avoid
398
- ```
399
-
400
- ### 4. Reset Between Independent Runs
401
-
402
- ```ruby
403
- network.reset_memory
404
- result = network.run(message: "New conversation")
405
- ```
406
-
407
- ## Next Steps
408
-
409
- - [Network Orchestration](network-orchestration.md) - How networks share memory
410
- - [Message Flow](message-flow.md) - How messages are processed
@@ -1,56 +0,0 @@
1
- /* Custom styles for RobotLab documentation */
2
-
3
- /* Robot-themed accent colors */
4
- :root {
5
- --md-primary-fg-color: #673ab7;
6
- --md-primary-fg-color--light: #9575cd;
7
- --md-primary-fg-color--dark: #512da8;
8
- --md-accent-fg-color: #ffc107;
9
- }
10
-
11
- /* Code block styling */
12
- .md-typeset code {
13
- background-color: rgba(103, 58, 183, 0.1);
14
- }
15
-
16
- /* Admonition customization */
17
- .md-typeset .admonition.robot,
18
- .md-typeset details.robot {
19
- border-color: #673ab7;
20
- }
21
-
22
- .md-typeset .robot > .admonition-title,
23
- .md-typeset .robot > summary {
24
- background-color: rgba(103, 58, 183, 0.1);
25
- }
26
-
27
- .md-typeset .robot > .admonition-title::before,
28
- .md-typeset .robot > summary::before {
29
- background-color: #673ab7;
30
- -webkit-mask-image: var(--md-admonition-icon--robot);
31
- mask-image: var(--md-admonition-icon--robot);
32
- }
33
-
34
- /* Grid cards spacing */
35
- .md-typeset .grid.cards > ul > li {
36
- margin-bottom: 1em;
37
- }
38
-
39
- /* API reference table styling */
40
- .md-typeset table:not([class]) th {
41
- background-color: rgba(103, 58, 183, 0.1);
42
- }
43
-
44
- /* Mermaid diagram styling */
45
- .mermaid {
46
- background: transparent !important;
47
- }
48
-
49
- /* Dark mode adjustments */
50
- [data-md-color-scheme="slate"] {
51
- --md-code-bg-color: #1e1e2e;
52
- }
53
-
54
- [data-md-color-scheme="slate"] .md-typeset code {
55
- background-color: rgba(149, 117, 205, 0.2);
56
- }
Binary file