fix(#3996): preserve pending sid on hidden-tab skip so a bg-tab session reopens (Codex CORE)

If startSessionStream(sid) runs while the tab is ALREADY hidden (session loaded/
restored in a background tab), it set _sessionStreamSessionId then returned at the
hidden-skip WITHOUT recording _sessionStreamHiddenSid — so the visibility handler
(which reopens only from the holder) never reattached, silently dropping
bg_task_complete/server_turn_started until the next explicit startSessionStream.
Set _sessionStreamHiddenSid = sid on the hidden-skip return. Adds a regression test.
This commit is contained in:
nesquena-hermes
2026-06-11 19:17:11 +00:00
parent 8a22540df4
commit 2cbae63a8d
2 changed files with 31 additions and 3 deletions

View File

@@ -4230,8 +4230,13 @@ function startSessionStream(sid) {
});
document._hermesSessionStreamVisibilityHook = true;
}
// Don't open when tab is hidden — saves connection pool slots
if (typeof document !== 'undefined' && document.hidden) return;
// Don't open when tab is hidden — saves connection pool slots. Preserve the
// pending session id so the visibility handler reopens it on re-show (a session
// loaded/restored while the tab is already hidden must still reattach).
if (typeof document !== 'undefined' && document.hidden) {
_sessionStreamHiddenSid = sid;
return;
}
try {
const es = new EventSource(_apiUrl('api/session/stream?session_id=' + encodeURIComponent(sid)));
_sessionEventSource = es;

View File

@@ -45,7 +45,7 @@ def test_session_stream_has_visibility_hook():
assert "visibilitychange" in block
assert "document.hidden" in block
# Must skip opening a new EventSource while the tab is hidden.
assert "if (typeof document !== 'undefined' && document.hidden) return;" in block
assert "if (typeof document !== 'undefined' && document.hidden) {" in block
def test_session_stream_reopens_from_dedicated_var_not_nulled_id():
@@ -82,3 +82,26 @@ def test_stop_session_stream_still_nulls_session_id():
assert stop_idx != -1
block = MESSAGES_JS[stop_idx:stop_idx + 400]
assert "_sessionStreamSessionId = null" in block
def test_session_stream_hidden_open_preserves_id_for_reopen():
"""A session opened while the tab is ALREADY hidden must still reopen on re-show.
Codex CORE: startSessionStream(sid) sets _sessionStreamSessionId and then
returns early when document.hidden. If it doesn't also record the id in the
dedicated holder, the visibility handler (which reopens only from the holder)
never reattaches — silently dropping bg_task_complete / server_turn_started
for a session loaded in a background tab. The hidden-skip path must set
_sessionStreamHiddenSid = sid before returning.
"""
start_idx = MESSAGES_JS.find("function startSessionStream(sid)")
block = MESSAGES_JS[start_idx:start_idx + 1700]
# Find the hidden-tab early-return skip path (distinct from the in-hook
# `if (document.hidden)` branch) and assert it preserves the id.
hidden_idx = block.find("!== 'undefined' && document.hidden) {")
assert hidden_idx != -1, "expected a braced hidden-tab skip block (not a bare return)"
hidden_block = block[hidden_idx:hidden_idx + 160]
assert "_sessionStreamHiddenSid = sid" in hidden_block, (
"hidden-tab skip must record the pending session id for reopen on re-show"
)