robot_lab 0.3.0 → 0.3.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 (256) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/README.md +1 -1
  4. data/lib/robot_lab/mcp/transports/streamable_http.rb +1 -1
  5. data/lib/robot_lab/version.rb +1 -1
  6. metadata +3 -253
  7. data/.architecture/AGENTS.md +0 -32
  8. data/.architecture/config.yml +0 -8
  9. data/.architecture/members.yml +0 -60
  10. data/.architecture/reviews/feature-free-will.md +0 -490
  11. data/.architecture/reviews/overall-codebase.md +0 -427
  12. data/.claude/settings.local.json +0 -57
  13. data/.codex/config.toml +0 -2
  14. data/.envrc +0 -6
  15. data/.github/workflows/deploy-github-pages.yml +0 -52
  16. data/.irbrc +0 -6
  17. data/.loki +0 -65
  18. data/.quality/reek_baseline.txt +0 -43
  19. data/.rubocop.yml +0 -10
  20. data/Archspec.rb +0 -44
  21. data/CLAUDE.md +0 -141
  22. data/COMMITS.md +0 -196
  23. data/Rakefile +0 -193
  24. data/_typos.toml +0 -21
  25. data/agent2agent_review.md +0 -192
  26. data/agentf_improvements.md +0 -253
  27. data/agents.md +0 -14
  28. data/docs/api/core/index.md +0 -147
  29. data/docs/api/core/memory.md +0 -578
  30. data/docs/api/core/network.md +0 -553
  31. data/docs/api/core/result.md +0 -211
  32. data/docs/api/core/robot.md +0 -1667
  33. data/docs/api/core/state.md +0 -145
  34. data/docs/api/core/tool.md +0 -520
  35. data/docs/api/errors.md +0 -323
  36. data/docs/api/hooks.md +0 -469
  37. data/docs/api/index.md +0 -137
  38. data/docs/api/mcp/client.md +0 -387
  39. data/docs/api/mcp/index.md +0 -267
  40. data/docs/api/mcp/server.md +0 -252
  41. data/docs/api/mcp/transports.md +0 -339
  42. data/docs/api/messages/index.md +0 -126
  43. data/docs/api/messages/text-message.md +0 -170
  44. data/docs/api/messages/tool-call-message.md +0 -206
  45. data/docs/api/messages/tool-result-message.md +0 -242
  46. data/docs/api/messages/user-message.md +0 -232
  47. data/docs/api/skills.md +0 -423
  48. data/docs/api/streaming/context.md +0 -280
  49. data/docs/api/streaming/events.md +0 -185
  50. data/docs/api/streaming/index.md +0 -156
  51. data/docs/api/support.md +0 -846
  52. data/docs/architecture/core-concepts.md +0 -575
  53. data/docs/architecture/index.md +0 -252
  54. data/docs/architecture/message-flow.md +0 -366
  55. data/docs/architecture/network-orchestration.md +0 -478
  56. data/docs/architecture/robot-execution.md +0 -396
  57. data/docs/architecture/state-management.md +0 -410
  58. data/docs/assets/css/custom.css +0 -56
  59. data/docs/assets/images/robot_lab.jpg +0 -0
  60. data/docs/concepts.md +0 -641
  61. data/docs/examples/basic-chat.md +0 -258
  62. data/docs/examples/index.md +0 -425
  63. data/docs/examples/mcp-server.md +0 -403
  64. data/docs/examples/multi-robot-network.md +0 -476
  65. data/docs/examples/tool-usage.md +0 -468
  66. data/docs/getting-started/configuration.md +0 -645
  67. data/docs/getting-started/index.md +0 -56
  68. data/docs/getting-started/installation.md +0 -197
  69. data/docs/getting-started/quick-start.md +0 -293
  70. data/docs/guides/building-robots.md +0 -1187
  71. data/docs/guides/creating-networks.md +0 -736
  72. data/docs/guides/hooks.md +0 -1206
  73. data/docs/guides/index.md +0 -78
  74. data/docs/guides/knowledge.md +0 -219
  75. data/docs/guides/mcp-integration.md +0 -740
  76. data/docs/guides/memory.md +0 -458
  77. data/docs/guides/observability.md +0 -733
  78. data/docs/guides/streaming.md +0 -323
  79. data/docs/guides/using-tools.md +0 -780
  80. data/docs/index.md +0 -280
  81. data/docs/superpowers/plans/2026-05-06-agentskills.md +0 -1303
  82. data/docs/superpowers/specs/2026-05-06-agentskills-design.md +0 -247
  83. data/examples/.envrc +0 -3
  84. data/examples/01_simple_robot.rb +0 -31
  85. data/examples/02_tools.rb +0 -109
  86. data/examples/03_network.rb +0 -118
  87. data/examples/04_mcp.rb +0 -217
  88. data/examples/05_streaming.rb +0 -137
  89. data/examples/06_prompt_templates.rb +0 -325
  90. data/examples/07_network_memory.rb +0 -313
  91. data/examples/08_llm_config.rb +0 -162
  92. data/examples/09_chaining.rb +0 -251
  93. data/examples/10_memory.rb +0 -315
  94. data/examples/11_network_introspection.rb +0 -239
  95. data/examples/12_message_bus.rb +0 -67
  96. data/examples/13_spawn.rb +0 -85
  97. data/examples/14_rusty_circuit/.envrc +0 -1
  98. data/examples/14_rusty_circuit/.gitignore +0 -1
  99. data/examples/14_rusty_circuit/README.md +0 -1
  100. data/examples/14_rusty_circuit/comic.rb +0 -149
  101. data/examples/14_rusty_circuit/display.rb +0 -217
  102. data/examples/14_rusty_circuit/heckler.rb +0 -65
  103. data/examples/14_rusty_circuit/open_mic.rb +0 -132
  104. data/examples/14_rusty_circuit/prompts/open_mic_comic.md +0 -20
  105. data/examples/14_rusty_circuit/prompts/open_mic_heckler.md +0 -23
  106. data/examples/14_rusty_circuit/prompts/open_mic_scout.md +0 -20
  107. data/examples/14_rusty_circuit/scout.rb +0 -165
  108. data/examples/14_rusty_circuit/show.log +0 -234
  109. data/examples/15_memory_network_and_bus/.envrc +0 -1
  110. data/examples/15_memory_network_and_bus/README.md +0 -66
  111. data/examples/15_memory_network_and_bus/editor_in_chief.rb +0 -24
  112. data/examples/15_memory_network_and_bus/editorial_pipeline.rb +0 -213
  113. data/examples/15_memory_network_and_bus/linux_writer.rb +0 -80
  114. data/examples/15_memory_network_and_bus/os_editor.rb +0 -48
  115. data/examples/15_memory_network_and_bus/os_writer.rb +0 -49
  116. data/examples/15_memory_network_and_bus/output/combined_article.md +0 -11
  117. data/examples/15_memory_network_and_bus/output/final_article.md +0 -8
  118. data/examples/15_memory_network_and_bus/output/linux_draft.md +0 -7
  119. data/examples/15_memory_network_and_bus/output/mac_draft.md +0 -7
  120. data/examples/15_memory_network_and_bus/output/memory.json +0 -13
  121. data/examples/15_memory_network_and_bus/output/revision_1.md +0 -29
  122. data/examples/15_memory_network_and_bus/output/revision_2.md +0 -50
  123. data/examples/15_memory_network_and_bus/output/revision_3.md +0 -8
  124. data/examples/15_memory_network_and_bus/output/windows_draft.md +0 -7
  125. data/examples/15_memory_network_and_bus/prompts/os_advocate.md +0 -13
  126. data/examples/15_memory_network_and_bus/prompts/os_chief.md +0 -13
  127. data/examples/15_memory_network_and_bus/prompts/os_editor.md +0 -13
  128. data/examples/16_writers_room/.envrc +0 -1
  129. data/examples/16_writers_room/display.rb +0 -158
  130. data/examples/16_writers_room/output/.gitignore +0 -4
  131. data/examples/16_writers_room/output/README.md +0 -69
  132. data/examples/16_writers_room/output/opus_001.md +0 -263
  133. data/examples/16_writers_room/output/opus_001_notes.log +0 -470
  134. data/examples/16_writers_room/output/opus_002.md +0 -245
  135. data/examples/16_writers_room/output/opus_002_notes.log +0 -546
  136. data/examples/16_writers_room/output/opus_002_screenplay.md +0 -7989
  137. data/examples/16_writers_room/output/opus_002_screenplay_notes.md +0 -993
  138. data/examples/16_writers_room/prompts/screenplay_writer.md +0 -66
  139. data/examples/16_writers_room/prompts/writer.md +0 -37
  140. data/examples/16_writers_room/room.rb +0 -186
  141. data/examples/16_writers_room/tools.rb +0 -173
  142. data/examples/16_writers_room/writer.rb +0 -121
  143. data/examples/16_writers_room/writers_room.rb +0 -256
  144. data/examples/17_skills.rb +0 -234
  145. data/examples/18_rails/.envrc +0 -3
  146. data/examples/18_rails/.gitignore +0 -5
  147. data/examples/18_rails/Gemfile +0 -11
  148. data/examples/18_rails/README.md +0 -67
  149. data/examples/18_rails/Rakefile +0 -4
  150. data/examples/18_rails/app/controllers/application_controller.rb +0 -4
  151. data/examples/18_rails/app/controllers/chat_controller.rb +0 -50
  152. data/examples/18_rails/app/jobs/application_job.rb +0 -4
  153. data/examples/18_rails/app/jobs/robot_run_job.rb +0 -25
  154. data/examples/18_rails/app/models/application_record.rb +0 -5
  155. data/examples/18_rails/app/models/robot_lab_result.rb +0 -36
  156. data/examples/18_rails/app/models/robot_lab_thread.rb +0 -23
  157. data/examples/18_rails/app/robots/chat_robot.rb +0 -25
  158. data/examples/18_rails/app/tools/time_tool.rb +0 -9
  159. data/examples/18_rails/app/views/chat/_user_message.html.erb +0 -1
  160. data/examples/18_rails/app/views/chat/index.html.erb +0 -67
  161. data/examples/18_rails/app/views/layouts/application.html.erb +0 -49
  162. data/examples/18_rails/bin/dev +0 -7
  163. data/examples/18_rails/bin/rails +0 -6
  164. data/examples/18_rails/bin/setup +0 -15
  165. data/examples/18_rails/config/application.rb +0 -33
  166. data/examples/18_rails/config/cable.yml +0 -2
  167. data/examples/18_rails/config/database.yml +0 -5
  168. data/examples/18_rails/config/environment.rb +0 -4
  169. data/examples/18_rails/config/initializers/robot_lab.rb +0 -11
  170. data/examples/18_rails/config/routes.rb +0 -6
  171. data/examples/18_rails/config.ru +0 -4
  172. data/examples/18_rails/db/migrate/001_create_robot_lab_tables.rb +0 -32
  173. data/examples/19_token_tracking.rb +0 -138
  174. data/examples/20_circuit_breaker.rb +0 -147
  175. data/examples/21_learning_loop.rb +0 -181
  176. data/examples/22_context_compression.rb +0 -172
  177. data/examples/23_convergence.rb +0 -133
  178. data/examples/24_structured_delegation.rb +0 -151
  179. data/examples/25_history_search/conversation.jsonl +0 -30
  180. data/examples/25_history_search.rb +0 -133
  181. data/examples/26_document_store/api_versioning_adr.md +0 -52
  182. data/examples/26_document_store/incident_postmortem.md +0 -46
  183. data/examples/26_document_store/postgres_runbook.md +0 -49
  184. data/examples/26_document_store/redis_caching_guide.md +0 -48
  185. data/examples/26_document_store/sidekiq_guide.md +0 -51
  186. data/examples/26_document_store.rb +0 -140
  187. data/examples/27_incident_response/README.md +0 -65
  188. data/examples/27_incident_response/incident_response.rb +0 -261
  189. data/examples/28_mcp_discovery.rb +0 -113
  190. data/examples/29_ractor_tools.rb +0 -240
  191. data/examples/30_ractor_network.rb +0 -252
  192. data/examples/31_launch_assessment.rb +0 -246
  193. data/examples/32_newsletter_reader.rb +0 -193
  194. data/examples/33_stock_generator.rb +0 -80
  195. data/examples/33_stock_predictor.rb +0 -327
  196. data/examples/34_agentskills.rb +0 -76
  197. data/examples/35_hooks.rb +0 -266
  198. data/examples/README.md +0 -550
  199. data/examples/common.rb +0 -180
  200. data/examples/prompts/assistant.md +0 -5
  201. data/examples/prompts/audit_trail.md +0 -8
  202. data/examples/prompts/billing.md +0 -10
  203. data/examples/prompts/classifier.md +0 -7
  204. data/examples/prompts/comedian.md +0 -6
  205. data/examples/prompts/comedy_critic.md +0 -10
  206. data/examples/prompts/configurable.md +0 -9
  207. data/examples/prompts/dispatcher.md +0 -12
  208. data/examples/prompts/entity_extractor.md +0 -14
  209. data/examples/prompts/escalation.md +0 -42
  210. data/examples/prompts/frontmatter_mcp_test.md +0 -9
  211. data/examples/prompts/frontmatter_named_test.md +0 -5
  212. data/examples/prompts/frontmatter_tools_test.md +0 -6
  213. data/examples/prompts/general.md +0 -7
  214. data/examples/prompts/github_assistant.md +0 -14
  215. data/examples/prompts/helper.md +0 -4
  216. data/examples/prompts/incident_responder.md +0 -18
  217. data/examples/prompts/keyword_extractor.md +0 -11
  218. data/examples/prompts/llm_config_demo.md +0 -20
  219. data/examples/prompts/order_support.md +0 -35
  220. data/examples/prompts/os_advocate.md +0 -13
  221. data/examples/prompts/os_chief.md +0 -13
  222. data/examples/prompts/os_editor.md +0 -13
  223. data/examples/prompts/parameterized_main_test.md +0 -6
  224. data/examples/prompts/pii_redactor.md +0 -7
  225. data/examples/prompts/product_support.md +0 -37
  226. data/examples/prompts/runbook_protocol.md +0 -12
  227. data/examples/prompts/sentiment_analyzer.md +0 -12
  228. data/examples/prompts/skill_a_test.md +0 -4
  229. data/examples/prompts/skill_b_test.md +0 -4
  230. data/examples/prompts/skill_config_test.md +0 -5
  231. data/examples/prompts/skill_cycle_a_test.md +0 -6
  232. data/examples/prompts/skill_cycle_b_test.md +0 -6
  233. data/examples/prompts/skill_description_test.md +0 -4
  234. data/examples/prompts/skill_leaf_test.md +0 -4
  235. data/examples/prompts/skill_nested_test.md +0 -6
  236. data/examples/prompts/skill_refs_main_test.md +0 -6
  237. data/examples/prompts/skill_self_ref_test.md +0 -6
  238. data/examples/prompts/skill_with_mcp_test.md +0 -9
  239. data/examples/prompts/skill_with_params_test.md +0 -6
  240. data/examples/prompts/skill_with_robot_name_test.md +0 -5
  241. data/examples/prompts/skill_with_tools_test.md +0 -6
  242. data/examples/prompts/sre_compliance.md +0 -10
  243. data/examples/prompts/structured_output.md +0 -7
  244. data/examples/prompts/synthesizer.md +0 -17
  245. data/examples/prompts/technical.md +0 -10
  246. data/examples/prompts/template_with_skills_test.md +0 -6
  247. data/examples/prompts/triage.md +0 -22
  248. data/examples/ruboruby.md +0 -423
  249. data/examples/run_all.rb +0 -60
  250. data/examples/xyzzy.rb +0 -97
  251. data/logfile +0 -8
  252. data/mkdocs.yml +0 -209
  253. data/robot_concurrency.md +0 -38
  254. data/simple_acp_review.md +0 -298
  255. data/temp.md +0 -6
  256. data/tool_manifest_plan.md +0 -155
