swarm_memory 2.1.5 → 2.1.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 +4 -4
- data/lib/swarm_memory/version.rb +1 -1
- metadata +5 -184
- data/lib/claude_swarm/base_executor.rb +0 -133
- data/lib/claude_swarm/claude_code_executor.rb +0 -349
- data/lib/claude_swarm/claude_mcp_server.rb +0 -78
- data/lib/claude_swarm/cli.rb +0 -697
- data/lib/claude_swarm/commands/ps.rb +0 -215
- data/lib/claude_swarm/commands/show.rb +0 -139
- data/lib/claude_swarm/configuration.rb +0 -373
- data/lib/claude_swarm/hooks/session_start_hook.rb +0 -42
- data/lib/claude_swarm/json_handler.rb +0 -91
- data/lib/claude_swarm/mcp_generator.rb +0 -230
- data/lib/claude_swarm/openai/chat_completion.rb +0 -256
- data/lib/claude_swarm/openai/executor.rb +0 -256
- data/lib/claude_swarm/openai/responses.rb +0 -319
- data/lib/claude_swarm/orchestrator.rb +0 -878
- data/lib/claude_swarm/process_tracker.rb +0 -78
- data/lib/claude_swarm/session_cost_calculator.rb +0 -209
- data/lib/claude_swarm/session_path.rb +0 -42
- data/lib/claude_swarm/settings_generator.rb +0 -77
- data/lib/claude_swarm/system_utils.rb +0 -46
- data/lib/claude_swarm/templates/generation_prompt.md.erb +0 -230
- data/lib/claude_swarm/tools/reset_session_tool.rb +0 -24
- data/lib/claude_swarm/tools/session_info_tool.rb +0 -24
- data/lib/claude_swarm/tools/task_tool.rb +0 -63
- data/lib/claude_swarm/version.rb +0 -5
- data/lib/claude_swarm/worktree_manager.rb +0 -475
- data/lib/claude_swarm/yaml_loader.rb +0 -22
- data/lib/claude_swarm.rb +0 -67
- data/lib/swarm_cli/cli.rb +0 -201
- data/lib/swarm_cli/command_registry.rb +0 -61
- data/lib/swarm_cli/commands/mcp_serve.rb +0 -130
- data/lib/swarm_cli/commands/mcp_tools.rb +0 -148
- data/lib/swarm_cli/commands/migrate.rb +0 -55
- data/lib/swarm_cli/commands/run.rb +0 -173
- data/lib/swarm_cli/config_loader.rb +0 -98
- data/lib/swarm_cli/formatters/human_formatter.rb +0 -781
- data/lib/swarm_cli/formatters/json_formatter.rb +0 -51
- data/lib/swarm_cli/interactive_repl.rb +0 -924
- data/lib/swarm_cli/mcp_serve_options.rb +0 -44
- data/lib/swarm_cli/mcp_tools_options.rb +0 -59
- data/lib/swarm_cli/migrate_options.rb +0 -54
- data/lib/swarm_cli/migrator.rb +0 -132
- data/lib/swarm_cli/options.rb +0 -151
- data/lib/swarm_cli/ui/components/agent_badge.rb +0 -33
- data/lib/swarm_cli/ui/components/content_block.rb +0 -120
- data/lib/swarm_cli/ui/components/divider.rb +0 -57
- data/lib/swarm_cli/ui/components/panel.rb +0 -62
- data/lib/swarm_cli/ui/components/usage_stats.rb +0 -70
- data/lib/swarm_cli/ui/formatters/cost.rb +0 -49
- data/lib/swarm_cli/ui/formatters/number.rb +0 -58
- data/lib/swarm_cli/ui/formatters/text.rb +0 -77
- data/lib/swarm_cli/ui/formatters/time.rb +0 -73
- data/lib/swarm_cli/ui/icons.rb +0 -36
- data/lib/swarm_cli/ui/renderers/event_renderer.rb +0 -188
- data/lib/swarm_cli/ui/state/agent_color_cache.rb +0 -45
- data/lib/swarm_cli/ui/state/depth_tracker.rb +0 -40
- data/lib/swarm_cli/ui/state/spinner_manager.rb +0 -170
- data/lib/swarm_cli/ui/state/usage_tracker.rb +0 -62
- data/lib/swarm_cli/version.rb +0 -5
- data/lib/swarm_cli.rb +0 -46
- data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -127
- data/lib/swarm_sdk/agent/builder.rb +0 -552
- data/lib/swarm_sdk/agent/chat.rb +0 -774
- data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -268
- data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
- data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
- data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -78
- data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -233
- data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
- data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
- data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -136
- data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
- data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -98
- data/lib/swarm_sdk/agent/context.rb +0 -116
- data/lib/swarm_sdk/agent/context_manager.rb +0 -315
- data/lib/swarm_sdk/agent/definition.rb +0 -477
- data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -182
- data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
- data/lib/swarm_sdk/builders/base_builder.rb +0 -409
- data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
- data/lib/swarm_sdk/concerns/cleanupable.rb +0 -39
- data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
- data/lib/swarm_sdk/concerns/validatable.rb +0 -55
- data/lib/swarm_sdk/configuration/parser.rb +0 -353
- data/lib/swarm_sdk/configuration/translator.rb +0 -255
- data/lib/swarm_sdk/configuration.rb +0 -135
- data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
- data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -106
- data/lib/swarm_sdk/context_compactor.rb +0 -335
- data/lib/swarm_sdk/context_management/builder.rb +0 -128
- data/lib/swarm_sdk/context_management/context.rb +0 -328
- data/lib/swarm_sdk/defaults.rb +0 -196
- data/lib/swarm_sdk/events_to_messages.rb +0 -199
- data/lib/swarm_sdk/hooks/adapter.rb +0 -359
- data/lib/swarm_sdk/hooks/context.rb +0 -197
- data/lib/swarm_sdk/hooks/definition.rb +0 -80
- data/lib/swarm_sdk/hooks/error.rb +0 -29
- data/lib/swarm_sdk/hooks/executor.rb +0 -146
- data/lib/swarm_sdk/hooks/registry.rb +0 -147
- data/lib/swarm_sdk/hooks/result.rb +0 -150
- data/lib/swarm_sdk/hooks/shell_executor.rb +0 -255
- data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
- data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
- data/lib/swarm_sdk/log_collector.rb +0 -227
- data/lib/swarm_sdk/log_stream.rb +0 -127
- data/lib/swarm_sdk/markdown_parser.rb +0 -75
- data/lib/swarm_sdk/model_aliases.json +0 -8
- data/lib/swarm_sdk/models.json +0 -1
- data/lib/swarm_sdk/models.rb +0 -120
- data/lib/swarm_sdk/node_context.rb +0 -245
- data/lib/swarm_sdk/observer/builder.rb +0 -81
- data/lib/swarm_sdk/observer/config.rb +0 -45
- data/lib/swarm_sdk/observer/manager.rb +0 -236
- data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
- data/lib/swarm_sdk/permissions/config.rb +0 -239
- data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
- data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
- data/lib/swarm_sdk/permissions/validator.rb +0 -173
- data/lib/swarm_sdk/permissions_builder.rb +0 -122
- data/lib/swarm_sdk/plugin.rb +0 -309
- data/lib/swarm_sdk/plugin_registry.rb +0 -101
- data/lib/swarm_sdk/proc_helpers.rb +0 -53
- data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -117
- data/lib/swarm_sdk/restore_result.rb +0 -65
- data/lib/swarm_sdk/result.rb +0 -123
- data/lib/swarm_sdk/snapshot.rb +0 -156
- data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
- data/lib/swarm_sdk/state_restorer.rb +0 -476
- data/lib/swarm_sdk/state_snapshot.rb +0 -334
- data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -683
- data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -167
- data/lib/swarm_sdk/swarm/builder.rb +0 -249
- data/lib/swarm_sdk/swarm/executor.rb +0 -213
- data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -150
- data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -340
- data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -154
- data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
- data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -358
- data/lib/swarm_sdk/swarm.rb +0 -717
- data/lib/swarm_sdk/swarm_loader.rb +0 -145
- data/lib/swarm_sdk/swarm_registry.rb +0 -136
- data/lib/swarm_sdk/tools/bash.rb +0 -282
- data/lib/swarm_sdk/tools/clock.rb +0 -44
- data/lib/swarm_sdk/tools/delegate.rb +0 -267
- data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
- data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
- data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
- data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
- data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
- data/lib/swarm_sdk/tools/edit.rb +0 -145
- data/lib/swarm_sdk/tools/glob.rb +0 -166
- data/lib/swarm_sdk/tools/grep.rb +0 -235
- data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
- data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -163
- data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
- data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
- data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
- data/lib/swarm_sdk/tools/read.rb +0 -261
- data/lib/swarm_sdk/tools/registry.rb +0 -205
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
- data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
- data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -272
- data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
- data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
- data/lib/swarm_sdk/tools/think.rb +0 -98
- data/lib/swarm_sdk/tools/todo_write.rb +0 -235
- data/lib/swarm_sdk/tools/web_fetch.rb +0 -262
- data/lib/swarm_sdk/tools/write.rb +0 -112
- data/lib/swarm_sdk/utils.rb +0 -68
- data/lib/swarm_sdk/validation_result.rb +0 -33
- data/lib/swarm_sdk/version.rb +0 -5
- data/lib/swarm_sdk/workflow/agent_config.rb +0 -79
- data/lib/swarm_sdk/workflow/builder.rb +0 -143
- data/lib/swarm_sdk/workflow/executor.rb +0 -497
- data/lib/swarm_sdk/workflow/node_builder.rb +0 -555
- data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -249
- data/lib/swarm_sdk/workflow.rb +0 -554
- data/lib/swarm_sdk.rb +0 -524
data/lib/swarm_sdk/swarm.rb
DELETED
|
@@ -1,717 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module SwarmSDK
|
|
4
|
-
# Swarm orchestrates multiple AI agents with shared rate limiting and coordination.
|
|
5
|
-
#
|
|
6
|
-
# This is the main user-facing API for SwarmSDK. Users create swarms using:
|
|
7
|
-
# - Ruby DSL: SwarmSDK.build { ... } (Recommended)
|
|
8
|
-
# - YAML String: SwarmSDK.load(yaml, base_dir:)
|
|
9
|
-
# - YAML File: SwarmSDK.load_file(path)
|
|
10
|
-
# - Direct API: Swarm.new + add_agent (Advanced)
|
|
11
|
-
#
|
|
12
|
-
# ## Ruby DSL (Recommended)
|
|
13
|
-
#
|
|
14
|
-
# swarm = SwarmSDK.build do
|
|
15
|
-
# name "Development Team"
|
|
16
|
-
# lead :backend
|
|
17
|
-
#
|
|
18
|
-
# agent :backend do
|
|
19
|
-
# model "gpt-5"
|
|
20
|
-
# description "Backend developer"
|
|
21
|
-
# prompt "You build APIs"
|
|
22
|
-
# tools :Read, :Edit, :Bash
|
|
23
|
-
# end
|
|
24
|
-
# end
|
|
25
|
-
# result = swarm.execute("Build authentication")
|
|
26
|
-
#
|
|
27
|
-
# ## YAML String API
|
|
28
|
-
#
|
|
29
|
-
# yaml = File.read("swarm.yml")
|
|
30
|
-
# swarm = SwarmSDK.load(yaml, base_dir: "/path/to/project")
|
|
31
|
-
# result = swarm.execute("Build authentication")
|
|
32
|
-
#
|
|
33
|
-
# ## YAML File API (Convenience)
|
|
34
|
-
#
|
|
35
|
-
# swarm = SwarmSDK.load_file("swarm.yml")
|
|
36
|
-
# result = swarm.execute("Build authentication")
|
|
37
|
-
#
|
|
38
|
-
# ## Direct API (Advanced)
|
|
39
|
-
#
|
|
40
|
-
# swarm = Swarm.new(name: "Development Team")
|
|
41
|
-
#
|
|
42
|
-
# backend_agent = Agent::Definition.new(:backend, {
|
|
43
|
-
# description: "Backend developer",
|
|
44
|
-
# model: "gpt-5",
|
|
45
|
-
# system_prompt: "You build APIs and databases...",
|
|
46
|
-
# tools: [:Read, :Edit, :Bash],
|
|
47
|
-
# delegates_to: [:database]
|
|
48
|
-
# })
|
|
49
|
-
# swarm.add_agent(backend_agent)
|
|
50
|
-
#
|
|
51
|
-
# swarm.lead = :backend
|
|
52
|
-
# result = swarm.execute("Build authentication")
|
|
53
|
-
#
|
|
54
|
-
# ## Architecture
|
|
55
|
-
#
|
|
56
|
-
# All APIs converge on Agent::Definition for validation.
|
|
57
|
-
# Swarm delegates to specialized concerns:
|
|
58
|
-
# - Agent::Definition: Validates configuration, builds system prompts
|
|
59
|
-
# - AgentInitializer: Complex 5-pass agent setup
|
|
60
|
-
# - ToolConfigurator: Tool creation and permissions (via AgentInitializer)
|
|
61
|
-
# - McpConfigurator: MCP client management (via AgentInitializer)
|
|
62
|
-
#
|
|
63
|
-
class Swarm
|
|
64
|
-
include Concerns::Snapshotable
|
|
65
|
-
include Concerns::Validatable
|
|
66
|
-
include Concerns::Cleanupable
|
|
67
|
-
include LoggingCallbacks
|
|
68
|
-
include HookTriggers
|
|
69
|
-
|
|
70
|
-
# Backward compatibility aliases - use Defaults module for new code
|
|
71
|
-
DEFAULT_MCP_LOG_LEVEL = Defaults::Logging::MCP_LOG_LEVEL
|
|
72
|
-
|
|
73
|
-
# Default tools available to all agents
|
|
74
|
-
DEFAULT_TOOLS = ToolConfigurator::DEFAULT_TOOLS
|
|
75
|
-
|
|
76
|
-
attr_reader :name, :agents, :lead_agent, :mcp_clients, :delegation_instances, :agent_definitions, :swarm_id, :parent_swarm_id, :swarm_registry, :scratchpad_storage, :allow_filesystem_tools, :hook_registry, :global_semaphore, :plugin_storages, :config_for_hooks, :observer_configs
|
|
77
|
-
attr_accessor :delegation_call_stack
|
|
78
|
-
|
|
79
|
-
# Check if scratchpad tools are enabled
|
|
80
|
-
#
|
|
81
|
-
# @return [Boolean]
|
|
82
|
-
def scratchpad_enabled?
|
|
83
|
-
@scratchpad_mode == :enabled
|
|
84
|
-
end
|
|
85
|
-
attr_writer :config_for_hooks
|
|
86
|
-
|
|
87
|
-
# Check if first message has been sent (for system reminder injection)
|
|
88
|
-
#
|
|
89
|
-
# @return [Boolean]
|
|
90
|
-
def first_message_sent?
|
|
91
|
-
@first_message_sent
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
# Set first message sent flag (used by snapshot/restore)
|
|
95
|
-
#
|
|
96
|
-
# @param value [Boolean] New value
|
|
97
|
-
# @return [void]
|
|
98
|
-
attr_writer :first_message_sent
|
|
99
|
-
|
|
100
|
-
# Class-level MCP log level configuration
|
|
101
|
-
@mcp_log_level = DEFAULT_MCP_LOG_LEVEL
|
|
102
|
-
@mcp_logging_configured = false
|
|
103
|
-
|
|
104
|
-
class << self
|
|
105
|
-
attr_accessor :mcp_log_level
|
|
106
|
-
|
|
107
|
-
# Configure MCP client logging globally
|
|
108
|
-
#
|
|
109
|
-
# This should be called before creating any swarms that use MCP servers.
|
|
110
|
-
# The configuration is global and affects all MCP clients.
|
|
111
|
-
#
|
|
112
|
-
# @param level [Integer] Log level (Logger::DEBUG, Logger::INFO, Logger::WARN, Logger::ERROR, Logger::FATAL)
|
|
113
|
-
# @return [void]
|
|
114
|
-
def configure_mcp_logging(level = DEFAULT_MCP_LOG_LEVEL)
|
|
115
|
-
@mcp_log_level = level
|
|
116
|
-
apply_mcp_logging_configuration
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# Apply MCP logging configuration to RubyLLM::MCP
|
|
120
|
-
#
|
|
121
|
-
# @return [void]
|
|
122
|
-
def apply_mcp_logging_configuration
|
|
123
|
-
return if @mcp_logging_configured
|
|
124
|
-
|
|
125
|
-
RubyLLM::MCP.configure do |config|
|
|
126
|
-
config.log_level = @mcp_log_level
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
@mcp_logging_configured = true
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
# Initialize a new Swarm
|
|
134
|
-
#
|
|
135
|
-
# @param name [String] Human-readable swarm name
|
|
136
|
-
# @param swarm_id [String, nil] Optional swarm ID (auto-generated if not provided)
|
|
137
|
-
# @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
|
|
140
|
-
# @param scratchpad [Tools::Stores::Scratchpad, nil] Optional scratchpad instance (for testing/internal use)
|
|
141
|
-
# @param scratchpad_mode [Symbol, String] Scratchpad mode (:enabled or :disabled). :per_node not allowed for non-node swarms.
|
|
142
|
-
# @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: Defaults::Concurrency::GLOBAL_LIMIT, default_local_concurrency: Defaults::Concurrency::LOCAL_LIMIT, scratchpad: nil, scratchpad_mode: :enabled, allow_filesystem_tools: nil)
|
|
144
|
-
@name = name
|
|
145
|
-
@swarm_id = swarm_id || generate_swarm_id(name)
|
|
146
|
-
@parent_swarm_id = parent_swarm_id
|
|
147
|
-
@global_concurrency = global_concurrency
|
|
148
|
-
@default_local_concurrency = default_local_concurrency
|
|
149
|
-
|
|
150
|
-
# Handle scratchpad_mode parameter
|
|
151
|
-
# For Swarm: :enabled or :disabled (not :per_node - that's for nodes)
|
|
152
|
-
@scratchpad_mode = validate_swarm_scratchpad_mode(scratchpad_mode)
|
|
153
|
-
|
|
154
|
-
# Resolve allow_filesystem_tools with priority:
|
|
155
|
-
# 1. Explicit parameter (if not nil)
|
|
156
|
-
# 2. Global settings
|
|
157
|
-
@allow_filesystem_tools = if allow_filesystem_tools.nil?
|
|
158
|
-
SwarmSDK.settings.allow_filesystem_tools
|
|
159
|
-
else
|
|
160
|
-
allow_filesystem_tools
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
# Swarm registry for managing sub-swarms (initialized later if needed)
|
|
164
|
-
@swarm_registry = nil
|
|
165
|
-
|
|
166
|
-
# Delegation call stack for circular dependency detection
|
|
167
|
-
@delegation_call_stack = []
|
|
168
|
-
|
|
169
|
-
# Shared semaphore for all agents
|
|
170
|
-
@global_semaphore = Async::Semaphore.new(@global_concurrency)
|
|
171
|
-
|
|
172
|
-
# Shared scratchpad storage for all agents (volatile)
|
|
173
|
-
# Use provided scratchpad storage (for testing) or create volatile one based on mode
|
|
174
|
-
@scratchpad_storage = if scratchpad
|
|
175
|
-
scratchpad # Testing/internal use - explicit instance provided
|
|
176
|
-
elsif @scratchpad_mode == :enabled
|
|
177
|
-
Tools::Stores::ScratchpadStorage.new
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
# Per-agent plugin storages (persistent)
|
|
181
|
-
# Format: { plugin_name => { agent_name => storage } }
|
|
182
|
-
# Will be populated when agents are initialized
|
|
183
|
-
@plugin_storages = {}
|
|
184
|
-
|
|
185
|
-
# Hook registry for named hooks and swarm defaults
|
|
186
|
-
@hook_registry = Hooks::Registry.new
|
|
187
|
-
|
|
188
|
-
# Register default logging hooks
|
|
189
|
-
register_default_logging_callbacks
|
|
190
|
-
|
|
191
|
-
# Agent definitions and instances
|
|
192
|
-
@agent_definitions = {}
|
|
193
|
-
@agents = {}
|
|
194
|
-
@delegation_instances = {} # { "delegate@delegator" => Agent::Chat }
|
|
195
|
-
@agents_initialized = false
|
|
196
|
-
@agent_contexts = {}
|
|
197
|
-
|
|
198
|
-
# MCP clients per agent (for cleanup)
|
|
199
|
-
@mcp_clients = Hash.new { |h, k| h[k] = [] }
|
|
200
|
-
|
|
201
|
-
@lead_agent = nil
|
|
202
|
-
|
|
203
|
-
# Track if first message has been sent
|
|
204
|
-
@first_message_sent = false
|
|
205
|
-
|
|
206
|
-
# Track if agent_start events have been emitted
|
|
207
|
-
# This prevents duplicate emissions and ensures events are emitted when logging is ready
|
|
208
|
-
@agent_start_events_emitted = false
|
|
209
|
-
|
|
210
|
-
# Observer agent configurations
|
|
211
|
-
@observer_configs = []
|
|
212
|
-
@observer_manager = nil
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
# Add an agent to the swarm
|
|
216
|
-
#
|
|
217
|
-
# Accepts only Agent::Definition objects. This ensures all validation
|
|
218
|
-
# happens in a single place (Agent::Definition) and keeps the API clean.
|
|
219
|
-
#
|
|
220
|
-
# If the definition doesn't specify max_concurrent_tools, the swarm's
|
|
221
|
-
# default_local_concurrency is applied.
|
|
222
|
-
#
|
|
223
|
-
# @param definition [Agent::Definition] Fully configured agent definition
|
|
224
|
-
# @return [self]
|
|
225
|
-
#
|
|
226
|
-
# @example
|
|
227
|
-
# definition = Agent::Definition.new(:backend, {
|
|
228
|
-
# description: "Backend developer",
|
|
229
|
-
# model: "gpt-5",
|
|
230
|
-
# system_prompt: "You build APIs"
|
|
231
|
-
# })
|
|
232
|
-
# swarm.add_agent(definition)
|
|
233
|
-
def add_agent(definition)
|
|
234
|
-
unless definition.is_a?(Agent::Definition)
|
|
235
|
-
raise ArgumentError, "Expected Agent::Definition, got #{definition.class}"
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
name = definition.name
|
|
239
|
-
raise ConfigurationError, "Agent '#{name}' already exists" if @agent_definitions.key?(name)
|
|
240
|
-
|
|
241
|
-
# Apply swarm's default_local_concurrency if max_concurrent_tools not set
|
|
242
|
-
definition.max_concurrent_tools = @default_local_concurrency if definition.max_concurrent_tools.nil?
|
|
243
|
-
|
|
244
|
-
@agent_definitions[name] = definition
|
|
245
|
-
self
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
# Set the lead agent (entry point for swarm execution)
|
|
249
|
-
#
|
|
250
|
-
# @param name [Symbol, String] Name of agent to make lead
|
|
251
|
-
# @return [self]
|
|
252
|
-
def lead=(name)
|
|
253
|
-
name = name.to_sym
|
|
254
|
-
|
|
255
|
-
unless @agent_definitions.key?(name)
|
|
256
|
-
raise ConfigurationError, "Cannot set lead: agent '#{name}' not found"
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
@lead_agent = name
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
# Execute a task using the lead agent
|
|
263
|
-
#
|
|
264
|
-
# The lead agent can delegate to other agents via tool calls,
|
|
265
|
-
# and the entire swarm coordinates with shared rate limiting.
|
|
266
|
-
# Supports reprompting via swarm_stop hooks.
|
|
267
|
-
#
|
|
268
|
-
# By default, this method blocks until execution completes. Set wait: false
|
|
269
|
-
# to return an Async::Task immediately, enabling cancellation via task.stop.
|
|
270
|
-
#
|
|
271
|
-
# @param prompt [String] Task to execute
|
|
272
|
-
# @param wait [Boolean] If true (default), blocks until execution completes.
|
|
273
|
-
# If false, returns Async::Task immediately for non-blocking execution.
|
|
274
|
-
# @yield [Hash] Log entry if block given (for streaming)
|
|
275
|
-
# @return [Result, Async::Task] Result if wait: true, Async::Task if wait: false
|
|
276
|
-
#
|
|
277
|
-
# @example Blocking execution (default)
|
|
278
|
-
# result = swarm.execute("Build auth")
|
|
279
|
-
# puts result.content
|
|
280
|
-
#
|
|
281
|
-
# @example Non-blocking execution with cancellation
|
|
282
|
-
# task = swarm.execute("Build auth", wait: false) { |event| puts event }
|
|
283
|
-
# # ... do other work ...
|
|
284
|
-
# task.stop # Cancel anytime
|
|
285
|
-
# result = task.wait # Returns nil for cancelled tasks
|
|
286
|
-
def execute(prompt, wait: true, &block)
|
|
287
|
-
raise ConfigurationError, "No lead agent set. Set lead= first." unless @lead_agent
|
|
288
|
-
|
|
289
|
-
logs = []
|
|
290
|
-
current_prompt = prompt
|
|
291
|
-
has_logging = block_given?
|
|
292
|
-
|
|
293
|
-
# Save original Fiber storage for restoration (preserves parent context for nested swarms)
|
|
294
|
-
original_fiber_storage = {
|
|
295
|
-
execution_id: Fiber[:execution_id],
|
|
296
|
-
swarm_id: Fiber[:swarm_id],
|
|
297
|
-
parent_swarm_id: Fiber[:parent_swarm_id],
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
# Set fiber-local execution context
|
|
301
|
-
# Use ||= to inherit parent's execution_id if one exists (for mini-swarms)
|
|
302
|
-
Fiber[:execution_id] ||= generate_execution_id
|
|
303
|
-
Fiber[:swarm_id] = @swarm_id
|
|
304
|
-
Fiber[:parent_swarm_id] = @parent_swarm_id
|
|
305
|
-
|
|
306
|
-
# Setup logging FIRST if block given (so swarm_start event can be emitted)
|
|
307
|
-
setup_logging(logs, &block) if has_logging
|
|
308
|
-
|
|
309
|
-
# Setup observer execution if any observers configured
|
|
310
|
-
# MUST happen AFTER setup_logging (which clears Fiber[:log_subscriptions])
|
|
311
|
-
setup_observer_execution if @observer_configs.any?
|
|
312
|
-
|
|
313
|
-
# Trigger swarm_start hooks (before any execution)
|
|
314
|
-
current_prompt = apply_swarm_start_hooks(current_prompt)
|
|
315
|
-
|
|
316
|
-
# Trigger first_message hooks on first execution
|
|
317
|
-
unless @first_message_sent
|
|
318
|
-
trigger_first_message(current_prompt)
|
|
319
|
-
@first_message_sent = true
|
|
320
|
-
end
|
|
321
|
-
|
|
322
|
-
# Lazy initialization of agents (with optional logging)
|
|
323
|
-
initialize_agents unless @agents_initialized
|
|
324
|
-
|
|
325
|
-
# Emit agent_start events if agents were initialized before logging was set up
|
|
326
|
-
emit_retroactive_agent_start_events if has_logging
|
|
327
|
-
|
|
328
|
-
# Delegate to Executor for actual execution
|
|
329
|
-
executor = Executor.new(self)
|
|
330
|
-
@current_task = executor.run(
|
|
331
|
-
current_prompt,
|
|
332
|
-
wait: wait,
|
|
333
|
-
logs: logs,
|
|
334
|
-
has_logging: has_logging,
|
|
335
|
-
original_fiber_storage: original_fiber_storage,
|
|
336
|
-
)
|
|
337
|
-
end
|
|
338
|
-
|
|
339
|
-
# Get an agent chat instance by name
|
|
340
|
-
#
|
|
341
|
-
# @param name [Symbol, String] Agent name
|
|
342
|
-
# @return [AgentChat] Agent chat instance
|
|
343
|
-
def agent(name)
|
|
344
|
-
name = name.to_sym
|
|
345
|
-
initialize_agents unless @agents_initialized
|
|
346
|
-
|
|
347
|
-
@agents[name] || raise(AgentNotFoundError, "Agent '#{name}' not found")
|
|
348
|
-
end
|
|
349
|
-
|
|
350
|
-
# Get an agent definition by name
|
|
351
|
-
#
|
|
352
|
-
# Use this to access and modify agent configuration:
|
|
353
|
-
# swarm.agent_definition(:backend).bypass_permissions = true
|
|
354
|
-
#
|
|
355
|
-
# @param name [Symbol, String] Agent name
|
|
356
|
-
# @return [AgentDefinition] Agent definition object
|
|
357
|
-
def agent_definition(name)
|
|
358
|
-
name = name.to_sym
|
|
359
|
-
|
|
360
|
-
@agent_definitions[name] || raise(AgentNotFoundError, "Agent '#{name}' not found")
|
|
361
|
-
end
|
|
362
|
-
|
|
363
|
-
# Get all agent names
|
|
364
|
-
#
|
|
365
|
-
# @return [Array<Symbol>] Agent names
|
|
366
|
-
def agent_names
|
|
367
|
-
@agent_definitions.keys
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
# Implement Snapshotable interface
|
|
371
|
-
def primary_agents
|
|
372
|
-
@agents
|
|
373
|
-
end
|
|
374
|
-
|
|
375
|
-
def delegation_instances_hash
|
|
376
|
-
@delegation_instances
|
|
377
|
-
end
|
|
378
|
-
|
|
379
|
-
# NOTE: validate() and emit_validation_warnings() are provided by Concerns::Validatable
|
|
380
|
-
# Note: cleanup() is provided by Concerns::Cleanupable
|
|
381
|
-
|
|
382
|
-
# Register a named hook that can be referenced in agent configurations
|
|
383
|
-
#
|
|
384
|
-
# Named hooks are stored in the registry and can be referenced by symbol
|
|
385
|
-
# in agent YAML configurations or programmatically.
|
|
386
|
-
#
|
|
387
|
-
# @param name [Symbol] Unique hook name
|
|
388
|
-
# @param block [Proc] Hook implementation
|
|
389
|
-
# @return [self]
|
|
390
|
-
#
|
|
391
|
-
# @example Register a validation hook
|
|
392
|
-
# swarm.register_hook(:validate_code) do |context|
|
|
393
|
-
# raise SwarmSDK::Hooks::Error, "Invalid" unless valid?(context.tool_call)
|
|
394
|
-
# end
|
|
395
|
-
def register_hook(name, &block)
|
|
396
|
-
@hook_registry.register(name, &block)
|
|
397
|
-
self
|
|
398
|
-
end
|
|
399
|
-
|
|
400
|
-
# Reset context for all agents
|
|
401
|
-
#
|
|
402
|
-
# Clears conversation history for all agents. This is used by composable swarms
|
|
403
|
-
# to reset sub-swarm context when keep_context: false is specified.
|
|
404
|
-
#
|
|
405
|
-
# @return [void]
|
|
406
|
-
def reset_context!
|
|
407
|
-
@agents.each_value do |agent_chat|
|
|
408
|
-
agent_chat.clear_conversation if agent_chat.respond_to?(:clear_conversation)
|
|
409
|
-
end
|
|
410
|
-
end
|
|
411
|
-
|
|
412
|
-
# Add observer configuration
|
|
413
|
-
#
|
|
414
|
-
# Called by Swarm::Builder to register observer agent configurations.
|
|
415
|
-
# Validates that the referenced agent exists.
|
|
416
|
-
#
|
|
417
|
-
# @param config [Observer::Config] Observer configuration
|
|
418
|
-
# @return [void]
|
|
419
|
-
def add_observer_config(config)
|
|
420
|
-
validate_observer_agent(config.agent_name)
|
|
421
|
-
@observer_configs << config
|
|
422
|
-
end
|
|
423
|
-
|
|
424
|
-
# Wait for all observer tasks to complete
|
|
425
|
-
#
|
|
426
|
-
# Called by Executor to wait for observer agents before cleanup.
|
|
427
|
-
# Safe to call even if no observers are configured.
|
|
428
|
-
#
|
|
429
|
-
# @return [void]
|
|
430
|
-
def wait_for_observers
|
|
431
|
-
@observer_manager&.wait_for_completion
|
|
432
|
-
end
|
|
433
|
-
|
|
434
|
-
# Cleanup observer subscriptions
|
|
435
|
-
#
|
|
436
|
-
# Called by Executor.cleanup_after_execution to unsubscribe observers.
|
|
437
|
-
# Matches the MCP cleanup pattern.
|
|
438
|
-
#
|
|
439
|
-
# @return [void]
|
|
440
|
-
def cleanup_observers
|
|
441
|
-
@observer_manager&.cleanup
|
|
442
|
-
@observer_manager = nil
|
|
443
|
-
end
|
|
444
|
-
|
|
445
|
-
# Create snapshot of current conversation state
|
|
446
|
-
#
|
|
447
|
-
# Returns a Snapshot object containing:
|
|
448
|
-
# - All agent conversations (@messages arrays)
|
|
449
|
-
# - Agent context state (warnings, compression, TodoWrite tracking, skills)
|
|
450
|
-
# - Delegation instance conversations
|
|
451
|
-
# - Scratchpad contents (volatile shared storage)
|
|
452
|
-
# - Read tracking state (which files each agent has read with digests)
|
|
453
|
-
# - Memory read tracking state (which memory entries each agent has read with digests)
|
|
454
|
-
#
|
|
455
|
-
# Configuration (agent definitions, tools, prompts) stays in your YAML/DSL
|
|
456
|
-
# and is NOT included in snapshots.
|
|
457
|
-
#
|
|
458
|
-
# @return [Snapshot] Snapshot object with convenient serialization methods
|
|
459
|
-
#
|
|
460
|
-
# @example Save snapshot to JSON file
|
|
461
|
-
# snapshot = swarm.snapshot
|
|
462
|
-
# snapshot.write_to_file("session.json")
|
|
463
|
-
#
|
|
464
|
-
# @example Convert to hash or JSON string
|
|
465
|
-
# snapshot = swarm.snapshot
|
|
466
|
-
# hash = snapshot.to_hash
|
|
467
|
-
# json_string = snapshot.to_json
|
|
468
|
-
def snapshot
|
|
469
|
-
StateSnapshot.new(self).snapshot
|
|
470
|
-
end
|
|
471
|
-
|
|
472
|
-
# Restore conversation state from snapshot
|
|
473
|
-
#
|
|
474
|
-
# Accepts a Snapshot object, hash, or JSON string. Validates compatibility
|
|
475
|
-
# between snapshot and current swarm configuration, restores agent conversations,
|
|
476
|
-
# context state, scratchpad, and read tracking. Returns RestoreResult with
|
|
477
|
-
# warnings about any agents that couldn't be restored due to configuration
|
|
478
|
-
# mismatches.
|
|
479
|
-
#
|
|
480
|
-
# The swarm must be created with the SAME configuration (agent definitions,
|
|
481
|
-
# tools, prompts) as when the snapshot was created. Only conversation state
|
|
482
|
-
# is restored from the snapshot.
|
|
483
|
-
#
|
|
484
|
-
# @param snapshot [Snapshot, Hash, String] Snapshot object, hash, or JSON string
|
|
485
|
-
# @return [RestoreResult] Result with warnings about skipped agents
|
|
486
|
-
#
|
|
487
|
-
# @example Restore from Snapshot object
|
|
488
|
-
# swarm = SwarmSDK.build { ... } # Same config as snapshot
|
|
489
|
-
# snapshot = Snapshot.from_file("session.json")
|
|
490
|
-
# result = swarm.restore(snapshot)
|
|
491
|
-
# if result.success?
|
|
492
|
-
# puts "All agents restored"
|
|
493
|
-
# else
|
|
494
|
-
# puts result.summary
|
|
495
|
-
# result.warnings.each { |w| puts " - #{w[:message]}" }
|
|
496
|
-
# end
|
|
497
|
-
#
|
|
498
|
-
# Restore swarm state from snapshot
|
|
499
|
-
#
|
|
500
|
-
# By default, uses current system prompts from agent definitions (YAML + SDK defaults + plugin injections).
|
|
501
|
-
# Set preserve_system_prompts: true to use historical prompts from snapshot.
|
|
502
|
-
#
|
|
503
|
-
# @param snapshot [Snapshot, Hash, String] Snapshot object, hash, or JSON string
|
|
504
|
-
# @param preserve_system_prompts [Boolean] Use historical system prompts instead of current config (default: false)
|
|
505
|
-
# @return [RestoreResult] Result with warnings about partial restores
|
|
506
|
-
def restore(snapshot, preserve_system_prompts: false)
|
|
507
|
-
StateRestorer.new(self, snapshot, preserve_system_prompts: preserve_system_prompts).restore
|
|
508
|
-
end
|
|
509
|
-
|
|
510
|
-
# Override swarm IDs for composable swarms
|
|
511
|
-
#
|
|
512
|
-
# Used by SwarmLoader to set hierarchical IDs when loading sub-swarms.
|
|
513
|
-
# This is called after the swarm is built to ensure proper parent/child relationships.
|
|
514
|
-
#
|
|
515
|
-
# @param swarm_id [String] New swarm ID
|
|
516
|
-
# @param parent_swarm_id [String] New parent swarm ID
|
|
517
|
-
# @return [void]
|
|
518
|
-
def override_swarm_ids(swarm_id:, parent_swarm_id:)
|
|
519
|
-
@swarm_id = swarm_id
|
|
520
|
-
@parent_swarm_id = parent_swarm_id
|
|
521
|
-
end
|
|
522
|
-
|
|
523
|
-
# Set swarm registry for composable swarms
|
|
524
|
-
#
|
|
525
|
-
# Used by Builder to set the registry after swarm creation.
|
|
526
|
-
# This must be called before agent initialization to enable swarm delegation.
|
|
527
|
-
#
|
|
528
|
-
# @param registry [SwarmRegistry] Configured swarm registry
|
|
529
|
-
# @return [void]
|
|
530
|
-
attr_writer :swarm_registry
|
|
531
|
-
|
|
532
|
-
# --- Internal API (for Executor use only) ---
|
|
533
|
-
# Hook triggers for swarm lifecycle events are provided by HookTriggers module
|
|
534
|
-
|
|
535
|
-
private
|
|
536
|
-
|
|
537
|
-
# Apply swarm_start hooks to prompt
|
|
538
|
-
#
|
|
539
|
-
# @param prompt [String] Original prompt
|
|
540
|
-
# @return [String] Modified prompt (possibly with hook context appended)
|
|
541
|
-
def apply_swarm_start_hooks(prompt)
|
|
542
|
-
swarm_start_result = trigger_swarm_start(prompt)
|
|
543
|
-
if swarm_start_result&.replace?
|
|
544
|
-
"#{prompt}\n\n<hook-context>\n#{swarm_start_result.value}\n</hook-context>"
|
|
545
|
-
else
|
|
546
|
-
prompt
|
|
547
|
-
end
|
|
548
|
-
end
|
|
549
|
-
|
|
550
|
-
# Validate that observer agent exists
|
|
551
|
-
#
|
|
552
|
-
# @param agent_name [Symbol] Name of the observer agent
|
|
553
|
-
# @raise [ConfigurationError] If agent not found
|
|
554
|
-
# @return [void]
|
|
555
|
-
def validate_observer_agent(agent_name)
|
|
556
|
-
return if @agent_definitions.key?(agent_name)
|
|
557
|
-
|
|
558
|
-
raise ConfigurationError,
|
|
559
|
-
"Observer agent '#{agent_name}' not found. " \
|
|
560
|
-
"Define the agent first with `agent :#{agent_name} do ... end`"
|
|
561
|
-
end
|
|
562
|
-
|
|
563
|
-
# Setup observer manager and subscriptions
|
|
564
|
-
#
|
|
565
|
-
# Creates Observer::Manager and registers event subscriptions.
|
|
566
|
-
# Must be called AFTER setup_logging (which clears Fiber[:log_subscriptions]).
|
|
567
|
-
#
|
|
568
|
-
# @return [void]
|
|
569
|
-
def setup_observer_execution
|
|
570
|
-
@observer_manager = Observer::Manager.new(self)
|
|
571
|
-
@observer_configs.each { |c| @observer_manager.add_config(c) }
|
|
572
|
-
@observer_manager.setup
|
|
573
|
-
end
|
|
574
|
-
|
|
575
|
-
# Validate and normalize scratchpad mode for Swarm
|
|
576
|
-
#
|
|
577
|
-
# Regular Swarms support :enabled or :disabled.
|
|
578
|
-
# Rejects :per_node since it only makes sense for Workflow with multiple nodes.
|
|
579
|
-
#
|
|
580
|
-
# @param value [Symbol, String] Scratchpad mode (strings from YAML converted to symbols)
|
|
581
|
-
# @return [Symbol] :enabled or :disabled
|
|
582
|
-
# @raise [ArgumentError] If :per_node used, or invalid value
|
|
583
|
-
def validate_swarm_scratchpad_mode(value)
|
|
584
|
-
# Convert strings from YAML to symbols
|
|
585
|
-
value = value.to_sym if value.is_a?(String)
|
|
586
|
-
|
|
587
|
-
case value
|
|
588
|
-
when :enabled, :disabled
|
|
589
|
-
value
|
|
590
|
-
when :per_node
|
|
591
|
-
raise ArgumentError,
|
|
592
|
-
"scratchpad: :per_node is only valid for Workflow with nodes. " \
|
|
593
|
-
"For regular Swarms, use :enabled or :disabled."
|
|
594
|
-
else
|
|
595
|
-
raise ArgumentError,
|
|
596
|
-
"Invalid scratchpad mode for Swarm: #{value.inspect}. " \
|
|
597
|
-
"Use :enabled or :disabled."
|
|
598
|
-
end
|
|
599
|
-
end
|
|
600
|
-
|
|
601
|
-
# Generate a unique swarm ID from name
|
|
602
|
-
#
|
|
603
|
-
# Creates a swarm ID by sanitizing the name and appending a random suffix.
|
|
604
|
-
# Used when swarm_id is not explicitly provided.
|
|
605
|
-
#
|
|
606
|
-
# @param name [String] Swarm name
|
|
607
|
-
# @return [String] Generated swarm ID (e.g., "dev_team_a3f2b1c8")
|
|
608
|
-
def generate_swarm_id(name)
|
|
609
|
-
sanitized = name.to_s.gsub(/[^a-z0-9_-]/i, "_").downcase
|
|
610
|
-
"#{sanitized}_#{SecureRandom.hex(4)}"
|
|
611
|
-
end
|
|
612
|
-
|
|
613
|
-
# Generate a unique execution ID
|
|
614
|
-
#
|
|
615
|
-
# Creates an execution ID that uniquely identifies a single swarm.execute() call.
|
|
616
|
-
# Format: "exec_{swarm_id}_{random_hex}"
|
|
617
|
-
#
|
|
618
|
-
# @return [String] Generated execution ID (e.g., "exec_main_a3f2b1c8")
|
|
619
|
-
def generate_execution_id
|
|
620
|
-
"exec_#{@swarm_id}_#{SecureRandom.hex(8)}"
|
|
621
|
-
end
|
|
622
|
-
|
|
623
|
-
# Initialize all agents using AgentInitializer
|
|
624
|
-
#
|
|
625
|
-
# This is called automatically (lazy initialization) by execute() and agent().
|
|
626
|
-
# Delegates to AgentInitializer which handles the complex 5-pass setup.
|
|
627
|
-
#
|
|
628
|
-
# @return [void]
|
|
629
|
-
def initialize_agents
|
|
630
|
-
return if @agents_initialized
|
|
631
|
-
|
|
632
|
-
initializer = AgentInitializer.new(self)
|
|
633
|
-
|
|
634
|
-
@agents = initializer.initialize_all
|
|
635
|
-
@agent_contexts = initializer.agent_contexts
|
|
636
|
-
@agents_initialized = true
|
|
637
|
-
|
|
638
|
-
# NOTE: agent_start events are emitted in execute() when logging is set up
|
|
639
|
-
# This ensures events are never lost, even if agents are initialized early (e.g., by restore())
|
|
640
|
-
end
|
|
641
|
-
|
|
642
|
-
# Normalize tools to internal format (kept for add_agent)
|
|
643
|
-
#
|
|
644
|
-
# Handles both Ruby API (simple symbols) and YAML API (already parsed configs)
|
|
645
|
-
#
|
|
646
|
-
# @param tools [Array] Tool specifications
|
|
647
|
-
# @return [Array<Hash>] Normalized tool configs
|
|
648
|
-
def normalize_tools(tools)
|
|
649
|
-
Array(tools).map do |tool|
|
|
650
|
-
case tool
|
|
651
|
-
when Symbol, String
|
|
652
|
-
# Simple tool from Ruby API
|
|
653
|
-
{ name: tool.to_sym, permissions: nil }
|
|
654
|
-
when Hash
|
|
655
|
-
# Already in config format from YAML (has :name and :permissions keys)
|
|
656
|
-
if tool.key?(:name)
|
|
657
|
-
tool
|
|
658
|
-
else
|
|
659
|
-
# Inline permissions format: { Write: { allowed_paths: [...] } }
|
|
660
|
-
tool_name = tool.keys.first.to_sym
|
|
661
|
-
{ name: tool_name, permissions: tool[tool_name] }
|
|
662
|
-
end
|
|
663
|
-
else
|
|
664
|
-
raise ConfigurationError, "Invalid tool specification: #{tool.inspect}"
|
|
665
|
-
end
|
|
666
|
-
end
|
|
667
|
-
end
|
|
668
|
-
|
|
669
|
-
# Delegation methods for testing (delegate to concerns)
|
|
670
|
-
# These allow tests to verify behavior without depending on internal structure
|
|
671
|
-
|
|
672
|
-
# Create a tool instance (delegates to ToolConfigurator)
|
|
673
|
-
def create_tool_instance(tool_name, agent_name, directory)
|
|
674
|
-
ToolConfigurator.new(self, @scratchpad_storage, @plugin_storages).create_tool_instance(tool_name, agent_name, directory)
|
|
675
|
-
end
|
|
676
|
-
|
|
677
|
-
# Wrap tool with permissions (delegates to ToolConfigurator)
|
|
678
|
-
def wrap_tool_with_permissions(tool_instance, permissions_config, agent_definition)
|
|
679
|
-
ToolConfigurator.new(self, @scratchpad_storage, @plugin_storages).wrap_tool_with_permissions(tool_instance, permissions_config, agent_definition)
|
|
680
|
-
end
|
|
681
|
-
|
|
682
|
-
# Build MCP transport config (delegates to McpConfigurator)
|
|
683
|
-
def build_mcp_transport_config(transport_type, config)
|
|
684
|
-
McpConfigurator.new(self).build_transport_config(transport_type, config)
|
|
685
|
-
end
|
|
686
|
-
|
|
687
|
-
# Create delegation tool (delegates to AgentInitializer)
|
|
688
|
-
def create_delegation_tool(name:, description:, delegate_chat:, agent_name:)
|
|
689
|
-
AgentInitializer.new(self)
|
|
690
|
-
.create_delegation_tool(name: name, description: description, delegate_chat: delegate_chat, agent_name: agent_name)
|
|
691
|
-
end
|
|
692
|
-
|
|
693
|
-
# Extract loggable info from plugin config
|
|
694
|
-
#
|
|
695
|
-
# Attempts to extract useful information from plugin configuration
|
|
696
|
-
# for logging purposes. Handles MemoryConfig, Hashes, and other objects.
|
|
697
|
-
#
|
|
698
|
-
# @param config [Object] Plugin configuration object
|
|
699
|
-
# @return [Hash, nil] Extracted config info or nil
|
|
700
|
-
def extract_plugin_config_info(config)
|
|
701
|
-
return if config.nil?
|
|
702
|
-
|
|
703
|
-
# Handle MemoryConfig object (has directory method)
|
|
704
|
-
if config.respond_to?(:directory)
|
|
705
|
-
return { directory: config.directory }
|
|
706
|
-
end
|
|
707
|
-
|
|
708
|
-
# Handle Hash
|
|
709
|
-
if config.is_a?(Hash)
|
|
710
|
-
return config.slice(:directory, "directory", :adapter, "adapter")
|
|
711
|
-
end
|
|
712
|
-
|
|
713
|
-
# Unknown config type
|
|
714
|
-
nil
|
|
715
|
-
end
|
|
716
|
-
end
|
|
717
|
-
end
|