Skip to content

feat(plugins): add declarative agent plugin support#75

Open
galuszkm wants to merge 2 commits into
mainfrom
feat/mg/plugins
Open

feat(plugins): add declarative agent plugin support#75
galuszkm wants to merge 2 commits into
mainfrom
feat/mg/plugins

Conversation

@galuszkm

Copy link
Copy Markdown
Member

Description

Adds first-class support for strands plugins as a declarative field on agents.
Agents can now attach reusable behaviour packages — skills, context injection, steering, goal loops, or any custom strands.plugins.Plugin — straight from YAML, the same way hooks: already works.

Each plugins: entry is resolved to a live strands.plugins.Plugin instance and passed through to strands.Agent(plugins=[...]). strands-compose stays a thin translator: it resolves the import spec, calls it with params, validates the result is a Plugin, and otherwise gets out of the way.

What's included:

  • Schema — new PluginDef (type + params) and a plugins: list[PluginDef | str] field on AgentDef. Accepts an inline object (type: + optional params:) or a bare string shorthand, mirroring hooks:.
  • Resolverconfig/resolvers/plugins.py with resolve_plugin / resolve_plugin_entry. Supports both module.path:Name (installed package) and ./file.py:Name (local file) import specs, and resolves either a Plugin subclass or a factory callable returning one.
  • Path handling — a plugin's type: is rewritten relative to the config file (like tools/hooks); params are treated as opaque kwargs and forwarded verbatim.
  • Agent wiringbuild_agent_from_def resolves the plugin list and passes it to both the standard and custom-factory Agent(...) construction paths.
  • Cleanupplugins removed from the documented agent_kwargs passthrough now that it's a first-class field (prevents a duplicate-keyword error).
  • Docs & example — new Chapter 19 (Plugins) plus a full-reference entry, a restructured docs/README.md, and a runnable examples/15_plugins/ demoing AgentSkills, a ContextInjector factory, and GoalLoop, including a sample conventional-commits skill.
  • Dependency floor — bumps strands-agents to >=1.48.0,<2.0.0 across all extras, the minimum exposing the plugins API used here.

Related Issues

N/A

Type of Change

  • New feature

YAML / API Impact

Yes — this extends both the config schema and the public API, backwards-compatible:

  • YAML: adds an optional agents.<name>.plugins: list. Defaults to empty, so all existing configs are unaffected.
  • Python API: exports a new PluginDef model and resolve_plugin / resolve_plugin_entry resolvers. Nothing existing is renamed or removed.
  • Behavioural note: plugins is no longer accepted via agent_kwargs — it's now a dedicated field. Passing it both ways raises a duplicate-keyword TypeError from Agent(), which is the intended guard rather than a silent regression.
  • Minimum dependency raised to strands-agents>=1.48.0.

Testing

How have you tested the change?

  • I ran uv run just check (lint + type check) — clean, no issues
  • I ran uv run just test for overall testing — 232 passed, 76% coverage
  • I added or updated tests that prove my fix is effective or my feature works
  • I verified existing examples in examples/ still work

New/updated tests:

  • tests/resolve/test_plugins.py — covers class resolution with params, factory resolution, the bare-string shorthand, missing : in type (ValueError), and a non-Plugin result (TypeError).
  • tests/resolve/test_agents.py — asserts a declared plugin's @tool reaches agent.tool_names, proving the resolved list is wired into Agent(plugins=[...]).
  • tests/fakes/ — adds a FakePlugin and fake_plugin_factory covering both the class and callable resolution paths.

Checklist

  • I have read the CONTRIBUTING document
  • I have updated the documentation accordingly
  • 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.

galuszkm added 2 commits July 21, 2026 22:56
- add `PluginDef` schema and `plugins:` field on agents (inline object + string shorthand)
- resolve entries to live `strands.plugins.Plugin` instances via class or factory, passed to `Agent(plugins=[...])`
- rewrite plugin `type:` import specs relative to the config file; leave `params` opaque
- remove `plugins` from `agent_kwargs` now that it's first-class
- require `strands-agents>=1.48.0` across all extras for the plugins API
- document in Chapter 19 + full reference and add runnable `examples/15_plugins`
- cover class, factory, non-Plugin, and bad-spec paths in tests with a `FakePlugin` fake
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant