@howells/motif-sdk 6.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 +5 -5
- package/dist/image.d.ts +17 -22
- package/dist/image.js +24 -639
- package/dist/index.cjs +50 -810
- package/dist/index.d.cts +20 -29
- package/dist/index.d.ts +20 -29
- package/dist/index.js +50 -810
- package/dist/registry.d.ts +1750 -0
- package/dist/registry.js +2705 -0
- package/package.json +5 -1
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",
|
|
@@ -236,8 +236,7 @@ const FORMAT_PRESETS = {
|
|
|
236
236
|
label: "Wide"
|
|
237
237
|
}
|
|
238
238
|
};
|
|
239
|
-
|
|
240
|
-
//#region src/creative.ts
|
|
239
|
+
// src/creative.ts
|
|
241
240
|
const CONTROL_CHAR_REGEX = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g;
|
|
242
241
|
const TRAILING_PERIODS_REGEX = /\.+$/;
|
|
243
242
|
/**
|
|
@@ -313,7 +312,7 @@ const CREATIVE_TAXONOMY = {
|
|
|
313
312
|
description: "Natural, unposed documentary portraits of people. Pair with a mood for the light.",
|
|
314
313
|
id: "portrait",
|
|
315
314
|
label: "Documentary portrait",
|
|
316
|
-
model: "
|
|
315
|
+
model: "seedream5"
|
|
317
316
|
},
|
|
318
317
|
{
|
|
319
318
|
acceptsMood: false,
|
|
@@ -479,8 +478,7 @@ function enrichPrompt(options) {
|
|
|
479
478
|
prompt: clauses.length ? joinSentences([basePrompt, ...clauses].filter((part) => part !== "")) : basePrompt
|
|
480
479
|
};
|
|
481
480
|
}
|
|
482
|
-
|
|
483
|
-
//#region src/errors.ts
|
|
481
|
+
// src/errors.ts
|
|
484
482
|
/**
|
|
485
483
|
* `MotifError` and its coercion helper.
|
|
486
484
|
*
|
|
@@ -537,8 +535,7 @@ function toMotifError(error) {
|
|
|
537
535
|
if (error instanceof MotifError) return error;
|
|
538
536
|
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
537
|
}
|
|
540
|
-
|
|
541
|
-
//#region src/task-plan-shared.ts
|
|
538
|
+
// src/task-plan-shared.ts
|
|
542
539
|
/**
|
|
543
540
|
* Helpers every request builder in the Task planner shares: refusing fields a
|
|
544
541
|
* Model can't carry, and merging `params` without letting them replace what
|
|
@@ -618,8 +615,7 @@ function mergeParams(body, params, owned) {
|
|
|
618
615
|
...params
|
|
619
616
|
});
|
|
620
617
|
}
|
|
621
|
-
|
|
622
|
-
//#region src/prompt-warnings.ts
|
|
618
|
+
// src/prompt-warnings.ts
|
|
623
619
|
const EDIT_VERB_REGEX = /^\s*(remove|erase|extend|outpaint)\b/i;
|
|
624
620
|
/** The CLI verb that does each edit directly, keyed by the prompt's first word. */
|
|
625
621
|
const EDIT_VERBS = {
|
|
@@ -685,8 +681,7 @@ function promptWarnings(prompt, context = {}) {
|
|
|
685
681
|
});
|
|
686
682
|
return warnings;
|
|
687
683
|
}
|
|
688
|
-
|
|
689
|
-
//#region src/env.ts
|
|
684
|
+
// src/env.ts
|
|
690
685
|
const motifEnvSchema = defineEnv({ optional: { FAL_KEY: z.string().min(1) } });
|
|
691
686
|
function parseMotifEnv(input = process.env) {
|
|
692
687
|
return motifEnvSchema.parse(input);
|
|
@@ -694,13 +689,11 @@ function parseMotifEnv(input = process.env) {
|
|
|
694
689
|
function getFalKeyFromEnv(input = process.env) {
|
|
695
690
|
return parseMotifEnv(input).FAL_KEY;
|
|
696
691
|
}
|
|
697
|
-
|
|
698
|
-
//#region src/models.ts
|
|
692
|
+
// src/models.ts
|
|
699
693
|
const AA_IMAGE_LEADERBOARD_SNAPSHOT = "2026-10-07";
|
|
700
694
|
const AA_IMAGE_SOURCES = ["https://artificialanalysis.ai/image/leaderboard/text-to-image", "https://artificialanalysis.ai/image/leaderboard/editing"];
|
|
701
695
|
const FAL_PRICING_CHECKED_AT = "2026-05-12";
|
|
702
696
|
const FAL_PRICING_CHECKED_JUL_2026 = "2026-07-11";
|
|
703
|
-
const FAL_PRICING_CHECKED_AUG_2026 = "2026-08-23";
|
|
704
697
|
const FAL_PRICING_CHECKED_SEP_2026 = "2026-09-16";
|
|
705
698
|
const FAL_PRICING_CHECKED_OCT_2026 = "2026-10-29";
|
|
706
699
|
const MODELS = {
|
|
@@ -999,7 +992,7 @@ const MODELS = {
|
|
|
999
992
|
quality: "frontier",
|
|
1000
993
|
speed: "unknown"
|
|
1001
994
|
},
|
|
1002
|
-
useCase: "
|
|
995
|
+
useCase: "Gemini workhorse with 0.5K output"
|
|
1003
996
|
},
|
|
1004
997
|
editEndpoint: "fal-ai/nano-banana-2/edit",
|
|
1005
998
|
endpoint: "fal-ai/nano-banana-2",
|
|
@@ -1104,211 +1097,6 @@ const MODELS = {
|
|
|
1104
1097
|
supportsWebSearch: true,
|
|
1105
1098
|
type: "generation"
|
|
1106
1099
|
},
|
|
1107
|
-
gemini: {
|
|
1108
|
-
benchmark: { artificialAnalysis: {
|
|
1109
|
-
editing: {
|
|
1110
|
-
elo: 987,
|
|
1111
|
-
rank: 50
|
|
1112
|
-
},
|
|
1113
|
-
snapshotDate: AA_IMAGE_LEADERBOARD_SNAPSHOT,
|
|
1114
|
-
sourceUrls: AA_IMAGE_SOURCES,
|
|
1115
|
-
textToImage: {
|
|
1116
|
-
elo: 985,
|
|
1117
|
-
rank: 60
|
|
1118
|
-
}
|
|
1119
|
-
} },
|
|
1120
|
-
editEndpoint: "fal-ai/gemini-25-flash-image/edit",
|
|
1121
|
-
endpoint: "fal-ai/gemini-25-flash-image",
|
|
1122
|
-
falPricing: {
|
|
1123
|
-
checkedAt: FAL_PRICING_CHECKED_AT,
|
|
1124
|
-
currency: "USD",
|
|
1125
|
-
endpointId: "fal-ai/gemini-25-flash-image",
|
|
1126
|
-
estimatedCostPerImageUsd: .0398,
|
|
1127
|
-
source: "fal-pricing-api",
|
|
1128
|
-
unit: "images",
|
|
1129
|
-
unitPrice: .0398
|
|
1130
|
-
},
|
|
1131
|
-
maxReferenceImages: 4,
|
|
1132
|
-
name: "Gemini 2.5 Flash",
|
|
1133
|
-
pricePerImageUsd: .0398,
|
|
1134
|
-
pricing: "$0.04",
|
|
1135
|
-
sizeMode: "aspect_ratio",
|
|
1136
|
-
supportedAspects: [
|
|
1137
|
-
"21:9",
|
|
1138
|
-
"16:9",
|
|
1139
|
-
"3:2",
|
|
1140
|
-
"4:3",
|
|
1141
|
-
"5:4",
|
|
1142
|
-
"1:1",
|
|
1143
|
-
"4:5",
|
|
1144
|
-
"3:4",
|
|
1145
|
-
"2:3",
|
|
1146
|
-
"9:16"
|
|
1147
|
-
],
|
|
1148
|
-
supportsAspect: true,
|
|
1149
|
-
supportsEdit: true,
|
|
1150
|
-
supportsNumImages: true,
|
|
1151
|
-
supportsOutputFormat: true,
|
|
1152
|
-
supportsResolution: false,
|
|
1153
|
-
supportsSafetyTolerance: true,
|
|
1154
|
-
supportsSeed: true,
|
|
1155
|
-
supportsSyncMode: true,
|
|
1156
|
-
type: "generation"
|
|
1157
|
-
},
|
|
1158
|
-
gemini3: {
|
|
1159
|
-
editEndpoint: "fal-ai/gemini-3-pro-image-preview/edit",
|
|
1160
|
-
endpoint: "fal-ai/gemini-3-pro-image-preview",
|
|
1161
|
-
falPricing: {
|
|
1162
|
-
checkedAt: FAL_PRICING_CHECKED_AT,
|
|
1163
|
-
currency: "USD",
|
|
1164
|
-
endpointId: "fal-ai/gemini-3-pro-image-preview",
|
|
1165
|
-
estimatedCostPerImageUsd: .15,
|
|
1166
|
-
source: "fal-pricing-api",
|
|
1167
|
-
unit: "images",
|
|
1168
|
-
unitPrice: .15
|
|
1169
|
-
},
|
|
1170
|
-
maxReferenceImages: 4,
|
|
1171
|
-
name: "Gemini 3 Pro",
|
|
1172
|
-
pricePerImageUsd: .15,
|
|
1173
|
-
pricing: "$0.15",
|
|
1174
|
-
sizeMode: "aspect_ratio",
|
|
1175
|
-
supportedAspects: [
|
|
1176
|
-
"auto",
|
|
1177
|
-
"21:9",
|
|
1178
|
-
"16:9",
|
|
1179
|
-
"3:2",
|
|
1180
|
-
"4:3",
|
|
1181
|
-
"5:4",
|
|
1182
|
-
"1:1",
|
|
1183
|
-
"4:5",
|
|
1184
|
-
"3:4",
|
|
1185
|
-
"2:3",
|
|
1186
|
-
"9:16"
|
|
1187
|
-
],
|
|
1188
|
-
supportedResolutions: [
|
|
1189
|
-
"1K",
|
|
1190
|
-
"2K",
|
|
1191
|
-
"4K"
|
|
1192
|
-
],
|
|
1193
|
-
supportsAspect: true,
|
|
1194
|
-
supportsEdit: true,
|
|
1195
|
-
supportsNumImages: true,
|
|
1196
|
-
supportsOutputFormat: true,
|
|
1197
|
-
supportsResolution: true,
|
|
1198
|
-
supportsSafetyTolerance: true,
|
|
1199
|
-
supportsSeed: true,
|
|
1200
|
-
supportsSyncMode: true,
|
|
1201
|
-
supportsWebSearch: true,
|
|
1202
|
-
type: "generation"
|
|
1203
|
-
},
|
|
1204
|
-
seedream4: {
|
|
1205
|
-
benchmark: {
|
|
1206
|
-
artificialAnalysis: {
|
|
1207
|
-
editing: {
|
|
1208
|
-
elo: 1015,
|
|
1209
|
-
rank: 36
|
|
1210
|
-
},
|
|
1211
|
-
snapshotDate: AA_IMAGE_LEADERBOARD_SNAPSHOT,
|
|
1212
|
-
sourceUrls: AA_IMAGE_SOURCES,
|
|
1213
|
-
textToImage: {
|
|
1214
|
-
elo: 1030,
|
|
1215
|
-
rank: 21
|
|
1216
|
-
}
|
|
1217
|
-
},
|
|
1218
|
-
speed: {
|
|
1219
|
-
medianSeconds: 14.3,
|
|
1220
|
-
p95Seconds: 21,
|
|
1221
|
-
source: "artificial-analysis-models"
|
|
1222
|
-
},
|
|
1223
|
-
tiers: {
|
|
1224
|
-
price: "budget",
|
|
1225
|
-
quality: "best",
|
|
1226
|
-
speed: "balanced"
|
|
1227
|
-
},
|
|
1228
|
-
useCase: "Legacy budget generation and large multi-reference edits"
|
|
1229
|
-
},
|
|
1230
|
-
customImageSize: {
|
|
1231
|
-
maxPixels: 16777216,
|
|
1232
|
-
minPixels: 921600
|
|
1233
|
-
},
|
|
1234
|
-
editEndpoint: "fal-ai/bytedance/seedream/v4/edit",
|
|
1235
|
-
endpoint: "fal-ai/bytedance/seedream/v4/text-to-image",
|
|
1236
|
-
falPricing: {
|
|
1237
|
-
checkedAt: FAL_PRICING_CHECKED_AT,
|
|
1238
|
-
currency: "USD",
|
|
1239
|
-
endpointId: "fal-ai/bytedance/seedream/v4/text-to-image",
|
|
1240
|
-
estimatedCostPerImageUsd: .03,
|
|
1241
|
-
source: "fal-pricing-api",
|
|
1242
|
-
unit: "images",
|
|
1243
|
-
unitPrice: .03
|
|
1244
|
-
},
|
|
1245
|
-
maxReferenceImages: 10,
|
|
1246
|
-
name: "Seedream 4.0",
|
|
1247
|
-
pricePerImageUsd: .03,
|
|
1248
|
-
pricing: "$0.03",
|
|
1249
|
-
sizeMode: "image_size_enum",
|
|
1250
|
-
supportsAspect: true,
|
|
1251
|
-
supportsEdit: true,
|
|
1252
|
-
supportsNumImages: true,
|
|
1253
|
-
supportsResolution: false,
|
|
1254
|
-
supportsSeed: true,
|
|
1255
|
-
supportsSyncMode: true,
|
|
1256
|
-
type: "generation"
|
|
1257
|
-
},
|
|
1258
|
-
seedream45: {
|
|
1259
|
-
benchmark: {
|
|
1260
|
-
artificialAnalysis: {
|
|
1261
|
-
editing: {
|
|
1262
|
-
elo: 1037,
|
|
1263
|
-
rank: 32
|
|
1264
|
-
},
|
|
1265
|
-
snapshotDate: AA_IMAGE_LEADERBOARD_SNAPSHOT,
|
|
1266
|
-
sourceUrls: AA_IMAGE_SOURCES,
|
|
1267
|
-
textToImage: {
|
|
1268
|
-
elo: 1022,
|
|
1269
|
-
rank: 26
|
|
1270
|
-
}
|
|
1271
|
-
},
|
|
1272
|
-
speed: {
|
|
1273
|
-
medianSeconds: 18.2,
|
|
1274
|
-
p95Seconds: 43.3,
|
|
1275
|
-
source: "artificial-analysis-models"
|
|
1276
|
-
},
|
|
1277
|
-
tiers: {
|
|
1278
|
-
price: "standard",
|
|
1279
|
-
quality: "better",
|
|
1280
|
-
speed: "balanced"
|
|
1281
|
-
},
|
|
1282
|
-
useCase: "Cheap current Seedream model with good animation/art scores"
|
|
1283
|
-
},
|
|
1284
|
-
customImageSize: {
|
|
1285
|
-
maxPixels: 16777216,
|
|
1286
|
-
minPixels: 3686400
|
|
1287
|
-
},
|
|
1288
|
-
editEndpoint: "fal-ai/bytedance/seedream/v4.5/edit",
|
|
1289
|
-
endpoint: "fal-ai/bytedance/seedream/v4.5/text-to-image",
|
|
1290
|
-
falPricing: {
|
|
1291
|
-
checkedAt: FAL_PRICING_CHECKED_AT,
|
|
1292
|
-
currency: "USD",
|
|
1293
|
-
endpointId: "fal-ai/bytedance/seedream/v4.5/text-to-image",
|
|
1294
|
-
estimatedCostPerImageUsd: .04,
|
|
1295
|
-
source: "fal-pricing-api",
|
|
1296
|
-
unit: "images",
|
|
1297
|
-
unitPrice: .04
|
|
1298
|
-
},
|
|
1299
|
-
maxReferenceImages: 10,
|
|
1300
|
-
name: "Seedream 4.5",
|
|
1301
|
-
pricePerImageUsd: .04,
|
|
1302
|
-
pricing: "$0.04",
|
|
1303
|
-
sizeMode: "image_size_enum",
|
|
1304
|
-
supportsAspect: true,
|
|
1305
|
-
supportsEdit: true,
|
|
1306
|
-
supportsNumImages: true,
|
|
1307
|
-
supportsResolution: false,
|
|
1308
|
-
supportsSeed: true,
|
|
1309
|
-
supportsSyncMode: true,
|
|
1310
|
-
type: "generation"
|
|
1311
|
-
},
|
|
1312
1100
|
seedream5: {
|
|
1313
1101
|
benchmark: { artificialAnalysis: {
|
|
1314
1102
|
editing: {
|
|
@@ -1392,65 +1180,6 @@ const MODELS = {
|
|
|
1392
1180
|
supportsSyncMode: true,
|
|
1393
1181
|
maxReferenceImages: 10
|
|
1394
1182
|
},
|
|
1395
|
-
"flux2-max": {
|
|
1396
|
-
benchmark: {
|
|
1397
|
-
artificialAnalysis: {
|
|
1398
|
-
editing: {
|
|
1399
|
-
elo: 997,
|
|
1400
|
-
rank: 49
|
|
1401
|
-
},
|
|
1402
|
-
snapshotDate: AA_IMAGE_LEADERBOARD_SNAPSHOT,
|
|
1403
|
-
sourceUrls: AA_IMAGE_SOURCES,
|
|
1404
|
-
textToImage: {
|
|
1405
|
-
elo: 1020,
|
|
1406
|
-
rank: 28
|
|
1407
|
-
}
|
|
1408
|
-
},
|
|
1409
|
-
speed: {
|
|
1410
|
-
medianSeconds: 31.6,
|
|
1411
|
-
p95Seconds: 41,
|
|
1412
|
-
source: "artificial-analysis-models"
|
|
1413
|
-
},
|
|
1414
|
-
tiers: {
|
|
1415
|
-
price: "premium",
|
|
1416
|
-
quality: "best",
|
|
1417
|
-
speed: "slow"
|
|
1418
|
-
},
|
|
1419
|
-
useCase: "Best FLUX quality and high-end editing"
|
|
1420
|
-
},
|
|
1421
|
-
customImageSize: {
|
|
1422
|
-
maxEdge: 2560,
|
|
1423
|
-
maxPixels: 4194304,
|
|
1424
|
-
minEdge: 256,
|
|
1425
|
-
multipleOf: 16
|
|
1426
|
-
},
|
|
1427
|
-
editEndpoint: "fal-ai/flux-2-max/edit",
|
|
1428
|
-
endpoint: "fal-ai/flux-2-max",
|
|
1429
|
-
falPricing: {
|
|
1430
|
-
checkedAt: FAL_PRICING_CHECKED_AT,
|
|
1431
|
-
currency: "USD",
|
|
1432
|
-
endpointId: "fal-ai/flux-2-max",
|
|
1433
|
-
estimatedCostPerImageUsd: .07,
|
|
1434
|
-
source: "fal-pricing-api",
|
|
1435
|
-
unit: "megapixels",
|
|
1436
|
-
unitPrice: .07
|
|
1437
|
-
},
|
|
1438
|
-
maxReferenceImages: 10,
|
|
1439
|
-
name: "FLUX.2 Max",
|
|
1440
|
-
pricePerImageUsd: .07,
|
|
1441
|
-
pricing: "$0.07/MP",
|
|
1442
|
-
sizeMode: "image_size_enum",
|
|
1443
|
-
supportsAspect: true,
|
|
1444
|
-
supportsEdit: true,
|
|
1445
|
-
supportsNumImages: false,
|
|
1446
|
-
supportsOutputFormat: true,
|
|
1447
|
-
supportsResolution: false,
|
|
1448
|
-
supportsSafetyChecker: true,
|
|
1449
|
-
supportsSafetyTolerance: true,
|
|
1450
|
-
supportsSeed: true,
|
|
1451
|
-
supportsSyncMode: true,
|
|
1452
|
-
type: "generation"
|
|
1453
|
-
},
|
|
1454
1183
|
"flux2-pro": {
|
|
1455
1184
|
benchmark: {
|
|
1456
1185
|
artificialAnalysis: {
|
|
@@ -1572,69 +1301,6 @@ const MODELS = {
|
|
|
1572
1301
|
supportsSyncMode: true,
|
|
1573
1302
|
type: "generation"
|
|
1574
1303
|
},
|
|
1575
|
-
"flux2-dev": {
|
|
1576
|
-
benchmark: {
|
|
1577
|
-
artificialAnalysis: {
|
|
1578
|
-
editing: {
|
|
1579
|
-
elo: 1e3,
|
|
1580
|
-
rank: 45
|
|
1581
|
-
},
|
|
1582
|
-
snapshotDate: AA_IMAGE_LEADERBOARD_SNAPSHOT,
|
|
1583
|
-
sourceUrls: AA_IMAGE_SOURCES,
|
|
1584
|
-
textToImage: {
|
|
1585
|
-
elo: 1e3,
|
|
1586
|
-
rank: 42
|
|
1587
|
-
}
|
|
1588
|
-
},
|
|
1589
|
-
speed: {
|
|
1590
|
-
medianSeconds: 4.6,
|
|
1591
|
-
p95Seconds: 69.6,
|
|
1592
|
-
source: "artificial-analysis-models"
|
|
1593
|
-
},
|
|
1594
|
-
tiers: {
|
|
1595
|
-
price: "variable",
|
|
1596
|
-
quality: "better",
|
|
1597
|
-
speed: "fast"
|
|
1598
|
-
},
|
|
1599
|
-
useCase: "Open FLUX.2 quality with low average cost"
|
|
1600
|
-
},
|
|
1601
|
-
customImageSize: {
|
|
1602
|
-
maxEdge: 2048,
|
|
1603
|
-
minEdge: 512
|
|
1604
|
-
},
|
|
1605
|
-
editEndpoint: "fal-ai/flux-2/edit",
|
|
1606
|
-
endpoint: "fal-ai/flux-2",
|
|
1607
|
-
falPricing: {
|
|
1608
|
-
checkedAt: FAL_PRICING_CHECKED_AT,
|
|
1609
|
-
currency: "USD",
|
|
1610
|
-
endpointId: "fal-ai/flux-2",
|
|
1611
|
-
estimatedCostPerImageUsd: .012,
|
|
1612
|
-
source: "fal-pricing-api",
|
|
1613
|
-
unit: "compute seconds",
|
|
1614
|
-
unitPrice: .00167
|
|
1615
|
-
},
|
|
1616
|
-
maxReferenceImages: 4,
|
|
1617
|
-
name: "FLUX.2 [dev]",
|
|
1618
|
-
pricePerImageUsd: .012,
|
|
1619
|
-
pricing: "$0.00167/sec",
|
|
1620
|
-
sizeMode: "image_size_enum",
|
|
1621
|
-
supportsAspect: true,
|
|
1622
|
-
streaming: {
|
|
1623
|
-
generation: true,
|
|
1624
|
-
edit: true
|
|
1625
|
-
},
|
|
1626
|
-
supportsEdit: true,
|
|
1627
|
-
supportsGuidanceScale: true,
|
|
1628
|
-
supportsInferenceSteps: true,
|
|
1629
|
-
supportsNumImages: true,
|
|
1630
|
-
supportsOutputFormat: true,
|
|
1631
|
-
supportsResolution: false,
|
|
1632
|
-
supportsSafetyChecker: true,
|
|
1633
|
-
supportsSafetyTolerance: true,
|
|
1634
|
-
supportsSeed: true,
|
|
1635
|
-
supportsSyncMode: true,
|
|
1636
|
-
type: "generation"
|
|
1637
|
-
},
|
|
1638
1304
|
"flux2-turbo": {
|
|
1639
1305
|
customImageSize: {
|
|
1640
1306
|
maxEdge: 2048,
|
|
@@ -1665,188 +1331,6 @@ const MODELS = {
|
|
|
1665
1331
|
supportsSyncMode: true,
|
|
1666
1332
|
type: "generation"
|
|
1667
1333
|
},
|
|
1668
|
-
flux: {
|
|
1669
|
-
endpoint: "fal-ai/flux-pro/v1.1-ultra",
|
|
1670
|
-
falPricing: {
|
|
1671
|
-
checkedAt: FAL_PRICING_CHECKED_AT,
|
|
1672
|
-
currency: "USD",
|
|
1673
|
-
endpointId: "fal-ai/flux-pro/v1.1-ultra",
|
|
1674
|
-
estimatedCostPerImageUsd: .06,
|
|
1675
|
-
source: "fal-pricing-api",
|
|
1676
|
-
unit: "images",
|
|
1677
|
-
unitPrice: .06
|
|
1678
|
-
},
|
|
1679
|
-
maxReferenceImages: 1,
|
|
1680
|
-
name: "FLUX Pro Ultra",
|
|
1681
|
-
pricePerImageUsd: .06,
|
|
1682
|
-
pricing: "$0.06",
|
|
1683
|
-
sizeMode: "aspect_ratio",
|
|
1684
|
-
supportsAspect: true,
|
|
1685
|
-
supportsEdit: true,
|
|
1686
|
-
supportsEnhancePrompt: true,
|
|
1687
|
-
supportsImagePromptStrength: true,
|
|
1688
|
-
supportsNumImages: true,
|
|
1689
|
-
supportsOutputFormat: true,
|
|
1690
|
-
supportsRaw: true,
|
|
1691
|
-
supportsResolution: false,
|
|
1692
|
-
supportsSafetyTolerance: true,
|
|
1693
|
-
supportsSeed: true,
|
|
1694
|
-
supportsSyncMode: true,
|
|
1695
|
-
type: "generation"
|
|
1696
|
-
},
|
|
1697
|
-
"flux-fast": {
|
|
1698
|
-
customImageSize: {},
|
|
1699
|
-
endpoint: "fal-ai/flux/schnell",
|
|
1700
|
-
falPricing: {
|
|
1701
|
-
checkedAt: FAL_PRICING_CHECKED_AT,
|
|
1702
|
-
currency: "USD",
|
|
1703
|
-
endpointId: "fal-ai/flux/schnell",
|
|
1704
|
-
estimatedCostPerImageUsd: .003,
|
|
1705
|
-
source: "fal-pricing-api",
|
|
1706
|
-
unit: "megapixels",
|
|
1707
|
-
unitPrice: .003
|
|
1708
|
-
},
|
|
1709
|
-
name: "FLUX Schnell",
|
|
1710
|
-
pricePerImageUsd: .003,
|
|
1711
|
-
pricing: "$0.003",
|
|
1712
|
-
sizeMode: "image_size_enum",
|
|
1713
|
-
supportsAspect: true,
|
|
1714
|
-
supportsEdit: false,
|
|
1715
|
-
supportsGuidanceScale: true,
|
|
1716
|
-
supportsInferenceSteps: true,
|
|
1717
|
-
supportsNumImages: true,
|
|
1718
|
-
supportsOutputFormat: true,
|
|
1719
|
-
supportsResolution: false,
|
|
1720
|
-
supportsSeed: true,
|
|
1721
|
-
supportsSyncMode: true,
|
|
1722
|
-
type: "generation"
|
|
1723
|
-
},
|
|
1724
|
-
recraft: {
|
|
1725
|
-
customImageSize: {},
|
|
1726
|
-
endpoint: "fal-ai/recraft/v3/text-to-image",
|
|
1727
|
-
falPricing: {
|
|
1728
|
-
checkedAt: FAL_PRICING_CHECKED_AT,
|
|
1729
|
-
currency: "USD",
|
|
1730
|
-
endpointId: "fal-ai/recraft/v3/text-to-image",
|
|
1731
|
-
estimatedCostPerImageUsd: .04,
|
|
1732
|
-
source: "fal-pricing-api",
|
|
1733
|
-
unit: "images",
|
|
1734
|
-
unitPrice: .04
|
|
1735
|
-
},
|
|
1736
|
-
name: "Recraft V3",
|
|
1737
|
-
pricePerImageUsd: .04,
|
|
1738
|
-
pricing: "$0.04",
|
|
1739
|
-
sizeMode: "image_size_enum",
|
|
1740
|
-
supportsAspect: true,
|
|
1741
|
-
supportsEdit: false,
|
|
1742
|
-
supportsNumImages: false,
|
|
1743
|
-
supportsResolution: false,
|
|
1744
|
-
supportsStyle: true,
|
|
1745
|
-
supportsSyncMode: true,
|
|
1746
|
-
type: "generation"
|
|
1747
|
-
},
|
|
1748
|
-
reve: {
|
|
1749
|
-
benchmark: {
|
|
1750
|
-
tiers: {
|
|
1751
|
-
price: "premium",
|
|
1752
|
-
quality: "frontier",
|
|
1753
|
-
speed: "unknown"
|
|
1754
|
-
},
|
|
1755
|
-
useCase: "Historical Reve route; not currently verified on fal"
|
|
1756
|
-
},
|
|
1757
|
-
editEndpoint: "fal-ai/reve/edit",
|
|
1758
|
-
endpoint: "fal-ai/reve/text-to-image",
|
|
1759
|
-
falPricing: {
|
|
1760
|
-
checkedAt: FAL_PRICING_CHECKED_AUG_2026,
|
|
1761
|
-
currency: "USD",
|
|
1762
|
-
endpointId: "fal-ai/reve/text-to-image",
|
|
1763
|
-
estimatedCostPerImageUsd: .04,
|
|
1764
|
-
source: "fal-pricing-api",
|
|
1765
|
-
unit: "images",
|
|
1766
|
-
unitPrice: .04
|
|
1767
|
-
},
|
|
1768
|
-
maxReferenceImages: 1,
|
|
1769
|
-
name: "Reve 2.1",
|
|
1770
|
-
pricePerImageUsd: .04,
|
|
1771
|
-
pricing: "$0.04",
|
|
1772
|
-
sizeMode: "aspect_ratio",
|
|
1773
|
-
supportedAspects: [
|
|
1774
|
-
"16:9",
|
|
1775
|
-
"9:16",
|
|
1776
|
-
"3:2",
|
|
1777
|
-
"2:3",
|
|
1778
|
-
"4:3",
|
|
1779
|
-
"3:4",
|
|
1780
|
-
"1:1"
|
|
1781
|
-
],
|
|
1782
|
-
supportsAspect: true,
|
|
1783
|
-
supportsEdit: true,
|
|
1784
|
-
supportsNumImages: true,
|
|
1785
|
-
supportsOutputFormat: true,
|
|
1786
|
-
supportsResolution: false,
|
|
1787
|
-
supportsSeed: false,
|
|
1788
|
-
supportsSyncMode: true,
|
|
1789
|
-
type: "generation"
|
|
1790
|
-
},
|
|
1791
|
-
recraft4: {
|
|
1792
|
-
benchmark: { artificialAnalysis: {
|
|
1793
|
-
snapshotDate: AA_IMAGE_LEADERBOARD_SNAPSHOT,
|
|
1794
|
-
sourceUrls: AA_IMAGE_SOURCES,
|
|
1795
|
-
textToImage: {
|
|
1796
|
-
elo: 984,
|
|
1797
|
-
rank: 62
|
|
1798
|
-
}
|
|
1799
|
-
} },
|
|
1800
|
-
customImageSize: {},
|
|
1801
|
-
endpoint: "fal-ai/recraft/v4/text-to-image",
|
|
1802
|
-
falPricing: {
|
|
1803
|
-
checkedAt: FAL_PRICING_CHECKED_JUL_2026,
|
|
1804
|
-
currency: "USD",
|
|
1805
|
-
endpointId: "fal-ai/recraft/v4/text-to-image",
|
|
1806
|
-
estimatedCostPerImageUsd: .04,
|
|
1807
|
-
source: "fal-pricing-api",
|
|
1808
|
-
unit: "images",
|
|
1809
|
-
unitPrice: .04
|
|
1810
|
-
},
|
|
1811
|
-
name: "Recraft V4",
|
|
1812
|
-
pricePerImageUsd: .04,
|
|
1813
|
-
pricing: "$0.04",
|
|
1814
|
-
sizeMode: "image_size_enum",
|
|
1815
|
-
supportsAspect: true,
|
|
1816
|
-
supportsEdit: false,
|
|
1817
|
-
supportsNumImages: false,
|
|
1818
|
-
supportsResolution: false,
|
|
1819
|
-
supportsSyncMode: true,
|
|
1820
|
-
type: "generation"
|
|
1821
|
-
},
|
|
1822
|
-
ideogram: {
|
|
1823
|
-
customImageSize: {},
|
|
1824
|
-
endpoint: "fal-ai/ideogram/v3",
|
|
1825
|
-
falPricing: {
|
|
1826
|
-
checkedAt: FAL_PRICING_CHECKED_AT,
|
|
1827
|
-
currency: "USD",
|
|
1828
|
-
endpointId: "fal-ai/ideogram/v3",
|
|
1829
|
-
estimatedCostPerImageUsd: .03,
|
|
1830
|
-
source: "fal-pricing-api",
|
|
1831
|
-
unit: "images",
|
|
1832
|
-
unitPrice: .03
|
|
1833
|
-
},
|
|
1834
|
-
name: "Ideogram V3",
|
|
1835
|
-
pricePerImageUsd: .03,
|
|
1836
|
-
pricing: "$0.03",
|
|
1837
|
-
sizeMode: "image_size_enum",
|
|
1838
|
-
supportsAspect: true,
|
|
1839
|
-
supportsEdit: false,
|
|
1840
|
-
supportsExpandPrompt: true,
|
|
1841
|
-
supportsNegativePrompt: true,
|
|
1842
|
-
supportsNumImages: true,
|
|
1843
|
-
supportsRenderingSpeed: true,
|
|
1844
|
-
supportsResolution: false,
|
|
1845
|
-
supportsSeed: true,
|
|
1846
|
-
supportsStyle: true,
|
|
1847
|
-
supportsSyncMode: true,
|
|
1848
|
-
type: "generation"
|
|
1849
|
-
},
|
|
1850
1334
|
ideogram4: {
|
|
1851
1335
|
benchmark: { artificialAnalysis: {
|
|
1852
1336
|
snapshotDate: AA_IMAGE_LEADERBOARD_SNAPSHOT,
|
|
@@ -1947,52 +1431,6 @@ const MODELS = {
|
|
|
1947
1431
|
supportsSyncMode: true,
|
|
1948
1432
|
type: "generation"
|
|
1949
1433
|
},
|
|
1950
|
-
qwen: {
|
|
1951
|
-
benchmark: {
|
|
1952
|
-
artificialAnalysis: {
|
|
1953
|
-
snapshotDate: AA_IMAGE_LEADERBOARD_SNAPSHOT,
|
|
1954
|
-
sourceUrls: AA_IMAGE_SOURCES,
|
|
1955
|
-
textToImage: {
|
|
1956
|
-
elo: 890,
|
|
1957
|
-
rank: 106
|
|
1958
|
-
}
|
|
1959
|
-
},
|
|
1960
|
-
speed: {
|
|
1961
|
-
medianSeconds: 23.3,
|
|
1962
|
-
p95Seconds: 491,
|
|
1963
|
-
source: "artificial-analysis-models"
|
|
1964
|
-
},
|
|
1965
|
-
tiers: {
|
|
1966
|
-
price: "budget",
|
|
1967
|
-
quality: "better",
|
|
1968
|
-
speed: "slow"
|
|
1969
|
-
},
|
|
1970
|
-
useCase: "Low-cost open-weight text and design generation"
|
|
1971
|
-
},
|
|
1972
|
-
customImageSize: {},
|
|
1973
|
-
endpoint: "fal-ai/qwen-image",
|
|
1974
|
-
falPricing: {
|
|
1975
|
-
checkedAt: FAL_PRICING_CHECKED_AT,
|
|
1976
|
-
currency: "USD",
|
|
1977
|
-
endpointId: "fal-ai/qwen-image",
|
|
1978
|
-
estimatedCostPerImageUsd: .02,
|
|
1979
|
-
source: "fal-pricing-api",
|
|
1980
|
-
unit: "megapixels",
|
|
1981
|
-
unitPrice: .02
|
|
1982
|
-
},
|
|
1983
|
-
name: "Qwen Image",
|
|
1984
|
-
pricePerImageUsd: .02,
|
|
1985
|
-
pricing: "$0.02/MP",
|
|
1986
|
-
sizeMode: "image_size_enum",
|
|
1987
|
-
supportsAspect: true,
|
|
1988
|
-
supportsEdit: false,
|
|
1989
|
-
supportsNumImages: true,
|
|
1990
|
-
supportsOutputFormat: true,
|
|
1991
|
-
supportsResolution: false,
|
|
1992
|
-
supportsSeed: true,
|
|
1993
|
-
supportsSyncMode: true,
|
|
1994
|
-
type: "generation"
|
|
1995
|
-
},
|
|
1996
1434
|
qwen3: {
|
|
1997
1435
|
benchmark: {
|
|
1998
1436
|
artificialAnalysis: {
|
|
@@ -2393,29 +1831,9 @@ const MODELS = {
|
|
|
2393
1831
|
supportsNumImages: false,
|
|
2394
1832
|
supportsResolution: false,
|
|
2395
1833
|
type: "utility"
|
|
2396
|
-
},
|
|
2397
|
-
rmbg: {
|
|
2398
|
-
endpoint: "fal-ai/birefnet",
|
|
2399
|
-
name: "BiRefNet (Background Removal)",
|
|
2400
|
-
pricing: "$0.02",
|
|
2401
|
-
supportsAspect: false,
|
|
2402
|
-
supportsEdit: false,
|
|
2403
|
-
supportsNumImages: false,
|
|
2404
|
-
supportsResolution: false,
|
|
2405
|
-
type: "utility"
|
|
2406
|
-
},
|
|
2407
|
-
bria: {
|
|
2408
|
-
endpoint: "fal-ai/bria/background/remove",
|
|
2409
|
-
name: "Bria RMBG 2.0",
|
|
2410
|
-
pricing: "$0.02",
|
|
2411
|
-
supportsAspect: false,
|
|
2412
|
-
supportsEdit: false,
|
|
2413
|
-
supportsNumImages: false,
|
|
2414
|
-
supportsResolution: false,
|
|
2415
|
-
type: "utility"
|
|
2416
1834
|
}
|
|
2417
1835
|
};
|
|
2418
|
-
/** Curated generation
|
|
1836
|
+
/** Curated generation Models, the only ones Motif recommends. */
|
|
2419
1837
|
const GENERATION_MODELS = [
|
|
2420
1838
|
"sunburst",
|
|
2421
1839
|
"flare",
|
|
@@ -2441,30 +1859,8 @@ const GENERATION_MODELS = [
|
|
|
2441
1859
|
"ideogram3-transparent",
|
|
2442
1860
|
"recraft41"
|
|
2443
1861
|
];
|
|
2444
|
-
/** Retained for old pins, explicit overrides and tuned Looks, never auto-selected. */
|
|
2445
|
-
const LEGACY_GENERATION_MODELS = [
|
|
2446
|
-
"gemini",
|
|
2447
|
-
"gemini3",
|
|
2448
|
-
"seedream4",
|
|
2449
|
-
"seedream45",
|
|
2450
|
-
"flux2-max",
|
|
2451
|
-
"flux2-dev",
|
|
2452
|
-
"flux",
|
|
2453
|
-
"flux-fast",
|
|
2454
|
-
"recraft",
|
|
2455
|
-
"recraft4",
|
|
2456
|
-
"ideogram",
|
|
2457
|
-
"qwen"
|
|
2458
|
-
];
|
|
2459
1862
|
GENERATION_MODELS.filter((id) => MODELS[id]?.supportsEdit === true);
|
|
2460
|
-
|
|
2461
|
-
"clarity",
|
|
2462
|
-
"crystal",
|
|
2463
|
-
"rmbg",
|
|
2464
|
-
"bria"
|
|
2465
|
-
];
|
|
2466
|
-
//#endregion
|
|
2467
|
-
//#region src/cost.ts
|
|
1863
|
+
// src/cost.ts
|
|
2468
1864
|
/**
|
|
2469
1865
|
* Estimate cost based on model and settings. `editImages` is the number of
|
|
2470
1866
|
* input images on an edit, for Models whose edits cost more than generation.
|
|
@@ -2476,7 +1872,7 @@ function estimateCost(model, resolution, numImages = 1, editImages = 0) {
|
|
|
2476
1872
|
if (model === "grok-image-2" && editImages > 0) return (resolution === "2K" || resolution === "4K" ? .08 : .06) * numImages + .01 * editImages;
|
|
2477
1873
|
if (model === "grok-image-quality") return (resolution === "2K" || resolution === "4K" ? .07 : .05) * numImages + .01 * editImages;
|
|
2478
1874
|
if (configuredPrice !== void 0) {
|
|
2479
|
-
if (
|
|
1875
|
+
if (model === "banana" && resolution === "4K") return configuredPrice * 2 * numImages;
|
|
2480
1876
|
if (model === "seedream5" && (resolution === "2K" || resolution === "4K")) return configuredPrice * 2 * numImages;
|
|
2481
1877
|
if (model === "grok-image-2" && (resolution === "2K" || resolution === "4K")) return .08 * numImages;
|
|
2482
1878
|
if (model === "banana2") return configuredPrice * (resolution === "4K" ? 2 : resolution === "2K" ? 1.5 : resolution === "0.5K" ? .75 : 1) * numImages;
|
|
@@ -2484,17 +1880,8 @@ function estimateCost(model, resolution, numImages = 1, editImages = 0) {
|
|
|
2484
1880
|
}
|
|
2485
1881
|
switch (model) {
|
|
2486
1882
|
case "gpt": return .133 * numImages;
|
|
2487
|
-
case "banana":
|
|
2488
|
-
case "gemini3": return (resolution === "4K" ? .3 : .15) * numImages;
|
|
2489
|
-
case "gemini": return .039 * numImages;
|
|
2490
|
-
case "flux":
|
|
2491
|
-
case "ideogram": return .06 * numImages;
|
|
2492
|
-
case "recraft": return .04 * numImages;
|
|
2493
|
-
case "flux-fast": return .003 * numImages;
|
|
2494
1883
|
case "clarity": return .03 * numImages;
|
|
2495
|
-
case "crystal":
|
|
2496
|
-
case "rmbg":
|
|
2497
|
-
case "bria": return .02 * numImages;
|
|
1884
|
+
case "crystal": return .02 * numImages;
|
|
2498
1885
|
default: return .1 * numImages;
|
|
2499
1886
|
}
|
|
2500
1887
|
}
|
|
@@ -2503,8 +1890,7 @@ function estimateVideoCost(durationSeconds = 5, generateAudio = true, model = "k
|
|
|
2503
1890
|
if (model === "kling-turbo") return .14 * durationSeconds;
|
|
2504
1891
|
return (generateAudio ? .168 : .112) * durationSeconds;
|
|
2505
1892
|
}
|
|
2506
|
-
|
|
2507
|
-
//#region src/fal-parse.ts
|
|
1893
|
+
// src/fal-parse.ts
|
|
2508
1894
|
/**
|
|
2509
1895
|
* Boundary parsing for fal.ai HTTP responses.
|
|
2510
1896
|
*
|
|
@@ -2609,8 +1995,7 @@ function requestIdFromBody(text) {
|
|
|
2609
1995
|
if (!isRecord$1(parsed)) return;
|
|
2610
1996
|
return asString(parsed.request_id) ?? asString(parsed.requestId) ?? asString(parsed.trace_id);
|
|
2611
1997
|
}
|
|
2612
|
-
|
|
2613
|
-
//#region src/capabilities.ts
|
|
1998
|
+
// src/capabilities.ts
|
|
2614
1999
|
/**
|
|
2615
2000
|
* Which generation options each model accepts, derived from the registry.
|
|
2616
2001
|
*
|
|
@@ -2638,11 +2023,9 @@ const OPTION_CAPABILITIES = {
|
|
|
2638
2023
|
enableGoogleSearch: (config) => config.supportsGoogleSearch === true,
|
|
2639
2024
|
enableSafetyChecker: (config) => config.supportsSafetyChecker === true,
|
|
2640
2025
|
enableWebSearch: (config) => config.supportsWebSearch === true,
|
|
2641
|
-
enhancePrompt: (config) => config.supportsEnhancePrompt === true,
|
|
2642
2026
|
expandPrompt: (config) => config.supportsExpandPrompt === true,
|
|
2643
2027
|
guidanceScale: (config) => config.supportsGuidanceScale === true,
|
|
2644
2028
|
"image editing": (config) => config.supportsEdit,
|
|
2645
|
-
imagePromptStrength: (config) => config.supportsImagePromptStrength === true,
|
|
2646
2029
|
imageSize: (config) => config.sizeMode === "gpt_size" || config.sizeMode === "image_size_enum",
|
|
2647
2030
|
inputFidelity: (config) => config.sizeMode === "gpt_size",
|
|
2648
2031
|
limitGenerations: (config) => config.supportsLimitGenerations === true,
|
|
@@ -2653,12 +2036,10 @@ const OPTION_CAPABILITIES = {
|
|
|
2653
2036
|
numInferenceSteps: (config) => config.supportsInferenceSteps === true,
|
|
2654
2037
|
outputFormat: (config) => config.supportsOutputFormat === true,
|
|
2655
2038
|
quality: (config) => config.supportsQuality === true,
|
|
2656
|
-
raw: (config) => config.supportsRaw === true,
|
|
2657
2039
|
renderingSpeed: (config) => config.supportsRenderingSpeed === true,
|
|
2658
2040
|
resolution: (config) => config.supportsResolution,
|
|
2659
2041
|
safetyTolerance: (config) => config.supportsSafetyTolerance === true,
|
|
2660
2042
|
seed: (config) => config.supportsSeed === true,
|
|
2661
|
-
style: (config) => config.supportsStyle === true,
|
|
2662
2043
|
syncMode: (config) => config.supportsSyncMode === true,
|
|
2663
2044
|
thinkingLevel: (config) => config.supportsThinkingLevel === true,
|
|
2664
2045
|
"transparent output": (config) => config.supportsBackground === true || config.transparentOutput === true
|
|
@@ -2686,7 +2067,7 @@ function modelsSupporting(option) {
|
|
|
2686
2067
|
*/
|
|
2687
2068
|
var UnsupportedOptionError = class extends Error {
|
|
2688
2069
|
code = "INVALID_OPTION";
|
|
2689
|
-
/** Display name of the model that refused, e.g. `"Seedream
|
|
2070
|
+
/** Display name of the model that refused, e.g. `"Seedream 5 Pro"`. */
|
|
2690
2071
|
model;
|
|
2691
2072
|
/** Generation model ids that accept `option`. */
|
|
2692
2073
|
modelsSupporting;
|
|
@@ -2704,8 +2085,7 @@ var UnsupportedOptionError = class extends Error {
|
|
|
2704
2085
|
this.supportedOptions = supported;
|
|
2705
2086
|
}
|
|
2706
2087
|
};
|
|
2707
|
-
|
|
2708
|
-
//#region src/generate.ts
|
|
2088
|
+
// src/generate.ts
|
|
2709
2089
|
const GPT_IMAGE_SIZES = [
|
|
2710
2090
|
"auto",
|
|
2711
2091
|
"1024x1024",
|
|
@@ -2775,8 +2155,6 @@ function validateGenerateOptions(options, config, sizeMode, hasEditImages) {
|
|
|
2775
2155
|
if (config.sizeMode !== "gpt_size") unsupported(config, "inputFidelity");
|
|
2776
2156
|
}
|
|
2777
2157
|
if (options.imageSize !== void 0 && sizeMode !== "gpt_size" && sizeMode !== "image_size_enum") unsupported(config, "imageSize");
|
|
2778
|
-
if (options.imagePromptStrength !== void 0 && config.supportsImagePromptStrength !== true) unsupported(config, "imagePromptStrength");
|
|
2779
|
-
if (options.imagePromptStrength !== void 0 && !hasEditImages) throw new Error("imagePromptStrength requires editImageUrls");
|
|
2780
2158
|
if (options.maskImageUrl !== void 0 && config.supportsMaskImage !== true) unsupported(config, "maskImageUrl");
|
|
2781
2159
|
if (options.maskImageUrl !== void 0 && !hasEditImages) throw new Error("maskImageUrl requires editImageUrls");
|
|
2782
2160
|
if (options.markupImageUrl !== void 0 && config.supportsMarkupImage !== true) unsupported(config, "markupImageUrl");
|
|
@@ -2795,13 +2173,10 @@ function validateGenerateOptions(options, config, sizeMode, hasEditImages) {
|
|
|
2795
2173
|
if (!qualities.includes(options.quality)) throw new Error(`${config.name} quality must be one of ${qualities.join(", ")}`);
|
|
2796
2174
|
}
|
|
2797
2175
|
if (options.negativePrompt !== void 0 && config.supportsNegativePrompt !== true) unsupported(config, "negativePrompt");
|
|
2798
|
-
if (options.style !== void 0 && config.supportsStyle !== true) unsupported(config, "style");
|
|
2799
2176
|
if (options.syncMode !== void 0 && config.supportsSyncMode !== true) unsupported(config, "syncMode");
|
|
2800
2177
|
if (options.renderingSpeed !== void 0 && config.supportsRenderingSpeed !== true) unsupported(config, "renderingSpeed");
|
|
2801
2178
|
if (options.guidanceScale !== void 0 && config.supportsGuidanceScale !== true) unsupported(config, "guidanceScale");
|
|
2802
2179
|
if (options.numInferenceSteps !== void 0 && config.supportsInferenceSteps !== true) unsupported(config, "numInferenceSteps");
|
|
2803
|
-
if (options.raw !== void 0 && config.supportsRaw !== true) unsupported(config, "raw");
|
|
2804
|
-
if (options.enhancePrompt !== void 0 && config.supportsEnhancePrompt !== true) unsupported(config, "enhancePrompt");
|
|
2805
2180
|
if (options.safetyTolerance !== void 0 && config.supportsSafetyTolerance !== true) unsupported(config, "safetyTolerance");
|
|
2806
2181
|
if (options.enableWebSearch !== void 0 && config.supportsWebSearch !== true) unsupported(config, "enableWebSearch");
|
|
2807
2182
|
if (options.enableGoogleSearch !== void 0 && config.supportsGoogleSearch !== true) unsupported(config, "enableGoogleSearch");
|
|
@@ -2821,7 +2196,7 @@ function validateGenerateOptions(options, config, sizeMode, hasEditImages) {
|
|
|
2821
2196
|
* - `none`: no size control (video models)
|
|
2822
2197
|
*/
|
|
2823
2198
|
function buildGenerateBody(options) {
|
|
2824
|
-
const { prompt, model, creative, aspect = "1:1", resolution = "2K", numImages = 1, background, editImageUrls, enableGoogleSearch, enableSafetyChecker, transparent, inputFidelity, imageSize,
|
|
2199
|
+
const { prompt, model, creative, aspect = "1:1", resolution = "2K", numImages = 1, background, editImageUrls, enableGoogleSearch, enableSafetyChecker, transparent, inputFidelity, imageSize, limitGenerations, maskImageUrl, markupImageUrl, seed, outputFormat, quality, negativePrompt, syncMode, thinkingLevel, renderingSpeed, guidanceScale, numInferenceSteps, safetyTolerance, enableWebSearch, expandPrompt } = options;
|
|
2825
2200
|
const config = MODELS[model];
|
|
2826
2201
|
if (!config) throw new Error(`Unknown model: ${model}`);
|
|
2827
2202
|
let { endpoint } = config;
|
|
@@ -2857,12 +2232,6 @@ function buildGenerateBody(options) {
|
|
|
2857
2232
|
if (!formats.includes(outputFormat)) throw new Error(`${config.name} ${hasEditImages ? "edits support" : "supports"} output formats: ${formats.join(", ")}`);
|
|
2858
2233
|
body.output_format = outputFormat;
|
|
2859
2234
|
}
|
|
2860
|
-
if (config.supportsRaw === true && raw !== void 0) body.raw = raw;
|
|
2861
|
-
if (config.supportsEnhancePrompt === true && enhancePrompt !== void 0) body.enhance_prompt = enhancePrompt;
|
|
2862
|
-
if (config.supportsImagePromptStrength === true && imagePromptStrength !== void 0) body.image_prompt_strength = imagePromptStrength;
|
|
2863
|
-
if (model === "flux") {
|
|
2864
|
-
if (safetyTolerance !== void 0 && safetyTolerance !== "") body.safety_tolerance = safetyTolerance;
|
|
2865
|
-
}
|
|
2866
2235
|
if (config.supportsGuidanceScale === true && guidanceScale !== void 0) body.guidance_scale = guidanceScale;
|
|
2867
2236
|
if (config.supportsInferenceSteps === true && numInferenceSteps !== void 0) body.num_inference_steps = numInferenceSteps;
|
|
2868
2237
|
if (config.supportsSafetyTolerance === true) {
|
|
@@ -2883,25 +2252,17 @@ function buildGenerateBody(options) {
|
|
|
2883
2252
|
if (config.supportsThinkingLevel === true) {
|
|
2884
2253
|
if (thinkingLevel) body.thinking_level = thinkingLevel;
|
|
2885
2254
|
}
|
|
2886
|
-
if (config.supportsStyle === true && style !== void 0 && style !== "") body.style = style;
|
|
2887
2255
|
if (config.supportsNegativePrompt === true) {
|
|
2888
2256
|
if (negativePrompt !== void 0 && negativePrompt !== "") body.negative_prompt = negativePrompt;
|
|
2889
2257
|
}
|
|
2890
|
-
if (model === "ideogram") {
|
|
2891
|
-
if (style !== void 0 && style !== "") body.style = style;
|
|
2892
|
-
}
|
|
2893
2258
|
if (config.supportsRenderingSpeed === true) {
|
|
2894
2259
|
if (renderingSpeed) body.rendering_speed = renderingSpeed;
|
|
2895
2260
|
}
|
|
2896
2261
|
if (config.supportsExpandPrompt === true) {
|
|
2897
2262
|
if (expandPrompt !== void 0) body.expand_prompt = expandPrompt;
|
|
2898
2263
|
}
|
|
2899
|
-
if (model === "flux" && hasEditImages) {
|
|
2900
|
-
body.image_url = editImages[0];
|
|
2901
|
-
body.image_prompt_strength = imagePromptStrength ?? .5;
|
|
2902
|
-
}
|
|
2903
2264
|
if (config.supportsNumImages) body.num_images = numImages;
|
|
2904
|
-
if (hasEditImages && sizeMode !== "gpt_size"
|
|
2265
|
+
if (hasEditImages && sizeMode !== "gpt_size") {
|
|
2905
2266
|
if (!config.supportsEdit) throw new Error(`Model ${model} does not support image editing`);
|
|
2906
2267
|
endpoint = config.editEndpoint ?? `${endpoint}/edit`;
|
|
2907
2268
|
const editImagesField = config.editImagesField ?? "image_urls";
|
|
@@ -2919,8 +2280,7 @@ function buildGenerateBody(options) {
|
|
|
2919
2280
|
endpoint
|
|
2920
2281
|
};
|
|
2921
2282
|
}
|
|
2922
|
-
|
|
2923
|
-
//#region src/tool-registry/analysis.ts
|
|
2283
|
+
// src/tool-registry/analysis.ts
|
|
2924
2284
|
const ANALYSIS_TOOLS = {
|
|
2925
2285
|
"got-ocr": {
|
|
2926
2286
|
category: "analysis",
|
|
@@ -3034,8 +2394,7 @@ const ANALYSIS_TOOLS = {
|
|
|
3034
2394
|
task: "vision moderation"
|
|
3035
2395
|
}
|
|
3036
2396
|
};
|
|
3037
|
-
|
|
3038
|
-
//#region src/tool-registry/assets.ts
|
|
2397
|
+
// src/tool-registry/assets.ts
|
|
3039
2398
|
const ASSET_TOOLS = {
|
|
3040
2399
|
"hunyuan3d-v3": {
|
|
3041
2400
|
category: "3d",
|
|
@@ -3353,8 +2712,7 @@ const ASSET_TOOLS = {
|
|
|
3353
2712
|
task: "single-image 3D reconstruction"
|
|
3354
2713
|
}
|
|
3355
2714
|
};
|
|
3356
|
-
|
|
3357
|
-
//#region src/tool-registry/background.ts
|
|
2715
|
+
// src/tool-registry/background.ts
|
|
3358
2716
|
const BACKGROUND_TOOLS = {
|
|
3359
2717
|
"ben-v2": {
|
|
3360
2718
|
category: "background",
|
|
@@ -3729,8 +3087,7 @@ const BACKGROUND_TOOLS = {
|
|
|
3729
3087
|
task: "video enhancement"
|
|
3730
3088
|
}
|
|
3731
3089
|
};
|
|
3732
|
-
|
|
3733
|
-
//#region src/tool-registry/editing.ts
|
|
3090
|
+
// src/tool-registry/editing.ts
|
|
3734
3091
|
const EDITING_TOOLS = {
|
|
3735
3092
|
"bria-eraser": {
|
|
3736
3093
|
category: "erase",
|
|
@@ -4001,8 +3358,7 @@ const EDITING_TOOLS = {
|
|
|
4001
3358
|
task: "virtual garment try-on"
|
|
4002
3359
|
}
|
|
4003
3360
|
};
|
|
4004
|
-
|
|
4005
|
-
//#region src/tool-registry/structure.ts
|
|
3361
|
+
// src/tool-registry/structure.ts
|
|
4006
3362
|
const STRUCTURE_TOOLS = {
|
|
4007
3363
|
"depth-anything": {
|
|
4008
3364
|
category: "preprocess",
|
|
@@ -4394,8 +3750,7 @@ const STRUCTURE_TOOLS = {
|
|
|
4394
3750
|
task: "depth preprocessing"
|
|
4395
3751
|
}
|
|
4396
3752
|
};
|
|
4397
|
-
|
|
4398
|
-
//#region src/tools.ts
|
|
3753
|
+
// src/tools.ts
|
|
4399
3754
|
const FAL_TOOLS = {
|
|
4400
3755
|
...ANALYSIS_TOOLS,
|
|
4401
3756
|
...ASSET_TOOLS,
|
|
@@ -4423,8 +3778,7 @@ function buildFalToolRequest(options) {
|
|
|
4423
3778
|
tool
|
|
4424
3779
|
};
|
|
4425
3780
|
}
|
|
4426
|
-
|
|
4427
|
-
//#region src/server-tools.ts
|
|
3781
|
+
// src/server-tools.ts
|
|
4428
3782
|
/**
|
|
4429
3783
|
* Tool execution bodies for `FalClient`, both synchronous and queued.
|
|
4430
3784
|
*
|
|
@@ -4554,8 +3908,7 @@ async function runToolQueued(exec, options, onProgress) {
|
|
|
4554
3908
|
if (request.isErr()) return err$1(request.error);
|
|
4555
3909
|
return (await runRequestQueued(exec, request.value, onProgress)).map(({ data }) => data);
|
|
4556
3910
|
}
|
|
4557
|
-
|
|
4558
|
-
//#region src/server.ts
|
|
3911
|
+
// src/server.ts
|
|
4559
3912
|
const FAL_BASE_URL = "https://fal.run";
|
|
4560
3913
|
const FAL_QUEUE_URL = "https://queue.fal.run";
|
|
4561
3914
|
const FAL_API_URL = "https://api.fal.ai";
|
|
@@ -4690,100 +4043,6 @@ var FalClient = class {
|
|
|
4690
4043
|
const data = await response.value.json();
|
|
4691
4044
|
return this.normalizeResponse(data, requestId);
|
|
4692
4045
|
}
|
|
4693
|
-
/** ─── Processing ──────────────────────────────────────────── */
|
|
4694
|
-
/** Upscale an image using clarity or crystal upscaler. */
|
|
4695
|
-
async upscale(options) {
|
|
4696
|
-
const { imageUrl, model = "clarity", scaleFactor, creativity, resemblance, prompt: upscalePrompt, negativePrompt, numInferenceSteps, guidanceScale } = options;
|
|
4697
|
-
const config = MODELS[model];
|
|
4698
|
-
if (!config || config.type !== "utility") return err$1(new MotifError(`Invalid upscale model: ${model}`, 0));
|
|
4699
|
-
const body = { image_url: imageUrl };
|
|
4700
|
-
if (model === "crystal") {
|
|
4701
|
-
if (scaleFactor !== void 0) body.scale_factor = scaleFactor;
|
|
4702
|
-
if (creativity !== void 0) body.creativity = creativity;
|
|
4703
|
-
} else {
|
|
4704
|
-
if (scaleFactor !== void 0) body.upscale_factor = scaleFactor;
|
|
4705
|
-
if (creativity !== void 0) body.creativity = creativity;
|
|
4706
|
-
if (resemblance !== void 0) body.resemblance = resemblance;
|
|
4707
|
-
if (upscalePrompt !== void 0 && upscalePrompt !== "") body.prompt = upscalePrompt;
|
|
4708
|
-
if (negativePrompt !== void 0 && negativePrompt !== "") body.negative_prompt = negativePrompt;
|
|
4709
|
-
if (numInferenceSteps !== void 0) body.num_inference_steps = numInferenceSteps;
|
|
4710
|
-
if (guidanceScale !== void 0) body.guidance_scale = guidanceScale;
|
|
4711
|
-
}
|
|
4712
|
-
const response = await this.request(`${FAL_BASE_URL}/${config.endpoint}`, {
|
|
4713
|
-
body: JSON.stringify(body),
|
|
4714
|
-
method: "POST"
|
|
4715
|
-
});
|
|
4716
|
-
if (response.isErr()) return err$1(response.error);
|
|
4717
|
-
const data = await response.value.json();
|
|
4718
|
-
return this.normalizeResponse(data);
|
|
4719
|
-
}
|
|
4720
|
-
/** Remove the background from an image. */
|
|
4721
|
-
async removeBackground(options) {
|
|
4722
|
-
const { imageUrl, model = "rmbg", variant, operatingResolution, outputFormat, refineForeground, outputMask } = options;
|
|
4723
|
-
const config = MODELS[model];
|
|
4724
|
-
if (!config) return err$1(new MotifError(`Invalid background removal model: ${model}`, 0));
|
|
4725
|
-
const rbBody = { image_url: imageUrl };
|
|
4726
|
-
if (model === "rmbg") {
|
|
4727
|
-
if (variant) rbBody.model = variant;
|
|
4728
|
-
if (operatingResolution) rbBody.operating_resolution = operatingResolution;
|
|
4729
|
-
if (outputFormat) rbBody.output_format = outputFormat;
|
|
4730
|
-
if (refineForeground !== void 0) rbBody.refine_foreground = refineForeground;
|
|
4731
|
-
if (outputMask !== void 0) rbBody.output_mask = outputMask;
|
|
4732
|
-
}
|
|
4733
|
-
const response = await this.request(`${FAL_BASE_URL}/${config.endpoint}`, {
|
|
4734
|
-
body: JSON.stringify(rbBody),
|
|
4735
|
-
method: "POST"
|
|
4736
|
-
});
|
|
4737
|
-
if (response.isErr()) return err$1(response.error);
|
|
4738
|
-
const data = await response.value.json();
|
|
4739
|
-
return this.normalizeResponse(data);
|
|
4740
|
-
}
|
|
4741
|
-
/** ─── Video Generation ───────────────────────────────────── */
|
|
4742
|
-
/**
|
|
4743
|
-
* Generate a video from an image using Kling v3 Pro.
|
|
4744
|
-
* This uses the queue API since video generation takes 30-120s.
|
|
4745
|
-
* Returns immediately with a job — poll with getJobStatus/getVideoResult.
|
|
4746
|
-
*/
|
|
4747
|
-
async submitVideo(options) {
|
|
4748
|
-
const { imageUrl, prompt, duration = 5, generateAudio = true, endImageUrl, negativePrompt, cfgScale } = options;
|
|
4749
|
-
const config = MODELS.kling;
|
|
4750
|
-
if (!config) return err$1(new MotifError("Kling video model not found", 0));
|
|
4751
|
-
const body = {
|
|
4752
|
-
duration: String(duration),
|
|
4753
|
-
generate_audio: generateAudio,
|
|
4754
|
-
prompt,
|
|
4755
|
-
start_image_url: imageUrl
|
|
4756
|
-
};
|
|
4757
|
-
if (endImageUrl !== void 0 && endImageUrl !== "") body.end_image_url = endImageUrl;
|
|
4758
|
-
if (negativePrompt !== void 0 && negativePrompt !== "") body.negative_prompt = negativePrompt;
|
|
4759
|
-
if (cfgScale !== void 0) body.cfg_scale = cfgScale;
|
|
4760
|
-
const response = await this.request(`${FAL_QUEUE_URL}/${config.endpoint}`, {
|
|
4761
|
-
body: JSON.stringify(body),
|
|
4762
|
-
method: "POST"
|
|
4763
|
-
});
|
|
4764
|
-
if (response.isErr()) return err$1(response.error);
|
|
4765
|
-
const submission = parseQueueSubmission(await response.value.json());
|
|
4766
|
-
return ok$1({
|
|
4767
|
-
endpoint: endpointFromQueueUrl(submission.responseUrl, config.endpoint),
|
|
4768
|
-
estimatedCost: estimateVideoCost(duration, generateAudio),
|
|
4769
|
-
requestId: submission.requestId
|
|
4770
|
-
});
|
|
4771
|
-
}
|
|
4772
|
-
/** Fetch the completed video result from the queue. */
|
|
4773
|
-
async getVideoResult(endpoint, requestId) {
|
|
4774
|
-
const url = `${FAL_QUEUE_URL}/${endpoint}/requests/${requestId}`;
|
|
4775
|
-
const response = await this.request(url);
|
|
4776
|
-
if (response.isErr()) return err$1(response.error);
|
|
4777
|
-
const data = await response.value.json();
|
|
4778
|
-
const video = isRecord$1(data) && isRecord$1(data.video) ? data.video : void 0;
|
|
4779
|
-
if (video === void 0) return err$1(new MotifError("No video in response", 0));
|
|
4780
|
-
return ok$1({
|
|
4781
|
-
contentType: asString(video.content_type) ?? "",
|
|
4782
|
-
fileName: asString(video.file_name) ?? "",
|
|
4783
|
-
fileSize: asNumber(video.file_size) ?? 0,
|
|
4784
|
-
url: asString(video.url) ?? ""
|
|
4785
|
-
});
|
|
4786
|
-
}
|
|
4787
4046
|
/** ─── File Upload ─────────────────────────────────────────── */
|
|
4788
4047
|
/**
|
|
4789
4048
|
* Upload a file to fal.ai CDN storage and return the public URL.
|
|
@@ -4879,10 +4138,6 @@ var FalClient = class {
|
|
|
4879
4138
|
get generationModels() {
|
|
4880
4139
|
return GENERATION_MODELS;
|
|
4881
4140
|
}
|
|
4882
|
-
/** Utility model keys. */
|
|
4883
|
-
get utilityModels() {
|
|
4884
|
-
return UTILITY_MODELS;
|
|
4885
|
-
}
|
|
4886
4141
|
/** Registered fal utility/tool endpoints. */
|
|
4887
4142
|
get tools() {
|
|
4888
4143
|
return FAL_TOOLS;
|
|
@@ -4970,8 +4225,7 @@ var FalClient = class {
|
|
|
4970
4225
|
});
|
|
4971
4226
|
}
|
|
4972
4227
|
};
|
|
4973
|
-
|
|
4974
|
-
//#region src/source-size.ts
|
|
4228
|
+
// src/source-size.ts
|
|
4975
4229
|
const DATA_URL_REGEX = /^data:[^;,]*;base64,(.*)$/s;
|
|
4976
4230
|
function decodeBase64(data) {
|
|
4977
4231
|
try {
|
|
@@ -5069,8 +4323,7 @@ function dataUrlImageSize(url) {
|
|
|
5069
4323
|
const size = pngSize(bytes) ?? jpegSize(bytes) ?? webpSize(bytes);
|
|
5070
4324
|
return size !== void 0 && size.width > 0 && size.height > 0 ? size : void 0;
|
|
5071
4325
|
}
|
|
5072
|
-
|
|
5073
|
-
//#region src/tool-cost.ts
|
|
4326
|
+
// src/tool-cost.ts
|
|
5074
4327
|
/**
|
|
5075
4328
|
* What a tool run costs, before it happens and after.
|
|
5076
4329
|
*
|
|
@@ -5254,8 +4507,8 @@ function sumCosts(costs) {
|
|
|
5254
4507
|
unknown
|
|
5255
4508
|
};
|
|
5256
4509
|
}
|
|
5257
|
-
|
|
5258
|
-
|
|
4510
|
+
// src/image-benchmarks.ts
|
|
4511
|
+
const MEASURED_ON_2_5 = "Measured on GPT Image 2.5. Motif runs GPT Image 2.6, which Arena has not scored yet.";
|
|
5259
4512
|
const BOARDS = {
|
|
5260
4513
|
"text-to-image": {
|
|
5261
4514
|
sunburst: {
|
|
@@ -5263,6 +4516,7 @@ const BOARDS = {
|
|
|
5263
4516
|
rank: 1,
|
|
5264
4517
|
uncertainty: 5,
|
|
5265
4518
|
evaluatedModel: "GPT-Image-2.5 Sunburst",
|
|
4519
|
+
note: MEASURED_ON_2_5,
|
|
5266
4520
|
preliminary: true,
|
|
5267
4521
|
votes: 40323
|
|
5268
4522
|
},
|
|
@@ -5271,6 +4525,7 @@ const BOARDS = {
|
|
|
5271
4525
|
rank: 2,
|
|
5272
4526
|
uncertainty: 5,
|
|
5273
4527
|
evaluatedModel: "GPT-Image-2.5 Flare",
|
|
4528
|
+
note: MEASURED_ON_2_5,
|
|
5274
4529
|
preliminary: true,
|
|
5275
4530
|
votes: 39218
|
|
5276
4531
|
},
|
|
@@ -5360,6 +4615,7 @@ const BOARDS = {
|
|
|
5360
4615
|
rank: 1,
|
|
5361
4616
|
uncertainty: 5,
|
|
5362
4617
|
evaluatedModel: "GPT-Image-2.5 Sunburst",
|
|
4618
|
+
note: MEASURED_ON_2_5,
|
|
5363
4619
|
preliminary: true
|
|
5364
4620
|
},
|
|
5365
4621
|
flare: {
|
|
@@ -5367,6 +4623,7 @@ const BOARDS = {
|
|
|
5367
4623
|
rank: 2,
|
|
5368
4624
|
uncertainty: 5,
|
|
5369
4625
|
evaluatedModel: "GPT-Image-2.5 Flare",
|
|
4626
|
+
note: MEASURED_ON_2_5,
|
|
5370
4627
|
preliminary: true
|
|
5371
4628
|
},
|
|
5372
4629
|
"grok-image-2": {
|
|
@@ -5436,8 +4693,7 @@ function imageModelBenchmark(model, task) {
|
|
|
5436
4693
|
task
|
|
5437
4694
|
};
|
|
5438
4695
|
}
|
|
5439
|
-
|
|
5440
|
-
//#region src/tasks.ts
|
|
4696
|
+
// src/tasks.ts
|
|
5441
4697
|
/**
|
|
5442
4698
|
* The Task registry: every job Motif does, with the Models that can do it
|
|
5443
4699
|
* ranked best-first and tagged with the Tier each belongs to.
|
|
@@ -5814,7 +5070,7 @@ const TASKS = {
|
|
|
5814
5070
|
summary: "Remove an object, person, text or clutter from an image and fill the gap."
|
|
5815
5071
|
},
|
|
5816
5072
|
generate: {
|
|
5817
|
-
basis: "Order follows Arena text-to-image (https://arena.ai/leaderboard/image/text-to-image), read 2026-10-29
|
|
5073
|
+
basis: "Order follows Arena text-to-image (https://arena.ai/leaderboard/image/text-to-image), read 2026-10-29. Sunburst and Flare lead quality at the benchmarked max setting. Balanced starts with Nano Banana 2.1 on preliminary Arena evidence, then Grok Image 2 and Muse Image. Models not yet on the board follow the ranked ones in their Tier, in their previous order. The Artificial Analysis v2 snapshot of 2026-10-07 stays as recorded benchmark data. Fast keeps Nano Banana 2 Lite, budget Grok and Seedream 5 Lite, and FLUX.2 Turbo. Design, transparency and tuned Look routes are capability exceptions. Generation with References uses the separate editing ranking. Older routes are explicit/pin/Look-only.",
|
|
5818
5074
|
models: GENERATION_MODELS_RANKED,
|
|
5819
5075
|
notFor: "Variations of an image you already have (vary), or a consistent set of images (series run).",
|
|
5820
5076
|
rankedAt: IMAGE_RANKED_AT,
|
|
@@ -6302,7 +5558,7 @@ const TASKS = {
|
|
|
6302
5558
|
summary: "Trace a raster image to a clean SVG."
|
|
6303
5559
|
},
|
|
6304
5560
|
vary: {
|
|
6305
|
-
basis: "Order follows Arena image edit, single image (https://arena.ai/leaderboard/image/image-edit/single-image), read 2026-10-29
|
|
5561
|
+
basis: "Order follows Arena image edit, single image (https://arena.ai/leaderboard/image/image-edit/single-image), read 2026-10-29. Editing order differs from generation: Grok Image 2 leads balanced, ahead of Nano Banana 2.1, and Seedream 5 Pro outranks GPT Image 1.5. Arena scores Krea 3 only at its Ultra setting, which costs $0.27 to $0.35 an edit and ignores the requested size, so krea3, which runs fal's default setting, is ranked as unscored. Models not yet on the board follow the ranked ones in their Tier, in their previous order. The Artificial Analysis v2 snapshot of 2026-10-07 stays as recorded benchmark data. Sunburst and Flare use max quality. vary reuses a previously chosen Model when explicitly supplied, including retained legacy routes.",
|
|
6306
5562
|
models: EDITING_MODELS_RANKED,
|
|
6307
5563
|
notFor: "A specific change to an image described in words (generate with a reference), or a set of different scenes in one style (series run).",
|
|
6308
5564
|
rankedAt: IMAGE_RANKED_AT,
|
|
@@ -6314,8 +5570,7 @@ const TASK_IDS = Object.keys(TASKS).filter(isTaskId);
|
|
|
6314
5570
|
function isTaskId(value) {
|
|
6315
5571
|
return Object.hasOwn(TASKS, value);
|
|
6316
5572
|
}
|
|
6317
|
-
|
|
6318
|
-
//#region src/tool-parameters.generated.ts
|
|
5573
|
+
// src/tool-parameters.generated.ts
|
|
6319
5574
|
const FAL_TOOL_PARAMETERS = {
|
|
6320
5575
|
"ben-v2": [{
|
|
6321
5576
|
key: "seed",
|
|
@@ -8472,8 +7727,7 @@ const FAL_TOOL_PARAMETERS = {
|
|
|
8472
7727
|
function falToolParameters(tool) {
|
|
8473
7728
|
return FAL_TOOL_PARAMETERS[tool] ?? [];
|
|
8474
7729
|
}
|
|
8475
|
-
|
|
8476
|
-
//#region src/resolve.ts
|
|
7730
|
+
// src/resolve.ts
|
|
8477
7731
|
/**
|
|
8478
7732
|
* Model choice: the one place a Model is chosen, for the CLI and the SDK.
|
|
8479
7733
|
*
|
|
@@ -8508,6 +7762,7 @@ function generationProfile(config) {
|
|
|
8508
7762
|
if (config.supportsNegativePrompt === true) capabilities.add("negativePrompt");
|
|
8509
7763
|
if (config.supportsOutputFormat === true) capabilities.add("outputFormat");
|
|
8510
7764
|
return {
|
|
7765
|
+
name: config.name,
|
|
8511
7766
|
aspects: config.supportedAspects,
|
|
8512
7767
|
capabilities,
|
|
8513
7768
|
keys: [FAL_KEY],
|
|
@@ -8541,6 +7796,7 @@ function toolProfile(tool) {
|
|
|
8541
7796
|
const takesReference = "referenceField" in config;
|
|
8542
7797
|
if (takesReference) capabilities.add("references");
|
|
8543
7798
|
return {
|
|
7799
|
+
name: config.name,
|
|
8544
7800
|
capabilities,
|
|
8545
7801
|
keys: [FAL_KEY],
|
|
8546
7802
|
maxReferences: takesReference ? 1 : 0
|
|
@@ -8682,7 +7938,7 @@ function resolveFixed(task, fixed, request, needed, keys) {
|
|
|
8682
7938
|
const { chosenBy, model } = fixed;
|
|
8683
7939
|
const tier = request.tier ?? "balanced";
|
|
8684
7940
|
const entries = TASKS[task].models;
|
|
8685
|
-
const entry = entries.find((candidate) => candidate.model === model && candidate.mode === request.mode)
|
|
7941
|
+
const entry = entries.find((candidate) => candidate.model === model && candidate.mode === request.mode);
|
|
8686
7942
|
const profile = modelProfile(model);
|
|
8687
7943
|
if (entry === void 0 || profile === void 0) {
|
|
8688
7944
|
const servesTask = entries.some((candidate) => candidate.model === model);
|
|
@@ -8695,14 +7951,6 @@ function resolveFixed(task, fixed, request, needed, keys) {
|
|
|
8695
7951
|
unblockers.push(unblockerFor(result));
|
|
8696
7952
|
return unresolved(task, result.blockedBy, unblockers, `${model} (${chosenBy}) ${describeBlock(result.blockedBy, request, result.missingKey, result.missingInput)}.`, result.missingKey);
|
|
8697
7953
|
}
|
|
8698
|
-
/** Old pins and tuned Looks remain usable without recommending predecessors. */
|
|
8699
|
-
function legacyEntry(task, model, mode, tier) {
|
|
8700
|
-
if (mode !== void 0 || task !== "generate" && task !== "vary" || !LEGACY_GENERATION_MODELS.some((id) => id === model) || task === "vary" && MODELS[model]?.supportsEdit !== true) return;
|
|
8701
|
-
return {
|
|
8702
|
-
model,
|
|
8703
|
-
tier
|
|
8704
|
-
};
|
|
8705
|
-
}
|
|
8706
7954
|
function unknownForMode(task, model, mode, entries) {
|
|
8707
7955
|
const otherModes = entries.filter((candidate) => candidate.model === model).map((candidate) => candidate.mode ?? "no mode");
|
|
8708
7956
|
const inMode = [...new Set(entries.filter((candidate) => candidate.mode === mode).map((candidate) => candidate.model))];
|
|
@@ -8789,8 +8037,7 @@ function tierChangesChoice(task, request, environment) {
|
|
|
8789
8037
|
}
|
|
8790
8038
|
return chosen.size > 1;
|
|
8791
8039
|
}
|
|
8792
|
-
|
|
8793
|
-
//#region src/task-output.ts
|
|
8040
|
+
// src/task-output.ts
|
|
8794
8041
|
function isPlainRecord(value) {
|
|
8795
8042
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8796
8043
|
}
|
|
@@ -8915,8 +8162,7 @@ function labelUrls(urls, labels) {
|
|
|
8915
8162
|
return names !== void 0 && names.length === totals.get(key) ? names[occurrence] : void 0;
|
|
8916
8163
|
});
|
|
8917
8164
|
}
|
|
8918
|
-
|
|
8919
|
-
//#region src/task-plan-pricing.ts
|
|
8165
|
+
// src/task-plan-pricing.ts
|
|
8920
8166
|
/**
|
|
8921
8167
|
* What a generation request bills and which body keys the caller owns. Both
|
|
8922
8168
|
* read the body as sent, `params` included, because fal bills that body.
|
|
@@ -8995,8 +8241,7 @@ function checkParamsImageSize(config, model, task, params) {
|
|
|
8995
8241
|
task
|
|
8996
8242
|
});
|
|
8997
8243
|
}
|
|
8998
|
-
|
|
8999
|
-
//#region src/task-plan-tools.ts
|
|
8244
|
+
// src/task-plan-tools.ts
|
|
9000
8245
|
/**
|
|
9001
8246
|
* Request bodies for fal tool Models: map each TaskInput field onto the key
|
|
9002
8247
|
* the tool's generated parameter list names, refuse what it doesn't list, and
|
|
@@ -9345,8 +8590,7 @@ function toolPlan(task, model, input) {
|
|
|
9345
8590
|
queued: "queued" in tool
|
|
9346
8591
|
});
|
|
9347
8592
|
}
|
|
9348
|
-
|
|
9349
|
-
//#region src/task-plan-video.ts
|
|
8593
|
+
// src/task-plan-video.ts
|
|
9350
8594
|
/**
|
|
9351
8595
|
* Request bodies for video Models: Kling v3 Pro and Kling v3 Turbo Pro, which
|
|
9352
8596
|
* take the start frame under different keys and bill by the second.
|
|
@@ -9427,8 +8671,7 @@ function turboVideoPlan(task, endpoint, input) {
|
|
|
9427
8671
|
queued: true
|
|
9428
8672
|
});
|
|
9429
8673
|
}
|
|
9430
|
-
|
|
9431
|
-
//#region src/task-plan.ts
|
|
8674
|
+
// src/task-plan.ts
|
|
9432
8675
|
/**
|
|
9433
8676
|
* `plan()` for the Task client: resolve the Model, build the request body the
|
|
9434
8677
|
* Model's kind needs, and price it. Pure: no I/O.
|
|
@@ -9729,8 +8972,7 @@ function upscalerPlan(task, model, input) {
|
|
|
9729
8972
|
queued: false
|
|
9730
8973
|
});
|
|
9731
8974
|
}
|
|
9732
|
-
|
|
9733
|
-
//#region src/task-stream.ts
|
|
8975
|
+
// src/task-stream.ts
|
|
9734
8976
|
const MAX_EVENT_CHARACTERS = 16777216;
|
|
9735
8977
|
const JSON_START = /^[[{]/;
|
|
9736
8978
|
function parsePayload(text) {
|
|
@@ -10009,8 +9251,7 @@ function createFrames(requestId) {
|
|
|
10009
9251
|
function enforceBufferLimit(length, requestId) {
|
|
10010
9252
|
if (length > MAX_EVENT_CHARACTERS) throw new MotifError("Stream event exceeds the buffer limit.", 0, "STREAM_EVENT_TOO_LARGE", requestId);
|
|
10011
9253
|
}
|
|
10012
|
-
|
|
10013
|
-
//#region src/task-client.ts
|
|
9254
|
+
// src/task-client.ts
|
|
10014
9255
|
/**
|
|
10015
9256
|
* The Task client: one function per Task. `createMotif()` returns a client
|
|
10016
9257
|
* whose `generate`, `erase`, `upscale` and the rest resolve the Model through
|
|
@@ -10186,5 +9427,4 @@ function createMotif(config = {}) {
|
|
|
10186
9427
|
}
|
|
10187
9428
|
};
|
|
10188
9429
|
}
|
|
10189
|
-
//#endregion
|
|
10190
9430
|
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 };
|