Class: SwarmSDK::Agent::Definition

Inherits:
Object
  • Object
show all
Defined in:
lib/swarm_sdk/agent/definition.rb

Overview

Agent definition encapsulates agent configuration and builds system prompts

This class is responsible for:

  • Parsing and validating agent configuration
  • Building the full system prompt (base + custom)
  • Handling tool permissions
  • Managing hooks (both DSL Ruby blocks and YAML shell commands)

Examples:

definition = Agent::Definition.new(:backend, {
  description: "Backend API developer",
  model: "gpt-5",
  tools: [:Read, :Write, :Bash],
  system_prompt: "You build APIs"
})

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, config = {}) ⇒ Definition

Returns a new instance of Definition.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/swarm_sdk/agent/definition.rb', line 51

def initialize(name, config = {})
  @name = name.to_sym

  # Validate name doesn't contain '@' (reserved for delegation instances)
  if @name.to_s.include?("@")
    raise ConfigurationError,
      "Agent names cannot contain '@' character (reserved for delegation instance naming). " \
        "Agent: #{@name}"
  end

  # BREAKING CHANGE: Hard error for plural form
  if config[:directories]
    raise ConfigurationError,
      "The 'directories' (plural) configuration is no longer supported in SwarmSDK 1.0+.\n\n" \
        "Change 'directories:' to 'directory:' (singular).\n\n" \
        "If you need access to multiple directories, use permissions:\n\n  " \
        "directory: 'backend/'\n  " \
        "permissions do\n    " \
        "tool(:Read).allow_paths('../shared/**')\n  " \
        "end"
  end

  @description = config[:description]
  @model = config[:model] || SwarmSDK.config.default_model
  @provider = config[:provider] || SwarmSDK.config.default_provider
  @base_url = config[:base_url]
  @api_version = config[:api_version]
  @context_window = coerce_to_integer(config[:context_window]) # Explicit context window override
  @parameters = config[:parameters] || {}
  @headers = Utils.stringify_keys(config[:headers] || {})
  @request_timeout = config[:request_timeout] || SwarmSDK.config.agent_request_timeout
  @bypass_permissions = config[:bypass_permissions] || false
  @max_concurrent_tools = config[:max_concurrent_tools]

  # Use default from config unless explicitly set (including nil to disable)
  @turn_timeout = if config.key?(:turn_timeout)
    config[:turn_timeout] # Could be a number OR nil (to disable)
  else
    SwarmSDK.config.default_turn_timeout
  end
  # Always assume model exists - SwarmSDK validates models separately using models.json
  # This prevents RubyLLM from trying to validate models in its registry
  @assume_model_exists = true

  # disable_default_tools can be:
  # - nil/not set: include all default tools (default behavior)
  # - true: disable ALL default tools
  # - Array of symbols: disable specific tools (e.g., [:Think, :TodoWrite])
  @disable_default_tools = config[:disable_default_tools]

  # coding_agent defaults to false if not specified
  # When true, includes the base system prompt for coding tasks
  # When false, uses only the custom system prompt (no base prompt)
  @coding_agent = config.key?(:coding_agent) ? config[:coding_agent] : false

  # Parse directory first so it can be used in system prompt rendering
  @directory = parse_directory(config[:directory])

  # Extract plugin configurations (generic bucket for all plugin-specific keys)
  # This allows plugins to store their config without SDK knowing about them
  @plugin_configs = extract_plugin_configs(config)

  # Delegation isolation mode (default: false = isolated instances per delegation)
  @shared_across_delegations = config[:shared_across_delegations] || false

  # Streaming configuration (default: true from global config)
  @streaming = config.fetch(:streaming, SwarmSDK.config.streaming)

  # Extended thinking configuration (nil = disabled)
  @thinking = config[:thinking]

  # When true, omits date/platform/OS/working directory from system prompts
  @disable_environment_info = config.fetch(:disable_environment_info, false)

  # Build system prompt after directory and memory are set
  @system_prompt = build_full_system_prompt(config[:system_prompt])

  # Parse tools with permissions support
  @default_permissions = config[:default_permissions] || {}
  @agent_permissions = config[:permissions] || {}
  @tools = parse_tools_with_permissions(
    config[:tools],
    @default_permissions,
    @agent_permissions,
  )

  # Inject default write restrictions for security
  @tools = inject_default_write_permissions(@tools)

  # Parse delegation configuration (supports both simple arrays and custom tool names)
  @delegation_configs = parse_delegation_config(config[:delegates_to])
  @mcp_servers = Array(config[:mcp_servers] || [])

  # Parse hooks configuration
  # Handles both DSL (HookDefinition objects) and YAML (raw hash) formats
  @hooks = parse_hooks(config[:hooks])

  validate!
