robot_lab 0.0.4 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +76 -0
- data/README.md +64 -6
- data/Rakefile +2 -1
- data/docs/api/core/index.md +41 -46
- data/docs/api/core/memory.md +200 -154
- data/docs/api/core/network.md +13 -3
- data/docs/api/core/robot.md +38 -26
- data/docs/api/core/state.md +55 -73
- data/docs/api/index.md +7 -28
- data/docs/api/messages/index.md +35 -20
- data/docs/api/messages/text-message.md +67 -21
- data/docs/api/messages/tool-call-message.md +80 -41
- data/docs/api/messages/tool-result-message.md +119 -50
- data/docs/api/messages/user-message.md +48 -24
- data/docs/architecture/core-concepts.md +10 -15
- data/docs/concepts.md +5 -7
- data/docs/examples/index.md +2 -2
- data/docs/getting-started/configuration.md +80 -0
- data/docs/guides/building-robots.md +10 -9
- data/docs/guides/creating-networks.md +49 -0
- data/docs/guides/index.md +0 -5
- data/docs/guides/rails-integration.md +244 -162
- data/docs/guides/streaming.md +118 -138
- data/docs/index.md +0 -8
- data/examples/03_network.rb +10 -7
- data/examples/08_llm_config.rb +40 -11
- data/examples/09_chaining.rb +45 -6
- data/examples/11_network_introspection.rb +30 -7
- data/examples/12_message_bus.rb +1 -1
- data/examples/14_rusty_circuit/heckler.rb +14 -8
- data/examples/14_rusty_circuit/open_mic.rb +5 -3
- data/examples/14_rusty_circuit/scout.rb +14 -31
- data/examples/15_memory_network_and_bus/editorial_pipeline.rb +1 -1
- data/examples/16_writers_room/display.rb +158 -0
- data/examples/16_writers_room/output/.gitignore +4 -0
- data/examples/16_writers_room/output/README.md +69 -0
- data/examples/16_writers_room/output/opus_001.md +263 -0
- data/examples/16_writers_room/output/opus_001_notes.log +470 -0
- data/examples/16_writers_room/output/opus_002.md +245 -0
- data/examples/16_writers_room/output/opus_002_notes.log +546 -0
- data/examples/16_writers_room/output/opus_002_screenplay.md +7989 -0
- data/examples/16_writers_room/output/opus_002_screenplay_notes.md +993 -0
- data/examples/16_writers_room/prompts/screenplay_writer.md +66 -0
- data/examples/16_writers_room/prompts/writer.md +37 -0
- data/examples/16_writers_room/room.rb +186 -0
- data/examples/16_writers_room/tools.rb +173 -0
- data/examples/16_writers_room/writer.rb +121 -0
- data/examples/16_writers_room/writers_room.rb +256 -0
- data/lib/generators/robot_lab/templates/initializer.rb.tt +0 -13
- data/lib/robot_lab/memory.rb +8 -32
- data/lib/robot_lab/network.rb +13 -20
- data/lib/robot_lab/robot/bus_messaging.rb +239 -0
- data/lib/robot_lab/robot/mcp_management.rb +88 -0
- data/lib/robot_lab/robot/template_rendering.rb +130 -0
- data/lib/robot_lab/robot.rb +56 -420
- data/lib/robot_lab/run_config.rb +184 -0
- data/lib/robot_lab/state_proxy.rb +2 -12
- data/lib/robot_lab/task.rb +8 -1
- data/lib/robot_lab/utils.rb +39 -0
- data/lib/robot_lab/version.rb +1 -1
- data/lib/robot_lab.rb +29 -8
- data/mkdocs.yml +0 -11
- metadata +21 -20
- data/docs/api/adapters/anthropic.md +0 -121
- data/docs/api/adapters/gemini.md +0 -133
- data/docs/api/adapters/index.md +0 -104
- data/docs/api/adapters/openai.md +0 -134
- data/docs/api/history/active-record-adapter.md +0 -275
- data/docs/api/history/config.md +0 -284
- data/docs/api/history/index.md +0 -128
- data/docs/api/history/thread-manager.md +0 -194
- data/docs/guides/history.md +0 -359
- data/lib/robot_lab/adapters/anthropic.rb +0 -163
- data/lib/robot_lab/adapters/base.rb +0 -85
- data/lib/robot_lab/adapters/gemini.rb +0 -193
- data/lib/robot_lab/adapters/openai.rb +0 -160
- data/lib/robot_lab/adapters/registry.rb +0 -81
- data/lib/robot_lab/errors.rb +0 -70
- data/lib/robot_lab/history/active_record_adapter.rb +0 -146
- data/lib/robot_lab/history/config.rb +0 -115
- data/lib/robot_lab/history/thread_manager.rb +0 -93
- data/lib/robot_lab/robotic_model.rb +0 -324
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
# TextMessage
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Text message from system, user, or assistant.
|
|
4
4
|
|
|
5
5
|
## Class: `RobotLab::TextMessage`
|
|
6
6
|
|
|
7
7
|
```ruby
|
|
8
|
-
message = TextMessage.new("Hello! How can I help you today?")
|
|
8
|
+
message = TextMessage.new(role: "assistant", content: "Hello! How can I help you today?")
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Constructor
|
|
12
12
|
|
|
13
13
|
```ruby
|
|
14
|
-
TextMessage.new(content)
|
|
14
|
+
TextMessage.new(role:, content:, stop_reason: nil)
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
**Parameters:**
|
|
18
18
|
|
|
19
19
|
| Name | Type | Description |
|
|
20
20
|
|------|------|-------------|
|
|
21
|
-
| `
|
|
21
|
+
| `role` | `String` | Message role ("system", "user", or "assistant") |
|
|
22
|
+
| `content` | `String` | The text content |
|
|
23
|
+
| `stop_reason` | `String`, `nil` | Stop reason ("stop" or "tool") |
|
|
22
24
|
|
|
23
25
|
## Attributes
|
|
24
26
|
|
|
@@ -28,15 +30,31 @@ TextMessage.new(content)
|
|
|
28
30
|
message.content # => String
|
|
29
31
|
```
|
|
30
32
|
|
|
31
|
-
The
|
|
33
|
+
The text content.
|
|
32
34
|
|
|
33
35
|
### role
|
|
34
36
|
|
|
35
37
|
```ruby
|
|
36
|
-
message.role # =>
|
|
38
|
+
message.role # => "assistant"
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
Returns a String: `"system"`, `"user"`, or `"assistant"`.
|
|
42
|
+
|
|
43
|
+
### type
|
|
44
|
+
|
|
45
|
+
```ruby
|
|
46
|
+
message.type # => "text"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Always returns `"text"`.
|
|
50
|
+
|
|
51
|
+
### stop_reason
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
message.stop_reason # => "stop" or nil
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The stop reason, if any.
|
|
40
58
|
|
|
41
59
|
## Methods
|
|
42
60
|
|
|
@@ -52,8 +70,10 @@ Hash representation.
|
|
|
52
70
|
|
|
53
71
|
```ruby
|
|
54
72
|
{
|
|
55
|
-
|
|
56
|
-
|
|
73
|
+
type: "text",
|
|
74
|
+
role: "assistant",
|
|
75
|
+
content: "Hello! How can I help you today?",
|
|
76
|
+
stop_reason: "stop"
|
|
57
77
|
}
|
|
58
78
|
```
|
|
59
79
|
|
|
@@ -65,34 +85,60 @@ message.to_json # => String
|
|
|
65
85
|
|
|
66
86
|
JSON representation.
|
|
67
87
|
|
|
88
|
+
### Predicates
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
message.text? # => true
|
|
92
|
+
message.tool_call? # => false
|
|
93
|
+
message.assistant? # => true (if role is "assistant")
|
|
94
|
+
message.user? # => false
|
|
95
|
+
message.stopped? # => true (if stop_reason is "stop")
|
|
96
|
+
```
|
|
97
|
+
|
|
68
98
|
## Examples
|
|
69
99
|
|
|
70
|
-
###
|
|
100
|
+
### System Message
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
message = TextMessage.new(role: "system", content: "You are a helpful assistant")
|
|
104
|
+
message.system? # => true
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### User Message
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
message = TextMessage.new(role: "user", content: "What's the weather?")
|
|
111
|
+
message.user? # => true
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Assistant Response
|
|
71
115
|
|
|
72
116
|
```ruby
|
|
73
|
-
message = TextMessage.new(
|
|
117
|
+
message = TextMessage.new(
|
|
118
|
+
role: "assistant",
|
|
119
|
+
content: "Your order has shipped!",
|
|
120
|
+
stop_reason: "stop"
|
|
121
|
+
)
|
|
122
|
+
message.assistant? # => true
|
|
123
|
+
message.stopped? # => true
|
|
74
124
|
```
|
|
75
125
|
|
|
76
126
|
### In Robot Results
|
|
77
127
|
|
|
78
128
|
```ruby
|
|
79
|
-
result = robot.run(
|
|
129
|
+
result = robot.run("Tell me a joke")
|
|
80
130
|
|
|
81
|
-
#
|
|
82
|
-
result.
|
|
83
|
-
|
|
84
|
-
puts msg.content
|
|
85
|
-
end
|
|
131
|
+
# The result is a TextMessage when the assistant replies with text
|
|
132
|
+
if result.text?
|
|
133
|
+
puts result.content
|
|
86
134
|
end
|
|
87
135
|
```
|
|
88
136
|
|
|
89
137
|
### Filtering Text Content
|
|
90
138
|
|
|
91
139
|
```ruby
|
|
92
|
-
# Get only text
|
|
93
|
-
|
|
94
|
-
msg.is_a?(TextMessage)
|
|
95
|
-
end.map(&:content)
|
|
140
|
+
# Get only text messages from memory
|
|
141
|
+
text_messages = memory.messages.select(&:text?).map(&:content)
|
|
96
142
|
```
|
|
97
143
|
|
|
98
144
|
## See Also
|
|
@@ -6,20 +6,35 @@ Tool invocation request from the LLM.
|
|
|
6
6
|
|
|
7
7
|
```ruby
|
|
8
8
|
message = ToolCallMessage.new(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
role: "assistant",
|
|
10
|
+
tools: [
|
|
11
|
+
ToolMessage.new(id: "call_abc123", name: "get_weather", input: { city: "New York" })
|
|
12
|
+
]
|
|
12
13
|
)
|
|
13
14
|
```
|
|
14
15
|
|
|
15
16
|
## Constructor
|
|
16
17
|
|
|
17
18
|
```ruby
|
|
18
|
-
ToolCallMessage.new(
|
|
19
|
+
ToolCallMessage.new(role:, tools:, stop_reason: nil)
|
|
19
20
|
```
|
|
20
21
|
|
|
21
22
|
**Parameters:**
|
|
22
23
|
|
|
24
|
+
| Name | Type | Description |
|
|
25
|
+
|------|------|-------------|
|
|
26
|
+
| `role` | `String` | Message role (typically "assistant") |
|
|
27
|
+
| `tools` | `Array<ToolMessage>` | Array of tool call objects |
|
|
28
|
+
| `stop_reason` | `String`, `nil` | Stop reason (defaults to "tool") |
|
|
29
|
+
|
|
30
|
+
## ToolMessage
|
|
31
|
+
|
|
32
|
+
Each tool call is represented by a standalone `ToolMessage` object:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
ToolMessage.new(id:, name:, input:)
|
|
36
|
+
```
|
|
37
|
+
|
|
23
38
|
| Name | Type | Description |
|
|
24
39
|
|------|------|-------------|
|
|
25
40
|
| `id` | `String` | Unique call identifier |
|
|
@@ -28,37 +43,45 @@ ToolCallMessage.new(id:, name:, input:)
|
|
|
28
43
|
|
|
29
44
|
## Attributes
|
|
30
45
|
|
|
31
|
-
###
|
|
46
|
+
### tools
|
|
32
47
|
|
|
33
48
|
```ruby
|
|
34
|
-
message.
|
|
49
|
+
message.tools # => Array<ToolMessage>
|
|
35
50
|
```
|
|
36
51
|
|
|
37
|
-
|
|
52
|
+
Array of `ToolMessage` objects representing the tool calls.
|
|
38
53
|
|
|
39
|
-
###
|
|
54
|
+
### role
|
|
40
55
|
|
|
41
56
|
```ruby
|
|
42
|
-
message.
|
|
57
|
+
message.role # => "assistant"
|
|
43
58
|
```
|
|
44
59
|
|
|
45
|
-
|
|
60
|
+
Returns a String. The LLM initiates tool calls, so this is typically `"assistant"`.
|
|
46
61
|
|
|
47
|
-
###
|
|
62
|
+
### type
|
|
48
63
|
|
|
49
64
|
```ruby
|
|
50
|
-
message.
|
|
65
|
+
message.type # => "tool_call"
|
|
51
66
|
```
|
|
52
67
|
|
|
53
|
-
|
|
68
|
+
Always returns `"tool_call"`.
|
|
54
69
|
|
|
55
|
-
###
|
|
70
|
+
### content
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
message.content # => nil
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Always `nil` for tool call messages (the tool data is in `tools`).
|
|
77
|
+
|
|
78
|
+
### stop_reason
|
|
56
79
|
|
|
57
80
|
```ruby
|
|
58
|
-
message.
|
|
81
|
+
message.stop_reason # => "tool"
|
|
59
82
|
```
|
|
60
83
|
|
|
61
|
-
|
|
84
|
+
Defaults to `"tool"` indicating the conversation stopped for tool execution.
|
|
62
85
|
|
|
63
86
|
## Methods
|
|
64
87
|
|
|
@@ -74,12 +97,12 @@ Hash representation.
|
|
|
74
97
|
|
|
75
98
|
```ruby
|
|
76
99
|
{
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
name: "get_weather",
|
|
81
|
-
|
|
82
|
-
|
|
100
|
+
type: "tool_call",
|
|
101
|
+
role: "assistant",
|
|
102
|
+
tools: [
|
|
103
|
+
{ type: "tool", id: "call_abc123", name: "get_weather", input: { city: "New York" } }
|
|
104
|
+
],
|
|
105
|
+
stop_reason: "tool"
|
|
83
106
|
}
|
|
84
107
|
```
|
|
85
108
|
|
|
@@ -91,28 +114,48 @@ message.to_json # => String
|
|
|
91
114
|
|
|
92
115
|
JSON representation.
|
|
93
116
|
|
|
117
|
+
### Predicates
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
message.tool_call? # => true
|
|
121
|
+
message.text? # => false
|
|
122
|
+
message.assistant? # => true
|
|
123
|
+
message.tool_stop? # => true
|
|
124
|
+
```
|
|
125
|
+
|
|
94
126
|
## Examples
|
|
95
127
|
|
|
96
|
-
###
|
|
128
|
+
### Single Tool Call
|
|
97
129
|
|
|
98
130
|
```ruby
|
|
99
|
-
|
|
131
|
+
tool = ToolMessage.new(
|
|
100
132
|
id: "call_1",
|
|
101
133
|
name: "search_orders",
|
|
102
134
|
input: { user_id: "123", status: "pending" }
|
|
103
135
|
)
|
|
136
|
+
|
|
137
|
+
call = ToolCallMessage.new(role: "assistant", tools: [tool])
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Multiple Tool Calls
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
tools = [
|
|
144
|
+
ToolMessage.new(id: "call_1", name: "get_weather", input: { city: "NYC" }),
|
|
145
|
+
ToolMessage.new(id: "call_2", name: "get_time", input: { timezone: "EST" })
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
call = ToolCallMessage.new(role: "assistant", tools: tools)
|
|
149
|
+
call.tools.length # => 2
|
|
104
150
|
```
|
|
105
151
|
|
|
106
152
|
### Processing Tool Calls
|
|
107
153
|
|
|
108
154
|
```ruby
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
puts "
|
|
113
|
-
puts "Parameters: #{msg.input.inspect}"
|
|
114
|
-
when ToolResultMessage
|
|
115
|
-
puts "Result for #{msg.id}: #{msg.result}"
|
|
155
|
+
if message.tool_call?
|
|
156
|
+
message.tools.each do |tool|
|
|
157
|
+
puts "Tool called: #{tool.name}"
|
|
158
|
+
puts "Parameters: #{tool.input.inspect}"
|
|
116
159
|
end
|
|
117
160
|
end
|
|
118
161
|
```
|
|
@@ -121,19 +164,15 @@ end
|
|
|
121
164
|
|
|
122
165
|
```ruby
|
|
123
166
|
# LLM returns a tool call
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
name: "get_weather",
|
|
127
|
-
input: { city: "Seattle" }
|
|
128
|
-
)
|
|
167
|
+
tool = ToolMessage.new(id: "call_weather_1", name: "get_weather", input: { city: "Seattle" })
|
|
168
|
+
tool_call = ToolCallMessage.new(role: "assistant", tools: [tool])
|
|
129
169
|
|
|
130
|
-
#
|
|
131
|
-
|
|
170
|
+
# Execute the tool and record the result
|
|
171
|
+
result_data = execute_tool(tool.name, tool.input)
|
|
132
172
|
|
|
133
|
-
# Result is recorded
|
|
134
173
|
tool_result = ToolResultMessage.new(
|
|
135
|
-
|
|
136
|
-
|
|
174
|
+
tool: tool,
|
|
175
|
+
content: { data: result_data }
|
|
137
176
|
)
|
|
138
177
|
```
|
|
139
178
|
|
|
@@ -5,53 +5,104 @@ Result from tool execution.
|
|
|
5
5
|
## Class: `RobotLab::ToolResultMessage`
|
|
6
6
|
|
|
7
7
|
```ruby
|
|
8
|
+
tool = ToolMessage.new(id: "call_abc123", name: "get_weather", input: { city: "NYC" })
|
|
9
|
+
|
|
8
10
|
message = ToolResultMessage.new(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
tool: tool,
|
|
12
|
+
content: { data: { temperature: 72, conditions: "sunny" } }
|
|
11
13
|
)
|
|
12
14
|
```
|
|
13
15
|
|
|
14
16
|
## Constructor
|
|
15
17
|
|
|
16
18
|
```ruby
|
|
17
|
-
ToolResultMessage.new(
|
|
19
|
+
ToolResultMessage.new(tool:, content:, stop_reason: nil)
|
|
18
20
|
```
|
|
19
21
|
|
|
20
22
|
**Parameters:**
|
|
21
23
|
|
|
22
24
|
| Name | Type | Description |
|
|
23
25
|
|------|------|-------------|
|
|
24
|
-
| `
|
|
25
|
-
| `
|
|
26
|
+
| `tool` | `ToolMessage` | The tool call that was executed |
|
|
27
|
+
| `content` | `Hash` | Result with `:data` key (success) or `:error` key (failure) |
|
|
28
|
+
| `stop_reason` | `String`, `nil` | Stop reason (defaults to "tool") |
|
|
26
29
|
|
|
27
30
|
## Attributes
|
|
28
31
|
|
|
29
|
-
###
|
|
32
|
+
### tool
|
|
30
33
|
|
|
31
34
|
```ruby
|
|
32
|
-
message.
|
|
35
|
+
message.tool # => ToolMessage
|
|
33
36
|
```
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
The `ToolMessage` representing the tool call that produced this result. Provides access to `tool.id`, `tool.name`, and `tool.input`.
|
|
36
39
|
|
|
37
|
-
###
|
|
40
|
+
### content
|
|
38
41
|
|
|
39
42
|
```ruby
|
|
40
|
-
message.
|
|
43
|
+
message.content # => Hash
|
|
41
44
|
```
|
|
42
45
|
|
|
43
|
-
The result
|
|
46
|
+
The result content. Contains either a `:data` key (success) or an `:error` key (failure).
|
|
44
47
|
|
|
45
48
|
### role
|
|
46
49
|
|
|
47
50
|
```ruby
|
|
48
|
-
message.role # =>
|
|
51
|
+
message.role # => "tool_result"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Always returns `"tool_result"`.
|
|
55
|
+
|
|
56
|
+
### type
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
message.type # => "tool_result"
|
|
49
60
|
```
|
|
50
61
|
|
|
51
|
-
Always returns
|
|
62
|
+
Always returns `"tool_result"`.
|
|
63
|
+
|
|
64
|
+
### stop_reason
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
message.stop_reason # => "tool"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Defaults to `"tool"`.
|
|
52
71
|
|
|
53
72
|
## Methods
|
|
54
73
|
|
|
74
|
+
### success?
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
message.success? # => Boolean
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Returns `true` if the content contains a `:data` key.
|
|
81
|
+
|
|
82
|
+
### error?
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
message.error? # => Boolean
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Returns `true` if the content contains an `:error` key.
|
|
89
|
+
|
|
90
|
+
### data
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
message.data # => Object | nil
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Returns the result data if successful, `nil` otherwise.
|
|
97
|
+
|
|
98
|
+
### error
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
message.error # => String | nil
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Returns the error message if there was an error, `nil` otherwise.
|
|
105
|
+
|
|
55
106
|
### to_h
|
|
56
107
|
|
|
57
108
|
```ruby
|
|
@@ -64,11 +115,11 @@ Hash representation.
|
|
|
64
115
|
|
|
65
116
|
```ruby
|
|
66
117
|
{
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
118
|
+
type: "tool_result",
|
|
119
|
+
role: "tool_result",
|
|
120
|
+
tool: { type: "tool", id: "call_abc123", name: "get_weather", input: { city: "NYC" } },
|
|
121
|
+
content: { data: { temperature: 72, conditions: "sunny" } },
|
|
122
|
+
stop_reason: "tool"
|
|
72
123
|
}
|
|
73
124
|
```
|
|
74
125
|
|
|
@@ -80,70 +131,88 @@ message.to_json # => String
|
|
|
80
131
|
|
|
81
132
|
JSON representation.
|
|
82
133
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
### Basic Result
|
|
134
|
+
### Predicates
|
|
86
135
|
|
|
87
136
|
```ruby
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
137
|
+
message.tool_result? # => true
|
|
138
|
+
message.tool_call? # => false
|
|
139
|
+
message.text? # => false
|
|
140
|
+
message.tool_stop? # => true
|
|
92
141
|
```
|
|
93
142
|
|
|
94
|
-
|
|
143
|
+
## Examples
|
|
144
|
+
|
|
145
|
+
### Successful Result
|
|
95
146
|
|
|
96
147
|
```ruby
|
|
148
|
+
tool = ToolMessage.new(id: "call_1", name: "search_orders", input: { user_id: "123" })
|
|
149
|
+
|
|
97
150
|
result = ToolResultMessage.new(
|
|
98
|
-
|
|
99
|
-
|
|
151
|
+
tool: tool,
|
|
152
|
+
content: { data: { order_id: "ord_123", status: "shipped" } }
|
|
100
153
|
)
|
|
154
|
+
|
|
155
|
+
result.success? # => true
|
|
156
|
+
result.data # => { order_id: "ord_123", status: "shipped" }
|
|
101
157
|
```
|
|
102
158
|
|
|
103
|
-
###
|
|
159
|
+
### Error Result
|
|
104
160
|
|
|
105
161
|
```ruby
|
|
162
|
+
tool = ToolMessage.new(id: "call_order", name: "get_order", input: { id: "bad" })
|
|
163
|
+
|
|
106
164
|
result = ToolResultMessage.new(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
{ id: 1, name: "Product A" },
|
|
110
|
-
{ id: 2, name: "Product B" }
|
|
111
|
-
]
|
|
165
|
+
tool: tool,
|
|
166
|
+
content: { error: "Order not found" }
|
|
112
167
|
)
|
|
168
|
+
|
|
169
|
+
result.error? # => true
|
|
170
|
+
result.error # => "Order not found"
|
|
171
|
+
result.data # => nil
|
|
113
172
|
```
|
|
114
173
|
|
|
115
|
-
###
|
|
174
|
+
### Accessing Tool Information
|
|
116
175
|
|
|
117
176
|
```ruby
|
|
118
177
|
result = ToolResultMessage.new(
|
|
119
|
-
id: "
|
|
120
|
-
|
|
178
|
+
tool: ToolMessage.new(id: "call_1", name: "get_weather", input: { city: "Berlin" }),
|
|
179
|
+
content: { data: { temperature: 15, unit: "celsius" } }
|
|
121
180
|
)
|
|
181
|
+
|
|
182
|
+
result.tool.name # => "get_weather"
|
|
183
|
+
result.tool.id # => "call_1"
|
|
184
|
+
result.tool.input # => { city: "Berlin" }
|
|
185
|
+
result.data # => { temperature: 15, unit: "celsius" }
|
|
122
186
|
```
|
|
123
187
|
|
|
124
|
-
### Matching
|
|
188
|
+
### Matching Tool Calls with Results
|
|
125
189
|
|
|
126
190
|
```ruby
|
|
127
|
-
#
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
191
|
+
# Given a ToolCallMessage and its results
|
|
192
|
+
tool_call_msg.tools.each do |tool|
|
|
193
|
+
# Find the matching result
|
|
194
|
+
matching_result = results.find { |r| r.tool.id == tool.id }
|
|
195
|
+
|
|
196
|
+
if matching_result&.success?
|
|
197
|
+
puts "#{tool.name}(#{tool.input}) => #{matching_result.data}"
|
|
198
|
+
elsif matching_result&.error?
|
|
199
|
+
puts "#{tool.name} failed: #{matching_result.error}"
|
|
133
200
|
end
|
|
134
201
|
end
|
|
135
202
|
```
|
|
136
203
|
|
|
137
|
-
### In
|
|
204
|
+
### In Memory History
|
|
138
205
|
|
|
139
206
|
```ruby
|
|
140
|
-
# Find all tool results from
|
|
141
|
-
tool_results =
|
|
142
|
-
.flat_map(&:output)
|
|
143
|
-
.select { |m| m.is_a?(ToolResultMessage) }
|
|
207
|
+
# Find all tool results from memory
|
|
208
|
+
tool_results = memory.messages.select(&:tool_result?)
|
|
144
209
|
|
|
145
210
|
tool_results.each do |tr|
|
|
146
|
-
|
|
211
|
+
if tr.success?
|
|
212
|
+
puts "#{tr.tool.name}: #{tr.data}"
|
|
213
|
+
else
|
|
214
|
+
puts "#{tr.tool.name} error: #{tr.error}"
|
|
215
|
+
end
|
|
147
216
|
end
|
|
148
217
|
```
|
|
149
218
|
|