diff --git a/static/messages.js b/static/messages.js index 9f1532f1..75a3ddbe 100644 --- a/static/messages.js +++ b/static/messages.js @@ -5941,10 +5941,17 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){ // render also populates the cache with the correctly-collapsed DOM, and // the same-frame JS restore absorbs the collapse so there is no jump. // (#5260 gate-cert: keep-open must be transient + uncached for everyone.) + // #6385: capture the scroll snapshot from the LIVE DOM before arming + // keep-open, so the collapse render below anchors to the content the + // reader was actually viewing — not to a stale intermediate state where + // the worklog was temporarily expanded. + const _doneLiveScrollSnapshot=typeof _captureMessageScrollSnapshot==='function' + ? _captureMessageScrollSnapshot() + : null; if(typeof _armKeepSettledWorklogOpen==='function') _armKeepSettledWorklogOpen(_settledStreamId); syncTopbar();renderMessages({preserveScroll:true}); if(typeof _disarmKeepSettledWorklogOpen==='function') _disarmKeepSettledWorklogOpen(); - if(typeof _renderMessagesWithScrollSnapshot==='function') _renderMessagesWithScrollSnapshot(); + if(typeof _renderMessagesWithScrollSnapshot==='function') _renderMessagesWithScrollSnapshot({_prescrollSnapshot:_doneLiveScrollSnapshot}); else renderMessages({preserveScroll:true}); if(shouldFollowOnDone&&typeof scrollToBottom==='function') scrollToBottom(); if(typeof noteWorkspaceMutationsFromToolCalls==='function') noteWorkspaceMutationsFromToolCalls(S.toolCalls); diff --git a/static/ui.js b/static/ui.js index 3e92cd34..a156eb3a 100644 --- a/static/ui.js +++ b/static/ui.js @@ -15086,7 +15086,13 @@ function _restoreMessageScrollSnapshotSameFrame(snapshot){ } } function _renderMessagesWithScrollSnapshot(options){ - const scrollSnapshot=_captureMessageScrollSnapshot(); + // Accept an optional pre-captured scroll snapshot via _prescrollSnapshot. + // When provided, it is used INSTEAD of capturing a fresh one from the current + // DOM state — essential for the STREAM_DONE collapse render: the caller has + // already captured the snapshot from the LIVE DOM (before keep-open was armed), + // and re-capturing from the intermediate expanded-worklog state would capture + // stale anchors that no longer exist after the worklog collapses. (#6385) + const scrollSnapshot=(options&&options._prescrollSnapshot)||_captureMessageScrollSnapshot(); renderMessages({...(options||{}),preserveScroll:true}); _restoreMessageScrollSnapshotSameFrame(scrollSnapshot); }