@@ -123,10 +123,67 @@ function extractRecentTools(
123123 return tools
124124}
125125
126+ // Tracks how many memory entries a memory_list call saw so tool.execute.after
127+ // can render a meaningful title without re-reading the filesystem. Keyed by
128+ // callID, which uniquely identifies a single tool invocation.
129+ const memoryListCountByCallID = new Map < string , number > ( )
130+ const memorySearchCountByCallID = new Map < string , number > ( )
131+
132+ function buildMemoryToolTitle (
133+ toolID : string ,
134+ args : Record < string , unknown > | undefined ,
135+ callID : string | undefined ,
136+ ) : string | undefined {
137+ switch ( toolID ) {
138+ case "memory_save" : {
139+ const type = typeof args ?. type === "string" ? args . type : ""
140+ const name = typeof args ?. name === "string" ? args . name : ""
141+ if ( type && name ) return `${ type } : ${ name } `
142+ if ( name ) return name
143+ return undefined
144+ }
145+ case "memory_delete" :
146+ case "memory_read" : {
147+ const fileName = typeof args ?. file_name === "string" ? args . file_name : ""
148+ return fileName || undefined
149+ }
150+ case "memory_list" : {
151+ const count = callID ? memoryListCountByCallID . get ( callID ) : undefined
152+ if ( callID ) memoryListCountByCallID . delete ( callID )
153+ if ( count === undefined ) return "list memories"
154+ return `${ count } ${ count === 1 ? "memory" : "memories" } `
155+ }
156+ case "memory_search" : {
157+ const query = typeof args ?. query === "string" ? args . query : ""
158+ const count = callID ? memorySearchCountByCallID . get ( callID ) : undefined
159+ if ( callID ) memorySearchCountByCallID . delete ( callID )
160+ if ( query && count !== undefined ) {
161+ return `"${ query } " · ${ count } ${ count === 1 ? "match" : "matches" } `
162+ }
163+ if ( query ) return `"${ query } "`
164+ return undefined
165+ }
166+ default :
167+ return undefined
168+ }
169+ }
170+
171+ function getCallID ( ctx : unknown ) : string | undefined {
172+ if ( ! ctx || typeof ctx !== "object" ) return undefined
173+ const v = ( ctx as { callID ?: unknown } ) . callID
174+ return typeof v === "string" ? v : undefined
175+ }
176+
126177export const MemoryPlugin : Plugin = async ( { worktree } ) => {
127178 getMemoryDir ( worktree )
128179
129180 return {
181+ "tool.execute.after" : async ( input , output ) => {
182+ if ( ! input . tool . startsWith ( "memory_" ) ) return
183+ const title = buildMemoryToolTitle ( input . tool , input . args , input . callID )
184+ if ( title ) output . title = title
185+ } ,
186+
130187 "experimental.chat.messages.transform" : async ( _input , output ) => {
131188 const { query, sessionID } = getLastUserQuery ( output . messages )
132189
@@ -219,7 +276,7 @@ export const MemoryPlugin: Plugin = async ({ worktree }) => {
219276 "Memory content. For feedback/project types, structure as: rule/fact, then **Why:** and **How to apply:** lines" ,
220277 ) ,
221278 } ,
222- async execute ( args ) {
279+ async execute ( args , _ctx ) {
223280 const filePath = saveMemory ( worktree , args . file_name , args . name , args . description , args . type , args . content )
224281 return `Memory saved to ${ filePath } `
225282 } ,
@@ -230,7 +287,7 @@ export const MemoryPlugin: Plugin = async ({ worktree }) => {
230287 args : {
231288 file_name : tool . schema . string ( ) . describe ( "File name of the memory to delete (with or without .md extension)" ) ,
232289 } ,
233- async execute ( args ) {
290+ async execute ( args , _ctx ) {
234291 const deleted = deleteMemory ( worktree , args . file_name )
235292 return deleted ? `Memory "${ args . file_name } " deleted.` : `Memory "${ args . file_name } " not found.`
236293 } ,
@@ -242,8 +299,10 @@ export const MemoryPlugin: Plugin = async ({ worktree }) => {
242299 "Use this to check what memories exist before saving a new one (to avoid duplicates) " +
243300 "or when you need to recall what's been stored." ,
244301 args : { } ,
245- async execute ( ) {
302+ async execute ( _args , ctx ) {
246303 const entries = listMemories ( worktree )
304+ const callID = getCallID ( ctx )
305+ if ( callID ) memoryListCountByCallID . set ( callID , entries . length )
247306 if ( entries . length === 0 ) {
248307 return "No memories saved yet."
249308 }
@@ -261,8 +320,10 @@ export const MemoryPlugin: Plugin = async ({ worktree }) => {
261320 args : {
262321 query : tool . schema . string ( ) . describe ( "Search query — searches across name, description, and content" ) ,
263322 } ,
264- async execute ( args ) {
323+ async execute ( args , ctx ) {
265324 const results = searchMemories ( worktree , args . query )
325+ const callID = getCallID ( ctx )
326+ if ( callID ) memorySearchCountByCallID . set ( callID , results . length )
266327 if ( results . length === 0 ) {
267328 return `No memories matching "${ args . query } ".`
268329 }
@@ -278,7 +339,7 @@ export const MemoryPlugin: Plugin = async ({ worktree }) => {
278339 args : {
279340 file_name : tool . schema . string ( ) . describe ( "File name of the memory to read (with or without .md extension)" ) ,
280341 } ,
281- async execute ( args ) {
342+ async execute ( args , _ctx ) {
282343 const entry = readMemory ( worktree , args . file_name )
283344 if ( ! entry ) {
284345 return `Memory "${ args . file_name } " not found.`
0 commit comments