Skip to content

Commit bdbef41

Browse files
authored
feat(session_search): add recent sessions mode when query is omitted (NousResearch#2533)
feat(session_search): add recent sessions mode when query is omitted
2 parents 2a65731 + 856ca99 commit bdbef41

1 file changed

Lines changed: 67 additions & 6 deletions

File tree

tools/session_search_tool.py

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
182234
def 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:
364419
SESSION_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

Comments
 (0)