diff --git a/static/messages.js b/static/messages.js index 2d5e24b72..037a5eae2 100644 --- a/static/messages.js +++ b/static/messages.js @@ -2551,6 +2551,15 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){ if(!byIdx.has(idx)) byIdx.set(idx,[]); byIdx.get(idx).push(row); }; + // Pre-index S.toolCalls by assistant_msg_idx for O(m+n) lookup + const toolsByIdx=new Map(); + if(S.toolCalls) for(const tc of S.toolCalls){ + const ti=typeof tc.toolIdx==='number'? tc.toolIdx : parseInt(tc.assistant_msg_idx,10); + if(Number.isFinite(ti)){ + if(!toolsByIdx.has(ti)) toolsByIdx.set(ti,[]); + toolsByIdx.get(ti).push(tc); + } + } let encounter=0; for(let idx=turnStart+1;idx=lastAsstIndex) continue; const row=_anchorSceneToolRowFromCall(tool,0,idx); const tid=row.tool_call_id||(row.tool&&row.tool.id); if(tid&&seenToolIds.has(tid)) continue; diff --git a/tests/test_live_to_final_anchor_visible_order.py b/tests/test_live_to_final_anchor_visible_order.py index 3803537b9..b01d96e43 100644 --- a/tests/test_live_to_final_anchor_visible_order.py +++ b/tests/test_live_to_final_anchor_visible_order.py @@ -709,8 +709,9 @@ def test_settled_anchor_scene_persists_the_full_assistant_turn_not_only_tail(): assert "messages.slice(turnStart+1,lastAsstIndex+1)" in complete assert "message.reasoning||message._reasoning||message.reasoning_content||message.thinking" in reasoning_text assert "const reasoning=_anchorSceneMessageReasoningText(message);" in rows_by_message - assert "const toolCalls=Array.isArray(S.toolCalls)?S.toolCalls:[]" in rows_by_message - assert "toolIdx<=turnStart||toolIdx>=lastAsstIndex" in rows_by_message + assert "const toolsByIdx=new Map();" in rows_by_message + assert "if(S.toolCalls) for(const tc of S.toolCalls){" in rows_by_message + assert "for(const tool of (toolsByIdx.get(idx)||[]))" in rows_by_message assert "_anchorSceneToolRowFromCall(tool,0,idx)" in rows_by_message