feat(task-tool): live subagent progress + transcript (cutover Bundle B)

Merged
SW
5mo ago
+343-149

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)

  1. Initial: {toolCallCount: 0, startedAt, modelId} — stable timestamp for elapsed-time UI
  2. Per tool-call part: {pending: {name, input}, toolCallCount, usage, startedAt, modelId}
  3. Per finish-step part: {pending (sticky), toolCallCount, usage (accumulated), startedAt, modelId} — sticky pending prevents UI flicker between steps
  4. 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 — wraps addLanguageModelUsage to 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

#BundleThis PRNotes
1C per-message cost/usage✅ merged#592 / #593
2B subagent live progress + transcript✅ this PR
3A.7+9 real cwd + contextLimit
4A.6 Anthropic prompt cache control
5A.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-available chunks (one per yield), with pending, usage, and final: [...] shapes matching open-agents production
  • Cross-validate chunk shape against sandbox.recoupable.com capture

🤖 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.execute now yields:
      • Initial: { toolCallCount: 0, startedAt, modelId }
      • On each tool-call: { pending: { name, input }, toolCallCount, usage, startedAt, modelId }
      • On each finish-step: same with accumulated usage and sticky pending
      • Final: { final: ModelMessage[], toolCallCount, usage, startedAt, modelId }
    • Added sumLanguageModelUsage to safely combine optional usage values.
    • taskTool.toModelOutput extracts the last assistant text from output.final.
  • Bug Fixes

    • askUserQuestionTool.toModelOutput now uses ({ output }) (current ai@^6.0.190 shape) 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.

Review Change Stack