@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.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",
|
|
@@ -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
|
|
175
|
-
* only as far as a minimum edge or
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
2138
|
-
*
|
|
2139
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4532
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 };
|