mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-05 18:27:04 +08:00
Compare commits
1 Commits
dependabot
...
hermes/her
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0b325b9f9 |
@@ -787,6 +787,7 @@ class SessionDB:
|
|||||||
exclude_sources: List[str] = None,
|
exclude_sources: List[str] = None,
|
||||||
limit: int = 20,
|
limit: int = 20,
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
|
include_children: bool = False,
|
||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""List sessions with preview (first user message) and last active timestamp.
|
"""List sessions with preview (first user message) and last active timestamp.
|
||||||
|
|
||||||
@@ -795,10 +796,16 @@ class SessionDB:
|
|||||||
last_active (timestamp of last message).
|
last_active (timestamp of last message).
|
||||||
|
|
||||||
Uses a single query with correlated subqueries instead of N+2 queries.
|
Uses a single query with correlated subqueries instead of N+2 queries.
|
||||||
|
|
||||||
|
By default, child sessions (subagent runs, compression continuations)
|
||||||
|
are excluded. Pass ``include_children=True`` to include them.
|
||||||
"""
|
"""
|
||||||
where_clauses = []
|
where_clauses = []
|
||||||
params = []
|
params = []
|
||||||
|
|
||||||
|
if not include_children:
|
||||||
|
where_clauses.append("s.parent_session_id IS NULL")
|
||||||
|
|
||||||
if source:
|
if source:
|
||||||
where_clauses.append("s.source = ?")
|
where_clauses.append("s.source = ?")
|
||||||
params.append(source)
|
params.append(source)
|
||||||
@@ -1229,22 +1236,38 @@ class SessionDB:
|
|||||||
self._execute_write(_do)
|
self._execute_write(_do)
|
||||||
|
|
||||||
def delete_session(self, session_id: str) -> bool:
|
def delete_session(self, session_id: str) -> bool:
|
||||||
"""Delete a session and all its messages. Returns True if found."""
|
"""Delete a session, its child sessions, and all their messages.
|
||||||
|
|
||||||
|
Child sessions (subagent runs, compression continuations) are deleted
|
||||||
|
first to satisfy the ``parent_session_id`` foreign key constraint.
|
||||||
|
Returns True if the session was found and deleted.
|
||||||
|
"""
|
||||||
def _do(conn):
|
def _do(conn):
|
||||||
cursor = conn.execute(
|
cursor = conn.execute(
|
||||||
"SELECT COUNT(*) FROM sessions WHERE id = ?", (session_id,)
|
"SELECT COUNT(*) FROM sessions WHERE id = ?", (session_id,)
|
||||||
)
|
)
|
||||||
if cursor.fetchone()[0] == 0:
|
if cursor.fetchone()[0] == 0:
|
||||||
return False
|
return False
|
||||||
|
# Delete child sessions first (FK constraint)
|
||||||
|
child_ids = [r[0] for r in conn.execute(
|
||||||
|
"SELECT id FROM sessions WHERE parent_session_id = ?",
|
||||||
|
(session_id,),
|
||||||
|
).fetchall()]
|
||||||
|
for cid in child_ids:
|
||||||
|
conn.execute("DELETE FROM messages WHERE session_id = ?", (cid,))
|
||||||
|
conn.execute("DELETE FROM sessions WHERE id = ?", (cid,))
|
||||||
|
# Delete the session itself
|
||||||
conn.execute("DELETE FROM messages WHERE session_id = ?", (session_id,))
|
conn.execute("DELETE FROM messages WHERE session_id = ?", (session_id,))
|
||||||
conn.execute("DELETE FROM sessions WHERE id = ?", (session_id,))
|
conn.execute("DELETE FROM sessions WHERE id = ?", (session_id,))
|
||||||
return True
|
return True
|
||||||
return self._execute_write(_do)
|
return self._execute_write(_do)
|
||||||
|
|
||||||
def prune_sessions(self, older_than_days: int = 90, source: str = None) -> int:
|
def prune_sessions(self, older_than_days: int = 90, source: str = None) -> int:
|
||||||
"""
|
"""Delete sessions older than N days. Returns count of deleted sessions.
|
||||||
Delete sessions older than N days. Returns count of deleted sessions.
|
|
||||||
Only prunes ended sessions (not active ones).
|
Only prunes ended sessions (not active ones). Child sessions whose
|
||||||
|
parents are being pruned are deleted first to satisfy the
|
||||||
|
``parent_session_id`` foreign key constraint.
|
||||||
"""
|
"""
|
||||||
cutoff = time.time() - (older_than_days * 86400)
|
cutoff = time.time() - (older_than_days * 86400)
|
||||||
|
|
||||||
@@ -1260,7 +1283,19 @@ class SessionDB:
|
|||||||
"SELECT id FROM sessions WHERE started_at < ? AND ended_at IS NOT NULL",
|
"SELECT id FROM sessions WHERE started_at < ? AND ended_at IS NOT NULL",
|
||||||
(cutoff,),
|
(cutoff,),
|
||||||
)
|
)
|
||||||
session_ids = [row["id"] for row in cursor.fetchall()]
|
session_ids = set(row["id"] for row in cursor.fetchall())
|
||||||
|
|
||||||
|
# Delete children first whose parents are in the prune set
|
||||||
|
# (avoids FK constraint errors)
|
||||||
|
for sid in list(session_ids):
|
||||||
|
child_ids = [r[0] for r in conn.execute(
|
||||||
|
"SELECT id FROM sessions WHERE parent_session_id = ?",
|
||||||
|
(sid,),
|
||||||
|
).fetchall()]
|
||||||
|
for cid in child_ids:
|
||||||
|
conn.execute("DELETE FROM messages WHERE session_id = ?", (cid,))
|
||||||
|
conn.execute("DELETE FROM sessions WHERE id = ?", (cid,))
|
||||||
|
session_ids.discard(cid) # don't double-delete
|
||||||
|
|
||||||
for sid in session_ids:
|
for sid in session_ids:
|
||||||
conn.execute("DELETE FROM messages WHERE session_id = ?", (sid,))
|
conn.execute("DELETE FROM messages WHERE session_id = ?", (sid,))
|
||||||
|
|||||||
@@ -530,6 +530,7 @@ class AIAgent:
|
|||||||
skip_context_files: bool = False,
|
skip_context_files: bool = False,
|
||||||
skip_memory: bool = False,
|
skip_memory: bool = False,
|
||||||
session_db=None,
|
session_db=None,
|
||||||
|
parent_session_id: str = None,
|
||||||
iteration_budget: "IterationBudget" = None,
|
iteration_budget: "IterationBudget" = None,
|
||||||
fallback_model: Dict[str, Any] = None,
|
fallback_model: Dict[str, Any] = None,
|
||||||
credential_pool=None,
|
credential_pool=None,
|
||||||
@@ -1025,6 +1026,7 @@ class AIAgent:
|
|||||||
|
|
||||||
# SQLite session store (optional -- provided by CLI or gateway)
|
# SQLite session store (optional -- provided by CLI or gateway)
|
||||||
self._session_db = session_db
|
self._session_db = session_db
|
||||||
|
self._parent_session_id = parent_session_id
|
||||||
self._last_flushed_db_idx = 0 # tracks DB-write cursor to prevent duplicate writes
|
self._last_flushed_db_idx = 0 # tracks DB-write cursor to prevent duplicate writes
|
||||||
if self._session_db:
|
if self._session_db:
|
||||||
try:
|
try:
|
||||||
@@ -1038,6 +1040,7 @@ class AIAgent:
|
|||||||
"max_tokens": max_tokens,
|
"max_tokens": max_tokens,
|
||||||
},
|
},
|
||||||
user_id=None,
|
user_id=None,
|
||||||
|
parent_session_id=self._parent_session_id,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Transient SQLite lock contention (e.g. CLI and gateway writing
|
# Transient SQLite lock contention (e.g. CLI and gateway writing
|
||||||
|
|||||||
@@ -251,6 +251,7 @@ def _build_child_agent(
|
|||||||
clarify_callback=None,
|
clarify_callback=None,
|
||||||
thinking_callback=child_thinking_cb,
|
thinking_callback=child_thinking_cb,
|
||||||
session_db=getattr(parent_agent, '_session_db', None),
|
session_db=getattr(parent_agent, '_session_db', None),
|
||||||
|
parent_session_id=getattr(parent_agent, 'session_id', None),
|
||||||
providers_allowed=parent_agent.providers_allowed,
|
providers_allowed=parent_agent.providers_allowed,
|
||||||
providers_ignored=parent_agent.providers_ignored,
|
providers_ignored=parent_agent.providers_ignored,
|
||||||
providers_order=parent_agent.providers_order,
|
providers_order=parent_agent.providers_order,
|
||||||
|
|||||||
Reference in New Issue
Block a user