diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index 9b8c96dea1d..a0b08b265e0 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -465,26 +465,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction { - const prev = prevExpandedRowsRef.current - let wasAnyRowExpandedByUser = false - if (prev) { - // Check if any row transitioned from false/undefined to true - for (const [tsKey, isExpanded] of Object.entries(expandedRows)) { - const ts = Number(tsKey) - if (isExpanded && !(prev[ts] ?? false)) { - wasAnyRowExpandedByUser = true - break - } - } - } - - if (wasAnyRowExpandedByUser) { - disableAutoScrollRef.current = true - } - prevExpandedRowsRef.current = expandedRows // Store current state for next comparison - }, [expandedRows]) - const isStreaming = useMemo(() => { // Checking clineAsk isn't enough since messages effect may be called // again for a tool for example, set clineAsk to its value, and if the @@ -529,6 +509,27 @@ const ChatViewComponent: React.ForwardRefRenderFunction { + const prev = prevExpandedRowsRef.current + let wasAnyRowExpandedByUser = false + if (prev) { + // Check if any row transitioned from false/undefined to true + for (const [tsKey, isExpanded] of Object.entries(expandedRows)) { + const ts = Number(tsKey) + if (isExpanded && !(prev[ts] ?? false)) { + wasAnyRowExpandedByUser = true + break + } + } + } + + // Don't disable auto-scroll during streaming even if rows are expanded + if (wasAnyRowExpandedByUser && !isStreaming) { + disableAutoScrollRef.current = true + } + prevExpandedRowsRef.current = expandedRows // Store current state for next comparison + }, [expandedRows, isStreaming]) + const markFollowUpAsAnswered = useCallback(() => { const lastFollowUpMessage = messagesRef.current.findLast((msg: ClineMessage) => msg.ask === "followup") if (lastFollowUpMessage) { @@ -1390,7 +1391,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction { let timer: ReturnType | undefined - if (!disableAutoScrollRef.current) { + // Always scroll to bottom during streaming unless user explicitly scrolled up + if (!disableAutoScrollRef.current || isStreaming) { timer = setTimeout(() => scrollToBottomSmooth(), 50) } return () => { @@ -1398,18 +1400,23 @@ const ChatViewComponent: React.ForwardRefRenderFunction { - const wheelEvent = event as WheelEvent + const handleWheel = useCallback( + (event: Event) => { + const wheelEvent = event as WheelEvent - if (wheelEvent.deltaY && wheelEvent.deltaY < 0) { - if (scrollContainerRef.current?.contains(wheelEvent.target as Node)) { - // User scrolled up - disableAutoScrollRef.current = true + if (wheelEvent.deltaY && wheelEvent.deltaY < 0) { + if (scrollContainerRef.current?.contains(wheelEvent.target as Node)) { + // User scrolled up - but don't disable during streaming if we're near bottom + if (!isStreaming || !isAtBottom) { + disableAutoScrollRef.current = true + } + } } - } - }, []) + }, + [isStreaming, isAtBottom], + ) useEvent("wheel", handleWheel, window, { passive: true }) // passive improves scrolling performance @@ -1878,6 +1885,10 @@ const ChatViewComponent: React.ForwardRefRenderFunction