@ai-sdk/openai 4.0.9 → 4.0.11

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.
@@ -11,21 +11,7 @@ The [OpenAI](https://openai.com/) provider contains language model support for t
11
11
 
12
12
  The OpenAI provider is available in the `@ai-sdk/openai` module. You can install it with
13
13
 
14
- <Tabs items={['pnpm', 'npm', 'yarn', 'bun']}>
15
- <Tab>
16
- <Snippet text="pnpm add @ai-sdk/openai" dark />
17
- </Tab>
18
- <Tab>
19
- <Snippet text="npm install @ai-sdk/openai" dark />
20
- </Tab>
21
- <Tab>
22
- <Snippet text="yarn add @ai-sdk/openai" dark />
23
- </Tab>
24
-
25
- <Tab>
26
- <Snippet text="bun add @ai-sdk/openai" dark />
27
- </Tab>
28
- </Tabs>
14
+ <InstallPackages packages="@ai-sdk/openai" />
29
15
 
30
16
  ## Provider Instance
31
17
 
@@ -201,16 +187,20 @@ The following provider options are available:
201
187
  - **user** _string_
202
188
  A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. Defaults to `undefined`.
203
189
 
204
- - **reasoningEffort** _'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'_
190
+ - **reasoningEffort** _'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max'_
205
191
  Reasoning effort for reasoning models. Defaults to `medium`. If you use `providerOptions` to set the `reasoningEffort` option, this model setting will be ignored.
206
192
 
207
193
  <Note>
208
- The 'none' type for `reasoningEffort` is only available for OpenAI's GPT-5.1
209
- models. Also, the 'xhigh' type for `reasoningEffort` is only available for
210
- OpenAI's GPT-5.1-Codex-Max model. Setting `reasoningEffort` to 'none' or
211
- 'xhigh' with unsupported models will result in an error.
194
+ Supported reasoning efforts vary by model. GPT-5.6 supports `'none'`, `'low'`,
195
+ `'medium'`, `'high'`, `'xhigh'`, and `'max'`.
212
196
  </Note>
213
197
 
198
+ - **reasoningMode** _'standard' | 'pro'_
199
+ Controls how much model work GPT-5.6 performs before returning a final answer. `'standard'` is the default. Use `'pro'` for difficult tasks where quality matters more than latency and token usage.
200
+
201
+ - **reasoningContext** _'auto' | 'current_turn' | 'all_turns'_
202
+ Controls which available reasoning items GPT-5.6 can reuse. `'auto'` uses the model default, `'current_turn'` excludes reasoning from earlier turns, and `'all_turns'` makes compatible earlier reasoning available. The effective context is returned as `providerMetadata.openai.reasoningContext`.
203
+
214
204
  - **reasoningSummary** _'auto' | 'detailed'_
215
205
  Controls whether the model returns its reasoning process. Set to `'auto'` for a condensed summary, `'detailed'` for more comprehensive reasoning. Defaults to `undefined` (no reasoning summaries). When enabled, reasoning summaries appear in the stream as events with type `'reasoning'` and in non-streaming responses within the `reasoning` field.
216
206
 
@@ -252,8 +242,11 @@ The following provider options are available:
252
242
  - **promptCacheKey** _string_
253
243
  A cache key for manual prompt caching control. Used by OpenAI to cache responses for similar requests to optimize your cache hit rates.
254
244
 
245
+ - **promptCacheOptions** _object_
246
+ Configures prompt caching for GPT-5.6 and later models. `mode` can be `'implicit'` or `'explicit'`, and `ttl` currently only supports `'30m'`. In explicit mode, only content blocks marked with a prompt cache breakpoint are cached.
247
+
255
248
  - **promptCacheRetention** _'in_memory' | '24h'_
256
- The retention policy for the prompt cache. Set to `'24h'` to enable extended prompt caching, which keeps cached prefixes active for up to 24 hours. Defaults to `'in_memory'` for standard prompt caching. Note: `'24h'` is currently only available for the 5.1 series of models.
249
+ The legacy retention policy for models before GPT-5.6. Set to `'24h'` to enable extended prompt caching on supported models. For GPT-5.6 and later models, use `promptCacheOptions.ttl` instead.
257
250
 
258
251
  - **safetyIdentifier** _string_
259
252
  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.
@@ -285,7 +278,8 @@ const providerMetadata = result.providerMetadata as
285
278
  | OpenaiResponsesProviderMetadata
286
279
  | undefined;
287
280
 
288
- const { responseId, logprobs, serviceTier } = providerMetadata?.openai ?? {};
281
+ const { responseId, logprobs, serviceTier, reasoningContext } =
282
+ providerMetadata?.openai ?? {};
289
283
 
290
284
  // responseId can be used to continue a conversation (previousResponseId).
291
285
  console.log(responseId);
@@ -299,6 +293,8 @@ The following OpenAI-specific metadata may be returned:
299
293
  Log probabilities of output tokens (when enabled).
300
294
  - **serviceTier** _(optional)_
301
295
  Service tier information returned by the API.
296
+ - **reasoningContext** _(optional)_
297
+ Effective persisted-reasoning context returned by GPT-5.6 (`'current_turn'` or `'all_turns'`).
302
298
 
303
299
  #### Reasoning Output
304
300
 
@@ -363,20 +359,7 @@ The [`ai-sdk-openai-websocket-fetch`](https://www.npmjs.com/package/ai-sdk-opena
363
359
  package provides a drop-in `fetch` replacement that routes streaming requests
364
360
  through a persistent WebSocket connection.
365
361
 
366
- <Tabs items={['pnpm', 'npm', 'yarn', 'bun']}>
367
- <Tab>
368
- <Snippet text="pnpm add ai-sdk-openai-websocket-fetch" dark />
369
- </Tab>
370
- <Tab>
371
- <Snippet text="npm install ai-sdk-openai-websocket-fetch" dark />
372
- </Tab>
373
- <Tab>
374
- <Snippet text="yarn add ai-sdk-openai-websocket-fetch" dark />
375
- </Tab>
376
- <Tab>
377
- <Snippet text="bun add ai-sdk-openai-websocket-fetch" dark />
378
- </Tab>
379
- </Tabs>
362
+ <InstallPackages packages="ai-sdk-openai-websocket-fetch" />
380
363
 
381
364
  Pass the WebSocket fetch to `createOpenAI` via the `fetch` option:
382
365
 
@@ -1791,12 +1774,14 @@ The following optional provider options are available for OpenAI chat models:
1791
1774
  A unique identifier representing your end-user, which can help OpenAI to
1792
1775
  monitor and detect abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids).
1793
1776
 
1794
- - **reasoningEffort** _'minimal' | 'low' | 'medium' | 'high' | 'xhigh'_
1777
+ - **reasoningEffort** _'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max'_
1795
1778
 
1796
1779
  Reasoning effort for reasoning models. Defaults to `medium`. If you use
1797
1780
  `providerOptions` to set the `reasoningEffort` option, this
1798
1781
  model setting will be ignored.
1799
1782
 
1783
+ Supported reasoning efforts vary by model. GPT-5.6 supports `'none'`, `'low'`, `'medium'`, `'high'`, `'xhigh'`, and `'max'`.
1784
+
1800
1785
  - **maxCompletionTokens** _number_
1801
1786
 
1802
1787
  Maximum number of completion tokens to generate. Useful for reasoning models.
@@ -1834,9 +1819,13 @@ The following optional provider options are available for OpenAI chat models:
1834
1819
 
1835
1820
  A cache key for manual prompt caching control. Used by OpenAI to cache responses for similar requests to optimize your cache hit rates.
1836
1821
 
1822
+ - **promptCacheOptions** _object_
1823
+
1824
+ Configures prompt caching for GPT-5.6 and later models. `mode` can be `'implicit'` or `'explicit'`, and `ttl` currently only supports `'30m'`. In explicit mode, only content blocks marked with a prompt cache breakpoint are cached.
1825
+
1837
1826
  - **promptCacheRetention** _'in_memory' | '24h'_
1838
1827
 
1839
- The retention policy for the prompt cache. Set to `'24h'` to enable extended prompt caching, which keeps cached prefixes active for up to 24 hours. Defaults to `'in_memory'` for standard prompt caching. Note: `'24h'` is currently only available for the 5.1 series of models.
1828
+ The legacy retention policy for models before GPT-5.6. Set to `'24h'` to enable extended prompt caching on supported models. For GPT-5.6 and later models, use `promptCacheOptions.ttl` instead.
1840
1829
 
1841
1830
  - **safetyIdentifier** _string_
1842
1831
 
@@ -2138,7 +2127,7 @@ const rejectedPredictionTokens = openaiMetadata?.rejectedPredictionTokens;
2138
2127
 
2139
2128
  #### Image Detail
2140
2129
 
2141
- You can use the `openai` provider option to set the [image input detail](https://platform.openai.com/docs/guides/images-vision?api-mode=responses#specify-image-input-detail-level) to `high`, `low`, or `auto`:
2130
+ You can use the `openai` provider option to set the [image input detail](https://platform.openai.com/docs/guides/images-vision?api-mode=responses#specify-image-input-detail-level) to `high`, `low`, `original`, or `auto`:
2142
2131
 
2143
2132
  ```ts highlight="13-16"
2144
2133
  const result = await generateText({
@@ -2164,6 +2153,8 @@ const result = await generateText({
2164
2153
  });
2165
2154
  ```
2166
2155
 
2156
+ For GPT-5.6, `original` preserves the input dimensions without resizing to a patch budget or pixel-dimension limit. `auto` and an omitted detail setting use the same sizing behavior as `original`, which can increase input token usage for large images.
2157
+
2167
2158
  <Note type="warning">
2168
2159
  Because the `UIMessage` type (used by AI SDK UI hooks like `useChat`) does not
2169
2160
  support the `providerOptions` property, you can use `convertToModelMessages`
@@ -2213,9 +2204,8 @@ including `gpt-4o` and `gpt-4o-mini`.
2213
2204
  - Prompt caching is automatically enabled for these models, when the prompt is 1024 tokens or longer. It does
2214
2205
  not need to be explicitly enabled.
2215
2206
  - You can use the response `usage` to access the number of prompt tokens that were a cache hit via `usage.inputTokenDetails.cacheReadTokens`.
2216
- - Note that caching behavior is dependent on load on OpenAI's infrastructure. Prompt prefixes generally remain in the
2217
- cache following 5-10 minutes of inactivity before they are evicted, but during off-peak periods they may persist for up
2218
- to an hour.
2207
+ - For GPT-5.6 and later models, `usage.inputTokenDetails.cacheWriteTokens` reports tokens written to the cache.
2208
+ - For GPT-5.6 and later models, `promptCacheOptions.ttl` sets a minimum cache lifetime of 30 minutes. Earlier models generally retain in-memory prefixes for 5-10 minutes of inactivity, up to one hour.
2219
2209
 
2220
2210
  ```ts highlight="11"
2221
2211
  import { openai } from '@ai-sdk/openai';
@@ -2248,19 +2238,61 @@ const { text, usage } = await generateText({
2248
2238
  console.log('Cached tokens:', usage.inputTokenDetails.cacheReadTokens);
2249
2239
  ```
2250
2240
 
2251
- For GPT-5.1 models, you can enable extended prompt caching that keeps cached prefixes active for up to 24 hours:
2241
+ GPT-5.6 and later models support explicit cache breakpoints on text, image, and file content blocks. Set a request-level cache key and mark the end of each reusable prefix with `promptCacheBreakpoint`:
2242
+
2243
+ ```ts highlight="9-12,20-28"
2244
+ import {
2245
+ openai,
2246
+ type OpenAILanguageModelResponsesOptions,
2247
+ } from '@ai-sdk/openai';
2248
+ import { generateText } from 'ai';
2249
+
2250
+ const { usage } = await generateText({
2251
+ model: openai('gpt-5.6'),
2252
+ providerOptions: {
2253
+ openai: {
2254
+ promptCacheKey: 'tenant:acme:support-v1',
2255
+ promptCacheOptions: { mode: 'explicit', ttl: '30m' },
2256
+ } satisfies OpenAILanguageModelResponsesOptions,
2257
+ },
2258
+ messages: [
2259
+ {
2260
+ role: 'user',
2261
+ content: [
2262
+ {
2263
+ type: 'text',
2264
+ text: `A stable prefix of at least 1024 tokens...`,
2265
+ providerOptions: {
2266
+ openai: {
2267
+ promptCacheBreakpoint: { mode: 'explicit' },
2268
+ },
2269
+ },
2270
+ },
2271
+ { type: 'text', text: 'What should I do next?' },
2272
+ ],
2273
+ },
2274
+ ],
2275
+ });
2276
+
2277
+ console.log('Cache reads:', usage.inputTokenDetails.cacheReadTokens);
2278
+ console.log('Cache writes:', usage.inputTokenDetails.cacheWriteTokens);
2279
+ ```
2280
+
2281
+ In `'implicit'` mode, OpenAI places an automatic breakpoint on the latest message and also honors explicit breakpoints. In `'explicit'` mode, only marked content blocks are eligible for caching; a request without any explicit breakpoint does not use prompt caching.
2282
+
2283
+ For models before GPT-5.6 that support extended caching, you can keep cached prefixes active for up to 24 hours:
2252
2284
 
2253
2285
  ```ts highlight="7-12"
2254
2286
  import { openai, type OpenAILanguageModelChatOptions } from '@ai-sdk/openai';
2255
2287
  import { generateText } from 'ai';
2256
2288
 
2257
2289
  const { text, usage } = await generateText({
2258
- model: openai.chat('gpt-5.1'),
2290
+ model: openai.chat('gpt-5.5'),
2259
2291
  prompt: `A 1024-token or longer prompt...`,
2260
2292
  providerOptions: {
2261
2293
  openai: {
2262
2294
  promptCacheKey: 'my-custom-cache-key-123',
2263
- promptCacheRetention: '24h', // Extended caching for GPT-5.1
2295
+ promptCacheRetention: '24h',
2264
2296
  } satisfies OpenAILanguageModelChatOptions,
2265
2297
  },
2266
2298
  });
@@ -2374,32 +2406,36 @@ The following optional provider options are available for OpenAI completion mode
2374
2406
 
2375
2407
  ### Model Capabilities
2376
2408
 
2377
- | Model | Image Input | Audio Input | Object Generation | Tool Usage |
2378
- | --------------------- | ------------------- | ------------------- | ------------------- | ------------------- |
2379
- | `gpt-5.5` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2380
- | `gpt-5.4-pro` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2381
- | `gpt-5.4` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2382
- | `gpt-5.4-mini` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2383
- | `gpt-5.4-nano` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2384
- | `gpt-5.3-chat-latest` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2385
- | `gpt-5.2-pro` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2386
- | `gpt-5.2-chat-latest` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2387
- | `gpt-5.2` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2388
- | `gpt-5.1-codex-mini` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2389
- | `gpt-5.1-codex` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2390
- | `gpt-5.1-chat-latest` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2391
- | `gpt-5.1` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2392
- | `gpt-5-pro` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2393
- | `gpt-5` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2394
- | `gpt-5-mini` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2395
- | `gpt-5-nano` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2396
- | `gpt-5-codex` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2397
- | `gpt-5-chat-latest` | <Check size={18} /> | <Cross size={18} /> | <Cross size={18} /> | <Cross size={18} /> |
2398
- | `gpt-4.1` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2399
- | `gpt-4.1-mini` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2400
- | `gpt-4.1-nano` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2401
- | `gpt-4o` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2402
- | `gpt-4o-mini` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> |
2409
+ | Model | Image Input | Audio Input | Object Generation | Tool Usage |
2410
+ | --------------------- | ----------- | ----------- | ----------------- | ---------- |
2411
+ | `gpt-5.6` | <Check /> | <Cross /> | <Check /> | <Check /> |
2412
+ | `gpt-5.6-luna` | <Check /> | <Cross /> | <Check /> | <Check /> |
2413
+ | `gpt-5.6-sol` | <Check /> | <Cross /> | <Check /> | <Check /> |
2414
+ | `gpt-5.6-terra` | <Check /> | <Cross /> | <Check /> | <Check /> |
2415
+ | `gpt-5.5` | <Check /> | <Cross /> | <Check /> | <Check /> |
2416
+ | `gpt-5.4-pro` | <Check /> | <Cross /> | <Check /> | <Check /> |
2417
+ | `gpt-5.4` | <Check /> | <Cross /> | <Check /> | <Check /> |
2418
+ | `gpt-5.4-mini` | <Check /> | <Cross /> | <Check /> | <Check /> |
2419
+ | `gpt-5.4-nano` | <Check /> | <Cross /> | <Check /> | <Check /> |
2420
+ | `gpt-5.3-chat-latest` | <Check /> | <Cross /> | <Check /> | <Check /> |
2421
+ | `gpt-5.2-pro` | <Check /> | <Cross /> | <Check /> | <Check /> |
2422
+ | `gpt-5.2-chat-latest` | <Check /> | <Cross /> | <Check /> | <Check /> |
2423
+ | `gpt-5.2` | <Check /> | <Cross /> | <Check /> | <Check /> |
2424
+ | `gpt-5.1-codex-mini` | <Check /> | <Cross /> | <Check /> | <Check /> |
2425
+ | `gpt-5.1-codex` | <Check /> | <Cross /> | <Check /> | <Check /> |
2426
+ | `gpt-5.1-chat-latest` | <Check /> | <Cross /> | <Check /> | <Check /> |
2427
+ | `gpt-5.1` | <Check /> | <Cross /> | <Check /> | <Check /> |
2428
+ | `gpt-5-pro` | <Check /> | <Cross /> | <Check /> | <Check /> |
2429
+ | `gpt-5` | <Check /> | <Cross /> | <Check /> | <Check /> |
2430
+ | `gpt-5-mini` | <Check /> | <Cross /> | <Check /> | <Check /> |
2431
+ | `gpt-5-nano` | <Check /> | <Cross /> | <Check /> | <Check /> |
2432
+ | `gpt-5-codex` | <Check /> | <Cross /> | <Check /> | <Check /> |
2433
+ | `gpt-5-chat-latest` | <Check /> | <Cross /> | <Cross /> | <Cross /> |
2434
+ | `gpt-4.1` | <Check /> | <Cross /> | <Check /> | <Check /> |
2435
+ | `gpt-4.1-mini` | <Check /> | <Cross /> | <Check /> | <Check /> |
2436
+ | `gpt-4.1-nano` | <Check /> | <Cross /> | <Check /> | <Check /> |
2437
+ | `gpt-4o` | <Check /> | <Cross /> | <Check /> | <Check /> |
2438
+ | `gpt-4o-mini` | <Check /> | <Cross /> | <Check /> | <Check /> |
2403
2439
 
2404
2440
  <Note>
2405
2441
  The table above lists popular models. Please see the [OpenAI
@@ -2475,11 +2511,11 @@ The following optional provider options are available for OpenAI embedding model
2475
2511
 
2476
2512
  ### Model Capabilities
2477
2513
 
2478
- | Model | Default Dimensions | Custom Dimensions |
2479
- | ------------------------ | ------------------ | ------------------- |
2480
- | `text-embedding-3-large` | 3072 | <Check size={18} /> |
2481
- | `text-embedding-3-small` | 1536 | <Check size={18} /> |
2482
- | `text-embedding-ada-002` | 1536 | <Cross size={18} /> |
2514
+ | Model | Default Dimensions | Custom Dimensions |
2515
+ | ------------------------ | ------------------ | ----------------- |
2516
+ | `text-embedding-3-large` | 3072 | <Check /> |
2517
+ | `text-embedding-3-small` | 1536 | <Check /> |
2518
+ | `text-embedding-ada-002` | 1536 | <Cross /> |
2483
2519
 
2484
2520
  ## Image Models
2485
2521
 
@@ -2709,12 +2745,12 @@ The following provider options are available:
2709
2745
 
2710
2746
  ### Model Capabilities
2711
2747
 
2712
- | Model | Transcription | Streaming | Duration | Segments | Language |
2713
- | ------------------------ | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- |
2714
- | `whisper-1` | <Check size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
2715
- | `gpt-4o-mini-transcribe` | <Check size={18} /> | <Cross size={18} /> | <Cross size={18} /> | <Cross size={18} /> | <Cross size={18} /> |
2716
- | `gpt-4o-transcribe` | <Check size={18} /> | <Cross size={18} /> | <Cross size={18} /> | <Cross size={18} /> | <Cross size={18} /> |
2717
- | `gpt-realtime-whisper` | <Cross size={18} /> | <Check size={18} /> | <Cross size={18} /> | <Cross size={18} /> | <Cross size={18} /> |
2748
+ | Model | Transcription | Streaming | Duration | Segments | Language |
2749
+ | ------------------------ | ------------- | --------- | --------- | --------- | --------- |
2750
+ | `whisper-1` | <Check /> | <Cross /> | <Check /> | <Check /> | <Check /> |
2751
+ | `gpt-4o-mini-transcribe` | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
2752
+ | `gpt-4o-transcribe` | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
2753
+ | `gpt-realtime-whisper` | <Cross /> | <Check /> | <Cross /> | <Cross /> | <Cross /> |
2718
2754
 
2719
2755
  ## Speech Models
2720
2756
 
@@ -2771,8 +2807,8 @@ const result = await generateSpeech({
2771
2807
 
2772
2808
  ### Model Capabilities
2773
2809
 
2774
- | Model | Instructions |
2775
- | ----------------- | ------------------- |
2776
- | `tts-1` | <Check size={18} /> |
2777
- | `tts-1-hd` | <Check size={18} /> |
2778
- | `gpt-4o-mini-tts` | <Check size={18} /> |
2810
+ | Model | Instructions |
2811
+ | ----------------- | ------------ |
2812
+ | `tts-1` | <Check /> |
2813
+ | `tts-1-hd` | <Check /> |
2814
+ | `gpt-4o-mini-tts` | <Check /> |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "4.0.9",
3
+ "version": "4.0.11",
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.2",
39
- "@ai-sdk/provider-utils": "5.0.6"
38
+ "@ai-sdk/provider": "4.0.3",
39
+ "@ai-sdk/provider-utils": "5.0.7"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/node": "22.19.19",
@@ -6,6 +6,7 @@ export type OpenAIChatUsage = {
6
6
  total_tokens?: number | null;
7
7
  prompt_tokens_details?: {
8
8
  cached_tokens?: number | null;
9
+ cache_write_tokens?: number | null;
9
10
  } | null;
10
11
  completion_tokens_details?: {
11
12
  reasoning_tokens?: number | null;
@@ -37,15 +38,17 @@ export function convertOpenAIChatUsage(
37
38
  const promptTokens = usage.prompt_tokens ?? 0;
38
39
  const completionTokens = usage.completion_tokens ?? 0;
39
40
  const cachedTokens = usage.prompt_tokens_details?.cached_tokens ?? 0;
41
+ const cacheWriteTokens =
42
+ usage.prompt_tokens_details?.cache_write_tokens ?? undefined;
40
43
  const reasoningTokens =
41
44
  usage.completion_tokens_details?.reasoning_tokens ?? 0;
42
45
 
43
46
  return {
44
47
  inputTokens: {
45
48
  total: promptTokens,
46
- noCache: promptTokens - cachedTokens,
49
+ noCache: promptTokens - cachedTokens - (cacheWriteTokens ?? 0),
47
50
  cacheRead: cachedTokens,
48
- cacheWrite: undefined,
51
+ cacheWrite: cacheWriteTokens,
49
52
  },
50
53
  outputTokens: {
51
54
  total: completionTokens,
@@ -2,6 +2,7 @@ import {
2
2
  UnsupportedFunctionalityError,
3
3
  type SharedV4Warning,
4
4
  type LanguageModelV4Prompt,
5
+ type SharedV4ProviderOptions,
5
6
  } from '@ai-sdk/provider';
6
7
  import type { OpenAIChatPrompt } from './openai-chat-prompt';
7
8
  import {
@@ -15,6 +16,16 @@ function serializeToolCallArguments(input: unknown): string {
15
16
  return JSON.stringify(input === undefined ? {} : input);
16
17
  }
17
18
 
19
+ type OpenAIPromptCacheBreakpoint = { mode: 'explicit' };
20
+
21
+ function getPromptCacheBreakpoint(
22
+ providerOptions: SharedV4ProviderOptions | undefined,
23
+ ): OpenAIPromptCacheBreakpoint | undefined {
24
+ return providerOptions?.openai?.promptCacheBreakpoint as
25
+ | OpenAIPromptCacheBreakpoint
26
+ | undefined;
27
+ }
28
+
18
29
  export function convertToOpenAIChatMessages({
19
30
  prompt,
20
31
  systemMessageMode = 'system',
@@ -28,16 +39,44 @@ export function convertToOpenAIChatMessages({
28
39
  const messages: OpenAIChatPrompt = [];
29
40
  const warnings: Array<SharedV4Warning> = [];
30
41
 
31
- for (const { role, content } of prompt) {
42
+ for (const { role, content, providerOptions } of prompt) {
32
43
  switch (role) {
33
44
  case 'system': {
34
45
  switch (systemMessageMode) {
35
46
  case 'system': {
36
- messages.push({ role: 'system', content });
47
+ const promptCacheBreakpoint =
48
+ getPromptCacheBreakpoint(providerOptions);
49
+ messages.push({
50
+ role: 'system',
51
+ content:
52
+ promptCacheBreakpoint == null
53
+ ? content
54
+ : [
55
+ {
56
+ type: 'text',
57
+ text: content,
58
+ prompt_cache_breakpoint: promptCacheBreakpoint,
59
+ },
60
+ ],
61
+ });
37
62
  break;
38
63
  }
39
64
  case 'developer': {
40
- messages.push({ role: 'developer', content });
65
+ const promptCacheBreakpoint =
66
+ getPromptCacheBreakpoint(providerOptions);
67
+ messages.push({
68
+ role: 'developer',
69
+ content:
70
+ promptCacheBreakpoint == null
71
+ ? content
72
+ : [
73
+ {
74
+ type: 'text',
75
+ text: content,
76
+ prompt_cache_breakpoint: promptCacheBreakpoint,
77
+ },
78
+ ],
79
+ });
41
80
  break;
42
81
  }
43
82
  case 'remove': {
@@ -58,7 +97,11 @@ export function convertToOpenAIChatMessages({
58
97
  }
59
98
 
60
99
  case 'user': {
61
- if (content.length === 1 && content[0].type === 'text') {
100
+ if (
101
+ content.length === 1 &&
102
+ content[0].type === 'text' &&
103
+ getPromptCacheBreakpoint(content[0].providerOptions) == null
104
+ ) {
62
105
  messages.push({ role: 'user', content: content[0].text });
63
106
  break;
64
107
  }
@@ -68,9 +111,21 @@ export function convertToOpenAIChatMessages({
68
111
  content: content.map((part, index) => {
69
112
  switch (part.type) {
70
113
  case 'text': {
71
- return { type: 'text', text: part.text };
114
+ const promptCacheBreakpoint = getPromptCacheBreakpoint(
115
+ part.providerOptions,
116
+ );
117
+ return {
118
+ type: 'text',
119
+ text: part.text,
120
+ ...(promptCacheBreakpoint != null && {
121
+ prompt_cache_breakpoint: promptCacheBreakpoint,
122
+ }),
123
+ };
72
124
  }
73
125
  case 'file': {
126
+ const promptCacheBreakpoint = getPromptCacheBreakpoint(
127
+ part.providerOptions,
128
+ );
74
129
  switch (part.data.type) {
75
130
  case 'reference': {
76
131
  return {
@@ -81,6 +136,9 @@ export function convertToOpenAIChatMessages({
81
136
  provider: 'openai',
82
137
  }),
83
138
  },
139
+ ...(promptCacheBreakpoint != null && {
140
+ prompt_cache_breakpoint: promptCacheBreakpoint,
141
+ }),
84
142
  };
85
143
  }
86
144
  case 'text': {
@@ -103,6 +161,9 @@ export function convertToOpenAIChatMessages({
103
161
 
104
162
  detail: part.providerOptions?.openai?.imageDetail,
105
163
  },
164
+ ...(promptCacheBreakpoint != null && {
165
+ prompt_cache_breakpoint: promptCacheBreakpoint,
166
+ }),
106
167
  };
107
168
  } else if (topLevel === 'audio') {
108
169
  if (part.data.type === 'url') {
@@ -121,6 +182,9 @@ export function convertToOpenAIChatMessages({
121
182
  data: convertToBase64(part.data.data),
122
183
  format: 'wav',
123
184
  },
185
+ ...(promptCacheBreakpoint != null && {
186
+ prompt_cache_breakpoint: promptCacheBreakpoint,
187
+ }),
124
188
  };
125
189
  }
126
190
  case 'audio/mp3':
@@ -131,6 +195,9 @@ export function convertToOpenAIChatMessages({
131
195
  data: convertToBase64(part.data.data),
132
196
  format: 'mp3',
133
197
  },
198
+ ...(promptCacheBreakpoint != null && {
199
+ prompt_cache_breakpoint: promptCacheBreakpoint,
200
+ }),
134
201
  };
135
202
  }
136
203
 
@@ -161,6 +228,9 @@ export function convertToOpenAIChatMessages({
161
228
  filename: part.filename ?? `part-${index}.pdf`,
162
229
  file_data: `data:application/pdf;base64,${convertToBase64(part.data.data)}`,
163
230
  },
231
+ ...(promptCacheBreakpoint != null && {
232
+ prompt_cache_breakpoint: promptCacheBreakpoint,
233
+ }),
164
234
  };
165
235
  }
166
236
  }
@@ -175,6 +245,12 @@ export function convertToOpenAIChatMessages({
175
245
 
176
246
  case 'assistant': {
177
247
  let text = '';
248
+ const textParts: Array<{
249
+ type: 'text';
250
+ text: string;
251
+ prompt_cache_breakpoint?: OpenAIPromptCacheBreakpoint;
252
+ }> = [];
253
+ let hasPromptCacheBreakpoint = false;
178
254
  const toolCalls: Array<{
179
255
  id: string;
180
256
  type: 'function';
@@ -184,7 +260,18 @@ export function convertToOpenAIChatMessages({
184
260
  for (const part of content) {
185
261
  switch (part.type) {
186
262
  case 'text': {
263
+ const promptCacheBreakpoint = getPromptCacheBreakpoint(
264
+ part.providerOptions,
265
+ );
187
266
  text += part.text;
267
+ textParts.push({
268
+ type: 'text',
269
+ text: part.text,
270
+ ...(promptCacheBreakpoint != null && {
271
+ prompt_cache_breakpoint: promptCacheBreakpoint,
272
+ }),
273
+ });
274
+ hasPromptCacheBreakpoint ||= promptCacheBreakpoint != null;
188
275
  break;
189
276
  }
190
277
  case 'tool-call': {
@@ -203,7 +290,11 @@ export function convertToOpenAIChatMessages({
203
290
 
204
291
  messages.push({
205
292
  role: 'assistant',
206
- content: toolCalls.length > 0 ? text || null : text,
293
+ content: hasPromptCacheBreakpoint
294
+ ? textParts
295
+ : toolCalls.length > 0
296
+ ? text || null
297
+ : text,
207
298
  tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
208
299
  });
209
300
 
@@ -216,6 +307,13 @@ export function convertToOpenAIChatMessages({
216
307
  continue;
217
308
  }
218
309
  const output = toolResponse.output;
310
+ const promptCacheBreakpoint =
311
+ (output.type === 'content'
312
+ ? output.value
313
+ .map(part => getPromptCacheBreakpoint(part.providerOptions))
314
+ .find(breakpoint => breakpoint != null)
315
+ : getPromptCacheBreakpoint(output.providerOptions)) ??
316
+ getPromptCacheBreakpoint(toolResponse.providerOptions);
219
317
 
220
318
  let contentValue: string;
221
319
  switch (output.type) {
@@ -236,7 +334,16 @@ export function convertToOpenAIChatMessages({
236
334
  messages.push({
237
335
  role: 'tool',
238
336
  tool_call_id: toolResponse.toolCallId,
239
- content: contentValue,
337
+ content:
338
+ promptCacheBreakpoint == null
339
+ ? contentValue
340
+ : [
341
+ {
342
+ type: 'text',
343
+ text: contentValue,
344
+ prompt_cache_breakpoint: promptCacheBreakpoint,
345
+ },
346
+ ],
240
347
  });
241
348
  }
242
349
  break;
@@ -92,6 +92,7 @@ export const openaiChatResponseSchema = lazySchema(() =>
92
92
  prompt_tokens_details: z
93
93
  .object({
94
94
  cached_tokens: z.number().nullish(),
95
+ cache_write_tokens: z.number().nullish(),
95
96
  })
96
97
  .nullish(),
97
98
  completion_tokens_details: z
@@ -180,6 +181,7 @@ export const openaiChatChunkSchema = lazySchema(() =>
180
181
  prompt_tokens_details: z
181
182
  .object({
182
183
  cached_tokens: z.number().nullish(),
184
+ cache_write_tokens: z.number().nullish(),
183
185
  })
184
186
  .nullish(),
185
187
  completion_tokens_details: z