Fix auto scroll to bottom during chat (#4923)
This commit is contained in:
@@ -117,50 +117,6 @@ function BaseChatContent({
|
||||
const [currentRecipeTitle, setCurrentRecipeTitle] = React.useState<string | null>(null);
|
||||
const { isCompacting, handleManualCompaction } = useContextManager();
|
||||
|
||||
// Timeout ref for debouncing auto-scroll
|
||||
const autoScrollTimeoutRef = useRef<number | null>(null);
|
||||
// Track if user was following when agent started responding
|
||||
const wasFollowingRef = useRef<boolean>(true);
|
||||
|
||||
const isNearBottom = React.useCallback(() => {
|
||||
if (!scrollRef.current) return false;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const viewport = scrollRef.current as any;
|
||||
if (!viewport.viewportRef?.current) return false;
|
||||
|
||||
const viewportElement = viewport.viewportRef.current;
|
||||
const { scrollHeight, scrollTop, clientHeight } = viewportElement;
|
||||
const scrollBottom = scrollTop + clientHeight;
|
||||
const distanceFromBottom = scrollHeight - scrollBottom;
|
||||
|
||||
return distanceFromBottom <= 100;
|
||||
}, []);
|
||||
|
||||
// Function to auto-scroll if user was following when agent started
|
||||
const conditionalAutoScroll = React.useCallback(() => {
|
||||
// Clear any existing timeout
|
||||
if (autoScrollTimeoutRef.current) {
|
||||
clearTimeout(autoScrollTimeoutRef.current);
|
||||
}
|
||||
|
||||
// Debounce the auto-scroll to prevent jumpy behavior and prevent multiple rapid scrolls
|
||||
autoScrollTimeoutRef.current = window.setTimeout(() => {
|
||||
// Only auto-scroll if user was following when the agent started responding
|
||||
if (wasFollowingRef.current && scrollRef.current) {
|
||||
scrollRef.current.scrollToBottom();
|
||||
}
|
||||
}, 150);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (autoScrollTimeoutRef.current) {
|
||||
clearTimeout(autoScrollTimeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Use shared chat engine
|
||||
const {
|
||||
messages,
|
||||
@@ -187,14 +143,10 @@ function BaseChatContent({
|
||||
chat,
|
||||
setChat,
|
||||
onMessageStreamFinish: () => {
|
||||
conditionalAutoScroll();
|
||||
|
||||
// Call the original callback if provided
|
||||
onMessageStreamFinish?.();
|
||||
},
|
||||
onMessageSent: () => {
|
||||
wasFollowingRef.current = isNearBottom();
|
||||
|
||||
// Mark that user has started using the recipe
|
||||
if (recipeConfig) {
|
||||
setHasStartedUsingRecipe(true);
|
||||
@@ -275,12 +227,23 @@ function BaseChatContent({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// Track if this is the initial render for session resuming
|
||||
const initialRenderRef = useRef(true);
|
||||
|
||||
// Auto-scroll when messages are loaded (for session resuming)
|
||||
const handleRenderingComplete = React.useCallback(() => {
|
||||
if (scrollRef.current?.scrollToBottom) {
|
||||
scrollRef.current.scrollToBottom();
|
||||
// Only force scroll on the very first render
|
||||
if (initialRenderRef.current && messages.length > 0) {
|
||||
initialRenderRef.current = false;
|
||||
if (scrollRef.current?.scrollToBottom) {
|
||||
scrollRef.current.scrollToBottom();
|
||||
}
|
||||
} else if (scrollRef.current?.isFollowing) {
|
||||
if (scrollRef.current?.scrollToBottom) {
|
||||
scrollRef.current.scrollToBottom();
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
}, [messages.length]);
|
||||
|
||||
// Handle submit
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
@@ -441,7 +404,12 @@ function BaseChatContent({
|
||||
onClick={async () => {
|
||||
clearError();
|
||||
|
||||
await handleManualCompaction(messages, setMessages, append, chat.sessionId);
|
||||
await handleManualCompaction(
|
||||
messages,
|
||||
setMessages,
|
||||
append,
|
||||
chat.sessionId
|
||||
);
|
||||
}}
|
||||
>
|
||||
Summarize Conversation
|
||||
|
||||
Reference in New Issue
Block a user