fix: queue drain survives navigation away from a streaming conversation
Previously the queue drain guard (currentConversation.id === convId) meant that if the user navigated to ChatView while a workspace stream was running, the workspace's queued messages were silently abandoned — they sat in localStorage indefinitely with no code path to resume them. - Extract _tryDrainQueue(convId) with the same guard logic - Call it at stream-end (replaces the inline block) - Call it in fetchConversation after _loadQueue, so returning to a conversation with orphaned queue messages drains them automatically - Order is now preserved: messages drain in the order they were queued, even across navigation events Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+28
-17
@@ -109,6 +109,28 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Drain the next queued message for a conversation, if conditions are met.
|
||||
// Called both at stream-end and after fetchConversation, so orphaned queue
|
||||
// messages (e.g. from a navigation away mid-stream) are picked up on return.
|
||||
function _tryDrainQueue(convId: number) {
|
||||
const queue = convQueues.value[convId];
|
||||
if (!queue?.length) return;
|
||||
if (isStreamingConv(convId)) return; // stream-end will drain naturally
|
||||
if (currentConversation.value?.id !== convId) return; // not our conversation
|
||||
const next = queue.shift()!;
|
||||
_saveQueue(convId);
|
||||
setTimeout(() => sendMessage(
|
||||
next.content,
|
||||
next.contextNoteId,
|
||||
next.includeNoteIds,
|
||||
next.think,
|
||||
next.contextNoteTitle,
|
||||
next.excludeNoteIds,
|
||||
next.ragProjectId,
|
||||
next.workspaceProjectId,
|
||||
), 0);
|
||||
}
|
||||
|
||||
function clearQueue() {
|
||||
const id = currentConversation.value?.id;
|
||||
if (id) {
|
||||
@@ -158,6 +180,9 @@ export const useChatStore = defineStore("chat", () => {
|
||||
`/api/chat/conversations/${id}`
|
||||
);
|
||||
_loadQueue(id);
|
||||
// Drain any messages that were queued but never sent because the user
|
||||
// navigated away before the previous stream finished.
|
||||
_tryDrainQueue(id);
|
||||
} catch (e) {
|
||||
useToastStore().show("Failed to load conversation", "error");
|
||||
throw e;
|
||||
@@ -431,23 +456,9 @@ export const useChatStore = defineStore("chat", () => {
|
||||
s.pendingTool = null;
|
||||
}
|
||||
|
||||
// Process next queued message, if any.
|
||||
// Use setTimeout so this frame resolves before the next send begins.
|
||||
const queue = convQueues.value[convId];
|
||||
if (queue?.length && currentConversation.value?.id === convId) {
|
||||
const next = queue.shift()!;
|
||||
_saveQueue(convId);
|
||||
setTimeout(() => sendMessage(
|
||||
next.content,
|
||||
next.contextNoteId,
|
||||
next.includeNoteIds,
|
||||
next.think,
|
||||
next.contextNoteTitle,
|
||||
next.excludeNoteIds,
|
||||
next.ragProjectId,
|
||||
next.workspaceProjectId,
|
||||
), 0);
|
||||
}
|
||||
// Process next queued message if this is still the active conversation.
|
||||
// If the user has navigated away, _tryDrainQueue will fire on fetchConversation.
|
||||
_tryDrainQueue(convId);
|
||||
}
|
||||
|
||||
async function reconnectIfGenerating(convId: number): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user