diff --git a/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts b/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts index 06dd074a85..085680d69d 100644 --- a/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts +++ b/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts @@ -1801,10 +1801,16 @@ export class AIChatManager { // fall back on — the raw-app inline prompt would lose what the user // typed outright. Not `restoreToInput`, whose no-composer fallback is // the very queue being refused. - const restored = this.aiChatInput?.prependText(text, images, files) === true - if (restored) this.#restoreDomContext(context, true) + const composer = this.aiChatInput + if (composer) { + // `prependText` answers "did this land on top of a draft already being + // written", not "did it land at all" — it always restores. Its return + // is what tells #restoreDomContext whether to keep the existing chips + // as well as the restored ones. + this.#restoreDomContext(context, composer.prependText(text, images, files)) + } sendUserToast( - restored + composer ? 'This session is running in another tab. Your prompt is waiting in the composer.' : 'This session is running in another tab. Try again when it finishes.', true diff --git a/frontend/src/lib/components/sessions/sessionRunOwner.svelte.ts b/frontend/src/lib/components/sessions/sessionRunOwner.svelte.ts index 9e996622fa..37cdb20ac6 100644 --- a/frontend/src/lib/components/sessions/sessionRunOwner.svelte.ts +++ b/frontend/src/lib/components/sessions/sessionRunOwner.svelte.ts @@ -98,7 +98,14 @@ export function noteDriverAlive(sessionId: string, planMode: boolean): void { * the truthful position rather than merely the convenient one. */ export function noteRemoteTurnEnded(sessionId: string): void { if (runPosition(sessionId).state !== 'watching') return - positions.set(sessionId, canCompleteCatchUp() ? { state: 'catchingUp' } : { state: 'idle' }) + // Deleted rather than set to idle: a missing entry already reads as idle, and + // the tab this branch exists for has no runtime, so nothing in it would ever + // call clearRunPosition to take the entry back out again. + if (!canCompleteCatchUp()) { + positions.delete(sessionId) + return + } + positions.set(sessionId, { state: 'catchingUp' }) } /** The re-read finished: this tab's transcript and history are one conversation