robot_lab 0.0.4 → 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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -0
  3. data/README.md +64 -6
  4. data/Rakefile +2 -1
  5. data/docs/api/core/index.md +41 -46
  6. data/docs/api/core/memory.md +200 -154
  7. data/docs/api/core/network.md +13 -3
  8. data/docs/api/core/robot.md +38 -26
  9. data/docs/api/core/state.md +55 -73
  10. data/docs/api/index.md +7 -28
  11. data/docs/api/messages/index.md +35 -20
  12. data/docs/api/messages/text-message.md +67 -21
  13. data/docs/api/messages/tool-call-message.md +80 -41
  14. data/docs/api/messages/tool-result-message.md +119 -50
  15. data/docs/api/messages/user-message.md +48 -24
  16. data/docs/architecture/core-concepts.md +10 -15
  17. data/docs/concepts.md +5 -7
  18. data/docs/examples/index.md +2 -2
  19. data/docs/getting-started/configuration.md +80 -0
  20. data/docs/guides/building-robots.md +10 -9
  21. data/docs/guides/creating-networks.md +49 -0
  22. data/docs/guides/index.md +0 -5
  23. data/docs/guides/rails-integration.md +244 -162
  24. data/docs/guides/streaming.md +118 -138
  25. data/docs/index.md +0 -8
  26. data/examples/03_network.rb +10 -7
  27. data/examples/08_llm_config.rb +40 -11
  28. data/examples/09_chaining.rb +45 -6
  29. data/examples/11_network_introspection.rb +30 -7
  30. data/examples/12_message_bus.rb +1 -1
  31. data/examples/14_rusty_circuit/heckler.rb +14 -8
  32. data/examples/14_rusty_circuit/open_mic.rb +5 -3
  33. data/examples/14_rusty_circuit/scout.rb +14 -31
  34. data/examples/15_memory_network_and_bus/editorial_pipeline.rb +1 -1
  35. data/examples/16_writers_room/display.rb +158 -0
  36. data/examples/16_writers_room/output/.gitignore +2 -0
  37. data/examples/16_writers_room/output/opus_001.md +263 -0
  38. data/examples/16_writers_room/output/opus_001_notes.log +470 -0
  39. data/examples/16_writers_room/prompts/writer.md +37 -0
  40. data/examples/16_writers_room/room.rb +150 -0
  41. data/examples/16_writers_room/tools.rb +162 -0
  42. data/examples/16_writers_room/writer.rb +121 -0
  43. data/examples/16_writers_room/writers_room.rb +162 -0
  44. data/lib/generators/robot_lab/templates/initializer.rb.tt +0 -13
  45. data/lib/robot_lab/memory.rb +8 -32
  46. data/lib/robot_lab/network.rb +13 -20
  47. data/lib/robot_lab/robot/bus_messaging.rb +239 -0
  48. data/lib/robot_lab/robot/mcp_management.rb +88 -0
  49. data/lib/robot_lab/robot/template_rendering.rb +130 -0
  50. data/lib/robot_lab/robot.rb +56 -420
  51. data/lib/robot_lab/run_config.rb +184 -0
  52. data/lib/robot_lab/state_proxy.rb +2 -12
  53. data/lib/robot_lab/task.rb +8 -1
  54. data/lib/robot_lab/utils.rb +39 -0
  55. data/lib/robot_lab/version.rb +1 -1
  56. data/lib/robot_lab.rb +29 -8
  57. data/mkdocs.yml +0 -11
  58. metadata +15 -20
  59. data/docs/api/adapters/anthropic.md +0 -121
  60. data/docs/api/adapters/gemini.md +0 -133
  61. data/docs/api/adapters/index.md +0 -104
  62. data/docs/api/adapters/openai.md +0 -134
  63. data/docs/api/history/active-record-adapter.md +0 -275
  64. data/docs/api/history/config.md +0 -284
  65. data/docs/api/history/index.md +0 -128
  66. data/docs/api/history/thread-manager.md +0 -194
  67. data/docs/guides/history.md +0 -359
  68. data/lib/robot_lab/adapters/anthropic.rb +0 -163
  69. data/lib/robot_lab/adapters/base.rb +0 -85
  70. data/lib/robot_lab/adapters/gemini.rb +0 -193
  71. data/lib/robot_lab/adapters/openai.rb +0 -160
  72. data/lib/robot_lab/adapters/registry.rb +0 -81
  73. data/lib/robot_lab/errors.rb +0 -70
  74. data/lib/robot_lab/history/active_record_adapter.rb +0 -146
  75. data/lib/robot_lab/history/config.rb +0 -115
  76. data/lib/robot_lab/history/thread_manager.rb +0 -93
  77. data/lib/robot_lab/robotic_model.rb +0 -324
