@howells/motif-sdk 7.0.0 → 7.1.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/README.md CHANGED
@@ -34,7 +34,7 @@ Every Task function returns `Result<TaskOutput, MotifError>` from `neverthrow` a
34
34
 
35
35
  ## Curated Models and Tiers
36
36
 
37
- The Task client curates 23 generation Models, with separate rankings for generation and editing. Both follow Arena, read 29 October 2026. `TASKS.generate` and `TASKS.vary` expose the current choices, Tiers and evidence in `basis` and `rankedAt`. A generation with `references` uses the editing ranking.
37
+ The Task client curates 23 generation Models, with separate rankings for generation and editing. Both follow Arena, read 29 October 2026. `TASKS.generate` and `TASKS.vary` expose the current choices, Tiers and evidence in `basis` and `rankedAt`. Sunburst and Flare run GPT Image 2.6; Arena has not scored 2.6 yet, so their benchmarks are the GPT Image 2.5 scores, and each carries a `note` saying so. A generation with `references` uses the editing ranking.
38
38
 
39
39
  | Tier | Generation default | Editing default |
40
40
  | -------------------- | ------------------ | ----------------- |
package/dist/image.d.ts CHANGED
@@ -1,11 +1,25 @@
1
+ /**
2
+ * `@howells/motif-sdk/image` — provider-agnostic image generation + editing.
3
+ *
4
+ * ESM-only subpath export, built on the Vercel AI SDK image interface
5
+ * (`generateImage`, `@ai-sdk/*`). The caller names the provider and model;
6
+ * reuses the SDK's Result convention (`Result<T, MotifError>` — no
7
+ * thrown exceptions). Gemini is reached through OpenRouter.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { createMotifImage } from "@howells/motif-sdk/image";
12
+ *
13
+ * const img = createMotifImage({ defaultProvider: "openrouter" });
14
+ * const r = await img.generate({ model: "gemini-3.1-flash-image", prompt: "a bare concrete wall" });
15
+ * if (r.isOk()) console.log(r.value.images[0].mediaType, r.value.cost);
16
+ * ```
17
+ */
1
18
  import { ImageModel, generateImage } from "ai";
2
19
  import { Result } from "neverthrow";
3
- //#region src/types.d.ts
4
20
  /** ─── Configuration ──────────────────────────────────────────── */
5
21
  /** The network seam: a `fetch`-shaped function. */
6
22
  type FalFetch = (url: string, init: RequestInit) => Promise<Response>;
7
- //#endregion
8
- //#region src/errors.d.ts
9
23
  /**
10
24
  * `MotifError` and its coercion helper.
11
25
  *
@@ -24,8 +38,6 @@ declare class MotifError extends Error {
24
38
  readonly details?: Record<string, unknown>;
25
39
  constructor(message: string, status: number, code?: string, requestId?: string, details?: Record<string, unknown>);
26
40
  }
27
- //#endregion
28
- //#region src/image/types.d.ts
29
41
  /**
30
42
  * Image provider id. All four Phase 1b adapters are implemented
31
43
  * (`openrouter`, `openai`, `replicate`, `fal`); the type keeps an open union tail so
@@ -240,8 +252,6 @@ interface MotifImageClient {
240
252
  */
241
253
  bestOfN: (opts: BestOfNOptions) => Promise<Result<BestOfNResult, MotifError>>;
242
254
  }
243
- //#endregion
244
- //#region src/image/deps.d.ts
245
255
  /** A model resolver: builds an AI SDK `ImageModel` for a (provider, model, key). */
246
256
  type ResolveImageModel = (provider: ImageProviderId, modelId: string, apiKey?: string, fetch?: FalFetch) => ImageModel;
247
257
  /** Internal dependency-injection seam (default: real `generateImage` + adapters). */
@@ -249,8 +259,6 @@ interface MotifImageDeps {
249
259
  generateImage?: typeof generateImage;
250
260
  resolveModel?: ResolveImageModel;
251
261
  }
252
- //#endregion
253
- //#region src/image/provider.d.ts
254
262
  /**
255
263
  * A single image provider. A thin wrapper over the provider's `@ai-sdk/*` image
256
264
  * model, plus the metadata the layer needs to resolve keys and meter spend.
@@ -292,24 +300,14 @@ export declare const PROVIDERS: Record<ImageProviderId, ImageProviderAdapter>;
292
300
  * provider (callers catch this into a `Result.err`).
293
301
  */
294
302
  export declare function getProviderAdapter(provider: ImageProviderId): ImageProviderAdapter;
295
- //#endregion
296
- //#region src/image/openrouter.d.ts
297
303
  /** Env var read for the OpenRouter API key when `apiKey` is not supplied in config. */
298
304
  export declare const OPENROUTER_API_KEY_ENV = "OPENROUTER_API_KEY";
299
- //#endregion
300
- //#region src/image/openai.d.ts
301
305
  /** Env var read for the OpenAI API key when `apiKey` is not supplied in config. */
302
306
  export declare const OPENAI_API_KEY_ENV = "OPENAI_API_KEY";
303
- //#endregion
304
- //#region src/image/replicate.d.ts
305
307
  /** Env var read for the Replicate API token when `apiToken` is not in config. */
306
308
  export declare const REPLICATE_API_KEY_ENV = "REPLICATE_API_TOKEN";
307
- //#endregion
308
- //#region src/image/fal.d.ts
309
309
  /** Env var read for the fal key when `apiKey` is not supplied in config. */
310
310
  export declare const FAL_API_KEY_ENV = "FAL_KEY";
311
- //#endregion
312
- //#region src/image/cost.d.ts
313
311
  /**
314
312
  * Extract a provider-reported total cost from a `generateImage` result's
315
313
  * `providerMetadata`, if the provider surfaces a numeric `cost`. The shape is
@@ -323,8 +321,6 @@ export declare function providerPricePerImageUsd(provider: ImageProviderId, mode
323
321
  * then the static table (× image count), then unknown.
324
322
  */
325
323
  export declare function costForImages(provider: ImageProviderId, modelId: string, providerMetadata: unknown, imageCount: number): ImageCost;
326
- //#endregion
327
- //#region src/image/index.d.ts
328
324
  /**
329
325
  * Create a provider-agnostic image client.
330
326
  *
@@ -333,5 +329,4 @@ export declare function costForImages(provider: ImageProviderId, modelId: string
333
329
  * and the built-in provider adapters; tests inject fakes here to run offline.
334
330
  */
335
331
  export declare function createMotifImage(config?: MotifImageConfig, deps?: MotifImageDeps): MotifImageClient;
336
- //#endregion
337
332
  export type { BestOfNOptions, BestOfNResult, EditImageOptions, GenerateImageOptions, ImageCost, ImageCostSource, ImageJudge, ImageProviderAdapter, ImageProviderId, MotifImageClient, MotifImageConfig, MotifImageFile, MotifImageResult };
package/dist/image.js CHANGED
@@ -3,7 +3,7 @@ import { err, ok } from "neverthrow";
3
3
  import { createFal } from "@ai-sdk/fal";
4
4
  import { createOpenAI } from "@ai-sdk/openai";
5
5
  import { createReplicate } from "@ai-sdk/replicate";
6
- //#region src/errors.ts
6
+ // src/errors.ts
7
7
  /**
8
8
  * `MotifError` and its coercion helper.
9
9
  *
@@ -49,8 +49,7 @@ function falHttpError(status, body, requestId) {
49
49
  if (isFalAccountLocked(status, body)) return new MotifError(`fal account is locked because it is out of credit (fal said: ${body})`, status, ACCOUNT_LOCKED, requestId);
50
50
  return new MotifError(`Request failed: ${status} ${body}`, status, void 0, requestId);
51
51
  }
52
- //#endregion
53
- //#region src/models.ts
52
+ // src/models.ts
54
53
  const AA_IMAGE_LEADERBOARD_SNAPSHOT = "2026-10-07";
55
54
  const AA_IMAGE_SOURCES = ["https://artificialanalysis.ai/image/leaderboard/text-to-image", "https://artificialanalysis.ai/image/leaderboard/editing"];
56
55
  const FAL_PRICING_CHECKED_AT = "2026-05-12";
@@ -1219,8 +1218,7 @@ const MODELS = {
1219
1218
  "ideogram3-transparent",
1220
1219
  "recraft41"
1221
1220
  ].filter((id) => MODELS[id]?.supportsEdit === true);
1222
- //#endregion
1223
- //#region src/capabilities.ts
1221
+ // src/capabilities.ts
1224
1222
  /** Generation options a model can refuse, with the registry test for each. */
1225
1223
  const OPTION_CAPABILITIES = {
1226
1224
  aspect: (config) => (config.sizeMode ?? "aspect_ratio") !== "none",
@@ -1377,8 +1375,7 @@ Object.keys(OPTION_CAPABILITIES).filter(isModelOption);
1377
1375
  }
1378
1376
  ]
1379
1377
  }).look;
1380
- //#endregion
1381
- //#region src/tool-registry/analysis.ts
1378
+ // src/tool-registry/analysis.ts
1382
1379
  const ANALYSIS_TOOLS = {
1383
1380
  "got-ocr": {
1384
1381
  category: "analysis",
@@ -1492,8 +1489,7 @@ const ANALYSIS_TOOLS = {
1492
1489
  task: "vision moderation"
1493
1490
  }
1494
1491
  };
1495
- //#endregion
1496
- //#region src/tool-registry/assets.ts
1492
+ // src/tool-registry/assets.ts
1497
1493
  const ASSET_TOOLS = {
1498
1494
  "hunyuan3d-v3": {
1499
1495
  category: "3d",
@@ -1811,8 +1807,7 @@ const ASSET_TOOLS = {
1811
1807
  task: "single-image 3D reconstruction"
1812
1808
  }
1813
1809
  };
1814
- //#endregion
1815
- //#region src/tool-registry/background.ts
1810
+ // src/tool-registry/background.ts
1816
1811
  const BACKGROUND_TOOLS = {
1817
1812
  "ben-v2": {
1818
1813
  category: "background",
@@ -2187,8 +2182,7 @@ const BACKGROUND_TOOLS = {
2187
2182
  task: "video enhancement"
2188
2183
  }
2189
2184
  };
2190
- //#endregion
2191
- //#region src/tool-registry/editing.ts
2185
+ // src/tool-registry/editing.ts
2192
2186
  const EDITING_TOOLS = {
2193
2187
  "bria-eraser": {
2194
2188
  category: "erase",
@@ -2459,8 +2453,7 @@ const EDITING_TOOLS = {
2459
2453
  task: "virtual garment try-on"
2460
2454
  }
2461
2455
  };
2462
- //#endregion
2463
- //#region src/tool-registry/structure.ts
2456
+ // src/tool-registry/structure.ts
2464
2457
  const STRUCTURE_TOOLS = {
2465
2458
  "depth-anything": {
2466
2459
  category: "preprocess",
@@ -2852,8 +2845,7 @@ const STRUCTURE_TOOLS = {
2852
2845
  task: "depth preprocessing"
2853
2846
  }
2854
2847
  };
2855
- //#endregion
2856
- //#region src/tools.ts
2848
+ // src/tools.ts
2857
2849
  const FAL_TOOLS = {
2858
2850
  ...ANALYSIS_TOOLS,
2859
2851
  ...ASSET_TOOLS,
@@ -2862,8 +2854,7 @@ const FAL_TOOLS = {
2862
2854
  ...STRUCTURE_TOOLS
2863
2855
  };
2864
2856
  Object.keys(FAL_TOOLS);
2865
- //#endregion
2866
- //#region src/image/fetch.ts
2857
+ // src/image/fetch.ts
2867
2858
  function urlOf(input) {
2868
2859
  if (typeof input === "string") return input;
2869
2860
  return input instanceof URL ? input.href : input.url;
@@ -2873,8 +2864,7 @@ function toProviderFetch(fetch) {
2873
2864
  if (fetch === void 0) return {};
2874
2865
  return { fetch: async (input, init) => await fetch(urlOf(input), init ?? {}) };
2875
2866
  }
2876
- //#endregion
2877
- //#region src/image/fal.ts
2867
+ // src/image/fal.ts
2878
2868
  /**
2879
2869
  * fal provider adapter.
2880
2870
  *
@@ -2960,8 +2950,7 @@ const falAdapter = {
2960
2950
  resolveModel: resolveModel$3,
2961
2951
  priceUsdByModel: FAL_IMAGE_PRICE_USD
2962
2952
  };
2963
- //#endregion
2964
- //#region src/image/openai.ts
2953
+ // src/image/openai.ts
2965
2954
  /**
2966
2955
  * OpenAI (gpt-image) provider adapter.
2967
2956
  *
@@ -3007,8 +2996,7 @@ const openaiAdapter = {
3007
2996
  resolveModel: resolveModel$2,
3008
2997
  priceUsdByModel: OPENAI_IMAGE_PRICE_USD
3009
2998
  };
3010
- //#endregion
3011
- //#region src/image/openrouter.ts
2999
+ // src/image/openrouter.ts
3012
3000
  /** Env var read for the OpenRouter API key when `apiKey` is not supplied in config. */
3013
3001
  const OPENROUTER_API_KEY_ENV = "OPENROUTER_API_KEY";
3014
3002
  const OPENROUTER_IMAGES_URL = "https://openrouter.ai/api/v1/images";
@@ -3171,8 +3159,7 @@ const openrouterAdapter = {
3171
3159
  resolveModel: resolveModel$1,
3172
3160
  priceUsdByModel: OPENROUTER_IMAGE_PRICE_USD
3173
3161
  };
3174
- //#endregion
3175
- //#region src/image/replicate.ts
3162
+ // src/image/replicate.ts
3176
3163
  /**
3177
3164
  * Replicate provider adapter.
3178
3165
  *
@@ -3207,8 +3194,7 @@ function resolveModel(modelId, apiKey, fetch) {
3207
3194
  ...toProviderFetch(fetch)
3208
3195
  }).image(modelId);
3209
3196
  }
3210
- //#endregion
3211
- //#region src/image/provider.ts
3197
+ // src/image/provider.ts
3212
3198
  /**
3213
3199
  * The provider registry. Every id in {@link ImageProviderId}'s closed part maps
3214
3200
  * to its adapter; the open union tail means a lookup can still miss, so access
@@ -3234,8 +3220,7 @@ function getProviderAdapter(provider) {
3234
3220
  if (adapter === void 0) throw new MotifError(`Unsupported image provider: ${provider}`, 0);
3235
3221
  return adapter;
3236
3222
  }
3237
- //#endregion
3238
- //#region src/image/cost.ts
3223
+ // src/image/cost.ts
3239
3224
  /**
3240
3225
  * Per-call cost tracking for the image layer.
3241
3226
  *
@@ -3305,8 +3290,7 @@ function costForCalls(provider, modelId, callMetadata, imageCount) {
3305
3290
  source: "unknown"
3306
3291
  };
3307
3292
  }
3308
- //#endregion
3309
- //#region src/image/index.ts
3293
+ // src/image/index.ts
3310
3294
  /**
3311
3295
  * `@howells/motif-sdk/image` — provider-agnostic image generation + editing.
3312
3296
  *
@@ -3578,5 +3562,4 @@ function toMotifError(error) {
3578
3562
  if (isFalAccountLocked(status, body)) return falHttpError(status, body);
3579
3563
  return new MotifError(message, status, code);
3580
3564
  }
3581
- //#endregion
3582
3565
  export { FAL_API_KEY_ENV, OPENAI_API_KEY_ENV, OPENROUTER_API_KEY_ENV, PROVIDERS, REPLICATE_API_KEY_ENV, costForImages, costFromProviderMetadata, createMotifImage, getProviderAdapter, providerPricePerImageUsd };
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",
@@ -237,8 +237,7 @@ const FORMAT_PRESETS = {
237
237
  label: "Wide"
238
238
  }
239
239
  };
240
- //#endregion
241
- //#region src/creative.ts
240
+ // src/creative.ts
242
241
  const CONTROL_CHAR_REGEX = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g;
243
242
  const TRAILING_PERIODS_REGEX = /\.+$/;
244
243
  /**
@@ -480,8 +479,7 @@ function enrichPrompt(options) {
480
479
  prompt: clauses.length ? joinSentences([basePrompt, ...clauses].filter((part) => part !== "")) : basePrompt
481
480
  };
482
481
  }
483
- //#endregion
484
- //#region src/errors.ts
482
+ // src/errors.ts
485
483
  /**
486
484
  * `MotifError` and its coercion helper.
487
485
  *
@@ -538,8 +536,7 @@ function toMotifError(error) {
538
536
  if (error instanceof MotifError) return error;
539
537
  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
538
  }
541
- //#endregion
542
- //#region src/task-plan-shared.ts
539
+ // src/task-plan-shared.ts
543
540
  /**
544
541
  * Helpers every request builder in the Task planner shares: refusing fields a
545
542
  * Model can't carry, and merging `params` without letting them replace what
@@ -619,8 +616,7 @@ function mergeParams(body, params, owned) {
619
616
  ...params
620
617
  });
621
618
  }
622
- //#endregion
623
- //#region src/prompt-warnings.ts
619
+ // src/prompt-warnings.ts
624
620
  const EDIT_VERB_REGEX = /^\s*(remove|erase|extend|outpaint)\b/i;
625
621
  /** The CLI verb that does each edit directly, keyed by the prompt's first word. */
626
622
  const EDIT_VERBS = {
@@ -686,8 +682,7 @@ function promptWarnings(prompt, context = {}) {
686
682
  });
687
683
  return warnings;
688
684
  }
689
- //#endregion
690
- //#region src/env.ts
685
+ // src/env.ts
691
686
  const motifEnvSchema = (0, _howells_envy.defineEnv)({ optional: { FAL_KEY: zod.z.string().min(1) } });
692
687
  function parseMotifEnv(input = process.env) {
693
688
  return motifEnvSchema.parse(input);
@@ -695,8 +690,7 @@ function parseMotifEnv(input = process.env) {
695
690
  function getFalKeyFromEnv(input = process.env) {
696
691
  return parseMotifEnv(input).FAL_KEY;
697
692
  }
698
- //#endregion
699
- //#region src/models.ts
693
+ // src/models.ts
700
694
  const AA_IMAGE_LEADERBOARD_SNAPSHOT = "2026-10-07";
701
695
  const AA_IMAGE_SOURCES = ["https://artificialanalysis.ai/image/leaderboard/text-to-image", "https://artificialanalysis.ai/image/leaderboard/editing"];
702
696
  const FAL_PRICING_CHECKED_AT = "2026-05-12";
@@ -1867,8 +1861,7 @@ const GENERATION_MODELS = [
1867
1861
  "recraft41"
1868
1862
  ];
1869
1863
  GENERATION_MODELS.filter((id) => MODELS[id]?.supportsEdit === true);
1870
- //#endregion
1871
- //#region src/cost.ts
1864
+ // src/cost.ts
1872
1865
  /**
1873
1866
  * Estimate cost based on model and settings. `editImages` is the number of
1874
1867
  * input images on an edit, for Models whose edits cost more than generation.
@@ -1898,8 +1891,7 @@ function estimateVideoCost(durationSeconds = 5, generateAudio = true, model = "k
1898
1891
  if (model === "kling-turbo") return .14 * durationSeconds;
1899
1892
  return (generateAudio ? .168 : .112) * durationSeconds;
1900
1893
  }
1901
- //#endregion
1902
- //#region src/fal-parse.ts
1894
+ // src/fal-parse.ts
1903
1895
  /**
1904
1896
  * Boundary parsing for fal.ai HTTP responses.
1905
1897
  *
@@ -2004,8 +1996,7 @@ function requestIdFromBody(text) {
2004
1996
  if (!isRecord$1(parsed)) return;
2005
1997
  return asString(parsed.request_id) ?? asString(parsed.requestId) ?? asString(parsed.trace_id);
2006
1998
  }
2007
- //#endregion
2008
- //#region src/capabilities.ts
1999
+ // src/capabilities.ts
2009
2000
  /**
2010
2001
  * Which generation options each model accepts, derived from the registry.
2011
2002
  *
@@ -2095,8 +2086,7 @@ var UnsupportedOptionError = class extends Error {
2095
2086
  this.supportedOptions = supported;
2096
2087
  }
2097
2088
  };
2098
- //#endregion
2099
- //#region src/generate.ts
2089
+ // src/generate.ts
2100
2090
  const GPT_IMAGE_SIZES = [
2101
2091
  "auto",
2102
2092
  "1024x1024",
@@ -2291,8 +2281,7 @@ function buildGenerateBody(options) {
2291
2281
  endpoint
2292
2282
  };
2293
2283
  }
2294
- //#endregion
2295
- //#region src/tool-registry/analysis.ts
2284
+ // src/tool-registry/analysis.ts
2296
2285
  const ANALYSIS_TOOLS = {
2297
2286
  "got-ocr": {
2298
2287
  category: "analysis",
@@ -2406,8 +2395,7 @@ const ANALYSIS_TOOLS = {
2406
2395
  task: "vision moderation"
2407
2396
  }
2408
2397
  };
2409
- //#endregion
2410
- //#region src/tool-registry/assets.ts
2398
+ // src/tool-registry/assets.ts
2411
2399
  const ASSET_TOOLS = {
2412
2400
  "hunyuan3d-v3": {
2413
2401
  category: "3d",
@@ -2725,8 +2713,7 @@ const ASSET_TOOLS = {
2725
2713
  task: "single-image 3D reconstruction"
2726
2714
  }
2727
2715
  };
2728
- //#endregion
2729
- //#region src/tool-registry/background.ts
2716
+ // src/tool-registry/background.ts
2730
2717
  const BACKGROUND_TOOLS = {
2731
2718
  "ben-v2": {
2732
2719
  category: "background",
@@ -3101,8 +3088,7 @@ const BACKGROUND_TOOLS = {
3101
3088
  task: "video enhancement"
3102
3089
  }
3103
3090
  };
3104
- //#endregion
3105
- //#region src/tool-registry/editing.ts
3091
+ // src/tool-registry/editing.ts
3106
3092
  const EDITING_TOOLS = {
3107
3093
  "bria-eraser": {
3108
3094
  category: "erase",
@@ -3373,8 +3359,7 @@ const EDITING_TOOLS = {
3373
3359
  task: "virtual garment try-on"
3374
3360
  }
3375
3361
  };
3376
- //#endregion
3377
- //#region src/tool-registry/structure.ts
3362
+ // src/tool-registry/structure.ts
3378
3363
  const STRUCTURE_TOOLS = {
3379
3364
  "depth-anything": {
3380
3365
  category: "preprocess",
@@ -3766,8 +3751,7 @@ const STRUCTURE_TOOLS = {
3766
3751
  task: "depth preprocessing"
3767
3752
  }
3768
3753
  };
3769
- //#endregion
3770
- //#region src/tools.ts
3754
+ // src/tools.ts
3771
3755
  const FAL_TOOLS = {
3772
3756
  ...ANALYSIS_TOOLS,
3773
3757
  ...ASSET_TOOLS,
@@ -3795,8 +3779,7 @@ function buildFalToolRequest(options) {
3795
3779
  tool
3796
3780
  };
3797
3781
  }
3798
- //#endregion
3799
- //#region src/server-tools.ts
3782
+ // src/server-tools.ts
3800
3783
  /**
3801
3784
  * Tool execution bodies for `FalClient`, both synchronous and queued.
3802
3785
  *
@@ -3926,8 +3909,7 @@ async function runToolQueued(exec, options, onProgress) {
3926
3909
  if (request.isErr()) return (0, neverthrow.err)(request.error);
3927
3910
  return (await runRequestQueued(exec, request.value, onProgress)).map(({ data }) => data);
3928
3911
  }
3929
- //#endregion
3930
- //#region src/server.ts
3912
+ // src/server.ts
3931
3913
  const FAL_BASE_URL = "https://fal.run";
3932
3914
  const FAL_QUEUE_URL = "https://queue.fal.run";
3933
3915
  const FAL_API_URL = "https://api.fal.ai";
@@ -4244,8 +4226,7 @@ var FalClient = class {
4244
4226
  });
4245
4227
  }
4246
4228
  };
4247
- //#endregion
4248
- //#region src/source-size.ts
4229
+ // src/source-size.ts
4249
4230
  const DATA_URL_REGEX = /^data:[^;,]*;base64,(.*)$/s;
4250
4231
  function decodeBase64(data) {
4251
4232
  try {
@@ -4343,8 +4324,7 @@ function dataUrlImageSize(url) {
4343
4324
  const size = pngSize(bytes) ?? jpegSize(bytes) ?? webpSize(bytes);
4344
4325
  return size !== void 0 && size.width > 0 && size.height > 0 ? size : void 0;
4345
4326
  }
4346
- //#endregion
4347
- //#region src/tool-cost.ts
4327
+ // src/tool-cost.ts
4348
4328
  /**
4349
4329
  * What a tool run costs, before it happens and after.
4350
4330
  *
@@ -4528,8 +4508,8 @@ function sumCosts(costs) {
4528
4508
  unknown
4529
4509
  };
4530
4510
  }
4531
- //#endregion
4532
- //#region src/image-benchmarks.ts
4511
+ // src/image-benchmarks.ts
4512
+ const MEASURED_ON_2_5 = "Measured on GPT Image 2.5. Motif runs GPT Image 2.6, which Arena has not scored yet.";
4533
4513
  const BOARDS = {
4534
4514
  "text-to-image": {
4535
4515
  sunburst: {
@@ -4537,6 +4517,7 @@ const BOARDS = {
4537
4517
  rank: 1,
4538
4518
  uncertainty: 5,
4539
4519
  evaluatedModel: "GPT-Image-2.5 Sunburst",
4520
+ note: MEASURED_ON_2_5,
4540
4521
  preliminary: true,
4541
4522
  votes: 40323
4542
4523
  },
@@ -4545,6 +4526,7 @@ const BOARDS = {
4545
4526
  rank: 2,
4546
4527
  uncertainty: 5,
4547
4528
  evaluatedModel: "GPT-Image-2.5 Flare",
4529
+ note: MEASURED_ON_2_5,
4548
4530
  preliminary: true,
4549
4531
  votes: 39218
4550
4532
  },
@@ -4634,6 +4616,7 @@ const BOARDS = {
4634
4616
  rank: 1,
4635
4617
  uncertainty: 5,
4636
4618
  evaluatedModel: "GPT-Image-2.5 Sunburst",
4619
+ note: MEASURED_ON_2_5,
4637
4620
  preliminary: true
4638
4621
  },
4639
4622
  flare: {
@@ -4641,6 +4624,7 @@ const BOARDS = {
4641
4624
  rank: 2,
4642
4625
  uncertainty: 5,
4643
4626
  evaluatedModel: "GPT-Image-2.5 Flare",
4627
+ note: MEASURED_ON_2_5,
4644
4628
  preliminary: true
4645
4629
  },
4646
4630
  "grok-image-2": {
@@ -4710,8 +4694,7 @@ function imageModelBenchmark(model, task) {
4710
4694
  task
4711
4695
  };
4712
4696
  }
4713
- //#endregion
4714
- //#region src/tasks.ts
4697
+ // src/tasks.ts
4715
4698
  /**
4716
4699
  * The Task registry: every job Motif does, with the Models that can do it
4717
4700
  * ranked best-first and tagged with the Tier each belongs to.
@@ -5588,8 +5571,7 @@ const TASK_IDS = Object.keys(TASKS).filter(isTaskId);
5588
5571
  function isTaskId(value) {
5589
5572
  return Object.hasOwn(TASKS, value);
5590
5573
  }
5591
- //#endregion
5592
- //#region src/tool-parameters.generated.ts
5574
+ // src/tool-parameters.generated.ts
5593
5575
  const FAL_TOOL_PARAMETERS = {
5594
5576
  "ben-v2": [{
5595
5577
  key: "seed",
@@ -7746,8 +7728,7 @@ const FAL_TOOL_PARAMETERS = {
7746
7728
  function falToolParameters(tool) {
7747
7729
  return FAL_TOOL_PARAMETERS[tool] ?? [];
7748
7730
  }
7749
- //#endregion
7750
- //#region src/resolve.ts
7731
+ // src/resolve.ts
7751
7732
  /**
7752
7733
  * Model choice: the one place a Model is chosen, for the CLI and the SDK.
7753
7734
  *
@@ -7782,6 +7763,7 @@ function generationProfile(config) {
7782
7763
  if (config.supportsNegativePrompt === true) capabilities.add("negativePrompt");
7783
7764
  if (config.supportsOutputFormat === true) capabilities.add("outputFormat");
7784
7765
  return {
7766
+ name: config.name,
7785
7767
  aspects: config.supportedAspects,
7786
7768
  capabilities,
7787
7769
  keys: [FAL_KEY],
@@ -7815,6 +7797,7 @@ function toolProfile(tool) {
7815
7797
  const takesReference = "referenceField" in config;
7816
7798
  if (takesReference) capabilities.add("references");
7817
7799
  return {
7800
+ name: config.name,
7818
7801
  capabilities,
7819
7802
  keys: [FAL_KEY],
7820
7803
  maxReferences: takesReference ? 1 : 0
@@ -8055,8 +8038,7 @@ function tierChangesChoice(task, request, environment) {
8055
8038
  }
8056
8039
  return chosen.size > 1;
8057
8040
  }
8058
- //#endregion
8059
- //#region src/task-output.ts
8041
+ // src/task-output.ts
8060
8042
  function isPlainRecord(value) {
8061
8043
  return typeof value === "object" && value !== null && !Array.isArray(value);
8062
8044
  }
@@ -8181,8 +8163,7 @@ function labelUrls(urls, labels) {
8181
8163
  return names !== void 0 && names.length === totals.get(key) ? names[occurrence] : void 0;
8182
8164
  });
8183
8165
  }
8184
- //#endregion
8185
- //#region src/task-plan-pricing.ts
8166
+ // src/task-plan-pricing.ts
8186
8167
  /**
8187
8168
  * What a generation request bills and which body keys the caller owns. Both
8188
8169
  * read the body as sent, `params` included, because fal bills that body.
@@ -8261,8 +8242,7 @@ function checkParamsImageSize(config, model, task, params) {
8261
8242
  task
8262
8243
  });
8263
8244
  }
8264
- //#endregion
8265
- //#region src/task-plan-tools.ts
8245
+ // src/task-plan-tools.ts
8266
8246
  /**
8267
8247
  * Request bodies for fal tool Models: map each TaskInput field onto the key
8268
8248
  * the tool's generated parameter list names, refuse what it doesn't list, and
@@ -8611,8 +8591,7 @@ function toolPlan(task, model, input) {
8611
8591
  queued: "queued" in tool
8612
8592
  });
8613
8593
  }
8614
- //#endregion
8615
- //#region src/task-plan-video.ts
8594
+ // src/task-plan-video.ts
8616
8595
  /**
8617
8596
  * Request bodies for video Models: Kling v3 Pro and Kling v3 Turbo Pro, which
8618
8597
  * take the start frame under different keys and bill by the second.
@@ -8693,8 +8672,7 @@ function turboVideoPlan(task, endpoint, input) {
8693
8672
  queued: true
8694
8673
  });
8695
8674
  }
8696
- //#endregion
8697
- //#region src/task-plan.ts
8675
+ // src/task-plan.ts
8698
8676
  /**
8699
8677
  * `plan()` for the Task client: resolve the Model, build the request body the
8700
8678
  * Model's kind needs, and price it. Pure: no I/O.
@@ -8995,8 +8973,7 @@ function upscalerPlan(task, model, input) {
8995
8973
  queued: false
8996
8974
  });
8997
8975
  }
8998
- //#endregion
8999
- //#region src/task-stream.ts
8976
+ // src/task-stream.ts
9000
8977
  const MAX_EVENT_CHARACTERS = 16777216;
9001
8978
  const JSON_START = /^[[{]/;
9002
8979
  function parsePayload(text) {
@@ -9275,8 +9252,7 @@ function createFrames(requestId) {
9275
9252
  function enforceBufferLimit(length, requestId) {
9276
9253
  if (length > MAX_EVENT_CHARACTERS) throw new MotifError("Stream event exceeds the buffer limit.", 0, "STREAM_EVENT_TOO_LARGE", requestId);
9277
9254
  }
9278
- //#endregion
9279
- //#region src/task-client.ts
9255
+ // src/task-client.ts
9280
9256
  /**
9281
9257
  * The Task client: one function per Task. `createMotif()` returns a client
9282
9258
  * whose `generate`, `erase`, `upscale` and the rest resolve the Model through
@@ -9452,7 +9428,6 @@ function createMotif(config = {}) {
9452
9428
  }
9453
9429
  };
9454
9430
  }
9455
- //#endregion
9456
9431
  exports.ACCOUNT_LOCKED = ACCOUNT_LOCKED;
9457
9432
  exports.ASPECT_RATIOS = ASPECT_RATIOS;
9458
9433
  exports.CREATIVE_FIELDS = CREATIVE_FIELDS;