From 6f9d2b6ca1a101075cf879db01a495c741718eba Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 2 Sep 2026 11:39:52 -0700 Subject: [PATCH 1/8] docs: spec + plan for Mastra sub-agent streaming via a public-API stream tee Co-Authored-By: Claude Fable 5.1 --- .../2026-09-02-mastra-subagent-streaming.md | 51 +++++++++++ ...-09-02-mastra-subagent-streaming-design.md | 86 +++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 docs/superpowers/plans/2026-09-02-mastra-subagent-streaming.md create mode 100644 docs/superpowers/specs/2026-09-02-mastra-subagent-streaming-design.md diff --git a/docs/superpowers/plans/2026-09-02-mastra-subagent-streaming.md b/docs/superpowers/plans/2026-09-02-mastra-subagent-streaming.md new file mode 100644 index 000000000..6e9d81bbe --- /dev/null +++ b/docs/superpowers/plans/2026-09-02-mastra-subagent-streaming.md @@ -0,0 +1,51 @@ +# Mastra Sub-agent Streaming Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** The Mastra demo streams the sub-agent's child deltas to the AG-UI wire (with an eager `TOOL_CALL_START`), flipping the matrix cell from Partial to Yes. + +**Architecture:** See `docs/superpowers/specs/2026-09-02-mastra-subagent-streaming-design.md`. A public-API stream tee (`Proxy` over the Mastra `Agent`, wrapping `stream()`/`resumeStream()`'s `fullStream`) observes each chunk before the unmodified bridge consumes it; the per-run injector maps `tool-call`/`tool-output`/`tool-result`/`tool-call-suspended` chunks to synthesized eager `TOOL_CALL_*` + `SUBAGENT_*` + attributed `TEXT_MESSAGE_*` events and dedupes the bridge's later buffered copies. + +**Tech Stack:** Node 20+, `@mastra/core@1.63.2`, `@ag-ui/mastra@1.1.2` (unchanged pins), `node --test`, Playwright + aimock replay. + +**Branch:** `blove/mastra-subagent-streaming` (off origin/main; spec + plan committed). + +**Files:** `deployments/ag-ui-mastra/{streaming-tee.mjs (new), subagent-emitter.mjs, server.mjs, test/streaming-tee.test.mjs (new), test/subagent-emitter.test.mjs}`; `cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md`; docs/blog pages listed in Task 5. + +--- + +### Task 0: Spike (no production code) + +- [ ] Read `deployments/ag-ui-mastra/server.mjs`, `agents.mjs`, `subagent-emitter.mjs`, `test/subagent-emitter.test.mjs`, and the wire-capture doc; read `node_modules/@ag-ui/mastra/dist/*.mjs` around `isLocalMastraAgent`, `streamMastraAgent` (`this.agent.stream(A,s)` → `processFullStream(m.fullStream,…)`), and `resumeStream` usage, to list every agent member the bridge touches. +- [ ] Card-mount check: read `libs/chat/src/lib/primitives/chat-tool-calls/chat-tool-calls.component.ts` — confirm cards are anchored to entries in the parent `toolCalls()` list (i.e. a `SUBAGENT_STARTED` with no prior `TOOL_CALL_START` renders no card). Record the finding. +- [ ] Raw `fullStream` capture: export the key silently (`export OPENAI_API_KEY=$(grep '^OPENAI_API_KEY=' /Users/blove/repos/angular-agent-framework/.env | cut -d= -f2-)`), write a scratch script in `deployments/ag-ui-mastra/` (uncommitted) that calls the camping supervisor's `stream()` with the delegation prompt and logs every chunk `{type, payload.toolCallId?, payload.toolName?, payload.output?.type}`; note the order of `tool-call` → `tool-output(start/text-start/text-delta×N/text-end/…)` → `tool-result`, the `start`/`step-start` messageId available for `parentMessageId`, and whether `tool-call-suspended` appears. +- [ ] Proxy feasibility test (this one IS committed): `test/streaming-tee.test.mjs` — construct a real `Agent` from `agents.mjs`'s exports (no model call), wrap with a minimal Proxy prototype, assert `'getMemory' in proxy`, `typeof proxy.listTools === 'function'`, and that calling a stubbed `stream()` via the proxy returns an object whose `fullStream` is the wrapped generator. Run `node --test test/streaming-tee.test.mjs` → this fails until Task 1 provides the module; keep it as the failing test. +- [ ] Append "## Streaming spike" to `cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md` (chunk order, parentMessageId source, card-mount finding, suspended presence). Commit `docs(runtimes): mastra streaming spike — raw fullStream order and card-mount finding` + `Co-Authored-By: Claude Fable 5.1 `. + +### Task 1: `streaming-tee.mjs` (TDD) + +- [ ] Tests (`test/streaming-tee.test.mjs`): with a fake agent `{ getMemory(){}, listTools(){}, async stream(){ return { fullStream: (async function*(){ yield {type:'a'}; yield {type:'b'}; })(), text: 'x' } } }`: (1) observer sees `a` then `b`, each BEFORE the consumer receives it (record an interleaved trace `obs:a, out:a, obs:b, out:b`); (2) non-`fullStream` properties of the stream result are preserved (`text === 'x'`); (3) `resumeStream` wrapped the same way; (4) other members forward with `this` bound to the real agent (a method reading a `#private` field on a real `Agent` subclass instance still works through the proxy); (5) an observer exception does not break the consumer (logged, chunk still yielded). +- [ ] Implement `withDelegationTee(agent, observe)` per the spec. Commit `feat(runtimes): mastra stream tee — observe fullStream chunks before the bridge consumes them`. + +### Task 2: Injector chunk mapping + dedupe (TDD) + +- [ ] Tests (`test/subagent-emitter.test.mjs`, extend): feed `chunk()` sequences copied from the spike capture and assert exact events: eager `TOOL_CALL_START{toolCallId,toolCallName,parentMessageId}`/`ARGS{delta: JSON}`/`END` + `SUBAGENT_STARTED` on the `agent-*` `tool-call`; attributed `TEXT_MESSAGE_START/CONTENT×N/END` from `tool-output` inner text chunks (lazy START when `text-start` is absent); `SUBAGENT_FINISHED` on `tool-result` (and `SUBAGENT_ERROR` on the failure shape); `eventsFor` DROPS the bridge's later `TOOL_CALL_START/ARGS/END` for a synthesized id but passes `TOOL_CALL_RESULT`; the old single-chunk synthesis fires ONLY when no deltas were observed; `tool-call-suspended` → close message + `SUBAGENT_FINISHED{outcome:{type:'suspended'}}`; non-`agent-` tool-calls untouched; terminal cleanup closes open messages then `SUBAGENT_ERROR` for pending ids exactly once. +- [ ] Implement in `subagent-emitter.mjs` (pure per-run state: `pending` map with `{ name, messageOpen, messageId, deltasSeen, synthesized }`). Commit `feat(runtimes): mastra injector maps delegation chunks to eager TOOL_CALL_* and attributed child deltas`. + +### Task 3: `server.mjs` wiring + e2e + +- [ ] Per request: `const injector = createSubagentInjector(); const observe = (c) => { for (const e of injector.chunk(c)) write(e); }; const bridge = new MastraAgent({ ..., agent: withDelegationTee(agent, observe) });` keeping the existing `for (const e of injector.eventsFor(event)) write(e)` for bridge events. Make sure `write` is the same SSE frame writer for both paths. +- [ ] `npm test` (lane) green; free ports (cockpit/ports.mjs → cockpit-runtimes-mastra-angular), `npx playwright test --config cockpit/runtimes/mastra/angular/e2e/playwright.config.ts` → 5/5 (assertions unchanged). Commit `feat(runtimes): mastra server wires the delegation tee into the SSE stream`. + +### Task 4: Live verification + +- [ ] Real-key server + `npx nx serve cockpit-runtimes-mastra-angular`; POST the delegation prompt and tee the SSE: assert eager `TOOL_CALL_START` + `SUBAGENT_STARTED` precede the first attributed delta; count `TEXT_MESSAGE_CONTENT` with `subagentRunId`; confirm no duplicate `TOOL_CALL_START` for the delegation id. Browser: poll the card's innerText ~150 ms; record growth while `running`; screenshot over `cockpit/runtimes/mastra/angular/e2e/manual/subagent-card-live.png`. Append "## After streaming" + updated "## Browser verification" to the wire-capture doc; note the suspended caveat and the subclass alternative as fallback design. Kill servers. Commit `docs(runtimes): mastra streaming live verification`. + +### Task 5: Docs — flip the cell + +- [ ] `apps/website/content/docs/choosing-an-adapter/index.mdx`: Mastra Subagents cell → `Yes`; cause cell → the emitter (public-API stream tee) note; the "one Partial cell" sentences in the subagents section rewritten (all three stream live; note Mastra's card streams via the tee because the bridge itself drops child output). `runtimes/getting-started/introduction.mdx` matrix + the "lifecycle-plus-final-text on Mastra" clause; `runtimes/mastra/overview.mdx` Surface row + "How subagents surface" section; `runtimes/mastra/how-it-connects.mdx` sentence pair. Blog: `2026-08-31-we-measured-the-runtime-swap.mdx` matrix cell + the "Two of the three cards stream live. Mastra's fills in at completion…" passage + conclusion; `2026-08-31-what-changes-when-the-runtime-changes.mdx` if it names the Partial. No contractions; one sentence per line. `npx nx test website` green. Commit `docs(website,blog): mastra subagents stream — cell flips to Yes`. + +### Task 6: PR + follow-ups + +- [ ] Push; open PR `feat(runtimes): mastra sub-agent streaming via a public-API stream tee` (body: research verdict summary, evidence links, tallies, the suspended caveat; end with `🤖 Generated with [Claude Code](https://claude.com/claude-code)`). Do NOT arm auto-merge (the coordinator reviews first). +- [ ] Follow-up chip (coordinator): upstream `tool-output` mapping patch against `ag-ui-protocol/ag-ui` `integrations/mastra/typescript/src/mastra.ts`, referencing #2402/#2403. diff --git a/docs/superpowers/specs/2026-09-02-mastra-subagent-streaming-design.md b/docs/superpowers/specs/2026-09-02-mastra-subagent-streaming-design.md new file mode 100644 index 000000000..3d7e9f273 --- /dev/null +++ b/docs/superpowers/specs/2026-09-02-mastra-subagent-streaming-design.md @@ -0,0 +1,86 @@ +# Mastra sub-agent streaming: forward child deltas via a public-API stream tee + +**Date:** 2026-09-02 +**Status:** Approved (Brian, after deep research validated the layer and revised the seam) + +## Problem + +The Mastra runtime's subagent cell is Partial: Mastra streams the sub-agent's chunks +in-process as parent `tool-output` chunks (`{type:'tool-output', payload:{output: +, toolCallId, toolName}}` — a public, typed shape), but `@ag-ui/mastra` +1.1.2 drops them (`case "tool-output": break`) and buffers the delegation's +`TOOL_CALL_START/ARGS/END` until the tool result. The card therefore mounts already +complete after a ~5 s silent gap. + +## Research verdicts (evidence in the session's research report) + +- Pin not stale: 1.1.2 is the latest `@ag-ui/mastra`; upstream `main` still drops + `tool-output`; the only related upstream work is open PR #2403 (opt-in eager + `TOOL_CALL_START` for server tools), which also documents that buffering is + load-bearing for suspend retraction. +- No alternative layer: `@mastra/server` has no AG-UI route; Mastra's documented server + integration builds the same bridge inside a runtime we cannot depend on. `server.mjs` + is the canonical pattern and adds things upstream lacks. +- Mastra's official `onChunk` hook excludes `tool-output` in its compiled allow-list. +- A bridge subclass works today but couples to three TS-private methods, a `clone()` + that constructs the base class (drops overrides), and signature drift on `main`. + +## Design + +1. **Stream tee on a proxied agent** — `deployments/ag-ui-mastra/streaming-tee.mjs` + exports `withDelegationTee(agent, observe)`: a `Proxy` over the real Mastra `Agent` + that forwards every member bound to the real instance (so `#private` fields and the + bridge's `'getMemory' in agent` check keep working) except `stream()` and + `resumeStream()`, whose results are returned with `fullStream` replaced by an async + generator that calls `observe(chunk)` **before** yielding each chunk to the bridge. + One reader, one iteration → the observer's SSE writes are strictly ordered ahead of + the bridge's processing of the same chunk. The unmodified `MastraAgent` receives the + proxy. +2. **Injector grows a chunk input** — `subagent-emitter.mjs`'s per-run injector gains + `chunk(c)` returning AG-UI events to write, alongside the existing `eventsFor(event)`: + - `tool-call` whose `toolName` starts with `agent-` → synthesize eager + `TOOL_CALL_START/ARGS/END` (args are complete in the chunk; `parentMessageId` = the + last `start`/`step-start` chunk's message id) + `SUBAGENT_STARTED {subagentRunId: + -sub, name, parentToolCallId}`. Record the id so the bridge's later + buffered `TOOL_CALL_START/ARGS/END` for the same id are dropped in `eventsFor` + (its `TOOL_CALL_RESULT` still passes through). + - `tool-output` for a tracked id: inner `text-start` → attributed `TEXT_MESSAGE_START` + (lazy: open on first delta if no explicit start), `text-delta` → + `TEXT_MESSAGE_CONTENT`, `text-end` → `TEXT_MESSAGE_END`. Inner tool chunks are + out of scope for this PR (ignored). + - `tool-result` for a tracked id → close any open message, `SUBAGENT_FINISHED` + (success) or `SUBAGENT_ERROR` per the existing result check; mark deltas-seen. + - `tool-call-suspended` for a tracked id → close any open message, + `SUBAGENT_FINISHED {outcome:{type:'suspended'}}` (the eager START has already been + painted — accepted, documented caveat; the demo's delegation does not suspend). + - The existing `TOOL_CALL_RESULT` synthesis of a single-chunk message stays ONLY as + the fallback when no deltas were observed for that id. + - Terminal cleanup (RUN_FINISHED/RUN_ERROR) unchanged, extended to close open + messages. +3. **server.mjs wiring** — build the proxy per request with an observer that runs + `injector.chunk(c)` and writes each returned event as an SSE frame through the same + `res.write` path; the bridge's events keep flowing through `injector.eventsFor`. +4. **Spike first** (the two unverified items): (a) a unit test that a Proxy-wrapped + real `Agent` still satisfies the bridge (`'getMemory' in proxy`, `listTools`, + `stream()` returning a wrapped `fullStream`); (b) confirmation from + `libs/chat` that a subagent card needs the parent tool call present (it does — + `chat-tool-calls` anchors cards to tool-call entries), which is why synthesis is + required rather than optional; (c) a raw `fullStream` capture of one delegation + (chunk types + order, presence of `text-start/end`, whether `tool-call-suspended` + ever appears here). + +## Verification gates + +Wire capture showing eager `TOOL_CALL_START` + `SUBAGENT_STARTED` before the child +deltas and N attributed `TEXT_MESSAGE_CONTENT` events; browser check with the card's +text growing while `running` (char-growth samples + screenshot); e2e 5/5 in replay +(assertions unchanged); lane unit tests for the tee, the chunk mapping, dedupe, the +no-delta fallback, error, suspended, and terminal cleanup. Then the docs cell flips: +`choosing-an-adapter` matrix + section, runtimes intro + Mastra overview/how-it-connects, +both runtime blog posts ("one Partial cell" sentences), and the wire-capture doc. + +## Out of scope + +Inner sub-agent tool calls as attributed `TOOL_CALL_*`; the upstream `tool-output` +mapping patch (filed as a follow-up referencing #2403 for the eager-START half); the +bridge-subclass alternative (documented in the wire-capture doc as the fallback design). From 99f2dd980c622621a3f53ee57aa8b917499fba0f Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 2 Sep 2026 11:43:23 -0700 Subject: [PATCH 2/8] =?UTF-8?q?docs(runtimes):=20mastra=20streaming=20spik?= =?UTF-8?q?e=20=E2=80=94=20raw=20fullStream=20order=20and=20card-mount=20f?= =?UTF-8?q?inding?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 --- .../angular/docs/wire-capture-subagents.md | 72 +++++++++++++++++++ .../ag-ui-mastra/test/streaming-tee.test.mjs | 45 ++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 deployments/ag-ui-mastra/test/streaming-tee.test.mjs diff --git a/cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md b/cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md index da27af630..bd8425704 100644 --- a/cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md +++ b/cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md @@ -244,3 +244,75 @@ the completed, expanded card: `e2e/manual/subagent-card-live.png`. `data-state="done"` on first sight). The emitter is not the limiter; @ag-ui/mastra's buffered tool-call flush is (same upstream drop/buffer behavior documented above). + +## Streaming spike + +Task 0 of the streaming PR (spec: +`docs/superpowers/specs/2026-09-02-mastra-subagent-streaming-design.md`). +Captured 2026-09-02 by calling the supervisor's `stream()` directly with the +delegation prompt and logging every `fullStream` chunk. Pins unchanged +(`@mastra/core@1.63.2`, `@ag-ui/mastra@1.1.2`). + +### Bridge members touched (from `node_modules/@ag-ui/mastra/dist/mastra-*.mjs`) + +- `'getMemory' in agent` (`isLocalMastraAgent`) — decides the local dispatch path. +- `agent.stream(messages, options)` → reads `.fullStream` (consumed by + `processFullStream`), then `.traceId` and `.usage` for RUN_FINISHED. +- `agent.resumeStream(resume, options)` → the same `.fullStream` read. +- `agent.getMemory({requestContext})`, `agent.listTools(...)`, `agent.model`. +- `parentMessageId` on `TOOL_CALL_START` is the bridge's current message id, + set by `onMessageId` from the last `start` / `step-start` chunk's + `payload.messageId` (and re-randomized after `step-finish` / `finish`). +- The delegation `tool-call` chunk is buffered (`u = {toolCallId, toolName, + args}`) and flushed as START+ARGS+END only by the next flushing chunk — + for a delegation that is the `tool-result`, because every `tool-output` + in between hits `case "tool-output": break`. + +### Raw fullStream order (one delegation, 248 chunks) + +``` + 1 start messageId=b45dfabd-… ← parentMessageId source + 2 step-start messageId=b45dfabd-… + 3-51 tool-call-input-streaming-start / tool-call-delta x48 / -end (agent-weather_forecaster) +52 tool-call toolCallId=call_s7dO… toolName=agent-weather_forecaster + args={prompt, threadId:null, resourceId:null, instructions:null, maxSteps:5, …} ← complete +53 tool-output/start output.payload={id:'weather_forecaster', messageId:467ded64-…} +54 tool-output/step-start +55-74 tool-output/tool-call-input-streaming-* + tool-call + tool-result (inner updateWorkingMemory) +75 tool-output/step-finish +76 tool-output/step-start +77 tool-output/text-start output.payload.id=msg_0dad… +78-185 tool-output/text-delta x108 output.payload.text="Here's", " the", " weather", … +186 tool-output/text-end +187 tool-output/step-finish +188 tool-output/finish +189 tool-result toolCallId=call_s7dO… result keys={text, subAgentThreadId, subAgentResourceId, subAgentToolResults} +190 step-finish, 191 step-start, 192-207 parent updateWorkingMemory tool call, +208 step-finish, 209 step-start, 210 text-start, 211-245 text-delta x35, 246 text-end, +247 step-finish, 248 finish +``` + +Findings: + +- Chunk order is `tool-call` (args complete) → `tool-output` x135 (the whole + child stream, incrementally) → `tool-result`, exactly as the earlier tap. +- The child emits an explicit `text-start` before its deltas and `text-end` + after them; the lazy-START path in the injector is defensive only. +- `parentMessageId` for the eager `TOOL_CALL_START` is the `messageId` of the + last top-level `start` / `step-start` chunk (`b45dfabd-…` here), which is + the same id the bridge would stamp when it flushes at `tool-result`. +- `tool-call-suspended` never appears in this capture (the delegation tool + does not suspend; the demo child has no suspending tools). The injector + still maps it defensively to `SUBAGENT_FINISHED {outcome:{type:'suspended'}}`. +- Inner sub-agent tool chunks (`updateWorkingMemory` — 16 `tool-call-delta` + plus `tool-call` / `tool-result`) are present under `tool-output` and are + ignored by this PR (out of scope). + +### Card-mount check (`libs/chat/src/lib/primitives/chat-tool-calls/chat-tool-calls.component.ts`) + +`groups()` iterates the parent message's `toolCalls()` list and mounts +`chat-subagent-card` only when `subs.has(tc.id)` for an existing tool-call +entry (`Subagent.toolCallId` is the anchor). A `SUBAGENT_STARTED` with no +prior `TOOL_CALL_START` for its `parentToolCallId` therefore renders NO card: +synthesizing the eager `TOOL_CALL_START/ARGS/END` on the `tool-call` chunk +is required, not optional, for the card to appear before the child finishes. diff --git a/deployments/ag-ui-mastra/test/streaming-tee.test.mjs b/deployments/ag-ui-mastra/test/streaming-tee.test.mjs new file mode 100644 index 000000000..ebddaea20 --- /dev/null +++ b/deployments/ag-ui-mastra/test/streaming-tee.test.mjs @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +// Unit tests for the delegation stream tee — a Proxy over a Mastra Agent +// that lets an observer see every `fullStream` chunk BEFORE the @ag-ui/mastra +// bridge consumes it, while every other member forwards to the real agent. +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { Agent } from '@mastra/core/agent'; +import { withDelegationTee } from '../streaming-tee.mjs'; + +/** A real Agent (no model call is ever made) so `#private` fields exist. */ +function realAgent() { + return new Agent({ + id: 'tee-probe', + name: 'tee-probe', + instructions: 'probe', + model: 'openai/gpt-4o-mini', + }); +} + +// ── Task 0 feasibility: the bridge's agent contract survives the Proxy ──── +test('proxy over a real Agent still satisfies the bridge contract', async () => { + const agent = realAgent(); + // Stub stream() on the instance: the bridge awaits it and reads fullStream. + agent.stream = async () => ({ + fullStream: (async function* () { + yield { type: 'start', payload: { messageId: 'm1' } }; + })(), + text: Promise.resolve('x'), + }); + + const proxy = withDelegationTee(agent, () => {}); + + assert.ok('getMemory' in proxy, "bridge's isLocalMastraAgent check: 'getMemory' in agent"); + assert.equal(typeof proxy.listTools, 'function'); + assert.equal(typeof proxy.getMemory, 'function'); + assert.equal(typeof proxy.resumeStream, 'function'); + assert.equal(proxy.model, agent.model, 'model property forwards'); + + const result = await proxy.stream([], {}); + assert.ok(result && typeof result === 'object'); + assert.equal(typeof result.fullStream[Symbol.asyncIterator], 'function', 'fullStream is async-iterable'); + const seen = []; + for await (const c of result.fullStream) seen.push(c.type); + assert.deepEqual(seen, ['start']); +}); From 41c9cf4dc26b40603f6e8b55603f86baa5c63991 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 2 Sep 2026 11:44:22 -0700 Subject: [PATCH 3/8] =?UTF-8?q?feat(runtimes):=20mastra=20stream=20tee=20?= =?UTF-8?q?=E2=80=94=20observe=20fullStream=20chunks=20before=20the=20brid?= =?UTF-8?q?ge=20consumes=20them?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 --- deployments/ag-ui-mastra/streaming-tee.mjs | 76 ++++++++++++ .../ag-ui-mastra/test/streaming-tee.test.mjs | 114 ++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 deployments/ag-ui-mastra/streaming-tee.mjs diff --git a/deployments/ag-ui-mastra/streaming-tee.mjs b/deployments/ag-ui-mastra/streaming-tee.mjs new file mode 100644 index 000000000..abf35799d --- /dev/null +++ b/deployments/ag-ui-mastra/streaming-tee.mjs @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT +// Delegation stream tee: observe a Mastra Agent's `fullStream` chunks before +// the @ag-ui/mastra bridge consumes them. +// +// Why a Proxy and not a bridge subclass: the bridge (1.1.2) reads the agent +// only through public members — `'getMemory' in agent`, `stream()`, +// `resumeStream()`, `getMemory()`, `listTools()`, `model` — and consumes +// `stream()`'s `.fullStream` in a private chunk processor that DROPS every +// `tool-output` chunk (the in-process sub-agent deltas). Wrapping the agent +// keeps the bridge unmodified and version-independent; wrapping only the +// `fullStream` iterator keeps `.traceId` / `.usage` / everything else on the +// stream result intact. +// +// Ordering guarantee: the bridge is the single reader of the wrapped +// generator, so `observe(chunk)` runs strictly before the bridge processes +// that same chunk. Anything the observer writes to the SSE socket therefore +// lands ahead of the bridge's own events for the chunk. + +/** + * Wrap an async iterable so `observe` sees each item before it is yielded. + * Observer failures are logged and never break the consumer. + */ +async function* tee(source, observe) { + for await (const chunk of source) { + try { + observe(chunk); + } catch (err) { + console.warn('[streaming-tee] observer threw; chunk still forwarded:', err); + } + yield chunk; + } +} + +const WRAPPED_METHODS = new Set(['stream', 'resumeStream']); + +/** + * @template {object} T + * @param {T} agent the real Mastra Agent (or any object with `stream()`). + * @param {(chunk: object) => void} observe called with every `fullStream` + * chunk of every `stream()` / `resumeStream()` result, before the bridge + * receives it. + * @returns {T} a Proxy that forwards every member to `agent` with `this` + * bound to the real instance (so `#private` fields keep working), except + * that `stream` / `resumeStream` return their result with `fullStream` + * replaced by the teed generator. + */ +export function withDelegationTee(agent, observe) { + return new Proxy(agent, { + get(target, prop, receiver) { + const value = Reflect.get(target, prop, target); + if (typeof value !== 'function') return value; + if (!WRAPPED_METHODS.has(prop)) { + // Bind to the REAL target, not the receiver: class methods that touch + // `#private` state throw when `this` is the Proxy. + return value.bind(target); + } + return async (...args) => { + const result = await value.apply(target, args); + if (!result || typeof result !== 'object' || !result.fullStream) return result; + const wrapped = tee(result.fullStream, observe); + // Keep the original result object (its getters for traceId/usage/ + // text/etc. must still resolve); only shadow `fullStream`. + return new Proxy(result, { + get(res, key) { + if (key === 'fullStream') return wrapped; + const v = Reflect.get(res, key, res); + return typeof v === 'function' ? v.bind(res) : v; + }, + }); + }; + }, + has(target, prop) { + return prop in target; + }, + }); +} diff --git a/deployments/ag-ui-mastra/test/streaming-tee.test.mjs b/deployments/ag-ui-mastra/test/streaming-tee.test.mjs index ebddaea20..981c50bb9 100644 --- a/deployments/ag-ui-mastra/test/streaming-tee.test.mjs +++ b/deployments/ag-ui-mastra/test/streaming-tee.test.mjs @@ -17,6 +17,32 @@ function realAgent() { }); } +/** Fake agent whose stream() yields two chunks and carries a sibling prop. */ +function fakeAgent(trace = []) { + return { + getMemory() {}, + listTools() {}, + async stream() { + return { + fullStream: (async function* () { + yield { type: 'a' }; + yield { type: 'b' }; + })(), + text: 'x', + }; + }, + async resumeStream() { + return { + fullStream: (async function* () { + yield { type: 'r1' }; + })(), + usage: 'u', + }; + }, + _trace: trace, + }; +} + // ── Task 0 feasibility: the bridge's agent contract survives the Proxy ──── test('proxy over a real Agent still satisfies the bridge contract', async () => { const agent = realAgent(); @@ -43,3 +69,91 @@ test('proxy over a real Agent still satisfies the bridge contract', async () => for await (const c of result.fullStream) seen.push(c.type); assert.deepEqual(seen, ['start']); }); + +// ── Task 1: ordering, passthrough, resumeStream, `this`, observer errors ── +test('observer sees each chunk BEFORE the consumer receives it', async () => { + const trace = []; + const proxy = withDelegationTee(fakeAgent(), (c) => trace.push(`obs:${c.type}`)); + const result = await proxy.stream([], {}); + for await (const c of result.fullStream) trace.push(`out:${c.type}`); + assert.deepEqual(trace, ['obs:a', 'out:a', 'obs:b', 'out:b']); +}); + +test('non-fullStream properties of the stream result are preserved', async () => { + const proxy = withDelegationTee(fakeAgent(), () => {}); + const result = await proxy.stream([], {}); + assert.equal(result.text, 'x'); +}); + +test('resumeStream is wrapped the same way', async () => { + const trace = []; + const proxy = withDelegationTee(fakeAgent(), (c) => trace.push(`obs:${c.type}`)); + const result = await proxy.resumeStream({}, {}); + assert.equal(result.usage, 'u'); + for await (const c of result.fullStream) trace.push(`out:${c.type}`); + assert.deepEqual(trace, ['obs:r1', 'out:r1']); +}); + +test('stream/resumeStream receive the original arguments', async () => { + const calls = []; + const agent = { + getMemory() {}, + async stream(...args) { + calls.push(['stream', ...args]); + return { fullStream: (async function* () {})() }; + }, + async resumeStream(...args) { + calls.push(['resume', ...args]); + return { fullStream: (async function* () {})() }; + }, + }; + const proxy = withDelegationTee(agent, () => {}); + await proxy.stream('msgs', { runId: 'r' }); + await proxy.resumeStream({ approved: true }, { runId: 'r2' }); + assert.deepEqual(calls, [ + ['stream', 'msgs', { runId: 'r' }], + ['resume', { approved: true }, { runId: 'r2' }], + ]); +}); + +test('other members forward with `this` bound to the real agent (#private fields work)', () => { + class Probe extends Agent { + #secret = 'hidden'; + readSecret() { + return this.#secret; + } + } + const agent = new Probe({ id: 'p', name: 'p', instructions: 'p', model: 'openai/gpt-4o-mini' }); + const proxy = withDelegationTee(agent, () => {}); + // Calling through the proxy must not throw "Cannot read private member". + assert.equal(proxy.readSecret(), 'hidden'); + assert.equal(proxy.id, 'p'); + assert.equal(typeof proxy.getMemory, 'function'); +}); + +test('a throwing observer does not break the consumer', async () => { + const warnings = []; + const originalWarn = console.warn; + console.warn = (...args) => warnings.push(args); + try { + const proxy = withDelegationTee(fakeAgent(), (c) => { + if (c.type === 'a') throw new Error('observer boom'); + }); + const result = await proxy.stream([], {}); + const seen = []; + for await (const c of result.fullStream) seen.push(c.type); + assert.deepEqual(seen, ['a', 'b']); + assert.equal(warnings.length, 1); + assert.match(String(warnings[0][0]), /observer/); + } finally { + console.warn = originalWarn; + } +}); + +test('a stream result without fullStream is returned untouched', async () => { + const agent = { getMemory() {}, async stream() { return { processDataStream() {} }; } }; + const proxy = withDelegationTee(agent, () => {}); + const result = await proxy.stream([], {}); + assert.equal(typeof result.processDataStream, 'function'); + assert.equal(result.fullStream, undefined); +}); From bfe31e8b62c3cb3819da100515d6bafe7d37d9b1 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 2 Sep 2026 11:46:46 -0700 Subject: [PATCH 4/8] feat(runtimes): mastra injector maps delegation chunks to eager TOOL_CALL_* and attributed child deltas Co-Authored-By: Claude Fable 5.1 --- deployments/ag-ui-mastra/subagent-emitter.mjs | 312 +++++++++++++----- .../test/subagent-emitter.test.mjs | 302 +++++++++++++++++ 2 files changed, 539 insertions(+), 75 deletions(-) diff --git a/deployments/ag-ui-mastra/subagent-emitter.mjs b/deployments/ag-ui-mastra/subagent-emitter.mjs index 24ab9fd9c..17c13993a 100644 --- a/deployments/ag-ui-mastra/subagent-emitter.mjs +++ b/deployments/ag-ui-mastra/subagent-emitter.mjs @@ -2,58 +2,252 @@ // SUBAGENT_* injection for Mastra delegation tool calls. // // Mastra surfaces a registered sub-agent as an ordinary backend tool named -// `agent-`: TOOL_CALL_START → TOOL_CALL_ARGS → TOOL_CALL_END → -// TOOL_CALL_RESULT whose `content` is JSON `{text, subAgentThreadId, ...}` -// (measured: cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md). -// The upstream @ag-ui/mastra bridge drops the in-process child deltas -// (`case "tool-output": break`), so the honest wire contract here is a -// single final text chunk per delegation. +// `agent-`. On the wire the upstream @ag-ui/mastra bridge buffers +// that tool call and flushes TOOL_CALL_START → ARGS → END only when the +// TOOL_CALL_RESULT arrives (content = JSON `{text, subAgentThreadId, ...}`), +// and it DROPS the in-process child deltas (`case "tool-output": break`) — +// measured in cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md. // -// This module is a pure transform over the outbound AG-UI event stream — -// keyed off the events themselves, NOT the Mastra delegation hooks, which -// fire in a different async context with no ordering guarantee relative to -// the Observable frames. +// This module is a pure per-run transform with TWO inputs: // -// Injected sequence per delegation tool call (child key = tool name -// minus the `agent-` prefix, subagentRunId = `-sub`): -// - AFTER TOOL_CALL_START: SUBAGENT_STARTED {subagentRunId, name, -// parentToolCallId} -// - BEFORE TOOL_CALL_RESULT (success): TEXT_MESSAGE_START/CONTENT/END -// carrying the child's final text under the subagent identity, then -// SUBAGENT_FINISHED {outcome:{type:'success'}} -// - BEFORE TOOL_CALL_RESULT (failure — parsed content says success:false -// or finishReason:'error'): SUBAGENT_ERROR {subagentRunId, message} -// - Terminal cleanup: a RUN_ERROR or RUN_FINISHED arriving while -// delegations are still pending (no TOOL_CALL_RESULT seen — e.g. the -// Observable errored mid-delegation) closes each pending card with -// SUBAGENT_ERROR before the terminal frame, so no card is left spinning. -// In the measured captures the RESULT always precedes the terminal frame, -// so this path is defensive only. +// - `chunk(c)`: raw Mastra `fullStream` chunks, observed through the stream +// tee (streaming-tee.mjs) BEFORE the bridge processes each one. This is +// where the child text actually streams, so it is the primary emitter: +// - `tool-call` named `agent-*` → synthesized EAGER TOOL_CALL_START/ARGS/END +// (args are complete in the chunk; parentMessageId = the last +// `start`/`step-start` chunk's messageId, the same id the bridge would +// stamp) + SUBAGENT_STARTED {subagentRunId: `-sub`, name, +// parentToolCallId}. The card needs the parent tool call present to mount, +// so synthesis is required rather than optional. +// - `tool-output` for a tracked id: inner `text-start` → attributed +// TEXT_MESSAGE_START (opened lazily on the first delta if absent), +// `text-delta` → TEXT_MESSAGE_CONTENT, `text-end` → TEXT_MESSAGE_END. +// Inner tool chunks are ignored (out of scope). +// - `tool-result` / `tool-error` → close any open message, then +// SUBAGENT_FINISHED {success} or SUBAGENT_ERROR (result says +// success:false / finishReason:'error', or the tool errored). When NO +// delta was observed the old single-chunk TEXT_MESSAGE_* synthesis from +// `result.text` fires as the fallback. +// - `tool-call-suspended` → close any open message, SUBAGENT_FINISHED +// {outcome:{type:'suspended'}}. The eager START has already been painted +// (the bridge would have retracted it) — accepted caveat; the demo's +// delegation never suspends. +// +// - `eventsFor(event)`: the bridge's outbound AG-UI events. For an id that +// was synthesized above, the bridge's later buffered TOOL_CALL_START/ARGS/ +// END copies are DROPPED (its TOOL_CALL_RESULT passes through untouched). +// For an id the chunk path never saw (tee not wired), the original +// event-keyed behavior stays: SUBAGENT_STARTED after TOOL_CALL_START and the +// single-chunk text + SUBAGENT_FINISHED/ERROR before TOOL_CALL_RESULT. +// Terminal cleanup: RUN_ERROR / RUN_FINISHED with delegations still pending +// closes open child messages and emits SUBAGENT_ERROR per pending id, +// exactly once, before the terminal frame. const AGENT_TOOL_PREFIX = 'agent-'; +/** + * @typedef {object} Entry + * @property {string} subagentRunId + * @property {string} name + * @property {boolean} synthesized TOOL_CALL_* were emitted from the chunk path + * @property {boolean} deltasSeen at least one child text delta was forwarded + * @property {boolean} messageOpen + * @property {string|undefined} messageId + * @property {number} messageCount + */ + +/** Result-shape failure check shared by both inputs. */ +function parseResult(raw) { + if (raw !== null && typeof raw === 'object') return raw; + if (typeof raw !== 'string') return undefined; + try { + return JSON.parse(raw); + } catch { + return undefined; + } +} + +function isFailure(parsed) { + return ( + parsed !== undefined && + typeof parsed === 'object' && + parsed !== null && + (parsed.success === false || parsed.finishReason === 'error') + ); +} + +function failureMessage(parsed) { + return String(parsed.error ?? parsed.text ?? 'sub-agent delegation failed'); +} + /** * Create a per-run injector. * - * @returns {{ eventsFor(event: object): object[] }} — for each outbound - * AG-UI event, the ordered list of frames to write (injections plus the - * original event). Non-delegation events pass through as `[event]`. + * @returns {{ chunk(chunk: object): object[], eventsFor(event: object): object[] }} + * `chunk` returns the AG-UI events to write for a raw Mastra chunk (usually + * none); `eventsFor` returns, for each outbound bridge event, the ordered + * list of frames to write (injections plus, unless deduped, the event). */ export function createSubagentInjector() { - /** @type {Map} pending delegations by toolCallId */ + /** @type {Map} pending delegations by toolCallId */ const pending = new Map(); + /** Ids whose TOOL_CALL_START/ARGS/END were synthesized — bridge copies drop. */ + const synthesized = new Set(); + /** The bridge's current parent message id (last start/step-start chunk). */ + let parentMessageId; + + function newEntry(toolCallId, toolName, isSynthesized) { + const entry = { + subagentRunId: `${toolCallId}-sub`, + name: toolName.slice(AGENT_TOOL_PREFIX.length), + synthesized: isSynthesized, + deltasSeen: false, + messageOpen: false, + messageId: undefined, + messageCount: 0, + }; + pending.set(toolCallId, entry); + return entry; + } + + function openMessage(toolCallId, entry) { + entry.messageCount += 1; + entry.messageId = `${toolCallId}-sub-m${entry.messageCount}`; + entry.messageOpen = true; + return { + type: 'TEXT_MESSAGE_START', + messageId: entry.messageId, + role: 'assistant', + subagentRunId: entry.subagentRunId, + }; + } + + function closeMessage(entry) { + if (!entry.messageOpen) return []; + entry.messageOpen = false; + return [{ type: 'TEXT_MESSAGE_END', messageId: entry.messageId, subagentRunId: entry.subagentRunId }]; + } + + /** Close + FINISHED/ERROR for a result; falls back to single-chunk text when no deltas streamed. */ + function finalize(toolCallId, entry, rawResult) { + pending.delete(toolCallId); + const { subagentRunId } = entry; + const parsed = parseResult(rawResult); + if (isFailure(parsed)) { + return [...closeMessage(entry), { type: 'SUBAGENT_ERROR', subagentRunId, message: failureMessage(parsed) }]; + } + const out = closeMessage(entry); + if (!entry.deltasSeen) { + const raw = typeof rawResult === 'string' ? rawResult : JSON.stringify(rawResult); + const text = typeof parsed?.text === 'string' ? parsed.text : raw; + out.push(openMessage(toolCallId, entry)); + out.push({ type: 'TEXT_MESSAGE_CONTENT', messageId: entry.messageId, delta: text, subagentRunId }); + out.push(...closeMessage(entry)); + } + out.push({ type: 'SUBAGENT_FINISHED', subagentRunId, outcome: { type: 'success' } }); + return out; + } + + function fail(toolCallId, entry, message) { + pending.delete(toolCallId); + return [...closeMessage(entry), { type: 'SUBAGENT_ERROR', subagentRunId: entry.subagentRunId, message }]; + } return { + chunk(chunk) { + const payload = chunk?.payload ?? {}; + switch (chunk?.type) { + case 'start': + case 'step-start': { + if (payload.messageId) parentMessageId = payload.messageId; + return []; + } + + case 'tool-call': { + const { toolCallId, toolName = '' } = payload; + if (!toolCallId || !toolName.startsWith(AGENT_TOOL_PREFIX)) return []; + const entry = newEntry(toolCallId, toolName, true); + synthesized.add(toolCallId); + return [ + { + type: 'TOOL_CALL_START', + ...(parentMessageId !== undefined ? { parentMessageId } : {}), + toolCallId, + toolCallName: toolName, + }, + { type: 'TOOL_CALL_ARGS', toolCallId, delta: JSON.stringify(payload.args ?? {}) }, + { type: 'TOOL_CALL_END', toolCallId }, + { + type: 'SUBAGENT_STARTED', + subagentRunId: entry.subagentRunId, + name: entry.name, + parentToolCallId: toolCallId, + }, + ]; + } + + case 'tool-output': { + const entry = pending.get(payload.toolCallId); + const inner = payload.output; + if (!entry || !inner) return []; + switch (inner.type) { + case 'text-start': + return [...closeMessage(entry), openMessage(payload.toolCallId, entry)]; + case 'text-delta': { + const text = inner.payload?.text; + if (typeof text !== 'string' || text.length === 0) return []; + const out = entry.messageOpen ? [] : [openMessage(payload.toolCallId, entry)]; + entry.deltasSeen = true; + out.push({ + type: 'TEXT_MESSAGE_CONTENT', + messageId: entry.messageId, + delta: text, + subagentRunId: entry.subagentRunId, + }); + return out; + } + case 'text-end': + return closeMessage(entry); + default: + return []; // inner tool chunks etc. — out of scope + } + } + + case 'tool-result': { + const entry = pending.get(payload.toolCallId); + if (!entry) return []; + return finalize(payload.toolCallId, entry, payload.result); + } + + case 'tool-error': { + const entry = pending.get(payload.toolCallId); + if (!entry) return []; + const err = payload.error; + return fail(payload.toolCallId, entry, String(err?.message ?? err ?? 'sub-agent delegation failed')); + } + + case 'tool-call-suspended': { + const entry = pending.get(payload.toolCallId); + if (!entry) return []; + pending.delete(payload.toolCallId); + return [ + ...closeMessage(entry), + { type: 'SUBAGENT_FINISHED', subagentRunId: entry.subagentRunId, outcome: { type: 'suspended' } }, + ]; + } + + default: + return []; + } + }, + eventsFor(event) { switch (event.type) { case 'TOOL_CALL_START': { + if (synthesized.has(event.toolCallId)) return []; // eager copy already on the wire const name = event.toolCallName ?? ''; if (!name.startsWith(AGENT_TOOL_PREFIX)) return [event]; - const entry = { - subagentRunId: `${event.toolCallId}-sub`, - name: name.slice(AGENT_TOOL_PREFIX.length), - }; - pending.set(event.toolCallId, entry); + const entry = newEntry(event.toolCallId, name, false); return [ event, { @@ -65,54 +259,22 @@ export function createSubagentInjector() { ]; } + case 'TOOL_CALL_ARGS': + case 'TOOL_CALL_END': + return synthesized.has(event.toolCallId) ? [] : [event]; + case 'TOOL_CALL_RESULT': { const entry = pending.get(event.toolCallId); - if (!entry) return [event]; // not a delegation (or unmatched) — pass through - pending.delete(event.toolCallId); - const { subagentRunId } = entry; - - const raw = typeof event.content === 'string' ? event.content : JSON.stringify(event.content); - let parsed; - try { - parsed = JSON.parse(raw); - } catch { - parsed = undefined; - } - const failed = - parsed !== undefined && - typeof parsed === 'object' && - parsed !== null && - (parsed.success === false || parsed.finishReason === 'error'); - if (failed) { - return [ - { - type: 'SUBAGENT_ERROR', - subagentRunId, - message: String(parsed.error ?? parsed.text ?? 'sub-agent delegation failed'), - }, - event, - ]; - } - - const text = typeof parsed?.text === 'string' ? parsed.text : raw; - const messageId = `${event.toolCallId}-sub-m1`; - return [ - { type: 'TEXT_MESSAGE_START', messageId, role: 'assistant', subagentRunId }, - { type: 'TEXT_MESSAGE_CONTENT', messageId, delta: text, subagentRunId }, - { type: 'TEXT_MESSAGE_END', messageId, subagentRunId }, - { type: 'SUBAGENT_FINISHED', subagentRunId, outcome: { type: 'success' } }, - event, - ]; + if (!entry) return [event]; // not a delegation, already finalized by the chunk path, or unmatched + return [...finalize(event.toolCallId, entry, event.content), event]; } case 'RUN_ERROR': case 'RUN_FINISHED': { if (pending.size === 0) return [event]; - const cleanup = [...pending.values()].map(({ subagentRunId }) => ({ - type: 'SUBAGENT_ERROR', - subagentRunId, - message: 'delegation did not complete before the run terminated', - })); + const cleanup = [...pending.entries()].flatMap(([toolCallId, entry]) => + fail(toolCallId, entry, 'delegation did not complete before the run terminated'), + ); pending.clear(); return [...cleanup, event]; } diff --git a/deployments/ag-ui-mastra/test/subagent-emitter.test.mjs b/deployments/ag-ui-mastra/test/subagent-emitter.test.mjs index 5cedb98fd..71d7ba666 100644 --- a/deployments/ag-ui-mastra/test/subagent-emitter.test.mjs +++ b/deployments/ag-ui-mastra/test/subagent-emitter.test.mjs @@ -144,6 +144,308 @@ test('pending delegation at RUN_FINISHED → SUBAGENT_ERROR cleanup before the t ]); }); +// ── chunk() — the stream-tee input (shapes copied from the Task 0 capture) ── + +const PARENT_MID = 'b45dfabd-fec1-4072-92db-215f394625a4'; +const CHILD_TEXT_ID = 'msg_0dadf9a2c94517c2006a986e0c8ecc87d0b86efe35436a91a4'; +const ARGS = { + prompt: 'What is the weather forecast for Bear Lake this weekend?', + threadId: null, + resourceId: null, + instructions: null, + maxSteps: 5, + suspendedToolRunId: null, + resumeData: null, +}; + +const startChunk = { type: 'start', runId: 'r', payload: { messageId: PARENT_MID } }; +const stepStartChunk = { type: 'step-start', runId: 'r', payload: { messageId: PARENT_MID } }; +function toolCallChunk(tid = TID, toolName = 'agent-weather_forecaster', args = ARGS) { + return { type: 'tool-call', runId: 'r', payload: { toolCallId: tid, toolName, args } }; +} +function toolOutput(output, tid = TID) { + return { + type: 'tool-output', + runId: 'r', + payload: { output, toolCallId: tid, toolName: 'agent-weather_forecaster' }, + }; +} +const childTextStart = toolOutput({ type: 'text-start', payload: { id: CHILD_TEXT_ID } }); +const childDelta = (text) => toolOutput({ type: 'text-delta', payload: { id: CHILD_TEXT_ID, text } }); +const childTextEnd = toolOutput({ type: 'text-end', payload: { id: CHILD_TEXT_ID } }); +function toolResultChunk(result, tid = TID) { + return { + type: 'tool-result', + runId: 'r', + payload: { toolCallId: tid, toolName: 'agent-weather_forecaster', result }, + }; +} +const SUCCESS_RESULT = { + text: "Here's the weather", + subAgentThreadId: 't-1-abc', + subAgentResourceId: 't-1-weather_forecaster', + subAgentToolResults: [], +}; + +const SUB = `${TID}-sub`; +const M1 = `${TID}-sub-m1`; +const eagerToolCall = [ + { type: 'TOOL_CALL_START', parentMessageId: PARENT_MID, toolCallId: TID, toolCallName: 'agent-weather_forecaster' }, + { type: 'TOOL_CALL_ARGS', toolCallId: TID, delta: JSON.stringify(ARGS) }, + { type: 'TOOL_CALL_END', toolCallId: TID }, + { type: 'SUBAGENT_STARTED', subagentRunId: SUB, name: 'weather_forecaster', parentToolCallId: TID }, +]; + +test('chunk: agent-* tool-call → eager TOOL_CALL_START/ARGS/END + SUBAGENT_STARTED (parentMessageId from step-start)', () => { + const injector = createSubagentInjector(); + assert.deepEqual(injector.chunk(startChunk), []); + assert.deepEqual(injector.chunk(stepStartChunk), []); + assert.deepEqual(injector.chunk(toolCallChunk()), eagerToolCall); +}); + +test('chunk: parentMessageId tracks the LAST start/step-start chunk', () => { + const injector = createSubagentInjector(); + injector.chunk(startChunk); + injector.chunk({ type: 'step-start', payload: { messageId: 'later-mid' } }); + const [start] = injector.chunk(toolCallChunk()); + assert.equal(start.parentMessageId, 'later-mid'); +}); + +test('chunk: tool-output text-start/delta/end → attributed TEXT_MESSAGE_START/CONTENT/END', () => { + const injector = createSubagentInjector(); + injector.chunk(stepStartChunk); + injector.chunk(toolCallChunk()); + assert.deepEqual(injector.chunk(childTextStart), [ + { type: 'TEXT_MESSAGE_START', messageId: M1, role: 'assistant', subagentRunId: SUB }, + ]); + assert.deepEqual(injector.chunk(childDelta("Here's")), [ + { type: 'TEXT_MESSAGE_CONTENT', messageId: M1, delta: "Here's", subagentRunId: SUB }, + ]); + assert.deepEqual(injector.chunk(childDelta(' the')), [ + { type: 'TEXT_MESSAGE_CONTENT', messageId: M1, delta: ' the', subagentRunId: SUB }, + ]); + assert.deepEqual(injector.chunk(childTextEnd), [ + { type: 'TEXT_MESSAGE_END', messageId: M1, subagentRunId: SUB }, + ]); +}); + +test('chunk: lazy TEXT_MESSAGE_START when the child omits text-start; empty deltas skipped', () => { + const injector = createSubagentInjector(); + injector.chunk(stepStartChunk); + injector.chunk(toolCallChunk()); + assert.deepEqual(injector.chunk(childDelta('')), []); + assert.deepEqual(injector.chunk(childDelta('Hi')), [ + { type: 'TEXT_MESSAGE_START', messageId: M1, role: 'assistant', subagentRunId: SUB }, + { type: 'TEXT_MESSAGE_CONTENT', messageId: M1, delta: 'Hi', subagentRunId: SUB }, + ]); +}); + +test('chunk: inner non-text child chunks are ignored', () => { + const injector = createSubagentInjector(); + injector.chunk(stepStartChunk); + injector.chunk(toolCallChunk()); + for (const inner of [ + { type: 'start', payload: { id: 'weather_forecaster', messageId: 'c-mid' } }, + { type: 'step-start', payload: { messageId: 'c-mid' } }, + { type: 'tool-call-input-streaming-start', payload: { toolName: 'updateWorkingMemory' } }, + { type: 'tool-call', payload: { toolCallId: 'inner-1', toolName: 'updateWorkingMemory', args: {} } }, + { type: 'tool-result', payload: { toolCallId: 'inner-1', toolName: 'updateWorkingMemory', result: {} } }, + { type: 'step-finish', payload: { messageId: 'c-mid' } }, + { type: 'finish', payload: { messageId: 'c-mid' } }, + ]) { + assert.deepEqual(injector.chunk(toolOutput(inner)), [], inner.type); + } + // An inner step-start must NOT move the parent's parentMessageId. + const [start] = injector.chunk(toolCallChunk('call_second')); + assert.equal(start.parentMessageId, PARENT_MID); +}); + +test('chunk: tool-result after deltas → close message + SUBAGENT_FINISHED (no fallback text)', () => { + const injector = createSubagentInjector(); + injector.chunk(stepStartChunk); + injector.chunk(toolCallChunk()); + injector.chunk(childTextStart); + injector.chunk(childDelta('Hi')); + // No text-end arrived: the result must close the open message first. + assert.deepEqual(injector.chunk(toolResultChunk(SUCCESS_RESULT)), [ + { type: 'TEXT_MESSAGE_END', messageId: M1, subagentRunId: SUB }, + { type: 'SUBAGENT_FINISHED', subagentRunId: SUB, outcome: { type: 'success' } }, + ]); +}); + +test('chunk: tool-result with text-end already seen → SUBAGENT_FINISHED only', () => { + const injector = createSubagentInjector(); + injector.chunk(stepStartChunk); + injector.chunk(toolCallChunk()); + injector.chunk(childTextStart); + injector.chunk(childDelta('Hi')); + injector.chunk(childTextEnd); + assert.deepEqual(injector.chunk(toolResultChunk(SUCCESS_RESULT)), [ + { type: 'SUBAGENT_FINISHED', subagentRunId: SUB, outcome: { type: 'success' } }, + ]); +}); + +test('chunk: tool-result with NO deltas observed → single-chunk fallback from result.text', () => { + const injector = createSubagentInjector(); + injector.chunk(stepStartChunk); + injector.chunk(toolCallChunk()); + assert.deepEqual(injector.chunk(toolResultChunk(SUCCESS_RESULT)), [ + { type: 'TEXT_MESSAGE_START', messageId: M1, role: 'assistant', subagentRunId: SUB }, + { type: 'TEXT_MESSAGE_CONTENT', messageId: M1, delta: "Here's the weather", subagentRunId: SUB }, + { type: 'TEXT_MESSAGE_END', messageId: M1, subagentRunId: SUB }, + { type: 'SUBAGENT_FINISHED', subagentRunId: SUB, outcome: { type: 'success' } }, + ]); +}); + +test('chunk: failed tool-result → close message + SUBAGENT_ERROR', () => { + const injector = createSubagentInjector(); + injector.chunk(stepStartChunk); + injector.chunk(toolCallChunk()); + injector.chunk(childDelta('partial')); + assert.deepEqual(injector.chunk(toolResultChunk({ text: 'partial', finishReason: 'error' })), [ + { type: 'TEXT_MESSAGE_END', messageId: M1, subagentRunId: SUB }, + { type: 'SUBAGENT_ERROR', subagentRunId: SUB, message: 'partial' }, + ]); + const injector2 = createSubagentInjector(); + injector2.chunk(toolCallChunk()); + assert.deepEqual(injector2.chunk(toolResultChunk({ success: false, error: 'model refused' })), [ + { type: 'SUBAGENT_ERROR', subagentRunId: SUB, message: 'model refused' }, + ]); +}); + +test('chunk: tool-error for a tracked id → close message + SUBAGENT_ERROR', () => { + const injector = createSubagentInjector(); + injector.chunk(toolCallChunk()); + injector.chunk(childDelta('x')); + assert.deepEqual( + injector.chunk({ type: 'tool-error', payload: { toolCallId: TID, toolName: 'agent-weather_forecaster', error: new Error('boom') } }), + [ + { type: 'TEXT_MESSAGE_END', messageId: M1, subagentRunId: SUB }, + { type: 'SUBAGENT_ERROR', subagentRunId: SUB, message: 'boom' }, + ], + ); +}); + +test('chunk: tool-call-suspended for a tracked id → close message + SUBAGENT_FINISHED{suspended}', () => { + const injector = createSubagentInjector(); + injector.chunk(stepStartChunk); + injector.chunk(toolCallChunk()); + injector.chunk(childDelta('thinking')); + assert.deepEqual( + injector.chunk({ + type: 'tool-call-suspended', + payload: { toolCallId: TID, toolName: 'agent-weather_forecaster', suspendPayload: {}, runId: 'r' }, + }), + [ + { type: 'TEXT_MESSAGE_END', messageId: M1, subagentRunId: SUB }, + { type: 'SUBAGENT_FINISHED', subagentRunId: SUB, outcome: { type: 'suspended' } }, + ], + ); + // Suspended is terminal for the card: RUN_FINISHED must not error it. + const finished = { type: 'RUN_FINISHED', threadId: 't', runId: 'r', outcome: { type: 'interrupt' } }; + assert.deepEqual(injector.eventsFor(finished), [finished]); +}); + +test('chunk: non-agent tool-calls and untracked tool-output/tool-result are untouched', () => { + const injector = createSubagentInjector(); + injector.chunk(stepStartChunk); + assert.deepEqual(injector.chunk(toolCallChunk('c1', 'check_conditions', { location: 'x' })), []); + assert.deepEqual(injector.chunk(toolOutput({ type: 'text-delta', payload: { text: 'nope' } }, 'c1')), []); + assert.deepEqual(injector.chunk(toolResultChunk({ forecast: 'clear' }, 'c1')), []); + // Parent-level text chunks are the bridge's job. + assert.deepEqual(injector.chunk({ type: 'text-delta', payload: { text: 'parent' } }), []); + assert.deepEqual(injector.chunk({ type: 'finish', payload: {} }), []); +}); + +test('eventsFor: bridge copies of a synthesized TOOL_CALL_START/ARGS/END are dropped; RESULT passes through', () => { + const injector = createSubagentInjector(); + injector.chunk(stepStartChunk); + injector.chunk(toolCallChunk()); + injector.chunk(childTextStart); + injector.chunk(childDelta('Hi')); + injector.chunk(childTextEnd); + injector.chunk(toolResultChunk(SUCCESS_RESULT)); + // The bridge flushes its buffered copy AFTER the tool-result chunk. + assert.deepEqual(injector.eventsFor(delegationStart()), []); + assert.deepEqual(injector.eventsFor({ type: 'TOOL_CALL_ARGS', toolCallId: TID, delta: '{}' }), []); + assert.deepEqual(injector.eventsFor({ type: 'TOOL_CALL_END', toolCallId: TID }), []); + const result = delegationResult(JSON.stringify(SUCCESS_RESULT)); + assert.deepEqual(injector.eventsFor(result), [result], 'no second SUBAGENT_* / TEXT_MESSAGE_* synthesis'); + const finished = { type: 'RUN_FINISHED', threadId: 't', runId: 'r' }; + assert.deepEqual(injector.eventsFor(finished), [finished]); +}); + +test('end-to-end interleave: exact wire order for one streamed delegation', () => { + const injector = createSubagentInjector(); + const out = []; + const chunkThenBridge = (chunk, bridgeEvents = []) => { + out.push(...injector.chunk(chunk)); + for (const e of bridgeEvents) out.push(...injector.eventsFor(e)); + }; + const runStarted = { type: 'RUN_STARTED', threadId: 't', runId: 'r' }; + out.push(...injector.eventsFor(runStarted)); + chunkThenBridge(startChunk); + chunkThenBridge(stepStartChunk); + chunkThenBridge(toolCallChunk()); // bridge buffers; emits nothing + chunkThenBridge(childTextStart); + chunkThenBridge(childDelta('A')); + chunkThenBridge(childDelta('B')); + chunkThenBridge(childTextEnd); + const result = delegationResult(JSON.stringify(SUCCESS_RESULT)); + chunkThenBridge(toolResultChunk(SUCCESS_RESULT), [ + delegationStart(), + { type: 'TOOL_CALL_ARGS', toolCallId: TID, delta: JSON.stringify(ARGS) }, + { type: 'TOOL_CALL_END', toolCallId: TID }, + result, + ]); + const parentText = { type: 'TEXT_MESSAGE_CHUNK', messageId: 'x', delta: 'ok' }; + chunkThenBridge({ type: 'text-delta', payload: { text: 'ok' } }, [parentText]); + const finished = { type: 'RUN_FINISHED', threadId: 't', runId: 'r' }; + chunkThenBridge({ type: 'finish', payload: {} }, [finished]); + + assert.deepEqual(out, [ + runStarted, + ...eagerToolCall, + { type: 'TEXT_MESSAGE_START', messageId: M1, role: 'assistant', subagentRunId: SUB }, + { type: 'TEXT_MESSAGE_CONTENT', messageId: M1, delta: 'A', subagentRunId: SUB }, + { type: 'TEXT_MESSAGE_CONTENT', messageId: M1, delta: 'B', subagentRunId: SUB }, + { type: 'TEXT_MESSAGE_END', messageId: M1, subagentRunId: SUB }, + { type: 'SUBAGENT_FINISHED', subagentRunId: SUB, outcome: { type: 'success' } }, + result, + parentText, + finished, + ]); + assert.equal(out.filter((e) => e.type === 'TOOL_CALL_START').length, 1); +}); + +test('terminal cleanup closes an open child message before SUBAGENT_ERROR, exactly once', () => { + const injector = createSubagentInjector(); + injector.chunk(stepStartChunk); + injector.chunk(toolCallChunk()); + injector.chunk(childDelta('half')); + const out = injector.eventsFor({ type: 'RUN_ERROR', message: 'boom' }); + assert.deepEqual(out, [ + { type: 'TEXT_MESSAGE_END', messageId: M1, subagentRunId: SUB }, + { type: 'SUBAGENT_ERROR', subagentRunId: SUB, message: 'delegation did not complete before the run terminated' }, + { type: 'RUN_ERROR', message: 'boom' }, + ]); + assert.deepEqual(injector.eventsFor({ type: 'RUN_FINISHED' }), [{ type: 'RUN_FINISHED' }]); +}); + +test('two sequential delegations get distinct message ids and independent state', () => { + const injector = createSubagentInjector(); + injector.chunk(stepStartChunk); + injector.chunk(toolCallChunk('call_a')); + injector.chunk(childDelta('a1')); + injector.chunk(toolResultChunk(SUCCESS_RESULT, 'call_a')); + injector.chunk(toolCallChunk('call_b')); + const out = injector.chunk(toolOutput({ type: 'text-delta', payload: { text: 'b1' } }, 'call_b')); + assert.deepEqual(out, [ + { type: 'TEXT_MESSAGE_START', messageId: 'call_b-sub-m1', role: 'assistant', subagentRunId: 'call_b-sub' }, + { type: 'TEXT_MESSAGE_CONTENT', messageId: 'call_b-sub-m1', delta: 'b1', subagentRunId: 'call_b-sub' }, + ]); +}); + test('pending delegation at RUN_ERROR → SUBAGENT_ERROR cleanup, then no double-cleanup', () => { const injector = createSubagentInjector(); const out = [ From 6142c7052eaaf621d4e4df3b0140287bfeeabaa8 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 2 Sep 2026 11:47:53 -0700 Subject: [PATCH 5/8] feat(runtimes): mastra server wires the delegation tee into the SSE stream Co-Authored-By: Claude Fable 5.1 --- deployments/ag-ui-mastra/server.mjs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/deployments/ag-ui-mastra/server.mjs b/deployments/ag-ui-mastra/server.mjs index 8987db394..6641f90f5 100644 --- a/deployments/ag-ui-mastra/server.mjs +++ b/deployments/ag-ui-mastra/server.mjs @@ -23,6 +23,7 @@ import { dirname, resolve } from 'node:path'; import { MastraAgent } from '@ag-ui/mastra'; import { createMastra } from './agents.mjs'; import { createSubagentInjector } from './subagent-emitter.mjs'; +import { withDelegationTee } from './streaming-tee.mjs'; const AG_UI_INTERNAL_TOKEN = process.env.AG_UI_INTERNAL_TOKEN; if (!AG_UI_INTERNAL_TOKEN) { @@ -100,27 +101,40 @@ export function createAgUiServer() { connection: 'keep-alive', }); + // One injector per run with two inputs, both writing through the same + // SSE frame writer: + // - `chunk()`: raw Mastra fullStream chunks observed through the stream + // tee BEFORE the bridge processes them — the eager TOOL_CALL_* + + // SUBAGENT_STARTED on the delegation `tool-call`, the child's + // attributed TEXT_MESSAGE_* deltas from `tool-output`, and + // SUBAGENT_FINISHED/ERROR on `tool-result`. + // - `eventsFor()`: the bridge's own AG-UI events, with its later buffered + // TOOL_CALL_START/ARGS/END copies for a synthesized id dropped. + const injector = createSubagentInjector(); + const write = (event) => res.write(sseFrame(event)); + const observe = (chunk) => { + for (const e of injector.chunk(chunk)) write(e); + }; + // A fresh bridge per request: MastraAgent carries per-run state. // resourceId scopes Mastra memory (threads live under a resource); - // keying it by AG-UI threadId gives per-conversation memory. + // keying it by AG-UI threadId gives per-conversation memory. The bridge + // receives the teed agent; it is otherwise unmodified. const bridge = new MastraAgent({ agentId: topic, - agent, + agent: withDelegationTee(agent, observe), resourceId: input.threadId, }); - // One injector per run: turns delegation tool calls (`agent-`) - // into SUBAGENT_* frames around the events the bridge already emits. - const injector = createSubagentInjector(); const sub = bridge.run(input).subscribe({ next: (event) => { - for (const e of injector.eventsFor(event)) res.write(sseFrame(e)); + for (const e of injector.eventsFor(event)) write(e); }, error: (err) => { // Map failures into the protocol instead of killing the socket: // the client finalizes the run as an error rather than hanging. const runError = { type: 'RUN_ERROR', message: String(err?.message ?? err) }; - for (const e of injector.eventsFor(runError)) res.write(sseFrame(e)); + for (const e of injector.eventsFor(runError)) write(e); res.end(); }, complete: () => { From 6775188589bfbc6b5dde92a2e58f3866bcb3092b Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 2 Sep 2026 11:52:31 -0700 Subject: [PATCH 6/8] docs(runtimes): mastra streaming live verification Co-Authored-By: Claude Fable 5.1 --- .../angular/docs/wire-capture-subagents.md | 90 +++++++++++++++++- .../angular/e2e/manual/subagent-card-live.png | Bin 77840 -> 73341 bytes 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md b/cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md index bd8425704..c42d239a0 100644 --- a/cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md +++ b/cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md @@ -221,12 +221,13 @@ Notes: (`case "tool-output": break` in @ag-ui/mastra), so the one TEXT_MESSAGE_CONTENT carries the child's entire final text. -## Browser verification +## Browser verification (pre-streaming, superseded below) Live check 2026-09-02: real-key `deployments/ag-ui-mastra` on the topic port + `npx nx serve cockpit-runtimes-mastra-angular`, driving "Plan a trip to Bear -Lake this weekend - what will the weather be?" in the real UI. Screenshot of -the completed, expanded card: `e2e/manual/subagent-card-live.png`. +Lake this weekend - what will the weather be?" in the real UI. The screenshot +referenced here was replaced by the post-streaming capture (see "Browser +verification (after streaming)"). - The card renders from the injected events with ZERO component code: `chat-tool-calls` groups on `parentToolCallId` and mounts @@ -316,3 +317,86 @@ entry (`Subagent.toolCallId` is the anchor). A `SUBAGENT_STARTED` with no prior `TOOL_CALL_START` for its `parentToolCallId` therefore renders NO card: synthesizing the eager `TOOL_CALL_START/ARGS/END` on the `tool-call` chunk is required, not optional, for the card to appear before the child finishes. + +## After streaming + +Live smoke 2026-09-02 against the committed stream tee +(`deployments/ag-ui-mastra/streaming-tee.mjs`) + the chunk-aware injector +(`subagent-emitter.mjs`) wired in `server.mjs`. Pins unchanged +(`@ag-ui/mastra@1.1.2`, `@mastra/core@1.63.2`); the bridge itself is not +modified. Request: `POST /agent/mastra` with the same delegation prompt, +timestamped from the request start (scrubbed): + +``` +t= 169ms {"type":"RUN_STARTED","threadId":"t-live-…","runId":"r-live-…"} +t= 1578ms {"type":"TOOL_CALL_START","parentMessageId":"5764473e-…","toolCallId":"call_nXsj…","toolCallName":"agent-weather_forecaster"} ← eager (synthesized on the tool-call chunk) +t= 1578ms {"type":"TOOL_CALL_ARGS","toolCallId":"call_nXsj…","delta":"{\"prompt\":\"What is the weather forecast for Bear Lake this w…"} +t= 1578ms {"type":"TOOL_CALL_END","toolCallId":"call_nXsj…"} +t= 1578ms {"type":"SUBAGENT_STARTED","subagentRunId":"call_nXsj…-sub","name":"weather_forecaster","parentToolCallId":"call_nXsj…"} +t= 6263ms {"type":"TEXT_MESSAGE_START","messageId":"call_nXsj…-sub-m1","role":"assistant","subagentRunId":"call_nXsj…-sub"} +t= 6266ms {"type":"TEXT_MESSAGE_CONTENT","messageId":"call_nXsj…-sub-m1","delta":"Here's","subagentRunId":"call_nXsj…-sub"} +t= 6306ms {"type":"TEXT_MESSAGE_CONTENT",…,"delta":" the",…} +t= 6314ms {"type":"TEXT_MESSAGE_CONTENT",…,"delta":" weather",…} + … x94 attributed deltas, 399 chars, t=6266→7183ms … +t= 7183ms {"type":"TEXT_MESSAGE_END","messageId":"call_nXsj…-sub-m1","subagentRunId":"call_nXsj…-sub"} +t= 7382ms {"type":"SUBAGENT_FINISHED","subagentRunId":"call_nXsj…-sub","outcome":{"type":"success"}} +t= 7382ms {"type":"TOOL_CALL_RESULT","toolCallId":"call_nXsj…","content":"{\"text\":\"Here's the weather forecast for Bear Lake this weekend:…","messageId":"731b3738-…","role":"tool"} +t= 8138ms {"type":"STATE_SNAPSHOT","snapshot":{}} + {"type":"TEXT_MESSAGE_CHUNK",…} x68 — the parent's own summary + {"type":"RUN_FINISHED",…} +``` + +Event-type totals: 1 each RUN_STARTED / TOOL_CALL_START / TOOL_CALL_ARGS / +TOOL_CALL_END / SUBAGENT_STARTED / TEXT_MESSAGE_START / TEXT_MESSAGE_END / +SUBAGENT_FINISHED / TOOL_CALL_RESULT / STATE_SNAPSHOT / RUN_FINISHED, +94 TEXT_MESSAGE_CONTENT (all carrying `subagentRunId`), 68 TEXT_MESSAGE_CHUNK. + +Verified on the wire: + +- Eager `TOOL_CALL_START` + `SUBAGENT_STARTED` land at t=1.6 s, ~4.7 s before + the first attributed delta and ~5.8 s before `TOOL_CALL_RESULT` — the gap + the pre-streaming capture spent silent. +- Exactly ONE `TOOL_CALL_START` for the delegation id: the bridge's buffered + copy (flushed at `tool-result`) is dropped by the injector's dedupe. +- `SUBAGENT_FINISHED` precedes `TOOL_CALL_RESULT` (both written when the + `tool-result` chunk is observed, before the bridge processes it). +- The ~4.7 s between STARTED and the first delta is the child's own inner + `updateWorkingMemory` tool call plus model latency, not buffering: the raw + tap shows the same inner call preceding the child's `text-start`. + +Caveats and the fallback design: + +- Suspended delegations: if a child ever emitted `tool-call-suspended`, the + bridge would retract its buffered tool call (never emit START), but the + eager START is already painted; the injector closes the card with + `SUBAGENT_FINISHED {outcome:{type:'suspended'}}` and lets the bridge's + CUSTOM on_interrupt + RUN_FINISHED interrupt outcome through. The demo's + delegation does not suspend (no suspending tools on the child); this path + is unit-tested only. +- Inner sub-agent tool calls stay out of scope (ignored under `tool-output`). +- Alternative considered: subclassing the bridge and overriding its chunk + processor. Rejected because it couples to three TS-private methods, the + bridge's `clone()` constructs the base class (dropping overrides), and the + method signatures drift on upstream `main`. The Proxy tee touches only the + public agent surface the bridge reads (`'getMemory' in agent`, `stream`, + `resumeStream`, `getMemory`, `listTools`, `model`) and remains the fallback + design should the public seam ever move. + +## Browser verification (after streaming) + +Live check 2026-09-02, same servers, driving the real UI with "Plan a trip to +Bear Lake this weekend - what will the weather be?". Screenshot of the +completed, expanded card: `e2e/manual/subagent-card-live.png`. + +- The card mounts in the `running` state with "0 message(s)" at ~2.5–3.5 s + after send — before any child text exists — because the eager + `TOOL_CALL_START` gives `chat-tool-calls` the tool-call entry to anchor on. +- Headless 150 ms poll of the card's `innerText` length while + `data-state="running"` (distinct samples): 67 → 110 → 188 → 261 → 279 → + 306 → 330 → 457 → 494 chars (t=3454 ms → 10827 ms), then `done` (the card + collapses to its header, 68 chars) at t=10982 ms. Text visibly grows inside + the running card; the earlier capture never left `running` visible at all. +- A second, interactive run through the dev browser pane showed the same + shape at coarser (1 s, throttled) sampling: 67 → 131 → 474 chars while + `running`, then `done`. +- The parent's own summary streams below the card afterwards, unchanged. diff --git a/cockpit/runtimes/mastra/angular/e2e/manual/subagent-card-live.png b/cockpit/runtimes/mastra/angular/e2e/manual/subagent-card-live.png index fac129361f819bc5e3d7c7f8cdcd7941aacfb9b6..ab41577605f28ace00ea5544b124a53531705147 100644 GIT binary patch literal 73341 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 literal 77840 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%0AO2NGojadoRtAa4!)Uvh<^>;lhG zXea%FAUAi*GB-h63AY*|7eH#n=&25zpxs2gT0QpEmuhL?kyiFhmo~oC$`CAsAJW)7 z#xxJ%mCyun)^HJRDx_?NaAa|Aa5g*mys}n4Ea`Me5`KVe!YvYKs3YDj^cxOdgV|W9PkSfY) z^ZFYUXQPARJ;dPkvI$i4^8NN~&*Y2o1~ox1{W$M&#@UKs(B za8dRX#iQ_UF}rt zBOgFtM&`Z#*YRkD=E1H@?#K<4NWl$@9R}5hBD1IaC%_vyh8tLPt&De*H@48bFdOVh{JZl*8Pm4 zfAGml4Kl6D#{l*`bhgngx^UFMA?B~NKDsNPDBeAaih$v8k4+BsUmfje_JV)kz>q-e zaS;q|rKBs$u2MmbXrpZXA%vYgO852)klbAE841N>6k zyxzXAFOt6UEVF-|*Y+5xI`p~rOmB;@eucm_=Y*)e6~hA&Rb;qfQVvW$W!XzSgOaqR z0By2aLPk$w1}k0+YX3oOSvkidMHasmcgkrf3zCS|NL<%LTV2}f|1W?_EbD*WR_RAGAO zZee)sY%<$4-`}gJe8(ZiAMBA!#?18*Rrz@!_C~0RzPx449sN4wumtbIO&~ZrZ|(y& z%m9|zcg>;uyAR2~BMP+`07AClG7#T;*Hz`R6G&WhrEN^28%#TeL-7Y3 zxll#)bZ<7!!jW~5=dvHDs=DwanmVRx4S4vn(I~4;VLyPkk=tugXS?)7mhHwgjok>I z-kP3Bi#*hK4S)jXs&=`@)`Q_jb@eLLTrle~*z$HeI*F&oxVfja4RqGa!RoS=QaIa) z#3F^;0Nc@~3nFKIKhoZEnf+4Xy_HNsY;8B*70H#~BGzBSWfbm6KCc-RoMLg4_8$ZYR3 z_9k3i3P+~Fid?RlT`4Ao503|b!7oq5N2txb9KaCEfGb=2o;y!kJx|eKthQr%H;fHk zInJS**Vdezqd3YZOswvwoO$H4kPxu0g7LqhaX(10C^oj-q1n+mAEqrKiGRo*y%#Uxtz zbhWct(;654=m{kh%S0wu`A7kn;r3(-go4-6>*npf6`z(YL*ENO`ZMK&UL7|flm->i3Y11Qo$@NT^q1nBezNv$hcQ-gRNf5~hV8I_Y5`Rj%?m(j zj^WckOFFH~09GTJ$NfN7L8mZiB+)R}NW4E&+WS5ncyL%i$}x(cqJ-VE13sE$Whhi; zF_&ap)x(s0loFEvg!?2_c1WdmRD=aCAWXvnn+{TzsyU1R*8;)~!x#4tPWIy4?0^u4 zug@b#`%wZKx|=&eqA(l0LGiSOvqBk4{?Ocfr5InJ56qL+M)P%pMuN{1sjF+WREI9T zg?T{t=Oq@XnUh{4wp%;WCJ8_wAU-NBUeQqvY0qHH2MjZQ41YUIyC2jv|7Ot#luI z_~uZoKjq0kk%8lUPG{iZ%_=zP#3+Pwgk5G54Tp`kt>%#xx$%MqR%n_FM=(?f(aa#t z)v0`*Xdu)C%usb9IseZ1iWkq){&6kwH04WAL!9P}+>k9T1AwE;IMN!LL4Nf{7tl*< ze|yS`+UD>1nX(VX=|&*7;q60GI?WThpRfaZrmJsCAEo!gwR|rvb;4Fi4)rLc2iUoK zVDJCkt2Mz~1{{vWLm$%4r@8GL+Cf_0e zL4B6k!{1-k_38Nw-^z}Tl!FhRN!nI=mo)hZ>7|v1Kzn}DhjcfUI^T$~B$km^@f9Pk z!UGWjX~cOV8s(&kJCP?(hL4Ej_!^7haK9{C>N>w*-m^UD^`U zD1(NXz1<_~LQLWRO<=cXP=7J-#*F_Tv87YyGiT16o|ZK3Pr^UoB8~64Gw(cw?i^<9 S^uT{PgI3W|u2#Gi{C@yQgK Date: Wed, 2 Sep 2026 11:54:41 -0700 Subject: [PATCH 7/8] =?UTF-8?q?docs(website,blog):=20mastra=20subagents=20?= =?UTF-8?q?stream=20=E2=80=94=20cell=20flips=20to=20Yes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 --- .../2026-08-31-we-measured-the-runtime-swap.mdx | 13 +++++++------ .../content/docs/choosing-an-adapter/index.mdx | 5 +++-- .../docs/runtimes/getting-started/introduction.mdx | 4 ++-- .../docs/runtimes/mastra/how-it-connects.mdx | 7 ++++--- .../content/docs/runtimes/mastra/overview.mdx | 8 +++++--- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/apps/website/content/blog/2026-08-31-we-measured-the-runtime-swap.mdx b/apps/website/content/blog/2026-08-31-we-measured-the-runtime-swap.mdx index 309efb2ee..e2c0a8d65 100644 --- a/apps/website/content/blog/2026-08-31-we-measured-the-runtime-swap.mdx +++ b/apps/website/content/blog/2026-08-31-we-measured-the-runtime-swap.mdx @@ -45,7 +45,7 @@ A committed transcript replayed through the real client proves what the runtime | LangGraph (baseline) | Yes | Yes | Yes | Yes | Yes | | AWS Strands | Yes | Yes | Partial | Yes | Yes | | Microsoft Agent Framework | Yes | Yes | Yes | Yes | Yes | -| Mastra | Yes | Yes | Yes | Yes | Partial | +| Mastra | Yes | Yes | Yes | Yes | Yes | Messages, tool calls, and shared state crossed three non-LangGraph runtimes with zero changes to the adapter. Not one line. @@ -123,7 +123,7 @@ They were only findable by pointing the adapter at software written by people wh ## What stayed partial -Two cells did not go fully green. +One cell did not go fully green. **Shared state on Strands is partial.** Its bridge sends whole-document snapshots and never sends a patch, and a tool only contributes state if it opts in through a per-tool hook. @@ -138,11 +138,12 @@ The cause is the upstream bridge, not the protocol and not us. The protocol standardized the events — `SUBAGENT_STARTED`, `SUBAGENT_FINISHED`, `SUBAGENT_ERROR`, plus a `subagentRunId` attribution field on ordinary content events — and the adapter consumes them directly. What no runtime does is emit them natively. -Each one reports delegation in its own dialect: Strands surfaces the specialist's tool use and forwards its token stream, Microsoft Agent Framework streams the specialist's updates in-process into the tool body where the in-tree emitter merges them across the bridge boundary, and Mastra reports the delegation through its tool frames and returns the child's final text. +Each one reports delegation in its own dialect: Strands surfaces the specialist's tool use and forwards its token stream, Microsoft Agent Framework streams the specialist's updates in-process into the tool body where the in-tree emitter merges them across the bridge boundary, and Mastra forwards the child's chunks on the parent stream, where its bridge drops them and withholds the delegation tool call until the child resolves. So each demo backend carries a small emitter — roughly 125 to 310 lines each — that translates its runtime's dialect into the standard events at the bridge boundary. -Two of the three cards stream live. -Mastra's fills in at completion, because its bridge does not forward child tokens to the wire; that is the one Partial cell, and it belongs to the runtime's bridge rather than to the protocol or the adapter. +All three cards stream live. +Mastra's took one more seam than the others: the emitter observes the runtime's public stream through a tee ahead of the bridge, emits the delegation tool call eagerly, and forwards the child's deltas itself, because the bridge would otherwise have painted the card only at completion. +That extra seam belongs to the runtime's bridge rather than to the protocol or the adapter, and the bridge itself is left unmodified. If you are building on server-declared subagents today, the contract to target is the protocol's own events; the emitter is the per-runtime cost, and it is small. ## What the deploy check found @@ -171,7 +172,7 @@ That is now measured against three implementations in two languages. Interrupts are portable as of these fixes, and they were not before, in a way no amount of internal testing would have revealed. -Subagents are portable through a per-runtime emitter that speaks the protocol's own events, streaming on two of the three runtimes and lifecycle-plus-final-text on the third. +Subagents are portable through a per-runtime emitter that speaks the protocol's own events, streaming on all three runtimes. The matrix now lives in the [adapter guide](/docs/choosing-an-adapter), with a cause column on every gap. Split three ways: the protocol cannot express it, the upstream bridge does not emit it, or our adapter failed to consume it. diff --git a/apps/website/content/docs/choosing-an-adapter/index.mdx b/apps/website/content/docs/choosing-an-adapter/index.mdx index b711d1aa4..52611a9a7 100644 --- a/apps/website/content/docs/choosing-an-adapter/index.mdx +++ b/apps/website/content/docs/choosing-an-adapter/index.mdx @@ -94,7 +94,7 @@ We tested it against three runtimes that have nothing to do with LangGraph, in t | **LangGraph** (via the AG-UI bridge) | Yes | Yes | Yes | Yes | Yes | — | | **AWS Strands** (Python) | Yes | Yes | Partial | Yes | Yes | State: upstream. Subagents: a small in-tree emitter translates native delegation signals to the protocol's `SUBAGENT_*` events | | **Microsoft Agent Framework** (Python) | Yes | Yes | Yes | Yes | Yes | Subagents: a small in-tree emitter translates native delegation signals to the protocol's `SUBAGENT_*` events | -| **Mastra** (TypeScript) | Yes | Yes | Yes | Yes | Partial | Subagents: lifecycle and final text via the emitter; the runtime's bridge does not forward child token streams | +| **Mastra** (TypeScript) | Yes | Yes | Yes | Yes | Yes | Subagents: a small in-tree emitter observes the runtime's public stream through a tee and emits the protocol's `SUBAGENT_*` events plus the child's token deltas, because the runtime's bridge drops child output | Every gap in that table falls into one of three causes, and the distinction is the point of the column: @@ -133,7 +133,8 @@ The protocol standardized the events — `SUBAGENT_STARTED`, `SUBAGENT_FINISHED` What differs per runtime is how the emitter learns about the delegation. Strands surfaces the specialist's tool use and streamed tokens through a per-tool stream handler, so the card streams live. On Microsoft Agent Framework the specialist's updates stream in-process into the tool body, and the in-tree emitter merges them across the bridge boundary, so the card streams live there too. -Mastra reports delegation through its tool frames and returns the child's final text; its bridge does not forward child tokens, so the card fills in at completion — the one Partial cell, a property of the runtime's bridge rather than of the protocol or the adapter. +Mastra streams the child's chunks in-process on the parent stream, but its bridge drops them and withholds the delegation tool call until the child resolves; the in-tree emitter therefore observes the runtime's public stream through a tee ahead of the bridge, emits the delegation tool call eagerly, and forwards the child's deltas under the subagent identity, so the card mounts while the child runs and streams live there too. +All three cards stream live; the Mastra card streams through the tee rather than through the bridge, a property of the runtime's bridge rather than of the protocol or the adapter. Each demo backend ships its emitter in tree, roughly 125 to 310 lines per runtime. ### How this was measured diff --git a/apps/website/content/docs/runtimes/getting-started/introduction.mdx b/apps/website/content/docs/runtimes/getting-started/introduction.mdx index 80a6a2b46..6427852cd 100644 --- a/apps/website/content/docs/runtimes/getting-started/introduction.mdx +++ b/apps/website/content/docs/runtimes/getting-started/introduction.mdx @@ -41,7 +41,7 @@ TypeScript. Messages, tool calls, state, and interrupts all work, against a hand | **LangGraph** (via the AG-UI bridge) | Yes | Yes | Yes | Yes | Yes | | **AWS Strands** (Python) | Yes | Yes | Partial | Yes | Yes | | **Microsoft Agent Framework** (Python) | Yes | Yes | Yes | Yes | Yes | -| **Mastra** (TypeScript) | Yes | Yes | Yes | Yes | Partial | +| **Mastra** (TypeScript) | Yes | Yes | Yes | Yes | Yes | Every gap in that table is caused by an upstream integration, not by the AG-UI protocol and not by a defect in `@threadplane/ag-ui`. The full cause analysis, including the two adapter defects that were found and fixed, lives in [Choosing an adapter](/docs/choosing-an-adapter). @@ -88,7 +88,7 @@ Three differences turned up repeatedly, and each runtime page returns to them. **Resume payloads are not portable.** The adapter derives the wire shape from how the interrupt arrived, so application code passes one neutral `submit({ resume })` regardless of runtime. -**Subagents now work on every runtime measured here** — streaming on AWS Strands and Microsoft Agent Framework, and as lifecycle-plus-final-text on Mastra. Each backend ships a small emitter that translates its native delegation signals into the protocol's `SUBAGENT_*` events, which `@threadplane/ag-ui` consumes directly. The per-runtime pages show the emitter and the wire capture behind each cell. +**Subagents now stream on every runtime measured here** — AWS Strands, Microsoft Agent Framework, and Mastra. Each backend ships a small emitter that translates its native delegation signals into the protocol's `SUBAGENT_*` events, which `@threadplane/ag-ui` consumes directly. The per-runtime pages show the emitter and the wire capture behind each cell. ## Further reading diff --git a/apps/website/content/docs/runtimes/mastra/how-it-connects.mdx b/apps/website/content/docs/runtimes/mastra/how-it-connects.mdx index e817a9a94..a33b86e77 100644 --- a/apps/website/content/docs/runtimes/mastra/how-it-connects.mdx +++ b/apps/website/content/docs/runtimes/mastra/how-it-connects.mdx @@ -54,10 +54,11 @@ Shared state is a Mastra working-memory object under a Zod schema. The bridge em That places Mastra alongside Microsoft Agent Framework and apart from AWS Strands, whose bridge emits snapshots only. -## Subagents surface as lifecycle plus final text +## Subagents stream through a tee ahead of the bridge -An in-tree injector in the hosting service watches the wire for delegation tool frames — Mastra names them `agent-` — and adds `SUBAGENT_STARTED` on the tool-call start, one attributed text message carrying the child's final text, and `SUBAGENT_FINISHED` on the result. -The child's incremental tokens never reach the wire because `@ag-ui/mastra` drops its `tool-output` chunks and buffers the delegation burst until it resolves, which is why this cell is Partial. +Mastra forwards every chunk of a delegated child on the parent stream as a public `tool-output` chunk, but `@ag-ui/mastra` drops those chunks and withholds the delegation tool call — Mastra names it `agent-` — until the child resolves. +The hosting service wraps the agent so that each chunk is observed before the bridge processes it, and a per-run injector emits the delegation tool call eagerly, `SUBAGENT_STARTED`, one `TEXT_MESSAGE_CONTENT` per child delta attributed to the subagent, and `SUBAGENT_FINISHED` on the result, while dropping the bridge's later copy of the same tool call. +The card therefore mounts as soon as the delegation begins and its text grows while the child runs, which is what makes this cell Supported. ## Next steps diff --git a/apps/website/content/docs/runtimes/mastra/overview.mdx b/apps/website/content/docs/runtimes/mastra/overview.mdx index 9c407dd3c..2f1a50613 100644 --- a/apps/website/content/docs/runtimes/mastra/overview.mdx +++ b/apps/website/content/docs/runtimes/mastra/overview.mdx @@ -21,7 +21,7 @@ The hosted example runs at [examples.threadplane.ai/runtimes/mastra](https://exa | Tool calls | Supported | `check_conditions` executes server-side with no pause. | | Shared state | Supported | A working-memory packing list, over snapshots and real JSON-Patch deltas. | | Interrupts | Supported | `reserve_campsite` suspends the run and resumes from a persisted snapshot. | -| Subagents | Partial | The bridge emits delegation tool frames; an in-tree injector adds `SUBAGENT_*` lifecycle and the child's final text — the runtime's bridge does not forward child tokens. | +| Subagents | Supported | An in-tree stream tee observes the parent stream ahead of the bridge and emits the delegation tool call eagerly, `SUBAGENT_*` lifecycle, and the child's token deltas under the subagent identity. | ## Upstream ships no HTTP endpoint @@ -37,9 +37,11 @@ Mastra persists memory and suspended-run snapshots to LibSQL file storage. Resum ## How subagents surface -Mastra registers a child agent as a delegation tool named `agent-`, so a delegation crosses the wire as ordinary `TOOL_CALL_*` frames whose result carries the child's final text. An in-tree injector in the hosting service (`deployments/ag-ui-mastra/subagent-emitter.mjs`) keys off those frames: it emits `SUBAGENT_STARTED` when the delegation tool call starts, an attributed text message carrying the child's final text, and `SUBAGENT_FINISHED` when the result lands. +Mastra registers a child agent as a delegation tool named `agent-`, and while the child runs its every chunk is forwarded on the parent stream as a public `tool-output` chunk. The runtime's bridge drops those chunks and withholds the delegation tool call until the child resolves, so on its own the wire would carry only the child's final text, after a silent gap. -The cell is Partial rather than green because the runtime's bridge does not forward child tokens: the child's deltas exist in-process, but `@ag-ui/mastra` drops its `tool-output` chunks and buffers the delegation burst until it resolves, so the card fills in at completion instead of streaming. That is a property of the bridge, not of the protocol or the adapter. The wire capture behind this cell is committed at [`cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md`](https://github.com/cacheplane/angular-agent-framework/tree/main/cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md). +The hosting service therefore wraps the agent in a small stream tee (`deployments/ag-ui-mastra/streaming-tee.mjs`) that observes each chunk before the bridge processes it, and a per-run injector (`deployments/ag-ui-mastra/subagent-emitter.mjs`) maps them to the protocol: the delegation `tool-call` chunk becomes an eager `TOOL_CALL_START`, `TOOL_CALL_ARGS`, and `TOOL_CALL_END` plus `SUBAGENT_STARTED`; each child text delta becomes a `TEXT_MESSAGE_CONTENT` attributed to the subagent; and the delegation result becomes `SUBAGENT_FINISHED` or `SUBAGENT_ERROR`. The bridge's own copy of the delegation tool call, flushed at the result, is dropped so the wire carries it once. + +The bridge itself is unmodified; the tee touches only the public agent members the bridge reads. The child's tokens reach the card while it is still running, which is what flips this cell to Supported. The wire capture behind this cell is committed at [`cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md`](https://github.com/cacheplane/angular-agent-framework/tree/main/cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md). ## How the Mastra row was measured From ed48227f7e268f90b466693e4d130e3c3309f8bc Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 2 Sep 2026 13:44:49 -0700 Subject: [PATCH 8/8] =?UTF-8?q?docs+test(runtimes):=20mastra=20streaming?= =?UTF-8?q?=20review=20fixes=20=E2=80=94=20line-count=20range,=20supersede?= =?UTF-8?q?d=20marker,=20tee=20edge=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Correct the emitter line-count claim in the blog post and adapter-choice docs from a stale "125 to 310" to the measured "190 to 360" (aws-strands 189, microsoft-agent-framework 309, mastra emitter+tee 287+76=363). - Mark the wire-capture-subagents.md verdict-summary row for incremental child streaming as superseded, pointing at the After streaming section that documents the actual (later) behavior. - Add streaming-tee tests: consumer early break on the wrapped fullStream propagates to the source generator's return(); traceId/usage defined as prototype getters still resolve through the result proxy. - Add a subagent-emitter test: an agent-* tool-call chunk with no prior start/step-start synthesizes TOOL_CALL_START with the parentMessageId key entirely absent, not present-but-undefined. - Annotate the tee's has() trap as a deliberate restatement of default behavior rather than dead code. Co-Authored-By: Claude Fable 5.1 --- ...026-08-31-we-measured-the-runtime-swap.mdx | 2 +- .../docs/choosing-an-adapter/index.mdx | 2 +- .../angular/docs/wire-capture-subagents.md | 2 +- deployments/ag-ui-mastra/streaming-tee.mjs | 3 + .../ag-ui-mastra/test/streaming-tee.test.mjs | 55 +++++++++++++++++++ .../test/subagent-emitter.test.mjs | 7 +++ 6 files changed, 68 insertions(+), 3 deletions(-) diff --git a/apps/website/content/blog/2026-08-31-we-measured-the-runtime-swap.mdx b/apps/website/content/blog/2026-08-31-we-measured-the-runtime-swap.mdx index e2c0a8d65..aa7f53631 100644 --- a/apps/website/content/blog/2026-08-31-we-measured-the-runtime-swap.mdx +++ b/apps/website/content/blog/2026-08-31-we-measured-the-runtime-swap.mdx @@ -139,7 +139,7 @@ The cause is the upstream bridge, not the protocol and not us. The protocol standardized the events — `SUBAGENT_STARTED`, `SUBAGENT_FINISHED`, `SUBAGENT_ERROR`, plus a `subagentRunId` attribution field on ordinary content events — and the adapter consumes them directly. What no runtime does is emit them natively. Each one reports delegation in its own dialect: Strands surfaces the specialist's tool use and forwards its token stream, Microsoft Agent Framework streams the specialist's updates in-process into the tool body where the in-tree emitter merges them across the bridge boundary, and Mastra forwards the child's chunks on the parent stream, where its bridge drops them and withholds the delegation tool call until the child resolves. -So each demo backend carries a small emitter — roughly 125 to 310 lines each — that translates its runtime's dialect into the standard events at the bridge boundary. +So each demo backend carries a small emitter — roughly 190 to 360 lines each — that translates its runtime's dialect into the standard events at the bridge boundary. All three cards stream live. Mastra's took one more seam than the others: the emitter observes the runtime's public stream through a tee ahead of the bridge, emits the delegation tool call eagerly, and forwards the child's deltas itself, because the bridge would otherwise have painted the card only at completion. diff --git a/apps/website/content/docs/choosing-an-adapter/index.mdx b/apps/website/content/docs/choosing-an-adapter/index.mdx index 52611a9a7..8999c7df9 100644 --- a/apps/website/content/docs/choosing-an-adapter/index.mdx +++ b/apps/website/content/docs/choosing-an-adapter/index.mdx @@ -135,7 +135,7 @@ Strands surfaces the specialist's tool use and streamed tokens through a per-too On Microsoft Agent Framework the specialist's updates stream in-process into the tool body, and the in-tree emitter merges them across the bridge boundary, so the card streams live there too. Mastra streams the child's chunks in-process on the parent stream, but its bridge drops them and withholds the delegation tool call until the child resolves; the in-tree emitter therefore observes the runtime's public stream through a tee ahead of the bridge, emits the delegation tool call eagerly, and forwards the child's deltas under the subagent identity, so the card mounts while the child runs and streams live there too. All three cards stream live; the Mastra card streams through the tee rather than through the bridge, a property of the runtime's bridge rather than of the protocol or the adapter. -Each demo backend ships its emitter in tree, roughly 125 to 310 lines per runtime. +Each demo backend ships its emitter in tree, roughly 190 to 360 lines per runtime. ### How this was measured diff --git a/cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md b/cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md index c42d239a0..6f074133d 100644 --- a/cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md +++ b/cockpit/runtimes/mastra/angular/docs/wire-capture-subagents.md @@ -14,7 +14,7 @@ this document is the only artifact. | Child registration | `agents: { weather_forecaster: childAgent }` on the supervisor's `Agent` config. | | Delegation hooks | `delegation: { onDelegationStart, onDelegationComplete }` in stream options; works via the supervisor's `defaultOptions` (verified live — both hooks fired). | | Delegation on the AG-UI wire today | An ordinary backend tool call named `agent-`: `TOOL_CALL_START` → one `TOOL_CALL_ARGS` blob → `TOOL_CALL_END` → `TOOL_CALL_RESULT` whose `content` is JSON `{text, subAgentThreadId, subAgentResourceId, subAgentToolResults}`. | -| Does child text stream incrementally anywhere? | **In-process yes, on the wire no.** The parent `fullStream` carries every child chunk wrapped as `tool-output` (`payload: {output: , toolCallId, toolName}`) — 82 inner `text-delta` chunks in the raw tap — but `@ag-ui/mastra`'s chunk processor drops them (`case "tool-output": break`). Only the final text reaches AG-UI, inside `TOOL_CALL_RESULT`. | +| Does child text stream incrementally anywhere? | **In-process yes, on the wire no.** The parent `fullStream` carries every child chunk wrapped as `tool-output` (`payload: {output: , toolCallId, toolName}`) — 82 inner `text-delta` chunks in the raw tap — but `@ag-ui/mastra`'s chunk processor drops them (`case "tool-output": break`). Only the final text reaches AG-UI, inside `TOOL_CALL_RESULT`. — superseded, see [After streaming](#after-streaming) | | Delegation tool-call id (for `parentToolCallId`) | The LLM's tool-call id (e.g. `call_aUfV9K0RCDZdZK3NWt9dRDKx`). Identical across `TOOL_CALL_START/ARGS/END/RESULT` and both hooks' `toolCallId`. | ## Installed-API details (`node_modules/@mastra/core/dist`) diff --git a/deployments/ag-ui-mastra/streaming-tee.mjs b/deployments/ag-ui-mastra/streaming-tee.mjs index abf35799d..191c17916 100644 --- a/deployments/ag-ui-mastra/streaming-tee.mjs +++ b/deployments/ag-ui-mastra/streaming-tee.mjs @@ -70,6 +70,9 @@ export function withDelegationTee(agent, observe) { }; }, has(target, prop) { + // Restates the default `has` behavior explicitly, so the bridge's + // `'getMemory' in agent` check reads as a deliberate, documented + // contract of this Proxy rather than an accident of the default trap. return prop in target; }, }); diff --git a/deployments/ag-ui-mastra/test/streaming-tee.test.mjs b/deployments/ag-ui-mastra/test/streaming-tee.test.mjs index 981c50bb9..86cc9fb04 100644 --- a/deployments/ag-ui-mastra/test/streaming-tee.test.mjs +++ b/deployments/ag-ui-mastra/test/streaming-tee.test.mjs @@ -157,3 +157,58 @@ test('a stream result without fullStream is returned untouched', async () => { assert.equal(typeof result.processDataStream, 'function'); assert.equal(result.fullStream, undefined); }); + +// ── Consumer early-exit propagates to the source generator ──────────────── +test('consumer breaking out of the wrapped fullStream closes the source generator', async () => { + let finallyRan = false; + async function* source() { + try { + yield { type: 'a' }; + yield { type: 'b' }; + yield { type: 'c' }; + } finally { + finallyRan = true; + } + } + const agent = { + getMemory() {}, + async stream() { + return { fullStream: source() }; + }, + }; + const proxy = withDelegationTee(agent, () => {}); + const result = await proxy.stream([], {}); + const seen = []; + for await (const c of result.fullStream) { + seen.push(c.type); + if (c.type === 'a') break; + } + assert.deepEqual(seen, ['a']); + assert.equal(finallyRan, true, "breaking the consumer's loop must call the source generator's return()"); +}); + +// ── Result proxy forwards prototype getters, not just own properties ────── +test('traceId/usage defined as prototype getters still resolve through the result proxy', async () => { + class StreamResult { + get traceId() { + return 'trace-123'; + } + get usage() { + return { total: 42 }; + } + } + const resultInstance = new StreamResult(); + resultInstance.fullStream = (async function* () { + yield { type: 'a' }; + })(); + const agent = { + getMemory() {}, + async stream() { + return resultInstance; + }, + }; + const proxy = withDelegationTee(agent, () => {}); + const result = await proxy.stream([], {}); + assert.equal(result.traceId, 'trace-123'); + assert.deepEqual(result.usage, { total: 42 }); +}); diff --git a/deployments/ag-ui-mastra/test/subagent-emitter.test.mjs b/deployments/ag-ui-mastra/test/subagent-emitter.test.mjs index 71d7ba666..b883655aa 100644 --- a/deployments/ag-ui-mastra/test/subagent-emitter.test.mjs +++ b/deployments/ag-ui-mastra/test/subagent-emitter.test.mjs @@ -457,3 +457,10 @@ test('pending delegation at RUN_ERROR → SUBAGENT_ERROR cleanup, then no double // A second terminal frame injects nothing more. assert.deepEqual(injector.eventsFor({ type: 'RUN_FINISHED' }), [{ type: 'RUN_FINISHED' }]); }); + +test('chunk: agent-* tool-call with NO prior start/step-start omits parentMessageId entirely', () => { + const injector = createSubagentInjector(); + const [start] = injector.chunk(toolCallChunk()); + assert.equal(start.type, 'TOOL_CALL_START'); + assert.equal('parentMessageId' in start, false, 'key must be absent, not present with an undefined value'); +});