diff --git a/apps/web/src/components/chat/MessagesTimeline.logic.test.ts b/apps/web/src/components/chat/MessagesTimeline.logic.test.ts index 245a745a898b..e64d9dcf6621 100644 --- a/apps/web/src/components/chat/MessagesTimeline.logic.test.ts +++ b/apps/web/src/components/chat/MessagesTimeline.logic.test.ts @@ -3640,6 +3640,47 @@ describe("v2 run and attempt history", () => { expect(rows.map((row) => row.id)).toEqual(["work-entry", "interrupt-result"]); expect(rows.some((row) => row.kind === "turn-fold")).toBe(false); + + // The command the interrupt cut short stays visible with its outcome. + const stoppedRows = deriveMessagesTimelineRows({ + timelineEntries: [ + { + id: "stopped-command-entry", + kind: "work", + createdAt: "2026-01-01T00:00:01Z", + entry: { + id: "stopped-command", + createdAt: "2026-01-01T00:00:01Z", + runId, + label: "Ran command", + tone: "tool", + itemType: "command_execution", + command: "/bin/bash -lc 'sleep 90 && echo slept'", + toolLifecycleStatus: "stopped", + }, + }, + { + id: "interrupt-result", + kind: "event", + createdAt: "2026-01-01T00:00:03Z", + projectedItem: interruptEvent("run_interrupt_result") as never, + }, + ], + latestRun: { + runId, + status: "interrupted", + startedAt: "2026-01-01T00:00:00Z", + completedAt: "2026-01-01T00:00:03Z", + }, + isWorking: false, + turnDiffSummaries: [], + supportsConversationRollback: false, + }); + expect(stoppedRows.map((row) => row.id)).toEqual(["stopped-command-entry", "interrupt-result"]); + expect(stoppedRows[0]).toMatchObject({ + kind: "work", + displayLabel: "sleep 90 && echo slept", + }); }); }); diff --git a/apps/web/src/components/chat/MessagesTimeline.logic.ts b/apps/web/src/components/chat/MessagesTimeline.logic.ts index d079a0501d2c..b468a50b36f7 100644 --- a/apps/web/src/components/chat/MessagesTimeline.logic.ts +++ b/apps/web/src/components/chat/MessagesTimeline.logic.ts @@ -151,6 +151,8 @@ export function workEntryIsVisibleInGroup( (expandedToolGroupEntry && (entry.toolLifecycleStatus === "inProgress" || entry.sourceActivityKind === "task.progress")) || + // A stopped call is an outcome ("Stopped sleep"), not an empty row. + entry.toolLifecycleStatus === "stopped" || !workEntryIndicatesToolNeutralStatus(entry) ); }