@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.
@@ -393,6 +393,8 @@ interface CatalogCapabilities {
393
393
  videoEdit?: boolean;
394
394
  /** Video rows: first/last frames and reference images are mutually exclusive inputs. */
395
395
  framesExcludeReferences?: boolean;
396
+ /** Video rows: a source video is never sent with first/last frames or reference images. */
397
+ sourceVideoExcludesFrames?: boolean;
396
398
  /** Video rows: a last frame is accepted only together with a first frame. */
397
399
  lastFrameRequiresFirstFrame?: boolean;
398
400
  /** Text rows. `reasoning`: the model streams reasoning the UI should surface. */
@@ -994,6 +996,7 @@ declare const CatalogModelSchemaBase: z.ZodObject<{
994
996
  acceptsSourceVideo: z.ZodOptional<z.ZodBoolean>;
995
997
  videoEdit: z.ZodOptional<z.ZodBoolean>;
996
998
  framesExcludeReferences: z.ZodOptional<z.ZodBoolean>;
999
+ sourceVideoExcludesFrames: z.ZodOptional<z.ZodBoolean>;
997
1000
  lastFrameRequiresFirstFrame: z.ZodOptional<z.ZodBoolean>;
998
1001
  reasoning: z.ZodOptional<z.ZodBoolean>;
999
1002
  vision: z.ZodOptional<z.ZodBoolean>;
package/dist/catalog.d.ts CHANGED
@@ -393,6 +393,8 @@ interface CatalogCapabilities {
393
393
  videoEdit?: boolean;
394
394
  /** Video rows: first/last frames and reference images are mutually exclusive inputs. */
395
395
  framesExcludeReferences?: boolean;
396
+ /** Video rows: a source video is never sent with first/last frames or reference images. */
397
+ sourceVideoExcludesFrames?: boolean;
396
398
  /** Video rows: a last frame is accepted only together with a first frame. */
397
399
  lastFrameRequiresFirstFrame?: boolean;
398
400
  /** Text rows. `reasoning`: the model streams reasoning the UI should surface. */
@@ -994,6 +996,7 @@ declare const CatalogModelSchemaBase: z.ZodObject<{
994
996
  acceptsSourceVideo: z.ZodOptional<z.ZodBoolean>;
995
997
  videoEdit: z.ZodOptional<z.ZodBoolean>;
996
998
  framesExcludeReferences: z.ZodOptional<z.ZodBoolean>;
999
+ sourceVideoExcludesFrames: z.ZodOptional<z.ZodBoolean>;
997
1000
  lastFrameRequiresFirstFrame: z.ZodOptional<z.ZodBoolean>;
998
1001
  reasoning: z.ZodOptional<z.ZodBoolean>;
999
1002
  vision: z.ZodOptional<z.ZodBoolean>;
package/dist/catalog.js CHANGED
@@ -2239,7 +2239,8 @@ var VIDEO_INPUT_SPEC_KEYS = [
2239
2239
  "generateAudio",
2240
2240
  "cfgScale",
2241
2241
  "promptExpansion",
2242
- "referenceImages"
2242
+ "referenceImages",
2243
+ "sourceVideo"
2243
2244
  ];
2244
2245
  var IMAGE_INPUT_SPEC_KEYS = [
2245
2246
  "prompt",
@@ -2258,6 +2259,12 @@ var AUDIO_INPUT_SPEC_KEYS = [
2258
2259
  "sourceVideo",
2259
2260
  "instrumental"
2260
2261
  ];
2262
+ var ARRAY_INPUT_SPEC_KEYS = [
2263
+ "firstFrame",
2264
+ "referenceImages",
2265
+ "lastFrame",
2266
+ "references"
2267
+ ];
2261
2268
  var INPUT_SPEC_SUPPORTS_KEYS = [
2262
2269
  "lastFrame",
2263
2270
  "seed",
@@ -2271,6 +2278,7 @@ var INPUT_SPEC_SUPPORTS_KEYS = [
2271
2278
  var VIDEO_KEY_SET = new Set(VIDEO_INPUT_SPEC_KEYS);
2272
2279
  var IMAGE_KEY_SET = new Set(IMAGE_INPUT_SPEC_KEYS);
2273
2280
  var AUDIO_KEY_SET = new Set(AUDIO_INPUT_SPEC_KEYS);
2281
+ var ARRAY_KEY_SET = new Set(ARRAY_INPUT_SPEC_KEYS);
2274
2282
  var ALL_KEY_SET = /* @__PURE__ */ new Set([
2275
2283
  ...VIDEO_INPUT_SPEC_KEYS,
2276
2284
  ...IMAGE_INPUT_SPEC_KEYS,
@@ -2315,13 +2323,30 @@ var ValuesSchema = z2.record(z2.string(), z2.record(z2.string(), ProviderScalarS
2315
2323
  }
2316
2324
  });
2317
2325
  var StaticSchema = z2.record(z2.string(), ProviderScalarSchema);
2326
+ var ArraysSchema = z2.record(z2.string().min(1), z2.array(z2.string()).min(1)).superRefine((arrays, ctx) => {
2327
+ for (const [name, keys] of Object.entries(arrays)) {
2328
+ for (const key of keys) {
2329
+ if (!ARRAY_KEY_SET.has(key)) {
2330
+ ctx.addIssue({
2331
+ code: "custom",
2332
+ path: [name],
2333
+ message: `inputSpec.arrays "${name}" has unknown image key "${key}"`
2334
+ });
2335
+ }
2336
+ }
2337
+ }
2338
+ });
2318
2339
  var InputSpecSchema = z2.strictObject({
2319
2340
  fields: FieldsSchema,
2320
2341
  values: ValuesSchema.optional(),
2321
2342
  static: StaticSchema.optional(),
2343
+ arrays: ArraysSchema.optional(),
2322
2344
  editEndpoint: z2.string().min(1).optional()
2323
2345
  }).superRefine((spec, ctx) => {
2324
- const mappedNames = new Set(Object.values(spec.fields));
2346
+ const mappedNames = /* @__PURE__ */ new Set([
2347
+ ...Object.values(spec.fields),
2348
+ ...Object.keys(spec.arrays ?? {})
2349
+ ]);
2325
2350
  for (const key of Object.keys(spec.static ?? {})) {
2326
2351
  if (mappedNames.has(key)) {
2327
2352
  ctx.addIssue({
@@ -2410,14 +2435,54 @@ function validateInputSpec(raw, row) {
2410
2435
  });
2411
2436
  }
2412
2437
  }
2438
+ const arrayOwner = /* @__PURE__ */ new Map();
2439
+ for (const [name, keys] of Object.entries(spec.arrays ?? {})) {
2440
+ const fieldKey = seenNames.get(name);
2441
+ if (fieldKey !== void 0) {
2442
+ issues.push({
2443
+ path: ["arrays", name],
2444
+ message: `inputSpec.arrays "${name}" is also the provider field of inputSpec.fields "${fieldKey}"`
2445
+ });
2446
+ }
2447
+ for (const key of keys) {
2448
+ if (allowed !== void 0 && !allowed.has(key)) {
2449
+ issues.push({
2450
+ path: ["arrays", name],
2451
+ message: `inputSpec.arrays "${key}" is not supported for ${row.type} rows`
2452
+ });
2453
+ }
2454
+ if (key in spec.fields) {
2455
+ issues.push({
2456
+ path: ["arrays", name],
2457
+ message: `inputSpec.arrays "${key}" is already mapped in inputSpec.fields`
2458
+ });
2459
+ }
2460
+ const owner = arrayOwner.get(key);
2461
+ if (owner === void 0) arrayOwner.set(key, name);
2462
+ else {
2463
+ issues.push({
2464
+ path: ["arrays", name],
2465
+ message: owner === name ? `inputSpec.arrays "${name}" lists "${key}" twice` : `inputSpec.arrays "${owner}" and "${name}" both take "${key}"`
2466
+ });
2467
+ }
2468
+ }
2469
+ }
2413
2470
  const supports = row.constraints.supports ?? [];
2414
2471
  for (const key of INPUT_SPEC_SUPPORTS_KEYS) {
2415
- if (key in spec.fields && !supports.includes(key)) {
2472
+ if (supports.includes(key)) continue;
2473
+ if (key in spec.fields) {
2416
2474
  issues.push({
2417
2475
  path: ["fields", key],
2418
2476
  message: `inputSpec.fields "${key}" needs "${key}" in constraints.supports`
2419
2477
  });
2420
2478
  }
2479
+ const arrayName = arrayOwner.get(key);
2480
+ if (arrayName !== void 0) {
2481
+ issues.push({
2482
+ path: ["arrays", arrayName],
2483
+ message: `inputSpec.arrays "${key}" needs "${key}" in constraints.supports`
2484
+ });
2485
+ }
2421
2486
  }
2422
2487
  if (issues.length > 0) return { ok: false, issues };
2423
2488
  return { ok: true, spec };
@@ -2639,6 +2704,7 @@ var CatalogCapabilitiesSchema = z3.looseObject({
2639
2704
  acceptsSourceVideo: z3.boolean().optional(),
2640
2705
  videoEdit: z3.boolean().optional(),
2641
2706
  framesExcludeReferences: z3.boolean().optional(),
2707
+ sourceVideoExcludesFrames: z3.boolean().optional(),
2642
2708
  lastFrameRequiresFirstFrame: z3.boolean().optional(),
2643
2709
  reasoning: z3.boolean().optional(),
2644
2710
  vision: z3.boolean().optional(),
@@ -3336,6 +3402,26 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
3336
3402
  });
3337
3403
  delete merged.sourceVideo;
3338
3404
  }
3405
+ const imageInputs = ["firstFrame", "lastFrame", "referenceImages"].filter(
3406
+ (field) => field === "referenceImages" ? compact(merged.referenceImages).length > 0 : merged[field] !== void 0
3407
+ );
3408
+ if (merged.sourceVideo !== void 0 && imageInputs.length > 0 && model.capabilities?.sourceVideoExcludesFrames) {
3409
+ if (onUnsupported === "error") {
3410
+ throw new ModelKitError({
3411
+ code: "unsupported_option",
3412
+ message: `${model.id} takes a source video or images, not both`,
3413
+ model: model.id
3414
+ });
3415
+ }
3416
+ for (const field of imageInputs) {
3417
+ warnings.push({
3418
+ code: "option_ignored",
3419
+ field,
3420
+ message: `${model.id} takes a source video or images, not both; ${field} dropped`
3421
+ });
3422
+ delete merged[field];
3423
+ }
3424
+ }
3339
3425
  if (merged.lastFrame !== void 0 && merged.firstFrame === void 0 && model.capabilities?.lastFrameRequiresFirstFrame) {
3340
3426
  if (onUnsupported === "error") {
3341
3427
  throw new ModelKitError({