feat(runtimes): mastra sub-agent streaming via a public-API stream tee - #961
Merged
Conversation
…eam tee Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d-mount finding Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…the bridge consumes them Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…CALL_* and attributed child deltas Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tream Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
…, superseded marker, tee edge tests - 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 <noreply@anthropic.com>
Contributor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Mastra demo's subagent card now streams the child's deltas live, flipping the matrix cell from Partial to Yes. Spec:
docs/superpowers/specs/2026-09-02-mastra-subagent-streaming-design.md; plan:docs/superpowers/plans/2026-09-02-mastra-subagent-streaming.md.Research verdict (why this layer):
@ag-ui/mastra@1.1.2is the latest pin and drops everytool-outputchunk (case "tool-output": break) while buffering the delegation'sTOOL_CALL_START/ARGS/ENDuntil the tool result. There is no alternative upstream layer, the officialonChunkhook excludestool-output, and a bridge subclass would couple to three TS-private methods plus aclone()that rebuilds the base class. The child's chunks are, however, public and typed on the parentfullStream({type:'tool-output', payload:{output:<childChunk>, toolCallId, toolName}}), so the fix observes them through a public-API seam. Pins unchanged (@ag-ui/mastra@1.1.2,@mastra/core@1.63.2); the bridge is not modified.What changed
deployments/ag-ui-mastra/streaming-tee.mjs(new):withDelegationTee(agent, observe)— aProxyover the realAgentthat forwards every member bound to the real instance (#privatefields and the bridge's'getMemory' in agentcheck keep working) and wraps onlystream()/resumeStream()results sofullStreamis an async generator that callsobserve(chunk)before yielding to the bridge. One reader, one iteration, so observer writes are ordered ahead of the bridge's events for the same chunk.deployments/ag-ui-mastra/subagent-emitter.mjs: the per-run injector gainschunk(c)alongsideeventsFor(e). The delegationtool-callchunk synthesizes eagerTOOL_CALL_START/ARGS/END(args are complete there;parentMessageIdfrom the laststart/step-startchunk) +SUBAGENT_STARTED;tool-outputinnertext-start/delta/endbecome attributedTEXT_MESSAGE_START/CONTENT/END;tool-result/tool-error/tool-call-suspendedclose the card. The bridge's later bufferedTOOL_CALL_START/ARGS/ENDcopies for a synthesized id are dropped ineventsFor(itsTOOL_CALL_RESULTpasses through). The old single-chunk synthesis stays only as the no-deltas fallback.deployments/ag-ui-mastra/server.mjs: builds the proxy per request; both inputs write through the same SSE frame writer.choosing-an-adapter, runtimes intro, Mastra overview and how-it-connects, both runtime blog posts.Evidence
fullStream, 248 chunks):tool-call(args complete) →tool-outputx135 (explicittext-start, 108text-delta,text-end) →tool-result;tool-call-suspendednever appears;chat-tool-callsanchors cards to entries in the parenttoolCalls()list, so the eagerTOOL_CALL_STARTis required for the card to mount.TOOL_CALL_START+SUBAGENT_STARTEDat t=1578 ms; 94 attributedTEXT_MESSAGE_CONTENT(399 chars) t=6266–7183 ms;SUBAGENT_FINISHEDbeforeTOOL_CALL_RESULTat t=7382 ms; exactly oneTOOL_CALL_STARTfor the delegation id.data-state="running"): 67 → 110 → 188 → 261 → 279 → 306 → 330 → 457 → 494 chars, thendone. Screenshot:cockpit/runtimes/mastra/angular/e2e/manual/subagent-card-live.png.Tallies
deployments/ag-ui-mastra): 42/42 (8 tee, 24 injector, 10 service).cockpit/runtimes/mastra/angular: 5/5, assertions unchanged.npx nx test website: green.Caveats
TOOL_CALL_STARTis already painted when a child suspends (the bridge would have retracted its buffered copy); the injector closes the card withSUBAGENT_FINISHED {outcome:{type:'suspended'}}. The demo's delegation cannot suspend; the path is unit-tested only.tool-output).tool-outputmapping patch against the@ag-ui/mastraintegration, referencing #2402/#2403 for the eager-START half.🤖 Generated with Claude Code