@@ -179,6 +179,58 @@ async def _summarize_session(
179179 return None
180180
181181
182+ def _list_recent_sessions (db , limit : int , current_session_id : str = None ) -> str :
183+ """Return metadata for the most recent sessions (no LLM calls)."""
184+ try :
185+ sessions = db .list_sessions_rich (limit = limit + 5 ) # fetch extra to skip current
186+
187+ # Resolve current session lineage to exclude it
188+ current_root = None
189+ if current_session_id :
190+ try :
191+ sid = current_session_id
192+ visited = set ()
193+ while sid and sid not in visited :
194+ visited .add (sid )
195+ s = db .get_session (sid )
196+ parent = s .get ("parent_session_id" ) if s else None
197+ sid = parent if parent else None
198+ current_root = max (visited , key = len ) if visited else current_session_id
199+ except Exception :
200+ current_root = current_session_id
201+
202+ results = []
203+ for s in sessions :
204+ sid = s .get ("id" , "" )
205+ if current_root and (sid == current_root or sid == current_session_id ):
206+ continue
207+ # Skip child/delegation sessions (they have parent_session_id)
208+ if s .get ("parent_session_id" ):
209+ continue
210+ results .append ({
211+ "session_id" : sid ,
212+ "title" : s .get ("title" ) or None ,
213+ "source" : s .get ("source" , "" ),
214+ "started_at" : s .get ("started_at" , "" ),
215+ "last_active" : s .get ("last_active" , "" ),
216+ "message_count" : s .get ("message_count" , 0 ),
217+ "preview" : s .get ("preview" , "" ),
218+ })
219+ if len (results ) >= limit :
220+ break
221+
222+ return json .dumps ({
223+ "success" : True ,
224+ "mode" : "recent" ,
225+ "results" : results ,
226+ "count" : len (results ),
227+ "message" : f"Showing { len (results )} most recent sessions. Use a keyword query to search specific topics." ,
228+ }, ensure_ascii = False )
229+ except Exception as e :
230+ logging .error ("Error listing recent sessions: %s" , e , exc_info = True )
231+ return json .dumps ({"success" : False , "error" : f"Failed to list recent sessions: { e } " }, ensure_ascii = False )
232+
233+
182234def session_search (
183235 query : str ,
184236 role_filter : str = None ,
@@ -195,11 +247,14 @@ def session_search(
195247 if db is None :
196248 return json .dumps ({"success" : False , "error" : "Session database not available." }, ensure_ascii = False )
197249
250+ limit = min (limit , 5 ) # Cap at 5 sessions to avoid excessive LLM calls
251+
252+ # Recent sessions mode: when query is empty, return metadata for recent sessions.
253+ # No LLM calls — just DB queries for titles, previews, timestamps.
198254 if not query or not query .strip ():
199- return json . dumps ({ "success" : False , "error" : "Query cannot be empty." }, ensure_ascii = False )
255+ return _list_recent_sessions ( db , limit , current_session_id )
200256
201257 query = query .strip ()
202- limit = min (limit , 5 ) # Cap at 5 sessions to avoid excessive LLM calls
203258
204259 try :
205260 # Parse role filter
@@ -364,8 +419,14 @@ def check_session_search_requirements() -> bool:
364419SESSION_SEARCH_SCHEMA = {
365420 "name" : "session_search" ,
366421 "description" : (
367- "Search your long-term memory of past conversations. This is your recall -- "
422+ "Search your long-term memory of past conversations, or browse recent sessions . This is your recall -- "
368423 "every past session is searchable, and this tool summarizes what happened.\n \n "
424+ "TWO MODES:\n "
425+ "1. Recent sessions (no query): Call with no arguments to see what was worked on recently. "
426+ "Returns titles, previews, and timestamps. Zero LLM cost, instant. "
427+ "Start here when the user asks what were we working on or what did we do recently.\n "
428+ "2. Keyword search (with query): Search for specific topics across all past sessions. "
429+ "Returns LLM-generated summaries of matching sessions.\n \n "
369430 "USE THIS PROACTIVELY when:\n "
370431 "- The user says 'we did this before', 'remember when', 'last time', 'as I mentioned'\n "
371432 "- The user asks about a topic you worked on before but don't have in current context\n "
@@ -385,7 +446,7 @@ def check_session_search_requirements() -> bool:
385446 "properties" : {
386447 "query" : {
387448 "type" : "string" ,
388- "description" : "Search query — keywords, phrases, or boolean expressions to find in past sessions." ,
449+ "description" : "Search query — keywords, phrases, or boolean expressions to find in past sessions. Omit this parameter entirely to browse recent sessions instead (returns titles, previews, timestamps with no LLM cost). " ,
389450 },
390451 "role_filter" : {
391452 "type" : "string" ,
@@ -397,7 +458,7 @@ def check_session_search_requirements() -> bool:
397458 "default" : 3 ,
398459 },
399460 },
400- "required" : ["query" ],
461+ "required" : [],
401462 },
402463}
403464
@@ -410,7 +471,7 @@ def check_session_search_requirements() -> bool:
410471 toolset = "session_search" ,
411472 schema = SESSION_SEARCH_SCHEMA ,
412473 handler = lambda args , ** kw : session_search (
413- query = args .get ("query" , "" ) ,
474+ query = args .get ("query" ) or "" ,
414475 role_filter = args .get ("role_filter" ),
415476 limit = args .get ("limit" , 3 ),
416477 db = kw .get ("db" ),
0 commit comments