@shop-os/modelkit 0.3.0 → 0.3.1

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,18 @@ header in the release PR.
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [0.3.1] - Unreleased
13
+
14
+ ### Added
15
+ - `providerOptions.modelkit.inputSpec` now works on fal image rows, so a new fal image model is a database row. The spec uses the image keys (`prompt`, `references`, `aspectRatio`, `size`, `outputFormat`, `seed`) with `fields`, `values` and `static`, exactly as on Replicate image rows. The new optional `editEndpoint` (fal rows only) names the endpoint called instead of `providerModelId` when the request has references, for models that split text-to-image and edit across two endpoints. Only the mapped fields are sent: no `num_images`, so a spec row returns one image per call. A fal row without an `inputSpec` keeps the Muse-shaped request and Ideogram keeps its own path. fal video rows still reject `inputSpec`. On fal an explicit `inputSpec` wins over the built-in Ideogram path, and `editEndpoint` needs a `references` entry in `fields`.
16
+ - `resolveRowInputSpec(req, ctx)` and `invalidInputSpecError(provider, ctx, issues)` in the shared mapper, used by the Replicate and fal adapters.
17
+
18
+ ### Changed
19
+ - fal image calls decode every image in the response that has a URL and fail only when none do. The Muse path used to fail when the first image had no URL even if later ones did.
20
+
21
+ ### Live rows to add after publish
22
+ Add a fal image row that carries an `inputSpec` only after every app that will call it runs 0.3.1. An older kit accepts the row but ignores the `inputSpec`, so it sends the Muse-shaped request and the call fails or loses its fields.
23
+
12
24
  ## [0.3.0] - Unreleased
13
25
 
14
26
  ### Added
package/README.md CHANGED
@@ -213,8 +213,8 @@ The Bedrock model id is `<routing.bedrockProfile>.anthropic.<providerModelId>`
213
213
  breaks the pattern sets `providerOptions.modelkit.bedrockModelId` on its row.
214
214
  See the CHANGELOG entry for the caller-visible Bedrock limits.
215
215
 
216
- A Replicate video, image or audio row for a new model carries `providerOptions.modelkit.inputSpec`
217
- instead of a kit change. It is read by the Replicate adapter only. `fields` maps a canonical key to the provider field name,
216
+ A Replicate video, image or audio row, or a fal image row, for a new model carries `providerOptions.modelkit.inputSpec`
217
+ instead of a kit change. It is read by the Replicate and fal adapters only. `fields` maps a canonical key to the provider field name,
218
218
  `values` remaps canonical values per key, and `static` merges literal provider fields
219
219
  last. Video rows use `VIDEO_INPUT_SPEC_KEYS` (`prompt`, `durationSeconds`,
220
220
  `aspectRatio`, `resolution`, `firstFrame`, `lastFrame`, `seed`, `negativePrompt`,
@@ -223,7 +223,7 @@ last. Video rows use `VIDEO_INPUT_SPEC_KEYS` (`prompt`, `durationSeconds`,
223
223
  `seed`; map `references` to the provider's array field and remap `size` and `outputFormat`
224
224
  with `values`); audio rows use
225
225
  `AUDIO_INPUT_SPEC_KEYS` (`prompt`, `durationSeconds`, `seed`, `negativePrompt`,
226
- `references`, `sourceVideo`, `instrumental`). `aspectRatio: "adaptive"` is omitted.
226
+ `references`, `sourceVideo`, `instrumental`). `aspectRatio: "adaptive"` is omitted. A fal image row has no kind and builds its whole input from the spec; the optional `editEndpoint` (fal rows only) is the fal endpoint called instead of `providerModelId` when the request has references. fal rows without an `inputSpec` keep the Muse-shaped request and Ideogram keeps its own path; an `inputSpec` on an Ideogram row replaces that path. `editEndpoint` needs a `references` entry in `fields`. `inputSpec` on fal video rows is not supported.
227
227
  `validateInputSpec` is the shared contract the write schema, `dataOnlyCapable`, and
