11/// <cts-enable />
22import {
3+ BuiltInLLMMessage ,
34 Cell ,
45 cell ,
56 derive ,
67 handler ,
78 ifElse ,
9+ lift ,
810 NAME ,
911 navigateTo ,
1012 recipe ,
@@ -101,6 +103,46 @@ const toggle = handler<any, { value: Cell<boolean> }>((_, { value }) => {
101103 value . set ( ! value . get ( ) ) ;
102104} ) ;
103105
106+ const messagesToNotifications = lift <
107+ {
108+ messages : BuiltInLLMMessage [ ] ;
109+ seen : Cell < number > ;
110+ notifications : Cell < { id : string ; text : string ; timestamp : number } [ ] > ;
111+ }
112+ > ( ( { messages, seen, notifications } ) => {
113+ if ( messages . length > 0 ) {
114+ if ( seen . get ( ) >= messages . length ) return ;
115+
116+ const latestMessage = messages [ messages . length - 1 ] ;
117+ if ( latestMessage . role === "assistant" ) {
118+ const contentText = typeof latestMessage . content === "string"
119+ ? latestMessage . content
120+ : latestMessage . content . map ( ( part ) => {
121+ if ( part . type === "text" ) {
122+ return part . text ;
123+ } else if ( part . type === "tool-call" ) {
124+ return `Tool call: ${ part . toolName } ` ;
125+ } else if ( part . type === "tool-result" ) {
126+ return part . output . type === "text"
127+ ? part . output . value
128+ : JSON . stringify ( part . output . value ) ;
129+ } else if ( part . type === "image" ) {
130+ return "[Image]" ;
131+ }
132+ return "" ;
133+ } ) . join ( "" ) ;
134+
135+ notifications . push ( {
136+ id : Math . random ( ) . toString ( 36 ) ,
137+ text : contentText ,
138+ timestamp : Date . now ( ) ,
139+ } ) ;
140+
141+ seen . set ( messages . length ) ;
142+ }
143+ }
144+ } ) ;
145+
104146export default recipe < CharmsListInput , CharmsListOutput > (
105147 "DefaultCharmList" ,
106148 ( _ ) => {
@@ -110,6 +152,8 @@ export default recipe<CharmsListInput, CharmsListOutput>(
110152 ) ;
111153 const index = BacklinksIndex ( { allCharms } ) ;
112154 const fabExpanded = cell ( false ) ;
155+ const notifications = cell < { text : string ; timestamp : number } [ ] > ( [ ] ) ;
156+ const seen = cell < number > ( 0 ) ;
113157
114158 const omnibot = Chatbot ( {
115159 messages : [ ] ,
@@ -126,6 +170,14 @@ export default recipe<CharmsListInput, CharmsListOutput>(
126170 } ,
127171 } ) ;
128172
173+ messagesToNotifications ( {
174+ messages : omnibot . messages ,
175+ seen : seen as unknown as Cell < number > ,
176+ notifications : notifications as unknown as Cell <
177+ { id : string ; text : string ; timestamp : number } [ ]
178+ > ,
179+ } ) ;
180+
129181 return {
130182 backlinksIndex : index ,
131183 [ NAME ] : str `DefaultCharmList (${ allCharms . length } )` ,
@@ -215,10 +267,20 @@ export default recipe<CharmsListInput, CharmsListOutput>(
215267 { omnibot . ui . chatLog as any }
216268 </ div >
217269 ) ,
218- fabUI : ifElse (
219- fabExpanded ,
220- omnibot . ui . promptInput ,
221- < ct-button onClick = { toggle ( { value : fabExpanded } ) } > ✨</ ct-button > ,
270+ fabUI : (
271+ < >
272+ < ct-toast-stack
273+ $notifications = { notifications }
274+ position = "top-right"
275+ auto-dismiss = { 5000 }
276+ max-toasts = { 5 }
277+ />
278+ { ifElse (
279+ fabExpanded ,
280+ omnibot . ui . promptInput ,
281+ < ct-button onClick = { toggle ( { value : fabExpanded } ) } > ✨</ ct-button > ,
282+ ) }
283+ </ >
222284 ) ,
223285 } ;
224286 } ,
0 commit comments