bunnyquery 1.8.0 → 1.8.2
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 +455 -43
- package/dist/engine.cjs +489 -33
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.mts +232 -3
- package/dist/engine.d.ts +232 -3
- package/dist/engine.mjs +462 -34
- package/dist/engine.mjs.map +1 -1
- package/package.json +1 -1
- package/src/engine/ai_agent.ts +80 -0
- package/src/engine/budget.ts +113 -7
- package/src/engine/download_encoding.ts +281 -0
- package/src/engine/errors.ts +34 -0
- package/src/engine/history.ts +48 -18
- package/src/engine/index.ts +11 -0
- package/src/engine/requests.ts +15 -3
- package/src/engine/session.ts +227 -6
package/dist/engine.d.mts
CHANGED
|
@@ -312,18 +312,44 @@ declare function isAuthExpiredError(input: any): boolean;
|
|
|
312
312
|
|
|
313
313
|
declare var CONTEXT_WINDOW_DEFAULT: Record<string, number>;
|
|
314
314
|
declare var CONTEXT_WINDOW_BY_MODEL: Record<string, number>;
|
|
315
|
+
/**
|
|
316
|
+
* Record context windows from a provider models listing. Accepts the raw list
|
|
317
|
+
* items and reads `max_input_tokens` (Anthropic); items without it are skipped,
|
|
318
|
+
* so passing an OpenAI listing is a no-op rather than an error.
|
|
319
|
+
*/
|
|
320
|
+
declare function registerModelContextWindows(models: Array<{
|
|
321
|
+
id?: string;
|
|
322
|
+
max_input_tokens?: number;
|
|
323
|
+
}> | null | undefined): void;
|
|
324
|
+
declare function setProjectContextWindow(serviceId: string, tokens: number | null | undefined): void;
|
|
325
|
+
declare function getProjectContextWindow(serviceId: string): number | null;
|
|
315
326
|
declare var OUTPUT_TOKEN_RESERVE: number;
|
|
316
327
|
declare var TOOL_AND_RESPONSE_BUFFER: number;
|
|
317
328
|
declare var MIN_INPUT_TOKEN_BUDGET: number;
|
|
318
329
|
declare var CLAUDE_PER_REQUEST_INPUT_CAP: number;
|
|
319
330
|
declare var MAX_HISTORY_MESSAGES: number;
|
|
320
331
|
declare var HISTORY_TOKEN_BUDGET: number;
|
|
332
|
+
declare var CLAUDE_INPUT_CAP_RATIO: number;
|
|
333
|
+
declare var HISTORY_BUDGET_RATIO: number;
|
|
321
334
|
declare function estimateTextTokens(text: string): number;
|
|
322
335
|
declare function estimateMessageTokens(msg: {
|
|
323
336
|
role: string;
|
|
324
337
|
content: string;
|
|
325
338
|
}): number;
|
|
326
|
-
|
|
339
|
+
/**
|
|
340
|
+
* Resolve a model's context window, most specific source first:
|
|
341
|
+
* 1. per-project override (project settings)
|
|
342
|
+
* 2. the provider's own models listing (Anthropic `max_input_tokens`)
|
|
343
|
+
* 3. an exact entry in CONTEXT_WINDOW_BY_MODEL
|
|
344
|
+
* 4. a family entry, by dropping trailing '-' segments off the id
|
|
345
|
+
* 5. the platform default
|
|
346
|
+
*
|
|
347
|
+
* Step 4 is why a new or suffixed id no longer drops straight to the platform
|
|
348
|
+
* default: 'gpt-5.6-luna' resolves via 'gpt-5.6', and a dated Claude snapshot
|
|
349
|
+
* such as 'claude-opus-4-7-20260101' resolves via 'claude-opus-4-7'. The walk
|
|
350
|
+
* stops at the first hit, so a more specific entry always wins over its family.
|
|
351
|
+
*/
|
|
352
|
+
declare function getContextWindow(platform: string, model?: string, serviceId?: string): number;
|
|
327
353
|
declare function stripFileBlocksFromHistory(content: string): string;
|
|
328
354
|
type BoundedChatOptions = {
|
|
329
355
|
platform: string;
|
|
@@ -346,6 +372,102 @@ declare function buildBoundedChatMessages(options: BoundedChatOptions): {
|
|
|
346
372
|
estimatedBudget: number;
|
|
347
373
|
};
|
|
348
374
|
|
|
375
|
+
/**
|
|
376
|
+
* How a text file the chat offers as a download is encoded and labelled, so that
|
|
377
|
+
* whatever opens it reads the characters correctly, in any language.
|
|
378
|
+
*
|
|
379
|
+
* When the model answers with a fenced ```name.ext block, the client turns that
|
|
380
|
+
* block into a Blob and an <a download>. We always write UTF-8, but several very
|
|
381
|
+
* common consumers do not assume UTF-8 when nothing in the file says so, and fall
|
|
382
|
+
* back to the reader's local ANSI codepage: CP949 in Korea, CP932 in Japan,
|
|
383
|
+
* CP936/CP950 in China and Taiwan, CP1251 for Cyrillic. The file is valid and
|
|
384
|
+
* every non-ASCII character still opens as mojibake.
|
|
385
|
+
*
|
|
386
|
+
* There is no single fix, because the way a file declares "this is UTF-8" is a
|
|
387
|
+
* property of the FORMAT:
|
|
388
|
+
*
|
|
389
|
+
* - a spreadsheet (csv/tsv) and a Windows text editor read a BOM;
|
|
390
|
+
* - HTML is opened from disk with no HTTP headers, so only an in-document
|
|
391
|
+
* <meta charset> survives;
|
|
392
|
+
* - XML carries its encoding in its declaration, and a WRONG declaration makes
|
|
393
|
+
* a conforming parser fail outright;
|
|
394
|
+
* - RTF is 7-bit, so non-ASCII has to be escaped into \uNNNN?;
|
|
395
|
+
* - JSON, JSONL and YAML are UTF-8 by specification, and a BOM BREAKS them.
|
|
396
|
+
*
|
|
397
|
+
* Anything unrecognised is left byte-for-byte alone: an unknown extension is far
|
|
398
|
+
* more likely to be machine-parsed, where an uninvited BOM is a new bug, than to
|
|
399
|
+
* be opened by a legacy editor.
|
|
400
|
+
*
|
|
401
|
+
* MIRROR of skapi-mcp/download-encoding.js, which does the same job for files the
|
|
402
|
+
* server publishes (writeReport / exportRecordsToFile). A file the user gets from
|
|
403
|
+
* a fenced block and the same file published as a download must behave
|
|
404
|
+
* identically, so the two have to change together.
|
|
405
|
+
*/
|
|
406
|
+
declare const BOM = "\uFEFF";
|
|
407
|
+
/** Files a spreadsheet or a Windows text editor opens directly. */
|
|
408
|
+
declare const BOM_EXTS: Set<string>;
|
|
409
|
+
/** Read from disk with no HTTP headers, so the declaration must be in the file. */
|
|
410
|
+
declare const HTML_EXTS: Set<string>;
|
|
411
|
+
declare const XML_EXTS: Set<string>;
|
|
412
|
+
declare const RTF_EXTS: Set<string>;
|
|
413
|
+
/** Content types by extension. Every text family carries an explicit charset. */
|
|
414
|
+
declare const EXT_CONTENT_TYPES: Record<string, string>;
|
|
415
|
+
type EncodingClass = 'bom' | 'html' | 'xml' | 'rtf' | 'none';
|
|
416
|
+
declare function normalizeExt(ext: string | null | undefined): string;
|
|
417
|
+
/** Extension of a filename, '' when it has none. */
|
|
418
|
+
declare function extOf(filename: string | null | undefined): string;
|
|
419
|
+
/** Which encoding declaration this format understands. */
|
|
420
|
+
declare function encodingClassForExt(ext: string | null | undefined): EncodingClass;
|
|
421
|
+
/** True when a file with this extension must be written BOM-first. */
|
|
422
|
+
declare function needsBomForExt(ext: string | null | undefined): boolean;
|
|
423
|
+
/**
|
|
424
|
+
* Content type to declare. Everything textual carries an explicit charset:
|
|
425
|
+
* without one the receiving end guesses, and it guesses the local codepage.
|
|
426
|
+
*/
|
|
427
|
+
declare function contentTypeForExt(ext: string | null | undefined, fallback?: string): string;
|
|
428
|
+
declare function hasBom(text: string): boolean;
|
|
429
|
+
declare const HTML_HEAD_WINDOW = 4096;
|
|
430
|
+
/**
|
|
431
|
+
* Make an HTML document state its own encoding. Downloaded HTML is opened from
|
|
432
|
+
* disk, where the Content-Type we set no longer exists, so a document with no
|
|
433
|
+
* <meta charset> is decoded with the browser's locale default.
|
|
434
|
+
*/
|
|
435
|
+
declare function ensureHtmlCharset(text: string): string;
|
|
436
|
+
/**
|
|
437
|
+
* Correct an XML declaration that names the wrong encoding.
|
|
438
|
+
*
|
|
439
|
+
* A MISSING declaration is left alone on purpose: XML with none is UTF-8 by
|
|
440
|
+
* specification, so every conforming parser already gets it right. A declaration
|
|
441
|
+
* naming EUC-KR over UTF-8 bytes, on the other hand, makes a parser fail outright.
|
|
442
|
+
*/
|
|
443
|
+
declare function ensureXmlEncoding(text: string): string;
|
|
444
|
+
/** True when the body really is RTF rather than text merely named .rtf. */
|
|
445
|
+
declare function looksLikeRtf(text: string): boolean;
|
|
446
|
+
/**
|
|
447
|
+
* Escape every non-ASCII character into RTF's \uNNNN? form.
|
|
448
|
+
*
|
|
449
|
+
* RTF is 7-bit: a literal UTF-8 byte in the body is read through the codepage the
|
|
450
|
+
* header declares, which is how Korean, Japanese and Cyrillic RTF turns to
|
|
451
|
+
* mojibake in Word. \uNNNN? is codepage-independent.
|
|
452
|
+
*
|
|
453
|
+
* ASCII is never touched, which matters: backslashes and braces in an RTF body
|
|
454
|
+
* are control syntax, and "escaping" them would destroy the document. \u takes a
|
|
455
|
+
* SIGNED 16-bit value, so anything above 0x7FFF is emitted negative, and astral
|
|
456
|
+
* characters are emitted as their two surrogates.
|
|
457
|
+
*/
|
|
458
|
+
declare function escapeRtfNonAscii(text: string): string;
|
|
459
|
+
/** Apply the format's encoding declaration to a whole document. */
|
|
460
|
+
declare function applyEncodingDeclaration(text: string, ext: string | null | undefined): string;
|
|
461
|
+
/**
|
|
462
|
+
* Everything a client needs to turn a fenced ```name.ext block into a download:
|
|
463
|
+
* the exact text to put in the Blob and the type to give it.
|
|
464
|
+
*/
|
|
465
|
+
declare function prepareDownloadText(filename: string, body: string): {
|
|
466
|
+
ext: string;
|
|
467
|
+
text: string;
|
|
468
|
+
contentType: string;
|
|
469
|
+
};
|
|
470
|
+
|
|
349
471
|
/**
|
|
350
472
|
* Pure link/path helpers (no DOM, no marked). Moved verbatim from the chatbox.
|
|
351
473
|
* `serviceId` is passed as a PARAMETER (the original read it from a global) so
|
|
@@ -498,9 +620,61 @@ declare function wallClockNow(): number;
|
|
|
498
620
|
*/
|
|
499
621
|
declare function formatChatTimestamp(ms?: number): string;
|
|
500
622
|
|
|
623
|
+
/**
|
|
624
|
+
* The `ai_agent` service option, parsed and serialized in ONE place.
|
|
625
|
+
*
|
|
626
|
+
* Stored on the skapi service record as up to three '#'-delimited segments:
|
|
627
|
+
*
|
|
628
|
+
* none AI chat disabled
|
|
629
|
+
* claude platform chosen, no model saved yet
|
|
630
|
+
* claude#claude-sonnet-4-6 platform + model
|
|
631
|
+
* claude#claude-sonnet-4-6#400000 platform + model + context-window override
|
|
632
|
+
*
|
|
633
|
+
* The third segment is new and optional, so every value written before it
|
|
634
|
+
* existed parses unchanged with `contextWindow: null`. Nothing writes a third
|
|
635
|
+
* segment without a model, because the window is meaningless without one.
|
|
636
|
+
*
|
|
637
|
+
* This lived as four separate copies (agent.vue, dbfile.vue, service.vue, and
|
|
638
|
+
* the widget's index.js), which is how the format drifts. New callers should
|
|
639
|
+
* import from here rather than re-deriving the split.
|
|
640
|
+
*/
|
|
641
|
+
type AiAgentPlatform = 'claude' | 'openai' | null;
|
|
642
|
+
type ParsedAiAgent = {
|
|
643
|
+
/** null when unset or explicitly 'none'. */
|
|
644
|
+
platform: AiAgentPlatform;
|
|
645
|
+
/** '' when no model has been saved. */
|
|
646
|
+
model: string;
|
|
647
|
+
/** Per-project context-window override in tokens, or null to use the model's. */
|
|
648
|
+
contextWindow: number | null;
|
|
649
|
+
/** True when a real platform is configured (i.e. not unset and not 'none'). */
|
|
650
|
+
hasPlatform: boolean;
|
|
651
|
+
};
|
|
652
|
+
declare function parseAiAgentValue(value: string | null | undefined): ParsedAiAgent;
|
|
653
|
+
declare function buildAiAgentValue(platform: string | null | undefined, model?: string | null, contextWindow?: number | null): string;
|
|
654
|
+
|
|
501
655
|
declare function filterListByClearHorizon(list: any[], clearedAt: number): any[];
|
|
502
656
|
declare function normalizeTextContent(content: any): string;
|
|
503
657
|
declare function extractLastUserTextFromRequest(requestBody: any): string;
|
|
658
|
+
/** The two openings an indexing prompt can have. A bg-queue item that starts with
|
|
659
|
+
* neither is an ordinary chat that happened to be routed onto that queue. */
|
|
660
|
+
declare function isIndexingRequestText(userText: any): boolean;
|
|
661
|
+
type IndexingRequestRef = {
|
|
662
|
+
name: string;
|
|
663
|
+
path?: string;
|
|
664
|
+
mime?: string;
|
|
665
|
+
size?: number;
|
|
666
|
+
/** A CONTINUE pass rather than the run's first. */
|
|
667
|
+
continued: boolean;
|
|
668
|
+
};
|
|
669
|
+
/**
|
|
670
|
+
* The file an indexing prompt is about, read back out of the prompt itself.
|
|
671
|
+
*
|
|
672
|
+
* The prompt is the only description of the pass that survives on the server, so
|
|
673
|
+
* this is how BOTH a history rebuild and a worker-minted pass the client never
|
|
674
|
+
* dispatched (ChatSession._adoptWorkerIndexingPasses) recover the file. Shared so
|
|
675
|
+
* the two produce the same `_indexFile`, which is what makes them group together.
|
|
676
|
+
*/
|
|
677
|
+
declare function parseIndexingRequestText(userText: any): IndexingRequestRef | null;
|
|
504
678
|
type MapHistoryOptions = {
|
|
505
679
|
clearedAt: number;
|
|
506
680
|
serviceId: string;
|
|
@@ -643,7 +817,7 @@ type CallClaudeWithMcpParams = {
|
|
|
643
817
|
onResponse?: (res: any) => void;
|
|
644
818
|
onError?: (err: any) => void;
|
|
645
819
|
};
|
|
646
|
-
declare const POLL_INTERVAL =
|
|
820
|
+
declare const POLL_INTERVAL = 3000;
|
|
647
821
|
declare function callClaudeWithMcp({ prompt, messages, service, owner, userId, model, maxTokens, system, mcpServer, extractContent, fileUrls, }: CallClaudeWithMcpParams): Promise<any>;
|
|
648
822
|
declare function callClaudeWithPublicMcp(prompt: string, service: string, owner: string, messages?: ClaudeMessage[], system?: string, model?: string, userId?: string, extractContent?: ExtractDirective[], fileUrls?: FileUrlDirective[], onResponse?: (res: any) => void, onError?: (err: any) => void): Promise<any>;
|
|
649
823
|
declare function callOpenAIWithPublicMcp(prompt: string, service: string, owner: string, messages?: OpenAIMessage[], system?: string, model?: string, userId?: string, extractContent?: ExtractDirective[], fileUrls?: FileUrlDirective[], onResponse?: (res: any) => void, onError?: (err: any) => void): Promise<any>;
|
|
@@ -713,11 +887,20 @@ type BgTaskEntry = {
|
|
|
713
887
|
/** How many CONTINUE passes have already run for this file (resume-across-passes). */
|
|
714
888
|
resumePass?: number;
|
|
715
889
|
};
|
|
890
|
+
/**
|
|
891
|
+
* `queue` narrows the fetch to one processing chain; `status` narrows it to items
|
|
892
|
+
* in one state. Passing both is how the client asks "is there still unresolved
|
|
893
|
+
* work on the background-indexing queue?" without pulling a page of chat history
|
|
894
|
+
* (see ChatSession._adoptWorkerIndexingPasses) — the server answers that from a
|
|
895
|
+
* status-keyed index, so the reply carries only the live items, not the bodies of
|
|
896
|
+
* everything already finished.
|
|
897
|
+
*/
|
|
716
898
|
declare function getChatHistory(params: {
|
|
717
899
|
service?: string;
|
|
718
900
|
owner?: string;
|
|
719
901
|
platform: 'claude' | 'openai';
|
|
720
902
|
queue?: string;
|
|
903
|
+
status?: 'pending' | 'running' | 'resolved' | 'failed';
|
|
721
904
|
}, fetchOptions: Record<string, any>): Promise<any>;
|
|
722
905
|
|
|
723
906
|
/**
|
|
@@ -1152,6 +1335,9 @@ declare class ChatSession {
|
|
|
1152
1335
|
_clearPendingUserBubble(itemId: string): void;
|
|
1153
1336
|
resumePendingRequest(token: number): Promise<void>;
|
|
1154
1337
|
handleHistoryItemResolution(itemId: string, response: any, platform: string): void;
|
|
1338
|
+
/** The file an already-rendered background pass is about, off its request
|
|
1339
|
+
* bubble. Null for an ordinary turn, which is most of them. */
|
|
1340
|
+
private _indexRefOfItem;
|
|
1155
1341
|
applyHistoryItemResolution(itemId: string, response: any, platform: string): void;
|
|
1156
1342
|
/** How a bg task maps onto a collapsed row: the row's own key (storage path
|
|
1157
1343
|
* when known, else the filename), scoped to the chat it belongs to. A storage
|
|
@@ -1183,6 +1369,49 @@ declare class ChatSession {
|
|
|
1183
1369
|
* Runs from drainBgTaskQueue, which both clients call after a history load.
|
|
1184
1370
|
*/
|
|
1185
1371
|
private _sweepCancelledIndexing;
|
|
1372
|
+
/**
|
|
1373
|
+
* True when the WORKER, not this client, drives the rest of this file's chain.
|
|
1374
|
+
* The mirror image of the early returns in maybeResumeIndexing: whatever that
|
|
1375
|
+
* refuses to continue is exactly what nothing client-side is tracking.
|
|
1376
|
+
*/
|
|
1377
|
+
private _isWorkerDrivenIndexing;
|
|
1378
|
+
/**
|
|
1379
|
+
* Pick up indexing passes the WORKER minted, which no client ever dispatched.
|
|
1380
|
+
*
|
|
1381
|
+
* For a PDF (and for text/grid when windowed indexing is on) the worker writes
|
|
1382
|
+
* pass N+1's row itself, inside pass N's invocation, right after saving pass
|
|
1383
|
+
* N's result. That row reaches this client through nothing at all: it is not in
|
|
1384
|
+
* bgTaskQueue (the client never asked for it) and it is not in state.messages
|
|
1385
|
+
* (only a first-page history load maps it in, which happens on mount, project
|
|
1386
|
+
* switch or tab return). So between two worker passes every pass the client
|
|
1387
|
+
* knows about is settled, and the collapsed row renders "Indexed N passes"
|
|
1388
|
+
* with no spinner and no Stop, for a file that is still being read. A user who
|
|
1389
|
+
* believes that then asks questions against a half-indexed file — which is what
|
|
1390
|
+
* this exists to prevent.
|
|
1391
|
+
*
|
|
1392
|
+
* So when a background indexing pass settles, ask the bg queue what is still
|
|
1393
|
+
* unresolved on it and adopt anything unknown as an ordinary BgTaskEntry.
|
|
1394
|
+
* drainBgTaskQueue then treats it exactly like a pass this client dispatched:
|
|
1395
|
+
* same bubble, same `_indexFile` (so it joins the file's collapsed row), same
|
|
1396
|
+
* poll — and that poll settling runs this again, so the chain is followed to
|
|
1397
|
+
* its end. `status`-scoped so the reply carries the live items only, never a
|
|
1398
|
+
* page of finished ones with their bodies.
|
|
1399
|
+
*
|
|
1400
|
+
* Termination: the only trigger is a pass SETTLING, which happens once per
|
|
1401
|
+
* pass. An adopted item that is still running is not re-adopted (its id is
|
|
1402
|
+
* already polled), and when the queue holds nothing unknown the chain stops on
|
|
1403
|
+
* its own. Nothing here is periodic — a timer that re-reads history is the
|
|
1404
|
+
* shape that previously looped fetchHistoryPage after an already-DONE index.
|
|
1405
|
+
*/
|
|
1406
|
+
private _adoptingWorkerPasses;
|
|
1407
|
+
private _adoptWorkerIndexingPasses;
|
|
1408
|
+
/** Any of these ids still queued or still polled, i.e. surviving work. */
|
|
1409
|
+
private _isTrackingAny;
|
|
1410
|
+
/** One live bg-queue item -> a BgTaskEntry, if it is an indexing pass this
|
|
1411
|
+
* client is not already tracking. Returns whether it was adopted. */
|
|
1412
|
+
private _adoptWorkerIndexingItem;
|
|
1413
|
+
/** Follow the chain on from a background indexing pass that just settled. */
|
|
1414
|
+
private _followWorkerIndexingChain;
|
|
1186
1415
|
/** Best-effort server-side cancel of a bg-queue item that has no bubble (so
|
|
1187
1416
|
* cancelQueuedMessage, which drives one, has nothing to act on). */
|
|
1188
1417
|
private _cancelServerItem;
|
|
@@ -1203,4 +1432,4 @@ declare class ChatSession {
|
|
|
1203
1432
|
bumpGate(): void;
|
|
1204
1433
|
}
|
|
1205
1434
|
|
|
1206
|
-
export { type AttachmentFailureGroup, type AttachmentParser, type AttachmentSaveInfo, BG_INDEXING_QUEUE_SUFFIX, type BgTaskEntry, type BoundedChatOptions, type BuildDisplayListOptions, type BuildIndexingUserMessageOptions, CLAUDE_PER_REQUEST_INPUT_CAP, CONTEXT_WINDOW_BY_MODEL, CONTEXT_WINDOW_DEFAULT, type CallClaudeWithMcpParams, type ChatEngineConfig, type ChatHost, type ChatIdentity, type ChatMessage, ChatSession, type ChatState, type ChatSystemPromptParams, type ClaudeMcpServerRequest, type ClaudeMcpToolConfig, type ClaudeMessage, type ClaudeRole, type ComposedUserMessage, DEFAULT_CLAUDE_MODEL, DEFAULT_OPENAI_MODEL, type DisplayEntry, EXPIRED_ATTACHMENT_URL_HOST, EXPIRED_ATTACHMENT_URL_ORIGIN, EXPIRED_LINK_REFRESH_EXPIRES_SECONDS, type ExtractDirective, type FillHistoryViewportOptions, HISTORY_FILL_SLACK_PX, HISTORY_TOKEN_BUDGET, type IndexingAttachmentInfo, type IndexingFileRef, type IndexingGroup, type IndexingGroupStatus, type IndexingSystemPromptParams, type InlineLinkContext, type InlineLinkPart, LINK_LABEL_MAX_DISPLAY_CHARS, LINK_REFRESH_WINDOW_MS, MAX_HISTORY_FILL_PAGES, MAX_HISTORY_MESSAGES, MAX_PARSED_CONTENT_CHARS, MCP_NAME, MIN_INPUT_TOKEN_BUDGET, type MapHistoryOptions, OUTPUT_TOKEN_RESERVE, type OpenAIMessage, POLL_INTERVAL, type PinnedDispatchContext, RENDER_FROM_TOKEN, TOOL_AND_RESPONSE_BUFFER, buildBoundedChatMessages, buildChatDisplayList, buildChatSystemPrompt, buildDisplayExpiredAttachmentHref, buildIndexingContinueMessage, buildIndexingRenderContinueTemplate, buildIndexingRenderMessage, buildIndexingSystemPrompt, buildIndexingUserMessage, buildIndexingWindowMessage, callClaudeWithMcp, callClaudeWithPublicMcp, callOpenAIWithPublicMcp, chatEngineConfig, classifyInlineLink, clearAttachmentParsers, composeUserMessage, configureChatEngine, createHistoryFiller, createInlineLinkRegex, encodePathSegments, estimateMessageTokens, estimateTextTokens, extractClaudeText, extractLastUserTextFromRequest, extractOpenAIText, extractRemotePathFromAttachmentHref, fillHistoryViewport, filterListByClearHorizon, findAttachmentParser, formatChatTimestamp, getAttachmentParsers, getChatHistory, getContextWindow, getErrorMessage, getExpiredAttachmentVisiblePath, groupAttachmentFailures, isAuthExpiredError, isBgIndexingQueue, isErrorResponseBody, isHttpUrlLike, isNonRetryableRequestError, isOfficeFile, isServerExtractable, isServiceDbAttachmentHref, listClaudeModels, listOpenAIModels, makeExtractPlaceholder, mapHistoryListToMessages, normalizeAttachmentPathCandidate, normalizeTextContent, normalizeTrailingInlineToken, notifyAgentSaveAttachment, parseAttachmentContent, parseIndexingLabel, readExpiredAttachmentHref, registerAttachmentParser, repairUrlEntities, repairUrlWhitespace, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay, wallClockNow };
|
|
1435
|
+
export { type AiAgentPlatform, type AttachmentFailureGroup, type AttachmentParser, type AttachmentSaveInfo, BG_INDEXING_QUEUE_SUFFIX, BOM, BOM_EXTS, type BgTaskEntry, type BoundedChatOptions, type BuildDisplayListOptions, type BuildIndexingUserMessageOptions, CLAUDE_INPUT_CAP_RATIO, CLAUDE_PER_REQUEST_INPUT_CAP, CONTEXT_WINDOW_BY_MODEL, CONTEXT_WINDOW_DEFAULT, type CallClaudeWithMcpParams, type ChatEngineConfig, type ChatHost, type ChatIdentity, type ChatMessage, ChatSession, type ChatState, type ChatSystemPromptParams, type ClaudeMcpServerRequest, type ClaudeMcpToolConfig, type ClaudeMessage, type ClaudeRole, type ComposedUserMessage, DEFAULT_CLAUDE_MODEL, DEFAULT_OPENAI_MODEL, type DisplayEntry, EXPIRED_ATTACHMENT_URL_HOST, EXPIRED_ATTACHMENT_URL_ORIGIN, EXPIRED_LINK_REFRESH_EXPIRES_SECONDS, EXT_CONTENT_TYPES, type EncodingClass, type ExtractDirective, type FillHistoryViewportOptions, HISTORY_BUDGET_RATIO, HISTORY_FILL_SLACK_PX, HISTORY_TOKEN_BUDGET, HTML_EXTS, HTML_HEAD_WINDOW, type IndexingAttachmentInfo, type IndexingFileRef, type IndexingGroup, type IndexingGroupStatus, type IndexingRequestRef, type IndexingSystemPromptParams, type InlineLinkContext, type InlineLinkPart, LINK_LABEL_MAX_DISPLAY_CHARS, LINK_REFRESH_WINDOW_MS, MAX_HISTORY_FILL_PAGES, MAX_HISTORY_MESSAGES, MAX_PARSED_CONTENT_CHARS, MCP_NAME, MIN_INPUT_TOKEN_BUDGET, type MapHistoryOptions, OUTPUT_TOKEN_RESERVE, type OpenAIMessage, POLL_INTERVAL, type ParsedAiAgent, type PinnedDispatchContext, RENDER_FROM_TOKEN, RTF_EXTS, TOOL_AND_RESPONSE_BUFFER, XML_EXTS, applyEncodingDeclaration, buildAiAgentValue, buildBoundedChatMessages, buildChatDisplayList, buildChatSystemPrompt, buildDisplayExpiredAttachmentHref, buildIndexingContinueMessage, buildIndexingRenderContinueTemplate, buildIndexingRenderMessage, buildIndexingSystemPrompt, buildIndexingUserMessage, buildIndexingWindowMessage, callClaudeWithMcp, callClaudeWithPublicMcp, callOpenAIWithPublicMcp, chatEngineConfig, classifyInlineLink, clearAttachmentParsers, composeUserMessage, configureChatEngine, contentTypeForExt, createHistoryFiller, createInlineLinkRegex, encodePathSegments, encodingClassForExt, ensureHtmlCharset, ensureXmlEncoding, escapeRtfNonAscii, estimateMessageTokens, estimateTextTokens, extOf, extractClaudeText, extractLastUserTextFromRequest, extractOpenAIText, extractRemotePathFromAttachmentHref, fillHistoryViewport, filterListByClearHorizon, findAttachmentParser, formatChatTimestamp, getAttachmentParsers, getChatHistory, getContextWindow, getErrorMessage, getExpiredAttachmentVisiblePath, getProjectContextWindow, groupAttachmentFailures, hasBom, isAuthExpiredError, isBgIndexingQueue, isErrorResponseBody, isHttpUrlLike, isIndexingRequestText, isNonRetryableRequestError, isOfficeFile, isServerExtractable, isServiceDbAttachmentHref, listClaudeModels, listOpenAIModels, looksLikeRtf, makeExtractPlaceholder, mapHistoryListToMessages, needsBomForExt, normalizeAttachmentPathCandidate, normalizeExt, normalizeTextContent, normalizeTrailingInlineToken, notifyAgentSaveAttachment, parseAiAgentValue, parseAttachmentContent, parseIndexingLabel, parseIndexingRequestText, prepareDownloadText, readExpiredAttachmentHref, registerAttachmentParser, registerModelContextWindows, repairUrlEntities, repairUrlWhitespace, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, setProjectContextWindow, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay, wallClockNow };
|
package/dist/engine.d.ts
CHANGED
|
@@ -312,18 +312,44 @@ declare function isAuthExpiredError(input: any): boolean;
|
|
|
312
312
|
|
|
313
313
|
declare var CONTEXT_WINDOW_DEFAULT: Record<string, number>;
|
|
314
314
|
declare var CONTEXT_WINDOW_BY_MODEL: Record<string, number>;
|
|
315
|
+
/**
|
|
316
|
+
* Record context windows from a provider models listing. Accepts the raw list
|
|
317
|
+
* items and reads `max_input_tokens` (Anthropic); items without it are skipped,
|
|
318
|
+
* so passing an OpenAI listing is a no-op rather than an error.
|
|
319
|
+
*/
|
|
320
|
+
declare function registerModelContextWindows(models: Array<{
|
|
321
|
+
id?: string;
|
|
322
|
+
max_input_tokens?: number;
|
|
323
|
+
}> | null | undefined): void;
|
|
324
|
+
declare function setProjectContextWindow(serviceId: string, tokens: number | null | undefined): void;
|
|
325
|
+
declare function getProjectContextWindow(serviceId: string): number | null;
|
|
315
326
|
declare var OUTPUT_TOKEN_RESERVE: number;
|
|
316
327
|
declare var TOOL_AND_RESPONSE_BUFFER: number;
|
|
317
328
|
declare var MIN_INPUT_TOKEN_BUDGET: number;
|
|
318
329
|
declare var CLAUDE_PER_REQUEST_INPUT_CAP: number;
|
|
319
330
|
declare var MAX_HISTORY_MESSAGES: number;
|
|
320
331
|
declare var HISTORY_TOKEN_BUDGET: number;
|
|
332
|
+
declare var CLAUDE_INPUT_CAP_RATIO: number;
|
|
333
|
+
declare var HISTORY_BUDGET_RATIO: number;
|
|
321
334
|
declare function estimateTextTokens(text: string): number;
|
|
322
335
|
declare function estimateMessageTokens(msg: {
|
|
323
336
|
role: string;
|
|
324
337
|
content: string;
|
|
325
338
|
}): number;
|
|
326
|
-
|
|
339
|
+
/**
|
|
340
|
+
* Resolve a model's context window, most specific source first:
|
|
341
|
+
* 1. per-project override (project settings)
|
|
342
|
+
* 2. the provider's own models listing (Anthropic `max_input_tokens`)
|
|
343
|
+
* 3. an exact entry in CONTEXT_WINDOW_BY_MODEL
|
|
344
|
+
* 4. a family entry, by dropping trailing '-' segments off the id
|
|
345
|
+
* 5. the platform default
|
|
346
|
+
*
|
|
347
|
+
* Step 4 is why a new or suffixed id no longer drops straight to the platform
|
|
348
|
+
* default: 'gpt-5.6-luna' resolves via 'gpt-5.6', and a dated Claude snapshot
|
|
349
|
+
* such as 'claude-opus-4-7-20260101' resolves via 'claude-opus-4-7'. The walk
|
|
350
|
+
* stops at the first hit, so a more specific entry always wins over its family.
|
|
351
|
+
*/
|
|
352
|
+
declare function getContextWindow(platform: string, model?: string, serviceId?: string): number;
|
|
327
353
|
declare function stripFileBlocksFromHistory(content: string): string;
|
|
328
354
|
type BoundedChatOptions = {
|
|
329
355
|
platform: string;
|
|
@@ -346,6 +372,102 @@ declare function buildBoundedChatMessages(options: BoundedChatOptions): {
|
|
|
346
372
|
estimatedBudget: number;
|
|
347
373
|
};
|
|
348
374
|
|
|
375
|
+
/**
|
|
376
|
+
* How a text file the chat offers as a download is encoded and labelled, so that
|
|
377
|
+
* whatever opens it reads the characters correctly, in any language.
|
|
378
|
+
*
|
|
379
|
+
* When the model answers with a fenced ```name.ext block, the client turns that
|
|
380
|
+
* block into a Blob and an <a download>. We always write UTF-8, but several very
|
|
381
|
+
* common consumers do not assume UTF-8 when nothing in the file says so, and fall
|
|
382
|
+
* back to the reader's local ANSI codepage: CP949 in Korea, CP932 in Japan,
|
|
383
|
+
* CP936/CP950 in China and Taiwan, CP1251 for Cyrillic. The file is valid and
|
|
384
|
+
* every non-ASCII character still opens as mojibake.
|
|
385
|
+
*
|
|
386
|
+
* There is no single fix, because the way a file declares "this is UTF-8" is a
|
|
387
|
+
* property of the FORMAT:
|
|
388
|
+
*
|
|
389
|
+
* - a spreadsheet (csv/tsv) and a Windows text editor read a BOM;
|
|
390
|
+
* - HTML is opened from disk with no HTTP headers, so only an in-document
|
|
391
|
+
* <meta charset> survives;
|
|
392
|
+
* - XML carries its encoding in its declaration, and a WRONG declaration makes
|
|
393
|
+
* a conforming parser fail outright;
|
|
394
|
+
* - RTF is 7-bit, so non-ASCII has to be escaped into \uNNNN?;
|
|
395
|
+
* - JSON, JSONL and YAML are UTF-8 by specification, and a BOM BREAKS them.
|
|
396
|
+
*
|
|
397
|
+
* Anything unrecognised is left byte-for-byte alone: an unknown extension is far
|
|
398
|
+
* more likely to be machine-parsed, where an uninvited BOM is a new bug, than to
|
|
399
|
+
* be opened by a legacy editor.
|
|
400
|
+
*
|
|
401
|
+
* MIRROR of skapi-mcp/download-encoding.js, which does the same job for files the
|
|
402
|
+
* server publishes (writeReport / exportRecordsToFile). A file the user gets from
|
|
403
|
+
* a fenced block and the same file published as a download must behave
|
|
404
|
+
* identically, so the two have to change together.
|
|
405
|
+
*/
|
|
406
|
+
declare const BOM = "\uFEFF";
|
|
407
|
+
/** Files a spreadsheet or a Windows text editor opens directly. */
|
|
408
|
+
declare const BOM_EXTS: Set<string>;
|
|
409
|
+
/** Read from disk with no HTTP headers, so the declaration must be in the file. */
|
|
410
|
+
declare const HTML_EXTS: Set<string>;
|
|
411
|
+
declare const XML_EXTS: Set<string>;
|
|
412
|
+
declare const RTF_EXTS: Set<string>;
|
|
413
|
+
/** Content types by extension. Every text family carries an explicit charset. */
|
|
414
|
+
declare const EXT_CONTENT_TYPES: Record<string, string>;
|
|
415
|
+
type EncodingClass = 'bom' | 'html' | 'xml' | 'rtf' | 'none';
|
|
416
|
+
declare function normalizeExt(ext: string | null | undefined): string;
|
|
417
|
+
/** Extension of a filename, '' when it has none. */
|
|
418
|
+
declare function extOf(filename: string | null | undefined): string;
|
|
419
|
+
/** Which encoding declaration this format understands. */
|
|
420
|
+
declare function encodingClassForExt(ext: string | null | undefined): EncodingClass;
|
|
421
|
+
/** True when a file with this extension must be written BOM-first. */
|
|
422
|
+
declare function needsBomForExt(ext: string | null | undefined): boolean;
|
|
423
|
+
/**
|
|
424
|
+
* Content type to declare. Everything textual carries an explicit charset:
|
|
425
|
+
* without one the receiving end guesses, and it guesses the local codepage.
|
|
426
|
+
*/
|
|
427
|
+
declare function contentTypeForExt(ext: string | null | undefined, fallback?: string): string;
|
|
428
|
+
declare function hasBom(text: string): boolean;
|
|
429
|
+
declare const HTML_HEAD_WINDOW = 4096;
|
|
430
|
+
/**
|
|
431
|
+
* Make an HTML document state its own encoding. Downloaded HTML is opened from
|
|
432
|
+
* disk, where the Content-Type we set no longer exists, so a document with no
|
|
433
|
+
* <meta charset> is decoded with the browser's locale default.
|
|
434
|
+
*/
|
|
435
|
+
declare function ensureHtmlCharset(text: string): string;
|
|
436
|
+
/**
|
|
437
|
+
* Correct an XML declaration that names the wrong encoding.
|
|
438
|
+
*
|
|
439
|
+
* A MISSING declaration is left alone on purpose: XML with none is UTF-8 by
|
|
440
|
+
* specification, so every conforming parser already gets it right. A declaration
|
|
441
|
+
* naming EUC-KR over UTF-8 bytes, on the other hand, makes a parser fail outright.
|
|
442
|
+
*/
|
|
443
|
+
declare function ensureXmlEncoding(text: string): string;
|
|
444
|
+
/** True when the body really is RTF rather than text merely named .rtf. */
|
|
445
|
+
declare function looksLikeRtf(text: string): boolean;
|
|
446
|
+
/**
|
|
447
|
+
* Escape every non-ASCII character into RTF's \uNNNN? form.
|
|
448
|
+
*
|
|
449
|
+
* RTF is 7-bit: a literal UTF-8 byte in the body is read through the codepage the
|
|
450
|
+
* header declares, which is how Korean, Japanese and Cyrillic RTF turns to
|
|
451
|
+
* mojibake in Word. \uNNNN? is codepage-independent.
|
|
452
|
+
*
|
|
453
|
+
* ASCII is never touched, which matters: backslashes and braces in an RTF body
|
|
454
|
+
* are control syntax, and "escaping" them would destroy the document. \u takes a
|
|
455
|
+
* SIGNED 16-bit value, so anything above 0x7FFF is emitted negative, and astral
|
|
456
|
+
* characters are emitted as their two surrogates.
|
|
457
|
+
*/
|
|
458
|
+
declare function escapeRtfNonAscii(text: string): string;
|
|
459
|
+
/** Apply the format's encoding declaration to a whole document. */
|
|
460
|
+
declare function applyEncodingDeclaration(text: string, ext: string | null | undefined): string;
|
|
461
|
+
/**
|
|
462
|
+
* Everything a client needs to turn a fenced ```name.ext block into a download:
|
|
463
|
+
* the exact text to put in the Blob and the type to give it.
|
|
464
|
+
*/
|
|
465
|
+
declare function prepareDownloadText(filename: string, body: string): {
|
|
466
|
+
ext: string;
|
|
467
|
+
text: string;
|
|
468
|
+
contentType: string;
|
|
469
|
+
};
|
|
470
|
+
|
|
349
471
|
/**
|
|
350
472
|
* Pure link/path helpers (no DOM, no marked). Moved verbatim from the chatbox.
|
|
351
473
|
* `serviceId` is passed as a PARAMETER (the original read it from a global) so
|
|
@@ -498,9 +620,61 @@ declare function wallClockNow(): number;
|
|
|
498
620
|
*/
|
|
499
621
|
declare function formatChatTimestamp(ms?: number): string;
|
|
500
622
|
|
|
623
|
+
/**
|
|
624
|
+
* The `ai_agent` service option, parsed and serialized in ONE place.
|
|
625
|
+
*
|
|
626
|
+
* Stored on the skapi service record as up to three '#'-delimited segments:
|
|
627
|
+
*
|
|
628
|
+
* none AI chat disabled
|
|
629
|
+
* claude platform chosen, no model saved yet
|
|
630
|
+
* claude#claude-sonnet-4-6 platform + model
|
|
631
|
+
* claude#claude-sonnet-4-6#400000 platform + model + context-window override
|
|
632
|
+
*
|
|
633
|
+
* The third segment is new and optional, so every value written before it
|
|
634
|
+
* existed parses unchanged with `contextWindow: null`. Nothing writes a third
|
|
635
|
+
* segment without a model, because the window is meaningless without one.
|
|
636
|
+
*
|
|
637
|
+
* This lived as four separate copies (agent.vue, dbfile.vue, service.vue, and
|
|
638
|
+
* the widget's index.js), which is how the format drifts. New callers should
|
|
639
|
+
* import from here rather than re-deriving the split.
|
|
640
|
+
*/
|
|
641
|
+
type AiAgentPlatform = 'claude' | 'openai' | null;
|
|
642
|
+
type ParsedAiAgent = {
|
|
643
|
+
/** null when unset or explicitly 'none'. */
|
|
644
|
+
platform: AiAgentPlatform;
|
|
645
|
+
/** '' when no model has been saved. */
|
|
646
|
+
model: string;
|
|
647
|
+
/** Per-project context-window override in tokens, or null to use the model's. */
|
|
648
|
+
contextWindow: number | null;
|
|
649
|
+
/** True when a real platform is configured (i.e. not unset and not 'none'). */
|
|
650
|
+
hasPlatform: boolean;
|
|
651
|
+
};
|
|
652
|
+
declare function parseAiAgentValue(value: string | null | undefined): ParsedAiAgent;
|
|
653
|
+
declare function buildAiAgentValue(platform: string | null | undefined, model?: string | null, contextWindow?: number | null): string;
|
|
654
|
+
|
|
501
655
|
declare function filterListByClearHorizon(list: any[], clearedAt: number): any[];
|
|
502
656
|
declare function normalizeTextContent(content: any): string;
|
|
503
657
|
declare function extractLastUserTextFromRequest(requestBody: any): string;
|
|
658
|
+
/** The two openings an indexing prompt can have. A bg-queue item that starts with
|
|
659
|
+
* neither is an ordinary chat that happened to be routed onto that queue. */
|
|
660
|
+
declare function isIndexingRequestText(userText: any): boolean;
|
|
661
|
+
type IndexingRequestRef = {
|
|
662
|
+
name: string;
|
|
663
|
+
path?: string;
|
|
664
|
+
mime?: string;
|
|
665
|
+
size?: number;
|
|
666
|
+
/** A CONTINUE pass rather than the run's first. */
|
|
667
|
+
continued: boolean;
|
|
668
|
+
};
|
|
669
|
+
/**
|
|
670
|
+
* The file an indexing prompt is about, read back out of the prompt itself.
|
|
671
|
+
*
|
|
672
|
+
* The prompt is the only description of the pass that survives on the server, so
|
|
673
|
+
* this is how BOTH a history rebuild and a worker-minted pass the client never
|
|
674
|
+
* dispatched (ChatSession._adoptWorkerIndexingPasses) recover the file. Shared so
|
|
675
|
+
* the two produce the same `_indexFile`, which is what makes them group together.
|
|
676
|
+
*/
|
|
677
|
+
declare function parseIndexingRequestText(userText: any): IndexingRequestRef | null;
|
|
504
678
|
type MapHistoryOptions = {
|
|
505
679
|
clearedAt: number;
|
|
506
680
|
serviceId: string;
|
|
@@ -643,7 +817,7 @@ type CallClaudeWithMcpParams = {
|
|
|
643
817
|
onResponse?: (res: any) => void;
|
|
644
818
|
onError?: (err: any) => void;
|
|
645
819
|
};
|
|
646
|
-
declare const POLL_INTERVAL =
|
|
820
|
+
declare const POLL_INTERVAL = 3000;
|
|
647
821
|
declare function callClaudeWithMcp({ prompt, messages, service, owner, userId, model, maxTokens, system, mcpServer, extractContent, fileUrls, }: CallClaudeWithMcpParams): Promise<any>;
|
|
648
822
|
declare function callClaudeWithPublicMcp(prompt: string, service: string, owner: string, messages?: ClaudeMessage[], system?: string, model?: string, userId?: string, extractContent?: ExtractDirective[], fileUrls?: FileUrlDirective[], onResponse?: (res: any) => void, onError?: (err: any) => void): Promise<any>;
|
|
649
823
|
declare function callOpenAIWithPublicMcp(prompt: string, service: string, owner: string, messages?: OpenAIMessage[], system?: string, model?: string, userId?: string, extractContent?: ExtractDirective[], fileUrls?: FileUrlDirective[], onResponse?: (res: any) => void, onError?: (err: any) => void): Promise<any>;
|
|
@@ -713,11 +887,20 @@ type BgTaskEntry = {
|
|
|
713
887
|
/** How many CONTINUE passes have already run for this file (resume-across-passes). */
|
|
714
888
|
resumePass?: number;
|
|
715
889
|
};
|
|
890
|
+
/**
|
|
891
|
+
* `queue` narrows the fetch to one processing chain; `status` narrows it to items
|
|
892
|
+
* in one state. Passing both is how the client asks "is there still unresolved
|
|
893
|
+
* work on the background-indexing queue?" without pulling a page of chat history
|
|
894
|
+
* (see ChatSession._adoptWorkerIndexingPasses) — the server answers that from a
|
|
895
|
+
* status-keyed index, so the reply carries only the live items, not the bodies of
|
|
896
|
+
* everything already finished.
|
|
897
|
+
*/
|
|
716
898
|
declare function getChatHistory(params: {
|
|
717
899
|
service?: string;
|
|
718
900
|
owner?: string;
|
|
719
901
|
platform: 'claude' | 'openai';
|
|
720
902
|
queue?: string;
|
|
903
|
+
status?: 'pending' | 'running' | 'resolved' | 'failed';
|
|
721
904
|
}, fetchOptions: Record<string, any>): Promise<any>;
|
|
722
905
|
|
|
723
906
|
/**
|
|
@@ -1152,6 +1335,9 @@ declare class ChatSession {
|
|
|
1152
1335
|
_clearPendingUserBubble(itemId: string): void;
|
|
1153
1336
|
resumePendingRequest(token: number): Promise<void>;
|
|
1154
1337
|
handleHistoryItemResolution(itemId: string, response: any, platform: string): void;
|
|
1338
|
+
/** The file an already-rendered background pass is about, off its request
|
|
1339
|
+
* bubble. Null for an ordinary turn, which is most of them. */
|
|
1340
|
+
private _indexRefOfItem;
|
|
1155
1341
|
applyHistoryItemResolution(itemId: string, response: any, platform: string): void;
|
|
1156
1342
|
/** How a bg task maps onto a collapsed row: the row's own key (storage path
|
|
1157
1343
|
* when known, else the filename), scoped to the chat it belongs to. A storage
|
|
@@ -1183,6 +1369,49 @@ declare class ChatSession {
|
|
|
1183
1369
|
* Runs from drainBgTaskQueue, which both clients call after a history load.
|
|
1184
1370
|
*/
|
|
1185
1371
|
private _sweepCancelledIndexing;
|
|
1372
|
+
/**
|
|
1373
|
+
* True when the WORKER, not this client, drives the rest of this file's chain.
|
|
1374
|
+
* The mirror image of the early returns in maybeResumeIndexing: whatever that
|
|
1375
|
+
* refuses to continue is exactly what nothing client-side is tracking.
|
|
1376
|
+
*/
|
|
1377
|
+
private _isWorkerDrivenIndexing;
|
|
1378
|
+
/**
|
|
1379
|
+
* Pick up indexing passes the WORKER minted, which no client ever dispatched.
|
|
1380
|
+
*
|
|
1381
|
+
* For a PDF (and for text/grid when windowed indexing is on) the worker writes
|
|
1382
|
+
* pass N+1's row itself, inside pass N's invocation, right after saving pass
|
|
1383
|
+
* N's result. That row reaches this client through nothing at all: it is not in
|
|
1384
|
+
* bgTaskQueue (the client never asked for it) and it is not in state.messages
|
|
1385
|
+
* (only a first-page history load maps it in, which happens on mount, project
|
|
1386
|
+
* switch or tab return). So between two worker passes every pass the client
|
|
1387
|
+
* knows about is settled, and the collapsed row renders "Indexed N passes"
|
|
1388
|
+
* with no spinner and no Stop, for a file that is still being read. A user who
|
|
1389
|
+
* believes that then asks questions against a half-indexed file — which is what
|
|
1390
|
+
* this exists to prevent.
|
|
1391
|
+
*
|
|
1392
|
+
* So when a background indexing pass settles, ask the bg queue what is still
|
|
1393
|
+
* unresolved on it and adopt anything unknown as an ordinary BgTaskEntry.
|
|
1394
|
+
* drainBgTaskQueue then treats it exactly like a pass this client dispatched:
|
|
1395
|
+
* same bubble, same `_indexFile` (so it joins the file's collapsed row), same
|
|
1396
|
+
* poll — and that poll settling runs this again, so the chain is followed to
|
|
1397
|
+
* its end. `status`-scoped so the reply carries the live items only, never a
|
|
1398
|
+
* page of finished ones with their bodies.
|
|
1399
|
+
*
|
|
1400
|
+
* Termination: the only trigger is a pass SETTLING, which happens once per
|
|
1401
|
+
* pass. An adopted item that is still running is not re-adopted (its id is
|
|
1402
|
+
* already polled), and when the queue holds nothing unknown the chain stops on
|
|
1403
|
+
* its own. Nothing here is periodic — a timer that re-reads history is the
|
|
1404
|
+
* shape that previously looped fetchHistoryPage after an already-DONE index.
|
|
1405
|
+
*/
|
|
1406
|
+
private _adoptingWorkerPasses;
|
|
1407
|
+
private _adoptWorkerIndexingPasses;
|
|
1408
|
+
/** Any of these ids still queued or still polled, i.e. surviving work. */
|
|
1409
|
+
private _isTrackingAny;
|
|
1410
|
+
/** One live bg-queue item -> a BgTaskEntry, if it is an indexing pass this
|
|
1411
|
+
* client is not already tracking. Returns whether it was adopted. */
|
|
1412
|
+
private _adoptWorkerIndexingItem;
|
|
1413
|
+
/** Follow the chain on from a background indexing pass that just settled. */
|
|
1414
|
+
private _followWorkerIndexingChain;
|
|
1186
1415
|
/** Best-effort server-side cancel of a bg-queue item that has no bubble (so
|
|
1187
1416
|
* cancelQueuedMessage, which drives one, has nothing to act on). */
|
|
1188
1417
|
private _cancelServerItem;
|
|
@@ -1203,4 +1432,4 @@ declare class ChatSession {
|
|
|
1203
1432
|
bumpGate(): void;
|
|
1204
1433
|
}
|
|
1205
1434
|
|
|
1206
|
-
export { type AttachmentFailureGroup, type AttachmentParser, type AttachmentSaveInfo, BG_INDEXING_QUEUE_SUFFIX, type BgTaskEntry, type BoundedChatOptions, type BuildDisplayListOptions, type BuildIndexingUserMessageOptions, CLAUDE_PER_REQUEST_INPUT_CAP, CONTEXT_WINDOW_BY_MODEL, CONTEXT_WINDOW_DEFAULT, type CallClaudeWithMcpParams, type ChatEngineConfig, type ChatHost, type ChatIdentity, type ChatMessage, ChatSession, type ChatState, type ChatSystemPromptParams, type ClaudeMcpServerRequest, type ClaudeMcpToolConfig, type ClaudeMessage, type ClaudeRole, type ComposedUserMessage, DEFAULT_CLAUDE_MODEL, DEFAULT_OPENAI_MODEL, type DisplayEntry, EXPIRED_ATTACHMENT_URL_HOST, EXPIRED_ATTACHMENT_URL_ORIGIN, EXPIRED_LINK_REFRESH_EXPIRES_SECONDS, type ExtractDirective, type FillHistoryViewportOptions, HISTORY_FILL_SLACK_PX, HISTORY_TOKEN_BUDGET, type IndexingAttachmentInfo, type IndexingFileRef, type IndexingGroup, type IndexingGroupStatus, type IndexingSystemPromptParams, type InlineLinkContext, type InlineLinkPart, LINK_LABEL_MAX_DISPLAY_CHARS, LINK_REFRESH_WINDOW_MS, MAX_HISTORY_FILL_PAGES, MAX_HISTORY_MESSAGES, MAX_PARSED_CONTENT_CHARS, MCP_NAME, MIN_INPUT_TOKEN_BUDGET, type MapHistoryOptions, OUTPUT_TOKEN_RESERVE, type OpenAIMessage, POLL_INTERVAL, type PinnedDispatchContext, RENDER_FROM_TOKEN, TOOL_AND_RESPONSE_BUFFER, buildBoundedChatMessages, buildChatDisplayList, buildChatSystemPrompt, buildDisplayExpiredAttachmentHref, buildIndexingContinueMessage, buildIndexingRenderContinueTemplate, buildIndexingRenderMessage, buildIndexingSystemPrompt, buildIndexingUserMessage, buildIndexingWindowMessage, callClaudeWithMcp, callClaudeWithPublicMcp, callOpenAIWithPublicMcp, chatEngineConfig, classifyInlineLink, clearAttachmentParsers, composeUserMessage, configureChatEngine, createHistoryFiller, createInlineLinkRegex, encodePathSegments, estimateMessageTokens, estimateTextTokens, extractClaudeText, extractLastUserTextFromRequest, extractOpenAIText, extractRemotePathFromAttachmentHref, fillHistoryViewport, filterListByClearHorizon, findAttachmentParser, formatChatTimestamp, getAttachmentParsers, getChatHistory, getContextWindow, getErrorMessage, getExpiredAttachmentVisiblePath, groupAttachmentFailures, isAuthExpiredError, isBgIndexingQueue, isErrorResponseBody, isHttpUrlLike, isNonRetryableRequestError, isOfficeFile, isServerExtractable, isServiceDbAttachmentHref, listClaudeModels, listOpenAIModels, makeExtractPlaceholder, mapHistoryListToMessages, normalizeAttachmentPathCandidate, normalizeTextContent, normalizeTrailingInlineToken, notifyAgentSaveAttachment, parseAttachmentContent, parseIndexingLabel, readExpiredAttachmentHref, registerAttachmentParser, repairUrlEntities, repairUrlWhitespace, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay, wallClockNow };
|
|
1435
|
+
export { type AiAgentPlatform, type AttachmentFailureGroup, type AttachmentParser, type AttachmentSaveInfo, BG_INDEXING_QUEUE_SUFFIX, BOM, BOM_EXTS, type BgTaskEntry, type BoundedChatOptions, type BuildDisplayListOptions, type BuildIndexingUserMessageOptions, CLAUDE_INPUT_CAP_RATIO, CLAUDE_PER_REQUEST_INPUT_CAP, CONTEXT_WINDOW_BY_MODEL, CONTEXT_WINDOW_DEFAULT, type CallClaudeWithMcpParams, type ChatEngineConfig, type ChatHost, type ChatIdentity, type ChatMessage, ChatSession, type ChatState, type ChatSystemPromptParams, type ClaudeMcpServerRequest, type ClaudeMcpToolConfig, type ClaudeMessage, type ClaudeRole, type ComposedUserMessage, DEFAULT_CLAUDE_MODEL, DEFAULT_OPENAI_MODEL, type DisplayEntry, EXPIRED_ATTACHMENT_URL_HOST, EXPIRED_ATTACHMENT_URL_ORIGIN, EXPIRED_LINK_REFRESH_EXPIRES_SECONDS, EXT_CONTENT_TYPES, type EncodingClass, type ExtractDirective, type FillHistoryViewportOptions, HISTORY_BUDGET_RATIO, HISTORY_FILL_SLACK_PX, HISTORY_TOKEN_BUDGET, HTML_EXTS, HTML_HEAD_WINDOW, type IndexingAttachmentInfo, type IndexingFileRef, type IndexingGroup, type IndexingGroupStatus, type IndexingRequestRef, type IndexingSystemPromptParams, type InlineLinkContext, type InlineLinkPart, LINK_LABEL_MAX_DISPLAY_CHARS, LINK_REFRESH_WINDOW_MS, MAX_HISTORY_FILL_PAGES, MAX_HISTORY_MESSAGES, MAX_PARSED_CONTENT_CHARS, MCP_NAME, MIN_INPUT_TOKEN_BUDGET, type MapHistoryOptions, OUTPUT_TOKEN_RESERVE, type OpenAIMessage, POLL_INTERVAL, type ParsedAiAgent, type PinnedDispatchContext, RENDER_FROM_TOKEN, RTF_EXTS, TOOL_AND_RESPONSE_BUFFER, XML_EXTS, applyEncodingDeclaration, buildAiAgentValue, buildBoundedChatMessages, buildChatDisplayList, buildChatSystemPrompt, buildDisplayExpiredAttachmentHref, buildIndexingContinueMessage, buildIndexingRenderContinueTemplate, buildIndexingRenderMessage, buildIndexingSystemPrompt, buildIndexingUserMessage, buildIndexingWindowMessage, callClaudeWithMcp, callClaudeWithPublicMcp, callOpenAIWithPublicMcp, chatEngineConfig, classifyInlineLink, clearAttachmentParsers, composeUserMessage, configureChatEngine, contentTypeForExt, createHistoryFiller, createInlineLinkRegex, encodePathSegments, encodingClassForExt, ensureHtmlCharset, ensureXmlEncoding, escapeRtfNonAscii, estimateMessageTokens, estimateTextTokens, extOf, extractClaudeText, extractLastUserTextFromRequest, extractOpenAIText, extractRemotePathFromAttachmentHref, fillHistoryViewport, filterListByClearHorizon, findAttachmentParser, formatChatTimestamp, getAttachmentParsers, getChatHistory, getContextWindow, getErrorMessage, getExpiredAttachmentVisiblePath, getProjectContextWindow, groupAttachmentFailures, hasBom, isAuthExpiredError, isBgIndexingQueue, isErrorResponseBody, isHttpUrlLike, isIndexingRequestText, isNonRetryableRequestError, isOfficeFile, isServerExtractable, isServiceDbAttachmentHref, listClaudeModels, listOpenAIModels, looksLikeRtf, makeExtractPlaceholder, mapHistoryListToMessages, needsBomForExt, normalizeAttachmentPathCandidate, normalizeExt, normalizeTextContent, normalizeTrailingInlineToken, notifyAgentSaveAttachment, parseAiAgentValue, parseAttachmentContent, parseIndexingLabel, parseIndexingRequestText, prepareDownloadText, readExpiredAttachmentHref, registerAttachmentParser, registerModelContextWindows, repairUrlEntities, repairUrlWhitespace, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, setProjectContextWindow, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay, wallClockNow };
|