@ai-sdk/openai 3.0.135 → 3.0.136

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.
@@ -2847,6 +2847,30 @@ const result = await transcribe({
2847
2847
  });
2848
2848
  ```
2849
2849
 
2850
+ For `gpt-transcribe`, use `languages` for expected languages and `keywords` for
2851
+ names, acronyms, and domain vocabulary. These hints are sent as repeated
2852
+ `languages[]` and `keywords[]` multipart fields:
2853
+
2854
+ ```ts
2855
+ import { transcribe } from 'ai';
2856
+ import { openai, type OpenAITranscriptionModelOptions } from '@ai-sdk/openai';
2857
+
2858
+ const result = await transcribe({
2859
+ model: openai.transcription('gpt-transcribe'),
2860
+ audio: new Uint8Array([1, 2, 3, 4]),
2861
+ providerOptions: {
2862
+ openai: {
2863
+ languages: ['en', 'fr'],
2864
+ keywords: ['premium plan', 'AC-42'],
2865
+ prompt: 'A customer support call.',
2866
+ } satisfies OpenAITranscriptionModelOptions,
2867
+ },
2868
+ });
2869
+ ```
2870
+
2871
+ Use `languages` instead of `language` with `gpt-transcribe`; do not send both.
2872
+ The API validates model support and language codes. These options apply to REST transcription.
2873
+
2850
2874
  To get word-level timestamps, specify the granularity:
2851
2875
 
2852
2876
  ```ts highlight="8-9"
@@ -2880,6 +2904,16 @@ The following provider options are available:
2880
2904
  The language of the input audio. Supplying the input language in ISO-639-1 format (e.g. 'en') will improve accuracy and latency.
2881
2905
  Optional.
2882
2906
 
2907
+ - **languages** _string[]_
2908
+ Expected languages for REST transcription, such as `['en', 'fr']` for `gpt-transcribe`.
2909
+ Use this instead of `language`; do not send both. The API validates model support.
2910
+ Optional.
2911
+
2912
+ - **keywords** _string[]_
2913
+ Vocabulary hints for REST transcription, such as product names, acronyms, or technical terms.
2914
+ Supported by `gpt-transcribe`; the API validates support for other models.
2915
+ Optional.
2916
+
2883
2917
  - **prompt** _string_
2884
2918
  An optional text to guide the model's style or continue a previous audio segment. The prompt should match the audio language.
2885
2919
  Optional.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "3.0.135",
3
+ "version": "3.0.136",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -36,8 +36,8 @@
36
36
  }
37
37
  },
