@shop-os/modelkit 0.3.0 → 0.3.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.d.cts CHANGED
@@ -11,7 +11,7 @@ import { LanguageModelV3, LanguageModelV2 } from '@ai-sdk/provider';
11
11
 
12
12
  /** The AI SDK video model spelling: a catalog id or a provider video model instance. */
13
13
  type VideoModel = Parameters<typeof experimental_generateVideo>[0]["model"];
14
- type AspectRatio = "1:1" | "16:9" | "9:16" | "4:3" | "3:4" | "3:2" | "2:3" | "4:5" | "5:4" | "21:9" | "9:21" | "97:30" | "adaptive";
14
+ type AspectRatio = "1:1" | "16:9" | "9:16" | "4:3" | "3:4" | "3:2" | "2:3" | "4:5" | "5:4" | "21:9" | "9:21" | "97:30" | "1:4" | "4:1" | "1:8" | "8:1" | "adaptive";
15
15
  type ImageSize = "512" | "1K" | "2K" | "4K";
16
16
  type VideoResolution = "360p" | "480p" | "720p" | "768p" | "1080p" | "2k" | "4k";
17
17
  /** "xhigh" and "max" exist only on gpt-image-2.5; gpt-image-2 rejects them at the provider. */
@@ -716,6 +716,10 @@ declare const CatalogModelSchemaBase: z.ZodObject<{
716
716
  "21:9": "21:9";
717
717
  "9:21": "9:21";
718
718
  "97:30": "97:30";
719
+ "1:4": "1:4";
720
+ "4:1": "4:1";
721
+ "1:8": "1:8";
722
+ "8:1": "8:1";
719
723
  adaptive: "adaptive";
720
724
  }>>>;
