@ai-sdk/alibaba 1.0.34 → 1.0.36

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,30 @@
1
1
  # @ai-sdk/alibaba
2
2
 
3
+ ## 1.0.36
4
+
5
+ ### Patch Changes
6
+
7
+ - bef93ae: fix(security): prevent streaming tool calls from finalizing on parsable partial JSON
8
+
9
+ Streaming tool call arguments were finalized using `isParsableJson()` as a heuristic for completion. If partial accumulated JSON happened to be valid JSON before all chunks arrived, the tool call would be executed with incomplete arguments. Tool call finalization now only occurs in `flush()` after the stream is fully consumed.
10
+
11
+ - 327642b: fix: more precise default message for tool execution denial
12
+ - Updated dependencies [4d4e176]
13
+ - Updated dependencies [bef93ae]
14
+ - Updated dependencies [d559de9]
15
+ - Updated dependencies [327642b]
16
+ - @ai-sdk/openai-compatible@2.0.58
17
+ - @ai-sdk/provider-utils@4.0.37
18
+
19
+ ## 1.0.35
20
+
21
+ ### Patch Changes
22
+
23
+ - 7dea716: feat(alibaba): support wan2.7 text-to-video and reference-to-video models with the new protocol (`input.media`, `resolution` + `ratio`)
24
+ - Updated dependencies [0952964]
25
+ - @ai-sdk/provider-utils@4.0.36
26
+ - @ai-sdk/openai-compatible@2.0.57
27
+
3
28
  ## 1.0.34
4
29
 
5
30
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -29,7 +29,7 @@ declare const alibabaEmbeddingModelOptions: z.ZodObject<{
29
29
  }, z.core.$strip>;
30
30
  type AlibabaEmbeddingModelOptions = z.infer<typeof alibabaEmbeddingModelOptions>;
31
31
 
32
- type AlibabaVideoModelId = 'wan2.6-t2v' | 'wan2.5-t2v-preview' | 'wan2.6-i2v' | 'wan2.6-i2v-flash' | 'wan2.6-r2v' | 'wan2.6-r2v-flash' | (string & {});
32
+ type AlibabaVideoModelId = 'wan2.6-t2v' | 'wan2.5-t2v-preview' | 'wan2.7-t2v' | 'wan2.7-t2v-2026-06-12' | 'wan2.6-i2v' | 'wan2.6-i2v-flash' | 'wan2.6-r2v' | 'wan2.6-r2v-flash' | 'wan2.7-r2v' | 'wan2.7-r2v-2026-06-12' | (string & {});
33
33
 
