@openclaw/ai 0.0.0 → 2026.7.1-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/LICENSE +21 -0
- package/README.md +27 -3
- package/dist/anthropic-B5gZQM5X.mjs +1383 -0
- package/dist/api-registry-BXYnCOIR.d.mts +33 -0
- package/dist/azure-openai-responses-DNoSk8Uy.mjs +141 -0
- package/dist/azure-openai-responses-client-compat-a_O_GVQV.mjs +41 -0
- package/dist/diagnostics-BaTA9eVl.d.mts +25 -0
- package/dist/diagnostics-COpOtRwq.mjs +36 -0
- package/dist/diagnostics.d.mts +2 -0
- package/dist/diagnostics.mjs +2 -0
- package/dist/env-api-keys-CtMlqaQ4.mjs +171 -0
- package/dist/event-stream-0nZeBKl2.d.mts +26 -0
- package/dist/event-stream-ReMmOTzX.mjs +65 -0
- package/dist/event-stream.d.mts +2 -0
- package/dist/event-stream.mjs +2 -0
- package/dist/github-copilot-headers-BsH5cqGj.mjs +48 -0
- package/dist/google-D6sIQ1bL.mjs +55 -0
- package/dist/google-shared-ZPSl2qTi.mjs +548 -0
- package/dist/google-vertex-rDGwkoZK.mjs +111 -0
- package/dist/hash-CHgqbJmD.mjs +16 -0
- package/dist/headers-B_e4-1J0.mjs +9 -0
- package/dist/host-4t713IeR.mjs +37 -0
- package/dist/index-BoTnz8cv.d.mts +74 -0
- package/dist/index.d.mts +69 -0
- package/dist/index.mjs +7 -0
- package/dist/internal/anthropic.d.mts +234 -0
- package/dist/internal/anthropic.mjs +4 -0
- package/dist/internal/openai.d.mts +244 -0
- package/dist/internal/openai.mjs +7 -0
- package/dist/internal/runtime.d.mts +245 -0
- package/dist/internal/runtime.mjs +176 -0
- package/dist/internal/shared.d.mts +48 -0
- package/dist/internal/shared.mjs +3 -0
- package/dist/json-parse-DzNSIQBq.mjs +134 -0
- package/dist/llm-request-activity-CehVkZP-.mjs +35 -0
- package/dist/mistral-CePVNdws.mjs +563 -0
- package/dist/model-utils-DgmOla96.mjs +69 -0
- package/dist/openai-chatgpt-jwt-DhAAzLkj.mjs +39 -0
- package/dist/openai-chatgpt-responses-DVC4Bk_A.mjs +1068 -0
- package/dist/openai-completions-B9QLIq2U.mjs +844 -0
- package/dist/openai-responses-B6LylGxM.mjs +136 -0
- package/dist/openai-responses-shared-sj2YUPYc.mjs +1944 -0
- package/dist/openai-tool-projection-BknoV11q.mjs +195 -0
- package/dist/providers.d.mts +11 -0
- package/dist/providers.mjs +109 -0
- package/dist/reasoning-tag-text-partitioner-axhAdUwg.mjs +394 -0
- package/dist/sanitize-unicode-BZiVbGwK.d.mts +24 -0
- package/dist/sanitize-unicode-DT5o51ur.mjs +26 -0
- package/dist/src-CZ503MYJ.mjs +99 -0
- package/dist/stream-CREqxHgU.mjs +74 -0
- package/dist/stream-first-event-timeout-RjWszj8c.mjs +106 -0
- package/dist/streaming-byte-guard-BrbkbwUu.mjs +46 -0
- package/dist/tool-schema-json-projection-BXtBc_mD.mjs +74 -0
- package/dist/transform-messages-BhGF_fF4.mjs +507 -0
- package/dist/types-BVVgDSdq.d.mts +1 -0
- package/dist/types-DRgdPqaZ.d.mts +587 -0
- package/dist/types.d.mts +6 -0
- package/dist/types.mjs +5 -0
- package/dist/validation-BDMWOr8d.d.mts +9 -0
- package/dist/validation-FrchoOlv.mjs +199 -0
- package/dist/validation.d.mts +2 -0
- package/dist/validation.mjs +2 -0
- package/npm-shrinkwrap.json +645 -0
- package/package.json +74 -2
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { n as getEnvApiKey, t as findEnvKeys } from "../env-api-keys-CtMlqaQ4.mjs";
|
|
2
|
+
import { n as createApiRegistry, t as createLlmRuntime } from "../stream-CREqxHgU.mjs";
|
|
3
|
+
import { a as modelsAreEqual, i as getSupportedThinkingLevels, n as calculateCost, r as clampThinkingLevel, t as applyProviderReportedUsageCost } from "../model-utils-DgmOla96.mjs";
|
|
4
|
+
import { n as onLlmRequestActivity, r as createDeferredEventBuffer, t as notifyLlmRequestActivity } from "../llm-request-activity-CehVkZP-.mjs";
|
|
5
|
+
import { t as headersToRecord } from "../headers-B_e4-1J0.mjs";
|
|
6
|
+
import { n as parseStreamingJson, r as repairJson, t as parseJsonWithRepair } from "../json-parse-DzNSIQBq.mjs";
|
|
7
|
+
import { t as sanitizeSurrogates } from "../sanitize-unicode-DT5o51ur.mjs";
|
|
8
|
+
import { t as createReasoningTagTextPartitioner } from "../reasoning-tag-text-partitioner-axhAdUwg.mjs";
|
|
9
|
+
import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, n as createFirstStreamEventTimeoutError, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "../stream-first-event-timeout-RjWszj8c.mjs";
|
|
10
|
+
import { t as shortHash } from "../hash-CHgqbJmD.mjs";
|
|
11
|
+
import { i as registerSessionResourceCleanup, n as resolveOpenAICodexAccountId, r as cleanupSessionResources, t as decodeOpenAICodexJwtPayload } from "../openai-chatgpt-jwt-DhAAzLkj.mjs";
|
|
12
|
+
import { t as createSseByteGuard } from "../streaming-byte-guard-BrbkbwUu.mjs";
|
|
13
|
+
//#region packages/ai/src/internal/default-runtime.ts
|
|
14
|
+
const DEFAULT_RUNTIME_KEY = Symbol.for("openclaw.ai.defaultRuntime");
|
|
15
|
+
function resolveDefaultRuntime() {
|
|
16
|
+
const globalStore = globalThis;
|
|
17
|
+
if (Object.hasOwn(globalStore, DEFAULT_RUNTIME_KEY)) return globalStore[DEFAULT_RUNTIME_KEY];
|
|
18
|
+
const registry = createApiRegistry();
|
|
19
|
+
const state = {
|
|
20
|
+
registry,
|
|
21
|
+
runtime: createLlmRuntime(registry)
|
|
22
|
+
};
|
|
23
|
+
globalStore[DEFAULT_RUNTIME_KEY] = state;
|
|
24
|
+
return state;
|
|
25
|
+
}
|
|
26
|
+
const defaultRuntime = resolveDefaultRuntime();
|
|
27
|
+
const defaultApiRegistry = defaultRuntime.registry;
|
|
28
|
+
const defaultLlmRuntime = defaultRuntime.runtime;
|
|
29
|
+
const { registerApiProvider, getApiProvider, getApiProviders, unregisterApiProviders, clearApiProviders } = defaultApiRegistry;
|
|
30
|
+
const { stream, complete, streamSimple, completeSimple } = defaultLlmRuntime;
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region packages/ai/src/utils/overflow.ts
|
|
33
|
+
const CONFIGURED_CONTEXT_SIZE_OVERFLOW_RE = /prompt has [\d,]+ tokens?, but the configured context size is [\d,]+ tokens?/i;
|
|
34
|
+
/** Detects DS4-style raw token-count context overflow errors. */
|
|
35
|
+
function isConfiguredContextSizeOverflowError(errorMessage) {
|
|
36
|
+
return CONFIGURED_CONTEXT_SIZE_OVERFLOW_RE.test(errorMessage);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Regex patterns to detect context overflow errors from different providers.
|
|
40
|
+
*
|
|
41
|
+
* These patterns match error messages returned when the input exceeds
|
|
42
|
+
* the model's context window.
|
|
43
|
+
*
|
|
44
|
+
* Provider-specific patterns (with example error messages):
|
|
45
|
+
*
|
|
46
|
+
* - Anthropic: "prompt is too long: 213462 tokens > 200000 maximum"
|
|
47
|
+
* - Anthropic: "413 {\"error\":{\"type\":\"request_too_large\",\"message\":\"Request exceeds the maximum size\"}}"
|
|
48
|
+
* - OpenAI: "Your input exceeds the context window of this model"
|
|
49
|
+
* - OpenAI/LiteLLM: "Requested token count exceeds the model's maximum context length of 131072 tokens"
|
|
50
|
+
* - Google: "The input token count (1196265) exceeds the maximum number of tokens allowed (1048575)"
|
|
51
|
+
* - xAI: "This model's maximum prompt length is 131072 but the request contains 537812 tokens"
|
|
52
|
+
* - Groq: "Please reduce the length of the messages or completion"
|
|
53
|
+
* - OpenRouter: "This endpoint's maximum context length is X tokens. However, you requested about Y tokens"
|
|
54
|
+
* - Together AI: "The input (X tokens) is longer than the model's context length (Y tokens)."
|
|
55
|
+
* - llama.cpp: "the request exceeds the available context size, try increasing it"
|
|
56
|
+
* - LM Studio: "tokens to keep from the initial prompt is greater than the context length"
|
|
57
|
+
* - GitHub Copilot: "prompt token count of X exceeds the limit of Y"
|
|
58
|
+
* - MiniMax: "invalid params, context window exceeds limit"
|
|
59
|
+
* - Kimi For Coding: "Your request exceeded model token limit: X (requested: Y)"
|
|
60
|
+
* - Cerebras: "400/413 status code (no body)"
|
|
61
|
+
* - Mistral: "Prompt contains X tokens ... too large for model with Y maximum context length"
|
|
62
|
+
* - z.ai: Does NOT error, accepts overflow silently - handled via usage.input > contextWindow
|
|
63
|
+
* - Xiaomi MiMo: Truncates input to fill contextWindow exactly, then returns finish_reason "length"
|
|
64
|
+
* with output=0 (no room left to generate). Detected via stopReason "length" + zero output +
|
|
65
|
+
* input filling the context window.
|
|
66
|
+
* - Ollama: Some deployments truncate silently, others return errors like "prompt too long; exceeded max context length by X tokens"
|
|
67
|
+
*/
|
|
68
|
+
const OVERFLOW_PATTERNS = [
|
|
69
|
+
/prompt is too long/i,
|
|
70
|
+
/request_too_large/i,
|
|
71
|
+
/input is too long for requested model/i,
|
|
72
|
+
/exceeds the context window/i,
|
|
73
|
+
/exceeds (?:the )?(?:model'?s )?maximum context length of [\d,]+ tokens?/i,
|
|
74
|
+
/input token count.*exceeds the maximum/i,
|
|
75
|
+
/maximum prompt length is \d+/i,
|
|
76
|
+
/reduce the length of the messages/i,
|
|
77
|
+
/maximum context length is \d+ tokens/i,
|
|
78
|
+
/input \(\d+ tokens\) is longer than the model'?s context length \(\d+ tokens\)/i,
|
|
79
|
+
/exceeds the limit of \d+/i,
|
|
80
|
+
/exceeds the available context size/i,
|
|
81
|
+
/greater than the context length/i,
|
|
82
|
+
/context window exceeds limit/i,
|
|
83
|
+
/exceeded model token limit/i,
|
|
84
|
+
/too large for model with \d+ maximum context length/i,
|
|
85
|
+
CONFIGURED_CONTEXT_SIZE_OVERFLOW_RE,
|
|
86
|
+
/model_context_window_exceeded/i,
|
|
87
|
+
/prompt too long; exceeded (?:max )?context length/i,
|
|
88
|
+
/context[_ ]length[_ ]exceeded/i,
|
|
89
|
+
/too many tokens/i,
|
|
90
|
+
/token limit exceeded/i,
|
|
91
|
+
/^4(?:00|13)\s*(?:status code)?\s*\(no body\)/i
|
|
92
|
+
];
|
|
93
|
+
/**
|
|
94
|
+
* Patterns that indicate non-overflow errors (e.g. rate limiting, server errors).
|
|
95
|
+
* Error messages matching unknown of these are excluded from overflow detection
|
|
96
|
+
* even if they also match an OVERFLOW_PATTERN.
|
|
97
|
+
*
|
|
98
|
+
* Example: Bedrock formats throttling errors as "ThrottlingException: Too many tokens,
|
|
99
|
+
* please wait before trying again." which would match the /too many tokens/i overflow
|
|
100
|
+
* pattern without this exclusion.
|
|
101
|
+
*/
|
|
102
|
+
const NON_OVERFLOW_PATTERNS = [
|
|
103
|
+
/^(Throttling error|Service unavailable):/i,
|
|
104
|
+
/rate limit/i,
|
|
105
|
+
/too many requests/i
|
|
106
|
+
];
|
|
107
|
+
function resolveContextInputTokens(message) {
|
|
108
|
+
if (message.usage.contextUsage?.state === "available") return message.usage.contextUsage.promptTokens;
|
|
109
|
+
if (message.usage.contextUsage?.state === "unavailable") return;
|
|
110
|
+
return message.usage.input + message.usage.cacheRead;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Check if an assistant message represents a context overflow error.
|
|
114
|
+
*
|
|
115
|
+
* This handles two cases:
|
|
116
|
+
* 1. Error-based overflow: Most providers return stopReason "error" with a
|
|
117
|
+
* specific error message pattern.
|
|
118
|
+
* 2. Silent overflow: Some providers accept overflow requests and return
|
|
119
|
+
* successfully. For these, we check if usage.input exceeds the context window.
|
|
120
|
+
*
|
|
121
|
+
* ## Reliability by Provider
|
|
122
|
+
*
|
|
123
|
+
* **Reliable detection (returns error with detectable message):**
|
|
124
|
+
* - Anthropic: "prompt is too long: X tokens > Y maximum" or "request_too_large"
|
|
125
|
+
* - OpenAI (Completions & Responses): "exceeds the context window" or "exceeds the model's maximum context length of X tokens"
|
|
126
|
+
* - Google Gemini: "input token count exceeds the maximum"
|
|
127
|
+
* - xAI (Grok): "maximum prompt length is X but request contains Y"
|
|
128
|
+
* - Groq: "reduce the length of the messages"
|
|
129
|
+
* - Cerebras: 400/413 status code (no body)
|
|
130
|
+
* - Mistral: "Prompt contains X tokens ... too large for model with Y maximum context length"
|
|
131
|
+
* - OpenRouter (all backends): "maximum context length is X tokens"
|
|
132
|
+
* - Together AI: "The input (X tokens) is longer than the model's context length (Y tokens)."
|
|
133
|
+
* - llama.cpp: "exceeds the available context size"
|
|
134
|
+
* - LM Studio: "greater than the context length"
|
|
135
|
+
* - Kimi For Coding: "exceeded model token limit: X (requested: Y)"
|
|
136
|
+
*
|
|
137
|
+
* **Unreliable detection:**
|
|
138
|
+
* - z.ai: Sometimes accepts overflow silently (detectable via usage.input > contextWindow),
|
|
139
|
+
* sometimes returns rate limit errors. Pass contextWindow param to detect silent overflow.
|
|
140
|
+
* - Xiaomi MiMo: Truncates input to fit contextWindow then returns stopReason "length" with
|
|
141
|
+
* output=0. Pass contextWindow param to detect via the "filled context + zero output" signal.
|
|
142
|
+
* - Ollama: May truncate input silently for some setups, but may also return explicit
|
|
143
|
+
* overflow errors that match the patterns above. Silent truncation still cannot be
|
|
144
|
+
* detected here because we do not know the expected token count.
|
|
145
|
+
*
|
|
146
|
+
* ## Custom Providers
|
|
147
|
+
*
|
|
148
|
+
* If you've added custom models via settings.json, this function may not detect
|
|
149
|
+
* overflow errors from those providers. To add support:
|
|
150
|
+
*
|
|
151
|
+
* 1. Send a request that exceeds the model's context window
|
|
152
|
+
* 2. Check the errorMessage in the response
|
|
153
|
+
* 3. Create a regex pattern that matches the error
|
|
154
|
+
* 4. The pattern should be added to OVERFLOW_PATTERNS in this file, or
|
|
155
|
+
* check the errorMessage yourself before calling this function
|
|
156
|
+
*
|
|
157
|
+
* @param message - The assistant message to check
|
|
158
|
+
* @param contextWindow - Optional context window size for detecting silent overflow (z.ai)
|
|
159
|
+
* @returns true if the message indicates a context overflow
|
|
160
|
+
*/
|
|
161
|
+
function isContextOverflow(message, contextWindow) {
|
|
162
|
+
if (message.stopReason === "error" && message.errorMessage) {
|
|
163
|
+
if (!NON_OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage)) && OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage))) return true;
|
|
164
|
+
}
|
|
165
|
+
if (contextWindow && message.stopReason === "stop") {
|
|
166
|
+
const inputTokens = resolveContextInputTokens(message);
|
|
167
|
+
if (inputTokens !== void 0 && inputTokens > contextWindow) return true;
|
|
168
|
+
}
|
|
169
|
+
if (contextWindow && message.stopReason === "length" && message.usage.output === 0) {
|
|
170
|
+
const inputTokens = resolveContextInputTokens(message);
|
|
171
|
+
if (inputTokens !== void 0 && inputTokens >= contextWindow * .99) return true;
|
|
172
|
+
}
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
//#endregion
|
|
176
|
+
export { applyProviderReportedUsageCost, calculateCost, clampThinkingLevel, cleanupSessionResources, clearApiProviders, complete, completeSimple, createDeferredEventBuffer, createFirstStreamEventAbortController, createFirstStreamEventTimeoutError, createReasoningTagTextPartitioner, createSseByteGuard, decodeOpenAICodexJwtPayload, defaultApiRegistry, defaultLlmRuntime, findEnvKeys, getApiProvider, getApiProviders, getEnvApiKey, getFirstStreamEventTimeoutHandler, getFirstStreamEventTimeoutMs, getSupportedThinkingLevels, headersToRecord, isConfiguredContextSizeOverflowError, isContextOverflow, modelsAreEqual, notifyLlmRequestActivity, onLlmRequestActivity, parseJsonWithRepair, parseStreamingJson, registerApiProvider, registerSessionResourceCleanup, repairJson, resolveOpenAICodexAccountId, sanitizeSurrogates, shortHash, stream, streamSimple, unregisterApiProviders, withFirstStreamEventTimeout };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { E as Model, F as SimpleStreamOptions, H as ThinkingBudgets, T as Message, W as ThinkingLevel, i as AssistantMessage, n as Api, z as StreamOptions } from "../types-DRgdPqaZ.mjs";
|
|
2
|
+
import { t as sanitizeSurrogates } from "../sanitize-unicode-BZiVbGwK.mjs";
|
|
3
|
+
|
|
4
|
+
//#region packages/ai/src/providers/simple-options.d.ts
|
|
5
|
+
type FirstEventStreamOptions = {
|
|
6
|
+
firstEventTimeoutMs?: number;
|
|
7
|
+
onFirstEventTimeout?: (reason: Error) => void;
|
|
8
|
+
};
|
|
9
|
+
declare function buildBaseOptions(model: Model, options?: SimpleStreamOptions, apiKey?: string): StreamOptions & FirstEventStreamOptions;
|
|
10
|
+
declare function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, "xhigh"> | undefined;
|
|
11
|
+
declare function adjustMaxTokensForThinking(baseMaxTokens: number | undefined, modelMaxTokens: number, reasoningLevel: ThinkingLevel, customBudgets?: ThinkingBudgets): {
|
|
12
|
+
maxTokens: number;
|
|
13
|
+
thinkingBudget: number;
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region packages/ai/src/providers/tool-result-text.d.ts
|
|
17
|
+
declare function describeToolResultMediaPlaceholder(blocks: readonly unknown[]): string | undefined;
|
|
18
|
+
declare function extractToolResultBlockText(block: unknown): string | undefined;
|
|
19
|
+
declare function extractToolResultText(blocks: readonly unknown[]): string;
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region packages/ai/src/providers/transform-messages.d.ts
|
|
22
|
+
/**
|
|
23
|
+
* Normalize tool call ID for cross-provider compatibility.
|
|
24
|
+
* OpenAI Responses API generates IDs that are 450+ chars with special characters like `|`.
|
|
25
|
+
* Anthropic APIs require IDs matching ^[a-zA-Z0-9_-]+$ (max 64 chars).
|
|
26
|
+
*/
|
|
27
|
+
declare function transformMessages<TApi extends Api>(messages: Message[], model: Model<TApi>, normalizeToolCallId?: (id: string, model: Model<TApi>, source: AssistantMessage) => string): Message[];
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region packages/ai/src/utils/prompt-cache-stability.d.ts
|
|
30
|
+
/** Normalize structured prompt text before hashing or snapshot comparison. */
|
|
31
|
+
declare function normalizeStructuredPromptSection(text: string): string;
|
|
32
|
+
/** Normalize, de-dupe, and sort capability ids for stable prompt payloads. */
|
|
33
|
+
declare function normalizePromptCapabilityIds(capabilities: ReadonlyArray<string>): string[];
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region packages/ai/src/utils/system-prompt-cache-boundary.d.ts
|
|
36
|
+
declare const SYSTEM_PROMPT_CACHE_BOUNDARY = "\n<!-- OPENCLAW_CACHE_BOUNDARY -->\n";
|
|
37
|
+
declare function stripSystemPromptCacheBoundary(text: string): string;
|
|
38
|
+
declare function ensureSystemPromptCacheBoundary(systemPrompt: string): string;
|
|
39
|
+
declare function splitSystemPromptCacheBoundary(text: string): {
|
|
40
|
+
stablePrefix: string;
|
|
41
|
+
dynamicSuffix: string;
|
|
42
|
+
} | undefined;
|
|
43
|
+
declare function prependSystemPromptAdditionAfterCacheBoundary(params: {
|
|
44
|
+
systemPrompt: string;
|
|
45
|
+
systemPromptAddition?: string;
|
|
46
|
+
}): string;
|
|
47
|
+
//#endregion
|
|
48
|
+
export { SYSTEM_PROMPT_CACHE_BOUNDARY, adjustMaxTokensForThinking, buildBaseOptions, clampReasoning, describeToolResultMediaPlaceholder, ensureSystemPromptCacheBoundary, extractToolResultBlockText, extractToolResultText, normalizePromptCapabilityIds, normalizeStructuredPromptSection, prependSystemPromptAdditionAfterCacheBoundary, sanitizeSurrogates, splitSystemPromptCacheBoundary, stripSystemPromptCacheBoundary, transformMessages };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { t as sanitizeSurrogates } from "../sanitize-unicode-DT5o51ur.mjs";
|
|
2
|
+
import { S as normalizeStructuredPromptSection, _ as ensureSystemPromptCacheBoundary, a as adjustMaxTokensForThinking, b as stripSystemPromptCacheBoundary, g as SYSTEM_PROMPT_CACHE_BOUNDARY, i as extractToolResultText, n as describeToolResultMediaPlaceholder, o as buildBaseOptions, r as extractToolResultBlockText, s as clampReasoning, t as transformMessages, v as prependSystemPromptAdditionAfterCacheBoundary, x as normalizePromptCapabilityIds, y as splitSystemPromptCacheBoundary } from "../transform-messages-BhGF_fF4.mjs";
|
|
3
|
+
export { SYSTEM_PROMPT_CACHE_BOUNDARY, adjustMaxTokensForThinking, buildBaseOptions, clampReasoning, describeToolResultMediaPlaceholder, ensureSystemPromptCacheBoundary, extractToolResultBlockText, extractToolResultText, normalizePromptCapabilityIds, normalizeStructuredPromptSection, prependSystemPromptAdditionAfterCacheBoundary, sanitizeSurrogates, splitSystemPromptCacheBoundary, stripSystemPromptCacheBoundary, transformMessages };
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { parse } from "partial-json";
|
|
2
|
+
//#region packages/ai/src/utils/json-parse.ts
|
|
3
|
+
const VALID_JSON_ESCAPES = /* @__PURE__ */ new Set([
|
|
4
|
+
"\"",
|
|
5
|
+
"\\",
|
|
6
|
+
"/",
|
|
7
|
+
"b",
|
|
8
|
+
"f",
|
|
9
|
+
"n",
|
|
10
|
+
"r",
|
|
11
|
+
"t",
|
|
12
|
+
"u"
|
|
13
|
+
]);
|
|
14
|
+
const JSON_CONTROL_ESCAPES = /* @__PURE__ */ new Set([
|
|
15
|
+
"b",
|
|
16
|
+
"f",
|
|
17
|
+
"n",
|
|
18
|
+
"r",
|
|
19
|
+
"t"
|
|
20
|
+
]);
|
|
21
|
+
function isControlCharacter(char) {
|
|
22
|
+
const codePoint = char.codePointAt(0);
|
|
23
|
+
return codePoint !== void 0 && codePoint >= 0 && codePoint <= 31;
|
|
24
|
+
}
|
|
25
|
+
function escapeControlCharacter(char) {
|
|
26
|
+
switch (char) {
|
|
27
|
+
case "\b": return "\\b";
|
|
28
|
+
case "\f": return "\\f";
|
|
29
|
+
case "\n": return "\\n";
|
|
30
|
+
case "\r": return "\\r";
|
|
31
|
+
case " ": return "\\t";
|
|
32
|
+
default: return `\\u${char.codePointAt(0)?.toString(16).padStart(4, "0") ?? "0000"}`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Repairs malformed JSON string literals by:
|
|
37
|
+
* - escaping raw control characters inside strings
|
|
38
|
+
* - doubling backslashes before invalid escape characters
|
|
39
|
+
*/
|
|
40
|
+
function repairJson(json) {
|
|
41
|
+
let repaired = "";
|
|
42
|
+
let inString = false;
|
|
43
|
+
let stringValuePrefix = "";
|
|
44
|
+
for (let index = 0; index < json.length; index++) {
|
|
45
|
+
const char = json[index];
|
|
46
|
+
if (!inString) {
|
|
47
|
+
repaired += char;
|
|
48
|
+
if (char === "\"") {
|
|
49
|
+
inString = true;
|
|
50
|
+
stringValuePrefix = "";
|
|
51
|
+
}
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (char === "\"") {
|
|
55
|
+
repaired += char;
|
|
56
|
+
inString = false;
|
|
57
|
+
stringValuePrefix = "";
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (char === "\\") {
|
|
61
|
+
const nextChar = json[index + 1];
|
|
62
|
+
if (nextChar === void 0) {
|
|
63
|
+
repaired += "\\\\";
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (nextChar === "u") {
|
|
67
|
+
const unicodeDigits = json.slice(index + 2, index + 6);
|
|
68
|
+
if (/^[0-9a-fA-F]{4}$/.test(unicodeDigits)) {
|
|
69
|
+
repaired += `\\u${unicodeDigits}`;
|
|
70
|
+
stringValuePrefix += `\\u${unicodeDigits}`;
|
|
71
|
+
index += 5;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
repaired += "\\\\";
|
|
75
|
+
stringValuePrefix += "\\";
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (JSON_CONTROL_ESCAPES.has(nextChar) && looksLikeWindowsPathPrefix(stringValuePrefix)) {
|
|
79
|
+
repaired += "\\\\";
|
|
80
|
+
stringValuePrefix += "\\";
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (VALID_JSON_ESCAPES.has(nextChar)) {
|
|
84
|
+
repaired += `\\${nextChar}`;
|
|
85
|
+
stringValuePrefix += nextChar === "\\" ? "\\" : `\\${nextChar}`;
|
|
86
|
+
index += 1;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
repaired += "\\\\";
|
|
90
|
+
stringValuePrefix += "\\";
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
repaired += isControlCharacter(char) ? escapeControlCharacter(char) : char;
|
|
94
|
+
stringValuePrefix += char;
|
|
95
|
+
}
|
|
96
|
+
return repaired;
|
|
97
|
+
}
|
|
98
|
+
function parseJsonWithRepair(json) {
|
|
99
|
+
const repairedJson = repairJson(json);
|
|
100
|
+
if (repairedJson !== json) return JSON.parse(repairedJson);
|
|
101
|
+
return JSON.parse(json);
|
|
102
|
+
}
|
|
103
|
+
function looksLikeWindowsPathPrefix(prefix) {
|
|
104
|
+
const tail = prefix.slice(-160);
|
|
105
|
+
return /(?:^|[^A-Za-z0-9])[A-Za-z]:(?:[\\/][^"\\/:*?<>|\r\n]*)*$/.test(tail);
|
|
106
|
+
}
|
|
107
|
+
function asStreamingJsonRecord(value) {
|
|
108
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Attempts to parse potentially incomplete JSON during streaming.
|
|
112
|
+
* Always returns a valid object, even if the JSON is incomplete.
|
|
113
|
+
*
|
|
114
|
+
* @param partialJson The partial JSON string from streaming
|
|
115
|
+
* @returns Parsed object or empty object if parsing fails
|
|
116
|
+
*/
|
|
117
|
+
function parseStreamingJson(partialJson) {
|
|
118
|
+
if (!partialJson || partialJson.trim() === "") return {};
|
|
119
|
+
try {
|
|
120
|
+
return asStreamingJsonRecord(parseJsonWithRepair(partialJson));
|
|
121
|
+
} catch {
|
|
122
|
+
try {
|
|
123
|
+
return asStreamingJsonRecord(parse(partialJson));
|
|
124
|
+
} catch {
|
|
125
|
+
try {
|
|
126
|
+
return asStreamingJsonRecord(parse(repairJson(partialJson)));
|
|
127
|
+
} catch {
|
|
128
|
+
return {};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//#endregion
|
|
134
|
+
export { parseStreamingJson as n, repairJson as r, parseJsonWithRepair as t };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region packages/ai/src/utils/deferred-event-buffer.ts
|
|
2
|
+
function createDeferredEventBuffer(sink, onBufferedEvent) {
|
|
3
|
+
let events = [];
|
|
4
|
+
return {
|
|
5
|
+
push(event) {
|
|
6
|
+
events.push(event);
|
|
7
|
+
onBufferedEvent?.();
|
|
8
|
+
},
|
|
9
|
+
flush() {
|
|
10
|
+
for (const event of events) sink.push(event);
|
|
11
|
+
events = [];
|
|
12
|
+
},
|
|
13
|
+
discard() {
|
|
14
|
+
events = [];
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region packages/ai/src/utils/llm-request-activity.ts
|
|
20
|
+
const requestActivityListeners = /* @__PURE__ */ new WeakMap();
|
|
21
|
+
function notifyLlmRequestActivity(signal) {
|
|
22
|
+
if (!signal) return;
|
|
23
|
+
for (const listener of requestActivityListeners.get(signal) ?? []) listener();
|
|
24
|
+
}
|
|
25
|
+
function onLlmRequestActivity(signal, listener) {
|
|
26
|
+
const listeners = requestActivityListeners.get(signal) ?? /* @__PURE__ */ new Set();
|
|
27
|
+
listeners.add(listener);
|
|
28
|
+
requestActivityListeners.set(signal, listeners);
|
|
29
|
+
return () => {
|
|
30
|
+
listeners.delete(listener);
|
|
31
|
+
if (listeners.size === 0) requestActivityListeners.delete(signal);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { onLlmRequestActivity as n, createDeferredEventBuffer as r, notifyLlmRequestActivity as t };
|