From fd48f26162130ab8b1a21b8f36c871ea2a4c237e Mon Sep 17 00:00:00 2001 From: Frank Song Date: Sun, 19 Jul 2026 05:16:06 +0800 Subject: [PATCH] Fail closed on historical anchor hydration throws --- static/ui.js | 4 +++- ...issue6220_id_linked_tool_anchor_hydration.py | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/static/ui.js b/static/ui.js index 3f696474..6b7c45c1 100644 --- a/static/ui.js +++ b/static/ui.js @@ -14808,7 +14808,9 @@ function _hydrateIdLinkedHistoricalToolScenes(messages, options){ let hydrated=0; const hydrateTurn=(turnEnd)=>{ if(turnStart<0||turnEnd<=turnStart+1) return; - const hydratedTurn=_idLinkedHistoricalTurnScene(list,turnStart,turnEnd,options); + let hydratedTurn; + try{hydratedTurn=_idLinkedHistoricalTurnScene(list,turnStart,turnEnd,options);} + catch(e){return;} if(!hydratedTurn) return; const owner=list[hydratedTurn.ownerIndex]; try{owner._anchor_activity_scene=hydratedTurn.scene;} diff --git a/tests/test_issue6220_id_linked_tool_anchor_hydration.py b/tests/test_issue6220_id_linked_tool_anchor_hydration.py index 2b32510b..42c4b460 100644 --- a/tests/test_issue6220_id_linked_tool_anchor_hydration.py +++ b/tests/test_issue6220_id_linked_tool_anchor_hydration.py @@ -49,7 +49,7 @@ function extractFunc(name){ """.strip() -def _run_hydration(messages: list[dict], *, repeat: bool = False) -> dict: +def _run_hydration(messages: list[dict], *, repeat: bool = False, throw_helper: bool = False) -> dict: assert NODE, "node is required for Anchor hydration behavior tests" script = f""" const fs = require('fs'); @@ -89,6 +89,13 @@ for(const name of [ vm.runInContext(extractFunc(name), sandbox, {{filename:'ui.js:' + name}}); }} +if({str(throw_helper).lower()}){{ + vm.runInContext( + "_toolArgsSnapshot = function(){{ throw new Error('synthetic event build failure'); }}", + sandbox + ); +}} + const messages = {json.dumps(messages)}; sandbox.messages = messages; const first = vm.runInContext( @@ -294,6 +301,14 @@ def test_ambiguous_or_richer_historical_tool_shapes_keep_legacy_ownership(messag assert data["owners"] == [] +@pytest.mark.skipif(NODE is None, reason="node is required for Anchor hydration tests") +def test_event_building_helper_exceptions_keep_legacy_ownership(): + data = _run_hydration(_linked_turn(), throw_helper=True) + + assert data["first"] == 0 + assert data["owners"] == [] + + @pytest.mark.skipif(NODE is None, reason="node is required for Anchor hydration tests") def test_reused_ids_in_adjacent_complete_turns_remain_turn_scoped(): data = _run_hydration(_linked_turn("call-reused") + _linked_turn("call-reused"))