Fix session history loading (#1468)

Fix chat history pagination and scroll preservation

Align session history loading with the expected scroll-up pagination UX while
keeping OpenChamber-specific initial message limits for constrained runtimes.

- Separate initial load sizes from older-history pagination size
- Load older messages automatically when scrolling near the top
- Continue fetching history until a visible older turn is available
- Preserve the current viewport synchronously during prepends
- Prevent history loading from fighting pinned-to-bottom follow behavior
- Remove delayed scroll-to-bottom correction that caused jumpbacks
- Fix the virtualizer fallback path that could render a large blank spacer
- Track oldest loaded message per pagination iteration to avoid redundant fetches
This commit is contained in:
Bohdan Triapitsyn
2026-05-30 02:03:41 +03:00
committed by GitHub
parent 4a1ebd98da
commit f9e9f30873
4 changed files with 196 additions and 73 deletions
@@ -156,6 +156,7 @@ type ChatViewportProps = {
handleMessageContentChange: (reason?: ContentChangeReason) => void;
getAnimationHandlers: (messageId: string) => AnimationHandlers;
handleLoadOlder: () => void;
handleHistoryScroll: () => void;
scrollToBottom: () => void;
sessionQuestions: QuestionRequest[];
sessionPermissions: PermissionRequest[];
@@ -181,6 +182,7 @@ const ChatViewport = React.memo(({
handleMessageContentChange,
getAnimationHandlers,
handleLoadOlder,
handleHistoryScroll,
scrollToBottom,
sessionQuestions,
sessionPermissions,
@@ -217,6 +219,7 @@ const ChatViewport = React.memo(({
hideTopShadow={isMobile && stickyUserHeader}
tabIndex={0}
onClick={focusScrollContainer}
onScroll={handleHistoryScroll}
data-scroll-shadow="true"
data-scrollbar="chat"
>
@@ -280,6 +283,7 @@ const ChatViewport = React.memo(({
&& prev.handleMessageContentChange === next.handleMessageContentChange
&& prev.getAnimationHandlers === next.getAnimationHandlers
&& prev.handleLoadOlder === next.handleLoadOlder
&& prev.handleHistoryScroll === next.handleHistoryScroll
&& prev.scrollToBottom === next.scrollToBottom
&& prev.sessionQuestions === next.sessionQuestions
&& prev.sessionPermissions === next.sessionPermissions
@@ -655,7 +659,7 @@ export const ChatContainer: React.FC<ChatContainerProps> = ({ autoOpenDraft = tr
}, [handleMessageContentChange, sessionPermissions, sessionQuestions]);
const handleLoadOlder = React.useCallback(() => {
void loadEarlier();
void loadEarlier({ userInitiated: true });
}, [loadEarlier]);
const navigation = useChatTurnNavigation({
@@ -950,6 +954,7 @@ export const ChatContainer: React.FC<ChatContainerProps> = ({ autoOpenDraft = tr
handleMessageContentChange={handleMessageContentChange}
getAnimationHandlers={getAnimationHandlers}
handleLoadOlder={handleLoadOlder}
handleHistoryScroll={timelineController.handleHistoryScroll}
scrollToBottom={resumeToLatestInstant}
sessionQuestions={sessionQuestions}
sessionPermissions={sessionPermissions}