Skip to content

feat(runtimes): maf subagent delegation demo with queue-merged SUBAGENT_* emission - #957

Merged
blove merged 8 commits into
mainfrom
blove/maf-subagent-demo
Sep 2, 2026
Merged

feat(runtimes): maf subagent delegation demo with queue-merged SUBAGENT_* emission#957
blove merged 8 commits into
mainfrom
blove/maf-subagent-demo

Conversation

@blove

@blove blove commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Third PR of the runtime-subagents arc (adapter #955, Strands #956).

  • The MAF expense demo delegates policy research to a policy_researcher specialist (agents-as-tools; handoff autonomous mode avoided as experimental).
  • The MAF bridge has no tool-reachable emitter, so src/subagent_emitter.py wraps AgentFrameworkAgent.run with a ContextVar-carried queue merge: a pump task drains the bridge generator into the queue while the tool body enqueues SUBAGENT_STARTEDtoken-granular attributed child deltasSUBAGENT_FINISHED (SUBAGENT_ERROR on failure). Composition-built subclass shares config + approval store, so the interrupt/resume flows ride the same wrapped instance untouched.
  • Tool-call-id correlation: the pump records each TOOL_CALL_START id in a per-tool-name FIFO; each delegation pops its own id — safe under MAF's concurrent tool batches (identity-separation test included). Clean shutdown proven (pump cancelled+awaited, zero pending tasks, ContextVar reset).
  • Evidence in docs/wire-capture-subagents.md: pre-emitter capture (specialist invisible on the wire), post-emitter capture (100 streamed child deltas), and live browser verification — card text grows monotonically while running (two runs sampled), screenshot committed.
  • e2e: new delegation spec + fixtures (hasToolResult-first ordering); deployments/ag-ui-dev regenerated.

Testing

  • Python: 20/20 (delegation registry, emitter sequence field-for-field, error path, double-call identity separation, consumer-break shutdown, str-terminal fallback).
  • e2e replay: 4/4 post-rebase.
  • Live: full wire capture + streaming browser verification; servers torn down after.

🤖 Generated with Claude Code

blove and others added 8 commits September 2, 2026 09:56
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…alist

The expense copilot gains a tool-less policy_researcher specialist Agent
and an async research_policy tool that streams the specialist's deltas
through the delegation_* emitter helpers (SUBAGENT_STARTED / attributed
TEXT_MESSAGE_* / SUBAGENT_FINISHED|ERROR, ids derived from the delegation
toolCallId with a generated sub-<hex8> fallback). The helpers are pure
no-ops outside a wrapped run; the queue-merge run wrapper that puts these
events on the wire lands in the next commit. Adds the pytest dev-group
and asyncio_mode infra plus registration tests (no live model calls).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… at the bridge boundary

SubagentEmittingAgent wraps AgentFrameworkAgent.run (the exact method the
FastAPI endpoint consumes) with the pump-task merge queue the Task-0 spike
named: a task drains the inner bridge generator into an asyncio.Queue the
ContextVar shares with the tool body, so a delta enqueued mid-tool wakes
the outer consumer immediately (live interleaving; a drain-between-yields
design would batch every child delta until the tool returned). The pump
records each TOOL_CALL_START toolCallId by name, which is what makes
current_tool_call_id deterministic before the tool body runs. Pump
exceptions propagate to the consumer; consumer break / client disconnect
cancels and awaits the pump and closes the inner generator — no orphaned
tasks. server.py mounts the wrapped agent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ocstring

The name→tid map overwrote on a same-tool double call (reachable: MAF
runs multi-tool batches concurrently via asyncio.gather and the bridge
streams all TOOL_CALL_STARTs first), making both bodies share the second
tid and one delegation. The correlation map is now a per-name FIFO: the
pump appends each TOOL_CALL_START id, current_tool_call_id pops the
oldest, so every invocation gets its own tid, _Delegation, and message
id (new identity-separation test). Also corrects the module docstring —
the measured wire shows TOOL_CALL_END arrives AFTER the tool returns
(SUBAGENT_* lands between ARGS and END), so correlation relies on START
alone — and aligns the unit-test fake's event order with that wire.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three fixture entries for the delegation turn (primary tool call,
specialist matched on its 'expense-policy researcher' system prompt,
hasToolResult continuation ordered first) plus a spec asserting the
delegation renders as one <chat-subagent-card> naming policy_researcher.
Requires the cherry-picked toolCallId anchoring fix — AG-UI native
SUBAGENT_* keys the adapter map by subagentRunId (`<toolCallId>-sub`).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Live run (real key) on :5330/:4330 driven headlessly with Playwright:
the delegation prompt renders an inline <chat-subagent-card> anchored to
the research_policy call, and 150ms innerText polling shows the
specialist's transcript growing monotonically (66 -> 622 chars) while the
badge reads running, confirming progressive delta rendering. Screenshot
follows the Strands e2e/manual convention.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@blove
blove enabled auto-merge (squash) September 2, 2026 16:56
@vercel

vercel Bot commented Sep 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
threadplane Building Building Preview Sep 2, 2026 4:56pm UTC

Request Review

@github-actions github-actions Bot 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.

Automated approval: this PR received an intelligent (AI) code review. See the review comments on this PR.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 0s —— View job


I'll analyze this and get back to you.

@blove
blove merged commit 5e581fa into main Sep 2, 2026
31 of 32 checks passed
@blove
blove deleted the blove/maf-subagent-demo branch September 2, 2026 17:44
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