fix(sessions): retry resumeStream in poll loop when chatModule loads late

sessions.js executes before chat.js in ES module order, so
window.chatModule is not yet set when _checkServerStream runs on page
load. The resumeStream guard evaluates false and the spinner fallback
kicks in; that fallback only polls stream_status and never retries the
live-resume path, leaving the user with a dead spinner for the entire
duration of the detached agent run.

Fix: add a one-shot retry in the polling loop. On the first tick where
window.chatModule.resumeStream is available, attempt to attach. If it
succeeds, clear the interval and remove the spinner — live SSE streaming
takes over. If the run has already finished (404), the loop continues to
poll status and calls selectSession on completion.

Fixes #3048

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Giuseppe
2026-06-06 11:36:30 +02:00
committed by GitHub
parent 870ae2823f
commit 893cb8254f
+14
View File
@@ -2184,6 +2184,10 @@ async function _checkServerStream(sessionId) {
box.appendChild(holder);
uiModule.scrollHistory();
// sessions.js executes before chat.js in module order, so window.chatModule
// may not be set yet when _checkServerStream first runs. Retry resumeStream
// on the first poll tick where it becomes available.
let _resumeRetried = false;
const pollId = setInterval(async () => {
if (getCurrentSessionId() !== sessionId) {
clearInterval(pollId);
@@ -2191,6 +2195,16 @@ async function _checkServerStream(sessionId) {
if (holder.parentNode) holder.remove();
return;
}
if (!_resumeRetried && window.chatModule && window.chatModule.resumeStream) {
_resumeRetried = true;
const attached = await window.chatModule.resumeStream(sessionId);
if (attached) {
clearInterval(pollId);
spinner.destroy();
if (holder.parentNode) holder.remove();
return;
}
}
try {
const r = await fetch(`${API_BASE}/api/chat/stream_status/${sessionId}`);
if (!r.ok || (await r.json()).status !== 'streaming') {