tongflow 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/abi/tongflow.abi.json +49 -4
- package/dist/canvas-messages.cjs +71 -63
- package/dist/canvas-messages.js +71 -63
- package/dist/canvas.cjs +860 -260
- package/dist/canvas.css +1 -1
- package/dist/canvas.d.cts +157 -11
- package/dist/canvas.d.ts +157 -11
- package/dist/canvas.js +856 -261
- package/dist/index.cjs +680 -24
- package/dist/index.d.cts +323 -22
- package/dist/index.d.ts +323 -22
- package/dist/index.js +671 -25
- package/package.json +120 -26
package/dist/index.js
CHANGED
|
@@ -502,7 +502,11 @@ const ABI_NODES = {
|
|
|
502
502
|
properties: {
|
|
503
503
|
success: { type: "boolean" },
|
|
504
504
|
error: { type: "string" },
|
|
505
|
-
text: { type: "string" }
|
|
505
|
+
text: { type: "string" },
|
|
506
|
+
images: {
|
|
507
|
+
type: "array",
|
|
508
|
+
items: { $ref: "#/$defs/ImageRef" }
|
|
509
|
+
}
|
|
506
510
|
},
|
|
507
511
|
additionalProperties: false
|
|
508
512
|
}
|
|
@@ -618,6 +622,34 @@ const ABI_NODES = {
|
|
|
618
622
|
additionalProperties: false
|
|
619
623
|
}
|
|
620
624
|
},
|
|
625
|
+
"text-gen-audio": {
|
|
626
|
+
inputs: {
|
|
627
|
+
type: "object",
|
|
628
|
+
required: ["text"],
|
|
629
|
+
properties: {
|
|
630
|
+
text: {
|
|
631
|
+
type: "string",
|
|
632
|
+
minLength: 1
|
|
633
|
+
},
|
|
634
|
+
ref_audios: {
|
|
635
|
+
type: "array",
|
|
636
|
+
items: { $ref: "#/$defs/Asset" }
|
|
637
|
+
},
|
|
638
|
+
seed: { type: "integer" }
|
|
639
|
+
},
|
|
640
|
+
additionalProperties: false
|
|
641
|
+
},
|
|
642
|
+
outputs: {
|
|
643
|
+
type: "object",
|
|
644
|
+
required: ["success"],
|
|
645
|
+
properties: {
|
|
646
|
+
success: { type: "boolean" },
|
|
647
|
+
error: { type: "string" },
|
|
648
|
+
audio: { $ref: "#/$defs/AudioRef" }
|
|
649
|
+
},
|
|
650
|
+
additionalProperties: false
|
|
651
|
+
}
|
|
652
|
+
},
|
|
621
653
|
"text-gen-speech-preset": {
|
|
622
654
|
inputs: {
|
|
623
655
|
type: "object",
|
|
@@ -1487,10 +1519,10 @@ const ABI_NODES = {
|
|
|
1487
1519
|
convert_voice: {
|
|
1488
1520
|
inputs: {
|
|
1489
1521
|
type: "object",
|
|
1490
|
-
required: ["
|
|
1522
|
+
required: ["audio", "ref_audio"],
|
|
1491
1523
|
properties: {
|
|
1492
|
-
|
|
1493
|
-
|
|
1524
|
+
audio: { $ref: "#/$defs/Asset" },
|
|
1525
|
+
ref_audio: { $ref: "#/$defs/Asset" }
|
|
1494
1526
|
},
|
|
1495
1527
|
additionalProperties: false
|
|
1496
1528
|
},
|
|
@@ -2127,6 +2159,7 @@ const NODE_TYPE_TO_ABI_FEATURE = {
|
|
|
2127
2159
|
imageGenImageUpscaleNode: "image-upscale",
|
|
2128
2160
|
textGenImageNode: "image-gen",
|
|
2129
2161
|
textGenMusicNode: "gen-music",
|
|
2162
|
+
textGenAudioNode: "text-gen-audio",
|
|
2130
2163
|
textGenSpeechCloneNode: "text-gen-speech-clone",
|
|
2131
2164
|
textGenSpeechCloneComposeNode: "text-gen-speech-clone",
|
|
2132
2165
|
imageGenVideoComposeNode: "image-gen-video",
|
|
@@ -2250,6 +2283,18 @@ const NODE_TYPE_SOURCE_SPEC = {
|
|
|
2250
2283
|
manual: true
|
|
2251
2284
|
})
|
|
2252
2285
|
},
|
|
2286
|
+
musicCoverNode: {
|
|
2287
|
+
text: handle({
|
|
2288
|
+
nodeType: "textNode",
|
|
2289
|
+
path: "texts[0]",
|
|
2290
|
+
manual: true
|
|
2291
|
+
}),
|
|
2292
|
+
lyrics: handle({
|
|
2293
|
+
nodeType: "textNode",
|
|
2294
|
+
path: "texts[0]",
|
|
2295
|
+
manual: true
|
|
2296
|
+
})
|
|
2297
|
+
},
|
|
2253
2298
|
textGenSpeechCloneComposeNode: { text: batchOn({
|
|
2254
2299
|
nodeType: "textNode",
|
|
2255
2300
|
path: "texts"
|
|
@@ -2287,7 +2332,10 @@ const NODE_TYPE_SOURCE_SPEC = {
|
|
|
2287
2332
|
audioGenTextSpeechRecognizeNode: { audio: batchOn() },
|
|
2288
2333
|
concatVideoComposeNode: { videos: collectAll() },
|
|
2289
2334
|
concatVideoNode: { videos: collectAll() },
|
|
2290
|
-
convertVoiceNode: {
|
|
2335
|
+
convertVoiceNode: {
|
|
2336
|
+
audio: batchOn({ nodeType: "audioNode" }),
|
|
2337
|
+
ref_audio: handle({ nodeType: "audioNode" })
|
|
2338
|
+
},
|
|
2291
2339
|
denoiseAudioSubtitleNode: { fileKey: batchOn({ nodeType: "audioNode" }) },
|
|
2292
2340
|
dropVideoNode: { videos: collectAll() },
|
|
2293
2341
|
extractAudioNode: { video: batchOn() },
|
|
@@ -2335,6 +2383,14 @@ const NODE_TYPE_SOURCE_SPEC = {
|
|
|
2335
2383
|
path: "texts[0]"
|
|
2336
2384
|
})
|
|
2337
2385
|
},
|
|
2386
|
+
textGenAudioNode: {
|
|
2387
|
+
text: handle({
|
|
2388
|
+
nodeType: "textNode",
|
|
2389
|
+
path: "texts[0]",
|
|
2390
|
+
manual: true
|
|
2391
|
+
}),
|
|
2392
|
+
ref_audios: collectAll({ nodeType: "audioNode" })
|
|
2393
|
+
},
|
|
2338
2394
|
textGenSpeechCloneNode: {
|
|
2339
2395
|
text: batchOn({
|
|
2340
2396
|
nodeType: "textNode",
|
|
@@ -2579,6 +2635,381 @@ function getEdgeTargetOptions(edge, nodes) {
|
|
|
2579
2635
|
return options;
|
|
2580
2636
|
}
|
|
2581
2637
|
//#endregion
|
|
2638
|
+
//#region src/core/abi/node-actions.ts
|
|
2639
|
+
const MEDIA_TYPES = [
|
|
2640
|
+
"imageNode",
|
|
2641
|
+
"videoNode",
|
|
2642
|
+
"audioNode"
|
|
2643
|
+
];
|
|
2644
|
+
/**
|
|
2645
|
+
* Per-node-type presentation + caps. Every ABI node type must appear here (a
|
|
2646
|
+
* vitest guard fails otherwise) so a new slot can't quietly end up without an
|
|
2647
|
+
* entry point. Order groups by the modality a button hangs off: text 100s,
|
|
2648
|
+
* image 200s, video 300s, audio 400s, document/link/model 500s, combos 600s.
|
|
2649
|
+
*/
|
|
2650
|
+
const NODE_ACTION_META = {
|
|
2651
|
+
splitTextNode: {
|
|
2652
|
+
label: "splitText",
|
|
2653
|
+
order: 100
|
|
2654
|
+
},
|
|
2655
|
+
genTextNode: {
|
|
2656
|
+
label: "generateText",
|
|
2657
|
+
order: 110
|
|
2658
|
+
},
|
|
2659
|
+
textGenImageNode: {
|
|
2660
|
+
label: "generateImage",
|
|
2661
|
+
order: 120
|
|
2662
|
+
},
|
|
2663
|
+
textGenMusicNode: {
|
|
2664
|
+
label: "generateMusic",
|
|
2665
|
+
order: 130,
|
|
2666
|
+
limits: { textNode: [1, 2] }
|
|
2667
|
+
},
|
|
2668
|
+
textGenAudioNode: {
|
|
2669
|
+
label: "generateAudio",
|
|
2670
|
+
order: 135
|
|
2671
|
+
},
|
|
2672
|
+
textGenSpeechCloneNode: {
|
|
2673
|
+
label: "textToSpeechClone",
|
|
2674
|
+
order: 140
|
|
2675
|
+
},
|
|
2676
|
+
textGenSpeechPresetNode: {
|
|
2677
|
+
label: "textToSpeechPreset",
|
|
2678
|
+
order: 150
|
|
2679
|
+
},
|
|
2680
|
+
textGenSpeechInstructNode: {
|
|
2681
|
+
label: "textToSpeechInstruct",
|
|
2682
|
+
order: 160
|
|
2683
|
+
},
|
|
2684
|
+
textGenVideoNode: {
|
|
2685
|
+
label: "generateVideo",
|
|
2686
|
+
order: 170
|
|
2687
|
+
},
|
|
2688
|
+
musicBriefNode: {
|
|
2689
|
+
label: "musicBrief",
|
|
2690
|
+
order: 180
|
|
2691
|
+
},
|
|
2692
|
+
textsGenTextNode: {
|
|
2693
|
+
label: "rewriteText",
|
|
2694
|
+
order: 190,
|
|
2695
|
+
limits: { textNode: [2, Number.POSITIVE_INFINITY] }
|
|
2696
|
+
},
|
|
2697
|
+
imageGenTextNode: {
|
|
2698
|
+
label: "describeReverse",
|
|
2699
|
+
order: 200,
|
|
2700
|
+
aliases: { modelNode: "imageNode" }
|
|
2701
|
+
},
|
|
2702
|
+
imageGenVideoNode: {
|
|
2703
|
+
label: "generateVideo",
|
|
2704
|
+
order: 210,
|
|
2705
|
+
aliases: { modelNode: "imageNode" }
|
|
2706
|
+
},
|
|
2707
|
+
imageGenVideoComposeNode: {
|
|
2708
|
+
label: "generateVideo",
|
|
2709
|
+
order: 211
|
|
2710
|
+
},
|
|
2711
|
+
imageGenImageNode: {
|
|
2712
|
+
label: "editImage",
|
|
2713
|
+
order: 220
|
|
2714
|
+
},
|
|
2715
|
+
imageGenImageUpscaleNode: {
|
|
2716
|
+
label: "upscale",
|
|
2717
|
+
order: 230
|
|
2718
|
+
},
|
|
2719
|
+
imageGenModelNode: {
|
|
2720
|
+
label: "generate3D",
|
|
2721
|
+
order: 240
|
|
2722
|
+
},
|
|
2723
|
+
imagePoseNode: {
|
|
2724
|
+
label: "detectPose",
|
|
2725
|
+
order: 250
|
|
2726
|
+
},
|
|
2727
|
+
imageBodySegNode: {
|
|
2728
|
+
label: "segmentBody",
|
|
2729
|
+
order: 260
|
|
2730
|
+
},
|
|
2731
|
+
imageNormalNode: {
|
|
2732
|
+
label: "estimateNormal",
|
|
2733
|
+
order: 270
|
|
2734
|
+
},
|
|
2735
|
+
imageMattingNode: {
|
|
2736
|
+
label: "extractForeground",
|
|
2737
|
+
order: 280
|
|
2738
|
+
},
|
|
2739
|
+
imageFusionNode: {
|
|
2740
|
+
label: "imageFusion",
|
|
2741
|
+
order: 290,
|
|
2742
|
+
limits: { imageNode: [2, 14] }
|
|
2743
|
+
},
|
|
2744
|
+
imagesGenVideoNode: {
|
|
2745
|
+
label: "imagesGenVideo",
|
|
2746
|
+
order: 291,
|
|
2747
|
+
limits: { imageNode: [2, 9] }
|
|
2748
|
+
},
|
|
2749
|
+
imageImageGenVideoNode: {
|
|
2750
|
+
label: "firstLastFrameVideo",
|
|
2751
|
+
order: 292,
|
|
2752
|
+
limits: { imageNode: [2, 2] }
|
|
2753
|
+
},
|
|
2754
|
+
videoGenTextNode: {
|
|
2755
|
+
label: "describeReverse",
|
|
2756
|
+
order: 300
|
|
2757
|
+
},
|
|
2758
|
+
videoGenTextSpeechRecognizeNode: {
|
|
2759
|
+
label: "speechRecognize",
|
|
2760
|
+
order: 310
|
|
2761
|
+
},
|
|
2762
|
+
videoUpscaleNode: {
|
|
2763
|
+
label: "upscale",
|
|
2764
|
+
order: 320
|
|
2765
|
+
},
|
|
2766
|
+
videoGenModelNode: {
|
|
2767
|
+
label: "captureMotion",
|
|
2768
|
+
order: 330
|
|
2769
|
+
},
|
|
2770
|
+
videoEditNode: {
|
|
2771
|
+
label: "editVideo",
|
|
2772
|
+
order: 340
|
|
2773
|
+
},
|
|
2774
|
+
extractAudioNode: {
|
|
2775
|
+
label: "extractAudioTrack",
|
|
2776
|
+
order: 350
|
|
2777
|
+
},
|
|
2778
|
+
removeVideoAudioNode: {
|
|
2779
|
+
label: "removeVideoAudio",
|
|
2780
|
+
order: 360
|
|
2781
|
+
},
|
|
2782
|
+
removeWatermarkNode: {
|
|
2783
|
+
label: "removeWatermark",
|
|
2784
|
+
order: 365
|
|
2785
|
+
},
|
|
2786
|
+
removeVideoSubtitleNode: {
|
|
2787
|
+
label: "removeSubtitle",
|
|
2788
|
+
order: 366
|
|
2789
|
+
},
|
|
2790
|
+
splitVideoNode: {
|
|
2791
|
+
label: "slice",
|
|
2792
|
+
order: 370
|
|
2793
|
+
},
|
|
2794
|
+
getFirstFrameNode: {
|
|
2795
|
+
label: "firstFrame",
|
|
2796
|
+
order: 380
|
|
2797
|
+
},
|
|
2798
|
+
getLastFrameNode: {
|
|
2799
|
+
label: "lastFrame",
|
|
2800
|
+
order: 390
|
|
2801
|
+
},
|
|
2802
|
+
dropVideoNode: {
|
|
2803
|
+
label: "filter",
|
|
2804
|
+
order: 391,
|
|
2805
|
+
groupOnly: true
|
|
2806
|
+
},
|
|
2807
|
+
arrangeNode: {
|
|
2808
|
+
label: "arrange",
|
|
2809
|
+
order: 392,
|
|
2810
|
+
groupOnly: true
|
|
2811
|
+
},
|
|
2812
|
+
concatVideoNode: {
|
|
2813
|
+
label: "concat",
|
|
2814
|
+
order: 393,
|
|
2815
|
+
groupOnly: true
|
|
2816
|
+
},
|
|
2817
|
+
concatVideoComposeNode: {
|
|
2818
|
+
label: "concat",
|
|
2819
|
+
order: 394,
|
|
2820
|
+
minNodes: 2
|
|
2821
|
+
},
|
|
2822
|
+
audioDescribeNode: {
|
|
2823
|
+
label: "describeReverse",
|
|
2824
|
+
order: 400
|
|
2825
|
+
},
|
|
2826
|
+
audioGenTextSpeechRecognizeNode: {
|
|
2827
|
+
label: "speechRecognize",
|
|
2828
|
+
order: 410
|
|
2829
|
+
},
|
|
2830
|
+
separateAudioTrackNode: {
|
|
2831
|
+
label: "separateAudio",
|
|
2832
|
+
order: 420
|
|
2833
|
+
},
|
|
2834
|
+
separateSpeakerNode: {
|
|
2835
|
+
label: "separateSpeaker",
|
|
2836
|
+
order: 430
|
|
2837
|
+
},
|
|
2838
|
+
separateSoundNode: {
|
|
2839
|
+
label: "separateSound",
|
|
2840
|
+
order: 440
|
|
2841
|
+
},
|
|
2842
|
+
denoiseAudioSubtitleNode: {
|
|
2843
|
+
label: "denoise",
|
|
2844
|
+
order: 450
|
|
2845
|
+
},
|
|
2846
|
+
convertVoiceNode: {
|
|
2847
|
+
label: "convertVoice",
|
|
2848
|
+
order: 460
|
|
2849
|
+
},
|
|
2850
|
+
musicRepaintNode: {
|
|
2851
|
+
label: "repaintMusic",
|
|
2852
|
+
order: 470
|
|
2853
|
+
},
|
|
2854
|
+
musicCoverNode: {
|
|
2855
|
+
label: "coverMusic",
|
|
2856
|
+
order: 480
|
|
2857
|
+
},
|
|
2858
|
+
musicExtractNode: {
|
|
2859
|
+
label: "extractStem",
|
|
2860
|
+
order: 490
|
|
2861
|
+
},
|
|
2862
|
+
musicLegoNode: {
|
|
2863
|
+
label: "addTrack",
|
|
2864
|
+
order: 491
|
|
2865
|
+
},
|
|
2866
|
+
musicCompleteNode: {
|
|
2867
|
+
label: "completeMusic",
|
|
2868
|
+
order: 492
|
|
2869
|
+
},
|
|
2870
|
+
fileGenTextNode: {
|
|
2871
|
+
label: "parseDocument",
|
|
2872
|
+
order: 500
|
|
2873
|
+
},
|
|
2874
|
+
linkGenTextNode: {
|
|
2875
|
+
label: "extractContent",
|
|
2876
|
+
order: 510
|
|
2877
|
+
},
|
|
2878
|
+
audioVideoLipSyncNode: {
|
|
2879
|
+
label: "lipSync",
|
|
2880
|
+
order: 600
|
|
2881
|
+
},
|
|
2882
|
+
mergeVideoAudioNode: {
|
|
2883
|
+
label: "merge",
|
|
2884
|
+
order: 610
|
|
2885
|
+
},
|
|
2886
|
+
speechVideoGenVideoNode: {
|
|
2887
|
+
label: "lipDub",
|
|
2888
|
+
order: 620
|
|
2889
|
+
},
|
|
2890
|
+
videoImageGenVideoMoveNode: {
|
|
2891
|
+
label: "videoTransfer",
|
|
2892
|
+
order: 630
|
|
2893
|
+
},
|
|
2894
|
+
videoImageGenVideoMixNode: {
|
|
2895
|
+
label: "characterReplace",
|
|
2896
|
+
order: 640
|
|
2897
|
+
},
|
|
2898
|
+
speechImageGenVideoNode: {
|
|
2899
|
+
label: "generateVideo",
|
|
2900
|
+
order: 650
|
|
2901
|
+
},
|
|
2902
|
+
speechTextGenVideoNode: {
|
|
2903
|
+
label: "generateVideo",
|
|
2904
|
+
order: 660
|
|
2905
|
+
},
|
|
2906
|
+
speechGenVideoNode: {
|
|
2907
|
+
label: "generateVideo",
|
|
2908
|
+
order: 661
|
|
2909
|
+
},
|
|
2910
|
+
textAudioGenSpeechNode: {
|
|
2911
|
+
label: "speakWithStyle",
|
|
2912
|
+
order: 670
|
|
2913
|
+
},
|
|
2914
|
+
textGenSpeechCloneComposeNode: {
|
|
2915
|
+
label: "cloneVoice",
|
|
2916
|
+
order: 680
|
|
2917
|
+
},
|
|
2918
|
+
refsGenVideoNode: {
|
|
2919
|
+
label: "refsGenVideo",
|
|
2920
|
+
order: 690,
|
|
2921
|
+
minNodes: 2,
|
|
2922
|
+
limits: {
|
|
2923
|
+
imageNode: [0, 9],
|
|
2924
|
+
videoNode: [0, 3],
|
|
2925
|
+
audioNode: [0, 3],
|
|
2926
|
+
textNode: [0, 1]
|
|
2927
|
+
},
|
|
2928
|
+
totalMedia: [1, 12]
|
|
2929
|
+
}
|
|
2930
|
+
};
|
|
2931
|
+
function capacities(nodeType) {
|
|
2932
|
+
const spec = resolvedSpecForNodeType(nodeType);
|
|
2933
|
+
if (!spec) return void 0;
|
|
2934
|
+
const caps = {};
|
|
2935
|
+
for (const field of spec.topology.inputOrder) {
|
|
2936
|
+
const f = spec.fields[field];
|
|
2937
|
+
if (f?.kind !== "handle") continue;
|
|
2938
|
+
const cap = caps[f.nodeType] ?? {
|
|
2939
|
+
max: 0,
|
|
2940
|
+
min: 0
|
|
2941
|
+
};
|
|
2942
|
+
caps[f.nodeType] = cap;
|
|
2943
|
+
cap.max = f.array || f.collect === true ? Number.POSITIVE_INFINITY : cap.max + 1;
|
|
2944
|
+
if (f.required && !f.manual) cap.min = Math.max(cap.min, 1);
|
|
2945
|
+
}
|
|
2946
|
+
return caps;
|
|
2947
|
+
}
|
|
2948
|
+
/** Fold aliased modalities into the modality they stand in for. */
|
|
2949
|
+
function applyAliases(counts, aliases) {
|
|
2950
|
+
if (!aliases) return counts;
|
|
2951
|
+
const out = { ...counts };
|
|
2952
|
+
for (const [from, to] of Object.entries(aliases)) {
|
|
2953
|
+
const n = out[from];
|
|
2954
|
+
if (!n) continue;
|
|
2955
|
+
out[to] = (out[to] ?? 0) + n;
|
|
2956
|
+
delete out[from];
|
|
2957
|
+
}
|
|
2958
|
+
return out;
|
|
2959
|
+
}
|
|
2960
|
+
function withinLimits(counts, meta) {
|
|
2961
|
+
for (const [type, range] of Object.entries(meta.limits ?? {})) {
|
|
2962
|
+
const n = counts[type] ?? 0;
|
|
2963
|
+
if (n < range[0] || n > range[1]) return false;
|
|
2964
|
+
}
|
|
2965
|
+
if (meta.totalMedia) {
|
|
2966
|
+
const total = MEDIA_TYPES.reduce((sum, t) => sum + (counts[t] ?? 0), 0);
|
|
2967
|
+
if (total < meta.totalMedia[0] || total > meta.totalMedia[1]) return false;
|
|
2968
|
+
}
|
|
2969
|
+
return true;
|
|
2970
|
+
}
|
|
2971
|
+
/**
|
|
2972
|
+
* Node types the given selection can be turned into, ordered for display.
|
|
2973
|
+
*
|
|
2974
|
+
* `counts` holds only modality nodes — the caller drops processing nodes and
|
|
2975
|
+
* `add*` nodes before calling, since neither carries an output to feed.
|
|
2976
|
+
*/
|
|
2977
|
+
function nodeActionsForSelection(counts, options = {}) {
|
|
2978
|
+
const total = Object.values(counts).reduce((sum, n) => sum + (n ?? 0), 0);
|
|
2979
|
+
const out = [];
|
|
2980
|
+
for (const [nodeType, meta] of Object.entries(NODE_ACTION_META)) {
|
|
2981
|
+
if (meta.groupOnly && !(options.group && total === 1)) continue;
|
|
2982
|
+
if (meta.minNodes && total < meta.minNodes) continue;
|
|
2983
|
+
const caps = capacities(nodeType);
|
|
2984
|
+
if (!caps) continue;
|
|
2985
|
+
const effective = applyAliases(counts, meta.aliases);
|
|
2986
|
+
if (!withinLimits(effective, meta)) continue;
|
|
2987
|
+
const modalities = /* @__PURE__ */ new Set([...Object.keys(caps), ...Object.keys(effective)]);
|
|
2988
|
+
let ok = true;
|
|
2989
|
+
for (const modality of modalities) {
|
|
2990
|
+
const n = effective[modality] ?? 0;
|
|
2991
|
+
const cap = caps[modality] ?? {
|
|
2992
|
+
max: 0,
|
|
2993
|
+
min: 0
|
|
2994
|
+
};
|
|
2995
|
+
if (n > cap.max || n < cap.min) {
|
|
2996
|
+
ok = false;
|
|
2997
|
+
break;
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
if (!ok) continue;
|
|
3001
|
+
const feature = NODE_TYPE_TO_ABI_FEATURE[nodeType];
|
|
3002
|
+
if (!feature) continue;
|
|
3003
|
+
out.push({
|
|
3004
|
+
nodeType,
|
|
3005
|
+
feature,
|
|
3006
|
+
label: meta.label,
|
|
3007
|
+
order: meta.order
|
|
3008
|
+
});
|
|
3009
|
+
}
|
|
3010
|
+
return out.sort((a, b) => a.order - b.order);
|
|
3011
|
+
}
|
|
3012
|
+
//#endregion
|
|
2582
3013
|
//#region src/core/workflow/connection-validator.ts
|
|
2583
3014
|
function resolveRefs(schema, depth = 0) {
|
|
2584
3015
|
if (depth > 48 || typeof schema !== "object" || schema === null) return schema ?? {};
|
|
@@ -3490,6 +3921,7 @@ function applyGraphPatch(store, patch, options = {}) {
|
|
|
3490
3921
|
const nodeData = { ...data };
|
|
3491
3922
|
if (spec.pluginId) nodeData.pluginId = spec.pluginId;
|
|
3492
3923
|
if (spec.pluginModel) nodeData.pluginModel = spec.pluginModel;
|
|
3924
|
+
if (spec.pluginParams && Object.keys(spec.pluginParams).length > 0) nodeData.pluginParams = { ...spec.pluginParams };
|
|
3493
3925
|
const edgeIdx = pendingEdges.findIndex((e) => {
|
|
3494
3926
|
if (e.to !== spec.alias) return false;
|
|
3495
3927
|
return !!resolveNodeRef(e.from, store.getState().nodes, aliases).id;
|
|
@@ -3839,6 +4271,11 @@ const TONGFLOW_TOOL_DEFS = [
|
|
|
3839
4271
|
type: "string",
|
|
3840
4272
|
description: "Optional model id, only for plugins that advertise models."
|
|
3841
4273
|
},
|
|
4274
|
+
pluginParams: {
|
|
4275
|
+
type: "object",
|
|
4276
|
+
description: "Optional advanced parameters, only keys the plugin advertises for this slot.",
|
|
4277
|
+
additionalProperties: true
|
|
4278
|
+
},
|
|
3842
4279
|
fromAttachment: {
|
|
3843
4280
|
type: "integer",
|
|
3844
4281
|
description: "1-based index of a file the user attached to the chat. Use this for add*Node/modality nodes carrying user uploads — never write a storage key yourself."
|
|
@@ -4694,7 +5131,11 @@ var tongflow_abi_default = {
|
|
|
4694
5131
|
"properties": {
|
|
4695
5132
|
"success": { "type": "boolean" },
|
|
4696
5133
|
"error": { "type": "string" },
|
|
4697
|
-
"text": { "type": "string" }
|
|
5134
|
+
"text": { "type": "string" },
|
|
5135
|
+
"images": {
|
|
5136
|
+
"type": "array",
|
|
5137
|
+
"items": { "$ref": "#/$defs/ImageRef" }
|
|
5138
|
+
}
|
|
4698
5139
|
},
|
|
4699
5140
|
"additionalProperties": false
|
|
4700
5141
|
}
|
|
@@ -4814,6 +5255,35 @@ var tongflow_abi_default = {
|
|
|
4814
5255
|
"additionalProperties": false
|
|
4815
5256
|
}
|
|
4816
5257
|
},
|
|
5258
|
+
{
|
|
5259
|
+
"nodeSlot": "text-gen-audio",
|
|
5260
|
+
"inputs": {
|
|
5261
|
+
"type": "object",
|
|
5262
|
+
"required": ["text"],
|
|
5263
|
+
"properties": {
|
|
5264
|
+
"text": {
|
|
5265
|
+
"type": "string",
|
|
5266
|
+
"minLength": 1
|
|
5267
|
+
},
|
|
5268
|
+
"ref_audios": {
|
|
5269
|
+
"type": "array",
|
|
5270
|
+
"items": { "$ref": "#/$defs/Asset" }
|
|
5271
|
+
},
|
|
5272
|
+
"seed": { "type": "integer" }
|
|
5273
|
+
},
|
|
5274
|
+
"additionalProperties": false
|
|
5275
|
+
},
|
|
5276
|
+
"outputs": {
|
|
5277
|
+
"type": "object",
|
|
5278
|
+
"required": ["success"],
|
|
5279
|
+
"properties": {
|
|
5280
|
+
"success": { "type": "boolean" },
|
|
5281
|
+
"error": { "type": "string" },
|
|
5282
|
+
"audio": { "$ref": "#/$defs/AudioRef" }
|
|
5283
|
+
},
|
|
5284
|
+
"additionalProperties": false
|
|
5285
|
+
}
|
|
5286
|
+
},
|
|
4817
5287
|
{
|
|
4818
5288
|
"nodeSlot": "text-gen-speech-preset",
|
|
4819
5289
|
"inputs": {
|
|
@@ -5716,10 +6186,10 @@ var tongflow_abi_default = {
|
|
|
5716
6186
|
"nodeSlot": "convert_voice",
|
|
5717
6187
|
"inputs": {
|
|
5718
6188
|
"type": "object",
|
|
5719
|
-
"required": ["
|
|
6189
|
+
"required": ["audio", "ref_audio"],
|
|
5720
6190
|
"properties": {
|
|
5721
|
-
"
|
|
5722
|
-
"
|
|
6191
|
+
"audio": { "$ref": "#/$defs/Asset" },
|
|
6192
|
+
"ref_audio": { "$ref": "#/$defs/Asset" }
|
|
5723
6193
|
},
|
|
5724
6194
|
"additionalProperties": false
|
|
5725
6195
|
},
|
|
@@ -6099,6 +6569,103 @@ const resolveLabelLookupFeatureName = clientRegistry.resolveLabelLookupFeatureNa
|
|
|
6099
6569
|
const getFeatureByName = clientRegistry.getFeatureByName;
|
|
6100
6570
|
const getFeatureRegistryAliases = clientRegistry.getFeatureRegistryAliases;
|
|
6101
6571
|
//#endregion
|
|
6572
|
+
//#region src/core/registry/model-catalog.ts
|
|
6573
|
+
/** Read a dot-path (`a.b.c`) off an unknown JSON value; `undefined` when absent. */
|
|
6574
|
+
function getPath(value, path) {
|
|
6575
|
+
let cur = value;
|
|
6576
|
+
for (const key of path.split(".")) {
|
|
6577
|
+
if (cur === null || typeof cur !== "object") return void 0;
|
|
6578
|
+
cur = cur[key];
|
|
6579
|
+
}
|
|
6580
|
+
return cur;
|
|
6581
|
+
}
|
|
6582
|
+
/** Substring match against the field's JSON serialization (strings as-is). */
|
|
6583
|
+
function fieldContains(value, token) {
|
|
6584
|
+
if (value === void 0 || value === null) return false;
|
|
6585
|
+
return (typeof value === "string" ? value : JSON.stringify(value)).includes(token);
|
|
6586
|
+
}
|
|
6587
|
+
/**
|
|
6588
|
+
* Filter a fetched catalog payload into `slot -> model ids`, applying the
|
|
6589
|
+
* plugin's declared `exclude` and per-slot `slots` rules (substring tokens,
|
|
6590
|
+
* `!`-prefixed = must be absent). Ids keep catalog order; malformed records
|
|
6591
|
+
* are skipped. Pure — the fetch lives in the canvas.
|
|
6592
|
+
*/
|
|
6593
|
+
function filterModelCatalog(catalog, payload) {
|
|
6594
|
+
const out = {};
|
|
6595
|
+
for (const slot of Object.keys(catalog.slots)) out[slot] = [];
|
|
6596
|
+
const items = getPath(payload, catalog.items);
|
|
6597
|
+
if (!Array.isArray(items)) return out;
|
|
6598
|
+
const exclude = Object.entries(catalog.exclude ?? {});
|
|
6599
|
+
for (const record of items) {
|
|
6600
|
+
const id = getPath(record, catalog.id);
|
|
6601
|
+
if (typeof id !== "string" || !id.trim()) continue;
|
|
6602
|
+
if (exclude.some(([field, literal]) => getPath(record, field) === literal)) continue;
|
|
6603
|
+
for (const [slot, rules] of Object.entries(catalog.slots)) if (Object.entries(rules).every(([field, tokens]) => {
|
|
6604
|
+
const value = getPath(record, field);
|
|
6605
|
+
return (Array.isArray(tokens) ? tokens : [tokens]).every((token) => token.startsWith("!") ? !fieldContains(value, token.slice(1)) : fieldContains(value, token));
|
|
6606
|
+
}) && !out[slot].includes(id)) out[slot].push(id);
|
|
6607
|
+
}
|
|
6608
|
+
return out;
|
|
6609
|
+
}
|
|
6610
|
+
//#endregion
|
|
6611
|
+
//#region src/core/registry/plugin-params.ts
|
|
6612
|
+
/**
|
|
6613
|
+
* The params a node offers for the active plugin + model: every declared entry
|
|
6614
|
+
* whose `models` gate is absent or names the selected model.
|
|
6615
|
+
*/
|
|
6616
|
+
function visiblePluginParams(params, model) {
|
|
6617
|
+
if (!params) return [];
|
|
6618
|
+
const out = [];
|
|
6619
|
+
for (const [name, spec] of Object.entries(params)) {
|
|
6620
|
+
if (spec.models && !(model && spec.models.includes(model))) continue;
|
|
6621
|
+
out.push({
|
|
6622
|
+
name,
|
|
6623
|
+
spec
|
|
6624
|
+
});
|
|
6625
|
+
}
|
|
6626
|
+
return out;
|
|
6627
|
+
}
|
|
6628
|
+
/** True when `value` is a legal setting for `spec` (type + range/options). */
|
|
6629
|
+
function isValidPluginParamValue(spec, value) {
|
|
6630
|
+
switch (spec.type) {
|
|
6631
|
+
case "select": return (spec.options ?? []).some((o) => o === value);
|
|
6632
|
+
case "boolean": return typeof value === "boolean";
|
|
6633
|
+
case "text": return typeof value === "string";
|
|
6634
|
+
case "number":
|
|
6635
|
+
case "integer":
|
|
6636
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return false;
|
|
6637
|
+
if (spec.type === "integer" && !Number.isInteger(value)) return false;
|
|
6638
|
+
if (spec.min !== void 0 && value < spec.min) return false;
|
|
6639
|
+
if (spec.max !== void 0 && value > spec.max) return false;
|
|
6640
|
+
return true;
|
|
6641
|
+
default: return false;
|
|
6642
|
+
}
|
|
6643
|
+
}
|
|
6644
|
+
/**
|
|
6645
|
+
* Keep only the entries of `values` that the visible params accept and that
|
|
6646
|
+
* differ from the declared default. Unset means "plugin default", so a value
|
|
6647
|
+
* equal to it is dropped; the result is what travels to the plugin.
|
|
6648
|
+
*/
|
|
6649
|
+
function normalizePluginParams(entries, values) {
|
|
6650
|
+
const out = {};
|
|
6651
|
+
if (!values) return out;
|
|
6652
|
+
for (const { name, spec } of entries) {
|
|
6653
|
+
if (!(name in values)) continue;
|
|
6654
|
+
const v = values[name];
|
|
6655
|
+
if (!isValidPluginParamValue(spec, v)) continue;
|
|
6656
|
+
if (spec.default !== void 0 && v === spec.default) continue;
|
|
6657
|
+
out[name] = v;
|
|
6658
|
+
}
|
|
6659
|
+
return out;
|
|
6660
|
+
}
|
|
6661
|
+
/** Shallow key/value equality for two param records. */
|
|
6662
|
+
function samePluginParams(a, b) {
|
|
6663
|
+
const ka = Object.keys(a ?? {});
|
|
6664
|
+
const kb = Object.keys(b ?? {});
|
|
6665
|
+
if (ka.length !== kb.length) return false;
|
|
6666
|
+
return ka.every((k) => Object.is(a?.[k], b?.[k]));
|
|
6667
|
+
}
|
|
6668
|
+
//#endregion
|
|
6102
6669
|
//#region src/core/registry/plugins-registry-schema.ts
|
|
6103
6670
|
/**
|
|
6104
6671
|
* Plugins registry produced by the Python scanner over `plugins/*`.
|
|
@@ -6116,12 +6683,75 @@ const getFeatureRegistryAliases = clientRegistry.getFeatureRegistryAliases;
|
|
|
6116
6683
|
* the first plugin in directory order.
|
|
6117
6684
|
* - plugins[pluginId]: how to launch that plugin's entry
|
|
6118
6685
|
*/
|
|
6686
|
+
/**
|
|
6687
|
+
* One entry of a plugin's `TONGFLOW_SLOT_PARAMS` declaration: a plugin-specific
|
|
6688
|
+
* run-time knob the node offers under its collapsed "Advanced" section. These
|
|
6689
|
+
* are never ABI fields — the canvas sends the user's picks top-level as
|
|
6690
|
+
* `params` and the plugin reads them via `tongflow.slots.current_params()`,
|
|
6691
|
+
* falling back to its own defaults for anything unset.
|
|
6692
|
+
*/
|
|
6693
|
+
const paramLiteral = z.union([
|
|
6694
|
+
z.string(),
|
|
6695
|
+
z.number(),
|
|
6696
|
+
z.boolean()
|
|
6697
|
+
]);
|
|
6698
|
+
const PluginParamSpecSchema = z.object({
|
|
6699
|
+
type: z.enum([
|
|
6700
|
+
"select",
|
|
6701
|
+
"number",
|
|
6702
|
+
"integer",
|
|
6703
|
+
"boolean",
|
|
6704
|
+
"text"
|
|
6705
|
+
]),
|
|
6706
|
+
label: z.string().min(1).optional(),
|
|
6707
|
+
description: z.string().min(1).optional(),
|
|
6708
|
+
default: paramLiteral.optional(),
|
|
6709
|
+
/** `select` only. */
|
|
6710
|
+
options: z.array(z.union([z.string(), z.number()])).min(1).optional(),
|
|
6711
|
+
/** `number` / `integer` only. */
|
|
6712
|
+
min: z.number().optional(),
|
|
6713
|
+
max: z.number().optional(),
|
|
6714
|
+
step: z.number().optional(),
|
|
6715
|
+
/** When set, only offered while one of these router models is selected. */
|
|
6716
|
+
models: z.array(z.string().min(1)).min(1).optional()
|
|
6717
|
+
});
|
|
6119
6718
|
const PluginMethodSchema = z.object({
|
|
6120
6719
|
methodName: z.string().min(1),
|
|
6121
6720
|
/** Optional per-slot model ids a router-style plugin exposes
|
|
6122
6721
|
* (`TONGFLOW_SLOT_MODELS` in the plugin source); first entry is the
|
|
6123
6722
|
* default. Absent for single-model plugins. */
|
|
6124
|
-
models: z.array(z.string().min(1)).optional()
|
|
6723
|
+
models: z.array(z.string().min(1)).optional(),
|
|
6724
|
+
/** Optional per-slot advanced parameters (`TONGFLOW_SLOT_PARAMS` in the
|
|
6725
|
+
* plugin source), in declared order. Absent when the plugin exposes none. */
|
|
6726
|
+
params: z.record(z.string().min(1), PluginParamSpecSchema).optional()
|
|
6727
|
+
});
|
|
6728
|
+
/**
|
|
6729
|
+
* Optional live model catalog (`TONGFLOW_MODEL_CATALOG` in the plugin source).
|
|
6730
|
+
* The canvas GETs `url` in the browser (public, CORS-enabled, no auth) — or,
|
|
6731
|
+
* when `authEnv` names the env key holding a bearer token, through the app's
|
|
6732
|
+
* `/api/plugins/model-catalog` route, which injects the stored key server-side
|
|
6733
|
+
* — reads the record array at dot-path `items`, each model id at dot-path `id`, drops
|
|
6734
|
+
* records where an `exclude` field equals its literal, and keeps a record for
|
|
6735
|
+
* a slot when every `slots[slot]` token is a substring of the named field
|
|
6736
|
+
* (arrays/objects are JSON-serialized before matching; a token prefixed with
|
|
6737
|
+
* `!` must be absent instead). Matching ids extend
|
|
6738
|
+
* that slot's dropdown after the static `models` shortlist.
|
|
6739
|
+
*/
|
|
6740
|
+
const PluginModelCatalogSchema = z.object({
|
|
6741
|
+
url: z.string().url(),
|
|
6742
|
+
/** Env key whose value is sent as `Authorization: Bearer …`; the fetch is
|
|
6743
|
+
* proxied server-side so the key never reaches the browser. */
|
|
6744
|
+
authEnv: z.string().min(1).optional(),
|
|
6745
|
+
items: z.string().min(1).default("data"),
|
|
6746
|
+
id: z.string().min(1).default("id"),
|
|
6747
|
+
exclude: z.record(z.string().min(1), z.union([
|
|
6748
|
+
z.string(),
|
|
6749
|
+
z.boolean(),
|
|
6750
|
+
z.number()
|
|
6751
|
+
])).optional(),
|
|
6752
|
+
/** slot -> field -> token(s). Every token must be a substring of the
|
|
6753
|
+
* field's JSON; a token prefixed with `!` must be absent. */
|
|
6754
|
+
slots: z.record(z.string().min(1), z.record(z.string().min(1), z.union([z.string().min(1), z.array(z.string().min(1)).min(1)])))
|
|
6125
6755
|
});
|
|
6126
6756
|
const PluginConfigSchema = z.object({
|
|
6127
6757
|
/** Relative to repo root, e.g. `plugins/tongflow-<runner>-foo` */
|
|
@@ -6136,6 +6766,8 @@ const PluginConfigSchema = z.object({
|
|
|
6136
6766
|
* such as Modal): its entry.py deploys once before invoking. Informational —
|
|
6137
6767
|
* the deploy step lives inside the plugin's entry.py. */
|
|
6138
6768
|
needsDeploy: z.boolean().optional(),
|
|
6769
|
+
/** Live model catalog the canvas can fetch to extend the model dropdown. */
|
|
6770
|
+
modelCatalog: PluginModelCatalogSchema.optional(),
|
|
6139
6771
|
/** Presentation-only metadata merged in from `tongflow.plugin.json`'s
|
|
6140
6772
|
* top-level `plugin` block (name/description/icon). Not produced by the
|
|
6141
6773
|
* scanner; attached by the registry API route for the node picker. */
|
|
@@ -6261,6 +6893,10 @@ const NODE_SIZE_TABLE = {
|
|
|
6261
6893
|
w: 520,
|
|
6262
6894
|
h: 480
|
|
6263
6895
|
},
|
|
6896
|
+
textGenAudioNode: {
|
|
6897
|
+
w: 480,
|
|
6898
|
+
h: 480
|
|
6899
|
+
},
|
|
6264
6900
|
musicExtractNode: {
|
|
6265
6901
|
w: 420,
|
|
6266
6902
|
h: 400
|
|
@@ -6765,7 +7401,7 @@ function createFlowSlice(set, get, options = {}) {
|
|
|
6765
7401
|
if (newlyCreatedIds.length > 0) get().nodeCreatedCallbacks.forEach((cb) => cb(newlyCreatedIds));
|
|
6766
7402
|
return ids;
|
|
6767
7403
|
},
|
|
6768
|
-
compose: ({ type, data }) => {
|
|
7404
|
+
compose: ({ type, data, sourceOrder }) => {
|
|
6769
7405
|
get().commitHistory();
|
|
6770
7406
|
const { comboSelectedIds, nodes, edges } = get();
|
|
6771
7407
|
const nodeId = createId();
|
|
@@ -6793,7 +7429,7 @@ function createFlowSlice(set, get, options = {}) {
|
|
|
6793
7429
|
data: data ?? {}
|
|
6794
7430
|
};
|
|
6795
7431
|
const usedTargetHandles = /* @__PURE__ */ new Set();
|
|
6796
|
-
const newEdges = Array.from(comboSelectedIds).map((id) => {
|
|
7432
|
+
const newEdges = (sourceOrder ? [...sourceOrder.filter((id) => comboSelectedIds.has(id)), ...Array.from(comboSelectedIds).filter((id) => !sourceOrder.includes(id))] : Array.from(comboSelectedIds)).map((id) => {
|
|
6797
7433
|
const node = nodes.find((n) => n.id === id);
|
|
6798
7434
|
if (!node) return null;
|
|
6799
7435
|
const { sourceHandle, targetHandle } = resolveEdgeHandles({
|
|
@@ -6909,6 +7545,16 @@ function getUpstreamNodeData(nodeId, nodes, edges) {
|
|
|
6909
7545
|
}];
|
|
6910
7546
|
});
|
|
6911
7547
|
}
|
|
7548
|
+
/**
|
|
7549
|
+
* Workflow input name for a level-0 data / add node: an explicit
|
|
7550
|
+
* `data.inputName` (a-z, 0-9, _ , -; set by authors so bindings read
|
|
7551
|
+
* `refs`, `prompt` …) else the legacy `input_<id8>`.
|
|
7552
|
+
*/
|
|
7553
|
+
function inputNameFor(nodeId, nodeData) {
|
|
7554
|
+
const custom = nodeData.inputName;
|
|
7555
|
+
if (typeof custom === "string" && /^[A-Za-z][A-Za-z0-9_-]{0,63}$/.test(custom)) return custom;
|
|
7556
|
+
return `input_${nodeId.substring(0, 8)}`;
|
|
7557
|
+
}
|
|
6912
7558
|
var WorkflowExporter = class {
|
|
6913
7559
|
nodes;
|
|
6914
7560
|
edges;
|
|
@@ -7019,16 +7665,14 @@ var WorkflowExporter = class {
|
|
|
7019
7665
|
const texts = nodeData.texts;
|
|
7020
7666
|
const hasStaticData = fileKeys && fileKeys.length > 0 || texts && texts.length > 0;
|
|
7021
7667
|
const isInput = this.parser.getStartNodes().includes(node.id) && !hasStaticData;
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
});
|
|
7031
|
-
}
|
|
7668
|
+
const inputName = inputNameFor(node.id, nodeData);
|
|
7669
|
+
if (isInput) inputs.push({
|
|
7670
|
+
name: inputName,
|
|
7671
|
+
type: dataTypeInfo.outputField === "texts" ? "text[]" : "file[]",
|
|
7672
|
+
description: `Input data for ${nodeType}`,
|
|
7673
|
+
required: true,
|
|
7674
|
+
nodeId: node.id
|
|
7675
|
+
});
|
|
7032
7676
|
const label = nodeData.label;
|
|
7033
7677
|
const comment = nodeData.comment;
|
|
7034
7678
|
return {
|
|
@@ -7038,7 +7682,7 @@ var WorkflowExporter = class {
|
|
|
7038
7682
|
label,
|
|
7039
7683
|
comment,
|
|
7040
7684
|
isInput,
|
|
7041
|
-
inputName: isInput ?
|
|
7685
|
+
inputName: isInput ? inputName : void 0,
|
|
7042
7686
|
staticData: hasStaticData ? {
|
|
7043
7687
|
fileKeys,
|
|
7044
7688
|
texts
|
|
@@ -7083,7 +7727,7 @@ var WorkflowExporter = class {
|
|
|
7083
7727
|
const dataTypeInfo = DATA_NODE_TYPES[outputType];
|
|
7084
7728
|
if (dataTypeInfo) {
|
|
7085
7729
|
const isInput = level === 0;
|
|
7086
|
-
const inputName =
|
|
7730
|
+
const inputName = inputNameFor(node.id, nodeData);
|
|
7087
7731
|
if (isInput) inputs.push({
|
|
7088
7732
|
name: inputName,
|
|
7089
7733
|
type: dataTypeInfo.outputField === "texts" ? "text[]" : "file[]",
|
|
@@ -7209,12 +7853,14 @@ var WorkflowExporter = class {
|
|
|
7209
7853
|
}));
|
|
7210
7854
|
const pluginId = typeof nodeData.pluginId === "string" ? nodeData.pluginId.trim() : "";
|
|
7211
7855
|
const model = typeof nodeData.pluginModel === "string" ? nodeData.pluginModel.trim() : "";
|
|
7856
|
+
const params = nodeData.pluginParams && typeof nodeData.pluginParams === "object" && !Array.isArray(nodeData.pluginParams) && Object.keys(nodeData.pluginParams).length > 0 ? { ...nodeData.pluginParams } : void 0;
|
|
7212
7857
|
return {
|
|
7213
7858
|
id: node.id,
|
|
7214
7859
|
type: nodeType,
|
|
7215
7860
|
feature: ns.abi.feature,
|
|
7216
7861
|
pluginId,
|
|
7217
7862
|
...model ? { model } : {},
|
|
7863
|
+
...params ? { params } : {},
|
|
7218
7864
|
label,
|
|
7219
7865
|
comment,
|
|
7220
7866
|
locked,
|
|
@@ -7458,4 +8104,4 @@ function coerceBaseNodeData(data) {
|
|
|
7458
8104
|
return {};
|
|
7459
8105
|
}
|
|
7460
8106
|
//#endregion
|
|
7461
|
-
export { ABI_DEFINITIONS, ABI_NODES, ADD_NODE_OUTPUT_TYPE, ADD_NODE_TYPES, COMPONENT_V_GAP, DATA_NODE_TYPES, FeatureRegistryBundleSchema, HISTORY_LIMIT, H_GAP, IMAGE_ASPECT_RATIOS, IMAGE_RESOLUTION_TIERS, KNOWN_NODE_TYPES, MEDIA_NODE_MAX_DISPLAY_WIDTH_PX, MEDIA_NODE_MIN_DISPLAY_WIDTH_PX, MEDIA_NODE_REF_DISPLAY_WIDTH_PX, MEDIA_NODE_REF_LONG_EDGE_PX, MIN_SUPPORTED_ABI_VERSION, MODALITY_NODE_TYPES, NODE_TYPE_SOURCE_SPEC, NODE_TYPE_TO_ABI_FEATURE, NodeStatus, PluginConfigSchema, PluginMethodSchema, PluginsRegistrySchema, RUNNING_STATUSES, SHORT_ID_LENGTH, TERMINAL_STATUSES, TONGFLOW_ABI_NODES, TONGFLOW_ABI_VERSION, TONGFLOW_TOOL_DEFS, TONGFLOW_TOOL_NAMES, TaskStatus, VIDEO_ASPECT_RATIOS, VIDEO_DURATIONS, VIDEO_DURATION_DEFAULT, VIDEO_DURATION_MAX, VIDEO_DURATION_MIN, V_GAP, WORKFLOW_IMPORT_NO_CANVAS, WorkflowExecutor, WorkflowExporter, WorkflowParser, WorkflowStatus, abiSpecForNodeType, addEdgeIfAbsent, applyGraphPatch, batchOn, buildFeatureRegistry, buildPrompts, bumpFocusGeneration, clampVideoDuration, closestNodeTypes, coerceBaseNodeData, collectAll, collectHandleValues, compareAbiProducerConsumerSchemas, componentsContaining, computeAutoLayout, configField, createFlowSlice, createFlowStore, currentFocusGeneration, describeNodeType, edgeShapeError, estimateNodeSize, executeGraphTool, exportWorkflow, featureForNodeType, getAbiNodeBySlot, getAbiOutputRoutesBySlot, getAbiTopology, getAllFeatures, getAspectRatioIconSize, getEdgeTargetOptions, getEffectiveOutputType, getFeatureByName, getFeatureRegistryAliases, getValueByPath, getWorkflowEndNodes, getWorkflowStartNodes, handle, hasDuplicateAddSourceEdge, hasDuplicateTargetHandle, isAbiNodeType, isKnownNodeType, isModalityNode, isRunningStatus, isTerminalStatus, isValidFlowConnection, isWorkflowValid, logger, mapSSEStatusToTaskStatus, neighborhood, nodeKind, parseExecutableWorkflow, parseSourceHandleId, parseTargetHandleId, parseWorkflow, parseWorkflowImportJson, promptMissingRequired, proportionalMediaNodeWidthPx, pushSnapshot, readCanvas, renderCanvas, resolveAbiOutputMappings, resolveCanonicalFeatureName, resolveEdgeHandles, resolveLabelLookupFeatureName, resolveNodeRef, resolveSpec, resolvedSpecForNodeType, shortId, singleEdgeTextScalarTargetHandles, snapshotFlow, sourceHandleId, sourceSpecForNodeType, staticValue, stringifyExecutableWorkflow, targetHandleId, tryAbiCompatibility, validateFeatureRegistryBundle, validateWorkflow, workflowInput };
|
|
8107
|
+
export { ABI_DEFINITIONS, ABI_NODES, ADD_NODE_OUTPUT_TYPE, ADD_NODE_TYPES, COMPONENT_V_GAP, DATA_NODE_TYPES, FeatureRegistryBundleSchema, HISTORY_LIMIT, H_GAP, IMAGE_ASPECT_RATIOS, IMAGE_RESOLUTION_TIERS, KNOWN_NODE_TYPES, MEDIA_NODE_MAX_DISPLAY_WIDTH_PX, MEDIA_NODE_MIN_DISPLAY_WIDTH_PX, MEDIA_NODE_REF_DISPLAY_WIDTH_PX, MEDIA_NODE_REF_LONG_EDGE_PX, MIN_SUPPORTED_ABI_VERSION, MODALITY_NODE_TYPES, NODE_ACTION_META, NODE_TYPE_SOURCE_SPEC, NODE_TYPE_TO_ABI_FEATURE, NodeStatus, PluginConfigSchema, PluginMethodSchema, PluginModelCatalogSchema, PluginParamSpecSchema, PluginsRegistrySchema, RUNNING_STATUSES, SHORT_ID_LENGTH, TERMINAL_STATUSES, TONGFLOW_ABI_NODES, TONGFLOW_ABI_VERSION, TONGFLOW_TOOL_DEFS, TONGFLOW_TOOL_NAMES, TaskStatus, VIDEO_ASPECT_RATIOS, VIDEO_DURATIONS, VIDEO_DURATION_DEFAULT, VIDEO_DURATION_MAX, VIDEO_DURATION_MIN, V_GAP, WORKFLOW_IMPORT_NO_CANVAS, WorkflowExecutor, WorkflowExporter, WorkflowParser, WorkflowStatus, abiSpecForNodeType, addEdgeIfAbsent, applyGraphPatch, batchOn, buildFeatureRegistry, buildPrompts, bumpFocusGeneration, clampVideoDuration, closestNodeTypes, coerceBaseNodeData, collectAll, collectHandleValues, compareAbiProducerConsumerSchemas, componentsContaining, computeAutoLayout, configField, createFlowSlice, createFlowStore, currentFocusGeneration, describeNodeType, edgeShapeError, estimateNodeSize, executeGraphTool, exportWorkflow, featureForNodeType, filterModelCatalog, getAbiNodeBySlot, getAbiOutputRoutesBySlot, getAbiTopology, getAllFeatures, getAspectRatioIconSize, getEdgeTargetOptions, getEffectiveOutputType, getFeatureByName, getFeatureRegistryAliases, getValueByPath, getWorkflowEndNodes, getWorkflowStartNodes, handle, hasDuplicateAddSourceEdge, hasDuplicateTargetHandle, inputNameFor, isAbiNodeType, isKnownNodeType, isModalityNode, isRunningStatus, isTerminalStatus, isValidFlowConnection, isValidPluginParamValue, isWorkflowValid, logger, mapSSEStatusToTaskStatus, neighborhood, nodeActionsForSelection, nodeKind, normalizePluginParams, parseExecutableWorkflow, parseSourceHandleId, parseTargetHandleId, parseWorkflow, parseWorkflowImportJson, promptMissingRequired, proportionalMediaNodeWidthPx, pushSnapshot, readCanvas, renderCanvas, resolveAbiOutputMappings, resolveCanonicalFeatureName, resolveEdgeHandles, resolveLabelLookupFeatureName, resolveNodeRef, resolveSpec, resolvedSpecForNodeType, samePluginParams, shortId, singleEdgeTextScalarTargetHandles, snapshotFlow, sourceHandleId, sourceSpecForNodeType, staticValue, stringifyExecutableWorkflow, targetHandleId, tryAbiCompatibility, validateFeatureRegistryBundle, validateWorkflow, visiblePluginParams, workflowInput };
|