diff --git a/mobile/src/session/mobile-structured-session-timeline.test.ts b/mobile/src/session/mobile-structured-session-timeline.test.ts index 2f15cf264d8..25c0eea9169 100644 --- a/mobile/src/session/mobile-structured-session-timeline.test.ts +++ b/mobile/src/session/mobile-structured-session-timeline.test.ts @@ -91,6 +91,30 @@ describe('mobile structured session timeline', () => { expect(rows[0]).toMatchObject({ key: wal.itemId, outbox: { state: 'unconfirmed' } }) }) + it('keeps the device-local thumbnail on the adopted row while delivery is unconfirmed', () => { + const wal: AgentJournalRenderItem = { + itemId: agentJournalSubmissionKey(OUTBOX.clientMessageId), + revision: 1, + sequence: 1, + observedAt: 3, + body: OUTBOX.body + } + + const rows = buildMobileStructuredTimeline([wal], [OUTBOX]) + + expect(rows).toHaveLength(1) + expect(rows[0]).toMatchObject({ + key: wal.itemId, + outbox: { state: 'unconfirmed' }, + message: { + blocks: [ + { type: 'text', text: 'look' }, + { type: 'image-ref', url: 'file:///preview.png' } + ] + } + }) + }) + it('restores host paths and local previews when a queued send is edited', () => { expect(restoreMobileStructuredAttachments(OUTBOX)).toEqual([ { diff --git a/mobile/src/session/mobile-structured-session-timeline.ts b/mobile/src/session/mobile-structured-session-timeline.ts index dafe07e8c6a..77133294316 100644 --- a/mobile/src/session/mobile-structured-session-timeline.ts +++ b/mobile/src/session/mobile-structured-session-timeline.ts @@ -26,22 +26,29 @@ function isPendingPrompt(item: AgentJournalRenderItem): item is MobileStructured } function outboxMessage(entry: MobileStructuredOutboxEntry): NativeChatMessage { - let imageIndex = 0 return { id: entry.clientMessageId, role: 'user', timestamp: entry.queuedAt, source: 'transcript', - blocks: entry.body.blocks.map((block) => { - if (block.type !== 'image-ref') { - return block - } - const preview = entry.previewUris[imageIndex++] - return preview ? { ...block, url: preview, path: undefined } : block - }) + blocks: mobilePreviewBlocks(entry.body.blocks, entry.previewUris) } } +function mobilePreviewBlocks( + blocks: NativeChatMessage['blocks'], + previewUris: readonly string[] +): NativeChatMessage['blocks'] { + let imageIndex = 0 + return blocks.map((block) => { + if (block.type !== 'image-ref') { + return block + } + const preview = previewUris[imageIndex++] + return preview ? { ...block, url: preview, path: undefined } : block + }) +} + export function buildMobileStructuredTimeline( items: readonly AgentJournalRenderItem[], outbox: readonly MobileStructuredOutboxEntry[] @@ -67,7 +74,16 @@ export function buildMobileStructuredTimeline( if (entry) { seen.add(entry.clientMessageId) } - return [{ kind: 'message', key: message.id, message, ...(entry ? { outbox: entry } : {}) }] + return [ + { + kind: 'message', + key: message.id, + message: entry + ? { ...message, blocks: mobilePreviewBlocks(message.blocks, entry.previewUris) } + : message, + ...(entry ? { outbox: entry } : {}) + } + ] }) return [ ...canonical,