@openclaw/ai 2026.7.2-beta.6 → 2026.7.33
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 +5 -6
- package/dist/{anthropic-CH4UUnZr.mjs → anthropic-BML72tLz.mjs} +468 -101
- package/dist/{api-registry-DlMgPR39.d.mts → api-registry-BXYnCOIR.d.mts} +2 -1
- package/dist/{azure-openai-responses-client-compat-C7K7QfUE.mjs → azure-openai-responses-client-compat-a_O_GVQV.mjs} +2 -23
- package/dist/{azure-openai-responses-CImcwB83.mjs → azure-openai-responses-kEN8II8I.mjs} +13 -11
- package/dist/{env-api-keys-DrgeBuva.mjs → env-api-keys-CtMlqaQ4.mjs} +4 -5
- package/dist/{event-stream-YjaPW20U.d.mts → event-stream-0nZeBKl2.d.mts} +1 -1
- package/dist/{event-stream-D8n2uFee.mjs → event-stream-ReMmOTzX.mjs} +6 -14
- package/dist/event-stream.d.mts +1 -1
- package/dist/event-stream.mjs +1 -1
- package/dist/{github-copilot-headers-NCJtz9i0.mjs → github-copilot-headers-BsH5cqGj.mjs} +12 -1
- package/dist/{google-CtSg0iTS.mjs → google-DTM4O3e9.mjs} +5 -5
- package/dist/{google-shared-DNBz5rcD.mjs → google-shared-BAP0BQVi.mjs} +22 -34
- package/dist/{google-vertex-31f1uS9L.mjs → google-vertex-D58MZHCQ.mjs} +19 -6
- package/dist/host-4t713IeR.mjs +37 -0
- package/dist/{anthropic-SrGtwsJu.d.mts → index-BoTnz8cv.d.mts} +1 -27
- package/dist/index.d.mts +50 -7
- package/dist/index.mjs +5 -5
- package/dist/internal/anthropic.d.mts +62 -22
- package/dist/internal/anthropic.mjs +4 -5
- package/dist/internal/openai.d.mts +82 -98
- package/dist/internal/openai.mjs +6 -8
- package/dist/internal/runtime.d.mts +34 -13
- package/dist/internal/runtime.mjs +14 -26
- package/dist/internal/shared.d.mts +9 -26
- package/dist/internal/shared.mjs +2 -6
- package/dist/{json-parse-BvXNt1-7.mjs → json-parse-DzNSIQBq.mjs} +6 -4
- package/dist/{llm-request-activity-BjtkplhG.mjs → llm-request-activity-CehVkZP-.mjs} +19 -1
- package/dist/{mistral-CWmpvWYh.mjs → mistral-CePVNdws.mjs} +39 -141
- package/dist/model-utils-DgmOla96.mjs +69 -0
- package/dist/{openai-chatgpt-responses-B84Ibtrd.mjs → openai-chatgpt-responses-BHqbcipc.mjs} +154 -101
- package/dist/{openai-completions-DsOxhOD1.mjs → openai-completions-9qYFVS7H.mjs} +295 -81
- package/dist/{openai-responses-BT7A3sLu.mjs → openai-responses-D6l9URyV.mjs} +8 -10
- package/dist/openai-responses-shared-L3PWZvkm.mjs +1949 -0
- package/dist/{openai-tool-projection-OhX64DoP.mjs → openai-tool-projection-BPlyXt8H.mjs} +12 -32
- package/dist/providers.d.mts +2 -3
- package/dist/providers.mjs +10 -11
- package/dist/reasoning-tag-text-partitioner-axhAdUwg.mjs +394 -0
- package/dist/{src-QkygScBs.mjs → src-CZ503MYJ.mjs} +5 -24
- package/dist/{stream-first-event-timeout-BBys9hSb.mjs → stream-first-event-timeout-RjWszj8c.mjs} +22 -2
- package/dist/transform-messages-BhGF_fF4.mjs +507 -0
- package/dist/{types-bzp5k29J.d.mts → types-DRgdPqaZ.d.mts} +0 -19
- package/dist/types.d.mts +5 -5
- package/dist/types.mjs +4 -4
- package/dist/{validation-B-j7cOYp.d.mts → validation-BDMWOr8d.d.mts} +1 -1
- package/dist/{validation-DAa_yFOM.mjs → validation-FrchoOlv.mjs} +7 -2
- package/dist/validation.d.mts +1 -1
- package/dist/validation.mjs +1 -1
- package/npm-shrinkwrap.json +645 -0
- package/package.json +11 -36
- package/dist/anthropic-usage-DWU-x8MI.mjs +0 -459
- package/dist/cache-retention-0x979a5V.mjs +0 -12
- package/dist/deferred-event-buffer-DAvyP7qA.mjs +0 -19
- package/dist/error-coercion-DgxlWC0n.mjs +0 -15
- package/dist/host-B9GUmcra.d.mts +0 -173
- package/dist/host-Dog2WQiR.mjs +0 -369
- package/dist/index-BVVgDSdq.d.mts +0 -1
- package/dist/internal/retry-after.d.mts +0 -5
- package/dist/internal/retry-after.mjs +0 -101
- package/dist/number-coercion-DvG7SNMg.mjs +0 -129
- package/dist/openai-completions-compat-DBWjXoMZ.d.mts +0 -43
- package/dist/openai-prompt-cache-2uo_1OR1.d.mts +0 -7
- package/dist/openai-prompt-cache-mZTCdRPo.mjs +0 -12
- package/dist/openai-reasoning-compat-YgeLncHw.mjs +0 -396
- package/dist/openai-responses-shared-pXl6Wd8S.mjs +0 -392
- package/dist/openai-responses-stream-internal-Cw5txaGW.mjs +0 -2964
- package/dist/prompt-cache-stability-Cwcjv_fx.d.mts +0 -13
- package/dist/provider-error-CAEvRjry.mjs +0 -47
- package/dist/provider-options-D8bB3z9b.d.mts +0 -144
- package/dist/reasoning-tag-text-partitioner-CGDyLWUR.mjs +0 -12209
- package/dist/simple-options-9lhRrN73.mjs +0 -50
- package/dist/stream-first-event-timeout-DvDeSucC.d.mts +0 -29
- package/dist/tls-certificate-errors-DXSpluKI.mjs +0 -93
- package/dist/tool-result-text-CTpIRbYd.mjs +0 -225
- package/dist/transform-messages-C8mBqZxF.mjs +0 -2
- package/dist/transport-stream-shared-D81p90xq.mjs +0 -297
- package/dist/transports.d.mts +0 -573
- package/dist/transports.mjs +0 -4110
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { a as requiresClaudeMandatoryAdaptiveThinking, l as resolveClaudeNativeThinkingLevelMap } from "./src-QkygScBs.mjs";
|
|
2
|
-
//#region packages/ai/src/model-utils.ts
|
|
3
|
-
/** Calculates and stores model cost fields from token usage and per-million pricing. */
|
|
4
|
-
function calculateCost(model, usage) {
|
|
5
|
-
const cacheWrite1h = Math.min(usage.cacheWrite, Math.max(0, usage.cacheWrite1h ?? 0));
|
|
6
|
-
const cacheWrite5m = usage.cacheWrite - cacheWrite1h;
|
|
7
|
-
usage.cost.input = model.cost.input / 1e6 * usage.input;
|
|
8
|
-
usage.cost.output = model.cost.output / 1e6 * usage.output;
|
|
9
|
-
usage.cost.cacheRead = model.cost.cacheRead / 1e6 * usage.cacheRead;
|
|
10
|
-
usage.cost.cacheWrite = (model.cost.cacheWrite * cacheWrite5m + model.cost.input * 2 * cacheWrite1h) / 1e6;
|
|
11
|
-
usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
|
|
12
|
-
return usage.cost;
|
|
13
|
-
}
|
|
14
|
-
/** Replaces the catalog estimate when the provider reports an authoritative billed total. */
|
|
15
|
-
function applyProviderReportedUsageCost(usage, reportedCost) {
|
|
16
|
-
if (typeof reportedCost !== "number" || !Number.isFinite(reportedCost) || reportedCost < 0) return;
|
|
17
|
-
usage.cost.total = reportedCost;
|
|
18
|
-
usage.cost.totalOrigin = "provider-billed";
|
|
19
|
-
}
|
|
20
|
-
const EXTENDED_THINKING_LEVELS = [
|
|
21
|
-
"off",
|
|
22
|
-
"minimal",
|
|
23
|
-
"low",
|
|
24
|
-
"medium",
|
|
25
|
-
"high",
|
|
26
|
-
"xhigh",
|
|
27
|
-
"max"
|
|
28
|
-
];
|
|
29
|
-
function resolveThinkingLevelMap(model) {
|
|
30
|
-
return model.api === "anthropic-messages" ? resolveClaudeNativeThinkingLevelMap(model) ?? model.thinkingLevelMap : model.thinkingLevelMap;
|
|
31
|
-
}
|
|
32
|
-
/** Returns thinking levels exposed by a reasoning-capable model. */
|
|
33
|
-
function getSupportedThinkingLevels(model) {
|
|
34
|
-
const mandatoryAdaptiveContract = model.api === "anthropic-messages" && requiresClaudeMandatoryAdaptiveThinking(model);
|
|
35
|
-
if (!model.reasoning && !mandatoryAdaptiveContract) return ["off"];
|
|
36
|
-
const thinkingLevelMap = resolveThinkingLevelMap(model);
|
|
37
|
-
return EXTENDED_THINKING_LEVELS.filter((level) => {
|
|
38
|
-
const mapped = thinkingLevelMap?.[level];
|
|
39
|
-
if (mapped === null) return false;
|
|
40
|
-
if (level === "xhigh" || level === "max") return mapped !== void 0;
|
|
41
|
-
return true;
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
/** Clamps a requested thinking level to the closest supported level for a model. */
|
|
45
|
-
function clampThinkingLevel(model, level) {
|
|
46
|
-
const availableLevels = getSupportedThinkingLevels(model);
|
|
47
|
-
if (availableLevels.includes(level)) return level;
|
|
48
|
-
const requestedIndex = EXTENDED_THINKING_LEVELS.indexOf(level);
|
|
49
|
-
if (requestedIndex === -1) return availableLevels[0] ?? "off";
|
|
50
|
-
const thinkingLevelMap = resolveThinkingLevelMap(model);
|
|
51
|
-
if ((level === "xhigh" || level === "max") && thinkingLevelMap?.[level] === null) {
|
|
52
|
-
for (const candidate of EXTENDED_THINKING_LEVELS.slice(0, requestedIndex).toReversed()) if (availableLevels.includes(candidate)) return candidate;
|
|
53
|
-
}
|
|
54
|
-
for (const candidate of EXTENDED_THINKING_LEVELS.slice(requestedIndex)) if (availableLevels.includes(candidate)) return candidate;
|
|
55
|
-
for (const candidate of EXTENDED_THINKING_LEVELS.slice(0, requestedIndex).toReversed()) if (availableLevels.includes(candidate)) return candidate;
|
|
56
|
-
return availableLevels[0] ?? "off";
|
|
57
|
-
}
|
|
58
|
-
/** Compares model identity by provider and id. */
|
|
59
|
-
function modelsAreEqual(a, b) {
|
|
60
|
-
if (!a || !b) return false;
|
|
61
|
-
return a.id === b.id && a.provider === b.provider;
|
|
62
|
-
}
|
|
63
|
-
//#endregion
|
|
64
|
-
//#region packages/normalization-core/src/number-coercion.ts
|
|
65
|
-
/** Returns a number only when the input is already finite. */
|
|
66
|
-
function asFiniteNumber(value) {
|
|
67
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
68
|
-
}
|
|
69
|
-
/** Returns a finite number only when it satisfies the supplied inclusive/exclusive bounds. */
|
|
70
|
-
function asFiniteNumberInRange(value, range) {
|
|
71
|
-
const number = asFiniteNumber(value);
|
|
72
|
-
if (number === void 0) return;
|
|
73
|
-
if (range.min !== void 0) {
|
|
74
|
-
if (range.minExclusive ? number <= range.min : number < range.min) return;
|
|
75
|
-
}
|
|
76
|
-
if (range.max !== void 0) {
|
|
77
|
-
if (range.maxExclusive ? number >= range.max : number > range.max) return;
|
|
78
|
-
}
|
|
79
|
-
return number;
|
|
80
|
-
}
|
|
81
|
-
function normalizeNumericString(value) {
|
|
82
|
-
const trimmed = value.trim();
|
|
83
|
-
return trimmed ? trimmed : void 0;
|
|
84
|
-
}
|
|
85
|
-
/** Parses only safe integer numbers or base-10 integer strings. */
|
|
86
|
-
function parseStrictInteger(value) {
|
|
87
|
-
if (typeof value === "number") return Number.isSafeInteger(value) ? value : void 0;
|
|
88
|
-
if (typeof value !== "string") return;
|
|
89
|
-
const normalized = normalizeNumericString(value);
|
|
90
|
-
if (!normalized || !/^[+-]?\d+$/.test(normalized)) return;
|
|
91
|
-
const parsed = Number(normalized);
|
|
92
|
-
return Number.isSafeInteger(parsed) ? parsed : void 0;
|
|
93
|
-
}
|
|
94
|
-
/** Parses only finite decimal/scientific string tokens, rejecting partial numbers. */
|
|
95
|
-
function parseStrictFiniteNumber(value) {
|
|
96
|
-
if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
|
|
97
|
-
if (typeof value !== "string") return;
|
|
98
|
-
const normalized = normalizeNumericString(value);
|
|
99
|
-
if (!normalized || !/^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))(?:e[+-]?\d+)?$/i.test(normalized)) return;
|
|
100
|
-
const parsed = Number(normalized);
|
|
101
|
-
return Number.isFinite(parsed) ? parsed : void 0;
|
|
102
|
-
}
|
|
103
|
-
/** Conservative upper bound for Node timer delays. */
|
|
104
|
-
const MAX_TIMER_TIMEOUT_MS = 2147e6;
|
|
105
|
-
/** Clamps finite millisecond values into the Node-safe timer range. */
|
|
106
|
-
function clampTimerTimeoutMs(valueMs, minMs = 1) {
|
|
107
|
-
const value = asFiniteNumber(valueMs);
|
|
108
|
-
if (value === void 0) return;
|
|
109
|
-
return Math.min(Math.max(Math.floor(value), Math.max(1, Math.floor(minMs))), MAX_TIMER_TIMEOUT_MS);
|
|
110
|
-
}
|
|
111
|
-
/** Resolves arbitrary timeout input with fallback and minimum timer bounds. */
|
|
112
|
-
function resolveTimerTimeoutMs(valueMs, fallbackMs, minMs = 1) {
|
|
113
|
-
const value = asFiniteNumber(valueMs) ?? asFiniteNumber(fallbackMs);
|
|
114
|
-
const min = Math.max(0, Math.floor(minMs));
|
|
115
|
-
if (value === void 0) return min;
|
|
116
|
-
return Math.min(Math.max(Math.floor(value), min), MAX_TIMER_TIMEOUT_MS);
|
|
117
|
-
}
|
|
118
|
-
/** Parses strict positive integer values from numbers or strings. */
|
|
119
|
-
function parseStrictPositiveInteger(value) {
|
|
120
|
-
const parsed = parseStrictInteger(value);
|
|
121
|
-
return parsed !== void 0 && parsed > 0 ? parsed : void 0;
|
|
122
|
-
}
|
|
123
|
-
/** Parses strict non-negative integer values from numbers or strings. */
|
|
124
|
-
function parseStrictNonNegativeInteger(value) {
|
|
125
|
-
const parsed = parseStrictInteger(value);
|
|
126
|
-
return parsed !== void 0 && parsed >= 0 ? parsed : void 0;
|
|
127
|
-
}
|
|
128
|
-
//#endregion
|
|
129
|
-
export { parseStrictPositiveInteger as a, calculateCost as c, modelsAreEqual as d, parseStrictNonNegativeInteger as i, clampThinkingLevel as l, clampTimerTimeoutMs as n, resolveTimerTimeoutMs as o, parseStrictFiniteNumber as r, applyProviderReportedUsageCost as s, asFiniteNumberInRange as t, getSupportedThinkingLevels as u };
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { E as Model, O as OpenAICompletionsCompat } from "./types-bzp5k29J.mjs";
|
|
2
|
-
import { a as AiProviderRequestPolicyInput, i as AiProviderRequestCapabilities } from "./host-B9GUmcra.mjs";
|
|
3
|
-
|
|
4
|
-
//#region packages/ai/src/transports/openai-completions-compat.d.ts
|
|
5
|
-
type ProviderRequestCapabilities = AiProviderRequestCapabilities;
|
|
6
|
-
type OpenAICompletionsSessionAffinity = "none" | "openai" | "openrouter";
|
|
7
|
-
type OpenAICompletionsCompatDefaults = {
|
|
8
|
-
supportsStore: boolean;
|
|
9
|
-
supportsDeveloperRole: boolean;
|
|
10
|
-
supportsReasoningEffort: boolean;
|
|
11
|
-
supportsUsageInStreaming: boolean;
|
|
12
|
-
maxTokensField: "max_completion_tokens" | "max_tokens";
|
|
13
|
-
thinkingFormat: "openai" | "openrouter" | "deepseek" | "together" | "zai";
|
|
14
|
-
visibleReasoningDetailTypes: string[];
|
|
15
|
-
supportsStrictMode: boolean;
|
|
16
|
-
supportsJsonSchemaResponseFormat: boolean;
|
|
17
|
-
requiresReasoningContentOnAssistantMessages: boolean;
|
|
18
|
-
requiresNonEmptyUserOrAssistantMessage: boolean;
|
|
19
|
-
cacheControlFormat?: OpenAICompletionsCompat["cacheControlFormat"];
|
|
20
|
-
sessionAffinityFormat: Exclude<OpenAICompletionsSessionAffinity, "none">;
|
|
21
|
-
supportsLongCacheRetention: boolean;
|
|
22
|
-
};
|
|
23
|
-
type DetectedOpenAICompletionsCompat = {
|
|
24
|
-
capabilities: ProviderRequestCapabilities;
|
|
25
|
-
defaults: OpenAICompletionsCompatDefaults;
|
|
26
|
-
};
|
|
27
|
-
type ResolvedOpenAICompletionsCompat = Omit<Required<OpenAICompletionsCompat>, "cacheControlFormat" | "openRouterRouting" | "sendSessionAffinityHeaders"> & {
|
|
28
|
-
cacheControlFormat?: OpenAICompletionsCompat["cacheControlFormat"];
|
|
29
|
-
openRouterRouting?: OpenAICompletionsCompat["openRouterRouting"];
|
|
30
|
-
sessionAffinity: OpenAICompletionsSessionAffinity;
|
|
31
|
-
visibleReasoningDetailTypes: string[];
|
|
32
|
-
requiresNonEmptyUserOrAssistantMessage: boolean;
|
|
33
|
-
};
|
|
34
|
-
/** Detects endpoint capabilities and defaults for an OpenAI-completions model. */
|
|
35
|
-
declare function detectOpenAICompletionsCompat(model: Pick<Model<"openai-completions">, "provider" | "baseUrl" | "id"> & {
|
|
36
|
-
compat?: {
|
|
37
|
-
supportsStore?: boolean;
|
|
38
|
-
} | null;
|
|
39
|
-
}, resolveCapabilities?: (input: AiProviderRequestPolicyInput) => ProviderRequestCapabilities): DetectedOpenAICompletionsCompat;
|
|
40
|
-
/** Applies explicit model overrides once on top of the canonical transport defaults. */
|
|
41
|
-
declare function resolveOpenAICompletionsCompat(model: Model<"openai-completions">, resolveCapabilities?: (input: AiProviderRequestPolicyInput) => ProviderRequestCapabilities): ResolvedOpenAICompletionsCompat;
|
|
42
|
-
//#endregion
|
|
43
|
-
export { detectOpenAICompletionsCompat as n, resolveOpenAICompletionsCompat as r, ResolvedOpenAICompletionsCompat as t };
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
//#region packages/ai/src/providers/openai-prompt-cache.d.ts
|
|
2
|
-
/** Maximum prompt cache key length accepted by OpenAI-compatible request metadata. */
|
|
3
|
-
declare const OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH = 64;
|
|
4
|
-
/** Truncates a prompt cache key by Unicode code point count. */
|
|
5
|
-
declare function clampOpenAIPromptCacheKey(key: string | undefined): string | undefined;
|
|
6
|
-
//#endregion
|
|
7
|
-
export { clampOpenAIPromptCacheKey as n, OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH as t };
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
//#region packages/ai/src/providers/openai-prompt-cache.ts
|
|
2
|
-
/** Maximum prompt cache key length accepted by OpenAI-compatible request metadata. */
|
|
3
|
-
const OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH = 64;
|
|
4
|
-
/** Truncates a prompt cache key by Unicode code point count. */
|
|
5
|
-
function clampOpenAIPromptCacheKey(key) {
|
|
6
|
-
if (key === void 0) return;
|
|
7
|
-
const chars = Array.from(key);
|
|
8
|
-
if (chars.length <= 64) return key;
|
|
9
|
-
return chars.slice(0, 64).join("");
|
|
10
|
-
}
|
|
11
|
-
//#endregion
|
|
12
|
-
export { clampOpenAIPromptCacheKey as n, OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH as t };
|
|
@@ -1,396 +0,0 @@
|
|
|
1
|
-
import { g as isRecord, i as transformMessages, p as normalizeLowercaseStringOrEmpty } from "./host-Dog2WQiR.mjs";
|
|
2
|
-
import { t as sanitizeSurrogates } from "./sanitize-unicode-DT5o51ur.mjs";
|
|
3
|
-
import { a as isImageWithMediaPayload, d as stripSystemPromptCacheBoundary, r as extractToolResultText, t as describeToolResultMediaPlaceholder } from "./tool-result-text-CTpIRbYd.mjs";
|
|
4
|
-
import { c as resolveProviderRequestCapabilities } from "./openai-tool-projection-OhX64DoP.mjs";
|
|
5
|
-
//#region packages/ai/src/utils/assistant-text-phase.ts
|
|
6
|
-
function isAssistantTextPhaseBlock(block) {
|
|
7
|
-
if (!block || typeof block !== "object") return false;
|
|
8
|
-
const record = block;
|
|
9
|
-
return record.type === "text" && typeof record.text === "string";
|
|
10
|
-
}
|
|
11
|
-
function encodeAssistantTextSignatureV1(id, phase) {
|
|
12
|
-
return JSON.stringify({
|
|
13
|
-
v: 1,
|
|
14
|
-
id,
|
|
15
|
-
...phase ? { phase } : {}
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
/** Tags unphased narration before a tool-call event becomes consumer-visible. */
|
|
19
|
-
function tagPendingCommentaryText(content) {
|
|
20
|
-
const textBlocks = content.filter(isAssistantTextPhaseBlock);
|
|
21
|
-
let commentaryIndex = textBlocks.filter((block) => block.textSignature !== void 0).length;
|
|
22
|
-
const tagged = /* @__PURE__ */ new Map();
|
|
23
|
-
for (const block of textBlocks) {
|
|
24
|
-
if (block.text.trim().length === 0 || block.textSignature !== void 0) continue;
|
|
25
|
-
const signature = encodeAssistantTextSignatureV1(`commentary-${commentaryIndex}`, "commentary");
|
|
26
|
-
block.textSignature = signature;
|
|
27
|
-
tagged.set(block, signature);
|
|
28
|
-
commentaryIndex += 1;
|
|
29
|
-
}
|
|
30
|
-
return tagged;
|
|
31
|
-
}
|
|
32
|
-
/** Rolls back only the exact provisional signatures created by this transport turn. */
|
|
33
|
-
function clearPendingCommentaryText(tags) {
|
|
34
|
-
for (const [block, signature] of tags) if (block.textSignature === signature) delete block.textSignature;
|
|
35
|
-
tags.clear();
|
|
36
|
-
}
|
|
37
|
-
function rememberPendingCommentaryTags(target, tagged) {
|
|
38
|
-
for (const [block, signature] of tagged) target.set(block, signature);
|
|
39
|
-
}
|
|
40
|
-
//#endregion
|
|
41
|
-
//#region packages/ai/src/providers/openai-response-format.ts
|
|
42
|
-
const JSON_SCHEMA_RESPONSE_FORMAT_NAME = "openclaw_response";
|
|
43
|
-
const OLLAMA_CLOUD_ORIGIN = "https://ollama.com";
|
|
44
|
-
function isKnownOpenAIJsonSchemaModelId(modelId) {
|
|
45
|
-
if (typeof modelId !== "string") return false;
|
|
46
|
-
if (/^gpt-5(?:[.-]|$)/i.test(modelId) || /^gpt-4\.1(?:-|$)/i.test(modelId)) return true;
|
|
47
|
-
const gpt4o = /^gpt-4o(-mini)?(?:-(\d{4}-\d{2}-\d{2}))?$/i.exec(modelId);
|
|
48
|
-
if (gpt4o) {
|
|
49
|
-
const snapshot = gpt4o[2];
|
|
50
|
-
return !snapshot || snapshot >= (gpt4o[1] ? "2024-07-18" : "2024-08-06");
|
|
51
|
-
}
|
|
52
|
-
return /^(?:o1|o3(?:-mini|-pro)?|o4-mini)(?:-\d{4}-\d{2}-\d{2})?$/i.test(modelId);
|
|
53
|
-
}
|
|
54
|
-
function shouldOmitOllamaCompatResponseFormat(params) {
|
|
55
|
-
if (!params.provider.includes("ollama")) return false;
|
|
56
|
-
if (params.hasTools()) return true;
|
|
57
|
-
try {
|
|
58
|
-
return new URL(params.baseUrl).origin === OLLAMA_CLOUD_ORIGIN;
|
|
59
|
-
} catch {
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Maps the shared JSON Schema option to Chat Completions while preserving the
|
|
65
|
-
* older provider-shaped json_object/json_schema inputs accepted by model params.
|
|
66
|
-
*/
|
|
67
|
-
function resolveOpenAICompletionsResponseFormat(responseFormat, supportsJsonSchemaResponseFormat) {
|
|
68
|
-
if (!responseFormat) return;
|
|
69
|
-
if (responseFormat.type === "json_object") return responseFormat;
|
|
70
|
-
if (responseFormat.type === "text") return responseFormat;
|
|
71
|
-
if (responseFormat.type === "json_schema" && isRecord(responseFormat.json_schema)) return responseFormat;
|
|
72
|
-
if (!supportsJsonSchemaResponseFormat) return;
|
|
73
|
-
return {
|
|
74
|
-
type: "json_schema",
|
|
75
|
-
json_schema: {
|
|
76
|
-
name: JSON_SCHEMA_RESPONSE_FORMAT_NAME,
|
|
77
|
-
schema: responseFormat
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
//#endregion
|
|
82
|
-
//#region packages/ai/src/transports/openai-completions-compat.ts
|
|
83
|
-
function isDefaultRouteProvider(provider, ...ids) {
|
|
84
|
-
return provider !== void 0 && ids.includes(provider);
|
|
85
|
-
}
|
|
86
|
-
/** Resolves default request flags for an OpenAI-compatible completions endpoint. */
|
|
87
|
-
function resolveOpenAICompletionsCompatDefaults(input) {
|
|
88
|
-
const { provider, modelId, endpointClass, knownProviderFamily, supportsNativeStreamingUsageCompat = false, supportsOpenAICompletionsStreamingUsageCompat = false, usesExplicitProxyLikeEndpoint = false } = input;
|
|
89
|
-
const isDefaultRoute = endpointClass === "default";
|
|
90
|
-
const usesConfiguredNonOpenAIEndpoint = endpointClass !== "default" && endpointClass !== "openai-public";
|
|
91
|
-
const isMoonshot = knownProviderFamily === "moonshot" || endpointClass === "moonshot-native";
|
|
92
|
-
const isMoonshotLike = isMoonshot || knownProviderFamily === "modelstudio" || endpointClass === "modelstudio-native";
|
|
93
|
-
const isModelStudioLike = knownProviderFamily === "modelstudio" || endpointClass === "modelstudio-native" || isDefaultRoute && isDefaultRouteProvider(provider, "dashscope", "modelstudio", "qwen");
|
|
94
|
-
const isZai = endpointClass === "zai-native" || isDefaultRoute && isDefaultRouteProvider(input.provider, "zai");
|
|
95
|
-
const isDeepSeek = endpointClass === "deepseek-native" || isDefaultRoute && isDefaultRouteProvider(input.provider, "deepseek");
|
|
96
|
-
const isTogether = knownProviderFamily === "together" || input.baseUrl?.includes("api.together.ai") === true || input.baseUrl?.includes("api.together.xyz") === true || isDefaultRoute && isDefaultRouteProvider(input.provider, "together");
|
|
97
|
-
const isCloudflareAiGateway = provider === "cloudflare-ai-gateway" || input.baseUrl?.includes("gateway.ai.cloudflare.com") === true;
|
|
98
|
-
const isXiaomi = endpointClass === "xiaomi-native" || isDefaultRoute && isDefaultRouteProvider(input.provider, "xiaomi");
|
|
99
|
-
const isNonStandard = endpointClass === "cerebras-native" || endpointClass === "chutes-native" || endpointClass === "deepseek-native" || endpointClass === "mistral-public" || endpointClass === "opencode-native" || endpointClass === "xai-native" || isXiaomi || isZai || isDefaultRoute && isDefaultRouteProvider(input.provider, "cerebras", "chutes", "deepseek", "opencode", "xai");
|
|
100
|
-
const isOpenRouterLike = input.provider === "openrouter" || endpointClass === "openrouter";
|
|
101
|
-
const isLocalEndpoint = endpointClass === "local";
|
|
102
|
-
const usesMaxTokens = endpointClass === "chutes-native" || endpointClass === "mistral-public" || knownProviderFamily === "mistral" || isMoonshot || isCloudflareAiGateway || isZai || isTogether || isDefaultRoute && isDefaultRouteProvider(provider, "chutes");
|
|
103
|
-
return {
|
|
104
|
-
supportsStore: !isNonStandard && knownProviderFamily !== "mistral" && !usesExplicitProxyLikeEndpoint,
|
|
105
|
-
supportsDeveloperRole: !isNonStandard && !isMoonshotLike && !usesConfiguredNonOpenAIEndpoint,
|
|
106
|
-
supportsReasoningEffort: !isZai && !isTogether && knownProviderFamily !== "mistral" && endpointClass !== "xai-native" && !usesExplicitProxyLikeEndpoint,
|
|
107
|
-
supportsUsageInStreaming: supportsOpenAICompletionsStreamingUsageCompat || !isNonStandard && (isLocalEndpoint || !usesConfiguredNonOpenAIEndpoint || supportsNativeStreamingUsageCompat),
|
|
108
|
-
maxTokensField: usesMaxTokens ? "max_tokens" : "max_completion_tokens",
|
|
109
|
-
thinkingFormat: isDeepSeek || isXiaomi ? "deepseek" : isZai ? "zai" : isTogether ? "together" : isOpenRouterLike ? "openrouter" : "openai",
|
|
110
|
-
visibleReasoningDetailTypes: isOpenRouterLike ? ["response.output_text", "response.text"] : [],
|
|
111
|
-
supportsStrictMode: !isZai && !usesConfiguredNonOpenAIEndpoint,
|
|
112
|
-
supportsJsonSchemaResponseFormat: (endpointClass === "openai-public" || isDefaultRoute && isDefaultRouteProvider(provider, "openai")) && isKnownOpenAIJsonSchemaModelId(modelId),
|
|
113
|
-
requiresReasoningContentOnAssistantMessages: isDeepSeek || isXiaomi,
|
|
114
|
-
requiresNonEmptyUserOrAssistantMessage: isModelStudioLike,
|
|
115
|
-
cacheControlFormat: provider === "openrouter" && modelId?.startsWith("anthropic/") === true ? "anthropic" : void 0,
|
|
116
|
-
sessionAffinityFormat: isOpenRouterLike ? "openrouter" : "openai",
|
|
117
|
-
supportsLongCacheRetention: provider !== "cloudflare-workers-ai" && provider !== "cloudflare-ai-gateway" && knownProviderFamily !== "together" && !input.baseUrl?.includes("api.cloudflare.com") && !input.baseUrl?.includes("gateway.ai.cloudflare.com") && !input.baseUrl?.includes("api.together.ai") && !input.baseUrl?.includes("api.together.xyz")
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
function resolveOpenAICompletionsCompatDefaultsFromCapabilities(input) {
|
|
121
|
-
return resolveOpenAICompletionsCompatDefaults(input);
|
|
122
|
-
}
|
|
123
|
-
/** Detects endpoint capabilities and defaults for an OpenAI-completions model. */
|
|
124
|
-
function detectOpenAICompletionsCompat(model, resolveCapabilities = resolveProviderRequestCapabilities) {
|
|
125
|
-
const capabilities = resolveCapabilities({
|
|
126
|
-
provider: model.provider,
|
|
127
|
-
api: "openai-completions",
|
|
128
|
-
baseUrl: model.baseUrl,
|
|
129
|
-
capability: "llm",
|
|
130
|
-
transport: "stream",
|
|
131
|
-
modelId: model.id,
|
|
132
|
-
compat: model.compat && typeof model.compat === "object" ? model.compat : void 0
|
|
133
|
-
});
|
|
134
|
-
return {
|
|
135
|
-
capabilities,
|
|
136
|
-
defaults: resolveOpenAICompletionsCompatDefaultsFromCapabilities({
|
|
137
|
-
provider: model.provider,
|
|
138
|
-
modelId: model.id,
|
|
139
|
-
baseUrl: model.baseUrl,
|
|
140
|
-
...capabilities
|
|
141
|
-
})
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
function resolveSessionAffinity(model, detectedFormat) {
|
|
145
|
-
if (model.compat?.sendSessionAffinityHeaders !== true) return "none";
|
|
146
|
-
if (detectedFormat === "openrouter" || model.compat.thinkingFormat === "openrouter" || model.compat.openRouterRouting !== void 0) return "openrouter";
|
|
147
|
-
return "openai";
|
|
148
|
-
}
|
|
149
|
-
/** Applies explicit model overrides once on top of the canonical transport defaults. */
|
|
150
|
-
function resolveOpenAICompletionsCompat(model, resolveCapabilities = resolveProviderRequestCapabilities) {
|
|
151
|
-
const { defaults } = detectOpenAICompletionsCompat(model, resolveCapabilities);
|
|
152
|
-
const configured = model.compat;
|
|
153
|
-
return {
|
|
154
|
-
supportsStore: configured?.supportsStore ?? defaults.supportsStore,
|
|
155
|
-
supportsDeveloperRole: configured?.supportsDeveloperRole ?? defaults.supportsDeveloperRole,
|
|
156
|
-
supportsReasoningEffort: configured?.supportsReasoningEffort ?? defaults.supportsReasoningEffort,
|
|
157
|
-
supportsUsageInStreaming: configured?.supportsUsageInStreaming ?? defaults.supportsUsageInStreaming,
|
|
158
|
-
maxTokensField: configured?.maxTokensField ?? defaults.maxTokensField,
|
|
159
|
-
requiresToolResultName: configured?.requiresToolResultName ?? false,
|
|
160
|
-
requiresAssistantAfterToolResult: configured?.requiresAssistantAfterToolResult ?? false,
|
|
161
|
-
requiresThinkingAsText: configured?.requiresThinkingAsText ?? false,
|
|
162
|
-
requiresReasoningContentOnAssistantMessages: configured?.requiresReasoningContentOnAssistantMessages ?? defaults.requiresReasoningContentOnAssistantMessages,
|
|
163
|
-
thinkingFormat: configured?.thinkingFormat ?? defaults.thinkingFormat,
|
|
164
|
-
openRouterRouting: configured?.openRouterRouting,
|
|
165
|
-
vercelGatewayRouting: configured?.vercelGatewayRouting ?? {},
|
|
166
|
-
zaiToolStream: configured?.zaiToolStream ?? false,
|
|
167
|
-
supportsStrictMode: configured?.supportsStrictMode ?? defaults.supportsStrictMode,
|
|
168
|
-
supportsJsonSchemaResponseFormat: configured?.supportsJsonSchemaResponseFormat ?? defaults.supportsJsonSchemaResponseFormat,
|
|
169
|
-
cacheControlFormat: configured?.cacheControlFormat ?? defaults.cacheControlFormat,
|
|
170
|
-
sessionAffinity: resolveSessionAffinity(model, defaults.sessionAffinityFormat),
|
|
171
|
-
supportsPromptCacheKey: configured?.supportsPromptCacheKey ?? false,
|
|
172
|
-
supportsLongCacheRetention: configured?.supportsLongCacheRetention ?? defaults.supportsLongCacheRetention,
|
|
173
|
-
visibleReasoningDetailTypes: configured && "visibleReasoningDetailTypes" in configured ? configured.visibleReasoningDetailTypes ?? defaults.visibleReasoningDetailTypes : defaults.visibleReasoningDetailTypes,
|
|
174
|
-
requiresNonEmptyUserOrAssistantMessage: defaults.requiresNonEmptyUserOrAssistantMessage
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
if (process.env.VITEST || false) globalThis[Symbol.for("openclaw.openAICompletionsCompatTestApi")] = { resolveOpenAICompletionsCompatDefaults };
|
|
178
|
-
//#endregion
|
|
179
|
-
//#region packages/ai/src/openai-completions-messages.ts
|
|
180
|
-
const EMPTY_TOOL_RESULT_TEXT = "(no output)";
|
|
181
|
-
function isTextContentBlock(block) {
|
|
182
|
-
return block.type === "text";
|
|
183
|
-
}
|
|
184
|
-
function isThinkingContentBlock(block) {
|
|
185
|
-
return block.type === "thinking";
|
|
186
|
-
}
|
|
187
|
-
function isToolCallBlock(block) {
|
|
188
|
-
return block.type === "toolCall";
|
|
189
|
-
}
|
|
190
|
-
function sanitizeToolResultText(text, fallback) {
|
|
191
|
-
const sanitized = sanitizeSurrogates(text);
|
|
192
|
-
return sanitized.trim().length > 0 ? sanitized : fallback;
|
|
193
|
-
}
|
|
194
|
-
/** Convert a normalized transcript to OpenAI Chat Completions messages. */
|
|
195
|
-
function convertMessages(model, context, compat, options = {}) {
|
|
196
|
-
const params = [];
|
|
197
|
-
const normalizeToolCallId = (id) => {
|
|
198
|
-
if (id.includes("|")) return id.slice(0, id.indexOf("|")).replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 40);
|
|
199
|
-
if (model.provider === "openai") return id.length > 40 ? id.slice(0, 40) : id;
|
|
200
|
-
return id;
|
|
201
|
-
};
|
|
202
|
-
const transformedMessages = transformMessages(context.messages, model, (id) => normalizeToolCallId(id));
|
|
203
|
-
if (context.systemPrompt) {
|
|
204
|
-
const role = model.reasoning && compat.supportsDeveloperRole ? "developer" : "system";
|
|
205
|
-
const systemPrompt = options.preserveSystemPromptCacheBoundary ? context.systemPrompt : stripSystemPromptCacheBoundary(context.systemPrompt);
|
|
206
|
-
params.push({
|
|
207
|
-
role,
|
|
208
|
-
content: sanitizeSurrogates(systemPrompt)
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
let lastRole = null;
|
|
212
|
-
for (let i = 0; i < transformedMessages.length; i++) {
|
|
213
|
-
const msg = transformedMessages[i];
|
|
214
|
-
if (!msg) continue;
|
|
215
|
-
if (compat.requiresAssistantAfterToolResult && lastRole === "toolResult" && msg.role === "user") params.push({
|
|
216
|
-
role: "assistant",
|
|
217
|
-
content: "I have processed the tool results."
|
|
218
|
-
});
|
|
219
|
-
if (msg.role === "user") {
|
|
220
|
-
const isRuntimeContextCarrier = msg.runtimeContextCarrier === true;
|
|
221
|
-
if (typeof msg.content === "string") {
|
|
222
|
-
const userParam = {
|
|
223
|
-
role: "user",
|
|
224
|
-
content: sanitizeSurrogates(msg.content)
|
|
225
|
-
};
|
|
226
|
-
if (isRuntimeContextCarrier) options.cacheOptOutIndexes?.add(params.length);
|
|
227
|
-
params.push(userParam);
|
|
228
|
-
} else {
|
|
229
|
-
const content = msg.content.map((item) => {
|
|
230
|
-
if (item.type === "text") return {
|
|
231
|
-
type: "text",
|
|
232
|
-
text: sanitizeSurrogates(item.text)
|
|
233
|
-
};
|
|
234
|
-
return {
|
|
235
|
-
type: "image_url",
|
|
236
|
-
image_url: { url: `data:${item.mimeType};base64,${item.data}` }
|
|
237
|
-
};
|
|
238
|
-
});
|
|
239
|
-
if (content.length === 0) continue;
|
|
240
|
-
const userParam = {
|
|
241
|
-
role: "user",
|
|
242
|
-
content
|
|
243
|
-
};
|
|
244
|
-
if (isRuntimeContextCarrier) options.cacheOptOutIndexes?.add(params.length);
|
|
245
|
-
params.push(userParam);
|
|
246
|
-
}
|
|
247
|
-
} else if (msg.role === "assistant") {
|
|
248
|
-
const assistantMsg = {
|
|
249
|
-
role: "assistant",
|
|
250
|
-
content: compat.requiresAssistantAfterToolResult ? "" : null
|
|
251
|
-
};
|
|
252
|
-
const assistantTextParts = msg.content.filter(isTextContentBlock).filter((block) => block.text.trim().length > 0).map((block) => ({
|
|
253
|
-
type: "text",
|
|
254
|
-
text: sanitizeSurrogates(block.text)
|
|
255
|
-
}));
|
|
256
|
-
const assistantText = assistantTextParts.map((part) => part.text).join("");
|
|
257
|
-
const nonEmptyThinkingBlocks = msg.content.filter(isThinkingContentBlock).filter((block) => block.thinking.trim().length > 0);
|
|
258
|
-
if (nonEmptyThinkingBlocks.length > 0) if (compat.requiresThinkingAsText) assistantMsg.content = [{
|
|
259
|
-
type: "text",
|
|
260
|
-
text: nonEmptyThinkingBlocks.map((block) => sanitizeSurrogates(block.thinking)).join("\n\n")
|
|
261
|
-
}, ...assistantTextParts];
|
|
262
|
-
else {
|
|
263
|
-
if (assistantText.length > 0) assistantMsg.content = assistantText;
|
|
264
|
-
let signature = nonEmptyThinkingBlocks.at(0)?.thinkingSignature;
|
|
265
|
-
if (model.provider === "opencode-go" && signature === "reasoning") signature = "reasoning_content";
|
|
266
|
-
if (signature && signature.length > 0) assistantMsg[signature] = nonEmptyThinkingBlocks.map((block) => block.thinking).join("\n");
|
|
267
|
-
}
|
|
268
|
-
else if (assistantText.length > 0) assistantMsg.content = assistantText;
|
|
269
|
-
const toolCalls = msg.content.filter(isToolCallBlock);
|
|
270
|
-
if (toolCalls.length > 0) {
|
|
271
|
-
assistantMsg.tool_calls = toolCalls.map((toolCall) => ({
|
|
272
|
-
id: toolCall.id,
|
|
273
|
-
type: "function",
|
|
274
|
-
function: {
|
|
275
|
-
name: toolCall.name,
|
|
276
|
-
arguments: JSON.stringify(toolCall.arguments)
|
|
277
|
-
}
|
|
278
|
-
}));
|
|
279
|
-
const reasoningDetails = toolCalls.flatMap((toolCall) => {
|
|
280
|
-
const signature = toolCall.thoughtSignature;
|
|
281
|
-
if (!signature) return [];
|
|
282
|
-
try {
|
|
283
|
-
const parsed = JSON.parse(signature);
|
|
284
|
-
return parsed ? [parsed] : [];
|
|
285
|
-
} catch {
|
|
286
|
-
return [];
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
if (reasoningDetails.length > 0) assistantMsg.reasoning_details = reasoningDetails;
|
|
290
|
-
}
|
|
291
|
-
if (compat.requiresReasoningContentOnAssistantMessages && model.reasoning && assistantMsg.reasoning_content === void 0) assistantMsg.reasoning_content = "";
|
|
292
|
-
const content = assistantMsg.content;
|
|
293
|
-
if (!(content !== null && content !== void 0 && (typeof content === "string" ? content.length > 0 : content.length > 0)) && !assistantMsg.tool_calls) continue;
|
|
294
|
-
params.push(assistantMsg);
|
|
295
|
-
} else if (msg.role === "toolResult") {
|
|
296
|
-
const imageBlocks = [];
|
|
297
|
-
let j = i;
|
|
298
|
-
while (j < transformedMessages.length) {
|
|
299
|
-
const toolMsg = transformedMessages.at(j);
|
|
300
|
-
if (toolMsg?.role !== "toolResult") break;
|
|
301
|
-
const textResult = extractToolResultText(toolMsg.content);
|
|
302
|
-
const mediaPlaceholder = describeToolResultMediaPlaceholder(toolMsg.content);
|
|
303
|
-
const hasImages = toolMsg.content.some(isImageWithMediaPayload);
|
|
304
|
-
const toolResultMsg = {
|
|
305
|
-
role: "tool",
|
|
306
|
-
content: sanitizeToolResultText(textResult, mediaPlaceholder ?? EMPTY_TOOL_RESULT_TEXT),
|
|
307
|
-
tool_call_id: toolMsg.toolCallId
|
|
308
|
-
};
|
|
309
|
-
if (compat.requiresToolResultName && toolMsg.toolName) toolResultMsg.name = toolMsg.toolName;
|
|
310
|
-
params.push(toolResultMsg);
|
|
311
|
-
if (hasImages && model.input.includes("image")) {
|
|
312
|
-
for (const block of toolMsg.content) if (isImageWithMediaPayload(block)) imageBlocks.push({
|
|
313
|
-
type: "image_url",
|
|
314
|
-
image_url: { url: `data:${block.mimeType};base64,${block.data}` }
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
j += 1;
|
|
318
|
-
}
|
|
319
|
-
i = j - 1;
|
|
320
|
-
if (imageBlocks.length > 0) {
|
|
321
|
-
if (compat.requiresAssistantAfterToolResult) params.push({
|
|
322
|
-
role: "assistant",
|
|
323
|
-
content: "I have processed the tool results."
|
|
324
|
-
});
|
|
325
|
-
params.push({
|
|
326
|
-
role: "user",
|
|
327
|
-
content: [{
|
|
328
|
-
type: "text",
|
|
329
|
-
text: "Attached image(s) from tool result:"
|
|
330
|
-
}, ...imageBlocks]
|
|
331
|
-
});
|
|
332
|
-
lastRole = "user";
|
|
333
|
-
} else lastRole = "toolResult";
|
|
334
|
-
continue;
|
|
335
|
-
}
|
|
336
|
-
lastRole = msg.role;
|
|
337
|
-
}
|
|
338
|
-
return params;
|
|
339
|
-
}
|
|
340
|
-
//#endregion
|
|
341
|
-
//#region packages/ai/src/providers/openai-stop-reason.ts
|
|
342
|
-
function mapOpenAIStopReason(reason, options) {
|
|
343
|
-
if (reason === null) return { stopReason: "stop" };
|
|
344
|
-
switch (reason) {
|
|
345
|
-
case "stop":
|
|
346
|
-
case "end": return { stopReason: "stop" };
|
|
347
|
-
case "length": return { stopReason: "length" };
|
|
348
|
-
case "function_call":
|
|
349
|
-
case "tool_calls": return { stopReason: "toolUse" };
|
|
350
|
-
case "tool_call":
|
|
351
|
-
if (options?.allowSingularToolCall) return { stopReason: "toolUse" };
|
|
352
|
-
break;
|
|
353
|
-
case "content_filter": return {
|
|
354
|
-
stopReason: "error",
|
|
355
|
-
errorMessage: "Provider finish_reason: content_filter"
|
|
356
|
-
};
|
|
357
|
-
case "network_error": return {
|
|
358
|
-
stopReason: "error",
|
|
359
|
-
errorMessage: "Provider finish_reason: network_error"
|
|
360
|
-
};
|
|
361
|
-
}
|
|
362
|
-
return {
|
|
363
|
-
stopReason: "error",
|
|
364
|
-
errorMessage: `Provider finish_reason: ${reason}`
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
//#endregion
|
|
368
|
-
//#region packages/ai/src/transports/openai-reasoning-compat.ts
|
|
369
|
-
/**
|
|
370
|
-
* OpenAI reasoning-effort compatibility helpers.
|
|
371
|
-
*
|
|
372
|
-
* Keeps provider metadata and built-in model exceptions on one path before request payloads are built.
|
|
373
|
-
*/
|
|
374
|
-
const OPENAI_MEDIUM_ONLY_REASONING_MODEL_IDS = /* @__PURE__ */ new Set(["gpt-5.1-codex-mini"]);
|
|
375
|
-
function readCompatReasoningEffortMap(compat) {
|
|
376
|
-
if (!compat || typeof compat !== "object") return {};
|
|
377
|
-
const rawMap = compat.reasoningEffortMap;
|
|
378
|
-
if (!rawMap || typeof rawMap !== "object") return {};
|
|
379
|
-
return Object.fromEntries(Object.entries(rawMap).filter((entry) => typeof entry[0] === "string" && typeof entry[1] === "string"));
|
|
380
|
-
}
|
|
381
|
-
/** Resolves the reasoning effort remap for an OpenAI-compatible model. */
|
|
382
|
-
function resolveOpenAIReasoningEffortMap(model, fallbackMap = {}) {
|
|
383
|
-
const provider = normalizeLowercaseStringOrEmpty(model.provider ?? "");
|
|
384
|
-
const id = normalizeLowercaseStringOrEmpty(model.id ?? "");
|
|
385
|
-
const builtinMap = provider === "openai" && OPENAI_MEDIUM_ONLY_REASONING_MODEL_IDS.has(id) ? {
|
|
386
|
-
minimal: "medium",
|
|
387
|
-
low: "medium"
|
|
388
|
-
} : {};
|
|
389
|
-
return {
|
|
390
|
-
...fallbackMap,
|
|
391
|
-
...builtinMap,
|
|
392
|
-
...readCompatReasoningEffortMap(model.compat)
|
|
393
|
-
};
|
|
394
|
-
}
|
|
395
|
-
//#endregion
|
|
396
|
-
export { resolveOpenAICompletionsCompat as a, clearPendingCommentaryText as c, detectOpenAICompletionsCompat as i, rememberPendingCommentaryTags as l, mapOpenAIStopReason as n, resolveOpenAICompletionsResponseFormat as o, convertMessages as r, shouldOmitOllamaCompatResponseFormat as s, resolveOpenAIReasoningEffortMap as t, tagPendingCommentaryText as u };
|