diff --git a/src/stores/chat/runtime-send-actions.ts b/src/stores/chat/runtime-send-actions.ts index b268786..51a13a4 100644 --- a/src/stores/chat/runtime-send-actions.ts +++ b/src/stores/chat/runtime-send-actions.ts @@ -223,8 +223,19 @@ export function createRuntimeSendActions(set: ChatSet, get: ChatGet): Pick | null = null; -const PHASE_COMPLETION_GRACE_MS = 5_000; -function clearPhaseCompletionTimer(): void { - if (_phaseCompletionTimer) { - clearTimeout(_phaseCompletionTimer); - _phaseCompletionTimer = null; - } -} - interface GatewayHealth { ok: boolean; error?: string; @@ -144,7 +130,6 @@ function handleGatewayNotification(notification: { method?: string; params?: Rec if (hasChatData) { // Any streaming data cancels the phase-completion grace timer — the // run is still producing output (or a new sub-run has started). - clearPhaseCompletionTimer(); const normalizedEvent: Record = { ...data, runId: p.runId ?? data.runId, @@ -166,7 +151,6 @@ function handleGatewayNotification(notification: { method?: string; params?: Rec const runId = p.runId ?? data.runId; const sessionKey = p.sessionKey ?? data.sessionKey; if (phase === 'started' && runId != null && sessionKey != null) { - clearPhaseCompletionTimer(); import('./chat') .then(({ useChatStore }) => { const state = useChatStore.getState(); @@ -206,29 +190,11 @@ function handleGatewayNotification(notification: { method?: string; params?: Rec if (matchesCurrentSession || matchesActiveRun) { maybeLoadHistory(state); } - if ((matchesCurrentSession || matchesActiveRun) && state.sending) { - // The Gateway sends phase "end" after each tool-execution round, - // not only when the entire conversation finishes. Delay the - // sending=false so a subsequent sub-run's "started" event or - // streaming delta can cancel it and keep the UI in the active state. - clearPhaseCompletionTimer(); - _phaseCompletionTimer = setTimeout(() => { - _phaseCompletionTimer = null; - const current = useChatStore.getState(); - // Only finalize if still in the same run and no new streaming data arrived. - if (current.sending && !current.streamingMessage) { - useChatStore.setState({ - sending: false, - activeRunId: null, - pendingFinal: false, - lastUserMessageAt: null, - error: null, - }); - // Reload history to get the final state. - maybeLoadHistory(current); - } - }, PHASE_COMPLETION_GRACE_MS); - } + // Note: we do NOT set sending=false here. The Gateway sends + // phase "end" after each tool-execution round (sub-run), not only + // when the entire conversation finishes. Run completion is + // determined by the chat.send RPC returning (runtime-send-actions) + // or a streaming "final" event with output (runtime-event-handlers). }) .catch(() => {}); }