@ai-sdk/openai 4.0.108 → 4.0.110

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 (34) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/index.d.ts +79 -15
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +788 -423
  5. package/dist/index.js.map +1 -1
  6. package/dist/internal/index.d.ts +389 -9
  7. package/dist/internal/index.d.ts.map +1 -1
  8. package/dist/internal/index.js +629 -380
  9. package/dist/internal/index.js.map +1 -1
  10. package/docs/03-openai.mdx +224 -18
  11. package/package.json +3 -3
  12. package/src/chat/convert-to-openai-chat-messages.ts +29 -4
  13. package/src/chat/map-openai-finish-reason.ts +11 -4
  14. package/src/chat/openai-chat-api.ts +36 -0
  15. package/src/chat/openai-chat-language-model-options.ts +13 -0
  16. package/src/chat/openai-chat-language-model.ts +111 -22
  17. package/src/chat/openai-chat-prompt.ts +4 -0
  18. package/src/image/openai-image-model-options.ts +48 -0
  19. package/src/image/openai-image-model.ts +49 -4
  20. package/src/index.ts +1 -0
  21. package/src/internal/index.ts +4 -0
  22. package/src/live/openai-realtime-model-live.ts +21 -2
  23. package/src/openai-batch.ts +8 -0
  24. package/src/openai-model-catalog.ts +3 -1
  25. package/src/openai-tools.ts +4 -3
  26. package/src/realtime/openai-realtime-event-mapper.ts +172 -11
  27. package/src/realtime/openai-realtime-model.ts +57 -3
  28. package/src/responses/map-openai-responses-finish-reason.ts +7 -1
  29. package/src/responses/openai-responses-api.ts +90 -49
  30. package/src/responses/openai-responses-language-model.ts +56 -1
  31. package/src/responses/openai-responses-prepare-tools.ts +18 -1
  32. package/src/tool/code-interpreter.ts +38 -2
  33. package/src/tool/mcp.ts +27 -8
  34. package/src/transcription/openai-transcription-model.ts +43 -8
@@ -333,7 +333,23 @@ export async function prepareResponsesTools({
333
333
  ? { type: 'auto', file_ids: undefined }
334
334
  : typeof args.container === 'string'
335
335
  ? args.container
336
- : { type: 'auto', file_ids: args.container.fileIds },
336
+ : {
337
+ type: 'auto',
338
+ file_ids: args.container.fileIds,
339
+ memory_limit: args.container.memoryLimit,
340
+ network_policy:
341
+ args.container.networkPolicy == null
342
+ ? undefined
343
+ : args.container.networkPolicy.type === 'disabled'
344
+ ? { type: 'disabled' }
345
+ : {
346
+ type: 'allowlist',
347
+ allowed_domains:
348
+ args.container.networkPolicy.allowedDomains,
349
+ domain_secrets:
350
+ args.container.networkPolicy.domainSecrets,
351
+ },
352
+ },
337
353
  });
338
354
  break;
339
355
  }
@@ -407,6 +423,7 @@ export async function prepareResponsesTools({
407
423
  require_approval: requireApprovalParam ?? 'never',
408
424
  server_description: args.serverDescription,
409
425
  server_url: args.serverUrl,
426
+ tunnel_id: args.tunnelId,
410
427
  });
411
428
 
412
429
  break;
@@ -37,6 +37,25 @@ export const codeInterpreterArgsSchema = lazySchema(() =>
37
37
  z.string(),
38
38
  z.object({
39
39
  fileIds: z.array(z.string()).optional(),
40
+ memoryLimit: z.enum(['1g', '4g', '16g', '64g']).optional(),
41
+ networkPolicy: z
42
+ .discriminatedUnion('type', [
43
+ z.object({ type: z.literal('disabled') }),
44
+ z.object({
45
+ type: z.literal('allowlist'),
46
+ allowedDomains: z.array(z.string()),
47
+ domainSecrets: z
48
+ .array(
49
+ z.object({
50
+ domain: z.string(),
51
+ name: z.string(),
52
+ value: z.string(),
53
+ }),
54
+ )
55
+ .optional(),
56
+ }),
57
+ ])
58
+ .optional(),
40
59
  }),
41
60
  ])
