robot_lab 0.0.1 → 0.0.4
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/.github/workflows/deploy-github-pages.yml +9 -9
- data/.irbrc +6 -0
- data/CHANGELOG.md +90 -0
- data/README.md +203 -46
- data/Rakefile +70 -1
- data/docs/api/core/index.md +12 -0
- data/docs/api/core/robot.md +478 -130
- data/docs/api/core/tool.md +205 -209
- data/docs/api/history/active-record-adapter.md +174 -94
- data/docs/api/history/config.md +186 -93
- data/docs/api/history/index.md +57 -61
- data/docs/api/history/thread-manager.md +123 -73
- data/docs/api/mcp/client.md +119 -48
- data/docs/api/mcp/index.md +75 -60
- data/docs/api/mcp/server.md +120 -136
- data/docs/api/mcp/transports.md +172 -184
- data/docs/api/streaming/context.md +157 -74
- data/docs/api/streaming/events.md +114 -166
- data/docs/api/streaming/index.md +74 -72
- data/docs/architecture/core-concepts.md +361 -112
- data/docs/architecture/index.md +97 -59
- data/docs/architecture/message-flow.md +138 -129
- data/docs/architecture/network-orchestration.md +197 -50
- data/docs/architecture/robot-execution.md +199 -146
- data/docs/architecture/state-management.md +255 -187
- data/docs/concepts.md +312 -48
- data/docs/examples/basic-chat.md +89 -77
- data/docs/examples/index.md +222 -47
- data/docs/examples/mcp-server.md +207 -203
- data/docs/examples/multi-robot-network.md +129 -35
- data/docs/examples/rails-application.md +159 -160
- data/docs/examples/tool-usage.md +295 -204
- data/docs/getting-started/configuration.md +275 -162
- data/docs/getting-started/index.md +1 -1
- data/docs/getting-started/installation.md +22 -13
- data/docs/getting-started/quick-start.md +166 -121
- data/docs/guides/building-robots.md +417 -212
- data/docs/guides/creating-networks.md +94 -24
- data/docs/guides/mcp-integration.md +152 -113
- data/docs/guides/memory.md +220 -164
- data/docs/guides/streaming.md +80 -110
- data/docs/guides/using-tools.md +259 -212
- data/docs/index.md +50 -37
- data/examples/01_simple_robot.rb +6 -9
- data/examples/02_tools.rb +6 -9
- data/examples/03_network.rb +13 -14
- data/examples/04_mcp.rb +5 -8
- data/examples/05_streaming.rb +5 -8
- data/examples/06_prompt_templates.rb +42 -37
- data/examples/07_network_memory.rb +13 -14
- data/examples/08_llm_config.rb +140 -0
- data/examples/09_chaining.rb +223 -0
- data/examples/10_memory.rb +331 -0
- data/examples/11_network_introspection.rb +230 -0
- data/examples/12_message_bus.rb +74 -0
- data/examples/13_spawn.rb +90 -0
- data/examples/14_rusty_circuit/comic.rb +143 -0
- data/examples/14_rusty_circuit/display.rb +203 -0
- data/examples/14_rusty_circuit/heckler.rb +57 -0
- data/examples/14_rusty_circuit/open_mic.rb +121 -0
- data/examples/14_rusty_circuit/prompts/open_mic_comic.md +20 -0
- data/examples/14_rusty_circuit/prompts/open_mic_heckler.md +23 -0
- data/examples/14_rusty_circuit/prompts/open_mic_scout.md +20 -0
- data/examples/14_rusty_circuit/scout.rb +173 -0
- data/examples/14_rusty_circuit/scout_notes.md +89 -0
- data/examples/14_rusty_circuit/show.log +234 -0
- data/examples/15_memory_network_and_bus/editor_in_chief.rb +24 -0
- data/examples/15_memory_network_and_bus/editorial_pipeline.rb +206 -0
- data/examples/15_memory_network_and_bus/linux_writer.rb +80 -0
- data/examples/15_memory_network_and_bus/os_editor.rb +46 -0
- data/examples/15_memory_network_and_bus/os_writer.rb +46 -0
- data/examples/15_memory_network_and_bus/output/combined_article.md +13 -0
- data/examples/15_memory_network_and_bus/output/final_article.md +15 -0
- data/examples/15_memory_network_and_bus/output/linux_draft.md +5 -0
- data/examples/15_memory_network_and_bus/output/mac_draft.md +7 -0
- data/examples/15_memory_network_and_bus/output/memory.json +13 -0
- data/examples/15_memory_network_and_bus/output/revision_1.md +19 -0
- data/examples/15_memory_network_and_bus/output/revision_2.md +15 -0
- data/examples/15_memory_network_and_bus/output/windows_draft.md +7 -0
- data/examples/15_memory_network_and_bus/prompts/os_advocate.md +13 -0
- data/examples/15_memory_network_and_bus/prompts/os_chief.md +13 -0
- data/examples/15_memory_network_and_bus/prompts/os_editor.md +13 -0
- data/examples/README.md +197 -0
- data/examples/prompts/{assistant/system.txt.erb → assistant.md} +3 -0
- data/examples/prompts/{billing/system.txt.erb → billing.md} +3 -0
- data/examples/prompts/{classifier/system.txt.erb → classifier.md} +3 -0
- data/examples/prompts/comedian.md +6 -0
- data/examples/prompts/comedy_critic.md +10 -0
- data/examples/prompts/configurable.md +9 -0
- data/examples/prompts/dispatcher.md +12 -0
- data/examples/prompts/{entity_extractor/system.txt.erb → entity_extractor.md} +3 -0
- data/examples/prompts/{escalation/system.txt.erb → escalation.md} +7 -0
- data/examples/prompts/frontmatter_mcp_test.md +9 -0
- data/examples/prompts/frontmatter_named_test.md +5 -0
- data/examples/prompts/frontmatter_tools_test.md +6 -0
- data/examples/prompts/{general/system.txt.erb → general.md} +3 -0
- data/examples/prompts/{github_assistant/system.txt.erb → github_assistant.md} +8 -0
- data/examples/prompts/{helper/system.txt.erb → helper.md} +3 -0
- data/examples/prompts/{keyword_extractor/system.txt.erb → keyword_extractor.md} +3 -0
- data/examples/prompts/llm_config_demo.md +20 -0
- data/examples/prompts/{order_support/system.txt.erb → order_support.md} +8 -0
- data/examples/prompts/os_advocate.md +13 -0
- data/examples/prompts/os_chief.md +13 -0
- data/examples/prompts/os_editor.md +13 -0
- data/examples/prompts/{product_support/system.txt.erb → product_support.md} +7 -0
- data/examples/prompts/{sentiment_analyzer/system.txt.erb → sentiment_analyzer.md} +3 -0
- data/examples/prompts/{synthesizer/system.txt.erb → synthesizer.md} +3 -0
- data/examples/prompts/{technical/system.txt.erb → technical.md} +3 -0
- data/examples/prompts/{triage/system.txt.erb → triage.md} +6 -0
- data/lib/generators/robot_lab/templates/initializer.rb.tt +1 -1
- data/lib/robot_lab/adapters/openai.rb +2 -1
- data/lib/robot_lab/ask_user.rb +75 -0
- data/lib/robot_lab/config/defaults.yml +121 -0
- data/lib/robot_lab/config.rb +183 -0
- data/lib/robot_lab/error.rb +6 -0
- data/lib/robot_lab/mcp/client.rb +1 -1
- data/lib/robot_lab/memory.rb +2 -2
- data/lib/robot_lab/robot.rb +523 -249
- data/lib/robot_lab/robot_message.rb +44 -0
- data/lib/robot_lab/robot_result.rb +1 -0
- data/lib/robot_lab/robotic_model.rb +1 -1
- data/lib/robot_lab/streaming/context.rb +1 -1
- data/lib/robot_lab/tool.rb +108 -172
- data/lib/robot_lab/tool_config.rb +1 -1
- data/lib/robot_lab/tool_manifest.rb +2 -18
- data/lib/robot_lab/version.rb +1 -1
- data/lib/robot_lab.rb +66 -55
- metadata +107 -116
- data/examples/prompts/assistant/user.txt.erb +0 -1
- data/examples/prompts/billing/user.txt.erb +0 -1
- data/examples/prompts/classifier/user.txt.erb +0 -1
- data/examples/prompts/entity_extractor/user.txt.erb +0 -3
- data/examples/prompts/escalation/user.txt.erb +0 -34
- data/examples/prompts/general/user.txt.erb +0 -1
- data/examples/prompts/github_assistant/user.txt.erb +0 -1
- data/examples/prompts/helper/user.txt.erb +0 -1
- data/examples/prompts/keyword_extractor/user.txt.erb +0 -3
- data/examples/prompts/order_support/user.txt.erb +0 -22
- data/examples/prompts/product_support/user.txt.erb +0 -32
- data/examples/prompts/sentiment_analyzer/user.txt.erb +0 -3
- data/examples/prompts/synthesizer/user.txt.erb +0 -15
- data/examples/prompts/technical/user.txt.erb +0 -1
- data/examples/prompts/triage/user.txt.erb +0 -17
- data/lib/robot_lab/configuration.rb +0 -143
data/docs/api/history/config.md
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
# History::Config
|
|
2
2
|
|
|
3
|
-
Configuration for conversation persistence.
|
|
3
|
+
Configuration for conversation history persistence using callback-based architecture.
|
|
4
4
|
|
|
5
5
|
## Class: `RobotLab::History::Config`
|
|
6
6
|
|
|
7
7
|
```ruby
|
|
8
|
-
config = History::Config.new(
|
|
9
|
-
create_thread:
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
config = RobotLab::History::Config.new(
|
|
9
|
+
create_thread: ->(state:, input:, **) {
|
|
10
|
+
{ session_id: SecureRandom.uuid }
|
|
11
|
+
},
|
|
12
|
+
get: ->(session_id:, **) {
|
|
13
|
+
database.find_results(session_id)
|
|
14
|
+
},
|
|
15
|
+
append_results: ->(session_id:, new_results:, **) {
|
|
16
|
+
database.insert_results(session_id, new_results)
|
|
17
|
+
}
|
|
12
18
|
)
|
|
13
19
|
```
|
|
14
20
|
|
|
@@ -16,101 +22,217 @@ config = History::Config.new(
|
|
|
16
22
|
|
|
17
23
|
```ruby
|
|
18
24
|
Config.new(
|
|
19
|
-
create_thread
|
|
20
|
-
get
|
|
21
|
-
|
|
25
|
+
create_thread: nil,
|
|
26
|
+
get: nil,
|
|
27
|
+
append_user_message: nil,
|
|
28
|
+
append_results: nil
|
|
22
29
|
)
|
|
23
30
|
```
|
|
24
31
|
|
|
32
|
+
All parameters are optional Proc/lambda callbacks. The `configured?` method returns `true` only when both `create_thread` and `get` are set.
|
|
33
|
+
|
|
25
34
|
**Parameters:**
|
|
26
35
|
|
|
27
|
-
| Name | Type | Description |
|
|
28
|
-
|
|
29
|
-
| `create_thread` | `Proc` |
|
|
30
|
-
| `get` | `Proc` |
|
|
31
|
-
| `
|
|
36
|
+
| Name | Type | Default | Description |
|
|
37
|
+
|------|------|---------|-------------|
|
|
38
|
+
| `create_thread` | `Proc`, `nil` | `nil` | Callback to create a new conversation thread |
|
|
39
|
+
| `get` | `Proc`, `nil` | `nil` | Callback to retrieve history for a thread |
|
|
40
|
+
| `append_user_message` | `Proc`, `nil` | `nil` | Callback to append user messages |
|
|
41
|
+
| `append_results` | `Proc`, `nil` | `nil` | Callback to append robot results |
|
|
42
|
+
|
|
43
|
+
## Attributes
|
|
32
44
|
|
|
33
|
-
|
|
45
|
+
All attributes are read-write (`attr_accessor`):
|
|
34
46
|
|
|
35
47
|
### create_thread
|
|
36
48
|
|
|
37
|
-
|
|
49
|
+
```ruby
|
|
50
|
+
config.create_thread # => Proc | nil
|
|
51
|
+
config.create_thread = ->(state:, input:, **) { ... }
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### get
|
|
38
55
|
|
|
39
56
|
```ruby
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
{ id: SecureRandom.uuid }
|
|
43
|
-
}
|
|
57
|
+
config.get # => Proc | nil
|
|
58
|
+
config.get = ->(session_id:, **) { ... }
|
|
44
59
|
```
|
|
45
60
|
|
|
46
|
-
|
|
61
|
+
### append_user_message
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
config.append_user_message # => Proc | nil
|
|
65
|
+
config.append_user_message = ->(session_id:, message:, **) { ... }
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### append_results
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
config.append_results # => Proc | nil
|
|
72
|
+
config.append_results = ->(session_id:, new_results:, **) { ... }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Methods
|
|
76
|
+
|
|
77
|
+
### configured?
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
config.configured? # => Boolean
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Returns `true` if both `create_thread` and `get` callbacks are set.
|
|
84
|
+
|
|
85
|
+
### create_thread!
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
result = config.create_thread!(state:, input:, **kwargs)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Invoke the `create_thread` callback. Validates that the callback is configured and that the return value is a Hash containing `:session_id`.
|
|
92
|
+
|
|
93
|
+
**Parameters:**
|
|
47
94
|
|
|
48
95
|
| Name | Type | Description |
|
|
49
96
|
|------|------|-------------|
|
|
50
|
-
| `state` | `
|
|
51
|
-
| `input` | `String` |
|
|
52
|
-
| `**
|
|
97
|
+
| `state` | `Object` | Current state or memory |
|
|
98
|
+
| `input` | `String`, `UserMessage` | Initial user input |
|
|
99
|
+
| `**kwargs` | `Hash` | Additional context passed through |
|
|
53
100
|
|
|
54
|
-
**Returns:** Hash with
|
|
101
|
+
**Returns:** Hash with at least `{ session_id: "..." }`.
|
|
55
102
|
|
|
56
|
-
|
|
103
|
+
**Raises:** `HistoryError` if callback is not configured or return value is invalid.
|
|
57
104
|
|
|
58
|
-
|
|
105
|
+
### get!
|
|
59
106
|
|
|
60
107
|
```ruby
|
|
61
|
-
get
|
|
62
|
-
# Return array of previous results
|
|
63
|
-
Thread.find(thread_id).results
|
|
64
|
-
}
|
|
108
|
+
results = config.get!(session_id:, **kwargs)
|
|
65
109
|
```
|
|
66
110
|
|
|
67
|
-
|
|
111
|
+
Invoke the `get` callback to retrieve history for a thread.
|
|
112
|
+
|
|
113
|
+
**Parameters:**
|
|
68
114
|
|
|
69
115
|
| Name | Type | Description |
|
|
70
116
|
|------|------|-------------|
|
|
71
|
-
| `
|
|
72
|
-
| `**
|
|
117
|
+
| `session_id` | `String` | Thread identifier |
|
|
118
|
+
| `**kwargs` | `Hash` | Additional context |
|
|
73
119
|
|
|
74
|
-
**Returns:** Array of `RobotResult` or
|
|
120
|
+
**Returns:** Array of `RobotResult` (or whatever the callback returns).
|
|
75
121
|
|
|
76
|
-
|
|
122
|
+
**Raises:** `HistoryError` if callback is not configured.
|
|
77
123
|
|
|
78
|
-
|
|
124
|
+
### append_user_message!
|
|
79
125
|
|
|
80
126
|
```ruby
|
|
81
|
-
|
|
82
|
-
# Persist the new results
|
|
83
|
-
thread = Thread.find(thread_id)
|
|
84
|
-
new_results.each { |r| thread.results.create(r.to_h) }
|
|
85
|
-
}
|
|
127
|
+
config.append_user_message!(session_id:, message:, **kwargs)
|
|
86
128
|
```
|
|
87
129
|
|
|
88
|
-
|
|
130
|
+
Invoke the `append_user_message` callback. No-op if the callback is not configured.
|
|
131
|
+
|
|
132
|
+
**Parameters:**
|
|
89
133
|
|
|
90
134
|
| Name | Type | Description |
|
|
91
135
|
|------|------|-------------|
|
|
92
|
-
| `
|
|
136
|
+
| `session_id` | `String` | Thread identifier |
|
|
137
|
+
| `message` | `UserMessage` | User message to append |
|
|
138
|
+
| `**kwargs` | `Hash` | Additional context |
|
|
139
|
+
|
|
140
|
+
### append_results!
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
config.append_results!(session_id:, new_results:, **kwargs)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Invoke the `append_results` callback. No-op if the callback is not configured.
|
|
147
|
+
|
|
148
|
+
**Parameters:**
|
|
149
|
+
|
|
150
|
+
| Name | Type | Description |
|
|
151
|
+
|------|------|-------------|
|
|
152
|
+
| `session_id` | `String` | Thread identifier |
|
|
93
153
|
| `new_results` | `Array<RobotResult>` | Results to append |
|
|
94
|
-
| `**
|
|
154
|
+
| `**kwargs` | `Hash` | Additional context |
|
|
95
155
|
|
|
96
|
-
##
|
|
156
|
+
## Callback Signatures
|
|
97
157
|
|
|
98
158
|
### create_thread
|
|
99
159
|
|
|
160
|
+
Called when a new conversation starts.
|
|
161
|
+
|
|
100
162
|
```ruby
|
|
101
|
-
|
|
163
|
+
create_thread: ->(state:, input:, **context) {
|
|
164
|
+
# Must return a Hash with :session_id
|
|
165
|
+
{ session_id: SecureRandom.uuid }
|
|
166
|
+
}
|
|
102
167
|
```
|
|
103
168
|
|
|
169
|
+
| Argument | Type | Description |
|
|
170
|
+
|----------|------|-------------|
|
|
171
|
+
| `state` | `Object` | Current robot memory or state |
|
|
172
|
+
| `input` | `String`, `UserMessage` | Initial user input |
|
|
173
|
+
| `**context` | `Hash` | Additional context |
|
|
174
|
+
|
|
104
175
|
### get
|
|
105
176
|
|
|
177
|
+
Called to retrieve existing conversation history.
|
|
178
|
+
|
|
106
179
|
```ruby
|
|
107
|
-
|
|
180
|
+
get: ->(session_id:, **context) {
|
|
181
|
+
# Return array of previous results
|
|
182
|
+
Thread.find(session_id).results
|
|
183
|
+
}
|
|
108
184
|
```
|
|
109
185
|
|
|
186
|
+
| Argument | Type | Description |
|
|
187
|
+
|----------|------|-------------|
|
|
188
|
+
| `session_id` | `String` | Thread identifier |
|
|
189
|
+
| `**context` | `Hash` | Additional context |
|
|
190
|
+
|
|
191
|
+
### append_user_message
|
|
192
|
+
|
|
193
|
+
Called to record user messages in the thread.
|
|
194
|
+
|
|
195
|
+
```ruby
|
|
196
|
+
append_user_message: ->(session_id:, message:, **context) {
|
|
197
|
+
Thread.find(session_id).update(last_message: message.content)
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
| Argument | Type | Description |
|
|
202
|
+
|----------|------|-------------|
|
|
203
|
+
| `session_id` | `String` | Thread identifier |
|
|
204
|
+
| `message` | `UserMessage` | User message |
|
|
205
|
+
| `**context` | `Hash` | Additional context |
|
|
206
|
+
|
|
110
207
|
### append_results
|
|
111
208
|
|
|
209
|
+
Called after robot execution to persist results.
|
|
210
|
+
|
|
112
211
|
```ruby
|
|
113
|
-
|
|
212
|
+
append_results: ->(session_id:, new_results:, **context) {
|
|
213
|
+
new_results.each { |r| Thread.find(session_id).results.create(r.to_h) }
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
| Argument | Type | Description |
|
|
218
|
+
|----------|------|-------------|
|
|
219
|
+
| `session_id` | `String` | Thread identifier |
|
|
220
|
+
| `new_results` | `Array<RobotResult>` | Results to append |
|
|
221
|
+
| `**context` | `Hash` | Additional context |
|
|
222
|
+
|
|
223
|
+
## Error Handling
|
|
224
|
+
|
|
225
|
+
History operations raise `RobotLab::History::HistoryError` (a subclass of `RobotLab::Error`) when:
|
|
226
|
+
|
|
227
|
+
- A required callback is not configured and the `!` method is called
|
|
228
|
+
- The `create_thread` callback returns a value without `:session_id`
|
|
229
|
+
|
|
230
|
+
```ruby
|
|
231
|
+
begin
|
|
232
|
+
config.create_thread!(state: memory, input: "Hello")
|
|
233
|
+
rescue RobotLab::History::HistoryError => e
|
|
234
|
+
puts "History error: #{e.message}"
|
|
235
|
+
end
|
|
114
236
|
```
|
|
115
237
|
|
|
116
238
|
## Examples
|
|
@@ -120,66 +242,37 @@ config.append_results # => Proc
|
|
|
120
242
|
```ruby
|
|
121
243
|
STORE = {}
|
|
122
244
|
|
|
123
|
-
config = History::Config.new(
|
|
245
|
+
config = RobotLab::History::Config.new(
|
|
124
246
|
create_thread: ->(state:, **) {
|
|
125
247
|
id = SecureRandom.uuid
|
|
126
248
|
STORE[id] = { results: [] }
|
|
127
|
-
{
|
|
249
|
+
{ session_id: id }
|
|
128
250
|
},
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
STORE.dig(thread_id, :results) || []
|
|
251
|
+
get: ->(session_id:, **) {
|
|
252
|
+
STORE.dig(session_id, :results) || []
|
|
132
253
|
},
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
STORE[thread_id][:results].concat(new_results.map(&:to_h))
|
|
254
|
+
append_results: ->(session_id:, new_results:, **) {
|
|
255
|
+
STORE[session_id][:results].concat(new_results.map(&:to_h))
|
|
136
256
|
}
|
|
137
257
|
)
|
|
138
258
|
```
|
|
139
259
|
|
|
140
|
-
### With
|
|
260
|
+
### With User Scoping
|
|
141
261
|
|
|
142
262
|
```ruby
|
|
143
|
-
config = History::Config.new(
|
|
263
|
+
config = RobotLab::History::Config.new(
|
|
144
264
|
create_thread: ->(state:, user_id:, **) {
|
|
145
|
-
|
|
265
|
+
thread = ConversationThread.create!(user_id: user_id)
|
|
266
|
+
{ session_id: thread.session_id }
|
|
146
267
|
},
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
268
|
+
get: ->(session_id:, user_id:, **) {
|
|
269
|
+
ConversationThread.where(session_id: session_id, user_id: user_id)
|
|
270
|
+
.first&.results || []
|
|
150
271
|
},
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
thread = Thread.find_by(id: thread_id, user_id: user_id)
|
|
272
|
+
append_results: ->(session_id:, new_results:, user_id:, **) {
|
|
273
|
+
thread = ConversationThread.find_by(session_id: session_id, user_id: user_id)
|
|
154
274
|
return unless thread
|
|
155
|
-
new_results.each { |r| thread.results.create(r.to_h) }
|
|
156
|
-
}
|
|
157
|
-
)
|
|
158
|
-
|
|
159
|
-
# Pass context when running
|
|
160
|
-
network.run(state: state, user_id: current_user.id)
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### With Validation
|
|
164
|
-
|
|
165
|
-
```ruby
|
|
166
|
-
config = History::Config.new(
|
|
167
|
-
create_thread: ->(state:, **) {
|
|
168
|
-
raise "Invalid state" unless state.data[:user_id]
|
|
169
|
-
Thread.create(user_id: state.data[:user_id])
|
|
170
|
-
},
|
|
171
|
-
|
|
172
|
-
get: ->(thread_id:, **) {
|
|
173
|
-
thread = Thread.find_by(id: thread_id)
|
|
174
|
-
raise "Thread not found" unless thread
|
|
175
|
-
thread.results
|
|
176
|
-
},
|
|
177
|
-
|
|
178
|
-
append_results: ->(thread_id:, new_results:, **) {
|
|
179
|
-
thread = Thread.find(thread_id)
|
|
180
|
-
Thread.transaction do
|
|
181
|
-
new_results.each { |r| thread.results.create!(r.to_h) }
|
|
182
|
-
end
|
|
275
|
+
new_results.each { |r| thread.results.create!(r.to_h) }
|
|
183
276
|
}
|
|
184
277
|
)
|
|
185
278
|
```
|
data/docs/api/history/index.md
CHANGED
|
@@ -4,47 +4,49 @@ Conversation persistence and thread management.
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
The history system enables persistent conversations by storing and retrieving conversation threads and results.
|
|
7
|
+
The history system enables persistent conversations by storing and retrieving conversation threads and results. It uses a callback-based architecture where you provide lambda/proc implementations for thread creation, retrieval, and result storage.
|
|
8
8
|
|
|
9
9
|
```ruby
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
end
|
|
10
|
+
config = RobotLab::History::Config.new(
|
|
11
|
+
create_thread: ->(state:, input:, **) {
|
|
12
|
+
{ session_id: SecureRandom.uuid }
|
|
13
|
+
},
|
|
14
|
+
get: ->(session_id:, **) {
|
|
15
|
+
STORE[session_id] || []
|
|
16
|
+
},
|
|
17
|
+
append_results: ->(session_id:, new_results:, **) {
|
|
18
|
+
STORE[session_id] ||= []
|
|
19
|
+
STORE[session_id].concat(new_results)
|
|
20
|
+
}
|
|
21
|
+
)
|
|
23
22
|
```
|
|
24
23
|
|
|
25
24
|
## Components
|
|
26
25
|
|
|
27
26
|
| Component | Description |
|
|
28
27
|
|-----------|-------------|
|
|
29
|
-
| [Config](config.md) | History configuration |
|
|
28
|
+
| [Config](config.md) | History configuration with persistence callbacks |
|
|
30
29
|
| [ThreadManager](thread-manager.md) | Thread lifecycle management |
|
|
31
|
-
| [ActiveRecordAdapter](active-record-adapter.md) | Rails integration |
|
|
30
|
+
| [ActiveRecordAdapter](active-record-adapter.md) | Rails ActiveRecord integration |
|
|
32
31
|
|
|
33
32
|
## Quick Start
|
|
34
33
|
|
|
35
34
|
### Basic Configuration
|
|
36
35
|
|
|
37
36
|
```ruby
|
|
38
|
-
|
|
37
|
+
STORE = {}
|
|
38
|
+
|
|
39
|
+
history = RobotLab::History::Config.new(
|
|
39
40
|
create_thread: ->(state:, input:, **) {
|
|
40
|
-
|
|
41
|
+
id = SecureRandom.uuid
|
|
42
|
+
STORE[id] = []
|
|
43
|
+
{ session_id: id }
|
|
41
44
|
},
|
|
42
|
-
get: ->(
|
|
43
|
-
STORE[
|
|
45
|
+
get: ->(session_id:, **) {
|
|
46
|
+
STORE[session_id] || []
|
|
44
47
|
},
|
|
45
|
-
append_results: ->(
|
|
46
|
-
STORE[
|
|
47
|
-
STORE[thread_id].concat(new_results)
|
|
48
|
+
append_results: ->(session_id:, new_results:, **) {
|
|
49
|
+
STORE[session_id].concat(new_results)
|
|
48
50
|
}
|
|
49
51
|
)
|
|
50
52
|
```
|
|
@@ -52,36 +54,29 @@ history = History::Config.new(
|
|
|
52
54
|
### With ActiveRecord
|
|
53
55
|
|
|
54
56
|
```ruby
|
|
55
|
-
|
|
56
|
-
thread_model:
|
|
57
|
-
result_model:
|
|
58
|
-
)
|
|
57
|
+
adapter = RobotLab::History::ActiveRecordAdapter.new(
|
|
58
|
+
thread_model: RobotLabThread,
|
|
59
|
+
result_model: RobotLabResult
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
config = adapter.to_config
|
|
59
63
|
```
|
|
60
64
|
|
|
61
65
|
## Callbacks
|
|
62
66
|
|
|
63
|
-
| Callback | Purpose |
|
|
64
|
-
|
|
65
|
-
| `create_thread` | Create new conversation thread |
|
|
66
|
-
| `get` | Retrieve existing thread history |
|
|
67
|
-
| `
|
|
67
|
+
| Callback | Required | Purpose |
|
|
68
|
+
|----------|----------|---------|
|
|
69
|
+
| `create_thread` | Yes (for `configured?`) | Create a new conversation thread |
|
|
70
|
+
| `get` | Yes (for `configured?`) | Retrieve existing thread history |
|
|
71
|
+
| `append_user_message` | No | Record user messages |
|
|
72
|
+
| `append_results` | No | Persist robot results |
|
|
68
73
|
|
|
69
74
|
## Thread Lifecycle
|
|
70
75
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
participant H as History
|
|
76
|
-
|
|
77
|
-
U->>N: Run with new message
|
|
78
|
-
N->>H: get(thread_id)
|
|
79
|
-
H-->>N: Previous results
|
|
80
|
-
N->>N: Execute robots
|
|
81
|
-
N->>H: append_results(new_results)
|
|
82
|
-
H-->>N: Saved
|
|
83
|
-
N-->>U: Result with thread_id
|
|
84
|
-
```
|
|
76
|
+
1. **Create** -- When a new conversation starts, `create_thread` is called. It must return a Hash with a `:session_id` key.
|
|
77
|
+
2. **Retrieve** -- On subsequent messages, `get` is called with the `session_id` to load previous results.
|
|
78
|
+
3. **Append** -- After each robot execution, `append_results` is called with the new `RobotResult` objects.
|
|
79
|
+
4. **User Messages** -- Optionally, `append_user_message` records each user input.
|
|
85
80
|
|
|
86
81
|
## Examples
|
|
87
82
|
|
|
@@ -90,17 +85,17 @@ sequenceDiagram
|
|
|
90
85
|
```ruby
|
|
91
86
|
THREADS = {}
|
|
92
87
|
|
|
93
|
-
history = History::Config.new(
|
|
88
|
+
history = RobotLab::History::Config.new(
|
|
94
89
|
create_thread: ->(state:, **) {
|
|
95
90
|
id = SecureRandom.uuid
|
|
96
91
|
THREADS[id] = []
|
|
97
|
-
{
|
|
92
|
+
{ session_id: id }
|
|
98
93
|
},
|
|
99
|
-
get: ->(
|
|
100
|
-
THREADS[
|
|
94
|
+
get: ->(session_id:, **) {
|
|
95
|
+
THREADS[session_id] || []
|
|
101
96
|
},
|
|
102
|
-
append_results: ->(
|
|
103
|
-
THREADS[
|
|
97
|
+
append_results: ->(session_id:, new_results:, **) {
|
|
98
|
+
THREADS[session_id].concat(new_results)
|
|
104
99
|
}
|
|
105
100
|
)
|
|
106
101
|
```
|
|
@@ -108,25 +103,26 @@ history = History::Config.new(
|
|
|
108
103
|
### Redis Store
|
|
109
104
|
|
|
110
105
|
```ruby
|
|
111
|
-
history = History::Config.new(
|
|
106
|
+
history = RobotLab::History::Config.new(
|
|
112
107
|
create_thread: ->(state:, **) {
|
|
113
108
|
id = SecureRandom.uuid
|
|
114
109
|
Redis.current.set("thread:#{id}", [].to_json)
|
|
115
|
-
{
|
|
110
|
+
{ session_id: id }
|
|
116
111
|
},
|
|
117
|
-
get: ->(
|
|
118
|
-
data = Redis.current.get("thread:#{
|
|
112
|
+
get: ->(session_id:, **) {
|
|
113
|
+
data = Redis.current.get("thread:#{session_id}")
|
|
119
114
|
data ? JSON.parse(data) : []
|
|
120
115
|
},
|
|
121
|
-
append_results: ->(
|
|
122
|
-
existing = JSON.parse(Redis.current.get("thread:#{
|
|
116
|
+
append_results: ->(session_id:, new_results:, **) {
|
|
117
|
+
existing = JSON.parse(Redis.current.get("thread:#{session_id}") || "[]")
|
|
123
118
|
existing.concat(new_results.map(&:to_h))
|
|
124
|
-
Redis.current.set("thread:#{
|
|
119
|
+
Redis.current.set("thread:#{session_id}", existing.to_json)
|
|
125
120
|
}
|
|
126
121
|
)
|
|
127
122
|
```
|
|
128
123
|
|
|
129
124
|
## See Also
|
|
130
125
|
|
|
131
|
-
- [
|
|
132
|
-
- [
|
|
126
|
+
- [Config](config.md)
|
|
127
|
+
- [ThreadManager](thread-manager.md)
|
|
128
|
+
- [ActiveRecordAdapter](active-record-adapter.md)
|