Module: A2A::Plugin

Defined in:
lib/a2a/plugin.rb

Defined Under Namespace

Modules: Events Classes: AuthPlugin, Base, MiddlewarePlugin, TransportPlugin

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.hooksHash<Symbol, Array> (readonly)

Registered hooks

Returns:



33
34
35
# File 'lib/a2a/plugin.rb', line 33

def hooks
  @hooks
end

.registryHash<Symbol, Hash> (readonly)

Registry of all plugins

Returns:



29
30
31
# File 'lib/a2a/plugin.rb', line 29

def registry
  @registry
end

Class Method Details

.add_hook(event, callable = nil, priority: 50, &block) ⇒ Object

Register a hook

Parameters:

  • Hook event name

  • (defaults to: nil)

    Hook handler (optional if block given)

  • (defaults to: 50)

    Hook priority (lower = higher priority)

Raises:



130
131
132
133
134
135
136
137
138
# File 'lib/a2a/plugin.rb', line 130

def add_hook(event, callable = nil, priority: 50, &block)
  initialize! unless @hooks

  handler = callable || block
  raise ArgumentError, "Must provide callable or block" unless handler

  @hooks[event] << { callable: handler, priority: priority }
  @hooks[event].sort_by! { |hook| hook[:priority] }
end

.clear!Object

Clear all plugins (for testing)



181
182
183
184
185
186
# File 'lib/a2a/plugin.rb', line 181

def clear!
  @loaded_plugins&.each { |name| unload(name) }
  @registry&.clear
  @hooks&.clear
  initialize!
end

.execute_hooks(event, *args) ⇒ Array

Execute hooks for an event

Parameters:

  • Hook event name

  • Arguments to pass to hooks

Returns:

  • Results from all hooks



144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/a2a/plugin.rb', line 144

def execute_hooks(event, *args)
  initialize! unless @hooks

  results = []
  @hooks[event].each do |hook|
    result = hook[:callable].call(*args)
    results << result
  rescue StandardError => e
    A2A.config.logger&.error("Hook execution failed for #{event}: #{e.message}")
    raise A2A::Errors::PluginError, "Hook execution failed: #{e.message}"
  end
  results
end

.initialize!Object

Initialize plugin system



36
37
38
39
40
# File 'lib/a2a/plugin.rb', line 36

def initialize!
  @registry = {}
  @hooks = Hash.new { |h, k| h[k] = [] }
  @loaded_plugins = Set.new
end

.listHash

List all registered plugins

Returns:

  • Plugin registry information



168
169
170
171
172
173
174
175
176
177
178
# File 'lib/a2a/plugin.rb', line 168

def list
  initialize! unless @registry

  @registry.transform_values do |info|
    {
      type: info[:type],
      loaded: info[:loaded],
      options: info[:options]
    }
  end
end

.load(name, **config) ⇒ Object

Load a plugin

Parameters:

  • Plugin name

  • Plugin configuration

Returns:

  • Plugin instance

Raises:



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/a2a/plugin.rb', line 67

def load(name, **config)
  initialize! unless @registry

  plugin_info = @registry[name]
  raise A2A::Errors::PluginError, "Plugin not found: #{name}" unless plugin_info

  return plugin_info[:instance] if plugin_info[:loaded]

  begin
    instance = plugin_info[:class].new(**config)
    plugin_info[:instance] = instance
    plugin_info[:loaded] = true
    @loaded_plugins << name

    # Register plugin hooks
    instance.register_hooks(self) if instance.respond_to?(:register_hooks)

    A2A.config.logger&.info("Loaded plugin: #{name}")
    instance
  rescue StandardError => e
    raise A2A::Errors::PluginError, "Failed to load plugin #{name}: #{e.message}"
  end
end

.loaded?(name) ⇒ Boolean

Check if a plugin is loaded

Parameters:

  • Plugin name

Returns:



161
162
163
164
# File 'lib/a2a/plugin.rb', line 161

def loaded?(name)
  initialize! unless @registry
  @loaded_plugins.include?(name)
end

.loaded_plugins(type: nil) ⇒ Array<Object>

Get loaded plugins by type

Parameters:

  • (defaults to: nil)

    Plugin type

Returns:

  • Plugin instances



114
115
116
117
118
119
120
121
122
123
124
# File 'lib/a2a/plugin.rb', line 114

def loaded_plugins(type: nil)
  initialize! unless @registry

  plugins = @loaded_plugins.filter_map { |name| @registry[name][:instance] }

  if type
    plugins.select { |plugin| plugin.class.plugin_type == type }
  else
    plugins
  end
end

.register(name, plugin_class, **options) ⇒ Object

Register a plugin

Parameters:

  • Plugin name

  • Plugin class

  • Plugin options



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/a2a/plugin.rb', line 46

def register(name, plugin_class, **options)
  initialize! unless @registry

  unless plugin_class.respond_to?(:plugin_type)
    raise A2A::Errors::PluginError, "Plugin class must include A2A::Plugin::Base"
  end

  @registry[name] = {
    class: plugin_class,
    type: plugin_class.plugin_type,
    options: options,
    loaded: false
  }

  A2A.config.logger&.info("Registered plugin: #{name} (#{plugin_class.plugin_type})")
end

.unload(name) ⇒ Object

Unload a plugin

Parameters:

  • Plugin name



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/a2a/plugin.rb', line 93

def unload(name)
  initialize! unless @registry

  plugin_info = @registry[name]
  return unless plugin_info && plugin_info[:loaded]

  instance = plugin_info[:instance]

  # Call cleanup if available
  instance.cleanup if instance.respond_to?(:cleanup)

  plugin_info[:loaded] = false
  plugin_info[:instance] = nil
  @loaded_plugins.delete(name)

  A2A.config.logger&.info("Unloaded plugin: #{name}")
end