```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
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:
- 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 %% ═══════════════════════════════════════════════════════════════════════════ Note over UI,IDB: 📊 MODALITY TRACKING %% ═══════════════════════════════════════════════════════════════════════════ Note over convStore: usedModalities = $derived.by(() => {
calculateModalitiesFromMessages(activeMessages)
}) Note over convStore: Scans activeMessages for attachments:
- IMAGE → vision: true
- PDF (processedAsImages) → vision: true
- AUDIO → audio: true UI->>convStore: getModalitiesUpToMessage(msgId) Note right of convStore: Used for regeneration validation
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 ```