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