@@ -79,7 +79,7 @@ function deferred<T>() {
7979}
8080
8181async function flushPromises ( ) {
82- for ( let index = 0 ; index < 8 ; index += 1 ) {
82+ for ( let index = 0 ; index < 16 ; index += 1 ) {
8383 await Promise . resolve ( ) ;
8484 }
8585}
@@ -1743,6 +1743,111 @@ describe('conversationStore pagination', () => {
17431743 expect ( useConversationStore . getState ( ) . enabledMemoryNamespaceIds ) . toEqual ( [ ] ) ;
17441744 } ) ;
17451745
1746+ it ( 'tracks context compression loading by conversation id' , async ( ) => {
1747+ const summary = {
1748+ id : 'summary-1' ,
1749+ conversation_id : 'conv-1' ,
1750+ summary_text : 'compressed context' ,
1751+ compressed_until_message_id : 'msg-1' ,
1752+ token_count : 12 ,
1753+ model_used : 'summary-model' ,
1754+ created_at : 1 ,
1755+ updated_at : 1 ,
1756+ } ;
1757+ const compression = deferred < typeof summary > ( ) ;
1758+ invokeMock . mockImplementation ( ( cmd : string , args : Record < string , unknown > ) => {
1759+ if ( cmd === 'compress_context' ) {
1760+ expect ( args . conversationId ) . toBe ( 'conv-1' ) ;
1761+ return compression . promise ;
1762+ }
1763+ if ( cmd === 'list_messages_page' ) {
1764+ return Promise . resolve ( makePage ( [ makeMessage ( 1 , 'conv-1' ) ] , false ) ) ;
1765+ }
1766+ throw new Error ( `unexpected command: ${ cmd } ` ) ;
1767+ } ) ;
1768+ const { useConversationStore } = await import ( '../conversationStore' ) ;
1769+
1770+ useConversationStore . setState ( {
1771+ activeConversationId : 'conv-1' ,
1772+ conversations : [
1773+ makeConversation ( 'conv-1' ) ,
1774+ makeConversation ( 'conv-2' ) ,
1775+ ] as never [ ] ,
1776+ messages : [ makeMessage ( 1 , 'conv-1' ) ] ,
1777+ } ) ;
1778+
1779+ const pending = useConversationStore . getState ( ) . compressContext ( ) ;
1780+ await flushPromises ( ) ;
1781+
1782+ expect ( useConversationStore . getState ( ) . compressingConversationId ) . toBe ( 'conv-1' ) ;
1783+ useConversationStore . setState ( { activeConversationId : 'conv-2' } ) ;
1784+ expect ( useConversationStore . getState ( ) . compressingConversationId ) . toBe ( 'conv-1' ) ;
1785+
1786+ compression . resolve ( summary ) ;
1787+ await pending ;
1788+
1789+ expect ( useConversationStore . getState ( ) . compressingConversationId ) . toBeNull ( ) ;
1790+ } ) ;
1791+
1792+ it ( 'applies compression events only to the matching active conversation' , async ( ) => {
1793+ const listeners = new Map < string , ( event : { payload : unknown } ) => void > ( ) ;
1794+ listenMock . mockImplementation ( async ( eventName : string , handler : ( event : { payload : unknown } ) => void ) => {
1795+ listeners . set ( eventName , handler ) ;
1796+ return ( ) => { } ;
1797+ } ) ;
1798+ const { useConversationStore } = await import ( '../conversationStore' ) ;
1799+ const marker = {
1800+ ...makeMessage ( 50 , 'conv-1' ) ,
1801+ role : 'system' ,
1802+ content : '<!-- context-compressed -->' ,
1803+ } ;
1804+ const otherMarker = {
1805+ ...makeMessage ( 60 , 'conv-2' ) ,
1806+ role : 'system' ,
1807+ content : '<!-- context-compressed -->' ,
1808+ } ;
1809+ const summary = {
1810+ id : 'summary-1' ,
1811+ conversation_id : 'conv-1' ,
1812+ summary_text : 'compressed context' ,
1813+ compressed_until_message_id : 'msg-1' ,
1814+ token_count : 12 ,
1815+ model_used : 'summary-model' ,
1816+ created_at : 1 ,
1817+ updated_at : 1 ,
1818+ } ;
1819+
1820+ useConversationStore . setState ( {
1821+ activeConversationId : 'conv-1' ,
1822+ conversations : [
1823+ makeConversation ( 'conv-1' ) ,
1824+ makeConversation ( 'conv-2' ) ,
1825+ ] as never [ ] ,
1826+ messages : [ makeMessage ( 1 , 'conv-1' ) ] ,
1827+ } ) ;
1828+
1829+ await useConversationStore . getState ( ) . startStreamListening ( ) ;
1830+
1831+ listeners . get ( 'conversation:compressed' ) ?.( {
1832+ payload : {
1833+ conversation_id : 'conv-2' ,
1834+ marker_message : otherMarker ,
1835+ summary : { ...summary , conversation_id : 'conv-2' } ,
1836+ } ,
1837+ } ) ;
1838+ expect ( useConversationStore . getState ( ) . messages . map ( ( message ) => message . id ) ) . toEqual ( [ 'msg-1' ] ) ;
1839+
1840+ listeners . get ( 'conversation:compressed' ) ?.( {
1841+ payload : {
1842+ conversation_id : 'conv-1' ,
1843+ marker_message : marker ,
1844+ summary,
1845+ } ,
1846+ } ) ;
1847+
1848+ expect ( useConversationStore . getState ( ) . messages . map ( ( message ) => message . id ) ) . toEqual ( [ 'msg-1' , 'msg-50' ] ) ;
1849+ } ) ;
1850+
17461851 it ( 'persists reasoning level changes separately from legacy thinking budget' , async ( ) => {
17471852 invokeMock . mockResolvedValueOnce ( makeConversation ( 'conv-1' , { thinking_budget : 4096 , thinking_level : 'high' } ) ) ;
17481853 const { useConversationStore } = await import ( '../conversationStore' ) ;
0 commit comments