@ai-sdk/openai 4.0.0-beta.2 → 4.0.0-beta.21

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 (48) hide show
  1. package/CHANGELOG.md +234 -22
  2. package/README.md +2 -0
  3. package/dist/index.d.mts +134 -35
  4. package/dist/index.d.ts +134 -35
  5. package/dist/index.js +1700 -1139
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +1697 -1117
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/internal/index.d.mts +107 -41
  10. package/dist/internal/index.d.ts +107 -41
  11. package/dist/internal/index.js +1380 -939
  12. package/dist/internal/index.js.map +1 -1
  13. package/dist/internal/index.mjs +1371 -917
  14. package/dist/internal/index.mjs.map +1 -1
  15. package/docs/03-openai.mdx +274 -9
  16. package/package.json +3 -5
  17. package/src/chat/convert-openai-chat-usage.ts +2 -2
  18. package/src/chat/convert-to-openai-chat-messages.ts +26 -15
  19. package/src/chat/map-openai-finish-reason.ts +2 -2
  20. package/src/chat/openai-chat-language-model.ts +32 -24
  21. package/src/chat/openai-chat-options.ts +5 -0
  22. package/src/chat/openai-chat-prepare-tools.ts +6 -6
  23. package/src/completion/convert-openai-completion-usage.ts +2 -2
  24. package/src/completion/convert-to-openai-completion-prompt.ts +2 -2
  25. package/src/completion/map-openai-finish-reason.ts +2 -2
  26. package/src/completion/openai-completion-language-model.ts +20 -20
  27. package/src/embedding/openai-embedding-model.ts +5 -5
  28. package/src/files/openai-files-api.ts +17 -0
  29. package/src/files/openai-files-options.ts +18 -0
  30. package/src/files/openai-files.ts +102 -0
  31. package/src/image/openai-image-model.ts +9 -9
  32. package/src/index.ts +2 -0
  33. package/src/openai-config.ts +5 -5
  34. package/src/openai-language-model-capabilities.ts +3 -2
  35. package/src/openai-provider.ts +39 -21
  36. package/src/openai-tools.ts +12 -1
  37. package/src/responses/convert-openai-responses-usage.ts +2 -2
  38. package/src/responses/convert-to-openai-responses-input.ts +188 -14
  39. package/src/responses/map-openai-responses-finish-reason.ts +2 -2
  40. package/src/responses/openai-responses-api.ts +136 -2
  41. package/src/responses/openai-responses-language-model.ts +233 -37
  42. package/src/responses/openai-responses-options.ts +24 -2
  43. package/src/responses/openai-responses-prepare-tools.ts +34 -9
  44. package/src/responses/openai-responses-provider-metadata.ts +10 -0
  45. package/src/speech/openai-speech-model.ts +7 -7
  46. package/src/tool/custom.ts +0 -6
  47. package/src/tool/tool-search.ts +98 -0
  48. package/src/transcription/openai-transcription-model.ts +8 -8
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  APICallError,
3
3
  JSONValue,
4
- LanguageModelV3,
5
- LanguageModelV3Prompt,
6
- LanguageModelV3CallOptions,
7
- LanguageModelV3Content,
8
- LanguageModelV3FinishReason,
9
- LanguageModelV3GenerateResult,
10
- LanguageModelV3ProviderTool,
11
- LanguageModelV3StreamPart,
12
- LanguageModelV3StreamResult,
13
- LanguageModelV3ToolApprovalRequest,
14
- SharedV3ProviderMetadata,
15
- SharedV3Warning,
4
+ LanguageModelV4,
5
+ LanguageModelV4Prompt,
6
+ LanguageModelV4CallOptions,
7
+ LanguageModelV4Content,
8
+ LanguageModelV4FinishReason,
9
+ LanguageModelV4GenerateResult,
10
+ LanguageModelV4ProviderTool,
11
+ LanguageModelV4StreamPart,
12
+ LanguageModelV4StreamResult,
13
+ LanguageModelV4ToolApprovalRequest,
14
+ SharedV4ProviderMetadata,
15
+ SharedV4Warning,
16
16
  } from '@ai-sdk/provider';
