@@ -11,6 +11,7 @@ import {
1111 llmDialog ,
1212 NAME ,
1313 navigateTo ,
14+ Opaque ,
1415 recipe ,
1516 Stream ,
1617 UI ,
@@ -19,6 +20,10 @@ import {
1920} from "commontools" ;
2021import { type MentionableCharm } from "./backlinks-index.tsx" ;
2122
23+ function schemaifyWish < T > ( path : string , def : Opaque < T > ) {
24+ return derive < T , T > ( wish < T > ( path , def ) , ( i ) => i ) ;
25+ }
26+
2227const addAttachment = handler <
2328 {
2429 detail : {
@@ -181,16 +186,6 @@ export const TitleGenerator = recipe<
181186 return title ;
182187} ) ;
183188
184- function getMentionable ( ) {
185- return derive < Cell < MentionableCharm [ ] > , Cell < MentionableCharm [ ] > > (
186- wish < MentionableCharm [ ] > (
187- "/backlinksIndex/mentionable" ,
188- [ ] ,
189- ) as unknown as Cell < MentionableCharm [ ] > ,
190- ( i ) => i ,
191- ) ;
192- }
193-
194189const navigateToAttachment = handler <
195190 { id : string } ,
196191 { allAttachments : Array < PromptAttachment > }
@@ -211,12 +206,77 @@ const listAttachments = handler<
211206 } ) ) ) ) ;
212207} ) ;
213208
209+ const addAttachmentTool = handler <
210+ {
211+ mentionableName : string ;
212+ } ,
213+ {
214+ mentionable : Array < MentionableCharm > ;
215+ allAttachments : Cell < Array < PromptAttachment > > ;
216+ }
217+ > ( ( { mentionableName } , { mentionable, allAttachments } ) => {
218+ const charm = mentionable . find ( ( c ) => c [ NAME ] === mentionableName ) ;
219+
220+ // borrowed from `ct-prompt-input` to match
221+ const id = `attachment-${ Date . now ( ) } -${
222+ Math . random ( ) . toString ( 36 ) . substring ( 2 , 9 )
223+ } `;
224+
225+ if ( ! charm ) {
226+ throw new Error (
227+ `Unknown mentionable "${ mentionableName } ", cannot add attachment.` ,
228+ ) ;
229+ }
230+
231+ allAttachments . push ( {
232+ id,
233+ name : mentionableName ,
234+ type : "mention" ,
235+ charm,
236+ } ) ;
237+ } ) ;
238+
239+ const removeAttachmentTool = handler <
240+ {
241+ mentionableName : string ;
242+ } ,
243+ {
244+ allAttachments : Cell < Array < PromptAttachment > > ;
245+ }
246+ > ( ( { mentionableName } , { allAttachments } ) => {
247+ allAttachments . set (
248+ allAttachments . get ( ) . filter ( ( attachment ) =>
249+ attachment . name !== mentionableName
250+ ) ,
251+ ) ;
252+ } ) ;
253+
254+ const listMentionable = handler <
255+ {
256+ /** A cell to store the result text */
257+ result : Cell < string > ;
258+ } ,
259+ { mentionable : MentionableCharm [ ] }
260+ > (
261+ ( args , state ) => {
262+ try {
263+ const namesList = state . mentionable . map ( ( charm ) => charm [ NAME ] ) ;
264+ args . result . set ( JSON . stringify ( namesList ) ) ;
265+ } catch ( error ) {
266+ args . result . set ( `Error: ${ ( error as any ) ?. message || "<error>" } ` ) ;
267+ }
268+ } ,
269+ ) ;
270+
214271export default recipe < ChatInput , ChatOutput > (
215272 "Chat" ,
216273 ( { messages, tools, theme } ) => {
217- const mentionable = getMentionable ( ) ;
218274 const model = cell < string > ( "anthropic:claude-sonnet-4-5" ) ;
219275 const allAttachments = cell < Array < PromptAttachment > > ( [ ] ) ;
276+ const mentionable = schemaifyWish < MentionableCharm [ ] > (
277+ "/backlinksIndex/mentionable" ,
278+ [ ] ,
279+ ) ;
220280
221281 // Derive tools from attachments
222282 const dynamicTools = derive ( allAttachments , ( attachments ) => {
@@ -245,6 +305,20 @@ export default recipe<ChatInput, ChatOutput>(
245305 description : "List all attachments in the attachments array." ,
246306 handler : listAttachments ( { allAttachments } ) ,
247307 } ,
308+ listMentionable : {
309+ description : "List all mentionable NAMEs in the space." ,
310+ handler : listMentionable ( { mentionable } ) ,
311+ } ,
312+ addAttachment : {
313+ description :
314+ "Add a new attachment to the attachments array by its mentionable NAME." ,
315+ handler : addAttachmentTool ( { mentionable, allAttachments } ) ,
316+ } ,
317+ removeAttachment : {
318+ description :
319+ "Remove an attachment from the attachments array by its mentionable NAME." ,
320+ handler : removeAttachmentTool ( { allAttachments } ) ,
321+ } ,
248322 } ;
249323
250324 // Merge static and dynamic tools
0 commit comments