diff --git a/src/main/native-chat/transcript-line-decoders-codex.ts b/src/main/native-chat/transcript-line-decoders-codex.ts index 2a5dfc4f5b1..78e29d23d6b 100644 --- a/src/main/native-chat/transcript-line-decoders-codex.ts +++ b/src/main/native-chat/transcript-line-decoders-codex.ts @@ -3,6 +3,7 @@ import { type NativeChatBlock, type NativeChatMessage } from '../../shared/native-chat-types' +import { NATIVE_CHAT_NOTICE_COPY } from '../../shared/native-chat-notice' import { asRecord, extractString, @@ -132,6 +133,10 @@ function codexEventMessage( source: 'transcript' } } + // Legacy rollouts persist this event; paginated rollouts persist a ContextCompaction item instead. + if (payload.type === 'context_compacted') { + return codexCompactionMarker(id, timestamp) + } if (payload.type === 'item_completed') { return codexCompletedTurnItem(payload, id, timestamp) } @@ -160,6 +165,9 @@ function codexCompletedTurnItem( return null } const id = extractString(item.id) ?? fallbackId + if (item.type === 'ContextCompaction') { + return codexCompactionMarker(id, timestamp) + } const blocks = codexTurnItemBlocks(item.content) if (blocks.length === 0) { return null @@ -173,6 +181,18 @@ function codexCompletedTurnItem( return null } +function codexCompactionMarker(id: string, timestamp: number | null): NativeChatMessage { + return { + id, + role: 'system', + blocks: [ + { type: 'text', text: NATIVE_CHAT_NOTICE_COPY.compaction, presentation: 'compaction' } + ], + timestamp, + source: 'transcript' + } +} + function codexTurnItemBlocks(content: unknown): NativeChatBlock[] { if (!Array.isArray(content)) { return [] diff --git a/src/main/native-chat/transcript-reader-codex-history-mode.test.ts b/src/main/native-chat/transcript-reader-codex-history-mode.test.ts index afb7e9325c2..36e5748d6e7 100644 --- a/src/main/native-chat/transcript-reader-codex-history-mode.test.ts +++ b/src/main/native-chat/transcript-reader-codex-history-mode.test.ts @@ -134,6 +134,7 @@ describe('Codex transcript history modes', () => { }, '2026-08-09T10:00:01.000Z' ), + completedItem({ type: 'ContextCompaction', id: 'compaction-1' }, '2026-08-09T10:00:01.500Z'), { type: 'response_item', payload: { @@ -172,6 +173,12 @@ describe('Codex transcript history modes', () => { { type: 'image-ref', path: '/tmp/reference.png' } ] }, + { + id: 'compaction-1', + role: 'system', + timestamp: Date.parse('2026-08-09T10:00:01.500Z'), + blocks: [{ type: 'text', text: 'Context compacted', presentation: 'compaction' }] + }, { id: 'assistant-1', role: 'assistant', @@ -179,7 +186,6 @@ describe('Codex transcript history modes', () => { } ] }) - expect('messages' in result && result.messages).toHaveLength(2) expect(tail).toMatchObject({ messages: 'messages' in result ? result.messages : [] }) }) @@ -194,6 +200,8 @@ describe('Codex transcript history modes', () => { } }, { type: 'event_msg', payload: { type: 'user_message', message: 'Prompt' } }, + { type: 'compacted', payload: { message: 'summary', replacement_history: [] } }, + { type: 'event_msg', payload: { type: 'context_compacted' } }, { type: 'event_msg', payload: { type: 'agent_message', message: 'Response' } }, { type: 'response_item', @@ -210,6 +218,10 @@ describe('Codex transcript history modes', () => { expect(result).toMatchObject({ messages: [ { role: 'user', blocks: [{ type: 'text', text: 'Prompt' }] }, + { + role: 'system', + blocks: [{ type: 'text', text: 'Context compacted', presentation: 'compaction' }] + }, { role: 'assistant', blocks: [{ type: 'text', text: 'Response' }] } ] })