fix(streaming): scope streaming message rendering per-session to prevent cross-session render leak (#6449) (#6502)
When the user switches from a streaming session (A) to another session (B), A's streaming text could render in B's window because: 1. The token handler guards against rendering when the session is not active, but the rAF/setTimeout window between _scheduleRender() and _doRender() can outlive a session switch. 2. _doRender() writes to assistantBody without checking whether the stream's session is still the active frontend pane. Fix: add _isActiveSession() guards to: - _scheduleRender() — drop scheduled renders when the session changed - _doRender() — bail before any DOM write if the session switched - _flushPendingSegmentRender() — defense-in-depth for any future callers These guard at the same level the token/interim_assistant event handlers already do, closing the rAF gap that could leak streamed text into a different session's view. Co-authored-by: webtecnica <contato@webtecnica.com.br> Co-authored-by: nesquena-hermes <nesquena+hermes@gmail.com>
This commit is contained in:
1 file changed
+12
@@ -5226,6 +5226,10 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){
|
||||
const force=!!(options&&options.force);
|
||||
const skipAnchorProcessProse=!!(options&&options.skipAnchorProcessProse);
|
||||
if(!assistantBody||(!force&&!_renderPending)) return;
|
||||
// #6449: guard — this stream's session is no longer the active pane.
|
||||
// Callers already gate on _isActiveSession(), but add the guard here too
|
||||
// so any future call-site cannot leak rendering into the wrong session.
|
||||
if(!_isActiveSession()) return;
|
||||
if(_renderPending) _cancelAnimationFramePendingStreamRender();
|
||||
const displayText=segmentStart===0
|
||||
? _parseStreamState().displayText
|
||||
@@ -5551,6 +5555,11 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){
|
||||
}
|
||||
if(_renderPending) return;
|
||||
if(_streamFinalized) return; // Bug A: don't schedule new rAF after stream finalized
|
||||
// #6449: guard — this stream's session is no longer the active frontend pane.
|
||||
// Drop the scheduled render instead of writing into a detached or wrong-session DOM.
|
||||
// Callers (token/interim_assistant handlers) already gate on _isActiveSession(), but
|
||||
// the rAF/setTimeout window between schedule and execution can outlive a session switch.
|
||||
if(!_isActiveSession()) return;
|
||||
_renderPending=true;
|
||||
// Cap render rate to ~15fps. The browser's rAF fires at 60fps, but each DOM
|
||||
// update takes 50-150ms on large sessions. During GC pauses, rAF callbacks
|
||||
@@ -5566,6 +5575,9 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){
|
||||
_renderPending=false;
|
||||
// Guard: a pending setTimeout+rAF can outlive stream finalization.
|
||||
if(_streamFinalized) return;
|
||||
// #6449: guard — the frontend session changed between rAF schedule and execution.
|
||||
// Writing DOM into this stream's assistantBody would leak text into the wrong pane.
|
||||
if(!_isActiveSession()) return;
|
||||
// Mobile scroll-jank guard: temporarily disable overflow-anchor before DOM
|
||||
// writes to suppress Chromium scroll re-anchoring during streaming growth.
|
||||
if(typeof window._fixMobileScrollJank==='function') window._fixMobileScrollJank();
|
||||
|
||||
Reference in new issue
Block a user