claude_swarm 1.0.9 → 1.0.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.
Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. data/{CHANGELOG.md → CHANGELOG.claude-swarm.md} +10 -0
  3. data/CLAUDE.md +346 -191
  4. data/decisions/2025-11-22-001-global-agent-registry.md +172 -0
  5. data/docs/v2/CHANGELOG.swarm_cli.md +20 -0
  6. data/docs/v2/CHANGELOG.swarm_memory.md +146 -1
  7. data/docs/v2/CHANGELOG.swarm_sdk.md +433 -10
  8. data/docs/v2/README.md +20 -5
  9. data/docs/v2/guides/complete-tutorial.md +95 -9
  10. data/docs/v2/guides/getting-started.md +10 -8
  11. data/docs/v2/guides/memory-adapters.md +41 -0
  12. data/docs/v2/guides/migrating-to-2.x.md +746 -0
  13. data/docs/v2/guides/plugins.md +52 -5
  14. data/docs/v2/guides/rails-integration.md +6 -0
  15. data/docs/v2/guides/snapshots.md +14 -14
  16. data/docs/v2/guides/swarm-memory.md +2 -13
  17. data/docs/v2/reference/architecture-flow.md +3 -3
  18. data/docs/v2/reference/cli.md +0 -1
  19. data/docs/v2/reference/configuration_reference.md +300 -0
  20. data/docs/v2/reference/event_payload_structures.md +27 -5
  21. data/docs/v2/reference/ruby-dsl.md +614 -18
  22. data/docs/v2/reference/swarm_memory_technical_details.md +7 -29
  23. data/docs/v2/reference/yaml.md +172 -54
  24. data/examples/snapshot_demo.rb +2 -2
  25. data/lib/claude_swarm/mcp_generator.rb +8 -21
  26. data/lib/claude_swarm/orchestrator.rb +8 -1
  27. data/lib/claude_swarm/version.rb +1 -1
  28. data/lib/swarm_cli/commands/run.rb +2 -2
  29. data/lib/swarm_cli/config_loader.rb +11 -11
  30. data/lib/swarm_cli/formatters/human_formatter.rb +0 -33
  31. data/lib/swarm_cli/interactive_repl.rb +2 -2
  32. data/lib/swarm_cli/ui/icons.rb +0 -23
  33. data/lib/swarm_cli/version.rb +1 -1
  34. data/lib/swarm_memory/adapters/filesystem_adapter.rb +11 -34
  35. data/lib/swarm_memory/core/semantic_index.rb +10 -2
  36. data/lib/swarm_memory/core/storage.rb +7 -2
  37. data/lib/swarm_memory/dsl/memory_config.rb +37 -0
  38. data/lib/swarm_memory/integration/sdk_plugin.rb +201 -28
  39. data/lib/swarm_memory/optimization/defragmenter.rb +1 -1
  40. data/lib/swarm_memory/prompts/memory_researcher.md.erb +0 -1
  41. data/lib/swarm_memory/tools/load_skill.rb +0 -1
  42. data/lib/swarm_memory/tools/memory_edit.rb +2 -1
  43. data/lib/swarm_memory/tools/memory_read.rb +1 -1
  44. data/lib/swarm_memory/version.rb +1 -1
  45. data/lib/swarm_memory.rb +8 -6
  46. data/lib/swarm_sdk/agent/builder.rb +58 -0
  47. data/lib/swarm_sdk/agent/chat.rb +527 -1061
  48. data/lib/swarm_sdk/agent/{chat → chat_helpers}/context_tracker.rb +13 -88
  49. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +204 -0
  50. data/lib/swarm_sdk/agent/{chat → chat_helpers}/hook_integration.rb +108 -46
  51. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +78 -0
  52. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +267 -0
  53. data/lib/swarm_sdk/agent/{chat → chat_helpers}/logging_helpers.rb +3 -3
  54. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +83 -0
  55. data/lib/swarm_sdk/agent/{chat → chat_helpers}/system_reminder_injector.rb +11 -13
  56. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +79 -0
  57. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +146 -0
  58. data/lib/swarm_sdk/agent/context.rb +1 -2
  59. data/lib/swarm_sdk/agent/definition.rb +66 -154
  60. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +4 -2
  61. data/lib/swarm_sdk/agent/system_prompt_builder.rb +161 -0
  62. data/lib/swarm_sdk/agent_registry.rb +146 -0
  63. data/lib/swarm_sdk/builders/base_builder.rb +488 -0
  64. data/lib/swarm_sdk/concerns/cleanupable.rb +39 -0
  65. data/lib/swarm_sdk/concerns/snapshotable.rb +67 -0
  66. data/lib/swarm_sdk/concerns/validatable.rb +55 -0
  67. data/lib/swarm_sdk/config.rb +302 -0
  68. data/lib/swarm_sdk/configuration/parser.rb +373 -0
  69. data/lib/swarm_sdk/configuration/translator.rb +255 -0
  70. data/lib/swarm_sdk/configuration.rb +77 -546
  71. data/lib/swarm_sdk/context_compactor/token_counter.rb +2 -6
  72. data/lib/swarm_sdk/context_compactor.rb +6 -11
  73. data/lib/swarm_sdk/context_management/builder.rb +128 -0
  74. data/lib/swarm_sdk/context_management/context.rb +328 -0
  75. data/lib/swarm_sdk/custom_tool_registry.rb +226 -0
  76. data/lib/swarm_sdk/defaults.rb +196 -0
  77. data/lib/swarm_sdk/events_to_messages.rb +18 -0
  78. data/lib/swarm_sdk/hooks/adapter.rb +3 -3
  79. data/lib/swarm_sdk/hooks/shell_executor.rb +4 -2
  80. data/lib/swarm_sdk/log_collector.rb +179 -29
  81. data/lib/swarm_sdk/log_stream.rb +29 -0
  82. data/lib/swarm_sdk/models.json +4333 -1
  83. data/lib/swarm_sdk/models.rb +43 -2
  84. data/lib/swarm_sdk/node_context.rb +1 -1
  85. data/lib/swarm_sdk/observer/builder.rb +81 -0
  86. data/lib/swarm_sdk/observer/config.rb +45 -0
  87. data/lib/swarm_sdk/observer/manager.rb +236 -0
  88. data/lib/swarm_sdk/patterns/agent_observer.rb +160 -0
  89. data/lib/swarm_sdk/plugin.rb +95 -5
  90. data/lib/swarm_sdk/result.rb +52 -0
  91. data/lib/swarm_sdk/snapshot.rb +6 -6
  92. data/lib/swarm_sdk/snapshot_from_events.rb +13 -2
  93. data/lib/swarm_sdk/state_restorer.rb +136 -151
  94. data/lib/swarm_sdk/state_snapshot.rb +65 -100
  95. data/lib/swarm_sdk/swarm/agent_initializer.rb +181 -137
  96. data/lib/swarm_sdk/swarm/builder.rb +44 -578
  97. data/lib/swarm_sdk/swarm/executor.rb +213 -0
  98. data/lib/swarm_sdk/swarm/hook_triggers.rb +151 -0
  99. data/lib/swarm_sdk/swarm/logging_callbacks.rb +341 -0
  100. data/lib/swarm_sdk/swarm/mcp_configurator.rb +7 -4
  101. data/lib/swarm_sdk/swarm/tool_configurator.rb +58 -140
  102. data/lib/swarm_sdk/swarm.rb +203 -683
  103. data/lib/swarm_sdk/tools/bash.rb +14 -8
  104. data/lib/swarm_sdk/tools/delegate.rb +61 -43
  105. data/lib/swarm_sdk/tools/edit.rb +8 -13
  106. data/lib/swarm_sdk/tools/glob.rb +12 -4
  107. data/lib/swarm_sdk/tools/grep.rb +7 -0
  108. data/lib/swarm_sdk/tools/multi_edit.rb +15 -11
  109. data/lib/swarm_sdk/tools/path_resolver.rb +51 -2
  110. data/lib/swarm_sdk/tools/read.rb +16 -18
  111. data/lib/swarm_sdk/tools/registry.rb +122 -10
  112. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +9 -5
  113. data/lib/swarm_sdk/tools/stores/storage.rb +0 -6
  114. data/lib/swarm_sdk/tools/todo_write.rb +7 -0
  115. data/lib/swarm_sdk/tools/web_fetch.rb +20 -17
  116. data/lib/swarm_sdk/tools/write.rb +8 -13
  117. data/lib/swarm_sdk/version.rb +1 -1
  118. data/lib/swarm_sdk/{node → workflow}/agent_config.rb +1 -1
  119. data/lib/swarm_sdk/workflow/builder.rb +192 -0
  120. data/lib/swarm_sdk/workflow/executor.rb +497 -0
  121. data/lib/swarm_sdk/{node/builder.rb → workflow/node_builder.rb} +7 -5
  122. data/lib/swarm_sdk/{node → workflow}/transformer_executor.rb +5 -3
  123. data/lib/swarm_sdk/{node_orchestrator.rb → workflow.rb} +152 -456
  124. data/lib/swarm_sdk.rb +294 -108
  125. data/rubocop/cop/security/no_reflection_methods.rb +1 -1
  126. data/swarm_cli.gemspec +1 -1
  127. data/swarm_memory.gemspec +8 -3
  128. data/swarm_sdk.gemspec +6 -4
  129. data/team_full.yml +124 -320
  130. metadata +42 -14
  131. data/lib/swarm_memory/chat_extension.rb +0 -34
  132. data/lib/swarm_memory/tools/memory_multi_edit.rb +0 -281
  133. data/lib/swarm_sdk/providers/openai_with_responses.rb +0 -589
  134. /data/lib/swarm_memory/{errors.rb → error.rb} +0 -0
