Skip to content

feat(cockpit): ag-ui subagents demo emits the protocol's SUBAGENT_* events - #962

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

feat(cockpit): ag-ui subagents demo emits the protocol's SUBAGENT_* events#962
blove merged 8 commits into
mainfrom
blove/agui-demo-subagent-events

Conversation

@blove

@blove blove commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

What changed

The cockpit AG-UI subagents demo (cockpit/ag-ui/subagents/python) now emits the protocol's standard subagent events instead of the private ACTIVITY convention:

  • SubagentEmittingAgent (src/streaming/subagent_emitting_agent.py) subclasses the ag-ui-langgraph bridge and wraps LangGraphAgent.run(), expanding the graph's subagent_activity CUSTOM events 1:N into SUBAGENT_STARTEDsubagentRunId-attributed TEXT_MESSAGE_START/CONTENT/ENDSUBAGENT_FINISHED (or SUBAGENT_ERROR). Ids follow the feat(runtimes): strands subagent delegation demo with standard SUBAGENT_* emission #956feat(runtimes): mastra subagent delegation demo with SUBAGENT_* injection in the bridge #958 convention: <toolCallId>-sub / <toolCallId>-sub-m1, parentToolCallId = the task tool call id. The CUSTOM event is consumed; other CUSTOM events pass through. Replaces activity_transform.py + ActivityEmittingAgent (the bridge's _dispatch_event hook is strictly 1:1 and could not carry the expansion).
  • Per-token deltas: SubagentStreamHandler drops the text_so_far accumulator and emits message_start {message_id} once, then message {message_id, delta} per token. The task tool emits an error phase (then re-raises) when the child fails.
  • SDK bump: ag-ui-protocol>=0.1.22 added as a direct dependency (pyproject.toml, uv.lock, re-exported requirements.txt) — the first release with subagent_run_id on every event.
  • deployments/ag-ui-dev regenerated (byte-identical mirror; combined requirements.txt now pins ag-ui-protocol==0.1.22).
  • Docs: docs/guide.md rewritten to the standard events + SubagentEmittingAgent; new docs/wire-capture-subagents.md (baseline, serializer probe, after-emitter capture, browser verification); e2e/component/prompt comments updated.

Spec: docs/superpowers/specs/2026-09-02-agui-demo-subagent-events-design.md. Plan: docs/superpowers/plans/2026-09-02-agui-demo-subagent-events.md (Tasks 0–3; Tasks 4–5 — the examples demo and website docs — follow in separate PRs).

Wire capture

cockpit/ag-ui/subagents/python/docs/wire-capture-subagents.md

Ordering finding (design §6): in every delegation round the bridge streams TOOL_CALL_START → all TOOL_CALL_ARGSTOOL_CALL_ENDSTEP_FINISHED(orchestrator)/STEP_STARTED(tools) before the tool body runs, so SUBAGENT_STARTED always follows an already-announced tool call (after-emitter capture: START 7 → END 292 → SUBAGENT_STARTED 306; 1307 → 1586 → 1600; 3037 → 3312 → 3326). The SUBAGENT_* block nests between TOOL_CALL_END and TOOL_CALL_RESULT.

Streaming finding

Live browser check (real key, nx serve, Playwright polling every 150ms): the research card mounts on SUBAGENT_STARTED and its message grows monotonically while running — 22 → 56 → 113 → 147 → 223 → 262 → 299 → 330 → 367 → 401 → 431 → 506 → 540 chars across consecutive samples — reaching 5,336 chars before flipping to complete and collapsing. 1,478 attributed TEXT_MESSAGE_CONTENT events across three delegations, one raw token each (the baseline shipped 2,077 ACTIVITY_DELTAs each carrying the full text-so-far). Screenshot: cockpit/ag-ui/subagents/angular/e2e/manual/subagent-card-live.png.

Tests

  • uv run pytest -q (cockpit/ag-ui/subagents/python): 18 passed (4 stream-handler + 14 emitter; the 4 activity-transform tests were deleted with the translator).
  • npx playwright test --config cockpit/ag-ui/subagents/angular/e2e/playwright.config.ts: 1 passed — assertions unchanged (projection-level: name, status, messages()[0].content, card count); aimock fixtures unchanged.
  • Serializer probe: SubagentStartedEvent reached the wire as {"type":"SUBAGENT_STARTED","subagentRunId":"…-sub","name":"research","parentToolCallId":"…"} with the stock encoder.

Deployment generator

