@openclaw/ai 2026.7.2-beta.7 → 2026.8.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{anthropic-CH4UUnZr.mjs → anthropic-B6dLpq5L.mjs} +55 -203
- package/dist/{src-QkygScBs.mjs → anthropic-JsNA5KCu.mjs} +0 -1
- package/dist/anthropic-compaction-replay-8lJNKXOE.mjs +840 -0
- package/dist/anthropic-payload-policy-CiEuQS72.d.mts +49 -0
- package/dist/{api-registry-DlMgPR39.d.mts → api-registry-k3zTz0cV.d.mts} +1 -1
- package/dist/{azure-openai-responses-CImcwB83.mjs → azure-openai-responses-mxIOtUnn.mjs} +23 -29
- package/dist/diagnostics.d.mts +24 -1
- package/dist/diagnostics.mjs +2 -1
- package/dist/{event-stream-YjaPW20U.d.mts → event-stream-BP6AWT8j.d.mts} +4 -1
- package/dist/{event-stream-D8n2uFee.mjs → event-stream-uSMZJ3FA.mjs} +26 -5
- package/dist/event-stream.d.mts +1 -1
- package/dist/event-stream.mjs +1 -1
- package/dist/{google-CtSg0iTS.mjs → google-C7h2QzDX.mjs} +5 -5
- package/dist/{google-shared-DNBz5rcD.mjs → google-shared-B0Qr9OR7.mjs} +146 -89
- package/dist/google-thinking-level-C-V3tecN.mjs +9 -0
- package/dist/{google-vertex-31f1uS9L.mjs → google-vertex-Bhc3TjDl.mjs} +11 -7
- package/dist/{llm-request-activity-BjtkplhG.mjs → headers-DdOQtGuU.mjs} +9 -1
- package/dist/host-DTqNc7ad.mjs +466 -0
- package/dist/{host-B9GUmcra.d.mts → host-vWgMMhiJ.d.mts} +9 -4
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +7 -5
- package/dist/internal/anthropic.d.mts +29 -5
- package/dist/internal/anthropic.mjs +5 -5
- package/dist/internal/openai-responses-payload-policy.d.mts +3 -0
- package/dist/internal/openai-responses-payload-policy.mjs +3 -0
- package/dist/internal/openai.d.mts +6 -6
- package/dist/internal/openai.mjs +8 -7
- package/dist/internal/runtime.d.mts +17 -5
- package/dist/internal/runtime.mjs +85 -73
- package/dist/internal/shared.d.mts +1 -6
- package/dist/internal/shared.mjs +3 -5
- package/dist/{json-parse-BvXNt1-7.mjs → json-parse-CDnesDM_.mjs} +4 -6
- package/dist/{mistral-CWmpvWYh.mjs → mistral-CEWoQI_g.mjs} +45 -48
- package/dist/number-coercion-H9qHik3g.mjs +71 -0
- package/dist/openai-chatgpt-jwt-KWcgd0d_.mjs +19 -0
- package/dist/{openai-chatgpt-responses-B84Ibtrd.mjs → openai-chatgpt-responses-CrPmqERt.mjs} +284 -240
- package/dist/{openai-completions-DsOxhOD1.mjs → openai-completions-BPnt4Sml.mjs} +65 -99
- package/dist/{openai-completions-compat-DBWjXoMZ.d.mts → openai-completions-compat-Dt3dcawL.d.mts} +2 -2
- package/dist/{openai-responses-BT7A3sLu.mjs → openai-responses-DhIKtOup.mjs} +18 -41
- package/dist/openai-responses-contracts-CyfIkQi5.mjs +253 -0
- package/dist/openai-responses-contracts-XpZJxrRG.d.mts +68 -0
- package/dist/openai-responses-payload-policy-BDxV-W0c.mjs +206 -0
- package/dist/openai-responses-payload-policy-BSs371VM.d.mts +40 -0
- package/dist/openai-responses-prompt-observer-internal-DgNTYnRY.mjs +46 -0
- package/dist/{openai-responses-stream-internal-Cw5txaGW.mjs → openai-responses-shared-DXIt3iY5.mjs} +1406 -940
- package/dist/{openai-reasoning-compat-YgeLncHw.mjs → openai-stop-reason-BkFkqqK0.mjs} +204 -37
- package/dist/openai-tool-projection-CY04OcvQ.mjs +338 -0
- package/dist/provider-error-BUwEnjXq.mjs +429 -0
- package/dist/provider-error-CzNw4BWX.d.mts +12 -0
- package/dist/{provider-options-D8bB3z9b.d.mts → provider-options-B96RdNpH.d.mts} +9 -3
- package/dist/provider-transcript-transform-ePx-Bbfr.mjs +155 -0
- package/dist/provider-types.d.mts +31 -0
- package/dist/provider-types.mjs +8 -0
- package/dist/providers.d.mts +1 -1
- package/dist/providers.mjs +17 -19
- package/dist/{reasoning-tag-text-partitioner-CGDyLWUR.mjs → reasoning-tag-text-partitioner-rnPwX2pg.mjs} +14 -8
- package/dist/record-coerce-DdXsgUd_.mjs +23 -0
- package/dist/sanitize-unicode-BYqrYtC_.mjs +90 -0
- package/dist/session-resources-CkR4WWy1.mjs +21 -0
- package/dist/simple-options-D58D5Kvw.mjs +117 -0
- package/dist/src-D2H6yKkH.mjs +2 -0
- package/dist/{stream-first-event-timeout-BBys9hSb.mjs → stream-first-event-timeout-MK28puvq.mjs} +2 -2
- package/dist/string-coerce-fsri9iCu.mjs +34 -0
- package/dist/{tool-schema-json-projection-BwNu3nDi.mjs → tool-schema-json-projection-q5d7QX5c.mjs} +32 -7
- package/dist/transport-utils-DJqkxbhC.mjs +138 -0
- package/dist/transports.d.mts +166 -241
- package/dist/transports.mjs +1979 -1825
- package/dist/types-BDdaOVi2.mjs +6 -0
- package/dist/{types-bzp5k29J.d.mts → types-BHNrPS1l.d.mts} +23 -1
- package/dist/types.d.mts +4 -4
- package/dist/types.mjs +6 -4
- package/dist/utf16-slice-CvGodqok.mjs +29 -0
- package/dist/{validation-DAa_yFOM.mjs → validation-B61OhAio.mjs} +6 -6
- package/dist/{validation-B-j7cOYp.d.mts → validation-DT9SrFn3.d.mts} +1 -1
- package/dist/validation.d.mts +1 -1
- package/dist/validation.mjs +1 -1
- package/package.json +15 -1
- package/dist/anthropic-usage-DWU-x8MI.mjs +0 -459
- package/dist/error-coercion-DgxlWC0n.mjs +0 -15
- package/dist/headers-B_e4-1J0.mjs +0 -9
- package/dist/host-Dog2WQiR.mjs +0 -369
- package/dist/number-coercion-DvG7SNMg.mjs +0 -129
- package/dist/openai-chatgpt-jwt-DhAAzLkj.mjs +0 -39
- package/dist/openai-responses-shared-pXl6Wd8S.mjs +0 -392
- package/dist/openai-tool-projection-OhX64DoP.mjs +0 -215
- package/dist/provider-error-CAEvRjry.mjs +0 -47
- package/dist/sanitize-unicode-DT5o51ur.mjs +0 -26
- package/dist/simple-options-9lhRrN73.mjs +0 -50
- 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
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as sanitizeSurrogates } from "./sanitize-unicode-
|
|
3
|
-
import { a as
|
|
4
|
-
import {
|
|
1
|
+
import { n as normalizeLowercaseStringOrEmpty } from "./string-coerce-fsri9iCu.mjs";
|
|
2
|
+
import { t as sanitizeSurrogates } from "./sanitize-unicode-BYqrYtC_.mjs";
|
|
3
|
+
import { a as describeToolResultMediaPlaceholder, l as isImageWithMediaPayload, s as extractToolResultText } from "./host-DTqNc7ad.mjs";
|
|
4
|
+
import { a as isRecord, r as asOptionalObjectRecord } from "./record-coerce-DdXsgUd_.mjs";
|
|
5
|
+
import { t as truncateUtf16Safe } from "./utf16-slice-CvGodqok.mjs";
|
|
6
|
+
import { l as stripSystemPromptCacheBoundary } from "./simple-options-D58D5Kvw.mjs";
|
|
7
|
+
import { o as resolveProviderRequestCapabilities } from "./tool-schema-json-projection-q5d7QX5c.mjs";
|
|
8
|
+
import { t as transformProviderMessages } from "./provider-transcript-transform-ePx-Bbfr.mjs";
|
|
9
|
+
import { l as measureUtf8AppendBytes } from "./openai-tool-projection-CY04OcvQ.mjs";
|
|
10
|
+
import { randomUUID } from "node:crypto";
|
|
5
11
|
//#region packages/ai/src/utils/assistant-text-phase.ts
|
|
6
12
|
function isAssistantTextPhaseBlock(block) {
|
|
7
13
|
if (!block || typeof block !== "object") return false;
|
|
@@ -174,7 +180,161 @@ function resolveOpenAICompletionsCompat(model, resolveCapabilities = resolveProv
|
|
|
174
180
|
requiresNonEmptyUserOrAssistantMessage: defaults.requiresNonEmptyUserOrAssistantMessage
|
|
175
181
|
};
|
|
176
182
|
}
|
|
177
|
-
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region packages/ai/src/providers/openai-completions-tool-calls.ts
|
|
185
|
+
const MAX_BUFFERED_TOOL_CALL_ARGUMENT_BYTES = 256e3;
|
|
186
|
+
const MAX_BUFFERED_LEGACY_FOLLOWING_DELTA_BYTES = 256e3;
|
|
187
|
+
const MAX_BUFFERED_LEGACY_FOLLOWING_DELTAS = 1024;
|
|
188
|
+
/** Normalize the SDK's legacy single-function lane into its modern tool-call shape. */
|
|
189
|
+
function createOpenAICompletionsToolCallDeltaNormalizer() {
|
|
190
|
+
let sawModernToolCall = false;
|
|
191
|
+
let pendingLegacyArgumentBytes = 0;
|
|
192
|
+
let pendingFollowingDeltaBytes = 0;
|
|
193
|
+
let pendingLegacyToolCall;
|
|
194
|
+
const modernArguments = /* @__PURE__ */ new Map();
|
|
195
|
+
const pendingFollowingDeltas = [];
|
|
196
|
+
const takePendingFollowingDeltas = () => {
|
|
197
|
+
pendingFollowingDeltaBytes = 0;
|
|
198
|
+
return pendingFollowingDeltas.splice(0).map((delta) => ({
|
|
199
|
+
delta,
|
|
200
|
+
toolCalls: []
|
|
201
|
+
}));
|
|
202
|
+
};
|
|
203
|
+
const bufferFollowingDelta = (delta) => {
|
|
204
|
+
const nextDeltaBytes = Buffer.byteLength(JSON.stringify(delta), "utf8");
|
|
205
|
+
if (pendingFollowingDeltaBytes + nextDeltaBytes > MAX_BUFFERED_LEGACY_FOLLOWING_DELTA_BYTES || pendingFollowingDeltas.length >= MAX_BUFFERED_LEGACY_FOLLOWING_DELTAS) throw new Error("Exceeded legacy tool-call content buffer limit");
|
|
206
|
+
pendingFollowingDeltaBytes += nextDeltaBytes;
|
|
207
|
+
pendingFollowingDeltas.push(delta);
|
|
208
|
+
};
|
|
209
|
+
const withoutToolCalls = (delta) => {
|
|
210
|
+
const ordinaryDelta = { ...delta };
|
|
211
|
+
delete ordinaryDelta.function_call;
|
|
212
|
+
delete ordinaryDelta.tool_calls;
|
|
213
|
+
return ordinaryDelta;
|
|
214
|
+
};
|
|
215
|
+
const hasObservableContent = (value) => {
|
|
216
|
+
if (typeof value === "string") return value.length > 0;
|
|
217
|
+
if (Array.isArray(value)) return value.some(hasObservableContent);
|
|
218
|
+
if (isRecord(value)) return Object.entries(value).some(([field, nestedValue]) => field !== "type" && field !== "id" && field !== "index" && hasObservableContent(nestedValue));
|
|
219
|
+
return false;
|
|
220
|
+
};
|
|
221
|
+
const hasOrdinaryContent = (delta) => Object.entries(delta).some(([field, value]) => field !== "role" && hasObservableContent(value));
|
|
222
|
+
return (delta, finishReason) => {
|
|
223
|
+
const ordinaryDelta = withoutToolCalls(delta);
|
|
224
|
+
if (delta.tool_calls && delta.tool_calls.length > 0) {
|
|
225
|
+
for (const toolCall of delta.tool_calls) {
|
|
226
|
+
const index = typeof toolCall.index === "number" ? toolCall.index : void 0;
|
|
227
|
+
const state = (index === void 0 ? void 0 : modernArguments.get(index)) ?? (toolCall.id ? modernArguments.get(toolCall.id) : void 0) ?? {
|
|
228
|
+
bytes: 0,
|
|
229
|
+
pendingHighSurrogate: false
|
|
230
|
+
};
|
|
231
|
+
if (index !== void 0) modernArguments.set(index, state);
|
|
232
|
+
if (toolCall.id) modernArguments.set(toolCall.id, state);
|
|
233
|
+
const argumentDelta = toolCall.function?.arguments ?? "";
|
|
234
|
+
const append = measureUtf8AppendBytes(state.pendingHighSurrogate, argumentDelta);
|
|
235
|
+
state.bytes += append.bytes;
|
|
236
|
+
if (state.bytes > MAX_BUFFERED_TOOL_CALL_ARGUMENT_BYTES) throw new Error("Exceeded tool-call argument buffer limit");
|
|
237
|
+
state.pendingHighSurrogate = append.endsWithHighSurrogate;
|
|
238
|
+
}
|
|
239
|
+
const precedingDeltas = takePendingFollowingDeltas();
|
|
240
|
+
sawModernToolCall = true;
|
|
241
|
+
pendingLegacyArgumentBytes = 0;
|
|
242
|
+
pendingLegacyToolCall = void 0;
|
|
243
|
+
return [...precedingDeltas, {
|
|
244
|
+
delta: ordinaryDelta,
|
|
245
|
+
toolCalls: delta.tool_calls
|
|
246
|
+
}];
|
|
247
|
+
}
|
|
248
|
+
const functionCall = delta.function_call;
|
|
249
|
+
if (sawModernToolCall) return [{
|
|
250
|
+
delta: ordinaryDelta,
|
|
251
|
+
toolCalls: []
|
|
252
|
+
}];
|
|
253
|
+
const hadPendingLegacyCall = pendingLegacyToolCall !== void 0;
|
|
254
|
+
const leadingDeltas = [];
|
|
255
|
+
if (hasOrdinaryContent(ordinaryDelta)) if (hadPendingLegacyCall) bufferFollowingDelta(ordinaryDelta);
|
|
256
|
+
else leadingDeltas.push({
|
|
257
|
+
delta: ordinaryDelta,
|
|
258
|
+
toolCalls: []
|
|
259
|
+
});
|
|
260
|
+
if (functionCall && (functionCall.name || functionCall.arguments)) {
|
|
261
|
+
const nextFunctionName = pendingLegacyToolCall?.function?.name ? void 0 : functionCall.name;
|
|
262
|
+
const nextArgumentBytes = Buffer.byteLength(functionCall.arguments ?? "", "utf8") + Buffer.byteLength(nextFunctionName ?? "", "utf8");
|
|
263
|
+
if (pendingLegacyArgumentBytes + nextArgumentBytes > MAX_BUFFERED_TOOL_CALL_ARGUMENT_BYTES) throw new Error("Exceeded tool-call argument buffer limit");
|
|
264
|
+
pendingLegacyArgumentBytes += nextArgumentBytes;
|
|
265
|
+
pendingLegacyToolCall ??= {
|
|
266
|
+
index: 0,
|
|
267
|
+
id: `call_${randomUUID().replaceAll("-", "").slice(0, 24)}`,
|
|
268
|
+
type: "function",
|
|
269
|
+
function: {}
|
|
270
|
+
};
|
|
271
|
+
const pendingFunction = pendingLegacyToolCall.function ??= {};
|
|
272
|
+
if (nextFunctionName) pendingFunction.name = nextFunctionName;
|
|
273
|
+
if (functionCall.arguments) pendingFunction.arguments = (pendingFunction.arguments ?? "") + functionCall.arguments;
|
|
274
|
+
}
|
|
275
|
+
if (!pendingLegacyToolCall) return leadingDeltas.length > 0 ? leadingDeltas : [{
|
|
276
|
+
delta: ordinaryDelta,
|
|
277
|
+
toolCalls: []
|
|
278
|
+
}];
|
|
279
|
+
if (finishReason === "function_call") {
|
|
280
|
+
const confirmedLegacyToolCall = pendingLegacyToolCall;
|
|
281
|
+
pendingLegacyToolCall = void 0;
|
|
282
|
+
pendingLegacyArgumentBytes = 0;
|
|
283
|
+
return [
|
|
284
|
+
...leadingDeltas,
|
|
285
|
+
{
|
|
286
|
+
delta: {},
|
|
287
|
+
toolCalls: [confirmedLegacyToolCall]
|
|
288
|
+
},
|
|
289
|
+
...takePendingFollowingDeltas()
|
|
290
|
+
];
|
|
291
|
+
}
|
|
292
|
+
if (finishReason) {
|
|
293
|
+
pendingLegacyArgumentBytes = 0;
|
|
294
|
+
pendingLegacyToolCall = void 0;
|
|
295
|
+
return [...leadingDeltas, ...takePendingFollowingDeltas()];
|
|
296
|
+
}
|
|
297
|
+
return leadingDeltas;
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
/** Publish only executable calls; streaming scratch state never belongs in replay. */
|
|
301
|
+
function finalizeOpenAICompletionsToolCalls(output, options = {}) {
|
|
302
|
+
const isToolCall = (block) => block.type === "toolCall";
|
|
303
|
+
const hasToolCalls = output.content.some(isToolCall);
|
|
304
|
+
if (output.stopReason === "toolUse" && !hasToolCalls) output.stopReason = "stop";
|
|
305
|
+
if (output.stopReason === "stop" && hasToolCalls && options.allowSilentToolCallPromotion !== false && !output.content.some((block) => {
|
|
306
|
+
const candidate = block;
|
|
307
|
+
return candidate.type === "text" && typeof candidate.text === "string" && candidate.text.trim().length > 0;
|
|
308
|
+
})) output.stopReason = "toolUse";
|
|
309
|
+
if (output.stopReason !== "toolUse") {
|
|
310
|
+
if (hasToolCalls) output.content = output.content.filter((block) => !isToolCall(block));
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
for (const block of output.content) {
|
|
314
|
+
if (!isToolCall(block)) continue;
|
|
315
|
+
const toolCall = block;
|
|
316
|
+
let completeArguments;
|
|
317
|
+
try {
|
|
318
|
+
completeArguments = typeof toolCall.partialArgs === "string" && toolCall.partialArgs.trim().length > 0 ? JSON.parse(toolCall.partialArgs) : void 0;
|
|
319
|
+
} catch {
|
|
320
|
+
completeArguments = void 0;
|
|
321
|
+
}
|
|
322
|
+
if (typeof toolCall.name !== "string" || toolCall.name.trim().length === 0 || !isRecord(completeArguments)) {
|
|
323
|
+
output.stopReason = "error";
|
|
324
|
+
output.errorMessage = "Provider returned an incomplete or malformed tool call";
|
|
325
|
+
output.content = output.content.filter((candidate) => !isToolCall(candidate));
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
toolCall.arguments = completeArguments;
|
|
329
|
+
}
|
|
330
|
+
for (let contentIndex = 0; contentIndex < output.content.length; contentIndex += 1) {
|
|
331
|
+
const block = output.content[contentIndex];
|
|
332
|
+
if (!block || !isToolCall(block)) continue;
|
|
333
|
+
delete block.partialArgs;
|
|
334
|
+
delete block.streamIndex;
|
|
335
|
+
options.onConfirmedToolCall?.(block, contentIndex);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
178
338
|
//#endregion
|
|
179
339
|
//#region packages/ai/src/openai-completions-messages.ts
|
|
180
340
|
const EMPTY_TOOL_RESULT_TEXT = "(no output)";
|
|
@@ -191,15 +351,19 @@ function sanitizeToolResultText(text, fallback) {
|
|
|
191
351
|
const sanitized = sanitizeSurrogates(text);
|
|
192
352
|
return sanitized.trim().length > 0 ? sanitized : fallback;
|
|
193
353
|
}
|
|
354
|
+
/** Whether replayed messages require a tools marker for proxy compatibility. */
|
|
355
|
+
function hasToolCallHistory(messages) {
|
|
356
|
+
return messages.some((message) => message.role === "toolResult" || message.role === "assistant" && Array.isArray(message.content) && message.content.some((block) => block.type === "toolCall"));
|
|
357
|
+
}
|
|
194
358
|
/** Convert a normalized transcript to OpenAI Chat Completions messages. */
|
|
195
359
|
function convertMessages(model, context, compat, options = {}) {
|
|
196
360
|
const params = [];
|
|
197
361
|
const normalizeToolCallId = (id) => {
|
|
198
362
|
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
|
|
363
|
+
if (model.provider === "openai") return id.length > 40 ? truncateUtf16Safe(id, 40) : id;
|
|
200
364
|
return id;
|
|
201
365
|
};
|
|
202
|
-
const transformedMessages =
|
|
366
|
+
const transformedMessages = transformProviderMessages(context.messages, model, (id) => normalizeToolCallId(id));
|
|
203
367
|
if (context.systemPrompt) {
|
|
204
368
|
const role = model.reasoning && compat.supportsDeveloperRole ? "developer" : "system";
|
|
205
369
|
const systemPrompt = options.preserveSystemPromptCacheBoundary ? context.systemPrompt : stripSystemPromptCacheBoundary(context.systemPrompt);
|
|
@@ -231,6 +395,10 @@ function convertMessages(model, context, compat, options = {}) {
|
|
|
231
395
|
type: "text",
|
|
232
396
|
text: sanitizeSurrogates(item.text)
|
|
233
397
|
};
|
|
398
|
+
if (item.type === "video") return {
|
|
399
|
+
type: "video_url",
|
|
400
|
+
video_url: { url: `data:${item.mimeType};base64,${item.data}` }
|
|
401
|
+
};
|
|
234
402
|
return {
|
|
235
403
|
type: "image_url",
|
|
236
404
|
image_url: { url: `data:${item.mimeType};base64,${item.data}` }
|
|
@@ -253,7 +421,7 @@ function convertMessages(model, context, compat, options = {}) {
|
|
|
253
421
|
type: "text",
|
|
254
422
|
text: sanitizeSurrogates(block.text)
|
|
255
423
|
}));
|
|
256
|
-
const assistantText = assistantTextParts.map((part) => part.text).join("");
|
|
424
|
+
const assistantText = assistantTextParts.map((part) => part.text).join("\n");
|
|
257
425
|
const nonEmptyThinkingBlocks = msg.content.filter(isThinkingContentBlock).filter((block) => block.thinking.trim().length > 0);
|
|
258
426
|
if (nonEmptyThinkingBlocks.length > 0) if (compat.requiresThinkingAsText) assistantMsg.content = [{
|
|
259
427
|
type: "text",
|
|
@@ -338,6 +506,33 @@ function convertMessages(model, context, compat, options = {}) {
|
|
|
338
506
|
return params;
|
|
339
507
|
}
|
|
340
508
|
//#endregion
|
|
509
|
+
//#region packages/ai/src/transports/openai-reasoning-compat.ts
|
|
510
|
+
/**
|
|
511
|
+
* OpenAI reasoning-effort compatibility helpers.
|
|
512
|
+
*
|
|
513
|
+
* Keeps provider metadata and built-in model exceptions on one path before request payloads are built.
|
|
514
|
+
*/
|
|
515
|
+
const OPENAI_MEDIUM_ONLY_REASONING_MODEL_IDS = /* @__PURE__ */ new Set(["gpt-5.1-codex-mini"]);
|
|
516
|
+
function readCompatReasoningEffortMap(compat) {
|
|
517
|
+
const rawMap = asOptionalObjectRecord(asOptionalObjectRecord(compat)?.reasoningEffortMap);
|
|
518
|
+
if (!rawMap) return {};
|
|
519
|
+
return Object.fromEntries(Object.entries(rawMap).filter((entry) => typeof entry[0] === "string" && typeof entry[1] === "string"));
|
|
520
|
+
}
|
|
521
|
+
/** Resolves the reasoning effort remap for an OpenAI-compatible model. */
|
|
522
|
+
function resolveOpenAIReasoningEffortMap(model, fallbackMap = {}) {
|
|
523
|
+
const provider = normalizeLowercaseStringOrEmpty(model.provider ?? "");
|
|
524
|
+
const id = normalizeLowercaseStringOrEmpty(model.id ?? "");
|
|
525
|
+
const builtinMap = provider === "openai" && OPENAI_MEDIUM_ONLY_REASONING_MODEL_IDS.has(id) ? {
|
|
526
|
+
minimal: "medium",
|
|
527
|
+
low: "medium"
|
|
528
|
+
} : {};
|
|
529
|
+
return {
|
|
530
|
+
...fallbackMap,
|
|
531
|
+
...builtinMap,
|
|
532
|
+
...readCompatReasoningEffortMap(model.compat)
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
//#endregion
|
|
341
536
|
//#region packages/ai/src/providers/openai-stop-reason.ts
|
|
342
537
|
function mapOpenAIStopReason(reason, options) {
|
|
343
538
|
if (reason === null) return { stopReason: "stop" };
|
|
@@ -365,32 +560,4 @@ function mapOpenAIStopReason(reason, options) {
|
|
|
365
560
|
};
|
|
366
561
|
}
|
|
367
562
|
//#endregion
|
|
368
|
-
|
|
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 };
|
|
563
|
+
export { createOpenAICompletionsToolCallDeltaNormalizer as a, resolveOpenAICompletionsCompat as c, clearPendingCommentaryText as d, rememberPendingCommentaryTags as f, hasToolCallHistory as i, resolveOpenAICompletionsResponseFormat as l, resolveOpenAIReasoningEffortMap as n, finalizeOpenAICompletionsToolCalls as o, tagPendingCommentaryText as p, convertMessages as r, detectOpenAICompletionsCompat as s, mapOpenAIStopReason as t, shouldOmitOllamaCompatResponseFormat as u };
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { n as applyProviderReportedUsageCost, r as calculateCost } from "./sanitize-unicode-BYqrYtC_.mjs";
|
|
2
|
+
import { n as getAiTransportHost } from "./host-DTqNc7ad.mjs";
|
|
3
|
+
import { a as isRecord } from "./record-coerce-DdXsgUd_.mjs";
|
|
4
|
+
import { n as clampOpenAIPromptCacheKey } from "./openai-prompt-cache-mZTCdRPo.mjs";
|
|
5
|
+
import { t as projectRuntimeToolInputSchema } from "./tool-schema-json-projection-q5d7QX5c.mjs";
|
|
6
|
+
import { t as headersToRecord } from "./headers-DdOQtGuU.mjs";
|
|
7
|
+
import { f as transportAbortError } from "./provider-transcript-transform-ePx-Bbfr.mjs";
|
|
8
|
+
//#region packages/ai/src/transports/openai-transport-shared.ts
|
|
9
|
+
/** Shared options, usage shape, cache identity, ordering, and stream scheduling for OpenAI APIs. */
|
|
10
|
+
const MODEL_STREAM_COOPERATIVE_YIELD_INTERVAL_MS = 12;
|
|
11
|
+
const MODEL_STREAM_COOPERATIVE_YIELD_MAX_EVENTS = 64;
|
|
12
|
+
const GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP = "skip_thought_signature_validator";
|
|
13
|
+
const log = {
|
|
14
|
+
debug(message, data) {
|
|
15
|
+
getAiTransportHost().logDebug("openai-transport", () => ({
|
|
16
|
+
message,
|
|
17
|
+
data
|
|
18
|
+
}));
|
|
19
|
+
},
|
|
20
|
+
info(message, data) {
|
|
21
|
+
getAiTransportHost().logInfo("openai-transport", message, data);
|
|
22
|
+
},
|
|
23
|
+
warn(message, data) {
|
|
24
|
+
getAiTransportHost().logWarn("openai-transport", message, data);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
function parseOpenAICompletionsUsage(rawUsage, model, options) {
|
|
28
|
+
const cacheRead = rawUsage.prompt_tokens_details?.cached_tokens ?? rawUsage.prompt_cache_hit_tokens ?? 0;
|
|
29
|
+
const cacheWrite = rawUsage.prompt_tokens_details?.cache_write_tokens || 0;
|
|
30
|
+
const input = Math.max(0, (rawUsage.prompt_tokens || 0) - cacheRead - cacheWrite);
|
|
31
|
+
const output = rawUsage.completion_tokens || 0;
|
|
32
|
+
const reasoningTokens = rawUsage.completion_tokens_details?.reasoning_tokens;
|
|
33
|
+
const usage = {
|
|
34
|
+
input,
|
|
35
|
+
output,
|
|
36
|
+
cacheRead,
|
|
37
|
+
cacheWrite,
|
|
38
|
+
...options?.includeReasoningTokens !== false && typeof reasoningTokens === "number" && Number.isFinite(reasoningTokens) ? { reasoningTokens } : {},
|
|
39
|
+
totalTokens: input + output + cacheRead + cacheWrite,
|
|
40
|
+
cost: {
|
|
41
|
+
input: 0,
|
|
42
|
+
output: 0,
|
|
43
|
+
cacheRead: 0,
|
|
44
|
+
cacheWrite: 0,
|
|
45
|
+
total: 0
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
calculateCost(model, usage);
|
|
49
|
+
applyProviderReportedUsageCost(usage, rawUsage.cost);
|
|
50
|
+
return usage;
|
|
51
|
+
}
|
|
52
|
+
function createOpenAIResponseHook(onResponse, response, model) {
|
|
53
|
+
return onResponse ? () => onResponse({
|
|
54
|
+
status: response.status,
|
|
55
|
+
headers: headersToRecord(response.headers)
|
|
56
|
+
}, model) : void 0;
|
|
57
|
+
}
|
|
58
|
+
function throwIfModelStreamAborted(signal) {
|
|
59
|
+
if (signal?.aborted) throw transportAbortError(signal);
|
|
60
|
+
}
|
|
61
|
+
/** Measure one UTF-8 append without double-counting a surrogate pair split across chunks. */
|
|
62
|
+
function measureUtf8AppendBytes(bufferEndsWithHighSurrogate, chunk) {
|
|
63
|
+
let bytes = Buffer.byteLength(chunk, "utf8");
|
|
64
|
+
if (!chunk) return {
|
|
65
|
+
bytes,
|
|
66
|
+
endsWithHighSurrogate: bufferEndsWithHighSurrogate
|
|
67
|
+
};
|
|
68
|
+
const nextCodeUnit = chunk.charCodeAt(0);
|
|
69
|
+
if (bufferEndsWithHighSurrogate && nextCodeUnit >= 56320 && nextCodeUnit <= 57343) bytes -= 2;
|
|
70
|
+
const finalCodeUnit = chunk.charCodeAt(chunk.length - 1);
|
|
71
|
+
return {
|
|
72
|
+
bytes,
|
|
73
|
+
endsWithHighSurrogate: finalCodeUnit >= 55296 && finalCodeUnit <= 56319
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function createModelStreamCooperativeScheduler(signal) {
|
|
77
|
+
let lastYieldedAt = Date.now();
|
|
78
|
+
let eventsSinceYield = 0;
|
|
79
|
+
return { async afterEvent() {
|
|
80
|
+
throwIfModelStreamAborted(signal);
|
|
81
|
+
eventsSinceYield += 1;
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
if (eventsSinceYield < MODEL_STREAM_COOPERATIVE_YIELD_MAX_EVENTS && now - lastYieldedAt < MODEL_STREAM_COOPERATIVE_YIELD_INTERVAL_MS) return;
|
|
84
|
+
eventsSinceYield = 0;
|
|
85
|
+
lastYieldedAt = now;
|
|
86
|
+
await new Promise((resolve) => {
|
|
87
|
+
setTimeout(resolve, 0);
|
|
88
|
+
});
|
|
89
|
+
throwIfModelStreamAborted(signal);
|
|
90
|
+
} };
|
|
91
|
+
}
|
|
92
|
+
function resolvePromptCacheKey(options, cacheRetention) {
|
|
93
|
+
if (cacheRetention === "none") return;
|
|
94
|
+
return clampOpenAIPromptCacheKey(options?.promptCacheKey ?? options?.sessionId);
|
|
95
|
+
}
|
|
96
|
+
function isOpenAICompletionsThinkingEnabled(effort) {
|
|
97
|
+
const normalized = effort.trim().toLowerCase();
|
|
98
|
+
return normalized !== "off" && normalized !== "none";
|
|
99
|
+
}
|
|
100
|
+
function readOpenAICompletionsContentDeltas(content, topLevelRefusal, mirroredThinking = []) {
|
|
101
|
+
let deltas = readOpenAICompletionsContentPartDeltas(content);
|
|
102
|
+
if (mirroredThinking.length > 0) {
|
|
103
|
+
const structuredThinking = deltas.filter((delta) => delta.kind === "thinking").map((delta) => delta.text);
|
|
104
|
+
const mirrorsCombinedThinking = structuredThinking.length > 1 && mirroredThinking.includes(structuredThinking.join(""));
|
|
105
|
+
deltas = deltas.filter((delta) => delta.kind !== "thinking" || !mirrorsCombinedThinking && !mirroredThinking.includes(delta.text));
|
|
106
|
+
}
|
|
107
|
+
if (typeof topLevelRefusal !== "string" || !topLevelRefusal) return deltas;
|
|
108
|
+
const structuredRefusals = deltas.filter((delta) => delta.kind === "text" && delta.source === "refusal").map((delta) => delta.text);
|
|
109
|
+
if (structuredRefusals.some((refusal) => refusal === topLevelRefusal) || structuredRefusals.length > 1 && structuredRefusals.join("") === topLevelRefusal) return deltas;
|
|
110
|
+
return [...deltas, {
|
|
111
|
+
kind: "text",
|
|
112
|
+
text: topLevelRefusal,
|
|
113
|
+
source: "refusal"
|
|
114
|
+
}];
|
|
115
|
+
}
|
|
116
|
+
function readOpenAICompletionsContentPartDeltas(content) {
|
|
117
|
+
if (typeof content === "string") return content ? [{
|
|
118
|
+
kind: "text",
|
|
119
|
+
text: content
|
|
120
|
+
}] : [];
|
|
121
|
+
if (Array.isArray(content)) return content.flatMap(readOpenAICompletionsContentPartDeltas);
|
|
122
|
+
if (!content || typeof content !== "object") return [];
|
|
123
|
+
const record = content;
|
|
124
|
+
const type = typeof record.type === "string" ? record.type.toLowerCase() : "";
|
|
125
|
+
const extractText = (value) => {
|
|
126
|
+
if (typeof value === "string") return value;
|
|
127
|
+
if (Array.isArray(value)) return value.map(extractText).join("");
|
|
128
|
+
if (value && typeof value === "object") {
|
|
129
|
+
const nested = value;
|
|
130
|
+
return extractText(nested.text ?? nested.content ?? nested.thinking ?? nested.refusal);
|
|
131
|
+
}
|
|
132
|
+
return "";
|
|
133
|
+
};
|
|
134
|
+
const text = extractText(record.text ?? record.content ?? record.thinking ?? record.refusal);
|
|
135
|
+
if (!text) return [];
|
|
136
|
+
if (type.includes("thinking") || type.includes("reasoning")) return [{
|
|
137
|
+
kind: "thinking",
|
|
138
|
+
text
|
|
139
|
+
}];
|
|
140
|
+
if (type === "refusal") return [{
|
|
141
|
+
kind: "text",
|
|
142
|
+
text,
|
|
143
|
+
source: "refusal"
|
|
144
|
+
}];
|
|
145
|
+
if (["text", "output_text"].includes(type) || type.endsWith(".output_text")) return [{
|
|
146
|
+
kind: "text",
|
|
147
|
+
text
|
|
148
|
+
}];
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region packages/ai/src/providers/openai-tool-projection.ts
|
|
153
|
+
function unreadableToolDiagnostic(toolIndex) {
|
|
154
|
+
return {
|
|
155
|
+
toolIndex,
|
|
156
|
+
violations: [`tool[${toolIndex}] is unreadable`]
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/** Snapshots direct/custom tool descriptors before OpenAI payload construction. */
|
|
160
|
+
function projectOpenAITools(tools) {
|
|
161
|
+
let inputToolCount;
|
|
162
|
+
try {
|
|
163
|
+
inputToolCount = tools.length;
|
|
164
|
+
} catch {
|
|
165
|
+
return {
|
|
166
|
+
inputToolCount: 0,
|
|
167
|
+
tools: [],
|
|
168
|
+
diagnostics: [unreadableToolDiagnostic(0)]
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
const projectedTools = [];
|
|
172
|
+
const diagnostics = [];
|
|
173
|
+
for (let toolIndex = 0; toolIndex < inputToolCount; toolIndex += 1) {
|
|
174
|
+
let tool;
|
|
175
|
+
try {
|
|
176
|
+
const candidate = tools[toolIndex];
|
|
177
|
+
if (!candidate) {
|
|
178
|
+
diagnostics.push(unreadableToolDiagnostic(toolIndex));
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
tool = candidate;
|
|
182
|
+
} catch {
|
|
183
|
+
diagnostics.push(unreadableToolDiagnostic(toolIndex));
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
let name;
|
|
187
|
+
try {
|
|
188
|
+
name = tool.name;
|
|
189
|
+
} catch {
|
|
190
|
+
diagnostics.push({
|
|
191
|
+
toolIndex,
|
|
192
|
+
violations: [`tool[${toolIndex}].name is unreadable`]
|
|
193
|
+
});
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (typeof name !== "string" || !name) {
|
|
197
|
+
diagnostics.push({
|
|
198
|
+
toolIndex,
|
|
199
|
+
violations: [`tool[${toolIndex}].name is empty`]
|
|
200
|
+
});
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
let parameters;
|
|
204
|
+
try {
|
|
205
|
+
parameters = tool.parameters;
|
|
206
|
+
} catch {
|
|
207
|
+
diagnostics.push({
|
|
208
|
+
toolIndex,
|
|
209
|
+
toolName: name,
|
|
210
|
+
violations: [`${name}.parameters is unreadable`]
|
|
211
|
+
});
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
const schemaProjection = projectRuntimeToolInputSchema(parameters ?? {}, `${name}.parameters`);
|
|
215
|
+
if (!isRecord(schemaProjection.schema) || schemaProjection.violations.length > 0) {
|
|
216
|
+
diagnostics.push({
|
|
217
|
+
toolIndex,
|
|
218
|
+
toolName: name,
|
|
219
|
+
violations: schemaProjection.violations.length > 0 ? schemaProjection.violations : [`${name}.parameters must be a JSON object schema`]
|
|
220
|
+
});
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
let descriptionValue;
|
|
224
|
+
try {
|
|
225
|
+
descriptionValue = tool.description;
|
|
226
|
+
} catch {}
|
|
227
|
+
const description = typeof descriptionValue === "string" ? descriptionValue : void 0;
|
|
228
|
+
projectedTools.push({
|
|
229
|
+
toolIndex,
|
|
230
|
+
name,
|
|
231
|
+
...description !== void 0 ? { description } : {},
|
|
232
|
+
parameters: schemaProjection.schema
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
inputToolCount,
|
|
237
|
+
tools: projectedTools,
|
|
238
|
+
diagnostics
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
function requireProjectedFunction(name, projection, choiceLabel) {
|
|
242
|
+
if (!projection.tools.some((tool) => tool.name === name)) throw new Error(`${choiceLabel} requested unavailable tool "${name}" after schema conversion`);
|
|
243
|
+
}
|
|
244
|
+
/** Keeps Responses tool choices aligned with surviving function schemas. */
|
|
245
|
+
function reconcileOpenAIResponsesToolChoice(choice, projection) {
|
|
246
|
+
if (choice === "auto") return projection.tools.length > 0 ? choice : void 0;
|
|
247
|
+
if (choice === "required") {
|
|
248
|
+
if (projection.tools.length === 0) throw new Error("OpenAI Responses tool_choice requires a tool, but no tools survived schema conversion");
|
|
249
|
+
return choice;
|
|
250
|
+
}
|
|
251
|
+
if (choice === "none" || !isRecord(choice)) return choice;
|
|
252
|
+
const choiceType = choice.type;
|
|
253
|
+
if (choiceType === "function") {
|
|
254
|
+
const functionName = choice.name;
|
|
255
|
+
if (typeof functionName !== "string") return choice;
|
|
256
|
+
requireProjectedFunction(functionName, projection, "OpenAI Responses tool_choice");
|
|
257
|
+
return {
|
|
258
|
+
type: "function",
|
|
259
|
+
name: functionName
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
if (choiceType !== "allowed_tools") return choice;
|
|
263
|
+
const mode = choice.mode;
|
|
264
|
+
const tools = choice.tools;
|
|
265
|
+
if (mode !== "auto" && mode !== "required" || !Array.isArray(tools)) return choice;
|
|
266
|
+
const normalizedAllowedTools = [];
|
|
267
|
+
for (const tool of tools) {
|
|
268
|
+
if (!isRecord(tool) || tool.type !== "function") {
|
|
269
|
+
normalizedAllowedTools.push(tool);
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
const functionName = tool.name;
|
|
273
|
+
if (typeof functionName === "string" && projection.tools.some((projectedTool) => projectedTool.name === functionName)) normalizedAllowedTools.push({
|
|
274
|
+
type: "function",
|
|
275
|
+
name: functionName
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
if (normalizedAllowedTools.length === 0) {
|
|
279
|
+
if (mode === "auto") return "none";
|
|
280
|
+
throw new Error("OpenAI Responses tool_choice requires a tool, but no allowed tools survived schema conversion");
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
type: "allowed_tools",
|
|
284
|
+
mode,
|
|
285
|
+
tools: normalizedAllowedTools
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
/** Keeps Chat Completions tool choices aligned with surviving function schemas. */
|
|
289
|
+
function reconcileOpenAICompletionsToolChoice(choice, projection) {
|
|
290
|
+
if (choice === "auto") return projection.tools.length > 0 ? choice : void 0;
|
|
291
|
+
if (choice === "required") {
|
|
292
|
+
if (projection.tools.length === 0) throw new Error("OpenAI Chat Completions tool_choice requires a tool, but no tools survived schema conversion");
|
|
293
|
+
return choice;
|
|
294
|
+
}
|
|
295
|
+
if (choice === "none" || !isRecord(choice)) return choice;
|
|
296
|
+
const choiceType = choice.type;
|
|
297
|
+
if (choiceType === "custom") throw new Error("OpenAI Chat Completions custom tool_choice is unsupported because this adapter emits function tools only");
|
|
298
|
+
if (choiceType === "function") {
|
|
299
|
+
const functionChoice = choice.function;
|
|
300
|
+
if (!isRecord(functionChoice)) return choice;
|
|
301
|
+
const functionName = functionChoice.name;
|
|
302
|
+
if (typeof functionName !== "string") return choice;
|
|
303
|
+
requireProjectedFunction(functionName, projection, "OpenAI Chat Completions tool_choice");
|
|
304
|
+
return {
|
|
305
|
+
type: "function",
|
|
306
|
+
function: { name: functionName }
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
if (choiceType !== "allowed_tools") return choice;
|
|
310
|
+
const allowedConfig = choice.allowed_tools;
|
|
311
|
+
if (!isRecord(allowedConfig)) return choice;
|
|
312
|
+
const mode = allowedConfig.mode;
|
|
313
|
+
const tools = allowedConfig.tools;
|
|
314
|
+
if (mode !== "auto" && mode !== "required" || !Array.isArray(tools)) return choice;
|
|
315
|
+
const normalizedAllowedTools = [];
|
|
316
|
+
for (const tool of tools) {
|
|
317
|
+
if (!isRecord(tool) || tool.type !== "function") continue;
|
|
318
|
+
const functionChoice = tool.function;
|
|
319
|
+
const functionName = isRecord(functionChoice) ? functionChoice.name : void 0;
|
|
320
|
+
if (typeof functionName === "string" && projection.tools.some((projectedTool) => projectedTool.name === functionName)) normalizedAllowedTools.push({
|
|
321
|
+
type: "function",
|
|
322
|
+
function: { name: functionName }
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
if (normalizedAllowedTools.length === 0) {
|
|
326
|
+
if (mode === "auto") return "none";
|
|
327
|
+
throw new Error("OpenAI Chat Completions tool_choice requires a tool, but no allowed tools survived schema conversion");
|
|
328
|
+
}
|
|
329
|
+
return {
|
|
330
|
+
type: "allowed_tools",
|
|
331
|
+
allowed_tools: {
|
|
332
|
+
mode,
|
|
333
|
+
tools: normalizedAllowedTools
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
//#endregion
|
|
338
|
+
export { createModelStreamCooperativeScheduler as a, log as c, readOpenAICompletionsContentDeltas as d, resolvePromptCacheKey as f, GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP as i, measureUtf8AppendBytes as l, reconcileOpenAICompletionsToolChoice as n, createOpenAIResponseHook as o, throwIfModelStreamAborted as p, reconcileOpenAIResponsesToolChoice as r, isOpenAICompletionsThinkingEnabled as s, projectOpenAITools as t, parseOpenAICompletionsUsage as u };
|