diff --git a/apps/desktop/src/components/assistant-ui/streaming.test.tsx b/apps/desktop/src/components/assistant-ui/streaming.test.tsx index 70f66040e..51edee952 100644 --- a/apps/desktop/src/components/assistant-ui/streaming.test.tsx +++ b/apps/desktop/src/components/assistant-ui/streaming.test.tsx @@ -415,6 +415,40 @@ describe('assistant-ui streaming renderer', () => { expect(viewport.scrollTop).toBe(420) }) + it('honors the first upward wheel scroll even when a programmatic bottom-pin scroll event is still pending', async () => { + const { container } = render() + + const content = container.querySelector('[data-slot="aui_thread-content"]') as HTMLDivElement + const viewport = content.parentElement as HTMLDivElement + let scrollHeight = 1_000 + + Object.defineProperty(viewport, 'clientHeight', { configurable: true, value: 200 }) + Object.defineProperty(viewport, 'scrollHeight', { + configurable: true, + get: () => scrollHeight + }) + + await wait(80) + await wait(0) + + await act(async () => { + fireEvent.wheel(viewport, { deltaY: -120 }) + viewport.scrollTop = 420 + fireEvent.scroll(viewport) + }) + + scrollHeight = 1_200 + + await act(async () => { + for (const observer of resizeObservers) { + observer.trigger(1_200) + } + }) + await wait(0) + + expect(viewport.scrollTop).toBe(420) + }) + it('renders reasoning text without a leading token space', () => { const { container } = render() diff --git a/apps/desktop/src/components/assistant-ui/thread-virtualizer.tsx b/apps/desktop/src/components/assistant-ui/thread-virtualizer.tsx index 3ee02e755..784ed71f3 100644 --- a/apps/desktop/src/components/assistant-ui/thread-virtualizer.tsx +++ b/apps/desktop/src/components/assistant-ui/thread-virtualizer.tsx @@ -237,6 +237,7 @@ function useThreadScrollAnchor({ enabled, groupCount, scrollerRef, sessionKey, v const disarm = () => { armedRef.current = false + programmaticScrollPendingRef.current = 0 } const onScroll = () => {