diff --git a/CHANGELOG.md b/CHANGELOG.md index b9e39143..74f075d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ ### Fixed +- **PR #2337** by @Michaelyklam (closes #2336) — Pre-compression snapshot preservation now also clears stale runtime stream fields when the existing on-disk snapshot is already as complete as the in-memory session. This keeps the load-and-mark branch aligned with the full-save branch and adds regression coverage so archived parent snapshots cannot retain stale `active_stream_id` / `pending_*` state. + - **PR #2322** by @Michaelyklam (refs #2271) — LAN Ollama models selected from endpoint-discovered `custom:-` / `custom::` picker entries now route through the configured `ollama` provider and base URL instead of surfacing a missing `CUSTOM_*_API_KEY` error. The picker still surfaces endpoint-discovered entries; the fix is to recognize them as UI routing hints matching the configured local-server base URL and resolve them via the actual `ollama` provider. diff --git a/api/streaming.py b/api/streaming.py index 9c4f4548..f5bc30ad 100644 --- a/api/streaming.py +++ b/api/streaming.py @@ -1738,8 +1738,6 @@ def _preserve_pre_compression_snapshot(s, old_sid: str) -> None: # than leaving an unreadable recovery snapshot behind. existing_msgs = -1 existing_snapshot = False - if len(s.messages) <= existing_msgs and existing_snapshot: - return if len(s.messages) > existing_msgs: # In-memory messages are newer than the file; save the full old # snapshot from the current session object while preserving its diff --git a/tests/test_compression_snapshot_runtime_clear.py b/tests/test_compression_snapshot_runtime_clear.py index 9584c1a5..6ee5bd50 100644 --- a/tests/test_compression_snapshot_runtime_clear.py +++ b/tests/test_compression_snapshot_runtime_clear.py @@ -1,5 +1,6 @@ import json +from api import models from api import streaming @@ -62,3 +63,35 @@ def test_preserve_pre_compression_snapshot_clears_runtime_fields_while_restoring assert saved["pending_user_message"] is None assert saved["pending_attachments"] == [] assert saved["pending_started_at"] is None + + +def test_preserve_pre_compression_snapshot_load_and_mark_branch_clears_runtime_fields(tmp_path, monkeypatch): + monkeypatch.setattr(streaming, "SESSION_DIR", tmp_path) + monkeypatch.setattr(models, "SESSION_DIR", tmp_path) + old_payload = { + "session_id": "old_session", + "title": "Archived parent", + "messages": [ + {"role": "user", "content": "older prompt"}, + {"role": "assistant", "content": "older answer"}, + {"role": "user", "content": "newer prompt already on disk"}, + ], + "pre_compression_snapshot": True, + "active_stream_id": "stale-stream", + "pending_user_message": "stale prompt", + "pending_attachments": [{"name": "stale.txt"}], + "pending_started_at": 12345, + } + (tmp_path / "old_session.json").write_text(json.dumps(old_payload), encoding="utf-8") + session = FakeSession() + session.messages = [{"role": "user", "content": "current prompt"}] + + streaming._preserve_pre_compression_snapshot(session, "old_session") + + saved = json.loads((tmp_path / "old_session.json").read_text(encoding="utf-8")) + assert saved["messages"] == old_payload["messages"] + assert saved["pre_compression_snapshot"] is True + assert saved["active_stream_id"] is None + assert saved["pending_user_message"] is None + assert saved["pending_attachments"] == [] + assert saved["pending_started_at"] is None