11/// <cts-enable />
22import {
3- BuiltInLLMMessage ,
43 Cell ,
5- cell ,
64 derive ,
75 handler ,
8- ifElse ,
9- lift ,
106 NAME ,
117 navigateTo ,
12- patternTool ,
138 recipe ,
149 str ,
1510 UI ,
@@ -21,7 +16,7 @@ import ChatbotOutliner from "./chatbot-outliner.tsx";
2116import { default as Note } from "./note.tsx" ;
2217import BacklinksIndex , { type MentionableCharm } from "./backlinks-index.tsx" ;
2318import ChatList from "./chatbot-list-view.tsx" ;
24- import { calculator , readWebpage , searchWeb } from "./common-tools .tsx" ;
19+ import OmniboxFAB from "./omnibox-fab .tsx" ;
2520
2621type MinimalCharm = {
2722 [ NAME ] ?: string ;
@@ -61,10 +56,16 @@ const removeCharm = handler<
6156 console . log ( "charmListCopy before" , charmListCopy . length ) ;
6257 charmListCopy . splice ( index , 1 ) ;
6358 console . log ( "charmListCopy after" , charmListCopy . length ) ;
64- state . allCharms . resolveAsCell ( ) . set ( charmListCopy ) ;
59+ state . allCharms . set ( charmListCopy ) ;
6560 }
6661} ) ;
6762
63+ const toggleFab = handler < any , { fabExpanded : Cell < boolean > } > (
64+ ( _ , { fabExpanded } ) => {
65+ fabExpanded . set ( ! fabExpanded . get ( ) ) ;
66+ } ,
67+ ) ;
68+
6869const spawnChatList = handler < void , void > ( ( _ , __ ) => {
6970 return navigateTo ( ChatList ( {
7071 selectedCharm : { charm : undefined } ,
@@ -97,88 +98,17 @@ const spawnNote = handler<void, void>((_, __) => {
9798 } ) ) ;
9899} ) ;
99100
100- const toggle = handler < any , { value : Cell < boolean > } > ( ( _ , { value } ) => {
101- value . set ( ! value . get ( ) ) ;
102- } ) ;
103-
104- const messagesToNotifications = lift <
105- {
106- messages : BuiltInLLMMessage [ ] ;
107- seen : Cell < number > ;
108- notifications : Cell < { text : string ; timestamp : number } [ ] > ;
109- }
110- > ( ( { messages, seen, notifications } ) => {
111- if ( messages . length > 0 ) {
112- if ( seen . get ( ) >= messages . length ) {
113- // If messages length went backwards, reset seen counter
114- if ( seen . get ( ) > messages . length ) {
115- seen . set ( 0 ) ;
116- } else {
117- return ;
118- }
119- }
120-
121- const latestMessage = messages [ messages . length - 1 ] ;
122- if ( latestMessage . role === "assistant" ) {
123- const contentText = typeof latestMessage . content === "string"
124- ? latestMessage . content
125- : latestMessage . content . map ( ( part ) => {
126- if ( part . type === "text" ) {
127- return part . text ;
128- } else if ( part . type === "tool-call" ) {
129- return `Tool call: ${ part . toolName } ` ;
130- } else if ( part . type === "tool-result" ) {
131- return part . output . type === "text"
132- ? part . output . value
133- : JSON . stringify ( part . output . value ) ;
134- } else if ( part . type === "image" ) {
135- return "[Image]" ;
136- }
137- return "" ;
138- } ) . join ( "" ) ;
139-
140- notifications . push ( {
141- text : contentText ,
142- timestamp : Date . now ( ) ,
143- } ) ;
144-
145- seen . set ( messages . length ) ;
146- }
147- }
148- } ) ;
149-
150101export default recipe < CharmsListInput , CharmsListOutput > (
151102 "DefaultCharmList" ,
152103 ( _ ) => {
153104 const allCharms = derive < MentionableCharm [ ] , MentionableCharm [ ] > (
154- wish < MentionableCharm [ ] > ( "#allCharms" , [ ] ) ,
105+ wish < MentionableCharm [ ] > ( "#allCharms" ) ,
155106 ( c ) => c ,
156107 ) ;
157108 const index = BacklinksIndex ( { allCharms } ) ;
158- const fabExpanded = cell ( false ) ;
159- const notifications = cell < { text : string ; timestamp : number } [ ] > ( [ ] ) ;
160- const seen = cell < number > ( 0 ) ;
161-
162- const omnibot = Chatbot ( {
163- messages : [ ] ,
164- tools : {
165- searchWeb : {
166- pattern : searchWeb ,
167- } ,
168- readWebpage : {
169- pattern : readWebpage ,
170- } ,
171- // Example of using patternTool with an existing recipe and extra params
172- calculator : patternTool ( calculator , { base : 10 } ) ,
173- } ,
174- } ) ;
175109
176- messagesToNotifications ( {
177- messages : omnibot . messages ,
178- seen : seen as unknown as Cell < number > ,
179- notifications : notifications as unknown as Cell <
180- { id : string ; text : string ; timestamp : number } [ ]
181- > ,
110+ const fab = OmniboxFAB ( {
111+ mentionable : index . mentionable as unknown as Cell < MentionableCharm [ ] > ,
182112 } ) ;
183113
184114 return {
@@ -192,14 +122,20 @@ export default recipe<CharmsListInput, CharmsListOutput>(
192122 preventDefault
193123 onct-keybind = { spawnChatList ( ) }
194124 />
195-
196125 < ct-keybind
197- code = "Escape"
126+ code = "KeyO"
127+ meta
198128 preventDefault
199- onct-keybind = { toggle ( { value : fabExpanded } ) }
129+ onct-keybind = { toggleFab ( { fabExpanded : fab . fabExpanded } ) }
130+ />
131+ < ct-keybind
132+ code = "KeyO"
133+ ctrl
134+ preventDefault
135+ onct-keybind = { toggleFab ( { fabExpanded : fab . fabExpanded } ) }
200136 />
201137
202- < ct-toolbar slot = "header" >
138+ < ct-toolbar slot = "header" sticky >
203139 < div slot = "start" >
204140 < ct-button
205141 onClick = { spawnChatList ( ) }
@@ -264,28 +200,8 @@ export default recipe<CharmsListInput, CharmsListOutput>(
264200 </ ct-vscroll >
265201 </ ct-screen >
266202 ) ,
267- sidebarUI : (
268- < div >
269- { /* TODO(bf): Remove once we fix types to not require ReactNode */ }
270- { omnibot . ui . attachmentsAndTools as any }
271- { omnibot . ui . chatLog as any }
272- </ div >
273- ) ,
274- fabUI : (
275- < >
276- < ct-toast-stack
277- $notifications = { notifications }
278- position = "top-right"
279- auto-dismiss = { 5000 }
280- max-toasts = { 5 }
281- />
282- { ifElse (
283- fabExpanded ,
284- omnibot . ui . promptInput ,
285- < ct-button onClick = { toggle ( { value : fabExpanded } ) } > ✨</ ct-button > ,
286- ) }
287- </ >
288- ) ,
203+ sidebarUI : undefined ,
204+ fabUI : fab [ UI ] ,
289205 } ;
290206 } ,
291207) ;
0 commit comments