- {field.help || SETTING_CONFIG_INFO[field.key]} + {@html field.help || SETTING_CONFIG_INFO[field.key]}
{/if} {:else if field.type === 'textarea'} @@ -106,13 +106,28 @@ value={String(localConfig[field.key] ?? '')} onchange={(e) => onConfigChange(field.key, e.currentTarget.value)} placeholder={`Default: ${SETTING_CONFIG_DEFAULT[field.key] ?? 'none'}`} - class="min-h-[100px] w-full md:max-w-2xl" + class="min-h-[10rem] w-full md:max-w-2xl" /> + {#if field.help || SETTING_CONFIG_INFO[field.key]}{field.help || SETTING_CONFIG_INFO[field.key]}
{/if} + + {#if field.key === 'systemMessage'} +--api-key option for the server.',
systemMessage: 'The starting message that defines how model should behave.',
+ showSystemMessage: 'Display the system message at the top of each conversation.',
theme:
'Choose the color theme for the interface. You can choose between System (follows your device settings), Light, or Dark.',
pasteLongTextToFileLen:
diff --git a/tools/server/webui/src/lib/services/chat.ts b/tools/server/webui/src/lib/services/chat.ts
index 414e060764d7e..4cca0543e3efd 100644
--- a/tools/server/webui/src/lib/services/chat.ts
+++ b/tools/server/webui/src/lib/services/chat.ts
@@ -103,6 +103,7 @@ export class ChatService {
}
})
.filter((msg) => {
+ // Filter out empty system messages
if (msg.role === 'system') {
const content = typeof msg.content === 'string' ? msg.content : '';
@@ -112,10 +113,8 @@ export class ChatService {
return true;
});
- const processedMessages = this.injectSystemMessage(normalizedMessages);
-
const requestBody: ApiChatCompletionRequest = {
- messages: processedMessages.map((msg: ApiChatMessageData) => ({
+ messages: normalizedMessages.map((msg: ApiChatMessageData) => ({
role: msg.role,
content: msg.content
})),
diff --git a/tools/server/webui/src/lib/stores/chat.svelte.ts b/tools/server/webui/src/lib/stores/chat.svelte.ts
index 3f97a89183d82..e6ad01e7318a8 100644
--- a/tools/server/webui/src/lib/stores/chat.svelte.ts
+++ b/tools/server/webui/src/lib/stores/chat.svelte.ts
@@ -98,6 +98,25 @@ class ChatStore {
this.activeConversation = conversation;
this.activeMessages = [];
+ // Create root message
+ const rootId = await DatabaseStore.createRootMessage(conversation.id);
+
+ // Create system message if system prompt is configured in settings
+ // This uses the systemMessage from localStorage as a template for new conversations
+ // Once created, the conversation uses its own system message from IndexedDB
+ const currentConfig = config();
+ const systemPrompt = currentConfig.systemMessage?.toString().trim();
+
+ if (systemPrompt) {
+ const systemMessage = await DatabaseStore.createSystemMessage(
+ conversation.id,
+ systemPrompt,
+ rootId
+ );
+
+ this.activeMessages.push(systemMessage);
+ }
+
slotsService.setActiveConversation(conversation.id);
const isConvLoading = this.isConversationLoading(conversation.id);
diff --git a/tools/server/webui/src/lib/stores/database.ts b/tools/server/webui/src/lib/stores/database.ts
index 6394c5b7eda74..9f49b45462e07 100644
--- a/tools/server/webui/src/lib/stores/database.ts
+++ b/tools/server/webui/src/lib/stores/database.ts
@@ -161,6 +161,51 @@ export class DatabaseStore {
return rootMessage.id;
}
+ /**
+ * Creates a system prompt message for a conversation.
+ *
+ * @param convId - Conversation ID
+ * @param systemPrompt - The system prompt content (must be non-empty)
+ * @param parentId - Parent message ID (typically the root message)
+ * @returns The created system message
+ * @throws Error if systemPrompt is empty
+ */
+ static async createSystemMessage(
+ convId: string,
+ systemPrompt: string,
+ parentId: string
+ ): Promise