@ai-sdk/openai 4.0.0-beta.6 → 4.0.0-beta.74

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.
Files changed (73) hide show
  1. package/CHANGELOG.md +644 -24
  2. package/README.md +2 -0
  3. package/dist/index.d.ts +240 -44
  4. package/dist/index.js +3345 -1683
  5. package/dist/index.js.map +1 -1
  6. package/dist/internal/index.d.ts +390 -36
  7. package/dist/internal/index.js +2707 -1706
  8. package/dist/internal/index.js.map +1 -1
  9. package/docs/03-openai.mdx +413 -39
  10. package/package.json +17 -18
  11. package/src/chat/convert-openai-chat-usage.ts +1 -1
  12. package/src/chat/convert-to-openai-chat-messages.ts +96 -68
  13. package/src/chat/map-openai-finish-reason.ts +1 -1
  14. package/src/chat/openai-chat-api.ts +6 -2
  15. package/src/chat/{openai-chat-options.ts → openai-chat-language-model-options.ts} +11 -1
  16. package/src/chat/openai-chat-language-model.ts +82 -148
  17. package/src/chat/openai-chat-prepare-tools.ts +3 -3
  18. package/src/completion/convert-openai-completion-usage.ts +1 -1
  19. package/src/completion/convert-to-openai-completion-prompt.ts +1 -2
  20. package/src/completion/map-openai-finish-reason.ts +1 -1
  21. package/src/completion/openai-completion-api.ts +5 -2
  22. package/src/completion/{openai-completion-options.ts → openai-completion-language-model-options.ts} +5 -1
  23. package/src/completion/openai-completion-language-model.ts +53 -17
  24. package/src/embedding/{openai-embedding-options.ts → openai-embedding-model-options.ts} +5 -1
  25. package/src/embedding/openai-embedding-model.ts +22 -5
  26. package/src/files/openai-files-api.ts +17 -0
  27. package/src/files/openai-files-options.ts +22 -0
  28. package/src/files/openai-files.ts +100 -0
  29. package/src/image/openai-image-model-options.ts +123 -0
  30. package/src/image/openai-image-model.ts +62 -83
  31. package/src/index.ts +15 -6
  32. package/src/internal/index.ts +7 -6
  33. package/src/openai-config.ts +7 -7
  34. package/src/openai-language-model-capabilities.ts +5 -4
  35. package/src/openai-provider.ts +80 -9
  36. package/src/openai-stream-error.ts +181 -0
  37. package/src/openai-tools.ts +12 -1
  38. package/src/realtime/index.ts +2 -0
  39. package/src/realtime/openai-realtime-event-mapper.ts +436 -0
  40. package/src/realtime/openai-realtime-model-options.ts +3 -0
  41. package/src/realtime/openai-realtime-model.ts +111 -0
  42. package/src/responses/convert-openai-responses-usage.ts +1 -1
  43. package/src/responses/convert-to-openai-responses-input.ts +345 -90
  44. package/src/responses/map-openai-responses-finish-reason.ts +1 -1
  45. package/src/responses/openai-responses-api.ts +186 -17
  46. package/src/responses/{openai-responses-options.ts → openai-responses-language-model-options.ts} +55 -1
  47. package/src/responses/openai-responses-language-model.ts +330 -52
  48. package/src/responses/openai-responses-prepare-tools.ts +129 -18
  49. package/src/responses/openai-responses-provider-metadata.ts +12 -2
  50. package/src/skills/openai-skills-api.ts +31 -0
  51. package/src/skills/openai-skills.ts +83 -0
  52. package/src/speech/{openai-speech-options.ts → openai-speech-model-options.ts} +5 -1
  53. package/src/speech/openai-speech-model.ts +23 -7
  54. package/src/tool/apply-patch.ts +33 -32
  55. package/src/tool/code-interpreter.ts +40 -41
  56. package/src/tool/custom.ts +2 -8
  57. package/src/tool/file-search.ts +3 -3
  58. package/src/tool/image-generation.ts +2 -2
  59. package/src/tool/local-shell.ts +2 -2
  60. package/src/tool/mcp.ts +3 -3
  61. package/src/tool/shell.ts +9 -4
  62. package/src/tool/tool-search.ts +98 -0
  63. package/src/tool/web-search-preview.ts +2 -2
  64. package/src/tool/web-search.ts +10 -2
  65. package/src/transcription/{openai-transcription-options.ts → openai-transcription-model-options.ts} +5 -1
  66. package/src/transcription/openai-transcription-model.ts +35 -13
  67. package/dist/index.d.mts +0 -1107
  68. package/dist/index.mjs +0 -6509
  69. package/dist/index.mjs.map +0 -1
  70. package/dist/internal/index.d.mts +0 -1137
  71. package/dist/internal/index.mjs +0 -6322
  72. package/dist/internal/index.mjs.map +0 -1
  73. package/src/image/openai-image-options.ts +0 -31
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "4.0.0-beta.6",
3
+ "version": "4.0.0-beta.74",
4
+ "type": "module",
4
5
  "license": "Apache-2.0",
