fix: keep compression anchor stable in windowed transcript

This commit is contained in:
Lumen Yang 2026-05-13 08:49:25 +02:00
parent 9268f411d8
commit d13a174fe1
2 changed files with 38 additions and 3 deletions

View file

@ -4472,9 +4472,11 @@ function _compressionAnchorIndex(visWithIdx, anchorKey, fallbackIdx=null){
for(let i=visWithIdx.length-1;i>=0;i--){
const candidate=_compressionMessageAnchorKey(visWithIdx[i].m);
if(!candidate) continue;
const anchorTs=String(anchorKey.ts??'');
const candidateTs=String(candidate.ts??'');
if(
candidate.role===String(anchorKey.role||'') &&
String(candidate.ts??'')===String(anchorKey.ts??'') &&
(!anchorTs||!candidateTs||candidateTs===anchorTs) &&
String(candidate.text||'')===String(anchorKey.text||'') &&
Number(candidate.attachments||0)===Number(anchorKey.attachments||0)
){
@ -4938,13 +4940,19 @@ function renderMessages(options){
break;
}
}
const insertionAnchor=_compressionAnchorIndex(
renderVisWithIdx,
const insertionAnchorFull=_compressionAnchorIndex(
visWithIdx,
compressionState ? compressionState.anchorMessageKey : sessionCompressionAnchorKey,
compressionState
? (typeof compressionState.anchorVisibleIdx==='number' ? compressionState.anchorVisibleIdx : compressionState.anchorRawIdx)
: sessionCompressionAnchor
);
let insertionAnchor=null;
if(typeof insertionAnchorFull==='number'){
if(insertionAnchorFull<windowStart) insertionAnchor=renderVisWithIdx.length?0:null;
else if(insertionAnchorFull<windowStart+renderVisWithIdx.length) insertionAnchor=insertionAnchorFull-windowStart;
else insertionAnchor=renderVisWithIdx.length?renderVisWithIdx.length-1:null;
}
let _prevSepKey=null;
let currentAssistantTurn=null;
const assistantSegments=new Map();

View file

@ -217,6 +217,33 @@ def test_context_anchor_reference_uses_session_summary_fallback():
assert "!!referenceText && (sessionCompressionAnchor!==null || sessionCompressionAnchorKey || sessionCompressionSummary)" in src
def test_compression_anchor_matching_tolerates_legacy_missing_timestamp():
src = _read("static/ui.js")
start = src.find("function _compressionAnchorIndex")
assert start != -1, "compression anchor matcher not found"
end = src.find("function _compressionReferenceCardHtml", start)
assert end != -1, "compression reference renderer not found after anchor matcher"
helper = src[start:end]
assert "const anchorTs=String(anchorKey.ts??'');" in helper
assert "const candidateTs=String(candidate.ts??'');" in helper
assert "(!anchorTs||!candidateTs||candidateTs===anchorTs)" in helper
def test_compression_anchor_index_is_translated_into_render_window():
src = _read("static/ui.js")
start = src.find("const insertionAnchorFull=_compressionAnchorIndex")
assert start != -1, "full compression anchor lookup not found"
end = src.find("let _prevSepKey=null", start)
assert end != -1, "message render loop marker not found after anchor lookup"
block = src[start:end]
assert "_compressionAnchorIndex(\n visWithIdx," in block
assert "insertionAnchorFull<windowStart" in block
assert "insertionAnchorFull-windowStart" in block
assert "windowStart+renderVisWithIdx.length" in block
def test_preserved_task_list_attaches_once_per_render():
src = _read("static/ui.js")