From 54130e8d14aea06457ac953f93e10693b1e0be5e Mon Sep 17 00:00:00 2001 From: Haileyesus Date: Fri, 8 May 2026 16:03:14 +0300 Subject: [PATCH] fix(cursor-history): align pagination with visible rows Why: - Cursor normalization emits internal tool_result items so tool outputs can attach to tool cards. - The UI does not render tool_result as standalone rows. - Pagination previously mixed datasets: total excluded tool_result, but page slicing and hasMore used the unfiltered collection. - That mismatch caused offset and limit drift versus what users actually see. - Tool normalization also renamed ApplyPatch to Edit before input normalization. - That hid the original tool identity from normalizeCursorToolInput and could drop patch-specific shaping. What changed: - Added one pagination source of truth: renderableMessages filters out tool_result. - total, page slicing, and hasMore now all use renderableMessages. - Unlimited-history responses now return renderableMessages for consistent semantics. - normalizeCursorToolInput now receives rawToolName first. - The user-facing rename from ApplyPatch to Edit is still preserved in toolName. Impact: - Offset and limit now map to visible Cursor rows. - hasMore reflects remaining renderable history. - ApplyPatch payloads keep patch-aware normalization while preserving UI naming. --- .../list/cursor/cursor-sessions.provider.ts | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/server/modules/providers/list/cursor/cursor-sessions.provider.ts b/server/modules/providers/list/cursor/cursor-sessions.provider.ts index ca97fe05..90c9afa0 100644 --- a/server/modules/providers/list/cursor/cursor-sessions.provider.ts +++ b/server/modules/providers/list/cursor/cursor-sessions.provider.ts @@ -386,22 +386,17 @@ export class CursorSessionsProvider implements IProviderSessions { try { const blobs = await this.loadCursorBlobs(sessionId, projectPath); const allNormalized = this.normalizeCursorBlobs(blobs, sessionId); - const totalNormalized = allNormalized.length; - let total = 0; - for (const msg of allNormalized) { - if (msg.kind !== 'tool_result') { - total += 1; - } - } + const renderableMessages = allNormalized.filter((msg) => msg.kind !== 'tool_result'); + const total = renderableMessages.length; if (limit !== null) { const start = offset; const page = limit === 0 ? [] - : allNormalized.slice(start, start + limit); + : renderableMessages.slice(start, start + limit); const hasMore = limit === 0 - ? start < totalNormalized - : start + limit < totalNormalized; + ? start < total + : start + limit < total; return { messages: page, total, @@ -412,7 +407,7 @@ export class CursorSessionsProvider implements IProviderSessions { } return { - messages: allNormalized, + messages: renderableMessages, total, hasMore: false, offset: 0, @@ -560,6 +555,7 @@ export class CursorSessionsProvider implements IProviderSessions { || normalizeToolId(part.tool_call_id) || normalizeToolId(part.id) || `tool_${i}_${partIdx}`; + const normalizedToolInput = normalizeCursorToolInput(rawToolName, part.args ?? part.input); const message = createNormalizedMessage({ id: `${baseId}_${partIdx}`, sessionId, @@ -567,7 +563,7 @@ export class CursorSessionsProvider implements IProviderSessions { provider: PROVIDER, kind: 'tool_use', toolName, - toolInput: normalizeCursorToolInput(toolName, part.args ?? part.input), + toolInput: normalizedToolInput, toolId, }); messages.push(message);