@shop-os/modelkit 0.7.3 → 0.7.6

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
@@ -9,6 +9,20 @@ header in the release PR.
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [0.7.6] - Unreleased
13
+
14
+ ENG-3323: one xAI reference-mode rule.
15
+
16
+ ### Changed
17
+ - `xaiReferenceResolution` (kit-internal) now owns "is this request in xAI reference mode" and the 720p cap for both the resolver and the `xai-video` adapter. The adapter no longer keeps its own reference-mode check or its own copy of the refuse/lower rule. Requests, refusals and warnings are unchanged.
18
+
19
+ ## [0.7.4] - Unreleased
20
+
21
+ ENG-3321: one source of truth for each 3D family's options.
22
+
23
+ ### Changed
24
+ - The 3D family rules (`MODEL3D_FAMILY_RULES`, `model3dSpecIssues`) move from the catalog schema to `catalog/model3d-spec.ts`. Each family's texture and resolution options are now a map to the value the fal request sends (Hi3D `quality`/`master` to `2048quality`/`2048master`; Tripo `texture_quality`; Hunyuan `generate_type`; Meshy's text `mode`; Hi3D `enable_texture`). The catalog check allows only the map's keys and `model3dCall` sends its values, so an option cannot be offered without a value to send. An option missing from the map (only possible on an unvalidated `catalogOverride` row) now fails with `unsupported_option` instead of being sent as the family's default. Every request the current rows can make sends the same body as before.
25
+
12
26
  ## [0.7.3] - Unreleased
13
27
 
14
28
  ENG-3272 Luma code review follow-ups.
package/dist/catalog.cjs CHANGED
@@ -6401,14 +6401,14 @@ function xaiReferenceMode(model, req) {
6401
6401
  const takesLastFrame = (model.constraints.supports ?? []).includes("lastFrame");
6402
6402
  return (req.referenceImages ?? []).length > 0 || takesLastFrame && req.lastFrame !== void 0;
6403
6403
  }
