@nodaro/shared 3.9.0 → 3.11.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 +448 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +959 -30
- package/dist/index.d.ts +959 -30
- package/dist/index.js +410 -52
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/credit-identifiers.test.ts +51 -1
- package/src/__tests__/gvp-supported-providers.test.ts +20 -3
- package/src/__tests__/model-catalog-sections.test.ts +59 -0
- package/src/__tests__/model-tree.test.ts +2 -2
- package/src/__tests__/parameter-node-value.test.ts +47 -0
- package/src/__tests__/pricing-default-duration.test.ts +45 -0
- package/src/__tests__/prompt-length-limits.test.ts +4 -0
- package/src/__tests__/scene3d-delivery-review.test.ts +512 -0
- package/src/__tests__/template-categories.test.ts +45 -0
- package/src/__tests__/video-analysis.test.ts +15 -0
- package/src/__tests__/video-frame-fit.test.ts +189 -0
- package/src/__tests__/video-ref-limits.test.ts +11 -2
- package/src/catalog-projection.ts +3 -0
- package/src/character-motion-metadata.ts +19 -0
- package/src/credit-identifiers.ts +44 -9
- package/src/i18n/character-motion.ar.ts +1082 -0
- package/src/i18n/character-motion.de.ts +1082 -0
- package/src/i18n/character-motion.es.ts +1082 -0
- package/src/i18n/character-motion.fr.ts +1082 -0
- package/src/i18n/character-motion.he.ts +1082 -0
- package/src/i18n/character-motion.hi.ts +1082 -0
- package/src/i18n/character-motion.ja.ts +1082 -0
- package/src/i18n/character-motion.ko.ts +1082 -0
- package/src/i18n/character-motion.pt-BR.ts +1082 -0
- package/src/i18n/character-motion.ru.ts +1082 -0
- package/src/i18n/character-motion.zh-CN.ts +1082 -0
- package/src/i18n/types.ts +1 -0
- package/src/index.ts +26 -0
- package/src/model-catalog.ts +49 -32
- package/src/model-constants.ts +50 -11
- package/src/node-execution-state.ts +95 -0
- package/src/parameter-node-value.ts +59 -0
- package/src/presentation-utils.ts +1 -0
- package/src/pro-3d-render.ts +159 -0
- package/src/scene3d-delivery-notes.ts +490 -0
- package/src/scene3d-v2-plan.ts +8 -2
- package/src/smart-cut-windows.ts +15 -10
- package/src/template-categories.ts +67 -0
- package/src/video-analysis.ts +15 -0
- package/src/video-frame-fit.ts +228 -0
- package/src/video-output-canvas.ts +119 -0
package/src/i18n/types.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -167,6 +167,7 @@ export {
|
|
|
167
167
|
DEFAULT_VIDEO_DURATION_SEC,
|
|
168
168
|
applyDefaultVideoSelection,
|
|
169
169
|
PRICING_DEFAULT_DURATION_SEC,
|
|
170
|
+
pricedOutputDurationSec,
|
|
170
171
|
PRICING_DEFAULT_RESOLUTION,
|
|
171
172
|
} from "./model-constants.js"
|
|
172
173
|
|
|
@@ -547,6 +548,8 @@ export type { LocationCatalogRef } from "./location-preset-catalog-map.js"
|
|
|
547
548
|
export {
|
|
548
549
|
PARAMETER_NODE_TYPES,
|
|
549
550
|
HINT_EXEMPT_PARAMETER_TYPES,
|
|
551
|
+
VIDEO_ONLY_PARAMETER_NODE_TYPES,
|
|
552
|
+
EXECUTION_GRAPH_COMPOSED_PARAMETER_TYPES,
|
|
550
553
|
getParameterValue,
|
|
551
554
|
setRegisteredPersonPackFields,
|
|
552
555
|
} from "./parameter-node-value.js"
|
|
@@ -731,6 +734,8 @@ export {
|
|
|
731
734
|
MODEL_RECOMMENDATIONS,
|
|
732
735
|
listModels,
|
|
733
736
|
groupByFamily,
|
|
737
|
+
groupByKindAndFamily,
|
|
738
|
+
MODEL_KINDS,
|
|
734
739
|
getModel,
|
|
735
740
|
validateModelInput,
|
|
736
741
|
// Frontend picker derivers
|
|
@@ -977,6 +982,16 @@ export type { VoiceChangerModel } from "./voice-changer-models.js"
|
|
|
977
982
|
// --- Node presets ---
|
|
978
983
|
export { EXECUTION_DATA_KEYS, TRANSIENT_RUNTIME_KEYS, stripTransientRuntimeData } from "./node-runtime-keys.js"
|
|
979
984
|
|
|
985
|
+
// --- Execution node state (wire contract) ---
|
|
986
|
+
export {
|
|
987
|
+
OUTPUT_BEARING_NODE_STATUSES,
|
|
988
|
+
nodeStateMayCarryOutput,
|
|
989
|
+
} from "./node-execution-state.js"
|
|
990
|
+
export type {
|
|
991
|
+
NodeExecutionStatus,
|
|
992
|
+
NodeExecutionStateWire,
|
|
993
|
+
} from "./node-execution-state.js"
|
|
994
|
+
|
|
980
995
|
export {
|
|
981
996
|
MODEL_PARAM_NODE_TYPES,
|
|
982
997
|
normalizeNodeModelParams,
|
|
@@ -1003,6 +1018,9 @@ export * from "./reference-sheet/index.js"
|
|
|
1003
1018
|
// --- Reference Board (templates + provider constant) ---
|
|
1004
1019
|
export * from "./reference-board-templates.js"
|
|
1005
1020
|
|
|
1021
|
+
// --- Marketplace template categories (the eight use cases) ---
|
|
1022
|
+
export * from "./template-categories.js"
|
|
1023
|
+
|
|
1006
1024
|
// --- Model tree (derive node targets + product-line grouping for the Models tab) ---
|
|
1007
1025
|
export * from "./model-tree.js"
|
|
1008
1026
|
|
|
@@ -1071,6 +1089,9 @@ export * from "./scene3d-v2.js"
|
|
|
1071
1089
|
export * from "./scene3d-v2-plan.js"
|
|
1072
1090
|
export * from "./scene3d-v2-resources.js"
|
|
1073
1091
|
export * from "./scene3d-camera-track.js"
|
|
1092
|
+
// --- What an authoring run says about its own answer: assumptions, summary,
|
|
1093
|
+
// repair count. Additive and optional on every Scene3D authoring lane. ---
|
|
1094
|
+
export * from "./scene3d-delivery-notes.js"
|
|
1074
1095
|
// --- 3D Render Pro: one durable operation, scene + video in one result ---
|
|
1075
1096
|
export * from "./pro-3d-render.js"
|
|
1076
1097
|
// --- Scene3D render pricing: which frame-size tier a render settles at.
|
|
@@ -1088,3 +1109,8 @@ export * from "./scene3d-v2-edit.js"
|
|
|
1088
1109
|
export { STUDIO_DEPENDENT_FRAMES_CAPABILITY, SequenceExecutionRequiredError, requiresSequenceExecution, assertCanvasExecutionAllowed } from "./sequence-execution"
|
|
1089
1110
|
export * from "./scene3d-authoring-engine.js"
|
|
1090
1111
|
export * from "./scene3d-input-assets.js"
|
|
1112
|
+
|
|
1113
|
+
// --- Start/end frame fit: measured output canvases + the pure fit math ---
|
|
1114
|
+
export * from "./video-output-canvas.js"
|
|
1115
|
+
export * from "./video-frame-fit.js"
|
|
1116
|
+
export type { CharacterMotionMetadata } from "./character-motion-metadata.js"
|
package/src/model-catalog.ts
CHANGED
|
@@ -52,7 +52,6 @@ export type ModelMode =
|
|
|
52
52
|
| "music"
|
|
53
53
|
| "sfx"
|
|
54
54
|
| "stt"
|
|
55
|
-
| "voice-clone"
|
|
56
55
|
| "voice-design"
|
|
57
56
|
| "voice-changer"
|
|
58
57
|
| "isolation"
|
|
@@ -755,23 +754,8 @@ const IMAGE_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
755
754
|
{ identifier: "ideogram-remix:QUALITY", credits: 60, note: "best quality" },
|
|
756
755
|
],
|
|
757
756
|
},
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
kind: "image",
|
|
761
|
-
modes: ["edit"] as const,
|
|
762
|
-
family: "Ideogram",
|
|
763
|
-
label: "Ideogram Reframe",
|
|
764
|
-
series: "Ideogram",
|
|
765
|
-
description: "Outpaint / reframe to a new aspect ratio while preserving subject.",
|
|
766
|
-
useCases: ["outpaint", "reframe"],
|
|
767
|
-
features: ["reference-image"],
|
|
768
|
-
aspectRatios: IDEOGRAM_RATIOS,
|
|
769
|
-
pricing: [
|
|
770
|
-
{ identifier: "ideogram-reframe", credits: 18, note: "BALANCED default" },
|
|
771
|
-
{ identifier: "ideogram-reframe:TURBO", credits: 18, note: "fastest" },
|
|
772
|
-
{ identifier: "ideogram-reframe:QUALITY", credits: 18, note: "best quality" },
|
|
773
|
-
],
|
|
774
|
-
},
|
|
757
|
+
// `ideogram-reframe` was retired 2026-09-15 — KIE's `ideogram/v3-reframe`
|
|
758
|
+
// fails every task upstream (#1331); see IDEOGRAM_PROVIDERS in model-constants.
|
|
775
759
|
|
|
776
760
|
// ── Google Imagen ──
|
|
777
761
|
"imagen4": {
|
|
@@ -1238,9 +1222,17 @@ const VIDEO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
1238
1222
|
family: "Google",
|
|
1239
1223
|
label: "VEO 3.1 Quality",
|
|
1240
1224
|
series: "VEO",
|
|
1241
|
-
description: "Google VEO 3.1 Quality — premium cinematic video. 4/6/8s clips, optional end frame, native audio. Flat per-generation pricing across durations.",
|
|
1225
|
+
description: "Google VEO 3.1 Quality — premium cinematic video. 4/6/8s clips, optional end frame, native audio. No reference-to-video mode (Fast/Lite only). Flat per-generation pricing across durations.",
|
|
1242
1226
|
useCases: ["cinematic", "premium", "narrative"],
|
|
1243
|
-
|
|
1227
|
+
// NO "reference-image": KIE serves REFERENCE_2_VIDEO on the Fast and Lite
|
|
1228
|
+
// SKUs only. Its own words, on a production job (2026-09-04, app-reports
|
|
1229
|
+
// lane G): "Reference to video only supports the Veo Fast model and Veo
|
|
1230
|
+
// Lite model." Until 2026-09-15 this entry claimed the feature, so the
|
|
1231
|
+
// editor offered the reference handles, the adapter sent
|
|
1232
|
+
// generationType: "REFERENCE_2_VIDEO", and the call came back 422 every
|
|
1233
|
+
// time — after credits were reserved. `veo3.1` (KIE `veo3_fast`) and
|
|
1234
|
+
// `veo3_lite` DO serve it and keep the flag.
|
|
1235
|
+
features: ["end-frame", "audio"],
|
|
1244
1236
|
durations: [4, 6, 8],
|
|
1245
1237
|
aspectRatios: VIDEO_RATIOS_HV,
|
|
1246
1238
|
// 720p (default) + 1080p inline. 4K generates the base at 1080p then chains
|
|
@@ -2204,7 +2196,7 @@ const VIDEO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
2204
2196
|
id: "omnihuman-1-5",
|
|
2205
2197
|
kind: "video",
|
|
2206
2198
|
modes: ["lip-sync"] as const,
|
|
2207
|
-
family: "
|
|
2199
|
+
family: "Bytedance",
|
|
2208
2200
|
label: "OmniHuman 1.5",
|
|
2209
2201
|
series: "OmniHuman",
|
|
2210
2202
|
description: "Premium prompt-directed talking avatar from a still image + audio. 720p / 1080p, up to 60s. People, pets, anime.",
|
|
@@ -2468,17 +2460,8 @@ const AUDIO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
2468
2460
|
},
|
|
2469
2461
|
|
|
2470
2462
|
// ── ElevenLabs voice utilities ──
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
kind: "audio",
|
|
2474
|
-
modes: ["voice-clone"] as const,
|
|
2475
|
-
family: "ElevenLabs",
|
|
2476
|
-
label: "Voice Clone (Instant)",
|
|
2477
|
-
series: "ElevenLabs",
|
|
2478
|
-
description: "Clone a voice from a short reference clip. Instant clone via direct ElevenLabs API.",
|
|
2479
|
-
useCases: ["voice-clone", "personalization"],
|
|
2480
|
-
pricing: [{ identifier: "voice-clone", credits: 50 }],
|
|
2481
|
-
},
|
|
2463
|
+
// (voice cloning was retired platform-wide on 2026-09-15 — no catalog entry,
|
|
2464
|
+
// no price, no MCP tool; existing clones still resolve as TTS voice ids.)
|
|
2482
2465
|
"elevenlabs-voice-design": {
|
|
2483
2466
|
id: "elevenlabs-voice-design",
|
|
2484
2467
|
kind: "audio",
|
|
@@ -2534,6 +2517,17 @@ const AUDIO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
2534
2517
|
useCases: ["dubbing", "multilingual"],
|
|
2535
2518
|
pricing: [{ identifier: "elevenlabs-dubbing", credits: 40, note: "per minute of the dubbed span (min 1)" }],
|
|
2536
2519
|
},
|
|
2520
|
+
"elevenlabs-dubbing-v2": {
|
|
2521
|
+
id: "elevenlabs-dubbing-v2",
|
|
2522
|
+
kind: "audio",
|
|
2523
|
+
modes: ["dubbing"] as const,
|
|
2524
|
+
family: "ElevenLabs",
|
|
2525
|
+
label: "ElevenLabs Dubbing v2",
|
|
2526
|
+
series: "ElevenLabs",
|
|
2527
|
+
description: "Translate + dub audio or a whole video into a new language — video in, dubbed video out. Async.",
|
|
2528
|
+
useCases: ["dubbing", "multilingual"],
|
|
2529
|
+
pricing: [{ identifier: "elevenlabs-dubbing-v2", credits: 1100, note: "per minute of the dubbed span (min 1)" }],
|
|
2530
|
+
},
|
|
2537
2531
|
"elevenlabs-forced-alignment": {
|
|
2538
2532
|
id: "elevenlabs-forced-alignment",
|
|
2539
2533
|
kind: "audio",
|
|
@@ -2678,6 +2672,29 @@ export function groupByFamily(
|
|
|
2678
2672
|
return Array.from(groups.entries()).map(([family, models]) => ({ family, models }))
|
|
2679
2673
|
}
|
|
2680
2674
|
|
|
2675
|
+
export const MODEL_KINDS = ["image", "video", "audio"] as const satisfies readonly ModelKind[]
|
|
2676
|
+
|
|
2677
|
+
/**
|
|
2678
|
+
* The Image / Video / Audio envelope every model-discovery surface renders
|
|
2679
|
+
* (`GET /v1/models`, MCP `list_models`): each model is filed under ITS OWN
|
|
2680
|
+
* kind, then by vendor family within that kind — so a vendor that ships more
|
|
2681
|
+
* than one kind (Google: Imagen + VEO, ByteDance: Seedream + Seedance, …)
|
|
2682
|
+
* appears once per kind it actually ships.
|
|
2683
|
+
*
|
|
2684
|
+
* This is the ONE grouping both surfaces call. Grouping by family first and
|
|
2685
|
+
* letting the family's first model pick the section filed every VEO, Seedance,
|
|
2686
|
+
* Wan and ByteDance video model under "image" whenever the call carried no
|
|
2687
|
+
* `kind` filter (#1332) — an explicit `kind` pre-filtered the list and hid it.
|
|
2688
|
+
* Empty sections are omitted; section order is fixed image → video → audio.
|
|
2689
|
+
*/
|
|
2690
|
+
export function groupByKindAndFamily(
|
|
2691
|
+
entries: ModelCatalogEntry[],
|
|
2692
|
+
): Array<{ kind: ModelKind; families: Array<{ family: string; models: ModelCatalogEntry[] }> }> {
|
|
2693
|
+
return MODEL_KINDS
|
|
2694
|
+
.map((kind) => ({ kind, families: groupByFamily(entries.filter((m) => m.kind === kind)) }))
|
|
2695
|
+
.filter((section) => section.families.length > 0)
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2681
2698
|
export function getModel(id: string): ModelCatalogEntry | undefined {
|
|
2682
2699
|
return MODEL_CATALOG[id]
|
|
2683
2700
|
}
|
package/src/model-constants.ts
CHANGED
|
@@ -91,14 +91,20 @@ export const MAX_IMAGE_PROMPT_CHARS_BY_PROVIDER: Record<string, number> = {
|
|
|
91
91
|
"seedream-5-lite-i2i": 3000, // docs.kie.ai/market/seedream-5-lite-image-to-image (NB: t2i sibling is 1000)
|
|
92
92
|
"qwen": 3000, // docs.kie.ai/market/qwen/text-to-image
|
|
93
93
|
"qwen-edit": 2000, // docs.kie.ai/market/qwen/image-edit
|
|
94
|
+
// Z-Image is the SHORTEST of the family — "maxLength: 1000" in its schema
|
|
95
|
+
// (docs.kie.ai/market/z-image/z-image, re-fetched 2026-09-15). It was listed
|
|
96
|
+
// below as "verified == 5000", which is how three production runs on
|
|
97
|
+
// 2026-09-07 sent a workflow-assembled prompt straight into KIE's
|
|
98
|
+
// `{"code":500,"msg":"The text length cannot exceed the maximum limit"}`.
|
|
99
|
+
"z-image": 1000, // docs.kie.ai/market/z-image/z-image
|
|
94
100
|
// verified == 5000 default (no entry needed): imagen4(-fast/-ultra), nano-banana,
|
|
95
101
|
// nano-banana-edit, flux, flux-flex, gpt-image-2, ideogram-v3/-edit/-remix,
|
|
96
|
-
//
|
|
102
|
+
// grok, qwen-i2i, seedream-5-pro, seedream-5-pro-i2i
|
|
97
103
|
// (docs.kie.ai/market/seedream/5-pro-text-to-image + 5-pro-image-to-image).
|
|
98
104
|
// grok-i2i: doc states 390000 (78× its t2i sibling) — treated as a KIE schema
|
|
99
105
|
// typo and left at the 5000 default per the sanity-cap decision.
|
|
100
106
|
// UNVERIFIED (no limit stated in schema) → 5000 default: flux-kontext(-max)
|
|
101
|
-
// gpt-image, gpt-image-i2i, flux-i2i, flux-pro-i2i
|
|
107
|
+
// gpt-image, gpt-image-i2i, flux-i2i, flux-pro-i2i.
|
|
102
108
|
}
|
|
103
109
|
|
|
104
110
|
/** Max assembled image-prompt length (chars) for a provider: its verified
|
|
@@ -508,7 +514,6 @@ export const MODELS_WITH_REFERENCE_IMAGE_SUPPORT = new Set([
|
|
|
508
514
|
"flux-kontext-max",
|
|
509
515
|
"ideogram-edit",
|
|
510
516
|
"ideogram-remix",
|
|
511
|
-
"ideogram-reframe",
|
|
512
517
|
"qwen-i2i",
|
|
513
518
|
"qwen-edit",
|
|
514
519
|
"seedream-edit",
|
|
@@ -588,7 +593,6 @@ export const REF_IMAGE_MAX_LIMITS: Record<string, number> = {
|
|
|
588
593
|
"flux-kontext-max": 1,
|
|
589
594
|
"ideogram-edit": 1,
|
|
590
595
|
"ideogram-remix": 1,
|
|
591
|
-
"ideogram-reframe": 1,
|
|
592
596
|
"qwen-i2i": 1,
|
|
593
597
|
"qwen-edit": 1,
|
|
594
598
|
"grok-i2i": 1,
|
|
@@ -662,7 +666,6 @@ export const VARIABLE_PRICING_MODELS: Record<string, "quality" | "resolution" |
|
|
|
662
666
|
"topaz-image-upscale": "resolution",
|
|
663
667
|
"ideogram-edit": "rendering-speed",
|
|
664
668
|
"ideogram-remix": "rendering-speed",
|
|
665
|
-
"ideogram-reframe": "rendering-speed",
|
|
666
669
|
"ideogram-v3": "rendering-speed",
|
|
667
670
|
"wan-2.7": "resolution",
|
|
668
671
|
"wan-2.7-pro": "resolution",
|
|
@@ -689,7 +692,12 @@ export const RESOLUTION_2K_4K_TIERED_PROVIDERS = new Set([
|
|
|
689
692
|
])
|
|
690
693
|
|
|
691
694
|
// Ideogram family models with TURBO/QUALITY pricing variants
|
|
692
|
-
|
|
695
|
+
// `ideogram-reframe` (KIE `ideogram/v3-reframe`) was retired 2026-09-15: KIE no
|
|
696
|
+
// longer documents the model and every task — the minimal documented payload
|
|
697
|
+
// included — fails upstream with "[500] internal error" (#1331). Its price rows
|
|
698
|
+
// are removed by migration 424; re-add everywhere per the Provider Enum Sync
|
|
699
|
+
// table if KIE brings it back.
|
|
700
|
+
export const IDEOGRAM_PROVIDERS = new Set(["ideogram-edit", "ideogram-remix", "ideogram-v3"])
|
|
693
701
|
|
|
694
702
|
// =====================================================================
|
|
695
703
|
// Provider arrays (single source of truth for route Zod validation)
|
|
@@ -744,7 +752,6 @@ export const IMAGE_I2I_PROVIDERS = [
|
|
|
744
752
|
"grok-2-i2i",
|
|
745
753
|
"ideogram-edit",
|
|
746
754
|
"ideogram-remix",
|
|
747
|
-
"ideogram-reframe",
|
|
748
755
|
"qwen-i2i",
|
|
749
756
|
"qwen-edit",
|
|
750
757
|
"seedream-edit",
|
|
@@ -1365,7 +1372,7 @@ export const I2I_STRENGTH_SUPPORT: Record<string, { min: number; max: number; st
|
|
|
1365
1372
|
|
|
1366
1373
|
/** Models that accept a seed parameter for reproducible generation */
|
|
1367
1374
|
export const SEED_SUPPORT = new Set([
|
|
1368
|
-
"ideogram-remix", "ideogram-
|
|
1375
|
+
"ideogram-remix", "ideogram-v3",
|
|
1369
1376
|
"qwen", "qwen-i2i", "qwen-edit",
|
|
1370
1377
|
"flux", "flux-flex", "flux-i2i", "flux-pro-i2i", "flux-kontext", "flux-kontext-max",
|
|
1371
1378
|
"flux-2-klein", "kontext-multi",
|
|
@@ -1373,7 +1380,7 @@ export const SEED_SUPPORT = new Set([
|
|
|
1373
1380
|
|
|
1374
1381
|
/** Ideogram models that support rendering_speed selection (TURBO/BALANCED/QUALITY) */
|
|
1375
1382
|
export const RENDERING_SPEED_SUPPORT = new Set([
|
|
1376
|
-
"ideogram-remix", "ideogram-
|
|
1383
|
+
"ideogram-remix", "ideogram-v3",
|
|
1377
1384
|
])
|
|
1378
1385
|
|
|
1379
1386
|
/** Models that accept guidance_scale for controlling prompt adherence */
|
|
@@ -1979,8 +1986,13 @@ export const VIDEO_REF_LIMITS_BY_PROVIDER: Record<
|
|
|
1979
1986
|
"kling-3-omni": { images: 7 }, // catalog/docs: "end frame + up to 7 reference images"
|
|
1980
1987
|
"grok-i2v": { images: 7 }, // backend kie/models.ts maxRefImages: 7
|
|
1981
1988
|
"happyhorse-ref2v": { images: 9 }, // backend kie/models.ts maxRefImages: 9
|
|
1982
|
-
// VEO 3.x — REFERENCE_2_VIDEO path caps refs at 3 (kie/video.ts
|
|
1983
|
-
|
|
1989
|
+
// VEO 3.x — REFERENCE_2_VIDEO path caps refs at 3 (kie/video.ts slices to
|
|
1990
|
+
// this number). `veo3` (VEO 3.1 QUALITY) is deliberately ABSENT: KIE serves
|
|
1991
|
+
// reference-to-video on the Fast and Lite SKUs only and rejects it on
|
|
1992
|
+
// Quality with "Reference to video only supports the Veo Fast model and Veo
|
|
1993
|
+
// Lite model." (production, 2026-09-04). Absent ⇒ 0 ⇒ the handle dims, the
|
|
1994
|
+
// `connectedReferences` assembly strips image tokens, and kie/video.ts never
|
|
1995
|
+
// flips a Quality call to REFERENCE_2_VIDEO.
|
|
1984
1996
|
"veo3.1": { images: 3 },
|
|
1985
1997
|
"veo3_lite": { images: 3 },
|
|
1986
1998
|
// NOTE: wan-i2v / hailuo-2.3[-pro] / bytedance-pro[-fast] / grok-imagine-video-1.5
|
|
@@ -2513,6 +2525,33 @@ export const VIDEO_VARIABLE_PRICING: Record<string, "duration" | "duration+audio
|
|
|
2513
2525
|
*/
|
|
2514
2526
|
export const PRICING_DEFAULT_DURATION_SEC: Record<string, number> = {
|
|
2515
2527
|
"minimax-h3": 6,
|
|
2528
|
+
// KIE renders 8s when `duration` is omitted (kie/models.ts extraParams), and
|
|
2529
|
+
// Seedance 2.5 prices one tier per second across 4–30s, so the 5s fallback
|
|
2530
|
+
// billed a 5s tier against an 8s render — and under-reserved every
|
|
2531
|
+
// reference-video run's output seconds by three (#1397).
|
|
2532
|
+
"seedance-2-5": 8,
|
|
2533
|
+
// Same shape: KIE renders 8s by default and the ladder is priced per second,
|
|
2534
|
+
// so the 5s fallback billed a 5s tier against an 8s render (caught by the
|
|
2535
|
+
// render-default ↔ priced-tier invariant in
|
|
2536
|
+
// backend/src/providers/__tests__/pricing-default-duration-sync.test.ts).
|
|
2537
|
+
"grok-imagine-video-1.5": 8,
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
/**
|
|
2541
|
+
* The output seconds a request is PRICED at: the requested duration when the
|
|
2542
|
+
* caller gave one, else the provider's own default render length
|
|
2543
|
+
* ({@link PRICING_DEFAULT_DURATION_SEC}), else the historical 5s fallback.
|
|
2544
|
+
*
|
|
2545
|
+
* The ONE source for `buildVideoCreditModelIdentifier`'s tier AND for every
|
|
2546
|
+
* dynamic reservation that scales by output seconds (the Seedance 2 and
|
|
2547
|
+
* MiniMax Hailuo 3 reference-video overrides on both the route and the DAG
|
|
2548
|
+
* lane) — a literal `?? 5` in any of those places re-opens the gap this map
|
|
2549
|
+
* closes.
|
|
2550
|
+
*/
|
|
2551
|
+
export function pricedOutputDurationSec(provider: string, requested: number | string | undefined): number {
|
|
2552
|
+
const fallback = PRICING_DEFAULT_DURATION_SEC[provider] ?? 5
|
|
2553
|
+
const parsed = typeof requested === "string" ? parseInt(requested, 10) : requested
|
|
2554
|
+
return parsed === undefined || Number.isNaN(parsed) ? fallback : parsed
|
|
2516
2555
|
}
|
|
2517
2556
|
|
|
2518
2557
|
/**
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wire contract for one node's entry in an execution's `nodeStates` map —
|
|
3
|
+
* the shape the orchestrator persists on `workflow_executions.node_states`,
|
|
4
|
+
* emits on the SSE execution stream, and every client reads back.
|
|
5
|
+
*
|
|
6
|
+
* Why this lives here rather than in the backend
|
|
7
|
+
* ----------------------------------------------
|
|
8
|
+
* The shape had THREE independent declarations — the orchestrator's rich
|
|
9
|
+
* `NodeExecutionState` (workflow-engine/types.ts), the SDK's loose one
|
|
10
|
+
* (`packages/client/src/resources/executions.ts`) and the editor's local copy
|
|
11
|
+
* (`workflow-editor/run-handlers.ts`) — and nothing tied them together. The
|
|
12
|
+
* field that made that expensive is `output`: it used to be an unstated
|
|
13
|
+
* convention that only a COMPLETED node carries one, so every consumer read it
|
|
14
|
+
* exclusively under `status === "completed"` and a failed node's retained
|
|
15
|
+
* result had nowhere to travel.
|
|
16
|
+
*
|
|
17
|
+
* This module states the rule once. The backend keeps its richer `NodeOutput`
|
|
18
|
+
* typing (its `NodeExecutionState` must stay ASSIGNABLE to the wire shape — a
|
|
19
|
+
* type-level test pins that); the SDK and the editor extend/import it.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The status a node reports inside an execution.
|
|
24
|
+
*
|
|
25
|
+
* `cancelled` is deliberately absent: a cancelled child job is mapped onto
|
|
26
|
+
* `skipped` by the reconcile lane (see `lib/reconcile/node-states.ts`), and a
|
|
27
|
+
* HELD job keeps `status: "running"` with the `awaitingReview` sidecar rather
|
|
28
|
+
* than adding a member here.
|
|
29
|
+
*/
|
|
30
|
+
export type NodeExecutionStatus =
|
|
31
|
+
| "pending"
|
|
32
|
+
| "running"
|
|
33
|
+
| "completed"
|
|
34
|
+
| "failed"
|
|
35
|
+
| "skipped"
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The statuses whose node state MAY carry `output`.
|
|
39
|
+
*
|
|
40
|
+
* `completed` is the obvious one. `failed` is here because a run can refuse
|
|
41
|
+
* its result and still RETAIN what it produced — the 3D-scene authoring lanes
|
|
42
|
+
* publish a real, renderable revision and then fail the job on the visual
|
|
43
|
+
* reviewer's verdict (`SCENE_QUALITY_FAILED`), so the scene and the refusal are
|
|
44
|
+
* both true at once. That output was billed; dropping it because the status is
|
|
45
|
+
* not `"completed"` is what this set exists to stop.
|
|
46
|
+
*
|
|
47
|
+
* `pending` / `running` / `skipped` never carry one: nothing has settled, or
|
|
48
|
+
* the node was gated out.
|
|
49
|
+
*/
|
|
50
|
+
export const OUTPUT_BEARING_NODE_STATUSES: ReadonlySet<NodeExecutionStatus> =
|
|
51
|
+
new Set<NodeExecutionStatus>(["completed", "failed"])
|
|
52
|
+
|
|
53
|
+
/** Whether a node in this status may carry `output`. */
|
|
54
|
+
export function nodeStateMayCarryOutput(status: string | undefined): boolean {
|
|
55
|
+
return (
|
|
56
|
+
status !== undefined &&
|
|
57
|
+
OUTPUT_BEARING_NODE_STATUSES.has(status as NodeExecutionStatus)
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* One node's execution state, as it travels on the wire.
|
|
63
|
+
*
|
|
64
|
+
* Additive by construction — an older client ignores fields it does not know,
|
|
65
|
+
* which is why `output` on a failed node is safe to start sending.
|
|
66
|
+
*
|
|
67
|
+
* `TOutput` lets a declaration that knows its own richer output shape (the
|
|
68
|
+
* orchestrator's `NodeOutput`, the editor's) stay ASSIGNABLE to this contract
|
|
69
|
+
* instead of restating it; the default is what an external client sees.
|
|
70
|
+
*/
|
|
71
|
+
export interface NodeExecutionStateWire<TOutput = Record<string, unknown>> {
|
|
72
|
+
status: NodeExecutionStatus | (string & {})
|
|
73
|
+
nodeType?: string
|
|
74
|
+
jobId?: string | null
|
|
75
|
+
/** Every job id of a fan-out node (one per list / loop iteration). */
|
|
76
|
+
jobIds?: string[]
|
|
77
|
+
creditsUsed?: number
|
|
78
|
+
error?: string | null
|
|
79
|
+
/** Stable code for a refusal a client may branch on — never on the text. */
|
|
80
|
+
errorCode?: string
|
|
81
|
+
/**
|
|
82
|
+
* What the node produced.
|
|
83
|
+
*
|
|
84
|
+
* Present for a `completed` node, and for a `failed` node whose run RETAINED
|
|
85
|
+
* a structured result (see {@link OUTPUT_BEARING_NODE_STATUSES}). A consumer
|
|
86
|
+
* that reads it must therefore gate on the FIELD, not on the status, and
|
|
87
|
+
* must not treat its presence as success.
|
|
88
|
+
*/
|
|
89
|
+
output?: TOutput
|
|
90
|
+
startedAt?: string | null
|
|
91
|
+
completedAt?: string | null
|
|
92
|
+
/** The node's job is parked in `pending_review`; `status` stays "running". */
|
|
93
|
+
awaitingReview?: boolean
|
|
94
|
+
progress?: number
|
|
95
|
+
}
|
|
@@ -45,6 +45,7 @@ export const PARAMETER_NODE_TYPES: ReadonlySet<string> = new Set([
|
|
|
45
45
|
"post-process-effects",
|
|
46
46
|
"action-fx",
|
|
47
47
|
"character-fx",
|
|
48
|
+
"character-motion",
|
|
48
49
|
"transition",
|
|
49
50
|
"loop-subject",
|
|
50
51
|
"scene-count",
|
|
@@ -77,6 +78,62 @@ export const HINT_EXEMPT_PARAMETER_TYPES: ReadonlySet<string> = new Set([
|
|
|
77
78
|
"aspect-ratio",
|
|
78
79
|
])
|
|
79
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Parameter pickers whose fragment only makes sense in MOTION — a camera move,
|
|
83
|
+
* a transition, a timeline, a character effect or a character movement. Every
|
|
84
|
+
* still-image consumer (generate-image, edit-image, image-to-image,
|
|
85
|
+
* modify-image, location) excludes these on BOTH executors and in the add-node
|
|
86
|
+
* popup. One set instead of three hand-synced copies: `STILL_IMAGE_EXCLUDE_TYPES`
|
|
87
|
+
* (frontend cinematography-hints.ts and backend payload-builder.ts) and
|
|
88
|
+
* `MOTION_ONLY_PICKER_TYPES` (frontend node-compatibility.ts) alias it.
|
|
89
|
+
*/
|
|
90
|
+
export const VIDEO_ONLY_PARAMETER_NODE_TYPES: ReadonlySet<string> = new Set([
|
|
91
|
+
"camera-motion",
|
|
92
|
+
"temporal",
|
|
93
|
+
"transition",
|
|
94
|
+
"character-fx",
|
|
95
|
+
"character-motion",
|
|
96
|
+
])
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Pickers whose fragment depends on OTHER nodes wired into them — camera
|
|
100
|
+
* motion's and transition's start / end states, character motion's target and
|
|
101
|
+
* partner names, character FX's target name — so both executors must pass the
|
|
102
|
+
* graph to `getParameterPromptHint` for them.
|
|
103
|
+
*
|
|
104
|
+
* TRANSITION AND CHARACTER-FX JOINED THIS SET (signed off). They compose from
|
|
105
|
+
* the graph everywhere a human LOOKS at them — the config panel's injection
|
|
106
|
+
* preview and the canvas card both run
|
|
107
|
+
* `getParameterPromptHint(node, { nodes, edges })` — and on the frontend
|
|
108
|
+
* `{Label}` path (`execution-graph.ts :: extractNodeOutput`), but the two
|
|
109
|
+
* cinematography collectors that read THIS set dispatched them without the
|
|
110
|
+
* graph, so a wired `startState` / `target` was promised in the preview and
|
|
111
|
+
* dropped at execution. Admitting them here closes that gap on BOTH executors
|
|
112
|
+
* at once.
|
|
113
|
+
*
|
|
114
|
+
* THE BOUND, and it is proved rather than asserted: a picker with NOTHING
|
|
115
|
+
* wired to its own `startState` / `endState` / `target` handles emits
|
|
116
|
+
* byte-identical text with and without the graph — the composers are simply
|
|
117
|
+
* called with empty clause arrays either way. So only workflows that actually
|
|
118
|
+
* wire those handles change at all, and they change to the text their own
|
|
119
|
+
* preview already shows. The prompts package's
|
|
120
|
+
* `graph-composed-unwired-identity.test.ts` walks every transition and
|
|
121
|
+
* character-fx catalog entry in both hint modes, under two unwired graph
|
|
122
|
+
* shapes, and asserts that equality — with a wired positive control so it
|
|
123
|
+
* cannot go vacuous.
|
|
124
|
+
*
|
|
125
|
+
* ADD A NEW GRAPH-COMPOSED PICKER HERE AND TO
|
|
126
|
+
* `LABEL_REF_GRAPH_COMPOSED_PARAMETER_TYPES` (backend
|
|
127
|
+
* `services/workflow-engine/label-ref-hint-context.ts`) when it ships, so its
|
|
128
|
+
* `{Label}` text and its directly-wired text agree from its first release.
|
|
129
|
+
*/
|
|
130
|
+
export const EXECUTION_GRAPH_COMPOSED_PARAMETER_TYPES: ReadonlySet<string> = new Set([
|
|
131
|
+
"camera-motion",
|
|
132
|
+
"character-motion",
|
|
133
|
+
"transition",
|
|
134
|
+
"character-fx",
|
|
135
|
+
])
|
|
136
|
+
|
|
80
137
|
/**
|
|
81
138
|
* Extra person-dimension data-field names contributed by registered person
|
|
82
139
|
* packs. Content-free (field-name strings only) — populated at runtime by
|
|
@@ -158,6 +215,8 @@ export function getParameterValue(
|
|
|
158
215
|
return trim(data.actionFx)
|
|
159
216
|
case "character-fx":
|
|
160
217
|
return trim(data.characterFx)
|
|
218
|
+
case "character-motion":
|
|
219
|
+
return trim(data.characterMotion)
|
|
161
220
|
case "transition":
|
|
162
221
|
return trim(data.transition)
|
|
163
222
|
case "style":
|
|
@@ -369,6 +369,7 @@ export const INPUT_FIELD_MAP: Record<string, InputFieldSchema> = {
|
|
|
369
369
|
"post-process-effects": { key: "postProcess", type: "select" },
|
|
370
370
|
"action-fx": { key: "actionFx", type: "select" },
|
|
371
371
|
"character-fx": { key: "characterFx", type: "select" },
|
|
372
|
+
"character-motion": { key: "characterMotion", type: "select" },
|
|
372
373
|
"transition": { key: "transition", type: "select" },
|
|
373
374
|
"loop-subject": { key: "loopSubject", type: "select" },
|
|
374
375
|
// --- Multi-dimension pickers: representative (first) field. Overriding only
|