5
6
  "sideEffects": false,
6
7
  "main": "./dist/index.js",
7
- "module": "./dist/index.mjs",
8
8
  "types": "./dist/index.d.ts",
9
9
  "files": [
10
10
  "dist/**/*",
@@ -25,41 +25,42 @@
25
25
  "./package.json": "./package.json",
26
26
  ".": {
27
27
  "types": "./dist/index.d.ts",
28
- "import": "./dist/index.mjs",
29
- "require": "./dist/index.js"
28
+ "import": "./dist/index.js",
29
+ "default": "./dist/index.js"
30
30
  },
31
31
  "./internal": {
32
32
  "types": "./dist/internal/index.d.ts",
33
- "import": "./dist/internal/index.mjs",
34
- "module": "./dist/internal/index.mjs",
35
- "require": "./dist/internal/index.js"
33
+ "import": "./dist/internal/index.js",
34
+ "default": "./dist/internal/index.js"
36
35
  }
37
36
  },
38
37
  "dependencies": {
39
- "@ai-sdk/provider": "4.0.0-beta.0",
40
- "@ai-sdk/provider-utils": "5.0.0-beta.1"
38
+ "@ai-sdk/provider": "4.0.0-beta.19",
39
+ "@ai-sdk/provider-utils": "5.0.0-beta.49"
41
40
  },
42
41
  "devDependencies": {
43
- "@types/node": "20.17.24",
44
- "tsup": "^8",
42
+ "@types/node": "22.19.19",
43
+ "tsup": "^8.5.1",
45
44
  "typescript": "5.8.3",
46
45
  "zod": "3.25.76",
47
- "@vercel/ai-tsconfig": "0.0.0",
48
- "@ai-sdk/test-server": "2.0.0-beta.0"
46
+ "@ai-sdk/test-server": "2.0.0-beta.7",
47
+ "@vercel/ai-tsconfig": "0.0.0"
49
48
  },
50
49
  "peerDependencies": {
51
50
  "zod": "^3.25.76 || ^4.1.8"
52
51
  },
53
52
  "engines": {
54
- "node": ">=18"
53
+ "node": ">=22"
55
54
  },
56
55
  "publishConfig": {
57
- "access": "public"
56
+ "access": "public",
57
+ "provenance": true
58
58
  },
59
59
  "homepage": "https://ai-sdk.dev/docs",
60
60
  "repository": {
61
61
  "type": "git",
62
- "url": "git+https://github.com/vercel/ai.git"
62
+ "url": "https://github.com/vercel/ai",
63
+ "directory": "packages/openai"
63
64
  },
