From ea691eaea357af66a65b4f458a6ca79407eb3dff Mon Sep 17 00:00:00 2001 From: Benjamin Lu Date: Fri, 13 Mar 2026 11:54:47 -0700 Subject: [PATCH] fix: clear stale active job after reconnect --- src/stores/executionStore.test.ts | 39 +++++++++++++++++++++++++++++++ src/stores/executionStore.ts | 14 ++++++++++- src/stores/queueStore.ts | 2 +- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/stores/executionStore.test.ts b/src/stores/executionStore.test.ts index f006b0aadd..8e80588cf9 100644 --- a/src/stores/executionStore.test.ts +++ b/src/stores/executionStore.test.ts @@ -491,6 +491,45 @@ describe('useExecutionStore - clearTrackedJob', () => { expect(store.initializingJobIds).toEqual(new Set(['job-2'])) expect(store._executingNodeProgress).toBeNull() }) + + it('clears a stale active job when a different prompt completes', () => { + const terminalJobState = { + value: 3, + max: 10, + state: 'running' as const, + node_id: 'node-2', + prompt_id: 'job-2' + } + + store.activeJobId = 'job-1' + store.queuedJobs = { + 'job-1': { nodes: {} }, + 'job-2': { nodes: {} } + } + store.nodeProgressStates = { + 'node-2': terminalJobState + } + store.nodeProgressStatesByJob = { + 'job-1': {}, + 'job-2': { 'node-2': terminalJobState } + } + store.initializingJobIds = new Set(['job-1', 'job-2']) + store.bindExecutionEvents() + + const handler = apiEventHandlers.get('execution_success') + if (!handler) throw new Error('execution_success handler not bound') + handler( + new CustomEvent('execution_success', { + detail: { prompt_id: 'job-2' } + }) + ) + + expect(store.activeJobId).toBeNull() + expect(store.queuedJobs).toEqual({}) + expect(store.nodeProgressStates).toEqual({}) + expect(store.nodeProgressStatesByJob).toEqual({}) + expect(store.initializingJobIds).toEqual(new Set()) + }) }) describe('useExecutionErrorStore - Node Error Lookups', () => { diff --git a/src/stores/executionStore.ts b/src/stores/executionStore.ts index 89e36066d6..7df79388f6 100644 --- a/src/stores/executionStore.ts +++ b/src/stores/executionStore.ts @@ -544,10 +544,22 @@ export const useExecutionStore = defineStore('execution', () => { return } - removeTrackedJobState(jobId, { + const normalizedJobId = String(jobId) + const staleActiveJobId = + activeJobId.value && activeJobId.value !== normalizedJobId + ? activeJobId.value + : null + + removeTrackedJobState(normalizedJobId, { clearAllNodeProgressStates: true, clearPromptError: true }) + + if (staleActiveJobId) { + removeTrackedJobState(staleActiveJobId, { + clearPromptError: true + }) + } } /** diff --git a/src/stores/queueStore.ts b/src/stores/queueStore.ts index ec3675911b..7c68ea926b 100644 --- a/src/stores/queueStore.ts +++ b/src/stores/queueStore.ts @@ -585,7 +585,7 @@ export const useQueueStore = defineStore('queue', () => { const activeJobId = executionStore.activeJobId const missedTerminalExecution = activeJobId !== null && - !activeJobIds.has(String(activeJobId)) && + !activeJobIds.has(activeJobId) && nextHistoryTasks.some((task) => task.jobId === activeJobId) if (missedTerminalExecution) {