```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:
conversations: DatabaseConversation[]
activeConversation: DatabaseConversation | null
activeMessages: DatabaseMessage[]
isInitialized: boolean
pendingMcpServerOverrides: Map<string, McpServerOverride> %% ═══════════════════════════════════════════════════════════════════════════ 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([]) alt pendingMcpServerOverrides has entries loop each pending override convStore->>DbSvc: Store MCP server override for new conversation end convStore->>convStore: clearPendingMcpServerOverrides() end 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) Note right of convStore: Route (+page.svelte) then calls:
chatStore.syncLoadingStateForChat(convId) deactivate convStore %% ═══════════════════════════════════════════════════════════════════════════ Note over UI,IDB: 🌳 MESSAGE BRANCHING MODEL %% ═══════════════════════════════════════════════════════════════════════════ Note over IDB: Message Tree Structure:
- Each message has parent (null for root)
- Each message has children[] array
- Conversation.currNode points to active leaf
- 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)
↘ 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 UI->>convStore: deleteAll() activate convStore convStore->>DbSvc: Delete all conversations and messages convStore->>convStore: conversations = [] convStore->>convStore: clearActiveConversation() deactivate convStore %% ═══════════════════════════════════════════════════════════════════════════ Note over UI,IDB: � MCP SERVER PER-CHAT OVERRIDES %% ═══════════════════════════════════════════════════════════════════════════ Note over convStore: Conversations can override which MCP servers are enabled. Note over convStore: Uses pendingMcpServerOverrides before conversation
is created, then persists to conversation metadata. UI->>convStore: setMcpServerOverride(convId, serverName, override) Note right of convStore: override = {enabled: boolean} UI->>convStore: toggleMcpServerForChat(convId, serverName, enabled) activate convStore convStore->>convStore: setMcpServerOverride(convId, serverName, {enabled}) deactivate convStore UI->>convStore: isMcpServerEnabledForChat(convId, serverName) Note right of convStore: Check override → fall back to global MCP config UI->>convStore: getAllMcpServerOverrides(convId) Note right of convStore: Returns all overrides for a conversation UI->>convStore: removeMcpServerOverride(convId, serverName) UI->>convStore: getMcpServerOverride(convId, serverName) %% ═══════════════════════════════════════════════════════════════════════════ 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->>convStore: importConversationsData(parsed) convStore->>DbSvc: importConversations(parsed) Note right of DbSvc: Skips duplicate conversations
(checks existing by ID) DbSvc->>IDB: INSERT conversations + messages (skip existing) convStore->>convStore: loadConversations() deactivate convStore ```