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,104 +0,0 @@
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)
@@ -1,134 +0,0 @@
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/)
@@ -1,195 +0,0 @@
1
- # ActiveRecordAdapter
2
-
3
- Rails ActiveRecord integration for conversation persistence.
4
-
5
- ## Class: `RobotLab::History::ActiveRecordAdapter`
6
-
7
- ```ruby
8
- adapter = History::ActiveRecordAdapter.new(
9
- thread_model: ConversationThread,
10
- result_model: ConversationResult
11
- )
12
-
13
- config = adapter.to_config
14
- ```
15
-
16
- ## Constructor
17
-
18
- ```ruby
19
- ActiveRecordAdapter.new(
20
- thread_model:,
21
- result_model:,
22
- thread_factory: nil,
23
- result_factory: nil
24
- )
25
- ```
26
-
27
- **Parameters:**
28
-
29
- | Name | Type | Description |
30
- |------|------|-------------|
31
- | `thread_model` | `Class` | ActiveRecord model for threads |
32
- | `result_model` | `Class` | ActiveRecord model for results |
33
- | `thread_factory` | `Proc`, `nil` | Custom thread creation |
34
- | `result_factory` | `Proc`, `nil` | Custom result creation |
35
-
36
- ## Methods
37
-
38
- ### to_config
39
-
40
- ```ruby
41
- config = adapter.to_config
42
- ```
43
-
44
- Convert to `History::Config` for use with networks.
45
-
46
- ## Model Requirements
47
-
48
- ### Thread Model
49
-
50
- ```ruby
51
- # db/migrate/xxx_create_conversation_threads.rb
52
- create_table :conversation_threads do |t|
53
- t.string :external_id, null: false, index: { unique: true }
54
- t.jsonb :metadata, default: {}
55
- t.timestamps
56
- 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
- ```
64
-
65
- ### Result Model
66
-
67
- ```ruby
68
- # db/migrate/xxx_create_conversation_results.rb
69
- create_table :conversation_results do |t|
70
- t.references :thread, foreign_key: { to_table: :conversation_threads }
71
- t.string :robot_name
72
- t.jsonb :input, default: {}
73
- t.jsonb :output, default: []
74
- t.jsonb :tool_calls, default: []
75
- t.jsonb :metadata, default: {}
76
- t.integer :position
77
- t.timestamps
78
- 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
- ```
89
-
90
- ## Examples
91
-
92
- ### Basic Setup
93
-
94
- ```ruby
95
- adapter = History::ActiveRecordAdapter.new(
96
- thread_model: ConversationThread,
97
- result_model: ConversationResult
98
- )
99
-
100
- network = RobotLab.create_network do
101
- name "chat"
102
- history adapter.to_config
103
- add_robot assistant
104
- end
105
- ```
106
-
107
- ### With Custom Factory
108
-
109
- ```ruby
110
- adapter = History::ActiveRecordAdapter.new(
111
- thread_model: ConversationThread,
112
- result_model: ConversationResult,
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
- }
121
- )
122
- ```
123
-
124
- ### With User Scoping
125
-
126
- ```ruby
127
- class ScopedAdapter
128
- def initialize(thread_model:, result_model:)
129
- @thread_model = thread_model
130
- @result_model = result_model
131
- end
132
-
133
- def to_config
134
- History::Config.new(
135
- create_thread: method(:create_thread),
136
- get: method(:get),
137
- append_results: method(:append_results)
138
- )
139
- end
140
-
141
- private
142
-
143
- def create_thread(state:, input:, user_id:, **)
144
- @thread_model.create!(
145
- external_id: SecureRandom.uuid,
146
- user_id: user_id,
147
- title: input.truncate(100)
148
- )
149
- end
150
-
151
- def get(thread_id:, user_id:, **)
152
- thread = @thread_model.find_by(external_id: thread_id, user_id: user_id)
153
- return [] unless thread
154
- thread.results.order(:position).map(&:to_robot_result)
155
- end
156
-
157
- def append_results(thread_id:, new_results:, user_id:, **)
158
- thread = @thread_model.find_by!(external_id: thread_id, user_id: user_id)
159
- position = thread.results.maximum(:position) || 0
160
-
161
- @result_model.transaction do
162
- new_results.each_with_index do |result, i|
163
- thread.results.create!(
164
- robot_name: result.robot_name,
165
- input: result.input.to_h,
166
- output: result.output.map(&:to_h),
167
- tool_calls: result.tool_calls.map(&:to_h),
168
- position: position + i + 1
169
- )
170
- end
171
- end
172
- end
173
- end
174
- ```
175
-
176
- ### Rails Generator
177
-
178
- Use the Rails generator to create models:
179
-
180
- ```bash
181
- rails generate robot_lab:history
182
- ```
183
-
184
- This creates:
185
-
186
- - `ConversationThread` model
187
- - `ConversationResult` model
188
- - Database migrations
189
- - Initializer configuration
190
-
191
- ## See Also
192
-
193
- - [History Overview](index.md)
194
- - [Config](config.md)
195
- - [Rails Integration Guide](../../guides/rails-integration.md)
@@ -1,191 +0,0 @@
1
- # History::Config
2
-
3
- Configuration for conversation persistence.
4
-
5
- ## Class: `RobotLab::History::Config`
6
-
7
- ```ruby
8
- config = History::Config.new(
9
- create_thread: create_proc,
10
- get: get_proc,
11
- append_results: append_proc
12
- )
13
- ```
14
-
15
- ## Constructor
16
-
17
- ```ruby
18
- Config.new(
19
- create_thread:,
20
- get:,
21
- append_results:
22
- )
23
- ```
24
-
25
- **Parameters:**
26
-
27
- | Name | Type | Description |
28
- |------|------|-------------|
29
- | `create_thread` | `Proc` | Creates a new thread |
30
- | `get` | `Proc` | Retrieves thread history |
31
- | `append_results` | `Proc` | Appends results to thread |
32
-
33
- ## Callbacks
34
-
35
- ### create_thread
36
-
37
- Called when a new conversation starts without a thread_id.
38
-
39
- ```ruby
40
- create_thread: ->(state:, input:, **context) {
41
- # Create and return thread info
42
- { id: SecureRandom.uuid }
43
- }
44
- ```
45
-
46
- **Arguments:**
47
-
48
- | Name | Type | Description |
49
- |------|------|-------------|
50
- | `state` | `State` | Current state |
51
- | `input` | `String` | User input |
52
- | `**context` | `Hash` | Additional context |
53
-
54
- **Returns:** Hash with `:id` key.
55
-
56
- ### get
57
-
58
- Called to retrieve existing conversation history.
59
-
60
- ```ruby
61
- get: ->(thread_id:, **context) {
62
- # Return array of previous results
63
- Thread.find(thread_id).results
64
- }
65
- ```
66
-
67
- **Arguments:**
68
-
69
- | Name | Type | Description |
70
- |------|------|-------------|
71
- | `thread_id` | `String` | Thread identifier |
72
- | `**context` | `Hash` | Additional context |
73
-
74
- **Returns:** Array of `RobotResult` or hashes.
75
-
76
- ### append_results
77
-
78
- Called after each network run to persist new results.
79
-
80
- ```ruby
81
- append_results: ->(thread_id:, new_results:, **context) {
82
- # Persist the new results
83
- thread = Thread.find(thread_id)
84
- new_results.each { |r| thread.results.create(r.to_h) }
85
- }
86
- ```
87
-
88
- **Arguments:**
89
-
90
- | Name | Type | Description |
91
- |------|------|-------------|
92
- | `thread_id` | `String` | Thread identifier |
93
- | `new_results` | `Array<RobotResult>` | Results to append |
94
- | `**context` | `Hash` | Additional context |
95
-
96
- ## Attributes
97
-
98
- ### create_thread
99
-
100
- ```ruby
101
- config.create_thread # => Proc
102
- ```
103
-
104
- ### get
105
-
106
- ```ruby
107
- config.get # => Proc
108
- ```
109
-
110
- ### append_results
111
-
112
- ```ruby
113
- config.append_results # => Proc
114
- ```
115
-
116
- ## Examples
117
-
118
- ### Basic Config
119
-
120
- ```ruby
121
- STORE = {}
122
-
123
- config = History::Config.new(
124
- create_thread: ->(state:, **) {
125
- id = SecureRandom.uuid
126
- STORE[id] = { results: [] }
127
- { id: id }
128
- },
129
-
130
- get: ->(thread_id:, **) {
131
- STORE.dig(thread_id, :results) || []
132
- },
133
-
134
- append_results: ->(thread_id:, new_results:, **) {
135
- STORE[thread_id][:results].concat(new_results.map(&:to_h))
136
- }
137
- )
138
- ```
139
-
140
- ### With Context
141
-
142
- ```ruby
143
- config = History::Config.new(
144
- create_thread: ->(state:, user_id:, **) {
145
- Thread.create(user_id: user_id, started_at: Time.current)
146
- },
147
-
148
- get: ->(thread_id:, user_id:, **) {
149
- Thread.where(id: thread_id, user_id: user_id).first&.results || []
150
- },
151
-
152
- append_results: ->(thread_id:, new_results:, user_id:, **) {
153
- thread = Thread.find_by(id: thread_id, user_id: user_id)
154
- 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
183
- }
184
- )
185
- ```
186
-
187
- ## See Also
188
-
189
- - [History Overview](index.md)
190
- - [ThreadManager](thread-manager.md)
191
- - [ActiveRecordAdapter](active-record-adapter.md)