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