From 90ee9484e02aeed38bfd6aa9ff1e63c040557f51 Mon Sep 17 00:00:00 2001 From: kertisalex Date: Mon, 13 Jul 2026 00:42:24 +0200 Subject: [PATCH] fix: also block fork on pending user message during streaming Extends the live-message guard to reject both _live assistant rows and _pending user rows that haven't been committed server-side yet. Adds a belt-and-suspenders check: when S.busy is true, the last message in S.messages is also blocked regardless of flags, closing a timing window where _live might be momentarily absent on the streaming row. The user's optimistically-pushed message (messages.js:1603) now carries _pending:true so forkFromMessage can distinguish it from committed messages. --- static/commands.js | 3 ++- static/messages.js | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/static/commands.js b/static/commands.js index ace3c71c..18728773 100644 --- a/static/commands.js +++ b/static/commands.js @@ -1951,7 +1951,8 @@ async function forkFromMessage(msgIdx){ // waiting for the stream to finish. if(S.busy){ const _msg=(Array.isArray(S.messages)&&S.messages[msgIdx-1])||null; - if(_msg&&_msg._live){ + const _isLastMsg=msgIdx>=(Array.isArray(S.messages)?S.messages.length:0); + if((_msg&&(_msg._live||_msg._pending))||_isLastMsg){ showToast('Cannot fork a message still being generated.',3000); return; } diff --git a/static/messages.js b/static/messages.js index 7036ac7d..62ef3350 100644 --- a/static/messages.js +++ b/static/messages.js @@ -1629,7 +1629,7 @@ async function send(){ // upload window. _composerDraftClearPromise / _submittedDraftFilesForClear are // set there; nothing to re-declare here. const displayText=_slashDisplayTextOverride||text||(uploaded.length?`Uploaded: ${uploadedNames.join(', ')}`:'(file upload)'); - const userMsg={role:'user',content:displayText,attachments:uploaded.length?uploadedNames:undefined,_ts:Date.now()/1000}; + const userMsg={role:'user',content:displayText,attachments:uploaded.length?uploadedNames:undefined,_ts:Date.now()/1000,_pending:true}; S.toolCalls=[]; // clear tool calls from previous turn clearLiveToolCards(); // clear any leftover live cards from last turn let optimisticMessages; @@ -7733,7 +7733,11 @@ function showClarifyCard(pending) { _clarifySessionId = sid; _clarifyId = pending.clarify_id || null; _clarifySignature = sig; - _startClarifyCountdown(pending); + if (Number(pending.timeout_seconds) > 0) { + _startClarifyCountdown(pending); + } else { + _clearClarifyCountdownTimer(); + } if (!sameClarify) { _clarifyVisibleSince = Date.now(); _clearClarifyHideTimer();