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