robot_lab 0.0.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 (153) hide show
  1. checksums.yaml +7 -0
  2. data/.envrc +1 -0
  3. data/.github/workflows/deploy-github-pages.yml +52 -0
  4. data/.github/workflows/deploy-yard-docs.yml +52 -0
  5. data/CHANGELOG.md +55 -0
  6. data/COMMITS.md +196 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +332 -0
  9. data/Rakefile +67 -0
  10. data/docs/api/adapters/anthropic.md +121 -0
  11. data/docs/api/adapters/gemini.md +133 -0
  12. data/docs/api/adapters/index.md +104 -0
  13. data/docs/api/adapters/openai.md +134 -0
  14. data/docs/api/core/index.md +113 -0
  15. data/docs/api/core/memory.md +314 -0
  16. data/docs/api/core/network.md +291 -0
  17. data/docs/api/core/robot.md +273 -0
  18. data/docs/api/core/state.md +273 -0
  19. data/docs/api/core/tool.md +353 -0
  20. data/docs/api/history/active-record-adapter.md +195 -0
  21. data/docs/api/history/config.md +191 -0
  22. data/docs/api/history/index.md +132 -0
  23. data/docs/api/history/thread-manager.md +144 -0
  24. data/docs/api/index.md +82 -0
  25. data/docs/api/mcp/client.md +221 -0
  26. data/docs/api/mcp/index.md +111 -0
  27. data/docs/api/mcp/server.md +225 -0
  28. data/docs/api/mcp/transports.md +264 -0
  29. data/docs/api/messages/index.md +67 -0
  30. data/docs/api/messages/text-message.md +102 -0
  31. data/docs/api/messages/tool-call-message.md +144 -0
  32. data/docs/api/messages/tool-result-message.md +154 -0
  33. data/docs/api/messages/user-message.md +171 -0
  34. data/docs/api/streaming/context.md +174 -0
  35. data/docs/api/streaming/events.md +237 -0
  36. data/docs/api/streaming/index.md +108 -0
  37. data/docs/architecture/core-concepts.md +243 -0
  38. data/docs/architecture/index.md +138 -0
  39. data/docs/architecture/message-flow.md +320 -0
  40. data/docs/architecture/network-orchestration.md +216 -0
  41. data/docs/architecture/robot-execution.md +243 -0
  42. data/docs/architecture/state-management.md +323 -0
  43. data/docs/assets/css/custom.css +56 -0
  44. data/docs/assets/images/robot_lab.jpg +0 -0
  45. data/docs/concepts.md +216 -0
  46. data/docs/examples/basic-chat.md +193 -0
  47. data/docs/examples/index.md +129 -0
  48. data/docs/examples/mcp-server.md +290 -0
  49. data/docs/examples/multi-robot-network.md +312 -0
  50. data/docs/examples/rails-application.md +420 -0
  51. data/docs/examples/tool-usage.md +310 -0
  52. data/docs/getting-started/configuration.md +230 -0
  53. data/docs/getting-started/index.md +56 -0
  54. data/docs/getting-started/installation.md +179 -0
  55. data/docs/getting-started/quick-start.md +203 -0
  56. data/docs/guides/building-robots.md +376 -0
  57. data/docs/guides/creating-networks.md +366 -0
  58. data/docs/guides/history.md +359 -0
  59. data/docs/guides/index.md +68 -0
  60. data/docs/guides/mcp-integration.md +356 -0
  61. data/docs/guides/memory.md +309 -0
  62. data/docs/guides/rails-integration.md +432 -0
  63. data/docs/guides/streaming.md +314 -0
  64. data/docs/guides/using-tools.md +394 -0
  65. data/docs/index.md +160 -0
  66. data/examples/01_simple_robot.rb +38 -0
  67. data/examples/02_tools.rb +106 -0
  68. data/examples/03_network.rb +103 -0
  69. data/examples/04_mcp.rb +219 -0
  70. data/examples/05_streaming.rb +124 -0
  71. data/examples/06_prompt_templates.rb +324 -0
  72. data/examples/07_network_memory.rb +329 -0
  73. data/examples/prompts/assistant/system.txt.erb +2 -0
  74. data/examples/prompts/assistant/user.txt.erb +1 -0
  75. data/examples/prompts/billing/system.txt.erb +7 -0
  76. data/examples/prompts/billing/user.txt.erb +1 -0
  77. data/examples/prompts/classifier/system.txt.erb +4 -0
  78. data/examples/prompts/classifier/user.txt.erb +1 -0
  79. data/examples/prompts/entity_extractor/system.txt.erb +11 -0
  80. data/examples/prompts/entity_extractor/user.txt.erb +3 -0
  81. data/examples/prompts/escalation/system.txt.erb +35 -0
  82. data/examples/prompts/escalation/user.txt.erb +34 -0
  83. data/examples/prompts/general/system.txt.erb +4 -0
  84. data/examples/prompts/general/user.txt.erb +1 -0
  85. data/examples/prompts/github_assistant/system.txt.erb +6 -0
  86. data/examples/prompts/github_assistant/user.txt.erb +1 -0
  87. data/examples/prompts/helper/system.txt.erb +1 -0
  88. data/examples/prompts/helper/user.txt.erb +1 -0
  89. data/examples/prompts/keyword_extractor/system.txt.erb +8 -0
  90. data/examples/prompts/keyword_extractor/user.txt.erb +3 -0
  91. data/examples/prompts/order_support/system.txt.erb +27 -0
  92. data/examples/prompts/order_support/user.txt.erb +22 -0
  93. data/examples/prompts/product_support/system.txt.erb +30 -0
  94. data/examples/prompts/product_support/user.txt.erb +32 -0
  95. data/examples/prompts/sentiment_analyzer/system.txt.erb +9 -0
  96. data/examples/prompts/sentiment_analyzer/user.txt.erb +3 -0
  97. data/examples/prompts/synthesizer/system.txt.erb +14 -0
  98. data/examples/prompts/synthesizer/user.txt.erb +15 -0
  99. data/examples/prompts/technical/system.txt.erb +7 -0
  100. data/examples/prompts/technical/user.txt.erb +1 -0
  101. data/examples/prompts/triage/system.txt.erb +16 -0
  102. data/examples/prompts/triage/user.txt.erb +17 -0
  103. data/lib/generators/robot_lab/install_generator.rb +78 -0
  104. data/lib/generators/robot_lab/robot_generator.rb +55 -0
  105. data/lib/generators/robot_lab/templates/initializer.rb.tt +41 -0
  106. data/lib/generators/robot_lab/templates/migration.rb.tt +32 -0
  107. data/lib/generators/robot_lab/templates/result_model.rb.tt +52 -0
  108. data/lib/generators/robot_lab/templates/robot.rb.tt +46 -0
  109. data/lib/generators/robot_lab/templates/robot_test.rb.tt +32 -0
  110. data/lib/generators/robot_lab/templates/routing_robot.rb.tt +53 -0
  111. data/lib/generators/robot_lab/templates/thread_model.rb.tt +40 -0
  112. data/lib/robot_lab/adapters/anthropic.rb +163 -0
  113. data/lib/robot_lab/adapters/base.rb +85 -0
  114. data/lib/robot_lab/adapters/gemini.rb +193 -0
  115. data/lib/robot_lab/adapters/openai.rb +159 -0
  116. data/lib/robot_lab/adapters/registry.rb +81 -0
  117. data/lib/robot_lab/configuration.rb +143 -0
  118. data/lib/robot_lab/error.rb +32 -0
  119. data/lib/robot_lab/errors.rb +70 -0
  120. data/lib/robot_lab/history/active_record_adapter.rb +146 -0
  121. data/lib/robot_lab/history/config.rb +115 -0
  122. data/lib/robot_lab/history/thread_manager.rb +93 -0
  123. data/lib/robot_lab/mcp/client.rb +210 -0
  124. data/lib/robot_lab/mcp/server.rb +84 -0
  125. data/lib/robot_lab/mcp/transports/base.rb +56 -0
  126. data/lib/robot_lab/mcp/transports/sse.rb +117 -0
  127. data/lib/robot_lab/mcp/transports/stdio.rb +133 -0
  128. data/lib/robot_lab/mcp/transports/streamable_http.rb +139 -0
  129. data/lib/robot_lab/mcp/transports/websocket.rb +108 -0
  130. data/lib/robot_lab/memory.rb +882 -0
  131. data/lib/robot_lab/memory_change.rb +123 -0
  132. data/lib/robot_lab/message.rb +357 -0
  133. data/lib/robot_lab/network.rb +350 -0
  134. data/lib/robot_lab/rails/engine.rb +29 -0
  135. data/lib/robot_lab/rails/railtie.rb +42 -0
  136. data/lib/robot_lab/robot.rb +560 -0
  137. data/lib/robot_lab/robot_result.rb +205 -0
  138. data/lib/robot_lab/robotic_model.rb +324 -0
  139. data/lib/robot_lab/state_proxy.rb +188 -0
  140. data/lib/robot_lab/streaming/context.rb +144 -0
  141. data/lib/robot_lab/streaming/events.rb +95 -0
  142. data/lib/robot_lab/streaming/sequence_counter.rb +48 -0
  143. data/lib/robot_lab/task.rb +117 -0
  144. data/lib/robot_lab/tool.rb +223 -0
  145. data/lib/robot_lab/tool_config.rb +112 -0
  146. data/lib/robot_lab/tool_manifest.rb +234 -0
  147. data/lib/robot_lab/user_message.rb +118 -0
  148. data/lib/robot_lab/version.rb +5 -0
  149. data/lib/robot_lab/waiter.rb +73 -0
  150. data/lib/robot_lab.rb +195 -0
  151. data/mkdocs.yml +214 -0
  152. data/sig/robot_lab.rbs +4 -0
  153. metadata +442 -0
