Skip to content

Commit b94627a

Browse files
committed
Improve organization search ranking and bound rerank admission
1 parent 0bba808 commit b94627a

16 files changed

Lines changed: 28344 additions & 146 deletions

‎apps/sim/lib/core/rate-limiter/provider-admission.test.ts‎

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,66 @@ describe('provider admission', () => {
3535
consumeTokens.mockResolvedValue({ allowed: true, tokensRemaining: 1, resetAt: new Date() })
3636
})
3737

38-
afterEach(() => vi.useRealTimers())
38+
afterEach(() => {
39+
vi.useRealTimers()
40+
vi.unstubAllEnvs()
41+
})
42+
43+
it.each([
44+
{ requestsPerMinute: 1, capacity: 1 },
45+
{ requestsPerMinute: 60, capacity: 2 },
46+
{ requestsPerMinute: 120, capacity: 2 },
47+
{ requestsPerMinute: 121, capacity: 3 },
48+
{ requestsPerMinute: 600, capacity: 10 },
49+
])(
50+
'admits a complete rerank refill at $requestsPerMinute requests per minute',
51+
async ({ requestsPerMinute, capacity }) => {
52+
vi.stubEnv('KB_CONFIG_RERANK_REQUESTS_PER_MINUTE', String(requestsPerMinute))
53+
54+
await waitForProviderAdmission({ ...INPUT, operation: 'rerank', providerId: 'cohere' })
55+
56+
expect(consumeTokens).toHaveBeenCalledExactlyOnceWith(
57+
[
58+
{
59+
key: 'provider:rerank:cohere:hashed-credential:requests',
60+
cost: 1,
61+
config: {
62+
maxTokens: capacity,
63+
refillRate: requestsPerMinute / 60,
64+
refillIntervalMs: 1000,
65+
},
66+
},
67+
],
68+
expect.objectContaining({
69+
cooldownKeys: [
70+
'provider:rerank:cohere:hashed-credential:cooldown',
71+
'provider:rerank:cohere:hashed-credential:quota',
72+
],
73+
})
74+
)
75+
}
76+
)
77+
78+
it.each([
79+
{ operation: 'embedding' as const, capacity: 8, refillRate: 10 },
80+
{ operation: 'ocr' as const, capacity: 2, refillRate: 1 },
81+
{ operation: 'rerank' as const, capacity: 2, refillRate: 1 },
82+
])('preserves default $operation request limits', async ({ operation, capacity, refillRate }) => {
83+
vi.stubEnv('KB_CONFIG_EMBEDDING_REQUESTS_PER_MINUTE', undefined)
84+
vi.stubEnv('KB_CONFIG_OCR_REQUESTS_PER_MINUTE', undefined)
85+
vi.stubEnv('KB_CONFIG_RERANK_REQUESTS_PER_MINUTE', undefined)
86+
87+
await waitForProviderAdmission({ ...INPUT, operation })
88+
89+
expect(consumeTokens.mock.calls[0][0]).toEqual(
90+
expect.arrayContaining([
91+
expect.objectContaining({
92+
key: `provider:${operation}:openai:hashed-credential:requests`,
93+
config: { maxTokens: capacity, refillRate, refillIntervalMs: 1000 },
94+
}),
95+
])
96+
)
97+
})
3998

4099
it('shares both credential dimensions in one reservation across concurrent callers', async () => {
41100
await Promise.all([waitForProviderAdmission(INPUT), waitForProviderAdmission(INPUT)])

‎apps/sim/lib/core/rate-limiter/provider-admission.ts‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ export async function waitForProviderAdmission(input: ProviderAdmissionInput): P
4646
: input.operation === 'ocr'
4747
? envNumber(env.KB_CONFIG_OCR_REQUESTS_PER_MINUTE, 60, { min: 1 })
4848
: envNumber(env.KB_CONFIG_RERANK_REQUESTS_PER_MINUTE, 60, { min: 1 })
49+
/** Rerank capacity must retain a complete refill from the backends' whole-second ticks. */
50+
const requestBurst =
51+
input.operation === 'embedding'
52+
? 8
53+
: input.operation === 'rerank'
54+
? Math.max(2, Math.ceil(requestsPerMinute / 60))
55+
: 2
4956
const reservations: TokenBucketReservation[] = []
5057
if (input.operation === 'embedding' && input.inputTokens) {
5158
const tokensPerMinute = envNumber(env.KB_CONFIG_EMBEDDING_TOKENS_PER_MINUTE, 600_000, {
@@ -68,7 +75,7 @@ export async function waitForProviderAdmission(input: ProviderAdmissionInput): P
6875
key: `${key}:requests`,
6976
cost: 1,
7077
config: {
71-
maxTokens: Math.min(input.operation === 'embedding' ? 8 : 2, requestsPerMinute),
78+
maxTokens: Math.min(requestBurst, requestsPerMinute),
7279
refillRate: requestsPerMinute / 60,
7380
refillIntervalMs: 1000,
7481
},

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

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
66

77
const mocks = vi.hoisted(() => ({
88
getKnowledgeBase: vi.fn(),
9+
getKnowledgeBaseWithCounts: vi.fn(),
910
getDocument: vi.fn(),
1011
getDocumentById: vi.fn(),
1112
getTag: vi.fn(),
@@ -22,7 +23,8 @@ vi.mock('@/lib/knowledge/access/scope', () => ({
2223
}))
2324

2425
vi.mock('@/lib/knowledge/service', () => ({
25-
getKnowledgeBaseById: mocks.getKnowledgeBase,
26+
getActiveKnowledgeBaseReference: mocks.getKnowledgeBase,
27+
getKnowledgeBaseById: mocks.getKnowledgeBaseWithCounts,
2628
}))
2729

2830
vi.mock('@/lib/knowledge/documents/service', () => ({
@@ -66,10 +68,76 @@ describe('knowledge application contexts', () => {
6668
beforeEach(() => {
6769
vi.clearAllMocks()
6870
mocks.getKnowledgeBase.mockResolvedValue(knowledgeBase)
71+
mocks.getKnowledgeBaseWithCounts.mockResolvedValue({
72+
...knowledgeBase,
73+
docCount: 3,
74+
tokenCount: 1536,
75+
})
6976
mocks.loadWorkspace.mockResolvedValue(workspace)
7077
mocks.loadWorkspaceIncludingArchived.mockResolvedValue(workspace)
7178
})
7279

80+
it('resolves child-resource context without loading display counts', async () => {
81+
const context = await resolveActiveKnowledgeResourceContext(
82+
{ knowledgeBaseId: 'knowledge-1', assertedWorkspaceId: 'workspace-1' },
83+
principal
84+
)
85+
86+
expect(context.knowledgeBase).toEqual(knowledgeBase)
87+
expect(mocks.getKnowledgeBaseWithCounts).not.toHaveBeenCalled()
88+
expect(mocks.createAccessProvider).toHaveBeenCalledWith(principal, {
89+
workspaceId: 'workspace-1',
90+
})
91+
})
92+
93+
it('retains display counts in workspace knowledge-base detail context', async () => {
94+
const context = await resolveActiveKnowledgeBaseContext(
95+
{ knowledgeBaseId: 'knowledge-1' },
96+
principal
97+
)
98+
99+
expect(context.knowledgeBase).toMatchObject({ docCount: 3, tokenCount: 1536 })
100+
expect(mocks.getKnowledgeBase).not.toHaveBeenCalled()
101+
})
102+
103+
it('conceals a missing or archived knowledge-base reference before loading its owner', async () => {
104+
mocks.getKnowledgeBase.mockResolvedValueOnce(null)
105+
106+
await expect(
107+
resolveActiveKnowledgeResourceContext({ knowledgeBaseId: 'archived' }, principal)
108+
).rejects.toMatchObject({ code: 'not_found' })
109+
expect(mocks.loadWorkspace).not.toHaveBeenCalled()
110+
expect(mocks.createAccessProvider).not.toHaveBeenCalled()
111+
})
112+
113+
it('conceals an organization reference outside the asserted organization', async () => {
114+
mocks.getKnowledgeBase.mockResolvedValueOnce({
115+
id: 'org-index',
116+
workspaceId: null,
117+
organizationId: 'org-canonical',
118+
})
119+
120+
await expect(
121+
resolveActiveKnowledgeResourceContext(
122+
{ knowledgeBaseId: 'org-index', assertedOrganizationId: 'org-other' },
123+
principal
124+
)
125+
).rejects.toMatchObject({ code: 'not_found' })
126+
expect(mocks.createAccessProvider).not.toHaveBeenCalled()
127+
})
128+
129+
it('conceals a reference with conflicting owners', async () => {
130+
mocks.getKnowledgeBase.mockResolvedValueOnce({
131+
...knowledgeBase,
132+
organizationId: 'org-canonical',
133+
})
134+
135+
await expect(
136+
resolveActiveKnowledgeResourceContext({ knowledgeBaseId: 'knowledge-1' }, principal)
137+
).rejects.toMatchObject({ code: 'not_found' })
138+
expect(mocks.createAccessProvider).not.toHaveBeenCalled()
139+
})
140+
73141
it('uses the canonical active-workspace loader', async () => {
74142
await expect(resolveKnowledgeWorkspaceContext({ workspaceId: 'workspace-1' })).resolves.toBe(
75143
workspace

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ import {
2121
getRestorableKnowledgeBase,
2222
type RestorableKnowledgeBase,
2323
} from '@/lib/knowledge/orchestration/restore'
24-
import { getKnowledgeBaseById } from '@/lib/knowledge/service'
24+
import {
25+
type ActiveKnowledgeBaseReference,
26+
getActiveKnowledgeBaseReference,
27+
getKnowledgeBaseById,
28+
} from '@/lib/knowledge/service'
2529
import { getTagDefinitionById } from '@/lib/knowledge/tags/service'
2630
import type { DocumentTagDefinition } from '@/lib/knowledge/tags/types'
2731
import type { KnowledgeBaseWithCounts } from '@/lib/knowledge/types'
@@ -71,7 +75,7 @@ export interface ActiveKnowledgeBaseContext
7175
export type ActiveKnowledgeResourceBaseContext = KnowledgeResourceContext &
7276
KnowledgeAccessBearingContext & {
7377
knowledgeBaseId: string
74-
knowledgeBase: KnowledgeBaseWithCounts
78+
knowledgeBase: ActiveKnowledgeBaseReference
7579
}
7680

7781
export type ActiveKnowledgeDocumentContext = ActiveKnowledgeResourceBaseContext & {
@@ -227,7 +231,7 @@ export async function resolveActiveKnowledgeResourceContext(
227231
},
228232
principal: Principal
229233
): Promise<ActiveKnowledgeResourceBaseContext> {
230-
const knowledgeBase = await getKnowledgeBaseById(input.knowledgeBaseId)
234+
const knowledgeBase = await getActiveKnowledgeBaseReference(input.knowledgeBaseId)
231235
if (
232236
!knowledgeBase ||
233237
(input.assertedOrganizationId !== undefined &&

0 commit comments

Comments
 (0)