ai 3.4.5 → 3.4.7

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # ai
2
2
 
3
+ ## 3.4.7
4
+
5
+ ### Patch Changes
6
+
7
+ - db04700: feat (core): support converting attachments to file parts
8
+ - 988707c: feat (ai/core): automatically download files from urls
9
+
10
+ ## 3.4.6
11
+
12
+ ### Patch Changes
13
+
14
+ - d595d0d: feat (ai/core): file content parts
15
+ - Updated dependencies [d595d0d]
16
+ - @ai-sdk/provider@0.0.24
17
+ - @ai-sdk/provider-utils@1.0.20
18
+ - @ai-sdk/ui-utils@0.0.46
19
+ - @ai-sdk/react@0.0.62
20
+ - @ai-sdk/solid@0.0.49
21
+ - @ai-sdk/svelte@0.0.51
22
+ - @ai-sdk/vue@0.0.53
23
+
3
24
  ## 3.4.5
4
25
 
5
26
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -438,6 +438,29 @@ interface ImagePart {
438
438
  experimental_providerMetadata?: ProviderMetadata;
439
439
  }
440
440
  /**
441
+ File content part of a prompt. It contains a file.
442
+ */
443
+ interface FilePart {
444
+ type: 'file';
445
+ /**
446
+ File data. Can either be:
447
+
448
+ - data: a base64-encoded string, a Uint8Array, an ArrayBuffer, or a Buffer
449
+ - URL: a URL that points to the image
450
+ */
451
+ data: DataContent | URL;
452
+ /**
453
+ Mime type of the file.
454
+ */
455
+ mimeType: string;
456
+ /**
457
+ Additional provider-specific metadata. They are passed through
458
+ to the provider from the AI SDK and enable provider-specific
459
+ functionality that can be fully encapsulated in the provider.
460
+ */
461
+ experimental_providerMetadata?: ProviderMetadata;
462
+ }
463
+ /**
441
464
  Tool call content part of a prompt. It contains a tool call (usually generated by the AI model).
442
465
  */
