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.
- checksums.yaml +7 -0
- data/.envrc +1 -0
- data/.github/workflows/deploy-github-pages.yml +52 -0
- data/.github/workflows/deploy-yard-docs.yml +52 -0
- data/CHANGELOG.md +55 -0
- data/COMMITS.md +196 -0
- data/LICENSE.txt +21 -0
- data/README.md +332 -0
- data/Rakefile +67 -0
- data/docs/api/adapters/anthropic.md +121 -0
- data/docs/api/adapters/gemini.md +133 -0
- data/docs/api/adapters/index.md +104 -0
- data/docs/api/adapters/openai.md +134 -0
- data/docs/api/core/index.md +113 -0
- data/docs/api/core/memory.md +314 -0
- data/docs/api/core/network.md +291 -0
- data/docs/api/core/robot.md +273 -0
- data/docs/api/core/state.md +273 -0
- data/docs/api/core/tool.md +353 -0
- data/docs/api/history/active-record-adapter.md +195 -0
- data/docs/api/history/config.md +191 -0
- data/docs/api/history/index.md +132 -0
- data/docs/api/history/thread-manager.md +144 -0
- data/docs/api/index.md +82 -0
- data/docs/api/mcp/client.md +221 -0
- data/docs/api/mcp/index.md +111 -0
- data/docs/api/mcp/server.md +225 -0
- data/docs/api/mcp/transports.md +264 -0
- data/docs/api/messages/index.md +67 -0
- data/docs/api/messages/text-message.md +102 -0
- data/docs/api/messages/tool-call-message.md +144 -0
- data/docs/api/messages/tool-result-message.md +154 -0
- data/docs/api/messages/user-message.md +171 -0
- data/docs/api/streaming/context.md +174 -0
- data/docs/api/streaming/events.md +237 -0
- data/docs/api/streaming/index.md +108 -0
- data/docs/architecture/core-concepts.md +243 -0
- data/docs/architecture/index.md +138 -0
- data/docs/architecture/message-flow.md +320 -0
- data/docs/architecture/network-orchestration.md +216 -0
- data/docs/architecture/robot-execution.md +243 -0
- data/docs/architecture/state-management.md +323 -0
- data/docs/assets/css/custom.css +56 -0
- data/docs/assets/images/robot_lab.jpg +0 -0
- data/docs/concepts.md +216 -0
- data/docs/examples/basic-chat.md +193 -0
- data/docs/examples/index.md +129 -0
- data/docs/examples/mcp-server.md +290 -0
- data/docs/examples/multi-robot-network.md +312 -0
- data/docs/examples/rails-application.md +420 -0
- data/docs/examples/tool-usage.md +310 -0
- data/docs/getting-started/configuration.md +230 -0
- data/docs/getting-started/index.md +56 -0
- data/docs/getting-started/installation.md +179 -0
- data/docs/getting-started/quick-start.md +203 -0
- data/docs/guides/building-robots.md +376 -0
- data/docs/guides/creating-networks.md +366 -0
- data/docs/guides/history.md +359 -0
- data/docs/guides/index.md +68 -0
- data/docs/guides/mcp-integration.md +356 -0
- data/docs/guides/memory.md +309 -0
- data/docs/guides/rails-integration.md +432 -0
- data/docs/guides/streaming.md +314 -0
- data/docs/guides/using-tools.md +394 -0
- data/docs/index.md +160 -0
- data/examples/01_simple_robot.rb +38 -0
- data/examples/02_tools.rb +106 -0
- data/examples/03_network.rb +103 -0
- data/examples/04_mcp.rb +219 -0
- data/examples/05_streaming.rb +124 -0
- data/examples/06_prompt_templates.rb +324 -0
- data/examples/07_network_memory.rb +329 -0
- data/examples/prompts/assistant/system.txt.erb +2 -0
- data/examples/prompts/assistant/user.txt.erb +1 -0
- data/examples/prompts/billing/system.txt.erb +7 -0
- data/examples/prompts/billing/user.txt.erb +1 -0
- data/examples/prompts/classifier/system.txt.erb +4 -0
- data/examples/prompts/classifier/user.txt.erb +1 -0
- data/examples/prompts/entity_extractor/system.txt.erb +11 -0
- data/examples/prompts/entity_extractor/user.txt.erb +3 -0
- data/examples/prompts/escalation/system.txt.erb +35 -0
- data/examples/prompts/escalation/user.txt.erb +34 -0
- data/examples/prompts/general/system.txt.erb +4 -0
- data/examples/prompts/general/user.txt.erb +1 -0
- data/examples/prompts/github_assistant/system.txt.erb +6 -0
- data/examples/prompts/github_assistant/user.txt.erb +1 -0
- data/examples/prompts/helper/system.txt.erb +1 -0
- data/examples/prompts/helper/user.txt.erb +1 -0
- data/examples/prompts/keyword_extractor/system.txt.erb +8 -0
- data/examples/prompts/keyword_extractor/user.txt.erb +3 -0
- data/examples/prompts/order_support/system.txt.erb +27 -0
- data/examples/prompts/order_support/user.txt.erb +22 -0
- data/examples/prompts/product_support/system.txt.erb +30 -0
- data/examples/prompts/product_support/user.txt.erb +32 -0
- data/examples/prompts/sentiment_analyzer/system.txt.erb +9 -0
- data/examples/prompts/sentiment_analyzer/user.txt.erb +3 -0
- data/examples/prompts/synthesizer/system.txt.erb +14 -0
- data/examples/prompts/synthesizer/user.txt.erb +15 -0
- data/examples/prompts/technical/system.txt.erb +7 -0
- data/examples/prompts/technical/user.txt.erb +1 -0
- data/examples/prompts/triage/system.txt.erb +16 -0
- data/examples/prompts/triage/user.txt.erb +17 -0
- data/lib/generators/robot_lab/install_generator.rb +78 -0
- data/lib/generators/robot_lab/robot_generator.rb +55 -0
- data/lib/generators/robot_lab/templates/initializer.rb.tt +41 -0
- data/lib/generators/robot_lab/templates/migration.rb.tt +32 -0
- data/lib/generators/robot_lab/templates/result_model.rb.tt +52 -0
- data/lib/generators/robot_lab/templates/robot.rb.tt +46 -0
- data/lib/generators/robot_lab/templates/robot_test.rb.tt +32 -0
- data/lib/generators/robot_lab/templates/routing_robot.rb.tt +53 -0
- data/lib/generators/robot_lab/templates/thread_model.rb.tt +40 -0
- data/lib/robot_lab/adapters/anthropic.rb +163 -0
- data/lib/robot_lab/adapters/base.rb +85 -0
- data/lib/robot_lab/adapters/gemini.rb +193 -0
- data/lib/robot_lab/adapters/openai.rb +159 -0
- data/lib/robot_lab/adapters/registry.rb +81 -0
- data/lib/robot_lab/configuration.rb +143 -0
- data/lib/robot_lab/error.rb +32 -0
- data/lib/robot_lab/errors.rb +70 -0
- data/lib/robot_lab/history/active_record_adapter.rb +146 -0
- data/lib/robot_lab/history/config.rb +115 -0
- data/lib/robot_lab/history/thread_manager.rb +93 -0
- data/lib/robot_lab/mcp/client.rb +210 -0
- data/lib/robot_lab/mcp/server.rb +84 -0
- data/lib/robot_lab/mcp/transports/base.rb +56 -0
- data/lib/robot_lab/mcp/transports/sse.rb +117 -0
- data/lib/robot_lab/mcp/transports/stdio.rb +133 -0
- data/lib/robot_lab/mcp/transports/streamable_http.rb +139 -0
- data/lib/robot_lab/mcp/transports/websocket.rb +108 -0
- data/lib/robot_lab/memory.rb +882 -0
- data/lib/robot_lab/memory_change.rb +123 -0
- data/lib/robot_lab/message.rb +357 -0
- data/lib/robot_lab/network.rb +350 -0
- data/lib/robot_lab/rails/engine.rb +29 -0
- data/lib/robot_lab/rails/railtie.rb +42 -0
- data/lib/robot_lab/robot.rb +560 -0
- data/lib/robot_lab/robot_result.rb +205 -0
- data/lib/robot_lab/robotic_model.rb +324 -0
- data/lib/robot_lab/state_proxy.rb +188 -0
- data/lib/robot_lab/streaming/context.rb +144 -0
- data/lib/robot_lab/streaming/events.rb +95 -0
- data/lib/robot_lab/streaming/sequence_counter.rb +48 -0
- data/lib/robot_lab/task.rb +117 -0
- data/lib/robot_lab/tool.rb +223 -0
- data/lib/robot_lab/tool_config.rb +112 -0
- data/lib/robot_lab/tool_manifest.rb +234 -0
- data/lib/robot_lab/user_message.rb +118 -0
- data/lib/robot_lab/version.rb +5 -0
- data/lib/robot_lab/waiter.rb +73 -0
- data/lib/robot_lab.rb +195 -0
- data/mkdocs.yml +214 -0
- data/sig/robot_lab.rbs +4 -0
- metadata +442 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Adapters
|
|
2
|
+
|
|
3
|
+
LLM provider adapters for unified API access.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Adapters provide a consistent interface to different LLM providers, handling the translation between RobotLab's message format and provider-specific APIs.
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
# Configure globally
|
|
11
|
+
RobotLab.configure do |config|
|
|
12
|
+
config.default_model = "claude-sonnet-4"
|
|
13
|
+
# Adapter is selected automatically based on model
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Or configure per-robot
|
|
17
|
+
robot = RobotLab.build do
|
|
18
|
+
model "gpt-4o" # Uses OpenAI adapter
|
|
19
|
+
end
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Adapter Selection
|
|
23
|
+
|
|
24
|
+
Adapters are automatically selected based on model name:
|
|
25
|
+
|
|
26
|
+
| Model Pattern | Adapter |
|
|
27
|
+
|---------------|---------|
|
|
28
|
+
| `claude-*`, `anthropic/*` | Anthropic |
|
|
29
|
+
| `gpt-*`, `o1-*`, `openai/*` | OpenAI |
|
|
30
|
+
| `gemini-*`, `google/*` | Gemini |
|
|
31
|
+
|
|
32
|
+
## Common Interface
|
|
33
|
+
|
|
34
|
+
All adapters implement:
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
adapter.chat(
|
|
38
|
+
messages: messages,
|
|
39
|
+
model: model,
|
|
40
|
+
tools: tools,
|
|
41
|
+
system: system_prompt,
|
|
42
|
+
streaming: callback
|
|
43
|
+
)
|
|
44
|
+
# => Response with content and usage
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Available Adapters
|
|
48
|
+
|
|
49
|
+
| Adapter | Description |
|
|
50
|
+
|---------|-------------|
|
|
51
|
+
| [Anthropic](anthropic.md) | Claude models via Anthropic API |
|
|
52
|
+
| [OpenAI](openai.md) | GPT models via OpenAI API |
|
|
53
|
+
| [Gemini](gemini.md) | Gemini models via Google AI |
|
|
54
|
+
|
|
55
|
+
## Configuration
|
|
56
|
+
|
|
57
|
+
### API Keys
|
|
58
|
+
|
|
59
|
+
Set via environment variables:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
export ANTHROPIC_API_KEY="sk-ant-..."
|
|
63
|
+
export OPENAI_API_KEY="sk-..."
|
|
64
|
+
export GOOGLE_AI_API_KEY="..."
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Custom Endpoints
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
RobotLab.configure do |config|
|
|
71
|
+
config.adapter_options = {
|
|
72
|
+
anthropic: { base_url: "https://custom.anthropic.endpoint" },
|
|
73
|
+
openai: { base_url: "https://custom.openai.endpoint" }
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Creating Custom Adapters
|
|
79
|
+
|
|
80
|
+
Implement the adapter interface:
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
class MyAdapter
|
|
84
|
+
def chat(messages:, model:, tools: [], system: nil, streaming: nil)
|
|
85
|
+
# Translate messages to provider format
|
|
86
|
+
# Make API call
|
|
87
|
+
# Translate response back
|
|
88
|
+
|
|
89
|
+
Response.new(
|
|
90
|
+
content: content,
|
|
91
|
+
tool_calls: tool_calls,
|
|
92
|
+
usage: { input_tokens: x, output_tokens: y }
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Register the adapter
|
|
98
|
+
RobotLab.register_adapter(:my_provider, MyAdapter)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## See Also
|
|
102
|
+
|
|
103
|
+
- [Configuration Guide](../../getting-started/configuration.md)
|
|
104
|
+
- [Streaming Guide](../../guides/streaming.md)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# OpenAI Adapter
|
|
2
|
+
|
|
3
|
+
Adapter for GPT models via OpenAI API.
|
|
4
|
+
|
|
5
|
+
## Class: `RobotLab::Adapters::OpenAI`
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
# Automatically used for GPT models
|
|
9
|
+
robot = RobotLab.build do
|
|
10
|
+
model "gpt-4o"
|
|
11
|
+
end
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Supported Models
|
|
15
|
+
|
|
16
|
+
| Model | Description |
|
|
17
|
+
|-------|-------------|
|
|
18
|
+
| `gpt-4o` | Latest GPT-4 Omni |
|
|
19
|
+
| `gpt-4o-mini` | Fast, efficient GPT-4 |
|
|
20
|
+
| `gpt-4-turbo` | GPT-4 Turbo |
|
|
21
|
+
| `o1-preview` | Reasoning model |
|
|
22
|
+
| `o1-mini` | Fast reasoning model |
|
|
23
|
+
|
|
24
|
+
## Configuration
|
|
25
|
+
|
|
26
|
+
### API Key
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
export OPENAI_API_KEY="sk-..."
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Options
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
RobotLab.configure do |config|
|
|
36
|
+
config.adapter_options = {
|
|
37
|
+
openai: {
|
|
38
|
+
base_url: "https://api.openai.com/v1",
|
|
39
|
+
organization: "org-...",
|
|
40
|
+
timeout: 120,
|
|
41
|
+
max_tokens: 4096
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Azure OpenAI
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
RobotLab.configure do |config|
|
|
51
|
+
config.adapter_options = {
|
|
52
|
+
openai: {
|
|
53
|
+
base_url: "https://your-resource.openai.azure.com",
|
|
54
|
+
api_key: ENV["AZURE_OPENAI_KEY"],
|
|
55
|
+
api_version: "2024-02-15-preview"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Features
|
|
62
|
+
|
|
63
|
+
### Streaming
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
result = robot.run(state: state) do |event|
|
|
67
|
+
case event
|
|
68
|
+
when :text_delta
|
|
69
|
+
print event.text
|
|
70
|
+
when :tool_call
|
|
71
|
+
puts "Calling: #{event.name}"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Tool Use
|
|
77
|
+
|
|
78
|
+
Tools are automatically converted to OpenAI's function calling format:
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
robot = RobotLab.build do
|
|
82
|
+
model "gpt-4o"
|
|
83
|
+
|
|
84
|
+
tool :get_weather do
|
|
85
|
+
description "Get current weather"
|
|
86
|
+
parameter :location, type: :string, required: true
|
|
87
|
+
handler { |location:, **_| WeatherAPI.fetch(location) }
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### JSON Mode
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
robot = RobotLab.build do
|
|
96
|
+
model "gpt-4o"
|
|
97
|
+
template "Always respond with valid JSON."
|
|
98
|
+
# Response format is automatically configured
|
|
99
|
+
end
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Response Format
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
{
|
|
106
|
+
content: [TextMessage, ...],
|
|
107
|
+
tool_calls: [ToolCallMessage, ...],
|
|
108
|
+
usage: {
|
|
109
|
+
input_tokens: 150,
|
|
110
|
+
output_tokens: 250,
|
|
111
|
+
total_tokens: 400
|
|
112
|
+
},
|
|
113
|
+
stop_reason: "stop"
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Error Handling
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
begin
|
|
121
|
+
result = robot.run(state: state)
|
|
122
|
+
rescue RobotLab::Adapters::RateLimitError => e
|
|
123
|
+
sleep(e.retry_after || 60)
|
|
124
|
+
retry
|
|
125
|
+
rescue RobotLab::Adapters::APIError => e
|
|
126
|
+
logger.error("OpenAI API error: #{e.message}")
|
|
127
|
+
end
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## See Also
|
|
131
|
+
|
|
132
|
+
- [Adapters Overview](index.md)
|
|
133
|
+
- [Streaming Guide](../../guides/streaming.md)
|
|
134
|
+
- [OpenAI API Documentation](https://platform.openai.com/docs/)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Core Classes
|
|
2
|
+
|
|
3
|
+
The fundamental classes that power RobotLab.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
classDiagram
|
|
9
|
+
class Robot {
|
|
10
|
+
+name: String
|
|
11
|
+
+description: String
|
|
12
|
+
+model: String
|
|
13
|
+
+template: String
|
|
14
|
+
+tools: Array~Tool~
|
|
15
|
+
+run(state, network)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
class Network {
|
|
19
|
+
+name: String
|
|
20
|
+
+robots: Hash
|
|
21
|
+
+router: Proc
|
|
22
|
+
+run(state)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class State {
|
|
26
|
+
+data: StateProxy
|
|
27
|
+
+results: Array
|
|
28
|
+
+messages: Array
|
|
29
|
+
+memory: Memory
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
class Tool {
|
|
33
|
+
+name: String
|
|
34
|
+
+description: String
|
|
35
|
+
+parameters: Hash
|
|
36
|
+
+handler: Proc
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class Memory {
|
|
40
|
+
+remember(key, value)
|
|
41
|
+
+recall(key)
|
|
42
|
+
+forget(key)
|
|
43
|
+
+scoped(namespace)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
Network --> Robot : contains
|
|
47
|
+
Robot --> Tool : has
|
|
48
|
+
State --> Memory : has
|
|
49
|
+
Network --> State : uses
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Classes
|
|
53
|
+
|
|
54
|
+
| Class | Purpose |
|
|
55
|
+
|-------|---------|
|
|
56
|
+
| [Robot](robot.md) | LLM agent with personality, tools, and model configuration |
|
|
57
|
+
| [Network](network.md) | Container for robots with routing and orchestration |
|
|
58
|
+
| [State](state.md) | Conversation state with data, results, and memory |
|
|
59
|
+
| [Tool](tool.md) | Callable function with parameters and handler |
|
|
60
|
+
| [Memory](memory.md) | Namespaced key-value store for sharing data |
|
|
61
|
+
|
|
62
|
+
## Quick Examples
|
|
63
|
+
|
|
64
|
+
### Robot
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
robot = RobotLab.build do
|
|
68
|
+
name "assistant"
|
|
69
|
+
model "claude-sonnet-4"
|
|
70
|
+
template "You are helpful."
|
|
71
|
+
|
|
72
|
+
tool :greet do
|
|
73
|
+
parameter :name, type: :string
|
|
74
|
+
handler { |name:, **_| "Hello, #{name}!" }
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Network
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
network = RobotLab.create_network do
|
|
83
|
+
name "my_network"
|
|
84
|
+
add_robot robot
|
|
85
|
+
router ->(args) { args.call_count.zero? ? :assistant : nil }
|
|
86
|
+
end
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### State
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
state = RobotLab.create_state(
|
|
93
|
+
message: "Hello",
|
|
94
|
+
data: { user_id: "123" }
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Tool
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
tool = RobotLab::Tool.new(
|
|
102
|
+
name: "get_time",
|
|
103
|
+
description: "Get current time",
|
|
104
|
+
handler: ->(**, _) { Time.now.to_s }
|
|
105
|
+
)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Memory
|
|
109
|
+
|
|
110
|
+
```ruby
|
|
111
|
+
state.memory.remember("key", "value")
|
|
112
|
+
value = state.memory.recall("key")
|
|
113
|
+
```
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
# Memory
|
|
2
|
+
|
|
3
|
+
Namespaced key-value store for sharing data between robots.
|
|
4
|
+
|
|
5
|
+
## Class: `RobotLab::Memory`
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
memory = state.memory
|
|
9
|
+
|
|
10
|
+
memory.remember("key", "value")
|
|
11
|
+
value = memory.recall("key")
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Constants
|
|
15
|
+
|
|
16
|
+
### SHARED_NAMESPACE
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
Memory::SHARED_NAMESPACE # => "SHARED"
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Conventional namespace for cross-robot data.
|
|
23
|
+
|
|
24
|
+
## Constructor
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
memory = Memory.new(initial_data = {})
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Methods
|
|
31
|
+
|
|
32
|
+
### remember
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
memory.remember(key, value)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Store a value.
|
|
39
|
+
|
|
40
|
+
**Parameters:**
|
|
41
|
+
|
|
42
|
+
| Name | Type | Description |
|
|
43
|
+
|------|------|-------------|
|
|
44
|
+
| `key` | `String`, `Symbol` | Storage key |
|
|
45
|
+
| `value` | `Object` | Value to store |
|
|
46
|
+
|
|
47
|
+
### recall
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
memory.recall(key) # => Object | nil
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Retrieve a value.
|
|
54
|
+
|
|
55
|
+
**Parameters:**
|
|
56
|
+
|
|
57
|
+
| Name | Type | Description |
|
|
58
|
+
|------|------|-------------|
|
|
59
|
+
| `key` | `String`, `Symbol` | Storage key |
|
|
60
|
+
|
|
61
|
+
**Returns:** Stored value or `nil`.
|
|
62
|
+
|
|
63
|
+
### exists?
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
memory.exists?(key) # => Boolean
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Check if key exists.
|
|
70
|
+
|
|
71
|
+
### forget
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
memory.forget(key) # => Object | nil
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Remove a key, returns the value.
|
|
78
|
+
|
|
79
|
+
### all
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
memory.all # => Hash
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Get all stored data.
|
|
86
|
+
|
|
87
|
+
### namespaces
|
|
88
|
+
|
|
89
|
+
```ruby
|
|
90
|
+
memory.namespaces # => Array<String>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
List all namespaces.
|
|
94
|
+
|
|
95
|
+
### clear
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
memory.clear
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Clear all data in current scope.
|
|
102
|
+
|
|
103
|
+
### clear_all
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
memory.clear_all
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Clear all data globally.
|
|
110
|
+
|
|
111
|
+
### search
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
memory.search(pattern) # => Hash
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Find keys matching pattern.
|
|
118
|
+
|
|
119
|
+
**Parameters:**
|
|
120
|
+
|
|
121
|
+
| Name | Type | Description |
|
|
122
|
+
|------|------|-------------|
|
|
123
|
+
| `pattern` | `String` | Glob pattern (e.g., "user:*") |
|
|
124
|
+
|
|
125
|
+
### stats
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
memory.stats # => Hash
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Get memory statistics.
|
|
132
|
+
|
|
133
|
+
**Returns:**
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
{
|
|
137
|
+
total_keys: 15,
|
|
138
|
+
namespaces: ["user", "session"]
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### scoped
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
scoped_memory = memory.scoped(namespace) # => ScopedMemory
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Create a scoped view.
|
|
149
|
+
|
|
150
|
+
## ScopedMemory
|
|
151
|
+
|
|
152
|
+
Scoped view with automatic key prefixing.
|
|
153
|
+
|
|
154
|
+
### Methods
|
|
155
|
+
|
|
156
|
+
All Memory methods are available:
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
scoped = memory.scoped("user:123")
|
|
160
|
+
|
|
161
|
+
scoped.remember("name", "Alice") # Key: "user:123:name"
|
|
162
|
+
scoped.recall("name") # => "Alice"
|
|
163
|
+
scoped.exists?("name") # => true
|
|
164
|
+
scoped.forget("name")
|
|
165
|
+
scoped.all # Only "user:123:*" keys
|
|
166
|
+
scoped.clear # Clear only this scope
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Nested Scopes
|
|
170
|
+
|
|
171
|
+
```ruby
|
|
172
|
+
user = memory.scoped("user:123")
|
|
173
|
+
prefs = user.scoped("preferences")
|
|
174
|
+
|
|
175
|
+
prefs.remember("theme", "dark")
|
|
176
|
+
# Full key: "user:123:preferences:theme"
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Examples
|
|
180
|
+
|
|
181
|
+
### Basic Usage
|
|
182
|
+
|
|
183
|
+
```ruby
|
|
184
|
+
state.memory.remember("user_name", "Alice")
|
|
185
|
+
state.memory.remember("order_count", 5)
|
|
186
|
+
|
|
187
|
+
name = state.memory.recall("user_name") # => "Alice"
|
|
188
|
+
count = state.memory.recall("order_count") # => 5
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Storing Objects
|
|
192
|
+
|
|
193
|
+
```ruby
|
|
194
|
+
state.memory.remember("user", {
|
|
195
|
+
id: 123,
|
|
196
|
+
name: "Alice",
|
|
197
|
+
plan: "pro"
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
user = state.memory.recall("user")
|
|
201
|
+
user[:plan] # => "pro"
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Scoped Organization
|
|
205
|
+
|
|
206
|
+
```ruby
|
|
207
|
+
# User-specific data
|
|
208
|
+
user = state.memory.scoped("user:#{user_id}")
|
|
209
|
+
user.remember("last_login", Time.now)
|
|
210
|
+
user.remember("preferences", { theme: "dark" })
|
|
211
|
+
|
|
212
|
+
# Session-specific data
|
|
213
|
+
session = state.memory.scoped("session:#{session_id}")
|
|
214
|
+
session.remember("page_views", 0)
|
|
215
|
+
|
|
216
|
+
# Temporary working data
|
|
217
|
+
temp = state.memory.scoped("temp")
|
|
218
|
+
temp.remember("intermediate_result", calculation)
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Cross-Robot Communication
|
|
222
|
+
|
|
223
|
+
```ruby
|
|
224
|
+
# In classifier robot
|
|
225
|
+
state.memory.remember("SHARED:intent", "billing")
|
|
226
|
+
state.memory.remember("SHARED:entities", ["order", "refund"])
|
|
227
|
+
|
|
228
|
+
# In handler robot
|
|
229
|
+
intent = state.memory.recall("SHARED:intent")
|
|
230
|
+
entities = state.memory.recall("SHARED:entities")
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### In Tool Handlers
|
|
234
|
+
|
|
235
|
+
```ruby
|
|
236
|
+
tool :update_preference do
|
|
237
|
+
handler do |key:, value:, state:, **_|
|
|
238
|
+
prefs = state.memory.scoped("preferences")
|
|
239
|
+
old_value = prefs.recall(key)
|
|
240
|
+
prefs.remember(key, value)
|
|
241
|
+
|
|
242
|
+
{
|
|
243
|
+
success: true,
|
|
244
|
+
key: key,
|
|
245
|
+
old_value: old_value,
|
|
246
|
+
new_value: value
|
|
247
|
+
}
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Search and Iteration
|
|
253
|
+
|
|
254
|
+
```ruby
|
|
255
|
+
# Find all user keys
|
|
256
|
+
user_data = state.memory.search("user:*")
|
|
257
|
+
# => { "user:123:name" => "Alice", "user:123:email" => "..." }
|
|
258
|
+
|
|
259
|
+
# Process all keys
|
|
260
|
+
state.memory.all.each do |key, value|
|
|
261
|
+
puts "#{key}: #{value}"
|
|
262
|
+
end
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Cleanup
|
|
266
|
+
|
|
267
|
+
```ruby
|
|
268
|
+
# Clear temporary data
|
|
269
|
+
state.memory.scoped("temp").clear
|
|
270
|
+
|
|
271
|
+
# Clear specific namespace
|
|
272
|
+
state.memory.scoped("cache").clear
|
|
273
|
+
|
|
274
|
+
# Clear everything
|
|
275
|
+
state.memory.clear_all
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Caching Pattern
|
|
279
|
+
|
|
280
|
+
```ruby
|
|
281
|
+
def cached_fetch(state, key, &block)
|
|
282
|
+
cache = state.memory.scoped("cache")
|
|
283
|
+
cached = cache.recall(key)
|
|
284
|
+
return cached if cached
|
|
285
|
+
|
|
286
|
+
result = block.call
|
|
287
|
+
cache.remember(key, result)
|
|
288
|
+
result
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# Usage
|
|
292
|
+
data = cached_fetch(state, "expensive:#{id}") do
|
|
293
|
+
ExpensiveService.fetch(id)
|
|
294
|
+
end
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Accumulating Results
|
|
298
|
+
|
|
299
|
+
```ruby
|
|
300
|
+
# In each robot, accumulate findings
|
|
301
|
+
findings = state.memory.recall("findings") || []
|
|
302
|
+
findings << { robot: robot.name, finding: new_finding }
|
|
303
|
+
state.memory.remember("findings", findings)
|
|
304
|
+
|
|
305
|
+
# In final robot, aggregate
|
|
306
|
+
all_findings = state.memory.recall("findings")
|
|
307
|
+
summary = all_findings.group_by { |f| f[:robot] }
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## See Also
|
|
311
|
+
|
|
312
|
+
- [Memory Guide](../../guides/memory.md)
|
|
313
|
+
- [State](state.md)
|
|
314
|
+
- [State Management Architecture](../../architecture/state-management.md)
|