feat: add persistent memory system + SQLite session store

Two-part implementation:

Part A - Curated Bounded Memory:
- New memory tool (tools/memory_tool.py) with MEMORY.md + USER.md stores
- Character-limited (2200/1375 chars), § delimited entries
- Frozen snapshot injected into system prompt at session start
- Model manages pruning via replace/remove with substring matching
- Usage indicator shown in system prompt header

Part B - SQLite Session Store:
- New hermes_state.py with SessionDB class, FTS5 full-text search
- Gateway session.py rewritten to dual-write SQLite + legacy JSONL
- Compression-triggered session splitting with parent_session_id chains
- New session_search tool with Gemini Flash summarization of matched sessions
- CLI session lifecycle (create on launch, close on exit)

Also:
- System prompt now cached per session, only rebuilt on compression
  (fixes prefix cache invalidation from date/time changes every turn)
- Config version bumped to 3, hermes doctor checks for new artifacts
- Disabled in batch_runner and RL environments
This commit is contained in:
teknium1 2026-02-19 00:57:31 -08:00
parent 655303f2f1
commit 440c244cac
19 changed files with 2397 additions and 327 deletions

15
cli.py
View file

@ -723,6 +723,14 @@ class HermesCLI:
if self.agent is not None:
return True
# Initialize SQLite session store for CLI sessions
self._session_db = None
try:
from hermes_state import SessionDB
self._session_db = SessionDB()
except Exception:
pass # SQLite session store is optional
try:
self.agent = AIAgent(
model=self.model,
@ -735,6 +743,7 @@ class HermesCLI:
ephemeral_system_prompt=self.system_prompt if self.system_prompt else None,
session_id=self.session_id, # Pass CLI's session ID to agent
platform="cli", # CLI interface — agent uses terminal-friendly formatting
session_db=self._session_db,
)
return True
except Exception as e:
@ -1775,6 +1784,12 @@ class HermesCLI:
pass
finally:
self._should_exit = True
# Close session in SQLite
if hasattr(self, '_session_db') and self._session_db and self.agent:
try:
self._session_db.end_session(self.agent.session_id, "cli_close")
except Exception:
pass
_run_cleanup()
print("\nGoodbye! ⚕")