@ai-sdk/openai 3.0.136 → 3.0.137

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.
@@ -2755,6 +2755,8 @@ const { images } = await generateImage({
2755
2755
 
2756
2756
  | Model | Sizes |
2757
2757
  | ------------------------ | -------------------------------------- |
2758
+ | `gpt-image-2.6-flare` | Standard presets and custom dimensions |
2759
+ | `gpt-image-2.6-sunburst` | Standard presets and custom dimensions |
2758
2760
  | `gpt-image-2.5-flare` | Standard presets and custom dimensions |
2759
2761
  | `gpt-image-2.5-sunburst` | Standard presets and custom dimensions |
2760
2762
  | `gpt-image-2` | 1024x1024, 1536x1024, 1024x1536 |
@@ -2802,6 +2804,28 @@ const { image } = await generateImage({
2802
2804
  });
2803
2805
  ```
2804
2806
 
2807
+ The `gpt-image-2.6-flare` and `gpt-image-2.6-sunburst` models support these additional options:
2808
+
2809
+ - **complexity** _'low' | 'medium' | 'high'_ - how much detail the model puts into the image (generation and editing). The API defaults to `high`.
2810
+ - **outputFormat: 'gif'** _(generation only)_ - generates an animated GIF. Use **frameCount** (2-64, API default 9) and **frameDurationMs** (20-2000, API default 200) to control the animation.
2811
+ - **markup** _string_ _(editing only)_ - a transparent PNG (HTTPS URL or base64 data URL) overlaid on the first input image to mark up the regions to change. Supported by `gpt-image-2.5-*` and `gpt-image-2.6-*` models. It cannot be combined with `mask`; providing both throws an error.
2812
+
2813
+ ```ts
2814
+ const { image } = await generateImage({
2815
+ model: openai.image('gpt-image-2.6-flare'),
2816
+ prompt: 'A red panda waving hello, flat illustration',
2817
+ providerOptions: {
2818
+ openai: {
2819
+ outputFormat: 'gif',
2820
+ frameCount: 9,
2821
+ frameDurationMs: 200,
2822
+ } satisfies OpenAIImageModelGenerationOptions,
2823
+ },
2824
+ });
2825
+ ```
2826
+
2827
+ All image options also accept `safetyIdentifier` (max 128 characters) to help OpenAI detect abuse by your end users.
2828
+
2805
2829
  For more on `generateImage()` see [Image Generation](/docs/ai-sdk-core/image-generation).
2806
2830
 
2807
2831
  OpenAI's image models return additional metadata in the response that can be
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "3.0.136",
3
+ "version": "3.0.137",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -44,8 +44,8 @@
44
44
  "tsup": "^8",
45
45
  "typescript": "5.8.3",
46
46
  "zod": "3.25.76",
47
- "@vercel/ai-tsconfig": "0.0.0",
48
- "@ai-sdk/test-server": "1.0.6"
47
+ "@ai-sdk/test-server": "1.0.6",
48
+ "@vercel/ai-tsconfig": "0.0.0"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "zod": "^3.25.76 || ^4.1.8"
@@ -12,6 +12,8 @@ export type OpenAIImageModelId =
12
12
  | 'gpt-image-1-mini'
13
13
  | 'gpt-image-1.5'
14
14
  | 'gpt-image-2'
15
+ | 'gpt-image-2.6-flare'
16
+ | 'gpt-image-2.6-sunburst'
15
17
  | 'gpt-image-2.5-flare'
16
18
  | 'gpt-image-2.5-flare-2026-09-08'
17
19
  | 'gpt-image-2.5-sunburst'
@@ -27,6 +29,8 @@ export const modelMaxImagesPerCall: Record<OpenAIImageModelId, number> = {
27
29
  'gpt-image-1-mini': 10,
28
30
  'gpt-image-1.5': 10,
29
31
  'gpt-image-2': 10,
32
+ 'gpt-image-2.6-flare': 10,
33
+ 'gpt-image-2.6-sunburst': 10,
30
34
  'gpt-image-2.5-flare': 10,
31
35
  'gpt-image-2.5-flare-2026-09-08': 10,
32
36
  'gpt-image-2.5-sunburst': 10,
@@ -74,6 +78,12 @@ const baseImageModelOptionsObject = () =>
74
78
  */
75
79
  outputFormat: z.enum(['png', 'jpeg', 'webp']).optional(),
76
80
 
81
+ /**
82
+ * How much detail the model puts into the image. Supported by GPT Image
83
+ * 2.6 models. The API defaults to `high`.
84
+ */
85
+ complexity: z.enum(['low', 'medium', 'high']).optional(),
86
+
77
87
  /**
78
88
  * Compression level (0-100) for the generated image(s). Applies to the
79
89
  * `jpeg` and `webp` output formats.
@@ -85,6 +95,13 @@ const baseImageModelOptionsObject = () =>
85
95
  * to monitor and detect abuse.
86
96
  */
87
97
  user: z.string().optional(),
98
+
99
+ /**
100
+ * A stable identifier used to help detect users of your application that
101
+ * may be violating OpenAI's usage policies. Should be a hashed username
102
+ * or email address.
103
+ */
104
+ safetyIdentifier: z.string().max(128).optional(),
88
105
  });
89
106
 
90
107
  export const openaiImageModelOptions = lazySchema(() =>
@@ -105,6 +122,25 @@ export const openaiImageModelGenerationOptions = lazySchema(() =>
105
122
  */
106
123
  style: z.enum(['vivid', 'natural']).optional(),
107
124
 
125
+ /**
126
+ * Format in which the generated image(s) are returned. `gif` produces
127
+ * an animated GIF and is supported by GPT Image 2.6 models.
128
+ */
129
+ outputFormat: z.enum(['png', 'jpeg', 'webp', 'gif']).optional(),
130
+
131
+ /**
132
+ * Number of frames (2-64) of an animated GIF. Only applies to the `gif`
133
+ * output format. The API defaults to 9.
134
+ */
135
+ frameCount: z.number().int().min(2).max(64).optional(),
136
+
137
+ /**
138
+ * Duration of each frame in milliseconds (20-2000) of an animated GIF.
139
+ * The API rounds it to the nearest 10 ms. Only applies to the `gif`
140
+ * output format. The API defaults to 200.
141
+ */
142
+ frameDurationMs: z.number().int().min(20).max(2000).optional(),
143
+
108
144
  /**
109
145
  * Content moderation level for the generated image(s). `low` applies
110
146
  * less restrictive filtering.
@@ -125,6 +161,14 @@ export const openaiImageModelEditOptions = lazySchema(() =>
125
161
  * Fidelity of the output image(s) to the input image(s).
126
162
  */
127
163
  inputFidelity: z.enum(['high', 'low']).optional(),
164
+
165
+ /**
166
+ * A transparent PNG overlaid on the first input image to mark up the
167
+ * regions to change, as an HTTPS URL or a base64 data URL. It must match
168
+ * the dimensions of the first image. Supported by GPT Image 2.5 and 2.6
169
+ * models. Cannot be combined with a `mask`.
170
+ */
171
+ markup: z.string().optional(),
128
172
  }),
129
173
  ),
130
174
  );
@@ -1,7 +1,8 @@
1
- import type {
2
- ImageModelV3,
3
- ImageModelV3File,
4
- SharedV3Warning,
1
+ import {
2
+ InvalidArgumentError,
3
+ type ImageModelV3,
4
+ type ImageModelV3File,
5
+ type SharedV3Warning,
5
6
  } from '@ai-sdk/provider';
6
7
  import {
7
8
  combineHeaders,
@@ -86,6 +87,13 @@ export class OpenAIImageModel implements ImageModelV3 {
86
87
  schema: openaiImageModelEditOptions,
87
88
  })) ?? {};
88
89
 
90
+ if (mask != null && openaiOptions.markup != null) {
91
+ throw new InvalidArgumentError({
92
+ argument: 'providerOptions.openai.markup',
93
+ message: '`markup` cannot be combined with `mask`.',
94
+ });
95
+ }
96
+
89
97
  const { value: response, responseHeaders } = await postFormDataToApi({
90
98
  url: this.config.url({
91
99
  path: '/images/edits',
@@ -114,14 +122,20 @@ export class OpenAIImageModel implements ImageModelV3 {
114
122
  ),
115
123
  ),
116
124
  mask: mask != null ? await fileToBlob(mask) : undefined,
125
+ markup:
126
+ openaiOptions.markup != null
127
+ ? await markupToBlob(openaiOptions.markup)
128
+ : undefined,
117
129
  n,
118
130
  size,
119
131
  quality: openaiOptions.quality,
120
132
  background: openaiOptions.background,
121
133
  output_format: openaiOptions.outputFormat,
122
134
  output_compression: openaiOptions.outputCompression,
135
+ complexity: openaiOptions.complexity,
123
136
  input_fidelity: openaiOptions.inputFidelity,
124
137
  user: openaiOptions.user,
138
+ safety_identifier: openaiOptions.safetyIdentifier,
125
139
  }),
126
140
  failedResponseHandler: openaiFailedResponseHandler,
127
141
  successfulResponseHandler: createJsonResponseHandler(
@@ -193,7 +207,11 @@ export class OpenAIImageModel implements ImageModelV3 {
193
207
  moderation: openaiOptions.moderation,
194
208
  output_format: openaiOptions.outputFormat,
195
209
  output_compression: openaiOptions.outputCompression,
210
+ complexity: openaiOptions.complexity,
211
+ frame_count: openaiOptions.frameCount,
212
+ frame_duration_ms: openaiOptions.frameDurationMs,
196
213
  user: openaiOptions.user,
214
+ safety_identifier: openaiOptions.safetyIdentifier,
197
215
  ...(!hasDefaultResponseFormat(this.modelId)
198
216
  ? { response_format: 'b64_json' }
199
217
  : {}),
@@ -284,16 +302,38 @@ type OpenAIImageEditInput = {
284
302
  prompt?: string;
285
303
  image: Blob | Blob[];
286
304
  mask?: Blob;
305
+ markup?: Blob;
287
306
  n?: number;
288
307
  size?: `${number}x${number}`;
289
308
  quality?: OpenAIImageModelEditOptions['quality'];
290
309
  background?: OpenAIImageModelEditOptions['background'];
291
310
  output_format?: OpenAIImageModelEditOptions['outputFormat'];
292
311
  output_compression?: OpenAIImageModelEditOptions['outputCompression'];
312
+ complexity?: OpenAIImageModelEditOptions['complexity'];
293
313
  input_fidelity?: OpenAIImageModelEditOptions['inputFidelity'];
294
314
  user?: OpenAIImageModelEditOptions['user'];
315
+ safety_identifier?: OpenAIImageModelEditOptions['safetyIdentifier'];
295
316
  };
296
317
 
318
+ async function markupToBlob(markup: string): Promise<Blob> {
319
+ const dataUrl = /^data:([^;,]*)(;base64)?,(.*)$/s.exec(markup);
320
+
321
+ if (dataUrl == null) {
322
+ return downloadBlob(markup);
323
+ }
324
+
325
+ if (dataUrl[2] == null) {
326
+ throw new InvalidArgumentError({
327
+ argument: 'providerOptions.openai.markup',
328
+ message: '`markup` data URLs must be base64 encoded.',
329
+ });
330
+ }
331
+
332
+ return new Blob([convertBase64ToUint8Array(dataUrl[3]) as BlobPart], {
333
+ type: dataUrl[1] || 'image/png',
334
+ });
335
+ }
336
+
297
337
  async function fileToBlob(
298
338
  file: ImageModelV3File | undefined,
299
339
  ): Promise<Blob | undefined> {