swarm_memory 2.1.2 → 2.1.4
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/claude_swarm/claude_mcp_server.rb +1 -0
- data/lib/claude_swarm/cli.rb +5 -18
- data/lib/claude_swarm/configuration.rb +30 -19
- data/lib/claude_swarm/mcp_generator.rb +5 -10
- data/lib/claude_swarm/openai/chat_completion.rb +4 -12
- data/lib/claude_swarm/openai/executor.rb +3 -1
- data/lib/claude_swarm/openai/responses.rb +13 -32
- data/lib/claude_swarm/version.rb +1 -1
- data/lib/swarm_cli/commands/mcp_serve.rb +2 -2
- data/lib/swarm_cli/commands/run.rb +2 -2
- data/lib/swarm_cli/config_loader.rb +14 -14
- data/lib/swarm_cli/formatters/human_formatter.rb +70 -0
- data/lib/swarm_cli/interactive_repl.rb +11 -5
- data/lib/swarm_cli/ui/icons.rb +0 -23
- data/lib/swarm_cli/version.rb +1 -1
- data/lib/swarm_memory/adapters/base.rb +4 -4
- data/lib/swarm_memory/adapters/filesystem_adapter.rb +11 -34
- data/lib/swarm_memory/core/storage_read_tracker.rb +51 -14
- data/lib/swarm_memory/integration/cli_registration.rb +3 -2
- data/lib/swarm_memory/integration/sdk_plugin.rb +98 -12
- data/lib/swarm_memory/tools/memory_edit.rb +2 -2
- data/lib/swarm_memory/tools/memory_multi_edit.rb +2 -2
- data/lib/swarm_memory/tools/memory_read.rb +3 -3
- data/lib/swarm_memory/version.rb +1 -1
- data/lib/swarm_memory.rb +6 -1
- data/lib/swarm_sdk/agent/builder.rb +91 -0
- data/lib/swarm_sdk/agent/chat.rb +540 -925
- data/lib/swarm_sdk/agent/{chat → chat_helpers}/context_tracker.rb +33 -79
- data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +204 -0
- data/lib/swarm_sdk/agent/{chat → chat_helpers}/hook_integration.rb +147 -39
- data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +78 -0
- data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +233 -0
- data/lib/swarm_sdk/agent/{chat → chat_helpers}/logging_helpers.rb +1 -1
- data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +83 -0
- data/lib/swarm_sdk/agent/{chat → chat_helpers}/system_reminder_injector.rb +22 -38
- data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +79 -0
- data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +98 -0
- data/lib/swarm_sdk/agent/context.rb +8 -4
- data/lib/swarm_sdk/agent/context_manager.rb +6 -0
- data/lib/swarm_sdk/agent/definition.rb +79 -174
- data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +182 -0
- data/lib/swarm_sdk/agent/system_prompt_builder.rb +161 -0
- data/lib/swarm_sdk/builders/base_builder.rb +409 -0
- data/lib/swarm_sdk/concerns/cleanupable.rb +39 -0
- data/lib/swarm_sdk/concerns/snapshotable.rb +67 -0
- data/lib/swarm_sdk/concerns/validatable.rb +55 -0
- data/lib/swarm_sdk/configuration/parser.rb +353 -0
- data/lib/swarm_sdk/configuration/translator.rb +255 -0
- data/lib/swarm_sdk/configuration.rb +100 -261
- data/lib/swarm_sdk/context_compactor/token_counter.rb +3 -3
- data/lib/swarm_sdk/context_compactor.rb +6 -11
- data/lib/swarm_sdk/context_management/builder.rb +128 -0
- data/lib/swarm_sdk/context_management/context.rb +328 -0
- data/lib/swarm_sdk/defaults.rb +196 -0
- data/lib/swarm_sdk/events_to_messages.rb +199 -0
- data/lib/swarm_sdk/hooks/shell_executor.rb +2 -1
- data/lib/swarm_sdk/log_collector.rb +192 -16
- data/lib/swarm_sdk/log_stream.rb +66 -8
- data/lib/swarm_sdk/model_aliases.json +4 -1
- data/lib/swarm_sdk/node_context.rb +1 -1
- data/lib/swarm_sdk/observer/builder.rb +81 -0
- data/lib/swarm_sdk/observer/config.rb +45 -0
- data/lib/swarm_sdk/observer/manager.rb +236 -0
- data/lib/swarm_sdk/patterns/agent_observer.rb +160 -0
- data/lib/swarm_sdk/plugin.rb +93 -3
- data/lib/swarm_sdk/proc_helpers.rb +53 -0
- data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -126
- data/lib/swarm_sdk/restore_result.rb +65 -0
- data/lib/swarm_sdk/snapshot.rb +156 -0
- data/lib/swarm_sdk/snapshot_from_events.rb +397 -0
- data/lib/swarm_sdk/state_restorer.rb +476 -0
- data/lib/swarm_sdk/state_snapshot.rb +334 -0
- data/lib/swarm_sdk/swarm/agent_initializer.rb +428 -79
- data/lib/swarm_sdk/swarm/all_agents_builder.rb +28 -1
- data/lib/swarm_sdk/swarm/builder.rb +69 -407
- data/lib/swarm_sdk/swarm/executor.rb +213 -0
- data/lib/swarm_sdk/swarm/hook_triggers.rb +150 -0
- data/lib/swarm_sdk/swarm/logging_callbacks.rb +340 -0
- data/lib/swarm_sdk/swarm/mcp_configurator.rb +7 -4
- data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +67 -0
- data/lib/swarm_sdk/swarm/tool_configurator.rb +88 -149
- data/lib/swarm_sdk/swarm.rb +366 -631
- data/lib/swarm_sdk/swarm_loader.rb +145 -0
- data/lib/swarm_sdk/swarm_registry.rb +136 -0
- data/lib/swarm_sdk/tools/bash.rb +11 -3
- data/lib/swarm_sdk/tools/delegate.rb +127 -24
- data/lib/swarm_sdk/tools/edit.rb +8 -13
- data/lib/swarm_sdk/tools/glob.rb +9 -1
- data/lib/swarm_sdk/tools/grep.rb +7 -0
- data/lib/swarm_sdk/tools/multi_edit.rb +15 -11
- data/lib/swarm_sdk/tools/path_resolver.rb +51 -2
- data/lib/swarm_sdk/tools/read.rb +28 -18
- data/lib/swarm_sdk/tools/registry.rb +122 -10
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +23 -2
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +23 -2
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +21 -4
- data/lib/swarm_sdk/tools/stores/read_tracker.rb +47 -12
- data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +53 -5
- data/lib/swarm_sdk/tools/stores/storage.rb +0 -6
- data/lib/swarm_sdk/tools/think.rb +4 -1
- data/lib/swarm_sdk/tools/todo_write.rb +27 -8
- data/lib/swarm_sdk/tools/web_fetch.rb +3 -2
- data/lib/swarm_sdk/tools/write.rb +8 -13
- data/lib/swarm_sdk/utils.rb +18 -0
- data/lib/swarm_sdk/validation_result.rb +33 -0
- data/lib/swarm_sdk/version.rb +1 -1
- data/lib/swarm_sdk/{node → workflow}/agent_config.rb +34 -9
- data/lib/swarm_sdk/workflow/builder.rb +143 -0
- data/lib/swarm_sdk/workflow/executor.rb +497 -0
- data/lib/swarm_sdk/{node/builder.rb → workflow/node_builder.rb} +42 -21
- data/lib/swarm_sdk/{node → workflow}/transformer_executor.rb +3 -2
- data/lib/swarm_sdk/workflow.rb +554 -0
- data/lib/swarm_sdk.rb +393 -22
- metadata +51 -16
- data/lib/swarm_memory/chat_extension.rb +0 -34
- data/lib/swarm_sdk/node_orchestrator.rb +0 -591
- data/lib/swarm_sdk/providers/openai_with_responses.rb +0 -582
|
@@ -40,7 +40,7 @@ module SwarmSDK
|
|
|
40
40
|
# Fetch tools from MCP server and register with chat
|
|
41
41
|
# Tools are already in RubyLLM::Tool format
|
|
42
42
|
tools = client.tools
|
|
43
|
-
tools.each { |tool| chat.
|
|
43
|
+
tools.each { |tool| chat.add_tool(tool) }
|
|
44
44
|
|
|
45
45
|
RubyLLM.logger.debug("SwarmSDK: Registered #{tools.size} tools from MCP server '#{server_config[:name]}' for agent #{agent_name}")
|
|
46
46
|
rescue StandardError => e
|
|
@@ -138,13 +138,16 @@ module SwarmSDK
|
|
|
138
138
|
# @param config [Hash] MCP server configuration
|
|
139
139
|
# @return [Hash] Streamable configuration
|
|
140
140
|
def build_streamable_config(config)
|
|
141
|
-
{
|
|
141
|
+
streamable_config = {
|
|
142
142
|
url: config[:url],
|
|
143
143
|
headers: config[:headers] || {},
|
|
144
144
|
version: config[:version]&.to_sym || :http2,
|
|
145
|
-
oauth: config[:oauth],
|
|
146
|
-
rate_limit: config[:rate_limit],
|
|
147
145
|
}
|
|
146
|
+
|
|
147
|
+
# Only include rate_limit if present
|
|
148
|
+
streamable_config[:rate_limit] = config[:rate_limit] if config[:rate_limit]
|
|
149
|
+
|
|
150
|
+
streamable_config
|
|
148
151
|
end
|
|
149
152
|
end
|
|
150
153
|
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SwarmSDK
|
|
4
|
+
class Swarm
|
|
5
|
+
# Builder for swarm registry in DSL
|
|
6
|
+
#
|
|
7
|
+
# Supports registering external swarms for composable swarms pattern.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# swarms do
|
|
11
|
+
# register "code_review", file: "./swarms/code_review.rb"
|
|
12
|
+
# register "testing", file: "./swarms/testing.yml", keep_context: false
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# @example Inline swarm definition
|
|
16
|
+
# swarms do
|
|
17
|
+
# register "tester" do
|
|
18
|
+
# lead :tester
|
|
19
|
+
# agent :tester do
|
|
20
|
+
# model "gpt-4o-mini"
|
|
21
|
+
# system "You test code"
|
|
22
|
+
# end
|
|
23
|
+
# end
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
class SwarmRegistryBuilder
|
|
27
|
+
attr_reader :registrations
|
|
28
|
+
|
|
29
|
+
def initialize
|
|
30
|
+
@registrations = []
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Register a swarm from file, YAML string, or inline block
|
|
34
|
+
#
|
|
35
|
+
# @param name [String, Symbol] Registration name
|
|
36
|
+
# @param file [String, nil] Path to swarm file (.rb or .yml)
|
|
37
|
+
# @param yaml [String, nil] YAML content string
|
|
38
|
+
# @param keep_context [Boolean] Whether to preserve conversation state (default: true)
|
|
39
|
+
# @yield Optional block for inline swarm definition
|
|
40
|
+
# @raise [ArgumentError] If neither file, yaml, nor block provided
|
|
41
|
+
def register(name, file: nil, yaml: nil, keep_context: true, &block)
|
|
42
|
+
# Validate that exactly one source is provided
|
|
43
|
+
sources = [file, yaml, block].compact
|
|
44
|
+
if sources.empty?
|
|
45
|
+
raise ArgumentError, "register '#{name}' requires either file:, yaml:, or a block"
|
|
46
|
+
elsif sources.size > 1
|
|
47
|
+
raise ArgumentError, "register '#{name}' accepts only one of: file:, yaml:, or block (got #{sources.size})"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Determine source type and store
|
|
51
|
+
source = if file
|
|
52
|
+
{ type: :file, value: file }
|
|
53
|
+
elsif yaml
|
|
54
|
+
{ type: :yaml, value: yaml }
|
|
55
|
+
else
|
|
56
|
+
{ type: :block, value: block }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
@registrations << {
|
|
60
|
+
name: name.to_s,
|
|
61
|
+
source: source,
|
|
62
|
+
keep_context: keep_context,
|
|
63
|
+
}
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -17,10 +17,6 @@ module SwarmSDK
|
|
|
17
17
|
:Read,
|
|
18
18
|
:Grep,
|
|
19
19
|
:Glob,
|
|
20
|
-
:TodoWrite,
|
|
21
|
-
:Think,
|
|
22
|
-
:WebFetch,
|
|
23
|
-
:Clock,
|
|
24
20
|
].freeze
|
|
25
21
|
|
|
26
22
|
# Scratchpad tools (added if scratchpad is enabled)
|
|
@@ -30,6 +26,17 @@ module SwarmSDK
|
|
|
30
26
|
:ScratchpadList,
|
|
31
27
|
].freeze
|
|
32
28
|
|
|
29
|
+
# Filesystem tools that can be globally disabled for security
|
|
30
|
+
FILESYSTEM_TOOLS = [
|
|
31
|
+
:Read,
|
|
32
|
+
:Write,
|
|
33
|
+
:Edit,
|
|
34
|
+
:MultiEdit,
|
|
35
|
+
:Grep,
|
|
36
|
+
:Glob,
|
|
37
|
+
:Bash,
|
|
38
|
+
].freeze
|
|
39
|
+
|
|
33
40
|
def initialize(swarm, scratchpad_storage, plugin_storages = {})
|
|
34
41
|
@swarm = swarm
|
|
35
42
|
@scratchpad_storage = scratchpad_storage
|
|
@@ -50,6 +57,9 @@ module SwarmSDK
|
|
|
50
57
|
|
|
51
58
|
# Create a tool instance by name
|
|
52
59
|
#
|
|
60
|
+
# Uses the Registry factory pattern to instantiate tools based on their
|
|
61
|
+
# declared requirements. This eliminates the need for a giant case statement.
|
|
62
|
+
#
|
|
53
63
|
# File tools and TodoWrite require agent context for tracking state.
|
|
54
64
|
# Scratchpad tools require shared scratchpad instance.
|
|
55
65
|
# Plugin tools are delegated to their respective plugins.
|
|
@@ -70,47 +80,14 @@ module SwarmSDK
|
|
|
70
80
|
return create_plugin_tool(tool_name_sym, agent_name, directory, chat, agent_definition)
|
|
71
81
|
end
|
|
72
82
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
Tools::Edit.new(agent_name: agent_name, directory: directory)
|
|
80
|
-
when :MultiEdit
|
|
81
|
-
Tools::MultiEdit.new(agent_name: agent_name, directory: directory)
|
|
82
|
-
when :Bash
|
|
83
|
-
Tools::Bash.new(directory: directory)
|
|
84
|
-
when :Glob
|
|
85
|
-
Tools::Glob.new(directory: directory)
|
|
86
|
-
when :Grep
|
|
87
|
-
Tools::Grep.new(directory: directory)
|
|
88
|
-
when :TodoWrite
|
|
89
|
-
Tools::TodoWrite.new(agent_name: agent_name) # TodoWrite doesn't need directory
|
|
90
|
-
when :ScratchpadWrite
|
|
91
|
-
Tools::Scratchpad::ScratchpadWrite.create_for_scratchpad(@scratchpad_storage)
|
|
92
|
-
when :ScratchpadRead
|
|
93
|
-
Tools::Scratchpad::ScratchpadRead.create_for_scratchpad(@scratchpad_storage)
|
|
94
|
-
when :ScratchpadList
|
|
95
|
-
Tools::Scratchpad::ScratchpadList.create_for_scratchpad(@scratchpad_storage)
|
|
96
|
-
when :Think
|
|
97
|
-
Tools::Think.new
|
|
98
|
-
when :Clock
|
|
99
|
-
Tools::Clock.new
|
|
100
|
-
else
|
|
101
|
-
# Regular tools - get class from registry and instantiate
|
|
102
|
-
tool_class = Tools::Registry.get(tool_name_sym)
|
|
103
|
-
raise ConfigurationError, "Unknown tool: #{tool_name}" unless tool_class
|
|
104
|
-
|
|
105
|
-
# Check if tool is marked as :special but not handled in case statement
|
|
106
|
-
if tool_class == :special
|
|
107
|
-
raise ConfigurationError,
|
|
108
|
-
"Tool '#{tool_name}' requires special initialization but is not handled in create_tool_instance. " \
|
|
109
|
-
"This is a bug - #{tool_name} should be added to the case statement above."
|
|
110
|
-
end
|
|
83
|
+
# Use Registry factory pattern - tools declare their own requirements
|
|
84
|
+
context = {
|
|
85
|
+
agent_name: agent_name,
|
|
86
|
+
directory: directory,
|
|
87
|
+
scratchpad_storage: @scratchpad_storage,
|
|
88
|
+
}
|
|
111
89
|
|
|
112
|
-
|
|
113
|
-
end
|
|
90
|
+
Tools::Registry.create(tool_name_sym, context)
|
|
114
91
|
end
|
|
115
92
|
|
|
116
93
|
# Wrap a tool instance with permissions validator if configured
|
|
@@ -144,6 +121,19 @@ module SwarmSDK
|
|
|
144
121
|
# @param agent_name [Symbol] Agent name
|
|
145
122
|
# @param agent_definition [AgentDefinition] Agent definition
|
|
146
123
|
def register_explicit_tools(chat, tool_configs, agent_name:, agent_definition:)
|
|
124
|
+
# Validate filesystem tools if globally disabled
|
|
125
|
+
unless @swarm.allow_filesystem_tools
|
|
126
|
+
# Extract tool names from hashes and convert to symbols for comparison
|
|
127
|
+
forbidden = tool_configs.map { |tc| tc[:name].to_sym }.select { |name| FILESYSTEM_TOOLS.include?(name) }
|
|
128
|
+
unless forbidden.empty?
|
|
129
|
+
raise ConfigurationError,
|
|
130
|
+
"Filesystem tools are globally disabled (SwarmSDK.settings.allow_filesystem_tools = false) " \
|
|
131
|
+
"but agent '#{agent_name}' attempts to use: #{forbidden.join(", ")}.\n\n" \
|
|
132
|
+
"This is a system-wide security setting that cannot be overridden by swarm configuration.\n" \
|
|
133
|
+
"To use filesystem tools, set SwarmSDK.settings.allow_filesystem_tools = true before loading the swarm."
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
147
137
|
tool_configs.each do |tool_config|
|
|
148
138
|
tool_name = tool_config[:name]
|
|
149
139
|
permissions_config = tool_config[:permissions]
|
|
@@ -151,14 +141,8 @@ module SwarmSDK
|
|
|
151
141
|
# Create tool instance
|
|
152
142
|
tool_instance = create_tool_instance(tool_name, agent_name, agent_definition.directory)
|
|
153
143
|
|
|
154
|
-
# Wrap with permissions
|
|
155
|
-
tool_instance
|
|
156
|
-
tool_instance,
|
|
157
|
-
permissions_config,
|
|
158
|
-
agent_definition,
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
chat.with_tool(tool_instance)
|
|
144
|
+
# Wrap with permissions and add to chat
|
|
145
|
+
wrap_and_add_tool(chat, tool_instance, permissions_config, agent_definition)
|
|
162
146
|
end
|
|
163
147
|
end
|
|
164
148
|
|
|
@@ -177,6 +161,9 @@ module SwarmSDK
|
|
|
177
161
|
# Register core default tools (unless disabled)
|
|
178
162
|
if agent_definition.disable_default_tools != true
|
|
179
163
|
DEFAULT_TOOLS.each do |tool_name|
|
|
164
|
+
# Skip filesystem tools if globally disabled
|
|
165
|
+
next if !@swarm.allow_filesystem_tools && FILESYSTEM_TOOLS.include?(tool_name)
|
|
166
|
+
|
|
180
167
|
register_tool_if_not_disabled(chat, tool_name, explicit_tool_names, agent_name, agent_definition)
|
|
181
168
|
end
|
|
182
169
|
|
|
@@ -202,19 +189,36 @@ module SwarmSDK
|
|
|
202
189
|
return if tool_disabled?(tool_name, agent_definition.disable_default_tools)
|
|
203
190
|
|
|
204
191
|
tool_instance = create_tool_instance(tool_name, agent_name, agent_definition.directory)
|
|
192
|
+
permissions_config = resolve_default_permissions(tool_name, agent_definition)
|
|
205
193
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
agent_definition.default_permissions[tool_name]
|
|
194
|
+
wrap_and_add_tool(chat, tool_instance, permissions_config, agent_definition)
|
|
195
|
+
end
|
|
209
196
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
197
|
+
# Wrap tool with permissions and add to chat
|
|
198
|
+
#
|
|
199
|
+
# This is the common pattern for registering tools:
|
|
200
|
+
# 1. Wrap with permissions validator (if configured)
|
|
201
|
+
# 2. Add to chat
|
|
202
|
+
#
|
|
203
|
+
# @param chat [Agent::Chat] The chat instance
|
|
204
|
+
# @param tool_instance [RubyLLM::Tool] Tool instance
|
|
205
|
+
# @param permissions_config [Hash, nil] Permissions configuration
|
|
206
|
+
# @param agent_definition [Agent::Definition] Agent definition
|
|
207
|
+
# @return [void]
|
|
208
|
+
def wrap_and_add_tool(chat, tool_instance, permissions_config, agent_definition)
|
|
209
|
+
tool_instance = wrap_tool_with_permissions(tool_instance, permissions_config, agent_definition)
|
|
210
|
+
chat.add_tool(tool_instance)
|
|
211
|
+
end
|
|
216
212
|
|
|
217
|
-
|
|
213
|
+
# Resolve permissions for a default/plugin tool
|
|
214
|
+
#
|
|
215
|
+
# Looks up permissions in agent-specific config first, falls back to global defaults.
|
|
216
|
+
#
|
|
217
|
+
# @param tool_name [Symbol] Tool name
|
|
218
|
+
# @param agent_definition [Agent::Definition] Agent definition
|
|
219
|
+
# @return [Hash, nil] Permissions configuration or nil
|
|
220
|
+
def resolve_default_permissions(tool_name, agent_definition)
|
|
221
|
+
agent_definition.agent_permissions[tool_name] || agent_definition.default_permissions[tool_name]
|
|
218
222
|
end
|
|
219
223
|
|
|
220
224
|
# Create a tool instance via plugin
|
|
@@ -229,15 +233,21 @@ module SwarmSDK
|
|
|
229
233
|
plugin = PluginRegistry.plugin_for_tool(tool_name)
|
|
230
234
|
raise ConfigurationError, "Tool #{tool_name} is not provided by any plugin" unless plugin
|
|
231
235
|
|
|
232
|
-
#
|
|
236
|
+
# V7.0: Extract base name for storage lookup (handles delegation instances)
|
|
237
|
+
# For primary agents: :tester → :tester (no change)
|
|
238
|
+
# For delegation instances: "tester@frontend" → :tester (extracts base)
|
|
239
|
+
base_name = agent_name.to_s.split("@").first.to_sym
|
|
240
|
+
|
|
241
|
+
# Get plugin storage using BASE NAME (shared across instances)
|
|
233
242
|
plugin_storages = @plugin_storages[plugin.name] || {}
|
|
234
|
-
storage = plugin_storages[agent_name
|
|
243
|
+
storage = plugin_storages[base_name] # ← Changed from agent_name to base_name
|
|
235
244
|
|
|
236
245
|
# Build context for tool creation
|
|
246
|
+
# Pass full agent_name for tool state tracking (TodoWrite, ReadTracker, etc.)
|
|
237
247
|
context = {
|
|
238
|
-
agent_name: agent_name,
|
|
248
|
+
agent_name: agent_name, # Full instance name for tool's use
|
|
239
249
|
directory: directory,
|
|
240
|
-
storage: storage,
|
|
250
|
+
storage: storage, # Shared storage by base name
|
|
241
251
|
agent_definition: agent_definition,
|
|
242
252
|
chat: chat,
|
|
243
253
|
tool_configurator: self,
|
|
@@ -259,10 +269,6 @@ module SwarmSDK
|
|
|
259
269
|
# Check if plugin has storage enabled for this agent
|
|
260
270
|
next unless plugin.storage_enabled?(agent_definition)
|
|
261
271
|
|
|
262
|
-
# Get plugin storage for this agent
|
|
263
|
-
plugin_storages = @plugin_storages[plugin.name] || {}
|
|
264
|
-
plugin_storages[agent_name]
|
|
265
|
-
|
|
266
272
|
# Register each tool provided by the plugin
|
|
267
273
|
plugin.tools.each do |tool_name|
|
|
268
274
|
# Skip if already registered explicitly
|
|
@@ -279,18 +285,9 @@ module SwarmSDK
|
|
|
279
285
|
agent_definition: agent_definition,
|
|
280
286
|
)
|
|
281
287
|
|
|
282
|
-
|
|
283
|
-
permissions_config = agent_definition.agent_permissions[tool_name] ||
|
|
284
|
-
agent_definition.default_permissions[tool_name]
|
|
288
|
+
permissions_config = resolve_default_permissions(tool_name, agent_definition)
|
|
285
289
|
|
|
286
|
-
|
|
287
|
-
tool_instance = wrap_tool_with_permissions(
|
|
288
|
-
tool_instance,
|
|
289
|
-
permissions_config,
|
|
290
|
-
agent_definition,
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
chat.with_tool(tool_instance)
|
|
290
|
+
wrap_and_add_tool(chat, tool_instance, permissions_config, agent_definition)
|
|
294
291
|
end
|
|
295
292
|
end
|
|
296
293
|
end
|
|
@@ -303,15 +300,21 @@ module SwarmSDK
|
|
|
303
300
|
def tool_disabled?(tool_name, disable_config)
|
|
304
301
|
return false if disable_config.nil?
|
|
305
302
|
|
|
303
|
+
# Normalize tool_name to symbol for comparison
|
|
304
|
+
tool_name_sym = tool_name.to_sym
|
|
305
|
+
|
|
306
306
|
if disable_config == true
|
|
307
307
|
# Disable all default tools
|
|
308
308
|
true
|
|
309
309
|
elsif disable_config.is_a?(Symbol)
|
|
310
310
|
# Single tool name
|
|
311
|
-
disable_config ==
|
|
311
|
+
disable_config == tool_name_sym
|
|
312
|
+
elsif disable_config.is_a?(String)
|
|
313
|
+
# Single tool name as string (from YAML)
|
|
314
|
+
disable_config.to_sym == tool_name_sym
|
|
312
315
|
elsif disable_config.is_a?(Array)
|
|
313
|
-
# Disable only tools in the array
|
|
314
|
-
disable_config.include?(
|
|
316
|
+
# Disable only tools in the array - normalize to symbols for comparison
|
|
317
|
+
disable_config.map(&:to_sym).include?(tool_name_sym)
|
|
315
318
|
else
|
|
316
319
|
false
|
|
317
320
|
end
|
|
@@ -344,76 +347,12 @@ module SwarmSDK
|
|
|
344
347
|
delegate_chat: delegate_agent,
|
|
345
348
|
agent_name: agent_name,
|
|
346
349
|
swarm: @swarm,
|
|
347
|
-
hook_registry: @hook_registry,
|
|
348
350
|
delegating_chat: chat,
|
|
349
351
|
)
|
|
350
352
|
|
|
351
|
-
chat.
|
|
352
|
-
end
|
|
353
|
-
end
|
|
354
|
-
|
|
355
|
-
# Pass 4: Configure hook system
|
|
356
|
-
#
|
|
357
|
-
# Setup the callback system for each agent.
|
|
358
|
-
def pass_4_configure_hooks
|
|
359
|
-
@agents.each do |agent_name, chat|
|
|
360
|
-
agent_definition = @agent_definitions[agent_name]
|
|
361
|
-
|
|
362
|
-
chat.setup_hooks(
|
|
363
|
-
registry: @hook_registry,
|
|
364
|
-
agent_definition: agent_definition,
|
|
365
|
-
swarm: @swarm,
|
|
366
|
-
) if chat.respond_to?(:setup_hooks)
|
|
367
|
-
end
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
# Pass 5: Apply YAML hooks if present
|
|
371
|
-
#
|
|
372
|
-
# If loaded from YAML, apply agent-specific hooks.
|
|
373
|
-
def pass_5_apply_yaml_hooks
|
|
374
|
-
return unless @config_for_hooks
|
|
375
|
-
|
|
376
|
-
@agents.each do |agent_name, chat|
|
|
377
|
-
agent_def = @config_for_hooks.agents[agent_name]
|
|
378
|
-
next unless agent_def&.hooks
|
|
379
|
-
|
|
380
|
-
HooksAdapter.apply_agent_hooks(chat, agent_name, agent_def.hooks, @swarm.name)
|
|
353
|
+
chat.add_tool(tool)
|
|
381
354
|
end
|
|
382
355
|
end
|
|
383
|
-
|
|
384
|
-
# Create an AgentChat instance
|
|
385
|
-
#
|
|
386
|
-
# NOTE: This is dead code, left over from refactoring. AgentInitializer
|
|
387
|
-
# now handles agent creation. This should be removed in a cleanup pass.
|
|
388
|
-
#
|
|
389
|
-
# @param agent_name [Symbol] Agent name
|
|
390
|
-
# @param agent_definition [AgentDefinition] Agent definition
|
|
391
|
-
# @param tool_configurator [ToolConfigurator] Tool configurator
|
|
392
|
-
# @return [AgentChat] Configured chat instance
|
|
393
|
-
def create_agent_chat(agent_name, agent_definition, tool_configurator)
|
|
394
|
-
chat = AgentChat.new(
|
|
395
|
-
definition: agent_definition.to_h,
|
|
396
|
-
global_semaphore: @global_semaphore,
|
|
397
|
-
)
|
|
398
|
-
|
|
399
|
-
# Set agent name on provider for logging (if provider supports it)
|
|
400
|
-
chat.provider.agent_name = agent_name if chat.provider.respond_to?(:agent_name=)
|
|
401
|
-
|
|
402
|
-
# Register tools
|
|
403
|
-
tool_configurator.register_all_tools(
|
|
404
|
-
chat: chat,
|
|
405
|
-
agent_name: agent_name,
|
|
406
|
-
agent_definition: agent_definition,
|
|
407
|
-
)
|
|
408
|
-
|
|
409
|
-
# Register MCP servers if any
|
|
410
|
-
if agent_definition.mcp_servers.any?
|
|
411
|
-
mcp_configurator = McpConfigurator.new(@swarm)
|
|
412
|
-
mcp_configurator.register_mcp_servers(chat, agent_definition.mcp_servers, agent_name: agent_name)
|
|
413
|
-
end
|
|
414
|
-
|
|
415
|
-
chat
|
|
416
|
-
end
|
|
417
356
|
end
|
|
418
357
|
end
|
|
419
358
|
end
|