17
17
  import {
18
18
  combineHeaders,
@@ -21,6 +21,7 @@ import {
21
21
  createToolNameMapping,
22
22
  generateId,
23
23
  InferSchema,
24
+ isCustomReasoning,
24
25
  parseProviderOptions,
25
26
  ParseResult,
26
27
  postJsonToApi,
@@ -38,6 +39,10 @@ import { imageGenerationOutputSchema } from '../tool/image-generation';
38
39
  import { localShellInputSchema } from '../tool/local-shell';
39
40
  import { mcpOutputSchema } from '../tool/mcp';
40
41
  import { shellInputSchema, shellOutputSchema } from '../tool/shell';
42
+ import {
43
+ toolSearchInputSchema,
44
+ toolSearchOutputSchema,
45
+ } from '../tool/tool-search';
41
46
  import { webSearchOutputSchema } from '../tool/web-search';
42
47
  import {
43
48
  convertOpenAIResponsesUsage,
@@ -63,6 +68,7 @@ import {
63
68
  } from './openai-responses-options';
64
69
  import { prepareResponsesTools } from './openai-responses-prepare-tools';
65
70
  import {
71
+ ResponsesCompactionProviderMetadata,
66
72
  ResponsesProviderMetadata,
67
73
  ResponsesReasoningProviderMetadata,
68
74
  ResponsesSourceDocumentProviderMetadata,
@@ -77,7 +83,7 @@ import {
77
83
  * so that tool results reference the correct tool call.
78
84
  */
79
85
  function extractApprovalRequestIdToToolCallIdMapping(
80
- prompt: LanguageModelV3Prompt,
86
+ prompt: LanguageModelV4Prompt,
81
87
  ): Record<string, string> {
82
88
  const mapping: Record<string, string> = {};
83
89
  for (const message of prompt) {
@@ -94,8 +100,8 @@ function extractApprovalRequestIdToToolCallIdMapping(
94
100
  return mapping;
95
101
  }
96
102
 
97
- export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
98
- readonly specificationVersion = 'v3';
103
+ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
104
+ readonly specificationVersion = 'v4';
99
105
 
100
106
  readonly modelId: OpenAIResponsesModelId;
101
107
 
@@ -125,12 +131,13 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
125
131
  frequencyPenalty,
126
132
  seed,
127
133
  prompt,
134
+ reasoning,
128
135
  providerOptions,
129
136
  tools,
130
137
  toolChoice,
131
138
  responseFormat,
132
- }: LanguageModelV3CallOptions) {
133
- const warnings: SharedV3Warning[] = [];
139
+ }: LanguageModelV4CallOptions) {
140
+ const warnings: SharedV4Warning[] = [];
134
141
  const modelCapabilities = getOpenAILanguageModelCapabilities(this.modelId);
135
142
 
136
143
  if (topK != null) {
@@ -170,6 +177,10 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
170
177
  });
171
178
  }
172
179
 
180
+ const resolvedReasoningEffort =
181
+ openaiOptions?.reasoningEffort ??
182
+ (isCustomReasoning(reasoning) ? reasoning : undefined);
183
+
173
184
  const isReasoningModel =
174
185
  openaiOptions?.forceReasoning ?? modelCapabilities.isReasoningModel;
175
186
 
@@ -193,11 +204,8 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
193
204
  'openai.web_search_preview': 'web_search_preview',
194
205
  'openai.mcp': 'mcp',
195
206
  'openai.apply_patch': 'apply_patch',
207
+ 'openai.tool_search': 'tool_search',
196
208
  },
197
- resolveProviderToolName: tool =>
198
- tool.id === 'openai.custom'
199
- ? (tool.args as { name?: string }).name
200
- : undefined,
201
209
  });
202
210
 
203
211
  const customProviderToolNames = new Set<string>();
@@ -273,7 +281,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
273
281
  tool.type === 'provider' &&
274
282
  (tool.id === 'openai.web_search' ||
275
283
  tool.id === 'openai.web_search_preview'),
