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.
Files changed (153) hide show
  1. checksums.yaml +7 -0
  2. data/.envrc +1 -0
  3. data/.github/workflows/deploy-github-pages.yml +52 -0
  4. data/.github/workflows/deploy-yard-docs.yml +52 -0
  5. data/CHANGELOG.md +55 -0
  6. data/COMMITS.md +196 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +332 -0
  9. data/Rakefile +67 -0
  10. data/docs/api/adapters/anthropic.md +121 -0
  11. data/docs/api/adapters/gemini.md +133 -0
  12. data/docs/api/adapters/index.md +104 -0
  13. data/docs/api/adapters/openai.md +134 -0
  14. data/docs/api/core/index.md +113 -0
  15. data/docs/api/core/memory.md +314 -0
  16. data/docs/api/core/network.md +291 -0
  17. data/docs/api/core/robot.md +273 -0
  18. data/docs/api/core/state.md +273 -0
  19. data/docs/api/core/tool.md +353 -0
  20. data/docs/api/history/active-record-adapter.md +195 -0
  21. data/docs/api/history/config.md +191 -0
  22. data/docs/api/history/index.md +132 -0
  23. data/docs/api/history/thread-manager.md +144 -0
  24. data/docs/api/index.md +82 -0
  25. data/docs/api/mcp/client.md +221 -0
  26. data/docs/api/mcp/index.md +111 -0
  27. data/docs/api/mcp/server.md +225 -0
  28. data/docs/api/mcp/transports.md +264 -0
  29. data/docs/api/messages/index.md +67 -0
  30. data/docs/api/messages/text-message.md +102 -0
  31. data/docs/api/messages/tool-call-message.md +144 -0
  32. data/docs/api/messages/tool-result-message.md +154 -0
  33. data/docs/api/messages/user-message.md +171 -0
  34. data/docs/api/streaming/context.md +174 -0
  35. data/docs/api/streaming/events.md +237 -0
  36. data/docs/api/streaming/index.md +108 -0
  37. data/docs/architecture/core-concepts.md +243 -0
  38. data/docs/architecture/index.md +138 -0
  39. data/docs/architecture/message-flow.md +320 -0
  40. data/docs/architecture/network-orchestration.md +216 -0
  41. data/docs/architecture/robot-execution.md +243 -0
  42. data/docs/architecture/state-management.md +323 -0
  43. data/docs/assets/css/custom.css +56 -0
  44. data/docs/assets/images/robot_lab.jpg +0 -0
  45. data/docs/concepts.md +216 -0
  46. data/docs/examples/basic-chat.md +193 -0
  47. data/docs/examples/index.md +129 -0
  48. data/docs/examples/mcp-server.md +290 -0
  49. data/docs/examples/multi-robot-network.md +312 -0
  50. data/docs/examples/rails-application.md +420 -0
  51. data/docs/examples/tool-usage.md +310 -0
  52. data/docs/getting-started/configuration.md +230 -0
  53. data/docs/getting-started/index.md +56 -0
  54. data/docs/getting-started/installation.md +179 -0
  55. data/docs/getting-started/quick-start.md +203 -0
  56. data/docs/guides/building-robots.md +376 -0
  57. data/docs/guides/creating-networks.md +366 -0
  58. data/docs/guides/history.md +359 -0
  59. data/docs/guides/index.md +68 -0
  60. data/docs/guides/mcp-integration.md +356 -0
  61. data/docs/guides/memory.md +309 -0
  62. data/docs/guides/rails-integration.md +432 -0
  63. data/docs/guides/streaming.md +314 -0
  64. data/docs/guides/using-tools.md +394 -0
  65. data/docs/index.md +160 -0
  66. data/examples/01_simple_robot.rb +38 -0
  67. data/examples/02_tools.rb +106 -0
  68. data/examples/03_network.rb +103 -0
  69. data/examples/04_mcp.rb +219 -0
  70. data/examples/05_streaming.rb +124 -0
  71. data/examples/06_prompt_templates.rb +324 -0
  72. data/examples/07_network_memory.rb +329 -0
  73. data/examples/prompts/assistant/system.txt.erb +2 -0
  74. data/examples/prompts/assistant/user.txt.erb +1 -0
  75. data/examples/prompts/billing/system.txt.erb +7 -0
  76. data/examples/prompts/billing/user.txt.erb +1 -0
  77. data/examples/prompts/classifier/system.txt.erb +4 -0
  78. data/examples/prompts/classifier/user.txt.erb +1 -0
  79. data/examples/prompts/entity_extractor/system.txt.erb +11 -0
  80. data/examples/prompts/entity_extractor/user.txt.erb +3 -0
  81. data/examples/prompts/escalation/system.txt.erb +35 -0
  82. data/examples/prompts/escalation/user.txt.erb +34 -0
  83. data/examples/prompts/general/system.txt.erb +4 -0
  84. data/examples/prompts/general/user.txt.erb +1 -0
  85. data/examples/prompts/github_assistant/system.txt.erb +6 -0
  86. data/examples/prompts/github_assistant/user.txt.erb +1 -0
  87. data/examples/prompts/helper/system.txt.erb +1 -0
  88. data/examples/prompts/helper/user.txt.erb +1 -0
  89. data/examples/prompts/keyword_extractor/system.txt.erb +8 -0
  90. data/examples/prompts/keyword_extractor/user.txt.erb +3 -0
  91. data/examples/prompts/order_support/system.txt.erb +27 -0
  92. data/examples/prompts/order_support/user.txt.erb +22 -0
  93. data/examples/prompts/product_support/system.txt.erb +30 -0
  94. data/examples/prompts/product_support/user.txt.erb +32 -0
  95. data/examples/prompts/sentiment_analyzer/system.txt.erb +9 -0
  96. data/examples/prompts/sentiment_analyzer/user.txt.erb +3 -0
  97. data/examples/prompts/synthesizer/system.txt.erb +14 -0
  98. data/examples/prompts/synthesizer/user.txt.erb +15 -0
  99. data/examples/prompts/technical/system.txt.erb +7 -0
  100. data/examples/prompts/technical/user.txt.erb +1 -0
  101. data/examples/prompts/triage/system.txt.erb +16 -0
  102. data/examples/prompts/triage/user.txt.erb +17 -0
  103. data/lib/generators/robot_lab/install_generator.rb +78 -0
  104. data/lib/generators/robot_lab/robot_generator.rb +55 -0
  105. data/lib/generators/robot_lab/templates/initializer.rb.tt +41 -0
  106. data/lib/generators/robot_lab/templates/migration.rb.tt +32 -0
  107. data/lib/generators/robot_lab/templates/result_model.rb.tt +52 -0
  108. data/lib/generators/robot_lab/templates/robot.rb.tt +46 -0
  109. data/lib/generators/robot_lab/templates/robot_test.rb.tt +32 -0
  110. data/lib/generators/robot_lab/templates/routing_robot.rb.tt +53 -0
  111. data/lib/generators/robot_lab/templates/thread_model.rb.tt +40 -0
  112. data/lib/robot_lab/adapters/anthropic.rb +163 -0
  113. data/lib/robot_lab/adapters/base.rb +85 -0
  114. data/lib/robot_lab/adapters/gemini.rb +193 -0
  115. data/lib/robot_lab/adapters/openai.rb +159 -0
  116. data/lib/robot_lab/adapters/registry.rb +81 -0
  117. data/lib/robot_lab/configuration.rb +143 -0
  118. data/lib/robot_lab/error.rb +32 -0
  119. data/lib/robot_lab/errors.rb +70 -0
  120. data/lib/robot_lab/history/active_record_adapter.rb +146 -0
  121. data/lib/robot_lab/history/config.rb +115 -0
  122. data/lib/robot_lab/history/thread_manager.rb +93 -0
  123. data/lib/robot_lab/mcp/client.rb +210 -0
  124. data/lib/robot_lab/mcp/server.rb +84 -0
  125. data/lib/robot_lab/mcp/transports/base.rb +56 -0
  126. data/lib/robot_lab/mcp/transports/sse.rb +117 -0
  127. data/lib/robot_lab/mcp/transports/stdio.rb +133 -0
  128. data/lib/robot_lab/mcp/transports/streamable_http.rb +139 -0
  129. data/lib/robot_lab/mcp/transports/websocket.rb +108 -0
  130. data/lib/robot_lab/memory.rb +882 -0
  131. data/lib/robot_lab/memory_change.rb +123 -0
  132. data/lib/robot_lab/message.rb +357 -0
  133. data/lib/robot_lab/network.rb +350 -0
  134. data/lib/robot_lab/rails/engine.rb +29 -0
  135. data/lib/robot_lab/rails/railtie.rb +42 -0
  136. data/lib/robot_lab/robot.rb +560 -0
  137. data/lib/robot_lab/robot_result.rb +205 -0
  138. data/lib/robot_lab/robotic_model.rb +324 -0
  139. data/lib/robot_lab/state_proxy.rb +188 -0
  140. data/lib/robot_lab/streaming/context.rb +144 -0
  141. data/lib/robot_lab/streaming/events.rb +95 -0
  142. data/lib/robot_lab/streaming/sequence_counter.rb +48 -0
  143. data/lib/robot_lab/task.rb +117 -0
  144. data/lib/robot_lab/tool.rb +223 -0
  145. data/lib/robot_lab/tool_config.rb +112 -0
  146. data/lib/robot_lab/tool_manifest.rb +234 -0
  147. data/lib/robot_lab/user_message.rb +118 -0
  148. data/lib/robot_lab/version.rb +5 -0
  149. data/lib/robot_lab/waiter.rb +73 -0
  150. data/lib/robot_lab.rb +195 -0
  151. data/mkdocs.yml +214 -0
  152. data/sig/robot_lab.rbs +4 -0
  153. metadata +442 -0
