@openclaw/ai 2026.7.2-beta.3 → 2026.7.2-beta.5
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-D7SyZQ5v.mjs → anthropic-CQVj3le6.mjs} +174 -33
- package/dist/{index-BoTnz8cv.d.mts → anthropic-SrGtwsJu.d.mts} +27 -1
- package/dist/{api-registry-DXBIXISf.d.mts → api-registry-DlMgPR39.d.mts} +1 -2
- package/dist/{azure-openai-responses-BkZgyZ3I.mjs → azure-openai-responses-DIYgsqFM.mjs} +7 -11
- package/dist/{env-api-keys-DnhYpc27.mjs → env-api-keys-DrgeBuva.mjs} +1 -1
- package/dist/error-coercion-DgxlWC0n.mjs +15 -0
- package/dist/{event-stream-BPemFrFW.d.mts → event-stream-YjaPW20U.d.mts} +1 -1
- package/dist/event-stream.d.mts +1 -1
- package/dist/{tool-schema-json-projection-BwNu3nDi.mjs → github-copilot-headers-BCoBNmL7.mjs} +48 -1
- package/dist/{google-C_biGbV7.mjs → google-f-A8xrae.mjs} +4 -4
- package/dist/{google-shared-BK-NoHl8.mjs → google-shared-J6qvYINH.mjs} +5 -4
- package/dist/{google-vertex-CvdzF1U7.mjs → google-vertex-D3yMVXIY.mjs} +3 -3
- package/dist/host-B9GUmcra.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 +3 -3
- package/dist/internal/anthropic.d.mts +15 -11
- package/dist/internal/anthropic.mjs +4 -4
- package/dist/internal/openai.d.mts +3 -280
- package/dist/internal/openai.mjs +5 -7
- package/dist/internal/runtime.d.mts +13 -34
- package/dist/internal/runtime.mjs +19 -11
- package/dist/internal/shared.d.mts +13 -8
- package/dist/internal/shared.mjs +2 -2
- package/dist/{mistral-BdrQmDWp.mjs → mistral-CKV-TOQj.mjs} +7 -6
- package/dist/number-coercion-DvG7SNMg.mjs +129 -0
- package/dist/openai-BPor_3WI.d.mts +358 -0
- package/dist/{openai-responses-shared-CwnGU0KW.mjs → openai-D3PD6PE-.mjs} +1890 -705
- package/dist/{openai-chatgpt-responses-DP63Qt01.mjs → openai-chatgpt-responses-CedIj0hk.mjs} +54 -58
- package/dist/{openai-completions-zLDfebnN.mjs → openai-completions-CiSutyu0.mjs} +459 -104
- package/dist/openai-prompt-cache-2uo_1OR1.d.mts +7 -0
- package/dist/openai-prompt-cache-mZTCdRPo.mjs +12 -0
- package/dist/prompt-cache-stability-Cwcjv_fx.d.mts +13 -0
- package/dist/{provider-error-LMfTEkfO.mjs → provider-error-apVOZI6G.mjs} +9 -2
- package/dist/providers.d.mts +3 -2
- package/dist/providers.mjs +10 -9
- package/dist/{transform-messages-eb6lxDLB.mjs → shared-CdjNZd35.mjs} +273 -161
- package/dist/{src-CXno1H5g.mjs → src-QkygScBs.mjs} +23 -4
- package/dist/stream-first-event-timeout-C3OgBjIk.mjs +12294 -0
- package/dist/stream-first-event-timeout-DvDeSucC.d.mts +29 -0
- package/dist/transport-stream-shared-BbMELSI4.mjs +297 -0
- package/dist/transports.d.mts +593 -0
- package/dist/transports.mjs +4069 -0
- package/dist/{types-CYORveZ7.d.mts → types-bzp5k29J.d.mts} +8 -0
- package/dist/types.d.mts +5 -5
- package/dist/types.mjs +2 -2
- package/dist/{validation-BX8euiDv.d.mts → validation-B-j7cOYp.d.mts} +1 -1
- package/dist/validation.d.mts +1 -1
- package/package.json +36 -11
- package/dist/azure-openai-responses-client-compat-C7K7QfUE.mjs +0 -62
- package/dist/github-copilot-headers-BsH5cqGj.mjs +0 -48
- package/dist/host-4t713IeR.mjs +0 -37
- package/dist/model-utils-1GiZ2_rr.mjs +0 -64
- package/dist/openai-responses-ClspWt4I.mjs +0 -136
- package/dist/openai-tool-projection-WHf2nuOI.mjs +0 -200
- package/dist/reasoning-tag-text-partitioner-BlVe67g6.mjs +0 -400
- package/dist/stream-first-event-timeout-RjWszj8c.mjs +0 -106
- package/npm-shrinkwrap.json +0 -645
|
@@ -1,17 +1,245 @@
|
|
|
1
|
-
import { n as getEnvApiKey, r as __exportAll } from "./env-api-keys-
|
|
1
|
+
import { n as getEnvApiKey, r as __exportAll } from "./env-api-keys-DrgeBuva.mjs";
|
|
2
2
|
import { t as AssistantMessageEventStream } from "./event-stream-D8n2uFee.mjs";
|
|
3
|
-
import { n as getAiTransportHost } from "./host-
|
|
4
|
-
import { n as
|
|
3
|
+
import { n as getAiTransportHost } from "./host-XYGZcgO8.mjs";
|
|
4
|
+
import { n as clampOpenAIPromptCacheKey } from "./openai-prompt-cache-mZTCdRPo.mjs";
|
|
5
|
+
import { A as buildBaseOptions, E as isImageWithMediaPayload, O as isRecord, S as describeToolResultMediaPlaceholder, a as splitSystemPromptCacheBoundary, o as stripSystemPromptCacheBoundary, u as transformMessages, w as extractToolResultText, y as normalizeLowercaseStringOrEmpty } from "./shared-CdjNZd35.mjs";
|
|
6
|
+
import { t as sanitizeSurrogates } from "./sanitize-unicode-DT5o51ur.mjs";
|
|
7
|
+
import { c as calculateCost, l as clampThinkingLevel, s as applyProviderReportedUsageCost } from "./number-coercion-DvG7SNMg.mjs";
|
|
8
|
+
import { d as transportAbortError } from "./transport-stream-shared-BbMELSI4.mjs";
|
|
5
9
|
import { t as headersToRecord } from "./headers-B_e4-1J0.mjs";
|
|
6
10
|
import { n as parseStreamingJson } from "./json-parse-BvXNt1-7.mjs";
|
|
7
|
-
import { t as
|
|
8
|
-
import {
|
|
9
|
-
import { a as
|
|
10
|
-
import { t as formatProviderError } from "./provider-error-LMfTEkfO.mjs";
|
|
11
|
-
import { t as createReasoningTagTextPartitioner } from "./reasoning-tag-text-partitioner-BlVe67g6.mjs";
|
|
12
|
-
import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-RjWszj8c.mjs";
|
|
13
|
-
import { a as clampOpenAIPromptCacheKey, n as reconcileOpenAICompletionsToolChoice, t as projectOpenAITools } from "./openai-tool-projection-WHf2nuOI.mjs";
|
|
11
|
+
import { t as formatProviderError } from "./provider-error-apVOZI6G.mjs";
|
|
12
|
+
import { a as resolveCacheRetention, i as resolveCloudflareBaseUrl, n as hasCopilotVisionInput, o as projectRuntimeToolInputSchema, r as isCloudflareProvider, t as buildCopilotDynamicHeaders } from "./github-copilot-headers-BCoBNmL7.mjs";
|
|
13
|
+
import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, o as createReasoningTagTextPartitioner, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-C3OgBjIk.mjs";
|
|
14
14
|
import OpenAI from "openai";
|
|
15
|
+
//#region packages/ai/src/transports/host-policy.ts
|
|
16
|
+
function buildGuardedModelFetch(model, timeoutMs, options) {
|
|
17
|
+
const host = getAiTransportHost();
|
|
18
|
+
if (options !== void 0) return host.buildModelFetch(model, timeoutMs, options) ?? globalThis.fetch;
|
|
19
|
+
if (timeoutMs !== void 0) return host.buildModelFetch(model, timeoutMs) ?? globalThis.fetch;
|
|
20
|
+
return host.buildModelFetch(model) ?? globalThis.fetch;
|
|
21
|
+
}
|
|
22
|
+
function resolveProviderEndpoint(baseUrl) {
|
|
23
|
+
return { endpointClass: getAiTransportHost().resolveProviderEndpointClass(baseUrl) };
|
|
24
|
+
}
|
|
25
|
+
function resolveProviderRequestCapabilities(input) {
|
|
26
|
+
return getAiTransportHost().resolveProviderRequestCapabilities(input);
|
|
27
|
+
}
|
|
28
|
+
function resolveProviderRequestPolicyConfig(input) {
|
|
29
|
+
return { headers: getAiTransportHost().resolveProviderRequestHeaders(input) };
|
|
30
|
+
}
|
|
31
|
+
function resolveModelRequestTimeoutMs(model, timeoutMs) {
|
|
32
|
+
return timeoutMs ?? getAiTransportHost().resolveModelRequestTimeoutMs(model);
|
|
33
|
+
}
|
|
34
|
+
function resolveOpenAIStrictToolSetting(model, options) {
|
|
35
|
+
return getAiTransportHost().resolveOpenAIStrictToolSetting(model, options);
|
|
36
|
+
}
|
|
37
|
+
function transformTransportMessages(messages, model, normalizeToolCallId, options) {
|
|
38
|
+
return getAiTransportHost().transformTransportMessages(messages, model, normalizeToolCallId, options);
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region packages/ai/src/utils/assistant-text-phase.ts
|
|
42
|
+
function isAssistantTextPhaseBlock(block) {
|
|
43
|
+
if (!block || typeof block !== "object") return false;
|
|
44
|
+
const record = block;
|
|
45
|
+
return record.type === "text" && typeof record.text === "string";
|
|
46
|
+
}
|
|
47
|
+
function encodeAssistantTextSignatureV1(id, phase) {
|
|
48
|
+
return JSON.stringify({
|
|
49
|
+
v: 1,
|
|
50
|
+
id,
|
|
51
|
+
...phase ? { phase } : {}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/** Tags unphased narration before a tool-call event becomes consumer-visible. */
|
|
55
|
+
function tagPendingCommentaryText(content) {
|
|
56
|
+
const textBlocks = content.filter(isAssistantTextPhaseBlock);
|
|
57
|
+
let commentaryIndex = textBlocks.filter((block) => block.textSignature !== void 0).length;
|
|
58
|
+
const tagged = /* @__PURE__ */ new Map();
|
|
59
|
+
for (const block of textBlocks) {
|
|
60
|
+
if (block.text.trim().length === 0 || block.textSignature !== void 0) continue;
|
|
61
|
+
const signature = encodeAssistantTextSignatureV1(`commentary-${commentaryIndex}`, "commentary");
|
|
62
|
+
block.textSignature = signature;
|
|
63
|
+
tagged.set(block, signature);
|
|
64
|
+
commentaryIndex += 1;
|
|
65
|
+
}
|
|
66
|
+
return tagged;
|
|
67
|
+
}
|
|
68
|
+
/** Rolls back only the exact provisional signatures created by this transport turn. */
|
|
69
|
+
function clearPendingCommentaryText(tags) {
|
|
70
|
+
for (const [block, signature] of tags) if (block.textSignature === signature) delete block.textSignature;
|
|
71
|
+
tags.clear();
|
|
72
|
+
}
|
|
73
|
+
function rememberPendingCommentaryTags(target, tagged) {
|
|
74
|
+
for (const [block, signature] of tagged) target.set(block, signature);
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region packages/ai/src/providers/openai-response-format.ts
|
|
78
|
+
const JSON_SCHEMA_RESPONSE_FORMAT_NAME = "openclaw_response";
|
|
79
|
+
const OLLAMA_CLOUD_ORIGIN = "https://ollama.com";
|
|
80
|
+
function isKnownOpenAIJsonSchemaModelId(modelId) {
|
|
81
|
+
if (typeof modelId !== "string") return false;
|
|
82
|
+
if (/^gpt-5(?:[.-]|$)/i.test(modelId) || /^gpt-4\.1(?:-|$)/i.test(modelId)) return true;
|
|
83
|
+
const gpt4o = /^gpt-4o(-mini)?(?:-(\d{4}-\d{2}-\d{2}))?$/i.exec(modelId);
|
|
84
|
+
if (gpt4o) {
|
|
85
|
+
const snapshot = gpt4o[2];
|
|
86
|
+
return !snapshot || snapshot >= (gpt4o[1] ? "2024-07-18" : "2024-08-06");
|
|
87
|
+
}
|
|
88
|
+
return /^(?:o1|o3(?:-mini|-pro)?|o4-mini)(?:-\d{4}-\d{2}-\d{2})?$/i.test(modelId);
|
|
89
|
+
}
|
|
90
|
+
function shouldOmitOllamaCompatResponseFormat(params) {
|
|
91
|
+
if (!params.provider.includes("ollama")) return false;
|
|
92
|
+
if (params.hasTools()) return true;
|
|
93
|
+
try {
|
|
94
|
+
return new URL(params.baseUrl).origin === OLLAMA_CLOUD_ORIGIN;
|
|
95
|
+
} catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Maps the shared JSON Schema option to Chat Completions while preserving the
|
|
101
|
+
* older provider-shaped json_object/json_schema inputs accepted by model params.
|
|
102
|
+
*/
|
|
103
|
+
function resolveOpenAICompletionsResponseFormat(responseFormat, supportsJsonSchemaResponseFormat) {
|
|
104
|
+
if (!responseFormat) return;
|
|
105
|
+
if (responseFormat.type === "json_object") return responseFormat;
|
|
106
|
+
if (responseFormat.type === "text") return responseFormat;
|
|
107
|
+
if (responseFormat.type === "json_schema" && isRecord(responseFormat.json_schema)) return responseFormat;
|
|
108
|
+
if (!supportsJsonSchemaResponseFormat) return;
|
|
109
|
+
return {
|
|
110
|
+
type: "json_schema",
|
|
111
|
+
json_schema: {
|
|
112
|
+
name: JSON_SCHEMA_RESPONSE_FORMAT_NAME,
|
|
113
|
+
schema: responseFormat
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
//#endregion
|
|
118
|
+
//#region packages/ai/src/transports/openai-completions-compat.ts
|
|
119
|
+
function isDefaultRouteProvider(provider, ...ids) {
|
|
120
|
+
return provider !== void 0 && ids.includes(provider);
|
|
121
|
+
}
|
|
122
|
+
/** Resolves default request flags for an OpenAI-compatible completions endpoint. */
|
|
123
|
+
function resolveOpenAICompletionsCompatDefaults(input) {
|
|
124
|
+
const { provider, modelId, endpointClass, knownProviderFamily, supportsNativeStreamingUsageCompat = false, supportsOpenAICompletionsStreamingUsageCompat = false, usesExplicitProxyLikeEndpoint = false } = input;
|
|
125
|
+
const isDefaultRoute = endpointClass === "default";
|
|
126
|
+
const usesConfiguredNonOpenAIEndpoint = endpointClass !== "default" && endpointClass !== "openai-public";
|
|
127
|
+
const isMoonshot = knownProviderFamily === "moonshot" || endpointClass === "moonshot-native";
|
|
128
|
+
const isMoonshotLike = isMoonshot || knownProviderFamily === "modelstudio" || endpointClass === "modelstudio-native";
|
|
129
|
+
const isModelStudioLike = knownProviderFamily === "modelstudio" || endpointClass === "modelstudio-native" || isDefaultRoute && isDefaultRouteProvider(provider, "dashscope", "modelstudio", "qwen");
|
|
130
|
+
const isZai = endpointClass === "zai-native" || isDefaultRoute && isDefaultRouteProvider(input.provider, "zai");
|
|
131
|
+
const isDeepSeek = endpointClass === "deepseek-native" || isDefaultRoute && isDefaultRouteProvider(input.provider, "deepseek");
|
|
132
|
+
const isTogether = knownProviderFamily === "together" || input.baseUrl?.includes("api.together.ai") === true || input.baseUrl?.includes("api.together.xyz") === true || isDefaultRoute && isDefaultRouteProvider(input.provider, "together");
|
|
133
|
+
const isCloudflareAiGateway = provider === "cloudflare-ai-gateway" || input.baseUrl?.includes("gateway.ai.cloudflare.com") === true;
|
|
134
|
+
const isXiaomi = endpointClass === "xiaomi-native" || isDefaultRoute && isDefaultRouteProvider(input.provider, "xiaomi");
|
|
135
|
+
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");
|
|
136
|
+
const isOpenRouterLike = input.provider === "openrouter" || endpointClass === "openrouter";
|
|
137
|
+
const isLocalEndpoint = endpointClass === "local";
|
|
138
|
+
const usesMaxTokens = endpointClass === "chutes-native" || endpointClass === "mistral-public" || knownProviderFamily === "mistral" || isMoonshot || isCloudflareAiGateway || isZai || isTogether || isDefaultRoute && isDefaultRouteProvider(provider, "chutes");
|
|
139
|
+
return {
|
|
140
|
+
supportsStore: !isNonStandard && knownProviderFamily !== "mistral" && !usesExplicitProxyLikeEndpoint,
|
|
141
|
+
supportsDeveloperRole: !isNonStandard && !isMoonshotLike && !usesConfiguredNonOpenAIEndpoint,
|
|
142
|
+
supportsReasoningEffort: !isZai && !isTogether && knownProviderFamily !== "mistral" && endpointClass !== "xai-native" && !usesExplicitProxyLikeEndpoint,
|
|
143
|
+
supportsUsageInStreaming: supportsOpenAICompletionsStreamingUsageCompat || !isNonStandard && (isLocalEndpoint || !usesConfiguredNonOpenAIEndpoint || supportsNativeStreamingUsageCompat),
|
|
144
|
+
maxTokensField: usesMaxTokens ? "max_tokens" : "max_completion_tokens",
|
|
145
|
+
thinkingFormat: isDeepSeek || isXiaomi ? "deepseek" : isZai ? "zai" : isTogether ? "together" : isOpenRouterLike ? "openrouter" : "openai",
|
|
146
|
+
visibleReasoningDetailTypes: isOpenRouterLike ? ["response.output_text", "response.text"] : [],
|
|
147
|
+
supportsStrictMode: !isZai && !usesConfiguredNonOpenAIEndpoint,
|
|
148
|
+
supportsJsonSchemaResponseFormat: (endpointClass === "openai-public" || isDefaultRoute && isDefaultRouteProvider(provider, "openai")) && isKnownOpenAIJsonSchemaModelId(modelId),
|
|
149
|
+
requiresReasoningContentOnAssistantMessages: isDeepSeek || isXiaomi,
|
|
150
|
+
requiresNonEmptyUserOrAssistantMessage: isModelStudioLike,
|
|
151
|
+
cacheControlFormat: provider === "openrouter" && modelId?.startsWith("anthropic/") === true ? "anthropic" : void 0,
|
|
152
|
+
sessionAffinityFormat: isOpenRouterLike ? "openrouter" : "openai",
|
|
153
|
+
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")
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function resolveOpenAICompletionsCompatDefaultsFromCapabilities(input) {
|
|
157
|
+
return resolveOpenAICompletionsCompatDefaults(input);
|
|
158
|
+
}
|
|
159
|
+
/** Detects endpoint capabilities and defaults for an OpenAI-completions model. */
|
|
160
|
+
function detectOpenAICompletionsCompat(model, resolveCapabilities = resolveProviderRequestCapabilities) {
|
|
161
|
+
const capabilities = resolveCapabilities({
|
|
162
|
+
provider: model.provider,
|
|
163
|
+
api: "openai-completions",
|
|
164
|
+
baseUrl: model.baseUrl,
|
|
165
|
+
capability: "llm",
|
|
166
|
+
transport: "stream",
|
|
167
|
+
modelId: model.id,
|
|
168
|
+
compat: model.compat && typeof model.compat === "object" ? model.compat : void 0
|
|
169
|
+
});
|
|
170
|
+
return {
|
|
171
|
+
capabilities,
|
|
172
|
+
defaults: resolveOpenAICompletionsCompatDefaultsFromCapabilities({
|
|
173
|
+
provider: model.provider,
|
|
174
|
+
modelId: model.id,
|
|
175
|
+
baseUrl: model.baseUrl,
|
|
176
|
+
...capabilities
|
|
177
|
+
})
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function resolveSessionAffinity(model, detectedFormat) {
|
|
181
|
+
if (model.compat?.sendSessionAffinityHeaders !== true) return "none";
|
|
182
|
+
if (detectedFormat === "openrouter" || model.compat.thinkingFormat === "openrouter" || model.compat.openRouterRouting !== void 0) return "openrouter";
|
|
183
|
+
return "openai";
|
|
184
|
+
}
|
|
185
|
+
/** Applies explicit model overrides once on top of the canonical transport defaults. */
|
|
186
|
+
function resolveOpenAICompletionsCompat(model, resolveCapabilities = resolveProviderRequestCapabilities) {
|
|
187
|
+
const { defaults } = detectOpenAICompletionsCompat(model, resolveCapabilities);
|
|
188
|
+
const configured = model.compat;
|
|
189
|
+
return {
|
|
190
|
+
supportsStore: configured?.supportsStore ?? defaults.supportsStore,
|
|
191
|
+
supportsDeveloperRole: configured?.supportsDeveloperRole ?? defaults.supportsDeveloperRole,
|
|
192
|
+
supportsReasoningEffort: configured?.supportsReasoningEffort ?? defaults.supportsReasoningEffort,
|
|
193
|
+
supportsUsageInStreaming: configured?.supportsUsageInStreaming ?? defaults.supportsUsageInStreaming,
|
|
194
|
+
maxTokensField: configured?.maxTokensField ?? defaults.maxTokensField,
|
|
195
|
+
requiresToolResultName: configured?.requiresToolResultName ?? false,
|
|
196
|
+
requiresAssistantAfterToolResult: configured?.requiresAssistantAfterToolResult ?? false,
|
|
197
|
+
requiresThinkingAsText: configured?.requiresThinkingAsText ?? false,
|
|
198
|
+
requiresReasoningContentOnAssistantMessages: configured?.requiresReasoningContentOnAssistantMessages ?? defaults.requiresReasoningContentOnAssistantMessages,
|
|
199
|
+
thinkingFormat: configured?.thinkingFormat ?? defaults.thinkingFormat,
|
|
200
|
+
openRouterRouting: configured?.openRouterRouting,
|
|
201
|
+
vercelGatewayRouting: configured?.vercelGatewayRouting ?? {},
|
|
202
|
+
zaiToolStream: configured?.zaiToolStream ?? false,
|
|
203
|
+
supportsStrictMode: configured?.supportsStrictMode ?? defaults.supportsStrictMode,
|
|
204
|
+
supportsJsonSchemaResponseFormat: configured?.supportsJsonSchemaResponseFormat ?? defaults.supportsJsonSchemaResponseFormat,
|
|
205
|
+
cacheControlFormat: configured?.cacheControlFormat ?? defaults.cacheControlFormat,
|
|
206
|
+
sessionAffinity: resolveSessionAffinity(model, defaults.sessionAffinityFormat),
|
|
207
|
+
supportsPromptCacheKey: configured?.supportsPromptCacheKey ?? false,
|
|
208
|
+
supportsLongCacheRetention: configured?.supportsLongCacheRetention ?? defaults.supportsLongCacheRetention,
|
|
209
|
+
visibleReasoningDetailTypes: configured && "visibleReasoningDetailTypes" in configured ? configured.visibleReasoningDetailTypes ?? defaults.visibleReasoningDetailTypes : defaults.visibleReasoningDetailTypes,
|
|
210
|
+
requiresNonEmptyUserOrAssistantMessage: defaults.requiresNonEmptyUserOrAssistantMessage
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
if (process.env.VITEST || false) globalThis[Symbol.for("openclaw.openAICompletionsCompatTestApi")] = { resolveOpenAICompletionsCompatDefaults };
|
|
214
|
+
//#endregion
|
|
215
|
+
//#region packages/ai/src/transports/openai-reasoning-compat.ts
|
|
216
|
+
/**
|
|
217
|
+
* OpenAI reasoning-effort compatibility helpers.
|
|
218
|
+
*
|
|
219
|
+
* Keeps provider metadata and built-in model exceptions on one path before request payloads are built.
|
|
220
|
+
*/
|
|
221
|
+
const OPENAI_MEDIUM_ONLY_REASONING_MODEL_IDS = /* @__PURE__ */ new Set(["gpt-5.1-codex-mini"]);
|
|
222
|
+
function readCompatReasoningEffortMap(compat) {
|
|
223
|
+
if (!compat || typeof compat !== "object") return {};
|
|
224
|
+
const rawMap = compat.reasoningEffortMap;
|
|
225
|
+
if (!rawMap || typeof rawMap !== "object") return {};
|
|
226
|
+
return Object.fromEntries(Object.entries(rawMap).filter((entry) => typeof entry[0] === "string" && typeof entry[1] === "string"));
|
|
227
|
+
}
|
|
228
|
+
/** Resolves the reasoning effort remap for an OpenAI-compatible model. */
|
|
229
|
+
function resolveOpenAIReasoningEffortMap(model, fallbackMap = {}) {
|
|
230
|
+
const provider = normalizeLowercaseStringOrEmpty(model.provider ?? "");
|
|
231
|
+
const id = normalizeLowercaseStringOrEmpty(model.id ?? "");
|
|
232
|
+
const builtinMap = provider === "openai" && OPENAI_MEDIUM_ONLY_REASONING_MODEL_IDS.has(id) ? {
|
|
233
|
+
minimal: "medium",
|
|
234
|
+
low: "medium"
|
|
235
|
+
} : {};
|
|
236
|
+
return {
|
|
237
|
+
...fallbackMap,
|
|
238
|
+
...builtinMap,
|
|
239
|
+
...readCompatReasoningEffortMap(model.compat)
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
//#endregion
|
|
15
243
|
//#region packages/ai/src/providers/openai-stop-reason.ts
|
|
16
244
|
function mapOpenAIStopReason(reason, options) {
|
|
17
245
|
if (reason === null) return { stopReason: "stop" };
|
|
@@ -39,6 +267,192 @@ function mapOpenAIStopReason(reason, options) {
|
|
|
39
267
|
};
|
|
40
268
|
}
|
|
41
269
|
//#endregion
|
|
270
|
+
//#region packages/ai/src/providers/openai-tool-projection.ts
|
|
271
|
+
function unreadableToolDiagnostic(toolIndex) {
|
|
272
|
+
return {
|
|
273
|
+
toolIndex,
|
|
274
|
+
violations: [`tool[${toolIndex}] is unreadable`]
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
/** Snapshots direct/custom tool descriptors before OpenAI payload construction. */
|
|
278
|
+
function projectOpenAITools(tools) {
|
|
279
|
+
let inputToolCount;
|
|
280
|
+
try {
|
|
281
|
+
inputToolCount = tools.length;
|
|
282
|
+
} catch {
|
|
283
|
+
return {
|
|
284
|
+
inputToolCount: 0,
|
|
285
|
+
tools: [],
|
|
286
|
+
diagnostics: [unreadableToolDiagnostic(0)]
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
const projectedTools = [];
|
|
290
|
+
const diagnostics = [];
|
|
291
|
+
for (let toolIndex = 0; toolIndex < inputToolCount; toolIndex += 1) {
|
|
292
|
+
let tool;
|
|
293
|
+
try {
|
|
294
|
+
const candidate = tools[toolIndex];
|
|
295
|
+
if (!candidate) {
|
|
296
|
+
diagnostics.push(unreadableToolDiagnostic(toolIndex));
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
tool = candidate;
|
|
300
|
+
} catch {
|
|
301
|
+
diagnostics.push(unreadableToolDiagnostic(toolIndex));
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
let name;
|
|
305
|
+
try {
|
|
306
|
+
name = tool.name;
|
|
307
|
+
} catch {
|
|
308
|
+
diagnostics.push({
|
|
309
|
+
toolIndex,
|
|
310
|
+
violations: [`tool[${toolIndex}].name is unreadable`]
|
|
311
|
+
});
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (typeof name !== "string" || !name) {
|
|
315
|
+
diagnostics.push({
|
|
316
|
+
toolIndex,
|
|
317
|
+
violations: [`tool[${toolIndex}].name is empty`]
|
|
318
|
+
});
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
let parameters;
|
|
322
|
+
try {
|
|
323
|
+
parameters = tool.parameters;
|
|
324
|
+
} catch {
|
|
325
|
+
diagnostics.push({
|
|
326
|
+
toolIndex,
|
|
327
|
+
toolName: name,
|
|
328
|
+
violations: [`${name}.parameters is unreadable`]
|
|
329
|
+
});
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
const schemaProjection = projectRuntimeToolInputSchema(parameters ?? {}, `${name}.parameters`);
|
|
333
|
+
if (!isRecord(schemaProjection.schema) || schemaProjection.violations.length > 0) {
|
|
334
|
+
diagnostics.push({
|
|
335
|
+
toolIndex,
|
|
336
|
+
toolName: name,
|
|
337
|
+
violations: schemaProjection.violations.length > 0 ? schemaProjection.violations : [`${name}.parameters must be a JSON object schema`]
|
|
338
|
+
});
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
let descriptionValue;
|
|
342
|
+
try {
|
|
343
|
+
descriptionValue = tool.description;
|
|
344
|
+
} catch {}
|
|
345
|
+
const description = typeof descriptionValue === "string" ? descriptionValue : void 0;
|
|
346
|
+
projectedTools.push({
|
|
347
|
+
toolIndex,
|
|
348
|
+
name,
|
|
349
|
+
...description !== void 0 ? { description } : {},
|
|
350
|
+
parameters: schemaProjection.schema
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
return {
|
|
354
|
+
inputToolCount,
|
|
355
|
+
tools: projectedTools,
|
|
356
|
+
diagnostics
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
function requireProjectedFunction(name, projection, choiceLabel) {
|
|
360
|
+
if (!projection.tools.some((tool) => tool.name === name)) throw new Error(`${choiceLabel} requested unavailable tool "${name}" after schema conversion`);
|
|
361
|
+
}
|
|
362
|
+
/** Keeps Responses tool choices aligned with surviving function schemas. */
|
|
363
|
+
function reconcileOpenAIResponsesToolChoice(choice, projection) {
|
|
364
|
+
if (choice === "auto") return projection.tools.length > 0 ? choice : void 0;
|
|
365
|
+
if (choice === "required") {
|
|
366
|
+
if (projection.tools.length === 0) throw new Error("OpenAI Responses tool_choice requires a tool, but no tools survived schema conversion");
|
|
367
|
+
return choice;
|
|
368
|
+
}
|
|
369
|
+
if (choice === "none" || !isRecord(choice)) return choice;
|
|
370
|
+
const choiceType = choice.type;
|
|
371
|
+
if (choiceType === "function") {
|
|
372
|
+
const functionName = choice.name;
|
|
373
|
+
if (typeof functionName !== "string") return choice;
|
|
374
|
+
requireProjectedFunction(functionName, projection, "OpenAI Responses tool_choice");
|
|
375
|
+
return {
|
|
376
|
+
type: "function",
|
|
377
|
+
name: functionName
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
if (choiceType !== "allowed_tools") return choice;
|
|
381
|
+
const mode = choice.mode;
|
|
382
|
+
const tools = choice.tools;
|
|
383
|
+
if (mode !== "auto" && mode !== "required" || !Array.isArray(tools)) return choice;
|
|
384
|
+
const normalizedAllowedTools = [];
|
|
385
|
+
for (const tool of tools) {
|
|
386
|
+
if (!isRecord(tool) || tool.type !== "function") {
|
|
387
|
+
normalizedAllowedTools.push(tool);
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
const functionName = tool.name;
|
|
391
|
+
if (typeof functionName === "string" && projection.tools.some((projectedTool) => projectedTool.name === functionName)) normalizedAllowedTools.push({
|
|
392
|
+
type: "function",
|
|
393
|
+
name: functionName
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
if (normalizedAllowedTools.length === 0) {
|
|
397
|
+
if (mode === "auto") return "none";
|
|
398
|
+
throw new Error("OpenAI Responses tool_choice requires a tool, but no allowed tools survived schema conversion");
|
|
399
|
+
}
|
|
400
|
+
return {
|
|
401
|
+
type: "allowed_tools",
|
|
402
|
+
mode,
|
|
403
|
+
tools: normalizedAllowedTools
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
/** Keeps Chat Completions tool choices aligned with surviving function schemas. */
|
|
407
|
+
function reconcileOpenAICompletionsToolChoice(choice, projection) {
|
|
408
|
+
if (choice === "auto") return projection.tools.length > 0 ? choice : void 0;
|
|
409
|
+
if (choice === "required") {
|
|
410
|
+
if (projection.tools.length === 0) throw new Error("OpenAI Chat Completions tool_choice requires a tool, but no tools survived schema conversion");
|
|
411
|
+
return choice;
|
|
412
|
+
}
|
|
413
|
+
if (choice === "none" || !isRecord(choice)) return choice;
|
|
414
|
+
const choiceType = choice.type;
|
|
415
|
+
if (choiceType === "custom") throw new Error("OpenAI Chat Completions custom tool_choice is unsupported because this adapter emits function tools only");
|
|
416
|
+
if (choiceType === "function") {
|
|
417
|
+
const functionChoice = choice.function;
|
|
418
|
+
if (!isRecord(functionChoice)) return choice;
|
|
419
|
+
const functionName = functionChoice.name;
|
|
420
|
+
if (typeof functionName !== "string") return choice;
|
|
421
|
+
requireProjectedFunction(functionName, projection, "OpenAI Chat Completions tool_choice");
|
|
422
|
+
return {
|
|
423
|
+
type: "function",
|
|
424
|
+
function: { name: functionName }
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
if (choiceType !== "allowed_tools") return choice;
|
|
428
|
+
const allowedConfig = choice.allowed_tools;
|
|
429
|
+
if (!isRecord(allowedConfig)) return choice;
|
|
430
|
+
const mode = allowedConfig.mode;
|
|
431
|
+
const tools = allowedConfig.tools;
|
|
432
|
+
if (mode !== "auto" && mode !== "required" || !Array.isArray(tools)) return choice;
|
|
433
|
+
const normalizedAllowedTools = [];
|
|
434
|
+
for (const tool of tools) {
|
|
435
|
+
if (!isRecord(tool) || tool.type !== "function") continue;
|
|
436
|
+
const functionChoice = tool.function;
|
|
437
|
+
const functionName = isRecord(functionChoice) ? functionChoice.name : void 0;
|
|
438
|
+
if (typeof functionName === "string" && projection.tools.some((projectedTool) => projectedTool.name === functionName)) normalizedAllowedTools.push({
|
|
439
|
+
type: "function",
|
|
440
|
+
function: { name: functionName }
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
if (normalizedAllowedTools.length === 0) {
|
|
444
|
+
if (mode === "auto") return "none";
|
|
445
|
+
throw new Error("OpenAI Chat Completions tool_choice requires a tool, but no allowed tools survived schema conversion");
|
|
446
|
+
}
|
|
447
|
+
return {
|
|
448
|
+
type: "allowed_tools",
|
|
449
|
+
allowed_tools: {
|
|
450
|
+
mode,
|
|
451
|
+
tools: normalizedAllowedTools
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
//#endregion
|
|
42
456
|
//#region packages/ai/src/providers/openai-completions.ts
|
|
43
457
|
var openai_completions_exports = /* @__PURE__ */ __exportAll({
|
|
44
458
|
convertMessages: () => convertMessages,
|
|
@@ -104,10 +518,11 @@ const streamOpenAICompletions = (model, context, options) => {
|
|
|
104
518
|
stopReason: "stop",
|
|
105
519
|
timestamp: Date.now()
|
|
106
520
|
};
|
|
521
|
+
const provisionalCommentaryTags = /* @__PURE__ */ new Map();
|
|
107
522
|
let firstEventAbort;
|
|
108
523
|
try {
|
|
109
524
|
const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
|
|
110
|
-
const compat =
|
|
525
|
+
const compat = resolveOpenAICompletionsCompat(model);
|
|
111
526
|
const cacheRetention = resolveCacheRetention(options?.cacheRetention);
|
|
112
527
|
const cacheSessionId = cacheRetention === "none" ? void 0 : options?.sessionId;
|
|
113
528
|
const client = createClient(model, context, apiKey, options?.headers, cacheSessionId, compat);
|
|
@@ -328,9 +743,10 @@ const streamOpenAICompletions = (model, context, options) => {
|
|
|
328
743
|
if (choiceDelta.content !== null && choiceDelta.content !== void 0 && choiceDelta.content.length > 0) appendPartitionedContent(choiceDelta.content, Boolean(foundReasoningField));
|
|
329
744
|
const refusalText = typeof choiceDelta.refusal === "string" ? choiceDelta.refusal : "";
|
|
330
745
|
if (refusalText.length > 0) appendPartitionedContent(refusalText, Boolean(foundReasoningField));
|
|
331
|
-
if (choiceDelta.tool_calls) {
|
|
746
|
+
if (choiceDelta.tool_calls && choiceDelta.tool_calls.length > 0) {
|
|
332
747
|
flushPartitionedContent();
|
|
333
748
|
sealNativeReasoningBeforeText();
|
|
749
|
+
rememberPendingCommentaryTags(provisionalCommentaryTags, tagPendingCommentaryText(output.content));
|
|
334
750
|
for (const toolCall of choiceDelta.tool_calls) {
|
|
335
751
|
const block = ensureToolCallBlock(toolCall);
|
|
336
752
|
if (!block.id && toolCall.id) {
|
|
@@ -366,7 +782,7 @@ const streamOpenAICompletions = (model, context, options) => {
|
|
|
366
782
|
}
|
|
367
783
|
flushPartitionedContent();
|
|
368
784
|
for (const block of blocks) finishBlock(block);
|
|
369
|
-
if (options?.signal?.aborted) throw
|
|
785
|
+
if (options?.signal?.aborted) throw transportAbortError(options.signal);
|
|
370
786
|
if (output.stopReason === "aborted") throw new Error("Request was aborted");
|
|
371
787
|
if (output.stopReason === "error") throw new Error(output.errorMessage || "Provider returned an error stop reason");
|
|
372
788
|
if (!hasFinishReason) throw new Error("Stream ended without finish_reason");
|
|
@@ -375,6 +791,8 @@ const streamOpenAICompletions = (model, context, options) => {
|
|
|
375
791
|
if (output.stopReason === "toolUse" && !hasToolCalls) output.stopReason = "stop";
|
|
376
792
|
if (output.stopReason === "stop" && hasToolCalls && !hasVisibleText) output.stopReason = "toolUse";
|
|
377
793
|
if (hasToolCalls && output.stopReason !== "toolUse") output.content = output.content.filter((block) => block.type !== "toolCall");
|
|
794
|
+
if (output.stopReason !== "toolUse") clearPendingCommentaryText(provisionalCommentaryTags);
|
|
795
|
+
if (output.stopReason === "toolUse") tagPendingCommentaryText(output.content);
|
|
378
796
|
stream.push({
|
|
379
797
|
type: "done",
|
|
380
798
|
reason: output.stopReason,
|
|
@@ -416,7 +834,7 @@ const streamSimpleOpenAICompletions = (model, context, options) => {
|
|
|
416
834
|
toolChoice
|
|
417
835
|
});
|
|
418
836
|
};
|
|
419
|
-
function createClient(model, context, apiKey, optionsHeaders, sessionId, compat =
|
|
837
|
+
function createClient(model, context, apiKey, optionsHeaders, sessionId, compat = resolveOpenAICompletionsCompat(model)) {
|
|
420
838
|
if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
|
|
421
839
|
const headers = { ...model.headers };
|
|
422
840
|
if (model.provider === "github-copilot") {
|
|
@@ -427,7 +845,7 @@ function createClient(model, context, apiKey, optionsHeaders, sessionId, compat
|
|
|
427
845
|
});
|
|
428
846
|
Object.assign(headers, copilotHeaders);
|
|
429
847
|
}
|
|
430
|
-
if (sessionId && compat.
|
|
848
|
+
if (sessionId && compat.sessionAffinity !== "none") if (compat.sessionAffinity === "openrouter") headers["x-session-id"] = sessionId;
|
|
431
849
|
else {
|
|
432
850
|
headers.session_id = sessionId;
|
|
433
851
|
headers["x-client-request-id"] = sessionId;
|
|
@@ -447,7 +865,7 @@ function createClient(model, context, apiKey, optionsHeaders, sessionId, compat
|
|
|
447
865
|
fetch: getAiTransportHost().buildModelFetch(model)
|
|
448
866
|
});
|
|
449
867
|
}
|
|
450
|
-
function buildParams(model, context, options, compat =
|
|
868
|
+
function buildParams(model, context, options, compat = resolveOpenAICompletionsCompat(model), cacheRetention = resolveCacheRetention(options?.cacheRetention)) {
|
|
451
869
|
const cacheControl = getCompatCacheControl(compat, cacheRetention);
|
|
452
870
|
const cacheOptOutIndexes = /* @__PURE__ */ new Set();
|
|
453
871
|
const messages = convertMessages(model, context, compat, {
|
|
@@ -472,6 +890,13 @@ function buildParams(model, context, options, compat = getCompat(model), cacheRe
|
|
|
472
890
|
}
|
|
473
891
|
if (options?.temperature !== void 0) params.temperature = options.temperature;
|
|
474
892
|
if (options?.stop !== void 0 && options.stop.length > 0) params.stop = options.stop;
|
|
893
|
+
const requestedResponseFormat = options?.responseFormat;
|
|
894
|
+
const responseFormat = requestedResponseFormat === void 0 ? void 0 : resolveOpenAICompletionsResponseFormat(shouldOmitOllamaCompatResponseFormat({
|
|
895
|
+
provider: model.provider,
|
|
896
|
+
baseUrl: model.baseUrl,
|
|
897
|
+
hasTools: () => Boolean(context.tools?.length)
|
|
898
|
+
}) ? void 0 : requestedResponseFormat, compat.supportsJsonSchemaResponseFormat);
|
|
899
|
+
if (responseFormat !== void 0) params.response_format = responseFormat;
|
|
475
900
|
let toolProjection;
|
|
476
901
|
if (context.tools) {
|
|
477
902
|
const converted = convertTools(context.tools, compat);
|
|
@@ -485,32 +910,35 @@ function buildParams(model, context, options, compat = getCompat(model), cacheRe
|
|
|
485
910
|
const toolChoice = reconcileOpenAICompletionsToolChoice(options.toolChoice, toolProjection ?? projectOpenAITools([]));
|
|
486
911
|
if (toolChoice !== void 0) params.tool_choice = toolChoice;
|
|
487
912
|
}
|
|
488
|
-
|
|
913
|
+
const reasoningEffortMap = resolveOpenAIReasoningEffortMap(model);
|
|
914
|
+
const reasoningEffort = options?.reasoningEffort === void 0 ? void 0 : reasoningEffortMap[options.reasoningEffort] ?? model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;
|
|
915
|
+
const reasoningEnabled = reasoningEffort !== void 0;
|
|
916
|
+
const offReasoningEffort = reasoningEffortMap.off ?? model.thinkingLevelMap?.off;
|
|
917
|
+
if (compat.thinkingFormat === "zai" && model.reasoning) params.thinking = reasoningEnabled ? {
|
|
489
918
|
type: "enabled",
|
|
490
919
|
clear_thinking: false
|
|
491
920
|
} : { type: "disabled" };
|
|
492
|
-
else if (compat.thinkingFormat === "qwen" && model.reasoning) params.enable_thinking =
|
|
921
|
+
else if (compat.thinkingFormat === "qwen" && model.reasoning) params.enable_thinking = reasoningEnabled;
|
|
493
922
|
else if (compat.thinkingFormat === "qwen-chat-template" && model.reasoning) params.chat_template_kwargs = {
|
|
494
|
-
enable_thinking:
|
|
923
|
+
enable_thinking: reasoningEnabled,
|
|
495
924
|
preserve_thinking: true
|
|
496
925
|
};
|
|
497
926
|
else if (compat.thinkingFormat === "deepseek" && model.reasoning) {
|
|
498
|
-
params.thinking = { type:
|
|
499
|
-
if (
|
|
927
|
+
params.thinking = { type: reasoningEnabled ? "enabled" : "disabled" };
|
|
928
|
+
if (reasoningEnabled && compat.supportsReasoningEffort) params.reasoning_effort = reasoningEffort;
|
|
500
929
|
} else if (compat.thinkingFormat === "openrouter" && model.reasoning) {
|
|
501
930
|
const openRouterParams = params;
|
|
502
|
-
if (
|
|
503
|
-
else if (
|
|
931
|
+
if (reasoningEnabled) openRouterParams.reasoning = { effort: reasoningEffort };
|
|
932
|
+
else if (offReasoningEffort !== null) openRouterParams.reasoning = { effort: offReasoningEffort ?? "none" };
|
|
504
933
|
} else if (compat.thinkingFormat === "together" && model.reasoning) {
|
|
505
934
|
const togetherParams = params;
|
|
506
|
-
togetherParams.reasoning = { enabled:
|
|
507
|
-
if (
|
|
508
|
-
} else if (
|
|
509
|
-
else if (
|
|
510
|
-
|
|
511
|
-
if (typeof offValue === "string") params.reasoning_effort = offValue;
|
|
935
|
+
togetherParams.reasoning = { enabled: reasoningEnabled };
|
|
936
|
+
if (reasoningEnabled && compat.supportsReasoningEffort) togetherParams.reasoning_effort = reasoningEffort;
|
|
937
|
+
} else if (reasoningEnabled && model.reasoning && compat.supportsReasoningEffort) params.reasoning_effort = reasoningEffort;
|
|
938
|
+
else if (model.reasoning && compat.supportsReasoningEffort) {
|
|
939
|
+
if (typeof offReasoningEffort === "string") params.reasoning_effort = offReasoningEffort;
|
|
512
940
|
}
|
|
513
|
-
if (
|
|
941
|
+
if (compat.openRouterRouting) params.provider = compat.openRouterRouting;
|
|
514
942
|
if (model.baseUrl.includes("ai-gateway.vercel.sh") && model.compat?.vercelGatewayRouting) {
|
|
515
943
|
const routing = model.compat.vercelGatewayRouting;
|
|
516
944
|
if (routing.only || routing.order) {
|
|
@@ -791,78 +1219,5 @@ function parseChunkUsage(rawUsage, model) {
|
|
|
791
1219
|
applyProviderReportedUsageCost(usage, rawUsage.cost);
|
|
792
1220
|
return usage;
|
|
793
1221
|
}
|
|
794
|
-
/**
|
|
795
|
-
* Detect compatibility settings from provider and baseUrl for known providers.
|
|
796
|
-
* Provider takes precedence over URL-based detection since it's explicitly configured.
|
|
797
|
-
* Returns a fully resolved OpenAICompletionsCompat object with all fields set.
|
|
798
|
-
*/
|
|
799
|
-
function detectCompat(model) {
|
|
800
|
-
const provider = model.provider;
|
|
801
|
-
const baseUrl = model.baseUrl;
|
|
802
|
-
const isZai = provider === "zai" || baseUrl.includes("api.z.ai");
|
|
803
|
-
const isTogether = provider === "together" || baseUrl.includes("api.together.ai") || baseUrl.includes("api.together.xyz");
|
|
804
|
-
const isMoonshot = provider === "moonshotai" || provider === "moonshotai-cn" || baseUrl.includes("api.moonshot.");
|
|
805
|
-
const isCloudflareWorkersAI = provider === "cloudflare-workers-ai" || baseUrl.includes("api.cloudflare.com");
|
|
806
|
-
const isCloudflareAiGateway = provider === "cloudflare-ai-gateway" || baseUrl.includes("gateway.ai.cloudflare.com");
|
|
807
|
-
const isOpenRouter = provider === "openrouter" || baseUrl.includes("openrouter.ai");
|
|
808
|
-
const isNonStandard = provider === "cerebras" || baseUrl.includes("cerebras.ai") || provider === "xai" || baseUrl.includes("api.x.ai") || isTogether || baseUrl.includes("chutes.ai") || baseUrl.includes("deepseek.com") || isZai || isMoonshot || provider === "opencode" || baseUrl.includes("opencode.ai") || isCloudflareWorkersAI || isCloudflareAiGateway;
|
|
809
|
-
const useMaxTokens = baseUrl.includes("chutes.ai") || isMoonshot || isCloudflareAiGateway || isTogether || isZai;
|
|
810
|
-
const isGrok = provider === "xai" || baseUrl.includes("api.x.ai");
|
|
811
|
-
const isDeepSeek = provider === "deepseek" || baseUrl.includes("deepseek.com");
|
|
812
|
-
const isXiaomi = provider === "xiaomi" || baseUrl.includes("xiaomimimo.com");
|
|
813
|
-
const supportsOpenRouterDeveloperRole = isOpenRouter && (model.id.startsWith("anthropic/") || model.id.startsWith("openai/"));
|
|
814
|
-
const usesOpenRouterSessionAffinity = isOpenRouter || model.compat?.thinkingFormat === "openrouter" || model.compat?.openRouterRouting !== void 0;
|
|
815
|
-
const cacheControlFormat = provider === "openrouter" && model.id.startsWith("anthropic/") ? "anthropic" : void 0;
|
|
816
|
-
return {
|
|
817
|
-
supportsStore: !isNonStandard,
|
|
818
|
-
supportsDeveloperRole: supportsOpenRouterDeveloperRole || !isNonStandard && !isOpenRouter,
|
|
819
|
-
supportsReasoningEffort: !isGrok && !isZai && !isMoonshot && !isTogether && !isCloudflareAiGateway,
|
|
820
|
-
supportsUsageInStreaming: true,
|
|
821
|
-
maxTokensField: useMaxTokens ? "max_tokens" : "max_completion_tokens",
|
|
822
|
-
requiresToolResultName: false,
|
|
823
|
-
requiresAssistantAfterToolResult: false,
|
|
824
|
-
requiresThinkingAsText: false,
|
|
825
|
-
requiresReasoningContentOnAssistantMessages: isDeepSeek || isXiaomi,
|
|
826
|
-
thinkingFormat: isDeepSeek ? "deepseek" : isXiaomi ? "deepseek" : isZai ? "zai" : isTogether ? "together" : isOpenRouter ? "openrouter" : "openai",
|
|
827
|
-
openRouterRouting: {},
|
|
828
|
-
vercelGatewayRouting: {},
|
|
829
|
-
zaiToolStream: false,
|
|
830
|
-
supportsStrictMode: !isMoonshot && !isTogether && !isCloudflareAiGateway,
|
|
831
|
-
cacheControlFormat,
|
|
832
|
-
sendSessionAffinityHeaders: false,
|
|
833
|
-
sessionAffinityFormat: usesOpenRouterSessionAffinity ? "openrouter" : "openai",
|
|
834
|
-
supportsPromptCacheKey: false,
|
|
835
|
-
supportsLongCacheRetention: !(isTogether || isCloudflareWorkersAI || isCloudflareAiGateway)
|
|
836
|
-
};
|
|
837
|
-
}
|
|
838
|
-
/**
|
|
839
|
-
* Get resolved compatibility settings for a model.
|
|
840
|
-
* Uses explicit model.compat if provided, otherwise auto-detects from provider/URL.
|
|
841
|
-
*/
|
|
842
|
-
function getCompat(model) {
|
|
843
|
-
const detected = detectCompat(model);
|
|
844
|
-
if (!model.compat) return detected;
|
|
845
|
-
return {
|
|
846
|
-
supportsStore: model.compat.supportsStore ?? detected.supportsStore,
|
|
847
|
-
supportsDeveloperRole: model.compat.supportsDeveloperRole ?? detected.supportsDeveloperRole,
|
|
848
|
-
supportsReasoningEffort: model.compat.supportsReasoningEffort ?? detected.supportsReasoningEffort,
|
|
849
|
-
supportsUsageInStreaming: model.compat.supportsUsageInStreaming ?? detected.supportsUsageInStreaming,
|
|
850
|
-
maxTokensField: model.compat.maxTokensField ?? detected.maxTokensField,
|
|
851
|
-
requiresToolResultName: model.compat.requiresToolResultName ?? detected.requiresToolResultName,
|
|
852
|
-
requiresAssistantAfterToolResult: model.compat.requiresAssistantAfterToolResult ?? detected.requiresAssistantAfterToolResult,
|
|
853
|
-
requiresThinkingAsText: model.compat.requiresThinkingAsText ?? detected.requiresThinkingAsText,
|
|
854
|
-
requiresReasoningContentOnAssistantMessages: model.compat.requiresReasoningContentOnAssistantMessages ?? detected.requiresReasoningContentOnAssistantMessages,
|
|
855
|
-
thinkingFormat: model.compat.thinkingFormat ?? detected.thinkingFormat,
|
|
856
|
-
openRouterRouting: model.compat.openRouterRouting ?? {},
|
|
857
|
-
vercelGatewayRouting: model.compat.vercelGatewayRouting ?? detected.vercelGatewayRouting,
|
|
858
|
-
zaiToolStream: model.compat.zaiToolStream ?? detected.zaiToolStream,
|
|
859
|
-
supportsStrictMode: model.compat.supportsStrictMode ?? detected.supportsStrictMode,
|
|
860
|
-
cacheControlFormat: model.compat.cacheControlFormat ?? detected.cacheControlFormat,
|
|
861
|
-
sendSessionAffinityHeaders: model.compat.sendSessionAffinityHeaders ?? detected.sendSessionAffinityHeaders,
|
|
862
|
-
sessionAffinityFormat: detected.sessionAffinityFormat,
|
|
863
|
-
supportsPromptCacheKey: model.compat.supportsPromptCacheKey ?? detected.supportsPromptCacheKey,
|
|
864
|
-
supportsLongCacheRetention: model.compat.supportsLongCacheRetention ?? detected.supportsLongCacheRetention
|
|
865
|
-
};
|
|
866
|
-
}
|
|
867
1222
|
//#endregion
|
|
868
|
-
export {
|
|
1223
|
+
export { transformTransportMessages as C, resolveProviderRequestPolicyConfig as S, buildGuardedModelFetch as _, projectOpenAITools as a, resolveProviderEndpoint as b, mapOpenAIStopReason as c, resolveOpenAICompletionsCompat as d, resolveOpenAICompletionsResponseFormat as f, tagPendingCommentaryText as g, rememberPendingCommentaryTags as h, streamSimpleOpenAICompletions as i, resolveOpenAIReasoningEffortMap as l, clearPendingCommentaryText as m, openai_completions_exports as n, reconcileOpenAICompletionsToolChoice as o, shouldOmitOllamaCompatResponseFormat as p, streamOpenAICompletions as r, reconcileOpenAIResponsesToolChoice as s, convertMessages as t, detectOpenAICompletionsCompat as u, resolveModelRequestTimeoutMs as v, resolveProviderRequestCapabilities as x, resolveOpenAIStrictToolSetting as y };
|