From cef983eed4a67321240811635debdc5d67b9bc45 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Thu, 4 Jun 2026 01:41:59 +0200 Subject: [PATCH] fix(chat): don't let chatCompletedHandler wipe taskIds from a concurrent send chatCompletedHandler runs fire-and-forget and suspends at the getChatList await, then unconditionally set taskIds = null. A sendMessage that resolved during that window had its freshly registered task ids erased, so the stop button vanished and in-flight background tasks (title gen, follow-ups, tags) became uncancellable. Snapshot taskIds before the await and only clear it if no concurrent write happened since. For that reference check to be reliable, register task ids as a new array instead of pushing in place; the in-place push also never triggered Svelte reactivity, so the stop UI could miss appended ids. Co-Authored-By: Claude Opus 4.8 (1M context) Fixes #25217 --- src/lib/components/chat/Chat.svelte | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 69652dbe41..a3467d3683 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -1556,11 +1556,15 @@ const chatCompletedHandler = async (_chatId, modelId, responseMessageId, messages) => { // Backend handles outlet filters and persistence inline. // Just refresh the sidebar chat list. + const capturedTaskIds = taskIds; if ($chatId == _chatId && !$temporaryChatEnabled) { currentChatPage.set(1); await chats.set(await getChatList(localStorage.token, $currentChatPage)); } - taskIds = null; + // Don't clobber task ids a concurrent sendMessage registered while we were suspended. + if (taskIds === capturedTaskIds) { + taskIds = null; + } }; const chatActionHandler = async (_chatId, actionId, modelId, responseMessageId, event = null) => { @@ -2529,11 +2533,8 @@ } else { // Backend returns task_ids (multi-model) or task_id (single model) const newTaskIds = res.task_ids ?? (res.task_id ? [res.task_id] : []); - if (taskIds) { - taskIds.push(...newTaskIds); - } else { - taskIds = newTaskIds; - } + // New array each write so the snapshot guard in chatCompletedHandler can detect it. + taskIds = [...(taskIds ?? []), ...newTaskIds]; // Backend returns chat_id for new chats — set store + URL. // Only update if the user hasn't navigated to a different chat