@nodaro/shared 2.18.0 → 2.20.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/dist/index.cjs +350 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +955 -564
- package/dist/index.d.ts +955 -564
- package/dist/index.js +334 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/credit-identifiers.test.ts +180 -0
- package/src/__tests__/gvp-supported-providers.test.ts +22 -1
- package/src/__tests__/image-pricing-catalog-coverage.test.ts +139 -0
- package/src/__tests__/normalize-node-params.test.ts +36 -0
- package/src/__tests__/organizations-types.test.ts +29 -1
- package/src/__tests__/prompt-length-limits.test.ts +40 -0
- package/src/__tests__/suno-credit-type.test.ts +54 -0
- package/src/__tests__/video-analysis-brief.test.ts +61 -0
- package/src/__tests__/video-audio-capability.test.ts +43 -0
- package/src/__tests__/video-mode-for-inputs.test.ts +1 -1
- package/src/__tests__/wan-3-catalog.test.ts +243 -0
- package/src/credit-identifiers.ts +191 -21
- package/src/i18n/held-prop.ar.ts +2 -0
- package/src/i18n/held-prop.de.ts +3 -0
- package/src/i18n/held-prop.es.ts +3 -0
- package/src/i18n/held-prop.fr.ts +2 -0
- package/src/i18n/held-prop.he.ts +3 -0
- package/src/i18n/held-prop.hi.ts +2 -0
- package/src/i18n/held-prop.ja.ts +3 -0
- package/src/i18n/held-prop.ko.ts +3 -0
- package/src/i18n/held-prop.pt-BR.ts +3 -0
- package/src/i18n/held-prop.ru.ts +2 -0
- package/src/i18n/held-prop.zh-CN.ts +3 -0
- package/src/i18n/person.ar.ts +3 -0
- package/src/i18n/person.de.ts +4 -0
- package/src/i18n/person.es.ts +4 -0
- package/src/i18n/person.fr.ts +3 -0
- package/src/i18n/person.he.ts +4 -0
- package/src/i18n/person.hi.ts +3 -0
- package/src/i18n/person.ja.ts +4 -0
- package/src/i18n/person.ko.ts +4 -0
- package/src/i18n/person.pt-BR.ts +4 -0
- package/src/i18n/person.ru.ts +3 -0
- package/src/i18n/person.zh-CN.ts +4 -0
- package/src/i18n/setting.ar.ts +2 -0
- package/src/i18n/setting.de.ts +3 -0
- package/src/i18n/setting.es.ts +3 -0
- package/src/i18n/setting.fr.ts +2 -0
- package/src/i18n/setting.he.ts +3 -0
- package/src/i18n/setting.hi.ts +2 -0
- package/src/i18n/setting.ja.ts +3 -0
- package/src/i18n/setting.ko.ts +3 -0
- package/src/i18n/setting.pt-BR.ts +3 -0
- package/src/i18n/setting.ru.ts +2 -0
- package/src/i18n/setting.zh-CN.ts +3 -0
- package/src/i18n/style.ar.ts +2 -0
- package/src/i18n/style.de.ts +3 -0
- package/src/i18n/style.es.ts +3 -0
- package/src/i18n/style.fr.ts +2 -0
- package/src/i18n/style.he.ts +3 -0
- package/src/i18n/style.hi.ts +2 -0
- package/src/i18n/style.ja.ts +3 -0
- package/src/i18n/style.ko.ts +3 -0
- package/src/i18n/style.pt-BR.ts +3 -0
- package/src/i18n/style.ru.ts +2 -0
- package/src/i18n/style.zh-CN.ts +3 -0
- package/src/i18n/styling.ar.ts +4 -0
- package/src/i18n/styling.de.ts +5 -0
- package/src/i18n/styling.es.ts +5 -0
- package/src/i18n/styling.fr.ts +4 -0
- package/src/i18n/styling.he.ts +5 -0
- package/src/i18n/styling.hi.ts +4 -0
- package/src/i18n/styling.ja.ts +5 -0
- package/src/i18n/styling.ko.ts +5 -0
- package/src/i18n/styling.pt-BR.ts +5 -0
- package/src/i18n/styling.ru.ts +4 -0
- package/src/i18n/styling.zh-CN.ts +5 -0
- package/src/index.ts +17 -0
- package/src/model-catalog.ts +101 -0
- package/src/model-constants.ts +251 -16
- package/src/node-default-mappings.ts +5 -0
- package/src/normalize-node-params.ts +8 -0
- package/src/organizations/types.ts +12 -0
- package/src/organizations/views.ts +114 -0
- package/src/video-analysis.ts +45 -0
- package/src/video-ui-defaults.ts +66 -0
package/src/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ export { usdToCredits, creditsToUsd, CREDIT_ROUNDING_RESOLUTION } from "./credit
|
|
|
18
18
|
export {
|
|
19
19
|
CREDIT_BASE_USD,
|
|
20
20
|
IMAGE_PROMPT_MAX,
|
|
21
|
+
IMAGE_ASPECT_RATIO_VALUES,
|
|
21
22
|
MAX_IMAGE_PROMPT_CHARS_BY_PROVIDER,
|
|
22
23
|
getMaxImagePromptChars,
|
|
23
24
|
PROMPT_HARD_CEILING,
|
|
@@ -35,6 +36,7 @@ export {
|
|
|
35
36
|
getMaxSunoStyleChars,
|
|
36
37
|
VIDEO_PROMPT_MAX,
|
|
37
38
|
SUNO_TEXT_MAX,
|
|
39
|
+
SUNO_HARD_CEILING,
|
|
38
40
|
NATIVE_NEGATIVE_PROMPT_MODELS,
|
|
39
41
|
NATIVE_NEGATIVE_VIDEO_PROVIDERS,
|
|
40
42
|
applyVideoNegativePrompt,
|
|
@@ -117,6 +119,12 @@ export {
|
|
|
117
119
|
isMinimaxH3Provider,
|
|
118
120
|
MINIMAX_H3_DEFAULT_RESOLUTION,
|
|
119
121
|
normalizeMinimaxH3Resolution,
|
|
122
|
+
WAN_3_PROVIDERS,
|
|
123
|
+
isWan3Provider,
|
|
124
|
+
WAN_3_DEFAULT_RESOLUTION,
|
|
125
|
+
normalizeWan3Resolution,
|
|
126
|
+
GEMINI_OMNI_PROVIDERS,
|
|
127
|
+
isGeminiOmniProvider,
|
|
120
128
|
VIDEO_PROVIDERS_WITHOUT_DISPATCH,
|
|
121
129
|
GVP_DEFAULT_PROVIDER,
|
|
122
130
|
GVP_SUPPORTED_PROVIDERS,
|
|
@@ -167,6 +175,7 @@ export { FEATURED_ENTITIES, getFeaturedEntities } from "./featured-entities.js"
|
|
|
167
175
|
export type { FeaturedEntity } from "./featured-entities.js"
|
|
168
176
|
|
|
169
177
|
export type {
|
|
178
|
+
ImageAspectRatio,
|
|
170
179
|
ImageGenProvider,
|
|
171
180
|
ImageMaskMode,
|
|
172
181
|
ImageI2IProvider,
|
|
@@ -228,9 +237,14 @@ export type {
|
|
|
228
237
|
export {
|
|
229
238
|
buildCreditModelIdentifier,
|
|
230
239
|
resolveImageGenCreditIdentifier,
|
|
240
|
+
resolveNormalizedImageGen,
|
|
231
241
|
buildVideoCreditModelIdentifier,
|
|
232
242
|
buildMotionCreditModelIdentifier,
|
|
243
|
+
sunoCreditType,
|
|
244
|
+
SUNO_VERSION_PRICED_OPERATIONS,
|
|
245
|
+
SUNO_SELECT_OPERATIONS,
|
|
233
246
|
} from "./credit-identifiers.js"
|
|
247
|
+
export type { NormalizedImageGen } from "./credit-identifiers.js"
|
|
234
248
|
|
|
235
249
|
export * from "./credit-estimators/index.js"
|
|
236
250
|
export { extractVideoDurationFromNode } from "./video-duration.js"
|
|
@@ -988,6 +1002,9 @@ export * from "./video-analysis.js"
|
|
|
988
1002
|
// buildVideoAuditCreditId / videoAuditCreditsForBucket / bucketSecondsFromAuditCreditId).
|
|
989
1003
|
export * from "./video-analysis-pricing.js"
|
|
990
1004
|
|
|
1005
|
+
// --- Unified video node UI-default fills (panel snap == strip == DAG payload) ---
|
|
1006
|
+
export * from "./video-ui-defaults.js"
|
|
1007
|
+
|
|
991
1008
|
// --- Smart-cut best-pair search windows (shared bound + clamp) ---
|
|
992
1009
|
export * from "./smart-cut-windows.js"
|
|
993
1010
|
|
package/src/model-catalog.ts
CHANGED
|
@@ -228,6 +228,12 @@ const VIDEO_RATIOS_SEEDANCE_2 = ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9", "a
|
|
|
228
228
|
// portrait-social and 21:9/9:21 cinematic (docs.kie.ai/market/happyhorse-1-1).
|
|
229
229
|
// Kept separate so the wider set can't leak to models that don't support it.
|
|
230
230
|
const VIDEO_RATIOS_HAPPYHORSE_11 = ["16:9", "9:16", "1:1", "4:3", "3:4", "4:5", "5:4", "21:9", "9:21"] as const
|
|
231
|
+
// Wan 3.0 (standard + Prime) — the model's own six-ratio enum, `adaptive` first
|
|
232
|
+
// because that is the KIE default ("automatically selects the ratio based on the
|
|
233
|
+
// input media and intent"). Deliberately NO 21:9 — the Wan 3.0 enum rejects it,
|
|
234
|
+
// so VIDEO_RATIOS_SEEDANCE_2 must NOT be reused here
|
|
235
|
+
// (docs.kie.ai/market/wan/3-0-video and /3-0-video-prime — identical schemas).
|
|
236
|
+
const VIDEO_RATIOS_WAN_3 = ["adaptive", "16:9", "4:3", "1:1", "3:4", "9:16"] as const
|
|
231
237
|
|
|
232
238
|
// =============================================================================
|
|
233
239
|
// IMAGE MODELS
|
|
@@ -1179,6 +1185,41 @@ const VIDEO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
1179
1185
|
{ identifier: "gemini-omni-video:4k:vref", credits: 900, note: "video-edit 4K" },
|
|
1180
1186
|
],
|
|
1181
1187
|
},
|
|
1188
|
+
// Gemini Omni Flash 1.1 — the faster/cheaper Omni SKU (KIE
|
|
1189
|
+
// `google/gemini-omni-flash-1-1`). Identical request surface to
|
|
1190
|
+
// gemini-omni-video, so every capability below is deliberate PARITY with the
|
|
1191
|
+
// sibling: same 4/6/8/10s ladder, same 720p/1080p + 4K bands, same
|
|
1192
|
+
// features (the KIE schema also exposes first/last frame, but the pro
|
|
1193
|
+
// sibling's frame path is unwired here too — no "end-frame" until it is).
|
|
1194
|
+
// 360p is on the KIE enum but NOT exposed: it sits in the same credit band as
|
|
1195
|
+
// 720p/1080p, so it could only hand the user a worse render at the same price.
|
|
1196
|
+
"gemini-omni-flash": {
|
|
1197
|
+
id: "gemini-omni-flash",
|
|
1198
|
+
kind: "video",
|
|
1199
|
+
modes: ["i2v", "t2v"] as const, // V2V is served via the i2v handle, not a catalog mode
|
|
1200
|
+
family: "Google",
|
|
1201
|
+
label: "Gemini Omni Flash",
|
|
1202
|
+
series: "Gemini",
|
|
1203
|
+
description: "Google Gemini Omni Flash — faster/cheaper Omni tier: multimodal video with native audio, text/image-to-video + video-edit.",
|
|
1204
|
+
useCases: ["cinematic", "fast"],
|
|
1205
|
+
features: ["audio", "reference-image"],
|
|
1206
|
+
aspectRatios: VIDEO_RATIOS_HV,
|
|
1207
|
+
resolutions: ["720p", "1080p", "4k"],
|
|
1208
|
+
durations: [4, 6, 8, 10],
|
|
1209
|
+
pricing: [
|
|
1210
|
+
{ identifier: "gemini-omni-flash", credits: 270, note: "default — 8s 720p/1080p (the credit builder's duration fallback)" },
|
|
1211
|
+
{ identifier: "gemini-omni-flash:4", credits: 160, note: "720p/1080p 4s" },
|
|
1212
|
+
{ identifier: "gemini-omni-flash:6", credits: 210, note: "720p/1080p 6s" },
|
|
1213
|
+
{ identifier: "gemini-omni-flash:8", credits: 270, note: "720p/1080p 8s" },
|
|
1214
|
+
{ identifier: "gemini-omni-flash:10", credits: 320, note: "720p/1080p 10s" },
|
|
1215
|
+
{ identifier: "gemini-omni-flash:4k:4", credits: 370, note: "4K 4s" },
|
|
1216
|
+
{ identifier: "gemini-omni-flash:4k:6", credits: 420, note: "4K 6s" },
|
|
1217
|
+
{ identifier: "gemini-omni-flash:4k:8", credits: 480, note: "4K 8s" },
|
|
1218
|
+
{ identifier: "gemini-omni-flash:4k:10", credits: 530, note: "4K 10s" },
|
|
1219
|
+
{ identifier: "gemini-omni-flash:vref", credits: 420, note: "video-edit 720p/1080p" },
|
|
1220
|
+
{ identifier: "gemini-omni-flash:4k:vref", credits: 630, note: "video-edit 4K" },
|
|
1221
|
+
],
|
|
1222
|
+
},
|
|
1182
1223
|
|
|
1183
1224
|
// ── Kling ──
|
|
1184
1225
|
"kling": {
|
|
@@ -1450,6 +1491,66 @@ const VIDEO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
1450
1491
|
},
|
|
1451
1492
|
|
|
1452
1493
|
// ── Wan ──
|
|
1494
|
+
// Wan 3.0 (standard + Prime) — a NEW generation, not a tier of the 2.x ladder.
|
|
1495
|
+
// One id per SKU serves BOTH modes (no t2v twin, no alias): first/last frame
|
|
1496
|
+
// OR an all-purpose reference mode (images/videos/audio, bound in the prompt
|
|
1497
|
+
// as Image1/Video1/Audio1 — no space, unlike Wan 2.x), native audio behind a
|
|
1498
|
+
// boolean `audio` lever, 2-30s at 480p/720p/1080p.
|
|
1499
|
+
// `video-reference` is deliberately NOT declared: KIE accepts reference videos,
|
|
1500
|
+
// but the extend chain is unwired and KIE caps input-video + output at 30s,
|
|
1501
|
+
// which the segment bounds cannot express. Precedent: gemini-omni-video carries
|
|
1502
|
+
// ref limits without the feature. The ref CAPS still live in
|
|
1503
|
+
// VIDEO_REF_LIMITS_BY_PROVIDER (model-constants).
|
|
1504
|
+
// `resolutions` is ascending (repo convention); the DEFAULT tier (720p) is
|
|
1505
|
+
// declared explicitly in PRICING_DEFAULT_RESOLUTION, never by array position.
|
|
1506
|
+
"wan-3": {
|
|
1507
|
+
id: "wan-3",
|
|
1508
|
+
kind: "video",
|
|
1509
|
+
modes: ["i2v", "t2v"] as const,
|
|
1510
|
+
family: "Alibaba",
|
|
1511
|
+
label: "Wan 3.0",
|
|
1512
|
+
series: "Wan",
|
|
1513
|
+
description: "Wan 3.0 — multimodal: first/last frame or image/video/audio references, native audio, 2-30s at 480p/720p/1080p.",
|
|
1514
|
+
useCases: ["motion", "narrative", "long-form"],
|
|
1515
|
+
features: ["end-frame", "audio", "reference-image"],
|
|
1516
|
+
aspectRatios: VIDEO_RATIOS_WAN_3,
|
|
1517
|
+
durations: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
|
|
1518
|
+
resolutions: ["480p", "720p", "1080p"],
|
|
1519
|
+
pricing: [
|
|
1520
|
+
{ identifier: "wan-3", credits: 200, note: "default 5s 720p — see :Ns:res variants for exact" },
|
|
1521
|
+
{ identifier: "wan-3:5s:720p", credits: 200, note: "5s 720p (the default tier)" },
|
|
1522
|
+
{ identifier: "wan-3:8s:480p", credits: 160, note: "8s 480p" },
|
|
1523
|
+
{ identifier: "wan-3:8s:720p", credits: 320, note: "8s 720p" },
|
|
1524
|
+
{ identifier: "wan-3:8s:1080p", credits: 640, note: "8s 1080p" },
|
|
1525
|
+
{ identifier: "wan-3:30s:480p", credits: 600, note: "30s 480p (max)" },
|
|
1526
|
+
{ identifier: "wan-3:30s:720p", credits: 1200, note: "30s 720p (max)" },
|
|
1527
|
+
{ identifier: "wan-3:30s:1080p", credits: 2400, note: "30s 1080p (max)" },
|
|
1528
|
+
],
|
|
1529
|
+
},
|
|
1530
|
+
"wan-3-prime": {
|
|
1531
|
+
id: "wan-3-prime",
|
|
1532
|
+
kind: "video",
|
|
1533
|
+
modes: ["i2v", "t2v"] as const,
|
|
1534
|
+
family: "Alibaba",
|
|
1535
|
+
label: "Wan 3.0 Prime",
|
|
1536
|
+
series: "Wan",
|
|
1537
|
+
description: "Wan 3.0 Prime — Alibaba's high-speed Wan 3.0 tier: same multimodal surface and 2-30s range, faster turnaround at a higher per-second rate.",
|
|
1538
|
+
useCases: ["fast", "motion", "narrative"],
|
|
1539
|
+
features: ["end-frame", "audio", "reference-image"],
|
|
1540
|
+
aspectRatios: VIDEO_RATIOS_WAN_3,
|
|
1541
|
+
durations: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
|
|
1542
|
+
resolutions: ["480p", "720p", "1080p"],
|
|
1543
|
+
pricing: [
|
|
1544
|
+
{ identifier: "wan-3-prime", credits: 320, note: "default 5s 720p — see :Ns:res variants for exact" },
|
|
1545
|
+
{ identifier: "wan-3-prime:5s:720p", credits: 320, note: "5s 720p (the default tier)" },
|
|
1546
|
+
{ identifier: "wan-3-prime:8s:480p", credits: 250, note: "8s 480p" },
|
|
1547
|
+
{ identifier: "wan-3-prime:8s:720p", credits: 510, note: "8s 720p" },
|
|
1548
|
+
{ identifier: "wan-3-prime:8s:1080p", credits: 1010, note: "8s 1080p" },
|
|
1549
|
+
{ identifier: "wan-3-prime:30s:480p", credits: 920, note: "30s 480p (max)" },
|
|
1550
|
+
{ identifier: "wan-3-prime:30s:720p", credits: 1890, note: "30s 720p (max)" },
|
|
1551
|
+
{ identifier: "wan-3-prime:30s:1080p", credits: 3780, note: "30s 1080p (max)" },
|
|
1552
|
+
],
|
|
1553
|
+
},
|
|
1453
1554
|
"wan-i2v": {
|
|
1454
1555
|
id: "wan-i2v",
|
|
1455
1556
|
kind: "video",
|
package/src/model-constants.ts
CHANGED
|
@@ -13,6 +13,42 @@ export const CREDIT_BASE_USD = 0.002
|
|
|
13
13
|
* schemas and the factory-preset guard test all read this. Prompt cap ONLY (not negativePrompt). */
|
|
14
14
|
export const IMAGE_PROMPT_MAX = 5000
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* The ONE aspect-ratio vocabulary the image routes' Zod enums are built from —
|
|
18
|
+
* `/v1/generate-image`, `/v1/image-to-image` and `/v1/edit-image` all declare
|
|
19
|
+
* `z.enum(IMAGE_ASPECT_RATIO_VALUES)` instead of keeping three literal lists
|
|
20
|
+
* that drift.
|
|
21
|
+
*
|
|
22
|
+
* It is the UNION of every ratio any `kind: "image"` catalog entry declares, so
|
|
23
|
+
* a value the picker offers can never 400 at the route. That gap has shipped
|
|
24
|
+
* twice — Wan 2.7's ultra-wide `8:1`/`1:8` (fixed on generate-image only) and
|
|
25
|
+
* Nano Banana 2 Lite's banner `4:1`/`1:4` (still open until this tuple landed).
|
|
26
|
+
* `packages/shared/src/__tests__/image-pricing-catalog-coverage.test.ts` fails
|
|
27
|
+
* the build if a new model declares a ratio this tuple is missing.
|
|
28
|
+
*
|
|
29
|
+
* This enum is a VOCABULARY BOUND, not a per-model gate: it only stops a
|
|
30
|
+
* free-form string from reaching a provider as `image_size`. The per-model gate
|
|
31
|
+
* is the catalog snap (`resolveNormalizedImageGen` → `normalizeModelInput`),
|
|
32
|
+
* which CORRECTS an unsupported ratio and discloses it in the response's
|
|
33
|
+
* `adjustments` — never rejects. So widening this tuple is always safe: it
|
|
34
|
+
* defers a rejection to the correcting snap, which is the desired behaviour.
|
|
35
|
+
*
|
|
36
|
+
* `auto` is model-specific (GPT Image 2 / Nano Banana 2 Lite treat it as
|
|
37
|
+
* "native"); it lives here for the same reason as the rest — the snap drops or
|
|
38
|
+
* replaces it for models that do not declare it.
|
|
39
|
+
*/
|
|
40
|
+
export const IMAGE_ASPECT_RATIO_VALUES = [
|
|
41
|
+
"auto",
|
|
42
|
+
"1:1", "16:9", "9:16", "4:3", "3:4",
|
|
43
|
+
"3:2", "2:3", "5:4", "4:5", "21:9",
|
|
44
|
+
// Ultra-wide / ultra-tall banner ratios: Wan 2.7 + Wan 2.7 Pro (8:1, 1:8)
|
|
45
|
+
// and Nano Banana 2 Lite (4:1, 1:4, 8:1, 1:8).
|
|
46
|
+
"4:1", "1:4", "8:1", "1:8",
|
|
47
|
+
] as const
|
|
48
|
+
|
|
49
|
+
/** A ratio string the image routes accept (pre-snap vocabulary, not a per-model guarantee). */
|
|
50
|
+
export type ImageAspectRatio = typeof IMAGE_ASPECT_RATIO_VALUES[number]
|
|
51
|
+
|
|
16
52
|
/**
|
|
17
53
|
* Per-provider maximum ASSEMBLED image-prompt length (chars), VERIFIED against
|
|
18
54
|
* each model's official docs.kie.ai schema (2026-06). Providers absent here use
|
|
@@ -75,15 +111,37 @@ export const VIDEO_PROMPT_MAX = 8000
|
|
|
75
111
|
|
|
76
112
|
/**
|
|
77
113
|
* Suno prompt / lyrics / content ceiling — the LARGEST any Suno version accepts
|
|
78
|
-
* in custom mode (V4.5 / V4.5PLUS / V4.5ALL / V5 / V5.5 = 5000).
|
|
79
|
-
*
|
|
80
|
-
* {@link getMaxSunoPromptChars} (
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
114
|
+
* in custom mode (V4.5 / V4.5PLUS / V4.5ALL / V5 / V5.5 = 5000). NOT the route
|
|
115
|
+
* Zod bound — the routes bind at {@link SUNO_HARD_CEILING} and clamp to the
|
|
116
|
+
* per-version cap via {@link getMaxSunoPromptChars} (3000 non-custom for every
|
|
117
|
+
* version; in custom mode 3000 for V4/V3.5, 5000 for V4.5+/V5) before the job
|
|
118
|
+
* is built. This constant is shared with the editor `maxLength` / counter
|
|
119
|
+
* (warn-don't-block at the per-version cap). `style` and `title` have their
|
|
120
|
+
* own caps ({@link getMaxSunoStyleChars} / {@link SUNO_TITLE_MAX}).
|
|
84
121
|
*/
|
|
85
122
|
export const SUNO_TEXT_MAX = 5000
|
|
86
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Absolute ceiling for every Suno text field on the route Zod schemas
|
|
126
|
+
* (`prompt`, `lyrics`, `fullLyrics`, `content`, `userPrompt`).
|
|
127
|
+
*
|
|
128
|
+
* WARN-DON'T-BLOCK. The per-version caps ({@link getMaxSunoPromptChars} /
|
|
129
|
+
* {@link getMaxSunoStyleChars}) do the real work — the routes CLAMP to them
|
|
130
|
+
* before building the job. The Zod bound only exists to stop abuse, so it must
|
|
131
|
+
* stay generous: until 2026-09 the routes bounded these fields at
|
|
132
|
+
* {@link SUNO_TEXT_MAX} (5000), which meant a programmatically-set prompt (an
|
|
133
|
+
* agent, an app run, a FieldMapping) was hard-REJECTED with a 400 before the
|
|
134
|
+
* clamp could trim it — three app-report rows on 2026-08-19..31.
|
|
135
|
+
*
|
|
136
|
+
* DISTINCT FROM {@link PROMPT_HARD_CEILING} on purpose: that one is an
|
|
137
|
+
* image/video budget pinned to MAX_IMAGE/VIDEO_PROMPT_CHARS_BY_PROVIDER by its
|
|
138
|
+
* own drift guard. Coupling them would let one modality's limits move the
|
|
139
|
+
* other's. This one has a single invariant, enforced in
|
|
140
|
+
* `__tests__/prompt-length-limits.test.ts`: it MUST stay >= every value
|
|
141
|
+
* getMaxSunoPromptChars / getMaxSunoStyleChars can return.
|
|
142
|
+
*/
|
|
143
|
+
export const SUNO_HARD_CEILING = 30000
|
|
144
|
+
|
|
87
145
|
/**
|
|
88
146
|
* Absolute ceiling for the `prompt` / `negativePrompt` fields on the image and
|
|
89
147
|
* video routes' Zod schemas. The PER-MODEL limits below (and the editor warning)
|
|
@@ -139,6 +197,13 @@ export const MAX_VIDEO_PROMPT_CHARS_BY_PROVIDER: Record<string, number> = {
|
|
|
139
197
|
// (docs.kie.ai/market/bytedance/seedance-2-5).
|
|
140
198
|
"seedance-2-5": 30000,
|
|
141
199
|
"gemini-omni-video": 20000,
|
|
200
|
+
// Gemini Omni Flash 1.1 — same 20000-char prompt surface as the pro sibling
|
|
201
|
+
// (docs.kie.ai/market/google/gemini-omni-flash-1-1).
|
|
202
|
+
"gemini-omni-flash": 20000,
|
|
203
|
+
// Wan 3.0 / 3.0 Prime — 20000 chars, excess truncated by the provider
|
|
204
|
+
// (docs.kie.ai/market/wan/3-0-video and /3-0-video-prime).
|
|
205
|
+
"wan-3": 20000,
|
|
206
|
+
"wan-3-prime": 20000,
|
|
142
207
|
"bytedance-lite": 10000,
|
|
143
208
|
"bytedance-pro": 10000,
|
|
144
209
|
"bytedance-pro-fast": 10000,
|
|
@@ -231,9 +296,11 @@ export function getMaxTtsChars(provider: string | undefined): number {
|
|
|
231
296
|
}
|
|
232
297
|
|
|
233
298
|
/**
|
|
234
|
-
* Suno per-version field caps (from docs.kie.ai/suno-api/generate-music). The
|
|
235
|
-
* flat
|
|
236
|
-
*
|
|
299
|
+
* Suno per-version field caps (from docs.kie.ai/suno-api/generate-music). The
|
|
300
|
+
* original flat 3000 cap was simultaneously too low for V4.5+/V5 prompts
|
|
301
|
+
* (5000) and too high for `style` (1000) and `title` (80). ({@link
|
|
302
|
+
* SUNO_TEXT_MAX} is 5000 today — the largest per-version prompt cap; the
|
|
303
|
+
* route Zod bound is {@link SUNO_HARD_CEILING}.)
|
|
237
304
|
* - prompt / lyrics: 3000 in non-custom mode (all versions); in custom mode
|
|
238
305
|
* 3000 for V4/V3.5 and 5000 for V4.5 / V4.5PLUS / V4.5ALL / V5 / V5.5.
|
|
239
306
|
* - style: 200 for V4/V3.5, 1000 for V4.5+.
|
|
@@ -750,6 +817,11 @@ export const IMAGE_TO_VIDEO_PROVIDERS = [
|
|
|
750
817
|
"runway-kie",
|
|
751
818
|
"kling-3-omni",
|
|
752
819
|
"gemini-omni-video",
|
|
820
|
+
"gemini-omni-flash",
|
|
821
|
+
// Wan 3.0 family — one id per SKU serves BOTH modes (no t2v twin, no alias),
|
|
822
|
+
// so each id is listed in this array AND in TEXT_TO_VIDEO_PROVIDERS.
|
|
823
|
+
"wan-3",
|
|
824
|
+
"wan-3-prime",
|
|
753
825
|
"ltx-2.3-pro",
|
|
754
826
|
"ltx-2.3-fast",
|
|
755
827
|
// xAI Grok Imagine Video 1.5 — KIE i2v (image_urls required). Also listed in
|
|
@@ -788,6 +860,12 @@ export const TEXT_TO_VIDEO_PROVIDERS = [
|
|
|
788
860
|
"happyhorse",
|
|
789
861
|
"runway-kie",
|
|
790
862
|
"gemini-omni-video",
|
|
863
|
+
"gemini-omni-flash",
|
|
864
|
+
// Wan 3.0 family — REAL t2v (prompt-only runs are the documented default
|
|
865
|
+
// mode), so they belong in this main section and must NOT be gated by
|
|
866
|
+
// VIDEO_PROVIDERS_REQUIRING_IMAGE.
|
|
867
|
+
"wan-3",
|
|
868
|
+
"wan-3-prime",
|
|
791
869
|
"ltx-2.3-pro",
|
|
792
870
|
"ltx-2.3-fast",
|
|
793
871
|
// ── i2v-only providers (image required) ──────────────────────────────────
|
|
@@ -1245,6 +1323,12 @@ export const DURATION_PRICED_PROVIDERS = new Set([
|
|
|
1245
1323
|
"happyhorse",
|
|
1246
1324
|
"happyhorse-i2v",
|
|
1247
1325
|
"happyhorse-ref2v",
|
|
1326
|
+
// Wan 3.0 family — per-second billing at three resolution rates. NOTE:
|
|
1327
|
+
// gemini-omni-flash is deliberately ABSENT (like gemini-omni-video): the
|
|
1328
|
+
// Gemini Omni branch in buildVideoCreditModelIdentifier early-returns before
|
|
1329
|
+
// this gate is consulted.
|
|
1330
|
+
"wan-3",
|
|
1331
|
+
"wan-3-prime",
|
|
1248
1332
|
])
|
|
1249
1333
|
|
|
1250
1334
|
/**
|
|
@@ -1302,6 +1386,75 @@ export function normalizeMinimaxH3Resolution(resolution: string | undefined): "7
|
|
|
1302
1386
|
return resolution?.trim().toLowerCase() === "768p" ? "768P" : MINIMAX_H3_DEFAULT_RESOLUTION
|
|
1303
1387
|
}
|
|
1304
1388
|
|
|
1389
|
+
/**
|
|
1390
|
+
* Wan 3.0 family — the KIE "wan/3-0-video" market model and its high-speed
|
|
1391
|
+
* "wan/3-0-video-prime" sibling. The two share a BYTE-IDENTICAL input schema
|
|
1392
|
+
* (first/last frame OR an all-purpose reference mode with images/videos/audio,
|
|
1393
|
+
* native `audio` boolean, 2-30s, 480P/720P/1080P, six aspect ratios with
|
|
1394
|
+
* `adaptive` as the default); only the per-second rate differs. Prime is the
|
|
1395
|
+
* FASTER tier at a higher rate — never describe it as "higher quality".
|
|
1396
|
+
*
|
|
1397
|
+
* Exact-membership set — NEVER match on a "wan" prefix: "wan", "wan-i2v",
|
|
1398
|
+
* "wan-turbo", "wan-flash", "wan-videoedit" and the "wan-2.7-*" ids are
|
|
1399
|
+
* unrelated 2.x models with a different surface (and a different reference
|
|
1400
|
+
* token format — see WAN_3_DOCTRINE in @nodaro/prompts).
|
|
1401
|
+
*/
|
|
1402
|
+
export const WAN_3_PROVIDERS = new Set<string>([
|
|
1403
|
+
"wan-3",
|
|
1404
|
+
"wan-3-prime",
|
|
1405
|
+
])
|
|
1406
|
+
|
|
1407
|
+
export function isWan3Provider(provider: string | undefined): boolean {
|
|
1408
|
+
return !!provider && WAN_3_PROVIDERS.has(provider)
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
/** Wan 3.0 resolution the PLATFORM renders when the param is omitted or unknown.
|
|
1412
|
+
* Deliberately NOT KIE's own default (1080P): 720p is the tier the bare credit
|
|
1413
|
+
* identifier prices, so the provider layer pins it to keep render == billed. */
|
|
1414
|
+
export const WAN_3_DEFAULT_RESOLUTION = "720P"
|
|
1415
|
+
|
|
1416
|
+
/**
|
|
1417
|
+
* SINGLE normalization for the Wan 3.0 resolution lever (KIE wire enum
|
|
1418
|
+
* "480P" | "720P" | "1080P"). Everything INTERNAL — the catalog, QUALITY_MAP,
|
|
1419
|
+
* dropdowns, RESOLUTION_DURATION_PRICING keys and every emitted credit
|
|
1420
|
+
* identifier — stays LOWERCASE; this helper is the ONE place the uppercase wire
|
|
1421
|
+
* form is produced (backend KIE payload build), the twin of
|
|
1422
|
+
* {@link normalizeMinimaxH3Resolution}.
|
|
1423
|
+
*
|
|
1424
|
+
* Case-insensitive. Anything else (undefined, garbage, a stale "4k") collapses
|
|
1425
|
+
* to {@link WAN_3_DEFAULT_RESOLUTION} — the tier the default credit identifier
|
|
1426
|
+
* reserves — so the billed tier can never undercut the rendered one.
|
|
1427
|
+
*/
|
|
1428
|
+
export function normalizeWan3Resolution(resolution: string | undefined): "480P" | "720P" | "1080P" {
|
|
1429
|
+
switch (resolution?.trim().toLowerCase()) {
|
|
1430
|
+
case "480p": return "480P"
|
|
1431
|
+
case "1080p": return "1080P"
|
|
1432
|
+
case "720p": return "720P"
|
|
1433
|
+
default: return WAN_3_DEFAULT_RESOLUTION
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
/**
|
|
1438
|
+
* Google Gemini Omni family — the KIE "gemini-omni-video" market model and its
|
|
1439
|
+
* faster/cheaper "google/gemini-omni-flash-1-1" sibling. Both take the SAME
|
|
1440
|
+
* request shape (prompt + image_urls references, video-edit through the i2v
|
|
1441
|
+
* handle, 4/6/8/10s, 720p/1080p or a 4K band) and are dispatched through the
|
|
1442
|
+
* same runner, so every behavioural branch that used to compare against the
|
|
1443
|
+
* literal "gemini-omni-video" must ask this predicate instead — V2V routing,
|
|
1444
|
+
* the 7-slot reference quota, the mode swap and the aspect-ratio panels.
|
|
1445
|
+
*
|
|
1446
|
+
* Exact-membership set — NEVER match on a "gemini" prefix (the Gemini LLM ids
|
|
1447
|
+
* would collide).
|
|
1448
|
+
*/
|
|
1449
|
+
export const GEMINI_OMNI_PROVIDERS = new Set<string>([
|
|
1450
|
+
"gemini-omni-video",
|
|
1451
|
+
"gemini-omni-flash",
|
|
1452
|
+
])
|
|
1453
|
+
|
|
1454
|
+
export function isGeminiOmniProvider(provider: string | undefined): boolean {
|
|
1455
|
+
return !!provider && GEMINI_OMNI_PROVIDERS.has(provider)
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1305
1458
|
/**
|
|
1306
1459
|
* Video models that are CATALOGUED and priced but have NO working dispatch
|
|
1307
1460
|
* path today — selecting one fails at the router, not at validation.
|
|
@@ -1553,9 +1706,15 @@ export function maxSegmentsFor(provider: string | undefined, capSec: number): nu
|
|
|
1553
1706
|
* param at all (inferred from the frame). Only the pure-t2v endpoint requires
|
|
1554
1707
|
* a concrete ratio — the KIE provider layer coerces `adaptive` → `16:9` there
|
|
1555
1708
|
* (see applyMinimaxH3Params in backend kie/video.ts).
|
|
1709
|
+
*
|
|
1710
|
+
* Wan 3.0 also defaults to `adaptive` — it is the model's own KIE default and
|
|
1711
|
+
* the first value in its aspect enum, so an un-set node must not silently run
|
|
1712
|
+
* at 16:9 while the panel displays Adaptive.
|
|
1556
1713
|
*/
|
|
1557
1714
|
export function defaultVideoAspectRatio(provider: string | undefined): string {
|
|
1558
|
-
return isSeedance2Provider(provider) || isMinimaxH3Provider(provider)
|
|
1715
|
+
return isSeedance2Provider(provider) || isMinimaxH3Provider(provider) || isWan3Provider(provider)
|
|
1716
|
+
? "adaptive"
|
|
1717
|
+
: "16:9"
|
|
1559
1718
|
}
|
|
1560
1719
|
|
|
1561
1720
|
/**
|
|
@@ -1656,6 +1815,10 @@ export const SEEDANCE_2_R2V_MAX_AUDIO_SEC_BY_PROVIDER: Record<string, number> =
|
|
|
1656
1815
|
// MiniMax Hailuo 3 — documented hard limit: each reference audio segment
|
|
1657
1816
|
// 2-15s, ≤15s total (docs.kie.ai/market/minimax-h3/reference-to-video).
|
|
1658
1817
|
"minimax-h3": 15,
|
|
1818
|
+
// Wan 3.0 family — documented hard limit: each reference audio clip 1-15s,
|
|
1819
|
+
// ≤15s combined (docs.kie.ai/market/wan/3-0-video).
|
|
1820
|
+
"wan-3": 15,
|
|
1821
|
+
"wan-3-prime": 15,
|
|
1659
1822
|
}
|
|
1660
1823
|
|
|
1661
1824
|
/** The verified r2v reference-audio cap (seconds) for a provider, or null when
|
|
@@ -1711,8 +1874,17 @@ export const VIDEO_REF_LIMITS_BY_PROVIDER: Record<
|
|
|
1711
1874
|
// bills input images beyond the first 5 (11 KIE cr each) — see the
|
|
1712
1875
|
// minimax-h3 credit helper in backend ee/billing.
|
|
1713
1876
|
"minimax-h3": { ...SEEDANCE_2_REF_LIMITS },
|
|
1877
|
+
// Wan 3.0 family — all-purpose reference mode: up to 10 images / 5 videos
|
|
1878
|
+
// (each 1-15s, ≤15s combined) / 5 audio clips (each 1-15s, ≤15s combined).
|
|
1879
|
+
// The reference arrays are mutually EXCLUSIVE with first/last frame at the
|
|
1880
|
+
// provider (docs.kie.ai/market/wan/3-0-video).
|
|
1881
|
+
"wan-3": { images: 10, videos: 5, audio: 5 },
|
|
1882
|
+
"wan-3-prime": { images: 10, videos: 5, audio: 5 },
|
|
1714
1883
|
// Multi-image reference providers.
|
|
1715
1884
|
"gemini-omni-video": { images: 7, videos: 1 },
|
|
1885
|
+
// Gemini Omni Flash 1.1 — identical quota to the pro sibling
|
|
1886
|
+
// (images + 2×videos + character_ids ≤ 7).
|
|
1887
|
+
"gemini-omni-flash": { images: 7, videos: 1 },
|
|
1716
1888
|
"kling-3-omni": { images: 7 }, // catalog/docs: "end frame + up to 7 reference images"
|
|
1717
1889
|
"grok-i2v": { images: 7 }, // backend kie/models.ts maxRefImages: 7
|
|
1718
1890
|
"happyhorse-ref2v": { images: 9 }, // backend kie/models.ts maxRefImages: 9
|
|
@@ -1738,10 +1910,15 @@ export const RESOLUTION_VIDEO_REF_PRICING = SEEDANCE_2_PROVIDERS
|
|
|
1738
1910
|
/**
|
|
1739
1911
|
* Video models priced by (duration × resolution) WITHOUT a video-ref dimension.
|
|
1740
1912
|
* Identifier suffix: `:{resolution}`, appended after the duration tier; value =
|
|
1741
|
-
* the provider's PRICED resolution tiers.
|
|
1742
|
-
*
|
|
1743
|
-
*
|
|
1744
|
-
*
|
|
1913
|
+
* the provider's PRICED resolution tiers.
|
|
1914
|
+
*
|
|
1915
|
+
* Any resolution outside the list (or undefined) collapses to the provider's
|
|
1916
|
+
* DEFAULT tier, so the builder can never emit an unpriced composite (the
|
|
1917
|
+
* hard-fail guard fuzzes the full resolution space). That default is
|
|
1918
|
+
* {@link PRICING_DEFAULT_RESOLUTION} when the provider declares one, and
|
|
1919
|
+
* otherwise the FIRST entry here — so a member with a declared default (wan-3)
|
|
1920
|
+
* can list its tiers in the repo-standard ascending order without index 0
|
|
1921
|
+
* silently becoming the billed default. Distinct from
|
|
1745
1922
|
* RESOLUTION_VIDEO_REF_PRICING (Seedance gen), which also adds `-ref` variants.
|
|
1746
1923
|
*/
|
|
1747
1924
|
export const RESOLUTION_DURATION_PRICING: Record<string, readonly string[]> = {
|
|
@@ -1757,6 +1934,12 @@ export const RESOLUTION_DURATION_PRICING: Record<string, readonly string[]> = {
|
|
|
1757
1934
|
"happyhorse": ["720p", "1080p"],
|
|
1758
1935
|
"happyhorse-i2v": ["720p", "1080p"],
|
|
1759
1936
|
"happyhorse-ref2v": ["720p", "1080p"],
|
|
1937
|
+
// Wan 3.0 / Prime — per-second billing at three published resolution rates.
|
|
1938
|
+
// Ascending, matching the catalog; the BILLED default is declared explicitly
|
|
1939
|
+
// in PRICING_DEFAULT_RESOLUTION ("720p") rather than carried by index 0, and
|
|
1940
|
+
// the provider layer pins the same 720P so render == billed.
|
|
1941
|
+
"wan-3": ["480p", "720p", "1080p"],
|
|
1942
|
+
"wan-3-prime": ["480p", "720p", "1080p"],
|
|
1760
1943
|
}
|
|
1761
1944
|
|
|
1762
1945
|
/**
|
|
@@ -1779,6 +1962,13 @@ export const NATIVE_ADAPTIVE_ASPECT: Record<string, string> = {
|
|
|
1779
1962
|
"seedance-2-fast": "adaptive",
|
|
1780
1963
|
"seedance-2-mini": "adaptive",
|
|
1781
1964
|
"seedance-2-5": "adaptive",
|
|
1965
|
+
// Wan 3.0 family: `adaptive` is the enum DEFAULT and KIE documents it as
|
|
1966
|
+
// "automatically selects the ratio based on the input media and intent"
|
|
1967
|
+
// (docs.kie.ai/market/wan/3-0-video) — i.e. match-the-input, not merely
|
|
1968
|
+
// "provider default" (the grok `auto` trap). DOC-verified only; re-confirm
|
|
1969
|
+
// with a live job before relying on it for off-catalog ratios.
|
|
1970
|
+
"wan-3": "adaptive",
|
|
1971
|
+
"wan-3-prime": "adaptive",
|
|
1782
1972
|
}
|
|
1783
1973
|
|
|
1784
1974
|
/**
|
|
@@ -1877,8 +2067,9 @@ export type VideoAudioMode = "none" | "ambient" | "native_speech" | "audio_drive
|
|
|
1877
2067
|
|
|
1878
2068
|
export interface VideoAudioCapability {
|
|
1879
2069
|
mode: VideoAudioMode
|
|
1880
|
-
/** Provider-option field carrying the on/off toggle, when user-controllable.
|
|
1881
|
-
|
|
2070
|
+
/** Provider-option field carrying the on/off toggle, when user-controllable.
|
|
2071
|
+
* `audio` is Wan 3.0's own boolean lever (KIE `input.audio`, default true). */
|
|
2072
|
+
field?: "generateAudio" | "sound" | "audio"
|
|
1882
2073
|
/** Audio is always produced and can't be turned off by the user (VEO 3.x). */
|
|
1883
2074
|
alwaysOn?: boolean
|
|
1884
2075
|
/** Enabling audio raises the credit cost (Kling — see AUDIO_ADDON_PROVIDERS). */
|
|
@@ -1937,6 +2128,19 @@ export const VIDEO_AUDIO_CAPABILITY: Record<string, VideoAudioCapability> = {
|
|
|
1937
2128
|
// KIE API exposes NO audio on/off parameter (audio is always produced), so
|
|
1938
2129
|
// there is no toggle field — alwaysOn, like VEO.
|
|
1939
2130
|
"minimax-h3": { mode: "audio_driven", alwaysOn: true },
|
|
2131
|
+
// Wan 3.0 family — a single boolean `audio` lever (KIE default true) produces
|
|
2132
|
+
// an ambient/SFX track with the clip. Classified "ambient", NOT
|
|
2133
|
+
// "native_speech" or "audio_driven": the schema documents no dialogue
|
|
2134
|
+
// guarantee, and reference audio is a generic conditioning array, not a
|
|
2135
|
+
// verified lip-sync transport. Upgrade only on a live probe (the kling-3.0
|
|
2136
|
+
// standard) — `audio_driven` would reroute the Story→Video dialogue pipeline
|
|
2137
|
+
// and skip the lip-sync pass. `defaultOn` mirrors the KIE default so an
|
|
2138
|
+
// intent-less request is described honestly; audio is priced into the uniform
|
|
2139
|
+
// per-second rate, so NOT cost-affecting (no `:audio` composite).
|
|
2140
|
+
// gemini-omni-flash is deliberately ABSENT — gemini-omni-video is absent too
|
|
2141
|
+
// (mode "none"), and the siblings must not disagree.
|
|
2142
|
+
"wan-3": { mode: "ambient", field: "audio", defaultOn: true },
|
|
2143
|
+
"wan-3-prime": { mode: "ambient", field: "audio", defaultOn: true },
|
|
1940
2144
|
}
|
|
1941
2145
|
|
|
1942
2146
|
const VIDEO_AUDIO_NONE: VideoAudioCapability = { mode: "none" }
|
|
@@ -2008,6 +2212,7 @@ export function applyVideoAudioToggle(
|
|
|
2008
2212
|
const enabled = cap.affectsCost ? opts?.sound : (opts?.sound ?? opts?.generateAudio)
|
|
2009
2213
|
if (enabled === undefined) return // no intent — keep the model's own default
|
|
2010
2214
|
if (cap.field === "generateAudio") input.generate_audio = enabled
|
|
2215
|
+
else if (cap.field === "audio") input.audio = enabled
|
|
2011
2216
|
else input.sound = enabled
|
|
2012
2217
|
}
|
|
2013
2218
|
|
|
@@ -2063,6 +2268,11 @@ export const VIDEO_VARIABLE_PRICING: Record<string, "duration" | "duration+audio
|
|
|
2063
2268
|
"minimax-h3": "duration+resolution",
|
|
2064
2269
|
// Grok Imagine Video 1.5 — per-second billing split 480p/720p (no video-ref dimension).
|
|
2065
2270
|
"grok-imagine-video-1.5": "duration+resolution",
|
|
2271
|
+
// Wan 3.0 family — per-second billing at three resolution rates (no video-ref
|
|
2272
|
+
// dimension: reference runs bill output seconds only). No gemini-omni-flash
|
|
2273
|
+
// entry, mirroring gemini-omni-video which has none either.
|
|
2274
|
+
"wan-3": "duration+resolution",
|
|
2275
|
+
"wan-3-prime": "duration+resolution",
|
|
2066
2276
|
}
|
|
2067
2277
|
|
|
2068
2278
|
/**
|
|
@@ -2098,6 +2308,14 @@ export const PRICING_DEFAULT_DURATION_SEC: Record<string, number> = {
|
|
|
2098
2308
|
export const PRICING_DEFAULT_RESOLUTION: Record<string, string> = {
|
|
2099
2309
|
// KIE renders 720p when `resolution` is omitted (kie/models.ts extraParams).
|
|
2100
2310
|
"seedance-2-5": "720p",
|
|
2311
|
+
// Wan 3.0 family — KIE's OWN default is 1080P, but the provider layer pins
|
|
2312
|
+
// 720P (normalizeWan3Resolution / WAN_3_DEFAULT_RESOLUTION) so the rendered
|
|
2313
|
+
// tier equals the tier the bare identifier bills. This declaration is what
|
|
2314
|
+
// makes the billed default explicit instead of an array ordering: the
|
|
2315
|
+
// RESOLUTION_DURATION_PRICING branch consults it before falling back to the
|
|
2316
|
+
// first tier, so the catalog can stay ascending without repricing anything.
|
|
2317
|
+
"wan-3": "720p",
|
|
2318
|
+
"wan-3-prime": "720p",
|
|
2101
2319
|
}
|
|
2102
2320
|
|
|
2103
2321
|
/** HappyHorse 1.1 per-second tiers — one per allowed duration (3–15s), shared
|
|
@@ -2122,6 +2340,21 @@ const SEEDANCE_2_5_DURATION_TIERS: Array<{ maxSeconds: number; suffix: string }>
|
|
|
2122
2340
|
(_, i) => ({ maxSeconds: i + 4, suffix: `${i + 4}s` }),
|
|
2123
2341
|
)
|
|
2124
2342
|
|
|
2343
|
+
/**
|
|
2344
|
+
* Wan 3.0 per-second tiers — one per allowed duration (2-30s), shared by both
|
|
2345
|
+
* SKUs (the ladder shape is identical; only the seeded rates differ).
|
|
2346
|
+
*
|
|
2347
|
+
* Per-second is REQUIRED, not a nicety: the ladder snaps a request UP to the
|
|
2348
|
+
* first tier whose `maxSeconds` covers it and falls back to the LAST tier when
|
|
2349
|
+
* none does, so a coarse ladder over a 29-value range would reserve a
|
|
2350
|
+
* short-clip price for a 30s render. `commit_credits` only ever refunds a
|
|
2351
|
+
* surplus and can never collect an upward delta.
|
|
2352
|
+
*/
|
|
2353
|
+
const WAN_3_DURATION_TIERS: Array<{ maxSeconds: number; suffix: string }> = Array.from(
|
|
2354
|
+
{ length: 29 },
|
|
2355
|
+
(_, i) => ({ maxSeconds: i + 2, suffix: `${i + 2}s` }),
|
|
2356
|
+
)
|
|
2357
|
+
|
|
2125
2358
|
/**
|
|
2126
2359
|
* Duration tier breakpoints for variable-priced video models.
|
|
2127
2360
|
* Maps provider → array of { maxSeconds, suffix } in ascending order.
|
|
@@ -2202,6 +2435,8 @@ export const VIDEO_DURATION_TIERS: Record<string, Array<{ maxSeconds: number; su
|
|
|
2202
2435
|
{ maxSeconds: 15, suffix: "15s" },
|
|
2203
2436
|
],
|
|
2204
2437
|
"seedance-2-5": SEEDANCE_2_5_DURATION_TIERS,
|
|
2438
|
+
"wan-3": WAN_3_DURATION_TIERS,
|
|
2439
|
+
"wan-3-prime": WAN_3_DURATION_TIERS,
|
|
2205
2440
|
// MiniMax Hailuo 3 — true per-second billing (KIE 36.5 cr/s @2K, 22.5 cr/s
|
|
2206
2441
|
// @768P). One tier per allowed second (4-15s) so the composite identifier
|
|
2207
2442
|
// maps 1:1 to the seeded price — no rounding/overcharge for any on-menu
|
|
@@ -187,6 +187,10 @@ const QUALITY_MAP: Record<string, QualityMapping> = {
|
|
|
187
187
|
// Seedance 2.5 spans 480p/720p/1080p on KIE (1080p accepted since the
|
|
188
188
|
// 2026-08-17 re-probe; 4k still rejected), so each quality rung gets its own tier.
|
|
189
189
|
"seedance-2-5": { field: "resolution", values: { low: "480p", mid: "720p", high: "1080p" } },
|
|
190
|
+
// Wan 3.0 family — 480p / 720p / 1080p (lowercase catalog spellings; the
|
|
191
|
+
// uppercase KIE wire form is produced only by normalizeWan3Resolution).
|
|
192
|
+
"wan-3": { field: "resolution", values: { low: "480p", mid: "720p", high: "1080p" } },
|
|
193
|
+
"wan-3-prime": { field: "resolution", values: { low: "480p", mid: "720p", high: "1080p" } },
|
|
190
194
|
"wan-2.7-i2v": { field: "resolution", values: { low: "720p", mid: "1080p", high: "1080p" } },
|
|
191
195
|
"wan-2.7-t2v": { field: "resolution", values: { low: "720p", mid: "1080p", high: "1080p" } },
|
|
192
196
|
"happyhorse": { field: "resolution", values: { low: "720p", mid: "1080p", high: "1080p" } },
|
|
@@ -200,6 +204,7 @@ const QUALITY_MAP: Record<string, QualityMapping> = {
|
|
|
200
204
|
"ltx-2.3-pro": { field: "resolution", values: { low: "1080p", mid: "2k", high: "4k" } },
|
|
201
205
|
"ltx-2.3-fast": { field: "resolution", values: { low: "1080p", mid: "2k", high: "4k" } },
|
|
202
206
|
"gemini-omni-video": { field: "resolution", values: { low: "720p", mid: "1080p", high: "4k" } },
|
|
207
|
+
"gemini-omni-flash": { field: "resolution", values: { low: "720p", mid: "1080p", high: "4k" } },
|
|
203
208
|
// Grok Imagine Video 1.5 — only 480p/720p (no 1080p tier); high clamps to 720p.
|
|
204
209
|
"grok-imagine-video-1.5": { field: "resolution", values: { low: "480p", mid: "720p", high: "720p" } },
|
|
205
210
|
// Replicate Flux 2 family — MP-based resolution (matching IMAGE_RESOLUTION_OPTIONS["flux-2-*"]).
|
|
@@ -30,10 +30,18 @@ import { normalizeModelInput, type ModelInputAdjustment } from "./model-catalog.
|
|
|
30
30
|
* through mode-dependent defaults (`"adaptive"` for Seedance/Hailuo, duration
|
|
31
31
|
* composites tied to pricing) that this flat normalizer would flatten wrongly;
|
|
32
32
|
* they get their own pass once those defaults are catalog-derived too.
|
|
33
|
+
*
|
|
34
|
+
* `modify-image` carries the same provider/aspectRatio/resolution/quality trio
|
|
35
|
+
* as `image-to-image` (it routes through the same worker), and `edit-image`
|
|
36
|
+
* carries provider + aspectRatio. `edit-image`'s `targetResolution` is an
|
|
37
|
+
* UPSCALE target, a different field this module never reads — so listing the
|
|
38
|
+
* type here heals its ratio without touching what it is priced on.
|
|
33
39
|
*/
|
|
34
40
|
export const MODEL_PARAM_NODE_TYPES: ReadonlySet<string> = new Set([
|
|
35
41
|
"generate-image",
|
|
36
42
|
"image-to-image",
|
|
43
|
+
"modify-image",
|
|
44
|
+
"edit-image",
|
|
37
45
|
])
|
|
38
46
|
|
|
39
47
|
export interface NodeParamAdjustment extends ModelInputAdjustment {
|