@openclaw/ai 2026.7.2-beta.2 → 2026.7.2-beta.4
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 +6 -5
- package/dist/{anthropic-BIRSg5x9.mjs → anthropic-CrUDIBpM.mjs} +173 -47
- package/dist/{api-registry-Byvoz8Ha.d.mts → api-registry-BMphkFf1.d.mts} +1 -2
- package/dist/{azure-openai-responses-CHi7Wo4A.mjs → azure-openai-responses-CbrpVeEv.mjs} +9 -11
- package/dist/{env-api-keys-DnhYpc27.mjs → env-api-keys-DrgeBuva.mjs} +1 -1
- package/dist/{event-stream-uQspnL8S.d.mts → event-stream-Douf9dob.d.mts} +1 -1
- package/dist/event-stream.d.mts +1 -1
- package/dist/{google-BmsqsNwR.mjs → google-Cs62KA7t.mjs} +4 -4
- package/dist/{google-shared-Dx2aba47.mjs → google-shared-CMLI-tCZ.mjs} +4 -3
- package/dist/{google-vertex-HZ_0rTwS.mjs → google-vertex-B4SD3U0f.mjs} +3 -3
- package/dist/host-WvWBo4h8.d.mts +173 -0
- package/dist/host-XYGZcgO8.mjs +98 -0
- package/dist/index-BVVgDSdq.d.mts +1 -0
- package/dist/index.d.mts +7 -50
- package/dist/index.mjs +1 -1
- package/dist/internal/anthropic.d.mts +9 -3
- package/dist/internal/anthropic.mjs +3 -3
- package/dist/internal/openai.d.mts +2 -279
- package/dist/internal/openai.mjs +5 -5
- package/dist/internal/runtime.d.mts +8 -5
- package/dist/internal/runtime.mjs +22 -12
- package/dist/internal/shared.d.mts +4 -2
- package/dist/internal/shared.mjs +2 -2
- package/dist/{mistral-DxMPt9q9.mjs → mistral-D5Ps7Led.mjs} +26 -10
- package/dist/{model-utils-Q1LSRIdo.mjs → model-utils-1GiZ2_rr.mjs} +3 -1
- package/dist/openai-CoGicoDt.d.mts +332 -0
- package/dist/{openai-chatgpt-responses-BuH2NvsR.mjs → openai-chatgpt-responses-h0o5yV8Y.mjs} +47 -48
- package/dist/{openai-completions-DPR_O2RW.mjs → openai-completions-exO8NFQf.mjs} +342 -102
- package/dist/{openai-responses-Cov-Vdc2.mjs → openai-responses-BHpmtUKo.mjs} +5 -5
- package/dist/{openai-responses-shared-Befb4D6R.mjs → openai-responses-shared-CzCurmY1.mjs} +527 -268
- package/dist/{openai-tool-projection-CFqm42J2.mjs → openai-tool-projection-ITOU9bG1.mjs} +1 -1
- package/dist/provider-error-C4VvV_3t.mjs +41 -0
- package/dist/providers.d.mts +1 -1
- package/dist/providers.mjs +8 -8
- package/dist/{stream-first-event-timeout-RjWszj8c.mjs → stream-first-event-timeout-DP4xEyBY.mjs} +45 -1
- package/dist/{transform-messages-BmS70CP5.mjs → system-prompt-cache-boundary-CbHeV4_l.mjs} +171 -161
- package/dist/transports.d.mts +590 -0
- package/dist/transports.mjs +5701 -0
- package/dist/{types-Cx2zJtyz.d.mts → types-AFwwWium.d.mts} +7 -0
- package/dist/types.d.mts +4 -4
- package/dist/{validation-Cej7htKc.d.mts → validation-sxvxC8J-.d.mts} +1 -1
- package/dist/validation.d.mts +1 -1
- package/npm-shrinkwrap.json +43 -50
- package/package.json +36 -10
- package/dist/host-4t713IeR.mjs +0 -37
- /package/dist/{index-BoTnz8cv.d.mts → anthropic-BoTnz8cv.d.mts} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { T as isRecord } from "./system-prompt-cache-boundary-CbHeV4_l.mjs";
|
|
2
2
|
import { t as projectRuntimeToolInputSchema } from "./tool-schema-json-projection-BwNu3nDi.mjs";
|
|
3
3
|
//#region packages/ai/src/providers/openai-prompt-cache.ts
|
|
4
4
|
/** Maximum prompt cache key length accepted by OpenAI-compatible request metadata. */
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { w as truncateUtf16Safe } from "./system-prompt-cache-boundary-CbHeV4_l.mjs";
|
|
2
|
+
//#region packages/ai/src/utils/provider-error.ts
|
|
3
|
+
const MAX_ERROR_BODY_LENGTH = 4e3;
|
|
4
|
+
function stringify(value) {
|
|
5
|
+
try {
|
|
6
|
+
return JSON.stringify(value) ?? String(value);
|
|
7
|
+
} catch {
|
|
8
|
+
return String(value);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function readStatus(error) {
|
|
12
|
+
for (const value of [
|
|
13
|
+
error.status,
|
|
14
|
+
error.statusCode,
|
|
15
|
+
error.response?.status,
|
|
16
|
+
error.response?.statusCode
|
|
17
|
+
]) if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
18
|
+
}
|
|
19
|
+
function readBody(error) {
|
|
20
|
+
for (const value of [
|
|
21
|
+
error.body,
|
|
22
|
+
error.error,
|
|
23
|
+
error.response?.body,
|
|
24
|
+
error.response?.data
|
|
25
|
+
]) {
|
|
26
|
+
if (value === void 0 || value === null) continue;
|
|
27
|
+
if (typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0) continue;
|
|
28
|
+
const body = (typeof value === "string" ? value : stringify(value)).trim();
|
|
29
|
+
if (body.length > 0) return body.length <= MAX_ERROR_BODY_LENGTH ? body : `${truncateUtf16Safe(body, MAX_ERROR_BODY_LENGTH)}... [truncated]`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function formatProviderError(error) {
|
|
33
|
+
if (!(error instanceof Error)) return stringify(error);
|
|
34
|
+
const httpError = error;
|
|
35
|
+
const status = readStatus(httpError);
|
|
36
|
+
const body = readBody(httpError);
|
|
37
|
+
if (status === void 0 || body === void 0 || error.message.includes(body)) return error.message;
|
|
38
|
+
return `${status}: ${body}`;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { formatProviderError as t };
|
package/dist/providers.d.mts
CHANGED
package/dist/providers.mjs
CHANGED
|
@@ -63,35 +63,35 @@ function createLazyRegistration(api, importModule, select) {
|
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
65
|
const registerBuiltIns = [
|
|
66
|
-
createLazyRegistration("anthropic-messages", () => import("./anthropic-
|
|
66
|
+
createLazyRegistration("anthropic-messages", () => import("./anthropic-CrUDIBpM.mjs").then((n) => n.t), (module) => ({
|
|
67
67
|
stream: module.streamAnthropic,
|
|
68
68
|
streamSimple: module.streamSimpleAnthropic
|
|
69
69
|
})),
|
|
70
|
-
createLazyRegistration("openai-completions", () => import("./openai-completions-
|
|
70
|
+
createLazyRegistration("openai-completions", () => import("./openai-completions-exO8NFQf.mjs").then((n) => n.n), (module) => ({
|
|
71
71
|
stream: module.streamOpenAICompletions,
|
|
72
72
|
streamSimple: module.streamSimpleOpenAICompletions
|
|
73
73
|
})),
|
|
74
|
-
createLazyRegistration("mistral-conversations", () => import("./mistral-
|
|
74
|
+
createLazyRegistration("mistral-conversations", () => import("./mistral-D5Ps7Led.mjs"), (module) => ({
|
|
75
75
|
stream: module.streamMistral,
|
|
76
76
|
streamSimple: module.streamSimpleMistral
|
|
77
77
|
})),
|
|
78
|
-
createLazyRegistration("openai-responses", () => import("./openai-responses-
|
|
78
|
+
createLazyRegistration("openai-responses", () => import("./openai-responses-BHpmtUKo.mjs").then((n) => n.t), (module) => ({
|
|
79
79
|
stream: module.streamOpenAIResponses,
|
|
80
80
|
streamSimple: module.streamSimpleOpenAIResponses
|
|
81
81
|
})),
|
|
82
|
-
createLazyRegistration("azure-openai-responses", () => import("./azure-openai-responses-
|
|
82
|
+
createLazyRegistration("azure-openai-responses", () => import("./azure-openai-responses-CbrpVeEv.mjs"), (module) => ({
|
|
83
83
|
stream: module.streamAzureOpenAIResponses,
|
|
84
84
|
streamSimple: module.streamSimpleAzureOpenAIResponses
|
|
85
85
|
})),
|
|
86
|
-
createLazyRegistration("openai-chatgpt-responses", () => import("./openai-chatgpt-responses-
|
|
86
|
+
createLazyRegistration("openai-chatgpt-responses", () => import("./openai-chatgpt-responses-h0o5yV8Y.mjs"), (module) => ({
|
|
87
87
|
stream: module.streamOpenAICodexResponses,
|
|
88
88
|
streamSimple: module.streamSimpleOpenAICodexResponses
|
|
89
89
|
})),
|
|
90
|
-
createLazyRegistration("google-generative-ai", () => import("./google-
|
|
90
|
+
createLazyRegistration("google-generative-ai", () => import("./google-Cs62KA7t.mjs"), (module) => ({
|
|
91
91
|
stream: module.streamGoogle,
|
|
92
92
|
streamSimple: module.streamSimpleGoogle
|
|
93
93
|
})),
|
|
94
|
-
createLazyRegistration("google-vertex", () => import("./google-vertex-
|
|
94
|
+
createLazyRegistration("google-vertex", () => import("./google-vertex-B4SD3U0f.mjs"), (module) => ({
|
|
95
95
|
stream: module.streamGoogleVertex,
|
|
96
96
|
streamSimple: module.streamSimpleGoogleVertex
|
|
97
97
|
}))
|
package/dist/{stream-first-event-timeout-RjWszj8c.mjs → stream-first-event-timeout-DP4xEyBY.mjs}
RENAMED
|
@@ -3,6 +3,40 @@
|
|
|
3
3
|
function asFiniteNumber(value) {
|
|
4
4
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
5
5
|
}
|
|
6
|
+
/** Returns a finite number only when it satisfies the supplied inclusive/exclusive bounds. */
|
|
7
|
+
function asFiniteNumberInRange(value, range) {
|
|
8
|
+
const number = asFiniteNumber(value);
|
|
9
|
+
if (number === void 0) return;
|
|
10
|
+
if (range.min !== void 0) {
|
|
11
|
+
if (range.minExclusive ? number <= range.min : number < range.min) return;
|
|
12
|
+
}
|
|
13
|
+
if (range.max !== void 0) {
|
|
14
|
+
if (range.maxExclusive ? number >= range.max : number > range.max) return;
|
|
15
|
+
}
|
|
16
|
+
return number;
|
|
17
|
+
}
|
|
18
|
+
function normalizeNumericString(value) {
|
|
19
|
+
const trimmed = value.trim();
|
|
20
|
+
return trimmed ? trimmed : void 0;
|
|
21
|
+
}
|
|
22
|
+
/** Parses only safe integer numbers or base-10 integer strings. */
|
|
23
|
+
function parseStrictInteger(value) {
|
|
24
|
+
if (typeof value === "number") return Number.isSafeInteger(value) ? value : void 0;
|
|
25
|
+
if (typeof value !== "string") return;
|
|
26
|
+
const normalized = normalizeNumericString(value);
|
|
27
|
+
if (!normalized || !/^[+-]?\d+$/.test(normalized)) return;
|
|
28
|
+
const parsed = Number(normalized);
|
|
29
|
+
return Number.isSafeInteger(parsed) ? parsed : void 0;
|
|
30
|
+
}
|
|
31
|
+
/** Parses only finite decimal/scientific string tokens, rejecting partial numbers. */
|
|
32
|
+
function parseStrictFiniteNumber(value) {
|
|
33
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
|
|
34
|
+
if (typeof value !== "string") return;
|
|
35
|
+
const normalized = normalizeNumericString(value);
|
|
36
|
+
if (!normalized || !/^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))(?:e[+-]?\d+)?$/i.test(normalized)) return;
|
|
37
|
+
const parsed = Number(normalized);
|
|
38
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
39
|
+
}
|
|
6
40
|
/** Conservative upper bound for Node timer delays. */
|
|
7
41
|
const MAX_TIMER_TIMEOUT_MS = 2147e6;
|
|
8
42
|
/** Clamps finite millisecond values into the Node-safe timer range. */
|
|
@@ -18,6 +52,16 @@ function resolveTimerTimeoutMs(valueMs, fallbackMs, minMs = 1) {
|
|
|
18
52
|
if (value === void 0) return min;
|
|
19
53
|
return Math.min(Math.max(Math.floor(value), min), MAX_TIMER_TIMEOUT_MS);
|
|
20
54
|
}
|
|
55
|
+
/** Parses strict positive integer values from numbers or strings. */
|
|
56
|
+
function parseStrictPositiveInteger(value) {
|
|
57
|
+
const parsed = parseStrictInteger(value);
|
|
58
|
+
return parsed !== void 0 && parsed > 0 ? parsed : void 0;
|
|
59
|
+
}
|
|
60
|
+
/** Parses strict non-negative integer values from numbers or strings. */
|
|
61
|
+
function parseStrictNonNegativeInteger(value) {
|
|
62
|
+
const parsed = parseStrictInteger(value);
|
|
63
|
+
return parsed !== void 0 && parsed >= 0 ? parsed : void 0;
|
|
64
|
+
}
|
|
21
65
|
//#endregion
|
|
22
66
|
//#region packages/ai/src/utils/stream-first-event-timeout.ts
|
|
23
67
|
function getFirstStreamEventTimeoutMs(options) {
|
|
@@ -103,4 +147,4 @@ function withFirstStreamEventTimeout(stream, context) {
|
|
|
103
147
|
} };
|
|
104
148
|
}
|
|
105
149
|
//#endregion
|
|
106
|
-
export { withFirstStreamEventTimeout as a, getFirstStreamEventTimeoutMs as i, createFirstStreamEventTimeoutError as n,
|
|
150
|
+
export { withFirstStreamEventTimeout as a, parseStrictFiniteNumber as c, resolveTimerTimeoutMs as d, getFirstStreamEventTimeoutMs as i, parseStrictNonNegativeInteger as l, createFirstStreamEventTimeoutError as n, asFiniteNumberInRange as o, getFirstStreamEventTimeoutHandler as r, clampTimerTimeoutMs as s, createFirstStreamEventAbortController as t, parseStrictPositiveInteger as u };
|
|
@@ -1,164 +1,6 @@
|
|
|
1
1
|
import { a as resolveClaudeFable5ModelIdentity, i as requiresClaudeMandatoryAdaptiveThinking, l as resolveClaudeSonnet5ModelIdentity, r as requiresClaudeDefaultSampling, s as resolveClaudeMythos5ModelIdentity } from "./src-CXno1H5g.mjs";
|
|
2
|
-
import { n as getAiTransportHost } from "./host-
|
|
2
|
+
import { n as getAiTransportHost } from "./host-XYGZcgO8.mjs";
|
|
3
3
|
import { t as sanitizeSurrogates } from "./sanitize-unicode-DT5o51ur.mjs";
|
|
4
|
-
//#region packages/normalization-core/src/string-coerce.ts
|
|
5
|
-
/** Trims string input and returns null for non-strings or empty strings. */
|
|
6
|
-
function normalizeNullableString(value) {
|
|
7
|
-
if (typeof value !== "string") return null;
|
|
8
|
-
const trimmed = value.trim();
|
|
9
|
-
return trimmed ? trimmed : null;
|
|
10
|
-
}
|
|
11
|
-
/** Trims string input and returns undefined for non-strings or empty strings. */
|
|
12
|
-
function normalizeOptionalString(value) {
|
|
13
|
-
return normalizeNullableString(value) ?? void 0;
|
|
14
|
-
}
|
|
15
|
-
/** Lowercases a normalized optional string. */
|
|
16
|
-
function normalizeOptionalLowercaseString(value) {
|
|
17
|
-
return normalizeOptionalString(value)?.toLowerCase();
|
|
18
|
-
}
|
|
19
|
-
/** Lowercases a normalized string or returns an empty string when absent. */
|
|
20
|
-
function normalizeLowercaseStringOrEmpty(value) {
|
|
21
|
-
return normalizeOptionalLowercaseString(value) ?? "";
|
|
22
|
-
}
|
|
23
|
-
//#endregion
|
|
24
|
-
//#region packages/ai/src/utils/prompt-cache-stability.ts
|
|
25
|
-
/**
|
|
26
|
-
* Prompt-cache normalization helpers. They keep generated prompt sections
|
|
27
|
-
* deterministic across platform newlines, trailing whitespace, and input
|
|
28
|
-
* ordering.
|
|
29
|
-
*/
|
|
30
|
-
/** Normalize structured prompt text before hashing or snapshot comparison. */
|
|
31
|
-
function normalizeStructuredPromptSection(text) {
|
|
32
|
-
return sanitizeSurrogates(text).replace(/\r\n?/g, "\n").replace(/[ \t]+$/gm, "").trim();
|
|
33
|
-
}
|
|
34
|
-
/** Normalize, de-dupe, and sort capability ids for stable prompt payloads. */
|
|
35
|
-
function normalizePromptCapabilityIds(capabilities) {
|
|
36
|
-
const seen = /* @__PURE__ */ new Set();
|
|
37
|
-
const normalized = [];
|
|
38
|
-
for (const capability of capabilities) {
|
|
39
|
-
const value = normalizeLowercaseStringOrEmpty(normalizeStructuredPromptSection(capability));
|
|
40
|
-
if (!value || seen.has(value)) continue;
|
|
41
|
-
seen.add(value);
|
|
42
|
-
normalized.push(value);
|
|
43
|
-
}
|
|
44
|
-
return normalized.toSorted((left, right) => left.localeCompare(right));
|
|
45
|
-
}
|
|
46
|
-
//#endregion
|
|
47
|
-
//#region packages/ai/src/utils/system-prompt-cache-boundary.ts
|
|
48
|
-
/**
|
|
49
|
-
* System prompt cache-boundary helpers.
|
|
50
|
-
*
|
|
51
|
-
* Keeps stable prompt prefixes separate from dynamic runtime additions for provider prompt caching.
|
|
52
|
-
*/
|
|
53
|
-
const SYSTEM_PROMPT_CACHE_BOUNDARY = "\n<!-- OPENCLAW_CACHE_BOUNDARY -->\n";
|
|
54
|
-
function stripSystemPromptCacheBoundary(text) {
|
|
55
|
-
return text.replaceAll(SYSTEM_PROMPT_CACHE_BOUNDARY, "\n");
|
|
56
|
-
}
|
|
57
|
-
function ensureSystemPromptCacheBoundary(systemPrompt) {
|
|
58
|
-
if (systemPrompt.trim().length === 0) return systemPrompt;
|
|
59
|
-
return systemPrompt.includes("\n<!-- OPENCLAW_CACHE_BOUNDARY -->\n") ? systemPrompt : `${systemPrompt}${SYSTEM_PROMPT_CACHE_BOUNDARY}`;
|
|
60
|
-
}
|
|
61
|
-
function splitSystemPromptCacheBoundary(text) {
|
|
62
|
-
const boundaryIndex = text.indexOf(SYSTEM_PROMPT_CACHE_BOUNDARY);
|
|
63
|
-
if (boundaryIndex === -1) return;
|
|
64
|
-
return {
|
|
65
|
-
stablePrefix: text.slice(0, boundaryIndex).trimEnd(),
|
|
66
|
-
dynamicSuffix: text.slice(boundaryIndex + 34).trimStart()
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
function prependSystemPromptAdditionAfterCacheBoundary(params) {
|
|
70
|
-
const systemPromptAddition = typeof params.systemPromptAddition === "string" ? normalizeStructuredPromptSection(params.systemPromptAddition) : "";
|
|
71
|
-
if (!systemPromptAddition) return params.systemPrompt;
|
|
72
|
-
if (params.systemPrompt.trim().length === 0) return systemPromptAddition;
|
|
73
|
-
const split = splitSystemPromptCacheBoundary(params.systemPrompt);
|
|
74
|
-
if (!split) return `${systemPromptAddition}\n\n${params.systemPrompt}`;
|
|
75
|
-
const dynamicSuffix = split.dynamicSuffix ? normalizeStructuredPromptSection(split.dynamicSuffix) : "";
|
|
76
|
-
if (!dynamicSuffix) return `${split.stablePrefix}${SYSTEM_PROMPT_CACHE_BOUNDARY}${systemPromptAddition}`;
|
|
77
|
-
return `${split.stablePrefix}${SYSTEM_PROMPT_CACHE_BOUNDARY}${systemPromptAddition}\n\n${dynamicSuffix}`;
|
|
78
|
-
}
|
|
79
|
-
//#endregion
|
|
80
|
-
//#region packages/ai/src/providers/anthropic-model-contract.ts
|
|
81
|
-
function normalizeModelId(modelId) {
|
|
82
|
-
const normalized = normalizeLowercaseStringOrEmpty(modelId);
|
|
83
|
-
return (normalized.startsWith("anthropic/") ? normalized.slice(10) : normalized).replace(/[._\s]+/g, "-");
|
|
84
|
-
}
|
|
85
|
-
function normalizeApi(api) {
|
|
86
|
-
const normalized = normalizeLowercaseStringOrEmpty(api);
|
|
87
|
-
return normalized === "openclaw-anthropic-messages-transport" ? "anthropic-messages" : normalized;
|
|
88
|
-
}
|
|
89
|
-
function hasConcreteResponseModel(ref) {
|
|
90
|
-
const responseModelId = normalizeModelId(ref.responseModelId);
|
|
91
|
-
return responseModelId.length > 0 && responseModelId !== normalizeModelId(ref.modelId);
|
|
92
|
-
}
|
|
93
|
-
function usesClaudeFable5MessagesContract(model) {
|
|
94
|
-
return normalizeApi(model.api) === "anthropic-messages" && resolveClaudeFable5ModelIdentity(model) !== void 0;
|
|
95
|
-
}
|
|
96
|
-
/** Return whether streamed output must wait for the terminal refusal decision. */
|
|
97
|
-
function usesClaudeStreamingRefusalContract(model) {
|
|
98
|
-
if (normalizeApi(model.api) !== "anthropic-messages") return false;
|
|
99
|
-
return resolveClaudeFable5ModelIdentity(model) !== void 0 || resolveClaudeMythos5ModelIdentity(model) !== void 0 || resolveClaudeSonnet5ModelIdentity(model) !== void 0;
|
|
100
|
-
}
|
|
101
|
-
function requiresClaudeAdaptiveThinking(model) {
|
|
102
|
-
if (normalizeApi(model.api) !== "anthropic-messages") return false;
|
|
103
|
-
return requiresClaudeMandatoryAdaptiveThinking(model);
|
|
104
|
-
}
|
|
105
|
-
/** Return whether omitted thinking should default to adaptive/high. */
|
|
106
|
-
function defaultsClaudeAdaptiveThinking(model) {
|
|
107
|
-
return requiresClaudeAdaptiveThinking(model) || normalizeApi(model.api) === "anthropic-messages" && resolveClaudeSonnet5ModelIdentity(model) !== void 0;
|
|
108
|
-
}
|
|
109
|
-
/** Remove Sonnet 5 assistant prefills while preserving completed tool-use turns. */
|
|
110
|
-
function prepareClaudeSonnet5RequestContext(model, context) {
|
|
111
|
-
if (!resolveClaudeSonnet5ModelIdentity(model)) return context;
|
|
112
|
-
let end = context.messages.length;
|
|
113
|
-
while (end > 0) {
|
|
114
|
-
const message = context.messages[end - 1];
|
|
115
|
-
if (message?.role !== "assistant" || Array.isArray(message.content) && message.content.some((block) => block.type === "toolCall")) break;
|
|
116
|
-
end -= 1;
|
|
117
|
-
}
|
|
118
|
-
return end === context.messages.length ? context : {
|
|
119
|
-
...context,
|
|
120
|
-
messages: context.messages.slice(0, end)
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
function applyClaudeRequestContract(params, model) {
|
|
124
|
-
if (normalizeApi(model.api) !== "anthropic-messages") return;
|
|
125
|
-
const sonnet5 = resolveClaudeSonnet5ModelIdentity(model) !== void 0;
|
|
126
|
-
if (!requiresClaudeDefaultSampling(model) && !sonnet5) return;
|
|
127
|
-
delete params.temperature;
|
|
128
|
-
delete params.top_p;
|
|
129
|
-
delete params.top_k;
|
|
130
|
-
if (sonnet5) delete params.service_tier;
|
|
131
|
-
}
|
|
132
|
-
function resolveReplayModelBoundIdentity(ref) {
|
|
133
|
-
if (normalizeApi(ref.api) !== "anthropic-messages") return;
|
|
134
|
-
const modelRef = hasConcreteResponseModel(ref) ? { id: ref.responseModelId } : {
|
|
135
|
-
id: ref.modelId,
|
|
136
|
-
params: ref.modelParams
|
|
137
|
-
};
|
|
138
|
-
const fableIdentity = resolveClaudeFable5ModelIdentity(modelRef);
|
|
139
|
-
if (fableIdentity) return `fable:${fableIdentity}`;
|
|
140
|
-
const mythosIdentity = resolveClaudeMythos5ModelIdentity(modelRef);
|
|
141
|
-
if (mythosIdentity) return `mythos:${mythosIdentity}`;
|
|
142
|
-
const sonnetIdentity = resolveClaudeSonnet5ModelIdentity(modelRef);
|
|
143
|
-
return sonnetIdentity ? `sonnet:${sonnetIdentity}` : void 0;
|
|
144
|
-
}
|
|
145
|
-
function resolveModelBoundThinkingReplayMode(params) {
|
|
146
|
-
const sourceApi = normalizeApi(params.source.api);
|
|
147
|
-
const targetApi = normalizeApi(params.target.api);
|
|
148
|
-
const sourceIdentity = resolveReplayModelBoundIdentity(params.source);
|
|
149
|
-
const targetIdentity = resolveReplayModelBoundIdentity(params.target);
|
|
150
|
-
const sameRoute = normalizeLowercaseStringOrEmpty(params.source.provider) === normalizeLowercaseStringOrEmpty(params.target.provider) && sourceApi === targetApi && normalizeModelId(params.source.modelId) === normalizeModelId(params.target.modelId);
|
|
151
|
-
if (!sourceIdentity && !targetIdentity) return "default";
|
|
152
|
-
if (!sourceIdentity && !hasConcreteResponseModel(params.source) && targetIdentity && sameRoute) return "preserve";
|
|
153
|
-
return sourceApi === targetApi && sourceIdentity === targetIdentity ? "preserve" : "drop";
|
|
154
|
-
}
|
|
155
|
-
//#endregion
|
|
156
|
-
//#region packages/normalization-core/src/record-coerce.ts
|
|
157
|
-
/** Type guard for non-array object records at browser-safe boundaries. */
|
|
158
|
-
function isRecord(value) {
|
|
159
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
160
|
-
}
|
|
161
|
-
//#endregion
|
|
162
4
|
//#region packages/ai/src/providers/simple-options.ts
|
|
163
5
|
function buildBaseOptions(model, options, apiKey) {
|
|
164
6
|
const firstEventOptions = options;
|
|
@@ -183,6 +25,9 @@ function buildBaseOptions(model, options, apiKey) {
|
|
|
183
25
|
metadata: options?.metadata
|
|
184
26
|
};
|
|
185
27
|
}
|
|
28
|
+
function clampMaxTokensToModel(model, requestedMaxTokens) {
|
|
29
|
+
return requestedMaxTokens === void 0 ? void 0 : Math.max(1, Math.min(requestedMaxTokens, model.maxTokens));
|
|
30
|
+
}
|
|
186
31
|
function clampReasoning(effort) {
|
|
187
32
|
return effort === "xhigh" ? "high" : effort;
|
|
188
33
|
}
|
|
@@ -205,6 +50,12 @@ function adjustMaxTokensForThinking(baseMaxTokens, modelMaxTokens, reasoningLeve
|
|
|
205
50
|
};
|
|
206
51
|
}
|
|
207
52
|
//#endregion
|
|
53
|
+
//#region packages/normalization-core/src/record-coerce.ts
|
|
54
|
+
/** Type guard for non-array object records at browser-safe boundaries. */
|
|
55
|
+
function isRecord(value) {
|
|
56
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
208
59
|
//#region packages/normalization-core/src/utf16-slice.ts
|
|
209
60
|
function isHighSurrogate(codeUnit) {
|
|
210
61
|
return codeUnit >= 55296 && codeUnit <= 56319;
|
|
@@ -362,6 +213,106 @@ function extractToolResultText(blocks) {
|
|
|
362
213
|
return sanitizeSurrogates(truncateProviderToolText(structuredTexts.join("\n")));
|
|
363
214
|
}
|
|
364
215
|
//#endregion
|
|
216
|
+
//#region packages/normalization-core/src/string-coerce.ts
|
|
217
|
+
/** Reads a value only when it is already a string, preserving whitespace. */
|
|
218
|
+
function readStringValue(value) {
|
|
219
|
+
return typeof value === "string" ? value : void 0;
|
|
220
|
+
}
|
|
221
|
+
/** Trims string input and returns null for non-strings or empty strings. */
|
|
222
|
+
function normalizeNullableString(value) {
|
|
223
|
+
if (typeof value !== "string") return null;
|
|
224
|
+
const trimmed = value.trim();
|
|
225
|
+
return trimmed ? trimmed : null;
|
|
226
|
+
}
|
|
227
|
+
/** Trims string input and returns undefined for non-strings or empty strings. */
|
|
228
|
+
function normalizeOptionalString(value) {
|
|
229
|
+
return normalizeNullableString(value) ?? void 0;
|
|
230
|
+
}
|
|
231
|
+
/** Lowercases a normalized optional string. */
|
|
232
|
+
function normalizeOptionalLowercaseString(value) {
|
|
233
|
+
return normalizeOptionalString(value)?.toLowerCase();
|
|
234
|
+
}
|
|
235
|
+
/** Lowercases a normalized string or returns an empty string when absent. */
|
|
236
|
+
function normalizeLowercaseStringOrEmpty(value) {
|
|
237
|
+
return normalizeOptionalLowercaseString(value) ?? "";
|
|
238
|
+
}
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region packages/ai/src/providers/anthropic-model-contract.ts
|
|
241
|
+
function normalizeModelId(modelId) {
|
|
242
|
+
const normalized = normalizeLowercaseStringOrEmpty(modelId);
|
|
243
|
+
return (normalized.startsWith("anthropic/") ? normalized.slice(10) : normalized).replace(/[._\s]+/g, "-");
|
|
244
|
+
}
|
|
245
|
+
function normalizeApi(api) {
|
|
246
|
+
const normalized = normalizeLowercaseStringOrEmpty(api);
|
|
247
|
+
return normalized === "openclaw-anthropic-messages-transport" ? "anthropic-messages" : normalized;
|
|
248
|
+
}
|
|
249
|
+
function hasConcreteResponseModel(ref) {
|
|
250
|
+
const responseModelId = normalizeModelId(ref.responseModelId);
|
|
251
|
+
return responseModelId.length > 0 && responseModelId !== normalizeModelId(ref.modelId);
|
|
252
|
+
}
|
|
253
|
+
function usesClaudeFable5MessagesContract(model) {
|
|
254
|
+
return normalizeApi(model.api) === "anthropic-messages" && resolveClaudeFable5ModelIdentity(model) !== void 0;
|
|
255
|
+
}
|
|
256
|
+
/** Return whether streamed output must wait for the terminal refusal decision. */
|
|
257
|
+
function usesClaudeStreamingRefusalContract(model) {
|
|
258
|
+
if (normalizeApi(model.api) !== "anthropic-messages") return false;
|
|
259
|
+
return resolveClaudeFable5ModelIdentity(model) !== void 0 || resolveClaudeMythos5ModelIdentity(model) !== void 0 || resolveClaudeSonnet5ModelIdentity(model) !== void 0;
|
|
260
|
+
}
|
|
261
|
+
function requiresClaudeAdaptiveThinking(model) {
|
|
262
|
+
if (normalizeApi(model.api) !== "anthropic-messages") return false;
|
|
263
|
+
return requiresClaudeMandatoryAdaptiveThinking(model);
|
|
264
|
+
}
|
|
265
|
+
/** Return whether omitted thinking should default to adaptive/high. */
|
|
266
|
+
function defaultsClaudeAdaptiveThinking(model) {
|
|
267
|
+
return requiresClaudeAdaptiveThinking(model) || normalizeApi(model.api) === "anthropic-messages" && resolveClaudeSonnet5ModelIdentity(model) !== void 0;
|
|
268
|
+
}
|
|
269
|
+
/** Remove Sonnet 5 assistant prefills while preserving completed tool-use turns. */
|
|
270
|
+
function prepareClaudeSonnet5RequestContext(model, context) {
|
|
271
|
+
if (!resolveClaudeSonnet5ModelIdentity(model)) return context;
|
|
272
|
+
let end = context.messages.length;
|
|
273
|
+
while (end > 0) {
|
|
274
|
+
const message = context.messages[end - 1];
|
|
275
|
+
if (message?.role !== "assistant" || Array.isArray(message.content) && message.content.some((block) => block.type === "toolCall")) break;
|
|
276
|
+
end -= 1;
|
|
277
|
+
}
|
|
278
|
+
return end === context.messages.length ? context : {
|
|
279
|
+
...context,
|
|
280
|
+
messages: context.messages.slice(0, end)
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
function applyClaudeRequestContract(params, model) {
|
|
284
|
+
if (normalizeApi(model.api) !== "anthropic-messages") return;
|
|
285
|
+
const sonnet5 = resolveClaudeSonnet5ModelIdentity(model) !== void 0;
|
|
286
|
+
if (!requiresClaudeDefaultSampling(model) && !sonnet5) return;
|
|
287
|
+
delete params.temperature;
|
|
288
|
+
delete params.top_p;
|
|
289
|
+
delete params.top_k;
|
|
290
|
+
if (sonnet5) delete params.service_tier;
|
|
291
|
+
}
|
|
292
|
+
function resolveReplayModelBoundIdentity(ref) {
|
|
293
|
+
if (normalizeApi(ref.api) !== "anthropic-messages") return;
|
|
294
|
+
const modelRef = hasConcreteResponseModel(ref) ? { id: ref.responseModelId } : {
|
|
295
|
+
id: ref.modelId,
|
|
296
|
+
params: ref.modelParams
|
|
297
|
+
};
|
|
298
|
+
const fableIdentity = resolveClaudeFable5ModelIdentity(modelRef);
|
|
299
|
+
if (fableIdentity) return `fable:${fableIdentity}`;
|
|
300
|
+
const mythosIdentity = resolveClaudeMythos5ModelIdentity(modelRef);
|
|
301
|
+
if (mythosIdentity) return `mythos:${mythosIdentity}`;
|
|
302
|
+
const sonnetIdentity = resolveClaudeSonnet5ModelIdentity(modelRef);
|
|
303
|
+
return sonnetIdentity ? `sonnet:${sonnetIdentity}` : void 0;
|
|
304
|
+
}
|
|
305
|
+
function resolveModelBoundThinkingReplayMode(params) {
|
|
306
|
+
const sourceApi = normalizeApi(params.source.api);
|
|
307
|
+
const targetApi = normalizeApi(params.target.api);
|
|
308
|
+
const sourceIdentity = resolveReplayModelBoundIdentity(params.source);
|
|
309
|
+
const targetIdentity = resolveReplayModelBoundIdentity(params.target);
|
|
310
|
+
const sameRoute = normalizeLowercaseStringOrEmpty(params.source.provider) === normalizeLowercaseStringOrEmpty(params.target.provider) && sourceApi === targetApi && normalizeModelId(params.source.modelId) === normalizeModelId(params.target.modelId);
|
|
311
|
+
if (!sourceIdentity && !targetIdentity) return "default";
|
|
312
|
+
if (!sourceIdentity && !hasConcreteResponseModel(params.source) && targetIdentity && sameRoute) return "preserve";
|
|
313
|
+
return sourceApi === targetApi && sourceIdentity === targetIdentity ? "preserve" : "drop";
|
|
314
|
+
}
|
|
315
|
+
//#endregion
|
|
365
316
|
//#region packages/ai/src/providers/transform-messages.ts
|
|
366
317
|
const NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
|
|
367
318
|
const NON_VISION_TOOL_IMAGE_PLACEHOLDER = "(tool image omitted: model does not support images)";
|
|
@@ -404,7 +355,10 @@ function downgradeUnsupportedImages(messages, model) {
|
|
|
404
355
|
*/
|
|
405
356
|
function transformMessages(messages, model, normalizeToolCallId) {
|
|
406
357
|
const toolCallIdMap = /* @__PURE__ */ new Map();
|
|
407
|
-
const transformed = downgradeUnsupportedImages(messages
|
|
358
|
+
const transformed = downgradeUnsupportedImages(messages.map((msg) => msg.content == null ? {
|
|
359
|
+
...msg,
|
|
360
|
+
content: []
|
|
361
|
+
} : msg), model).map((msg) => {
|
|
408
362
|
if (msg.role === "user") return msg;
|
|
409
363
|
if (msg.role === "toolResult") {
|
|
410
364
|
const normalizedId = toolCallIdMap.get(msg.toolCallId);
|
|
@@ -513,4 +467,60 @@ function transformMessages(messages, model, normalizeToolCallId) {
|
|
|
513
467
|
return result;
|
|
514
468
|
}
|
|
515
469
|
//#endregion
|
|
516
|
-
|
|
470
|
+
//#region packages/ai/src/utils/prompt-cache-stability.ts
|
|
471
|
+
/**
|
|
472
|
+
* Prompt-cache normalization helpers. They keep generated prompt sections
|
|
473
|
+
* deterministic across platform newlines, trailing whitespace, and input
|
|
474
|
+
* ordering.
|
|
475
|
+
*/
|
|
476
|
+
/** Normalize structured prompt text before hashing or snapshot comparison. */
|
|
477
|
+
function normalizeStructuredPromptSection(text) {
|
|
478
|
+
return sanitizeSurrogates(text).replace(/\r\n?/g, "\n").replace(/[ \t]+$/gm, "").trim();
|
|
479
|
+
}
|
|
480
|
+
/** Normalize, de-dupe, and sort capability ids for stable prompt payloads. */
|
|
481
|
+
function normalizePromptCapabilityIds(capabilities) {
|
|
482
|
+
const seen = /* @__PURE__ */ new Set();
|
|
483
|
+
const normalized = [];
|
|
484
|
+
for (const capability of capabilities) {
|
|
485
|
+
const value = normalizeLowercaseStringOrEmpty(normalizeStructuredPromptSection(capability));
|
|
486
|
+
if (!value || seen.has(value)) continue;
|
|
487
|
+
seen.add(value);
|
|
488
|
+
normalized.push(value);
|
|
489
|
+
}
|
|
490
|
+
return normalized.toSorted((left, right) => left.localeCompare(right));
|
|
491
|
+
}
|
|
492
|
+
//#endregion
|
|
493
|
+
//#region packages/ai/src/utils/system-prompt-cache-boundary.ts
|
|
494
|
+
/**
|
|
495
|
+
* System prompt cache-boundary helpers.
|
|
496
|
+
*
|
|
497
|
+
* Keeps stable prompt prefixes separate from dynamic runtime additions for provider prompt caching.
|
|
498
|
+
*/
|
|
499
|
+
const SYSTEM_PROMPT_CACHE_BOUNDARY = "\n<!-- OPENCLAW_CACHE_BOUNDARY -->\n";
|
|
500
|
+
function stripSystemPromptCacheBoundary(text) {
|
|
501
|
+
return text.replaceAll(SYSTEM_PROMPT_CACHE_BOUNDARY, "\n");
|
|
502
|
+
}
|
|
503
|
+
function ensureSystemPromptCacheBoundary(systemPrompt) {
|
|
504
|
+
if (systemPrompt.trim().length === 0) return systemPrompt;
|
|
505
|
+
return systemPrompt.includes("\n<!-- OPENCLAW_CACHE_BOUNDARY -->\n") ? systemPrompt : `${systemPrompt}${SYSTEM_PROMPT_CACHE_BOUNDARY}`;
|
|
506
|
+
}
|
|
507
|
+
function splitSystemPromptCacheBoundary(text) {
|
|
508
|
+
const boundaryIndex = text.indexOf(SYSTEM_PROMPT_CACHE_BOUNDARY);
|
|
509
|
+
if (boundaryIndex === -1) return;
|
|
510
|
+
return {
|
|
511
|
+
stablePrefix: text.slice(0, boundaryIndex).trimEnd(),
|
|
512
|
+
dynamicSuffix: text.slice(boundaryIndex + 34).trimStart()
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
function prependSystemPromptAdditionAfterCacheBoundary(params) {
|
|
516
|
+
const systemPromptAddition = typeof params.systemPromptAddition === "string" ? normalizeStructuredPromptSection(params.systemPromptAddition) : "";
|
|
517
|
+
if (!systemPromptAddition) return params.systemPrompt;
|
|
518
|
+
if (params.systemPrompt.trim().length === 0) return systemPromptAddition;
|
|
519
|
+
const split = splitSystemPromptCacheBoundary(params.systemPrompt);
|
|
520
|
+
if (!split) return `${systemPromptAddition}\n\n${params.systemPrompt}`;
|
|
521
|
+
const dynamicSuffix = split.dynamicSuffix ? normalizeStructuredPromptSection(split.dynamicSuffix) : "";
|
|
522
|
+
if (!dynamicSuffix) return `${split.stablePrefix}${SYSTEM_PROMPT_CACHE_BOUNDARY}${systemPromptAddition}`;
|
|
523
|
+
return `${split.stablePrefix}${SYSTEM_PROMPT_CACHE_BOUNDARY}${systemPromptAddition}\n\n${dynamicSuffix}`;
|
|
524
|
+
}
|
|
525
|
+
//#endregion
|
|
526
|
+
export { isImageWithMediaPayload as C, buildBaseOptions as D, adjustMaxTokensForThinking as E, clampMaxTokensToModel as O, hasMediaPayload as S, isRecord as T, normalizeOptionalString as _, stripSystemPromptCacheBoundary as a, extractToolResultBlockText as b, transformMessages as c, prepareClaudeSonnet5RequestContext as d, requiresClaudeAdaptiveThinking as f, normalizeLowercaseStringOrEmpty as g, usesClaudeStreamingRefusalContract as h, splitSystemPromptCacheBoundary as i, clampReasoning as k, applyClaudeRequestContract as l, usesClaudeFable5MessagesContract as m, ensureSystemPromptCacheBoundary as n, normalizePromptCapabilityIds as o, resolveModelBoundThinkingReplayMode as p, prependSystemPromptAdditionAfterCacheBoundary as r, normalizeStructuredPromptSection as s, SYSTEM_PROMPT_CACHE_BOUNDARY as t, defaultsClaudeAdaptiveThinking as u, readStringValue as v, truncateUtf16Safe as w, extractToolResultText as x, describeToolResultMediaPlaceholder as y };
|