swarm_sdk 2.7.9 → 2.7.11

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.
@@ -0,0 +1,372 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SwarmSDK
4
+ class Swarm
5
+ # Lazy loader for delegation agent chats
6
+ #
7
+ # Instead of creating delegation instances eagerly at swarm initialization,
8
+ # this class defers creation until the first delegation call. This improves
9
+ # initialization performance for swarms where not all agents are used.
10
+ #
11
+ # Thread-safe via Mutex - safe for concurrent access.
12
+ #
13
+ # @example
14
+ # lazy_chat = LazyDelegateChat.new(
15
+ # instance_name: "backend@frontend",
16
+ # base_name: :backend,
17
+ # agent_definition: backend_def,
18
+ # swarm: swarm
19
+ # )
20
+ #
21
+ # # Later, when delegation is first called:
22
+ # chat = lazy_chat.chat # Creates agent on first access
23
+ # chat.ask("Do something")
24
+ class LazyDelegateChat
25
+ attr_reader :instance_name, :base_name, :agent_definition
26
+
27
+ # Initialize a lazy delegate chat wrapper
28
+ #
29
+ # @param instance_name [String] Unique instance name ("base@delegator")
30
+ # @param base_name [Symbol] Base agent name (for definition lookup)
31
+ # @param agent_definition [Agent::Definition] Agent definition
32
+ # @param swarm [Swarm] Parent swarm reference
33
+ def initialize(instance_name:, base_name:, agent_definition:, swarm:)
34
+ @instance_name = instance_name
35
+ @base_name = base_name
36
+ @agent_definition = agent_definition
37
+ @swarm = swarm
38
+ @chat = nil
39
+ @mutex = Mutex.new
40
+ @initialized = false
41
+ end
42
+
43
+ # Get or create the agent chat instance
44
+ #
45
+ # On first call, creates the agent chat and runs initialization.
46
+ # Subsequent calls return the cached instance.
47
+ #
48
+ # @return [Agent::Chat] The initialized chat instance
49
+ def chat
50
+ return @chat if @initialized
51
+
52
+ @mutex.synchronize do
53
+ return @chat if @initialized
54
+
55
+ @chat = initialize_chat
56
+ @initialized = true
57
+ @chat
58
+ end
59
+ end
60
+
61
+ # Check if the agent has been initialized
62
+ #
63
+ # @return [Boolean] True if chat has been created
64
+ def initialized?
65
+ @mutex.synchronize { @initialized }
66
+ end
67
+
68
+ private
69
+
70
+ # Create and initialize the agent chat
71
+ #
72
+ # This mirrors the initialization done in AgentInitializer passes 1-6
73
+ # but for a single lazy delegate.
74
+ #
75
+ # @return [Agent::Chat] Fully initialized chat instance
76
+ def initialize_chat
77
+ emit_lazy_init_start
78
+
79
+ # Create tool configurator
80
+ tool_configurator = ToolConfigurator.new(
81
+ @swarm,
82
+ @swarm.scratchpad_storage,
83
+ @swarm.plugin_storages,
84
+ )
85
+
86
+ # Create the agent chat (mirrors AgentInitializer#create_agent_chat_for_delegation)
87
+ chat = create_delegation_chat(tool_configurator)
88
+
89
+ # Store in delegation_instances (so other code can find it)
90
+ @swarm.delegation_instances[@instance_name] = chat
91
+
92
+ # Wire delegation tools for this instance (nested delegation support)
93
+ wire_delegation_tools(chat, tool_configurator)
94
+
95
+ # Setup context
96
+ setup_context(chat)
97
+
98
+ # Configure hooks
99
+ configure_hooks(chat)
100
+
101
+ # Apply YAML hooks if present
102
+ apply_yaml_hooks(chat)
103
+
104
+ # Activate tools
105
+ chat.activate_tools_for_prompt
106
+
107
+ # Notify plugins
108
+ notify_plugins(chat, tool_configurator)
109
+
110
+ emit_lazy_init_complete
111
+
112
+ chat
113
+ end
114
+
115
+ # Create the delegation chat instance
116
+ #
117
+ # @param tool_configurator [ToolConfigurator] Tool configuration helper
118
+ # @return [Agent::Chat] Newly created chat instance
119
+ def create_delegation_chat(tool_configurator)
120
+ chat = Agent::Chat.new(
121
+ definition: @agent_definition.to_h,
122
+ agent_name: @instance_name.to_sym,
123
+ global_semaphore: @swarm.global_semaphore,
124
+ )
125
+
126
+ # Set provider agent name for logging
127
+ chat.provider.agent_name = @instance_name if chat.provider.respond_to?(:agent_name=)
128
+
129
+ # Register all tools (built-in, permissions, etc.)
130
+ tool_configurator.register_all_tools(
131
+ chat: chat,
132
+ agent_name: @instance_name.to_sym,
133
+ agent_definition: @agent_definition,
134
+ )
135
+
136
+ # Register MCP servers if configured
137
+ if @agent_definition.mcp_servers.any?
138
+ mcp_configurator = McpConfigurator.new(@swarm)
139
+ mcp_configurator.register_mcp_servers(
140
+ chat,
141
+ @agent_definition.mcp_servers,
142
+ agent_name: @instance_name,
143
+ )
144
+ end
145
+
146
+ # Setup tool activation dependencies
147
+ chat.setup_tool_activation(
148
+ tool_configurator: tool_configurator,
149
+ agent_definition: @agent_definition,
150
+ )
151
+
152
+ chat
153
+ end
154
+
155
+ # Wire delegation tools for this instance (nested delegation support)
156
+ #
157
+ # If this agent delegates to other agents, create those tools.
158
+ # The delegate targets may themselves be lazy.
159
+ #
160
+ # @param chat [Agent::Chat] The chat instance
161
+ # @param tool_configurator [ToolConfigurator] Tool configuration helper
162
+ # @return [void]
163
+ def wire_delegation_tools(chat, tool_configurator)
164
+ @agent_definition.delegation_configs.each do |delegation_config|
165
+ delegate_name_sym = delegation_config[:agent]
166
+ delegate_name_str = delegate_name_sym.to_s
167
+ custom_tool_name = delegation_config[:tool_name]
168
+ preserve_context = delegation_config.fetch(:preserve_context, true)
169
+
170
+ # Check if target is a registered swarm
171
+ if @swarm.swarm_registry&.registered?(delegate_name_str)
172
+ wire_swarm_delegation(chat, delegate_name_str, custom_tool_name, preserve_context)
173
+ elsif @swarm.agent_definitions.key?(delegate_name_sym)
174
+ wire_agent_delegation(chat, delegate_name_sym, custom_tool_name, tool_configurator, preserve_context)
175
+ else
176
+ raise ConfigurationError,
177
+ "Agent '#{@instance_name}' delegates to unknown target '#{delegate_name_str}'"
178
+ end
179
+ end
180
+ end
181
+
182
+ # Wire delegation to an external swarm
183
+ #
184
+ # @param chat [Agent::Chat] The delegating chat
185
+ # @param swarm_name [String] Name of the registered swarm
186
+ # @param custom_tool_name [String, nil] Optional custom tool name
187
+ # @param preserve_context [Boolean] Whether to preserve context
188
+ # @return [void]
189
+ def wire_swarm_delegation(chat, swarm_name, custom_tool_name, preserve_context)
190
+ tool = Tools::Delegate.new(
191
+ delegate_name: swarm_name,
192
+ delegate_description: "External swarm: #{swarm_name}",
193
+ delegate_chat: nil,
194
+ agent_name: @instance_name,
195
+ swarm: @swarm,
196
+ delegating_chat: chat,
197
+ custom_tool_name: custom_tool_name,
198
+ preserve_context: preserve_context,
199
+ )
200
+
201
+ chat.tool_registry.register(
202
+ tool,
203
+ source: :delegation,
204
+ metadata: { delegate_name: swarm_name, delegation_type: :swarm, preserve_context: preserve_context },
205
+ )
206
+ end
207
+
208
+ # Wire delegation to a local agent
209
+ #
210
+ # For lazy-loaded agents, creates a LazyDelegateChat wrapper.
211
+ # For shared agents, uses the primary instance.
212
+ #
213
+ # @param chat [Agent::Chat] The delegating chat
214
+ # @param delegate_name_sym [Symbol] Name of the delegate agent
215
+ # @param custom_tool_name [String, nil] Optional custom tool name
216
+ # @param tool_configurator [ToolConfigurator] Tool configuration helper
217
+ # @param preserve_context [Boolean] Whether to preserve context
218
+ # @return [void]
219
+ def wire_agent_delegation(chat, delegate_name_sym, custom_tool_name, tool_configurator, preserve_context)
220
+ delegate_definition = @swarm.agent_definitions[delegate_name_sym]
221
+
222
+ # Determine which chat instance to use
223
+ target_chat = if delegate_definition.shared_across_delegations
224
+ # Shared mode: use primary agent
225
+ @swarm.agents[delegate_name_sym]
226
+ else
227
+ # Isolated mode: create nested lazy loader or get existing instance
228
+ nested_instance_name = "#{delegate_name_sym}@#{@instance_name}"
229
+
230
+ # Check if already exists (might have been created by another path)
231
+ existing = @swarm.delegation_instances[nested_instance_name]
232
+ if existing
233
+ existing
234
+ else
235
+ # Create lazy loader for nested delegation
236
+ LazyDelegateChat.new(
237
+ instance_name: nested_instance_name,
238
+ base_name: delegate_name_sym,
239
+ agent_definition: delegate_definition,
240
+ swarm: @swarm,
241
+ )
242
+ end
243
+ end
244
+
245
+ # Create delegation tool pointing to chosen instance
246
+ tool = Tools::Delegate.new(
247
+ delegate_name: delegate_name_sym.to_s,
248
+ delegate_description: delegate_definition.description,
249
+ delegate_chat: target_chat,
250
+ agent_name: @instance_name,
251
+ swarm: @swarm,
252
+ delegating_chat: chat,
253
+ custom_tool_name: custom_tool_name,
254
+ preserve_context: preserve_context,
255
+ )
256
+
257
+ chat.tool_registry.register(
258
+ tool,
259
+ source: :delegation,
260
+ metadata: {
261
+ delegate_name: delegate_name_sym,
262
+ delegation_mode: delegate_definition.shared_across_delegations ? :shared : :isolated,
263
+ preserve_context: preserve_context,
264
+ },
265
+ )
266
+ end
267
+
268
+ # Setup agent context
269
+ #
270
+ # @param chat [Agent::Chat] The chat instance
271
+ # @return [void]
272
+ def setup_context(chat)
273
+ delegate_tool_names = @agent_definition.delegation_configs.map do |delegation_config|
274
+ delegation_config[:tool_name] || Tools::Delegate.tool_name_for(delegation_config[:agent])
275
+ end
276
+
277
+ context = Agent::Context.new(
278
+ name: @instance_name.to_sym,
279
+ swarm_id: @swarm.swarm_id,
280
+ parent_swarm_id: @swarm.parent_swarm_id,
281
+ delegation_tools: delegate_tool_names,
282
+ metadata: { is_delegation_instance: true },
283
+ )
284
+
285
+ chat.setup_context(context) if chat.respond_to?(:setup_context)
286
+
287
+ # Configure logging if enabled
288
+ return unless LogStream.emitter
289
+
290
+ chat.setup_logging if chat.respond_to?(:setup_logging)
291
+ end
292
+
293
+ # Configure hooks for the agent
294
+ #
295
+ # @param chat [Agent::Chat] The chat instance
296
+ # @return [void]
297
+ def configure_hooks(chat)
298
+ return unless chat.respond_to?(:setup_hooks)
299
+
300
+ chat.setup_hooks(
301
+ registry: @swarm.hook_registry,
302
+ agent_definition: @agent_definition,
303
+ swarm: @swarm,
304
+ )
305
+ end
306
+
307
+ # Apply YAML hooks if present
308
+ #
309
+ # @param chat [Agent::Chat] The chat instance
310
+ # @return [void]
311
+ def apply_yaml_hooks(chat)
312
+ return unless @swarm.config_for_hooks
313
+
314
+ agent_config = @swarm.config_for_hooks.agents[@base_name]
315
+ return unless agent_config
316
+
317
+ hooks = agent_config.is_a?(Hash) ? agent_config[:hooks] : agent_config.hooks
318
+ return unless hooks&.any?
319
+
320
+ Hooks::Adapter.apply_agent_hooks(chat, @instance_name.to_sym, hooks, @swarm.name)
321
+ end
322
+
323
+ # Notify plugins that agent was initialized
324
+ #
325
+ # @param chat [Agent::Chat] The chat instance
326
+ # @param tool_configurator [ToolConfigurator] Tool configuration helper
327
+ # @return [void]
328
+ def notify_plugins(chat, tool_configurator)
329
+ PluginRegistry.all.each do |plugin|
330
+ plugin_storages = @swarm.plugin_storages[plugin.name] || {}
331
+ storage = plugin_storages[@base_name]
332
+
333
+ context = {
334
+ storage: storage,
335
+ agent_definition: @agent_definition,
336
+ tool_configurator: tool_configurator,
337
+ }
338
+
339
+ plugin.on_agent_initialized(
340
+ agent_name: @instance_name.to_sym,
341
+ agent: chat,
342
+ context: context,
343
+ )
344
+ end
345
+ end
346
+
347
+ # Emit lazy initialization start event
348
+ #
349
+ # @return [void]
350
+ def emit_lazy_init_start
351
+ LogStream.emit(
352
+ type: "agent_lazy_initialization_start",
353
+ instance_name: @instance_name,
354
+ base_name: @base_name,
355
+ timestamp: Time.now.utc.iso8601,
356
+ )
357
+ end
358
+
359
+ # Emit lazy initialization complete event
360
+ #
361
+ # @return [void]
362
+ def emit_lazy_init_complete
363
+ LogStream.emit(
364
+ type: "agent_lazy_initialization_complete",
365
+ instance_name: @instance_name,
366
+ base_name: @base_name,
367
+ timestamp: Time.now.utc.iso8601,
368
+ )
369
+ end
370
+ end
371
+ end
372
+ end
@@ -581,6 +581,61 @@ module SwarmSDK
581
581
  # @return [void]
