@shop-os/modelkit 0.3.2 → 0.3.3

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
@@ -33,6 +33,7 @@ var index_exports = {};
33
33
  __export(index_exports, {
34
34
  ADAPTER_IDS: () => ADAPTER_IDS,
35
35
  ADAPTER_KEYS: () => ADAPTER_KEYS,
36
+ ARRAY_INPUT_SPEC_KEYS: () => ARRAY_INPUT_SPEC_KEYS,
36
37
  AUDIO_INPUT_SPEC_KEYS: () => AUDIO_INPUT_SPEC_KEYS,
37
38
  Catalog: () => Catalog,
38
39
  CatalogModelSchema: () => CatalogModelSchema,
@@ -75,6 +76,7 @@ __export(index_exports, {
75
76
  googleImageAdapter: () => googleImageAdapter,
76
77
  hasAwsCredentials: () => hasAwsCredentials,
77
78
  higgsfieldAdapter: () => higgsfieldAdapter,
79
+ isArrayInputSpecKey: () => isArrayInputSpecKey,
78
80
  isInputSpecKey: () => isInputSpecKey,
79
81
  isListed: () => isListed,
80
82
  isListedOn: () => isListedOn,
@@ -2355,7 +2357,8 @@ var VIDEO_INPUT_SPEC_KEYS = [
2355
2357
  "generateAudio",
2356
2358
  "cfgScale",
2357
2359
  "promptExpansion",
2358
- "referenceImages"
2360
+ "referenceImages",
2361
+ "sourceVideo"
2359
2362
  ];
2360
2363
  var IMAGE_INPUT_SPEC_KEYS = [
2361
2364
  "prompt",
@@ -2374,6 +2377,12 @@ var AUDIO_INPUT_SPEC_KEYS = [
2374
2377
  "sourceVideo",
2375
2378
  "instrumental"
2376
2379
  ];
2380
+ var ARRAY_INPUT_SPEC_KEYS = [
2381
+ "firstFrame",
2382
+ "referenceImages",
2383
+ "lastFrame",
2384
+ "references"
2385
+ ];
2377
2386
  var INPUT_SPEC_SUPPORTS_KEYS = [
2378
2387
  "lastFrame",
2379
2388
  "seed",
@@ -2387,6 +2396,7 @@ var INPUT_SPEC_SUPPORTS_KEYS = [
2387
2396
  var VIDEO_KEY_SET = new Set(VIDEO_INPUT_SPEC_KEYS);
2388
2397
  var IMAGE_KEY_SET = new Set(IMAGE_INPUT_SPEC_KEYS);
2389
2398
  var AUDIO_KEY_SET = new Set(AUDIO_INPUT_SPEC_KEYS);
2399
+ var ARRAY_KEY_SET = new Set(ARRAY_INPUT_SPEC_KEYS);
2390
2400
  var ALL_KEY_SET = /* @__PURE__ */ new Set([
2391
2401
  ...VIDEO_INPUT_SPEC_KEYS,
2392
2402
  ...IMAGE_INPUT_SPEC_KEYS,
@@ -2431,13 +2441,30 @@ var ValuesSchema = import_zod2.z.record(import_zod2.z.string(), import_zod2.z.re
2431
2441
  }
2432
2442
  });
2433
2443
  var StaticSchema = import_zod2.z.record(import_zod2.z.string(), ProviderScalarSchema);
2444
+ var ArraysSchema = import_zod2.z.record(import_zod2.z.string().min(1), import_zod2.z.array(import_zod2.z.string()).min(1)).superRefine((arrays, ctx) => {
2445
+ for (const [name, keys] of Object.entries(arrays)) {
2446
+ for (const key of keys) {
2447
+ if (!ARRAY_KEY_SET.has(key)) {
2448
+ ctx.addIssue({
2449
+ code: "custom",
2450
+ path: [name],
2451
+ message: `inputSpec.arrays "${name}" has unknown image key "${key}"`
2452
+ });
2453
+ }
2454
+ }
2455
+ }
2456
+ });
2434
2457
  var InputSpecSchema = import_zod2.z.strictObject({
2435
2458
  fields: FieldsSchema,
2436
2459
  values: ValuesSchema.optional(),
2437
2460
  static: StaticSchema.optional(),
2461
+ arrays: ArraysSchema.optional(),
2438
2462
  editEndpoint: import_zod2.z.string().min(1).optional()
2439
2463
  }).superRefine((spec, ctx) => {
2440
- const mappedNames = new Set(Object.values(spec.fields));
2464
+ const mappedNames = /* @__PURE__ */ new Set([
2465
+ ...Object.values(spec.fields),
2466
+ ...Object.keys(spec.arrays ?? {})
2467
+ ]);
2441
2468
  for (const key of Object.keys(spec.static ?? {})) {
2442
2469
  if (mappedNames.has(key)) {
2443
2470
  ctx.addIssue({
@@ -2451,6 +2478,9 @@ var InputSpecSchema = import_zod2.z.strictObject({
2451
2478
  function isInputSpecKey(key) {
2452
2479
  return ALL_KEY_SET.has(key);
2453
2480
  }
2481
+ function isArrayInputSpecKey(key) {
2482
+ return ARRAY_KEY_SET.has(key);
2483
+ }
2454
2484
  function validateInputSpec(raw, row) {
2455
2485
  const parsed = InputSpecSchema.safeParse(raw);
2456
2486
  if (!parsed.success) {
@@ -2529,14 +2559,54 @@ function validateInputSpec(raw, row) {
2529
2559
  });
2530
2560
  }
2531
2561
  }
2562
+ const arrayOwner = /* @__PURE__ */ new Map();
2563
+ for (const [name, keys] of Object.entries(spec.arrays ?? {})) {
2564
+ const fieldKey = seenNames.get(name);
2565
+ if (fieldKey !== void 0) {
2566
+ issues.push({
2567
+ path: ["arrays", name],
2568
+ message: `inputSpec.arrays "${name}" is also the provider field of inputSpec.fields "${fieldKey}"`
2569
+ });
2570
+ }
2571
+ for (const key of keys) {
2572
+ if (allowed !== void 0 && !allowed.has(key)) {
2573
+ issues.push({
2574
+ path: ["arrays", name],
2575
+ message: `inputSpec.arrays "${key}" is not supported for ${row.type} rows`
2576
+ });
2577
+ }
2578
+ if (key in spec.fields) {
2579
+ issues.push({
2580
+ path: ["arrays", name],
2581
+ message: `inputSpec.arrays "${key}" is already mapped in inputSpec.fields`
2582
+ });
2583
+ }
2584
+ const owner = arrayOwner.get(key);
2585
+ if (owner === void 0) arrayOwner.set(key, name);
2586
+ else {
2587
+ issues.push({
2588
+ path: ["arrays", name],
2589
+ message: owner === name ? `inputSpec.arrays "${name}" lists "${key}" twice` : `inputSpec.arrays "${owner}" and "${name}" both take "${key}"`
2590
+ });
2591
+ }
2592
+ }
2593
+ }
2532
2594
  const supports = row.constraints.supports ?? [];
2533
2595
  for (const key of INPUT_SPEC_SUPPORTS_KEYS) {
2534
- if (key in spec.fields && !supports.includes(key)) {
2596
+ if (supports.includes(key)) continue;
2597
+ if (key in spec.fields) {
2535
2598
  issues.push({
2536
2599
  path: ["fields", key],
2537
2600
  message: `inputSpec.fields "${key}" needs "${key}" in constraints.supports`
2538
2601
  });
2539
2602
  }
2603
+ const arrayName = arrayOwner.get(key);
2604
+ if (arrayName !== void 0) {
2605
+ issues.push({
2606
+ path: ["arrays", arrayName],
2607
+ message: `inputSpec.arrays "${key}" needs "${key}" in constraints.supports`
2608
+ });
2609
+ }
2540
2610
  }
2541
2611
  if (issues.length > 0) return { ok: false, issues };
2542
2612
  return { ok: true, spec };
@@ -2758,6 +2828,7 @@ var CatalogCapabilitiesSchema = import_zod3.z.looseObject({
2758
2828
  acceptsSourceVideo: import_zod3.z.boolean().optional(),
2759
2829
  videoEdit: import_zod3.z.boolean().optional(),
2760
2830
  framesExcludeReferences: import_zod3.z.boolean().optional(),
2831
+ sourceVideoExcludesFrames: import_zod3.z.boolean().optional(),
2761
2832
  lastFrameRequiresFirstFrame: import_zod3.z.boolean().optional(),
2762
2833
  reasoning: import_zod3.z.boolean().optional(),
2763
2834
  vision: import_zod3.z.boolean().optional(),
@@ -4285,6 +4356,17 @@ function applyInputSpec(spec, req, refToUrl2, opts) {
4285
4356
  const mapped = spec.values?.[canonical]?.[String(value)];
4286
4357
  out[providerField] = mapped ?? serialised;
4287
4358
  }
4359
+ for (const [providerField, keys] of Object.entries(spec.arrays ?? {})) {
4360
+ const urls = [];
4361
+ for (const key of keys) {
4362
+ if (!isArrayInputSpecKey(key)) continue;
4363
+ const value = canonicalValue(req, key);
4364
+ if (value === void 0) continue;
4365
+ if (Array.isArray(value)) urls.push(...value.map(refToUrl2));
4366
+ else if (isMediaRef(value)) urls.push(refToUrl2(value));
4367
+ }
4368
+ if (urls.length > 0) out[providerField] = urls;
4369
+ }
4288
4370
  for (const [key, value] of Object.entries(spec.static ?? {})) {
4289
4371
  out[key] = value;
4290
4372
  }
@@ -8404,6 +8486,26 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
8404
8486
  });
8405
8487
  delete merged.sourceVideo;
8406
8488
  }
8489
+ const imageInputs = ["firstFrame", "lastFrame", "referenceImages"].filter(
8490
+ (field) => field === "referenceImages" ? compact(merged.referenceImages).length > 0 : merged[field] !== void 0
8491
+ );
8492
+ if (merged.sourceVideo !== void 0 && imageInputs.length > 0 && model.capabilities?.sourceVideoExcludesFrames) {
8493
+ if (onUnsupported === "error") {
8494
+ throw new ModelKitError({
8495
+ code: "unsupported_option",
8496
+ message: `${model.id} takes a source video or images, not both`,
8497
+ model: model.id
8498
+ });
8499
+ }
8500
+ for (const field of imageInputs) {
8501
+ warnings.push({
8502
+ code: "option_ignored",
8503
+ field,
8504
+ message: `${model.id} takes a source video or images, not both; ${field} dropped`
8505
+ });
8506
+ delete merged[field];
8507
+ }
8508
+ }
8407
8509
  if (merged.lastFrame !== void 0 && merged.firstFrame === void 0 && model.capabilities?.lastFrameRequiresFirstFrame) {
8408
8510
  if (onUnsupported === "error") {
8409
8511
  throw new ModelKitError({
@@ -9514,6 +9616,7 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
9514
9616
  0 && (module.exports = {
9515
9617
  ADAPTER_IDS,
9516
9618
  ADAPTER_KEYS,
9619
+ ARRAY_INPUT_SPEC_KEYS,
9517
9620
  AUDIO_INPUT_SPEC_KEYS,
9518
9621
  Catalog,
9519
9622
  CatalogModelSchema,
@@ -9556,6 +9659,7 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
9556
9659
  googleImageAdapter,
9557
9660
  hasAwsCredentials,
9558
9661
  higgsfieldAdapter,
9662
+ isArrayInputSpecKey,
9559
9663
  isInputSpecKey,
9560
9664
  isListed,
9561
9665
  isListedOn,