char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
0afb805b1
char/aliceai-t5-moe
1// Field updates to the active conversation must keep the object identity 2// stable: effects that track the identity ( the chat screen's sibling-info 3// refresh ) refire on every identity change, which used to trigger a full 4// message refetch on every send and tool result. 5 6import { beforeEach , describe , expect , it , vi } from 'vitest' ; 7 8vi . mock ( '$lib/services/database.service' , () => ({ 9DatabaseService :{ 10getConversation :vi . fn (), 11getConversationMessages :vi . fn (), 12updateConversation :vi . fn (), 13updateCurrentNode :vi . fn () 14} 15})); 16 17import { DatabaseService } from '$lib/services/database.service' ; 18import { conversationsStore } from '$lib/stores/conversations/index.svelte' ; 19import type { DatabaseConversation , DatabaseMessage } from '$lib/types/database' ; 20 21const getConversationMock = vi . mocked ( DatabaseService . getConversation ); 22const getMessagesMock = vi . mocked ( DatabaseService . getConversationMessages ); 23const updateCurrentNodeMock = vi . mocked ( DatabaseService . updateCurrentNode ); 24 25function makeConversation ( overrides :Partial < DatabaseConversation > = {}) :DatabaseConversation { 26return { 27currNode :'node-1' , 28id :'conv-1' , 29lastModified :1000 , 30name :'conversation' , 31 ...overrides 32}; 33} 34 35async function loadActive ( conversation :DatabaseConversation , messages :DatabaseMessage []) { 36getConversationMock . mockResolvedValue ( conversation ); 37getMessagesMock . mockResolvedValue ( messages ); 38 39expect ( await conversationsStore . loadConversation ( conversation . id )). toBe ( true ); 40} 41 42beforeEach (() => { 43getConversationMock . mockReset (); 44getMessagesMock . mockReset (); 45updateCurrentNodeMock . mockReset (); 46updateCurrentNodeMock . mockResolvedValue ( undefined ); 47vi . mocked ( DatabaseService . updateConversation ). mockReset (); 48vi . mocked ( DatabaseService . updateConversation ). mockResolvedValue ( undefined ); 49}); 50 51describe ( 'active conversation identity' , () => { 52it ( 'hands the load read off exactly once' , async () => { 53await loadActive ( makeConversation (), []); 54 55expect ( conversationsStore . consumeLastLoadedMessages ( 'conv-1' )). toEqual ([]); 56// a second consume is a miss: branch actions must fall back to a refetch 57expect ( conversationsStore . consumeLastLoadedMessages ( 'conv-1' )). toBeNull (); 58}); 59 60it ( 'writes currNode in place on updateCurrentNode' , async () => { 61await loadActive ( makeConversation (), []); 62const before = conversationsStore . activeConversation ; 63 64await conversationsStore . updateCurrentNode ( 'node-2' ); 65 66expect ( conversationsStore . activeConversation ). toBe ( before ); 67expect ( conversationsStore . activeConversation ?. currNode ). toBe ( 'node-2' ); 68}); 69 70it ( 'writes renamed and pinned fields in place on applyConversationUpdate' , async () => { 71await loadActive ( makeConversation (), []); 72const before = conversationsStore . activeConversation ; 73 74conversationsStore . applyConversationUpdate ( 'conv-1' , { name :'renamed' , pinned :true }); 75 76expect ( conversationsStore . activeConversation ). toBe ( before ); 77expect ( conversationsStore . activeConversation ?. name ). toBe ( 'renamed' ); 78expect ( conversationsStore . activeConversation ?. pinned ). toBe ( true ); 79}); 80 81it ( 'writes lastModified in place on updateConversationTimestamp' , async () => { 82await loadActive ( makeConversation (), []); 83const before = conversationsStore . activeConversation ; 84 85conversationsStore . updateConversationTimestamp ( 'conv-1' ); 86 87expect ( conversationsStore . activeConversation ). toBe ( before ); 88expect ( conversationsStore . activeConversation ?. lastModified ). toBeGreaterThan ( 1000 ); 89}); 90});