582
582
  attr_writer :swarm_registry
583
583
 
584
+ # Force initialization of all lazy delegation instances
585
+ #
586
+ # By default, delegation instances for isolated delegates are lazy-loaded
587
+ # (created on first delegation call). This method forces immediate initialization
588
+ # of all lazy delegates, which can be useful for:
589
+ # - Testing: Verify delegation instance properties without mocking
590
+ # - Preloading: Initialize all agents upfront for predictable timing
591
+ #
592
+ # This method is recursive - it will initialize nested lazy delegates until
593
+ # all delegation chains are fully initialized.
594
+ #
595
+ # @return [void]
596
+ #
597
+ # @example Force-initialize all delegates for testing
598
+ # swarm.initialize_agents
599
+ # swarm.initialize_lazy_delegates!
600
+ # assert swarm.delegation_instances.key?("backend@lead")
601
+ def initialize_lazy_delegates!
602
+ initialize_agents unless @agents_initialized
603
+
604
+ # Keep initializing until no more lazy delegates are found
605
+ # This handles nested delegation chains (A -> B -> C)
606
+ loop do
607
+ initialized_any = false
608
+
609
+ # Find all delegation tools with lazy loaders in primary agents
610
+ @agents.each_value do |chat|
611
+ chat.tools.each_value do |tool|
612
+ next unless tool.is_a?(Tools::Delegate)
613
+ next unless tool.lazy? && !tool.initialized?
614
+
615
+ tool.initialize_delegate!
616
+ initialized_any = true
617
+ end
618
+ end
619
+
620
+ # Also check delegation instances for their own lazy delegates (nested)
621
+ @delegation_instances.values.each do |chat|
622
+ # Skip if this is still a LazyDelegateChat (shouldn't happen after above loop)
623
+ next if chat.is_a?(Swarm::LazyDelegateChat)
624
+
625
+ chat.tools.each_value do |tool|
626
+ next unless tool.is_a?(Tools::Delegate)
627
+ next unless tool.lazy? && !tool.initialized?
628
+
629
+ tool.initialize_delegate!
630
+ initialized_any = true
631
+ end
632
+ end
633
+
634
+ # Exit loop when no more lazy delegates were initialized
635
+ break unless initialized_any
636
+ end
637
+ end
638
+
584
639
  # --- Internal API (for Executor use only) ---
