diff --git a/apps/shared/src/gateway-events.ts b/apps/shared/src/gateway-events.ts index 65df723e68..e6d26aed34 100644 --- a/apps/shared/src/gateway-events.ts +++ b/apps/shared/src/gateway-events.ts @@ -64,7 +64,8 @@ export type SubagentStatus = 'completed' | 'error' | 'failed' | 'interrupted' | /** `tui_gateway/tool_progress.py::_progress_subagent` — every `subagent.*` frame. */ export interface SubagentEventPayload { api_calls?: number - cost_usd?: number + /** The child's own gateway session id — the key a watch window mirrors. */ + child_session_id?: string /** Batch (delegation) id this subagent belongs to — distinguishes * interleaved `[n/N]` progress from concurrent or nested fan-outs. */ delegation_id?: string @@ -74,7 +75,6 @@ export interface SubagentEventPayload { files_written?: string[] goal: string input_tokens?: number - iteration?: number model?: string output_tail?: { is_error?: boolean; preview?: string; tool?: string }[] output_tokens?: number @@ -115,7 +115,7 @@ export interface MessageCompletePayload { /** `status: "error"` — the failure message (`text` may be streamed output). */ error?: string error_surface?: ErrorSurface - failure_reason?: string + failure_reason?: string | null /** `status: "error"` — `text` is streamed partial output to keep, not the error string. */ partial?: boolean reasoning?: string @@ -142,6 +142,8 @@ export interface ToolStartPayload { /** Mirrored child tool rows carry a short preview instead of args. */ preview?: string tool_id: string + /** Not on the wire (`_on_tool_start` never sets it): the todo snapshot rides `tool.complete` / + * `todo.updated`. Kept because the TUI handler reads it and its fixtures exercise that path. */ todos?: unknown[] } @@ -149,7 +151,6 @@ export interface ToolStartPayload { export interface ToolCompletePayload { args?: Record duration_s?: number - error?: string inline_diff?: string name?: string /** Parsed JSON when the tool returned JSON, else the raw string. */ diff --git a/ui-tui/src/app/createGatewayEventHandler.ts b/ui-tui/src/app/createGatewayEventHandler.ts index 6be1717d92..98a46ce619 100644 --- a/ui-tui/src/app/createGatewayEventHandler.ts +++ b/ui-tui/src/app/createGatewayEventHandler.ts @@ -1239,7 +1239,6 @@ export function createGatewayEventHandler(ctx: GatewayEventHandlerContext): (ev: inlineDiffText, ev.payload.tool_id, ev.payload.name, - ev.payload.error, ev.payload.duration_s, resultText ) @@ -1247,7 +1246,6 @@ export function createGatewayEventHandler(ctx: GatewayEventHandlerContext): (ev: turnController.recordToolComplete( ev.payload.tool_id, ev.payload.name, - ev.payload.error, ev.payload.summary, ev.payload.duration_s, ev.payload.todos, diff --git a/ui-tui/src/app/turnController.ts b/ui-tui/src/app/turnController.ts index b31f7ac3e2..06d10fe701 100644 --- a/ui-tui/src/app/turnController.ts +++ b/ui-tui/src/app/turnController.ts @@ -796,7 +796,6 @@ class TurnController { recordToolComplete( toolId: string, fallbackName?: string, - error?: string, summary?: string, duration?: number, todos?: unknown, @@ -807,38 +806,26 @@ class TurnController { } this.recordTodos(todos) - const line = this.completeTool(toolId, fallbackName, error, summary, duration, resultText) + const line = this.completeTool(toolId, fallbackName, summary, duration, resultText) this.pendingSegmentTools = [...this.pendingSegmentTools, line] this.flushPendingToolsIntoLastSegment() this.publishToolState() } - recordInlineDiffToolComplete( - diffText: string, - toolId: string, - fallbackName?: string, - error?: string, - duration?: number, - resultText?: string - ) { + recordInlineDiffToolComplete(diffText: string, toolId: string, fallbackName?: string, duration?: number, resultText?: string) { if (this.interrupted) { return } this.flushStreamingSegment() - this.pushInlineDiffSegment(diffText, [this.completeTool(toolId, fallbackName, error, '', duration, resultText)]) + this.pushInlineDiffSegment(diffText, [this.completeTool(toolId, fallbackName, '', duration, resultText)]) this.publishToolState() } - private completeTool( - toolId: string, - fallbackName?: string, - error?: string, - summary?: string, - duration?: number, - resultText?: string - ) { + // `tool.complete` carries no error flag on the wire (tui_gateway/tool_progress.py::_on_tool_complete); + // a failed tool surfaces through its result text, so every trail line renders as non-error. + private completeTool(toolId: string, fallbackName?: string, summary?: string, duration?: number, resultText?: string) { const done = this.activeTools.find(tool => tool.id === toolId) const name = done?.name ?? fallbackName ?? 'tool' const label = toolTrailLabel(name) @@ -849,18 +836,12 @@ class TurnController { ? buildVerboseToolTrailLine( name, done?.context || '', - Boolean(error), + false, duration ?? fallbackDuration, done?.verboseArgs, - error || resultText || summary || '' - ) - : buildToolTrailLine( - name, - done?.context || '', - Boolean(error), - error || summary || '', - duration ?? fallbackDuration + resultText || summary || '' ) + : buildToolTrailLine(name, done?.context || '', false, summary || '', duration ?? fallbackDuration) this.activeTools = this.activeTools.filter(tool => tool.id !== toolId) @@ -1044,14 +1025,12 @@ class TurnController { const next: SubagentProgress = { ...base, apiCalls: p.api_calls ?? base.apiCalls, - costUsd: p.cost_usd ?? base.costUsd, delegationId: p.delegation_id ?? base.delegationId, depth: p.depth ?? base.depth, filesRead: p.files_read ?? base.filesRead, filesWritten: p.files_written ?? base.filesWritten, goal: p.goal || base.goal, inputTokens: p.input_tokens ?? base.inputTokens, - iteration: p.iteration ?? base.iteration, model: p.model ?? base.model, outputTail, outputTokens: p.output_tokens ?? base.outputTokens,