@ai-sdk/openai 4.0.10 → 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.
@@ -187,16 +187,20 @@ The following provider options are available:
187
187
  - **user** _string_
188
188
  A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. Defaults to `undefined`.
189
189
 
190
- - **reasoningEffort** _'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'_
190
+ - **reasoningEffort** _'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max'_
191
191
  Reasoning effort for reasoning models. Defaults to `medium`. If you use `providerOptions` to set the `reasoningEffort` option, this model setting will be ignored.
192
192
 
193
193
  <Note>
194
- The 'none' type for `reasoningEffort` is only available for OpenAI's GPT-5.1
195
- models. Also, the 'xhigh' type for `reasoningEffort` is only available for
196
- OpenAI's GPT-5.1-Codex-Max model. Setting `reasoningEffort` to 'none' or
197
- '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'`.
198
196
  </Note>
199
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
+
200
204
  - **reasoningSummary** _'auto' | 'detailed'_
201
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.
202
206
 
@@ -238,8 +242,11 @@ The following provider options are available:
238
242
  - **promptCacheKey** _string_
239
243
  A cache key for manual prompt caching control. Used by OpenAI to cache responses for similar requests to optimize your cache hit rates.
240
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
+
241
248
  - **promptCacheRetention** _'in_memory' | '24h'_
242
- 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.
243
250
 
244
251
  - **safetyIdentifier** _string_
245
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.
@@ -271,7 +278,8 @@ const providerMetadata = result.providerMetadata as
271
278
  | OpenaiResponsesProviderMetadata
272
279
  | undefined;
273
280
 
274
- const { responseId, logprobs, serviceTier } = providerMetadata?.openai ?? {};
281
+ const { responseId, logprobs, serviceTier, reasoningContext } =
282
+ providerMetadata?.openai ?? {};
275
283
 
276
284
  // responseId can be used to continue a conversation (previousResponseId).
277
285
  console.log(responseId);
@@ -285,6 +293,8 @@ The following OpenAI-specific metadata may be returned:
285
293
  Log probabilities of output tokens (when enabled).
286
294
  - **serviceTier** _(optional)_
287
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'`).
288
298
 
289
299
  #### Reasoning Output
290
300
 
@@ -1764,12 +1774,14 @@ The following optional provider options are available for OpenAI chat models:
1764
1774
  A unique identifier representing your end-user, which can help OpenAI to
1765
1775
  monitor and detect abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids).
1766
1776
 
1767
- - **reasoningEffort** _'minimal' | 'low' | 'medium' | 'high' | 'xhigh'_
1777
+ - **reasoningEffort** _'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max'_
1768
1778
 
1769
1779
  Reasoning effort for reasoning models. Defaults to `medium`. If you use
1770
1780
  `providerOptions` to set the `reasoningEffort` option, this
1771
1781
  model setting will be ignored.
1772
1782
 
1783
+ Supported reasoning efforts vary by model. GPT-5.6 supports `'none'`, `'low'`, `'medium'`, `'high'`, `'xhigh'`, and `'max'`.
1784
+
1773
1785
  - **maxCompletionTokens** _number_
1774
1786
 
1775
1787
  Maximum number of completion tokens to generate. Useful for reasoning models.
@@ -1807,9 +1819,13 @@ The following optional provider options are available for OpenAI chat models:
1807
1819
 
1808
1820
  A cache key for manual prompt caching control. Used by OpenAI to cache responses for similar requests to optimize your cache hit rates.
1809
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
+
1810
1826
  - **promptCacheRetention** _'in_memory' | '24h'_
1811
1827
 
1812
- 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.
1813
1829
 
1814
1830
  - **safetyIdentifier** _string_
1815
1831
 
@@ -2111,7 +2127,7 @@ const rejectedPredictionTokens = openaiMetadata?.rejectedPredictionTokens;
2111
2127
 
2112
2128
  #### Image Detail
2113
2129
 
2114
- 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`:
2115
2131
 
2116
2132
  ```ts highlight="13-16"
