fix: allow current-pane SSE reconnect when unfocused

This commit is contained in:
ai-ag2026
2026-05-28 09:02:06 +02:00
parent 5528e2c579
commit c197e0c091
3 changed files with 42 additions and 1 deletions

View File

@@ -3,6 +3,10 @@
## [Unreleased]
### Fixed
- Visible but unfocused chat windows now still attempt the immediate SSE reconnect for the current session; only a real session switch skips the reconnect path. (Refs #3040)
## [v0.51.152] — 2026-05-28 — Release DX (stage-batch34 — single-PR optional gateway-backed browser chat)
### Added

View File

@@ -2155,7 +2155,7 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){
// If the user has switched to a different session, don't attempt to
// reconnect — the old stream's EventSource was closed intentionally
// during session switch and reconnecting would leak a background stream.
if(!_isSessionActivelyViewed(activeSid)) return;
if(!_isSessionCurrentPane(activeSid)) return;
if(_terminalStateReached || _streamFinalized){
return;
}

View File

@@ -0,0 +1,37 @@
"""Regression coverage for #3040 item 4: visible-but-unfocused stream reattach."""
from __future__ import annotations
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
MESSAGES_JS = (REPO_ROOT / "static" / "messages.js").read_text(encoding="utf-8")
def _chat_error_handler() -> str:
return MESSAGES_JS.split("source.addEventListener('error',async e=>{", 1)[1].split(
"source.addEventListener('cancel'", 1
)[0]
def test_visible_unfocused_current_session_still_attempts_sse_reconnect():
"""The immediate chat SSE error path should only require current-pane ownership.
`_isSessionActivelyViewed()` also gates on document focus/visibility. Hidden tabs
are already deferred by `_deferStreamErrorIfPageHidden(source)`, so the direct
reconnect branch must not skip a visible-but-unfocused current session.
"""
handler = _chat_error_handler()
assert "if(!_isSessionCurrentPane(activeSid)) return;" in handler
assert "if(!_isSessionActivelyViewed(activeSid)) return;" not in handler
assert handler.index("if(!_isSessionCurrentPane(activeSid)) return;") < handler.index(
"if(!_reconnectAttempted && streamId)"
)
def test_reconnect_gate_comment_matches_current_pane_contract():
handler = _chat_error_handler()
guard_idx = handler.index("if(!_isSessionCurrentPane(activeSid)) return;")
comment_window = handler[max(0, guard_idx - 260):guard_idx]
assert "different session" in comment_window
assert "visible" not in comment_window.lower()
assert "focused" not in comment_window.lower()