Even though #1360 is marked resolved and my app is up-to-date, I can still reproduce this on master.
Steps to reproduce
- Send a prompt that produces a long response (or kicks off many tool calls).
- While streaming, scroll up to re-read earlier content.
- Observe: the view snaps back to the bottom within ~100–500ms.
Browser: Chrome 147.0.7727.138
Diagnosis
After digging into static/ui.js:1170-1184, I think the 150 → 250px threshold bump in the previous fix papers over the symptom rather than addressing the root cause. Two issues:
- The
scroll listener can't tell programmatic scrolls from user scrolls. Every time scrollIfPinned() writes el.scrollTop = el.scrollHeight, the same listener fires, sees nearBottom = true, and re-pins — even if the user just scrolled up moments before.
- The 250px threshold is racy against streaming. A fast wheel flick clears it in one event, which is why the issue feels "almost fixed". But on a slow trackpad scroll the user only accumulates ~50px per event, and each streaming tick re-snaps to bottom before that delta can cross the threshold. Slow scroll within an active streaming message becomes effectively impossible.
Suggested approach
A position-threshold approach is fundamentally racy against streaming. A more robust fix would:
- Decouple programmatic scrolls from user-scroll detection (flag set before our
scrollTop writes, cleared on the next frame, listener ignores while set).
- Drive unpin from user intent, not position — listen for
wheel (deltaY < 0), touchmove (finger moves down = content moves up), and keydown (ArrowUp / PageUp / Home) on #messages. Any upward intent unpins immediately, regardless of distance to bottom.
- Re-pin only when the user actually reaches the bottom (small tolerance, e.g. <8px) — not when they're merely "near" it.
I tried this approach locally and slow scroll within an active stream now stays put. Happy to help test a fix.
Even though #1360 is marked resolved and my app is up-to-date, I can still reproduce this on master.
Steps to reproduce
Browser: Chrome 147.0.7727.138
Diagnosis
After digging into static/ui.js:1170-1184, I think the 150 → 250px threshold bump in the previous fix papers over the symptom rather than addressing the root cause. Two issues:
scrolllistener can't tell programmatic scrolls from user scrolls. Every timescrollIfPinned()writesel.scrollTop = el.scrollHeight, the same listener fires, seesnearBottom = true, and re-pins — even if the user just scrolled up moments before.Suggested approach
A position-threshold approach is fundamentally racy against streaming. A more robust fix would:
scrollTopwrites, cleared on the next frame, listener ignores while set).wheel(deltaY < 0),touchmove(finger moves down = content moves up), andkeydown(ArrowUp/PageUp/Home) on#messages. Any upward intent unpins immediately, regardless of distance to bottom.I tried this approach locally and slow scroll within an active stream now stays put. Happy to help test a fix.