UNPKG

@ai-sdk/openai

Version:

The **[OpenAI provider](https://ai-sdk.dev/providers/ai-sdk-providers/openai)** for the [AI SDK](https://ai-sdk.dev/docs) contains language model support for the OpenAI chat and completion APIs and embedding model support for the OpenAI embeddings API.

1,420 lines (1,402 loc) 284 kB
// src/chat/openai-chat-language-model.ts import { StreamingToolCallTracker, combineHeaders, createEventSourceResponseHandler, createJsonResponseHandler, generateId, isCustomReasoning, parseProviderOptions, postJsonToApi, serializeModelOptions, WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE } from "@ai-sdk/provider-utils"; // src/openai-error.ts import { z } from "zod/v4"; import { createJsonErrorResponseHandler } from "@ai-sdk/provider-utils"; var openaiErrorDataSchema = z.object({ error: z.object({ message: z.string(), // The additional information below is handled loosely to support // OpenAI-compatible providers that have slightly different error // responses: type: z.string().nullish(), param: z.any().nullish(), code: z.union([z.string(), z.number()]).nullish() }) }); var openaiFailedResponseHandler = createJsonErrorResponseHandler({ errorSchema: openaiErrorDataSchema, errorToMessage: (data) => data.error.message }); // src/openai-language-model-capabilities.ts function getOpenAILanguageModelCapabilities(modelId) { const supportsFlexProcessing = modelId.startsWith("o3") || modelId.startsWith("o4-mini") || modelId.startsWith("gpt-5") && !modelId.startsWith("gpt-5-chat"); const supportsPriorityProcessing = modelId.startsWith("gpt-4") || modelId.startsWith("gpt-5") && !modelId.startsWith("gpt-5-nano") && !modelId.startsWith("gpt-5-chat") && !modelId.startsWith("gpt-5.4-nano") || modelId.startsWith("o3") || modelId.startsWith("o4-mini"); const isReasoningModel = modelId.startsWith("o1") || modelId.startsWith("o3") || modelId.startsWith("o4-mini") || modelId.startsWith("gpt-5") && !modelId.startsWith("gpt-5-chat"); const supportsNonReasoningParameters = modelId.startsWith("gpt-5.1") || modelId.startsWith("gpt-5.2") || modelId.startsWith("gpt-5.3") || modelId.startsWith("gpt-5.4") || modelId.startsWith("gpt-5.5") || modelId.startsWith("gpt-5.6"); const systemMessageMode = isReasoningModel ? "developer" : "system"; return { supportsFlexProcessing, supportsPriorityProcessing, isReasoningModel, systemMessageMode, supportsNonReasoningParameters }; } // src/openai-stream-error.ts import { APICallError } from "@ai-sdk/provider"; async function throwIfOpenAIStreamErrorBeforeOutput({ stream, getError, isOutputChunk, url, requestBodyValues, responseHeaders }) { const [streamForEarlyError, streamForConsumer] = stream.tee(); const reader = streamForEarlyError.getReader(); try { while (true) { const result = await reader.read(); if (result.done) { return streamForConsumer; } const chunk = result.value; if (!chunk.success) { return streamForConsumer; } const errorFrame = getError(chunk.value); if (errorFrame != null) { streamForConsumer.cancel().catch(() => { }); throw createOpenAIStreamError({ frame: errorFrame, url, requestBodyValues, responseHeaders }); } if (isOutputChunk(chunk.value)) { return streamForConsumer; } } } finally { reader.cancel().catch(() => { }); reader.releaseLock(); } } function createOpenAIStreamError({ frame, url, requestBodyValues, responseHeaders }) { var _a; const streamError = parseStreamError(frame); return new APICallError({ message: (_a = streamError == null ? void 0 : streamError.message) != null ? _a : "OpenAI stream failed before any output was generated", url, requestBodyValues, statusCode: streamError == null ? 500 : getStatusCode(streamError), responseHeaders, responseBody: JSON.stringify(frame), data: frame }); } function parseStreamError(frame) { var _a; const value = asRecord(frame); if (value == null) { return void 0; } if (value.type === "response.failed") { const response = asRecord(value.response); const responseError = asRecord(response == null ? void 0 : response.error); return typeof (responseError == null ? void 0 : responseError.message) === "string" ? { message: responseError.message, code: getStringOrNumber(responseError.code), type: "response.failed", frame } : void 0; } const error = (_a = asRecord(value.error)) != null ? _a : value; return typeof error.message === "string" && (asRecord(value.error) != null || typeof error.type === "string" || "code" in error || "param" in error) ? { message: error.message, code: getStringOrNumber(error.code), type: typeof error.type === "string" ? error.type : void 0, frame } : void 0; } function getStatusCode(error) { if (typeof error.code === "number" && isHttpErrorStatusCode(error.code)) { return error.code; } if (typeof error.code === "string" && /^\d{3}$/.test(error.code)) { const numericCode = Number(error.code); if (isHttpErrorStatusCode(numericCode)) { return numericCode; } } const discriminator = [error.code, error.type].filter((value) => typeof value === "string" || typeof value === "number").join(" ").toLowerCase(); if (["insufficient_quota", "rate_limit"].some( (term) => discriminator.includes(term) )) { return 429; } if (discriminator.includes("authentication")) return 401; if (discriminator.includes("permission")) return 403; if (discriminator.includes("not_found")) return 404; if (["invalid", "bad_request", "context_length"].some( (term) => discriminator.includes(term) )) { return 400; } if (discriminator.includes("overload")) return 503; if (discriminator.includes("timeout")) return 504; return 500; } function asRecord(value) { return typeof value === "object" && value != null ? value : void 0; } function getStringOrNumber(value) { return typeof value === "string" || typeof value === "number" ? value : void 0; } function isHttpErrorStatusCode(value) { return Number.isInteger(value) && value >= 400 && value <= 599; } // src/chat/convert-openai-chat-usage.ts function convertOpenAIChatUsage(usage) { var _a, _b, _c, _d, _e, _f, _g, _h; if (usage == null) { return { inputTokens: { total: void 0, noCache: void 0, cacheRead: void 0, cacheWrite: void 0 }, outputTokens: { total: void 0, text: void 0, reasoning: void 0 }, raw: void 0 }; } const promptTokens = (_a = usage.prompt_tokens) != null ? _a : 0; const completionTokens = (_b = usage.completion_tokens) != null ? _b : 0; const cachedTokens = (_d = (_c = usage.prompt_tokens_details) == null ? void 0 : _c.cached_tokens) != null ? _d : 0; const cacheWriteTokens = (_f = (_e = usage.prompt_tokens_details) == null ? void 0 : _e.cache_write_tokens) != null ? _f : void 0; const reasoningTokens = (_h = (_g = usage.completion_tokens_details) == null ? void 0 : _g.reasoning_tokens) != null ? _h : 0; return { inputTokens: { total: promptTokens, noCache: promptTokens - cachedTokens - (cacheWriteTokens != null ? cacheWriteTokens : 0), cacheRead: cachedTokens, cacheWrite: cacheWriteTokens }, outputTokens: { total: completionTokens, text: completionTokens - reasoningTokens, reasoning: reasoningTokens }, raw: usage }; } // src/chat/convert-to-openai-chat-messages.ts import { UnsupportedFunctionalityError } from "@ai-sdk/provider"; import { convertToBase64, getTopLevelMediaType, resolveFullMediaType, resolveProviderReference } from "@ai-sdk/provider-utils"; function serializeToolCallArguments(input) { return JSON.stringify(input === void 0 ? {} : input); } function getPromptCacheBreakpoint(providerOptions) { var _a; return (_a = providerOptions == null ? void 0 : providerOptions.openai) == null ? void 0 : _a.promptCacheBreakpoint; } function convertToOpenAIChatMessages({ prompt, systemMessageMode = "system" }) { var _a, _b; const messages = []; const warnings = []; for (const { role, content, providerOptions } of prompt) { switch (role) { case "system": { switch (systemMessageMode) { case "system": { const promptCacheBreakpoint = getPromptCacheBreakpoint(providerOptions); messages.push({ role: "system", content: promptCacheBreakpoint == null ? content : [ { type: "text", text: content, prompt_cache_breakpoint: promptCacheBreakpoint } ] }); break; } case "developer": { const promptCacheBreakpoint = getPromptCacheBreakpoint(providerOptions); messages.push({ role: "developer", content: promptCacheBreakpoint == null ? content : [ { type: "text", text: content, prompt_cache_breakpoint: promptCacheBreakpoint } ] }); break; } case "remove": { warnings.push({ type: "other", message: "system messages are removed for this model" }); break; } default: { const _exhaustiveCheck = systemMessageMode; throw new Error( `Unsupported system message mode: ${_exhaustiveCheck}` ); } } break; } case "user": { if (content.length === 1 && content[0].type === "text" && getPromptCacheBreakpoint(content[0].providerOptions) == null) { messages.push({ role: "user", content: content[0].text }); break; } messages.push({ role: "user", content: content.map((part, index) => { var _a2, _b2, _c; switch (part.type) { case "text": { const promptCacheBreakpoint = getPromptCacheBreakpoint( part.providerOptions ); return { type: "text", text: part.text, ...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint } }; } case "file": { const promptCacheBreakpoint = getPromptCacheBreakpoint( part.providerOptions ); switch (part.data.type) { case "reference": { return { type: "file", file: { file_id: resolveProviderReference({ reference: part.data.reference, provider: "openai" }) }, ...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint } }; } case "text": { throw new UnsupportedFunctionalityError({ functionality: "text file parts" }); } case "url": case "data": { const topLevel = getTopLevelMediaType(part.mediaType); if (topLevel === "image") { return { type: "image_url", image_url: { url: part.data.type === "url" ? part.data.url.toString() : `data:${resolveFullMediaType({ part })};base64,${convertToBase64(part.data.data)}`, detail: (_b2 = (_a2 = part.providerOptions) == null ? void 0 : _a2.openai) == null ? void 0 : _b2.imageDetail }, ...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint } }; } else if (topLevel === "audio") { if (part.data.type === "url") { throw new UnsupportedFunctionalityError({ functionality: "audio file parts with URLs" }); } const fullMediaType = resolveFullMediaType({ part }); switch (fullMediaType) { case "audio/wav": { return { type: "input_audio", input_audio: { data: convertToBase64(part.data.data), format: "wav" }, ...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint } }; } case "audio/mp3": case "audio/mpeg": { return { type: "input_audio", input_audio: { data: convertToBase64(part.data.data), format: "mp3" }, ...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint } }; } default: { throw new UnsupportedFunctionalityError({ functionality: `audio content parts with media type ${fullMediaType}` }); } } } { const fullMediaType = resolveFullMediaType({ part }); if (fullMediaType !== "application/pdf") { throw new UnsupportedFunctionalityError({ functionality: `file part media type ${fullMediaType}` }); } if (part.data.type === "url") { throw new UnsupportedFunctionalityError({ functionality: "PDF file parts with URLs" }); } return { type: "file", file: { filename: (_c = part.filename) != null ? _c : `part-${index}.pdf`, file_data: `data:application/pdf;base64,${convertToBase64(part.data.data)}` }, ...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint } }; } } } } } }) }); break; } case "assistant": { let text = ""; const textParts = []; let hasPromptCacheBreakpoint = false; const toolCalls = []; for (const part of content) { switch (part.type) { case "text": { const promptCacheBreakpoint = getPromptCacheBreakpoint( part.providerOptions ); text += part.text; textParts.push({ type: "text", text: part.text, ...promptCacheBreakpoint != null && { prompt_cache_breakpoint: promptCacheBreakpoint } }); hasPromptCacheBreakpoint || (hasPromptCacheBreakpoint = promptCacheBreakpoint != null); break; } case "tool-call": { toolCalls.push({ id: part.toolCallId, type: "function", function: { name: part.toolName, arguments: serializeToolCallArguments(part.input) } }); break; } } } messages.push({ role: "assistant", content: hasPromptCacheBreakpoint ? textParts : toolCalls.length > 0 ? text || null : text, tool_calls: toolCalls.length > 0 ? toolCalls : void 0 }); break; } case "tool": { for (const toolResponse of content) { if (toolResponse.type === "tool-approval-response") { continue; } const output = toolResponse.output; const promptCacheBreakpoint = (_a = output.type === "content" ? output.value.map((part) => getPromptCacheBreakpoint(part.providerOptions)).find((breakpoint) => breakpoint != null) : getPromptCacheBreakpoint(output.providerOptions)) != null ? _a : getPromptCacheBreakpoint(toolResponse.providerOptions); let contentValue; switch (output.type) { case "text": case "error-text": contentValue = output.value; break; case "execution-denied": contentValue = (_b = output.reason) != null ? _b : "Tool call execution denied."; break; case "content": case "json": case "error-json": contentValue = JSON.stringify(output.value); break; } messages.push({ role: "tool", tool_call_id: toolResponse.toolCallId, content: promptCacheBreakpoint == null ? contentValue : [ { type: "text", text: contentValue, prompt_cache_breakpoint: promptCacheBreakpoint } ] }); } break; } default: { const _exhaustiveCheck = role; throw new Error(`Unsupported role: ${_exhaustiveCheck}`); } } } return { messages, warnings }; } // src/chat/get-response-metadata.ts function getResponseMetadata({ id, model, created }) { return { id: id != null ? id : void 0, modelId: model != null ? model : void 0, timestamp: created ? new Date(created * 1e3) : void 0 }; } // src/chat/map-openai-finish-reason.ts function mapOpenAIFinishReason(finishReason) { switch (finishReason) { case "stop": return "stop"; case "length": return "length"; case "content_filter": return "content-filter"; case "function_call": case "tool_calls": return "tool-calls"; default: return "other"; } } // src/chat/openai-chat-api.ts import { lazySchema, zodSchema } from "@ai-sdk/provider-utils"; import { z as z2 } from "zod/v4"; var openaiChatResponseSchema = lazySchema( () => zodSchema( z2.object({ id: z2.string().nullish(), created: z2.number().nullish(), model: z2.string().nullish(), choices: z2.array( z2.object({ message: z2.object({ role: z2.literal("assistant").nullish(), content: z2.string().nullish(), tool_calls: z2.array( z2.object({ id: z2.string().nullish(), type: z2.literal("function"), function: z2.object({ name: z2.string(), arguments: z2.string() }) }) ).nullish(), annotations: z2.array( z2.object({ type: z2.literal("url_citation"), url_citation: z2.object({ start_index: z2.number(), end_index: z2.number(), url: z2.string(), title: z2.string() }) }) ).nullish() }), index: z2.number(), logprobs: z2.object({ content: z2.array( z2.object({ token: z2.string(), logprob: z2.number(), top_logprobs: z2.array( z2.object({ token: z2.string(), logprob: z2.number() }) ) }) ).nullish() }).nullish(), finish_reason: z2.string().nullish() }) ), usage: z2.object({ prompt_tokens: z2.number().nullish(), completion_tokens: z2.number().nullish(), total_tokens: z2.number().nullish(), prompt_tokens_details: z2.object({ cached_tokens: z2.number().nullish(), cache_write_tokens: z2.number().nullish() }).nullish(), completion_tokens_details: z2.object({ reasoning_tokens: z2.number().nullish(), accepted_prediction_tokens: z2.number().nullish(), rejected_prediction_tokens: z2.number().nullish() }).nullish() }).nullish() }) ) ); var openaiChatChunkSchema = lazySchema( () => zodSchema( z2.union([ z2.object({ id: z2.string().nullish(), created: z2.number().nullish(), model: z2.string().nullish(), choices: z2.array( z2.object({ delta: z2.object({ role: z2.enum(["assistant"]).nullish(), content: z2.string().nullish(), tool_calls: z2.array( z2.object({ index: z2.number(), id: z2.string().nullish(), type: z2.literal("function").nullish(), function: z2.object({ name: z2.string().nullish(), arguments: z2.string().nullish() }) }) ).nullish(), annotations: z2.array( z2.object({ type: z2.literal("url_citation"), url_citation: z2.object({ start_index: z2.number(), end_index: z2.number(), url: z2.string(), title: z2.string() }) }) ).nullish() }).nullish(), logprobs: z2.object({ content: z2.array( z2.object({ token: z2.string(), logprob: z2.number(), top_logprobs: z2.array( z2.object({ token: z2.string(), logprob: z2.number() }) ) }) ).nullish() }).nullish(), finish_reason: z2.string().nullish(), index: z2.number() }) ), usage: z2.object({ prompt_tokens: z2.number().nullish(), completion_tokens: z2.number().nullish(), total_tokens: z2.number().nullish(), prompt_tokens_details: z2.object({ cached_tokens: z2.number().nullish(), cache_write_tokens: z2.number().nullish() }).nullish(), completion_tokens_details: z2.object({ reasoning_tokens: z2.number().nullish(), accepted_prediction_tokens: z2.number().nullish(), rejected_prediction_tokens: z2.number().nullish() }).nullish() }).nullish() }), openaiErrorDataSchema ]) ) ); // src/chat/openai-chat-language-model-options.ts import { lazySchema as lazySchema2, zodSchema as zodSchema2 } from "@ai-sdk/provider-utils"; import { z as z3 } from "zod/v4"; var openaiLanguageModelChatOptions = lazySchema2( () => zodSchema2( z3.object({ /** * Modify the likelihood of specified tokens appearing in the completion. * * Accepts a JSON object that maps tokens (specified by their token ID in * the GPT tokenizer) to an associated bias value from -100 to 100. */ logitBias: z3.record(z3.coerce.number(), z3.number()).optional(), /** * Return the log probabilities of the tokens. * * Setting to true will return the log probabilities of the tokens that * were generated. * * Setting to a number will return the log probabilities of the top n * tokens that were generated. */ logprobs: z3.union([z3.boolean(), z3.number()]).optional(), /** * Whether to enable parallel function calling during tool use. Default to true. */ parallelToolCalls: z3.boolean().optional(), /** * A unique identifier representing your end-user, which can help OpenAI to * monitor and detect abuse. */ user: z3.string().optional(), /** * Reasoning effort for reasoning models. Defaults to `medium`. */ reasoningEffort: z3.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]).optional(), /** * Maximum number of completion tokens to generate. Useful for reasoning models. */ maxCompletionTokens: z3.number().optional(), /** * Whether to enable persistence in responses API. */ store: z3.boolean().optional(), /** * Metadata to associate with the request. */ metadata: z3.record(z3.string().max(64), z3.string().max(512)).optional(), /** * Parameters for prediction mode. */ prediction: z3.record(z3.string(), z3.any()).optional(), /** * Service tier for the request. * - 'auto': Default service tier. The request will be processed with the service tier configured in the * Project settings. Unless otherwise configured, the Project will use 'default'. * - 'flex': 50% cheaper processing at the cost of increased latency. Only available for o3 and o4-mini models. * - 'priority': Higher-speed processing with predictably low latency at premium cost. Available for Enterprise customers. * - 'default': The request will be processed with the standard pricing and performance for the selected model. * * @default 'auto' */ serviceTier: z3.enum(["auto", "flex", "priority", "default"]).optional(), /** * Whether to use strict JSON schema validation. * * @default true */ strictJsonSchema: z3.boolean().optional(), /** * Controls the verbosity of the model's responses. * Lower values will result in more concise responses, while higher values will result in more verbose responses. */ textVerbosity: z3.enum(["low", "medium", "high"]).optional(), /** * A cache key for prompt caching. Allows manual control over prompt caching behavior. * Useful for improving cache hit rates and working around automatic caching issues. */ promptCacheKey: z3.string().optional(), /** * Prompt cache behavior for GPT-5.6 and later models. * `mode` controls whether OpenAI also places an implicit breakpoint. * `ttl` sets the minimum cache lifetime and currently only supports 30 minutes. */ promptCacheOptions: z3.object({ mode: z3.enum(["implicit", "explicit"]).optional(), ttl: z3.literal("30m").optional() }).optional(), /** * The retention policy for the prompt cache. * - 'in_memory': Default. Standard prompt caching behavior. * - '24h': Extended prompt caching that keeps cached prefixes active for up to 24 hours. * Available for models before GPT-5.6 that support extended caching. * * @deprecated For GPT-5.6 and later models, use `promptCacheOptions.ttl`. * * @default 'in_memory' */ promptCacheRetention: z3.enum(["in_memory", "24h"]).optional(), /** * A stable identifier used to help detect users of your application * that may be violating OpenAI's usage policies. The IDs should be a * string that uniquely identifies each user. We recommend hashing their * username or email address, in order to avoid sending us any identifying * information. */ safetyIdentifier: z3.string().optional(), /** * Override the system message mode for this model. * - 'system': Use the 'system' role for system messages (default for most models) * - 'developer': Use the 'developer' role for system messages (used by reasoning models) * - 'remove': Remove system messages entirely * * If not specified, the mode is automatically determined based on the model. */ systemMessageMode: z3.enum(["system", "developer", "remove"]).optional(), /** * Force treating this model as a reasoning model. * * This is useful for "stealth" reasoning models (e.g. via a custom baseURL) * where the model ID is not recognized by the SDK's allowlist. * * When enabled, the SDK applies reasoning-model parameter compatibility rules * and defaults `systemMessageMode` to `developer` unless overridden. */ forceReasoning: z3.boolean().optional() }) ) ); // src/chat/openai-chat-prepare-tools.ts import { UnsupportedFunctionalityError as UnsupportedFunctionalityError2 } from "@ai-sdk/provider"; function prepareChatTools({ tools, toolChoice }) { tools = (tools == null ? void 0 : tools.length) ? tools : void 0; const toolWarnings = []; if (tools == null) { return { tools: void 0, toolChoice: void 0, toolWarnings }; } const openaiTools = []; for (const tool of tools) { switch (tool.type) { case "function": openaiTools.push({ type: "function", function: { name: tool.name, description: tool.description, parameters: tool.inputSchema, ...tool.strict != null ? { strict: tool.strict } : {} } }); break; default: toolWarnings.push({ type: "unsupported", feature: `tool type: ${tool.type}` }); break; } } if (toolChoice == null) { return { tools: openaiTools, toolChoice: void 0, toolWarnings }; } const type = toolChoice.type; switch (type) { case "auto": case "none": case "required": return { tools: openaiTools, toolChoice: type, toolWarnings }; case "tool": return { tools: openaiTools, toolChoice: { type: "function", function: { name: toolChoice.toolName } }, toolWarnings }; default: { const _exhaustiveCheck = type; throw new UnsupportedFunctionalityError2({ functionality: `tool choice type: ${_exhaustiveCheck}` }); } } } // src/chat/openai-chat-language-model.ts var OpenAIChatLanguageModel = class _OpenAIChatLanguageModel { constructor(modelId, config) { this.specificationVersion = "v4"; this.supportedUrls = { "image/*": [/^https?:\/\/.*$/] }; this.modelId = modelId; this.config = config; } static [WORKFLOW_SERIALIZE](model) { return serializeModelOptions({ modelId: model.modelId, config: model.config }); } static [WORKFLOW_DESERIALIZE](options) { return new _OpenAIChatLanguageModel(options.modelId, options.config); } get provider() { return this.config.provider; } async getArgs({ prompt, maxOutputTokens, temperature, topP, topK, frequencyPenalty, presencePenalty, stopSequences, responseFormat, seed, tools, toolChoice, reasoning, providerOptions }) { var _a, _b, _c, _d, _e, _f; const warnings = []; const openaiOptions = (_a = await parseProviderOptions({ provider: "openai", providerOptions, schema: openaiLanguageModelChatOptions })) != null ? _a : {}; const modelCapabilities = getOpenAILanguageModelCapabilities(this.modelId); const resolvedReasoningEffort = (_b = openaiOptions.reasoningEffort) != null ? _b : isCustomReasoning(reasoning) ? reasoning : void 0; const isReasoningModel = (_c = openaiOptions.forceReasoning) != null ? _c : modelCapabilities.isReasoningModel; if (topK != null) { warnings.push({ type: "unsupported", feature: "topK" }); } const { messages, warnings: messageWarnings } = convertToOpenAIChatMessages( { prompt, systemMessageMode: (_d = openaiOptions.systemMessageMode) != null ? _d : isReasoningModel ? "developer" : modelCapabilities.systemMessageMode } ); warnings.push(...messageWarnings); const strictJsonSchema = (_e = openaiOptions.strictJsonSchema) != null ? _e : true; const baseArgs = { // model id: model: this.modelId, // model specific settings: logit_bias: openaiOptions.logitBias, logprobs: openaiOptions.logprobs === true || typeof openaiOptions.logprobs === "number" ? true : void 0, top_logprobs: typeof openaiOptions.logprobs === "number" ? openaiOptions.logprobs : typeof openaiOptions.logprobs === "boolean" ? openaiOptions.logprobs ? 0 : void 0 : void 0, user: openaiOptions.user, parallel_tool_calls: openaiOptions.parallelToolCalls, // standardized settings: max_tokens: maxOutputTokens, temperature, top_p: topP, frequency_penalty: frequencyPenalty, presence_penalty: presencePenalty, response_format: (responseFormat == null ? void 0 : responseFormat.type) === "json" ? responseFormat.schema != null ? { type: "json_schema", json_schema: { schema: responseFormat.schema, strict: strictJsonSchema, name: (_f = responseFormat.name) != null ? _f : "response", description: responseFormat.description } } : { type: "json_object" } : void 0, stop: stopSequences, seed, verbosity: openaiOptions.textVerbosity, // openai specific settings: // TODO AI SDK 6: remove, we auto-map maxOutputTokens now max_completion_tokens: openaiOptions.maxCompletionTokens, store: openaiOptions.store, metadata: openaiOptions.metadata, prediction: openaiOptions.prediction, reasoning_effort: resolvedReasoningEffort, service_tier: openaiOptions.serviceTier, prompt_cache_key: openaiOptions.promptCacheKey, prompt_cache_options: openaiOptions.promptCacheOptions, prompt_cache_retention: openaiOptions.promptCacheRetention, safety_identifier: openaiOptions.safetyIdentifier, // messages: messages }; if (isReasoningModel) { if (resolvedReasoningEffort !== "none" || !modelCapabilities.supportsNonReasoningParameters) { if (baseArgs.temperature != null) { baseArgs.temperature = void 0; warnings.push({ type: "unsupported", feature: "temperature", details: "temperature is not supported for reasoning models" }); } if (baseArgs.top_p != null) { baseArgs.top_p = void 0; warnings.push({ type: "unsupported", feature: "topP", details: "topP is not supported for reasoning models" }); } if (baseArgs.logprobs != null) { baseArgs.logprobs = void 0; warnings.push({ type: "other", message: "logprobs is not supported for reasoning models" }); } } if (baseArgs.frequency_penalty != null) { baseArgs.frequency_penalty = void 0; warnings.push({ type: "unsupported", feature: "frequencyPenalty", details: "frequencyPenalty is not supported for reasoning models" }); } if (baseArgs.presence_penalty != null) { baseArgs.presence_penalty = void 0; warnings.push({ type: "unsupported", feature: "presencePenalty", details: "presencePenalty is not supported for reasoning models" }); } if (baseArgs.logit_bias != null) { baseArgs.logit_bias = void 0; warnings.push({ type: "other", message: "logitBias is not supported for reasoning models" }); } if (baseArgs.top_logprobs != null) { baseArgs.top_logprobs = void 0; warnings.push({ type: "other", message: "topLogprobs is not supported for reasoning models" }); } if (baseArgs.max_tokens != null) { if (baseArgs.max_completion_tokens == null) { baseArgs.max_completion_tokens = baseArgs.max_tokens; } baseArgs.max_tokens = void 0; } } else if (this.modelId.startsWith("gpt-4o-search-preview") || this.modelId.startsWith("gpt-4o-mini-search-preview")) { if (baseArgs.temperature != null) { baseArgs.temperature = void 0; warnings.push({ type: "unsupported", feature: "temperature", details: "temperature is not supported for the search preview models and has been removed." }); } } if (openaiOptions.serviceTier === "flex" && !modelCapabilities.supportsFlexProcessing) { warnings.push({ type: "unsupported", feature: "serviceTier", details: "flex processing is only available for o3, o4-mini, and gpt-5 models" }); baseArgs.service_tier = void 0; } if (openaiOptions.serviceTier === "priority" && !modelCapabilities.supportsPriorityProcessing) { warnings.push({ type: "unsupported", feature: "serviceTier", details: "priority processing is only available for supported models (gpt-4, gpt-5, gpt-5-mini, o3, o4-mini) and requires Enterprise access. gpt-5-nano is not supported" }); baseArgs.service_tier = void 0; } const { tools: openaiTools, toolChoice: openaiToolChoice, toolWarnings } = prepareChatTools({ tools, toolChoice }); return { args: { ...baseArgs, tools: openaiTools, tool_choice: openaiToolChoice }, warnings: [...warnings, ...toolWarnings] }; } async doGenerate(options) { var _a, _b, _c, _d, _e, _f, _g, _h; const { args: body, warnings } = await this.getArgs(options); const { responseHeaders, value: response, rawValue: rawResponse } = await postJsonToApi({ url: this.config.url({ path: "/chat/completions", modelId: this.modelId }), headers: combineHeaders((_b = (_a = this.config).headers) == null ? void 0 : _b.call(_a), options.headers), body, failedResponseHandler: openaiFailedResponseHandler, successfulResponseHandler: createJsonResponseHandler( openaiChatResponseSchema ), abortSignal: options.abortSignal, fetch: this.config.fetch }); const choice = response.choices[0]; const content = []; const text = choice.message.content; if (text != null && text.length > 0) { content.push({ type: "text", text }); } for (const toolCall of (_c = choice.message.tool_calls) != null ? _c : []) { content.push({ type: "tool-call", toolCallId: (_d = toolCall.id) != null ? _d : generateId(), toolName: toolCall.function.name, input: toolCall.function.arguments }); } for (const annotation of (_e = choice.message.annotations) != null ? _e : []) { content.push({ type: "source", sourceType: "url", id: generateId(), url: annotation.url_citation.url, title: annotation.url_citation.title }); } const completionTokenDetails = (_f = response.usage) == null ? void 0 : _f.completion_tokens_details; const providerMetadata = { openai: {} }; if ((completionTokenDetails == null ? void 0 : completionTokenDetails.accepted_prediction_tokens) != null) { providerMetadata.openai.acceptedPredictionTokens = completionTokenDetails == null ? void 0 : completionTokenDetails.accepted_prediction_tokens; } if ((completionTokenDetails == null ? void 0 : completionTokenDetails.rejected_prediction_tokens) != null) { providerMetadata.openai.rejectedPredictionTokens = completionTokenDetails == null ? void 0 : completionTokenDetails.rejected_prediction_tokens; } if (((_g = choice.logprobs) == null ? void 0 : _g.content) != null) { providerMetadata.openai.logprobs = choice.logprobs.content; } return { content, finishReason: { unified: mapOpenAIFinishReason(choice.finish_reason), raw: (_h = choice.finish_reason) != null ? _h : void 0 }, usage: convertOpenAIChatUsage(response.usage), request: { body }, response: { ...getResponseMetadata(response), headers: responseHeaders, body: rawResponse }, warnings, providerMetadata }; } async doStream(options) { var _a, _b; const { args, warnings } = await this.getArgs(options); const body = { ...args, stream: true, stream_options: { include_usage: true } }; const url = this.config.url({ path: "/chat/completions", modelId: this.modelId }); const { responseHeaders, value: response } = await postJsonToApi({ url, headers: combineHeaders((_b = (_a = this.config).headers) == null ? void 0 : _b.call(_a), options.headers), body, failedResponseHandler: openaiFailedResponseHandler, successfulResponseHandler: createEventSourceResponseHandler( openaiChatChunkSchema ), abortSignal: options.abortSignal, fetch: this.config.fetch }); const checkedResponse = await throwIfOpenAIStreamErrorBeforeOutput({ stream: response, getError: (chunk) => "error" in chunk ? chunk.error : void 0, isOutputChunk: isOpenAIChatOutputChunk, url, requestBodyValues: body, responseHeaders }); let toolCallTracker; let finishReason = { unified: "other", raw: void 0 }; let usage = void 0; let metadataExtracted = false; let isActiveText = false; const providerMetadata = { openai: {} }; const result = { stream: checkedResponse.pipeThrough( new TransformStream({ start(controller) { toolCallTracker = new StreamingToolCallTracker(controller, { generateId, typeValidation: "if-present" }); controller.enqueue({ type: "stream-start", warnings }); }, transform(chunk, controller) { var _a2, _b2, _c, _d, _e; if (options.includeRawChunks) { controller.enqueue({ type: "raw", rawValue: chunk.rawValue }); } if (!chunk.success) { finishReason = { unified: "error", raw: void 0 }; controller.enqueue({ type: "error", error: chunk.error }); return; } const value = chunk.value; if ("error" in value) { finishReason = { unified: "error", raw: void 0 }; controller.enqueue({ type: "error", error: value.error }); return; } if (!metadataExtracted) { const metadata = getResponseMetadata(value); if (Object.values(metadata).some(Boolean)) { metadataExtracted = true; controller.enqueue({ type: "response-metadata", ...getResponseMetadata(value) }); } } if (value.usage != null) { usage = value.usage; if (((_a2 = value.usage.completion_tokens_details) == null ? void 0 : _a2.accepted_prediction_tokens) != null) { providerMetadata.openai.acceptedPredictionTokens = (_b2 = value.usage.completion_tokens_details) == null ? void 0 : _b2.accepted_prediction_tokens; } if (((_c = value.usage.completion_tokens_details) == null ? void 0 : _c.rejected_prediction_tokens) != null) { providerMetadata.openai.rejectedPredictionTokens = (_d = value.usage.completion_tokens_details) == null ? void 0 : _d.rejected_prediction_tokens; } } const choice = value.choices[0]; if ((choice == null ? void 0 : choice.finish_reason) != null) { finishReason = { unified: mapOpenAIFinishReason(choice.finish_reason), raw: choice.finish_reason }; } if (((_e = choice == null ? void 0 : choice.logprobs) == null ? void 0 : _e.content) != null) { providerMetadata.openai.logprobs = choice.logprobs.content; } if ((choice == null ? void 0 : choice.delta) == null) { return; } const delta = choice.delta; if (delta.content != null) { if (!isActiveText) { controller.enqueue({ type: "text-start", id: "0" }); isActiveText = true; } controller.enqueue({ type: "text-delta", id: "0", delta: delta.content }); } if (delta.tool_calls != null) { for (const toolCallDelta of delta.tool_calls) { toolCallTracker.processDelta(toolCallDelta); } } if (delta.annotations != null) { for (const annotation of delta.annotations) { controller.enqueue({ type: "source", sourceType: "url", id: generateId(), url: annotation.url_citation.url, title: annotation.url_citation.title }); } } }, flush(controller) { if (isActiveText) { controller.enqueue({ type: "text-end", id: "0" }); } toolCallTracker.flush(); controller.enqueue({ type: "finish", finishReason, usage: convertOpenAIChatUsage(usage), ...providerMetadata != null ? { providerMetadata } : {} }); } }) ), request: { body }, response: { headers: responseHeaders } }; return result; } }; function isOpenAIChatOutputChunk(chunk) { if ("error" in chunk) { return false; } return chunk.choices.some((choice) => { const delta = choice.delta; return (delta == null ? void 0 : delta.content) != null && delta.content.length > 0 || (delta == null ? void 0 : delta.tool_calls) != null && delta.tool_calls.length > 0 || (delta == null ? void 0 : delta.annotations) != null && delta.annotations.length > 0; }); } // src/completion/openai-completion-language-model.ts import { combineHeaders as combineHeaders2, createEventSourceResponseHandler as createEventSourceResponseHandler2, createJsonResponseHandler as createJsonResponseHandler2, parseProviderOptions as parseProviderOptions2, postJsonToApi as postJsonToApi2, serializeModelOptions as serializeModelOptions2, WORKFLOW_DESERIALIZE as WORKFLOW_DESERIALIZE2, WORKFLOW_SERIALIZE as WORKFLOW_SERIALIZE2 } from "@ai-sdk/provider-utils"; // src/completion/convert-openai-completion-usage.ts function convertOpenAICompletionUsage(usage) { var _a, _b, _c, _d; if (usage == null) { return { inputTokens: { total: void 0, noCache: void 0, cacheRead: void 0, cacheWrite: void 0 }, outputTokens: { total: void 0, text: void 0, reasoning: void 0 }, raw: void 0 }; } const promptTokens = (_a = usage.prompt_tokens) != null ? _a : 0; const completionTokens = (_b = usage.completion_tokens) != null ? _b : 0; return { inputTokens: { total: (_c = usage.prompt_tokens) != null ? _c : void 0, noCache: promptTokens, cacheRead: void 0, cacheWrite: void 0 }, outputTokens: { total: (_d = usage.completion_tokens) != null ? _d : void 0, text: completionTokens, reasoning: void 0 }, raw: usage }; } // src/completion/convert-to-openai-completion-prompt.ts import { InvalidPromptError, UnsupportedFunctionalityError as UnsupportedFunctionalityError3 } from "@ai-sdk/provider"; function convertToOpenAICompletionPrompt({ prompt, user = "user", assistant = "assistant" }) { let text = ""; if (prompt[0].role === "system") { text += `${prompt[0].content} `; prompt = prompt.slice(1); } for (const { role, content } of prompt) { switch (role) { case "system": { throw new InvalidPromptError({ message: "Unexpected system message in prompt: ${content}", prompt }); } case "user": { const userMessage = content.map((part) => { switch (part.type) { case "text": { return part.text; } } }).filter(Boolean).join(""); text += `${user}: ${userMessage} `; break; } case "assistant": { const assistantMessage = content.map((part) => { switch (part.type) { case "text": { return part.text; } case "tool-call": { throw new UnsupportedFunctionalityError3({ functionality: "tool-call messages" }); } } }).join(""); text += `${assistant}: ${assistantMessage} `;