authorgravatar for maria@kuuro.netmaria <maria@kuuro.net> 2026-09-04 14:26:31-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-04 14:26:31-04:00
logcfc9bf34156ddcc4a98b7f5c67193adb5aedce06
tree969c241f03318f1c87fdc6525f33e453c05205e4
parentc8f77e0d441264efb0acfac312e852c81ae3da83
signature Signed by PGP key B5690EEEBB952194

fix(web): fold single trailing activity (#9739)

Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>

3 files changed, 17 insertions(+), 8 deletions(-)

apps/web/src/components/chat/MessagesTimeline.logic.test.ts+9-4
...@@ -1170,11 +1170,10 @@ describe("deriveMessagesTimelineRows", () => {...@@ -1170,11 +1170,10 @@ describe("deriveMessagesTimelineRows", () => {
1170 })),1170 })),
1171 ];1171 ];
11721172
1173 const rows = deriveMessagesTimelineRows({1173 const input = {
1174 timelineEntries,
1175 latestTurn: {1174 latestTurn: {
1176 turnId,1175 turnId,
1177 state: "error",1176 state: "error" as const,
1178 startedAt: "2026-01-01T00:00:00Z",1177 startedAt: "2026-01-01T00:00:00Z",
1179 completedAt: "2026-01-01T00:00:10Z",1178 completedAt: "2026-01-01T00:00:10Z",
1180 },1179 },
...@@ -1182,7 +1181,8 @@ describe("deriveMessagesTimelineRows", () => {...@@ -1182,7 +1181,8 @@ describe("deriveMessagesTimelineRows", () => {
1182 activeTurnStartedAt: null,1181 activeTurnStartedAt: null,
1183 turnDiffSummaryByAssistantMessageId: new Map(),1182 turnDiffSummaryByAssistantMessageId: new Map(),
1184 revertTurnCountByUserMessageId: new Map(),1183 revertTurnCountByUserMessageId: new Map(),
1185 });1184 };
1185 const rows = deriveMessagesTimelineRows({ ...input, timelineEntries });
11861186
1187 expect(rows.map((row) => row.id)).toEqual([1187 expect(rows.map((row) => row.id)).toEqual([
1188 "turn-fold:turn-1",1188 "turn-fold:turn-1",
...@@ -1205,6 +1205,11 @@ describe("deriveMessagesTimelineRows", () => {...@@ -1205,6 +1205,11 @@ describe("deriveMessagesTimelineRows", () => {
1205 showAssistantMeta: false,1205 showAssistantMeta: false,
1206 showAssistantCopyButton: false,1206 showAssistantCopyButton: false,
1207 });1207 });
1208 expect(
1209 deriveMessagesTimelineRows({ ...input, timelineEntries: timelineEntries.slice(0, 3) }).map(
1210 (row) => row.id,
1211 ),
1212 ).toEqual(["turn-fold:turn-1", "assistant-final-entry"]);
1208 });1213 });
12091214
1210 it("folds all assistant messages before the terminal message", () => {1215 it("folds all assistant messages before the terminal message", () => {
apps/web/src/components/chat/MessagesTimeline.logic.ts+7-3
...@@ -542,8 +542,8 @@ function workEntryIsActiveTurnActivity(entry: WorkLogEntry): boolean {...@@ -542,8 +542,8 @@ function workEntryIsActiveTurnActivity(entry: WorkLogEntry): boolean {
542542
543/**543/**
544 * Settled turns fold activity before their terminal assistant message behind544 * Settled turns fold activity before their terminal assistant message behind
545 * a "Worked for ..." row. Work that lands after that message stays visible so545 * a "Worked for ..." row. A single ordinary activity after that message joins
546 * failed or interrupted turns do not hide their trailing tool-call summary.546 * the fold, while larger groups and failures stay visible as a trailing summary.
547 */547 */
548function deriveTurnFolds(input: {548function deriveTurnFolds(input: {
549 timelineEntries: ReadonlyArray<TimelineEntry>;549 timelineEntries: ReadonlyArray<TimelineEntry>;
...@@ -623,7 +623,11 @@ function deriveTurnFolds(input: {...@@ -623,7 +623,11 @@ function deriveTurnFolds(input: {
623 }623 }
624 const isCompaction =624 const isCompaction =
625 entry.kind === "work" && entry.entry.sourceActivityKind === "context-compaction";625 entry.kind === "work" && entry.entry.sourceActivityKind === "context-compaction";
626 if (!isCompaction && index > terminalEntryIndex) {626 const isSingleTrailingActivity =
627 group.entries.length === terminalEntryIndex + 2 &&
628 entry.kind === "work" &&
629 !workEntryDisplayIndicatesToolFailure(entry.entry);
630 if (!isCompaction && index > terminalEntryIndex && !isSingleTrailingActivity) {
627 continue;631 continue;
628 }632 }
629 // Agent-spawn CTA rows never fold: workflows outlive their launching633 // Agent-spawn CTA rows never fold: workflows outlive their launching
apps/web/src/components/chat/MessagesTimeline.test.tsx+1-1
...@@ -1135,7 +1135,7 @@ describe("MessagesTimeline", () => {...@@ -1135,7 +1135,7 @@ describe("MessagesTimeline", () => {
1135 label: "Ran command",1135 label: "Ran command",
1136 tone: "tool",1136 tone: "tool",
1137 itemType: "command_execution",1137 itemType: "command_execution",
1138 toolLifecycleStatus: "completed",1138 toolLifecycleStatus: "failed",
1139 },1139 },
1140 },1140 },
1141 ]}1141 ]}