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
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
# ActiveRecordAdapter
|
|
1
|
+
# History::ActiveRecordAdapter
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
ActiveRecord-based history persistence adapter for Rails applications.
|
|
4
4
|
|
|
5
5
|
## Class: `RobotLab::History::ActiveRecordAdapter`
|
|
6
6
|
|
|
7
|
+
Provides thread and result storage using ActiveRecord models. Converts itself to a `History::Config` via `to_config` for use with networks and thread managers.
|
|
8
|
+
|
|
7
9
|
```ruby
|
|
8
|
-
adapter = History::ActiveRecordAdapter.new(
|
|
9
|
-
thread_model:
|
|
10
|
-
result_model:
|
|
10
|
+
adapter = RobotLab::History::ActiveRecordAdapter.new(
|
|
11
|
+
thread_model: RobotLabThread,
|
|
12
|
+
result_model: RobotLabResult
|
|
11
13
|
)
|
|
12
14
|
|
|
13
15
|
config = adapter.to_config
|
|
@@ -16,75 +18,142 @@ config = adapter.to_config
|
|
|
16
18
|
## Constructor
|
|
17
19
|
|
|
18
20
|
```ruby
|
|
19
|
-
ActiveRecordAdapter.new(
|
|
20
|
-
thread_model:,
|
|
21
|
-
result_model:,
|
|
22
|
-
thread_factory: nil,
|
|
23
|
-
result_factory: nil
|
|
24
|
-
)
|
|
21
|
+
ActiveRecordAdapter.new(thread_model:, result_model:)
|
|
25
22
|
```
|
|
26
23
|
|
|
27
24
|
**Parameters:**
|
|
28
25
|
|
|
29
26
|
| Name | Type | Description |
|
|
30
27
|
|------|------|-------------|
|
|
31
|
-
| `thread_model` | `Class` | ActiveRecord model for threads |
|
|
32
|
-
| `result_model` | `Class` | ActiveRecord model for results |
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
| `thread_model` | `Class` | ActiveRecord model class for conversation threads |
|
|
29
|
+
| `result_model` | `Class` | ActiveRecord model class for conversation results |
|
|
30
|
+
|
|
31
|
+
## Attributes
|
|
32
|
+
|
|
33
|
+
### thread_model
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
adapter.thread_model # => Class (ActiveRecord model)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The ActiveRecord model class used for storing conversation threads.
|
|
40
|
+
|
|
41
|
+
### result_model
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
adapter.result_model # => Class (ActiveRecord model)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The ActiveRecord model class used for storing conversation results.
|
|
35
48
|
|
|
36
49
|
## Methods
|
|
37
50
|
|
|
38
51
|
### to_config
|
|
39
52
|
|
|
40
53
|
```ruby
|
|
41
|
-
config = adapter.to_config
|
|
54
|
+
config = adapter.to_config # => RobotLab::History::Config
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Convert the adapter to a `History::Config` object. The config's callbacks delegate to the adapter's `create_thread`, `get`, `append_user_message`, and `append_results` methods.
|
|
58
|
+
|
|
59
|
+
### create_thread
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
adapter.create_thread(state:, input:, **)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Create a new conversation thread record. Generates a UUID `session_id`, extracts content and metadata from the input, and stores `state.data` as serialized state data.
|
|
66
|
+
|
|
67
|
+
**Parameters:**
|
|
68
|
+
|
|
69
|
+
| Name | Type | Description |
|
|
70
|
+
|------|------|-------------|
|
|
71
|
+
| `state` | `Object` | Current memory/state (must respond to `.data`) |
|
|
72
|
+
| `input` | `String`, `UserMessage` | Initial user input |
|
|
73
|
+
|
|
74
|
+
**Returns:** Hash with `{ session_id: "...", created_at: Time }`.
|
|
75
|
+
|
|
76
|
+
### get
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
results = adapter.get(session_id:, **)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Retrieve all results for a thread, ordered by `sequence_number` and `created_at`. Deserializes each record into a `RobotResult`.
|
|
83
|
+
|
|
84
|
+
**Parameters:**
|
|
85
|
+
|
|
86
|
+
| Name | Type | Description |
|
|
87
|
+
|------|------|-------------|
|
|
88
|
+
| `session_id` | `String` | Thread identifier |
|
|
89
|
+
|
|
90
|
+
**Returns:** `Array<RobotResult>` -- deserialized results.
|
|
91
|
+
|
|
92
|
+
### append_user_message
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
adapter.append_user_message(session_id:, message:, **)
|
|
42
96
|
```
|
|
43
97
|
|
|
44
|
-
|
|
98
|
+
Update the thread record with the latest user message content and timestamp.
|
|
99
|
+
|
|
100
|
+
**Parameters:**
|
|
101
|
+
|
|
102
|
+
| Name | Type | Description |
|
|
103
|
+
|------|------|-------------|
|
|
104
|
+
| `session_id` | `String` | Thread identifier |
|
|
105
|
+
| `message` | `UserMessage` | User message |
|
|
106
|
+
|
|
107
|
+
### append_results
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
adapter.append_results(session_id:, new_results:, **)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Append robot results to the thread. Each result is stored with an auto-incrementing `sequence_number`. Serializes `output` and `tool_calls` from each `RobotResult`. Also updates the thread's `updated_at` timestamp.
|
|
114
|
+
|
|
115
|
+
**Parameters:**
|
|
116
|
+
|
|
117
|
+
| Name | Type | Description |
|
|
118
|
+
|------|------|-------------|
|
|
119
|
+
| `session_id` | `String` | Thread identifier |
|
|
120
|
+
| `new_results` | `Array<RobotResult>` | Results to append |
|
|
45
121
|
|
|
46
122
|
## Model Requirements
|
|
47
123
|
|
|
48
124
|
### Thread Model
|
|
49
125
|
|
|
126
|
+
The thread model must have the following columns:
|
|
127
|
+
|
|
50
128
|
```ruby
|
|
51
|
-
# db/migrate/
|
|
52
|
-
create_table :
|
|
53
|
-
t.string :
|
|
54
|
-
t.
|
|
129
|
+
# db/migrate/xxx_create_robot_lab_threads.rb
|
|
130
|
+
create_table :robot_lab_threads do |t|
|
|
131
|
+
t.string :session_id, null: false, index: { unique: true }
|
|
132
|
+
t.text :initial_input
|
|
133
|
+
t.jsonb :input_metadata, default: {}
|
|
134
|
+
t.jsonb :state_data, default: {}
|
|
135
|
+
t.text :last_user_message
|
|
136
|
+
t.datetime :last_user_message_at
|
|
55
137
|
t.timestamps
|
|
56
138
|
end
|
|
57
|
-
|
|
58
|
-
# app/models/conversation_thread.rb
|
|
59
|
-
class ConversationThread < ApplicationRecord
|
|
60
|
-
has_many :results, class_name: "ConversationResult",
|
|
61
|
-
foreign_key: :thread_id, dependent: :destroy
|
|
62
|
-
end
|
|
63
139
|
```
|
|
64
140
|
|
|
65
141
|
### Result Model
|
|
66
142
|
|
|
143
|
+
The result model must have the following columns:
|
|
144
|
+
|
|
67
145
|
```ruby
|
|
68
|
-
# db/migrate/
|
|
69
|
-
create_table :
|
|
70
|
-
t.
|
|
146
|
+
# db/migrate/xxx_create_robot_lab_results.rb
|
|
147
|
+
create_table :robot_lab_results do |t|
|
|
148
|
+
t.string :session_id, null: false, index: true
|
|
71
149
|
t.string :robot_name
|
|
72
|
-
t.
|
|
73
|
-
t.jsonb :
|
|
74
|
-
t.jsonb :
|
|
75
|
-
t.
|
|
76
|
-
t.
|
|
150
|
+
t.integer :sequence_number
|
|
151
|
+
t.jsonb :output_data, default: []
|
|
152
|
+
t.jsonb :tool_calls_data, default: []
|
|
153
|
+
t.string :stop_reason
|
|
154
|
+
t.string :checksum
|
|
77
155
|
t.timestamps
|
|
78
156
|
end
|
|
79
|
-
|
|
80
|
-
# app/models/conversation_result.rb
|
|
81
|
-
class ConversationResult < ApplicationRecord
|
|
82
|
-
belongs_to :thread, class_name: "ConversationThread"
|
|
83
|
-
|
|
84
|
-
def to_robot_result
|
|
85
|
-
RobotLab::RobotResult.from_hash(attributes)
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
157
|
```
|
|
89
158
|
|
|
90
159
|
## Examples
|
|
@@ -92,48 +161,52 @@ end
|
|
|
92
161
|
### Basic Setup
|
|
93
162
|
|
|
94
163
|
```ruby
|
|
95
|
-
adapter = History::ActiveRecordAdapter.new(
|
|
96
|
-
thread_model:
|
|
97
|
-
result_model:
|
|
164
|
+
adapter = RobotLab::History::ActiveRecordAdapter.new(
|
|
165
|
+
thread_model: RobotLabThread,
|
|
166
|
+
result_model: RobotLabResult
|
|
98
167
|
)
|
|
99
168
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
history adapter.to_config
|
|
103
|
-
add_robot assistant
|
|
104
|
-
end
|
|
169
|
+
config = adapter.to_config
|
|
170
|
+
# Use config with a ThreadManager or pass to network configuration
|
|
105
171
|
```
|
|
106
172
|
|
|
107
|
-
###
|
|
173
|
+
### Using with ThreadManager
|
|
108
174
|
|
|
109
175
|
```ruby
|
|
110
|
-
adapter = History::ActiveRecordAdapter.new(
|
|
111
|
-
thread_model:
|
|
112
|
-
result_model:
|
|
113
|
-
thread_factory: ->(state:, input:, **context) {
|
|
114
|
-
ConversationThread.create!(
|
|
115
|
-
external_id: SecureRandom.uuid,
|
|
116
|
-
user_id: context[:user_id],
|
|
117
|
-
title: input.truncate(100),
|
|
118
|
-
metadata: { source: context[:source] }
|
|
119
|
-
)
|
|
120
|
-
}
|
|
176
|
+
adapter = RobotLab::History::ActiveRecordAdapter.new(
|
|
177
|
+
thread_model: RobotLabThread,
|
|
178
|
+
result_model: RobotLabResult
|
|
121
179
|
)
|
|
180
|
+
|
|
181
|
+
manager = RobotLab::History::ThreadManager.new(adapter.to_config)
|
|
182
|
+
|
|
183
|
+
# Create a thread
|
|
184
|
+
session_id = manager.create_thread(state: memory, input: "Hello")
|
|
185
|
+
|
|
186
|
+
# Run robot and save
|
|
187
|
+
result = robot.run("Hello")
|
|
188
|
+
manager.append_results(session_id: session_id, results: [result])
|
|
189
|
+
|
|
190
|
+
# Later, retrieve
|
|
191
|
+
history = manager.get_history(session_id)
|
|
122
192
|
```
|
|
123
193
|
|
|
124
|
-
### With User
|
|
194
|
+
### With User-Scoped Models
|
|
195
|
+
|
|
196
|
+
For applications that need per-user thread scoping, create a custom adapter:
|
|
125
197
|
|
|
126
198
|
```ruby
|
|
127
|
-
class
|
|
199
|
+
class ScopedHistoryAdapter
|
|
128
200
|
def initialize(thread_model:, result_model:)
|
|
129
201
|
@thread_model = thread_model
|
|
130
202
|
@result_model = result_model
|
|
131
203
|
end
|
|
132
204
|
|
|
133
205
|
def to_config
|
|
134
|
-
History::Config.new(
|
|
206
|
+
RobotLab::History::Config.new(
|
|
135
207
|
create_thread: method(:create_thread),
|
|
136
208
|
get: method(:get),
|
|
209
|
+
append_user_message: method(:append_user_message),
|
|
137
210
|
append_results: method(:append_results)
|
|
138
211
|
)
|
|
139
212
|
end
|
|
@@ -141,55 +214,62 @@ class ScopedAdapter
|
|
|
141
214
|
private
|
|
142
215
|
|
|
143
216
|
def create_thread(state:, input:, user_id:, **)
|
|
144
|
-
@thread_model.create!(
|
|
145
|
-
|
|
217
|
+
thread = @thread_model.create!(
|
|
218
|
+
session_id: SecureRandom.uuid,
|
|
146
219
|
user_id: user_id,
|
|
147
|
-
|
|
220
|
+
initial_input: input.to_s
|
|
148
221
|
)
|
|
222
|
+
{ session_id: thread.session_id, created_at: thread.created_at }
|
|
149
223
|
end
|
|
150
224
|
|
|
151
|
-
def get(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
225
|
+
def get(session_id:, user_id:, **)
|
|
226
|
+
@result_model
|
|
227
|
+
.joins(:thread)
|
|
228
|
+
.where(threads: { session_id: session_id, user_id: user_id })
|
|
229
|
+
.order(:sequence_number)
|
|
230
|
+
.map(&:to_robot_result)
|
|
155
231
|
end
|
|
156
232
|
|
|
157
|
-
def
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
233
|
+
def append_user_message(session_id:, message:, user_id:, **)
|
|
234
|
+
@thread_model.where(session_id: session_id, user_id: user_id)
|
|
235
|
+
.update_all(last_user_message: message.content, last_user_message_at: Time.current)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def append_results(session_id:, new_results:, user_id:, **)
|
|
239
|
+
base_seq = @result_model.where(session_id: session_id).maximum(:sequence_number) || 0
|
|
240
|
+
|
|
241
|
+
new_results.each_with_index do |result, i|
|
|
242
|
+
@result_model.create!(
|
|
243
|
+
session_id: session_id,
|
|
244
|
+
robot_name: result.robot_name,
|
|
245
|
+
sequence_number: base_seq + i + 1,
|
|
246
|
+
output_data: result.output.map(&:to_h),
|
|
247
|
+
tool_calls_data: result.tool_calls.map(&:to_h),
|
|
248
|
+
stop_reason: result.stop_reason,
|
|
249
|
+
checksum: result.checksum
|
|
250
|
+
)
|
|
171
251
|
end
|
|
252
|
+
|
|
253
|
+
@thread_model.where(session_id: session_id).update_all(updated_at: Time.current)
|
|
172
254
|
end
|
|
173
255
|
end
|
|
174
256
|
```
|
|
175
257
|
|
|
176
258
|
### Rails Generator
|
|
177
259
|
|
|
178
|
-
Use the Rails generator to
|
|
260
|
+
Use the Rails generator to scaffold the required models and migrations:
|
|
179
261
|
|
|
180
262
|
```bash
|
|
181
263
|
rails generate robot_lab:history
|
|
182
264
|
```
|
|
183
265
|
|
|
184
266
|
This creates:
|
|
185
|
-
|
|
186
|
-
-
|
|
187
|
-
- `ConversationResult` model
|
|
188
|
-
- Database migrations
|
|
267
|
+
- Thread and result ActiveRecord models
|
|
268
|
+
- Database migrations with required columns
|
|
189
269
|
- Initializer configuration
|
|
190
270
|
|
|
191
271
|
## See Also
|
|
192
272
|
|
|
193
273
|
- [History Overview](index.md)
|
|
194
274
|
- [Config](config.md)
|
|
195
|
-
- [
|
|
275
|
+
- [ThreadManager](thread-manager.md)
|