bunnyquery 1.3.4 → 1.4.0
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/README.md +76 -7
- package/bunnyquery.js +177 -44
- package/dist/engine.cjs +175 -40
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.mts +72 -1
- package/dist/engine.d.ts +72 -1
- package/dist/engine.mjs +170 -41
- package/dist/engine.mjs.map +1 -1
- package/package.json +1 -1
- package/src/engine/attachment_parsers.ts +112 -0
- package/src/engine/config.ts +11 -0
- package/src/engine/index.ts +12 -0
- package/src/engine/office.ts +26 -4
- package/src/engine/prompts/indexing_user_message.ts +20 -0
- package/src/engine/requests.ts +17 -5
- package/src/engine/session.ts +63 -0
package/dist/engine.d.mts
CHANGED
|
@@ -1,3 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side attachment-parser plugins.
|
|
3
|
+
*
|
|
4
|
+
* Some attachment formats can't be read by the model's web_fetch (binary) and
|
|
5
|
+
* have no server-side extractor either — e.g. legacy Hancom .hwp. A parser
|
|
6
|
+
* plugin runs IN THE BROWSER, turns the uploaded File into indexable text (or an
|
|
7
|
+
* HTML string), and the engine sends that content INLINE in the background
|
|
8
|
+
* indexing request — so the model indexes the parsed content directly, with no
|
|
9
|
+
* upload-side server extraction and no web_fetch for that file.
|
|
10
|
+
*
|
|
11
|
+
* Register a parser with `registerAttachmentParser()`, or via
|
|
12
|
+
* `configureChatEngine({ attachmentParsers: [...] })`. The BunnyQuery widget also
|
|
13
|
+
* exposes `BunnyQuery.registerAttachmentParser()` and an `attachmentParsers`
|
|
14
|
+
* init option. First matching parser wins.
|
|
15
|
+
*/
|
|
16
|
+
interface AttachmentParser {
|
|
17
|
+
/** Human-readable label — used only in logs. */
|
|
18
|
+
name?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Return true if this parser handles the file. Receives the file name and
|
|
21
|
+
* (when known) its MIME type. Keep it cheap — it runs for every upload.
|
|
22
|
+
*/
|
|
23
|
+
match: (file: {
|
|
24
|
+
name: string;
|
|
25
|
+
mime?: string;
|
|
26
|
+
}) => boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Parse the File into indexable plain text OR an HTML string (the model reads
|
|
29
|
+
* either). Runs in the browser; may be async. Return a falsy/empty value to
|
|
30
|
+
* skip (the file then falls back to web_fetch / server extraction).
|
|
31
|
+
*/
|
|
32
|
+
parse: (file: File) => string | null | undefined | Promise<string | null | undefined>;
|
|
33
|
+
}
|
|
34
|
+
declare const MAX_PARSED_CONTENT_CHARS = 200000;
|
|
35
|
+
/** Register an attachment parser. Ignores duplicates (by reference) and invalid plugins. */
|
|
36
|
+
declare function registerAttachmentParser(parser: AttachmentParser): void;
|
|
37
|
+
/** Remove all registered parsers (mainly for tests / re-init). */
|
|
38
|
+
declare function clearAttachmentParsers(): void;
|
|
39
|
+
/** Snapshot of the registered parsers. */
|
|
40
|
+
declare function getAttachmentParsers(): AttachmentParser[];
|
|
41
|
+
/** First parser whose `match` returns true for the given file, if any. */
|
|
42
|
+
declare function findAttachmentParser(name: string, mime?: string): AttachmentParser | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Run the matching parser (if any) and return capped, trimmed content — or null
|
|
45
|
+
* when there is no parser, the parser throws, or it yields nothing. Never throws:
|
|
46
|
+
* a parser failure degrades to null so the upload still completes (the file then
|
|
47
|
+
* resolves via its normal path).
|
|
48
|
+
*/
|
|
49
|
+
declare function parseAttachmentContent(file: File, name: string, mime?: string): Promise<string | null>;
|
|
50
|
+
|
|
1
51
|
/**
|
|
2
52
|
* Engine configuration / dependency injection.
|
|
3
53
|
*
|
|
@@ -12,6 +62,7 @@
|
|
|
12
62
|
* `poll: 0` to get the early ack + a manual `.poll()` handle (needed for queued-
|
|
13
63
|
* send cancel). So the request builders include `poll` only when it is set.
|
|
14
64
|
*/
|
|
65
|
+
|
|
15
66
|
interface ChatEngineConfig {
|
|
16
67
|
/** skapi.clientSecretRequest, bound to the consumer's skapi instance. */
|
|
17
68
|
clientSecretRequest: (opts: any) => Promise<any>;
|
|
@@ -24,6 +75,12 @@ interface ChatEngineConfig {
|
|
|
24
75
|
* the `poll` key is omitted entirely (agent.vue). BunnyQuery sets `0`.
|
|
25
76
|
*/
|
|
26
77
|
poll?: number;
|
|
78
|
+
/**
|
|
79
|
+
* Optional client-side attachment parsers (e.g. an .hwp parser). Each is
|
|
80
|
+
* registered at configure time; more can be added later via
|
|
81
|
+
* `registerAttachmentParser()`. See attachment_parsers.ts.
|
|
82
|
+
*/
|
|
83
|
+
attachmentParsers?: AttachmentParser[];
|
|
27
84
|
}
|
|
28
85
|
declare function configureChatEngine(config: ChatEngineConfig): void;
|
|
29
86
|
declare function chatEngineConfig(): ChatEngineConfig;
|
|
@@ -153,6 +210,12 @@ type BuildIndexingUserMessageOptions = {
|
|
|
153
210
|
* drops the temporary-URL line — there is nothing for the model to fetch).
|
|
154
211
|
*/
|
|
155
212
|
inlineContentPlaceholder?: string;
|
|
213
|
+
/**
|
|
214
|
+
* Actual file content parsed CLIENT-SIDE by an attachment-parser plugin (e.g.
|
|
215
|
+
* an .hwp parser). Embedded inline verbatim — no server extraction and no
|
|
216
|
+
* web_fetch for this file. Takes precedence over `inlineContentPlaceholder`.
|
|
217
|
+
*/
|
|
218
|
+
inlineContent?: string;
|
|
156
219
|
};
|
|
157
220
|
declare function buildIndexingUserMessage(attachment: IndexingAttachmentInfo, options?: BuildIndexingUserMessageOptions): string;
|
|
158
221
|
|
|
@@ -293,6 +356,12 @@ type AttachmentSaveInfo = {
|
|
|
293
356
|
size?: number;
|
|
294
357
|
url: string;
|
|
295
358
|
};
|
|
359
|
+
/**
|
|
360
|
+
* Content parsed CLIENT-SIDE by an attachment-parser plugin (e.g. an .hwp
|
|
361
|
+
* parser). When set, it is inlined into the indexing message verbatim and
|
|
362
|
+
* takes precedence over server-side office extraction / web_fetch.
|
|
363
|
+
*/
|
|
364
|
+
parsedContent?: string;
|
|
296
365
|
};
|
|
297
366
|
declare function notifyAgentSaveAttachment(info: AttachmentSaveInfo): Promise<any>;
|
|
298
367
|
declare function extractClaudeText(response: any): any;
|
|
@@ -475,6 +544,8 @@ declare class ChatSession {
|
|
|
475
544
|
private typewriterQueue;
|
|
476
545
|
enqueueTypewrite(idx: number, fullText: string, localId?: string): Promise<any>;
|
|
477
546
|
typewriteLatestReply(key: string): Promise<any>;
|
|
547
|
+
_removeStrayPendingAssistants(): void;
|
|
548
|
+
_clearPendingUserBubble(itemId: string): void;
|
|
478
549
|
resumePendingRequest(token: number): Promise<void>;
|
|
479
550
|
handleHistoryItemResolution(itemId: string, response: any, platform: string): void;
|
|
480
551
|
applyHistoryItemResolution(itemId: string, response: any, platform: string): void;
|
|
@@ -494,4 +565,4 @@ declare class ChatSession {
|
|
|
494
565
|
bumpGate(): void;
|
|
495
566
|
}
|
|
496
567
|
|
|
497
|
-
export { type AttachmentFailureGroup, 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, 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, composeUserMessage, configureChatEngine, createInlineLinkRegex, encodePathSegments, estimateMessageTokens, estimateTextTokens, extractClaudeText, extractLastUserTextFromRequest, extractOpenAIText, extractRemotePathFromAttachmentHref, filterListByClearHorizon, getChatHistory, getContextWindow, getErrorMessage, getExpiredAttachmentVisiblePath, groupAttachmentFailures, isAuthExpiredError, isErrorResponseBody, isNonRetryableRequestError, isOfficeFile, listClaudeModels, listOpenAIModels, makeExtractPlaceholder, mapHistoryListToMessages, normalizeAttachmentPathCandidate, normalizeTextContent, notifyAgentSaveAttachment, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay };
|
|
568
|
+
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, listClaudeModels, listOpenAIModels, makeExtractPlaceholder, mapHistoryListToMessages, normalizeAttachmentPathCandidate, normalizeTextContent, notifyAgentSaveAttachment, parseAttachmentContent, registerAttachmentParser, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay };
|
package/dist/engine.d.ts
CHANGED
|
@@ -1,3 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side attachment-parser plugins.
|
|
3
|
+
*
|
|
4
|
+
* Some attachment formats can't be read by the model's web_fetch (binary) and
|
|
5
|
+
* have no server-side extractor either — e.g. legacy Hancom .hwp. A parser
|
|
6
|
+
* plugin runs IN THE BROWSER, turns the uploaded File into indexable text (or an
|
|
7
|
+
* HTML string), and the engine sends that content INLINE in the background
|
|
8
|
+
* indexing request — so the model indexes the parsed content directly, with no
|
|
9
|
+
* upload-side server extraction and no web_fetch for that file.
|
|
10
|
+
*
|
|
11
|
+
* Register a parser with `registerAttachmentParser()`, or via
|
|
12
|
+
* `configureChatEngine({ attachmentParsers: [...] })`. The BunnyQuery widget also
|
|
13
|
+
* exposes `BunnyQuery.registerAttachmentParser()` and an `attachmentParsers`
|
|
14
|
+
* init option. First matching parser wins.
|
|
15
|
+
*/
|
|
16
|
+
interface AttachmentParser {
|
|
17
|
+
/** Human-readable label — used only in logs. */
|
|
18
|
+
name?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Return true if this parser handles the file. Receives the file name and
|
|
21
|
+
* (when known) its MIME type. Keep it cheap — it runs for every upload.
|
|
22
|
+
*/
|
|
23
|
+
match: (file: {
|
|
24
|
+
name: string;
|
|
25
|
+
mime?: string;
|
|
26
|
+
}) => boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Parse the File into indexable plain text OR an HTML string (the model reads
|
|
29
|
+
* either). Runs in the browser; may be async. Return a falsy/empty value to
|
|
30
|
+
* skip (the file then falls back to web_fetch / server extraction).
|
|
31
|
+
*/
|
|
32
|
+
parse: (file: File) => string | null | undefined | Promise<string | null | undefined>;
|
|
33
|
+
}
|
|
34
|
+
declare const MAX_PARSED_CONTENT_CHARS = 200000;
|
|
35
|
+
/** Register an attachment parser. Ignores duplicates (by reference) and invalid plugins. */
|
|
36
|
+
declare function registerAttachmentParser(parser: AttachmentParser): void;
|
|
37
|
+
/** Remove all registered parsers (mainly for tests / re-init). */
|
|
38
|
+
declare function clearAttachmentParsers(): void;
|
|
39
|
+
/** Snapshot of the registered parsers. */
|
|
40
|
+
declare function getAttachmentParsers(): AttachmentParser[];
|
|
41
|
+
/** First parser whose `match` returns true for the given file, if any. */
|
|
42
|
+
declare function findAttachmentParser(name: string, mime?: string): AttachmentParser | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Run the matching parser (if any) and return capped, trimmed content — or null
|
|
45
|
+
* when there is no parser, the parser throws, or it yields nothing. Never throws:
|
|
46
|
+
* a parser failure degrades to null so the upload still completes (the file then
|
|
47
|
+
* resolves via its normal path).
|
|
48
|
+
*/
|
|
49
|
+
declare function parseAttachmentContent(file: File, name: string, mime?: string): Promise<string | null>;
|
|
50
|
+
|
|
1
51
|
/**
|
|
2
52
|
* Engine configuration / dependency injection.
|
|
3
53
|
*
|
|
@@ -12,6 +62,7 @@
|
|
|
12
62
|
* `poll: 0` to get the early ack + a manual `.poll()` handle (needed for queued-
|
|
13
63
|
* send cancel). So the request builders include `poll` only when it is set.
|
|
14
64
|
*/
|
|
65
|
+
|
|
15
66
|
interface ChatEngineConfig {
|
|
16
67
|
/** skapi.clientSecretRequest, bound to the consumer's skapi instance. */
|
|
17
68
|
clientSecretRequest: (opts: any) => Promise<any>;
|
|
@@ -24,6 +75,12 @@ interface ChatEngineConfig {
|
|
|
24
75
|
* the `poll` key is omitted entirely (agent.vue). BunnyQuery sets `0`.
|
|
25
76
|
*/
|
|
26
77
|
poll?: number;
|
|
78
|
+
/**
|
|
79
|
+
* Optional client-side attachment parsers (e.g. an .hwp parser). Each is
|
|
80
|
+
* registered at configure time; more can be added later via
|
|
81
|
+
* `registerAttachmentParser()`. See attachment_parsers.ts.
|
|
82
|
+
*/
|
|
83
|
+
attachmentParsers?: AttachmentParser[];
|
|
27
84
|
}
|
|
28
85
|
declare function configureChatEngine(config: ChatEngineConfig): void;
|
|
29
86
|
declare function chatEngineConfig(): ChatEngineConfig;
|
|
@@ -153,6 +210,12 @@ type BuildIndexingUserMessageOptions = {
|
|
|
153
210
|
* drops the temporary-URL line — there is nothing for the model to fetch).
|
|
154
211
|
*/
|
|
155
212
|
inlineContentPlaceholder?: string;
|
|
213
|
+
/**
|
|
214
|
+
* Actual file content parsed CLIENT-SIDE by an attachment-parser plugin (e.g.
|
|
215
|
+
* an .hwp parser). Embedded inline verbatim — no server extraction and no
|
|
216
|
+
* web_fetch for this file. Takes precedence over `inlineContentPlaceholder`.
|
|
217
|
+
*/
|
|
218
|
+
inlineContent?: string;
|
|
156
219
|
};
|
|
157
220
|
declare function buildIndexingUserMessage(attachment: IndexingAttachmentInfo, options?: BuildIndexingUserMessageOptions): string;
|
|
158
221
|
|
|
@@ -293,6 +356,12 @@ type AttachmentSaveInfo = {
|
|
|
293
356
|
size?: number;
|
|
294
357
|
url: string;
|
|
295
358
|
};
|
|
359
|
+
/**
|
|
360
|
+
* Content parsed CLIENT-SIDE by an attachment-parser plugin (e.g. an .hwp
|
|
361
|
+
* parser). When set, it is inlined into the indexing message verbatim and
|
|
362
|
+
* takes precedence over server-side office extraction / web_fetch.
|
|
363
|
+
*/
|
|
364
|
+
parsedContent?: string;
|
|
296
365
|
};
|
|
297
366
|
declare function notifyAgentSaveAttachment(info: AttachmentSaveInfo): Promise<any>;
|
|
298
367
|
declare function extractClaudeText(response: any): any;
|
|
@@ -475,6 +544,8 @@ declare class ChatSession {
|
|
|
475
544
|
private typewriterQueue;
|
|
476
545
|
enqueueTypewrite(idx: number, fullText: string, localId?: string): Promise<any>;
|
|
477
546
|
typewriteLatestReply(key: string): Promise<any>;
|
|
547
|
+
_removeStrayPendingAssistants(): void;
|
|
548
|
+
_clearPendingUserBubble(itemId: string): void;
|
|
478
549
|
resumePendingRequest(token: number): Promise<void>;
|
|
479
550
|
handleHistoryItemResolution(itemId: string, response: any, platform: string): void;
|
|
480
551
|
applyHistoryItemResolution(itemId: string, response: any, platform: string): void;
|
|
@@ -494,4 +565,4 @@ declare class ChatSession {
|
|
|
494
565
|
bumpGate(): void;
|
|
495
566
|
}
|
|
496
567
|
|
|
497
|
-
export { type AttachmentFailureGroup, 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, 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, composeUserMessage, configureChatEngine, createInlineLinkRegex, encodePathSegments, estimateMessageTokens, estimateTextTokens, extractClaudeText, extractLastUserTextFromRequest, extractOpenAIText, extractRemotePathFromAttachmentHref, filterListByClearHorizon, getChatHistory, getContextWindow, getErrorMessage, getExpiredAttachmentVisiblePath, groupAttachmentFailures, isAuthExpiredError, isErrorResponseBody, isNonRetryableRequestError, isOfficeFile, listClaudeModels, listOpenAIModels, makeExtractPlaceholder, mapHistoryListToMessages, normalizeAttachmentPathCandidate, normalizeTextContent, notifyAgentSaveAttachment, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay };
|
|
568
|
+
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, listClaudeModels, listOpenAIModels, makeExtractPlaceholder, mapHistoryListToMessages, normalizeAttachmentPathCandidate, normalizeTextContent, notifyAgentSaveAttachment, parseAttachmentContent, registerAttachmentParser, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay };
|
package/dist/engine.mjs
CHANGED
|
@@ -1,7 +1,55 @@
|
|
|
1
|
+
// src/engine/attachment_parsers.ts
|
|
2
|
+
var MAX_PARSED_CONTENT_CHARS = 2e5;
|
|
3
|
+
var _parsers = [];
|
|
4
|
+
function registerAttachmentParser(parser) {
|
|
5
|
+
if (parser && typeof parser.match === "function" && typeof parser.parse === "function" && _parsers.indexOf(parser) === -1) {
|
|
6
|
+
_parsers.push(parser);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
function clearAttachmentParsers() {
|
|
10
|
+
_parsers.length = 0;
|
|
11
|
+
}
|
|
12
|
+
function getAttachmentParsers() {
|
|
13
|
+
return _parsers.slice();
|
|
14
|
+
}
|
|
15
|
+
function findAttachmentParser(name, mime) {
|
|
16
|
+
for (let i = 0; i < _parsers.length; i++) {
|
|
17
|
+
try {
|
|
18
|
+
if (_parsers[i].match({ name, mime })) return _parsers[i];
|
|
19
|
+
} catch {
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return void 0;
|
|
23
|
+
}
|
|
24
|
+
async function parseAttachmentContent(file, name, mime) {
|
|
25
|
+
const parser = findAttachmentParser(name, mime);
|
|
26
|
+
if (!parser) return null;
|
|
27
|
+
let raw;
|
|
28
|
+
try {
|
|
29
|
+
raw = await parser.parse(file);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
console.error(
|
|
32
|
+
`[chat-engine] attachment parser ${parser.name || "(unnamed)"} failed for ${name}:`,
|
|
33
|
+
err
|
|
34
|
+
);
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
let text = (raw == null ? "" : String(raw)).trim();
|
|
38
|
+
if (!text) return null;
|
|
39
|
+
if (text.length > MAX_PARSED_CONTENT_CHARS) {
|
|
40
|
+
text = text.slice(0, MAX_PARSED_CONTENT_CHARS) + `
|
|
41
|
+
...[truncated for length; original ${text.length} characters]`;
|
|
42
|
+
}
|
|
43
|
+
return text;
|
|
44
|
+
}
|
|
45
|
+
|
|
1
46
|
// src/engine/config.ts
|
|
2
47
|
var _config = null;
|
|
3
48
|
function configureChatEngine(config) {
|
|
4
49
|
_config = config;
|
|
50
|
+
if (config.attachmentParsers) {
|
|
51
|
+
for (const parser of config.attachmentParsers) registerAttachmentParser(parser);
|
|
52
|
+
}
|
|
5
53
|
}
|
|
6
54
|
function chatEngineConfig() {
|
|
7
55
|
if (!_config) {
|
|
@@ -28,13 +76,41 @@ var OFFICE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
28
76
|
"pptx",
|
|
29
77
|
"pptm",
|
|
30
78
|
"hwp",
|
|
31
|
-
"hwpx"
|
|
79
|
+
"hwpx",
|
|
80
|
+
"ods",
|
|
81
|
+
"odt",
|
|
82
|
+
"odp",
|
|
83
|
+
"epub"
|
|
84
|
+
]);
|
|
85
|
+
var WEB_FETCHABLE_TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
86
|
+
"csv",
|
|
87
|
+
"tsv",
|
|
88
|
+
"tab",
|
|
89
|
+
"txt",
|
|
90
|
+
"text",
|
|
91
|
+
"md",
|
|
92
|
+
"markdown",
|
|
93
|
+
"json",
|
|
94
|
+
"ndjson",
|
|
95
|
+
"jsonl",
|
|
96
|
+
"xml",
|
|
97
|
+
"yaml",
|
|
98
|
+
"yml",
|
|
99
|
+
"log",
|
|
100
|
+
// RTF is a TEXT format (not a binary zip), so web_fetch can read it and the
|
|
101
|
+
// model decodes its control words. Pin it here so a `.rtf` reported as
|
|
102
|
+
// `application/msword` isn't misrouted to server-side extraction (which has no
|
|
103
|
+
// .rtf extractor → "unsupported format" note).
|
|
104
|
+
"rtf",
|
|
105
|
+
"htm",
|
|
106
|
+
"html"
|
|
32
107
|
]);
|
|
33
108
|
function isOfficeFile(name, mime) {
|
|
34
109
|
const ext = (name || "").split(".").pop()?.toLowerCase() || "";
|
|
35
110
|
if (OFFICE_FILE_EXTENSIONS.has(ext)) return true;
|
|
111
|
+
if (WEB_FETCHABLE_TEXT_EXTENSIONS.has(ext)) return false;
|
|
36
112
|
const m = (mime || "").toLowerCase();
|
|
37
|
-
return m.includes("officedocument") || m.includes("hwp") || m === "application/msword" || m === "application/vnd.ms-excel" || m === "application/vnd.ms-powerpoint";
|
|
113
|
+
return m.includes("officedocument") || m.includes("opendocument") || m.includes("hwp") || m.includes("epub") || m === "application/msword" || m === "application/vnd.ms-excel" || m === "application/vnd.ms-powerpoint";
|
|
38
114
|
}
|
|
39
115
|
var _extractPlaceholderSeq = 0;
|
|
40
116
|
function makeExtractPlaceholder(seed) {
|
|
@@ -155,6 +231,14 @@ File metadata:
|
|
|
155
231
|
` + (attachment.mime ? `- mime type: ${attachment.mime}
|
|
156
232
|
` : "") + (typeof attachment.size === "number" ? `- size (bytes): ${attachment.size}
|
|
157
233
|
` : "");
|
|
234
|
+
if (options?.inlineContent) {
|
|
235
|
+
return head + `
|
|
236
|
+
The file's content was parsed by the client and is provided inline below. Read it directly \u2014 do NOT fetch any URL for this file. Use the storage path above (not this content) for the "src::" unique_id.
|
|
237
|
+
|
|
238
|
+
----- BEGIN FILE CONTENT -----
|
|
239
|
+
${options.inlineContent}
|
|
240
|
+
----- END FILE CONTENT -----`;
|
|
241
|
+
}
|
|
158
242
|
if (options?.inlineContentPlaceholder) {
|
|
159
243
|
return head + `
|
|
160
244
|
The file's text content was extracted on the server and is provided inline below. Read it directly \u2014 do NOT fetch any URL for this file. Use the storage path above (not this content) for the "src::" unique_id.
|
|
@@ -653,14 +737,14 @@ async function callOpenAIWithPublicMcp(prompt, service, owner, messages, system,
|
|
|
653
737
|
});
|
|
654
738
|
}
|
|
655
739
|
async function notifyAgentSaveAttachment(info) {
|
|
656
|
-
const { platform, service, owner, attachment } = info;
|
|
657
|
-
const office = isOfficeFile(attachment.name, attachment.mime);
|
|
740
|
+
const { platform, service, owner, attachment, parsedContent } = info;
|
|
741
|
+
const office = !parsedContent && isOfficeFile(attachment.name, attachment.mime);
|
|
658
742
|
const placeholder = office ? makeExtractPlaceholder(attachment.storagePath) : void 0;
|
|
659
743
|
const extractContent = office && placeholder ? [{ path: attachment.storagePath, placeholder, name: attachment.name, mime: attachment.mime }] : void 0;
|
|
660
744
|
const skapiExtract = extractContent && extractContent.length ? { _skapi_extract: extractContent } : {};
|
|
661
745
|
const userMessage = buildIndexingUserMessage(
|
|
662
746
|
attachment,
|
|
663
|
-
placeholder ? { inlineContentPlaceholder: placeholder } : void 0
|
|
747
|
+
parsedContent ? { inlineContent: parsedContent } : placeholder ? { inlineContentPlaceholder: placeholder } : void 0
|
|
664
748
|
);
|
|
665
749
|
const systemPrompt = buildIndexingSystemPrompt({
|
|
666
750
|
service,
|
|
@@ -1246,6 +1330,7 @@ var ChatSession = class {
|
|
|
1246
1330
|
this.enqueueTypewrite(aiIdx, answer, lid);
|
|
1247
1331
|
}
|
|
1248
1332
|
}
|
|
1333
|
+
this._removeStrayPendingAssistants();
|
|
1249
1334
|
this.promoteNextQueuedToRunning();
|
|
1250
1335
|
this.updateHistoryCache();
|
|
1251
1336
|
this.host.notify();
|
|
@@ -1288,6 +1373,7 @@ var ChatSession = class {
|
|
|
1288
1373
|
if (thPos2 !== -1) this.state.messages.splice(thPos2, 1);
|
|
1289
1374
|
}
|
|
1290
1375
|
if (serverId) this.cancelledServerIds.delete(serverId);
|
|
1376
|
+
this._removeStrayPendingAssistants();
|
|
1291
1377
|
this.promoteNextQueuedToRunning();
|
|
1292
1378
|
this.updateHistoryCache();
|
|
1293
1379
|
this.host.notify();
|
|
@@ -1301,6 +1387,7 @@ var ChatSession = class {
|
|
|
1301
1387
|
return;
|
|
1302
1388
|
}
|
|
1303
1389
|
this.insertAtTarget({ role: "assistant", content: getErrorMessage(err), isError: true }, targetIdx);
|
|
1390
|
+
this._removeStrayPendingAssistants();
|
|
1304
1391
|
this.promoteNextQueuedToRunning();
|
|
1305
1392
|
this.updateHistoryCache();
|
|
1306
1393
|
this.host.notify();
|
|
@@ -1462,16 +1549,48 @@ var ChatSession = class {
|
|
|
1462
1549
|
if (pendingIdx === -1) return Promise.resolve();
|
|
1463
1550
|
if (latest.isError || !latest.content) {
|
|
1464
1551
|
this.state.messages[pendingIdx] = { role: "assistant", content: latest.content || "", isError: !!latest.isError };
|
|
1552
|
+
this._removeStrayPendingAssistants();
|
|
1465
1553
|
this.host.notify();
|
|
1466
1554
|
this.promoteNextQueuedToRunning();
|
|
1467
1555
|
return Promise.resolve();
|
|
1468
1556
|
}
|
|
1469
1557
|
var lid = this._newLocalId();
|
|
1470
1558
|
this.state.messages[pendingIdx] = { role: "assistant", content: "", isPending: false, _localId: lid };
|
|
1559
|
+
this._removeStrayPendingAssistants();
|
|
1471
1560
|
this.host.notify();
|
|
1472
1561
|
this.promoteNextQueuedToRunning();
|
|
1473
1562
|
return this.enqueueTypewrite(pendingIdx, latest.content, lid);
|
|
1474
1563
|
}
|
|
1564
|
+
// Remove any leftover non-background pending ("Thinking…") assistant bubbles.
|
|
1565
|
+
// There is normally at most ONE such bubble at a time (promoteNext* refuses to
|
|
1566
|
+
// add a second), so any extra is a duplicate — it appears when a concurrent
|
|
1567
|
+
// history refetch re-maps the still-"running" turn into a pending placeholder
|
|
1568
|
+
// (with a real _serverItemId) while the local pending bubble (no _serverItemId)
|
|
1569
|
+
// is rescued and re-appended (see loadHistory rescue below). Each resolve path
|
|
1570
|
+
// only replaces the FIRST pending bubble, so without this a stray "Thinking…"
|
|
1571
|
+
// survives next to the reply/error. MUST run AFTER the resolved bubble has been
|
|
1572
|
+
// made non-pending and BEFORE promoteNext*() (so a freshly-promoted Thinking,
|
|
1573
|
+
// which is added only once no pending assistant remains, is preserved).
|
|
1574
|
+
_removeStrayPendingAssistants() {
|
|
1575
|
+
for (var k = this.state.messages.length - 1; k >= 0; k--) {
|
|
1576
|
+
var m = this.state.messages[k];
|
|
1577
|
+
if (m.isPending && m.role === "assistant" && !m.isBackgroundTask) this.state.messages.splice(k, 1);
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
// Drop the pending flags on the resolved turn's USER bubble (preserving its
|
|
1581
|
+
// content + background-task marker). Needed because a bg "Indexing:" turn's user
|
|
1582
|
+
// bubble carries isPendingInProcess; leaving it set keeps the bubble visually
|
|
1583
|
+
// stuck and keeps its bgTaskQueue entry alive forever.
|
|
1584
|
+
_clearPendingUserBubble(itemId) {
|
|
1585
|
+
var uIdx = this.state.messages.findIndex(function(m) {
|
|
1586
|
+
return m.role === "user" && m._serverItemId === itemId && (m.isPendingInProcess || m.isPendingQueued || m.isSendingToServer);
|
|
1587
|
+
});
|
|
1588
|
+
if (uIdx === -1) return;
|
|
1589
|
+
var u = this.state.messages[uIdx];
|
|
1590
|
+
var cleaned = { role: "user", content: u.content, _serverItemId: itemId };
|
|
1591
|
+
if (u.isBackgroundTask) cleaned.isBackgroundTask = true;
|
|
1592
|
+
this.state.messages[uIdx] = cleaned;
|
|
1593
|
+
}
|
|
1475
1594
|
// If an immediate-send request for the current cache key is still in flight
|
|
1476
1595
|
// (e.g. the view unmounted then remounted mid-request), show the sending
|
|
1477
1596
|
// state, await it, then render the reply from the cache. Skipped when the
|
|
@@ -1510,6 +1629,7 @@ var ChatSession = class {
|
|
|
1510
1629
|
return m.isPending && m._serverItemId === itemId;
|
|
1511
1630
|
});
|
|
1512
1631
|
if (idx !== -1) {
|
|
1632
|
+
this._clearPendingUserBubble(itemId);
|
|
1513
1633
|
if (isErr) {
|
|
1514
1634
|
this.state.messages[idx] = { role: "assistant", content: answer, isError: true, _serverItemId: itemId };
|
|
1515
1635
|
this.host.notify();
|
|
@@ -1659,12 +1779,16 @@ var ChatSession = class {
|
|
|
1659
1779
|
self.state.messages.forEach(function(m) {
|
|
1660
1780
|
if (m.isCancelled && m._serverItemId) locallyCancelled[m._serverItemId] = 1;
|
|
1661
1781
|
});
|
|
1782
|
+
var mappedHasPendingAssistant = mapped.some(function(m) {
|
|
1783
|
+
return m.isPending && m.role === "assistant" && !m.isBackgroundTask;
|
|
1784
|
+
});
|
|
1662
1785
|
var rescued = [];
|
|
1663
1786
|
for (var ri = 0; ri < self.state.messages.length; ri++) {
|
|
1664
1787
|
var mm = self.state.messages[ri];
|
|
1665
1788
|
if (mm.isBackgroundTask) continue;
|
|
1666
1789
|
if (mm._serverItemId && serverIds[mm._serverItemId]) continue;
|
|
1667
1790
|
if (!mm._serverItemId) {
|
|
1791
|
+
if (mappedHasPendingAssistant) continue;
|
|
1668
1792
|
if (mm.isSendingToServer || mm.isPendingQueued || mm.isPendingInProcess || mm.isPending) rescued.push(mm);
|
|
1669
1793
|
else if (self.state.sending && mm.role === "user") {
|
|
1670
1794
|
var next = self.state.messages[ri + 1];
|
|
@@ -1822,44 +1946,49 @@ var ChatSession = class {
|
|
|
1822
1946
|
att.storagePath = member.storagePath;
|
|
1823
1947
|
}
|
|
1824
1948
|
var mime = member.file.type || self.host.getMimeType(member.file.name);
|
|
1825
|
-
return
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
url
|
|
1839
|
-
}
|
|
1840
|
-
}).then(function(ack) {
|
|
1841
|
-
if (ack && typeof ack.id === "string") {
|
|
1842
|
-
self.bgTaskQueue.push({
|
|
1843
|
-
serviceId: id.serviceId,
|
|
1844
|
-
platform: id.platform,
|
|
1845
|
-
id: ack.id,
|
|
1846
|
-
filename: member.file.name,
|
|
1949
|
+
return Promise.resolve(
|
|
1950
|
+
parseAttachmentContent(member.file, member.file.name, mime || void 0)
|
|
1951
|
+
).then(function(parsedContent) {
|
|
1952
|
+
return notifyAgentSaveAttachment({
|
|
1953
|
+
platform: id.platform,
|
|
1954
|
+
model: id.model,
|
|
1955
|
+
service: id.serviceId,
|
|
1956
|
+
owner: id.owner,
|
|
1957
|
+
userId: id.userId || id.serviceId,
|
|
1958
|
+
serviceName: id.serviceName,
|
|
1959
|
+
serviceDescription: id.serviceDescription,
|
|
1960
|
+
attachment: {
|
|
1961
|
+
name: member.file.name,
|
|
1847
1962
|
storagePath: member.storagePath,
|
|
1848
|
-
isReindex: hadExists,
|
|
1849
1963
|
mime: mime || void 0,
|
|
1850
1964
|
size: member.file.size,
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1965
|
+
url
|
|
1966
|
+
},
|
|
1967
|
+
parsedContent: parsedContent || void 0
|
|
1968
|
+
}).then(function(ack) {
|
|
1969
|
+
if (ack && typeof ack.id === "string") {
|
|
1970
|
+
self.bgTaskQueue.push({
|
|
1971
|
+
serviceId: id.serviceId,
|
|
1972
|
+
platform: id.platform,
|
|
1973
|
+
id: ack.id,
|
|
1974
|
+
filename: member.file.name,
|
|
1975
|
+
storagePath: member.storagePath,
|
|
1976
|
+
isReindex: hadExists,
|
|
1977
|
+
mime: mime || void 0,
|
|
1978
|
+
size: member.file.size,
|
|
1979
|
+
status: ack.status === "running" ? "running" : "pending",
|
|
1980
|
+
poll: ack.poll
|
|
1981
|
+
});
|
|
1982
|
+
self.drainBgTaskQueue();
|
|
1983
|
+
}
|
|
1984
|
+
}, function(e) {
|
|
1985
|
+
console.error("[chat-engine] indexing request failed", e);
|
|
1986
|
+
anyIndexFailed = true;
|
|
1987
|
+
if (!att.errorCode && !att.errorDetail) {
|
|
1988
|
+
att.errorCode = e && (e.code || e.body && e.body.code) || "";
|
|
1989
|
+
att.errorDetail = e && (e.message || e.body && e.body.message) || (typeof e === "string" ? e : "");
|
|
1990
|
+
}
|
|
1991
|
+
});
|
|
1863
1992
|
});
|
|
1864
1993
|
});
|
|
1865
1994
|
});
|
|
@@ -1939,6 +2068,6 @@ var ChatSession = class {
|
|
|
1939
2068
|
}
|
|
1940
2069
|
};
|
|
1941
2070
|
|
|
1942
|
-
export { BG_INDEXING_QUEUE_SUFFIX, CLAUDE_PER_REQUEST_INPUT_CAP, CONTEXT_WINDOW_BY_MODEL, CONTEXT_WINDOW_DEFAULT, ChatSession, DEFAULT_CLAUDE_MODEL, DEFAULT_OPENAI_MODEL, EXPIRED_ATTACHMENT_URL_HOST, EXPIRED_ATTACHMENT_URL_ORIGIN, HISTORY_TOKEN_BUDGET, LINK_LABEL_MAX_DISPLAY_CHARS, MAX_HISTORY_MESSAGES, MCP_NAME, MIN_INPUT_TOKEN_BUDGET, OUTPUT_TOKEN_RESERVE, POLL_INTERVAL, TOOL_AND_RESPONSE_BUFFER, buildBoundedChatMessages, buildChatSystemPrompt, buildDisplayExpiredAttachmentHref, buildIndexingSystemPrompt, buildIndexingUserMessage, callClaudeWithMcp, callClaudeWithPublicMcp, callOpenAIWithPublicMcp, chatEngineConfig, composeUserMessage, configureChatEngine, createInlineLinkRegex, encodePathSegments, estimateMessageTokens, estimateTextTokens, extractClaudeText, extractLastUserTextFromRequest, extractOpenAIText, extractRemotePathFromAttachmentHref, filterListByClearHorizon, getChatHistory, getContextWindow, getErrorMessage, getExpiredAttachmentVisiblePath, groupAttachmentFailures, isAuthExpiredError, isErrorResponseBody, isNonRetryableRequestError, isOfficeFile, listClaudeModels, listOpenAIModels, makeExtractPlaceholder, mapHistoryListToMessages, normalizeAttachmentPathCandidate, normalizeTextContent, notifyAgentSaveAttachment, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay };
|
|
2071
|
+
export { BG_INDEXING_QUEUE_SUFFIX, CLAUDE_PER_REQUEST_INPUT_CAP, CONTEXT_WINDOW_BY_MODEL, CONTEXT_WINDOW_DEFAULT, ChatSession, DEFAULT_CLAUDE_MODEL, DEFAULT_OPENAI_MODEL, EXPIRED_ATTACHMENT_URL_HOST, EXPIRED_ATTACHMENT_URL_ORIGIN, HISTORY_TOKEN_BUDGET, LINK_LABEL_MAX_DISPLAY_CHARS, MAX_HISTORY_MESSAGES, MAX_PARSED_CONTENT_CHARS, MCP_NAME, MIN_INPUT_TOKEN_BUDGET, OUTPUT_TOKEN_RESERVE, 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, listClaudeModels, listOpenAIModels, makeExtractPlaceholder, mapHistoryListToMessages, normalizeAttachmentPathCandidate, normalizeTextContent, notifyAgentSaveAttachment, parseAttachmentContent, registerAttachmentParser, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay };
|
|
1943
2072
|
//# sourceMappingURL=engine.mjs.map
|
|
1944
2073
|
//# sourceMappingURL=engine.mjs.map
|