@@ -1,133 +0,0 @@
1
- # Gemini Adapter
2
-
3
- Adapter for Gemini models via Google AI API.
4
-
5
- ## Class: `RobotLab::Adapters::Gemini`
6
-
7
- ```ruby
8
- # Automatically used for Gemini models
9
- robot = RobotLab.build do
10
- model "gemini-1.5-pro"
11
- end
12
- ```
13
-
14
- ## Supported Models
15
-
16
- | Model | Description |
17
- |-------|-------------|
18
- | `gemini-1.5-pro` | Most capable Gemini |
19
- | `gemini-1.5-flash` | Fast, efficient model |
20
- | `gemini-1.5-flash-8b` | Lightweight model |
21
- | `gemini-2.0-flash-exp` | Experimental next-gen |
22
-
23
- ## Configuration
24
-
25
- ### API Key
26
-
27
- ```bash
28
- export GOOGLE_AI_API_KEY="..."
29
- ```
30
-
31
- ### Options
32
-
33
- ```ruby
34
- RobotLab.configure do |config|
35
- config.adapter_options = {
36
- gemini: {
37
- base_url: "https://generativelanguage.googleapis.com",
38
- timeout: 120,
39
- max_tokens: 8192
40
- }
41
- }
42
- end
43
- ```
44
-
45
- ### Vertex AI
46
-
47
- ```ruby
48
- RobotLab.configure do |config|
49
- config.adapter_options = {
50
- gemini: {
51
- base_url: "https://us-central1-aiplatform.googleapis.com",
52
- project_id: "your-project",
53
- location: "us-central1"
54
- }
55
- }
56
- end
57
- ```
58
-
59
- ## Features
60
-
61
- ### Streaming
62
-
63
- ```ruby
64
- result = robot.run(state: state) do |event|
65
- case event
66
- when :text_delta
67
- print event.text
68
- when :tool_call
69
- puts "Calling: #{event.name}"
70
- end
71
- end
72
- ```
73
-
74
- ### Tool Use
75
-
76
- Tools are automatically converted to Gemini's format:
77
-
78
- ```ruby
79
- robot = RobotLab.build do
80
- model "gemini-1.5-pro"
81
-
82
- tool :search_products do
83
- description "Search product catalog"
84
- parameter :query, type: :string, required: true
85
- parameter :category, type: :string
86
- handler { |query:, category: nil, **_| Catalog.search(query, category) }
87
- end
88
- end
89
- ```
90
-
91
- ### Long Context
92
-
93
- Gemini supports very long contexts:
94
-
95
- ```ruby
96
- robot = RobotLab.build do
97
- model "gemini-1.5-pro"
98
- # Supports up to 2M tokens context
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
- },
112
- stop_reason: "STOP"
113
- }
114
- ```
115
-
116
- ## Error Handling
117
-
118
- ```ruby
119
- begin
120
- result = robot.run(state: state)
121
- rescue RobotLab::Adapters::RateLimitError => e
122
- sleep(e.retry_after || 60)
123
- retry
124
- rescue RobotLab::Adapters::APIError => e
125
- logger.error("Gemini API error: #{e.message}")
126
- end
127
- ```
128
-
129
- ## See Also
130
-
131
- - [Adapters Overview](index.md)
132
- - [Streaming Guide](../../guides/streaming.md)
133
- - [Google AI Documentation](https://ai.google.dev/docs)
@@ -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,275 +0,0 @@
1
- # History::ActiveRecordAdapter
2
-
3
- ActiveRecord-based history persistence adapter for Rails applications.
4
-
5
- ## Class: `RobotLab::History::ActiveRecordAdapter`
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
-
9
- ```ruby
10
- adapter = RobotLab::History::ActiveRecordAdapter.new(
11
- thread_model: RobotLabThread,
12
- result_model: RobotLabResult
13
- )
14
-
15
- config = adapter.to_config
16
- ```
17
-
18
- ## Constructor
19
-
20
- ```ruby
21
- ActiveRecordAdapter.new(thread_model:, result_model:)
22
- ```
23
-
24
- **Parameters:**
25
-
26
- | Name | Type | Description |
27
- |------|------|-------------|
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.
48
-
49
- ## Methods
50
-
51
- ### to_config
52
-
53
- ```ruby
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:, **)
96
- ```
97
-
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 |
121
-
122
- ## Model Requirements
123
-
124
- ### Thread Model
125
-
126
- The thread model must have the following columns:
127
-
128
- ```ruby
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
137
- t.timestamps
138
- end
139
- ```
140
-
141
- ### Result Model
142
-
143
- The result model must have the following columns:
144
-
145
- ```ruby
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
149
- t.string :robot_name
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
155
- t.timestamps
156
- end
157
- ```
158
-
159
- ## Examples
160
-
161
- ### Basic Setup
162
-
163
- ```ruby
164
- adapter = RobotLab::History::ActiveRecordAdapter.new(
165
- thread_model: RobotLabThread,
166
- result_model: RobotLabResult
167
- )
168
-
169
- config = adapter.to_config
170
- # Use config with a ThreadManager or pass to network configuration
171
- ```
172
-
173
- ### Using with ThreadManager
174
-
175
- ```ruby
176
- adapter = RobotLab::History::ActiveRecordAdapter.new(
177
- thread_model: RobotLabThread,
178
- result_model: RobotLabResult
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)
192
- ```
193
-
194
- ### With User-Scoped Models
195
-
196
- For applications that need per-user thread scoping, create a custom adapter:
197
-
198
- ```ruby
199
- class ScopedHistoryAdapter
200
- def initialize(thread_model:, result_model:)
201
- @thread_model = thread_model
202
- @result_model = result_model
203
- end
204
-
205
- def to_config
206
- RobotLab::History::Config.new(
207
- create_thread: method(:create_thread),
208
- get: method(:get),
209
- append_user_message: method(:append_user_message),
210
- append_results: method(:append_results)
211
- )
212
- end
213
-
214
- private
215
-
216
- def create_thread(state:, input:, user_id:, **)
217
- thread = @thread_model.create!(
218
- session_id: SecureRandom.uuid,
219
- user_id: user_id,
220
- initial_input: input.to_s
221
- )
222
- { session_id: thread.session_id, created_at: thread.created_at }
223
- end
224
-
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)
231
- end
232
-
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
- )
251
- end
252
-
253
- @thread_model.where(session_id: session_id).update_all(updated_at: Time.current)
254
- end
255
- end
256
- ```
257
-
258
- ### Rails Generator
259
-
260
- Use the Rails generator to scaffold the required models and migrations:
261
-
262
- ```bash
263
- rails generate robot_lab:history
264
- ```
265
-
266
- This creates:
267
- - Thread and result ActiveRecord models
268
- - Database migrations with required columns
269
- - Initializer configuration
270
-
271
- ## See Also
272
-
273
- - [History Overview](index.md)
274
- - [Config](config.md)
275
- - [ThreadManager](thread-manager.md)