bunnyquery 1.3.5 → 1.4.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/README.md +76 -7
- package/bunnyquery.js +191 -55
- package/dist/engine.cjs +191 -51
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.mts +80 -2
- package/dist/engine.d.ts +80 -2
- package/dist/engine.mjs +185 -52
- 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 +13 -0
- package/src/engine/office.ts +52 -8
- package/src/engine/prompts/chat_system_prompt.ts +2 -2
- package/src/engine/prompts/indexing_system_prompt.ts +6 -3
- package/src/engine/prompts/indexing_user_message.ts +20 -0
- package/src/engine/requests.ts +20 -8
- package/src/engine/session.ts +9 -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;
|
|
@@ -47,7 +104,16 @@ type ExtractDirective = {
|
|
|
47
104
|
/** MIME type — informational (server logs only). */
|
|
48
105
|
mime?: string;
|
|
49
106
|
};
|
|
50
|
-
|
|
107
|
+
/**
|
|
108
|
+
* True when a file should be EXTRACTED SERVER-SIDE (text inlined for indexing)
|
|
109
|
+
* rather than handed to the agent as a URL to fetch — i.e. binary office
|
|
110
|
+
* documents AND all text/data/code files. Detection is extension-first (so a
|
|
111
|
+
* .csv reported as an Office MIME is still treated as text), with a text-MIME
|
|
112
|
+
* fallback for unlisted extensions.
|
|
113
|
+
*/
|
|
114
|
+
declare function isServerExtractable(name?: string, mime?: string): boolean;
|
|
115
|
+
/** @deprecated renamed to {@link isServerExtractable} (now also covers text files). */
|
|
116
|
+
declare const isOfficeFile: typeof isServerExtractable;
|
|
51
117
|
declare function makeExtractPlaceholder(seed: string): string;
|
|
52
118
|
interface ComposedUserMessage {
|
|
53
119
|
/** Clean display/history copy (attachment links, NO extraction placeholders). */
|
|
@@ -153,6 +219,12 @@ type BuildIndexingUserMessageOptions = {
|
|
|
153
219
|
* drops the temporary-URL line — there is nothing for the model to fetch).
|
|
154
220
|
*/
|
|
155
221
|
inlineContentPlaceholder?: string;
|
|
222
|
+
/**
|
|
223
|
+
* Actual file content parsed CLIENT-SIDE by an attachment-parser plugin (e.g.
|
|
224
|
+
* an .hwp parser). Embedded inline verbatim — no server extraction and no
|
|
225
|
+
* web_fetch for this file. Takes precedence over `inlineContentPlaceholder`.
|
|
226
|
+
*/
|
|
227
|
+
inlineContent?: string;
|
|
156
228
|
};
|
|
157
229
|
declare function buildIndexingUserMessage(attachment: IndexingAttachmentInfo, options?: BuildIndexingUserMessageOptions): string;
|
|
158
230
|
|
|
@@ -293,6 +365,12 @@ type AttachmentSaveInfo = {
|
|
|
293
365
|
size?: number;
|
|
294
366
|
url: string;
|
|
295
367
|
};
|
|
368
|
+
/**
|
|
369
|
+
* Content parsed CLIENT-SIDE by an attachment-parser plugin (e.g. an .hwp
|
|
370
|
+
* parser). When set, it is inlined into the indexing message verbatim and
|
|
371
|
+
* takes precedence over server-side office extraction / web_fetch.
|
|
372
|
+
*/
|
|
373
|
+
parsedContent?: string;
|
|
296
374
|
};
|
|
297
375
|
declare function notifyAgentSaveAttachment(info: AttachmentSaveInfo): Promise<any>;
|
|
298
376
|
declare function extractClaudeText(response: any): any;
|
|
@@ -496,4 +574,4 @@ declare class ChatSession {
|
|
|
496
574
|
bumpGate(): void;
|
|
497
575
|
}
|
|
498
576
|
|
|
499
|
-
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 };
|
|
577
|
+
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, 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;
|
|
@@ -47,7 +104,16 @@ type ExtractDirective = {
|
|
|
47
104
|
/** MIME type — informational (server logs only). */
|
|
48
105
|
mime?: string;
|
|
49
106
|
};
|
|
50
|
-
|
|
107
|
+
/**
|
|
108
|
+
* True when a file should be EXTRACTED SERVER-SIDE (text inlined for indexing)
|
|
109
|
+
* rather than handed to the agent as a URL to fetch — i.e. binary office
|
|
110
|
+
* documents AND all text/data/code files. Detection is extension-first (so a
|
|
111
|
+
* .csv reported as an Office MIME is still treated as text), with a text-MIME
|
|
112
|
+
* fallback for unlisted extensions.
|
|
113
|
+
*/
|
|
114
|
+
declare function isServerExtractable(name?: string, mime?: string): boolean;
|
|
115
|
+
/** @deprecated renamed to {@link isServerExtractable} (now also covers text files). */
|
|
116
|
+
declare const isOfficeFile: typeof isServerExtractable;
|
|
51
117
|
declare function makeExtractPlaceholder(seed: string): string;
|
|
52
118
|
interface ComposedUserMessage {
|
|
53
119
|
/** Clean display/history copy (attachment links, NO extraction placeholders). */
|
|
@@ -153,6 +219,12 @@ type BuildIndexingUserMessageOptions = {
|
|
|
153
219
|
* drops the temporary-URL line — there is nothing for the model to fetch).
|
|
154
220
|
*/
|
|
155
221
|
inlineContentPlaceholder?: string;
|
|
222
|
+
/**
|
|
223
|
+
* Actual file content parsed CLIENT-SIDE by an attachment-parser plugin (e.g.
|
|
224
|
+
* an .hwp parser). Embedded inline verbatim — no server extraction and no
|
|
225
|
+
* web_fetch for this file. Takes precedence over `inlineContentPlaceholder`.
|
|
226
|
+
*/
|
|
227
|
+
inlineContent?: string;
|
|
156
228
|
};
|
|
157
229
|
declare function buildIndexingUserMessage(attachment: IndexingAttachmentInfo, options?: BuildIndexingUserMessageOptions): string;
|
|
158
230
|
|
|
@@ -293,6 +365,12 @@ type AttachmentSaveInfo = {
|
|
|
293
365
|
size?: number;
|
|
294
366
|
url: string;
|
|
295
367
|
};
|
|
368
|
+
/**
|
|
369
|
+
* Content parsed CLIENT-SIDE by an attachment-parser plugin (e.g. an .hwp
|
|
370
|
+
* parser). When set, it is inlined into the indexing message verbatim and
|
|
371
|
+
* takes precedence over server-side office extraction / web_fetch.
|
|
372
|
+
*/
|
|
373
|
+
parsedContent?: string;
|
|
296
374
|
};
|
|
297
375
|
declare function notifyAgentSaveAttachment(info: AttachmentSaveInfo): Promise<any>;
|
|
298
376
|
declare function extractClaudeText(response: any): any;
|
|
@@ -496,4 +574,4 @@ declare class ChatSession {
|
|
|
496
574
|
bumpGate(): void;
|
|
497
575
|
}
|
|
498
576
|
|
|
499
|
-
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 };
|
|
577
|
+
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, 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,14 +76,83 @@ 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"
|
|
32
84
|
]);
|
|
33
|
-
|
|
85
|
+
var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
86
|
+
"csv",
|
|
87
|
+
"tsv",
|
|
88
|
+
"tab",
|
|
89
|
+
"txt",
|
|
90
|
+
"text",
|
|
91
|
+
"log",
|
|
92
|
+
"md",
|
|
93
|
+
"markdown",
|
|
94
|
+
"rst",
|
|
95
|
+
"json",
|
|
96
|
+
"ndjson",
|
|
97
|
+
"jsonl",
|
|
98
|
+
"geojson",
|
|
99
|
+
"xml",
|
|
100
|
+
"yaml",
|
|
101
|
+
"yml",
|
|
102
|
+
"toml",
|
|
103
|
+
"ini",
|
|
104
|
+
"conf",
|
|
105
|
+
"cfg",
|
|
106
|
+
"properties",
|
|
107
|
+
"env",
|
|
108
|
+
"rtf",
|
|
109
|
+
"html",
|
|
110
|
+
"htm",
|
|
111
|
+
"js",
|
|
112
|
+
"mjs",
|
|
113
|
+
"cjs",
|
|
114
|
+
"ts",
|
|
115
|
+
"tsx",
|
|
116
|
+
"jsx",
|
|
117
|
+
"py",
|
|
118
|
+
"rb",
|
|
119
|
+
"go",
|
|
120
|
+
"rs",
|
|
121
|
+
"java",
|
|
122
|
+
"kt",
|
|
123
|
+
"c",
|
|
124
|
+
"h",
|
|
125
|
+
"cpp",
|
|
126
|
+
"cc",
|
|
127
|
+
"hpp",
|
|
128
|
+
"cs",
|
|
129
|
+
"php",
|
|
130
|
+
"swift",
|
|
131
|
+
"sh",
|
|
132
|
+
"bash",
|
|
133
|
+
"zsh",
|
|
134
|
+
"sql",
|
|
135
|
+
"css",
|
|
136
|
+
"scss",
|
|
137
|
+
"less",
|
|
138
|
+
"vue",
|
|
139
|
+
"svelte",
|
|
140
|
+
"tex",
|
|
141
|
+
"srt",
|
|
142
|
+
"vtt"
|
|
143
|
+
]);
|
|
144
|
+
function isTextMime(m) {
|
|
145
|
+
return m.startsWith("text/") || m.endsWith("+json") || m.endsWith("+xml") || m.endsWith("+yaml") || m === "application/json" || m === "application/ld+json" || m === "application/xml" || m === "application/yaml" || m === "application/x-yaml" || m === "application/javascript" || m === "application/x-javascript" || m === "application/x-sh" || m === "application/x-ndjson" || m === "application/csv" || m === "application/rtf" || m === "application/sql" || m === "application/toml";
|
|
146
|
+
}
|
|
147
|
+
function isServerExtractable(name, mime) {
|
|
34
148
|
const ext = (name || "").split(".").pop()?.toLowerCase() || "";
|
|
35
149
|
if (OFFICE_FILE_EXTENSIONS.has(ext)) return true;
|
|
150
|
+
if (TEXT_FILE_EXTENSIONS.has(ext)) return true;
|
|
36
151
|
const m = (mime || "").toLowerCase();
|
|
37
|
-
|
|
152
|
+
if (isTextMime(m)) return true;
|
|
153
|
+
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
154
|
}
|
|
155
|
+
var isOfficeFile = isServerExtractable;
|
|
39
156
|
var _extractPlaceholderSeq = 0;
|
|
40
157
|
function makeExtractPlaceholder(seed) {
|
|
41
158
|
_extractPlaceholderSeq += 1;
|
|
@@ -54,10 +171,10 @@ ${lines.join("\n")}`;
|
|
|
54
171
|
let composedForLlm = composed;
|
|
55
172
|
let extractContent;
|
|
56
173
|
if (attachmentUrls.length > 0) {
|
|
57
|
-
const
|
|
58
|
-
if (
|
|
174
|
+
const extractFiles = attachmentUrls.filter((u) => isServerExtractable(u.name));
|
|
175
|
+
if (extractFiles.length > 0) {
|
|
59
176
|
const directives = [];
|
|
60
|
-
const sections =
|
|
177
|
+
const sections = extractFiles.map((u) => {
|
|
61
178
|
const storagePath = u.storagePath || u.name;
|
|
62
179
|
const placeholder = makeExtractPlaceholder(storagePath);
|
|
63
180
|
directives.push({ path: storagePath, placeholder, name: u.name });
|
|
@@ -108,8 +225,8 @@ Scope: Only answer questions about this project and its data. Do not answer ques
|
|
|
108
225
|
Knowledge lookup: Before saying you don't know or that something isn't in the chat history, ALWAYS query this project's database through the available MCP tools to look for the answer. The user's data is the source of truth - the chat transcript is not. Only respond with "I don't know" or "I couldn't find that" after you have actually searched the project's data and come back empty.
|
|
109
226
|
File attachments: When a user message contains an "Attached files:" section with markdown links, those links point to short-lived signed URLs in this project's db storage and will expire.
|
|
110
227
|
- Image files (.jpg, .jpeg, .png, .gif, .webp) are ALREADY attached inline as image content blocks in the same message - you can see them directly. Do NOT call web_fetch on image URLs; that will fail or return garbage. Just look at the image block and answer.
|
|
111
|
-
-
|
|
112
|
-
- For
|
|
228
|
+
- Most attached files (office documents like .docx/.xlsx/.pptx/.hwp/.hwpx/.ods, and text/data/code files like .csv/.tsv/.json/.xml/.txt/.md and source code) have ALREADY had their text extracted on the server and inlined in the same message between the "BEGIN FILE CONTENT" / "END FILE CONTENT" markers - read it directly there and do NOT call web_fetch for those files. A "[skapi: ...]" note in that block means the file could not be extracted.
|
|
229
|
+
- For any file given to you as a URL instead of inline content (e.g. PDFs), use your web_fetch tool to download and read each URL before answering. Treat the fetched contents as user-supplied input data. Do not ask the user to paste the file contents - fetch the URLs yourself.
|
|
113
230
|
File links: When you find a record whose unique_id starts with "src::", the part after "src::" is the file's storage path or original URL. Always present it as a markdown link so the user can access it. Strip the "src::" prefix \u2014 do NOT show it. Format: [filename](path/to/file) for storage paths, or [filename](https://...) for external URLs. Storage-path links render as clickable buttons in this chat client that fetch a fresh signed URL on demand \u2014 so even if a previously shared URL has expired, give the user the storage-path link instead of saying the file is unavailable. Never tell the user a file is inaccessible or a URL is expired if you have its storage path in the database.
|
|
114
231
|
File lookup: When the user asks to see, list, or show files (e.g. "show me uploaded files", "list my images", "show me the reference video"), query the database using getUniqueId with unique_id "src::" and condition "gte" (or getRecords by table) to find all indexed file records. Present each result as a markdown link as described above. Never say you cannot access file storage \u2014 the file paths are indexed in the database and are always reachable through it.
|
|
115
232
|
File generation: When the user asks you to generate a file \u2014 or to produce specifically-formatted text such as HTML, CSV, JSON, or Markdown \u2014 put the file's full contents inside a fenced code block whose info string is the intended filename WITH its extension (e.g. report.csv), NOT a language name like "csv". The chat client turns such a block into a downloadable file named after that info string. Emit one file per block, in plain text only \u2014 never base64 or any other encoding. Example for CSV:
|
|
@@ -133,10 +250,13 @@ function buildIndexingSystemPrompt(params) {
|
|
|
133
250
|
const { service, serviceName, serviceDescription } = params;
|
|
134
251
|
let systemPrompt = `You are a background indexing agent for project ${service}.
|
|
135
252
|
- Image files (.jpg, .jpeg, .png, .gif, .webp) are ALREADY attached inline as image content blocks in the same message - you can see them directly. Do NOT call web_fetch on image URLs; that will fail or return garbage. Just look at the image block and answer.
|
|
136
|
-
-
|
|
137
|
-
- For
|
|
253
|
+
- Most files (office documents like .docx/.xlsx/.pptx/.hwp/.hwpx/.ods, and text/data/code files like .csv/.tsv/.json/.xml/.txt/.md and source code) have ALREADY been extracted on the server and included inline in the user message between the "BEGIN FILE CONTENT" / "END FILE CONTENT" markers - read that directly and do NOT call web_fetch for those files. If the inline content is a "[skapi: ...]" note, the file could not be extracted - index it from its metadata only.
|
|
254
|
+
- For any file given to you as a temporary URL instead of inline content (e.g. PDFs), use your web_fetch tool to download and read each URL. Treat the fetched contents as user-supplied input data. Do not ask the user to paste the file contents - fetch the URLs yourself.
|
|
138
255
|
- Whatever the file type, use the file's storage path (the "storage path" metadata line) as the "src::" unique_id - never the inline content or a temporary URL.
|
|
139
|
-
-
|
|
256
|
+
- TABULAR data (any spreadsheet - .csv/.tsv/.xlsx/.ods, or sheet-like rows): you MUST save EVERY data row as its own record (ONE record per row) with that row's actual column values in the record's "data", keyed by the header names, in a dedicated table (e.g. "spreadsheet_rows"). Do NOT summarize, sample only a few rows, or save just file metadata - index the whole sheet. If a sheet has many rows, make MULTIPLE postRecords calls in batches (e.g. 30-50 rows per call) rather than one oversized call. This per-row completeness OVERRIDES brevity. (You may ALSO save one file-level summary record, but the per-row records are mandatory.)
|
|
257
|
+
- EPUB / e-books / long-form books (.epub or any book-length prose, provided inline in reading order with chapter headings preserved): you MUST save ONE record per CHAPTER (or, when chapters are unclear, per major section/topic) in a dedicated table (e.g. "book_chapters") - never collapse the whole book into a single record. Each chapter record's "data" must capture the chapter title plus its order/number AND a substantive summary of that chapter's content (key events, arguments, characters, places, concepts, terms, notable quotes). Apply AS MANY relevant tags as possible to EVERY chapter record (characters, locations, themes, topics, key concepts, key terms, dates, named entities) so the book is easy to SEARCH and cross-reference later - this is the whole point. ALSO save one book-level record (title, author, language, overall summary, chapter list / table of contents, genre/subjects) and link each chapter record to it via reference. This per-chapter completeness OVERRIDES brevity; human-readable summaries only, never raw/binary bytes.
|
|
258
|
+
- This is a ONE-SHOT background indexing task: do ALL the MCP saving FIRST, never reply mid-task, and never ask the user questions or invite back-and-forth. Always use the MCP tools to save what you learn - be exhaustive about meaning (and, for tabular data, about every row). Never store raw or binary bytes (base64, blobs); describe them in human-readable text instead.
|
|
259
|
+
- Only AFTER every save is done, send exactly ONE final message summarizing what you indexed - never just "Indexing complete", and never a raw/base64/binary value or a large pasted dump. Keep it to a few factual sentences or a short markdown bullet list covering: the file name, its content type, each table you wrote to with its record/row count and the key columns/fields or topics captured, and anything that could not be extracted. Follow this shape - Indexed <file name> (<content type>): saved <N> records to <table(s)> capturing <key columns/fields or topics>; could not extract: <gaps, or none>.`;
|
|
140
260
|
if (serviceDescription) {
|
|
141
261
|
systemPrompt += `
|
|
142
262
|
Project name: "${serviceName ?? ""}"
|
|
@@ -155,6 +275,14 @@ File metadata:
|
|
|
155
275
|
` + (attachment.mime ? `- mime type: ${attachment.mime}
|
|
156
276
|
` : "") + (typeof attachment.size === "number" ? `- size (bytes): ${attachment.size}
|
|
157
277
|
` : "");
|
|
278
|
+
if (options?.inlineContent) {
|
|
279
|
+
return head + `
|
|
280
|
+
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.
|
|
281
|
+
|
|
282
|
+
----- BEGIN FILE CONTENT -----
|
|
283
|
+
${options.inlineContent}
|
|
284
|
+
----- END FILE CONTENT -----`;
|
|
285
|
+
}
|
|
158
286
|
if (options?.inlineContentPlaceholder) {
|
|
159
287
|
return head + `
|
|
160
288
|
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 +781,14 @@ async function callOpenAIWithPublicMcp(prompt, service, owner, messages, system,
|
|
|
653
781
|
});
|
|
654
782
|
}
|
|
655
783
|
async function notifyAgentSaveAttachment(info) {
|
|
656
|
-
const { platform, service, owner, attachment } = info;
|
|
657
|
-
const
|
|
658
|
-
const placeholder =
|
|
659
|
-
const extractContent =
|
|
784
|
+
const { platform, service, owner, attachment, parsedContent } = info;
|
|
785
|
+
const serverExtract = !parsedContent && isServerExtractable(attachment.name, attachment.mime);
|
|
786
|
+
const placeholder = serverExtract ? makeExtractPlaceholder(attachment.storagePath) : void 0;
|
|
787
|
+
const extractContent = serverExtract && placeholder ? [{ path: attachment.storagePath, placeholder, name: attachment.name, mime: attachment.mime }] : void 0;
|
|
660
788
|
const skapiExtract = extractContent && extractContent.length ? { _skapi_extract: extractContent } : {};
|
|
661
789
|
const userMessage = buildIndexingUserMessage(
|
|
662
790
|
attachment,
|
|
663
|
-
placeholder ? { inlineContentPlaceholder: placeholder } : void 0
|
|
791
|
+
parsedContent ? { inlineContent: parsedContent } : placeholder ? { inlineContentPlaceholder: placeholder } : void 0
|
|
664
792
|
);
|
|
665
793
|
const systemPrompt = buildIndexingSystemPrompt({
|
|
666
794
|
service,
|
|
@@ -1862,44 +1990,49 @@ var ChatSession = class {
|
|
|
1862
1990
|
att.storagePath = member.storagePath;
|
|
1863
1991
|
}
|
|
1864
1992
|
var mime = member.file.type || self.host.getMimeType(member.file.name);
|
|
1865
|
-
return
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
url
|
|
1879
|
-
}
|
|
1880
|
-
}).then(function(ack) {
|
|
1881
|
-
if (ack && typeof ack.id === "string") {
|
|
1882
|
-
self.bgTaskQueue.push({
|
|
1883
|
-
serviceId: id.serviceId,
|
|
1884
|
-
platform: id.platform,
|
|
1885
|
-
id: ack.id,
|
|
1886
|
-
filename: member.file.name,
|
|
1993
|
+
return Promise.resolve(
|
|
1994
|
+
parseAttachmentContent(member.file, member.file.name, mime || void 0)
|
|
1995
|
+
).then(function(parsedContent) {
|
|
1996
|
+
return notifyAgentSaveAttachment({
|
|
1997
|
+
platform: id.platform,
|
|
1998
|
+
model: id.model,
|
|
1999
|
+
service: id.serviceId,
|
|
2000
|
+
owner: id.owner,
|
|
2001
|
+
userId: id.userId || id.serviceId,
|
|
2002
|
+
serviceName: id.serviceName,
|
|
2003
|
+
serviceDescription: id.serviceDescription,
|
|
2004
|
+
attachment: {
|
|
2005
|
+
name: member.file.name,
|
|
1887
2006
|
storagePath: member.storagePath,
|
|
1888
|
-
isReindex: hadExists,
|
|
1889
2007
|
mime: mime || void 0,
|
|
1890
2008
|
size: member.file.size,
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
2009
|
+
url
|
|
2010
|
+
},
|
|
2011
|
+
parsedContent: parsedContent || void 0
|
|
2012
|
+
}).then(function(ack) {
|
|
2013
|
+
if (ack && typeof ack.id === "string") {
|
|
2014
|
+
self.bgTaskQueue.push({
|
|
2015
|
+
serviceId: id.serviceId,
|
|
2016
|
+
platform: id.platform,
|
|
2017
|
+
id: ack.id,
|
|
2018
|
+
filename: member.file.name,
|
|
2019
|
+
storagePath: member.storagePath,
|
|
2020
|
+
isReindex: hadExists,
|
|
2021
|
+
mime: mime || void 0,
|
|
2022
|
+
size: member.file.size,
|
|
2023
|
+
status: ack.status === "running" ? "running" : "pending",
|
|
2024
|
+
poll: ack.poll
|
|
2025
|
+
});
|
|
2026
|
+
self.drainBgTaskQueue();
|
|
2027
|
+
}
|
|
2028
|
+
}, function(e) {
|
|
2029
|
+
console.error("[chat-engine] indexing request failed", e);
|
|
2030
|
+
anyIndexFailed = true;
|
|
2031
|
+
if (!att.errorCode && !att.errorDetail) {
|
|
2032
|
+
att.errorCode = e && (e.code || e.body && e.body.code) || "";
|
|
2033
|
+
att.errorDetail = e && (e.message || e.body && e.body.message) || (typeof e === "string" ? e : "");
|
|
2034
|
+
}
|
|
2035
|
+
});
|
|
1903
2036
|
});
|
|
1904
2037
|
});
|
|
1905
2038
|
});
|
|
@@ -1979,6 +2112,6 @@ var ChatSession = class {
|
|
|
1979
2112
|
}
|
|
1980
2113
|
};
|
|
1981
2114
|
|
|
1982
|
-
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 };
|
|
2115
|
+
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, isServerExtractable, listClaudeModels, listOpenAIModels, makeExtractPlaceholder, mapHistoryListToMessages, normalizeAttachmentPathCandidate, normalizeTextContent, notifyAgentSaveAttachment, parseAttachmentContent, registerAttachmentParser, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay };
|
|
1983
2116
|
//# sourceMappingURL=engine.mjs.map
|
|
1984
2117
|
//# sourceMappingURL=engine.mjs.map
|