swarm_sdk 2.3.0 → 2.4.0
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/chat.rb +1 -1
- data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +1 -1
- data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +32 -3
- data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +3 -5
- data/lib/swarm_sdk/agent/context.rb +1 -2
- data/lib/swarm_sdk/agent/definition.rb +3 -3
- data/lib/swarm_sdk/builders/base_builder.rb +6 -6
- data/lib/swarm_sdk/config.rb +301 -0
- data/lib/swarm_sdk/context_compactor/token_counter.rb +2 -6
- data/lib/swarm_sdk/hooks/adapter.rb +3 -3
- data/lib/swarm_sdk/hooks/shell_executor.rb +4 -3
- data/lib/swarm_sdk/models.json +4333 -1
- data/lib/swarm_sdk/swarm/tool_configurator.rb +2 -2
- data/lib/swarm_sdk/swarm.rb +12 -13
- data/lib/swarm_sdk/tools/bash.rb +7 -9
- data/lib/swarm_sdk/tools/glob.rb +5 -5
- data/lib/swarm_sdk/tools/read.rb +8 -8
- data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +4 -3
- data/lib/swarm_sdk/tools/web_fetch.rb +20 -18
- data/lib/swarm_sdk/version.rb +1 -1
- data/lib/swarm_sdk/workflow/node_builder.rb +4 -2
- data/lib/swarm_sdk/workflow/transformer_executor.rb +4 -3
- data/lib/swarm_sdk.rb +31 -101
- metadata +4 -3
|
@@ -127,10 +127,10 @@ module SwarmSDK
|
|
|
127
127
|
forbidden = tool_configs.map { |tc| tc[:name].to_sym }.select { |name| FILESYSTEM_TOOLS.include?(name) }
|
|
128
128
|
unless forbidden.empty?
|
|
129
129
|
raise ConfigurationError,
|
|
130
|
-
"Filesystem tools are globally disabled (SwarmSDK.
|
|
130
|
+
"Filesystem tools are globally disabled (SwarmSDK.config.allow_filesystem_tools = false) " \
|
|
131
131
|
"but agent '#{agent_name}' attempts to use: #{forbidden.join(", ")}.\n\n" \
|
|
132
132
|
"This is a system-wide security setting that cannot be overridden by swarm configuration.\n" \
|
|
133
|
-
"To use filesystem tools, set SwarmSDK.
|
|
133
|
+
"To use filesystem tools, set SwarmSDK.config.allow_filesystem_tools = true before loading the swarm."
|
|
134
134
|
end
|
|
135
135
|
end
|
|
136
136
|
|
data/lib/swarm_sdk/swarm.rb
CHANGED
|
@@ -67,8 +67,7 @@ module SwarmSDK
|
|
|
67
67
|
include LoggingCallbacks
|
|
68
68
|
include HookTriggers
|
|
69
69
|
|
|
70
|
-
#
|
|
71
|
-
DEFAULT_MCP_LOG_LEVEL = Defaults::Logging::MCP_LOG_LEVEL
|
|
70
|
+
# NOTE: MCP log level now accessed via SwarmSDK.config.mcp_log_level
|
|
72
71
|
|
|
73
72
|
# Default tools available to all agents
|
|
74
73
|
DEFAULT_TOOLS = ToolConfigurator::DEFAULT_TOOLS
|
|
@@ -98,7 +97,7 @@ module SwarmSDK
|
|
|
98
97
|
attr_writer :first_message_sent
|
|
99
98
|
|
|
100
99
|
# Class-level MCP log level configuration
|
|
101
|
-
@mcp_log_level =
|
|
100
|
+
@mcp_log_level = nil
|
|
102
101
|
@mcp_logging_configured = false
|
|
103
102
|
|
|
104
103
|
class << self
|
|
@@ -111,8 +110,8 @@ module SwarmSDK
|
|
|
111
110
|
#
|
|
112
111
|
# @param level [Integer] Log level (Logger::DEBUG, Logger::INFO, Logger::WARN, Logger::ERROR, Logger::FATAL)
|
|
113
112
|
# @return [void]
|
|
114
|
-
def configure_mcp_logging(level =
|
|
115
|
-
@mcp_log_level = level
|
|
113
|
+
def configure_mcp_logging(level = nil)
|
|
114
|
+
@mcp_log_level = level || SwarmSDK.config.mcp_log_level
|
|
116
115
|
apply_mcp_logging_configuration
|
|
117
116
|
end
|
|
118
117
|
|
|
@@ -123,7 +122,7 @@ module SwarmSDK
|
|
|
123
122
|
return if @mcp_logging_configured
|
|
124
123
|
|
|
125
124
|
RubyLLM::MCP.configure do |config|
|
|
126
|
-
config.log_level = @mcp_log_level
|
|
125
|
+
config.log_level = @mcp_log_level || SwarmSDK.config.mcp_log_level
|
|
127
126
|
end
|
|
128
127
|
|
|
129
128
|
@mcp_logging_configured = true
|
|
@@ -135,17 +134,17 @@ module SwarmSDK
|
|
|
135
134
|
# @param name [String] Human-readable swarm name
|
|
136
135
|
# @param swarm_id [String, nil] Optional swarm ID (auto-generated if not provided)
|
|
137
136
|
# @param parent_swarm_id [String, nil] Optional parent swarm ID (nil for root swarms)
|
|
138
|
-
# @param global_concurrency [Integer] Max concurrent LLM calls across entire swarm
|
|
139
|
-
# @param default_local_concurrency [Integer] Default max concurrent tool calls per agent
|
|
137
|
+
# @param global_concurrency [Integer, nil] Max concurrent LLM calls across entire swarm (nil uses config default)
|
|
138
|
+
# @param default_local_concurrency [Integer, nil] Default max concurrent tool calls per agent (nil uses config default)
|
|
140
139
|
# @param scratchpad [Tools::Stores::Scratchpad, nil] Optional scratchpad instance (for testing/internal use)
|
|
141
140
|
# @param scratchpad_mode [Symbol, String] Scratchpad mode (:enabled or :disabled). :per_node not allowed for non-node swarms.
|
|
142
141
|
# @param allow_filesystem_tools [Boolean, nil] Whether to allow filesystem tools (nil uses global setting)
|
|
143
|
-
def initialize(name:, swarm_id: nil, parent_swarm_id: nil, global_concurrency:
|
|
142
|
+
def initialize(name:, swarm_id: nil, parent_swarm_id: nil, global_concurrency: nil, default_local_concurrency: nil, scratchpad: nil, scratchpad_mode: :enabled, allow_filesystem_tools: nil)
|
|
144
143
|
@name = name
|
|
145
144
|
@swarm_id = swarm_id || generate_swarm_id(name)
|
|
146
145
|
@parent_swarm_id = parent_swarm_id
|
|
147
|
-
@global_concurrency = global_concurrency
|
|
148
|
-
@default_local_concurrency = default_local_concurrency
|
|
146
|
+
@global_concurrency = global_concurrency || SwarmSDK.config.global_concurrency_limit
|
|
147
|
+
@default_local_concurrency = default_local_concurrency || SwarmSDK.config.local_concurrency_limit
|
|
149
148
|
|
|
150
149
|
# Handle scratchpad_mode parameter
|
|
151
150
|
# For Swarm: :enabled or :disabled (not :per_node - that's for nodes)
|
|
@@ -153,9 +152,9 @@ module SwarmSDK
|
|
|
153
152
|
|
|
154
153
|
# Resolve allow_filesystem_tools with priority:
|
|
155
154
|
# 1. Explicit parameter (if not nil)
|
|
156
|
-
# 2. Global
|
|
155
|
+
# 2. Global config
|
|
157
156
|
@allow_filesystem_tools = if allow_filesystem_tools.nil?
|
|
158
|
-
SwarmSDK.
|
|
157
|
+
SwarmSDK.config.allow_filesystem_tools
|
|
159
158
|
else
|
|
160
159
|
allow_filesystem_tools
|
|
161
160
|
end
|
data/lib/swarm_sdk/tools/bash.rb
CHANGED
|
@@ -85,10 +85,7 @@ module SwarmSDK
|
|
|
85
85
|
desc: "Optional timeout in milliseconds (max 600000)",
|
|
86
86
|
required: false
|
|
87
87
|
|
|
88
|
-
#
|
|
89
|
-
DEFAULT_TIMEOUT_MS = Defaults::Timeouts::BASH_COMMAND_MS
|
|
90
|
-
MAX_TIMEOUT_MS = Defaults::Timeouts::BASH_COMMAND_MAX_MS
|
|
91
|
-
MAX_OUTPUT_LENGTH = Defaults::Limits::OUTPUT_CHARACTERS
|
|
88
|
+
# NOTE: Timeout and output limits now accessed via SwarmSDK.config
|
|
92
89
|
|
|
93
90
|
# Commands that are ALWAYS blocked for safety reasons
|
|
94
91
|
# These cannot be overridden by permissions configuration
|
|
@@ -107,8 +104,8 @@ module SwarmSDK
|
|
|
107
104
|
end
|
|
108
105
|
|
|
109
106
|
# Validate and set timeout
|
|
110
|
-
timeout_ms = timeout ||
|
|
111
|
-
timeout_ms = [timeout_ms,
|
|
107
|
+
timeout_ms = timeout || SwarmSDK.config.bash_command_timeout
|
|
108
|
+
timeout_ms = [timeout_ms, SwarmSDK.config.bash_command_max_timeout].min
|
|
112
109
|
timeout_seconds = timeout_ms / 1000.0
|
|
113
110
|
|
|
114
111
|
# Execute command with timeout
|
|
@@ -149,9 +146,10 @@ module SwarmSDK
|
|
|
149
146
|
output = format_command_output(command, description, stdout, stderr, exit_status)
|
|
150
147
|
|
|
151
148
|
# Truncate if too long
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
truncated
|
|
149
|
+
max_output = SwarmSDK.config.output_character_limit
|
|
150
|
+
if output.length > max_output
|
|
151
|
+
truncated = output[0...max_output]
|
|
152
|
+
truncated += "\n\n<system-reminder>Output truncated at #{max_output} characters. The full output was #{output.length} characters.</system-reminder>"
|
|
155
153
|
output = truncated
|
|
156
154
|
end
|
|
157
155
|
|
data/lib/swarm_sdk/tools/glob.rb
CHANGED
|
@@ -50,8 +50,7 @@ module SwarmSDK
|
|
|
50
50
|
desc: "The directory to search in. If not specified, the current working directory will be used. IMPORTANT: Omit this field to use the default directory. DO NOT enter \"undefined\" or \"null\" - simply omit it for the default behavior. Must be a valid directory path if provided.",
|
|
51
51
|
required: false
|
|
52
52
|
|
|
53
|
-
#
|
|
54
|
-
MAX_RESULTS = Defaults::Limits::GLOB_RESULTS
|
|
53
|
+
# NOTE: Result limit now accessed via SwarmSDK.config.glob_result_limit
|
|
55
54
|
|
|
56
55
|
def execute(pattern:, path: nil)
|
|
57
56
|
# Validate inputs
|
|
@@ -108,8 +107,9 @@ module SwarmSDK
|
|
|
108
107
|
matches.sort_by! { |f| -File.mtime(f).to_i }
|
|
109
108
|
|
|
110
109
|
# Limit results
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
max_results = SwarmSDK.config.glob_result_limit
|
|
111
|
+
if matches.count > max_results
|
|
112
|
+
matches = matches.take(max_results)
|
|
113
113
|
truncated = true
|
|
114
114
|
else
|
|
115
115
|
truncated = false
|
|
@@ -123,7 +123,7 @@ module SwarmSDK
|
|
|
123
123
|
output += <<~REMINDER
|
|
124
124
|
|
|
125
125
|
<system-reminder>
|
|
126
|
-
Results limited to first #{
|
|
126
|
+
Results limited to first #{max_results} matches (sorted by most recently modified).
|
|
127
127
|
Consider using a more specific pattern to narrow your search.
|
|
128
128
|
</system-reminder>
|
|
129
129
|
REMINDER
|
data/lib/swarm_sdk/tools/read.rb
CHANGED
|
@@ -10,9 +10,7 @@ module SwarmSDK
|
|
|
10
10
|
class Read < RubyLLM::Tool
|
|
11
11
|
include PathResolver
|
|
12
12
|
|
|
13
|
-
#
|
|
14
|
-
MAX_LINE_LENGTH = Defaults::Limits::LINE_CHARACTERS
|
|
15
|
-
DEFAULT_LIMIT = Defaults::Limits::READ_LINES
|
|
13
|
+
# NOTE: Line length and limit now accessed via SwarmSDK.config
|
|
16
14
|
|
|
17
15
|
# List of available document converters
|
|
18
16
|
CONVERTERS = [
|
|
@@ -153,18 +151,20 @@ module SwarmSDK
|
|
|
153
151
|
lines = lines.drop(start_line)
|
|
154
152
|
|
|
155
153
|
# Apply limit if specified, otherwise use default
|
|
156
|
-
|
|
154
|
+
default_limit = SwarmSDK.config.read_line_limit
|
|
155
|
+
effective_limit = limit || default_limit
|
|
157
156
|
lines = lines.take(effective_limit)
|
|
158
|
-
truncated = limit.nil? && total_lines >
|
|
157
|
+
truncated = limit.nil? && total_lines > default_limit
|
|
159
158
|
|
|
160
159
|
# Format with line numbers (cat -n style)
|
|
160
|
+
max_line_length = SwarmSDK.config.line_character_limit
|
|
161
161
|
output_lines = lines.each_with_index.map do |line, idx|
|
|
162
162
|
line_number = start_line + idx + 1
|
|
163
163
|
display_line = line.chomp
|
|
164
164
|
|
|
165
165
|
# Truncate long lines
|
|
166
|
-
if display_line.length >
|
|
167
|
-
display_line = display_line[0...
|
|
166
|
+
if display_line.length > max_line_length
|
|
167
|
+
display_line = display_line[0...max_line_length]
|
|
168
168
|
display_line += "... (line truncated)"
|
|
169
169
|
end
|
|
170
170
|
|
|
@@ -203,7 +203,7 @@ module SwarmSDK
|
|
|
203
203
|
|
|
204
204
|
if truncated
|
|
205
205
|
reminders << ""
|
|
206
|
-
reminders << "Note: This file has #{total_lines} lines but only the first #{
|
|
206
|
+
reminders << "Note: This file has #{total_lines} lines but only the first #{SwarmSDK.config.read_line_limit} lines are shown. Use the offset and limit parameters to read additional sections if needed."
|
|
207
207
|
end
|
|
208
208
|
|
|
209
209
|
reminders << "</system-reminder>"
|
|
@@ -21,7 +21,7 @@ module SwarmSDK
|
|
|
21
21
|
super() # Initialize parent Storage class
|
|
22
22
|
@entries = {}
|
|
23
23
|
@total_size = 0
|
|
24
|
-
@total_size_limit = total_size_limit ||
|
|
24
|
+
@total_size_limit = total_size_limit || SwarmSDK.config.scratchpad_total_size_limit
|
|
25
25
|
@mutex = Mutex.new
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -41,8 +41,9 @@ module SwarmSDK
|
|
|
41
41
|
content_size = content.bytesize
|
|
42
42
|
|
|
43
43
|
# Check entry size limit
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
entry_size_limit = SwarmSDK.config.scratchpad_entry_size_limit
|
|
45
|
+
if content_size > entry_size_limit
|
|
46
|
+
raise ArgumentError, "Content exceeds maximum size (#{format_bytes(entry_size_limit)}). " \
|
|
46
47
|
"Current: #{format_bytes(content_size)}"
|
|
47
48
|
end
|
|
48
49
|
|
|
@@ -11,7 +11,6 @@ module SwarmSDK
|
|
|
11
11
|
super()
|
|
12
12
|
@cache = {}
|
|
13
13
|
@cache_ttl = 900 # 15 minutes in seconds
|
|
14
|
-
@llm_enabled = SwarmSDK.settings.webfetch_llm_enabled?
|
|
15
14
|
end
|
|
16
15
|
|
|
17
16
|
def name
|
|
@@ -51,17 +50,18 @@ module SwarmSDK
|
|
|
51
50
|
desc: "The prompt to run on the fetched content. Required when SwarmSDK is configured with webfetch_provider and webfetch_model. Optional otherwise (ignored if LLM processing not configured).",
|
|
52
51
|
required: false
|
|
53
52
|
|
|
54
|
-
#
|
|
55
|
-
MAX_CONTENT_LENGTH = Defaults::Limits::WEB_FETCH_CHARACTERS
|
|
53
|
+
# NOTE: Content length and timeout now accessed via SwarmSDK.config
|
|
56
54
|
USER_AGENT = "SwarmSDK WebFetch Tool (https://github.com/parruda/claude-swarm)"
|
|
57
|
-
TIMEOUT = Defaults::Timeouts::WEB_FETCH_SECONDS
|
|
58
55
|
|
|
59
56
|
def execute(url:, prompt: nil)
|
|
60
57
|
# Validate inputs
|
|
61
58
|
return validation_error("url is required") if url.nil? || url.empty?
|
|
62
59
|
|
|
60
|
+
# Check if LLM processing is enabled (lazy check)
|
|
61
|
+
llm_enabled = SwarmSDK.config.webfetch_llm_enabled?
|
|
62
|
+
|
|
63
63
|
# Validate prompt when LLM processing is enabled
|
|
64
|
-
if
|
|
64
|
+
if llm_enabled && (prompt.nil? || prompt.empty?)
|
|
65
65
|
return validation_error("prompt is required when LLM processing is configured")
|
|
66
66
|
end
|
|
67
67
|
|
|
@@ -70,7 +70,7 @@ module SwarmSDK
|
|
|
70
70
|
return validation_error("Invalid URL format: #{url}") unless normalized_url
|
|
71
71
|
|
|
72
72
|
# Check cache first (cache key includes prompt if LLM is enabled)
|
|
73
|
-
cache_key =
|
|
73
|
+
cache_key = llm_enabled ? "#{normalized_url}:#{prompt}" : normalized_url
|
|
74
74
|
cached = get_from_cache(cache_key)
|
|
75
75
|
return cached if cached
|
|
76
76
|
|
|
@@ -87,13 +87,14 @@ module SwarmSDK
|
|
|
87
87
|
markdown_content = html_to_markdown(fetch_result[:body])
|
|
88
88
|
|
|
89
89
|
# Truncate if too long
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
max_content = SwarmSDK.config.web_fetch_character_limit
|
|
91
|
+
if markdown_content.length > max_content
|
|
92
|
+
markdown_content = markdown_content[0...max_content]
|
|
92
93
|
markdown_content += "\n\n[Content truncated due to length]"
|
|
93
94
|
end
|
|
94
95
|
|
|
95
96
|
# Process with AI model if LLM is enabled, otherwise return markdown
|
|
96
|
-
result = if
|
|
97
|
+
result = if llm_enabled
|
|
97
98
|
process_with_llm(markdown_content, prompt, normalized_url)
|
|
98
99
|
else
|
|
99
100
|
markdown_content
|
|
@@ -143,12 +144,13 @@ module SwarmSDK
|
|
|
143
144
|
require "faraday"
|
|
144
145
|
require "faraday/follow_redirects"
|
|
145
146
|
|
|
147
|
+
timeout = SwarmSDK.config.web_fetch_timeout
|
|
146
148
|
response = Faraday.new(url: url) do |conn|
|
|
147
149
|
conn.request(:url_encoded)
|
|
148
150
|
conn.response(:follow_redirects, limit: 5)
|
|
149
151
|
conn.adapter(Faraday.default_adapter)
|
|
150
|
-
conn.options.timeout =
|
|
151
|
-
conn.options.open_timeout =
|
|
152
|
+
conn.options.timeout = timeout
|
|
153
|
+
conn.options.open_timeout = timeout
|
|
152
154
|
end.get do |req|
|
|
153
155
|
req.headers["User-Agent"] = USER_AGENT
|
|
154
156
|
req.headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
|
@@ -167,7 +169,7 @@ module SwarmSDK
|
|
|
167
169
|
redirect_url: redirect_url,
|
|
168
170
|
}
|
|
169
171
|
rescue Faraday::TimeoutError
|
|
170
|
-
error("Request timed out after #{
|
|
172
|
+
error("Request timed out after #{SwarmSDK.config.web_fetch_timeout} seconds")
|
|
171
173
|
rescue Faraday::ConnectionFailed => e
|
|
172
174
|
error("Connection failed: #{e.message}")
|
|
173
175
|
rescue StandardError => e
|
|
@@ -194,17 +196,17 @@ module SwarmSDK
|
|
|
194
196
|
Please respond to the user's request based on the content above.
|
|
195
197
|
PROMPT
|
|
196
198
|
|
|
197
|
-
# Get
|
|
198
|
-
|
|
199
|
+
# Get config
|
|
200
|
+
sdk_config = SwarmSDK.config
|
|
199
201
|
|
|
200
202
|
# Build chat with configured provider and model
|
|
201
203
|
chat_params = {
|
|
202
|
-
model:
|
|
203
|
-
provider:
|
|
204
|
+
model: sdk_config.webfetch_model,
|
|
205
|
+
provider: sdk_config.webfetch_provider.to_sym,
|
|
204
206
|
}
|
|
205
|
-
chat_params[:base_url] =
|
|
207
|
+
chat_params[:base_url] = sdk_config.webfetch_base_url if sdk_config.webfetch_base_url
|
|
206
208
|
|
|
207
|
-
chat = RubyLLM.chat(**chat_params).with_params(max_tokens:
|
|
209
|
+
chat = RubyLLM.chat(**chat_params).with_params(max_tokens: sdk_config.webfetch_max_tokens)
|
|
208
210
|
|
|
209
211
|
response = chat.ask(full_prompt)
|
|
210
212
|
|
data/lib/swarm_sdk/version.rb
CHANGED
|
@@ -214,7 +214,8 @@ module SwarmSDK
|
|
|
214
214
|
#
|
|
215
215
|
# @example
|
|
216
216
|
# input_command("scripts/validate.sh", timeout: 30)
|
|
217
|
-
def input_command(command, timeout:
|
|
217
|
+
def input_command(command, timeout: nil)
|
|
218
|
+
timeout ||= SwarmSDK.config.transformer_command_timeout
|
|
218
219
|
@input_transformer_command = { command: command, timeout: timeout }
|
|
219
220
|
end
|
|
220
221
|
|
|
@@ -288,7 +289,8 @@ module SwarmSDK
|
|
|
288
289
|
#
|
|
289
290
|
# @example
|
|
290
291
|
# output_command("scripts/format.sh", timeout: 30)
|
|
291
|
-
def output_command(command, timeout:
|
|
292
|
+
def output_command(command, timeout: nil)
|
|
293
|
+
timeout ||= SwarmSDK.config.transformer_command_timeout
|
|
292
294
|
@output_transformer_command = { command: command, timeout: timeout }
|
|
293
295
|
end
|
|
294
296
|
|
|
@@ -90,8 +90,7 @@ module SwarmSDK
|
|
|
90
90
|
# echo "$CONTENT"
|
|
91
91
|
# exit 0
|
|
92
92
|
class TransformerExecutor
|
|
93
|
-
#
|
|
94
|
-
DEFAULT_TIMEOUT = Defaults::Timeouts::TRANSFORMER_COMMAND_SECONDS
|
|
93
|
+
# NOTE: Timeout now accessed via SwarmSDK.config.transformer_command_timeout
|
|
95
94
|
|
|
96
95
|
# Result object for transformer execution
|
|
97
96
|
TransformerResult = Struct.new(:success, :content, :skip_execution, :halt, :error_message, keyword_init: true) do
|
|
@@ -114,7 +113,9 @@ module SwarmSDK
|
|
|
114
113
|
# @param fallback_content [String] Content to use if skip (exit 1)
|
|
115
114
|
# @param timeout [Integer] Timeout in seconds (default: 60)
|
|
116
115
|
# @return [TransformerResult] Result with transformed content or skip/halt flags
|
|
117
|
-
def execute(command:, context:, event:, node_name:, fallback_content:, timeout:
|
|
116
|
+
def execute(command:, context:, event:, node_name:, fallback_content:, timeout: nil)
|
|
117
|
+
timeout ||= SwarmSDK.config.transformer_command_timeout
|
|
118
|
+
|
|
118
119
|
# Build JSON input for transformer
|
|
119
120
|
input_json = build_transformer_input(context, event, node_name)
|
|
120
121
|
|
data/lib/swarm_sdk.rb
CHANGED
|
@@ -63,8 +63,37 @@ module SwarmSDK
|
|
|
63
63
|
class StateError < Error; end
|
|
64
64
|
|
|
65
65
|
class << self
|
|
66
|
-
#
|
|
67
|
-
|
|
66
|
+
# Get the global configuration instance
|
|
67
|
+
#
|
|
68
|
+
# @return [Config] The singleton Config instance
|
|
69
|
+
def config
|
|
70
|
+
Config.instance
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Configure SwarmSDK global settings
|
|
74
|
+
#
|
|
75
|
+
# @yield [Config] The configuration instance
|
|
76
|
+
# @return [Config] The configuration instance
|
|
77
|
+
#
|
|
78
|
+
# @example
|
|
79
|
+
# SwarmSDK.configure do |config|
|
|
80
|
+
# config.openai_api_key = "sk-..."
|
|
81
|
+
# config.default_model = "claude-sonnet-4"
|
|
82
|
+
# end
|
|
83
|
+
def configure
|
|
84
|
+
yield(config) if block_given?
|
|
85
|
+
config
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Reset configuration to defaults
|
|
89
|
+
#
|
|
90
|
+
# Clears all configuration including explicit values and cached ENV values.
|
|
91
|
+
# Use in tests to ensure clean state.
|
|
92
|
+
#
|
|
93
|
+
# @return [void]
|
|
94
|
+
def reset_config!
|
|
95
|
+
Config.reset!
|
|
96
|
+
end
|
|
68
97
|
|
|
69
98
|
# Main entry point for DSL - builds simple multi-agent swarms
|
|
70
99
|
#
|
|
@@ -248,21 +277,6 @@ module SwarmSDK
|
|
|
248
277
|
swarm
|
|
249
278
|
end
|
|
250
279
|
|
|
251
|
-
# Configure SwarmSDK global settings
|
|
252
|
-
def configure
|
|
253
|
-
self.settings ||= Settings.new
|
|
254
|
-
yield(settings)
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
# Reset settings to defaults
|
|
258
|
-
def reset_settings!
|
|
259
|
-
self.settings = Settings.new
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
# Alias for backward compatibility
|
|
263
|
-
alias_method :configuration, :settings
|
|
264
|
-
alias_method :reset_configuration!, :reset_settings!
|
|
265
|
-
|
|
266
280
|
private
|
|
267
281
|
|
|
268
282
|
# Check if hooks are configured in the configuration
|
|
@@ -437,88 +451,4 @@ module SwarmSDK
|
|
|
437
451
|
error_hash.compact
|
|
438
452
|
end
|
|
439
453
|
end
|
|
440
|
-
|
|
441
|
-
# Settings class for SwarmSDK global settings (not to be confused with Configuration for YAML loading)
|
|
442
|
-
class Settings
|
|
443
|
-
# WebFetch tool LLM processing configuration
|
|
444
|
-
attr_accessor :webfetch_provider, :webfetch_model, :webfetch_base_url, :webfetch_max_tokens
|
|
445
|
-
|
|
446
|
-
# Filesystem tools control
|
|
447
|
-
attr_accessor :allow_filesystem_tools
|
|
448
|
-
|
|
449
|
-
def initialize
|
|
450
|
-
@webfetch_provider = nil
|
|
451
|
-
@webfetch_model = nil
|
|
452
|
-
@webfetch_base_url = nil
|
|
453
|
-
@webfetch_max_tokens = 4096
|
|
454
|
-
@allow_filesystem_tools = parse_env_bool("SWARM_SDK_ALLOW_FILESYSTEM_TOOLS", default: true)
|
|
455
|
-
end
|
|
456
|
-
|
|
457
|
-
# Check if WebFetch LLM processing is enabled
|
|
458
|
-
def webfetch_llm_enabled?
|
|
459
|
-
!@webfetch_provider.nil? && !@webfetch_model.nil?
|
|
460
|
-
end
|
|
461
|
-
|
|
462
|
-
private
|
|
463
|
-
|
|
464
|
-
def parse_env_bool(key, default:)
|
|
465
|
-
return default unless ENV.key?(key)
|
|
466
|
-
|
|
467
|
-
value = ENV[key].to_s.downcase
|
|
468
|
-
return true if ["true", "yes", "1", "on", "enabled"].include?(value)
|
|
469
|
-
return false if ["false", "no", "0", "off", "disabled"].include?(value)
|
|
470
|
-
|
|
471
|
-
default
|
|
472
|
-
end
|
|
473
|
-
end
|
|
474
|
-
|
|
475
|
-
# Initialize default settings
|
|
476
|
-
self.settings = Settings.new
|
|
477
|
-
end
|
|
478
|
-
|
|
479
|
-
# Automatically configure RubyLLM from environment variables
|
|
480
|
-
# This makes SwarmSDK "just work" when users set standard ENV variables
|
|
481
|
-
RubyLLM.configure do |config|
|
|
482
|
-
# Only set if config not already set (||= handles nil ENV values gracefully)
|
|
483
|
-
|
|
484
|
-
# OpenAI
|
|
485
|
-
config.openai_api_key ||= ENV["OPENAI_API_KEY"]
|
|
486
|
-
config.openai_api_base ||= ENV["OPENAI_API_BASE"]
|
|
487
|
-
config.openai_organization_id ||= ENV["OPENAI_ORG_ID"]
|
|
488
|
-
config.openai_project_id ||= ENV["OPENAI_PROJECT_ID"]
|
|
489
|
-
|
|
490
|
-
# Anthropic
|
|
491
|
-
config.anthropic_api_key ||= ENV["ANTHROPIC_API_KEY"]
|
|
492
|
-
|
|
493
|
-
# Google Gemini
|
|
494
|
-
config.gemini_api_key ||= ENV["GEMINI_API_KEY"]
|
|
495
|
-
|
|
496
|
-
# Google Vertex AI (note: vertexai, not vertex_ai)
|
|
497
|
-
config.vertexai_project_id ||= ENV["GOOGLE_CLOUD_PROJECT"] || ENV["VERTEXAI_PROJECT_ID"]
|
|
498
|
-
config.vertexai_location ||= ENV["GOOGLE_CLOUD_LOCATION"] || ENV["VERTEXAI_LOCATION"]
|
|
499
|
-
|
|
500
|
-
# DeepSeek
|
|
501
|
-
config.deepseek_api_key ||= ENV["DEEPSEEK_API_KEY"]
|
|
502
|
-
|
|
503
|
-
# Mistral
|
|
504
|
-
config.mistral_api_key ||= ENV["MISTRAL_API_KEY"]
|
|
505
|
-
|
|
506
|
-
# Perplexity
|
|
507
|
-
config.perplexity_api_key ||= ENV["PERPLEXITY_API_KEY"]
|
|
508
|
-
|
|
509
|
-
# OpenRouter
|
|
510
|
-
config.openrouter_api_key ||= ENV["OPENROUTER_API_KEY"]
|
|
511
|
-
|
|
512
|
-
# AWS Bedrock
|
|
513
|
-
config.bedrock_api_key ||= ENV["AWS_ACCESS_KEY_ID"]
|
|
514
|
-
config.bedrock_secret_key ||= ENV["AWS_SECRET_ACCESS_KEY"]
|
|
515
|
-
config.bedrock_region ||= ENV["AWS_REGION"]
|
|
516
|
-
config.bedrock_session_token ||= ENV["AWS_SESSION_TOKEN"]
|
|
517
|
-
|
|
518
|
-
# Ollama (local)
|
|
519
|
-
config.ollama_api_base ||= ENV["OLLAMA_API_BASE"]
|
|
520
|
-
|
|
521
|
-
# GPUStack (local)
|
|
522
|
-
config.gpustack_api_base ||= ENV["GPUSTACK_API_BASE"]
|
|
523
|
-
config.gpustack_api_key ||= ENV["GPUSTACK_API_KEY"]
|
|
524
454
|
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.
|
|
4
|
+
version: 2.4.0
|
|
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.4
|
|
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.4
|
|
82
82
|
- !ruby/object:Gem::Dependency
|
|
83
83
|
name: zeitwerk
|
|
84
84
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -129,6 +129,7 @@ files:
|
|
|
129
129
|
- lib/swarm_sdk/concerns/cleanupable.rb
|
|
130
130
|
- lib/swarm_sdk/concerns/snapshotable.rb
|
|
131
131
|
- lib/swarm_sdk/concerns/validatable.rb
|
|
132
|
+
- lib/swarm_sdk/config.rb
|
|
132
133
|
- lib/swarm_sdk/configuration.rb
|
|
133
134
|
- lib/swarm_sdk/configuration/parser.rb
|
|
134
135
|
- lib/swarm_sdk/configuration/translator.rb
|