bunnyquery 1.5.6 → 1.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bunnyquery.js +21 -7
- package/dist/engine.cjs +20 -6
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.mts +6 -0
- package/dist/engine.d.ts +6 -0
- package/dist/engine.mjs +20 -6
- package/dist/engine.mjs.map +1 -1
- package/package.json +1 -1
- package/src/engine/office.ts +24 -0
- package/src/engine/prompts/indexing_user_message.ts +20 -0
- package/src/engine/requests.ts +10 -3
package/package.json
CHANGED
package/src/engine/office.ts
CHANGED
|
@@ -101,6 +101,30 @@ export function isServerExtractable(name?: string, mime?: string): boolean {
|
|
|
101
101
|
/** @deprecated renamed to {@link isServerExtractable} (now also covers text files). */
|
|
102
102
|
export const isOfficeFile = isServerExtractable;
|
|
103
103
|
|
|
104
|
+
// Extensions that are best read WINDOW-BY-WINDOW via the readFileContent tool instead of
|
|
105
|
+
// inlined once: spreadsheets (grid rows + embedded photos, and can be huge) and PDFs
|
|
106
|
+
// (scanned page images). For these the indexing agent is told to page through the whole
|
|
107
|
+
// file with readFileContent rather than reading a capped inline dump or web_fetching a URL.
|
|
108
|
+
const PAGED_READ_EXTENSIONS = new Set(['xls', 'xlsx', 'xlsm', 'ods', 'pdf']);
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* True when a file should be indexed by PAGING through readFileContent (spreadsheets and
|
|
112
|
+
* PDFs), rather than inline extraction or a web_fetch URL. This is what lets a huge sheet
|
|
113
|
+
* be read row-window by row-window and a scanned PDF be read page-image by page-image,
|
|
114
|
+
* with embedded photos delivered to the vision model.
|
|
115
|
+
*/
|
|
116
|
+
export function isPagedReadFile(name?: string, mime?: string): boolean {
|
|
117
|
+
const ext = (name || '').split('.').pop()?.toLowerCase() || '';
|
|
118
|
+
if (PAGED_READ_EXTENSIONS.has(ext)) return true;
|
|
119
|
+
const m = (mime || '').toLowerCase();
|
|
120
|
+
return (
|
|
121
|
+
m === 'application/pdf' ||
|
|
122
|
+
m === 'application/vnd.ms-excel' ||
|
|
123
|
+
m.includes('spreadsheetml') ||
|
|
124
|
+
m.includes('opendocument.spreadsheet')
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
104
128
|
// Monotonic counter so placeholders are unique even for same-named files in one
|
|
105
129
|
// request. Token shape must match the worker's _EXTRACT_PLACEHOLDER_RE:
|
|
106
130
|
// {{SKAPI_FILE_CONTENT::<id>}}.
|
|
@@ -36,6 +36,12 @@ export type BuildIndexingUserMessageOptions = {
|
|
|
36
36
|
* web_fetch for this file. Takes precedence over `inlineContentPlaceholder`.
|
|
37
37
|
*/
|
|
38
38
|
inlineContent?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Spreadsheet or PDF: read by PAGING through the readFileContent tool (grid rows +
|
|
41
|
+
* embedded photos / rendered scanned pages), not inline and not by web_fetch. The
|
|
42
|
+
* message instructs the agent to page through EVERY window and datafy each.
|
|
43
|
+
*/
|
|
44
|
+
pagedRead?: boolean;
|
|
39
45
|
};
|
|
40
46
|
|
|
41
47
|
export function buildIndexingUserMessage(
|
|
@@ -78,5 +84,19 @@ export function buildIndexingUserMessage(
|
|
|
78
84
|
);
|
|
79
85
|
}
|
|
80
86
|
|
|
87
|
+
if (options?.pagedRead) {
|
|
88
|
+
// Spreadsheet / PDF: force the paging path. The agent MUST read this with the
|
|
89
|
+
// readFileContent tool (which returns the file window by window, with grid rows,
|
|
90
|
+
// embedded photos, and rendered scanned pages), NOT by fetching the URL.
|
|
91
|
+
return (
|
|
92
|
+
head +
|
|
93
|
+
`\nRead this file with the readFileContent tool, using the storage path above - do NOT fetch a URL and do NOT rely on a single sample. ` +
|
|
94
|
+
`readFileContent returns the file ONE WINDOW at a time: spreadsheets as coordinate-tagged grid rows (e.g. 'R4 A:E&I NUMBER | B:E1007'), scanned/large PDFs as rendered PAGE IMAGES, and windows may include embedded photos - LOOK at any images and datafy what they show. ` +
|
|
95
|
+
`Page through EVERY window: for each window SAVE records for its rows/items/pages (postRecords, one record per row/item), THEN if the window says MORE REMAINS call readFileContent again with the cursor it gives you. Repeat until it says END OF FILE, so the WHOLE file is indexed. ` +
|
|
96
|
+
`Do NOT stop after the first window and do NOT just write a summary. Use the storage path above for the "src::" unique_id.` +
|
|
97
|
+
(attachment.url ? `\n(A temporary URL is provided ONLY as a fallback if readFileContent fails: ${attachment.url})` : '')
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
81
101
|
return head + `- temporary URL (fetch this to read the file contents): ${attachment.url}`;
|
|
82
102
|
}
|
package/src/engine/requests.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* only the BgTaskEntry TYPE lives here)
|
|
12
12
|
*/
|
|
13
13
|
import { buildIndexingSystemPrompt, buildIndexingUserMessage } from './prompts';
|
|
14
|
-
import { isServerExtractable, makeExtractPlaceholder, type ExtractDirective, type FileUrlDirective } from './office';
|
|
14
|
+
import { isServerExtractable, isPagedReadFile, makeExtractPlaceholder, type ExtractDirective, type FileUrlDirective } from './office';
|
|
15
15
|
import { chatEngineConfig, pollOpt } from './config';
|
|
16
16
|
|
|
17
17
|
export const ANTHROPIC_MESSAGES_API_URL = 'https://api.anthropic.com/v1/messages';
|
|
@@ -450,8 +450,13 @@ export type AttachmentSaveInfo = {
|
|
|
450
450
|
export async function notifyAgentSaveAttachment(info: AttachmentSaveInfo) {
|
|
451
451
|
const { platform, service, owner, attachment, parsedContent } = info;
|
|
452
452
|
|
|
453
|
+
// Spreadsheets and PDFs are read by PAGING through readFileContent (grid rows +
|
|
454
|
+
// embedded photos / scanned page images), NOT inlined once - so they skip the inline
|
|
455
|
+
// server-extract and the agent is told to page the whole file (see pagedRead below).
|
|
456
|
+
const pagedRead = !parsedContent && isPagedReadFile(attachment.name, attachment.mime);
|
|
457
|
+
|
|
453
458
|
// Client-parsed content wins over server-side extraction.
|
|
454
|
-
const serverExtract = !parsedContent && isServerExtractable(attachment.name, attachment.mime);
|
|
459
|
+
const serverExtract = !parsedContent && !pagedRead && isServerExtractable(attachment.name, attachment.mime);
|
|
455
460
|
const placeholder = serverExtract ? makeExtractPlaceholder(attachment.storagePath) : undefined;
|
|
456
461
|
const extractContent: ExtractDirective[] | undefined =
|
|
457
462
|
serverExtract && placeholder
|
|
@@ -466,7 +471,9 @@ export async function notifyAgentSaveAttachment(info: AttachmentSaveInfo) {
|
|
|
466
471
|
? { inlineContent: parsedContent }
|
|
467
472
|
: placeholder
|
|
468
473
|
? { inlineContentPlaceholder: placeholder }
|
|
469
|
-
:
|
|
474
|
+
: pagedRead
|
|
475
|
+
? { pagedRead: true }
|
|
476
|
+
: undefined,
|
|
470
477
|
);
|
|
471
478
|
|
|
472
479
|
const systemPrompt = buildIndexingSystemPrompt({
|