mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-30 19:09:28 +00:00
fix(session): resolve default state DB path at call time
DEFAULT_DB_PATH in hermes_state.py is computed at import time, freezing the developer's real ~/.hermes even when a test fixture (or runtime profile switch) later redirects HERMES_HOME. Any default SessionDB() — e.g. gateway SessionStore — then opened the real state.db. Add _default_db_path(): resolves get_hermes_home() fresh at call time, while a deliberately re-pointed DEFAULT_DB_PATH (the established monkeypatch escape hatch) still wins via an import-time snapshot comparison, preserving existing test behavior. SessionDB.__init__ and session_search's requirement check now use the resolver; explicit db_path arguments are untouched. Reimplemented from PR #11875 by @JorkeyLiu (original diff predates the hermes_state rewrite); regression test ported and modernized.
This commit is contained in:
parent
3e54a366e7
commit
05afea65f4
4 changed files with 52 additions and 3 deletions
2
contributors/emails/jorkeyliu@gmail.com
Normal file
2
contributors/emails/jorkeyliu@gmail.com
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
JorkeyLiu
|
||||
# PR #11875 salvage
|
||||
|
|
@ -234,6 +234,30 @@ T = TypeVar("T")
|
|||
|
||||
DEFAULT_DB_PATH = get_hermes_home() / "state.db"
|
||||
|
||||
# Import-time snapshot used by _default_db_path() to detect a deliberately
|
||||
# re-pointed DEFAULT_DB_PATH (tests monkeypatch the constant directly).
|
||||
_IMPORT_DEFAULT_DB_PATH = DEFAULT_DB_PATH
|
||||
|
||||
|
||||
def _default_db_path() -> Path:
|
||||
"""Resolve the default state DB path at call time.
|
||||
|
||||
``DEFAULT_DB_PATH`` is computed when this module is first imported, which
|
||||
freezes the developer's real ``~/.hermes`` even when a test fixture later
|
||||
redirects ``HERMES_HOME`` — importing this module during collection was
|
||||
enough to point every default ``SessionDB()`` at the real state.db.
|
||||
|
||||
Precedence:
|
||||
|
||||
1. A deliberately re-pointed ``DEFAULT_DB_PATH`` (differs from the
|
||||
import-time snapshot — the established test escape hatch) wins.
|
||||
2. Otherwise resolve ``get_hermes_home()`` fresh so a runtime
|
||||
``HERMES_HOME`` redirect takes effect regardless of import order.
|
||||
"""
|
||||
if DEFAULT_DB_PATH != _IMPORT_DEFAULT_DB_PATH:
|
||||
return DEFAULT_DB_PATH
|
||||
return get_hermes_home() / "state.db"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# WAL-compatibility fallback
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -1765,7 +1789,7 @@ class SessionDB(SessionSearchMixin, SessionSchemaMixin, SessionPortabilityMixin)
|
|||
_IMPORT_MAX_TOTAL_BYTES = 25 * 1024 * 1024
|
||||
|
||||
def __init__(self, db_path: Path = None, read_only: bool = False):
|
||||
self.db_path = db_path or DEFAULT_DB_PATH
|
||||
self.db_path = db_path or _default_db_path()
|
||||
self.read_only = read_only
|
||||
|
||||
self._lock = threading.Lock()
|
||||
|
|
|
|||
|
|
@ -24,6 +24,29 @@ from gateway.config import GatewayConfig, Platform, SessionResetPolicy
|
|||
from gateway.session import SessionEntry, SessionStore
|
||||
|
||||
|
||||
def test_session_store_default_db_uses_runtime_hermes_home(tmp_path, monkeypatch):
|
||||
"""SessionStore must honor runtime HERMES_HOME when opening the default DB.
|
||||
|
||||
Regression for the import-time DEFAULT_DB_PATH freeze: importing
|
||||
hermes_state before a fixture redirected HERMES_HOME used to pin every
|
||||
default SessionDB() at the developer's real ~/.hermes/state.db.
|
||||
"""
|
||||
config = GatewayConfig(default_reset_policy=SessionResetPolicy(mode="none"))
|
||||
fake_home = tmp_path / "alt_hermes_home"
|
||||
fake_home.mkdir()
|
||||
monkeypatch.setenv("HERMES_HOME", str(fake_home))
|
||||
|
||||
with patch("gateway.session.SessionStore._ensure_loaded"):
|
||||
store = SessionStore(sessions_dir=tmp_path / "sessions", config=config)
|
||||
|
||||
try:
|
||||
assert store._db is not None
|
||||
assert store._db.db_path == fake_home / "state.db"
|
||||
finally:
|
||||
if store._db is not None:
|
||||
store._db.close()
|
||||
|
||||
|
||||
def _make_store(tmp_path, max_age_days: int = 90, has_active_processes_fn=None):
|
||||
"""Build a SessionStore bypassing SQLite/disk-load side effects."""
|
||||
config = GatewayConfig(
|
||||
|
|
|
|||
|
|
@ -954,8 +954,8 @@ def session_search(
|
|||
def check_session_search_requirements() -> bool:
|
||||
"""Requires the SQLite state database."""
|
||||
try:
|
||||
from hermes_state import DEFAULT_DB_PATH
|
||||
return DEFAULT_DB_PATH.parent.exists()
|
||||
from hermes_state import _default_db_path
|
||||
return _default_db_path().parent.exists()
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue