@workglow/task-graph 0.0.85 → 0.0.86
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 +1 -53
- package/dist/browser.js +281 -273
- package/dist/browser.js.map +19 -20
- package/dist/bun.js +281 -273
- package/dist/bun.js.map +19 -20
- package/dist/common.d.ts +1 -16
- package/dist/common.d.ts.map +1 -1
- package/dist/node.js +281 -273
- package/dist/node.js.map +19 -20
- package/dist/storage/TaskGraphTabularRepository.d.ts +2 -2
- package/dist/storage/TaskGraphTabularRepository.d.ts.map +1 -1
- package/dist/storage/TaskOutputTabularRepository.d.ts +2 -2
- package/dist/storage/TaskOutputTabularRepository.d.ts.map +1 -1
- package/dist/task/ConditionalTask.d.ts +1 -0
- package/dist/task/ConditionalTask.d.ts.map +1 -1
- package/dist/task/GraphAsTask.d.ts +2 -0
- package/dist/task/GraphAsTask.d.ts.map +1 -1
- package/dist/task/GraphAsTaskRunner.d.ts +0 -1
- package/dist/task/GraphAsTaskRunner.d.ts.map +1 -1
- package/dist/task/ITask.d.ts +5 -6
- package/dist/task/ITask.d.ts.map +1 -1
- package/dist/task/InputResolver.d.ts +34 -0
- package/dist/task/InputResolver.d.ts.map +1 -0
- package/dist/task/JobQueueTask.d.ts +3 -3
- package/dist/task/JobQueueTask.d.ts.map +1 -1
- package/dist/task/Task.d.ts +22 -11
- package/dist/task/Task.d.ts.map +1 -1
- package/dist/task/TaskEvents.d.ts +1 -1
- package/dist/task/TaskEvents.d.ts.map +1 -1
- package/dist/task/TaskJSON.d.ts +1 -4
- package/dist/task/TaskJSON.d.ts.map +1 -1
- package/dist/task/TaskRunner.d.ts +6 -5
- package/dist/task/TaskRunner.d.ts.map +1 -1
- package/dist/task/TaskTypes.d.ts +0 -4
- package/dist/task/TaskTypes.d.ts.map +1 -1
- package/dist/task/index.d.ts +23 -0
- package/dist/task/index.d.ts.map +1 -0
- package/dist/task-graph/Dataflow.d.ts +2 -3
- package/dist/task-graph/Dataflow.d.ts.map +1 -1
- package/dist/task-graph/ITaskGraph.d.ts +1 -1
- package/dist/task-graph/ITaskGraph.d.ts.map +1 -1
- package/dist/task-graph/TaskGraph.d.ts +4 -4
- package/dist/task-graph/TaskGraph.d.ts.map +1 -1
- package/dist/task-graph/TaskGraphRunner.d.ts +11 -18
- package/dist/task-graph/TaskGraphRunner.d.ts.map +1 -1
- package/dist/task-graph/Workflow.d.ts +1 -1
- package/dist/task-graph/Workflow.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/storage/README.md +1 -1
- package/src/task/README.md +91 -15
- package/src/task-graph/README.md +0 -2
- package/dist/task/ArrayTask.d.ts +0 -77
- package/dist/task/ArrayTask.d.ts.map +0 -1
- package/dist/task/InputTask.d.ts +0 -27
- package/dist/task/InputTask.d.ts.map +0 -1
- package/dist/task/OutputTask.d.ts +0 -27
- package/dist/task/OutputTask.d.ts.map +0 -1
package/dist/browser.js
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
// src/task/ArrayTask.ts
|
|
2
|
-
import { uuid4 as uuid44 } from "@workglow/util";
|
|
3
|
-
|
|
4
|
-
// src/task-graph/TaskGraph.ts
|
|
5
|
-
import { DirectedAcyclicGraph, EventEmitter as EventEmitter5, uuid4 as uuid43 } from "@workglow/util";
|
|
6
|
-
|
|
7
|
-
// src/task/GraphAsTask.ts
|
|
8
|
-
import { compileSchema as compileSchema2 } from "@workglow/util";
|
|
9
|
-
|
|
10
1
|
// src/task-graph/Dataflow.ts
|
|
11
2
|
import { areSemanticallyCompatible, EventEmitter } from "@workglow/util";
|
|
12
3
|
|
|
@@ -42,14 +33,12 @@ class Dataflow {
|
|
|
42
33
|
return Dataflow.createId(this.sourceTaskId, this.sourceTaskPortId, this.targetTaskId, this.targetTaskPortId);
|
|
43
34
|
}
|
|
44
35
|
value = undefined;
|
|
45
|
-
provenance = {};
|
|
46
36
|
status = TaskStatus.PENDING;
|
|
47
37
|
error;
|
|
48
38
|
reset() {
|
|
49
39
|
this.status = TaskStatus.PENDING;
|
|
50
40
|
this.error = undefined;
|
|
51
41
|
this.value = undefined;
|
|
52
|
-
this.provenance = {};
|
|
53
42
|
this.emit("reset");
|
|
54
43
|
this.emit("status", this.status);
|
|
55
44
|
}
|
|
@@ -79,7 +68,7 @@ class Dataflow {
|
|
|
79
68
|
}
|
|
80
69
|
this.emit("status", this.status);
|
|
81
70
|
}
|
|
82
|
-
setPortData(entireDataBlock
|
|
71
|
+
setPortData(entireDataBlock) {
|
|
83
72
|
if (this.sourceTaskPortId === DATAFLOW_ALL_PORTS) {
|
|
84
73
|
this.value = entireDataBlock;
|
|
85
74
|
} else if (this.sourceTaskPortId === DATAFLOW_ERROR_PORT) {
|
|
@@ -87,8 +76,6 @@ class Dataflow {
|
|
|
87
76
|
} else {
|
|
88
77
|
this.value = entireDataBlock[this.sourceTaskPortId];
|
|
89
78
|
}
|
|
90
|
-
if (nodeProvenance)
|
|
91
|
-
this.provenance = nodeProvenance;
|
|
92
79
|
}
|
|
93
80
|
getPortData() {
|
|
94
81
|
if (this.targetTaskPortId === DATAFLOW_ALL_PORTS) {
|
|
@@ -171,11 +158,17 @@ class DataflowArrow extends Dataflow {
|
|
|
171
158
|
super(sourceTaskId, sourceTaskPortId, targetTaskId, targetTaskPortId);
|
|
172
159
|
}
|
|
173
160
|
}
|
|
161
|
+
// src/task-graph/TaskGraph.ts
|
|
162
|
+
import { DirectedAcyclicGraph, EventEmitter as EventEmitter5, uuid4 as uuid43 } from "@workglow/util";
|
|
163
|
+
|
|
164
|
+
// src/task/GraphAsTask.ts
|
|
165
|
+
import { compileSchema as compileSchema2 } from "@workglow/util";
|
|
174
166
|
|
|
175
167
|
// src/task-graph/TaskGraphRunner.ts
|
|
176
168
|
import {
|
|
177
169
|
collectPropertyValues,
|
|
178
170
|
globalServiceRegistry as globalServiceRegistry2,
|
|
171
|
+
ServiceRegistry as ServiceRegistry2,
|
|
179
172
|
uuid4 as uuid42
|
|
180
173
|
} from "@workglow/util";
|
|
181
174
|
|
|
@@ -280,13 +273,69 @@ class TaskInvalidInputError extends TaskError {
|
|
|
280
273
|
|
|
281
274
|
// src/task/TaskRunner.ts
|
|
282
275
|
import { globalServiceRegistry } from "@workglow/util";
|
|
276
|
+
|
|
277
|
+
// src/task/InputResolver.ts
|
|
278
|
+
import { getInputResolvers } from "@workglow/util";
|
|
279
|
+
function getSchemaFormat(schema) {
|
|
280
|
+
if (typeof schema !== "object" || schema === null)
|
|
281
|
+
return;
|
|
282
|
+
const s = schema;
|
|
283
|
+
if (typeof s.format === "string")
|
|
284
|
+
return s.format;
|
|
285
|
+
const variants = s.oneOf ?? s.anyOf;
|
|
286
|
+
if (Array.isArray(variants)) {
|
|
287
|
+
for (const variant of variants) {
|
|
288
|
+
if (typeof variant === "object" && variant !== null) {
|
|
289
|
+
const v = variant;
|
|
290
|
+
if (typeof v.format === "string")
|
|
291
|
+
return v.format;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
function getFormatPrefix(format) {
|
|
298
|
+
const colonIndex = format.indexOf(":");
|
|
299
|
+
return colonIndex >= 0 ? format.substring(0, colonIndex) : format;
|
|
300
|
+
}
|
|
301
|
+
async function resolveSchemaInputs(input, schema, config) {
|
|
302
|
+
if (typeof schema === "boolean")
|
|
303
|
+
return input;
|
|
304
|
+
const properties = schema.properties;
|
|
305
|
+
if (!properties || typeof properties !== "object")
|
|
306
|
+
return input;
|
|
307
|
+
const resolvers = getInputResolvers();
|
|
308
|
+
const resolved = { ...input };
|
|
309
|
+
for (const [key, propSchema] of Object.entries(properties)) {
|
|
310
|
+
const value = resolved[key];
|
|
311
|
+
const format = getSchemaFormat(propSchema);
|
|
312
|
+
if (!format)
|
|
313
|
+
continue;
|
|
314
|
+
let resolver = resolvers.get(format);
|
|
315
|
+
if (!resolver) {
|
|
316
|
+
const prefix = getFormatPrefix(format);
|
|
317
|
+
resolver = resolvers.get(prefix);
|
|
318
|
+
}
|
|
319
|
+
if (!resolver)
|
|
320
|
+
continue;
|
|
321
|
+
if (typeof value === "string") {
|
|
322
|
+
resolved[key] = await resolver(value, format, config.registry);
|
|
323
|
+
} else if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
|
|
324
|
+
const results = await Promise.all(value.map((item) => resolver(item, format, config.registry)));
|
|
325
|
+
resolved[key] = results.filter((result) => result !== undefined);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return resolved;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// src/task/TaskRunner.ts
|
|
283
332
|
class TaskRunner {
|
|
284
333
|
running = false;
|
|
285
334
|
reactiveRunning = false;
|
|
286
|
-
nodeProvenance = {};
|
|
287
335
|
task;
|
|
288
336
|
abortController;
|
|
289
337
|
outputCache;
|
|
338
|
+
registry = globalServiceRegistry;
|
|
290
339
|
constructor(task) {
|
|
291
340
|
this.task = task;
|
|
292
341
|
this.own = this.own.bind(this);
|
|
@@ -296,6 +345,8 @@ class TaskRunner {
|
|
|
296
345
|
await this.handleStart(config);
|
|
297
346
|
try {
|
|
298
347
|
this.task.setInput(overrides);
|
|
348
|
+
const schema = this.task.constructor.inputSchema();
|
|
349
|
+
this.task.runInputData = await resolveSchemaInputs(this.task.runInputData, schema, { registry: this.registry });
|
|
299
350
|
const isValid = await this.task.validateInput(this.task.runInputData);
|
|
300
351
|
if (!isValid) {
|
|
301
352
|
throw new TaskInvalidInputError("Invalid input data");
|
|
@@ -331,6 +382,8 @@ class TaskRunner {
|
|
|
331
382
|
return this.task.runOutputData;
|
|
332
383
|
}
|
|
333
384
|
this.task.setInput(overrides);
|
|
385
|
+
const schema = this.task.constructor.inputSchema();
|
|
386
|
+
this.task.runInputData = await resolveSchemaInputs(this.task.runInputData, schema, { registry: this.registry });
|
|
334
387
|
await this.handleStartReactive();
|
|
335
388
|
try {
|
|
336
389
|
const isValid = await this.task.validateInput(this.task.runInputData);
|
|
@@ -361,8 +414,8 @@ class TaskRunner {
|
|
|
361
414
|
const result = await this.task.execute(input, {
|
|
362
415
|
signal: this.abortController.signal,
|
|
363
416
|
updateProgress: this.handleProgress.bind(this),
|
|
364
|
-
|
|
365
|
-
|
|
417
|
+
own: this.own,
|
|
418
|
+
registry: this.registry
|
|
366
419
|
});
|
|
367
420
|
return await this.executeTaskReactive(input, result || {});
|
|
368
421
|
}
|
|
@@ -373,7 +426,6 @@ class TaskRunner {
|
|
|
373
426
|
async handleStart(config = {}) {
|
|
374
427
|
if (this.task.status === TaskStatus.PROCESSING)
|
|
375
428
|
return;
|
|
376
|
-
this.nodeProvenance = {};
|
|
377
429
|
this.running = true;
|
|
378
430
|
this.task.startedAt = new Date;
|
|
379
431
|
this.task.progress = 0;
|
|
@@ -382,7 +434,6 @@ class TaskRunner {
|
|
|
382
434
|
this.abortController.signal.addEventListener("abort", () => {
|
|
383
435
|
this.handleAbort();
|
|
384
436
|
});
|
|
385
|
-
this.nodeProvenance = config.nodeProvenance ?? {};
|
|
386
437
|
const cache = this.task.config.outputCache ?? config.outputCache;
|
|
387
438
|
if (cache === true) {
|
|
388
439
|
let instance = globalServiceRegistry.get(TASK_OUTPUT_REPOSITORY);
|
|
@@ -395,6 +446,9 @@ class TaskRunner {
|
|
|
395
446
|
if (config.updateProgress) {
|
|
396
447
|
this.updateProgress = config.updateProgress;
|
|
397
448
|
}
|
|
449
|
+
if (config.registry) {
|
|
450
|
+
this.registry = config.registry;
|
|
451
|
+
}
|
|
398
452
|
this.task.emit("start");
|
|
399
453
|
this.task.emit("status", this.task.status);
|
|
400
454
|
}
|
|
@@ -421,7 +475,6 @@ class TaskRunner {
|
|
|
421
475
|
this.task.progress = 100;
|
|
422
476
|
this.task.status = TaskStatus.COMPLETED;
|
|
423
477
|
this.abortController = undefined;
|
|
424
|
-
this.nodeProvenance = {};
|
|
425
478
|
this.task.emit("complete");
|
|
426
479
|
this.task.emit("status", this.task.status);
|
|
427
480
|
}
|
|
@@ -435,7 +488,6 @@ class TaskRunner {
|
|
|
435
488
|
this.task.progress = 100;
|
|
436
489
|
this.task.completedAt = new Date;
|
|
437
490
|
this.abortController = undefined;
|
|
438
|
-
this.nodeProvenance = {};
|
|
439
491
|
this.task.emit("disabled");
|
|
440
492
|
this.task.emit("status", this.task.status);
|
|
441
493
|
}
|
|
@@ -455,7 +507,6 @@ class TaskRunner {
|
|
|
455
507
|
this.task.status = TaskStatus.FAILED;
|
|
456
508
|
this.task.error = err instanceof TaskError ? err : new TaskFailedError(err?.message || "Task failed");
|
|
457
509
|
this.abortController = undefined;
|
|
458
|
-
this.nodeProvenance = {};
|
|
459
510
|
this.task.emit("error", this.task.error);
|
|
460
511
|
this.task.emit("status", this.task.status);
|
|
461
512
|
}
|
|
@@ -553,7 +604,6 @@ class Task {
|
|
|
553
604
|
return this._events;
|
|
554
605
|
}
|
|
555
606
|
_events;
|
|
556
|
-
nodeProvenance = {};
|
|
557
607
|
constructor(callerDefaultInputs = {}, config = {}) {
|
|
558
608
|
const inputDefaults = this.getDefaultInputsFromStaticInputDefinitions();
|
|
559
609
|
const mergedDefaults = Object.assign(inputDefaults, callerDefaultInputs);
|
|
@@ -590,10 +640,45 @@ class Task {
|
|
|
590
640
|
}
|
|
591
641
|
}
|
|
592
642
|
resetInputData() {
|
|
643
|
+
this.runInputData = this.smartClone(this.defaults);
|
|
644
|
+
}
|
|
645
|
+
smartClone(obj, visited = new WeakSet) {
|
|
646
|
+
if (obj === null || obj === undefined) {
|
|
647
|
+
return obj;
|
|
648
|
+
}
|
|
649
|
+
if (typeof obj !== "object") {
|
|
650
|
+
return obj;
|
|
651
|
+
}
|
|
652
|
+
if (visited.has(obj)) {
|
|
653
|
+
throw new Error("Circular reference detected in input data. " + "Cannot clone objects with circular references.");
|
|
654
|
+
}
|
|
655
|
+
if (ArrayBuffer.isView(obj)) {
|
|
656
|
+
if (typeof DataView !== "undefined" && obj instanceof DataView) {
|
|
657
|
+
return obj;
|
|
658
|
+
}
|
|
659
|
+
const typedArray = obj;
|
|
660
|
+
return new typedArray.constructor(typedArray);
|
|
661
|
+
}
|
|
662
|
+
if (!Array.isArray(obj)) {
|
|
663
|
+
const proto = Object.getPrototypeOf(obj);
|
|
664
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
665
|
+
return obj;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
visited.add(obj);
|
|
593
669
|
try {
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
670
|
+
if (Array.isArray(obj)) {
|
|
671
|
+
return obj.map((item) => this.smartClone(item, visited));
|
|
672
|
+
}
|
|
673
|
+
const result = {};
|
|
674
|
+
for (const key in obj) {
|
|
675
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
676
|
+
result[key] = this.smartClone(obj[key], visited);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
return result;
|
|
680
|
+
} finally {
|
|
681
|
+
visited.delete(obj);
|
|
597
682
|
}
|
|
598
683
|
}
|
|
599
684
|
setDefaults(defaults) {
|
|
@@ -621,7 +706,7 @@ class Task {
|
|
|
621
706
|
}
|
|
622
707
|
if (schema.additionalProperties === true) {
|
|
623
708
|
for (const [inputId, value] of Object.entries(input)) {
|
|
624
|
-
if (
|
|
709
|
+
if (!(inputId in properties)) {
|
|
625
710
|
this.runInputData[inputId] = value;
|
|
626
711
|
}
|
|
627
712
|
}
|
|
@@ -674,7 +759,7 @@ class Task {
|
|
|
674
759
|
}
|
|
675
760
|
if (inputSchema.additionalProperties === true) {
|
|
676
761
|
for (const [inputId, value] of Object.entries(overrides)) {
|
|
677
|
-
if (
|
|
762
|
+
if (!(inputId in properties)) {
|
|
678
763
|
if (!deepEqual(this.runInputData[inputId], value)) {
|
|
679
764
|
this.runInputData[inputId] = value;
|
|
680
765
|
changed = true;
|
|
@@ -684,7 +769,7 @@ class Task {
|
|
|
684
769
|
}
|
|
685
770
|
return changed;
|
|
686
771
|
}
|
|
687
|
-
async narrowInput(input) {
|
|
772
|
+
async narrowInput(input, _registry) {
|
|
688
773
|
return input;
|
|
689
774
|
}
|
|
690
775
|
subscribe(name, fn) {
|
|
@@ -744,20 +829,20 @@ class Task {
|
|
|
744
829
|
const path = e.data.pointer || "";
|
|
745
830
|
return `${e.message}${path ? ` (${path})` : ""}`;
|
|
746
831
|
});
|
|
747
|
-
throw new TaskInvalidInputError(`Input ${JSON.stringify(input)} does not match schema: ${errorMessages.join(", ")}`);
|
|
832
|
+
throw new TaskInvalidInputError(`Input ${JSON.stringify(Object.keys(input))} does not match schema: ${errorMessages.join(", ")}`);
|
|
748
833
|
}
|
|
749
834
|
return true;
|
|
750
835
|
}
|
|
751
836
|
id() {
|
|
752
837
|
return this.config.id;
|
|
753
838
|
}
|
|
754
|
-
getProvenance() {
|
|
755
|
-
return this.config.provenance ?? {};
|
|
756
|
-
}
|
|
757
839
|
stripSymbols(obj) {
|
|
758
840
|
if (obj === null || obj === undefined) {
|
|
759
841
|
return obj;
|
|
760
842
|
}
|
|
843
|
+
if (ArrayBuffer.isView(obj)) {
|
|
844
|
+
return obj;
|
|
845
|
+
}
|
|
761
846
|
if (Array.isArray(obj)) {
|
|
762
847
|
return obj.map((item) => this.stripSymbols(item));
|
|
763
848
|
}
|
|
@@ -773,14 +858,12 @@ class Task {
|
|
|
773
858
|
return obj;
|
|
774
859
|
}
|
|
775
860
|
toJSON() {
|
|
776
|
-
const provenance = this.getProvenance();
|
|
777
861
|
const extras = this.config.extras;
|
|
778
862
|
let json = this.stripSymbols({
|
|
779
863
|
id: this.config.id,
|
|
780
864
|
type: this.type,
|
|
781
865
|
...this.config.name ? { name: this.config.name } : {},
|
|
782
866
|
defaults: this.defaults,
|
|
783
|
-
...Object.keys(provenance).length ? { provenance } : {},
|
|
784
867
|
...extras && Object.keys(extras).length ? { extras } : {}
|
|
785
868
|
});
|
|
786
869
|
return json;
|
|
@@ -826,8 +909,9 @@ class Task {
|
|
|
826
909
|
// src/task/ConditionalTask.ts
|
|
827
910
|
class ConditionalTask extends Task {
|
|
828
911
|
static type = "ConditionalTask";
|
|
829
|
-
static category = "
|
|
912
|
+
static category = "Hidden";
|
|
830
913
|
static title = "Conditional Task";
|
|
914
|
+
static description = "Evaluates conditions to determine which dataflows are active";
|
|
831
915
|
static hasDynamicSchemas = true;
|
|
832
916
|
activeBranches = new Set;
|
|
833
917
|
async execute(input, context) {
|
|
@@ -1052,9 +1136,9 @@ class TaskGraphRunner {
|
|
|
1052
1136
|
reactiveScheduler;
|
|
1053
1137
|
running = false;
|
|
1054
1138
|
reactiveRunning = false;
|
|
1055
|
-
provenanceInput;
|
|
1056
1139
|
graph;
|
|
1057
1140
|
outputCache;
|
|
1141
|
+
registry = globalServiceRegistry2;
|
|
1058
1142
|
abortController;
|
|
1059
1143
|
inProgressTasks = new Map;
|
|
1060
1144
|
inProgressFunctions = new Map;
|
|
@@ -1063,7 +1147,6 @@ class TaskGraphRunner {
|
|
|
1063
1147
|
this.processScheduler = processScheduler;
|
|
1064
1148
|
this.reactiveScheduler = reactiveScheduler;
|
|
1065
1149
|
this.graph = graph;
|
|
1066
|
-
this.provenanceInput = new Map;
|
|
1067
1150
|
graph.outputCache = outputCache;
|
|
1068
1151
|
this.handleProgress = this.handleProgress.bind(this);
|
|
1069
1152
|
}
|
|
@@ -1083,7 +1166,7 @@ class TaskGraphRunner {
|
|
|
1083
1166
|
const runAsync = async () => {
|
|
1084
1167
|
try {
|
|
1085
1168
|
const taskInput = isRootTask ? input : this.filterInputForTask(task, input);
|
|
1086
|
-
const taskPromise = this.
|
|
1169
|
+
const taskPromise = this.runTask(task, taskInput);
|
|
1087
1170
|
this.inProgressTasks.set(task.config.id, taskPromise);
|
|
1088
1171
|
const taskResult = await taskPromise;
|
|
1089
1172
|
if (this.graph.getTargetDataflows(task.config.id).length === 0) {
|
|
@@ -1193,23 +1276,16 @@ class TaskGraphRunner {
|
|
|
1193
1276
|
this.addInputData(task, dataflow.getPortData());
|
|
1194
1277
|
}
|
|
1195
1278
|
}
|
|
1196
|
-
|
|
1197
|
-
const nodeProvenance = {};
|
|
1198
|
-
this.graph.getSourceDataflows(node.config.id).forEach((dataflow) => {
|
|
1199
|
-
Object.assign(nodeProvenance, dataflow.provenance);
|
|
1200
|
-
});
|
|
1201
|
-
return nodeProvenance;
|
|
1202
|
-
}
|
|
1203
|
-
async pushOutputFromNodeToEdges(node, results, nodeProvenance) {
|
|
1279
|
+
async pushOutputFromNodeToEdges(node, results) {
|
|
1204
1280
|
const dataflows = this.graph.getTargetDataflows(node.config.id);
|
|
1205
1281
|
for (const dataflow of dataflows) {
|
|
1206
1282
|
const compatibility = dataflow.semanticallyCompatible(this.graph, dataflow);
|
|
1207
1283
|
if (compatibility === "static") {
|
|
1208
|
-
dataflow.setPortData(results
|
|
1284
|
+
dataflow.setPortData(results);
|
|
1209
1285
|
} else if (compatibility === "runtime") {
|
|
1210
1286
|
const task = this.graph.getTask(dataflow.targetTaskId);
|
|
1211
|
-
const narrowed = await task.narrowInput({ ...results });
|
|
1212
|
-
dataflow.setPortData(narrowed
|
|
1287
|
+
const narrowed = await task.narrowInput({ ...results }, this.registry);
|
|
1288
|
+
dataflow.setPortData(narrowed);
|
|
1213
1289
|
} else {}
|
|
1214
1290
|
}
|
|
1215
1291
|
}
|
|
@@ -1279,20 +1355,14 @@ class TaskGraphRunner {
|
|
|
1279
1355
|
}
|
|
1280
1356
|
}
|
|
1281
1357
|
}
|
|
1282
|
-
async
|
|
1283
|
-
const nodeProvenance = {
|
|
1284
|
-
...parentProvenance,
|
|
1285
|
-
...this.getInputProvenance(task),
|
|
1286
|
-
...task.getProvenance()
|
|
1287
|
-
};
|
|
1288
|
-
this.provenanceInput.set(task.config.id, nodeProvenance);
|
|
1358
|
+
async runTask(task, input) {
|
|
1289
1359
|
this.copyInputFromEdgesToNode(task);
|
|
1290
1360
|
const results = await task.runner.run(input, {
|
|
1291
|
-
nodeProvenance,
|
|
1292
1361
|
outputCache: this.outputCache,
|
|
1293
|
-
updateProgress: async (task2, progress, message, ...args) => await this.handleProgress(task2, progress, message, ...args)
|
|
1362
|
+
updateProgress: async (task2, progress, message, ...args) => await this.handleProgress(task2, progress, message, ...args),
|
|
1363
|
+
registry: this.registry
|
|
1294
1364
|
});
|
|
1295
|
-
await this.pushOutputFromNodeToEdges(task, results
|
|
1365
|
+
await this.pushOutputFromNodeToEdges(task, results);
|
|
1296
1366
|
return {
|
|
1297
1367
|
id: task.config.id,
|
|
1298
1368
|
type: task.constructor.runtype || task.constructor.type,
|
|
@@ -1326,10 +1396,15 @@ class TaskGraphRunner {
|
|
|
1326
1396
|
});
|
|
1327
1397
|
}
|
|
1328
1398
|
async handleStart(config) {
|
|
1399
|
+
if (config?.registry !== undefined) {
|
|
1400
|
+
this.registry = config.registry;
|
|
1401
|
+
} else {
|
|
1402
|
+
this.registry = new ServiceRegistry2(globalServiceRegistry2.container.createChildContainer());
|
|
1403
|
+
}
|
|
1329
1404
|
if (config?.outputCache !== undefined) {
|
|
1330
1405
|
if (typeof config.outputCache === "boolean") {
|
|
1331
1406
|
if (config.outputCache === true) {
|
|
1332
|
-
this.outputCache =
|
|
1407
|
+
this.outputCache = this.registry.get(TASK_OUTPUT_REPOSITORY);
|
|
1333
1408
|
} else {
|
|
1334
1409
|
this.outputCache = undefined;
|
|
1335
1410
|
}
|
|
@@ -1415,7 +1490,7 @@ class TaskGraphRunner {
|
|
|
1415
1490
|
progress = Math.round(completed / total);
|
|
1416
1491
|
}
|
|
1417
1492
|
this.pushStatusFromNodeToEdges(this.graph, task);
|
|
1418
|
-
await this.pushOutputFromNodeToEdges(task, task.runOutputData
|
|
1493
|
+
await this.pushOutputFromNodeToEdges(task, task.runOutputData);
|
|
1419
1494
|
this.graph.emit("graph_progress", progress, message, args);
|
|
1420
1495
|
}
|
|
1421
1496
|
}
|
|
@@ -1427,7 +1502,6 @@ class GraphAsTaskRunner extends TaskRunner {
|
|
|
1427
1502
|
this.task.emit("progress", progress, message, ...args);
|
|
1428
1503
|
});
|
|
1429
1504
|
const results = await this.task.subGraph.run(input, {
|
|
1430
|
-
parentProvenance: this.nodeProvenance || {},
|
|
1431
1505
|
parentSignal: this.abortController?.signal,
|
|
1432
1506
|
outputCache: this.outputCache
|
|
1433
1507
|
});
|
|
@@ -1443,27 +1517,12 @@ class GraphAsTaskRunner extends TaskRunner {
|
|
|
1443
1517
|
}
|
|
1444
1518
|
super.handleDisable();
|
|
1445
1519
|
}
|
|
1446
|
-
fixInput(input) {
|
|
1447
|
-
const inputSchema = this.task.inputSchema();
|
|
1448
|
-
if (typeof inputSchema === "boolean") {
|
|
1449
|
-
return input;
|
|
1450
|
-
}
|
|
1451
|
-
const flattenedInput = Object.entries(input).reduce((acc, [key, value]) => {
|
|
1452
|
-
const inputDef = inputSchema.properties?.[key];
|
|
1453
|
-
const shouldFlatten = Array.isArray(value) && typeof inputDef === "object" && inputDef !== null && "x-replicate" in inputDef && inputDef["x-replicate"] === true;
|
|
1454
|
-
if (shouldFlatten) {
|
|
1455
|
-
return { ...acc, [key]: value[0] };
|
|
1456
|
-
}
|
|
1457
|
-
return { ...acc, [key]: value };
|
|
1458
|
-
}, {});
|
|
1459
|
-
return flattenedInput;
|
|
1460
|
-
}
|
|
1461
1520
|
async executeTask(input) {
|
|
1462
1521
|
if (this.task.hasChildren()) {
|
|
1463
1522
|
const runExecuteOutputData = await this.executeTaskChildren(input);
|
|
1464
1523
|
this.task.runOutputData = this.task.subGraph.mergeExecuteOutputsToRunOutput(runExecuteOutputData, this.task.compoundMerge);
|
|
1465
1524
|
} else {
|
|
1466
|
-
const result = await super.executeTask(
|
|
1525
|
+
const result = await super.executeTask(input);
|
|
1467
1526
|
this.task.runOutputData = result ?? {};
|
|
1468
1527
|
}
|
|
1469
1528
|
return this.task.runOutputData;
|
|
@@ -1473,7 +1532,7 @@ class GraphAsTaskRunner extends TaskRunner {
|
|
|
1473
1532
|
const reactiveResults = await this.executeTaskChildrenReactive();
|
|
1474
1533
|
this.task.runOutputData = this.task.subGraph.mergeExecuteOutputsToRunOutput(reactiveResults, this.task.compoundMerge);
|
|
1475
1534
|
} else {
|
|
1476
|
-
const reactiveResults = await super.executeTaskReactive(
|
|
1535
|
+
const reactiveResults = await super.executeTaskReactive(input, output);
|
|
1477
1536
|
this.task.runOutputData = Object.assign({}, output, reactiveResults ?? {});
|
|
1478
1537
|
}
|
|
1479
1538
|
return this.task.runOutputData;
|
|
@@ -1483,6 +1542,8 @@ class GraphAsTaskRunner extends TaskRunner {
|
|
|
1483
1542
|
// src/task/GraphAsTask.ts
|
|
1484
1543
|
class GraphAsTask extends Task {
|
|
1485
1544
|
static type = "GraphAsTask";
|
|
1545
|
+
static title = "Graph as Task";
|
|
1546
|
+
static description = "A task that contains a subgraph of tasks";
|
|
1486
1547
|
static category = "Hidden";
|
|
1487
1548
|
static compoundMerge = PROPERTY_ARRAY;
|
|
1488
1549
|
static hasDynamicSchemas = true;
|
|
@@ -1709,6 +1770,15 @@ class Workflow {
|
|
|
1709
1770
|
const sourceSchema = parent.outputSchema();
|
|
1710
1771
|
const targetSchema = task.inputSchema();
|
|
1711
1772
|
const makeMatch = (comparator) => {
|
|
1773
|
+
if (typeof sourceSchema === "object") {
|
|
1774
|
+
if (targetSchema === true || typeof targetSchema === "object" && targetSchema.additionalProperties === true) {
|
|
1775
|
+
for (const fromOutputPortId of Object.keys(sourceSchema.properties || {})) {
|
|
1776
|
+
matches.set(fromOutputPortId, fromOutputPortId);
|
|
1777
|
+
this.connect(parent.config.id, fromOutputPortId, task.config.id, fromOutputPortId);
|
|
1778
|
+
}
|
|
1779
|
+
return matches;
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1712
1782
|
if (typeof sourceSchema === "boolean" || typeof targetSchema === "boolean") {
|
|
1713
1783
|
return matches;
|
|
1714
1784
|
}
|
|
@@ -1722,25 +1792,135 @@ class Workflow {
|
|
|
1722
1792
|
}
|
|
1723
1793
|
return matches;
|
|
1724
1794
|
};
|
|
1725
|
-
|
|
1795
|
+
const getSpecificTypeIdentifiers = (schema) => {
|
|
1796
|
+
const formats = new Set;
|
|
1797
|
+
const ids = new Set;
|
|
1798
|
+
if (typeof schema === "boolean") {
|
|
1799
|
+
return { formats, ids };
|
|
1800
|
+
}
|
|
1801
|
+
const extractFromSchema = (s) => {
|
|
1802
|
+
if (!s || typeof s !== "object" || Array.isArray(s))
|
|
1803
|
+
return;
|
|
1804
|
+
if (s.format)
|
|
1805
|
+
formats.add(s.format);
|
|
1806
|
+
if (s.$id)
|
|
1807
|
+
ids.add(s.$id);
|
|
1808
|
+
};
|
|
1809
|
+
extractFromSchema(schema);
|
|
1810
|
+
const checkUnion = (schemas) => {
|
|
1811
|
+
if (!schemas)
|
|
1812
|
+
return;
|
|
1813
|
+
for (const s of schemas) {
|
|
1814
|
+
if (typeof s === "boolean")
|
|
1815
|
+
continue;
|
|
1816
|
+
extractFromSchema(s);
|
|
1817
|
+
if (s.items && typeof s.items === "object" && !Array.isArray(s.items)) {
|
|
1818
|
+
extractFromSchema(s.items);
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
};
|
|
1822
|
+
checkUnion(schema.oneOf);
|
|
1823
|
+
checkUnion(schema.anyOf);
|
|
1824
|
+
if (schema.items && typeof schema.items === "object" && !Array.isArray(schema.items)) {
|
|
1825
|
+
extractFromSchema(schema.items);
|
|
1826
|
+
}
|
|
1827
|
+
return { formats, ids };
|
|
1828
|
+
};
|
|
1829
|
+
const isTypeCompatible = (fromPortOutputSchema, toPortInputSchema, requireSpecificType = false) => {
|
|
1726
1830
|
if (typeof fromPortOutputSchema === "boolean" || typeof toPortInputSchema === "boolean") {
|
|
1727
|
-
|
|
1831
|
+
return fromPortOutputSchema === true && toPortInputSchema === true;
|
|
1832
|
+
}
|
|
1833
|
+
const outputIds = getSpecificTypeIdentifiers(fromPortOutputSchema);
|
|
1834
|
+
const inputIds = getSpecificTypeIdentifiers(toPortInputSchema);
|
|
1835
|
+
for (const format of outputIds.formats) {
|
|
1836
|
+
if (inputIds.formats.has(format)) {
|
|
1837
|
+
return true;
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
for (const id of outputIds.ids) {
|
|
1841
|
+
if (inputIds.ids.has(id)) {
|
|
1728
1842
|
return true;
|
|
1729
1843
|
}
|
|
1844
|
+
}
|
|
1845
|
+
if (requireSpecificType) {
|
|
1730
1846
|
return false;
|
|
1731
1847
|
}
|
|
1732
|
-
const idTypeMatch = fromPortOutputSchema.$id !== undefined && fromPortOutputSchema.$id === toPortInputSchema.$id;
|
|
1733
1848
|
const idTypeBlank = fromPortOutputSchema.$id === undefined && toPortInputSchema.$id === undefined;
|
|
1734
|
-
|
|
1849
|
+
if (!idTypeBlank)
|
|
1850
|
+
return false;
|
|
1851
|
+
if (fromPortOutputSchema.type === toPortInputSchema.type)
|
|
1852
|
+
return true;
|
|
1853
|
+
const matchesOneOf = toPortInputSchema.oneOf?.some((schema) => {
|
|
1854
|
+
if (typeof schema === "boolean")
|
|
1855
|
+
return schema;
|
|
1856
|
+
return schema.type === fromPortOutputSchema.type;
|
|
1857
|
+
}) ?? false;
|
|
1858
|
+
const matchesAnyOf = toPortInputSchema.anyOf?.some((schema) => {
|
|
1859
|
+
if (typeof schema === "boolean")
|
|
1860
|
+
return schema;
|
|
1861
|
+
return schema.type === fromPortOutputSchema.type;
|
|
1862
|
+
}) ?? false;
|
|
1863
|
+
return matchesOneOf || matchesAnyOf;
|
|
1864
|
+
};
|
|
1865
|
+
makeMatch(([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema]) => {
|
|
1735
1866
|
const outputPortIdMatch = fromOutputPortId === toInputPortId;
|
|
1736
1867
|
const outputPortIdOutputInput = fromOutputPortId === "output" && toInputPortId === "input";
|
|
1737
1868
|
const portIdsCompatible = outputPortIdMatch || outputPortIdOutputInput;
|
|
1738
|
-
return (
|
|
1869
|
+
return portIdsCompatible && isTypeCompatible(fromPortOutputSchema, toPortInputSchema, false);
|
|
1739
1870
|
});
|
|
1740
|
-
|
|
1741
|
-
|
|
1871
|
+
makeMatch(([_fromOutputPortId, fromPortOutputSchema], [_toInputPortId, toPortInputSchema]) => {
|
|
1872
|
+
return isTypeCompatible(fromPortOutputSchema, toPortInputSchema, true);
|
|
1873
|
+
});
|
|
1874
|
+
const requiredInputs = new Set(typeof targetSchema === "object" ? targetSchema.required || [] : []);
|
|
1875
|
+
const providedInputKeys = new Set(Object.keys(input || {}));
|
|
1876
|
+
const requiredInputsNeedingConnection = [...requiredInputs].filter((r) => !providedInputKeys.has(r));
|
|
1877
|
+
let unmatchedRequired = requiredInputsNeedingConnection.filter((r) => !matches.has(r));
|
|
1878
|
+
if (unmatchedRequired.length > 0) {
|
|
1879
|
+
const nodes = this._graph.getTasks();
|
|
1880
|
+
const parentIndex = nodes.findIndex((n) => n.config.id === parent.config.id);
|
|
1881
|
+
for (let i = parentIndex - 1;i >= 0 && unmatchedRequired.length > 0; i--) {
|
|
1882
|
+
const earlierTask = nodes[i];
|
|
1883
|
+
const earlierOutputSchema = earlierTask.outputSchema();
|
|
1884
|
+
const makeMatchFromEarlier = (comparator) => {
|
|
1885
|
+
if (typeof earlierOutputSchema === "boolean" || typeof targetSchema === "boolean") {
|
|
1886
|
+
return;
|
|
1887
|
+
}
|
|
1888
|
+
for (const [fromOutputPortId, fromPortOutputSchema] of Object.entries(earlierOutputSchema.properties || {})) {
|
|
1889
|
+
for (const requiredInputId of unmatchedRequired) {
|
|
1890
|
+
const toPortInputSchema = targetSchema.properties?.[requiredInputId];
|
|
1891
|
+
if (!matches.has(requiredInputId) && toPortInputSchema && comparator([fromOutputPortId, fromPortOutputSchema], [requiredInputId, toPortInputSchema])) {
|
|
1892
|
+
matches.set(requiredInputId, fromOutputPortId);
|
|
1893
|
+
this.connect(earlierTask.config.id, fromOutputPortId, task.config.id, requiredInputId);
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
};
|
|
1898
|
+
makeMatchFromEarlier(([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema]) => {
|
|
1899
|
+
const outputPortIdMatch = fromOutputPortId === toInputPortId;
|
|
1900
|
+
const outputPortIdOutputInput = fromOutputPortId === "output" && toInputPortId === "input";
|
|
1901
|
+
const portIdsCompatible = outputPortIdMatch || outputPortIdOutputInput;
|
|
1902
|
+
return portIdsCompatible && isTypeCompatible(fromPortOutputSchema, toPortInputSchema, false);
|
|
1903
|
+
});
|
|
1904
|
+
makeMatchFromEarlier(([_fromOutputPortId, fromPortOutputSchema], [_toInputPortId, toPortInputSchema]) => {
|
|
1905
|
+
return isTypeCompatible(fromPortOutputSchema, toPortInputSchema, true);
|
|
1906
|
+
});
|
|
1907
|
+
unmatchedRequired = unmatchedRequired.filter((r) => !matches.has(r));
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
const stillUnmatchedRequired = requiredInputsNeedingConnection.filter((r) => !matches.has(r));
|
|
1911
|
+
if (stillUnmatchedRequired.length > 0) {
|
|
1912
|
+
this._error = `Could not find matches for required inputs [${stillUnmatchedRequired.join(", ")}] of ${task.type}. ` + `Attempted to match from ${parent.type} and earlier tasks. Task not added.`;
|
|
1742
1913
|
console.error(this._error);
|
|
1743
1914
|
this.graph.removeTask(task.config.id);
|
|
1915
|
+
} else if (matches.size === 0 && requiredInputsNeedingConnection.length === 0) {
|
|
1916
|
+
const hasRequiredInputs = requiredInputs.size > 0;
|
|
1917
|
+
const allRequiredInputsProvided = hasRequiredInputs && [...requiredInputs].every((r) => providedInputKeys.has(r));
|
|
1918
|
+
const hasInputsWithDefaults = typeof targetSchema === "object" && targetSchema.properties && Object.values(targetSchema.properties).some((prop) => prop && typeof prop === "object" && ("default" in prop));
|
|
1919
|
+
if (!allRequiredInputsProvided && !hasInputsWithDefaults) {
|
|
1920
|
+
this._error = `Could not find a match between the outputs of ${parent.type} and the inputs of ${task.type}. ` + `You now need to connect the outputs to the inputs via connect() manually before adding this task. Task not added.`;
|
|
1921
|
+
console.error(this._error);
|
|
1922
|
+
this.graph.removeTask(task.config.id);
|
|
1923
|
+
}
|
|
1744
1924
|
}
|
|
1745
1925
|
}
|
|
1746
1926
|
return this;
|
|
@@ -1785,7 +1965,6 @@ class Workflow {
|
|
|
1785
1965
|
try {
|
|
1786
1966
|
const output = await this.graph.run(input, {
|
|
1787
1967
|
parentSignal: this._abortController.signal,
|
|
1788
|
-
parentProvenance: {},
|
|
1789
1968
|
outputCache: this._repository
|
|
1790
1969
|
});
|
|
1791
1970
|
const results = this.graph.mergeExecuteOutputsToRunOutput(output, PROPERTY_ARRAY);
|
|
@@ -1917,7 +2096,8 @@ class Workflow {
|
|
|
1917
2096
|
if (targetSchema === false) {
|
|
1918
2097
|
throw new WorkflowError(`Target task has schema 'false' and accepts no inputs`);
|
|
1919
2098
|
}
|
|
1920
|
-
|
|
2099
|
+
if (targetSchema === true) {}
|
|
2100
|
+
} else if (targetSchema.additionalProperties === true) {} else if (!targetSchema.properties?.[targetTaskPortId]) {
|
|
1921
2101
|
throw new WorkflowError(`Input ${targetTaskPortId} not found on target task`);
|
|
1922
2102
|
}
|
|
1923
2103
|
const dataflow = new Dataflow(sourceTaskId, sourceTaskPortId, targetTaskId, targetTaskPortId);
|
|
@@ -2097,7 +2277,6 @@ class TaskGraph {
|
|
|
2097
2277
|
run(input = {}, config = {}) {
|
|
2098
2278
|
return this.runner.runGraph(input, {
|
|
2099
2279
|
outputCache: config?.outputCache || this.outputCache,
|
|
2100
|
-
parentProvenance: config?.parentProvenance || {},
|
|
2101
2280
|
parentSignal: config?.parentSignal || undefined
|
|
2102
2281
|
});
|
|
2103
2282
|
}
|
|
@@ -2338,142 +2517,6 @@ function serialGraph(tasks, inputHandle, outputHandle) {
|
|
|
2338
2517
|
graph.addDataflows(serialGraphEdges(tasks, inputHandle, outputHandle));
|
|
2339
2518
|
return graph;
|
|
2340
2519
|
}
|
|
2341
|
-
|
|
2342
|
-
// src/task/ArrayTask.ts
|
|
2343
|
-
class ArrayTask extends GraphAsTask {
|
|
2344
|
-
static type = "ArrayTask";
|
|
2345
|
-
static compoundMerge = PROPERTY_ARRAY;
|
|
2346
|
-
inputSchema() {
|
|
2347
|
-
return this.constructor.inputSchema();
|
|
2348
|
-
}
|
|
2349
|
-
outputSchema() {
|
|
2350
|
-
return this.constructor.outputSchema();
|
|
2351
|
-
}
|
|
2352
|
-
regenerateGraph() {
|
|
2353
|
-
const arrayInputs = new Map;
|
|
2354
|
-
let hasArrayInputs = false;
|
|
2355
|
-
const inputSchema = this.inputSchema();
|
|
2356
|
-
if (typeof inputSchema !== "boolean") {
|
|
2357
|
-
const keys = Object.keys(inputSchema.properties || {});
|
|
2358
|
-
for (const inputId of keys) {
|
|
2359
|
-
const inputValue = this.runInputData[inputId];
|
|
2360
|
-
const inputDef = inputSchema.properties?.[inputId];
|
|
2361
|
-
if (typeof inputDef === "object" && inputDef !== null && "x-replicate" in inputDef && inputDef["x-replicate"] === true && Array.isArray(inputValue) && inputValue.length > 1) {
|
|
2362
|
-
arrayInputs.set(inputId, inputValue);
|
|
2363
|
-
hasArrayInputs = true;
|
|
2364
|
-
}
|
|
2365
|
-
}
|
|
2366
|
-
}
|
|
2367
|
-
this.subGraph = new TaskGraph;
|
|
2368
|
-
if (!hasArrayInputs) {
|
|
2369
|
-
super.regenerateGraph();
|
|
2370
|
-
return;
|
|
2371
|
-
}
|
|
2372
|
-
const inputIds = Array.from(arrayInputs.keys());
|
|
2373
|
-
const inputObject = Object.fromEntries(arrayInputs);
|
|
2374
|
-
const combinations = this.generateCombinations(inputObject, inputIds);
|
|
2375
|
-
const tasks = combinations.map((combination) => {
|
|
2376
|
-
const { id, name, ...rest } = this.config;
|
|
2377
|
-
const task = new this.constructor({ ...this.defaults, ...this.runInputData, ...combination }, { ...rest, id: `${id}_${uuid44()}` });
|
|
2378
|
-
return task;
|
|
2379
|
-
});
|
|
2380
|
-
this.subGraph.addTasks(tasks);
|
|
2381
|
-
super.regenerateGraph();
|
|
2382
|
-
}
|
|
2383
|
-
generateCombinations(input, inputMakeArray) {
|
|
2384
|
-
const arraysToCombine = inputMakeArray.map((key) => Array.isArray(input[key]) ? input[key] : []);
|
|
2385
|
-
const indices = arraysToCombine.map(() => 0);
|
|
2386
|
-
const combinations = [];
|
|
2387
|
-
let done = false;
|
|
2388
|
-
while (!done) {
|
|
2389
|
-
combinations.push([...indices]);
|
|
2390
|
-
for (let i = indices.length - 1;i >= 0; i--) {
|
|
2391
|
-
if (++indices[i] < arraysToCombine[i].length)
|
|
2392
|
-
break;
|
|
2393
|
-
if (i === 0)
|
|
2394
|
-
done = true;
|
|
2395
|
-
else
|
|
2396
|
-
indices[i] = 0;
|
|
2397
|
-
}
|
|
2398
|
-
}
|
|
2399
|
-
const combos = combinations.map((combination) => {
|
|
2400
|
-
const result = { ...input };
|
|
2401
|
-
combination.forEach((valueIndex, arrayIndex) => {
|
|
2402
|
-
const key = inputMakeArray[arrayIndex];
|
|
2403
|
-
if (Array.isArray(input[key]))
|
|
2404
|
-
result[key] = input[key][valueIndex];
|
|
2405
|
-
});
|
|
2406
|
-
return result;
|
|
2407
|
-
});
|
|
2408
|
-
return combos;
|
|
2409
|
-
}
|
|
2410
|
-
toJSON() {
|
|
2411
|
-
const { subgraph, ...result } = super.toJSON();
|
|
2412
|
-
return result;
|
|
2413
|
-
}
|
|
2414
|
-
toDependencyJSON() {
|
|
2415
|
-
const { subtasks, ...result } = super.toDependencyJSON();
|
|
2416
|
-
return result;
|
|
2417
|
-
}
|
|
2418
|
-
get runner() {
|
|
2419
|
-
if (!this._runner) {
|
|
2420
|
-
this._runner = new ArrayTaskRunner(this);
|
|
2421
|
-
}
|
|
2422
|
-
return this._runner;
|
|
2423
|
-
}
|
|
2424
|
-
}
|
|
2425
|
-
|
|
2426
|
-
class ArrayTaskRunner extends GraphAsTaskRunner {
|
|
2427
|
-
async executeTaskChildren(_input) {
|
|
2428
|
-
return super.executeTaskChildren({});
|
|
2429
|
-
}
|
|
2430
|
-
async executeTaskReactive(input, output) {
|
|
2431
|
-
const reactiveResults = await super.executeTaskReactive(input, output);
|
|
2432
|
-
if (this.task.hasChildren()) {
|
|
2433
|
-
return reactiveResults;
|
|
2434
|
-
} else {
|
|
2435
|
-
this.task.runOutputData = Object.assign({}, output, reactiveResults ?? {});
|
|
2436
|
-
return this.task.runOutputData;
|
|
2437
|
-
}
|
|
2438
|
-
}
|
|
2439
|
-
}
|
|
2440
|
-
// src/task/InputTask.ts
|
|
2441
|
-
import { Task as Task2 } from "@workglow/task-graph";
|
|
2442
|
-
|
|
2443
|
-
class InputTask extends Task2 {
|
|
2444
|
-
static type = "InputTask";
|
|
2445
|
-
static category = "Flow Control";
|
|
2446
|
-
static title = "Input";
|
|
2447
|
-
static description = "Starts the workflow";
|
|
2448
|
-
static hasDynamicSchemas = true;
|
|
2449
|
-
static cacheable = false;
|
|
2450
|
-
static inputSchema() {
|
|
2451
|
-
return {
|
|
2452
|
-
type: "object",
|
|
2453
|
-
properties: {},
|
|
2454
|
-
additionalProperties: true
|
|
2455
|
-
};
|
|
2456
|
-
}
|
|
2457
|
-
static outputSchema() {
|
|
2458
|
-
return {
|
|
2459
|
-
type: "object",
|
|
2460
|
-
properties: {},
|
|
2461
|
-
additionalProperties: true
|
|
2462
|
-
};
|
|
2463
|
-
}
|
|
2464
|
-
inputSchema() {
|
|
2465
|
-
return this.config?.extras?.inputSchema ?? this.constructor.inputSchema();
|
|
2466
|
-
}
|
|
2467
|
-
outputSchema() {
|
|
2468
|
-
return this.config?.extras?.outputSchema ?? this.constructor.outputSchema();
|
|
2469
|
-
}
|
|
2470
|
-
async execute(input, _context) {
|
|
2471
|
-
return input;
|
|
2472
|
-
}
|
|
2473
|
-
async executeReactive(input, _output, _context) {
|
|
2474
|
-
return input;
|
|
2475
|
-
}
|
|
2476
|
-
}
|
|
2477
2520
|
// src/task/JobQueueFactory.ts
|
|
2478
2521
|
import {
|
|
2479
2522
|
JobQueueClient,
|
|
@@ -2602,7 +2645,7 @@ function setTaskQueueRegistry(registry) {
|
|
|
2602
2645
|
}
|
|
2603
2646
|
|
|
2604
2647
|
// src/task/JobQueueTask.ts
|
|
2605
|
-
class JobQueueTask extends
|
|
2648
|
+
class JobQueueTask extends GraphAsTask {
|
|
2606
2649
|
static type = "JobQueueTask";
|
|
2607
2650
|
static canRunDirectly = true;
|
|
2608
2651
|
currentQueueName;
|
|
@@ -2734,43 +2777,6 @@ class JobQueueTask extends ArrayTask {
|
|
|
2734
2777
|
super.abort();
|
|
2735
2778
|
}
|
|
2736
2779
|
}
|
|
2737
|
-
// src/task/OutputTask.ts
|
|
2738
|
-
import { Task as Task3 } from "@workglow/task-graph";
|
|
2739
|
-
|
|
2740
|
-
class OutputTask extends Task3 {
|
|
2741
|
-
static type = "OutputTask";
|
|
2742
|
-
static category = "Flow Control";
|
|
2743
|
-
static title = "Output";
|
|
2744
|
-
static description = "Ends the workflow";
|
|
2745
|
-
static hasDynamicSchemas = true;
|
|
2746
|
-
static cacheable = false;
|
|
2747
|
-
static inputSchema() {
|
|
2748
|
-
return {
|
|
2749
|
-
type: "object",
|
|
2750
|
-
properties: {},
|
|
2751
|
-
additionalProperties: true
|
|
2752
|
-
};
|
|
2753
|
-
}
|
|
2754
|
-
static outputSchema() {
|
|
2755
|
-
return {
|
|
2756
|
-
type: "object",
|
|
2757
|
-
properties: {},
|
|
2758
|
-
additionalProperties: true
|
|
2759
|
-
};
|
|
2760
|
-
}
|
|
2761
|
-
inputSchema() {
|
|
2762
|
-
return this.config?.extras?.inputSchema ?? this.constructor.inputSchema();
|
|
2763
|
-
}
|
|
2764
|
-
outputSchema() {
|
|
2765
|
-
return this.config?.extras?.outputSchema ?? this.constructor.outputSchema();
|
|
2766
|
-
}
|
|
2767
|
-
async execute(input, _context) {
|
|
2768
|
-
return input;
|
|
2769
|
-
}
|
|
2770
|
-
async executeReactive(input, _output, _context) {
|
|
2771
|
-
return input;
|
|
2772
|
-
}
|
|
2773
|
-
}
|
|
2774
2780
|
// src/task/TaskRegistry.ts
|
|
2775
2781
|
var taskConstructors = new Map;
|
|
2776
2782
|
function registerTask(baseClass) {
|
|
@@ -2788,17 +2794,14 @@ var createSingleTaskFromJSON = (item) => {
|
|
|
2788
2794
|
throw new TaskJSONError("Task id required");
|
|
2789
2795
|
if (!item.type)
|
|
2790
2796
|
throw new TaskJSONError("Task type required");
|
|
2791
|
-
if (item.defaults &&
|
|
2797
|
+
if (item.defaults && Array.isArray(item.defaults))
|
|
2792
2798
|
throw new TaskJSONError("Task defaults must be an object");
|
|
2793
|
-
if (item.provenance && (Array.isArray(item.provenance) || typeof item.provenance !== "object"))
|
|
2794
|
-
throw new TaskJSONError("Task provenance must be an object");
|
|
2795
2799
|
const taskClass = TaskRegistry.all.get(item.type);
|
|
2796
2800
|
if (!taskClass)
|
|
2797
2801
|
throw new TaskJSONError(`Task type ${item.type} not found, perhaps not registered?`);
|
|
2798
2802
|
const taskConfig = {
|
|
2799
2803
|
id: item.id,
|
|
2800
2804
|
name: item.name,
|
|
2801
|
-
provenance: item.provenance ?? {},
|
|
2802
2805
|
extras: item.extras
|
|
2803
2806
|
};
|
|
2804
2807
|
const task = new taskClass(item.defaults ?? {}, taskConfig);
|
|
@@ -2841,6 +2844,12 @@ var createGraphFromGraphJSON = (graphJsonObj) => {
|
|
|
2841
2844
|
}
|
|
2842
2845
|
return subGraph;
|
|
2843
2846
|
};
|
|
2847
|
+
// src/task/index.ts
|
|
2848
|
+
var registerBaseTasks = () => {
|
|
2849
|
+
const tasks = [ConditionalTask, GraphAsTask];
|
|
2850
|
+
tasks.map(TaskRegistry.registerTask);
|
|
2851
|
+
return tasks;
|
|
2852
|
+
};
|
|
2844
2853
|
// src/storage/TaskGraphRepository.ts
|
|
2845
2854
|
import { createServiceToken as createServiceToken3, EventEmitter as EventEmitter6 } from "@workglow/util";
|
|
2846
2855
|
var TASK_GRAPH_REPOSITORY = createServiceToken3("taskgraph.taskGraphRepository");
|
|
@@ -3000,7 +3009,9 @@ class TaskOutputTabularRepository extends TaskOutputRepository {
|
|
|
3000
3009
|
export {
|
|
3001
3010
|
setTaskQueueRegistry,
|
|
3002
3011
|
serialGraph,
|
|
3012
|
+
resolveSchemaInputs,
|
|
3003
3013
|
registerJobQueueFactory,
|
|
3014
|
+
registerBaseTasks,
|
|
3004
3015
|
pipe,
|
|
3005
3016
|
parallel,
|
|
3006
3017
|
getTaskQueueRegistry,
|
|
@@ -3038,11 +3049,9 @@ export {
|
|
|
3038
3049
|
TASK_OUTPUT_REPOSITORY,
|
|
3039
3050
|
TASK_GRAPH_REPOSITORY,
|
|
3040
3051
|
PROPERTY_ARRAY,
|
|
3041
|
-
OutputTask,
|
|
3042
3052
|
JobTaskFailedError,
|
|
3043
3053
|
JobQueueTask,
|
|
3044
3054
|
JOB_QUEUE_FACTORY,
|
|
3045
|
-
InputTask,
|
|
3046
3055
|
GraphAsTaskRunner,
|
|
3047
3056
|
GraphAsTask,
|
|
3048
3057
|
GRAPH_RESULT_ARRAY,
|
|
@@ -3053,8 +3062,7 @@ export {
|
|
|
3053
3062
|
DATAFLOW_ERROR_PORT,
|
|
3054
3063
|
DATAFLOW_ALL_PORTS,
|
|
3055
3064
|
CreateWorkflow,
|
|
3056
|
-
ConditionalTask
|
|
3057
|
-
ArrayTask
|
|
3065
|
+
ConditionalTask
|
|
3058
3066
|
};
|
|
3059
3067
|
|
|
3060
|
-
//# debugId=
|
|
3068
|
+
//# debugId=C40AC8C0A1FC6ED164756E2164756E21
|