Class: SwarmSDK::Tools::Delegate
- Inherits:
-
RubyLLM::Tool
- Object
- RubyLLM::Tool
- SwarmSDK::Tools::Delegate
- Defined in:
- lib/swarm_sdk/tools/delegate.rb
Overview
Delegate tool for working with other agents in the swarm
Creates agent-specific collaboration tools (e.g., WorkWithBackend) that allow one agent to work with another agent. Supports pre/post delegation hooks for customization.
Constant Summary collapse
- TOOL_NAME_PREFIX =
Tool name prefix for delegation tools Change this to customize the tool naming pattern (e.g., "DelegateTaskTo", "AskAgent", etc.)
"WorkWith"
Instance Attribute Summary collapse
-
#delegate_name ⇒ Object
readonly
Returns the value of attribute delegate_name.
-
#delegate_target ⇒ Object
readonly
Returns the value of attribute delegate_target.
-
#tool_name ⇒ Object
readonly
Returns the value of attribute tool_name.
Class Method Summary collapse
-
.tool_name_for(delegate_name) ⇒ String
Generate tool name for a delegate agent.
Instance Method Summary collapse
-
#description ⇒ Object
Override description to return dynamic string based on delegate.
-
#execute(message:) ⇒ String
Execute delegation with pre/post hooks.
-
#initialize(delegate_name:, delegate_description:, delegate_chat:, agent_name:, swarm:, delegating_chat: nil) ⇒ Delegate
constructor
Initialize a delegation tool.
-
#name ⇒ Object
Override name to return custom delegation tool name.
Constructor Details
#initialize(delegate_name:, delegate_description:, delegate_chat:, agent_name:, swarm:, delegating_chat: nil) ⇒ Delegate
Initialize a delegation tool
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/swarm_sdk/tools/delegate.rb', line 39 def initialize( delegate_name:, delegate_description:, delegate_chat:, agent_name:, swarm:, delegating_chat: nil ) super() @delegate_name = delegate_name @delegate_description = delegate_description @delegate_chat = delegate_chat @agent_name = agent_name @swarm = swarm @delegating_chat = delegating_chat # Generate tool name using canonical method @tool_name = self.class.tool_name_for(delegate_name) @delegate_target = delegate_name.to_s end |
Instance Attribute Details
#delegate_name ⇒ Object (readonly)
Returns the value of attribute delegate_name.
29 30 31 |
# File 'lib/swarm_sdk/tools/delegate.rb', line 29 def delegate_name @delegate_name end |
#delegate_target ⇒ Object (readonly)
Returns the value of attribute delegate_target.
29 30 31 |
# File 'lib/swarm_sdk/tools/delegate.rb', line 29 def delegate_target @delegate_target end |
#tool_name ⇒ Object (readonly)
Returns the value of attribute tool_name.
29 30 31 |
# File 'lib/swarm_sdk/tools/delegate.rb', line 29 def tool_name @tool_name end |
Class Method Details
.tool_name_for(delegate_name) ⇒ String
Generate tool name for a delegate agent
This is the single source of truth for delegation tool naming. Used both when creating Delegate instances and when predicting tool names for agent context setup.
24 25 26 |
# File 'lib/swarm_sdk/tools/delegate.rb', line 24 def tool_name_for(delegate_name) "#{TOOL_NAME_PREFIX}#{delegate_name.to_s.capitalize}" end |
Instance Method Details
#description ⇒ Object
Override description to return dynamic string based on delegate
62 63 64 |
# File 'lib/swarm_sdk/tools/delegate.rb', line 62 def description "Work with #{@delegate_name} to delegate work, ask questions, or collaborate. #{@delegate_description}" end |
#execute(message:) ⇒ String
Execute delegation with pre/post hooks
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/swarm_sdk/tools/delegate.rb', line 80 def execute(message:) # Access swarm infrastructure call_stack = @swarm.delegation_call_stack hook_registry = @swarm.hook_registry swarm_registry = @swarm.swarm_registry # Check for circular dependency if call_stack.include?(@delegate_target) emit_circular_warning(call_stack) return "Error: Circular delegation detected: #{call_stack.join(" -> ")} -> #{@delegate_target}. " \ "Please restructure your delegation to avoid infinite loops." end # Get agent-specific hooks from the delegating chat instance agent_hooks = if @delegating_chat&.respond_to?(:hook_agent_hooks) @delegating_chat.hook_agent_hooks || {} else {} end # Trigger pre_delegation callback context = Hooks::Context.new( event: :pre_delegation, agent_name: @agent_name, swarm: @swarm, delegation_target: @delegate_target, metadata: { tool_name: @tool_name, message: , timestamp: Time.now.utc.iso8601, }, ) executor = Hooks::Executor.new(hook_registry, logger: RubyLLM.logger) pre_agent_hooks = agent_hooks[:pre_delegation] || [] result = executor.execute_safe(event: :pre_delegation, context: context, callbacks: pre_agent_hooks) # Check if callback halted or replaced the delegation if result.halt? return result.value || "Delegation halted by callback" elsif result.replace? return result.value end # Determine delegation type and proceed delegation_result = if @delegate_chat # Delegate to agent delegate_to_agent(, call_stack) elsif swarm_registry&.registered?(@delegate_target) # Delegate to registered swarm delegate_to_swarm(, call_stack, swarm_registry) else raise ConfigurationError, "Unknown delegation target: #{@delegate_target}" end # Trigger post_delegation callback post_context = Hooks::Context.new( event: :post_delegation, agent_name: @agent_name, swarm: @swarm, delegation_target: @delegate_target, delegation_result: delegation_result, metadata: { tool_name: @tool_name, message: , result: delegation_result, timestamp: Time.now.utc.iso8601, }, ) post_agent_hooks = agent_hooks[:post_delegation] || [] post_result = executor.execute_safe(event: :post_delegation, context: post_context, callbacks: post_agent_hooks) # Return modified result if callback replaces it if post_result.replace? post_result.value else delegation_result end rescue Faraday::TimeoutError, Net::ReadTimeout => e # Log timeout error as JSON event LogStream.emit( type: "delegation_error", agent: @agent_name, swarm_id: @swarm.swarm_id, parent_swarm_id: @swarm.parent_swarm_id, delegate_to: @tool_name, error_class: e.class.name, error_message: "Request timed out", error_backtrace: e.backtrace&.first(5) || [], ) "Error: Request to #{@tool_name} timed out. The agent may be overloaded or the LLM service is not responding. Please try again or simplify the task." rescue Faraday::Error => e # Log network error as JSON event LogStream.emit( type: "delegation_error", agent: @agent_name, swarm_id: @swarm.swarm_id, parent_swarm_id: @swarm.parent_swarm_id, delegate_to: @tool_name, error_class: e.class.name, error_message: e., error_backtrace: e.backtrace&.first(5) || [], ) "Error: Network error communicating with #{@tool_name}: #{e.class.name}. Please check connectivity and try again." rescue StandardError => e # Log unexpected error as JSON event backtrace_array = e.backtrace&.first(5) || [] LogStream.emit( type: "delegation_error", agent: @agent_name, swarm_id: @swarm.swarm_id, parent_swarm_id: @swarm.parent_swarm_id, delegate_to: @tool_name, error_class: e.class.name, error_message: e., error_backtrace: backtrace_array, ) # Return error string for LLM backtrace_str = backtrace_array.join("\n ") "Error: #{@tool_name} encountered an error: #{e.class.name}: #{e.}\nBacktrace:\n #{backtrace_str}" end |
#name ⇒ Object
Override name to return custom delegation tool name
72 73 74 |
# File 'lib/swarm_sdk/tools/delegate.rb', line 72 def name @tool_name end |