← Back to PRs

#19754: feat(webchat): add cursor-based pagination to chat.history

by aleiby open 2026-02-18 04:25 View on GitHub →
app: web-ui gateway size: S
## Summary Adds backward cursor-based pagination to `chat.history` so users can scroll back to the beginning of long conversations. **Discussion**: #19753 - **Server**: New optional `before` parameter returns messages preceding a given index. Response now includes `cursor` (index of first returned message) and `hasMore` (whether older messages exist). Fully backward-compatible. - **Client**: Detects when user scrolls near the top of the chat thread and automatically fetches the previous page, preserving scroll position. Shows a "Loading older messages..." indicator. Bounded by the existing 1000-message hard max. Does not add virtual scrolling (see PR #16020). Related: #19060, #13703, PR #19343 ## Test plan - [x] Extended existing e2e test (300 messages) to verify `before` cursor returns messages 0-99 after initial load returns 100-299 - [x] Verified `cursor` and `hasMore` fields in both default and paginated responses - [x] Session-switch safety: stale responses discarded if session changes mid-fetch - [x] TypeScript compiles cleanly (0 errors) - [x] All 439 gateway tests pass AI-assisted (Claude Code). Tested via TypeScript compilation and gateway unit/integration test suite. Full build + e2e require Node >= 22 (environment has Node 20). --- 🤖 [Tackled](https://github.com/aleiby/claude-skills/tree/main/tackle) with [Claude Code](https://claude.com/claude-code) <!-- greptile_comment --> <h3>Greptile Summary</h3> Adds backward cursor-based pagination to `chat.history`, allowing users to scroll back through long conversations. The server-side changes introduce `before`, `cursor`, and `hasMore` fields — well-structured and backward-compatible. The client detects when the user scrolls near the top and fetches older pages, preserving scroll position. Session-switch safety is handled via a session key check. - **Critical**: The client-side `CHAT_HISTORY_RENDER_LIMIT` (200) in `buildChatItems` (`ui/src/ui/views/chat.ts:485`) renders only the last 200 messages from the `chatMessages` array. Since `loadOlderChatHistory` *prepends* older messages, they are immediately excluded by this render cap — making the pagination UI-invisible. This needs to be addressed for the feature to work as intended. - **Minor**: The `onLoadOlderMessages` callback fires on every scroll event while near the top. After scroll-position restoration, this could trigger rapid successive fetches. A debounce or cooldown would be more robust. - Server-side cursor math, schema changes, and test coverage look correct. The e2e test properly validates the `before` cursor and `hasMore` semantics. <h3>Confidence Score: 2/5</h3> - The server-side pagination is correct, but the client-side rendering bug means older messages will never be visible to users. - The core client-side feature is broken: CHAT_HISTORY_RENDER_LIMIT in buildChatItems caps rendering to the last 200 messages, so prepended older messages from pagination are never displayed. The server-side changes are clean and well-tested, but the end-to-end feature does not work. - ui/src/ui/views/chat.ts (render limit conflicts with pagination), ui/src/ui/app-scroll.ts (debounce concern) <sub>Last reviewed commit: 5b5c695</sub> <!-- greptile_other_comments_section --> <sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub> <!-- /greptile_comment -->

Most Similar PRs