64
65
  "bugs": {
65
66
  "url": "https://github.com/vercel/ai/issues"
@@ -71,9 +72,7 @@
71
72
  "build": "pnpm clean && tsup --tsconfig tsconfig.build.json",
72
73
  "build:watch": "pnpm clean && tsup --watch",
73
74
  "clean": "del-cli dist docs *.tsbuildinfo",
74
- "lint": "eslint \"./**/*.ts*\"",
75
75
  "type-check": "tsc --build",
76
- "prettier-check": "prettier --check \"./**/*.ts*\"",
77
76
  "test": "pnpm test:node && pnpm test:edge",
78
77
  "test:update": "pnpm test:node -u",
79
78
  "test:watch": "vitest --config vitest.node.config.js",
@@ -1,4 +1,4 @@
1
- import { LanguageModelV4Usage } from '@ai-sdk/provider';
1
+ import type { LanguageModelV4Usage } from '@ai-sdk/provider';
2
2
 
3
3
  export type OpenAIChatUsage = {
4
4
  prompt_tokens?: number | null;
@@ -1,10 +1,19 @@
1
1
  import {
2
- SharedV4Warning,
3
- LanguageModelV4Prompt,
4
2
  UnsupportedFunctionalityError,
3
+ type SharedV4Warning,
4
+ type LanguageModelV4Prompt,
5
5
  } from '@ai-sdk/provider';
6
- import { OpenAIChatPrompt } from './openai-chat-prompt';
7
- import { convertToBase64 } from '@ai-sdk/provider-utils';
6
+ import type { OpenAIChatPrompt } from './openai-chat-prompt';
7
+ import {
8
+ convertToBase64,
9
+ getTopLevelMediaType,
10
+ resolveFullMediaType,
11
+ resolveProviderReference,
12
+ } from '@ai-sdk/provider-utils';
13
+
14
+ function serializeToolCallArguments(input: unknown): string {
15
+ return JSON.stringify(input === undefined ? {} : input);
16
+ }
8
17
 
9
18
  export function convertToOpenAIChatMessages({
10
19
  prompt,
@@ -62,80 +71,99 @@ export function convertToOpenAIChatMessages({
62
71
  return { type: 'text', text: part.text };
63
72
  }
64
73
  case 'file': {
65
- if (part.mediaType.startsWith('image/')) {
66
- const mediaType =
67
- part.mediaType === 'image/*'
68
- ? 'image/jpeg'
69
- : part.mediaType;
70
-
71
- return {
72
- type: 'image_url',
73
- image_url: {
74
- url:
75
- part.data instanceof URL
76
- ? part.data.toString()
77
- : `data:${mediaType};base64,${convertToBase64(part.data)}`,
78
-
79
- // OpenAI specific extension: image detail
80
- detail: part.providerOptions?.openai?.imageDetail,
81
- },
82
- };
83
- } else if (part.mediaType.startsWith('audio/')) {
84
- if (part.data instanceof URL) {
74
+ switch (part.data.type) {
75
+ case 'reference': {
76
+ return {
77
+ type: 'file',
78
+ file: {
79
+ file_id: resolveProviderReference({
80
+ reference: part.data.reference,
81
+ provider: 'openai',
82
+ }),
83
+ },
84
+ };
85
+ }
86
+ case 'text': {
85
87
  throw new UnsupportedFunctionalityError({
86
- functionality: 'audio file parts with URLs',
88
+ functionality: 'text file parts',
87
89
  });
88
90
  }
91
+ case 'url':
92
+ case 'data': {
93
+ const topLevel = getTopLevelMediaType(part.mediaType);
89
94
 
90
- switch (part.mediaType) {
91
- case 'audio/wav': {
95
+ if (topLevel === 'image') {
92
96
  return {
93
- type: 'input_audio',
94
- input_audio: {
95
- data: convertToBase64(part.data),
96
- format: 'wav',
97
+ type: 'image_url',
98
+ image_url: {
99
+ url:
100
+ part.data.type === 'url'
101
+ ? part.data.url.toString()
102
+ : convertToBase64(part.data.data),
103
+
104
+ detail: part.providerOptions?.openai?.imageDetail,
97
105
  },
98
106
  };
107
+ } else if (topLevel === 'audio') {
108
+ if (part.data.type === 'url') {
109
+ throw new UnsupportedFunctionalityError({
110
+ functionality: 'audio file parts with URLs',
111
+ });
112
+ }
113
+
114
+ const fullMediaType = resolveFullMediaType({ part });
115
+
116
+ switch (fullMediaType) {
117
+ case 'audio/wav': {
118
+ return {
119
+ type: 'input_audio',
120
+ input_audio: {
121
+ data: convertToBase64(part.data.data),
122
+ format: 'wav',
123
+ },
124
+ };
125
+ }
126
+ case 'audio/mp3':
127
+ case 'audio/mpeg': {
128
+ return {
129
+ type: 'input_audio',
130
+ input_audio: {
131
+ data: convertToBase64(part.data.data),
132
+ format: 'mp3',
133
+ },
134
+ };
135
+ }
136
+
137
+ default: {
138
+ throw new UnsupportedFunctionalityError({
139
+ functionality: `audio content parts with media type ${fullMediaType}`,
140
+ });
141
+ }
142
+ }
99
143
  }
100
- case 'audio/mp3':
101
- case 'audio/mpeg': {
144
+ {
145
+ const fullMediaType = resolveFullMediaType({ part });
146
+ if (fullMediaType !== 'application/pdf') {
147
+ throw new UnsupportedFunctionalityError({
148
+ functionality: `file part media type ${fullMediaType}`,
149
+ });
150
+ }
151
+
152
+ if (part.data.type === 'url') {
153
+ throw new UnsupportedFunctionalityError({
154
+ functionality: 'PDF file parts with URLs',
155
+ });
156
+ }
157
+
102
158
  return {
103
- type: 'input_audio',
104
- input_audio: {
105
- data: convertToBase64(part.data),
106
- format: 'mp3',
159
+ type: 'file',
160
+ file: {
161
+ filename: part.filename ?? `part-${index}.pdf`,
162
+ file_data: `data:application/pdf;base64,${convertToBase64(part.data.data)}`,
107
163
  },
108
164
  };
109
165
  }
110
-
111
- default: {
112
- throw new UnsupportedFunctionalityError({
113
- functionality: `audio content parts with media type ${part.mediaType}`,
114
- });
115
- }
116
166
  }
117
- } else if (part.mediaType === 'application/pdf') {
118
- if (part.data instanceof URL) {
119
- throw new UnsupportedFunctionalityError({
120
- functionality: 'PDF file parts with URLs',
121
- });
122
- }
123
-
124
- return {
125
- type: 'file',
126
- file:
127
- typeof part.data === 'string' &&
128
- part.data.startsWith('file-')
129
- ? { file_id: part.data }
130
- : {
131
- filename: part.filename ?? `part-${index}.pdf`,
132
- file_data: `data:application/pdf;base64,${convertToBase64(part.data)}`,
133
- },
134
- };
135
- } else {
136
- throw new UnsupportedFunctionalityError({
137
- functionality: `file part media type ${part.mediaType}`,
138
- });
139
167
  }
140
168
  }
141
169
  }
@@ -165,7 +193,7 @@ export function convertToOpenAIChatMessages({
165
193
  type: 'function',
166
194
  function: {
167
195
  name: part.toolName,
168
- arguments: JSON.stringify(part.input),
196
+ arguments: serializeToolCallArguments(part.input),
169
197
  },
170
198
  });
171
199
  break;
@@ -175,7 +203,7 @@ export function convertToOpenAIChatMessages({
175
203
 
176
204
  messages.push({
177
205
  role: 'assistant',
178
- content: text,
206
+ content: toolCalls.length > 0 ? text || null : text,
179
207
  tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
180
208
  });
181
209
 
@@ -196,7 +224,7 @@ export function convertToOpenAIChatMessages({
196
224
  contentValue = output.value;
197
225
  break;
198
226
  case 'execution-denied':
199
- contentValue = output.reason ?? 'Tool execution denied.';
227
+ contentValue = output.reason ?? 'Tool call execution denied.';
200
228
  break;
201
229
  case 'content':
202
230
  case 'json':
@@ -1,4 +1,4 @@
1
- import { LanguageModelV4FinishReason } from '@ai-sdk/provider';
1
+ import type { LanguageModelV4FinishReason } from '@ai-sdk/provider';
2
2
 
3
3
  export function mapOpenAIFinishReason(
4
4
  finishReason: string | null | undefined,
@@ -1,5 +1,9 @@
1
- import { JSONSchema7 } from '@ai-sdk/provider';
2
- import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
1
+ import type { JSONSchema7 } from '@ai-sdk/provider';
2
+ import {
3
+ lazySchema,
4
+ zodSchema,
5
+ type InferSchema,
6
+ } from '@ai-sdk/provider-utils';
3
7
  import { z } from 'zod/v4';
4
8
  import { openaiErrorDataSchema } from '../openai-error';
5
9
 
@@ -1,4 +1,8 @@
1
- import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
1
+ import {
2
+ lazySchema,
3
+ zodSchema,
4
+ type InferSchema,
5
+ } from '@ai-sdk/provider-utils';
2
6
  import { z } from 'zod/v4';
3
7
 
4
8
  // https://platform.openai.com/docs/models
@@ -54,8 +58,14 @@ export type OpenAIChatModelId =
54
58
  | 'gpt-5.3-chat-latest'
55
59
  | 'gpt-5.4'
56
60
  | 'gpt-5.4-2026-03-05'
61
+ | 'gpt-5.4-mini'
62
+ | 'gpt-5.4-mini-2026-03-17'
63
+ | 'gpt-5.4-nano'
64
+ | 'gpt-5.4-nano-2026-03-17'
57
65
  | 'gpt-5.4-pro'
58
66
  | 'gpt-5.4-pro-2026-03-05'
67
+ | 'gpt-5.5'
68
+ | 'gpt-5.5-2026-04-23'
59
69
  | (string & {});
60
70
 
61
71
  export const openaiLanguageModelChatOptions = lazySchema(() =>