swarm_sdk 2.7.3 → 2.7.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9d0b44f3edf346a30b0442027c9ca2e8cf06e3e2c074c89f483c0eab0964a592
4
- data.tar.gz: b7c690fd69303078c70c252a09a9e4f46b63f0f4a438a3fc9188cacc30e44109
3
+ metadata.gz: 6aaba8cabb5957715e88ee02e40e9492fe3546791c806d1ddaff95e967f77aba
4
+ data.tar.gz: 752d15e6e69bb1a9941212d1c33622d678dcc0dc734b88b77a845c7fca4e982b
5
5
  SHA512:
6
- metadata.gz: e0881dd9ae7fefc423bdbad4d56d535be627b622f2301eae1c12858d8198f7f55472198f6413535bccd768b17368233ac24ca5d2ab58417cbee9a7a68e8cdc79
7
- data.tar.gz: a2af0ea8bf741a017196ce6db4d17a7b1bdc9fed2e517c35ae17c2336b950d25300186970f15b746fbc7dfd5c2679a53b9596d9f675c5a44089dc10672d542a0
6
+ metadata.gz: 36532a008bbb328cddf60bca55d7d8e210b2c0701ca546190164a16067d3878e26c6c4a6d347e9f262669c34289bad7ac0ddd714062a6d4ab9807e0ef5fd9dc5
7
+ data.tar.gz: e7e512794d27d5bd378ea1c96e66f18683cbab8c95e3820672bd74174e0fd5963894958a61aa2e7cf40485c908a7a7adf6a7cbda9d7bfdd480ccd0c3156e4d15
@@ -117,6 +117,9 @@ module SwarmSDK
117
117
  def build_custom_context(provider:, base_url:, timeout:)
118
118
  RubyLLM.context do |config|
119
119
  config.request_timeout = timeout
120
+ # Set read_timeout to match request_timeout for streaming support
121
+ # This ensures long gaps between chunks (model thinking) don't cause timeouts
122
+ config.read_timeout = SwarmSDK.config.llm_read_timeout || timeout
120
123
 
121
124
  configure_provider_base_url(config, provider, base_url) if base_url
122
125
  end
@@ -56,6 +56,15 @@ module SwarmSDK
56
56
  gpustack_api_key: [:gpustack_api_key, "GPUSTACK_API_KEY"],
57
57
  }.freeze
58
58
 
59
+ # RubyLLM connection settings that proxy to RubyLLM.config
60
+ # Maps SwarmSDK config key => [RubyLLM config key, ENV variable, default value]
61
+ RUBYLLM_CONNECTION_MAPPINGS = {
62
+ llm_request_timeout: [:request_timeout, "SWARM_SDK_LLM_REQUEST_TIMEOUT", 300],
63
+ llm_read_timeout: [:read_timeout, "SWARM_SDK_LLM_READ_TIMEOUT", nil], # nil = use request_timeout
64
+ llm_open_timeout: [:open_timeout, "SWARM_SDK_LLM_OPEN_TIMEOUT", 30],
65
+ llm_write_timeout: [:write_timeout, "SWARM_SDK_LLM_WRITE_TIMEOUT", 30],
66
+ }.freeze
67
+
59
68
  # SwarmSDK defaults that can be overridden
60
69
  # Maps config key => [ENV variable, default proc]
