@ai-sdk/openai 4.0.56 → 4.0.58

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.
@@ -217,12 +217,13 @@ The following provider options are available:
217
217
  `.nullable()`.
218
218
  </Note>
219
219
 
220
- - **serviceTier** _'auto' | 'flex' | 'priority' | 'fast' | 'default'_
220
+ - **serviceTier** _'auto' | 'flex' | 'priority' | 'fast' | 'ultrafast' | 'default'_
221
221
  Service tier for the request. Set to 'flex' for 50% cheaper processing
222
222
  at the cost of increased latency (available for o3, o4-mini, and gpt-5 models).
223
223
  Set to 'priority' for faster processing with Enterprise access (available for gpt-4, gpt-5, gpt-5-mini, o3, o4-mini; gpt-5-nano is not supported).
224
224
  'fast' is OpenAI's newer name for the 'priority' tier; the two are interchangeable, and responses from
225
225
  gpt-5.6 and earlier report `serviceTier: 'priority'` for either.
226
+ Set to 'ultrafast' for access-controlled Ultrafast processing (available only for gpt-5.6-sol).
226
227
 
227
228
  Defaults to 'auto'.
228
229
 
@@ -2106,13 +2107,14 @@ The following optional provider options are available for OpenAI chat models:
2106
2107
 
2107
2108
  Parameters for prediction mode.
2108
2109
 
2109
- - **serviceTier** _'auto' | 'flex' | 'priority' | 'fast' | 'default'_
2110
+ - **serviceTier** _'auto' | 'flex' | 'priority' | 'fast' | 'ultrafast' | 'default'_
2110
2111
 
2111
2112
  Service tier for the request. Set to 'flex' for 50% cheaper processing
2112
2113
  at the cost of increased latency (available for o3, o4-mini, and gpt-5 models).
2113
2114
  Set to 'priority' for faster processing with Enterprise access (available for gpt-4, gpt-5, gpt-5-mini, o3, o4-mini; gpt-5-nano is not supported).
2114
2115
  'fast' is OpenAI's newer name for the 'priority' tier; the two are interchangeable, and responses from
2115
2116
  gpt-5.6 and earlier report `serviceTier: 'priority'` for either.
2117
+ Set to 'ultrafast' for access-controlled Ultrafast processing (available only for gpt-5.6-sol).
2116
2118
 
2117
2119
  Defaults to 'auto'.
2118
2120
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "4.0.56",
3
+ "version": "4.0.58",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -139,12 +139,13 @@ export const openaiLanguageModelChatOptions = lazySchema(() =>
139
139
  * - 'flex': 50% cheaper processing at the cost of increased latency. Only available for o3 and o4-mini models.
140
140
  * - 'priority': Higher-speed processing with predictably low latency at premium cost. Available for Enterprise customers.
141
141
  * - 'fast': OpenAI's newer name for the 'priority' tier. Interchangeable with it.
142
+ * - 'ultrafast': Access-controlled Ultrafast processing. Only available for gpt-5.6-sol.
142
143
  * - 'default': The request will be processed with the standard pricing and performance for the selected model.
143
144
  *
144
145
  * @default 'auto'
145
146
  */
146
147
  serviceTier: z
147
- .enum(['auto', 'flex', 'priority', 'fast', 'default'])
148
+ .enum(['auto', 'flex', 'priority', 'fast', 'ultrafast', 'default'])
148
149
  .optional(),
149
150
 
150
151
  /**
@@ -20,6 +20,7 @@ import {
20
20
  getFromApi,
21
21
  lazySchema,
22
22
  normalizeBatchRequestCounts,
23
+ parseProviderOptions,
23
24
  postJsonToApi,
24
25
  postToApi,
25
26
  safeValidateTypes,
@@ -52,7 +53,25 @@ import type { OpenAIResponsesModelId } from './responses/openai-responses-langua
52
53
  import type { ResponsesReasoningProviderMetadata } from './responses/openai-responses-provider-metadata';
53
54
 
54
55
  const openaiBatchEndpoint = '/v1/responses';
55
- const openaiBatchInputFileExpiresAfterSeconds = 48 * 60 * 60;
56
+ const openaiBatchInputFileDefaultExpiresAfterSeconds = 48 * 60 * 60;
57
+
58
+ const openaiBatchProviderOptionsSchema = lazySchema(() =>
59
+ zodSchema(
60
+ z.object({
61
+ /**
62
+ * TTL in seconds for the uploaded batch input file, measured from
63
+ * upload time. OpenAI accepts integers between 3600 (1 hour) and
64
+ * 2592000 (30 days) inclusive. Defaults to 48 hours.
65
+ */
66
+ inputFileExpiresAfter: z
67
+ .number()
68
+ .int()
69
+ .min(3600)
70
+ .max(2_592_000)
71
+ .optional(),
72
+ }),
73
+ ),
74
+ );
56
75
 
