fix(memory/holographic): store the default fact DB path as $HERMES_HOME, not the profile's concrete path
The setup schema offered db_path as f"{display_hermes_home()}/memory_store.db",
so `hermes memory setup` (Enter on the field) and the dashboard form wrote the
active profile's concrete path into plugins.hermes-memory-store. initialize()
only expands a literal $HERMES_HOME, and neither `profile create --clone` nor
`profile rename` rewrites config.yaml, so:
- a cloned profile opened the source profile's memory_store.db: facts stored
in one profile were recalled into the other's prompts, both ways;
- a renamed profile opened profiles/<old>/memory_store.db, which MemoryStore
re-created as an empty DB in a ghost directory under the old name, while the
real facts sat orphaned in the renamed directory.
The schema default is now "$HERMES_HOME/memory_store.db", the value the docs
already give, which initialize() resolves against whichever profile opens it.
save_config also stores a db_path equal to this profile's own DB as the
placeholder, so a config written by an older setup is repaired on its next save
from the CLI or the dashboard. A path anywhere else is kept as given.
This commit is contained in:
committed by
Teknium
parent
6ba45d4adb
commit
d6246b4e01
96
tests/plugins/memory/test_holographic_profile_db_path.py
Normal file
96
tests/plugins/memory/test_holographic_profile_db_path.py
Normal file
@@ -0,0 +1,96 @@
|
||||
"""The holographic fact DB set up with the default path belongs to whichever profile opens it.
|
||||
|
||||
Setup used to offer, and store, the active profile's concrete path (``~/.hermes/memory_store.db``).
|
||||
``profile create --clone`` copies config.yaml verbatim, so the clone opened the source profile's
|
||||
facts; ``profile rename`` moves the directory, so the renamed profile opened an empty DB in a
|
||||
re-created directory under its old name.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
import hermes_cli.memory_setup as memory_setup
|
||||
from hermes_cli.profiles import create_profile, rename_profile
|
||||
from plugins.memory.holographic import HolographicMemoryProvider, _load_plugin_config
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def root(tmp_path, monkeypatch):
|
||||
# A ``~/`` path is displayed through Path.home() and expanded through HOME; both name the sandbox.
|
||||
monkeypatch.setenv("HOME", str(tmp_path))
|
||||
monkeypatch.setattr(Path, "home", lambda: tmp_path)
|
||||
home = tmp_path / ".hermes"
|
||||
home.mkdir()
|
||||
monkeypatch.setenv("HERMES_HOME", str(home))
|
||||
return home
|
||||
|
||||
|
||||
def _setup_with_defaults(monkeypatch, home: Path) -> dict:
|
||||
"""``hermes memory setup`` for holographic with Enter on every field, saved as ``cmd_setup`` does."""
|
||||
monkeypatch.setenv("HERMES_HOME", str(home))
|
||||
provider = HolographicMemoryProvider(config={"hrr_dim": 64})
|
||||
monkeypatch.setattr(memory_setup, "_curses_select", lambda *_a, default=0, **_k: default)
|
||||
monkeypatch.setattr(sys, "stdin", io.StringIO("\n" * 10))
|
||||
answers: dict = {}
|
||||
assert memory_setup._prompt_schema_fields("holographic", provider.get_config_schema(), answers, {})
|
||||
provider.save_config(answers, str(home))
|
||||
return answers
|
||||
|
||||
|
||||
def _opened_db(monkeypatch, home: Path) -> Path:
|
||||
"""The DB a session started with ``hermes -p <profile>`` opens."""
|
||||
monkeypatch.setenv("HERMES_HOME", str(home))
|
||||
provider = HolographicMemoryProvider(config=_load_plugin_config())
|
||||
provider.initialize("s")
|
||||
try:
|
||||
return provider._store.db_path.resolve()
|
||||
finally:
|
||||
provider.shutdown()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("lifecycle", ["clone", "rename"])
|
||||
def test_default_db_path_follows_the_profile_that_opens_it(root, monkeypatch, lifecycle):
|
||||
if lifecycle == "clone":
|
||||
answers = _setup_with_defaults(monkeypatch, root)
|
||||
monkeypatch.setenv("HERMES_HOME", str(root))
|
||||
profile = create_profile("work", clone_config=True, no_alias=True)
|
||||
else:
|
||||
source = create_profile("alpha", no_alias=True)
|
||||
answers = _setup_with_defaults(monkeypatch, source)
|
||||
monkeypatch.setenv("HERMES_HOME", str(root))
|
||||
with patch("hermes_cli.profiles.check_alias_collision", return_value="skip"):
|
||||
profile = rename_profile("alpha", "beta")
|
||||
|
||||
assert _opened_db(monkeypatch, profile) == (profile / "memory_store.db").resolve()
|
||||
if lifecycle == "rename":
|
||||
assert not (root / "profiles" / "alpha").exists()
|
||||
# The prompt offers the value it stores, so what the user accepted is what config.yaml says.
|
||||
assert answers["db_path"] == "$HERMES_HOME/memory_store.db"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("spelling", ["display", "absolute"])
|
||||
def test_save_config_stores_this_profiles_default_path_as_the_placeholder(root, monkeypatch, spelling):
|
||||
# The concrete value an older setup wrote, and the dashboard form re-submits on its next save.
|
||||
profile = create_profile("work", no_alias=True)
|
||||
monkeypatch.setenv("HERMES_HOME", str(profile))
|
||||
concrete = "~/.hermes/profiles/work/memory_store.db" if spelling == "display" else str(profile / "memory_store.db")
|
||||
|
||||
HolographicMemoryProvider(config={"hrr_dim": 64}).save_config({"db_path": concrete, "hrr_dim": "64"}, str(profile))
|
||||
|
||||
stored = yaml.safe_load((profile / "config.yaml").read_text(encoding="utf-8"))["plugins"]["hermes-memory-store"]
|
||||
assert stored == {"db_path": "$HERMES_HOME/memory_store.db", "hrr_dim": "64"}
|
||||
|
||||
|
||||
def test_save_config_keeps_an_explicit_path(root, monkeypatch):
|
||||
elsewhere = str(root / "shared" / "facts.db")
|
||||
|
||||
HolographicMemoryProvider(config={"hrr_dim": 64}).save_config({"db_path": elsewhere}, str(root))
|
||||
|
||||
stored = yaml.safe_load((root / "config.yaml").read_text(encoding="utf-8"))["plugins"]["hermes-memory-store"]
|
||||
assert stored["db_path"] == elsewhere
|
||||
Reference in New Issue
Block a user