fix: harden /save for test doubles, async session-store boundary, snapshot shape pin

Three CI-red follow-ups on the /save rework:

- cli.py save_conversation: getattr-guard _session_db/session_id so
  SimpleNamespace/object.__new__ test doubles (and any embedder passing a
  minimal stub) don't AttributeError (pitfall #17 pattern).
- gateway/slash_commands.py: route through the awaited
  async_session_store.get_or_create_session boundary — the architecture
  test forbids raw session_store calls in async gateway code.
- tests/cli/test_save_conversation_location.py: /save now emits the
  canonical export_session payload shape; the session id key is "id"
  (was "session_id" in the legacy snapshot format) — update the pin.

The slice-8 lost-and-found failure was pre-existing on main and is fixed
there by f2a30fa400 (test: derive lost-and-found synthetic width from the
live schema); picked up via rebase.
This commit is contained in:
Teknium
2026-08-15 01:02:48 -07:00
parent 26aa12337a
commit e5a2c80c0e
3 changed files with 10 additions and 4 deletions
+6 -2
View File
@@ -9374,10 +9374,14 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
# Prefer the durable DB row (has metadata + tool calls); fall back to
# the in-memory history for sessions that never touched the DB.
# getattr: test doubles (SimpleNamespace / object.__new__) may not
# carry _session_db or session_id.
session_data = None
if self._session_db and self.session_id:
_db = getattr(self, "_session_db", None)
_sid = getattr(self, "session_id", None)
if _db and _sid:
try:
session_data = self._session_db.export_session(self.session_id)
session_data = _db.export_session(_sid)
except Exception:
session_data = None
if not session_data:
+1 -1
View File
@@ -4543,7 +4543,7 @@ class GatewaySlashCommandsMixin:
)
source = event.source
session_entry = self.session_store.get_or_create_session(source)
session_entry = await self.async_session_store.get_or_create_session(source)
session_id = session_entry.session_id
if not self._session_db:
+3 -1
View File
@@ -75,7 +75,9 @@ def test_save_conversation_writes_under_hermes_home(hermes_home, tmp_path, monke
payload = json.loads(files[0].read_text())
assert payload["model"] == "test-model"
assert payload["session_id"] == "20260101_120000_abc123"
# /save now emits the canonical export_session shape: the session id
# lives under "id" (was "session_id" in the legacy snapshot format).
assert payload["id"] == "20260101_120000_abc123"
assert payload["messages"] == [
{"role": "user", "content": "hi"},
{"role": "assistant", "content": "hello"},