2117
2133
  const result = await generateText({
@@ -2137,6 +2153,8 @@ const result = await generateText({
2137
2153
  });
2138
2154
  ```
2139
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
+
2140
2158
  <Note type="warning">
2141
2159
  Because the `UIMessage` type (used by AI SDK UI hooks like `useChat`) does not
2142
2160
  support the `providerOptions` property, you can use `convertToModelMessages`
@@ -2186,9 +2204,8 @@ including `gpt-4o` and `gpt-4o-mini`.
2186
2204
  - Prompt caching is automatically enabled for these models, when the prompt is 1024 tokens or longer. It does
2187
2205
  not need to be explicitly enabled.
2188
2206
  - You can use the response `usage` to access the number of prompt tokens that were a cache hit via `usage.inputTokenDetails.cacheReadTokens`.
2189
- - Note that caching behavior is dependent on load on OpenAI's infrastructure. Prompt prefixes generally remain in the
2190
- cache following 5-10 minutes of inactivity before they are evicted, but during off-peak periods they may persist for up
2191
- 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.
2192
2209
 
2193
2210
  ```ts highlight="11"
2194
2211
  import { openai } from '@ai-sdk/openai';
@@ -2221,19 +2238,61 @@ const { text, usage } = await generateText({
2221
2238
  console.log('Cached tokens:', usage.inputTokenDetails.cacheReadTokens);
2222
2239
  ```
2223
2240
 
2224
- 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:
2225
2284
 
2226
2285
  ```ts highlight="7-12"
2227
2286
  import { openai, type OpenAILanguageModelChatOptions } from '@ai-sdk/openai';
2228
2287
  import { generateText } from 'ai';
2229
2288
 
2230
2289
  const { text, usage } = await generateText({
2231
- model: openai.chat('gpt-5.1'),
2290
+ model: openai.chat('gpt-5.5'),
2232
2291
  prompt: `A 1024-token or longer prompt...`,
2233
2292
  providerOptions: {
2234
2293
  openai: {
2235
2294
  promptCacheKey: 'my-custom-cache-key-123',
2236
- promptCacheRetention: '24h', // Extended caching for GPT-5.1
2295
+ promptCacheRetention: '24h',
2237
2296
  } satisfies OpenAILanguageModelChatOptions,
2238
2297
  },
2239
2298
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "4.0.10",
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-utils": "5.0.7",
39
- "@ai-sdk/provider": "4.0.3"
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
@@ -109,7 +109,7 @@ export const openaiLanguageModelChatOptions = lazySchema(() =>
109
109
  * Reasoning effort for reasoning models. Defaults to `medium`.
110
110
  */
111
111
  reasoningEffort: z
112
- .enum(['none', 'minimal', 'low', 'medium', 'high', 'xhigh'])
112
+ .enum(['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'])
113
113
  .optional(),
114
114
 
115
115
  /**
@@ -163,11 +163,25 @@ export const openaiLanguageModelChatOptions = lazySchema(() =>
163
163
  */
164
164
  promptCacheKey: z.string().optional(),
165
165
 
166
+ /**
167
+ * Prompt cache behavior for GPT-5.6 and later models.
168
+ * `mode` controls whether OpenAI also places an implicit breakpoint.
169
+ * `ttl` sets the minimum cache lifetime and currently only supports 30 minutes.
170
+ */
171
+ promptCacheOptions: z
172
+ .object({
173
+ mode: z.enum(['implicit', 'explicit']).optional(),
174
+ ttl: z.literal('30m').optional(),
175
+ })
176
+ .optional(),
177
+
166
178
  /**
167
179
  * The retention policy for the prompt cache.
168
180
  * - 'in_memory': Default. Standard prompt caching behavior.
169
181
  * - '24h': Extended prompt caching that keeps cached prefixes active for up to 24 hours.
170
- * Currently only available for 5.1 series models.
182
+ * Available for models before GPT-5.6 that support extended caching.
183
+ *
184
+ * @deprecated For GPT-5.6 and later models, use `promptCacheOptions.ttl`.
171
185
  *
172
186
  * @default 'in_memory'
173
187
  */
@@ -196,6 +196,7 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
196
196
  reasoning_effort: resolvedReasoningEffort,
197
197
  service_tier: openaiOptions.serviceTier,
198
198
  prompt_cache_key: openaiOptions.promptCacheKey,
199
+ prompt_cache_options: openaiOptions.promptCacheOptions,
199
200
  prompt_cache_retention: openaiOptions.promptCacheRetention,
200
201
  safety_identifier: openaiOptions.safetyIdentifier,
201
202
 
@@ -9,12 +9,12 @@ export type ChatCompletionMessage =
9
9
 
10
10
  export interface ChatCompletionSystemMessage {
11
11
  role: 'system';
12
- content: string;
12
+ content: string | Array<ChatCompletionContentPartText>;
13
13
  }
14
14
 
15
15
  export interface ChatCompletionDeveloperMessage {
16
16
  role: 'developer';
17
- content: string;
17
+ content: string | Array<ChatCompletionContentPartText>;
18
18
  }
19
19
 
20
20
  export interface ChatCompletionUserMessage {
@@ -31,26 +31,30 @@ export type ChatCompletionContentPart =
31
31
  export interface ChatCompletionContentPartText {
32
32
  type: 'text';
33
33
  text: string;
34
+ prompt_cache_breakpoint?: { mode: 'explicit' };
34
35
  }
35
36
 
36
37
  export interface ChatCompletionContentPartImage {
37
38
  type: 'image_url';
38
39
  image_url: { url: string };
40
+ prompt_cache_breakpoint?: { mode: 'explicit' };
39
41
  }
40
42
 
41
43
  export interface ChatCompletionContentPartInputAudio {
42
44
  type: 'input_audio';
43
45
  input_audio: { data: string; format: 'wav' | 'mp3' };
46
+ prompt_cache_breakpoint?: { mode: 'explicit' };
44
47
  }
45
48
 
46
49
  export interface ChatCompletionContentPartFile {
47
50
  type: 'file';
48
51
  file: { filename: string; file_data: string } | { file_id: string };
52
+ prompt_cache_breakpoint?: { mode: 'explicit' };
49
53
  }
50
54
 
51
55
  export interface ChatCompletionAssistantMessage {
52
56
  role: 'assistant';
53
- content?: string | null;
57
+ content?: string | null | Array<ChatCompletionContentPartText>;
54
58
  tool_calls?: Array<ChatCompletionMessageToolCall>;
55
59
  }
56
60
 
@@ -65,6 +69,6 @@ export interface ChatCompletionMessageToolCall {
65
69
 
66
70
  export interface ChatCompletionToolMessage {
67
71
  role: 'tool';
68
- content: string;
72
+ content: string | Array<ChatCompletionContentPartText>;
69
73
  tool_call_id: string;
70
74
  }
@@ -5,6 +5,7 @@ export type OpenAIResponsesUsage = {
5
5
  output_tokens: number;
6
6
  input_tokens_details?: {
7
7
  cached_tokens?: number | null;
8
+ cache_write_tokens?: number | null;
8
9
  orchestration_input_tokens?: number | null;
9
10
  orchestration_input_cached_tokens?: number | null;
10
11
  } | null;
@@ -37,14 +38,16 @@ export function convertOpenAIResponsesUsage(
37
38
  const inputTokens = usage.input_tokens;
38
39
  const outputTokens = usage.output_tokens;
39
40
  const cachedTokens = usage.input_tokens_details?.cached_tokens ?? 0;
41
+ const cacheWriteTokens =
42
+ usage.input_tokens_details?.cache_write_tokens ?? undefined;
40
43
  const reasoningTokens = usage.output_tokens_details?.reasoning_tokens ?? 0;
41
44
 
42
45
  return {
43
46
  inputTokens: {
44
47
  total: inputTokens,
45
- noCache: inputTokens - cachedTokens,
48
+ noCache: inputTokens - cachedTokens - (cacheWriteTokens ?? 0),
46
49
  cacheRead: cachedTokens,
47
- cacheWrite: undefined,
50
+ cacheWrite: cacheWriteTokens,
48
51
  },
49
52
  outputTokens: {
50
53
  total: outputTokens,