swarm_sdk 2.7.4 → 2.7.6

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: b5c93c6e9a850d624b8ac0fe9d31e53a4a764a1caa23319efcfa5b34edfd33b8
4
- data.tar.gz: 2d4ec3258101a45507cbacbd98eeb86d8448627e35faedd2a693c0a18d8622a1
3
+ metadata.gz: 5806264bb99cea0a71727c89c5839ff3027c17cd725e4261244e14ae9079f513
4
+ data.tar.gz: f3d489dd1d6045dec6b97b499b2d6e27d78440d1b2289a19c2f3bedb27440c8d
5
5
  SHA512:
6
- metadata.gz: ac8f8c8dea846e5b0783b49dace5f2e01a0908ebed31eb377fdd4217480e99499fe9eb4bda14772cbfd71d52badc642687434a214f76cf136768c21967e1beff
7
- data.tar.gz: 61a58b209810484c7bcf24727feaa8fb0e23aafc485dbb3ad8a510c095caeaa72778b0e3c97b22eb599a2d9153ef95093dc9aa6a3b34e717b23c4c5d9797b490
6
+ metadata.gz: a37edf046435540ba32aa47b5552ef48e1c599c69a0bf0540ccfa2199a01947006ffe98eb8df1848175e11b673bebbf787156815dc4e5ea9403ab0db984997bd
7
+ data.tar.gz: 2ca616d67f41b19fe596d86fdd36aa6255cb314480c34253aacb7d8276196fd2e2bbd4fb3057b42faec5b000474754df7cce56cddbeb26fcc3301e6fa2a89fcb
@@ -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)
@@ -45,17 +45,23 @@ module SwarmSDK
45
45
  Swarm.apply_mcp_logging_configuration
46
46
 
47
47
  mcp_server_configs.each do |server_config|
48
+ tools_config = server_config[:tools]
49
+ mode = tools_config.nil? ? :discovery : :optimized
50
+
51
+ # Emit event before initialization
52
+ emit_mcp_init_start(agent_name, server_config, mode)
53
+
48
54
  client = initialize_mcp_client(server_config)
49
55
 
50
56
  # Store client for cleanup
51
57
  @mcp_clients[agent_name] << client
52
58
 
53
- tools_config = server_config[:tools]
54
-
55
59
  if tools_config.nil?
56
60
  # Discovery mode: Fetch all tools from server (calls tools/list)
57
61
  # client.tools returns RubyLLM::Tool instances (already wrapped by internal Coordinator)
58
62
  all_tools = client.tools
63
+ tool_names = all_tools.map { |t| t.respond_to?(:name) ? t.name : t.to_s }
64
+
59
65
  all_tools.each do |tool|
60
66
  chat.tool_registry.register(
61
67
  tool,
@@ -63,10 +69,15 @@ module SwarmSDK
63
69
  metadata: { server_name: server_config[:name] },
64
70
  )
65
71
  end
72
+
73
+ # Emit completion event for discovery mode
74
+ emit_mcp_init_complete(agent_name, server_config, mode, all_tools.size, tool_names)
66
75
  RubyLLM.logger.debug("SwarmSDK: Discovered and registered #{all_tools.size} tools from MCP server '#{server_config[:name]}'")
67
76
  else
68
77
  # Optimized mode: Create tool stubs without tools/list RPC (Plan 025)
69
78
  # Use client directly (it has internal coordinator)
79
+ tool_names = tools_config.map(&:to_s)
80
+
70
81
  tools_config.each do |tool_name|
71
82
  stub = Tools::McpToolStub.new(
72
83
  client: client,
@@ -78,6 +89,9 @@ module SwarmSDK
78
89
  metadata: { server_name: server_config[:name] },
79
90
  )
80
91
  end
92
+
93
+ # Emit completion event for optimized mode
94
+ emit_mcp_init_complete(agent_name, server_config, mode, tools_config.size, tool_names)
81
95
  RubyLLM.logger.debug("SwarmSDK: Registered #{tools_config.size} tool stubs from MCP server '#{server_config[:name]}' (lazy schema)")
82
96
  end
83
97
  rescue StandardError => e
@@ -187,6 +201,42 @@ module SwarmSDK
187
201
 
188
202
  streamable_config
189
203
  end
204
+
205
+ # Emit MCP server initialization start event
206
+ #
207
+ # @param agent_name [Symbol] Agent name
208
+ # @param server_config [Hash] MCP server configuration
209
+ # @param mode [Symbol] Initialization mode (:discovery or :optimized)
210
+ # @return [void]
211
+ def emit_mcp_init_start(agent_name, server_config, mode)
212
+ LogStream.emit(
213
+ type: "mcp_server_init_start",
214
+ agent: agent_name,
215
+ server_name: server_config[:name],
216
+ transport_type: server_config[:type],
217
+ mode: mode,
218
+ )
219
+ end
220
+
221
+ # Emit MCP server initialization complete event
222
+ #
223
+ # @param agent_name [Symbol] Agent name
224
+ # @param server_config [Hash] MCP server configuration
225
+ # @param mode [Symbol] Initialization mode (:discovery or :optimized)
226
+ # @param tool_count [Integer] Number of tools registered
227
+ # @param tool_names [Array<String>] Names of registered tools
228
+ # @return [void]
229
+ def emit_mcp_init_complete(agent_name, server_config, mode, tool_count, tool_names)
230
+ LogStream.emit(
231
+ type: "mcp_server_init_complete",
232
+ agent: agent_name,
233
+ server_name: server_config[:name],
234
+ transport_type: server_config[:type],
235
+ mode: mode,
236
+ tool_count: tool_count,
237
+ tools: tool_names,
238
+ )
239
+ end
190
240
  end
191
241
  end
192
242
  end
@@ -4,8 +4,10 @@ module SwarmSDK
4
4
  module Tools
5
5
  module ImageExtractors
6
6
  # Extracts images from PDF documents
7
- # Supports JPEG (DCTDecode), FlateDecode, and LZWDecode formats
8
- # Converts non-JPEG images to TIFF format
7
+ # Only extracts JPEG images (DCTDecode format) which are LLM API compatible
8
+ # Non-JPEG images (FlateDecode, LZWDecode) are skipped because they would
9
+ # require TIFF format which is not supported by LLM APIs
10
+ # Supported LLM image formats: ['png', 'jpeg', 'gif', 'webp']
9
11
  class PdfImageExtractor
10
12
  class << self
11
13
  # Extract all images from a PDF document
@@ -65,11 +67,13 @@ module SwarmSDK
65
67
 
66
68
  case filter
67
69
  when :DCTDecode
68
- # JPEG images can be saved directly
70
+ # JPEG images can be saved directly - LLM API compatible
69
71
  save_jpeg(stream, page_number, name, temp_dir)
70
72
  when :FlateDecode, :LZWDecode, nil
71
- # Raw or compressed formats - save as TIFF
72
- save_as_tiff(stream, page_number, name, temp_dir)
73
+ # Skip non-JPEG images to avoid TIFF format (not supported by LLM APIs)
74
+ # LLM APIs only support: ['png', 'jpeg', 'gif', 'webp']
75
+ # These images would require TIFF conversion which causes API errors
76
+ nil
73
77
  end
74
78
  # Unsupported formats return nil
75
79
  rescue StandardError
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SwarmSDK
4
- VERSION = "2.7.4"
4
+ VERSION = "2.7.6"
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.4
4
+ version: 2.7.6
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