diff --git a/apps/desktop/src/lib/inflight-turn-journal.test.ts b/apps/desktop/src/lib/inflight-turn-journal.test.ts index 552793a0e4..8041db1059 100644 --- a/apps/desktop/src/lib/inflight-turn-journal.test.ts +++ b/apps/desktop/src/lib/inflight-turn-journal.test.ts @@ -577,6 +577,9 @@ describe('recoverInFlightTurnJournal', () => { expect(result.applied).toBe(true) expect(result.messages.map(m => m.id)).toEqual(['db-u1', 'assistant-stream-1']) + // Idle resume: the assistant-tail append path must not resurrect the + // stream target either, or the journal entry re-folds on every open. + expect(result.streamId).toBeNull() const tail = result.messages.at(-1)! expect(tail.pending).toBe(false) expect(tail.parts[0]).toMatchObject({ type: 'tool-call' }) diff --git a/apps/desktop/src/lib/inflight-turn-journal.ts b/apps/desktop/src/lib/inflight-turn-journal.ts index 82397579b0..31a314bb05 100644 --- a/apps/desktop/src/lib/inflight-turn-journal.ts +++ b/apps/desktop/src/lib/inflight-turn-journal.ts @@ -797,7 +797,11 @@ export function mergeInFlightMessages( applied: true, caughtUp: false, messages: [...baseMessages, ...withoutBaseIds(tailAssistants, baseMessages)], - streamId, + // Same idle-resume rule as the other exit paths: only a running turn + // keeps the stream target alive. Carrying the stale streamId here kept + // the journal entry alive (persistInFlightTurnState only clears when + // streamId is null), so the same tail was folded again on every open. + streamId: options.keepPending ? streamId : null, turnStartedAt: null } }