From 5554e4e85ea2185ef60caeccd03796798b138c48 Mon Sep 17 00:00:00 2001 From: Haileyesus Date: Fri, 8 May 2026 15:35:45 +0300 Subject: [PATCH] fix(cursor-chat): count totals as rendered rows, not normalized transport rows Cursor sessions were still showing inflated totals after the earlier total-count work, producing UX mismatches like "Showing 16 of 31" while only ~16 visible chat rows existed. Why this happened: - Cursor history normalization emits both `tool_use` and `tool_result` entries. - The UI intentionally does not render `tool_result` as its own message bubble; it attaches tool results onto the related `tool_use` card. - Total counting that includes `tool_result` therefore measures transport artifacts, not user-visible conversation rows. - In practice, this makes totals look wrong and undermines trust in pagination status and session message counts. Why this change: - `total` is a user-facing semantic value and must represent what the user can actually see in the timeline. - Cursor should follow the same rendered-message counting rule as other providers to keep behavior predictable across providers. - Avoiding hidden/internal row counts in totals prevents confusion in "showing X of Y" indicators and load-more expectations. What was changed: - Replaced implicit/raw-style counting with explicit provider-side total tracking in Cursor history fetch. - Total tracker increments only for processed messages that map to rendered chat rows, excluding standalone `tool_result` entries. - Pagination windowing remains based on full normalized history payload to avoid changing ordering/loading mechanics; only displayed `total` semantics were corrected. Result: - Cursor `total` now reflects rendered chat rows rather than internal normalized event count. - Session counters are now aligned with what users perceive in the UI. --- src/components/chat/hooks/useChatSessionState.ts | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/components/chat/hooks/useChatSessionState.ts b/src/components/chat/hooks/useChatSessionState.ts index babc436d..62f3a2f4 100644 --- a/src/components/chat/hooks/useChatSessionState.ts +++ b/src/components/chat/hooks/useChatSessionState.ts @@ -182,6 +182,7 @@ export function useChatSessionState({ messagesOffsetRef.current = 0; setHasMoreMessages(false); setTotalMessages(0); + setTokenBudget(null); setVisibleMessageCount(INITIAL_VISIBLE_MESSAGES); setAllMessagesLoaded(false); @@ -318,7 +319,6 @@ export function useChatSessionState({ if (!hasMoreMessages || !selectedSession || !selectedProject) return false; const sessionProvider = selectedSession.__provider || 'claude'; - if (sessionProvider === 'cursor') return false; isLoadingMoreRef.current = true; const previousScrollHeight = container.scrollHeight; @@ -551,7 +551,6 @@ export function useChatSessionState({ const scrollToTarget = async () => { if (!allMessagesLoadedRef.current && selectedSession && selectedProject) { const sessionProvider = selectedSession.__provider || 'claude'; - if (sessionProvider !== 'cursor') { try { // Load all messages into the store for search navigation const slot = await sessionStore.fetchFromServer(selectedSession.id, { @@ -573,7 +572,6 @@ export function useChatSessionState({ } catch { // Fall through and scroll in current messages } - } } setVisibleMessageCount(Infinity); @@ -722,15 +720,6 @@ export function useChatSessionState({ if (!selectedSession || !selectedProject) return; if (isLoadingAllMessages) return; const sessionProvider = selectedSession.__provider || 'claude'; - if (sessionProvider === 'cursor') { - setVisibleMessageCount(Infinity); - setAllMessagesLoaded(true); - allMessagesLoadedRef.current = true; - setLoadAllJustFinished(true); - if (loadAllFinishedTimerRef.current) clearTimeout(loadAllFinishedTimerRef.current); - loadAllFinishedTimerRef.current = setTimeout(() => { setLoadAllJustFinished(false); setShowLoadAllOverlay(false); }, 1000); - return; - } const requestSessionId = selectedSession.id; allMessagesLoadedRef.current = true;