diff --git a/tools/server/public/index.html.gz b/tools/server/public/index.html.gz index bc9124dd1c..1a69dde329 100644 Binary files a/tools/server/public/index.html.gz and b/tools/server/public/index.html.gz differ diff --git a/tools/server/webui/src/lib/stores/chat.svelte.ts b/tools/server/webui/src/lib/stores/chat.svelte.ts index 3af91be836..5f3812ed32 100644 --- a/tools/server/webui/src/lib/stores/chat.svelte.ts +++ b/tools/server/webui/src/lib/stores/chat.svelte.ts @@ -28,6 +28,7 @@ import { filterByLeafNodeId, findDescendantMessages, findLeafNode, + findMessageById, isAbortError } from '$lib/utils'; import { @@ -416,7 +417,7 @@ class ChatStore { if (!activeConv) return false; try { const allMessages = await conversationsStore.getConversationMessages(activeConv.id); - const systemMessage = allMessages.find((m) => m.id === messageId); + const systemMessage = findMessageById(allMessages, messageId); if (!systemMessage || systemMessage.role !== MessageRole.SYSTEM) return false; const rootMessage = allMessages.find((m) => m.type === 'root' && m.parent === null); if (!rootMessage) return false; @@ -878,7 +879,7 @@ class ChatStore { const msg = conversationsStore.activeMessages[idx]; if (msg.role !== MessageRole.ASSISTANT) return; const allMessages = await conversationsStore.getConversationMessages(activeConv.id); - const parentMessage = allMessages.find((m) => m.id === msg.parent); + const parentMessage = findMessageById(allMessages, msg.parent); if (!parentMessage) return; this.setChatLoading(activeConv.id, true); this.clearChatStreaming(activeConv.id); @@ -928,7 +929,7 @@ class ChatStore { if (!activeConv) return { totalCount: 0, userMessages: 0, assistantMessages: 0, messageTypes: [] }; const allMessages = await conversationsStore.getConversationMessages(activeConv.id); - const messageToDelete = allMessages.find((m) => m.id === messageId); + const messageToDelete = findMessageById(allMessages, messageId); // For system messages, don't count descendants as they will be preserved (reparented to root) if (messageToDelete?.role === MessageRole.SYSTEM) { @@ -975,7 +976,7 @@ class ChatStore { if (!activeConv) return; try { const allMessages = await conversationsStore.getConversationMessages(activeConv.id); - const messageToDelete = allMessages.find((m) => m.id === messageId); + const messageToDelete = findMessageById(allMessages, messageId); if (!messageToDelete) return; @@ -1024,7 +1025,7 @@ class ChatStore { this.clearChatStreaming(activeConv.id); const allMessages = await conversationsStore.getConversationMessages(activeConv.id); - const dbMessage = allMessages.find((m) => m.id === messageId); + const dbMessage = findMessageById(allMessages, messageId); if (!dbMessage) { this.setChatLoading(activeConv.id, false); @@ -1280,7 +1281,10 @@ class ChatStore { let messageIdForResponse: string; - if (msg.children.length === 0) { + const dbMsg = findMessageById(allMessages, msg.id); + const hasChildren = dbMsg ? dbMsg.children.length > 0 : msg.children.length > 0; + + if (!hasChildren) { // No responses after this message — update in place instead of branching const updates: Partial = { content: newContent, diff --git a/tools/server/webui/src/lib/utils/branching.ts b/tools/server/webui/src/lib/utils/branching.ts index e60fb206f7..4e117b3c2a 100644 --- a/tools/server/webui/src/lib/utils/branching.ts +++ b/tools/server/webui/src/lib/utils/branching.ts @@ -17,6 +17,17 @@ import { MessageRole } from '$lib/enums'; +/** + * Finds a message by its ID in the given messages array. + */ +export function findMessageById( + messages: readonly DatabaseMessage[], + id: string | null | undefined +): DatabaseMessage | undefined { + if (!id) return undefined; + return messages.find((m) => m.id === id); +} + /** * Filters messages to get the conversation path from root to a specific leaf node. * If the leafNodeId doesn't exist, returns the path with the latest timestamp. diff --git a/tools/server/webui/src/lib/utils/index.ts b/tools/server/webui/src/lib/utils/index.ts index e3bf1b9f5f..455d4f2c3f 100644 --- a/tools/server/webui/src/lib/utils/index.ts +++ b/tools/server/webui/src/lib/utils/index.ts @@ -22,6 +22,7 @@ export { default as autoResizeTextarea } from './autoresize-textarea'; // Branching utilities export { filterByLeafNodeId, + findMessageById, findLeafNode, findDescendantMessages, getMessageSiblings,