Skip to content

feat(plugins): add MultiAgentPlugin for Swarm and Graph orchestrators#2280

Open
zastrowm wants to merge 9 commits into
strands-agents:mainfrom
zastrowm:multi_agent_plugins
Open

feat(plugins): add MultiAgentPlugin for Swarm and Graph orchestrators#2280
zastrowm wants to merge 9 commits into
strands-agents:mainfrom
zastrowm:multi_agent_plugins

Conversation

@zastrowm
Copy link
Copy Markdown
Member

Description

The existing Plugin system only targets individual agents. When building observability, guardrails, or custom behavior for multi-agent orchestrators (Swarm, Graph), there's no composable mechanism — you're forced to manually wire up HookProvider instances and manage initialization yourself. This PR introduces MultiAgentPlugin, the orchestrator-level counterpart to Plugin, giving orchestrators the same declarative plugin experience that agents already have.

Public API Changes

New MultiAgentPlugin base class (exported from strands and strands.plugins):

from strands import MultiAgentPlugin
from strands.plugins import hook
from strands.hooks import BeforeNodeCallEvent, AfterNodeCallEvent

class MonitoringPlugin(MultiAgentPlugin):
    name = "monitoring"

    @hook
    def on_before_node(self, event: BeforeNodeCallEvent):
        print(f"Node {event.node_id} starting")

    @hook
    def on_after_node(self, event: AfterNodeCallEvent):
        print(f"Node {event.node_id} completed")

Both Swarm and Graph accept a new plugins parameter:

from strands.multiagent import Swarm, GraphBuilder

# Swarm
swarm = Swarm(nodes=[agent1, agent2], plugins=[MonitoringPlugin()])

# Graph (via builder)
graph = GraphBuilder()
    .add_node(agent1, node_id="a1")
    .set_entry_point("a1")
    .set_plugins([MonitoringPlugin()])
    .build()

A single class can implement both Plugin and MultiAgentPlugin for dual-use across agents and orchestrators:

class ObservabilityPlugin(Plugin, MultiAgentPlugin):
    name = "observability"

    @hook
    def on_model_call(self, event: BeforeModelCallEvent):
        ...  # Fires when attached to an agent

    @hook
    def on_node_call(self, event: BeforeNodeCallEvent):
        ...  # Fires when attached to an orchestrator

    def init_agent(self, agent): ...
    def init_multi_agent(self, orchestrator): ...

Related Issues

Documentation PR

Type of Change

New feature

Testing

How have you tested the change? Verify that the changes do not break functionality or introduce warnings in consuming repositories: agents-docs, agents-tools, agents-cli

  • I ran hatch run prepare

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 11, 2026

Codecov Report

❌ Patch coverage is 97.36842% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/strands/plugins/plugin.py 60.00% 0 Missing and 2 partials ⚠️
src/strands/multiagent/base.py 66.66% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Comment thread src/strands/plugins/_discovery.py Outdated
Comment thread src/strands/plugins/multiagent_registry.py Outdated
@github-actions
Copy link
Copy Markdown

Issue: This PR introduces a new public class (MultiAgentPlugin) that customers will directly use and extend. Per the API Bar Raising guidelines, this qualifies as a "moderate change" (adding a new class that customers use to achieve new behavior) and should have the needs-api-review label.

Suggestion: Add the needs-api-review label and ensure an API reviewer evaluates the public surface from a customer perspective before merge.

Comment thread tests/strands/plugins/test_multiagent_plugin.py
Comment thread src/strands/plugins/multiagent_plugin.py
Comment thread src/strands/plugins/multiagent_registry.py Outdated
Comment thread src/strands/plugins/_discovery.py Outdated
@github-actions github-actions Bot removed the size/xl label May 11, 2026
@zastrowm zastrowm added the needs-api-review Makes changes to the public API surface label May 11, 2026
- Extract _discover_methods generic helper in _discovery.py to eliminate
  duplication between discover_hooks and discover_tools
- Add test_dual_plugin_discover_hooks_called_once to verify the hasattr
  guard prevents double-discovery in dual inheritance
mkmeral
mkmeral previously approved these changes May 13, 2026
Comment thread src/strands/plugins/multiagent_plugin.py
@mkmeral
Copy link
Copy Markdown
Contributor

mkmeral commented May 13, 2026

/strands review

Comment thread src/strands/plugins/_discovery.py Outdated
@github-actions

This comment was marked as outdated.

@github-actions
Copy link
Copy Markdown

Assessment: Approve

All review feedback has been addressed. The unused TypeVar is removed. No further changes needed from my side.

The multiagent vs multi_agent naming question from @mkmeral has been answered by the author — it follows existing SessionManager.initialize_multi_agent() / SessionManager.sync_multi_agent() conventions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-api-review Makes changes to the public API surface size/xl

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants