@@ -90,16 +90,27 @@ export function ConversationView({
9090 const { saveScrollPosition, getScrollPosition } = useSessionViewActions ( ) ;
9191
9292 const [ showScrollButton , setShowScrollButton ] = useState ( false ) ;
93+ const showScrollButtonRef = useRef ( false ) ;
9394 const hasRestoredScrollRef = useRef ( false ) ;
9495 const prevItemCountRef = useRef ( 0 ) ;
96+ const prevPendingCountRef = useRef ( 0 ) ;
97+ const prevEventsLengthRef = useRef ( events . length ) ;
9598
9699 const queuedItems = useMemo < QueuedItem [ ] > (
97- ( ) => queuedMessages . map ( ( msg ) => ( { type : "queued" as const , id : msg . id , message : msg } ) ) ,
100+ ( ) =>
101+ queuedMessages . map ( ( msg ) => ( {
102+ type : "queued" as const ,
103+ id : msg . id ,
104+ message : msg ,
105+ } ) ) ,
98106 [ queuedMessages ] ,
99107 ) ;
100108
101109 const virtualizedItems = useMemo < VirtualizedItem [ ] > (
102- ( ) => ( queuedItems . length > 0 ? [ ...conversationItems , ...queuedItems ] : conversationItems ) ,
110+ ( ) =>
111+ queuedItems . length > 0
112+ ? [ ...conversationItems , ...queuedItems ]
113+ : conversationItems ,
103114 [ conversationItems , queuedItems ] ,
104115 ) ;
105116
@@ -108,35 +119,37 @@ export function ConversationView({
108119
109120 const savedPosition = getScrollPosition ( taskId ) ;
110121 if ( savedPosition > 0 ) {
111- const virtualizer = listRef . current ?. getVirtualizer ( ) ;
112- if ( virtualizer ) {
113- virtualizer . scrollOffset = savedPosition ;
114- hasRestoredScrollRef . current = true ;
115- }
122+ listRef . current ?. scrollToOffset ( savedPosition ) ;
123+ hasRestoredScrollRef . current = true ;
116124 }
117125 } , [ taskId , getScrollPosition ] ) ;
118126
119- const isStreaming = lastTurn && ! lastTurn . isComplete ;
120-
121127 useEffect ( ( ) => {
122128 const isNewContent = virtualizedItems . length > prevItemCountRef . current ;
129+ const isNewPending = pendingPermissionsCount > prevPendingCountRef . current ;
130+ const isNewEvents = events . length > prevEventsLengthRef . current ;
123131 prevItemCountRef . current = virtualizedItems . length ;
132+ prevPendingCountRef . current = pendingPermissionsCount ;
133+ prevEventsLengthRef . current = events . length ;
124134
125- if ( isNewContent && ! showScrollButton ) {
135+ // Always force-scroll for new items or new permissions (needs attention)
136+ if ( isNewContent || isNewPending ) {
126137 listRef . current ?. scrollToBottom ( ) ;
138+ return ;
127139 }
128- } , [ virtualizedItems . length , showScrollButton ] ) ;
129140
130- useEffect ( ( ) => {
131- if ( isStreaming && ! showScrollButton ) {
141+ // For streaming content growth, only scroll if user hasn't scrolled up
142+ if ( isNewEvents && ! showScrollButtonRef . current ) {
132143 listRef . current ?. scrollToBottom ( ) ;
133144 }
134- } , [ isStreaming , showScrollButton ] ) ;
145+ } , [ events . length , virtualizedItems . length , pendingPermissionsCount ] ) ;
135146
136147 const handleScroll = useCallback (
137148 ( scrollOffset : number , scrollHeight : number , clientHeight : number ) => {
138149 const distanceFromBottom = scrollHeight - scrollOffset - clientHeight ;
139- setShowScrollButton ( distanceFromBottom > SHOW_BUTTON_THRESHOLD ) ;
150+ const isScrolledUp = distanceFromBottom > SHOW_BUTTON_THRESHOLD ;
151+ showScrollButtonRef . current = isScrolledUp ;
152+ setShowScrollButton ( isScrolledUp ) ;
140153
141154 if ( taskId ) {
142155 saveScrollPosition ( taskId , scrollOffset ) ;
0 commit comments