@workglow/task-graph 0.0.125 → 0.1.0

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 (57) hide show
  1. package/README.md +104 -36
  2. package/dist/browser.js +888 -1031
  3. package/dist/browser.js.map +26 -28
  4. package/dist/bun.js +888 -1027
  5. package/dist/bun.js.map +25 -27
  6. package/dist/debug/console/ConsoleFormatters.d.ts.map +1 -1
  7. package/dist/node.js +888 -1027
  8. package/dist/node.js.map +25 -27
  9. package/dist/task/ConditionalTask.d.ts +1 -0
  10. package/dist/task/ConditionalTask.d.ts.map +1 -1
  11. package/dist/task/FallbackTask.d.ts +0 -1
  12. package/dist/task/FallbackTask.d.ts.map +1 -1
  13. package/dist/task/GraphAsTask.d.ts.map +1 -1
  14. package/dist/task/ITask.d.ts +6 -0
  15. package/dist/task/ITask.d.ts.map +1 -1
  16. package/dist/task/InputResolver.d.ts +6 -0
  17. package/dist/task/InputResolver.d.ts.map +1 -1
  18. package/dist/task/IteratorTask.d.ts +11 -0
  19. package/dist/task/IteratorTask.d.ts.map +1 -1
  20. package/dist/task/IteratorTaskRunner.d.ts.map +1 -1
  21. package/dist/task/JobQueueFactory.d.ts +3 -4
  22. package/dist/task/JobQueueFactory.d.ts.map +1 -1
  23. package/dist/task/MapTask.d.ts +4 -0
  24. package/dist/task/MapTask.d.ts.map +1 -1
  25. package/dist/task/ReduceTask.d.ts +4 -0
  26. package/dist/task/ReduceTask.d.ts.map +1 -1
  27. package/dist/task/Task.d.ts +13 -1
  28. package/dist/task/Task.d.ts.map +1 -1
  29. package/dist/task/TaskError.d.ts +23 -0
  30. package/dist/task/TaskError.d.ts.map +1 -1
  31. package/dist/task/TaskEvents.d.ts +1 -1
  32. package/dist/task/TaskEvents.d.ts.map +1 -1
  33. package/dist/task/TaskJSON.d.ts +17 -7
  34. package/dist/task/TaskJSON.d.ts.map +1 -1
  35. package/dist/task/TaskQueueRegistry.d.ts +8 -0
  36. package/dist/task/TaskQueueRegistry.d.ts.map +1 -1
  37. package/dist/task/TaskRunner.d.ts.map +1 -1
  38. package/dist/task/WhileTask.d.ts +1 -0
  39. package/dist/task/WhileTask.d.ts.map +1 -1
  40. package/dist/task/index.d.ts +0 -1
  41. package/dist/task/index.d.ts.map +1 -1
  42. package/dist/task-graph/Conversions.d.ts.map +1 -1
  43. package/dist/task-graph/Dataflow.d.ts +11 -0
  44. package/dist/task-graph/Dataflow.d.ts.map +1 -1
  45. package/dist/task-graph/GraphSchemaUtils.d.ts.map +1 -1
  46. package/dist/task-graph/TaskGraph.d.ts +10 -0
  47. package/dist/task-graph/TaskGraph.d.ts.map +1 -1
  48. package/dist/task-graph/TaskGraphRunner.d.ts +15 -2
  49. package/dist/task-graph/TaskGraphRunner.d.ts.map +1 -1
  50. package/dist/task-graph/Workflow.d.ts.map +1 -1
  51. package/package.json +20 -11
  52. package/src/storage/README.md +51 -5
  53. package/src/task/README.md +0 -17
  54. package/dist/task/JobQueueTask.d.ts +0 -130
  55. package/dist/task/JobQueueTask.d.ts.map +0 -1
  56. package/dist/types.d.ts +0 -8
  57. package/dist/types.d.ts.map +0 -1
package/dist/node.js CHANGED
@@ -1,89 +1,51 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropNames = Object.getOwnPropertyNames;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- function __accessProp(key) {
6
- return this[key];
7
- }
8
- var __toCommonJS = (from) => {
9
- var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
- if (entry)
11
- return entry;
12
- entry = __defProp({}, "__esModule", { value: true });
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (var key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(entry, key))
16
- __defProp(entry, key, {
17
- get: __accessProp.bind(from, key),
18
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
- });
20
- }
21
- __moduleCache.set(from, entry);
22
- return entry;
23
- };
24
- var __moduleCache;
25
- var __returnValue = (v) => v;
26
- function __exportSetter(name, newValue) {
27
- this[name] = __returnValue.bind(null, newValue);
28
- }
29
- var __export = (target, all) => {
30
- for (var name in all)
31
- __defProp(target, name, {
32
- get: all[name],
33
- enumerable: true,
34
- configurable: true,
35
- set: __exportSetter.bind(all, name)
36
- });
37
- };
38
- var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
1
+ // src/task-graph/Dataflow.ts
2
+ import { areSemanticallyCompatible } from "@workglow/util/schema";
3
+ import { EventEmitter } from "@workglow/util";
39
4
 
40
5
  // src/task/TaskTypes.ts
