robot_lab 0.1.0 → 0.2.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 (242) hide show
  1. checksums.yaml +4 -4
  2. data/.architecture/AGENTS.md +32 -0
  3. data/.architecture/config.yml +8 -0
  4. data/.architecture/members.yml +60 -0
  5. data/.architecture/reviews/feature-free-will.md +490 -0
  6. data/.architecture/reviews/overall-codebase.md +427 -0
  7. data/.claude/settings.local.json +57 -0
  8. data/.codex/config.toml +2 -0
  9. data/.irbrc +2 -2
  10. data/.rubocop.yml +172 -0
  11. data/CHANGELOG.md +72 -0
  12. data/CLAUDE.md +139 -0
  13. data/README.md +91 -95
  14. data/Rakefile +109 -3
  15. data/agent2agent_review.md +192 -0
  16. data/agentf_improvements.md +253 -0
  17. data/agents.md +14 -0
  18. data/docs/examples/index.md +37 -2
  19. data/docs/getting-started/configuration.md +20 -7
  20. data/docs/guides/index.md +16 -16
  21. data/docs/guides/knowledge.md +7 -1
  22. data/docs/guides/observability.md +132 -0
  23. data/docs/index.md +30 -3
  24. data/docs/superpowers/plans/2026-05-06-agentskills.md +1303 -0
  25. data/docs/superpowers/specs/2026-05-06-agentskills-design.md +247 -0
  26. data/examples/.envrc +1 -0
  27. data/examples/01_simple_robot.rb +5 -9
  28. data/examples/02_tools.rb +5 -9
  29. data/examples/03_network.rb +8 -9
  30. data/examples/04_mcp.rb +21 -29
  31. data/examples/05_streaming.rb +12 -18
  32. data/examples/06_prompt_templates.rb +11 -19
  33. data/examples/07_network_memory.rb +16 -31
  34. data/examples/08_llm_config.rb +10 -22
  35. data/examples/09_chaining.rb +16 -27
  36. data/examples/10_memory.rb +12 -28
  37. data/examples/11_network_introspection.rb +15 -29
  38. data/examples/12_message_bus.rb +5 -12
  39. data/examples/13_spawn.rb +5 -10
  40. data/examples/14_rusty_circuit/.envrc +1 -0
  41. data/examples/14_rusty_circuit/comic.rb +2 -0
  42. data/examples/14_rusty_circuit/heckler.rb +1 -1
  43. data/examples/14_rusty_circuit/open_mic.rb +1 -3
  44. data/examples/14_rusty_circuit/scout.rb +2 -0
  45. data/examples/15_memory_network_and_bus/.envrc +1 -0
  46. data/examples/15_memory_network_and_bus/editorial_pipeline.rb +6 -3
  47. data/examples/15_memory_network_and_bus/linux_writer.rb +1 -1
  48. data/examples/15_memory_network_and_bus/output/combined_article.md +6 -6
  49. data/examples/15_memory_network_and_bus/output/final_article.md +6 -8
  50. data/examples/15_memory_network_and_bus/output/linux_draft.md +4 -2
  51. data/examples/15_memory_network_and_bus/output/mac_draft.md +3 -3
  52. data/examples/15_memory_network_and_bus/output/memory.json +6 -6
  53. data/examples/15_memory_network_and_bus/output/revision_1.md +10 -11
  54. data/examples/15_memory_network_and_bus/output/revision_2.md +6 -8
  55. data/examples/15_memory_network_and_bus/output/windows_draft.md +3 -3
  56. data/examples/16_writers_room/.envrc +1 -0
  57. data/examples/16_writers_room/writers_room.rb +2 -4
  58. data/examples/17_skills.rb +8 -17
  59. data/examples/18_rails/Gemfile +1 -0
  60. data/examples/19_token_tracking.rb +9 -15
  61. data/examples/20_circuit_breaker.rb +10 -19
  62. data/examples/21_learning_loop.rb +11 -20
  63. data/examples/22_context_compression.rb +6 -13
  64. data/examples/23_convergence.rb +6 -17
  65. data/examples/24_structured_delegation.rb +11 -15
  66. data/examples/25_history_search.rb +5 -12
  67. data/examples/26_document_store.rb +6 -13
  68. data/examples/27_incident_response/incident_response.rb +4 -5
  69. data/examples/28_mcp_discovery.rb +8 -11
  70. data/examples/29_ractor_tools.rb +4 -9
  71. data/examples/30_ractor_network.rb +10 -19
  72. data/examples/31_launch_assessment.rb +10 -23
  73. data/examples/32_newsletter_reader.rb +188 -0
  74. data/examples/33_stock_generator.rb +80 -0
  75. data/examples/33_stock_predictor.rb +306 -0
  76. data/examples/34_agentskills.rb +72 -0
  77. data/examples/README.md +1 -1
  78. data/examples/common.rb +76 -0
  79. data/examples/ruboruby.md +423 -0
  80. data/examples/temp.md +51 -0
  81. data/lib/robot_lab/agent_skill.rb +63 -0
  82. data/lib/robot_lab/agent_skill_catalog.rb +74 -0
  83. data/lib/robot_lab/ask_user.rb +2 -2
  84. data/lib/robot_lab/bus_poller.rb +12 -5
  85. data/lib/robot_lab/config.rb +1 -12
  86. data/lib/robot_lab/delegation_future.rb +1 -1
  87. data/lib/robot_lab/doom_loop_detector.rb +98 -0
  88. data/lib/robot_lab/history_compressor.rb +4 -10
  89. data/lib/robot_lab/mcp/client.rb +1 -2
  90. data/lib/robot_lab/mcp/connection_poller.rb +3 -3
  91. data/lib/robot_lab/mcp/server.rb +1 -1
  92. data/lib/robot_lab/mcp/server_discovery.rb +0 -2
  93. data/lib/robot_lab/memory.rb +32 -27
  94. data/lib/robot_lab/memory_change.rb +2 -2
  95. data/lib/robot_lab/message.rb +4 -4
  96. data/lib/robot_lab/network.rb +11 -6
  97. data/lib/robot_lab/robot/agent_skill_matching.rb +99 -0
  98. data/lib/robot_lab/robot/bus_messaging.rb +9 -27
  99. data/lib/robot_lab/robot/history_search.rb +4 -1
  100. data/lib/robot_lab/robot/mcp_management.rb +5 -11
  101. data/lib/robot_lab/robot/template_rendering.rb +60 -40
  102. data/lib/robot_lab/robot.rb +323 -206
  103. data/lib/robot_lab/robot_result.rb +6 -5
  104. data/lib/robot_lab/run_config.rb +5 -11
  105. data/lib/robot_lab/script_tool.rb +76 -0
  106. data/lib/robot_lab/state_proxy.rb +7 -5
  107. data/lib/robot_lab/tool.rb +3 -3
  108. data/lib/robot_lab/tool_config.rb +1 -1
  109. data/lib/robot_lab/tool_manifest.rb +5 -7
  110. data/lib/robot_lab/user_message.rb +2 -2
  111. data/lib/robot_lab/version.rb +1 -1
  112. data/lib/robot_lab/waiter.rb +1 -1
  113. data/lib/robot_lab.rb +41 -52
  114. data/logfile +8 -0
  115. data/mkdocs.yml +2 -3
  116. data/robot_concurrency.md +38 -0
  117. data/simple_acp_review.md +298 -0
  118. data/site/404.html +2300 -0
  119. data/site/api/core/index.html +2706 -0
  120. data/site/api/core/memory/index.html +3793 -0
  121. data/site/api/core/network/index.html +3500 -0
  122. data/site/api/core/robot/index.html +4566 -0
  123. data/site/api/core/state/index.html +3390 -0
  124. data/site/api/core/tool/index.html +3843 -0
  125. data/site/api/index.html +2635 -0
  126. data/site/api/mcp/client/index.html +3435 -0
  127. data/site/api/mcp/index.html +2783 -0
  128. data/site/api/mcp/server/index.html +3252 -0
  129. data/site/api/mcp/transports/index.html +3352 -0
  130. data/site/api/messages/index.html +2641 -0
  131. data/site/api/messages/text-message/index.html +3087 -0
  132. data/site/api/messages/tool-call-message/index.html +3159 -0
  133. data/site/api/messages/tool-result-message/index.html +3252 -0
  134. data/site/api/messages/user-message/index.html +3212 -0
  135. data/site/api/streaming/context/index.html +3282 -0
  136. data/site/api/streaming/events/index.html +3347 -0
  137. data/site/api/streaming/index.html +2738 -0
  138. data/site/architecture/core-concepts/index.html +3757 -0
  139. data/site/architecture/index.html +2797 -0
  140. data/site/architecture/message-flow/index.html +3238 -0
  141. data/site/architecture/network-orchestration/index.html +3433 -0
  142. data/site/architecture/robot-execution/index.html +3140 -0
  143. data/site/architecture/state-management/index.html +3498 -0
  144. data/site/assets/css/custom.css +56 -0
  145. data/site/assets/images/favicon.png +0 -0
  146. data/site/assets/images/robot_lab.jpg +0 -0
  147. data/site/assets/javascripts/bundle.79ae519e.min.js +16 -0
  148. data/site/assets/javascripts/bundle.79ae519e.min.js.map +7 -0
  149. data/site/assets/javascripts/lunr/min/lunr.ar.min.js +1 -0
  150. data/site/assets/javascripts/lunr/min/lunr.da.min.js +18 -0
  151. data/site/assets/javascripts/lunr/min/lunr.de.min.js +18 -0
  152. data/site/assets/javascripts/lunr/min/lunr.du.min.js +18 -0
  153. data/site/assets/javascripts/lunr/min/lunr.el.min.js +1 -0
  154. data/site/assets/javascripts/lunr/min/lunr.es.min.js +18 -0
  155. data/site/assets/javascripts/lunr/min/lunr.fi.min.js +18 -0
  156. data/site/assets/javascripts/lunr/min/lunr.fr.min.js +18 -0
  157. data/site/assets/javascripts/lunr/min/lunr.he.min.js +1 -0
  158. data/site/assets/javascripts/lunr/min/lunr.hi.min.js +1 -0
  159. data/site/assets/javascripts/lunr/min/lunr.hu.min.js +18 -0
  160. data/site/assets/javascripts/lunr/min/lunr.hy.min.js +1 -0
  161. data/site/assets/javascripts/lunr/min/lunr.it.min.js +18 -0
  162. data/site/assets/javascripts/lunr/min/lunr.ja.min.js +1 -0
  163. data/site/assets/javascripts/lunr/min/lunr.jp.min.js +1 -0
  164. data/site/assets/javascripts/lunr/min/lunr.kn.min.js +1 -0
  165. data/site/assets/javascripts/lunr/min/lunr.ko.min.js +1 -0
  166. data/site/assets/javascripts/lunr/min/lunr.multi.min.js +1 -0
  167. data/site/assets/javascripts/lunr/min/lunr.nl.min.js +18 -0
  168. data/site/assets/javascripts/lunr/min/lunr.no.min.js +18 -0
  169. data/site/assets/javascripts/lunr/min/lunr.pt.min.js +18 -0
  170. data/site/assets/javascripts/lunr/min/lunr.ro.min.js +18 -0
  171. data/site/assets/javascripts/lunr/min/lunr.ru.min.js +18 -0
  172. data/site/assets/javascripts/lunr/min/lunr.sa.min.js +1 -0
  173. data/site/assets/javascripts/lunr/min/lunr.stemmer.support.min.js +1 -0
  174. data/site/assets/javascripts/lunr/min/lunr.sv.min.js +18 -0
  175. data/site/assets/javascripts/lunr/min/lunr.ta.min.js +1 -0
  176. data/site/assets/javascripts/lunr/min/lunr.te.min.js +1 -0
  177. data/site/assets/javascripts/lunr/min/lunr.th.min.js +1 -0
  178. data/site/assets/javascripts/lunr/min/lunr.tr.min.js +18 -0
  179. data/site/assets/javascripts/lunr/min/lunr.vi.min.js +1 -0
  180. data/site/assets/javascripts/lunr/min/lunr.zh.min.js +1 -0
  181. data/site/assets/javascripts/lunr/tinyseg.js +206 -0
  182. data/site/assets/javascripts/lunr/wordcut.js +6708 -0
  183. data/site/assets/javascripts/workers/search.2c215733.min.js +42 -0
  184. data/site/assets/javascripts/workers/search.2c215733.min.js.map +7 -0
  185. data/site/assets/stylesheets/main.484c7ddc.min.css +1 -0
  186. data/site/assets/stylesheets/main.484c7ddc.min.css.map +1 -0
  187. data/site/assets/stylesheets/palette.ab4e12ef.min.css +1 -0
  188. data/site/assets/stylesheets/palette.ab4e12ef.min.css.map +1 -0
  189. data/site/concepts/index.html +3455 -0
  190. data/site/examples/basic-chat/index.html +2880 -0
  191. data/site/examples/index.html +2907 -0
  192. data/site/examples/mcp-server/index.html +3018 -0
  193. data/site/examples/multi-robot-network/index.html +3131 -0
  194. data/site/examples/rails-application/index.html +3329 -0
  195. data/site/examples/tool-usage/index.html +3085 -0
  196. data/site/getting-started/configuration/index.html +3745 -0
  197. data/site/getting-started/index.html +2572 -0
  198. data/site/getting-started/installation/index.html +2981 -0
  199. data/site/getting-started/quick-start/index.html +2942 -0
  200. data/site/guides/building-robots/index.html +4290 -0
  201. data/site/guides/creating-networks/index.html +3858 -0
  202. data/site/guides/index.html +2586 -0
  203. data/site/guides/mcp-integration/index.html +3581 -0
  204. data/site/guides/memory/index.html +3586 -0
  205. data/site/guides/rails-integration/index.html +4019 -0
  206. data/site/guides/streaming/index.html +3157 -0
  207. data/site/guides/using-tools/index.html +3802 -0
  208. data/site/index.html +2671 -0
  209. data/site/search/search_index.json +1 -0
  210. data/site/sitemap.xml +183 -0
  211. data/site/sitemap.xml.gz +0 -0
  212. data/site/tags.json +1 -0
  213. data/temp.md +6 -0
  214. data/tool_manifest_plan.md +155 -0
  215. metadata +154 -92
  216. data/docs/examples/rails-application.md +0 -419
  217. data/docs/guides/ractor-parallelism.md +0 -364
  218. data/docs/guides/rails-integration.md +0 -681
  219. data/docs/superpowers/plans/2026-04-14-ractor-integration.md +0 -1538
  220. data/docs/superpowers/specs/2026-04-14-ractor-integration-design.md +0 -258
  221. data/lib/generators/robot_lab/install_generator.rb +0 -90
  222. data/lib/generators/robot_lab/job_generator.rb +0 -40
  223. data/lib/generators/robot_lab/robot_generator.rb +0 -55
  224. data/lib/generators/robot_lab/templates/initializer.rb.tt +0 -42
  225. data/lib/generators/robot_lab/templates/job.rb.tt +0 -21
  226. data/lib/generators/robot_lab/templates/migration.rb.tt +0 -32
  227. data/lib/generators/robot_lab/templates/result_model.rb.tt +0 -52
  228. data/lib/generators/robot_lab/templates/robot.rb.tt +0 -31
  229. data/lib/generators/robot_lab/templates/robot_job.rb.tt +0 -18
  230. data/lib/generators/robot_lab/templates/robot_test.rb.tt +0 -34
  231. data/lib/generators/robot_lab/templates/routing_robot.rb.tt +0 -59
  232. data/lib/generators/robot_lab/templates/thread_model.rb.tt +0 -40
  233. data/lib/robot_lab/document_store.rb +0 -155
  234. data/lib/robot_lab/ractor_boundary.rb +0 -42
  235. data/lib/robot_lab/ractor_job.rb +0 -37
  236. data/lib/robot_lab/ractor_memory_proxy.rb +0 -85
  237. data/lib/robot_lab/ractor_network_scheduler.rb +0 -154
  238. data/lib/robot_lab/ractor_worker_pool.rb +0 -117
  239. data/lib/robot_lab/rails_integration/engine.rb +0 -29
  240. data/lib/robot_lab/rails_integration/job.rb +0 -158
  241. data/lib/robot_lab/rails_integration/railtie.rb +0 -51
  242. data/lib/robot_lab/rails_integration/turbo_stream_callbacks.rb +0 -72
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RobotLab
4
- module RailsIntegration
5
- # Rails Engine for RobotLab integration
6
- #
7
- # Provides automatic loading of RobotLab components and
8
- # integration with Rails applications.
9
- #
10
- class Engine < ::Rails::Engine
11
- isolate_namespace RobotLab
12
-
13
- initializer "robot_lab.configure" do |app|
14
- # Load configuration from Rails config
15
- app.config.robot_lab ||= ActiveSupport::OrderedOptions.new
16
- end
17
-
18
- initializer "robot_lab.add_autoload_paths", before: :set_autoload_paths do |app|
19
- app.config.autoload_paths << root.join("app", "robots")
20
- app.config.autoload_paths << root.join("app", "tools")
21
- end
22
-
23
- config.generators do |g|
24
- g.test_framework :minitest, fixture: false
25
- g.fixture_replacement nil
26
- end
27
- end
28
- end
29
- end
@@ -1,158 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RobotLab
4
- module RailsIntegration
5
- # Base class for RobotLab background jobs.
6
- #
7
- # Encapsulates the full robot-run lifecycle: robot class resolution,
8
- # Turbo Stream callback wiring, thread-record persistence, and
9
- # completion/error broadcasting. Suitable for fiber-safe execution
10
- # under Solid Queue's fiber mode (see issue #20 for SQ version details).
11
- #
12
- # @example Minimal subclass using the robot_class DSL
13
- # class SupportRobotJob < RobotLab::Job
14
- # queue_as :default
15
- # robot_class SupportRobot
16
- # end
17
- #
18
- # # Enqueue (no robot_class: needed — taken from DSL):
19
- # SupportRobotJob.perform_later(message: "Hello", thread_id: session_id)
20
- #
21
- # @example Generic job accepting robot_class at enqueue time
22
- # class RobotRunJob < RobotLab::Job
23
- # queue_as :default
24
- # end
25
- #
26
- # RobotRunJob.perform_later(
27
- # robot_class: "SupportRobot",
28
- # message: params[:message],
29
- # thread_id: session_id
30
- # )
31
- #
32
- class Job < ActiveJob::Base
33
- # Set or get the default robot class for this job subclass.
34
- #
35
- # @overload robot_class
36
- # @return [Class, nil] the configured robot class
37
- # @overload robot_class(klass)
38
- # @param klass [Class] the robot class (must respond to .build)
39
- # @return [Class]
40
- def self.robot_class(klass = nil)
41
- klass ? @robot_class = klass : @robot_class
42
- end
43
-
44
- retry_on StandardError, wait: 5.seconds, attempts: 3
45
- discard_on ActiveJob::DeserializationError
46
-
47
- # Run a robot as a background job.
48
- #
49
- # When +thread_id+ is provided the job:
50
- # - Finds or creates a +RobotLabThread+ record and updates its last-message fields
51
- # - Wires +TurboStreamCallbacks+ onto the robot (when turbo-rails is present)
52
- # - Persists the +RobotResult+ to +RobotLabResult+
53
- # - Broadcasts a completion or error event via Turbo Streams
54
- #
55
- # When +thread_id+ is omitted the robot runs in a fire-and-forget mode —
56
- # no persistence, no broadcasting, result returned directly.
57
- #
58
- # @param message [String] the user message forwarded to robot.run
59
- # @param robot_class [String, Class, nil] override; falls back to the class-level DSL
60
- # @param thread_id [String, nil] session key for persistence and Turbo broadcasting
61
- # @param context [Hash] additional keyword args forwarded to robot.run
62
- # @return [RobotResult]
63
- def perform(message:, robot_class: nil, thread_id: nil, **context)
64
- klass = resolve_robot_class(robot_class)
65
- thread = setup_thread(thread_id, message)
66
- robot = build_robot(klass, thread_id)
67
- result = robot.run(message, **context)
68
-
69
- if thread
70
- persist_result(thread, result)
71
- broadcast_completion(thread_id)
72
- end
73
-
74
- result
75
- rescue StandardError => e
76
- broadcast_error(thread_id, e) if thread_id
77
- raise
78
- end
79
-
80
- private
81
-
82
- # Resolve the robot class from the runtime arg or the class-level DSL.
83
- def resolve_robot_class(runtime_class)
84
- klass = runtime_class || self.class.robot_class
85
- raise ArgumentError,
86
- "No robot class specified. Pass robot_class: to perform or set robot_class on the job class." \
87
- unless klass
88
-
89
- return klass if klass.is_a?(Class)
90
-
91
- klass.to_s.constantize
92
- end
93
-
94
- # Find or create the thread record and stamp the incoming message.
95
- # Returns nil when thread_id is absent (fire-and-forget mode).
96
- def setup_thread(thread_id, message)
97
- return nil unless thread_id
98
-
99
- thread = "RobotLabThread".constantize.find_or_create_by_session_id(thread_id)
100
- thread.update!(last_user_message: message, last_user_message_at: Time.current)
101
- thread
102
- end
103
-
104
- # Build the robot, wiring Turbo callbacks when thread_id + turbo-rails are present.
105
- def build_robot(klass, thread_id)
106
- if thread_id && turbo_available?
107
- stream_name = "robot_lab_thread_#{thread_id}"
108
- on_content = TurboStreamCallbacks.build_content_callback(stream_name: stream_name)
109
- on_tool_call = TurboStreamCallbacks.build_tool_call_callback(stream_name: stream_name)
110
- klass.build(on_content: on_content, on_tool_call: on_tool_call)
111
- else
112
- klass.build
113
- end
114
- end
115
-
116
- # Append a RobotLabResult record to the thread.
117
- def persist_result(thread, result)
118
- sequence = thread.results.maximum(:sequence_number).to_i + 1
119
- exported = result.export
120
-
121
- thread.results.create!(
122
- robot_name: result.robot_name,
123
- sequence_number: sequence,
124
- output_data: exported[:output],
125
- tool_calls_data: exported[:tool_calls],
126
- stop_reason: result.stop_reason,
127
- checksum: result.checksum
128
- )
129
- end
130
-
131
- # Broadcast a "Complete" badge to the Turbo Stream.
132
- def broadcast_completion(thread_id)
133
- return unless turbo_available?
134
-
135
- Turbo::StreamsChannel.broadcast_replace_to(
136
- "robot_lab_thread_#{thread_id}",
137
- target: "robot_status",
138
- html: "<div id=\"robot_status\"><span class=\"complete\">Complete</span></div>"
139
- )
140
- end
141
-
142
- # Broadcast an HTML-escaped error message to the Turbo Stream.
143
- def broadcast_error(thread_id, error)
144
- return unless turbo_available?
145
-
146
- Turbo::StreamsChannel.broadcast_append_to(
147
- "robot_lab_thread_#{thread_id}",
148
- target: "robot_errors",
149
- html: "<div class=\"error\">#{ERB::Util.html_escape(error.message)}</div>"
150
- )
151
- end
152
-
153
- def turbo_available?
154
- defined?(Turbo::StreamsChannel)
155
- end
156
- end
157
- end
158
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RobotLab
4
- module RailsIntegration
5
- # Railtie for RobotLab Rails integration
6
- #
7
- # Provides configuration hooks and initialization for
8
- # Rails applications using RobotLab.
9
- #
10
- class Railtie < ::Rails::Railtie
11
- config.robot_lab = ActiveSupport::OrderedOptions.new
12
-
13
- initializer "robot_lab.configuration" do |app|
14
- RobotLab.configure do |config|
15
- # Apply Rails-specific configuration
16
- rails_config = app.config.robot_lab
17
-
18
- config.default_model = rails_config.default_model if rails_config.default_model
19
- config.default_provider = rails_config.default_provider if rails_config.default_provider
20
- config.logger = ::Rails.logger
21
- end
22
- end
23
-
24
- initializer "robot_lab.active_record" do
25
- ActiveSupport.on_load(:active_record) do
26
- # Extend ActiveRecord with RobotLab concerns if needed
27
- end
28
- end
29
-
30
- rake_tasks do
31
- # Load RobotLab rake tasks
32
- path = File.expand_path("../tasks", __dir__)
33
- Dir.glob("#{path}/**/*.rake").each { |f| load f }
34
- end
35
-
36
- # TODO: Add fiber isolation warning once Solid Queue fiber mode lands in a
37
- # mainline release. PR rails/solid_queue#728 (branch crmne/solid_queue
38
- # async-worker-execution-mode) introduces the `fibers:` worker key but has
39
- # not yet been merged or released. When a released version is detectable,
40
- # add an initializer here that warns when:
41
- # defined?(SolidQueue) &&
42
- # app.config.active_support.isolation_level != :fiber
43
-
44
- generators do
45
- require "generators/robot_lab/install_generator"
46
- require "generators/robot_lab/robot_generator"
47
- require "generators/robot_lab/job_generator"
48
- end
49
- end
50
- end
51
- end
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RobotLab
4
- module RailsIntegration
5
- # Stateless utility module that builds callback Procs for Turbo Stream broadcasting.
6
- #
7
- # Safe to require even without turbo-rails installed — checks at call time
8
- # via `defined?(Turbo::StreamsChannel)`.
9
- #
10
- # @example Wire streaming in a background job
11
- # stream_name = "robot_lab_thread_#{thread_id}"
12
- # on_content = RobotLab::RailsIntegration::TurboStreamCallbacks.build_content_callback(
13
- # stream_name: stream_name
14
- # )
15
- # robot = MyRobot.build(on_content: on_content)
16
- # robot.run(message)
17
- #
18
- module TurboStreamCallbacks
19
- # Check whether Turbo Streams broadcasting is available at runtime.
20
- #
21
- # @return [Boolean]
22
- #
23
- def self.available?
24
- defined?(Turbo::StreamsChannel) ? true : false
25
- end
26
-
27
- # Build a Proc that broadcasts content chunks via Turbo Streams.
28
- #
29
- # The returned Proc receives a chunk object (e.g. RubyLLM::Chunk) and
30
- # broadcasts `chunk.content` as HTML-escaped text via `broadcast_append_to`.
31
- #
32
- # @param stream_name [String] the Turbo Stream channel name
33
- # @param target [String] the DOM target ID (default: "robot_response")
34
- # @return [Proc] a callback suitable for `on_content:`
35
- #
36
- def self.build_content_callback(stream_name:, target: "robot_response")
37
- ->(chunk) {
38
- content = chunk.respond_to?(:content) ? chunk.content : chunk.to_s
39
- return unless content && TurboStreamCallbacks.available?
40
-
41
- Turbo::StreamsChannel.broadcast_append_to(
42
- stream_name,
43
- target: target,
44
- html: ERB::Util.html_escape(content)
45
- )
46
- }
47
- end
48
-
49
- # Build a Proc that broadcasts tool call badges via Turbo Streams.
50
- #
51
- # The returned Proc receives a tool_call object and broadcasts
52
- # a badge showing the tool name.
53
- #
54
- # @param stream_name [String] the Turbo Stream channel name
55
- # @param target [String] the DOM target ID (default: "robot_tools")
56
- # @return [Proc] a callback suitable for `on_tool_call:`
57
- #
58
- def self.build_tool_call_callback(stream_name:, target: "robot_tools")
59
- ->(tool_call) {
60
- return unless TurboStreamCallbacks.available?
61
-
62
- name = tool_call.respond_to?(:name) ? tool_call.name : tool_call.to_s
63
- Turbo::StreamsChannel.broadcast_append_to(
64
- stream_name,
65
- target: target,
66
- html: "<span class=\"tool-badge\">Using: #{ERB::Util.html_escape(name)}</span>"
67
- )
68
- }
69
- end
70
- end
71
- end
72
- end