data/lib/swarm_sdk.rb CHANGED
@@ -17,6 +17,27 @@ require "async/semaphore"
17
17
  require "ruby_llm"
18
18
  require "ruby_llm/mcp"
19
19
 
20
+ # Patch ruby_llm-mcp's Zeitwerk loader to ignore railtie.rb when Rails is not present
21
+ # This prevents NameError when eager loading outside of Rails applications
22
+ # Can be removed once https://github.com/parruda/ruby_llm-mcp/issues/XXX is fixed
23
+ unless defined?(Rails)
24
+ require "zeitwerk"
25
+ mcp_loader = nil
26
+ Zeitwerk::Registry.loaders.each { |l| mcp_loader = l if l.tag == "RubyLLM-mcp" }
27
+ if mcp_loader
28
+ mcp_gem_dir = Gem.loaded_specs["ruby_llm-mcp"]&.gem_dir
29
+ if mcp_gem_dir
30
+ railtie_path = File.join(mcp_gem_dir, "lib", "ruby_llm", "mcp", "railtie.rb")
31
+ mcp_loader.ignore(railtie_path)
32
+ end
33
+ end
34
+ end
35
+
36
+ # Configure Faraday to use async-http adapter by default
37
+ # This ensures HTTP requests are fiber-aware and don't block the Async scheduler
38
+ # when SwarmSDK executes LLM requests within Async/Sync blocks
39
+ require "async/http/faraday/default"
40
+
20
41
  require_relative "swarm_sdk/version"
