1+ import {
2+ saveMessage ,
3+ deleteAllMessages ,
4+ deleteMessagesAfter ,
5+ getMessages ,
6+ updateMessage ,
7+ } from './db' ;
8+
19import type { ToolResponseContent , ToolCalls , ServiceResponse , Metadata } from './executor/types' ;
210
311export type AssistantMessageContentType = 'text' | 'image' ;
@@ -18,13 +26,14 @@ export type UserAttachment = {
1826 value : string ;
1927} ;
2028
21- type BaseMessage = {
29+ export type BaseMessage = {
2230 id : string ;
2331 hidden : boolean ;
2432 ctx : Record < string , unknown > ;
2533 toolCalls ?: undefined ;
2634 contexts ?: undefined ;
2735 attachments ?: undefined ;
36+ init ?: boolean | undefined ;
2837} ;
2938
3039export type ToolResponseMessage = BaseMessage & {
@@ -58,6 +67,7 @@ export type Message = UserMessage | AssistantMessage | ToolResponseMessage;
5867type Namespace = {
5968 history : Message [ ] ;
6069 idRef : Record < string , Message > ;
70+ persist : boolean ;
6171 onAddMessage : < M extends Message = Message > ( msg : M ) => UpdatableHTMLElement < M > | undefined ;
6272} ;
6373
@@ -95,6 +105,10 @@ const addUserMessage = (
95105 }
96106
97107 msgObject . el = namespace . onAddMessage ( msgObject ) ;
108+
109+ if ( namespace . persist ) {
110+ void saveMessage ( key , msgObject ) ;
111+ }
98112} ;
99113
100114const addToolResponseMessage = (
@@ -123,6 +137,10 @@ const addToolResponseMessage = (
123137 }
124138
125139 msgObject . el = namespace . onAddMessage ( msgObject ) ;
140+
141+ if ( namespace . persist ) {
142+ void saveMessage ( key , msgObject ) ;
143+ }
126144} ;
127145
128146const addAssistantMessage = ( key : string , data : ServiceResponse , hidden : boolean = false ) => {
@@ -156,6 +174,10 @@ const addAssistantMessage = (key: string, data: ServiceResponse, hidden: boolean
156174 }
157175
158176 msgObject . el = namespace . onAddMessage ( msgObject ) ;
177+
178+ if ( namespace . persist ) {
179+ void saveMessage ( key , msgObject ) ;
180+ }
159181} ;
160182
161183const updateAssistantMessage = ( key : string , data : ServiceResponse ) => {
@@ -180,6 +202,10 @@ const updateAssistantMessage = (key: string, data: ServiceResponse) => {
180202 if ( msg . __type === 'AssistantMessage' && msg . el && msg . el . update ) {
181203 msg . el . update ( msg ) ;
182204 }
205+
206+ if ( namespace . persist ) {
207+ void updateMessage ( msg ) ;
208+ }
183209} ;
184210
185211const getMessage = ( key : string , id : string ) => {
@@ -191,6 +217,91 @@ const getMessage = (key: string, id: string) => {
191217 return namespace . idRef [ id ] ;
192218} ;
193219
220+ const loadFromDB = async ( key : string , onInitDone ?: ( ) => void ) => {
221+ const messages = await getMessages ( key ) ;
222+ for ( const message of messages ) {
223+ const namespace = _namespace [ message . category ] ;
224+ if ( ! namespace ) {
225+ continue ;
226+ }
227+
228+ if ( message . __type === 'UserMessage' ) {
229+ const msgObject : UserMessage = {
230+ init : true ,
231+ __type : 'UserMessage' ,
232+ content : message . content as string ,
233+ contexts : message . contexts ,
234+ attachments : message . attachments ,
235+ role : 'user' ,
236+ id : message . id ,
237+ hidden : message . hidden ,
238+ ctx : { } ,
239+ } ;
240+
241+ const index = namespace . history . push ( msgObject ) - 1 ;
242+ namespace . idRef [ message . id ] = namespace . history [ index ] ;
243+
244+ msgObject . el = namespace . onAddMessage ( msgObject ) ;
245+
246+ continue ;
247+ }
248+
249+ if ( message . __type === 'AssistantMessage' ) {
250+ const msgObject : AssistantMessage = {
251+ init : true ,
252+ __type : 'AssistantMessage' ,
253+ content : undefined ,
254+ toolCalls : undefined ,
255+ contentType : 'text' ,
256+ role : 'assistant' ,
257+ id : message . id ,
258+ metadata : message . metadata ,
259+ hidden : message . hidden ,
260+ ctx : message . ctx ,
261+ attachments : message . attachments ,
262+ contexts : message . contexts ,
263+ } ;
264+
265+ if ( message . contentType === 'image' ) {
266+ msgObject . content = message . content ;
267+ msgObject . contentType = 'image' ;
268+ } else {
269+ msgObject . content = message . content ;
270+ msgObject . toolCalls = message . toolCalls ;
271+ }
272+
273+ const index = namespace . history . push ( msgObject ) - 1 ;
274+ namespace . idRef [ message . id ] = namespace . history [ index ] ;
275+
276+ msgObject . el = namespace . onAddMessage ( msgObject ) ;
277+ continue ;
278+ }
279+
280+ if ( message . __type === 'ToolResponseMessage' ) {
281+ const msgObject : ToolResponseMessage = {
282+ init : true ,
283+ __type : 'ToolResponseMessage' ,
284+ content : message . content ,
285+ role : 'tool' ,
286+ id : message . id ,
287+ hidden : message . hidden ,
288+ ctx : { } ,
289+ } ;
290+
291+ const index = namespace . history . push ( msgObject ) - 1 ;
292+ if ( message . id ) {
293+ namespace . idRef [ message . id ] = namespace . history [ index ] ;
294+ }
295+
296+ msgObject . el = namespace . onAddMessage ( msgObject ) ;
297+ }
298+ }
299+
300+ if ( onInitDone ) {
301+ onInitDone ( ) ;
302+ }
303+ } ;
304+
194305export type ChatHistory = {
195306 addUserMessage : (
196307 content :
@@ -206,6 +317,7 @@ export type ChatHistory = {
206317 hidden ?: boolean ,
207318 ) => void ;
208319 updateAssistantMessage : ( data : ServiceResponse ) => void ;
320+ syncMessage : ( id : string ) => void ;
209321 getAssistantMessage : ( id : string ) => Message | undefined ;
210322 getMessages : ( ) => Message [ ] ;
211323 getMessagesHistory : ( ) => Pick <
@@ -217,31 +329,41 @@ export type ChatHistory = {
217329} ;
218330
219331export const chatHistory = {
220- init : ( key : string , onAddMessage : Namespace [ 'onAddMessage' ] ) : ChatHistory => {
221- if ( ! _namespace [ key ] ) {
222- _namespace [ key ] = {
332+ init : ( config : {
333+ key : string ;
334+ persist ?: boolean ;
335+ onAddMessage : Namespace [ 'onAddMessage' ] ;
336+ onInitDone ?: ( ) => void ;
337+ } ) : ChatHistory => {
338+ if ( ! _namespace [ config . key ] ) {
339+ _namespace [ config . key ] = {
223340 history : [ ] ,
224341 idRef : { } ,
225- onAddMessage,
342+ persist : config . persist ?? false ,
343+ onAddMessage : config . onAddMessage ,
226344 } ;
345+
346+ if ( config . persist ) {
347+ void loadFromDB ( config . key , config . onInitDone ) ;
348+ }
227349 }
228350
229- if ( onAddMessage ) {
230- _namespace [ key ] . onAddMessage = onAddMessage ;
351+ if ( config . onAddMessage ) {
352+ _namespace [ config . key ] . onAddMessage = config . onAddMessage ;
231353 }
232354
233355 return {
234356 addUserMessage : ( content , hidden = false ) => {
235357 const id = 'user-msg-' + Date . now ( ) + Math . round ( Math . random ( ) * 1000 ) ;
236- addUserMessage ( key , id , content , hidden ) ;
358+ addUserMessage ( config . key , id , content , hidden ) ;
237359 } ,
238360 addAssistantMessage : ( data , hidden = false ) => {
239- addAssistantMessage ( key , data , hidden ) ;
361+ addAssistantMessage ( config . key , data , hidden ) ;
240362 } ,
241363
242364 addToolCallsMessage : ( toolCalls , hidden = false ) => {
243365 addAssistantMessage (
244- key ,
366+ config . key ,
245367 {
246368 __type : 'ToolsData' ,
247369 id : crypto . randomUUID ( ) ,
@@ -256,19 +378,31 @@ export const chatHistory = {
256378 ) ;
257379 } ,
258380 addToolResponseMessage : ( id , content , hidden = false ) => {
259- addToolResponseMessage ( key , id , content , hidden ) ;
381+ addToolResponseMessage ( config . key , id , content , hidden ) ;
260382 } ,
261383 updateAssistantMessage : ( data ) => {
262- updateAssistantMessage ( key , data ) ;
384+ updateAssistantMessage ( config . key , data ) ;
385+ } ,
386+ syncMessage : ( id ) => {
387+ const namespace = _namespace [ config . key ] ;
388+ if ( ! namespace ) {
389+ return ;
390+ }
391+
392+ if ( ! namespace . idRef [ id ] ) {
393+ return ;
394+ }
395+
396+ void updateMessage ( namespace . idRef [ id ] ) ;
263397 } ,
264398 getAssistantMessage : ( id ) => {
265- return getMessage ( key , id ) ;
399+ return getMessage ( config . key , id ) ;
266400 } ,
267401 getMessages : ( ) => {
268- return _namespace [ key ] . history ;
402+ return _namespace [ config . key ] . history ;
269403 } ,
270404 getMessagesHistory : ( ) => {
271- return _namespace [ key ] . history . map ( ( m ) => ( {
405+ return _namespace [ config . key ] . history . map ( ( m ) => ( {
272406 role : m . role ,
273407 content : m . content ,
274408 toolCalls : m . toolCalls ,
@@ -277,22 +411,26 @@ export const chatHistory = {
277411 } ) ) ;
278412 } ,
279413 clearHistory : ( ) => {
280- _namespace [ key ] . history . forEach ( ( msg ) => {
414+ _namespace [ config . key ] . history . forEach ( ( msg ) => {
281415 msg . el ?. remove ( ) ;
282416 } ) ;
283- _namespace [ key ] . history = [ ] ;
417+ _namespace [ config . key ] . history = [ ] ;
418+
419+ void deleteAllMessages ( config . key ) ;
284420 } ,
285421 clearHistoryFrom : ( id : string ) => {
286- const startIndex = _namespace [ key ] . history . findIndex ( ( obj ) => obj . id === id ) ;
422+ const startIndex = _namespace [ config . key ] . history . findIndex ( ( obj ) => obj . id === id ) ;
287423
288424 if ( startIndex !== - 1 ) {
289- for ( let i = startIndex ; i < _namespace [ key ] . history . length ; i ++ ) {
290- const obj = _namespace [ key ] . history [ i ] ;
425+ for ( let i = startIndex ; i < _namespace [ config . key ] . history . length ; i ++ ) {
426+ const obj = _namespace [ config . key ] . history [ i ] ;
291427 obj . el ?. remove ( ) ;
292428 }
293429
294- _namespace [ key ] . history . splice ( startIndex ) ;
430+ _namespace [ config . key ] . history . splice ( startIndex ) ;
295431 }
432+
433+ void deleteMessagesAfter ( config . key , id ) ;
296434 } ,
297435 } ;
298436 } ,
0 commit comments