@workglow/task-graph 0.2.13 → 0.2.15
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/dist/__tests__/public-exports.test.d.ts +7 -0
- package/dist/__tests__/public-exports.test.d.ts.map +1 -0
- package/dist/browser.js +1068 -404
- package/dist/browser.js.map +30 -20
- package/dist/bun.js +1063 -399
- package/dist/bun.js.map +30 -20
- package/dist/common.d.ts +4 -0
- package/dist/common.d.ts.map +1 -1
- package/dist/node.js +1063 -399
- package/dist/node.js.map +30 -20
- package/dist/task/EntitlementEnforcer.d.ts +37 -4
- package/dist/task/EntitlementEnforcer.d.ts.map +1 -1
- package/dist/task/EntitlementPolicy.d.ts +10 -0
- package/dist/task/EntitlementPolicy.d.ts.map +1 -1
- package/dist/task/FallbackTask.d.ts +2 -1
- package/dist/task/FallbackTask.d.ts.map +1 -1
- package/dist/task/GraphAsTask.d.ts +8 -0
- package/dist/task/GraphAsTask.d.ts.map +1 -1
- package/dist/task/IteratorTask.d.ts +26 -7
- package/dist/task/IteratorTask.d.ts.map +1 -1
- package/dist/task/IteratorTaskRunner.d.ts +1 -1
- package/dist/task/IteratorTaskRunner.d.ts.map +1 -1
- package/dist/task/MapTask.d.ts +47 -3
- package/dist/task/MapTask.d.ts.map +1 -1
- package/dist/task/ReduceTask.d.ts +10 -3
- package/dist/task/ReduceTask.d.ts.map +1 -1
- package/dist/task/Task.d.ts +4 -1
- package/dist/task/Task.d.ts.map +1 -1
- package/dist/task/TaskJSON.d.ts +10 -1
- package/dist/task/TaskJSON.d.ts.map +1 -1
- package/dist/task/WhileTask.d.ts +20 -7
- package/dist/task/WhileTask.d.ts.map +1 -1
- package/dist/task/__tests__/DataflowJson.transforms.test.d.ts +7 -0
- package/dist/task/__tests__/DataflowJson.transforms.test.d.ts.map +1 -0
- package/dist/task-graph/ConditionalBuilder.d.ts +49 -0
- package/dist/task-graph/ConditionalBuilder.d.ts.map +1 -0
- package/dist/task-graph/Conversions.d.ts.map +1 -1
- package/dist/task-graph/Dataflow.d.ts +41 -1
- package/dist/task-graph/Dataflow.d.ts.map +1 -1
- package/dist/task-graph/GraphSchemaUtils.d.ts +2 -2
- package/dist/task-graph/GraphSchemaUtils.d.ts.map +1 -1
- package/dist/task-graph/GraphToWorkflowCode.d.ts.map +1 -1
- package/dist/task-graph/TaskGraph.d.ts +6 -0
- package/dist/task-graph/TaskGraph.d.ts.map +1 -1
- package/dist/task-graph/TaskGraphRunner.d.ts.map +1 -1
- package/dist/task-graph/TransformRegistry.d.ts +14 -0
- package/dist/task-graph/TransformRegistry.d.ts.map +1 -0
- package/dist/task-graph/TransformTypes.d.ts +51 -0
- package/dist/task-graph/TransformTypes.d.ts.map +1 -0
- package/dist/task-graph/Workflow.d.ts +31 -3
- package/dist/task-graph/Workflow.d.ts.map +1 -1
- package/dist/task-graph/__tests__/Dataflow.streaming.test.d.ts +7 -0
- package/dist/task-graph/__tests__/Dataflow.streaming.test.d.ts.map +1 -0
- package/dist/task-graph/__tests__/Dataflow.transforms.test.d.ts +7 -0
- package/dist/task-graph/__tests__/Dataflow.transforms.test.d.ts.map +1 -0
- package/dist/task-graph/__tests__/TaskGraphRunner.transforms.test.d.ts +7 -0
- package/dist/task-graph/__tests__/TaskGraphRunner.transforms.test.d.ts.map +1 -0
- package/dist/task-graph/__tests__/TransformRegistry.test.d.ts +6 -0
- package/dist/task-graph/__tests__/TransformRegistry.test.d.ts.map +1 -0
- package/dist/task-graph/__tests__/transforms/coalesce.test.d.ts +6 -0
- package/dist/task-graph/__tests__/transforms/coalesce.test.d.ts.map +1 -0
- package/dist/task-graph/__tests__/transforms/date-conversions.test.d.ts +6 -0
- package/dist/task-graph/__tests__/transforms/date-conversions.test.d.ts.map +1 -0
- package/dist/task-graph/__tests__/transforms/index-access.test.d.ts +6 -0
- package/dist/task-graph/__tests__/transforms/index-access.test.d.ts.map +1 -0
- package/dist/task-graph/__tests__/transforms/pick.test.d.ts +6 -0
- package/dist/task-graph/__tests__/transforms/pick.test.d.ts.map +1 -0
- package/dist/task-graph/__tests__/transforms/scalar-conversions.test.d.ts +6 -0
- package/dist/task-graph/__tests__/transforms/scalar-conversions.test.d.ts.map +1 -0
- package/dist/task-graph/__tests__/transforms/string-casts.test.d.ts +6 -0
- package/dist/task-graph/__tests__/transforms/string-casts.test.d.ts.map +1 -0
- package/dist/task-graph/autoConnect.d.ts +39 -0
- package/dist/task-graph/autoConnect.d.ts.map +1 -0
- package/dist/task-graph/transforms/coalesce.d.ts +11 -0
- package/dist/task-graph/transforms/coalesce.d.ts.map +1 -0
- package/dist/task-graph/transforms/date-conversions.d.ts +12 -0
- package/dist/task-graph/transforms/date-conversions.d.ts.map +1 -0
- package/dist/task-graph/transforms/index-access.d.ts +11 -0
- package/dist/task-graph/transforms/index-access.d.ts.map +1 -0
- package/dist/task-graph/transforms/index.d.ts +18 -0
- package/dist/task-graph/transforms/index.d.ts.map +1 -0
- package/dist/task-graph/transforms/pick.d.ts +11 -0
- package/dist/task-graph/transforms/pick.d.ts.map +1 -0
- package/dist/task-graph/transforms/scalar-conversions.d.ts +10 -0
- package/dist/task-graph/transforms/scalar-conversions.d.ts.map +1 -0
- package/dist/task-graph/transforms/string-casts.d.ts +18 -0
- package/dist/task-graph/transforms/string-casts.d.ts.map +1 -0
- package/package.json +7 -7
- package/src/EXECUTION_MODEL.md +6 -0
package/dist/bun.js
CHANGED
|
@@ -3,6 +3,98 @@
|
|
|
3
3
|
import { areSemanticallyCompatible } from "@workglow/util/schema";
|
|
4
4
|
import { EventEmitter } from "@workglow/util";
|
|
5
5
|
|
|
6
|
+
// src/task/TaskError.ts
|
|
7
|
+
import { BaseError } from "@workglow/util";
|
|
8
|
+
|
|
9
|
+
class TaskError extends BaseError {
|
|
10
|
+
static type = "TaskError";
|
|
11
|
+
taskType;
|
|
12
|
+
taskId;
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
class TaskConfigurationError extends TaskError {
|
|
19
|
+
static type = "TaskConfigurationError";
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super(message);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class WorkflowError extends TaskError {
|
|
26
|
+
static type = "WorkflowError";
|
|
27
|
+
constructor(message) {
|
|
28
|
+
super(message);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
class TaskAbortedError extends TaskError {
|
|
33
|
+
static type = "TaskAbortedError";
|
|
34
|
+
constructor(message = "Task aborted") {
|
|
35
|
+
super(message);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class TaskTimeoutError extends TaskAbortedError {
|
|
40
|
+
static type = "TaskTimeoutError";
|
|
41
|
+
constructor(timeoutMs) {
|
|
42
|
+
super(timeoutMs ? `Task timed out after ${timeoutMs}ms` : "Task timed out");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
class TaskGraphTimeoutError extends TaskTimeoutError {
|
|
47
|
+
static type = "TaskGraphTimeoutError";
|
|
48
|
+
constructor(timeoutMs) {
|
|
49
|
+
super(timeoutMs);
|
|
50
|
+
this.message = timeoutMs ? `Graph execution timed out after ${timeoutMs}ms` : "Graph execution timed out";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class TaskFailedError extends TaskError {
|
|
55
|
+
static type = "TaskFailedError";
|
|
56
|
+
constructor(message = "Task failed") {
|
|
57
|
+
super(message);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
class JobTaskFailedError extends TaskFailedError {
|
|
62
|
+
static type = "JobTaskFailedError";
|
|
63
|
+
jobError;
|
|
64
|
+
constructor(err) {
|
|
65
|
+
super(String(err));
|
|
66
|
+
this.jobError = err;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
class TaskJSONError extends TaskError {
|
|
71
|
+
static type = "TaskJSONError";
|
|
72
|
+
constructor(message = "Error converting JSON to a Task") {
|
|
73
|
+
super(message);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
class TaskInvalidInputError extends TaskError {
|
|
78
|
+
static type = "TaskInvalidInputError";
|
|
79
|
+
constructor(message = "Invalid input data") {
|
|
80
|
+
super(message);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
class TaskEntitlementError extends TaskError {
|
|
85
|
+
static type = "TaskEntitlementError";
|
|
86
|
+
constructor(message = "Required entitlements denied") {
|
|
87
|
+
super(message);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
class TaskSerializationError extends TaskError {
|
|
92
|
+
static type = "TaskSerializationError";
|
|
93
|
+
constructor(taskType) {
|
|
94
|
+
super(`Task "${taskType}" cannot be serialized: config contains non-serializable values. ` + `Use a declarative config alternative or remove function-valued config properties.`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
6
98
|
// src/task/TaskTypes.ts
|
|
7
99
|
var TaskStatus = {
|
|
8
100
|
PENDING: "PENDING",
|
|
@@ -49,6 +141,21 @@ var TaskConfigSchema = {
|
|
|
49
141
|
additionalProperties: false
|
|
50
142
|
};
|
|
51
143
|
|
|
144
|
+
// src/task-graph/TransformRegistry.ts
|
|
145
|
+
import { createServiceToken, globalServiceRegistry } from "@workglow/util";
|
|
146
|
+
var transformDefs = new Map;
|
|
147
|
+
var TransformRegistry = {
|
|
148
|
+
all: transformDefs,
|
|
149
|
+
registerTransform(def) {
|
|
150
|
+
transformDefs.set(def.id, def);
|
|
151
|
+
},
|
|
152
|
+
unregisterTransform(id) {
|
|
153
|
+
transformDefs.delete(id);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
var TRANSFORM_DEFS = createServiceToken("transform.defs");
|
|
157
|
+
globalServiceRegistry.registerIfAbsent(TRANSFORM_DEFS, () => TransformRegistry.all, true);
|
|
158
|
+
|
|
52
159
|
// src/task-graph/Dataflow.ts
|
|
53
160
|
var DATAFLOW_ALL_PORTS = "*";
|
|
54
161
|
var DATAFLOW_ERROR_PORT = "[error]";
|
|
@@ -178,18 +285,62 @@ class Dataflow {
|
|
|
178
285
|
return result;
|
|
179
286
|
}
|
|
180
287
|
toJSON() {
|
|
181
|
-
|
|
288
|
+
const base = {
|
|
182
289
|
sourceTaskId: this.sourceTaskId,
|
|
183
290
|
sourceTaskPortId: this.sourceTaskPortId,
|
|
184
291
|
targetTaskId: this.targetTaskId,
|
|
185
292
|
targetTaskPortId: this.targetTaskPortId
|
|
186
293
|
};
|
|
294
|
+
if (this._transforms.length > 0) {
|
|
295
|
+
base.transforms = this._transforms.map((s) => ({ id: s.id, params: s.params }));
|
|
296
|
+
}
|
|
297
|
+
return base;
|
|
187
298
|
}
|
|
188
299
|
_compatibilityCache;
|
|
300
|
+
_transforms = [];
|
|
301
|
+
getTransforms() {
|
|
302
|
+
return this._transforms;
|
|
303
|
+
}
|
|
304
|
+
setTransforms(steps) {
|
|
305
|
+
this._transforms = steps.map((s) => ({ id: s.id, params: s.params }));
|
|
306
|
+
this.invalidateCompatibilityCache();
|
|
307
|
+
}
|
|
308
|
+
addTransform(step) {
|
|
309
|
+
this._transforms.push({ id: step.id, params: step.params });
|
|
310
|
+
this.invalidateCompatibilityCache();
|
|
311
|
+
}
|
|
312
|
+
removeTransform(index) {
|
|
313
|
+
this._transforms.splice(index, 1);
|
|
314
|
+
this.invalidateCompatibilityCache();
|
|
315
|
+
}
|
|
316
|
+
async applyTransforms(registry) {
|
|
317
|
+
if (this._transforms.length === 0)
|
|
318
|
+
return;
|
|
319
|
+
const defs = registry.get(TRANSFORM_DEFS);
|
|
320
|
+
let cur = this.value;
|
|
321
|
+
try {
|
|
322
|
+
for (const step of this._transforms) {
|
|
323
|
+
const def = defs.get(step.id);
|
|
324
|
+
if (!def) {
|
|
325
|
+
throw new Error(`Unknown transform: ${step.id}`);
|
|
326
|
+
}
|
|
327
|
+
cur = await def.apply(cur, step.params ?? {});
|
|
328
|
+
}
|
|
329
|
+
this.value = cur;
|
|
330
|
+
} catch (e) {
|
|
331
|
+
const error = e instanceof TaskError ? e : new TaskError(e instanceof Error ? e.message : String(e));
|
|
332
|
+
if (!(e instanceof TaskError) && e instanceof Error && e.stack) {
|
|
333
|
+
error.stack = e.stack;
|
|
334
|
+
}
|
|
335
|
+
this.error = error;
|
|
336
|
+
this.setStatus(TaskStatus.FAILED);
|
|
337
|
+
throw e;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
189
340
|
invalidateCompatibilityCache() {
|
|
190
341
|
this._compatibilityCache = undefined;
|
|
191
342
|
}
|
|
192
|
-
semanticallyCompatible(graph, dataflow) {
|
|
343
|
+
semanticallyCompatible(graph, dataflow, registry) {
|
|
193
344
|
const sourceTask = graph.getTask(dataflow.sourceTaskId);
|
|
194
345
|
const targetTask = graph.getTask(dataflow.targetTaskId);
|
|
195
346
|
const shouldCache = !(sourceTask.constructor.hasDynamicSchemas ?? true) && !(targetTask.constructor.hasDynamicSchemas ?? true);
|
|
@@ -218,7 +369,26 @@ class Dataflow {
|
|
|
218
369
|
if (sourceSchemaProperty === undefined && sourceSchema.additionalProperties === true) {
|
|
219
370
|
sourceSchemaProperty = true;
|
|
220
371
|
}
|
|
221
|
-
|
|
372
|
+
let effectiveSourceSchema = sourceSchemaProperty;
|
|
373
|
+
if (this._transforms.length > 0) {
|
|
374
|
+
const defs = registry ? registry.get(TRANSFORM_DEFS) : TransformRegistry.all;
|
|
375
|
+
try {
|
|
376
|
+
let cur = effectiveSourceSchema === true ? {} : effectiveSourceSchema;
|
|
377
|
+
for (const step of this._transforms) {
|
|
378
|
+
const def = defs.get(step.id);
|
|
379
|
+
if (!def) {
|
|
380
|
+
return "incompatible";
|
|
381
|
+
}
|
|
382
|
+
cur = def.inferOutputSchema(cur, step.params ?? {});
|
|
383
|
+
}
|
|
384
|
+
effectiveSourceSchema = cur;
|
|
385
|
+
} catch {
|
|
386
|
+
if (shouldCache)
|
|
387
|
+
this._compatibilityCache = "incompatible";
|
|
388
|
+
return "incompatible";
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
const result = areSemanticallyCompatible(effectiveSourceSchema, targetSchemaProperty);
|
|
222
392
|
if (shouldCache) {
|
|
223
393
|
this._compatibilityCache = result;
|
|
224
394
|
}
|
|
@@ -637,7 +807,8 @@ function computeGraphInputSchema(graph, options) {
|
|
|
637
807
|
for (const [inputName, inputProp] of Object.entries(taskProperties)) {
|
|
638
808
|
if (!properties[inputName]) {
|
|
639
809
|
properties[inputName] = inputProp;
|
|
640
|
-
|
|
810
|
+
const isRequired = taskInputSchema.required?.includes(inputName) === true && !(task.defaults && task.defaults[inputName] !== undefined);
|
|
811
|
+
if (isRequired) {
|
|
641
812
|
required.push(inputName);
|
|
642
813
|
}
|
|
643
814
|
if (trackOrigins) {
|
|
@@ -950,6 +1121,7 @@ import { DirectedAcyclicGraph } from "@workglow/util/graph";
|
|
|
950
1121
|
|
|
951
1122
|
// src/task/GraphAsTask.ts
|
|
952
1123
|
import { getLogger as getLogger4 } from "@workglow/util";
|
|
1124
|
+
import { CycleError } from "@workglow/util/graph";
|
|
953
1125
|
import { compileSchema as compileSchema2 } from "@workglow/util/schema";
|
|
954
1126
|
|
|
955
1127
|
// src/task-graph/TaskGraphRunner.ts
|
|
@@ -957,15 +1129,15 @@ import {
|
|
|
957
1129
|
collectPropertyValues,
|
|
958
1130
|
getLogger as getLogger3,
|
|
959
1131
|
getTelemetryProvider as getTelemetryProvider2,
|
|
960
|
-
globalServiceRegistry as
|
|
1132
|
+
globalServiceRegistry as globalServiceRegistry3,
|
|
961
1133
|
ServiceRegistry as ServiceRegistry2,
|
|
962
1134
|
SpanStatusCode as SpanStatusCode2,
|
|
963
1135
|
uuid4 as uuid43
|
|
964
1136
|
} from "@workglow/util";
|
|
965
1137
|
|
|
966
1138
|
// src/storage/TaskOutputRepository.ts
|
|
967
|
-
import { createServiceToken, EventEmitter as EventEmitter2 } from "@workglow/util";
|
|
968
|
-
var TASK_OUTPUT_REPOSITORY =
|
|
1139
|
+
import { createServiceToken as createServiceToken2, EventEmitter as EventEmitter2 } from "@workglow/util";
|
|
1140
|
+
var TASK_OUTPUT_REPOSITORY = createServiceToken2("taskgraph.taskOutputRepository");
|
|
969
1141
|
|
|
970
1142
|
class TaskOutputRepository {
|
|
971
1143
|
outputCompression;
|
|
@@ -1067,103 +1239,11 @@ function getNestedValue(obj, path) {
|
|
|
1067
1239
|
import { deepEqual, EventEmitter as EventEmitter3, uuid4 as uuid42 } from "@workglow/util";
|
|
1068
1240
|
import { compileSchema } from "@workglow/util/schema";
|
|
1069
1241
|
|
|
1070
|
-
// src/task/TaskError.ts
|
|
1071
|
-
import { BaseError } from "@workglow/util";
|
|
1072
|
-
|
|
1073
|
-
class TaskError extends BaseError {
|
|
1074
|
-
static type = "TaskError";
|
|
1075
|
-
taskType;
|
|
1076
|
-
taskId;
|
|
1077
|
-
constructor(message) {
|
|
1078
|
-
super(message);
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
class TaskConfigurationError extends TaskError {
|
|
1083
|
-
static type = "TaskConfigurationError";
|
|
1084
|
-
constructor(message) {
|
|
1085
|
-
super(message);
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
class WorkflowError extends TaskError {
|
|
1090
|
-
static type = "WorkflowError";
|
|
1091
|
-
constructor(message) {
|
|
1092
|
-
super(message);
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
class TaskAbortedError extends TaskError {
|
|
1097
|
-
static type = "TaskAbortedError";
|
|
1098
|
-
constructor(message = "Task aborted") {
|
|
1099
|
-
super(message);
|
|
1100
|
-
}
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
class TaskTimeoutError extends TaskAbortedError {
|
|
1104
|
-
static type = "TaskTimeoutError";
|
|
1105
|
-
constructor(timeoutMs) {
|
|
1106
|
-
super(timeoutMs ? `Task timed out after ${timeoutMs}ms` : "Task timed out");
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1110
|
-
class TaskGraphTimeoutError extends TaskTimeoutError {
|
|
1111
|
-
static type = "TaskGraphTimeoutError";
|
|
1112
|
-
constructor(timeoutMs) {
|
|
1113
|
-
super(timeoutMs);
|
|
1114
|
-
this.message = timeoutMs ? `Graph execution timed out after ${timeoutMs}ms` : "Graph execution timed out";
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
class TaskFailedError extends TaskError {
|
|
1119
|
-
static type = "TaskFailedError";
|
|
1120
|
-
constructor(message = "Task failed") {
|
|
1121
|
-
super(message);
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
class JobTaskFailedError extends TaskFailedError {
|
|
1126
|
-
static type = "JobTaskFailedError";
|
|
1127
|
-
jobError;
|
|
1128
|
-
constructor(err) {
|
|
1129
|
-
super(String(err));
|
|
1130
|
-
this.jobError = err;
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
class TaskJSONError extends TaskError {
|
|
1135
|
-
static type = "TaskJSONError";
|
|
1136
|
-
constructor(message = "Error converting JSON to a Task") {
|
|
1137
|
-
super(message);
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
class TaskInvalidInputError extends TaskError {
|
|
1142
|
-
static type = "TaskInvalidInputError";
|
|
1143
|
-
constructor(message = "Invalid input data") {
|
|
1144
|
-
super(message);
|
|
1145
|
-
}
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
class TaskEntitlementError extends TaskError {
|
|
1149
|
-
static type = "TaskEntitlementError";
|
|
1150
|
-
constructor(message = "Required entitlements denied") {
|
|
1151
|
-
super(message);
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
class TaskSerializationError extends TaskError {
|
|
1156
|
-
static type = "TaskSerializationError";
|
|
1157
|
-
constructor(taskType) {
|
|
1158
|
-
super(`Task "${taskType}" cannot be serialized: config contains non-serializable values. ` + `Use a declarative config alternative or remove function-valued config properties.`);
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
1242
|
// src/task/TaskRunner.ts
|
|
1163
1243
|
import {
|
|
1164
1244
|
getLogger,
|
|
1165
1245
|
getTelemetryProvider,
|
|
1166
|
-
globalServiceRegistry,
|
|
1246
|
+
globalServiceRegistry as globalServiceRegistry2,
|
|
1167
1247
|
SpanStatusCode
|
|
1168
1248
|
} from "@workglow/util";
|
|
1169
1249
|
|
|
@@ -1279,7 +1359,7 @@ class TaskRunner {
|
|
|
1279
1359
|
task;
|
|
1280
1360
|
abortController;
|
|
1281
1361
|
outputCache;
|
|
1282
|
-
registry =
|
|
1362
|
+
registry = globalServiceRegistry2;
|
|
1283
1363
|
resourceScope;
|
|
1284
1364
|
inputStreams;
|
|
1285
1365
|
timeoutTimer;
|
|
@@ -1550,7 +1630,7 @@ class TaskRunner {
|
|
|
1550
1630
|
});
|
|
1551
1631
|
const cache = config.outputCache ?? this.task.runConfig?.outputCache;
|
|
1552
1632
|
if (cache === true) {
|
|
1553
|
-
let instance =
|
|
1633
|
+
let instance = globalServiceRegistry2.get(TASK_OUTPUT_REPOSITORY);
|
|
1554
1634
|
this.outputCache = instance;
|
|
1555
1635
|
} else if (cache === false) {
|
|
1556
1636
|
this.outputCache = undefined;
|
|
@@ -2437,7 +2517,7 @@ class ConditionalTask extends Task {
|
|
|
2437
2517
|
}
|
|
2438
2518
|
|
|
2439
2519
|
// src/task/EntitlementEnforcer.ts
|
|
2440
|
-
import { createServiceToken as
|
|
2520
|
+
import { createServiceToken as createServiceToken4 } from "@workglow/util";
|
|
2441
2521
|
|
|
2442
2522
|
// src/task/EntitlementPolicy.ts
|
|
2443
2523
|
var EMPTY_POLICY = Object.freeze({
|
|
@@ -2474,9 +2554,14 @@ function evaluatePolicy(policy, required) {
|
|
|
2474
2554
|
}
|
|
2475
2555
|
return results;
|
|
2476
2556
|
}
|
|
2557
|
+
function can(policy, id, resources) {
|
|
2558
|
+
const required = resources !== undefined ? { id, resources } : { id };
|
|
2559
|
+
const [result] = evaluatePolicy(policy, { entitlements: [required] });
|
|
2560
|
+
return result;
|
|
2561
|
+
}
|
|
2477
2562
|
|
|
2478
2563
|
// src/task/EntitlementResolver.ts
|
|
2479
|
-
import { createServiceToken as
|
|
2564
|
+
import { createServiceToken as createServiceToken3 } from "@workglow/util";
|
|
2480
2565
|
var PERMISSIVE_RESOLVER = {
|
|
2481
2566
|
lookup: () => "grant",
|
|
2482
2567
|
prompt: async () => "grant",
|
|
@@ -2487,9 +2572,19 @@ var DENY_ALL_RESOLVER = {
|
|
|
2487
2572
|
prompt: async () => "deny",
|
|
2488
2573
|
save: () => {}
|
|
2489
2574
|
};
|
|
2490
|
-
var ENTITLEMENT_RESOLVER =
|
|
2575
|
+
var ENTITLEMENT_RESOLVER = createServiceToken3("workglow.entitlementResolver");
|
|
2491
2576
|
|
|
2492
2577
|
// src/task/EntitlementEnforcer.ts
|
|
2578
|
+
function formatEntitlementDenial(denial) {
|
|
2579
|
+
switch (denial.reason) {
|
|
2580
|
+
case "policy-deny":
|
|
2581
|
+
return `${denial.entitlement.id} (denied by rule ${denial.matchedRule.id})`;
|
|
2582
|
+
case "user-deny":
|
|
2583
|
+
return `${denial.entitlement.id} (denied by user)`;
|
|
2584
|
+
case "default-deny":
|
|
2585
|
+
return `${denial.entitlement.id} (no matching grant)`;
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2493
2588
|
var PERMISSIVE_ENFORCER = {
|
|
2494
2589
|
checkAll: async () => [],
|
|
2495
2590
|
checkTask: async () => []
|
|
@@ -2500,24 +2595,35 @@ function createPolicyEnforcer(policy, resolver = PERMISSIVE_RESOLVER) {
|
|
|
2500
2595
|
const denied = [];
|
|
2501
2596
|
for (const result of results) {
|
|
2502
2597
|
if (result.verdict === "denied") {
|
|
2503
|
-
|
|
2598
|
+
if (result.matchedRule) {
|
|
2599
|
+
denied.push({
|
|
2600
|
+
entitlement: result.entitlement,
|
|
2601
|
+
reason: "policy-deny",
|
|
2602
|
+
matchedRule: result.matchedRule
|
|
2603
|
+
});
|
|
2604
|
+
} else {
|
|
2605
|
+
denied.push({ entitlement: result.entitlement, reason: "default-deny" });
|
|
2606
|
+
}
|
|
2504
2607
|
} else if (result.verdict === "ask") {
|
|
2505
2608
|
const request = {
|
|
2506
2609
|
entitlement: result.entitlement,
|
|
2507
2610
|
taskType: taskType ?? "unknown",
|
|
2508
2611
|
taskId: taskId ?? "unknown"
|
|
2509
2612
|
};
|
|
2510
|
-
|
|
2511
|
-
if (
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
}
|
|
2515
|
-
continue;
|
|
2613
|
+
let answer = resolver.lookup(request);
|
|
2614
|
+
if (answer === undefined) {
|
|
2615
|
+
answer = await resolver.prompt(request);
|
|
2616
|
+
resolver.save(request, answer);
|
|
2516
2617
|
}
|
|
2517
|
-
const answer = await resolver.prompt(request);
|
|
2518
|
-
resolver.save(request, answer);
|
|
2519
2618
|
if (answer === "deny") {
|
|
2520
|
-
|
|
2619
|
+
if (!result.matchedRule) {
|
|
2620
|
+
throw new Error(`Invariant violation: ask verdict for "${result.entitlement.id}" is missing matchedRule`);
|
|
2621
|
+
}
|
|
2622
|
+
denied.push({
|
|
2623
|
+
entitlement: result.entitlement,
|
|
2624
|
+
reason: "user-deny",
|
|
2625
|
+
matchedRule: result.matchedRule
|
|
2626
|
+
});
|
|
2521
2627
|
}
|
|
2522
2628
|
}
|
|
2523
2629
|
}
|
|
@@ -2539,7 +2645,7 @@ function createScopedEnforcer(grants) {
|
|
|
2539
2645
|
function createGrantListEnforcer(grants) {
|
|
2540
2646
|
return createScopedEnforcer(grants.map((id) => ({ id })));
|
|
2541
2647
|
}
|
|
2542
|
-
var ENTITLEMENT_ENFORCER =
|
|
2648
|
+
var ENTITLEMENT_ENFORCER = createServiceToken4("workglow.entitlementEnforcer");
|
|
2543
2649
|
|
|
2544
2650
|
// src/task-graph/TaskGraphScheduler.ts
|
|
2545
2651
|
class TopologicalScheduler {
|
|
@@ -2703,7 +2809,7 @@ class TaskGraphRunner {
|
|
|
2703
2809
|
graph;
|
|
2704
2810
|
outputCache;
|
|
2705
2811
|
accumulateLeafOutputs = true;
|
|
2706
|
-
registry =
|
|
2812
|
+
registry = globalServiceRegistry3;
|
|
2707
2813
|
resourceScope;
|
|
2708
2814
|
abortController;
|
|
2709
2815
|
inProgressTasks = new Map;
|
|
@@ -2785,6 +2891,21 @@ class TaskGraphRunner {
|
|
|
2785
2891
|
}
|
|
2786
2892
|
async runGraphReactive(input = {}, config) {
|
|
2787
2893
|
await this.handleStartReactive(config);
|
|
2894
|
+
const telemetry = getTelemetryProvider2();
|
|
2895
|
+
const telemetryEnabled = telemetry.isEnabled;
|
|
2896
|
+
const reactiveRunId = telemetryEnabled ? uuid43() : "";
|
|
2897
|
+
let reactiveSpan;
|
|
2898
|
+
if (telemetryEnabled) {
|
|
2899
|
+
reactiveSpan = telemetry.startSpan("workglow.graph.runReactive", {
|
|
2900
|
+
attributes: {
|
|
2901
|
+
"workglow.graph.reactive.run_id": reactiveRunId,
|
|
2902
|
+
"workglow.graph.task_count": this.graph.getTasks().length,
|
|
2903
|
+
"workglow.graph.dataflow_count": this.graph.getDataflows().length
|
|
2904
|
+
}
|
|
2905
|
+
});
|
|
2906
|
+
}
|
|
2907
|
+
const t0 = telemetryEnabled ? performance.now() : 0;
|
|
2908
|
+
const taskTimings = [];
|
|
2788
2909
|
const results = [];
|
|
2789
2910
|
try {
|
|
2790
2911
|
for await (const task of this.reactiveScheduler.tasks()) {
|
|
@@ -2794,20 +2915,68 @@ class TaskGraphRunner {
|
|
|
2794
2915
|
this.copyInputFromEdgesToNode(task);
|
|
2795
2916
|
}
|
|
2796
2917
|
const taskInput = isRootTask ? input : {};
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2918
|
+
if (telemetryEnabled) {
|
|
2919
|
+
const taskType = String(task.constructor.runtype || task.constructor.type || "?");
|
|
2920
|
+
const tReactive = performance.now();
|
|
2921
|
+
const taskResult = await task.runReactive(taskInput);
|
|
2922
|
+
const runReactiveMs = performance.now() - tReactive;
|
|
2923
|
+
const tPush = performance.now();
|
|
2924
|
+
await this.pushOutputFromNodeToEdges(task, taskResult);
|
|
2925
|
+
const pushOutputMs = performance.now() - tPush;
|
|
2926
|
+
taskTimings.push({ id: task.id, type: taskType, runReactiveMs, pushOutputMs });
|
|
2927
|
+
if (this.graph.getTargetDataflows(task.id).length === 0) {
|
|
2928
|
+
results.push({
|
|
2929
|
+
id: task.id,
|
|
2930
|
+
type: task.constructor.runtype || task.constructor.type,
|
|
2931
|
+
data: taskResult
|
|
2932
|
+
});
|
|
2933
|
+
}
|
|
2934
|
+
} else {
|
|
2935
|
+
const taskResult = await task.runReactive(taskInput);
|
|
2936
|
+
await this.pushOutputFromNodeToEdges(task, taskResult);
|
|
2937
|
+
if (this.graph.getTargetDataflows(task.id).length === 0) {
|
|
2938
|
+
results.push({
|
|
2939
|
+
id: task.id,
|
|
2940
|
+
type: task.constructor.runtype || task.constructor.type,
|
|
2941
|
+
data: taskResult
|
|
2942
|
+
});
|
|
2943
|
+
}
|
|
2805
2944
|
}
|
|
2806
2945
|
}
|
|
2807
2946
|
await this.handleCompleteReactive();
|
|
2947
|
+
if (reactiveSpan) {
|
|
2948
|
+
const totalMs = performance.now() - t0;
|
|
2949
|
+
reactiveSpan.setAttributes({
|
|
2950
|
+
"workglow.graph.reactive.duration_ms": Math.round(totalMs * 1000) / 1000,
|
|
2951
|
+
"workglow.graph.reactive.tasks_executed": taskTimings.length
|
|
2952
|
+
});
|
|
2953
|
+
reactiveSpan.setStatus(SpanStatusCode2.OK);
|
|
2954
|
+
reactiveSpan.end();
|
|
2955
|
+
getLogger3().debug("task graph runReactive timings", {
|
|
2956
|
+
reactiveRunId,
|
|
2957
|
+
totalMs: Math.round(totalMs * 1000) / 1000,
|
|
2958
|
+
taskTimings
|
|
2959
|
+
});
|
|
2960
|
+
}
|
|
2808
2961
|
return this.filterLeafResults(results);
|
|
2809
2962
|
} catch (error) {
|
|
2810
2963
|
await this.handleErrorReactive();
|
|
2964
|
+
if (reactiveSpan) {
|
|
2965
|
+
const totalMs = performance.now() - t0;
|
|
2966
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2967
|
+
reactiveSpan.setAttributes({
|
|
2968
|
+
"workglow.graph.reactive.duration_ms": Math.round(totalMs * 1000) / 1000,
|
|
2969
|
+
"workglow.graph.reactive.tasks_executed": taskTimings.length
|
|
2970
|
+
});
|
|
2971
|
+
reactiveSpan.setStatus(SpanStatusCode2.ERROR, message);
|
|
2972
|
+
reactiveSpan.end();
|
|
2973
|
+
getLogger3().debug("task graph runReactive failed", {
|
|
2974
|
+
reactiveRunId,
|
|
2975
|
+
totalMs: Math.round(totalMs * 1000) / 1000,
|
|
2976
|
+
taskTimings,
|
|
2977
|
+
error
|
|
2978
|
+
});
|
|
2979
|
+
}
|
|
2811
2980
|
throw error;
|
|
2812
2981
|
}
|
|
2813
2982
|
}
|
|
@@ -2875,13 +3044,17 @@ class TaskGraphRunner {
|
|
|
2875
3044
|
async pushOutputFromNodeToEdges(node, results) {
|
|
2876
3045
|
const dataflows = this.graph.getTargetDataflows(node.id);
|
|
2877
3046
|
for (const dataflow of dataflows) {
|
|
2878
|
-
|
|
3047
|
+
if (dataflow.stream !== undefined)
|
|
3048
|
+
continue;
|
|
3049
|
+
const compatibility = dataflow.semanticallyCompatible(this.graph, dataflow, this.registry);
|
|
2879
3050
|
if (compatibility === "static") {
|
|
2880
3051
|
dataflow.setPortData(results);
|
|
3052
|
+
await dataflow.applyTransforms(this.registry);
|
|
2881
3053
|
} else if (compatibility === "runtime") {
|
|
2882
3054
|
const task = this.graph.getTask(dataflow.targetTaskId);
|
|
2883
3055
|
const narrowed = await task.narrowInput({ ...results }, this.registry);
|
|
2884
3056
|
dataflow.setPortData(narrowed);
|
|
3057
|
+
await dataflow.applyTransforms(this.registry);
|
|
2885
3058
|
} else {
|
|
2886
3059
|
const resultsKeys = Object.keys(results);
|
|
2887
3060
|
if (resultsKeys.length > 0) {
|
|
@@ -2907,6 +3080,8 @@ class TaskGraphRunner {
|
|
|
2907
3080
|
}
|
|
2908
3081
|
const activeBranches = node.getActiveBranches();
|
|
2909
3082
|
for (const dataflow of dataflows) {
|
|
3083
|
+
if (dataflow.status === TaskStatus.FAILED)
|
|
3084
|
+
continue;
|
|
2910
3085
|
const branchId = portToBranch.get(dataflow.sourceTaskPortId);
|
|
2911
3086
|
if (branchId !== undefined) {
|
|
2912
3087
|
if (activeBranches.has(branchId)) {
|
|
@@ -2922,6 +3097,8 @@ class TaskGraphRunner {
|
|
|
2922
3097
|
return;
|
|
2923
3098
|
}
|
|
2924
3099
|
dataflows.forEach((dataflow) => {
|
|
3100
|
+
if (dataflow.status === TaskStatus.FAILED)
|
|
3101
|
+
return;
|
|
2925
3102
|
dataflow.setStatus(effectiveStatus);
|
|
2926
3103
|
});
|
|
2927
3104
|
}
|
|
@@ -3025,7 +3202,7 @@ class TaskGraphRunner {
|
|
|
3025
3202
|
if (this.activeEnforcer && task.constructor.hasDynamicEntitlements) {
|
|
3026
3203
|
const denied = await this.activeEnforcer.checkTask(task);
|
|
3027
3204
|
if (denied.length > 0) {
|
|
3028
|
-
throw new TaskEntitlementError(`Task ${task.constructor.type} denied entitlements: ${denied.map(
|
|
3205
|
+
throw new TaskEntitlementError(`Task ${task.constructor.type} denied entitlements: ${denied.map(formatEntitlementDenial).join(", ")}`);
|
|
3029
3206
|
}
|
|
3030
3207
|
}
|
|
3031
3208
|
if (isStreamable) {
|
|
@@ -3046,10 +3223,13 @@ class TaskGraphRunner {
|
|
|
3046
3223
|
}
|
|
3047
3224
|
async awaitStreamInputs(task) {
|
|
3048
3225
|
const dataflows = this.graph.getSourceDataflows(task.id);
|
|
3049
|
-
const
|
|
3050
|
-
if (
|
|
3051
|
-
|
|
3052
|
-
|
|
3226
|
+
const streamingDataflows = dataflows.filter((df) => df.stream !== undefined);
|
|
3227
|
+
if (streamingDataflows.length === 0)
|
|
3228
|
+
return;
|
|
3229
|
+
await Promise.all(streamingDataflows.map(async (df) => {
|
|
3230
|
+
await df.awaitStreamValue();
|
|
3231
|
+
await df.applyTransforms(this.registry);
|
|
3232
|
+
}));
|
|
3053
3233
|
}
|
|
3054
3234
|
async runStreamingTask(task, input) {
|
|
3055
3235
|
const streamMode = getOutputStreamMode(task.outputSchema());
|
|
@@ -3184,7 +3364,7 @@ class TaskGraphRunner {
|
|
|
3184
3364
|
if (config?.registry !== undefined) {
|
|
3185
3365
|
this.registry = config.registry;
|
|
3186
3366
|
} else if (this.registry === undefined) {
|
|
3187
|
-
this.registry = new ServiceRegistry2(
|
|
3367
|
+
this.registry = new ServiceRegistry2(globalServiceRegistry3.container.createChildContainer());
|
|
3188
3368
|
}
|
|
3189
3369
|
if (config?.resourceScope !== undefined) {
|
|
3190
3370
|
this.resourceScope = config.resourceScope;
|
|
@@ -3248,7 +3428,7 @@ class TaskGraphRunner {
|
|
|
3248
3428
|
const enforcer = this.registry.get(ENTITLEMENT_ENFORCER);
|
|
3249
3429
|
const denied = await enforcer.checkAll(computeGraphEntitlements(this.graph));
|
|
3250
3430
|
if (denied.length > 0) {
|
|
3251
|
-
throw new TaskEntitlementError(`Denied entitlements: ${denied.map(
|
|
3431
|
+
throw new TaskEntitlementError(`Denied entitlements: ${denied.map(formatEntitlementDenial).join(", ")}`);
|
|
3252
3432
|
}
|
|
3253
3433
|
this.activeEnforcer = enforcer;
|
|
3254
3434
|
} else {
|
|
@@ -3592,6 +3772,18 @@ class GraphAsTask extends Task {
|
|
|
3592
3772
|
yield { type: "finish", data: input };
|
|
3593
3773
|
}
|
|
3594
3774
|
}
|
|
3775
|
+
validateAcyclic() {
|
|
3776
|
+
if (!this.hasChildren())
|
|
3777
|
+
return;
|
|
3778
|
+
if (!this.subGraph.isAcyclic()) {
|
|
3779
|
+
throw new CycleError(`${this.type} (${this.id}): subgraph contains a cycle \u2014 loop tasks must wrap an acyclic subgraph.`);
|
|
3780
|
+
}
|
|
3781
|
+
for (const child of this.subGraph.getTasks()) {
|
|
3782
|
+
if (child instanceof GraphAsTask) {
|
|
3783
|
+
child.validateAcyclic();
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3595
3787
|
regenerateGraph() {
|
|
3596
3788
|
this._inputSchemaNode = undefined;
|
|
3597
3789
|
this.events.emit("regenerate");
|
|
@@ -3742,7 +3934,7 @@ function convertPipeFunctionToTask(fn, config) {
|
|
|
3742
3934
|
properties: {
|
|
3743
3935
|
[DATAFLOW_ALL_PORTS]: {}
|
|
3744
3936
|
},
|
|
3745
|
-
additionalProperties:
|
|
3937
|
+
additionalProperties: true
|
|
3746
3938
|
};
|
|
3747
3939
|
};
|
|
3748
3940
|
static outputSchema = () => {
|
|
@@ -3751,7 +3943,7 @@ function convertPipeFunctionToTask(fn, config) {
|
|
|
3751
3943
|
properties: {
|
|
3752
3944
|
[DATAFLOW_ALL_PORTS]: {}
|
|
3753
3945
|
},
|
|
3754
|
-
additionalProperties:
|
|
3946
|
+
additionalProperties: true
|
|
3755
3947
|
};
|
|
3756
3948
|
};
|
|
3757
3949
|
static cacheable = false;
|
|
@@ -3860,6 +4052,9 @@ class TaskGraph {
|
|
|
3860
4052
|
topologicallySortedNodes() {
|
|
3861
4053
|
return this._dag.topologicallySortedNodes();
|
|
3862
4054
|
}
|
|
4055
|
+
isAcyclic() {
|
|
4056
|
+
return this._dag.isAcyclic();
|
|
4057
|
+
}
|
|
3863
4058
|
addTask(task, config) {
|
|
3864
4059
|
return this._dag.addNode(ensureTask(task, config));
|
|
3865
4060
|
}
|
|
@@ -4133,7 +4328,315 @@ function serialGraph(tasks, inputHandle, outputHandle) {
|
|
|
4133
4328
|
return graph;
|
|
4134
4329
|
}
|
|
4135
4330
|
// src/task-graph/Workflow.ts
|
|
4136
|
-
import { EventEmitter as EventEmitter5, getLogger as getLogger5, uuid4 as
|
|
4331
|
+
import { EventEmitter as EventEmitter5, getLogger as getLogger5, uuid4 as uuid46 } from "@workglow/util";
|
|
4332
|
+
|
|
4333
|
+
// src/task-graph/autoConnect.ts
|
|
4334
|
+
function autoConnect(graph, sourceTask, targetTask, options) {
|
|
4335
|
+
const matches = new Map;
|
|
4336
|
+
const sourceSchema = sourceTask.outputSchema();
|
|
4337
|
+
const targetSchema = targetTask.inputSchema();
|
|
4338
|
+
const providedInputKeys = options?.providedInputKeys ?? new Set;
|
|
4339
|
+
const connectedInputKeys = options?.connectedInputKeys ?? new Set;
|
|
4340
|
+
const earlierTasks = options?.earlierTasks ?? [];
|
|
4341
|
+
const dryRun = options?.dryRun ?? false;
|
|
4342
|
+
const addDataflow = (df) => {
|
|
4343
|
+
if (!dryRun)
|
|
4344
|
+
graph.addDataflow(df);
|
|
4345
|
+
};
|
|
4346
|
+
const getSpecificTypeIdentifiers = (schema) => {
|
|
4347
|
+
const formats = new Set;
|
|
4348
|
+
const ids = new Set;
|
|
4349
|
+
if (typeof schema === "boolean") {
|
|
4350
|
+
return { formats, ids };
|
|
4351
|
+
}
|
|
4352
|
+
const extractFromSchema = (s) => {
|
|
4353
|
+
if (!s || typeof s !== "object" || Array.isArray(s))
|
|
4354
|
+
return;
|
|
4355
|
+
if (s.format)
|
|
4356
|
+
formats.add(s.format);
|
|
4357
|
+
if (s.$id)
|
|
4358
|
+
ids.add(s.$id);
|
|
4359
|
+
};
|
|
4360
|
+
extractFromSchema(schema);
|
|
4361
|
+
const checkUnion = (schemas) => {
|
|
4362
|
+
if (!schemas)
|
|
4363
|
+
return;
|
|
4364
|
+
for (const s of schemas) {
|
|
4365
|
+
if (typeof s === "boolean")
|
|
4366
|
+
continue;
|
|
4367
|
+
extractFromSchema(s);
|
|
4368
|
+
if (s.items && typeof s.items === "object" && !Array.isArray(s.items)) {
|
|
4369
|
+
extractFromSchema(s.items);
|
|
4370
|
+
}
|
|
4371
|
+
}
|
|
4372
|
+
};
|
|
4373
|
+
checkUnion(schema.oneOf);
|
|
4374
|
+
checkUnion(schema.anyOf);
|
|
4375
|
+
if (schema.items && typeof schema.items === "object" && !Array.isArray(schema.items)) {
|
|
4376
|
+
extractFromSchema(schema.items);
|
|
4377
|
+
}
|
|
4378
|
+
return { formats, ids };
|
|
4379
|
+
};
|
|
4380
|
+
const isTypeCompatible = (fromPortOutputSchema, toPortInputSchema, requireSpecificType = false) => {
|
|
4381
|
+
if (typeof fromPortOutputSchema === "boolean" || typeof toPortInputSchema === "boolean") {
|
|
4382
|
+
return fromPortOutputSchema === true && toPortInputSchema === true;
|
|
4383
|
+
}
|
|
4384
|
+
const outputIds = getSpecificTypeIdentifiers(fromPortOutputSchema);
|
|
4385
|
+
const inputIds = getSpecificTypeIdentifiers(toPortInputSchema);
|
|
4386
|
+
for (const format of outputIds.formats) {
|
|
4387
|
+
if (inputIds.formats.has(format)) {
|
|
4388
|
+
return true;
|
|
4389
|
+
}
|
|
4390
|
+
}
|
|
4391
|
+
for (const id of outputIds.ids) {
|
|
4392
|
+
if (inputIds.ids.has(id)) {
|
|
4393
|
+
return true;
|
|
4394
|
+
}
|
|
4395
|
+
}
|
|
4396
|
+
if (requireSpecificType) {
|
|
4397
|
+
return false;
|
|
4398
|
+
}
|
|
4399
|
+
const idTypeBlank = fromPortOutputSchema.$id === undefined && toPortInputSchema.$id === undefined;
|
|
4400
|
+
if (!idTypeBlank)
|
|
4401
|
+
return false;
|
|
4402
|
+
if (fromPortOutputSchema.type === toPortInputSchema.type)
|
|
4403
|
+
return true;
|
|
4404
|
+
const matchesOneOf = toPortInputSchema.oneOf?.some((schema) => {
|
|
4405
|
+
if (typeof schema === "boolean")
|
|
4406
|
+
return schema;
|
|
4407
|
+
return schema.type === fromPortOutputSchema.type;
|
|
4408
|
+
}) ?? false;
|
|
4409
|
+
const matchesAnyOf = toPortInputSchema.anyOf?.some((schema) => {
|
|
4410
|
+
if (typeof schema === "boolean")
|
|
4411
|
+
return schema;
|
|
4412
|
+
return schema.type === fromPortOutputSchema.type;
|
|
4413
|
+
}) ?? false;
|
|
4414
|
+
return matchesOneOf || matchesAnyOf;
|
|
4415
|
+
};
|
|
4416
|
+
const makeMatch = (fromSchema, toSchema, fromTaskId, toTaskId, comparator) => {
|
|
4417
|
+
if (typeof fromSchema === "object") {
|
|
4418
|
+
if (toSchema === true || typeof toSchema === "object" && toSchema.additionalProperties === true) {
|
|
4419
|
+
const outputKeys = Object.keys(fromSchema.properties || {});
|
|
4420
|
+
if (outputKeys.length > 0) {
|
|
4421
|
+
for (const fromOutputPortId of outputKeys) {
|
|
4422
|
+
if (matches.has(fromOutputPortId))
|
|
4423
|
+
continue;
|
|
4424
|
+
matches.set(fromOutputPortId, fromOutputPortId);
|
|
4425
|
+
addDataflow(new Dataflow(fromTaskId, fromOutputPortId, toTaskId, fromOutputPortId));
|
|
4426
|
+
}
|
|
4427
|
+
} else if (fromSchema.additionalProperties === true) {
|
|
4428
|
+
const sourceGraphTask = graph.getTask(fromTaskId);
|
|
4429
|
+
if (sourceGraphTask && sourceGraphTask.constructor.passthroughInputsToOutputs === true) {
|
|
4430
|
+
const incomingDfs = graph.getSourceDataflows(fromTaskId);
|
|
4431
|
+
for (const df of incomingDfs) {
|
|
4432
|
+
const portId = df.targetTaskPortId;
|
|
4433
|
+
if (portId === DATAFLOW_ALL_PORTS)
|
|
4434
|
+
continue;
|
|
4435
|
+
if (matches.has(portId))
|
|
4436
|
+
continue;
|
|
4437
|
+
if (connectedInputKeys.has(portId))
|
|
4438
|
+
continue;
|
|
4439
|
+
matches.set(portId, portId);
|
|
4440
|
+
addDataflow(new Dataflow(fromTaskId, portId, toTaskId, portId));
|
|
4441
|
+
}
|
|
4442
|
+
}
|
|
4443
|
+
}
|
|
4444
|
+
return;
|
|
4445
|
+
}
|
|
4446
|
+
}
|
|
4447
|
+
if (typeof fromSchema === "object" && fromSchema.additionalProperties === true && typeof toSchema === "object" && (sourceTask.type === "InputTask" || sourceTask.type === "OutputTask")) {
|
|
4448
|
+
for (const toInputPortId of Object.keys(toSchema.properties || {})) {
|
|
4449
|
+
if (matches.has(toInputPortId))
|
|
4450
|
+
continue;
|
|
4451
|
+
if (connectedInputKeys.has(toInputPortId))
|
|
4452
|
+
continue;
|
|
4453
|
+
matches.set(toInputPortId, toInputPortId);
|
|
4454
|
+
addDataflow(new Dataflow(fromTaskId, toInputPortId, toTaskId, toInputPortId));
|
|
4455
|
+
}
|
|
4456
|
+
return;
|
|
4457
|
+
}
|
|
4458
|
+
if (typeof fromSchema === "boolean" || typeof toSchema === "boolean") {
|
|
4459
|
+
return;
|
|
4460
|
+
}
|
|
4461
|
+
for (const [toInputPortId, toPortInputSchema] of Object.entries(toSchema.properties || {})) {
|
|
4462
|
+
if (matches.has(toInputPortId))
|
|
4463
|
+
continue;
|
|
4464
|
+
if (connectedInputKeys.has(toInputPortId))
|
|
4465
|
+
continue;
|
|
4466
|
+
const candidates = [];
|
|
4467
|
+
for (const [fromOutputPortId, fromPortOutputSchema] of Object.entries(fromSchema.properties || {})) {
|
|
4468
|
+
if (comparator([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema])) {
|
|
4469
|
+
candidates.push(fromOutputPortId);
|
|
4470
|
+
}
|
|
4471
|
+
}
|
|
4472
|
+
if (candidates.length === 0)
|
|
4473
|
+
continue;
|
|
4474
|
+
let winner = candidates[0];
|
|
4475
|
+
if (candidates.length > 1) {
|
|
4476
|
+
const targetStreamMode = getPortStreamMode(toSchema, toInputPortId);
|
|
4477
|
+
const streamMatch = candidates.find((portId) => getPortStreamMode(fromSchema, portId) === targetStreamMode);
|
|
4478
|
+
if (streamMatch)
|
|
4479
|
+
winner = streamMatch;
|
|
4480
|
+
}
|
|
4481
|
+
matches.set(toInputPortId, winner);
|
|
4482
|
+
addDataflow(new Dataflow(fromTaskId, winner, toTaskId, toInputPortId));
|
|
4483
|
+
}
|
|
4484
|
+
};
|
|
4485
|
+
makeMatch(sourceSchema, targetSchema, sourceTask.id, targetTask.id, ([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema]) => {
|
|
4486
|
+
const outputPortIdMatch = fromOutputPortId === toInputPortId;
|
|
4487
|
+
const outputPortIdOutputInput = fromOutputPortId === "output" && toInputPortId === "input";
|
|
4488
|
+
const portIdsCompatible = outputPortIdMatch || outputPortIdOutputInput;
|
|
4489
|
+
return portIdsCompatible && isTypeCompatible(fromPortOutputSchema, toPortInputSchema, false);
|
|
4490
|
+
});
|
|
4491
|
+
makeMatch(sourceSchema, targetSchema, sourceTask.id, targetTask.id, ([_fromOutputPortId, fromPortOutputSchema], [_toInputPortId, toPortInputSchema]) => {
|
|
4492
|
+
return isTypeCompatible(fromPortOutputSchema, toPortInputSchema, true);
|
|
4493
|
+
});
|
|
4494
|
+
const requiredInputs = new Set(typeof targetSchema === "object" ? targetSchema.required || [] : []);
|
|
4495
|
+
const requiredInputsNeedingConnection = [...requiredInputs].filter((r) => !providedInputKeys.has(r) && !connectedInputKeys.has(r));
|
|
4496
|
+
let unmatchedRequired = requiredInputsNeedingConnection.filter((r) => !matches.has(r));
|
|
4497
|
+
if (unmatchedRequired.length > 0 && earlierTasks.length > 0) {
|
|
4498
|
+
for (let i = 0;i < earlierTasks.length && unmatchedRequired.length > 0; i++) {
|
|
4499
|
+
const earlierTask = earlierTasks[i];
|
|
4500
|
+
const earlierOutputSchema = earlierTask.outputSchema();
|
|
4501
|
+
if (earlierTask.type === "InputTask") {
|
|
4502
|
+
const inputConfig = earlierTask.config;
|
|
4503
|
+
const inputSchema = inputConfig?.inputSchema ?? inputConfig?.outputSchema;
|
|
4504
|
+
const isManualSchema = inputSchema && typeof inputSchema === "object" && inputSchema["x-ui-manual"] === true;
|
|
4505
|
+
const inputProperties = isManualSchema && inputSchema && typeof inputSchema === "object" && "properties" in inputSchema && inputSchema.properties && typeof inputSchema.properties === "object" ? new Set(Object.keys(inputSchema.properties)) : undefined;
|
|
4506
|
+
for (const requiredInputId of [...unmatchedRequired]) {
|
|
4507
|
+
if (matches.has(requiredInputId))
|
|
4508
|
+
continue;
|
|
4509
|
+
if (inputProperties && !inputProperties.has(requiredInputId))
|
|
4510
|
+
continue;
|
|
4511
|
+
matches.set(requiredInputId, requiredInputId);
|
|
4512
|
+
addDataflow(new Dataflow(earlierTask.id, requiredInputId, targetTask.id, requiredInputId));
|
|
4513
|
+
}
|
|
4514
|
+
unmatchedRequired = unmatchedRequired.filter((r) => !matches.has(r));
|
|
4515
|
+
continue;
|
|
4516
|
+
}
|
|
4517
|
+
const makeMatchFromEarlier = (comparator) => {
|
|
4518
|
+
if (typeof earlierOutputSchema === "boolean" || typeof targetSchema === "boolean") {
|
|
4519
|
+
return;
|
|
4520
|
+
}
|
|
4521
|
+
for (const [fromOutputPortId, fromPortOutputSchema] of Object.entries(earlierOutputSchema.properties || {})) {
|
|
4522
|
+
for (const requiredInputId of unmatchedRequired) {
|
|
4523
|
+
const toPortInputSchema = targetSchema.properties?.[requiredInputId];
|
|
4524
|
+
if (!matches.has(requiredInputId) && toPortInputSchema && comparator([fromOutputPortId, fromPortOutputSchema], [requiredInputId, toPortInputSchema])) {
|
|
4525
|
+
matches.set(requiredInputId, fromOutputPortId);
|
|
4526
|
+
addDataflow(new Dataflow(earlierTask.id, fromOutputPortId, targetTask.id, requiredInputId));
|
|
4527
|
+
}
|
|
4528
|
+
}
|
|
4529
|
+
}
|
|
4530
|
+
};
|
|
4531
|
+
makeMatchFromEarlier(([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema]) => {
|
|
4532
|
+
const outputPortIdMatch = fromOutputPortId === toInputPortId;
|
|
4533
|
+
const outputPortIdOutputInput = fromOutputPortId === "output" && toInputPortId === "input";
|
|
4534
|
+
const portIdsCompatible = outputPortIdMatch || outputPortIdOutputInput;
|
|
4535
|
+
return portIdsCompatible && isTypeCompatible(fromPortOutputSchema, toPortInputSchema, false);
|
|
4536
|
+
});
|
|
4537
|
+
makeMatchFromEarlier(([_fromOutputPortId, fromPortOutputSchema], [_toInputPortId, toPortInputSchema]) => {
|
|
4538
|
+
return isTypeCompatible(fromPortOutputSchema, toPortInputSchema, true);
|
|
4539
|
+
});
|
|
4540
|
+
unmatchedRequired = unmatchedRequired.filter((r) => !matches.has(r));
|
|
4541
|
+
}
|
|
4542
|
+
}
|
|
4543
|
+
const stillUnmatchedRequired = requiredInputsNeedingConnection.filter((r) => !matches.has(r));
|
|
4544
|
+
if (stillUnmatchedRequired.length > 0) {
|
|
4545
|
+
return {
|
|
4546
|
+
matches,
|
|
4547
|
+
error: `Could not find matches for required inputs [${stillUnmatchedRequired.join(", ")}] of ${targetTask.type}. ` + `Attempted to match from ${sourceTask.type} and earlier tasks.`,
|
|
4548
|
+
unmatchedRequired: stillUnmatchedRequired
|
|
4549
|
+
};
|
|
4550
|
+
}
|
|
4551
|
+
if (matches.size === 0 && requiredInputsNeedingConnection.length === 0) {
|
|
4552
|
+
const existingTargetConnections = graph.getSourceDataflows(targetTask.id);
|
|
4553
|
+
if (existingTargetConnections.length > 0) {
|
|
4554
|
+
return { matches, unmatchedRequired: [] };
|
|
4555
|
+
}
|
|
4556
|
+
const hasRequiredInputs = requiredInputs.size > 0;
|
|
4557
|
+
const allRequiredInputsProvided = hasRequiredInputs && [...requiredInputs].every((r) => providedInputKeys.has(r));
|
|
4558
|
+
const hasInputsWithDefaults = typeof targetSchema === "object" && targetSchema.properties && Object.values(targetSchema.properties).some((prop) => prop && typeof prop === "object" && ("default" in prop));
|
|
4559
|
+
if (!allRequiredInputsProvided && !hasInputsWithDefaults) {
|
|
4560
|
+
return {
|
|
4561
|
+
matches,
|
|
4562
|
+
error: `Could not find a match between the outputs of ${sourceTask.type} and the inputs of ${targetTask.type}. ` + `You may need to connect the outputs to the inputs via connect() manually.`,
|
|
4563
|
+
unmatchedRequired: []
|
|
4564
|
+
};
|
|
4565
|
+
}
|
|
4566
|
+
}
|
|
4567
|
+
return {
|
|
4568
|
+
matches,
|
|
4569
|
+
unmatchedRequired: []
|
|
4570
|
+
};
|
|
4571
|
+
}
|
|
4572
|
+
|
|
4573
|
+
// src/task-graph/ConditionalBuilder.ts
|
|
4574
|
+
import { uuid4 as uuid45 } from "@workglow/util";
|
|
4575
|
+
class ConditionalBuilder {
|
|
4576
|
+
workflow;
|
|
4577
|
+
condition;
|
|
4578
|
+
thenSpec;
|
|
4579
|
+
elseSpec;
|
|
4580
|
+
constructor(workflow, condition) {
|
|
4581
|
+
this.workflow = workflow;
|
|
4582
|
+
this.condition = condition;
|
|
4583
|
+
}
|
|
4584
|
+
then(taskClass, input, config) {
|
|
4585
|
+
this.thenSpec = { taskClass, input, config };
|
|
4586
|
+
return this;
|
|
4587
|
+
}
|
|
4588
|
+
else(taskClass, input, config) {
|
|
4589
|
+
this.elseSpec = { taskClass, input, config };
|
|
4590
|
+
return this;
|
|
4591
|
+
}
|
|
4592
|
+
endIf() {
|
|
4593
|
+
if (!this.thenSpec) {
|
|
4594
|
+
throw new WorkflowError(".endIf() called without a prior .then(...) call");
|
|
4595
|
+
}
|
|
4596
|
+
const thenPort = "then";
|
|
4597
|
+
const elsePort = "else";
|
|
4598
|
+
const branches = [
|
|
4599
|
+
{
|
|
4600
|
+
id: thenPort,
|
|
4601
|
+
condition: this.condition,
|
|
4602
|
+
outputPort: thenPort
|
|
4603
|
+
}
|
|
4604
|
+
];
|
|
4605
|
+
if (this.elseSpec) {
|
|
4606
|
+
branches.push({
|
|
4607
|
+
id: elsePort,
|
|
4608
|
+
condition: (input) => !this.condition(input),
|
|
4609
|
+
outputPort: elsePort
|
|
4610
|
+
});
|
|
4611
|
+
}
|
|
4612
|
+
const conditionalTask = new ConditionalTask({
|
|
4613
|
+
id: uuid45(),
|
|
4614
|
+
branches,
|
|
4615
|
+
exclusive: true,
|
|
4616
|
+
defaultBranch: this.elseSpec ? elsePort : undefined
|
|
4617
|
+
});
|
|
4618
|
+
this.workflow.graph.addTask(conditionalTask);
|
|
4619
|
+
const thenTask = instantiate(this.thenSpec);
|
|
4620
|
+
this.workflow.graph.addTask(thenTask);
|
|
4621
|
+
this.workflow.graph.addDataflow(new Dataflow(conditionalTask.id, thenPort, thenTask.id, "*"));
|
|
4622
|
+
if (this.elseSpec) {
|
|
4623
|
+
const elseTask = instantiate(this.elseSpec);
|
|
4624
|
+
this.workflow.graph.addTask(elseTask);
|
|
4625
|
+
this.workflow.graph.addDataflow(new Dataflow(conditionalTask.id, elsePort, elseTask.id, "*"));
|
|
4626
|
+
}
|
|
4627
|
+
return this.workflow;
|
|
4628
|
+
}
|
|
4629
|
+
}
|
|
4630
|
+
function instantiate(spec) {
|
|
4631
|
+
const config = {
|
|
4632
|
+
id: uuid45(),
|
|
4633
|
+
...spec.config,
|
|
4634
|
+
defaults: spec.input
|
|
4635
|
+
};
|
|
4636
|
+
return new spec.taskClass(config);
|
|
4637
|
+
}
|
|
4638
|
+
|
|
4639
|
+
// src/task-graph/Workflow.ts
|
|
4137
4640
|
function getLastTask(workflow) {
|
|
4138
4641
|
const tasks = workflow.graph.getTasks();
|
|
4139
4642
|
return tasks.length > 0 ? tasks[tasks.length - 1] : undefined;
|
|
@@ -4276,7 +4779,7 @@ class Workflow {
|
|
|
4276
4779
|
this._error = "";
|
|
4277
4780
|
const parent = getLastTask(this);
|
|
4278
4781
|
const task = this.addTaskToGraph(taskClass, {
|
|
4279
|
-
id:
|
|
4782
|
+
id: uuid46(),
|
|
4280
4783
|
...config,
|
|
4281
4784
|
defaults: input
|
|
4282
4785
|
});
|
|
@@ -4430,8 +4933,10 @@ class Workflow {
|
|
|
4430
4933
|
static parallel(args, mergeFn) {
|
|
4431
4934
|
return parallel(args, mergeFn ?? PROPERTY_ARRAY, new Workflow);
|
|
4432
4935
|
}
|
|
4433
|
-
rename(source, target,
|
|
4936
|
+
rename(source, target, indexOrOptions = -1) {
|
|
4434
4937
|
this._error = "";
|
|
4938
|
+
const index = typeof indexOrOptions === "number" ? indexOrOptions : indexOrOptions.index ?? -1;
|
|
4939
|
+
const transforms = typeof indexOrOptions === "number" ? undefined : indexOrOptions.transforms;
|
|
4435
4940
|
const nodes = this._graph.getTasks();
|
|
4436
4941
|
if (-index > nodes.length) {
|
|
4437
4942
|
const errorMsg = `Back index greater than number of tasks`;
|
|
@@ -4454,7 +4959,10 @@ class Workflow {
|
|
|
4454
4959
|
getLogger5().error(this._error);
|
|
4455
4960
|
throw new WorkflowError(errorMsg);
|
|
4456
4961
|
}
|
|
4457
|
-
|
|
4962
|
+
const df = new Dataflow(lastNode.id, source, undefined, target);
|
|
4963
|
+
if (transforms && transforms.length > 0)
|
|
4964
|
+
df.setTransforms(transforms);
|
|
4965
|
+
this._dataFlows.push(df);
|
|
4458
4966
|
return this;
|
|
4459
4967
|
}
|
|
4460
4968
|
onError(handler) {
|
|
@@ -4557,7 +5065,11 @@ class Workflow {
|
|
|
4557
5065
|
addLoopTask(taskClass, config = {}) {
|
|
4558
5066
|
this._error = "";
|
|
4559
5067
|
const parent = getLastTask(this);
|
|
4560
|
-
const
|
|
5068
|
+
const schema = taskClass.configSchema?.();
|
|
5069
|
+
const required = typeof schema === "object" && schema !== null ? schema.required : undefined;
|
|
5070
|
+
const needsMaxIterations = Array.isArray(required) && required.includes("maxIterations");
|
|
5071
|
+
const resolvedConfig = needsMaxIterations && config.maxIterations === undefined ? { ...config, maxIterations: "unbounded" } : config;
|
|
5072
|
+
const task = this.addTaskToGraph(taskClass, { id: uuid46(), ...resolvedConfig });
|
|
4561
5073
|
if (this._dataFlows.length > 0) {
|
|
4562
5074
|
this._dataFlows.forEach((dataflow) => {
|
|
4563
5075
|
const taskSchema = task.inputSchema();
|
|
@@ -4577,6 +5089,9 @@ class Workflow {
|
|
|
4577
5089
|
}
|
|
4578
5090
|
return loopBuilder;
|
|
4579
5091
|
}
|
|
5092
|
+
if(condition) {
|
|
5093
|
+
return new ConditionalBuilder(this, condition);
|
|
5094
|
+
}
|
|
4580
5095
|
autoConnectLoopTask(pending) {
|
|
4581
5096
|
if (!pending)
|
|
4582
5097
|
return;
|
|
@@ -4697,243 +5212,14 @@ class Workflow {
|
|
|
4697
5212
|
}
|
|
4698
5213
|
static AutoConnectOptions = Symbol("AutoConnectOptions");
|
|
4699
5214
|
static autoConnect(graph, sourceTask, targetTask, options) {
|
|
4700
|
-
|
|
4701
|
-
const sourceSchema = sourceTask.outputSchema();
|
|
4702
|
-
const targetSchema = targetTask.inputSchema();
|
|
4703
|
-
const providedInputKeys = options?.providedInputKeys ?? new Set;
|
|
4704
|
-
const connectedInputKeys = options?.connectedInputKeys ?? new Set;
|
|
4705
|
-
const earlierTasks = options?.earlierTasks ?? [];
|
|
4706
|
-
const getSpecificTypeIdentifiers = (schema) => {
|
|
4707
|
-
const formats = new Set;
|
|
4708
|
-
const ids = new Set;
|
|
4709
|
-
if (typeof schema === "boolean") {
|
|
4710
|
-
return { formats, ids };
|
|
4711
|
-
}
|
|
4712
|
-
const extractFromSchema = (s) => {
|
|
4713
|
-
if (!s || typeof s !== "object" || Array.isArray(s))
|
|
4714
|
-
return;
|
|
4715
|
-
if (s.format)
|
|
4716
|
-
formats.add(s.format);
|
|
4717
|
-
if (s.$id)
|
|
4718
|
-
ids.add(s.$id);
|
|
4719
|
-
};
|
|
4720
|
-
extractFromSchema(schema);
|
|
4721
|
-
const checkUnion = (schemas) => {
|
|
4722
|
-
if (!schemas)
|
|
4723
|
-
return;
|
|
4724
|
-
for (const s of schemas) {
|
|
4725
|
-
if (typeof s === "boolean")
|
|
4726
|
-
continue;
|
|
4727
|
-
extractFromSchema(s);
|
|
4728
|
-
if (s.items && typeof s.items === "object" && !Array.isArray(s.items)) {
|
|
4729
|
-
extractFromSchema(s.items);
|
|
4730
|
-
}
|
|
4731
|
-
}
|
|
4732
|
-
};
|
|
4733
|
-
checkUnion(schema.oneOf);
|
|
4734
|
-
checkUnion(schema.anyOf);
|
|
4735
|
-
if (schema.items && typeof schema.items === "object" && !Array.isArray(schema.items)) {
|
|
4736
|
-
extractFromSchema(schema.items);
|
|
4737
|
-
}
|
|
4738
|
-
return { formats, ids };
|
|
4739
|
-
};
|
|
4740
|
-
const isTypeCompatible = (fromPortOutputSchema, toPortInputSchema, requireSpecificType = false) => {
|
|
4741
|
-
if (typeof fromPortOutputSchema === "boolean" || typeof toPortInputSchema === "boolean") {
|
|
4742
|
-
return fromPortOutputSchema === true && toPortInputSchema === true;
|
|
4743
|
-
}
|
|
4744
|
-
const outputIds = getSpecificTypeIdentifiers(fromPortOutputSchema);
|
|
4745
|
-
const inputIds = getSpecificTypeIdentifiers(toPortInputSchema);
|
|
4746
|
-
for (const format of outputIds.formats) {
|
|
4747
|
-
if (inputIds.formats.has(format)) {
|
|
4748
|
-
return true;
|
|
4749
|
-
}
|
|
4750
|
-
}
|
|
4751
|
-
for (const id of outputIds.ids) {
|
|
4752
|
-
if (inputIds.ids.has(id)) {
|
|
4753
|
-
return true;
|
|
4754
|
-
}
|
|
4755
|
-
}
|
|
4756
|
-
if (requireSpecificType) {
|
|
4757
|
-
return false;
|
|
4758
|
-
}
|
|
4759
|
-
const idTypeBlank = fromPortOutputSchema.$id === undefined && toPortInputSchema.$id === undefined;
|
|
4760
|
-
if (!idTypeBlank)
|
|
4761
|
-
return false;
|
|
4762
|
-
if (fromPortOutputSchema.type === toPortInputSchema.type)
|
|
4763
|
-
return true;
|
|
4764
|
-
const matchesOneOf = toPortInputSchema.oneOf?.some((schema) => {
|
|
4765
|
-
if (typeof schema === "boolean")
|
|
4766
|
-
return schema;
|
|
4767
|
-
return schema.type === fromPortOutputSchema.type;
|
|
4768
|
-
}) ?? false;
|
|
4769
|
-
const matchesAnyOf = toPortInputSchema.anyOf?.some((schema) => {
|
|
4770
|
-
if (typeof schema === "boolean")
|
|
4771
|
-
return schema;
|
|
4772
|
-
return schema.type === fromPortOutputSchema.type;
|
|
4773
|
-
}) ?? false;
|
|
4774
|
-
return matchesOneOf || matchesAnyOf;
|
|
4775
|
-
};
|
|
4776
|
-
const makeMatch = (fromSchema, toSchema, fromTaskId, toTaskId, comparator) => {
|
|
4777
|
-
if (typeof fromSchema === "object") {
|
|
4778
|
-
if (toSchema === true || typeof toSchema === "object" && toSchema.additionalProperties === true) {
|
|
4779
|
-
const outputKeys = Object.keys(fromSchema.properties || {});
|
|
4780
|
-
if (outputKeys.length > 0) {
|
|
4781
|
-
for (const fromOutputPortId of outputKeys) {
|
|
4782
|
-
if (matches.has(fromOutputPortId))
|
|
4783
|
-
continue;
|
|
4784
|
-
matches.set(fromOutputPortId, fromOutputPortId);
|
|
4785
|
-
graph.addDataflow(new Dataflow(fromTaskId, fromOutputPortId, toTaskId, fromOutputPortId));
|
|
4786
|
-
}
|
|
4787
|
-
} else if (fromSchema.additionalProperties === true) {
|
|
4788
|
-
const sourceGraphTask = graph.getTask(fromTaskId);
|
|
4789
|
-
if (sourceGraphTask && sourceGraphTask.constructor.passthroughInputsToOutputs === true) {
|
|
4790
|
-
const incomingDfs = graph.getSourceDataflows(fromTaskId);
|
|
4791
|
-
for (const df of incomingDfs) {
|
|
4792
|
-
const portId = df.targetTaskPortId;
|
|
4793
|
-
if (portId === DATAFLOW_ALL_PORTS)
|
|
4794
|
-
continue;
|
|
4795
|
-
if (matches.has(portId))
|
|
4796
|
-
continue;
|
|
4797
|
-
if (connectedInputKeys.has(portId))
|
|
4798
|
-
continue;
|
|
4799
|
-
matches.set(portId, portId);
|
|
4800
|
-
graph.addDataflow(new Dataflow(fromTaskId, portId, toTaskId, portId));
|
|
4801
|
-
}
|
|
4802
|
-
}
|
|
4803
|
-
}
|
|
4804
|
-
return;
|
|
4805
|
-
}
|
|
4806
|
-
}
|
|
4807
|
-
if (typeof fromSchema === "object" && fromSchema.additionalProperties === true && typeof toSchema === "object" && (sourceTask.type === "InputTask" || sourceTask.type === "OutputTask")) {
|
|
4808
|
-
for (const toInputPortId of Object.keys(toSchema.properties || {})) {
|
|
4809
|
-
if (matches.has(toInputPortId))
|
|
4810
|
-
continue;
|
|
4811
|
-
if (connectedInputKeys.has(toInputPortId))
|
|
4812
|
-
continue;
|
|
4813
|
-
matches.set(toInputPortId, toInputPortId);
|
|
4814
|
-
graph.addDataflow(new Dataflow(fromTaskId, toInputPortId, toTaskId, toInputPortId));
|
|
4815
|
-
}
|
|
4816
|
-
return;
|
|
4817
|
-
}
|
|
4818
|
-
if (typeof fromSchema === "boolean" || typeof toSchema === "boolean") {
|
|
4819
|
-
return;
|
|
4820
|
-
}
|
|
4821
|
-
for (const [toInputPortId, toPortInputSchema] of Object.entries(toSchema.properties || {})) {
|
|
4822
|
-
if (matches.has(toInputPortId))
|
|
4823
|
-
continue;
|
|
4824
|
-
if (connectedInputKeys.has(toInputPortId))
|
|
4825
|
-
continue;
|
|
4826
|
-
const candidates = [];
|
|
4827
|
-
for (const [fromOutputPortId, fromPortOutputSchema] of Object.entries(fromSchema.properties || {})) {
|
|
4828
|
-
if (comparator([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema])) {
|
|
4829
|
-
candidates.push(fromOutputPortId);
|
|
4830
|
-
}
|
|
4831
|
-
}
|
|
4832
|
-
if (candidates.length === 0)
|
|
4833
|
-
continue;
|
|
4834
|
-
let winner = candidates[0];
|
|
4835
|
-
if (candidates.length > 1) {
|
|
4836
|
-
const targetStreamMode = getPortStreamMode(toSchema, toInputPortId);
|
|
4837
|
-
const streamMatch = candidates.find((portId) => getPortStreamMode(fromSchema, portId) === targetStreamMode);
|
|
4838
|
-
if (streamMatch)
|
|
4839
|
-
winner = streamMatch;
|
|
4840
|
-
}
|
|
4841
|
-
matches.set(toInputPortId, winner);
|
|
4842
|
-
graph.addDataflow(new Dataflow(fromTaskId, winner, toTaskId, toInputPortId));
|
|
4843
|
-
}
|
|
4844
|
-
};
|
|
4845
|
-
makeMatch(sourceSchema, targetSchema, sourceTask.id, targetTask.id, ([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema]) => {
|
|
4846
|
-
const outputPortIdMatch = fromOutputPortId === toInputPortId;
|
|
4847
|
-
const outputPortIdOutputInput = fromOutputPortId === "output" && toInputPortId === "input";
|
|
4848
|
-
const portIdsCompatible = outputPortIdMatch || outputPortIdOutputInput;
|
|
4849
|
-
return portIdsCompatible && isTypeCompatible(fromPortOutputSchema, toPortInputSchema, false);
|
|
4850
|
-
});
|
|
4851
|
-
makeMatch(sourceSchema, targetSchema, sourceTask.id, targetTask.id, ([_fromOutputPortId, fromPortOutputSchema], [_toInputPortId, toPortInputSchema]) => {
|
|
4852
|
-
return isTypeCompatible(fromPortOutputSchema, toPortInputSchema, true);
|
|
4853
|
-
});
|
|
4854
|
-
const requiredInputs = new Set(typeof targetSchema === "object" ? targetSchema.required || [] : []);
|
|
4855
|
-
const requiredInputsNeedingConnection = [...requiredInputs].filter((r) => !providedInputKeys.has(r) && !connectedInputKeys.has(r));
|
|
4856
|
-
let unmatchedRequired = requiredInputsNeedingConnection.filter((r) => !matches.has(r));
|
|
4857
|
-
if (unmatchedRequired.length > 0 && earlierTasks.length > 0) {
|
|
4858
|
-
for (let i = 0;i < earlierTasks.length && unmatchedRequired.length > 0; i++) {
|
|
4859
|
-
const earlierTask = earlierTasks[i];
|
|
4860
|
-
const earlierOutputSchema = earlierTask.outputSchema();
|
|
4861
|
-
if (earlierTask.type === "InputTask") {
|
|
4862
|
-
const inputConfig = earlierTask.config;
|
|
4863
|
-
const inputSchema = inputConfig?.inputSchema ?? inputConfig?.outputSchema;
|
|
4864
|
-
const isManualSchema = inputSchema && typeof inputSchema === "object" && inputSchema["x-ui-manual"] === true;
|
|
4865
|
-
const inputProperties = isManualSchema && inputSchema && typeof inputSchema === "object" && "properties" in inputSchema && inputSchema.properties && typeof inputSchema.properties === "object" ? new Set(Object.keys(inputSchema.properties)) : undefined;
|
|
4866
|
-
for (const requiredInputId of [...unmatchedRequired]) {
|
|
4867
|
-
if (matches.has(requiredInputId))
|
|
4868
|
-
continue;
|
|
4869
|
-
if (inputProperties && !inputProperties.has(requiredInputId))
|
|
4870
|
-
continue;
|
|
4871
|
-
matches.set(requiredInputId, requiredInputId);
|
|
4872
|
-
graph.addDataflow(new Dataflow(earlierTask.id, requiredInputId, targetTask.id, requiredInputId));
|
|
4873
|
-
}
|
|
4874
|
-
unmatchedRequired = unmatchedRequired.filter((r) => !matches.has(r));
|
|
4875
|
-
continue;
|
|
4876
|
-
}
|
|
4877
|
-
const makeMatchFromEarlier = (comparator) => {
|
|
4878
|
-
if (typeof earlierOutputSchema === "boolean" || typeof targetSchema === "boolean") {
|
|
4879
|
-
return;
|
|
4880
|
-
}
|
|
4881
|
-
for (const [fromOutputPortId, fromPortOutputSchema] of Object.entries(earlierOutputSchema.properties || {})) {
|
|
4882
|
-
for (const requiredInputId of unmatchedRequired) {
|
|
4883
|
-
const toPortInputSchema = targetSchema.properties?.[requiredInputId];
|
|
4884
|
-
if (!matches.has(requiredInputId) && toPortInputSchema && comparator([fromOutputPortId, fromPortOutputSchema], [requiredInputId, toPortInputSchema])) {
|
|
4885
|
-
matches.set(requiredInputId, fromOutputPortId);
|
|
4886
|
-
graph.addDataflow(new Dataflow(earlierTask.id, fromOutputPortId, targetTask.id, requiredInputId));
|
|
4887
|
-
}
|
|
4888
|
-
}
|
|
4889
|
-
}
|
|
4890
|
-
};
|
|
4891
|
-
makeMatchFromEarlier(([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema]) => {
|
|
4892
|
-
const outputPortIdMatch = fromOutputPortId === toInputPortId;
|
|
4893
|
-
const outputPortIdOutputInput = fromOutputPortId === "output" && toInputPortId === "input";
|
|
4894
|
-
const portIdsCompatible = outputPortIdMatch || outputPortIdOutputInput;
|
|
4895
|
-
return portIdsCompatible && isTypeCompatible(fromPortOutputSchema, toPortInputSchema, false);
|
|
4896
|
-
});
|
|
4897
|
-
makeMatchFromEarlier(([_fromOutputPortId, fromPortOutputSchema], [_toInputPortId, toPortInputSchema]) => {
|
|
4898
|
-
return isTypeCompatible(fromPortOutputSchema, toPortInputSchema, true);
|
|
4899
|
-
});
|
|
4900
|
-
unmatchedRequired = unmatchedRequired.filter((r) => !matches.has(r));
|
|
4901
|
-
}
|
|
4902
|
-
}
|
|
4903
|
-
const stillUnmatchedRequired = requiredInputsNeedingConnection.filter((r) => !matches.has(r));
|
|
4904
|
-
if (stillUnmatchedRequired.length > 0) {
|
|
4905
|
-
return {
|
|
4906
|
-
matches,
|
|
4907
|
-
error: `Could not find matches for required inputs [${stillUnmatchedRequired.join(", ")}] of ${targetTask.type}. ` + `Attempted to match from ${sourceTask.type} and earlier tasks.`,
|
|
4908
|
-
unmatchedRequired: stillUnmatchedRequired
|
|
4909
|
-
};
|
|
4910
|
-
}
|
|
4911
|
-
if (matches.size === 0 && requiredInputsNeedingConnection.length === 0) {
|
|
4912
|
-
const existingTargetConnections = graph.getSourceDataflows(targetTask.id);
|
|
4913
|
-
if (existingTargetConnections.length > 0) {
|
|
4914
|
-
return { matches, unmatchedRequired: [] };
|
|
4915
|
-
}
|
|
4916
|
-
const hasRequiredInputs = requiredInputs.size > 0;
|
|
4917
|
-
const allRequiredInputsProvided = hasRequiredInputs && [...requiredInputs].every((r) => providedInputKeys.has(r));
|
|
4918
|
-
const hasInputsWithDefaults = typeof targetSchema === "object" && targetSchema.properties && Object.values(targetSchema.properties).some((prop) => prop && typeof prop === "object" && ("default" in prop));
|
|
4919
|
-
if (!allRequiredInputsProvided && !hasInputsWithDefaults) {
|
|
4920
|
-
return {
|
|
4921
|
-
matches,
|
|
4922
|
-
error: `Could not find a match between the outputs of ${sourceTask.type} and the inputs of ${targetTask.type}. ` + `You may need to connect the outputs to the inputs via connect() manually.`,
|
|
4923
|
-
unmatchedRequired: []
|
|
4924
|
-
};
|
|
4925
|
-
}
|
|
4926
|
-
}
|
|
4927
|
-
return {
|
|
4928
|
-
matches,
|
|
4929
|
-
unmatchedRequired: []
|
|
4930
|
-
};
|
|
5215
|
+
return autoConnect(graph, sourceTask, targetTask, options);
|
|
4931
5216
|
}
|
|
4932
5217
|
finalizeTemplate() {
|
|
4933
5218
|
if (!this._iteratorTask || this.graph.getTasks().length === 0) {
|
|
4934
5219
|
return;
|
|
4935
5220
|
}
|
|
4936
5221
|
this._iteratorTask.subGraph = this.graph;
|
|
5222
|
+
this._iteratorTask.validateAcyclic();
|
|
4937
5223
|
}
|
|
4938
5224
|
finalizeAndReturn() {
|
|
4939
5225
|
if (!this._parentWorkflow) {
|
|
@@ -4968,6 +5254,7 @@ function getMethodNameMap() {
|
|
|
4968
5254
|
}
|
|
4969
5255
|
var LOOP_TASK_TYPES = {
|
|
4970
5256
|
MapTask: { method: "map", endMethod: "endMap" },
|
|
5257
|
+
ForEachTask: { method: "forEach", endMethod: "endForEach" },
|
|
4971
5258
|
ReduceTask: { method: "reduce", endMethod: "endReduce" },
|
|
4972
5259
|
WhileTask: { method: "while", endMethod: "endWhile" },
|
|
4973
5260
|
GraphAsTask: { method: "group", endMethod: "endGroup" }
|
|
@@ -5150,7 +5437,8 @@ function extractLoopConfig(task) {
|
|
|
5150
5437
|
}
|
|
5151
5438
|
break;
|
|
5152
5439
|
}
|
|
5153
|
-
case "MapTask":
|
|
5440
|
+
case "MapTask":
|
|
5441
|
+
case "ForEachTask": {
|
|
5154
5442
|
if (rawConfig.preserveOrder !== undefined && rawConfig.preserveOrder !== true) {
|
|
5155
5443
|
config.preserveOrder = rawConfig.preserveOrder;
|
|
5156
5444
|
}
|
|
@@ -5163,16 +5451,22 @@ function extractLoopConfig(task) {
|
|
|
5163
5451
|
if (rawConfig.batchSize !== undefined) {
|
|
5164
5452
|
config.batchSize = rawConfig.batchSize;
|
|
5165
5453
|
}
|
|
5454
|
+
if (rawConfig.maxIterations !== undefined) {
|
|
5455
|
+
config.maxIterations = rawConfig.maxIterations;
|
|
5456
|
+
}
|
|
5166
5457
|
break;
|
|
5167
5458
|
}
|
|
5168
5459
|
case "ReduceTask": {
|
|
5169
5460
|
if (rawConfig.initialValue !== undefined) {
|
|
5170
5461
|
config.initialValue = rawConfig.initialValue;
|
|
5171
5462
|
}
|
|
5463
|
+
if (rawConfig.maxIterations !== undefined) {
|
|
5464
|
+
config.maxIterations = rawConfig.maxIterations;
|
|
5465
|
+
}
|
|
5172
5466
|
break;
|
|
5173
5467
|
}
|
|
5174
5468
|
case "WhileTask": {
|
|
5175
|
-
if (rawConfig.maxIterations !== undefined
|
|
5469
|
+
if (rawConfig.maxIterations !== undefined) {
|
|
5176
5470
|
config.maxIterations = rawConfig.maxIterations;
|
|
5177
5471
|
}
|
|
5178
5472
|
if (rawConfig.chainIterations !== undefined && rawConfig.chainIterations !== true) {
|
|
@@ -5282,6 +5576,304 @@ ${baseIndent}}`;
|
|
|
5282
5576
|
function resetMethodNameCache() {
|
|
5283
5577
|
methodNameCache = undefined;
|
|
5284
5578
|
}
|
|
5579
|
+
// src/task-graph/transforms/pick.ts
|
|
5580
|
+
import { areSemanticallyCompatible as areSemanticallyCompatible2 } from "@workglow/util/schema";
|
|
5581
|
+
function walk(value, path) {
|
|
5582
|
+
if (value == null)
|
|
5583
|
+
return;
|
|
5584
|
+
const parts = path.split(".");
|
|
5585
|
+
let cur = value;
|
|
5586
|
+
for (const p of parts) {
|
|
5587
|
+
if (cur == null)
|
|
5588
|
+
return;
|
|
5589
|
+
cur = cur[p];
|
|
5590
|
+
}
|
|
5591
|
+
return cur;
|
|
5592
|
+
}
|
|
5593
|
+
function walkSchema(schema, path) {
|
|
5594
|
+
const parts = path.split(".");
|
|
5595
|
+
let cur = schema;
|
|
5596
|
+
for (const p of parts) {
|
|
5597
|
+
if (!cur || typeof cur !== "object")
|
|
5598
|
+
return {};
|
|
5599
|
+
if (cur.type !== "object" || !cur.properties || !cur.properties[p]) {
|
|
5600
|
+
return {};
|
|
5601
|
+
}
|
|
5602
|
+
cur = cur.properties[p];
|
|
5603
|
+
}
|
|
5604
|
+
return cur;
|
|
5605
|
+
}
|
|
5606
|
+
var pickTransform = {
|
|
5607
|
+
id: "pick",
|
|
5608
|
+
title: "Pick field",
|
|
5609
|
+
category: "Structural",
|
|
5610
|
+
paramsSchema: {
|
|
5611
|
+
type: "object",
|
|
5612
|
+
properties: {
|
|
5613
|
+
path: { type: "string", description: "Dotted property path" }
|
|
5614
|
+
},
|
|
5615
|
+
required: ["path"]
|
|
5616
|
+
},
|
|
5617
|
+
inferOutputSchema(inputSchema, params) {
|
|
5618
|
+
return walkSchema(inputSchema, params.path);
|
|
5619
|
+
},
|
|
5620
|
+
apply(value, params) {
|
|
5621
|
+
return walk(value, params.path);
|
|
5622
|
+
},
|
|
5623
|
+
suggestFromSchemas(source, target) {
|
|
5624
|
+
if (source.type !== "object" || !source.properties) {
|
|
5625
|
+
return;
|
|
5626
|
+
}
|
|
5627
|
+
const props = source.properties;
|
|
5628
|
+
for (const [name, propSchema] of Object.entries(props)) {
|
|
5629
|
+
const compat = areSemanticallyCompatible2(propSchema, target);
|
|
5630
|
+
if (compat === "static")
|
|
5631
|
+
return { score: 1, params: { path: name } };
|
|
5632
|
+
if (compat === "runtime")
|
|
5633
|
+
return { score: 0.6, params: { path: name } };
|
|
5634
|
+
}
|
|
5635
|
+
return;
|
|
5636
|
+
}
|
|
5637
|
+
};
|
|
5638
|
+
|
|
5639
|
+
// src/task-graph/transforms/index-access.ts
|
|
5640
|
+
import { areSemanticallyCompatible as areSemanticallyCompatible3 } from "@workglow/util/schema";
|
|
5641
|
+
function doIndex(value, idx) {
|
|
5642
|
+
if (!Array.isArray(value))
|
|
5643
|
+
return;
|
|
5644
|
+
const i = idx < 0 ? value.length + idx : idx;
|
|
5645
|
+
return value[i];
|
|
5646
|
+
}
|
|
5647
|
+
var indexTransform = {
|
|
5648
|
+
id: "index",
|
|
5649
|
+
title: "Array index",
|
|
5650
|
+
category: "Structural",
|
|
5651
|
+
paramsSchema: {
|
|
5652
|
+
type: "object",
|
|
5653
|
+
properties: {
|
|
5654
|
+
index: { type: "integer", description: "Array index (negative counts from end)" }
|
|
5655
|
+
},
|
|
5656
|
+
required: ["index"]
|
|
5657
|
+
},
|
|
5658
|
+
inferOutputSchema(inputSchema) {
|
|
5659
|
+
const s = inputSchema;
|
|
5660
|
+
if (s?.type === "array" && s.items)
|
|
5661
|
+
return s.items;
|
|
5662
|
+
return {};
|
|
5663
|
+
},
|
|
5664
|
+
apply(value, params) {
|
|
5665
|
+
return doIndex(value, params.index);
|
|
5666
|
+
},
|
|
5667
|
+
suggestFromSchemas(source, target) {
|
|
5668
|
+
const s = source;
|
|
5669
|
+
if (s?.type !== "array" || !s.items)
|
|
5670
|
+
return;
|
|
5671
|
+
const compat = areSemanticallyCompatible3(s.items, target);
|
|
5672
|
+
if (compat === "static")
|
|
5673
|
+
return { score: 0.9, params: { index: 0 } };
|
|
5674
|
+
if (compat === "runtime")
|
|
5675
|
+
return { score: 0.5, params: { index: 0 } };
|
|
5676
|
+
return;
|
|
5677
|
+
}
|
|
5678
|
+
};
|
|
5679
|
+
|
|
5680
|
+
// src/task-graph/transforms/coalesce.ts
|
|
5681
|
+
function stripNullable(schema) {
|
|
5682
|
+
const s = schema;
|
|
5683
|
+
if (!s || typeof s !== "object")
|
|
5684
|
+
return schema;
|
|
5685
|
+
if (Array.isArray(s.type)) {
|
|
5686
|
+
const nonNull = s.type.filter((t) => t !== "null");
|
|
5687
|
+
if (nonNull.length === 1)
|
|
5688
|
+
return { ...s, type: nonNull[0] };
|
|
5689
|
+
return { ...s, type: nonNull };
|
|
5690
|
+
}
|
|
5691
|
+
return schema;
|
|
5692
|
+
}
|
|
5693
|
+
var coalesceTransform = {
|
|
5694
|
+
id: "coalesce",
|
|
5695
|
+
title: "Coalesce null",
|
|
5696
|
+
category: "Conversion",
|
|
5697
|
+
paramsSchema: {
|
|
5698
|
+
type: "object",
|
|
5699
|
+
properties: { defaultValue: {} },
|
|
5700
|
+
required: ["defaultValue"]
|
|
5701
|
+
},
|
|
5702
|
+
inferOutputSchema: (input) => stripNullable(input),
|
|
5703
|
+
apply: (v, { defaultValue }) => v == null ? defaultValue : v
|
|
5704
|
+
};
|
|
5705
|
+
|
|
5706
|
+
// src/task-graph/transforms/string-casts.ts
|
|
5707
|
+
var stringSchema = { type: "string" };
|
|
5708
|
+
var uppercaseTransform = {
|
|
5709
|
+
id: "uppercase",
|
|
5710
|
+
title: "Uppercase",
|
|
5711
|
+
category: "String",
|
|
5712
|
+
paramsSchema: undefined,
|
|
5713
|
+
inferOutputSchema: () => stringSchema,
|
|
5714
|
+
apply: (v) => String(v ?? "").toUpperCase()
|
|
5715
|
+
};
|
|
5716
|
+
var lowercaseTransform = {
|
|
5717
|
+
id: "lowercase",
|
|
5718
|
+
title: "Lowercase",
|
|
5719
|
+
category: "String",
|
|
5720
|
+
paramsSchema: undefined,
|
|
5721
|
+
inferOutputSchema: () => stringSchema,
|
|
5722
|
+
apply: (v) => String(v ?? "").toLowerCase()
|
|
5723
|
+
};
|
|
5724
|
+
var truncateTransform = {
|
|
5725
|
+
id: "truncate",
|
|
5726
|
+
title: "Truncate",
|
|
5727
|
+
category: "String",
|
|
5728
|
+
paramsSchema: {
|
|
5729
|
+
type: "object",
|
|
5730
|
+
properties: { max: { type: "integer", minimum: 0 } },
|
|
5731
|
+
required: ["max"]
|
|
5732
|
+
},
|
|
5733
|
+
inferOutputSchema: () => stringSchema,
|
|
5734
|
+
apply: (v, { max }) => String(v ?? "").slice(0, max)
|
|
5735
|
+
};
|
|
5736
|
+
var substringTransform = {
|
|
5737
|
+
id: "substring",
|
|
5738
|
+
title: "Substring",
|
|
5739
|
+
category: "String",
|
|
5740
|
+
paramsSchema: {
|
|
5741
|
+
type: "object",
|
|
5742
|
+
properties: {
|
|
5743
|
+
start: { type: "integer" },
|
|
5744
|
+
end: { type: "integer" }
|
|
5745
|
+
},
|
|
5746
|
+
required: ["start"]
|
|
5747
|
+
},
|
|
5748
|
+
inferOutputSchema: () => stringSchema,
|
|
5749
|
+
apply: (v, { start, end }) => String(v ?? "").slice(start, end)
|
|
5750
|
+
};
|
|
5751
|
+
|
|
5752
|
+
// src/task-graph/transforms/date-conversions.ts
|
|
5753
|
+
var isoSchema = { type: "string", format: "date-time" };
|
|
5754
|
+
var numberSchema = { type: "number" };
|
|
5755
|
+
function hasDateTimeFormat(schema) {
|
|
5756
|
+
const s = schema;
|
|
5757
|
+
return s?.type === "string" && s.format === "date-time";
|
|
5758
|
+
}
|
|
5759
|
+
var unixToIsoDateTransform = {
|
|
5760
|
+
id: "unixToIsoDate",
|
|
5761
|
+
title: "Unix timestamp \u2192 ISO date",
|
|
5762
|
+
category: "Date",
|
|
5763
|
+
paramsSchema: {
|
|
5764
|
+
type: "object",
|
|
5765
|
+
properties: {
|
|
5766
|
+
unit: { type: "string", enum: ["s", "ms"] }
|
|
5767
|
+
},
|
|
5768
|
+
required: ["unit"]
|
|
5769
|
+
},
|
|
5770
|
+
inferOutputSchema: () => isoSchema,
|
|
5771
|
+
apply: (v, { unit }) => {
|
|
5772
|
+
const n = Number(v);
|
|
5773
|
+
return new Date(unit === "s" ? n * 1000 : n).toISOString();
|
|
5774
|
+
},
|
|
5775
|
+
suggestFromSchemas(source, target) {
|
|
5776
|
+
const s = source;
|
|
5777
|
+
if (s?.type !== "number" && s?.type !== "integer")
|
|
5778
|
+
return;
|
|
5779
|
+
if (!hasDateTimeFormat(target))
|
|
5780
|
+
return;
|
|
5781
|
+
return { score: 0.85, params: { unit: "s" } };
|
|
5782
|
+
}
|
|
5783
|
+
};
|
|
5784
|
+
var isoDateToUnixTransform = {
|
|
5785
|
+
id: "isoDateToUnix",
|
|
5786
|
+
title: "ISO date \u2192 Unix ms",
|
|
5787
|
+
category: "Date",
|
|
5788
|
+
paramsSchema: undefined,
|
|
5789
|
+
inferOutputSchema: () => numberSchema,
|
|
5790
|
+
apply: (v) => new Date(String(v)).getTime(),
|
|
5791
|
+
suggestFromSchemas(source, target) {
|
|
5792
|
+
if (!hasDateTimeFormat(source))
|
|
5793
|
+
return;
|
|
5794
|
+
const t = target;
|
|
5795
|
+
if (t?.type !== "number" && t?.type !== "integer")
|
|
5796
|
+
return;
|
|
5797
|
+
return { score: 0.9, params: {} };
|
|
5798
|
+
}
|
|
5799
|
+
};
|
|
5800
|
+
|
|
5801
|
+
// src/task-graph/transforms/scalar-conversions.ts
|
|
5802
|
+
var stringSchema2 = { type: "string" };
|
|
5803
|
+
var booleanSchema = { type: "boolean" };
|
|
5804
|
+
var numberToStringTransform = {
|
|
5805
|
+
id: "numberToString",
|
|
5806
|
+
title: "Number \u2192 String",
|
|
5807
|
+
category: "Conversion",
|
|
5808
|
+
paramsSchema: undefined,
|
|
5809
|
+
inferOutputSchema: () => stringSchema2,
|
|
5810
|
+
apply: (v) => String(v),
|
|
5811
|
+
suggestFromSchemas(source, target) {
|
|
5812
|
+
const s = source;
|
|
5813
|
+
const t = target;
|
|
5814
|
+
if ((s?.type === "number" || s?.type === "integer") && t?.type === "string") {
|
|
5815
|
+
return { score: 0.8, params: {} };
|
|
5816
|
+
}
|
|
5817
|
+
return;
|
|
5818
|
+
}
|
|
5819
|
+
};
|
|
5820
|
+
var toBooleanTransform = {
|
|
5821
|
+
id: "toBoolean",
|
|
5822
|
+
title: "To Boolean",
|
|
5823
|
+
category: "Conversion",
|
|
5824
|
+
paramsSchema: undefined,
|
|
5825
|
+
inferOutputSchema: () => booleanSchema,
|
|
5826
|
+
apply: (v) => {
|
|
5827
|
+
if (typeof v === "boolean")
|
|
5828
|
+
return v;
|
|
5829
|
+
if (typeof v === "number")
|
|
5830
|
+
return v !== 0;
|
|
5831
|
+
if (typeof v === "string")
|
|
5832
|
+
return v.toLowerCase() === "true" || v === "1";
|
|
5833
|
+
return Boolean(v);
|
|
5834
|
+
}
|
|
5835
|
+
};
|
|
5836
|
+
var stringifyTransform = {
|
|
5837
|
+
id: "stringify",
|
|
5838
|
+
title: "JSON.stringify",
|
|
5839
|
+
category: "Conversion",
|
|
5840
|
+
paramsSchema: undefined,
|
|
5841
|
+
inferOutputSchema: () => stringSchema2,
|
|
5842
|
+
apply: (v) => JSON.stringify(v),
|
|
5843
|
+
suggestFromSchemas(source, target) {
|
|
5844
|
+
const t = target;
|
|
5845
|
+
return t?.type === "string" ? { score: 0.4, params: {} } : undefined;
|
|
5846
|
+
}
|
|
5847
|
+
};
|
|
5848
|
+
var parseJsonTransform = {
|
|
5849
|
+
id: "parseJson",
|
|
5850
|
+
title: "Parse JSON",
|
|
5851
|
+
category: "Conversion",
|
|
5852
|
+
paramsSchema: undefined,
|
|
5853
|
+
inferOutputSchema: () => ({}),
|
|
5854
|
+
apply: (v) => JSON.parse(String(v))
|
|
5855
|
+
};
|
|
5856
|
+
|
|
5857
|
+
// src/task-graph/transforms/index.ts
|
|
5858
|
+
function registerBuiltInTransforms() {
|
|
5859
|
+
const all = [
|
|
5860
|
+
pickTransform,
|
|
5861
|
+
indexTransform,
|
|
5862
|
+
coalesceTransform,
|
|
5863
|
+
uppercaseTransform,
|
|
5864
|
+
lowercaseTransform,
|
|
5865
|
+
truncateTransform,
|
|
5866
|
+
substringTransform,
|
|
5867
|
+
unixToIsoDateTransform,
|
|
5868
|
+
isoDateToUnixTransform,
|
|
5869
|
+
numberToStringTransform,
|
|
5870
|
+
toBooleanTransform,
|
|
5871
|
+
stringifyTransform,
|
|
5872
|
+
parseJsonTransform
|
|
5873
|
+
];
|
|
5874
|
+
for (const t of all)
|
|
5875
|
+
TransformRegistry.registerTransform(t);
|
|
5876
|
+
}
|
|
5285
5877
|
// src/task/EntitlementProfiles.ts
|
|
5286
5878
|
var BROWSER_GRANTS = [
|
|
5287
5879
|
{ id: Entitlements.NETWORK_HTTP },
|
|
@@ -5610,15 +6202,15 @@ async function compactSchemaInputs(input, schema, config, visited = new Set) {
|
|
|
5610
6202
|
return compacted;
|
|
5611
6203
|
}
|
|
5612
6204
|
// src/task/IteratorTaskRunner.ts
|
|
5613
|
-
import { uuid4 as
|
|
6205
|
+
import { uuid4 as uuid47 } from "@workglow/util";
|
|
5614
6206
|
class IteratorTaskRunner extends GraphAsTaskRunner {
|
|
5615
6207
|
aggregatingParentMapProgress = false;
|
|
5616
6208
|
mapPartialProgress = [];
|
|
5617
6209
|
mapPartialIterationCount = 0;
|
|
5618
6210
|
async executeTask(input) {
|
|
5619
6211
|
let analysis = this.task.analyzeIterationInput(input);
|
|
5620
|
-
const maxIterations = this.task.config.maxIterations;
|
|
5621
|
-
if (
|
|
6212
|
+
const maxIterations = resolveIterationBound(this.task.config.maxIterations);
|
|
6213
|
+
if (analysis.iterationCount > maxIterations) {
|
|
5622
6214
|
analysis = { ...analysis, iterationCount: maxIterations };
|
|
5623
6215
|
}
|
|
5624
6216
|
if (analysis.iterationCount === 0) {
|
|
@@ -5724,7 +6316,7 @@ class IteratorTaskRunner extends GraphAsTaskRunner {
|
|
|
5724
6316
|
const idMap = new Map;
|
|
5725
6317
|
for (const task of graph.getTasks()) {
|
|
5726
6318
|
const ctor = task.constructor;
|
|
5727
|
-
const newId =
|
|
6319
|
+
const newId = uuid47();
|
|
5728
6320
|
idMap.set(task.config.id, newId);
|
|
5729
6321
|
const clonedConfig = { ...task.config, id: newId };
|
|
5730
6322
|
const newTask = new ctor({ ...clonedConfig, defaults: task.defaults }, task.runConfig);
|
|
@@ -5794,15 +6386,24 @@ var ITERATOR_CONTEXT_SCHEMA = {
|
|
|
5794
6386
|
}
|
|
5795
6387
|
}
|
|
5796
6388
|
};
|
|
6389
|
+
function resolveIterationBound(bound) {
|
|
6390
|
+
return bound === "unbounded" ? Number.POSITIVE_INFINITY : bound;
|
|
6391
|
+
}
|
|
5797
6392
|
var iteratorTaskConfigSchema = {
|
|
5798
6393
|
type: "object",
|
|
5799
6394
|
properties: {
|
|
5800
6395
|
...graphAsTaskConfigSchema["properties"],
|
|
5801
6396
|
concurrencyLimit: { type: "integer", minimum: 1 },
|
|
5802
6397
|
batchSize: { type: "integer", minimum: 1 },
|
|
5803
|
-
maxIterations: {
|
|
6398
|
+
maxIterations: {
|
|
6399
|
+
oneOf: [
|
|
6400
|
+
{ type: "integer", minimum: 1 },
|
|
6401
|
+
{ type: "string", const: "unbounded" }
|
|
6402
|
+
]
|
|
6403
|
+
},
|
|
5804
6404
|
iterationInputConfig: { type: "object", additionalProperties: true }
|
|
5805
6405
|
},
|
|
6406
|
+
required: ["maxIterations"],
|
|
5806
6407
|
additionalProperties: false
|
|
5807
6408
|
};
|
|
5808
6409
|
function isArrayVariant(schema) {
|
|
@@ -5917,6 +6518,12 @@ class IteratorTask extends GraphAsTask {
|
|
|
5917
6518
|
static configSchema() {
|
|
5918
6519
|
return iteratorTaskConfigSchema;
|
|
5919
6520
|
}
|
|
6521
|
+
constructor(config = {}, runConfig = {}) {
|
|
6522
|
+
if (config.maxIterations === undefined) {
|
|
6523
|
+
throw new TaskConfigurationError(`${new.target.type ?? "IteratorTask"}: maxIterations is required. ` + `Pass a positive integer to cap iteration, or "unbounded" to opt out explicitly.`);
|
|
6524
|
+
}
|
|
6525
|
+
super(config, runConfig);
|
|
6526
|
+
}
|
|
5920
6527
|
static getIterationContextSchema() {
|
|
5921
6528
|
return ITERATOR_CONTEXT_SCHEMA;
|
|
5922
6529
|
}
|
|
@@ -6306,13 +6913,19 @@ var whileTaskConfigSchema = {
|
|
|
6306
6913
|
properties: {
|
|
6307
6914
|
...graphAsTaskConfigSchema["properties"],
|
|
6308
6915
|
condition: {},
|
|
6309
|
-
maxIterations: {
|
|
6916
|
+
maxIterations: {
|
|
6917
|
+
oneOf: [
|
|
6918
|
+
{ type: "integer", minimum: 1 },
|
|
6919
|
+
{ type: "string", const: "unbounded" }
|
|
6920
|
+
]
|
|
6921
|
+
},
|
|
6310
6922
|
chainIterations: { type: "boolean" },
|
|
6311
6923
|
conditionField: { type: "string" },
|
|
6312
6924
|
conditionOperator: { type: "string" },
|
|
6313
6925
|
conditionValue: { type: "string" },
|
|
6314
6926
|
iterationInputConfig: { type: "object", additionalProperties: true }
|
|
6315
6927
|
},
|
|
6928
|
+
required: ["maxIterations"],
|
|
6316
6929
|
additionalProperties: false
|
|
6317
6930
|
};
|
|
6318
6931
|
|
|
@@ -6325,6 +6938,12 @@ class WhileTask extends GraphAsTask {
|
|
|
6325
6938
|
static configSchema() {
|
|
6326
6939
|
return whileTaskConfigSchema;
|
|
6327
6940
|
}
|
|
6941
|
+
constructor(config = {}, runConfig = {}) {
|
|
6942
|
+
if (config.maxIterations === undefined) {
|
|
6943
|
+
throw new TaskConfigurationError(`${new.target.type ?? "WhileTask"}: maxIterations is required. ` + `Pass a positive integer to cap iteration, or "unbounded" to opt out explicitly.`);
|
|
6944
|
+
}
|
|
6945
|
+
super(config, runConfig);
|
|
6946
|
+
}
|
|
6328
6947
|
static getIterationContextSchema() {
|
|
6329
6948
|
return WHILE_CONTEXT_SCHEMA;
|
|
6330
6949
|
}
|
|
@@ -6342,7 +6961,7 @@ class WhileTask extends GraphAsTask {
|
|
|
6342
6961
|
return this.config.condition;
|
|
6343
6962
|
}
|
|
6344
6963
|
get maxIterations() {
|
|
6345
|
-
return this.config.maxIterations
|
|
6964
|
+
return resolveIterationBound(this.config.maxIterations);
|
|
6346
6965
|
}
|
|
6347
6966
|
get chainIterations() {
|
|
6348
6967
|
return this.config.chainIterations ?? true;
|
|
@@ -6873,8 +7492,8 @@ import {
|
|
|
6873
7492
|
JobQueueServer
|
|
6874
7493
|
} from "@workglow/job-queue";
|
|
6875
7494
|
import { InMemoryQueueStorage } from "@workglow/storage";
|
|
6876
|
-
import { createServiceToken as
|
|
6877
|
-
var JOB_QUEUE_FACTORY =
|
|
7495
|
+
import { createServiceToken as createServiceToken5, globalServiceRegistry as globalServiceRegistry4 } from "@workglow/util";
|
|
7496
|
+
var JOB_QUEUE_FACTORY = createServiceToken5("taskgraph.jobQueueFactory");
|
|
6878
7497
|
var defaultJobQueueFactory = async ({
|
|
6879
7498
|
queueName,
|
|
6880
7499
|
jobClass,
|
|
@@ -6901,7 +7520,7 @@ var defaultJobQueueFactory = async ({
|
|
|
6901
7520
|
return { server, client, storage };
|
|
6902
7521
|
};
|
|
6903
7522
|
function registerJobQueueFactory(factory) {
|
|
6904
|
-
|
|
7523
|
+
globalServiceRegistry4.registerInstance(JOB_QUEUE_FACTORY, factory);
|
|
6905
7524
|
}
|
|
6906
7525
|
function createJobQueueFactoryWithOptions(defaultOptions = {}) {
|
|
6907
7526
|
return async ({
|
|
@@ -6935,12 +7554,12 @@ function createJobQueueFactoryWithOptions(defaultOptions = {}) {
|
|
|
6935
7554
|
};
|
|
6936
7555
|
}
|
|
6937
7556
|
function getJobQueueFactory() {
|
|
6938
|
-
if (!
|
|
7557
|
+
if (!globalServiceRegistry4.has(JOB_QUEUE_FACTORY)) {
|
|
6939
7558
|
registerJobQueueFactory(defaultJobQueueFactory);
|
|
6940
7559
|
}
|
|
6941
|
-
return
|
|
7560
|
+
return globalServiceRegistry4.get(JOB_QUEUE_FACTORY);
|
|
6942
7561
|
}
|
|
6943
|
-
if (!
|
|
7562
|
+
if (!globalServiceRegistry4.has(JOB_QUEUE_FACTORY)) {
|
|
6944
7563
|
registerJobQueueFactory(defaultJobQueueFactory);
|
|
6945
7564
|
}
|
|
6946
7565
|
// src/task/MapTask.ts
|
|
@@ -6949,8 +7568,10 @@ var mapTaskConfigSchema = {
|
|
|
6949
7568
|
properties: {
|
|
6950
7569
|
...iteratorTaskConfigSchema["properties"],
|
|
6951
7570
|
preserveOrder: { type: "boolean" },
|
|
6952
|
-
flatten: { type: "boolean" }
|
|
7571
|
+
flatten: { type: "boolean" },
|
|
7572
|
+
discardResults: { type: "boolean" }
|
|
6953
7573
|
},
|
|
7574
|
+
required: iteratorTaskConfigSchema.required,
|
|
6954
7575
|
additionalProperties: false
|
|
6955
7576
|
};
|
|
6956
7577
|
|
|
@@ -6983,6 +7604,9 @@ class MapTask extends IteratorTask {
|
|
|
6983
7604
|
get flatten() {
|
|
6984
7605
|
return this.config.flatten ?? false;
|
|
6985
7606
|
}
|
|
7607
|
+
get discardResults() {
|
|
7608
|
+
return this.config.discardResults ?? false;
|
|
7609
|
+
}
|
|
6986
7610
|
preserveIterationOrder() {
|
|
6987
7611
|
return this.preserveOrder;
|
|
6988
7612
|
}
|
|
@@ -7004,6 +7628,9 @@ class MapTask extends IteratorTask {
|
|
|
7004
7628
|
return this.getWrappedOutputSchema();
|
|
7005
7629
|
}
|
|
7006
7630
|
collectResults(results) {
|
|
7631
|
+
if (this.discardResults) {
|
|
7632
|
+
return this.getEmptyResult();
|
|
7633
|
+
}
|
|
7007
7634
|
const collected = super.collectResults(results);
|
|
7008
7635
|
if (!this.flatten || typeof collected !== "object" || collected === null) {
|
|
7009
7636
|
return collected;
|
|
@@ -7019,8 +7646,19 @@ class MapTask extends IteratorTask {
|
|
|
7019
7646
|
return flattened;
|
|
7020
7647
|
}
|
|
7021
7648
|
}
|
|
7649
|
+
|
|
7650
|
+
class ForEachTask extends MapTask {
|
|
7651
|
+
static type = "ForEachTask";
|
|
7652
|
+
static title = "For Each";
|
|
7653
|
+
static description = "Runs a workflow per array item for side effects; discards collected results";
|
|
7654
|
+
constructor(config = {}, runConfig = {}) {
|
|
7655
|
+
super({ discardResults: true, ...config }, runConfig);
|
|
7656
|
+
}
|
|
7657
|
+
}
|
|
7022
7658
|
Workflow.prototype.map = CreateLoopWorkflow(MapTask);
|
|
7023
7659
|
Workflow.prototype.endMap = CreateEndLoopWorkflow("endMap");
|
|
7660
|
+
Workflow.prototype.forEach = CreateLoopWorkflow(ForEachTask);
|
|
7661
|
+
Workflow.prototype.endForEach = CreateEndLoopWorkflow("endForEach");
|
|
7024
7662
|
// src/task/ReduceTask.ts
|
|
7025
7663
|
var reduceTaskConfigSchema = {
|
|
7026
7664
|
type: "object",
|
|
@@ -7028,6 +7666,7 @@ var reduceTaskConfigSchema = {
|
|
|
7028
7666
|
...iteratorTaskConfigSchema["properties"],
|
|
7029
7667
|
initialValue: {}
|
|
7030
7668
|
},
|
|
7669
|
+
required: iteratorTaskConfigSchema.required,
|
|
7031
7670
|
additionalProperties: false
|
|
7032
7671
|
};
|
|
7033
7672
|
|
|
@@ -7039,13 +7678,13 @@ class ReduceTask extends IteratorTask {
|
|
|
7039
7678
|
static configSchema() {
|
|
7040
7679
|
return reduceTaskConfigSchema;
|
|
7041
7680
|
}
|
|
7042
|
-
constructor(config = {}) {
|
|
7681
|
+
constructor(config = {}, runConfig = {}) {
|
|
7043
7682
|
const reduceConfig = {
|
|
7044
7683
|
...config,
|
|
7045
7684
|
concurrencyLimit: 1,
|
|
7046
7685
|
batchSize: 1
|
|
7047
7686
|
};
|
|
7048
|
-
super(reduceConfig);
|
|
7687
|
+
super(reduceConfig, runConfig);
|
|
7049
7688
|
}
|
|
7050
7689
|
get initialValue() {
|
|
7051
7690
|
return this.config.initialValue ?? {};
|
|
@@ -7117,9 +7756,9 @@ queueMicrotask(() => {
|
|
|
7117
7756
|
});
|
|
7118
7757
|
// src/task/TaskRegistry.ts
|
|
7119
7758
|
import {
|
|
7120
|
-
createServiceToken as
|
|
7759
|
+
createServiceToken as createServiceToken6,
|
|
7121
7760
|
getLogger as getLogger6,
|
|
7122
|
-
globalServiceRegistry as
|
|
7761
|
+
globalServiceRegistry as globalServiceRegistry5,
|
|
7123
7762
|
registerInputCompactor,
|
|
7124
7763
|
registerInputResolver
|
|
7125
7764
|
} from "@workglow/util";
|
|
@@ -7157,13 +7796,13 @@ var TaskRegistry = {
|
|
|
7157
7796
|
registerTask,
|
|
7158
7797
|
unregisterTask
|
|
7159
7798
|
};
|
|
7160
|
-
var TASK_CONSTRUCTORS =
|
|
7161
|
-
|
|
7799
|
+
var TASK_CONSTRUCTORS = createServiceToken6("task.constructors");
|
|
7800
|
+
globalServiceRegistry5.registerIfAbsent(TASK_CONSTRUCTORS, () => TaskRegistry.all, true);
|
|
7162
7801
|
function getGlobalTaskConstructors() {
|
|
7163
|
-
return
|
|
7802
|
+
return globalServiceRegistry5.get(TASK_CONSTRUCTORS);
|
|
7164
7803
|
}
|
|
7165
7804
|
function setGlobalTaskConstructors(map) {
|
|
7166
|
-
|
|
7805
|
+
globalServiceRegistry5.registerInstance(TASK_CONSTRUCTORS, map);
|
|
7167
7806
|
}
|
|
7168
7807
|
function getTaskConstructors(registry) {
|
|
7169
7808
|
if (!registry)
|
|
@@ -7260,7 +7899,11 @@ var createGraphFromGraphJSON = (graphJsonObj, registry, options) => {
|
|
|
7260
7899
|
subGraph.addTask(createTaskFromGraphJSON(subitem, registry, options));
|
|
7261
7900
|
}
|
|
7262
7901
|
for (const subitem of graphJsonObj.dataflows) {
|
|
7263
|
-
|
|
7902
|
+
const dataflow = new Dataflow(subitem.sourceTaskId, subitem.sourceTaskPortId, subitem.targetTaskId, subitem.targetTaskPortId);
|
|
7903
|
+
if (subitem.transforms && subitem.transforms.length > 0) {
|
|
7904
|
+
dataflow.setTransforms(subitem.transforms);
|
|
7905
|
+
}
|
|
7906
|
+
subGraph.addDataflow(dataflow);
|
|
7264
7907
|
}
|
|
7265
7908
|
return subGraph;
|
|
7266
7909
|
};
|
|
@@ -7318,8 +7961,8 @@ var registerBaseTasks = () => {
|
|
|
7318
7961
|
return tasks;
|
|
7319
7962
|
};
|
|
7320
7963
|
// src/storage/TaskGraphRepository.ts
|
|
7321
|
-
import { createServiceToken as
|
|
7322
|
-
var TASK_GRAPH_REPOSITORY =
|
|
7964
|
+
import { createServiceToken as createServiceToken7, EventEmitter as EventEmitter7 } from "@workglow/util";
|
|
7965
|
+
var TASK_GRAPH_REPOSITORY = createServiceToken7("taskgraph.taskGraphRepository");
|
|
7323
7966
|
|
|
7324
7967
|
class TaskGraphRepository {
|
|
7325
7968
|
type = "TaskGraphRepository";
|
|
@@ -7479,7 +8122,13 @@ class TaskOutputTabularRepository extends TaskOutputRepository {
|
|
|
7479
8122
|
export {
|
|
7480
8123
|
wrapSchemaInArray,
|
|
7481
8124
|
whileTaskConfigSchema,
|
|
8125
|
+
uppercaseTransform,
|
|
8126
|
+
unixToIsoDateTransform,
|
|
8127
|
+
truncateTransform,
|
|
8128
|
+
toBooleanTransform,
|
|
7482
8129
|
taskPrototypeHasOwnExecute,
|
|
8130
|
+
substringTransform,
|
|
8131
|
+
stringifyTransform,
|
|
7483
8132
|
setTaskQueueRegistry,
|
|
7484
8133
|
setGlobalTaskConstructors,
|
|
7485
8134
|
serialGraph,
|
|
@@ -7489,23 +8138,31 @@ export {
|
|
|
7489
8138
|
scanGraphForCredentials,
|
|
7490
8139
|
resourcePatternMatches,
|
|
7491
8140
|
resolveSchemaInputs,
|
|
8141
|
+
resolveIterationBound,
|
|
7492
8142
|
resetMethodNameCache,
|
|
7493
8143
|
removeIterationProperties,
|
|
7494
8144
|
registerJobQueueFactory,
|
|
8145
|
+
registerBuiltInTransforms,
|
|
7495
8146
|
registerBaseTasks,
|
|
7496
8147
|
reduceTaskConfigSchema,
|
|
7497
8148
|
pipe,
|
|
8149
|
+
pickTransform,
|
|
8150
|
+
parseJsonTransform,
|
|
7498
8151
|
parallel,
|
|
8152
|
+
numberToStringTransform,
|
|
7499
8153
|
mergeResources,
|
|
7500
8154
|
mergeEntitlements,
|
|
7501
8155
|
mergeEntitlementPair,
|
|
7502
8156
|
mergeChainedOutputToInput,
|
|
7503
8157
|
mapTaskConfigSchema,
|
|
8158
|
+
lowercaseTransform,
|
|
7504
8159
|
iteratorTaskConfigSchema,
|
|
8160
|
+
isoDateToUnixTransform,
|
|
7505
8161
|
isTaskStreamable,
|
|
7506
8162
|
isStrictArraySchema,
|
|
7507
8163
|
isIterationProperty,
|
|
7508
8164
|
isFlexibleSchema,
|
|
8165
|
+
indexTransform,
|
|
7509
8166
|
hasVectorOutput,
|
|
7510
8167
|
hasVectorLikeInput,
|
|
7511
8168
|
hasStructuredOutput,
|
|
@@ -7531,6 +8188,7 @@ export {
|
|
|
7531
8188
|
getFormatPrefix,
|
|
7532
8189
|
getAppendPortId,
|
|
7533
8190
|
formatValue,
|
|
8191
|
+
formatEntitlementDenial,
|
|
7534
8192
|
findArrayPorts,
|
|
7535
8193
|
filterIterationProperties,
|
|
7536
8194
|
fallbackTaskConfigSchema,
|
|
@@ -7559,8 +8217,11 @@ export {
|
|
|
7559
8217
|
computeGraphInputSchema,
|
|
7560
8218
|
computeGraphEntitlements,
|
|
7561
8219
|
compactSchemaInputs,
|
|
8220
|
+
coalesceTransform,
|
|
8221
|
+
can,
|
|
7562
8222
|
calculateNodeDepths,
|
|
7563
8223
|
buildIterationInputSchema,
|
|
8224
|
+
autoConnect,
|
|
7564
8225
|
addIterationContextToSchema,
|
|
7565
8226
|
addBoundaryNodesToGraphJson,
|
|
7566
8227
|
addBoundaryNodesToDependencyJson,
|
|
@@ -7569,6 +8230,7 @@ export {
|
|
|
7569
8230
|
WhileTaskRunner,
|
|
7570
8231
|
WhileTask,
|
|
7571
8232
|
WHILE_CONTEXT_SCHEMA,
|
|
8233
|
+
TransformRegistry,
|
|
7572
8234
|
TaskTimeoutError,
|
|
7573
8235
|
TaskStatus,
|
|
7574
8236
|
TaskSerializationError,
|
|
@@ -7594,6 +8256,7 @@ export {
|
|
|
7594
8256
|
TaskConfigSchema,
|
|
7595
8257
|
TaskAbortedError,
|
|
7596
8258
|
Task,
|
|
8259
|
+
TRANSFORM_DEFS,
|
|
7597
8260
|
TASK_OUTPUT_REPOSITORY,
|
|
7598
8261
|
TASK_GRAPH_REPOSITORY,
|
|
7599
8262
|
TASK_CONSTRUCTORS,
|
|
@@ -7611,6 +8274,7 @@ export {
|
|
|
7611
8274
|
GraphAsTaskRunner,
|
|
7612
8275
|
GraphAsTask,
|
|
7613
8276
|
GRAPH_RESULT_ARRAY,
|
|
8277
|
+
ForEachTask,
|
|
7614
8278
|
FallbackTaskRunner,
|
|
7615
8279
|
FallbackTask,
|
|
7616
8280
|
EventTaskGraphToDagMapping,
|
|
@@ -7634,4 +8298,4 @@ export {
|
|
|
7634
8298
|
BROWSER_GRANTS
|
|
7635
8299
|
};
|
|
7636
8300
|
|
|
7637
|
-
//# debugId=
|
|
8301
|
+
//# debugId=2328438A94292C4964756E2164756E21
|