Class: SwarmSDK::Plugin

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

Overview

Base class for SwarmSDK plugins

Plugins provide tools, storage, configuration parsing, and lifecycle hooks. Plugins are self-registering - they call SwarmSDK::PluginRegistry.register when the gem is loaded.

Adding Custom Attributes to Agents

Plugins can add custom attributes to Agent::Definition that are preserved when agents are cloned (e.g., in Workflow). To do this:

  1. Add attr_reader to Agent::Definition for your attribute
  2. Parse the attribute in Agent::Definition#initialize
  3. Implement serialize_config to preserve it during serialization

Now agents can use your custom config:

agent :researcher do
my_custom_config { option: "value" }
end

And it will be preserved when Workflow clones the agent!

Examples:

Plugin with custom agent attributes

# 1. Extend Agent::Definition (in your plugin gem)
module SwarmSDK
  module Agent
    class Definition
      attr_reader :my_custom_config

      alias_method :original_initialize, :initialize
      def initialize(name, config = {})
        @my_custom_config = config[:my_custom_config]
        original_initialize(name, config)
      end
    end
  end
end

# 2. Implement plugin with serialize_config
class MyPlugin < SwarmSDK::Plugin
  def name
    :my_plugin
  end

  def tools
    [:MyTool, :OtherTool]
  end

  def create_tool(tool_name, context)
    # Create and return tool instance
  end

  # Preserve custom config when agents are cloned
  def serialize_config(agent_definition:)
    return {} unless agent_definition.my_custom_config

    { my_custom_config: agent_definition.my_custom_config }
  end
end

SwarmSDK::PluginRegistry.register(MyPlugin.new)

Real-world: SwarmMemory plugin

# SwarmMemory adds 'memory' attribute to agents
class SDKPlugin < SwarmSDK::Plugin
  def serialize_config(agent_definition:)
    return {} unless agent_definition.memory
    { memory: agent_definition.memory }
  end
end

Instance Method Summary collapse

Instance Method Details

#create_storage(agent_name:, config:) ⇒ Object?

Create plugin storage for an agent (optional)

Called during agent initialization. Return nil if plugin doesn't need storage.

Parameters:

  • agent_name (Symbol)

    Agent identifier

  • config (Object)

    Plugin configuration from agent definition

Returns:

  • (Object, nil)

    Storage instance or nil



112
113
114
# File 'lib/swarm_sdk/plugin.rb', line 112

def create_storage(agent_name:, config:)
  nil
end

#create_tool(tool_name, context) ⇒ RubyLLM::Tool

Create a tool instance

Parameters:

  • tool_name (Symbol)

    Tool name (e.g., :MemoryWrite)

  • context (Hash)

    Creation context

    • :agent_name [Symbol] Agent identifier
    • :storage [Object] Plugin storage instance (if created)
    • :agent_definition [Agent::Definition] Full agent definition
    • :chat [Agent::Chat] Chat instance (for tools that need it)
    • :tool_configurator [Swarm::ToolConfigurator] For tools that register other tools

Returns:

  • (RubyLLM::Tool)

    Tool instance

Raises:

  • (NotImplementedError)


101
102
103
# File 'lib/swarm_sdk/plugin.rb', line 101

def create_tool(tool_name, context)
  raise NotImplementedError, "#{self.class} must implement #create_tool"
end

#get_tool_result_digest(agent_name:, tool_name:, path:) ⇒ String?

Get digest for a tool result (e.g., file hash, memory entry hash)

Called during tool result metadata collection. Returns a digest that can be used to detect if the resource has changed since it was last read. This enables change detection hooks.

Examples:

Memory read tracking

def get_tool_result_digest(agent_name:, tool_name:, path:)
  return unless tool_name == "MemoryRead"

  StorageReadTracker.get_read_entries(agent_name)[path]
end

Parameters:

  • agent_name (Symbol)

    Agent identifier

  • tool_name (String)

    Name of the tool (e.g., "MemoryRead")

  • path (String)

    Path or identifier of the resource

