robot_lab 0.3.0 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +1 -1
- data/lib/robot_lab/mcp/transports/streamable_http.rb +1 -1
- data/lib/robot_lab/version.rb +1 -1
- metadata +3 -253
- data/.architecture/AGENTS.md +0 -32
- data/.architecture/config.yml +0 -8
- data/.architecture/members.yml +0 -60
- data/.architecture/reviews/feature-free-will.md +0 -490
- data/.architecture/reviews/overall-codebase.md +0 -427
- data/.claude/settings.local.json +0 -57
- data/.codex/config.toml +0 -2
- data/.envrc +0 -6
- data/.github/workflows/deploy-github-pages.yml +0 -52
- data/.irbrc +0 -6
- data/.loki +0 -65
- data/.quality/reek_baseline.txt +0 -43
- data/.rubocop.yml +0 -10
- data/Archspec.rb +0 -44
- data/CLAUDE.md +0 -141
- data/COMMITS.md +0 -196
- data/Rakefile +0 -193
- data/_typos.toml +0 -21
- data/agent2agent_review.md +0 -192
- data/agentf_improvements.md +0 -253
- data/agents.md +0 -14
- data/docs/api/core/index.md +0 -147
- data/docs/api/core/memory.md +0 -578
- data/docs/api/core/network.md +0 -553
- data/docs/api/core/result.md +0 -211
- data/docs/api/core/robot.md +0 -1667
- data/docs/api/core/state.md +0 -145
- data/docs/api/core/tool.md +0 -520
- data/docs/api/errors.md +0 -323
- data/docs/api/hooks.md +0 -469
- data/docs/api/index.md +0 -137
- data/docs/api/mcp/client.md +0 -387
- data/docs/api/mcp/index.md +0 -267
- data/docs/api/mcp/server.md +0 -252
- data/docs/api/mcp/transports.md +0 -339
- data/docs/api/messages/index.md +0 -126
- data/docs/api/messages/text-message.md +0 -170
- data/docs/api/messages/tool-call-message.md +0 -206
- data/docs/api/messages/tool-result-message.md +0 -242
- data/docs/api/messages/user-message.md +0 -232
- data/docs/api/skills.md +0 -423
- data/docs/api/streaming/context.md +0 -280
- data/docs/api/streaming/events.md +0 -185
- data/docs/api/streaming/index.md +0 -156
- data/docs/api/support.md +0 -846
- data/docs/architecture/core-concepts.md +0 -575
- data/docs/architecture/index.md +0 -252
- data/docs/architecture/message-flow.md +0 -366
- data/docs/architecture/network-orchestration.md +0 -478
- data/docs/architecture/robot-execution.md +0 -396
- data/docs/architecture/state-management.md +0 -410
- data/docs/assets/css/custom.css +0 -56
- data/docs/assets/images/robot_lab.jpg +0 -0
- data/docs/concepts.md +0 -641
- data/docs/examples/basic-chat.md +0 -258
- data/docs/examples/index.md +0 -425
- data/docs/examples/mcp-server.md +0 -403
- data/docs/examples/multi-robot-network.md +0 -476
- data/docs/examples/tool-usage.md +0 -468
- data/docs/getting-started/configuration.md +0 -645
- data/docs/getting-started/index.md +0 -56
- data/docs/getting-started/installation.md +0 -197
- data/docs/getting-started/quick-start.md +0 -293
- data/docs/guides/building-robots.md +0 -1187
- data/docs/guides/creating-networks.md +0 -736
- data/docs/guides/hooks.md +0 -1206
- data/docs/guides/index.md +0 -78
- data/docs/guides/knowledge.md +0 -219
- data/docs/guides/mcp-integration.md +0 -740
- data/docs/guides/memory.md +0 -458
- data/docs/guides/observability.md +0 -733
- data/docs/guides/streaming.md +0 -323
- data/docs/guides/using-tools.md +0 -780
- data/docs/index.md +0 -280
- data/docs/superpowers/plans/2026-05-06-agentskills.md +0 -1303
- data/docs/superpowers/specs/2026-05-06-agentskills-design.md +0 -247
- data/examples/.envrc +0 -3
- data/examples/01_simple_robot.rb +0 -31
- data/examples/02_tools.rb +0 -109
- data/examples/03_network.rb +0 -118
- data/examples/04_mcp.rb +0 -217
- data/examples/05_streaming.rb +0 -137
- data/examples/06_prompt_templates.rb +0 -325
- data/examples/07_network_memory.rb +0 -313
- data/examples/08_llm_config.rb +0 -162
- data/examples/09_chaining.rb +0 -251
- data/examples/10_memory.rb +0 -315
- data/examples/11_network_introspection.rb +0 -239
- data/examples/12_message_bus.rb +0 -67
- data/examples/13_spawn.rb +0 -85
- data/examples/14_rusty_circuit/.envrc +0 -1
- data/examples/14_rusty_circuit/.gitignore +0 -1
- data/examples/14_rusty_circuit/README.md +0 -1
- data/examples/14_rusty_circuit/comic.rb +0 -149
- data/examples/14_rusty_circuit/display.rb +0 -217
- data/examples/14_rusty_circuit/heckler.rb +0 -65
- data/examples/14_rusty_circuit/open_mic.rb +0 -132
- data/examples/14_rusty_circuit/prompts/open_mic_comic.md +0 -20
- data/examples/14_rusty_circuit/prompts/open_mic_heckler.md +0 -23
- data/examples/14_rusty_circuit/prompts/open_mic_scout.md +0 -20
- data/examples/14_rusty_circuit/scout.rb +0 -165
- data/examples/14_rusty_circuit/show.log +0 -234
- data/examples/15_memory_network_and_bus/.envrc +0 -1
- data/examples/15_memory_network_and_bus/README.md +0 -66
- data/examples/15_memory_network_and_bus/editor_in_chief.rb +0 -24
- data/examples/15_memory_network_and_bus/editorial_pipeline.rb +0 -213
- data/examples/15_memory_network_and_bus/linux_writer.rb +0 -80
- data/examples/15_memory_network_and_bus/os_editor.rb +0 -48
- data/examples/15_memory_network_and_bus/os_writer.rb +0 -49
- data/examples/15_memory_network_and_bus/output/combined_article.md +0 -11
- data/examples/15_memory_network_and_bus/output/final_article.md +0 -8
- data/examples/15_memory_network_and_bus/output/linux_draft.md +0 -7
- data/examples/15_memory_network_and_bus/output/mac_draft.md +0 -7
- data/examples/15_memory_network_and_bus/output/memory.json +0 -13
- data/examples/15_memory_network_and_bus/output/revision_1.md +0 -29
- data/examples/15_memory_network_and_bus/output/revision_2.md +0 -50
- data/examples/15_memory_network_and_bus/output/revision_3.md +0 -8
- data/examples/15_memory_network_and_bus/output/windows_draft.md +0 -7
- data/examples/15_memory_network_and_bus/prompts/os_advocate.md +0 -13
- data/examples/15_memory_network_and_bus/prompts/os_chief.md +0 -13
- data/examples/15_memory_network_and_bus/prompts/os_editor.md +0 -13
- data/examples/16_writers_room/.envrc +0 -1
- data/examples/16_writers_room/display.rb +0 -158
- data/examples/16_writers_room/output/.gitignore +0 -4
- data/examples/16_writers_room/output/README.md +0 -69
- data/examples/16_writers_room/output/opus_001.md +0 -263
- data/examples/16_writers_room/output/opus_001_notes.log +0 -470
- data/examples/16_writers_room/output/opus_002.md +0 -245
- data/examples/16_writers_room/output/opus_002_notes.log +0 -546
- data/examples/16_writers_room/output/opus_002_screenplay.md +0 -7989
- data/examples/16_writers_room/output/opus_002_screenplay_notes.md +0 -993
- data/examples/16_writers_room/prompts/screenplay_writer.md +0 -66
- data/examples/16_writers_room/prompts/writer.md +0 -37
- data/examples/16_writers_room/room.rb +0 -186
- data/examples/16_writers_room/tools.rb +0 -173
- data/examples/16_writers_room/writer.rb +0 -121
- data/examples/16_writers_room/writers_room.rb +0 -256
- data/examples/17_skills.rb +0 -234
- data/examples/18_rails/.envrc +0 -3
- data/examples/18_rails/.gitignore +0 -5
- data/examples/18_rails/Gemfile +0 -11
- data/examples/18_rails/README.md +0 -67
- data/examples/18_rails/Rakefile +0 -4
- data/examples/18_rails/app/controllers/application_controller.rb +0 -4
- data/examples/18_rails/app/controllers/chat_controller.rb +0 -50
- data/examples/18_rails/app/jobs/application_job.rb +0 -4
- data/examples/18_rails/app/jobs/robot_run_job.rb +0 -25
- data/examples/18_rails/app/models/application_record.rb +0 -5
- data/examples/18_rails/app/models/robot_lab_result.rb +0 -36
- data/examples/18_rails/app/models/robot_lab_thread.rb +0 -23
- data/examples/18_rails/app/robots/chat_robot.rb +0 -25
- data/examples/18_rails/app/tools/time_tool.rb +0 -9
- data/examples/18_rails/app/views/chat/_user_message.html.erb +0 -1
- data/examples/18_rails/app/views/chat/index.html.erb +0 -67
- data/examples/18_rails/app/views/layouts/application.html.erb +0 -49
- data/examples/18_rails/bin/dev +0 -7
- data/examples/18_rails/bin/rails +0 -6
- data/examples/18_rails/bin/setup +0 -15
- data/examples/18_rails/config/application.rb +0 -33
- data/examples/18_rails/config/cable.yml +0 -2
- data/examples/18_rails/config/database.yml +0 -5
- data/examples/18_rails/config/environment.rb +0 -4
- data/examples/18_rails/config/initializers/robot_lab.rb +0 -11
- data/examples/18_rails/config/routes.rb +0 -6
- data/examples/18_rails/config.ru +0 -4
- data/examples/18_rails/db/migrate/001_create_robot_lab_tables.rb +0 -32
- data/examples/19_token_tracking.rb +0 -138
- data/examples/20_circuit_breaker.rb +0 -147
- data/examples/21_learning_loop.rb +0 -181
- data/examples/22_context_compression.rb +0 -172
- data/examples/23_convergence.rb +0 -133
- data/examples/24_structured_delegation.rb +0 -151
- data/examples/25_history_search/conversation.jsonl +0 -30
- data/examples/25_history_search.rb +0 -133
- data/examples/26_document_store/api_versioning_adr.md +0 -52
- data/examples/26_document_store/incident_postmortem.md +0 -46
- data/examples/26_document_store/postgres_runbook.md +0 -49
- data/examples/26_document_store/redis_caching_guide.md +0 -48
- data/examples/26_document_store/sidekiq_guide.md +0 -51
- data/examples/26_document_store.rb +0 -140
- data/examples/27_incident_response/README.md +0 -65
- data/examples/27_incident_response/incident_response.rb +0 -261
- data/examples/28_mcp_discovery.rb +0 -113
- data/examples/29_ractor_tools.rb +0 -240
- data/examples/30_ractor_network.rb +0 -252
- data/examples/31_launch_assessment.rb +0 -246
- data/examples/32_newsletter_reader.rb +0 -193
- data/examples/33_stock_generator.rb +0 -80
- data/examples/33_stock_predictor.rb +0 -327
- data/examples/34_agentskills.rb +0 -76
- data/examples/35_hooks.rb +0 -266
- data/examples/README.md +0 -550
- data/examples/common.rb +0 -180
- data/examples/prompts/assistant.md +0 -5
- data/examples/prompts/audit_trail.md +0 -8
- data/examples/prompts/billing.md +0 -10
- data/examples/prompts/classifier.md +0 -7
- data/examples/prompts/comedian.md +0 -6
- data/examples/prompts/comedy_critic.md +0 -10
- data/examples/prompts/configurable.md +0 -9
- data/examples/prompts/dispatcher.md +0 -12
- data/examples/prompts/entity_extractor.md +0 -14
- data/examples/prompts/escalation.md +0 -42
- data/examples/prompts/frontmatter_mcp_test.md +0 -9
- data/examples/prompts/frontmatter_named_test.md +0 -5
- data/examples/prompts/frontmatter_tools_test.md +0 -6
- data/examples/prompts/general.md +0 -7
- data/examples/prompts/github_assistant.md +0 -14
- data/examples/prompts/helper.md +0 -4
- data/examples/prompts/incident_responder.md +0 -18
- data/examples/prompts/keyword_extractor.md +0 -11
- data/examples/prompts/llm_config_demo.md +0 -20
- data/examples/prompts/order_support.md +0 -35
- data/examples/prompts/os_advocate.md +0 -13
- data/examples/prompts/os_chief.md +0 -13
- data/examples/prompts/os_editor.md +0 -13
- data/examples/prompts/parameterized_main_test.md +0 -6
- data/examples/prompts/pii_redactor.md +0 -7
- data/examples/prompts/product_support.md +0 -37
- data/examples/prompts/runbook_protocol.md +0 -12
- data/examples/prompts/sentiment_analyzer.md +0 -12
- data/examples/prompts/skill_a_test.md +0 -4
- data/examples/prompts/skill_b_test.md +0 -4
- data/examples/prompts/skill_config_test.md +0 -5
- data/examples/prompts/skill_cycle_a_test.md +0 -6
- data/examples/prompts/skill_cycle_b_test.md +0 -6
- data/examples/prompts/skill_description_test.md +0 -4
- data/examples/prompts/skill_leaf_test.md +0 -4
- data/examples/prompts/skill_nested_test.md +0 -6
- data/examples/prompts/skill_refs_main_test.md +0 -6
- data/examples/prompts/skill_self_ref_test.md +0 -6
- data/examples/prompts/skill_with_mcp_test.md +0 -9
- data/examples/prompts/skill_with_params_test.md +0 -6
- data/examples/prompts/skill_with_robot_name_test.md +0 -5
- data/examples/prompts/skill_with_tools_test.md +0 -6
- data/examples/prompts/sre_compliance.md +0 -10
- data/examples/prompts/structured_output.md +0 -7
- data/examples/prompts/synthesizer.md +0 -17
- data/examples/prompts/technical.md +0 -10
- data/examples/prompts/template_with_skills_test.md +0 -6
- data/examples/prompts/triage.md +0 -22
- data/examples/ruboruby.md +0 -423
- data/examples/run_all.rb +0 -60
- data/examples/xyzzy.rb +0 -97
- data/logfile +0 -8
- data/mkdocs.yml +0 -209
- data/robot_concurrency.md +0 -38
- data/simple_acp_review.md +0 -298
- data/temp.md +0 -6
- 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 when the optional gem is installed, else nil
|
|
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` or `nil` | Semantic cache module when the optional ruby_llm-semantic_cache gem is installed (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 or the optional gem is absent
|
|
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` (optional ruby_llm-semantic_cache gem; not yet ruby_llm 2.0-compatible, so `memory.cache` is `nil` without it) 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
|
data/docs/assets/css/custom.css
DELETED
|
@@ -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
|