6404
- function applyXaiVideoRules(model, req, onUnsupported, warnings) {
6405
- if (model.adapter !== "xai-video" || req.resolution !== "1080p") return;
6406
- if (!xaiReferenceMode(model, req)) return;
6404
+ function xaiReferenceResolution(model, req, onUnsupported, warnings, provider) {
6405
+ if (req.resolution !== "1080p" || !xaiReferenceMode(model, req)) return void 0;
6407
6406
  const message = xaiReferenceResolutionMessage(model.id);
6408
6407
  if (onUnsupported === "error") {
6409
6408
  throw new ModelKitError({
6410
6409
  code: "unsupported_option",
6411
6410
  message,
6411
+ ...provider === void 0 ? {} : { provider },
6412
6412
  model: model.id,
6413
6413
  retryable: false
6414
6414
  });
@@ -6420,7 +6420,12 @@ function applyXaiVideoRules(model, req, onUnsupported, warnings) {
6420
6420
  to: XAI_REFERENCE_MAX_RESOLUTION,
6421
6421
  message
6422
6422
  });
6423
- req.resolution = XAI_REFERENCE_MAX_RESOLUTION;
6423
+ return XAI_REFERENCE_MAX_RESOLUTION;
6424
+ }
6425
+ function applyXaiVideoRules(model, req, onUnsupported, warnings) {
6426
+ if (model.adapter !== "xai-video") return;
6427
+ const lowered = xaiReferenceResolution(model, req, onUnsupported, warnings);
6428
+ if (lowered !== void 0) req.resolution = lowered;
6424
6429
  }
6425
6430
  function takesTargetAspectRatio(model) {
6426
6431
  const ratios = model.constraints.aspectRatios ?? [];
@@ -6633,6 +6638,161 @@ var MODEL3D_IMAGE_SLOTS = {
6633
6638
  ordered: ["image", "left", "back", "right"],
6634
6639
  unordered: ["image", "back", "left", "right", "top"]
6635
6640
  };
6641
+ var MODEL3D_FAMILY_RULES = {
6642
+ trellis: {
6643
+ textPath: false,
6644
+ views: ["none"],
6645
+ multiImage: false,
6646
+ texture: null,
6647
+ pbr: false,
6648
+ seed: true,
6649
+ textureRef: false,
6650
+ resolutions: "integer"
6651
+ },
6652
+ hunyuan: {
6653
+ textPath: true,
6654
+ views: ["none", "named"],
6655
+ multiImage: false,
6656
+ // generate_type
6657
+ texture: { none: "Geometry", standard: "Normal" },
6658
+ pbr: true,
6659
+ seed: false,
6660
+ textureRef: false,
6661
+ resolutions: null
6662
+ },
6663
+ tripo: {
6664
+ textPath: true,
6665
+ views: ["none", "ordered"],
6666
+ multiImage: true,
6667
+ // texture_quality; null sends an untextured model.
6668
+ texture: { none: null, standard: "standard", detailed: "detailed" },
6669
+ pbr: true,
6670
+ seed: true,
6671
+ textureRef: false,
6672
+ resolutions: null
6673
+ },
6674
+ rodin: {
6675
+ textPath: true,
6676
+ views: ["none", "unordered"],
6677
+ multiImage: false,
6678
+ texture: null,
6679
+ pbr: false,
6680
+ seed: true,
6681
+ textureRef: false,
6682
+ resolutions: null
6683
+ },
6684
+ meshy: {
6685
+ textPath: true,
6686
+ views: ["none", "unordered"],
6687
+ multiImage: true,
6688
+ // The text endpoint's mode; the image endpoints take should_texture.
6689
+ texture: { none: "preview", standard: "full" },
6690
+ pbr: true,
6691
+ seed: true,
6692
+ textureRef: true,
6693
+ resolutions: null
6694
+ },
6695
+ hi3d: {
6696
+ textPath: false,
6697
+ views: ["none", "named"],
6698
+ multiImage: true,
6699
+ // enable_texture
6700
+ texture: { none: false, standard: true },
6701
+ pbr: true,
6702
+ seed: false,
6703
+ textureRef: false,
6704
+ resolutions: { quality: "2048quality", master: "2048master" }
6705
+ },
6706
+ sam: {
6707
+ textPath: false,
6708
+ views: ["none"],
6709
+ multiImage: false,
6710
+ texture: null,
6711
+ pbr: false,
6712
+ seed: true,
6713
+ textureRef: false,
6714
+ resolutions: null
6715
+ }
6716
+ };
6717
+ function model3dSpecIssues(spec) {
6718
+ const issues = [];
6719
+ const add = (path, message) => issues.push({ path, message });
6720
+ const rules = MODEL3D_FAMILY_RULES[spec.family];
6721
+ const promptOnly = spec.text && !spec.imageRequired;
6722
+ if (spec.endpoints.image === void 0)
6723
+ add(["endpoints", "image"], "every row needs an image endpoint");
6724
+ if (promptOnly && !rules.textPath) {
6725
+ add(
6726
+ ["imageRequired"],
6727
+ `${spec.family} has no text-to-3D endpoint; a text row needs an image`
6728
+ );
6729
+ }
6730
+ if (promptOnly && spec.endpoints.text === void 0) {
6731
+ add(["endpoints", "text"], "a text row needs a text endpoint");
6732
+ }
6733
+ if (!rules.views.includes(spec.views)) {
6734
+ add(["views"], `${spec.family} takes views ${rules.views.join(" or ")}`);
6735
+ }
6736
+ if (spec.views === "none" && spec.maxImages !== 1) {
6737
+ add(["maxImages"], "a row without views takes 1 image");
6738
+ }
6739
+ if (spec.views === "unordered" && spec.maxImages < 2) {
6740
+ add(["maxImages"], "a row with views takes at least 2 images");
6741
+ }
6742
+ const slots = MODEL3D_IMAGE_SLOTS[spec.views].length;
6743
+ if (spec.views !== "none" && spec.maxImages > slots) {
6744
+ add(["maxImages"], `a row with ${spec.views} views sends at most ${slots} images`);
6745
+ }
6746
+ if ((spec.views === "named" || spec.views === "ordered") && spec.maxImages < slots) {
6747
+ add(
6748
+ ["maxImages"],
6749
+ `a row with ${spec.views} views takes ${slots} images (front and three sides)`
6750
+ );
6751
+ }
6752
+ if (spec.views !== "none" && rules.multiImage && spec.endpoints.multiImage === void 0) {
6753
+ add(["endpoints", "multiImage"], `${spec.family} sends views to a multi-image endpoint`);
6754
+ }
6755
+ if (rules.texture === null) {
6756
+ if (spec.texture.length > 0) add(["texture"], `${spec.family} has no texture switch`);
6757
+ } else {
6758
+ const allowed = rules.texture;
6759
+ if (spec.texture.length === 0) add(["texture"], `${spec.family} needs its texture options`);
6760
+ if (new Set(spec.texture).size !== spec.texture.length)
6761
+ add(["texture"], "texture options repeat");
6762
+ for (const t of spec.texture) {
6763
+ if (!Object.hasOwn(allowed, t))
6764
+ add(["texture"], `${spec.family} has no "${t}" texture`);
6765
+ }
6766
+ }
6767
+ if (spec.pbr && !rules.pbr) add(["pbr"], `${spec.family} has no PBR switch`);
6768
+ if (spec.pbr && !spec.texture.some((t) => t !== "none")) {
6769
+ add(["pbr"], "PBR needs a textured option");
6770
+ }
6771
+ if (spec.seed && !rules.seed) add(["seed"], `${spec.family} takes no seed`);
6772
+ if (spec.seedMax !== void 0 && !spec.seed) add(["seedMax"], "seedMax needs seed");
6773
+ if (spec.textureRef && !rules.textureRef)
6774
+ add(["textureRef"], `${spec.family} takes no texture reference`);
6775
+ const res = spec.resolutions;
6776
+ if (rules.resolutions === null) {
6777
+ if (res !== void 0) add(["resolutions"], `${spec.family} has no resolution option`);
6778
+ } else if (res === void 0) {
6779
+ add(["resolutions"], `${spec.family} needs its resolution options`);
6780
+ } else {
6781
+ if (!res.options.includes(res.default)) {
6782
+ add(["resolutions", "default"], "default must be an option");
6783
+ }
6784
+ if (new Set(res.options).size !== res.options.length) {
6785
+ add(["resolutions", "options"], "resolution options repeat");
6786
+ }
6787
+ const allowed = rules.resolutions;
6788
+ for (const option of res.options) {
6789
+ const ok = allowed === "integer" ? /^[1-9][0-9]*$/.test(option) : Object.hasOwn(allowed, option);
6790
+ if (!ok)
6791
+ add(["resolutions", "options"], `${spec.family} has no "${option}" resolution`);
6792
+ }
6793
+ }
6794
+ return issues;
6795
+ }
6636
6796
  function model3dInputRefusal(spec, wired) {
6637
6797
  const top = spec.views === "unordered" && wired.top === true;
6638
6798
  const anyView = spec.views !== "none" && (wired.back || wired.left || wired.right || top);
@@ -7214,156 +7374,6 @@ var LanguageOptionSchema = import_zod3.z.looseObject({
7214
7374
  code: import_zod3.z.string().min(1),
7215
7375
  name: import_zod3.z.string().min(1)
7216
7376
  });
7217
- var MODEL3D_FAMILY_RULES = {
7218
- trellis: {
7219
- textPath: false,
7220
- views: ["none"],
7221
- multiImage: false,
7222
- texture: null,
7223
- pbr: false,
7224
- seed: true,
7225
- textureRef: false,
7226
- resolutions: "integer"
7227
- },
7228
- hunyuan: {
7229
- textPath: true,
7230
- views: ["none", "named"],
7231
- multiImage: false,
7232
- texture: ["none", "standard"],
7233
- pbr: true,
7234
- seed: false,
7235
- textureRef: false,
7236
- resolutions: null
7237
- },
7238
- tripo: {
7239
- textPath: true,
7240
- views: ["none", "ordered"],
7241
- multiImage: true,
7242
- texture: ["none", "standard", "detailed"],
7243
- pbr: true,
7244
- seed: true,
7245
- textureRef: false,
7246
- resolutions: null
7247
- },
7248
- rodin: {
7249
- textPath: true,
7250
- views: ["none", "unordered"],
7251
- multiImage: false,
7252
- texture: null,
7253
- pbr: false,
7254
- seed: true,
7255
- textureRef: false,
7256
- resolutions: null
7257
- },
7258
- meshy: {
7259
- textPath: true,
7260
- views: ["none", "unordered"],
7261
- multiImage: true,
7262
- texture: ["none", "standard"],
7263
- pbr: true,
7264
- seed: true,
7265
- textureRef: true,
7266
- resolutions: null
7267
- },
7268
- hi3d: {
7269
- textPath: false,
7270
- views: ["none", "named"],
7271
- multiImage: true,
7272
- texture: ["none", "standard"],
7273
- pbr: true,
7274
- seed: false,
7275
- textureRef: false,
7276
- resolutions: ["quality", "master"]
7277
- },
7278
- sam: {
7279
- textPath: false,
7280
- views: ["none"],
7281
- multiImage: false,
7282
- texture: null,
7283
- pbr: false,
7284
- seed: true,
7285
- textureRef: false,
7286
- resolutions: null
7287
- }
7288
- };
7289
- function model3dSpecIssues(spec) {
7290
- const issues = [];
7291
- const add = (path, message) => issues.push({ path, message });
7292
- const rules = MODEL3D_FAMILY_RULES[spec.family];
7293
- const promptOnly = spec.text && !spec.imageRequired;
7294
- if (spec.endpoints.image === void 0)
7295
- add(["endpoints", "image"], "every row needs an image endpoint");
7296
- if (promptOnly && !rules.textPath) {
7297
- add(
7298
- ["imageRequired"],
7299
- `${spec.family} has no text-to-3D endpoint; a text row needs an image`
7300
- );
7301
- }
7302
- if (promptOnly && spec.endpoints.text === void 0) {
7303
- add(["endpoints", "text"], "a text row needs a text endpoint");
7304
- }
7305
- if (!rules.views.includes(spec.views)) {
7306
- add(["views"], `${spec.family} takes views ${rules.views.join(" or ")}`);
7307
- }
7308
- if (spec.views === "none" && spec.maxImages !== 1) {
7309
- add(["maxImages"], "a row without views takes 1 image");
7310
- }
7311
- if (spec.views === "unordered" && spec.maxImages < 2) {
7312
- add(["maxImages"], "a row with views takes at least 2 images");
7313
- }
7314
- const slots = MODEL3D_IMAGE_SLOTS[spec.views].length;
7315
- if (spec.views !== "none" && spec.maxImages > slots) {
7316
- add(["maxImages"], `a row with ${spec.views} views sends at most ${slots} images`);
7317
- }
7318
- if ((spec.views === "named" || spec.views === "ordered") && spec.maxImages < slots) {
7319
- add(
7320
- ["maxImages"],
7321
- `a row with ${spec.views} views takes ${slots} images (front and three sides)`
7322
- );
7323
- }
7324
- if (spec.views !== "none" && rules.multiImage && spec.endpoints.multiImage === void 0) {
7325
- add(["endpoints", "multiImage"], `${spec.family} sends views to a multi-image endpoint`);
7326
- }
7327
- if (rules.texture === null) {
7328
- if (spec.texture.length > 0) add(["texture"], `${spec.family} has no texture switch`);
7329
- } else {
7330
- const allowed = rules.texture;
7331
- if (spec.texture.length === 0) add(["texture"], `${spec.family} needs its texture options`);
7332
- if (new Set(spec.texture).size !== spec.texture.length)
7333
- add(["texture"], "texture options repeat");
7334
- for (const t of spec.texture) {
7335
- if (!allowed.includes(t)) add(["texture"], `${spec.family} has no "${t}" texture`);
7336
- }
7337
- }
7338
- if (spec.pbr && !rules.pbr) add(["pbr"], `${spec.family} has no PBR switch`);
7339
- if (spec.pbr && !spec.texture.some((t) => t !== "none")) {
7340
- add(["pbr"], "PBR needs a textured option");
7341
- }
7342
- if (spec.seed && !rules.seed) add(["seed"], `${spec.family} takes no seed`);
7343
- if (spec.seedMax !== void 0 && !spec.seed) add(["seedMax"], "seedMax needs seed");
7344
- if (spec.textureRef && !rules.textureRef)
7345
- add(["textureRef"], `${spec.family} takes no texture reference`);
7346
- const res = spec.resolutions;
7347
- if (rules.resolutions === null) {
7348
- if (res !== void 0) add(["resolutions"], `${spec.family} has no resolution option`);
7349
- } else if (res === void 0) {
7350
- add(["resolutions"], `${spec.family} needs its resolution options`);
7351
- } else {
7352
- if (!res.options.includes(res.default)) {
7353
- add(["resolutions", "default"], "default must be an option");
7354
- }
7355
- if (new Set(res.options).size !== res.options.length) {
7356
- add(["resolutions", "options"], "resolution options repeat");
7357
- }
7358
- const allowed = rules.resolutions;
7359
- for (const option of res.options) {
7360
- const ok = allowed === "integer" ? /^[1-9][0-9]*$/.test(option) : allowed.includes(option);
7361
- if (!ok)
7362
- add(["resolutions", "options"], `${spec.family} has no "${option}" resolution`);
7363
- }
7364
- }
7365
- return issues;
7366
- }
7367
7377
  var VideoToolConstraintsSchema = import_zod3.z.looseObject({
7368
7378
  kind: import_zod3.z.enum(["upscale", "interpolate", "hdr", "bg-remove", "subtitles"]),
7369
7379
  upscaleFactor: RangeSchema.optional(),