21
42
 
22
43
  require "zeitwerk"
@@ -42,14 +63,262 @@ module SwarmSDK
42
63
  class StateError < Error; end
43
64
 
44
65
  class << self
45
- # Settings for SwarmSDK (global configuration)
46
- attr_accessor :settings
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
97
+
98
+ # Register a global agent definition
99
+ #
100
+ # Declares an agent configuration that can be referenced by name in any
101
+ # swarm definition. This allows defining agents in separate files and
102
+ # composing them into swarms without duplication.
103
+ #
104
+ # The registered block uses the Agent::Builder DSL and is executed when
105
+ # the agent is referenced in a swarm definition.
106
+ #
107
+ # @param name [Symbol, String] Agent name (will be symbolized)
108
+ # @yield Agent configuration block using Agent::Builder DSL
109
+ # @return [void]
110
+ # @raise [ArgumentError] If no block is provided
111
+ #
112
+ # @example Register agent in separate file
113
+ # # agents/backend.rb
114
+ # SwarmSDK.agent :backend do
115
+ # model "claude-sonnet-4"
116
+ # description "Backend API developer"
117
+ # system_prompt "You build REST APIs"
118
+ # tools :Read, :Edit, :Bash
119
+ # delegates_to :database
120
+ # end
121
+ #
122
+ # @example Reference in swarm definition
123
+ # # swarm.rb
124
+ # require_relative "agents/backend"
125
+ #
126
+ # SwarmSDK.build do
127
+ # name "Dev Team"
128
+ # lead :backend
129
+ #
130
+ # agent :backend # Pulls from registry
131
+ # end
132
+ #
133
+ # @example Extend registered agent with overrides
134
+ # SwarmSDK.build do
135
+ # name "Extended Team"
136
+ # lead :backend
137
+ #
138
+ # agent :backend do
139
+ # # Registry config applied first, then this block
140
+ # tools :CustomTool # Adds to existing tools
141
+ # delegates_to :cache # Adds delegation target
142
+ # end
143
+ # end
144
+ #
145
+ # @see AgentRegistry
146
+ def agent(name, &block)
147
+ AgentRegistry.register(name, &block)
148
+ end
149
+
150
+ # Clear the global agent registry
151
+ #
152
+ # Removes all registered agent definitions. Primarily useful for testing
153
+ # to ensure clean state between tests.
154
+ #
155
+ # @return [void]
156
+ #
157
+ # @example In test teardown
158
+ # def teardown
159
+ # SwarmSDK.clear_agent_registry!
160
+ # end
161
+ def clear_agent_registry!
162
+ AgentRegistry.clear
163
+ end
164
+
165
+ # Register a custom tool for use in swarms
166
+ #
167
+ # Provides a simple way to add tools without creating a full plugin.
168
+ # Tools can be registered with an explicit name or the name can be
169
+ # inferred from the class name.
170
+ #
171
+ # Custom tools are available to any agent that includes them in their
172
+ # tools configuration, just like built-in tools.
173
+ #
174
+ # @overload register_tool(tool_class)
175
+ # Register a tool with name inferred from class name
176
+ # @param tool_class [Class] Tool class (must inherit from RubyLLM::Tool)
177
+ # @return [Symbol] The registered tool name
178
+ #
179
+ # @overload register_tool(name, tool_class)
180
+ # Register a tool with explicit name
181
+ # @param name [Symbol, String] Tool name
182
+ # @param tool_class [Class] Tool class (must inherit from RubyLLM::Tool)
183
+ # @return [Symbol] The registered tool name
184
+ #
185
+ # @raise [ArgumentError] If tool_class doesn't inherit from RubyLLM::Tool
186
+ # @raise [ArgumentError] If a tool with the same name is already registered
187
+ # @raise [ArgumentError] If the name conflicts with a built-in or plugin tool
188
+ #
189
+ # @example Register with inferred name
190
+ # class WeatherTool < RubyLLM::Tool
191
+ # description "Get weather for a city"
192
+ # param :city, type: "string", required: true
193
+ #
194
+ # def execute(city:)
195
+ # "Weather in #{city}: Sunny, 72°F"
196
+ # end
197
+ # end
198
+ #
199
+ # SwarmSDK.register_tool(WeatherTool) # Registers as :Weather
200
+ #
201
+ # @example Register with explicit name
202
+ # SwarmSDK.register_tool(:GetWeather, WeatherTool)
203
+ #
204
+ # @example Tool with agent context
205
+ # class ContextAwareTool < RubyLLM::Tool
206
+ # # Declare what context the tool needs
207
+ # def self.creation_requirements
208
+ # [:agent_name, :directory]
209
+ # end
210
+ #
211
+ # def initialize(agent_name:, directory:)
212
+ # super()
213
+ # @agent_name = agent_name
214
+ # @directory = directory
215
+ # end
216
+ #
217
+ # description "Shows agent context"
218
+ # def execute
219
+ # "Agent: #{@agent_name} in #{@directory}"
220
+ # end
221
+ # end
222
+ #
223
+ # SwarmSDK.register_tool(ContextAwareTool)
224
+ #
225
+ # @example Use registered tool in a swarm
226
+ # SwarmSDK.register_tool(WeatherTool)
227
+ #
228
+ # swarm = SwarmSDK.build do
229
+ # name "Weather Assistant"
230
+ # lead :assistant
231
+ #
232
+ # agent :assistant do
233
+ # model "claude-sonnet-4"
234
+ # description "Weather helper"
235
+ # tools :Weather, :Read # Custom + built-in tools
236
+ # end
237
+ # end
238
+ #
239
+ # @see CustomToolRegistry For the underlying registry
240
+ # @see Plugin For complex tool systems requiring storage or lifecycle hooks
241
+ def register_tool(name_or_class, tool_class = nil)
242
+ if tool_class.nil?
243
+ # Single argument: infer name from class
244
+ tool_class = name_or_class
245
+ name = CustomToolRegistry.infer_name(tool_class)
246
+ else
247
+ # Two arguments: explicit name
248
+ name = name_or_class.to_sym
249
+ end
250
+
251
+ CustomToolRegistry.register(name, tool_class)
252
+ name
253
+ end
47
254
 