@@ -0,0 +1,68 @@
1
+ # Guides
2
+
3
+ Practical guides for building applications with RobotLab.
4
+
5
+ ## Getting Started
6
+
7
+ If you're new to RobotLab, start here:
8
+
9
+ <div class="grid cards" markdown>
10
+
11
+ - [:octicons-cpu-24: **Building Robots**](building-robots.md)
12
+
13
+ Create specialized AI agents with personalities and tools
14
+
15
+ - [:octicons-git-branch-24: **Creating Networks**](creating-networks.md)
16
+
17
+ Orchestrate multiple robots for complex workflows
18
+
19
+ </div>
20
+
21
+ ## Core Features
22
+
23
+ <div class="grid cards" markdown>
24
+
25
+ - [:octicons-tools-24: **Using Tools**](using-tools.md)
26
+
27
+ Give robots custom capabilities to interact with external systems
28
+
29
+ - [:octicons-server-24: **MCP Integration**](mcp-integration.md)
30
+
31
+ Connect to Model Context Protocol servers
32
+
33
+ - [:octicons-broadcast-24: **Streaming Responses**](streaming.md)
34
+
35
+ Real-time streaming of LLM responses
36
+
37
+ - [:octicons-database-24: **Conversation History**](history.md)
38
+
39
+ Persist and restore conversation threads
40
+
41
+ - [:octicons-cpu-24: **Memory System**](memory.md)
42
+
43
+ Share data between robots with the memory system
44
+
45
+ </div>
46
+
47
+ ## Framework Integration
48
+
49
+ <div class="grid cards" markdown>
50
+
51
+ - [:material-language-ruby:{ .lg } **Rails Integration**](rails-integration.md)
52
+
53
+ Use RobotLab in Ruby on Rails applications
54
+
55
+ </div>
56
+
57
+ ## Guide Index
58
+
59
+ | Guide | Description | Time |
60
+ |-------|-------------|------|
61
+ | [Building Robots](building-robots.md) | Create and configure robots | 10 min |
62
+ | [Creating Networks](creating-networks.md) | Multi-robot orchestration | 15 min |
63
+ | [Using Tools](using-tools.md) | Add custom capabilities | 10 min |
64
+ | [MCP Integration](mcp-integration.md) | External tool servers | 10 min |
65
+ | [Streaming](streaming.md) | Real-time responses | 5 min |
66
+ | [History](history.md) | Conversation persistence | 10 min |
67
+ | [Memory](memory.md) | Shared data store | 5 min |
68
+ | [Rails Integration](rails-integration.md) | Rails application setup | 15 min |
@@ -0,0 +1,356 @@
1
+ # MCP Integration
2
+
3
+ RobotLab supports the Model Context Protocol (MCP) for connecting to external tool servers.
4
+
5
+ ## What is MCP?
6
+
7
+ MCP is a protocol that allows LLM applications to connect to external servers that provide tools, resources, and context. This enables:
8
+
9
+ - Reusable tool servers across applications
10
+ - Separation of tool logic from AI logic
11
+ - Dynamic tool discovery
12
+
13
+ ## Configuring MCP Servers
14
+
15
+ ### At Network Level
16
+
17
+ ```ruby
18
+ network = RobotLab.create_network do
19
+ name "dev_assistant"
20
+
21
+ mcp [
22
+ {
23
+ name: "filesystem",
24
+ transport: {
25
+ type: "stdio",
26
+ command: "mcp-server-filesystem",
27
+ args: ["--root", "/home/user/projects"]
28
+ }
29
+ },
30
+ {
31
+ name: "github",
32
+ transport: {
33
+ type: "stdio",
34
+ command: "mcp-server-github"
35
+ }
36
+ }
37
+ ]
38
+ end
39
+ ```
40
+
41
+ ### At Robot Level
42
+
43
+ ```ruby
44
+ robot = RobotLab.build do
45
+ name "coder"
46
+
47
+ # Use network's MCP servers
48
+ mcp :inherit
49
+
50
+ # Or specific servers
51
+ mcp [
52
+ { name: "filesystem", transport: { type: "stdio", command: "mcp-fs" } }
53
+ ]
54
+
55
+ # Or disable MCP
56
+ mcp :none
57
+ end
58
+ ```
59
+
60
+ ### Global Configuration
61
+
62
+ ```ruby
63
+ RobotLab.configure do |config|
64
+ config.mcp = [
65
+ { name: "common_tools", transport: { type: "stdio", command: "common-mcp" } }
66
+ ]
67
+ end
68
+ ```
69
+
70
+ ## Transport Types
71
+
72
+ ### Stdio Transport
73
+
74
+ Communicate via stdin/stdout with a subprocess:
75
+
76
+ ```ruby
77
+ {
78
+ name: "server_name",
79
+ transport: {
80
+ type: "stdio",
81
+ command: "mcp-server-command",
82
+ args: ["--option", "value"],
83
+ env: { "API_KEY" => ENV["API_KEY"] }
84
+ }
85
+ }
86
+ ```
87
+
88
+ ### WebSocket Transport
89
+
90
+ Connect via WebSocket:
91
+
92
+ ```ruby
93
+ {
94
+ name: "remote_server",
95
+ transport: {
96
+ type: "websocket",
97
+ url: "ws://localhost:8080/mcp"
98
+ }
99
+ }
100
+ ```
101
+
102
+ !!! note "Dependency Required"
103
+ WebSocket transport requires the `async-websocket` gem.
104
+
105
+ ### SSE Transport
106
+
107
+ Server-Sent Events transport:
108
+
109
+ ```ruby
110
+ {
111
+ name: "sse_server",
112
+ transport: {
113
+ type: "sse",
114
+ url: "http://localhost:8080/sse"
115
+ }
116
+ }
117
+ ```
118
+
119
+ ### HTTP Transport
120
+
121
+ Streamable HTTP transport with session support:
122
+
123
+ ```ruby
124
+ {
125
+ name: "http_server",
126
+ transport: {
127
+ type: "streamable_http",
128
+ url: "https://api.example.com/mcp",
129
+ session_id: "optional_session_id",
130
+ auth_provider: -> { "Bearer #{fetch_token}" }
131
+ }
132
+ }
133
+ ```
134
+
135
+ ## Using MCP Tools
136
+
137
+ Once configured, MCP tools are automatically available to robots:
138
+
139
+ ```ruby
140
+ network = RobotLab.create_network do
141
+ mcp [
142
+ { name: "github", transport: { type: "stdio", command: "mcp-server-github" } }
143
+ ]
144
+
145
+ add_robot RobotLab.build {
146
+ name "helper"
147
+ template <<~PROMPT
148
+ You can help users with GitHub tasks.
149
+ Use available tools to search repositories, create issues, etc.
150
+ PROMPT
151
+ }
152
+ end
153
+
154
+ # The robot can now use GitHub MCP tools
155
+ state = RobotLab.create_state(message: "Find repositories about machine learning")
156
+ network.run(state: state)
157
+ ```
158
+
159
+ ## Filtering MCP Tools
160
+
161
+ Restrict which MCP tools are available:
162
+
163
+ ```ruby
164
+ robot = RobotLab.build do
165
+ name "reader"
166
+ mcp :inherit
167
+
168
+ # Only allow specific MCP tools
169
+ tools %w[read_file search_code list_directory]
170
+ end
171
+ ```
172
+
173
+ ## MCP Server Configuration
174
+
175
+ ### Server Object
176
+
177
+ ```ruby
178
+ server = RobotLab::MCP::Server.new(
179
+ name: "my_server",
180
+ transport: {
181
+ type: "stdio",
182
+ command: "my-mcp-server"
183
+ }
184
+ )
185
+
186
+ server.name # => "my_server"
187
+ server.transport_type # => "stdio"
188
+ server.to_h # Hash representation
189
+ ```
190
+
191
+ ### Client Object
192
+
193
+ ```ruby
194
+ client = RobotLab::MCP::Client.new(server: server)
195
+ client.connect
196
+
197
+ client.connected? # => true
198
+ client.to_h # Client info
199
+ ```
200
+
201
+ ## Common MCP Servers
202
+
203
+ ### Filesystem
204
+
205
+ ```ruby
206
+ {
207
+ name: "filesystem",
208
+ transport: {
209
+ type: "stdio",
210
+ command: "mcp-server-filesystem",
211
+ args: ["--root", "/path/to/files"]
212
+ }
213
+ }
214
+ ```
215
+
216
+ Tools: `read_file`, `write_file`, `list_directory`, `search_files`
217
+
218
+ ### GitHub
219
+
220
+ ```ruby
221
+ {
222
+ name: "github",
223
+ transport: {
224
+ type: "stdio",
225
+ command: "mcp-server-github",
226
+ env: { "GITHUB_TOKEN" => ENV["GITHUB_TOKEN"] }
227
+ }
228
+ }
229
+ ```
230
+
231
+ Tools: `search_repositories`, `create_issue`, `get_file_contents`, etc.
232
+
233
+ ### Database
234
+
235
+ ```ruby
236
+ {
237
+ name: "postgres",
238
+ transport: {
239
+ type: "stdio",
240
+ command: "mcp-server-postgres",
241
+ env: { "DATABASE_URL" => ENV["DATABASE_URL"] }
242
+ }
243
+ }
244
+ ```
245
+
246
+ Tools: `query`, `list_tables`, `describe_table`
247
+
248
+ ## Error Handling
249
+
250
+ ### Connection Errors
251
+
252
+ ```ruby
253
+ begin
254
+ network.run(state: state)
255
+ rescue RobotLab::MCPError => e
256
+ puts "MCP Error: #{e.message}"
257
+ # Handle gracefully
258
+ end
259
+ ```
260
+
261
+ ### Missing Dependencies
262
+
263
+ ```ruby
264
+ # If async-websocket not installed
265
+ rescue RobotLab::MCPError => e
266
+ if e.message.include?("async-websocket")
267
+ puts "Install async-websocket gem for WebSocket support"
268
+ end
269
+ end
270
+ ```
271
+
272
+ ## Disconnecting
273
+
274
+ Robots automatically disconnect from MCP servers when done:
275
+
276
+ ```ruby
277
+ robot.disconnect # Manually disconnect
278
+ ```
279
+
280
+ Networks handle this automatically at the end of a run.
281
+
282
+ ## Patterns
283
+
284
+ ### Development vs Production
285
+
286
+ ```ruby
287
+ network = RobotLab.create_network do
288
+ mcp_config = if Rails.env.development?
289
+ [{ name: "local_fs", transport: { type: "stdio", command: "mcp-fs", args: ["--root", "."] } }]
290
+ else
291
+ [{ name: "s3", transport: { type: "stdio", command: "mcp-s3" } }]
292
+ end
293
+
294
+ mcp mcp_config
295
+ end
296
+ ```
297
+
298
+ ### Dynamic Server Selection
299
+
300
+ ```ruby
301
+ def mcp_servers_for_user(user)
302
+ servers = []
303
+ servers << github_server if user.github_connected?
304
+ servers << slack_server if user.slack_connected?
305
+ servers
306
+ end
307
+
308
+ network = RobotLab.create_network do
309
+ mcp mcp_servers_for_user(current_user)
310
+ end
311
+ ```
312
+
313
+ ## Best Practices
314
+
315
+ ### 1. Use Environment Variables for Credentials
316
+
317
+ ```ruby
318
+ {
319
+ name: "github",
320
+ transport: {
321
+ type: "stdio",
322
+ command: "mcp-server-github",
323
+ env: {
324
+ "GITHUB_TOKEN" => ENV["GITHUB_TOKEN"],
325
+ "GITHUB_ORG" => ENV["GITHUB_ORG"]
326
+ }
327
+ }
328
+ }
329
+ ```
330
+
331
+ ### 2. Limit Tool Access
332
+
333
+ ```ruby
334
+ # Don't expose all tools
335
+ robot = RobotLab.build do
336
+ mcp :inherit
337
+ tools %w[read_file search_files] # No write access
338
+ end
339
+ ```
340
+
341
+ ### 3. Handle Disconnections
342
+
343
+ ```ruby
344
+ begin
345
+ result = network.run(state: state)
346
+ rescue RobotLab::MCPError
347
+ # Retry without MCP
348
+ result = network.run(state: state, mcp: :none)
349
+ end
350
+ ```
351
+
352
+ ## Next Steps
353
+
354
+ - [Using Tools](using-tools.md) - Local tool patterns
355
+ - [Creating Networks](creating-networks.md) - Network configuration
356
+ - [API Reference: MCP](../api/mcp/index.md) - Complete MCP API
@@ -0,0 +1,309 @@
1
+ # Memory System
2
+
3
+ The memory system allows robots to share data within a network run.
4
+
5
+ ## Overview
6
+
7
+ Memory provides:
8
+
9
+ - Key-value storage accessible by all robots
10
+ - Namespaced scopes for organization
11
+ - Persistence within a single network run
12
+
13
+ ## Basic Usage
14
+
15
+ ### Store Values
16
+
17
+ ```ruby
18
+ state.memory.remember("user_name", "Alice")
19
+ state.memory.remember("preferences", { theme: "dark", language: "en" })
20
+ ```
21
+
22
+ ### Retrieve Values
23
+
24
+ ```ruby
25
+ name = state.memory.recall("user_name") # => "Alice"
26
+ prefs = state.memory.recall("preferences") # => { theme: "dark", ... }
27
+
28
+ # Returns nil if not found
29
+ missing = state.memory.recall("unknown") # => nil
30
+ ```
31
+
32
+ ### Check Existence
33
+
34
+ ```ruby
35
+ state.memory.exists?("user_name") # => true
36
+ state.memory.exists?("unknown") # => false
37
+ ```
38
+
39
+ ### Remove Values
40
+
41
+ ```ruby
42
+ state.memory.forget("user_name")
43
+ ```
44
+
45
+ ## Scoped Memory
46
+
47
+ Organize data with namespaces:
48
+
49
+ ```ruby
50
+ # Create a scoped view
51
+ user_memory = state.memory.scoped("user:123")
52
+
53
+ # Operations are scoped
54
+ user_memory.remember("name", "Alice")
55
+ user_memory.remember("email", "alice@example.com")
56
+
57
+ # Keys are prefixed
58
+ state.memory.recall("user:123:name") # => "Alice"
59
+
60
+ # Scoped recall
61
+ user_memory.recall("name") # => "Alice"
62
+ ```
63
+
64
+ ### Nested Scopes
65
+
66
+ ```ruby
67
+ session = state.memory.scoped("session:abc")
68
+ prefs = session.scoped("preferences")
69
+
70
+ prefs.remember("theme", "dark")
71
+ # Full key: "session:abc:preferences:theme"
72
+ ```
73
+
74
+ ## Memory Operations
75
+
76
+ ### List All Keys
77
+
78
+ ```ruby
79
+ state.memory.all
80
+ # => {
81
+ # "user_name" => "Alice",
82
+ # "user:123:email" => "alice@example.com",
83
+ # ...
84
+ # }
85
+ ```
86
+
87
+ ### List Namespaces
88
+
89
+ ```ruby
90
+ state.memory.namespaces
91
+ # => ["user:123", "session:abc", ...]
92
+ ```
93
+
94
+ ### Search by Pattern
95
+
96
+ ```ruby
97
+ # Find keys matching pattern
98
+ matches = state.memory.search("user:*")
99
+ # => { "user:123:name" => "Alice", "user:123:email" => "..." }
100
+ ```
101
+
102
+ ### Statistics
103
+
104
+ ```ruby
105
+ state.memory.stats
106
+ # => { total_keys: 15, namespaces: ["user:123", "session"] }
107
+ ```
108
+
109
+ ### Clear Memory
110
+
111
+ ```ruby
112
+ # Clear a namespace
113
+ state.memory.scoped("temp").clear
114
+
115
+ # Clear all memory
116
+ state.memory.clear_all
117
+ ```
118
+
119
+ ## Shared Namespace
120
+
121
+ The `SHARED` namespace is a convention for cross-robot data:
122
+
123
+ ```ruby
124
+ # In first robot
125
+ state.memory.remember("SHARED:context", important_data)
126
+
127
+ # In later robot
128
+ context = state.memory.recall("SHARED:context")
129
+ ```
130
+
131
+ ### Using Shared Scope
132
+
133
+ ```ruby
134
+ shared = state.memory.scoped(RobotLab::Memory::SHARED_NAMESPACE)
135
+ shared.remember("workflow_status", "in_progress")
136
+ ```
137
+
138
+ ## In Tool Handlers
139
+
140
+ Access memory from tools:
141
+
142
+ ```ruby
143
+ tool :update_preference do
144
+ description "Update user preference"
145
+ parameter :key, type: :string, required: true
146
+ parameter :value, type: :string, required: true
147
+
148
+ handler do |key:, value:, state:, **_|
149
+ prefs = state.memory.scoped("preferences")
150
+ prefs.remember(key, value)
151
+ { success: true, key: key, value: value }
152
+ end
153
+ end
154
+ ```
155
+
156
+ ## In Routers
157
+
158
+ Use memory for routing decisions:
159
+
160
+ ```ruby
161
+ router = ->(args) {
162
+ case args.call_count
163
+ when 0
164
+ :classifier
165
+ when 1
166
+ # Read classification from memory
167
+ intent = args.network.state.memory.recall("SHARED:intent")
168
+ case intent
169
+ when "billing" then :billing_agent
170
+ when "technical" then :tech_agent
171
+ else :general_agent
172
+ end
173
+ else
174
+ nil
175
+ end
176
+ }
177
+ ```
178
+
179
+ ## Patterns
180
+
181
+ ### Accumulating Data
182
+
183
+ ```ruby
184
+ # In each robot
185
+ def add_finding(state, finding)
186
+ findings = state.memory.recall("findings") || []
187
+ findings << finding
188
+ state.memory.remember("findings", findings)
189
+ end
190
+
191
+ # In final robot
192
+ all_findings = state.memory.recall("findings")
193
+ ```
194
+
195
+ ### Tracking Progress
196
+
197
+ ```ruby
198
+ # Track workflow stages
199
+ state.memory.remember("stage", "intake")
200
+ # ... processing ...
201
+ state.memory.remember("stage", "analysis")
202
+ # ... processing ...
203
+ state.memory.remember("stage", "response")
204
+ ```
205
+
206
+ ### Caching Expensive Operations
207
+
208
+ ```ruby
209
+ tool :fetch_user do
210
+ handler do |user_id:, state:, **_|
211
+ cache_key = "cache:user:#{user_id}"
212
+
213
+ # Check cache
214
+ cached = state.memory.recall(cache_key)
215
+ return cached if cached
216
+
217
+ # Fetch and cache
218
+ user = User.find(user_id).to_h
219
+ state.memory.remember(cache_key, user)
220
+ user
221
+ end
222
+ end
223
+ ```
224
+
225
+ ### User Session Data
226
+
227
+ ```ruby
228
+ # Store session data
229
+ session = state.memory.scoped("session:#{session_id}")
230
+ session.remember("started_at", Time.now.iso8601)
231
+ session.remember("page_views", 0)
232
+
233
+ # Update during conversation
234
+ views = session.recall("page_views") || 0
235
+ session.remember("page_views", views + 1)
236
+ ```
237
+
238
+ ## Memory vs State.data
239
+
240
+ | Feature | Memory | State.data |
241
+ |---------|--------|------------|
242
+ | Purpose | Robot-to-robot sharing | Input/output data |
243
+ | Scope | Namespaced | Flat hash |
244
+ | Typical Use | Intermediate results | User input, workflow config |
245
+ | Persistence | Within run | Can be serialized |
246
+
247
+ ```ruby
248
+ # Use state.data for input configuration
249
+ state = RobotLab.create_state(
250
+ message: "Process order",
251
+ data: { order_id: "123", priority: "high" }
252
+ )
253
+
254
+ # Use memory for intermediate findings
255
+ state.memory.remember("validation_result", { valid: true })
256
+ state.memory.remember("processing_steps", ["validated", "charged"])
257
+ ```
258
+
259
+ ## Best Practices
260
+
261
+ ### 1. Use Descriptive Keys
262
+
263
+ ```ruby
264
+ # Good
265
+ state.memory.remember("classification:intent", "billing")
266
+ state.memory.remember("user:123:last_order_id", "ord_456")
267
+
268
+ # Bad
269
+ state.memory.remember("x", "billing")
270
+ state.memory.remember("temp1", "ord_456")
271
+ ```
272
+
273
+ ### 2. Scope Related Data
274
+
275
+ ```ruby
276
+ # Good
277
+ user = state.memory.scoped("user:#{user_id}")
278
+ user.remember("name", name)
279
+ user.remember("email", email)
280
+ user.remember("plan", plan)
281
+
282
+ # Less organized
283
+ state.memory.remember("user_name", name)
284
+ state.memory.remember("user_email", email)
285
+ state.memory.remember("user_plan", plan)
286
+ ```
287
+
288
+ ### 3. Clean Up Temporary Data
289
+
290
+ ```ruby
291
+ # At end of processing
292
+ state.memory.scoped("temp").clear
293
+ ```
294
+
295
+ ### 4. Document Memory Keys
296
+
297
+ ```ruby
298
+ # In your robot definitions, document expected keys
299
+ # Memory keys used:
300
+ # - SHARED:intent - Classification result
301
+ # - SHARED:entities - Extracted entities
302
+ # - user:{id}:* - User-specific data
303
+ ```
304
+
305
+ ## Next Steps
306
+
307
+ - [State Management](../architecture/state-management.md) - Full state details
308
+ - [Building Robots](building-robots.md) - Using memory in robots
309
+ - [API Reference: Memory](../api/core/memory.md) - Complete API