fix: live-resume chat stream on session re-entry (#2539) (#2561)

* fix: live-resume chat stream on session re-entry (#2539)

When a session was re-entered after a page refresh or in a new tab while
its agent run was still streaming, the UI showed a frozen "Generating
response..." spinner, polled stream_status until the run finished, and
then did a full reload. The live tokens were never shown.

Add resumeStream() in chat.js: it consumes GET /api/chat/resume/{id}
(which replays the run's buffer then streams live), renders reply tokens
as they arrive, and reloads the session on completion for the canonical
final render. sessions.js _checkServerStream now calls it on re-entry and
falls back to the previous spinner+poll path if it is unavailable.

* Finalize plain-text resume in place instead of reloading

On stream completion, resumeStream() called selectSession(), forcing a full
history re-fetch and a visible flicker right as the stream finished.

For plain text replies (no tool calls, sources, doc streaming, or multi-round
output) the live tokens are already rendered, so finalize in place: replace the
live bubble with a canonical single message via chatRenderer.addMessage (markdown
+ footer actions + metrics, the same renderer history uses), captured from the
streamed metrics event. No history refetch, no extra round-trip, no flicker.

Rich responses still reload, since their canonical render (tool bubbles, sources,
multi-bubble) is rebuilt from the saved DB record.

* Use a dedicated set for the resume re-attach lock; fix stale docblock

resumeStream() marked its re-attach lock in _backgroundStreams, which
checkBackgroundStream() also reads. On a second re-entry of the same session
while a resume was still live, checkBackgroundStream() mistook that entry for a
same-tab POST stream and spawned its own spinner+poll bubble. Move the lock to a
dedicated _resumingStreams set (also covered by hasActiveStream) so the two paths
no longer collide. Also update the resumeStream docblock to describe the
in-place finalize vs reload split.
This commit is contained in:
Kenny Van de Maele
2026-06-04 17:56:15 +02:00
committed by GitHub
parent c916224510
commit 66fba78011
2 changed files with 158 additions and 2 deletions
+8 -1
View File
@@ -2157,7 +2157,14 @@ async function _checkServerStream(sessionId) {
// Skip if this is a research stream — research has its own progress UI
if (info.mode === 'research' || info.is_research) return;
// Server is still streaming — show spinner and poll
// Live-resume the detached run: replay its buffer then stream live tokens
// (#2539). Falls back to the spinner+poll path below if unavailable.
if (window.chatModule && window.chatModule.resumeStream) {
const attached = await window.chatModule.resumeStream(sessionId);
if (attached) return;
}
// Fallback: server is still streaming, show spinner and poll.
const box = document.getElementById('chat-history');
if (!box) return;