276
- ) as LanguageModelV3ProviderTool | undefined
284
+ ) as LanguageModelV4ProviderTool | undefined
277
285
  )?.name;
278
286
 
279
287
  if (webSearchToolName) {
@@ -336,13 +344,21 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
336
344
  top_logprobs: topLogprobs,
337
345
  truncation: openaiOptions?.truncation,
338
346
 
347
+ // context management (server-side compaction):
348
+ ...(openaiOptions?.contextManagement && {
349
+ context_management: openaiOptions.contextManagement.map(cm => ({
350
+ type: cm.type,
351
+ compact_threshold: cm.compactThreshold,
352
+ })),
353
+ }),
354
+
339
355
  // model-specific settings:
340
356
  ...(isReasoningModel &&
341
- (openaiOptions?.reasoningEffort != null ||
357
+ (resolvedReasoningEffort != null ||
342
358
  openaiOptions?.reasoningSummary != null) && {
343
359
  reasoning: {
344
- ...(openaiOptions?.reasoningEffort != null && {
345
- effort: openaiOptions.reasoningEffort,
360
+ ...(resolvedReasoningEffort != null && {
361
+ effort: resolvedReasoningEffort,
346
362
  }),
347
363
  ...(openaiOptions?.reasoningSummary != null && {
348
364
  summary: openaiOptions.reasoningSummary,
@@ -358,7 +374,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
358
374
  // https://platform.openai.com/docs/guides/latest-model#gpt-5-1-parameter-compatibility
359
375
  if (
360
376
  !(
361
- openaiOptions?.reasoningEffort === 'none' &&
377
+ resolvedReasoningEffort === 'none' &&
362
378
  modelCapabilities.supportsNonReasoningParameters
363
379
  )
364
380
  ) {
@@ -454,8 +470,8 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
454
470
  }
455
471
 
456
472
  async doGenerate(
457
- options: LanguageModelV3CallOptions,
458
- ): Promise<LanguageModelV3GenerateResult> {
473
+ options: LanguageModelV4CallOptions,
474
+ ): Promise<LanguageModelV4GenerateResult> {
459
475
  const {
460
476
  args: body,
461
477
  warnings,
@@ -500,11 +516,12 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
500
516
  });
501
517
  }
502
518
 
503
- const content: Array<LanguageModelV3Content> = [];
519
+ const content: Array<LanguageModelV4Content> = [];
504
520
  const logprobs: Array<OpenAIResponsesLogprobs> = [];
505
521
 
506
522
  // flag that checks if there have been client-side tool calls (not executed by openai)
507
523
  let hasFunctionCall = false;
524
+ const hostedToolSearchCallIds: string[] = [];
508
525
 
509
526
  // map response content to content array (defined when there is no error)
510
527
  for (const part of response.output!) {
@@ -551,6 +568,54 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
551
568
  break;
552
569
  }
553
570
 
571
+ case 'tool_search_call': {
572
+ const toolCallId = part.call_id ?? part.id;
573
+ const isHosted = part.execution === 'server';
574
+
575
+ if (isHosted) {
576
+ hostedToolSearchCallIds.push(toolCallId);
577
+ }
578
+
579
+ content.push({
580
+ type: 'tool-call',
581
+ toolCallId,
582
+ toolName: toolNameMapping.toCustomToolName('tool_search'),
583
+ input: JSON.stringify({
584
+ arguments: part.arguments,
585
+ call_id: part.call_id,
586
+ } satisfies InferSchema<typeof toolSearchInputSchema>),
587
+ ...(isHosted ? { providerExecuted: true } : {}),
588
+ providerMetadata: {
589
+ [providerOptionsName]: {
590
+ itemId: part.id,
591
+ },
592
+ },
593
+ });
594
+
595
+ break;
596
+ }
597
+
598
+ case 'tool_search_output': {
599
+ const toolCallId =
600
+ part.call_id ?? hostedToolSearchCallIds.shift() ?? part.id;
601
+
602
+ content.push({
603
+ type: 'tool-result',
604
+ toolCallId,
605
+ toolName: toolNameMapping.toCustomToolName('tool_search'),
606
+ result: {
607
+ tools: part.tools,
608
+ } satisfies InferSchema<typeof toolSearchOutputSchema>,
609
+ providerMetadata: {
610
+ [providerOptionsName]: {
611
+ itemId: part.id,
612
+ },
613
+ },
614
+ });
615
+
616
+ break;
617
+ }
618
+
554
619
  case 'local_shell_call': {
555
620
  content.push({
556
621
  type: 'tool-call',
@@ -621,7 +686,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
621
686
  logprobs.push(contentPart.logprobs);
622
687
  }
623
688
 
624
- const providerMetadata: SharedV3ProviderMetadata[string] = {
689
+ const providerMetadata: SharedV4ProviderMetadata[string] = {
625
690
  itemId: part.id,
626
691
  ...(part.phase != null && { phase: part.phase }),
627
692
  ...(contentPart.annotations.length > 0 && {
@@ -833,7 +898,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
833
898
  type: 'tool-approval-request',
834
899
  approvalId: approvalRequestId,
835
900
  toolCallId: dummyToolCallId,
836
- } satisfies LanguageModelV3ToolApprovalRequest);
901
+ } satisfies LanguageModelV4ToolApprovalRequest);
837
902
  break;
838
903
  }
839
904
 
@@ -927,10 +992,25 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
927
992
 
928
993
  break;
929
994
  }
995
+
996
+ case 'compaction': {
997
+ content.push({
998
+ type: 'custom',
999
+ kind: 'openai.compaction',
1000
+ providerMetadata: {
1001
+ [providerOptionsName]: {
1002
+ type: 'compaction',
1003
+ itemId: part.id,
1004
+ encryptedContent: part.encrypted_content,
1005
+ } satisfies ResponsesCompactionProviderMetadata,
1006
+ },
1007
+ });
1008
+ break;
1009
+ }
930
1010
  }
931
1011
  }
932
1012
 
933
- const providerMetadata: SharedV3ProviderMetadata = {
1013
+ const providerMetadata: SharedV4ProviderMetadata = {
934
1014
  [providerOptionsName]: {
935
1015
  responseId: response.id,
936
1016
  ...(logprobs.length > 0 ? { logprobs } : {}),
@@ -966,8 +1046,8 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
966
1046
  }
967
1047
 
968
1048
  async doStream(
969
- options: LanguageModelV3CallOptions,
970
- ): Promise<LanguageModelV3StreamResult> {
1049
+ options: LanguageModelV4CallOptions,
1050
+ ): Promise<LanguageModelV4StreamResult> {
971
1051
  const {
972
1052
  args: body,
973
1053
  warnings,
@@ -1006,7 +1086,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1006
1086
  string
1007
1087
  >();
1008
1088
 
1009
- let finishReason: LanguageModelV3FinishReason = {
1089
+ let finishReason: LanguageModelV4FinishReason = {
1010
1090
  unified: 'other',
1011
1091
  raw: undefined,
1012
1092
  };
@@ -1026,6 +1106,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1026
1106
  hasDiff: boolean;
1027
1107
  endEmitted: boolean;
1028
1108
  };
1109
+ toolSearchExecution?: 'server' | 'client';
1029
1110
  }
1030
1111
  | undefined
1031
1112
  > = {};
@@ -1054,12 +1135,13 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1054
1135
  > = {};
1055
1136
 
1056
1137
  let serviceTier: string | undefined;
1138
+ const hostedToolSearchCallIds: string[] = [];
1057
1139
 
1058
1140
  return {
1059
1141
  stream: response.pipeThrough(
1060
1142
  new TransformStream<
1061
1143
  ParseResult<OpenAIResponsesChunk>,
1062
- LanguageModelV3StreamPart
1144
+ LanguageModelV4StreamPart
1063
1145
  >({
1064
1146
  start(controller) {
1065
1147
  controller.enqueue({ type: 'stream-start', warnings });
@@ -1188,6 +1270,28 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1188
1270
  input: '{}',
1189
1271
  providerExecuted: true,
1190
1272
  });
1273
+ } else if (value.item.type === 'tool_search_call') {
1274
+ const toolCallId = value.item.id;
1275
+ const toolName =
1276
+ toolNameMapping.toCustomToolName('tool_search');
1277
+ const isHosted = value.item.execution === 'server';
1278
+
1279
+ ongoingToolCalls[value.output_index] = {
1280
+ toolName,
1281
+ toolCallId,
1282
+ toolSearchExecution: value.item.execution ?? 'server',
1283
+ };
1284
+
1285
+ if (isHosted) {
1286
+ controller.enqueue({
1287
+ type: 'tool-input-start',
1288
+ id: toolCallId,
1289
+ toolName,
1290
+ providerExecuted: true,
1291
+ });
1292
+ }
1293
+ } else if (value.item.type === 'tool_search_output') {
1294
+ // handled on output_item.done so we can pair it with the call
1191
1295
  } else if (
1192
1296
  value.item.type === 'mcp_call' ||
1193
1297
  value.item.type === 'mcp_list_tools' ||
@@ -1418,6 +1522,67 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1418
1522
  result: value.item.result,
1419
1523
  } satisfies InferSchema<typeof imageGenerationOutputSchema>,
1420
1524
  });
1525
+ } else if (value.item.type === 'tool_search_call') {
1526
+ const toolCall = ongoingToolCalls[value.output_index];
1527
+ const isHosted = value.item.execution === 'server';
1528
+
1529
+ if (toolCall != null) {
1530
+ const toolCallId = isHosted
1531
+ ? toolCall.toolCallId
1532
+ : (value.item.call_id ?? value.item.id);
1533
+
1534
+ if (isHosted) {
1535
+ hostedToolSearchCallIds.push(toolCallId);
1536
+ } else {
1537
+ controller.enqueue({
1538
+ type: 'tool-input-start',
1539
+ id: toolCallId,
1540
+ toolName: toolCall.toolName,
1541
+ });
1542
+ }
1543
+
1544
+ controller.enqueue({
1545
+ type: 'tool-input-end',
1546
+ id: toolCallId,
1547
+ });
1548
+
1549
+ controller.enqueue({
1550
+ type: 'tool-call',
1551
+ toolCallId,
1552
+ toolName: toolCall.toolName,
1553
+ input: JSON.stringify({
1554
+ arguments: value.item.arguments,
1555
+ call_id: isHosted ? null : toolCallId,
1556
+ } satisfies InferSchema<typeof toolSearchInputSchema>),
1557
+ ...(isHosted ? { providerExecuted: true } : {}),
1558
+ providerMetadata: {
1559
+ [providerOptionsName]: {
1560
+ itemId: value.item.id,
1561
+ },
1562
+ },
1563
+ });
1564
+ }
1565
+
1566
+ ongoingToolCalls[value.output_index] = undefined;
1567
+ } else if (value.item.type === 'tool_search_output') {
1568
+ const toolCallId =
1569
+ value.item.call_id ??
1570
+ hostedToolSearchCallIds.shift() ??
1571
+ value.item.id;
1572
+
1573
+ controller.enqueue({
1574
+ type: 'tool-result',
1575
+ toolCallId,
1576
+ toolName: toolNameMapping.toCustomToolName('tool_search'),
1577
+ result: {
1578
+ tools: value.item.tools,
1579
+ } satisfies InferSchema<typeof toolSearchOutputSchema>,
1580
+ providerMetadata: {
1581
+ [providerOptionsName]: {
1582
+ itemId: value.item.id,
1583
+ },
1584
+ },
1585
+ });
1421
1586
  } else if (value.item.type === 'mcp_call') {
1422
1587
  ongoingToolCalls[value.output_index] = undefined;
1423
1588
 
@@ -1647,6 +1812,18 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1647
1812
  }
1648
1813
 
1649
1814
  delete activeReasoning[value.item.id];
1815
+ } else if (value.item.type === 'compaction') {
1816
+ controller.enqueue({
1817
+ type: 'custom',
1818
+ kind: 'openai.compaction',
1819
+ providerMetadata: {
1820
+ [providerOptionsName]: {
1821
+ type: 'compaction',
1822
+ itemId: value.item.id,
1823
+ encryptedContent: value.item.encrypted_content,
1824
+ } satisfies ResponsesCompactionProviderMetadata,
1825
+ },
1826
+ });
1650
1827
  }
1651
1828
  } else if (isResponseFunctionCallArgumentsDeltaChunk(value)) {
1652
1829
  const toolCall = ongoingToolCalls[value.output_index];
@@ -1867,6 +2044,19 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1867
2044
  if (typeof value.response.service_tier === 'string') {
1868
2045
  serviceTier = value.response.service_tier;
1869
2046
  }
2047
+ } else if (isResponseFailedChunk(value)) {
2048
+ const incompleteReason =
2049
+ value.response.incomplete_details?.reason;
2050
+ finishReason = {
2051
+ unified: incompleteReason
2052
+ ? mapOpenAIResponseFinishReason({
2053
+ finishReason: incompleteReason,
2054
+ hasFunctionCall,
2055
+ })
2056
+ : 'error',
2057
+ raw: incompleteReason ?? 'error',
2058
+ };
2059
+ usage = value.response.usage ?? undefined;
1870
2060
  } else if (isResponseAnnotationAddedChunk(value)) {
1871
2061
  ongoingAnnotations.push(value.annotation);
1872
2062
  if (value.annotation.type === 'url_citation') {
@@ -1941,7 +2131,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1941
2131
  },
1942
2132
 
1943
2133
  flush(controller) {
1944
- const providerMetadata: SharedV3ProviderMetadata = {
2134
+ const providerMetadata: SharedV4ProviderMetadata = {
1945
2135
  [providerOptionsName]: {
1946
2136
  responseId: responseId,
1947
2137
  ...(logprobs.length > 0 ? { logprobs } : {}),
@@ -1986,6 +2176,12 @@ function isResponseFinishedChunk(
1986
2176
  );
1987
2177
  }
1988
2178
 
2179
+ function isResponseFailedChunk(
2180
+ chunk: OpenAIResponsesChunk,
2181
+ ): chunk is OpenAIResponsesChunk & { type: 'response.failed' } {
2182
+ return chunk.type === 'response.failed';
2183
+ }
2184
+
1989
2185
  function isResponseCreatedChunk(
1990
2186
  chunk: OpenAIResponsesChunk,
1991
2187
  ): chunk is OpenAIResponsesChunk & { type: 'response.created' } {
@@ -37,11 +37,16 @@ export const openaiResponsesReasoningModelIds = [
37
37
  'gpt-5.2-chat-latest',
38
38
  'gpt-5.2-pro',
39
39
  'gpt-5.2-codex',
40
+ 'gpt-5.3-chat-latest',
41
+ 'gpt-5.3-codex',
40
42
  'gpt-5.4',
41
43
  'gpt-5.4-2026-03-05',
44
+ 'gpt-5.4-mini',
45
+ 'gpt-5.4-mini-2026-03-17',
46
+ 'gpt-5.4-nano',
47
+ 'gpt-5.4-nano-2026-03-17',
42
48
  'gpt-5.4-pro',
43
49
  'gpt-5.4-pro-2026-03-05',
44
- 'gpt-5.3-codex',
45
50
  ] as const;
46
51
 
47
52
  export const openaiResponsesModelIds = [
@@ -98,11 +103,16 @@ export type OpenAIResponsesModelId =
98
103
  | 'gpt-5.2-pro'
99
104
  | 'gpt-5.2-pro-2025-12-11'
100
105
  | 'gpt-5.2-codex'
106
+ | 'gpt-5.3-chat-latest'
107
+ | 'gpt-5.3-codex'
101
108
  | 'gpt-5.4'
102
109
  | 'gpt-5.4-2026-03-05'
110
+ | 'gpt-5.4-mini'
111
+ | 'gpt-5.4-mini-2026-03-17'
112
+ | 'gpt-5.4-nano'
113
+ | 'gpt-5.4-nano-2026-03-17'
103
114
  | 'gpt-5.4-pro'
104
115
  | 'gpt-5.4-pro-2026-03-05'
105
- | 'gpt-5.3-codex'
106
116
  | 'gpt-5-2025-08-07'
107
117
  | 'gpt-5-chat-latest'
108
118
  | 'gpt-5-codex'
@@ -298,6 +308,18 @@ export const openaiLanguageModelResponsesOptionsSchema = lazySchema(() =>
298
308
  * and defaults `systemMessageMode` to `developer` unless overridden.
299
309
  */
300
310
  forceReasoning: z.boolean().optional(),
311
+
312
+ /**
313
+ * Enable server-side context management (compaction).
314
+ */
315
+ contextManagement: z
316
+ .array(
317
+ z.object({
318
+ type: z.literal('compaction'),
319
+ compactThreshold: z.number(),
320
+ }),
321
+ )
322
+ .nullish(),
301
323
  }),
302
324
  ),
303
325
  );
@@ -1,6 +1,6 @@
1
1
  import {
2
- LanguageModelV3CallOptions,
3
- SharedV3Warning,
2
+ LanguageModelV4CallOptions,
3
+ SharedV4Warning,
4
4
  UnsupportedFunctionalityError,
5
5
  } from '@ai-sdk/provider';
6
6
  import { ToolNameMapping, validateTypes } from '@ai-sdk/provider-utils';
@@ -10,6 +10,7 @@ import { imageGenerationArgsSchema } from '../tool/image-generation';
10
10
  import { customArgsSchema } from '../tool/custom';
11
11
  import { mcpArgsSchema } from '../tool/mcp';
12
12
  import { shellArgsSchema } from '../tool/shell';
13
+ import { toolSearchArgsSchema } from '../tool/tool-search';
13
14
  import { webSearchArgsSchema } from '../tool/web-search';
14
15
  import { webSearchPreviewArgsSchema } from '../tool/web-search-preview';
15
16
  import { OpenAIResponsesTool } from './openai-responses-api';
@@ -20,8 +21,8 @@ export async function prepareResponsesTools({
20
21
  toolNameMapping,
21
22
  customProviderToolNames,
22
23
  }: {
23
- tools: LanguageModelV3CallOptions['tools'];
24
- toolChoice: LanguageModelV3CallOptions['toolChoice'] | undefined;
24
+ tools: LanguageModelV4CallOptions['tools'];
25
+ toolChoice: LanguageModelV4CallOptions['toolChoice'] | undefined;
25
26
  toolNameMapping?: ToolNameMapping;
26
27
  customProviderToolNames?: Set<string>;
27
28
  }): Promise<{
@@ -39,12 +40,12 @@ export async function prepareResponsesTools({
39
40
  | { type: 'mcp' }
40
41
  | { type: 'image_generation' }
41
42
  | { type: 'apply_patch' };
42
- toolWarnings: SharedV3Warning[];
43
+ toolWarnings: SharedV4Warning[];
43
44
  }> {
44
45
  // when the tools array is empty, change it to undefined to prevent errors:
45
46
  tools = tools?.length ? tools : undefined;
46
47
 
47
- const toolWarnings: SharedV3Warning[] = [];
48
+ const toolWarnings: SharedV4Warning[] = [];
48
49
 
49
50
  if (tools == null) {
50
51
  return { tools: undefined, toolChoice: undefined, toolWarnings };
@@ -56,15 +57,22 @@ export async function prepareResponsesTools({
56
57
 
57
58
  for (const tool of tools) {
58
59
  switch (tool.type) {
59
- case 'function':
60
+ case 'function': {
61
+ const openaiOptions = tool.providerOptions?.openai as
62
+ | { deferLoading?: boolean }
63
+ | undefined;
64
+ const deferLoading = openaiOptions?.deferLoading;
65
+
60
66
  openaiTools.push({
61
67
  type: 'function',
62
68
  name: tool.name,
63
69
  description: tool.description,
64
70
  parameters: tool.inputSchema,
65
71
  ...(tool.strict != null ? { strict: tool.strict } : {}),
72
+ ...(deferLoading != null ? { defer_loading: deferLoading } : {}),
66
73
  });
67
74
  break;
75
+ }
68
76
  case 'provider': {
69
77
  switch (tool.id) {
70
78
  case 'openai.file_search': {
@@ -241,11 +249,28 @@ export async function prepareResponsesTools({
241
249
 
242
250
  openaiTools.push({
243
251
  type: 'custom',
244
- name: args.name,
252
+ name: tool.name,
245
253
  description: args.description,
246
254
  format: args.format,
247
255
  });
248
- resolvedCustomProviderToolNames.add(args.name);
256
+ resolvedCustomProviderToolNames.add(tool.name);
257
+ break;
258
+ }
259
+ case 'openai.tool_search': {
260
+ const args = await validateTypes({
261
+ value: tool.args,
262
+ schema: toolSearchArgsSchema,
263
+ });
264
+ openaiTools.push({
265
+ type: 'tool_search',
266
+ ...(args.execution != null ? { execution: args.execution } : {}),
267
+ ...(args.description != null
268
+ ? { description: args.description }
269
+ : {}),
270
+ ...(args.parameters != null
271
+ ? { parameters: args.parameters }
272
+ : {}),
273
+ });
249
274
  break;
250
275
  }
251
276
  }
@@ -30,6 +30,16 @@ export type OpenaiResponsesProviderMetadata = {
30
30
  openai: ResponsesProviderMetadata;
31
31
  };
32
32
 
33
+ export type ResponsesCompactionProviderMetadata = {
34
+ type: 'compaction';
35
+ itemId: string;
36
+ encryptedContent?: string;
37
+ };
38
+
39
+ export type OpenaiResponsesCompactionProviderMetadata = {
40
+ openai: ResponsesCompactionProviderMetadata;
41
+ };
42
+
33
43
  export type ResponsesTextProviderMetadata = {
34
44
  itemId: string;
35
45
  phase?: 'commentary' | 'final_answer' | null;
@@ -1,4 +1,4 @@
1
- import { SpeechModelV3, SharedV3Warning } from '@ai-sdk/provider';
1
+ import { SpeechModelV4, SharedV4Warning } from '@ai-sdk/provider';
2
2
  import {
3
3
  combineHeaders,
4
4
  createBinaryResponseHandler,
@@ -19,8 +19,8 @@ interface OpenAISpeechModelConfig extends OpenAIConfig {
19
19
  };
20
20
  }
21
21
 
22
- export class OpenAISpeechModel implements SpeechModelV3 {
23
- readonly specificationVersion = 'v3';
22
+ export class OpenAISpeechModel implements SpeechModelV4 {
23
+ readonly specificationVersion = 'v4';
24
24
 
25
25
  get provider(): string {
26
26
  return this.config.provider;
@@ -39,8 +39,8 @@ export class OpenAISpeechModel implements SpeechModelV3 {
39
39
  instructions,
40
40
  language,
41
41
  providerOptions,
42
- }: Parameters<SpeechModelV3['doGenerate']>[0]) {
43
- const warnings: SharedV3Warning[] = [];
42
+ }: Parameters<SpeechModelV4['doGenerate']>[0]) {
43
+ const warnings: SharedV4Warning[] = [];
44
44
 
45
45
  // Parse provider options
46
46
  const openAIOptions = await parseProviderOptions({
@@ -98,8 +98,8 @@ export class OpenAISpeechModel implements SpeechModelV3 {
98
98
  }
99
99
 
100
100
  async doGenerate(
101
- options: Parameters<SpeechModelV3['doGenerate']>[0],
102
- ): Promise<Awaited<ReturnType<SpeechModelV3['doGenerate']>>> {
101
+ options: Parameters<SpeechModelV4['doGenerate']>[0],
102
+ ): Promise<Awaited<ReturnType<SpeechModelV4['doGenerate']>>> {
103
103
  const currentDate = this.config._internal?.currentDate?.() ?? new Date();
104
104
  const { requestBody, warnings } = await this.getArgs(options);
105
105