585
640
  # Hook triggers for swarm lifecycle events are provided by HookTriggers module
586
641
 
@@ -37,7 +37,7 @@ module SwarmSDK
37
37
  end
38
38
  end
39
39
 
40
- attr_reader :delegate_name, :delegate_target, :tool_name, :preserve_context
40
+ attr_reader :delegate_name, :delegate_target, :tool_name, :preserve_context, :delegate_chat
41
41
 
42
42
  # Initialize a delegation tool
43
43
  #
@@ -94,6 +94,32 @@ module SwarmSDK
94
94
  @tool_name
95
95
  end
96
96
 
97
+ # Check if this delegate uses lazy loading
98
+ #
99
+ # @return [Boolean] True if delegate is lazy-loaded
100
+ def lazy?
101
+ @delegate_chat.is_a?(Swarm::LazyDelegateChat)
102
+ end
103
+
104
+ # Check if this delegate has been initialized
105
+ #
106
+ # @return [Boolean] True if delegate chat is ready (either eager or lazy-initialized)
107
+ def initialized?
108
+ return true unless lazy?
109
+
110
+ @delegate_chat.initialized?
111
+ end
112
+
113
+ # Force initialization of lazy delegate
114
+ #
115
+ # If the delegate is lazy-loaded, this will trigger immediate initialization.
116
+ # For eager delegates, this is a no-op.
117
+ #
118
+ # @return [Agent::Chat] The resolved chat instance
119
+ def initialize_delegate!
120
+ resolve_delegate_chat
121
+ end
122
+
97
123
  # Execute delegation with pre/post hooks