41
- var TaskStatus, TaskConfigSchema;
42
- var init_TaskTypes = __esm(() => {
43
- TaskStatus = {
44
- PENDING: "PENDING",
45
- DISABLED: "DISABLED",
46
- PROCESSING: "PROCESSING",
47
- STREAMING: "STREAMING",
48
- COMPLETED: "COMPLETED",
49
- ABORTING: "ABORTING",
50
- FAILED: "FAILED"
51
- };
52
- TaskConfigSchema = {
53
- type: "object",
54
- properties: {
55
- id: {
56
- "x-ui-hidden": true
57
- },
58
- title: { type: "string" },
59
- description: { type: "string" },
60
- cacheable: { type: "boolean" },
61
- timeout: { type: "number", description: "Max execution time in milliseconds" },
62
- inputSchema: {
63
- type: "object",
64
- properties: {},
65
- additionalProperties: true,
66
- "x-ui-hidden": true
67
- },
68
- outputSchema: {
69
- type: "object",
70
- properties: {},
71
- additionalProperties: true,
72
- "x-ui-hidden": true
73
- },
74
- extras: {
75
- type: "object",
76
- additionalProperties: true,
77
- "x-ui-hidden": true
78
- }
6
+ var TaskStatus = {
7
+ PENDING: "PENDING",
8
+ DISABLED: "DISABLED",
9
+ PROCESSING: "PROCESSING",
10
+ STREAMING: "STREAMING",
11
+ COMPLETED: "COMPLETED",
12
+ ABORTING: "ABORTING",
13
+ FAILED: "FAILED"
14
+ };
15
+ var TaskConfigSchema = {
16
+ type: "object",
17
+ properties: {
18
+ id: {
19
+ "x-ui-hidden": true
79
20
  },
80
- additionalProperties: false
81
- };
82
- });
21
+ title: { type: "string" },
22
+ description: { type: "string" },
23
+ cacheable: { type: "boolean" },
24
+ timeout: { type: "number", description: "Max execution time in milliseconds" },
25
+ inputSchema: {
26
+ type: "object",
27
+ properties: {},
28
+ additionalProperties: true,
29
+ "x-ui-hidden": true
30
+ },
31
+ outputSchema: {
32
+ type: "object",
33
+ properties: {},
34
+ additionalProperties: true,
35
+ "x-ui-hidden": true
36
+ },
37
+ extras: {
38
+ type: "object",
39
+ additionalProperties: true,
40
+ "x-ui-hidden": true
41
+ }
42
+ },
43
+ additionalProperties: false
44
+ };
83
45
 
84
46
  // src/task-graph/Dataflow.ts
85
- import { areSemanticallyCompatible } from "@workglow/util/schema";
86
- import { EventEmitter } from "@workglow/util";
47
+ var DATAFLOW_ALL_PORTS = "*";
48
+ var DATAFLOW_ERROR_PORT = "[error]";
87
49
 
88
50
  class Dataflow {
89
51
  sourceTaskId;
@@ -156,6 +118,7 @@ class Dataflow {
156
118
  this.error = undefined;
157
119
  this.value = undefined;
158
120
  this.stream = undefined;
121
+ this._compatibilityCache = undefined;
159
122
  this.emit("reset");
160
123
  this.emit("status", this.status);
161
124
  }
@@ -216,9 +179,19 @@ class Dataflow {
216
179
  targetTaskPortId: this.targetTaskPortId
217
180
  };
218
181
  }
182
+ _compatibilityCache;
183
+ invalidateCompatibilityCache() {
184
+ this._compatibilityCache = undefined;
185
+ }
219
186
  semanticallyCompatible(graph, dataflow) {
220
- const targetSchema = graph.getTask(dataflow.targetTaskId).inputSchema();
221
- const sourceSchema = graph.getTask(dataflow.sourceTaskId).outputSchema();
187
+ const sourceTask = graph.getTask(dataflow.sourceTaskId);
188
+ const targetTask = graph.getTask(dataflow.targetTaskId);
189
+ const shouldCache = !(sourceTask.constructor.hasDynamicSchemas ?? true) && !(targetTask.constructor.hasDynamicSchemas ?? true);
190
+ if (shouldCache && this._compatibilityCache !== undefined) {
191
+ return this._compatibilityCache;
192
+ }
193
+ const targetSchema = targetTask.inputSchema();
194
+ const sourceSchema = sourceTask.outputSchema();
222
195
  if (typeof targetSchema === "boolean") {
223
196
  if (targetSchema === false) {
224
197
  return "incompatible";
@@ -239,8 +212,11 @@ class Dataflow {
239
212
  if (sourceSchemaProperty === undefined && sourceSchema.additionalProperties === true) {
240
213
  sourceSchemaProperty = true;
241
214
  }
242
- const semanticallyCompatible = areSemanticallyCompatible(sourceSchemaProperty, targetSchemaProperty);
243
- return semanticallyCompatible;
215
+ const result = areSemanticallyCompatible(sourceSchemaProperty, targetSchemaProperty);
216
+ if (shouldCache) {
217
+ this._compatibilityCache = result;
218
+ }
219
+ return result;
244
220
  }
245
221
  get events() {
246
222
  if (!this._events) {
@@ -268,22 +244,18 @@ class Dataflow {
268
244
  this._events?.emit(name, ...args);
269
245
  }
270
246
  }
271
- var DATAFLOW_ALL_PORTS = "*", DATAFLOW_ERROR_PORT = "[error]", DataflowArrow;
272
- var init_Dataflow = __esm(() => {
273
- init_TaskTypes();
274
- DataflowArrow = class DataflowArrow extends Dataflow {
275
- constructor(dataflow) {
276
- const pattern = /^([a-zA-Z0-9-]+?)\[([a-zA-Z0-9-]+?)\] ==> ([a-zA-Z0-9-]+?)\[([a-zA-Z0-9-]+?)\]$/;
277
- const match = dataflow.match(pattern);
278
- if (!match) {
279
- throw new Error(`Invalid dataflow format: ${dataflow}`);
280
- }
281
- const [, sourceTaskId, sourceTaskPortId, targetTaskId, targetTaskPortId] = match;
282
- super(sourceTaskId, sourceTaskPortId, targetTaskId, targetTaskPortId);
283
- }
284
- };
285
- });
286
247
 
248
+ class DataflowArrow extends Dataflow {
249
+ constructor(dataflow) {
250
+ const pattern = /^([a-zA-Z0-9-]+?)\[([a-zA-Z0-9-]+?)\] ==> ([a-zA-Z0-9-]+?)\[([a-zA-Z0-9-]+?)\]$/;
251
+ const match = dataflow.match(pattern);
252
+ if (!match) {
253
+ throw new Error(`Invalid dataflow format: ${dataflow}`);
254
+ }
255
+ const [, sourceTaskId, sourceTaskPortId, targetTaskId, targetTaskPortId] = match;
256
+ super(sourceTaskId, sourceTaskPortId, targetTaskId, targetTaskPortId);
257
+ }
258
+ }
287
259
  // src/task-graph/GraphSchemaUtils.ts
288
260
  import { uuid4 } from "@workglow/util";
289
261
  function calculateNodeDepths(graph) {
@@ -632,74 +604,28 @@ function addBoundaryNodesToDependencyJson(items, graph) {
632
604
  }
633
605
  return [...prependItems, ...items, ...appendItems];
634
606
  }
635
- var init_GraphSchemaUtils = __esm(() => {
636
- init_Dataflow();
637
- });
607
+ // src/task-graph/TaskGraph.ts
608
+ import { DirectedAcyclicGraph } from "@workglow/util/graph";
609
+ import { EventEmitter as EventEmitter4, uuid4 as uuid44 } from "@workglow/util";
638
610
 
639
- // src/task/TaskError.ts
640
- import { BaseError } from "@workglow/util";
641
- var TaskError, TaskConfigurationError, WorkflowError, TaskAbortedError, TaskTimeoutError, TaskFailedError, JobTaskFailedError, TaskJSONError, TaskInvalidInputError;
642
- var init_TaskError = __esm(() => {
643
- TaskError = class TaskError extends BaseError {
644
- static type = "TaskError";
645
- constructor(message) {
646
- super(message);
647
- }
648
- };
649
- TaskConfigurationError = class TaskConfigurationError extends TaskError {
650
- static type = "TaskConfigurationError";
651
- constructor(message) {
652
- super(message);
653
- }
654
- };
655
- WorkflowError = class WorkflowError extends TaskError {
656
- static type = "WorkflowError";
657
- constructor(message) {
658
- super(message);
659
- }
660
- };
661
- TaskAbortedError = class TaskAbortedError extends TaskError {
662
- static type = "TaskAbortedError";
663
- constructor(message = "Task aborted") {
664
- super(message);
665
- }
666
- };
667
- TaskTimeoutError = class TaskTimeoutError extends TaskAbortedError {
668
- static type = "TaskTimeoutError";
669
- constructor(timeoutMs) {
670
- super(timeoutMs ? `Task timed out after ${timeoutMs}ms` : "Task timed out");
671
- }
672
- };
673
- TaskFailedError = class TaskFailedError extends TaskError {
674
- static type = "TaskFailedError";
675
- constructor(message = "Task failed") {
676
- super(message);
677
- }
678
- };
679
- JobTaskFailedError = class JobTaskFailedError extends TaskFailedError {
680
- static type = "JobTaskFailedError";
681
- jobError;
682
- constructor(err) {
683
- super(String(err));
684
- this.jobError = err;
685
- }
686
- };
687
- TaskJSONError = class TaskJSONError extends TaskError {
688
- static type = "TaskJSONError";
689
- constructor(message = "Error converting JSON to a Task") {
690
- super(message);
691
- }
692
- };
693
- TaskInvalidInputError = class TaskInvalidInputError extends TaskError {
694
- static type = "TaskInvalidInputError";
695
- constructor(message = "Invalid input data") {
696
- super(message);
697
- }
698
- };
699
- });
611
+ // src/task/GraphAsTask.ts
612
+ import { getLogger as getLogger4 } from "@workglow/util";
613
+ import { compileSchema as compileSchema2 } from "@workglow/util/schema";
614
+
615
+ // src/task-graph/TaskGraphRunner.ts
616
+ import {
617
+ collectPropertyValues,
618
+ getLogger as getLogger3,
619
+ getTelemetryProvider as getTelemetryProvider2,
620
+ globalServiceRegistry as globalServiceRegistry2,
621
+ ServiceRegistry as ServiceRegistry2,
622
+ SpanStatusCode as SpanStatusCode2,
623
+ uuid4 as uuid43
624
+ } from "@workglow/util";
700
625
 
701
626
  // src/storage/TaskOutputRepository.ts
702
627
  import { createServiceToken, EventEmitter as EventEmitter2 } from "@workglow/util";
628
+ var TASK_OUTPUT_REPOSITORY = createServiceToken("taskgraph.taskOutputRepository");
703
629
 
704
630
  class TaskOutputRepository {
705
631
  outputCompression;
@@ -726,10 +652,173 @@ class TaskOutputRepository {
726
652
  this._events?.emit(name, ...args);
727
653
  }
728
654
  }
729
- var TASK_OUTPUT_REPOSITORY;
730
- var init_TaskOutputRepository = __esm(() => {
731
- TASK_OUTPUT_REPOSITORY = createServiceToken("taskgraph.taskOutputRepository");
732
- });
655
+
656
+ // src/task/ConditionalTask.ts
657
+ import { getLogger as getLogger2 } from "@workglow/util";
658
+
659
+ // src/task/ConditionUtils.ts
660
+ function evaluateCondition(fieldValue, operator, compareValue) {
661
+ if (fieldValue === null || fieldValue === undefined) {
662
+ switch (operator) {
663
+ case "is_empty":
664
+ return true;
665
+ case "is_not_empty":
666
+ return false;
667
+ case "is_true":
668
+ return false;
669
+ case "is_false":
670
+ return true;
671
+ default:
672
+ return false;
673
+ }
674
+ }
675
+ const strValue = String(fieldValue);
676
+ const numValue = Number(fieldValue);
677
+ switch (operator) {
678
+ case "equals":
679
+ if (!isNaN(numValue) && !isNaN(Number(compareValue))) {
680
+ return numValue === Number(compareValue);
681
+ }
682
+ return strValue === compareValue;
683
+ case "not_equals":
684
+ if (!isNaN(numValue) && !isNaN(Number(compareValue))) {
685
+ return numValue !== Number(compareValue);
686
+ }
687
+ return strValue !== compareValue;
688
+ case "greater_than":
689
+ return numValue > Number(compareValue);
690
+ case "greater_or_equal":
691
+ return numValue >= Number(compareValue);
692
+ case "less_than":
693
+ return numValue < Number(compareValue);
694
+ case "less_or_equal":
695
+ return numValue <= Number(compareValue);
696
+ case "contains":
697
+ return strValue.toLowerCase().includes(compareValue.toLowerCase());
698
+ case "starts_with":
699
+ return strValue.toLowerCase().startsWith(compareValue.toLowerCase());
700
+ case "ends_with":
701
+ return strValue.toLowerCase().endsWith(compareValue.toLowerCase());
702
+ case "is_empty":
703
+ return strValue === "" || Array.isArray(fieldValue) && fieldValue.length === 0;
704
+ case "is_not_empty":
705
+ return strValue !== "" && !(Array.isArray(fieldValue) && fieldValue.length === 0);
706
+ case "is_true":
707
+ return Boolean(fieldValue) === true;
708
+ case "is_false":
709
+ return Boolean(fieldValue) === false;
710
+ default:
711
+ return false;
712
+ }
713
+ }
714
+ function getNestedValue(obj, path) {
715
+ const parts = path.split(".");
716
+ let current = obj;
717
+ for (const part of parts) {
718
+ if (current === null || current === undefined || typeof current !== "object") {
719
+ return;
720
+ }
721
+ current = current[part];
722
+ }
723
+ return current;
724
+ }
725
+
726
+ // src/task/Task.ts
727
+ import { compileSchema } from "@workglow/util/schema";
728
+ import { deepEqual, EventEmitter as EventEmitter3, uuid4 as uuid42 } from "@workglow/util";
729
+
730
+ // src/task/TaskError.ts
731
+ import { BaseError } from "@workglow/util";
732
+
733
+ class TaskError extends BaseError {
734
+ static type = "TaskError";
735
+ taskType;
736
+ taskId;
737
+ constructor(message) {
738
+ super(message);
739
+ }
740
+ }
741
+
742
+ class TaskConfigurationError extends TaskError {
743
+ static type = "TaskConfigurationError";
744
+ constructor(message) {
745
+ super(message);
746
+ }
747
+ }
748
+
749
+ class WorkflowError extends TaskError {
750
+ static type = "WorkflowError";
751
+ constructor(message) {
752
+ super(message);
753
+ }
754
+ }
755
+
756
+ class TaskAbortedError extends TaskError {
757
+ static type = "TaskAbortedError";
758
+ constructor(message = "Task aborted") {
759
+ super(message);
760
+ }
761
+ }
762
+
763
+ class TaskTimeoutError extends TaskAbortedError {
764
+ static type = "TaskTimeoutError";
765
+ constructor(timeoutMs) {
766
+ super(timeoutMs ? `Task timed out after ${timeoutMs}ms` : "Task timed out");
767
+ }
768
+ }
769
+
770
+ class TaskGraphTimeoutError extends TaskTimeoutError {
771
+ static type = "TaskGraphTimeoutError";
772
+ constructor(timeoutMs) {
773
+ super(timeoutMs);
774
+ this.message = timeoutMs ? `Graph execution timed out after ${timeoutMs}ms` : "Graph execution timed out";
775
+ }
776
+ }
777
+
778
+ class TaskFailedError extends TaskError {
779
+ static type = "TaskFailedError";
780
+ constructor(message = "Task failed") {
781
+ super(message);
782
+ }
783
+ }
784
+
785
+ class JobTaskFailedError extends TaskFailedError {
786
+ static type = "JobTaskFailedError";
787
+ jobError;
788
+ constructor(err) {
789
+ super(String(err));
790
+ this.jobError = err;
791
+ }
792
+ }
793
+
794
+ class TaskJSONError extends TaskError {
795
+ static type = "TaskJSONError";
796
+ constructor(message = "Error converting JSON to a Task") {
797
+ super(message);
798
+ }
799
+ }
800
+
801
+ class TaskInvalidInputError extends TaskError {
802
+ static type = "TaskInvalidInputError";
803
+ constructor(message = "Invalid input data") {
804
+ super(message);
805
+ }
806
+ }
807
+
808
+ class TaskSerializationError extends TaskError {
809
+ static type = "TaskSerializationError";
810
+ constructor(taskType) {
811
+ super(`Task "${taskType}" cannot be serialized: config contains non-serializable values. ` + `Use a declarative config alternative or remove function-valued config properties.`);
812
+ }
813
+ }
814
+
815
+ // src/task/TaskRunner.ts
816
+ import {
817
+ getLogger,
818
+ getTelemetryProvider,
819
+ globalServiceRegistry,
820
+ SpanStatusCode
821
+ } from "@workglow/util";
733
822
 
734
823
  // src/task/InputResolver.ts
735
824
  import { getInputResolvers } from "@workglow/util";
@@ -775,6 +864,18 @@ function getFormatPrefix(format) {
775
864
  const colonIndex = format.indexOf(":");
776
865
  return colonIndex >= 0 ? format.substring(0, colonIndex) : format;
777
866
  }
867
+ function schemaHasFormatAnnotations(schema) {
868
+ if (typeof schema === "boolean")
869
+ return false;
870
+ const properties = schema.properties;
871
+ if (!properties || typeof properties !== "object")
872
+ return false;
873
+ for (const propSchema of Object.values(properties)) {
874
+ if (getSchemaFormat(propSchema) !== undefined)
875
+ return true;
876
+ }
877
+ return false;
878
+ }
778
879
  async function resolveSchemaInputs(input, schema, config) {
779
880
  if (typeof schema === "boolean")
780
881
  return input;
@@ -812,7 +913,6 @@ async function resolveSchemaInputs(input, schema, config) {
812
913
  }
813
914
  return resolved;
814
915
  }
815
- var init_InputResolver = () => {};
816
916
 
817
917
  // src/task/StreamTypes.ts
818
918
  function getPortStreamMode(schema, portId) {
@@ -916,11 +1016,6 @@ function hasStructuredOutput(schema) {
916
1016
  }
917
1017
 
918
1018
  // src/task/TaskRunner.ts
919
- import {
920
- getTelemetryProvider,
921
- globalServiceRegistry,
922
- SpanStatusCode
923
- } from "@workglow/util";
924
1019
  function hasRunConfig(i) {
925
1020
  return i !== null && typeof i === "object" && "runConfig" in i;
926
1021
  }
@@ -946,6 +1041,12 @@ class TaskRunner {
946
1041
  await this.handleStart(config);
947
1042
  try {
948
1043
  this.task.setInput(overrides);
1044
+ const configSchema = this.task.constructor.configSchema();
1045
+ if (schemaHasFormatAnnotations(configSchema)) {
1046
+ const source = this.task.originalConfig ?? this.task.config;
1047
+ const resolved = await resolveSchemaInputs({ ...source }, configSchema, { registry: this.registry });
1048
+ Object.assign(this.task.config, resolved);
1049
+ }
949
1050
  const schema = this.task.constructor.inputSchema();
950
1051
  this.task.runInputData = await resolveSchemaInputs(this.task.runInputData, schema, { registry: this.registry });
951
1052
  const inputs = this.task.runInputData;
@@ -959,6 +1060,12 @@ class TaskRunner {
959
1060
  }
960
1061
  let outputs;
961
1062
  const isStreamable = isTaskStreamable(this.task);
1063
+ if (!isStreamable && typeof this.task.executeStream !== "function") {
1064
+ const streamMode = getOutputStreamMode(this.task.outputSchema());
1065
+ if (streamMode !== "none") {
1066
+ getLogger().warn(`Task "${this.task.type}" declares streaming output (x-stream: "${streamMode}") ` + `but does not implement executeStream(). Falling back to non-streaming execute().`);
1067
+ }
1068
+ }
962
1069
  if (this.task.cacheable) {
963
1070
  outputs = await this.outputCache?.getOutput(this.task.type, inputs);
964
1071
  if (outputs) {
@@ -997,6 +1104,12 @@ class TaskRunner {
997
1104
  return this.task.runOutputData;
998
1105
  }
999
1106
  this.task.setInput(overrides);
1107
+ const configSchema = this.task.constructor.configSchema();
1108
+ if (schemaHasFormatAnnotations(configSchema)) {
1109
+ const source = this.task.originalConfig ?? this.task.config;
1110
+ const resolved = await resolveSchemaInputs({ ...source }, configSchema, { registry: this.registry });
1111
+ Object.assign(this.task.config, resolved);
1112
+ }
1000
1113
  const schema = this.task.constructor.inputSchema();
1001
1114
  this.task.runInputData = await resolveSchemaInputs(this.task.runInputData, schema, { registry: this.registry });
1002
1115
  await this.handleStartReactive();
@@ -1225,6 +1338,11 @@ class TaskRunner {
1225
1338
  this.telemetrySpan.end();
1226
1339
  this.telemetrySpan = undefined;
1227
1340
  }
1341
+ if (typeof this.task.cleanup === "function") {
1342
+ try {
1343
+ await this.task.cleanup();
1344
+ } catch {}
1345
+ }
1228
1346
  this.task.emit("abort", this.task.error);
1229
1347
  this.task.emit("status", this.task.status);
1230
1348
  }
@@ -1277,7 +1395,15 @@ class TaskRunner {
1277
1395
  this.task.completedAt = new Date;
1278
1396
  this.task.progress = 100;
1279
1397
  this.task.status = TaskStatus.FAILED;
1280
- this.task.error = err instanceof TaskError ? err : new TaskFailedError(err?.message || "Task failed");
1398
+ if (err instanceof TaskError) {
1399
+ this.task.error = err;
1400
+ } else {
1401
+ this.task.error = new TaskFailedError(`Task "${this.task.type}" (${this.task.id}): ${err?.message || "Task failed"}`);
1402
+ }
1403
+ if (this.task.error instanceof TaskError) {
1404
+ this.task.error.taskType ??= this.task.type;
1405
+ this.task.error.taskId ??= this.task.id;
1406
+ }
1281
1407
  this.abortController = undefined;
1282
1408
  if (this.telemetrySpan) {
1283
1409
  this.telemetrySpan.setStatus(SpanStatusCode.ERROR, this.task.error.message);
@@ -1297,18 +1423,8 @@ class TaskRunner {
1297
1423
  await this.updateProgress(this.task, progress, message, ...args);
1298
1424
  }
1299
1425
  }
1300
- var init_TaskRunner = __esm(() => {
1301
- init_TaskOutputRepository();
1302
- init_Conversions();
1303
- init_InputResolver();
1304
- init_TaskError();
1305
- init_TaskTypes();
1306
- });
1307
1426
 
1308
1427
  // src/task/Task.ts
1309
- import { compileSchema } from "@workglow/util/schema";
1310
- import { deepEqual, EventEmitter as EventEmitter3, uuid4 as uuid42 } from "@workglow/util";
1311
-
1312
1428
  class Task {
1313
1429
  static type = "Task";
1314
1430
  static category = "Hidden";
@@ -1391,6 +1507,7 @@ class Task {
1391
1507
  runInputData = {};
1392
1508
  runOutputData = {};
1393
1509
  config;
1510
+ originalConfig;
1394
1511
  get id() {
1395
1512
  return this.config.id;
1396
1513
  }
@@ -1421,6 +1538,11 @@ class Task {
1421
1538
  baseConfig.id = uuid42();
1422
1539
  }
1423
1540
  this.config = this.validateAndApplyConfigDefaults(baseConfig);
1541
+ try {
1542
+ this.originalConfig = Object.freeze(structuredClone(this.config));
1543
+ } catch {
1544
+ this.originalConfig = undefined;
1545
+ }
1424
1546
  this.runConfig = runConfig;
1425
1547
  }
1426
1548
  getDefaultInputsFromStaticInputDefinitions() {
@@ -1691,7 +1813,10 @@ class Task {
1691
1813
  const path = e.data.pointer || "";
1692
1814
  return `${e.message}${path ? ` (${path})` : ""}`;
1693
1815
  });
1694
- throw new TaskInvalidInputError(`Input ${JSON.stringify(Object.keys(input))} does not match schema: ${errorMessages.join(", ")}`);
1816
+ const err = new TaskInvalidInputError(`Task "${this.type}" (${this.id}): Input ${JSON.stringify(Object.keys(input))} does not match schema: ${errorMessages.join(", ")}`);
1817
+ err.taskType = this.type;
1818
+ err.taskId = this.id;
1819
+ throw err;
1695
1820
  }
1696
1821
  return true;
1697
1822
  }
@@ -1716,8 +1841,14 @@ class Task {
1716
1841
  }
1717
1842
  return obj;
1718
1843
  }
1844
+ canSerializeConfig() {
1845
+ return true;
1846
+ }
1719
1847
  toJSON(_options) {
1720
1848
  const ctor = this.constructor;
1849
+ if (!this.canSerializeConfig() || !this.originalConfig) {
1850
+ throw new TaskSerializationError(this.type);
1851
+ }
1721
1852
  const schema = ctor.configSchema();
1722
1853
  const schemaProperties = typeof schema !== "boolean" && schema?.properties ? schema.properties : {};
1723
1854
  const config = {};
@@ -1727,7 +1858,7 @@ class Task {
1727
1858
  if (propSchema?.["x-ui-hidden"] === true && key !== "inputSchema" && key !== "outputSchema" && key !== "extras") {
1728
1859
  continue;
1729
1860
  }
1730
- const value = this.config[key];
1861
+ const value = this.originalConfig[key];
1731
1862
  if (value === undefined)
1732
1863
  continue;
1733
1864
  if (typeof value === "function" || typeof value === "symbol")
@@ -1788,146 +1919,57 @@ class Task {
1788
1919
  this.events.emit("regenerate");
1789
1920
  }
1790
1921
  }
1791
- var init_Task = __esm(() => {
1792
- init_Dataflow();
1793
- init_TaskGraph();
1794
- init_TaskError();
1795
- init_TaskRunner();
1796
- init_TaskTypes();
1797
- });
1798
-
1799
- // src/task/ConditionUtils.ts
1800
- function evaluateCondition(fieldValue, operator, compareValue) {
1801
- if (fieldValue === null || fieldValue === undefined) {
1802
- switch (operator) {
1803
- case "is_empty":
1804
- return true;
1805
- case "is_not_empty":
1806
- return false;
1807
- case "is_true":
1808
- return false;
1809
- case "is_false":
1810
- return true;
1811
- default:
1812
- return false;
1813
- }
1814
- }
1815
- const strValue = String(fieldValue);
1816
- const numValue = Number(fieldValue);
1817
- switch (operator) {
1818
- case "equals":
1819
- if (!isNaN(numValue) && !isNaN(Number(compareValue))) {
1820
- return numValue === Number(compareValue);
1821
- }
1822
- return strValue === compareValue;
1823
- case "not_equals":
1824
- if (!isNaN(numValue) && !isNaN(Number(compareValue))) {
1825
- return numValue !== Number(compareValue);
1826
- }
1827
- return strValue !== compareValue;
1828
- case "greater_than":
1829
- return numValue > Number(compareValue);
1830
- case "greater_or_equal":
1831
- return numValue >= Number(compareValue);
1832
- case "less_than":
1833
- return numValue < Number(compareValue);
1834
- case "less_or_equal":
1835
- return numValue <= Number(compareValue);
1836
- case "contains":
1837
- return strValue.toLowerCase().includes(compareValue.toLowerCase());
1838
- case "starts_with":
1839
- return strValue.toLowerCase().startsWith(compareValue.toLowerCase());
1840
- case "ends_with":
1841
- return strValue.toLowerCase().endsWith(compareValue.toLowerCase());
1842
- case "is_empty":
1843
- return strValue === "" || Array.isArray(fieldValue) && fieldValue.length === 0;
1844
- case "is_not_empty":
1845
- return strValue !== "" && !(Array.isArray(fieldValue) && fieldValue.length === 0);
1846
- case "is_true":
1847
- return Boolean(fieldValue) === true;
1848
- case "is_false":
1849
- return Boolean(fieldValue) === false;
1850
- default:
1851
- return false;
1852
- }
1853
- }
1854
- function getNestedValue(obj, path) {
1855
- const parts = path.split(".");
1856
- let current = obj;
1857
- for (const part of parts) {
1858
- if (current === null || current === undefined || typeof current !== "object") {
1859
- return;
1860
- }
1861
- current = current[part];
1862
- }
1863
- return current;
1864
- }
1865
1922
 
1866
1923
  // src/task/ConditionalTask.ts
1867
- import { getLogger } from "@workglow/util";
1868
- var conditionalTaskConfigSchema, ConditionalTask;
1869
- var init_ConditionalTask = __esm(() => {
1870
- init_Task();
1871
- init_TaskTypes();
1872
- conditionalTaskConfigSchema = {
1873
- type: "object",
1874
- properties: {
1875
- ...TaskConfigSchema["properties"],
1876
- branches: { type: "array", items: {} },
1877
- defaultBranch: { type: "string" },
1878
- exclusive: { type: "boolean" },
1879
- conditionConfig: { type: "object", additionalProperties: true }
1880
- },
1881
- additionalProperties: false
1882
- };
1883
- ConditionalTask = class ConditionalTask extends Task {
1884
- static type = "ConditionalTask";
1885
- static category = "Flow Control";
1886
- static title = "Condition";
1887
- static description = "Route data based on conditions";
1888
- static hasDynamicSchemas = true;
1889
- static configSchema() {
1890
- return conditionalTaskConfigSchema;
1891
- }
1892
- activeBranches = new Set;
1893
- buildBranchesFromConditionConfig(conditionConfig) {
1894
- if (!conditionConfig?.branches || conditionConfig.branches.length === 0) {
1895
- return [
1896
- {
1897
- id: "default",
1898
- condition: () => true,
1899
- outputPort: "1"
1900
- }
1901
- ];
1902
- }
1903
- return conditionConfig.branches.map((branch, index) => ({
1904
- id: branch.id,
1905
- outputPort: String(index + 1),
1906
- condition: (inputData) => {
1907
- const fieldValue = getNestedValue(inputData, branch.field);
1908
- return evaluateCondition(fieldValue, branch.operator, branch.value);
1924
+ var conditionalTaskConfigSchema = {
1925
+ type: "object",
1926
+ properties: {
1927
+ ...TaskConfigSchema["properties"],
1928
+ branches: { type: "array", items: {} },
1929
+ defaultBranch: { type: "string" },
1930
+ exclusive: { type: "boolean" },
1931
+ conditionConfig: { type: "object", additionalProperties: true }
1932
+ },
1933
+ additionalProperties: false
1934
+ };
1935
+
1936
+ class ConditionalTask extends Task {
1937
+ static type = "ConditionalTask";
1938
+ static category = "Flow Control";
1939
+ static title = "Condition";
1940
+ static description = "Route data based on conditions";
1941
+ static hasDynamicSchemas = true;
1942
+ static configSchema() {
1943
+ return conditionalTaskConfigSchema;
1944
+ }
1945
+ canSerializeConfig() {
1946
+ if (!this.config.branches)
1947
+ return true;
1948
+ return !this.config.branches.some((b) => typeof b.condition === "function");
1949
+ }
1950
+ activeBranches = new Set;
1951
+ buildBranchesFromConditionConfig(conditionConfig) {
1952
+ if (!conditionConfig?.branches || conditionConfig.branches.length === 0) {
1953
+ return [
1954
+ {
1955
+ id: "default",
1956
+ condition: () => true,
1957
+ outputPort: "1"
1909
1958
  }
1910
- }));
1959
+ ];
1911
1960
  }
1912
- resolveBranches(input) {
1913
- const configBranches = this.config.branches ?? [];
1914
- if (configBranches.length > 0 && typeof configBranches[0].condition === "function") {
1915
- return {
1916
- branches: configBranches,
1917
- isExclusive: this.config.exclusive ?? true,
1918
- defaultBranch: this.config.defaultBranch,
1919
- fromConditionConfig: false
1920
- };
1921
- }
1922
- const conditionConfig = input.conditionConfig ?? this.config.conditionConfig;
1923
- if (conditionConfig) {
1924
- return {
1925
- branches: this.buildBranchesFromConditionConfig(conditionConfig),
1926
- isExclusive: conditionConfig.exclusive ?? true,
1927
- defaultBranch: conditionConfig.defaultBranch,
1928
- fromConditionConfig: true
1929
- };
1961
+ return conditionConfig.branches.map((branch, index) => ({
1962
+ id: branch.id,
1963
+ outputPort: String(index + 1),
1964
+ condition: (inputData) => {
1965
+ const fieldValue = getNestedValue(inputData, branch.field);
1966
+ return evaluateCondition(fieldValue, branch.operator, branch.value);
1930
1967
  }
1968
+ }));
1969
+ }
1970
+ resolveBranches(input) {
1971
+ const configBranches = this.config.branches ?? [];
1972
+ if (configBranches.length > 0 && typeof configBranches[0].condition === "function") {
1931
1973
  return {
1932
1974
  branches: configBranches,
1933
1975
  isExclusive: this.config.exclusive ?? true,
@@ -1935,146 +1977,161 @@ var init_ConditionalTask = __esm(() => {
1935
1977
  fromConditionConfig: false
1936
1978
  };
1937
1979
  }
1938
- async execute(input, context) {
1939
- if (context.signal?.aborted) {
1940
- return;
1941
- }
1942
- this.activeBranches.clear();
1943
- const { branches, isExclusive, defaultBranch, fromConditionConfig } = this.resolveBranches(input);
1944
- for (const branch of branches) {
1945
- try {
1946
- const isActive = branch.condition(input);
1947
- if (isActive) {
1948
- this.activeBranches.add(branch.id);
1949
- if (isExclusive) {
1950
- break;
1951
- }
1980
+ const conditionConfig = input.conditionConfig ?? this.config.conditionConfig;
1981
+ if (conditionConfig) {
1982
+ return {
1983
+ branches: this.buildBranchesFromConditionConfig(conditionConfig),
1984
+ isExclusive: conditionConfig.exclusive ?? true,
1985
+ defaultBranch: conditionConfig.defaultBranch,
1986
+ fromConditionConfig: true
1987
+ };
1988
+ }
1989
+ return {
1990
+ branches: configBranches,
1991
+ isExclusive: this.config.exclusive ?? true,
1992
+ defaultBranch: this.config.defaultBranch,
1993
+ fromConditionConfig: false
1994
+ };
1995
+ }
1996
+ async execute(input, context) {
1997
+ if (context.signal?.aborted) {
1998
+ return;
1999
+ }
2000
+ this.activeBranches.clear();
2001
+ const { branches, isExclusive, defaultBranch, fromConditionConfig } = this.resolveBranches(input);
2002
+ for (const branch of branches) {
2003
+ try {
2004
+ const isActive = branch.condition(input);
2005
+ if (isActive) {
2006
+ this.activeBranches.add(branch.id);
2007
+ if (isExclusive) {
2008
+ break;
1952
2009
  }
1953
- } catch (error) {
1954
- getLogger().warn(`Condition evaluation failed for branch "${branch.id}":`, { error });
1955
- }
1956
- }
1957
- if (this.activeBranches.size === 0 && defaultBranch) {
1958
- const defaultBranchExists = branches.some((b) => b.id === defaultBranch);
1959
- if (defaultBranchExists) {
1960
- this.activeBranches.add(defaultBranch);
1961
2010
  }
2011
+ } catch (error) {
2012
+ getLogger2().warn(`Condition evaluation failed for branch "${branch.id}":`, { error });
1962
2013
  }
1963
- if (fromConditionConfig) {
1964
- return this.buildConditionConfigOutput(input, branches, isExclusive);
2014
+ }
2015
+ if (this.activeBranches.size === 0 && defaultBranch) {
2016
+ const defaultBranchExists = branches.some((b) => b.id === defaultBranch);
2017
+ if (defaultBranchExists) {
2018
+ this.activeBranches.add(defaultBranch);
1965
2019
  }
1966
- return this.buildOutput(input);
1967
2020
  }
1968
- buildConditionConfigOutput(input, branches, isExclusive) {
1969
- const output = {};
1970
- const { conditionConfig, ...passThrough } = input;
1971
- const inputKeys = Object.keys(passThrough);
1972
- let matchedBranchNumber = null;
1973
- for (let i = 0;i < branches.length; i++) {
1974
- if (this.activeBranches.has(branches[i].id)) {
1975
- if (matchedBranchNumber === null) {
1976
- matchedBranchNumber = i + 1;
1977
- }
2021
+ if (fromConditionConfig) {
2022
+ return this.buildConditionConfigOutput(input, branches, isExclusive);
2023
+ }
2024
+ return this.buildOutput(input);
2025
+ }
2026
+ buildConditionConfigOutput(input, branches, isExclusive) {
2027
+ const output = {};
2028
+ const { conditionConfig, ...passThrough } = input;
2029
+ const inputKeys = Object.keys(passThrough);
2030
+ let matchedBranchNumber = null;
2031
+ for (let i = 0;i < branches.length; i++) {
2032
+ if (this.activeBranches.has(branches[i].id)) {
2033
+ if (matchedBranchNumber === null) {
2034
+ matchedBranchNumber = i + 1;
1978
2035
  }
1979
2036
  }
1980
- if (isExclusive) {
1981
- if (matchedBranchNumber !== null) {
1982
- for (const key of inputKeys) {
1983
- output[`${key}_${matchedBranchNumber}`] = passThrough[key];
1984
- }
1985
- } else {
1986
- for (const key of inputKeys) {
1987
- output[`${key}_else`] = passThrough[key];
1988
- }
2037
+ }
2038
+ if (isExclusive) {
2039
+ if (matchedBranchNumber !== null) {
2040
+ for (const key of inputKeys) {
2041
+ output[`${key}_${matchedBranchNumber}`] = passThrough[key];
1989
2042
  }
1990
2043
  } else {
1991
- for (let i = 0;i < branches.length; i++) {
1992
- if (this.activeBranches.has(branches[i].id)) {
1993
- for (const key of inputKeys) {
1994
- output[`${key}_${i + 1}`] = passThrough[key];
1995
- }
1996
- }
2044
+ for (const key of inputKeys) {
2045
+ output[`${key}_else`] = passThrough[key];
1997
2046
  }
1998
2047
  }
1999
- return output;
2000
- }
2001
- buildOutput(input) {
2002
- const output = {
2003
- _activeBranches: Array.from(this.activeBranches)
2004
- };
2005
- const branches = this.config.branches ?? [];
2006
- for (const branch of branches) {
2007
- if (this.activeBranches.has(branch.id)) {
2008
- output[branch.outputPort] = { ...input };
2048
+ } else {
2049
+ for (let i = 0;i < branches.length; i++) {
2050
+ if (this.activeBranches.has(branches[i].id)) {
2051
+ for (const key of inputKeys) {
2052
+ output[`${key}_${i + 1}`] = passThrough[key];
2053
+ }
2009
2054
  }
2010
2055
  }
2011
- return output;
2012
- }
2013
- isBranchActive(branchId) {
2014
- return this.activeBranches.has(branchId);
2015
- }
2016
- getActiveBranches() {
2017
- return new Set(this.activeBranches);
2018
2056
  }
2019
- getPortActiveStatus() {
2020
- const status = new Map;
2021
- const branches = this.config.branches ?? [];
2022
- for (const branch of branches) {
2023
- status.set(branch.outputPort, this.activeBranches.has(branch.id));
2057
+ return output;
2058
+ }
2059
+ buildOutput(input) {
2060
+ const output = {
2061
+ _activeBranches: Array.from(this.activeBranches)
2062
+ };
2063
+ const branches = this.config.branches ?? [];
2064
+ for (const branch of branches) {
2065
+ if (this.activeBranches.has(branch.id)) {
2066
+ output[branch.outputPort] = { ...input };
2024
2067
  }
2025
- return status;
2026
2068
  }
2027
- static outputSchema() {
2028
- return {
2029
- type: "object",
2030
- properties: {
2031
- _activeBranches: {
2032
- type: "array",
2033
- items: { type: "string" },
2034
- description: "List of active branch IDs after condition evaluation"
2035
- }
2036
- },
2037
- additionalProperties: true
2038
- };
2069
+ return output;
2070
+ }
2071
+ isBranchActive(branchId) {
2072
+ return this.activeBranches.has(branchId);
2073
+ }
2074
+ getActiveBranches() {
2075
+ return new Set(this.activeBranches);
2076
+ }
2077
+ getPortActiveStatus() {
2078
+ const status = new Map;
2079
+ const branches = this.config.branches ?? [];
2080
+ for (const branch of branches) {
2081
+ status.set(branch.outputPort, this.activeBranches.has(branch.id));
2039
2082
  }
2040
- outputSchema() {
2041
- const branches = this.config?.branches ?? [];
2042
- const properties = {
2083
+ return status;
2084
+ }
2085
+ static outputSchema() {
2086
+ return {
2087
+ type: "object",
2088
+ properties: {
2043
2089
  _activeBranches: {
2044
2090
  type: "array",
2045
2091
  items: { type: "string" },
2046
2092
  description: "List of active branch IDs after condition evaluation"
2047
2093
  }
2048
- };
2049
- for (const branch of branches) {
2050
- properties[branch.outputPort] = {
2051
- type: "object",
2052
- description: `Output for branch "${branch.id}" when active`,
2053
- additionalProperties: true
2054
- };
2094
+ },
2095
+ additionalProperties: true
2096
+ };
2097
+ }
2098
+ outputSchema() {
2099
+ const branches = this.config?.branches ?? [];
2100
+ const properties = {
2101
+ _activeBranches: {
2102
+ type: "array",
2103
+ items: { type: "string" },
2104
+ description: "List of active branch IDs after condition evaluation"
2055
2105
  }
2056
- return {
2057
- type: "object",
2058
- properties,
2059
- additionalProperties: false
2060
- };
2061
- }
2062
- static inputSchema() {
2063
- return {
2064
- type: "object",
2065
- properties: {},
2066
- additionalProperties: true
2067
- };
2068
- }
2069
- inputSchema() {
2070
- return {
2106
+ };
2107
+ for (const branch of branches) {
2108
+ properties[branch.outputPort] = {
2071
2109
  type: "object",
2072
- properties: {},
2110
+ description: `Output for branch "${branch.id}" when active`,
2073
2111
  additionalProperties: true
2074
2112
  };
2075
2113
  }
2076
- };
2077
- });
2114
+ return {
2115
+ type: "object",
2116
+ properties,
2117
+ additionalProperties: false
2118
+ };
2119
+ }
2120
+ static inputSchema() {
2121
+ return {
2122
+ type: "object",
2123
+ properties: {},
2124
+ additionalProperties: true
2125
+ };
2126
+ }
2127
+ inputSchema() {
2128
+ return {
2129
+ type: "object",
2130
+ properties: {},
2131
+ additionalProperties: true
2132
+ };
2133
+ }
2134
+ }
2078
2135
 
2079
2136
  // src/task-graph/TaskGraphScheduler.ts
2080
2137
  class TopologicalScheduler {
@@ -2219,24 +2276,14 @@ class DependencyBasedScheduler {
2219
2276
  this.nextResolver = null;
2220
2277
  }
2221
2278
  }
2222
- var init_TaskGraphScheduler = __esm(() => {
2223
- init_TaskTypes();
2224
- });
2225
2279
 
2226
2280
  // src/task-graph/TaskGraphRunner.ts
2227
- import {
2228
- collectPropertyValues,
2229
- getLogger as getLogger2,
2230
- getTelemetryProvider as getTelemetryProvider2,
2231
- globalServiceRegistry as globalServiceRegistry2,
2232
- ServiceRegistry as ServiceRegistry2,
2233
- SpanStatusCode as SpanStatusCode2,
2234
- uuid4 as uuid43
2235
- } from "@workglow/util";
2236
2281
  function taskPrototypeHasOwnExecute(task) {
2237
2282
  const Ctor = task.constructor;
2238
2283
  return Object.hasOwn(Ctor.prototype, "execute");
2239
2284
  }
2285
+ var PROPERTY_ARRAY = "PROPERTY_ARRAY";
2286
+ var GRAPH_RESULT_ARRAY = "GRAPH_RESULT_ARRAY";
2240
2287
 
2241
2288
  class TaskGraphRunner {
2242
2289
  processScheduler;
@@ -2252,6 +2299,8 @@ class TaskGraphRunner {
2252
2299
  inProgressFunctions = new Map;
2253
2300
  failedTaskErrors = new Map;
2254
2301
  telemetrySpan;
2302
+ graphTimeoutTimer;
2303
+ pendingGraphTimeoutError;
2255
2304
  constructor(graph, outputCache, processScheduler = new DependencyBasedScheduler(graph), reactiveScheduler = new TopologicalScheduler(graph)) {
2256
2305
  this.processScheduler = processScheduler;
2257
2306
  this.reactiveScheduler = reactiveScheduler;
@@ -2302,10 +2351,14 @@ class TaskGraphRunner {
2302
2351
  }
2303
2352
  } catch (err) {
2304
2353
  error = err;
2305
- getLogger2().error("Error running graph", { error });
2354
+ getLogger3().error("Error running graph", { error });
2306
2355
  }
2307
2356
  await Promise.allSettled(Array.from(this.inProgressTasks.values()));
2308
2357
  await Promise.allSettled(Array.from(this.inProgressFunctions.values()));
2358
+ if (this.pendingGraphTimeoutError) {
2359
+ await this.handleAbort();
2360
+ throw this.pendingGraphTimeoutError;
2361
+ }
2309
2362
  if (this.failedTaskErrors.size > 0) {
2310
2363
  const latestError = this.failedTaskErrors.values().next().value;
2311
2364
  this.handleError(latestError);
@@ -2393,6 +2446,7 @@ class TaskGraphRunner {
2393
2446
  }
2394
2447
  copyInputFromEdgesToNode(task) {
2395
2448
  const dataflows = this.graph.getSourceDataflows(task.id);
2449
+ dataflows.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
2396
2450
  for (const dataflow of dataflows) {
2397
2451
  this.addInputData(task, dataflow.getPortData());
2398
2452
  }
@@ -2401,7 +2455,7 @@ class TaskGraphRunner {
2401
2455
  const dataflows = this.graph.getTargetDataflows(node.id);
2402
2456
  for (const dataflow of dataflows) {
2403
2457
  const compatibility = dataflow.semanticallyCompatible(this.graph, dataflow);
2404
- getLogger2().debug("pushOutputFromNodeToEdges", {
2458
+ getLogger3().debug("pushOutputFromNodeToEdges", {
2405
2459
  dataflowId: dataflow.id,
2406
2460
  compatibility,
2407
2461
  resultsKeys: Object.keys(results)
@@ -2415,7 +2469,7 @@ class TaskGraphRunner {
2415
2469
  } else {
2416
2470
  const resultsKeys = Object.keys(results);
2417
2471
  if (resultsKeys.length > 0) {
2418
- getLogger2().warn("pushOutputFromNodeToEdge not compatible, not setting port data", {
2472
+ getLogger3().warn("pushOutputFromNodeToEdge not compatible, not setting port data", {
2419
2473
  dataflowId: dataflow.id,
2420
2474
  compatibility,
2421
2475
  resultsKeys
@@ -2721,6 +2775,12 @@ class TaskGraphRunner {
2721
2775
  }
2722
2776
  this.graph.outputCache = this.outputCache;
2723
2777
  }
2778
+ if (config?.maxTasks !== undefined && config.maxTasks > 0) {
2779
+ const taskCount = this.graph.getTasks().length;
2780
+ if (taskCount > config.maxTasks) {
2781
+ throw new TaskConfigurationError(`Graph has ${taskCount} tasks, exceeding the limit of ${config.maxTasks}`);
2782
+ }
2783
+ }
2724
2784
  if (this.running || this.reactiveRunning) {
2725
2785
  throw new TaskConfigurationError("Graph is already running");
2726
2786
  }
@@ -2729,6 +2789,13 @@ class TaskGraphRunner {
2729
2789
  this.abortController.signal.addEventListener("abort", () => {
2730
2790
  this.handleAbort();
2731
2791
  });
2792
+ if (config?.timeout !== undefined && config.timeout > 0) {
2793
+ this.pendingGraphTimeoutError = undefined;
2794
+ this.graphTimeoutTimer = setTimeout(() => {
2795
+ this.pendingGraphTimeoutError = new TaskGraphTimeoutError(config.timeout);
2796
+ this.abortController?.abort();
2797
+ }, config.timeout);
2798
+ }
2732
2799
  if (config?.parentSignal?.aborted) {
2733
2800
  this.abortController.abort();
2734
2801
  return;
@@ -2762,10 +2829,23 @@ class TaskGraphRunner {
2762
2829
  if (config?.registry !== undefined) {
2763
2830
  this.registry = config.registry;
2764
2831
  }
2832
+ if (config?.maxTasks !== undefined && config.maxTasks > 0) {
2833
+ const taskCount = this.graph.getTasks().length;
2834
+ if (taskCount > config.maxTasks) {
2835
+ throw new TaskConfigurationError(`Graph has ${taskCount} tasks, exceeding the limit of ${config.maxTasks}`);
2836
+ }
2837
+ }
2765
2838
  this.reactiveScheduler.reset();
2766
2839
  this.reactiveRunning = true;
2767
2840
  }
2841
+ clearGraphTimeout() {
2842
+ if (this.graphTimeoutTimer !== undefined) {
2843
+ clearTimeout(this.graphTimeoutTimer);
2844
+ this.graphTimeoutTimer = undefined;
2845
+ }
2846
+ }
2768
2847
  async handleComplete() {
2848
+ this.clearGraphTimeout();
2769
2849
  this.running = false;
2770
2850
  if (this.telemetrySpan) {
2771
2851
  this.telemetrySpan.setStatus(SpanStatusCode2.OK);
@@ -2778,6 +2858,7 @@ class TaskGraphRunner {
2778
2858
  this.reactiveRunning = false;
2779
2859
  }
2780
2860
  async handleError(error) {
2861
+ this.clearGraphTimeout();
2781
2862
  await Promise.allSettled(this.graph.getTasks().map(async (task) => {
2782
2863
  if (task.status === TaskStatus.PROCESSING || task.status === TaskStatus.STREAMING) {
2783
2864
  return task.abort();
@@ -2796,6 +2877,7 @@ class TaskGraphRunner {
2796
2877
  this.reactiveRunning = false;
2797
2878
  }
2798
2879
  async handleAbort() {
2880
+ this.clearGraphTimeout();
2799
2881
  await Promise.allSettled(this.graph.getTasks().map(async (task) => {
2800
2882
  if (task.status === TaskStatus.PROCESSING || task.status === TaskStatus.STREAMING) {
2801
2883
  return task.abort();
@@ -2838,254 +2920,231 @@ class TaskGraphRunner {
2838
2920
  }
2839
2921
  }
2840
2922
  }
2841
- var PROPERTY_ARRAY = "PROPERTY_ARRAY", GRAPH_RESULT_ARRAY = "GRAPH_RESULT_ARRAY";
2842
- var init_TaskGraphRunner = __esm(() => {
2843
- init_TaskOutputRepository();
2844
- init_ConditionalTask();
2845
- init_TaskError();
2846
- init_TaskTypes();
2847
- init_Dataflow();
2848
- init_TaskGraphScheduler();
2849
- });
2850
2923
 
2851
2924
  // src/task/GraphAsTaskRunner.ts
2852
- var GraphAsTaskRunner;
2853
- var init_GraphAsTaskRunner = __esm(() => {
2854
- init_TaskRunner();
2855
- GraphAsTaskRunner = class GraphAsTaskRunner extends TaskRunner {
2856
- async executeTaskChildren(input) {
2857
- const unsubscribe = this.task.subGraph.subscribe("graph_progress", (progress, message, ...args) => {
2858
- this.task.emit("progress", progress, message, ...args);
2859
- });
2860
- const results = await this.task.subGraph.run(input, {
2861
- parentSignal: this.abortController?.signal,
2862
- outputCache: this.outputCache,
2863
- registry: this.registry
2864
- });
2865
- unsubscribe();
2866
- return results;
2867
- }
2868
- async executeTaskChildrenReactive() {
2869
- return this.task.subGraph.runReactive(this.task.runInputData, {
2870
- registry: this.registry
2871
- });
2872
- }
2873
- async handleDisable() {
2874
- if (this.task.hasChildren()) {
2875
- await this.task.subGraph.disable();
2876
- }
2877
- super.handleDisable();
2925
+ class GraphAsTaskRunner extends TaskRunner {
2926
+ async executeTaskChildren(input) {
2927
+ const unsubscribe = this.task.subGraph.subscribe("graph_progress", (progress, message, ...args) => {
2928
+ this.task.emit("progress", progress, message, ...args);
2929
+ });
2930
+ const results = await this.task.subGraph.run(input, {
2931
+ parentSignal: this.abortController?.signal,
2932
+ outputCache: this.outputCache,
2933
+ registry: this.registry
2934
+ });
2935
+ unsubscribe();
2936
+ return results;
2937
+ }
2938
+ async executeTaskChildrenReactive() {
2939
+ return this.task.subGraph.runReactive(this.task.runInputData, {
2940
+ registry: this.registry
2941
+ });
2942
+ }
2943
+ async handleDisable() {
2944
+ if (this.task.hasChildren()) {
2945
+ await this.task.subGraph.disable();
2878
2946
  }
2879
- async executeTask(input) {
2880
- if (this.task.hasChildren()) {
2881
- const runExecuteOutputData = await this.executeTaskChildren(input);
2882
- this.task.runOutputData = this.task.subGraph.mergeExecuteOutputsToRunOutput(runExecuteOutputData, this.task.compoundMerge);
2883
- } else {
2884
- const result = await super.executeTask(input);
2885
- this.task.runOutputData = result ?? {};
2886
- }
2887
- return this.task.runOutputData;
2947
+ super.handleDisable();
2948
+ }
2949
+ async executeTask(input) {
2950
+ if (this.task.hasChildren()) {
2951
+ const runExecuteOutputData = await this.executeTaskChildren(input);
2952
+ this.task.runOutputData = this.task.subGraph.mergeExecuteOutputsToRunOutput(runExecuteOutputData, this.task.compoundMerge);
2953
+ } else {
2954
+ const result = await super.executeTask(input);
2955
+ this.task.runOutputData = result ?? {};
2888
2956
  }
2889
- async executeTaskReactive(input, output) {
2890
- if (this.task.hasChildren()) {
2891
- const reactiveResults = await this.executeTaskChildrenReactive();
2892
- this.task.runOutputData = this.task.subGraph.mergeExecuteOutputsToRunOutput(reactiveResults, this.task.compoundMerge);
2893
- } else {
2894
- const reactiveResults = await super.executeTaskReactive(input, output);
2895
- this.task.runOutputData = Object.assign({}, output, reactiveResults ?? {});
2896
- }
2897
- return this.task.runOutputData;
2957
+ return this.task.runOutputData;
2958
+ }
2959
+ async executeTaskReactive(input, output) {
2960
+ if (this.task.hasChildren()) {
2961
+ const reactiveResults = await this.executeTaskChildrenReactive();
2962
+ this.task.runOutputData = this.task.subGraph.mergeExecuteOutputsToRunOutput(reactiveResults, this.task.compoundMerge);
2963
+ } else {
2964
+ const reactiveResults = await super.executeTaskReactive(input, output);
2965
+ this.task.runOutputData = Object.assign({}, output, reactiveResults ?? {});
2898
2966
  }
2899
- };
2900
- });
2967
+ return this.task.runOutputData;
2968
+ }
2969
+ }
2901
2970
 
2902
2971
  // src/task/GraphAsTask.ts
2903
- var exports_GraphAsTask = {};
2904
- __export(exports_GraphAsTask, {
2905
- graphAsTaskConfigSchema: () => graphAsTaskConfigSchema,
2906
- GraphAsTask: () => GraphAsTask
2907
- });
2908
- import { compileSchema as compileSchema2 } from "@workglow/util/schema";
2909
- var graphAsTaskConfigSchema, GraphAsTask;
2910
- var init_GraphAsTask = __esm(() => {
2911
- init_GraphSchemaUtils();
2912
- init_TaskGraphRunner();
2913
- init_GraphAsTaskRunner();
2914
- init_Task();
2915
- init_TaskTypes();
2916
- graphAsTaskConfigSchema = {
2917
- type: "object",
2918
- properties: {
2919
- ...TaskConfigSchema["properties"],
2920
- compoundMerge: { type: "string", "x-ui-hidden": true }
2921
- },
2922
- additionalProperties: false
2923
- };
2924
- GraphAsTask = class GraphAsTask extends Task {
2925
- static type = "GraphAsTask";
2926
- static title = "Group";
2927
- static description = "A group of tasks that are executed together";
2928
- static category = "Flow Control";
2929
- static compoundMerge = PROPERTY_ARRAY;
2930
- static hasDynamicSchemas = true;
2931
- constructor(input = {}, config = {}) {
2932
- const { subGraph, ...rest } = config;
2933
- super(input, rest);
2934
- if (subGraph) {
2935
- this.subGraph = subGraph;
2936
- }
2937
- this.regenerateGraph();
2972
+ var graphAsTaskConfigSchema = {
2973
+ type: "object",
2974
+ properties: {
2975
+ ...TaskConfigSchema["properties"],
2976
+ compoundMerge: { type: "string", "x-ui-hidden": true }
2977
+ },
2978
+ additionalProperties: false
2979
+ };
2980
+
2981
+ class GraphAsTask extends Task {
2982
+ static type = "GraphAsTask";
2983
+ static title = "Group";
2984
+ static description = "A group of tasks that are executed together";
2985
+ static category = "Flow Control";
2986
+ static compoundMerge = PROPERTY_ARRAY;
2987
+ static hasDynamicSchemas = true;
2988
+ constructor(input = {}, config = {}) {
2989
+ const { subGraph, ...rest } = config;
2990
+ super(input, rest);
2991
+ if (subGraph) {
2992
+ this.subGraph = subGraph;
2938
2993
  }
2939
- get runner() {
2940
- if (!this._runner) {
2941
- this._runner = new GraphAsTaskRunner(this);
2942
- }
2943
- return this._runner;
2994
+ this.regenerateGraph();
2995
+ }
2996
+ get runner() {
2997
+ if (!this._runner) {
2998
+ this._runner = new GraphAsTaskRunner(this);
2944
2999
  }
2945
- static configSchema() {
2946
- return graphAsTaskConfigSchema;
3000
+ return this._runner;
3001
+ }
3002
+ static configSchema() {
3003
+ return graphAsTaskConfigSchema;
3004
+ }
3005
+ get compoundMerge() {
3006
+ return this.config?.compoundMerge || this.constructor.compoundMerge;
3007
+ }
3008
+ get cacheable() {
3009
+ return this.runConfig?.cacheable ?? this.config?.cacheable ?? (this.constructor.cacheable && !this.hasChildren());
3010
+ }
3011
+ inputSchema() {
3012
+ if (!this.hasChildren()) {
3013
+ return this.constructor.inputSchema();
2947
3014
  }
2948
- get compoundMerge() {
2949
- return this.config?.compoundMerge || this.constructor.compoundMerge;
3015
+ return computeGraphInputSchema(this.subGraph);
3016
+ }
3017
+ _inputSchemaNode;
3018
+ getInputSchemaNode() {
3019
+ if (!this._inputSchemaNode) {
3020
+ try {
3021
+ const dataPortSchema = this.inputSchema();
3022
+ const schemaNode = Task.generateInputSchemaNode(dataPortSchema);
3023
+ this._inputSchemaNode = schemaNode;
3024
+ } catch (error) {
3025
+ getLogger4().warn(`GraphAsTask "${this.type}" (${this.id}): Failed to compile input schema, ` + `falling back to permissive validation. Inputs will NOT be validated.`, { error, taskType: this.type, taskId: this.id });
3026
+ this._inputSchemaNode = compileSchema2({});
3027
+ }
2950
3028
  }
2951
- get cacheable() {
2952
- return this.runConfig?.cacheable ?? this.config?.cacheable ?? (this.constructor.cacheable && !this.hasChildren());
3029
+ return this._inputSchemaNode;
3030
+ }
3031
+ outputSchema() {
3032
+ if (!this.hasChildren()) {
3033
+ return this.constructor.outputSchema();
2953
3034
  }
2954
- inputSchema() {
2955
- if (!this.hasChildren()) {
2956
- return this.constructor.inputSchema();
2957
- }
2958
- return computeGraphInputSchema(this.subGraph);
3035
+ return computeGraphOutputSchema(this.subGraph);
3036
+ }
3037
+ resetInputData() {
3038
+ super.resetInputData();
3039
+ if (this.hasChildren()) {
3040
+ this.subGraph.getTasks().forEach((node) => {
3041
+ node.resetInputData();
3042
+ });
3043
+ this.subGraph.getDataflows().forEach((dataflow) => {
3044
+ dataflow.reset();
3045
+ });
2959
3046
  }
2960
- _inputSchemaNode;
2961
- getInputSchemaNode() {
2962
- if (!this._inputSchemaNode) {
3047
+ }
3048
+ async* executeStream(input, context) {
3049
+ if (context.inputStreams) {
3050
+ for (const [, stream] of context.inputStreams) {
3051
+ const reader = stream.getReader();
2963
3052
  try {
2964
- const dataPortSchema = this.inputSchema();
2965
- const schemaNode = Task.generateInputSchemaNode(dataPortSchema);
2966
- this._inputSchemaNode = schemaNode;
2967
- } catch (error) {
2968
- console.warn(`Failed to compile input schema for ${this.type}, falling back to permissive validation:`, error);
2969
- this._inputSchemaNode = compileSchema2({});
3053
+ while (true) {
3054
+ const { done, value } = await reader.read();
3055
+ if (done)
3056
+ break;
3057
+ if (value.type === "finish")
3058
+ continue;
3059
+ yield value;
3060
+ }
3061
+ } finally {
3062
+ reader.releaseLock();
2970
3063
  }
2971
3064
  }
2972
- return this._inputSchemaNode;
2973
- }
2974
- outputSchema() {
2975
- if (!this.hasChildren()) {
2976
- return this.constructor.outputSchema();
2977
- }
2978
- return computeGraphOutputSchema(this.subGraph);
2979
- }
2980
- resetInputData() {
2981
- super.resetInputData();
2982
- if (this.hasChildren()) {
2983
- this.subGraph.getTasks().forEach((node) => {
2984
- node.resetInputData();
2985
- });
2986
- this.subGraph.getDataflows().forEach((dataflow) => {
2987
- dataflow.reset();
2988
- });
2989
- }
2990
3065
  }
2991
- async* executeStream(input, context) {
2992
- if (context.inputStreams) {
2993
- for (const [, stream] of context.inputStreams) {
2994
- const reader = stream.getReader();
2995
- try {
2996
- while (true) {
2997
- const { done, value } = await reader.read();
2998
- if (done)
2999
- break;
3000
- if (value.type === "finish")
3001
- continue;
3002
- yield value;
3003
- }
3004
- } finally {
3005
- reader.releaseLock();
3006
- }
3066
+ if (this.hasChildren()) {
3067
+ const endingNodeIds = new Set;
3068
+ const tasks = this.subGraph.getTasks();
3069
+ for (const task of tasks) {
3070
+ if (this.subGraph.getTargetDataflows(task.id).length === 0) {
3071
+ endingNodeIds.add(task.id);
3007
3072
  }
3008
3073
  }
3009
- if (this.hasChildren()) {
3010
- const endingNodeIds = new Set;
3011
- const tasks = this.subGraph.getTasks();
3012
- for (const task of tasks) {
3013
- if (this.subGraph.getTargetDataflows(task.id).length === 0) {
3014
- endingNodeIds.add(task.id);
3074
+ const eventQueue = [];
3075
+ let resolveWaiting;
3076
+ let subgraphDone = false;
3077
+ const unsub = this.subGraph.subscribeToTaskStreaming({
3078
+ onStreamChunk: (taskId, event) => {
3079
+ if (endingNodeIds.has(taskId) && event.type !== "finish") {
3080
+ eventQueue.push(event);
3081
+ resolveWaiting?.();
3015
3082
  }
3016
3083
  }
3017
- const eventQueue = [];
3018
- let resolveWaiting;
3019
- let subgraphDone = false;
3020
- const unsub = this.subGraph.subscribeToTaskStreaming({
3021
- onStreamChunk: (taskId, event) => {
3022
- if (endingNodeIds.has(taskId) && event.type !== "finish") {
3023
- eventQueue.push(event);
3024
- resolveWaiting?.();
3025
- }
3026
- }
3027
- });
3028
- const runPromise = this.subGraph.run(input, { parentSignal: context.signal, accumulateLeafOutputs: false }).then((results2) => {
3029
- subgraphDone = true;
3030
- resolveWaiting?.();
3031
- return results2;
3032
- });
3033
- while (!subgraphDone) {
3034
- if (eventQueue.length === 0) {
3035
- await new Promise((resolve) => {
3036
- resolveWaiting = resolve;
3037
- });
3038
- }
3039
- while (eventQueue.length > 0) {
3040
- yield eventQueue.shift();
3041
- }
3084
+ });
3085
+ const runPromise = this.subGraph.run(input, { parentSignal: context.signal, accumulateLeafOutputs: false }).then((results2) => {
3086
+ subgraphDone = true;
3087
+ resolveWaiting?.();
3088
+ return results2;
3089
+ });
3090
+ while (!subgraphDone) {
3091
+ if (eventQueue.length === 0) {
3092
+ await new Promise((resolve) => {
3093
+ resolveWaiting = resolve;
3094
+ });
3042
3095
  }
3043
3096
  while (eventQueue.length > 0) {
3044
3097
  yield eventQueue.shift();
3045
3098
  }
3046
- unsub();
3047
- const results = await runPromise;
3048
- const mergedOutput = this.subGraph.mergeExecuteOutputsToRunOutput(results, this.compoundMerge);
3049
- yield { type: "finish", data: mergedOutput };
3050
- } else {
3051
- yield { type: "finish", data: input };
3052
3099
  }
3053
- }
3054
- regenerateGraph() {
3055
- this._inputSchemaNode = undefined;
3056
- this.events.emit("regenerate");
3057
- }
3058
- toJSON(options) {
3059
- let json = super.toJSON(options);
3060
- const hasChildren = this.hasChildren();
3061
- if (hasChildren) {
3062
- json = {
3063
- ...json,
3064
- merge: this.compoundMerge,
3065
- subgraph: this.subGraph.toJSON(options)
3066
- };
3100
+ while (eventQueue.length > 0) {
3101
+ yield eventQueue.shift();
3067
3102
  }
3068
- return json;
3103
+ unsub();
3104
+ const results = await runPromise;
3105
+ const mergedOutput = this.subGraph.mergeExecuteOutputsToRunOutput(results, this.compoundMerge);
3106
+ yield { type: "finish", data: mergedOutput };
3107
+ } else {
3108
+ yield { type: "finish", data: input };
3069
3109
  }
3070
- toDependencyJSON(options) {
3071
- const json = this.toJSON(options);
3072
- if (this.hasChildren()) {
3073
- if ("subgraph" in json) {
3074
- delete json.subgraph;
3075
- }
3076
- return { ...json, subtasks: this.subGraph.toDependencyJSON(options) };
3110
+ }
3111
+ regenerateGraph() {
3112
+ this._inputSchemaNode = undefined;
3113
+ this.events.emit("regenerate");
3114
+ }
3115
+ toJSON(options) {
3116
+ let json = super.toJSON(options);
3117
+ const hasChildren = this.hasChildren();
3118
+ if (hasChildren) {
3119
+ json = {
3120
+ ...json,
3121
+ merge: this.compoundMerge,
3122
+ subgraph: this.subGraph.toJSON(options)
3123
+ };
3124
+ }
3125
+ return json;
3126
+ }
3127
+ toDependencyJSON(options) {
3128
+ const json = this.toJSON(options);
3129
+ if (this.hasChildren()) {
3130
+ if ("subgraph" in json) {
3131
+ delete json.subgraph;
3077
3132
  }
3078
- return json;
3133
+ return { ...json, subtasks: this.subGraph.toDependencyJSON(options) };
3079
3134
  }
3080
- };
3081
- });
3135
+ return json;
3136
+ }
3137
+ }
3082
3138
 
3083
3139
  // src/task-graph/Conversions.ts
3140
+ var _OwnGraphTask;
3141
+ var _OwnWorkflowTask;
3142
+ var _GraphTask;
3143
+ var _ConvWorkflowTask;
3084
3144
  function getWrapperClasses() {
3085
3145
  if (!_OwnGraphTask) {
3086
- const GaT = (init_GraphAsTask(), __toCommonJS(exports_GraphAsTask)).GraphAsTask;
3087
3146
 
3088
- class ListeningGraphAsTask extends GaT {
3147
+ class ListeningGraphAsTask extends GraphAsTask {
3089
3148
  constructor(input, config) {
3090
3149
  super(input, config);
3091
3150
  this.subGraph.on("start", () => {
@@ -3108,11 +3167,11 @@ function getWrapperClasses() {
3108
3167
  static type = "Own[Workflow]";
3109
3168
  }
3110
3169
 
3111
- class GraphTask extends GaT {
3170
+ class GraphTask extends GraphAsTask {
3112
3171
  static type = "Graph";
3113
3172
  }
3114
3173
 
3115
- class ConvWorkflowTask extends GaT {
3174
+ class ConvWorkflowTask extends GraphAsTask {
3116
3175
  static type = "Workflow";
3117
3176
  }
3118
3177
  _OwnGraphTask = OwnGraphTask;
@@ -3177,37 +3236,31 @@ function ensureTask(arg, config = {}) {
3177
3236
  }
3178
3237
  return convertPipeFunctionToTask(arg, config);
3179
3238
  }
3180
- var _OwnGraphTask, _OwnWorkflowTask, _GraphTask, _ConvWorkflowTask;
3181
- var init_Conversions = __esm(() => {
3182
- init_Task();
3183
- init_Dataflow();
3184
- init_TaskGraph();
3185
- });
3186
3239
 
3187
3240
  // src/task-graph/TaskGraphEvents.ts
3188
- var EventDagToTaskGraphMapping, EventTaskGraphToDagMapping;
3189
- var init_TaskGraphEvents = __esm(() => {
3190
- EventDagToTaskGraphMapping = {
3191
- "node-added": "task_added",
3192
- "node-removed": "task_removed",
3193
- "node-replaced": "task_replaced",
3194
- "edge-added": "dataflow_added",
3195
- "edge-removed": "dataflow_removed",
3196
- "edge-replaced": "dataflow_replaced"
3197
- };
3198
- EventTaskGraphToDagMapping = {
3199
- task_added: "node-added",
3200
- task_removed: "node-removed",
3201
- task_replaced: "node-replaced",
3202
- dataflow_added: "edge-added",
3203
- dataflow_removed: "edge-removed",
3204
- dataflow_replaced: "edge-replaced"
3205
- };
3206
- });
3241
+ var EventDagToTaskGraphMapping = {
3242
+ "node-added": "task_added",
3243
+ "node-removed": "task_removed",
3244
+ "node-replaced": "task_replaced",
3245
+ "edge-added": "dataflow_added",
3246
+ "edge-removed": "dataflow_removed",
3247
+ "edge-replaced": "dataflow_replaced"
3248
+ };
3249
+ var EventTaskGraphToDagMapping = {
3250
+ task_added: "node-added",
3251
+ task_removed: "node-removed",
3252
+ task_replaced: "node-replaced",
3253
+ dataflow_added: "edge-added",
3254
+ dataflow_removed: "edge-removed",
3255
+ dataflow_replaced: "edge-replaced"
3256
+ };
3207
3257
 
3208
3258
  // src/task-graph/TaskGraph.ts
3209
- import { DirectedAcyclicGraph } from "@workglow/util/graph";
3210
- import { EventEmitter as EventEmitter4, uuid4 as uuid44 } from "@workglow/util";
3259
+ class TaskGraphDAG extends DirectedAcyclicGraph {
3260
+ constructor() {
3261
+ super((task) => task.id, (dataflow) => dataflow.id);
3262
+ }
3263
+ }
3211
3264
 
3212
3265
  class TaskGraph {
3213
3266
  outputCache;
@@ -3228,7 +3281,9 @@ class TaskGraph {
3228
3281
  outputCache: config?.outputCache || this.outputCache,
3229
3282
  parentSignal: config?.parentSignal || undefined,
3230
3283
  accumulateLeafOutputs: config?.accumulateLeafOutputs,
3231
- registry: config?.registry
3284
+ registry: config?.registry,
3285
+ timeout: config?.timeout,
3286
+ maxTasks: config?.maxTasks
3232
3287
  });
3233
3288
  }
3234
3289
  runReactive(input = {}, config = {}) {
@@ -3268,18 +3323,12 @@ class TaskGraph {
3268
3323
  return this._dag.addEdges(addedEdges);
3269
3324
  }
3270
3325
  getDataflow(id) {
3271
- for (const i in this._dag.adjacency) {
3272
- for (const j in this._dag.adjacency[i]) {
3273
- const maybeEdges = this._dag.adjacency[i][j];
3274
- if (maybeEdges !== null) {
3275
- for (const edge of maybeEdges) {
3276
- if (this._dag.edgeIdentity(edge, "", "") == id) {
3277
- return edge;
3278
- }
3279
- }
3280
- }
3326
+ for (const [, , edge] of this._dag.getEdges()) {
3327
+ if (edge.id === id) {
3328
+ return edge;
3281
3329
  }
3282
3330
  }
3331
+ return;
3283
3332
  }
3284
3333
  getDataflows() {
3285
3334
  return this._dag.getEdges().map((edge) => edge[2]);
@@ -3467,9 +3516,9 @@ class TaskGraph {
3467
3516
  emit(name, ...args) {
3468
3517
  const dagEvent = EventTaskGraphToDagMapping[name];
3469
3518
  if (dagEvent) {
3470
- return this.emit_dag(name, ...args);
3519
+ return this.emit_dag.call(this, name, ...args);
3471
3520
  } else {
3472
- return this.emit_local(name, ...args);
3521
+ return this.emit_local.call(this, name, ...args);
3473
3522
  }
3474
3523
  }
3475
3524
  emit_local(name, ...args) {
@@ -3493,41 +3542,10 @@ function serialGraph(tasks, inputHandle, outputHandle) {
3493
3542
  graph.addDataflows(serialGraphEdges(tasks, inputHandle, outputHandle));
3494
3543
  return graph;
3495
3544
  }
3496
- var TaskGraphDAG;
3497
- var init_TaskGraph = __esm(() => {
3498
- init_Conversions();
3499
- init_Dataflow();
3500
- init_GraphSchemaUtils();
3501
- init_TaskGraphEvents();
3502
- init_TaskGraphRunner();
3503
- TaskGraphDAG = class TaskGraphDAG extends DirectedAcyclicGraph {
3504
- constructor() {
3505
- super((task) => task.id, (dataflow) => dataflow.id);
3506
- }
3507
- };
3508
- });
3509
-
3510
- // src/common.ts
3511
- init_Dataflow();
3512
- init_GraphSchemaUtils();
3513
- init_TaskGraph();
3514
- init_TaskGraphEvents();
3515
- init_TaskGraphRunner();
3516
- init_Conversions();
3517
-
3518
- // src/task-graph/GraphToWorkflowCode.ts
3519
- init_Dataflow();
3520
-
3521
3545
  // src/task-graph/Workflow.ts
3522
- init_GraphAsTask();
3523
- init_TaskError();
3524
- init_Conversions();
3525
- init_Dataflow();
3526
- init_TaskGraph();
3527
- init_TaskGraphRunner();
3528
3546
  import {
3529
3547
  EventEmitter as EventEmitter5,
3530
- getLogger as getLogger3,
3548
+ getLogger as getLogger5,
3531
3549
  uuid4 as uuid45
3532
3550
  } from "@workglow/util";
3533
3551
  function getLastTask(workflow) {
@@ -3675,7 +3693,7 @@ class Workflow {
3675
3693
  const taskSchema = task.inputSchema();
3676
3694
  if (typeof taskSchema !== "boolean" && taskSchema.properties?.[dataflow.targetTaskPortId] === undefined && taskSchema.additionalProperties !== true || taskSchema === true && dataflow.targetTaskPortId !== DATAFLOW_ALL_PORTS) {
3677
3695
  this._error = `Input ${dataflow.targetTaskPortId} not found on task ${task.id}`;
3678
- getLogger3().error(this._error);
3696
+ getLogger5().error(this._error);
3679
3697
  return;
3680
3698
  }
3681
3699
  dataflow.targetTaskId = task.id;
@@ -3700,10 +3718,10 @@ class Workflow {
3700
3718
  if (result.error) {
3701
3719
  if (this.isLoopBuilder) {
3702
3720
  this._error = result.error;
3703
- getLogger3().warn(this._error);
3721
+ getLogger5().warn(this._error);
3704
3722
  } else {
3705
3723
  this._error = result.error + " Task not added.";
3706
- getLogger3().error(this._error);
3724
+ getLogger5().error(this._error);
3707
3725
  this.graph.removeTask(task.id);
3708
3726
  }
3709
3727
  }
@@ -3791,7 +3809,7 @@ class Workflow {
3791
3809
  const nodes = this._graph.getTasks();
3792
3810
  if (nodes.length === 0) {
3793
3811
  this._error = "No tasks to remove";
3794
- getLogger3().error(this._error);
3812
+ getLogger5().error(this._error);
3795
3813
  return this;
3796
3814
  }
3797
3815
  const lastNode = nodes[nodes.length - 1];
@@ -3822,7 +3840,7 @@ class Workflow {
3822
3840
  if (-index > nodes.length) {
3823
3841
  const errorMsg = `Back index greater than number of tasks`;
3824
3842
  this._error = errorMsg;
3825
- getLogger3().error(this._error);
3843
+ getLogger5().error(this._error);
3826
3844
  throw new WorkflowError(errorMsg);
3827
3845
  }
3828
3846
  const lastNode = nodes[nodes.length + index];
@@ -3831,13 +3849,13 @@ class Workflow {
3831
3849
  if (outputSchema === false && source !== DATAFLOW_ALL_PORTS) {
3832
3850
  const errorMsg = `Task ${lastNode.id} has schema 'false' and outputs nothing`;
3833
3851
  this._error = errorMsg;
3834
- getLogger3().error(this._error);
3852
+ getLogger5().error(this._error);
3835
3853
  throw new WorkflowError(errorMsg);
3836
3854
  }
3837
3855
  } else if (!outputSchema.properties?.[source] && source !== DATAFLOW_ALL_PORTS) {
3838
3856
  const errorMsg = `Output ${source} not found on task ${lastNode.id}`;
3839
3857
  this._error = errorMsg;
3840
- getLogger3().error(this._error);
3858
+ getLogger5().error(this._error);
3841
3859
  throw new WorkflowError(errorMsg);
3842
3860
  }
3843
3861
  this._dataFlows.push(new Dataflow(lastNode.id, source, undefined, target));
@@ -3848,7 +3866,7 @@ class Workflow {
3848
3866
  const parent = getLastTask(this);
3849
3867
  if (!parent) {
3850
3868
  this._error = "onError() requires a preceding task in the workflow";
3851
- getLogger3().error(this._error);
3869
+ getLogger5().error(this._error);
3852
3870
  throw new WorkflowError(this._error);
3853
3871
  }
3854
3872
  const handlerTask = ensureTask(handler);
@@ -3946,7 +3964,7 @@ class Workflow {
3946
3964
  const taskSchema = task.inputSchema();
3947
3965
  if (typeof taskSchema !== "boolean" && taskSchema.properties?.[dataflow.targetTaskPortId] === undefined && taskSchema.additionalProperties !== true || taskSchema === true && dataflow.targetTaskPortId !== DATAFLOW_ALL_PORTS) {
3948
3966
  this._error = `Input ${dataflow.targetTaskPortId} not found on task ${task.id}`;
3949
- getLogger3().error(this._error);
3967
+ getLogger5().error(this._error);
3950
3968
  return;
3951
3969
  }
3952
3970
  dataflow.targetTaskId = task.id;
@@ -3976,7 +3994,7 @@ class Workflow {
3976
3994
  });
3977
3995
  if (result.error) {
3978
3996
  this._error = result.error + " Task not added.";
3979
- getLogger3().error(this._error);
3997
+ getLogger5().error(this._error);
3980
3998
  this.graph.removeTask(iteratorTask.id);
3981
3999
  }
3982
4000
  }
@@ -4616,17 +4634,7 @@ ${baseIndent}}`;
4616
4634
  function resetMethodNameCache() {
4617
4635
  methodNameCache = undefined;
4618
4636
  }
4619
- // src/task/index.ts
4620
- init_ConditionalTask();
4621
-
4622
- // src/task/FallbackTask.ts
4623
- init_GraphAsTask();
4624
-
4625
4637
  // src/task/FallbackTaskRunner.ts
4626
- init_GraphAsTaskRunner();
4627
- init_TaskError();
4628
- init_TaskTypes();
4629
-
4630
4638
  class FallbackTaskRunner extends GraphAsTaskRunner {
4631
4639
  async executeTask(input) {
4632
4640
  if (this.task.fallbackMode === "data") {
@@ -4825,27 +4833,18 @@ queueMicrotask(() => {
4825
4833
  };
4826
4834
  Workflow.prototype.endFallbackWith = CreateEndLoopWorkflow("endFallbackWith");
4827
4835
  });
4828
-
4829
- // src/task/index.ts
4830
- init_GraphAsTask();
4831
- init_GraphAsTaskRunner();
4832
- init_InputResolver();
4833
-
4834
- // src/task/IteratorTask.ts
4835
- init_GraphAsTask();
4836
-
4837
4836
  // src/task/IteratorTaskRunner.ts
4838
- init_Dataflow();
4839
- init_TaskGraph();
4840
- init_GraphAsTaskRunner();
4841
4837
  import { uuid4 as uuid46 } from "@workglow/util";
4842
-
4843
4838
  class IteratorTaskRunner extends GraphAsTaskRunner {
4844
4839
  aggregatingParentMapProgress = false;
4845
4840
  mapPartialProgress = [];
4846
4841
  mapPartialIterationCount = 0;
4847
4842
  async executeTask(input) {
4848
- const analysis = this.task.analyzeIterationInput(input);
4843
+ let analysis = this.task.analyzeIterationInput(input);
4844
+ const maxIterations = this.task.config.maxIterations;
4845
+ if (maxIterations !== undefined && maxIterations > 0 && analysis.iterationCount > maxIterations) {
4846
+ analysis = { ...analysis, iterationCount: maxIterations };
4847
+ }
4849
4848
  if (analysis.iterationCount === 0) {
4850
4849
  const emptyResult = this.task.getEmptyResult();
4851
4850
  return this.executeTaskReactive(input, emptyResult);
@@ -5005,7 +5004,6 @@ class IteratorTaskRunner extends GraphAsTaskRunner {
5005
5004
  }
5006
5005
 
5007
5006
  // src/task/IteratorTask.ts
5008
- init_TaskError();
5009
5007
  var ITERATOR_CONTEXT_SCHEMA = {
5010
5008
  type: "object",
5011
5009
  properties: {
@@ -5031,6 +5029,7 @@ var iteratorTaskConfigSchema = {
5031
5029
  ...graphAsTaskConfigSchema["properties"],
5032
5030
  concurrencyLimit: { type: "integer", minimum: 1 },
5033
5031
  batchSize: { type: "integer", minimum: 1 },
5032
+ maxIterations: { type: "integer", minimum: 1 },
5034
5033
  iterationInputConfig: { type: "object", additionalProperties: true }
5035
5034
  },
5036
5035
  additionalProperties: false
@@ -5099,22 +5098,29 @@ function extractBaseSchema(schema) {
5099
5098
  }
5100
5099
  const variants = schema.oneOf ?? schema.anyOf;
5101
5100
  if (Array.isArray(variants)) {
5101
+ let hasScalar = false;
5102
+ let hasArray = false;
5103
+ let scalarVariant;
5104
+ let arrayVariant;
5102
5105
  for (const variant of variants) {
5103
5106
  if (typeof variant === "object") {
5104
- const variantType = variant.type;
5105
- if (variantType !== "array") {
5106
- return variant;
5107
+ const v = variant;
5108
+ if (v.type === "array" || "items" in v) {
5109
+ hasArray = true;
5110
+ arrayVariant = variant;
5111
+ } else {
5112
+ hasScalar = true;
5113
+ scalarVariant = variant;
5107
5114
  }
5108
5115
  }
5109
5116
  }
5110
- for (const variant of variants) {
5111
- if (typeof variant === "object") {
5112
- const variantType = variant.type;
5113
- if (variantType === "array" && variant.items) {
5114
- return variant.items;
5115
- }
5116
- }
5117
+ if (hasScalar && hasArray && variants.length === 2) {
5118
+ return scalarVariant;
5119
+ }
5120
+ if (!hasScalar && hasArray && arrayVariant) {
5121
+ return arrayVariant.items;
5117
5122
  }
5123
+ return schema;
5118
5124
  }
5119
5125
  return schema;
5120
5126
  }
@@ -5497,13 +5503,7 @@ class IteratorTask extends GraphAsTask {
5497
5503
  }
5498
5504
  }
5499
5505
 
5500
- // src/task/WhileTask.ts
5501
- init_GraphAsTask();
5502
- init_TaskError();
5503
-
5504
5506
  // src/task/WhileTaskRunner.ts
5505
- init_GraphAsTaskRunner();
5506
-
5507
5507
  class WhileTaskRunner extends GraphAsTaskRunner {
5508
5508
  async executeTask(input) {
5509
5509
  const result = await this.task.execute(input, {
@@ -5561,6 +5561,9 @@ class WhileTask extends GraphAsTask {
5561
5561
  return WHILE_CONTEXT_SCHEMA;
5562
5562
  }
5563
5563
  _currentIteration = 0;
5564
+ canSerializeConfig() {
5565
+ return typeof this.config.condition !== "function";
5566
+ }
5564
5567
  constructor(input = {}, config = {}) {
5565
5568
  super(input, config);
5566
5569
  }
@@ -5682,7 +5685,27 @@ class WhileTask extends GraphAsTask {
5682
5685
  parentSignal: context.signal
5683
5686
  });
5684
5687
  currentOutput = this.subGraph.mergeExecuteOutputsToRunOutput(results, this.compoundMerge);
5685
- if (!condition(currentOutput, this._currentIteration)) {
5688
+ let shouldContinue;
5689
+ try {
5690
+ shouldContinue = condition(currentOutput, this._currentIteration);
5691
+ } catch (err) {
5692
+ if (err instanceof TaskFailedError) {
5693
+ throw err;
5694
+ }
5695
+ const message = `${this.type}: Condition function threw at iteration ${this._currentIteration}: ${err instanceof Error ? err.message : String(err)}`;
5696
+ const wrappedError = new TaskFailedError(message);
5697
+ if (err instanceof Error && err.stack) {
5698
+ if (wrappedError.stack) {
5699
+ wrappedError.stack += `
5700
+ Caused by original error:
5701
+ ${err.stack}`;
5702
+ } else {
5703
+ wrappedError.stack = err.stack;
5704
+ }
5705
+ }
5706
+ throw wrappedError;
5707
+ }
5708
+ if (!shouldContinue) {
5686
5709
  break;
5687
5710
  }
5688
5711
  if (this.chainIterations) {
@@ -5726,7 +5749,13 @@ class WhileTask extends GraphAsTask {
5726
5749
  parentSignal: context.signal
5727
5750
  });
5728
5751
  currentOutput = this.subGraph.mergeExecuteOutputsToRunOutput(results, this.compoundMerge);
5729
- if (!condition(currentOutput, this._currentIteration)) {
5752
+ let shouldContinue;
5753
+ try {
5754
+ shouldContinue = condition(currentOutput, this._currentIteration);
5755
+ } catch (err) {
5756
+ throw new TaskFailedError(`${this.type}: Condition function threw at iteration ${this._currentIteration}: ${err instanceof Error ? err.message : String(err)}`);
5757
+ }
5758
+ if (!shouldContinue) {
5730
5759
  break;
5731
5760
  }
5732
5761
  if (this.chainIterations) {
@@ -6129,209 +6158,7 @@ function getJobQueueFactory() {
6129
6158
  if (!globalServiceRegistry3.has(JOB_QUEUE_FACTORY)) {
6130
6159
  registerJobQueueFactory(defaultJobQueueFactory);
6131
6160
  }
6132
- // src/task/JobQueueTask.ts
6133
- init_GraphAsTask();
6134
- import { Job as Job2 } from "@workglow/job-queue";
6135
- init_TaskError();
6136
-
6137
- // src/task/TaskQueueRegistry.ts
6138
- var taskQueueRegistry = null;
6139
-
6140
- class TaskQueueRegistry {
6141
- queues = new Map;
6142
- registerQueue(queue) {
6143
- const queueName = queue.server.queueName;
6144
- if (this.queues.has(queueName)) {
6145
- throw new Error(`Queue with name ${queueName} already exists`);
6146
- }
6147
- this.queues.set(queueName, queue);
6148
- }
6149
- getQueue(queueName) {
6150
- return this.queues.get(queueName);
6151
- }
6152
- async startQueues() {
6153
- for (const queue of this.queues.values()) {
6154
- await queue.server.start();
6155
- }
6156
- }
6157
- async stopQueues() {
6158
- for (const queue of this.queues.values()) {
6159
- await queue.server.stop();
6160
- }
6161
- }
6162
- async clearQueues() {
6163
- for (const queue of this.queues.values()) {
6164
- await queue.storage.deleteAll();
6165
- }
6166
- }
6167
- }
6168
- function getTaskQueueRegistry() {
6169
- if (!taskQueueRegistry) {
6170
- taskQueueRegistry = new TaskQueueRegistry;
6171
- }
6172
- return taskQueueRegistry;
6173
- }
6174
- async function setTaskQueueRegistry(registry) {
6175
- if (taskQueueRegistry) {
6176
- await taskQueueRegistry.stopQueues();
6177
- await taskQueueRegistry.clearQueues();
6178
- }
6179
- taskQueueRegistry = registry;
6180
- }
6181
-
6182
- // src/task/JobQueueTask.ts
6183
- var jobQueueTaskConfigSchema = {
6184
- type: "object",
6185
- properties: {
6186
- ...graphAsTaskConfigSchema["properties"],
6187
- queue: {
6188
- oneOf: [{ type: "boolean" }, { type: "string" }],
6189
- description: "Queue handling: false=run inline, true=use default, string=explicit queue name",
6190
- "x-ui-hidden": true
6191
- }
6192
- },
6193
- additionalProperties: false
6194
- };
6195
-
6196
- class JobQueueTask extends GraphAsTask {
6197
- static type = "JobQueueTask";
6198
- static canRunDirectly = true;
6199
- static configSchema() {
6200
- return jobQueueTaskConfigSchema;
6201
- }
6202
- currentQueueName;
6203
- currentJobId;
6204
- currentRunnerId;
6205
- jobClass;
6206
- constructor(input = {}, config = {}) {
6207
- config.queue ??= true;
6208
- super(input, config);
6209
- this.jobClass = Job2;
6210
- }
6211
- async execute(input, executeContext) {
6212
- let cleanup = () => {};
6213
- try {
6214
- if (this.config.queue === false && !this.constructor.canRunDirectly) {
6215
- throw new TaskConfigurationError(`${this.type} cannot run directly without a queue`);
6216
- }
6217
- const registeredQueue = await this.resolveQueue(input);
6218
- if (!registeredQueue) {
6219
- if (!this.constructor.canRunDirectly) {
6220
- const queueLabel = typeof this.config.queue === "string" ? this.config.queue : this.currentQueueName ?? this.type;
6221
- throw new TaskConfigurationError(`Queue ${queueLabel} not found, and ${this.type} cannot run directly`);
6222
- }
6223
- this.currentJobId = undefined;
6224
- const job = await this.createJob(input, this.currentQueueName);
6225
- cleanup = job.onJobProgress((progress, message, details) => {
6226
- executeContext.updateProgress(progress, message, details);
6227
- });
6228
- const output2 = await job.execute(job.input, {
6229
- signal: executeContext.signal,
6230
- updateProgress: executeContext.updateProgress.bind(this)
6231
- });
6232
- return output2;
6233
- }
6234
- const { client } = registeredQueue;
6235
- const jobInput = await this.getJobInput(input);
6236
- const handle = await client.submit(jobInput, {
6237
- jobRunId: this.currentRunnerId,
6238
- maxRetries: 10
6239
- });
6240
- this.currentJobId = handle.id;
6241
- this.currentQueueName = client.queueName;
6242
- cleanup = handle.onProgress((progress, message, details) => {
6243
- executeContext.updateProgress(progress, message, details);
6244
- });
6245
- const output = await handle.waitFor();
6246
- if (output === undefined) {
6247
- throw new TaskConfigurationError("Job disabled, should not happen");
6248
- }
6249
- return output;
6250
- } catch (err) {
6251
- throw new JobTaskFailedError(err);
6252
- } finally {
6253
- cleanup();
6254
- }
6255
- }
6256
- async getJobInput(input) {
6257
- return input;
6258
- }
6259
- async createJob(input, queueName) {
6260
- return new this.jobClass({
6261
- queueName: queueName ?? this.currentQueueName,
6262
- jobRunId: this.currentRunnerId,
6263
- input
6264
- });
6265
- }
6266
- async resolveQueue(input) {
6267
- const preference = this.config.queue ?? true;
6268
- if (preference === false) {
6269
- this.currentQueueName = undefined;
6270
- return;
6271
- }
6272
- if (typeof preference === "string") {
6273
- const registeredQueue2 = getTaskQueueRegistry().getQueue(preference);
6274
- if (registeredQueue2) {
6275
- this.currentQueueName = registeredQueue2.server.queueName;
6276
- return registeredQueue2;
6277
- }
6278
- this.currentQueueName = preference;
6279
- return;
6280
- }
6281
- const queueName = await this.getDefaultQueueName(input);
6282
- if (!queueName) {
6283
- this.currentQueueName = undefined;
6284
- return;
6285
- }
6286
- this.currentQueueName = queueName;
6287
- let registeredQueue = getTaskQueueRegistry().getQueue(queueName);
6288
- if (!registeredQueue) {
6289
- registeredQueue = await this.createAndRegisterQueue(queueName, input);
6290
- await registeredQueue.server.start();
6291
- }
6292
- return registeredQueue;
6293
- }
6294
- async getDefaultQueueName(_input) {
6295
- return this.type;
6296
- }
6297
- async createAndRegisterQueue(queueName, input) {
6298
- const factory = getJobQueueFactory();
6299
- let registeredQueue = await factory({
6300
- queueName,
6301
- jobClass: this.jobClass,
6302
- input,
6303
- config: this.config,
6304
- task: this
6305
- });
6306
- const registry = getTaskQueueRegistry();
6307
- try {
6308
- registry.registerQueue(registeredQueue);
6309
- } catch (err) {
6310
- if (err instanceof Error && err.message.includes("already exists")) {
6311
- const existing = registry.getQueue(queueName);
6312
- if (existing) {
6313
- registeredQueue = existing;
6314
- }
6315
- } else {
6316
- throw err;
6317
- }
6318
- }
6319
- return registeredQueue;
6320
- }
6321
- abort() {
6322
- if (this.currentQueueName && this.currentJobId) {
6323
- const registeredQueue = getTaskQueueRegistry().getQueue(this.currentQueueName);
6324
- if (registeredQueue) {
6325
- registeredQueue.client.abort(this.currentJobId).catch((err) => {
6326
- console.warn(`Failed to abort remote job ${this.currentJobId}`, err);
6327
- });
6328
- }
6329
- }
6330
- super.abort();
6331
- }
6332
- }
6333
6161
  // src/task/MapTask.ts
6334
- init_TaskGraphRunner();
6335
6162
  var mapTaskConfigSchema = {
6336
6163
  type: "object",
6337
6164
  properties: {
@@ -6503,16 +6330,6 @@ queueMicrotask(() => {
6503
6330
  Workflow.prototype.reduce = CreateLoopWorkflow(ReduceTask);
6504
6331
  Workflow.prototype.endReduce = CreateEndLoopWorkflow("endReduce");
6505
6332
  });
6506
-
6507
- // src/task/index.ts
6508
- init_Task();
6509
- init_TaskError();
6510
-
6511
- // src/task/TaskJSON.ts
6512
- init_Dataflow();
6513
- init_TaskGraph();
6514
- init_TaskError();
6515
-
6516
6333
  // src/task/TaskRegistry.ts
6517
6334
  import {
6518
6335
  createServiceToken as createServiceToken3,
@@ -6561,14 +6378,19 @@ function resolveTaskFromRegistry(id, _format, registry) {
6561
6378
  registerInputResolver("tasks", resolveTaskFromRegistry);
6562
6379
 
6563
6380
  // src/task/TaskJSON.ts
6564
- init_GraphAsTask();
6565
- var createSingleTaskFromJSON = (item, registry) => {
6381
+ var createSingleTaskFromJSON = (item, registry, options) => {
6566
6382
  if (!item.id)
6567
6383
  throw new TaskJSONError("Task id required");
6568
6384
  if (!item.type)
6569
6385
  throw new TaskJSONError("Task type required");
6570
6386
  if (item.defaults && Array.isArray(item.defaults))
6571
6387
  throw new TaskJSONError("Task defaults must be an object");
6388
+ if (options?.allowedTypes) {
6389
+ const allowed = options.allowedTypes instanceof Set ? options.allowedTypes : new Set(options.allowedTypes);
6390
+ if (!allowed.has(item.type)) {
6391
+ throw new TaskJSONError(`Task type "${item.type}" is not in the allowed types list`);
6392
+ }
6393
+ }
6572
6394
  const constructors = getTaskConstructors(registry);
6573
6395
  const taskClass = constructors.get(item.type);
6574
6396
  if (!taskClass)
@@ -6580,62 +6402,105 @@ var createSingleTaskFromJSON = (item, registry) => {
6580
6402
  const task = new taskClass(item.defaults ?? {}, taskConfig, registry ? { registry } : {});
6581
6403
  return task;
6582
6404
  };
6583
- var createTaskFromDependencyJSON = (item, registry) => {
6584
- const task = createSingleTaskFromJSON(item, registry);
6405
+ var createTaskFromDependencyJSON = (item, registry, options) => {
6406
+ const task = createSingleTaskFromJSON(item, registry, options);
6585
6407
  if (item.subtasks && item.subtasks.length > 0) {
6586
6408
  if (!(task instanceof GraphAsTask)) {
6587
6409
  throw new TaskConfigurationError("Subgraph is only supported for CompoundTasks");
6588
6410
  }
6589
- task.subGraph = createGraphFromDependencyJSON(item.subtasks, registry);
6411
+ task.subGraph = createGraphFromDependencyJSON(item.subtasks, registry, options);
6590
6412
  }
6591
6413
  return task;
6592
6414
  };
6593
- var createGraphFromDependencyJSON = (jsonItems, registry) => {
6415
+ var createGraphFromDependencyJSON = (jsonItems, registry, options) => {
6594
6416
  const subGraph = new TaskGraph;
6595
6417
  for (const subitem of jsonItems) {
6596
- subGraph.addTask(createTaskFromDependencyJSON(subitem, registry));
6418
+ subGraph.addTask(createTaskFromDependencyJSON(subitem, registry, options));
6597
6419
  }
6598
6420
  return subGraph;
6599
6421
  };
6600
- var createTaskFromGraphJSON = (item, registry) => {
6601
- const task = createSingleTaskFromJSON(item, registry);
6422
+ var createTaskFromGraphJSON = (item, registry, options) => {
6423
+ const task = createSingleTaskFromJSON(item, registry, options);
6602
6424
  if (item.subgraph) {
6603
6425
  if (!(task instanceof GraphAsTask)) {
6604
6426
  throw new TaskConfigurationError("Subgraph is only supported for GraphAsTask");
6605
6427
  }
6606
- task.subGraph = createGraphFromGraphJSON(item.subgraph, registry);
6428
+ task.subGraph = createGraphFromGraphJSON(item.subgraph, registry, options);
6607
6429
  }
6608
6430
  return task;
6609
6431
  };
6610
- var createGraphFromGraphJSON = (graphJsonObj, registry) => {
6432
+ var createGraphFromGraphJSON = (graphJsonObj, registry, options) => {
6611
6433
  const subGraph = new TaskGraph;
6612
6434
  for (const subitem of graphJsonObj.tasks) {
6613
- subGraph.addTask(createTaskFromGraphJSON(subitem, registry));
6435
+ subGraph.addTask(createTaskFromGraphJSON(subitem, registry, options));
6614
6436
  }
6615
6437
  for (const subitem of graphJsonObj.dataflows) {
6616
6438
  subGraph.addDataflow(new Dataflow(subitem.sourceTaskId, subitem.sourceTaskPortId, subitem.targetTaskId, subitem.targetTaskPortId));
6617
6439
  }
6618
6440
  return subGraph;
6619
6441
  };
6442
+ // src/task/TaskQueueRegistry.ts
6443
+ import { EventEmitter as EventEmitter6 } from "@workglow/util";
6444
+ var taskQueueRegistry = null;
6620
6445
 
6446
+ class TaskQueueRegistry {
6447
+ emitter = new EventEmitter6;
6448
+ queues = new Map;
6449
+ registerQueue(queue) {
6450
+ const queueName = queue.server.queueName;
6451
+ if (this.queues.has(queueName)) {
6452
+ throw new Error(`Queue with name ${queueName} already exists`);
6453
+ }
6454
+ this.queues.set(queueName, queue);
6455
+ this.emitter.emit("queue_registered", queueName);
6456
+ }
6457
+ getQueue(queueName) {
6458
+ return this.queues.get(queueName);
6459
+ }
6460
+ async startQueues() {
6461
+ for (const queue of this.queues.values()) {
6462
+ await queue.server.start();
6463
+ }
6464
+ }
6465
+ async stopQueues() {
6466
+ for (const queue of this.queues.values()) {
6467
+ await queue.server.stop();
6468
+ }
6469
+ }
6470
+ async clearQueues() {
6471
+ for (const queue of this.queues.values()) {
6472
+ await queue.storage.deleteAll();
6473
+ }
6474
+ }
6475
+ }
6476
+ function getTaskQueueRegistry() {
6477
+ if (!taskQueueRegistry) {
6478
+ taskQueueRegistry = new TaskQueueRegistry;
6479
+ }
6480
+ return taskQueueRegistry;
6481
+ }
6482
+ async function setTaskQueueRegistry(registry) {
6483
+ if (taskQueueRegistry) {
6484
+ await taskQueueRegistry.stopQueues();
6485
+ await taskQueueRegistry.clearQueues();
6486
+ }
6487
+ taskQueueRegistry = registry;
6488
+ }
6621
6489
  // src/task/index.ts
6622
- init_ConditionalTask();
6623
- init_TaskTypes();
6624
- init_GraphAsTask();
6625
6490
  var registerBaseTasks = () => {
6626
6491
  const tasks = [GraphAsTask, ConditionalTask, FallbackTask, MapTask, WhileTask, ReduceTask];
6627
6492
  tasks.map(TaskRegistry.registerTask);
6628
6493
  return tasks;
6629
6494
  };
6630
6495
  // src/storage/TaskGraphRepository.ts
6631
- import { createServiceToken as createServiceToken4, EventEmitter as EventEmitter6 } from "@workglow/util";
6496
+ import { createServiceToken as createServiceToken4, EventEmitter as EventEmitter7 } from "@workglow/util";
6632
6497
  var TASK_GRAPH_REPOSITORY = createServiceToken4("taskgraph.taskGraphRepository");
6633
6498
 
6634
6499
  class TaskGraphRepository {
6635
6500
  type = "TaskGraphRepository";
6636
6501
  get events() {
6637
6502
  if (!this._events) {
6638
- this._events = new EventEmitter6;
6503
+ this._events = new EventEmitter7;
6639
6504
  }
6640
6505
  return this._events;
6641
6506
  }
@@ -6703,12 +6568,7 @@ class TaskGraphTabularRepository extends TaskGraphRepository {
6703
6568
  return await this.tabularRepository.size();
6704
6569
  }
6705
6570
  }
6706
-
6707
- // src/common.ts
6708
- init_TaskOutputRepository();
6709
-
6710
6571
  // src/storage/TaskOutputTabularRepository.ts
6711
- init_TaskOutputRepository();
6712
6572
  import { compress, decompress } from "@workglow/util/compress";
6713
6573
  import { makeFingerprint } from "@workglow/util";
6714
6574
  var TaskOutputSchema = {
@@ -6798,6 +6658,7 @@ export {
6798
6658
  setTaskQueueRegistry,
6799
6659
  setGlobalTaskConstructors,
6800
6660
  serialGraph,
6661
+ schemaHasFormatAnnotations,
6801
6662
  schemaAcceptsArray,
6802
6663
  resolveSchemaInputs,
6803
6664
  resetMethodNameCache,
@@ -6809,7 +6670,6 @@ export {
6809
6670
  parallel,
6810
6671
  mergeChainedOutputToInput,
6811
6672
  mapTaskConfigSchema,
6812
- jobQueueTaskConfigSchema,
6813
6673
  iteratorTaskConfigSchema,
6814
6674
  isTaskStreamable,
6815
6675
  isStrictArraySchema,
@@ -6866,6 +6726,7 @@ export {
6866
6726
  WHILE_CONTEXT_SCHEMA,
6867
6727
  TaskTimeoutError,
6868
6728
  TaskStatus,
6729
+ TaskSerializationError,
6869
6730
  TaskRegistry,
6870
6731
  TaskQueueRegistry,
6871
6732
  TaskOutputTabularRepository,
@@ -6874,6 +6735,7 @@ export {
6874
6735
  TaskOutputPrimaryKeyNames,
6875
6736
  TaskJSONError,
6876
6737
  TaskInvalidInputError,
6738
+ TaskGraphTimeoutError,
6877
6739
  TaskGraphTabularRepository,
6878
6740
  TaskGraphSchema,
6879
6741
  TaskGraphRunner,
@@ -6893,7 +6755,6 @@ export {
6893
6755
  PROPERTY_ARRAY,
6894
6756
  MapTask,
6895
6757
  JobTaskFailedError,
6896
- JobQueueTask,
6897
6758
  JOB_QUEUE_FACTORY,
6898
6759
  IteratorTaskRunner,
6899
6760
  IteratorTask,
@@ -6916,4 +6777,4 @@ export {
6916
6777
  ConditionalTask
6917
6778
  };
6918
6779
 
6919
- //# debugId=E5A646FA7909390A64756E2164756E21
6780
+ //# debugId=2758F4534C10DA3764756E2164756E21