34
34
  interface AlibabaProvider extends ProviderV3 {
35
35
  (modelId: AlibabaChatModelId): LanguageModelV3;
@@ -135,6 +135,23 @@ type AlibabaVideoModelOptions = {
135
135
  * Use character identifiers (character1, character2) in prompts to reference them.
136
136
  */
137
137
  referenceUrls?: string[] | null;
138
+ /**
139
+ * Explicit media array for reference-to-video mode (wan2.7 models).
140
+ * Overrides the automatic mapping from `inputReferences` and `frameImages`.
141
+ * Use `Image 1`, `Video 1`, etc. in prompts to reference media items
142
+ * (images and videos are counted separately, in array order).
143
+ */
144
+ media?: Array<{
145
+ type: 'reference_image' | 'reference_video' | 'first_frame';
146
+ /** Public URL, or a `data:{mime};base64,{data}` URI for images. */
147
+ url: string;
148
+ /** URL to an audio file used as voice reference for this media item. */
149
+ referenceVoice?: string | null;
150
+ }> | null;
151
+ /**
152
+ * Aspect ratio (wan2.7 text-to-video and reference-to-video models).
153
+ */
154
+ ratio?: '16:9' | '9:16' | '1:1' | '4:3' | '3:4' | null;
138
155
  /** Polling interval in milliseconds. Defaults to 5000 (5 seconds). */
139
156
  pollIntervalMs?: number | null;
140
157
  /** Maximum wait time in milliseconds for video generation. Defaults to 600000 (10 minutes). */
package/dist/index.d.ts CHANGED
@@ -29,7 +29,7 @@ declare const alibabaEmbeddingModelOptions: z.ZodObject<{
29
29
  }, z.core.$strip>;
30
30
  type AlibabaEmbeddingModelOptions = z.infer<typeof alibabaEmbeddingModelOptions>;
31
31
 
32
- type AlibabaVideoModelId = 'wan2.6-t2v' | 'wan2.5-t2v-preview' | 'wan2.6-i2v' | 'wan2.6-i2v-flash' | 'wan2.6-r2v' | 'wan2.6-r2v-flash' | (string & {});
32
+ type AlibabaVideoModelId = 'wan2.6-t2v' | 'wan2.5-t2v-preview' | 'wan2.7-t2v' | 'wan2.7-t2v-2026-06-12' | 'wan2.6-i2v' | 'wan2.6-i2v-flash' | 'wan2.6-r2v' | 'wan2.6-r2v-flash' | 'wan2.7-r2v' | 'wan2.7-r2v-2026-06-12' | (string & {});
33
33
 
34
34
  interface AlibabaProvider extends ProviderV3 {
35
35
  (modelId: AlibabaChatModelId): LanguageModelV3;
@@ -135,6 +135,23 @@ type AlibabaVideoModelOptions = {
135
135
  * Use character identifiers (character1, character2) in prompts to reference them.
136
136
  */
137
137
  referenceUrls?: string[] | null;
138
+ /**
139
+ * Explicit media array for reference-to-video mode (wan2.7 models).
140
+ * Overrides the automatic mapping from `inputReferences` and `frameImages`.
141
+ * Use `Image 1`, `Video 1`, etc. in prompts to reference media items
142
+ * (images and videos are counted separately, in array order).
143
+ */
144
+ media?: Array<{
145
+ type: 'reference_image' | 'reference_video' | 'first_frame';
146
+ /** Public URL, or a `data:{mime};base64,{data}` URI for images. */
147
+ url: string;
148
+ /** URL to an audio file used as voice reference for this media item. */
149
+ referenceVoice?: string | null;
150
+ }> | null;
151
+ /**
152
+ * Aspect ratio (wan2.7 text-to-video and reference-to-video models).
153
+ */
154
+ ratio?: '16:9' | '9:16' | '1:1' | '4:3' | '3:4' | null;
138
155
  /** Polling interval in milliseconds. Defaults to 5000 (5 seconds). */
139
156
  pollIntervalMs?: number | null;
140
157
  /** Maximum wait time in milliseconds for video generation. Defaults to 600000 (10 minutes). */
package/dist/index.js CHANGED
@@ -214,7 +214,7 @@ function convertToAlibabaChatMessages({
214
214
  contentValue = output.value;
215
215
  break;
216
216
  case "execution-denied":
217
- contentValue = (_b = output.reason) != null ? _b : "Tool execution denied.";
217
+ contentValue = (_b = output.reason) != null ? _b : "Tool call execution denied.";
218
218
  break;
219
219
  case "content":
220
220
  case "json":
@@ -562,19 +562,6 @@ var AlibabaLanguageModel = class {
562
562
  delta: toolCall2.function.arguments
563
563
  });
564
564
  }
565
- if ((0, import_provider_utils3.isParsableJson)(toolCall2.function.arguments)) {
566
- controller.enqueue({
567
- type: "tool-input-end",
568
- id: toolCall2.id
569
- });
570
- controller.enqueue({
571
- type: "tool-call",
572
- toolCallId: toolCall2.id,
573
- toolName: toolCall2.function.name,
574
- input: toolCall2.function.arguments
575
- });
576
- toolCall2.hasFinished = true;
577
- }
578
565
  continue;
579
566
  }
580
567
  const toolCall = toolCalls[index];
@@ -589,19 +576,6 @@ var AlibabaLanguageModel = class {
589
576
  delta: toolCallDelta.function.arguments
590
577
  });
591
578
  }
592
- if ((0, import_provider_utils3.isParsableJson)(toolCall.function.arguments)) {
593
- controller.enqueue({
594
- type: "tool-input-end",
595
- id: toolCall.id
596
- });
597
- controller.enqueue({
598
- type: "tool-call",
599
- toolCallId: toolCall.id,
600
- toolName: toolCall.function.name,
601
- input: toolCall.function.arguments
602
- });
603
- toolCall.hasFinished = true;
604
- }
605
579
  }