98
124
  #
99
125
  # @param message [String] Message to send to the agent
@@ -226,6 +252,9 @@ module SwarmSDK
226
252
 
227
253
  # Delegate to an agent
228
254
  #
255
+ # Handles both eager Agent::Chat instances and lazy-loaded delegates.
256
+ # LazyDelegateChat instances are initialized on first access.
257
+ #
229
258
  # @param message [String] Message to send to the agent
230
259
  # @param call_stack [Array] Delegation call stack for circular dependency detection
231
260
  # @param reset_context [Boolean] Whether to reset the agent's conversation history before delegation
@@ -234,11 +263,14 @@ module SwarmSDK
234
263
  # Push delegate target onto call stack to track delegation chain
235
264
  call_stack.push(@delegate_target)
236
265
  begin
266
+ # Resolve the chat instance (handles lazy loading)
267
+ chat = resolve_delegate_chat
268
+
237
269
  # Clear conversation if reset_context is true OR if preserve_context is false
238
270
  # reset_context takes precedence as it's an explicit request
239
- @delegate_chat.clear_conversation if reset_context || !@preserve_context
271
+ chat.clear_conversation if reset_context || !@preserve_context
240
272
 
241
- response = @delegate_chat.ask(message, source: "delegation")
273
+ response = chat.ask(message, source: "delegation")
242
274
  response.content
