Skip to content

Commit 00432f3

Browse files
committed
improvement(search): size a scaled read window by its JSON-encoded length
1 parent 1d17e0a commit 00432f3

2 files changed

Lines changed: 52 additions & 15 deletions

File tree

‎apps/sim/lib/sim-search/live/application.test.ts‎

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,10 +1191,10 @@ describe('authorized live retrieval', () => {
11911191
})
11921192
describe('read window', () => {
11931193
const content = 'x'.repeat(30_000)
1194-
async function readWindow(extra: Record<string, unknown>) {
1194+
async function readWindow(extra: Record<string, unknown>, text = content) {
11951195
const [result] = (await searchLiveKnowledge.execute({ principal, input })).results
11961196
if (!result) throw new Error('Expected the search fixture to return a result')
1197-
mocks.read.mockResolvedValue({ ...document, content })
1197+
mocks.read.mockResolvedValue({ ...document, content: text })
11981198
const read = await readLiveDocument.execute({
11991199
principal,
12001200
input: {
@@ -1207,7 +1207,11 @@ describe('authorized live retrieval', () => {
12071207
})
12081208
const [chunk] = read.chunks
12091209
if (!chunk) throw new Error('Expected the read to return a window')
1210-
return { length: chunk.content.length, next: read.next }
1210+
return {
1211+
length: chunk.content.length,
1212+
encoded: JSON.stringify(chunk.content).length - 2,
1213+
next: read.next,
1214+
}
12111215
}
12121216

12131217
const scaled = (documentsInCall: number) => ({ scaledWindow: { documentsInCall } })
@@ -1236,6 +1240,28 @@ describe('authorized live retrieval', () => {
12361240
}
12371241
)
12381242

1243+
it.each([
1244+
[1, 21_333],
1245+
[2, 20_000],
1246+
])(
1247+
'keeps a quote-heavy window within its share once JSON-encoded, across %i documents',
1248+
async (documentsInCall, share) => {
1249+
const quotes = '"'.repeat(30_000)
1250+
const { length, encoded, next } = await readWindow(
1251+
{ limit: 8, ...scaled(documentsInCall) },
1252+
quotes
1253+
)
1254+
expect(encoded).toBeLessThanOrEqual(share)
1255+
expect(length).toBeGreaterThanOrEqual(8_000)
1256+
expect(next).toEqual({ startChunkIndex: 0, startOffset: length })
1257+
}
1258+
)
1259+
1260+
it('keeps the standard window for quote-heavy text at the default limit', async () => {
1261+
const { length } = await readWindow({ limit: 3, ...scaled(1) }, '"'.repeat(30_000))
1262+
expect(length).toBe(8_000)
1263+
})
1264+
12391265
it.each([
12401266
['at the default limit', { limit: 3, ...scaled(1) }],
12411267
['below the default limit', { limit: 1, ...scaled(1) }],

‎apps/sim/lib/sim-search/live/application.ts‎

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -301,19 +301,30 @@ const READ_WINDOW_LIMIT = 3
301301
const SCALED_READ_CALL_CHARACTERS = 40_000
302302

303303
/**
304-
* Characters one read returns. A live document is one chunk, so a caller that scales the window
305-
* gets a longer one when it asks for more chunks than the default, bounded by an even share of
306-
* the call's budget across the documents it reads, and never shorter than the standard page. At
307-
* or below the default limit, and for every other caller, the window is the standard page.
304+
* Where one read's window ends. A live document is one chunk, so a caller that scales the window
305+
* gets a longer one when it asks for more chunks than the default, bounded by an even share of the
306+
* call's budget across the documents it reads. The share counts the window as the result encodes
307+
* it, since JSON escapes quotes, backslashes and line breaks, so a longer window is shortened until
308+
* its encoded text fits. The window is never shorter than the standard page, which is also what a
309+
* read at or below the default limit, or from any other caller, returns.
308310
*/
309-
function readWindowCharacters({
310-
limit,
311-
scaledWindow,
312-
}: Pick<LiveReadInput, 'limit' | 'scaledWindow'>) {
313-
if (!scaledWindow || limit <= READ_WINDOW_LIMIT) return READ_WINDOW_CHARACTERS
311+
function readWindowEnd(
312+
content: string,
313+
start: number,
314+
{ limit, scaledWindow }: Pick<LiveReadInput, 'limit' | 'scaledWindow'>
315+
): number {
316+
const standardEnd = Math.min(content.length, start + READ_WINDOW_CHARACTERS)
317+
if (!scaledWindow || limit <= READ_WINDOW_LIMIT) return standardEnd
314318
const scaled = Math.floor((READ_WINDOW_CHARACTERS * limit) / READ_WINDOW_LIMIT)
315319
const share = Math.floor(SCALED_READ_CALL_CHARACTERS / Math.max(1, scaledWindow.documentsInCall))
316-
return Math.max(READ_WINDOW_CHARACTERS, Math.min(scaled, share))
320+
const budget = Math.min(scaled, share)
321+
let end = Math.min(content.length, start + budget)
322+
for (let attempt = 0; attempt < 3 && end > standardEnd; attempt++) {
323+
const encoded = JSON.stringify(content.slice(start, end)).length - 2
324+
if (encoded <= budget) return end
325+
end = start + Math.floor(((end - start) * budget) / encoded)
326+
}
327+
return standardEnd
317328
}
318329

319330
/**
@@ -1008,7 +1019,7 @@ export type LiveReadInput = ResourceOwner & {
10081019
limit: number
10091020
/**
10101021
* Lengthens the window for a limit above the default, sharing one call's budget across the
1011-
* documents it reads, as {@link readWindowCharacters} sizes it.
1022+
* documents it reads, as {@link readWindowEnd} sizes it.
10121023
*/
10131024
scaledWindow?: { documentsInCall: number }
10141025
startChunkIndex?: number
@@ -1156,7 +1167,7 @@ export const readLiveDocument = defineAuthorizedKnowledgeUseCase({
11561167
'validation',
11571168
'This document changed. Read again from the beginning'
11581169
)
1159-
const end = Math.min(content.length, start + readWindowCharacters(input))
1170+
const end = readWindowEnd(content, start, input)
11601171
return {
11611172
documentId: input.documentId,
11621173
knowledgeBaseId: '',

0 commit comments

Comments
 (0)