robot_lab 0.0.1
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 +7 -0
- data/.envrc +1 -0
- data/.github/workflows/deploy-github-pages.yml +52 -0
- data/.github/workflows/deploy-yard-docs.yml +52 -0
- data/CHANGELOG.md +55 -0
- data/COMMITS.md +196 -0
- data/LICENSE.txt +21 -0
- data/README.md +332 -0
- data/Rakefile +67 -0
- data/docs/api/adapters/anthropic.md +121 -0
- data/docs/api/adapters/gemini.md +133 -0
- data/docs/api/adapters/index.md +104 -0
- data/docs/api/adapters/openai.md +134 -0
- data/docs/api/core/index.md +113 -0
- data/docs/api/core/memory.md +314 -0
- data/docs/api/core/network.md +291 -0
- data/docs/api/core/robot.md +273 -0
- data/docs/api/core/state.md +273 -0
- data/docs/api/core/tool.md +353 -0
- data/docs/api/history/active-record-adapter.md +195 -0
- data/docs/api/history/config.md +191 -0
- data/docs/api/history/index.md +132 -0
- data/docs/api/history/thread-manager.md +144 -0
- data/docs/api/index.md +82 -0
- data/docs/api/mcp/client.md +221 -0
- data/docs/api/mcp/index.md +111 -0
- data/docs/api/mcp/server.md +225 -0
- data/docs/api/mcp/transports.md +264 -0
- data/docs/api/messages/index.md +67 -0
- data/docs/api/messages/text-message.md +102 -0
- data/docs/api/messages/tool-call-message.md +144 -0
- data/docs/api/messages/tool-result-message.md +154 -0
- data/docs/api/messages/user-message.md +171 -0
- data/docs/api/streaming/context.md +174 -0
- data/docs/api/streaming/events.md +237 -0
- data/docs/api/streaming/index.md +108 -0
- data/docs/architecture/core-concepts.md +243 -0
- data/docs/architecture/index.md +138 -0
- data/docs/architecture/message-flow.md +320 -0
- data/docs/architecture/network-orchestration.md +216 -0
- data/docs/architecture/robot-execution.md +243 -0
- data/docs/architecture/state-management.md +323 -0
- data/docs/assets/css/custom.css +56 -0
- data/docs/assets/images/robot_lab.jpg +0 -0
- data/docs/concepts.md +216 -0
- data/docs/examples/basic-chat.md +193 -0
- data/docs/examples/index.md +129 -0
- data/docs/examples/mcp-server.md +290 -0
- data/docs/examples/multi-robot-network.md +312 -0
- data/docs/examples/rails-application.md +420 -0
- data/docs/examples/tool-usage.md +310 -0
- data/docs/getting-started/configuration.md +230 -0
- data/docs/getting-started/index.md +56 -0
- data/docs/getting-started/installation.md +179 -0
- data/docs/getting-started/quick-start.md +203 -0
- data/docs/guides/building-robots.md +376 -0
- data/docs/guides/creating-networks.md +366 -0
- data/docs/guides/history.md +359 -0
- data/docs/guides/index.md +68 -0
- data/docs/guides/mcp-integration.md +356 -0
- data/docs/guides/memory.md +309 -0
- data/docs/guides/rails-integration.md +432 -0
- data/docs/guides/streaming.md +314 -0
- data/docs/guides/using-tools.md +394 -0
- data/docs/index.md +160 -0
- data/examples/01_simple_robot.rb +38 -0
- data/examples/02_tools.rb +106 -0
- data/examples/03_network.rb +103 -0
- data/examples/04_mcp.rb +219 -0
- data/examples/05_streaming.rb +124 -0
- data/examples/06_prompt_templates.rb +324 -0
- data/examples/07_network_memory.rb +329 -0
- data/examples/prompts/assistant/system.txt.erb +2 -0
- data/examples/prompts/assistant/user.txt.erb +1 -0
- data/examples/prompts/billing/system.txt.erb +7 -0
- data/examples/prompts/billing/user.txt.erb +1 -0
- data/examples/prompts/classifier/system.txt.erb +4 -0
- data/examples/prompts/classifier/user.txt.erb +1 -0
- data/examples/prompts/entity_extractor/system.txt.erb +11 -0
- data/examples/prompts/entity_extractor/user.txt.erb +3 -0
- data/examples/prompts/escalation/system.txt.erb +35 -0
- data/examples/prompts/escalation/user.txt.erb +34 -0
- data/examples/prompts/general/system.txt.erb +4 -0
- data/examples/prompts/general/user.txt.erb +1 -0
- data/examples/prompts/github_assistant/system.txt.erb +6 -0
- data/examples/prompts/github_assistant/user.txt.erb +1 -0
- data/examples/prompts/helper/system.txt.erb +1 -0
- data/examples/prompts/helper/user.txt.erb +1 -0
- data/examples/prompts/keyword_extractor/system.txt.erb +8 -0
- data/examples/prompts/keyword_extractor/user.txt.erb +3 -0
- data/examples/prompts/order_support/system.txt.erb +27 -0
- data/examples/prompts/order_support/user.txt.erb +22 -0
- data/examples/prompts/product_support/system.txt.erb +30 -0
- data/examples/prompts/product_support/user.txt.erb +32 -0
- data/examples/prompts/sentiment_analyzer/system.txt.erb +9 -0
- data/examples/prompts/sentiment_analyzer/user.txt.erb +3 -0
- data/examples/prompts/synthesizer/system.txt.erb +14 -0
- data/examples/prompts/synthesizer/user.txt.erb +15 -0
- data/examples/prompts/technical/system.txt.erb +7 -0
- data/examples/prompts/technical/user.txt.erb +1 -0
- data/examples/prompts/triage/system.txt.erb +16 -0
- data/examples/prompts/triage/user.txt.erb +17 -0
- data/lib/generators/robot_lab/install_generator.rb +78 -0
- data/lib/generators/robot_lab/robot_generator.rb +55 -0
- data/lib/generators/robot_lab/templates/initializer.rb.tt +41 -0
- data/lib/generators/robot_lab/templates/migration.rb.tt +32 -0
- data/lib/generators/robot_lab/templates/result_model.rb.tt +52 -0
- data/lib/generators/robot_lab/templates/robot.rb.tt +46 -0
- data/lib/generators/robot_lab/templates/robot_test.rb.tt +32 -0
- data/lib/generators/robot_lab/templates/routing_robot.rb.tt +53 -0
- data/lib/generators/robot_lab/templates/thread_model.rb.tt +40 -0
- data/lib/robot_lab/adapters/anthropic.rb +163 -0
- data/lib/robot_lab/adapters/base.rb +85 -0
- data/lib/robot_lab/adapters/gemini.rb +193 -0
- data/lib/robot_lab/adapters/openai.rb +159 -0
- data/lib/robot_lab/adapters/registry.rb +81 -0
- data/lib/robot_lab/configuration.rb +143 -0
- data/lib/robot_lab/error.rb +32 -0
- data/lib/robot_lab/errors.rb +70 -0
- data/lib/robot_lab/history/active_record_adapter.rb +146 -0
- data/lib/robot_lab/history/config.rb +115 -0
- data/lib/robot_lab/history/thread_manager.rb +93 -0
- data/lib/robot_lab/mcp/client.rb +210 -0
- data/lib/robot_lab/mcp/server.rb +84 -0
- data/lib/robot_lab/mcp/transports/base.rb +56 -0
- data/lib/robot_lab/mcp/transports/sse.rb +117 -0
- data/lib/robot_lab/mcp/transports/stdio.rb +133 -0
- data/lib/robot_lab/mcp/transports/streamable_http.rb +139 -0
- data/lib/robot_lab/mcp/transports/websocket.rb +108 -0
- data/lib/robot_lab/memory.rb +882 -0
- data/lib/robot_lab/memory_change.rb +123 -0
- data/lib/robot_lab/message.rb +357 -0
- data/lib/robot_lab/network.rb +350 -0
- data/lib/robot_lab/rails/engine.rb +29 -0
- data/lib/robot_lab/rails/railtie.rb +42 -0
- data/lib/robot_lab/robot.rb +560 -0
- data/lib/robot_lab/robot_result.rb +205 -0
- data/lib/robot_lab/robotic_model.rb +324 -0
- data/lib/robot_lab/state_proxy.rb +188 -0
- data/lib/robot_lab/streaming/context.rb +144 -0
- data/lib/robot_lab/streaming/events.rb +95 -0
- data/lib/robot_lab/streaming/sequence_counter.rb +48 -0
- data/lib/robot_lab/task.rb +117 -0
- data/lib/robot_lab/tool.rb +223 -0
- data/lib/robot_lab/tool_config.rb +112 -0
- data/lib/robot_lab/tool_manifest.rb +234 -0
- data/lib/robot_lab/user_message.rb +118 -0
- data/lib/robot_lab/version.rb +5 -0
- data/lib/robot_lab/waiter.rb +73 -0
- data/lib/robot_lab.rb +195 -0
- data/mkdocs.yml +214 -0
- data/sig/robot_lab.rbs +4 -0
- metadata +442 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# State
|
|
2
|
+
|
|
3
|
+
Manages conversation data, results, and memory.
|
|
4
|
+
|
|
5
|
+
## Class: `RobotLab::State`
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
state = RobotLab.create_state(
|
|
9
|
+
message: "Hello",
|
|
10
|
+
data: { user_id: "123" }
|
|
11
|
+
)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Attributes
|
|
15
|
+
|
|
16
|
+
### thread_id
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
state.thread_id # => String | nil
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Conversation thread identifier for persistence.
|
|
23
|
+
|
|
24
|
+
### memory
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
state.memory # => Memory
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Shared key-value store.
|
|
31
|
+
|
|
32
|
+
## Methods
|
|
33
|
+
|
|
34
|
+
### data
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
state.data # => StateProxy
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Access workflow data as a proxy object.
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
state.data[:user_id] # Hash access
|
|
44
|
+
state.data.user_id # Method access
|
|
45
|
+
state.data[:status] = "active"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### results
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
state.results # => Array<RobotResult>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
All robot execution results.
|
|
55
|
+
|
|
56
|
+
### messages
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
state.messages # => Array<Message>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Formatted conversation messages for LLM.
|
|
63
|
+
|
|
64
|
+
### append_result
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
state.append_result(robot_result)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Add a robot result to history.
|
|
71
|
+
|
|
72
|
+
### set_results
|
|
73
|
+
|
|
74
|
+
```ruby
|
|
75
|
+
state.set_results(array_of_results)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Replace all results.
|
|
79
|
+
|
|
80
|
+
### results_from
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
state.results_from(5) # => Array<RobotResult>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Get results starting at index.
|
|
87
|
+
|
|
88
|
+
### thread_id=
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
state.thread_id = "thread_123"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Set the thread identifier.
|
|
95
|
+
|
|
96
|
+
### format_history
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
state.format_history # => Array<Message>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Format results as conversation history.
|
|
103
|
+
|
|
104
|
+
### clone
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
new_state = state.clone
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Create a deep copy.
|
|
111
|
+
|
|
112
|
+
### to_h
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
state.to_h # => Hash
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Hash representation.
|
|
119
|
+
|
|
120
|
+
### to_json
|
|
121
|
+
|
|
122
|
+
```ruby
|
|
123
|
+
state.to_json # => String
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
JSON representation.
|
|
127
|
+
|
|
128
|
+
### from_hash (class method)
|
|
129
|
+
|
|
130
|
+
```ruby
|
|
131
|
+
state = State.from_hash(hash)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Restore from hash.
|
|
135
|
+
|
|
136
|
+
## StateProxy
|
|
137
|
+
|
|
138
|
+
The `data` attribute is a `StateProxy`:
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
proxy = state.data
|
|
142
|
+
|
|
143
|
+
# Hash-style access
|
|
144
|
+
proxy[:key]
|
|
145
|
+
proxy[:key] = value
|
|
146
|
+
|
|
147
|
+
# Method-style access
|
|
148
|
+
proxy.key
|
|
149
|
+
proxy.key = value
|
|
150
|
+
|
|
151
|
+
# Hash operations
|
|
152
|
+
proxy.key?(:key)
|
|
153
|
+
proxy.keys
|
|
154
|
+
proxy.values
|
|
155
|
+
proxy.each { |k, v| ... }
|
|
156
|
+
proxy.merge!(other_hash)
|
|
157
|
+
proxy.delete(:key)
|
|
158
|
+
proxy.to_h
|
|
159
|
+
proxy.empty?
|
|
160
|
+
proxy.size
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Creating State
|
|
164
|
+
|
|
165
|
+
### Basic
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
state = RobotLab.create_state(message: "Hello")
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### With Data
|
|
172
|
+
|
|
173
|
+
```ruby
|
|
174
|
+
state = RobotLab.create_state(
|
|
175
|
+
message: "Process order",
|
|
176
|
+
data: {
|
|
177
|
+
user_id: "user_123",
|
|
178
|
+
order_id: "ord_456"
|
|
179
|
+
}
|
|
180
|
+
)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### With Thread ID
|
|
184
|
+
|
|
185
|
+
```ruby
|
|
186
|
+
# Via UserMessage
|
|
187
|
+
message = UserMessage.new("Continue", thread_id: "thread_123")
|
|
188
|
+
state = RobotLab.create_state(message: message)
|
|
189
|
+
|
|
190
|
+
# Direct assignment
|
|
191
|
+
state = RobotLab.create_state(message: "Continue")
|
|
192
|
+
state.thread_id = "thread_123"
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### With Existing Results
|
|
196
|
+
|
|
197
|
+
```ruby
|
|
198
|
+
state = RobotLab.create_state(
|
|
199
|
+
message: "Follow up",
|
|
200
|
+
results: previous_results
|
|
201
|
+
)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## UserMessage
|
|
205
|
+
|
|
206
|
+
Enhanced message with metadata:
|
|
207
|
+
|
|
208
|
+
```ruby
|
|
209
|
+
message = UserMessage.new(
|
|
210
|
+
"What's my order status?",
|
|
211
|
+
thread_id: "thread_123",
|
|
212
|
+
system_prompt: "Respond in Spanish",
|
|
213
|
+
metadata: { source: "web" }
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
message.content # => "What's my order status?"
|
|
217
|
+
message.thread_id # => "thread_123"
|
|
218
|
+
message.system_prompt # => "Respond in Spanish"
|
|
219
|
+
message.metadata # => { source: "web" }
|
|
220
|
+
message.id # => UUID
|
|
221
|
+
message.created_at # => Time
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Examples
|
|
225
|
+
|
|
226
|
+
### Accessing Data
|
|
227
|
+
|
|
228
|
+
```ruby
|
|
229
|
+
state = RobotLab.create_state(
|
|
230
|
+
message: "Help",
|
|
231
|
+
data: { user: { name: "Alice", plan: "pro" } }
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
state.data[:user][:name] # => "Alice"
|
|
235
|
+
state.data.to_h # => { user: { name: "Alice", plan: "pro" } }
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Working with Results
|
|
239
|
+
|
|
240
|
+
```ruby
|
|
241
|
+
# After running network
|
|
242
|
+
state.results.size # Number of results
|
|
243
|
+
state.results.last # Most recent
|
|
244
|
+
state.results.map(&:robot_name) # ["classifier", "support"]
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Using Memory
|
|
248
|
+
|
|
249
|
+
```ruby
|
|
250
|
+
state.memory.remember("intent", "billing")
|
|
251
|
+
intent = state.memory.recall("intent")
|
|
252
|
+
|
|
253
|
+
scoped = state.memory.scoped("user:123")
|
|
254
|
+
scoped.remember("preference", "dark_mode")
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Serialization
|
|
258
|
+
|
|
259
|
+
```ruby
|
|
260
|
+
# Save state
|
|
261
|
+
json = state.to_json
|
|
262
|
+
File.write("state.json", json)
|
|
263
|
+
|
|
264
|
+
# Restore state
|
|
265
|
+
data = JSON.parse(File.read("state.json"))
|
|
266
|
+
state = State.from_hash(data)
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## See Also
|
|
270
|
+
|
|
271
|
+
- [State Management Architecture](../../architecture/state-management.md)
|
|
272
|
+
- [Memory](memory.md)
|
|
273
|
+
- [History Guide](../../guides/history.md)
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
# Tool
|
|
2
|
+
|
|
3
|
+
Callable function that robots can use to interact with external systems.
|
|
4
|
+
|
|
5
|
+
## Class: `RobotLab::Tool`
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
tool = RobotLab::Tool.new(
|
|
9
|
+
name: "get_weather",
|
|
10
|
+
description: "Get weather for a location",
|
|
11
|
+
parameters: { location: { type: "string", required: true } },
|
|
12
|
+
handler: ->(location:, **_) { WeatherService.fetch(location) }
|
|
13
|
+
)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Constructor
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
Tool.new(
|
|
20
|
+
name:,
|
|
21
|
+
description: nil,
|
|
22
|
+
parameters: {},
|
|
23
|
+
handler:,
|
|
24
|
+
mcp: false,
|
|
25
|
+
strict: false
|
|
26
|
+
)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Parameters:**
|
|
30
|
+
|
|
31
|
+
| Name | Type | Description |
|
|
32
|
+
|------|------|-------------|
|
|
33
|
+
| `name` | `String` | Tool identifier |
|
|
34
|
+
| `description` | `String` | What the tool does |
|
|
35
|
+
| `parameters` | `Hash` | Parameter definitions |
|
|
36
|
+
| `handler` | `Proc` | Execution function |
|
|
37
|
+
| `mcp` | `Boolean` | Is this an MCP tool? |
|
|
38
|
+
| `strict` | `Boolean` | Strict parameter validation |
|
|
39
|
+
|
|
40
|
+
## Attributes
|
|
41
|
+
|
|
42
|
+
### name
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
tool.name # => String
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Tool identifier.
|
|
49
|
+
|
|
50
|
+
### description
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
tool.description # => String
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Human-readable description.
|
|
57
|
+
|
|
58
|
+
### parameters
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
tool.parameters # => Hash
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Parameter schema.
|
|
65
|
+
|
|
66
|
+
### handler
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
tool.handler # => Proc
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Function that executes the tool.
|
|
73
|
+
|
|
74
|
+
### mcp
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
tool.mcp # => Boolean
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Whether this is an MCP-sourced tool.
|
|
81
|
+
|
|
82
|
+
### strict
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
tool.strict # => Boolean
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Whether to use strict parameter validation.
|
|
89
|
+
|
|
90
|
+
## Methods
|
|
91
|
+
|
|
92
|
+
### call
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
result = tool.call(
|
|
96
|
+
params,
|
|
97
|
+
robot: robot,
|
|
98
|
+
network: network,
|
|
99
|
+
state: state
|
|
100
|
+
)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Execute the tool with parameters.
|
|
104
|
+
|
|
105
|
+
### to_h
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
tool.to_h # => Hash
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Hash representation.
|
|
112
|
+
|
|
113
|
+
### to_json
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
tool.to_json # => String
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
JSON representation.
|
|
120
|
+
|
|
121
|
+
### to_json_schema
|
|
122
|
+
|
|
123
|
+
```ruby
|
|
124
|
+
tool.to_json_schema # => Hash
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
JSON Schema representation for LLM.
|
|
128
|
+
|
|
129
|
+
## Parameter Schema
|
|
130
|
+
|
|
131
|
+
### Basic Types
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
parameters: {
|
|
135
|
+
name: { type: "string" },
|
|
136
|
+
count: { type: "integer" },
|
|
137
|
+
price: { type: "number" },
|
|
138
|
+
active: { type: "boolean" },
|
|
139
|
+
tags: { type: "array" }
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Required Parameters
|
|
144
|
+
|
|
145
|
+
```ruby
|
|
146
|
+
parameters: {
|
|
147
|
+
id: { type: "string", required: true }
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Descriptions
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
parameters: {
|
|
155
|
+
query: {
|
|
156
|
+
type: "string",
|
|
157
|
+
description: "Search query (supports wildcards)"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Enums
|
|
163
|
+
|
|
164
|
+
```ruby
|
|
165
|
+
parameters: {
|
|
166
|
+
status: {
|
|
167
|
+
type: "string",
|
|
168
|
+
enum: ["pending", "active", "completed"]
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Defaults
|
|
174
|
+
|
|
175
|
+
```ruby
|
|
176
|
+
parameters: {
|
|
177
|
+
limit: {
|
|
178
|
+
type: "integer",
|
|
179
|
+
default: 10
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Handler
|
|
185
|
+
|
|
186
|
+
### Basic Handler
|
|
187
|
+
|
|
188
|
+
```ruby
|
|
189
|
+
handler: ->(param:, **_context) {
|
|
190
|
+
do_something(param)
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### With Context
|
|
195
|
+
|
|
196
|
+
```ruby
|
|
197
|
+
handler: ->(param:, robot:, network:, state:) {
|
|
198
|
+
# robot - The executing Robot
|
|
199
|
+
# network - The NetworkRun
|
|
200
|
+
# state - Current State
|
|
201
|
+
|
|
202
|
+
user = state.data[:user_id]
|
|
203
|
+
state.memory.remember("last_action", param)
|
|
204
|
+
|
|
205
|
+
perform_action(param, user)
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Error Handling
|
|
210
|
+
|
|
211
|
+
```ruby
|
|
212
|
+
handler: ->(id:, **_) {
|
|
213
|
+
record = Record.find_by(id: id)
|
|
214
|
+
|
|
215
|
+
if record
|
|
216
|
+
{ success: true, data: record.to_h }
|
|
217
|
+
else
|
|
218
|
+
{ success: false, error: "Not found" }
|
|
219
|
+
end
|
|
220
|
+
rescue StandardError => e
|
|
221
|
+
{ success: false, error: e.message }
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Builder DSL
|
|
226
|
+
|
|
227
|
+
In robot builder:
|
|
228
|
+
|
|
229
|
+
```ruby
|
|
230
|
+
tool :tool_name do
|
|
231
|
+
description "What it does"
|
|
232
|
+
|
|
233
|
+
parameter :param1, type: :string, required: true
|
|
234
|
+
parameter :param2, type: :integer, default: 10
|
|
235
|
+
|
|
236
|
+
handler do |param1:, param2:, **_context|
|
|
237
|
+
# Implementation
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## ToolManifest
|
|
243
|
+
|
|
244
|
+
Wrap tools with modified metadata:
|
|
245
|
+
|
|
246
|
+
```ruby
|
|
247
|
+
manifest = RobotLab::ToolManifest.new(
|
|
248
|
+
tool: original_tool,
|
|
249
|
+
name: "custom_name",
|
|
250
|
+
description: "Custom description"
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
# Original tool is used, metadata is overridden
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Attributes
|
|
257
|
+
|
|
258
|
+
- `tool` - The wrapped tool
|
|
259
|
+
- `name` - Override name (or original)
|
|
260
|
+
- `description` - Override description (or original)
|
|
261
|
+
- `aliases` - Alternative names
|
|
262
|
+
|
|
263
|
+
## Examples
|
|
264
|
+
|
|
265
|
+
### Simple Tool
|
|
266
|
+
|
|
267
|
+
```ruby
|
|
268
|
+
tool = Tool.new(
|
|
269
|
+
name: "current_time",
|
|
270
|
+
description: "Get the current time",
|
|
271
|
+
handler: ->(**, _) { Time.now.iso8601 }
|
|
272
|
+
)
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Tool with Parameters
|
|
276
|
+
|
|
277
|
+
```ruby
|
|
278
|
+
tool = Tool.new(
|
|
279
|
+
name: "search_users",
|
|
280
|
+
description: "Search users by criteria",
|
|
281
|
+
parameters: {
|
|
282
|
+
query: {
|
|
283
|
+
type: "string",
|
|
284
|
+
description: "Search query",
|
|
285
|
+
required: true
|
|
286
|
+
},
|
|
287
|
+
limit: {
|
|
288
|
+
type: "integer",
|
|
289
|
+
description: "Max results",
|
|
290
|
+
default: 10
|
|
291
|
+
},
|
|
292
|
+
status: {
|
|
293
|
+
type: "string",
|
|
294
|
+
enum: ["active", "inactive", "all"],
|
|
295
|
+
default: "active"
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
handler: ->(query:, limit:, status:, **_) {
|
|
299
|
+
User.search(query, limit: limit, status: status)
|
|
300
|
+
}
|
|
301
|
+
)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### API Integration Tool
|
|
305
|
+
|
|
306
|
+
```ruby
|
|
307
|
+
tool = Tool.new(
|
|
308
|
+
name: "fetch_stock_price",
|
|
309
|
+
description: "Get current stock price",
|
|
310
|
+
parameters: {
|
|
311
|
+
symbol: { type: "string", required: true }
|
|
312
|
+
},
|
|
313
|
+
handler: ->(symbol:, **_) {
|
|
314
|
+
response = HTTP.get("https://api.stocks.example/#{symbol}")
|
|
315
|
+
|
|
316
|
+
if response.status.success?
|
|
317
|
+
JSON.parse(response.body)
|
|
318
|
+
else
|
|
319
|
+
{ error: "Failed to fetch", status: response.status.code }
|
|
320
|
+
end
|
|
321
|
+
rescue HTTP::Error => e
|
|
322
|
+
{ error: "Network error: #{e.message}" }
|
|
323
|
+
}
|
|
324
|
+
)
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Database Tool
|
|
328
|
+
|
|
329
|
+
```ruby
|
|
330
|
+
tool = Tool.new(
|
|
331
|
+
name: "get_order",
|
|
332
|
+
description: "Get order details",
|
|
333
|
+
parameters: {
|
|
334
|
+
order_id: { type: "string", required: true }
|
|
335
|
+
},
|
|
336
|
+
handler: ->(order_id:, state:, **_) {
|
|
337
|
+
user_id = state.data[:user_id]
|
|
338
|
+
order = Order.find_by(id: order_id, user_id: user_id)
|
|
339
|
+
|
|
340
|
+
if order
|
|
341
|
+
order.as_json(include: [:items, :shipping])
|
|
342
|
+
else
|
|
343
|
+
{ error: "Order not found or unauthorized" }
|
|
344
|
+
end
|
|
345
|
+
}
|
|
346
|
+
)
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## See Also
|
|
350
|
+
|
|
351
|
+
- [Using Tools Guide](../../guides/using-tools.md)
|
|
352
|
+
- [Robot](robot.md)
|
|
353
|
+
- [MCP Integration](../../guides/mcp-integration.md)
|