@ai-sdk/openai 4.0.108 → 4.0.110
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/CHANGELOG.md +54 -0
- package/dist/index.d.ts +79 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +788 -423
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +389 -9
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +629 -380
- package/dist/internal/index.js.map +1 -1
- package/docs/03-openai.mdx +224 -18
- package/package.json +3 -3
- package/src/chat/convert-to-openai-chat-messages.ts +29 -4
- package/src/chat/map-openai-finish-reason.ts +11 -4
- package/src/chat/openai-chat-api.ts +36 -0
- package/src/chat/openai-chat-language-model-options.ts +13 -0
- package/src/chat/openai-chat-language-model.ts +111 -22
- package/src/chat/openai-chat-prompt.ts +4 -0
- package/src/image/openai-image-model-options.ts +48 -0
- package/src/image/openai-image-model.ts +49 -4
- package/src/index.ts +1 -0
- package/src/internal/index.ts +4 -0
- package/src/live/openai-realtime-model-live.ts +21 -2
- package/src/openai-batch.ts +8 -0
- package/src/openai-model-catalog.ts +3 -1
- package/src/openai-tools.ts +4 -3
- package/src/realtime/openai-realtime-event-mapper.ts +172 -11
- package/src/realtime/openai-realtime-model.ts +57 -3
- package/src/responses/map-openai-responses-finish-reason.ts +7 -1
- package/src/responses/openai-responses-api.ts +90 -49
- package/src/responses/openai-responses-language-model.ts +56 -1
- package/src/responses/openai-responses-prepare-tools.ts +18 -1
- package/src/tool/code-interpreter.ts +38 -2
- package/src/tool/mcp.ts +27 -8
- package/src/transcription/openai-transcription-model.ts +43 -8
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EXPERIMENTAL_EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL, StreamingToolCallTracker, WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE, combineHeaders, connectToWebSocket, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertInlineFileDataToUint8Array, convertToBase64, convertToFormData, convertUint8ArrayToBase64, createBinaryResponseHandler, createBinaryStreamResponseHandler, createEventSourceResponseHandler, createJsonErrorResponseHandler, createJsonLinesResponseHandler, createJsonResponseHandler, createLanguageModelResponseMetadata, createLanguageModelResponseMetadata as getResponseMetadata, createNullLanguageModelUsage, createProviderDefinedToolFactory, createProviderDefinedToolFactoryWithOutputSchema, createProviderExecutedToolFactory, createProviderStreamError, createToolNameMapping, deleteFromApi, detectMediaType, downloadBlob, encodePathSegment, experimental_toolCaller, generateId, getFromApi, getTopLevelMediaType, isCustomReasoning, isFullMediaType, isNonNullable, isRecord, lazySchema, loadApiKey, loadOptionalSetting, mapReasoningToProviderEffort, mediaTypeToExtension, normalizeBatchRequestCounts, parseJSON, parseProviderOptions, postFormDataToApi, postJsonToApi, postMultipartStreamToApi, postToApi, resolve, resolveFullMediaType, resolveProviderReference, resolveWith, safeParseJSON, safeValidateTypes, secureJsonParse, serializeModelOptions, stringifyWithBigIntAndCycles, toWebSocketUrl, validateBaseURL, validateTypes, waitForWebSocketBufferDrain, withUserAgentSuffix, withoutTrailingSlash, zodSchema } from "@ai-sdk/provider-utils";
|
|
1
|
+
import { EXPERIMENTAL_EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL, StreamingToolCallTracker, WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE, combineHeaders, connectToWebSocket, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertInlineFileDataToUint8Array, convertToBase64, convertToFormData, convertUint8ArrayToBase64, createBinaryResponseHandler, createBinaryStreamResponseHandler, createEventSourceResponseHandler, createJsonErrorResponseHandler, createJsonLinesResponseHandler, createJsonResponseHandler, createLanguageModelResponseMetadata, createLanguageModelResponseMetadata as getResponseMetadata, createNullLanguageModelUsage, createProviderDefinedToolFactory, createProviderDefinedToolFactoryWithOutputSchema, createProviderExecutedToolFactory, createProviderStreamError, createToolNameMapping, deleteFromApi, detectMediaType, downloadBlob, encodePathSegment, experimental_toolCaller, generateId, getFromApi, getTopLevelMediaType, isCustomReasoning, isFullMediaType, isNonNullable, isRecord, lazySchema, loadApiKey, loadOptionalSetting, mapReasoningToProviderEffort, mediaTypeToExtension, normalizeBatchRequestCounts, parseJSON, parseProviderOptions, postFormDataToApi, postJsonToApi, postMultipartStreamToApi, postToApi, removeUndefinedEntries, resolve, resolveFullMediaType, resolveProviderReference, resolveWith, safeParseJSON, safeValidateTypes, secureJsonParse, serializeModelOptions, stringifyWithBigIntAndCycles, toWebSocketUrl, validateBaseURL, validateTypes, waitForWebSocketBufferDrain, withUserAgentSuffix, withoutTrailingSlash, zodSchema } from "@ai-sdk/provider-utils";
|
|
2
2
|
import { APICallError, InvalidArgumentError, InvalidPromptError, InvalidResponseDataError, TooManyEmbeddingValuesForCallError, UnsupportedFunctionalityError, isJSONObject } from "@ai-sdk/provider";
|
|
3
3
|
import { z } from "zod/v4";
|
|
4
4
|
//#region src/openai-config.ts
|
|
@@ -537,6 +537,8 @@ function createGptImageEntry(sizes) {
|
|
|
537
537
|
};
|
|
538
538
|
}
|
|
539
539
|
const openaiImageModelEntries = {
|
|
540
|
+
"gpt-image-2.6-flare": createGptImageEntry(customImageSizes),
|
|
541
|
+
"gpt-image-2.6-sunburst": createGptImageEntry(customImageSizes),
|
|
540
542
|
"gpt-image-2.5-flare": createGptImageEntry(customImageSizes),
|
|
541
543
|
"gpt-image-2.5-sunburst": createGptImageEntry(customImageSizes),
|
|
542
544
|
"gpt-image-2": createGptImageEntry(gptImageSizes),
|
|
@@ -725,7 +727,7 @@ const realtimeModelEntry = {
|
|
|
725
727
|
capabilities: { realtime: {
|
|
726
728
|
conversation: "turn-based",
|
|
727
729
|
transports: ["websocket"],
|
|
728
|
-
connections: ["client-secret-websocket"]
|
|
730
|
+
connections: ["client-secret-websocket", "server-websocket"]
|
|
729
731
|
} },
|
|
730
732
|
requestConfig: { realtime: {
|
|
731
733
|
api: "realtime",
|
|
@@ -1004,347 +1006,6 @@ function convertOpenAIChatUsage(usage) {
|
|
|
1004
1006
|
};
|
|
1005
1007
|
}
|
|
1006
1008
|
//#endregion
|
|
1007
|
-
//#region src/chat/convert-to-openai-chat-messages.ts
|
|
1008
|
-
function serializeToolCallArguments$1(input) {
|
|
1009
|
-
if (typeof input === "string") try {
|
|
1010
|
-
const parsed = secureJsonParse(input);
|
|
1011
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return "{}";
|
|
1012
|
-
return input;
|
|
1013
|
-
} catch {
|
|
1014
|
-
return "{}";
|
|
1015
|
-
}
|
|
1016
|
-
return stringifyWithBigIntAndCycles(typeof input === "object" && input !== null && !Array.isArray(input) ? input : {});
|
|
1017
|
-
}
|
|
1018
|
-
function getPromptCacheBreakpoint$1(providerOptions) {
|
|
1019
|
-
return providerOptions?.openai?.promptCacheBreakpoint;
|
|
1020
|
-
}
|
|
1021
|
-
function convertToOpenAIChatMessages({ prompt, systemMessageMode = "system" }) {
|
|
1022
|
-
const messages = [];
|
|
1023
|
-
const warnings = [];
|
|
1024
|
-
for (const { role, content, providerOptions } of prompt) switch (role) {
|
|
1025
|
-
case "system":
|
|
1026
|
-
switch (systemMessageMode) {
|
|
1027
|
-
case "system": {
|
|
1028
|
-
const promptCacheBreakpoint = getPromptCacheBreakpoint$1(providerOptions);
|
|
1029
|
-
messages.push({
|
|
1030
|
-
role: "system",
|
|
1031
|
-
content: promptCacheBreakpoint == null ? content : [{
|
|
1032
|
-
type: "text",
|
|
1033
|
-
text: content,
|
|
1034
|
-
prompt_cache_breakpoint: promptCacheBreakpoint
|
|
1035
|
-
}]
|
|
1036
|
-
});
|
|
1037
|
-
break;
|
|
1038
|
-
}
|
|
1039
|
-
case "developer": {
|
|
1040
|
-
const promptCacheBreakpoint = getPromptCacheBreakpoint$1(providerOptions);
|
|
1041
|
-
messages.push({
|
|
1042
|
-
role: "developer",
|
|
1043
|
-
content: promptCacheBreakpoint == null ? content : [{
|
|
1044
|
-
type: "text",
|
|
1045
|
-
text: content,
|
|
1046
|
-
prompt_cache_breakpoint: promptCacheBreakpoint
|
|
1047
|
-
}]
|
|
1048
|
-
});
|
|
1049
|
-
break;
|
|
1050
|
-
}
|
|
1051
|
-
case "remove":
|
|
1052
|
-
warnings.push({
|
|
1053
|
-
type: "other",
|
|
1054
|
-
message: "system messages are removed for this model"
|
|
1055
|
-
});
|
|
1056
|
-
break;
|
|
1057
|
-
default: throw new Error(`Unsupported system message mode: ${systemMessageMode}`);
|
|
1058
|
-
}
|
|
1059
|
-
break;
|
|
1060
|
-
case "user":
|
|
1061
|
-
if (content.length === 1 && content[0].type === "text" && getPromptCacheBreakpoint$1(content[0].providerOptions) == null) {
|
|
1062
|
-
messages.push({
|
|
1063
|
-
role: "user",
|
|
1064
|
-
content: content[0].text
|
|
1065
|
-
});
|
|
1066
|
-
break;
|
|
1067
|
-
}
|
|
1068
|
-
messages.push({
|
|
1069
|
-
role: "user",
|
|
1070
|
-
content: content.map((part, index) => {
|
|
1071
|
-
switch (part.type) {
|
|
1072
|
-
case "text": {
|
|
1073
|
-
const promptCacheBreakpoint = getPromptCacheBreakpoint$1(part.providerOptions);
|
|
1074
|
-
return {
|
|
1075
|
-
type: "text",
|
|
1076
|
-
text: part.text,
|
|
1077
|
-
...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint }
|
|
1078
|
-
};
|
|
1079
|
-
}
|
|
1080
|
-
case "file": {
|
|
1081
|
-
const promptCacheBreakpoint = getPromptCacheBreakpoint$1(part.providerOptions);
|
|
1082
|
-
switch (part.data.type) {
|
|
1083
|
-
case "reference": return {
|
|
1084
|
-
type: "file",
|
|
1085
|
-
file: { file_id: resolveProviderReference({
|
|
1086
|
-
reference: part.data.reference,
|
|
1087
|
-
provider: "openai"
|
|
1088
|
-
}) },
|
|
1089
|
-
...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint }
|
|
1090
|
-
};
|
|
1091
|
-
case "text": throw new UnsupportedFunctionalityError({ functionality: "text file parts" });
|
|
1092
|
-
case "url":
|
|
1093
|
-
case "data": {
|
|
1094
|
-
const topLevel = getTopLevelMediaType(part.mediaType);
|
|
1095
|
-
if (topLevel === "image") return {
|
|
1096
|
-
type: "image_url",
|
|
1097
|
-
image_url: {
|
|
1098
|
-
url: part.data.type === "url" ? part.data.url.toString() : `data:${resolveFullMediaType({ part })};base64,${convertToBase64(part.data.data)}`,
|
|
1099
|
-
detail: part.providerOptions?.openai?.imageDetail
|
|
1100
|
-
},
|
|
1101
|
-
...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint }
|
|
1102
|
-
};
|
|
1103
|
-
else if (topLevel === "audio") {
|
|
1104
|
-
if (part.data.type === "url") throw new UnsupportedFunctionalityError({ functionality: "audio file parts with URLs" });
|
|
1105
|
-
const fullMediaType = resolveFullMediaType({ part });
|
|
1106
|
-
switch (fullMediaType) {
|
|
1107
|
-
case "audio/wav": return {
|
|
1108
|
-
type: "input_audio",
|
|
1109
|
-
input_audio: {
|
|
1110
|
-
data: convertToBase64(part.data.data),
|
|
1111
|
-
format: "wav"
|
|
1112
|
-
},
|
|
1113
|
-
...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint }
|
|
1114
|
-
};
|
|
1115
|
-
case "audio/mp3":
|
|
1116
|
-
case "audio/mpeg": return {
|
|
1117
|
-
type: "input_audio",
|
|
1118
|
-
input_audio: {
|
|
1119
|
-
data: convertToBase64(part.data.data),
|
|
1120
|
-
format: "mp3"
|
|
1121
|
-
},
|
|
1122
|
-
...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint }
|
|
1123
|
-
};
|
|
1124
|
-
default: throw new UnsupportedFunctionalityError({ functionality: `audio content parts with media type ${fullMediaType}` });
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
{
|
|
1128
|
-
const fullMediaType = resolveFullMediaType({ part });
|
|
1129
|
-
if (fullMediaType !== "application/pdf") throw new UnsupportedFunctionalityError({ functionality: `file part media type ${fullMediaType}` });
|
|
1130
|
-
if (part.data.type === "url") throw new UnsupportedFunctionalityError({ functionality: "PDF file parts with URLs" });
|
|
1131
|
-
return {
|
|
1132
|
-
type: "file",
|
|
1133
|
-
file: {
|
|
1134
|
-
filename: part.filename ?? `part-${index}.pdf`,
|
|
1135
|
-
file_data: `data:application/pdf;base64,${convertToBase64(part.data.data)}`
|
|
1136
|
-
},
|
|
1137
|
-
...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint }
|
|
1138
|
-
};
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
})
|
|
1145
|
-
});
|
|
1146
|
-
break;
|
|
1147
|
-
case "assistant": {
|
|
1148
|
-
let text = "";
|
|
1149
|
-
const textParts = [];
|
|
1150
|
-
let hasPromptCacheBreakpoint = false;
|
|
1151
|
-
const toolCalls = [];
|
|
1152
|
-
for (const part of content) switch (part.type) {
|
|
1153
|
-
case "text": {
|
|
1154
|
-
const promptCacheBreakpoint = getPromptCacheBreakpoint$1(part.providerOptions);
|
|
1155
|
-
text += part.text;
|
|
1156
|
-
textParts.push({
|
|
1157
|
-
type: "text",
|
|
1158
|
-
text: part.text,
|
|
1159
|
-
...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint }
|
|
1160
|
-
});
|
|
1161
|
-
hasPromptCacheBreakpoint ||= promptCacheBreakpoint != null;
|
|
1162
|
-
break;
|
|
1163
|
-
}
|
|
1164
|
-
case "tool-call": toolCalls.push({
|
|
1165
|
-
id: part.toolCallId,
|
|
1166
|
-
type: "function",
|
|
1167
|
-
function: {
|
|
1168
|
-
name: part.toolName,
|
|
1169
|
-
arguments: serializeToolCallArguments$1(part.input)
|
|
1170
|
-
}
|
|
1171
|
-
});
|
|
1172
|
-
}
|
|
1173
|
-
messages.push({
|
|
1174
|
-
role: "assistant",
|
|
1175
|
-
content: hasPromptCacheBreakpoint ? textParts : toolCalls.length > 0 ? text || null : text,
|
|
1176
|
-
tool_calls: toolCalls.length > 0 ? toolCalls : void 0
|
|
1177
|
-
});
|
|
1178
|
-
break;
|
|
1179
|
-
}
|
|
1180
|
-
case "tool":
|
|
1181
|
-
for (const toolResponse of content) {
|
|
1182
|
-
if (toolResponse.type === "tool-approval-response") continue;
|
|
1183
|
-
const output = toolResponse.output;
|
|
1184
|
-
const promptCacheBreakpoint = (output.type === "content" ? output.value.map((part) => getPromptCacheBreakpoint$1(part.providerOptions)).find((breakpoint) => breakpoint != null) : getPromptCacheBreakpoint$1(output.providerOptions)) ?? getPromptCacheBreakpoint$1(toolResponse.providerOptions);
|
|
1185
|
-
let contentValue;
|
|
1186
|
-
switch (output.type) {
|
|
1187
|
-
case "text":
|
|
1188
|
-
contentValue = output.value;
|
|
1189
|
-
break;
|
|
1190
|
-
case "error-text":
|
|
1191
|
-
case "error-json":
|
|
1192
|
-
contentValue = stringifyWithBigIntAndCycles({ error: output.value });
|
|
1193
|
-
break;
|
|
1194
|
-
case "execution-denied":
|
|
1195
|
-
contentValue = output.reason ?? "Tool call execution denied.";
|
|
1196
|
-
break;
|
|
1197
|
-
case "content":
|
|
1198
|
-
case "json": contentValue = stringifyWithBigIntAndCycles(output.value);
|
|
1199
|
-
}
|
|
1200
|
-
messages.push({
|
|
1201
|
-
role: "tool",
|
|
1202
|
-
tool_call_id: toolResponse.toolCallId,
|
|
1203
|
-
content: promptCacheBreakpoint == null ? contentValue : [{
|
|
1204
|
-
type: "text",
|
|
1205
|
-
text: contentValue,
|
|
1206
|
-
prompt_cache_breakpoint: promptCacheBreakpoint
|
|
1207
|
-
}]
|
|
1208
|
-
});
|
|
1209
|
-
}
|
|
1210
|
-
break;
|
|
1211
|
-
default: throw new Error(`Unsupported role: ${role}`);
|
|
1212
|
-
}
|
|
1213
|
-
return {
|
|
1214
|
-
messages,
|
|
1215
|
-
warnings
|
|
1216
|
-
};
|
|
1217
|
-
}
|
|
1218
|
-
//#endregion
|
|
1219
|
-
//#region src/chat/get-response-metadata.ts
|
|
1220
|
-
function getResponseMetadata$1({ id, model, created }) {
|
|
1221
|
-
return createLanguageModelResponseMetadata({
|
|
1222
|
-
id,
|
|
1223
|
-
model,
|
|
1224
|
-
created: created || void 0
|
|
1225
|
-
});
|
|
1226
|
-
}
|
|
1227
|
-
//#endregion
|
|
1228
|
-
//#region src/chat/map-openai-finish-reason.ts
|
|
1229
|
-
function mapOpenAIFinishReason$1(finishReason) {
|
|
1230
|
-
switch (finishReason) {
|
|
1231
|
-
case "stop": return "stop";
|
|
1232
|
-
case "length": return "length";
|
|
1233
|
-
case "content_filter": return "content-filter";
|
|
1234
|
-
case "function_call":
|
|
1235
|
-
case "tool_calls": return "tool-calls";
|
|
1236
|
-
default: return "other";
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
//#endregion
|
|
1240
|
-
//#region src/chat/openai-chat-api.ts
|
|
1241
|
-
const openaiChatResponseSchema = lazySchema(() => zodSchema(z.object({
|
|
1242
|
-
id: z.string().nullish(),
|
|
1243
|
-
created: z.number().nullish(),
|
|
1244
|
-
model: z.string().nullish(),
|
|
1245
|
-
choices: z.array(z.object({
|
|
1246
|
-
message: z.object({
|
|
1247
|
-
role: z.literal("assistant").nullish(),
|
|
1248
|
-
content: z.string().nullish(),
|
|
1249
|
-
audio: z.object({ transcript: z.string().nullish() }).nullish(),
|
|
1250
|
-
tool_calls: z.array(z.object({
|
|
1251
|
-
id: z.string().nullish(),
|
|
1252
|
-
type: z.literal("function"),
|
|
1253
|
-
function: z.object({
|
|
1254
|
-
name: z.string(),
|
|
1255
|
-
arguments: z.string()
|
|
1256
|
-
})
|
|
1257
|
-
})).nullish(),
|
|
1258
|
-
annotations: z.array(z.object({
|
|
1259
|
-
type: z.literal("url_citation"),
|
|
1260
|
-
url_citation: z.object({
|
|
1261
|
-
start_index: z.number(),
|
|
1262
|
-
end_index: z.number(),
|
|
1263
|
-
url: z.string(),
|
|
1264
|
-
title: z.string()
|
|
1265
|
-
})
|
|
1266
|
-
})).nullish()
|
|
1267
|
-
}),
|
|
1268
|
-
index: z.number(),
|
|
1269
|
-
logprobs: z.object({ content: z.array(z.object({
|
|
1270
|
-
token: z.string(),
|
|
1271
|
-
logprob: z.number(),
|
|
1272
|
-
top_logprobs: z.array(z.object({
|
|
1273
|
-
token: z.string(),
|
|
1274
|
-
logprob: z.number()
|
|
1275
|
-
}))
|
|
1276
|
-
})).nullish() }).nullish(),
|
|
1277
|
-
finish_reason: z.string().nullish()
|
|
1278
|
-
})),
|
|
1279
|
-
usage: z.object({
|
|
1280
|
-
prompt_tokens: z.number().nullish(),
|
|
1281
|
-
completion_tokens: z.number().nullish(),
|
|
1282
|
-
total_tokens: z.number().nullish(),
|
|
1283
|
-
prompt_tokens_details: z.object({
|
|
1284
|
-
cached_tokens: z.number().nullish(),
|
|
1285
|
-
cache_write_tokens: z.number().nullish()
|
|
1286
|
-
}).nullish(),
|
|
1287
|
-
completion_tokens_details: z.object({
|
|
1288
|
-
reasoning_tokens: z.number().nullish(),
|
|
1289
|
-
accepted_prediction_tokens: z.number().nullish(),
|
|
1290
|
-
rejected_prediction_tokens: z.number().nullish()
|
|
1291
|
-
}).nullish()
|
|
1292
|
-
}).nullish()
|
|
1293
|
-
})));
|
|
1294
|
-
const openaiChatChunkSchema = lazySchema(() => zodSchema(z.union([z.object({
|
|
1295
|
-
id: z.string().nullish(),
|
|
1296
|
-
created: z.number().nullish(),
|
|
1297
|
-
model: z.string().nullish(),
|
|
1298
|
-
choices: z.array(z.object({
|
|
1299
|
-
delta: z.object({
|
|
1300
|
-
role: z.enum(["assistant"]).nullish(),
|
|
1301
|
-
content: z.string().nullish(),
|
|
1302
|
-
tool_calls: z.array(z.object({
|
|
1303
|
-
index: z.number(),
|
|
1304
|
-
id: z.string().nullish(),
|
|
1305
|
-
type: z.literal("function").nullish(),
|
|
1306
|
-
function: z.object({
|
|
1307
|
-
name: z.string().nullish(),
|
|
1308
|
-
arguments: z.string().nullish()
|
|
1309
|
-
})
|
|
1310
|
-
})).nullish(),
|
|
1311
|
-
annotations: z.array(z.object({
|
|
1312
|
-
type: z.literal("url_citation"),
|
|
1313
|
-
url_citation: z.object({
|
|
1314
|
-
start_index: z.number(),
|
|
1315
|
-
end_index: z.number(),
|
|
1316
|
-
url: z.string(),
|
|
1317
|
-
title: z.string()
|
|
1318
|
-
})
|
|
1319
|
-
})).nullish()
|
|
1320
|
-
}).nullish(),
|
|
1321
|
-
logprobs: z.object({ content: z.array(z.object({
|
|
1322
|
-
token: z.string(),
|
|
1323
|
-
logprob: z.number(),
|
|
1324
|
-
top_logprobs: z.array(z.object({
|
|
1325
|
-
token: z.string(),
|
|
1326
|
-
logprob: z.number()
|
|
1327
|
-
}))
|
|
1328
|
-
})).nullish() }).nullish(),
|
|
1329
|
-
finish_reason: z.string().nullish(),
|
|
1330
|
-
index: z.number()
|
|
1331
|
-
})),
|
|
1332
|
-
usage: z.object({
|
|
1333
|
-
prompt_tokens: z.number().nullish(),
|
|
1334
|
-
completion_tokens: z.number().nullish(),
|
|
1335
|
-
total_tokens: z.number().nullish(),
|
|
1336
|
-
prompt_tokens_details: z.object({
|
|
1337
|
-
cached_tokens: z.number().nullish(),
|
|
1338
|
-
cache_write_tokens: z.number().nullish()
|
|
1339
|
-
}).nullish(),
|
|
1340
|
-
completion_tokens_details: z.object({
|
|
1341
|
-
reasoning_tokens: z.number().nullish(),
|
|
1342
|
-
accepted_prediction_tokens: z.number().nullish(),
|
|
1343
|
-
rejected_prediction_tokens: z.number().nullish()
|
|
1344
|
-
}).nullish()
|
|
1345
|
-
}).nullish()
|
|
1346
|
-
}), openaiErrorDataSchema()])));
|
|
1347
|
-
//#endregion
|
|
1348
1009
|
//#region src/chat/openai-chat-language-model-options.ts
|
|
1349
1010
|
const openaiLanguageModelChatOptions = lazySchema(() => zodSchema(z.object({
|
|
1350
1011
|
/**
|
|
@@ -1493,6 +1154,388 @@ const openaiLanguageModelChatOptions = lazySchema(() => zodSchema(z.object({
|
|
|
1493
1154
|
*/
|
|
1494
1155
|
forceReasoning: z.boolean().optional()
|
|
1495
1156
|
})));
|
|
1157
|
+
const openaiChatMessageProviderOptions = lazySchema(() => zodSchema(z.object({
|
|
1158
|
+
/** The participant name on a system, developer, user, or assistant message. */
|
|
1159
|
+
name: z.string().optional() })));
|
|
1160
|
+
//#endregion
|
|
1161
|
+
//#region src/chat/convert-to-openai-chat-messages.ts
|
|
1162
|
+
function serializeToolCallArguments$1(input) {
|
|
1163
|
+
if (typeof input === "string") try {
|
|
1164
|
+
const parsed = secureJsonParse(input);
|
|
1165
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return "{}";
|
|
1166
|
+
return input;
|
|
1167
|
+
} catch {
|
|
1168
|
+
return "{}";
|
|
1169
|
+
}
|
|
1170
|
+
return stringifyWithBigIntAndCycles(typeof input === "object" && input !== null && !Array.isArray(input) ? input : {});
|
|
1171
|
+
}
|
|
1172
|
+
function getPromptCacheBreakpoint$1(providerOptions) {
|
|
1173
|
+
return providerOptions?.openai?.promptCacheBreakpoint;
|
|
1174
|
+
}
|
|
1175
|
+
async function convertToOpenAIChatMessages({ prompt, systemMessageMode = "system" }) {
|
|
1176
|
+
const messages = [];
|
|
1177
|
+
const warnings = [];
|
|
1178
|
+
for (const { role, content, providerOptions } of prompt) {
|
|
1179
|
+
const name = (await parseProviderOptions({
|
|
1180
|
+
provider: "openai",
|
|
1181
|
+
providerOptions,
|
|
1182
|
+
schema: openaiChatMessageProviderOptions
|
|
1183
|
+
}))?.name;
|
|
1184
|
+
switch (role) {
|
|
1185
|
+
case "system":
|
|
1186
|
+
switch (systemMessageMode) {
|
|
1187
|
+
case "system": {
|
|
1188
|
+
const promptCacheBreakpoint = getPromptCacheBreakpoint$1(providerOptions);
|
|
1189
|
+
messages.push({
|
|
1190
|
+
role: "system",
|
|
1191
|
+
...name != null && { name },
|
|
1192
|
+
content: promptCacheBreakpoint == null ? content : [{
|
|
1193
|
+
type: "text",
|
|
1194
|
+
text: content,
|
|
1195
|
+
prompt_cache_breakpoint: promptCacheBreakpoint
|
|
1196
|
+
}]
|
|
1197
|
+
});
|
|
1198
|
+
break;
|
|
1199
|
+
}
|
|
1200
|
+
case "developer": {
|
|
1201
|
+
const promptCacheBreakpoint = getPromptCacheBreakpoint$1(providerOptions);
|
|
1202
|
+
messages.push({
|
|
1203
|
+
role: "developer",
|
|
1204
|
+
...name != null && { name },
|
|
1205
|
+
content: promptCacheBreakpoint == null ? content : [{
|
|
1206
|
+
type: "text",
|
|
1207
|
+
text: content,
|
|
1208
|
+
prompt_cache_breakpoint: promptCacheBreakpoint
|
|
1209
|
+
}]
|
|
1210
|
+
});
|
|
1211
|
+
break;
|
|
1212
|
+
}
|
|
1213
|
+
case "remove":
|
|
1214
|
+
warnings.push({
|
|
1215
|
+
type: "other",
|
|
1216
|
+
message: "system messages are removed for this model"
|
|
1217
|
+
});
|
|
1218
|
+
break;
|
|
1219
|
+
default: throw new Error(`Unsupported system message mode: ${systemMessageMode}`);
|
|
1220
|
+
}
|
|
1221
|
+
break;
|
|
1222
|
+
case "user":
|
|
1223
|
+
if (content.length === 1 && content[0].type === "text" && getPromptCacheBreakpoint$1(content[0].providerOptions) == null) {
|
|
1224
|
+
messages.push({
|
|
1225
|
+
role: "user",
|
|
1226
|
+
content: content[0].text,
|
|
1227
|
+
...name != null && { name }
|
|
1228
|
+
});
|
|
1229
|
+
break;
|
|
1230
|
+
}
|
|
1231
|
+
messages.push({
|
|
1232
|
+
role: "user",
|
|
1233
|
+
...name != null && { name },
|
|
1234
|
+
content: content.map((part, index) => {
|
|
1235
|
+
switch (part.type) {
|
|
1236
|
+
case "text": {
|
|
1237
|
+
const promptCacheBreakpoint = getPromptCacheBreakpoint$1(part.providerOptions);
|
|
1238
|
+
return {
|
|
1239
|
+
type: "text",
|
|
1240
|
+
text: part.text,
|
|
1241
|
+
...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint }
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1244
|
+
case "file": {
|
|
1245
|
+
const promptCacheBreakpoint = getPromptCacheBreakpoint$1(part.providerOptions);
|
|
1246
|
+
switch (part.data.type) {
|
|
1247
|
+
case "reference": return {
|
|
1248
|
+
type: "file",
|
|
1249
|
+
file: { file_id: resolveProviderReference({
|
|
1250
|
+
reference: part.data.reference,
|
|
1251
|
+
provider: "openai"
|
|
1252
|
+
}) },
|
|
1253
|
+
...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint }
|
|
1254
|
+
};
|
|
1255
|
+
case "text": throw new UnsupportedFunctionalityError({ functionality: "text file parts" });
|
|
1256
|
+
case "url":
|
|
1257
|
+
case "data": {
|
|
1258
|
+
const topLevel = getTopLevelMediaType(part.mediaType);
|
|
1259
|
+
if (topLevel === "image") return {
|
|
1260
|
+
type: "image_url",
|
|
1261
|
+
image_url: {
|
|
1262
|
+
url: part.data.type === "url" ? part.data.url.toString() : `data:${resolveFullMediaType({ part })};base64,${convertToBase64(part.data.data)}`,
|
|
1263
|
+
detail: part.providerOptions?.openai?.imageDetail
|
|
1264
|
+
},
|
|
1265
|
+
...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint }
|
|
1266
|
+
};
|
|
1267
|
+
else if (topLevel === "audio") {
|
|
1268
|
+
if (part.data.type === "url") throw new UnsupportedFunctionalityError({ functionality: "audio file parts with URLs" });
|
|
1269
|
+
const fullMediaType = resolveFullMediaType({ part });
|
|
1270
|
+
switch (fullMediaType) {
|
|
1271
|
+
case "audio/wav": return {
|
|
1272
|
+
type: "input_audio",
|
|
1273
|
+
input_audio: {
|
|
1274
|
+
data: convertToBase64(part.data.data),
|
|
1275
|
+
format: "wav"
|
|
1276
|
+
},
|
|
1277
|
+
...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint }
|
|
1278
|
+
};
|
|
1279
|
+
case "audio/mp3":
|
|
1280
|
+
case "audio/mpeg": return {
|
|
1281
|
+
type: "input_audio",
|
|
1282
|
+
input_audio: {
|
|
1283
|
+
data: convertToBase64(part.data.data),
|
|
1284
|
+
format: "mp3"
|
|
1285
|
+
},
|
|
1286
|
+
...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint }
|
|
1287
|
+
};
|
|
1288
|
+
default: throw new UnsupportedFunctionalityError({ functionality: `audio content parts with media type ${fullMediaType}` });
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
{
|
|
1292
|
+
const fullMediaType = resolveFullMediaType({ part });
|
|
1293
|
+
if (fullMediaType !== "application/pdf") throw new UnsupportedFunctionalityError({ functionality: `file part media type ${fullMediaType}` });
|
|
1294
|
+
if (part.data.type === "url") throw new UnsupportedFunctionalityError({ functionality: "PDF file parts with URLs" });
|
|
1295
|
+
return {
|
|
1296
|
+
type: "file",
|
|
1297
|
+
file: {
|
|
1298
|
+
filename: part.filename ?? `part-${index}.pdf`,
|
|
1299
|
+
file_data: `data:application/pdf;base64,${convertToBase64(part.data.data)}`
|
|
1300
|
+
},
|
|
1301
|
+
...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint }
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
})
|
|
1309
|
+
});
|
|
1310
|
+
break;
|
|
1311
|
+
case "assistant": {
|
|
1312
|
+
let text = "";
|
|
1313
|
+
const textParts = [];
|
|
1314
|
+
let hasPromptCacheBreakpoint = false;
|
|
1315
|
+
const toolCalls = [];
|
|
1316
|
+
for (const part of content) switch (part.type) {
|
|
1317
|
+
case "text": {
|
|
1318
|
+
const promptCacheBreakpoint = getPromptCacheBreakpoint$1(part.providerOptions);
|
|
1319
|
+
text += part.text;
|
|
1320
|
+
textParts.push({
|
|
1321
|
+
type: "text",
|
|
1322
|
+
text: part.text,
|
|
1323
|
+
...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint }
|
|
1324
|
+
});
|
|
1325
|
+
hasPromptCacheBreakpoint ||= promptCacheBreakpoint != null;
|
|
1326
|
+
break;
|
|
1327
|
+
}
|
|
1328
|
+
case "tool-call": toolCalls.push({
|
|
1329
|
+
id: part.toolCallId,
|
|
1330
|
+
type: "function",
|
|
1331
|
+
function: {
|
|
1332
|
+
name: part.toolName,
|
|
1333
|
+
arguments: serializeToolCallArguments$1(part.input)
|
|
1334
|
+
}
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
messages.push({
|
|
1338
|
+
role: "assistant",
|
|
1339
|
+
...name != null && { name },
|
|
1340
|
+
content: hasPromptCacheBreakpoint ? textParts : toolCalls.length > 0 ? text || null : text,
|
|
1341
|
+
tool_calls: toolCalls.length > 0 ? toolCalls : void 0
|
|
1342
|
+
});
|
|
1343
|
+
break;
|
|
1344
|
+
}
|
|
1345
|
+
case "tool":
|
|
1346
|
+
if (name != null) warnings.push({
|
|
1347
|
+
type: "unsupported",
|
|
1348
|
+
feature: "message name on tool messages"
|
|
1349
|
+
});
|
|
1350
|
+
for (const toolResponse of content) {
|
|
1351
|
+
if (toolResponse.type === "tool-approval-response") continue;
|
|
1352
|
+
const output = toolResponse.output;
|
|
1353
|
+
const promptCacheBreakpoint = (output.type === "content" ? output.value.map((part) => getPromptCacheBreakpoint$1(part.providerOptions)).find((breakpoint) => breakpoint != null) : getPromptCacheBreakpoint$1(output.providerOptions)) ?? getPromptCacheBreakpoint$1(toolResponse.providerOptions);
|
|
1354
|
+
let contentValue;
|
|
1355
|
+
switch (output.type) {
|
|
1356
|
+
case "text":
|
|
1357
|
+
contentValue = output.value;
|
|
1358
|
+
break;
|
|
1359
|
+
case "error-text":
|
|
1360
|
+
case "error-json":
|
|
1361
|
+
contentValue = stringifyWithBigIntAndCycles({ error: output.value });
|
|
1362
|
+
break;
|
|
1363
|
+
case "execution-denied":
|
|
1364
|
+
contentValue = output.reason ?? "Tool call execution denied.";
|
|
1365
|
+
break;
|
|
1366
|
+
case "content":
|
|
1367
|
+
case "json": contentValue = stringifyWithBigIntAndCycles(output.value);
|
|
1368
|
+
}
|
|
1369
|
+
messages.push({
|
|
1370
|
+
role: "tool",
|
|
1371
|
+
tool_call_id: toolResponse.toolCallId,
|
|
1372
|
+
content: promptCacheBreakpoint == null ? contentValue : [{
|
|
1373
|
+
type: "text",
|
|
1374
|
+
text: contentValue,
|
|
1375
|
+
prompt_cache_breakpoint: promptCacheBreakpoint
|
|
1376
|
+
}]
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
break;
|
|
1380
|
+
default: throw new Error(`Unsupported role: ${role}`);
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
return {
|
|
1384
|
+
messages,
|
|
1385
|
+
warnings
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
//#endregion
|
|
1389
|
+
//#region src/chat/get-response-metadata.ts
|
|
1390
|
+
function getResponseMetadata$1({ id, model, created }) {
|
|
1391
|
+
return createLanguageModelResponseMetadata({
|
|
1392
|
+
id,
|
|
1393
|
+
model,
|
|
1394
|
+
created: created || void 0
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
//#endregion
|
|
1398
|
+
//#region src/chat/map-openai-finish-reason.ts
|
|
1399
|
+
function mapOpenAIFinishReason$1({ finishReason, hasRefusal = false }) {
|
|
1400
|
+
switch (finishReason) {
|
|
1401
|
+
case "stop": return hasRefusal ? "content-filter" : "stop";
|
|
1402
|
+
case "length": return "length";
|
|
1403
|
+
case "content_filter": return "content-filter";
|
|
1404
|
+
case "function_call":
|
|
1405
|
+
case "tool_calls": return "tool-calls";
|
|
1406
|
+
default: return "other";
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
//#endregion
|
|
1410
|
+
//#region src/chat/openai-chat-api.ts
|
|
1411
|
+
const openaiChatResponseSchema = lazySchema(() => zodSchema(z.object({
|
|
1412
|
+
id: z.string().nullish(),
|
|
1413
|
+
created: z.number().nullish(),
|
|
1414
|
+
model: z.string().nullish(),
|
|
1415
|
+
choices: z.array(z.object({
|
|
1416
|
+
message: z.object({
|
|
1417
|
+
role: z.literal("assistant").nullish(),
|
|
1418
|
+
content: z.string().nullish(),
|
|
1419
|
+
refusal: z.string().nullish(),
|
|
1420
|
+
audio: z.object({ transcript: z.string().nullish() }).nullish(),
|
|
1421
|
+
tool_calls: z.array(z.object({
|
|
1422
|
+
id: z.string().nullish(),
|
|
1423
|
+
type: z.literal("function"),
|
|
1424
|
+
function: z.object({
|
|
1425
|
+
name: z.string(),
|
|
1426
|
+
arguments: z.string()
|
|
1427
|
+
})
|
|
1428
|
+
})).nullish(),
|
|
1429
|
+
annotations: z.array(z.object({
|
|
1430
|
+
type: z.literal("url_citation"),
|
|
1431
|
+
url_citation: z.object({
|
|
1432
|
+
start_index: z.number(),
|
|
1433
|
+
end_index: z.number(),
|
|
1434
|
+
url: z.string(),
|
|
1435
|
+
title: z.string()
|
|
1436
|
+
})
|
|
1437
|
+
})).nullish()
|
|
1438
|
+
}),
|
|
1439
|
+
index: z.number(),
|
|
1440
|
+
logprobs: z.object({
|
|
1441
|
+
content: z.array(z.object({
|
|
1442
|
+
token: z.string(),
|
|
1443
|
+
logprob: z.number(),
|
|
1444
|
+
top_logprobs: z.array(z.object({
|
|
1445
|
+
token: z.string(),
|
|
1446
|
+
logprob: z.number()
|
|
1447
|
+
}))
|
|
1448
|
+
})).nullish(),
|
|
1449
|
+
refusal: z.array(z.object({
|
|
1450
|
+
token: z.string(),
|
|
1451
|
+
logprob: z.number(),
|
|
1452
|
+
top_logprobs: z.array(z.object({
|
|
1453
|
+
token: z.string(),
|
|
1454
|
+
logprob: z.number()
|
|
1455
|
+
}))
|
|
1456
|
+
})).nullish()
|
|
1457
|
+
}).nullish(),
|
|
1458
|
+
finish_reason: z.string().nullish()
|
|
1459
|
+
})),
|
|
1460
|
+
usage: z.object({
|
|
1461
|
+
prompt_tokens: z.number().nullish(),
|
|
1462
|
+
completion_tokens: z.number().nullish(),
|
|
1463
|
+
total_tokens: z.number().nullish(),
|
|
1464
|
+
prompt_tokens_details: z.object({
|
|
1465
|
+
cached_tokens: z.number().nullish(),
|
|
1466
|
+
cache_write_tokens: z.number().nullish()
|
|
1467
|
+
}).nullish(),
|
|
1468
|
+
completion_tokens_details: z.object({
|
|
1469
|
+
reasoning_tokens: z.number().nullish(),
|
|
1470
|
+
accepted_prediction_tokens: z.number().nullish(),
|
|
1471
|
+
rejected_prediction_tokens: z.number().nullish()
|
|
1472
|
+
}).nullish()
|
|
1473
|
+
}).nullish()
|
|
1474
|
+
})));
|
|
1475
|
+
const openaiChatChunkSchema = lazySchema(() => zodSchema(z.union([z.object({
|
|
1476
|
+
id: z.string().nullish(),
|
|
1477
|
+
created: z.number().nullish(),
|
|
1478
|
+
model: z.string().nullish(),
|
|
1479
|
+
choices: z.array(z.object({
|
|
1480
|
+
delta: z.object({
|
|
1481
|
+
role: z.enum(["assistant"]).nullish(),
|
|
1482
|
+
content: z.string().nullish(),
|
|
1483
|
+
refusal: z.string().nullish(),
|
|
1484
|
+
tool_calls: z.array(z.object({
|
|
1485
|
+
index: z.number(),
|
|
1486
|
+
id: z.string().nullish(),
|
|
1487
|
+
type: z.literal("function").nullish(),
|
|
1488
|
+
function: z.object({
|
|
1489
|
+
name: z.string().nullish(),
|
|
1490
|
+
arguments: z.string().nullish()
|
|
1491
|
+
})
|
|
1492
|
+
})).nullish(),
|
|
1493
|
+
annotations: z.array(z.object({
|
|
1494
|
+
type: z.literal("url_citation"),
|
|
1495
|
+
url_citation: z.object({
|
|
1496
|
+
start_index: z.number(),
|
|
1497
|
+
end_index: z.number(),
|
|
1498
|
+
url: z.string(),
|
|
1499
|
+
title: z.string()
|
|
1500
|
+
})
|
|
1501
|
+
})).nullish()
|
|
1502
|
+
}).nullish(),
|
|
1503
|
+
logprobs: z.object({
|
|
1504
|
+
content: z.array(z.object({
|
|
1505
|
+
token: z.string(),
|
|
1506
|
+
logprob: z.number(),
|
|
1507
|
+
top_logprobs: z.array(z.object({
|
|
1508
|
+
token: z.string(),
|
|
1509
|
+
logprob: z.number()
|
|
1510
|
+
}))
|
|
1511
|
+
})).nullish(),
|
|
1512
|
+
refusal: z.array(z.object({
|
|
1513
|
+
token: z.string(),
|
|
1514
|
+
logprob: z.number(),
|
|
1515
|
+
top_logprobs: z.array(z.object({
|
|
1516
|
+
token: z.string(),
|
|
1517
|
+
logprob: z.number()
|
|
1518
|
+
}))
|
|
1519
|
+
})).nullish()
|
|
1520
|
+
}).nullish(),
|
|
1521
|
+
finish_reason: z.string().nullish(),
|
|
1522
|
+
index: z.number()
|
|
1523
|
+
})),
|
|
1524
|
+
usage: z.object({
|
|
1525
|
+
prompt_tokens: z.number().nullish(),
|
|
1526
|
+
completion_tokens: z.number().nullish(),
|
|
1527
|
+
total_tokens: z.number().nullish(),
|
|
1528
|
+
prompt_tokens_details: z.object({
|
|
1529
|
+
cached_tokens: z.number().nullish(),
|
|
1530
|
+
cache_write_tokens: z.number().nullish()
|
|
1531
|
+
}).nullish(),
|
|
1532
|
+
completion_tokens_details: z.object({
|
|
1533
|
+
reasoning_tokens: z.number().nullish(),
|
|
1534
|
+
accepted_prediction_tokens: z.number().nullish(),
|
|
1535
|
+
rejected_prediction_tokens: z.number().nullish()
|
|
1536
|
+
}).nullish()
|
|
1537
|
+
}).nullish()
|
|
1538
|
+
}), openaiErrorDataSchema()])));
|
|
1496
1539
|
//#endregion
|
|
1497
1540
|
//#region src/normalize-openai-json-schema.ts
|
|
1498
1541
|
/**
|
|
@@ -1732,7 +1775,7 @@ var OpenAIChatLanguageModel = class OpenAIChatLanguageModel {
|
|
|
1732
1775
|
feature: "reasoningSummary",
|
|
1733
1776
|
details: "reasoningSummary is only supported by the Responses API, not the Chat Completions API"
|
|
1734
1777
|
});
|
|
1735
|
-
const { messages, warnings: messageWarnings } = convertToOpenAIChatMessages({
|
|
1778
|
+
const { messages, warnings: messageWarnings } = await convertToOpenAIChatMessages({
|
|
1736
1779
|
prompt,
|
|
1737
1780
|
systemMessageMode: openaiOptions.systemMessageMode ?? (isReasoningModel ? "developer" : modelRequestConfig.systemMessageMode)
|
|
1738
1781
|
});
|
|
@@ -1885,11 +1928,12 @@ var OpenAIChatLanguageModel = class OpenAIChatLanguageModel {
|
|
|
1885
1928
|
}
|
|
1886
1929
|
async doGenerate(options) {
|
|
1887
1930
|
const { args: body, warnings } = await this.getArgs(options);
|
|
1931
|
+
const url = this.config.url({
|
|
1932
|
+
path: "/chat/completions",
|
|
1933
|
+
modelId: this.config.requestModelId ?? this.modelId
|
|
1934
|
+
});
|
|
1888
1935
|
const { responseHeaders, value: response, rawValue: rawResponse } = await postJsonToApi({
|
|
1889
|
-
url
|
|
1890
|
-
path: "/chat/completions",
|
|
1891
|
-
modelId: this.config.requestModelId ?? this.modelId
|
|
1892
|
-
}),
|
|
1936
|
+
url,
|
|
1893
1937
|
headers: combineHeaders(await resolve(this.config.headers), options.headers),
|
|
1894
1938
|
body,
|
|
1895
1939
|
failedResponseHandler: openaiFailedResponseHandler,
|
|
@@ -1908,6 +1952,12 @@ var OpenAIChatLanguageModel = class OpenAIChatLanguageModel {
|
|
|
1908
1952
|
type: "text",
|
|
1909
1953
|
text
|
|
1910
1954
|
});
|
|
1955
|
+
const refusal = choice.message.refusal;
|
|
1956
|
+
const hasRefusal = refusal != null && refusal.length > 0;
|
|
1957
|
+
if (hasRefusal) content.push({
|
|
1958
|
+
type: "text",
|
|
1959
|
+
text: refusal
|
|
1960
|
+
});
|
|
1911
1961
|
for (const toolCall of choice.message.tool_calls ?? []) content.push({
|
|
1912
1962
|
type: "tool-call",
|
|
1913
1963
|
toolCallId: toolCall.id || generateId(),
|
|
@@ -1925,15 +1975,23 @@ var OpenAIChatLanguageModel = class OpenAIChatLanguageModel {
|
|
|
1925
1975
|
const providerMetadata = { openai: {} };
|
|
1926
1976
|
if (completionTokenDetails?.accepted_prediction_tokens != null) providerMetadata.openai.acceptedPredictionTokens = completionTokenDetails?.accepted_prediction_tokens;
|
|
1927
1977
|
if (completionTokenDetails?.rejected_prediction_tokens != null) providerMetadata.openai.rejectedPredictionTokens = completionTokenDetails?.rejected_prediction_tokens;
|
|
1928
|
-
|
|
1978
|
+
const contentLogprobs = choice.logprobs?.content;
|
|
1979
|
+
const refusalLogprobs = choice.logprobs?.refusal;
|
|
1980
|
+
if (contentLogprobs != null || refusalLogprobs != null) providerMetadata.openai.logprobs = [...contentLogprobs ?? [], ...refusalLogprobs ?? []];
|
|
1929
1981
|
return {
|
|
1930
1982
|
content,
|
|
1931
1983
|
finishReason: {
|
|
1932
|
-
unified: mapOpenAIFinishReason$1(
|
|
1984
|
+
unified: mapOpenAIFinishReason$1({
|
|
1985
|
+
finishReason: choice.finish_reason,
|
|
1986
|
+
hasRefusal
|
|
1987
|
+
}),
|
|
1933
1988
|
raw: choice.finish_reason ?? void 0
|
|
1934
1989
|
},
|
|
1935
1990
|
usage: convertOpenAIChatUsage(response.usage),
|
|
1936
|
-
request: {
|
|
1991
|
+
request: {
|
|
1992
|
+
body,
|
|
1993
|
+
url
|
|
1994
|
+
},
|
|
1937
1995
|
response: {
|
|
1938
1996
|
...getResponseMetadata$1(response),
|
|
1939
1997
|
headers: responseHeaders,
|
|
@@ -1979,6 +2037,10 @@ var OpenAIChatLanguageModel = class OpenAIChatLanguageModel {
|
|
|
1979
2037
|
let usage = void 0;
|
|
1980
2038
|
let metadataExtracted = false;
|
|
1981
2039
|
let isActiveText = false;
|
|
2040
|
+
let hasRefusal = false;
|
|
2041
|
+
let rawFinishReason = void 0;
|
|
2042
|
+
let hasLogprobs = false;
|
|
2043
|
+
const streamedLogprobs = [];
|
|
1982
2044
|
const providerMetadata = { openai: {} };
|
|
1983
2045
|
return {
|
|
1984
2046
|
stream: checkedResponse.pipeThrough(new TransformStream({
|
|
@@ -2002,6 +2064,7 @@ var OpenAIChatLanguageModel = class OpenAIChatLanguageModel {
|
|
|
2002
2064
|
unified: "error",
|
|
2003
2065
|
raw: void 0
|
|
2004
2066
|
};
|
|
2067
|
+
rawFinishReason = void 0;
|
|
2005
2068
|
controller.enqueue({
|
|
2006
2069
|
type: "error",
|
|
2007
2070
|
error: chunk.error
|
|
@@ -2014,6 +2077,7 @@ var OpenAIChatLanguageModel = class OpenAIChatLanguageModel {
|
|
|
2014
2077
|
unified: "error",
|
|
2015
2078
|
raw: void 0
|
|
2016
2079
|
};
|
|
2080
|
+
rawFinishReason = void 0;
|
|
2017
2081
|
controller.enqueue({
|
|
2018
2082
|
type: "error",
|
|
2019
2083
|
error: createOpenAIProviderStreamError(value.error) ?? value.error
|
|
@@ -2036,14 +2100,25 @@ var OpenAIChatLanguageModel = class OpenAIChatLanguageModel {
|
|
|
2036
2100
|
if (value.usage.completion_tokens_details?.rejected_prediction_tokens != null) providerMetadata.openai.rejectedPredictionTokens = value.usage.completion_tokens_details?.rejected_prediction_tokens;
|
|
2037
2101
|
}
|
|
2038
2102
|
const choice = value.choices[0];
|
|
2039
|
-
if (choice?.finish_reason != null)
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2103
|
+
if (choice?.finish_reason != null) rawFinishReason = choice.finish_reason;
|
|
2104
|
+
if (choice?.logprobs != null) {
|
|
2105
|
+
const contentLogprobs = choice.logprobs.content;
|
|
2106
|
+
const refusalLogprobs = choice.logprobs.refusal;
|
|
2107
|
+
if (contentLogprobs != null || refusalLogprobs != null) {
|
|
2108
|
+
hasLogprobs = true;
|
|
2109
|
+
streamedLogprobs.push(...contentLogprobs ?? [], ...refusalLogprobs ?? []);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2044
2112
|
if (choice?.delta == null) return;
|
|
2045
2113
|
const delta = choice.delta;
|
|
2046
|
-
|
|
2114
|
+
const textDeltas = [];
|
|
2115
|
+
if (delta.content != null && delta.content.length > 0) textDeltas.push(delta.content);
|
|
2116
|
+
if (delta.refusal != null && delta.refusal.length > 0) {
|
|
2117
|
+
hasRefusal = true;
|
|
2118
|
+
textDeltas.push(delta.refusal);
|
|
2119
|
+
}
|
|
2120
|
+
if (textDeltas.length === 0 && delta.content === "") textDeltas.push(delta.content);
|
|
2121
|
+
for (const textDelta of textDeltas) {
|
|
2047
2122
|
if (!isActiveText) {
|
|
2048
2123
|
controller.enqueue({
|
|
2049
2124
|
type: "text-start",
|
|
@@ -2054,7 +2129,7 @@ var OpenAIChatLanguageModel = class OpenAIChatLanguageModel {
|
|
|
2054
2129
|
controller.enqueue({
|
|
2055
2130
|
type: "text-delta",
|
|
2056
2131
|
id: "0",
|
|
2057
|
-
delta:
|
|
2132
|
+
delta: textDelta
|
|
2058
2133
|
});
|
|
2059
2134
|
}
|
|
2060
2135
|
if (delta.tool_calls != null) for (const toolCallDelta of delta.tool_calls) toolCallTracker.processDelta(toolCallDelta);
|
|
@@ -2072,6 +2147,14 @@ var OpenAIChatLanguageModel = class OpenAIChatLanguageModel {
|
|
|
2072
2147
|
id: "0"
|
|
2073
2148
|
});
|
|
2074
2149
|
toolCallTracker.flush();
|
|
2150
|
+
if (rawFinishReason != null) finishReason = {
|
|
2151
|
+
unified: mapOpenAIFinishReason$1({
|
|
2152
|
+
finishReason: rawFinishReason,
|
|
2153
|
+
hasRefusal
|
|
2154
|
+
}),
|
|
2155
|
+
raw: rawFinishReason
|
|
2156
|
+
};
|
|
2157
|
+
if (hasLogprobs) providerMetadata.openai.logprobs = streamedLogprobs;
|
|
2075
2158
|
controller.enqueue({
|
|
2076
2159
|
type: "finish",
|
|
2077
2160
|
finishReason,
|
|
@@ -2080,7 +2163,10 @@ var OpenAIChatLanguageModel = class OpenAIChatLanguageModel {
|
|
|
2080
2163
|
});
|
|
2081
2164
|
}
|
|
2082
2165
|
})),
|
|
2083
|
-
request: {
|
|
2166
|
+
request: {
|
|
2167
|
+
body,
|
|
2168
|
+
url
|
|
2169
|
+
},
|
|
2084
2170
|
response: { headers: responseHeaders }
|
|
2085
2171
|
};
|
|
2086
2172
|
}
|
|
@@ -2089,7 +2175,7 @@ function isOpenAIChatOutputChunk(chunk) {
|
|
|
2089
2175
|
if ("error" in chunk) return false;
|
|
2090
2176
|
return chunk.choices.some((choice) => {
|
|
2091
2177
|
const delta = choice.delta;
|
|
2092
|
-
return delta?.content != null && delta.content.length > 0 || delta?.tool_calls != null && delta.tool_calls.length > 0 || delta?.annotations != null && delta.annotations.length > 0;
|
|
2178
|
+
return delta?.content != null && delta.content.length > 0 || delta?.refusal != null && delta.refusal.length > 0 || delta?.tool_calls != null && delta.tool_calls.length > 0 || delta?.annotations != null && delta.annotations.length > 0;
|
|
2093
2179
|
});
|
|
2094
2180
|
}
|
|
2095
2181
|
//#endregion
|
|
@@ -2819,6 +2905,15 @@ const baseImageModelOptionsObject = () => z.object({
|
|
|
2819
2905
|
"webp"
|
|
2820
2906
|
]).optional(),
|
|
2821
2907
|
/**
|
|
2908
|
+
* How much detail the model puts into the image. Supported by GPT Image
|
|
2909
|
+
* 2.6 models. The API defaults to `high`.
|
|
2910
|
+
*/
|
|
2911
|
+
complexity: z.enum([
|
|
2912
|
+
"low",
|
|
2913
|
+
"medium",
|
|
2914
|
+
"high"
|
|
2915
|
+
]).optional(),
|
|
2916
|
+
/**
|
|
2822
2917
|
* Compression level (0-100) for the generated image(s). Applies to the
|
|
2823
2918
|
* `jpeg` and `webp` output formats.
|
|
2824
2919
|
*/
|
|
@@ -2827,7 +2922,13 @@ const baseImageModelOptionsObject = () => z.object({
|
|
|
2827
2922
|
* A unique identifier representing your end-user, which can help OpenAI
|
|
2828
2923
|
* to monitor and detect abuse.
|
|
2829
2924
|
*/
|
|
2830
|
-
user: z.string().optional()
|
|
2925
|
+
user: z.string().optional(),
|
|
2926
|
+
/**
|
|
2927
|
+
* A stable identifier used to help detect users of your application that
|
|
2928
|
+
* may be violating OpenAI's usage policies. Should be a hashed username
|
|
2929
|
+
* or email address.
|
|
2930
|
+
*/
|
|
2931
|
+
safetyIdentifier: z.string().max(128).optional()
|
|
2831
2932
|
});
|
|
2832
2933
|
lazySchema(() => zodSchema(baseImageModelOptionsObject()));
|
|
2833
2934
|
const openaiImageModelGenerationOptions = lazySchema(() => zodSchema(baseImageModelOptionsObject().extend({
|
|
@@ -2838,16 +2939,50 @@ const openaiImageModelGenerationOptions = lazySchema(() => zodSchema(baseImageMo
|
|
|
2838
2939
|
*/
|
|
2839
2940
|
style: z.enum(["vivid", "natural"]).optional(),
|
|
2840
2941
|
/**
|
|
2942
|
+
* Format in which the generated image(s) are returned. `gif` produces
|
|
2943
|
+
* an animated GIF and is supported by GPT Image 2.6 models.
|
|
2944
|
+
*/
|
|
2945
|
+
outputFormat: z.enum([
|
|
2946
|
+
"png",
|
|
2947
|
+
"jpeg",
|
|
2948
|
+
"webp",
|
|
2949
|
+
"gif"
|
|
2950
|
+
]).optional(),
|
|
2951
|
+
/**
|
|
2952
|
+
* Number of frames (2-64) of an animated GIF. Only applies to the `gif`
|
|
2953
|
+
* output format. The API defaults to 9.
|
|
2954
|
+
*/
|
|
2955
|
+
frameCount: z.number().int().min(2).max(64).optional(),
|
|
2956
|
+
/**
|
|
2957
|
+
* Duration of each frame in milliseconds (20-2000) of an animated GIF.
|
|
2958
|
+
* The API rounds it to the nearest 10 ms. Only applies to the `gif`
|
|
2959
|
+
* output format. The API defaults to 200.
|
|
2960
|
+
*/
|
|
2961
|
+
frameDurationMs: z.number().int().min(20).max(2e3).optional(),
|
|
2962
|
+
/**
|
|
2841
2963
|
* Content moderation level for the generated image(s). `low` applies
|
|
2842
2964
|
* less restrictive filtering.
|
|
2843
2965
|
*/
|
|
2844
2966
|
moderation: z.enum(["auto", "low"]).optional()
|
|
2845
2967
|
})));
|
|
2846
|
-
const openaiImageModelEditOptions = lazySchema(() => zodSchema(baseImageModelOptionsObject().extend({
|
|
2847
|
-
/**
|
|
2848
|
-
* Fidelity of the output image(s) to the input image(s).
|
|
2849
|
-
*/
|
|
2850
|
-
inputFidelity: z.enum(["high", "low"]).optional()
|
|
2968
|
+
const openaiImageModelEditOptions = lazySchema(() => zodSchema(baseImageModelOptionsObject().extend({
|
|
2969
|
+
/**
|
|
2970
|
+
* Fidelity of the output image(s) to the input image(s).
|
|
2971
|
+
*/
|
|
2972
|
+
inputFidelity: z.enum(["high", "low"]).optional(),
|
|
2973
|
+
/**
|
|
2974
|
+
* A transparent PNG overlaid on the first input image to mark up the
|
|
2975
|
+
* regions to change, as an HTTPS URL or a base64 data URL. It must match
|
|
2976
|
+
* the dimensions of the first image. Supported by GPT Image 2.5 and 2.6
|
|
2977
|
+
* models. Cannot be combined with a `mask`.
|
|
2978
|
+
*/
|
|
2979
|
+
markup: z.string().optional(),
|
|
2980
|
+
/**
|
|
2981
|
+
* Content moderation level for the edited image(s). `low` applies
|
|
2982
|
+
* less restrictive filtering. Supported by GPT Image models.
|
|
2983
|
+
*/
|
|
2984
|
+
moderation: z.enum(["auto", "low"]).optional()
|
|
2985
|
+
})));
|
|
2851
2986
|
//#endregion
|
|
2852
2987
|
//#region src/image/openai-image-model.ts
|
|
2853
2988
|
var OpenAIImageModel = class OpenAIImageModel {
|
|
@@ -2899,6 +3034,10 @@ var OpenAIImageModel = class OpenAIImageModel {
|
|
|
2899
3034
|
providerOptions,
|
|
2900
3035
|
schema: openaiImageModelEditOptions
|
|
2901
3036
|
}) ?? {};
|
|
3037
|
+
if (mask != null && openaiOptions.markup != null) throw new InvalidArgumentError({
|
|
3038
|
+
argument: "providerOptions.openai.markup",
|
|
3039
|
+
message: "`markup` cannot be combined with `mask`."
|
|
3040
|
+
});
|
|
2902
3041
|
const { value: response, responseHeaders } = await postFormDataToApi({
|
|
2903
3042
|
url: this.config.url({
|
|
2904
3043
|
path: "/images/edits",
|
|
@@ -2910,14 +3049,18 @@ var OpenAIImageModel = class OpenAIImageModel {
|
|
|
2910
3049
|
prompt,
|
|
2911
3050
|
image: await Promise.all(files.map((file) => file.type === "file" ? new Blob([file.data instanceof Uint8Array ? new Blob([file.data], { type: file.mediaType }) : new Blob([convertBase64ToUint8Array(file.data)], { type: file.mediaType })], { type: file.mediaType }) : downloadBlob(file.url, { abortSignal }))),
|
|
2912
3051
|
mask: mask != null ? await fileToBlob(mask, abortSignal) : void 0,
|
|
3052
|
+
markup: openaiOptions.markup != null ? await markupToBlob(openaiOptions.markup, abortSignal) : void 0,
|
|
2913
3053
|
n,
|
|
2914
3054
|
size,
|
|
2915
3055
|
quality: openaiOptions.quality,
|
|
2916
3056
|
background: openaiOptions.background,
|
|
2917
3057
|
output_format: openaiOptions.outputFormat,
|
|
2918
3058
|
output_compression: openaiOptions.outputCompression,
|
|
3059
|
+
complexity: openaiOptions.complexity,
|
|
2919
3060
|
input_fidelity: openaiOptions.inputFidelity,
|
|
2920
|
-
|
|
3061
|
+
moderation: openaiOptions.moderation,
|
|
3062
|
+
user: openaiOptions.user,
|
|
3063
|
+
safety_identifier: openaiOptions.safetyIdentifier
|
|
2921
3064
|
}),
|
|
2922
3065
|
failedResponseHandler: openaiFailedResponseHandler,
|
|
2923
3066
|
successfulResponseHandler: createJsonResponseHandler(openaiImageResponseSchema),
|
|
@@ -2970,7 +3113,11 @@ var OpenAIImageModel = class OpenAIImageModel {
|
|
|
2970
3113
|
moderation: openaiOptions.moderation,
|
|
2971
3114
|
output_format: openaiOptions.outputFormat,
|
|
2972
3115
|
output_compression: openaiOptions.outputCompression,
|
|
3116
|
+
complexity: openaiOptions.complexity,
|
|
3117
|
+
frame_count: openaiOptions.frameCount,
|
|
3118
|
+
frame_duration_ms: openaiOptions.frameDurationMs,
|
|
2973
3119
|
user: openaiOptions.user,
|
|
3120
|
+
safety_identifier: openaiOptions.safetyIdentifier,
|
|
2974
3121
|
...!hasDefaultResponseFormat(this.modelId) ? { response_format: "b64_json" } : {}
|
|
2975
3122
|
},
|
|
2976
3123
|
failedResponseHandler: openaiFailedResponseHandler,
|
|
@@ -3023,6 +3170,15 @@ function distributeTokenDetails(details, index, total) {
|
|
|
3023
3170
|
}
|
|
3024
3171
|
return result;
|
|
3025
3172
|
}
|
|
3173
|
+
async function markupToBlob(markup, abortSignal) {
|
|
3174
|
+
const dataUrl = /^data:([^;,]*)(;base64)?,(.*)$/s.exec(markup);
|
|
3175
|
+
if (dataUrl == null) return downloadBlob(markup, { abortSignal });
|
|
3176
|
+
if (dataUrl[2] == null) throw new InvalidArgumentError({
|
|
3177
|
+
argument: "providerOptions.openai.markup",
|
|
3178
|
+
message: "`markup` data URLs must be base64 encoded."
|
|
3179
|
+
});
|
|
3180
|
+
return new Blob([convertBase64ToUint8Array(dataUrl[3])], { type: dataUrl[1] || "image/png" });
|
|
3181
|
+
}
|
|
3026
3182
|
async function fileToBlob(file, abortSignal) {
|
|
3027
3183
|
if (!file) return void 0;
|
|
3028
3184
|
if (file.type === "url") return downloadBlob(file.url, { abortSignal });
|
|
@@ -3088,7 +3244,24 @@ const codeInterpreterOutputSchema = lazySchema(() => zodSchema(z.object({ output
|
|
|
3088
3244
|
type: z.literal("image"),
|
|
3089
3245
|
url: z.string()
|
|
3090
3246
|
})])).nullish() })));
|
|
3091
|
-
const codeInterpreterArgsSchema = lazySchema(() => zodSchema(z.object({ container: z.union([z.string(), z.object({
|
|
3247
|
+
const codeInterpreterArgsSchema = lazySchema(() => zodSchema(z.object({ container: z.union([z.string(), z.object({
|
|
3248
|
+
fileIds: z.array(z.string()).optional(),
|
|
3249
|
+
memoryLimit: z.enum([
|
|
3250
|
+
"1g",
|
|
3251
|
+
"4g",
|
|
3252
|
+
"16g",
|
|
3253
|
+
"64g"
|
|
3254
|
+
]).optional(),
|
|
3255
|
+
networkPolicy: z.discriminatedUnion("type", [z.object({ type: z.literal("disabled") }), z.object({
|
|
3256
|
+
type: z.literal("allowlist"),
|
|
3257
|
+
allowedDomains: z.array(z.string()),
|
|
3258
|
+
domainSecrets: z.array(z.object({
|
|
3259
|
+
domain: z.string(),
|
|
3260
|
+
name: z.string(),
|
|
3261
|
+
value: z.string()
|
|
3262
|
+
})).optional()
|
|
3263
|
+
})]).optional()
|
|
3264
|
+
})]).optional() })));
|
|
3092
3265
|
const codeInterpreterToolFactory = createProviderExecutedToolFactory({
|
|
3093
3266
|
id: "openai.code_interpreter",
|
|
3094
3267
|
inputSchema: codeInterpreterInputSchema,
|
|
@@ -3532,8 +3705,9 @@ const mcpArgsSchema = lazySchema(() => zodSchema(z.object({
|
|
|
3532
3705
|
headers: z.record(z.string(), z.string()).optional(),
|
|
3533
3706
|
requireApproval: z.union([z.enum(["always", "never"]), z.object({ never: z.object({ toolNames: z.array(z.string()).optional() }).optional() })]).optional(),
|
|
3534
3707
|
serverDescription: z.string().optional(),
|
|
3535
|
-
serverUrl: z.string().optional()
|
|
3536
|
-
|
|
3708
|
+
serverUrl: z.string().optional(),
|
|
3709
|
+
tunnelId: z.string().optional()
|
|
3710
|
+
}).refine((v) => v.serverUrl != null || v.connectorId != null || v.tunnelId != null, "One of serverUrl, connectorId, or tunnelId must be provided.").refine((v) => v.tunnelId == null || v.serverUrl == null && v.connectorId == null, "tunnelId cannot be combined with serverUrl or connectorId.")));
|
|
3537
3711
|
const mcpInputSchema = lazySchema(() => zodSchema(z.object({})));
|
|
3538
3712
|
const mcpOutputSchema = lazySchema(() => zodSchema(z.object({
|
|
3539
3713
|
type: z.literal("call"),
|
|
@@ -3684,16 +3858,17 @@ const openaiTools = {
|
|
|
3684
3858
|
webSearch,
|
|
3685
3859
|
/**
|
|
3686
3860
|
* MCP (Model Context Protocol) allows models to call tools exposed by
|
|
3687
|
-
* remote MCP servers or
|
|
3861
|
+
* remote MCP servers, service connectors, or Secure MCP tunnels.
|
|
3688
3862
|
*
|
|
3689
3863
|
* @param serverLabel - Label to identify the MCP server.
|
|
3690
3864
|
* @param allowedTools - Allowed tool names or filter object.
|
|
3691
|
-
* @param authorization - OAuth access token for the MCP server
|
|
3865
|
+
* @param authorization - OAuth access token for the MCP server or connector (including tunneled servers).
|
|
3692
3866
|
* @param connectorId - Identifier for a service connector.
|
|
3693
3867
|
* @param headers - Optional headers to include in MCP requests.
|
|
3694
|
-
*
|
|
3868
|
+
* @param requireApproval - Approval policy ('always'|'never'|filter object).
|
|
3695
3869
|
* @param serverDescription - Optional description of the server.
|
|
3696
3870
|
* @param serverUrl - URL for the MCP server.
|
|
3871
|
+
* @param tunnelId - Identifier for an OpenAI Secure MCP tunnel.
|
|
3697
3872
|
*/
|
|
3698
3873
|
mcp,
|
|
3699
3874
|
/**
|
|
@@ -3738,10 +3913,12 @@ function convertOpenAIResponsesUsage(usage) {
|
|
|
3738
3913
|
}
|
|
3739
3914
|
//#endregion
|
|
3740
3915
|
//#region src/responses/map-openai-responses-finish-reason.ts
|
|
3741
|
-
function mapOpenAIResponseFinishReason({ finishReason, hasFunctionCall }) {
|
|
3916
|
+
function mapOpenAIResponseFinishReason({ finishReason, hasFunctionCall, hasRefusal = false }) {
|
|
3742
3917
|
switch (finishReason) {
|
|
3743
3918
|
case void 0:
|
|
3744
|
-
case null:
|
|
3919
|
+
case null:
|
|
3920
|
+
if (hasFunctionCall) return "tool-calls";
|
|
3921
|
+
return hasRefusal ? "content-filter" : "stop";
|
|
3745
3922
|
case "max_output_tokens": return "length";
|
|
3746
3923
|
case "content_filter": return "content-filter";
|
|
3747
3924
|
default: return hasFunctionCall ? "tool-calls" : "other";
|
|
@@ -3921,6 +4098,8 @@ const openaiResponsesModeledChunkTypes = /* @__PURE__ */ new Set([
|
|
|
3921
4098
|
"response.output_item.done",
|
|
3922
4099
|
"response.output_text.annotation.added",
|
|
3923
4100
|
"response.output_text.delta",
|
|
4101
|
+
"response.refusal.delta",
|
|
4102
|
+
"response.refusal.done",
|
|
3924
4103
|
"response.reasoning_summary_part.added",
|
|
3925
4104
|
"response.reasoning_summary_part.done",
|
|
3926
4105
|
"response.reasoning_summary_text.delta"
|
|
@@ -3974,6 +4153,20 @@ const openaiResponsesChunkSchema = lazySchema(() => zodSchema(z.union([
|
|
|
3974
4153
|
}))
|
|
3975
4154
|
})).nullish()
|
|
3976
4155
|
}),
|
|
4156
|
+
z.object({
|
|
4157
|
+
type: z.literal("response.refusal.delta"),
|
|
4158
|
+
item_id: z.string(),
|
|
4159
|
+
output_index: z.number().nullish(),
|
|
4160
|
+
content_index: z.number().nullish(),
|
|
4161
|
+
delta: z.string()
|
|
4162
|
+
}),
|
|
4163
|
+
z.object({
|
|
4164
|
+
type: z.literal("response.refusal.done"),
|
|
4165
|
+
item_id: z.string(),
|
|
4166
|
+
output_index: z.number().nullish(),
|
|
4167
|
+
content_index: z.number().nullish(),
|
|
4168
|
+
refusal: z.string()
|
|
4169
|
+
}),
|
|
3977
4170
|
z.object({
|
|
3978
4171
|
type: z.enum(["response.completed", "response.incomplete"]),
|
|
3979
4172
|
response: z.object({
|
|
@@ -4531,7 +4724,7 @@ const openaiResponsesResponseSchema = lazySchema(() => zodSchema(z.object({
|
|
|
4531
4724
|
role: z.literal("assistant"),
|
|
4532
4725
|
id: z.string(),
|
|
4533
4726
|
phase: z.enum(["commentary", "final_answer"]).nullish(),
|
|
4534
|
-
content: z.array(z.object({
|
|
4727
|
+
content: z.array(z.discriminatedUnion("type", [z.object({
|
|
4535
4728
|
type: z.literal("output_text"),
|
|
4536
4729
|
text: z.string(),
|
|
4537
4730
|
logprobs: z.array(z.object({
|
|
@@ -4570,7 +4763,10 @@ const openaiResponsesResponseSchema = lazySchema(() => zodSchema(z.object({
|
|
|
4570
4763
|
index: z.number()
|
|
4571
4764
|
})
|
|
4572
4765
|
]))
|
|
4573
|
-
})
|
|
4766
|
+
}), z.object({
|
|
4767
|
+
type: z.literal("refusal"),
|
|
4768
|
+
refusal: z.string()
|
|
4769
|
+
})]))
|
|
4574
4770
|
}),
|
|
4575
4771
|
z.object({
|
|
4576
4772
|
type: z.literal("web_search_call"),
|
|
@@ -6353,7 +6549,13 @@ async function prepareResponsesTools({ tools, toolChoice, allowedTools, toolName
|
|
|
6353
6549
|
file_ids: void 0
|
|
6354
6550
|
} : typeof args.container === "string" ? args.container : {
|
|
6355
6551
|
type: "auto",
|
|
6356
|
-
file_ids: args.container.fileIds
|
|
6552
|
+
file_ids: args.container.fileIds,
|
|
6553
|
+
memory_limit: args.container.memoryLimit,
|
|
6554
|
+
network_policy: args.container.networkPolicy == null ? void 0 : args.container.networkPolicy.type === "disabled" ? { type: "disabled" } : {
|
|
6555
|
+
type: "allowlist",
|
|
6556
|
+
allowed_domains: args.container.networkPolicy.allowedDomains,
|
|
6557
|
+
domain_secrets: args.container.networkPolicy.domainSecrets
|
|
6558
|
+
}
|
|
6357
6559
|
}
|
|
6358
6560
|
});
|
|
6359
6561
|
break;
|
|
@@ -6402,7 +6604,8 @@ async function prepareResponsesTools({ tools, toolChoice, allowedTools, toolName
|
|
|
6402
6604
|
headers: args.headers,
|
|
6403
6605
|
require_approval: requireApprovalParam ?? "never",
|
|
6404
6606
|
server_description: args.serverDescription,
|
|
6405
|
-
server_url: args.serverUrl
|
|
6607
|
+
server_url: args.serverUrl,
|
|
6608
|
+
tunnel_id: args.tunnelId
|
|
6406
6609
|
});
|
|
6407
6610
|
break;
|
|
6408
6611
|
}
|
|
@@ -7096,6 +7299,7 @@ var OpenAIResponsesLanguageModel = class OpenAIResponsesLanguageModel {
|
|
|
7096
7299
|
const retrievedFileIds = /* @__PURE__ */ new Set();
|
|
7097
7300
|
let hasFunctionCall = false;
|
|
7098
7301
|
const hostedToolSearchCallIds = [];
|
|
7302
|
+
let hasRefusal = false;
|
|
7099
7303
|
let structuredOutputText;
|
|
7100
7304
|
for (const part of response.output) switch (part.type) {
|
|
7101
7305
|
case "reasoning":
|
|
@@ -7197,8 +7401,20 @@ var OpenAIResponsesLanguageModel = class OpenAIResponsesLanguageModel {
|
|
|
7197
7401
|
});
|
|
7198
7402
|
break;
|
|
7199
7403
|
case "message":
|
|
7200
|
-
if (options.responseFormat?.type === "json" && part.phase === "final_answer") structuredOutputText = part.content.map((contentPart) => contentPart.text).join("");
|
|
7404
|
+
if (options.responseFormat?.type === "json" && part.phase === "final_answer") structuredOutputText = part.content.map((contentPart) => contentPart.type === "output_text" ? contentPart.text : contentPart.refusal).join("");
|
|
7201
7405
|
for (const contentPart of part.content) {
|
|
7406
|
+
if (contentPart.type === "refusal") {
|
|
7407
|
+
hasRefusal = true;
|
|
7408
|
+
content.push({
|
|
7409
|
+
type: "text",
|
|
7410
|
+
text: contentPart.refusal,
|
|
7411
|
+
providerMetadata: { [providerOptionsName]: {
|
|
7412
|
+
itemId: part.id,
|
|
7413
|
+
...part.phase != null && { phase: part.phase }
|
|
7414
|
+
} }
|
|
7415
|
+
});
|
|
7416
|
+
continue;
|
|
7417
|
+
}
|
|
7202
7418
|
if (options.providerOptions?.[providerOptionsName]?.logprobs && contentPart.logprobs) logprobs.push(contentPart.logprobs);
|
|
7203
7419
|
const providerMetadata = {
|
|
7204
7420
|
itemId: part.id,
|
|
@@ -7485,7 +7701,8 @@ var OpenAIResponsesLanguageModel = class OpenAIResponsesLanguageModel {
|
|
|
7485
7701
|
finishReason: {
|
|
7486
7702
|
unified: mapOpenAIResponseFinishReason({
|
|
7487
7703
|
finishReason: response.incomplete_details?.reason,
|
|
7488
|
-
hasFunctionCall
|
|
7704
|
+
hasFunctionCall,
|
|
7705
|
+
hasRefusal
|
|
7489
7706
|
}),
|
|
7490
7707
|
raw: response.incomplete_details?.reason ?? void 0
|
|
7491
7708
|
},
|
|
@@ -7548,6 +7765,7 @@ var OpenAIResponsesLanguageModel = class OpenAIResponsesLanguageModel {
|
|
|
7548
7765
|
const fallbackAnnotations = [];
|
|
7549
7766
|
let activeMessagePhase;
|
|
7550
7767
|
let hasFunctionCall = false;
|
|
7768
|
+
let hasRefusal = false;
|
|
7551
7769
|
const activeReasoning = {};
|
|
7552
7770
|
const activeOutputItemIds = {};
|
|
7553
7771
|
const resolveOutputItemId = ({ itemId, outputIndex }) => outputIndex == null ? itemId : activeOutputItemIds[outputIndex] ?? itemId;
|
|
@@ -8314,7 +8532,19 @@ var OpenAIResponsesLanguageModel = class OpenAIResponsesLanguageModel {
|
|
|
8314
8532
|
delta: value.delta
|
|
8315
8533
|
});
|
|
8316
8534
|
if (options.providerOptions?.[providerOptionsName]?.logprobs && value.logprobs) logprobs.push(value.logprobs);
|
|
8317
|
-
} else if (value
|
|
8535
|
+
} else if (isRefusalDeltaChunk(value)) {
|
|
8536
|
+
hasRefusal = true;
|
|
8537
|
+
const itemId = resolveOutputItemId({
|
|
8538
|
+
itemId: value.item_id,
|
|
8539
|
+
outputIndex: value.output_index
|
|
8540
|
+
});
|
|
8541
|
+
controller.enqueue({
|
|
8542
|
+
type: "text-delta",
|
|
8543
|
+
id: itemId,
|
|
8544
|
+
delta: value.delta
|
|
8545
|
+
});
|
|
8546
|
+
} else if (isRefusalDoneChunk(value)) hasRefusal = true;
|
|
8547
|
+
else if (value.type === "response.reasoning_summary_part.added") {
|
|
8318
8548
|
const itemId = resolveOutputItemId({
|
|
8319
8549
|
itemId: value.item_id,
|
|
8320
8550
|
outputIndex: value.output_index
|
|
@@ -8372,7 +8602,8 @@ var OpenAIResponsesLanguageModel = class OpenAIResponsesLanguageModel {
|
|
|
8372
8602
|
if (!encounteredStreamError) finishReason = {
|
|
8373
8603
|
unified: mapOpenAIResponseFinishReason({
|
|
8374
8604
|
finishReason: value.response.incomplete_details?.reason,
|
|
8375
|
-
hasFunctionCall
|
|
8605
|
+
hasFunctionCall,
|
|
8606
|
+
hasRefusal
|
|
8376
8607
|
}),
|
|
8377
8608
|
raw: value.response.incomplete_details?.reason ?? void 0
|
|
8378
8609
|
};
|
|
@@ -8462,6 +8693,12 @@ var OpenAIResponsesLanguageModel = class OpenAIResponsesLanguageModel {
|
|
|
8462
8693
|
function isTextDeltaChunk(chunk) {
|
|
8463
8694
|
return chunk.type === "response.output_text.delta";
|
|
8464
8695
|
}
|
|
8696
|
+
function isRefusalDeltaChunk(chunk) {
|
|
8697
|
+
return chunk.type === "response.refusal.delta";
|
|
8698
|
+
}
|
|
8699
|
+
function isRefusalDoneChunk(chunk) {
|
|
8700
|
+
return chunk.type === "response.refusal.done";
|
|
8701
|
+
}
|
|
8465
8702
|
function isOpenAIChatCompletionChunk(value) {
|
|
8466
8703
|
const chunk = asRecord(value);
|
|
8467
8704
|
return chunk != null && Array.isArray(chunk.choices) && typeof chunk.type !== "string";
|
|
@@ -8982,6 +9219,7 @@ async function convertOpenAIBatchResult(body) {
|
|
|
8982
9219
|
const content = [];
|
|
8983
9220
|
const logprobs = [];
|
|
8984
9221
|
let hasFunctionCall = false;
|
|
9222
|
+
let hasRefusal = false;
|
|
8985
9223
|
for (const part of response.output) switch (part.type) {
|
|
8986
9224
|
case "reasoning": {
|
|
8987
9225
|
const summaries = part.summary.length > 0 ? part.summary : [{
|
|
@@ -9000,6 +9238,14 @@ async function convertOpenAIBatchResult(body) {
|
|
|
9000
9238
|
}
|
|
9001
9239
|
case "message":
|
|
9002
9240
|
for (const contentPart of part.content) {
|
|
9241
|
+
if (contentPart.type === "refusal") {
|
|
9242
|
+
hasRefusal = true;
|
|
9243
|
+
content.push({
|
|
9244
|
+
type: "text",
|
|
9245
|
+
text: contentPart.refusal
|
|
9246
|
+
});
|
|
9247
|
+
continue;
|
|
9248
|
+
}
|
|
9003
9249
|
content.push({
|
|
9004
9250
|
type: "text",
|
|
9005
9251
|
text: contentPart.text
|
|
@@ -9118,7 +9364,8 @@ async function convertOpenAIBatchResult(body) {
|
|
|
9118
9364
|
finishReason: {
|
|
9119
9365
|
unified: mapOpenAIResponseFinishReason({
|
|
9120
9366
|
finishReason: response.incomplete_details?.reason,
|
|
9121
|
-
hasFunctionCall
|
|
9367
|
+
hasFunctionCall,
|
|
9368
|
+
hasRefusal
|
|
9122
9369
|
}),
|
|
9123
9370
|
raw: response.incomplete_details?.reason ?? void 0
|
|
9124
9371
|
},
|
|
@@ -9471,7 +9718,8 @@ var OpenAIRealtimeModelLive = class {
|
|
|
9471
9718
|
getWebRTCConfig() {
|
|
9472
9719
|
return { dataChannelLabel: "oai-events" };
|
|
9473
9720
|
}
|
|
9474
|
-
getServerWebSocketConfig() {
|
|
9721
|
+
getServerWebSocketConfig(options) {
|
|
9722
|
+
this.assertConversationIntent(options);
|
|
9475
9723
|
return resolveWith(this.config.headers, (configHeaders) => {
|
|
9476
9724
|
const url = new URL(`${this.config.baseURL}/live/sessions`);
|
|
9477
9725
|
url.protocol = url.protocol === "http:" ? "ws:" : "wss:";
|
|
@@ -9511,10 +9759,15 @@ var OpenAIRealtimeModelLive = class {
|
|
|
9511
9759
|
createServerEventParser() {
|
|
9512
9760
|
return createOpenAILiveServerEventParser();
|
|
9513
9761
|
}
|
|
9514
|
-
|
|
9762
|
+
assertConversationIntent(options) {
|
|
9763
|
+
if (options?.intent != null && options.intent !== "conversation") throw new Error(`OpenAI Live session intent '${options.intent}' is not supported.`);
|
|
9764
|
+
}
|
|
9765
|
+
serializeClientEvent(event, options) {
|
|
9766
|
+
this.assertConversationIntent(options);
|
|
9515
9767
|
return serializeOpenAILiveClientEvent(event, this.modelId);
|
|
9516
9768
|
}
|
|
9517
|
-
buildSessionConfig(config) {
|
|
9769
|
+
buildSessionConfig(config, options) {
|
|
9770
|
+
this.assertConversationIntent(options);
|
|
9518
9771
|
return buildOpenAILiveSessionConfig(config, this.modelId);
|
|
9519
9772
|
}
|
|
9520
9773
|
};
|
|
@@ -9558,23 +9811,31 @@ function parseOpenAIRealtimeServerEvent(raw) {
|
|
|
9558
9811
|
item: event.item,
|
|
9559
9812
|
raw
|
|
9560
9813
|
};
|
|
9561
|
-
case "conversation.item.input_audio_transcription.completed":
|
|
9562
|
-
|
|
9563
|
-
|
|
9564
|
-
|
|
9565
|
-
|
|
9566
|
-
|
|
9814
|
+
case "conversation.item.input_audio_transcription.completed": {
|
|
9815
|
+
const usage = mapTranscriptionUsage(event.usage);
|
|
9816
|
+
return {
|
|
9817
|
+
type: "input-transcription-completed",
|
|
9818
|
+
itemId: event.item_id,
|
|
9819
|
+
transcript: event.transcript ?? "",
|
|
9820
|
+
...usage != null ? { usage } : {},
|
|
9821
|
+
raw
|
|
9822
|
+
};
|
|
9823
|
+
}
|
|
9567
9824
|
case "response.created": return {
|
|
9568
9825
|
type: "response-created",
|
|
9569
9826
|
responseId: event.response?.id ?? event.response_id,
|
|
9570
9827
|
raw
|
|
9571
9828
|
};
|
|
9572
|
-
case "response.done":
|
|
9573
|
-
|
|
9574
|
-
|
|
9575
|
-
|
|
9576
|
-
|
|
9577
|
-
|
|
9829
|
+
case "response.done": {
|
|
9830
|
+
const usage = mapResponseUsage(event.response?.usage);
|
|
9831
|
+
return {
|
|
9832
|
+
type: "response-done",
|
|
9833
|
+
responseId: event.response?.id ?? event.response_id,
|
|
9834
|
+
status: event.response?.status ?? "completed",
|
|
9835
|
+
...usage != null ? { usage } : {},
|
|
9836
|
+
raw
|
|
9837
|
+
};
|
|
9838
|
+
}
|
|
9578
9839
|
case "response.output_item.added": return {
|
|
9579
9840
|
type: "output-item-added",
|
|
9580
9841
|
responseId: event.response_id,
|
|
@@ -9672,13 +9933,60 @@ function parseOpenAIRealtimeServerEvent(raw) {
|
|
|
9672
9933
|
}
|
|
9673
9934
|
}
|
|
9674
9935
|
/**
|
|
9936
|
+
* Maps OpenAI realtime `response.done` usage to normalized usage.
|
|
9937
|
+
*
|
|
9938
|
+
* Input buckets are reported gross (cache-inclusive) with the cached portion
|
|
9939
|
+
* surfaced separately, so consumers can apply their own cached-vs-uncached
|
|
9940
|
+
* billing split without re-reading `raw`.
|
|
9941
|
+
*/
|
|
9942
|
+
function mapResponseUsage(usage) {
|
|
9943
|
+
if (usage == null) return void 0;
|
|
9944
|
+
const input = usage.input_token_details;
|
|
9945
|
+
const output = usage.output_token_details;
|
|
9946
|
+
const cached = input?.cached_tokens_details;
|
|
9947
|
+
return compactUsage({
|
|
9948
|
+
inputTokens: usage.input_tokens,
|
|
9949
|
+
outputTokens: usage.output_tokens,
|
|
9950
|
+
cachedInputTokens: input?.cached_tokens,
|
|
9951
|
+
inputAudioTokens: input?.audio_tokens,
|
|
9952
|
+
inputTextTokens: input?.text_tokens,
|
|
9953
|
+
outputAudioTokens: output?.audio_tokens,
|
|
9954
|
+
outputTextTokens: output?.text_tokens,
|
|
9955
|
+
cachedInputAudioTokens: cached?.audio_tokens,
|
|
9956
|
+
cachedInputTextTokens: cached?.text_tokens
|
|
9957
|
+
});
|
|
9958
|
+
}
|
|
9959
|
+
/**
|
|
9960
|
+
* Maps OpenAI realtime transcription-completed usage to normalized usage.
|
|
9961
|
+
* Duration-billed transcription reports `seconds`; token-billed reports tokens.
|
|
9962
|
+
*/
|
|
9963
|
+
function mapTranscriptionUsage(usage) {
|
|
9964
|
+
if (usage == null) return void 0;
|
|
9965
|
+
if (usage.type === "duration") return usage.seconds != null ? { seconds: usage.seconds } : void 0;
|
|
9966
|
+
const input = usage.input_token_details;
|
|
9967
|
+
return compactUsage({
|
|
9968
|
+
inputTokens: usage.input_tokens,
|
|
9969
|
+
outputTokens: usage.output_tokens,
|
|
9970
|
+
inputAudioTokens: input?.audio_tokens,
|
|
9971
|
+
inputTextTokens: input?.text_tokens,
|
|
9972
|
+
outputTextTokens: usage.output_tokens
|
|
9973
|
+
});
|
|
9974
|
+
}
|
|
9975
|
+
/** Drop `undefined` fields; return `undefined` when nothing is observable. */
|
|
9976
|
+
function compactUsage(usage) {
|
|
9977
|
+
const result = {};
|
|
9978
|
+
for (const [key, value] of Object.entries(usage)) if (value != null) result[key] = value;
|
|
9979
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
9980
|
+
}
|
|
9981
|
+
/**
|
|
9675
9982
|
* Serializes a normalized client event into OpenAI's Realtime API format.
|
|
9676
9983
|
*/
|
|
9677
|
-
function serializeOpenAIRealtimeClientEvent(event, modelId) {
|
|
9984
|
+
function serializeOpenAIRealtimeClientEvent(event, modelId, options) {
|
|
9985
|
+
assertSupportedOpenAIIntent(options?.intent);
|
|
9678
9986
|
switch (event.type) {
|
|
9679
9987
|
case "session-update": return {
|
|
9680
9988
|
type: "session.update",
|
|
9681
|
-
session: buildOpenAISessionConfig(event.config, modelId),
|
|
9989
|
+
session: buildOpenAISessionConfig(event.config, modelId, options),
|
|
9682
9990
|
...event.eventId != null ? { event_id: event.eventId } : {}
|
|
9683
9991
|
};
|
|
9684
9992
|
case "input-audio-append": return {
|
|
@@ -9744,15 +10052,27 @@ function serializeOpenAIRealtimeClientEvent(event, modelId) {
|
|
|
9744
10052
|
/**
|
|
9745
10053
|
* Builds an OpenAI-specific session configuration from a normalized config.
|
|
9746
10054
|
*/
|
|
9747
|
-
function buildOpenAISessionConfig(config, modelId) {
|
|
10055
|
+
function buildOpenAISessionConfig(config, modelId, options) {
|
|
10056
|
+
const intent = options?.intent ?? "conversation";
|
|
10057
|
+
assertSupportedOpenAIIntent(intent);
|
|
10058
|
+
if (intent === "transcription") {
|
|
10059
|
+
for (const key of [
|
|
10060
|
+
"instructions",
|
|
10061
|
+
"voice",
|
|
10062
|
+
"outputModalities",
|
|
10063
|
+
"outputAudioFormat",
|
|
10064
|
+
"outputAudioTranscription",
|
|
10065
|
+
"tools"
|
|
10066
|
+
]) if (config[key] != null) throw new Error(`OpenAI realtime transcription sessions do not support '${key}'.`);
|
|
10067
|
+
}
|
|
9748
10068
|
const session = {
|
|
9749
|
-
type: "realtime",
|
|
9750
|
-
model: modelId
|
|
10069
|
+
type: intent === "transcription" ? "transcription" : "realtime",
|
|
10070
|
+
...intent === "conversation" ? { model: modelId } : {}
|
|
9751
10071
|
};
|
|
9752
|
-
if (config.instructions != null) session.instructions = config.instructions;
|
|
9753
|
-
if (config.outputModalities != null) session.output_modalities = config.outputModalities;
|
|
10072
|
+
if (intent === "conversation" && config.instructions != null) session.instructions = config.instructions;
|
|
10073
|
+
if (intent === "conversation" && config.outputModalities != null) session.output_modalities = config.outputModalities;
|
|
9754
10074
|
const audio = {};
|
|
9755
|
-
if (config.inputAudioFormat != null || config.inputAudioTranscription != null || config.turnDetection != null) {
|
|
10075
|
+
if (intent === "transcription" || config.inputAudioFormat != null || config.inputAudioTranscription != null || config.turnDetection != null) {
|
|
9756
10076
|
const input = {};
|
|
9757
10077
|
if (config.inputAudioFormat != null) input.format = {
|
|
9758
10078
|
type: config.inputAudioFormat.type,
|
|
@@ -9768,14 +10088,19 @@ function buildOpenAISessionConfig(config, modelId) {
|
|
|
9768
10088
|
input.turn_detection = td;
|
|
9769
10089
|
}
|
|
9770
10090
|
}
|
|
9771
|
-
if (
|
|
10091
|
+
if (intent === "transcription") input.transcription = {
|
|
10092
|
+
model: config.inputAudioTranscription?.model ?? modelId,
|
|
10093
|
+
...config.inputAudioTranscription?.language != null ? { language: config.inputAudioTranscription.language } : {},
|
|
10094
|
+
...config.inputAudioTranscription?.prompt != null ? { prompt: config.inputAudioTranscription.prompt } : {}
|
|
10095
|
+
};
|
|
10096
|
+
else if (config.inputAudioTranscription != null) input.transcription = {
|
|
9772
10097
|
model: config.inputAudioTranscription.model ?? "gpt-realtime-whisper",
|
|
9773
10098
|
...config.inputAudioTranscription.language != null ? { language: config.inputAudioTranscription.language } : {},
|
|
9774
10099
|
...config.inputAudioTranscription.prompt != null ? { prompt: config.inputAudioTranscription.prompt } : {}
|
|
9775
10100
|
};
|
|
9776
10101
|
audio.input = input;
|
|
9777
10102
|
}
|
|
9778
|
-
if (config.outputAudioFormat != null || config.voice != null) {
|
|
10103
|
+
if (intent === "conversation" && (config.outputAudioFormat != null || config.voice != null)) {
|
|
9779
10104
|
const output = {};
|
|
9780
10105
|
if (config.outputAudioFormat != null) output.format = {
|
|
9781
10106
|
type: config.outputAudioFormat.type,
|
|
@@ -9785,7 +10110,7 @@ function buildOpenAISessionConfig(config, modelId) {
|
|
|
9785
10110
|
audio.output = output;
|
|
9786
10111
|
}
|
|
9787
10112
|
if (Object.keys(audio).length > 0) session.audio = audio;
|
|
9788
|
-
if (config.tools != null && config.tools.length > 0) {
|
|
10113
|
+
if (intent === "conversation" && config.tools != null && config.tools.length > 0) {
|
|
9789
10114
|
session.tools = config.tools.map((tool) => ({
|
|
9790
10115
|
type: tool.type,
|
|
9791
10116
|
name: tool.name,
|
|
@@ -9797,11 +10122,19 @@ function buildOpenAISessionConfig(config, modelId) {
|
|
|
9797
10122
|
if (config.providerOptions != null) Object.assign(session, config.providerOptions);
|
|
9798
10123
|
return session;
|
|
9799
10124
|
}
|
|
10125
|
+
function assertSupportedOpenAIIntent(intent) {
|
|
10126
|
+
if (intent != null && intent !== "conversation" && intent !== "transcription") throw new Error(`OpenAI realtime session intent '${intent}' is not supported.`);
|
|
10127
|
+
}
|
|
9800
10128
|
//#endregion
|
|
9801
10129
|
//#region src/realtime/openai-realtime-model.ts
|
|
9802
10130
|
var OpenAIRealtimeModel = class {
|
|
9803
10131
|
constructor(modelId, config) {
|
|
9804
10132
|
this.specificationVersion = "v4";
|
|
10133
|
+
this.capabilities = {
|
|
10134
|
+
conversation: "turn-based",
|
|
10135
|
+
transports: ["websocket"],
|
|
10136
|
+
connections: ["client-secret-websocket", "server-websocket"]
|
|
10137
|
+
};
|
|
9805
10138
|
this.modelId = modelId;
|
|
9806
10139
|
this.provider = config.provider;
|
|
9807
10140
|
this.config = config;
|
|
@@ -9844,16 +10177,36 @@ var OpenAIRealtimeModel = class {
|
|
|
9844
10177
|
protocols: ["realtime", `openai-insecure-api-key.${options.token}`]
|
|
9845
10178
|
};
|
|
9846
10179
|
}
|
|
10180
|
+
getServerWebSocketConfig(options) {
|
|
10181
|
+
return resolveWith(this.config.headers, (headers) => ({
|
|
10182
|
+
url: buildServerUrl(this.config.baseURL, this.modelId, options?.intent ?? "conversation"),
|
|
10183
|
+
headers: removeUndefinedEntries(headers)
|
|
10184
|
+
}));
|
|
10185
|
+
}
|
|
9847
10186
|
parseServerEvent(raw) {
|
|
9848
10187
|
return parseOpenAIRealtimeServerEvent(raw);
|
|
9849
10188
|
}
|
|
9850
|
-
serializeClientEvent(event) {
|
|
9851
|
-
return serializeOpenAIRealtimeClientEvent(event, this.modelId);
|
|
10189
|
+
serializeClientEvent(event, options) {
|
|
10190
|
+
return serializeOpenAIRealtimeClientEvent(event, this.modelId, options);
|
|
9852
10191
|
}
|
|
9853
|
-
buildSessionConfig(config) {
|
|
9854
|
-
return buildOpenAISessionConfig(config, this.modelId);
|
|
10192
|
+
buildSessionConfig(config, options) {
|
|
10193
|
+
return buildOpenAISessionConfig(config, this.modelId, options);
|
|
9855
10194
|
}
|
|
9856
10195
|
};
|
|
10196
|
+
/**
|
|
10197
|
+
* Builds the upstream realtime WebSocket URL for a server-initiated connection.
|
|
10198
|
+
* Transcription keeps the model in `session.update`; a `?model=` here would
|
|
10199
|
+
* open a voice session instead.
|
|
10200
|
+
*/
|
|
10201
|
+
function buildServerUrl(baseURL, modelId, intent) {
|
|
10202
|
+
const url = new URL(baseURL);
|
|
10203
|
+
const base = `${url.protocol === "http:" ? "ws:" : "wss:"}//${url.host}${url.pathname.replace(/\/$/, "")}`;
|
|
10204
|
+
switch (intent) {
|
|
10205
|
+
case "transcription": return `${base}/realtime?intent=transcription`;
|
|
10206
|
+
case "conversation": return `${base}/realtime?model=${encodeURIComponent(modelId)}`;
|
|
10207
|
+
default: throw new Error(`OpenAI realtime session intent '${intent}' is not supported.`);
|
|
10208
|
+
}
|
|
10209
|
+
}
|
|
9857
10210
|
//#endregion
|
|
9858
10211
|
//#region src/realtime/openai-realtime-factory.ts
|
|
9859
10212
|
function resolveRealtimeApi(modelId, { api } = {}) {
|
|
@@ -10180,7 +10533,7 @@ var OpenAITranscriptionModel = class OpenAITranscriptionModel {
|
|
|
10180
10533
|
this.config = config;
|
|
10181
10534
|
this.specificationVersion = "v4";
|
|
10182
10535
|
}
|
|
10183
|
-
async getArgs({ audio, mediaType, providerOptions }) {
|
|
10536
|
+
async getArgs({ audio, mediaType, providerOptions, timestampGranularities: requestedTimestampGranularities }) {
|
|
10184
10537
|
const warnings = [];
|
|
10185
10538
|
const openAIOptions = await parseProviderOptions({
|
|
10186
10539
|
provider: "openai",
|
|
@@ -10194,7 +10547,17 @@ var OpenAITranscriptionModel = class OpenAITranscriptionModel {
|
|
|
10194
10547
|
formData.append("file", new File([blob], "audio", { type: mediaType }), `audio.${fileExtension}`);
|
|
10195
10548
|
const { transcription: requestConfig } = getOpenAITranscriptionModelEntry(this.modelId).requestConfig;
|
|
10196
10549
|
const responseFormat = openAIOptions?.responseFormat ?? requestConfig.responseFormat;
|
|
10197
|
-
const timestampGranularities = openAIOptions?.timestampGranularities ?? (responseFormat === "verbose_json" ? ["segment"] : void 0);
|
|
10550
|
+
const timestampGranularities = openAIOptions?.timestampGranularities ?? requestedTimestampGranularities ?? (responseFormat === "verbose_json" ? ["segment"] : void 0);
|
|
10551
|
+
for (const granularity of requestedTimestampGranularities ?? []) if (openAIOptions?.timestampGranularities != null && !openAIOptions.timestampGranularities.includes(granularity)) warnings.push({
|
|
10552
|
+
type: "unsupported",
|
|
10553
|
+
feature: "timestampGranularities",
|
|
10554
|
+
details: `The "${granularity}" timestamp granularity is excluded by providerOptions.openai.timestampGranularities.`
|
|
10555
|
+
});
|
|
10556
|
+
for (const granularity of timestampGranularities ?? []) if (responseFormat !== "verbose_json" && !(responseFormat === "diarized_json" && granularity === "segment")) warnings.push({
|
|
10557
|
+
type: "unsupported",
|
|
10558
|
+
feature: openAIOptions?.timestampGranularities != null ? "providerOptions.openai.timestampGranularities" : "timestampGranularities",
|
|
10559
|
+
details: `OpenAI transcription with the ${responseFormat ?? "default JSON"} response format does not support ${granularity} timestamps.`
|
|
10560
|
+
});
|
|
10198
10561
|
const chunkingStrategy = openAIOptions?.chunkingStrategy ?? requestConfig.chunkingStrategy;
|
|
10199
10562
|
const transcriptionModelOptions = {
|
|
10200
10563
|
response_format: responseFormat,
|
|
@@ -10204,7 +10567,7 @@ var OpenAITranscriptionModel = class OpenAITranscriptionModel {
|
|
|
10204
10567
|
keywords: openAIOptions?.keywords,
|
|
10205
10568
|
prompt: openAIOptions?.prompt,
|
|
10206
10569
|
temperature: openAIOptions?.temperature,
|
|
10207
|
-
timestamp_granularities: timestampGranularities
|
|
10570
|
+
timestamp_granularities: responseFormat === "verbose_json" ? timestampGranularities : void 0
|
|
10208
10571
|
};
|
|
10209
10572
|
for (const [key, value] of Object.entries(transcriptionModelOptions)) if (value != null) {
|
|
10210
10573
|
if (Array.isArray(value)) for (const item of value) formData.append(`${key}[]`, String(item));
|
|
@@ -10244,17 +10607,19 @@ var OpenAITranscriptionModel = class OpenAITranscriptionModel {
|
|
|
10244
10607
|
endSecond: segment.end,
|
|
10245
10608
|
speaker: segment.speaker
|
|
10246
10609
|
}] : []);
|
|
10610
|
+
const words = response.words?.map((word) => ({
|
|
10611
|
+
text: word.word,
|
|
10612
|
+
startSecond: word.start,
|
|
10613
|
+
endSecond: word.end
|
|
10614
|
+
}));
|
|
10247
10615
|
return {
|
|
10248
10616
|
text: response.text,
|
|
10249
10617
|
segments: response.segments?.map((segment) => ({
|
|
10250
10618
|
text: segment.text,
|
|
10251
10619
|
startSecond: segment.start,
|
|
10252
10620
|
endSecond: segment.end
|
|
10253
|
-
})) ??
|
|
10254
|
-
|
|
10255
|
-
startSecond: word.start,
|
|
10256
|
-
endSecond: word.end
|
|
10257
|
-
})) ?? [],
|
|
10621
|
+
})) ?? words ?? [],
|
|
10622
|
+
...words != null && words.length > 0 ? { words } : {},
|
|
10258
10623
|
language,
|
|
10259
10624
|
durationInSeconds: response.duration ?? (response.usage?.type === "duration" && typeof response.usage.seconds === "number" ? response.usage.seconds : void 0),
|
|
10260
10625
|
warnings,
|
|
@@ -10767,7 +11132,7 @@ var OpenAISkills = class {
|
|
|
10767
11132
|
};
|
|
10768
11133
|
//#endregion
|
|
10769
11134
|
//#region src/version.ts
|
|
10770
|
-
const VERSION = "4.0.
|
|
11135
|
+
const VERSION = "4.0.110";
|
|
10771
11136
|
//#endregion
|
|
10772
11137
|
//#region src/openai-provider.ts
|
|
10773
11138
|
/**
|