swarm_sdk 2.6.0 → 2.6.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.
- checksums.yaml +4 -4
- data/lib/swarm_sdk/agent/builder.rb +33 -2
- data/lib/swarm_sdk/agent/definition.rb +64 -4
- data/lib/swarm_sdk/builders/base_builder.rb +49 -3
- data/lib/swarm_sdk/configuration/parser.rb +22 -1
- data/lib/swarm_sdk/configuration/translator.rb +23 -2
- data/lib/swarm_sdk/configuration.rb +22 -1
- data/lib/swarm_sdk/swarm/agent_initializer.rb +26 -16
- data/lib/swarm_sdk/tools/delegate.rb +5 -3
- data/lib/swarm_sdk/version.rb +1 -1
- data/lib/swarm_sdk/workflow/agent_config.rb +19 -3
- data/lib/swarm_sdk/workflow/builder.rb +36 -1
- data/lib/swarm_sdk/workflow/node_builder.rb +37 -1
- data/lib/swarm_sdk/workflow.rb +36 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ce2f1c2ddb88cfb9a4fe7505fc0417494c2baf22a41678cbe7eb9085d96f136f
|
|
4
|
+
data.tar.gz: 5d5c8174d6f96d52f6855636d5fc7c485db6a0470e11d18ee2b5866fcd91431a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5e503eeda171b1840cabc10fccc5f98d1c4bcd75eba1782f885fd19cc09219b39850662c901793ff9e9d0cbfbdfcc9759071c782476bb793ab87f9ddd94c3ae9
|
|
7
|
+
data.tar.gz: 054e3a4db5ead9c96e2d332a1a85e9102bdaabe8e50c1e3163776789709289b5fbc73fce5f73b4af856c6e1ca0a3e6f5b3cbf4918f10f6a946c9ef6223384b12
|
|
@@ -250,8 +250,39 @@ module SwarmSDK
|
|
|
250
250
|
end
|
|
251
251
|
|
|
252
252
|
# Set delegation targets
|
|
253
|
-
|
|
254
|
-
|
|
253
|
+
#
|
|
254
|
+
# Supports multiple formats for flexibility:
|
|
255
|
+
#
|
|
256
|
+
# @example Simple array (backwards compatible)
|
|
257
|
+
# delegates_to :frontend, :backend, :qa
|
|
258
|
+
#
|
|
259
|
+
# @example Hash with custom tool names
|
|
260
|
+
# delegates_to frontend: "AskFrontend",
|
|
261
|
+
# backend: "GetBackendHelp",
|
|
262
|
+
# qa: "RequestReview"
|
|
263
|
+
#
|
|
264
|
+
# @example Mixed - some auto, some custom
|
|
265
|
+
# delegates_to :frontend,
|
|
266
|
+
# backend: "GetBackendHelp",
|
|
267
|
+
# :qa
|
|
268
|
+
#
|
|
269
|
+
# @param agent_names_and_options [Array<Symbol, Hash>] Agent names and/or hash with custom tool names
|
|
270
|
+
# @return [void]
|
|
271
|
+
def delegates_to(*agent_names_and_options)
|
|
272
|
+
agent_names_and_options.each do |item|
|
|
273
|
+
case item
|
|
274
|
+
when Symbol, String
|
|
275
|
+
# Simple format: :frontend
|
|
276
|
+
@delegates_to << { agent: item.to_sym, tool_name: nil }
|
|
277
|
+
when Hash
|
|
278
|
+
# Hash format: { frontend: "AskFrontend", backend: nil }
|
|
279
|
+
item.each do |agent, tool_name|
|
|
280
|
+
@delegates_to << { agent: agent.to_sym, tool_name: tool_name }
|
|
281
|
+
end
|
|
282
|
+
else
|
|
283
|
+
raise ConfigurationError, "delegates_to accepts Symbols or Hashes, got #{item.class}"
|
|
284
|
+
end
|
|
285
|
+
end
|
|
255
286
|
end
|
|
256
287
|
|
|
257
288
|
# Add a hook (Ruby block OR shell command)
|
|
@@ -24,7 +24,7 @@ module SwarmSDK
|
|
|
24
24
|
:context_window,
|
|
25
25
|
:directory,
|
|
26
26
|
:tools,
|
|
27
|
-
:
|
|
27
|
+
:delegation_configs, # Full delegation config with tool names
|
|
28
28
|
:system_prompt,
|
|
29
29
|
:provider,
|
|
30
30
|
:base_url,
|
|
@@ -125,7 +125,8 @@ module SwarmSDK
|
|
|
125
125
|
# Inject default write restrictions for security
|
|
126
126
|
@tools = inject_default_write_permissions(@tools)
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
# Parse delegation configuration (supports both simple arrays and custom tool names)
|
|
129
|
+
@delegation_configs = parse_delegation_config(config[:delegates_to])
|
|
129
130
|
@mcp_servers = Array(config[:mcp_servers] || [])
|
|
130
131
|
|
|
131
132
|
# Parse hooks configuration
|
|
@@ -135,6 +136,20 @@ module SwarmSDK
|
|
|
135
136
|
validate!
|
|
136
137
|
end
|
|
137
138
|
|
|
139
|
+
# Get agent names that this agent delegates to (backwards compatible)
|
|
140
|
+
#
|
|
141
|
+
# Returns an array of agent name symbols. This maintains backwards compatibility
|
|
142
|
+
# with existing code that expects delegates_to to be a simple array.
|
|
143
|
+
#
|
|
144
|
+
# @return [Array<Symbol>] Delegate agent names
|
|
145
|
+
#
|
|
146
|
+
# @example
|
|
147
|
+
# agent_definition.delegates_to
|
|
148
|
+
# # => [:frontend, :backend, :qa]
|
|
149
|
+
def delegates_to
|
|
150
|
+
@delegation_configs.map { |config| config[:agent] }
|
|
151
|
+
end
|
|
152
|
+
|
|
138
153
|
# Get plugin-specific configuration
|
|
139
154
|
#
|
|
140
155
|
# Plugins store their configuration in the generic plugin_configs hash.
|
|
@@ -146,7 +161,7 @@ module SwarmSDK
|
|
|
146
161
|
#
|
|
147
162
|
# @example
|
|
148
163
|
# agent_definition.plugin_config(:memory)
|
|
149
|
-
# # => { directory: "tmp/memory", mode: :
|
|
164
|
+
# # => { directory: "tmp/memory", mode: :full_access }
|
|
150
165
|
def plugin_config(plugin_name)
|
|
151
166
|
@plugin_configs[plugin_name.to_sym] || @plugin_configs[plugin_name.to_s]
|
|
152
167
|
end
|
|
@@ -160,7 +175,7 @@ module SwarmSDK
|
|
|
160
175
|
context_window: @context_window,
|
|
161
176
|
directory: @directory,
|
|
162
177
|
tools: @tools,
|
|
163
|
-
delegates_to: @
|
|
178
|
+
delegates_to: @delegation_configs, # Serialize full config
|
|
164
179
|
system_prompt: @system_prompt,
|
|
165
180
|
provider: @provider,
|
|
166
181
|
base_url: @base_url,
|
|
@@ -285,6 +300,51 @@ module SwarmSDK
|
|
|
285
300
|
File.expand_path(directory_config.to_s)
|
|
286
301
|
end
|
|
287
302
|
|
|
303
|
+
# Parse delegation configuration
|
|
304
|
+
#
|
|
305
|
+
# Supports multiple formats for backwards compatibility and new features:
|
|
306
|
+
# 1. Simple array (backwards compatible): [:frontend, :backend]
|
|
307
|
+
# 2. Hash with custom tool names: { frontend: "AskFrontend", backend: nil }
|
|
308
|
+
# 3. Array of hashes: [{ agent: :frontend, tool_name: "AskFrontend" }]
|
|
309
|
+
#
|
|
310
|
+
# Returns normalized format: [{agent: :name, tool_name: "Custom" or nil}]
|
|
311
|
+
#
|
|
312
|
+
# @param delegation_config [nil, Array, Hash] Delegation configuration
|
|
313
|
+
# @return [Array<Hash>] Normalized delegation config
|
|
314
|
+
def parse_delegation_config(delegation_config)
|
|
315
|
+
return [] if delegation_config.nil?
|
|
316
|
+
return [] if delegation_config.respond_to?(:empty?) && delegation_config.empty?
|
|
317
|
+
|
|
318
|
+
# Handle array format (could be symbols or hashes)
|
|
319
|
+
if delegation_config.is_a?(Array)
|
|
320
|
+
delegation_config.flat_map do |item|
|
|
321
|
+
case item
|
|
322
|
+
when Symbol, String
|
|
323
|
+
# Simple format: :frontend → {agent: :frontend, tool_name: nil}
|
|
324
|
+
[{ agent: item.to_sym, tool_name: nil }]
|
|
325
|
+
when Hash
|
|
326
|
+
# Could be already normalized or hash format
|
|
327
|
+
if item.key?(:agent)
|
|
328
|
+
# Already normalized: {agent: :frontend, tool_name: "Custom"}
|
|
329
|
+
[item]
|
|
330
|
+
else
|
|
331
|
+
# Hash format in array: {frontend: "AskFrontend"}
|
|
332
|
+
item.map { |agent, tool_name| { agent: agent.to_sym, tool_name: tool_name } }
|
|
333
|
+
end
|
|
334
|
+
else
|
|
335
|
+
raise ConfigurationError, "Invalid delegation config format: #{item.inspect}"
|
|
336
|
+
end
|
|
337
|
+
end.uniq { |config| config[:agent] } # Remove duplicates by agent name
|
|
338
|
+
elsif delegation_config.is_a?(Hash)
|
|
339
|
+
# Hash format: {frontend: "AskFrontend", backend: nil}
|
|
340
|
+
delegation_config.map do |agent, tool_name|
|
|
341
|
+
{ agent: agent.to_sym, tool_name: tool_name }
|
|
342
|
+
end
|
|
343
|
+
else
|
|
344
|
+
raise ConfigurationError, "delegates_to must be an Array or Hash, got #{delegation_config.class}"
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
|
|
288
348
|
# Extract plugin-specific configuration keys from the config hash
|
|
289
349
|
#
|
|
290
350
|
# Standard SDK keys are filtered out, leaving only plugin-specific keys.
|
|
@@ -276,8 +276,17 @@ module SwarmSDK
|
|
|
276
276
|
builder.tools(*tool_names)
|
|
277
277
|
end
|
|
278
278
|
|
|
279
|
-
# Add delegates_to
|
|
280
|
-
|
|
279
|
+
# Add delegates_to (handle both array and hash formats)
|
|
280
|
+
if config[:delegates_to]&.any?
|
|
281
|
+
delegation_config = config[:delegates_to]
|
|
282
|
+
if delegation_config.is_a?(Hash)
|
|
283
|
+
# Hash format: pass as single argument
|
|
284
|
+
builder.delegates_to(delegation_config)
|
|
285
|
+
elsif delegation_config.is_a?(Array)
|
|
286
|
+
# Array format: splat the array
|
|
287
|
+
builder.delegates_to(*delegation_config)
|
|
288
|
+
end
|
|
289
|
+
end
|
|
281
290
|
|
|
282
291
|
# Add MCP servers
|
|
283
292
|
config[:mcp_servers]&.each do |server|
|
|
@@ -333,7 +342,15 @@ module SwarmSDK
|
|
|
333
342
|
when :tools
|
|
334
343
|
merged[:tools] = Array(merged[:tools]) + Array(value)
|
|
335
344
|
when :delegates_to
|
|
336
|
-
|
|
345
|
+
# Handle merging delegation configs (can be array or hash)
|
|
346
|
+
existing = merged[:delegates_to] || []
|
|
347
|
+
new_value = value || []
|
|
348
|
+
|
|
349
|
+
# Convert both to array of delegation configs for merging
|
|
350
|
+
existing_array = normalize_delegation_array(existing)
|
|
351
|
+
new_array = normalize_delegation_array(new_value)
|
|
352
|
+
|
|
353
|
+
merged[:delegates_to] = existing_array + new_array
|
|
337
354
|
when :parameters
|
|
338
355
|
merged[:parameters] = (merged[:parameters] || {}).merge(value || {})
|
|
339
356
|
when :headers
|
|
@@ -357,6 +374,35 @@ module SwarmSDK
|
|
|
357
374
|
merged
|
|
358
375
|
end
|
|
359
376
|
|
|
377
|
+
# Normalize delegation config to array of hashes format
|
|
378
|
+
#
|
|
379
|
+
# Converts various delegation formats to normalized array for merging:
|
|
380
|
+
# - Array of symbols: [:frontend, :backend] → [{agent: :frontend, tool_name: nil}, ...]
|
|
381
|
+
# - Hash: {frontend: "Custom"} → [{agent: :frontend, tool_name: "Custom"}, ...]
|
|
382
|
+
# - Array of hashes: [{agent: :frontend, tool_name: "Custom"}] → unchanged
|
|
383
|
+
#
|
|
384
|
+
# @param delegation_config [Array, Hash] Delegation configuration
|
|
385
|
+
# @return [Array<Hash>] Normalized array of {agent:, tool_name:} hashes
|
|
386
|
+
def normalize_delegation_array(delegation_config)
|
|
387
|
+
return [] if delegation_config.nil? || (delegation_config.respond_to?(:empty?) && delegation_config.empty?)
|
|
388
|
+
|
|
389
|
+
case delegation_config
|
|
390
|
+
when Array
|
|
391
|
+
delegation_config.map do |item|
|
|
392
|
+
case item
|
|
393
|
+
when Symbol, String
|
|
394
|
+
{ agent: item.to_sym, tool_name: nil }
|
|
395
|
+
when Hash
|
|
396
|
+
item.key?(:agent) ? item : item.map { |agent, tool_name| { agent: agent.to_sym, tool_name: tool_name } }
|
|
397
|
+
end
|
|
398
|
+
end.flatten
|
|
399
|
+
when Hash
|
|
400
|
+
delegation_config.map { |agent, tool_name| { agent: agent.to_sym, tool_name: tool_name } }
|
|
401
|
+
else
|
|
402
|
+
[]
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
|
|
360
406
|
# Apply all_agents defaults to an agent builder
|
|
361
407
|
#
|
|
362
408
|
# @param agent_builder [Agent::Builder] The agent builder to configure
|
|
@@ -90,7 +90,28 @@ module SwarmSDK
|
|
|
90
90
|
return [] unless agent_config
|
|
91
91
|
|
|
92
92
|
delegates = agent_config[:delegates_to] || []
|
|
93
|
-
|
|
93
|
+
|
|
94
|
+
# Handle both array and hash formats for delegates_to
|
|
95
|
+
case delegates
|
|
96
|
+
when Array
|
|
97
|
+
# Array of symbols: [:frontend, :backend]
|
|
98
|
+
# OR array of hashes: [{agent: :frontend, tool_name: "Custom"}]
|
|
99
|
+
delegates.map do |item|
|
|
100
|
+
case item
|
|
101
|
+
when Symbol, String
|
|
102
|
+
item.to_sym
|
|
103
|
+
when Hash
|
|
104
|
+
# Extract agent name from hash format
|
|
105
|
+
agent_name = item[:agent] || item["agent"]
|
|
106
|
+
agent_name&.to_sym
|
|
107
|
+
end
|
|
108
|
+
end.compact # Remove nils from malformed hashes
|
|
109
|
+
when Hash
|
|
110
|
+
# Hash format: {frontend: "Custom", backend: nil}
|
|
111
|
+
delegates.keys.map(&:to_sym)
|
|
112
|
+
else
|
|
113
|
+
[]
|
|
114
|
+
end
|
|
94
115
|
end
|
|
95
116
|
|
|
96
117
|
attr_reader :base_dir
|
|
@@ -168,7 +168,19 @@ module SwarmSDK
|
|
|
168
168
|
tools(*tool_names)
|
|
169
169
|
end
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
# Handle both array and hash formats for delegates_to
|
|
172
|
+
if config[:delegates_to]&.any?
|
|
173
|
+
delegation_config = config[:delegates_to]
|
|
174
|
+
if delegation_config.is_a?(Hash)
|
|
175
|
+
# Hash format: { frontend: "Custom", backend: nil }
|
|
176
|
+
# Pass as single hash argument, not splatted
|
|
177
|
+
delegates_to(delegation_config)
|
|
178
|
+
elsif delegation_config.is_a?(Array)
|
|
179
|
+
# Array format: [:frontend, :backend] OR [{agent: :frontend, tool_name: "Custom"}]
|
|
180
|
+
# Splat the array
|
|
181
|
+
delegates_to(*delegation_config)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
172
184
|
|
|
173
185
|
config[:mcp_servers]&.each do |server|
|
|
174
186
|
mcp_server(server[:name], **server.except(:name))
|
|
@@ -229,7 +241,16 @@ module SwarmSDK
|
|
|
229
241
|
tools_override = agent_config[:tools]
|
|
230
242
|
|
|
231
243
|
agent_cfg = agent(agent_name, reset_context: reset_ctx)
|
|
232
|
-
|
|
244
|
+
|
|
245
|
+
# Handle both array and hash formats for delegates_to
|
|
246
|
+
if delegates.any?
|
|
247
|
+
if delegates.is_a?(Hash)
|
|
248
|
+
agent_cfg = agent_cfg.delegates_to(delegates)
|
|
249
|
+
elsif delegates.is_a?(Array)
|
|
250
|
+
agent_cfg = agent_cfg.delegates_to(*delegates)
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
233
254
|
agent_cfg.tools(*tools_override) if tools_override
|
|
234
255
|
end
|
|
235
256
|
|
|
@@ -104,7 +104,28 @@ module SwarmSDK
|
|
|
104
104
|
return [] unless agent_config
|
|
105
105
|
|
|
106
106
|
delegates = agent_config[:delegates_to] || []
|
|
107
|
-
|
|
107
|
+
|
|
108
|
+
# Handle both array and hash formats for delegates_to
|
|
109
|
+
case delegates
|
|
110
|
+
when Array
|
|
111
|
+
# Array of symbols: [:frontend, :backend]
|
|
112
|
+
# OR array of hashes: [{agent: :frontend, tool_name: "Custom"}]
|
|
113
|
+
delegates.map do |item|
|
|
114
|
+
case item
|
|
115
|
+
when Symbol, String
|
|
116
|
+
item.to_sym
|
|
117
|
+
when Hash
|
|
118
|
+
# Extract agent name from hash format
|
|
119
|
+
agent_name = item[:agent] || item["agent"]
|
|
120
|
+
agent_name&.to_sym
|
|
121
|
+
end
|
|
122
|
+
end.compact # Remove nils from malformed hashes
|
|
123
|
+
when Hash
|
|
124
|
+
# Hash format: {frontend: "Custom", backend: nil}
|
|
125
|
+
delegates.keys.map(&:to_sym)
|
|
126
|
+
else
|
|
127
|
+
[]
|
|
128
|
+
end
|
|
108
129
|
end
|
|
109
130
|
|
|
110
131
|
# Convert configuration to Swarm or Workflow using appropriate builder
|
|
@@ -88,8 +88,9 @@ module SwarmSDK
|
|
|
88
88
|
# @param delegate_chat [Agent::Chat] The delegate's chat instance
|
|
89
89
|
# @param agent_name [Symbol] Name of the delegating agent
|
|
90
90
|
# @param delegating_chat [Agent::Chat, nil] The chat instance of the agent doing the delegating
|
|
91
|
+
# @param custom_tool_name [String, nil] Optional custom tool name (overrides auto-generated name)
|
|
91
92
|
# @return [Tools::Delegate] Delegation tool
|
|
92
|
-
def create_delegation_tool(name:, description:, delegate_chat:, agent_name:, delegating_chat: nil)
|
|
93
|
+
def create_delegation_tool(name:, description:, delegate_chat:, agent_name:, delegating_chat: nil, custom_tool_name: nil)
|
|
93
94
|
Tools::Delegate.new(
|
|
94
95
|
delegate_name: name,
|
|
95
96
|
delegate_description: description,
|
|
@@ -97,6 +98,7 @@ module SwarmSDK
|
|
|
97
98
|
agent_name: agent_name,
|
|
98
99
|
swarm: @swarm,
|
|
99
100
|
delegating_chat: delegating_chat,
|
|
101
|
+
custom_tool_name: custom_tool_name,
|
|
100
102
|
)
|
|
101
103
|
end
|
|
102
104
|
|
|
@@ -140,8 +142,8 @@ module SwarmSDK
|
|
|
140
142
|
|
|
141
143
|
# Sub-pass 2a: Create delegation instances for isolated agents
|
|
142
144
|
@swarm.agent_definitions.each do |delegator_name, delegator_def|
|
|
143
|
-
delegator_def.
|
|
144
|
-
delegate_base_name =
|
|
145
|
+
delegator_def.delegation_configs.each do |delegation_config|
|
|
146
|
+
delegate_base_name = delegation_config[:agent]
|
|
145
147
|
|
|
146
148
|
unless @swarm.agent_definitions.key?(delegate_base_name)
|
|
147
149
|
raise ConfigurationError,
|
|
@@ -177,11 +179,11 @@ module SwarmSDK
|
|
|
177
179
|
# Skip if delegator doesn't exist as primary (wasn't created in pass_1)
|
|
178
180
|
next unless delegator_chat
|
|
179
181
|
|
|
180
|
-
delegator_def.
|
|
182
|
+
delegator_def.delegation_configs.each do |delegation_config|
|
|
181
183
|
wire_delegation(
|
|
182
184
|
delegator_name: delegator_name,
|
|
183
185
|
delegator_chat: delegator_chat,
|
|
184
|
-
|
|
186
|
+
delegation_config: delegation_config,
|
|
185
187
|
tool_configurator: tool_configurator,
|
|
186
188
|
create_nested_instances: false,
|
|
187
189
|
)
|
|
@@ -195,11 +197,11 @@ module SwarmSDK
|
|
|
195
197
|
delegate_definition = @swarm.agent_definitions[base_name]
|
|
196
198
|
|
|
197
199
|
# Register delegation tools for THIS instance's delegates_to
|
|
198
|
-
delegate_definition.
|
|
200
|
+
delegate_definition.delegation_configs.each do |delegation_config|
|
|
199
201
|
wire_delegation(
|
|
200
202
|
delegator_name: instance_name.to_sym,
|
|
201
203
|
delegator_chat: delegation_chat,
|
|
202
|
-
|
|
204
|
+
delegation_config: delegation_config,
|
|
203
205
|
tool_configurator: tool_configurator,
|
|
204
206
|
create_nested_instances: true,
|
|
205
207
|
)
|
|
@@ -215,22 +217,24 @@ module SwarmSDK
|
|
|
215
217
|
#
|
|
216
218
|
# @param delegator_name [Symbol, String] Name of the agent doing the delegating
|
|
217
219
|
# @param delegator_chat [Agent::Chat] Chat instance of the delegator
|
|
218
|
-
# @param
|
|
220
|
+
# @param delegation_config [Hash] Delegation configuration with :agent and :tool_name keys
|
|
219
221
|
# @param tool_configurator [ToolConfigurator] Tool configuration helper
|
|
220
222
|
# @param create_nested_instances [Boolean] Whether to create new instances for nested delegation
|
|
221
223
|
# @return [void]
|
|
222
|
-
def wire_delegation(delegator_name:, delegator_chat:,
|
|
223
|
-
|
|
224
|
-
|
|
224
|
+
def wire_delegation(delegator_name:, delegator_chat:, delegation_config:, tool_configurator:, create_nested_instances:)
|
|
225
|
+
delegate_name_sym = delegation_config[:agent]
|
|
226
|
+
delegate_name_str = delegate_name_sym.to_s
|
|
227
|
+
custom_tool_name = delegation_config[:tool_name]
|
|
225
228
|
|
|
226
229
|
# Check if target is a registered swarm
|
|
227
230
|
if @swarm.swarm_registry&.registered?(delegate_name_str)
|
|
228
|
-
wire_swarm_delegation(delegator_name, delegator_chat, delegate_name_str)
|
|
231
|
+
wire_swarm_delegation(delegator_name, delegator_chat, delegate_name_str, custom_tool_name)
|
|
229
232
|
elsif @swarm.agent_definitions.key?(delegate_name_sym)
|
|
230
233
|
wire_agent_delegation(
|
|
231
234
|
delegator_name: delegator_name,
|
|
232
235
|
delegator_chat: delegator_chat,
|
|
233
236
|
delegate_name_sym: delegate_name_sym,
|
|
237
|
+
custom_tool_name: custom_tool_name,
|
|
234
238
|
tool_configurator: tool_configurator,
|
|
235
239
|
create_nested_instances: create_nested_instances,
|
|
236
240
|
)
|
|
@@ -245,14 +249,16 @@ module SwarmSDK
|
|
|
245
249
|
# @param delegator_name [Symbol, String] Name of the delegating agent
|
|
246
250
|
# @param delegator_chat [Agent::Chat] Chat instance of the delegator
|
|
247
251
|
# @param swarm_name [String] Name of the registered swarm
|
|
252
|
+
# @param custom_tool_name [String, nil] Optional custom tool name
|
|
248
253
|
# @return [void]
|
|
249
|
-
def wire_swarm_delegation(delegator_name, delegator_chat, swarm_name)
|
|
254
|
+
def wire_swarm_delegation(delegator_name, delegator_chat, swarm_name, custom_tool_name)
|
|
250
255
|
tool = create_delegation_tool(
|
|
251
256
|
name: swarm_name,
|
|
252
257
|
description: "External swarm: #{swarm_name}",
|
|
253
258
|
delegate_chat: nil, # Swarm delegation - no direct chat
|
|
254
259
|
agent_name: delegator_name,
|
|
255
260
|
delegating_chat: delegator_chat,
|
|
261
|
+
custom_tool_name: custom_tool_name,
|
|
256
262
|
)
|
|
257
263
|
|
|
258
264
|
delegator_chat.add_tool(tool)
|
|
@@ -266,10 +272,11 @@ module SwarmSDK
|
|
|
266
272
|
# @param delegator_name [Symbol, String] Name of the delegating agent
|
|
267
273
|
# @param delegator_chat [Agent::Chat] Chat instance of the delegator
|
|
268
274
|
# @param delegate_name_sym [Symbol] Name of the delegate agent
|
|
275
|
+
# @param custom_tool_name [String, nil] Optional custom tool name
|
|
269
276
|
# @param tool_configurator [ToolConfigurator] Tool configuration helper
|
|
270
277
|
# @param create_nested_instances [Boolean] Whether to create new instances if not found
|
|
271
278
|
# @return [void]
|
|
272
|
-
def wire_agent_delegation(delegator_name:, delegator_chat:, delegate_name_sym:, tool_configurator:, create_nested_instances:)
|
|
279
|
+
def wire_agent_delegation(delegator_name:, delegator_chat:, delegate_name_sym:, custom_tool_name:, tool_configurator:, create_nested_instances:)
|
|
273
280
|
delegate_definition = @swarm.agent_definitions[delegate_name_sym]
|
|
274
281
|
|
|
275
282
|
# Determine which chat instance to use
|
|
@@ -301,6 +308,7 @@ module SwarmSDK
|
|
|
301
308
|
delegate_chat: target_chat,
|
|
302
309
|
agent_name: delegator_name,
|
|
303
310
|
delegating_chat: delegator_chat,
|
|
311
|
+
custom_tool_name: custom_tool_name,
|
|
304
312
|
)
|
|
305
313
|
|
|
306
314
|
delegator_chat.add_tool(tool)
|
|
@@ -326,8 +334,10 @@ module SwarmSDK
|
|
|
326
334
|
|
|
327
335
|
# Setup context for an agent (primary or delegation instance)
|
|
328
336
|
def setup_agent_context(agent_name, agent_definition, chat, is_delegation: false)
|
|
329
|
-
|
|
330
|
-
|
|
337
|
+
# Generate actual tool names (custom or auto-generated) for context tracking
|
|
338
|
+
delegate_tool_names = agent_definition.delegation_configs.map do |delegation_config|
|
|
339
|
+
# Use custom name if provided, otherwise auto-generate
|
|
340
|
+
delegation_config[:tool_name] || Tools::Delegate.tool_name_for(delegation_config[:agent])
|
|
331
341
|
end
|
|
332
342
|
|
|
333
343
|
context = Agent::Context.new(
|
|
@@ -36,13 +36,15 @@ module SwarmSDK
|
|
|
36
36
|
# @param agent_name [Symbol, String] Name of the agent using this tool
|
|
37
37
|
# @param swarm [Swarm] The swarm instance (provides hook_registry, delegation_call_stack, swarm_registry)
|
|
38
38
|
# @param delegating_chat [Agent::Chat, nil] The chat instance of the agent doing the delegating (for accessing hooks)
|
|
39
|
+
# @param custom_tool_name [String, nil] Optional custom tool name (overrides auto-generated name)
|
|
39
40
|
def initialize(
|
|
40
41
|
delegate_name:,
|
|
41
42
|
delegate_description:,
|
|
42
43
|
delegate_chat:,
|
|
43
44
|
agent_name:,
|
|
44
45
|
swarm:,
|
|
45
|
-
delegating_chat: nil
|
|
46
|
+
delegating_chat: nil,
|
|
47
|
+
custom_tool_name: nil
|
|
46
48
|
)
|
|
47
49
|
super()
|
|
48
50
|
|
|
@@ -53,8 +55,8 @@ module SwarmSDK
|
|
|
53
55
|
@swarm = swarm
|
|
54
56
|
@delegating_chat = delegating_chat
|
|
55
57
|
|
|
56
|
-
#
|
|
57
|
-
@tool_name = self.class.tool_name_for(delegate_name)
|
|
58
|
+
# Use custom tool name if provided, otherwise generate using canonical method
|
|
59
|
+
@tool_name = custom_tool_name || self.class.tool_name_for(delegate_name)
|
|
58
60
|
@delegate_target = delegate_name.to_s
|
|
59
61
|
end
|
|
60
62
|
|
data/lib/swarm_sdk/version.rb
CHANGED
|
@@ -37,10 +37,26 @@ module SwarmSDK
|
|
|
37
37
|
|
|
38
38
|
# Set delegation targets for this agent
|
|
39
39
|
#
|
|
40
|
-
#
|
|
40
|
+
# Supports multiple formats for flexibility:
|
|
41
|
+
# - Array: delegates_to(:frontend, :backend)
|
|
42
|
+
# - Hash: delegates_to(frontend: "AskFrontend", backend: "GetBackend")
|
|
43
|
+
#
|
|
44
|
+
# @param agent_names_and_options [Array<Symbol, Hash>] Names and/or hash with custom tool names
|
|
41
45
|
# @return [self] For method chaining
|
|
42
|
-
def delegates_to(*
|
|
43
|
-
|
|
46
|
+
def delegates_to(*agent_names_and_options)
|
|
47
|
+
# Parse delegation configs (same logic as Agent::Builder)
|
|
48
|
+
@delegates_to = []
|
|
49
|
+
agent_names_and_options.each do |item|
|
|
50
|
+
case item
|
|
51
|
+
when Symbol, String
|
|
52
|
+
@delegates_to << { agent: item.to_sym, tool_name: nil }
|
|
53
|
+
when Hash
|
|
54
|
+
item.each do |agent, tool_name|
|
|
55
|
+
@delegates_to << { agent: agent.to_sym, tool_name: tool_name }
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
44
60
|
update_registration
|
|
45
61
|
self
|
|
46
62
|
end
|
|
@@ -183,10 +183,45 @@ module SwarmSDK
|
|
|
183
183
|
@nodes.values.flat_map do |node_builder|
|
|
184
184
|
# Collect both direct agents and their delegation targets
|
|
185
185
|
node_builder.agent_configs.flat_map do |config|
|
|
186
|
-
|
|
186
|
+
# Extract delegate agent names (handles array and hash formats)
|
|
187
|
+
delegate_names = extract_delegate_agent_names(config[:delegates_to] || [])
|
|
188
|
+
[config[:agent]] + delegate_names
|
|
187
189
|
end
|
|
188
190
|
end.uniq
|
|
189
191
|
end
|
|
192
|
+
|
|
193
|
+
# Extract agent names from delegation configuration
|
|
194
|
+
#
|
|
195
|
+
# Handles multiple formats:
|
|
196
|
+
# - Array of symbols: [:frontend, :backend]
|
|
197
|
+
# - Hash: {frontend: "Custom", backend: nil}
|
|
198
|
+
# - Array of hashes: [{agent: :frontend, tool_name: "Custom"}]
|
|
199
|
+
#
|
|
200
|
+
# @param delegation_config [Array, Hash, nil] Delegation configuration
|
|
201
|
+
# @return [Array<Symbol>] Array of agent name symbols
|
|
202
|
+
def extract_delegate_agent_names(delegation_config)
|
|
203
|
+
return [] if delegation_config.nil?
|
|
204
|
+
return [] if delegation_config.respond_to?(:empty?) && delegation_config.empty?
|
|
205
|
+
|
|
206
|
+
case delegation_config
|
|
207
|
+
when Array
|
|
208
|
+
delegation_config.map do |item|
|
|
209
|
+
case item
|
|
210
|
+
when Symbol, String
|
|
211
|
+
item.to_sym
|
|
212
|
+
when Hash
|
|
213
|
+
# Extract agent name from normalized format
|
|
214
|
+
agent_name = item[:agent] || item["agent"]
|
|
215
|
+
agent_name&.to_sym
|
|
216
|
+
end
|
|
217
|
+
end.compact # Remove nils from malformed hashes
|
|
218
|
+
when Hash
|
|
219
|
+
# Hash format: keys are agent names
|
|
220
|
+
delegation_config.keys.map(&:to_sym)
|
|
221
|
+
else
|
|
222
|
+
[]
|
|
223
|
+
end
|
|
224
|
+
end
|
|
190
225
|
end
|
|
191
226
|
end
|
|
192
227
|
end
|
|
@@ -541,7 +541,10 @@ module SwarmSDK
|
|
|
541
541
|
# @return [void]
|
|
542
542
|
def auto_add_delegate_agents
|
|
543
543
|
# Collect all agents mentioned in delegates_to
|
|
544
|
-
|
|
544
|
+
# Extract agent names from all delegation configs (handles hash and array formats)
|
|
545
|
+
all_delegates = @agent_configs.flat_map do |ac|
|
|
546
|
+
extract_delegate_agent_names(ac[:delegates_to] || [])
|
|
547
|
+
end.uniq
|
|
545
548
|
|
|
546
549
|
# Find delegates that aren't explicitly declared
|
|
547
550
|
declared_agents = @agent_configs.map { |ac| ac[:agent] }
|
|
@@ -552,6 +555,39 @@ module SwarmSDK
|
|
|
552
555
|
@agent_configs << { agent: delegate_name, delegates_to: [], reset_context: true }
|
|
553
556
|
end
|
|
554
557
|
end
|
|
558
|
+
|
|
559
|
+
# Extract agent names from delegation configuration
|
|
560
|
+
#
|
|
561
|
+
# Handles multiple formats:
|
|
562
|
+
# - Array of symbols: [:frontend, :backend]
|
|
563
|
+
# - Hash: {frontend: "Custom", backend: nil}
|
|
564
|
+
# - Array of hashes: [{agent: :frontend, tool_name: "Custom"}]
|
|
565
|
+
#
|
|
566
|
+
# @param delegation_config [Array, Hash, nil] Delegation configuration
|
|
567
|
+
# @return [Array<Symbol>] Array of agent name symbols
|
|
568
|
+
def extract_delegate_agent_names(delegation_config)
|
|
569
|
+
return [] if delegation_config.nil?
|
|
570
|
+
return [] if delegation_config.respond_to?(:empty?) && delegation_config.empty?
|
|
571
|
+
|
|
572
|
+
case delegation_config
|
|
573
|
+
when Array
|
|
574
|
+
delegation_config.map do |item|
|
|
575
|
+
case item
|
|
576
|
+
when Symbol, String
|
|
577
|
+
item.to_sym
|
|
578
|
+
when Hash
|
|
579
|
+
# Extract agent name from normalized format
|
|
580
|
+
agent_name = item[:agent] || item["agent"]
|
|
581
|
+
agent_name&.to_sym
|
|
582
|
+
end
|
|
583
|
+
end.compact # Remove nils from malformed hashes
|
|
584
|
+
when Hash
|
|
585
|
+
# Hash format: keys are agent names
|
|
586
|
+
delegation_config.keys.map(&:to_sym)
|
|
587
|
+
else
|
|
588
|
+
[]
|
|
589
|
+
end
|
|
590
|
+
end
|
|
555
591
|
end
|
|
556
592
|
end
|
|
557
593
|
end
|
data/lib/swarm_sdk/workflow.rb
CHANGED
|
@@ -377,7 +377,9 @@ module SwarmSDK
|
|
|
377
377
|
end
|
|
378
378
|
|
|
379
379
|
# Validate delegation targets exist
|
|
380
|
-
config
|
|
380
|
+
# Extract agent names from delegation config (supports both array and hash formats)
|
|
381
|
+
delegate_names = extract_delegate_agent_names(config[:delegates_to])
|
|
382
|
+
delegate_names.each do |delegate|
|
|
381
383
|
unless @agent_definitions.key?(delegate)
|
|
382
384
|
raise ConfigurationError,
|
|
383
385
|
"Node '#{node_name}' agent '#{agent_name}' delegates to undefined agent '#{delegate}'"
|
|
@@ -550,5 +552,38 @@ module SwarmSDK
|
|
|
550
552
|
"Invalid scratchpad mode: #{value.inspect}. Use :enabled, :per_node, or :disabled"
|
|
551
553
|
end
|
|
552
554
|
end
|
|
555
|
+
|
|
556
|
+
# Extract agent names from delegation configuration
|
|
557
|
+
#
|
|
558
|
+
# Handles multiple formats:
|
|
559
|
+
# - Array of symbols: [:frontend, :backend]
|
|
560
|
+
# - Hash: {frontend: "Custom", backend: nil}
|
|
561
|
+
# - Array of hashes: [{agent: :frontend, tool_name: "Custom"}]
|
|
562
|
+
#
|
|
563
|
+
# @param delegation_config [Array, Hash, nil] Delegation configuration
|
|
564
|
+
# @return [Array<Symbol>] Array of agent name symbols
|
|
565
|
+
def extract_delegate_agent_names(delegation_config)
|
|
566
|
+
return [] if delegation_config.nil?
|
|
567
|
+
return [] if delegation_config.respond_to?(:empty?) && delegation_config.empty?
|
|
568
|
+
|
|
569
|
+
case delegation_config
|
|
570
|
+
when Array
|
|
571
|
+
delegation_config.map do |item|
|
|
572
|
+
case item
|
|
573
|
+
when Symbol, String
|
|
574
|
+
item.to_sym
|
|
575
|
+
when Hash
|
|
576
|
+
# Extract agent name from normalized format
|
|
577
|
+
agent_name = item[:agent] || item["agent"]
|
|
578
|
+
agent_name&.to_sym
|
|
579
|
+
end
|
|
580
|
+
end.compact # Remove nils from malformed hashes
|
|
581
|
+
when Hash
|
|
582
|
+
# Hash format: keys are agent names
|
|
583
|
+
delegation_config.keys.map(&:to_sym)
|
|
584
|
+
else
|
|
585
|
+
[]
|
|
586
|
+
end
|
|
587
|
+
end
|
|
553
588
|
end
|
|
554
589
|
end
|