721
725
  sizes: z.ZodOptional<z.ZodArray<z.ZodEnum<{
@@ -851,6 +855,10 @@ declare const CatalogModelSchemaBase: z.ZodObject<{
851
855
  "21:9": "21:9";
852
856
  "9:21": "9:21";
853
857
  "97:30": "97:30";
858
+ "1:4": "1:4";
859
+ "4:1": "4:1";
860
+ "1:8": "1:8";
861
+ "8:1": "8:1";
854
862
  adaptive: "adaptive";
855
863
  }>>;
856
864
  size: z.ZodOptional<z.ZodEnum<{
@@ -1031,6 +1039,7 @@ declare const InputSpecSchema: z.ZodObject<{
1031
1039
  fields: z.ZodRecord<z.ZodString, z.ZodString>;
1032
1040
  values: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>>;
1033
1041
  static: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
1042
+ editEndpoint: z.ZodOptional<z.ZodString>;
1034
1043
  }, z.core.$strict>;
1035
1044
  type InputSpec = z.infer<typeof InputSpecSchema>;
1036
1045
  interface InputSpecIssue {
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ import { LanguageModelV3, LanguageModelV2 } from '@ai-sdk/provider';
11
11
 
12
12
  /** The AI SDK video model spelling: a catalog id or a provider video model instance. */
13
13
  type VideoModel = Parameters<typeof experimental_generateVideo>[0]["model"];
14
- type AspectRatio = "1:1" | "16:9" | "9:16" | "4:3" | "3:4" | "3:2" | "2:3" | "4:5" | "5:4" | "21:9" | "9:21" | "97:30" | "adaptive";
14
+ type AspectRatio = "1:1" | "16:9" | "9:16" | "4:3" | "3:4" | "3:2" | "2:3" | "4:5" | "5:4" | "21:9" | "9:21" | "97:30" | "1:4" | "4:1" | "1:8" | "8:1" | "adaptive";
15
15
  type ImageSize = "512" | "1K" | "2K" | "4K";
16
16
  type VideoResolution = "360p" | "480p" | "720p" | "768p" | "1080p" | "2k" | "4k";
17
17
  /** "xhigh" and "max" exist only on gpt-image-2.5; gpt-image-2 rejects them at the provider. */
@@ -716,6 +716,10 @@ declare const CatalogModelSchemaBase: z.ZodObject<{
716
716
  "21:9": "21:9";
717
717
  "9:21": "9:21";
718
718
  "97:30": "97:30";
719
+ "1:4": "1:4";
720
+ "4:1": "4:1";
721
+ "1:8": "1:8";
722
+ "8:1": "8:1";
719
723
  adaptive: "adaptive";
720
724
  }>>>;
721
725
  sizes: z.ZodOptional<z.ZodArray<z.ZodEnum<{
@@ -851,6 +855,10 @@ declare const CatalogModelSchemaBase: z.ZodObject<{
851
855
  "21:9": "21:9";
852
856
  "9:21": "9:21";
853
857
  "97:30": "97:30";
858
+ "1:4": "1:4";
859
+ "4:1": "4:1";
860
+ "1:8": "1:8";
861
+ "8:1": "8:1";
854
862
  adaptive: "adaptive";
855
863
  }>>;
856
864
  size: z.ZodOptional<z.ZodEnum<{
@@ -1031,6 +1039,7 @@ declare const InputSpecSchema: z.ZodObject<{
1031
1039
  fields: z.ZodRecord<z.ZodString, z.ZodString>;
1032
1040
  values: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>>;
1033
1041
  static: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
1042
+ editEndpoint: z.ZodOptional<z.ZodString>;
1034
1043
  }, z.core.$strict>;
1035
1044
  type InputSpec = z.infer<typeof InputSpecSchema>;
1036
1045
  interface InputSpecIssue {
package/dist/index.js CHANGED
@@ -169,13 +169,21 @@ var GEMINI_RATIOS = [
169
169
  "5:4",
170
170
  "adaptive"
171
171
  ];
172
+ var NANO_BANANA_2_1_RATIOS = [
173
+ ...GEMINI_RATIOS.filter((r) => r !== "adaptive"),
174
+ "1:4",
175
+ "4:1",
176
+ "1:8",
177
+ "8:1",
178
+ "adaptive"
179
+ ];
172
180
  var GEMINI_PROMPT_MAX_CHARS = 5e4;
173
181
  var GPT_IMAGE_PROMPT = { referenceSyntax: "numbered", maxChars: 32e3 };
174
- function geminiImage(id, label, aliases, sizes, display, exposure, references, promptMaxChars) {
182
+ function geminiImage(id, label, aliases, sizes, display, exposure, references, promptMaxChars, aspectRatios = GEMINI_RATIOS) {
175
183
  const prompt = { referenceSyntax: "caption" };
176
184
  if (promptMaxChars !== void 0) prompt.maxChars = promptMaxChars;
177
185
  const constraints = {
178
- aspectRatios: [...GEMINI_RATIOS],
186
+ aspectRatios: [...aspectRatios],
179
187
  sizes,
180
188
  supports: ["safetySettings", "temperature"],
181
189
  prompt
@@ -199,6 +207,21 @@ function geminiImage(id, label, aliases, sizes, display, exposure, references, p
199
207
  return model;
200
208
  }
201
209
  var IMAGE_MODELS = [
210
+ geminiImage(
211
+ "gemini-nano-banana-2.1",
212
+ "Nano Banana 2.1",
213
+ ["nb-2.1"],
214
+ ["1K", "2K", "4K"],
215
+ {
216
+ provider: "google",
217
+ description: "Latest high-efficiency Nano Banana. Better realism, prompt adherence, text rendering and character consistency at Flash speed. Great for campaigns, infographics, and iterative edits.",
218
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
219
+ },
220
+ ["cowork", "space_builder"],
221
+ { images: 14 },
222
+ GEMINI_PROMPT_MAX_CHARS,
223
+ NANO_BANANA_2_1_RATIOS
224
+ ),
202
225
  geminiImage(
203
226
  "gemini-3-pro-image-preview",
204
227
  "Nano Banana Pro",
@@ -2252,6 +2275,10 @@ var ALL_KEY_SET = /* @__PURE__ */ new Set([
2252
2275
  ...IMAGE_INPUT_SPEC_KEYS,
2253
2276
  ...AUDIO_INPUT_SPEC_KEYS
2254
2277
  ]);
2278
+ var TYPES_BY_ADAPTER = /* @__PURE__ */ new Map([
2279
+ ["replicate", ["video", "image", "audio"]],
2280
+ ["fal", ["image"]]
2281
+ ]);
2255
2282
  var ALLOWED_KEYS_BY_TYPE = /* @__PURE__ */ new Map([
2256
2283
  ["video", VIDEO_KEY_SET],
2257
2284
  ["image", IMAGE_KEY_SET],
@@ -2290,7 +2317,8 @@ var StaticSchema = z2.record(z2.string(), ProviderScalarSchema);
2290
2317
  var InputSpecSchema = z2.strictObject({
2291
2318
  fields: FieldsSchema,
2292
2319
  values: ValuesSchema.optional(),
2293
- static: StaticSchema.optional()
2320
+ static: StaticSchema.optional(),
2321
+ editEndpoint: z2.string().min(1).optional()
2294
2322
  }).superRefine((spec, ctx) => {
2295
2323
  const mappedNames = new Set(Object.values(spec.fields));
2296
2324
  for (const key of Object.keys(spec.static ?? {})) {
@@ -2318,18 +2346,21 @@ function validateInputSpec(raw, row) {
2318
2346
  };
2319
2347
  }
2320
2348
  const spec = parsed.data;
2321
- if (row.adapter !== "replicate") {
2349
+ const supportedTypes = TYPES_BY_ADAPTER.get(row.adapter);
2350
+ if (supportedTypes === void 0) {
2322
2351
  return {
2323
2352
  ok: false,
2324
- issues: [{ path: [], message: "inputSpec is only supported on replicate rows" }]
2353
+ issues: [
2354
+ { path: [], message: "inputSpec is only supported on replicate and fal rows" }
2355
+ ]
2325
2356
  };
2326
2357
  }
2327
2358
  const issues = [];
2328
2359
  const allowed = ALLOWED_KEYS_BY_TYPE.get(row.type);
2329
- if (allowed === void 0) {
2360
+ if (allowed === void 0 || !supportedTypes.includes(row.type)) {
2330
2361
  issues.push({
2331
2362
  path: [],
2332
- message: `inputSpec is not supported for "${row.type}" rows`
2363
+ message: row.adapter === "fal" ? `inputSpec on fal rows is only supported for image rows, not "${row.type}"` : `inputSpec is not supported for "${row.type}" rows`
2333
2364
  });
2334
2365
  } else {
2335
2366
  for (const key of Object.keys(spec.fields)) {
@@ -2349,6 +2380,19 @@ function validateInputSpec(raw, row) {
2349
2380
  }
2350
2381
  }
2351
2382
  }
2383
+ if (spec.editEndpoint !== void 0) {
2384
+ if (row.adapter !== "fal") {
2385
+ issues.push({
2386
+ path: ["editEndpoint"],
2387
+ message: "inputSpec.editEndpoint is only supported on fal rows"
2388
+ });
2389
+ } else if (!("references" in spec.fields)) {
2390
+ issues.push({
2391
+ path: ["editEndpoint"],
2392
+ message: 'inputSpec.editEndpoint needs a "references" entry in inputSpec.fields'
2393
+ });
2394
+ }
2395
+ }
2352
2396
  const seenNames = /* @__PURE__ */ new Map();
2353
2397
  for (const [key, name] of Object.entries(spec.fields)) {
2354
2398
  const first = seenNames.get(name);
@@ -2424,6 +2468,10 @@ var AspectRatioSchema = z3.enum([
2424
2468
  "21:9",
2425
2469
  "9:21",
2426
2470
  "97:30",
2471
+ "1:4",
2472
+ "4:1",
2473
+ "1:8",
2474
+ "8:1",
2427
2475
  "adaptive"
2428
2476
  ]);
2429
2477
  var ImageSizeSchema = z3.enum(["512", "1K", "2K", "4K"]);
@@ -4093,6 +4141,70 @@ async function cancelFalVideoTool(sub, ctx) {
4093
4141
  throw falError(res.status, await readBody(res), ctx.model.id);
4094
4142
  }
4095
4143
 
4144
+ // src/adapters/input-spec-mapper.ts
4145
+ function canonicalValue(req, key) {
4146
+ return req[key];
4147
+ }
4148
+ function isMediaRef(value) {
4149
+ return value instanceof Object && ("url" in value || "bytes" in value);
4150
+ }
4151
+ function toProviderValue(value, refToUrl2) {
4152
+ if (Array.isArray(value)) {
4153
+ return value.map(refToUrl2);
4154
+ }
4155
+ if (isMediaRef(value)) {
4156
+ return refToUrl2(value);
4157
+ }
4158
+ return value;
4159
+ }
4160
+ function applyInputSpec(spec, req, refToUrl2, opts) {
4161
+ const out = {};
4162
+ for (const [canonical, providerField] of Object.entries(spec.fields)) {
4163
+ if (!isInputSpecKey(canonical)) continue;
4164
+ const value = canonicalValue(req, canonical);
4165
+ if (value === void 0) continue;
4166
+ if (opts?.omit?.(canonical, value)) continue;
4167
+ const serialised = toProviderValue(value, refToUrl2);
4168
+ const mapped = spec.values?.[canonical]?.[String(value)];
4169
+ out[providerField] = mapped ?? serialised;
4170
+ }
4171
+ for (const [key, value] of Object.entries(spec.static ?? {})) {
4172
+ out[key] = value;
4173
+ }
4174
+ return out;
4175
+ }
4176
+ function resolveRowInputSpec(req, ctx) {
4177
+ const raw = ctx.model.providerOptions?.["modelkit"]?.["inputSpec"];
4178
+ if (raw === void 0) return { kind: "absent" };
4179
+ const result = validateInputSpec(raw, ctx.model);
4180
+ if (!result.ok) {
4181
+ ctx.logger.warn(
4182
+ `[modelkit] ${ctx.model.id} has an invalid providerOptions.modelkit.inputSpec; the call fails`
4183
+ );
4184
+ return { kind: "invalid", issues: result.issues };
4185
+ }
4186
+ return {
4187
+ kind: "ok",
4188
+ spec: result.spec,
4189
+ input: applyInputSpec(result.spec, req, refToUrl, {
4190
+ omit: (key, value) => key === "aspectRatio" && value === "adaptive"
4191
+ })
4192
+ };
4193
+ }
4194
+ function describeInputSpecIssue(issue) {
4195
+ if (!issue) return "invalid inputSpec";
4196
+ return issue.path.length === 0 ? issue.message : `${issue.path.map((part) => String(part)).join(".")} ${issue.message}`;
4197
+ }
4198
+ function invalidInputSpecError(provider, ctx, issues) {
4199
+ return new ModelKitError({
4200
+ code: "unsupported_option",
4201
+ message: `${provider} row "${ctx.model.id}" has an invalid providerOptions.modelkit.inputSpec: ${describeInputSpecIssue(issues[0])}`,
4202
+ provider,
4203
+ model: ctx.model.id,
4204
+ retryable: false
4205
+ });
4206
+ }
4207
+
4096
4208
  // src/adapters/fal.ts
4097
4209
  var MUSE_T2I_ENDPOINT = "meta/muse-image/text-to-image";
4098
4210
  var MUSE_EDIT_ENDPOINT = "meta/muse-image/edit";
@@ -4147,6 +4259,11 @@ function createFalAdapter(deps = defaultDeps) {
4147
4259
  id: "fal",
4148
4260
  generateImage: (req, ctx) => {
4149
4261
  throwIfAborted(ctx.signal);
4262
+ const spec = resolveRowInputSpec(req, ctx);
4263
+ if (spec.kind === "invalid") {
4264
+ return Promise.reject(invalidInputSpecError("fal", ctx, spec.issues));
4265
+ }
4266
+ if (spec.kind === "ok") return generateSpecImage(req, ctx, deps, spec);
4150
4267
  if (isIdeogram(ctx.model.providerModelId)) return generateIdeogramImage(req, ctx, deps);
4151
4268
  return generateMuseImage(req, ctx, deps);
4152
4269
  },
@@ -4326,6 +4443,36 @@ var museImageResultSchema = z12.object({
4326
4443
  })
4327
4444
  ).optional()
4328
4445
  });
4446
+ async function collectFalImages(payload, ctx, req, label) {
4447
+ const parsed = museImageResultSchema.safeParse(payload);
4448
+ const images = parsed.success ? parsed.data.images ?? [] : [];
4449
+ const files = await Promise.all(
4450
+ images.flatMap((img) => {
4451
+ if (img.url === void 0) return [];
4452
+ return [decodeImage(ctx, img.url, img.content_type ?? void 0)];
4453
+ })
4454
+ );
4455
+ if (files.length === 0) {
4456
+ throw new ModelKitError({
4457
+ code: "provider_rejected",
4458
+ message: `${label} returned no image`,
4459
+ provider: "fal",
4460
+ model: ctx.model.id,
4461
+ retryable: false
4462
+ });
4463
+ }
4464
+ return {
4465
+ images: files.map((f) => ({ bytes: f.bytes, mime: f.mime })),
4466
+ usage: imageUsage(ctx, req, files.length),
4467
+ raw: payload
4468
+ };
4469
+ }
4470
+ async function generateSpecImage(req, ctx, deps, spec) {
4471
+ const hasReferences = (req.references ?? []).length > 0;
4472
+ const endpoint = hasReferences && spec.spec.editEndpoint !== void 0 ? spec.spec.editEndpoint : ctx.model.providerModelId;
4473
+ const payload = await runJob(ctx, deps, endpoint, spec.input);
4474
+ return collectFalImages(payload, ctx, req, `fal ${endpoint}`);
4475
+ }
4329
4476
  async function generateMuseImage(req, ctx, deps) {
4330
4477
  const refs = (req.references ?? []).map(refToUrl);
4331
4478
  const isEdit = refs.length > 0;
@@ -4342,29 +4489,7 @@ async function generateMuseImage(req, ctx, deps) {
4342
4489
  const custom = id.includes("/") && !id.startsWith("meta/muse-image") ? id : void 0;
4343
4490
  const endpoint = custom ?? (isEdit ? MUSE_EDIT_ENDPOINT : MUSE_T2I_ENDPOINT);
4344
4491
  const payload = await runJob(ctx, deps, endpoint, input);
4345
- const parsed = museImageResultSchema.safeParse(payload);
4346
- const images = parsed.success ? parsed.data.images ?? [] : [];
4347
- const firstUrl = images[0]?.url;
4348
- if (images.length === 0 || firstUrl === void 0) {
4349
- throw new ModelKitError({
4350
- code: "provider_rejected",
4351
- message: "fal Meta Muse returned no image",
4352
- provider: "fal",
4353
- model: ctx.model.id,
4354
- retryable: false
4355
- });
4356
- }
4357
- const files = await Promise.all(
4358
- images.flatMap((img) => {
4359
- if (img.url === void 0) return [];
4360
- return [decodeImage(ctx, img.url, img.content_type ?? void 0)];
4361
- })
4362
- );
4363
- return {
4364
- images: files.map((f) => ({ bytes: f.bytes, mime: f.mime })),
4365
- usage: imageUsage(ctx, req, files.length),
4366
- raw: payload
4367
- };
4492
+ return collectFalImages(payload, ctx, req, "fal Meta Muse");
4368
4493
  }
4369
4494
  var IDEOGRAM_MODEL_IDS = /* @__PURE__ */ new Set(["ideogram/v4.5"]);
4370
4495
  function isIdeogram(providerModelId) {
@@ -4409,28 +4534,7 @@ async function generateIdeogramImage(req, ctx, deps) {
4409
4534
  if (references.length > 0) input.reference_image_urls = references;
4410
4535
  }
4411
4536
  const payload = await runJob(ctx, deps, endpoint, input);
4412
- const parsed = museImageResultSchema.safeParse(payload);
4413
- const images = parsed.success ? parsed.data.images ?? [] : [];
4414
- const files = await Promise.all(
4415
- images.flatMap((img) => {
4416
- if (img.url === void 0) return [];
4417
- return [decodeImage(ctx, img.url, img.content_type ?? void 0)];
4418
- })
4419
- );
4420
- if (files.length === 0) {
4421
- throw new ModelKitError({
4422
- code: "provider_rejected",
4423
- message: "fal Ideogram returned no image",
4424
- provider: "fal",
4425
- model: ctx.model.id,
4426
- retryable: false
4427
- });
4428
- }
4429
- return {
4430
- images: files.map((f) => ({ bytes: f.bytes, mime: f.mime })),
4431
- usage: imageUsage(ctx, req, files.length),
4432
- raw: payload
4433
- };
4537
+ return collectFalImages(payload, ctx, req, "fal Ideogram");
4434
4538
  }
4435
4539
  var H3_MAX_MODEL_IDS = /* @__PURE__ */ new Set([
4436
4540
  "minimax/h3-max",
@@ -6781,41 +6885,6 @@ function createReplicateHttpClient(opts) {
6781
6885
 
6782
6886
  // src/adapters/replicate.ts
6783
6887
  import { z as z19 } from "zod";
6784
-
6785
- // src/adapters/input-spec-mapper.ts
6786
- function canonicalValue(req, key) {
6787
- return req[key];
6788
- }
6789
- function isMediaRef(value) {
6790
- return value instanceof Object && ("url" in value || "bytes" in value);
6791
- }
6792
- function toProviderValue(value, refToUrl2) {
6793
- if (Array.isArray(value)) {
6794
- return value.map(refToUrl2);
6795
- }
6796
- if (isMediaRef(value)) {
6797
- return refToUrl2(value);
6798
- }
6799
- return value;
6800
- }
6801
- function applyInputSpec(spec, req, refToUrl2, opts) {
6802
- const out = {};
6803
- for (const [canonical, providerField] of Object.entries(spec.fields)) {
6804
- if (!isInputSpecKey(canonical)) continue;
6805
- const value = canonicalValue(req, canonical);
6806
- if (value === void 0) continue;
6807
- if (opts?.omit?.(canonical, value)) continue;
6808
- const serialised = toProviderValue(value, refToUrl2);
6809
- const mapped = spec.values?.[canonical]?.[String(value)];
6810
- out[providerField] = mapped ?? serialised;
6811
- }
6812
- for (const [key, value] of Object.entries(spec.static ?? {})) {
6813
- out[key] = value;
6814
- }
6815
- return out;
6816
- }
6817
-
6818
- // src/adapters/replicate.ts
6819
6888
  var POLL_INTERVAL_MS = 1e3;
6820
6889
  var POLL_TIMEOUT_MS = 15 * 6e4;
6821
6890
  var defaultReplicateDeps = {
@@ -7058,38 +7127,6 @@ function replicateNoMapper(ctx, section) {
7058
7127
  retryable: false
7059
7128
  });
7060
7129
  }
7061
- function describeInputSpecIssue(issue) {
7062
- if (!issue) return "invalid inputSpec";
7063
- return issue.path.length === 0 ? issue.message : `${issue.path.map((part) => String(part)).join(".")} ${issue.message}`;
7064
- }
7065
- function replicateInvalidSpec(ctx, issues) {
7066
- const detail = describeInputSpecIssue(issues[0]);
7067
- return new ModelKitError({
7068
- code: "unsupported_option",
7069
- message: `replicate row "${ctx.model.id}" has an invalid providerOptions.modelkit.inputSpec: ${detail}`,
7070
- provider: "replicate",
7071
- model: ctx.model.id,
7072
- retryable: false
7073
- });
7074
- }
7075
- function omitAdaptive(key, value) {
7076
- return key === "aspectRatio" && value === "adaptive";
7077
- }
7078
- function replicateInputSpec(req, ctx) {
7079
- const raw = ctx.model.providerOptions?.["modelkit"]?.["inputSpec"];
7080
- if (raw === void 0) return { kind: "absent" };
7081
- const result = validateInputSpec(raw, ctx.model);
7082
- if (!result.ok) {
7083
- ctx.logger.warn(
7084
- `[modelkit] ${ctx.model.id} has an invalid providerOptions.modelkit.inputSpec; the call fails`
7085
- );
7086
- return { kind: "invalid", issues: result.issues };
7087
- }
7088
- return {
7089
- kind: "ok",
7090
- input: applyInputSpec(result.spec, req, refToUrl, { omit: omitAdaptive })
7091
- };
7092
- }
7093
7130
  var QWEN_IMAGE_RATIOS = /* @__PURE__ */ new Set([
7094
7131
  "1:1",
7095
7132
  "16:9",
@@ -7233,8 +7270,9 @@ async function generateReplicateImage(req, ctx, deps) {
7233
7270
  break;
7234
7271
  }
7235
7272
  default: {
7236
- const specResult = replicateInputSpec(req, ctx);
7237
- if (specResult.kind === "invalid") throw replicateInvalidSpec(ctx, specResult.issues);
7273
+ const specResult = resolveRowInputSpec(req, ctx);
7274
+ if (specResult.kind === "invalid")
7275
+ throw invalidInputSpecError("replicate", ctx, specResult.issues);
7238
7276
  if (specResult.kind === "ok") {
7239
7277
  input = specResult.input;
7240
7278
  break;
@@ -7314,9 +7352,10 @@ async function generateReplicateVideo(req, ctx, deps) {
7314
7352
  else if (kind === "kling-omni") input = klingOmniInput(req);
7315
7353
  else if (kind === "hailuo") input = hailuoInput(req);
7316
7354
  else {
7317
- const specResult = replicateInputSpec(req, ctx);
7355
+ const specResult = resolveRowInputSpec(req, ctx);
7318
7356
  if (specResult.kind === "absent") throw replicateNoMapper(ctx, "video");
7319
- if (specResult.kind === "invalid") throw replicateInvalidSpec(ctx, specResult.issues);
7357
+ if (specResult.kind === "invalid")
7358
+ throw invalidInputSpecError("replicate", ctx, specResult.issues);
7320
7359
  input = specResult.input;
7321
7360
  }
7322
7361
  const api = client(ctx, deps);
@@ -7471,9 +7510,10 @@ async function generateReplicateAudio(req, ctx, deps) {
7471
7510
  else if (kind === "elevenlabs") input = elevenLabsMusicInput(req, ctx);
7472
7511
  else if (kind === "lyria") input = lyriaAudioInput(req, ctx);
7473
7512
  else {
7474
- const specResult = replicateInputSpec(req, ctx);
7513
+ const specResult = resolveRowInputSpec(req, ctx);
7475
7514
  if (specResult.kind === "absent") throw replicateNoMapper(ctx, "audio");
7476
- if (specResult.kind === "invalid") throw replicateInvalidSpec(ctx, specResult.issues);
7515
+ if (specResult.kind === "invalid")
7516
+ throw invalidInputSpecError("replicate", ctx, specResult.issues);
7477
7517
  input = specResult.input;
7478
7518
  }
7479
7519
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);