@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 +1 -1
- package/dist/image.d.ts +17 -22
- package/dist/image.js +17 -34
- package/dist/index.cjs +39 -64
- package/dist/index.d.cts +17 -26
- package/dist/index.d.ts +17 -26
- package/dist/index.js +39 -64
- package/dist/registry.d.ts +5 -12
- package/dist/registry.js +9 -18
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4532
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|