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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5806264bb99cea0a71727c89c5839ff3027c17cd725e4261244e14ae9079f513
|
|
4
|
+
data.tar.gz: f3d489dd1d6045dec6b97b499b2d6e27d78440d1b2289a19c2f3bedb27440c8d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
data/lib/swarm_sdk/config.rb
CHANGED
|
@@ -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
|
-
#
|
|
8
|
-
#
|
|
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
|
-
#
|
|
72
|
-
|
|
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
|
data/lib/swarm_sdk/version.rb
CHANGED
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
|
+
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.
|
|
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.
|
|
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
|