swarm_sdk 2.7.13 → 3.0.0.alpha1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/swarm_sdk/ruby_llm_patches/chat_callbacks_patch.rb +43 -22
- data/lib/swarm_sdk/ruby_llm_patches/init.rb +6 -0
- data/lib/swarm_sdk/ruby_llm_patches/mcp_ssl_patch.rb +144 -0
- data/lib/swarm_sdk/ruby_llm_patches/tool_concurrency_patch.rb +3 -4
- data/lib/swarm_sdk/v3/agent.rb +1165 -0
- data/lib/swarm_sdk/v3/agent_builder.rb +533 -0
- data/lib/swarm_sdk/v3/agent_definition.rb +330 -0
- data/lib/swarm_sdk/v3/configuration.rb +490 -0
- data/lib/swarm_sdk/v3/debug_log.rb +86 -0
- data/lib/swarm_sdk/v3/event_stream.rb +130 -0
- data/lib/swarm_sdk/v3/hooks/context.rb +112 -0
- data/lib/swarm_sdk/v3/hooks/result.rb +115 -0
- data/lib/swarm_sdk/v3/hooks/runner.rb +128 -0
- data/lib/swarm_sdk/v3/mcp/connector.rb +183 -0
- data/lib/swarm_sdk/v3/mcp/mcp_error.rb +15 -0
- data/lib/swarm_sdk/v3/mcp/server_definition.rb +125 -0
- data/lib/swarm_sdk/v3/mcp/ssl_http_transport.rb +103 -0
- data/lib/swarm_sdk/v3/mcp/stdio_transport.rb +135 -0
- data/lib/swarm_sdk/v3/mcp/tool_proxy.rb +53 -0
- data/lib/swarm_sdk/v3/memory/adapters/base.rb +297 -0
- data/lib/swarm_sdk/v3/memory/adapters/faiss_support.rb +194 -0
- data/lib/swarm_sdk/v3/memory/adapters/filesystem_adapter.rb +212 -0
- data/lib/swarm_sdk/v3/memory/adapters/sqlite_adapter.rb +507 -0
- data/lib/swarm_sdk/v3/memory/adapters/vector_utils.rb +88 -0
- data/lib/swarm_sdk/v3/memory/card.rb +206 -0
- data/lib/swarm_sdk/v3/memory/cluster.rb +146 -0
- data/lib/swarm_sdk/v3/memory/compressor.rb +496 -0
- data/lib/swarm_sdk/v3/memory/consolidator.rb +427 -0
- data/lib/swarm_sdk/v3/memory/context_builder.rb +339 -0
- data/lib/swarm_sdk/v3/memory/edge.rb +105 -0
- data/lib/swarm_sdk/v3/memory/embedder.rb +185 -0
- data/lib/swarm_sdk/v3/memory/exposure_tracker.rb +104 -0
- data/lib/swarm_sdk/v3/memory/ingestion_pipeline.rb +394 -0
- data/lib/swarm_sdk/v3/memory/retriever.rb +289 -0
- data/lib/swarm_sdk/v3/memory/store.rb +489 -0
- data/lib/swarm_sdk/v3/skills/loader.rb +147 -0
- data/lib/swarm_sdk/v3/skills/manifest.rb +45 -0
- data/lib/swarm_sdk/v3/sub_task_agent.rb +248 -0
- data/lib/swarm_sdk/v3/tools/base.rb +80 -0
- data/lib/swarm_sdk/v3/tools/bash.rb +174 -0
- data/lib/swarm_sdk/v3/tools/clock.rb +32 -0
- data/lib/swarm_sdk/v3/tools/edit.rb +111 -0
- data/lib/swarm_sdk/v3/tools/glob.rb +96 -0
- data/lib/swarm_sdk/v3/tools/grep.rb +200 -0
- data/lib/swarm_sdk/v3/tools/message_teammate.rb +15 -0
- data/lib/swarm_sdk/v3/tools/message_user.rb +15 -0
- data/lib/swarm_sdk/v3/tools/read.rb +181 -0
- data/lib/swarm_sdk/v3/tools/read_tracker.rb +40 -0
- data/lib/swarm_sdk/v3/tools/registry.rb +208 -0
- data/lib/swarm_sdk/v3/tools/sub_task.rb +183 -0
- data/lib/swarm_sdk/v3/tools/think.rb +88 -0
- data/lib/swarm_sdk/v3/tools/write.rb +87 -0
- data/lib/swarm_sdk/v3.rb +145 -0
- metadata +84 -148
- data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -175
- data/lib/swarm_sdk/agent/builder.rb +0 -680
- data/lib/swarm_sdk/agent/chat.rb +0 -1432
- data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -375
- 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 -85
- data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -290
- 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 -134
- data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
- data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -146
- data/lib/swarm_sdk/agent/context.rb +0 -115
- data/lib/swarm_sdk/agent/context_manager.rb +0 -315
- data/lib/swarm_sdk/agent/definition.rb +0 -581
- data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -226
- data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
- data/lib/swarm_sdk/agent/tool_registry.rb +0 -189
- data/lib/swarm_sdk/agent_registry.rb +0 -146
- data/lib/swarm_sdk/builders/base_builder.rb +0 -553
- 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/config.rb +0 -367
- data/lib/swarm_sdk/configuration/parser.rb +0 -397
- data/lib/swarm_sdk/configuration/translator.rb +0 -283
- data/lib/swarm_sdk/configuration.rb +0 -165
- data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
- data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -102
- 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/custom_tool_registry.rb +0 -226
- data/lib/swarm_sdk/defaults.rb +0 -251
- 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 -256
- 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 -44002
- data/lib/swarm_sdk/models.rb +0 -161
- 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 -212
- 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 -648
- data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -195
- data/lib/swarm_sdk/swarm/builder.rb +0 -256
- data/lib/swarm_sdk/swarm/executor.rb +0 -290
- data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -151
- data/lib/swarm_sdk/swarm/lazy_delegate_chat.rb +0 -372
- data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -360
- data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -270
- data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
- data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -392
- data/lib/swarm_sdk/swarm.rb +0 -843
- data/lib/swarm_sdk/swarm_loader.rb +0 -145
- data/lib/swarm_sdk/swarm_registry.rb +0 -136
- data/lib/swarm_sdk/tools/base.rb +0 -63
- data/lib/swarm_sdk/tools/bash.rb +0 -280
- data/lib/swarm_sdk/tools/clock.rb +0 -46
- data/lib/swarm_sdk/tools/delegate.rb +0 -389
- 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 -167
- data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
- data/lib/swarm_sdk/tools/mcp_tool_stub.rb +0 -198
- 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 -273
- 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 -100
- data/lib/swarm_sdk/tools/todo_write.rb +0 -237
- data/lib/swarm_sdk/tools/web_fetch.rb +0 -264
- data/lib/swarm_sdk/tools/write.rb +0 -112
- data/lib/swarm_sdk/transcript_builder.rb +0 -278
- 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 -95
- data/lib/swarm_sdk/workflow/builder.rb +0 -227
- data/lib/swarm_sdk/workflow/executor.rb +0 -497
- data/lib/swarm_sdk/workflow/node_builder.rb +0 -593
- data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -250
- data/lib/swarm_sdk/workflow.rb +0 -589
- data/lib/swarm_sdk.rb +0 -718
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module SwarmSDK
|
|
4
|
-
# Global registry for reusable agent definitions
|
|
5
|
-
#
|
|
6
|
-
# AgentRegistry allows declaring agents in separate files that can be
|
|
7
|
-
# referenced by name in swarm definitions. This promotes code reuse and
|
|
8
|
-
# separation of concerns - agent definitions can live in dedicated files
|
|
9
|
-
# while swarm configurations compose them together.
|
|
10
|
-
#
|
|
11
|
-
# ## Usage
|
|
12
|
-
#
|
|
13
|
-
# Register agents globally (typically in separate files):
|
|
14
|
-
#
|
|
15
|
-
# # agents/backend.rb
|
|
16
|
-
# SwarmSDK.agent :backend do
|
|
17
|
-
# model "claude-sonnet-4"
|
|
18
|
-
# description "Backend API developer"
|
|
19
|
-
# system_prompt "You build REST APIs"
|
|
20
|
-
# tools :Read, :Edit, :Bash
|
|
21
|
-
# end
|
|
22
|
-
#
|
|
23
|
-
# Reference registered agents in swarm definitions:
|
|
24
|
-
#
|
|
25
|
-
# # swarm.rb
|
|
26
|
-
# SwarmSDK.build do
|
|
27
|
-
# name "Dev Team"
|
|
28
|
-
# lead :backend
|
|
29
|
-
#
|
|
30
|
-
# agent :backend # Pulls from registry
|
|
31
|
-
# end
|
|
32
|
-
#
|
|
33
|
-
# ## Override Support
|
|
34
|
-
#
|
|
35
|
-
# Registered agents can be extended with additional configuration:
|
|
36
|
-
#
|
|
37
|
-
# SwarmSDK.build do
|
|
38
|
-
# name "Dev Team"
|
|
39
|
-
# lead :backend
|
|
40
|
-
#
|
|
41
|
-
# agent :backend do
|
|
42
|
-
# # Registry config is applied first, then this block
|
|
43
|
-
# tools :CustomTool # Adds to tools from registry
|
|
44
|
-
# delegates_to :database
|
|
45
|
-
# end
|
|
46
|
-
# end
|
|
47
|
-
#
|
|
48
|
-
# @note This registry is not thread-safe. In multi-threaded environments,
|
|
49
|
-
# register all agents before spawning threads, or synchronize access
|
|
50
|
-
# externally. For typical fiber-based async usage (the default in SwarmSDK),
|
|
51
|
-
# this is not a concern.
|
|
52
|
-
#
|
|
53
|
-
class AgentRegistry
|
|
54
|
-
@agents = {}
|
|
55
|
-
|
|
56
|
-
class << self
|
|
57
|
-
# Register an agent definition block
|
|
58
|
-
#
|
|
59
|
-
# Stores a configuration block that will be executed when the agent
|
|
60
|
-
# is referenced in a swarm definition. The block receives an
|
|
61
|
-
# Agent::Builder context and can use all builder DSL methods.
|
|
62
|
-
#
|
|
63
|
-
# @param name [Symbol, String] Agent name (will be symbolized)
|
|
64
|
-
# @yield Agent configuration block using Agent::Builder DSL
|
|
65
|
-
# @return [void]
|
|
66
|
-
# @raise [ArgumentError] If no block is provided
|
|
67
|
-
# @raise [ArgumentError] If agent with same name is already registered
|
|
68
|
-
#
|
|
69
|
-
# @example Register a backend agent
|
|
70
|
-
# SwarmSDK::AgentRegistry.register(:backend) do
|
|
71
|
-
# model "claude-sonnet-4"
|
|
72
|
-
# description "Backend developer"
|
|
73
|
-
# tools :Read, :Edit, :Bash
|
|
74
|
-
# end
|
|
75
|
-
#
|
|
76
|
-
# @example Register with MCP servers
|
|
77
|
-
# SwarmSDK::AgentRegistry.register(:filesystem_agent) do
|
|
78
|
-
# model "gpt-4"
|
|
79
|
-
# description "File manager"
|
|
80
|
-
# mcp_server :fs, type: :stdio, command: "npx", args: ["-y", "@modelcontextprotocol/server-filesystem"]
|
|
81
|
-
# end
|
|
82
|
-
def register(name, &block)
|
|
83
|
-
raise ArgumentError, "Block required for agent registration" unless block_given?
|
|
84
|
-
|
|
85
|
-
sym_name = name.to_sym
|
|
86
|
-
if @agents.key?(sym_name)
|
|
87
|
-
raise ArgumentError,
|
|
88
|
-
"Agent '#{sym_name}' is already registered. " \
|
|
89
|
-
"Use SwarmSDK.clear_agent_registry! to reset, or choose a different name."
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
@agents[sym_name] = block
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
# Retrieve a registered agent block
|
|
96
|
-
#
|
|
97
|
-
# @param name [Symbol, String] Agent name
|
|
98
|
-
# @return [Proc, nil] The registration block or nil if not found
|
|
99
|
-
#
|
|
100
|
-
# @example
|
|
101
|
-
# block = SwarmSDK::AgentRegistry.get(:backend)
|
|
102
|
-
# builder.instance_eval(&block) if block
|
|
103
|
-
def get(name)
|
|
104
|
-
@agents[name.to_sym]
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
# Check if an agent is registered
|
|
108
|
-
#
|
|
109
|
-
# @param name [Symbol, String] Agent name
|
|
110
|
-
# @return [Boolean] true if agent is registered
|
|
111
|
-
#
|
|
112
|
-
# @example
|
|
113
|
-
# if SwarmSDK::AgentRegistry.registered?(:backend)
|
|
114
|
-
# puts "Backend agent is available"
|
|
115
|
-
# end
|
|
116
|
-
def registered?(name)
|
|
117
|
-
@agents.key?(name.to_sym)
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
# List all registered agent names
|
|
121
|
-
#
|
|
122
|
-
# @return [Array<Symbol>] Names of all registered agents
|
|
123
|
-
#
|
|
124
|
-
# @example
|
|
125
|
-
# SwarmSDK::AgentRegistry.names
|
|
126
|
-
# # => [:backend, :frontend, :database]
|
|
127
|
-
def names
|
|
128
|
-
@agents.keys
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
# Clear all registrations
|
|
132
|
-
#
|
|
133
|
-
# Primarily useful for testing to ensure clean state between tests.
|
|
134
|
-
#
|
|
135
|
-
# @return [void]
|
|
136
|
-
#
|
|
137
|
-
# @example In test setup/teardown
|
|
138
|
-
# def teardown
|
|
139
|
-
# SwarmSDK::AgentRegistry.clear
|
|
140
|
-
# end
|
|
141
|
-
def clear
|
|
142
|
-
@agents.clear
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
end
|
|
@@ -1,553 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module SwarmSDK
|
|
4
|
-
module Builders
|
|
5
|
-
# Base builder with shared DSL methods for Swarm and Workflow builders
|
|
6
|
-
#
|
|
7
|
-
# Provides common functionality:
|
|
8
|
-
# - Basic configuration (name, id, scratchpad)
|
|
9
|
-
# - Agent definition (inline DSL, markdown files, with overrides)
|
|
10
|
-
# - All agents configuration
|
|
11
|
-
# - External swarms registry
|
|
12
|
-
# - Validation helpers
|
|
13
|
-
# - Merging logic
|
|
14
|
-
#
|
|
15
|
-
# Subclasses must implement:
|
|
16
|
-
# - build_swarm - Build and return the appropriate instance
|
|
17
|
-
# - Type-specific DSL methods (lead for Swarm, node/start_node for Workflow)
|
|
18
|
-
#
|
|
19
|
-
class BaseBuilder
|
|
20
|
-
def initialize(allow_filesystem_tools: nil)
|
|
21
|
-
@swarm_id = nil
|
|
22
|
-
@swarm_name = nil
|
|
23
|
-
@agents = {}
|
|
24
|
-
@all_agents_config = nil
|
|
25
|
-
@swarm_registry_config = []
|
|
26
|
-
@scratchpad = :disabled
|
|
27
|
-
@allow_filesystem_tools = allow_filesystem_tools
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Set swarm ID
|
|
31
|
-
#
|
|
32
|
-
# @param swarm_id [String] Unique identifier for this swarm/workflow
|
|
33
|
-
def id(swarm_id)
|
|
34
|
-
@swarm_id = swarm_id
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Set swarm/workflow name
|
|
38
|
-
def name(swarm_name)
|
|
39
|
-
@swarm_name = swarm_name
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Configure scratchpad mode
|
|
43
|
-
#
|
|
44
|
-
# For Workflow: :enabled (shared across nodes), :per_node (isolated), or :disabled
|
|
45
|
-
# For Swarm: :enabled or :disabled
|
|
46
|
-
#
|
|
47
|
-
# @param mode [Symbol, Boolean] Scratchpad mode
|
|
48
|
-
def scratchpad(mode)
|
|
49
|
-
@scratchpad = mode
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# Register external swarms for composable swarms
|
|
53
|
-
#
|
|
54
|
-
# @example
|
|
55
|
-
# swarms do
|
|
56
|
-
# register "code_review", file: "./swarms/code_review.rb"
|
|
57
|
-
# register "testing", file: "./swarms/testing.yml", keep_context: false
|
|
58
|
-
# end
|
|
59
|
-
#
|
|
60
|
-
# @yield Block containing register() calls
|
|
61
|
-
def swarms(&block)
|
|
62
|
-
builder = Swarm::SwarmRegistryBuilder.new
|
|
63
|
-
builder.instance_eval(&block)
|
|
64
|
-
@swarm_registry_config = builder.registrations
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# Define an agent with fluent API, load from markdown, or reference registry
|
|
68
|
-
#
|
|
69
|
-
# Supports multiple forms:
|
|
70
|
-
# 1. Registry lookup: agent :name (pulls from global registry)
|
|
71
|
-
# 2. Registry + overrides: agent :name do ... end (when registered)
|
|
72
|
-
# 3. Inline DSL: agent :name do ... end (when not registered)
|
|
73
|
-
# 4. Markdown content: agent :name, <<~MD ... MD
|
|
74
|
-
# 5. Markdown + overrides: agent :name, <<~MD do ... end
|
|
75
|
-
#
|
|
76
|
-
# @example Inline DSL
|
|
77
|
-
# agent :backend do
|
|
78
|
-
# model "gpt-5"
|
|
79
|
-
# system_prompt "You build APIs"
|
|
80
|
-
# tools :Read, :Write
|
|
81
|
-
# end
|
|
82
|
-
#
|
|
83
|
-
# @example Registry lookup (agent must be registered with SwarmSDK.agent)
|
|
84
|
-
# agent :backend # Pulls configuration from registry
|
|
85
|
-
#
|
|
86
|
-
# @example Registry + overrides
|
|
87
|
-
# agent :backend do
|
|
88
|
-
# # Base config from registry, then apply overrides
|
|
89
|
-
# tools :CustomTool # Adds to registry-defined tools
|
|
90
|
-
# end
|
|
91
|
-
#
|
|
92
|
-
# @example Markdown content
|
|
93
|
-
# agent :backend, <<~MD
|
|
94
|
-
# ---
|
|
95
|
-
# description: "Backend developer"
|
|
96
|
-
# model: "gpt-4"
|
|
97
|
-
# ---
|
|
98
|
-
#
|
|
99
|
-
# You build APIs.
|
|
100
|
-
# MD
|
|
101
|
-
def agent(name, content = nil, &block)
|
|
102
|
-
name = name.to_sym
|
|
103
|
-
|
|
104
|
-
# Case 1: agent :name, <<~MD do ... end (markdown + overrides)
|
|
105
|
-
if content.is_a?(String) && block_given? && markdown_content?(content)
|
|
106
|
-
load_agent_from_markdown_with_overrides(content, name, &block)
|
|
107
|
-
|
|
108
|
-
# Case 2: agent :name, <<~MD (markdown only)
|
|
109
|
-
elsif content.is_a?(String) && !block_given? && markdown_content?(content)
|
|
110
|
-
load_agent_from_markdown(content, name)
|
|
111
|
-
|
|
112
|
-
# Case 3: agent :name (registry lookup only - no content, no block)
|
|
113
|
-
elsif content.nil? && !block_given?
|
|
114
|
-
load_agent_from_registry(name)
|
|
115
|
-
|
|
116
|
-
# Case 4: agent :name do ... end (with registered agent - registry + overrides)
|
|
117
|
-
elsif content.nil? && block_given? && AgentRegistry.registered?(name)
|
|
118
|
-
load_agent_from_registry_with_overrides(name, &block)
|
|
119
|
-
|
|
120
|
-
# Case 5: agent :name do ... end (inline DSL - not registered)
|
|
121
|
-
elsif block_given?
|
|
122
|
-
builder = Agent::Builder.new(name)
|
|
123
|
-
builder.instance_eval(&block)
|
|
124
|
-
@agents[name] = builder
|
|
125
|
-
|
|
126
|
-
else
|
|
127
|
-
raise ArgumentError,
|
|
128
|
-
"Invalid agent definition for '#{name}'. Use:\n " \
|
|
129
|
-
"agent :#{name} { ... } # Inline DSL\n " \
|
|
130
|
-
"agent :#{name} # Registry lookup\n " \
|
|
131
|
-
"agent :#{name} { ... } # Registry + overrides (if registered)\n " \
|
|
132
|
-
"agent :#{name}, <<~MD ... MD # Markdown\n " \
|
|
133
|
-
"agent :#{name}, <<~MD do ... end # Markdown + overrides"
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
# Configure all agents with a block
|
|
138
|
-
#
|
|
139
|
-
# @example
|
|
140
|
-
# all_agents do
|
|
141
|
-
# tools :Read, :Write
|
|
142
|
-
#
|
|
143
|
-
# hook :pre_tool_use, matcher: "Write" do |ctx|
|
|
144
|
-
# # Validation for all agents
|
|
145
|
-
# end
|
|
146
|
-
# end
|
|
147
|
-
def all_agents(&block)
|
|
148
|
-
builder = Swarm::AllAgentsBuilder.new
|
|
149
|
-
builder.instance_eval(&block)
|
|
150
|
-
@all_agents_config = builder
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
# Build the actual Swarm or Workflow instance
|
|
154
|
-
#
|
|
155
|
-
# Subclasses must implement this method.
|
|
156
|
-
#
|
|
157
|
-
# @return [Swarm, Workflow] Configured instance
|
|
158
|
-
def build_swarm
|
|
159
|
-
raise NotImplementedError, "#{self.class} must implement #build_swarm"
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
protected
|
|
163
|
-
|
|
164
|
-
# Check if a string is markdown content (has frontmatter)
|
|
165
|
-
#
|
|
166
|
-
# @param str [String] String to check
|
|
167
|
-
# @return [Boolean] true if string contains markdown frontmatter
|
|
168
|
-
def markdown_content?(str)
|
|
169
|
-
str.start_with?("---") || str.include?("\n---\n")
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
# Load an agent from the global registry
|
|
173
|
-
#
|
|
174
|
-
# Retrieves the registered agent block and executes it in the context
|
|
175
|
-
# of a new Agent::Builder.
|
|
176
|
-
#
|
|
177
|
-
# @param name [Symbol] Agent name
|
|
178
|
-
# @return [void]
|
|
179
|
-
# @raise [ConfigurationError] If agent is not registered
|
|
180
|
-
#
|
|
181
|
-
# @example
|
|
182
|
-
# load_agent_from_registry(:backend)
|
|
183
|
-
def load_agent_from_registry(name)
|
|
184
|
-
registered_proc = AgentRegistry.get(name)
|
|
185
|
-
unless registered_proc
|
|
186
|
-
raise ConfigurationError,
|
|
187
|
-
"Agent '#{name}' not found in registry. " \
|
|
188
|
-
"Either define inline with `agent :#{name} do ... end` or " \
|
|
189
|
-
"register globally with `SwarmSDK.agent :#{name} do ... end`"
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
builder = Agent::Builder.new(name)
|
|
193
|
-
builder.instance_eval(®istered_proc)
|
|
194
|
-
@agents[name] = builder
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
# Load an agent from the registry with additional overrides
|
|
198
|
-
#
|
|
199
|
-
# Applies the registered configuration first, then executes the
|
|
200
|
-
# override block to customize the agent.
|
|
201
|
-
#
|
|
202
|
-
# @param name [Symbol] Agent name
|
|
203
|
-
# @yield Override block with additional configuration
|
|
204
|
-
# @return [void]
|
|
205
|
-
#
|
|
206
|
-
# @example
|
|
207
|
-
# load_agent_from_registry_with_overrides(:backend) do
|
|
208
|
-
# tools :CustomTool # Adds to registry-defined tools
|
|
209
|
-
# end
|
|
210
|
-
def load_agent_from_registry_with_overrides(name, &override_block)
|
|
211
|
-
registered_proc = AgentRegistry.get(name)
|
|
212
|
-
# Guaranteed to exist since we checked in the condition
|
|
213
|
-
|
|
214
|
-
builder = Agent::Builder.new(name)
|
|
215
|
-
builder.instance_eval(®istered_proc) # Base config from registry
|
|
216
|
-
builder.instance_eval(&override_block) # Apply overrides
|
|
217
|
-
@agents[name] = builder
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
# Load an agent from markdown content
|
|
221
|
-
#
|
|
222
|
-
# Returns a hash of the agent config (not a Definition yet) so that
|
|
223
|
-
# all_agents config can be applied later in the build process.
|
|
224
|
-
#
|
|
225
|
-
# @param content [String] Markdown content with frontmatter
|
|
226
|
-
# @param name_override [Symbol, nil] Optional name to override frontmatter name
|
|
227
|
-
# @return [void]
|
|
228
|
-
def load_agent_from_markdown(content, name_override = nil)
|
|
229
|
-
definition = MarkdownParser.parse(content, name_override)
|
|
230
|
-
@agents[definition.name] = { __file_config__: definition.to_h }
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
# Load an agent from markdown content with DSL overrides
|
|
234
|
-
#
|
|
235
|
-
# @param content [String] Markdown content with frontmatter
|
|
236
|
-
# @param name_override [Symbol, nil] Optional name to override frontmatter name
|
|
237
|
-
# @yield Block with DSL overrides
|
|
238
|
-
# @return [void]
|
|
239
|
-
def load_agent_from_markdown_with_overrides(content, name_override = nil, &block)
|
|
240
|
-
definition = MarkdownParser.parse(content, name_override)
|
|
241
|
-
|
|
242
|
-
builder = Agent::Builder.new(definition.name)
|
|
243
|
-
apply_definition_to_builder(builder, definition.to_h)
|
|
244
|
-
builder.instance_eval(&block)
|
|
245
|
-
|
|
246
|
-
@agents[definition.name] = builder
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
# Apply agent definition hash to a builder
|
|
250
|
-
#
|
|
251
|
-
# @param builder [Agent::Builder] Builder to configure
|
|
252
|
-
# @param config [Hash] Configuration hash from definition
|
|
253
|
-
# @return [void]
|
|
254
|
-
def apply_definition_to_builder(builder, config)
|
|
255
|
-
builder.description(config[:description]) if config[:description]
|
|
256
|
-
builder.model(config[:model]) if config[:model]
|
|
257
|
-
builder.provider(config[:provider]) if config[:provider]
|
|
258
|
-
builder.base_url(config[:base_url]) if config[:base_url]
|
|
259
|
-
builder.api_version(config[:api_version]) if config[:api_version]
|
|
260
|
-
builder.context_window(config[:context_window]) if config[:context_window]
|
|
261
|
-
builder.system_prompt(config[:system_prompt]) if config[:system_prompt]
|
|
262
|
-
builder.directory(config[:directory]) if config[:directory]
|
|
263
|
-
builder.request_timeout(config[:request_timeout]) if config[:request_timeout]
|
|
264
|
-
builder.turn_timeout(config[:turn_timeout]) if config[:turn_timeout]
|
|
265
|
-
builder.parameters(config[:parameters]) if config[:parameters]
|
|
266
|
-
builder.headers(config[:headers]) if config[:headers]
|
|
267
|
-
builder.coding_agent(config[:coding_agent]) unless config[:coding_agent].nil?
|
|
268
|
-
builder.bypass_permissions(config[:bypass_permissions]) if config[:bypass_permissions]
|
|
269
|
-
builder.disable_default_tools(config[:disable_default_tools]) unless config[:disable_default_tools].nil?
|
|
270
|
-
|
|
271
|
-
# Add tools from markdown
|
|
272
|
-
if config[:tools]&.any?
|
|
273
|
-
tool_names = config[:tools].map do |tool|
|
|
274
|
-
tool.is_a?(Hash) ? tool[:name] : tool
|
|
275
|
-
end
|
|
276
|
-
builder.tools(*tool_names)
|
|
277
|
-
end
|
|
278
|
-
|
|
279
|
-
# Add delegates_to (handle both array and hash formats)
|
|
280
|
-
if config[:delegates_to]&.any?
|
|
281
|
-
delegation_config = config[:delegates_to]
|
|
282
|
-
if delegation_config.is_a?(Hash)
|
|
283
|
-
# Hash format: pass as single argument
|
|
284
|
-
builder.delegates_to(delegation_config)
|
|
285
|
-
elsif delegation_config.is_a?(Array)
|
|
286
|
-
# Array format: splat the array
|
|
287
|
-
builder.delegates_to(*delegation_config)
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
# Add MCP servers
|
|
292
|
-
config[:mcp_servers]&.each do |server|
|
|
293
|
-
builder.mcp_server(server[:name], **server.except(:name))
|
|
294
|
-
end
|
|
295
|
-
end
|
|
296
|
-
|
|
297
|
-
# Merge all_agents configuration into each agent
|
|
298
|
-
#
|
|
299
|
-
# All_agents values are used as defaults - agent-specific values override.
|
|
300
|
-
# This applies to both inline DSL agents (Builder) and file-loaded agents (config hash).
|
|
301
|
-
#
|
|
302
|
-
# @return [void]
|
|
303
|
-
def merge_all_agents_config_into_agents
|
|
304
|
-
return unless @all_agents_config
|
|
305
|
-
|
|
306
|
-
all_agents_hash = @all_agents_config.to_h
|
|
307
|
-
|
|
308
|
-
@agents.each_value do |agent_builder_or_config|
|
|
309
|
-
if agent_builder_or_config.is_a?(Hash) && agent_builder_or_config.key?(:__file_config__)
|
|
310
|
-
# File-loaded agent - merge into the config hash
|
|
311
|
-
file_config = agent_builder_or_config[:__file_config__]
|
|
312
|
-
merged_config = merge_all_agents_into_config(all_agents_hash, file_config)
|
|
313
|
-
agent_builder_or_config[:__file_config__] = merged_config
|
|
314
|
-
else
|
|
315
|
-
# Builder object (inline DSL agent)
|
|
316
|
-
agent_builder = agent_builder_or_config
|
|
317
|
-
|
|
318
|
-
apply_all_agents_defaults(agent_builder, all_agents_hash)
|
|
319
|
-
|
|
320
|
-
# Merge tools (prepend all_agents tools)
|
|
321
|
-
all_agents_tools = @all_agents_config.tools_list
|
|
322
|
-
agent_builder.prepend_tools(*all_agents_tools) if all_agents_tools.any?
|
|
323
|
-
|
|
324
|
-
# Pass all_agents permissions as default_permissions
|
|
325
|
-
if @all_agents_config.permissions_config.any?
|
|
326
|
-
agent_builder.default_permissions = @all_agents_config.permissions_config
|
|
327
|
-
end
|
|
328
|
-
end
|
|
329
|
-
end
|
|
330
|
-
end
|
|
331
|
-
|
|
332
|
-
# Merge all_agents config into file-loaded agent config
|
|
333
|
-
#
|
|
334
|
-
# @param all_agents_hash [Hash] All_agents configuration
|
|
335
|
-
# @param file_config [Hash] File-loaded agent configuration
|
|
336
|
-
# @return [Hash] Merged configuration
|
|
337
|
-
def merge_all_agents_into_config(all_agents_hash, file_config)
|
|
338
|
-
merged = all_agents_hash.dup
|
|
339
|
-
|
|
340
|
-
file_config.each do |key, value|
|
|
341
|
-
case key
|
|
342
|
-
when :tools
|
|
343
|
-
merged[:tools] = Array(merged[:tools]) + Array(value)
|
|
344
|
-
when :delegates_to
|
|
345
|
-
# Handle merging delegation configs (can be array or hash)
|
|
346
|
-
existing = merged[:delegates_to] || []
|
|
347
|
-
new_value = value || []
|
|
348
|
-
|
|
349
|
-
# Convert both to array of delegation configs for merging
|
|
350
|
-
existing_array = normalize_delegation_array(existing)
|
|
351
|
-
new_array = normalize_delegation_array(new_value)
|
|
352
|
-
|
|
353
|
-
merged[:delegates_to] = existing_array + new_array
|
|
354
|
-
when :parameters
|
|
355
|
-
merged[:parameters] = (merged[:parameters] || {}).merge(value || {})
|
|
356
|
-
when :headers
|
|
357
|
-
merged[:headers] = (merged[:headers] || {}).merge(value || {})
|
|
358
|
-
when :turn_timeout
|
|
359
|
-
# Agent-specific turn_timeout overrides all_agents
|
|
360
|
-
merged[key] = value
|
|
361
|
-
when :request_timeout
|
|
362
|
-
# Agent-specific request_timeout overrides all_agents
|
|
363
|
-
merged[key] = value
|
|
364
|
-
else
|
|
365
|
-
merged[key] = value
|
|
366
|
-
end
|
|
367
|
-
end
|
|
368
|
-
|
|
369
|
-
# Pass all_agents permissions as default_permissions
|
|
370
|
-
if all_agents_hash[:permissions] && !merged[:default_permissions]
|
|
371
|
-
merged[:default_permissions] = all_agents_hash[:permissions]
|
|
372
|
-
end
|
|
373
|
-
|
|
374
|
-
merged
|
|
375
|
-
end
|
|
376
|
-
|
|
377
|
-
# Normalize delegation config to array of hashes format
|
|
378
|
-
#
|
|
379
|
-
# Converts various delegation formats to normalized array for merging:
|
|
380
|
-
# - Array of symbols: [:frontend, :backend] → [{agent: :frontend, tool_name: nil}, ...]
|
|
381
|
-
# - Hash: {frontend: "Custom"} → [{agent: :frontend, tool_name: "Custom"}, ...]
|
|
382
|
-
# - Array of hashes: [{agent: :frontend, tool_name: "Custom"}] → unchanged
|
|
383
|
-
#
|
|
384
|
-
# @param delegation_config [Array, Hash] Delegation configuration
|
|
385
|
-
# @return [Array<Hash>] Normalized array of {agent:, tool_name:} hashes
|
|
386
|
-
def normalize_delegation_array(delegation_config)
|
|
387
|
-
return [] if delegation_config.nil? || (delegation_config.respond_to?(:empty?) && delegation_config.empty?)
|
|
388
|
-
|
|
389
|
-
case delegation_config
|
|
390
|
-
when Array
|
|
391
|
-
delegation_config.map do |item|
|
|
392
|
-
case item
|
|
393
|
-
when Symbol, String
|
|
394
|
-
{ agent: item.to_sym, tool_name: nil }
|
|
395
|
-
when Hash
|
|
396
|
-
item.key?(:agent) ? item : item.map { |agent, tool_name| { agent: agent.to_sym, tool_name: tool_name } }
|
|
397
|
-
end
|
|
398
|
-
end.flatten
|
|
399
|
-
when Hash
|
|
400
|
-
delegation_config.map { |agent, tool_name| { agent: agent.to_sym, tool_name: tool_name } }
|
|
401
|
-
else
|
|
402
|
-
[]
|
|
403
|
-
end
|
|
404
|
-
end
|
|
405
|
-
|
|
406
|
-
# Apply all_agents defaults to an agent builder
|
|
407
|
-
#
|
|
408
|
-
# @param agent_builder [Agent::Builder] The agent builder to configure
|
|
409
|
-
# @param all_agents_hash [Hash] All_agents configuration
|
|
410
|
-
# @return [void]
|
|
411
|
-
def apply_all_agents_defaults(agent_builder, all_agents_hash)
|
|
412
|
-
if all_agents_hash[:model] && !agent_builder.model_set?
|
|
413
|
-
agent_builder.model(all_agents_hash[:model])
|
|
414
|
-
end
|
|
415
|
-
|
|
416
|
-
if all_agents_hash[:provider] && !agent_builder.provider_set?
|
|
417
|
-
agent_builder.provider(all_agents_hash[:provider])
|
|
418
|
-
end
|
|
419
|
-
|
|
420
|
-
if all_agents_hash[:base_url] && !agent_builder.base_url_set?
|
|
421
|
-
agent_builder.base_url(all_agents_hash[:base_url])
|
|
422
|
-
end
|
|
423
|
-
|
|
424
|
-
if all_agents_hash[:api_version] && !agent_builder.api_version_set?
|
|
425
|
-
agent_builder.api_version(all_agents_hash[:api_version])
|
|
426
|
-
end
|
|
427
|
-
|
|
428
|
-
if all_agents_hash[:request_timeout] && !agent_builder.request_timeout_set?
|
|
429
|
-
agent_builder.request_timeout(all_agents_hash[:request_timeout])
|
|
430
|
-
end
|
|
431
|
-
|
|
432
|
-
if all_agents_hash[:turn_timeout] && !agent_builder.turn_timeout_set?
|
|
433
|
-
agent_builder.turn_timeout(all_agents_hash[:turn_timeout])
|
|
434
|
-
end
|
|
435
|
-
|
|
436
|
-
if all_agents_hash[:parameters]
|
|
437
|
-
merged_params = all_agents_hash[:parameters].merge(agent_builder.parameters)
|
|
438
|
-
agent_builder.parameters(merged_params)
|
|
439
|
-
end
|
|
440
|
-
|
|
441
|
-
if all_agents_hash[:headers]
|
|
442
|
-
merged_headers = all_agents_hash[:headers].merge(agent_builder.headers)
|
|
443
|
-
agent_builder.headers(merged_headers)
|
|
444
|
-
end
|
|
445
|
-
|
|
446
|
-
if !all_agents_hash[:coding_agent].nil? && !agent_builder.coding_agent_set?
|
|
447
|
-
agent_builder.coding_agent(all_agents_hash[:coding_agent])
|
|
448
|
-
end
|
|
449
|
-
|
|
450
|
-
if !all_agents_hash[:streaming].nil? && !agent_builder.streaming_set?
|
|
451
|
-
agent_builder.streaming(all_agents_hash[:streaming])
|
|
452
|
-
end
|
|
453
|
-
|
|
454
|
-
if all_agents_hash[:thinking] && !agent_builder.thinking_set?
|
|
455
|
-
agent_builder.thinking(**all_agents_hash[:thinking])
|
|
456
|
-
end
|
|
457
|
-
end
|
|
458
|
-
|
|
459
|
-
# Validate all_agents filesystem tools
|
|
460
|
-
#
|
|
461
|
-
# @raise [ConfigurationError] If filesystem tools are disabled and all_agents has them
|
|
462
|
-
# @return [void]
|
|
463
|
-
def validate_all_agents_filesystem_tools
|
|
464
|
-
resolved_setting = if @allow_filesystem_tools.nil?
|
|
465
|
-
SwarmSDK.config.allow_filesystem_tools
|
|
466
|
-
else
|
|
467
|
-
@allow_filesystem_tools
|
|
468
|
-
end
|
|
469
|
-
|
|
470
|
-
return if resolved_setting
|
|
471
|
-
return unless @all_agents_config&.tools_list&.any?
|
|
472
|
-
|
|
473
|
-
forbidden = @all_agents_config.tools_list.select do |tool|
|
|
474
|
-
SwarmSDK::Swarm::ToolConfigurator::FILESYSTEM_TOOLS.include?(tool.to_sym)
|
|
475
|
-
end
|
|
476
|
-
|
|
477
|
-
return if forbidden.empty?
|
|
478
|
-
|
|
479
|
-
raise ConfigurationError,
|
|
480
|
-
"Filesystem tools are globally disabled (SwarmSDK.config.allow_filesystem_tools = false) " \
|
|
481
|
-
"but all_agents configuration includes: #{forbidden.join(", ")}.\n\n" \
|
|
482
|
-
"This is a system-wide security setting that cannot be overridden by swarm configuration.\n" \
|
|
483
|
-
"To use filesystem tools, set SwarmSDK.config.allow_filesystem_tools = true before loading the swarm."
|
|
484
|
-
end
|
|
485
|
-
|
|
486
|
-
# Validate individual agent filesystem tools
|
|
487
|
-
#
|
|
488
|
-
# @raise [ConfigurationError] If filesystem tools are disabled and any agent has them
|
|
489
|
-
# @return [void]
|
|
490
|
-
def validate_agent_filesystem_tools
|
|
491
|
-
resolved_setting = if @allow_filesystem_tools.nil?
|
|
492
|
-
SwarmSDK.config.allow_filesystem_tools
|
|
493
|
-
else
|
|
494
|
-
@allow_filesystem_tools
|
|
495
|
-
end
|
|
496
|
-
|
|
497
|
-
return if resolved_setting
|
|
498
|
-
|
|
499
|
-
@agents.each do |agent_name, agent_builder_or_config|
|
|
500
|
-
tools_list = if agent_builder_or_config.is_a?(Hash) && agent_builder_or_config.key?(:__file_config__)
|
|
501
|
-
agent_builder_or_config[:__file_config__][:tools] || []
|
|
502
|
-
elsif agent_builder_or_config.is_a?(Agent::Builder)
|
|
503
|
-
agent_builder_or_config.tools_list
|
|
504
|
-
else
|
|
505
|
-
[]
|
|
506
|
-
end
|
|
507
|
-
|
|
508
|
-
tool_names = tools_list.map do |tool|
|
|
509
|
-
name = tool.is_a?(Hash) ? tool[:name] : tool
|
|
510
|
-
name.to_sym
|
|
511
|
-
end
|
|
512
|
-
|
|
513
|
-
forbidden = tool_names.select do |tool|
|
|
514
|
-
SwarmSDK::Swarm::ToolConfigurator::FILESYSTEM_TOOLS.include?(tool)
|
|
515
|
-
end
|
|
516
|
-
|
|
517
|
-
next if forbidden.empty?
|
|
518
|
-
|
|
519
|
-
raise ConfigurationError,
|
|
520
|
-
"Filesystem tools are globally disabled (SwarmSDK.config.allow_filesystem_tools = false) " \
|
|
521
|
-
"but agent '#{agent_name}' attempts to use: #{forbidden.join(", ")}.\n\n" \
|
|
522
|
-
"This is a system-wide security setting that cannot be overridden by swarm configuration.\n" \
|
|
523
|
-
"To use filesystem tools, set SwarmSDK.config.allow_filesystem_tools = true before loading the swarm."
|
|
524
|
-
end
|
|
525
|
-
end
|
|
526
|
-
|
|
527
|
-
# Build agent definitions from builders or file configs
|
|
528
|
-
#
|
|
529
|
-
# Handles both Agent::Builder (inline DSL) and file configs (from files).
|
|
530
|
-
# Merges all_agents config before building.
|
|
531
|
-
#
|
|
532
|
-
# @return [Hash<Symbol, Agent::Definition>] Agent definitions
|
|
533
|
-
def build_agent_definitions
|
|
534
|
-
# Merge all_agents config first
|
|
535
|
-
merge_all_agents_config_into_agents if @all_agents_config
|
|
536
|
-
|
|
537
|
-
# Build definitions
|
|
538
|
-
agent_definitions = {}
|
|
539
|
-
@agents.each do |agent_name, agent_builder_or_config|
|
|
540
|
-
agent_definitions[agent_name] = if agent_builder_or_config.is_a?(Hash) && agent_builder_or_config.key?(:__file_config__)
|
|
541
|
-
# File-loaded agent config (with all_agents merged)
|
|
542
|
-
Agent::Definition.new(agent_name, agent_builder_or_config[:__file_config__])
|
|
543
|
-
else
|
|
544
|
-
# Builder object (from inline DSL) - convert to definition
|
|
545
|
-
agent_builder_or_config.to_definition
|
|
546
|
-
end
|
|
547
|
-
end
|
|
548
|
-
|
|
549
|
-
agent_definitions
|
|
550
|
-
end
|
|
551
|
-
end
|
|
552
|
-
end
|
|
553
|
-
end
|