fix(pheby): restore paged history across session resets

This commit is contained in:
2026-09-23 12:04:31 +00:00
parent e8c60a1001
commit 7ad8bf1155
4 changed files with 155 additions and 39 deletions
+69 -6
View File
@@ -334,6 +334,16 @@ class TestConversations:
ev = client.ws.events()[-1]
assert ev["error"]["code"] == proto.ERR_BAD_REQUEST
@pytest.mark.asyncio
async def test_invalid_history_cursor_rejected(self, tmp_path):
server = make_server(tmp_path)
client = FakeClientConnection()
client.authenticated = True
await server._handle_conversation_open(client, {
"type": proto.C_CONVERSATION_OPEN,
"conversation_id": "conv", "before_message_id": "m0 OR 1=1"}, "r1")
assert client.ws.events()[-1]["error"]["code"] == proto.ERR_BAD_REQUEST
@pytest.mark.asyncio
async def test_ids_survive_router_reload(self, tmp_path):
server = make_server(tmp_path)
@@ -443,8 +453,12 @@ class TestBridge:
return "session-1"
class DB:
def get_messages_as_conversation(self, _session_id, include_row_ids=False):
def _read_all(self, sql, params):
return [{"id": "session-1"}]
def get_messages_as_conversation(self, _session_id, include_row_ids=False, include_compacted=False):
assert include_row_ids is True
assert include_compacted is True
return [
{"_row_id": 10, "role": "user", "content": "hello", "timestamp": 1_789_000_000.25},
{"_row_id": 11, "role": "assistant", "content": "reply", "timestamp": 1_789_000_001.5},
@@ -453,13 +467,58 @@ class TestBridge:
monkeypatch.setattr(hb, "_session_store", lambda: Store())
monkeypatch.setattr(hb, "_session_db", lambda: DB())
history, found = await hb.conversation_history("conv", 20)
history, found, older = await hb.conversation_history("conv", 20)
assert found is True
assert older is False
assert [message["message_id"] for message in history] == ["m10", "m11"]
assert history[0]["ts"] == "2026-09-10T00:26:40.250000+00:00"
assert history[1]["ts"] == "2026-09-10T00:26:41.500000+00:00"
@pytest.mark.asyncio
async def test_history_spans_reset_sessions_and_pages_without_duplicates(self, monkeypatch):
from pheby import hermes_bridge as hb
class Store:
def peek_session_id(self, _key):
return "new"
class DB:
def _read_all(self, sql, params):
assert "session_key" in sql and params[1] == "pheby"
return [{"id": "old"}, {"id": "new"}]
def get_messages_as_conversation(self, sid, **kwargs):
assert kwargs == {"include_row_ids": True, "include_compacted": True}
start = 1 if sid == "old" else 4
return [{"_row_id": n, "role": "user", "content": f"turn {n}", "timestamp": float(n)}
for n in range(start, start + 3)]
monkeypatch.setattr(hb, "_session_store", lambda: Store())
monkeypatch.setattr(hb, "_session_db", lambda: DB())
latest, found, older = await hb.conversation_history("conv", 2)
assert found and older
assert [m["message_id"] for m in latest] == ["m5", "m6"]
previous, found, older = await hb.conversation_history("conv", 2, before_id=5)
assert found and older
assert [m["message_id"] for m in previous] == ["m3", "m4"]
first, found, older = await hb.conversation_history("conv", 2, before_id=3)
assert found and not older
assert [m["message_id"] for m in first] == ["m1", "m2"]
@pytest.mark.asyncio
async def test_history_read_failure_is_not_reported_as_empty_chat(self, monkeypatch):
from pheby import hermes_bridge as hb
class DB:
def _read_all(self, _sql, _params):
raise OSError("database offline")
monkeypatch.setattr(hb, "_session_store", lambda: None)
monkeypatch.setattr(hb, "_session_db", lambda: DB())
with pytest.raises(RuntimeError, match="transcript"):
await hb.conversation_history("conv", 20)
def test_iso_parses_by_instant_for_naive_local_datetimes(self):
# gateway session-store timestamps are naive LOCAL datetimes
# (gateway.session_lifecycle._now). last_active must come back with a
@@ -776,9 +835,13 @@ class TestBridge:
class DB:
deleted = None
def delete_session(self, session_id):
self.deleted = session_id
return True
def _read_all(self, sql, params):
assert "session_key" in sql and params == (session_key, "pheby")
return [{"id": "session-old"}, {"id": "session-delete"}]
def delete_sessions(self, session_ids):
self.deleted = list(session_ids)
return len(session_ids)
store, db = Store(), DB()
from pheby import hermes_bridge as hb
@@ -786,7 +849,7 @@ class TestBridge:
monkeypatch.setattr(hb, "_session_db", lambda: db)
assert await hb.delete_conversation(cid) is True
assert db.deleted == "session-delete"
assert db.deleted == ["session-old", "session-delete"]
assert session_key not in store._entries
assert store.saved is True
assert await server.router.get_name(cid) is None