robot_lab 0.0.9 → 0.0.12
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 +53 -0
- data/README.md +210 -1
- data/Rakefile +2 -1
- data/docs/api/core/result.md +123 -0
- data/docs/api/core/robot.md +182 -0
- data/docs/api/errors.md +185 -0
- data/docs/guides/building-robots.md +125 -0
- data/docs/guides/creating-networks.md +21 -0
- data/docs/guides/index.md +10 -0
- data/docs/guides/knowledge.md +182 -0
- data/docs/guides/mcp-integration.md +106 -0
- data/docs/guides/memory.md +2 -0
- data/docs/guides/observability.md +486 -0
- data/docs/guides/ractor-parallelism.md +364 -0
- data/docs/superpowers/plans/2026-04-14-ractor-integration.md +1538 -0
- data/docs/superpowers/specs/2026-04-14-ractor-integration-design.md +258 -0
- data/examples/19_token_tracking.rb +128 -0
- data/examples/20_circuit_breaker.rb +153 -0
- data/examples/21_learning_loop.rb +164 -0
- data/examples/22_context_compression.rb +179 -0
- data/examples/23_convergence.rb +137 -0
- data/examples/24_structured_delegation.rb +150 -0
- data/examples/25_history_search/conversation.jsonl +30 -0
- data/examples/25_history_search.rb +136 -0
- data/examples/26_document_store/api_versioning_adr.md +52 -0
- data/examples/26_document_store/incident_postmortem.md +46 -0
- data/examples/26_document_store/postgres_runbook.md +49 -0
- data/examples/26_document_store/redis_caching_guide.md +48 -0
- data/examples/26_document_store/sidekiq_guide.md +51 -0
- data/examples/26_document_store.rb +147 -0
- data/examples/27_incident_response/incident_response.rb +244 -0
- data/examples/28_mcp_discovery.rb +112 -0
- data/examples/29_ractor_tools.rb +243 -0
- data/examples/30_ractor_network.rb +256 -0
- data/examples/README.md +136 -0
- data/examples/prompts/skill_with_mcp_test.md +9 -0
- data/examples/prompts/skill_with_robot_name_test.md +5 -0
- data/examples/prompts/skill_with_tools_test.md +6 -0
- data/lib/robot_lab/bus_poller.rb +149 -0
- data/lib/robot_lab/convergence.rb +69 -0
- data/lib/robot_lab/delegation_future.rb +93 -0
- data/lib/robot_lab/document_store.rb +155 -0
- data/lib/robot_lab/error.rb +25 -0
- data/lib/robot_lab/history_compressor.rb +205 -0
- data/lib/robot_lab/mcp/client.rb +17 -5
- data/lib/robot_lab/mcp/connection_poller.rb +187 -0
- data/lib/robot_lab/mcp/server.rb +7 -2
- data/lib/robot_lab/mcp/server_discovery.rb +110 -0
- data/lib/robot_lab/mcp/transports/stdio.rb +6 -0
- data/lib/robot_lab/memory.rb +103 -6
- data/lib/robot_lab/network.rb +44 -9
- data/lib/robot_lab/ractor_boundary.rb +42 -0
- data/lib/robot_lab/ractor_job.rb +37 -0
- data/lib/robot_lab/ractor_memory_proxy.rb +85 -0
- data/lib/robot_lab/ractor_network_scheduler.rb +154 -0
- data/lib/robot_lab/ractor_worker_pool.rb +117 -0
- data/lib/robot_lab/robot/bus_messaging.rb +43 -65
- data/lib/robot_lab/robot/history_search.rb +69 -0
- data/lib/robot_lab/robot.rb +228 -11
- data/lib/robot_lab/robot_result.rb +24 -5
- data/lib/robot_lab/run_config.rb +1 -1
- data/lib/robot_lab/text_analysis.rb +103 -0
- data/lib/robot_lab/tool.rb +42 -3
- data/lib/robot_lab/tool_config.rb +1 -1
- data/lib/robot_lab/version.rb +1 -1
- data/lib/robot_lab/waiter.rb +49 -29
- data/lib/robot_lab.rb +25 -0
- data/mkdocs.yml +1 -0
- metadata +72 -2
data/lib/robot_lab/waiter.rb
CHANGED
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module RobotLab
|
|
4
|
-
# Thread-safe waiter for blocking get operations on Memory
|
|
4
|
+
# Thread-safe waiter for blocking get operations on Memory.
|
|
5
5
|
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
6
|
+
# Uses an IO.pipe pair instead of ConditionVariable so that
|
|
7
|
+
# IO.select integrates with the Async fiber scheduler hook.
|
|
8
|
+
# ConditionVariable#wait can block the event loop in Async
|
|
9
|
+
# contexts; IO.select yields to the scheduler correctly.
|
|
8
10
|
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# # In thread A (waiting)
|
|
13
|
-
# value = waiter.wait(timeout: 30)
|
|
14
|
-
#
|
|
15
|
-
# # In thread B (signaling)
|
|
16
|
-
# waiter.signal("the value")
|
|
11
|
+
# Multiple threads may wait on the same Waiter instance.
|
|
12
|
+
# signal() writes one byte per waiting thread so every
|
|
13
|
+
# blocked IO.select wakes exactly once.
|
|
17
14
|
#
|
|
18
15
|
# @api private
|
|
19
16
|
class Waiter
|
|
20
17
|
# Creates a new Waiter instance.
|
|
21
18
|
def initialize
|
|
22
|
-
@
|
|
23
|
-
@
|
|
24
|
-
@value
|
|
25
|
-
@signaled
|
|
19
|
+
@read_io, @write_io = IO.pipe
|
|
20
|
+
@mutex = Mutex.new
|
|
21
|
+
@value = nil
|
|
22
|
+
@signaled = false
|
|
23
|
+
@waiter_count = 0
|
|
26
24
|
end
|
|
27
25
|
|
|
28
26
|
# Wait for a value to be signaled.
|
|
@@ -34,32 +32,44 @@ module RobotLab
|
|
|
34
32
|
@mutex.synchronize do
|
|
35
33
|
return @value if @signaled
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
@
|
|
45
|
-
|
|
46
|
-
|
|
35
|
+
@waiter_count += 1
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
begin
|
|
39
|
+
ready = IO.select([@read_io], nil, nil, timeout)
|
|
40
|
+
|
|
41
|
+
@mutex.synchronize do
|
|
42
|
+
@waiter_count -= 1
|
|
43
|
+
return :timeout unless ready
|
|
44
|
+
|
|
45
|
+
@read_io.read_nonblock(1) rescue nil # drain one wake byte
|
|
47
46
|
@value
|
|
48
47
|
end
|
|
48
|
+
rescue IOError
|
|
49
|
+
@mutex.synchronize { @waiter_count -= 1 }
|
|
50
|
+
:timeout
|
|
49
51
|
end
|
|
50
52
|
end
|
|
51
53
|
|
|
52
|
-
# Signal a value to waiting threads.
|
|
54
|
+
# Signal a value to all waiting threads.
|
|
53
55
|
#
|
|
54
56
|
# @param value [Object] the value to signal
|
|
55
57
|
# @return [void]
|
|
56
58
|
#
|
|
57
59
|
def signal(value)
|
|
58
|
-
@mutex.synchronize do
|
|
59
|
-
@value
|
|
60
|
+
count = @mutex.synchronize do
|
|
61
|
+
@value = value
|
|
60
62
|
@signaled = true
|
|
61
|
-
@
|
|
63
|
+
@waiter_count
|
|
62
64
|
end
|
|
65
|
+
|
|
66
|
+
# Write one byte per waiting thread (min 1 to handle the race
|
|
67
|
+
# where a thread passed the @signaled check but hasn't entered
|
|
68
|
+
# IO.select yet — its IO.select will return immediately).
|
|
69
|
+
bytes = [count, 1].max
|
|
70
|
+
@write_io.write_nonblock("." * bytes) rescue nil
|
|
71
|
+
rescue IOError
|
|
72
|
+
# pipe already closed — signal is a no-op
|
|
63
73
|
end
|
|
64
74
|
|
|
65
75
|
# Check if this waiter has been signaled.
|
|
@@ -69,5 +79,15 @@ module RobotLab
|
|
|
69
79
|
def signaled?
|
|
70
80
|
@mutex.synchronize { @signaled }
|
|
71
81
|
end
|
|
82
|
+
|
|
83
|
+
# Release the pipe file descriptors.
|
|
84
|
+
# Should be called after wait returns.
|
|
85
|
+
#
|
|
86
|
+
# @return [void]
|
|
87
|
+
#
|
|
88
|
+
def close
|
|
89
|
+
@read_io.close rescue nil
|
|
90
|
+
@write_io.close rescue nil
|
|
91
|
+
end
|
|
72
92
|
end
|
|
73
93
|
end
|
data/lib/robot_lab.rb
CHANGED
|
@@ -71,6 +71,7 @@ loader.setup
|
|
|
71
71
|
require_relative 'robot_lab/error'
|
|
72
72
|
require_relative 'robot_lab/message'
|
|
73
73
|
require_relative 'robot_lab/memory'
|
|
74
|
+
require_relative 'robot_lab/ractor_job'
|
|
74
75
|
|
|
75
76
|
# Eager load everything in Rails or when explicitly requested.
|
|
76
77
|
# Otherwise Zeitwerk's lazy autoloading keeps boot fast.
|
|
@@ -218,6 +219,30 @@ module RobotLab
|
|
|
218
219
|
def create_memory(data: {}, enable_cache: true, **options)
|
|
219
220
|
Memory.new(data: data, enable_cache: enable_cache, **options)
|
|
220
221
|
end
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
# Returns the shared RactorWorkerPool, lazily initialized.
|
|
225
|
+
#
|
|
226
|
+
# Pool size is determined by RobotLab.config.ractor_pool_size or
|
|
227
|
+
# defaults to Etc.nprocessors (:auto). The pool lives for the lifetime
|
|
228
|
+
# of the process. Call RobotLab.shutdown_ractor_pool to drain and
|
|
229
|
+
# close it explicitly.
|
|
230
|
+
#
|
|
231
|
+
# @return [RactorWorkerPool]
|
|
232
|
+
def ractor_pool
|
|
233
|
+
@ractor_pool ||= begin
|
|
234
|
+
size = config.respond_to?(:ractor_pool_size) ? (config.ractor_pool_size || :auto) : :auto
|
|
235
|
+
RactorWorkerPool.new(size: size)
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Shut down the shared Ractor worker pool, draining in-flight jobs.
|
|
240
|
+
#
|
|
241
|
+
# @return [void]
|
|
242
|
+
def shutdown_ractor_pool
|
|
243
|
+
@ractor_pool&.shutdown
|
|
244
|
+
@ractor_pool = nil
|
|
245
|
+
end
|
|
221
246
|
end
|
|
222
247
|
end
|
|
223
248
|
|
data/mkdocs.yml
CHANGED
|
@@ -170,6 +170,7 @@ nav:
|
|
|
170
170
|
- Streaming Responses: guides/streaming.md
|
|
171
171
|
- Memory System: guides/memory.md
|
|
172
172
|
- Rails Integration: guides/rails-integration.md
|
|
173
|
+
- Ractor Parallelism: guides/ractor-parallelism.md
|
|
173
174
|
- API Reference:
|
|
174
175
|
- api/index.md
|
|
175
176
|
- Core Classes:
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: robot_lab
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.12
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dewayne VanHoozer
|
|
@@ -163,6 +163,34 @@ dependencies:
|
|
|
163
163
|
- - "~>"
|
|
164
164
|
- !ruby/object:Gem::Version
|
|
165
165
|
version: 0.3.0
|
|
166
|
+
- !ruby/object:Gem::Dependency
|
|
167
|
+
name: ractor_queue
|
|
168
|
+
requirement: !ruby/object:Gem::Requirement
|
|
169
|
+
requirements:
|
|
170
|
+
- - ">="
|
|
171
|
+
- !ruby/object:Gem::Version
|
|
172
|
+
version: '0'
|
|
173
|
+
type: :runtime
|
|
174
|
+
prerelease: false
|
|
175
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
176
|
+
requirements:
|
|
177
|
+
- - ">="
|
|
178
|
+
- !ruby/object:Gem::Version
|
|
179
|
+
version: '0'
|
|
180
|
+
- !ruby/object:Gem::Dependency
|
|
181
|
+
name: ractor-wrapper
|
|
182
|
+
requirement: !ruby/object:Gem::Requirement
|
|
183
|
+
requirements:
|
|
184
|
+
- - ">="
|
|
185
|
+
- !ruby/object:Gem::Version
|
|
186
|
+
version: '0'
|
|
187
|
+
type: :runtime
|
|
188
|
+
prerelease: false
|
|
189
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
190
|
+
requirements:
|
|
191
|
+
- - ">="
|
|
192
|
+
- !ruby/object:Gem::Version
|
|
193
|
+
version: '0'
|
|
166
194
|
- !ruby/object:Gem::Dependency
|
|
167
195
|
name: async-http
|
|
168
196
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -216,9 +244,11 @@ files:
|
|
|
216
244
|
- docs/api/core/index.md
|
|
217
245
|
- docs/api/core/memory.md
|
|
218
246
|
- docs/api/core/network.md
|
|
247
|
+
- docs/api/core/result.md
|
|
219
248
|
- docs/api/core/robot.md
|
|
220
249
|
- docs/api/core/state.md
|
|
221
250
|
- docs/api/core/tool.md
|
|
251
|
+
- docs/api/errors.md
|
|
222
252
|
- docs/api/index.md
|
|
223
253
|
- docs/api/mcp/client.md
|
|
224
254
|
- docs/api/mcp/index.md
|
|
@@ -254,12 +284,17 @@ files:
|
|
|
254
284
|
- docs/guides/building-robots.md
|
|
255
285
|
- docs/guides/creating-networks.md
|
|
256
286
|
- docs/guides/index.md
|
|
287
|
+
- docs/guides/knowledge.md
|
|
257
288
|
- docs/guides/mcp-integration.md
|
|
258
289
|
- docs/guides/memory.md
|
|
290
|
+
- docs/guides/observability.md
|
|
291
|
+
- docs/guides/ractor-parallelism.md
|
|
259
292
|
- docs/guides/rails-integration.md
|
|
260
293
|
- docs/guides/streaming.md
|
|
261
294
|
- docs/guides/using-tools.md
|
|
262
295
|
- docs/index.md
|
|
296
|
+
- docs/superpowers/plans/2026-04-14-ractor-integration.md
|
|
297
|
+
- docs/superpowers/specs/2026-04-14-ractor-integration-design.md
|
|
263
298
|
- examples/01_simple_robot.rb
|
|
264
299
|
- examples/02_tools.rb
|
|
265
300
|
- examples/03_network.rb
|
|
@@ -343,6 +378,24 @@ files:
|
|
|
343
378
|
- examples/18_rails/config/initializers/robot_lab.rb
|
|
344
379
|
- examples/18_rails/config/routes.rb
|
|
345
380
|
- examples/18_rails/db/migrate/001_create_robot_lab_tables.rb
|
|
381
|
+
- examples/19_token_tracking.rb
|
|
382
|
+
- examples/20_circuit_breaker.rb
|
|
383
|
+
- examples/21_learning_loop.rb
|
|
384
|
+
- examples/22_context_compression.rb
|
|
385
|
+
- examples/23_convergence.rb
|
|
386
|
+
- examples/24_structured_delegation.rb
|
|
387
|
+
- examples/25_history_search.rb
|
|
388
|
+
- examples/25_history_search/conversation.jsonl
|
|
389
|
+
- examples/26_document_store.rb
|
|
390
|
+
- examples/26_document_store/api_versioning_adr.md
|
|
391
|
+
- examples/26_document_store/incident_postmortem.md
|
|
392
|
+
- examples/26_document_store/postgres_runbook.md
|
|
393
|
+
- examples/26_document_store/redis_caching_guide.md
|
|
394
|
+
- examples/26_document_store/sidekiq_guide.md
|
|
395
|
+
- examples/27_incident_response/incident_response.rb
|
|
396
|
+
- examples/28_mcp_discovery.rb
|
|
397
|
+
- examples/29_ractor_tools.rb
|
|
398
|
+
- examples/30_ractor_network.rb
|
|
346
399
|
- examples/README.md
|
|
347
400
|
- examples/prompts/assistant.md
|
|
348
401
|
- examples/prompts/audit_trail.md
|
|
@@ -382,7 +435,10 @@ files:
|
|
|
382
435
|
- examples/prompts/skill_nested_test.md
|
|
383
436
|
- examples/prompts/skill_refs_main_test.md
|
|
384
437
|
- examples/prompts/skill_self_ref_test.md
|
|
438
|
+
- examples/prompts/skill_with_mcp_test.md
|
|
385
439
|
- examples/prompts/skill_with_params_test.md
|
|
440
|
+
- examples/prompts/skill_with_robot_name_test.md
|
|
441
|
+
- examples/prompts/skill_with_tools_test.md
|
|
386
442
|
- examples/prompts/sre_compliance.md
|
|
387
443
|
- examples/prompts/structured_output.md
|
|
388
444
|
- examples/prompts/synthesizer.md
|
|
@@ -401,11 +457,18 @@ files:
|
|
|
401
457
|
- lib/generators/robot_lab/templates/thread_model.rb.tt
|
|
402
458
|
- lib/robot_lab.rb
|
|
403
459
|
- lib/robot_lab/ask_user.rb
|
|
460
|
+
- lib/robot_lab/bus_poller.rb
|
|
404
461
|
- lib/robot_lab/config.rb
|
|
405
462
|
- lib/robot_lab/config/defaults.yml
|
|
463
|
+
- lib/robot_lab/convergence.rb
|
|
464
|
+
- lib/robot_lab/delegation_future.rb
|
|
465
|
+
- lib/robot_lab/document_store.rb
|
|
406
466
|
- lib/robot_lab/error.rb
|
|
467
|
+
- lib/robot_lab/history_compressor.rb
|
|
407
468
|
- lib/robot_lab/mcp/client.rb
|
|
469
|
+
- lib/robot_lab/mcp/connection_poller.rb
|
|
408
470
|
- lib/robot_lab/mcp/server.rb
|
|
471
|
+
- lib/robot_lab/mcp/server_discovery.rb
|
|
409
472
|
- lib/robot_lab/mcp/transports/base.rb
|
|
410
473
|
- lib/robot_lab/mcp/transports/sse.rb
|
|
411
474
|
- lib/robot_lab/mcp/transports/stdio.rb
|
|
@@ -415,11 +478,17 @@ files:
|
|
|
415
478
|
- lib/robot_lab/memory_change.rb
|
|
416
479
|
- lib/robot_lab/message.rb
|
|
417
480
|
- lib/robot_lab/network.rb
|
|
481
|
+
- lib/robot_lab/ractor_boundary.rb
|
|
482
|
+
- lib/robot_lab/ractor_job.rb
|
|
483
|
+
- lib/robot_lab/ractor_memory_proxy.rb
|
|
484
|
+
- lib/robot_lab/ractor_network_scheduler.rb
|
|
485
|
+
- lib/robot_lab/ractor_worker_pool.rb
|
|
418
486
|
- lib/robot_lab/rails_integration/engine.rb
|
|
419
487
|
- lib/robot_lab/rails_integration/railtie.rb
|
|
420
488
|
- lib/robot_lab/rails_integration/turbo_stream_callbacks.rb
|
|
421
489
|
- lib/robot_lab/robot.rb
|
|
422
490
|
- lib/robot_lab/robot/bus_messaging.rb
|
|
491
|
+
- lib/robot_lab/robot/history_search.rb
|
|
423
492
|
- lib/robot_lab/robot/mcp_management.rb
|
|
424
493
|
- lib/robot_lab/robot/template_rendering.rb
|
|
425
494
|
- lib/robot_lab/robot_message.rb
|
|
@@ -430,6 +499,7 @@ files:
|
|
|
430
499
|
- lib/robot_lab/streaming/events.rb
|
|
431
500
|
- lib/robot_lab/streaming/sequence_counter.rb
|
|
432
501
|
- lib/robot_lab/task.rb
|
|
502
|
+
- lib/robot_lab/text_analysis.rb
|
|
433
503
|
- lib/robot_lab/tool.rb
|
|
434
504
|
- lib/robot_lab/tool_config.rb
|
|
435
505
|
- lib/robot_lab/tool_manifest.rb
|
|
@@ -464,7 +534,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
464
534
|
- !ruby/object:Gem::Version
|
|
465
535
|
version: '0'
|
|
466
536
|
requirements: []
|
|
467
|
-
rubygems_version: 4.0.
|
|
537
|
+
rubygems_version: 4.0.10
|
|
468
538
|
specification_version: 4
|
|
469
539
|
summary: Ruby framework for building and orchestrating multi-robot LLM workflows
|
|
470
540
|
test_files: []
|