@ai-sdk/openai 4.0.0-beta.6 → 4.0.0-beta.74

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 (73) hide show
  1. package/CHANGELOG.md +644 -24
  2. package/README.md +2 -0
  3. package/dist/index.d.ts +240 -44
  4. package/dist/index.js +3345 -1683
  5. package/dist/index.js.map +1 -1
  6. package/dist/internal/index.d.ts +390 -36
  7. package/dist/internal/index.js +2707 -1706
  8. package/dist/internal/index.js.map +1 -1
  9. package/docs/03-openai.mdx +413 -39
  10. package/package.json +17 -18
  11. package/src/chat/convert-openai-chat-usage.ts +1 -1
  12. package/src/chat/convert-to-openai-chat-messages.ts +96 -68
  13. package/src/chat/map-openai-finish-reason.ts +1 -1
  14. package/src/chat/openai-chat-api.ts +6 -2
  15. package/src/chat/{openai-chat-options.ts → openai-chat-language-model-options.ts} +11 -1
  16. package/src/chat/openai-chat-language-model.ts +82 -148
  17. package/src/chat/openai-chat-prepare-tools.ts +3 -3
  18. package/src/completion/convert-openai-completion-usage.ts +1 -1
  19. package/src/completion/convert-to-openai-completion-prompt.ts +1 -2
  20. package/src/completion/map-openai-finish-reason.ts +1 -1
  21. package/src/completion/openai-completion-api.ts +5 -2
  22. package/src/completion/{openai-completion-options.ts → openai-completion-language-model-options.ts} +5 -1
  23. package/src/completion/openai-completion-language-model.ts +53 -17
  24. package/src/embedding/{openai-embedding-options.ts → openai-embedding-model-options.ts} +5 -1
  25. package/src/embedding/openai-embedding-model.ts +22 -5
  26. package/src/files/openai-files-api.ts +17 -0
  27. package/src/files/openai-files-options.ts +22 -0
  28. package/src/files/openai-files.ts +100 -0
  29. package/src/image/openai-image-model-options.ts +123 -0
  30. package/src/image/openai-image-model.ts +62 -83
  31. package/src/index.ts +15 -6
  32. package/src/internal/index.ts +7 -6
  33. package/src/openai-config.ts +7 -7
  34. package/src/openai-language-model-capabilities.ts +5 -4
  35. package/src/openai-provider.ts +80 -9
  36. package/src/openai-stream-error.ts +181 -0
  37. package/src/openai-tools.ts +12 -1
  38. package/src/realtime/index.ts +2 -0
  39. package/src/realtime/openai-realtime-event-mapper.ts +436 -0
  40. package/src/realtime/openai-realtime-model-options.ts +3 -0
  41. package/src/realtime/openai-realtime-model.ts +111 -0
  42. package/src/responses/convert-openai-responses-usage.ts +1 -1
  43. package/src/responses/convert-to-openai-responses-input.ts +345 -90
  44. package/src/responses/map-openai-responses-finish-reason.ts +1 -1
  45. package/src/responses/openai-responses-api.ts +186 -17
  46. package/src/responses/{openai-responses-options.ts → openai-responses-language-model-options.ts} +55 -1
  47. package/src/responses/openai-responses-language-model.ts +330 -52
  48. package/src/responses/openai-responses-prepare-tools.ts +129 -18
  49. package/src/responses/openai-responses-provider-metadata.ts +12 -2
  50. package/src/skills/openai-skills-api.ts +31 -0
  51. package/src/skills/openai-skills.ts +83 -0
  52. package/src/speech/{openai-speech-options.ts → openai-speech-model-options.ts} +5 -1
  53. package/src/speech/openai-speech-model.ts +23 -7
  54. package/src/tool/apply-patch.ts +33 -32
  55. package/src/tool/code-interpreter.ts +40 -41
  56. package/src/tool/custom.ts +2 -8
  57. package/src/tool/file-search.ts +3 -3
  58. package/src/tool/image-generation.ts +2 -2
  59. package/src/tool/local-shell.ts +2 -2
  60. package/src/tool/mcp.ts +3 -3
  61. package/src/tool/shell.ts +9 -4
  62. package/src/tool/tool-search.ts +98 -0
  63. package/src/tool/web-search-preview.ts +2 -2
  64. package/src/tool/web-search.ts +10 -2
  65. package/src/transcription/{openai-transcription-options.ts → openai-transcription-model-options.ts} +5 -1
  66. package/src/transcription/openai-transcription-model.ts +35 -13
  67. package/dist/index.d.mts +0 -1107
  68. package/dist/index.mjs +0 -6509
  69. package/dist/index.mjs.map +0 -1
  70. package/dist/internal/index.d.mts +0 -1137
  71. package/dist/internal/index.mjs +0 -6322
  72. package/dist/internal/index.mjs.map +0 -1
  73. package/src/image/openai-image-options.ts +0 -31
