Skip to content

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

Merged
galuszkm merged 4 commits into
mainfrom
feat/mg/plugins
Jul 22, 2026
Merged

feat(plugins): add declarative agent plugin support#75
galuszkm merged 4 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
… trim docs (#77)

Co-authored-by: Kiro Agent <244629292+kiro-agent@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class declarative agent plugin support to strands-compose’s YAML schema and resolution pipeline, wiring resolved strands.plugins.Plugin instances into strands.Agent(plugins=[...]) while keeping the library as a thin translator.

Changes:

  • Introduces PluginDef and an agents.<name>.plugins: field (string shorthand or {type, params}), plus path rewriting for plugin import specs.
  • Adds plugin resolvers (resolve_plugin, resolve_plugin_entry) and wires resolved plugins through both default and custom agent factory construction paths.
  • Updates docs + examples with a new Plugins chapter and a runnable examples/15_plugins/ demo; bumps strands-agents dependency floor to >=1.48.0.

Reviewed changes

Copilot reviewed 26 out of 27 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
uv.lock Raises locked strands-agents floor to >=1.48.0,<2.0.0.
pyproject.toml Raises runtime + extras dependency floor for strands-agents.
README.md Updates badge to reflect new strands-agents minimum.
src/strands_compose/config/schema.py Adds PluginDef and AgentDef.plugins; removes plugins from documented agent_kwargs passthrough list.
src/strands_compose/config/loaders/helpers.py Rewrites relative plugin import specs to absolute paths (mirrors hooks/tools behavior).
src/strands_compose/config/resolvers/plugins.py Implements plugin resolution via load_object + params kwargs, validating return type is Plugin.
src/strands_compose/config/resolvers/agents.py Resolves AgentDef.plugins and passes plugins= into both Agent() and custom factory paths.
src/strands_compose/config/resolvers/hooks.py Aligns hook import error handling/docs to load_object / ImportResolutionError.
src/strands_compose/config/resolvers/init.py Exposes plugin resolvers in the resolvers package public surface.
src/strands_compose/config/init.py Exposes PluginDef in strands_compose.config public surface.
tests/fakes/strands.py Adds FakePlugin and fake_plugin_factory to support plugin wiring/resolution tests.
tests/fakes/init.py Re-exports new fake plugin helpers.
tests/resolve/test_plugins.py Adds unit tests for plugin resolver behavior (malformed spec, non-Plugin, class/factory, string shorthand).
tests/resolve/test_agents.py Adds wiring test proving plugin-contributed @tool reaches agent.tool_names.
docs/README.md Adds docs landing page and links in a chapter table.
docs/configuration/README.md Adds Chapter 19 entry (Plugins).
docs/configuration/Chapter_19.md New Plugins chapter describing YAML shape, factory/class patterns, and error reference.
docs/configuration/Chapter_18.md Updates full reference to include plugins and PluginDef.
docs/configuration/Chapter_06.md Adds hooks ↔ plugins cross-reference.
docs/img/index.html Fixes logo asset path in docs HTML.
examples/README.md Adds example index entry for 15_plugins.
examples/15_plugins/config.yaml New example config demonstrating plugins: usage (skills, context injector factory, goal loop).
examples/15_plugins/main.py Runnable example driver that loads the config and demonstrates plugin behavior.
examples/15_plugins/plugins.py Example factory for building a ContextInjector.
examples/15_plugins/README.md Example documentation explaining plugin use-cases and the demo setup.
examples/15_plugins/skills/conventional-commits/SKILL.md Example skill content used by AgentSkills.
.kiro/skills/library-development/references/project-map.md Updates documented dependency floor and extras list in the project map.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/resolve/test_plugins.py
Comment thread tests/resolve/test_plugins.py
@galuszkm

Copy link
Copy Markdown
Member Author

@copilot I agree with your proposals to adjust tests as proposed in comments above. Implement!

Copilot AI commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

@copilot I agree with your proposals to adjust tests as proposed in comments above. Implement!

Implemented in 9c237b6. I updated tests/resolve/test_plugins.py to assert ImportResolutionError for invalid import specs and removed brittle exception-message matching for the non-plugin TypeError case.

@galuszkm
galuszkm merged commit 50138f9 into main Jul 22, 2026
9 checks passed
@galuszkm
galuszkm deleted the feat/mg/plugins branch July 22, 2026 10:05
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.

3 participants