48
- # Main entry point for DSL
255
+ # Check if a custom tool is registered
256
+ #
257
+ # @param name [Symbol, String] Tool name
258
+ # @return [Boolean] true if the tool is registered
259
+ #
260
+ # @example
261
+ # SwarmSDK.register_tool(WeatherTool)
262
+ # SwarmSDK.custom_tool_registered?(:Weather) #=> true
263
+ # SwarmSDK.custom_tool_registered?(:Unknown) #=> false
264
+ def custom_tool_registered?(name)
265
+ CustomToolRegistry.registered?(name)
266
+ end
267
+
268
+ # Get all registered custom tool names
269
+ #
270
+ # @return [Array<Symbol>] List of registered custom tool names
271
+ #
272
+ # @example
273
+ # SwarmSDK.register_tool(WeatherTool)
274
+ # SwarmSDK.register_tool(StockTool)
275
+ # SwarmSDK.custom_tools #=> [:Weather, :Stock]
276
+ def custom_tools
277
+ CustomToolRegistry.tool_names
278
+ end
279
+
280
+ # Unregister a custom tool
281
+ #
282
+ # @param name [Symbol, String] Tool name to unregister
283
+ # @return [Class, nil] The unregistered tool class, or nil if not found
284
+ #
285
+ # @example
286
+ # SwarmSDK.register_tool(WeatherTool)
287
+ # SwarmSDK.unregister_tool(:Weather)
288
+ # SwarmSDK.custom_tool_registered?(:Weather) #=> false
289
+ def unregister_tool(name)
290
+ CustomToolRegistry.unregister(name)
291
+ end
292
+
293
+ # Clear all registered custom tools
294
+ #
295
+ # Removes all custom tool registrations. Primarily useful for testing
296
+ # to ensure clean state between tests.
297
+ #
298
+ # @return [void]
299
+ #
300
+ # @example In test teardown
301
+ # def teardown
302
+ # SwarmSDK.clear_custom_tools!
303
+ # end
304
+ def clear_custom_tools!
305
+ CustomToolRegistry.clear
306
+ end
307
+
308
+ # Main entry point for DSL - builds simple multi-agent swarms
309
+ #
310
+ # @return [Swarm] Always returns a Swarm instance
49
311
  def build(allow_filesystem_tools: nil, &block)
50
312
  Swarm::Builder.build(allow_filesystem_tools: allow_filesystem_tools, &block)
51
313
  end
52
314
 
315
+ # Entry point for building multi-stage workflows
316
+ #
317
+ # @return [Workflow] Always returns a Workflow instance
318
+ def workflow(allow_filesystem_tools: nil, &block)
319
+ Workflow::Builder.build(allow_filesystem_tools: allow_filesystem_tools, &block)
320
+ end
321
+
53
322
  # Validate YAML configuration without creating a swarm
54
323
  #
55
324
  # Performs comprehensive validation of YAML configuration including:
@@ -149,7 +418,12 @@ module SwarmSDK
149
418
  #
150
419
  # @param yaml_content [String] YAML configuration content
151
420
  # @param base_dir [String, Pathname] Base directory for resolving agent file paths (default: Dir.pwd)
152
- # @return [Swarm, NodeOrchestrator] Configured swarm or orchestrator instance
421
+ # @param allow_filesystem_tools [Boolean, nil] Whether to allow filesystem tools (nil uses global setting)
422
+ # @param env_interpolation [Boolean, nil] Whether to interpolate environment variables.
423
+ # When nil, uses the global SwarmSDK.config.env_interpolation setting.
424
+ # When true, interpolates ${VAR} and ${VAR:=default} patterns.
425
+ # When false, skips interpolation entirely.
426
+ # @return [Swarm, Workflow] Configured swarm or workflow instance
153
427
  # @raise [ConfigurationError] If YAML is invalid or configuration is incorrect
154
428
  #
155
429
  # @example Load from YAML string
@@ -171,8 +445,11 @@ module SwarmSDK
171
445
  # @example Load with default base_dir (Dir.pwd)
172
446
  # yaml = File.read("config.yml")
173
447
  # swarm = SwarmSDK.load(yaml) # base_dir defaults to Dir.pwd
174
- def load(yaml_content, base_dir: Dir.pwd, allow_filesystem_tools: nil)
175
- config = Configuration.new(yaml_content, base_dir: base_dir)
448
+ #
449
+ # @example Load without environment variable interpolation
450
+ # swarm = SwarmSDK.load(yaml, env_interpolation: false)
451
+ def load(yaml_content, base_dir: Dir.pwd, allow_filesystem_tools: nil, env_interpolation: nil)
452
+ config = Configuration.new(yaml_content, base_dir: base_dir, env_interpolation: env_interpolation)
176
453
  config.load_and_validate
177
454
  swarm = config.to_swarm(allow_filesystem_tools: allow_filesystem_tools)
178
455
 
@@ -194,7 +471,12 @@ module SwarmSDK
194
471
  # loading swarms from configuration files.
195
472
  #
196
473
  # @param path [String, Pathname] Path to YAML configuration file
197
- # @return [Swarm, NodeOrchestrator] Configured swarm or orchestrator instance
474
+ # @param allow_filesystem_tools [Boolean, nil] Whether to allow filesystem tools (nil uses global setting)
475
+ # @param env_interpolation [Boolean, nil] Whether to interpolate environment variables.
476
+ # When nil, uses the global SwarmSDK.config.env_interpolation setting.
477
+ # When true, interpolates ${VAR} and ${VAR:=default} patterns.
478
+ # When false, skips interpolation entirely.
479
+ # @return [Swarm, Workflow] Configured swarm or workflow instance
198
480
  # @raise [ConfigurationError] If file not found or configuration invalid
199
481
  #
200
482
  # @example
@@ -203,8 +485,11 @@ module SwarmSDK
203
485
  #
204
486
  # @example With absolute path
205
487
  # swarm = SwarmSDK.load_file("/absolute/path/config.yml")
206
- def load_file(path, allow_filesystem_tools: nil)
207
- config = Configuration.load_file(path)
488
+ #
489
+ # @example Load without environment variable interpolation
490
+ # swarm = SwarmSDK.load_file("config.yml", env_interpolation: false)
491
+ def load_file(path, allow_filesystem_tools: nil, env_interpolation: nil)
492
+ config = Configuration.load_file(path, env_interpolation: env_interpolation)
208
493
  swarm = config.to_swarm(allow_filesystem_tools: allow_filesystem_tools)
209
494
 
210
495
  # Apply hooks if any are configured (YAML-only feature)
@@ -218,21 +503,6 @@ module SwarmSDK
218
503
  swarm
219
504
  end
220
505
 
221
- # Configure SwarmSDK global settings
222
- def configure
223
- self.settings ||= Settings.new
224
- yield(settings)
225
- end
226
-
227
- # Reset settings to defaults
228
- def reset_settings!
229
- self.settings = Settings.new
230
- end
231
-
232
- # Alias for backward compatibility
233
- alias_method :configuration, :settings
234
- alias_method :reset_configuration!, :reset_settings!
235
-
236
506
  private
237
507
 
238
508
  # Check if hooks are configured in the configuration
@@ -407,88 +677,4 @@ module SwarmSDK
407
677
  error_hash.compact
408
678
  end
409
679
  end