@@ -1,15 +1,19 @@
1
1
  import {
2
- LanguageModelV4Prompt,
3
- LanguageModelV4ToolApprovalResponsePart,
4
- SharedV4Warning,
5
2
  UnsupportedFunctionalityError,
3
+ type LanguageModelV4Prompt,
4
+ type LanguageModelV4ToolApprovalResponsePart,
5
+ type SharedV4Warning,
6
6
  } from '@ai-sdk/provider';
7
7
  import {
8
8
  convertToBase64,
9
+ getTopLevelMediaType,
9
10
  isNonNullable,
11
+ parseJSON,
10
12
  parseProviderOptions,
11
- ToolNameMapping,
13
+ resolveFullMediaType,
14
+ resolveProviderReference,
12
15
  validateTypes,
16
+ type ToolNameMapping,
13
17
  } from '@ai-sdk/provider-utils';
14
18
  import { z } from 'zod/v4';
15
19
  import {
@@ -21,16 +25,27 @@ import {
21
25
  localShellOutputSchema,
22
26
  } from '../tool/local-shell';
23
27
  import { shellInputSchema, shellOutputSchema } from '../tool/shell';
24
- import {
28
+ import type {
29
+ OpenAIResponsesCompactionItem,
25
30
  OpenAIResponsesCustomToolCallOutput,
26
31
  OpenAIResponsesFunctionCallOutput,
27
32
  OpenAIResponsesInput,
28
33
  OpenAIResponsesReasoning,
29
34
  } from './openai-responses-api';
35
+ import {
36
+ toolSearchInputSchema,
37
+ toolSearchOutputSchema,
38
+ } from '../tool/tool-search';
39
+
40
+ function serializeToolCallArguments(input: unknown): string {
41
+ return JSON.stringify(input === undefined ? {} : input);
42
+ }
30
43
 
31
44
  /**
32
- * Check if a string is a file ID based on the given prefixes
33
- * Returns false if prefixes is undefined (disables file ID detection)
45
+ * This is soft-deprecated. Use provider references instead. Kept for backward compatibility
46
+ * with the `fileIdPrefixes` option.
47
+ *
48
+ * TODO: remove in v8
34
49
  */
35
50
  function isFileId(data: string, prefixes?: readonly string[]): boolean {
36
51
  if (!prefixes) return false;
@@ -43,8 +58,10 @@ export async function convertToOpenAIResponsesInput({
43
58
  systemMessageMode,
44
59
  providerOptionsName,
45
60
  fileIdPrefixes,
61
+ passThroughUnsupportedFiles = false,
46
62
  store,
47
63
  hasConversation = false,
64
+ hasPreviousResponseId = false,
48
65
  hasLocalShellTool = false,
49
66
  hasShellTool = false,
50
67
  hasApplyPatchTool = false,
@@ -54,9 +71,12 @@ export async function convertToOpenAIResponsesInput({
54
71
  toolNameMapping: ToolNameMapping;
55
72
  systemMessageMode: 'system' | 'developer' | 'remove';
56
73
  providerOptionsName: string;
74
+ /** @deprecated Use provider references instead. */
57
75
  fileIdPrefixes?: readonly string[];
76
+ passThroughUnsupportedFiles?: boolean;
58
77
  store: boolean;
59
78
  hasConversation?: boolean; // when true, skip assistant messages that already have item IDs
79
+ hasPreviousResponseId?: boolean; // when true, skip reasoning and function-call items that already exist in the previous response chain
60
80
  hasLocalShellTool?: boolean;
61
81
  hasShellTool?: boolean;
62
82
  hasApplyPatchTool?: boolean;
@@ -107,46 +127,86 @@ export async function convertToOpenAIResponsesInput({
107
127
  return { type: 'input_text', text: part.text };
108
128
  }
109
129
  case 'file': {
110
- if (part.mediaType.startsWith('image/')) {
111
- const mediaType =
112
- part.mediaType === 'image/*'
113
- ? 'image/jpeg'
114
- : part.mediaType;
115
-
116
- return {
117
- type: 'input_image',
118
- ...(part.data instanceof URL
119
- ? { image_url: part.data.toString() }
120
- : typeof part.data === 'string' &&
121
- isFileId(part.data, fileIdPrefixes)
122
- ? { file_id: part.data }
123
- : {
124
- image_url: `data:${mediaType};base64,${convertToBase64(part.data)}`,
125
- }),
126
- detail:
127
- part.providerOptions?.[providerOptionsName]?.imageDetail,
128
- };
129
- } else if (part.mediaType === 'application/pdf') {
130
- if (part.data instanceof URL) {
130
+ switch (part.data.type) {
131
+ case 'reference': {
132
+ const fileId = resolveProviderReference({
133
+ reference: part.data.reference,
134
+ provider: providerOptionsName,
135
+ });
136
+
137
+ if (getTopLevelMediaType(part.mediaType) === 'image') {
138
+ return {
139
+ type: 'input_image',
140
+ file_id: fileId,
141
+ detail:
142
+ part.providerOptions?.[providerOptionsName]
143
+ ?.imageDetail,
144
+ };
145
+ }
146
+
131
147
  return {
132
148
  type: 'input_file',
133
- file_url: part.data.toString(),
149
+ file_id: fileId,
134
150
  };
135
151
  }
136
- return {
137
- type: 'input_file',
138
- ...(typeof part.data === 'string' &&
139
- isFileId(part.data, fileIdPrefixes)
140
- ? { file_id: part.data }
141
- : {
142
- filename: part.filename ?? `part-${index}.pdf`,
143
- file_data: `data:application/pdf;base64,${convertToBase64(part.data)}`,
144
- }),
145
- };
146
- } else {
147
- throw new UnsupportedFunctionalityError({
148
- functionality: `file part media type ${part.mediaType}`,
149
- });
152
+ case 'text': {
153
+ throw new UnsupportedFunctionalityError({
154
+ functionality: 'text file parts',
155
+ });
156
+ }
157
+ case 'url':
158
+ case 'data': {
159
+ const topLevel = getTopLevelMediaType(part.mediaType);
160
+
161
+ if (topLevel === 'image') {
162
+ return {
163
+ type: 'input_image',
164
+ ...(part.data.type === 'url'
165
+ ? { image_url: part.data.url.toString() }
166
+ : typeof part.data.data === 'string' &&
167
+ isFileId(part.data.data, fileIdPrefixes)
168
+ ? { file_id: part.data.data }
169
+ : {
170
+ image_url: `data:${resolveFullMediaType({ part })};base64,${convertToBase64(part.data.data)}`,
171
+ }),
172
+ detail:
173
+ part.providerOptions?.[providerOptionsName]
174
+ ?.imageDetail,
175
+ };
176
+ } else {
177
+ if (part.data.type === 'url') {
178
+ return {
179
+ type: 'input_file',
180
+ file_url: part.data.url.toString(),
181
+ };
182
+ }
183
+
184
+ const fullMediaType = resolveFullMediaType({ part });
185
+ if (
186
+ fullMediaType !== 'application/pdf' &&
187
+ !passThroughUnsupportedFiles
188
+ ) {
189
+ throw new UnsupportedFunctionalityError({
190
+ functionality: `file part media type ${fullMediaType}`,
191
+ });
192
+ }
193
+
194
+ return {
195
+ type: 'input_file',
196
+ ...(typeof part.data.data === 'string' &&
197
+ isFileId(part.data.data, fileIdPrefixes)
198
+ ? { file_id: part.data.data }
199
+ : {
200
+ filename:
201
+ part.filename ??
202
+ (fullMediaType === 'application/pdf'
203
+ ? `part-${index}.pdf`
204
+ : `part-${index}`),
205
+ file_data: `data:${fullMediaType};base64,${convertToBase64(part.data.data)}`,
206
+ }),
207
+ };
208
+ }
209
+ }
150
210
  }
151
211
  }
152
212
  }
@@ -162,9 +222,10 @@ export async function convertToOpenAIResponsesInput({
162
222
  for (const part of content) {
163
223
  switch (part.type) {
164
224
  case 'text': {
165
- const providerOpts = part.providerOptions?.[providerOptionsName];
166
- const id = providerOpts?.itemId as string | undefined;
167
- const phase = providerOpts?.phase as
225
+ const providerOptions =
226
+ part.providerOptions?.[providerOptionsName];
227
+ const id = providerOptions?.itemId as string | undefined;
228
+ const phase = providerOptions?.phase as
168
229
  | 'commentary'
169
230
  | 'final_answer'
170
231
  | null
@@ -202,10 +263,57 @@ export async function convertToOpenAIResponsesInput({
202
263
  | string
203
264
  | undefined;
204
265
 
266
+ const namespace = (part.providerOptions?.[providerOptionsName]
267
+ ?.namespace ??
268
+ (
269
+ part as {
270
+ providerMetadata?: {
271
+ [providerOptionsName]?: { namespace?: string };
272
+ };
273
+ }
274
+ ).providerMetadata?.[providerOptionsName]?.namespace) as
275
+ | string
276
+ | undefined;
277
+
205
278
  if (hasConversation && id != null) {
206
279
  break;
207
280
  }
208
281
 
282
+ const resolvedToolName = toolNameMapping.toProviderToolName(
283
+ part.toolName,
284
+ );
285
+
286
+ if (resolvedToolName === 'tool_search') {
287
+ if (store && id != null) {
288
+ input.push({ type: 'item_reference', id });
289
+ break;
290
+ }
291
+
292
+ const parsedInput =
293
+ typeof part.input === 'string'
294
+ ? await parseJSON({
295
+ text: part.input,
296
+ schema: toolSearchInputSchema,
297
+ })
298
+ : await validateTypes({
299
+ value: part.input,
300
+ schema: toolSearchInputSchema,
301
+ });
302
+
303
+ const execution =
304
+ parsedInput.call_id != null ? 'client' : 'server';
305
+
306
+ input.push({
307
+ type: 'tool_search_call',
308
+ id: id ?? part.toolCallId,
309
+ execution,
310
+ call_id: parsedInput.call_id ?? null,
311
+ status: 'completed',
312
+ arguments: parsedInput.arguments,
313
+ });
314
+ break;
315
+ }
316
+
209
317
  if (part.providerExecuted) {
210
318
  if (store && id != null) {
211
319
  input.push({ type: 'item_reference', id });
@@ -213,14 +321,32 @@ export async function convertToOpenAIResponsesInput({
213
321
  break;
214
322
  }
215
323
 
216
- if (store && id != null) {
217
- input.push({ type: 'item_reference', id });
324
+ // When chaining with a previous response id, items already part
325
+ // of that response chain must not be resent.
326
+ if (hasPreviousResponseId && store && id != null) {
218
327
  break;
219
328
  }
220
329
 
221
- const resolvedToolName = toolNameMapping.toProviderToolName(
222
- part.toolName,
223
- );
330
+ // Provider-defined tool calls (local_shell, shell, apply_patch,
331
+ // and custom tools) are stored by the API and can be sent as an
332
+ // `item_reference` to reduce payload size. Plain client-executed
333
+ // function calls must NOT be: the matching `function_call_output`
334
+ // can only reference the call by `call_id` (`call_...`), which
335
+ // the API cannot reconcile with an item id (`fc_...`) or an
336
+ // `item_reference`. Sending either breaks call/output pairing and
337
+ // makes follow-up requests fail with "No tool call found for
338
+ // function call output with call_id", most visibly with parallel
339
+ // tool calls across multiple steps.
340
+ const isProviderDefinedToolCall =
341
+ (hasLocalShellTool && resolvedToolName === 'local_shell') ||
342
+ (hasShellTool && resolvedToolName === 'shell') ||
343
+ (hasApplyPatchTool && resolvedToolName === 'apply_patch') ||
344
+ (customProviderToolNames?.has(resolvedToolName) ?? false);
345
+
346
+ if (store && id != null && isProviderDefinedToolCall) {
347
+ input.push({ type: 'item_reference', id });
348
+ break;
349
+ }
224
350
 
225
351
  if (hasLocalShellTool && resolvedToolName === 'local_shell') {
226
352
  const parsedInput = await validateTypes({
@@ -298,8 +424,8 @@ export async function convertToOpenAIResponsesInput({
298
424
  type: 'function_call',
299
425
  call_id: part.toolCallId,
300
426
  name: resolvedToolName,
301
- arguments: JSON.stringify(part.input),
302
- id,
427
+ arguments: serializeToolCallArguments(part.input),
428
+ ...(namespace != null && { namespace }),
303
429
  });
304
430
  break;
305
431
  }
@@ -328,6 +454,35 @@ export async function convertToOpenAIResponsesInput({
328
454
  part.toolName,
329
455
  );
330
456
 
457
+ if (resolvedResultToolName === 'tool_search') {
458
+ const itemId =
459
+ (
460
+ part.providerOptions?.[providerOptionsName] as
461
+ | { itemId?: string }
462
+ | undefined
463
+ )?.itemId ?? part.toolCallId;
464
+
465
+ if (store) {
466
+ input.push({ type: 'item_reference', id: itemId });
467
+ } else if (part.output.type === 'json') {
468
+ const parsedOutput = await validateTypes({
469
+ value: part.output.value,
470
+ schema: toolSearchOutputSchema,
471
+ });
472
+
473
+ input.push({
474
+ type: 'tool_search_output',
475
+ id: itemId,
476
+ execution: 'server',
477
+ call_id: null,
478
+ status: 'completed',
479
+ tools: parsedOutput.tools,
480
+ });
481
+ }
482
+
483
+ break;
484
+ }
485
+
331
486
  /*
332
487
  * Shell tool results are separate output items (shell_call_output)
333
488
  * with their own item IDs distinct from the shell_call's item ID.
@@ -387,7 +542,10 @@ export async function convertToOpenAIResponsesInput({
387
542
 
388
543
  const reasoningId = providerOptions?.itemId;
389
544
 
390
- if (hasConversation && reasoningId != null) {
545
+ if (
546
+ (hasConversation || hasPreviousResponseId) &&
547
+ reasoningId != null
548
+ ) {
391
549
  break;
392
550
  }
393
551
 
@@ -478,6 +636,36 @@ export async function convertToOpenAIResponsesInput({
478
636
  }
479
637
  break;
480
638
  }
639
+
640
+ case 'custom': {
641
+ if (part.kind === 'openai.compaction') {
642
+ const providerOptions =
643
+ part.providerOptions?.[providerOptionsName];
644
+ const id = providerOptions?.itemId as string | undefined;
645
+
646
+ if (hasConversation && id != null) {
647
+ break;
648
+ }
649
+
650
+ if (store && id != null) {
651
+ input.push({ type: 'item_reference', id });
652
+ break;
653
+ }
654
+
655
+ const encryptedContent = providerOptions?.encryptedContent as
656
+ | string
657
+ | undefined;
658
+
659
+ if (id != null) {
660
+ input.push({
661
+ type: 'compaction',
662
+ id,
663
+ encrypted_content: encryptedContent!,
664
+ } satisfies OpenAIResponsesCompactionItem);
665
+ }
666
+ }
667
+ break;
668
+ }
481
669
  }
482
670
  }
483
671
 
@@ -527,6 +715,22 @@ export async function convertToOpenAIResponsesInput({
527
715
  part.toolName,
528
716
  );
529
717
 
718
+ if (resolvedToolName === 'tool_search' && output.type === 'json') {
719
+ const parsedOutput = await validateTypes({
720
+ value: output.value,
721
+ schema: toolSearchOutputSchema,
722
+ });
723
+
724
+ input.push({
725
+ type: 'tool_search_output',
726
+ execution: 'client',
727
+ call_id: part.toolCallId,
728
+ status: 'completed',
729
+ tools: parsedOutput.tools,
730
+ });
731
+ continue;
732
+ }
733
+
530
734
  if (
531
735
  hasLocalShellTool &&
532
736
  resolvedToolName === 'local_shell' &&
@@ -600,7 +804,7 @@ export async function convertToOpenAIResponsesInput({
600
804
  outputValue = output.value;
601
805
  break;
602
806
  case 'execution-denied':
603
- outputValue = output.reason ?? 'Tool execution denied.';
807
+ outputValue = output.reason ?? 'Tool call execution denied.';
604
808
  break;
605
809
  case 'json':
606
810
  case 'error-json':
@@ -612,22 +816,50 @@ export async function convertToOpenAIResponsesInput({
612
816
  switch (item.type) {
613
817
  case 'text':
614
818
  return { type: 'input_text' as const, text: item.text };
615
- case 'image-data':
616
- return {
617
- type: 'input_image' as const,
618
- image_url: `data:${item.mediaType};base64,${item.data}`,
619
- };
620
- case 'image-url':
621
- return {
622
- type: 'input_image' as const,
623
- image_url: item.url,
624
- };
625
- case 'file-data':
626
- return {
627
- type: 'input_file' as const,
628
- filename: item.filename ?? 'data',
629
- file_data: `data:${item.mediaType};base64,${item.data}`,
630
- };
819
+ case 'file': {
820
+ const topLevel = getTopLevelMediaType(item.mediaType);
821
+ const imageDetail =
822
+ item.providerOptions?.[providerOptionsName]
823
+ ?.imageDetail;
824
+
825
+ if (item.data.type === 'data') {
826
+ const fullMediaType = resolveFullMediaType({
827
+ part: item,
828
+ });
829
+ if (topLevel === 'image') {
830
+ return {
831
+ type: 'input_image' as const,
832
+ image_url: `data:${fullMediaType};base64,${convertToBase64(item.data.data)}`,
833
+ detail: imageDetail,
834
+ };
835
+ }
836
+ return {
837
+ type: 'input_file' as const,
838
+ filename: item.filename ?? 'data',
839
+ file_data: `data:${fullMediaType};base64,${convertToBase64(item.data.data)}`,
840
+ };
841
+ }
842
+
843
+ if (item.data.type === 'url') {
844
+ if (topLevel === 'image') {
845
+ return {
846
+ type: 'input_image' as const,
847
+ image_url: item.data.url.toString(),
848
+ detail: imageDetail,
849
+ };
850
+ }
851
+ return {
852
+ type: 'input_file' as const,
853
+ file_url: item.data.url.toString(),
854
+ };
855
+ }
856
+
857
+ warnings.push({
858
+ type: 'other',
859
+ message: `unsupported custom tool content part type: ${item.type} with data type: ${item.data.type}`,
860
+ });
861
+ return undefined;
862
+ }
631
863
  default:
632
864
  warnings.push({
633
865
  type: 'other',
@@ -656,7 +888,7 @@ export async function convertToOpenAIResponsesInput({
656
888
  contentValue = output.value;
657
889
  break;
658
890
  case 'execution-denied':
659
- contentValue = output.reason ?? 'Tool execution denied.';
891
+ contentValue = output.reason ?? 'Tool call execution denied.';
660
892
  break;
661
893
  case 'json':
662
894
  case 'error-json':
@@ -670,26 +902,49 @@ export async function convertToOpenAIResponsesInput({
670
902
  return { type: 'input_text' as const, text: item.text };
671
903
  }
672
904
 
673
- case 'image-data': {
674
- return {
675
- type: 'input_image' as const,
676
- image_url: `data:${item.mediaType};base64,${item.data}`,
677
- };
678
- }
905
+ case 'file': {
906
+ const topLevel = getTopLevelMediaType(item.mediaType);
907
+ const imageDetail =
908
+ item.providerOptions?.[providerOptionsName]
909
+ ?.imageDetail;
679
910
 
680
- case 'image-url': {
681
- return {
682
- type: 'input_image' as const,
683
- image_url: item.url,
684
- };
685
- }
911
+ if (item.data.type === 'data') {
912
+ const fullMediaType = resolveFullMediaType({
913
+ part: item,
914
+ });
915
+ if (topLevel === 'image') {
916
+ return {
917
+ type: 'input_image' as const,
918
+ image_url: `data:${fullMediaType};base64,${convertToBase64(item.data.data)}`,
919
+ detail: imageDetail,
920
+ };
921
+ }
922
+ return {
923
+ type: 'input_file' as const,
924
+ filename: item.filename ?? 'data',
925
+ file_data: `data:${fullMediaType};base64,${convertToBase64(item.data.data)}`,
926
+ };
927
+ }
928
+
929
+ if (item.data.type === 'url') {
930
+ if (topLevel === 'image') {
931
+ return {
932
+ type: 'input_image' as const,
933
+ image_url: item.data.url.toString(),
934
+ detail: imageDetail,
935
+ };
936
+ }
937
+ return {
938
+ type: 'input_file' as const,
939
+ file_url: item.data.url.toString(),
940
+ };
941
+ }
686
942
 
687
- case 'file-data': {
688
- return {
689
- type: 'input_file' as const,
690
- filename: item.filename ?? 'data',
691
- file_data: `data:${item.mediaType};base64,${item.data}`,
692
- };
943
+ warnings.push({
944
+ type: 'other',
945
+ message: `unsupported tool content part type: ${item.type} with data type: ${item.data.type}`,
946
+ });
947
+ return undefined;
693
948
  }
694
949
 
695
950
  default: {
@@ -1,4 +1,4 @@
1
- import { LanguageModelV4FinishReason } from '@ai-sdk/provider';
1
+ import type { LanguageModelV4FinishReason } from '@ai-sdk/provider';
2
2
 
3
3
  export function mapOpenAIResponseFinishReason({
4
4
  finishReason,