swarm_sdk 2.7.13 → 2.7.15
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/lib/swarm_sdk/agent/builder.rb +25 -0
- data/lib/swarm_sdk/agent/chat.rb +47 -40
- data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +4 -0
- data/lib/swarm_sdk/agent/definition.rb +8 -1
- data/lib/swarm_sdk/agent/system_prompt_builder.rb +15 -3
- data/lib/swarm_sdk/builders/base_builder.rb +5 -0
- data/lib/swarm_sdk/concerns/cleanupable.rb +3 -0
- data/lib/swarm_sdk/config.rb +2 -1
- data/lib/swarm_sdk/configuration/translator.rb +2 -0
- data/lib/swarm_sdk/observer/manager.rb +12 -0
- data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +2 -0
- data/lib/swarm_sdk/result.rb +29 -0
- data/lib/swarm_sdk/ruby_llm_patches/chat_callbacks_patch.rb +27 -22
- data/lib/swarm_sdk/ruby_llm_patches/init.rb +9 -0
- data/lib/swarm_sdk/ruby_llm_patches/mcp_ssl_patch.rb +144 -0
- data/lib/swarm_sdk/ruby_llm_patches/openai_thought_signature_patch.rb +98 -0
- data/lib/swarm_sdk/ruby_llm_patches/streaming_error_patch.rb +50 -0
- data/lib/swarm_sdk/ruby_llm_patches/tool_concurrency_patch.rb +3 -4
- data/lib/swarm_sdk/swarm/all_agents_builder.rb +9 -0
- data/lib/swarm_sdk/swarm/executor.rb +176 -20
- data/lib/swarm_sdk/swarm/hook_triggers.rb +11 -0
- data/lib/swarm_sdk/swarm/logging_callbacks.rb +1 -0
- data/lib/swarm_sdk/swarm/mcp_configurator.rb +20 -0
- data/lib/swarm_sdk/swarm.rb +132 -2
- data/lib/swarm_sdk/version.rb +1 -1
- data/lib/swarm_sdk.rb +3 -0
- metadata +4 -1
data/lib/swarm_sdk/swarm.rb
CHANGED
|
@@ -72,7 +72,7 @@ module SwarmSDK
|
|
|
72
72
|
# Default tools available to all agents
|
|
73
73
|
DEFAULT_TOOLS = ToolConfigurator::DEFAULT_TOOLS
|
|
74
74
|
|
|
75
|
-
attr_reader :name, :agents, :lead_agent, :mcp_clients, :delegation_instances, :agent_definitions, :swarm_id, :parent_swarm_id, :swarm_registry, :scratchpad_storage, :allow_filesystem_tools, :hook_registry, :global_semaphore, :plugin_storages, :config_for_hooks, :observer_configs, :execution_timeout
|
|
75
|
+
attr_reader :name, :agents, :lead_agent, :mcp_clients, :delegation_instances, :agent_definitions, :swarm_id, :parent_swarm_id, :swarm_registry, :scratchpad_storage, :allow_filesystem_tools, :hook_registry, :global_semaphore, :plugin_storages, :config_for_hooks, :observer_configs, :execution_timeout, :stop_signal_read
|
|
76
76
|
|
|
77
77
|
# Check if scratchpad tools are enabled
|
|
78
78
|
#
|
|
@@ -217,6 +217,13 @@ module SwarmSDK
|
|
|
217
217
|
# Observer agent configurations
|
|
218
218
|
@observer_configs = []
|
|
219
219
|
@observer_manager = nil
|
|
220
|
+
|
|
221
|
+
# Stop mechanism state
|
|
222
|
+
@stop_requested = false
|
|
223
|
+
@execution_barrier = nil
|
|
224
|
+
@stop_signal_read = nil
|
|
225
|
+
@stop_signal_write = nil
|
|
226
|
+
@active_agent_chats = {}
|
|
220
227
|
end
|
|
221
228
|
|
|
222
229
|
# Add an agent to the swarm
|
|
@@ -471,12 +478,17 @@ module SwarmSDK
|
|
|
471
478
|
|
|
472
479
|
# Wait for all observer tasks to complete
|
|
473
480
|
#
|
|
481
|
+
# If a stop was requested, stops observer tasks immediately instead of waiting.
|
|
474
482
|
# Called by Executor to wait for observer agents before cleanup.
|
|
475
483
|
# Safe to call even if no observers are configured.
|
|
476
484
|
#
|
|
477
485
|
# @return [void]
|
|
478
486
|
def wait_for_observers
|
|
479
|
-
@
|
|
487
|
+
if @stop_requested
|
|
488
|
+
stop_observers
|
|
489
|
+
else
|
|
490
|
+
@observer_manager&.wait_for_completion
|
|
491
|
+
end
|
|
480
492
|
end
|
|
481
493
|
|
|
482
494
|
# Cleanup observer subscriptions
|
|
@@ -490,6 +502,124 @@ module SwarmSDK
|
|
|
490
502
|
@observer_manager = nil
|
|
491
503
|
end
|
|
492
504
|
|
|
505
|
+
# Stop all swarm execution immediately
|
|
506
|
+
#
|
|
507
|
+
# Thread-safe method that signals the execution to stop. Uses IO.pipe
|
|
508
|
+
# for cross-thread signaling, which wakes the Async scheduler from any
|
|
509
|
+
# thread. The stop listener task then calls barrier.stop within the
|
|
510
|
+
# reactor to cancel all executing tasks.
|
|
511
|
+
#
|
|
512
|
+
# Safe to call from event callbacks, other threads, or signal handlers.
|
|
513
|
+
# No-op if no execution is in progress or stop was already requested.
|
|
514
|
+
#
|
|
515
|
+
# @return [void]
|
|
516
|
+
#
|
|
517
|
+
# @example Stop from event callback
|
|
518
|
+
# swarm.execute("Build auth") do |event|
|
|
519
|
+
# swarm.stop if event[:type] == "tool_call" && event[:tool] == "Dangerous"
|
|
520
|
+
# end
|
|
521
|
+
#
|
|
522
|
+
# @example Stop from another thread
|
|
523
|
+
# Thread.new { swarm.execute("Build auth") }
|
|
524
|
+
# sleep 10
|
|
525
|
+
# swarm.stop
|
|
526
|
+
def stop
|
|
527
|
+
return if @stop_requested
|
|
528
|
+
|
|
529
|
+
@stop_requested = true
|
|
530
|
+
begin
|
|
531
|
+
@stop_signal_write&.write("x") unless @stop_signal_write&.closed?
|
|
532
|
+
@stop_signal_write&.close unless @stop_signal_write&.closed?
|
|
533
|
+
rescue IOError, Errno::EPIPE
|
|
534
|
+
# Pipe already closed - normal during cleanup
|
|
535
|
+
end
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
# Check if a stop has been requested
|
|
539
|
+
#
|
|
540
|
+
# @return [Boolean] true if stop was requested
|
|
541
|
+
def stop_requested?
|
|
542
|
+
@stop_requested
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
# Prepare stop signaling for a new execution
|
|
546
|
+
#
|
|
547
|
+
# Resets the stop flag and creates a new IO.pipe for signaling.
|
|
548
|
+
# Called by Executor at the start of each execution.
|
|
549
|
+
#
|
|
550
|
+
# @return [void]
|
|
551
|
+
def prepare_for_execution
|
|
552
|
+
@stop_requested = false
|
|
553
|
+
@stop_signal_read, @stop_signal_write = IO.pipe
|
|
554
|
+
@active_agent_chats = {}
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
# Close the stop signal pipe
|
|
558
|
+
#
|
|
559
|
+
# Called by Executor after execution completes.
|
|
560
|
+
#
|
|
561
|
+
# @return [void]
|
|
562
|
+
def cleanup_stop_signal
|
|
563
|
+
@stop_signal_read&.close unless @stop_signal_read&.closed?
|
|
564
|
+
@stop_signal_write&.close unless @stop_signal_write&.closed?
|
|
565
|
+
@stop_signal_read = nil
|
|
566
|
+
@stop_signal_write = nil
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
# Register the execution barrier for stop cancellation
|
|
570
|
+
#
|
|
571
|
+
# @param barrier [Async::Barrier] The barrier wrapping execution tasks
|
|
572
|
+
# @return [void]
|
|
573
|
+
def register_execution_barrier(barrier)
|
|
574
|
+
@execution_barrier = barrier
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
# Clear the execution barrier reference
|
|
578
|
+
#
|
|
579
|
+
# @return [void]
|
|
580
|
+
def clear_execution_barrier
|
|
581
|
+
@execution_barrier = nil
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
# Mark an agent as actively executing an LLM call
|
|
585
|
+
#
|
|
586
|
+
# Called by Agent::Chat#execute_ask to track which agents are mid-execution.
|
|
587
|
+
# Used during interruption to emit agent_stop events for active agents.
|
|
588
|
+
#
|
|
589
|
+
# @param name [Symbol] Agent name
|
|
590
|
+
# @param chat [Agent::Chat] Agent chat instance
|
|
591
|
+
# @return [void]
|
|
592
|
+
def mark_agent_active(name, chat)
|
|
593
|
+
@active_agent_chats[name] = chat
|
|
594
|
+
end
|
|
595
|
+
|
|
596
|
+
# Mark an agent as no longer actively executing
|
|
597
|
+
#
|
|
598
|
+
# @param name [Symbol] Agent name
|
|
599
|
+
# @return [void]
|
|
600
|
+
def mark_agent_inactive(name)
|
|
601
|
+
@active_agent_chats.delete(name)
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
# Get a snapshot of currently active agent chats
|
|
605
|
+
#
|
|
606
|
+
# Returns a copy to avoid concurrent modification issues.
|
|
607
|
+
#
|
|
608
|
+
# @return [Hash{Symbol => Agent::Chat}] Copy of active agent chats
|
|
609
|
+
def active_agent_chats
|
|
610
|
+
@active_agent_chats.dup
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
# Stop all observer tasks immediately
|
|
614
|
+
#
|
|
615
|
+
# Interrupts in-flight observer LLM calls.
|
|
616
|
+
# Called during swarm interruption instead of wait_for_completion.
|
|
617
|
+
#
|
|
618
|
+
# @return [void]
|
|
619
|
+
def stop_observers
|
|
620
|
+
@observer_manager&.stop
|
|
621
|
+
end
|
|
622
|
+
|
|
493
623
|
# Create snapshot of current conversation state
|
|
494
624
|
#
|
|
495
625
|
# Returns a Snapshot object containing:
|
data/lib/swarm_sdk/version.rb
CHANGED
data/lib/swarm_sdk.rb
CHANGED
|
@@ -91,6 +91,9 @@ module SwarmSDK
|
|
|
91
91
|
# Raised when agent turn exceeds turn_timeout
|
|
92
92
|
class TurnTimeoutError < TimeoutError; end
|
|
93
93
|
|
|
94
|
+
# Raised when swarm execution is interrupted via swarm.stop
|
|
95
|
+
class InterruptedError < Error; end
|
|
96
|
+
|
|
94
97
|
# Base class for MCP-related errors (provides context about server/tool)
|
|
95
98
|
class MCPError < Error; end
|
|
96
99
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: swarm_sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.7.
|
|
4
|
+
version: 2.7.15
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Paulo Arruda
|
|
@@ -181,8 +181,11 @@ files:
|
|
|
181
181
|
- lib/swarm_sdk/ruby_llm_patches/connection_patch.rb
|
|
182
182
|
- lib/swarm_sdk/ruby_llm_patches/init.rb
|
|
183
183
|
- lib/swarm_sdk/ruby_llm_patches/io_endpoint_patch.rb
|
|
184
|
+
- lib/swarm_sdk/ruby_llm_patches/mcp_ssl_patch.rb
|
|
184
185
|
- lib/swarm_sdk/ruby_llm_patches/message_management_patch.rb
|
|
186
|
+
- lib/swarm_sdk/ruby_llm_patches/openai_thought_signature_patch.rb
|
|
185
187
|
- lib/swarm_sdk/ruby_llm_patches/responses_api_patch.rb
|
|
188
|
+
- lib/swarm_sdk/ruby_llm_patches/streaming_error_patch.rb
|
|
186
189
|
- lib/swarm_sdk/ruby_llm_patches/tool_concurrency_patch.rb
|
|
187
190
|
- lib/swarm_sdk/snapshot.rb
|
|
188
191
|
- lib/swarm_sdk/snapshot_from_events.rb
|