From 9e894a25553609b953c63f988245688cc4a85308 Mon Sep 17 00:00:00 2001 From: Dennis Soong Date: Fri, 1 May 2026 16:36:53 +0800 Subject: [PATCH] fix: sync URL after session id rotation --- static/messages.js | 8 ++++++++ tests/test_session_rotate_url_sync.py | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/test_session_rotate_url_sync.py diff --git a/static/messages.js b/static/messages.js index ceb3b475..e761972e 100644 --- a/static/messages.js +++ b/static/messages.js @@ -827,6 +827,10 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){ const _prevOut=(S.session&&S.session.output_tokens)||0; const _prevCost=(S.session&&S.session.estimated_cost)||0; S.session=d.session;S.messages=d.session.messages||[];if(typeof _messagesTruncated!=='undefined')_messagesTruncated=!!d.session._messages_truncated; + if(S.session&&S.session.session_id){ + localStorage.setItem('hermes-webui-session',S.session.session_id); + if(typeof _setActiveSessionUrl==='function') _setActiveSessionUrl(S.session.session_id); + } if( window._compressionUi&&window._compressionUi.automatic&& window._compressionUi.sessionId===activeSid&& @@ -1092,6 +1096,10 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){ S.activeStreamId=null; clearLiveToolCards();if(!assistantText)removeThinking(); S.session=session;S.messages=(session.messages||[]).filter(m=>m&&m.role); + if(S.session&&S.session.session_id){ + localStorage.setItem('hermes-webui-session',S.session.session_id); + if(typeof _setActiveSessionUrl==='function') _setActiveSessionUrl(S.session.session_id); + } const hasMessageToolMetadata=S.messages.some(m=>{ if(!m||m.role!=='assistant') return false; // Recognize both the standard `tool_calls` (used by completed assistant diff --git a/tests/test_session_rotate_url_sync.py b/tests/test_session_rotate_url_sync.py new file mode 100644 index 00000000..a941a3d7 --- /dev/null +++ b/tests/test_session_rotate_url_sync.py @@ -0,0 +1,24 @@ +"""Regression tests for session id rotation URL sync.""" +from pathlib import Path + +REPO_ROOT = Path(__file__).parent.parent.resolve() +MESSAGES_JS = (REPO_ROOT / "static" / "messages.js").read_text(encoding="utf-8") + + +def test_stream_completion_syncs_rotated_session_id_to_tab_state(): + """When compact/restore returns a new session id, the tab anchor follows it.""" + completion_marker = "S.session=d.session;S.messages=d.session.messages||[]" + settled_marker = "S.session=session;S.messages=(session.messages||[]).filter(m=>m&&m.role);" + + completion_pos = MESSAGES_JS.find(completion_marker) + settled_pos = MESSAGES_JS.find(settled_marker) + assert completion_pos != -1 + assert settled_pos != -1 + + completion_block = MESSAGES_JS[completion_pos : completion_pos + 500] + settled_block = MESSAGES_JS[settled_pos : settled_pos + 500] + + for block in (completion_block, settled_block): + assert "localStorage.setItem('hermes-webui-session',S.session.session_id);" in block + assert "_setActiveSessionUrl(S.session.session_id)" in block + assert "typeof _setActiveSessionUrl==='function'" in block