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

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 (44) hide show
  1. package/CHANGELOG.md +225 -22
  2. package/README.md +2 -0
  3. package/dist/index.d.mts +124 -35
  4. package/dist/index.d.ts +124 -35
  5. package/dist/index.js +1319 -895
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +1275 -844
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/internal/index.d.mts +102 -36
  10. package/dist/internal/index.d.ts +102 -36
  11. package/dist/internal/index.js +1348 -934
  12. package/dist/internal/index.js.map +1 -1
  13. package/dist/internal/index.mjs +1332 -911
  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 +5 -5
  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/image/openai-image-model.ts +9 -9
  29. package/src/index.ts +1 -0
  30. package/src/openai-language-model-capabilities.ts +3 -2
  31. package/src/openai-provider.ts +21 -21
  32. package/src/openai-tools.ts +12 -1
  33. package/src/responses/convert-openai-responses-usage.ts +2 -2
  34. package/src/responses/convert-to-openai-responses-input.ts +159 -12
  35. package/src/responses/map-openai-responses-finish-reason.ts +2 -2
  36. package/src/responses/openai-responses-api.ts +136 -2
  37. package/src/responses/openai-responses-language-model.ts +233 -37
  38. package/src/responses/openai-responses-options.ts +24 -2
  39. package/src/responses/openai-responses-prepare-tools.ts +34 -9
  40. package/src/responses/openai-responses-provider-metadata.ts +10 -0
  41. package/src/speech/openai-speech-model.ts +7 -7
  42. package/src/tool/custom.ts +0 -6
  43. package/src/tool/tool-search.ts +98 -0
  44. package/src/transcription/openai-transcription-model.ts +8 -8
@@ -1,8 +1,8 @@
1
- import { LanguageModelV3FinishReason } from '@ai-sdk/provider';
1
+ import { LanguageModelV4FinishReason } from '@ai-sdk/provider';
2
2
 
