@ai-sdk/openai 3.0.30 → 3.0.32
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 +12 -0
- package/dist/index.d.mts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +15 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +15 -7
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.d.mts +4 -4
- package/dist/internal/index.d.ts +4 -4
- package/dist/internal/index.js +14 -6
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/index.mjs +14 -6
- package/dist/internal/index.mjs.map +1 -1
- package/docs/03-openai.mdx +91 -38
- package/package.json +3 -3
- package/src/responses/openai-responses-api.ts +53 -46
- package/src/responses/openai-responses-language-model.ts +5 -1
- package/src/responses/openai-responses-options.ts +4 -0
- package/src/tool/web-search-preview.ts +18 -16
- package/src/tool/web-search.ts +18 -16
package/docs/03-openai.mdx
CHANGED
|
@@ -123,7 +123,8 @@ const { text } = await generateText({
|
|
|
123
123
|
});
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
-
OpenAI language models can also be used in the `streamText
|
|
126
|
+
OpenAI language models can also be used in the `streamText` function
|
|
127
|
+
and support structured data generation with [`Output`](/docs/reference/ai-sdk-core/output)
|
|
127
128
|
(see [AI SDK Core](/docs/ai-sdk-core)).
|
|
128
129
|
|
|
129
130
|
### Responses Models
|
|
@@ -340,6 +341,67 @@ console.log('Reasoning:', result.reasoning);
|
|
|
340
341
|
|
|
341
342
|
Learn more about reasoning summaries in the [OpenAI documentation](https://platform.openai.com/docs/guides/reasoning?api-mode=responses#reasoning-summaries).
|
|
342
343
|
|
|
344
|
+
#### WebSocket Transport
|
|
345
|
+
|
|
346
|
+
OpenAI's [WebSocket API](https://developers.openai.com/api/docs/guides/websocket-mode) keeps a persistent connection open, which can significantly
|
|
347
|
+
reduce Time-to-First-Byte (TTFB) in agentic workflows with many tool calls.
|
|
348
|
+
After the initial connection, subsequent requests skip TCP/TLS/HTTP negotiation entirely.
|
|
349
|
+
|
|
350
|
+
The [`ai-sdk-openai-websocket-fetch`](https://www.npmjs.com/package/ai-sdk-openai-websocket-fetch)
|
|
351
|
+
package provides a drop-in `fetch` replacement that routes streaming requests
|
|
352
|
+
through a persistent WebSocket connection.
|
|
353
|
+
|
|
354
|
+
<Tabs items={['pnpm', 'npm', 'yarn', 'bun']}>
|
|
355
|
+
<Tab>
|
|
356
|
+
<Snippet text="pnpm add ai-sdk-openai-websocket-fetch" dark />
|
|
357
|
+
</Tab>
|
|
358
|
+
<Tab>
|
|
359
|
+
<Snippet text="npm install ai-sdk-openai-websocket-fetch" dark />
|
|
360
|
+
</Tab>
|
|
361
|
+
<Tab>
|
|
362
|
+
<Snippet text="yarn add ai-sdk-openai-websocket-fetch" dark />
|
|
363
|
+
</Tab>
|
|
364
|
+
<Tab>
|
|
365
|
+
<Snippet text="bun add ai-sdk-openai-websocket-fetch" dark />
|
|
366
|
+
</Tab>
|
|
367
|
+
</Tabs>
|
|
368
|
+
|
|
369
|
+
Pass the WebSocket fetch to `createOpenAI` via the `fetch` option:
|
|
370
|
+
|
|
371
|
+
```ts highlight="2,6-7,15"
|
|
372
|
+
import { createOpenAI } from '@ai-sdk/openai';
|
|
373
|
+
import { createWebSocketFetch } from 'ai-sdk-openai-websocket-fetch';
|
|
374
|
+
import { streamText } from 'ai';
|
|
375
|
+
|
|
376
|
+
// Create a WebSocket-backed fetch instance
|
|
377
|
+
const wsFetch = createWebSocketFetch();
|
|
378
|
+
const openai = createOpenAI({ fetch: wsFetch });
|
|
379
|
+
|
|
380
|
+
const result = streamText({
|
|
381
|
+
model: openai('gpt-4.1-mini'),
|
|
382
|
+
prompt: 'Hello!',
|
|
383
|
+
tools: {
|
|
384
|
+
// ...
|
|
385
|
+
},
|
|
386
|
+
onFinish: () => wsFetch.close(), // close the WebSocket when done
|
|
387
|
+
});
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
The first request will be slower because it must establish the WebSocket connection
|
|
391
|
+
(DNS + TCP + TLS + WebSocket upgrade). After that, subsequent steps in a
|
|
392
|
+
multi-step tool-calling loop reuse the open connection, resulting in lower TTFB
|
|
393
|
+
per step.
|
|
394
|
+
|
|
395
|
+
<Note>
|
|
396
|
+
The WebSocket transport only routes streaming requests to the OpenAI Responses
|
|
397
|
+
API (`POST /responses` with `stream: true`) through the WebSocket. All other
|
|
398
|
+
requests (non-streaming, embeddings, etc.) fall through to the standard
|
|
399
|
+
`fetch` implementation.
|
|
400
|
+
</Note>
|
|
401
|
+
|
|
402
|
+
You can see a live side-by-side comparison of HTTP vs WebSocket streaming performance
|
|
403
|
+
in the [demo app](https://github.com/vercel-labs/ai-sdk-openai-websocket).
|
|
404
|
+
|
|
343
405
|
#### Verbosity Control
|
|
344
406
|
|
|
345
407
|
You can control the length and detail of model responses using the `textVerbosity` parameter:
|
|
@@ -999,37 +1061,26 @@ and the `mediaType` should be set to `'application/pdf'`.
|
|
|
999
1061
|
|
|
1000
1062
|
#### Structured Outputs
|
|
1001
1063
|
|
|
1002
|
-
The OpenAI Responses API supports structured outputs. You can
|
|
1064
|
+
The OpenAI Responses API supports structured outputs. You can use `generateText` or `streamText` with [`Output`](/docs/reference/ai-sdk-core/output) to enforce structured outputs.
|
|
1003
1065
|
|
|
1004
1066
|
```ts
|
|
1005
|
-
// Using generateObject
|
|
1006
|
-
const result = await generateObject({
|
|
1007
|
-
model: openai('gpt-4.1'),
|
|
1008
|
-
schema: z.object({
|
|
1009
|
-
recipe: z.object({
|
|
1010
|
-
name: z.string(),
|
|
1011
|
-
ingredients: z.array(
|
|
1012
|
-
z.object({
|
|
1013
|
-
name: z.string(),
|
|
1014
|
-
amount: z.string(),
|
|
1015
|
-
}),
|
|
1016
|
-
),
|
|
1017
|
-
steps: z.array(z.string()),
|
|
1018
|
-
}),
|
|
1019
|
-
}),
|
|
1020
|
-
prompt: 'Generate a lasagna recipe.',
|
|
1021
|
-
});
|
|
1022
|
-
|
|
1023
|
-
// Using generateText
|
|
1024
1067
|
const result = await generateText({
|
|
1025
1068
|
model: openai('gpt-4.1'),
|
|
1026
|
-
prompt: 'How do I make a pizza?',
|
|
1027
1069
|
output: Output.object({
|
|
1028
1070
|
schema: z.object({
|
|
1029
|
-
|
|
1030
|
-
|
|
1071
|
+
recipe: z.object({
|
|
1072
|
+
name: z.string(),
|
|
1073
|
+
ingredients: z.array(
|
|
1074
|
+
z.object({
|
|
1075
|
+
name: z.string(),
|
|
1076
|
+
amount: z.string(),
|
|
1077
|
+
}),
|
|
1078
|
+
),
|
|
1079
|
+
steps: z.array(z.string()),
|
|
1080
|
+
}),
|
|
1031
1081
|
}),
|
|
1032
1082
|
}),
|
|
1083
|
+
prompt: 'Generate a lasagna recipe.',
|
|
1033
1084
|
});
|
|
1034
1085
|
```
|
|
1035
1086
|
|
|
@@ -1458,32 +1509,34 @@ You can disable them by setting the `strictJsonSchema` option to `false`.
|
|
|
1458
1509
|
|
|
1459
1510
|
```ts highlight="7"
|
|
1460
1511
|
import { openai, OpenAILanguageModelChatOptions } from '@ai-sdk/openai';
|
|
1461
|
-
import {
|
|
1512
|
+
import { generateText, Output } from 'ai';
|
|
1462
1513
|
import { z } from 'zod';
|
|
1463
1514
|
|
|
1464
|
-
const result = await
|
|
1515
|
+
const result = await generateText({
|
|
1465
1516
|
model: openai.chat('gpt-4o-2024-08-06'),
|
|
1466
1517
|
providerOptions: {
|
|
1467
1518
|
openai: {
|
|
1468
1519
|
strictJsonSchema: false,
|
|
1469
1520
|
} satisfies OpenAILanguageModelChatOptions,
|
|
1470
1521
|
},
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1522
|
+
output: Output.object({
|
|
1523
|
+
schema: z.object({
|
|
1524
|
+
name: z.string(),
|
|
1525
|
+
ingredients: z.array(
|
|
1526
|
+
z.object({
|
|
1527
|
+
name: z.string(),
|
|
1528
|
+
amount: z.string(),
|
|
1529
|
+
}),
|
|
1530
|
+
),
|
|
1531
|
+
steps: z.array(z.string()),
|
|
1532
|
+
}),
|
|
1533
|
+
schemaName: 'recipe',
|
|
1534
|
+
schemaDescription: 'A recipe for lasagna.',
|
|
1482
1535
|
}),
|
|
1483
1536
|
prompt: 'Generate a lasagna recipe.',
|
|
1484
1537
|
});
|
|
1485
1538
|
|
|
1486
|
-
console.log(JSON.stringify(result.
|
|
1539
|
+
console.log(JSON.stringify(result.output, null, 2));
|
|
1487
1540
|
```
|
|
1488
1541
|
|
|
1489
1542
|
<Note type="warning">
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/openai",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.32",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"tsup": "^8",
|
|
45
45
|
"typescript": "5.8.3",
|
|
46
46
|
"zod": "3.25.76",
|
|
47
|
-
"@
|
|
48
|
-
"@ai-
|
|
47
|
+
"@ai-sdk/test-server": "1.0.3",
|
|
48
|
+
"@vercel/ai-tsconfig": "0.0.0"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"zod": "^3.25.76 || ^4.1.8"
|
|
@@ -599,29 +599,31 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
|
|
|
599
599
|
type: z.literal('web_search_call'),
|
|
600
600
|
id: z.string(),
|
|
601
601
|
status: z.string(),
|
|
602
|
-
action: z
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
z.
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
602
|
+
action: z
|
|
603
|
+
.discriminatedUnion('type', [
|
|
604
|
+
z.object({
|
|
605
|
+
type: z.literal('search'),
|
|
606
|
+
query: z.string().nullish(),
|
|
607
|
+
sources: z
|
|
608
|
+
.array(
|
|
609
|
+
z.discriminatedUnion('type', [
|
|
610
|
+
z.object({ type: z.literal('url'), url: z.string() }),
|
|
611
|
+
z.object({ type: z.literal('api'), name: z.string() }),
|
|
612
|
+
]),
|
|
613
|
+
)
|
|
614
|
+
.nullish(),
|
|
615
|
+
}),
|
|
616
|
+
z.object({
|
|
617
|
+
type: z.literal('open_page'),
|
|
618
|
+
url: z.string().nullish(),
|
|
619
|
+
}),
|
|
620
|
+
z.object({
|
|
621
|
+
type: z.literal('find_in_page'),
|
|
622
|
+
url: z.string().nullish(),
|
|
623
|
+
pattern: z.string().nullish(),
|
|
624
|
+
}),
|
|
625
|
+
])
|
|
626
|
+
.nullish(),
|
|
625
627
|
}),
|
|
626
628
|
z.object({
|
|
627
629
|
type: z.literal('file_search_call'),
|
|
@@ -966,29 +968,34 @@ export const openaiResponsesResponseSchema = lazySchema(() =>
|
|
|
966
968
|
type: z.literal('web_search_call'),
|
|
967
969
|
id: z.string(),
|
|
968
970
|
status: z.string(),
|
|
969
|
-
action: z
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
z.
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
971
|
+
action: z
|
|
972
|
+
.discriminatedUnion('type', [
|
|
973
|
+
z.object({
|
|
974
|
+
type: z.literal('search'),
|
|
975
|
+
query: z.string().nullish(),
|
|
976
|
+
sources: z
|
|
977
|
+
.array(
|
|
978
|
+
z.discriminatedUnion('type', [
|
|
979
|
+
z.object({ type: z.literal('url'), url: z.string() }),
|
|
980
|
+
z.object({
|
|
981
|
+
type: z.literal('api'),
|
|
982
|
+
name: z.string(),
|
|
983
|
+
}),
|
|
984
|
+
]),
|
|
985
|
+
)
|
|
986
|
+
.nullish(),
|
|
987
|
+
}),
|
|
988
|
+
z.object({
|
|
989
|
+
type: z.literal('open_page'),
|
|
990
|
+
url: z.string().nullish(),
|
|
991
|
+
}),
|
|
992
|
+
z.object({
|
|
993
|
+
type: z.literal('find_in_page'),
|
|
994
|
+
url: z.string().nullish(),
|
|
995
|
+
pattern: z.string().nullish(),
|
|
996
|
+
}),
|
|
997
|
+
])
|
|
998
|
+
.nullish(),
|
|
992
999
|
}),
|
|
993
1000
|
z.object({
|
|
994
1001
|
type: z.literal('file_search_call'),
|
|
@@ -1969,8 +1969,12 @@ function isErrorChunk(
|
|
|
1969
1969
|
}
|
|
1970
1970
|
|
|
1971
1971
|
function mapWebSearchOutput(
|
|
1972
|
-
action: OpenAIResponsesWebSearchAction,
|
|
1972
|
+
action: OpenAIResponsesWebSearchAction | null | undefined,
|
|
1973
1973
|
): InferSchema<typeof webSearchOutputSchema> {
|
|
1974
|
+
if (action == null) {
|
|
1975
|
+
return {};
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1974
1978
|
switch (action.type) {
|
|
1975
1979
|
case 'search':
|
|
1976
1980
|
return {
|
|
@@ -42,6 +42,8 @@ export const openaiResponsesReasoningModelIds = [
|
|
|
42
42
|
'gpt-5.2',
|
|
43
43
|
'gpt-5.2-chat-latest',
|
|
44
44
|
'gpt-5.2-pro',
|
|
45
|
+
'gpt-5.2-codex',
|
|
46
|
+
'gpt-5.3-codex',
|
|
45
47
|
] as const;
|
|
46
48
|
|
|
47
49
|
export const openaiResponsesModelIds = [
|
|
@@ -110,6 +112,8 @@ export type OpenAIResponsesModelId =
|
|
|
110
112
|
| 'gpt-5.2'
|
|
111
113
|
| 'gpt-5.2-chat-latest'
|
|
112
114
|
| 'gpt-5.2-pro'
|
|
115
|
+
| 'gpt-5.2-codex'
|
|
116
|
+
| 'gpt-5.3-codex'
|
|
113
117
|
| 'gpt-5-2025-08-07'
|
|
114
118
|
| 'gpt-5-chat-latest'
|
|
115
119
|
| 'gpt-5-codex'
|
|
@@ -29,21 +29,23 @@ export const webSearchPreviewInputSchema = lazySchema(() =>
|
|
|
29
29
|
const webSearchPreviewOutputSchema = lazySchema(() =>
|
|
30
30
|
zodSchema(
|
|
31
31
|
z.object({
|
|
32
|
-
action: z
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
32
|
+
action: z
|
|
33
|
+
.discriminatedUnion('type', [
|
|
34
|
+
z.object({
|
|
35
|
+
type: z.literal('search'),
|
|
36
|
+
query: z.string().optional(),
|
|
37
|
+
}),
|
|
38
|
+
z.object({
|
|
39
|
+
type: z.literal('openPage'),
|
|
40
|
+
url: z.string().nullish(),
|
|
41
|
+
}),
|
|
42
|
+
z.object({
|
|
43
|
+
type: z.literal('findInPage'),
|
|
44
|
+
url: z.string().nullish(),
|
|
45
|
+
pattern: z.string().nullish(),
|
|
46
|
+
}),
|
|
47
|
+
])
|
|
48
|
+
.optional(),
|
|
47
49
|
}),
|
|
48
50
|
),
|
|
49
51
|
);
|
|
@@ -57,7 +59,7 @@ export const webSearchPreview = createProviderToolFactoryWithOutputSchema<
|
|
|
57
59
|
* An object describing the specific action taken in this web search call.
|
|
58
60
|
* Includes details on how the model used the web (search, open_page, find_in_page).
|
|
59
61
|
*/
|
|
60
|
-
action
|
|
62
|
+
action?:
|
|
61
63
|
| {
|
|
62
64
|
/**
|
|
63
65
|
* Action type "search" - Performs a web search query.
|
package/src/tool/web-search.ts
CHANGED
|
@@ -31,21 +31,23 @@ const webSearchInputSchema = lazySchema(() => zodSchema(z.object({})));
|
|
|
31
31
|
export const webSearchOutputSchema = lazySchema(() =>
|
|
32
32
|
zodSchema(
|
|
33
33
|
z.object({
|
|
34
|
-
action: z
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
action: z
|
|
35
|
+
.discriminatedUnion('type', [
|
|
36
|
+
z.object({
|
|
37
|
+
type: z.literal('search'),
|
|
38
|
+
query: z.string().optional(),
|
|
39
|
+
}),
|
|
40
|
+
z.object({
|
|
41
|
+
type: z.literal('openPage'),
|
|
42
|
+
url: z.string().nullish(),
|
|
43
|
+
}),
|
|
44
|
+
z.object({
|
|
45
|
+
type: z.literal('findInPage'),
|
|
46
|
+
url: z.string().nullish(),
|
|
47
|
+
pattern: z.string().nullish(),
|
|
48
|
+
}),
|
|
49
|
+
])
|
|
50
|
+
.optional(),
|
|
49
51
|
sources: z
|
|
50
52
|
.array(
|
|
51
53
|
z.discriminatedUnion('type', [
|
|
@@ -67,7 +69,7 @@ export const webSearchToolFactory = createProviderToolFactoryWithOutputSchema<
|
|
|
67
69
|
* An object describing the specific action taken in this web search call.
|
|
68
70
|
* Includes details on how the model used the web (search, open_page, find_in_page).
|
|
69
71
|
*/
|
|
70
|
-
action
|
|
72
|
+
action?:
|
|
71
73
|
| {
|
|
72
74
|
/**
|
|
73
75
|
* Action type "search" - Performs a web search query.
|