From 92ee2db92dd9cee1bf993475830e4cd1ff94e091 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Sun, 9 Aug 2026 20:18:40 -0700 Subject: [PATCH] fix(native-chat): preserve stopped turn identity --- .../native-chat-working-suppression.test.ts | 20 ++++++++++++++++--- .../native-chat-working-suppression.ts | 15 +++++++------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/renderer/src/components/native-chat/native-chat-working-suppression.test.ts b/src/renderer/src/components/native-chat/native-chat-working-suppression.test.ts index a37c0bfa01b..d49e89449aa 100644 --- a/src/renderer/src/components/native-chat/native-chat-working-suppression.test.ts +++ b/src/renderer/src/components/native-chat/native-chat-working-suppression.test.ts @@ -71,7 +71,7 @@ describe('native chat working suppression', () => { ).toBe(true) }) - it('stops suppressing when the conversation or user turn changes', () => { + it('stops suppressing when the conversation changes', () => { expect( shouldSuppressNativeChatWorking({ ...interruption, @@ -80,6 +80,20 @@ describe('native chat working suppression', () => { interruption }) ).toBe(false) + }) + + it('keeps suppression when an initially unknown session id hydrates', () => { + const sessionPendingInterruption = { ...interruption, sessionId: null } + expect( + shouldSuppressNativeChatWorking({ + ...interruption, + working: true, + interruption: sessionPendingInterruption + }) + ).toBe(true) + }) + + it('keeps suppressing when the interrupted epoch only gains its transcript id', () => { expect( shouldSuppressNativeChatWorking({ ...interruption, @@ -87,10 +101,10 @@ describe('native chat working suppression', () => { userTurnKey: 'turn-2', interruption }) - ).toBe(false) + ).toBe(true) }) - it('suppresses an interrupted turn when its working epoch is unavailable', () => { + it('falls back to user-turn identity when the working epoch is unavailable', () => { const noEpochInterruption = { ...interruption, workingEpoch: null } expect( shouldSuppressNativeChatWorking({ diff --git a/src/renderer/src/components/native-chat/native-chat-working-suppression.ts b/src/renderer/src/components/native-chat/native-chat-working-suppression.ts index 3a4451d9276..957a93523ac 100644 --- a/src/renderer/src/components/native-chat/native-chat-working-suppression.ts +++ b/src/renderer/src/components/native-chat/native-chat-working-suppression.ts @@ -33,16 +33,17 @@ export function shouldSuppressNativeChatWorking(args: { interruption === null || interruption.paneKey !== args.paneKey || interruption.agent !== args.agent || - interruption.sessionId !== args.sessionId || - interruption.userTurnKey !== args.userTurnKey + (interruption.sessionId != null && + args.sessionId != null && + interruption.sessionId !== args.sessionId) ) { return false } - return ( - interruption.workingEpoch == null || - args.workingEpoch == null || - args.workingEpoch <= interruption.workingEpoch - ) + if (interruption.workingEpoch != null && args.workingEpoch != null) { + // A known hook epoch outranks transcript ids replaced during optimistic catch-up. + return args.workingEpoch <= interruption.workingEpoch + } + return interruption.userTurnKey === args.userTurnKey } export function shouldShowNativeChatWorking(args: {