42
61
  .optional(),
@@ -48,9 +67,26 @@ type CodeInterpreterArgs = {
48
67
  /**
49
68
  * The code interpreter container.
50
69
  * Can be a container ID
51
- * or an object that specifies uploaded file IDs to make available to your code.
70
+ * or an object that configures uploaded file IDs, the memory limit,
71
+ * and the network policy for a new container.
52
72
  */
53
- container?: string | { fileIds?: string[] };
73
+ container?:
74
+ | string
75
+ | {
76
+ fileIds?: string[];
77
+ memoryLimit?: '1g' | '4g' | '16g' | '64g';
78
+ networkPolicy?:
79
+ | { type: 'disabled' }
80
+ | {
81
+ type: 'allowlist';
82
+ allowedDomains: string[];
83
+ domainSecrets?: Array<{
84
+ domain: string;
85
+ name: string;
86
+ value: string;
87
+ }>;
88
+ };
89
+ };
54
90
  };
55
91
 
56
92
  export const codeInterpreterToolFactory = createProviderExecutedToolFactory<
package/src/tool/mcp.ts CHANGED
@@ -51,10 +51,16 @@ export const mcpArgsSchema = lazySchema(() =>
51
51
  .optional(),
52
52
  serverDescription: z.string().optional(),
53
53
  serverUrl: z.string().optional(),
54
+ tunnelId: z.string().optional(),
54
55
  })
55
56
  .refine(
56
- v => v.serverUrl != null || v.connectorId != null,
57
- 'One of serverUrl or connectorId must be provided.',
57
+ v => v.serverUrl != null || v.connectorId != null || v.tunnelId != null,
58
+ 'One of serverUrl, connectorId, or tunnelId must be provided.',
59
+ )
60
+ .refine(
61
+ v =>
62
+ v.tunnelId == null || (v.serverUrl == null && v.connectorId == null),
63
+ 'tunnelId cannot be combined with serverUrl or connectorId.',
58
64
  ),
59
65
  ),
60
66
  );
@@ -74,7 +80,7 @@ export const mcpOutputSchema = lazySchema(() =>
74
80
  ),
75
81
  );
76
82
 