Returns:

  • (String, nil)

    Digest string or nil if not tracked by this plugin



277
278
279
# File 'lib/swarm_sdk/plugin.rb', line 277

def get_tool_result_digest(agent_name:, tool_name:, path:)
  nil
end

#immutable_toolsArray<Symbol>

Tools that should be marked immutable (optional)

Immutable tools cannot be removed by other tools (e.g., LoadSkill).

Returns:

  • (Array<Symbol>)

    Tool names



138
139
140
# File 'lib/swarm_sdk/plugin.rb', line 138

def immutable_tools
  []
end

#memory_configured?(agent_definition) ⇒ Boolean

Check if memory is configured for this agent (optional)

Parameters:

Returns:

  • (Boolean)

    True if storage should be created



146
147
148
# File 'lib/swarm_sdk/plugin.rb', line 146

def memory_configured?(agent_definition)
  false
end

#nameSymbol

Plugin name (must be unique)

Returns:

  • (Symbol)

    Plugin identifier

Raises:

  • (NotImplementedError)


80
81
82
# File 'lib/swarm_sdk/plugin.rb', line 80

def name
  raise NotImplementedError, "#{self.class} must implement #name"
end

#on_agent_initialized(agent_name:, agent:, context:) ⇒ Object

Lifecycle: Called when agent is initialized

Parameters:

  • agent_name (Symbol)

    Agent identifier

  • agent (Agent::Chat)

    Chat instance

  • context (Hash)

    Initialization context

    • :storage [Object, nil] Plugin storage
    • :agent_definition [Agent::Definition] Definition
    • :tool_configurator [Swarm::ToolConfigurator] Configurator


158
159
160
# File 'lib/swarm_sdk/plugin.rb', line 158

def on_agent_initialized(agent_name:, agent:, context:)
  # Override if needed
end

#on_swarm_started(swarm:) ⇒ Object

Lifecycle: Called when swarm starts

Parameters:

  • swarm (Swarm)

    Swarm instance



165
166
167
# File 'lib/swarm_sdk/plugin.rb', line 165

def on_swarm_started(swarm:)
  # Override if needed
end

#on_swarm_stopped(swarm:) ⇒ Object

Lifecycle: Called when swarm stops

Parameters:

  • swarm (Swarm)

    Swarm instance



172
173
174
# File 'lib/swarm_sdk/plugin.rb', line 172

def on_swarm_stopped(swarm:)
  # Override if needed
end

#on_user_message(agent_name:, prompt:, is_first_message:) ⇒ Array<String>

Lifecycle: Called on every user message

Plugins can return system reminders to inject based on the user's prompt. This enables features like semantic skill discovery, context injection, etc.

Examples:

Semantic skill discovery

def on_user_message(agent_name:, prompt:, is_first_message:)
  skills = semantic_search(prompt, threshold: 0.65)
  return [] if skills.empty?

  [build_skill_reminder(skills)]
end

Parameters:

  • agent_name (Symbol)

    Agent identifier

  • prompt (String)

    The user's message

  • is_first_message (Boolean)

    True if this is the first message in the conversation

Returns:

  • (Array<String>)

    System reminders to inject (empty array if none)



193
194
195
# File 'lib/swarm_sdk/plugin.rb', line 193

def on_user_message(agent_name:, prompt:, is_first_message:)
  []
end

#parse_config(raw_config) ⇒ Object

Parse plugin configuration from agent definition

Parameters:

  • raw_config (Object)

    Raw config (DSL object or Hash from YAML)

Returns:

  • (Object)

    Parsed configuration



120
121
122
# File 'lib/swarm_sdk/plugin.rb', line 120

def parse_config(raw_config)
  raw_config
end

#restore_agent_state(agent_name, state) ⇒ void

This method returns an undefined value.

Restore plugin-specific state for an agent

