@zhivex-ai/openai 0.16.2 → 0.17.0
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 +4 -2
- package/dist/image-generation.d.ts.map +1 -1
- package/dist/image-generation.js +2 -1
- package/dist/image-generation.js.map +1 -1
- package/dist/index.d.ts +26 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +212 -30
- package/dist/index.js.map +1 -1
- package/dist/live-audio.d.ts +3 -2
- package/dist/live-audio.d.ts.map +1 -1
- package/dist/live-audio.js.map +1 -1
- package/dist/live-session.d.ts +7 -6
- package/dist/live-session.d.ts.map +1 -1
- package/dist/live-session.js +5 -3
- package/dist/live-session.js.map +1 -1
- package/dist/live-webrtc-server.d.ts +5 -3
- package/dist/live-webrtc-server.d.ts.map +1 -1
- package/dist/live-webrtc-server.js +2 -1
- package/dist/live-webrtc-server.js.map +1 -1
- package/dist/live.d.ts +3 -2
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js.map +1 -1
- package/dist/manual-redirect.d.ts +9 -0
- package/dist/manual-redirect.d.ts.map +1 -0
- package/dist/manual-redirect.js +28 -0
- package/dist/manual-redirect.js.map +1 -0
- package/dist/model-profiles.d.ts.map +1 -1
- package/dist/model-profiles.js +5 -2
- package/dist/model-profiles.js.map +1 -1
- package/dist/realtime.d.ts +4 -3
- package/dist/realtime.d.ts.map +1 -1
- package/dist/realtime.js +13 -2
- package/dist/realtime.js.map +1 -1
- package/dist/resource-models.d.ts +2 -1
- package/dist/resource-models.d.ts.map +1 -1
- package/dist/resource-models.js +2 -1
- package/dist/resource-models.js.map +1 -1
- package/dist/voice.d.ts +34 -0
- package/dist/voice.d.ts.map +1 -0
- package/dist/voice.js +29 -0
- package/dist/voice.js.map +1 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,17 +1,90 @@
|
|
|
1
|
+
import { withManualRedirect } from "./manual-redirect.js";
|
|
1
2
|
import { createOpenAIDecisionModel } from "./decision.js";
|
|
2
3
|
import { computerInputSchema, computerScreenshotSchema } from "./computer.js";
|
|
3
4
|
export { openAIComputerTool, OpenAIComputerExecutionError } from "./computer.js";
|
|
4
5
|
import { jsonHeaders, parseJson, RESERVED_REQUEST_HEADERS } from "./http.js";
|
|
5
6
|
import { OpenAIRealtimeModel, openAIRealtimeMcpMetadataKey, resolveOpenAIRealtimeHeaders } from "./realtime.js";
|
|
6
|
-
export { openAIRealtimeMcpMetadataKey } from "./realtime.js";
|
|
7
|
+
export { OpenAIRealtimeModel, openAIRealtimeMcpMetadataKey } from "./realtime.js";
|
|
7
8
|
import { OpenAIEmbeddingModel, OpenAITranscriptionModel, OpenAISpeechModel, toUint8Array } from "./resource-models.js";
|
|
9
|
+
export { OpenAISpeechModel } from "./resource-models.js";
|
|
8
10
|
import { OpenAIAgentsClient } from "./agents.js";
|
|
9
11
|
export { OpenAIAgentsClient } from "./agents.js";
|
|
10
12
|
import { toJSONSchema, z } from "zod";
|
|
11
13
|
import { OpenAILiveModel, isOpenAILiveModel } from "./live.js";
|
|
14
|
+
export { OpenAILiveModel } from "./live.js";
|
|
12
15
|
import { createOpenAIImageGenerationModel, normalizeOpenAIImageGenerationCall, normalizeOpenAIImageGenerationPartialImage } from "./image-generation.js";
|
|
13
16
|
import { groundedCapabilities, supportsOpenAIModernResponses, assertOpenAIModelRequestSupported, resolveOpenAIModelProfile, modelCapabilities } from "./capabilities.js";
|
|
14
|
-
import { imageInputToDataUrl, ConfigurationError, ProviderHTTPError, ProviderResponseTooLargeError, ProviderToolCallError, assertTrustedEndpoint, resolveAudioResponseLimits, openWebSocketConnection, hostedTool, providerDataPart, UnsupportedFeatureError, createProviderAdapter, isCallableToolDefinition, isHostedToolDefinition, normalizeFinishReason, streamSSE, streamChatCompletions, toolResultPayload, withRetry, withResponseRetry, withTimeoutSignal } from "@zhivex-ai/core/provider";
|
|
17
|
+
import { imageInputToDataUrl, ConfigurationError, ProviderHTTPError, ProviderResponseTooLargeError, ProviderToolCallError, ValidationError, assertTrustedEndpoint, resolveAudioResponseLimits, openWebSocketConnection, hostedTool, providerDataPart, UnsupportedFeatureError, createProviderAdapter, isCallableToolDefinition, isHostedToolDefinition, normalizeFinishReason, streamSSE, streamChatCompletions, toolResultPayload, withRetry, withResponseRetry, withTimeoutSignal } from "@zhivex-ai/core/provider";
|
|
18
|
+
const TOOL_INPUT_JSON_SCHEMA = Symbol.for("@zhivex-ai/core/json-schema");
|
|
19
|
+
/** Zod inputs stay on toJSONSchema so this package still loads against the oldest core in its peer range. */
|
|
20
|
+
const toolInputSchema = (schema) => {
|
|
21
|
+
if (schema !== null && typeof schema === "object" && schema[TOOL_INPUT_JSON_SCHEMA] === true) {
|
|
22
|
+
return { ...schema.jsonSchema };
|
|
23
|
+
}
|
|
24
|
+
return toJSONSchema(schema);
|
|
25
|
+
};
|
|
26
|
+
const openAISamplingWarnings = new Set();
|
|
27
|
+
const warnOpenAISampling = (option, detail) => {
|
|
28
|
+
const key = `openai:${option}:${detail}`;
|
|
29
|
+
if (openAISamplingWarnings.has(key))
|
|
30
|
+
return;
|
|
31
|
+
openAISamplingWarnings.add(key);
|
|
32
|
+
console.warn(`Provider "openai" does not support ${option}. ${detail} The option was ignored.`);
|
|
33
|
+
};
|
|
34
|
+
const openAIChatCacheTtlWarnings = new Set();
|
|
35
|
+
const warnOpenAIChatPromptCacheTtl = () => {
|
|
36
|
+
const key = 'openai:prompt_cache_options.ttl:12h:chat';
|
|
37
|
+
if (openAIChatCacheTtlWarnings.has(key))
|
|
38
|
+
return;
|
|
39
|
+
openAIChatCacheTtlWarnings.add(key);
|
|
40
|
+
console.warn('Provider "openai" does not support prompt_cache_options.ttl "12h" on Chat Completions. The option was ignored.');
|
|
41
|
+
};
|
|
42
|
+
/** Chat Completions support for a 12-hour cache TTL is unconfirmed, so that value is ignored. */
|
|
43
|
+
const openAIChatBodyOptions = (options) => {
|
|
44
|
+
const cache = options.prompt_cache_options;
|
|
45
|
+
if (cache?.ttl !== "12h")
|
|
46
|
+
return options;
|
|
47
|
+
warnOpenAIChatPromptCacheTtl();
|
|
48
|
+
const rest = { ...cache };
|
|
49
|
+
delete rest.ttl;
|
|
50
|
+
const next = { ...options };
|
|
51
|
+
if (Object.keys(rest).length === 0)
|
|
52
|
+
delete next.prompt_cache_options;
|
|
53
|
+
else
|
|
54
|
+
next.prompt_cache_options = rest;
|
|
55
|
+
return next;
|
|
56
|
+
};
|
|
57
|
+
/** Model profiles that already reject sampling. `topP` still throws in assertOpenAIModelRequestSupported. */
|
|
58
|
+
const openAISamplingRejected = (modelId, input, bodyOptions) => {
|
|
59
|
+
const profile = resolveOpenAIModelProfile(modelId);
|
|
60
|
+
if (profile.sampling === "allowed")
|
|
61
|
+
return null;
|
|
62
|
+
const effort = input.reasoning?.effort ?? bodyOptions.reasoning?.effort ?? bodyOptions.reasoning_effort;
|
|
63
|
+
return profile.sampling === "unsupported" || effort !== "none" ? profile.label : null;
|
|
64
|
+
};
|
|
65
|
+
const openAIChatSampling = (modelId, input, bodyOptions) => {
|
|
66
|
+
const rejected = openAISamplingRejected(modelId, input, bodyOptions);
|
|
67
|
+
if (rejected) {
|
|
68
|
+
if (input.seed !== undefined)
|
|
69
|
+
warnOpenAISampling("seed", `${rejected} does not support seed.`);
|
|
70
|
+
if (input.stopSequences !== undefined) {
|
|
71
|
+
warnOpenAISampling("stopSequences", `${rejected} does not support stop sequences.`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
...(input.topP !== undefined ? { top_p: input.topP } : {}),
|
|
76
|
+
...(!rejected && input.seed !== undefined ? { seed: input.seed } : {}),
|
|
77
|
+
...(!rejected && input.stopSequences !== undefined ? { stop: [...input.stopSequences] } : {})
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
const openAIResponsesSampling = (input) => {
|
|
81
|
+
if (input.seed !== undefined)
|
|
82
|
+
warnOpenAISampling("seed", "The Responses API does not accept seed.");
|
|
83
|
+
if (input.stopSequences !== undefined) {
|
|
84
|
+
warnOpenAISampling("stopSequences", "The Responses API does not accept stop sequences.");
|
|
85
|
+
}
|
|
86
|
+
return input.topP !== undefined ? { top_p: input.topP } : {};
|
|
87
|
+
};
|
|
15
88
|
const MIB = 1024 * 1024;
|
|
16
89
|
const DEFAULT_HOSTED_IMAGE_EVENT_BYTES = 32 * MIB;
|
|
17
90
|
const DEFAULT_HOSTED_IMAGE_TOTAL_BYTES = 128 * MIB;
|
|
@@ -58,13 +131,53 @@ const assertOpenAIToolPathInsideRoot = async (rootDir, targetPath, label) => {
|
|
|
58
131
|
return targetPath;
|
|
59
132
|
}
|
|
60
133
|
const path = await import("node:path");
|
|
134
|
+
const fs = await import("node:fs/promises");
|
|
61
135
|
const root = path.resolve(rootDir);
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
|
|
136
|
+
const lexical = path.resolve(root, targetPath);
|
|
137
|
+
const lexicalRelative = path.relative(root, lexical);
|
|
138
|
+
const escapes = (relative) => path.isAbsolute(relative) || relative.split(path.sep).includes("..");
|
|
139
|
+
if (escapes(lexicalRelative)) {
|
|
65
140
|
throw new Error(`OpenAI ${label} path escapes rootDir.`);
|
|
66
141
|
}
|
|
67
|
-
|
|
142
|
+
let rootReal;
|
|
143
|
+
try {
|
|
144
|
+
const rootStat = await fs.lstat(root);
|
|
145
|
+
if (rootStat.isSymbolicLink()) {
|
|
146
|
+
throw new Error(`OpenAI ${label} path escapes rootDir.`);
|
|
147
|
+
}
|
|
148
|
+
rootReal = await fs.realpath(root);
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
if (error instanceof Error && error.message.includes("escapes rootDir"))
|
|
152
|
+
throw error;
|
|
153
|
+
throw new Error(`OpenAI ${label} rootDir is not an accessible directory.`);
|
|
154
|
+
}
|
|
155
|
+
const missing = [];
|
|
156
|
+
let current = lexical;
|
|
157
|
+
let resolvedExisting = rootReal;
|
|
158
|
+
while (true) {
|
|
159
|
+
try {
|
|
160
|
+
resolvedExisting = await fs.realpath(current);
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
const code = error.code;
|
|
165
|
+
if (code !== "ENOENT")
|
|
166
|
+
throw new Error(`OpenAI ${label} path escapes rootDir.`);
|
|
167
|
+
const parent = path.dirname(current);
|
|
168
|
+
if (parent === current)
|
|
169
|
+
throw new Error(`OpenAI ${label} path escapes rootDir.`);
|
|
170
|
+
missing.push(path.basename(current));
|
|
171
|
+
current = parent;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const resolved = missing.length === 0 ? resolvedExisting : path.resolve(resolvedExisting, ...missing.reverse());
|
|
175
|
+
const relative = path.relative(rootReal, resolved);
|
|
176
|
+
if (escapes(relative) ||
|
|
177
|
+
(resolved !== rootReal && !resolved.startsWith(`${rootReal}${path.sep}`))) {
|
|
178
|
+
throw new Error(`OpenAI ${label} path escapes rootDir.`);
|
|
179
|
+
}
|
|
180
|
+
return resolved;
|
|
68
181
|
};
|
|
69
182
|
const resolveOpenAILanguageRequestOptions = (providerOptions, apiKey) => {
|
|
70
183
|
const bodyOptions = { ...(providerOptions ?? {}) };
|
|
@@ -141,6 +254,14 @@ const isOpenAIPromptCacheBreakpointPart = (part) => part.type === "provider-data
|
|
|
141
254
|
part.data !== null &&
|
|
142
255
|
typeof part.data === "object" &&
|
|
143
256
|
part.data.type === "prompt_cache_breakpoint";
|
|
257
|
+
const explicitPromptCacheBreakpoint = (breakpoint) => {
|
|
258
|
+
const record = breakpoint;
|
|
259
|
+
const ttl = record.ttl;
|
|
260
|
+
if (ttl !== undefined && ttl !== "30m" && ttl !== "12h") {
|
|
261
|
+
throw new ValidationError('OpenAI prompt cache breakpoint ttl must be "30m" or "12h".');
|
|
262
|
+
}
|
|
263
|
+
return ttl === "30m" || ttl === "12h" ? { mode: "explicit", ttl } : { mode: "explicit" };
|
|
264
|
+
};
|
|
144
265
|
const promptCacheBreakpointForContentPart = (part) => {
|
|
145
266
|
const metadata = part
|
|
146
267
|
.providerMetadata;
|
|
@@ -149,7 +270,7 @@ const promptCacheBreakpointForContentPart = (part) => {
|
|
|
149
270
|
: metadata;
|
|
150
271
|
const breakpoint = openAIMetadata?.prompt_cache_breakpoint;
|
|
151
272
|
return breakpoint && typeof breakpoint === "object" && !Array.isArray(breakpoint)
|
|
152
|
-
? { prompt_cache_breakpoint:
|
|
273
|
+
? { prompt_cache_breakpoint: explicitPromptCacheBreakpoint(breakpoint) }
|
|
153
274
|
: {};
|
|
154
275
|
};
|
|
155
276
|
const imageDetailForPart = (part) => {
|
|
@@ -160,12 +281,12 @@ const imageDetailForPart = (part) => {
|
|
|
160
281
|
: undefined);
|
|
161
282
|
return detail === "auto" || detail === "low" || detail === "high" || detail === "original" ? detail : undefined;
|
|
162
283
|
};
|
|
163
|
-
const markLastContentBlockForPromptCaching = (content) => {
|
|
284
|
+
const markLastContentBlockForPromptCaching = (content, breakpoint) => {
|
|
164
285
|
const last = content.at(-1);
|
|
165
286
|
if (!last) {
|
|
166
287
|
throw new ConfigurationError("OpenAI prompt cache breakpoints must follow a cacheable content part.");
|
|
167
288
|
}
|
|
168
|
-
last.prompt_cache_breakpoint =
|
|
289
|
+
last.prompt_cache_breakpoint = explicitPromptCacheBreakpoint(breakpoint);
|
|
169
290
|
};
|
|
170
291
|
const mapContentParts = (message) => {
|
|
171
292
|
const hasRichContent = message.parts.some((part) => part.type === "image" ||
|
|
@@ -210,7 +331,7 @@ const mapContentParts = (message) => {
|
|
|
210
331
|
});
|
|
211
332
|
}
|
|
212
333
|
else if (isOpenAIPromptCacheBreakpointPart(part)) {
|
|
213
|
-
markLastContentBlockForPromptCaching(content);
|
|
334
|
+
markLastContentBlockForPromptCaching(content, part.data);
|
|
214
335
|
}
|
|
215
336
|
}
|
|
216
337
|
return content;
|
|
@@ -317,7 +438,7 @@ const mapTools = (input) => input
|
|
|
317
438
|
function: {
|
|
318
439
|
name: tool.name,
|
|
319
440
|
description: tool.description,
|
|
320
|
-
parameters:
|
|
441
|
+
parameters: toolInputSchema(tool.schema)
|
|
321
442
|
}
|
|
322
443
|
};
|
|
323
444
|
}
|
|
@@ -344,7 +465,7 @@ const mapResponsesTools = (input) => input
|
|
|
344
465
|
type: "function",
|
|
345
466
|
name: tool.name,
|
|
346
467
|
description: tool.description,
|
|
347
|
-
parameters:
|
|
468
|
+
parameters: toolInputSchema(tool.schema),
|
|
348
469
|
...openAIResponsesFunctionConfig(tool)
|
|
349
470
|
};
|
|
350
471
|
}
|
|
@@ -757,7 +878,7 @@ const toResponsesInput = (messages, format, history = messages) => {
|
|
|
757
878
|
break;
|
|
758
879
|
case "provider-data":
|
|
759
880
|
if (isOpenAIPromptCacheBreakpointPart(part)) {
|
|
760
|
-
markLastContentBlockForPromptCaching(content);
|
|
881
|
+
markLastContentBlockForPromptCaching(content, part.data);
|
|
761
882
|
}
|
|
762
883
|
break;
|
|
763
884
|
}
|
|
@@ -925,36 +1046,90 @@ const attachTerminalUsage = (error, raw) => new ProviderToolCallError({
|
|
|
925
1046
|
cause: error.cause,
|
|
926
1047
|
usage: mapResponsesUsage(raw)
|
|
927
1048
|
});
|
|
928
|
-
const
|
|
929
|
-
|
|
1049
|
+
const mapOpenAICacheWriteTokensDetails = (details) => {
|
|
1050
|
+
if (!details || typeof details !== "object" || Array.isArray(details))
|
|
1051
|
+
return undefined;
|
|
1052
|
+
const record = details;
|
|
1053
|
+
const read = (key) => typeof record[key] === "number" ? record[key] : undefined;
|
|
1054
|
+
const ttl30mTokens = read("ttl_30m_tokens");
|
|
1055
|
+
const ttl12hTokens = read("ttl_12h_tokens");
|
|
1056
|
+
if (ttl30mTokens === undefined && ttl12hTokens === undefined)
|
|
1057
|
+
return undefined;
|
|
1058
|
+
return {
|
|
1059
|
+
...(ttl30mTokens !== undefined ? { ttl30mTokens } : {}),
|
|
1060
|
+
...(ttl12hTokens !== undefined ? { ttl12hTokens } : {})
|
|
1061
|
+
};
|
|
1062
|
+
};
|
|
1063
|
+
const mapResponsesUsage = (usage) => {
|
|
1064
|
+
if (!usage)
|
|
1065
|
+
return undefined;
|
|
1066
|
+
const cacheWriteTokensDetails = mapOpenAICacheWriteTokensDetails(usage.input_tokens_details?.cache_write_tokens_details);
|
|
1067
|
+
return {
|
|
930
1068
|
inputTokens: usage.input_tokens,
|
|
931
1069
|
cachedInputTokens: usage.input_tokens_details?.cached_tokens,
|
|
932
1070
|
cacheWriteTokens: usage.input_tokens_details?.cache_write_tokens,
|
|
1071
|
+
...(cacheWriteTokensDetails ? { cacheWriteTokensDetails } : {}),
|
|
933
1072
|
outputTokens: usage.output_tokens,
|
|
934
1073
|
reasoningTokens: usage.output_tokens_details?.reasoning_tokens,
|
|
935
1074
|
totalTokens: usage.total_tokens
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
const mapChatUsage = (usage) =>
|
|
939
|
-
|
|
1075
|
+
};
|
|
1076
|
+
};
|
|
1077
|
+
const mapChatUsage = (usage) => {
|
|
1078
|
+
if (!usage)
|
|
1079
|
+
return undefined;
|
|
1080
|
+
const cacheWriteTokensDetails = mapOpenAICacheWriteTokensDetails(usage.prompt_tokens_details?.cache_write_tokens_details);
|
|
1081
|
+
return {
|
|
940
1082
|
inputTokens: usage.prompt_tokens,
|
|
941
1083
|
cachedInputTokens: usage.prompt_tokens_details?.cached_tokens,
|
|
942
1084
|
cacheWriteTokens: usage.prompt_tokens_details?.cache_write_tokens,
|
|
1085
|
+
...(cacheWriteTokensDetails ? { cacheWriteTokensDetails } : {}),
|
|
943
1086
|
outputTokens: usage.completion_tokens,
|
|
944
1087
|
reasoningTokens: usage.completion_tokens_details?.reasoning_tokens,
|
|
945
1088
|
totalTokens: usage.total_tokens
|
|
946
|
-
}
|
|
947
|
-
|
|
1089
|
+
};
|
|
1090
|
+
};
|
|
1091
|
+
const openAIUsageCounters = (usage) => [
|
|
1092
|
+
usage.inputTokens,
|
|
1093
|
+
usage.outputTokens,
|
|
1094
|
+
usage.totalTokens,
|
|
1095
|
+
usage.cachedInputTokens,
|
|
1096
|
+
usage.cacheWriteTokens,
|
|
1097
|
+
usage.reasoningTokens,
|
|
1098
|
+
usage.cacheWriteTokensDetails?.ttl30mTokens,
|
|
1099
|
+
usage.cacheWriteTokensDetails?.ttl12hTokens
|
|
1100
|
+
];
|
|
1101
|
+
const openAIUsageCounterInvalid = (usage) => openAIUsageCounters(usage ?? {}).some((value) => value !== undefined && (!Number.isSafeInteger(value) || value < 0));
|
|
948
1102
|
const addTokenUsage = (left, right) => {
|
|
949
1103
|
if (!left)
|
|
950
1104
|
return right;
|
|
951
1105
|
if (!right)
|
|
952
1106
|
return left;
|
|
953
1107
|
const sum = (a, b) => a === undefined || b === undefined ? undefined : a + b;
|
|
1108
|
+
const consistentDetails = (writes, details) => {
|
|
1109
|
+
if (!details)
|
|
1110
|
+
return (writes ?? 0) === 0;
|
|
1111
|
+
return writes !== undefined && (details.ttl30mTokens ?? 0) + (details.ttl12hTokens ?? 0) === writes;
|
|
1112
|
+
};
|
|
1113
|
+
const cacheWriteTokensDetails = consistentDetails(left.cacheWriteTokens, left.cacheWriteTokensDetails) &&
|
|
1114
|
+
consistentDetails(right.cacheWriteTokens, right.cacheWriteTokensDetails) &&
|
|
1115
|
+
(left.cacheWriteTokensDetails || right.cacheWriteTokensDetails)
|
|
1116
|
+
? {
|
|
1117
|
+
...(left.cacheWriteTokensDetails?.ttl30mTokens !== undefined || right.cacheWriteTokensDetails?.ttl30mTokens !== undefined
|
|
1118
|
+
? { ttl30mTokens: (left.cacheWriteTokensDetails?.ttl30mTokens ?? 0) + (right.cacheWriteTokensDetails?.ttl30mTokens ?? 0) }
|
|
1119
|
+
: {}),
|
|
1120
|
+
...(left.cacheWriteTokensDetails?.ttl12hTokens !== undefined || right.cacheWriteTokensDetails?.ttl12hTokens !== undefined
|
|
1121
|
+
? { ttl12hTokens: (left.cacheWriteTokensDetails?.ttl12hTokens ?? 0) + (right.cacheWriteTokensDetails?.ttl12hTokens ?? 0) }
|
|
1122
|
+
: {})
|
|
1123
|
+
}
|
|
1124
|
+
: undefined;
|
|
954
1125
|
return {
|
|
955
1126
|
inputTokens: sum(left.inputTokens, right.inputTokens),
|
|
956
1127
|
cachedInputTokens: sum(left.cachedInputTokens, right.cachedInputTokens),
|
|
957
1128
|
cacheWriteTokens: sum(left.cacheWriteTokens, right.cacheWriteTokens),
|
|
1129
|
+
...(cacheWriteTokensDetails &&
|
|
1130
|
+
(cacheWriteTokensDetails.ttl30mTokens !== undefined || cacheWriteTokensDetails.ttl12hTokens !== undefined)
|
|
1131
|
+
? { cacheWriteTokensDetails }
|
|
1132
|
+
: {}),
|
|
958
1133
|
outputTokens: sum(left.outputTokens, right.outputTokens),
|
|
959
1134
|
reasoningTokens: sum(left.reasoningTokens, right.reasoningTokens),
|
|
960
1135
|
totalTokens: sum(left.totalTokens, right.totalTokens)
|
|
@@ -1528,17 +1703,18 @@ class OpenAILanguageModel {
|
|
|
1528
1703
|
...(input.toolChoice ? { tool_choice: mapResponsesToolChoice(input.toolChoice) } : {}),
|
|
1529
1704
|
text: mapResponsesStructuredOutput(input) ?? responseBodyOptions.text,
|
|
1530
1705
|
temperature: input.temperature,
|
|
1706
|
+
...openAIResponsesSampling(input),
|
|
1531
1707
|
max_output_tokens: ptc ? remainingOutputTokens : input.maxTokens,
|
|
1532
1708
|
...mapResponsesReasoning(input, responseBodyOptions.reasoning)
|
|
1533
1709
|
})
|
|
1534
1710
|
}), { ...input, abortSignal: signal, ...(ptc ? { maxRetries: 0 } : {}) }, "OpenAI");
|
|
1535
1711
|
const json = await parseJson(response);
|
|
1536
1712
|
const reportedUsage = mapResponsesUsage(json.usage);
|
|
1537
|
-
if (ptc && (!reportedUsage || ![reportedUsage.inputTokens, reportedUsage.outputTokens, reportedUsage.totalTokens].every(value => typeof value === "number" && Number.isSafeInteger(value) && value >= 0) || reportedUsage.totalTokens < reportedUsage.inputTokens + reportedUsage.outputTokens ||
|
|
1713
|
+
if (ptc && (!reportedUsage || ![reportedUsage.inputTokens, reportedUsage.outputTokens, reportedUsage.totalTokens].every(value => typeof value === "number" && Number.isSafeInteger(value) && value >= 0) || reportedUsage.totalTokens < reportedUsage.inputTokens + reportedUsage.outputTokens || openAIUsageCounterInvalid(reportedUsage))) {
|
|
1538
1714
|
throw failure("OPENAI_PTC_USAGE_UNKNOWN");
|
|
1539
1715
|
}
|
|
1540
1716
|
const nextUsage = addTokenUsage(accumulatedUsage, reportedUsage);
|
|
1541
|
-
if (ptc &&
|
|
1717
|
+
if (ptc && openAIUsageCounterInvalid(nextUsage))
|
|
1542
1718
|
throw failure("OPENAI_PTC_USAGE_UNKNOWN");
|
|
1543
1719
|
accumulatedUsage = nextUsage;
|
|
1544
1720
|
if (ptc)
|
|
@@ -1617,13 +1793,14 @@ class OpenAILanguageModel {
|
|
|
1617
1793
|
headers: options.headers,
|
|
1618
1794
|
signal,
|
|
1619
1795
|
body: JSON.stringify({
|
|
1620
|
-
...options.bodyOptions,
|
|
1796
|
+
...openAIChatBodyOptions(options.bodyOptions),
|
|
1621
1797
|
model: this.modelId,
|
|
1622
1798
|
messages: mapMessages(input.messages, input.toolResultFormat),
|
|
1623
1799
|
tools: mapTools(input.tools),
|
|
1624
1800
|
...(input.toolChoice ? { tool_choice: mapToolChoice(input.toolChoice) } : {}),
|
|
1625
1801
|
response_format: mapStructuredOutput(input) ?? options.bodyOptions.response_format,
|
|
1626
1802
|
temperature: input.temperature,
|
|
1803
|
+
...openAIChatSampling(this.modelId, input, options.bodyOptions),
|
|
1627
1804
|
...(input.reasoning ? {} : { max_tokens: input.maxTokens }),
|
|
1628
1805
|
...mapChatReasoning(input),
|
|
1629
1806
|
stream: false
|
|
@@ -1681,6 +1858,7 @@ class OpenAILanguageModel {
|
|
|
1681
1858
|
...(input.toolChoice ? { tool_choice: mapResponsesToolChoice(input.toolChoice) } : {}),
|
|
1682
1859
|
text: mapResponsesStructuredOutput(input) ?? responseBodyOptions.text,
|
|
1683
1860
|
temperature: input.temperature,
|
|
1861
|
+
...openAIResponsesSampling(input),
|
|
1684
1862
|
max_output_tokens: input.maxTokens,
|
|
1685
1863
|
...mapResponsesReasoning(input, responseBodyOptions.reasoning),
|
|
1686
1864
|
stream: true
|
|
@@ -1703,13 +1881,14 @@ class OpenAILanguageModel {
|
|
|
1703
1881
|
headers: options.headers,
|
|
1704
1882
|
signal,
|
|
1705
1883
|
body: JSON.stringify({
|
|
1706
|
-
...options.bodyOptions,
|
|
1884
|
+
...openAIChatBodyOptions(options.bodyOptions),
|
|
1707
1885
|
model: this.modelId,
|
|
1708
1886
|
messages: mapMessages(input.messages, input.toolResultFormat),
|
|
1709
1887
|
tools: mapTools(input.tools),
|
|
1710
1888
|
...(input.toolChoice ? { tool_choice: mapToolChoice(input.toolChoice) } : {}),
|
|
1711
1889
|
response_format: mapStructuredOutput(input) ?? options.bodyOptions.response_format,
|
|
1712
1890
|
temperature: input.temperature,
|
|
1891
|
+
...openAIChatSampling(this.modelId, input, options.bodyOptions),
|
|
1713
1892
|
...(input.reasoning ? {} : { max_tokens: input.maxTokens }),
|
|
1714
1893
|
...mapChatReasoning(input),
|
|
1715
1894
|
stream: true,
|
|
@@ -1800,7 +1979,8 @@ export const createOpenAI = (options = {}) => {
|
|
|
1800
1979
|
allowUnsafe: options.allowUnsafeEndpoints
|
|
1801
1980
|
}).toString()
|
|
1802
1981
|
: undefined;
|
|
1803
|
-
const
|
|
1982
|
+
const rawFetch = options.fetch ?? globalThis.fetch;
|
|
1983
|
+
const fetcher = withManualRedirect(rawFetch);
|
|
1804
1984
|
const responseLimits = resolveOpenAIResponseLimits(options.responseLimits);
|
|
1805
1985
|
return createProviderAdapter({
|
|
1806
1986
|
name: "openai",
|
|
@@ -1827,7 +2007,7 @@ export const createOpenAI = (options = {}) => {
|
|
|
1827
2007
|
return isOpenAILiveModel(modelId) ? new OpenAILiveModel(modelId, baseURL, (providerOptions) => resolveOpenAIRealtimeHeaders(apiKey, providerOptions), options.realtimeConnectionFactory ?? openWebSocketConnection, realtimeURL, options.allowUnsafeEndpoints) : new OpenAIRealtimeModel(modelId, apiKey, baseURL, fetcher, options.realtimeConnectionFactory, realtimeURL, browserTokenURL, options.allowUnsafeEndpoints);
|
|
1828
2008
|
},
|
|
1829
2009
|
groundedLanguageModel: (modelId) => new OpenAIGroundedLanguageModel(modelId, apiKey, baseURL, fetcher),
|
|
1830
|
-
rawFetch
|
|
2010
|
+
rawFetch,
|
|
1831
2011
|
agents: new OpenAIAgentsClient(baseURL, apiKey, fetcher, options.allowUnsafeEndpoints)
|
|
1832
2012
|
});
|
|
1833
2013
|
};
|
|
@@ -1907,9 +2087,10 @@ export const openAIRealtimeMcpApprovalResult = (response) => ({
|
|
|
1907
2087
|
}
|
|
1908
2088
|
}
|
|
1909
2089
|
});
|
|
1910
|
-
export const openAIPromptCacheBreakpoint = () => providerDataPart("openai", {
|
|
2090
|
+
export const openAIPromptCacheBreakpoint = (breakpoint) => providerDataPart("openai", {
|
|
1911
2091
|
type: "prompt_cache_breakpoint",
|
|
1912
|
-
mode: "explicit"
|
|
2092
|
+
mode: "explicit",
|
|
2093
|
+
...(breakpoint?.ttl ? { ttl: breakpoint.ttl } : {})
|
|
1913
2094
|
});
|
|
1914
2095
|
export const openAIComputerUseTool = (config) => hostedTool({
|
|
1915
2096
|
name: "computer",
|
|
@@ -2011,7 +2192,8 @@ export const openAIShellTool = (config = {}) => ({
|
|
|
2011
2192
|
});
|
|
2012
2193
|
const applyOpenAIPatchOperation = async (operation, config) => {
|
|
2013
2194
|
if (config.rootDir) {
|
|
2014
|
-
await assertOpenAIToolPathInsideRoot(config.rootDir, operation.path, "apply_patch");
|
|
2195
|
+
const safePath = await assertOpenAIToolPathInsideRoot(config.rootDir, operation.path, "apply_patch");
|
|
2196
|
+
return config.applyOperation({ ...operation, path: safePath });
|
|
2015
2197
|
}
|
|
2016
2198
|
return config.applyOperation(operation);
|
|
2017
2199
|
};
|