From 541c064a72a38ebe75d16dbf0884ac844f4fcd35 Mon Sep 17 00:00:00 2001 From: george-andraws <96165956+george-andraws@users.noreply.github.com> Date: Tue, 26 May 2026 22:00:04 -0700 Subject: [PATCH] fix(session): route messaging metadata loads through display merge Use _merged_session_messages_for_display for is_messaging_session even in the metadata-only (messages=0) path. This ensures message_count and last_message_at match the full load path for Telegram / external messaging sessions that have stitched or duplicate rows in state.db + sidecar. Prevents spurious refresh loops, scroll resets, and open panel closures when resuming cross-surface sessions in the WebUI. No impact on CLI, non-messaging, or full-message paths. All 580 session tests pass. Fixes the root cause identified in the SessionDB / render interaction changes. --- api/routes.py | 3 +-- tests/test_session_cli_scan_fast_path.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/api/routes.py b/api/routes.py index c80d74aa..4fddc8f7 100644 --- a/api/routes.py +++ b/api/routes.py @@ -4152,8 +4152,7 @@ def handle_get(handler, parsed) -> bool: ) else: if is_messaging_session and cli_messages: - sidecar_messages = getattr(s, "messages", []) or [] - _all_msgs = merge_session_messages_append_only(cli_messages, sidecar_messages) + _all_msgs = _merged_session_messages_for_display(s, cli_messages) else: if metadata_summary is None: metadata_summary = _message_summary(getattr(s, "messages", []) or []) diff --git a/tests/test_session_cli_scan_fast_path.py b/tests/test_session_cli_scan_fast_path.py index a28b0318..70069318 100644 --- a/tests/test_session_cli_scan_fast_path.py +++ b/tests/test_session_cli_scan_fast_path.py @@ -107,3 +107,20 @@ def test_messaging_session_metadata_load_preserves_cli_metadata_lookup(monkeypat assert looked_up == ["messaging_sidecar"] assert response["session"]["source_label"] == "Telegram" + + +def test_messaging_session_metadata_matches_full_display_merge(monkeypatch): + import api.routes as routes + from api.models import Session + sidecar = [{"role": "user", "content": "hi", "timestamp": 1000}, {"role": "assistant", "content": "ok", "timestamp": 1001}] + cli = sidecar + [{"role": "assistant", "content": "ok", "timestamp": 1001.7}] + session = Session(session_id="telegram_resume", title="Telegram", messages=sidecar, session_source="messaging", raw_source="telegram") + monkeypatch.setattr(routes, "get_session", lambda sid, metadata_only=False: session) + monkeypatch.setattr(routes, "_clear_stale_stream_state", lambda _session: None) + monkeypatch.setattr(routes, "_lookup_cli_session_metadata", lambda sid: {"session_id": sid, "session_source": "messaging", "raw_source": "telegram"}) + monkeypatch.setattr(routes, "get_cli_session_messages", lambda _sid: cli) + monkeypatch.setattr(routes, "redact_session_data", lambda payload: payload) + monkeypatch.setattr(routes, "j", lambda _handler, payload, status=200, extra_headers=None: payload) + full = routes.handle_get(object(), urlparse("/api/session?session_id=telegram_resume&messages=1&resolve_model=0"))["session"] + meta = routes.handle_get(object(), urlparse("/api/session?session_id=telegram_resume&messages=0&resolve_model=0"))["session"] + assert (meta["message_count"], meta["last_message_at"]) == (full["message_count"], full["last_message_at"])