end

Instance Attribute Details

#agent_permissionsObject (readonly)

Returns the value of attribute agent_permissions.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def agent_permissions
  @agent_permissions
end

#api_versionObject (readonly)

Returns the value of attribute api_version.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def api_version
  @api_version
end

#assume_model_existsObject (readonly)

Returns the value of attribute assume_model_exists.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def assume_model_exists
  @assume_model_exists
end

#base_urlObject (readonly)

Returns the value of attribute base_url.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def base_url
  @base_url
end

#bypass_permissionsObject

Returns the value of attribute bypass_permissions.



49
50
51
# File 'lib/swarm_sdk/agent/definition.rb', line 49

def bypass_permissions
  @bypass_permissions
end

#coding_agentObject (readonly)

Returns the value of attribute coding_agent.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def coding_agent
  @coding_agent
end

#context_windowObject (readonly)

Returns the value of attribute context_window.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def context_window
  @context_window
end

#default_permissionsObject (readonly)

Returns the value of attribute default_permissions.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def default_permissions
  @default_permissions
end

#delegation_configsObject (readonly)

Returns the value of attribute delegation_configs.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def delegation_configs
  @delegation_configs
end

#descriptionObject (readonly)

Returns the value of attribute description.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def description
  @description
end

#directoryObject (readonly)

Returns the value of attribute directory.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def directory
  @directory
end

#disable_default_toolsObject (readonly)

Returns the value of attribute disable_default_tools.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def disable_default_tools
  @disable_default_tools
end

#disable_environment_infoObject (readonly)

Returns the value of attribute disable_environment_info.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def disable_environment_info
  @disable_environment_info
end

#headersObject (readonly)

Returns the value of attribute headers.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def headers
  @headers
end

#hooksObject (readonly)

Returns the value of attribute hooks.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def hooks
  @hooks
end

#max_concurrent_toolsObject

Returns the value of attribute max_concurrent_tools.



49
50
51
# File 'lib/swarm_sdk/agent/definition.rb', line 49

def max_concurrent_tools
  @max_concurrent_tools
end

#mcp_serversObject (readonly)

Returns the value of attribute mcp_servers.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def mcp_servers
  @mcp_servers
end

#modelObject (readonly)

Returns the value of attribute model.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def model
  @model
end

#nameObject (readonly)

Returns the value of attribute name.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def name
  @name
end

#parametersObject (readonly)

Returns the value of attribute parameters.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def parameters
  @parameters
end

#plugin_configsObject (readonly)

Returns the value of attribute plugin_configs.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def plugin_configs
  @plugin_configs
end

#providerObject (readonly)

Returns the value of attribute provider.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def provider
  @provider
end

#request_timeoutObject (readonly)

Returns the value of attribute request_timeout.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def request_timeout
  @request_timeout
end

#shared_across_delegationsObject (readonly)

Returns the value of attribute shared_across_delegations.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def shared_across_delegations
  @shared_across_delegations
end

#streamingObject (readonly)

Returns the value of attribute streaming.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def streaming
  @streaming
end

#system_promptObject (readonly)

Returns the value of attribute system_prompt.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def system_prompt
  @system_prompt
end

#thinkingObject (readonly)

Returns the value of attribute thinking.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def thinking
  @thinking
end

#toolsObject (readonly)

Returns the value of attribute tools.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def tools
  @tools
end

#turn_timeoutObject (readonly)