scripts/generate-ag-ui-deployment-config.ts emitted LangGraphAgent(name=..., graph=...) for every LangGraph topic, so the aggregated Railway server (deployments/ag-ui-dev/server.py) mounted the stock bridge for subagents and served the graph's raw subagent_activity CUSTOM events — no subagent cards in production (pre-existing; the ACTIVITY translator had the same gap). The generator now reads each LangGraph topic's own src/server.py for agent = <Cls>( plus a package-relative from .<module> import <Cls> and, when <Cls> is a LangGraphAgent subclass, imports it from deps.<mod>.src.<module> and constructs it with the same name/graph args; other topics keep the plain wrapper, and a subclass that is mounted but not importable from the topic package fails at generation time rather than at container boot. No new marker file — the demo's server.py is the single source of truth. Regenerated deployments/ag-ui-dev/server.py (one import plus the subagents mount; requirements.txt and deps/ unchanged), so the Railway lane now runs SubagentEmittingAgent. Boot-checked from the deployment root with the Dockerfile's pip-installed requirements: /ok 200, /agent/subagents 401 without the internal token. Spec: 18 generator cases pass (6 new), nx test scripts green.

🤖 Generated with Claude Code

blove and others added 6 commits September 2, 2026 11:31
…* events

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…>=0.1.22

Baseline SSE capture of the ACTIVITY convention (TOOL_CALL_START precedes
the first ACTIVITY event; TOOL_CALL_END lands before the tool runs), the
serializer probe confirming SubagentStartedEvent camelCases on the wire,
and the SDK bump (pyproject + uv.lock + re-exported requirements.txt).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
SubagentStreamHandler drops the text_so_far accumulator: it emits one
message_start {message_id} before the first token and message {message_id,
delta} per token. The task tool emits an error phase (then re-raises) when
the child fails.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… run-wrapping emitter

SubagentEmittingAgent wraps LangGraphAgent.run and expands the graph's
subagent_activity CUSTOM events 1:N into SUBAGENT_STARTED / attributed
TEXT_MESSAGE_START/CONTENT/END / SUBAGENT_FINISHED / SUBAGENT_ERROR
(ids <tid>-sub and <tid>-sub-m<n>, tid = the task tool call id). The CUSTOM
event is consumed; other CUSTOM events pass through. Replaces the private
ACTIVITY_SNAPSHOT/DELTA translator (activity_transform + ActivityEmittingAgent).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…* emitter

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
guide.md describes the standard SUBAGENT_* events and SubagentEmittingAgent
(replacing the ACTIVITY walkthrough); the wire-capture doc gains the
after-emitter capture (per-token attributed deltas, START -> END ->
SUBAGENT_STARTED order measured) and the live browser verification with the
running-card screenshot; e2e comments name the new pipeline (assertions
unchanged). ag-ui-dev mirror regenerated for the mirrored docs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@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 Ready Ready Preview Sep 2, 2026 8:46pm 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 and others added 2 commits September 2, 2026 13:43
… agent class

The aggregated ag-ui-dev server emitted `LangGraphAgent(name=..., graph=...)`
for every LangGraph topic, but the subagents demo mounts
`SubagentEmittingAgent` — a LangGraphAgent subclass that expands the graph's
`subagent_activity` CUSTOM events into standard SUBAGENT_* events. The Railway
lane therefore served raw CUSTOM events and rendered no subagent cards (the
earlier ACTIVITY translator had the same gap).

Convention: the topic's own `src/server.py` is the source of truth — no new
marker file that could drift from what the demo actually mounts. The generator
looks for `agent = <Cls>(` plus a package-relative `from .<module> import <Cls>`
line; anything other than the stock `LangGraphAgent` is imported from
`deps.<mod>.src.<module>` and constructed with the same name/graph args. An
inline `LangGraphAgent(...)` mount keeps the plain wrapper; a subclass that is
mounted but not importable from the topic package fails at generation time
instead of at container boot.

Spec: generator case asserting subagents mounts SubagentEmittingAgent (and
interrupts keeps LangGraphAgent), a buildServerPy adapter case, and four
detectBridgeAgent parsing cases.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…mittingAgent

`npx tsx scripts/generate-ag-ui-deployment-config.ts`. Only server.py changes:
one added import and the subagents mount now constructs SubagentEmittingAgent.
requirements.txt and deps/ are byte-identical. Boot-checked locally from the
deployment root (pip-installed requirements.txt as the Dockerfile does):
/ok → 200, /agent/subagents → 401 without X-Internal-Token.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@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 enabled auto-merge (squash) September 2, 2026 20:44
@blove
blove merged commit 912927a into main Sep 2, 2026
31 checks passed
@blove
blove deleted the blove/agui-demo-subagent-events branch September 2, 2026 21:10
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