@@ -122,6 +122,7 @@ type ChatInput = {
122122 messages : Default < Array < BuiltInLLMMessage > , [ ] > ;
123123 tools : any ;
124124 theme ?: any ;
125+ system ?: string ;
125126} ;
126127
127128type PromptAttachment = {
@@ -268,15 +269,71 @@ const listMentionable = handler<
268269 } ,
269270) ;
270271
272+ const listRecent = handler <
273+ {
274+ /** A cell to store the result text */
275+ result : Cell < string > ;
276+ } ,
277+ { recentCharms : MentionableCharm [ ] }
278+ > (
279+ ( args , state ) => {
280+ try {
281+ const namesList = state . recentCharms . map ( ( charm ) => charm [ NAME ] ) ;
282+ args . result . set ( JSON . stringify ( namesList ) ) ;
283+ } catch ( error ) {
284+ args . result . set ( `Error: ${ ( error as any ) ?. message || "<error>" } ` ) ;
285+ }
286+ } ,
287+ ) ;
288+
271289export default recipe < ChatInput , ChatOutput > (
272290 "Chat" ,
273- ( { messages, tools, theme } ) => {
291+ ( { messages, tools, theme, system } ) => {
274292 const model = cell < string > ( "anthropic:claude-sonnet-4-5" ) ;
275293 const allAttachments = cell < Array < PromptAttachment > > ( [ ] ) ;
276294 const mentionable = schemaifyWish < MentionableCharm [ ] > ( "#mentionable" ) ;
295+ const recentCharms = schemaifyWish < MentionableCharm [ ] > ( "#recent" ) ;
296+
297+ // Auto-attach the most recent charm (union with user attachments)
298+ const attachmentsWithRecent = derive (
299+ [ allAttachments , recentCharms ] ,
300+ ( [ userAttachments , recent ] : [
301+ Array < PromptAttachment > ,
302+ Array < MentionableCharm > ,
303+ ] ) : Array < PromptAttachment > => {
304+ const attachments = userAttachments || [ ] ;
305+
306+ // If there's a most recent charm, auto-inject it
307+ if ( recent && recent . length > 0 ) {
308+ const mostRecent = recent [ 0 ] ;
309+ const mostRecentName = mostRecent [ NAME ] ;
310+
311+ // Check if it's already in the attachments
312+ const alreadyAttached = attachments . some (
313+ ( a ) => a . type === "mention" && a . name === mostRecentName ,
314+ ) ;
315+
316+ if ( ! alreadyAttached && mostRecentName ) {
317+ // Add the most recent charm to the beginning
318+ const id = `attachment-auto-recent-${ mostRecentName } ` ;
319+ return [
320+ {
321+ id,
322+ name : mostRecentName ,
323+ type : "mention" as const ,
324+ charm : mostRecent ,
325+ } ,
326+ ...attachments ,
327+ ] ;
328+ }
329+ }
277330
278- // Derive tools from attachments
279- const dynamicTools = derive ( allAttachments , ( attachments ) => {
331+ return attachments ;
332+ } ,
333+ ) ;
334+
335+ // Derive tools from attachments (including auto-attached recent charm)
336+ const dynamicTools = derive ( attachmentsWithRecent , ( attachments ) => {
280337 const tools : Record < string , any > = { } ;
281338
282339 for ( const attachment of attachments || [ ] ) {
@@ -296,16 +353,22 @@ export default recipe<ChatInput, ChatOutput>(
296353 navigateToAttachment : {
297354 description :
298355 "Navigate to a mentionable by its ID in the attachments array." ,
299- handler : navigateToAttachment ( { allAttachments } ) ,
356+ handler : navigateToAttachment ( {
357+ allAttachments : attachmentsWithRecent ,
358+ } ) ,
300359 } ,
301360 listAttachments : {
302361 description : "List all attachments in the attachments array." ,
303- handler : listAttachments ( { allAttachments } ) ,
362+ handler : listAttachments ( { allAttachments : attachmentsWithRecent } ) ,
304363 } ,
305364 listMentionable : {
306365 description : "List all mentionable NAMEs in the space." ,
307366 handler : listMentionable ( { mentionable } ) ,
308367 } ,
368+ listRecent : {
369+ description : "List all recently viewed charms in the space." ,
370+ handler : listRecent ( { recentCharms } ) ,
371+ } ,
309372 addAttachment : {
310373 description :
311374 "Add a new attachment to the attachments array by its mentionable NAME." ,
@@ -330,8 +393,9 @@ export default recipe<ChatInput, ChatOutput>(
330393
331394 const { addMessage, cancelGeneration, pending, flattenedTools } = llmDialog (
332395 {
333- system :
334- "You are a polite but efficient assistant. Think Star Trek computer - helpful and professional without unnecessary conversation. Let your actions speak for themselves.\n\nTool usage priority:\n- Search this space first: listMentionable → addAttachment to access items\n- Search externally only when clearly needed: searchWeb for current events, external information, or when nothing relevant exists in the space\n\nBe matter-of-fact. Prefer action to explanation." ,
396+ system : derive ( system , ( s ) =>
397+ s ??
398+ "You are a polite but efficient assistant." ) ,
335399 messages,
336400 tools : mergedTools ,
337401 model,
@@ -362,7 +426,10 @@ export default recipe<ChatInput, ChatOutput>(
362426 $mentionable = { mentionable }
363427 modelItems = { items }
364428 $model = { model }
365- onct-send = { sendMessage ( { addMessage, allAttachments } ) }
429+ onct-send = { sendMessage ( {
430+ addMessage,
431+ allAttachments : attachmentsWithRecent ,
432+ } ) }
366433 onct-stop = { cancelGeneration }
367434 onct-attachment-add = { addAttachment ( { allAttachments } ) }
368435 onct-attachment-remove = { removeAttachment ( { allAttachments } ) }
@@ -389,7 +456,7 @@ export default recipe<ChatInput, ChatOutput>(
389456 const attachmentsAndTools = (
390457 < ct-hstack align = "center" gap = "1" >
391458 < ct-attachments-bar
392- attachments = { allAttachments }
459+ attachments = { attachmentsWithRecent }
393460 removable
394461 onct-remove = { removeAttachment ( { allAttachments } ) }
395462 />
@@ -431,7 +498,7 @@ export default recipe<ChatInput, ChatOutput>(
431498 } ) ,
432499 cancelGeneration,
433500 title,
434- attachments : allAttachments ,
501+ attachments : attachmentsWithRecent ,
435502 tools : flattenedTools ,
436503 ui : {
437504 chatLog,
0 commit comments