File size: 10,218 Bytes
41a5ab2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | ```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
```
|