feat(task-tool): live subagent progress + transcript (cutover Bundle B)
Summary
Second cutover bundle. Converts taskTool.execute from a synchronous-return function to an async function* that yields progress chunks throughout the subagent run, then a final chunk carrying the full subagent transcript. Mirrors open-agents' packages/agent/tools/task.ts so sandbox.recoupable.com's "Subagent · X tools · Y tokens" live progress card and expandable transcript render correctly when cut over to api's /api/chat/workflow.
Yielded chunk sequence (mirrors open-agents)
- Initial:
{toolCallCount: 0, startedAt, modelId}— stable timestamp for elapsed-time UI - Per
tool-callpart:{pending: {name, input}, toolCallCount, usage, startedAt, modelId} - Per
finish-steppart:{pending (sticky), toolCallCount, usage (accumulated), startedAt, modelId}— sticky pending prevents UI flicker between steps - Final:
{final: ModelMessage[], toolCallCount, usage, startedAt, modelId}— full subagent transcript
toModelOutput
Extracts the last assistant text part from output.final for the parent agent's context — same logic as open-agents.
New files (SRP)
lib/agent/messageMetadata/sumLanguageModelUsage.ts— wrapsaddLanguageModelUsageto handle undefined inputs without introducing zero-tokens placeholders
Drive-by fix
askUserQuestionTool.toModelOutput was still using the old (output) => signature from the ai@6.0.0-beta.122 era. The current SDK (ai@^6.0.190) passes ({ toolCallId, input, output }). Updated to ({ output }) => so the function actually receives the user's answers at runtime — previously it was falling through to the generic "User responded to questions." path regardless of input. Tests updated.
Cutover roadmap
| # | Bundle | This PR | Notes |
|---|---|---|---|
| 1 | C per-message cost/usage | ✅ merged | #592 / #593 |
| 2 | B subagent live progress + transcript | ✅ this PR | |
| 3 | A.7+9 real cwd + contextLimit | ||
| 4 | A.6 Anthropic prompt cache control | ||
| 5 | A.4 forward Privy JWT as recoupAccessToken |
Test plan
- 25 new/updated unit tests across 3 files (12 taskTool + 4 sumLanguageModelUsage + 9 askUserQuestion)
- Full suite 3114/3114 pass; lint clean
- E2E on preview: confirm task tool emits multiple
tool-output-availablechunks (one per yield), withpending,usage, andfinal: [...]shapes matching open-agents production - Cross-validate chunk shape against
sandbox.recoupable.comcapture
🤖 Generated with Claude Code
Summary by cubic
Streams live subagent progress and final transcript from taskTool by converting execute to an async generator, matching open-agents so the UI shows the “Subagent · X tools · Y tokens” card and an expandable transcript. Also fixes askUserQuestionTool.toModelOutput to accept ({ output }) per the current ai SDK.
-
New Features
taskTool.executenow yields:- Initial:
{ toolCallCount: 0, startedAt, modelId } - On each tool-call:
{ pending: { name, input }, toolCallCount, usage, startedAt, modelId } - On each finish-step: same with accumulated
usageand stickypending - Final:
{ final: ModelMessage[], toolCallCount, usage, startedAt, modelId }
- Initial:
- Added
sumLanguageModelUsageto safely combine optional usage values. taskTool.toModelOutputextracts the last assistant text fromoutput.final.
-
Bug Fixes
askUserQuestionTool.toModelOutputnow uses({ output })(currentai@^6.0.190shape) so user answers are parsed correctly.
Summary by CodeRabbit
-
New Features
- Task execution now streams live progress updates with real-time metrics including tool call counts, token usage, and execution timing.
-
Refactor
- Improved tool output parameter handling and token usage aggregation across agent tools.