@ai-sdk/openai 4.0.105 → 4.0.107

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 (35) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/index.d.ts +51 -9
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +611 -202
  5. package/dist/index.js.map +1 -1
  6. package/dist/internal/index.d.ts +6 -4
  7. package/dist/internal/index.d.ts.map +1 -1
  8. package/dist/internal/index.js +565 -164
  9. package/dist/internal/index.js.map +1 -1
  10. package/docs/03-openai.mdx +127 -5
  11. package/package.json +3 -3
  12. package/src/chat/convert-to-openai-chat-messages.ts +22 -3
  13. package/src/chat/openai-chat-language-model.ts +27 -20
  14. package/src/completion/openai-completion-language-model.ts +11 -3
  15. package/src/embedding/openai-embedding-model.ts +2 -1
  16. package/src/files/openai-files.ts +10 -8
  17. package/src/image/openai-image-model-options.ts +10 -20
  18. package/src/image/openai-image-model.ts +10 -21
  19. package/src/live/openai-realtime-model-live.ts +15 -16
  20. package/src/openai-batch.ts +22 -6
  21. package/src/openai-config.ts +2 -1
  22. package/src/openai-decision-model.ts +2 -1
  23. package/src/openai-model-catalog.ts +935 -0
  24. package/src/openai-provider.ts +18 -13
  25. package/src/realtime/openai-realtime-factory.ts +6 -6
  26. package/src/realtime/openai-realtime-model.ts +7 -3
  27. package/src/resolve-openai-reasoning-effort.ts +45 -0
  28. package/src/responses/convert-to-openai-responses-input.ts +29 -11
  29. package/src/responses/openai-responses-language-model.ts +28 -22
  30. package/src/skills/openai-skills.ts +4 -2
  31. package/src/speech/openai-speech-model.ts +5 -1
  32. package/src/speech-translation/openai-speech-translation-model.ts +5 -1
  33. package/src/transcription/openai-transcription-model-options.ts +12 -0
  34. package/src/transcription/openai-transcription-model.ts +29 -56
  35. package/src/openai-language-model-capabilities.ts +0 -196
@@ -12,6 +12,8 @@ import type {
12
12
  Experimental_SpeechTranslationModelV4 as SpeechTranslationModelV4,
13
13
  } from '@ai-sdk/provider';
