robot_lab 0.0.1 → 0.0.6

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 (187) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/deploy-github-pages.yml +9 -9
  3. data/.irbrc +6 -0
  4. data/CHANGELOG.md +140 -0
  5. data/README.md +263 -48
  6. data/Rakefile +71 -1
  7. data/docs/api/core/index.md +53 -46
  8. data/docs/api/core/memory.md +200 -154
  9. data/docs/api/core/network.md +13 -3
  10. data/docs/api/core/robot.md +490 -130
  11. data/docs/api/core/state.md +55 -73
  12. data/docs/api/core/tool.md +205 -209
  13. data/docs/api/index.md +7 -28
  14. data/docs/api/mcp/client.md +119 -48
  15. data/docs/api/mcp/index.md +75 -60
  16. data/docs/api/mcp/server.md +120 -136
  17. data/docs/api/mcp/transports.md +172 -184
  18. data/docs/api/messages/index.md +35 -20
  19. data/docs/api/messages/text-message.md +67 -21
  20. data/docs/api/messages/tool-call-message.md +80 -41
  21. data/docs/api/messages/tool-result-message.md +119 -50
  22. data/docs/api/messages/user-message.md +48 -24
  23. data/docs/api/streaming/context.md +157 -74
  24. data/docs/api/streaming/events.md +114 -166
  25. data/docs/api/streaming/index.md +74 -72
  26. data/docs/architecture/core-concepts.md +360 -116
  27. data/docs/architecture/index.md +97 -59
  28. data/docs/architecture/message-flow.md +138 -129
  29. data/docs/architecture/network-orchestration.md +197 -50
  30. data/docs/architecture/robot-execution.md +199 -146
  31. data/docs/architecture/state-management.md +255 -187
  32. data/docs/concepts.md +311 -49
  33. data/docs/examples/basic-chat.md +89 -77
  34. data/docs/examples/index.md +222 -47
  35. data/docs/examples/mcp-server.md +207 -203
  36. data/docs/examples/multi-robot-network.md +129 -35
  37. data/docs/examples/rails-application.md +159 -160
  38. data/docs/examples/tool-usage.md +295 -204
  39. data/docs/getting-started/configuration.md +347 -154
  40. data/docs/getting-started/index.md +1 -1
  41. data/docs/getting-started/installation.md +22 -13
  42. data/docs/getting-started/quick-start.md +166 -121
  43. data/docs/guides/building-robots.md +418 -212
  44. data/docs/guides/creating-networks.md +143 -24
  45. data/docs/guides/index.md +0 -5
  46. data/docs/guides/mcp-integration.md +152 -113
  47. data/docs/guides/memory.md +220 -164
  48. data/docs/guides/rails-integration.md +244 -162
  49. data/docs/guides/streaming.md +137 -187
  50. data/docs/guides/using-tools.md +259 -212
  51. data/docs/index.md +46 -41
  52. data/examples/01_simple_robot.rb +6 -9
  53. data/examples/02_tools.rb +6 -9
  54. data/examples/03_network.rb +19 -17
  55. data/examples/04_mcp.rb +5 -8
  56. data/examples/05_streaming.rb +5 -8
  57. data/examples/06_prompt_templates.rb +42 -37
  58. data/examples/07_network_memory.rb +13 -14
  59. data/examples/08_llm_config.rb +169 -0
  60. data/examples/09_chaining.rb +262 -0
  61. data/examples/10_memory.rb +331 -0
  62. data/examples/11_network_introspection.rb +253 -0
  63. data/examples/12_message_bus.rb +74 -0
  64. data/examples/13_spawn.rb +90 -0
  65. data/examples/14_rusty_circuit/comic.rb +143 -0
  66. data/examples/14_rusty_circuit/display.rb +203 -0
  67. data/examples/14_rusty_circuit/heckler.rb +63 -0
  68. data/examples/14_rusty_circuit/open_mic.rb +123 -0
  69. data/examples/14_rusty_circuit/prompts/open_mic_comic.md +20 -0
  70. data/examples/14_rusty_circuit/prompts/open_mic_heckler.md +23 -0
  71. data/examples/14_rusty_circuit/prompts/open_mic_scout.md +20 -0
  72. data/examples/14_rusty_circuit/scout.rb +156 -0
  73. data/examples/14_rusty_circuit/scout_notes.md +89 -0
  74. data/examples/14_rusty_circuit/show.log +234 -0
  75. data/examples/15_memory_network_and_bus/editor_in_chief.rb +24 -0
  76. data/examples/15_memory_network_and_bus/editorial_pipeline.rb +206 -0
  77. data/examples/15_memory_network_and_bus/linux_writer.rb +80 -0
  78. data/examples/15_memory_network_and_bus/os_editor.rb +46 -0
  79. data/examples/15_memory_network_and_bus/os_writer.rb +46 -0
  80. data/examples/15_memory_network_and_bus/output/combined_article.md +13 -0
  81. data/examples/15_memory_network_and_bus/output/final_article.md +15 -0
  82. data/examples/15_memory_network_and_bus/output/linux_draft.md +5 -0
  83. data/examples/15_memory_network_and_bus/output/mac_draft.md +7 -0
  84. data/examples/15_memory_network_and_bus/output/memory.json +13 -0
  85. data/examples/15_memory_network_and_bus/output/revision_1.md +19 -0
  86. data/examples/15_memory_network_and_bus/output/revision_2.md +15 -0
  87. data/examples/15_memory_network_and_bus/output/windows_draft.md +7 -0
  88. data/examples/15_memory_network_and_bus/prompts/os_advocate.md +13 -0
  89. data/examples/15_memory_network_and_bus/prompts/os_chief.md +13 -0
  90. data/examples/15_memory_network_and_bus/prompts/os_editor.md +13 -0
  91. data/examples/16_writers_room/display.rb +158 -0
  92. data/examples/16_writers_room/output/.gitignore +2 -0
  93. data/examples/16_writers_room/output/opus_001.md +263 -0
  94. data/examples/16_writers_room/output/opus_001_notes.log +470 -0
  95. data/examples/16_writers_room/prompts/writer.md +37 -0
  96. data/examples/16_writers_room/room.rb +150 -0
  97. data/examples/16_writers_room/tools.rb +162 -0
  98. data/examples/16_writers_room/writer.rb +121 -0
  99. data/examples/16_writers_room/writers_room.rb +162 -0
  100. data/examples/README.md +197 -0
  101. data/examples/prompts/{assistant/system.txt.erb → assistant.md} +3 -0
  102. data/examples/prompts/{billing/system.txt.erb → billing.md} +3 -0
  103. data/examples/prompts/{classifier/system.txt.erb → classifier.md} +3 -0
  104. data/examples/prompts/comedian.md +6 -0
  105. data/examples/prompts/comedy_critic.md +10 -0
  106. data/examples/prompts/configurable.md +9 -0
  107. data/examples/prompts/dispatcher.md +12 -0
  108. data/examples/prompts/{entity_extractor/system.txt.erb → entity_extractor.md} +3 -0
  109. data/examples/prompts/{escalation/system.txt.erb → escalation.md} +7 -0
  110. data/examples/prompts/frontmatter_mcp_test.md +9 -0
  111. data/examples/prompts/frontmatter_named_test.md +5 -0
  112. data/examples/prompts/frontmatter_tools_test.md +6 -0
  113. data/examples/prompts/{general/system.txt.erb → general.md} +3 -0
  114. data/examples/prompts/{github_assistant/system.txt.erb → github_assistant.md} +8 -0
  115. data/examples/prompts/{helper/system.txt.erb → helper.md} +3 -0
  116. data/examples/prompts/{keyword_extractor/system.txt.erb → keyword_extractor.md} +3 -0
  117. data/examples/prompts/llm_config_demo.md +20 -0
  118. data/examples/prompts/{order_support/system.txt.erb → order_support.md} +8 -0
  119. data/examples/prompts/os_advocate.md +13 -0
  120. data/examples/prompts/os_chief.md +13 -0
  121. data/examples/prompts/os_editor.md +13 -0
  122. data/examples/prompts/{product_support/system.txt.erb → product_support.md} +7 -0
  123. data/examples/prompts/{sentiment_analyzer/system.txt.erb → sentiment_analyzer.md} +3 -0
  124. data/examples/prompts/{synthesizer/system.txt.erb → synthesizer.md} +3 -0
  125. data/examples/prompts/{technical/system.txt.erb → technical.md} +3 -0
  126. data/examples/prompts/{triage/system.txt.erb → triage.md} +6 -0
  127. data/lib/generators/robot_lab/templates/initializer.rb.tt +0 -13
  128. data/lib/robot_lab/ask_user.rb +75 -0
  129. data/lib/robot_lab/config/defaults.yml +121 -0
  130. data/lib/robot_lab/config.rb +183 -0
  131. data/lib/robot_lab/error.rb +6 -0
  132. data/lib/robot_lab/mcp/client.rb +1 -1
  133. data/lib/robot_lab/memory.rb +10 -34
  134. data/lib/robot_lab/network.rb +13 -20
  135. data/lib/robot_lab/robot/bus_messaging.rb +239 -0
  136. data/lib/robot_lab/robot/mcp_management.rb +88 -0
  137. data/lib/robot_lab/robot/template_rendering.rb +130 -0
  138. data/lib/robot_lab/robot.rb +240 -330
  139. data/lib/robot_lab/robot_message.rb +44 -0
  140. data/lib/robot_lab/robot_result.rb +1 -0
  141. data/lib/robot_lab/run_config.rb +184 -0
  142. data/lib/robot_lab/state_proxy.rb +2 -12
  143. data/lib/robot_lab/streaming/context.rb +1 -1
  144. data/lib/robot_lab/task.rb +8 -1
  145. data/lib/robot_lab/tool.rb +108 -172
  146. data/lib/robot_lab/tool_config.rb +1 -1
  147. data/lib/robot_lab/tool_manifest.rb +2 -18
  148. data/lib/robot_lab/utils.rb +39 -0
  149. data/lib/robot_lab/version.rb +1 -1
  150. data/lib/robot_lab.rb +89 -57
  151. data/mkdocs.yml +0 -11
  152. metadata +121 -135
  153. data/docs/api/adapters/anthropic.md +0 -121
  154. data/docs/api/adapters/gemini.md +0 -133
  155. data/docs/api/adapters/index.md +0 -104
  156. data/docs/api/adapters/openai.md +0 -134
  157. data/docs/api/history/active-record-adapter.md +0 -195
  158. data/docs/api/history/config.md +0 -191
  159. data/docs/api/history/index.md +0 -132
  160. data/docs/api/history/thread-manager.md +0 -144
  161. data/docs/guides/history.md +0 -359
  162. data/examples/prompts/assistant/user.txt.erb +0 -1
  163. data/examples/prompts/billing/user.txt.erb +0 -1
  164. data/examples/prompts/classifier/user.txt.erb +0 -1
  165. data/examples/prompts/entity_extractor/user.txt.erb +0 -3
  166. data/examples/prompts/escalation/user.txt.erb +0 -34
  167. data/examples/prompts/general/user.txt.erb +0 -1
  168. data/examples/prompts/github_assistant/user.txt.erb +0 -1
  169. data/examples/prompts/helper/user.txt.erb +0 -1
  170. data/examples/prompts/keyword_extractor/user.txt.erb +0 -3
  171. data/examples/prompts/order_support/user.txt.erb +0 -22
  172. data/examples/prompts/product_support/user.txt.erb +0 -32
  173. data/examples/prompts/sentiment_analyzer/user.txt.erb +0 -3
  174. data/examples/prompts/synthesizer/user.txt.erb +0 -15
  175. data/examples/prompts/technical/user.txt.erb +0 -1
  176. data/examples/prompts/triage/user.txt.erb +0 -17
  177. data/lib/robot_lab/adapters/anthropic.rb +0 -163
  178. data/lib/robot_lab/adapters/base.rb +0 -85
  179. data/lib/robot_lab/adapters/gemini.rb +0 -193
  180. data/lib/robot_lab/adapters/openai.rb +0 -159
  181. data/lib/robot_lab/adapters/registry.rb +0 -81
  182. data/lib/robot_lab/configuration.rb +0 -143
  183. data/lib/robot_lab/errors.rb +0 -70
  184. data/lib/robot_lab/history/active_record_adapter.rb +0 -146
  185. data/lib/robot_lab/history/config.rb +0 -115
  186. data/lib/robot_lab/history/thread_manager.rb +0 -93
  187. data/lib/robot_lab/robotic_model.rb +0 -324