61
70
  DEFAULTS_MAPPINGS = {
@@ -152,6 +161,46 @@ module SwarmSDK
152
161
  end
153
162
  end
154
163
 
164
+ # ========== RubyLLM Connection Accessors (with RubyLLM proxying) ==========
165
+
166
+ # @!method llm_request_timeout
167
+ # Get the LLM request timeout (seconds)
168
+ # @return [Integer] The timeout (default: 300)
169
+ #
170
+ # @!method llm_read_timeout
171
+ # Get the LLM read timeout (seconds) - time to wait between chunks
172
+ # @return [Integer, nil] The timeout (nil = use request_timeout)
173
+ #
174
+ # @!method llm_open_timeout
175
+ # Get the LLM connection open timeout (seconds)
176
+ # @return [Integer] The timeout (default: 30)
177
+ #
178
+ # @!method llm_write_timeout
179
+ # Get the LLM write timeout (seconds)
180
+ # @return [Integer] The timeout (default: 30)
181
+
182
+ RUBYLLM_CONNECTION_MAPPINGS.each_key do |config_key|
183
+ ruby_llm_key, _env_key, default_value = RUBYLLM_CONNECTION_MAPPINGS[config_key]
184
+
185
+ # Getter with default fallback
186
+ define_method(config_key) do
187
+ ensure_env_loaded!
188
+ if @explicit_values.key?(config_key)
189
+ @explicit_values[config_key]
190
+ elsif @env_values.key?(config_key)
191
+ @env_values[config_key]
192
+ else
193
+ default_value
194
+ end
195
+ end
196
+
197
+ # Setter with RubyLLM proxying
198
+ define_method("#{config_key}=") do |value|
199
+ @explicit_values[config_key] = value
200
+ RubyLLM.config.public_send("#{ruby_llm_key}=", value)
201
+ end
202
+ end
203
+
155
204
  # ========== Defaults Accessors (with module constant fallback) ==========
156
205
 
157
206
  # @!method default_model
@@ -256,6 +305,18 @@ module SwarmSDK
256
305
  RubyLLM.config.public_send("#{ruby_llm_key}=", value)
257
306
  end
258
307
 
308
+ # Load RubyLLM connection settings and proxy to RubyLLM
309
+ RUBYLLM_CONNECTION_MAPPINGS.each do |config_key, (ruby_llm_key, env_key, _default)|
310
+ next if @explicit_values.key?(config_key)
311
+ next unless ENV.key?(env_key)
312
+
313
+ value = parse_env_value(ENV[env_key], config_key)
314
+ @env_values[config_key] = value
315
+
316
+ # Proxy to RubyLLM
317
+ RubyLLM.config.public_send("#{ruby_llm_key}=", value)
318
+ end
319
+
259
320
  # Load defaults (no RubyLLM proxy)
260
321
  DEFAULTS_MAPPINGS.each do |config_key, (env_key, _default_proc)|
261
322
  next if @explicit_values.key?(config_key)
@@ -84,6 +84,11 @@ module SwarmSDK
84
84
  desc: "Message to send to the agent - can be a work request, question, or collaboration message",
85
85
  required: true
86
86
 
87
+ param :reset_context,
88
+ type: "boolean",
89
+ desc: "Reset the agent's conversation history before sending the message. Use it to recover from 'prompt too long' errors or other 4XX errors.",
90
+ required: false
91
+
87
92
  # Override name to return custom delegation tool name
88
93
  def name
89
94
  @tool_name
@@ -92,8 +97,9 @@ module SwarmSDK
92
97
  # Execute delegation with pre/post hooks
93
98
  #
94
99
  # @param message [String] Message to send to the agent
100
+ # @param reset_context [Boolean] Whether to reset the agent's conversation history before delegation
95
101
  # @return [String] Result from delegate agent or error message
96
- def execute(message:)
102
+ def execute(message:, reset_context: false)
97
103
  # Access swarm infrastructure
98
104
  call_stack = @swarm.delegation_call_stack
99
105
  hook_registry = @swarm.hook_registry
@@ -140,10 +146,10 @@ module SwarmSDK
140
146
  # Determine delegation type and proceed
141
147
  delegation_result = if @delegate_chat
142
148
  # Delegate to agent
143
- delegate_to_agent(message, call_stack)
149
+ delegate_to_agent(message, call_stack, reset_context: reset_context)
144
150
  elsif swarm_registry&.registered?(@delegate_target)
145
151
  # Delegate to registered swarm
146
- delegate_to_swarm(message, call_stack, swarm_registry)
152
+ delegate_to_swarm(message, call_stack, swarm_registry, reset_context: reset_context)
147
153
  else
148
154
  raise ConfigurationError, "Unknown delegation target: #{@delegate_target}"
149
155
  end
@@ -222,13 +228,15 @@ module SwarmSDK
222
228
  #
223
229
  # @param message [String] Message to send to the agent
224
230
  # @param call_stack [Array] Delegation call stack for circular dependency detection
231
+ # @param reset_context [Boolean] Whether to reset the agent's conversation history before delegation
225
232
  # @return [String] Result from agent
226
- def delegate_to_agent(message, call_stack)
233
+ def delegate_to_agent(message, call_stack, reset_context: false)
227
234
  # Push delegate target onto call stack to track delegation chain
228
235
  call_stack.push(@delegate_target)
229
236
  begin
230
- # Clear conversation if preserve_context is false
231
- @delegate_chat.clear_conversation unless @preserve_context
237
+ # Clear conversation if reset_context is true OR if preserve_context is false
238
+ # reset_context takes precedence as it's an explicit request
239
+ @delegate_chat.clear_conversation if reset_context || !@preserve_context
232
240
 
233
241
  response = @delegate_chat.ask(message, source: "delegation")
234
242
  response.content
@@ -243,20 +251,24 @@ module SwarmSDK
243
251
  # @param message [String] Message to send to the swarm
244
252
  # @param call_stack [Array] Delegation call stack for circular dependency detection
245
253
  # @param swarm_registry [SwarmRegistry] Registry for sub-swarms
254
+ # @param reset_context [Boolean] Whether to reset the swarm's conversation history before delegation
246
255
  # @return [String] Result from swarm's lead agent
247
- def delegate_to_swarm(message, call_stack, swarm_registry)
256
+ def delegate_to_swarm(message, call_stack, swarm_registry, reset_context: false)
248
257
  # Load sub-swarm (lazy load + cache)
249
258
  subswarm = swarm_registry.load_swarm(@delegate_target)
250
259
 
251
260
  # Push delegate target onto call stack to track delegation chain
252
261
  call_stack.push(@delegate_target)
253
262
  begin
263
+ # Reset swarm if reset_context is true
264
+ swarm_registry.reset(@delegate_target) if reset_context
265
+
254
266
  # Execute sub-swarm's lead agent
255
267
  lead_agent = subswarm.agents[subswarm.lead_agent]
256
268
  response = lead_agent.ask(message, source: "delegation")
257
269
  result = response.content
258
270
 
259
- # Reset if keep_context: false
271
+ # Reset if keep_context: false (standard behavior)
260
272
  swarm_registry.reset_if_needed(@delegate_target)
261
273
 
262
274
  result
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SwarmSDK
4
- VERSION = "2.7.3"
4
+ VERSION = "2.7.5"
5
5
  end
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.3
4
+ version: 2.7.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paulo Arruda
@@ -71,14 +71,14 @@ dependencies:
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: 1.9.6
74
+ version: 1.9.7
75
75
  type: :runtime
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: 1.9.6
81
+ version: 1.9.7
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: ruby_llm_swarm-mcp
84
84
  requirement: !ruby/object:Gem::Requirement