77
- type McpArgs = {
83
+ type McpCommonArgs = {
78
84
  /** A label for this MCP server, used to identify it in tool calls. */
79
85
  serverLabel: string;
80
86
  /** List of allowed tool names or a filter object. */
@@ -84,10 +90,8 @@ type McpArgs = {
84
90
  readOnly?: boolean;
85
91
  toolNames?: string[];
86
92
  };
87
- /** OAuth access token usable with the remote MCP server or connector. */
93
+ /** OAuth access token usable with the remote MCP server or connector (including tunneled servers). */
88
94
  authorization?: string;
89
- /** Identifier for a service connector. */
90
- connectorId?: string;
91
95
  /** Optional HTTP headers to send to the MCP server. */
92
96
  headers?: Record<string, string>;
93
97
  /**
@@ -103,10 +107,25 @@ type McpArgs = {
103
107
  };
104
108
  /** Optional description of the MCP server. */
105
109
  serverDescription?: string;
106
- /** URL for the MCP server. One of serverUrl or connectorId must be provided. */
107
- serverUrl?: string;
108
110
  };
109
111
 
112
+ type McpArgs = McpCommonArgs &
113
+ (
114
+ | {
115
+ /** URL for the MCP server. */
116
+ serverUrl?: string;
117
+ /** Identifier for a service connector. */
118
+ connectorId?: string;
119
+ tunnelId?: never;
120
+ }
121
+ | {
122
+ /** Identifier for an OpenAI Secure MCP tunnel. */
123
+ tunnelId: string;
124
+ serverUrl?: never;
125
+ connectorId?: never;
126
+ }
127
+ );
128
+
110
129
  export const mcpToolFactory = createProviderExecutedToolFactory<
111
130
  {},
112
131
  {
@@ -162,6 +162,7 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
162
162
  audio,
163
163
  mediaType,
164
164
  providerOptions,
165
+ timestampGranularities: requestedTimestampGranularities,
165
166
  }: OpenAITranscriptionCallOptions) {
166
167
  const warnings: SharedV4Warning[] = [];
167
168
 
@@ -194,12 +195,42 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
194
195
  const responseFormat =
195
196
  openAIOptions?.responseFormat ?? requestConfig.responseFormat;
196
197
 
197
- // Timestamps are only returned with verbose_json, so only default to
198
- // segments when that format is used.
198
+ // Only verbose_json accepts timestamp_granularities. Diarized JSON
199
+ // always returns segment timings without a timestamp control.
199
200
  const timestampGranularities =
200
201
  openAIOptions?.timestampGranularities ??
202
+ requestedTimestampGranularities ??
201
203
  (responseFormat === 'verbose_json' ? ['segment'] : undefined);
202
204
 
205
+ for (const granularity of requestedTimestampGranularities ?? []) {
206
+ if (
207
+ openAIOptions?.timestampGranularities != null &&
208
+ !openAIOptions.timestampGranularities.includes(granularity)
209
+ ) {
210
+ warnings.push({
211
+ type: 'unsupported',
212
+ feature: 'timestampGranularities',
213
+ details: `The "${granularity}" timestamp granularity is excluded by providerOptions.openai.timestampGranularities.`,
214
+ });
215
+ }
216
+ }
217
+
218
+ for (const granularity of timestampGranularities ?? []) {
219
+ if (
220
+ responseFormat !== 'verbose_json' &&
221
+ !(responseFormat === 'diarized_json' && granularity === 'segment')
222
+ ) {
223
+ warnings.push({
224
+ type: 'unsupported',
225
+ feature:
226
+ openAIOptions?.timestampGranularities != null
227
+ ? 'providerOptions.openai.timestampGranularities'
228
+ : 'timestampGranularities',
229
+ details: `OpenAI transcription with the ${responseFormat ?? 'default JSON'} response format does not support ${granularity} timestamps.`,
230
+ });
231
+ }
232
+ }
233
+
203
234
  const chunkingStrategy =
204
235
  openAIOptions?.chunkingStrategy ?? requestConfig.chunkingStrategy;
205
236
 
@@ -211,7 +242,8 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
211
242
  keywords: openAIOptions?.keywords,
212
243
  prompt: openAIOptions?.prompt,
213
244
  temperature: openAIOptions?.temperature,
214
- timestamp_granularities: timestampGranularities,
245
+ timestamp_granularities:
246
+ responseFormat === 'verbose_json' ? timestampGranularities : undefined,
215
247
  };
216
248
 
217
249
  for (const [key, value] of Object.entries(transcriptionModelOptions)) {
@@ -314,6 +346,12 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
314
346
  : [],
315
347
  );
316
348
 
349
+ const words = response.words?.map(word => ({
350
+ text: word.word,
351
+ startSecond: word.start,
352
+ endSecond: word.end,
353
+ }));
354
+
317
355
  return {
318
356
  text: response.text,
319
357
  segments:
@@ -322,12 +360,9 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
322
360
  startSecond: segment.start,
323
361
  endSecond: segment.end,
324
362
  })) ??
325
- response.words?.map(word => ({
326
- text: word.word,
327
- startSecond: word.start,
328
- endSecond: word.end,
329
- })) ??
363
+ words ??
330
364
  [],
365
+ ...(words != null && words.length > 0 ? { words } : {}),
331
366
  language,
332
367
  // Duration-billed json responses report the duration only in `usage`:
333
368
  durationInSeconds: