@ai-sdk/openai 4.0.110 → 4.0.111

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "4.0.110",
3
+ "version": "4.0.111",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -35,8 +35,8 @@
35
35
  }
36
36
  },
37
37
  "dependencies": {
38
- "@ai-sdk/provider": "4.0.36",
39
- "@ai-sdk/provider-utils": "5.0.75"
38
+ "@ai-sdk/provider": "4.0.37",
39
+ "@ai-sdk/provider-utils": "5.0.76"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@ai-sdk/test-server": "2.0.4",
@@ -19,8 +19,8 @@ import {
19
19
  createJsonResponseHandler,
20
20
  generateId,
21
21
  isCustomReasoning,
22
- parseProviderOptions,
23
22
  postJsonToApi,
23
+ resolveProviderOptions,
24
24
  serializeModelOptions,
25
25
  WORKFLOW_DESERIALIZE,
26
26
  WORKFLOW_SERIALIZE,
@@ -123,13 +123,20 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
123
123
  }: LanguageModelV4CallOptions) {
124
124
  const warnings: SharedV4Warning[] = [];
125
125
 
126
- // Parse provider options
126
+ // `openai` and the Azure key are merged; the Azure key wins (like Azure
127
+ // completion models).
128
+ const providerOptionsNames = this.config.provider.includes('azure')
129
+ ? (['openai', 'azure'] as const)
130
+ : (['openai'] as const);
127
131
  const openaiOptions =
128
- (await parseProviderOptions({
129
- provider: 'openai',
130
- providerOptions,
131
- schema: openaiLanguageModelChatOptions,
132
- })) ?? {};
132
+ (
133
+ await resolveProviderOptions({
134
+ providerOptions,
135
+ namespaces: providerOptionsNames,
136
+ resolution: 'merge',
137
+ schema: openaiLanguageModelChatOptions,
138
+ })
139
+ ).options ?? {};
133
140
 
134
141
  const {
135
142
  capabilities: { language: modelCapabilities },
@@ -178,7 +185,11 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
178
185
 
179
186
  // reasoningSummary is a Responses API option that the chat options schema strips,
180
187
  // so check the raw provider options to avoid silently ignoring it:
181
- if (providerOptions?.openai?.reasoningSummary != null) {
188
+ if (
189
+ providerOptionsNames.some(
190
+ name => providerOptions?.[name]?.reasoningSummary != null,
191
+ )
192
+ ) {
182
193
  warnings.push({
183
194
  type: 'unsupported',
184
195
  feature: 'reasoningSummary',
@@ -14,8 +14,8 @@ import {
14
14
  combineHeaders,
15
15
  createEventSourceResponseHandler,
16
16
  createJsonResponseHandler,
17
- parseProviderOptions,
18
17
  postJsonToApi,
18
+ resolveProviderOptions,
19
19
  serializeModelOptions,
20
20
  WORKFLOW_DESERIALIZE,
21
21
  WORKFLOW_SERIALIZE,
@@ -111,18 +111,16 @@ export class OpenAICompletionLanguageModel implements LanguageModelV4 {
111
111
  const warnings: SharedV4Warning[] = [];
112
112
 
113
113
  // Parse provider options
114
- const openaiOptions = {
115
- ...(await parseProviderOptions({
116
- provider: 'openai',
117
- providerOptions,
118
- schema: openaiLanguageModelCompletionOptions,
119
- })),
120
- ...(await parseProviderOptions({
121
- provider: this.providerOptionsName,
122
- providerOptions,
123
- schema: openaiLanguageModelCompletionOptions,
124
- })),
125
- };
114
+ // `openai` and the provider key are merged; the provider key wins.
115
+ const openaiOptions =
116
+ (
117
+ await resolveProviderOptions({
118
+ providerOptions,
119
+ namespaces: ['openai', this.providerOptionsName],
120
+ resolution: 'merge',
121
+ schema: openaiLanguageModelCompletionOptions,
122
+ })
123
+ ).options ?? {};
126
124
 
127
125
  if (topK != null) {
128
126
  warnings.push({ type: 'unsupported', feature: 'topK' });
@@ -100,71 +100,82 @@ export type OpenAIImageModelOptions = InferSchema<
100
100
  typeof openaiImageModelOptions
101
101
  >;
102
102
 
103
+ /**
104
+ * Shape of the OpenAI image generation options. Exported so that routers
105
+ * that also call the OpenAI image API (e.g. Azure) can accept these options
106
+ * under their own providerOptions key.
107
+ */
108
+ export const openaiImageModelGenerationOptionsShape = () =>
109
+ baseImageModelOptionsObject().extend({
110
+ /**
111
+ * Style of the generated image. `vivid` produces hyper-real and
112
+ * dramatic images; `natural` produces more subdued, less hyper-real
113
+ * looking images.
114
+ */
115
+ style: z.enum(['vivid', 'natural']).optional(),
116
+
117
+ /**
118
+ * Format in which the generated image(s) are returned. `gif` produces
119
+ * an animated GIF and is supported by GPT Image 2.6 models.
120
+ */
121
+ outputFormat: z.enum(['png', 'jpeg', 'webp', 'gif']).optional(),
122
+
123
+ /**
124
+ * Number of frames (2-64) of an animated GIF. Only applies to the `gif`
125
+ * output format. The API defaults to 9.
126
+ */
127
+ frameCount: z.number().int().min(2).max(64).optional(),
128
+
129
+ /**
130
+ * Duration of each frame in milliseconds (20-2000) of an animated GIF.
131
+ * The API rounds it to the nearest 10 ms. Only applies to the `gif`
132
+ * output format. The API defaults to 200.
133
+ */
134
+ frameDurationMs: z.number().int().min(20).max(2000).optional(),
135
+
136
+ /**
137
+ * Content moderation level for the generated image(s). `low` applies
138
+ * less restrictive filtering.
139
+ */
140
+ moderation: z.enum(['auto', 'low']).optional(),
141
+ }).shape;
142
+
103
143
  export const openaiImageModelGenerationOptions = lazySchema(() =>
104
- zodSchema(
105
- baseImageModelOptionsObject().extend({
106
- /**
107
- * Style of the generated image. `vivid` produces hyper-real and
108
- * dramatic images; `natural` produces more subdued, less hyper-real
109
- * looking images.
110
- */
111
- style: z.enum(['vivid', 'natural']).optional(),
112
-
113
- /**
114
- * Format in which the generated image(s) are returned. `gif` produces
115
- * an animated GIF and is supported by GPT Image 2.6 models.
116
- */
117
- outputFormat: z.enum(['png', 'jpeg', 'webp', 'gif']).optional(),
118
-
119
- /**
120
- * Number of frames (2-64) of an animated GIF. Only applies to the `gif`
121
- * output format. The API defaults to 9.
122
- */
123
- frameCount: z.number().int().min(2).max(64).optional(),
124
-
125
- /**
126
- * Duration of each frame in milliseconds (20-2000) of an animated GIF.
127
- * The API rounds it to the nearest 10 ms. Only applies to the `gif`
128
- * output format. The API defaults to 200.
129
- */
130
- frameDurationMs: z.number().int().min(20).max(2000).optional(),
131
-
132
- /**
133
- * Content moderation level for the generated image(s). `low` applies
134
- * less restrictive filtering.
135
- */
136
- moderation: z.enum(['auto', 'low']).optional(),
137
- }),
138
- ),
144
+ zodSchema(z.object(openaiImageModelGenerationOptionsShape())),
139
145
  );
140
146
 
141
147
  export type OpenAIImageModelGenerationOptions = InferSchema<
142
148
  typeof openaiImageModelGenerationOptions
143
149
  >;
144
150
 
151
+ /**
152
+ * Shape of the OpenAI image edit options. Exported so that routers can accept
153
+ * these options under their own providerOptions key.
154
+ */
155
+ export const openaiImageModelEditOptionsShape = () =>
156
+ baseImageModelOptionsObject().extend({
157
+ /**
158
+ * Fidelity of the output image(s) to the input image(s).
159
+ */
160
+ inputFidelity: z.enum(['high', 'low']).optional(),
161
+
162
+ /**
163
+ * A transparent PNG overlaid on the first input image to mark up the
164
+ * regions to change, as an HTTPS URL or a base64 data URL. It must match
165
+ * the dimensions of the first image. Supported by GPT Image 2.5 and 2.6
166
+ * models. Cannot be combined with a `mask`.
167
+ */
168
+ markup: z.string().optional(),
169
+
170
+ /**
171
+ * Content moderation level for the edited image(s). `low` applies
172
+ * less restrictive filtering. Supported by GPT Image models.
173
+ */
174
+ moderation: z.enum(['auto', 'low']).optional(),
175
+ }).shape;
176
+
145
177
  export const openaiImageModelEditOptions = lazySchema(() =>
146
- zodSchema(
147
- baseImageModelOptionsObject().extend({
148
- /**
149
- * Fidelity of the output image(s) to the input image(s).
150
- */
151
- inputFidelity: z.enum(['high', 'low']).optional(),
152
-
153
- /**
154
- * A transparent PNG overlaid on the first input image to mark up the
155
- * regions to change, as an HTTPS URL or a base64 data URL. It must match
156
- * the dimensions of the first image. Supported by GPT Image 2.5 and 2.6
157
- * models. Cannot be combined with a `mask`.
158
- */
159
- markup: z.string().optional(),
160
-
161
- /**
162
- * Content moderation level for the edited image(s). `low` applies
163
- * less restrictive filtering. Supported by GPT Image models.
164
- */
165
- moderation: z.enum(['auto', 'low']).optional(),
166
- }),
167
- ),
178
+ zodSchema(z.object(openaiImageModelEditOptionsShape())),
168
179
  );
169
180
 
170
181
  export type OpenAIImageModelEditOptions = InferSchema<
@@ -23,8 +23,8 @@ import {
23
23
  createJsonResponseHandler,
24
24
  createToolNameMapping,
25
25
  generateId,
26
- parseProviderOptions,
27
26
  postJsonToApi,
27
+ resolveProviderOptions,
28
28
  serializeModelOptions,
29
29
  WORKFLOW_DESERIALIZE,
30
30
  WORKFLOW_SERIALIZE,
@@ -331,20 +331,15 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
331
331
  const providerOptionsName = config.provider.includes('azure')
332
332
  ? 'azure'
333
333
  : 'openai';
334
- let openaiOptions = await parseProviderOptions({
335
- provider: providerOptionsName,
334
+ // The provider key (`azure`) and `openai` are alternatives: the first
335
+ // present one is used as a whole.
336
+ const { options: openaiOptions } = await resolveProviderOptions({
336
337
  providerOptions,
338
+ namespaces: [providerOptionsName, 'openai'],
339
+ resolution: 'first',
337
340
  schema: openaiLanguageModelResponsesOptionsSchema,
338
341
  });
339
342
 
340
- if (openaiOptions == null && providerOptionsName !== 'openai') {
341
- openaiOptions = await parseProviderOptions({
342
- provider: 'openai',
343
- providerOptions,
344
- schema: openaiLanguageModelResponsesOptionsSchema,
345
- });
346
- }
347
-
348
343
  const resolvedReasoningEffort = resolveOpenAIReasoningEffort({
349
344
  providerReasoningEffort: openaiOptions?.reasoningEffort,
350
345
  reasoning,
@@ -16,13 +16,18 @@ export type OpenAISpeechModelId =
16
16
  | (string & {});
17
17
 
18
18
  // https://platform.openai.com/docs/api-reference/audio/createSpeech
19
+ /**
20
+ * Shape of the OpenAI speech model options. Exported so that routers that
21
+ * also call the OpenAI speech API (e.g. Azure) can accept these options under
22
+ * their own providerOptions key.
23
+ */
24
+ export const openaiSpeechModelOptionsShape = () => ({
25
+ instructions: z.string().nullish(),
26
+ speed: z.number().min(0.25).max(4.0).nullish(),
27
+ });
28
+
19
29
  export const openaiSpeechModelOptionsSchema = lazySchema(() =>
20
- zodSchema(
21
- z.object({
22
- instructions: z.string().nullish(),
23
- speed: z.number().min(0.25).max(4.0).nullish(),
24
- }),
25
- ),
30
+ zodSchema(z.object(openaiSpeechModelOptionsShape())),
26
31
  );
27
32
 
28
33
  export type OpenAISpeechModelOptions = InferSchema<
@@ -18,91 +18,92 @@ export type OpenAITranscriptionModelId =
18
18
  | (string & {});
19
19
 
20
20
  // https://platform.openai.com/docs/api-reference/audio/createTranscription
21
- export const openAITranscriptionModelOptions = lazySchema(() =>
22
- zodSchema(
23
- z.object({
24
- /**
25
- * Additional information to include in the transcription response.
26
- */
21
+ /**
22
+ * Shape of the OpenAI transcription model options. Exported so that routers
23
+ * that also call the OpenAI transcription API (e.g. Azure) can accept these
24
+ * options under their own providerOptions key.
25
+ */
26
+ export const openAITranscriptionModelOptionsShape = () => ({
27
+ /**
28
+ * Additional information to include in the transcription response.
29
+ */
27
30
 
28
- include: z.array(z.string()).optional(),
31
+ include: z.array(z.string()).optional(),
29
32
 
30
- /**
31
- * The language of the input audio in ISO-639-1 format.
32
- */
33
- language: z.string().optional(),
33
+ /**
34
+ * The language of the input audio in ISO-639-1 format.
35
+ */
36
+ language: z.string().optional(),
34
37
 
35
- /**
36
- * Expected languages for REST transcription, e.g. with gpt-transcribe.
37
- * Use this instead of language. The API validates model support.
38
- */
39
- languages: z.array(z.string()).optional(),
38
+ /**
39
+ * Expected languages for REST transcription, e.g. with gpt-transcribe.
40
+ * Use this instead of language. The API validates model support.
41
+ */
42
+ languages: z.array(z.string()).optional(),
40
43
 
41
- /**
42
- * Vocabulary hints for REST transcription, e.g. names or technical terms.
43
- * The API validates model support.
44
- */
45
- keywords: z.array(z.string()).optional(),
44
+ /**
45
+ * Vocabulary hints for REST transcription, e.g. names or technical terms.
46
+ * The API validates model support.
47
+ */
48
+ keywords: z.array(z.string()).optional(),
46
49
 
47
- /**
48
- * An optional text to guide the model's style or continue a previous audio segment.
49
- */
50
- prompt: z.string().optional(),
50
+ /**
51
+ * An optional text to guide the model's style or continue a previous audio segment.
52
+ */
53
+ prompt: z.string().optional(),
51
54
 
52
- /**
53
- * The sampling temperature, between 0 and 1.
54
- * @default 0
55
- */
56
- temperature: z.number().min(0).max(1).default(0).optional(),
55
+ /**
56
+ * The sampling temperature, between 0 and 1.
57
+ * @default 0
58
+ */
59
+ temperature: z.number().min(0).max(1).default(0).optional(),
57
60
 
58
- /**
59
- * The timestamp granularities to populate for this transcription.
60
- * Defaults to ['segment'] when the response format is verbose_json.
61
- */
62
- timestampGranularities: z.array(z.enum(['word', 'segment'])).optional(),
61
+ /**
62
+ * The timestamp granularities to populate for this transcription.
63
+ * Defaults to ['segment'] when the response format is verbose_json.
64
+ */
65
+ timestampGranularities: z.array(z.enum(['word', 'segment'])).optional(),
63
66
 
64
- /**
65
- * The format of the transcription response.
66
- */
67
- responseFormat: z
68
- .enum(['json', 'verbose_json', 'diarized_json'])
69
- .optional(),
67
+ /**
68
+ * The format of the transcription response.
69
+ */
70
+ responseFormat: z.enum(['json', 'verbose_json', 'diarized_json']).optional(),
71
+
72
+ /**
73
+ * Controls how the audio is split into chunks before transcription.
74
+ */
75
+ chunkingStrategy: z
76
+ .union([
77
+ z.literal('auto'),
78
+ z.object({
79
+ type: z.literal('server_vad'),
80
+ threshold: z.number().min(0).max(1).optional(),
81
+ prefixPaddingMs: z.number().int().min(0).optional(),
82
+ silenceDurationMs: z.number().int().min(0).optional(),
83
+ }),
84
+ ])
85
+ .optional(),
70
86
 
87
+ /**
88
+ * Options for streaming transcription models such as `gpt-live-transcribe`.
89
+ */
90
+ streaming: z
91
+ .object({
71
92
  /**
72
- * Controls how the audio is split into chunks before transcription.
93
+ * Latency/accuracy tradeoff for realtime transcription.
73
94
  */
74
- chunkingStrategy: z
75
- .union([
76
- z.literal('auto'),
77
- z.object({
78
- type: z.literal('server_vad'),
79
- threshold: z.number().min(0).max(1).optional(),
80
- prefixPaddingMs: z.number().int().min(0).optional(),
81
- silenceDurationMs: z.number().int().min(0).optional(),
82
- }),
83
- ])
84
- .optional(),
95
+ delay: z.enum(['minimal', 'low', 'medium', 'high', 'xhigh']).optional(),
85
96
 
86
97
  /**
87
- * Options for streaming transcription models such as `gpt-live-transcribe`.
98
+ * Additional fields to include in realtime transcription events.
88
99
  */
89
- streaming: z
90
- .object({
91
- /**
92
- * Latency/accuracy tradeoff for realtime transcription.
93
- */
94
- delay: z
95
- .enum(['minimal', 'low', 'medium', 'high', 'xhigh'])
96
- .optional(),
100
+ include: z.array(z.string()).optional(),
101
+ })
102
+ .optional(),
103
+ });
97
104
 
98
- /**
99
- * Additional fields to include in realtime transcription events.
100
- */
101
- include: z.array(z.string()).optional(),
102
- })
103
- .optional(),
104
- }),
105
- ),
105
+ export const openAITranscriptionModelOptions = lazySchema(() =>
106
+ zodSchema(z.object(openAITranscriptionModelOptionsShape())),
106
107
  );
107
108
 
108
109
  export type OpenAITranscriptionModelOptions = InferSchema<