443
466
  interface ToolCallPart {
@@ -531,7 +554,7 @@ type ExperimentalUserMessage = CoreUserMessage;
531
554
  /**
532
555
  Content of a user message. It can be a string or an array of text and image parts.
533
556
  */
534
- type UserContent = string | Array<TextPart$1 | ImagePart>;
557
+ type UserContent = string | Array<TextPart$1 | ImagePart | FilePart>;
535
558
  /**
536
559
  An assistant message. It can contain text, tool calls, or a combination of text and tool calls.
537
560
  */
package/dist/index.d.ts CHANGED
@@ -438,6 +438,29 @@ interface ImagePart {
438
438
  experimental_providerMetadata?: ProviderMetadata;
439
439
  }
440
440
  /**
441
+ File content part of a prompt. It contains a file.
442
+ */
443
+ interface FilePart {
444
+ type: 'file';
445
+ /**
446
+ File data. Can either be:
447
+
448
+ - data: a base64-encoded string, a Uint8Array, an ArrayBuffer, or a Buffer
449
+ - URL: a URL that points to the image
450
+ */
451
+ data: DataContent | URL;
452
+ /**
453
+ Mime type of the file.
454
+ */
455
+ mimeType: string;
456
+ /**
457
+ Additional provider-specific metadata. They are passed through
458
+ to the provider from the AI SDK and enable provider-specific
459
+ functionality that can be fully encapsulated in the provider.
460
+ */
461
+ experimental_providerMetadata?: ProviderMetadata;
462
+ }
463
+ /**
441
464
  Tool call content part of a prompt. It contains a tool call (usually generated by the AI model).
442
465
  */
443
466
  interface ToolCallPart {
@@ -531,7 +554,7 @@ type ExperimentalUserMessage = CoreUserMessage;
531
554
  /**
532
555
  Content of a user message. It can be a string or an array of text and image parts.
533
556
  */
534
- type UserContent = string | Array<TextPart$1 | ImagePart>;
557
+ type UserContent = string | Array<TextPart$1 | ImagePart | FilePart>;
535
558
  /**
536
559
  An assistant message. It can contain text, tool calls, or a combination of text and tool calls.
537
560
  */
package/dist/index.js CHANGED
@@ -825,6 +825,15 @@ var dataContentSchema = import_zod.z.union([
825
825
  { message: "Must be a Buffer" }
826
826
  )
827
827
  ]);
828
+ function convertDataContentToBase64String(content) {
829
+ if (typeof content === "string") {
830
+ return content;
831
+ }
832
+ if (content instanceof ArrayBuffer) {
833
+ return (0, import_provider_utils2.convertUint8ArrayToBase64)(new Uint8Array(content));
834
+ }
835
+ return (0, import_provider_utils2.convertUint8ArrayToBase64)(content);
836
+ }
828
837
  function convertDataContentToUint8Array(content) {
829
838
  if (content instanceof Uint8Array) {
830
839
  return content;
@@ -891,6 +900,22 @@ var InvalidMessageRoleError = class extends import_provider5.AISDKError {
891
900
  };
892
901
  _a4 = symbol4;
893
902
 
903
+ // core/prompt/split-data-url.ts
904
+ function splitDataUrl(dataUrl) {
905
+ try {
906
+ const [header, base64Content] = dataUrl.split(",");
907
+ return {
908
+ mimeType: header.split(";")[0].split(":")[1],
909
+ base64Content
910
+ };
911
+ } catch (error) {
912
+ return {
913
+ mimeType: void 0,
914
+ base64Content: void 0
915
+ };
916
+ }
917
+ }
918
+
894
919
  // core/prompt/convert-to-language-model-prompt.ts
895
920
  async function convertToLanguageModelPrompt({
896
921
  prompt,
@@ -901,7 +926,7 @@ async function convertToLanguageModelPrompt({
901
926
  if (prompt.system != null) {
902
927
  languageModelMessages.push({ role: "system", content: prompt.system });
903
928
  }
904
- const downloadedImages = modelSupportsImageUrls || prompt.messages == null ? null : await downloadImages(prompt.messages, downloadImplementation);
929
+ const downloadedAssets = modelSupportsImageUrls || prompt.messages == null ? null : await downloadAssets(prompt.messages, downloadImplementation);
905
930
  const promptType = prompt.type;
906
931
  switch (promptType) {
907
932
  case "prompt": {
@@ -914,7 +939,7 @@ async function convertToLanguageModelPrompt({
914
939
  case "messages": {
915
940
  languageModelMessages.push(
916
941
  ...prompt.messages.map(
917
- (message) => convertToLanguageModelMessage(message, downloadedImages)
942
+ (message) => convertToLanguageModelMessage(message, downloadedAssets)
918
943
  )
919
944
  );
920
945
  break;
@@ -926,7 +951,7 @@ async function convertToLanguageModelPrompt({
926
951
  }
927
952
  return languageModelMessages;
928
953
  }
929
- function convertToLanguageModelMessage(message, downloadedImages) {
954
+ function convertToLanguageModelMessage(message, downloadedAssets) {
930
955
  const role = message.role;
931
956
  switch (role) {
932
957
  case "system": {
@@ -946,98 +971,178 @@ function convertToLanguageModelMessage(message, downloadedImages) {
946
971
  }
947
972
  return {
948
973
  role: "user",
949
- content: message.content.map((part) => {
950
- var _a11, _b, _c;
951
- switch (part.type) {
952
- case "text": {
953
- return {
954
- type: "text",
955
- text: part.text,
956
- providerMetadata: part.experimental_providerMetadata
957
- };
958
- }
959
- case "image": {
960
- if (part.image instanceof URL) {
961
- if (downloadedImages == null) {
962
- return {
963
- type: "image",
964
- image: part.image,
965
- mimeType: part.mimeType,
966
- providerMetadata: part.experimental_providerMetadata
967
- };
968
- } else {
969
- const downloadedImage = downloadedImages[part.image.toString()];
970
- return {
971
- type: "image",
972
- image: downloadedImage.data,
973
- mimeType: (_a11 = part.mimeType) != null ? _a11 : downloadedImage.mimeType,
974
- providerMetadata: part.experimental_providerMetadata
975
- };
976
- }
974
+ content: message.content.map(
975
+ (part) => {
976
+ var _a11, _b, _c, _d, _e;
977
+ switch (part.type) {
978
+ case "text": {
979
+ return {
980
+ type: "text",
981
+ text: part.text,
982
+ providerMetadata: part.experimental_providerMetadata
983
+ };
977
984
  }
978
- if (typeof part.image === "string") {
979
- try {
980
- const url = new URL(part.image);
981
- switch (url.protocol) {
982
- case "http:":
983
- case "https:": {
984
- if (downloadedImages == null) {
985
- return {
986
- type: "image",
987
- image: url,
988
- mimeType: part.mimeType,
989
- providerMetadata: part.experimental_providerMetadata
990
- };
991
- } else {
992
- const downloadedImage = downloadedImages[part.image];
993
- return {
994
- type: "image",
995
- image: downloadedImage.data,
996
- mimeType: (_b = part.mimeType) != null ? _b : downloadedImage.mimeType,
997
- providerMetadata: part.experimental_providerMetadata
998
- };
985
+ case "image": {
986
+ if (part.image instanceof URL) {
987
+ if (downloadedAssets == null) {
988
+ return {
989
+ type: "image",
990
+ image: part.image,
991
+ mimeType: part.mimeType,
992
+ providerMetadata: part.experimental_providerMetadata
993
+ };
994
+ } else {
995
+ const downloadedImage = downloadedAssets[part.image.toString()];
996
+ return {
997
+ type: "image",
998
+ image: downloadedImage.data,
999
+ mimeType: (_a11 = part.mimeType) != null ? _a11 : downloadedImage.mimeType,
1000
+ providerMetadata: part.experimental_providerMetadata
1001
+ };
1002
+ }
1003
+ }
1004
+ if (typeof part.image === "string") {
1005
+ try {
1006
+ const url = new URL(part.image);
1007
+ switch (url.protocol) {
1008
+ case "http:":
1009
+ case "https:": {
1010
+ if (downloadedAssets == null) {
1011
+ return {
1012
+ type: "image",
1013
+ image: url,
1014
+ mimeType: part.mimeType,
1015
+ providerMetadata: part.experimental_providerMetadata
1016
+ };
1017
+ } else {
1018
+ const downloadedImage = downloadedAssets[url.toString()];
1019
+ return {
1020
+ type: "image",
1021
+ image: downloadedImage.data,
1022
+ mimeType: (_b = part.mimeType) != null ? _b : downloadedImage.mimeType,
1023
+ providerMetadata: part.experimental_providerMetadata
1024
+ };
1025
+ }
999
1026
  }
1000
- }
1001
- case "data:": {
1002
- try {
1003
- const [header, base64Content] = part.image.split(",");
1004
- const mimeType = header.split(";")[0].split(":")[1];
1005
- if (mimeType == null || base64Content == null) {
1006
- throw new Error("Invalid data URL format");
1027
+ case "data:": {
1028
+ try {
1029
+ const { mimeType, base64Content } = splitDataUrl(
1030
+ part.image
1031
+ );
1032
+ if (mimeType == null || base64Content == null) {
1033
+ throw new Error("Invalid data URL format");
1034
+ }
1035
+ return {
1036
+ type: "image",
1037
+ image: convertDataContentToUint8Array(base64Content),
1038
+ mimeType,
1039
+ providerMetadata: part.experimental_providerMetadata
1040
+ };
1041
+ } catch (error) {
1042
+ throw new Error(
1043
+ `Error processing data URL: ${(0, import_provider_utils3.getErrorMessage)(
1044
+ message
1045
+ )}`
1046
+ );
1007
1047
  }
1008
- return {
1009
- type: "image",
1010
- image: convertDataContentToUint8Array(base64Content),
1011
- mimeType,
1012
- providerMetadata: part.experimental_providerMetadata
1013
- };
1014
- } catch (error) {
1015
- throw new Error(
1016
- `Error processing data URL: ${(0, import_provider_utils3.getErrorMessage)(
1017
- message
1018
- )}`
1019
- );
1020
1048
  }
1021
1049
  }
1022
- default: {
1023
- throw new Error(
1024
- `Unsupported URL protocol: ${url.protocol}`
1025
- );
1050
+ } catch (_ignored) {
1051
+ }
1052
+ }
1053
+ const imageUint8 = convertDataContentToUint8Array(part.image);
1054
+ return {
1055
+ type: "image",
1056
+ image: imageUint8,
1057
+ mimeType: (_c = part.mimeType) != null ? _c : detectImageMimeType(imageUint8),
1058
+ providerMetadata: part.experimental_providerMetadata
1059
+ };
1060
+ }
1061
+ case "file": {
1062
+ if (part.data instanceof URL) {
1063
+ if (downloadedAssets == null) {
1064
+ return {
1065
+ type: "file",
1066
+ data: part.data,
1067
+ mimeType: part.mimeType,
1068
+ providerMetadata: part.experimental_providerMetadata
1069
+ };
1070
+ } else {
1071
+ const downloadedImage = downloadedAssets[part.data.toString()];
1072
+ return {
1073
+ type: "file",
1074
+ data: (0, import_provider_utils3.convertUint8ArrayToBase64)(downloadedImage.data),
1075
+ mimeType: (_d = part.mimeType) != null ? _d : downloadedImage.mimeType,
1076
+ providerMetadata: part.experimental_providerMetadata
1077
+ };
1078
+ }
1079
+ }
1080
+ if (typeof part.data === "string") {
1081
+ try {
1082
+ const url = new URL(part.data);
1083
+ switch (url.protocol) {
1084
+ case "http:":
1085
+ case "https:": {
1086
+ if (downloadedAssets == null) {
1087
+ return {
1088
+ type: "file",
1089
+ data: url,
1090
+ mimeType: part.mimeType,
1091
+ providerMetadata: part.experimental_providerMetadata
1092
+ };
1093
+ } else {
1094
+ const downloadedImage = downloadedAssets[url.toString()];
1095
+ return {
1096
+ type: "file",
1097
+ data: (0, import_provider_utils3.convertUint8ArrayToBase64)(
1098
+ downloadedImage.data
1099
+ ),
1100
+ mimeType: (_e = part.mimeType) != null ? _e : downloadedImage.mimeType,
1101
+ providerMetadata: part.experimental_providerMetadata
1102
+ };
1103
+ }
1104
+ }
1105
+ case "data:": {
1106
+ try {
1107
+ const { mimeType, base64Content } = splitDataUrl(
1108
+ part.data
1109
+ );
1110
+ if (mimeType == null || base64Content == null) {
1111
+ throw new Error("Invalid data URL format");
1112
+ }
1113
+ return {
1114
+ type: "file",
1115
+ data: convertDataContentToBase64String(
1116
+ base64Content
1117
+ ),
1118
+ mimeType,
1119
+ providerMetadata: part.experimental_providerMetadata
1120
+ };
1121
+ } catch (error) {
1122
+ throw new Error(
1123
+ `Error processing data URL: ${(0, import_provider_utils3.getErrorMessage)(
1124
+ message
1125
+ )}`
1126
+ );
1127
+ }
1128
+ }
1026
1129
  }
1130
+ } catch (_ignored) {
1027
1131
  }
1028
- } catch (_ignored) {
1029
1132
  }
1133
+ const imageBase64 = convertDataContentToBase64String(
1134
+ part.data
1135
+ );
1136
+ return {
1137
+ type: "file",
1138
+ data: imageBase64,
1139
+ mimeType: part.mimeType,
1140
+ providerMetadata: part.experimental_providerMetadata
1141
+ };
1030
1142
  }
1031
- const imageUint8 = convertDataContentToUint8Array(part.image);
1032
- return {
1033
- type: "image",
1034
- image: imageUint8,
1035
- mimeType: (_c = part.mimeType) != null ? _c : detectImageMimeType(imageUint8),
1036
- providerMetadata: part.experimental_providerMetadata
1037
- };
1038
1143
  }
1039
1144
  }
1040
- }).filter((part) => part.type !== "text" || part.text !== ""),
1145
+ ).filter((part) => part.type !== "text" || part.text !== ""),
1041
1146
  providerMetadata: message.experimental_providerMetadata
1042
1147
  };
1043
1148
  }
@@ -1083,12 +1188,14 @@ function convertToLanguageModelMessage(message, downloadedImages) {
1083
1188
  }
1084
1189
  }
1085
1190
  }
1086
- async function downloadImages(messages, downloadImplementation) {
1191
+ async function downloadAssets(messages, downloadImplementation) {
1087
1192
  const urls = messages.filter((message) => message.role === "user").map((message) => message.content).filter(
1088
1193
  (content) => Array.isArray(content)
1089
- ).flat().filter((part) => part.type === "image").map((part) => part.image).map(
1194
+ ).flat().filter(
1195
+ (part) => part.type === "image" || part.type === "file"
1196
+ ).map((part) => part.type === "image" ? part.image : part.data).map(
1090
1197
  (part) => (
1091
- // support string urls in image parts:
1198
+ // support string urls:
1092
1199
  typeof part === "string" && (part.startsWith("http:") || part.startsWith("https:")) ? new URL(part) : part
1093
1200
  )
1094
1201
  ).filter((image) => image instanceof URL);
@@ -1298,6 +1405,12 @@ var imagePartSchema = import_zod4.z.object({
1298
1405
  mimeType: import_zod4.z.string().optional(),
1299
1406
  experimental_providerMetadata: providerMetadataSchema.optional()
1300
1407
  });
1408
+ var filePartSchema = import_zod4.z.object({
1409
+ type: import_zod4.z.literal("file"),
1410
+ data: import_zod4.z.union([dataContentSchema, import_zod4.z.instanceof(URL)]),
1411
+ mimeType: import_zod4.z.string(),
1412
+ experimental_providerMetadata: providerMetadataSchema.optional()
1413
+ });
1301
1414
  var toolCallPartSchema = import_zod4.z.object({
1302
1415
  type: import_zod4.z.literal("tool-call"),
1303
1416
  toolCallId: import_zod4.z.string(),
@@ -1323,7 +1436,7 @@ var coreUserMessageSchema = import_zod5.z.object({
1323
1436
  role: import_zod5.z.literal("user"),
1324
1437
  content: import_zod5.z.union([
1325
1438
  import_zod5.z.string(),
1326
- import_zod5.z.array(import_zod5.z.union([textPartSchema, imagePartSchema]))
1439
+ import_zod5.z.array(import_zod5.z.union([textPartSchema, imagePartSchema, filePartSchema]))
1327
1440
  ]),
1328
1441
  experimental_providerMetadata: providerMetadataSchema.optional()
1329
1442
  });
@@ -4651,6 +4764,17 @@ function attachmentsToParts(attachments) {
4651
4764
  case "https:": {
4652
4765
  if ((_a11 = attachment.contentType) == null ? void 0 : _a11.startsWith("image/")) {
4653
4766
  parts.push({ type: "image", image: url });
4767
+ } else {
4768
+ if (!attachment.contentType) {
4769
+ throw new Error(
4770
+ "If the attachment is not an image, it must specify a content type"
4771
+ );
4772
+ }
4773
+ parts.push({
4774
+ type: "file",
4775
+ data: url,
4776
+ mimeType: attachment.contentType
4777
+ });
4654
4778
  }
4655
4779
  break;
4656
4780
  }
@@ -4679,6 +4803,17 @@ function attachmentsToParts(attachments) {
4679
4803
  convertDataContentToUint8Array(base64Content)
4680
4804
  )
4681
4805
  });
4806
+ } else {
4807
+ if (!attachment.contentType) {
4808
+ throw new Error(
4809
+ "If the attachment is not an image or text, it must specify a content type"
4810
+ );
4811
+ }
4812
+ parts.push({
4813
+ type: "file",
4814
+ data: base64Content,
4815
+ mimeType: attachment.contentType
4816
+ });
4682
4817
  }
4683
4818
  break;
4684
4819
  }