@@ -1,126 +0,0 @@
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", session_id: "123")
12
-
13
- # Assistant response
14
- text_msg = TextMessage.new(role: "assistant", content: "Hi there!")
15
-
16
- # Tool interaction
17
- tool = ToolMessage.new(id: "call_1", name: "get_weather", input: { city: "NYC" })
18
- tool_call = ToolCallMessage.new(role: "assistant", tools: [tool])
19
- tool_result = ToolResultMessage.new(tool: tool, content: { data: { temp: 72 } })
20
- ```
21
-
22
- ## Message Hierarchy
23
-
24
- ```
25
- Message (base)
26
- ├── TextMessage - role + text content
27
- ├── ToolCallMessage - role + Array<ToolMessage>
28
- └── ToolResultMessage - tool + result content
29
-
30
- UserMessage - Standalone PORO (superclass Object)
31
- ToolMessage - Standalone PORO (superclass Object)
32
- ```
33
-
34
- `UserMessage` and `ToolMessage` are plain objects — their superclass is `Object`,
35
- not `Message`. They do not respond to `type`, `role`, or any of the predicates
36
- below.
37
-
38
- ## Common Interface
39
-
40
- All Message subclasses implement:
41
-
42
- ```ruby
43
- message.role # => String ("system", "user", "assistant", "tool_result")
44
- message.content # => String or structured data
45
- message.type # => String ("text", "tool_call", "tool_result")
46
- message.to_h # => Hash representation
47
- message.to_json # => JSON string
48
- ```
49
-
50
- Valid values are fixed by constants on `Message`, and the constructor raises
51
- `ArgumentError` for anything else:
52
-
53
- ```ruby
54
- RobotLab::Message::VALID_TYPES # => ["text", "tool_call", "tool_result"]
55
- RobotLab::Message::VALID_ROLES # => ["system", "user", "assistant", "tool_result"]
56
- RobotLab::Message::VALID_STOP_REASONS # => ["tool", "stop"]
57
- ```
58
-
59
- ### Nil keys and `to_h`
60
-
61
- `Message#to_h` — used as-is by `TextMessage` — ends in `.compact`, so any key
62
- whose value is `nil` is **absent** from the hash, not present with a `nil` value.
63
- A `TextMessage` built without a `stop_reason` produces a three-key hash. The same
64
- applies to `UserMessage#to_h`.
65
-
66
- `ToolCallMessage`, `ToolResultMessage`, and `ToolMessage` override `to_h` without
67
- compacting, so their keys are always present.
68
-
69
- Type and role predicates:
70
-
71
- ```ruby
72
- message.text? # => true if type is "text"
73
- message.tool_call? # => true if type is "tool_call"
74
- message.tool_result? # => true if type is "tool_result"
75
- message.system? # => true if role is "system"
76
- message.user? # => true if role is "user"
77
- message.assistant? # => true if role is "assistant"
78
- message.stopped? # => true if stop_reason is "stop"
79
- message.tool_stop? # => true if stop_reason is "tool"
80
- ```
81
-
82
- ## Classes
83
-
84
- | Class | Description |
85
- |-------|-------------|
86
- | [UserMessage](user-message.md) | User input with session and metadata |
87
- | [TextMessage](text-message.md) | Text message with role (system, user, or assistant) |
88
- | [ToolCallMessage](tool-call-message.md) | Tool invocation request containing ToolMessage objects |
89
- | [ToolResultMessage](tool-result-message.md) | Tool execution result |
90
-
91
- ## Usage in Memory
92
-
93
- Messages are typically accessed through memory:
94
-
95
- ```ruby
96
- memory.messages # => Array<Message>
97
-
98
- # Format for LLM
99
- memory.format_history # => Array<Message>
100
- ```
101
-
102
- ## Deserializing from Hash
103
-
104
- `Message.from_hash` reconstructs the correct subclass from a stored hash:
105
-
106
- ```ruby
107
- RobotLab::Message.from_hash({ type: "text", role: "user", content: "Hello" })
108
- # => #<RobotLab::TextMessage ...>
109
-
110
- RobotLab::Message.from_hash({ type: "tool_call", role: "assistant", tools: [...] })
111
- # => #<RobotLab::ToolCallMessage ...>
112
- ```
113
-
114
- When the `type` key is absent or `nil` (e.g. records persisted before the field was introduced), `from_hash` defaults to `TextMessage`:
115
-
116
- ```ruby
117
- RobotLab::Message.from_hash({ role: "user", content: "legacy row" })
118
- # => #<RobotLab::TextMessage ...>
119
- ```
120
-
121
- String keys are normalised automatically via `transform_keys(&:to_sym)`.
122
-
123
- ## See Also
124
-
125
- - [Memory](../core/memory.md)
126
- - [Message Flow Architecture](../../architecture/message-flow.md)
@@ -1,170 +0,0 @@
1
- # TextMessage
2
-
3
- Text message from system, user, or assistant.
4
-
5
- ## Class: `RobotLab::TextMessage`
6
-
7
- ```ruby
8
- message = TextMessage.new(role: "assistant", content: "Hello! How can I help you today?")
9
- ```
10
-
11
- ## Constructor
12
-
13
- ```ruby
14
- TextMessage.new(role:, content:, stop_reason: nil)
15
- ```
16
-
17
- **Parameters:**
18
-
19
- | Name | Type | Description |
20
- |------|------|-------------|
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") |
24
-
25
- ## Attributes
26
-
27
- ### content
28
-
29
- ```ruby
30
- message.content # => String
31
- ```
32
-
33
- The text content.
34
-
35
- ### role
36
-
37
- ```ruby
38
- message.role # => "assistant"
39
- ```
40
-
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.
58
-
59
- ## Methods
60
-
61
- ### to_h
62
-
63
- ```ruby
64
- message.to_h # => Hash
65
- ```
66
-
67
- Hash representation. Inherited from `Message#to_h`, which ends in `.compact` — a
68
- `nil` `stop_reason` is **omitted** rather than serialized as `nil`.
69
-
70
- **Returns:**
71
-
72
- ```ruby
73
- TextMessage.new(role: "assistant", content: "Hello! How can I help you today?").to_h
74
- # => { type: "text", role: "assistant", content: "Hello! How can I help you today?" }
75
-
76
- TextMessage.new(role: "assistant", content: "Done.", stop_reason: "stop").to_h
77
- # => { type: "text", role: "assistant", content: "Done.", stop_reason: "stop" }
78
- ```
79
-
80
- ### to_json
81
-
82
- ```ruby
83
- message.to_json # => String
84
- ```
85
-
86
- JSON representation.
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
-
98
- ## Examples
99
-
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
115
-
116
- ```ruby
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
124
- ```
125
-
126
- ### In Robot Results
127
-
128
- `Robot#run` returns a `RobotResult`, **not** a `TextMessage`. `RobotResult` has no
129
- `text?` and no `content` — calling either raises `NoMethodError`. Read the reply
130
- with `last_text_content` (aliased as `reply`):
131
-
132
- ```ruby
133
- result = robot.run("Tell me a joke")
134
-
135
- puts result.last_text_content # => the assistant's text
136
- puts result.reply # => same thing
137
- result.stopped? # => true whenever there are no tool calls
138
- result.has_tool_calls? # => whether the final message carried tool calls
139
- ```
140
-
141
- !!! note "`RobotResult#stopped?` is not driven by `stop_reason`"
142
- A `RobotResult` produced by `Robot#run` always has `stop_reason == nil`
143
- (`RubyLLM::Message` does not define the method, so `build_result` falls back
144
- to `nil`), and the `TextMessage` it wraps is built without a `stop_reason`
145
- too. `stopped?` therefore reduces to `!has_tool_calls?` — it never becomes
146
- true because a `stop_reason` of `"stop"` was reported. The
147
- `stop_reason: "stop"` form shown above only applies to `TextMessage`
148
- instances you construct yourself.
149
-
150
- `result.output` is an `Array` holding a single `TextMessage` rebuilt from the
151
- final response text — it is not the full turn:
152
-
153
- ```ruby
154
- msg = result.output.first
155
- msg.text? # => true
156
- msg.content # => the assistant's text
157
- ```
158
-
159
- ### Filtering Text Content
160
-
161
- ```ruby
162
- # Get only text messages from memory
163
- text_messages = memory.messages.select(&:text?).map(&:content)
164
- ```
165
-
166
- ## See Also
167
-
168
- - [UserMessage](user-message.md)
169
- - [ToolCallMessage](tool-call-message.md)
170
- - [Robot](../core/robot.md)
@@ -1,206 +0,0 @@
1
- # ToolCallMessage
2
-
3
- Tool invocation request from the LLM.
4
-
5
- ## Class: `RobotLab::ToolCallMessage`
6
-
7
- ```ruby
8
- message = ToolCallMessage.new(
9
- role: "assistant",
10
- tools: [
11
- ToolMessage.new(id: "call_abc123", name: "get_weather", input: { city: "New York" })
12
- ]
13
- )
14
- ```
15
-
16
- ## Constructor
17
-
18
- ```ruby
19
- ToolCallMessage.new(role:, tools:, stop_reason: nil)
20
- ```
21
-
22
- **Parameters:**
23
-
24
- | Name | Type | Description |
25
- |------|------|-------------|
26
- | `role` | `String` | Message role (typically "assistant") |
27
- | `tools` | `Array<ToolMessage, Hash>` | Tool calls; plain Hashes are normalized via `ToolMessage.from_hash` |
28
- | `stop_reason` | `String`, `nil` | Stop reason (defaults to "tool") |
29
-
30
- Each entry in `tools` may be a `ToolMessage` **or** a Hash. Anything else raises
31
- `ArgumentError: Invalid tool: must be ToolMessage or Hash`. The `tools` reader
32
- always returns `ToolMessage` objects.
33
-
34
- ```ruby
35
- ToolCallMessage.new(
36
- role: "assistant",
37
- tools: [{ id: "call_1", name: "get_weather", arguments: { city: "NYC" } }]
38
- ).tools.first.input
39
- # => { city: "NYC" }
40
- ```
41
-
42
- `ToolMessage.from_hash` symbolizes keys and accepts either `input:` or
43
- `arguments:` for the parameter hash (`input` wins), defaulting to `{}` when
44
- neither is present. This makes raw provider tool-call payloads usable directly.
45
-
46
- ## ToolMessage
47
-
48
- Each tool call is represented by a standalone `ToolMessage` object. It is a plain
49
- Ruby object — its superclass is `Object`, **not** `Message` — so it has no
50
- `type`, `role`, or predicate methods:
51
-
52
- ```ruby
53
- ToolMessage.new(id:, name:, input:)
54
- ToolMessage.from_hash(hash)
55
- ```
56
-
57
- | Name | Type | Description |
58
- |------|------|-------------|
59
- | `id` | `String` | Unique call identifier |
60
- | `name` | `String` | Tool name |
61
- | `input` | `Hash`, `nil` | Tool parameters; `nil` becomes `{}` |
62
-
63
- `ToolMessage#to_h` returns `{ type: "tool", id:, name:, input: }`. It is not
64
- compacted, so every key is always present.
65
-
66
- ## Attributes
67
-
68
- ### tools
69
-
70
- ```ruby
71
- message.tools # => Array<ToolMessage>
72
- ```
73
-
74
- Array of `ToolMessage` objects representing the tool calls.
75
-
76
- ### role
77
-
78
- ```ruby
79
- message.role # => "assistant"
80
- ```
81
-
82
- Returns a String. The LLM initiates tool calls, so this is typically `"assistant"`.
83
-
84
- ### type
85
-
86
- ```ruby
87
- message.type # => "tool_call"
88
- ```
89
-
90
- Always returns `"tool_call"`.
91
-
92
- ### content
93
-
94
- ```ruby
95
- message.content # => nil
96
- ```
97
-
98
- Always `nil` for tool call messages (the tool data is in `tools`).
99
-
100
- ### stop_reason
101
-
102
- ```ruby
103
- message.stop_reason # => "tool"
104
- ```
105
-
106
- Defaults to `"tool"` indicating the conversation stopped for tool execution.
107
-
108
- ## Methods
109
-
110
- ### to_h
111
-
112
- ```ruby
113
- message.to_h # => Hash
114
- ```
115
-
116
- Hash representation. `ToolCallMessage` overrides `Message#to_h` and does **not**
117
- compact, so all four keys are always present (`content` is not included at all).
118
-
119
- **Returns:**
120
-
121
- ```ruby
122
- {
123
- type: "tool_call",
124
- role: "assistant",
125
- tools: [
126
- { type: "tool", id: "call_abc123", name: "get_weather", input: { city: "New York" } }
127
- ],
128
- stop_reason: "tool"
129
- }
130
- ```
131
-
132
- ### to_json
133
-
134
- ```ruby
135
- message.to_json # => String
136
- ```
137
-
138
- JSON representation.
139
-
140
- ### Predicates
141
-
142
- ```ruby
143
- message.tool_call? # => true
144
- message.text? # => false
145
- message.assistant? # => true
146
- message.tool_stop? # => true
147
- ```
148
-
149
- ## Examples
150
-
151
- ### Single Tool Call
152
-
153
- ```ruby
154
- tool = ToolMessage.new(
155
- id: "call_1",
156
- name: "search_orders",
157
- input: { user_id: "123", status: "pending" }
158
- )
159
-
160
- call = ToolCallMessage.new(role: "assistant", tools: [tool])
161
- ```
162
-
163
- ### Multiple Tool Calls
164
-
165
- ```ruby
166
- tools = [
167
- ToolMessage.new(id: "call_1", name: "get_weather", input: { city: "NYC" }),
168
- ToolMessage.new(id: "call_2", name: "get_time", input: { timezone: "EST" })
169
- ]
170
-
171
- call = ToolCallMessage.new(role: "assistant", tools: tools)
172
- call.tools.length # => 2
173
- ```
174
-
175
- ### Processing Tool Calls
176
-
177
- ```ruby
178
- if message.tool_call?
179
- message.tools.each do |tool|
180
- puts "Tool called: #{tool.name}"
181
- puts "Parameters: #{tool.input.inspect}"
182
- end
183
- end
184
- ```
185
-
186
- ### In Tool Execution Flow
187
-
188
- ```ruby
189
- # LLM returns a tool call
190
- tool = ToolMessage.new(id: "call_weather_1", name: "get_weather", input: { city: "Seattle" })
191
- tool_call = ToolCallMessage.new(role: "assistant", tools: [tool])
192
-
193
- # Execute the tool and record the result
194
- result_data = execute_tool(tool.name, tool.input)
195
-
196
- tool_result = ToolResultMessage.new(
197
- tool: tool,
198
- content: { data: result_data }
199
- )
200
- ```
201
-
202
- ## See Also
203
-
204
- - [ToolResultMessage](tool-result-message.md)
205
- - [Tool](../core/tool.md)
206
- - [Using Tools Guide](../../guides/using-tools.md)