410
-
411
- # Settings class for SwarmSDK global settings (not to be confused with Configuration for YAML loading)
412
- class Settings
413
- # WebFetch tool LLM processing configuration
414
- attr_accessor :webfetch_provider, :webfetch_model, :webfetch_base_url, :webfetch_max_tokens
415
-
416
- # Filesystem tools control
417
- attr_accessor :allow_filesystem_tools
418
-
419
- def initialize
420
- @webfetch_provider = nil
421
- @webfetch_model = nil
422
- @webfetch_base_url = nil
423
- @webfetch_max_tokens = 4096
424
- @allow_filesystem_tools = parse_env_bool("SWARM_SDK_ALLOW_FILESYSTEM_TOOLS", default: true)
425
- end
426
-
427
- # Check if WebFetch LLM processing is enabled
428
- def webfetch_llm_enabled?
429
- !@webfetch_provider.nil? && !@webfetch_model.nil?
430
- end
431
-
432
- private
433
-
434
- def parse_env_bool(key, default:)
435
- return default unless ENV.key?(key)
436
-
437
- value = ENV[key].to_s.downcase
438
- return true if ["true", "yes", "1", "on", "enabled"].include?(value)
439
- return false if ["false", "no", "0", "off", "disabled"].include?(value)
440
-
441
- default
442
- end
443
- end
444
-
445
- # Initialize default settings
446
- self.settings = Settings.new
447
- end
448
-
449
- # Automatically configure RubyLLM from environment variables
450
- # This makes SwarmSDK "just work" when users set standard ENV variables
451
- RubyLLM.configure do |config|
452
- # Only set if config not already set (||= handles nil ENV values gracefully)
453
-
454
- # OpenAI
455
- config.openai_api_key ||= ENV["OPENAI_API_KEY"]
456
- config.openai_api_base ||= ENV["OPENAI_API_BASE"]
457
- config.openai_organization_id ||= ENV["OPENAI_ORG_ID"]
458
- config.openai_project_id ||= ENV["OPENAI_PROJECT_ID"]
459
-
460
- # Anthropic
461
- config.anthropic_api_key ||= ENV["ANTHROPIC_API_KEY"]
462
-
463
- # Google Gemini
464
- config.gemini_api_key ||= ENV["GEMINI_API_KEY"]
465
-
466
- # Google Vertex AI (note: vertexai, not vertex_ai)
467
- config.vertexai_project_id ||= ENV["GOOGLE_CLOUD_PROJECT"] || ENV["VERTEXAI_PROJECT_ID"]
468
- config.vertexai_location ||= ENV["GOOGLE_CLOUD_LOCATION"] || ENV["VERTEXAI_LOCATION"]
469
-
470
- # DeepSeek
471
- config.deepseek_api_key ||= ENV["DEEPSEEK_API_KEY"]
472
-
473
- # Mistral
474
- config.mistral_api_key ||= ENV["MISTRAL_API_KEY"]
475
-
476
- # Perplexity
477
- config.perplexity_api_key ||= ENV["PERPLEXITY_API_KEY"]
478
-
479
- # OpenRouter
480
- config.openrouter_api_key ||= ENV["OPENROUTER_API_KEY"]
481
-
482
- # AWS Bedrock
483
- config.bedrock_api_key ||= ENV["AWS_ACCESS_KEY_ID"]
484
- config.bedrock_secret_key ||= ENV["AWS_SECRET_ACCESS_KEY"]
485
- config.bedrock_region ||= ENV["AWS_REGION"]
486
- config.bedrock_session_token ||= ENV["AWS_SESSION_TOKEN"]
487
-
488
- # Ollama (local)
489
- config.ollama_api_base ||= ENV["OLLAMA_API_BASE"]
490
-
491
- # GPUStack (local)
492
- config.gpustack_api_base ||= ENV["GPUSTACK_API_BASE"]
493
- config.gpustack_api_key ||= ENV["GPUSTACK_API_KEY"]
494
680
  end
@@ -24,7 +24,7 @@ module RuboCop
24
24
 
25
25
  # Match method calls
26
26
  def on_send(node)
27
- banned_methods = [:instance_variable_get, :instance_variable_set, :send]
27
+ banned_methods = [:instance_variable_get, :instance_variable_set, :send, :const_set, :const_get]
28
28
 
