@workglow/task-graph 0.0.115 → 0.0.116
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/Workflow-7eps4dfz.js +31 -0
- package/dist/Workflow-7eps4dfz.js.map +9 -0
- package/dist/Workflow-v7wec8kc.js +31 -0
- package/dist/Workflow-v7wec8kc.js.map +9 -0
- package/dist/Workflow-wrs2y87g.js +32 -0
- package/dist/Workflow-wrs2y87g.js.map +9 -0
- package/dist/browser-bmjr6xz5.js +4245 -0
- package/dist/browser-bmjr6xz5.js.map +28 -0
- package/dist/browser.js +482 -4059
- package/dist/browser.js.map +11 -28
- package/dist/bun-tgs39x49.js +4240 -0
- package/dist/bun-tgs39x49.js.map +28 -0
- package/dist/bun.js +482 -4059
- package/dist/bun.js.map +11 -28
- package/dist/common.d.ts +1 -0
- package/dist/common.d.ts.map +1 -1
- package/dist/node-mthgc8tr.js +4240 -0
- package/dist/node-mthgc8tr.js.map +28 -0
- package/dist/node.js +482 -4059
- package/dist/node.js.map +11 -28
- package/dist/task/GraphAsTask.d.ts +14 -1
- package/dist/task/GraphAsTask.d.ts.map +1 -1
- package/dist/task/ITask.d.ts.map +1 -1
- package/dist/task/IteratorTaskRunner.d.ts.map +1 -1
- package/dist/task/MapTask.d.ts.map +1 -1
- package/dist/task/Task.d.ts.map +1 -1
- package/dist/task/TaskRunner.d.ts +5 -5
- package/dist/task/TaskRunner.d.ts.map +1 -1
- package/dist/task-graph/Conversions.d.ts +0 -15
- package/dist/task-graph/Conversions.d.ts.map +1 -1
- package/dist/task-graph/GraphToWorkflowCode.d.ts +46 -0
- package/dist/task-graph/GraphToWorkflowCode.d.ts.map +1 -0
- package/dist/task-graph/IWorkflow.d.ts +6 -1
- package/dist/task-graph/IWorkflow.d.ts.map +1 -1
- package/dist/task-graph/TaskGraphRunner.d.ts +5 -5
- package/dist/task-graph/TaskGraphRunner.d.ts.map +1 -1
- package/dist/task-graph/Workflow.d.ts +19 -3
- package/dist/task-graph/Workflow.d.ts.map +1 -1
- package/package.json +7 -7
package/dist/bun.js
CHANGED
|
@@ -1,4065 +1,432 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// src/task-graph/Dataflow.ts
|
|
3
|
-
import { areSemanticallyCompatible, EventEmitter } from "@workglow/util";
|
|
4
|
-
|
|
5
|
-
// src/task/TaskTypes.ts
|
|
6
|
-
var TaskStatus = {
|
|
7
|
-
PENDING: "PENDING",
|
|
8
|
-
DISABLED: "DISABLED",
|
|
9
|
-
PROCESSING: "PROCESSING",
|
|
10
|
-
STREAMING: "STREAMING",
|
|
11
|
-
COMPLETED: "COMPLETED",
|
|
12
|
-
ABORTING: "ABORTING",
|
|
13
|
-
FAILED: "FAILED"
|
|
14
|
-
};
|
|
15
|
-
var TaskConfigSchema = {
|
|
16
|
-
type: "object",
|
|
17
|
-
properties: {
|
|
18
|
-
id: {
|
|
19
|
-
"x-ui-hidden": true
|
|
20
|
-
},
|
|
21
|
-
title: { type: "string" },
|
|
22
|
-
description: { type: "string" },
|
|
23
|
-
cacheable: { type: "boolean" },
|
|
24
|
-
timeout: { type: "number", description: "Max execution time in milliseconds" },
|
|
25
|
-
inputSchema: {
|
|
26
|
-
type: "object",
|
|
27
|
-
properties: {},
|
|
28
|
-
additionalProperties: true,
|
|
29
|
-
"x-ui-hidden": true
|
|
30
|
-
},
|
|
31
|
-
outputSchema: {
|
|
32
|
-
type: "object",
|
|
33
|
-
properties: {},
|
|
34
|
-
additionalProperties: true,
|
|
35
|
-
"x-ui-hidden": true
|
|
36
|
-
},
|
|
37
|
-
extras: {
|
|
38
|
-
type: "object",
|
|
39
|
-
additionalProperties: true,
|
|
40
|
-
"x-ui-hidden": true
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
additionalProperties: false
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
// src/task-graph/Dataflow.ts
|
|
47
|
-
var DATAFLOW_ALL_PORTS = "*";
|
|
48
|
-
var DATAFLOW_ERROR_PORT = "[error]";
|
|
49
|
-
|
|
50
|
-
class Dataflow {
|
|
51
|
-
sourceTaskId;
|
|
52
|
-
sourceTaskPortId;
|
|
53
|
-
targetTaskId;
|
|
54
|
-
targetTaskPortId;
|
|
55
|
-
constructor(sourceTaskId, sourceTaskPortId, targetTaskId, targetTaskPortId) {
|
|
56
|
-
this.sourceTaskId = sourceTaskId;
|
|
57
|
-
this.sourceTaskPortId = sourceTaskPortId;
|
|
58
|
-
this.targetTaskId = targetTaskId;
|
|
59
|
-
this.targetTaskPortId = targetTaskPortId;
|
|
60
|
-
}
|
|
61
|
-
static createId(sourceTaskId, sourceTaskPortId, targetTaskId, targetTaskPortId) {
|
|
62
|
-
return `${sourceTaskId}[${sourceTaskPortId}] ==> ${targetTaskId}[${targetTaskPortId}]`;
|
|
63
|
-
}
|
|
64
|
-
get id() {
|
|
65
|
-
return Dataflow.createId(this.sourceTaskId, this.sourceTaskPortId, this.targetTaskId, this.targetTaskPortId);
|
|
66
|
-
}
|
|
67
|
-
value = undefined;
|
|
68
|
-
status = TaskStatus.PENDING;
|
|
69
|
-
error;
|
|
70
|
-
stream = undefined;
|
|
71
|
-
setStream(stream) {
|
|
72
|
-
this.stream = stream;
|
|
73
|
-
}
|
|
74
|
-
getStream() {
|
|
75
|
-
return this.stream;
|
|
76
|
-
}
|
|
77
|
-
async awaitStreamValue() {
|
|
78
|
-
if (!this.stream)
|
|
79
|
-
return;
|
|
80
|
-
const reader = this.stream.getReader();
|
|
81
|
-
let lastSnapshotData = undefined;
|
|
82
|
-
let finishData = undefined;
|
|
83
|
-
let streamError;
|
|
84
|
-
try {
|
|
85
|
-
while (true) {
|
|
86
|
-
const { done, value: event } = await reader.read();
|
|
87
|
-
if (done)
|
|
88
|
-
break;
|
|
89
|
-
switch (event.type) {
|
|
90
|
-
case "snapshot":
|
|
91
|
-
lastSnapshotData = event.data;
|
|
92
|
-
break;
|
|
93
|
-
case "finish":
|
|
94
|
-
finishData = event.data;
|
|
95
|
-
break;
|
|
96
|
-
case "error":
|
|
97
|
-
streamError = event.error;
|
|
98
|
-
break;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
} finally {
|
|
102
|
-
reader.releaseLock();
|
|
103
|
-
this.stream = undefined;
|
|
104
|
-
}
|
|
105
|
-
if (streamError) {
|
|
106
|
-
this.error = streamError;
|
|
107
|
-
this.setStatus(TaskStatus.FAILED);
|
|
108
|
-
throw streamError;
|
|
109
|
-
}
|
|
110
|
-
if (lastSnapshotData !== undefined) {
|
|
111
|
-
this.setPortData(lastSnapshotData);
|
|
112
|
-
} else if (finishData !== undefined) {
|
|
113
|
-
this.setPortData(finishData);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
reset() {
|
|
117
|
-
this.status = TaskStatus.PENDING;
|
|
118
|
-
this.error = undefined;
|
|
119
|
-
this.value = undefined;
|
|
120
|
-
this.stream = undefined;
|
|
121
|
-
this.emit("reset");
|
|
122
|
-
this.emit("status", this.status);
|
|
123
|
-
}
|
|
124
|
-
setStatus(status) {
|
|
125
|
-
if (status === this.status)
|
|
126
|
-
return;
|
|
127
|
-
this.status = status;
|
|
128
|
-
switch (status) {
|
|
129
|
-
case TaskStatus.PROCESSING:
|
|
130
|
-
this.emit("start");
|
|
131
|
-
break;
|
|
132
|
-
case TaskStatus.STREAMING:
|
|
133
|
-
this.emit("streaming");
|
|
134
|
-
break;
|
|
135
|
-
case TaskStatus.COMPLETED:
|
|
136
|
-
this.emit("complete");
|
|
137
|
-
break;
|
|
138
|
-
case TaskStatus.ABORTING:
|
|
139
|
-
this.emit("abort");
|
|
140
|
-
break;
|
|
141
|
-
case TaskStatus.PENDING:
|
|
142
|
-
this.emit("reset");
|
|
143
|
-
break;
|
|
144
|
-
case TaskStatus.FAILED:
|
|
145
|
-
this.emit("error", this.error);
|
|
146
|
-
break;
|
|
147
|
-
case TaskStatus.DISABLED:
|
|
148
|
-
this.emit("disabled");
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
this.emit("status", this.status);
|
|
152
|
-
}
|
|
153
|
-
setPortData(entireDataBlock) {
|
|
154
|
-
if (this.sourceTaskPortId === DATAFLOW_ALL_PORTS) {
|
|
155
|
-
this.value = entireDataBlock;
|
|
156
|
-
} else if (this.sourceTaskPortId === DATAFLOW_ERROR_PORT) {
|
|
157
|
-
this.error = entireDataBlock;
|
|
158
|
-
} else {
|
|
159
|
-
this.value = entireDataBlock[this.sourceTaskPortId];
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
getPortData() {
|
|
163
|
-
let result;
|
|
164
|
-
if (this.targetTaskPortId === DATAFLOW_ALL_PORTS) {
|
|
165
|
-
result = this.value;
|
|
166
|
-
} else if (this.targetTaskPortId === DATAFLOW_ERROR_PORT) {
|
|
167
|
-
result = { [DATAFLOW_ERROR_PORT]: this.error };
|
|
168
|
-
} else {
|
|
169
|
-
result = { [this.targetTaskPortId]: this.value };
|
|
170
|
-
}
|
|
171
|
-
return result;
|
|
172
|
-
}
|
|
173
|
-
toJSON() {
|
|
174
|
-
return {
|
|
175
|
-
sourceTaskId: this.sourceTaskId,
|
|
176
|
-
sourceTaskPortId: this.sourceTaskPortId,
|
|
177
|
-
targetTaskId: this.targetTaskId,
|
|
178
|
-
targetTaskPortId: this.targetTaskPortId
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
semanticallyCompatible(graph, dataflow) {
|
|
182
|
-
const targetSchema = graph.getTask(dataflow.targetTaskId).inputSchema();
|
|
183
|
-
const sourceSchema = graph.getTask(dataflow.sourceTaskId).outputSchema();
|
|
184
|
-
if (typeof targetSchema === "boolean") {
|
|
185
|
-
if (targetSchema === false) {
|
|
186
|
-
return "incompatible";
|
|
187
|
-
}
|
|
188
|
-
return "static";
|
|
189
|
-
}
|
|
190
|
-
if (typeof sourceSchema === "boolean") {
|
|
191
|
-
if (sourceSchema === false) {
|
|
192
|
-
return "incompatible";
|
|
193
|
-
}
|
|
194
|
-
return "runtime";
|
|
195
|
-
}
|
|
196
|
-
let targetSchemaProperty = DATAFLOW_ALL_PORTS === dataflow.targetTaskPortId ? true : targetSchema.properties?.[dataflow.targetTaskPortId];
|
|
197
|
-
if (targetSchemaProperty === undefined && targetSchema.additionalProperties === true) {
|
|
198
|
-
targetSchemaProperty = true;
|
|
199
|
-
}
|
|
200
|
-
let sourceSchemaProperty = DATAFLOW_ALL_PORTS === dataflow.sourceTaskPortId ? true : sourceSchema.properties?.[dataflow.sourceTaskPortId];
|
|
201
|
-
if (sourceSchemaProperty === undefined && sourceSchema.additionalProperties === true) {
|
|
202
|
-
sourceSchemaProperty = true;
|
|
203
|
-
}
|
|
204
|
-
const semanticallyCompatible = areSemanticallyCompatible(sourceSchemaProperty, targetSchemaProperty);
|
|
205
|
-
return semanticallyCompatible;
|
|
206
|
-
}
|
|
207
|
-
get events() {
|
|
208
|
-
if (!this._events) {
|
|
209
|
-
this._events = new EventEmitter;
|
|
210
|
-
}
|
|
211
|
-
return this._events;
|
|
212
|
-
}
|
|
213
|
-
_events;
|
|
214
|
-
subscribe(name, fn) {
|
|
215
|
-
return this.events.subscribe(name, fn);
|
|
216
|
-
}
|
|
217
|
-
on(name, fn) {
|
|
218
|
-
this.events.on(name, fn);
|
|
219
|
-
}
|
|
220
|
-
off(name, fn) {
|
|
221
|
-
this.events.off(name, fn);
|
|
222
|
-
}
|
|
223
|
-
once(name, fn) {
|
|
224
|
-
this.events.once(name, fn);
|
|
225
|
-
}
|
|
226
|
-
waitOn(name) {
|
|
227
|
-
return this.events.waitOn(name);
|
|
228
|
-
}
|
|
229
|
-
emit(name, ...args) {
|
|
230
|
-
this._events?.emit(name, ...args);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
class DataflowArrow extends Dataflow {
|
|
235
|
-
constructor(dataflow) {
|
|
236
|
-
const pattern = /^([a-zA-Z0-9-]+?)\[([a-zA-Z0-9-]+?)\] ==> ([a-zA-Z0-9-]+?)\[([a-zA-Z0-9-]+?)\]$/;
|
|
237
|
-
const match = dataflow.match(pattern);
|
|
238
|
-
if (!match) {
|
|
239
|
-
throw new Error(`Invalid dataflow format: ${dataflow}`);
|
|
240
|
-
}
|
|
241
|
-
const [, sourceTaskId, sourceTaskPortId, targetTaskId, targetTaskPortId] = match;
|
|
242
|
-
super(sourceTaskId, sourceTaskPortId, targetTaskId, targetTaskPortId);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
// src/task-graph/GraphSchemaUtils.ts
|
|
246
|
-
import { uuid4 } from "@workglow/util";
|
|
247
|
-
function calculateNodeDepths(graph) {
|
|
248
|
-
const depths = new Map;
|
|
249
|
-
const tasks = graph.getTasks();
|
|
250
|
-
for (const task of tasks) {
|
|
251
|
-
depths.set(task.id, 0);
|
|
252
|
-
}
|
|
253
|
-
const sortedTasks = graph.topologicallySortedNodes();
|
|
254
|
-
for (const task of sortedTasks) {
|
|
255
|
-
const currentDepth = depths.get(task.id) || 0;
|
|
256
|
-
const targetTasks = graph.getTargetTasks(task.id);
|
|
257
|
-
for (const targetTask of targetTasks) {
|
|
258
|
-
const targetDepth = depths.get(targetTask.id) || 0;
|
|
259
|
-
depths.set(targetTask.id, Math.max(targetDepth, currentDepth + 1));
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
return depths;
|
|
263
|
-
}
|
|
264
|
-
function computeGraphInputSchema(graph, options) {
|
|
265
|
-
const trackOrigins = options?.trackOrigins ?? false;
|
|
266
|
-
const properties = {};
|
|
267
|
-
const required = [];
|
|
268
|
-
const propertyOrigins = {};
|
|
269
|
-
const tasks = graph.getTasks();
|
|
270
|
-
const startingNodes = tasks.filter((task) => graph.getSourceDataflows(task.id).length === 0);
|
|
271
|
-
for (const task of startingNodes) {
|
|
272
|
-
const taskInputSchema = task.inputSchema();
|
|
273
|
-
if (typeof taskInputSchema === "boolean") {
|
|
274
|
-
if (taskInputSchema === false) {
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
if (taskInputSchema === true) {
|
|
278
|
-
properties[DATAFLOW_ALL_PORTS] = {};
|
|
279
|
-
continue;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
const taskProperties = taskInputSchema.properties || {};
|
|
283
|
-
for (const [inputName, inputProp] of Object.entries(taskProperties)) {
|
|
284
|
-
if (!properties[inputName]) {
|
|
285
|
-
properties[inputName] = inputProp;
|
|
286
|
-
if (taskInputSchema.required && taskInputSchema.required.includes(inputName)) {
|
|
287
|
-
required.push(inputName);
|
|
288
|
-
}
|
|
289
|
-
if (trackOrigins) {
|
|
290
|
-
propertyOrigins[inputName] = [task.id];
|
|
291
|
-
}
|
|
292
|
-
} else if (trackOrigins) {
|
|
293
|
-
propertyOrigins[inputName].push(task.id);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
const sourceIds = new Set(startingNodes.map((t) => t.id));
|
|
298
|
-
for (const task of tasks) {
|
|
299
|
-
if (sourceIds.has(task.id))
|
|
300
|
-
continue;
|
|
301
|
-
const taskInputSchema = task.inputSchema();
|
|
302
|
-
if (typeof taskInputSchema === "boolean")
|
|
303
|
-
continue;
|
|
304
|
-
const requiredKeys = new Set(taskInputSchema.required || []);
|
|
305
|
-
if (requiredKeys.size === 0)
|
|
306
|
-
continue;
|
|
307
|
-
const connectedPorts = new Set(graph.getSourceDataflows(task.id).map((df) => df.targetTaskPortId));
|
|
308
|
-
for (const key of requiredKeys) {
|
|
309
|
-
if (connectedPorts.has(key))
|
|
310
|
-
continue;
|
|
311
|
-
if (properties[key]) {
|
|
312
|
-
if (trackOrigins) {
|
|
313
|
-
propertyOrigins[key].push(task.id);
|
|
314
|
-
}
|
|
315
|
-
continue;
|
|
316
|
-
}
|
|
317
|
-
if (task.defaults && task.defaults[key] !== undefined)
|
|
318
|
-
continue;
|
|
319
|
-
const prop = (taskInputSchema.properties || {})[key];
|
|
320
|
-
if (!prop || typeof prop === "boolean")
|
|
321
|
-
continue;
|
|
322
|
-
properties[key] = prop;
|
|
323
|
-
if (!required.includes(key)) {
|
|
324
|
-
required.push(key);
|
|
325
|
-
}
|
|
326
|
-
if (trackOrigins) {
|
|
327
|
-
propertyOrigins[key] = [task.id];
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
if (trackOrigins) {
|
|
332
|
-
for (const [propName, origins] of Object.entries(propertyOrigins)) {
|
|
333
|
-
const prop = properties[propName];
|
|
334
|
-
if (!prop || typeof prop === "boolean")
|
|
335
|
-
continue;
|
|
336
|
-
if (origins.length === 1) {
|
|
337
|
-
properties[propName] = { ...prop, "x-source-task-id": origins[0] };
|
|
338
|
-
} else {
|
|
339
|
-
properties[propName] = { ...prop, "x-source-task-ids": origins };
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
return {
|
|
344
|
-
type: "object",
|
|
345
|
-
properties,
|
|
346
|
-
...required.length > 0 ? { required } : {},
|
|
347
|
-
additionalProperties: false
|
|
348
|
-
};
|
|
349
|
-
}
|
|
350
|
-
function computeGraphOutputSchema(graph, options) {
|
|
351
|
-
const trackOrigins = options?.trackOrigins ?? false;
|
|
352
|
-
const properties = {};
|
|
353
|
-
const required = [];
|
|
354
|
-
const propertyOrigins = {};
|
|
355
|
-
const tasks = graph.getTasks();
|
|
356
|
-
const endingNodes = tasks.filter((task) => graph.getTargetDataflows(task.id).length === 0);
|
|
357
|
-
const depths = calculateNodeDepths(graph);
|
|
358
|
-
const maxDepth = Math.max(...endingNodes.map((task) => depths.get(task.id) || 0));
|
|
359
|
-
const lastLevelNodes = endingNodes.filter((task) => depths.get(task.id) === maxDepth);
|
|
360
|
-
const propertyCount = {};
|
|
361
|
-
const propertySchema = {};
|
|
362
|
-
for (const task of lastLevelNodes) {
|
|
363
|
-
const taskOutputSchema = task.outputSchema();
|
|
364
|
-
if (typeof taskOutputSchema === "boolean") {
|
|
365
|
-
if (taskOutputSchema === false) {
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
if (taskOutputSchema === true) {
|
|
369
|
-
properties[DATAFLOW_ALL_PORTS] = {};
|
|
370
|
-
continue;
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
const taskProperties = taskOutputSchema.properties || {};
|
|
374
|
-
for (const [outputName, outputProp] of Object.entries(taskProperties)) {
|
|
375
|
-
propertyCount[outputName] = (propertyCount[outputName] || 0) + 1;
|
|
376
|
-
if (!propertySchema[outputName]) {
|
|
377
|
-
propertySchema[outputName] = outputProp;
|
|
378
|
-
}
|
|
379
|
-
if (trackOrigins) {
|
|
380
|
-
if (!propertyOrigins[outputName]) {
|
|
381
|
-
propertyOrigins[outputName] = [task.id];
|
|
382
|
-
} else {
|
|
383
|
-
propertyOrigins[outputName].push(task.id);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
for (const [outputName] of Object.entries(propertyCount)) {
|
|
389
|
-
const outputProp = propertySchema[outputName];
|
|
390
|
-
if (lastLevelNodes.length === 1) {
|
|
391
|
-
properties[outputName] = outputProp;
|
|
392
|
-
} else {
|
|
393
|
-
properties[outputName] = {
|
|
394
|
-
type: "array",
|
|
395
|
-
items: outputProp
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
if (trackOrigins) {
|
|
400
|
-
for (const [propName, origins] of Object.entries(propertyOrigins)) {
|
|
401
|
-
const prop = properties[propName];
|
|
402
|
-
if (!prop || typeof prop === "boolean")
|
|
403
|
-
continue;
|
|
404
|
-
if (origins.length === 1) {
|
|
405
|
-
properties[propName] = { ...prop, "x-source-task-id": origins[0] };
|
|
406
|
-
} else {
|
|
407
|
-
properties[propName] = { ...prop, "x-source-task-ids": origins };
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
return {
|
|
412
|
-
type: "object",
|
|
413
|
-
properties,
|
|
414
|
-
...required.length > 0 ? { required } : {},
|
|
415
|
-
additionalProperties: false
|
|
416
|
-
};
|
|
417
|
-
}
|
|
418
|
-
function stripOriginAnnotations(schema) {
|
|
419
|
-
if (typeof schema === "boolean" || !schema || typeof schema !== "object")
|
|
420
|
-
return schema;
|
|
421
|
-
const properties = schema.properties;
|
|
422
|
-
if (!properties)
|
|
423
|
-
return schema;
|
|
424
|
-
const strippedProperties = {};
|
|
425
|
-
for (const [key, prop] of Object.entries(properties)) {
|
|
426
|
-
if (!prop || typeof prop !== "object") {
|
|
427
|
-
strippedProperties[key] = prop;
|
|
428
|
-
continue;
|
|
429
|
-
}
|
|
430
|
-
const {
|
|
431
|
-
"x-source-task-id": _id,
|
|
432
|
-
"x-source-task-ids": _ids,
|
|
433
|
-
...rest
|
|
434
|
-
} = prop;
|
|
435
|
-
strippedProperties[key] = rest;
|
|
436
|
-
}
|
|
437
|
-
return { ...schema, properties: strippedProperties };
|
|
438
|
-
}
|
|
439
|
-
function getOriginTaskIds(prop) {
|
|
440
|
-
if (prop["x-source-task-ids"]) {
|
|
441
|
-
return prop["x-source-task-ids"];
|
|
442
|
-
}
|
|
443
|
-
if (prop["x-source-task-id"] !== undefined) {
|
|
444
|
-
return [prop["x-source-task-id"]];
|
|
445
|
-
}
|
|
446
|
-
return [];
|
|
447
|
-
}
|
|
448
|
-
function addBoundaryNodesToGraphJson(json, graph) {
|
|
449
|
-
const hasInputTask = json.tasks.some((t) => t.type === "InputTask");
|
|
450
|
-
const hasOutputTask = json.tasks.some((t) => t.type === "OutputTask");
|
|
451
|
-
if (hasInputTask && hasOutputTask) {
|
|
452
|
-
return json;
|
|
453
|
-
}
|
|
454
|
-
const inputSchema = !hasInputTask ? computeGraphInputSchema(graph, { trackOrigins: true }) : undefined;
|
|
455
|
-
const outputSchema = !hasOutputTask ? computeGraphOutputSchema(graph, { trackOrigins: true }) : undefined;
|
|
456
|
-
const prependTasks = [];
|
|
457
|
-
const appendTasks = [];
|
|
458
|
-
const inputDataflows = [];
|
|
459
|
-
const outputDataflows = [];
|
|
460
|
-
if (!hasInputTask && inputSchema) {
|
|
461
|
-
const inputTaskId = uuid4();
|
|
462
|
-
const strippedInputSchema = stripOriginAnnotations(inputSchema);
|
|
463
|
-
prependTasks.push({
|
|
464
|
-
id: inputTaskId,
|
|
465
|
-
type: "InputTask",
|
|
466
|
-
config: {
|
|
467
|
-
inputSchema: strippedInputSchema,
|
|
468
|
-
outputSchema: strippedInputSchema
|
|
469
|
-
}
|
|
470
|
-
});
|
|
471
|
-
if (typeof inputSchema !== "boolean" && inputSchema.properties) {
|
|
472
|
-
for (const [propName, prop] of Object.entries(inputSchema.properties)) {
|
|
473
|
-
if (!prop || typeof prop === "boolean")
|
|
474
|
-
continue;
|
|
475
|
-
const origins = getOriginTaskIds(prop);
|
|
476
|
-
for (const originId of origins) {
|
|
477
|
-
inputDataflows.push({
|
|
478
|
-
sourceTaskId: inputTaskId,
|
|
479
|
-
sourceTaskPortId: propName,
|
|
480
|
-
targetTaskId: originId,
|
|
481
|
-
targetTaskPortId: propName
|
|
482
|
-
});
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
if (!hasOutputTask && outputSchema) {
|
|
488
|
-
const outputTaskId = uuid4();
|
|
489
|
-
const strippedOutputSchema = stripOriginAnnotations(outputSchema);
|
|
490
|
-
appendTasks.push({
|
|
491
|
-
id: outputTaskId,
|
|
492
|
-
type: "OutputTask",
|
|
493
|
-
config: {
|
|
494
|
-
inputSchema: strippedOutputSchema,
|
|
495
|
-
outputSchema: strippedOutputSchema
|
|
496
|
-
}
|
|
497
|
-
});
|
|
498
|
-
if (typeof outputSchema !== "boolean" && outputSchema.properties) {
|
|
499
|
-
for (const [propName, prop] of Object.entries(outputSchema.properties)) {
|
|
500
|
-
if (!prop || typeof prop === "boolean")
|
|
501
|
-
continue;
|
|
502
|
-
const origins = getOriginTaskIds(prop);
|
|
503
|
-
for (const originId of origins) {
|
|
504
|
-
outputDataflows.push({
|
|
505
|
-
sourceTaskId: originId,
|
|
506
|
-
sourceTaskPortId: propName,
|
|
507
|
-
targetTaskId: outputTaskId,
|
|
508
|
-
targetTaskPortId: propName
|
|
509
|
-
});
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
return {
|
|
515
|
-
tasks: [...prependTasks, ...json.tasks, ...appendTasks],
|
|
516
|
-
dataflows: [...inputDataflows, ...json.dataflows, ...outputDataflows]
|
|
517
|
-
};
|
|
518
|
-
}
|
|
519
|
-
function addBoundaryNodesToDependencyJson(items, graph) {
|
|
520
|
-
const hasInputTask = items.some((t) => t.type === "InputTask");
|
|
521
|
-
const hasOutputTask = items.some((t) => t.type === "OutputTask");
|
|
522
|
-
if (hasInputTask && hasOutputTask) {
|
|
523
|
-
return items;
|
|
524
|
-
}
|
|
525
|
-
const prependItems = [];
|
|
526
|
-
const appendItems = [];
|
|
527
|
-
if (!hasInputTask) {
|
|
528
|
-
const inputSchema = computeGraphInputSchema(graph, { trackOrigins: true });
|
|
529
|
-
const inputTaskId = uuid4();
|
|
530
|
-
const strippedInputSchema = stripOriginAnnotations(inputSchema);
|
|
531
|
-
prependItems.push({
|
|
532
|
-
id: inputTaskId,
|
|
533
|
-
type: "InputTask",
|
|
534
|
-
config: {
|
|
535
|
-
inputSchema: strippedInputSchema,
|
|
536
|
-
outputSchema: strippedInputSchema
|
|
537
|
-
}
|
|
538
|
-
});
|
|
539
|
-
if (typeof inputSchema !== "boolean" && inputSchema.properties) {
|
|
540
|
-
for (const [propName, prop] of Object.entries(inputSchema.properties)) {
|
|
541
|
-
if (!prop || typeof prop === "boolean")
|
|
542
|
-
continue;
|
|
543
|
-
const origins = getOriginTaskIds(prop);
|
|
544
|
-
for (const originId of origins) {
|
|
545
|
-
const targetItem = items.find((item) => item.id === originId);
|
|
546
|
-
if (!targetItem)
|
|
547
|
-
continue;
|
|
548
|
-
if (!targetItem.dependencies) {
|
|
549
|
-
targetItem.dependencies = {};
|
|
550
|
-
}
|
|
551
|
-
const existing = targetItem.dependencies[propName];
|
|
552
|
-
const dep = { id: inputTaskId, output: propName };
|
|
553
|
-
if (!existing) {
|
|
554
|
-
targetItem.dependencies[propName] = dep;
|
|
555
|
-
} else if (Array.isArray(existing)) {
|
|
556
|
-
existing.push(dep);
|
|
557
|
-
} else {
|
|
558
|
-
targetItem.dependencies[propName] = [existing, dep];
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
if (!hasOutputTask) {
|
|
565
|
-
const outputSchema = computeGraphOutputSchema(graph, { trackOrigins: true });
|
|
566
|
-
const outputTaskId = uuid4();
|
|
567
|
-
const strippedOutputSchema = stripOriginAnnotations(outputSchema);
|
|
568
|
-
const outputDependencies = {};
|
|
569
|
-
if (typeof outputSchema !== "boolean" && outputSchema.properties) {
|
|
570
|
-
for (const [propName, prop] of Object.entries(outputSchema.properties)) {
|
|
571
|
-
if (!prop || typeof prop === "boolean")
|
|
572
|
-
continue;
|
|
573
|
-
const origins = getOriginTaskIds(prop);
|
|
574
|
-
if (origins.length === 1) {
|
|
575
|
-
outputDependencies[propName] = { id: origins[0], output: propName };
|
|
576
|
-
} else if (origins.length > 1) {
|
|
577
|
-
outputDependencies[propName] = origins.map((id) => ({ id, output: propName }));
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
appendItems.push({
|
|
582
|
-
id: outputTaskId,
|
|
583
|
-
type: "OutputTask",
|
|
584
|
-
config: {
|
|
585
|
-
inputSchema: strippedOutputSchema,
|
|
586
|
-
outputSchema: strippedOutputSchema
|
|
587
|
-
},
|
|
588
|
-
...Object.keys(outputDependencies).length > 0 ? { dependencies: outputDependencies } : {}
|
|
589
|
-
});
|
|
590
|
-
}
|
|
591
|
-
return [...prependItems, ...items, ...appendItems];
|
|
592
|
-
}
|
|
593
|
-
// src/task-graph/TaskGraph.ts
|
|
594
|
-
import { DirectedAcyclicGraph, EventEmitter as EventEmitter5, uuid4 as uuid45 } from "@workglow/util";
|
|
595
|
-
|
|
596
|
-
// src/task/GraphAsTask.ts
|
|
597
|
-
import { compileSchema as compileSchema2 } from "@workglow/util";
|
|
598
|
-
|
|
599
|
-
// src/task-graph/TaskGraphRunner.ts
|
|
600
|
-
import {
|
|
601
|
-
collectPropertyValues,
|
|
602
|
-
getLogger as getLogger3,
|
|
603
|
-
globalServiceRegistry as globalServiceRegistry2,
|
|
604
|
-
ServiceRegistry as ServiceRegistry2,
|
|
605
|
-
uuid4 as uuid43
|
|
606
|
-
} from "@workglow/util";
|
|
607
|
-
|
|
608
|
-
// src/storage/TaskOutputRepository.ts
|
|
609
|
-
import { createServiceToken, EventEmitter as EventEmitter2 } from "@workglow/util";
|
|
610
|
-
var TASK_OUTPUT_REPOSITORY = createServiceToken("taskgraph.taskOutputRepository");
|
|
611
|
-
|
|
612
|
-
class TaskOutputRepository {
|
|
613
|
-
outputCompression;
|
|
614
|
-
constructor({ outputCompression = true }) {
|
|
615
|
-
this.outputCompression = outputCompression;
|
|
616
|
-
}
|
|
617
|
-
get events() {
|
|
618
|
-
if (!this._events) {
|
|
619
|
-
this._events = new EventEmitter2;
|
|
620
|
-
}
|
|
621
|
-
return this._events;
|
|
622
|
-
}
|
|
623
|
-
_events;
|
|
624
|
-
on(name, fn) {
|
|
625
|
-
this.events.on(name, fn);
|
|
626
|
-
}
|
|
627
|
-
off(name, fn) {
|
|
628
|
-
this.events.off(name, fn);
|
|
629
|
-
}
|
|
630
|
-
waitOn(name) {
|
|
631
|
-
return this.events.waitOn(name);
|
|
632
|
-
}
|
|
633
|
-
emit(name, ...args) {
|
|
634
|
-
this._events?.emit(name, ...args);
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
// src/task/ConditionalTask.ts
|
|
639
|
-
import { getLogger as getLogger2 } from "@workglow/util";
|
|
640
|
-
|
|
641
|
-
// src/task/ConditionUtils.ts
|
|
642
|
-
function evaluateCondition(fieldValue, operator, compareValue) {
|
|
643
|
-
if (fieldValue === null || fieldValue === undefined) {
|
|
644
|
-
switch (operator) {
|
|
645
|
-
case "is_empty":
|
|
646
|
-
return true;
|
|
647
|
-
case "is_not_empty":
|
|
648
|
-
return false;
|
|
649
|
-
case "is_true":
|
|
650
|
-
return false;
|
|
651
|
-
case "is_false":
|
|
652
|
-
return true;
|
|
653
|
-
default:
|
|
654
|
-
return false;
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
const strValue = String(fieldValue);
|
|
658
|
-
const numValue = Number(fieldValue);
|
|
659
|
-
switch (operator) {
|
|
660
|
-
case "equals":
|
|
661
|
-
if (!isNaN(numValue) && !isNaN(Number(compareValue))) {
|
|
662
|
-
return numValue === Number(compareValue);
|
|
663
|
-
}
|
|
664
|
-
return strValue === compareValue;
|
|
665
|
-
case "not_equals":
|
|
666
|
-
if (!isNaN(numValue) && !isNaN(Number(compareValue))) {
|
|
667
|
-
return numValue !== Number(compareValue);
|
|
668
|
-
}
|
|
669
|
-
return strValue !== compareValue;
|
|
670
|
-
case "greater_than":
|
|
671
|
-
return numValue > Number(compareValue);
|
|
672
|
-
case "greater_or_equal":
|
|
673
|
-
return numValue >= Number(compareValue);
|
|
674
|
-
case "less_than":
|
|
675
|
-
return numValue < Number(compareValue);
|
|
676
|
-
case "less_or_equal":
|
|
677
|
-
return numValue <= Number(compareValue);
|
|
678
|
-
case "contains":
|
|
679
|
-
return strValue.toLowerCase().includes(compareValue.toLowerCase());
|
|
680
|
-
case "starts_with":
|
|
681
|
-
return strValue.toLowerCase().startsWith(compareValue.toLowerCase());
|
|
682
|
-
case "ends_with":
|
|
683
|
-
return strValue.toLowerCase().endsWith(compareValue.toLowerCase());
|
|
684
|
-
case "is_empty":
|
|
685
|
-
return strValue === "" || Array.isArray(fieldValue) && fieldValue.length === 0;
|
|
686
|
-
case "is_not_empty":
|
|
687
|
-
return strValue !== "" && !(Array.isArray(fieldValue) && fieldValue.length === 0);
|
|
688
|
-
case "is_true":
|
|
689
|
-
return Boolean(fieldValue) === true;
|
|
690
|
-
case "is_false":
|
|
691
|
-
return Boolean(fieldValue) === false;
|
|
692
|
-
default:
|
|
693
|
-
return false;
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
function getNestedValue(obj, path) {
|
|
697
|
-
const parts = path.split(".");
|
|
698
|
-
let current = obj;
|
|
699
|
-
for (const part of parts) {
|
|
700
|
-
if (current === null || current === undefined || typeof current !== "object") {
|
|
701
|
-
return;
|
|
702
|
-
}
|
|
703
|
-
current = current[part];
|
|
704
|
-
}
|
|
705
|
-
return current;
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
// src/task/Task.ts
|
|
709
|
-
import {
|
|
710
|
-
compileSchema,
|
|
711
|
-
deepEqual,
|
|
712
|
-
EventEmitter as EventEmitter3,
|
|
713
|
-
uuid4 as uuid42
|
|
714
|
-
} from "@workglow/util";
|
|
715
|
-
|
|
716
|
-
// src/task/TaskError.ts
|
|
717
|
-
import { BaseError } from "@workglow/util";
|
|
718
|
-
|
|
719
|
-
class TaskError extends BaseError {
|
|
720
|
-
static type = "TaskError";
|
|
721
|
-
constructor(message) {
|
|
722
|
-
super(message);
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
class TaskConfigurationError extends TaskError {
|
|
727
|
-
static type = "TaskConfigurationError";
|
|
728
|
-
constructor(message) {
|
|
729
|
-
super(message);
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
class WorkflowError extends TaskError {
|
|
734
|
-
static type = "WorkflowError";
|
|
735
|
-
constructor(message) {
|
|
736
|
-
super(message);
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
class TaskAbortedError extends TaskError {
|
|
741
|
-
static type = "TaskAbortedError";
|
|
742
|
-
constructor(message = "Task aborted") {
|
|
743
|
-
super(message);
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
class TaskTimeoutError extends TaskAbortedError {
|
|
748
|
-
static type = "TaskTimeoutError";
|
|
749
|
-
constructor(timeoutMs) {
|
|
750
|
-
super(timeoutMs ? `Task timed out after ${timeoutMs}ms` : "Task timed out");
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
class TaskFailedError extends TaskError {
|
|
755
|
-
static type = "TaskFailedError";
|
|
756
|
-
constructor(message = "Task failed") {
|
|
757
|
-
super(message);
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
class JobTaskFailedError extends TaskFailedError {
|
|
762
|
-
static type = "JobTaskFailedError";
|
|
763
|
-
jobError;
|
|
764
|
-
constructor(err) {
|
|
765
|
-
super(String(err));
|
|
766
|
-
this.jobError = err;
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
class TaskJSONError extends TaskError {
|
|
771
|
-
static type = "TaskJSONError";
|
|
772
|
-
constructor(message = "Error converting JSON to a Task") {
|
|
773
|
-
super(message);
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
class TaskInvalidInputError extends TaskError {
|
|
778
|
-
static type = "TaskInvalidInputError";
|
|
779
|
-
constructor(message = "Invalid input data") {
|
|
780
|
-
super(message);
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
// src/task/TaskRunner.ts
|
|
785
|
-
import { getLogger, globalServiceRegistry } from "@workglow/util";
|
|
786
|
-
|
|
787
|
-
// src/task/InputResolver.ts
|
|
788
|
-
import { getInputResolvers } from "@workglow/util";
|
|
789
|
-
function getSchemaFormat(schema) {
|
|
790
|
-
if (typeof schema !== "object" || schema === null)
|
|
791
|
-
return;
|
|
792
|
-
const s = schema;
|
|
793
|
-
if (typeof s.format === "string")
|
|
794
|
-
return s.format;
|
|
795
|
-
const variants = s.oneOf ?? s.anyOf;
|
|
796
|
-
if (Array.isArray(variants)) {
|
|
797
|
-
for (const variant of variants) {
|
|
798
|
-
if (typeof variant === "object" && variant !== null) {
|
|
799
|
-
const v = variant;
|
|
800
|
-
if (typeof v.format === "string")
|
|
801
|
-
return v.format;
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
return;
|
|
806
|
-
}
|
|
807
|
-
function getObjectSchema(schema) {
|
|
808
|
-
if (typeof schema !== "object" || schema === null)
|
|
809
|
-
return;
|
|
810
|
-
const s = schema;
|
|
811
|
-
if (s.type === "object" && s.properties && typeof s.properties === "object") {
|
|
812
|
-
return s;
|
|
813
|
-
}
|
|
814
|
-
const variants = s.oneOf ?? s.anyOf;
|
|
815
|
-
if (Array.isArray(variants)) {
|
|
816
|
-
for (const variant of variants) {
|
|
817
|
-
if (typeof variant === "object" && variant !== null) {
|
|
818
|
-
const v = variant;
|
|
819
|
-
if (v.type === "object" && v.properties && typeof v.properties === "object") {
|
|
820
|
-
return v;
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
return;
|
|
826
|
-
}
|
|
827
|
-
function getFormatPrefix(format) {
|
|
828
|
-
const colonIndex = format.indexOf(":");
|
|
829
|
-
return colonIndex >= 0 ? format.substring(0, colonIndex) : format;
|
|
830
|
-
}
|
|
831
|
-
async function resolveSchemaInputs(input, schema, config) {
|
|
832
|
-
if (typeof schema === "boolean")
|
|
833
|
-
return input;
|
|
834
|
-
const properties = schema.properties;
|
|
835
|
-
if (!properties || typeof properties !== "object")
|
|
836
|
-
return input;
|
|
837
|
-
const resolvers = getInputResolvers();
|
|
838
|
-
const resolved = { ...input };
|
|
839
|
-
for (const [key, propSchema] of Object.entries(properties)) {
|
|
840
|
-
let value = resolved[key];
|
|
841
|
-
const format = getSchemaFormat(propSchema);
|
|
842
|
-
if (format) {
|
|
843
|
-
let resolver = resolvers.get(format);
|
|
844
|
-
if (!resolver) {
|
|
845
|
-
const prefix = getFormatPrefix(format);
|
|
846
|
-
resolver = resolvers.get(prefix);
|
|
847
|
-
}
|
|
848
|
-
if (resolver) {
|
|
849
|
-
if (typeof value === "string") {
|
|
850
|
-
value = await resolver(value, format, config.registry);
|
|
851
|
-
resolved[key] = value;
|
|
852
|
-
} else if (Array.isArray(value) && value.some((item) => typeof item === "string")) {
|
|
853
|
-
const results = await Promise.all(value.map((item) => typeof item === "string" ? resolver(item, format, config.registry) : item));
|
|
854
|
-
value = results.filter((result) => result !== undefined);
|
|
855
|
-
resolved[key] = value;
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
if (value !== null && value !== undefined && typeof value === "object" && !Array.isArray(value)) {
|
|
860
|
-
const objectSchema = getObjectSchema(propSchema);
|
|
861
|
-
if (objectSchema) {
|
|
862
|
-
resolved[key] = await resolveSchemaInputs(value, objectSchema, config);
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
return resolved;
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
// src/task/StreamTypes.ts
|
|
870
|
-
function getPortStreamMode(schema, portId) {
|
|
871
|
-
if (typeof schema === "boolean")
|
|
872
|
-
return "none";
|
|
873
|
-
const prop = schema.properties?.[portId];
|
|
874
|
-
if (!prop || typeof prop === "boolean")
|
|
875
|
-
return "none";
|
|
876
|
-
const xStream = prop["x-stream"];
|
|
877
|
-
if (xStream === "append" || xStream === "replace" || xStream === "object")
|
|
878
|
-
return xStream;
|
|
879
|
-
return "none";
|
|
880
|
-
}
|
|
881
|
-
function getStreamingPorts(schema) {
|
|
882
|
-
if (typeof schema === "boolean")
|
|
883
|
-
return [];
|
|
884
|
-
const props = schema.properties;
|
|
885
|
-
if (!props)
|
|
886
|
-
return [];
|
|
887
|
-
const result = [];
|
|
888
|
-
for (const [name, prop] of Object.entries(props)) {
|
|
889
|
-
if (!prop || typeof prop === "boolean")
|
|
890
|
-
continue;
|
|
891
|
-
const xStream = prop["x-stream"];
|
|
892
|
-
if (xStream === "append" || xStream === "replace" || xStream === "object") {
|
|
893
|
-
result.push({ port: name, mode: xStream });
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
return result;
|
|
897
|
-
}
|
|
898
|
-
function getOutputStreamMode(outputSchema) {
|
|
899
|
-
const ports = getStreamingPorts(outputSchema);
|
|
900
|
-
if (ports.length === 0)
|
|
901
|
-
return "none";
|
|
902
|
-
const mode = ports[0].mode;
|
|
903
|
-
for (let i = 1;i < ports.length; i++) {
|
|
904
|
-
if (ports[i].mode !== mode) {
|
|
905
|
-
return "mixed";
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
return mode;
|
|
909
|
-
}
|
|
910
|
-
function isTaskStreamable(task) {
|
|
911
|
-
if (typeof task.executeStream !== "function")
|
|
912
|
-
return false;
|
|
913
|
-
return getOutputStreamMode(task.outputSchema()) !== "none";
|
|
914
|
-
}
|
|
915
|
-
function getAppendPortId(schema) {
|
|
916
|
-
if (typeof schema === "boolean")
|
|
917
|
-
return;
|
|
918
|
-
const props = schema.properties;
|
|
919
|
-
if (!props)
|
|
920
|
-
return;
|
|
921
|
-
for (const [name, prop] of Object.entries(props)) {
|
|
922
|
-
if (!prop || typeof prop === "boolean")
|
|
923
|
-
continue;
|
|
924
|
-
if (prop["x-stream"] === "append")
|
|
925
|
-
return name;
|
|
926
|
-
}
|
|
927
|
-
return;
|
|
928
|
-
}
|
|
929
|
-
function edgeNeedsAccumulation(sourceSchema, sourcePort, targetSchema, targetPort) {
|
|
930
|
-
const sourceMode = getPortStreamMode(sourceSchema, sourcePort);
|
|
931
|
-
if (sourceMode === "none")
|
|
932
|
-
return false;
|
|
933
|
-
const targetMode = getPortStreamMode(targetSchema, targetPort);
|
|
934
|
-
return sourceMode !== targetMode;
|
|
935
|
-
}
|
|
936
|
-
function getObjectPortId(schema) {
|
|
937
|
-
if (typeof schema === "boolean")
|
|
938
|
-
return;
|
|
939
|
-
const props = schema.properties;
|
|
940
|
-
if (!props)
|
|
941
|
-
return;
|
|
942
|
-
for (const [name, prop] of Object.entries(props)) {
|
|
943
|
-
if (!prop || typeof prop === "boolean")
|
|
944
|
-
continue;
|
|
945
|
-
if (prop["x-stream"] === "object")
|
|
946
|
-
return name;
|
|
947
|
-
}
|
|
948
|
-
return;
|
|
949
|
-
}
|
|
950
|
-
function getStructuredOutputSchemas(schema) {
|
|
951
|
-
const result = new Map;
|
|
952
|
-
if (typeof schema === "boolean")
|
|
953
|
-
return result;
|
|
954
|
-
const props = schema.properties;
|
|
955
|
-
if (!props)
|
|
956
|
-
return result;
|
|
957
|
-
for (const [name, prop] of Object.entries(props)) {
|
|
958
|
-
if (!prop || typeof prop === "boolean")
|
|
959
|
-
continue;
|
|
960
|
-
if (prop["x-structured-output"] === true) {
|
|
961
|
-
result.set(name, prop);
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
return result;
|
|
965
|
-
}
|
|
966
|
-
function hasStructuredOutput(schema) {
|
|
967
|
-
return getStructuredOutputSchemas(schema).size > 0;
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
// src/task/TaskRunner.ts
|
|
971
|
-
class TaskRunner {
|
|
972
|
-
running = false;
|
|
973
|
-
reactiveRunning = false;
|
|
974
|
-
task;
|
|
975
|
-
abortController;
|
|
976
|
-
outputCache;
|
|
977
|
-
registry = globalServiceRegistry;
|
|
978
|
-
inputStreams;
|
|
979
|
-
timeoutTimer;
|
|
980
|
-
pendingTimeoutError;
|
|
981
|
-
shouldAccumulate = true;
|
|
982
|
-
constructor(task) {
|
|
983
|
-
this.task = task;
|
|
984
|
-
this.own = this.own.bind(this);
|
|
985
|
-
this.handleProgress = this.handleProgress.bind(this);
|
|
986
|
-
}
|
|
987
|
-
get timerLabel() {
|
|
988
|
-
return `task:${this.task.type}:${this.task.config.id}`;
|
|
989
|
-
}
|
|
990
|
-
async run(overrides = {}, config = {}) {
|
|
991
|
-
await this.handleStart(config);
|
|
992
|
-
try {
|
|
993
|
-
this.task.setInput(overrides);
|
|
994
|
-
const schema = this.task.constructor.inputSchema();
|
|
995
|
-
this.task.runInputData = await resolveSchemaInputs(this.task.runInputData, schema, { registry: this.registry });
|
|
996
|
-
const isValid = await this.task.validateInput(this.task.runInputData);
|
|
997
|
-
if (!isValid) {
|
|
998
|
-
throw new TaskInvalidInputError("Invalid input data");
|
|
999
|
-
}
|
|
1000
|
-
if (this.abortController?.signal.aborted) {
|
|
1001
|
-
await this.handleAbort();
|
|
1002
|
-
throw new TaskAbortedError("Promise for task created and aborted before run");
|
|
1003
|
-
}
|
|
1004
|
-
const inputs = this.task.runInputData;
|
|
1005
|
-
let outputs;
|
|
1006
|
-
const isStreamable = isTaskStreamable(this.task);
|
|
1007
|
-
if (this.task.cacheable) {
|
|
1008
|
-
outputs = await this.outputCache?.getOutput(this.task.type, inputs);
|
|
1009
|
-
if (outputs) {
|
|
1010
|
-
if (isStreamable) {
|
|
1011
|
-
this.task.runOutputData = outputs;
|
|
1012
|
-
this.task.emit("stream_start");
|
|
1013
|
-
this.task.emit("stream_chunk", { type: "finish", data: outputs });
|
|
1014
|
-
this.task.emit("stream_end", outputs);
|
|
1015
|
-
this.task.runOutputData = await this.executeTaskReactive(inputs, outputs);
|
|
1016
|
-
} else {
|
|
1017
|
-
this.task.runOutputData = await this.executeTaskReactive(inputs, outputs);
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
if (!outputs) {
|
|
1022
|
-
if (isStreamable) {
|
|
1023
|
-
outputs = await this.executeStreamingTask(inputs);
|
|
1024
|
-
} else {
|
|
1025
|
-
outputs = await this.executeTask(inputs);
|
|
1026
|
-
}
|
|
1027
|
-
if (this.task.cacheable && outputs !== undefined) {
|
|
1028
|
-
await this.outputCache?.saveOutput(this.task.type, inputs, outputs);
|
|
1029
|
-
}
|
|
1030
|
-
this.task.runOutputData = outputs ?? {};
|
|
1031
|
-
}
|
|
1032
|
-
await this.handleComplete();
|
|
1033
|
-
return this.task.runOutputData;
|
|
1034
|
-
} catch (err) {
|
|
1035
|
-
await this.handleError(err);
|
|
1036
|
-
throw this.task.error instanceof TaskTimeoutError ? this.task.error : err;
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
async runReactive(overrides = {}) {
|
|
1040
|
-
if (this.task.status === TaskStatus.PROCESSING) {
|
|
1041
|
-
return this.task.runOutputData;
|
|
1042
|
-
}
|
|
1043
|
-
this.task.setInput(overrides);
|
|
1044
|
-
const schema = this.task.constructor.inputSchema();
|
|
1045
|
-
this.task.runInputData = await resolveSchemaInputs(this.task.runInputData, schema, { registry: this.registry });
|
|
1046
|
-
await this.handleStartReactive();
|
|
1047
|
-
try {
|
|
1048
|
-
const isValid = await this.task.validateInput(this.task.runInputData);
|
|
1049
|
-
if (!isValid) {
|
|
1050
|
-
throw new TaskInvalidInputError("Invalid input data");
|
|
1051
|
-
}
|
|
1052
|
-
const resultReactive = await this.executeTaskReactive(this.task.runInputData, this.task.runOutputData);
|
|
1053
|
-
this.task.runOutputData = resultReactive;
|
|
1054
|
-
await this.handleCompleteReactive();
|
|
1055
|
-
} catch (err) {
|
|
1056
|
-
await this.handleErrorReactive();
|
|
1057
|
-
} finally {
|
|
1058
|
-
return this.task.runOutputData;
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1061
|
-
abort() {
|
|
1062
|
-
if (this.task.hasChildren()) {
|
|
1063
|
-
this.task.subGraph.abort();
|
|
1064
|
-
}
|
|
1065
|
-
this.abortController?.abort();
|
|
1066
|
-
}
|
|
1067
|
-
own(i) {
|
|
1068
|
-
const task = ensureTask(i, { isOwned: true });
|
|
1069
|
-
this.task.subGraph.addTask(task);
|
|
1070
|
-
return i;
|
|
1071
|
-
}
|
|
1072
|
-
async executeTask(input) {
|
|
1073
|
-
const result = await this.task.execute(input, {
|
|
1074
|
-
signal: this.abortController.signal,
|
|
1075
|
-
updateProgress: this.handleProgress.bind(this),
|
|
1076
|
-
own: this.own,
|
|
1077
|
-
registry: this.registry
|
|
1078
|
-
});
|
|
1079
|
-
return await this.executeTaskReactive(input, result || {});
|
|
1080
|
-
}
|
|
1081
|
-
async executeTaskReactive(input, output) {
|
|
1082
|
-
const reactiveResult = await this.task.executeReactive(input, output, { own: this.own });
|
|
1083
|
-
return Object.assign({}, output, reactiveResult ?? {});
|
|
1084
|
-
}
|
|
1085
|
-
async executeStreamingTask(input) {
|
|
1086
|
-
const streamMode = getOutputStreamMode(this.task.outputSchema());
|
|
1087
|
-
if (streamMode === "append") {
|
|
1088
|
-
const ports = getStreamingPorts(this.task.outputSchema());
|
|
1089
|
-
if (ports.length === 0) {
|
|
1090
|
-
throw new TaskError(`Task ${this.task.type} declares append streaming but no output port has x-stream: "append"`);
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
if (streamMode === "object") {
|
|
1094
|
-
const ports = getStreamingPorts(this.task.outputSchema());
|
|
1095
|
-
if (ports.length === 0) {
|
|
1096
|
-
throw new TaskError(`Task ${this.task.type} declares object streaming but no output port has x-stream: "object"`);
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
const accumulated = this.shouldAccumulate ? new Map : undefined;
|
|
1100
|
-
const accumulatedObjects = this.shouldAccumulate ? new Map : undefined;
|
|
1101
|
-
let chunkCount = 0;
|
|
1102
|
-
let finalOutput;
|
|
1103
|
-
this.task.emit("stream_start");
|
|
1104
|
-
const stream = this.task.executeStream(input, {
|
|
1105
|
-
signal: this.abortController.signal,
|
|
1106
|
-
updateProgress: this.handleProgress.bind(this),
|
|
1107
|
-
own: this.own,
|
|
1108
|
-
registry: this.registry,
|
|
1109
|
-
inputStreams: this.inputStreams
|
|
1110
|
-
});
|
|
1111
|
-
for await (const event of stream) {
|
|
1112
|
-
chunkCount++;
|
|
1113
|
-
if (chunkCount === 1) {
|
|
1114
|
-
this.task.status = TaskStatus.STREAMING;
|
|
1115
|
-
this.task.emit("status", this.task.status);
|
|
1116
|
-
}
|
|
1117
|
-
if (event.type === "snapshot") {
|
|
1118
|
-
this.task.runOutputData = event.data;
|
|
1119
|
-
}
|
|
1120
|
-
switch (event.type) {
|
|
1121
|
-
case "text-delta": {
|
|
1122
|
-
if (accumulated) {
|
|
1123
|
-
accumulated.set(event.port, (accumulated.get(event.port) ?? "") + event.textDelta);
|
|
1124
|
-
}
|
|
1125
|
-
this.task.emit("stream_chunk", event);
|
|
1126
|
-
const progress = Math.min(99, Math.round(100 * (1 - Math.exp(-0.05 * chunkCount))));
|
|
1127
|
-
await this.handleProgress(progress);
|
|
1128
|
-
break;
|
|
1129
|
-
}
|
|
1130
|
-
case "object-delta": {
|
|
1131
|
-
if (accumulatedObjects) {
|
|
1132
|
-
accumulatedObjects.set(event.port, event.objectDelta);
|
|
1133
|
-
}
|
|
1134
|
-
this.task.runOutputData = {
|
|
1135
|
-
...this.task.runOutputData,
|
|
1136
|
-
[event.port]: event.objectDelta
|
|
1137
|
-
};
|
|
1138
|
-
this.task.emit("stream_chunk", event);
|
|
1139
|
-
const progress = Math.min(99, Math.round(100 * (1 - Math.exp(-0.05 * chunkCount))));
|
|
1140
|
-
await this.handleProgress(progress);
|
|
1141
|
-
break;
|
|
1142
|
-
}
|
|
1143
|
-
case "snapshot": {
|
|
1144
|
-
this.task.emit("stream_chunk", event);
|
|
1145
|
-
const progress = Math.min(99, Math.round(100 * (1 - Math.exp(-0.05 * chunkCount))));
|
|
1146
|
-
await this.handleProgress(progress);
|
|
1147
|
-
break;
|
|
1148
|
-
}
|
|
1149
|
-
case "finish": {
|
|
1150
|
-
if (accumulated || accumulatedObjects) {
|
|
1151
|
-
const merged = { ...event.data || {} };
|
|
1152
|
-
if (accumulated) {
|
|
1153
|
-
for (const [port, text] of accumulated) {
|
|
1154
|
-
if (text.length > 0)
|
|
1155
|
-
merged[port] = text;
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
if (accumulatedObjects) {
|
|
1159
|
-
for (const [port, obj] of accumulatedObjects) {
|
|
1160
|
-
merged[port] = obj;
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
finalOutput = merged;
|
|
1164
|
-
this.task.emit("stream_chunk", { type: "finish", data: merged });
|
|
1165
|
-
} else {
|
|
1166
|
-
finalOutput = event.data;
|
|
1167
|
-
this.task.emit("stream_chunk", event);
|
|
1168
|
-
}
|
|
1169
|
-
break;
|
|
1170
|
-
}
|
|
1171
|
-
case "error": {
|
|
1172
|
-
throw event.error;
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
if (this.abortController?.signal.aborted) {
|
|
1177
|
-
throw new TaskAbortedError("Task aborted during streaming");
|
|
1178
|
-
}
|
|
1179
|
-
if (finalOutput !== undefined) {
|
|
1180
|
-
this.task.runOutputData = finalOutput;
|
|
1181
|
-
}
|
|
1182
|
-
this.task.emit("stream_end", this.task.runOutputData);
|
|
1183
|
-
const reactiveResult = await this.executeTaskReactive(input, this.task.runOutputData || {});
|
|
1184
|
-
return reactiveResult;
|
|
1185
|
-
}
|
|
1186
|
-
async handleStart(config = {}) {
|
|
1187
|
-
if (this.task.status === TaskStatus.PROCESSING)
|
|
1188
|
-
return;
|
|
1189
|
-
this.running = true;
|
|
1190
|
-
this.task.startedAt = new Date;
|
|
1191
|
-
this.task.progress = 0;
|
|
1192
|
-
this.task.status = TaskStatus.PROCESSING;
|
|
1193
|
-
this.abortController = new AbortController;
|
|
1194
|
-
this.abortController.signal.addEventListener("abort", () => {
|
|
1195
|
-
this.handleAbort();
|
|
1196
|
-
});
|
|
1197
|
-
const cache = config.outputCache ?? this.task.runConfig?.outputCache;
|
|
1198
|
-
if (cache === true) {
|
|
1199
|
-
let instance = globalServiceRegistry.get(TASK_OUTPUT_REPOSITORY);
|
|
1200
|
-
this.outputCache = instance;
|
|
1201
|
-
} else if (cache === false) {
|
|
1202
|
-
this.outputCache = undefined;
|
|
1203
|
-
} else if (cache instanceof TaskOutputRepository) {
|
|
1204
|
-
this.outputCache = cache;
|
|
1205
|
-
}
|
|
1206
|
-
this.shouldAccumulate = config.shouldAccumulate !== false;
|
|
1207
|
-
const timeout = this.task.config.timeout;
|
|
1208
|
-
if (timeout !== undefined && timeout > 0) {
|
|
1209
|
-
this.pendingTimeoutError = new TaskTimeoutError(timeout);
|
|
1210
|
-
this.timeoutTimer = setTimeout(() => {
|
|
1211
|
-
this.abort();
|
|
1212
|
-
}, timeout);
|
|
1213
|
-
}
|
|
1214
|
-
if (config.updateProgress) {
|
|
1215
|
-
this.updateProgress = config.updateProgress;
|
|
1216
|
-
}
|
|
1217
|
-
if (config.registry) {
|
|
1218
|
-
this.registry = config.registry;
|
|
1219
|
-
}
|
|
1220
|
-
getLogger().time(this.timerLabel, { taskType: this.task.type, taskId: this.task.config.id });
|
|
1221
|
-
this.task.emit("start");
|
|
1222
|
-
this.task.emit("status", this.task.status);
|
|
1223
|
-
}
|
|
1224
|
-
updateProgress = async (task, progress, message, ...args) => {};
|
|
1225
|
-
async handleStartReactive() {
|
|
1226
|
-
this.reactiveRunning = true;
|
|
1227
|
-
}
|
|
1228
|
-
clearTimeoutTimer() {
|
|
1229
|
-
if (this.timeoutTimer !== undefined) {
|
|
1230
|
-
clearTimeout(this.timeoutTimer);
|
|
1231
|
-
this.timeoutTimer = undefined;
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
async handleAbort() {
|
|
1235
|
-
if (this.task.status === TaskStatus.ABORTING)
|
|
1236
|
-
return;
|
|
1237
|
-
this.clearTimeoutTimer();
|
|
1238
|
-
getLogger().timeEnd(this.timerLabel, { taskType: this.task.type, taskId: this.task.config.id });
|
|
1239
|
-
this.task.status = TaskStatus.ABORTING;
|
|
1240
|
-
this.task.progress = 100;
|
|
1241
|
-
this.task.error = this.pendingTimeoutError ?? new TaskAbortedError;
|
|
1242
|
-
this.pendingTimeoutError = undefined;
|
|
1243
|
-
this.task.emit("abort", this.task.error);
|
|
1244
|
-
this.task.emit("status", this.task.status);
|
|
1245
|
-
}
|
|
1246
|
-
async handleAbortReactive() {
|
|
1247
|
-
this.reactiveRunning = false;
|
|
1248
|
-
}
|
|
1249
|
-
async handleComplete() {
|
|
1250
|
-
if (this.task.status === TaskStatus.COMPLETED)
|
|
1251
|
-
return;
|
|
1252
|
-
this.clearTimeoutTimer();
|
|
1253
|
-
this.pendingTimeoutError = undefined;
|
|
1254
|
-
getLogger().timeEnd(this.timerLabel, { taskType: this.task.type, taskId: this.task.config.id });
|
|
1255
|
-
this.task.completedAt = new Date;
|
|
1256
|
-
this.task.progress = 100;
|
|
1257
|
-
this.task.status = TaskStatus.COMPLETED;
|
|
1258
|
-
this.abortController = undefined;
|
|
1259
|
-
this.task.emit("complete");
|
|
1260
|
-
this.task.emit("status", this.task.status);
|
|
1261
|
-
}
|
|
1262
|
-
async handleCompleteReactive() {
|
|
1263
|
-
this.reactiveRunning = false;
|
|
1264
|
-
}
|
|
1265
|
-
async handleDisable() {
|
|
1266
|
-
if (this.task.status === TaskStatus.DISABLED)
|
|
1267
|
-
return;
|
|
1268
|
-
this.task.status = TaskStatus.DISABLED;
|
|
1269
|
-
this.task.progress = 100;
|
|
1270
|
-
this.task.completedAt = new Date;
|
|
1271
|
-
this.abortController = undefined;
|
|
1272
|
-
this.task.emit("disabled");
|
|
1273
|
-
this.task.emit("status", this.task.status);
|
|
1274
|
-
}
|
|
1275
|
-
async disable() {
|
|
1276
|
-
await this.handleDisable();
|
|
1277
|
-
}
|
|
1278
|
-
async handleError(err) {
|
|
1279
|
-
if (err instanceof TaskAbortedError)
|
|
1280
|
-
return this.handleAbort();
|
|
1281
|
-
if (this.task.status === TaskStatus.FAILED)
|
|
1282
|
-
return;
|
|
1283
|
-
this.clearTimeoutTimer();
|
|
1284
|
-
this.pendingTimeoutError = undefined;
|
|
1285
|
-
getLogger().timeEnd(this.timerLabel, { taskType: this.task.type, taskId: this.task.config.id });
|
|
1286
|
-
if (this.task.hasChildren()) {
|
|
1287
|
-
this.task.subGraph.abort();
|
|
1288
|
-
}
|
|
1289
|
-
this.task.completedAt = new Date;
|
|
1290
|
-
this.task.progress = 100;
|
|
1291
|
-
this.task.status = TaskStatus.FAILED;
|
|
1292
|
-
this.task.error = err instanceof TaskError ? err : new TaskFailedError(err?.message || "Task failed");
|
|
1293
|
-
this.abortController = undefined;
|
|
1294
|
-
this.task.emit("error", this.task.error);
|
|
1295
|
-
this.task.emit("status", this.task.status);
|
|
1296
|
-
}
|
|
1297
|
-
async handleErrorReactive() {
|
|
1298
|
-
this.reactiveRunning = false;
|
|
1299
|
-
}
|
|
1300
|
-
async handleProgress(progress, message, ...args) {
|
|
1301
|
-
this.task.progress = progress;
|
|
1302
|
-
await this.updateProgress(this.task, progress, message, ...args);
|
|
1303
|
-
this.task.emit("progress", progress, message, ...args);
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
// src/task/Task.ts
|
|
1308
|
-
class Task {
|
|
1309
|
-
static type = "Task";
|
|
1310
|
-
static category = "Hidden";
|
|
1311
|
-
static title = "";
|
|
1312
|
-
static description = "";
|
|
1313
|
-
static cacheable = true;
|
|
1314
|
-
static hasDynamicSchemas = false;
|
|
1315
|
-
static passthroughInputsToOutputs = false;
|
|
1316
|
-
static customizable = false;
|
|
1317
|
-
static inputSchema() {
|
|
1318
|
-
return {
|
|
1319
|
-
type: "object",
|
|
1320
|
-
properties: {},
|
|
1321
|
-
additionalProperties: false
|
|
1322
|
-
};
|
|
1323
|
-
}
|
|
1324
|
-
static outputSchema() {
|
|
1325
|
-
return {
|
|
1326
|
-
type: "object",
|
|
1327
|
-
properties: {},
|
|
1328
|
-
additionalProperties: false
|
|
1329
|
-
};
|
|
1330
|
-
}
|
|
1331
|
-
static configSchema() {
|
|
1332
|
-
return TaskConfigSchema;
|
|
1333
|
-
}
|
|
1334
|
-
async execute(_input, context) {
|
|
1335
|
-
if (context.signal?.aborted) {
|
|
1336
|
-
throw new TaskAbortedError("Task aborted");
|
|
1337
|
-
}
|
|
1338
|
-
return;
|
|
1339
|
-
}
|
|
1340
|
-
async executeReactive(_input, output, _context) {
|
|
1341
|
-
return output;
|
|
1342
|
-
}
|
|
1343
|
-
_runner;
|
|
1344
|
-
get runner() {
|
|
1345
|
-
if (!this._runner) {
|
|
1346
|
-
this._runner = new TaskRunner(this);
|
|
1347
|
-
}
|
|
1348
|
-
return this._runner;
|
|
1349
|
-
}
|
|
1350
|
-
async run(overrides = {}, runConfig = {}) {
|
|
1351
|
-
return this.runner.run(overrides, { ...this.runConfig, ...runConfig });
|
|
1352
|
-
}
|
|
1353
|
-
async runReactive(overrides = {}) {
|
|
1354
|
-
return this.runner.runReactive(overrides);
|
|
1355
|
-
}
|
|
1356
|
-
abort() {
|
|
1357
|
-
this.runner.abort();
|
|
1358
|
-
}
|
|
1359
|
-
async disable() {
|
|
1360
|
-
await this.runner.disable();
|
|
1361
|
-
}
|
|
1362
|
-
inputSchema() {
|
|
1363
|
-
return this.constructor.inputSchema();
|
|
1364
|
-
}
|
|
1365
|
-
outputSchema() {
|
|
1366
|
-
return this.constructor.outputSchema();
|
|
1367
|
-
}
|
|
1368
|
-
configSchema() {
|
|
1369
|
-
return this.constructor.configSchema();
|
|
1370
|
-
}
|
|
1371
|
-
get type() {
|
|
1372
|
-
return this.constructor.type;
|
|
1373
|
-
}
|
|
1374
|
-
get category() {
|
|
1375
|
-
return this.constructor.category;
|
|
1376
|
-
}
|
|
1377
|
-
get title() {
|
|
1378
|
-
return this.config?.title ?? this.constructor.title;
|
|
1379
|
-
}
|
|
1380
|
-
get description() {
|
|
1381
|
-
return this.config?.description ?? this.constructor.description;
|
|
1382
|
-
}
|
|
1383
|
-
get cacheable() {
|
|
1384
|
-
return this.runConfig?.cacheable ?? this.config?.cacheable ?? this.constructor.cacheable;
|
|
1385
|
-
}
|
|
1386
|
-
defaults;
|
|
1387
|
-
runInputData = {};
|
|
1388
|
-
runOutputData = {};
|
|
1389
|
-
config;
|
|
1390
|
-
get id() {
|
|
1391
|
-
return this.config.id;
|
|
1392
|
-
}
|
|
1393
|
-
runConfig = {};
|
|
1394
|
-
status = TaskStatus.PENDING;
|
|
1395
|
-
progress = 0;
|
|
1396
|
-
createdAt = new Date;
|
|
1397
|
-
startedAt;
|
|
1398
|
-
completedAt;
|
|
1399
|
-
error;
|
|
1400
|
-
get events() {
|
|
1401
|
-
if (!this._events) {
|
|
1402
|
-
this._events = new EventEmitter3;
|
|
1403
|
-
}
|
|
1404
|
-
return this._events;
|
|
1405
|
-
}
|
|
1406
|
-
_events;
|
|
1407
|
-
constructor(callerDefaultInputs = {}, config = {}, runConfig = {}) {
|
|
1408
|
-
const inputDefaults = this.getDefaultInputsFromStaticInputDefinitions();
|
|
1409
|
-
const mergedDefaults = Object.assign(inputDefaults, callerDefaultInputs);
|
|
1410
|
-
this.defaults = this.stripSymbols(mergedDefaults);
|
|
1411
|
-
this.resetInputData();
|
|
1412
|
-
const title = this.constructor.title || undefined;
|
|
1413
|
-
const baseConfig = Object.assign({
|
|
1414
|
-
...title ? { title } : {}
|
|
1415
|
-
}, config);
|
|
1416
|
-
if (baseConfig.id === undefined) {
|
|
1417
|
-
baseConfig.id = uuid42();
|
|
1418
|
-
}
|
|
1419
|
-
this.config = this.validateAndApplyConfigDefaults(baseConfig);
|
|
1420
|
-
this.runConfig = runConfig;
|
|
1421
|
-
}
|
|
1422
|
-
getDefaultInputsFromStaticInputDefinitions() {
|
|
1423
|
-
const schema = this.inputSchema();
|
|
1424
|
-
if (typeof schema === "boolean") {
|
|
1425
|
-
return {};
|
|
1426
|
-
}
|
|
1427
|
-
try {
|
|
1428
|
-
const compiledSchema = this.getInputSchemaNode();
|
|
1429
|
-
const defaultData = compiledSchema.getData(undefined, {
|
|
1430
|
-
addOptionalProps: true,
|
|
1431
|
-
removeInvalidData: false,
|
|
1432
|
-
useTypeDefaults: false
|
|
1433
|
-
});
|
|
1434
|
-
return defaultData || {};
|
|
1435
|
-
} catch (error) {
|
|
1436
|
-
console.warn(`Failed to compile input schema for ${this.type}, falling back to manual extraction:`, error);
|
|
1437
|
-
return Object.entries(schema.properties || {}).reduce((acc, [id, prop]) => {
|
|
1438
|
-
const defaultValue = prop.default;
|
|
1439
|
-
if (defaultValue !== undefined) {
|
|
1440
|
-
acc[id] = defaultValue;
|
|
1441
|
-
}
|
|
1442
|
-
return acc;
|
|
1443
|
-
}, {});
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1446
|
-
resetInputData() {
|
|
1447
|
-
this.runInputData = this.smartClone(this.defaults);
|
|
1448
|
-
}
|
|
1449
|
-
smartClone(obj, visited = new WeakSet) {
|
|
1450
|
-
if (obj === null || obj === undefined) {
|
|
1451
|
-
return obj;
|
|
1452
|
-
}
|
|
1453
|
-
if (typeof obj !== "object") {
|
|
1454
|
-
return obj;
|
|
1455
|
-
}
|
|
1456
|
-
if (visited.has(obj)) {
|
|
1457
|
-
throw new TaskConfigurationError("Circular reference detected in input data. " + "Cannot clone objects with circular references.");
|
|
1458
|
-
}
|
|
1459
|
-
if (ArrayBuffer.isView(obj)) {
|
|
1460
|
-
if (typeof DataView !== "undefined" && obj instanceof DataView) {
|
|
1461
|
-
return obj;
|
|
1462
|
-
}
|
|
1463
|
-
const typedArray = obj;
|
|
1464
|
-
return new typedArray.constructor(typedArray);
|
|
1465
|
-
}
|
|
1466
|
-
if (!Array.isArray(obj)) {
|
|
1467
|
-
const proto = Object.getPrototypeOf(obj);
|
|
1468
|
-
if (proto !== Object.prototype && proto !== null) {
|
|
1469
|
-
return obj;
|
|
1470
|
-
}
|
|
1471
|
-
}
|
|
1472
|
-
visited.add(obj);
|
|
1473
|
-
try {
|
|
1474
|
-
if (Array.isArray(obj)) {
|
|
1475
|
-
return obj.map((item) => this.smartClone(item, visited));
|
|
1476
|
-
}
|
|
1477
|
-
const result = {};
|
|
1478
|
-
for (const key in obj) {
|
|
1479
|
-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
1480
|
-
result[key] = this.smartClone(obj[key], visited);
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
return result;
|
|
1484
|
-
} finally {
|
|
1485
|
-
visited.delete(obj);
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1488
|
-
setDefaults(defaults) {
|
|
1489
|
-
this.defaults = this.stripSymbols(defaults);
|
|
1490
|
-
}
|
|
1491
|
-
setInput(input) {
|
|
1492
|
-
const schema = this.inputSchema();
|
|
1493
|
-
if (typeof schema === "boolean") {
|
|
1494
|
-
if (schema === true) {
|
|
1495
|
-
for (const [inputId, value] of Object.entries(input)) {
|
|
1496
|
-
if (value !== undefined) {
|
|
1497
|
-
this.runInputData[inputId] = value;
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
}
|
|
1501
|
-
return;
|
|
1502
|
-
}
|
|
1503
|
-
const properties = schema.properties || {};
|
|
1504
|
-
for (const [inputId, prop] of Object.entries(properties)) {
|
|
1505
|
-
if (input[inputId] !== undefined) {
|
|
1506
|
-
this.runInputData[inputId] = input[inputId];
|
|
1507
|
-
} else if (this.runInputData[inputId] === undefined && prop.default !== undefined) {
|
|
1508
|
-
this.runInputData[inputId] = prop.default;
|
|
1509
|
-
}
|
|
1510
|
-
}
|
|
1511
|
-
if (schema.additionalProperties) {
|
|
1512
|
-
for (const [inputId, value] of Object.entries(input)) {
|
|
1513
|
-
if (!(inputId in properties)) {
|
|
1514
|
-
this.runInputData[inputId] = value;
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
}
|
|
1519
|
-
addInput(overrides) {
|
|
1520
|
-
if (!overrides)
|
|
1521
|
-
return false;
|
|
1522
|
-
let changed = false;
|
|
1523
|
-
const inputSchema = this.inputSchema();
|
|
1524
|
-
if (typeof inputSchema === "boolean") {
|
|
1525
|
-
if (inputSchema === false) {
|
|
1526
|
-
return false;
|
|
1527
|
-
}
|
|
1528
|
-
for (const [key, value] of Object.entries(overrides)) {
|
|
1529
|
-
if (!deepEqual(this.runInputData[key], value)) {
|
|
1530
|
-
this.runInputData[key] = value;
|
|
1531
|
-
changed = true;
|
|
1532
|
-
}
|
|
1533
|
-
}
|
|
1534
|
-
return changed;
|
|
1535
|
-
}
|
|
1536
|
-
const properties = inputSchema.properties || {};
|
|
1537
|
-
for (const [inputId, prop] of Object.entries(properties)) {
|
|
1538
|
-
if (inputId === DATAFLOW_ALL_PORTS) {
|
|
1539
|
-
this.runInputData = { ...this.runInputData, ...overrides };
|
|
1540
|
-
changed = true;
|
|
1541
|
-
} else {
|
|
1542
|
-
if (overrides[inputId] === undefined)
|
|
1543
|
-
continue;
|
|
1544
|
-
const isArray = prop?.type === "array" || prop?.type === "any" && (Array.isArray(overrides[inputId]) || Array.isArray(this.runInputData[inputId]));
|
|
1545
|
-
if (isArray) {
|
|
1546
|
-
const existingItems = Array.isArray(this.runInputData[inputId]) ? this.runInputData[inputId] : this.runInputData[inputId] !== undefined ? [this.runInputData[inputId]] : [];
|
|
1547
|
-
const newitems = [...existingItems];
|
|
1548
|
-
const overrideItem = overrides[inputId];
|
|
1549
|
-
if (Array.isArray(overrideItem)) {
|
|
1550
|
-
newitems.push(...overrideItem);
|
|
1551
|
-
} else {
|
|
1552
|
-
newitems.push(overrideItem);
|
|
1553
|
-
}
|
|
1554
|
-
this.runInputData[inputId] = newitems;
|
|
1555
|
-
changed = true;
|
|
1556
|
-
} else {
|
|
1557
|
-
if (!deepEqual(this.runInputData[inputId], overrides[inputId])) {
|
|
1558
|
-
this.runInputData[inputId] = overrides[inputId];
|
|
1559
|
-
changed = true;
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1564
|
-
if (inputSchema.additionalProperties) {
|
|
1565
|
-
for (const [inputId, value] of Object.entries(overrides)) {
|
|
1566
|
-
if (!(inputId in properties)) {
|
|
1567
|
-
if (!deepEqual(this.runInputData[inputId], value)) {
|
|
1568
|
-
this.runInputData[inputId] = value;
|
|
1569
|
-
changed = true;
|
|
1570
|
-
}
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
}
|
|
1574
|
-
return changed;
|
|
1575
|
-
}
|
|
1576
|
-
async narrowInput(input, _registry) {
|
|
1577
|
-
return input;
|
|
1578
|
-
}
|
|
1579
|
-
subscribe(name, fn) {
|
|
1580
|
-
return this.events.subscribe(name, fn);
|
|
1581
|
-
}
|
|
1582
|
-
on(name, fn) {
|
|
1583
|
-
this.events.on(name, fn);
|
|
1584
|
-
}
|
|
1585
|
-
off(name, fn) {
|
|
1586
|
-
this.events.off(name, fn);
|
|
1587
|
-
}
|
|
1588
|
-
once(name, fn) {
|
|
1589
|
-
this.events.once(name, fn);
|
|
1590
|
-
}
|
|
1591
|
-
waitOn(name) {
|
|
1592
|
-
return this.events.waitOn(name);
|
|
1593
|
-
}
|
|
1594
|
-
emit(name, ...args) {
|
|
1595
|
-
this._events?.emit(name, ...args);
|
|
1596
|
-
}
|
|
1597
|
-
emitSchemaChange(inputSchema, outputSchema) {
|
|
1598
|
-
const finalInputSchema = inputSchema ?? this.inputSchema();
|
|
1599
|
-
const finalOutputSchema = outputSchema ?? this.outputSchema();
|
|
1600
|
-
this.emit("schemaChange", finalInputSchema, finalOutputSchema);
|
|
1601
|
-
}
|
|
1602
|
-
static getConfigSchemaNode() {
|
|
1603
|
-
const schema = this.configSchema();
|
|
1604
|
-
if (!schema)
|
|
1605
|
-
return;
|
|
1606
|
-
if (!Object.hasOwn(this, "__compiledConfigSchema")) {
|
|
1607
|
-
try {
|
|
1608
|
-
const schemaNode = typeof schema === "boolean" ? compileSchema(schema ? {} : { not: {} }) : compileSchema(schema);
|
|
1609
|
-
Object.defineProperty(this, "__compiledConfigSchema", {
|
|
1610
|
-
value: schemaNode,
|
|
1611
|
-
writable: true,
|
|
1612
|
-
configurable: true,
|
|
1613
|
-
enumerable: false
|
|
1614
|
-
});
|
|
1615
|
-
} catch (error) {
|
|
1616
|
-
console.warn(`Failed to compile config schema for ${this.type}:`, error);
|
|
1617
|
-
return;
|
|
1618
|
-
}
|
|
1619
|
-
}
|
|
1620
|
-
return this.__compiledConfigSchema;
|
|
1621
|
-
}
|
|
1622
|
-
validateAndApplyConfigDefaults(config) {
|
|
1623
|
-
const ctor = this.constructor;
|
|
1624
|
-
const schemaNode = ctor.getConfigSchemaNode();
|
|
1625
|
-
if (!schemaNode)
|
|
1626
|
-
return config;
|
|
1627
|
-
const result = schemaNode.validate(config);
|
|
1628
|
-
if (!result.valid) {
|
|
1629
|
-
const errorMessages = result.errors.map((e) => {
|
|
1630
|
-
const path = e.data?.pointer || "";
|
|
1631
|
-
return `${e.message}${path ? ` (${path})` : ""}`;
|
|
1632
|
-
});
|
|
1633
|
-
throw new TaskConfigurationError(`[${ctor.name}] Configuration Error: ${errorMessages.join(", ")}`);
|
|
1634
|
-
}
|
|
1635
|
-
return config;
|
|
1636
|
-
}
|
|
1637
|
-
static generateInputSchemaNode(schema) {
|
|
1638
|
-
if (typeof schema === "boolean") {
|
|
1639
|
-
if (schema === false) {
|
|
1640
|
-
return compileSchema({ not: {} });
|
|
1641
|
-
}
|
|
1642
|
-
return compileSchema({});
|
|
1643
|
-
}
|
|
1644
|
-
return compileSchema(schema);
|
|
1645
|
-
}
|
|
1646
|
-
static getInputSchemaNode() {
|
|
1647
|
-
if (!Object.hasOwn(this, "__compiledInputSchema")) {
|
|
1648
|
-
const dataPortSchema = this.inputSchema();
|
|
1649
|
-
const schemaNode = this.generateInputSchemaNode(dataPortSchema);
|
|
1650
|
-
try {
|
|
1651
|
-
Object.defineProperty(this, "__compiledInputSchema", {
|
|
1652
|
-
value: schemaNode,
|
|
1653
|
-
writable: true,
|
|
1654
|
-
configurable: true,
|
|
1655
|
-
enumerable: false
|
|
1656
|
-
});
|
|
1657
|
-
} catch (error) {
|
|
1658
|
-
console.warn(`Failed to compile input schema for ${this.type}, falling back to permissive validation:`, error);
|
|
1659
|
-
Object.defineProperty(this, "__compiledInputSchema", {
|
|
1660
|
-
value: compileSchema({}),
|
|
1661
|
-
writable: true,
|
|
1662
|
-
configurable: true,
|
|
1663
|
-
enumerable: false
|
|
1664
|
-
});
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
return this.__compiledInputSchema;
|
|
1668
|
-
}
|
|
1669
|
-
getInputSchemaNode() {
|
|
1670
|
-
return this.constructor.getInputSchemaNode();
|
|
1671
|
-
}
|
|
1672
|
-
async validateInput(input) {
|
|
1673
|
-
const ctor = this.constructor;
|
|
1674
|
-
let schemaNode;
|
|
1675
|
-
if (ctor.hasDynamicSchemas) {
|
|
1676
|
-
const instanceSchema = this.inputSchema();
|
|
1677
|
-
schemaNode = ctor.generateInputSchemaNode(instanceSchema);
|
|
1678
|
-
} else {
|
|
1679
|
-
schemaNode = this.getInputSchemaNode();
|
|
1680
|
-
}
|
|
1681
|
-
const result = schemaNode.validate(input);
|
|
1682
|
-
if (!result.valid) {
|
|
1683
|
-
const errorMessages = result.errors.map((e) => {
|
|
1684
|
-
const path = e.data.pointer || "";
|
|
1685
|
-
return `${e.message}${path ? ` (${path})` : ""}`;
|
|
1686
|
-
});
|
|
1687
|
-
throw new TaskInvalidInputError(`Input ${JSON.stringify(Object.keys(input))} does not match schema: ${errorMessages.join(", ")}`);
|
|
1688
|
-
}
|
|
1689
|
-
return true;
|
|
1690
|
-
}
|
|
1691
|
-
stripSymbols(obj) {
|
|
1692
|
-
if (obj === null || obj === undefined) {
|
|
1693
|
-
return obj;
|
|
1694
|
-
}
|
|
1695
|
-
if (ArrayBuffer.isView(obj)) {
|
|
1696
|
-
return obj;
|
|
1697
|
-
}
|
|
1698
|
-
if (Array.isArray(obj)) {
|
|
1699
|
-
return obj.map((item) => this.stripSymbols(item));
|
|
1700
|
-
}
|
|
1701
|
-
if (typeof obj === "object") {
|
|
1702
|
-
const result = {};
|
|
1703
|
-
for (const key in obj) {
|
|
1704
|
-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
1705
|
-
result[key] = this.stripSymbols(obj[key]);
|
|
1706
|
-
}
|
|
1707
|
-
}
|
|
1708
|
-
return result;
|
|
1709
|
-
}
|
|
1710
|
-
return obj;
|
|
1711
|
-
}
|
|
1712
|
-
toJSON(_options) {
|
|
1713
|
-
const extras = this.config.extras;
|
|
1714
|
-
const json = this.stripSymbols({
|
|
1715
|
-
id: this.id,
|
|
1716
|
-
type: this.type,
|
|
1717
|
-
defaults: this.defaults,
|
|
1718
|
-
config: {
|
|
1719
|
-
...this.config.title ? { title: this.config.title } : {},
|
|
1720
|
-
...this.config.description ? { description: this.config.description } : {},
|
|
1721
|
-
...this.config.inputSchema ? { inputSchema: this.config.inputSchema } : {},
|
|
1722
|
-
...this.config.outputSchema ? { outputSchema: this.config.outputSchema } : {},
|
|
1723
|
-
...extras && Object.keys(extras).length ? { extras } : {}
|
|
1724
|
-
}
|
|
1725
|
-
});
|
|
1726
|
-
return json;
|
|
1727
|
-
}
|
|
1728
|
-
toDependencyJSON(options) {
|
|
1729
|
-
const json = this.toJSON(options);
|
|
1730
|
-
return json;
|
|
1731
|
-
}
|
|
1732
|
-
hasChildren() {
|
|
1733
|
-
return this._subGraph !== undefined && this._subGraph !== null && this._subGraph.getTasks().length > 0;
|
|
1734
|
-
}
|
|
1735
|
-
_taskAddedListener = () => {
|
|
1736
|
-
this.emit("regenerate");
|
|
1737
|
-
};
|
|
1738
|
-
_subGraph = undefined;
|
|
1739
|
-
set subGraph(subGraph) {
|
|
1740
|
-
if (this._subGraph) {
|
|
1741
|
-
this._subGraph.off("task_added", this._taskAddedListener);
|
|
1742
|
-
}
|
|
1743
|
-
this._subGraph = subGraph;
|
|
1744
|
-
this._subGraph.on("task_added", this._taskAddedListener);
|
|
1745
|
-
}
|
|
1746
|
-
get subGraph() {
|
|
1747
|
-
if (!this._subGraph) {
|
|
1748
|
-
this._subGraph = new TaskGraph;
|
|
1749
|
-
this._subGraph.on("task_added", this._taskAddedListener);
|
|
1750
|
-
}
|
|
1751
|
-
return this._subGraph;
|
|
1752
|
-
}
|
|
1753
|
-
regenerateGraph() {
|
|
1754
|
-
if (this.hasChildren()) {
|
|
1755
|
-
for (const dataflow of this.subGraph.getDataflows()) {
|
|
1756
|
-
this.subGraph.removeDataflow(dataflow);
|
|
1757
|
-
}
|
|
1758
|
-
for (const child of this.subGraph.getTasks()) {
|
|
1759
|
-
this.subGraph.removeTask(child.id);
|
|
1760
|
-
}
|
|
1761
|
-
}
|
|
1762
|
-
this.events.emit("regenerate");
|
|
1763
|
-
}
|
|
1764
|
-
}
|
|
1765
|
-
|
|
1766
|
-
// src/task/ConditionalTask.ts
|
|
1767
|
-
var conditionalTaskConfigSchema = {
|
|
1768
|
-
type: "object",
|
|
1769
|
-
properties: {
|
|
1770
|
-
...TaskConfigSchema["properties"],
|
|
1771
|
-
branches: { type: "array", items: {} },
|
|
1772
|
-
defaultBranch: { type: "string" },
|
|
1773
|
-
exclusive: { type: "boolean" },
|
|
1774
|
-
conditionConfig: { type: "object", additionalProperties: true }
|
|
1775
|
-
},
|
|
1776
|
-
additionalProperties: false
|
|
1777
|
-
};
|
|
1778
|
-
|
|
1779
|
-
class ConditionalTask extends Task {
|
|
1780
|
-
static type = "ConditionalTask";
|
|
1781
|
-
static category = "Flow Control";
|
|
1782
|
-
static title = "Condition";
|
|
1783
|
-
static description = "Route data based on conditions";
|
|
1784
|
-
static hasDynamicSchemas = true;
|
|
1785
|
-
static configSchema() {
|
|
1786
|
-
return conditionalTaskConfigSchema;
|
|
1787
|
-
}
|
|
1788
|
-
activeBranches = new Set;
|
|
1789
|
-
buildBranchesFromConditionConfig(conditionConfig) {
|
|
1790
|
-
if (!conditionConfig?.branches || conditionConfig.branches.length === 0) {
|
|
1791
|
-
return [
|
|
1792
|
-
{
|
|
1793
|
-
id: "default",
|
|
1794
|
-
condition: () => true,
|
|
1795
|
-
outputPort: "1"
|
|
1796
|
-
}
|
|
1797
|
-
];
|
|
1798
|
-
}
|
|
1799
|
-
return conditionConfig.branches.map((branch, index) => ({
|
|
1800
|
-
id: branch.id,
|
|
1801
|
-
outputPort: String(index + 1),
|
|
1802
|
-
condition: (inputData) => {
|
|
1803
|
-
const fieldValue = getNestedValue(inputData, branch.field);
|
|
1804
|
-
return evaluateCondition(fieldValue, branch.operator, branch.value);
|
|
1805
|
-
}
|
|
1806
|
-
}));
|
|
1807
|
-
}
|
|
1808
|
-
resolveBranches(input) {
|
|
1809
|
-
const configBranches = this.config.branches ?? [];
|
|
1810
|
-
if (configBranches.length > 0 && typeof configBranches[0].condition === "function") {
|
|
1811
|
-
return {
|
|
1812
|
-
branches: configBranches,
|
|
1813
|
-
isExclusive: this.config.exclusive ?? true,
|
|
1814
|
-
defaultBranch: this.config.defaultBranch,
|
|
1815
|
-
fromConditionConfig: false
|
|
1816
|
-
};
|
|
1817
|
-
}
|
|
1818
|
-
const conditionConfig = input.conditionConfig ?? this.config.conditionConfig;
|
|
1819
|
-
if (conditionConfig) {
|
|
1820
|
-
return {
|
|
1821
|
-
branches: this.buildBranchesFromConditionConfig(conditionConfig),
|
|
1822
|
-
isExclusive: conditionConfig.exclusive ?? true,
|
|
1823
|
-
defaultBranch: conditionConfig.defaultBranch,
|
|
1824
|
-
fromConditionConfig: true
|
|
1825
|
-
};
|
|
1826
|
-
}
|
|
1827
|
-
return {
|
|
1828
|
-
branches: configBranches,
|
|
1829
|
-
isExclusive: this.config.exclusive ?? true,
|
|
1830
|
-
defaultBranch: this.config.defaultBranch,
|
|
1831
|
-
fromConditionConfig: false
|
|
1832
|
-
};
|
|
1833
|
-
}
|
|
1834
|
-
async execute(input, context) {
|
|
1835
|
-
if (context.signal?.aborted) {
|
|
1836
|
-
return;
|
|
1837
|
-
}
|
|
1838
|
-
this.activeBranches.clear();
|
|
1839
|
-
const { branches, isExclusive, defaultBranch, fromConditionConfig } = this.resolveBranches(input);
|
|
1840
|
-
for (const branch of branches) {
|
|
1841
|
-
try {
|
|
1842
|
-
const isActive = branch.condition(input);
|
|
1843
|
-
if (isActive) {
|
|
1844
|
-
this.activeBranches.add(branch.id);
|
|
1845
|
-
if (isExclusive) {
|
|
1846
|
-
break;
|
|
1847
|
-
}
|
|
1848
|
-
}
|
|
1849
|
-
} catch (error) {
|
|
1850
|
-
getLogger2().warn(`Condition evaluation failed for branch "${branch.id}":`, { error });
|
|
1851
|
-
}
|
|
1852
|
-
}
|
|
1853
|
-
if (this.activeBranches.size === 0 && defaultBranch) {
|
|
1854
|
-
const defaultBranchExists = branches.some((b) => b.id === defaultBranch);
|
|
1855
|
-
if (defaultBranchExists) {
|
|
1856
|
-
this.activeBranches.add(defaultBranch);
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
if (fromConditionConfig) {
|
|
1860
|
-
return this.buildConditionConfigOutput(input, branches, isExclusive);
|
|
1861
|
-
}
|
|
1862
|
-
return this.buildOutput(input);
|
|
1863
|
-
}
|
|
1864
|
-
buildConditionConfigOutput(input, branches, isExclusive) {
|
|
1865
|
-
const output = {};
|
|
1866
|
-
const { conditionConfig, ...passThrough } = input;
|
|
1867
|
-
const inputKeys = Object.keys(passThrough);
|
|
1868
|
-
let matchedBranchNumber = null;
|
|
1869
|
-
for (let i = 0;i < branches.length; i++) {
|
|
1870
|
-
if (this.activeBranches.has(branches[i].id)) {
|
|
1871
|
-
if (matchedBranchNumber === null) {
|
|
1872
|
-
matchedBranchNumber = i + 1;
|
|
1873
|
-
}
|
|
1874
|
-
}
|
|
1875
|
-
}
|
|
1876
|
-
if (isExclusive) {
|
|
1877
|
-
if (matchedBranchNumber !== null) {
|
|
1878
|
-
for (const key of inputKeys) {
|
|
1879
|
-
output[`${key}_${matchedBranchNumber}`] = passThrough[key];
|
|
1880
|
-
}
|
|
1881
|
-
} else {
|
|
1882
|
-
for (const key of inputKeys) {
|
|
1883
|
-
output[`${key}_else`] = passThrough[key];
|
|
1884
|
-
}
|
|
1885
|
-
}
|
|
1886
|
-
} else {
|
|
1887
|
-
for (let i = 0;i < branches.length; i++) {
|
|
1888
|
-
if (this.activeBranches.has(branches[i].id)) {
|
|
1889
|
-
for (const key of inputKeys) {
|
|
1890
|
-
output[`${key}_${i + 1}`] = passThrough[key];
|
|
1891
|
-
}
|
|
1892
|
-
}
|
|
1893
|
-
}
|
|
1894
|
-
}
|
|
1895
|
-
return output;
|
|
1896
|
-
}
|
|
1897
|
-
buildOutput(input) {
|
|
1898
|
-
const output = {
|
|
1899
|
-
_activeBranches: Array.from(this.activeBranches)
|
|
1900
|
-
};
|
|
1901
|
-
const branches = this.config.branches ?? [];
|
|
1902
|
-
for (const branch of branches) {
|
|
1903
|
-
if (this.activeBranches.has(branch.id)) {
|
|
1904
|
-
output[branch.outputPort] = { ...input };
|
|
1905
|
-
}
|
|
1906
|
-
}
|
|
1907
|
-
return output;
|
|
1908
|
-
}
|
|
1909
|
-
isBranchActive(branchId) {
|
|
1910
|
-
return this.activeBranches.has(branchId);
|
|
1911
|
-
}
|
|
1912
|
-
getActiveBranches() {
|
|
1913
|
-
return new Set(this.activeBranches);
|
|
1914
|
-
}
|
|
1915
|
-
getPortActiveStatus() {
|
|
1916
|
-
const status = new Map;
|
|
1917
|
-
const branches = this.config.branches ?? [];
|
|
1918
|
-
for (const branch of branches) {
|
|
1919
|
-
status.set(branch.outputPort, this.activeBranches.has(branch.id));
|
|
1920
|
-
}
|
|
1921
|
-
return status;
|
|
1922
|
-
}
|
|
1923
|
-
static outputSchema() {
|
|
1924
|
-
return {
|
|
1925
|
-
type: "object",
|
|
1926
|
-
properties: {
|
|
1927
|
-
_activeBranches: {
|
|
1928
|
-
type: "array",
|
|
1929
|
-
items: { type: "string" },
|
|
1930
|
-
description: "List of active branch IDs after condition evaluation"
|
|
1931
|
-
}
|
|
1932
|
-
},
|
|
1933
|
-
additionalProperties: true
|
|
1934
|
-
};
|
|
1935
|
-
}
|
|
1936
|
-
outputSchema() {
|
|
1937
|
-
const branches = this.config?.branches ?? [];
|
|
1938
|
-
const properties = {
|
|
1939
|
-
_activeBranches: {
|
|
1940
|
-
type: "array",
|
|
1941
|
-
items: { type: "string" },
|
|
1942
|
-
description: "List of active branch IDs after condition evaluation"
|
|
1943
|
-
}
|
|
1944
|
-
};
|
|
1945
|
-
for (const branch of branches) {
|
|
1946
|
-
properties[branch.outputPort] = {
|
|
1947
|
-
type: "object",
|
|
1948
|
-
description: `Output for branch "${branch.id}" when active`,
|
|
1949
|
-
additionalProperties: true
|
|
1950
|
-
};
|
|
1951
|
-
}
|
|
1952
|
-
return {
|
|
1953
|
-
type: "object",
|
|
1954
|
-
properties,
|
|
1955
|
-
additionalProperties: false
|
|
1956
|
-
};
|
|
1957
|
-
}
|
|
1958
|
-
static inputSchema() {
|
|
1959
|
-
return {
|
|
1960
|
-
type: "object",
|
|
1961
|
-
properties: {},
|
|
1962
|
-
additionalProperties: true
|
|
1963
|
-
};
|
|
1964
|
-
}
|
|
1965
|
-
inputSchema() {
|
|
1966
|
-
return {
|
|
1967
|
-
type: "object",
|
|
1968
|
-
properties: {},
|
|
1969
|
-
additionalProperties: true
|
|
1970
|
-
};
|
|
1971
|
-
}
|
|
1972
|
-
}
|
|
1973
|
-
|
|
1974
|
-
// src/task-graph/TaskGraphScheduler.ts
|
|
1975
|
-
class TopologicalScheduler {
|
|
1976
|
-
dag;
|
|
1977
|
-
sortedNodes;
|
|
1978
|
-
currentIndex;
|
|
1979
|
-
constructor(dag) {
|
|
1980
|
-
this.dag = dag;
|
|
1981
|
-
this.sortedNodes = [];
|
|
1982
|
-
this.currentIndex = 0;
|
|
1983
|
-
this.reset();
|
|
1984
|
-
}
|
|
1985
|
-
async* tasks() {
|
|
1986
|
-
while (this.currentIndex < this.sortedNodes.length) {
|
|
1987
|
-
yield this.sortedNodes[this.currentIndex++];
|
|
1988
|
-
}
|
|
1989
|
-
}
|
|
1990
|
-
onTaskCompleted(taskId) {}
|
|
1991
|
-
onTaskStreaming(taskId) {}
|
|
1992
|
-
reset() {
|
|
1993
|
-
this.sortedNodes = this.dag.topologicallySortedNodes();
|
|
1994
|
-
this.currentIndex = 0;
|
|
1995
|
-
}
|
|
1996
|
-
}
|
|
1997
|
-
|
|
1998
|
-
class DependencyBasedScheduler {
|
|
1999
|
-
dag;
|
|
2000
|
-
completedTasks;
|
|
2001
|
-
streamingTasks;
|
|
2002
|
-
pendingTasks;
|
|
2003
|
-
nextResolver = null;
|
|
2004
|
-
constructor(dag) {
|
|
2005
|
-
this.dag = dag;
|
|
2006
|
-
this.completedTasks = new Set;
|
|
2007
|
-
this.streamingTasks = new Set;
|
|
2008
|
-
this.pendingTasks = new Set;
|
|
2009
|
-
this.reset();
|
|
2010
|
-
}
|
|
2011
|
-
isTaskReady(task) {
|
|
2012
|
-
if (task.status === TaskStatus.DISABLED) {
|
|
2013
|
-
return false;
|
|
2014
|
-
}
|
|
2015
|
-
const sourceDataflows = this.dag.getSourceDataflows(task.id);
|
|
2016
|
-
if (sourceDataflows.length > 0) {
|
|
2017
|
-
const allIncomingDisabled = sourceDataflows.every((df) => df.status === TaskStatus.DISABLED);
|
|
2018
|
-
if (allIncomingDisabled) {
|
|
2019
|
-
return false;
|
|
2020
|
-
}
|
|
2021
|
-
}
|
|
2022
|
-
const activeDataflows = sourceDataflows.filter((df) => df.status !== TaskStatus.DISABLED);
|
|
2023
|
-
return activeDataflows.every((df) => {
|
|
2024
|
-
const depId = df.sourceTaskId;
|
|
2025
|
-
if (this.completedTasks.has(depId))
|
|
2026
|
-
return true;
|
|
2027
|
-
if (this.streamingTasks.has(depId)) {
|
|
2028
|
-
const sourceTask = this.dag.getTask(depId);
|
|
2029
|
-
if (sourceTask) {
|
|
2030
|
-
const sourceMode = getPortStreamMode(sourceTask.outputSchema(), df.sourceTaskPortId);
|
|
2031
|
-
const targetMode = getPortStreamMode(task.inputSchema(), df.targetTaskPortId);
|
|
2032
|
-
if (sourceMode !== "none" && sourceMode === targetMode) {
|
|
2033
|
-
return true;
|
|
2034
|
-
}
|
|
2035
|
-
}
|
|
2036
|
-
}
|
|
2037
|
-
return false;
|
|
2038
|
-
});
|
|
2039
|
-
}
|
|
2040
|
-
async waitForNextTask() {
|
|
2041
|
-
if (this.pendingTasks.size === 0)
|
|
2042
|
-
return null;
|
|
2043
|
-
for (const task of Array.from(this.pendingTasks)) {
|
|
2044
|
-
if (task.status === TaskStatus.DISABLED) {
|
|
2045
|
-
this.pendingTasks.delete(task);
|
|
2046
|
-
}
|
|
2047
|
-
}
|
|
2048
|
-
if (this.pendingTasks.size === 0)
|
|
2049
|
-
return null;
|
|
2050
|
-
const readyTask = Array.from(this.pendingTasks).find((task) => this.isTaskReady(task));
|
|
2051
|
-
if (readyTask) {
|
|
2052
|
-
this.pendingTasks.delete(readyTask);
|
|
2053
|
-
return readyTask;
|
|
2054
|
-
}
|
|
2055
|
-
if (this.pendingTasks.size > 0) {
|
|
2056
|
-
return new Promise((resolve) => {
|
|
2057
|
-
this.nextResolver = resolve;
|
|
2058
|
-
});
|
|
2059
|
-
}
|
|
2060
|
-
return null;
|
|
2061
|
-
}
|
|
2062
|
-
async* tasks() {
|
|
2063
|
-
while (this.pendingTasks.size > 0) {
|
|
2064
|
-
const task = await this.waitForNextTask();
|
|
2065
|
-
if (task) {
|
|
2066
|
-
yield task;
|
|
2067
|
-
} else {
|
|
2068
|
-
break;
|
|
2069
|
-
}
|
|
2070
|
-
}
|
|
2071
|
-
}
|
|
2072
|
-
onTaskCompleted(taskId) {
|
|
2073
|
-
this.completedTasks.add(taskId);
|
|
2074
|
-
for (const task of Array.from(this.pendingTasks)) {
|
|
2075
|
-
if (task.status === TaskStatus.DISABLED) {
|
|
2076
|
-
this.pendingTasks.delete(task);
|
|
2077
|
-
}
|
|
2078
|
-
}
|
|
2079
|
-
if (this.nextResolver) {
|
|
2080
|
-
const readyTask = Array.from(this.pendingTasks).find((task) => this.isTaskReady(task));
|
|
2081
|
-
if (readyTask) {
|
|
2082
|
-
this.pendingTasks.delete(readyTask);
|
|
2083
|
-
const resolver = this.nextResolver;
|
|
2084
|
-
this.nextResolver = null;
|
|
2085
|
-
resolver(readyTask);
|
|
2086
|
-
} else if (this.pendingTasks.size === 0) {
|
|
2087
|
-
const resolver = this.nextResolver;
|
|
2088
|
-
this.nextResolver = null;
|
|
2089
|
-
resolver(null);
|
|
2090
|
-
}
|
|
2091
|
-
}
|
|
2092
|
-
}
|
|
2093
|
-
onTaskStreaming(taskId) {
|
|
2094
|
-
this.streamingTasks.add(taskId);
|
|
2095
|
-
for (const task of Array.from(this.pendingTasks)) {
|
|
2096
|
-
if (task.status === TaskStatus.DISABLED) {
|
|
2097
|
-
this.pendingTasks.delete(task);
|
|
2098
|
-
}
|
|
2099
|
-
}
|
|
2100
|
-
if (this.nextResolver) {
|
|
2101
|
-
const readyTask = Array.from(this.pendingTasks).find((task) => this.isTaskReady(task));
|
|
2102
|
-
if (readyTask) {
|
|
2103
|
-
this.pendingTasks.delete(readyTask);
|
|
2104
|
-
const resolver = this.nextResolver;
|
|
2105
|
-
this.nextResolver = null;
|
|
2106
|
-
resolver(readyTask);
|
|
2107
|
-
}
|
|
2108
|
-
}
|
|
2109
|
-
}
|
|
2110
|
-
reset() {
|
|
2111
|
-
this.completedTasks.clear();
|
|
2112
|
-
this.streamingTasks.clear();
|
|
2113
|
-
this.pendingTasks = new Set(this.dag.topologicallySortedNodes());
|
|
2114
|
-
this.nextResolver = null;
|
|
2115
|
-
}
|
|
2116
|
-
}
|
|
2117
|
-
|
|
2118
|
-
// src/task-graph/TaskGraphRunner.ts
|
|
2119
|
-
var PROPERTY_ARRAY = "PROPERTY_ARRAY";
|
|
2120
|
-
var GRAPH_RESULT_ARRAY = "GRAPH_RESULT_ARRAY";
|
|
2121
|
-
|
|
2122
|
-
class TaskGraphRunner {
|
|
2123
|
-
processScheduler;
|
|
2124
|
-
reactiveScheduler;
|
|
2125
|
-
running = false;
|
|
2126
|
-
reactiveRunning = false;
|
|
2127
|
-
graph;
|
|
2128
|
-
outputCache;
|
|
2129
|
-
accumulateLeafOutputs = true;
|
|
2130
|
-
registry = globalServiceRegistry2;
|
|
2131
|
-
abortController;
|
|
2132
|
-
inProgressTasks = new Map;
|
|
2133
|
-
inProgressFunctions = new Map;
|
|
2134
|
-
failedTaskErrors = new Map;
|
|
2135
|
-
constructor(graph, outputCache, processScheduler = new DependencyBasedScheduler(graph), reactiveScheduler = new TopologicalScheduler(graph)) {
|
|
2136
|
-
this.processScheduler = processScheduler;
|
|
2137
|
-
this.reactiveScheduler = reactiveScheduler;
|
|
2138
|
-
this.graph = graph;
|
|
2139
|
-
graph.outputCache = outputCache;
|
|
2140
|
-
this.handleProgress = this.handleProgress.bind(this);
|
|
2141
|
-
}
|
|
2142
|
-
runId = "";
|
|
2143
|
-
get timerLabel() {
|
|
2144
|
-
return `graph:${this.runId}`;
|
|
2145
|
-
}
|
|
2146
|
-
async runGraph(input = {}, config) {
|
|
2147
|
-
await this.handleStart(config);
|
|
2148
|
-
const results = [];
|
|
2149
|
-
let error;
|
|
2150
|
-
try {
|
|
2151
|
-
for await (const task of this.processScheduler.tasks()) {
|
|
2152
|
-
if (this.abortController?.signal.aborted) {
|
|
2153
|
-
break;
|
|
2154
|
-
}
|
|
2155
|
-
if (this.failedTaskErrors.size > 0) {
|
|
2156
|
-
break;
|
|
2157
|
-
}
|
|
2158
|
-
const isRootTask = this.graph.getSourceDataflows(task.id).length === 0;
|
|
2159
|
-
const runAsync = async () => {
|
|
2160
|
-
let errorRouted = false;
|
|
2161
|
-
try {
|
|
2162
|
-
const taskInput = isRootTask ? input : this.filterInputForTask(task, input);
|
|
2163
|
-
const taskPromise = this.runTask(task, taskInput);
|
|
2164
|
-
this.inProgressTasks.set(task.id, taskPromise);
|
|
2165
|
-
const taskResult = await taskPromise;
|
|
2166
|
-
if (this.graph.getTargetDataflows(task.id).length === 0) {
|
|
2167
|
-
results.push(taskResult);
|
|
2168
|
-
}
|
|
2169
|
-
} catch (error2) {
|
|
2170
|
-
if (this.hasErrorOutputEdges(task)) {
|
|
2171
|
-
errorRouted = true;
|
|
2172
|
-
this.pushErrorOutputToEdges(task);
|
|
2173
|
-
} else {
|
|
2174
|
-
this.failedTaskErrors.set(task.id, error2);
|
|
2175
|
-
}
|
|
2176
|
-
} finally {
|
|
2177
|
-
if (!errorRouted) {
|
|
2178
|
-
this.pushStatusFromNodeToEdges(this.graph, task);
|
|
2179
|
-
this.pushErrorFromNodeToEdges(this.graph, task);
|
|
2180
|
-
}
|
|
2181
|
-
this.processScheduler.onTaskCompleted(task.id);
|
|
2182
|
-
}
|
|
2183
|
-
};
|
|
2184
|
-
this.inProgressFunctions.set(Symbol(task.id), runAsync());
|
|
2185
|
-
}
|
|
2186
|
-
} catch (err) {
|
|
2187
|
-
error = err;
|
|
2188
|
-
}
|
|
2189
|
-
await Promise.allSettled(Array.from(this.inProgressTasks.values()));
|
|
2190
|
-
await Promise.allSettled(Array.from(this.inProgressFunctions.values()));
|
|
2191
|
-
if (this.failedTaskErrors.size > 0) {
|
|
2192
|
-
const latestError = this.failedTaskErrors.values().next().value;
|
|
2193
|
-
this.handleError(latestError);
|
|
2194
|
-
throw latestError;
|
|
2195
|
-
}
|
|
2196
|
-
if (this.abortController?.signal.aborted) {
|
|
2197
|
-
await this.handleAbort();
|
|
2198
|
-
throw new TaskAbortedError;
|
|
2199
|
-
}
|
|
2200
|
-
await this.handleComplete();
|
|
2201
|
-
return results;
|
|
2202
|
-
}
|
|
2203
|
-
async runGraphReactive(input = {}, config) {
|
|
2204
|
-
await this.handleStartReactive(config);
|
|
2205
|
-
const results = [];
|
|
2206
|
-
try {
|
|
2207
|
-
for await (const task of this.reactiveScheduler.tasks()) {
|
|
2208
|
-
const isRootTask = this.graph.getSourceDataflows(task.id).length === 0;
|
|
2209
|
-
if (task.status === TaskStatus.PENDING) {
|
|
2210
|
-
task.resetInputData();
|
|
2211
|
-
this.copyInputFromEdgesToNode(task);
|
|
2212
|
-
}
|
|
2213
|
-
const taskInput = isRootTask ? input : {};
|
|
2214
|
-
const taskResult = await task.runReactive(taskInput);
|
|
2215
|
-
await this.pushOutputFromNodeToEdges(task, taskResult);
|
|
2216
|
-
if (this.graph.getTargetDataflows(task.id).length === 0) {
|
|
2217
|
-
results.push({
|
|
2218
|
-
id: task.id,
|
|
2219
|
-
type: task.constructor.runtype || task.constructor.type,
|
|
2220
|
-
data: taskResult
|
|
2221
|
-
});
|
|
2222
|
-
}
|
|
2223
|
-
}
|
|
2224
|
-
await this.handleCompleteReactive();
|
|
2225
|
-
return results;
|
|
2226
|
-
} catch (error) {
|
|
2227
|
-
await this.handleErrorReactive();
|
|
2228
|
-
throw error;
|
|
2229
|
-
}
|
|
2230
|
-
}
|
|
2231
|
-
abort() {
|
|
2232
|
-
this.abortController?.abort();
|
|
2233
|
-
}
|
|
2234
|
-
async disable() {
|
|
2235
|
-
await this.handleDisable();
|
|
2236
|
-
}
|
|
2237
|
-
filterInputForTask(task, input) {
|
|
2238
|
-
const sourceDataflows = this.graph.getSourceDataflows(task.id);
|
|
2239
|
-
const connectedInputs = new Set(sourceDataflows.map((df) => df.targetTaskPortId));
|
|
2240
|
-
const allPortsConnected = connectedInputs.has(DATAFLOW_ALL_PORTS);
|
|
2241
|
-
const filteredInput = {};
|
|
2242
|
-
for (const [key, value] of Object.entries(input)) {
|
|
2243
|
-
if (!connectedInputs.has(key) && !allPortsConnected) {
|
|
2244
|
-
filteredInput[key] = value;
|
|
2245
|
-
}
|
|
2246
|
-
}
|
|
2247
|
-
return filteredInput;
|
|
2248
|
-
}
|
|
2249
|
-
addInputData(task, overrides) {
|
|
2250
|
-
if (!overrides)
|
|
2251
|
-
return;
|
|
2252
|
-
const changed = task.addInput(overrides);
|
|
2253
|
-
if (changed && "regenerateGraph" in task && typeof task.regenerateGraph === "function") {
|
|
2254
|
-
task.regenerateGraph();
|
|
2255
|
-
}
|
|
2256
|
-
}
|
|
2257
|
-
mergeExecuteOutputsToRunOutput(results, compoundMerge) {
|
|
2258
|
-
if (compoundMerge === GRAPH_RESULT_ARRAY) {
|
|
2259
|
-
return results;
|
|
2260
|
-
}
|
|
2261
|
-
if (compoundMerge === PROPERTY_ARRAY) {
|
|
2262
|
-
let fixedOutput = {};
|
|
2263
|
-
const outputs = results.map((result) => result.data);
|
|
2264
|
-
if (outputs.length === 1) {
|
|
2265
|
-
fixedOutput = outputs[0];
|
|
2266
|
-
} else if (outputs.length > 1) {
|
|
2267
|
-
const collected = collectPropertyValues(outputs);
|
|
2268
|
-
if (Object.keys(collected).length > 0) {
|
|
2269
|
-
fixedOutput = collected;
|
|
2270
|
-
}
|
|
2271
|
-
}
|
|
2272
|
-
return fixedOutput;
|
|
2273
|
-
}
|
|
2274
|
-
throw new TaskConfigurationError(`Unknown compound merge strategy: ${compoundMerge}`);
|
|
2275
|
-
}
|
|
2276
|
-
copyInputFromEdgesToNode(task) {
|
|
2277
|
-
const dataflows = this.graph.getSourceDataflows(task.id);
|
|
2278
|
-
for (const dataflow of dataflows) {
|
|
2279
|
-
this.addInputData(task, dataflow.getPortData());
|
|
2280
|
-
}
|
|
2281
|
-
}
|
|
2282
|
-
async pushOutputFromNodeToEdges(node, results) {
|
|
2283
|
-
const dataflows = this.graph.getTargetDataflows(node.id);
|
|
2284
|
-
for (const dataflow of dataflows) {
|
|
2285
|
-
const compatibility = dataflow.semanticallyCompatible(this.graph, dataflow);
|
|
2286
|
-
getLogger3().debug("pushOutputFromNodeToEdges", {
|
|
2287
|
-
dataflowId: dataflow.id,
|
|
2288
|
-
compatibility,
|
|
2289
|
-
resultsKeys: Object.keys(results)
|
|
2290
|
-
});
|
|
2291
|
-
if (compatibility === "static") {
|
|
2292
|
-
dataflow.setPortData(results);
|
|
2293
|
-
} else if (compatibility === "runtime") {
|
|
2294
|
-
const task = this.graph.getTask(dataflow.targetTaskId);
|
|
2295
|
-
const narrowed = await task.narrowInput({ ...results }, this.registry);
|
|
2296
|
-
dataflow.setPortData(narrowed);
|
|
2297
|
-
} else {
|
|
2298
|
-
getLogger3().warn("pushOutputFromNodeToEdges", {
|
|
2299
|
-
dataflowId: dataflow.id,
|
|
2300
|
-
compatibility,
|
|
2301
|
-
resultsKeys: Object.keys(results)
|
|
2302
|
-
});
|
|
2303
|
-
}
|
|
2304
|
-
}
|
|
2305
|
-
}
|
|
2306
|
-
pushStatusFromNodeToEdges(graph, node, status) {
|
|
2307
|
-
if (!node?.config?.id)
|
|
2308
|
-
return;
|
|
2309
|
-
const dataflows = graph.getTargetDataflows(node.id);
|
|
2310
|
-
const effectiveStatus = status ?? node.status;
|
|
2311
|
-
if (node instanceof ConditionalTask && effectiveStatus === TaskStatus.COMPLETED) {
|
|
2312
|
-
const branches = node.config.branches ?? [];
|
|
2313
|
-
const portToBranch = new Map;
|
|
2314
|
-
for (const branch of branches) {
|
|
2315
|
-
portToBranch.set(branch.outputPort, branch.id);
|
|
2316
|
-
}
|
|
2317
|
-
const activeBranches = node.getActiveBranches();
|
|
2318
|
-
for (const dataflow of dataflows) {
|
|
2319
|
-
const branchId = portToBranch.get(dataflow.sourceTaskPortId);
|
|
2320
|
-
if (branchId !== undefined) {
|
|
2321
|
-
if (activeBranches.has(branchId)) {
|
|
2322
|
-
dataflow.setStatus(TaskStatus.COMPLETED);
|
|
2323
|
-
} else {
|
|
2324
|
-
dataflow.setStatus(TaskStatus.DISABLED);
|
|
2325
|
-
}
|
|
2326
|
-
} else {
|
|
2327
|
-
dataflow.setStatus(effectiveStatus);
|
|
2328
|
-
}
|
|
2329
|
-
}
|
|
2330
|
-
this.propagateDisabledStatus(graph);
|
|
2331
|
-
return;
|
|
2332
|
-
}
|
|
2333
|
-
dataflows.forEach((dataflow) => {
|
|
2334
|
-
dataflow.setStatus(effectiveStatus);
|
|
2335
|
-
});
|
|
2336
|
-
}
|
|
2337
|
-
pushErrorFromNodeToEdges(graph, node) {
|
|
2338
|
-
if (!node?.config?.id)
|
|
2339
|
-
return;
|
|
2340
|
-
graph.getTargetDataflows(node.id).forEach((dataflow) => {
|
|
2341
|
-
dataflow.error = node.error;
|
|
2342
|
-
});
|
|
2343
|
-
}
|
|
2344
|
-
hasErrorOutputEdges(task) {
|
|
2345
|
-
const dataflows = this.graph.getTargetDataflows(task.id);
|
|
2346
|
-
return dataflows.some((df) => df.sourceTaskPortId === DATAFLOW_ERROR_PORT);
|
|
2347
|
-
}
|
|
2348
|
-
pushErrorOutputToEdges(task) {
|
|
2349
|
-
const taskError = task.error;
|
|
2350
|
-
const errorData = {
|
|
2351
|
-
error: taskError?.message ?? "Unknown error",
|
|
2352
|
-
errorType: taskError?.constructor?.type ?? "TaskError"
|
|
2353
|
-
};
|
|
2354
|
-
const dataflows = this.graph.getTargetDataflows(task.id);
|
|
2355
|
-
for (const df of dataflows) {
|
|
2356
|
-
if (df.sourceTaskPortId === DATAFLOW_ERROR_PORT) {
|
|
2357
|
-
df.value = errorData;
|
|
2358
|
-
df.setStatus(TaskStatus.COMPLETED);
|
|
2359
|
-
} else {
|
|
2360
|
-
df.setStatus(TaskStatus.DISABLED);
|
|
2361
|
-
}
|
|
2362
|
-
}
|
|
2363
|
-
this.propagateDisabledStatus(this.graph);
|
|
2364
|
-
}
|
|
2365
|
-
propagateDisabledStatus(graph) {
|
|
2366
|
-
let changed = true;
|
|
2367
|
-
while (changed) {
|
|
2368
|
-
changed = false;
|
|
2369
|
-
for (const task of graph.getTasks()) {
|
|
2370
|
-
if (task.status !== TaskStatus.PENDING) {
|
|
2371
|
-
continue;
|
|
2372
|
-
}
|
|
2373
|
-
const incomingDataflows = graph.getSourceDataflows(task.id);
|
|
2374
|
-
if (incomingDataflows.length === 0) {
|
|
2375
|
-
continue;
|
|
2376
|
-
}
|
|
2377
|
-
const allDisabled = incomingDataflows.every((df) => df.status === TaskStatus.DISABLED);
|
|
2378
|
-
if (allDisabled) {
|
|
2379
|
-
task.status = TaskStatus.DISABLED;
|
|
2380
|
-
task.progress = 100;
|
|
2381
|
-
task.completedAt = new Date;
|
|
2382
|
-
task.emit("disabled");
|
|
2383
|
-
task.emit("status", task.status);
|
|
2384
|
-
graph.getTargetDataflows(task.id).forEach((dataflow) => {
|
|
2385
|
-
dataflow.setStatus(TaskStatus.DISABLED);
|
|
2386
|
-
});
|
|
2387
|
-
this.processScheduler.onTaskCompleted(task.id);
|
|
2388
|
-
changed = true;
|
|
2389
|
-
}
|
|
2390
|
-
}
|
|
2391
|
-
}
|
|
2392
|
-
}
|
|
2393
|
-
taskNeedsAccumulation(task) {
|
|
2394
|
-
if (this.outputCache)
|
|
2395
|
-
return true;
|
|
2396
|
-
const outEdges = this.graph.getTargetDataflows(task.id);
|
|
2397
|
-
if (outEdges.length === 0)
|
|
2398
|
-
return this.accumulateLeafOutputs;
|
|
2399
|
-
const outSchema = task.outputSchema();
|
|
2400
|
-
for (const df of outEdges) {
|
|
2401
|
-
if (df.sourceTaskPortId === DATAFLOW_ALL_PORTS) {
|
|
2402
|
-
if (getStreamingPorts(outSchema).length > 0)
|
|
2403
|
-
return true;
|
|
2404
|
-
continue;
|
|
2405
|
-
}
|
|
2406
|
-
const targetTask = this.graph.getTask(df.targetTaskId);
|
|
2407
|
-
if (!targetTask)
|
|
2408
|
-
continue;
|
|
2409
|
-
const inSchema = targetTask.inputSchema();
|
|
2410
|
-
if (edgeNeedsAccumulation(outSchema, df.sourceTaskPortId, inSchema, df.targetTaskPortId)) {
|
|
2411
|
-
return true;
|
|
2412
|
-
}
|
|
2413
|
-
}
|
|
2414
|
-
return false;
|
|
2415
|
-
}
|
|
2416
|
-
async runTask(task, input) {
|
|
2417
|
-
const isStreamable = isTaskStreamable(task);
|
|
2418
|
-
if (isStreamable) {
|
|
2419
|
-
const dataflows = this.graph.getSourceDataflows(task.id);
|
|
2420
|
-
const streamingEdges = dataflows.filter((df) => df.stream !== undefined);
|
|
2421
|
-
if (streamingEdges.length > 0) {
|
|
2422
|
-
const inputStreams = new Map;
|
|
2423
|
-
for (const df of streamingEdges) {
|
|
2424
|
-
const stream = df.stream;
|
|
2425
|
-
const [forwardCopy, materializeCopy] = stream.tee();
|
|
2426
|
-
inputStreams.set(df.targetTaskPortId, forwardCopy);
|
|
2427
|
-
df.setStream(materializeCopy);
|
|
2428
|
-
}
|
|
2429
|
-
task.runner.inputStreams = inputStreams;
|
|
2430
|
-
}
|
|
2431
|
-
}
|
|
2432
|
-
await this.awaitStreamInputs(task);
|
|
2433
|
-
this.copyInputFromEdgesToNode(task);
|
|
2434
|
-
if (isStreamable) {
|
|
2435
|
-
return this.runStreamingTask(task, input);
|
|
2436
|
-
}
|
|
2437
|
-
const results = await task.runner.run(input, {
|
|
2438
|
-
outputCache: this.outputCache ?? false,
|
|
2439
|
-
updateProgress: async (task2, progress, message, ...args) => await this.handleProgress(task2, progress, message, ...args),
|
|
2440
|
-
registry: this.registry
|
|
2441
|
-
});
|
|
2442
|
-
await this.pushOutputFromNodeToEdges(task, results);
|
|
2443
|
-
return {
|
|
2444
|
-
id: task.id,
|
|
2445
|
-
type: task.constructor.runtype || task.constructor.type,
|
|
2446
|
-
data: results
|
|
2447
|
-
};
|
|
2448
|
-
}
|
|
2449
|
-
async awaitStreamInputs(task) {
|
|
2450
|
-
const dataflows = this.graph.getSourceDataflows(task.id);
|
|
2451
|
-
const streamPromises = dataflows.filter((df) => df.stream !== undefined).map((df) => df.awaitStreamValue());
|
|
2452
|
-
if (streamPromises.length > 0) {
|
|
2453
|
-
await Promise.all(streamPromises);
|
|
2454
|
-
}
|
|
2455
|
-
}
|
|
2456
|
-
async runStreamingTask(task, input) {
|
|
2457
|
-
const streamMode = getOutputStreamMode(task.outputSchema());
|
|
2458
|
-
const shouldAccumulate = this.taskNeedsAccumulation(task);
|
|
2459
|
-
let streamingNotified = false;
|
|
2460
|
-
const onStatus = (status) => {
|
|
2461
|
-
if (status === TaskStatus.STREAMING && !streamingNotified) {
|
|
2462
|
-
streamingNotified = true;
|
|
2463
|
-
this.pushStatusFromNodeToEdges(this.graph, task, TaskStatus.STREAMING);
|
|
2464
|
-
this.pushStreamToEdges(task, streamMode);
|
|
2465
|
-
this.processScheduler.onTaskStreaming(task.id);
|
|
2466
|
-
}
|
|
2467
|
-
};
|
|
2468
|
-
const onStreamStart = () => {
|
|
2469
|
-
this.graph.emit("task_stream_start", task.id);
|
|
2470
|
-
};
|
|
2471
|
-
const onStreamChunk = (event) => {
|
|
2472
|
-
this.graph.emit("task_stream_chunk", task.id, event);
|
|
2473
|
-
};
|
|
2474
|
-
const onStreamEnd = (output) => {
|
|
2475
|
-
this.graph.emit("task_stream_end", task.id, output);
|
|
2476
|
-
};
|
|
2477
|
-
task.on("status", onStatus);
|
|
2478
|
-
task.on("stream_start", onStreamStart);
|
|
2479
|
-
task.on("stream_chunk", onStreamChunk);
|
|
2480
|
-
task.on("stream_end", onStreamEnd);
|
|
2481
|
-
try {
|
|
2482
|
-
const results = await task.runner.run(input, {
|
|
2483
|
-
outputCache: this.outputCache ?? false,
|
|
2484
|
-
shouldAccumulate,
|
|
2485
|
-
updateProgress: async (task2, progress, message, ...args) => await this.handleProgress(task2, progress, message, ...args),
|
|
2486
|
-
registry: this.registry
|
|
2487
|
-
});
|
|
2488
|
-
await this.pushOutputFromNodeToEdges(task, results);
|
|
2489
|
-
return {
|
|
2490
|
-
id: task.id,
|
|
2491
|
-
type: task.constructor.runtype || task.constructor.type,
|
|
2492
|
-
data: results
|
|
2493
|
-
};
|
|
2494
|
-
} finally {
|
|
2495
|
-
task.off("status", onStatus);
|
|
2496
|
-
task.off("stream_start", onStreamStart);
|
|
2497
|
-
task.off("stream_chunk", onStreamChunk);
|
|
2498
|
-
task.off("stream_end", onStreamEnd);
|
|
2499
|
-
}
|
|
2500
|
-
}
|
|
2501
|
-
static isPortDelta(event) {
|
|
2502
|
-
return event.type === "text-delta" || event.type === "object-delta";
|
|
2503
|
-
}
|
|
2504
|
-
createStreamFromTaskEvents(task, portId) {
|
|
2505
|
-
return new ReadableStream({
|
|
2506
|
-
start: (controller) => {
|
|
2507
|
-
const onChunk = (event) => {
|
|
2508
|
-
try {
|
|
2509
|
-
if (portId !== undefined && TaskGraphRunner.isPortDelta(event) && event.port !== portId) {
|
|
2510
|
-
return;
|
|
2511
|
-
}
|
|
2512
|
-
controller.enqueue(event);
|
|
2513
|
-
} catch {}
|
|
2514
|
-
};
|
|
2515
|
-
const onEnd = () => {
|
|
2516
|
-
try {
|
|
2517
|
-
controller.close();
|
|
2518
|
-
} catch {}
|
|
2519
|
-
task.off("stream_chunk", onChunk);
|
|
2520
|
-
task.off("stream_end", onEnd);
|
|
2521
|
-
};
|
|
2522
|
-
task.on("stream_chunk", onChunk);
|
|
2523
|
-
task.on("stream_end", onEnd);
|
|
2524
|
-
}
|
|
2525
|
-
});
|
|
2526
|
-
}
|
|
2527
|
-
pushStreamToEdges(task, streamMode) {
|
|
2528
|
-
const targetDataflows = this.graph.getTargetDataflows(task.id);
|
|
2529
|
-
if (targetDataflows.length === 0)
|
|
2530
|
-
return;
|
|
2531
|
-
const groups = new Map;
|
|
2532
|
-
for (const df of targetDataflows) {
|
|
2533
|
-
const key = df.sourceTaskPortId;
|
|
2534
|
-
let group = groups.get(key);
|
|
2535
|
-
if (!group) {
|
|
2536
|
-
group = [];
|
|
2537
|
-
groups.set(key, group);
|
|
2538
|
-
}
|
|
2539
|
-
group.push(df);
|
|
2540
|
-
}
|
|
2541
|
-
for (const [portKey, edges] of groups) {
|
|
2542
|
-
const filterPort = portKey === DATAFLOW_ALL_PORTS ? undefined : portKey;
|
|
2543
|
-
const stream = this.createStreamFromTaskEvents(task, filterPort);
|
|
2544
|
-
if (edges.length === 1) {
|
|
2545
|
-
edges[0].setStream(stream);
|
|
2546
|
-
} else {
|
|
2547
|
-
let currentStream = stream;
|
|
2548
|
-
for (let i = 0;i < edges.length; i++) {
|
|
2549
|
-
if (i === edges.length - 1) {
|
|
2550
|
-
edges[i].setStream(currentStream);
|
|
2551
|
-
} else {
|
|
2552
|
-
const [s1, s2] = currentStream.tee();
|
|
2553
|
-
edges[i].setStream(s1);
|
|
2554
|
-
currentStream = s2;
|
|
2555
|
-
}
|
|
2556
|
-
}
|
|
2557
|
-
}
|
|
2558
|
-
}
|
|
2559
|
-
}
|
|
2560
|
-
resetTask(graph, task, runId) {
|
|
2561
|
-
task.status = TaskStatus.PENDING;
|
|
2562
|
-
task.resetInputData();
|
|
2563
|
-
task.runOutputData = {};
|
|
2564
|
-
task.error = undefined;
|
|
2565
|
-
task.progress = 0;
|
|
2566
|
-
task.runConfig = { ...task.runConfig, runnerId: runId };
|
|
2567
|
-
this.pushStatusFromNodeToEdges(graph, task);
|
|
2568
|
-
this.pushErrorFromNodeToEdges(graph, task);
|
|
2569
|
-
task.emit("reset");
|
|
2570
|
-
task.emit("status", task.status);
|
|
2571
|
-
}
|
|
2572
|
-
resetGraph(graph, runnerId) {
|
|
2573
|
-
graph.getTasks().forEach((node) => {
|
|
2574
|
-
this.resetTask(graph, node, runnerId);
|
|
2575
|
-
node.regenerateGraph();
|
|
2576
|
-
if (node.hasChildren()) {
|
|
2577
|
-
this.resetGraph(node.subGraph, runnerId);
|
|
2578
|
-
}
|
|
2579
|
-
});
|
|
2580
|
-
graph.getDataflows().forEach((dataflow) => {
|
|
2581
|
-
dataflow.reset();
|
|
2582
|
-
});
|
|
2583
|
-
}
|
|
2584
|
-
async handleStart(config) {
|
|
2585
|
-
if (config?.registry !== undefined) {
|
|
2586
|
-
this.registry = config.registry;
|
|
2587
|
-
} else if (this.registry === undefined) {
|
|
2588
|
-
this.registry = new ServiceRegistry2(globalServiceRegistry2.container.createChildContainer());
|
|
2589
|
-
}
|
|
2590
|
-
this.accumulateLeafOutputs = config?.accumulateLeafOutputs !== false;
|
|
2591
|
-
if (config?.outputCache !== undefined) {
|
|
2592
|
-
if (typeof config.outputCache === "boolean") {
|
|
2593
|
-
if (config.outputCache === true) {
|
|
2594
|
-
this.outputCache = this.registry.get(TASK_OUTPUT_REPOSITORY);
|
|
2595
|
-
} else {
|
|
2596
|
-
this.outputCache = undefined;
|
|
2597
|
-
}
|
|
2598
|
-
} else {
|
|
2599
|
-
this.outputCache = config.outputCache;
|
|
2600
|
-
}
|
|
2601
|
-
this.graph.outputCache = this.outputCache;
|
|
2602
|
-
}
|
|
2603
|
-
if (this.running || this.reactiveRunning) {
|
|
2604
|
-
throw new TaskConfigurationError("Graph is already running");
|
|
2605
|
-
}
|
|
2606
|
-
this.running = true;
|
|
2607
|
-
this.abortController = new AbortController;
|
|
2608
|
-
this.abortController.signal.addEventListener("abort", () => {
|
|
2609
|
-
this.handleAbort();
|
|
2610
|
-
});
|
|
2611
|
-
if (config?.parentSignal?.aborted) {
|
|
2612
|
-
this.abortController.abort();
|
|
2613
|
-
return;
|
|
2614
|
-
} else {
|
|
2615
|
-
config?.parentSignal?.addEventListener("abort", () => {
|
|
2616
|
-
this.abortController?.abort();
|
|
2617
|
-
}, { once: true });
|
|
2618
|
-
}
|
|
2619
|
-
this.runId = uuid43();
|
|
2620
|
-
this.resetGraph(this.graph, this.runId);
|
|
2621
|
-
this.processScheduler.reset();
|
|
2622
|
-
this.inProgressTasks.clear();
|
|
2623
|
-
this.inProgressFunctions.clear();
|
|
2624
|
-
this.failedTaskErrors.clear();
|
|
2625
|
-
const logger = getLogger3();
|
|
2626
|
-
logger.group(this.timerLabel, { graph: this.graph });
|
|
2627
|
-
logger.time(this.timerLabel);
|
|
2628
|
-
this.graph.emit("start");
|
|
2629
|
-
}
|
|
2630
|
-
async handleStartReactive(config) {
|
|
2631
|
-
if (this.reactiveRunning) {
|
|
2632
|
-
throw new TaskConfigurationError("Graph is already running reactively");
|
|
2633
|
-
}
|
|
2634
|
-
if (config?.registry !== undefined) {
|
|
2635
|
-
this.registry = config.registry;
|
|
2636
|
-
}
|
|
2637
|
-
this.reactiveScheduler.reset();
|
|
2638
|
-
this.reactiveRunning = true;
|
|
2639
|
-
}
|
|
2640
|
-
async handleComplete() {
|
|
2641
|
-
this.running = false;
|
|
2642
|
-
const logger = getLogger3();
|
|
2643
|
-
logger.timeEnd(this.timerLabel);
|
|
2644
|
-
logger.groupEnd();
|
|
2645
|
-
this.graph.emit("complete");
|
|
2646
|
-
}
|
|
2647
|
-
async handleCompleteReactive() {
|
|
2648
|
-
this.reactiveRunning = false;
|
|
2649
|
-
}
|
|
2650
|
-
async handleError(error) {
|
|
2651
|
-
await Promise.allSettled(this.graph.getTasks().map(async (task) => {
|
|
2652
|
-
if (task.status === TaskStatus.PROCESSING || task.status === TaskStatus.STREAMING) {
|
|
2653
|
-
task.abort();
|
|
2654
|
-
}
|
|
2655
|
-
}));
|
|
2656
|
-
this.running = false;
|
|
2657
|
-
const logger = getLogger3();
|
|
2658
|
-
logger.timeEnd(this.timerLabel);
|
|
2659
|
-
logger.groupEnd();
|
|
2660
|
-
this.graph.emit("error", error);
|
|
2661
|
-
}
|
|
2662
|
-
async handleErrorReactive() {
|
|
2663
|
-
this.reactiveRunning = false;
|
|
2664
|
-
}
|
|
2665
|
-
async handleAbort() {
|
|
2666
|
-
this.graph.getTasks().map(async (task) => {
|
|
2667
|
-
if (task.status === TaskStatus.PROCESSING || task.status === TaskStatus.STREAMING) {
|
|
2668
|
-
task.abort();
|
|
2669
|
-
}
|
|
2670
|
-
});
|
|
2671
|
-
this.running = false;
|
|
2672
|
-
const logger = getLogger3();
|
|
2673
|
-
logger.timeEnd(this.timerLabel);
|
|
2674
|
-
logger.groupEnd();
|
|
2675
|
-
this.graph.emit("abort");
|
|
2676
|
-
}
|
|
2677
|
-
async handleAbortReactive() {
|
|
2678
|
-
this.reactiveRunning = false;
|
|
2679
|
-
}
|
|
2680
|
-
async handleDisable() {
|
|
2681
|
-
await Promise.allSettled(this.graph.getTasks().map(async (task) => {
|
|
2682
|
-
if (task.status === TaskStatus.PENDING) {
|
|
2683
|
-
return task.disable();
|
|
2684
|
-
}
|
|
2685
|
-
}));
|
|
2686
|
-
this.running = false;
|
|
2687
|
-
this.graph.emit("disabled");
|
|
2688
|
-
}
|
|
2689
|
-
async handleProgress(task, progress, message, ...args) {
|
|
2690
|
-
const total = this.graph.getTasks().length;
|
|
2691
|
-
if (total > 1) {
|
|
2692
|
-
const completed = this.graph.getTasks().reduce((acc, t) => acc + t.progress, 0);
|
|
2693
|
-
progress = Math.round(completed / total);
|
|
2694
|
-
}
|
|
2695
|
-
this.pushStatusFromNodeToEdges(this.graph, task);
|
|
2696
|
-
await this.pushOutputFromNodeToEdges(task, task.runOutputData);
|
|
2697
|
-
this.graph.emit("graph_progress", progress, message, args);
|
|
2698
|
-
}
|
|
2699
|
-
}
|
|
2700
|
-
|
|
2701
|
-
// src/task/GraphAsTaskRunner.ts
|
|
2702
|
-
class GraphAsTaskRunner extends TaskRunner {
|
|
2703
|
-
async executeTaskChildren(input) {
|
|
2704
|
-
const unsubscribe = this.task.subGraph.subscribe("graph_progress", (progress, message, ...args) => {
|
|
2705
|
-
this.task.emit("progress", progress, message, ...args);
|
|
2706
|
-
});
|
|
2707
|
-
const results = await this.task.subGraph.run(input, {
|
|
2708
|
-
parentSignal: this.abortController?.signal,
|
|
2709
|
-
outputCache: this.outputCache
|
|
2710
|
-
});
|
|
2711
|
-
unsubscribe();
|
|
2712
|
-
return results;
|
|
2713
|
-
}
|
|
2714
|
-
async executeTaskChildrenReactive() {
|
|
2715
|
-
return this.task.subGraph.runReactive(this.task.runInputData);
|
|
2716
|
-
}
|
|
2717
|
-
async handleDisable() {
|
|
2718
|
-
if (this.task.hasChildren()) {
|
|
2719
|
-
await this.task.subGraph.disable();
|
|
2720
|
-
}
|
|
2721
|
-
super.handleDisable();
|
|
2722
|
-
}
|
|
2723
|
-
async executeTask(input) {
|
|
2724
|
-
if (this.task.hasChildren()) {
|
|
2725
|
-
const runExecuteOutputData = await this.executeTaskChildren(input);
|
|
2726
|
-
this.task.runOutputData = this.task.subGraph.mergeExecuteOutputsToRunOutput(runExecuteOutputData, this.task.compoundMerge);
|
|
2727
|
-
} else {
|
|
2728
|
-
const result = await super.executeTask(input);
|
|
2729
|
-
this.task.runOutputData = result ?? {};
|
|
2730
|
-
}
|
|
2731
|
-
return this.task.runOutputData;
|
|
2732
|
-
}
|
|
2733
|
-
async executeTaskReactive(input, output) {
|
|
2734
|
-
if (this.task.hasChildren()) {
|
|
2735
|
-
const reactiveResults = await this.executeTaskChildrenReactive();
|
|
2736
|
-
this.task.runOutputData = this.task.subGraph.mergeExecuteOutputsToRunOutput(reactiveResults, this.task.compoundMerge);
|
|
2737
|
-
} else {
|
|
2738
|
-
const reactiveResults = await super.executeTaskReactive(input, output);
|
|
2739
|
-
this.task.runOutputData = Object.assign({}, output, reactiveResults ?? {});
|
|
2740
|
-
}
|
|
2741
|
-
return this.task.runOutputData;
|
|
2742
|
-
}
|
|
2743
|
-
}
|
|
2744
|
-
|
|
2745
|
-
// src/task/GraphAsTask.ts
|
|
2746
|
-
var graphAsTaskConfigSchema = {
|
|
2747
|
-
type: "object",
|
|
2748
|
-
properties: {
|
|
2749
|
-
...TaskConfigSchema["properties"],
|
|
2750
|
-
compoundMerge: { type: "string", "x-ui-hidden": true }
|
|
2751
|
-
},
|
|
2752
|
-
additionalProperties: false
|
|
2753
|
-
};
|
|
2754
|
-
|
|
2755
|
-
class GraphAsTask extends Task {
|
|
2756
|
-
static type = "GraphAsTask";
|
|
2757
|
-
static title = "Group";
|
|
2758
|
-
static description = "A group of tasks that are executed together";
|
|
2759
|
-
static category = "Flow Control";
|
|
2760
|
-
static compoundMerge = PROPERTY_ARRAY;
|
|
2761
|
-
static hasDynamicSchemas = true;
|
|
2762
|
-
constructor(input = {}, config = {}) {
|
|
2763
|
-
const { subGraph, ...rest } = config;
|
|
2764
|
-
super(input, rest);
|
|
2765
|
-
if (subGraph) {
|
|
2766
|
-
this.subGraph = subGraph;
|
|
2767
|
-
}
|
|
2768
|
-
this.regenerateGraph();
|
|
2769
|
-
}
|
|
2770
|
-
get runner() {
|
|
2771
|
-
if (!this._runner) {
|
|
2772
|
-
this._runner = new GraphAsTaskRunner(this);
|
|
2773
|
-
}
|
|
2774
|
-
return this._runner;
|
|
2775
|
-
}
|
|
2776
|
-
static configSchema() {
|
|
2777
|
-
return graphAsTaskConfigSchema;
|
|
2778
|
-
}
|
|
2779
|
-
get compoundMerge() {
|
|
2780
|
-
return this.config?.compoundMerge || this.constructor.compoundMerge;
|
|
2781
|
-
}
|
|
2782
|
-
get cacheable() {
|
|
2783
|
-
return this.runConfig?.cacheable ?? this.config?.cacheable ?? (this.constructor.cacheable && !this.hasChildren());
|
|
2784
|
-
}
|
|
2785
|
-
inputSchema() {
|
|
2786
|
-
if (!this.hasChildren()) {
|
|
2787
|
-
return this.constructor.inputSchema();
|
|
2788
|
-
}
|
|
2789
|
-
return computeGraphInputSchema(this.subGraph);
|
|
2790
|
-
}
|
|
2791
|
-
_inputSchemaNode;
|
|
2792
|
-
getInputSchemaNode() {
|
|
2793
|
-
if (!this._inputSchemaNode) {
|
|
2794
|
-
try {
|
|
2795
|
-
const dataPortSchema = this.inputSchema();
|
|
2796
|
-
const schemaNode = Task.generateInputSchemaNode(dataPortSchema);
|
|
2797
|
-
this._inputSchemaNode = schemaNode;
|
|
2798
|
-
} catch (error) {
|
|
2799
|
-
console.warn(`Failed to compile input schema for ${this.type}, falling back to permissive validation:`, error);
|
|
2800
|
-
this._inputSchemaNode = compileSchema2({});
|
|
2801
|
-
}
|
|
2802
|
-
}
|
|
2803
|
-
return this._inputSchemaNode;
|
|
2804
|
-
}
|
|
2805
|
-
outputSchema() {
|
|
2806
|
-
if (!this.hasChildren()) {
|
|
2807
|
-
return this.constructor.outputSchema();
|
|
2808
|
-
}
|
|
2809
|
-
return computeGraphOutputSchema(this.subGraph);
|
|
2810
|
-
}
|
|
2811
|
-
resetInputData() {
|
|
2812
|
-
super.resetInputData();
|
|
2813
|
-
if (this.hasChildren()) {
|
|
2814
|
-
this.subGraph.getTasks().forEach((node) => {
|
|
2815
|
-
node.resetInputData();
|
|
2816
|
-
});
|
|
2817
|
-
this.subGraph.getDataflows().forEach((dataflow) => {
|
|
2818
|
-
dataflow.reset();
|
|
2819
|
-
});
|
|
2820
|
-
}
|
|
2821
|
-
}
|
|
2822
|
-
async* executeStream(input, context) {
|
|
2823
|
-
if (context.inputStreams) {
|
|
2824
|
-
for (const [, stream] of context.inputStreams) {
|
|
2825
|
-
const reader = stream.getReader();
|
|
2826
|
-
try {
|
|
2827
|
-
while (true) {
|
|
2828
|
-
const { done, value } = await reader.read();
|
|
2829
|
-
if (done)
|
|
2830
|
-
break;
|
|
2831
|
-
if (value.type === "finish")
|
|
2832
|
-
continue;
|
|
2833
|
-
yield value;
|
|
2834
|
-
}
|
|
2835
|
-
} finally {
|
|
2836
|
-
reader.releaseLock();
|
|
2837
|
-
}
|
|
2838
|
-
}
|
|
2839
|
-
}
|
|
2840
|
-
if (this.hasChildren()) {
|
|
2841
|
-
const endingNodeIds = new Set;
|
|
2842
|
-
const tasks = this.subGraph.getTasks();
|
|
2843
|
-
for (const task of tasks) {
|
|
2844
|
-
if (this.subGraph.getTargetDataflows(task.id).length === 0) {
|
|
2845
|
-
endingNodeIds.add(task.id);
|
|
2846
|
-
}
|
|
2847
|
-
}
|
|
2848
|
-
const eventQueue = [];
|
|
2849
|
-
let resolveWaiting;
|
|
2850
|
-
let subgraphDone = false;
|
|
2851
|
-
const unsub = this.subGraph.subscribeToTaskStreaming({
|
|
2852
|
-
onStreamChunk: (taskId, event) => {
|
|
2853
|
-
if (endingNodeIds.has(taskId) && event.type !== "finish") {
|
|
2854
|
-
eventQueue.push(event);
|
|
2855
|
-
resolveWaiting?.();
|
|
2856
|
-
}
|
|
2857
|
-
}
|
|
2858
|
-
});
|
|
2859
|
-
const runPromise = this.subGraph.run(input, { parentSignal: context.signal, accumulateLeafOutputs: false }).then((results2) => {
|
|
2860
|
-
subgraphDone = true;
|
|
2861
|
-
resolveWaiting?.();
|
|
2862
|
-
return results2;
|
|
2863
|
-
});
|
|
2864
|
-
while (!subgraphDone) {
|
|
2865
|
-
if (eventQueue.length === 0) {
|
|
2866
|
-
await new Promise((resolve) => {
|
|
2867
|
-
resolveWaiting = resolve;
|
|
2868
|
-
});
|
|
2869
|
-
}
|
|
2870
|
-
while (eventQueue.length > 0) {
|
|
2871
|
-
yield eventQueue.shift();
|
|
2872
|
-
}
|
|
2873
|
-
}
|
|
2874
|
-
while (eventQueue.length > 0) {
|
|
2875
|
-
yield eventQueue.shift();
|
|
2876
|
-
}
|
|
2877
|
-
unsub();
|
|
2878
|
-
const results = await runPromise;
|
|
2879
|
-
const mergedOutput = this.subGraph.mergeExecuteOutputsToRunOutput(results, this.compoundMerge);
|
|
2880
|
-
yield { type: "finish", data: mergedOutput };
|
|
2881
|
-
} else {
|
|
2882
|
-
yield { type: "finish", data: input };
|
|
2883
|
-
}
|
|
2884
|
-
}
|
|
2885
|
-
regenerateGraph() {
|
|
2886
|
-
this._inputSchemaNode = undefined;
|
|
2887
|
-
this.events.emit("regenerate");
|
|
2888
|
-
}
|
|
2889
|
-
toJSON(options) {
|
|
2890
|
-
let json = super.toJSON(options);
|
|
2891
|
-
const hasChildren = this.hasChildren();
|
|
2892
|
-
if (hasChildren) {
|
|
2893
|
-
json = {
|
|
2894
|
-
...json,
|
|
2895
|
-
merge: this.compoundMerge,
|
|
2896
|
-
subgraph: this.subGraph.toJSON(options)
|
|
2897
|
-
};
|
|
2898
|
-
}
|
|
2899
|
-
return json;
|
|
2900
|
-
}
|
|
2901
|
-
toDependencyJSON(options) {
|
|
2902
|
-
const json = this.toJSON(options);
|
|
2903
|
-
if (this.hasChildren()) {
|
|
2904
|
-
if ("subgraph" in json) {
|
|
2905
|
-
delete json.subgraph;
|
|
2906
|
-
}
|
|
2907
|
-
return { ...json, subtasks: this.subGraph.toDependencyJSON(options) };
|
|
2908
|
-
}
|
|
2909
|
-
return json;
|
|
2910
|
-
}
|
|
2911
|
-
}
|
|
2912
|
-
|
|
2913
|
-
// src/task-graph/Workflow.ts
|
|
2914
2
|
import {
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
get isLoopBuilder() {
|
|
3012
|
-
return this._parentWorkflow !== undefined;
|
|
3013
|
-
}
|
|
3014
|
-
events = new EventEmitter4;
|
|
3015
|
-
static createWorkflow(taskClass) {
|
|
3016
|
-
const helper = function(input = {}, config = {}) {
|
|
3017
|
-
this._error = "";
|
|
3018
|
-
const parent = getLastTask(this);
|
|
3019
|
-
const task = this.addTaskToGraph(taskClass, input, { id: uuid44(), ...config });
|
|
3020
|
-
if (this._dataFlows.length > 0) {
|
|
3021
|
-
this._dataFlows.forEach((dataflow) => {
|
|
3022
|
-
const taskSchema = task.inputSchema();
|
|
3023
|
-
if (typeof taskSchema !== "boolean" && taskSchema.properties?.[dataflow.targetTaskPortId] === undefined && taskSchema.additionalProperties !== true || taskSchema === true && dataflow.targetTaskPortId !== DATAFLOW_ALL_PORTS) {
|
|
3024
|
-
this._error = `Input ${dataflow.targetTaskPortId} not found on task ${task.id}`;
|
|
3025
|
-
getLogger4().error(this._error);
|
|
3026
|
-
return;
|
|
3027
|
-
}
|
|
3028
|
-
dataflow.targetTaskId = task.id;
|
|
3029
|
-
this.graph.addDataflow(dataflow);
|
|
3030
|
-
});
|
|
3031
|
-
this._dataFlows = [];
|
|
3032
|
-
}
|
|
3033
|
-
if (parent) {
|
|
3034
|
-
const nodes = this._graph.getTasks();
|
|
3035
|
-
const parentIndex = nodes.findIndex((n) => n.id === parent.id);
|
|
3036
|
-
const earlierTasks = [];
|
|
3037
|
-
for (let i = parentIndex - 1;i >= 0; i--) {
|
|
3038
|
-
earlierTasks.push(nodes[i]);
|
|
3039
|
-
}
|
|
3040
|
-
const providedInputKeys = new Set(Object.keys(input || {}));
|
|
3041
|
-
const connectedInputKeys = new Set(this.graph.getSourceDataflows(task.id).map((df) => df.targetTaskPortId));
|
|
3042
|
-
const result = Workflow.autoConnect(this.graph, parent, task, {
|
|
3043
|
-
providedInputKeys,
|
|
3044
|
-
connectedInputKeys,
|
|
3045
|
-
earlierTasks
|
|
3046
|
-
});
|
|
3047
|
-
if (result.error) {
|
|
3048
|
-
if (this.isLoopBuilder) {
|
|
3049
|
-
this._error = result.error;
|
|
3050
|
-
getLogger4().warn(this._error);
|
|
3051
|
-
} else {
|
|
3052
|
-
this._error = result.error + " Task not added.";
|
|
3053
|
-
getLogger4().error(this._error);
|
|
3054
|
-
this.graph.removeTask(task.id);
|
|
3055
|
-
}
|
|
3056
|
-
}
|
|
3057
|
-
}
|
|
3058
|
-
if (!this._error) {
|
|
3059
|
-
Workflow.updateBoundaryTaskSchemas(this._graph);
|
|
3060
|
-
}
|
|
3061
|
-
return this;
|
|
3062
|
-
};
|
|
3063
|
-
helper.type = taskClass.runtype ?? taskClass.type;
|
|
3064
|
-
helper.category = taskClass.category;
|
|
3065
|
-
helper.inputSchema = taskClass.inputSchema;
|
|
3066
|
-
helper.outputSchema = taskClass.outputSchema;
|
|
3067
|
-
helper.cacheable = taskClass.cacheable;
|
|
3068
|
-
helper.workflowCreate = true;
|
|
3069
|
-
return helper;
|
|
3070
|
-
}
|
|
3071
|
-
get graph() {
|
|
3072
|
-
return this._graph;
|
|
3073
|
-
}
|
|
3074
|
-
set graph(value) {
|
|
3075
|
-
this._dataFlows = [];
|
|
3076
|
-
this._error = "";
|
|
3077
|
-
this.clearEvents();
|
|
3078
|
-
this._graph = value;
|
|
3079
|
-
this.setupEvents();
|
|
3080
|
-
this.events.emit("reset");
|
|
3081
|
-
}
|
|
3082
|
-
get error() {
|
|
3083
|
-
return this._error;
|
|
3084
|
-
}
|
|
3085
|
-
on(name, fn) {
|
|
3086
|
-
this.events.on(name, fn);
|
|
3087
|
-
}
|
|
3088
|
-
off(name, fn) {
|
|
3089
|
-
this.events.off(name, fn);
|
|
3090
|
-
}
|
|
3091
|
-
once(name, fn) {
|
|
3092
|
-
this.events.once(name, fn);
|
|
3093
|
-
}
|
|
3094
|
-
waitOn(name) {
|
|
3095
|
-
return this.events.waitOn(name);
|
|
3096
|
-
}
|
|
3097
|
-
async run(input = {}) {
|
|
3098
|
-
if (this.isLoopBuilder) {
|
|
3099
|
-
this.finalizeTemplate();
|
|
3100
|
-
if (this._pendingLoopConnect) {
|
|
3101
|
-
this._parentWorkflow.autoConnectLoopTask(this._pendingLoopConnect);
|
|
3102
|
-
this._pendingLoopConnect = undefined;
|
|
3103
|
-
}
|
|
3104
|
-
return this._parentWorkflow.run(input);
|
|
3105
|
-
}
|
|
3106
|
-
this.events.emit("start");
|
|
3107
|
-
this._abortController = new AbortController;
|
|
3108
|
-
const unsubStreaming = this.graph.subscribeToTaskStreaming({
|
|
3109
|
-
onStreamStart: (taskId) => this.events.emit("stream_start", taskId),
|
|
3110
|
-
onStreamChunk: (taskId, event) => this.events.emit("stream_chunk", taskId, event),
|
|
3111
|
-
onStreamEnd: (taskId, output) => this.events.emit("stream_end", taskId, output)
|
|
3112
|
-
});
|
|
3
|
+
ConditionalTask,
|
|
4
|
+
CreateAdaptiveWorkflow,
|
|
5
|
+
CreateEndLoopWorkflow,
|
|
6
|
+
CreateLoopWorkflow,
|
|
7
|
+
CreateWorkflow,
|
|
8
|
+
DATAFLOW_ALL_PORTS,
|
|
9
|
+
DATAFLOW_ERROR_PORT,
|
|
10
|
+
Dataflow,
|
|
11
|
+
DataflowArrow,
|
|
12
|
+
EventDagToTaskGraphMapping,
|
|
13
|
+
EventTaskGraphToDagMapping,
|
|
14
|
+
GRAPH_RESULT_ARRAY,
|
|
15
|
+
GraphAsTask,
|
|
16
|
+
GraphAsTaskRunner,
|
|
17
|
+
JobTaskFailedError,
|
|
18
|
+
PROPERTY_ARRAY,
|
|
19
|
+
TASK_OUTPUT_REPOSITORY,
|
|
20
|
+
Task,
|
|
21
|
+
TaskAbortedError,
|
|
22
|
+
TaskConfigSchema,
|
|
23
|
+
TaskConfigurationError,
|
|
24
|
+
TaskError,
|
|
25
|
+
TaskFailedError,
|
|
26
|
+
TaskGraph,
|
|
27
|
+
TaskGraphRunner,
|
|
28
|
+
TaskInvalidInputError,
|
|
29
|
+
TaskJSONError,
|
|
30
|
+
TaskOutputRepository,
|
|
31
|
+
TaskStatus,
|
|
32
|
+
TaskTimeoutError,
|
|
33
|
+
Workflow,
|
|
34
|
+
WorkflowError,
|
|
35
|
+
__require,
|
|
36
|
+
addBoundaryNodesToDependencyJson,
|
|
37
|
+
addBoundaryNodesToGraphJson,
|
|
38
|
+
calculateNodeDepths,
|
|
39
|
+
computeGraphInputSchema,
|
|
40
|
+
computeGraphOutputSchema,
|
|
41
|
+
conditionalTaskConfigSchema,
|
|
42
|
+
connect,
|
|
43
|
+
edgeNeedsAccumulation,
|
|
44
|
+
ensureTask,
|
|
45
|
+
evaluateCondition,
|
|
46
|
+
getAppendPortId,
|
|
47
|
+
getLastTask,
|
|
48
|
+
getNestedValue,
|
|
49
|
+
getObjectPortId,
|
|
50
|
+
getOutputStreamMode,
|
|
51
|
+
getPortStreamMode,
|
|
52
|
+
getStreamingPorts,
|
|
53
|
+
getStructuredOutputSchemas,
|
|
54
|
+
graphAsTaskConfigSchema,
|
|
55
|
+
hasStructuredOutput,
|
|
56
|
+
hasVectorLikeInput,
|
|
57
|
+
hasVectorOutput,
|
|
58
|
+
init_ConditionUtils,
|
|
59
|
+
init_ConditionalTask,
|
|
60
|
+
init_Conversions,
|
|
61
|
+
init_Dataflow,
|
|
62
|
+
init_GraphAsTask,
|
|
63
|
+
init_GraphAsTaskRunner,
|
|
64
|
+
init_GraphSchemaUtils,
|
|
65
|
+
init_InputResolver,
|
|
66
|
+
init_StreamTypes,
|
|
67
|
+
init_Task,
|
|
68
|
+
init_TaskError,
|
|
69
|
+
init_TaskGraph,
|
|
70
|
+
init_TaskGraphEvents,
|
|
71
|
+
init_TaskGraphRunner,
|
|
72
|
+
init_TaskOutputRepository,
|
|
73
|
+
init_TaskTypes,
|
|
74
|
+
init_Workflow,
|
|
75
|
+
isTaskStreamable,
|
|
76
|
+
parallel,
|
|
77
|
+
pipe,
|
|
78
|
+
resolveSchemaInputs,
|
|
79
|
+
serialGraph
|
|
80
|
+
} from "./bun-tgs39x49.js";
|
|
81
|
+
|
|
82
|
+
// src/common.ts
|
|
83
|
+
init_Dataflow();
|
|
84
|
+
init_GraphSchemaUtils();
|
|
85
|
+
init_TaskGraph();
|
|
86
|
+
init_TaskGraphEvents();
|
|
87
|
+
init_TaskGraphRunner();
|
|
88
|
+
init_Conversions();
|
|
89
|
+
|
|
90
|
+
// src/task-graph/GraphToWorkflowCode.ts
|
|
91
|
+
init_Dataflow();
|
|
92
|
+
init_Workflow();
|
|
93
|
+
var methodNameCache;
|
|
94
|
+
function getMethodNameMap() {
|
|
95
|
+
if (methodNameCache)
|
|
96
|
+
return methodNameCache;
|
|
97
|
+
methodNameCache = new Map;
|
|
98
|
+
for (const key of Object.getOwnPropertyNames(Workflow.prototype)) {
|
|
3113
99
|
try {
|
|
3114
|
-
const
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
});
|
|
3118
|
-
const results = this.graph.mergeExecuteOutputsToRunOutput(output, PROPERTY_ARRAY);
|
|
3119
|
-
this.events.emit("complete");
|
|
3120
|
-
return results;
|
|
3121
|
-
} catch (error) {
|
|
3122
|
-
this.events.emit("error", String(error));
|
|
3123
|
-
throw error;
|
|
3124
|
-
} finally {
|
|
3125
|
-
unsubStreaming();
|
|
3126
|
-
this._abortController = undefined;
|
|
3127
|
-
}
|
|
3128
|
-
}
|
|
3129
|
-
async abort() {
|
|
3130
|
-
if (this._parentWorkflow) {
|
|
3131
|
-
return this._parentWorkflow.abort();
|
|
3132
|
-
}
|
|
3133
|
-
this._abortController?.abort();
|
|
3134
|
-
}
|
|
3135
|
-
pop() {
|
|
3136
|
-
this._error = "";
|
|
3137
|
-
const nodes = this._graph.getTasks();
|
|
3138
|
-
if (nodes.length === 0) {
|
|
3139
|
-
this._error = "No tasks to remove";
|
|
3140
|
-
getLogger4().error(this._error);
|
|
3141
|
-
return this;
|
|
3142
|
-
}
|
|
3143
|
-
const lastNode = nodes[nodes.length - 1];
|
|
3144
|
-
this._graph.removeTask(lastNode.id);
|
|
3145
|
-
return this;
|
|
3146
|
-
}
|
|
3147
|
-
toJSON(options = { withBoundaryNodes: true }) {
|
|
3148
|
-
return this._graph.toJSON(options);
|
|
3149
|
-
}
|
|
3150
|
-
toDependencyJSON(options = { withBoundaryNodes: true }) {
|
|
3151
|
-
return this._graph.toDependencyJSON(options);
|
|
3152
|
-
}
|
|
3153
|
-
pipe(...args) {
|
|
3154
|
-
return pipe(args, this);
|
|
3155
|
-
}
|
|
3156
|
-
static pipe(...args) {
|
|
3157
|
-
return pipe(args, new Workflow);
|
|
3158
|
-
}
|
|
3159
|
-
parallel(args, mergeFn) {
|
|
3160
|
-
return parallel(args, mergeFn ?? PROPERTY_ARRAY, this);
|
|
3161
|
-
}
|
|
3162
|
-
static parallel(args, mergeFn) {
|
|
3163
|
-
return parallel(args, mergeFn ?? PROPERTY_ARRAY, new Workflow);
|
|
3164
|
-
}
|
|
3165
|
-
rename(source, target, index = -1) {
|
|
3166
|
-
this._error = "";
|
|
3167
|
-
const nodes = this._graph.getTasks();
|
|
3168
|
-
if (-index > nodes.length) {
|
|
3169
|
-
const errorMsg = `Back index greater than number of tasks`;
|
|
3170
|
-
this._error = errorMsg;
|
|
3171
|
-
getLogger4().error(this._error);
|
|
3172
|
-
throw new WorkflowError(errorMsg);
|
|
3173
|
-
}
|
|
3174
|
-
const lastNode = nodes[nodes.length + index];
|
|
3175
|
-
const outputSchema = lastNode.outputSchema();
|
|
3176
|
-
if (typeof outputSchema === "boolean") {
|
|
3177
|
-
if (outputSchema === false && source !== DATAFLOW_ALL_PORTS) {
|
|
3178
|
-
const errorMsg = `Task ${lastNode.id} has schema 'false' and outputs nothing`;
|
|
3179
|
-
this._error = errorMsg;
|
|
3180
|
-
getLogger4().error(this._error);
|
|
3181
|
-
throw new WorkflowError(errorMsg);
|
|
3182
|
-
}
|
|
3183
|
-
} else if (!outputSchema.properties?.[source] && source !== DATAFLOW_ALL_PORTS) {
|
|
3184
|
-
const errorMsg = `Output ${source} not found on task ${lastNode.id}`;
|
|
3185
|
-
this._error = errorMsg;
|
|
3186
|
-
getLogger4().error(this._error);
|
|
3187
|
-
throw new WorkflowError(errorMsg);
|
|
3188
|
-
}
|
|
3189
|
-
this._dataFlows.push(new Dataflow(lastNode.id, source, undefined, target));
|
|
3190
|
-
return this;
|
|
3191
|
-
}
|
|
3192
|
-
onError(handler) {
|
|
3193
|
-
this._error = "";
|
|
3194
|
-
const parent = getLastTask(this);
|
|
3195
|
-
if (!parent) {
|
|
3196
|
-
this._error = "onError() requires a preceding task in the workflow";
|
|
3197
|
-
getLogger4().error(this._error);
|
|
3198
|
-
throw new WorkflowError(this._error);
|
|
3199
|
-
}
|
|
3200
|
-
const handlerTask = ensureTask(handler);
|
|
3201
|
-
this.graph.addTask(handlerTask);
|
|
3202
|
-
const dataflow = new Dataflow(parent.id, DATAFLOW_ERROR_PORT, handlerTask.id, DATAFLOW_ALL_PORTS);
|
|
3203
|
-
this.graph.addDataflow(dataflow);
|
|
3204
|
-
this.events.emit("changed", handlerTask.id);
|
|
3205
|
-
return this;
|
|
3206
|
-
}
|
|
3207
|
-
toTaskGraph() {
|
|
3208
|
-
return this._graph;
|
|
3209
|
-
}
|
|
3210
|
-
toTask() {
|
|
3211
|
-
const task = new WorkflowTask;
|
|
3212
|
-
task.subGraph = this.toTaskGraph();
|
|
3213
|
-
return task;
|
|
3214
|
-
}
|
|
3215
|
-
reset() {
|
|
3216
|
-
if (this._parentWorkflow) {
|
|
3217
|
-
throw new WorkflowError("Cannot reset a loop workflow. Call reset() on the parent workflow.");
|
|
3218
|
-
}
|
|
3219
|
-
this.clearEvents();
|
|
3220
|
-
this._graph = new TaskGraph({
|
|
3221
|
-
outputCache: this._outputCache
|
|
3222
|
-
});
|
|
3223
|
-
this._dataFlows = [];
|
|
3224
|
-
this._error = "";
|
|
3225
|
-
this.setupEvents();
|
|
3226
|
-
this.events.emit("changed", undefined);
|
|
3227
|
-
this.events.emit("reset");
|
|
3228
|
-
return this;
|
|
3229
|
-
}
|
|
3230
|
-
setupEvents() {
|
|
3231
|
-
this._graph.on("task_added", this._onChanged);
|
|
3232
|
-
this._graph.on("task_replaced", this._onChanged);
|
|
3233
|
-
this._graph.on("task_removed", this._onChanged);
|
|
3234
|
-
this._graph.on("dataflow_added", this._onChanged);
|
|
3235
|
-
this._graph.on("dataflow_replaced", this._onChanged);
|
|
3236
|
-
this._graph.on("dataflow_removed", this._onChanged);
|
|
3237
|
-
}
|
|
3238
|
-
clearEvents() {
|
|
3239
|
-
this._graph.off("task_added", this._onChanged);
|
|
3240
|
-
this._graph.off("task_replaced", this._onChanged);
|
|
3241
|
-
this._graph.off("task_removed", this._onChanged);
|
|
3242
|
-
this._graph.off("dataflow_added", this._onChanged);
|
|
3243
|
-
this._graph.off("dataflow_replaced", this._onChanged);
|
|
3244
|
-
this._graph.off("dataflow_removed", this._onChanged);
|
|
3245
|
-
}
|
|
3246
|
-
_onChanged(id) {
|
|
3247
|
-
this.events.emit("changed", id);
|
|
3248
|
-
}
|
|
3249
|
-
connect(sourceTaskId, sourceTaskPortId, targetTaskId, targetTaskPortId) {
|
|
3250
|
-
const sourceTask = this.graph.getTask(sourceTaskId);
|
|
3251
|
-
const targetTask = this.graph.getTask(targetTaskId);
|
|
3252
|
-
if (!sourceTask || !targetTask) {
|
|
3253
|
-
throw new WorkflowError("Source or target task not found");
|
|
3254
|
-
}
|
|
3255
|
-
const sourceSchema = sourceTask.outputSchema();
|
|
3256
|
-
const targetSchema = targetTask.inputSchema();
|
|
3257
|
-
if (typeof sourceSchema === "boolean") {
|
|
3258
|
-
if (sourceSchema === false) {
|
|
3259
|
-
throw new WorkflowError(`Source task has schema 'false' and outputs nothing`);
|
|
100
|
+
const val = Workflow.prototype[key];
|
|
101
|
+
if (val && val.workflowCreate && val.type) {
|
|
102
|
+
methodNameCache.set(val.type, key);
|
|
3260
103
|
}
|
|
3261
|
-
}
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
}
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
104
|
+
} catch {}
|
|
105
|
+
}
|
|
106
|
+
return methodNameCache;
|
|
107
|
+
}
|
|
108
|
+
var LOOP_TASK_TYPES = {
|
|
109
|
+
MapTask: { method: "map", endMethod: "endMap" },
|
|
110
|
+
ReduceTask: { method: "reduce", endMethod: "endReduce" },
|
|
111
|
+
WhileTask: { method: "while", endMethod: "endWhile" },
|
|
112
|
+
GraphAsTask: { method: "group", endMethod: "endGroup" }
|
|
113
|
+
};
|
|
114
|
+
function graphToWorkflowCode(graph, options = {}) {
|
|
115
|
+
const { variableName = "workflow", includeDeclaration = true, indent = " " } = options;
|
|
116
|
+
const lines = [];
|
|
117
|
+
if (includeDeclaration) {
|
|
118
|
+
lines.push(`const ${variableName} = new Workflow();`);
|
|
119
|
+
}
|
|
120
|
+
const tasks = graph.topologicallySortedNodes();
|
|
121
|
+
const dataflows = graph.getDataflows();
|
|
122
|
+
const incomingDataflows = new Map;
|
|
123
|
+
for (const df of dataflows) {
|
|
124
|
+
const list = incomingDataflows.get(df.targetTaskId) ?? [];
|
|
125
|
+
list.push(df);
|
|
126
|
+
incomingDataflows.set(df.targetTaskId, list);
|
|
127
|
+
}
|
|
128
|
+
const taskOrder = [];
|
|
129
|
+
generateTaskChain(tasks, incomingDataflows, taskOrder, variableName, indent, 0, lines);
|
|
130
|
+
return lines.join(`
|
|
131
|
+
`);
|
|
132
|
+
}
|
|
133
|
+
function generateTaskChain(tasks, incomingDataflows, taskOrder, variableName, indent, depth, lines) {
|
|
134
|
+
if (tasks.length === 0)
|
|
135
|
+
return;
|
|
136
|
+
const prefix = indent.repeat(depth);
|
|
137
|
+
const chainIndent = indent.repeat(depth + 1);
|
|
138
|
+
const chainLines = [];
|
|
139
|
+
for (let i = 0;i < tasks.length; i++) {
|
|
140
|
+
const task = tasks[i];
|
|
141
|
+
const loopInfo = LOOP_TASK_TYPES[task.type];
|
|
142
|
+
const renames = computeRenames(task, incomingDataflows, taskOrder);
|
|
143
|
+
for (const rename of renames) {
|
|
144
|
+
chainLines.push(`${chainIndent}.rename(${formatValue(rename.source)}, ${formatValue(rename.target)})`);
|
|
145
|
+
}
|
|
146
|
+
if (loopInfo) {
|
|
147
|
+
generateLoopTask(task, loopInfo, incomingDataflows, taskOrder, indent, depth, chainLines);
|
|
148
|
+
} else {
|
|
149
|
+
generateRegularTask(task, chainIndent, chainLines);
|
|
3306
150
|
}
|
|
3307
|
-
|
|
151
|
+
taskOrder.push(task.id);
|
|
3308
152
|
}
|
|
3309
|
-
|
|
3310
|
-
|
|
153
|
+
if (chainLines.length === 1 && !chainLines[0].includes(`
|
|
154
|
+
`)) {
|
|
155
|
+
const call = chainLines[0].trimStart();
|
|
156
|
+
const oneLine = `${prefix}${variableName}${call}`;
|
|
157
|
+
if (oneLine.length < 80) {
|
|
158
|
+
lines.push(`${oneLine};`);
|
|
3311
159
|
return;
|
|
3312
|
-
const { parent, iteratorTask } = pending;
|
|
3313
|
-
if (this.graph.getTargetDataflows(parent.id).length === 0) {
|
|
3314
|
-
const nodes = this._graph.getTasks();
|
|
3315
|
-
const parentIndex = nodes.findIndex((n) => n.id === parent.id);
|
|
3316
|
-
const earlierTasks = [];
|
|
3317
|
-
for (let i = parentIndex - 1;i >= 0; i--) {
|
|
3318
|
-
earlierTasks.push(nodes[i]);
|
|
3319
|
-
}
|
|
3320
|
-
const result = Workflow.autoConnect(this.graph, parent, iteratorTask, {
|
|
3321
|
-
earlierTasks
|
|
3322
|
-
});
|
|
3323
|
-
if (result.error) {
|
|
3324
|
-
this._error = result.error + " Task not added.";
|
|
3325
|
-
getLogger4().error(this._error);
|
|
3326
|
-
this.graph.removeTask(iteratorTask.id);
|
|
3327
|
-
}
|
|
3328
160
|
}
|
|
3329
161
|
}
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
const
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
162
|
+
lines.push(`${prefix}${variableName}`);
|
|
163
|
+
for (const line of chainLines) {
|
|
164
|
+
lines.push(line);
|
|
165
|
+
}
|
|
166
|
+
lines[lines.length - 1] += ";";
|
|
167
|
+
}
|
|
168
|
+
function generateRegularTask(task, chainIndent, lines) {
|
|
169
|
+
const methodMap = getMethodNameMap();
|
|
170
|
+
const methodName = methodMap.get(task.type);
|
|
171
|
+
const defaults = task.defaults;
|
|
172
|
+
const config = extractTaskConfig(task);
|
|
173
|
+
if (methodName) {
|
|
174
|
+
const colOffset = chainIndent.length + `.${methodName}(`.length;
|
|
175
|
+
const args = buildMethodArgs(defaults, config, chainIndent, colOffset);
|
|
176
|
+
lines.push(`${chainIndent}.${methodName}(${args})`);
|
|
177
|
+
} else {
|
|
178
|
+
const colOffset = chainIndent.length + ".addTask(".length;
|
|
179
|
+
const args = buildAddTaskArgs(task.type, defaults, config, chainIndent, colOffset);
|
|
180
|
+
lines.push(`${chainIndent}.addTask(${args})`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function generateLoopTask(task, loopInfo, incomingDataflows, taskOrder, indent, depth, lines) {
|
|
184
|
+
const chainIndent = indent.repeat(depth + 1);
|
|
185
|
+
const config = extractLoopConfig(task);
|
|
186
|
+
const loopColOffset = chainIndent.length + `.${loopInfo.method}(`.length;
|
|
187
|
+
const configStr = Object.keys(config).length > 0 ? formatValue(config, chainIndent, loopColOffset) : "";
|
|
188
|
+
lines.push(`${chainIndent}.${loopInfo.method}(${configStr})`);
|
|
189
|
+
if (task.hasChildren()) {
|
|
190
|
+
const subGraph = task.subGraph;
|
|
191
|
+
const innerTasks = subGraph.topologicallySortedNodes();
|
|
192
|
+
const innerDataflows = subGraph.getDataflows();
|
|
193
|
+
const innerIncoming = new Map;
|
|
194
|
+
for (const df of innerDataflows) {
|
|
195
|
+
const list = innerIncoming.get(df.targetTaskId) ?? [];
|
|
196
|
+
list.push(df);
|
|
197
|
+
innerIncoming.set(df.targetTaskId, list);
|
|
198
|
+
}
|
|
199
|
+
const innerOrder = [];
|
|
200
|
+
generateChainedInnerTasks(innerTasks, innerIncoming, innerOrder, indent, depth + 1, lines);
|
|
201
|
+
}
|
|
202
|
+
lines.push(`${chainIndent}.${loopInfo.endMethod}()`);
|
|
203
|
+
}
|
|
204
|
+
function generateChainedInnerTasks(tasks, incomingDataflows, taskOrder, indent, depth, lines) {
|
|
205
|
+
const innerPrefix = indent.repeat(depth + 1);
|
|
206
|
+
for (let i = 0;i < tasks.length; i++) {
|
|
207
|
+
const task = tasks[i];
|
|
208
|
+
const loopInfo = LOOP_TASK_TYPES[task.type];
|
|
209
|
+
const renames = computeRenames(task, incomingDataflows, taskOrder);
|
|
210
|
+
for (const rename of renames) {
|
|
211
|
+
lines.push(`${innerPrefix}.rename(${formatValue(rename.source)}, ${formatValue(rename.target)})`);
|
|
212
|
+
}
|
|
213
|
+
if (loopInfo) {
|
|
214
|
+
const config = extractLoopConfig(task);
|
|
215
|
+
const nestedColOffset = innerPrefix.length + `.${loopInfo.method}(`.length;
|
|
216
|
+
const configStr = Object.keys(config).length > 0 ? formatValue(config, innerPrefix, nestedColOffset) : "";
|
|
217
|
+
lines.push(`${innerPrefix}.${loopInfo.method}(${configStr})`);
|
|
218
|
+
if (task.hasChildren()) {
|
|
219
|
+
const subGraph = task.subGraph;
|
|
220
|
+
const innerTasks = subGraph.topologicallySortedNodes();
|
|
221
|
+
const innerDataflows = subGraph.getDataflows();
|
|
222
|
+
const innerIncoming = new Map;
|
|
223
|
+
for (const df of innerDataflows) {
|
|
224
|
+
const list = innerIncoming.get(df.targetTaskId) ?? [];
|
|
225
|
+
list.push(df);
|
|
226
|
+
innerIncoming.set(df.targetTaskId, list);
|
|
227
|
+
}
|
|
228
|
+
const innerOrder = [];
|
|
229
|
+
generateChainedInnerTasks(innerTasks, innerIncoming, innerOrder, indent, depth + 1, lines);
|
|
230
|
+
}
|
|
231
|
+
lines.push(`${innerPrefix}.${loopInfo.endMethod}()`);
|
|
232
|
+
} else {
|
|
233
|
+
const methodMap = getMethodNameMap();
|
|
234
|
+
const methodName = methodMap.get(task.type);
|
|
235
|
+
const defaults = task.defaults;
|
|
236
|
+
const config = extractTaskConfig(task);
|
|
237
|
+
if (methodName) {
|
|
238
|
+
const colOffset = innerPrefix.length + `.${methodName}(`.length;
|
|
239
|
+
const args = buildMethodArgs(defaults, config, innerPrefix, colOffset);
|
|
240
|
+
lines.push(`${innerPrefix}.${methodName}(${args})`);
|
|
241
|
+
} else {
|
|
242
|
+
const colOffset = innerPrefix.length + ".addTask(".length;
|
|
243
|
+
const args = buildAddTaskArgs(task.type, defaults, config, innerPrefix, colOffset);
|
|
244
|
+
lines.push(`${innerPrefix}.addTask(${args})`);
|
|
3400
245
|
}
|
|
3401
246
|
}
|
|
247
|
+
taskOrder.push(task.id);
|
|
3402
248
|
}
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
const getSpecificTypeIdentifiers = (schema) => {
|
|
3412
|
-
const formats = new Set;
|
|
3413
|
-
const ids = new Set;
|
|
3414
|
-
if (typeof schema === "boolean") {
|
|
3415
|
-
return { formats, ids };
|
|
3416
|
-
}
|
|
3417
|
-
const extractFromSchema = (s) => {
|
|
3418
|
-
if (!s || typeof s !== "object" || Array.isArray(s))
|
|
3419
|
-
return;
|
|
3420
|
-
if (s.format)
|
|
3421
|
-
formats.add(s.format);
|
|
3422
|
-
if (s.$id)
|
|
3423
|
-
ids.add(s.$id);
|
|
3424
|
-
};
|
|
3425
|
-
extractFromSchema(schema);
|
|
3426
|
-
const checkUnion = (schemas) => {
|
|
3427
|
-
if (!schemas)
|
|
3428
|
-
return;
|
|
3429
|
-
for (const s of schemas) {
|
|
3430
|
-
if (typeof s === "boolean")
|
|
3431
|
-
continue;
|
|
3432
|
-
extractFromSchema(s);
|
|
3433
|
-
if (s.items && typeof s.items === "object" && !Array.isArray(s.items)) {
|
|
3434
|
-
extractFromSchema(s.items);
|
|
3435
|
-
}
|
|
3436
|
-
}
|
|
3437
|
-
};
|
|
3438
|
-
checkUnion(schema.oneOf);
|
|
3439
|
-
checkUnion(schema.anyOf);
|
|
3440
|
-
if (schema.items && typeof schema.items === "object" && !Array.isArray(schema.items)) {
|
|
3441
|
-
extractFromSchema(schema.items);
|
|
3442
|
-
}
|
|
3443
|
-
return { formats, ids };
|
|
3444
|
-
};
|
|
3445
|
-
const isTypeCompatible = (fromPortOutputSchema, toPortInputSchema, requireSpecificType = false) => {
|
|
3446
|
-
if (typeof fromPortOutputSchema === "boolean" || typeof toPortInputSchema === "boolean") {
|
|
3447
|
-
return fromPortOutputSchema === true && toPortInputSchema === true;
|
|
3448
|
-
}
|
|
3449
|
-
const outputIds = getSpecificTypeIdentifiers(fromPortOutputSchema);
|
|
3450
|
-
const inputIds = getSpecificTypeIdentifiers(toPortInputSchema);
|
|
3451
|
-
for (const format of outputIds.formats) {
|
|
3452
|
-
if (inputIds.formats.has(format)) {
|
|
3453
|
-
return true;
|
|
3454
|
-
}
|
|
3455
|
-
}
|
|
3456
|
-
for (const id of outputIds.ids) {
|
|
3457
|
-
if (inputIds.ids.has(id)) {
|
|
3458
|
-
return true;
|
|
3459
|
-
}
|
|
3460
|
-
}
|
|
3461
|
-
if (requireSpecificType) {
|
|
3462
|
-
return false;
|
|
3463
|
-
}
|
|
3464
|
-
const idTypeBlank = fromPortOutputSchema.$id === undefined && toPortInputSchema.$id === undefined;
|
|
3465
|
-
if (!idTypeBlank)
|
|
3466
|
-
return false;
|
|
3467
|
-
if (fromPortOutputSchema.type === toPortInputSchema.type)
|
|
3468
|
-
return true;
|
|
3469
|
-
const matchesOneOf = toPortInputSchema.oneOf?.some((schema) => {
|
|
3470
|
-
if (typeof schema === "boolean")
|
|
3471
|
-
return schema;
|
|
3472
|
-
return schema.type === fromPortOutputSchema.type;
|
|
3473
|
-
}) ?? false;
|
|
3474
|
-
const matchesAnyOf = toPortInputSchema.anyOf?.some((schema) => {
|
|
3475
|
-
if (typeof schema === "boolean")
|
|
3476
|
-
return schema;
|
|
3477
|
-
return schema.type === fromPortOutputSchema.type;
|
|
3478
|
-
}) ?? false;
|
|
3479
|
-
return matchesOneOf || matchesAnyOf;
|
|
3480
|
-
};
|
|
3481
|
-
const makeMatch = (fromSchema, toSchema, fromTaskId, toTaskId, comparator) => {
|
|
3482
|
-
if (typeof fromSchema === "object") {
|
|
3483
|
-
if (toSchema === true || typeof toSchema === "object" && toSchema.additionalProperties === true) {
|
|
3484
|
-
for (const fromOutputPortId of Object.keys(fromSchema.properties || {})) {
|
|
3485
|
-
if (matches.has(fromOutputPortId))
|
|
3486
|
-
continue;
|
|
3487
|
-
matches.set(fromOutputPortId, fromOutputPortId);
|
|
3488
|
-
graph.addDataflow(new Dataflow(fromTaskId, fromOutputPortId, toTaskId, fromOutputPortId));
|
|
3489
|
-
}
|
|
3490
|
-
return;
|
|
3491
|
-
}
|
|
3492
|
-
}
|
|
3493
|
-
if (typeof fromSchema === "object" && fromSchema.additionalProperties === true && typeof toSchema === "object" && (sourceTask.type === "InputTask" || sourceTask.type === "OutputTask")) {
|
|
3494
|
-
for (const toInputPortId of Object.keys(toSchema.properties || {})) {
|
|
3495
|
-
if (matches.has(toInputPortId))
|
|
3496
|
-
continue;
|
|
3497
|
-
if (connectedInputKeys.has(toInputPortId))
|
|
3498
|
-
continue;
|
|
3499
|
-
matches.set(toInputPortId, toInputPortId);
|
|
3500
|
-
graph.addDataflow(new Dataflow(fromTaskId, toInputPortId, toTaskId, toInputPortId));
|
|
3501
|
-
}
|
|
3502
|
-
return;
|
|
3503
|
-
}
|
|
3504
|
-
if (typeof fromSchema === "boolean" || typeof toSchema === "boolean") {
|
|
3505
|
-
return;
|
|
3506
|
-
}
|
|
3507
|
-
for (const [toInputPortId, toPortInputSchema] of Object.entries(toSchema.properties || {})) {
|
|
3508
|
-
if (matches.has(toInputPortId))
|
|
3509
|
-
continue;
|
|
3510
|
-
if (connectedInputKeys.has(toInputPortId))
|
|
3511
|
-
continue;
|
|
3512
|
-
const candidates = [];
|
|
3513
|
-
for (const [fromOutputPortId, fromPortOutputSchema] of Object.entries(fromSchema.properties || {})) {
|
|
3514
|
-
if (comparator([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema])) {
|
|
3515
|
-
candidates.push(fromOutputPortId);
|
|
3516
|
-
}
|
|
3517
|
-
}
|
|
3518
|
-
if (candidates.length === 0)
|
|
3519
|
-
continue;
|
|
3520
|
-
let winner = candidates[0];
|
|
3521
|
-
if (candidates.length > 1) {
|
|
3522
|
-
const targetStreamMode = getPortStreamMode(toSchema, toInputPortId);
|
|
3523
|
-
const streamMatch = candidates.find((portId) => getPortStreamMode(fromSchema, portId) === targetStreamMode);
|
|
3524
|
-
if (streamMatch)
|
|
3525
|
-
winner = streamMatch;
|
|
3526
|
-
}
|
|
3527
|
-
matches.set(toInputPortId, winner);
|
|
3528
|
-
graph.addDataflow(new Dataflow(fromTaskId, winner, toTaskId, toInputPortId));
|
|
3529
|
-
}
|
|
3530
|
-
};
|
|
3531
|
-
makeMatch(sourceSchema, targetSchema, sourceTask.id, targetTask.id, ([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema]) => {
|
|
3532
|
-
const outputPortIdMatch = fromOutputPortId === toInputPortId;
|
|
3533
|
-
const outputPortIdOutputInput = fromOutputPortId === "output" && toInputPortId === "input";
|
|
3534
|
-
const portIdsCompatible = outputPortIdMatch || outputPortIdOutputInput;
|
|
3535
|
-
return portIdsCompatible && isTypeCompatible(fromPortOutputSchema, toPortInputSchema, false);
|
|
3536
|
-
});
|
|
3537
|
-
makeMatch(sourceSchema, targetSchema, sourceTask.id, targetTask.id, ([_fromOutputPortId, fromPortOutputSchema], [_toInputPortId, toPortInputSchema]) => {
|
|
3538
|
-
return isTypeCompatible(fromPortOutputSchema, toPortInputSchema, true);
|
|
3539
|
-
});
|
|
3540
|
-
const requiredInputs = new Set(typeof targetSchema === "object" ? targetSchema.required || [] : []);
|
|
3541
|
-
const requiredInputsNeedingConnection = [...requiredInputs].filter((r) => !providedInputKeys.has(r) && !connectedInputKeys.has(r));
|
|
3542
|
-
let unmatchedRequired = requiredInputsNeedingConnection.filter((r) => !matches.has(r));
|
|
3543
|
-
if (unmatchedRequired.length > 0 && earlierTasks.length > 0) {
|
|
3544
|
-
for (let i = 0;i < earlierTasks.length && unmatchedRequired.length > 0; i++) {
|
|
3545
|
-
const earlierTask = earlierTasks[i];
|
|
3546
|
-
const earlierOutputSchema = earlierTask.outputSchema();
|
|
3547
|
-
if (earlierTask.type === "InputTask") {
|
|
3548
|
-
for (const requiredInputId of [...unmatchedRequired]) {
|
|
3549
|
-
if (matches.has(requiredInputId))
|
|
3550
|
-
continue;
|
|
3551
|
-
matches.set(requiredInputId, requiredInputId);
|
|
3552
|
-
graph.addDataflow(new Dataflow(earlierTask.id, requiredInputId, targetTask.id, requiredInputId));
|
|
3553
|
-
}
|
|
3554
|
-
unmatchedRequired = unmatchedRequired.filter((r) => !matches.has(r));
|
|
3555
|
-
continue;
|
|
3556
|
-
}
|
|
3557
|
-
const makeMatchFromEarlier = (comparator) => {
|
|
3558
|
-
if (typeof earlierOutputSchema === "boolean" || typeof targetSchema === "boolean") {
|
|
3559
|
-
return;
|
|
3560
|
-
}
|
|
3561
|
-
for (const [fromOutputPortId, fromPortOutputSchema] of Object.entries(earlierOutputSchema.properties || {})) {
|
|
3562
|
-
for (const requiredInputId of unmatchedRequired) {
|
|
3563
|
-
const toPortInputSchema = targetSchema.properties?.[requiredInputId];
|
|
3564
|
-
if (!matches.has(requiredInputId) && toPortInputSchema && comparator([fromOutputPortId, fromPortOutputSchema], [requiredInputId, toPortInputSchema])) {
|
|
3565
|
-
matches.set(requiredInputId, fromOutputPortId);
|
|
3566
|
-
graph.addDataflow(new Dataflow(earlierTask.id, fromOutputPortId, targetTask.id, requiredInputId));
|
|
3567
|
-
}
|
|
3568
|
-
}
|
|
3569
|
-
}
|
|
3570
|
-
};
|
|
3571
|
-
makeMatchFromEarlier(([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema]) => {
|
|
3572
|
-
const outputPortIdMatch = fromOutputPortId === toInputPortId;
|
|
3573
|
-
const outputPortIdOutputInput = fromOutputPortId === "output" && toInputPortId === "input";
|
|
3574
|
-
const portIdsCompatible = outputPortIdMatch || outputPortIdOutputInput;
|
|
3575
|
-
return portIdsCompatible && isTypeCompatible(fromPortOutputSchema, toPortInputSchema, false);
|
|
3576
|
-
});
|
|
3577
|
-
makeMatchFromEarlier(([_fromOutputPortId, fromPortOutputSchema], [_toInputPortId, toPortInputSchema]) => {
|
|
3578
|
-
return isTypeCompatible(fromPortOutputSchema, toPortInputSchema, true);
|
|
3579
|
-
});
|
|
3580
|
-
unmatchedRequired = unmatchedRequired.filter((r) => !matches.has(r));
|
|
3581
|
-
}
|
|
3582
|
-
}
|
|
3583
|
-
const stillUnmatchedRequired = requiredInputsNeedingConnection.filter((r) => !matches.has(r));
|
|
3584
|
-
if (stillUnmatchedRequired.length > 0) {
|
|
3585
|
-
return {
|
|
3586
|
-
matches,
|
|
3587
|
-
error: `Could not find matches for required inputs [${stillUnmatchedRequired.join(", ")}] of ${targetTask.type}. ` + `Attempted to match from ${sourceTask.type} and earlier tasks.`,
|
|
3588
|
-
unmatchedRequired: stillUnmatchedRequired
|
|
3589
|
-
};
|
|
3590
|
-
}
|
|
3591
|
-
if (matches.size === 0 && requiredInputsNeedingConnection.length === 0) {
|
|
3592
|
-
const existingTargetConnections = graph.getSourceDataflows(targetTask.id);
|
|
3593
|
-
if (existingTargetConnections.length > 0) {
|
|
3594
|
-
return { matches, unmatchedRequired: [] };
|
|
3595
|
-
}
|
|
3596
|
-
const hasRequiredInputs = requiredInputs.size > 0;
|
|
3597
|
-
const allRequiredInputsProvided = hasRequiredInputs && [...requiredInputs].every((r) => providedInputKeys.has(r));
|
|
3598
|
-
const hasInputsWithDefaults = typeof targetSchema === "object" && targetSchema.properties && Object.values(targetSchema.properties).some((prop) => prop && typeof prop === "object" && ("default" in prop));
|
|
3599
|
-
if (!allRequiredInputsProvided && !hasInputsWithDefaults) {
|
|
3600
|
-
return {
|
|
3601
|
-
matches,
|
|
3602
|
-
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.`,
|
|
3603
|
-
unmatchedRequired: []
|
|
3604
|
-
};
|
|
3605
|
-
}
|
|
249
|
+
}
|
|
250
|
+
function computeRenames(task, incomingDataflows, taskOrder) {
|
|
251
|
+
const incoming = incomingDataflows.get(task.id) ?? [];
|
|
252
|
+
const renames = [];
|
|
253
|
+
const prevTaskId = taskOrder.length > 0 ? taskOrder[taskOrder.length - 1] : undefined;
|
|
254
|
+
for (const df of incoming) {
|
|
255
|
+
if (df.sourceTaskPortId === DATAFLOW_ALL_PORTS && df.targetTaskPortId === DATAFLOW_ALL_PORTS) {
|
|
256
|
+
continue;
|
|
3606
257
|
}
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
unmatchedRequired: []
|
|
3610
|
-
};
|
|
3611
|
-
}
|
|
3612
|
-
finalizeTemplate() {
|
|
3613
|
-
if (!this._iteratorTask || this.graph.getTasks().length === 0) {
|
|
3614
|
-
return;
|
|
258
|
+
if (df.sourceTaskPortId === DATAFLOW_ERROR_PORT || df.targetTaskPortId === DATAFLOW_ERROR_PORT) {
|
|
259
|
+
continue;
|
|
3615
260
|
}
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
finalizeAndReturn() {
|
|
3619
|
-
if (!this._parentWorkflow) {
|
|
3620
|
-
throw new WorkflowError("finalizeAndReturn() can only be called on loop workflows");
|
|
261
|
+
if (df.sourceTaskId !== prevTaskId) {
|
|
262
|
+
continue;
|
|
3621
263
|
}
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
this._parentWorkflow.autoConnectLoopTask(this._pendingLoopConnect);
|
|
3625
|
-
this._pendingLoopConnect = undefined;
|
|
264
|
+
if (df.sourceTaskPortId === df.targetTaskPortId) {
|
|
265
|
+
continue;
|
|
3626
266
|
}
|
|
3627
|
-
|
|
3628
|
-
}
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
267
|
+
renames.push({ source: df.sourceTaskPortId, target: df.targetTaskPortId });
|
|
268
|
+
}
|
|
269
|
+
return renames;
|
|
270
|
+
}
|
|
271
|
+
function extractTaskConfig(task) {
|
|
272
|
+
const config = {};
|
|
273
|
+
const rawConfig = task.config;
|
|
274
|
+
const staticTitle = task.constructor.title || "";
|
|
275
|
+
const staticDescription = task.constructor.description || "";
|
|
276
|
+
if (rawConfig.title && rawConfig.title !== staticTitle)
|
|
277
|
+
config.title = rawConfig.title;
|
|
278
|
+
if (rawConfig.description && rawConfig.description !== staticDescription)
|
|
279
|
+
config.description = rawConfig.description;
|
|
280
|
+
return config;
|
|
281
|
+
}
|
|
282
|
+
function extractLoopConfig(task) {
|
|
283
|
+
const config = {};
|
|
284
|
+
const rawConfig = task.config;
|
|
285
|
+
switch (task.type) {
|
|
286
|
+
case "GraphAsTask": {
|
|
287
|
+
if (rawConfig.compoundMerge !== undefined) {
|
|
288
|
+
config.compoundMerge = rawConfig.compoundMerge;
|
|
289
|
+
}
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
case "MapTask": {
|
|
293
|
+
if (rawConfig.preserveOrder !== undefined && rawConfig.preserveOrder !== true) {
|
|
294
|
+
config.preserveOrder = rawConfig.preserveOrder;
|
|
295
|
+
}
|
|
296
|
+
if (rawConfig.flatten !== undefined && rawConfig.flatten !== false) {
|
|
297
|
+
config.flatten = rawConfig.flatten;
|
|
298
|
+
}
|
|
299
|
+
if (rawConfig.concurrencyLimit !== undefined) {
|
|
300
|
+
config.concurrencyLimit = rawConfig.concurrencyLimit;
|
|
301
|
+
}
|
|
302
|
+
if (rawConfig.batchSize !== undefined) {
|
|
303
|
+
config.batchSize = rawConfig.batchSize;
|
|
304
|
+
}
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
case "ReduceTask": {
|
|
308
|
+
if (rawConfig.initialValue !== undefined) {
|
|
309
|
+
config.initialValue = rawConfig.initialValue;
|
|
310
|
+
}
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
case "WhileTask": {
|
|
314
|
+
if (rawConfig.maxIterations !== undefined && rawConfig.maxIterations !== 100) {
|
|
315
|
+
config.maxIterations = rawConfig.maxIterations;
|
|
316
|
+
}
|
|
317
|
+
if (rawConfig.chainIterations !== undefined && rawConfig.chainIterations !== true) {
|
|
318
|
+
config.chainIterations = rawConfig.chainIterations;
|
|
319
|
+
}
|
|
320
|
+
if (rawConfig.conditionField !== undefined) {
|
|
321
|
+
config.conditionField = rawConfig.conditionField;
|
|
322
|
+
}
|
|
323
|
+
if (rawConfig.conditionOperator !== undefined) {
|
|
324
|
+
config.conditionOperator = rawConfig.conditionOperator;
|
|
325
|
+
}
|
|
326
|
+
if (rawConfig.conditionValue !== undefined) {
|
|
327
|
+
config.conditionValue = rawConfig.conditionValue;
|
|
328
|
+
}
|
|
329
|
+
if (rawConfig.condition && !rawConfig.conditionOperator) {
|
|
330
|
+
config.condition = null;
|
|
331
|
+
}
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return config;
|
|
336
|
+
}
|
|
337
|
+
function buildMethodArgs(defaults, config, baseIndent = "", columnOffset = 0) {
|
|
338
|
+
const hasDefaults = defaults && Object.keys(defaults).length > 0;
|
|
339
|
+
const hasConfig = Object.keys(config).length > 0;
|
|
340
|
+
if (!hasDefaults && !hasConfig)
|
|
341
|
+
return "";
|
|
342
|
+
if (hasDefaults && !hasConfig)
|
|
343
|
+
return formatValue(defaults, baseIndent, columnOffset);
|
|
344
|
+
if (!hasDefaults && hasConfig)
|
|
345
|
+
return `{}, ${formatValue(config, baseIndent, columnOffset + 4)}`;
|
|
346
|
+
const defaultsStr = formatValue(defaults, baseIndent, columnOffset);
|
|
347
|
+
return `${defaultsStr}, ${formatValue(config, baseIndent, columnOffset + defaultsStr.length + 2)}`;
|
|
348
|
+
}
|
|
349
|
+
function buildAddTaskArgs(taskType, defaults, config, baseIndent = "", columnOffset = 0) {
|
|
350
|
+
const hasDefaults = defaults && Object.keys(defaults).length > 0;
|
|
351
|
+
const hasConfig = Object.keys(config).length > 0;
|
|
352
|
+
const typeOffset = columnOffset + taskType.length + 2;
|
|
353
|
+
if (!hasDefaults && !hasConfig)
|
|
354
|
+
return taskType;
|
|
355
|
+
if (hasDefaults && !hasConfig)
|
|
356
|
+
return `${taskType}, ${formatValue(defaults, baseIndent, typeOffset)}`;
|
|
357
|
+
if (!hasDefaults && hasConfig)
|
|
358
|
+
return `${taskType}, {}, ${formatValue(config, baseIndent, typeOffset + 4)}`;
|
|
359
|
+
const defaultsStr = formatValue(defaults, baseIndent, typeOffset);
|
|
360
|
+
return `${taskType}, ${defaultsStr}, ${formatValue(config, baseIndent, typeOffset + defaultsStr.length + 2)}`;
|
|
361
|
+
}
|
|
362
|
+
function formatValue(value, baseIndent = "", columnOffset = 0) {
|
|
363
|
+
if (value === undefined)
|
|
364
|
+
return "undefined";
|
|
365
|
+
if (value === null)
|
|
366
|
+
return "null";
|
|
367
|
+
if (typeof value === "string") {
|
|
368
|
+
return JSON.stringify(value);
|
|
369
|
+
}
|
|
370
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
371
|
+
return String(value);
|
|
372
|
+
if (value instanceof Float32Array) {
|
|
373
|
+
return `new Float32Array([${Array.from(value).join(", ")}])`;
|
|
374
|
+
}
|
|
375
|
+
if (value instanceof Float64Array) {
|
|
376
|
+
return `new Float64Array([${Array.from(value).join(", ")}])`;
|
|
377
|
+
}
|
|
378
|
+
const entryIndent = baseIndent + " ";
|
|
379
|
+
if (Array.isArray(value)) {
|
|
380
|
+
if (value.length === 0)
|
|
381
|
+
return "[]";
|
|
382
|
+
const items = value.map((v) => formatValue(v, entryIndent));
|
|
383
|
+
const oneLine = `[${items.join(", ")}]`;
|
|
384
|
+
if (columnOffset + oneLine.length < 80)
|
|
385
|
+
return oneLine;
|
|
386
|
+
return `[
|
|
387
|
+
${items.map((item) => `${entryIndent}${item}`).join(`,
|
|
388
|
+
`)}
|
|
389
|
+
${baseIndent}]`;
|
|
390
|
+
}
|
|
391
|
+
if (typeof value === "object") {
|
|
392
|
+
const obj = value;
|
|
393
|
+
const keys = Object.keys(obj);
|
|
394
|
+
if (keys.length === 0)
|
|
395
|
+
return "{}";
|
|
396
|
+
const entries = keys.map((k) => {
|
|
397
|
+
const formattedKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(k) ? k : JSON.stringify(k);
|
|
398
|
+
return `${formattedKey}: ${formatValue(obj[k], entryIndent)}`;
|
|
3640
399
|
});
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
}
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
static type = "Own[Graph]";
|
|
3649
|
-
}
|
|
3650
|
-
|
|
3651
|
-
class OwnWorkflowTask extends ListeningGraphAsTask {
|
|
3652
|
-
static type = "Own[Workflow]";
|
|
3653
|
-
}
|
|
3654
|
-
|
|
3655
|
-
class GraphTask extends GraphAsTask {
|
|
3656
|
-
static type = "Graph";
|
|
3657
|
-
}
|
|
3658
|
-
|
|
3659
|
-
class WorkflowTask2 extends GraphAsTask {
|
|
3660
|
-
static type = "Workflow";
|
|
3661
|
-
}
|
|
3662
|
-
function convertPipeFunctionToTask(fn, config) {
|
|
3663
|
-
|
|
3664
|
-
class QuickTask extends Task {
|
|
3665
|
-
static type = fn.name ? `\uD835\uDC53 ${fn.name}` : "\uD835\uDC53";
|
|
3666
|
-
static inputSchema = () => {
|
|
3667
|
-
return {
|
|
3668
|
-
type: "object",
|
|
3669
|
-
properties: {
|
|
3670
|
-
[DATAFLOW_ALL_PORTS]: {}
|
|
3671
|
-
},
|
|
3672
|
-
additionalProperties: false
|
|
3673
|
-
};
|
|
3674
|
-
};
|
|
3675
|
-
static outputSchema = () => {
|
|
3676
|
-
return {
|
|
3677
|
-
type: "object",
|
|
3678
|
-
properties: {
|
|
3679
|
-
[DATAFLOW_ALL_PORTS]: {}
|
|
3680
|
-
},
|
|
3681
|
-
additionalProperties: false
|
|
3682
|
-
};
|
|
3683
|
-
};
|
|
3684
|
-
static cacheable = false;
|
|
3685
|
-
async execute(input, context) {
|
|
3686
|
-
return fn(input, context);
|
|
3687
|
-
}
|
|
3688
|
-
}
|
|
3689
|
-
return new QuickTask({}, config);
|
|
3690
|
-
}
|
|
3691
|
-
function ensureTask(arg, config = {}) {
|
|
3692
|
-
if (arg instanceof Task) {
|
|
3693
|
-
return arg;
|
|
3694
|
-
}
|
|
3695
|
-
if (arg instanceof TaskGraph) {
|
|
3696
|
-
const { isOwned, ...cleanConfig } = config;
|
|
3697
|
-
if (isOwned) {
|
|
3698
|
-
return new OwnGraphTask({}, { ...cleanConfig, subGraph: arg });
|
|
3699
|
-
} else {
|
|
3700
|
-
return new GraphTask({}, { ...cleanConfig, subGraph: arg });
|
|
3701
|
-
}
|
|
3702
|
-
}
|
|
3703
|
-
if (arg instanceof Workflow) {
|
|
3704
|
-
const { isOwned, ...cleanConfig } = config;
|
|
3705
|
-
if (isOwned) {
|
|
3706
|
-
return new OwnWorkflowTask({}, { ...cleanConfig, subGraph: arg.graph });
|
|
3707
|
-
} else {
|
|
3708
|
-
return new WorkflowTask2({}, { ...cleanConfig, subGraph: arg.graph });
|
|
3709
|
-
}
|
|
400
|
+
const oneLine = `{ ${entries.join(", ")} }`;
|
|
401
|
+
if (columnOffset + oneLine.length < 80)
|
|
402
|
+
return oneLine;
|
|
403
|
+
return `{
|
|
404
|
+
${entries.map((e) => `${entryIndent}${e}`).join(`,
|
|
405
|
+
`)}
|
|
406
|
+
${baseIndent}}`;
|
|
3710
407
|
}
|
|
3711
|
-
return
|
|
3712
|
-
}
|
|
3713
|
-
function getLastTask(workflow) {
|
|
3714
|
-
const tasks = workflow.graph.getTasks();
|
|
3715
|
-
return tasks.length > 0 ? tasks[tasks.length - 1] : undefined;
|
|
3716
|
-
}
|
|
3717
|
-
function connect(source, target, workflow) {
|
|
3718
|
-
workflow.graph.addDataflow(new Dataflow(source.id, "*", target.id, "*"));
|
|
408
|
+
return String(value);
|
|
3719
409
|
}
|
|
3720
|
-
function
|
|
3721
|
-
|
|
3722
|
-
const tasks = args.map((arg) => ensureTask(arg));
|
|
3723
|
-
tasks.forEach((task) => {
|
|
3724
|
-
workflow.graph.addTask(task);
|
|
3725
|
-
if (previousTask) {
|
|
3726
|
-
connect(previousTask, task, workflow);
|
|
3727
|
-
}
|
|
3728
|
-
previousTask = task;
|
|
3729
|
-
});
|
|
3730
|
-
return workflow;
|
|
410
|
+
function resetMethodNameCache() {
|
|
411
|
+
methodNameCache = undefined;
|
|
3731
412
|
}
|
|
3732
|
-
function parallel(args, mergeFn = PROPERTY_ARRAY, workflow = new Workflow) {
|
|
3733
|
-
let previousTask = getLastTask(workflow);
|
|
3734
|
-
const tasks = args.map((arg) => ensureTask(arg));
|
|
3735
|
-
const input = {};
|
|
3736
|
-
const config = {
|
|
3737
|
-
compoundMerge: mergeFn
|
|
3738
|
-
};
|
|
3739
|
-
const name = `\u2016${args.map((arg) => "\uD835\uDC53").join("\u2016")}\u2016`;
|
|
3740
413
|
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
}
|
|
3744
|
-
const mergeTask = new ParallelTask(input, config);
|
|
3745
|
-
mergeTask.subGraph.addTasks(tasks);
|
|
3746
|
-
workflow.graph.addTask(mergeTask);
|
|
3747
|
-
if (previousTask) {
|
|
3748
|
-
connect(previousTask, mergeTask, workflow);
|
|
3749
|
-
}
|
|
3750
|
-
return workflow;
|
|
3751
|
-
}
|
|
414
|
+
// src/common.ts
|
|
415
|
+
init_Workflow();
|
|
3752
416
|
|
|
3753
|
-
// src/task
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
"node-removed": "task_removed",
|
|
3757
|
-
"node-replaced": "task_replaced",
|
|
3758
|
-
"edge-added": "dataflow_added",
|
|
3759
|
-
"edge-removed": "dataflow_removed",
|
|
3760
|
-
"edge-replaced": "dataflow_replaced"
|
|
3761
|
-
};
|
|
3762
|
-
var EventTaskGraphToDagMapping = {
|
|
3763
|
-
task_added: "node-added",
|
|
3764
|
-
task_removed: "node-removed",
|
|
3765
|
-
task_replaced: "node-replaced",
|
|
3766
|
-
dataflow_added: "edge-added",
|
|
3767
|
-
dataflow_removed: "edge-removed",
|
|
3768
|
-
dataflow_replaced: "edge-replaced"
|
|
3769
|
-
};
|
|
417
|
+
// src/task/index.ts
|
|
418
|
+
init_ConditionalTask();
|
|
419
|
+
init_ConditionUtils();
|
|
3770
420
|
|
|
3771
|
-
// src/task
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
super((task) => task.id, (dataflow) => dataflow.id);
|
|
3775
|
-
}
|
|
3776
|
-
}
|
|
421
|
+
// src/task/FallbackTask.ts
|
|
422
|
+
init_Workflow();
|
|
423
|
+
init_GraphAsTask();
|
|
3777
424
|
|
|
3778
|
-
class TaskGraph {
|
|
3779
|
-
outputCache;
|
|
3780
|
-
constructor({ outputCache, dag } = {}) {
|
|
3781
|
-
this.outputCache = outputCache;
|
|
3782
|
-
this._dag = dag || new TaskGraphDAG;
|
|
3783
|
-
}
|
|
3784
|
-
_dag;
|
|
3785
|
-
_runner;
|
|
3786
|
-
get runner() {
|
|
3787
|
-
if (!this._runner) {
|
|
3788
|
-
this._runner = new TaskGraphRunner(this, this.outputCache);
|
|
3789
|
-
}
|
|
3790
|
-
return this._runner;
|
|
3791
|
-
}
|
|
3792
|
-
run(input = {}, config = {}) {
|
|
3793
|
-
return this.runner.runGraph(input, {
|
|
3794
|
-
outputCache: config?.outputCache || this.outputCache,
|
|
3795
|
-
parentSignal: config?.parentSignal || undefined,
|
|
3796
|
-
accumulateLeafOutputs: config?.accumulateLeafOutputs,
|
|
3797
|
-
registry: config?.registry
|
|
3798
|
-
});
|
|
3799
|
-
}
|
|
3800
|
-
runReactive(input = {}, config = {}) {
|
|
3801
|
-
return this.runner.runGraphReactive(input, config);
|
|
3802
|
-
}
|
|
3803
|
-
mergeExecuteOutputsToRunOutput(results, compoundMerge) {
|
|
3804
|
-
return this.runner.mergeExecuteOutputsToRunOutput(results, compoundMerge);
|
|
3805
|
-
}
|
|
3806
|
-
abort() {
|
|
3807
|
-
this.runner.abort();
|
|
3808
|
-
}
|
|
3809
|
-
async disable() {
|
|
3810
|
-
await this.runner.disable();
|
|
3811
|
-
}
|
|
3812
|
-
getTask(id) {
|
|
3813
|
-
return this._dag.getNode(id);
|
|
3814
|
-
}
|
|
3815
|
-
getTasks() {
|
|
3816
|
-
return this._dag.getNodes();
|
|
3817
|
-
}
|
|
3818
|
-
topologicallySortedNodes() {
|
|
3819
|
-
return this._dag.topologicallySortedNodes();
|
|
3820
|
-
}
|
|
3821
|
-
addTask(task, config) {
|
|
3822
|
-
return this._dag.addNode(ensureTask(task, config));
|
|
3823
|
-
}
|
|
3824
|
-
addTasks(tasks) {
|
|
3825
|
-
return this._dag.addNodes(tasks.map(ensureTask));
|
|
3826
|
-
}
|
|
3827
|
-
addDataflow(dataflow) {
|
|
3828
|
-
return this._dag.addEdge(dataflow.sourceTaskId, dataflow.targetTaskId, dataflow);
|
|
3829
|
-
}
|
|
3830
|
-
addDataflows(dataflows) {
|
|
3831
|
-
const addedEdges = dataflows.map((edge) => {
|
|
3832
|
-
return [edge.sourceTaskId, edge.targetTaskId, edge];
|
|
3833
|
-
});
|
|
3834
|
-
return this._dag.addEdges(addedEdges);
|
|
3835
|
-
}
|
|
3836
|
-
getDataflow(id) {
|
|
3837
|
-
for (const i in this._dag.adjacency) {
|
|
3838
|
-
for (const j in this._dag.adjacency[i]) {
|
|
3839
|
-
const maybeEdges = this._dag.adjacency[i][j];
|
|
3840
|
-
if (maybeEdges !== null) {
|
|
3841
|
-
for (const edge of maybeEdges) {
|
|
3842
|
-
if (this._dag.edgeIdentity(edge, "", "") == id) {
|
|
3843
|
-
return edge;
|
|
3844
|
-
}
|
|
3845
|
-
}
|
|
3846
|
-
}
|
|
3847
|
-
}
|
|
3848
|
-
}
|
|
3849
|
-
}
|
|
3850
|
-
getDataflows() {
|
|
3851
|
-
return this._dag.getEdges().map((edge) => edge[2]);
|
|
3852
|
-
}
|
|
3853
|
-
removeDataflow(dataflow) {
|
|
3854
|
-
return this._dag.removeEdge(dataflow.sourceTaskId, dataflow.targetTaskId, dataflow.id);
|
|
3855
|
-
}
|
|
3856
|
-
getSourceDataflows(taskId) {
|
|
3857
|
-
return this._dag.inEdges(taskId).map(([, , dataflow]) => dataflow);
|
|
3858
|
-
}
|
|
3859
|
-
getTargetDataflows(taskId) {
|
|
3860
|
-
return this._dag.outEdges(taskId).map(([, , dataflow]) => dataflow);
|
|
3861
|
-
}
|
|
3862
|
-
getSourceTasks(taskId) {
|
|
3863
|
-
return this.getSourceDataflows(taskId).map((dataflow) => this.getTask(dataflow.sourceTaskId));
|
|
3864
|
-
}
|
|
3865
|
-
getTargetTasks(taskId) {
|
|
3866
|
-
return this.getTargetDataflows(taskId).map((dataflow) => this.getTask(dataflow.targetTaskId));
|
|
3867
|
-
}
|
|
3868
|
-
removeTask(taskId) {
|
|
3869
|
-
return this._dag.removeNode(taskId);
|
|
3870
|
-
}
|
|
3871
|
-
resetGraph() {
|
|
3872
|
-
this.runner.resetGraph(this, uuid45());
|
|
3873
|
-
}
|
|
3874
|
-
toJSON(options) {
|
|
3875
|
-
const tasks = this.getTasks().map((node) => node.toJSON(options));
|
|
3876
|
-
const dataflows = this.getDataflows().map((df) => df.toJSON());
|
|
3877
|
-
let json = {
|
|
3878
|
-
tasks,
|
|
3879
|
-
dataflows
|
|
3880
|
-
};
|
|
3881
|
-
if (options?.withBoundaryNodes) {
|
|
3882
|
-
json = addBoundaryNodesToGraphJson(json, this);
|
|
3883
|
-
}
|
|
3884
|
-
return json;
|
|
3885
|
-
}
|
|
3886
|
-
toDependencyJSON(options) {
|
|
3887
|
-
const tasks = this.getTasks().flatMap((node) => node.toDependencyJSON(options));
|
|
3888
|
-
this.getDataflows().forEach((df) => {
|
|
3889
|
-
const target = tasks.find((node) => node.id === df.targetTaskId);
|
|
3890
|
-
if (!target.dependencies) {
|
|
3891
|
-
target.dependencies = {};
|
|
3892
|
-
}
|
|
3893
|
-
const targetDeps = target.dependencies[df.targetTaskPortId];
|
|
3894
|
-
if (!targetDeps) {
|
|
3895
|
-
target.dependencies[df.targetTaskPortId] = {
|
|
3896
|
-
id: df.sourceTaskId,
|
|
3897
|
-
output: df.sourceTaskPortId
|
|
3898
|
-
};
|
|
3899
|
-
} else {
|
|
3900
|
-
if (Array.isArray(targetDeps)) {
|
|
3901
|
-
targetDeps.push({
|
|
3902
|
-
id: df.sourceTaskId,
|
|
3903
|
-
output: df.sourceTaskPortId
|
|
3904
|
-
});
|
|
3905
|
-
} else {
|
|
3906
|
-
target.dependencies[df.targetTaskPortId] = [
|
|
3907
|
-
targetDeps,
|
|
3908
|
-
{ id: df.sourceTaskId, output: df.sourceTaskPortId }
|
|
3909
|
-
];
|
|
3910
|
-
}
|
|
3911
|
-
}
|
|
3912
|
-
});
|
|
3913
|
-
if (options?.withBoundaryNodes) {
|
|
3914
|
-
return addBoundaryNodesToDependencyJson(tasks, this);
|
|
3915
|
-
}
|
|
3916
|
-
return tasks;
|
|
3917
|
-
}
|
|
3918
|
-
get events() {
|
|
3919
|
-
if (!this._events) {
|
|
3920
|
-
this._events = new EventEmitter5;
|
|
3921
|
-
}
|
|
3922
|
-
return this._events;
|
|
3923
|
-
}
|
|
3924
|
-
_events;
|
|
3925
|
-
subscribe(name, fn) {
|
|
3926
|
-
this.on(name, fn);
|
|
3927
|
-
return () => this.off(name, fn);
|
|
3928
|
-
}
|
|
3929
|
-
subscribeToTaskStatus(callback) {
|
|
3930
|
-
const unsubscribes = [];
|
|
3931
|
-
const tasks = this.getTasks();
|
|
3932
|
-
tasks.forEach((task) => {
|
|
3933
|
-
const unsub = task.subscribe("status", (status) => {
|
|
3934
|
-
callback(task.id, status);
|
|
3935
|
-
});
|
|
3936
|
-
unsubscribes.push(unsub);
|
|
3937
|
-
});
|
|
3938
|
-
const handleTaskAdded = (taskId) => {
|
|
3939
|
-
const task = this.getTask(taskId);
|
|
3940
|
-
if (!task || typeof task.subscribe !== "function")
|
|
3941
|
-
return;
|
|
3942
|
-
const unsub = task.subscribe("status", (status) => {
|
|
3943
|
-
callback(task.id, status);
|
|
3944
|
-
});
|
|
3945
|
-
unsubscribes.push(unsub);
|
|
3946
|
-
};
|
|
3947
|
-
const graphUnsub = this.subscribe("task_added", handleTaskAdded);
|
|
3948
|
-
unsubscribes.push(graphUnsub);
|
|
3949
|
-
return () => {
|
|
3950
|
-
unsubscribes.forEach((unsub) => unsub());
|
|
3951
|
-
};
|
|
3952
|
-
}
|
|
3953
|
-
subscribeToTaskProgress(callback) {
|
|
3954
|
-
const unsubscribes = [];
|
|
3955
|
-
const tasks = this.getTasks();
|
|
3956
|
-
tasks.forEach((task) => {
|
|
3957
|
-
const unsub = task.subscribe("progress", (progress, message, ...args) => {
|
|
3958
|
-
callback(task.id, progress, message, ...args);
|
|
3959
|
-
});
|
|
3960
|
-
unsubscribes.push(unsub);
|
|
3961
|
-
});
|
|
3962
|
-
const handleTaskAdded = (taskId) => {
|
|
3963
|
-
const task = this.getTask(taskId);
|
|
3964
|
-
if (!task || typeof task.subscribe !== "function")
|
|
3965
|
-
return;
|
|
3966
|
-
const unsub = task.subscribe("progress", (progress, message, ...args) => {
|
|
3967
|
-
callback(task.id, progress, message, ...args);
|
|
3968
|
-
});
|
|
3969
|
-
unsubscribes.push(unsub);
|
|
3970
|
-
};
|
|
3971
|
-
const graphUnsub = this.subscribe("task_added", handleTaskAdded);
|
|
3972
|
-
unsubscribes.push(graphUnsub);
|
|
3973
|
-
return () => {
|
|
3974
|
-
unsubscribes.forEach((unsub) => unsub());
|
|
3975
|
-
};
|
|
3976
|
-
}
|
|
3977
|
-
subscribeToDataflowStatus(callback) {
|
|
3978
|
-
const unsubscribes = [];
|
|
3979
|
-
const dataflows = this.getDataflows();
|
|
3980
|
-
dataflows.forEach((dataflow) => {
|
|
3981
|
-
const unsub = dataflow.subscribe("status", (status) => {
|
|
3982
|
-
callback(dataflow.id, status);
|
|
3983
|
-
});
|
|
3984
|
-
unsubscribes.push(unsub);
|
|
3985
|
-
});
|
|
3986
|
-
const handleDataflowAdded = (dataflowId) => {
|
|
3987
|
-
const dataflow = this.getDataflow(dataflowId);
|
|
3988
|
-
if (!dataflow || typeof dataflow.subscribe !== "function")
|
|
3989
|
-
return;
|
|
3990
|
-
const unsub = dataflow.subscribe("status", (status) => {
|
|
3991
|
-
callback(dataflow.id, status);
|
|
3992
|
-
});
|
|
3993
|
-
unsubscribes.push(unsub);
|
|
3994
|
-
};
|
|
3995
|
-
const graphUnsub = this.subscribe("dataflow_added", handleDataflowAdded);
|
|
3996
|
-
unsubscribes.push(graphUnsub);
|
|
3997
|
-
return () => {
|
|
3998
|
-
unsubscribes.forEach((unsub) => unsub());
|
|
3999
|
-
};
|
|
4000
|
-
}
|
|
4001
|
-
subscribeToTaskStreaming(callbacks) {
|
|
4002
|
-
const unsubscribes = [];
|
|
4003
|
-
if (callbacks.onStreamStart) {
|
|
4004
|
-
const unsub = this.subscribe("task_stream_start", callbacks.onStreamStart);
|
|
4005
|
-
unsubscribes.push(unsub);
|
|
4006
|
-
}
|
|
4007
|
-
if (callbacks.onStreamChunk) {
|
|
4008
|
-
const unsub = this.subscribe("task_stream_chunk", callbacks.onStreamChunk);
|
|
4009
|
-
unsubscribes.push(unsub);
|
|
4010
|
-
}
|
|
4011
|
-
if (callbacks.onStreamEnd) {
|
|
4012
|
-
const unsub = this.subscribe("task_stream_end", callbacks.onStreamEnd);
|
|
4013
|
-
unsubscribes.push(unsub);
|
|
4014
|
-
}
|
|
4015
|
-
return () => {
|
|
4016
|
-
unsubscribes.forEach((unsub) => unsub());
|
|
4017
|
-
};
|
|
4018
|
-
}
|
|
4019
|
-
on(name, fn) {
|
|
4020
|
-
const dagEvent = EventTaskGraphToDagMapping[name];
|
|
4021
|
-
if (dagEvent) {
|
|
4022
|
-
return this._dag.on(dagEvent, fn);
|
|
4023
|
-
}
|
|
4024
|
-
return this.events.on(name, fn);
|
|
4025
|
-
}
|
|
4026
|
-
off(name, fn) {
|
|
4027
|
-
const dagEvent = EventTaskGraphToDagMapping[name];
|
|
4028
|
-
if (dagEvent) {
|
|
4029
|
-
return this._dag.off(dagEvent, fn);
|
|
4030
|
-
}
|
|
4031
|
-
return this.events.off(name, fn);
|
|
4032
|
-
}
|
|
4033
|
-
emit(name, ...args) {
|
|
4034
|
-
const dagEvent = EventTaskGraphToDagMapping[name];
|
|
4035
|
-
if (dagEvent) {
|
|
4036
|
-
return this.emit_dag(name, ...args);
|
|
4037
|
-
} else {
|
|
4038
|
-
return this.emit_local(name, ...args);
|
|
4039
|
-
}
|
|
4040
|
-
}
|
|
4041
|
-
emit_local(name, ...args) {
|
|
4042
|
-
return this.events?.emit(name, ...args);
|
|
4043
|
-
}
|
|
4044
|
-
emit_dag(name, ...args) {
|
|
4045
|
-
const dagEvent = EventTaskGraphToDagMapping[name];
|
|
4046
|
-
return this._dag.emit(dagEvent, ...args);
|
|
4047
|
-
}
|
|
4048
|
-
}
|
|
4049
|
-
function serialGraphEdges(tasks, inputHandle, outputHandle) {
|
|
4050
|
-
const edges = [];
|
|
4051
|
-
for (let i = 0;i < tasks.length - 1; i++) {
|
|
4052
|
-
edges.push(new Dataflow(tasks[i].id, inputHandle, tasks[i + 1].id, outputHandle));
|
|
4053
|
-
}
|
|
4054
|
-
return edges;
|
|
4055
|
-
}
|
|
4056
|
-
function serialGraph(tasks, inputHandle, outputHandle) {
|
|
4057
|
-
const graph = new TaskGraph;
|
|
4058
|
-
graph.addTasks(tasks);
|
|
4059
|
-
graph.addDataflows(serialGraphEdges(tasks, inputHandle, outputHandle));
|
|
4060
|
-
return graph;
|
|
4061
|
-
}
|
|
4062
425
|
// src/task/FallbackTaskRunner.ts
|
|
426
|
+
init_GraphAsTaskRunner();
|
|
427
|
+
init_TaskError();
|
|
428
|
+
init_TaskTypes();
|
|
429
|
+
|
|
4063
430
|
class FallbackTaskRunner extends GraphAsTaskRunner {
|
|
4064
431
|
async executeTask(input) {
|
|
4065
432
|
if (this.task.fallbackMode === "data") {
|
|
@@ -4257,7 +624,21 @@ queueMicrotask(() => {
|
|
|
4257
624
|
};
|
|
4258
625
|
Workflow.prototype.endFallbackWith = CreateEndLoopWorkflow("endFallbackWith");
|
|
4259
626
|
});
|
|
627
|
+
|
|
628
|
+
// src/task/index.ts
|
|
629
|
+
init_GraphAsTask();
|
|
630
|
+
init_GraphAsTaskRunner();
|
|
631
|
+
init_InputResolver();
|
|
632
|
+
|
|
633
|
+
// src/task/IteratorTask.ts
|
|
634
|
+
init_GraphAsTask();
|
|
635
|
+
|
|
4260
636
|
// src/task/IteratorTaskRunner.ts
|
|
637
|
+
init_Dataflow();
|
|
638
|
+
init_TaskGraph();
|
|
639
|
+
init_GraphAsTaskRunner();
|
|
640
|
+
import { uuid4 } from "@workglow/util";
|
|
641
|
+
|
|
4261
642
|
class IteratorTaskRunner extends GraphAsTaskRunner {
|
|
4262
643
|
async executeTask(input) {
|
|
4263
644
|
const analysis = this.task.analyzeIterationInput(input);
|
|
@@ -4348,16 +729,20 @@ class IteratorTaskRunner extends GraphAsTaskRunner {
|
|
|
4348
729
|
}
|
|
4349
730
|
cloneGraph(graph) {
|
|
4350
731
|
const clone = new TaskGraph;
|
|
732
|
+
const idMap = new Map;
|
|
4351
733
|
for (const task of graph.getTasks()) {
|
|
4352
734
|
const ctor = task.constructor;
|
|
4353
|
-
const
|
|
735
|
+
const newId = uuid4();
|
|
736
|
+
idMap.set(task.config.id, newId);
|
|
737
|
+
const clonedConfig = { ...task.config, id: newId };
|
|
738
|
+
const newTask = new ctor(task.defaults, clonedConfig, task.runConfig);
|
|
4354
739
|
if (task.hasChildren()) {
|
|
4355
740
|
newTask.subGraph = this.cloneGraph(task.subGraph);
|
|
4356
741
|
}
|
|
4357
742
|
clone.addTask(newTask);
|
|
4358
743
|
}
|
|
4359
744
|
for (const df of graph.getDataflows()) {
|
|
4360
|
-
clone.addDataflow(new Dataflow(df.sourceTaskId, df.sourceTaskPortId, df.targetTaskId, df.targetTaskPortId));
|
|
745
|
+
clone.addDataflow(new Dataflow(idMap.get(df.sourceTaskId) ?? df.sourceTaskId, df.sourceTaskPortId, idMap.get(df.targetTaskId) ?? df.targetTaskId, df.targetTaskPortId));
|
|
4361
746
|
}
|
|
4362
747
|
return clone;
|
|
4363
748
|
}
|
|
@@ -4378,6 +763,7 @@ class IteratorTaskRunner extends GraphAsTaskRunner {
|
|
|
4378
763
|
}
|
|
4379
764
|
|
|
4380
765
|
// src/task/IteratorTask.ts
|
|
766
|
+
init_TaskError();
|
|
4381
767
|
var ITERATOR_CONTEXT_SCHEMA = {
|
|
4382
768
|
type: "object",
|
|
4383
769
|
properties: {
|
|
@@ -4869,7 +1255,15 @@ class IteratorTask extends GraphAsTask {
|
|
|
4869
1255
|
}
|
|
4870
1256
|
}
|
|
4871
1257
|
|
|
1258
|
+
// src/task/WhileTask.ts
|
|
1259
|
+
init_Workflow();
|
|
1260
|
+
init_ConditionUtils();
|
|
1261
|
+
init_GraphAsTask();
|
|
1262
|
+
init_TaskError();
|
|
1263
|
+
|
|
4872
1264
|
// src/task/WhileTaskRunner.ts
|
|
1265
|
+
init_GraphAsTaskRunner();
|
|
1266
|
+
|
|
4873
1267
|
class WhileTaskRunner extends GraphAsTaskRunner {
|
|
4874
1268
|
async executeTask(input) {
|
|
4875
1269
|
const result = await this.task.execute(input, {
|
|
@@ -5425,8 +1819,8 @@ import {
|
|
|
5425
1819
|
JobQueueServer
|
|
5426
1820
|
} from "@workglow/job-queue";
|
|
5427
1821
|
import { InMemoryQueueStorage } from "@workglow/storage";
|
|
5428
|
-
import { createServiceToken
|
|
5429
|
-
var JOB_QUEUE_FACTORY =
|
|
1822
|
+
import { createServiceToken, globalServiceRegistry } from "@workglow/util";
|
|
1823
|
+
var JOB_QUEUE_FACTORY = createServiceToken("taskgraph.jobQueueFactory");
|
|
5430
1824
|
var defaultJobQueueFactory = async ({
|
|
5431
1825
|
queueName,
|
|
5432
1826
|
jobClass,
|
|
@@ -5453,7 +1847,7 @@ var defaultJobQueueFactory = async ({
|
|
|
5453
1847
|
return { server, client, storage };
|
|
5454
1848
|
};
|
|
5455
1849
|
function registerJobQueueFactory(factory) {
|
|
5456
|
-
|
|
1850
|
+
globalServiceRegistry.registerInstance(JOB_QUEUE_FACTORY, factory);
|
|
5457
1851
|
}
|
|
5458
1852
|
function createJobQueueFactoryWithOptions(defaultOptions = {}) {
|
|
5459
1853
|
return async ({
|
|
@@ -5487,16 +1881,18 @@ function createJobQueueFactoryWithOptions(defaultOptions = {}) {
|
|
|
5487
1881
|
};
|
|
5488
1882
|
}
|
|
5489
1883
|
function getJobQueueFactory() {
|
|
5490
|
-
if (!
|
|
1884
|
+
if (!globalServiceRegistry.has(JOB_QUEUE_FACTORY)) {
|
|
5491
1885
|
registerJobQueueFactory(defaultJobQueueFactory);
|
|
5492
1886
|
}
|
|
5493
|
-
return
|
|
1887
|
+
return globalServiceRegistry.get(JOB_QUEUE_FACTORY);
|
|
5494
1888
|
}
|
|
5495
|
-
if (!
|
|
1889
|
+
if (!globalServiceRegistry.has(JOB_QUEUE_FACTORY)) {
|
|
5496
1890
|
registerJobQueueFactory(defaultJobQueueFactory);
|
|
5497
1891
|
}
|
|
5498
1892
|
// src/task/JobQueueTask.ts
|
|
1893
|
+
init_GraphAsTask();
|
|
5499
1894
|
import { Job as Job2 } from "@workglow/job-queue";
|
|
1895
|
+
init_TaskError();
|
|
5500
1896
|
|
|
5501
1897
|
// src/task/TaskQueueRegistry.ts
|
|
5502
1898
|
var taskQueueRegistry = null;
|
|
@@ -5693,6 +2089,7 @@ class JobQueueTask extends GraphAsTask {
|
|
|
5693
2089
|
}
|
|
5694
2090
|
}
|
|
5695
2091
|
// src/task/MapTask.ts
|
|
2092
|
+
init_TaskGraphRunner();
|
|
5696
2093
|
var mapTaskConfigSchema = {
|
|
5697
2094
|
type: "object",
|
|
5698
2095
|
properties: {
|
|
@@ -5768,11 +2165,13 @@ class MapTask extends IteratorTask {
|
|
|
5768
2165
|
return flattened;
|
|
5769
2166
|
}
|
|
5770
2167
|
}
|
|
5771
|
-
queueMicrotask(() => {
|
|
5772
|
-
Workflow
|
|
5773
|
-
|
|
2168
|
+
queueMicrotask(async () => {
|
|
2169
|
+
const { CreateLoopWorkflow: CreateLoopWorkflow3, CreateEndLoopWorkflow: CreateEndLoopWorkflow2, Workflow: Workflow2 } = await import("./Workflow-wrs2y87g.js");
|
|
2170
|
+
Workflow2.prototype.map = CreateLoopWorkflow3(MapTask);
|
|
2171
|
+
Workflow2.prototype.endMap = CreateEndLoopWorkflow2("endMap");
|
|
5774
2172
|
});
|
|
5775
2173
|
// src/task/ReduceTask.ts
|
|
2174
|
+
init_Workflow();
|
|
5776
2175
|
var reduceTaskConfigSchema = {
|
|
5777
2176
|
type: "object",
|
|
5778
2177
|
properties: {
|
|
@@ -5866,10 +2265,21 @@ queueMicrotask(() => {
|
|
|
5866
2265
|
Workflow.prototype.reduce = CreateLoopWorkflow(ReduceTask);
|
|
5867
2266
|
Workflow.prototype.endReduce = CreateEndLoopWorkflow("endReduce");
|
|
5868
2267
|
});
|
|
2268
|
+
|
|
2269
|
+
// src/task/index.ts
|
|
2270
|
+
init_StreamTypes();
|
|
2271
|
+
init_Task();
|
|
2272
|
+
init_TaskError();
|
|
2273
|
+
|
|
2274
|
+
// src/task/TaskJSON.ts
|
|
2275
|
+
init_Dataflow();
|
|
2276
|
+
init_TaskGraph();
|
|
2277
|
+
init_TaskError();
|
|
2278
|
+
|
|
5869
2279
|
// src/task/TaskRegistry.ts
|
|
5870
2280
|
import {
|
|
5871
|
-
createServiceToken as
|
|
5872
|
-
globalServiceRegistry as
|
|
2281
|
+
createServiceToken as createServiceToken2,
|
|
2282
|
+
globalServiceRegistry as globalServiceRegistry2,
|
|
5873
2283
|
registerInputResolver
|
|
5874
2284
|
} from "@workglow/util";
|
|
5875
2285
|
var taskConstructors = new Map;
|
|
@@ -5881,15 +2291,15 @@ var TaskRegistry = {
|
|
|
5881
2291
|
all: taskConstructors,
|
|
5882
2292
|
registerTask
|
|
5883
2293
|
};
|
|
5884
|
-
var TASK_CONSTRUCTORS =
|
|
5885
|
-
if (!
|
|
5886
|
-
|
|
2294
|
+
var TASK_CONSTRUCTORS = createServiceToken2("task.constructors");
|
|
2295
|
+
if (!globalServiceRegistry2.has(TASK_CONSTRUCTORS)) {
|
|
2296
|
+
globalServiceRegistry2.register(TASK_CONSTRUCTORS, () => TaskRegistry.all, true);
|
|
5887
2297
|
}
|
|
5888
2298
|
function getGlobalTaskConstructors() {
|
|
5889
|
-
return
|
|
2299
|
+
return globalServiceRegistry2.get(TASK_CONSTRUCTORS);
|
|
5890
2300
|
}
|
|
5891
2301
|
function setGlobalTaskConstructors(map) {
|
|
5892
|
-
|
|
2302
|
+
globalServiceRegistry2.registerInstance(TASK_CONSTRUCTORS, map);
|
|
5893
2303
|
}
|
|
5894
2304
|
function getTaskConstructors(registry) {
|
|
5895
2305
|
if (!registry)
|
|
@@ -5911,6 +2321,7 @@ function resolveTaskFromRegistry(id, _format, registry) {
|
|
|
5911
2321
|
registerInputResolver("tasks", resolveTaskFromRegistry);
|
|
5912
2322
|
|
|
5913
2323
|
// src/task/TaskJSON.ts
|
|
2324
|
+
init_GraphAsTask();
|
|
5914
2325
|
var createSingleTaskFromJSON = (item, registry) => {
|
|
5915
2326
|
if (!item.id)
|
|
5916
2327
|
throw new TaskJSONError("Task id required");
|
|
@@ -5966,21 +2377,25 @@ var createGraphFromGraphJSON = (graphJsonObj, registry) => {
|
|
|
5966
2377
|
}
|
|
5967
2378
|
return subGraph;
|
|
5968
2379
|
};
|
|
2380
|
+
|
|
5969
2381
|
// src/task/index.ts
|
|
2382
|
+
init_ConditionalTask();
|
|
2383
|
+
init_TaskTypes();
|
|
2384
|
+
init_GraphAsTask();
|
|
5970
2385
|
var registerBaseTasks = () => {
|
|
5971
2386
|
const tasks = [GraphAsTask, ConditionalTask, FallbackTask, MapTask, WhileTask, ReduceTask];
|
|
5972
2387
|
tasks.map(TaskRegistry.registerTask);
|
|
5973
2388
|
return tasks;
|
|
5974
2389
|
};
|
|
5975
2390
|
// src/storage/TaskGraphRepository.ts
|
|
5976
|
-
import { createServiceToken as
|
|
5977
|
-
var TASK_GRAPH_REPOSITORY =
|
|
2391
|
+
import { createServiceToken as createServiceToken3, EventEmitter } from "@workglow/util";
|
|
2392
|
+
var TASK_GRAPH_REPOSITORY = createServiceToken3("taskgraph.taskGraphRepository");
|
|
5978
2393
|
|
|
5979
2394
|
class TaskGraphRepository {
|
|
5980
2395
|
type = "TaskGraphRepository";
|
|
5981
2396
|
get events() {
|
|
5982
2397
|
if (!this._events) {
|
|
5983
|
-
this._events = new
|
|
2398
|
+
this._events = new EventEmitter;
|
|
5984
2399
|
}
|
|
5985
2400
|
return this._events;
|
|
5986
2401
|
}
|
|
@@ -6048,7 +2463,12 @@ class TaskGraphTabularRepository extends TaskGraphRepository {
|
|
|
6048
2463
|
return await this.tabularRepository.size();
|
|
6049
2464
|
}
|
|
6050
2465
|
}
|
|
2466
|
+
|
|
2467
|
+
// src/common.ts
|
|
2468
|
+
init_TaskOutputRepository();
|
|
2469
|
+
|
|
6051
2470
|
// src/storage/TaskOutputTabularRepository.ts
|
|
2471
|
+
init_TaskOutputRepository();
|
|
6052
2472
|
import { compress, decompress, makeFingerprint } from "@workglow/util";
|
|
6053
2473
|
var TaskOutputSchema = {
|
|
6054
2474
|
type: "object",
|
|
@@ -6138,6 +2558,7 @@ export {
|
|
|
6138
2558
|
serialGraph,
|
|
6139
2559
|
schemaAcceptsArray,
|
|
6140
2560
|
resolveSchemaInputs,
|
|
2561
|
+
resetMethodNameCache,
|
|
6141
2562
|
removeIterationProperties,
|
|
6142
2563
|
registerJobQueueFactory,
|
|
6143
2564
|
registerBaseTasks,
|
|
@@ -6155,6 +2576,7 @@ export {
|
|
|
6155
2576
|
hasVectorOutput,
|
|
6156
2577
|
hasVectorLikeInput,
|
|
6157
2578
|
hasStructuredOutput,
|
|
2579
|
+
graphToWorkflowCode,
|
|
6158
2580
|
graphAsTaskConfigSchema,
|
|
6159
2581
|
getTaskQueueRegistry,
|
|
6160
2582
|
getTaskConstructors,
|
|
@@ -6170,6 +2592,7 @@ export {
|
|
|
6170
2592
|
getInputModeFromSchema,
|
|
6171
2593
|
getGlobalTaskConstructors,
|
|
6172
2594
|
getAppendPortId,
|
|
2595
|
+
formatValue,
|
|
6173
2596
|
findArrayPorts,
|
|
6174
2597
|
filterIterationProperties,
|
|
6175
2598
|
fallbackTaskConfigSchema,
|
|
@@ -6251,4 +2674,4 @@ export {
|
|
|
6251
2674
|
ConditionalTask
|
|
6252
2675
|
};
|
|
6253
2676
|
|
|
6254
|
-
//# debugId=
|
|
2677
|
+
//# debugId=C456BB2ACC871E6964756E2164756E21
|