@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.
- package/CHANGELOG.md +6 -0
- package/dist/index.d.ts +20 -1
- package/dist/index.js +324 -74
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +14 -1
- package/dist/internal/index.js +323 -73
- package/dist/internal/index.js.map +1 -1
- package/docs/03-openai.mdx +75 -16
- package/package.json +3 -3
- package/src/chat/convert-openai-chat-usage.ts +5 -2
- package/src/chat/convert-to-openai-chat-messages.ts +114 -7
- package/src/chat/openai-chat-api.ts +2 -0
- package/src/chat/openai-chat-language-model-options.ts +16 -2
- package/src/chat/openai-chat-language-model.ts +1 -0
- package/src/chat/openai-chat-prompt.ts +8 -4
- package/src/responses/convert-openai-responses-usage.ts +5 -2
- package/src/responses/convert-to-openai-responses-input.ts +123 -6
- package/src/responses/openai-responses-api.ts +77 -11
- package/src/responses/openai-responses-language-model-options.ts +32 -7
- package/src/responses/openai-responses-language-model.ts +37 -1
- package/src/responses/openai-responses-provider-metadata.ts +1 -0
package/docs/03-openai.mdx
CHANGED
|
@@ -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
|
-
|
|
195
|
-
|
|
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
|
|
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 } =
|
|
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
|
|
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
|
-
-
|
|
2190
|
-
|
|
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
|
-
|
|
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.
|
|
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',
|
|
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.
|
|
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
|
|
39
|
-
"@ai-sdk/provider": "
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
-
*
|
|
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:
|
|
50
|
+
cacheWrite: cacheWriteTokens,
|
|
48
51
|
},
|
|
49
52
|
outputTokens: {
|
|
50
53
|
total: outputTokens,
|