14
14
  import {
15
+ type Resolvable,
16
+ resolveWith,
15
17
  loadApiKey,
16
18
  loadOptionalSetting,
17
19
  validateBaseURL,
@@ -175,8 +177,9 @@ export interface OpenAIProviderSettings {
175
177
 
176
178
  /**
177
179
  * API key for authenticating requests.
180
+ * A function is called before each request and may return a promise.
178
181
  */
179
- apiKey?: string;
182
+ apiKey?: Resolvable<string>;
180
183
 
181
184
  /**
182
185
  * OpenAI Organization.
@@ -230,18 +233,20 @@ export function createOpenAI(
230
233
  const providerName = options.name ?? 'openai';
231
234
 
232
235
  const getHeaders = () =>
233
- withUserAgentSuffix(
234
- {
235
- Authorization: `Bearer ${loadApiKey({
236
- apiKey: options.apiKey,
237
- environmentVariableName: 'OPENAI_API_KEY',
238
- description: 'OpenAI',
239
- })}`,
240
- 'OpenAI-Organization': options.organization,
241
- 'OpenAI-Project': options.project,
242
- ...options.headers,
243
- },
244
- `ai-sdk-openai/${VERSION}`,
236
+ resolveWith(options.apiKey, apiKey =>
237
+ withUserAgentSuffix(
238
+ {
239
+ Authorization: `Bearer ${loadApiKey({
240
+ apiKey,
241
+ environmentVariableName: 'OPENAI_API_KEY',
242
+ description: 'OpenAI',
243
+ })}`,
244
+ 'OpenAI-Organization': options.organization,
245
+ 'OpenAI-Project': options.project,
246
+ ...options.headers,
247
+ },
248
+ `ai-sdk-openai/${VERSION}`,
249
+ ),
245
250
  );
246
251
 
247
252
  const createChatModel = (modelId: OpenAIChatModelId) =>
@@ -5,13 +5,15 @@ import {
5
5
  type Experimental_RealtimeModelV4 as RealtimeModelV4,
6
6
  } from '@ai-sdk/provider';
7
7
  import { OpenAIRealtimeModelLive } from '../live/openai-realtime-model-live';
8
+ import {
9
+ getOpenAIRealtimeModelEntry,
10
+ type OpenAIKnownLiveModelId,
11
+ } from '../openai-model-catalog';
8
12
  import {
9
13
  OpenAIRealtimeModel,
10
14
  type OpenAIRealtimeModelConfig,
11
15
  } from './openai-realtime-model';
12
16
 
13
- const knownLiveModelIds = ['gpt-live-1'] as const;
14
-
15
17
  export type OpenAIRealtimeOptions = {
16
18
  /** Overrides model ID routing, including for early-access models. */
17
19
  api?: 'live' | 'realtime';
@@ -21,7 +23,7 @@ export interface OpenAIRealtimeFactory extends RealtimeFactoryV4 {
21
23
  (modelId: string, options: { api: 'live' }): OpenAIRealtimeModelLive;
22
24
  (modelId: string, options: { api: 'realtime' }): OpenAIRealtimeModel;
23
25
  (
24
- modelId: (typeof knownLiveModelIds)[number],
26
+ modelId: OpenAIKnownLiveModelId,
25
27
  options?: { api?: undefined },
26
28
  ): OpenAIRealtimeModelLive;
27
29
  (modelId: string, options?: OpenAIRealtimeOptions): RealtimeModelV4;
@@ -46,9 +48,7 @@ function resolveRealtimeApi(
46
48
  return api;
47
49
  }
48
50
 
49
- return knownLiveModelIds.some(knownModelId => knownModelId === modelId)
50
- ? 'live'
51
- : 'realtime';
51
+ return getOpenAIRealtimeModelEntry(modelId).requestConfig.realtime.api;
52
52
  }
53
53
 
54
54
  export function createOpenAIRealtimeFactory(
@@ -1,3 +1,8 @@
1
+ import {
2
+ type Resolvable,
3
+ resolve,
4
+ type FetchFunction,
5
+ } from '@ai-sdk/provider-utils';
1
6
  import type {
2
7
  Experimental_RealtimeModelV4 as RealtimeModelV4,
3
8
  Experimental_RealtimeModelV4ClientEvent as RealtimeModelV4ClientEvent,
@@ -6,7 +11,6 @@ import type {
6
11
  Experimental_RealtimeModelV4ServerEvent as RealtimeModelV4ServerEvent,
7
12
  Experimental_RealtimeModelV4SessionConfig as RealtimeModelV4SessionConfig,
8
13
  } from '@ai-sdk/provider';
9
- import type { FetchFunction } from '@ai-sdk/provider-utils';
10
14
  import {
11
15
  buildOpenAISessionConfig,
12
16
  parseOpenAIRealtimeServerEvent,
@@ -16,7 +20,7 @@ import {
16
20
  export type OpenAIRealtimeModelConfig = {
17
21
  provider: string;
18
22
  baseURL: string;
19
- headers: () => Record<string, string | undefined>;
23
+ headers: Resolvable<Record<string, string | undefined>>;
20
24
  fetch?: FetchFunction;
21
25
  };
22
26
 
@@ -47,7 +51,7 @@ export class OpenAIRealtimeModel implements RealtimeModelV4 {
47
51
  const response = await fetchFn(url, {
48
52
  method: 'POST',
49
53
  headers: {
50
- ...this.config.headers(),
54
+ ...(await resolve(this.config.headers)),
51
55
  'Content-Type': 'application/json',
52
56
  },
53
57
  body: JSON.stringify({
@@ -0,0 +1,45 @@
1
+ import type {
2
+ LanguageModelV4CallOptions,
3
+ SharedV4Warning,
4
+ } from '@ai-sdk/provider';
5
+ import { mapReasoningToProviderEffort } from '@ai-sdk/provider-utils';
6
+
7
+ type OpenAIReasoningEffort = Exclude<
8
+ LanguageModelV4CallOptions['reasoning'],
9
+ 'provider-default' | undefined
10
+ >;
11
+
12
+ const allOpenAIReasoningEfforts: readonly OpenAIReasoningEffort[] = [
13
+ 'none',
14
+ 'minimal',
15
+ 'low',
16
+ 'medium',
17
+ 'high',
18
+ 'xhigh',
19
+ 'max',
20
+ ];
21
+
22
+ /** Resolve portable reasoning against the efforts declared by the catalog. */
23
+ export function resolveOpenAIReasoningEffort({
24
+ providerReasoningEffort,
25
+ reasoning,
26
+ supportedReasoningEfforts,
27
+ warnings,
28
+ }: {
29
+ providerReasoningEffort: string | null | undefined;
30
+ reasoning: LanguageModelV4CallOptions['reasoning'];
31
+ supportedReasoningEfforts: readonly string[] | undefined;
32
+ warnings: SharedV4Warning[];
33
+ }): string | undefined {
34
+ return mapReasoningToProviderEffort({
35
+ reasoning,
36
+ providerOptionsEffort: providerReasoningEffort,
37
+ effortMap: Object.fromEntries(
38
+ (supportedReasoningEfforts ?? allOpenAIReasoningEfforts).map(effort => [
39
+ effort,
40
+ effort,
41
+ ]),
42
+ ),
43
+ warnings,
44
+ });
45
+ }
@@ -8,6 +8,8 @@ import {
8
8
  type SharedV4Warning,
9
9
  } from '@ai-sdk/provider';
10
10
  import {
11
+ secureJsonParse,
12
+ stringifyWithBigIntAndCycles,
11
13
  lazySchema,
12
14
  zodSchema,
13
15
  type InferSchema,
@@ -62,7 +64,15 @@ import {
62
64
  } from './expand-parallel-tool-call';
63
65
 
64
66
  function serializeToolCallArguments(input: unknown): string {
65
- return JSON.stringify(input === undefined ? {} : input);
67
+ if (typeof input === 'string') {
68
+ try {
69
+ secureJsonParse(input);
70
+ return input;
71
+ } catch {
72
+ return stringifyWithBigIntAndCycles(input);
73
+ }
74
+ }
75
+ return stringifyWithBigIntAndCycles(input === undefined ? {} : input);
66
76
  }
67
77
 
68
78
  function mapToolCaller(
@@ -172,19 +182,23 @@ async function convertFunctionToolResultOutput({
172
182
  switch (output.type) {
173
183
  case 'text':
174
184
  return convertScalarOutput(
175
- hasOutputSchema ? JSON.stringify(output.value) : output.value,
185
+ hasOutputSchema
186
+ ? stringifyWithBigIntAndCycles(output.value)
187
+ : output.value,
176
188
  );
177
189
  case 'error-text':
178
190
  case 'error-json':
179
- return convertScalarOutput(JSON.stringify({ error: output.value }));
191
+ return convertScalarOutput(
192
+ stringifyWithBigIntAndCycles({ error: output.value }),
193
+ );
180
194
  case 'execution-denied': {
181
195
  const reason = output.reason ?? 'Tool call execution denied.';
182
196
  return convertScalarOutput(
183
- hasOutputSchema ? JSON.stringify(reason) : reason,
197
+ hasOutputSchema ? stringifyWithBigIntAndCycles(reason) : reason,
184
198
  );
185
199
  }
186
200
  case 'json':
187
- return convertScalarOutput(JSON.stringify(output.value));
201
+ return convertScalarOutput(stringifyWithBigIntAndCycles(output.value));
188
202
  case 'content':
189
203
  return output.value
190
204
  .map(item => {
@@ -1074,7 +1088,7 @@ export async function convertToOpenAIResponsesInput({
1074
1088
  input:
1075
1089
  typeof part.input === 'string'
1076
1090
  ? part.input
1077
- : JSON.stringify(part.input),
1091
+ : stringifyWithBigIntAndCycles(part.input),
1078
1092
  ...(isAsync != null && { async: isAsync }),
1079
1093
  id,
1080
1094
  });
@@ -1311,7 +1325,7 @@ export async function convertToOpenAIResponsesInput({
1311
1325
  } else if (reasoningMessage !== undefined) {
1312
1326
  warnings.push({
1313
1327
  type: 'other',
1314
- message: `Cannot append empty reasoning part to existing reasoning sequence. Skipping reasoning part: ${JSON.stringify(part)}.`,
1328
+ message: `Cannot append empty reasoning part to existing reasoning sequence. Skipping reasoning part: ${stringifyWithBigIntAndCycles(part)}.`,
1315
1329
  });
1316
1330
  }
1317
1331
 
@@ -1362,7 +1376,7 @@ export async function convertToOpenAIResponsesInput({
1362
1376
  } else {
1363
1377
  warnings.push({
1364
1378
  type: 'other',
1365
- message: `Non-OpenAI reasoning parts are not supported. Skipping reasoning part: ${JSON.stringify(part)}.`,
1379
+ message: `Non-OpenAI reasoning parts are not supported. Skipping reasoning part: ${stringifyWithBigIntAndCycles(part)}.`,
1366
1380
  });
1367
1381
  }
1368
1382
  }
@@ -1480,7 +1494,9 @@ export async function convertToOpenAIResponsesInput({
1480
1494
  }),
1481
1495
  );
1482
1496
  const serializedToolOutputs = toolOutputs.map(({ output }) =>
1483
- typeof output === 'string' ? output : JSON.stringify(output),
1497
+ typeof output === 'string'
1498
+ ? output
1499
+ : stringifyWithBigIntAndCycles(output),
1484
1500
  );
1485
1501
  const hasPromptCacheBreakpoint = toolOutputs.some(
1486
1502
  ({ promptCacheBreakpoint }) => promptCacheBreakpoint != null,
@@ -1663,7 +1679,7 @@ export async function convertToOpenAIResponsesInput({
1663
1679
  case 'error-text':
1664
1680
  case 'error-json':
1665
1681
  outputValue = convertScalarOutput(
1666
- JSON.stringify({ error: output.value }),
1682
+ stringifyWithBigIntAndCycles({ error: output.value }),
1667
1683
  );
1668
1684
  break;
1669
1685
  case 'execution-denied':
@@ -1672,7 +1688,9 @@ export async function convertToOpenAIResponsesInput({
1672
1688
  );
1673
1689
  break;
1674
1690
  case 'json':
1675
- outputValue = convertScalarOutput(JSON.stringify(output.value));
1691
+ outputValue = convertScalarOutput(
1692
+ stringifyWithBigIntAndCycles(output.value),
1693
+ );
1676
1694
  break;
1677
1695
  case 'content':
1678
1696
  outputValue = output.value
@@ -17,6 +17,7 @@ import {
17
17
  type SharedV4Warning,
18
18
  } from '@ai-sdk/provider';
19
19
  import {
20
+ resolve,
20
21
  combineHeaders,
21
22
  createEventSourceResponseHandler,
22
23
  createJsonResponseHandler,
@@ -36,14 +37,12 @@ import {
36
37
  type OpenAIConfig,
37
38
  } from '../openai-config';
38
39
  import { openaiFailedResponseHandler } from '../openai-error';
39
- import {
40
- getOpenAILanguageModelCapabilities,
41
- resolveOpenAIReasoningEffort,
42
- } from '../openai-language-model-capabilities';
40
+ import { getOpenAILanguageModelEntry } from '../openai-model-catalog';
43
41
  import {
44
42
  createOpenAIProviderStreamError,
45
43
  throwIfOpenAIStreamErrorBeforeOutput,
46
44
  } from '../openai-stream-error';
45
+ import { resolveOpenAIReasoningEffort } from '../resolve-openai-reasoning-effort';
47
46
  import type { applyPatchInputSchema } from '../tool/apply-patch';
48
47
  import type {
49
48
  codeInterpreterInputSchema,
@@ -226,10 +225,10 @@ function getConfigurationUpdateUnsupportedReason({
226
225
  modelCapabilities,
227
226
  options,
228
227
  }: {
229
- modelCapabilities: { supportsConfigurationUpdate: boolean };
228
+ modelCapabilities: { configurationUpdates: boolean };
230
229
  options: OpenAILanguageModelResponsesOptions | undefined;
231
230
  }): string | undefined {
232
- if (!modelCapabilities.supportsConfigurationUpdate) {
231
+ if (!modelCapabilities.configurationUpdates) {
233
232
  return 'reasoningEffortUpdate is only supported by GPT-6 and later models';
234
233
  }
235
234
 
@@ -304,7 +303,10 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
304
303
  options: LanguageModelV4CallOptions;
305
304
  }) {
306
305
  const warnings: SharedV4Warning[] = [];
307
- const modelCapabilities = getOpenAILanguageModelCapabilities(modelId);
306
+ const {
307
+ capabilities: { language: modelCapabilities },
308
+ requestConfig: { language: modelRequestConfig },
309
+ } = getOpenAILanguageModelEntry(modelId);
308
310
 
309
311
  if (topK != null) {
310
312
  warnings.push({ type: 'unsupported', feature: 'topK' });
@@ -346,7 +348,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
346
348
  const resolvedReasoningEffort = resolveOpenAIReasoningEffort({
347
349
  providerReasoningEffort: openaiOptions?.reasoningEffort,
348
350
  reasoning,
349
- supportedReasoningEfforts: modelCapabilities.supportedReasoningEfforts,
351
+ supportedReasoningEfforts: modelCapabilities.reasoning.efforts,
350
352
  warnings,
351
353
  });
352
354
 
@@ -358,7 +360,8 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
358
360
  : undefined;
359
361
 
360
362
  const isReasoningModel =
361
- openaiOptions?.forceReasoning ?? modelCapabilities.isReasoningModel;
363
+ openaiOptions?.forceReasoning ??
364
+ modelCapabilities.reasoning.support === true;
362
365
 
363
366
  if (openaiOptions?.conversation && openaiOptions?.previousResponseId) {
364
367
  warnings.push({
@@ -402,7 +405,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
402
405
  toolNameMapping,
403
406
  customProviderToolNames,
404
407
  outputSchemaToolNames,
405
- supportsAsyncToolCalling: modelCapabilities.supportsAsyncToolCalling,
408
+ supportsAsyncToolCalling: modelCapabilities.tools.async,
406
409
  providerOptionsName,
407
410
  });
408
411
 
@@ -420,7 +423,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
420
423
  openaiOptions?.systemMessageMode ??
421
424
  (isReasoningModel
422
425
  ? 'developer'
423
- : modelCapabilities.systemMessageMode),
426
+ : modelRequestConfig.systemMessageMode),
424
427
  providerOptionsName,
425
428
  configurationUpdateUnsupportedReason,
426
429
  explicitMessageItemType: config.explicitMessageItemType,
@@ -448,10 +451,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
448
451
 
449
452
  // The schema accepts update efforts supported by any supported model. Check
450
453
  // whether this specific model supports the requested effort.
451
- const supportedReasoningEfforts =
452
- modelCapabilities.supportedReasoningEfforts as
453
- | readonly string[]
454
- | undefined;
454
+ const supportedReasoningEfforts = modelCapabilities.reasoning.efforts;
455
455
  const getUpdateEffortUnsupportedReason = (effort: string | undefined) =>
456
456
  effort != null && supportedReasoningEfforts?.includes(effort) === false
457
457
  ? `${modelId} only supports the following reasoning efforts: ${supportedReasoningEfforts.join(', ')}`
@@ -668,7 +668,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
668
668
  };
669
669
 
670
670
  if (
671
- modelCapabilities.supportsConfigurationUpdate &&
671
+ !modelCapabilities.promptCache.retention &&
672
672
  baseArgs.prompt_cache_retention != null
673
673
  ) {
674
674
  baseArgs.prompt_cache_retention = undefined;
@@ -696,7 +696,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
696
696
  if (
697
697
  !(
698
698
  effectiveReasoningEffort === 'none' &&
699
- modelCapabilities.supportsNonReasoningParameters
699
+ modelCapabilities.reasoning.sampling === 'reasoning-effort-none'
700
700
  )
701
701
  ) {
702
702
  if (baseArgs.temperature != null) {
@@ -718,7 +718,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
718
718
  }
719
719
 
720
720
  if (
721
- modelCapabilities.supportsConfigurationUpdate &&
721
+ modelCapabilities.endpoints.responses.logprobsRequireNonReasoning &&
722
722
  (baseArgs.top_logprobs != null ||
723
723
  baseArgs.include?.includes('message.output_text.logprobs'))
724
724
  ) {
@@ -774,7 +774,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
774
774
  // Validate flex processing support
775
775
  if (
776
776
  openaiOptions?.serviceTier === 'flex' &&
777
- !modelCapabilities.supportsFlexProcessing
777
+ !modelCapabilities.serviceTiers.flex
778
778
  ) {
779
779
  warnings.push({
780
780
  type: 'unsupported',
@@ -790,7 +790,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
790
790
  if (
791
791
  (openaiOptions?.serviceTier === 'priority' ||
792
792
  openaiOptions?.serviceTier === 'fast') &&
793
- !modelCapabilities.supportsPriorityProcessing
793
+ !modelCapabilities.serviceTiers.priority
794
794
  ) {
795
795
  warnings.push({
796
796
  type: 'unsupported',
@@ -860,7 +860,10 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
860
860
  rawValue: rawResponse,
861
861
  } = await postJsonToApi({
862
862
  url,
863
- headers: combineHeaders(this.config.headers?.(), options.headers),
863
+ headers: combineHeaders(
864
+ await resolve(this.config.headers),
865
+ options.headers,
866
+ ),
864
867
  body,
865
868
  failedResponseHandler: openaiFailedResponseHandler,
866
869
  successfulResponseHandler: createJsonResponseHandler(
@@ -1563,7 +1566,10 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1563
1566
 
1564
1567
  const { responseHeaders, value: response } = await postJsonToApi({
1565
1568
  url,
1566
- headers: combineHeaders(this.config.headers?.(), options.headers),
1569
+ headers: combineHeaders(
1570
+ await resolve(this.config.headers),
1571
+ options.headers,
1572
+ ),
1567
1573
  body: {
1568
1574
  ...body,
1569
1575
  stream: true,
@@ -1,5 +1,7 @@
1
1
  import type { SkillsV4, SharedV4Warning } from '@ai-sdk/provider';
2
2
  import {
3
+ type Resolvable,
4
+ resolve,
3
5
  combineHeaders,
4
6
  convertInlineFileDataToUint8Array,
5
7
  createJsonResponseHandler,
@@ -12,7 +14,7 @@ import { openaiSkillResponseSchema } from './openai-skills-api';
12
14
  interface OpenAISkillsConfig {
13
15
  provider: string;
14
16
  url: (options: { path: string }) => string;
15
- headers: () => Record<string, string | undefined>;
17
+ headers: Resolvable<Record<string, string | undefined>>;
16
18
  fetch?: FetchFunction;
17
19
  }
18
20
 
@@ -50,7 +52,7 @@ export class OpenAISkills implements SkillsV4 {
50
52
 
51
53
  const { value: response } = await postFormDataToApi({
52
54
  url: this.config.url({ path: '/skills' }),
53
- headers: combineHeaders(this.config.headers()),
55
+ headers: combineHeaders(await resolve(this.config.headers)),
54
56
  formData,
55
57
  failedResponseHandler: openaiFailedResponseHandler,
56
58
  successfulResponseHandler: createJsonResponseHandler(
@@ -1,5 +1,6 @@
1
1
  import type { SpeechModelV4, SharedV4Warning } from '@ai-sdk/provider';
2
2
  import {
3
+ resolve,
3
4
  combineHeaders,
4
5
  createBinaryResponseHandler,
5
6
  parseProviderOptions,
@@ -131,7 +132,10 @@ export class OpenAISpeechModel implements SpeechModelV4 {
131
132
  path: '/audio/speech',
132
133
  modelId: this.modelId,
133
134
  }),
134
- headers: combineHeaders(this.config.headers?.(), options.headers),
135
+ headers: combineHeaders(
136
+ await resolve(this.config.headers),
137
+ options.headers,
138
+ ),
135
139
  body: requestBody,
136
140
  failedResponseHandler: openaiFailedResponseHandler,
137
141
  successfulResponseHandler: createBinaryResponseHandler(),
@@ -6,6 +6,7 @@ import {
6
6
  type SharedV4Warning,
7
7
  } from '@ai-sdk/provider';
8
8
  import {
9
+ resolve,
9
10
  combineHeaders,
10
11
  connectToWebSocket,
11
12
  convertToBase64,
@@ -101,7 +102,10 @@ export class OpenAISpeechTranslationModel implements SpeechTranslationModelV4 {
101
102
  });
102
103
  }
103
104
 
104
- const headers = combineHeaders(this.config.headers?.(), options.headers);
105
+ const headers = combineHeaders(
106
+ await resolve(this.config.headers),
107
+ options.headers,
108
+ );
105
109
  const sessionUpdate = buildOpenAIRealtimeSpeechTranslationSession({
106
110
  targetLanguage: options.targetLanguage,
107
111
  });
@@ -32,6 +32,18 @@ export const openAITranscriptionModelOptions = lazySchema(() =>
32
32
  */
33
33
  language: z.string().optional(),
34
34
 
35
+ /**
36
+ * Expected languages for REST transcription, e.g. with gpt-transcribe.
37
+ * Use this instead of language. The API validates model support.
38
+ */
39
+ languages: z.array(z.string()).optional(),
40
+
41
+ /**
42
+ * Vocabulary hints for REST transcription, e.g. names or technical terms.
43
+ * The API validates model support.
44
+ */
45
+ keywords: z.array(z.string()).optional(),
46
+
35
47
  /**
36
48
  * An optional text to guide the model's style or continue a previous audio segment.
37
49
  */