@@ -187,7 +187,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
187187 const [ expandedRows , setExpandedRows ] = useState < Record < number , boolean > > ( { } )
188188 const prevExpandedRowsRef = useRef < Record < number , boolean > > ( )
189189 const scrollContainerRef = useRef < HTMLDivElement > ( null )
190- const disableAutoScrollRef = useRef ( false )
190+ const stickyFollowRef = useRef < boolean > ( false )
191191 const [ showScrollToBottom , setShowScrollToBottom ] = useState ( false )
192192 const [ isAtBottom , setIsAtBottom ] = useState ( false )
193193 const lastTtsRef = useRef < string > ( "" )
@@ -508,9 +508,11 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
508508 }
509509 }
510510
511+ // Expanding a row indicates the user is browsing; disable sticky follow
511512 if ( wasAnyRowExpandedByUser ) {
512- disableAutoScrollRef . current = true
513+ stickyFollowRef . current = false
513514 }
515+
514516 prevExpandedRowsRef . current = expandedRows // Store current state for next comparison
515517 } , [ expandedRows ] )
516518
@@ -583,7 +585,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
583585 // Do not reset mode here as it should persist.
584586 // setPrimaryButtonText(undefined)
585587 // setSecondaryButtonText(undefined)
586- disableAutoScrollRef . current = false
587588 } , [ ] )
588589
589590 /**
@@ -1385,41 +1386,25 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13851386
13861387 const handleRowHeightChange = useCallback (
13871388 ( isTaller : boolean ) => {
1388- if ( ! disableAutoScrollRef . current ) {
1389+ if ( isAtBottom ) {
13891390 if ( isTaller ) {
13901391 scrollToBottomSmooth ( )
13911392 } else {
13921393 setTimeout ( ( ) => scrollToBottomAuto ( ) , 0 )
13931394 }
13941395 }
13951396 } ,
1396- [ scrollToBottomSmooth , scrollToBottomAuto ] ,
1397+ [ scrollToBottomSmooth , scrollToBottomAuto , isAtBottom ] ,
13971398 )
13981399
1399- useEffect ( ( ) => {
1400- let timer : ReturnType < typeof setTimeout > | undefined
1401- if ( ! disableAutoScrollRef . current ) {
1402- timer = setTimeout ( ( ) => scrollToBottomSmooth ( ) , 50 )
1403- }
1404- return ( ) => {
1405- if ( timer ) {
1406- clearTimeout ( timer )
1407- }
1408- }
1409- } , [ groupedMessages . length , scrollToBottomSmooth ] )
1410-
1400+ // Disable sticky follow when user scrolls up inside the chat container
14111401 const handleWheel = useCallback ( ( event : Event ) => {
14121402 const wheelEvent = event as WheelEvent
1413-
1414- if ( wheelEvent . deltaY && wheelEvent . deltaY < 0 ) {
1415- if ( scrollContainerRef . current ?. contains ( wheelEvent . target as Node ) ) {
1416- // User scrolled up
1417- disableAutoScrollRef . current = true
1418- }
1403+ if ( wheelEvent . deltaY < 0 && scrollContainerRef . current ?. contains ( wheelEvent . target as Node ) ) {
1404+ stickyFollowRef . current = false
14191405 }
14201406 } , [ ] )
1421-
1422- useEvent ( "wheel" , handleWheel , window , { passive : true } ) // passive improves scrolling performance
1407+ useEvent ( "wheel" , handleWheel , window , { passive : true } )
14231408
14241409 // Effect to clear checkpoint warning when messages appear or task changes
14251410 useEffect ( ( ) => {
@@ -1867,12 +1852,15 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
18671852 increaseViewportBy = { { top : 3_000 , bottom : 1000 } }
18681853 data = { groupedMessages }
18691854 itemContent = { itemContent }
1855+ followOutput = "smooth"
18701856 atBottomStateChange = { ( isAtBottom : boolean ) => {
18711857 setIsAtBottom ( isAtBottom )
1872- if ( isAtBottom ) {
1873- disableAutoScrollRef . current = false
1858+ if ( ! isAtBottom && stickyFollowRef . current ) {
1859+ // While in sticky mode, force-pin as streaming increases height
1860+ scrollToBottomAuto ( )
1861+ return
18741862 }
1875- setShowScrollToBottom ( disableAutoScrollRef . current && ! isAtBottom )
1863+ setShowScrollToBottom ( ! isAtBottom )
18761864 } }
18771865 atBottomThreshold = { 10 }
18781866 initialTopMostItemIndex = { groupedMessages . length - 1 }
@@ -1893,8 +1881,10 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
18931881 appearance = "secondary"
18941882 className = "flex-[2]"
18951883 onClick = { ( ) => {
1896- scrollToBottomSmooth ( )
1897- disableAutoScrollRef . current = false
1884+ // Engage sticky follow until user scrolls up
1885+ stickyFollowRef . current = true
1886+ // Pin immediately to avoid lag during fast streaming
1887+ scrollToBottomAuto ( )
18981888 } } >
18991889 < span className = "codicon codicon-chevron-down" > </ span >
19001890 </ VSCodeButton >
0 commit comments