summaryrefslogtreecommitdiff
path: root/llama.cpp/tools/server/webui/docs/flows
diff options
context:
space:
mode:
Diffstat (limited to 'llama.cpp/tools/server/webui/docs/flows')
-rw-r--r--llama.cpp/tools/server/webui/docs/flows/chat-flow.md174
-rw-r--r--llama.cpp/tools/server/webui/docs/flows/conversations-flow.md155
-rw-r--r--llama.cpp/tools/server/webui/docs/flows/data-flow-simplified-model-mode.md45
-rw-r--r--llama.cpp/tools/server/webui/docs/flows/data-flow-simplified-router-mode.md77
-rw-r--r--llama.cpp/tools/server/webui/docs/flows/database-flow.md155
-rw-r--r--llama.cpp/tools/server/webui/docs/flows/models-flow.md181
-rw-r--r--llama.cpp/tools/server/webui/docs/flows/server-flow.md76
-rw-r--r--llama.cpp/tools/server/webui/docs/flows/settings-flow.md144
8 files changed, 1007 insertions, 0 deletions
diff --git a/llama.cpp/tools/server/webui/docs/flows/chat-flow.md b/llama.cpp/tools/server/webui/docs/flows/chat-flow.md
new file mode 100644
index 0000000..05e1df3
--- /dev/null
+++ b/llama.cpp/tools/server/webui/docs/flows/chat-flow.md
@@ -0,0 +1,174 @@
+```mermaid
+sequenceDiagram
+ participant UI as 🧩 ChatForm / ChatMessage
+ participant chatStore as đŸ—„ī¸ chatStore
+ participant convStore as đŸ—„ī¸ conversationsStore
+ participant settingsStore as đŸ—„ī¸ settingsStore
+ participant ChatSvc as âš™ī¸ ChatService
+ participant DbSvc as âš™ī¸ DatabaseService
+ participant API as 🌐 /v1/chat/completions
+
+ Note over chatStore: State:<br/>isLoading, currentResponse<br/>errorDialogState, activeProcessingState<br/>chatLoadingStates (Map)<br/>chatStreamingStates (Map)<br/>abortControllers (Map)<br/>processingStates (Map)
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: đŸ’Ŧ SEND MESSAGE
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>chatStore: sendMessage(content, extras)
+ activate chatStore
+
+ chatStore->>chatStore: setChatLoading(convId, true)
+ chatStore->>chatStore: clearChatStreaming(convId)
+
+ alt no active conversation
+ chatStore->>convStore: createConversation()
+ Note over convStore: → see conversations-flow.mmd
+ end
+
+ chatStore->>chatStore: addMessage("user", content, extras)
+ chatStore->>DbSvc: createMessageBranch(userMsg, parentId)
+ chatStore->>convStore: addMessageToActive(userMsg)
+ chatStore->>convStore: updateCurrentNode(userMsg.id)
+
+ chatStore->>chatStore: createAssistantMessage(userMsg.id)
+ chatStore->>DbSvc: createMessageBranch(assistantMsg, userMsg.id)
+ chatStore->>convStore: addMessageToActive(assistantMsg)
+
+ chatStore->>chatStore: streamChatCompletion(messages, assistantMsg)
+ deactivate chatStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: 🌊 STREAMING
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ activate chatStore
+ chatStore->>chatStore: startStreaming()
+ Note right of chatStore: isStreamingActive = true
+
+ chatStore->>chatStore: setActiveProcessingConversation(convId)
+ chatStore->>chatStore: getOrCreateAbortController(convId)
+ Note right of chatStore: abortControllers.set(convId, new AbortController())
+
+ chatStore->>chatStore: getApiOptions()
+ Note right of chatStore: Merge from settingsStore.config:<br/>temperature, max_tokens, top_p, etc.
+
+ chatStore->>ChatSvc: sendMessage(messages, options, signal)
+ activate ChatSvc
+
+ ChatSvc->>ChatSvc: convertMessageToChatData(messages)
+ Note right of ChatSvc: DatabaseMessage[] → ApiChatMessageData[]<br/>Process attachments (images, PDFs, audio)
+
+ ChatSvc->>API: POST /v1/chat/completions
+ Note right of API: {messages, model?, stream: true, ...params}
+
+ loop SSE chunks
+ API-->>ChatSvc: data: {"choices":[{"delta":{...}}]}
+ ChatSvc->>ChatSvc: parseSSEChunk(line)
+
+ alt content chunk
+ ChatSvc-->>chatStore: onChunk(content)
+ chatStore->>chatStore: setChatStreaming(convId, response, msgId)
+ Note right of chatStore: currentResponse = $state(accumulated)
+ chatStore->>convStore: updateMessageAtIndex(idx, {content})
+ end
+
+ alt reasoning chunk
+ ChatSvc-->>chatStore: onReasoningChunk(reasoning)
+ chatStore->>convStore: updateMessageAtIndex(idx, {thinking})
+ end
+
+ alt tool_calls chunk
+ ChatSvc-->>chatStore: onToolCallChunk(toolCalls)
+ chatStore->>convStore: updateMessageAtIndex(idx, {toolCalls})
+ end
+
+ alt model info
+ ChatSvc-->>chatStore: onModel(modelName)
+ chatStore->>chatStore: recordModel(modelName)
+ chatStore->>DbSvc: updateMessage(msgId, {model})
+ end
+
+ alt timings (during stream)
+ ChatSvc-->>chatStore: onTimings(timings, promptProgress)
+ chatStore->>chatStore: updateProcessingStateFromTimings()
+ end
+
+ chatStore-->>UI: reactive $state update
+ end
+
+ API-->>ChatSvc: data: [DONE]
+ ChatSvc-->>chatStore: onComplete(content, reasoning, timings, toolCalls)
+ deactivate ChatSvc
+
+ chatStore->>chatStore: stopStreaming()
+ chatStore->>DbSvc: updateMessage(msgId, {content, timings, model})
+ chatStore->>convStore: updateCurrentNode(msgId)
+ chatStore->>chatStore: setChatLoading(convId, false)
+ chatStore->>chatStore: clearChatStreaming(convId)
+ chatStore->>chatStore: clearProcessingState(convId)
+ deactivate chatStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: âšī¸ STOP GENERATION
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>chatStore: stopGeneration()
+ activate chatStore
+ chatStore->>chatStore: savePartialResponseIfNeeded(convId)
+ Note right of chatStore: Save currentResponse to DB if non-empty
+ chatStore->>chatStore: abortControllers.get(convId).abort()
+ Note right of chatStore: fetch throws AbortError → caught by isAbortError()
+ chatStore->>chatStore: stopStreaming()
+ chatStore->>chatStore: setChatLoading(convId, false)
+ chatStore->>chatStore: clearChatStreaming(convId)
+ chatStore->>chatStore: clearProcessingState(convId)
+ deactivate chatStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: 🔁 REGENERATE
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>chatStore: regenerateMessageWithBranching(msgId, model?)
+ activate chatStore
+ chatStore->>convStore: findMessageIndex(msgId)
+ chatStore->>chatStore: Get parent of target message
+ chatStore->>chatStore: createAssistantMessage(parentId)
+ chatStore->>DbSvc: createMessageBranch(newAssistantMsg, parentId)
+ chatStore->>convStore: refreshActiveMessages()
+ Note right of chatStore: Same streaming flow
+ chatStore->>chatStore: streamChatCompletion(...)
+ deactivate chatStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: âžĄī¸ CONTINUE
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>chatStore: continueAssistantMessage(msgId)
+ activate chatStore
+ chatStore->>chatStore: Get existing content from message
+ chatStore->>chatStore: streamChatCompletion(..., existingContent)
+ Note right of chatStore: Appends to existing message content
+ deactivate chatStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: âœī¸ EDIT USER MESSAGE
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>chatStore: editUserMessagePreserveResponses(msgId, newContent)
+ activate chatStore
+ chatStore->>chatStore: Get parent of target message
+ chatStore->>DbSvc: createMessageBranch(editedMsg, parentId)
+ chatStore->>convStore: refreshActiveMessages()
+ Note right of chatStore: Creates new branch, original preserved
+ deactivate chatStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: ❌ ERROR HANDLING
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Note over chatStore: On stream error (non-abort):
+ chatStore->>chatStore: showErrorDialog(type, message)
+ Note right of chatStore: errorDialogState = {type: 'timeout'|'server', message}
+ chatStore->>convStore: removeMessageAtIndex(failedMsgIdx)
+ chatStore->>DbSvc: deleteMessage(failedMsgId)
+```
diff --git a/llama.cpp/tools/server/webui/docs/flows/conversations-flow.md b/llama.cpp/tools/server/webui/docs/flows/conversations-flow.md
new file mode 100644
index 0000000..185ed16
--- /dev/null
+++ b/llama.cpp/tools/server/webui/docs/flows/conversations-flow.md
@@ -0,0 +1,155 @@
+```mermaid
+sequenceDiagram
+ participant UI as 🧩 ChatSidebar / ChatScreen
+ participant convStore as đŸ—„ī¸ conversationsStore
+ participant chatStore as đŸ—„ī¸ chatStore
+ participant DbSvc as âš™ī¸ DatabaseService
+ participant IDB as 💾 IndexedDB
+
+ Note over convStore: State:<br/>conversations: DatabaseConversation[]<br/>activeConversation: DatabaseConversation | null<br/>activeMessages: DatabaseMessage[]<br/>isInitialized: boolean<br/>usedModalities: $derived({vision, audio})
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,IDB: 🚀 INITIALIZATION
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Note over convStore: Auto-initialized in constructor (browser only)
+ convStore->>convStore: initialize()
+ activate convStore
+ convStore->>convStore: loadConversations()
+ convStore->>DbSvc: getAllConversations()
+ DbSvc->>IDB: SELECT * FROM conversations ORDER BY lastModified DESC
+ IDB-->>DbSvc: Conversation[]
+ DbSvc-->>convStore: conversations
+ convStore->>convStore: conversations = $state(data)
+ convStore->>convStore: isInitialized = true
+ deactivate convStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,IDB: ➕ CREATE CONVERSATION
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>convStore: createConversation(name?)
+ activate convStore
+ convStore->>DbSvc: createConversation(name || "New Chat")
+ DbSvc->>IDB: INSERT INTO conversations
+ IDB-->>DbSvc: conversation {id, name, lastModified, currNode: ""}
+ DbSvc-->>convStore: conversation
+ convStore->>convStore: conversations.unshift(conversation)
+ convStore->>convStore: activeConversation = $state(conversation)
+ convStore->>convStore: activeMessages = $state([])
+ deactivate convStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,IDB: 📂 LOAD CONVERSATION
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>convStore: loadConversation(convId)
+ activate convStore
+ convStore->>DbSvc: getConversation(convId)
+ DbSvc->>IDB: SELECT * FROM conversations WHERE id = ?
+ IDB-->>DbSvc: conversation
+ convStore->>convStore: activeConversation = $state(conversation)
+
+ convStore->>convStore: refreshActiveMessages()
+ convStore->>DbSvc: getConversationMessages(convId)
+ DbSvc->>IDB: SELECT * FROM messages WHERE convId = ?
+ IDB-->>DbSvc: allMessages[]
+ convStore->>convStore: filterByLeafNodeId(allMessages, currNode)
+ Note right of convStore: Filter to show only current branch path
+ convStore->>convStore: activeMessages = $state(filtered)
+
+ convStore->>chatStore: syncLoadingStateForChat(convId)
+ Note right of chatStore: Sync isLoading/currentResponse if streaming
+ deactivate convStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,IDB: đŸŒŗ MESSAGE BRANCHING MODEL
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Note over IDB: Message Tree Structure:<br/>- Each message has parent (null for root)<br/>- Each message has children[] array<br/>- Conversation.currNode points to active leaf<br/>- filterByLeafNodeId() traverses from root to currNode
+
+ rect rgb(240, 240, 255)
+ Note over convStore: Example Branch Structure:
+ Note over convStore: root → user1 → assistant1 → user2 → assistant2a (currNode)<br/> ↘ assistant2b (alt branch)
+ end
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,IDB: â†”ī¸ BRANCH NAVIGATION
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>convStore: navigateToSibling(msgId, direction)
+ activate convStore
+ convStore->>convStore: Find message in activeMessages
+ convStore->>convStore: Get parent message
+ convStore->>convStore: Find sibling in parent.children[]
+ convStore->>convStore: findLeafNode(siblingId, allMessages)
+ Note right of convStore: Navigate to leaf of sibling branch
+ convStore->>convStore: updateCurrentNode(leafId)
+ convStore->>DbSvc: updateCurrentNode(convId, leafId)
+ DbSvc->>IDB: UPDATE conversations SET currNode = ?
+ convStore->>convStore: refreshActiveMessages()
+ deactivate convStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,IDB: 📝 UPDATE CONVERSATION
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>convStore: updateConversationName(convId, newName)
+ activate convStore
+ convStore->>DbSvc: updateConversation(convId, {name: newName})
+ DbSvc->>IDB: UPDATE conversations SET name = ?
+ convStore->>convStore: Update in conversations array
+ deactivate convStore
+
+ Note over convStore: Auto-title update (after first response):
+ convStore->>convStore: updateConversationTitleWithConfirmation()
+ convStore->>convStore: titleUpdateConfirmationCallback?()
+ Note right of convStore: Shows dialog if title would change
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,IDB: đŸ—‘ī¸ DELETE CONVERSATION
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>convStore: deleteConversation(convId)
+ activate convStore
+ convStore->>DbSvc: deleteConversation(convId)
+ DbSvc->>IDB: DELETE FROM conversations WHERE id = ?
+ DbSvc->>IDB: DELETE FROM messages WHERE convId = ?
+ convStore->>convStore: conversations.filter(c => c.id !== convId)
+ alt deleted active conversation
+ convStore->>convStore: clearActiveConversation()
+ end
+ deactivate convStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,IDB: 📊 MODALITY TRACKING
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Note over convStore: usedModalities = $derived.by(() => {<br/> calculateModalitiesFromMessages(activeMessages)<br/>})
+
+ Note over convStore: Scans activeMessages for attachments:<br/>- IMAGE → vision: true<br/>- PDF (processedAsImages) → vision: true<br/>- AUDIO → audio: true
+
+ UI->>convStore: getModalitiesUpToMessage(msgId)
+ Note right of convStore: Used for regeneration validation<br/>Only checks messages BEFORE target
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,IDB: 📤 EXPORT / đŸ“Ĩ IMPORT
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>convStore: exportAllConversations()
+ activate convStore
+ convStore->>DbSvc: getAllConversations()
+ loop each conversation
+ convStore->>DbSvc: getConversationMessages(convId)
+ end
+ convStore->>convStore: triggerDownload(JSON blob)
+ deactivate convStore
+
+ UI->>convStore: importConversations(file)
+ activate convStore
+ convStore->>convStore: Parse JSON file
+ convStore->>DbSvc: importConversations(parsed)
+ DbSvc->>IDB: Bulk INSERT conversations + messages
+ convStore->>convStore: loadConversations()
+ deactivate convStore
+```
diff --git a/llama.cpp/tools/server/webui/docs/flows/data-flow-simplified-model-mode.md b/llama.cpp/tools/server/webui/docs/flows/data-flow-simplified-model-mode.md
new file mode 100644
index 0000000..07b3621
--- /dev/null
+++ b/llama.cpp/tools/server/webui/docs/flows/data-flow-simplified-model-mode.md
@@ -0,0 +1,45 @@
+```mermaid
+%% MODEL Mode Data Flow (single model)
+%% Detailed flows: ./flows/server-flow.mmd, ./flows/models-flow.mmd, ./flows/chat-flow.mmd
+
+sequenceDiagram
+ participant User as 👤 User
+ participant UI as 🧩 UI
+ participant Stores as đŸ—„ī¸ Stores
+ participant DB as 💾 IndexedDB
+ participant API as 🌐 llama-server
+
+ Note over User,API: 🚀 Initialization (see: server-flow.mmd, models-flow.mmd)
+
+ UI->>Stores: initialize()
+ Stores->>DB: load conversations
+ Stores->>API: GET /props
+ API-->>Stores: server config + modalities
+ Stores->>API: GET /v1/models
+ API-->>Stores: single model (auto-selected)
+
+ Note over User,API: đŸ’Ŧ Chat Flow (see: chat-flow.mmd)
+
+ User->>UI: send message
+ UI->>Stores: sendMessage()
+ Stores->>DB: save user message
+ Stores->>API: POST /v1/chat/completions (stream)
+ loop streaming
+ API-->>Stores: SSE chunks
+ Stores-->>UI: reactive update
+ end
+ API-->>Stores: done + timings
+ Stores->>DB: save assistant message
+
+ Note over User,API: 🔁 Regenerate
+
+ User->>UI: regenerate
+ Stores->>DB: create message branch
+ Note right of Stores: same streaming flow
+
+ Note over User,API: âšī¸ Stop
+
+ User->>UI: stop
+ Stores->>Stores: abort stream
+ Stores->>DB: save partial response
+```
diff --git a/llama.cpp/tools/server/webui/docs/flows/data-flow-simplified-router-mode.md b/llama.cpp/tools/server/webui/docs/flows/data-flow-simplified-router-mode.md
new file mode 100644
index 0000000..bccacf5
--- /dev/null
+++ b/llama.cpp/tools/server/webui/docs/flows/data-flow-simplified-router-mode.md
@@ -0,0 +1,77 @@
+```mermaid
+%% ROUTER Mode Data Flow (multi-model)
+%% Detailed flows: ./flows/server-flow.mmd, ./flows/models-flow.mmd, ./flows/chat-flow.mmd
+
+sequenceDiagram
+ participant User as 👤 User
+ participant UI as 🧩 UI
+ participant Stores as đŸ—„ī¸ Stores
+ participant DB as 💾 IndexedDB
+ participant API as 🌐 llama-server
+
+ Note over User,API: 🚀 Initialization (see: server-flow.mmd, models-flow.mmd)
+
+ UI->>Stores: initialize()
+ Stores->>DB: load conversations
+ Stores->>API: GET /props
+ API-->>Stores: {role: "router"}
+ Stores->>API: GET /v1/models
+ API-->>Stores: models[] with status (loaded/available)
+ loop each loaded model
+ Stores->>API: GET /props?model=X
+ API-->>Stores: modalities (vision/audio)
+ end
+
+ Note over User,API: 🔄 Model Selection (see: models-flow.mmd)
+
+ User->>UI: select model
+ alt model not loaded
+ Stores->>API: POST /models/load
+ loop poll status
+ Stores->>API: GET /v1/models
+ API-->>Stores: check if loaded
+ end
+ Stores->>API: GET /props?model=X
+ API-->>Stores: cache modalities
+ end
+ Stores->>Stores: validate modalities vs conversation
+ alt valid
+ Stores->>Stores: select model
+ else invalid
+ Stores->>API: POST /models/unload
+ UI->>User: show error toast
+ end
+
+ Note over User,API: đŸ’Ŧ Chat Flow (see: chat-flow.mmd)
+
+ User->>UI: send message
+ UI->>Stores: sendMessage()
+ Stores->>DB: save user message
+ Stores->>API: POST /v1/chat/completions {model: X}
+ Note right of API: router forwards to model
+ loop streaming
+ API-->>Stores: SSE chunks + model info
+ Stores-->>UI: reactive update
+ end
+ API-->>Stores: done + timings
+ Stores->>DB: save assistant message + model used
+
+ Note over User,API: 🔁 Regenerate (optional: different model)
+
+ User->>UI: regenerate
+ Stores->>Stores: validate modalities up to this message
+ Stores->>DB: create message branch
+ Note right of Stores: same streaming flow
+
+ Note over User,API: âšī¸ Stop
+
+ User->>UI: stop
+ Stores->>Stores: abort stream
+ Stores->>DB: save partial response
+
+ Note over User,API: đŸ—‘ī¸ LRU Unloading
+
+ Note right of API: Server auto-unloads LRU models<br/>when cache full
+ User->>UI: select unloaded model
+ Note right of Stores: triggers load flow again
+```
diff --git a/llama.cpp/tools/server/webui/docs/flows/database-flow.md b/llama.cpp/tools/server/webui/docs/flows/database-flow.md
new file mode 100644
index 0000000..50f8284
--- /dev/null
+++ b/llama.cpp/tools/server/webui/docs/flows/database-flow.md
@@ -0,0 +1,155 @@
+```mermaid
+sequenceDiagram
+ participant Store as đŸ—„ī¸ Stores
+ participant DbSvc as âš™ī¸ DatabaseService
+ participant Dexie as đŸ“Ļ Dexie ORM
+ participant IDB as 💾 IndexedDB
+
+ Note over DbSvc: Stateless service - all methods static<br/>Database: "LlamacppWebui"
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over Store,IDB: 📊 SCHEMA
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ rect rgb(240, 248, 255)
+ Note over IDB: conversations table:<br/>id (PK), lastModified, currNode, name
+ end
+
+ rect rgb(255, 248, 240)
+ Note over IDB: messages table:<br/>id (PK), convId (FK), type, role, timestamp,<br/>parent, children[], content, thinking,<br/>toolCalls, extra[], model, timings
+ end
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over Store,IDB: đŸ’Ŧ CONVERSATIONS CRUD
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Store->>DbSvc: createConversation(name)
+ activate DbSvc
+ DbSvc->>DbSvc: Generate UUID
+ DbSvc->>Dexie: db.conversations.add({id, name, lastModified, currNode: ""})
+ Dexie->>IDB: INSERT
+ IDB-->>Dexie: success
+ DbSvc-->>Store: DatabaseConversation
+ deactivate DbSvc
+
+ Store->>DbSvc: getConversation(convId)
+ DbSvc->>Dexie: db.conversations.get(convId)
+ Dexie->>IDB: SELECT WHERE id = ?
+ IDB-->>DbSvc: DatabaseConversation
+
+ Store->>DbSvc: getAllConversations()
+ DbSvc->>Dexie: db.conversations.orderBy('lastModified').reverse().toArray()
+ Dexie->>IDB: SELECT ORDER BY lastModified DESC
+ IDB-->>DbSvc: DatabaseConversation[]
+
+ Store->>DbSvc: updateConversation(convId, updates)
+ DbSvc->>Dexie: db.conversations.update(convId, {...updates, lastModified})
+ Dexie->>IDB: UPDATE
+
+ Store->>DbSvc: deleteConversation(convId)
+ activate DbSvc
+ DbSvc->>Dexie: db.conversations.delete(convId)
+ Dexie->>IDB: DELETE FROM conversations
+ DbSvc->>Dexie: db.messages.where('convId').equals(convId).delete()
+ Dexie->>IDB: DELETE FROM messages WHERE convId = ?
+ deactivate DbSvc
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over Store,IDB: 📝 MESSAGES CRUD
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Store->>DbSvc: createRootMessage(convId)
+ activate DbSvc
+ DbSvc->>DbSvc: Create root message {type: "root", parent: null}
+ DbSvc->>Dexie: db.messages.add(rootMsg)
+ Dexie->>IDB: INSERT
+ DbSvc-->>Store: rootMessageId
+ deactivate DbSvc
+
+ Store->>DbSvc: createMessageBranch(message, parentId)
+ activate DbSvc
+ DbSvc->>DbSvc: Generate UUID for new message
+ DbSvc->>Dexie: db.messages.add({...message, id, parent: parentId})
+ Dexie->>IDB: INSERT message
+
+ alt parentId exists
+ DbSvc->>Dexie: db.messages.get(parentId)
+ Dexie->>IDB: SELECT parent
+ DbSvc->>DbSvc: parent.children.push(newId)
+ DbSvc->>Dexie: db.messages.update(parentId, {children})
+ Dexie->>IDB: UPDATE parent.children
+ end
+
+ DbSvc->>Dexie: db.conversations.update(convId, {currNode: newId})
+ Dexie->>IDB: UPDATE conversation.currNode
+ DbSvc-->>Store: DatabaseMessage
+ deactivate DbSvc
+
+ Store->>DbSvc: getConversationMessages(convId)
+ DbSvc->>Dexie: db.messages.where('convId').equals(convId).toArray()
+ Dexie->>IDB: SELECT WHERE convId = ?
+ IDB-->>DbSvc: DatabaseMessage[]
+
+ Store->>DbSvc: updateMessage(msgId, updates)
+ DbSvc->>Dexie: db.messages.update(msgId, updates)
+ Dexie->>IDB: UPDATE
+
+ Store->>DbSvc: deleteMessage(msgId)
+ DbSvc->>Dexie: db.messages.delete(msgId)
+ Dexie->>IDB: DELETE
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over Store,IDB: đŸŒŗ BRANCHING OPERATIONS
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Store->>DbSvc: updateCurrentNode(convId, nodeId)
+ DbSvc->>Dexie: db.conversations.update(convId, {currNode: nodeId, lastModified})
+ Dexie->>IDB: UPDATE
+
+ Store->>DbSvc: deleteMessageCascading(msgId)
+ activate DbSvc
+ DbSvc->>DbSvc: findDescendantMessages(msgId, allMessages)
+ Note right of DbSvc: Recursively find all children
+ loop each descendant
+ DbSvc->>Dexie: db.messages.delete(descendantId)
+ Dexie->>IDB: DELETE
+ end
+ DbSvc->>Dexie: db.messages.delete(msgId)
+ Dexie->>IDB: DELETE target message
+ deactivate DbSvc
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over Store,IDB: đŸ“Ĩ IMPORT
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Store->>DbSvc: importConversations(data)
+ activate DbSvc
+ loop each conversation in data
+ DbSvc->>DbSvc: Generate new UUIDs (avoid conflicts)
+ DbSvc->>Dexie: db.conversations.add(conversation)
+ Dexie->>IDB: INSERT conversation
+ loop each message
+ DbSvc->>Dexie: db.messages.add(message)
+ Dexie->>IDB: INSERT message
+ end
+ end
+ deactivate DbSvc
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over Store,IDB: 🔗 MESSAGE TREE UTILITIES
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Note over DbSvc: Used by stores (imported from utils):
+
+ rect rgb(240, 255, 240)
+ Note over DbSvc: filterByLeafNodeId(messages, leafId)<br/>→ Returns path from root to leaf<br/>→ Used to display current branch
+ end
+
+ rect rgb(240, 255, 240)
+ Note over DbSvc: findLeafNode(startId, messages)<br/>→ Traverse to deepest child<br/>→ Used for branch navigation
+ end
+
+ rect rgb(240, 255, 240)
+ Note over DbSvc: findDescendantMessages(msgId, messages)<br/>→ Find all children recursively<br/>→ Used for cascading deletes
+ end
+```
diff --git a/llama.cpp/tools/server/webui/docs/flows/models-flow.md b/llama.cpp/tools/server/webui/docs/flows/models-flow.md
new file mode 100644
index 0000000..c3031b7
--- /dev/null
+++ b/llama.cpp/tools/server/webui/docs/flows/models-flow.md
@@ -0,0 +1,181 @@
+```mermaid
+sequenceDiagram
+ participant UI as 🧩 ModelsSelector
+ participant Hooks as đŸĒ useModelChangeValidation
+ participant modelsStore as đŸ—„ī¸ modelsStore
+ participant serverStore as đŸ—„ī¸ serverStore
+ participant convStore as đŸ—„ī¸ conversationsStore
+ participant ModelsSvc as âš™ī¸ ModelsService
+ participant PropsSvc as âš™ī¸ PropsService
+ participant API as 🌐 llama-server
+
+ Note over modelsStore: State:<br/>models: ModelOption[]<br/>routerModels: ApiModelDataEntry[]<br/>selectedModelId, selectedModelName<br/>loading, updating, error<br/>modelLoadingStates (Map)<br/>modelPropsCache (Map)<br/>propsCacheVersion
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: 🚀 INITIALIZATION (MODEL mode)
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>modelsStore: fetch()
+ activate modelsStore
+ modelsStore->>modelsStore: loading = true
+
+ alt serverStore.props not loaded
+ modelsStore->>serverStore: fetch()
+ Note over serverStore: → see server-flow.mmd
+ end
+
+ modelsStore->>ModelsSvc: list()
+ ModelsSvc->>API: GET /v1/models
+ API-->>ModelsSvc: ApiModelListResponse {data: [model]}
+
+ modelsStore->>modelsStore: models = $state(mapped)
+ Note right of modelsStore: Map to ModelOption[]:<br/>{id, name, model, description, capabilities}
+
+ Note over modelsStore: MODEL mode: Get modalities from serverStore.props
+ modelsStore->>modelsStore: modelPropsCache.set(model.id, serverStore.props)
+ modelsStore->>modelsStore: models[0].modalities = props.modalities
+
+ modelsStore->>modelsStore: Auto-select single model
+ Note right of modelsStore: selectedModelId = models[0].id
+ modelsStore->>modelsStore: loading = false
+ deactivate modelsStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: 🚀 INITIALIZATION (ROUTER mode)
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>modelsStore: fetch()
+ activate modelsStore
+ modelsStore->>ModelsSvc: list()
+ ModelsSvc->>API: GET /v1/models
+ API-->>ModelsSvc: ApiModelListResponse
+ modelsStore->>modelsStore: models = $state(mapped)
+ deactivate modelsStore
+
+ Note over UI: After models loaded, layout triggers:
+ UI->>modelsStore: fetchRouterModels()
+ activate modelsStore
+ modelsStore->>ModelsSvc: listRouter()
+ ModelsSvc->>API: GET /v1/models
+ API-->>ModelsSvc: ApiRouterModelsListResponse
+ Note right of API: {data: [{id, status, path, in_cache}]}
+ modelsStore->>modelsStore: routerModels = $state(data)
+
+ modelsStore->>modelsStore: fetchModalitiesForLoadedModels()
+ loop each model where status === "loaded"
+ modelsStore->>PropsSvc: fetchForModel(modelId)
+ PropsSvc->>API: GET /props?model={modelId}
+ API-->>PropsSvc: ApiLlamaCppServerProps
+ modelsStore->>modelsStore: modelPropsCache.set(modelId, props)
+ end
+ modelsStore->>modelsStore: propsCacheVersion++
+ deactivate modelsStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: 🔄 MODEL SELECTION (ROUTER mode)
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>Hooks: useModelChangeValidation({getRequiredModalities, onSuccess?, onValidationFailure?})
+ Note over Hooks: Hook configured per-component:<br/>ChatForm: getRequiredModalities = usedModalities<br/>ChatMessage: getRequiredModalities = getModalitiesUpToMessage(msgId)
+
+ UI->>Hooks: handleModelChange(modelId, modelName)
+ activate Hooks
+ Hooks->>Hooks: previousSelectedModelId = modelsStore.selectedModelId
+ Hooks->>modelsStore: isModelLoaded(modelName)?
+
+ alt model NOT loaded
+ Hooks->>modelsStore: loadModel(modelName)
+ Note over modelsStore: → see LOAD MODEL section below
+ end
+
+ Note over Hooks: Always fetch props (from cache or API)
+ Hooks->>modelsStore: fetchModelProps(modelName)
+ modelsStore-->>Hooks: props
+
+ Hooks->>convStore: getRequiredModalities()
+ convStore-->>Hooks: {vision, audio}
+
+ Hooks->>Hooks: Validate: model.modalities ⊇ required?
+
+ alt validation PASSED
+ Hooks->>modelsStore: selectModelById(modelId)
+ Hooks-->>UI: return true
+ else validation FAILED
+ Hooks->>UI: toast.error("Model doesn't support required modalities")
+ alt model was just loaded
+ Hooks->>modelsStore: unloadModel(modelName)
+ end
+ alt onValidationFailure provided
+ Hooks->>modelsStore: selectModelById(previousSelectedModelId)
+ end
+ Hooks-->>UI: return false
+ end
+ deactivate Hooks
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: âŦ†ī¸ LOAD MODEL (ROUTER mode)
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ modelsStore->>modelsStore: loadModel(modelId)
+ activate modelsStore
+
+ alt already loaded
+ modelsStore-->>modelsStore: return (no-op)
+ end
+
+ modelsStore->>modelsStore: modelLoadingStates.set(modelId, true)
+ modelsStore->>ModelsSvc: load(modelId)
+ ModelsSvc->>API: POST /models/load {model: modelId}
+ API-->>ModelsSvc: {status: "loading"}
+
+ modelsStore->>modelsStore: pollForModelStatus(modelId, LOADED)
+ loop poll every 500ms (max 60 attempts)
+ modelsStore->>modelsStore: fetchRouterModels()
+ modelsStore->>ModelsSvc: listRouter()
+ ModelsSvc->>API: GET /v1/models
+ API-->>ModelsSvc: models[]
+ modelsStore->>modelsStore: getModelStatus(modelId)
+ alt status === LOADED
+ Note right of modelsStore: break loop
+ else status === LOADING
+ Note right of modelsStore: wait 500ms, continue
+ end
+ end
+
+ modelsStore->>modelsStore: updateModelModalities(modelId)
+ modelsStore->>PropsSvc: fetchForModel(modelId)
+ PropsSvc->>API: GET /props?model={modelId}
+ API-->>PropsSvc: props with modalities
+ modelsStore->>modelsStore: modelPropsCache.set(modelId, props)
+ modelsStore->>modelsStore: propsCacheVersion++
+
+ modelsStore->>modelsStore: modelLoadingStates.set(modelId, false)
+ deactivate modelsStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: âŦ‡ī¸ UNLOAD MODEL (ROUTER mode)
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ modelsStore->>modelsStore: unloadModel(modelId)
+ activate modelsStore
+ modelsStore->>modelsStore: modelLoadingStates.set(modelId, true)
+ modelsStore->>ModelsSvc: unload(modelId)
+ ModelsSvc->>API: POST /models/unload {model: modelId}
+
+ modelsStore->>modelsStore: pollForModelStatus(modelId, UNLOADED)
+ loop poll until unloaded
+ modelsStore->>ModelsSvc: listRouter()
+ ModelsSvc->>API: GET /v1/models
+ end
+
+ modelsStore->>modelsStore: modelLoadingStates.set(modelId, false)
+ deactivate modelsStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: 📊 COMPUTED GETTERS
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Note over modelsStore: Getters:<br/>- selectedModel: ModelOption | null<br/>- loadedModelIds: string[] (from routerModels)<br/>- loadingModelIds: string[] (from modelLoadingStates)<br/>- singleModelName: string | null (MODEL mode only)
+
+ Note over modelsStore: Modality helpers:<br/>- getModelModalities(modelId): {vision, audio}<br/>- modelSupportsVision(modelId): boolean<br/>- modelSupportsAudio(modelId): boolean
+```
diff --git a/llama.cpp/tools/server/webui/docs/flows/server-flow.md b/llama.cpp/tools/server/webui/docs/flows/server-flow.md
new file mode 100644
index 0000000..d6a1611
--- /dev/null
+++ b/llama.cpp/tools/server/webui/docs/flows/server-flow.md
@@ -0,0 +1,76 @@
+```mermaid
+sequenceDiagram
+ participant UI as 🧩 +layout.svelte
+ participant serverStore as đŸ—„ī¸ serverStore
+ participant PropsSvc as âš™ī¸ PropsService
+ participant API as 🌐 llama-server
+
+ Note over serverStore: State:<br/>props: ApiLlamaCppServerProps | null<br/>loading, error<br/>role: ServerRole | null (MODEL | ROUTER)<br/>fetchPromise (deduplication)
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: 🚀 INITIALIZATION
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>serverStore: fetch()
+ activate serverStore
+
+ alt fetchPromise exists (already fetching)
+ serverStore-->>UI: return fetchPromise
+ Note right of serverStore: Deduplicate concurrent calls
+ end
+
+ serverStore->>serverStore: loading = true
+ serverStore->>serverStore: fetchPromise = new Promise()
+
+ serverStore->>PropsSvc: fetch()
+ PropsSvc->>API: GET /props
+ API-->>PropsSvc: ApiLlamaCppServerProps
+ Note right of API: {role, model_path, model_alias,<br/>modalities, default_generation_settings, ...}
+
+ PropsSvc-->>serverStore: props
+ serverStore->>serverStore: props = $state(data)
+
+ serverStore->>serverStore: detectRole(props)
+ Note right of serverStore: role = props.role === "router"<br/> ? ServerRole.ROUTER<br/> : ServerRole.MODEL
+
+ serverStore->>serverStore: loading = false
+ serverStore->>serverStore: fetchPromise = null
+ deactivate serverStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: 📊 COMPUTED GETTERS
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Note over serverStore: Getters from props:
+
+ rect rgb(240, 255, 240)
+ Note over serverStore: defaultParams<br/>→ props.default_generation_settings.params<br/>(temperature, top_p, top_k, etc.)
+ end
+
+ rect rgb(240, 255, 240)
+ Note over serverStore: contextSize<br/>→ props.default_generation_settings.n_ctx
+ end
+
+ rect rgb(255, 240, 240)
+ Note over serverStore: isRouterMode<br/>→ role === ServerRole.ROUTER
+ end
+
+ rect rgb(255, 240, 240)
+ Note over serverStore: isModelMode<br/>→ role === ServerRole.MODEL
+ end
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: 🔗 RELATIONSHIPS
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Note over serverStore: Used by:
+ Note right of serverStore: - modelsStore: role detection, MODEL mode modalities<br/>- settingsStore: syncWithServerDefaults (defaultParams)<br/>- chatStore: contextSize for processing state<br/>- UI components: isRouterMode for conditional rendering
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,API: ❌ ERROR HANDLING
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Note over serverStore: getErrorMessage(): string | null<br/>Returns formatted error for UI display
+
+ Note over serverStore: clear(): void<br/>Resets all state (props, error, loading, role)
+```
diff --git a/llama.cpp/tools/server/webui/docs/flows/settings-flow.md b/llama.cpp/tools/server/webui/docs/flows/settings-flow.md
new file mode 100644
index 0000000..578e01e
--- /dev/null
+++ b/llama.cpp/tools/server/webui/docs/flows/settings-flow.md
@@ -0,0 +1,144 @@
+```mermaid
+sequenceDiagram
+ participant UI as 🧩 ChatSettings
+ participant settingsStore as đŸ—„ī¸ settingsStore
+ participant serverStore as đŸ—„ī¸ serverStore
+ participant ParamSvc as âš™ī¸ ParameterSyncService
+ participant LS as 💾 LocalStorage
+
+ Note over settingsStore: State:<br/>config: SettingsConfigType<br/>theme: string ("auto" | "light" | "dark")<br/>isInitialized: boolean<br/>userOverrides: Set&lt;string&gt;
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,LS: 🚀 INITIALIZATION
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Note over settingsStore: Auto-initialized in constructor (browser only)
+ settingsStore->>settingsStore: initialize()
+ activate settingsStore
+
+ settingsStore->>settingsStore: loadConfig()
+ settingsStore->>LS: get("llama-config")
+ LS-->>settingsStore: StoredConfig | null
+
+ alt config exists
+ settingsStore->>settingsStore: Merge with SETTING_CONFIG_DEFAULT
+ Note right of settingsStore: Fill missing keys with defaults
+ else no config
+ settingsStore->>settingsStore: config = SETTING_CONFIG_DEFAULT
+ end
+
+ settingsStore->>LS: get("llama-userOverrides")
+ LS-->>settingsStore: string[] | null
+ settingsStore->>settingsStore: userOverrides = new Set(data)
+
+ settingsStore->>settingsStore: loadTheme()
+ settingsStore->>LS: get("llama-theme")
+ LS-->>settingsStore: theme | "auto"
+
+ settingsStore->>settingsStore: isInitialized = true
+ deactivate settingsStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,LS: 🔄 SYNC WITH SERVER DEFAULTS
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Note over UI: Triggered from +layout.svelte when serverStore.props loaded
+ UI->>settingsStore: syncWithServerDefaults()
+ activate settingsStore
+
+ settingsStore->>serverStore: defaultParams
+ serverStore-->>settingsStore: {temperature, top_p, top_k, ...}
+
+ settingsStore->>ParamSvc: extractServerDefaults(defaultParams)
+ ParamSvc-->>settingsStore: Record<string, value>
+
+ settingsStore->>ParamSvc: mergeWithServerDefaults(config, serverDefaults)
+ Note right of ParamSvc: For each syncable parameter:<br/>- If NOT in userOverrides → use server default<br/>- If in userOverrides → keep user value
+ ParamSvc-->>settingsStore: mergedConfig
+
+ settingsStore->>settingsStore: config = mergedConfig
+ settingsStore->>settingsStore: saveConfig()
+ deactivate settingsStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,LS: âš™ī¸ UPDATE CONFIG
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>settingsStore: updateConfig(key, value)
+ activate settingsStore
+ settingsStore->>settingsStore: config[key] = value
+ settingsStore->>settingsStore: userOverrides.add(key)
+ Note right of settingsStore: Mark as user-modified (won't be overwritten by server)
+ settingsStore->>settingsStore: saveConfig()
+ settingsStore->>LS: set("llama-config", config)
+ settingsStore->>LS: set("llama-userOverrides", [...userOverrides])
+ deactivate settingsStore
+
+ UI->>settingsStore: updateMultipleConfig({key1: val1, key2: val2})
+ activate settingsStore
+ Note right of settingsStore: Batch update, single save
+ settingsStore->>settingsStore: For each key: config[key] = value
+ settingsStore->>settingsStore: For each key: userOverrides.add(key)
+ settingsStore->>settingsStore: saveConfig()
+ deactivate settingsStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,LS: 🔄 RESET
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>settingsStore: resetConfig()
+ activate settingsStore
+ settingsStore->>settingsStore: config = SETTING_CONFIG_DEFAULT
+ settingsStore->>settingsStore: userOverrides.clear()
+ settingsStore->>settingsStore: syncWithServerDefaults()
+ Note right of settingsStore: Apply server defaults for syncable params
+ settingsStore->>settingsStore: saveConfig()
+ deactivate settingsStore
+
+ UI->>settingsStore: resetParameterToServerDefault(key)
+ activate settingsStore
+ settingsStore->>settingsStore: userOverrides.delete(key)
+ settingsStore->>serverStore: defaultParams[key]
+ settingsStore->>settingsStore: config[key] = serverDefault
+ settingsStore->>settingsStore: saveConfig()
+ deactivate settingsStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,LS: 🎨 THEME
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>settingsStore: updateTheme(newTheme)
+ activate settingsStore
+ settingsStore->>settingsStore: theme = newTheme
+ settingsStore->>settingsStore: saveTheme()
+ settingsStore->>LS: set("llama-theme", theme)
+ deactivate settingsStore
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,LS: 📊 PARAMETER INFO
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ UI->>settingsStore: getParameterInfo(key)
+ settingsStore->>ParamSvc: getParameterInfo(key, config, serverDefaults, userOverrides)
+ ParamSvc-->>settingsStore: ParameterInfo
+ Note right of ParamSvc: {<br/> currentValue,<br/> serverDefault,<br/> isUserOverride: boolean,<br/> canSync: boolean,<br/> isDifferentFromServer: boolean<br/>}
+
+ UI->>settingsStore: getParameterDiff()
+ settingsStore->>ParamSvc: createParameterDiff(config, serverDefaults, userOverrides)
+ ParamSvc-->>settingsStore: ParameterDiff[]
+ Note right of ParamSvc: Array of parameters where user != server
+
+ %% ═══════════════════════════════════════════════════════════════════════════
+ Note over UI,LS: 📋 CONFIG CATEGORIES
+ %% ═══════════════════════════════════════════════════════════════════════════
+
+ Note over settingsStore: Syncable with server (from /props):
+ rect rgb(240, 255, 240)
+ Note over settingsStore: temperature, top_p, top_k, min_p<br/>repeat_penalty, presence_penalty, frequency_penalty<br/>dynatemp_range, dynatemp_exponent<br/>typ_p, xtc_probability, xtc_threshold<br/>dry_multiplier, dry_base, dry_allowed_length, dry_penalty_last_n
+ end
+
+ Note over settingsStore: UI-only (not synced):
+ rect rgb(255, 240, 240)
+ Note over settingsStore: systemMessage, custom (JSON)<br/>showStatistics, enableContinueGeneration<br/>autoMicOnEmpty, disableAutoScroll<br/>apiKey, pdfAsImage, disableReasoningFormat
+ end
+```