From 0210e85762d42e3f00a52ef56969a80fdf5fb6d5 Mon Sep 17 00:00:00 2001 From: Andre Padez Date: Mon, 10 Aug 2026 03:50:20 +0100 Subject: [PATCH] page older messages in when the folded ones don't fill the screen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regression from the fold change. Scroll-up paging is driven by a scroll listener, and a scroll listener only fires on a list that actually scrolls. That was always true and never mattered, because the turn you were looking at rendered in full and was tall enough on its own. Folding on reload broke it. A window of twenty messages can be one turn with eighteen tool calls, which collapses to three short rows: no overflow, no scroll event, and paging never starts. The whole transcript above becomes unreachable — which reads as lost history rather than as a fetch that never fired. So don't wait for a scroll that cannot happen: after each render, if there is more to load and the content does not overflow its viewport, load the next page. Terminates because each pass either fills the viewport or exhausts the transcript. This also fixes a latent case that predates folding — any first window short enough to fit on screen could never be paged past. Co-Authored-By: Claude Opus 5 --- .../Chat/EmbeddableChat/useEmbeddableChat.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts b/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts index 3e86d79a..504ff125 100644 --- a/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts +++ b/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts @@ -122,6 +122,28 @@ export function useEmbeddableChat(params: UseEmbeddableChatParams, onMessageComp if (textareaRef.current) textareaRef.current.style.height = 'auto'; }; + /** + * Page older messages in when the loaded ones do not fill the viewport. + * + * Scroll-up paging is driven by a scroll listener, and a scroll listener only fires on a list that + * actually scrolls. That was always true and never mattered, because the turn you were looking at + * rendered in full and was tall enough on its own. Folding on reload broke it: a window of twenty + * messages can be one turn with eighteen tool calls, which collapses to three short rows — no overflow, + * no scroll event, and paging simply never starts. The symptom is a transcript you cannot scroll back + * through at all, which reads as lost history rather than as a stalled fetch. + * + * Terminates: each pass either fills the viewport or exhausts the transcript, and `hasMoreOlder` goes + * false at the top. It runs after every prepend, so several small pages in a row are fine. + */ + useEffect(() => { + const viewport = scrollViewportRef.current; + if (!viewport || !didInitialScrollRef.current) return; + if (!hasMoreOlder || isLoadingOlder) return; + // A pixel of slack: a list exactly as tall as its viewport cannot be scrolled either. + if (viewport.scrollHeight > viewport.clientHeight + 1) return; + void loadOlder(); + }, [messages, hasMoreOlder, isLoadingOlder, loadOlder]); + /** * Hand a batch to the agent as ONE message. Returns whether it actually started a turn — a slash * command the client handled itself (`/clear`, `/model`) never reaches the agent, so the drain below