@howells/motif-sdk 7.0.0 → 7.2.0

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
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let neverthrow = require("neverthrow");
3
3
  let _howells_envy = require("@howells/envy");
4
4
  let zod = require("zod");
5
- //#region src/aspects.ts
5
+ // src/aspects.ts
6
6
  /** Ordered by popularity: square first, then common ratios */
7
7
  const ASPECT_RATIOS = [
8
8
  "auto",
@@ -142,6 +142,9 @@ function scaleWithin(longEdge, longTerm, unit) {
142
142
  function roundUpTo(value, unit) {
143
143
  return unit * Math.ceil(value / unit);
144
144
  }
145
+ function roundDownTo(value, unit) {
146
+ return unit * Math.floor(value / unit);
147
+ }
145
148
  /**
146
149
  * Exact pixel dimensions for an aspect ratio at a resolution tier, or null for
147
150
  * `"auto"`.
@@ -171,8 +174,9 @@ function withinImageSizeBounds(size, bounds) {
171
174
  }
172
175
  /**
173
176
  * The exact size for an aspect on an endpoint with limits: the long edge as
174
- * close to `longEdge` as the ratio allows without passing it, then scaled up
175
- * only as far as a minimum edge or pixel count demands. Null for `"auto"`.
177
+ * close to `longEdge` as the ratio allows without passing it or the endpoint's
178
+ * maximum edge or pixel count, then scaled up only as far as a minimum edge or
179
+ * pixel count demands. Null for `"auto"`.
176
180
  * Undefined when no size in that ratio fits the limits: the caller refuses,
177
181
  * because rounding to another ratio is the defect this exists to remove.
178
182
  */
@@ -182,6 +186,8 @@ function boundedImageSize(aspect, longEdge, bounds) {
182
186
  const [width, height] = terms;
183
187
  const unit = bounds.multipleOf ?? EDGE_MULTIPLE;
184
188
  let scale = scaleWithin(longEdge, Math.max(width, height), unit);
189
+ if (bounds.maxEdge !== void 0) scale = Math.min(scale, roundDownTo(bounds.maxEdge / Math.max(width, height), unit));
190
+ if (bounds.maxPixels !== void 0) scale = Math.min(scale, roundDownTo(Math.sqrt(bounds.maxPixels / (width * height)), unit));
185
191
  if (bounds.minEdge !== void 0) scale = Math.max(scale, roundUpTo(bounds.minEdge / Math.min(width, height), unit));
186
192
  if (bounds.minPixels !== void 0) scale = Math.max(scale, roundUpTo(Math.sqrt(bounds.minPixels / (width * height)), unit));
187
193
  const size = {
@@ -237,8 +243,7 @@ const FORMAT_PRESETS = {
237
243
  label: "Wide"
238
244
  }
239
245
  };
240
- //#endregion
241
- //#region src/creative.ts
246
+ // src/creative.ts
242
247
  const CONTROL_CHAR_REGEX = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g;
243
248
  const TRAILING_PERIODS_REGEX = /\.+$/;
244
249
  /**
@@ -480,8 +485,7 @@ function enrichPrompt(options) {
480
485
  prompt: clauses.length ? joinSentences([basePrompt, ...clauses].filter((part) => part !== "")) : basePrompt
481
486
  };
482
487
  }
483
- //#endregion
484
- //#region src/errors.ts
488
+ // src/errors.ts
485
489
  /**
486
490
  * `MotifError` and its coercion helper.
487
491
  *
@@ -538,8 +542,7 @@ function toMotifError(error) {
538
542
  if (error instanceof MotifError) return error;
539
543
  return new MotifError(error instanceof Error ? error.message : String(error), 0, error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : void 0);
540
544
  }
541
- //#endregion
542
- //#region src/task-plan-shared.ts
545
+ // src/task-plan-shared.ts
543
546
  /**
544
547
  * Helpers every request builder in the Task planner shares: refusing fields a
545
548
  * Model can't carry, and merging `params` without letting them replace what
@@ -619,8 +622,7 @@ function mergeParams(body, params, owned) {
619
622
  ...params
620
623
  });
621
624
  }
622
- //#endregion
623
- //#region src/prompt-warnings.ts
625
+ // src/prompt-warnings.ts
624
626
  const EDIT_VERB_REGEX = /^\s*(remove|erase|extend|outpaint)\b/i;
625
627
  /** The CLI verb that does each edit directly, keyed by the prompt's first word. */
626
628
  const EDIT_VERBS = {
@@ -686,8 +688,7 @@ function promptWarnings(prompt, context = {}) {
686
688
  });
687
689
  return warnings;
688
690
  }
689
- //#endregion
690
- //#region src/env.ts
691
+ // src/env.ts
691
692
  const motifEnvSchema = (0, _howells_envy.defineEnv)({ optional: { FAL_KEY: zod.z.string().min(1) } });
692
693
  function parseMotifEnv(input = process.env) {
693
694
  return motifEnvSchema.parse(input);
@@ -695,8 +696,7 @@ function parseMotifEnv(input = process.env) {
695
696
  function getFalKeyFromEnv(input = process.env) {
696
697
  return parseMotifEnv(input).FAL_KEY;
697
698
  }
698
- //#endregion
699
- //#region src/models.ts
699
+ // src/models.ts
700
700
  const AA_IMAGE_LEADERBOARD_SNAPSHOT = "2026-10-07";
701
701
  const AA_IMAGE_SOURCES = ["https://artificialanalysis.ai/image/leaderboard/text-to-image", "https://artificialanalysis.ai/image/leaderboard/editing"];
702
702
  const FAL_PRICING_CHECKED_AT = "2026-05-12";
@@ -766,7 +766,7 @@ const MODELS = {
766
766
  "xhigh",
767
767
  "max"
768
768
  ],
769
- supportsResolution: false,
769
+ supportsResolution: true,
770
770
  supportsSyncMode: true,
771
771
  type: "generation",
772
772
  useQueue: true
@@ -833,7 +833,7 @@ const MODELS = {
833
833
  "xhigh",
834
834
  "max"
835
835
  ],
836
- supportsResolution: false,
836
+ supportsResolution: true,
837
837
  supportsSyncMode: true,
838
838
  type: "generation",
839
839
  useQueue: true
@@ -1867,8 +1867,7 @@ const GENERATION_MODELS = [
1867
1867
  "recraft41"
1868
1868
  ];
1869
1869
  GENERATION_MODELS.filter((id) => MODELS[id]?.supportsEdit === true);
1870
- //#endregion
1871
- //#region src/cost.ts
1870
+ // src/cost.ts
1872
1871
  /**
1873
1872
  * Estimate cost based on model and settings. `editImages` is the number of
1874
1873
  * input images on an edit, for Models whose edits cost more than generation.
@@ -1898,8 +1897,7 @@ function estimateVideoCost(durationSeconds = 5, generateAudio = true, model = "k
1898
1897
  if (model === "kling-turbo") return .14 * durationSeconds;
1899
1898
  return (generateAudio ? .168 : .112) * durationSeconds;
1900
1899
  }
1901
- //#endregion
1902
- //#region src/fal-parse.ts
1900
+ // src/fal-parse.ts
1903
1901
  /**
1904
1902
  * Boundary parsing for fal.ai HTTP responses.
1905
1903
  *
@@ -2004,8 +2002,7 @@ function requestIdFromBody(text) {
2004
2002
  if (!isRecord$1(parsed)) return;
2005
2003
  return asString(parsed.request_id) ?? asString(parsed.requestId) ?? asString(parsed.trace_id);
2006
2004
  }
2007
- //#endregion
2008
- //#region src/capabilities.ts
2005
+ // src/capabilities.ts
2009
2006
  /**
2010
2007
  * Which generation options each model accepts, derived from the registry.
2011
2008
  *
@@ -2095,8 +2092,7 @@ var UnsupportedOptionError = class extends Error {
2095
2092
  this.supportedOptions = supported;
2096
2093
  }
2097
2094
  };
2098
- //#endregion
2099
- //#region src/generate.ts
2095
+ // src/generate.ts
2100
2096
  const GPT_IMAGE_SIZES = [
2101
2097
  "auto",
2102
2098
  "1024x1024",
@@ -2134,15 +2130,16 @@ function normalizeImageSize(imageSize, sizeMode) {
2134
2130
  throw new Error(`fal image_size must be one of ${FAL_IMAGE_SIZE_PRESETS.join(", ")} or WIDTHxHEIGHT`);
2135
2131
  }
2136
2132
  /**
2137
- * `image_size` for an aspect: fal's named preset where one holds the ratio
2138
- * exactly, else exact dimensions where the endpoint takes them, else the
2139
- * nearest preset. A Model without a resolution setting is sized to the preset
2133
+ * `image_size` for an aspect: exact dimensions at the requested resolution
2134
+ * where the endpoint takes them and has a resolution setting; otherwise fal's
2135
+ * named preset where one holds the ratio exactly, else exact dimensions where
2136
+ * the endpoint takes them, else the nearest preset. A Model without a resolution setting is sized to the preset
2140
2137
  * long edge, so an exact size costs what a preset would. Out of the Model's
2141
2138
  * limits it throws rather than rounding to another ratio.
2142
2139
  */
2143
2140
  function falImageSizeFor(config, aspect, resolution) {
2144
2141
  const bounds = config.customImageSize;
2145
- if (bounds === void 0 || FAL_PRESET_ASPECTS.includes(aspect)) return aspectToFalImageSize(aspect);
2142
+ if (bounds === void 0 || !config.supportsResolution && FAL_PRESET_ASPECTS.includes(aspect)) return aspectToFalImageSize(aspect);
2146
2143
  const size = boundedImageSize(aspect, config.supportsResolution ? RESOLUTION_LONG_EDGE[resolution] : FAL_PRESET_LONG_EDGE, bounds);
2147
2144
  if (size === void 0) throw new ImageSizeBoundsError(config.name, aspect, bounds);
2148
2145
  return size ?? aspectToFalImageSize(aspect);
@@ -2155,6 +2152,7 @@ function validateGenerateOptions(options, config, sizeMode, hasEditImages) {
2155
2152
  if (options.editImageUrls !== void 0 && options.editImageUrls.length > 0 && !config.supportsEdit) unsupported(config, "image editing");
2156
2153
  if (options.aspect !== void 0 && sizeMode === "none") unsupported(config, "aspect");
2157
2154
  if (options.resolution !== void 0 && options.resolution !== "2K" && !config.supportsResolution) unsupported(config, "resolution");
2155
+ if (config.autoEditSize === true && hasEditImages && options.aspect === void 0 && options.imageSize === void 0 && options.resolution !== void 0) throw new Error(`${config.name} sizes an edit from its source image; pass an aspect with resolution`);
2158
2156
  if (options.aspect !== void 0 && config.supportedAspects !== void 0 && !config.supportedAspects.includes(options.aspect)) throw new Error(`${config.name} aspect must be one of ${config.supportedAspects.join(", ")}`);
2159
2157
  if (options.resolution !== void 0 && config.supportedResolutions !== void 0 && !config.supportedResolutions.includes(options.resolution)) throw new Error(`${config.name} resolution must be one of ${config.supportedResolutions.join(", ")}`);
2160
2158
  if (options.numImages !== void 0 && options.numImages !== 1 && !config.supportsNumImages) unsupported(config, "numImages");
@@ -2291,8 +2289,7 @@ function buildGenerateBody(options) {
2291
2289
  endpoint
2292
2290
  };
2293
2291
  }
2294
- //#endregion
2295
- //#region src/tool-registry/analysis.ts
2292
+ // src/tool-registry/analysis.ts
2296
2293
  const ANALYSIS_TOOLS = {
2297
2294
  "got-ocr": {
2298
2295
  category: "analysis",
@@ -2406,8 +2403,7 @@ const ANALYSIS_TOOLS = {
2406
2403
  task: "vision moderation"
2407
2404
  }
2408
2405
  };
2409
- //#endregion
2410
- //#region src/tool-registry/assets.ts
2406
+ // src/tool-registry/assets.ts
2411
2407
  const ASSET_TOOLS = {
2412
2408
  "hunyuan3d-v3": {
2413
2409
  category: "3d",
@@ -2725,8 +2721,7 @@ const ASSET_TOOLS = {
2725
2721
  task: "single-image 3D reconstruction"
2726
2722
  }
2727
2723
  };
2728
- //#endregion
2729
- //#region src/tool-registry/background.ts
2724
+ // src/tool-registry/background.ts
2730
2725
  const BACKGROUND_TOOLS = {
2731
2726
  "ben-v2": {
2732
2727
  category: "background",
@@ -3101,8 +3096,7 @@ const BACKGROUND_TOOLS = {
3101
3096
  task: "video enhancement"
3102
3097
  }
3103
3098
  };
3104
- //#endregion
3105
- //#region src/tool-registry/editing.ts
3099
+ // src/tool-registry/editing.ts
3106
3100
  const EDITING_TOOLS = {
3107
3101
  "bria-eraser": {
3108
3102
  category: "erase",
@@ -3373,8 +3367,7 @@ const EDITING_TOOLS = {
3373
3367
  task: "virtual garment try-on"
3374
3368
  }
3375
3369
  };
3376
- //#endregion
3377
- //#region src/tool-registry/structure.ts
3370
+ // src/tool-registry/structure.ts
3378
3371
  const STRUCTURE_TOOLS = {
3379
3372
  "depth-anything": {
3380
3373
  category: "preprocess",
@@ -3766,8 +3759,7 @@ const STRUCTURE_TOOLS = {
3766
3759
  task: "depth preprocessing"
3767
3760
  }
3768
3761
  };
3769
- //#endregion
3770
- //#region src/tools.ts
3762
+ // src/tools.ts
3771
3763
  const FAL_TOOLS = {
3772
3764
  ...ANALYSIS_TOOLS,
3773
3765
  ...ASSET_TOOLS,
@@ -3795,8 +3787,7 @@ function buildFalToolRequest(options) {
3795
3787
  tool
3796
3788
  };
3797
3789
  }
3798
- //#endregion
3799
- //#region src/server-tools.ts
3790
+ // src/server-tools.ts
3800
3791
  /**
3801
3792
  * Tool execution bodies for `FalClient`, both synchronous and queued.
3802
3793
  *
@@ -3926,8 +3917,7 @@ async function runToolQueued(exec, options, onProgress) {
3926
3917
  if (request.isErr()) return (0, neverthrow.err)(request.error);
3927
3918
  return (await runRequestQueued(exec, request.value, onProgress)).map(({ data }) => data);
3928
3919
  }
3929
- //#endregion
3930
- //#region src/server.ts
3920
+ // src/server.ts
3931
3921
  const FAL_BASE_URL = "https://fal.run";
3932
3922
  const FAL_QUEUE_URL = "https://queue.fal.run";
3933
3923
  const FAL_API_URL = "https://api.fal.ai";
@@ -4244,8 +4234,7 @@ var FalClient = class {
4244
4234
  });
4245
4235
  }
4246
4236
  };
4247
- //#endregion
4248
- //#region src/source-size.ts
4237
+ // src/source-size.ts
4249
4238
  const DATA_URL_REGEX = /^data:[^;,]*;base64,(.*)$/s;
4250
4239
  function decodeBase64(data) {
4251
4240
  try {
@@ -4343,8 +4332,7 @@ function dataUrlImageSize(url) {
4343
4332
  const size = pngSize(bytes) ?? jpegSize(bytes) ?? webpSize(bytes);
4344
4333
  return size !== void 0 && size.width > 0 && size.height > 0 ? size : void 0;
4345
4334
  }
4346
- //#endregion
4347
- //#region src/tool-cost.ts
4335
+ // src/tool-cost.ts
4348
4336
  /**
4349
4337
  * What a tool run costs, before it happens and after.
4350
4338
  *
@@ -4528,8 +4516,8 @@ function sumCosts(costs) {
4528
4516
  unknown
4529
4517
  };
4530
4518
  }
4531
- //#endregion
4532
- //#region src/image-benchmarks.ts
4519
+ // src/image-benchmarks.ts
4520
+ const MEASURED_ON_2_5 = "Measured on GPT Image 2.5. Motif runs GPT Image 2.6, which Arena has not scored yet.";
4533
4521
  const BOARDS = {
4534
4522
  "text-to-image": {
4535
4523
  sunburst: {
@@ -4537,6 +4525,7 @@ const BOARDS = {
4537
4525
  rank: 1,
4538
4526
  uncertainty: 5,
4539
4527
  evaluatedModel: "GPT-Image-2.5 Sunburst",
4528
+ note: MEASURED_ON_2_5,
4540
4529
  preliminary: true,
4541
4530
  votes: 40323
4542
4531
  },
@@ -4545,6 +4534,7 @@ const BOARDS = {
4545
4534
  rank: 2,
4546
4535
  uncertainty: 5,
4547
4536
  evaluatedModel: "GPT-Image-2.5 Flare",
4537
+ note: MEASURED_ON_2_5,
4548
4538
  preliminary: true,
4549
4539
  votes: 39218
4550
4540
  },
@@ -4634,6 +4624,7 @@ const BOARDS = {
4634
4624
  rank: 1,
4635
4625
  uncertainty: 5,
4636
4626
  evaluatedModel: "GPT-Image-2.5 Sunburst",
4627
+ note: MEASURED_ON_2_5,
4637
4628
  preliminary: true
4638
4629
  },
4639
4630
  flare: {
@@ -4641,6 +4632,7 @@ const BOARDS = {
4641
4632
  rank: 2,
4642
4633
  uncertainty: 5,
4643
4634
  evaluatedModel: "GPT-Image-2.5 Flare",
4635
+ note: MEASURED_ON_2_5,
4644
4636
  preliminary: true
4645
4637
  },
4646
4638
  "grok-image-2": {
@@ -4710,8 +4702,7 @@ function imageModelBenchmark(model, task) {
4710
4702
  task
4711
4703
  };
4712
4704
  }
4713
- //#endregion
4714
- //#region src/tasks.ts
4705
+ // src/tasks.ts
4715
4706
  /**
4716
4707
  * The Task registry: every job Motif does, with the Models that can do it
4717
4708
  * ranked best-first and tagged with the Tier each belongs to.
@@ -5588,8 +5579,7 @@ const TASK_IDS = Object.keys(TASKS).filter(isTaskId);
5588
5579
  function isTaskId(value) {
5589
5580
  return Object.hasOwn(TASKS, value);
5590
5581
  }
5591
- //#endregion
5592
- //#region src/tool-parameters.generated.ts
5582
+ // src/tool-parameters.generated.ts
5593
5583
  const FAL_TOOL_PARAMETERS = {
5594
5584
  "ben-v2": [{
5595
5585
  key: "seed",
@@ -7746,8 +7736,7 @@ const FAL_TOOL_PARAMETERS = {
7746
7736
  function falToolParameters(tool) {
7747
7737
  return FAL_TOOL_PARAMETERS[tool] ?? [];
7748
7738
  }
7749
- //#endregion
7750
- //#region src/resolve.ts
7739
+ // src/resolve.ts
7751
7740
  /**
7752
7741
  * Model choice: the one place a Model is chosen, for the CLI and the SDK.
7753
7742
  *
@@ -7782,6 +7771,7 @@ function generationProfile(config) {
7782
7771
  if (config.supportsNegativePrompt === true) capabilities.add("negativePrompt");
7783
7772
  if (config.supportsOutputFormat === true) capabilities.add("outputFormat");
7784
7773
  return {
7774
+ name: config.name,
7785
7775
  aspects: config.supportedAspects,
7786
7776
  capabilities,
7787
7777
  keys: [FAL_KEY],
@@ -7815,6 +7805,7 @@ function toolProfile(tool) {
7815
7805
  const takesReference = "referenceField" in config;
7816
7806
  if (takesReference) capabilities.add("references");
7817
7807
  return {
7808
+ name: config.name,
7818
7809
  capabilities,
7819
7810
  keys: [FAL_KEY],
7820
7811
  maxReferences: takesReference ? 1 : 0
@@ -8055,8 +8046,7 @@ function tierChangesChoice(task, request, environment) {
8055
8046
  }
8056
8047
  return chosen.size > 1;
8057
8048
  }
8058
- //#endregion
8059
- //#region src/task-output.ts
8049
+ // src/task-output.ts
8060
8050
  function isPlainRecord(value) {
8061
8051
  return typeof value === "object" && value !== null && !Array.isArray(value);
8062
8052
  }
@@ -8181,8 +8171,7 @@ function labelUrls(urls, labels) {
8181
8171
  return names !== void 0 && names.length === totals.get(key) ? names[occurrence] : void 0;
8182
8172
  });
8183
8173
  }
8184
- //#endregion
8185
- //#region src/task-plan-pricing.ts
8174
+ // src/task-plan-pricing.ts
8186
8175
  /**
8187
8176
  * What a generation request bills and which body keys the caller owns. Both
8188
8177
  * read the body as sent, `params` included, because fal bills that body.
@@ -8261,8 +8250,7 @@ function checkParamsImageSize(config, model, task, params) {
8261
8250
  task
8262
8251
  });
8263
8252
  }
8264
- //#endregion
8265
- //#region src/task-plan-tools.ts
8253
+ // src/task-plan-tools.ts
8266
8254
  /**
8267
8255
  * Request bodies for fal tool Models: map each TaskInput field onto the key
8268
8256
  * the tool's generated parameter list names, refuse what it doesn't list, and
@@ -8611,8 +8599,7 @@ function toolPlan(task, model, input) {
8611
8599
  queued: "queued" in tool
8612
8600
  });
8613
8601
  }
8614
- //#endregion
8615
- //#region src/task-plan-video.ts
8602
+ // src/task-plan-video.ts
8616
8603
  /**
8617
8604
  * Request bodies for video Models: Kling v3 Pro and Kling v3 Turbo Pro, which
8618
8605
  * take the start frame under different keys and bill by the second.
@@ -8693,8 +8680,7 @@ function turboVideoPlan(task, endpoint, input) {
8693
8680
  queued: true
8694
8681
  });
8695
8682
  }
8696
- //#endregion
8697
- //#region src/task-plan.ts
8683
+ // src/task-plan.ts
8698
8684
  /**
8699
8685
  * `plan()` for the Task client: resolve the Model, build the request body the
8700
8686
  * Model's kind needs, and price it. Pure: no I/O.
@@ -8995,8 +8981,7 @@ function upscalerPlan(task, model, input) {
8995
8981
  queued: false
8996
8982
  });
8997
8983
  }
8998
- //#endregion
8999
- //#region src/task-stream.ts
8984
+ // src/task-stream.ts
9000
8985
  const MAX_EVENT_CHARACTERS = 16777216;
9001
8986
  const JSON_START = /^[[{]/;
9002
8987
  function parsePayload(text) {
@@ -9275,8 +9260,7 @@ function createFrames(requestId) {
9275
9260
  function enforceBufferLimit(length, requestId) {
9276
9261
  if (length > MAX_EVENT_CHARACTERS) throw new MotifError("Stream event exceeds the buffer limit.", 0, "STREAM_EVENT_TOO_LARGE", requestId);
9277
9262
  }
9278
- //#endregion
9279
- //#region src/task-client.ts
9263
+ // src/task-client.ts
9280
9264
  /**
9281
9265
  * The Task client: one function per Task. `createMotif()` returns a client
9282
9266
  * whose `generate`, `erase`, `upscale` and the rest resolve the Model through
@@ -9452,7 +9436,6 @@ function createMotif(config = {}) {
9452
9436
  }
9453
9437
  };
9454
9438
  }
9455
- //#endregion
9456
9439
  exports.ACCOUNT_LOCKED = ACCOUNT_LOCKED;
9457
9440
  exports.ASPECT_RATIOS = ASPECT_RATIOS;
9458
9441
  exports.CREATIVE_FIELDS = CREATIVE_FIELDS;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,18 @@
1
+ /**
2
+ * Motif SDK: task-first image work over fal.ai.
3
+ *
4
+ * Callers name a task and a tier; Motif picks the model. The per-model registry
5
+ * and the fal client stay internal.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { createMotif } from "@howells/motif-sdk";
10
+ *
11
+ * const motif = createMotif();
12
+ * ```
13
+ */
1
14
  import { Result, Result as Result$1, ResultAsync, err, ok } from "neverthrow";
2
15
  import { z } from "zod";
3
- //#region src/creative.d.ts
4
16
  /**
5
17
  * Creative direction fields applied to prompts in Motif's canonical order.
6
18
  *
@@ -241,8 +253,6 @@ export declare function validateCreativeDirection(creative: CreativeDirection |
241
253
  * are joined with `". "` and closed with a period. With no clauses the sanitized prompt is returned unchanged.
242
254
  */
243
255
  export declare function enrichPrompt(options: EnrichPromptOptions): CreativePromptResult;
244
- //#endregion
245
- //#region src/types.d.ts
246
256
  /** ─── Model Types ─────────────────────────────────────────────── */
247
257
  type AspectRatio = "auto" | "8:1" | "4:1" | "21:9" | "16:9" | "3:2" | "4:3" | "5:4" | "1:1" | "4:5" | "3:4" | "2:3" | "9:16" | "1:4" | "1:8";
248
258
  type Resolution = "0.5K" | "1K" | "2K" | "4K";
@@ -275,8 +285,6 @@ interface JobStatus {
275
285
  /** ─── Configuration ──────────────────────────────────────────── */
276
286
  /** The network seam: a `fetch`-shaped function. */
277
287
  type FalFetch = (url: string, init: RequestInit) => Promise<Response>;
278
- //#endregion
279
- //#region src/aspects.d.ts
280
288
  /** Ordered by popularity: square first, then common ratios */
281
289
  export declare const ASPECT_RATIOS: AspectRatio[];
282
290
  export declare const RESOLUTIONS: Resolution[];
@@ -296,8 +304,6 @@ export declare const FORMAT_PRESETS: Record<string, {
296
304
  aspect: AspectRatio;
297
305
  resolution?: Resolution;
298
306
  }>;
299
- //#endregion
300
- //#region src/errors.d.ts
301
307
  /**
302
308
  * `MotifError` and its coercion helper.
303
309
  *
@@ -325,8 +331,6 @@ export declare const ACCOUNT_LOCKED = "ACCOUNT_LOCKED";
325
331
  * account has run out of credit. Retrying cannot help, and the key is valid.
326
332
  */
327
333
  export declare function isFalAccountLocked(status: number, body: string): boolean;
328
- //#endregion
329
- //#region src/image-benchmarks.d.ts
330
334
  /**
331
335
  * Arena image scores captured for MOT-72 on October 29, 2026. Flare and
332
336
  * Sunburst route to GPT Image 2.6 but keep 2.5's scores until 2.6 is
@@ -340,6 +344,8 @@ interface ArenaScore {
340
344
  readonly uncertainty: number;
341
345
  /** Exact leaderboard label, including a setting where one was reported. */
342
346
  readonly evaluatedModel: string;
347
+ /** Set when the score was measured on a different version than Motif runs. */
348
+ readonly note?: string;
343
349
  readonly preliminary?: true;
344
350
  readonly votes?: number;
345
351
  }
@@ -349,8 +355,6 @@ interface ImageModelBenchmark extends ArenaScore {
349
355
  readonly snapshotDate: string;
350
356
  readonly task: ImageBenchmarkTask;
351
357
  }
352
- //#endregion
353
- //#region src/tasks.d.ts
354
358
  export declare const TIERS: readonly ["fast", "balanced", "quality"];
355
359
  /** How far a Task trades cost and speed for quality. */
356
360
  type Tier = (typeof TIERS)[number];
@@ -958,8 +962,6 @@ export declare const TASKS: {
958
962
  type TaskId = keyof typeof TASKS;
959
963
  export declare const TASK_IDS: readonly TaskId[];
960
964
  export declare function isTaskId(value: string): value is TaskId;
961
- //#endregion
962
- //#region src/resolve.d.ts
963
965
  /** What the request needs. Only the fields that narrow the choice. */
964
966
  interface TaskRequest {
965
967
  /** Explicit Model id, e.g. from `--model`. Overrides everything. */
@@ -1029,6 +1031,8 @@ interface TaskUnresolved {
1029
1031
  }
1030
1032
  type TaskResolution = TaskResolved | TaskUnresolved;
1031
1033
  interface ModelProfile {
1034
+ /** The Model's display name, e.g. "GPT Image 2.6 Sunburst". */
1035
+ readonly name: string;
1032
1036
  readonly capabilities: ReadonlySet<Capability>;
1033
1037
  /** Key variables the Model needs for any request. */
1034
1038
  readonly keys: readonly string[];
@@ -1059,8 +1063,6 @@ export declare function resolveTask(task: TaskId, request: TaskRequest, environm
1059
1063
  * nothing there.
1060
1064
  */
1061
1065
  export declare function tierChangesChoice(task: TaskId, request: Omit<TaskRequest, "tier">, environment: TaskEnvironment): boolean;
1062
- //#endregion
1063
- //#region src/task-stream.d.ts
1064
1066
  interface TaskStreamOptions {
1065
1067
  signal?: AbortSignal;
1066
1068
  /** Overall deadline covering connection and consumption, in milliseconds. */
@@ -1091,8 +1093,6 @@ interface TaskStream {
1091
1093
  /** Stops local consumption; does not guarantee provider cancellation or refund. */
1092
1094
  abort: () => void;
1093
1095
  }
1094
- //#endregion
1095
- //#region src/tool-cost.d.ts
1096
1096
  /** Pixel dimensions of one file an endpoint returned. */
1097
1097
  interface OutputDimensions {
1098
1098
  height?: number;
@@ -1133,8 +1133,6 @@ export declare function sumCosts(costs: readonly (number | null)[]): {
1133
1133
  known: number;
1134
1134
  unknown: number;
1135
1135
  };
1136
- //#endregion
1137
- //#region src/task-client.d.ts
1138
1136
  interface MotifClientConfig {
1139
1137
  /** Falls back to FAL_KEY. */
1140
1138
  falKey?: string;
@@ -1309,11 +1307,7 @@ interface MotifClient {
1309
1307
  }
1310
1308
  /** Create the Task client. The key falls back to FAL_KEY. */
1311
1309
  export declare function createMotif(config?: MotifClientConfig): MotifClient;
1312
- //#endregion
1313
- //#region src/task-plan-shared.d.ts
1314
1310
  export declare const INVALID_OPTION = "INVALID_OPTION";
1315
- //#endregion
1316
- //#region src/prompt-warnings.d.ts
1317
1311
  /**
1318
1312
  * Advisory checks on a user-written prompt.
1319
1313
  *
@@ -1348,8 +1342,6 @@ interface PromptWarning {
1348
1342
  export declare function promptWarnings(prompt: string, context?: {
1349
1343
  editing?: boolean;
1350
1344
  }): PromptWarning[];
1351
- //#endregion
1352
- //#region src/env.d.ts
1353
1345
  export declare const motifEnvSchema: import("@howells/envy").EnvSchema<{
1354
1346
  readonly optional: {
1355
1347
  FAL_KEY: z.ZodString;
@@ -1358,5 +1350,4 @@ export declare const motifEnvSchema: import("@howells/envy").EnvSchema<{
1358
1350
  type MotifEnv = ReturnType<typeof motifEnvSchema.parse>;
1359
1351
  export declare function parseMotifEnv(input?: Record<string, unknown>): MotifEnv;
1360
1352
  export declare function getFalKeyFromEnv(input?: Record<string, unknown>): string | undefined;
1361
- //#endregion
1362
1353
  export { type AspectRatio, type Blocker, type Capability, type ChosenBy, type CreativeDirection, type CreativeField, type CreativeOption, type CreativeOptionErrorDetails, type CreativePromptResult, type CustomImageSize, type EnrichPromptOptions, type FalFetch, type ImageSizeBounds, type LookId, type LookOption, type ModelProfile, type MoodId, type MotifClient, type MotifClientConfig, type MotifEnv, type OutputDimensions, type PlanOptions, type PromptWarning, type PromptWarningRule, type RankedFrom, type RankedModel, type Resolution, type ResolvedCost, type Result, type ResultAsync, type TaskDefinition, type TaskEnvironment, type TaskFile, type TaskFunction, type TaskId, type TaskInput, type TaskMode, type TaskOutput, type TaskPlan, type TaskRequest, type TaskResolution, type TaskResolved, type TaskStream, type TaskStreamEvent, type TaskStreamOptions, type TaskUnresolved, type Tier, type Unblocker, err, ok };