29
29
  method_name = node.method_name
30
30
  return unless banned_methods.include?(method_name)
data/swarm_cli.gemspec CHANGED
@@ -36,7 +36,7 @@ Gem::Specification.new do |spec|
36
36
 
37
37
  spec.add_dependency("fast-mcp", "~> 1.6")
38
38
  spec.add_dependency("pastel")
39
- spec.add_dependency("swarm_sdk", "~> 2.2")
39
+ spec.add_dependency("swarm_sdk", "~> 2.5.1")
40
40
  spec.add_dependency("tty-box")
41
41
  spec.add_dependency("tty-cursor")
42
42
  spec.add_dependency("tty-link")
data/swarm_memory.gemspec CHANGED
@@ -14,7 +14,12 @@ Gem::Specification.new do |spec|
14
14
  spec.metadata["source_code_uri"] = "https://github.com/parruda/claude-swarm"
15
15
  spec.metadata["changelog_uri"] = "https://github.com/parruda/claude-swarm/blob/main/docs/v2/CHANGELOG.swarm_memory.md"
16
16
 
17
- spec.files = Dir["lib/**/*", "LICENSE"]
17
+ spec.files = IO.popen(["git", "ls-files", "-z"], chdir: __dir__, err: IO::NULL) do |ls|
18
+ ls.readlines("\x0", chomp: true).select do |f|
19
+ (f == "lib/swarm_memory.rb") ||
20
+ f.match?(%r{\Alib/swarm_memory/}) || (f == "LICENSE")
21
+ end
22
+ end
18
23
  spec.require_paths = ["lib"]
19
24
  spec.required_ruby_version = ">= 3.2.0"
20
25
 
@@ -22,7 +27,7 @@ Gem::Specification.new do |spec|
22
27
  spec.add_dependency("async", "~> 2.0")
23
28
  spec.add_dependency("informers", "~> 1.2.1")
24
29
  spec.add_dependency("rice", "~> 4.6.0")
25
- spec.add_dependency("ruby_llm", "~> 1.9")
26
- spec.add_dependency("swarm_sdk", "~> 2.2")
30
+ spec.add_dependency("ruby_llm_swarm", "~> 1.9.5")
31
+ spec.add_dependency("swarm_sdk", "~> 2.5.1")
27
32
  spec.add_dependency("zeitwerk", "~> 2.6")
28
33
  end
data/swarm_sdk.gemspec CHANGED
@@ -23,11 +23,10 @@ Gem::Specification.new do |spec|
23
23
  spec.metadata["source_code_uri"] = "https://github.com/parruda/claude-swarm"
24
24
  spec.metadata["changelog_uri"] = "https://github.com/parruda/claude-swarm/blob/main/docs/v2/CHANGELOG.swarm_sdk.md"
25
25
 
26
- File.basename(__FILE__)
27
26
  spec.files = IO.popen(["git", "ls-files", "-z"], chdir: __dir__, err: IO::NULL) do |ls|
28
27
  ls.readlines("\x0", chomp: true).select do |f|
29
28
  (f == "lib/swarm_sdk.rb") ||
30
- f.match?(%r{\Alib/swarm_sdk/})
29
+ f.match?(%r{\Alib/swarm_sdk/}) || (f == "LICENSE")
31
30
  end
32
31
  end
33
32
  # spec.bindir = "exe"
@@ -35,7 +34,10 @@ Gem::Specification.new do |spec|
35
34
  spec.require_paths = ["lib"]
36
35
 
37
36
  spec.add_dependency("async", "~> 2.0")
38
- spec.add_dependency("ruby_llm", "~> 1.9")
39
- spec.add_dependency("ruby_llm-mcp", "~> 0.7")
37
+ spec.add_dependency("async-http-faraday", "~> 0.22")
38
+ spec.add_dependency("faraday-follow_redirects", "~> 0.4")
39
+ spec.add_dependency("openssl", "~> 3.3.2")
40
+ spec.add_dependency("ruby_llm_swarm", "~> 1.9.5")
41
+ spec.add_dependency("ruby_llm_swarm-mcp", "~> 0.8.1")
40
42
  spec.add_dependency("zeitwerk", "~> 2.6")
41
43
  end