fix: state_sync.py -- correct class name, constructor type, title API, connection leak
Three bugs found during review: 1. Class is SessionDB not HermesState -- would silently no-op on every install 2. SessionDB.__init__ takes Path not str -- would crash with AttributeError 3. _execute_write() takes a callable not SQL+params -- wrong signature. Replaced with public set_session_title() API. 4. Each call opened a persistent SQLite connection and never closed it. Added try/finally db.close() to prevent WAL leak under sustained load. Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
This commit is contained in:
@@ -18,11 +18,12 @@ from pathlib import Path
|
|||||||
|
|
||||||
|
|
||||||
def _get_state_db():
|
def _get_state_db():
|
||||||
"""Get a HermesState instance for the active profile's state.db.
|
"""Get a SessionDB instance for the active profile's state.db.
|
||||||
Returns None if hermes_state is not importable or DB is unavailable.
|
Returns None if hermes_state is not importable or DB is unavailable.
|
||||||
|
Each caller is responsible for calling db.close() when done.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
from hermes_state import HermesState
|
from hermes_state import SessionDB
|
||||||
except ImportError:
|
except ImportError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -37,7 +38,7 @@ def _get_state_db():
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return HermesState(str(db_path))
|
return SessionDB(db_path)
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -46,10 +47,10 @@ def sync_session_start(session_id, model=None):
|
|||||||
"""Register a WebUI session in state.db (idempotent).
|
"""Register a WebUI session in state.db (idempotent).
|
||||||
Called when a session's first message is sent.
|
Called when a session's first message is sent.
|
||||||
"""
|
"""
|
||||||
try:
|
|
||||||
db = _get_state_db()
|
db = _get_state_db()
|
||||||
if not db:
|
if not db:
|
||||||
return
|
return
|
||||||
|
try:
|
||||||
db.ensure_session(
|
db.ensure_session(
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
source='webui',
|
source='webui',
|
||||||
@@ -57,6 +58,11 @@ def sync_session_start(session_id, model=None):
|
|||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass # never crash the WebUI for sync failures
|
pass # never crash the WebUI for sync failures
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
db.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def sync_session_usage(session_id, input_tokens=0, output_tokens=0,
|
def sync_session_usage(session_id, input_tokens=0, output_tokens=0,
|
||||||
@@ -65,10 +71,10 @@ def sync_session_usage(session_id, input_tokens=0, output_tokens=0,
|
|||||||
Called after each turn completes. Uses absolute=True to set totals
|
Called after each turn completes. Uses absolute=True to set totals
|
||||||
(the WebUI Session already accumulates across turns).
|
(the WebUI Session already accumulates across turns).
|
||||||
"""
|
"""
|
||||||
try:
|
|
||||||
db = _get_state_db()
|
db = _get_state_db()
|
||||||
if not db:
|
if not db:
|
||||||
return
|
return
|
||||||
|
try:
|
||||||
# Ensure session exists first (idempotent)
|
# Ensure session exists first (idempotent)
|
||||||
db.ensure_session(session_id=session_id, source='webui', model=model)
|
db.ensure_session(session_id=session_id, source='webui', model=model)
|
||||||
# Set absolute token counts
|
# Set absolute token counts
|
||||||
@@ -80,14 +86,16 @@ def sync_session_usage(session_id, input_tokens=0, output_tokens=0,
|
|||||||
model=model,
|
model=model,
|
||||||
absolute=True,
|
absolute=True,
|
||||||
)
|
)
|
||||||
# Update title if we have one
|
# Update title if we have one, using the public API
|
||||||
if title:
|
if title:
|
||||||
try:
|
try:
|
||||||
db._execute_write(
|
db.set_session_title(session_id, title)
|
||||||
"UPDATE sessions SET title = ? WHERE id = ?",
|
|
||||||
(title, session_id),
|
|
||||||
)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
pass # never crash the WebUI for sync failures
|
pass # never crash the WebUI for sync failures
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
db.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|||||||
Reference in New Issue
Block a user