Skip to content

feat(plugins): add AuthorityRoutingPlugin (ADVISE/EXECUTE/DEFER/STOP) - #172

Open
Palo-Alto-AI-Research-Lab wants to merge 1 commit into
google:mainfrom
Palo-Alto-AI-Research-Lab:feat/authority-routing-plugin
Open

feat(plugins): add AuthorityRoutingPlugin (ADVISE/EXECUTE/DEFER/STOP)#172
Palo-Alto-AI-Research-Lab wants to merge 1 commit into
google:mainfrom
Palo-Alto-AI-Research-Lab:feat/authority-routing-plugin

Conversation

@Palo-Alto-AI-Research-Lab

Copy link
Copy Markdown

Closes #171.

What

A self-contained ADK BasePlugin that decides an authority posture for every tool call before it runs. Tool schemas govern access; this plugin governs authorization — the layer where "advice became action", "one bounded edit became a workflow", and "an approval was required but the agent proceeded" failures live.

Two stages produce the final posture:

  1. Posture router — optional, caller-supplied callable (typically a model call) returning a validated ADVISE / EXECUTE / DEFER / STOP verdict with a scope statement.
  2. Deterministic guard — an irreversibility keyword tripwire (scanning tool name + arg values) plus an approval-state check on session context, composed with the router under most-restrictive-wins: plain code can only make a posture stricter, never looser.

Design properties:

  • Fail-closed — an unparseable or raised router verdict defaults to DEFER (an unreadable authorization is not an authorization).
  • Guard-only mode (no router) is fully deterministic, needs no model, and adds no dependency.
  • Complements AgentGovernancePlugin (policy-as-code allow/deny) and the HITL approval gateway rather than duplicating them — those answer "is this call permitted by policy?"; this answers "was the agent authorized to act at all, and within what scope?".

When the final posture is anything other than EXECUTE, before_tool_callback returns a block dict that short-circuits the tool (per the ADK plugin contract).

Files

  • src/google/adk_community/plugins/authority_routing_plugin.py — the plugin (self-contained, no new deps)
  • src/google/adk_community/plugins/__init__.py — exports AuthorityRoutingPlugin, Posture, PostureVerdict, AuthorityRequest, stricter
  • tests/plugins/test_authority_routing_plugin.py — 32 deterministic unit tests
  • contributing/samples/authority_routing/{main.py,README.md} — runnable sample

Testing plan

Unit tests — 32 deterministic tests (no credentials, no network) covering the posture ladder, guard-only mode, router mode, most-restrictive-wins composition, fail-closed behavior, verdict coercion, customization, and the block-response shape:

$ pytest tests/plugins/test_authority_routing_plugin.py -q
32 passed
$ pytest tests/ -q
106 passed, 14 skipped

End-to-end samplepython contributing/samples/authority_routing/main.py wires the plugin into a Runner and runs a live walkthrough of the decision layer (deterministic demo router; tool-call logs go to stderr):

CASE                                          TOOL             POSTURE  OUTCOME
------------------------------------------------------------------------------------------------
authorized read — router EXECUTE, guard clear web_search       EXECUTE  tool runs
advice requested — agent must NOT execute     update_ticket    ADVISE   blocked — user asked for a recommendation, not an action
irreversible call — guard overrides EXECUTE   delete_records   DEFER    blocked — deterministic guard: irreversibility tripwire: 'delete'
approval pending — guard floors to DEFER      send_email       DEFER    blocked — deterministic guard: approval-state marker in context: 'awaiting approval'
disallowed — STOP survives strictest-wins     read_vault       STOP     blocked — blocked by standing policy

Row 3 is the key case: the router authorized EXECUTE, but the tool call is irreversible, so the deterministic guard floored it to DEFER. Row 5 shows the opposite — the router's STOP survives even though the guard raised no concern.

Formattingisort + pyink clean on the added files (./autoformat.sh).

Type of change

New community plugin. Small, focused, one concern; no changes to existing modules beyond the __init__ export.

Provenance / AI-authorship disclosure

The four-posture pattern, the most-restrictive-wins composition, and the tripwire come from a live multi-agent system and were first published as an Anthropic cookbook notebook. Design and validation are mine; the implementation was drafted with AI assistance, then reviewed and tested by hand. Happy to adjust the API surface, naming, or placement to match maintainer preferences.

@google-cla

google-cla Bot commented Jul 23, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@Palo-Alto-AI-Research-Lab

Copy link
Copy Markdown
Author

@googlebot I signed it!

Adds a self-contained ADK BasePlugin that decides an authority posture for
every tool call before it runs. Tool schemas govern access; this plugin
governs authorization — the layer where "advice became action", "one bounded
edit became a workflow", and "an approval was required but the agent proceeded"
failures live.

- Posture router (optional, caller-supplied callable, typically a model call)
  returning a validated ADVISE/EXECUTE/DEFER/STOP verdict with a scope.
- Deterministic guard: irreversibility keyword tripwire + approval-state check,
  composed with the router under most-restrictive-wins — plain code can only
  tighten a verdict, never loosen it.
- Fail-closed: an unparseable or raised router verdict defaults to DEFER.
- Guard-only mode (no router) is fully deterministic and dependency-free.

Complements AgentGovernancePlugin (policy-as-code allow/deny) and the HITL
approval gateway: those answer "is this call permitted by policy?"; this answers
"was the agent authorized to act at all, and within what scope?".

Includes 32 deterministic unit tests, a registered export, and a runnable
sample with live output (no API key, no network).

The four-posture pattern, most-restrictive-wins composition, and tripwire were
first published as an Anthropic cookbook notebook and come from a live
multi-agent system. Design and validation are the author's; implementation was
drafted with AI assistance, then reviewed and tested by hand.
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.

feat(plugins): add AuthorityRoutingPlugin — pre-execution authority posture (ADVISE/EXECUTE/DEFER/STOP)

2 participants