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