From 8b41371c836c08fa375f92075adf6f28bd60e797 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Sun, 27 Sep 2026 20:16:34 -0700 Subject: [PATCH 1/2] fix(knowledge): serve list totals when a request omits the count flag --- .../components/user-input/hooks/use-mention-data.ts | 2 +- apps/sim/lib/api/contracts/knowledge/base.ts | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-mention-data.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-mention-data.ts index 2736c964f75..77c6765d44c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-mention-data.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-mention-data.ts @@ -250,7 +250,7 @@ export function useMentionData(props: UseMentionDataProps): MentionDataReturn { try { setIsLoadingKnowledge(true) const result = await requestJson(listKnowledgeBasesContract, { - query: { workspaceId }, + query: { workspaceId, includeCounts: false }, }) const items = result.data const sorted = [...items].sort((a, b) => { diff --git a/apps/sim/lib/api/contracts/knowledge/base.ts b/apps/sim/lib/api/contracts/knowledge/base.ts index 732d7276539..719d1bb0b4e 100644 --- a/apps/sim/lib/api/contracts/knowledge/base.ts +++ b/apps/sim/lib/api/contracts/knowledge/base.ts @@ -26,8 +26,12 @@ export type KnowledgeScope = z.output export const listKnowledgeBasesQuerySchema = z.object({ workspaceId: z.string().min(1).optional(), scope: knowledgeScopeSchema.default('active'), - /** Adds `docCount` and `tokenCount` for the documents the caller can see; costs a document scan. */ - includeCounts: booleanQueryFlagSchema.optional().default(false), + /** + * Adds `docCount` and `tokenCount` for the documents the caller can see; costs a document scan. + * Absent means counted: a page loaded before this flag existed requires both totals on every + * row, and current clients always send it. + */ + includeCounts: booleanQueryFlagSchema.optional().default(true), }) /** From fe9ab3a86e6dcad98fd2648faf3bc48baa90070f Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Sun, 27 Sep 2026 20:25:40 -0700 Subject: [PATCH 2/2] test(knowledge): cover the internal list request a pre-flag page sends --- .../app/api/v1/knowledge/route.integration.ts | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/apps/sim/app/api/v1/knowledge/route.integration.ts b/apps/sim/app/api/v1/knowledge/route.integration.ts index 4e8b63ce120..ab75f05a29d 100644 --- a/apps/sim/app/api/v1/knowledge/route.integration.ts +++ b/apps/sim/app/api/v1/knowledge/route.integration.ts @@ -1,18 +1,21 @@ /** * Knowledge-base document totals against real PostgreSQL: the public v1 list and detail count * only the documents their caller can read, and the internal list reads no document at all - * unless the caller asks for totals. + * unless the caller asks for totals. A request without the flag is counted, since a page loaded + * before the flag existed requires both totals on every row. */ import type { Principal } from '@sim/auth/principal' import { db } from '@sim/db' import { document, organization, user, workspace } from '@sim/db/schema' -import { createMockRequest } from '@sim/testing' +import { authMock, authMockFns, createMockRequest } from '@sim/testing' import { generateId } from '@sim/utils/id' import { eq, inArray } from 'drizzle-orm' import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest' const caller = vi.hoisted(() => ({ userId: '' })) +vi.mock('@/lib/auth', () => authMock) + vi.mock('@/app/api/v1/middleware', async (importOriginal) => ({ ...(await importOriginal()), authenticateRequest: async () => ({ @@ -34,6 +37,7 @@ import { seedKnowledgeAclFixture, } from '@/lib/knowledge/__integration__/seed-source-access-fixture' import { listInternalKnowledgeBases } from '@/lib/knowledge/application/knowledge-bases' +import { GET as listInternalKnowledgeBasesRoute } from '@/app/api/knowledge/route' import { GET as getKnowledgeBase } from '@/app/api/v1/knowledge/[id]/route' import { GET as listKnowledgeBases } from '@/app/api/v1/knowledge/route' @@ -46,6 +50,10 @@ describe('knowledge-base document totals in PostgreSQL', () => { throw new Error('Unexpected provider request in knowledge-base count tests') }) caller.userId = ids.bobId + authMockFns.mockGetSession.mockResolvedValue({ + user: { id: ids.bobId }, + session: { id: 'fixture-reader' }, + }) await seedKnowledgeAclFixture(ids, { connectorType: 'google_drive' }) await db.insert(document).values([ { @@ -134,4 +142,21 @@ describe('knowledge-base document totals in PostgreSQL', () => { ).knowledgeBases expect(counted).toMatchObject({ docCount: 1, tokenCount: 10 }) }) + + it('counts an internal list request that omits the flag', async () => { + const list = async (query: string) => { + const response = await listInternalKnowledgeBasesRoute( + createMockRequest('GET', undefined, {}, `http://localhost/api/knowledge?${query}`), + { params: Promise.resolve({}) } + ) + expect(response.status).toBe(200) + return (await response.json()).data + } + const workspaceQuery = `workspaceId=${ids.workspaceId}&scope=active` + expect(await list(workspaceQuery)).toEqual([ + expect.objectContaining({ id: ids.knowledgeBaseId, docCount: 1, tokenCount: 10 }), + ]) + const [uncounted] = await list(`${workspaceQuery}&includeCounts=false`) + expect(uncounted).not.toHaveProperty('tokenCount') + }) })