@shop-os/modelkit 0.4.0 → 0.4.2

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/dist/index.js CHANGED
@@ -222,35 +222,43 @@ var IMAGE_MODELS = [
222
222
  GEMINI_PROMPT_MAX_CHARS,
223
223
  NANO_BANANA_2_1_RATIOS
224
224
  ),
225
- geminiImage(
226
- "gemini-3-pro-image-preview",
227
- "Nano Banana Pro",
228
- ["nb-pro"],
229
- ["1K", "2K", "4K"],
230
- {
231
- provider: "google",
232
- description: "Create stunning, production-quality visuals with exceptional realism, detail, and typography. Best for campaigns, e-commerce, product photography, and hero creatives.",
233
- logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
234
- },
235
- ["cowork", "space_builder"],
236
- { images: 14 },
237
- GEMINI_PROMPT_MAX_CHARS
238
- ),
239
- geminiImage(
240
- "gemini-3.1-flash-image-preview",
241
- "Nano Banana 2",
242
- ["nb-2"],
243
- // Flash 3.1 is the only Gemini image model with the 512 tier.
244
- ["512", "1K", "2K", "4K"],
245
- {
246
- provider: "google",
247
- description: "Generate high-quality images at speed. Perfect for brainstorming, concept boards, concept testing, creative exploration, and large batch workflows.",
248
- logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
249
- },
250
- ["cowork", "space_builder"],
251
- { images: 14 },
252
- GEMINI_PROMPT_MAX_CHARS
253
- ),
225
+ // Google retired the -preview endpoints for the GA ids; the catalog ids stay because they
226
+ // are pricing keys and stored model ids.
227
+ {
228
+ ...geminiImage(
229
+ "gemini-3-pro-image-preview",
230
+ "Nano Banana Pro",
231
+ ["nb-pro"],
232
+ ["1K", "2K", "4K"],
233
+ {
234
+ provider: "google",
235
+ description: "Create stunning, production-quality visuals with exceptional realism, detail, and typography. Best for campaigns, e-commerce, product photography, and hero creatives.",
236
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
237
+ },
238
+ ["cowork", "space_builder"],
239
+ { images: 14 },
240
+ GEMINI_PROMPT_MAX_CHARS
241
+ ),
242
+ providerModelId: "gemini-3-pro-image"
243
+ },
244
+ {
245
+ ...geminiImage(
246
+ "gemini-3.1-flash-image-preview",
247
+ "Nano Banana 2",
248
+ ["nb-2"],
249
+ // Flash 3.1 is the only Gemini image model with the 512 tier.
250
+ ["512", "1K", "2K", "4K"],
251
+ {
252
+ provider: "google",
253
+ description: "Generate high-quality images at speed. Perfect for brainstorming, concept boards, concept testing, creative exploration, and large batch workflows.",
254
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
255
+ },
256
+ ["cowork", "space_builder"],
257
+ { images: 14 },
258
+ GEMINI_PROMPT_MAX_CHARS
259
+ ),
260
+ providerModelId: "gemini-3.1-flash-image"
261
+ },
254
262
  geminiImage(
255
263
  "gemini-3.1-flash-lite-image",
256
264
  "Nano Banana Lite",
@@ -1370,6 +1378,7 @@ var OMNI_RATIOS = ["16:9", "9:16"];
1370
1378
  var GROK_RATIOS = ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"];
1371
1379
  var H3_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"];
1372
1380
  var H3_REFERENCE_RATIOS = ["adaptive", ...H3_RATIOS];
1381
+ var WAN_RATIOS = ["adaptive", "16:9", "4:3", "1:1", "3:4", "9:16"];
1373
1382
  var NEGATIVE_PROMPT = "blur, distort, and low quality";
1374
1383
  var FRAMES_EXCLUDE_REFERENCES = { framesExcludeReferences: true };
1375
1384
  var KLING_PROMPT = { referenceSyntax: "numbered", maxChars: 2500 };
@@ -1380,10 +1389,12 @@ var SEEDANCE_2_AUDIO = {
1380
1389
  audioMaxBytes: 15 * 1024 * 1024
1381
1390
  };
1382
1391
  var H3_PROMPT = { referenceSyntax: "numbered", maxChars: 5e4 };
1392
+ var WAN_PROMPT = { referenceSyntax: "numbered", maxChars: 2e4 };
1383
1393
  var OMNI_PROMPT = { referenceSyntax: "caption", maxChars: 5e4 };
1384
1394
  var BYTEDANCE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/3bba5d81-4e57-4e71-911b-cdfa05acca2c_compressed.png";
1385
1395
  var GOOGLE_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
1386
1396
  var VIDEO_MODELS = [
1397
+ // Google shuts down the Veo 3.1 previews and Omni Flash 1.0 on 2026-10-22.
1387
1398
  {
1388
1399
  id: "veo-3.1",
1389
1400
  aliases: [
@@ -1396,8 +1407,9 @@ var VIDEO_MODELS = [
1396
1407
  type: "video",
1397
1408
  adapter: "google-genai",
1398
1409
  providerModelId: "veo-3.1-generate-preview",
1399
- lifecycle: "active",
1400
- exposure: ["cowork", "space_builder"],
1410
+ lifecycle: "deprecated",
1411
+ replacedBy: "gemini-omni-1.1-flash",
1412
+ exposure: [],
1401
1413
  constraints: {
1402
1414
  aspectRatios: [...OMNI_RATIOS],
1403
1415
  resolutions: ["720p", "1080p", "4k"],
@@ -1432,7 +1444,8 @@ var VIDEO_MODELS = [
1432
1444
  type: "video",
1433
1445
  adapter: "google-genai",
1434
1446
  providerModelId: "veo-3.1-fast-generate-preview",
1435
- lifecycle: "active",
1447
+ lifecycle: "deprecated",
1448
+ replacedBy: "gemini-omni-1.1-flash",
1436
1449
  exposure: [],
1437
1450
  constraints: {
1438
1451
  aspectRatios: [...OMNI_RATIOS],
@@ -1462,7 +1475,8 @@ var VIDEO_MODELS = [
1462
1475
  type: "video",
1463
1476
  adapter: "google-genai",
1464
1477
  providerModelId: "veo-3.1-lite-generate-preview",
1465
- lifecycle: "active",
1478
+ lifecycle: "deprecated",
1479
+ replacedBy: "gemini-omni-1.1-flash",
1466
1480
  exposure: [],
1467
1481
  constraints: {
1468
1482
  aspectRatios: [...OMNI_RATIOS],
@@ -1493,8 +1507,9 @@ var VIDEO_MODELS = [
1493
1507
  type: "video",
1494
1508
  adapter: "google-genai",
1495
1509
  providerModelId: "gemini-omni-flash-preview",
1496
- lifecycle: "active",
1497
- exposure: ["cowork", "space_builder"],
1510
+ lifecycle: "deprecated",
1511
+ replacedBy: "gemini-omni-1.1-flash",
1512
+ exposure: [],
1498
1513
  constraints: {
1499
1514
  // 1.0 rejects `resolution`; it renders 720p. No defaults: the adapter
1500
1515
  // sends ratio and duration only when the caller set them, so a
@@ -1980,6 +1995,48 @@ var VIDEO_MODELS = [
1980
1995
  // references instead of the adapter silently dropping the frame.
1981
1996
  capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1982
1997
  },
1998
+ {
1999
+ // One row for fal's three Wan 3.0 endpoints; the adapter picks text-, image- or
2000
+ // reference-to-video from the inputs. Each takes aspect_ratio, so none is ignored.
2001
+ // https://fal.ai/models/alibaba/wan-3.0/reference-to-video/api
2002
+ id: "wan-3.0",
2003
+ aliases: ["wan-3", "wan3"],
2004
+ label: "Wan 3",
2005
+ type: "video",
2006
+ adapter: "fal",
2007
+ providerModelId: "alibaba/wan-3.0",
2008
+ lifecycle: "active",
2009
+ exposure: ["cowork", "space_builder"],
2010
+ constraints: {
2011
+ aspectRatios: [...WAN_RATIOS],
2012
+ resolutions: ["480p", "720p", "1080p"],
2013
+ durations: { min: 2, max: 30 },
2014
+ durationPresets: [5, 10, 15, 30],
2015
+ references: {
2016
+ images: 10,
2017
+ videos: 5,
2018
+ audios: 5,
2019
+ videoSeconds: { total: 15 },
2020
+ audioSeconds: { total: 15 }
2021
+ },
2022
+ supports: ["seed", "lastFrame", "generateAudio", "safetyChecker"],
2023
+ prompt: WAN_PROMPT,
2024
+ audio: "optional"
2025
+ },
2026
+ defaults: {
2027
+ durationSeconds: 5,
2028
+ resolution: "1080p",
2029
+ aspectRatio: "adaptive",
2030
+ generateAudio: true
2031
+ },
2032
+ usage: { ...VIDEO_USAGE },
2033
+ pricingKind: "video_per_second",
2034
+ display: {
2035
+ provider: "alibaba",
2036
+ description: "Alibaba Wan 3 video model for text-to-video, image-to-video (start/end frame), and reference-to-video from up to 10 images, 5 videos and 5 audio clips, with native audio; 2-30 seconds at up to 1080p."
2037
+ },
2038
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES, lastFrameRequiresFirstFrame: true }
2039
+ },
1983
2040
  {
1984
2041
  // Duration 3-10s per trigger-workflows mapDuration; the endpoint takes no resolution.
1985
2042
  id: "kling-o1-v2v",
@@ -2049,7 +2106,8 @@ var VIDEO_MODELS = [
2049
2106
  },
2050
2107
  defaults: {},
2051
2108
  usage: { ...VIDEO_USAGE },
2052
- pricingKind: "video_per_second",
2109
+ // Higgsfield bills DoP per generation: a fixed-length clip with no duration knob.
2110
+ pricingKind: "flat",
2053
2111
  display: {
2054
2112
  provider: "higgsfield",
2055
2113
  description: "Higgsfield DOP image-to-video model; animates a required first-frame image from a text prompt with an optional last-frame image and motion controls."
@@ -4775,7 +4833,7 @@ function isMinimax(providerModelId) {
4775
4833
  return MINIMAX_MODEL_IDS.has(providerModelId.toLowerCase());
4776
4834
  }
4777
4835
  function isFalVideoKnown(providerModelId) {
4778
- return isKling(providerModelId) || isMinimax(providerModelId);
4836
+ return isKling(providerModelId) || isMinimax(providerModelId) || isWan(providerModelId);
4779
4837
  }
4780
4838
  function minimaxFamily(providerModelId) {
4781
4839
  return H3_MAX_MODEL_IDS.has(providerModelId.toLowerCase()) ? "h3-max" : "h3";
@@ -4792,6 +4850,44 @@ function minimaxBase(req, family) {
4792
4850
  if (req.seed !== void 0) input.seed = req.seed;
4793
4851
  return input;
4794
4852
  }
4853
+ var WAN_MODEL_IDS = /* @__PURE__ */ new Set(["alibaba/wan-3.0"]);
4854
+ function isWan(providerModelId) {
4855
+ return WAN_MODEL_IDS.has(providerModelId.toLowerCase());
4856
+ }
4857
+ function wanVideo(req, family) {
4858
+ const input = {
4859
+ prompt: req.prompt.trim(),
4860
+ duration: req.durationSeconds ?? 5,
4861
+ resolution: req.resolution ?? "1080p",
4862
+ aspect_ratio: req.aspectRatio ?? "adaptive",
4863
+ audio: req.generateAudio ?? true
4864
+ };
4865
+ if (req.safetyChecker !== void 0) input.enable_safety_checker = req.safetyChecker;
4866
+ if (req.seed !== void 0) input.seed = req.seed;
4867
+ const images = (req.referenceImages ?? []).map(refToUrl);
4868
+ const videos = (req.referenceVideos ?? []).map(refToUrl);
4869
+ const audios = (req.referenceAudios ?? []).map(refToUrl);
4870
+ if (images.length + videos.length + audios.length > 0) {
4871
+ if (images.length > 0) input.reference_image_urls = images;
4872
+ if (videos.length > 0) input.reference_video_urls = videos;
4873
+ if (audios.length > 0) input.reference_audio_urls = audios;
4874
+ return { endpoint: `${family}/reference-to-video`, input };
4875
+ }
4876
+ if (req.firstFrame) {
4877
+ input.start_image_url = refToUrl(req.firstFrame);
4878
+ if (req.lastFrame) input.end_image_url = refToUrl(req.lastFrame);
4879
+ return { endpoint: `${family}/image-to-video`, input };
4880
+ }
4881
+ if (req.lastFrame) {
4882
+ throw new ModelKitError({
4883
+ code: "missing_input",
4884
+ message: `${family} takes a last frame only together with a first frame`,
4885
+ provider: "fal",
4886
+ retryable: false
4887
+ });
4888
+ }
4889
+ return { endpoint: `${family}/text-to-video`, input };
4890
+ }
4795
4891
  var KLING_MODEL_IDS = /* @__PURE__ */ new Set([
4796
4892
  "fal-ai/kling-video/o1/video-to-video/reference"
4797
4893
  ]);
@@ -4847,10 +4943,17 @@ async function generateFalVideo(req, ctx, deps) {
4847
4943
  }
4848
4944
  return await submitQueueJob(ctx, req, deps, KLING_O1_ENDPOINT, input);
4849
4945
  }
4946
+ if (isWan(providerModelId)) {
4947
+ const { endpoint: endpoint2, input } = wanVideo(req, providerModelId.toLowerCase());
4948
+ if (ctx.routing.fal === "cloudflare-passthrough") {
4949
+ return await passthroughVideoJob(ctx, req, endpoint2, input);
4950
+ }
4951
+ return await submitQueueJob(ctx, req, deps, endpoint2, input);
4952
+ }
4850
4953
  if (!isMinimax(providerModelId)) {
4851
4954
  throw new ModelKitError({
4852
4955
  code: "unsupported_option",
4853
- message: `fal has no input mapper for "${providerModelId}"; add the id to KLING_MODEL_IDS or MINIMAX_MODEL_IDS`,
4956
+ message: `fal has no input mapper for "${providerModelId}"; add the id to KLING_MODEL_IDS, MINIMAX_MODEL_IDS or WAN_MODEL_IDS`,
4854
4957
  provider: "fal",
4855
4958
  model: ctx.model.id,
4856
4959
  retryable: false
@@ -8017,7 +8120,7 @@ function dataOnlyCapable(row) {
8017
8120
  }
8018
8121
  case "fal": {
8019
8122
  if (row.type === "video") {
8020
- return isFalVideoKnown(row.providerModelId) ? { ok: true } : { ok: false, reason: "fal video needs a Kling or MiniMax id" };
8123
+ return isFalVideoKnown(row.providerModelId) ? { ok: true } : { ok: false, reason: "fal video needs a Kling, MiniMax or Wan id" };
8021
8124
  }
8022
8125
  return { ok: true };
8023
8126
  }