"""Behavior coverage for content-addressed session system prompts.""" from __future__ import annotations import json import sqlite3 import time import pytest from hermes_state import SCHEMA_VERSION, SessionDB @pytest.fixture() def db(tmp_path): session_db = SessionDB(db_path=tmp_path / "state.db") yield session_db session_db.close() def _prompt_count(db: SessionDB) -> int: return int( db._conn.execute("SELECT COUNT(*) FROM system_prompts").fetchone()[0] ) def test_prompt_snapshots_are_deduplicated_and_hydrated_for_readers(db): prompt = "You are Hermes.\n" + ("Follow the profile policy.\n" * 5) db.create_session( "s1", "telegram", session_key="agent:main:telegram:dm:c1", chat_id="c1", chat_type="dm", system_prompt=prompt, ) db.create_session("s2", "cli", system_prompt=prompt) db.request_handoff("s1", "telegram") stored = db._conn.execute( "SELECT hash, prompt FROM system_prompts" ).fetchall() assert len(stored) == 1 assert stored[0]["prompt"] == prompt raw_sessions = db._conn.execute( "SELECT system_prompt, system_prompt_hash FROM sessions ORDER BY id" ).fetchall() assert [row["system_prompt"] for row in raw_sessions] == [None, None] assert {row["system_prompt_hash"] for row in raw_sessions} == { stored[0]["hash"] } assert db.get_session("s1")["system_prompt"] == prompt assert db.list_sessions_rich()[0]["system_prompt"] == prompt assert db.search_sessions()[0]["system_prompt"] == prompt assert db.export_session("s1")["system_prompt"] == prompt assert db.list_gateway_sessions()[0]["system_prompt"] == prompt assert db.list_pending_handoffs()[0]["system_prompt"] == prompt def test_prompt_replacement_and_route_changes_collect_only_orphans(db): shared_prompt = "Model: x-ai/grok-4.5\nProvider: nous" db.create_session( "s1", "hermes_browser", model="x-ai/grok-4.5", model_config={"_branched_from": "parent"}, system_prompt=shared_prompt, ) db.create_session("s2", "cli", system_prompt=shared_prompt) db.update_session_runtime_lock( "s1", model="anthropic/claude-opus-4.8", provider="anthropic", confirmed=True, ) s1 = db.get_session("s1") assert s1["system_prompt"] is None assert json.loads(s1["model_config"])["_branched_from"] == "parent" assert db.get_session("s2")["system_prompt"] == shared_prompt assert _prompt_count(db) == 1 db.update_session_billing_route( "s2", provider="openrouter", base_url="https://example.test/v1", ) assert db.get_session("s2")["system_prompt"] is None assert _prompt_count(db) == 0 db.update_system_prompt("s2", "replacement") assert db.get_session("s2")["system_prompt"] == "replacement" db.update_system_prompt("s2", None) assert _prompt_count(db) == 0 def test_existing_session_enrichment_does_not_leak_unused_prompt(db): db.create_session("s1", "cli", system_prompt="original prompt") db.create_session("s1", "cli", system_prompt="unused prompt") prompts = [ row["prompt"] for row in db._conn.execute("SELECT prompt FROM system_prompts") ] assert prompts == ["original prompt"] assert db.get_session("s1")["system_prompt"] == "original prompt" def test_every_session_deletion_path_reclaims_final_prompt_reference(db): def seed(session_id: str, *, source: str = "cli") -> None: db.create_session( session_id, source, system_prompt=f"unique prompt for {session_id}", ) assert _prompt_count(db) == 1 seed("single-empty") assert db.delete_session_if_empty("single-empty") is True assert _prompt_count(db) == 0 seed("bulk") assert db.delete_sessions(["bulk"]) == 1 assert _prompt_count(db) == 0 seed("ended-empty") db.end_session("ended-empty", "user_exit") assert db.delete_empty_sessions() == 1 assert _prompt_count(db) == 0 seed("pruned") db.end_session("pruned", "user_exit") assert db.prune_sessions( older_than_days=None, started_before=time.time() + 1, ) == 1 assert _prompt_count(db) == 0 seed("ghost", source="tui") db.end_session("ghost", "user_exit") db._conn.execute("UPDATE sessions SET started_at = 0 WHERE id = 'ghost'") db._conn.commit() assert db.prune_empty_ghost_sessions() == 1 assert _prompt_count(db) == 0 def test_deleting_one_shared_session_preserves_prompt_until_final_reference(db): prompt = "shared deletion prompt" db.create_session("s1", "cli", system_prompt=prompt) db.create_session("s2", "cli", system_prompt=prompt) assert db.delete_session("s1") is True assert _prompt_count(db) == 1 assert db.get_session("s2")["system_prompt"] == prompt assert db.delete_session("s2") is True assert _prompt_count(db) == 0 def test_compression_child_uses_content_addressed_prompt(db): prompt = "compressed child prompt" db.create_session("parent", "webui") db.append_message("parent", "user", "original") assert db.try_acquire_compression_lock("parent", "holder", ttl_seconds=60) db.publish_compression_child( parent_session_id="parent", child_session_id="child", source="webui", system_prompt=prompt, messages=[{"role": "user", "content": "summary"}], compression_lock_holder="holder", ) raw = db._conn.execute( "SELECT system_prompt, system_prompt_hash FROM sessions WHERE id = 'child'" ).fetchone() assert raw["system_prompt"] is None assert raw["system_prompt_hash"] is not None assert db.get_session("child")["system_prompt"] == prompt assert _prompt_count(db) == 1 def test_imported_prompts_are_deduplicated(tmp_path): prompt = "shared imported prompt" source = SessionDB(db_path=tmp_path / "source.db") try: source.create_session("s1", "cli", system_prompt=prompt) source.create_session("s2", "telegram", system_prompt=prompt) exported = [source.export_session("s1"), source.export_session("s2")] finally: source.close() target = SessionDB(db_path=tmp_path / "target.db") try: result = target.import_sessions(exported) assert result["ok"] is True assert result["imported"] == 2 assert _prompt_count(target) == 1 raw = target._conn.execute( "SELECT system_prompt, system_prompt_hash FROM sessions ORDER BY id" ).fetchall() assert [row["system_prompt"] for row in raw] == [None, None] assert len({row["system_prompt_hash"] for row in raw}) == 1 assert target.get_session("s1")["system_prompt"] == prompt assert target.get_session("s2")["system_prompt"] == prompt finally: target.close() def test_v24_inline_prompts_migrate_once_to_content_addressed_storage(tmp_path): db_path = tmp_path / "legacy-prompts.db" legacy_prompt = "Legacy system prompt\n" + ("same policy\n" * 20) db = SessionDB(db_path=db_path) db.create_session("s1", "cli") db.create_session("s2", "telegram") db._conn.execute( "UPDATE sessions SET system_prompt = ?, system_prompt_hash = NULL", (legacy_prompt,), ) db._conn.execute("UPDATE schema_version SET version = 24") db._conn.commit() db.close() migrated = SessionDB(db_path=db_path) try: assert migrated.get_session("s1")["system_prompt"] == legacy_prompt assert migrated.get_session("s2")["system_prompt"] == legacy_prompt assert _prompt_count(migrated) == 1 raw_sessions = migrated._conn.execute( "SELECT system_prompt, system_prompt_hash FROM sessions ORDER BY id" ).fetchall() assert [row["system_prompt"] for row in raw_sessions] == [None, None] assert len({row["system_prompt_hash"] for row in raw_sessions}) == 1 assert migrated._conn.execute( "SELECT version FROM schema_version LIMIT 1" ).fetchone()[0] == SCHEMA_VERSION finally: migrated.close() def test_compact_rows_omit_hash_and_never_read_prompt_blob(db): db.create_session("s1", "cli", system_prompt="never materialize me") def deny_prompt_reads(action, table, column, database, trigger): if action == sqlite3.SQLITE_READ and table == "system_prompts": return sqlite3.SQLITE_DENY return sqlite3.SQLITE_OK db._conn.set_authorizer(deny_prompt_reads) try: rows = db.list_sessions_rich( compact_rows=True, order_by_last_active=True, ) rich = db._get_session_rich_row("s1", compact_rows=True) finally: db._conn.set_authorizer(None) assert rows[0]["id"] == "s1" assert rich["id"] == "s1" assert "system_prompt" not in rows[0] assert "system_prompt_hash" not in rows[0] assert "system_prompt" not in rich assert "system_prompt_hash" not in rich