fix(state): batch large session cleanup queries below SQLite's variable limit

prune_sessions(), delete_empty_sessions() and prune_empty_ghost_sessions()
built one IN (?, ..., ?) clause containing every selected session id (the
parent-orphaning UPDATE), so cleaning more than SQLITE_MAX_VARIABLE_NUMBER
sessions failed atomically with "too many SQL variables". The per-row
DELETE loops that followed are folded into the same 900-id batches.

Same single _execute_write() transaction; only the binding is split.

Hand-ported from PR #100658 (targeted the pre-decomposition hermes_state.py
god file; the methods now live in hermes_state_maintenance.py /
hermes_state_sessions.py). The one-pass transcript-directory sweep from
that PR is not ported (out of scope for the variable-limit bug). Authored
by @Mi55ed; ported under --author.
This commit is contained in:
Mi55ed
2026-09-01 19:49:14 +00:00
committed by Teknium
parent acfda37598
commit 25670cd9e3
2 changed files with 16 additions and 16 deletions

View File

@@ -1573,16 +1573,14 @@ class SessionSessionsMixin:
).fetchall()}
if not session_ids:
return 0
conn.execute(
"UPDATE sessions SET parent_session_id = NULL "
f"WHERE parent_session_id IN ({_session_ids_placeholders(session_ids)})", list(session_ids),
)
for sid in session_ids:
for chunk in _id_chunks(session_ids):
ph = _session_ids_placeholders(chunk)
conn.execute(f"UPDATE sessions SET parent_session_id = NULL WHERE parent_session_id IN ({ph})", chunk)
# DELETE FROM messages: a row inserted between the SELECT and here
# would otherwise dangle (clean FK state).
conn.execute("DELETE FROM messages WHERE session_id = ?", (sid,))
conn.execute("DELETE FROM sessions WHERE id = ?", (sid,))
removed_ids.append(sid)
conn.execute(f"DELETE FROM messages WHERE session_id IN ({ph})", chunk)
conn.execute(f"DELETE FROM sessions WHERE id IN ({ph})", chunk)
removed_ids.extend(chunk)
self._delete_unreferenced_system_prompts(conn)
return len(session_ids)
count = self._execute_write(_do)