fix: dedupe sidebar completion session ids
This commit is contained in:
parent
7dc4273a21
commit
9458df6f4d
4 changed files with 66 additions and 2 deletions
|
|
@ -3,6 +3,10 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Avoid duplicate sidebar rows when a compressed session completes after both the preserved snapshot id and continuation id are already present in the session list.
|
||||
|
||||
## [v0.51.171] — 2026-05-30 — Release EQ (stage-batch53 — tool-output card badge + Neon opt-in skin)
|
||||
|
||||
### Added
|
||||
|
|
|
|||
|
|
@ -361,7 +361,9 @@ function _markSessionCompletedInList(session, previousSid = null) {
|
|||
if (!session || !Array.isArray(_allSessions)) return;
|
||||
const finalSid = session.session_id || previousSid;
|
||||
if (!finalSid) return;
|
||||
const idx = _allSessions.findIndex(s => s && (s.session_id === finalSid || s.session_id === previousSid));
|
||||
const finalIdx = _allSessions.findIndex(s => s && s.session_id === finalSid);
|
||||
const previousIdx = previousSid ? _allSessions.findIndex(s => s && s.session_id === previousSid) : -1;
|
||||
const idx = finalIdx >= 0 ? finalIdx : previousIdx;
|
||||
if (idx < 0) return;
|
||||
const {messages: _messages, tool_calls: _toolCalls, ...sessionMeta} = session;
|
||||
const messageCount = Number(
|
||||
|
|
@ -384,6 +386,11 @@ function _markSessionCompletedInList(session, previousSid = null) {
|
|||
_sessionStreamingById.set(finalSid, false);
|
||||
_forgetObservedStreamingSession(finalSid);
|
||||
if (previousSid && previousSid !== finalSid) {
|
||||
for (let i = _allSessions.length - 1; i >= 0; i--) {
|
||||
if (i !== idx && _allSessions[i] && _allSessions[i].session_id === previousSid) {
|
||||
_allSessions.splice(i, 1);
|
||||
}
|
||||
}
|
||||
_sessionStreamingById.delete(previousSid);
|
||||
_forgetObservedStreamingSession(previousSid);
|
||||
_sessionListSnapshotById.delete(previousSid);
|
||||
|
|
|
|||
|
|
@ -100,7 +100,9 @@ def test_sidebar_cache_completion_handles_compression_session_rotation():
|
|||
|
||||
assert "function _markSessionCompletedInList(session, previousSid = null)" in helper_block
|
||||
assert "const finalSid = session.session_id || previousSid;" in helper_block
|
||||
assert "s.session_id === finalSid || s.session_id === previousSid" in helper_block
|
||||
assert "const finalIdx = _allSessions.findIndex(s => s && s.session_id === finalSid);" in helper_block
|
||||
assert "const previousIdx = previousSid ? _allSessions.findIndex(s => s && s.session_id === previousSid) : -1;" in helper_block
|
||||
assert "const idx = finalIdx >= 0 ? finalIdx : previousIdx;" in helper_block
|
||||
assert "const {messages: _messages, tool_calls: _toolCalls, ...sessionMeta} = session;" in helper_block
|
||||
assert "...sessionMeta" in helper_block
|
||||
assert "session_id: finalSid" in helper_block
|
||||
|
|
|
|||
51
tests/test_sidebar_completion_dedupe.py
Normal file
51
tests/test_sidebar_completion_dedupe.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def _extract_js_function(src: str, name: str) -> str:
|
||||
start = src.index(f"function {name}(")
|
||||
brace = src.index("{", start)
|
||||
depth = 0
|
||||
for idx in range(brace, len(src)):
|
||||
ch = src[idx]
|
||||
if ch == "{":
|
||||
depth += 1
|
||||
elif ch == "}":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
return src[start : idx + 1]
|
||||
raise AssertionError(f"could not extract {name}")
|
||||
|
||||
|
||||
def test_mark_session_completed_in_list_dedupes_old_and_new_sid_rows():
|
||||
sessions_src = (REPO_ROOT / "static" / "sessions.js").read_text(encoding="utf-8")
|
||||
fn_src = _extract_js_function(sessions_src, "_markSessionCompletedInList")
|
||||
script = f"""
|
||||
let _allSessions = [
|
||||
{{ session_id: 'old', title: 'Before', message_count: 10, pre_compression_snapshot: true }},
|
||||
{{ session_id: 'new', title: 'After', message_count: 2, parent_session_id: 'old' }},
|
||||
];
|
||||
let _sessionStreamingById = new Map([['old', true], ['new', true]]);
|
||||
let _sessionListSnapshotById = new Map([['old', {{message_count: 10}}]]);
|
||||
function _forgetObservedStreamingSession(_sid) {{}}
|
||||
function renderSessionListFromCache() {{}}
|
||||
{fn_src}
|
||||
_markSessionCompletedInList({{
|
||||
session_id: 'new',
|
||||
title: 'After done',
|
||||
message_count: 3,
|
||||
parent_session_id: 'old',
|
||||
}}, 'old');
|
||||
console.log(JSON.stringify({{rows: _allSessions, oldStreaming: _sessionStreamingById.has('old')}}));
|
||||
"""
|
||||
result = subprocess.run(["node", "-e", script], check=True, text=True, capture_output=True)
|
||||
payload = json.loads(result.stdout)
|
||||
|
||||
assert [row["session_id"] for row in payload["rows"]] == ["new"]
|
||||
assert payload["rows"][0]["title"] == "After done"
|
||||
assert payload["rows"][0]["message_count"] == 3
|
||||
assert payload["oldStreaming"] is False
|
||||
Loading…
Reference in a new issue