mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-08-11 16:08:39 -04:00
d449a9d431
* fix(history): defer full hydration to model sends * fix(session): key hydration on real rows, fork through get_session Two regressions from the display/model-context split, both reproducible against dev. The hydration gate compared the cached transcript against the denormalized sessions.message_count column. That column drifts in normal operation — _persist_message swallows a failed insert while add_message has already appended in memory, so the next successful persist writes rows+1 — and _db_to_session re-read the same column after each reload, so the shortfall never closed. Every send, edit, delete and truncate on a warm session re-selected the whole message table: the cost this change set out to remove, relocated onto the hot path. The other direction was just as bad — a persist for an uncached session writes message_count = 0, and a stale-low counter with a partly filled cache meant no hydration at all and a silently truncated transcript for the model. sync_session_metadata now reconciles message_count against COUNT(*) on chat_messages (one indexed count inside the connection it already opens), and _db_to_session trusts the rows it just loaded. A hydrate always closes the gap, so the next read is a cache hit. fork_session read session_manager.sessions directly and never hydrated. keep_count indexes into source.history, and display pagination no longer fills that cache, so forking after a restart returned HTTP 200 with an empty conversation and no error surfaced. It goes through get_session now. _hydrate_session_history_from_db is gone with its helper: get_session is the hydration seam, and rebuilding session.history from raw rows in the display fallback overwrote the parsed multimodal content and the _db_id edit/delete keys that had just been set. Tests drive a real SessionManager over a temp DB instead of a stub that only proved the stub hydrates — both drift directions, the send path warm and cold, and a fork taken after a restart. All five fail without this change. The brittle SQL-text assertions are dropped; the page bounds are already proven by the response body. * fix(history): route pagination through canonical handler --------- Co-authored-by: Léo <leograndcontact@gmail.com>
39 lines
1.6 KiB
Python
39 lines
1.6 KiB
Python
"""Regression: the DB fallback in get_session_history must hide the same
|
|
messages the in-memory path hides.
|
|
|
|
The in-memory branch skips messages whose metadata has ``hidden`` (e.g.
|
|
compaction summaries that are kept for AI context but not shown to the user).
|
|
The DB fallback (taken when the in-memory history is empty, e.g. after a
|
|
restart) built the client response from every DB row with no such filter, so
|
|
hidden messages leaked to the client on DB-served sessions. Hydration of
|
|
``session.history`` belongs to ``get_session``; this fallback only shapes the
|
|
response, so only the response is filtered.
|
|
|
|
get_session_history depends on the DB, the session manager and a FastAPI
|
|
request, so this pins the regression at the source level (as other route tests
|
|
in this repo do).
|
|
"""
|
|
import ast
|
|
from pathlib import Path
|
|
|
|
SRC = Path(__file__).resolve().parent.parent / "routes" / "history" / "history_routes.py"
|
|
|
|
|
|
def _function_source(src_text, name):
|
|
tree = ast.parse(src_text)
|
|
for node in ast.walk(tree):
|
|
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and node.name == name:
|
|
return ast.get_source_segment(src_text, node)
|
|
raise AssertionError(f"{name} not found in {SRC}")
|
|
|
|
|
|
def test_db_fallback_filters_hidden_from_response():
|
|
src = _function_source(SRC.read_text(), "get_session_history")
|
|
marker = "load from DB"
|
|
assert marker in src, "expected the DB fallback block in get_session_history"
|
|
db_section = src.split(marker, 1)[1]
|
|
assert "hidden" in db_section, (
|
|
"the DB-fallback path must filter `hidden` messages from the response "
|
|
"to match the in-memory path"
|
|
)
|