38
38
  "dependencies": {
39
- "@ai-sdk/provider-utils": "4.0.63",
40
- "@ai-sdk/provider": "3.0.19"
39
+ "@ai-sdk/provider": "3.0.19",
40
+ "@ai-sdk/provider-utils": "4.0.64"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "20.17.24",
@@ -5,10 +5,29 @@ import {
5
5
  type SharedV3ProviderOptions,
6
6
  } from '@ai-sdk/provider';
7
7
  import type { OpenAIChatPrompt } from './openai-chat-prompt';
8
- import { convertToBase64 } from '@ai-sdk/provider-utils';
8
+ import {
9
+ secureJsonParse,
10
+ stringifyWithBigIntAndCycles,
11
+ convertToBase64,
12
+ } from '@ai-sdk/provider-utils';
9
13
 
10
14
  function serializeToolCallArguments(input: unknown): string {
11
- return JSON.stringify(
15
+ if (typeof input === 'string') {
16
+ try {
17
+ const parsed = secureJsonParse(input);
18
+ if (
19
+ typeof parsed !== 'object' ||
20
+ parsed === null ||
21
+ Array.isArray(parsed)
22
+ ) {
23
+ return '{}';
24
+ }
25
+ return input;
26
+ } catch {
27
+ return '{}';
28
+ }
29
+ }
30
+ return stringifyWithBigIntAndCycles(
12
31
  typeof input === 'object' && input !== null && !Array.isArray(input)
13
32
  ? input
14
33
  : {},
@@ -304,7 +323,7 @@ export function convertToOpenAIChatMessages({
304
323
  case 'content':
305
324
  case 'json':
306
325
  case 'error-json':
307
- contentValue = JSON.stringify(output.value);
326
+ contentValue = stringifyWithBigIntAndCycles(output.value);
308
327
  break;
309
328
  }
310
329
 
@@ -8,6 +8,8 @@ import {
8
8
  type SharedV3Warning,
9
9
  } from '@ai-sdk/provider';
10
10
  import {
11
+ secureJsonParse,
12
+ stringifyWithBigIntAndCycles,
11
13
  lazySchema,
12
14
  zodSchema,
13
15
  type InferSchema,
@@ -49,7 +51,15 @@ import {
49
51
  } from './expand-parallel-tool-call';
50
52
 
51
53
  function serializeToolCallArguments(input: unknown): string {
52
- return JSON.stringify(input === undefined ? {} : input);
54
+ if (typeof input === 'string') {
55
+ try {
56
+ secureJsonParse(input);
57
+ return input;
58
+ } catch {
59
+ return stringifyWithBigIntAndCycles(input);
60
+ }
61
+ }
62
+ return stringifyWithBigIntAndCycles(input === undefined ? {} : input);
53
63
  }
54
64
 
55
65
  async function convertWebSearchToolResultOutput({
@@ -146,7 +156,7 @@ async function convertFunctionToolResultOutput({
146
156
  }
147
157
  case 'json':
148
158
  case 'error-json':
149
- return convertScalarOutput(JSON.stringify(output.value));
159
+ return convertScalarOutput(stringifyWithBigIntAndCycles(output.value));
150
160
  case 'content':
151
161
  return output.value
152
162
  .map(item => {
@@ -901,7 +911,7 @@ export async function convertToOpenAIResponsesInput({
901
911
  input:
902
912
  typeof part.input === 'string'
903
913
  ? part.input
904
- : JSON.stringify(part.input),
914
+ : stringifyWithBigIntAndCycles(part.input),
905
915
  ...(isAsync != null && { async: isAsync }),
906
916
  id,
907
917
  });
@@ -1101,7 +1111,7 @@ export async function convertToOpenAIResponsesInput({
1101
1111
  } else if (reasoningMessage !== undefined) {
1102
1112
  warnings.push({
1103
1113
  type: 'other',
1104
- message: `Cannot append empty reasoning part to existing reasoning sequence. Skipping reasoning part: ${JSON.stringify(part)}.`,
1114
+ message: `Cannot append empty reasoning part to existing reasoning sequence. Skipping reasoning part: ${stringifyWithBigIntAndCycles(part)}.`,
1105
1115
  });
1106
1116
  }
1107
1117
 
@@ -1152,7 +1162,7 @@ export async function convertToOpenAIResponsesInput({
1152
1162
  } else {
1153
1163
  warnings.push({
1154
1164
  type: 'other',
1155
- message: `Non-OpenAI reasoning parts are not supported. Skipping reasoning part: ${JSON.stringify(part)}.`,
1165
+ message: `Non-OpenAI reasoning parts are not supported. Skipping reasoning part: ${stringifyWithBigIntAndCycles(part)}.`,
1156
1166
  });
1157
1167
  }
1158
1168
  }
@@ -1238,7 +1248,9 @@ export async function convertToOpenAIResponsesInput({
1238
1248
  }),
1239
1249
  );
1240
1250
  const serializedToolOutputs = toolOutputs.map(({ output }) =>
1241
- typeof output === 'string' ? output : JSON.stringify(output),
1251
+ typeof output === 'string'
1252
+ ? output
1253
+ : stringifyWithBigIntAndCycles(output),
1242
1254
  );
1243
1255
  const hasPromptCacheBreakpoint = toolOutputs.some(
1244
1256
  ({ promptCacheBreakpoint }) => promptCacheBreakpoint != null,
@@ -1394,7 +1406,9 @@ export async function convertToOpenAIResponsesInput({
1394
1406
  break;
1395
1407
  case 'json':
1396
1408
  case 'error-json':
1397
- outputValue = convertScalarOutput(JSON.stringify(output.value));
1409
+ outputValue = convertScalarOutput(
1410
+ stringifyWithBigIntAndCycles(output.value),
1411
+ );
1398
1412
  break;
1399
1413
  case 'content':
1400
1414
  outputValue = output.value
@@ -142,6 +142,8 @@ export class OpenAITranscriptionModel implements TranscriptionModelV3 {
142
142
  const transcriptionModelOptions = {
143
143
  include: openAIOptions.include,
144
144
  language: openAIOptions.language,
145
+ languages: openAIOptions.languages,
146
+ keywords: openAIOptions.keywords,
145
147
  prompt: openAIOptions.prompt,
146
148
  // https://platform.openai.com/docs/api-reference/audio/createTranscription#audio_createtranscription-response_format
147
149
  // prefer verbose_json to get segments for models that support it
@@ -29,6 +29,18 @@ export const openAITranscriptionModelOptions = lazySchema(() =>
29
29
  */
30
30
  language: z.string().optional(),
31
31
 
32
+ /**
33
+ * Expected languages for REST transcription, e.g. with gpt-transcribe.
34
+ * Use this instead of language. The API validates model support.
35
+ */
36
+ languages: z.array(z.string()).optional(),
37
+
38
+ /**
39
+ * Vocabulary hints for REST transcription, e.g. names or technical terms.
40
+ * The API validates model support.
41
+ */
42
+ keywords: z.array(z.string()).optional(),
43
+
32
44
  /**
33
45
  * An optional text to guide the model's style or continue a previous audio segment.
34
46
  */