bunnyquery 1.5.7 → 1.6.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 +522 -65
- package/dist/engine.cjs +516 -63
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.mts +160 -5
- package/dist/engine.d.ts +160 -5
- package/dist/engine.mjs +511 -64
- package/dist/engine.mjs.map +1 -1
- package/package.json +1 -1
- package/src/engine/config.ts +19 -0
- package/src/engine/host.ts +19 -0
- package/src/engine/index.ts +2 -1
- package/src/engine/office.ts +78 -5
- package/src/engine/prompts/index.ts +5 -0
- package/src/engine/prompts/indexing_system_prompt.ts +5 -3
- package/src/engine/prompts/indexing_user_message.ts +159 -0
- package/src/engine/requests.ts +170 -25
- package/src/engine/session.ts +402 -42
package/dist/engine.d.mts
CHANGED
|
@@ -81,6 +81,20 @@ interface ChatEngineConfig {
|
|
|
81
81
|
* `registerAttachmentParser()`. See attachment_parsers.ts.
|
|
82
82
|
*/
|
|
83
83
|
attachmentParsers?: AttachmentParser[];
|
|
84
|
+
/**
|
|
85
|
+
* Opt in to SERVER-DRIVEN windowed indexing for text/grid files.
|
|
86
|
+
*
|
|
87
|
+
* Off by default, and deliberately so. When on, the client emits a
|
|
88
|
+
* `_skapi_window` directive and the WORKER reads the file one window at a time,
|
|
89
|
+
* continuing until the reader says it is exhausted. When off, the agent pages the
|
|
90
|
+
* file itself with readFileContent, exactly as before.
|
|
91
|
+
*
|
|
92
|
+
* The flag exists because the backend must ship FIRST: a client emitting the
|
|
93
|
+
* directive against a worker that does not strip it leaves an unknown field in the
|
|
94
|
+
* request body, and the provider rejects the whole call with no retry. Keep it off
|
|
95
|
+
* until the worker is deployed, then flip it per environment.
|
|
96
|
+
*/
|
|
97
|
+
windowedIndexing?: boolean;
|
|
84
98
|
}
|
|
85
99
|
declare function configureChatEngine(config: ChatEngineConfig): void;
|
|
86
100
|
declare function chatEngineConfig(): ChatEngineConfig;
|
|
@@ -241,6 +255,51 @@ type BuildIndexingUserMessageOptions = {
|
|
|
241
255
|
pagedRead?: boolean;
|
|
242
256
|
};
|
|
243
257
|
declare function buildIndexingUserMessage(attachment: IndexingAttachmentInfo, options?: BuildIndexingUserMessageOptions): string;
|
|
258
|
+
/**
|
|
259
|
+
* Token the WORKER substitutes with the 1-based first page of the window it is about to
|
|
260
|
+
* render, when it builds the next pass of a document from `RENDER_CONTINUE_TEMPLATE`.
|
|
261
|
+
* Must match the worker's RENDER_FROM_TOKEN.
|
|
262
|
+
*/
|
|
263
|
+
declare const RENDER_FROM_TOKEN = "{{RENDER_FROM}}";
|
|
264
|
+
/**
|
|
265
|
+
* User message for a VISION file (PDF): its pages are delivered as RENDERED PAGE IMAGES that
|
|
266
|
+
* the proxy worker injects into THIS message at the `placeholder` token (tool-result images
|
|
267
|
+
* render on neither provider, so the pages must be image blocks in the message itself). Each
|
|
268
|
+
* pass shows one WINDOW of pages starting at `renderFrom` (0-based).
|
|
269
|
+
*
|
|
270
|
+
* The WORKER advances the window: when its renderer reports pages remaining it enqueues the
|
|
271
|
+
* next pass itself, off the true page count, so a document indexes end-to-end with no browser
|
|
272
|
+
* involved. This message therefore only ever describes ONE window, and the model is never
|
|
273
|
+
* asked to decide whether the document is finished.
|
|
274
|
+
*
|
|
275
|
+
* renderFrom === 0 is the FIRST pass (leads with "A new file has just been uploaded." so the
|
|
276
|
+
* client builds the "Indexing: <name>" bubble); a continue pass (built by the worker from
|
|
277
|
+
* buildIndexingRenderContinueTemplate) leads with "CONTINUE indexing" so it is not a duplicate
|
|
278
|
+
* primary bubble.
|
|
279
|
+
*/
|
|
280
|
+
declare function buildIndexingRenderMessage(attachment: IndexingAttachmentInfo, placeholder: string, renderFrom: number): string;
|
|
281
|
+
/**
|
|
282
|
+
* The CONTINUE pass, as a template the worker fills in. `pageLabel` defaults to the
|
|
283
|
+
* RENDER_FROM_TOKEN placeholder, which the worker replaces with the real 1-based start page
|
|
284
|
+
* of the window it is rendering; passing an explicit label produces a ready-to-send message.
|
|
285
|
+
*/
|
|
286
|
+
declare function buildIndexingRenderContinueTemplate(attachment: IndexingAttachmentInfo, placeholder: string, pageLabel?: string): string;
|
|
287
|
+
/**
|
|
288
|
+
* User message for a WINDOWED file: the worker splices ONE window of the file's rows or
|
|
289
|
+
* text into this message at `placeholder`, then continues from the reader's own cursor
|
|
290
|
+
* until the file is exhausted.
|
|
291
|
+
*
|
|
292
|
+
* The agent is deliberately NOT asked to page the file itself, and is NOT asked to judge
|
|
293
|
+
* whether it is finished. Both used to be its job, and both failed the same way: the
|
|
294
|
+
* traversal lived inside a single turn's budget, so a large file simply stopped partway
|
|
295
|
+
* with a confident summary of the part it had seen.
|
|
296
|
+
*/
|
|
297
|
+
declare function buildIndexingWindowMessage(attachment: IndexingAttachmentInfo, placeholder: string, isContinuation: boolean, positionLabel?: string): string;
|
|
298
|
+
/**
|
|
299
|
+
* User message for a RESUME pass: a previous indexing pass could not finish this large
|
|
300
|
+
* file, so continue it from where the already-saved records leave off (never restart).
|
|
301
|
+
*/
|
|
302
|
+
declare function buildIndexingContinueMessage(attachment: IndexingAttachmentInfo): string;
|
|
244
303
|
|
|
245
304
|
/**
|
|
246
305
|
* Error detection + message extraction (pure). Moved verbatim from the
|
|
@@ -387,6 +446,18 @@ type AttachmentSaveInfo = {
|
|
|
387
446
|
* takes precedence over server-side office extraction / web_fetch.
|
|
388
447
|
*/
|
|
389
448
|
parsedContent?: string;
|
|
449
|
+
/**
|
|
450
|
+
* True for a RESUME pass: a previous indexing pass could not finish this (large)
|
|
451
|
+
* file, so continue it - always via readFileContent paging, with a "continue"
|
|
452
|
+
* message telling the agent to resume from where the saved records leave off.
|
|
453
|
+
*/
|
|
454
|
+
continueIndexing?: boolean;
|
|
455
|
+
/**
|
|
456
|
+
* For an image-vision file (PDF), the 0-based PAGE the render window should start at.
|
|
457
|
+
* The worker renders [renderFrom, renderFrom+RENDER_PAGES_PER_WINDOW) and injects them
|
|
458
|
+
* as image blocks; the resume loop advances this by a window each pass.
|
|
459
|
+
*/
|
|
460
|
+
renderFrom?: number;
|
|
390
461
|
};
|
|
391
462
|
declare function notifyAgentSaveAttachment(info: AttachmentSaveInfo): Promise<any>;
|
|
392
463
|
declare function extractClaudeText(response: any): any;
|
|
@@ -394,6 +465,16 @@ declare function extractOpenAIText(response: any): any;
|
|
|
394
465
|
declare function listClaudeModels(service: string, owner: string): Promise<any>;
|
|
395
466
|
declare function listOpenAIModels(service: string, owner: string): Promise<any>;
|
|
396
467
|
declare const BG_INDEXING_QUEUE_SUFFIX = "-bg";
|
|
468
|
+
/**
|
|
469
|
+
* True when a request belongs to the background-indexing queue.
|
|
470
|
+
*
|
|
471
|
+
* Accepts BOTH shapes this value arrives in: the bare queue name the client sends
|
|
472
|
+
* ("<userId>-bg"), and the server qid that comes back on history/poll responses
|
|
473
|
+
* ("<service>:<queue>|<seq>"). Testing the tail of the raw value only works for the
|
|
474
|
+
* first: a qid ends in "|<seq>", so `endsWith('-bg')` is always false for it — which
|
|
475
|
+
* silently meant history items were NEVER recognised as background tasks.
|
|
476
|
+
*/
|
|
477
|
+
declare function isBgIndexingQueue(queueName?: string): boolean;
|
|
397
478
|
type BgTaskEntry = {
|
|
398
479
|
serviceId: string;
|
|
399
480
|
platform: 'claude' | 'openai';
|
|
@@ -407,6 +488,8 @@ type BgTaskEntry = {
|
|
|
407
488
|
poll: ((opts: {
|
|
408
489
|
latency: number;
|
|
409
490
|
}) => Promise<any>) | undefined;
|
|
491
|
+
/** How many CONTINUE passes have already run for this file (resume-across-passes). */
|
|
492
|
+
resumePass?: number;
|
|
410
493
|
};
|
|
411
494
|
declare function getChatHistory(params: {
|
|
412
495
|
service?: string;
|
|
@@ -433,6 +516,17 @@ interface ChatIdentity {
|
|
|
433
516
|
serviceName?: string;
|
|
434
517
|
serviceDescription?: string;
|
|
435
518
|
}
|
|
519
|
+
/**
|
|
520
|
+
* Project context captured at the moment the user hit Send, so a turn whose
|
|
521
|
+
* dispatch is delayed (attachment uploads are awaited first) still reaches the
|
|
522
|
+
* project the question was asked of rather than whichever project the user has
|
|
523
|
+
* navigated to by then. Both fields are identity-derived and must be snapshotted
|
|
524
|
+
* together — the system prompt embeds the service name/description/id.
|
|
525
|
+
*/
|
|
526
|
+
interface PinnedDispatchContext {
|
|
527
|
+
identity: ChatIdentity;
|
|
528
|
+
systemPrompt: string;
|
|
529
|
+
}
|
|
436
530
|
interface ChatMessage {
|
|
437
531
|
role: 'user' | 'assistant';
|
|
438
532
|
content: string;
|
|
@@ -449,6 +543,7 @@ interface ChatMessage {
|
|
|
449
543
|
_localId?: string;
|
|
450
544
|
_cancelling?: boolean;
|
|
451
545
|
_cancelError?: string;
|
|
546
|
+
_ownerKey?: string;
|
|
452
547
|
}
|
|
453
548
|
interface ChatState {
|
|
454
549
|
messages: ChatMessage[];
|
|
@@ -545,6 +640,13 @@ interface ChatHost {
|
|
|
545
640
|
* session via the public methods and re-renders in host.notify().
|
|
546
641
|
*/
|
|
547
642
|
|
|
643
|
+
/** A live poll registered in ChatSession.historyItemPolls. */
|
|
644
|
+
type PollHandle = {
|
|
645
|
+
/** 'bg' = background indexing, pausable. 'fg' = a reply the user is waiting on. */
|
|
646
|
+
kind: 'fg' | 'bg';
|
|
647
|
+
/** Absent on an older skapi-js that cannot stop an attached poll. */
|
|
648
|
+
stop?: () => void;
|
|
649
|
+
};
|
|
548
650
|
declare class ChatSession {
|
|
549
651
|
host: ChatHost;
|
|
550
652
|
state: ChatState;
|
|
@@ -556,21 +658,73 @@ declare class ChatSession {
|
|
|
556
658
|
endOfList: boolean;
|
|
557
659
|
startKeyHistory: string[];
|
|
558
660
|
}>;
|
|
559
|
-
historyItemPolls: Map<string,
|
|
661
|
+
historyItemPolls: Map<string, PollHandle>;
|
|
662
|
+
/** Non-empty while polling is paused; keyed by reason so overlapping causes
|
|
663
|
+
* (view detached AND tab hidden) do not resume each other prematurely. */
|
|
664
|
+
private _pauseReasons;
|
|
665
|
+
private _resuming;
|
|
560
666
|
private _lidSeq;
|
|
561
667
|
constructor(host: ChatHost);
|
|
668
|
+
/**
|
|
669
|
+
* Register a live poll so (a) a remount dedupes against it instead of stacking a
|
|
670
|
+
* SECOND poll on the same item, and (b) pausePolling can stop it.
|
|
671
|
+
*
|
|
672
|
+
* `stop` comes from the SDK and may be absent on an older skapi-js, in which case the
|
|
673
|
+
* poll simply cannot be stopped and is left running — see pausePolling.
|
|
674
|
+
*/
|
|
675
|
+
private _trackPoll;
|
|
676
|
+
/** True while any pause reason is active. */
|
|
677
|
+
isPollingPaused(): boolean;
|
|
678
|
+
/**
|
|
679
|
+
* Stop BACKGROUND polling until resumePolling. Foreground polls (a reply the user is
|
|
680
|
+
* waiting on) keep running deliberately: their results must still land in the history
|
|
681
|
+
* cache so resumePendingRequest can render them on return, otherwise a user who sends
|
|
682
|
+
* a message then navigates away comes back to a permanently stuck "Thinking...".
|
|
683
|
+
*
|
|
684
|
+
* Server-side work is untouched; this only stops asking about it. That is safe for
|
|
685
|
+
* document indexing because the worker drives that loop itself.
|
|
686
|
+
*/
|
|
687
|
+
pausePolling(reason: string): void;
|
|
688
|
+
/**
|
|
689
|
+
* Lift a pause reason WITHOUT running the reconcile. For a caller that is about to
|
|
690
|
+
* reload history anyway (a view remounting), letting resumePolling also reconcile
|
|
691
|
+
* would race that load and can double-attach.
|
|
692
|
+
*/
|
|
693
|
+
clearPauseReason(reason: string): void;
|
|
694
|
+
/**
|
|
695
|
+
* Clear a pause reason and, once none remain, re-attach polling and reconcile.
|
|
696
|
+
* Deliberately does NOT touch gateRefreshToken: bumping it would silently discard
|
|
697
|
+
* the results of anything still in flight across the pause.
|
|
698
|
+
*/
|
|
699
|
+
resumePolling(reason: string): Promise<void>;
|
|
562
700
|
private _newLocalId;
|
|
563
701
|
getHistoryCacheKey(): string;
|
|
564
702
|
updateHistoryCache(): void;
|
|
703
|
+
/**
|
|
704
|
+
* Land a resolved reply in the history cache of a chat that is NOT currently
|
|
705
|
+
* visible, without touching state.messages. Mirrors the cache-only path in
|
|
706
|
+
* dispatchAgentRequest: REPLACE the trailing pending "Thinking..." bubble
|
|
707
|
+
* (append only when there is none), and settle the matching pending user
|
|
708
|
+
* bubble, so the cached copy never keeps a stuck "Thinking..." that a later
|
|
709
|
+
* cache-first load would re-render forever.
|
|
710
|
+
*/
|
|
711
|
+
private _applyReplyToCache;
|
|
712
|
+
/**
|
|
713
|
+
* serviceId/owner are passed explicitly by every caller: a request can be
|
|
714
|
+
* dispatched after the user moved to another project, and re-reading the live
|
|
715
|
+
* identity here would silently send the turn to THAT project instead of the
|
|
716
|
+
* one it was composed for. Falls back to the live read only when a caller
|
|
717
|
+
* omits them.
|
|
718
|
+
*/
|
|
565
719
|
private _callProviderFor;
|
|
566
720
|
dispatchAgentRequest(params: any): Promise<any>;
|
|
567
|
-
dispatchComposedMessage(composed: string, useBgQueue?: boolean, composedForLlm?: string, extractContent?: any, fileUrls?: any): void;
|
|
721
|
+
dispatchComposedMessage(composed: string, useBgQueue?: boolean, composedForLlm?: string, extractContent?: any, fileUrls?: any, pinned?: PinnedDispatchContext): void;
|
|
568
722
|
promoteNextBgQueuedToRunning(): void;
|
|
569
723
|
promoteNextQueuedToRunning(): void;
|
|
570
724
|
resolveQueuedUserBubble(serverId?: string): number | undefined;
|
|
571
725
|
insertAtTarget(msg: ChatMessage, targetIdx: number): void;
|
|
572
|
-
onQueuedSendResponse(_composed: string, response: any, platform: string, serverId?: string): void;
|
|
573
|
-
onQueuedSendError(_composed: string, err: any, serverId?: string): void;
|
|
726
|
+
onQueuedSendResponse(_composed: string, response: any, platform: string, serverId?: string, ownerKey?: string): void;
|
|
727
|
+
onQueuedSendError(_composed: string, err: any, serverId?: string, ownerKey?: string): void;
|
|
574
728
|
cancelQueuedMessage(msg: ChatMessage, idx: number): void;
|
|
575
729
|
typewriteIntoIndex(idx: number, fullText: string, localId?: string): Promise<void>;
|
|
576
730
|
private typewriterQueue;
|
|
@@ -582,6 +736,7 @@ declare class ChatSession {
|
|
|
582
736
|
handleHistoryItemResolution(itemId: string, response: any, platform: string): void;
|
|
583
737
|
applyHistoryItemResolution(itemId: string, response: any, platform: string): void;
|
|
584
738
|
drainBgTaskQueue(): void;
|
|
739
|
+
maybeResumeIndexing(entry: BgTaskEntry, response: any, platform: string): void;
|
|
585
740
|
loadHistory(fetchMore?: boolean, token?: number): Promise<void>;
|
|
586
741
|
uploadSingleAttachment(att: any): Promise<Array<{
|
|
587
742
|
name: string;
|
|
@@ -597,4 +752,4 @@ declare class ChatSession {
|
|
|
597
752
|
bumpGate(): void;
|
|
598
753
|
}
|
|
599
754
|
|
|
600
|
-
export { type AttachmentFailureGroup, type AttachmentParser, type AttachmentSaveInfo, BG_INDEXING_QUEUE_SUFFIX, type BgTaskEntry, type BoundedChatOptions, 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, EXPIRED_ATTACHMENT_URL_HOST, EXPIRED_ATTACHMENT_URL_ORIGIN, type ExtractDirective, HISTORY_TOKEN_BUDGET, type IndexingAttachmentInfo, type IndexingSystemPromptParams, LINK_LABEL_MAX_DISPLAY_CHARS, MAX_HISTORY_MESSAGES, MAX_PARSED_CONTENT_CHARS, MCP_NAME, MIN_INPUT_TOKEN_BUDGET, type MapHistoryOptions, OUTPUT_TOKEN_RESERVE, type OpenAIMessage, POLL_INTERVAL, TOOL_AND_RESPONSE_BUFFER, buildBoundedChatMessages, buildChatSystemPrompt, buildDisplayExpiredAttachmentHref, buildIndexingSystemPrompt, buildIndexingUserMessage, callClaudeWithMcp, callClaudeWithPublicMcp, callOpenAIWithPublicMcp, chatEngineConfig, clearAttachmentParsers, composeUserMessage, configureChatEngine, createInlineLinkRegex, encodePathSegments, estimateMessageTokens, estimateTextTokens, extractClaudeText, extractLastUserTextFromRequest, extractOpenAIText, extractRemotePathFromAttachmentHref, filterListByClearHorizon, findAttachmentParser, getAttachmentParsers, getChatHistory, getContextWindow, getErrorMessage, getExpiredAttachmentVisiblePath, groupAttachmentFailures, isAuthExpiredError, isErrorResponseBody, isNonRetryableRequestError, isOfficeFile, isServerExtractable, isServiceDbAttachmentHref, listClaudeModels, listOpenAIModels, makeExtractPlaceholder, mapHistoryListToMessages, normalizeAttachmentPathCandidate, normalizeTextContent, notifyAgentSaveAttachment, parseAttachmentContent, registerAttachmentParser, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay };
|
|
755
|
+
export { type AttachmentFailureGroup, type AttachmentParser, type AttachmentSaveInfo, BG_INDEXING_QUEUE_SUFFIX, type BgTaskEntry, type BoundedChatOptions, 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, EXPIRED_ATTACHMENT_URL_HOST, EXPIRED_ATTACHMENT_URL_ORIGIN, type ExtractDirective, HISTORY_TOKEN_BUDGET, type IndexingAttachmentInfo, type IndexingSystemPromptParams, LINK_LABEL_MAX_DISPLAY_CHARS, 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, buildChatSystemPrompt, buildDisplayExpiredAttachmentHref, buildIndexingContinueMessage, buildIndexingRenderContinueTemplate, buildIndexingRenderMessage, buildIndexingSystemPrompt, buildIndexingUserMessage, buildIndexingWindowMessage, callClaudeWithMcp, callClaudeWithPublicMcp, callOpenAIWithPublicMcp, chatEngineConfig, clearAttachmentParsers, composeUserMessage, configureChatEngine, createInlineLinkRegex, encodePathSegments, estimateMessageTokens, estimateTextTokens, extractClaudeText, extractLastUserTextFromRequest, extractOpenAIText, extractRemotePathFromAttachmentHref, filterListByClearHorizon, findAttachmentParser, getAttachmentParsers, getChatHistory, getContextWindow, getErrorMessage, getExpiredAttachmentVisiblePath, groupAttachmentFailures, isAuthExpiredError, isBgIndexingQueue, isErrorResponseBody, isNonRetryableRequestError, isOfficeFile, isServerExtractable, isServiceDbAttachmentHref, listClaudeModels, listOpenAIModels, makeExtractPlaceholder, mapHistoryListToMessages, normalizeAttachmentPathCandidate, normalizeTextContent, notifyAgentSaveAttachment, parseAttachmentContent, registerAttachmentParser, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay };
|
package/dist/engine.d.ts
CHANGED
|
@@ -81,6 +81,20 @@ interface ChatEngineConfig {
|
|
|
81
81
|
* `registerAttachmentParser()`. See attachment_parsers.ts.
|
|
82
82
|
*/
|
|
83
83
|
attachmentParsers?: AttachmentParser[];
|
|
84
|
+
/**
|
|
85
|
+
* Opt in to SERVER-DRIVEN windowed indexing for text/grid files.
|
|
86
|
+
*
|
|
87
|
+
* Off by default, and deliberately so. When on, the client emits a
|
|
88
|
+
* `_skapi_window` directive and the WORKER reads the file one window at a time,
|
|
89
|
+
* continuing until the reader says it is exhausted. When off, the agent pages the
|
|
90
|
+
* file itself with readFileContent, exactly as before.
|
|
91
|
+
*
|
|
92
|
+
* The flag exists because the backend must ship FIRST: a client emitting the
|
|
93
|
+
* directive against a worker that does not strip it leaves an unknown field in the
|
|
94
|
+
* request body, and the provider rejects the whole call with no retry. Keep it off
|
|
95
|
+
* until the worker is deployed, then flip it per environment.
|
|
96
|
+
*/
|
|
97
|
+
windowedIndexing?: boolean;
|
|
84
98
|
}
|
|
85
99
|
declare function configureChatEngine(config: ChatEngineConfig): void;
|
|
86
100
|
declare function chatEngineConfig(): ChatEngineConfig;
|
|
@@ -241,6 +255,51 @@ type BuildIndexingUserMessageOptions = {
|
|
|
241
255
|
pagedRead?: boolean;
|
|
242
256
|
};
|
|
243
257
|
declare function buildIndexingUserMessage(attachment: IndexingAttachmentInfo, options?: BuildIndexingUserMessageOptions): string;
|
|
258
|
+
/**
|
|
259
|
+
* Token the WORKER substitutes with the 1-based first page of the window it is about to
|
|
260
|
+
* render, when it builds the next pass of a document from `RENDER_CONTINUE_TEMPLATE`.
|
|
261
|
+
* Must match the worker's RENDER_FROM_TOKEN.
|
|
262
|
+
*/
|
|
263
|
+
declare const RENDER_FROM_TOKEN = "{{RENDER_FROM}}";
|
|
264
|
+
/**
|
|
265
|
+
* User message for a VISION file (PDF): its pages are delivered as RENDERED PAGE IMAGES that
|
|
266
|
+
* the proxy worker injects into THIS message at the `placeholder` token (tool-result images
|
|
267
|
+
* render on neither provider, so the pages must be image blocks in the message itself). Each
|
|
268
|
+
* pass shows one WINDOW of pages starting at `renderFrom` (0-based).
|
|
269
|
+
*
|
|
270
|
+
* The WORKER advances the window: when its renderer reports pages remaining it enqueues the
|
|
271
|
+
* next pass itself, off the true page count, so a document indexes end-to-end with no browser
|
|
272
|
+
* involved. This message therefore only ever describes ONE window, and the model is never
|
|
273
|
+
* asked to decide whether the document is finished.
|
|
274
|
+
*
|
|
275
|
+
* renderFrom === 0 is the FIRST pass (leads with "A new file has just been uploaded." so the
|
|
276
|
+
* client builds the "Indexing: <name>" bubble); a continue pass (built by the worker from
|
|
277
|
+
* buildIndexingRenderContinueTemplate) leads with "CONTINUE indexing" so it is not a duplicate
|
|
278
|
+
* primary bubble.
|
|
279
|
+
*/
|
|
280
|
+
declare function buildIndexingRenderMessage(attachment: IndexingAttachmentInfo, placeholder: string, renderFrom: number): string;
|
|
281
|
+
/**
|
|
282
|
+
* The CONTINUE pass, as a template the worker fills in. `pageLabel` defaults to the
|
|
283
|
+
* RENDER_FROM_TOKEN placeholder, which the worker replaces with the real 1-based start page
|
|
284
|
+
* of the window it is rendering; passing an explicit label produces a ready-to-send message.
|
|
285
|
+
*/
|
|
286
|
+
declare function buildIndexingRenderContinueTemplate(attachment: IndexingAttachmentInfo, placeholder: string, pageLabel?: string): string;
|
|
287
|
+
/**
|
|
288
|
+
* User message for a WINDOWED file: the worker splices ONE window of the file's rows or
|
|
289
|
+
* text into this message at `placeholder`, then continues from the reader's own cursor
|
|
290
|
+
* until the file is exhausted.
|
|
291
|
+
*
|
|
292
|
+
* The agent is deliberately NOT asked to page the file itself, and is NOT asked to judge
|
|
293
|
+
* whether it is finished. Both used to be its job, and both failed the same way: the
|
|
294
|
+
* traversal lived inside a single turn's budget, so a large file simply stopped partway
|
|
295
|
+
* with a confident summary of the part it had seen.
|
|
296
|
+
*/
|
|
297
|
+
declare function buildIndexingWindowMessage(attachment: IndexingAttachmentInfo, placeholder: string, isContinuation: boolean, positionLabel?: string): string;
|
|
298
|
+
/**
|
|
299
|
+
* User message for a RESUME pass: a previous indexing pass could not finish this large
|
|
300
|
+
* file, so continue it from where the already-saved records leave off (never restart).
|
|
301
|
+
*/
|
|
302
|
+
declare function buildIndexingContinueMessage(attachment: IndexingAttachmentInfo): string;
|
|
244
303
|
|
|
245
304
|
/**
|
|
246
305
|
* Error detection + message extraction (pure). Moved verbatim from the
|
|
@@ -387,6 +446,18 @@ type AttachmentSaveInfo = {
|
|
|
387
446
|
* takes precedence over server-side office extraction / web_fetch.
|
|
388
447
|
*/
|
|
389
448
|
parsedContent?: string;
|
|
449
|
+
/**
|
|
450
|
+
* True for a RESUME pass: a previous indexing pass could not finish this (large)
|
|
451
|
+
* file, so continue it - always via readFileContent paging, with a "continue"
|
|
452
|
+
* message telling the agent to resume from where the saved records leave off.
|
|
453
|
+
*/
|
|
454
|
+
continueIndexing?: boolean;
|
|
455
|
+
/**
|
|
456
|
+
* For an image-vision file (PDF), the 0-based PAGE the render window should start at.
|
|
457
|
+
* The worker renders [renderFrom, renderFrom+RENDER_PAGES_PER_WINDOW) and injects them
|
|
458
|
+
* as image blocks; the resume loop advances this by a window each pass.
|
|
459
|
+
*/
|
|
460
|
+
renderFrom?: number;
|
|
390
461
|
};
|
|
391
462
|
declare function notifyAgentSaveAttachment(info: AttachmentSaveInfo): Promise<any>;
|
|
392
463
|
declare function extractClaudeText(response: any): any;
|
|
@@ -394,6 +465,16 @@ declare function extractOpenAIText(response: any): any;
|
|
|
394
465
|
declare function listClaudeModels(service: string, owner: string): Promise<any>;
|
|
395
466
|
declare function listOpenAIModels(service: string, owner: string): Promise<any>;
|
|
396
467
|
declare const BG_INDEXING_QUEUE_SUFFIX = "-bg";
|
|
468
|
+
/**
|
|
469
|
+
* True when a request belongs to the background-indexing queue.
|
|
470
|
+
*
|
|
471
|
+
* Accepts BOTH shapes this value arrives in: the bare queue name the client sends
|
|
472
|
+
* ("<userId>-bg"), and the server qid that comes back on history/poll responses
|
|
473
|
+
* ("<service>:<queue>|<seq>"). Testing the tail of the raw value only works for the
|
|
474
|
+
* first: a qid ends in "|<seq>", so `endsWith('-bg')` is always false for it — which
|
|
475
|
+
* silently meant history items were NEVER recognised as background tasks.
|
|
476
|
+
*/
|
|
477
|
+
declare function isBgIndexingQueue(queueName?: string): boolean;
|
|
397
478
|
type BgTaskEntry = {
|
|
398
479
|
serviceId: string;
|
|
399
480
|
platform: 'claude' | 'openai';
|
|
@@ -407,6 +488,8 @@ type BgTaskEntry = {
|
|
|
407
488
|
poll: ((opts: {
|
|
408
489
|
latency: number;
|
|
409
490
|
}) => Promise<any>) | undefined;
|
|
491
|
+
/** How many CONTINUE passes have already run for this file (resume-across-passes). */
|
|
492
|
+
resumePass?: number;
|
|
410
493
|
};
|
|
411
494
|
declare function getChatHistory(params: {
|
|
412
495
|
service?: string;
|
|
@@ -433,6 +516,17 @@ interface ChatIdentity {
|
|
|
433
516
|
serviceName?: string;
|
|
434
517
|
serviceDescription?: string;
|
|
435
518
|
}
|
|
519
|
+
/**
|
|
520
|
+
* Project context captured at the moment the user hit Send, so a turn whose
|
|
521
|
+
* dispatch is delayed (attachment uploads are awaited first) still reaches the
|
|
522
|
+
* project the question was asked of rather than whichever project the user has
|
|
523
|
+
* navigated to by then. Both fields are identity-derived and must be snapshotted
|
|
524
|
+
* together — the system prompt embeds the service name/description/id.
|
|
525
|
+
*/
|
|
526
|
+
interface PinnedDispatchContext {
|
|
527
|
+
identity: ChatIdentity;
|
|
528
|
+
systemPrompt: string;
|
|
529
|
+
}
|
|
436
530
|
interface ChatMessage {
|
|
437
531
|
role: 'user' | 'assistant';
|
|
438
532
|
content: string;
|
|
@@ -449,6 +543,7 @@ interface ChatMessage {
|
|
|
449
543
|
_localId?: string;
|
|
450
544
|
_cancelling?: boolean;
|
|
451
545
|
_cancelError?: string;
|
|
546
|
+
_ownerKey?: string;
|
|
452
547
|
}
|
|
453
548
|
interface ChatState {
|
|
454
549
|
messages: ChatMessage[];
|
|
@@ -545,6 +640,13 @@ interface ChatHost {
|
|
|
545
640
|
* session via the public methods and re-renders in host.notify().
|
|
546
641
|
*/
|
|
547
642
|
|
|
643
|
+
/** A live poll registered in ChatSession.historyItemPolls. */
|
|
644
|
+
type PollHandle = {
|
|
645
|
+
/** 'bg' = background indexing, pausable. 'fg' = a reply the user is waiting on. */
|
|
646
|
+
kind: 'fg' | 'bg';
|
|
647
|
+
/** Absent on an older skapi-js that cannot stop an attached poll. */
|
|
648
|
+
stop?: () => void;
|
|
649
|
+
};
|
|
548
650
|
declare class ChatSession {
|
|
549
651
|
host: ChatHost;
|
|
550
652
|
state: ChatState;
|
|
@@ -556,21 +658,73 @@ declare class ChatSession {
|
|
|
556
658
|
endOfList: boolean;
|
|
557
659
|
startKeyHistory: string[];
|
|
558
660
|
}>;
|
|
559
|
-
historyItemPolls: Map<string,
|
|
661
|
+
historyItemPolls: Map<string, PollHandle>;
|
|
662
|
+
/** Non-empty while polling is paused; keyed by reason so overlapping causes
|
|
663
|
+
* (view detached AND tab hidden) do not resume each other prematurely. */
|
|
664
|
+
private _pauseReasons;
|
|
665
|
+
private _resuming;
|
|
560
666
|
private _lidSeq;
|
|
561
667
|
constructor(host: ChatHost);
|
|
668
|
+
/**
|
|
669
|
+
* Register a live poll so (a) a remount dedupes against it instead of stacking a
|
|
670
|
+
* SECOND poll on the same item, and (b) pausePolling can stop it.
|
|
671
|
+
*
|
|
672
|
+
* `stop` comes from the SDK and may be absent on an older skapi-js, in which case the
|
|
673
|
+
* poll simply cannot be stopped and is left running — see pausePolling.
|
|
674
|
+
*/
|
|
675
|
+
private _trackPoll;
|
|
676
|
+
/** True while any pause reason is active. */
|
|
677
|
+
isPollingPaused(): boolean;
|
|
678
|
+
/**
|
|
679
|
+
* Stop BACKGROUND polling until resumePolling. Foreground polls (a reply the user is
|
|
680
|
+
* waiting on) keep running deliberately: their results must still land in the history
|
|
681
|
+
* cache so resumePendingRequest can render them on return, otherwise a user who sends
|
|
682
|
+
* a message then navigates away comes back to a permanently stuck "Thinking...".
|
|
683
|
+
*
|
|
684
|
+
* Server-side work is untouched; this only stops asking about it. That is safe for
|
|
685
|
+
* document indexing because the worker drives that loop itself.
|
|
686
|
+
*/
|
|
687
|
+
pausePolling(reason: string): void;
|
|
688
|
+
/**
|
|
689
|
+
* Lift a pause reason WITHOUT running the reconcile. For a caller that is about to
|
|
690
|
+
* reload history anyway (a view remounting), letting resumePolling also reconcile
|
|
691
|
+
* would race that load and can double-attach.
|
|
692
|
+
*/
|
|
693
|
+
clearPauseReason(reason: string): void;
|
|
694
|
+
/**
|
|
695
|
+
* Clear a pause reason and, once none remain, re-attach polling and reconcile.
|
|
696
|
+
* Deliberately does NOT touch gateRefreshToken: bumping it would silently discard
|
|
697
|
+
* the results of anything still in flight across the pause.
|
|
698
|
+
*/
|
|
699
|
+
resumePolling(reason: string): Promise<void>;
|
|
562
700
|
private _newLocalId;
|
|
563
701
|
getHistoryCacheKey(): string;
|
|
564
702
|
updateHistoryCache(): void;
|
|
703
|
+
/**
|
|
704
|
+
* Land a resolved reply in the history cache of a chat that is NOT currently
|
|
705
|
+
* visible, without touching state.messages. Mirrors the cache-only path in
|
|
706
|
+
* dispatchAgentRequest: REPLACE the trailing pending "Thinking..." bubble
|
|
707
|
+
* (append only when there is none), and settle the matching pending user
|
|
708
|
+
* bubble, so the cached copy never keeps a stuck "Thinking..." that a later
|
|
709
|
+
* cache-first load would re-render forever.
|
|
710
|
+
*/
|
|
711
|
+
private _applyReplyToCache;
|
|
712
|
+
/**
|
|
713
|
+
* serviceId/owner are passed explicitly by every caller: a request can be
|
|
714
|
+
* dispatched after the user moved to another project, and re-reading the live
|
|
715
|
+
* identity here would silently send the turn to THAT project instead of the
|
|
716
|
+
* one it was composed for. Falls back to the live read only when a caller
|
|
717
|
+
* omits them.
|
|
718
|
+
*/
|
|
565
719
|
private _callProviderFor;
|
|
566
720
|
dispatchAgentRequest(params: any): Promise<any>;
|
|
567
|
-
dispatchComposedMessage(composed: string, useBgQueue?: boolean, composedForLlm?: string, extractContent?: any, fileUrls?: any): void;
|
|
721
|
+
dispatchComposedMessage(composed: string, useBgQueue?: boolean, composedForLlm?: string, extractContent?: any, fileUrls?: any, pinned?: PinnedDispatchContext): void;
|
|
568
722
|
promoteNextBgQueuedToRunning(): void;
|
|
569
723
|
promoteNextQueuedToRunning(): void;
|
|
570
724
|
resolveQueuedUserBubble(serverId?: string): number | undefined;
|
|
571
725
|
insertAtTarget(msg: ChatMessage, targetIdx: number): void;
|
|
572
|
-
onQueuedSendResponse(_composed: string, response: any, platform: string, serverId?: string): void;
|
|
573
|
-
onQueuedSendError(_composed: string, err: any, serverId?: string): void;
|
|
726
|
+
onQueuedSendResponse(_composed: string, response: any, platform: string, serverId?: string, ownerKey?: string): void;
|
|
727
|
+
onQueuedSendError(_composed: string, err: any, serverId?: string, ownerKey?: string): void;
|
|
574
728
|
cancelQueuedMessage(msg: ChatMessage, idx: number): void;
|
|
575
729
|
typewriteIntoIndex(idx: number, fullText: string, localId?: string): Promise<void>;
|
|
576
730
|
private typewriterQueue;
|
|
@@ -582,6 +736,7 @@ declare class ChatSession {
|
|
|
582
736
|
handleHistoryItemResolution(itemId: string, response: any, platform: string): void;
|
|
583
737
|
applyHistoryItemResolution(itemId: string, response: any, platform: string): void;
|
|
584
738
|
drainBgTaskQueue(): void;
|
|
739
|
+
maybeResumeIndexing(entry: BgTaskEntry, response: any, platform: string): void;
|
|
585
740
|
loadHistory(fetchMore?: boolean, token?: number): Promise<void>;
|
|
586
741
|
uploadSingleAttachment(att: any): Promise<Array<{
|
|
587
742
|
name: string;
|
|
@@ -597,4 +752,4 @@ declare class ChatSession {
|
|
|
597
752
|
bumpGate(): void;
|
|
598
753
|
}
|
|
599
754
|
|
|
600
|
-
export { type AttachmentFailureGroup, type AttachmentParser, type AttachmentSaveInfo, BG_INDEXING_QUEUE_SUFFIX, type BgTaskEntry, type BoundedChatOptions, 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, EXPIRED_ATTACHMENT_URL_HOST, EXPIRED_ATTACHMENT_URL_ORIGIN, type ExtractDirective, HISTORY_TOKEN_BUDGET, type IndexingAttachmentInfo, type IndexingSystemPromptParams, LINK_LABEL_MAX_DISPLAY_CHARS, MAX_HISTORY_MESSAGES, MAX_PARSED_CONTENT_CHARS, MCP_NAME, MIN_INPUT_TOKEN_BUDGET, type MapHistoryOptions, OUTPUT_TOKEN_RESERVE, type OpenAIMessage, POLL_INTERVAL, TOOL_AND_RESPONSE_BUFFER, buildBoundedChatMessages, buildChatSystemPrompt, buildDisplayExpiredAttachmentHref, buildIndexingSystemPrompt, buildIndexingUserMessage, callClaudeWithMcp, callClaudeWithPublicMcp, callOpenAIWithPublicMcp, chatEngineConfig, clearAttachmentParsers, composeUserMessage, configureChatEngine, createInlineLinkRegex, encodePathSegments, estimateMessageTokens, estimateTextTokens, extractClaudeText, extractLastUserTextFromRequest, extractOpenAIText, extractRemotePathFromAttachmentHref, filterListByClearHorizon, findAttachmentParser, getAttachmentParsers, getChatHistory, getContextWindow, getErrorMessage, getExpiredAttachmentVisiblePath, groupAttachmentFailures, isAuthExpiredError, isErrorResponseBody, isNonRetryableRequestError, isOfficeFile, isServerExtractable, isServiceDbAttachmentHref, listClaudeModels, listOpenAIModels, makeExtractPlaceholder, mapHistoryListToMessages, normalizeAttachmentPathCandidate, normalizeTextContent, notifyAgentSaveAttachment, parseAttachmentContent, registerAttachmentParser, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay };
|
|
755
|
+
export { type AttachmentFailureGroup, type AttachmentParser, type AttachmentSaveInfo, BG_INDEXING_QUEUE_SUFFIX, type BgTaskEntry, type BoundedChatOptions, 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, EXPIRED_ATTACHMENT_URL_HOST, EXPIRED_ATTACHMENT_URL_ORIGIN, type ExtractDirective, HISTORY_TOKEN_BUDGET, type IndexingAttachmentInfo, type IndexingSystemPromptParams, LINK_LABEL_MAX_DISPLAY_CHARS, 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, buildChatSystemPrompt, buildDisplayExpiredAttachmentHref, buildIndexingContinueMessage, buildIndexingRenderContinueTemplate, buildIndexingRenderMessage, buildIndexingSystemPrompt, buildIndexingUserMessage, buildIndexingWindowMessage, callClaudeWithMcp, callClaudeWithPublicMcp, callOpenAIWithPublicMcp, chatEngineConfig, clearAttachmentParsers, composeUserMessage, configureChatEngine, createInlineLinkRegex, encodePathSegments, estimateMessageTokens, estimateTextTokens, extractClaudeText, extractLastUserTextFromRequest, extractOpenAIText, extractRemotePathFromAttachmentHref, filterListByClearHorizon, findAttachmentParser, getAttachmentParsers, getChatHistory, getContextWindow, getErrorMessage, getExpiredAttachmentVisiblePath, groupAttachmentFailures, isAuthExpiredError, isBgIndexingQueue, isErrorResponseBody, isNonRetryableRequestError, isOfficeFile, isServerExtractable, isServiceDbAttachmentHref, listClaudeModels, listOpenAIModels, makeExtractPlaceholder, mapHistoryListToMessages, normalizeAttachmentPathCandidate, normalizeTextContent, notifyAgentSaveAttachment, parseAttachmentContent, registerAttachmentParser, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay };
|