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