3
3
  export function mapOpenAIFinishReason(
4
4
  finishReason: string | null | undefined,
5
- ): LanguageModelV3FinishReason['unified'] {
5
+ ): LanguageModelV4FinishReason['unified'] {
6
6
  switch (finishReason) {
7
7
  case 'stop':
8
8
  return 'stop';
@@ -1,12 +1,12 @@
1
1
  import {
2
- LanguageModelV3,
3
- LanguageModelV3CallOptions,
4
- LanguageModelV3FinishReason,
5
- LanguageModelV3GenerateResult,
6
- LanguageModelV3StreamPart,
7
- LanguageModelV3StreamResult,
8
- SharedV3ProviderMetadata,
9
- SharedV3Warning,
2
+ LanguageModelV4,
3
+ LanguageModelV4CallOptions,
4
+ LanguageModelV4FinishReason,
5
+ LanguageModelV4GenerateResult,
6
+ LanguageModelV4StreamPart,
7
+ LanguageModelV4StreamResult,
8
+ SharedV4ProviderMetadata,
9
+ SharedV4Warning,
10
10
  } from '@ai-sdk/provider';
11
11
  import {
12
12
  combineHeaders,
@@ -42,8 +42,8 @@ type OpenAICompletionConfig = {
42
42
  fetch?: FetchFunction;
43
43
  };
44
44
 
45
- export class OpenAICompletionLanguageModel implements LanguageModelV3 {
46
- readonly specificationVersion = 'v3';
45
+ export class OpenAICompletionLanguageModel implements LanguageModelV4 {
46
+ readonly specificationVersion = 'v4';
47
47
 
48
48
  readonly modelId: OpenAICompletionModelId;
49
49
 
@@ -83,8 +83,8 @@ export class OpenAICompletionLanguageModel implements LanguageModelV3 {
83
83
  toolChoice,
84
84
  seed,
85
85
  providerOptions,
86
- }: LanguageModelV3CallOptions) {
87
- const warnings: SharedV3Warning[] = [];
86
+ }: LanguageModelV4CallOptions) {
87
+ const warnings: SharedV4Warning[] = [];
88
88
 
89
89
  // Parse provider options
90
90
  const openaiOptions = {
@@ -161,8 +161,8 @@ export class OpenAICompletionLanguageModel implements LanguageModelV3 {
161
161
  }
162
162
 
163
163
  async doGenerate(
164
- options: LanguageModelV3CallOptions,
165
- ): Promise<LanguageModelV3GenerateResult> {
164
+ options: LanguageModelV4CallOptions,
165
+ ): Promise<LanguageModelV4GenerateResult> {
166
166
  const { args, warnings } = await this.getArgs(options);
167
167
 
168
168
  const {
@@ -186,7 +186,7 @@ export class OpenAICompletionLanguageModel implements LanguageModelV3 {
186
186
 
187
187
  const choice = response.choices[0];
188
188
 
189
- const providerMetadata: SharedV3ProviderMetadata = { openai: {} };
189
+ const providerMetadata: SharedV4ProviderMetadata = { openai: {} };
190
190
 
191
191
  if (choice.logprobs != null) {
192
192
  providerMetadata.openai.logprobs = choice.logprobs;
@@ -211,8 +211,8 @@ export class OpenAICompletionLanguageModel implements LanguageModelV3 {
211
211
  }
212
212
 
213
213
  async doStream(
214
- options: LanguageModelV3CallOptions,
215
- ): Promise<LanguageModelV3StreamResult> {
214
+ options: LanguageModelV4CallOptions,
215
+ ): Promise<LanguageModelV4StreamResult> {
216
216
  const { args, warnings } = await this.getArgs(options);
217
217
 
218
218
  const body = {
@@ -239,11 +239,11 @@ export class OpenAICompletionLanguageModel implements LanguageModelV3 {
239
239
  fetch: this.config.fetch,
240
240
  });
241
241
 
242
- let finishReason: LanguageModelV3FinishReason = {
242
+ let finishReason: LanguageModelV4FinishReason = {
243
243
  unified: 'other',
244
244
  raw: undefined,
245
245
  };
246
- const providerMetadata: SharedV3ProviderMetadata = { openai: {} };
246
+ const providerMetadata: SharedV4ProviderMetadata = { openai: {} };
247
247
  let usage: OpenAICompletionUsage | undefined = undefined;
248
248
  let isFirstChunk = true;
249
249
 
@@ -251,7 +251,7 @@ export class OpenAICompletionLanguageModel implements LanguageModelV3 {
251
251
  stream: response.pipeThrough(
252
252
  new TransformStream<
253
253
  ParseResult<OpenAICompletionChunk>,
254
- LanguageModelV3StreamPart
254
+ LanguageModelV4StreamPart
255
255
  >({
256
256
  start(controller) {
257
257
  controller.enqueue({ type: 'stream-start', warnings });
@@ -1,5 +1,5 @@
1
1
  import {
2
- EmbeddingModelV3,
2
+ EmbeddingModelV4,
3
3
  TooManyEmbeddingValuesForCallError,
4
4
  } from '@ai-sdk/provider';
5
5
  import {
@@ -16,8 +16,8 @@ import {
16
16
  } from './openai-embedding-options';
17
17
  import { openaiTextEmbeddingResponseSchema } from './openai-embedding-api';
18
18
 
19
- export class OpenAIEmbeddingModel implements EmbeddingModelV3 {
20
- readonly specificationVersion = 'v3';
19
+ export class OpenAIEmbeddingModel implements EmbeddingModelV4 {
20
+ readonly specificationVersion = 'v4';
21
21
  readonly modelId: OpenAIEmbeddingModelId;
22
22
  readonly maxEmbeddingsPerCall = 2048;
23
23
  readonly supportsParallelCalls = true;
@@ -38,8 +38,8 @@ export class OpenAIEmbeddingModel implements EmbeddingModelV3 {
38
38
  headers,
39
39
  abortSignal,
40
40
  providerOptions,
41
- }: Parameters<EmbeddingModelV3['doEmbed']>[0]): Promise<
42
- Awaited<ReturnType<EmbeddingModelV3['doEmbed']>>
41
+ }: Parameters<EmbeddingModelV4['doEmbed']>[0]): Promise<
42
+ Awaited<ReturnType<EmbeddingModelV4['doEmbed']>>
43
43
  > {
44
44
  if (values.length > this.maxEmbeddingsPerCall) {
45
45
  throw new TooManyEmbeddingValuesForCallError({
@@ -1,7 +1,7 @@
1
1
  import {
2
- ImageModelV3,
3
- ImageModelV3File,
4
- SharedV3Warning,
2
+ ImageModelV4,
3
+ ImageModelV4File,
4
+ SharedV4Warning,
5
5
  } from '@ai-sdk/provider';
6
6
  import {
7
7
  combineHeaders,
@@ -27,8 +27,8 @@ interface OpenAIImageModelConfig extends OpenAIConfig {
27
27
  };
28
28
  }
29
29
 
30
- export class OpenAIImageModel implements ImageModelV3 {
31
- readonly specificationVersion = 'v3';
30
+ export class OpenAIImageModel implements ImageModelV4 {
31
+ readonly specificationVersion = 'v4';
32
32
 
33
33
  get maxImagesPerCall(): number {
34
34
  return modelMaxImagesPerCall[this.modelId] ?? 1;
@@ -54,10 +54,10 @@ export class OpenAIImageModel implements ImageModelV3 {
54
54
  providerOptions,
55
55
  headers,
56
56
  abortSignal,
57
- }: Parameters<ImageModelV3['doGenerate']>[0]): Promise<
58
- Awaited<ReturnType<ImageModelV3['doGenerate']>>
57
+ }: Parameters<ImageModelV4['doGenerate']>[0]): Promise<
58
+ Awaited<ReturnType<ImageModelV4['doGenerate']>>
59
59
  > {
60
- const warnings: Array<SharedV3Warning> = [];
60
+ const warnings: Array<SharedV4Warning> = [];
61
61
 
62
62
  if (aspectRatio != null) {
63
63
  warnings.push({
@@ -332,7 +332,7 @@ type OpenAIImageEditInput = {
332
332
  };
333
333
 
334
334
  async function fileToBlob(
335
- file: ImageModelV3File | undefined,
335
+ file: ImageModelV4File | undefined,
336
336
  ): Promise<Blob | undefined> {
337
337
  if (!file) return undefined;
338
338
 
package/src/index.ts CHANGED
@@ -15,6 +15,7 @@ export type { OpenAIEmbeddingModelOptions } from './embedding/openai-embedding-o
15
15
  export type { OpenAISpeechModelOptions } from './speech/openai-speech-options';
16
16
  export type { OpenAITranscriptionModelOptions } from './transcription/openai-transcription-options';
17
17
  export type {
18
+ OpenaiResponsesCompactionProviderMetadata,
18
19
  OpenaiResponsesProviderMetadata,
19
20
  OpenaiResponsesReasoningProviderMetadata,
20
21
  OpenaiResponsesTextProviderMetadata,
@@ -20,10 +20,10 @@ export function getOpenAILanguageModelCapabilities(
20
20
 
21
21
  const supportsPriorityProcessing =
22
22
  modelId.startsWith('gpt-4') ||
23
- modelId.startsWith('gpt-5-mini') ||
24
23
  (modelId.startsWith('gpt-5') &&
25
24
  !modelId.startsWith('gpt-5-nano') &&
26
- !modelId.startsWith('gpt-5-chat')) ||
25
+ !modelId.startsWith('gpt-5-chat') &&
26
+ !modelId.startsWith('gpt-5.4-nano')) ||
27
27
  modelId.startsWith('o3') ||
28
28
  modelId.startsWith('o4-mini');
29
29
 
@@ -40,6 +40,7 @@ export function getOpenAILanguageModelCapabilities(
40
40
  const supportsNonReasoningParameters =
41
41
  modelId.startsWith('gpt-5.1') ||
42
42
  modelId.startsWith('gpt-5.2') ||
43
+ modelId.startsWith('gpt-5.3') ||
43
44
  modelId.startsWith('gpt-5.4');
44
45
 
45
46
  const systemMessageMode = isReasoningModel ? 'developer' : 'system';
@@ -1,10 +1,10 @@
1
1
  import {
2
- EmbeddingModelV3,
3
- ImageModelV3,
4
- LanguageModelV3,
5
- ProviderV3,
6
- SpeechModelV3,
7
- TranscriptionModelV3,
2
+ EmbeddingModelV4,
3
+ ImageModelV4,
4
+ LanguageModelV4,
5
+ ProviderV4,
6
+ SpeechModelV4,
7
+ TranscriptionModelV4,
8
8
  } from '@ai-sdk/provider';
9
9
  import {
10
10
  FetchFunction,
@@ -30,68 +30,68 @@ import { OpenAITranscriptionModel } from './transcription/openai-transcription-m
30
30
  import { OpenAITranscriptionModelId } from './transcription/openai-transcription-options';
31
31
  import { VERSION } from './version';
32
32
 
33
- export interface OpenAIProvider extends ProviderV3 {
34
- (modelId: OpenAIResponsesModelId): LanguageModelV3;
33
+ export interface OpenAIProvider extends ProviderV4 {
34
+ (modelId: OpenAIResponsesModelId): LanguageModelV4;
35
35
 
36
36
  /**
37
37
  * Creates an OpenAI model for text generation.
38
38
  */
39
- languageModel(modelId: OpenAIResponsesModelId): LanguageModelV3;
39
+ languageModel(modelId: OpenAIResponsesModelId): LanguageModelV4;
40
40
 
41
41
  /**
42
42
  * Creates an OpenAI chat model for text generation.
43
43
  */
44
- chat(modelId: OpenAIChatModelId): LanguageModelV3;
44
+ chat(modelId: OpenAIChatModelId): LanguageModelV4;
45
45
 
46
46
  /**
47
47
  * Creates an OpenAI responses API model for text generation.
48
48
  */
49
- responses(modelId: OpenAIResponsesModelId): LanguageModelV3;
49
+ responses(modelId: OpenAIResponsesModelId): LanguageModelV4;
50
50
 
51
51
  /**
52
52
  * Creates an OpenAI completion model for text generation.
53
53
  */
54
- completion(modelId: OpenAICompletionModelId): LanguageModelV3;
54
+ completion(modelId: OpenAICompletionModelId): LanguageModelV4;
55
55
 
56
56
  /**
57
57
  * Creates a model for text embeddings.
58
58
  */
59
- embedding(modelId: OpenAIEmbeddingModelId): EmbeddingModelV3;
59
+ embedding(modelId: OpenAIEmbeddingModelId): EmbeddingModelV4;
60
60
 
61
61
  /**
62
62
  * Creates a model for text embeddings.
63
63
  */
64
- embeddingModel(modelId: OpenAIEmbeddingModelId): EmbeddingModelV3;
64
+ embeddingModel(modelId: OpenAIEmbeddingModelId): EmbeddingModelV4;
65
65
 
66
66
  /**
67
67
  * @deprecated Use `embedding` instead.
68
68
  */
69
- textEmbedding(modelId: OpenAIEmbeddingModelId): EmbeddingModelV3;
69
+ textEmbedding(modelId: OpenAIEmbeddingModelId): EmbeddingModelV4;
70
70
 
71
71
  /**
72
72
  * @deprecated Use `embeddingModel` instead.
73
73
  */
74
- textEmbeddingModel(modelId: OpenAIEmbeddingModelId): EmbeddingModelV3;
74
+ textEmbeddingModel(modelId: OpenAIEmbeddingModelId): EmbeddingModelV4;
75
75
 
76
76
  /**
77
77
  * Creates a model for image generation.
78
78
  */
79
- image(modelId: OpenAIImageModelId): ImageModelV3;
79
+ image(modelId: OpenAIImageModelId): ImageModelV4;
80
80
 
81
81
  /**
82
82
  * Creates a model for image generation.
83
83
  */
84
- imageModel(modelId: OpenAIImageModelId): ImageModelV3;
84
+ imageModel(modelId: OpenAIImageModelId): ImageModelV4;
85
85
 
86
86
  /**
87
87
  * Creates a model for transcription.
88
88
  */
89
- transcription(modelId: OpenAITranscriptionModelId): TranscriptionModelV3;
89
+ transcription(modelId: OpenAITranscriptionModelId): TranscriptionModelV4;
90
90
 
91
91
  /**
92
92
  * Creates a model for speech generation.
93
93
  */
94
- speech(modelId: OpenAISpeechModelId): SpeechModelV3;
94
+ speech(modelId: OpenAISpeechModelId): SpeechModelV4;
95
95
 
96
96
  /**
97
97
  * OpenAI-specific tools.
@@ -240,7 +240,7 @@ export function createOpenAI(
240
240
  return createLanguageModel(modelId);
241
241
  };
242
242
 
243
- provider.specificationVersion = 'v3' as const;
243
+ provider.specificationVersion = 'v4' as const;
244
244
  provider.languageModel = createLanguageModel;
245
245
  provider.chat = createChatModel;
246
246
  provider.completion = createCompletionModel;
@@ -5,6 +5,7 @@ import { fileSearch } from './tool/file-search';
5
5
  import { imageGeneration } from './tool/image-generation';
6
6
  import { localShell } from './tool/local-shell';
7
7
  import { shell } from './tool/shell';
8
+ import { toolSearch } from './tool/tool-search';
8
9
  import { webSearch } from './tool/web-search';
9
10
  import { webSearchPreview } from './tool/web-search-preview';
10
11
  import { mcp } from './tool/mcp';
@@ -24,7 +25,6 @@ export const openaiTools = {
24
25
  * Lark syntax). The model returns a `custom_tool_call` output item whose
25
26
  * `input` field is a string matching the specified grammar.
26
27
  *
27
- * @param name - The name of the custom tool.
28
28
  * @param description - An optional description of the tool.
29
29
  * @param format - The output format constraint (grammar type, syntax, and definition).
30
30
  */
@@ -123,4 +123,15 @@ export const openaiTools = {
123
123
  * @param serverUrl - URL for the MCP server.
124
124
  */
125
125
  mcp,
126
+
127
+ /**
128
+ * Tool search allows the model to dynamically search for and load deferred
129
+ * tools into the model's context as needed. This helps reduce overall token
130
+ * usage, cost, and latency by only loading tools when the model needs them.
131
+ *
132
+ * To use tool search, mark functions or namespaces with `defer_loading: true`
133
+ * in the tools array. The model will use tool search to load these tools
134
+ * when it determines they are needed.
135
+ */
136
+ toolSearch,
126
137
  };
@@ -1,4 +1,4 @@
1
- import { LanguageModelV3Usage } from '@ai-sdk/provider';
1
+ import { LanguageModelV4Usage } from '@ai-sdk/provider';
2
2
 
3
3
  export type OpenAIResponsesUsage = {
4
4
  input_tokens: number;
@@ -13,7 +13,7 @@ export type OpenAIResponsesUsage = {
13
13
 
14
14
  export function convertOpenAIResponsesUsage(
15
15
  usage: OpenAIResponsesUsage | undefined | null,
16
- ): LanguageModelV3Usage {
16
+ ): LanguageModelV4Usage {
17
17
  if (usage == null) {
18
18
  return {
19
19
  inputTokens: {
@@ -1,12 +1,13 @@
1
1
  import {
2
- LanguageModelV3Prompt,
3
- LanguageModelV3ToolApprovalResponsePart,
4
- SharedV3Warning,
2
+ LanguageModelV4Prompt,
3
+ LanguageModelV4ToolApprovalResponsePart,
4
+ SharedV4Warning,
5
5
  UnsupportedFunctionalityError,
6
6
  } from '@ai-sdk/provider';
7
7
  import {
8
8
  convertToBase64,
9
9
  isNonNullable,
10
+ parseJSON,
10
11
  parseProviderOptions,
11
12
  ToolNameMapping,
12
13
  validateTypes,
@@ -22,11 +23,16 @@ import {
22
23
  } from '../tool/local-shell';
23
24
  import { shellInputSchema, shellOutputSchema } from '../tool/shell';
24
25
  import {
26
+ OpenAIResponsesCompactionItem,
25
27
  OpenAIResponsesCustomToolCallOutput,
26
28
  OpenAIResponsesFunctionCallOutput,
27
29
  OpenAIResponsesInput,
28
30
  OpenAIResponsesReasoning,
29
31
  } from './openai-responses-api';
32
+ import {
33
+ toolSearchInputSchema,
34
+ toolSearchOutputSchema,
35
+ } from '../tool/tool-search';
30
36
 
31
37
  /**
32
38
  * Check if a string is a file ID based on the given prefixes
@@ -50,7 +56,7 @@ export async function convertToOpenAIResponsesInput({
50
56
  hasApplyPatchTool = false,
51
57
  customProviderToolNames,
52
58
  }: {
53
- prompt: LanguageModelV3Prompt;
59
+ prompt: LanguageModelV4Prompt;
54
60
  toolNameMapping: ToolNameMapping;
55
61
  systemMessageMode: 'system' | 'developer' | 'remove';
56
62
  providerOptionsName: string;
@@ -63,10 +69,10 @@ export async function convertToOpenAIResponsesInput({
63
69
  customProviderToolNames?: Set<string>;
64
70
  }): Promise<{
65
71
  input: OpenAIResponsesInput;
66
- warnings: Array<SharedV3Warning>;
72
+ warnings: Array<SharedV4Warning>;
67
73
  }> {
68
- const input: OpenAIResponsesInput = [];
69
- const warnings: Array<SharedV3Warning> = [];
74
+ let input: OpenAIResponsesInput = [];
75
+ const warnings: Array<SharedV4Warning> = [];
70
76
  const processedApprovalIds = new Set<string>();
71
77
 
72
78
  for (const { role, content } of prompt) {
@@ -206,6 +212,41 @@ export async function convertToOpenAIResponsesInput({
206
212
  break;
207
213
  }
208
214
 
215
+ const resolvedToolName = toolNameMapping.toProviderToolName(
216
+ part.toolName,
217
+ );
218
+
219
+ if (resolvedToolName === 'tool_search') {
220
+ if (store && id != null) {
221
+ input.push({ type: 'item_reference', id });
222
+ break;
223
+ }
224
+
225
+ const parsedInput =
226
+ typeof part.input === 'string'
227
+ ? await parseJSON({
228
+ text: part.input,
229
+ schema: toolSearchInputSchema,
230
+ })
231
+ : await validateTypes({
232
+ value: part.input,
233
+ schema: toolSearchInputSchema,
234
+ });
235
+
236
+ const execution =
237
+ parsedInput.call_id != null ? 'client' : 'server';
238
+
239
+ input.push({
240
+ type: 'tool_search_call',
241
+ id: id ?? part.toolCallId,
242
+ execution,
243
+ call_id: parsedInput.call_id ?? null,
244
+ status: 'completed',
245
+ arguments: parsedInput.arguments,
246
+ });
247
+ break;
248
+ }
249
+
209
250
  if (part.providerExecuted) {
210
251
  if (store && id != null) {
211
252
  input.push({ type: 'item_reference', id });
@@ -218,10 +259,6 @@ export async function convertToOpenAIResponsesInput({
218
259
  break;
219
260
  }
220
261
 
221
- const resolvedToolName = toolNameMapping.toProviderToolName(
222
- part.toolName,
223
- );
224
-
225
262
  if (hasLocalShellTool && resolvedToolName === 'local_shell') {
226
263
  const parsedInput = await validateTypes({
227
264
  value: part.input,
@@ -328,6 +365,35 @@ export async function convertToOpenAIResponsesInput({
328
365
  part.toolName,
329
366
  );
330
367
 
368
+ if (resolvedResultToolName === 'tool_search') {
369
+ const itemId =
370
+ (
371
+ part.providerOptions?.[providerOptionsName] as
372
+ | { itemId?: string }
373
+ | undefined
374
+ )?.itemId ?? part.toolCallId;
375
+
376
+ if (store) {
377
+ input.push({ type: 'item_reference', id: itemId });
378
+ } else if (part.output.type === 'json') {
379
+ const parsedOutput = await validateTypes({
380
+ value: part.output.value,
381
+ schema: toolSearchOutputSchema,
382
+ });
383
+
384
+ input.push({
385
+ type: 'tool_search_output',
386
+ id: itemId,
387
+ execution: 'server',
388
+ call_id: null,
389
+ status: 'completed',
390
+ tools: parsedOutput.tools,
391
+ });
392
+ }
393
+
394
+ break;
395
+ }
396
+
331
397
  /*
332
398
  * Shell tool results are separate output items (shell_call_output)
333
399
  * with their own item IDs distinct from the shell_call's item ID.
@@ -478,6 +544,36 @@ export async function convertToOpenAIResponsesInput({
478
544
  }
479
545
  break;
480
546
  }
547
+
548
+ case 'custom': {
549
+ if (part.kind === 'openai.compaction') {
550
+ const providerOpts =
551
+ part.providerOptions?.[providerOptionsName];
552
+ const id = providerOpts?.itemId as string | undefined;
553
+
554
+ if (hasConversation && id != null) {
555
+ break;
556
+ }
557
+
558
+ if (store && id != null) {
559
+ input.push({ type: 'item_reference', id });
560
+ break;
561
+ }
562
+
563
+ const encryptedContent = providerOpts?.encryptedContent as
564
+ | string
565
+ | undefined;
566
+
567
+ if (id != null) {
568
+ input.push({
569
+ type: 'compaction',
570
+ id,
571
+ encrypted_content: encryptedContent!,
572
+ } satisfies OpenAIResponsesCompactionItem);
573
+ }
574
+ }
575
+ break;
576
+ }
481
577
  }
482
578
  }
483
579
 
@@ -488,7 +584,7 @@ export async function convertToOpenAIResponsesInput({
488
584
  for (const part of content) {
489
585
  if (part.type === 'tool-approval-response') {
490
586
  const approvalResponse =
491
- part as LanguageModelV3ToolApprovalResponsePart;
587
+ part as LanguageModelV4ToolApprovalResponsePart;
492
588
 
493
589
  if (processedApprovalIds.has(approvalResponse.approvalId)) {
494
590
  continue;
@@ -527,6 +623,22 @@ export async function convertToOpenAIResponsesInput({
527
623
  part.toolName,
528
624
  );
529
625
 
626
+ if (resolvedToolName === 'tool_search' && output.type === 'json') {
627
+ const parsedOutput = await validateTypes({
628
+ value: output.value,
629
+ schema: toolSearchOutputSchema,
630
+ });
631
+
632
+ input.push({
633
+ type: 'tool_search_output',
634
+ execution: 'client',
635
+ call_id: part.toolCallId,
636
+ status: 'completed',
637
+ tools: parsedOutput.tools,
638
+ });
639
+ continue;
640
+ }
641
+
530
642
  if (
531
643
  hasLocalShellTool &&
532
644
  resolvedToolName === 'local_shell' &&
@@ -628,6 +740,11 @@ export async function convertToOpenAIResponsesInput({
628
740
  filename: item.filename ?? 'data',
629
741
  file_data: `data:${item.mediaType};base64,${item.data}`,
630
742
  };
743
+ case 'file-url':
744
+ return {
745
+ type: 'input_file' as const,
746
+ file_url: item.url,
747
+ };
631
748
  default:
632
749
  warnings.push({
633
750
  type: 'other',
@@ -692,6 +809,13 @@ export async function convertToOpenAIResponsesInput({
692
809
  };
693
810
  }
694
811
 
812
+ case 'file-url': {
813
+ return {
814
+ type: 'input_file' as const,
815
+ file_url: item.url,
816
+ };
817
+ }
818
+
695
819
  default: {
696
820
  warnings.push({
697
821
  type: 'other',
@@ -722,6 +846,29 @@ export async function convertToOpenAIResponsesInput({
722
846
  }
723
847
  }
724
848
 
849
+ // when store is false, remove reasoning parts without encrypted content
850
+ if (
851
+ !store &&
852
+ input.some(
853
+ item =>
854
+ 'type' in item &&
855
+ item.type === 'reasoning' &&
856
+ item.encrypted_content == null,
857
+ )
858
+ ) {
859
+ warnings.push({
860
+ type: 'other',
861
+ message:
862
+ 'Reasoning parts without encrypted content are not supported when store is false. Skipping reasoning parts.',
863
+ });
864
+ input = input.filter(
865
+ item =>
866
+ !('type' in item) ||
867
+ item.type !== 'reasoning' ||
868
+ item.encrypted_content != null,
869
+ );
870
+ }
871
+
725
872
  return { input, warnings };
726
873
  }
727
874
 
@@ -1,4 +1,4 @@
1
- import { LanguageModelV3FinishReason } from '@ai-sdk/provider';
1
+ import { LanguageModelV4FinishReason } from '@ai-sdk/provider';
2
2
 
3
3
  export function mapOpenAIResponseFinishReason({
4
4
  finishReason,
@@ -7,7 +7,7 @@ export function mapOpenAIResponseFinishReason({
7
7
  finishReason: string | null | undefined;
8
8
  // flag that checks if there have been client-side tool calls (not executed by openai)
9
9
  hasFunctionCall: boolean;
10
- }): LanguageModelV3FinishReason['unified'] {
10
+ }): LanguageModelV4FinishReason['unified'] {
11
11
  switch (finishReason) {
12
12
  case undefined:
13
13
  case null: