diff --git a/desktop/src/features/agents/ui/AgentSessionTranscriptList.tsx b/desktop/src/features/agents/ui/AgentSessionTranscriptList.tsx index 29bfd7dbab..f9f33c2e53 100644 --- a/desktop/src/features/agents/ui/AgentSessionTranscriptList.tsx +++ b/desktop/src/features/agents/ui/AgentSessionTranscriptList.tsx @@ -153,7 +153,7 @@ export function AgentSessionTranscriptList({ ); const displayBlocks = React.useMemo( - () => buildTranscriptDisplayBlocks(items, latestLiveSessionId), + () => buildTranscriptDisplayBlocks(items, latestLiveSessionId).reverse(), [items, latestLiveSessionId], ); // Derive the same block keys the DOM renders as `data-message-id` so diff --git a/desktop/src/features/agents/ui/RawEventRail.tsx b/desktop/src/features/agents/ui/RawEventRail.tsx index 2841251627..267a19753c 100644 --- a/desktop/src/features/agents/ui/RawEventRail.tsx +++ b/desktop/src/features/agents/ui/RawEventRail.tsx @@ -1,3 +1,4 @@ +import * as React from "react"; import type { ObserverEvent } from "./agentSessionTypes"; import { describeRawEvent } from "./agentSessionTranscript"; import { observerEventScrollId } from "./agentSessionPanelLayout"; @@ -6,17 +7,18 @@ import { useTranscriptTimestampsEnabled } from "./transcriptTimestampPreference" export function RawEventRail({ events }: { events: ObserverEvent[] }) { const showTimestamps = useTranscriptTimestampsEnabled(); + const displayEvents = React.useMemo(() => [...events].reverse(), [events]); return (
- {events.length === 0 ? ( + {displayEvents.length === 0 ? (

No raw events yet.

) : (
- {events.map((event) => ( + {displayEvents.map((event) => (
{ "block key identities must be identical before and after session_resolved seals the open batch (order may differ)", ); }); + +test("deriveTranscriptBlockIds returns block keys in reverse chronological order (newest first)", () => { + const events = [ + { + seq: 1, + timestamp: "2026-07-08T00:00:01.000Z", + kind: "acp_read", + agentIndex: 0, + channelId: "chan-1", + sessionId: "sess-1", + turnId: "turn-1", + payload: { + method: "session/update", + params: { + sessionId: "sess-1", + update: { + sessionUpdate: "tool_call_update", + toolCallId: "call-1", + toolName: "tool-1", + status: "completed", + args: "{}", + result: "ok", + }, + }, + }, + }, + { + seq: 2, + timestamp: "2026-07-08T00:00:02.000Z", + kind: "acp_read", + agentIndex: 0, + channelId: "chan-1", + sessionId: "sess-1", + turnId: "turn-2", + payload: { + method: "session/update", + params: { + sessionId: "sess-1", + update: { + sessionUpdate: "tool_call_update", + toolCallId: "call-2", + toolName: "tool-2", + status: "completed", + args: "{}", + result: "ok", + }, + }, + }, + }, + ]; + + const ids = deriveTranscriptBlockIds(events); + // Turn 2 (newest) must come before Turn 1 (oldest) in reverse activity order + assert.deepEqual(ids, ["turn:turn-2", "turn:turn-1"]); +}); diff --git a/desktop/src/features/agents/ui/agentSessionTranscriptGrouping.ts b/desktop/src/features/agents/ui/agentSessionTranscriptGrouping.ts index 795f1fcd16..a191696c18 100644 --- a/desktop/src/features/agents/ui/agentSessionTranscriptGrouping.ts +++ b/desktop/src/features/agents/ui/agentSessionTranscriptGrouping.ts @@ -780,7 +780,7 @@ export function deriveTranscriptBlockIds( ): string[] { const items = buildTranscriptState(events).items; const blocks = buildTranscriptDisplayBlocks(items); - return blocks.map(getDisplayBlockKey); + return blocks.map(getDisplayBlockKey).reverse(); } /** Human-readable labels for a collapsed turn setup row. */