@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.
Files changed (83) hide show
  1. package/dist/index.cjs +350 -23
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +955 -564
  4. package/dist/index.d.ts +955 -564
  5. package/dist/index.js +334 -24
  6. package/dist/index.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/__tests__/credit-identifiers.test.ts +180 -0
  9. package/src/__tests__/gvp-supported-providers.test.ts +22 -1
  10. package/src/__tests__/image-pricing-catalog-coverage.test.ts +139 -0
  11. package/src/__tests__/normalize-node-params.test.ts +36 -0
  12. package/src/__tests__/organizations-types.test.ts +29 -1
  13. package/src/__tests__/prompt-length-limits.test.ts +40 -0
  14. package/src/__tests__/suno-credit-type.test.ts +54 -0
  15. package/src/__tests__/video-analysis-brief.test.ts +61 -0
  16. package/src/__tests__/video-audio-capability.test.ts +43 -0
  17. package/src/__tests__/video-mode-for-inputs.test.ts +1 -1
  18. package/src/__tests__/wan-3-catalog.test.ts +243 -0
  19. package/src/credit-identifiers.ts +191 -21
  20. package/src/i18n/held-prop.ar.ts +2 -0
  21. package/src/i18n/held-prop.de.ts +3 -0
  22. package/src/i18n/held-prop.es.ts +3 -0
  23. package/src/i18n/held-prop.fr.ts +2 -0
  24. package/src/i18n/held-prop.he.ts +3 -0
  25. package/src/i18n/held-prop.hi.ts +2 -0
  26. package/src/i18n/held-prop.ja.ts +3 -0
  27. package/src/i18n/held-prop.ko.ts +3 -0
  28. package/src/i18n/held-prop.pt-BR.ts +3 -0
  29. package/src/i18n/held-prop.ru.ts +2 -0
  30. package/src/i18n/held-prop.zh-CN.ts +3 -0
  31. package/src/i18n/person.ar.ts +3 -0
  32. package/src/i18n/person.de.ts +4 -0
  33. package/src/i18n/person.es.ts +4 -0
  34. package/src/i18n/person.fr.ts +3 -0
  35. package/src/i18n/person.he.ts +4 -0
  36. package/src/i18n/person.hi.ts +3 -0
  37. package/src/i18n/person.ja.ts +4 -0
  38. package/src/i18n/person.ko.ts +4 -0
  39. package/src/i18n/person.pt-BR.ts +4 -0
  40. package/src/i18n/person.ru.ts +3 -0
  41. package/src/i18n/person.zh-CN.ts +4 -0
  42. package/src/i18n/setting.ar.ts +2 -0
  43. package/src/i18n/setting.de.ts +3 -0
  44. package/src/i18n/setting.es.ts +3 -0
  45. package/src/i18n/setting.fr.ts +2 -0
  46. package/src/i18n/setting.he.ts +3 -0
  47. package/src/i18n/setting.hi.ts +2 -0
  48. package/src/i18n/setting.ja.ts +3 -0
  49. package/src/i18n/setting.ko.ts +3 -0
  50. package/src/i18n/setting.pt-BR.ts +3 -0
  51. package/src/i18n/setting.ru.ts +2 -0
  52. package/src/i18n/setting.zh-CN.ts +3 -0
  53. package/src/i18n/style.ar.ts +2 -0
  54. package/src/i18n/style.de.ts +3 -0
  55. package/src/i18n/style.es.ts +3 -0
  56. package/src/i18n/style.fr.ts +2 -0
  57. package/src/i18n/style.he.ts +3 -0
  58. package/src/i18n/style.hi.ts +2 -0
  59. package/src/i18n/style.ja.ts +3 -0
  60. package/src/i18n/style.ko.ts +3 -0
  61. package/src/i18n/style.pt-BR.ts +3 -0
  62. package/src/i18n/style.ru.ts +2 -0
  63. package/src/i18n/style.zh-CN.ts +3 -0
  64. package/src/i18n/styling.ar.ts +4 -0
  65. package/src/i18n/styling.de.ts +5 -0
  66. package/src/i18n/styling.es.ts +5 -0
  67. package/src/i18n/styling.fr.ts +4 -0
  68. package/src/i18n/styling.he.ts +5 -0
  69. package/src/i18n/styling.hi.ts +4 -0
  70. package/src/i18n/styling.ja.ts +5 -0
  71. package/src/i18n/styling.ko.ts +5 -0
  72. package/src/i18n/styling.pt-BR.ts +5 -0
  73. package/src/i18n/styling.ru.ts +4 -0
  74. package/src/i18n/styling.zh-CN.ts +5 -0
  75. package/src/index.ts +17 -0
  76. package/src/model-catalog.ts +101 -0
  77. package/src/model-constants.ts +251 -16
  78. package/src/node-default-mappings.ts +5 -0
  79. package/src/normalize-node-params.ts +8 -0
  80. package/src/organizations/types.ts +12 -0
  81. package/src/organizations/views.ts +114 -0
  82. package/src/video-analysis.ts +45 -0
  83. 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
 
@@ -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",
@@ -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). The route Zod
79
- * uses this as a generous ceiling; the handler clamps to the per-version cap via
80
- * {@link getMaxSunoPromptChars} (V4/V3.5 = 3000, non-custom = 500). Shared with
81
- * the editor `maxLength` / counter (warn-don't-block at the per-version cap).
82
- * `style` and `title` have their own caps ({@link getMaxSunoStyleChars} /
83
- * {@link SUNO_TITLE_MAX}).
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 old
235
- * flat {@link SUNO_TEXT_MAX} (3000) was simultaneously too low for V4.5+/V5
236
- * prompts (5000) and too high for `style` (1000) and `title` (80).
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) ? "adaptive" : "16:9"
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. Any resolution outside the list
1742
- * (or undefined) collapses to the FIRST entry — the provider's default tier —
1743
- * so the builder can never emit an unpriced composite (the hard-fail guard
1744
- * fuzzes the full resolution space). Distinct from
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
- field?: "generateAudio" | "sound"
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 {