fix: retain legacy compression recovery on older Agent APIs

This commit is contained in:
Anthony Ruiz committed 2026-09-20 17:07:58 +00:00
1 parent e3db8f7e01
commit 26b4a5816a
2 files changed
+48

No files matched your search

+11
View File
@@ -3,6 +3,7 @@
SQLite owns compression lineage; sidecar snapshot flags may predate a
Desktop/CLI rotation. Never reopen a sealed parent or mutate Agent state here.
"""
import inspect
import logging
from pathlib import Path
@@ -30,6 +31,16 @@ def durable_compression_continuation(session):
if not path.is_file():
return False, None
db = SessionDB(path, read_only=True)
# Establish the complete read API before accepting SQLite authority.
# Old Agents must retain legacy sidecar recovery, not a sealed null tip.
for name in ('get_session', 'get_compression_tip'):
method = getattr(db, name, None)
if not callable(method):
return False, None
try:
inspect.signature(method).bind(sid)
except (TypeError, ValueError):
return False, None
parent = db.get_session(sid)
if not parent or parent.get("end_reason") != "compression":
return False, None
+37
View File
@@ -109,6 +109,43 @@ def test_noncompressed_parent_and_absent_database_keep_legacy_behavior(lineage,
assert not (tmp_path / 'missing').exists()
@pytest.mark.parametrize('method', ['get_session', 'get_compression_tip'])
@pytest.mark.parametrize('kind', ['missing', 'noncallable', 'signature'])
def test_older_agent_keeps_sidecar_recovery(tmp_path, monkeypatch, method, kind):
import sys
from api.compression_continuation import durable_compression_continuation
class OldDB:
closed = False
def __init__(self, *args, **kwargs):
pass
def get_session(self, sid):
return {'end_reason': 'compression'}
def get_compression_tip(self, sid):
return 'legacychild'
def close(self):
OldDB.closed = True
if kind == 'missing':
delattr(OldDB, method)
elif kind == 'noncallable':
setattr(OldDB, method, None)
else:
setattr(OldDB, method, lambda self, sid, required: None)
monkeypatch.setitem(sys.modules, 'hermes_state', SimpleNamespace(SessionDB=OldDB))
(tmp_path / 'state.db').touch()
monkeypatch.setattr(profiles, '_resolve_profile_home_for_name', lambda _: str(tmp_path))
session = SimpleNamespace(session_id='legacyparent', profile='default', pre_compression_snapshot=True)
child = SimpleNamespace(session_id='legacychild', profile='default',
parent_session_id='legacyparent', pre_compression_snapshot=False,
updated_at=2, created_at=1)
monkeypatch.setattr(routes, 'SESSIONS', {'legacychild': child})
monkeypatch.setattr(routes, 'SESSION_DIR', tmp_path)
assert durable_compression_continuation(session) == (False, None)
assert OldDB.closed
assert routes._pre_compression_continuation_session_id(session) == 'legacychild'
def test_browser_rotation_restores_draft_without_reposting():
source = (Path(__file__).parents[1] / 'static/messages.js').read_text()
helper = source[source.index('async function _recoverCompressedSend('):source.index('function _restoreComposerDraftAfterFailedSend(')]