Called during state restoration. Restore any persisted state. This method is idempotent - calling it multiple times with the same state should produce the same result.

Examples:

Memory read tracking

def restore_agent_state(agent_name, state)
  entries = state[:read_entries] || state["read_entries"]
  return unless entries

  StorageReadTracker.restore_read_entries(agent_name, entries)
end

Parameters:

  • agent_name (Symbol)

    Agent identifier

  • state (Hash)

    Previously snapshotted state (with symbol keys)



256
257
258
# File 'lib/swarm_sdk/plugin.rb', line 256

def restore_agent_state(agent_name, state)
  # Override if needed
end

#serialize_config(agent_definition:) ⇒ Hash

Contribute to agent serialization (optional)

Called when Agent::Definition.to_h is invoked (e.g., for cloning agents in Workflow). Plugins can return config keys that should be included in the serialized hash to preserve their state.

This allows plugins to maintain their configuration when agents are cloned or serialized, without SwarmSDK needing to know about plugin-specific fields.

Examples:

Memory plugin serialization

def serialize_config(agent_definition:)
  return {} unless agent_definition.memory

  { memory: agent_definition.memory }
end

Parameters:

Returns:

  • (Hash)

    Config keys to include in to_h (e.g., { memory: config })



215
216
217
# File 'lib/swarm_sdk/plugin.rb', line 215

def serialize_config(agent_definition:)
  {}
end

#snapshot_agent_state(agent_name) ⇒ Hash

Snapshot plugin-specific state for an agent

Called during state snapshot creation (e.g., session persistence). Return any state your plugin needs to persist for this agent. The returned hash will be JSON serialized.

Examples:

Memory read tracking

def snapshot_agent_state(agent_name)
  entries = StorageReadTracker.get_read_entries(agent_name)
  return {} if entries.empty?

  { read_entries: entries }
end

Parameters:

  • agent_name (Symbol)

    Agent identifier

Returns:

  • (Hash)

    Plugin-specific state (empty hash if nothing to snapshot)



235
236
237
# File 'lib/swarm_sdk/plugin.rb', line 235

def snapshot_agent_state(agent_name)
  {}
end

#system_prompt_contribution(agent_definition:, storage:) ⇒ String?

Contribute to agent system prompt (optional)

Parameters:

  • agent_definition (Agent::Definition)

    Agent definition

  • storage (Object, nil)

    Plugin storage instance (if created)

Returns:

  • (String, nil)

    Prompt contribution or nil



129
130
131
# File 'lib/swarm_sdk/plugin.rb', line 129

def system_prompt_contribution(agent_definition:, storage:)
  nil
end

#toolsArray<Symbol>

List of tools provided by this plugin

Returns:

  • (Array<Symbol>)

    Tool names (e.g., [:MemoryWrite, :MemoryRead])



87
88
89
# File 'lib/swarm_sdk/plugin.rb', line 87

def tools
  []
end

#translate_yaml_config(builder, agent_config) ⇒ void

This method returns an undefined value.

Translate YAML configuration into DSL calls

Called during YAML-to-DSL translation. Plugins can translate their specific YAML configuration keys into DSL method calls on the builder. This allows SDK to remain plugin-agnostic while plugins can add YAML configuration support.

Examples:

Memory plugin YAML translation

def translate_yaml_config(builder, agent_config)
  memory_config = agent_config[:memory]
  return unless memory_config

  builder.instance_eval do
    memory do
      directory(memory_config[:directory])
      adapter(memory_config[:adapter]) if memory_config[:adapter]
      mode(memory_config[:mode]) if memory_config[:mode]
    end
  end
end

Parameters:

  • builder (Agent::Builder)

    Builder instance (self in DSL context)

  • agent_config (Hash)

    Full agent config from YAML



305
306
307
# File 'lib/swarm_sdk/plugin.rb', line 305

def translate_yaml_config(builder, agent_config)
  # Override if plugin needs YAML configuration support
end