57
76
  type OpenAIBatchRequest = Parameters<
58
77
  BatchLanguageModelV4['experimental_doStartBatch']
@@ -153,6 +172,13 @@ class OpenAIResponsesBatch {
153
172
  },
154
173
  ];
155
174
 
175
+ const batchOptions = await this.parseBatchProviderOptions(
176
+ options.providerOptions,
177
+ );
178
+ const inputFileExpiresAfterSeconds =
179
+ batchOptions?.inputFileExpiresAfter ??
180
+ openaiBatchInputFileDefaultExpiresAfterSeconds;
181
+
156
182
  for (const request of options.requests) {
157
183
  const preparedRequest = await this.options.prepareRequest(request);
158
184
 
@@ -200,7 +226,7 @@ class OpenAIResponsesBatch {
200
226
  formData.append('expires_after[anchor]', 'created_at');
201
227
  formData.append(
202
228
  'expires_after[seconds]',
203
- String(openaiBatchInputFileExpiresAfterSeconds),
229
+ String(inputFileExpiresAfterSeconds),
204
230
  );
205
231
 
206
232
  const { value: uploadedFile } = await postToApi({
@@ -211,9 +237,7 @@ class OpenAIResponsesBatch {
211
237
  values: {
212
238
  purpose: 'batch',
213
239
  'expires_after[anchor]': 'created_at',
214
- 'expires_after[seconds]': String(
215
- openaiBatchInputFileExpiresAfterSeconds,
216
- ),
240
+ 'expires_after[seconds]': String(inputFileExpiresAfterSeconds),
217
241
  file: {
218
242
  name: filename,
219
243
  type: file.type,
@@ -245,13 +269,44 @@ class OpenAIResponsesBatch {
245
269
  fetch: this.options.config.fetch,
246
270
  });
247
271
 
272
+ const inputFileExpiresAt = convertUnixTimestamp(uploadedFile.expires_at);
273
+
248
274
  return {
249
275
  batchId: batch.id,
250
276
  ...convertOpenAIBatchStatus(batch),
277
+ providerMetadata: {
278
+ openai: {
279
+ inputFileId: uploadedFile.id,
280
+ ...(inputFileExpiresAt != null ? { inputFileExpiresAt } : {}),
281
+ },
282
+ },
251
283
  warnings,
252
284
  };
253
285
  }
254
286
 
287
+ private async parseBatchProviderOptions(
288
+ providerOptions: BatchV4StartOptions<OpenAIBatchRequest>['providerOptions'],
289
+ ) {
290
+ const providerOptionsName = this.options.config.provider.includes('azure')
291
+ ? 'azure'
292
+ : 'openai';
293
+ let batchOptions = await parseProviderOptions({
294
+ provider: providerOptionsName,
295
+ providerOptions,
296
+ schema: openaiBatchProviderOptionsSchema,
297
+ });
298
+
299
+ if (batchOptions == null && providerOptionsName !== 'openai') {
300
+ batchOptions = await parseProviderOptions({
301
+ provider: 'openai',
302
+ providerOptions,
303
+ schema: openaiBatchProviderOptionsSchema,
304
+ });
305
+ }
306
+
307
+ return batchOptions;
308
+ }
309
+
255
310
  async getBatchStatus(
256
311
  options: BatchV4OperationOptions,
257
312
  ): Promise<BatchV4Status> {
@@ -1,19 +1,24 @@
1
- import type { LanguageModelV4Usage } from '@ai-sdk/provider';
1
+ import type { JSONObject, LanguageModelV4Usage } from '@ai-sdk/provider';
2
2
  import { createNullLanguageModelUsage } from '@ai-sdk/provider-utils';
3
3
 
4
- export type OpenAIResponsesUsage = {
4
+ export type OpenAIResponsesUsage = JSONObject & {
5
5
  input_tokens: number;
6
6
  output_tokens: number;
7
- input_tokens_details?: {
8
- cached_tokens?: number | null;
9
- cache_write_tokens?: number | null;
10
- orchestration_input_tokens?: number | null;
11
- orchestration_input_cached_tokens?: number | null;
12
- } | null;
13
- output_tokens_details?: {
14
- reasoning_tokens?: number | null;
15
- orchestration_output_tokens?: number | null;
16
- } | null;
7
+ total_tokens?: number;
8
+ input_tokens_details?:
9
+ | (JSONObject & {
10
+ cached_tokens?: number | null;
11
+ cache_write_tokens?: number | null;
12
+ orchestration_input_tokens?: number | null;
13
+ orchestration_input_cached_tokens?: number | null;
14
+ })
15
+ | null;
16
+ output_tokens_details?:
17
+ | (JSONObject & {
18
+ reasoning_tokens?: number | null;
19
+ orchestration_output_tokens?: number | null;
20
+ })
21
+ | null;
17
22
  };
18
23
 
19
24
  export function convertOpenAIResponsesUsage(
@@ -18,6 +18,37 @@ const jsonValueSchema: z.ZodType<JSONValue> = z.lazy(() =>
18
18
  ]),
19
19
  );
20
20
 
21
+ const jsonObjectSchema = z.record(z.string(), jsonValueSchema.optional());
22
+
23
+ const openaiResponsesUsageSchema = z.intersection(
24
+ jsonObjectSchema,
25
+ z.object({
26
+ input_tokens: z.number(),
27
+ input_tokens_details: z
28
+ .intersection(
29
+ jsonObjectSchema,
30
+ z.object({
31
+ cached_tokens: z.number().nullish(),
32
+ cache_write_tokens: z.number().nullish(),
33
+ orchestration_input_tokens: z.number().nullish(),
34
+ orchestration_input_cached_tokens: z.number().nullish(),
35
+ }),
36
+ )
37
+ .nullish(),
38
+ output_tokens: z.number(),
39
+ output_tokens_details: z
40
+ .intersection(
41
+ jsonObjectSchema,
42
+ z.object({
43
+ reasoning_tokens: z.number().nullish(),
44
+ orchestration_output_tokens: z.number().nullish(),
45
+ }),
46
+ )
47
+ .nullish(),
48
+ total_tokens: z.number().optional(),
49
+ }),
50
+ );
51
+
21
52
  const openaiResponsesComputerSafetyCheckSchema = z.object({
22
53
  id: z.string(),
23
54
  code: z.string().nullish(),
@@ -570,6 +601,7 @@ export type OpenAIResponsesTool =
570
601
  }
571
602
  | {
572
603
  type: 'image_generation';
604
+ action: 'generate' | 'edit' | 'auto' | undefined;
573
605
  background: 'auto' | 'opaque' | 'transparent' | undefined;
574
606
  input_fidelity: 'low' | 'high' | undefined;
575
607
  input_image_mask:
@@ -579,12 +611,18 @@ export type OpenAIResponsesTool =
579
611
  }
580
612
  | undefined;
581
613
  model: string | undefined;
582
- moderation: 'auto' | undefined;
614
+ moderation: 'auto' | 'low' | undefined;
583
615
  output_compression: number | undefined;
584
616
  output_format: 'png' | 'jpeg' | 'webp' | undefined;
585
617
  partial_images: number | undefined;
586
618
  quality: 'auto' | 'low' | 'medium' | 'high' | undefined;
587
- size: 'auto' | '1024x1024' | '1024x1536' | '1536x1024' | undefined;
619
+ size:
620
+ | 'auto'
621
+ | '1024x1024'
622
+ | '1024x1536'
623
+ | '1536x1024'
624
+ | (string & {})
625
+ | undefined;
588
626
  }
589
627
 
590
628
  /**
@@ -831,26 +869,7 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
831
869
  type: z.enum(['response.completed', 'response.incomplete']),
832
870
  response: z.object({
833
871
  incomplete_details: z.object({ reason: z.string() }).nullish(),
834
- usage: z
835
- .object({
836
- input_tokens: z.number(),
837
- input_tokens_details: z
838
- .object({
839
- cached_tokens: z.number().nullish(),
840
- cache_write_tokens: z.number().nullish(),
841
- orchestration_input_tokens: z.number().nullish(),
842
- orchestration_input_cached_tokens: z.number().nullish(),
843
- })
844
- .nullish(),
845
- output_tokens: z.number(),
846
- output_tokens_details: z
847
- .object({
848
- reasoning_tokens: z.number().nullish(),
849
- orchestration_output_tokens: z.number().nullish(),
850
- })
851
- .nullish(),
852
- })
853
- .nullish(),
872
+ usage: openaiResponsesUsageSchema.nullish(),
854
873
  reasoning: z
855
874
  .object({
856
875
  context: z.string().nullish(),
@@ -870,26 +889,7 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
870
889
  })
871
890
  .nullish(),
872
891
  incomplete_details: z.object({ reason: z.string() }).nullish(),
873
- usage: z
874
- .object({
875
- input_tokens: z.number(),
876
- input_tokens_details: z
877
- .object({
878
- cached_tokens: z.number().nullish(),
879
- cache_write_tokens: z.number().nullish(),
880
- orchestration_input_tokens: z.number().nullish(),
881
- orchestration_input_cached_tokens: z.number().nullish(),
882
- })
883
- .nullish(),
884
- output_tokens: z.number(),
885
- output_tokens_details: z
886
- .object({
887
- reasoning_tokens: z.number().nullish(),
888
- orchestration_output_tokens: z.number().nullish(),
889
- })
890
- .nullish(),
891
- })
892
- .nullish(),
892
+ usage: openaiResponsesUsageSchema.nullish(),
893
893
  reasoning: z
894
894
  .object({
895
895
  context: z.string().nullish(),
@@ -1745,26 +1745,7 @@ export const openaiResponsesResponseSchema = lazySchema(() =>
1745
1745
  })
1746
1746
  .nullish(),
1747
1747
  incomplete_details: z.object({ reason: z.string() }).nullish(),
1748
- usage: z
1749
- .object({
1750
- input_tokens: z.number(),
1751
- input_tokens_details: z
1752
- .object({
1753
- cached_tokens: z.number().nullish(),
1754
- cache_write_tokens: z.number().nullish(),
1755
- orchestration_input_tokens: z.number().nullish(),
1756
- orchestration_input_cached_tokens: z.number().nullish(),
1757
- })
1758
- .nullish(),
1759
- output_tokens: z.number(),
1760
- output_tokens_details: z
1761
- .object({
1762
- reasoning_tokens: z.number().nullish(),
1763
- orchestration_output_tokens: z.number().nullish(),
1764
- })
1765
- .nullish(),
1766
- })
1767
- .nullish(),
1748
+ usage: openaiResponsesUsageSchema.nullish(),
1768
1749
  }),
1769
1750
  ),
1770
1751
  );
@@ -294,11 +294,12 @@ export const openaiLanguageModelResponsesOptionsSchema = lazySchema(() =>
294
294
  * Set to 'flex' for 50% cheaper processing at the cost of increased latency (available for o3, o4-mini, and gpt-5 models).
295
295
  * Set to 'priority' for faster processing with Enterprise access (available for gpt-4, gpt-5, gpt-5-mini, o3, o4-mini; gpt-5-nano is not supported).
296
296
  * Set to 'fast' for the same tier as 'priority' (OpenAI's newer name for it).
297
+ * Set to 'ultrafast' for access-controlled Ultrafast processing (available only for gpt-5.6-sol).
297
298
  *
298
299
  * Defaults to 'auto'.
299
300
  */
300
301
  serviceTier: z
301
- .enum(['auto', 'flex', 'priority', 'fast', 'default'])
302
+ .enum(['auto', 'flex', 'priority', 'fast', 'ultrafast', 'default'])
302
303
  .nullish(),
303
304
 
304
305
  /**
@@ -302,6 +302,7 @@ export async function prepareResponsesTools({
302
302
 
303
303
  openaiTools.push({
304
304
  type: 'image_generation',
305
+ action: args.action,
305
306
  background: args.background,
306
307
  input_fidelity: args.inputFidelity,
307
308
  input_image_mask: args.inputImageMask
@@ -9,6 +9,7 @@ export const imageGenerationArgsSchema = lazySchema(() =>
9
9
  zodSchema(
10
10
  z
11
11
  .object({
12
+ action: z.enum(['generate', 'edit', 'auto']).optional(),
12
13
  background: z.enum(['auto', 'opaque', 'transparent']).optional(),
13
14
  inputFidelity: z.enum(['low', 'high']).optional(),
14
15
  inputImageMask: z
@@ -18,13 +19,16 @@ export const imageGenerationArgsSchema = lazySchema(() =>
18
19
  })
19
20
  .optional(),
20
21
  model: z.string().optional(),
21
- moderation: z.enum(['auto']).optional(),
22
+ moderation: z.enum(['auto', 'low']).optional(),
22
23
  outputCompression: z.number().int().min(0).max(100).optional(),
23
24
  outputFormat: z.enum(['png', 'jpeg', 'webp']).optional(),
24
25
  partialImages: z.number().int().min(0).max(3).optional(),
25
26
  quality: z.enum(['auto', 'low', 'medium', 'high']).optional(),
26
27
  size: z
27
- .enum(['1024x1024', '1024x1536', '1536x1024', 'auto'])
28
+ .union([
29
+ z.enum(['1024x1024', '1024x1536', '1536x1024', 'auto']),
30
+ z.string().regex(/^\d+x\d+$/),
31
+ ])
28
32
  .optional(),
29
33
  })
30
34
  .strict(),
@@ -38,6 +42,11 @@ export const imageGenerationOutputSchema = lazySchema(() =>
38
42
  );
39
43
 
40
44
  type ImageGenerationArgs = {
45
+ /**
46
+ * Whether to generate a new image or edit an existing image. Default: auto.
47
+ */
48
+ action?: 'generate' | 'edit' | 'auto';
49
+
41
50
  /**
42
51
  * Background type for the generated image. Default is 'auto'.
43
52
  */
@@ -70,9 +79,9 @@ type ImageGenerationArgs = {
70
79
  model?: string;
71
80
 
72
81
  /**
73
- * Moderation level for the generated image. Default: auto.
82
+ * Moderation level for the generated image. One of auto or low. Default: auto.
74
83
  */
75
- moderation?: 'auto';
84
+ moderation?: 'auto' | 'low';
76
85
 
77
86
  /**
78
87
  * Compression level for the output image. Default: 100.
@@ -98,10 +107,11 @@ type ImageGenerationArgs = {
98
107
 
99
108
  /**
100
109
  * The size of the generated image.
101
- * One of 1024x1024, 1024x1536, 1536x1024, or auto.
110
+ * One of 1024x1024, 1024x1536, 1536x1024, or auto. gpt-image-2 also accepts
111
+ * arbitrary WIDTHxHEIGHT sizes where both are divisible by 16, e.g. 1536x864.
102
112
  * Default: auto.
103
113
  */
104
- size?: 'auto' | '1024x1024' | '1024x1536' | '1536x1024';
114
+ size?: 'auto' | '1024x1024' | '1024x1536' | '1536x1024' | (string & {});
105
115
  };
106
116
 
107
117
  const imageGenerationToolFactory = createProviderExecutedToolFactory<