diff --git a/tools/server/public/index.html.gz b/tools/server/public/index.html.gz index a2f084f3bb..3a62b93364 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/components/app/chat/ChatMessages/ChatMessageAssistant.svelte b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageAssistant.svelte index 013b77cbbe..ad3ffa3792 100644 --- a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageAssistant.svelte +++ b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageAssistant.svelte @@ -3,12 +3,14 @@ import { useProcessingState } from '$lib/hooks/use-processing-state.svelte'; import { isLoading } from '$lib/stores/chat.svelte'; import { fade } from 'svelte/transition'; - import { Check, X } from '@lucide/svelte'; + import { Check, Copy, Package, X } from '@lucide/svelte'; import { Button } from '$lib/components/ui/button'; import { Checkbox } from '$lib/components/ui/checkbox'; import { INPUT_CLASSES } from '$lib/constants/input-classes'; import ChatMessageActions from './ChatMessageActions.svelte'; import Label from '$lib/components/ui/label/label.svelte'; + import { config } from '$lib/stores/settings.svelte'; + import { copyToClipboard } from '$lib/utils/copy'; interface Props { class?: string; @@ -136,6 +138,23 @@ {/if} + {#if config().showModelInfo && message.model} + + + + Model used: + + + + {/if} + {#if message.timestamp && !isEditing} {@const IconComponent = icon} diff --git a/tools/server/webui/src/lib/constants/settings-config.ts b/tools/server/webui/src/lib/constants/settings-config.ts index 89eff7bdbd..5cb22f4c34 100644 --- a/tools/server/webui/src/lib/constants/settings-config.ts +++ b/tools/server/webui/src/lib/constants/settings-config.ts @@ -10,6 +10,7 @@ export const SETTING_CONFIG_DEFAULT: Record = askForTitleConfirmation: false, pasteLongTextToFileLen: 2500, pdfAsImage: false, + showModelInfo: false, // make sure these default values are in sync with `common.h` samplers: 'top_k;typ_p;top_p;min_p;temperature', temperature: 0.8, @@ -79,6 +80,7 @@ export const SETTING_CONFIG_INFO: Record = { askForTitleConfirmation: 'Ask for confirmation before automatically changing conversation title when editing the first message.', pdfAsImage: 'Parse PDF as image instead of text (requires vision-capable model).', + showModelInfo: 'Display the model name used to generate each message below the message content.', pyInterpreterEnabled: 'Enable Python interpreter using Pyodide. Allows running Python code in markdown code blocks.' }; diff --git a/tools/server/webui/src/lib/stores/chat.svelte.ts b/tools/server/webui/src/lib/stores/chat.svelte.ts index d3f8061108..4a6d3a8c61 100644 --- a/tools/server/webui/src/lib/stores/chat.svelte.ts +++ b/tools/server/webui/src/lib/stores/chat.svelte.ts @@ -353,7 +353,6 @@ class ChatStore { await DatabaseStore.updateCurrentNode(this.activeConversation!.id, assistantMessage.id); this.activeConversation!.currNode = assistantMessage.id; - await this.refreshActiveMessages(); if (onComplete) { @@ -479,6 +478,9 @@ class ChatStore { private async createAssistantMessage(parentId?: string): Promise { if (!this.activeConversation) return null; + // Capture the current model name when creating the assistant message + const currentModelName = serverStore.modelName; + return await DatabaseStore.createMessageBranch( { convId: this.activeConversation.id, @@ -487,7 +489,8 @@ class ChatStore { content: '', timestamp: Date.now(), thinking: '', - children: [] + children: [], + model: currentModelName || undefined }, parentId || null ); @@ -1138,7 +1141,8 @@ class ChatStore { role: messageToEdit.role, content: newContent, thinking: messageToEdit.thinking || '', - children: [] + children: [], + model: messageToEdit.model // Preserve original model info when branching }, messageToEdit.parent! ); @@ -1213,7 +1217,8 @@ class ChatStore { content: newContent, thinking: messageToEdit.thinking || '', children: [], - extra: messageToEdit.extra ? JSON.parse(JSON.stringify(messageToEdit.extra)) : undefined + extra: messageToEdit.extra ? JSON.parse(JSON.stringify(messageToEdit.extra)) : undefined, + model: messageToEdit.model // Preserve original model info when branching }, parentId ); @@ -1274,6 +1279,9 @@ class ChatStore { this.isLoading = true; this.currentResponse = ''; + // Capture the current model name when creating the assistant message + const currentModelName = serverStore.modelName; + const newAssistantMessage = await DatabaseStore.createMessageBranch( { convId: this.activeConversation.id, @@ -1282,7 +1290,8 @@ class ChatStore { role: 'assistant', content: '', thinking: '', - children: [] + children: [], + model: currentModelName || undefined }, parentMessage.id ); @@ -1329,6 +1338,9 @@ class ChatStore { false ) as DatabaseMessage[]; + // Capture the current model name when creating the assistant message + const currentModelName = serverStore.modelName; + // Create new assistant message branch const assistantMessage = await DatabaseStore.createMessageBranch( { @@ -1338,7 +1350,8 @@ class ChatStore { role: 'assistant', content: '', thinking: '', - children: [] + children: [], + model: currentModelName || undefined }, userMessageId ); diff --git a/tools/server/webui/src/lib/types/database.d.ts b/tools/server/webui/src/lib/types/database.d.ts index e3076ef12a..c6e12b3cac 100644 --- a/tools/server/webui/src/lib/types/database.d.ts +++ b/tools/server/webui/src/lib/types/database.d.ts @@ -52,4 +52,5 @@ export interface DatabaseMessage { children: string[]; extra?: DatabaseMessageExtra[]; timings?: ChatMessageTimings; + model?: string; }