refactor: consolidate gateway session metadata into state.db (#58899)

Moves gateway routing metadata (display_name, origin_json, expiry_finalized)
into state.db, making SQLite the single source of truth for gateway session
discovery. Eliminates the dual-file (sessions.json + state.db) polling
dependency that caused the mcp_serve new-conversation race (#8925).

- hermes_state.py: schema v18 (3 new sessions columns + sessions.json
  backfill migration), record_gateway_session_peer gains
  display_name/origin_json, new set_expiry_finalized(),
  list_gateway_sessions(), find_session_by_origin()
- gateway/session.py: peer recorder persists display_name + full origin
  JSON; new SessionStore.set_expiry_finalized() single write-path
- gateway/run.py: expiry watcher success + give-up paths use the store
  helper so the flag lands in both sessions.json and state.db
- mcp_serve.py: routing index reads state.db first (sessions.json fallback
  for pre-migration DBs); _poll_once collapses to a single state.db mtime
  check — the #8925 race is structurally impossible now
- gateway/mirror.py, gateway/channel_directory.py, hermes_cli/status.py:
  query state.db first, sessions.json fallback

Closes #9006
This commit is contained in:
Teknium 2026-07-05 14:01:03 -07:00 committed by GitHub
parent 0b67ff222a
commit 747386ecfa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 671 additions and 81 deletions

View file

@ -543,17 +543,39 @@ def show_status(args):
print()
print(color("◆ Sessions", Colors.CYAN, Colors.BOLD))
sessions_file = get_hermes_home() / "sessions" / "sessions.json"
if sessions_file.exists():
import json
# Gateway session count: state.db is the source of truth (#9006);
# fall back to sessions.json for pre-migration installs.
_session_count = None
try:
from hermes_state import SessionDB
_db = SessionDB()
try:
with open(sessions_file, encoding="utf-8") as f:
data = json.load(f)
print(f" Active: {len(data)} session(s)")
except Exception:
print(" Active: (error reading sessions file)")
_lister = getattr(_db, "list_gateway_sessions", None)
if callable(_lister):
_session_count = len(_lister(active_only=True))
finally:
_db.close()
except Exception:
_session_count = None
if _session_count is not None and _session_count > 0:
print(f" Active: {_session_count} session(s)")
else:
print(" Active: 0")
sessions_file = get_hermes_home() / "sessions" / "sessions.json"
if sessions_file.exists():
import json
try:
with open(sessions_file, encoding="utf-8") as f:
data = json.load(f)
_entries = {
k: v for k, v in data.items()
if not str(k).startswith("_")
} if isinstance(data, dict) else {}
print(f" Active: {len(_entries)} session(s)")
except Exception:
print(" Active: (error reading sessions file)")
else:
print(f" Active: {_session_count if _session_count is not None else 0}")
# =========================================================================
# Deep checks