243
275
  ensure
244
276
  # Always pop from stack, even if delegation fails
@@ -246,6 +278,20 @@ module SwarmSDK
246
278
  end
247
279
  end
248
280
 
281
+ # Resolve the delegate chat instance
282
+ #
283
+ # If the delegate is a LazyDelegateChat, initializes it on first access.
284
+ # Otherwise, returns the chat directly.
285
+ #
286
+ # @return [Agent::Chat] The resolved chat instance
287
+ def resolve_delegate_chat
288
+ if @delegate_chat.is_a?(Swarm::LazyDelegateChat)
289
+ @delegate_chat.chat
290
+ else
291
+ @delegate_chat
292
+ end
293
+ end
294
+
249
295
  # Delegate to a registered swarm
250
296
  #
251
297
  # @param message [String] Message to send to the swarm
@@ -263,8 +309,8 @@ module SwarmSDK
263
309
  # Reset swarm if reset_context is true
264
310
  swarm_registry.reset(@delegate_target) if reset_context
265
311
 
266
- # Execute sub-swarm's lead agent
267
- lead_agent = subswarm.agents[subswarm.lead_agent]
312
+ # Execute sub-swarm's lead agent (uses agent() to trigger lazy initialization)
313
+ lead_agent = subswarm.agent(subswarm.lead_agent)
268
314
  response = lead_agent.ask(message, source: "delegation")
269
315
  result = response.content
270
316
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SwarmSDK
4
- VERSION = "2.7.9"
4
+ VERSION = "2.7.11"
5
5
  end
data/lib/swarm_sdk.rb CHANGED
@@ -18,14 +18,32 @@ require "async/semaphore"
18
18
  require "ruby_llm"
19
19
  require "ruby_llm/mcp"
20
20
 
21
- # Patch ruby_llm_swarm-mcp's Zeitwerk loader to ignore railtie.rb when Rails is not present
21
+ # Load ruby_llm compatibility patches
22
+ # These patches extend upstream ruby_llm to match fork functionality used by SwarmSDK
23
+ require_relative "swarm_sdk/ruby_llm_patches/init"
24
+
25
+ # Patch Zeitwerk loaders to ignore Rails-dependent files when Rails is not present
22
26
  # This prevents NameError when eager loading outside of Rails applications
23
27
  unless defined?(Rails)
24
28
  require "zeitwerk"
29
+
30
+ # Ignore ruby_llm's ActiveRecord integration (requires ActiveSupport)
31
+ ruby_llm_loader = nil
32
+ Zeitwerk::Registry.loaders.each { |l| ruby_llm_loader = l if l.tag == "ruby_llm" }
33
+ if ruby_llm_loader
34
+ ruby_llm_gem_dir = Gem.loaded_specs["ruby_llm"]&.gem_dir
35
+ if ruby_llm_gem_dir
36
+ active_record_dir = File.join(ruby_llm_gem_dir, "lib", "ruby_llm", "active_record")
37
+ ruby_llm_loader.ignore(active_record_dir)
38
+ end
39
+ end
40
+
41
+ # Ignore ruby_llm-mcp's railtie
25
42
  mcp_loader = nil
26
43
  Zeitwerk::Registry.loaders.each { |l| mcp_loader = l if l.tag == "RubyLLM-mcp" }
27
44
  if mcp_loader
28
- mcp_gem_dir = Gem.loaded_specs["ruby_llm_swarm-mcp"]&.gem_dir
45
+ mcp_gem_dir = Gem.loaded_specs["ruby_llm-mcp"]&.gem_dir ||
46
+ Gem.loaded_specs["ruby_llm_swarm-mcp"]&.gem_dir
29
47
  if mcp_gem_dir
30
48
  railtie_path = File.join(mcp_gem_dir, "lib", "ruby_llm", "mcp", "railtie.rb")
31
49
  mcp_loader.ignore(railtie_path)
@@ -51,6 +69,8 @@ loader.inflector.inflect(
51
69
  "mcp" => "MCP",
52
70
  "openai_with_responses" => "OpenAIWithResponses",
53
71
  )
72
+ # Ignore ruby_llm_patches - these are manually required monkey patches, not autoloaded modules
73
+ loader.ignore("#{__dir__}/swarm_sdk/ruby_llm_patches")
54
74
  loader.setup
55
75
 
56
76
  module SwarmSDK
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.9
4
+ version: 2.7.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paulo Arruda
@@ -52,33 +52,19 @@ dependencies:
52
52
  - !ruby/object:Gem::Version
53
53
  version: '0.4'
54
54
  - !ruby/object:Gem::Dependency
55
- name: openssl
55
+ name: ruby_llm
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: 3.3.2
60
+ version: '1.11'
61
61
  type: :runtime
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: 3.3.2
68
- - !ruby/object:Gem::Dependency
69
- name: ruby_llm_swarm
70
- requirement: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - "~>"
73
- - !ruby/object:Gem::Version
74
- version: 1.9.7
75
- type: :runtime
76
- prerelease: false
77
- version_requirements: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - "~>"
80
- - !ruby/object:Gem::Version
81
- version: 1.9.7
67
+ version: '1.11'
82
68
  - !ruby/object:Gem::Dependency
83
69
  name: ruby_llm_swarm-mcp
84
70
  requirement: !ruby/object:Gem::Requirement
@@ -190,6 +176,14 @@ files:
190
176
  - lib/swarm_sdk/prompts/base_system_prompt.md.erb
191
177
  - lib/swarm_sdk/restore_result.rb
192
178
  - lib/swarm_sdk/result.rb
179
+ - lib/swarm_sdk/ruby_llm_patches/chat_callbacks_patch.rb
180
+ - lib/swarm_sdk/ruby_llm_patches/configuration_patch.rb
181
+ - lib/swarm_sdk/ruby_llm_patches/connection_patch.rb
182
+ - lib/swarm_sdk/ruby_llm_patches/init.rb
183
+ - lib/swarm_sdk/ruby_llm_patches/io_endpoint_patch.rb
184
+ - lib/swarm_sdk/ruby_llm_patches/message_management_patch.rb
185
+ - lib/swarm_sdk/ruby_llm_patches/responses_api_patch.rb
186
+ - lib/swarm_sdk/ruby_llm_patches/tool_concurrency_patch.rb
193
187
  - lib/swarm_sdk/snapshot.rb
194
188
  - lib/swarm_sdk/snapshot_from_events.rb
195
189
  - lib/swarm_sdk/state_restorer.rb
@@ -200,6 +194,7 @@ files:
200
194
  - lib/swarm_sdk/swarm/builder.rb
201
195
  - lib/swarm_sdk/swarm/executor.rb
202
196
  - lib/swarm_sdk/swarm/hook_triggers.rb
197
+ - lib/swarm_sdk/swarm/lazy_delegate_chat.rb
203
198
  - lib/swarm_sdk/swarm/logging_callbacks.rb
204
199
  - lib/swarm_sdk/swarm/mcp_configurator.rb
205
200
  - lib/swarm_sdk/swarm/swarm_registry_builder.rb