@ai-sdk/openai 4.0.96 → 4.0.98

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "4.0.96",
3
+ "version": "4.0.98",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -35,13 +35,14 @@
35
35
  }
36
36
  },
37
37
  "dependencies": {
38
- "@ai-sdk/provider": "4.0.29",
39
- "@ai-sdk/provider-utils": "5.0.62"
38
+ "@ai-sdk/provider": "4.0.31",
39
+ "@ai-sdk/provider-utils": "5.0.64"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@ai-sdk/test-server": "2.0.4",
43
43
  "@types/node": "22.19.19",
44
44
  "@vercel/ai-tsconfig": "0.0.0",
45
+ "@vercel/ai-tsdown-config": "0.0.0",
45
46
  "tsdown": "^0.23.0",
46
47
  "typescript": "6.0.3",
47
48
  "zod": "3.25.76"
@@ -52,6 +52,8 @@ import { normalizeOpenAIJsonSchema } from '../normalize-openai-json-schema';
52
52
 
53
53
  type OpenAIChatConfig = {
54
54
  provider: string;
55
+ /** Model ID sent to the API. Defaults to the model's reported ID. */
56
+ requestModelId?: string;
55
57
  headers?: () => Record<string, string | undefined>;
56
58
  url: (options: { modelId: string; path: string }) => string;
57
59
  fetch?: FetchFunction;
@@ -182,7 +184,7 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
182
184
 
183
185
  const baseArgs = {
184
186
  // model id:
185
- model: this.modelId,
187
+ model: this.config.requestModelId ?? this.modelId,
186
188
 
187
189
  // model specific settings:
188
190
  logit_bias: openaiOptions.logitBias,
@@ -404,7 +406,7 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
404
406
  } = await postJsonToApi({
405
407
  url: this.config.url({
406
408
  path: '/chat/completions',
407
- modelId: this.modelId,
409
+ modelId: this.config.requestModelId ?? this.modelId,
408
410
  }),
409
411
  headers: combineHeaders(this.config.headers?.(), options.headers),
410
412
  body,
@@ -504,7 +506,7 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
504
506
 
505
507
  const url = this.config.url({
506
508
  path: '/chat/completions',
507
- modelId: this.modelId,
509
+ modelId: this.config.requestModelId ?? this.modelId,
508
510
  });
509
511
 
510
512
  const { responseHeaders, value: response } = await postJsonToApi({
@@ -43,6 +43,8 @@ import {
43
43
  } from './openai-completion-language-model-options';
44
44
  type OpenAICompletionConfig = {
45
45
  provider: string;
46
+ /** Model ID sent to the API. Defaults to the model's reported ID. */
47
+ requestModelId?: string;
46
48
  headers?: () => Record<string, string | undefined>;
47
49
  url: (options: { modelId: string; path: string }) => string;
48
50
  fetch?: FetchFunction;
@@ -148,7 +150,7 @@ export class OpenAICompletionLanguageModel implements LanguageModelV4 {
148
150
  return {
149
151
  args: {
150
152
  // model id:
151
- model: this.modelId,
153
+ model: this.config.requestModelId ?? this.modelId,
152
154
 
153
155
  // model specific settings:
154
156
  echo: openaiOptions.echo,
@@ -192,7 +194,7 @@ export class OpenAICompletionLanguageModel implements LanguageModelV4 {
192
194
  } = await postJsonToApi({
193
195
  url: this.config.url({
194
196
  path: '/completions',
195
- modelId: this.modelId,
197
+ modelId: this.config.requestModelId ?? this.modelId,
196
198
  }),
197
199
  headers: combineHeaders(this.config.headers?.(), options.headers),
198
200
  body: args,
@@ -246,7 +248,7 @@ export class OpenAICompletionLanguageModel implements LanguageModelV4 {
246
248
 
247
249
  const url = this.config.url({
248
250
  path: '/completions',
249
- modelId: this.modelId,
251
+ modelId: this.config.requestModelId ?? this.modelId,
250
252
  });
251
253
 
252
254
  const { responseHeaders, value: response } = await postJsonToApi({
@@ -11,6 +11,8 @@ type SerializedOpenAIConfig = Omit<Partial<OpenAIConfig>, 'headers'> & {
11
11
 
12
12
  export type OpenAIConfig = {
13
13
  provider: string;
14
+ /** Model ID sent to the API. Defaults to the model's reported ID. */
15
+ requestModelId?: string;
14
16
  baseURL?: string;
15
17
  url: (options: { modelId: string; path: string }) => string;
16
18
  headers?: () => OpenAIHeaders;
@@ -114,6 +114,8 @@ export class DecisionOpenAIModel implements DecisionModelV4 {
114
114
  async doDecide({
115
115
  state,
116
116
  questions,
117
+ maxOutputTokens,
118
+ reasoning,
117
119
  headers,
118
120
  abortSignal,
119
121
  providerOptions,
@@ -180,7 +182,10 @@ export class DecisionOpenAIModel implements DecisionModelV4 {
180
182
  },
181
183
  ],
182
184
  questions: Object.entries(questions).map(([name, question]) => {
183
- const instructions = toText(question.instructions);
185
+ const instructions =
186
+ question.instructions == null
187
+ ? question.instructions
188
+ : toText(question.instructions);
184
189
  switch (question.type) {
185
190
  case 'boolean':
186
191
  return {
@@ -195,7 +200,7 @@ export class DecisionOpenAIModel implements DecisionModelV4 {
195
200
  ? undefined
196
201
  : `Criteria for false:\n${toText(question.criteria.false)}`,
197
202
  ]
198
- .filter(part => part !== undefined)
203
+ .filter(part => part != null)
199
204
  .join('\n\n'),
200
205
  };
201
206
  case 'choice':
@@ -299,12 +304,20 @@ export class DecisionOpenAIModel implements DecisionModelV4 {
299
304
  },
300
305
  // The Decisions API reports probabilities and scores to two decimal places.
301
306
  rounding: { probabilityDecimals: 2, scoreDecimals: 2 },
302
- warnings: Object.keys(providerOptions?.openai ?? {})
303
- .filter(option => option !== 'safetyIdentifier')
304
- .map(option => ({
305
- type: 'unsupported',
306
- feature: `providerOptions.openai.${option}`,
307
- })),
307
+ warnings: [
308
+ ...(maxOutputTokens != null
309
+ ? [{ type: 'unsupported' as const, feature: 'maxOutputTokens' }]
310
+ : []),
311
+ ...(reasoning != null
312
+ ? [{ type: 'unsupported' as const, feature: 'reasoning' }]
313
+ : []),
314
+ ...Object.keys(providerOptions?.openai ?? {})
315
+ .filter(option => option !== 'safetyIdentifier')
316
+ .map(option => ({
317
+ type: 'unsupported' as const,
318
+ feature: `providerOptions.openai.${option}`,
319
+ })),
320
+ ],
308
321
  providerMetadata: {
309
322
  openai: {
310
323
  ...(response.usage == null ? {} : { usage: response.usage }),
@@ -1224,6 +1224,9 @@ export async function convertToOpenAIResponsesInput({
1224
1224
  input.push({
1225
1225
  type: 'shell_call_output',
1226
1226
  call_id: part.toolCallId,
1227
+ ...(parsedOutput.maxOutputLength != null && {
1228
+ max_output_length: parsedOutput.maxOutputLength,
1229
+ }),
1227
1230
  output: parsedOutput.output.map(item => ({
1228
1231
  stdout: item.stdout,
1229
1232
  stderr: item.stderr,
@@ -1565,6 +1568,9 @@ export async function convertToOpenAIResponsesInput({
1565
1568
  input.push({
1566
1569
  type: 'shell_call_output',
1567
1570
  call_id: part.toolCallId,
1571
+ ...(parsedOutput.maxOutputLength != null && {
1572
+ max_output_length: parsedOutput.maxOutputLength,
1573
+ }),
1568
1574
  output: parsedOutput.output.map(item => ({
1569
1575
  stdout: item.stdout,
1570
1576
  stderr: item.stderr,
@@ -1061,6 +1061,8 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
1061
1061
  status: z.enum(['in_progress', 'completed', 'incomplete']),
1062
1062
  action: z.object({
1063
1063
  commands: z.array(z.string()),
1064
+ timeout_ms: z.number().nullish(),
1065
+ max_output_length: z.number().nullish(),
1064
1066
  }),
1065
1067
  }),
1066
1068
  z.object({
@@ -1073,6 +1075,7 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
1073
1075
  id: z.string(),
1074
1076
  call_id: z.string(),
1075
1077
  status: z.enum(['in_progress', 'completed', 'incomplete']),
1078
+ max_output_length: z.number().nullish(),
1076
1079
  output: z.array(
1077
1080
  z.object({
1078
1081
  stdout: z.string(),
@@ -1296,6 +1299,8 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
1296
1299
  status: z.enum(['in_progress', 'completed', 'incomplete']),
1297
1300
  action: z.object({
1298
1301
  commands: z.array(z.string()),
1302
+ timeout_ms: z.number().nullish(),
1303
+ max_output_length: z.number().nullish(),
1299
1304
  }),
1300
1305
  }),
1301
1306
  z.object({
@@ -1308,6 +1313,7 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
1308
1313
  id: z.string(),
1309
1314
  call_id: z.string(),
1310
1315
  status: z.enum(['in_progress', 'completed', 'incomplete']),
1316
+ max_output_length: z.number().nullish(),
1311
1317
  output: z.array(
1312
1318
  z.object({
1313
1319
  stdout: z.string(),
@@ -1737,6 +1743,8 @@ export const openaiResponsesResponseSchema = lazySchema(() =>
1737
1743
  status: z.enum(['in_progress', 'completed', 'incomplete']),
1738
1744
  action: z.object({
1739
1745
  commands: z.array(z.string()),
1746
+ timeout_ms: z.number().nullish(),
1747
+ max_output_length: z.number().nullish(),
1740
1748
  }),
1741
1749
  }),
1742
1750
  z.object({
@@ -1749,6 +1757,7 @@ export const openaiResponsesResponseSchema = lazySchema(() =>
1749
1757
  id: z.string(),
1750
1758
  call_id: z.string(),
1751
1759
  status: z.enum(['in_progress', 'completed', 'incomplete']),
1760
+ max_output_length: z.number().nullish(),
1752
1761
  output: z.array(
1753
1762
  z.object({
1754
1763
  stdout: z.string(),
@@ -598,7 +598,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
598
598
  }
599
599
 
600
600
  const baseArgs = {
601
- model: modelId,
601
+ model: config.requestModelId ?? modelId,
602
602
  input,
603
603
  temperature,
604
604
  top_p: topP,
@@ -854,7 +854,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
854
854
  } = await this.getArgs(options);
855
855
  const url = this.config.url({
856
856
  path: '/responses',
857
- modelId: this.modelId,
857
+ modelId: this.config.requestModelId ?? this.modelId,
858
858
  });
859
859
 
860
860
  const approvalRequestIdToDummyToolCallIdFromPrompt =
@@ -1045,6 +1045,8 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1045
1045
  input: JSON.stringify({
1046
1046
  action: {
1047
1047
  commands: part.action.commands,
1048
+ timeoutMs: part.action.timeout_ms ?? undefined,
1049
+ maxOutputLength: part.action.max_output_length ?? undefined,
1048
1050
  },
1049
1051
  } satisfies InferSchema<typeof shellInputSchema>),
1050
1052
  ...(isShellProviderExecuted && { providerExecuted: true }),
@@ -1064,6 +1066,9 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1064
1066
  toolCallId: part.call_id,
1065
1067
  toolName: toolNameMapping.toCustomToolName('shell'),
1066
1068
  result: {
1069
+ ...(part.max_output_length != null && {
1070
+ maxOutputLength: part.max_output_length,
1071
+ }),
1067
1072
  output: part.output.map(item => ({
1068
1073
  stdout: item.stdout,
1069
1074
  stderr: item.stderr,
@@ -1547,7 +1552,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1547
1552
 
1548
1553
  const url = this.config.url({
1549
1554
  path: '/responses',
1550
- modelId: this.modelId,
1555
+ modelId: this.config.requestModelId ?? this.modelId,
1551
1556
  });
1552
1557
 
1553
1558
  const { responseHeaders, value: response } = await postJsonToApi({
@@ -2530,6 +2535,9 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
2530
2535
  input: JSON.stringify({
2531
2536
  action: {
2532
2537
  commands: value.item.action.commands,
2538
+ timeoutMs: value.item.action.timeout_ms ?? undefined,
2539
+ maxOutputLength:
2540
+ value.item.action.max_output_length ?? undefined,
2533
2541
  },
2534
2542
  } satisfies InferSchema<typeof shellInputSchema>),
2535
2543
  ...(isShellProviderExecuted && {
@@ -2545,6 +2553,9 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
2545
2553
  toolCallId: value.item.call_id,
2546
2554
  toolName: toolNameMapping.toCustomToolName('shell'),
2547
2555
  result: {
2556
+ ...(value.item.max_output_length != null && {
2557
+ maxOutputLength: value.item.max_output_length,
2558
+ }),
2548
2559
  output: value.item.output.map(
2549
2560
  (item: {
2550
2561
  stdout: string;
package/src/tool/shell.ts CHANGED
@@ -21,6 +21,7 @@ export const shellInputSchema = lazySchema(() =>
21
21
  export const shellOutputSchema = lazySchema(() =>
22
22
  zodSchema(
23
23
  z.object({
24
+ maxOutputLength: z.number().optional(),
24
25
  output: z.array(
25
26
  z.object({
26
27
  stdout: z.string(),
@@ -180,6 +181,11 @@ export const shell = createProviderDefinedToolFactoryWithOutputSchema<
180
181
  };
181
182
  },
182
183
  {
184
+ /**
185
+ * Optional maximum number of characters that was applied to each command's output.
186
+ */
187
+ maxOutputLength?: number;
188
+
183
189
  /**
184
190
  * An array of shell call output contents.
185
191
  */
@@ -6,6 +6,7 @@ export const openaiTranscriptionResponseSchema = lazySchema(() =>
6
6
  z.object({
7
7
  text: z.string(),
8
8
  language: z.string().nullish(),
9
+ languages: z.array(z.object({ code: z.string() })).nullish(),
9
10
  duration: z.number().nullish(),
10
11
  words: z
11
12
  .array(
@@ -136,6 +136,12 @@ const languageMap = {
136
136
  welsh: 'cy',
137
137
  };
138
138
 
139
+ function isLanguageCode(
140
+ language: string | null | undefined,
141
+ ): language is string {
142
+ return language != null && /^[a-z]{2}$/.test(language);
143
+ }
144
+
139
145
  export class OpenAITranscriptionModel implements TranscriptionModelV4 {
140
146
  readonly specificationVersion = 'v4';
141
147
 
@@ -299,9 +305,16 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
299
305
  });
300
306
 
301
307
  const language =
302
- response.language != null && response.language in languageMap
303
- ? languageMap[response.language as keyof typeof languageMap]
304
- : undefined;
308
+ (isLanguageCode(response.language)
309
+ ? response.language
310
+ : response.language != null &&
311
+ Object.prototype.hasOwnProperty.call(languageMap, response.language)
312
+ ? languageMap[response.language as keyof typeof languageMap]
313
+ : undefined) ??
314
+ (response.languages?.length === 1 &&
315
+ isLanguageCode(response.languages[0].code)
316
+ ? response.languages[0].code
317
+ : undefined);
305
318
 
306
319
  const diarizedSegments = response.segments?.flatMap(segment =>
307
320
  'speaker' in segment
@@ -340,14 +353,20 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
340
353
  headers: responseHeaders,
341
354
  body: rawResponse,
342
355
  },
343
- ...(diarizedSegments != null &&
344
- diarizedSegments.length > 0 && {
345
- providerMetadata: {
346
- openai: {
347
- segments: diarizedSegments,
348
- },
356
+ ...(((diarizedSegments != null && diarizedSegments.length > 0) ||
357
+ response.languages != null) && {
358
+ providerMetadata: {
359
+ openai: {
360
+ ...(diarizedSegments != null &&
361
+ diarizedSegments.length > 0 && {
362
+ segments: diarizedSegments,
363
+ }),
364
+ ...(response.languages != null && {
365
+ languages: response.languages,
366
+ }),
349
367
  },
350
- }),
368
+ },
369
+ }),
351
370
  };
352
371
  }
353
372