@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/README.md +1 -1
- package/dist/image.d.ts +17 -22
- package/dist/image.js +19 -36
- package/dist/index.cjs +55 -72
- package/dist/index.d.cts +17 -26
- package/dist/index.d.ts +17 -26
- package/dist/index.js +55 -72
- package/dist/registry.d.ts +5 -12
- package/dist/registry.js +11 -20
- package/package.json +1 -1
package/dist/index.d.ts
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 };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { err, err as err$1, ok, ok as ok$1 } from "neverthrow";
|
|
2
2
|
import { defineEnv } from "@howells/envy";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
|
|
4
|
+
// src/aspects.ts
|
|
5
5
|
/** Ordered by popularity: square first, then common ratios */
|
|
6
6
|
const ASPECT_RATIOS = [
|
|
7
7
|
"auto",
|
|
@@ -141,6 +141,9 @@ function scaleWithin(longEdge, longTerm, unit) {
|
|
|
141
141
|
function roundUpTo(value, unit) {
|
|
142
142
|
return unit * Math.ceil(value / unit);
|
|
143
143
|
}
|
|
144
|
+
function roundDownTo(value, unit) {
|
|
145
|
+
return unit * Math.floor(value / unit);
|
|
146
|
+
}
|
|
144
147
|
/**
|
|
145
148
|
* Exact pixel dimensions for an aspect ratio at a resolution tier, or null for
|
|
146
149
|
* `"auto"`.
|
|
@@ -170,8 +173,9 @@ function withinImageSizeBounds(size, bounds) {
|
|
|
170
173
|
}
|
|
171
174
|
/**
|
|
172
175
|
* The exact size for an aspect on an endpoint with limits: the long edge as
|
|
173
|
-
* close to `longEdge` as the ratio allows without passing it
|
|
174
|
-
* only as far as a minimum edge or
|
|
176
|
+
* close to `longEdge` as the ratio allows without passing it or the endpoint's
|
|
177
|
+
* maximum edge or pixel count, then scaled up only as far as a minimum edge or
|
|
178
|
+
* pixel count demands. Null for `"auto"`.
|
|
175
179
|
* Undefined when no size in that ratio fits the limits: the caller refuses,
|
|
176
180
|
* because rounding to another ratio is the defect this exists to remove.
|
|
177
181
|
*/
|
|
@@ -181,6 +185,8 @@ function boundedImageSize(aspect, longEdge, bounds) {
|
|
|
181
185
|
const [width, height] = terms;
|
|
182
186
|
const unit = bounds.multipleOf ?? EDGE_MULTIPLE;
|
|
183
187
|
let scale = scaleWithin(longEdge, Math.max(width, height), unit);
|
|
188
|
+
if (bounds.maxEdge !== void 0) scale = Math.min(scale, roundDownTo(bounds.maxEdge / Math.max(width, height), unit));
|
|
189
|
+
if (bounds.maxPixels !== void 0) scale = Math.min(scale, roundDownTo(Math.sqrt(bounds.maxPixels / (width * height)), unit));
|
|
184
190
|
if (bounds.minEdge !== void 0) scale = Math.max(scale, roundUpTo(bounds.minEdge / Math.min(width, height), unit));
|
|
185
191
|
if (bounds.minPixels !== void 0) scale = Math.max(scale, roundUpTo(Math.sqrt(bounds.minPixels / (width * height)), unit));
|
|
186
192
|
const size = {
|
|
@@ -236,8 +242,7 @@ const FORMAT_PRESETS = {
|
|
|
236
242
|
label: "Wide"
|
|
237
243
|
}
|
|
238
244
|
};
|
|
239
|
-
|
|
240
|
-
//#region src/creative.ts
|
|
245
|
+
// src/creative.ts
|
|
241
246
|
const CONTROL_CHAR_REGEX = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g;
|
|
242
247
|
const TRAILING_PERIODS_REGEX = /\.+$/;
|
|
243
248
|
/**
|
|
@@ -479,8 +484,7 @@ function enrichPrompt(options) {
|
|
|
479
484
|
prompt: clauses.length ? joinSentences([basePrompt, ...clauses].filter((part) => part !== "")) : basePrompt
|
|
480
485
|
};
|
|
481
486
|
}
|
|
482
|
-
|
|
483
|
-
//#region src/errors.ts
|
|
487
|
+
// src/errors.ts
|
|
484
488
|
/**
|
|
485
489
|
* `MotifError` and its coercion helper.
|
|
486
490
|
*
|
|
@@ -537,8 +541,7 @@ function toMotifError(error) {
|
|
|
537
541
|
if (error instanceof MotifError) return error;
|
|
538
542
|
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);
|
|
539
543
|
}
|
|
540
|
-
|
|
541
|
-
//#region src/task-plan-shared.ts
|
|
544
|
+
// src/task-plan-shared.ts
|
|
542
545
|
/**
|
|
543
546
|
* Helpers every request builder in the Task planner shares: refusing fields a
|
|
544
547
|
* Model can't carry, and merging `params` without letting them replace what
|
|
@@ -618,8 +621,7 @@ function mergeParams(body, params, owned) {
|
|
|
618
621
|
...params
|
|
619
622
|
});
|
|
620
623
|
}
|
|
621
|
-
|
|
622
|
-
//#region src/prompt-warnings.ts
|
|
624
|
+
// src/prompt-warnings.ts
|
|
623
625
|
const EDIT_VERB_REGEX = /^\s*(remove|erase|extend|outpaint)\b/i;
|
|
624
626
|
/** The CLI verb that does each edit directly, keyed by the prompt's first word. */
|
|
625
627
|
const EDIT_VERBS = {
|
|
@@ -685,8 +687,7 @@ function promptWarnings(prompt, context = {}) {
|
|
|
685
687
|
});
|
|
686
688
|
return warnings;
|
|
687
689
|
}
|
|
688
|
-
|
|
689
|
-
//#region src/env.ts
|
|
690
|
+
// src/env.ts
|
|
690
691
|
const motifEnvSchema = defineEnv({ optional: { FAL_KEY: z.string().min(1) } });
|
|
691
692
|
function parseMotifEnv(input = process.env) {
|
|
692
693
|
return motifEnvSchema.parse(input);
|
|
@@ -694,8 +695,7 @@ function parseMotifEnv(input = process.env) {
|
|
|
694
695
|
function getFalKeyFromEnv(input = process.env) {
|
|
695
696
|
return parseMotifEnv(input).FAL_KEY;
|
|
696
697
|
}
|
|
697
|
-
|
|
698
|
-
//#region src/models.ts
|
|
698
|
+
// src/models.ts
|
|
699
699
|
const AA_IMAGE_LEADERBOARD_SNAPSHOT = "2026-10-07";
|
|
700
700
|
const AA_IMAGE_SOURCES = ["https://artificialanalysis.ai/image/leaderboard/text-to-image", "https://artificialanalysis.ai/image/leaderboard/editing"];
|
|
701
701
|
const FAL_PRICING_CHECKED_AT = "2026-05-12";
|
|
@@ -765,7 +765,7 @@ const MODELS = {
|
|
|
765
765
|
"xhigh",
|
|
766
766
|
"max"
|
|
767
767
|
],
|
|
768
|
-
supportsResolution:
|
|
768
|
+
supportsResolution: true,
|
|
769
769
|
supportsSyncMode: true,
|
|
770
770
|
type: "generation",
|
|
771
771
|
useQueue: true
|
|
@@ -832,7 +832,7 @@ const MODELS = {
|
|
|
832
832
|
"xhigh",
|
|
833
833
|
"max"
|
|
834
834
|
],
|
|
835
|
-
supportsResolution:
|
|
835
|
+
supportsResolution: true,
|
|
836
836
|
supportsSyncMode: true,
|
|
837
837
|
type: "generation",
|
|
838
838
|
useQueue: true
|
|
@@ -1866,8 +1866,7 @@ const GENERATION_MODELS = [
|
|
|
1866
1866
|
"recraft41"
|
|
1867
1867
|
];
|
|
1868
1868
|
GENERATION_MODELS.filter((id) => MODELS[id]?.supportsEdit === true);
|
|
1869
|
-
|
|
1870
|
-
//#region src/cost.ts
|
|
1869
|
+
// src/cost.ts
|
|
1871
1870
|
/**
|
|
1872
1871
|
* Estimate cost based on model and settings. `editImages` is the number of
|
|
1873
1872
|
* input images on an edit, for Models whose edits cost more than generation.
|
|
@@ -1897,8 +1896,7 @@ function estimateVideoCost(durationSeconds = 5, generateAudio = true, model = "k
|
|
|
1897
1896
|
if (model === "kling-turbo") return .14 * durationSeconds;
|
|
1898
1897
|
return (generateAudio ? .168 : .112) * durationSeconds;
|
|
1899
1898
|
}
|
|
1900
|
-
|
|
1901
|
-
//#region src/fal-parse.ts
|
|
1899
|
+
// src/fal-parse.ts
|
|
1902
1900
|
/**
|
|
1903
1901
|
* Boundary parsing for fal.ai HTTP responses.
|
|
1904
1902
|
*
|
|
@@ -2003,8 +2001,7 @@ function requestIdFromBody(text) {
|
|
|
2003
2001
|
if (!isRecord$1(parsed)) return;
|
|
2004
2002
|
return asString(parsed.request_id) ?? asString(parsed.requestId) ?? asString(parsed.trace_id);
|
|
2005
2003
|
}
|
|
2006
|
-
|
|
2007
|
-
//#region src/capabilities.ts
|
|
2004
|
+
// src/capabilities.ts
|
|
2008
2005
|
/**
|
|
2009
2006
|
* Which generation options each model accepts, derived from the registry.
|
|
2010
2007
|
*
|
|
@@ -2094,8 +2091,7 @@ var UnsupportedOptionError = class extends Error {
|
|
|
2094
2091
|
this.supportedOptions = supported;
|
|
2095
2092
|
}
|
|
2096
2093
|
};
|
|
2097
|
-
|
|
2098
|
-
//#region src/generate.ts
|
|
2094
|
+
// src/generate.ts
|
|
2099
2095
|
const GPT_IMAGE_SIZES = [
|
|
2100
2096
|
"auto",
|
|
2101
2097
|
"1024x1024",
|
|
@@ -2133,15 +2129,16 @@ function normalizeImageSize(imageSize, sizeMode) {
|
|
|
2133
2129
|
throw new Error(`fal image_size must be one of ${FAL_IMAGE_SIZE_PRESETS.join(", ")} or WIDTHxHEIGHT`);
|
|
2134
2130
|
}
|
|
2135
2131
|
/**
|
|
2136
|
-
* `image_size` for an aspect:
|
|
2137
|
-
*
|
|
2138
|
-
*
|
|
2132
|
+
* `image_size` for an aspect: exact dimensions at the requested resolution
|
|
2133
|
+
* where the endpoint takes them and has a resolution setting; otherwise fal's
|
|
2134
|
+
* named preset where one holds the ratio exactly, else exact dimensions where
|
|
2135
|
+
* the endpoint takes them, else the nearest preset. A Model without a resolution setting is sized to the preset
|
|
2139
2136
|
* long edge, so an exact size costs what a preset would. Out of the Model's
|
|
2140
2137
|
* limits it throws rather than rounding to another ratio.
|
|
2141
2138
|
*/
|
|
2142
2139
|
function falImageSizeFor(config, aspect, resolution) {
|
|
2143
2140
|
const bounds = config.customImageSize;
|
|
2144
|
-
if (bounds === void 0 || FAL_PRESET_ASPECTS.includes(aspect)) return aspectToFalImageSize(aspect);
|
|
2141
|
+
if (bounds === void 0 || !config.supportsResolution && FAL_PRESET_ASPECTS.includes(aspect)) return aspectToFalImageSize(aspect);
|
|
2145
2142
|
const size = boundedImageSize(aspect, config.supportsResolution ? RESOLUTION_LONG_EDGE[resolution] : FAL_PRESET_LONG_EDGE, bounds);
|
|
2146
2143
|
if (size === void 0) throw new ImageSizeBoundsError(config.name, aspect, bounds);
|
|
2147
2144
|
return size ?? aspectToFalImageSize(aspect);
|
|
@@ -2154,6 +2151,7 @@ function validateGenerateOptions(options, config, sizeMode, hasEditImages) {
|
|
|
2154
2151
|
if (options.editImageUrls !== void 0 && options.editImageUrls.length > 0 && !config.supportsEdit) unsupported(config, "image editing");
|
|
2155
2152
|
if (options.aspect !== void 0 && sizeMode === "none") unsupported(config, "aspect");
|
|
2156
2153
|
if (options.resolution !== void 0 && options.resolution !== "2K" && !config.supportsResolution) unsupported(config, "resolution");
|
|
2154
|
+
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`);
|
|
2157
2155
|
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(", ")}`);
|
|
2158
2156
|
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(", ")}`);
|
|
2159
2157
|
if (options.numImages !== void 0 && options.numImages !== 1 && !config.supportsNumImages) unsupported(config, "numImages");
|
|
@@ -2290,8 +2288,7 @@ function buildGenerateBody(options) {
|
|
|
2290
2288
|
endpoint
|
|
2291
2289
|
};
|
|
2292
2290
|
}
|
|
2293
|
-
|
|
2294
|
-
//#region src/tool-registry/analysis.ts
|
|
2291
|
+
// src/tool-registry/analysis.ts
|
|
2295
2292
|
const ANALYSIS_TOOLS = {
|
|
2296
2293
|
"got-ocr": {
|
|
2297
2294
|
category: "analysis",
|
|
@@ -2405,8 +2402,7 @@ const ANALYSIS_TOOLS = {
|
|
|
2405
2402
|
task: "vision moderation"
|
|
2406
2403
|
}
|
|
2407
2404
|
};
|
|
2408
|
-
|
|
2409
|
-
//#region src/tool-registry/assets.ts
|
|
2405
|
+
// src/tool-registry/assets.ts
|
|
2410
2406
|
const ASSET_TOOLS = {
|
|
2411
2407
|
"hunyuan3d-v3": {
|
|
2412
2408
|
category: "3d",
|
|
@@ -2724,8 +2720,7 @@ const ASSET_TOOLS = {
|
|
|
2724
2720
|
task: "single-image 3D reconstruction"
|
|
2725
2721
|
}
|
|
2726
2722
|
};
|
|
2727
|
-
|
|
2728
|
-
//#region src/tool-registry/background.ts
|
|
2723
|
+
// src/tool-registry/background.ts
|
|
2729
2724
|
const BACKGROUND_TOOLS = {
|
|
2730
2725
|
"ben-v2": {
|
|
2731
2726
|
category: "background",
|
|
@@ -3100,8 +3095,7 @@ const BACKGROUND_TOOLS = {
|
|
|
3100
3095
|
task: "video enhancement"
|
|
3101
3096
|
}
|
|
3102
3097
|
};
|
|
3103
|
-
|
|
3104
|
-
//#region src/tool-registry/editing.ts
|
|
3098
|
+
// src/tool-registry/editing.ts
|
|
3105
3099
|
const EDITING_TOOLS = {
|
|
3106
3100
|
"bria-eraser": {
|
|
3107
3101
|
category: "erase",
|
|
@@ -3372,8 +3366,7 @@ const EDITING_TOOLS = {
|
|
|
3372
3366
|
task: "virtual garment try-on"
|
|
3373
3367
|
}
|
|
3374
3368
|
};
|
|
3375
|
-
|
|
3376
|
-
//#region src/tool-registry/structure.ts
|
|
3369
|
+
// src/tool-registry/structure.ts
|
|
3377
3370
|
const STRUCTURE_TOOLS = {
|
|
3378
3371
|
"depth-anything": {
|
|
3379
3372
|
category: "preprocess",
|
|
@@ -3765,8 +3758,7 @@ const STRUCTURE_TOOLS = {
|
|
|
3765
3758
|
task: "depth preprocessing"
|
|
3766
3759
|
}
|
|
3767
3760
|
};
|
|
3768
|
-
|
|
3769
|
-
//#region src/tools.ts
|
|
3761
|
+
// src/tools.ts
|
|
3770
3762
|
const FAL_TOOLS = {
|
|
3771
3763
|
...ANALYSIS_TOOLS,
|
|
3772
3764
|
...ASSET_TOOLS,
|
|
@@ -3794,8 +3786,7 @@ function buildFalToolRequest(options) {
|
|
|
3794
3786
|
tool
|
|
3795
3787
|
};
|
|
3796
3788
|
}
|
|
3797
|
-
|
|
3798
|
-
//#region src/server-tools.ts
|
|
3789
|
+
// src/server-tools.ts
|
|
3799
3790
|
/**
|
|
3800
3791
|
* Tool execution bodies for `FalClient`, both synchronous and queued.
|
|
3801
3792
|
*
|
|
@@ -3925,8 +3916,7 @@ async function runToolQueued(exec, options, onProgress) {
|
|
|
3925
3916
|
if (request.isErr()) return err$1(request.error);
|
|
3926
3917
|
return (await runRequestQueued(exec, request.value, onProgress)).map(({ data }) => data);
|
|
3927
3918
|
}
|
|
3928
|
-
|
|
3929
|
-
//#region src/server.ts
|
|
3919
|
+
// src/server.ts
|
|
3930
3920
|
const FAL_BASE_URL = "https://fal.run";
|
|
3931
3921
|
const FAL_QUEUE_URL = "https://queue.fal.run";
|
|
3932
3922
|
const FAL_API_URL = "https://api.fal.ai";
|
|
@@ -4243,8 +4233,7 @@ var FalClient = class {
|
|
|
4243
4233
|
});
|
|
4244
4234
|
}
|
|
4245
4235
|
};
|
|
4246
|
-
|
|
4247
|
-
//#region src/source-size.ts
|
|
4236
|
+
// src/source-size.ts
|
|
4248
4237
|
const DATA_URL_REGEX = /^data:[^;,]*;base64,(.*)$/s;
|
|
4249
4238
|
function decodeBase64(data) {
|
|
4250
4239
|
try {
|
|
@@ -4342,8 +4331,7 @@ function dataUrlImageSize(url) {
|
|
|
4342
4331
|
const size = pngSize(bytes) ?? jpegSize(bytes) ?? webpSize(bytes);
|
|
4343
4332
|
return size !== void 0 && size.width > 0 && size.height > 0 ? size : void 0;
|
|
4344
4333
|
}
|
|
4345
|
-
|
|
4346
|
-
//#region src/tool-cost.ts
|
|
4334
|
+
// src/tool-cost.ts
|
|
4347
4335
|
/**
|
|
4348
4336
|
* What a tool run costs, before it happens and after.
|
|
4349
4337
|
*
|
|
@@ -4527,8 +4515,8 @@ function sumCosts(costs) {
|
|
|
4527
4515
|
unknown
|
|
4528
4516
|
};
|
|
4529
4517
|
}
|
|
4530
|
-
|
|
4531
|
-
|
|
4518
|
+
// src/image-benchmarks.ts
|
|
4519
|
+
const MEASURED_ON_2_5 = "Measured on GPT Image 2.5. Motif runs GPT Image 2.6, which Arena has not scored yet.";
|
|
4532
4520
|
const BOARDS = {
|
|
4533
4521
|
"text-to-image": {
|
|
4534
4522
|
sunburst: {
|
|
@@ -4536,6 +4524,7 @@ const BOARDS = {
|
|
|
4536
4524
|
rank: 1,
|
|
4537
4525
|
uncertainty: 5,
|
|
4538
4526
|
evaluatedModel: "GPT-Image-2.5 Sunburst",
|
|
4527
|
+
note: MEASURED_ON_2_5,
|
|
4539
4528
|
preliminary: true,
|
|
4540
4529
|
votes: 40323
|
|
4541
4530
|
},
|
|
@@ -4544,6 +4533,7 @@ const BOARDS = {
|
|
|
4544
4533
|
rank: 2,
|
|
4545
4534
|
uncertainty: 5,
|
|
4546
4535
|
evaluatedModel: "GPT-Image-2.5 Flare",
|
|
4536
|
+
note: MEASURED_ON_2_5,
|
|
4547
4537
|
preliminary: true,
|
|
4548
4538
|
votes: 39218
|
|
4549
4539
|
},
|
|
@@ -4633,6 +4623,7 @@ const BOARDS = {
|
|
|
4633
4623
|
rank: 1,
|
|
4634
4624
|
uncertainty: 5,
|
|
4635
4625
|
evaluatedModel: "GPT-Image-2.5 Sunburst",
|
|
4626
|
+
note: MEASURED_ON_2_5,
|
|
4636
4627
|
preliminary: true
|
|
4637
4628
|
},
|
|
4638
4629
|
flare: {
|
|
@@ -4640,6 +4631,7 @@ const BOARDS = {
|
|
|
4640
4631
|
rank: 2,
|
|
4641
4632
|
uncertainty: 5,
|
|
4642
4633
|
evaluatedModel: "GPT-Image-2.5 Flare",
|
|
4634
|
+
note: MEASURED_ON_2_5,
|
|
4643
4635
|
preliminary: true
|
|
4644
4636
|
},
|
|
4645
4637
|
"grok-image-2": {
|
|
@@ -4709,8 +4701,7 @@ function imageModelBenchmark(model, task) {
|
|
|
4709
4701
|
task
|
|
4710
4702
|
};
|
|
4711
4703
|
}
|
|
4712
|
-
|
|
4713
|
-
//#region src/tasks.ts
|
|
4704
|
+
// src/tasks.ts
|
|
4714
4705
|
/**
|
|
4715
4706
|
* The Task registry: every job Motif does, with the Models that can do it
|
|
4716
4707
|
* ranked best-first and tagged with the Tier each belongs to.
|
|
@@ -5587,8 +5578,7 @@ const TASK_IDS = Object.keys(TASKS).filter(isTaskId);
|
|
|
5587
5578
|
function isTaskId(value) {
|
|
5588
5579
|
return Object.hasOwn(TASKS, value);
|
|
5589
5580
|
}
|
|
5590
|
-
|
|
5591
|
-
//#region src/tool-parameters.generated.ts
|
|
5581
|
+
// src/tool-parameters.generated.ts
|
|
5592
5582
|
const FAL_TOOL_PARAMETERS = {
|
|
5593
5583
|
"ben-v2": [{
|
|
5594
5584
|
key: "seed",
|
|
@@ -7745,8 +7735,7 @@ const FAL_TOOL_PARAMETERS = {
|
|
|
7745
7735
|
function falToolParameters(tool) {
|
|
7746
7736
|
return FAL_TOOL_PARAMETERS[tool] ?? [];
|
|
7747
7737
|
}
|
|
7748
|
-
|
|
7749
|
-
//#region src/resolve.ts
|
|
7738
|
+
// src/resolve.ts
|
|
7750
7739
|
/**
|
|
7751
7740
|
* Model choice: the one place a Model is chosen, for the CLI and the SDK.
|
|
7752
7741
|
*
|
|
@@ -7781,6 +7770,7 @@ function generationProfile(config) {
|
|
|
7781
7770
|
if (config.supportsNegativePrompt === true) capabilities.add("negativePrompt");
|
|
7782
7771
|
if (config.supportsOutputFormat === true) capabilities.add("outputFormat");
|
|
7783
7772
|
return {
|
|
7773
|
+
name: config.name,
|
|
7784
7774
|
aspects: config.supportedAspects,
|
|
7785
7775
|
capabilities,
|
|
7786
7776
|
keys: [FAL_KEY],
|
|
@@ -7814,6 +7804,7 @@ function toolProfile(tool) {
|
|
|
7814
7804
|
const takesReference = "referenceField" in config;
|
|
7815
7805
|
if (takesReference) capabilities.add("references");
|
|
7816
7806
|
return {
|
|
7807
|
+
name: config.name,
|
|
7817
7808
|
capabilities,
|
|
7818
7809
|
keys: [FAL_KEY],
|
|
7819
7810
|
maxReferences: takesReference ? 1 : 0
|
|
@@ -8054,8 +8045,7 @@ function tierChangesChoice(task, request, environment) {
|
|
|
8054
8045
|
}
|
|
8055
8046
|
return chosen.size > 1;
|
|
8056
8047
|
}
|
|
8057
|
-
|
|
8058
|
-
//#region src/task-output.ts
|
|
8048
|
+
// src/task-output.ts
|
|
8059
8049
|
function isPlainRecord(value) {
|
|
8060
8050
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8061
8051
|
}
|
|
@@ -8180,8 +8170,7 @@ function labelUrls(urls, labels) {
|
|
|
8180
8170
|
return names !== void 0 && names.length === totals.get(key) ? names[occurrence] : void 0;
|
|
8181
8171
|
});
|
|
8182
8172
|
}
|
|
8183
|
-
|
|
8184
|
-
//#region src/task-plan-pricing.ts
|
|
8173
|
+
// src/task-plan-pricing.ts
|
|
8185
8174
|
/**
|
|
8186
8175
|
* What a generation request bills and which body keys the caller owns. Both
|
|
8187
8176
|
* read the body as sent, `params` included, because fal bills that body.
|
|
@@ -8260,8 +8249,7 @@ function checkParamsImageSize(config, model, task, params) {
|
|
|
8260
8249
|
task
|
|
8261
8250
|
});
|
|
8262
8251
|
}
|
|
8263
|
-
|
|
8264
|
-
//#region src/task-plan-tools.ts
|
|
8252
|
+
// src/task-plan-tools.ts
|
|
8265
8253
|
/**
|
|
8266
8254
|
* Request bodies for fal tool Models: map each TaskInput field onto the key
|
|
8267
8255
|
* the tool's generated parameter list names, refuse what it doesn't list, and
|
|
@@ -8610,8 +8598,7 @@ function toolPlan(task, model, input) {
|
|
|
8610
8598
|
queued: "queued" in tool
|
|
8611
8599
|
});
|
|
8612
8600
|
}
|
|
8613
|
-
|
|
8614
|
-
//#region src/task-plan-video.ts
|
|
8601
|
+
// src/task-plan-video.ts
|
|
8615
8602
|
/**
|
|
8616
8603
|
* Request bodies for video Models: Kling v3 Pro and Kling v3 Turbo Pro, which
|
|
8617
8604
|
* take the start frame under different keys and bill by the second.
|
|
@@ -8692,8 +8679,7 @@ function turboVideoPlan(task, endpoint, input) {
|
|
|
8692
8679
|
queued: true
|
|
8693
8680
|
});
|
|
8694
8681
|
}
|
|
8695
|
-
|
|
8696
|
-
//#region src/task-plan.ts
|
|
8682
|
+
// src/task-plan.ts
|
|
8697
8683
|
/**
|
|
8698
8684
|
* `plan()` for the Task client: resolve the Model, build the request body the
|
|
8699
8685
|
* Model's kind needs, and price it. Pure: no I/O.
|
|
@@ -8994,8 +8980,7 @@ function upscalerPlan(task, model, input) {
|
|
|
8994
8980
|
queued: false
|
|
8995
8981
|
});
|
|
8996
8982
|
}
|
|
8997
|
-
|
|
8998
|
-
//#region src/task-stream.ts
|
|
8983
|
+
// src/task-stream.ts
|
|
8999
8984
|
const MAX_EVENT_CHARACTERS = 16777216;
|
|
9000
8985
|
const JSON_START = /^[[{]/;
|
|
9001
8986
|
function parsePayload(text) {
|
|
@@ -9274,8 +9259,7 @@ function createFrames(requestId) {
|
|
|
9274
9259
|
function enforceBufferLimit(length, requestId) {
|
|
9275
9260
|
if (length > MAX_EVENT_CHARACTERS) throw new MotifError("Stream event exceeds the buffer limit.", 0, "STREAM_EVENT_TOO_LARGE", requestId);
|
|
9276
9261
|
}
|
|
9277
|
-
|
|
9278
|
-
//#region src/task-client.ts
|
|
9262
|
+
// src/task-client.ts
|
|
9279
9263
|
/**
|
|
9280
9264
|
* The Task client: one function per Task. `createMotif()` returns a client
|
|
9281
9265
|
* whose `generate`, `erase`, `upscale` and the rest resolve the Model through
|
|
@@ -9451,5 +9435,4 @@ function createMotif(config = {}) {
|
|
|
9451
9435
|
}
|
|
9452
9436
|
};
|
|
9453
9437
|
}
|
|
9454
|
-
//#endregion
|
|
9455
9438
|
export { ACCOUNT_LOCKED, ASPECT_RATIOS, CREATIVE_FIELDS, CREATIVE_TAXONOMY, CreativeOptionError, DEFAULT_TIER, FORMAT_PRESETS, INVALID_OPTION, ImageSizeBoundsError, LOOKS, MotifError, NO_MODEL_AVAILABLE, RESOLUTIONS, TASKS, TASK_IDS, TIERS, createMotif, enrichPrompt, err, formatCost, getFalKeyFromEnv, getLook, isFalAccountLocked, isTaskId, modelProfile, motifEnvSchema, ok, parseMotifEnv, promptWarnings, resolveTask, sanitizePrompt, sumCosts, tierChangesChoice, validateCreativeDirection };
|
package/dist/registry.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `@howells/motif-sdk/registry` — the Model and tool tables behind Task
|
|
3
|
+
* resolution, for callers that show or price Models themselves. Most callers
|
|
4
|
+
* want the Task client from the package root instead.
|
|
5
|
+
*/
|
|
2
6
|
/** ─── Model Types ─────────────────────────────────────────────── */
|
|
3
7
|
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";
|
|
4
8
|
type Resolution = "0.5K" | "1K" | "2K" | "4K";
|
|
@@ -139,22 +143,14 @@ interface ModelConfig {
|
|
|
139
143
|
/** Use fal queue submit/status/result even for generate() calls. */
|
|
140
144
|
useQueue?: boolean;
|
|
141
145
|
}
|
|
142
|
-
//#endregion
|
|
143
|
-
//#region src/aspects.d.ts
|
|
144
146
|
/** Pixel sizes of fal's named `image_size` presets. `auto` has none. */
|
|
145
147
|
export declare const FAL_PRESET_SIZES: Readonly<Record<string, CustomImageSize>>;
|
|
146
|
-
//#endregion
|
|
147
|
-
//#region src/cost.d.ts
|
|
148
148
|
/**
|
|
149
149
|
* Estimate cost based on model and settings. `editImages` is the number of
|
|
150
150
|
* input images on an edit, for Models whose edits cost more than generation.
|
|
151
151
|
*/
|
|
152
152
|
export declare function estimateCost(model: string, resolution?: Resolution, numImages?: number, editImages?: number): number | null;
|
|
153
|
-
//#endregion
|
|
154
|
-
//#region src/models.d.ts
|
|
155
153
|
export declare const MODELS: Record<string, ModelConfig>;
|
|
156
|
-
//#endregion
|
|
157
|
-
//#region src/tool-types.d.ts
|
|
158
154
|
type FalToolInputKind = "image" | "images" | "video";
|
|
159
155
|
/**
|
|
160
156
|
* Machine-readable cost, so `--dry-run` can emit a number rather than the
|
|
@@ -313,8 +309,6 @@ interface FalToolConfig {
|
|
|
313
309
|
sourceUrl: string;
|
|
314
310
|
task: string;
|
|
315
311
|
}
|
|
316
|
-
//#endregion
|
|
317
|
-
//#region src/tools.d.ts
|
|
318
312
|
export declare const FAL_TOOLS: {
|
|
319
313
|
readonly "got-ocr": {
|
|
320
314
|
readonly category: "analysis";
|
|
@@ -1753,5 +1747,4 @@ export declare const FAL_TOOLS: {
|
|
|
1753
1747
|
declare const FAL_TOOL_IDS: (keyof typeof FAL_TOOLS)[];
|
|
1754
1748
|
type FalToolId = (typeof FAL_TOOL_IDS)[number];
|
|
1755
1749
|
export declare function isFalToolId(tool: string): tool is FalToolId;
|
|
1756
|
-
//#endregion
|
|
1757
1750
|
export type { FalToolConfig, FalToolPrice, ModelConfig };
|