606
580
  }
607
581
  if (choice.finish_reason != null) {
@@ -621,6 +595,21 @@ var AlibabaLanguageModel = class {
621
595
  if (activeText) {
622
596
  controller.enqueue({ type: "text-end", id: "0" });
623
597
  }
598
+ for (const toolCall of toolCalls) {
599
+ if (!toolCall.hasFinished) {
600
+ controller.enqueue({
601
+ type: "tool-input-end",
602
+ id: toolCall.id
603
+ });
604
+ controller.enqueue({
605
+ type: "tool-call",
606
+ toolCallId: toolCall.id,
607
+ toolName: toolCall.function.name,
608
+ input: toolCall.function.arguments
609
+ });
610
+ toolCall.hasFinished = true;
611
+ }
612
+ }
624
613
  controller.enqueue({
625
614
  type: "finish",
626
615
  finishReason,
@@ -860,6 +849,18 @@ var alibabaVideoModelOptionsSchema = (0, import_provider_utils5.lazySchema)(
860
849
  watermark: import_v46.z.boolean().nullish(),
861
850
  audio: import_v46.z.boolean().nullish(),
862
851
  referenceUrls: import_v46.z.array(import_v46.z.string()).nullish(),
852
+ media: import_v46.z.array(
853
+ import_v46.z.object({
854
+ type: import_v46.z.enum([
855
+ "reference_image",
856
+ "reference_video",
857
+ "first_frame"
858
+ ]),
859
+ url: import_v46.z.string(),
860
+ referenceVoice: import_v46.z.string().nullish()
861
+ })
862
+ ).nullish(),
863
+ ratio: import_v46.z.enum(["16:9", "9:16", "1:1", "4:3", "3:4"]).nullish(),
863
864
  pollIntervalMs: import_v46.z.number().positive().nullish(),
864
865
  pollTimeoutMs: import_v46.z.number().positive().nullish()
865
866
  }).passthrough()
@@ -907,6 +908,38 @@ function detectMode(modelId) {
907
908
  if (modelId.includes("-r2v")) return "r2v";
908
909
  return "t2v";
909
910
  }
911
+ function isWan27Model(modelId) {
912
+ return modelId.startsWith("wan2.7");
913
+ }
914
+ var resolutionTierMap = {
915
+ "1280x720": "720P",
916
+ "720x1280": "720P",
917
+ "960x960": "720P",
918
+ "1088x832": "720P",
919
+ "832x1088": "720P",
920
+ "1920x1080": "1080P",
921
+ "1080x1920": "1080P",
922
+ "1440x1440": "1080P",
923
+ "1632x1248": "1080P",
924
+ "1248x1632": "1080P",
925
+ "832x480": "480P",
926
+ "480x832": "480P",
927
+ "624x624": "480P"
928
+ };
929
+ var supportedRatios = /* @__PURE__ */ new Set(["16:9", "9:16", "1:1", "4:3", "3:4"]);
930
+ function deriveRatioFromResolution(resolution) {
931
+ const [width, height] = resolution.split("x").map(Number);
932
+ if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0) {
933
+ return void 0;
934
+ }
935
+ let a = width;
936
+ let b = height;
937
+ while (b !== 0) {
938
+ [a, b] = [b, a % b];
939
+ }
940
+ const ratio = `${width / a}:${height / a}`;
941
+ return supportedRatios.has(ratio) ? ratio : void 0;
942
+ }
910
943
  function fileToImageString(file) {
911
944
  if (file.type === "url") {
912
945
  return file.url;
@@ -921,6 +954,47 @@ function resolveStartImage(options) {
921
954
  var _a;
922
955
  return (_a = getFirstFrameImage(options)) != null ? _a : options.image;
923
956
  }
957
+ function isVideoUrl(url) {
958
+ return /\.(mp4|mov)([?#]|$)/i.test(url);
959
+ }
960
+ function resolveMedia(options, alibabaOptions, warnings) {
961
+ var _a;
962
+ if ((alibabaOptions == null ? void 0 : alibabaOptions.media) != null && alibabaOptions.media.length > 0) {
963
+ return alibabaOptions.media.map((item) => ({
964
+ type: item.type,
965
+ url: item.url,
966
+ ...item.referenceVoice != null ? { reference_voice: item.referenceVoice } : {}
967
+ }));
968
+ }
969
+ const media = [];
970
+ for (const reference of (_a = options.inputReferences) != null ? _a : []) {
971
+ if (reference.type === "url") {
972
+ media.push({
973
+ type: isVideoUrl(reference.url) ? "reference_video" : "reference_image",
974
+ url: reference.url
975
+ });
976
+ } else if (reference.mediaType.startsWith("image/")) {
977
+ media.push({
978
+ type: "reference_image",
979
+ url: (0, import_provider_utils5.convertImageModelFileToDataUri)(reference)
980
+ });
981
+ } else {
982
+ warnings.push({
983
+ type: "unsupported",
984
+ feature: "inputReferences",
985
+ details: "Alibaba reference-to-video requires URL references for videos. Non-URL video reference was skipped."
986
+ });
987
+ }
988
+ }
989
+ const firstFrame = getFirstFrameImage(options);
990
+ if (firstFrame != null) {
991
+ media.push({
992
+ type: "first_frame",
993
+ url: (0, import_provider_utils5.convertImageModelFileToDataUri)(firstFrame)
994
+ });
995
+ }
996
+ return media.length > 0 ? media : void 0;
997
+ }
924
998
  function resolveReferenceUrls(options, alibabaOptions, warnings) {
925
999
  var _a;
926
1000
  if (options.frameImages != null && options.frameImages.length > 0) {
@@ -954,7 +1028,7 @@ var AlibabaVideoModel = class {
954
1028
  return this.config.provider;
955
1029
  }
956
1030
  async doGenerate(options) {
957
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
1031
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
958
1032
  const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
959
1033
  const warnings = [];
960
1034
  const mode = detectMode(this.modelId);
@@ -974,16 +1048,27 @@ var AlibabaVideoModel = class {
974
1048
  input.audio_url = alibabaOptions.audioUrl;
975
1049
  }
976
1050
  const startImage = resolveStartImage(options);
977
- const referenceUrls = resolveReferenceUrls(
978
- options,
979
- alibabaOptions,
980
- warnings
981
- );
1051
+ const wan27 = isWan27Model(this.modelId);
1052
+ const supportsRatio = wan27 && mode !== "i2v";
982
1053
  if (mode === "i2v" && startImage != null) {
983
1054
  input.img_url = fileToImageString(startImage);
984
1055
  }
985
- if (mode === "r2v" && referenceUrls != null && referenceUrls.length > 0) {
986
- input.reference_urls = referenceUrls;
1056
+ if (mode === "r2v") {
1057
+ if (wan27) {
1058
+ const media = resolveMedia(options, alibabaOptions, warnings);
1059
+ if (media != null) {
1060
+ input.media = media;
1061
+ }
1062
+ } else {
1063
+ const referenceUrls = resolveReferenceUrls(
1064
+ options,
1065
+ alibabaOptions,
1066
+ warnings
1067
+ );
1068
+ if (referenceUrls != null && referenceUrls.length > 0) {
1069
+ input.reference_urls = referenceUrls;
1070
+ }
1071
+ }
987
1072
  }
988
1073
  const lastFrame = (_e = (_d = options.frameImages) == null ? void 0 : _d.find(
989
1074
  (frame) => frame.frameType === "last_frame"
@@ -1010,41 +1095,57 @@ var AlibabaVideoModel = class {
1010
1095
  parameters.seed = options.seed;
1011
1096
  }
1012
1097
  if (options.resolution != null) {
1013
- if (mode === "i2v") {
1014
- const resolutionMap = {
1015
- "1280x720": "720P",
1016
- "720x1280": "720P",
1017
- "960x960": "720P",
1018
- "1088x832": "720P",
1019
- "832x1088": "720P",
1020
- "1920x1080": "1080P",
1021
- "1080x1920": "1080P",
1022
- "1440x1440": "1080P",
1023
- "1632x1248": "1080P",
1024
- "1248x1632": "1080P",
1025
- "832x480": "480P",
1026
- "480x832": "480P",
1027
- "624x624": "480P"
1028
- };
1029
- parameters.resolution = resolutionMap[options.resolution] || options.resolution;
1098
+ if (mode === "i2v" || wan27) {
1099
+ const resolutionTier = resolutionTierMap[options.resolution] || options.resolution;
1100
+ if (wan27 && resolutionTier !== "720P" && resolutionTier !== "1080P") {
1101
+ warnings.push({
1102
+ type: "unsupported",
1103
+ feature: "resolution",
1104
+ details: `wan2.7 models only support 720P and 1080P resolutions. The resolution "${options.resolution}" was ignored.`
1105
+ });
1106
+ } else {
1107
+ parameters.resolution = resolutionTier;
1108
+ }
1030
1109
  } else {
1031
1110
  parameters.size = options.resolution.replace("x", "*");
1032
1111
  }
1033
1112
  }
1113
+ if (supportsRatio) {
1114
+ const ratio = (_g = (_f = alibabaOptions == null ? void 0 : alibabaOptions.ratio) != null ? _f : options.aspectRatio) != null ? _g : options.resolution != null ? deriveRatioFromResolution(options.resolution) : void 0;
1115
+ if (ratio != null) {
1116
+ parameters.ratio = ratio;
1117
+ }
1118
+ }
1034
1119
  if ((alibabaOptions == null ? void 0 : alibabaOptions.promptExtend) != null) {
1035
1120
  parameters.prompt_extend = alibabaOptions.promptExtend;
1036
1121
  }
1037
1122
  if ((alibabaOptions == null ? void 0 : alibabaOptions.shotType) != null) {
1038
- parameters.shot_type = alibabaOptions.shotType;
1123
+ if (wan27) {
1124
+ warnings.push({
1125
+ type: "unsupported",
1126
+ feature: "shotType",
1127
+ details: "wan2.7 models do not support the shotType option. Describe the shot structure in the prompt instead."
1128
+ });
1129
+ } else {
1130
+ parameters.shot_type = alibabaOptions.shotType;
1131
+ }
1039
1132
  }
1040
1133
  if ((alibabaOptions == null ? void 0 : alibabaOptions.watermark) != null) {
1041
1134
  parameters.watermark = alibabaOptions.watermark;
1042
1135
  }
1043
- const audio = (_f = options.generateAudio) != null ? _f : alibabaOptions == null ? void 0 : alibabaOptions.audio;
1136
+ const audio = (_h = options.generateAudio) != null ? _h : alibabaOptions == null ? void 0 : alibabaOptions.audio;
1044
1137
  if (audio != null) {
1045
- parameters.audio = audio;
1138
+ if (wan27) {
1139
+ warnings.push({
1140
+ type: "unsupported",
1141
+ feature: "generateAudio",
1142
+ details: "wan2.7 models always generate audio. The audio option was ignored."
1143
+ });
1144
+ } else {
1145
+ parameters.audio = audio;
1146
+ }
1046
1147
  }
1047
- if (options.aspectRatio) {
1148
+ if (options.aspectRatio && !supportsRatio) {
1048
1149
  warnings.push({
1049
1150
  type: "unsupported",
1050
1151
  feature: "aspectRatio",
@@ -1086,15 +1187,15 @@ var AlibabaVideoModel = class {
1086
1187
  abortSignal: options.abortSignal,
1087
1188
  fetch: this.config.fetch
1088
1189
  });
1089
- const taskId = (_g = createResponse.output) == null ? void 0 : _g.task_id;
1190
+ const taskId = (_i = createResponse.output) == null ? void 0 : _i.task_id;
1090
1191
  if (!taskId) {
1091
1192
  throw new import_provider4.AISDKError({
1092
1193
  name: "ALIBABA_VIDEO_GENERATION_ERROR",
1093
1194
  message: `No task_id returned from Alibaba API. Response: ${JSON.stringify(createResponse)}`
1094
1195
  });
1095
1196
  }
1096
- const pollIntervalMs = (_h = alibabaOptions == null ? void 0 : alibabaOptions.pollIntervalMs) != null ? _h : 5e3;
1097
- const pollTimeoutMs = (_i = alibabaOptions == null ? void 0 : alibabaOptions.pollTimeoutMs) != null ? _i : 6e5;
1197
+ const pollIntervalMs = (_j = alibabaOptions == null ? void 0 : alibabaOptions.pollIntervalMs) != null ? _j : 5e3;
1198
+ const pollTimeoutMs = (_k = alibabaOptions == null ? void 0 : alibabaOptions.pollTimeoutMs) != null ? _k : 6e5;
1098
1199
  const startTime = Date.now();
1099
1200
  let finalResponse;
1100
1201
  let responseHeaders;
@@ -1120,7 +1221,7 @@ var AlibabaVideoModel = class {
1120
1221
  fetch: this.config.fetch
1121
1222
  });
1122
1223
  responseHeaders = pollHeaders;
1123
- const taskStatus = (_j = statusResponse.output) == null ? void 0 : _j.task_status;
1224
+ const taskStatus = (_l = statusResponse.output) == null ? void 0 : _l.task_status;
1124
1225
  if (taskStatus === "SUCCEEDED") {
1125
1226
  finalResponse = statusResponse;
1126
1227
  break;
@@ -1128,11 +1229,11 @@ var AlibabaVideoModel = class {
1128
1229
  if (taskStatus === "FAILED" || taskStatus === "CANCELED") {
1129
1230
  throw new import_provider4.AISDKError({
1130
1231
  name: "ALIBABA_VIDEO_GENERATION_FAILED",
1131
- message: `Video generation ${taskStatus.toLowerCase()}. Task ID: ${taskId}. ${(_l = (_k = statusResponse.output) == null ? void 0 : _k.message) != null ? _l : ""}`
1232
+ message: `Video generation ${taskStatus.toLowerCase()}. Task ID: ${taskId}. ${(_n = (_m = statusResponse.output) == null ? void 0 : _m.message) != null ? _n : ""}`
1132
1233
  });
1133
1234
  }
1134
1235
  }
1135
- const videoUrl = (_m = finalResponse == null ? void 0 : finalResponse.output) == null ? void 0 : _m.video_url;
1236
+ const videoUrl = (_o = finalResponse == null ? void 0 : finalResponse.output) == null ? void 0 : _o.video_url;
1136
1237
  if (!videoUrl) {
1137
1238
  throw new import_provider4.AISDKError({
1138
1239
  name: "ALIBABA_VIDEO_GENERATION_ERROR",
@@ -1157,7 +1258,7 @@ var AlibabaVideoModel = class {
1157
1258
  alibaba: {
1158
1259
  taskId,
1159
1260
  videoUrl,
1160
- ...((_n = finalResponse == null ? void 0 : finalResponse.output) == null ? void 0 : _n.actual_prompt) ? { actualPrompt: finalResponse.output.actual_prompt } : {},
1261
+ ...((_p = finalResponse == null ? void 0 : finalResponse.output) == null ? void 0 : _p.actual_prompt) ? { actualPrompt: finalResponse.output.actual_prompt } : {},
1161
1262
  ...(finalResponse == null ? void 0 : finalResponse.usage) ? {
1162
1263
  usage: {
1163
1264
  duration: finalResponse.usage.duration,
@@ -1173,7 +1274,7 @@ var AlibabaVideoModel = class {
1173
1274
  };
1174
1275
 
1175
1276
  // src/version.ts
1176
- var VERSION = true ? "1.0.34" : "0.0.0-test";
1277
+ var VERSION = true ? "1.0.36" : "0.0.0-test";
1177
1278
 
1178
1279
  // src/alibaba-provider.ts
1179
1280
  function createAlibaba(options = {}) {