@ai-sdk/openai 3.0.83 → 3.0.84
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.mts +20 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.js +307 -66
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +307 -66
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.d.mts +14 -1
- package/dist/internal/index.d.ts +14 -1
- package/dist/internal/index.js +306 -65
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/index.mjs +306 -65
- package/dist/internal/index.mjs.map +1 -1
- package/docs/03-openai.mdx +81 -31
- package/package.json +1 -1
- package/src/chat/convert-openai-chat-usage.ts +5 -2
- package/src/chat/convert-to-openai-chat-messages.ts +111 -7
- package/src/chat/openai-chat-api.ts +2 -0
- package/src/chat/openai-chat-language-model.ts +1 -0
- package/src/chat/openai-chat-options.ts +16 -2
- 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 +117 -6
- package/src/responses/openai-responses-api.ts +77 -11
- package/src/responses/openai-responses-language-model.ts +37 -1
- package/src/responses/openai-responses-options.ts +32 -7
- package/src/responses/openai-responses-provider-metadata.ts +1 -0
package/docs/03-openai.mdx
CHANGED
|
@@ -201,16 +201,20 @@ The following provider options are available:
|
|
|
201
201
|
- **user** _string_
|
|
202
202
|
A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. Defaults to `undefined`.
|
|
203
203
|
|
|
204
|
-
- **reasoningEffort** _'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'_
|
|
204
|
+
- **reasoningEffort** _'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max'_
|
|
205
205
|
Reasoning effort for reasoning models. Defaults to `medium`. If you use `providerOptions` to set the `reasoningEffort` option, this model setting will be ignored.
|
|
206
206
|
|
|
207
207
|
<Note>
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
OpenAI's GPT-5.1-Codex-Max model. Setting `reasoningEffort` to 'none' or
|
|
211
|
-
'xhigh' with unsupported models will result in an error.
|
|
208
|
+
Supported reasoning efforts vary by model. GPT-5.6 supports `'none'`, `'low'`,
|
|
209
|
+
`'medium'`, `'high'`, `'xhigh'`, and `'max'`.
|
|
212
210
|
</Note>
|
|
213
211
|
|
|
212
|
+
- **reasoningMode** _'standard' | 'pro'_
|
|
213
|
+
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.
|
|
214
|
+
|
|
215
|
+
- **reasoningContext** _'auto' | 'current_turn' | 'all_turns'_
|
|
216
|
+
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`.
|
|
217
|
+
|
|
214
218
|
- **reasoningSummary** _'auto' | 'detailed'_
|
|
215
219
|
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
220
|
|
|
@@ -253,8 +257,11 @@ The following provider options are available:
|
|
|
253
257
|
- **promptCacheKey** _string_
|
|
254
258
|
A cache key for manual prompt caching control. Used by OpenAI to cache responses for similar requests to optimize your cache hit rates.
|
|
255
259
|
|
|
260
|
+
- **promptCacheOptions** _object_
|
|
261
|
+
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.
|
|
262
|
+
|
|
256
263
|
- **promptCacheRetention** _'in_memory' | '24h'_
|
|
257
|
-
The retention policy for
|
|
264
|
+
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.
|
|
258
265
|
|
|
259
266
|
- **safetyIdentifier** _string_
|
|
260
267
|
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.
|
|
@@ -281,7 +288,8 @@ const providerMetadata = result.providerMetadata as
|
|
|
281
288
|
| OpenaiResponsesProviderMetadata
|
|
282
289
|
| undefined;
|
|
283
290
|
|
|
284
|
-
const { responseId, logprobs, serviceTier } =
|
|
291
|
+
const { responseId, logprobs, serviceTier, reasoningContext } =
|
|
292
|
+
providerMetadata?.openai ?? {};
|
|
285
293
|
|
|
286
294
|
// responseId can be used to continue a conversation (previousResponseId).
|
|
287
295
|
console.log(responseId);
|
|
@@ -295,6 +303,8 @@ The following OpenAI-specific metadata may be returned:
|
|
|
295
303
|
Log probabilities of output tokens (when enabled).
|
|
296
304
|
- **serviceTier** _(optional)_
|
|
297
305
|
Service tier information returned by the API.
|
|
306
|
+
- **reasoningContext** _(optional)_
|
|
307
|
+
Effective persisted-reasoning context returned by GPT-5.6 (`'current_turn'` or `'all_turns'`).
|
|
298
308
|
|
|
299
309
|
#### Reasoning Output
|
|
300
310
|
|
|
@@ -1671,12 +1681,14 @@ The following optional provider options are available for OpenAI chat models:
|
|
|
1671
1681
|
A unique identifier representing your end-user, which can help OpenAI to
|
|
1672
1682
|
monitor and detect abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids).
|
|
1673
1683
|
|
|
1674
|
-
- **reasoningEffort** _'minimal' | 'low' | 'medium' | 'high' | 'xhigh'_
|
|
1684
|
+
- **reasoningEffort** _'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max'_
|
|
1675
1685
|
|
|
1676
1686
|
Reasoning effort for reasoning models. Defaults to `medium`. If you use
|
|
1677
1687
|
`providerOptions` to set the `reasoningEffort` option, this
|
|
1678
1688
|
model setting will be ignored.
|
|
1679
1689
|
|
|
1690
|
+
Supported reasoning efforts vary by model. GPT-5.6 supports `'none'`, `'low'`, `'medium'`, `'high'`, `'xhigh'`, and `'max'`.
|
|
1691
|
+
|
|
1680
1692
|
- **maxCompletionTokens** _number_
|
|
1681
1693
|
|
|
1682
1694
|
Maximum number of completion tokens to generate. Useful for reasoning models.
|
|
@@ -1714,9 +1726,13 @@ The following optional provider options are available for OpenAI chat models:
|
|
|
1714
1726
|
|
|
1715
1727
|
A cache key for manual prompt caching control. Used by OpenAI to cache responses for similar requests to optimize your cache hit rates.
|
|
1716
1728
|
|
|
1729
|
+
- **promptCacheOptions** _object_
|
|
1730
|
+
|
|
1731
|
+
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.
|
|
1732
|
+
|
|
1717
1733
|
- **promptCacheRetention** _'in_memory' | '24h'_
|
|
1718
1734
|
|
|
1719
|
-
The retention policy for
|
|
1735
|
+
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.
|
|
1720
1736
|
|
|
1721
1737
|
- **safetyIdentifier** _string_
|
|
1722
1738
|
|
|
@@ -2021,7 +2037,7 @@ const rejectedPredictionTokens = openaiMetadata?.rejectedPredictionTokens;
|
|
|
2021
2037
|
|
|
2022
2038
|
#### Image Detail
|
|
2023
2039
|
|
|
2024
|
-
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`:
|
|
2040
|
+
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`:
|
|
2025
2041
|
|
|
2026
2042
|
```ts highlight="13-16"
|
|
2027
2043
|
const result = await generateText({
|
|
@@ -2047,6 +2063,8 @@ const result = await generateText({
|
|
|
2047
2063
|
});
|
|
2048
2064
|
```
|
|
2049
2065
|
|
|
2066
|
+
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.
|
|
2067
|
+
|
|
2050
2068
|
<Note type="warning">
|
|
2051
2069
|
Because the `UIMessage` type (used by AI SDK UI hooks like `useChat`) does not
|
|
2052
2070
|
support the `providerOptions` property, you can use `convertToModelMessages`
|
|
@@ -2095,24 +2113,20 @@ including `gpt-4o` and `gpt-4o-mini`.
|
|
|
2095
2113
|
|
|
2096
2114
|
- Prompt caching is automatically enabled for these models, when the prompt is 1024 tokens or longer. It does
|
|
2097
2115
|
not need to be explicitly enabled.
|
|
2098
|
-
- You can use response `
|
|
2099
|
-
-
|
|
2100
|
-
|
|
2101
|
-
to an hour.
|
|
2116
|
+
- You can use the response `usage` to access the number of prompt tokens that were a cache hit via `usage.inputTokenDetails.cacheReadTokens`.
|
|
2117
|
+
- For GPT-5.6 and later models, `usage.inputTokenDetails.cacheWriteTokens` reports tokens written to the cache.
|
|
2118
|
+
- 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.
|
|
2102
2119
|
|
|
2103
2120
|
```ts highlight="11"
|
|
2104
2121
|
import { openai } from '@ai-sdk/openai';
|
|
2105
2122
|
import { generateText } from 'ai';
|
|
2106
2123
|
|
|
2107
|
-
const { text, usage
|
|
2124
|
+
const { text, usage } = await generateText({
|
|
2108
2125
|
model: openai.chat('gpt-4o-mini'),
|
|
2109
2126
|
prompt: `A 1024-token or longer prompt...`,
|
|
2110
2127
|
});
|
|
2111
2128
|
|
|
2112
|
-
console.log(
|
|
2113
|
-
...usage,
|
|
2114
|
-
cachedPromptTokens: providerMetadata?.openai?.cachedPromptTokens,
|
|
2115
|
-
});
|
|
2129
|
+
console.log('Cached tokens:', usage.inputTokenDetails.cacheReadTokens);
|
|
2116
2130
|
```
|
|
2117
2131
|
|
|
2118
2132
|
To improve cache hit rates, you can manually control caching using the `promptCacheKey` option:
|
|
@@ -2121,7 +2135,7 @@ To improve cache hit rates, you can manually control caching using the `promptCa
|
|
|
2121
2135
|
import { openai, type OpenAILanguageModelChatOptions } from '@ai-sdk/openai';
|
|
2122
2136
|
import { generateText } from 'ai';
|
|
2123
2137
|
|
|
2124
|
-
const { text, usage
|
|
2138
|
+
const { text, usage } = await generateText({
|
|
2125
2139
|
model: openai.chat('gpt-5'),
|
|
2126
2140
|
prompt: `A 1024-token or longer prompt...`,
|
|
2127
2141
|
providerOptions: {
|
|
@@ -2131,33 +2145,69 @@ const { text, usage, providerMetadata } = await generateText({
|
|
|
2131
2145
|
},
|
|
2132
2146
|
});
|
|
2133
2147
|
|
|
2134
|
-
console.log(
|
|
2135
|
-
|
|
2136
|
-
|
|
2148
|
+
console.log('Cached tokens:', usage.inputTokenDetails.cacheReadTokens);
|
|
2149
|
+
```
|
|
2150
|
+
|
|
2151
|
+
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`:
|
|
2152
|
+
|
|
2153
|
+
```ts highlight="9-12,20-28"
|
|
2154
|
+
import {
|
|
2155
|
+
openai,
|
|
2156
|
+
type OpenAILanguageModelResponsesOptions,
|
|
2157
|
+
} from '@ai-sdk/openai';
|
|
2158
|
+
import { generateText } from 'ai';
|
|
2159
|
+
|
|
2160
|
+
const { usage } = await generateText({
|
|
2161
|
+
model: openai('gpt-5.6'),
|
|
2162
|
+
providerOptions: {
|
|
2163
|
+
openai: {
|
|
2164
|
+
promptCacheKey: 'tenant:acme:support-v1',
|
|
2165
|
+
promptCacheOptions: { mode: 'explicit', ttl: '30m' },
|
|
2166
|
+
} satisfies OpenAILanguageModelResponsesOptions,
|
|
2167
|
+
},
|
|
2168
|
+
messages: [
|
|
2169
|
+
{
|
|
2170
|
+
role: 'user',
|
|
2171
|
+
content: [
|
|
2172
|
+
{
|
|
2173
|
+
type: 'text',
|
|
2174
|
+
text: `A stable prefix of at least 1024 tokens...`,
|
|
2175
|
+
providerOptions: {
|
|
2176
|
+
openai: {
|
|
2177
|
+
promptCacheBreakpoint: { mode: 'explicit' },
|
|
2178
|
+
},
|
|
2179
|
+
},
|
|
2180
|
+
},
|
|
2181
|
+
{ type: 'text', text: 'What should I do next?' },
|
|
2182
|
+
],
|
|
2183
|
+
},
|
|
2184
|
+
],
|
|
2137
2185
|
});
|
|
2186
|
+
|
|
2187
|
+
console.log('Cache reads:', usage.inputTokenDetails.cacheReadTokens);
|
|
2188
|
+
console.log('Cache writes:', usage.inputTokenDetails.cacheWriteTokens);
|
|
2138
2189
|
```
|
|
2139
2190
|
|
|
2140
|
-
|
|
2191
|
+
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.
|
|
2192
|
+
|
|
2193
|
+
For models before GPT-5.6 that support extended caching, you can keep cached prefixes active for up to 24 hours:
|
|
2141
2194
|
|
|
2142
2195
|
```ts highlight="7-12"
|
|
2143
2196
|
import { openai, type OpenAILanguageModelChatOptions } from '@ai-sdk/openai';
|
|
2144
2197
|
import { generateText } from 'ai';
|
|
2145
2198
|
|
|
2146
|
-
const { text, usage
|
|
2147
|
-
model: openai.chat('gpt-5.
|
|
2199
|
+
const { text, usage } = await generateText({
|
|
2200
|
+
model: openai.chat('gpt-5.5'),
|
|
2148
2201
|
prompt: `A 1024-token or longer prompt...`,
|
|
2149
2202
|
providerOptions: {
|
|
2150
2203
|
openai: {
|
|
2151
2204
|
promptCacheKey: 'my-custom-cache-key-123',
|
|
2152
|
-
promptCacheRetention: '24h',
|
|
2205
|
+
promptCacheRetention: '24h',
|
|
2153
2206
|
} satisfies OpenAILanguageModelChatOptions,
|
|
2154
2207
|
},
|
|
2155
2208
|
});
|
|
2156
2209
|
|
|
2157
|
-
console.log(
|
|
2158
|
-
...usage,
|
|
2159
|
-
cachedPromptTokens: providerMetadata?.openai?.cachedPromptTokens,
|
|
2160
|
-
});
|
|
2210
|
+
console.log('Cached tokens:', usage.inputTokenDetails.cacheReadTokens);
|
|
2161
2211
|
```
|
|
2162
2212
|
|
|
2163
2213
|
#### Audio Input
|
package/package.json
CHANGED
|
@@ -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 SharedV3Warning,
|
|
4
4
|
type LanguageModelV3Prompt,
|
|
5
|
+
type SharedV3ProviderOptions,
|
|
5
6
|
} from '@ai-sdk/provider';
|
|
6
7
|
import type { OpenAIChatPrompt } from './openai-chat-prompt';
|
|
7
8
|
import { convertToBase64 } from '@ai-sdk/provider-utils';
|
|
@@ -10,6 +11,16 @@ function serializeToolCallArguments(input: unknown): string {
|
|
|
10
11
|
return JSON.stringify(input === undefined ? {} : input);
|
|
11
12
|
}
|
|
12
13
|
|
|
14
|
+
type OpenAIPromptCacheBreakpoint = { mode: 'explicit' };
|
|
15
|
+
|
|
16
|
+
function getPromptCacheBreakpoint(
|
|
17
|
+
providerOptions: SharedV3ProviderOptions | undefined,
|
|
18
|
+
): OpenAIPromptCacheBreakpoint | undefined {
|
|
19
|
+
return providerOptions?.openai?.promptCacheBreakpoint as
|
|
20
|
+
| OpenAIPromptCacheBreakpoint
|
|
21
|
+
| undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
13
24
|
export function convertToOpenAIChatMessages({
|
|
14
25
|
prompt,
|
|
15
26
|
systemMessageMode = 'system',
|
|
@@ -23,16 +34,44 @@ export function convertToOpenAIChatMessages({
|
|
|
23
34
|
const messages: OpenAIChatPrompt = [];
|
|
24
35
|
const warnings: Array<SharedV3Warning> = [];
|
|
25
36
|
|
|
26
|
-
for (const { role, content } of prompt) {
|
|
37
|
+
for (const { role, content, providerOptions } of prompt) {
|
|
27
38
|
switch (role) {
|
|
28
39
|
case 'system': {
|
|
29
40
|
switch (systemMessageMode) {
|
|
30
41
|
case 'system': {
|
|
31
|
-
|
|
42
|
+
const promptCacheBreakpoint =
|
|
43
|
+
getPromptCacheBreakpoint(providerOptions);
|
|
44
|
+
messages.push({
|
|
45
|
+
role: 'system',
|
|
46
|
+
content:
|
|
47
|
+
promptCacheBreakpoint == null
|
|
48
|
+
? content
|
|
49
|
+
: [
|
|
50
|
+
{
|
|
51
|
+
type: 'text',
|
|
52
|
+
text: content,
|
|
53
|
+
prompt_cache_breakpoint: promptCacheBreakpoint,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
});
|
|
32
57
|
break;
|
|
33
58
|
}
|
|
34
59
|
case 'developer': {
|
|
35
|
-
|
|
60
|
+
const promptCacheBreakpoint =
|
|
61
|
+
getPromptCacheBreakpoint(providerOptions);
|
|
62
|
+
messages.push({
|
|
63
|
+
role: 'developer',
|
|
64
|
+
content:
|
|
65
|
+
promptCacheBreakpoint == null
|
|
66
|
+
? content
|
|
67
|
+
: [
|
|
68
|
+
{
|
|
69
|
+
type: 'text',
|
|
70
|
+
text: content,
|
|
71
|
+
prompt_cache_breakpoint: promptCacheBreakpoint,
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
});
|
|
36
75
|
break;
|
|
37
76
|
}
|
|
38
77
|
case 'remove': {
|
|
@@ -53,7 +92,11 @@ export function convertToOpenAIChatMessages({
|
|
|
53
92
|
}
|
|
54
93
|
|
|
55
94
|
case 'user': {
|
|
56
|
-
if (
|
|
95
|
+
if (
|
|
96
|
+
content.length === 1 &&
|
|
97
|
+
content[0].type === 'text' &&
|
|
98
|
+
getPromptCacheBreakpoint(content[0].providerOptions) == null
|
|
99
|
+
) {
|
|
57
100
|
messages.push({ role: 'user', content: content[0].text });
|
|
58
101
|
break;
|
|
59
102
|
}
|
|
@@ -63,9 +106,21 @@ export function convertToOpenAIChatMessages({
|
|
|
63
106
|
content: content.map((part, index) => {
|
|
64
107
|
switch (part.type) {
|
|
65
108
|
case 'text': {
|
|
66
|
-
|
|
109
|
+
const promptCacheBreakpoint = getPromptCacheBreakpoint(
|
|
110
|
+
part.providerOptions,
|
|
111
|
+
);
|
|
112
|
+
return {
|
|
113
|
+
type: 'text',
|
|
114
|
+
text: part.text,
|
|
115
|
+
...(promptCacheBreakpoint != null && {
|
|
116
|
+
prompt_cache_breakpoint: promptCacheBreakpoint,
|
|
117
|
+
}),
|
|
118
|
+
};
|
|
67
119
|
}
|
|
68
120
|
case 'file': {
|
|
121
|
+
const promptCacheBreakpoint = getPromptCacheBreakpoint(
|
|
122
|
+
part.providerOptions,
|
|
123
|
+
);
|
|
69
124
|
if (part.mediaType.startsWith('image/')) {
|
|
70
125
|
const mediaType =
|
|
71
126
|
part.mediaType === 'image/*'
|
|
@@ -83,6 +138,9 @@ export function convertToOpenAIChatMessages({
|
|
|
83
138
|
// OpenAI specific extension: image detail
|
|
84
139
|
detail: part.providerOptions?.openai?.imageDetail,
|
|
85
140
|
},
|
|
141
|
+
...(promptCacheBreakpoint != null && {
|
|
142
|
+
prompt_cache_breakpoint: promptCacheBreakpoint,
|
|
143
|
+
}),
|
|
86
144
|
};
|
|
87
145
|
} else if (part.mediaType.startsWith('audio/')) {
|
|
88
146
|
if (part.data instanceof URL) {
|
|
@@ -99,6 +157,9 @@ export function convertToOpenAIChatMessages({
|
|
|
99
157
|
data: convertToBase64(part.data),
|
|
100
158
|
format: 'wav',
|
|
101
159
|
},
|
|
160
|
+
...(promptCacheBreakpoint != null && {
|
|
161
|
+
prompt_cache_breakpoint: promptCacheBreakpoint,
|
|
162
|
+
}),
|
|
102
163
|
};
|
|
103
164
|
}
|
|
104
165
|
case 'audio/mp3':
|
|
@@ -109,6 +170,9 @@ export function convertToOpenAIChatMessages({
|
|
|
109
170
|
data: convertToBase64(part.data),
|
|
110
171
|
format: 'mp3',
|
|
111
172
|
},
|
|
173
|
+
...(promptCacheBreakpoint != null && {
|
|
174
|
+
prompt_cache_breakpoint: promptCacheBreakpoint,
|
|
175
|
+
}),
|
|
112
176
|
};
|
|
113
177
|
}
|
|
114
178
|
|
|
@@ -135,6 +199,9 @@ export function convertToOpenAIChatMessages({
|
|
|
135
199
|
filename: part.filename ?? `part-${index}.pdf`,
|
|
136
200
|
file_data: `data:application/pdf;base64,${convertToBase64(part.data)}`,
|
|
137
201
|
},
|
|
202
|
+
...(promptCacheBreakpoint != null && {
|
|
203
|
+
prompt_cache_breakpoint: promptCacheBreakpoint,
|
|
204
|
+
}),
|
|
138
205
|
};
|
|
139
206
|
} else {
|
|
140
207
|
throw new UnsupportedFunctionalityError({
|
|
@@ -151,6 +218,12 @@ export function convertToOpenAIChatMessages({
|
|
|
151
218
|
|
|
152
219
|
case 'assistant': {
|
|
153
220
|
let text = '';
|
|
221
|
+
const textParts: Array<{
|
|
222
|
+
type: 'text';
|
|
223
|
+
text: string;
|
|
224
|
+
prompt_cache_breakpoint?: OpenAIPromptCacheBreakpoint;
|
|
225
|
+
}> = [];
|
|
226
|
+
let hasPromptCacheBreakpoint = false;
|
|
154
227
|
const toolCalls: Array<{
|
|
155
228
|
id: string;
|
|
156
229
|
type: 'function';
|
|
@@ -160,7 +233,18 @@ export function convertToOpenAIChatMessages({
|
|
|
160
233
|
for (const part of content) {
|
|
161
234
|
switch (part.type) {
|
|
162
235
|
case 'text': {
|
|
236
|
+
const promptCacheBreakpoint = getPromptCacheBreakpoint(
|
|
237
|
+
part.providerOptions,
|
|
238
|
+
);
|
|
163
239
|
text += part.text;
|
|
240
|
+
textParts.push({
|
|
241
|
+
type: 'text',
|
|
242
|
+
text: part.text,
|
|
243
|
+
...(promptCacheBreakpoint != null && {
|
|
244
|
+
prompt_cache_breakpoint: promptCacheBreakpoint,
|
|
245
|
+
}),
|
|
246
|
+
});
|
|
247
|
+
hasPromptCacheBreakpoint ||= promptCacheBreakpoint != null;
|
|
164
248
|
break;
|
|
165
249
|
}
|
|
166
250
|
case 'tool-call': {
|
|
@@ -179,7 +263,11 @@ export function convertToOpenAIChatMessages({
|
|
|
179
263
|
|
|
180
264
|
messages.push({
|
|
181
265
|
role: 'assistant',
|
|
182
|
-
content:
|
|
266
|
+
content: hasPromptCacheBreakpoint
|
|
267
|
+
? textParts
|
|
268
|
+
: toolCalls.length > 0
|
|
269
|
+
? text || null
|
|
270
|
+
: text,
|
|
183
271
|
tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
184
272
|
});
|
|
185
273
|
|
|
@@ -192,6 +280,13 @@ export function convertToOpenAIChatMessages({
|
|
|
192
280
|
continue;
|
|
193
281
|
}
|
|
194
282
|
const output = toolResponse.output;
|
|
283
|
+
const promptCacheBreakpoint =
|
|
284
|
+
(output.type === 'content'
|
|
285
|
+
? output.value
|
|
286
|
+
.map(part => getPromptCacheBreakpoint(part.providerOptions))
|
|
287
|
+
.find(breakpoint => breakpoint != null)
|
|
288
|
+
: getPromptCacheBreakpoint(output.providerOptions)) ??
|
|
289
|
+
getPromptCacheBreakpoint(toolResponse.providerOptions);
|
|
195
290
|
|
|
196
291
|
let contentValue: string;
|
|
197
292
|
switch (output.type) {
|
|
@@ -212,7 +307,16 @@ export function convertToOpenAIChatMessages({
|
|
|
212
307
|
messages.push({
|
|
213
308
|
role: 'tool',
|
|
214
309
|
tool_call_id: toolResponse.toolCallId,
|
|
215
|
-
content:
|
|
310
|
+
content:
|
|
311
|
+
promptCacheBreakpoint == null
|
|
312
|
+
? contentValue
|
|
313
|
+
: [
|
|
314
|
+
{
|
|
315
|
+
type: 'text',
|
|
316
|
+
text: contentValue,
|
|
317
|
+
prompt_cache_breakpoint: promptCacheBreakpoint,
|
|
318
|
+
},
|
|
319
|
+
],
|
|
216
320
|
});
|
|
217
321
|
}
|
|
218
322
|
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
|
|
@@ -171,6 +171,7 @@ export class OpenAIChatLanguageModel implements LanguageModelV3 {
|
|
|
171
171
|
reasoning_effort: openaiOptions.reasoningEffort,
|
|
172
172
|
service_tier: openaiOptions.serviceTier,
|
|
173
173
|
prompt_cache_key: openaiOptions.promptCacheKey,
|
|
174
|
+
prompt_cache_options: openaiOptions.promptCacheOptions,
|
|
174
175
|
prompt_cache_retention: openaiOptions.promptCacheRetention,
|
|
175
176
|
safety_identifier: openaiOptions.safetyIdentifier,
|
|
176
177
|
|
|
@@ -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
|
*/
|
|
@@ -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,
|