Returns the value of attribute turn_timeout.



21
22
23
# File 'lib/swarm_sdk/agent/definition.rb', line 21

def turn_timeout
  @turn_timeout
end

Instance Method Details

#delegates_toArray<Symbol>

Get agent names that this agent delegates to (backwards compatible)

Returns an array of agent name symbols. This maintains backwards compatibility with existing code that expects delegates_to to be a simple array.

Examples:

agent_definition.delegates_to
# => [:frontend, :backend, :qa]

Returns:

  • (Array<Symbol>)

    Delegate agent names



161
162
163
# File 'lib/swarm_sdk/agent/definition.rb', line 161

def delegates_to
  @delegation_configs.map { |config| config[:agent] }
end

#plugin_config(plugin_name) ⇒ Object?

Get plugin-specific configuration

Plugins store their configuration in the generic plugin_configs hash. This allows SDK to remain plugin-agnostic while plugins can store arbitrary configuration.

Examples:

agent_definition.plugin_config(:memory)
# => { directory: "tmp/memory", mode: :full_access }

Parameters:

  • plugin_name (Symbol)

    Plugin name (e.g., :memory)

Returns:

  • (Object, nil)

    Plugin configuration or nil if not present



177
178
179
# File 'lib/swarm_sdk/agent/definition.rb', line 177

def plugin_config(plugin_name)
  @plugin_configs[plugin_name.to_sym] || @plugin_configs[plugin_name.to_s]
end

#to_hObject



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/swarm_sdk/agent/definition.rb', line 181

def to_h
  # Core SDK configuration (always serialized)
  base_config = {
    name: @name,
    description: @description,
    model: SwarmSDK::Models.resolve_alias(@model), # Resolve model aliases
    context_window: @context_window,
    directory: @directory,
    tools: @tools,
    delegates_to: @delegation_configs, # Serialize full config
    system_prompt: @system_prompt,
    provider: @provider,
    base_url: @base_url,
    api_version: @api_version,
    mcp_servers: @mcp_servers,
    parameters: @parameters,
    headers: @headers,
    request_timeout: @request_timeout,
    turn_timeout: @turn_timeout,
    bypass_permissions: @bypass_permissions,
    disable_default_tools: @disable_default_tools,
    coding_agent: @coding_agent,
    assume_model_exists: @assume_model_exists,
    max_concurrent_tools: @max_concurrent_tools,
    hooks: @hooks,
    shared_across_delegations: @shared_across_delegations,
    streaming: @streaming,
    disable_environment_info: @disable_environment_info,
    # Permissions are core SDK functionality (not plugin-specific)
    default_permissions: @default_permissions,
    permissions: @agent_permissions,
  }.compact

  # Allow plugins to contribute their config for serialization
  # This enables plugin features (memory, skills, etc.) to be preserved
  # when cloning agents without SwarmSDK knowing about plugin-specific fields
  plugin_configs = SwarmSDK::PluginRegistry.all.map do |plugin|
    plugin.serialize_config(agent_definition: self)
  end

  # Merge plugin configs into base config
  # Later plugins override earlier ones if they have conflicting keys
  plugin_configs.reduce(base_config) { |acc, config| acc.merge(config) }
end

#validateArray<Hash>

Validate agent configuration and return warnings (non-fatal issues)

Unlike validate! which raises exceptions for critical errors, this method returns an array of warning hashes for non-fatal issues like:

  • Model not found in registry (informs user, suggests alternatives)
  • Context tracking unavailable (useful even with assume_model_exists)

Note: Validation ALWAYS runs, even with assume_model_exists: true or base_url set. The purpose is to inform the user about potential issues and suggest corrections, not to block execution.

Returns:

  • (Array<Hash>)

    Array of warning hashes



238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/swarm_sdk/agent/definition.rb', line 238

def validate
  warnings = []

  # Always validate model (even with assume_model_exists)
  # Warnings inform user about typos and context tracking limitations
  model_warning = validate_model
  warnings << model_warning if model_warning

  # Future: could add tool validation, delegate validation, etc.

  warnings
end