Skip to content

Phase 2: Per-skill middleware hook in ADCPAgentExecutor (PR-P) #226

@bokelley

Description

@bokelley

Summary

Downstream (salesagent) runs audit logging + activity-feed hooks on every A2A skill dispatch today. Their 2,288 LOC custom A2A executor exists partly because ADCPAgentExecutor.execute() is a black box — there's no pre/post hook.

Proposed API

Two shapes to choose from; either solves the problem:

Option A — middleware list (async, ordered):

class SkillMiddleware(Protocol):
    async def __call__(
        self,
        skill_name: str,
        params: dict[str, Any],
        context: ToolContext,
        call_next: Callable[[], Awaitable[Any]],
    ) -> Any: ...

ADCPAgentExecutor(handler, ..., middleware=[AuditLogMiddleware(), ActivityFeedMiddleware()])

Option B — two callbacks (simpler, no recursion):

ADCPAgentExecutor(
    handler,
    ...,
    before_skill: Callable[[str, dict, ToolContext], Awaitable[None]] | None = None,
    after_skill: Callable[[str, dict, ToolContext, Any | Exception], Awaitable[None]] | None = None,
)

Option A is more expressive (middleware can short-circuit, transform result, wrap in retry). Option B is easier to compose at the callsite and doesn't require Protocol/abstract-class boilerplate downstream. Leaning toward A because audit requires exception-capture semantics.

Acceptance

  • Hook wired into ADCPAgentExecutor.execute().
  • Surfaced on create_a2a_server(middleware=...) pass-through.
  • Integration test exercising a logging middleware observing every skill dispatch (including error paths).
  • Section in docs/handler-authoring.md showing the audit-log recipe.

Context

Roadmap item PR-P (Phase 2) from .context/sdk-adoption-roadmap.md. Third of three blockers gating salesagent's A2A migration (with #224, #225).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions