@scenario-labs/sdk 2.4.0-alpha.1 → 2.5.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/CHANGELOG.md +36 -0
- package/README.md +26 -0
- package/client.d.mts +1 -1
- package/client.d.mts.map +1 -1
- package/client.d.ts +1 -1
- package/client.d.ts.map +1 -1
- package/lib/cel/environment.d.mts +38 -0
- package/lib/cel/environment.d.mts.map +1 -0
- package/lib/cel/environment.d.ts +38 -0
- package/lib/cel/environment.d.ts.map +1 -0
- package/lib/cel/environment.js +52 -0
- package/lib/cel/environment.js.map +1 -0
- package/lib/cel/environment.mjs +48 -0
- package/lib/cel/environment.mjs.map +1 -0
- package/lib/cel/functions.d.mts +4 -0
- package/lib/cel/functions.d.mts.map +1 -0
- package/lib/cel/functions.d.ts +4 -0
- package/lib/cel/functions.d.ts.map +1 -0
- package/lib/cel/functions.js +67 -0
- package/lib/cel/functions.js.map +1 -0
- package/lib/cel/functions.mjs +64 -0
- package/lib/cel/functions.mjs.map +1 -0
- package/lib/cel/index.d.mts +3 -0
- package/lib/cel/index.d.mts.map +1 -0
- package/lib/cel/index.d.ts +3 -0
- package/lib/cel/index.d.ts.map +1 -0
- package/lib/cel/index.js +9 -0
- package/lib/cel/index.js.map +1 -0
- package/lib/cel/index.mjs +3 -0
- package/lib/cel/index.mjs.map +1 -0
- package/lib/cel/prng.d.mts +28 -0
- package/lib/cel/prng.d.mts.map +1 -0
- package/lib/cel/prng.d.ts +28 -0
- package/lib/cel/prng.d.ts.map +1 -0
- package/lib/cel/prng.js +64 -0
- package/lib/cel/prng.js.map +1 -0
- package/lib/cel/prng.mjs +58 -0
- package/lib/cel/prng.mjs.map +1 -0
- package/lib/workflow_converter.d.mts +3 -0
- package/lib/workflow_converter.d.mts.map +1 -1
- package/lib/workflow_converter.d.ts +3 -0
- package/lib/workflow_converter.d.ts.map +1 -1
- package/lib/workflow_converter.js +62 -34
- package/lib/workflow_converter.js.map +1 -1
- package/lib/workflow_converter.mjs +62 -34
- package/lib/workflow_converter.mjs.map +1 -1
- package/package.json +17 -2
- package/resources/assets/assets.d.mts +269 -31
- package/resources/assets/assets.d.mts.map +1 -1
- package/resources/assets/assets.d.ts +269 -31
- package/resources/assets/assets.d.ts.map +1 -1
- package/resources/assets/assets.js.map +1 -1
- package/resources/assets/assets.mjs.map +1 -1
- package/resources/generate.d.mts +157 -51
- package/resources/generate.d.mts.map +1 -1
- package/resources/generate.d.ts +157 -51
- package/resources/generate.d.ts.map +1 -1
- package/resources/generate.js +1 -5
- package/resources/generate.js.map +1 -1
- package/resources/generate.mjs +1 -5
- package/resources/generate.mjs.map +1 -1
- package/resources/index.d.mts +1 -1
- package/resources/index.d.mts.map +1 -1
- package/resources/index.d.ts +1 -1
- package/resources/index.d.ts.map +1 -1
- package/resources/jobs.d.mts +30 -12
- package/resources/jobs.d.mts.map +1 -1
- package/resources/jobs.d.ts +30 -12
- package/resources/jobs.d.ts.map +1 -1
- package/resources/models/description.d.mts +62 -4
- package/resources/models/description.d.mts.map +1 -1
- package/resources/models/description.d.ts +62 -4
- package/resources/models/description.d.ts.map +1 -1
- package/resources/models/examples.d.mts +94 -64
- package/resources/models/examples.d.mts.map +1 -1
- package/resources/models/examples.d.ts +94 -64
- package/resources/models/examples.d.ts.map +1 -1
- package/resources/models/models.d.mts +239 -295
- package/resources/models/models.d.mts.map +1 -1
- package/resources/models/models.d.ts +239 -295
- package/resources/models/models.d.ts.map +1 -1
- package/resources/models/models.js.map +1 -1
- package/resources/models/models.mjs.map +1 -1
- package/resources/models/train.d.mts +92 -110
- package/resources/models/train.d.mts.map +1 -1
- package/resources/models/train.d.ts +92 -110
- package/resources/models/train.d.ts.map +1 -1
- package/resources/search.d.mts +2 -2
- package/resources/search.d.ts +2 -2
- package/resources/uploads.d.mts +2 -3
- package/resources/uploads.d.mts.map +1 -1
- package/resources/uploads.d.ts +2 -3
- package/resources/uploads.d.ts.map +1 -1
- package/resources/usages.d.mts +44 -15
- package/resources/usages.d.mts.map +1 -1
- package/resources/usages.d.ts +44 -15
- package/resources/usages.d.ts.map +1 -1
- package/resources/workflows.d.mts +63 -45
- package/resources/workflows.d.mts.map +1 -1
- package/resources/workflows.d.ts +63 -45
- package/resources/workflows.d.ts.map +1 -1
- package/resources/workflows.js +4 -4
- package/resources/workflows.js.map +1 -1
- package/resources/workflows.mjs +4 -4
- package/resources/workflows.mjs.map +1 -1
- package/src/client.ts +1 -1
- package/src/lib/cel/environment.ts +81 -0
- package/src/lib/cel/functions.ts +109 -0
- package/src/lib/cel/index.ts +8 -0
- package/src/lib/cel/prng.ts +62 -0
- package/src/lib/workflow_converter.ts +91 -35
- package/src/resources/assets/assets.ts +300 -62
- package/src/resources/generate.ts +157 -129
- package/src/resources/index.ts +1 -1
- package/src/resources/jobs.ts +27 -37
- package/src/resources/models/description.ts +70 -12
- package/src/resources/models/examples.ts +100 -88
- package/src/resources/models/models.ts +228 -385
- package/src/resources/models/train.ts +89 -139
- package/src/resources/search.ts +2 -2
- package/src/resources/uploads.ts +2 -3
- package/src/resources/usages.ts +47 -20
- package/src/resources/workflows.ts +48 -157
- package/src/tools/cel.ts +4 -0
- package/src/version.ts +1 -1
- package/tools/cel.d.mts +2 -0
- package/tools/cel.d.mts.map +1 -0
- package/tools/cel.d.ts +2 -0
- package/tools/cel.d.ts.map +1 -0
- package/tools/cel.js +8 -0
- package/tools/cel.js.map +1 -0
- package/tools/cel.mjs +5 -0
- package/tools/cel.mjs.map +1 -0
- package/version.d.mts +1 -1
- package/version.d.mts.map +1 -1
- package/version.d.ts +1 -1
- package/version.d.ts.map +1 -1
- package/version.js +1 -1
- package/version.js.map +1 -1
- package/version.mjs +1 -1
- package/version.mjs.map +1 -1
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { Environment } from '@marcbachmann/cel-js';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
mulberry32,
|
|
5
|
+
normalizeSeed,
|
|
6
|
+
sampleWithoutReplacement,
|
|
7
|
+
sampleWithReplacement,
|
|
8
|
+
type RandomSource,
|
|
9
|
+
} from './prng';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Random integer with exactly `digits` digits, e.g. random(5) -> 48574.
|
|
13
|
+
* Ported verbatim from the backend's cel_evaluator for back-compat with
|
|
14
|
+
* deployed workflows. Float precision degrades above 15 digits.
|
|
15
|
+
*/
|
|
16
|
+
function randomDigits(digits: bigint | number): bigint {
|
|
17
|
+
const d = Number(digits);
|
|
18
|
+
if (d <= 0) return 0n;
|
|
19
|
+
const min = 10 ** (d - 1);
|
|
20
|
+
const max = 10 ** d;
|
|
21
|
+
return BigInt(Math.floor(Math.random() * (max - min)) + min);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function randomSampleImpl(
|
|
25
|
+
list: unknown,
|
|
26
|
+
count: bigint | number,
|
|
27
|
+
seed: bigint | number | undefined,
|
|
28
|
+
withReplacement: boolean,
|
|
29
|
+
): unknown[] {
|
|
30
|
+
if (!Array.isArray(list)) return [];
|
|
31
|
+
const rand: RandomSource = seed === undefined ? Math.random : mulberry32(normalizeSeed(seed));
|
|
32
|
+
const k = Number(count);
|
|
33
|
+
return withReplacement ? sampleWithReplacement(list, k, rand) : sampleWithoutReplacement(list, k, rand);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const RANDOM_SAMPLE_DESCRIPTION =
|
|
37
|
+
'Sample items from a list. An int seed makes the result reproducible (same seed, same sample); ' +
|
|
38
|
+
'withReplacement allows duplicates. Without replacement, count is clamped to the list size.';
|
|
39
|
+
|
|
40
|
+
const PARAM_LIST = { name: 'list', description: 'List to sample from' };
|
|
41
|
+
const PARAM_COUNT = { name: 'count', description: 'Number of items to sample' };
|
|
42
|
+
const PARAM_SEED = { name: 'seed', description: 'Seed for reproducible sampling' };
|
|
43
|
+
const PARAM_WITH_REPLACEMENT = { name: 'withReplacement', description: 'Allow duplicate picks' };
|
|
44
|
+
|
|
45
|
+
/** Register the shared base functions. Order and semantics are stable API. */
|
|
46
|
+
export function registerBaseFunctions(env: Environment): Environment {
|
|
47
|
+
// Registered as dyn so cel-js doesn't reject null before reaching the handler.
|
|
48
|
+
env.registerFunction('trim(dyn): string', (s: string) => (s == null ? '' : String(s).trim()), {
|
|
49
|
+
description: 'Trim leading and trailing whitespace. Null-safe: null becomes "".',
|
|
50
|
+
params: [{ name: 'value', description: 'Value to trim; null yields ""' }],
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Registered as dyn first arg so cel-js doesn't reject non-list inputs before the handler.
|
|
54
|
+
env.registerFunction(
|
|
55
|
+
'slice(dyn, int, int): list',
|
|
56
|
+
(arr: unknown, start: bigint | number, end: bigint | number) => {
|
|
57
|
+
if (!Array.isArray(arr)) return [];
|
|
58
|
+
return arr.slice(Number(start), Number(end));
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
description: 'Return list[start:end] with JS Array.prototype.slice semantics.',
|
|
62
|
+
params: [
|
|
63
|
+
{ name: 'list', description: 'List to slice' },
|
|
64
|
+
{ name: 'start', description: 'Start index (inclusive)' },
|
|
65
|
+
{ name: 'end', description: 'End index (exclusive)' },
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
env.registerFunction('random(int): int', (digits: bigint | number) => randomDigits(digits), {
|
|
71
|
+
description: 'Random integer with exactly N digits, e.g. random(5) -> 48574. Unseeded.',
|
|
72
|
+
params: [{ name: 'digits', description: 'Number of digits in the result' }],
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
env.registerFunction(
|
|
76
|
+
'randomSample(list, int): list',
|
|
77
|
+
(list: unknown, count: bigint | number) => randomSampleImpl(list, count, undefined, false),
|
|
78
|
+
{ description: RANDOM_SAMPLE_DESCRIPTION, params: [PARAM_LIST, PARAM_COUNT] },
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
env.registerFunction(
|
|
82
|
+
'randomSample(list, int, int): list',
|
|
83
|
+
(list: unknown, count: bigint | number, seed: bigint | number) =>
|
|
84
|
+
randomSampleImpl(list, count, seed, false),
|
|
85
|
+
{ description: RANDOM_SAMPLE_DESCRIPTION, params: [PARAM_LIST, PARAM_COUNT, PARAM_SEED] },
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
env.registerFunction(
|
|
89
|
+
'randomSample(list, int, bool): list',
|
|
90
|
+
(list: unknown, count: bigint | number, withReplacement: boolean) =>
|
|
91
|
+
randomSampleImpl(list, count, undefined, withReplacement),
|
|
92
|
+
{
|
|
93
|
+
description: RANDOM_SAMPLE_DESCRIPTION,
|
|
94
|
+
params: [PARAM_LIST, PARAM_COUNT, PARAM_WITH_REPLACEMENT],
|
|
95
|
+
},
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
env.registerFunction(
|
|
99
|
+
'randomSample(list, int, int, bool): list',
|
|
100
|
+
(list: unknown, count: bigint | number, seed: bigint | number, withReplacement: boolean) =>
|
|
101
|
+
randomSampleImpl(list, count, seed, withReplacement),
|
|
102
|
+
{
|
|
103
|
+
description: RANDOM_SAMPLE_DESCRIPTION,
|
|
104
|
+
params: [PARAM_LIST, PARAM_COUNT, PARAM_SEED, PARAM_WITH_REPLACEMENT],
|
|
105
|
+
},
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
return env;
|
|
109
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic PRNG + sampling primitives backing the CEL `randomSample`
|
|
3
|
+
* function.
|
|
4
|
+
*
|
|
5
|
+
* STABILITY CONTRACT — DO NOT CHANGE THESE ALGORITHMS.
|
|
6
|
+
* The same seed must produce the same sample on every runtime and every SDK
|
|
7
|
+
* version: the backend (server) and frontend (client) rely on agreeing outputs,
|
|
8
|
+
* and customers rely on seeds for reproducible workflow runs. Golden-value
|
|
9
|
+
* tests in tests/lib/cel/prng.test.ts pin the exact outputs.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** A source of random floats in [0, 1). */
|
|
13
|
+
export type RandomSource = () => number;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* mulberry32: fast 32-bit PRNG with exact, platform-independent output.
|
|
17
|
+
* `seed` is coerced to uint32 (via `>>> 0`); use {@link normalizeSeed} to
|
|
18
|
+
* convert arbitrary CEL ints before calling this.
|
|
19
|
+
*/
|
|
20
|
+
export function mulberry32(seed: number): RandomSource {
|
|
21
|
+
let a = seed >>> 0;
|
|
22
|
+
return () => {
|
|
23
|
+
a = (a + 0x6d2b79f5) | 0;
|
|
24
|
+
let t = Math.imul(a ^ (a >>> 15), 1 | a);
|
|
25
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
26
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Normalize a CEL int (bigint or number) to a uint32 PRNG seed. */
|
|
31
|
+
export function normalizeSeed(seed: bigint | number): number {
|
|
32
|
+
return Number(BigInt.asUintN(32, BigInt(seed)));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Sample `count` distinct elements via partial Fisher–Yates.
|
|
37
|
+
* `count` is clamped to [0, list.length]; the input list is not mutated.
|
|
38
|
+
*/
|
|
39
|
+
export function sampleWithoutReplacement<T>(list: readonly T[], count: number, rand: RandomSource): T[] {
|
|
40
|
+
const n = list.length;
|
|
41
|
+
const k = Math.min(Math.max(count, 0), n);
|
|
42
|
+
if (k === 0) return [];
|
|
43
|
+
const pool = list.slice();
|
|
44
|
+
for (let i = 0; i < k; i++) {
|
|
45
|
+
const j = i + Math.floor(rand() * (n - i));
|
|
46
|
+
const tmp = pool[i]!;
|
|
47
|
+
pool[i] = pool[j]!;
|
|
48
|
+
pool[j] = tmp;
|
|
49
|
+
}
|
|
50
|
+
return pool.slice(0, k);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** `count` independent draws; duplicates allowed. Returns [] if the list is empty or count <= 0. */
|
|
54
|
+
export function sampleWithReplacement<T>(list: readonly T[], count: number, rand: RandomSource): T[] {
|
|
55
|
+
const n = list.length;
|
|
56
|
+
if (n === 0 || count <= 0) return [];
|
|
57
|
+
const out: T[] = [];
|
|
58
|
+
for (let i = 0; i < count; i++) {
|
|
59
|
+
out.push(list[Math.floor(rand() * n)]!);
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
@@ -52,7 +52,13 @@ export type WorkflowEditorNode =
|
|
|
52
52
|
| {
|
|
53
53
|
id: string;
|
|
54
54
|
type: 'sliceAssets';
|
|
55
|
-
data: NodeCommonData & {
|
|
55
|
+
data: NodeCommonData & {
|
|
56
|
+
from?: number | string;
|
|
57
|
+
count?: number | string;
|
|
58
|
+
isRandomize?: boolean;
|
|
59
|
+
randomSeed?: string;
|
|
60
|
+
value?: string;
|
|
61
|
+
};
|
|
56
62
|
}
|
|
57
63
|
| { id: string; type: 'forEach'; data: NodeCommonData }
|
|
58
64
|
| { id: string; type: 'forEachEnd'; data: NodeCommonData & { parentNodeId?: string } }
|
|
@@ -561,6 +567,50 @@ function getOutputHandleVarName(targetNodeId: string, handleName: string): strin
|
|
|
561
567
|
return ['output', 'allOutputs'].includes(handleName) ? targetNodeId : `${targetNodeId}_${handleName}`;
|
|
562
568
|
}
|
|
563
569
|
|
|
570
|
+
function getIsSliceAssetsItemsSourceHandle(nodeId: string, sourceHandle: string | null | undefined): boolean {
|
|
571
|
+
return sourceHandle === `${nodeId}-source-items` || sourceHandle === `${nodeId}-source-assets`;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Builds the concat variables and flow inputs for a list-concatenating node
|
|
576
|
+
* (groupItems, sliceAssets in randomize mode) from its incoming edges.
|
|
577
|
+
* `getVarName` maps a target node id + output handle name to the variable name,
|
|
578
|
+
* which differs between callers.
|
|
579
|
+
*/
|
|
580
|
+
function collectConcatVarsAndInputs(
|
|
581
|
+
edges: WorkflowEditorEdge[],
|
|
582
|
+
ctx: SourceRefContext,
|
|
583
|
+
getVarName: (targetNodeId: string, handleName: string) => string,
|
|
584
|
+
): { variables: ConcatVariable[]; flowInputs: WorkflowEditorFlowInput[] } {
|
|
585
|
+
const { nodes, inputNodeIds } = ctx;
|
|
586
|
+
const variables: ConcatVariable[] = [];
|
|
587
|
+
const flowInputs: WorkflowEditorFlowInput[] = [];
|
|
588
|
+
|
|
589
|
+
for (const edge of edges) {
|
|
590
|
+
const targetNode = nodes.find((n) => n.id === edge.target);
|
|
591
|
+
if (!targetNode) continue;
|
|
592
|
+
const ref = getSourceRef(edge, ctx);
|
|
593
|
+
if (!ref) continue;
|
|
594
|
+
const outHandle = targetNode.data.outputHandles?.find((h) => h.id === edge.targetHandle);
|
|
595
|
+
const outHandleName = outHandle?.name ?? 'output';
|
|
596
|
+
const varName = getVarName(targetNode.id, outHandleName);
|
|
597
|
+
const isArr =
|
|
598
|
+
(targetNode.type === 'asset' && !!(targetNode.data as { isMultiple?: boolean }).isMultiple) ||
|
|
599
|
+
targetNode.type === 'groupItems' ||
|
|
600
|
+
targetNode.type === 'sliceAssets' ||
|
|
601
|
+
outHandleName === 'allOutputs';
|
|
602
|
+
const isRequired =
|
|
603
|
+
inputNodeIds.includes(targetNode.id) ?
|
|
604
|
+
(targetNode.type === 'asset' && !!(targetNode.data as { isRequired?: boolean }).isRequired) ||
|
|
605
|
+
['firstFrame', 'lastFrame'].includes(outHandleName)
|
|
606
|
+
: true;
|
|
607
|
+
variables.push({ name: varName, isArray: isArr, isRequired });
|
|
608
|
+
flowInputs.push({ name: varName, type: isArr ? 'file_array' : 'file', ref });
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
return { variables, flowInputs };
|
|
612
|
+
}
|
|
613
|
+
|
|
564
614
|
function setOrPushFlowInput(
|
|
565
615
|
flowInputs: WorkflowEditorFlowInput[],
|
|
566
616
|
existingIndex: number,
|
|
@@ -1522,32 +1572,12 @@ export function convertWorkflowEditorToFlow(
|
|
|
1522
1572
|
// GroupItems -> array concatenation
|
|
1523
1573
|
// ------------------------------------
|
|
1524
1574
|
} else if (node.type === 'groupItems') {
|
|
1525
|
-
const flowInputs: WorkflowEditorFlowInput[] = [];
|
|
1526
|
-
const variables: ConcatVariable[] = [];
|
|
1527
1575
|
const conditionalHandleId = getConditionalInputHandleId(node.id);
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
const ref = getSourceRef(edge, ctx);
|
|
1534
|
-
if (!ref) continue;
|
|
1535
|
-
const outHandle = targetNode.data.outputHandles?.find((h) => h.id === edge.targetHandle);
|
|
1536
|
-
const outHandleName = outHandle?.name ?? 'output';
|
|
1537
|
-
const varName = `${targetNode.id}_${outHandleName}`;
|
|
1538
|
-
const isArr =
|
|
1539
|
-
(targetNode.type === 'asset' && !!(targetNode.data as { isMultiple?: boolean }).isMultiple) ||
|
|
1540
|
-
targetNode.type === 'groupItems' ||
|
|
1541
|
-
targetNode.type === 'sliceAssets' ||
|
|
1542
|
-
outHandleName === 'allOutputs';
|
|
1543
|
-
const isRequired =
|
|
1544
|
-
inputNodeIds.includes(targetNode.id) ?
|
|
1545
|
-
(targetNode.type === 'asset' && !!(targetNode.data as { isRequired?: boolean }).isRequired) ||
|
|
1546
|
-
['firstFrame', 'lastFrame'].includes(outHandleName)
|
|
1547
|
-
: true;
|
|
1548
|
-
variables.push({ name: varName, isArray: isArr, isRequired });
|
|
1549
|
-
flowInputs.push({ name: varName, type: isArr ? 'file_array' : 'file', ref });
|
|
1550
|
-
}
|
|
1576
|
+
const { variables, flowInputs } = collectConcatVarsAndInputs(
|
|
1577
|
+
incomingEdges.filter((e) => e.sourceHandle !== conditionalHandleId),
|
|
1578
|
+
ctx,
|
|
1579
|
+
(targetNodeId, handleName) => `${targetNodeId}_${handleName}`,
|
|
1580
|
+
);
|
|
1551
1581
|
|
|
1552
1582
|
const orderedValues = convertValueToList((node.data as { value?: string }).value ?? '');
|
|
1553
1583
|
variables.sort((a, b) => orderedValues.indexOf(a.name) - orderedValues.indexOf(b.name));
|
|
@@ -1561,20 +1591,46 @@ export function convertWorkflowEditorToFlow(
|
|
|
1561
1591
|
});
|
|
1562
1592
|
|
|
1563
1593
|
// ------------------------------------
|
|
1564
|
-
// SliceAssets -> slice(list, from, from+count)
|
|
1594
|
+
// SliceAssets -> slice(list, from, from+count) or randomSample(list, count, seed)
|
|
1565
1595
|
// ------------------------------------
|
|
1566
1596
|
} else if (node.type === 'sliceAssets') {
|
|
1567
|
-
const
|
|
1568
|
-
|
|
1569
|
-
|
|
1597
|
+
const sliceData = node.data as {
|
|
1598
|
+
from?: number | string;
|
|
1599
|
+
count?: number | string;
|
|
1600
|
+
isRandomize?: boolean;
|
|
1601
|
+
randomSeed?: string;
|
|
1602
|
+
};
|
|
1603
|
+
const conditionalHandleId = getConditionalInputHandleId(node.id);
|
|
1604
|
+
const itemsEdges = incomingEdges.filter(
|
|
1605
|
+
(e) =>
|
|
1606
|
+
e.sourceHandle !== conditionalHandleId &&
|
|
1607
|
+
getIsSliceAssetsItemsSourceHandle(node.id, e.sourceHandle),
|
|
1608
|
+
);
|
|
1609
|
+
|
|
1610
|
+
if (sliceData.isRandomize) {
|
|
1611
|
+
const { variables, flowInputs } = collectConcatVarsAndInputs(itemsEdges, ctx, getOutputHandleVarName);
|
|
1612
|
+
flowInputs.push(...collectConditionalConnectionInputs(incomingEdges, node.id, ctx));
|
|
1613
|
+
|
|
1614
|
+
const count = Math.max(1, parseInt(String(sliceData.count ?? ''), 10) || 1);
|
|
1615
|
+
const seed = parseInt(String(sliceData.randomSeed ?? ''), 10) || 0;
|
|
1616
|
+
const transform = `randomSample(${buildConcatArrayTransform(variables)}, ${count}, ${seed})`;
|
|
1617
|
+
|
|
1618
|
+
flow.push({
|
|
1619
|
+
id: flowId,
|
|
1620
|
+
type: 'transform',
|
|
1621
|
+
logic: { transform },
|
|
1622
|
+
inputs: flowInputs.length > 0 ? flowInputs : undefined,
|
|
1623
|
+
});
|
|
1570
1624
|
} else {
|
|
1571
|
-
const
|
|
1572
|
-
if (
|
|
1573
|
-
|
|
1574
|
-
|
|
1625
|
+
const assetsEdge = itemsEdges[0];
|
|
1626
|
+
if (!assetsEdge) {
|
|
1627
|
+
flow.push({ id: flowId, type: 'transform', logic: { transform: '[]' } });
|
|
1628
|
+
} else {
|
|
1629
|
+
const targetNode = nodes.find((n) => n.id === assetsEdge.target);
|
|
1630
|
+
const ref = targetNode ? getSourceRef(assetsEdge, ctx) : undefined;
|
|
1631
|
+
if (targetNode && ref) {
|
|
1575
1632
|
const outHandle = targetNode.data.outputHandles?.find((h) => h.id === assetsEdge.targetHandle);
|
|
1576
1633
|
const varName = getOutputHandleVarName(targetNode.id, outHandle?.name ?? 'output');
|
|
1577
|
-
const sliceData = node.data as { from?: number | string; count?: number | string };
|
|
1578
1634
|
const from = parseInt(String(sliceData.from ?? ''), 10) || 0;
|
|
1579
1635
|
const count = parseInt(String(sliceData.count ?? ''), 10) || 0;
|
|
1580
1636
|
const transform =
|