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