@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.cjs CHANGED
@@ -341,35 +341,43 @@ var IMAGE_MODELS = [
341
341
  GEMINI_PROMPT_MAX_CHARS,
342
342
  NANO_BANANA_2_1_RATIOS
343
343
  ),
344
- geminiImage(
345
- "gemini-3-pro-image-preview",
346
- "Nano Banana Pro",
347
- ["nb-pro"],
348
- ["1K", "2K", "4K"],
349
- {
350
- provider: "google",
351
- description: "Create stunning, production-quality visuals with exceptional realism, detail, and typography. Best for campaigns, e-commerce, product photography, and hero creatives.",
352
- logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
353
- },
354
- ["cowork", "space_builder"],
355
- { images: 14 },
356
- GEMINI_PROMPT_MAX_CHARS
357
- ),
358
- geminiImage(
359
- "gemini-3.1-flash-image-preview",
360
- "Nano Banana 2",
361
- ["nb-2"],
362
- // Flash 3.1 is the only Gemini image model with the 512 tier.
363
- ["512", "1K", "2K", "4K"],
364
- {
365
- provider: "google",
366
- description: "Generate high-quality images at speed. Perfect for brainstorming, concept boards, concept testing, creative exploration, and large batch workflows.",
367
- logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
368
- },
369
- ["cowork", "space_builder"],
370
- { images: 14 },
371
- GEMINI_PROMPT_MAX_CHARS
372
- ),
344
+ // Google retired the -preview endpoints for the GA ids; the catalog ids stay because they
345
+ // are pricing keys and stored model ids.
346
+ {
347
+ ...geminiImage(
348
+ "gemini-3-pro-image-preview",
349
+ "Nano Banana Pro",
350
+ ["nb-pro"],
351
+ ["1K", "2K", "4K"],
352
+ {
353
+ provider: "google",
354
+ description: "Create stunning, production-quality visuals with exceptional realism, detail, and typography. Best for campaigns, e-commerce, product photography, and hero creatives.",
355
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
356
+ },
357
+ ["cowork", "space_builder"],
358
+ { images: 14 },
359
+ GEMINI_PROMPT_MAX_CHARS
360
+ ),
361
+ providerModelId: "gemini-3-pro-image"
362
+ },
363
+ {
364
+ ...geminiImage(
365
+ "gemini-3.1-flash-image-preview",
366
+ "Nano Banana 2",
367
+ ["nb-2"],
368
+ // Flash 3.1 is the only Gemini image model with the 512 tier.
369
+ ["512", "1K", "2K", "4K"],
370
+ {
371
+ provider: "google",
372
+ description: "Generate high-quality images at speed. Perfect for brainstorming, concept boards, concept testing, creative exploration, and large batch workflows.",
373
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
374
+ },
375
+ ["cowork", "space_builder"],
376
+ { images: 14 },
377
+ GEMINI_PROMPT_MAX_CHARS
378
+ ),
379
+ providerModelId: "gemini-3.1-flash-image"
380
+ },
373
381
  geminiImage(
374
382
  "gemini-3.1-flash-lite-image",
375
383
  "Nano Banana Lite",
@@ -1489,6 +1497,7 @@ var OMNI_RATIOS = ["16:9", "9:16"];
1489
1497
  var GROK_RATIOS = ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"];
1490
1498
  var H3_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"];
1491
1499
  var H3_REFERENCE_RATIOS = ["adaptive", ...H3_RATIOS];
1500
+ var WAN_RATIOS = ["adaptive", "16:9", "4:3", "1:1", "3:4", "9:16"];
1492
1501
  var NEGATIVE_PROMPT = "blur, distort, and low quality";
1493
1502
  var FRAMES_EXCLUDE_REFERENCES = { framesExcludeReferences: true };
1494
1503
  var KLING_PROMPT = { referenceSyntax: "numbered", maxChars: 2500 };
@@ -1499,10 +1508,12 @@ var SEEDANCE_2_AUDIO = {
1499
1508
  audioMaxBytes: 15 * 1024 * 1024
1500
1509
  };
1501
1510
  var H3_PROMPT = { referenceSyntax: "numbered", maxChars: 5e4 };
1511
+ var WAN_PROMPT = { referenceSyntax: "numbered", maxChars: 2e4 };
1502
1512
  var OMNI_PROMPT = { referenceSyntax: "caption", maxChars: 5e4 };
1503
1513
  var BYTEDANCE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/3bba5d81-4e57-4e71-911b-cdfa05acca2c_compressed.png";
1504
1514
  var GOOGLE_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
1505
1515
  var VIDEO_MODELS = [
1516
+ // Google shuts down the Veo 3.1 previews and Omni Flash 1.0 on 2026-10-22.
1506
1517
  {
1507
1518
  id: "veo-3.1",
1508
1519
  aliases: [
@@ -1515,8 +1526,9 @@ var VIDEO_MODELS = [
1515
1526
  type: "video",
1516
1527
  adapter: "google-genai",
1517
1528
  providerModelId: "veo-3.1-generate-preview",
1518
- lifecycle: "active",
1519
- exposure: ["cowork", "space_builder"],
1529
+ lifecycle: "deprecated",
1530
+ replacedBy: "gemini-omni-1.1-flash",
1531
+ exposure: [],
1520
1532
  constraints: {
1521
1533
  aspectRatios: [...OMNI_RATIOS],
1522
1534
  resolutions: ["720p", "1080p", "4k"],
@@ -1551,7 +1563,8 @@ var VIDEO_MODELS = [
1551
1563
  type: "video",
1552
1564
  adapter: "google-genai",
1553
1565
  providerModelId: "veo-3.1-fast-generate-preview",
1554
- lifecycle: "active",
1566
+ lifecycle: "deprecated",
1567
+ replacedBy: "gemini-omni-1.1-flash",
1555
1568
  exposure: [],
1556
1569
  constraints: {
1557
1570
  aspectRatios: [...OMNI_RATIOS],
@@ -1581,7 +1594,8 @@ var VIDEO_MODELS = [
1581
1594
  type: "video",
1582
1595
  adapter: "google-genai",
1583
1596
  providerModelId: "veo-3.1-lite-generate-preview",
1584
- lifecycle: "active",
1597
+ lifecycle: "deprecated",
1598
+ replacedBy: "gemini-omni-1.1-flash",
1585
1599
  exposure: [],
1586
1600
  constraints: {
1587
1601
  aspectRatios: [...OMNI_RATIOS],
@@ -1612,8 +1626,9 @@ var VIDEO_MODELS = [
1612
1626
  type: "video",
1613
1627
  adapter: "google-genai",
1614
1628
  providerModelId: "gemini-omni-flash-preview",
1615
- lifecycle: "active",
1616
- exposure: ["cowork", "space_builder"],
1629
+ lifecycle: "deprecated",
1630
+ replacedBy: "gemini-omni-1.1-flash",
1631
+ exposure: [],
1617
1632
  constraints: {
1618
1633
  // 1.0 rejects `resolution`; it renders 720p. No defaults: the adapter
1619
1634
  // sends ratio and duration only when the caller set them, so a
@@ -2099,6 +2114,48 @@ var VIDEO_MODELS = [
2099
2114
  // references instead of the adapter silently dropping the frame.
2100
2115
  capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
2101
2116
  },
2117
+ {
2118
+ // One row for fal's three Wan 3.0 endpoints; the adapter picks text-, image- or
2119
+ // reference-to-video from the inputs. Each takes aspect_ratio, so none is ignored.
2120
+ // https://fal.ai/models/alibaba/wan-3.0/reference-to-video/api
2121
+ id: "wan-3.0",
2122
+ aliases: ["wan-3", "wan3"],
2123
+ label: "Wan 3",
2124
+ type: "video",
2125
+ adapter: "fal",
2126
+ providerModelId: "alibaba/wan-3.0",
2127
+ lifecycle: "active",
2128
+ exposure: ["cowork", "space_builder"],
2129
+ constraints: {
2130
+ aspectRatios: [...WAN_RATIOS],
2131
+ resolutions: ["480p", "720p", "1080p"],
2132
+ durations: { min: 2, max: 30 },
2133
+ durationPresets: [5, 10, 15, 30],
2134
+ references: {
2135
+ images: 10,
2136
+ videos: 5,
2137
+ audios: 5,
2138
+ videoSeconds: { total: 15 },
2139
+ audioSeconds: { total: 15 }
2140
+ },
2141
+ supports: ["seed", "lastFrame", "generateAudio", "safetyChecker"],
2142
+ prompt: WAN_PROMPT,
2143
+ audio: "optional"
2144
+ },
2145
+ defaults: {
2146
+ durationSeconds: 5,
2147
+ resolution: "1080p",
2148
+ aspectRatio: "adaptive",
2149
+ generateAudio: true
2150
+ },
2151
+ usage: { ...VIDEO_USAGE },
2152
+ pricingKind: "video_per_second",
2153
+ display: {
2154
+ provider: "alibaba",
2155
+ 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."
2156
+ },
2157
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES, lastFrameRequiresFirstFrame: true }
2158
+ },
2102
2159
  {
2103
2160
  // Duration 3-10s per trigger-workflows mapDuration; the endpoint takes no resolution.
2104
2161
  id: "kling-o1-v2v",
@@ -2168,7 +2225,8 @@ var VIDEO_MODELS = [
2168
2225
  },
2169
2226
  defaults: {},
2170
2227
  usage: { ...VIDEO_USAGE },
2171
- pricingKind: "video_per_second",
2228
+ // Higgsfield bills DoP per generation: a fixed-length clip with no duration knob.
2229
+ pricingKind: "flat",
2172
2230
  display: {
2173
2231
  provider: "higgsfield",
2174
2232
  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."
@@ -4894,7 +4952,7 @@ function isMinimax(providerModelId) {
4894
4952
  return MINIMAX_MODEL_IDS.has(providerModelId.toLowerCase());
4895
4953
  }
4896
4954
  function isFalVideoKnown(providerModelId) {
4897
- return isKling(providerModelId) || isMinimax(providerModelId);
4955
+ return isKling(providerModelId) || isMinimax(providerModelId) || isWan(providerModelId);
4898
4956
  }
4899
4957
  function minimaxFamily(providerModelId) {
4900
4958
  return H3_MAX_MODEL_IDS.has(providerModelId.toLowerCase()) ? "h3-max" : "h3";
@@ -4911,6 +4969,44 @@ function minimaxBase(req, family) {
4911
4969
  if (req.seed !== void 0) input.seed = req.seed;
4912
4970
  return input;
4913
4971
  }
4972
+ var WAN_MODEL_IDS = /* @__PURE__ */ new Set(["alibaba/wan-3.0"]);
4973
+ function isWan(providerModelId) {
4974
+ return WAN_MODEL_IDS.has(providerModelId.toLowerCase());
4975
+ }
4976
+ function wanVideo(req, family) {
4977
+ const input = {
4978
+ prompt: req.prompt.trim(),
4979
+ duration: req.durationSeconds ?? 5,
4980
+ resolution: req.resolution ?? "1080p",
4981
+ aspect_ratio: req.aspectRatio ?? "adaptive",
4982
+ audio: req.generateAudio ?? true
4983
+ };
4984
+ if (req.safetyChecker !== void 0) input.enable_safety_checker = req.safetyChecker;
4985
+ if (req.seed !== void 0) input.seed = req.seed;
4986
+ const images = (req.referenceImages ?? []).map(refToUrl);
4987
+ const videos = (req.referenceVideos ?? []).map(refToUrl);
4988
+ const audios = (req.referenceAudios ?? []).map(refToUrl);
4989
+ if (images.length + videos.length + audios.length > 0) {
4990
+ if (images.length > 0) input.reference_image_urls = images;
4991
+ if (videos.length > 0) input.reference_video_urls = videos;
4992
+ if (audios.length > 0) input.reference_audio_urls = audios;
4993
+ return { endpoint: `${family}/reference-to-video`, input };
4994
+ }
4995
+ if (req.firstFrame) {
4996
+ input.start_image_url = refToUrl(req.firstFrame);
4997
+ if (req.lastFrame) input.end_image_url = refToUrl(req.lastFrame);
4998
+ return { endpoint: `${family}/image-to-video`, input };
4999
+ }
5000
+ if (req.lastFrame) {
5001
+ throw new ModelKitError({
5002
+ code: "missing_input",
5003
+ message: `${family} takes a last frame only together with a first frame`,
5004
+ provider: "fal",
5005
+ retryable: false
5006
+ });
5007
+ }
5008
+ return { endpoint: `${family}/text-to-video`, input };
5009
+ }
4914
5010
  var KLING_MODEL_IDS = /* @__PURE__ */ new Set([
4915
5011
  "fal-ai/kling-video/o1/video-to-video/reference"
4916
5012
  ]);
@@ -4966,10 +5062,17 @@ async function generateFalVideo(req, ctx, deps) {
4966
5062
  }
4967
5063
  return await submitQueueJob(ctx, req, deps, KLING_O1_ENDPOINT, input);
4968
5064
  }
5065
+ if (isWan(providerModelId)) {
5066
+ const { endpoint: endpoint2, input } = wanVideo(req, providerModelId.toLowerCase());
5067
+ if (ctx.routing.fal === "cloudflare-passthrough") {
5068
+ return await passthroughVideoJob(ctx, req, endpoint2, input);
5069
+ }
5070
+ return await submitQueueJob(ctx, req, deps, endpoint2, input);
5071
+ }
4969
5072
  if (!isMinimax(providerModelId)) {
4970
5073
  throw new ModelKitError({
4971
5074
  code: "unsupported_option",
4972
- message: `fal has no input mapper for "${providerModelId}"; add the id to KLING_MODEL_IDS or MINIMAX_MODEL_IDS`,
5075
+ message: `fal has no input mapper for "${providerModelId}"; add the id to KLING_MODEL_IDS, MINIMAX_MODEL_IDS or WAN_MODEL_IDS`,
4973
5076
  provider: "fal",
4974
5077
  model: ctx.model.id,
4975
5078
  retryable: false
@@ -8134,7 +8237,7 @@ function dataOnlyCapable(row) {
8134
8237
  }
8135
8238
  case "fal": {
8136
8239
  if (row.type === "video") {
8137
- return isFalVideoKnown(row.providerModelId) ? { ok: true } : { ok: false, reason: "fal video needs a Kling or MiniMax id" };
8240
+ return isFalVideoKnown(row.providerModelId) ? { ok: true } : { ok: false, reason: "fal video needs a Kling, MiniMax or Wan id" };
8138
8241
  }
8139
8242
  return { ok: true };
8140
8243
  }