Skip to content

Commit bc2f641

Browse files
authored
improvement(knowledge): score the page on the original vectors, resolve a search's context once, and read identities off the walk (#8100)
* improvement(knowledge): score the vector page on the original vectors and pin the clock in the PDF chunk test * improvement(knowledge): score both pages on the original vectors and say so where the walk is scored * improvement(knowledge): resolve a search's context once and carry candidate identities off the walk * improvement(knowledge): one scoped search shape, page and pool cleanups, admission ahead of the embedding beside the scope reads * improvement(knowledge): embed only after every prerequisite holds, refuse a contradicting owner, count the shared fill read * improvement(knowledge): reset the projection-fill memo per integration iteration
1 parent d5061d5 commit bc2f641

15 files changed

Lines changed: 970 additions & 761 deletions

File tree

‎apps/sim/lib/billing/core/billing-attribution.ts‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -742,13 +742,16 @@ export async function resolveBillingAttribution({
742742

743743
/** The organization payer is independent of the person making the request. */
744744
export async function resolveOrganizationBillingPayer(organizationId: string) {
745-
const [owner] = await db
746-
.select({ userId: member.userId })
747-
.from(member)
748-
.where(and(eq(member.organizationId, organizationId), eq(member.role, 'owner')))
749-
.limit(1)
745+
/** The owner and the subscription are independent reads; neither waits on the other. */
746+
const [[owner], payerSubscription] = await Promise.all([
747+
db
748+
.select({ userId: member.userId })
749+
.from(member)
750+
.where(and(eq(member.organizationId, organizationId), eq(member.role, 'owner')))
751+
.limit(1),
752+
getOrganizationSubscription(organizationId, { onError: 'throw' }),
753+
])
750754
if (!owner) throw new Error('Organization billing owner is unavailable')
751-
const payerSubscription = await getOrganizationSubscription(organizationId, { onError: 'throw' })
752755
if (payerSubscription && payerSubscription.referenceId !== organizationId)
753756
throw new Error('Organization subscription belongs to a different payer')
754757
return { organizationId, billedAccountUserId: owner.userId, payerSubscription }

‎apps/sim/lib/knowledge/__integration__/kb-block-search.integration.ts‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
} from '@/lib/knowledge/__integration__/seed-source-access-fixture'
1212
import { createKnowledgeAccessProvider } from '@/lib/knowledge/access/scope'
1313
import {
14+
forgetProjectionFilled,
1415
resolvePermittedDocuments,
1516
retrieveKnowledgeSearch,
1617
VECTOR_PROBE_DOCUMENT_LIMIT,
@@ -92,6 +93,8 @@ describe('API-key KB block fan-out', () => {
9293
it.each([false, true])(
9394
'completes 18 concurrent KB searches with access checks intact (tag filter: %s)',
9495
async (withTags) => {
96+
/** The projection-fill memo outlives an iteration; each one must read it once, like a cold process. */
97+
forgetProjectionFilled()
9598
const previousDebug = db.$client.options.debug
9699
const statements: string[] = []
97100
db.$client.options.debug = (_connection, query) => {
@@ -132,18 +135,20 @@ describe('API-key KB block fan-out', () => {
132135
statements.filter((query) => query.includes(fragment))
133136
/**
134137
* Every statement runs under the leg's deadline: the candidate search applies it with the
135-
* scan settings in one statement, and the probe, the exact ranking, the rerank and
136-
* hydration each open with one of their own.
138+
* scan settings in one statement, and the probe, the exact ranking and hydration each
139+
* open with one of their own. The projection-fill read is shared by the searches that
140+
* miss its memo together, so it appears once.
137141
*/
138-
expect(matching('statement_timeout')).toHaveLength(bases.length * 5)
142+
expect(matching('statement_timeout')).toHaveLength(bases.length * 4 + 1)
139143
/**
140144
* A scope this small leaves the bounded traversal short of its candidate limit, so every
141145
* search probes once and rescues once — never a widening retry loop.
142146
*/
143147
expect(matching('hnsw.iterative_scan')).toHaveLength(bases.length)
144148
expect(matching('AS visible')).toHaveLength(bases.length)
145149
expect(matching(') + 0 LIMIT')).toHaveLength(bases.length)
146-
expect(matching('"embedding_search"."id" = ANY(')).toHaveLength(bases.length)
150+
/** The walk carries each candidate's identities, so a filled projection reads no page. */
151+
expect(matching('"embedding_search"."id" = ANY(')).toHaveLength(0)
147152
/** The probe enumerates visible documents and reports saturation; it never ranks them. */
148153
expect(
149154
statements.filter(

‎apps/sim/lib/knowledge/access/availability.ts‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ export async function resolveKnowledgeAccessAvailability(
6464
throw new Error('Knowledge access requires one resource owner')
6565
/** A caller that brings its own billing snapshot is answered from that snapshot, uncached. */
6666
if (context.ownerBilling) return readKnowledgeAccessAvailability(context)
67-
const key = `${context.organizationId ?? ''}|${context.workspaceId ?? ''}|${context.userId ?? ''}`
67+
/** An organization's answer depends on the organization alone; a workspace's on its viewer too. */
68+
const key = context.organizationId
69+
? `${context.organizationId}||`
70+
: `|${context.workspaceId ?? ''}|${context.userId ?? ''}`
6871
const availability = await availabilityCache.fetch(key, { context })
6972
if (!availability) throw new Error('Knowledge access availability could not be resolved')
7073
return availability
@@ -89,14 +92,14 @@ async function readKnowledgeAccessAvailability(
8992
return { sourceMirrored: false, memberScoped: false }
9093
}
9194
if (context.organizationId) {
92-
return {
93-
sourceMirrored:
94-
!isHosted || (await isOrganizationOnEnterprisePlan(context.organizationId, 'throw')),
95-
memberScoped: await isScopedCredentialGroupsAvailable({
95+
const [enterprise, memberScoped] = await Promise.all([
96+
isHosted ? isOrganizationOnEnterprisePlan(context.organizationId, 'throw') : true,
97+
isScopedCredentialGroupsAvailable({
9698
kind: 'organization',
9799
organizationId: context.organizationId,
98100
}),
99-
}
101+
])
102+
return { sourceMirrored: enterprise, memberScoped }
100103
}
101104
if (!context.workspaceId) throw new Error('Knowledge access requires a resource owner')
102105
const ownerBilling =

‎apps/sim/lib/knowledge/application/contexts.ts‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,12 @@ import {
1818
} from '@/lib/knowledge/connectors/service'
1919
import type { ActiveKnowledgeDocument } from '@/lib/knowledge/documents/service'
2020
import { getKnowledgeDocument, getKnowledgeDocumentById } from '@/lib/knowledge/documents/service'
21+
import type { ActiveKnowledgeBaseReference } from '@/lib/knowledge/knowledge-base-reference'
2122
import {
2223
getRestorableKnowledgeBase,
2324
type RestorableKnowledgeBase,
2425
} from '@/lib/knowledge/orchestration/restore'
25-
import {
26-
type ActiveKnowledgeBaseReference,
27-
getActiveKnowledgeBaseReference,
28-
getKnowledgeBaseById,
29-
} from '@/lib/knowledge/service'
26+
import { getActiveKnowledgeBaseReference, getKnowledgeBaseById } from '@/lib/knowledge/service'
3027
import { getTagDefinitionById } from '@/lib/knowledge/tags/service'
3128
import type { DocumentTagDefinition } from '@/lib/knowledge/tags/types'
3229
import type { KnowledgeBaseWithCounts } from '@/lib/knowledge/types'

0 commit comments

Comments
 (0)