@@ -0,0 +1,264 @@
1
+ # MCP Transports
2
+
3
+ Communication methods for MCP connections.
4
+
5
+ ## Overview
6
+
7
+ Transports handle the low-level communication between MCP clients and servers. RobotLab supports multiple transport types for different deployment scenarios.
8
+
9
+ ## Transport Types
10
+
11
+ ### Stdio
12
+
13
+ Standard input/output for local process communication.
14
+
15
+ ```ruby
16
+ {
17
+ type: "stdio",
18
+ command: "npx",
19
+ args: ["@modelcontextprotocol/server-filesystem", "/path"],
20
+ env: { "DEBUG" => "true" }
21
+ }
22
+ ```
23
+
24
+ **Options:**
25
+
26
+ | Option | Type | Description |
27
+ |--------|------|-------------|
28
+ | `command` | `String` | Executable command |
29
+ | `args` | `Array` | Command arguments |
30
+ | `env` | `Hash` | Environment variables |
31
+ | `cwd` | `String` | Working directory |
32
+
33
+ **Use Cases:**
34
+
35
+ - Local development
36
+ - CLI tools
37
+ - Subprocess servers
38
+
39
+ ### WebSocket
40
+
41
+ Bidirectional real-time communication.
42
+
43
+ ```ruby
44
+ {
45
+ type: "websocket",
46
+ url: "wss://mcp.example.com/ws",
47
+ headers: { "Authorization" => "Bearer token" }
48
+ }
49
+ ```
50
+
51
+ **Options:**
52
+
53
+ | Option | Type | Description |
54
+ |--------|------|-------------|
55
+ | `url` | `String` | WebSocket endpoint |
56
+ | `headers` | `Hash` | HTTP headers |
57
+ | `ping_interval` | `Integer` | Keep-alive interval (seconds) |
58
+
59
+ **Use Cases:**
60
+
61
+ - Remote servers
62
+ - Real-time applications
63
+ - Long-running connections
64
+
65
+ ### SSE (Server-Sent Events)
66
+
67
+ Unidirectional server-to-client streaming.
68
+
69
+ ```ruby
70
+ {
71
+ type: "sse",
72
+ url: "https://mcp.example.com/sse",
73
+ headers: { "Authorization" => "Bearer token" }
74
+ }
75
+ ```
76
+
77
+ **Options:**
78
+
79
+ | Option | Type | Description |
80
+ |--------|------|-------------|
81
+ | `url` | `String` | SSE endpoint |
82
+ | `headers` | `Hash` | HTTP headers |
83
+ | `post_url` | `String` | Endpoint for client messages |
84
+
85
+ **Use Cases:**
86
+
87
+ - Firewall-friendly connections
88
+ - Browser-based clients
89
+ - Streaming responses
90
+
91
+ ### HTTP
92
+
93
+ Request/response communication.
94
+
95
+ ```ruby
96
+ {
97
+ type: "http",
98
+ url: "https://mcp.example.com/mcp",
99
+ headers: { "Authorization" => "Bearer token" },
100
+ timeout: 30
101
+ }
102
+ ```
103
+
104
+ **Options:**
105
+
106
+ | Option | Type | Description |
107
+ |--------|------|-------------|
108
+ | `url` | `String` | HTTP endpoint |
109
+ | `headers` | `Hash` | HTTP headers |
110
+ | `timeout` | `Integer` | Request timeout (seconds) |
111
+ | `retry` | `Integer` | Retry attempts |
112
+
113
+ **Use Cases:**
114
+
115
+ - Simple integrations
116
+ - Stateless operations
117
+ - Load-balanced servers
118
+
119
+ ## Examples
120
+
121
+ ### Local Server with Stdio
122
+
123
+ ```ruby
124
+ network = RobotLab.create_network do
125
+ mcp [
126
+ {
127
+ name: "filesystem",
128
+ transport: {
129
+ type: "stdio",
130
+ command: "npx",
131
+ args: ["@modelcontextprotocol/server-filesystem", "/home/user/docs"]
132
+ }
133
+ }
134
+ ]
135
+ end
136
+ ```
137
+
138
+ ### Remote Server with WebSocket
139
+
140
+ ```ruby
141
+ network = RobotLab.create_network do
142
+ mcp [
143
+ {
144
+ name: "remote_tools",
145
+ transport: {
146
+ type: "websocket",
147
+ url: "wss://tools.example.com/mcp",
148
+ headers: {
149
+ "Authorization" => "Bearer #{ENV['MCP_TOKEN']}"
150
+ }
151
+ }
152
+ }
153
+ ]
154
+ end
155
+ ```
156
+
157
+ ### Multiple Transports
158
+
159
+ ```ruby
160
+ network = RobotLab.create_network do
161
+ mcp [
162
+ # Local filesystem
163
+ {
164
+ name: "fs",
165
+ transport: { type: "stdio", command: "mcp-fs" }
166
+ },
167
+ # Remote API
168
+ {
169
+ name: "api",
170
+ transport: {
171
+ type: "http",
172
+ url: "https://api.example.com/mcp"
173
+ }
174
+ },
175
+ # Real-time service
176
+ {
177
+ name: "realtime",
178
+ transport: {
179
+ type: "websocket",
180
+ url: "wss://realtime.example.com/mcp"
181
+ }
182
+ }
183
+ ]
184
+ end
185
+ ```
186
+
187
+ ### Custom Transport
188
+
189
+ ```ruby
190
+ class CustomTransport
191
+ def initialize(options)
192
+ @options = options
193
+ end
194
+
195
+ def connect
196
+ # Establish connection
197
+ end
198
+
199
+ def disconnect
200
+ # Close connection
201
+ end
202
+
203
+ def send(message)
204
+ # Send message to server
205
+ end
206
+
207
+ def receive
208
+ # Receive message from server
209
+ end
210
+ end
211
+
212
+ RobotLab::MCP.register_transport(:custom, CustomTransport)
213
+
214
+ # Use custom transport
215
+ {
216
+ type: "custom",
217
+ option1: "value1"
218
+ }
219
+ ```
220
+
221
+ ## Connection Lifecycle
222
+
223
+ ```mermaid
224
+ sequenceDiagram
225
+ participant C as Client
226
+ participant T as Transport
227
+ participant S as Server
228
+
229
+ C->>T: connect()
230
+ T->>S: Establish connection
231
+ S-->>T: Connection established
232
+ T-->>C: Connected
233
+
234
+ C->>T: send(request)
235
+ T->>S: Forward request
236
+ S-->>T: Response
237
+ T-->>C: receive() → response
238
+
239
+ C->>T: disconnect()
240
+ T->>S: Close connection
241
+ ```
242
+
243
+ ## Error Handling
244
+
245
+ ```ruby
246
+ begin
247
+ client.connect
248
+ rescue RobotLab::MCP::ConnectionError => e
249
+ case e.transport
250
+ when "stdio"
251
+ puts "Command failed: #{e.message}"
252
+ when "websocket"
253
+ puts "WebSocket error: #{e.message}"
254
+ when "http"
255
+ puts "HTTP error: #{e.status} - #{e.message}"
256
+ end
257
+ end
258
+ ```
259
+
260
+ ## See Also
261
+
262
+ - [MCP Overview](index.md)
263
+ - [MCP Client](client.md)
264
+ - [MCP Server](server.md)
@@ -0,0 +1,67 @@
1
+ # Messages
2
+
3
+ Message types for LLM conversation representation.
4
+
5
+ ## Overview
6
+
7
+ RobotLab uses a structured message system to represent conversations between users, assistants, and tools.
8
+
9
+ ```ruby
10
+ # User input
11
+ user_msg = UserMessage.new("Hello", thread_id: "123")
12
+
13
+ # Assistant response
14
+ text_msg = TextMessage.new("Hi there!")
15
+
16
+ # Tool interaction
17
+ tool_call = ToolCallMessage.new(id: "call_1", name: "get_weather", input: { city: "NYC" })
18
+ tool_result = ToolResultMessage.new(id: "call_1", result: { temp: 72 })
19
+ ```
20
+
21
+ ## Message Hierarchy
22
+
23
+ ```
24
+ Message (base)
25
+ ├── UserMessage - User input with metadata
26
+ ├── TextMessage - Assistant text response
27
+ ├── ToolMessage - Tool-related messages
28
+ │ ├── ToolCallMessage - Tool invocation
29
+ │ └── ToolResultMessage - Tool result
30
+ └── SystemMessage - System prompts
31
+ ```
32
+
33
+ ## Common Interface
34
+
35
+ All messages implement:
36
+
37
+ ```ruby
38
+ message.role # => Symbol (:user, :assistant, :tool)
39
+ message.content # => String or structured data
40
+ message.to_h # => Hash representation
41
+ message.to_json # => JSON string
42
+ ```
43
+
44
+ ## Classes
45
+
46
+ | Class | Description |
47
+ |-------|-------------|
48
+ | [UserMessage](user-message.md) | User input with thread and metadata |
49
+ | [TextMessage](text-message.md) | Assistant text response |
50
+ | [ToolCallMessage](tool-call-message.md) | Tool invocation request |
51
+ | [ToolResultMessage](tool-result-message.md) | Tool execution result |
52
+
53
+ ## Usage in State
54
+
55
+ Messages are typically accessed through state:
56
+
57
+ ```ruby
58
+ state.messages # => Array<Message>
59
+
60
+ # Format for LLM
61
+ state.format_history # => Array<Hash>
62
+ ```
63
+
64
+ ## See Also
65
+
66
+ - [State](../core/state.md)
67
+ - [Message Flow Architecture](../../architecture/message-flow.md)
@@ -0,0 +1,102 @@
1
+ # TextMessage
2
+
3
+ Assistant text response.
4
+
5
+ ## Class: `RobotLab::TextMessage`
6
+
7
+ ```ruby
8
+ message = TextMessage.new("Hello! How can I help you today?")
9
+ ```
10
+
11
+ ## Constructor
12
+
13
+ ```ruby
14
+ TextMessage.new(content)
15
+ ```
16
+
17
+ **Parameters:**
18
+
19
+ | Name | Type | Description |
20
+ |------|------|-------------|
21
+ | `content` | `String` | Response text |
22
+
23
+ ## Attributes
24
+
25
+ ### content
26
+
27
+ ```ruby
28
+ message.content # => String
29
+ ```
30
+
31
+ The response text.
32
+
33
+ ### role
34
+
35
+ ```ruby
36
+ message.role # => :assistant
37
+ ```
38
+
39
+ Always returns `:assistant`.
40
+
41
+ ## Methods
42
+
43
+ ### to_h
44
+
45
+ ```ruby
46
+ message.to_h # => Hash
47
+ ```
48
+
49
+ Hash representation.
50
+
51
+ **Returns:**
52
+
53
+ ```ruby
54
+ {
55
+ role: :assistant,
56
+ content: "Hello! How can I help you today?"
57
+ }
58
+ ```
59
+
60
+ ### to_json
61
+
62
+ ```ruby
63
+ message.to_json # => String
64
+ ```
65
+
66
+ JSON representation.
67
+
68
+ ## Examples
69
+
70
+ ### Basic Response
71
+
72
+ ```ruby
73
+ message = TextMessage.new("Your order has shipped!")
74
+ ```
75
+
76
+ ### In Robot Results
77
+
78
+ ```ruby
79
+ result = robot.run(state: state)
80
+
81
+ # Extract text messages
82
+ result.output.each do |msg|
83
+ if msg.is_a?(TextMessage)
84
+ puts msg.content
85
+ end
86
+ end
87
+ ```
88
+
89
+ ### Filtering Text Content
90
+
91
+ ```ruby
92
+ # Get only text responses from results
93
+ text_responses = state.results.flat_map(&:output).select do |msg|
94
+ msg.is_a?(TextMessage)
95
+ end.map(&:content)
96
+ ```
97
+
98
+ ## See Also
99
+
100
+ - [UserMessage](user-message.md)
101
+ - [ToolCallMessage](tool-call-message.md)
102
+ - [Robot](../core/robot.md)
@@ -0,0 +1,144 @@
1
+ # ToolCallMessage
2
+
3
+ Tool invocation request from the LLM.
4
+
5
+ ## Class: `RobotLab::ToolCallMessage`
6
+
7
+ ```ruby
8
+ message = ToolCallMessage.new(
9
+ id: "call_abc123",
10
+ name: "get_weather",
11
+ input: { city: "New York", units: "fahrenheit" }
12
+ )
13
+ ```
14
+
15
+ ## Constructor
16
+
17
+ ```ruby
18
+ ToolCallMessage.new(id:, name:, input:)
19
+ ```
20
+
21
+ **Parameters:**
22
+
23
+ | Name | Type | Description |
24
+ |------|------|-------------|
25
+ | `id` | `String` | Unique call identifier |
26
+ | `name` | `String` | Tool name |
27
+ | `input` | `Hash` | Tool parameters |
28
+
29
+ ## Attributes
30
+
31
+ ### id
32
+
33
+ ```ruby
34
+ message.id # => String
35
+ ```
36
+
37
+ Unique identifier for this tool call. Used to match with `ToolResultMessage`.
38
+
39
+ ### name
40
+
41
+ ```ruby
42
+ message.name # => String
43
+ ```
44
+
45
+ Name of the tool being invoked.
46
+
47
+ ### input
48
+
49
+ ```ruby
50
+ message.input # => Hash
51
+ ```
52
+
53
+ Parameters passed to the tool.
54
+
55
+ ### role
56
+
57
+ ```ruby
58
+ message.role # => :assistant
59
+ ```
60
+
61
+ Always returns `:assistant` (the LLM initiates tool calls).
62
+
63
+ ## Methods
64
+
65
+ ### to_h
66
+
67
+ ```ruby
68
+ message.to_h # => Hash
69
+ ```
70
+
71
+ Hash representation.
72
+
73
+ **Returns:**
74
+
75
+ ```ruby
76
+ {
77
+ role: :assistant,
78
+ tool_call: {
79
+ id: "call_abc123",
80
+ name: "get_weather",
81
+ input: { city: "New York", units: "fahrenheit" }
82
+ }
83
+ }
84
+ ```
85
+
86
+ ### to_json
87
+
88
+ ```ruby
89
+ message.to_json # => String
90
+ ```
91
+
92
+ JSON representation.
93
+
94
+ ## Examples
95
+
96
+ ### Basic Tool Call
97
+
98
+ ```ruby
99
+ call = ToolCallMessage.new(
100
+ id: "call_1",
101
+ name: "search_orders",
102
+ input: { user_id: "123", status: "pending" }
103
+ )
104
+ ```
105
+
106
+ ### Processing Tool Calls
107
+
108
+ ```ruby
109
+ result.output.each do |msg|
110
+ case msg
111
+ when ToolCallMessage
112
+ puts "Tool called: #{msg.name}"
113
+ puts "Parameters: #{msg.input.inspect}"
114
+ when ToolResultMessage
115
+ puts "Result for #{msg.id}: #{msg.result}"
116
+ end
117
+ end
118
+ ```
119
+
120
+ ### In Tool Execution Flow
121
+
122
+ ```ruby
123
+ # LLM returns a tool call
124
+ tool_call = ToolCallMessage.new(
125
+ id: "call_weather_1",
126
+ name: "get_weather",
127
+ input: { city: "Seattle" }
128
+ )
129
+
130
+ # Tool is executed
131
+ result = tool.call(tool_call.input, state: state)
132
+
133
+ # Result is recorded
134
+ tool_result = ToolResultMessage.new(
135
+ id: tool_call.id,
136
+ result: result
137
+ )
138
+ ```
139
+
140
+ ## See Also
141
+
142
+ - [ToolResultMessage](tool-result-message.md)
143
+ - [Tool](../core/tool.md)
144
+ - [Using Tools Guide](../../guides/using-tools.md)
@@ -0,0 +1,154 @@
1
+ # ToolResultMessage
2
+
3
+ Result from tool execution.
4
+
5
+ ## Class: `RobotLab::ToolResultMessage`
6
+
7
+ ```ruby
8
+ message = ToolResultMessage.new(
9
+ id: "call_abc123",
10
+ result: { temperature: 72, conditions: "sunny" }
11
+ )
12
+ ```
13
+
14
+ ## Constructor
15
+
16
+ ```ruby
17
+ ToolResultMessage.new(id:, result:)
18
+ ```
19
+
20
+ **Parameters:**
21
+
22
+ | Name | Type | Description |
23
+ |------|------|-------------|
24
+ | `id` | `String` | Matching tool call ID |
25
+ | `result` | `Object` | Tool execution result |
26
+
27
+ ## Attributes
28
+
29
+ ### id
30
+
31
+ ```ruby
32
+ message.id # => String
33
+ ```
34
+
35
+ Identifier matching the corresponding `ToolCallMessage`.
36
+
37
+ ### result
38
+
39
+ ```ruby
40
+ message.result # => Object
41
+ ```
42
+
43
+ The result returned by the tool. Can be any serializable object.
44
+
45
+ ### role
46
+
47
+ ```ruby
48
+ message.role # => :tool
49
+ ```
50
+
51
+ Always returns `:tool`.
52
+
53
+ ## Methods
54
+
55
+ ### to_h
56
+
57
+ ```ruby
58
+ message.to_h # => Hash
59
+ ```
60
+
61
+ Hash representation.
62
+
63
+ **Returns:**
64
+
65
+ ```ruby
66
+ {
67
+ role: :tool,
68
+ tool_result: {
69
+ id: "call_abc123",
70
+ result: { temperature: 72, conditions: "sunny" }
71
+ }
72
+ }
73
+ ```
74
+
75
+ ### to_json
76
+
77
+ ```ruby
78
+ message.to_json # => String
79
+ ```
80
+
81
+ JSON representation.
82
+
83
+ ## Examples
84
+
85
+ ### Basic Result
86
+
87
+ ```ruby
88
+ result = ToolResultMessage.new(
89
+ id: "call_1",
90
+ result: { success: true, order_id: "ord_123" }
91
+ )
92
+ ```
93
+
94
+ ### String Result
95
+
96
+ ```ruby
97
+ result = ToolResultMessage.new(
98
+ id: "call_time",
99
+ result: "2024-01-15T10:30:00Z"
100
+ )
101
+ ```
102
+
103
+ ### Array Result
104
+
105
+ ```ruby
106
+ result = ToolResultMessage.new(
107
+ id: "call_search",
108
+ result: [
109
+ { id: 1, name: "Product A" },
110
+ { id: 2, name: "Product B" }
111
+ ]
112
+ )
113
+ ```
114
+
115
+ ### Error Result
116
+
117
+ ```ruby
118
+ result = ToolResultMessage.new(
119
+ id: "call_order",
120
+ result: { success: false, error: "Order not found" }
121
+ )
122
+ ```
123
+
124
+ ### Matching with Tool Calls
125
+
126
+ ```ruby
127
+ # Process all tool interactions
128
+ result.output.each_cons(2) do |a, b|
129
+ if a.is_a?(ToolCallMessage) && b.is_a?(ToolResultMessage)
130
+ if a.id == b.id
131
+ puts "#{a.name}(#{a.input}) => #{b.result}"
132
+ end
133
+ end
134
+ end
135
+ ```
136
+
137
+ ### In Result History
138
+
139
+ ```ruby
140
+ # Find all tool results from execution
141
+ tool_results = state.results
142
+ .flat_map(&:output)
143
+ .select { |m| m.is_a?(ToolResultMessage) }
144
+
145
+ tool_results.each do |tr|
146
+ puts "Tool result: #{tr.result}"
147
+ end
148
+ ```
149
+
150
+ ## See Also
151
+
152
+ - [ToolCallMessage](tool-call-message.md)
153
+ - [Tool](../core/tool.md)
154
+ - [Using Tools Guide](../../guides/using-tools.md)