@@ -1,132 +0,0 @@
1
- # History
2
-
3
- Conversation persistence and thread management.
4
-
5
- ## Overview
6
-
7
- The history system enables persistent conversations by storing and retrieving conversation threads and results.
8
-
9
- ```ruby
10
- network = RobotLab.create_network do
11
- name "persistent_chat"
12
-
13
- history History::Config.new(
14
- create_thread: ->(state:, **) { Thread.create(id: SecureRandom.uuid) },
15
- get: ->(thread_id:, **) { Thread.find(thread_id).results },
16
- append_results: ->(thread_id:, new_results:, **) {
17
- Thread.find(thread_id).results.concat(new_results)
18
- }
19
- )
20
-
21
- add_robot assistant
22
- end
23
- ```
24
-
25
- ## Components
26
-
27
- | Component | Description |
28
- |-----------|-------------|
29
- | [Config](config.md) | History configuration |
30
- | [ThreadManager](thread-manager.md) | Thread lifecycle management |
31
- | [ActiveRecordAdapter](active-record-adapter.md) | Rails integration |
32
-
33
- ## Quick Start
34
-
35
- ### Basic Configuration
36
-
37
- ```ruby
38
- history = History::Config.new(
39
- create_thread: ->(state:, input:, **) {
40
- { id: SecureRandom.uuid }
41
- },
42
- get: ->(thread_id:, **) {
43
- STORE[thread_id] || []
44
- },
45
- append_results: ->(thread_id:, new_results:, **) {
46
- STORE[thread_id] ||= []
47
- STORE[thread_id].concat(new_results)
48
- }
49
- )
50
- ```
51
-
52
- ### With ActiveRecord
53
-
54
- ```ruby
55
- history = History::ActiveRecordAdapter.new(
56
- thread_model: ConversationThread,
57
- result_model: ConversationResult
58
- ).to_config
59
- ```
60
-
61
- ## Callbacks
62
-
63
- | Callback | Purpose |
64
- |----------|---------|
65
- | `create_thread` | Create new conversation thread |
66
- | `get` | Retrieve existing thread history |
67
- | `append_results` | Add results to thread |
68
-
69
- ## Thread Lifecycle
70
-
71
- ```mermaid
72
- sequenceDiagram
73
- participant U as User
74
- participant N as Network
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
- ```
85
-
86
- ## Examples
87
-
88
- ### In-Memory Store
89
-
90
- ```ruby
91
- THREADS = {}
92
-
93
- history = History::Config.new(
94
- create_thread: ->(state:, **) {
95
- id = SecureRandom.uuid
96
- THREADS[id] = []
97
- { id: id }
98
- },
99
- get: ->(thread_id:, **) {
100
- THREADS[thread_id] || []
101
- },
102
- append_results: ->(thread_id:, new_results:, **) {
103
- THREADS[thread_id].concat(new_results)
104
- }
105
- )
106
- ```
107
-
108
- ### Redis Store
109
-
110
- ```ruby
111
- history = History::Config.new(
112
- create_thread: ->(state:, **) {
113
- id = SecureRandom.uuid
114
- Redis.current.set("thread:#{id}", [].to_json)
115
- { id: id }
116
- },
117
- get: ->(thread_id:, **) {
118
- data = Redis.current.get("thread:#{thread_id}")
119
- data ? JSON.parse(data) : []
120
- },
121
- append_results: ->(thread_id:, new_results:, **) {
122
- existing = JSON.parse(Redis.current.get("thread:#{thread_id}") || "[]")
123
- existing.concat(new_results.map(&:to_h))
124
- Redis.current.set("thread:#{thread_id}", existing.to_json)
125
- }
126
- )
127
- ```
128
-
129
- ## See Also
130
-
131
- - [History Guide](../../guides/history.md)
132
- - [State](../core/state.md)
@@ -1,144 +0,0 @@
1
- # ThreadManager
2
-
3
- Manages conversation thread lifecycle.
4
-
5
- ## Class: `RobotLab::History::ThreadManager`
6
-
7
- ```ruby
8
- manager = History::ThreadManager.new(config: history_config)
9
- ```
10
-
11
- ## Constructor
12
-
13
- ```ruby
14
- ThreadManager.new(config:)
15
- ```
16
-
17
- **Parameters:**
18
-
19
- | Name | Type | Description |
20
- |------|------|-------------|
21
- | `config` | `Config` | History configuration |
22
-
23
- ## Methods
24
-
25
- ### create_thread
26
-
27
- ```ruby
28
- thread_info = manager.create_thread(state: state, input: input, **context)
29
- ```
30
-
31
- Create a new conversation thread.
32
-
33
- **Returns:** Hash with `:id` and optional metadata.
34
-
35
- ### get_history
36
-
37
- ```ruby
38
- results = manager.get_history(thread_id: id, **context)
39
- ```
40
-
41
- Retrieve conversation history.
42
-
43
- **Returns:** Array of `RobotResult`.
44
-
45
- ### append_results
46
-
47
- ```ruby
48
- manager.append_results(thread_id: id, new_results: results, **context)
49
- ```
50
-
51
- Add results to a thread.
52
-
53
- ### ensure_thread
54
-
55
- ```ruby
56
- thread_id = manager.ensure_thread(state: state, input: input, **context)
57
- ```
58
-
59
- Create thread if state doesn't have one, or return existing.
60
-
61
- ### load_history
62
-
63
- ```ruby
64
- state = manager.load_history(state: state, **context)
65
- ```
66
-
67
- Load history into state if thread_id exists.
68
-
69
- ## Examples
70
-
71
- ### Basic Usage
72
-
73
- ```ruby
74
- config = History::Config.new(...)
75
- manager = History::ThreadManager.new(config: config)
76
-
77
- # Start new conversation
78
- state = RobotLab.create_state(message: "Hello")
79
- thread_id = manager.ensure_thread(state: state, input: "Hello")
80
- state.thread_id = thread_id
81
-
82
- # Run and save
83
- result = network.run(state: state)
84
- manager.append_results(thread_id: thread_id, new_results: result.new_results)
85
-
86
- # Continue conversation
87
- state2 = RobotLab.create_state(message: "Follow up")
88
- state2.thread_id = thread_id
89
- state2 = manager.load_history(state: state2)
90
- # state2 now has previous results
91
- ```
92
-
93
- ### In Network
94
-
95
- ```ruby
96
- # ThreadManager is used internally by Network
97
- network = RobotLab.create_network do
98
- history config
99
- add_robot assistant
100
- end
101
-
102
- # First message - thread created automatically
103
- result1 = network.run(state: state1)
104
- thread_id = result1.state.thread_id
105
-
106
- # Continue - history loaded automatically
107
- state2 = RobotLab.create_state(
108
- message: UserMessage.new("Continue", thread_id: thread_id)
109
- )
110
- result2 = network.run(state: state2)
111
- ```
112
-
113
- ### Custom Thread Data
114
-
115
- ```ruby
116
- manager = History::ThreadManager.new(
117
- config: History::Config.new(
118
- create_thread: ->(state:, input:, metadata:, **) {
119
- Thread.create(
120
- title: input.truncate(50),
121
- metadata: metadata,
122
- created_at: Time.current
123
- )
124
- },
125
- get: ->(thread_id:, **) { Thread.find(thread_id).results },
126
- append_results: ->(thread_id:, new_results:, **) {
127
- Thread.find(thread_id).results.concat(new_results)
128
- }
129
- )
130
- )
131
-
132
- # Pass metadata when creating thread
133
- thread = manager.create_thread(
134
- state: state,
135
- input: "Help with billing",
136
- metadata: { source: "web", priority: "high" }
137
- )
138
- ```
139
-
140
- ## See Also
141
-
142
- - [History Overview](index.md)
143
- - [Config](config.md)
144
- - [ActiveRecordAdapter](active-record-adapter.md)
@@ -1,359 +0,0 @@
1
- # Conversation History
2
-
3
- Persist and restore conversation threads across sessions.
4
-
5
- ## Overview
6
-
7
- History allows you to:
8
-
9
- - Save conversation results to a database
10
- - Restore previous conversations
11
- - Continue multi-turn interactions
12
- - Maintain context across sessions
13
-
14
- ## Configuration
15
-
16
- ### History Config
17
-
18
- Configure history with callbacks:
19
-
20
- ```ruby
21
- history_config = RobotLab::History::Config.new(
22
- create_thread: ->(state:, input:, **) {
23
- # Create a new thread, return thread_id
24
- { thread_id: SecureRandom.uuid }
25
- },
26
-
27
- get: ->(thread_id:, **) {
28
- # Retrieve history for thread
29
- # Return Array<RobotResult>
30
- []
31
- },
32
-
33
- append_user_message: ->(thread_id:, message:, **) {
34
- # Optional: Store user message
35
- },
36
-
37
- append_results: ->(thread_id:, new_results:, **) {
38
- # Store new results
39
- }
40
- )
41
- ```
42
-
43
- ### Apply to Network
44
-
45
- ```ruby
46
- network = RobotLab.create_network do
47
- name "persistent_chat"
48
- history history_config
49
- end
50
- ```
51
-
52
- ## Callback Reference
53
-
54
- ### create_thread
55
-
56
- Called when starting a new conversation:
57
-
58
- ```ruby
59
- create_thread: ->(state:, input:, **kwargs) {
60
- # state - Current State object
61
- # input - UserMessage or string
62
- # kwargs - Additional context
63
-
64
- thread = Thread.create!(
65
- initial_input: input.to_s,
66
- user_id: state.data[:user_id]
67
- )
68
-
69
- { thread_id: thread.id.to_s } # Must return hash with :thread_id
70
- }
71
- ```
72
-
73
- ### get
74
-
75
- Called to retrieve existing history:
76
-
77
- ```ruby
78
- get: ->(thread_id:, **kwargs) {
79
- # thread_id - The thread identifier
80
- # kwargs - Additional context
81
-
82
- Result.where(thread_id: thread_id)
83
- .order(:created_at)
84
- .map { |r| deserialize_result(r) }
85
-
86
- # Must return Array<RobotResult>
87
- }
88
- ```
89
-
90
- ### append_user_message (Optional)
91
-
92
- Called when a user message is added:
93
-
94
- ```ruby
95
- append_user_message: ->(thread_id:, message:, **kwargs) {
96
- # thread_id - The thread identifier
97
- # message - UserMessage object
98
-
99
- Message.create!(
100
- thread_id: thread_id,
101
- content: message.content,
102
- metadata: message.metadata
103
- )
104
- }
105
- ```
106
-
107
- ### append_results
108
-
109
- Called after robots finish:
110
-
111
- ```ruby
112
- append_results: ->(thread_id:, new_results:, **kwargs) {
113
- # thread_id - The thread identifier
114
- # new_results - Array<RobotResult>
115
-
116
- new_results.each do |result|
117
- Result.create!(
118
- thread_id: thread_id,
119
- robot_name: result.robot_name,
120
- output_data: serialize_output(result.output),
121
- stop_reason: result.stop_reason
122
- )
123
- end
124
- }
125
- ```
126
-
127
- ## ActiveRecord Adapter
128
-
129
- RobotLab includes a built-in ActiveRecord adapter:
130
-
131
- ```ruby
132
- adapter = RobotLab::History::ActiveRecordAdapter.new(
133
- thread_model: RobotLabThread,
134
- result_model: RobotLabResult
135
- )
136
-
137
- network = RobotLab.create_network do
138
- history adapter.to_config
139
- end
140
- ```
141
-
142
- ### Required Models
143
-
144
- ```ruby title="app/models/robot_lab_thread.rb"
145
- class RobotLabThread < ApplicationRecord
146
- has_many :results, class_name: "RobotLabResult", foreign_key: :thread_id
147
-
148
- # Required columns:
149
- # - thread_id: string
150
- # - initial_input: text
151
- # - input_metadata: jsonb
152
- # - state_data: jsonb
153
- # - last_user_message: text
154
- # - last_user_message_at: datetime
155
- end
156
- ```
157
-
158
- ```ruby title="app/models/robot_lab_result.rb"
159
- class RobotLabResult < ApplicationRecord
160
- belongs_to :thread, class_name: "RobotLabThread", foreign_key: :thread_id
161
-
162
- # Required columns:
163
- # - thread_id: string
164
- # - robot_name: string
165
- # - sequence_number: integer
166
- # - output_data: jsonb
167
- # - tool_calls_data: jsonb
168
- # - stop_reason: string
169
- # - checksum: string
170
- end
171
- ```
172
-
173
- ## Using Thread IDs
174
-
175
- ### Start New Thread
176
-
177
- ```ruby
178
- state = RobotLab.create_state(message: "Hello!")
179
- result = network.run(state: state)
180
-
181
- # Thread ID is assigned automatically
182
- thread_id = state.thread_id
183
- ```
184
-
185
- ### Continue Existing Thread
186
-
187
- ```ruby
188
- # Option 1: Via UserMessage
189
- message = RobotLab::UserMessage.new(
190
- "Continue our conversation",
191
- thread_id: existing_thread_id
192
- )
193
- state = RobotLab.create_state(message: message)
194
-
195
- # Option 2: Direct assignment
196
- state = RobotLab.create_state(message: "Continue")
197
- state.thread_id = existing_thread_id
198
-
199
- # History is automatically loaded
200
- result = network.run(state: state)
201
- ```
202
-
203
- ## ThreadManager
204
-
205
- For programmatic control:
206
-
207
- ```ruby
208
- manager = RobotLab::History::ThreadManager.new(history_config)
209
-
210
- # Create thread
211
- thread_id = manager.create_thread(state: state, input: message)
212
-
213
- # Load history
214
- results = manager.get_history(thread_id)
215
-
216
- # Save state
217
- manager.save_state(thread_id: thread_id, state: state, since_index: 5)
218
- ```
219
-
220
- ## Serialization
221
-
222
- ### RobotResult
223
-
224
- Results are serialized via `export`:
225
-
226
- ```ruby
227
- result.export
228
- # => {
229
- # robot_name: "assistant",
230
- # output: [...],
231
- # tool_calls: [...],
232
- # stop_reason: "stop",
233
- # id: "...",
234
- # created_at: "..."
235
- # }
236
- ```
237
-
238
- ### Messages
239
-
240
- Messages serialize to hashes:
241
-
242
- ```ruby
243
- message.to_h
244
- # => {
245
- # type: "text",
246
- # role: "assistant",
247
- # content: "Hello!",
248
- # stop_reason: "stop"
249
- # }
250
- ```
251
-
252
- ### Restore from hash
253
-
254
- ```ruby
255
- RobotLab::Message.from_hash(hash)
256
- ```
257
-
258
- ## Patterns
259
-
260
- ### Redis-Based History
261
-
262
- ```ruby
263
- history_config = History::Config.new(
264
- create_thread: ->(state:, input:, **) {
265
- thread_id = SecureRandom.uuid
266
- Redis.current.hset("threads", thread_id, input.to_s)
267
- { thread_id: thread_id }
268
- },
269
-
270
- get: ->(thread_id:, **) {
271
- data = Redis.current.lrange("results:#{thread_id}", 0, -1)
272
- data.map { |json| deserialize_result(JSON.parse(json)) }
273
- },
274
-
275
- append_results: ->(thread_id:, new_results:, **) {
276
- new_results.each do |result|
277
- Redis.current.rpush("results:#{thread_id}", result.export.to_json)
278
- end
279
- }
280
- )
281
- ```
282
-
283
- ### Custom Storage
284
-
285
- ```ruby
286
- class CustomHistoryAdapter
287
- def initialize(storage)
288
- @storage = storage
289
- end
290
-
291
- def to_config
292
- History::Config.new(
293
- create_thread: method(:create_thread),
294
- get: method(:get),
295
- append_results: method(:append_results)
296
- )
297
- end
298
-
299
- private
300
-
301
- def create_thread(state:, input:, **)
302
- id = @storage.create_conversation(input: input.to_s)
303
- { thread_id: id }
304
- end
305
-
306
- def get(thread_id:, **)
307
- @storage.fetch_results(thread_id)
308
- end
309
-
310
- def append_results(thread_id:, new_results:, **)
311
- @storage.store_results(thread_id, new_results)
312
- end
313
- end
314
- ```
315
-
316
- ## Best Practices
317
-
318
- ### 1. Handle Missing Threads
319
-
320
- ```ruby
321
- get: ->(thread_id:, **) {
322
- thread = Thread.find_by(thread_id: thread_id)
323
- return [] unless thread
324
-
325
- thread.results.order(:created_at).map(&:to_robot_result)
326
- }
327
- ```
328
-
329
- ### 2. Index for Performance
330
-
331
- ```sql
332
- CREATE INDEX idx_results_thread_id ON robot_lab_results(thread_id);
333
- CREATE INDEX idx_results_created_at ON robot_lab_results(created_at);
334
- ```
335
-
336
- ### 3. Clean Up Old Threads
337
-
338
- ```ruby
339
- # Periodic cleanup job
340
- Thread.where("updated_at < ?", 30.days.ago).destroy_all
341
- ```
342
-
343
- ### 4. Limit History Size
344
-
345
- ```ruby
346
- get: ->(thread_id:, **) {
347
- Result.where(thread_id: thread_id)
348
- .order(created_at: :desc)
349
- .limit(50) # Last 50 exchanges
350
- .reverse
351
- .map(&:to_robot_result)
352
- }
353
- ```
354
-
355
- ## Next Steps
356
-
357
- - [Memory System](memory.md) - In-memory data sharing
358
- - [State Management](../architecture/state-management.md) - State details
359
- - [API Reference: History](../api/history/index.md) - Complete API
@@ -1 +0,0 @@
1
- <%= message %>
@@ -1 +0,0 @@
1
- <%= message %>
@@ -1 +0,0 @@
1
- <%= message %>
@@ -1,3 +0,0 @@
1
- Extract all named entities from this text:
2
-
3
- <%= message %>
@@ -1,34 +0,0 @@
1
- Customer <%= customer[:name] %> (escalated case): <%= message %>
2
-
3
- ## Case Context
4
- <% if defined?(escalation_context) && escalation_context %>
5
- <% if escalation_context[:previous_interactions]&.any? %>
6
- ### Previous Interactions
7
- <% escalation_context[:previous_interactions].each do |interaction| %>
8
- - <%= interaction[:date] %> (<%= interaction[:channel] %>): <%= interaction[:summary] %>
9
- <% end %>
10
- <% end %>
11
-
12
- <% if escalation_context[:related_orders]&.any? %>
13
- ### Related Orders
14
- <% escalation_context[:related_orders].each do |order| %>
15
- - Order #<%= order[:id] %>: $<%= order[:total] %> - <%= order[:status] %>
16
- <% end %>
17
- <% end %>
18
-
19
- <% if escalation_context[:compensation_history]&.any? %>
20
- ### Previous Compensation
21
- <% escalation_context[:compensation_history].each do |comp| %>
22
- - <%= comp[:date] %>: <%= comp[:type] %> - $<%= comp[:amount] %> (<%= comp[:reason] %>)
23
- <% end %>
24
- <% end %>
25
-
26
- ### Escalation Reason
27
- <%= escalation_context[:escalation_reason] || "Not specified" %>
28
-
29
- ### Sentiment Analysis
30
- - Detected Sentiment: <%= escalation_context[:sentiment] || "Unknown" %>
31
- - Urgency Level: <%= escalation_context[:urgency] || "Normal" %>
32
- <% end %>
33
-
34
- Please resolve this escalated case with empathy and authority.
@@ -1 +0,0 @@
1
- <%= message %>
@@ -1 +0,0 @@
1
- <%= message %>
@@ -1 +0,0 @@
1
- <%= message %>
@@ -1,3 +0,0 @@
1
- Extract keywords and topics from this text:
2
-
3
- <%= message %>
@@ -1,22 +0,0 @@
1
- Customer <%= customer[:name] %> asks: <%= message %>
2
-
3
- ## Order History
4
- <% if orders&.any? %>
5
- <% orders.each do |order| %>
6
- ### Order #<%= order[:id] %>
7
- - Date: <%= order[:date] %>
8
- - Status: <%= order[:status] %>
9
- - Total: $<%= order[:total] %>
10
- - Items:
11
- <% order[:items].each do |item| %>
12
- - <%= item[:name] %> (x<%= item[:quantity] %>) - $<%= item[:price] %>
13
- <% end %>
14
- <% if order[:tracking] %>
15
- - Tracking: <%= order[:tracking] %>
16
- <% end %>
17
- <% end %>
18
- <% else %>
19
- No orders found for this customer.
20
- <% end %>
21
-
22
- Please help the customer with their order inquiry.