228
228
  the Replicate mapper all check. `dataOnlyCapable(row)` reports whether such a row would
229
229
  be served.
package/dist/catalog.cjs CHANGED
@@ -2317,6 +2317,10 @@ var ALL_KEY_SET = /* @__PURE__ */ new Set([
2317
2317
  ...IMAGE_INPUT_SPEC_KEYS,
2318
2318
  ...AUDIO_INPUT_SPEC_KEYS
2319
2319
  ]);
2320
+ var TYPES_BY_ADAPTER = /* @__PURE__ */ new Map([
2321
+ ["replicate", ["video", "image", "audio"]],
2322
+ ["fal", ["image"]]
2323
+ ]);
2320
2324
  var ALLOWED_KEYS_BY_TYPE = /* @__PURE__ */ new Map([
2321
2325
  ["video", VIDEO_KEY_SET],
2322
2326
  ["image", IMAGE_KEY_SET],
@@ -2355,7 +2359,8 @@ var StaticSchema = import_zod2.z.record(import_zod2.z.string(), ProviderScalarSc
2355
2359
  var InputSpecSchema = import_zod2.z.strictObject({
2356
2360
  fields: FieldsSchema,
2357
2361
  values: ValuesSchema.optional(),
2358
- static: StaticSchema.optional()
2362
+ static: StaticSchema.optional(),
2363
+ editEndpoint: import_zod2.z.string().min(1).optional()
2359
2364
  }).superRefine((spec, ctx) => {
2360
2365
  const mappedNames = new Set(Object.values(spec.fields));
2361
2366
  for (const key of Object.keys(spec.static ?? {})) {
@@ -2380,18 +2385,21 @@ function validateInputSpec(raw, row) {
2380
2385
  };
2381
2386
  }
2382
2387
  const spec = parsed.data;
2383
- if (row.adapter !== "replicate") {
2388
+ const supportedTypes = TYPES_BY_ADAPTER.get(row.adapter);
2389
+ if (supportedTypes === void 0) {
2384
2390
  return {
2385
2391
  ok: false,
2386
- issues: [{ path: [], message: "inputSpec is only supported on replicate rows" }]
2392
+ issues: [
2393
+ { path: [], message: "inputSpec is only supported on replicate and fal rows" }
2394
+ ]
2387
2395
  };
2388
2396
  }
2389
2397
  const issues = [];
2390
2398
  const allowed = ALLOWED_KEYS_BY_TYPE.get(row.type);
2391
- if (allowed === void 0) {
2399
+ if (allowed === void 0 || !supportedTypes.includes(row.type)) {
2392
2400
  issues.push({
2393
2401
  path: [],
2394
- message: `inputSpec is not supported for "${row.type}" rows`
2402
+ 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`
2395
2403
  });
2396
2404
  } else {
2397
2405
  for (const key of Object.keys(spec.fields)) {
@@ -2411,6 +2419,19 @@ function validateInputSpec(raw, row) {
2411
2419
  }
2412
2420
  }
2413
2421
  }
2422
+ if (spec.editEndpoint !== void 0) {
2423
+ if (row.adapter !== "fal") {
2424
+ issues.push({
2425
+ path: ["editEndpoint"],
2426
+ message: "inputSpec.editEndpoint is only supported on fal rows"
2427
+ });
2428
+ } else if (!("references" in spec.fields)) {
2429
+ issues.push({
2430
+ path: ["editEndpoint"],
2431
+ message: 'inputSpec.editEndpoint needs a "references" entry in inputSpec.fields'
2432
+ });
2433
+ }
2434
+ }
2414
2435
  const seenNames = /* @__PURE__ */ new Map();
2415
2436
  for (const [key, name] of Object.entries(spec.fields)) {
2416
2437
  const first = seenNames.get(name);