@workglow/task-graph 0.0.99 → 0.0.101

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 (38) hide show
  1. package/dist/browser.js +253 -82
  2. package/dist/browser.js.map +17 -17
  3. package/dist/bun.js +253 -82
  4. package/dist/bun.js.map +17 -17
  5. package/dist/node.js +253 -82
  6. package/dist/node.js.map +17 -17
  7. package/dist/task/ConditionalTask.d.ts +53 -21
  8. package/dist/task/ConditionalTask.d.ts.map +1 -1
  9. package/dist/task/GraphAsTask.d.ts +37 -2
  10. package/dist/task/GraphAsTask.d.ts.map +1 -1
  11. package/dist/task/ITask.d.ts +37 -2
  12. package/dist/task/ITask.d.ts.map +1 -1
  13. package/dist/task/IteratorTask.d.ts +49 -3
  14. package/dist/task/IteratorTask.d.ts.map +1 -1
  15. package/dist/task/JobQueueTask.d.ts +39 -3
  16. package/dist/task/JobQueueTask.d.ts.map +1 -1
  17. package/dist/task/MapTask.d.ts +54 -2
  18. package/dist/task/MapTask.d.ts.map +1 -1
  19. package/dist/task/ReduceTask.d.ts +49 -2
  20. package/dist/task/ReduceTask.d.ts.map +1 -1
  21. package/dist/task/Task.d.ts +43 -3
  22. package/dist/task/Task.d.ts.map +1 -1
  23. package/dist/task/TaskJSON.d.ts +10 -8
  24. package/dist/task/TaskJSON.d.ts.map +1 -1
  25. package/dist/task/TaskRunner.d.ts +20 -3
  26. package/dist/task/TaskRunner.d.ts.map +1 -1
  27. package/dist/task/TaskTypes.d.ts +60 -18
  28. package/dist/task/TaskTypes.d.ts.map +1 -1
  29. package/dist/task/WhileTask.d.ts +70 -7
  30. package/dist/task/WhileTask.d.ts.map +1 -1
  31. package/dist/task-graph/Conversions.d.ts.map +1 -1
  32. package/dist/task-graph/Dataflow.d.ts +11 -10
  33. package/dist/task-graph/Dataflow.d.ts.map +1 -1
  34. package/dist/task-graph/TaskGraph.d.ts +7 -0
  35. package/dist/task-graph/TaskGraph.d.ts.map +1 -1
  36. package/dist/task-graph/TaskGraphRunner.d.ts +22 -1
  37. package/dist/task-graph/TaskGraphRunner.d.ts.map +1 -1
  38. package/package.json +7 -7
package/dist/browser.js CHANGED
@@ -11,6 +11,22 @@ var TaskStatus = {
11
11
  ABORTING: "ABORTING",
12
12
  FAILED: "FAILED"
13
13
  };
14
+ var TaskConfigSchema = {
15
+ type: "object",
16
+ properties: {
17
+ id: {},
18
+ title: { type: "string" },
19
+ description: { type: "string" },
20
+ cacheable: { type: "boolean" },
21
+ inputSchema: { type: "object", properties: {}, additionalProperties: true },
22
+ outputSchema: { type: "object", properties: {}, additionalProperties: true },
23
+ extras: {
24
+ type: "object",
25
+ additionalProperties: true
26
+ }
27
+ },
28
+ additionalProperties: false
29
+ };
14
30
 
15
31
  // src/task-graph/Dataflow.ts
16
32
  var DATAFLOW_ALL_PORTS = "*";
@@ -47,10 +63,8 @@ class Dataflow {
47
63
  if (!this.stream)
48
64
  return;
49
65
  const reader = this.stream.getReader();
50
- const accumulatedPorts = new Map;
51
66
  let lastSnapshotData = undefined;
52
67
  let finishData = undefined;
53
- let hasTextDelta = false;
54
68
  let streamError;
55
69
  try {
56
70
  while (true) {
@@ -58,16 +72,6 @@ class Dataflow {
58
72
  if (done)
59
73
  break;
60
74
  switch (event.type) {
61
- case "text-delta": {
62
- if (this.sourceTaskPortId !== DATAFLOW_ALL_PORTS && event.port !== this.sourceTaskPortId) {
63
- break;
64
- }
65
- hasTextDelta = true;
66
- accumulatedPorts.set(event.port, (accumulatedPorts.get(event.port) ?? "") + event.textDelta);
67
- break;
68
- }
69
- case "object-delta":
70
- break;
71
75
  case "snapshot":
72
76
  lastSnapshotData = event.data;
73
77
  break;
@@ -90,19 +94,8 @@ class Dataflow {
90
94
  }
91
95
  if (lastSnapshotData !== undefined) {
92
96
  this.setPortData(lastSnapshotData);
93
- } else if (finishData && Object.keys(finishData).length > 0) {
97
+ } else if (finishData !== undefined) {
94
98
  this.setPortData(finishData);
95
- } else if (hasTextDelta) {
96
- if (this.sourceTaskPortId === DATAFLOW_ALL_PORTS) {
97
- const obj = {};
98
- for (const [port, text] of accumulatedPorts) {
99
- obj[port] = text;
100
- }
101
- this.value = obj;
102
- } else {
103
- const text = accumulatedPorts.values().next().value ?? "";
104
- this.value = text;
105
- }
106
99
  }
107
100
  }
108
101
  reset() {
@@ -548,6 +541,7 @@ class TaskRunner {
548
541
  outputCache;
549
542
  registry = globalServiceRegistry;
550
543
  inputStreams;
544
+ shouldAccumulate = true;
551
545
  constructor(task) {
552
546
  this.task = task;
553
547
  this.own = this.own.bind(this);
@@ -656,7 +650,7 @@ class TaskRunner {
656
650
  throw new TaskError(`Task ${this.task.type} declares append streaming but no output port has x-stream: "append"`);
657
651
  }
658
652
  }
659
- const accumulated = new Map;
653
+ const accumulated = this.shouldAccumulate ? new Map : undefined;
660
654
  let chunkCount = 0;
661
655
  let finalOutput;
662
656
  this.task.emit("stream_start");
@@ -676,33 +670,40 @@ class TaskRunner {
676
670
  if (event.type === "snapshot") {
677
671
  this.task.runOutputData = event.data;
678
672
  }
679
- this.task.emit("stream_chunk", event);
680
673
  switch (event.type) {
681
674
  case "text-delta": {
682
- accumulated.set(event.port, (accumulated.get(event.port) ?? "") + event.textDelta);
675
+ if (accumulated) {
676
+ accumulated.set(event.port, (accumulated.get(event.port) ?? "") + event.textDelta);
677
+ }
678
+ this.task.emit("stream_chunk", event);
683
679
  const progress = Math.min(99, Math.round(100 * (1 - Math.exp(-0.05 * chunkCount))));
684
680
  await this.handleProgress(progress);
685
681
  break;
686
682
  }
687
683
  case "object-delta": {
684
+ this.task.emit("stream_chunk", event);
688
685
  const progress = Math.min(99, Math.round(100 * (1 - Math.exp(-0.05 * chunkCount))));
689
686
  await this.handleProgress(progress);
690
687
  break;
691
688
  }
692
689
  case "snapshot": {
690
+ this.task.emit("stream_chunk", event);
693
691
  const progress = Math.min(99, Math.round(100 * (1 - Math.exp(-0.05 * chunkCount))));
694
692
  await this.handleProgress(progress);
695
693
  break;
696
694
  }
697
695
  case "finish": {
698
- if (streamMode === "append") {
696
+ if (accumulated) {
699
697
  const merged = { ...event.data || {} };
700
698
  for (const [port, text] of accumulated) {
701
- merged[port] = text.length > 0 ? text : event.data?.[port] ?? "";
699
+ if (text.length > 0)
700
+ merged[port] = text;
702
701
  }
703
702
  finalOutput = merged;
704
- } else if (streamMode === "replace") {
703
+ this.task.emit("stream_chunk", { type: "finish", data: merged });
704
+ } else {
705
705
  finalOutput = event.data;
706
+ this.task.emit("stream_chunk", event);
706
707
  }
707
708
  break;
708
709
  }
@@ -732,7 +733,7 @@ class TaskRunner {
732
733
  this.abortController.signal.addEventListener("abort", () => {
733
734
  this.handleAbort();
734
735
  });
735
- const cache = this.task.config.outputCache ?? config.outputCache;
736
+ const cache = config.outputCache ?? this.task.runConfig?.outputCache;
736
737
  if (cache === true) {
737
738
  let instance = globalServiceRegistry.get(TASK_OUTPUT_REPOSITORY);
738
739
  this.outputCache = instance;
@@ -741,6 +742,7 @@ class TaskRunner {
741
742
  } else if (cache instanceof TaskOutputRepository) {
742
743
  this.outputCache = cache;
743
744
  }
745
+ this.shouldAccumulate = config.shouldAccumulate !== false;
744
746
  if (config.updateProgress) {
745
747
  this.updateProgress = config.updateProgress;
746
748
  }
@@ -823,8 +825,10 @@ class Task {
823
825
  static type = "Task";
824
826
  static category = "Hidden";
825
827
  static title = "";
828
+ static description = "";
826
829
  static cacheable = true;
827
830
  static hasDynamicSchemas = false;
831
+ static passthroughInputsToOutputs = false;
828
832
  static inputSchema() {
829
833
  return {
830
834
  type: "object",
@@ -839,6 +843,9 @@ class Task {
839
843
  additionalProperties: false
840
844
  };
841
845
  }
846
+ static configSchema() {
847
+ return TaskConfigSchema;
848
+ }
842
849
  async execute(_input, context) {
843
850
  if (context.signal?.aborted) {
844
851
  throw new TaskAbortedError("Task aborted");
@@ -855,8 +862,8 @@ class Task {
855
862
  }
856
863
  return this._runner;
857
864
  }
858
- async run(overrides = {}) {
859
- return this.runner.run(overrides);
865
+ async run(overrides = {}, runConfig = {}) {
866
+ return this.runner.run(overrides, { ...this.runConfig, ...runConfig });
860
867
  }
861
868
  async runReactive(overrides = {}) {
862
869
  return this.runner.runReactive(overrides);
@@ -873,6 +880,9 @@ class Task {
873
880
  outputSchema() {
874
881
  return this.constructor.outputSchema();
875
882
  }
883
+ configSchema() {
884
+ return this.constructor.configSchema();
885
+ }
876
886
  get type() {
877
887
  return this.constructor.type;
878
888
  }
@@ -880,15 +890,19 @@ class Task {
880
890
  return this.constructor.category;
881
891
  }
882
892
  get title() {
883
- return this.constructor.title;
893
+ return this.config?.title ?? this.constructor.title;
894
+ }
895
+ get description() {
896
+ return this.config?.description ?? this.constructor.description;
884
897
  }
885
898
  get cacheable() {
886
- return this.config?.cacheable ?? this.constructor.cacheable;
899
+ return this.runConfig?.cacheable ?? this.config?.cacheable ?? this.constructor.cacheable;
887
900
  }
888
901
  defaults;
889
902
  runInputData = {};
890
903
  runOutputData = {};
891
904
  config;
905
+ runConfig = {};
892
906
  status = TaskStatus.PENDING;
893
907
  progress = 0;
894
908
  createdAt = new Date;
@@ -902,16 +916,18 @@ class Task {
902
916
  return this._events;
903
917
  }
904
918
  _events;
905
- constructor(callerDefaultInputs = {}, config = {}) {
919
+ constructor(callerDefaultInputs = {}, config = {}, runConfig = {}) {
906
920
  const inputDefaults = this.getDefaultInputsFromStaticInputDefinitions();
907
921
  const mergedDefaults = Object.assign(inputDefaults, callerDefaultInputs);
908
922
  this.defaults = this.stripSymbols(mergedDefaults);
909
923
  this.resetInputData();
910
- const name = this.title || new.target.title || new.target.name;
911
- this.config = Object.assign({
924
+ const title = this.constructor.title || undefined;
925
+ const baseConfig = Object.assign({
912
926
  id: uuid4(),
913
- name
927
+ ...title ? { title } : {}
914
928
  }, config);
929
+ this.config = this.validateAndApplyConfigDefaults(baseConfig);
930
+ this.runConfig = runConfig;
915
931
  }
916
932
  getDefaultInputsFromStaticInputDefinitions() {
917
933
  const schema = this.inputSchema();
@@ -948,7 +964,7 @@ class Task {
948
964
  return obj;
949
965
  }
950
966
  if (visited.has(obj)) {
951
- throw new Error("Circular reference detected in input data. " + "Cannot clone objects with circular references.");
967
+ throw new TaskConfigurationError("Circular reference detected in input data. " + "Cannot clone objects with circular references.");
952
968
  }
953
969
  if (ArrayBuffer.isView(obj)) {
954
970
  if (typeof DataView !== "undefined" && obj instanceof DataView) {
@@ -1093,6 +1109,37 @@ class Task {
1093
1109
  const finalOutputSchema = outputSchema ?? this.outputSchema();
1094
1110
  this.emit("schemaChange", finalInputSchema, finalOutputSchema);
1095
1111
  }
1112
+ static _configSchemaNode = new Map;
1113
+ static getConfigSchemaNode(type) {
1114
+ const schema = this.configSchema();
1115
+ if (!schema)
1116
+ return;
1117
+ if (!this._configSchemaNode.has(type)) {
1118
+ try {
1119
+ const schemaNode = typeof schema === "boolean" ? compileSchema(schema ? {} : { not: {} }) : compileSchema(schema);
1120
+ this._configSchemaNode.set(type, schemaNode);
1121
+ } catch (error) {
1122
+ console.warn(`Failed to compile config schema for ${this.type}:`, error);
1123
+ return;
1124
+ }
1125
+ }
1126
+ return this._configSchemaNode.get(type);
1127
+ }
1128
+ validateAndApplyConfigDefaults(config) {
1129
+ const ctor = this.constructor;
1130
+ const schemaNode = ctor.getConfigSchemaNode(this.type);
1131
+ if (!schemaNode)
1132
+ return config;
1133
+ const result = schemaNode.validate(config);
1134
+ if (!result.valid) {
1135
+ const errorMessages = result.errors.map((e) => {
1136
+ const path = e.data?.pointer || "";
1137
+ return `${e.message}${path ? ` (${path})` : ""}`;
1138
+ });
1139
+ throw new TaskConfigurationError(`[${ctor.name}] Configuration Error: ${errorMessages.join(", ")}`);
1140
+ }
1141
+ return config;
1142
+ }
1096
1143
  static _inputSchemaNode = new Map;
1097
1144
  static generateInputSchemaNode(schema) {
1098
1145
  if (typeof schema === "boolean") {
@@ -1157,12 +1204,16 @@ class Task {
1157
1204
  }
1158
1205
  toJSON() {
1159
1206
  const extras = this.config.extras;
1160
- let json = this.stripSymbols({
1207
+ const json = this.stripSymbols({
1161
1208
  id: this.config.id,
1162
1209
  type: this.type,
1163
- ...this.config.name ? { name: this.config.name } : {},
1164
1210
  defaults: this.defaults,
1165
- ...extras && Object.keys(extras).length ? { extras } : {}
1211
+ config: {
1212
+ ...this.config.title ? { title: this.config.title } : {},
1213
+ ...this.config.inputSchema ? { inputSchema: this.config.inputSchema } : {},
1214
+ ...this.config.outputSchema ? { outputSchema: this.config.outputSchema } : {},
1215
+ ...extras && Object.keys(extras).length ? { extras } : {}
1216
+ }
1166
1217
  });
1167
1218
  return json;
1168
1219
  }
@@ -1205,12 +1256,27 @@ class Task {
1205
1256
  }
1206
1257
 
1207
1258
  // src/task/ConditionalTask.ts
1259
+ var conditionalTaskConfigSchema = {
1260
+ type: "object",
1261
+ properties: {
1262
+ ...TaskConfigSchema["properties"],
1263
+ branches: { type: "array", items: {} },
1264
+ defaultBranch: { type: "string" },
1265
+ exclusive: { type: "boolean" },
1266
+ conditionConfig: { type: "object", additionalProperties: true }
1267
+ },
1268
+ additionalProperties: false
1269
+ };
1270
+
1208
1271
  class ConditionalTask extends Task {
1209
1272
  static type = "ConditionalTask";
1210
1273
  static category = "Flow Control";
1211
1274
  static title = "Condition";
1212
1275
  static description = "Route data based on conditions";
1213
1276
  static hasDynamicSchemas = true;
1277
+ static configSchema() {
1278
+ return conditionalTaskConfigSchema;
1279
+ }
1214
1280
  activeBranches = new Set;
1215
1281
  buildBranchesFromConditionConfig(conditionConfig) {
1216
1282
  if (!conditionConfig?.branches || conditionConfig.branches.length === 0) {
@@ -1241,7 +1307,7 @@ class ConditionalTask extends Task {
1241
1307
  fromConditionConfig: false
1242
1308
  };
1243
1309
  }
1244
- const conditionConfig = input.conditionConfig ?? this.config.extras?.conditionConfig;
1310
+ const conditionConfig = input.conditionConfig ?? this.config.conditionConfig;
1245
1311
  if (conditionConfig) {
1246
1312
  return {
1247
1313
  branches: this.buildBranchesFromConditionConfig(conditionConfig),
@@ -1552,6 +1618,7 @@ class TaskGraphRunner {
1552
1618
  reactiveRunning = false;
1553
1619
  graph;
1554
1620
  outputCache;
1621
+ accumulateLeafOutputs = true;
1555
1622
  registry = globalServiceRegistry2;
1556
1623
  abortController;
1557
1624
  inProgressTasks = new Map;
@@ -1771,6 +1838,29 @@ class TaskGraphRunner {
1771
1838
  }
1772
1839
  }
1773
1840
  }
1841
+ taskNeedsAccumulation(task) {
1842
+ if (this.outputCache)
1843
+ return true;
1844
+ const outEdges = this.graph.getTargetDataflows(task.config.id);
1845
+ if (outEdges.length === 0)
1846
+ return this.accumulateLeafOutputs;
1847
+ const outSchema = task.outputSchema();
1848
+ for (const df of outEdges) {
1849
+ if (df.sourceTaskPortId === DATAFLOW_ALL_PORTS) {
1850
+ if (getStreamingPorts(outSchema).length > 0)
1851
+ return true;
1852
+ continue;
1853
+ }
1854
+ const targetTask = this.graph.getTask(df.targetTaskId);
1855
+ if (!targetTask)
1856
+ continue;
1857
+ const inSchema = targetTask.inputSchema();
1858
+ if (edgeNeedsAccumulation(outSchema, df.sourceTaskPortId, inSchema, df.targetTaskPortId)) {
1859
+ return true;
1860
+ }
1861
+ }
1862
+ return false;
1863
+ }
1774
1864
  async runTask(task, input) {
1775
1865
  const isStreamable = isTaskStreamable(task);
1776
1866
  if (isStreamable) {
@@ -1793,7 +1883,7 @@ class TaskGraphRunner {
1793
1883
  return this.runStreamingTask(task, input);
1794
1884
  }
1795
1885
  const results = await task.runner.run(input, {
1796
- outputCache: this.outputCache,
1886
+ outputCache: this.outputCache ?? false,
1797
1887
  updateProgress: async (task2, progress, message, ...args) => await this.handleProgress(task2, progress, message, ...args),
1798
1888
  registry: this.registry
1799
1889
  });
@@ -1813,6 +1903,7 @@ class TaskGraphRunner {
1813
1903
  }
1814
1904
  async runStreamingTask(task, input) {
1815
1905
  const streamMode = getOutputStreamMode(task.outputSchema());
1906
+ const shouldAccumulate = this.taskNeedsAccumulation(task);
1816
1907
  let streamingNotified = false;
1817
1908
  const onStatus = (status) => {
1818
1909
  if (status === TaskStatus.STREAMING && !streamingNotified) {
@@ -1837,7 +1928,8 @@ class TaskGraphRunner {
1837
1928
  task.on("stream_end", onStreamEnd);
1838
1929
  try {
1839
1930
  const results = await task.runner.run(input, {
1840
- outputCache: this.outputCache,
1931
+ outputCache: this.outputCache ?? false,
1932
+ shouldAccumulate,
1841
1933
  updateProgress: async (task2, progress, message, ...args) => await this.handleProgress(task2, progress, message, ...args),
1842
1934
  registry: this.registry
1843
1935
  });
@@ -1919,9 +2011,7 @@ class TaskGraphRunner {
1919
2011
  task.runOutputData = {};
1920
2012
  task.error = undefined;
1921
2013
  task.progress = 0;
1922
- if (task.config) {
1923
- task.config.runnerId = runId;
1924
- }
2014
+ task.runConfig = { ...task.runConfig, runnerId: runId };
1925
2015
  this.pushStatusFromNodeToEdges(graph, task);
1926
2016
  this.pushErrorFromNodeToEdges(graph, task);
1927
2017
  task.emit("reset");
@@ -1945,6 +2035,7 @@ class TaskGraphRunner {
1945
2035
  } else {
1946
2036
  this.registry = new ServiceRegistry2(globalServiceRegistry2.container.createChildContainer());
1947
2037
  }
2038
+ this.accumulateLeafOutputs = config?.accumulateLeafOutputs !== false;
1948
2039
  if (config?.outputCache !== undefined) {
1949
2040
  if (typeof config.outputCache === "boolean") {
1950
2041
  if (config.outputCache === true) {
@@ -2084,6 +2175,15 @@ class GraphAsTaskRunner extends TaskRunner {
2084
2175
  }
2085
2176
 
2086
2177
  // src/task/GraphAsTask.ts
2178
+ var graphAsTaskConfigSchema = {
2179
+ type: "object",
2180
+ properties: {
2181
+ ...TaskConfigSchema["properties"],
2182
+ compoundMerge: { type: "string" }
2183
+ },
2184
+ additionalProperties: false
2185
+ };
2186
+
2087
2187
  class GraphAsTask extends Task {
2088
2188
  static type = "GraphAsTask";
2089
2189
  static title = "Group";
@@ -2105,11 +2205,14 @@ class GraphAsTask extends Task {
2105
2205
  }
2106
2206
  return this._runner;
2107
2207
  }
2208
+ static configSchema() {
2209
+ return graphAsTaskConfigSchema;
2210
+ }
2108
2211
  get compoundMerge() {
2109
2212
  return this.config?.compoundMerge || this.constructor.compoundMerge;
2110
2213
  }
2111
2214
  get cacheable() {
2112
- return this.config?.cacheable ?? (this.constructor.cacheable && !this.hasChildren());
2215
+ return this.runConfig?.cacheable ?? this.config?.cacheable ?? (this.constructor.cacheable && !this.hasChildren());
2113
2216
  }
2114
2217
  inputSchema() {
2115
2218
  if (!this.hasChildren()) {
@@ -2276,7 +2379,7 @@ class GraphAsTask extends Task {
2276
2379
  }
2277
2380
  }
2278
2381
  });
2279
- const runPromise = this.subGraph.run(input, { parentSignal: context.signal }).then((results2) => {
2382
+ const runPromise = this.subGraph.run(input, { parentSignal: context.signal, accumulateLeafOutputs: false }).then((results2) => {
2280
2383
  subgraphDone = true;
2281
2384
  resolveWaiting?.();
2282
2385
  return results2;
@@ -2986,17 +3089,19 @@ function ensureTask(arg, config = {}) {
2986
3089
  return arg;
2987
3090
  }
2988
3091
  if (arg instanceof TaskGraph) {
2989
- if (config.isOwned) {
2990
- return new OwnGraphTask({}, { ...config, subGraph: arg });
3092
+ const { isOwned, ...cleanConfig } = config;
3093
+ if (isOwned) {
3094
+ return new OwnGraphTask({}, { ...cleanConfig, subGraph: arg });
2991
3095
  } else {
2992
- return new GraphTask({}, { ...config, subGraph: arg });
3096
+ return new GraphTask({}, { ...cleanConfig, subGraph: arg });
2993
3097
  }
2994
3098
  }
2995
3099
  if (arg instanceof Workflow) {
2996
- if (config.isOwned) {
2997
- return new OwnWorkflowTask({}, { ...config, subGraph: arg.graph });
3100
+ const { isOwned, ...cleanConfig } = config;
3101
+ if (isOwned) {
3102
+ return new OwnWorkflowTask({}, { ...cleanConfig, subGraph: arg.graph });
2998
3103
  } else {
2999
- return new WorkflowTask2({}, { ...config, subGraph: arg.graph });
3104
+ return new WorkflowTask2({}, { ...cleanConfig, subGraph: arg.graph });
3000
3105
  }
3001
3106
  }
3002
3107
  return convertPipeFunctionToTask(arg, config);
@@ -3083,7 +3188,8 @@ class TaskGraph {
3083
3188
  run(input = {}, config = {}) {
3084
3189
  return this.runner.runGraph(input, {
3085
3190
  outputCache: config?.outputCache || this.outputCache,
3086
- parentSignal: config?.parentSignal || undefined
3191
+ parentSignal: config?.parentSignal || undefined,
3192
+ accumulateLeafOutputs: config?.accumulateLeafOutputs
3087
3193
  });
3088
3194
  }
3089
3195
  runReactive(input = {}) {
@@ -3472,6 +3578,16 @@ var ITERATOR_CONTEXT_SCHEMA = {
3472
3578
  }
3473
3579
  }
3474
3580
  };
3581
+ var iteratorTaskConfigSchema = {
3582
+ type: "object",
3583
+ properties: {
3584
+ ...graphAsTaskConfigSchema["properties"],
3585
+ concurrencyLimit: { type: "integer", minimum: 1 },
3586
+ batchSize: { type: "integer", minimum: 1 },
3587
+ iterationInputConfig: { type: "object", additionalProperties: true }
3588
+ },
3589
+ additionalProperties: false
3590
+ };
3475
3591
  function isArrayVariant(schema) {
3476
3592
  if (!schema || typeof schema !== "object")
3477
3593
  return false;
@@ -3580,6 +3696,9 @@ class IteratorTask extends GraphAsTask {
3580
3696
  static title = "Iterator";
3581
3697
  static description = "Base class for loop-type tasks";
3582
3698
  static hasDynamicSchemas = true;
3699
+ static configSchema() {
3700
+ return iteratorTaskConfigSchema;
3701
+ }
3583
3702
  static getIterationContextSchema() {
3584
3703
  return ITERATOR_CONTEXT_SCHEMA;
3585
3704
  }
@@ -3940,6 +4059,20 @@ var WHILE_CONTEXT_SCHEMA = {
3940
4059
  }
3941
4060
  }
3942
4061
  };
4062
+ var whileTaskConfigSchema = {
4063
+ type: "object",
4064
+ properties: {
4065
+ ...graphAsTaskConfigSchema["properties"],
4066
+ condition: {},
4067
+ maxIterations: { type: "integer", minimum: 1 },
4068
+ chainIterations: { type: "boolean" },
4069
+ conditionField: { type: "string" },
4070
+ conditionOperator: { type: "string" },
4071
+ conditionValue: { type: "string" },
4072
+ iterationInputConfig: { type: "object", additionalProperties: true }
4073
+ },
4074
+ additionalProperties: false
4075
+ };
3943
4076
 
3944
4077
  class WhileTask extends GraphAsTask {
3945
4078
  static type = "WhileTask";
@@ -3947,6 +4080,9 @@ class WhileTask extends GraphAsTask {
3947
4080
  static title = "While Loop";
3948
4081
  static description = "Loops until a condition function returns false";
3949
4082
  static hasDynamicSchemas = true;
4083
+ static configSchema() {
4084
+ return whileTaskConfigSchema;
4085
+ }
3950
4086
  static getIterationContextSchema() {
3951
4087
  return WHILE_CONTEXT_SCHEMA;
3952
4088
  }
@@ -3964,38 +4100,30 @@ class WhileTask extends GraphAsTask {
3964
4100
  return this.config.condition;
3965
4101
  }
3966
4102
  get maxIterations() {
3967
- if (this.config.maxIterations !== undefined)
3968
- return this.config.maxIterations;
3969
- const wc = this.config.extras?.whileConfig;
3970
- return wc?.maxIterations ?? 100;
4103
+ return this.config.maxIterations ?? 100;
3971
4104
  }
3972
4105
  get chainIterations() {
3973
- if (this.config.chainIterations !== undefined)
3974
- return this.config.chainIterations;
3975
- const wc = this.config.extras?.whileConfig;
3976
- return wc?.chainIterations ?? true;
4106
+ return this.config.chainIterations ?? true;
3977
4107
  }
3978
4108
  get currentIteration() {
3979
4109
  return this._currentIteration;
3980
4110
  }
3981
- buildConditionFromExtras() {
3982
- const wc = this.config.extras?.whileConfig;
3983
- if (!wc?.conditionOperator) {
4111
+ buildConditionFromConfig() {
4112
+ const { conditionOperator, conditionField, conditionValue } = this.config;
4113
+ if (!conditionOperator) {
3984
4114
  return;
3985
4115
  }
3986
- const { conditionField, conditionOperator, conditionValue } = wc;
3987
4116
  return (output) => {
3988
4117
  const fieldValue = conditionField ? getNestedValue(output, conditionField) : output;
3989
4118
  return evaluateCondition(fieldValue, conditionOperator, conditionValue ?? "");
3990
4119
  };
3991
4120
  }
3992
4121
  analyzeArrayInputs(input) {
3993
- const wc = this.config.extras?.whileConfig;
3994
- if (!wc?.iterationInputConfig) {
4122
+ if (!this.config.iterationInputConfig) {
3995
4123
  return null;
3996
4124
  }
3997
4125
  const inputData = input;
3998
- const config = wc.iterationInputConfig;
4126
+ const config = this.config.iterationInputConfig;
3999
4127
  const arrayPorts = [];
4000
4128
  const scalarPorts = [];
4001
4129
  const iteratedValues = {};
@@ -4051,7 +4179,7 @@ class WhileTask extends GraphAsTask {
4051
4179
  if (!this.hasChildren()) {
4052
4180
  throw new TaskConfigurationError(`${this.type}: No subgraph set for while loop`);
4053
4181
  }
4054
- const condition = this.condition ?? this.buildConditionFromExtras();
4182
+ const condition = this.condition ?? this.buildConditionFromConfig();
4055
4183
  if (!condition) {
4056
4184
  throw new TaskConfigurationError(`${this.type}: No condition function provided`);
4057
4185
  }
@@ -4096,7 +4224,7 @@ class WhileTask extends GraphAsTask {
4096
4224
  if (!this.hasChildren()) {
4097
4225
  throw new TaskConfigurationError(`${this.type}: No subgraph set for while loop`);
4098
4226
  }
4099
- const condition = this.condition ?? this.buildConditionFromExtras();
4227
+ const condition = this.condition ?? this.buildConditionFromConfig();
4100
4228
  if (!condition) {
4101
4229
  throw new TaskConfigurationError(`${this.type}: No condition function provided`);
4102
4230
  }
@@ -4166,12 +4294,11 @@ class WhileTask extends GraphAsTask {
4166
4294
  const baseSchema = super.inputSchema();
4167
4295
  if (typeof baseSchema === "boolean")
4168
4296
  return baseSchema;
4169
- const wc = this.config.extras?.whileConfig;
4170
- if (!wc?.iterationInputConfig) {
4297
+ if (!this.config.iterationInputConfig) {
4171
4298
  return baseSchema;
4172
4299
  }
4173
4300
  const properties = { ...baseSchema.properties || {} };
4174
- for (const [key, propConfig] of Object.entries(wc.iterationInputConfig)) {
4301
+ for (const [key, propConfig] of Object.entries(this.config.iterationInputConfig)) {
4175
4302
  if (propConfig.mode === "array" && properties[key]) {
4176
4303
  const scalarSchema = properties[key];
4177
4304
  properties[key] = {
@@ -4580,9 +4707,21 @@ function setTaskQueueRegistry(registry) {
4580
4707
  }
4581
4708
 
4582
4709
  // src/task/JobQueueTask.ts
4710
+ var jobQueueTaskConfigSchema = {
4711
+ type: "object",
4712
+ properties: {
4713
+ ...graphAsTaskConfigSchema["properties"],
4714
+ queue: {}
4715
+ },
4716
+ additionalProperties: false
4717
+ };
4718
+
4583
4719
  class JobQueueTask extends GraphAsTask {
4584
4720
  static type = "JobQueueTask";
4585
4721
  static canRunDirectly = true;
4722
+ static configSchema() {
4723
+ return jobQueueTaskConfigSchema;
4724
+ }
4586
4725
  currentQueueName;
4587
4726
  currentJobId;
4588
4727
  currentRunnerId;
@@ -4713,11 +4852,24 @@ class JobQueueTask extends GraphAsTask {
4713
4852
  }
4714
4853
  }
4715
4854
  // src/task/MapTask.ts
4855
+ var mapTaskConfigSchema = {
4856
+ type: "object",
4857
+ properties: {
4858
+ ...iteratorTaskConfigSchema["properties"],
4859
+ preserveOrder: { type: "boolean" },
4860
+ flatten: { type: "boolean" }
4861
+ },
4862
+ additionalProperties: false
4863
+ };
4864
+
4716
4865
  class MapTask extends IteratorTask {
4717
4866
  static type = "MapTask";
4718
4867
  static category = "Flow Control";
4719
4868
  static title = "Map";
4720
4869
  static description = "Transforms array inputs by running a workflow per item";
4870
+ static configSchema() {
4871
+ return mapTaskConfigSchema;
4872
+ }
4721
4873
  static compoundMerge = PROPERTY_ARRAY;
4722
4874
  static inputSchema() {
4723
4875
  return {
@@ -4780,11 +4932,23 @@ queueMicrotask(() => {
4780
4932
  Workflow.prototype.endMap = CreateEndLoopWorkflow("endMap");
4781
4933
  });
4782
4934
  // src/task/ReduceTask.ts
4935
+ var reduceTaskConfigSchema = {
4936
+ type: "object",
4937
+ properties: {
4938
+ ...iteratorTaskConfigSchema["properties"],
4939
+ initialValue: {}
4940
+ },
4941
+ additionalProperties: false
4942
+ };
4943
+
4783
4944
  class ReduceTask extends IteratorTask {
4784
4945
  static type = "ReduceTask";
4785
4946
  static category = "Flow Control";
4786
4947
  static title = "Reduce";
4787
4948
  static description = "Processes iterated inputs sequentially with an accumulator (fold)";
4949
+ static configSchema() {
4950
+ return reduceTaskConfigSchema;
4951
+ }
4788
4952
  constructor(input = {}, config = {}) {
4789
4953
  const reduceConfig = {
4790
4954
  ...config,
@@ -4884,9 +5048,8 @@ var createSingleTaskFromJSON = (item) => {
4884
5048
  if (!taskClass)
4885
5049
  throw new TaskJSONError(`Task type ${item.type} not found, perhaps not registered?`);
4886
5050
  const taskConfig = {
4887
- id: item.id,
4888
- name: item.name,
4889
- extras: item.extras
5051
+ ...item.config,
5052
+ id: item.id
4890
5053
  };
4891
5054
  const task = new taskClass(item.defaults ?? {}, taskConfig);
4892
5055
  return task;
@@ -5092,6 +5255,7 @@ class TaskOutputTabularRepository extends TaskOutputRepository {
5092
5255
  }
5093
5256
  export {
5094
5257
  wrapSchemaInArray,
5258
+ whileTaskConfigSchema,
5095
5259
  setTaskQueueRegistry,
5096
5260
  serialGraph,
5097
5261
  schemaAcceptsArray,
@@ -5099,15 +5263,20 @@ export {
5099
5263
  removeIterationProperties,
5100
5264
  registerJobQueueFactory,
5101
5265
  registerBaseTasks,
5266
+ reduceTaskConfigSchema,
5102
5267
  pipe,
5103
5268
  parallel,
5104
5269
  mergeChainedOutputToInput,
5270
+ mapTaskConfigSchema,
5271
+ jobQueueTaskConfigSchema,
5272
+ iteratorTaskConfigSchema,
5105
5273
  isTaskStreamable,
5106
5274
  isStrictArraySchema,
5107
5275
  isIterationProperty,
5108
5276
  isFlexibleSchema,
5109
5277
  hasVectorOutput,
5110
5278
  hasVectorLikeInput,
5279
+ graphAsTaskConfigSchema,
5111
5280
  getTaskQueueRegistry,
5112
5281
  getStreamingPorts,
5113
5282
  getPortStreamMode,
@@ -5133,6 +5302,7 @@ export {
5133
5302
  createFlexibleSchema,
5134
5303
  createArraySchema,
5135
5304
  connect,
5305
+ conditionalTaskConfigSchema,
5136
5306
  buildIterationInputSchema,
5137
5307
  addIterationContextToSchema,
5138
5308
  WorkflowError,
@@ -5158,6 +5328,7 @@ export {
5158
5328
  TaskFailedError,
5159
5329
  TaskError,
5160
5330
  TaskConfigurationError,
5331
+ TaskConfigSchema,
5161
5332
  TaskAbortedError,
5162
5333
  Task,
5163
5334
  TASK_OUTPUT_REPOSITORY,
@@ -5187,4 +5358,4 @@ export {
5187
5358
  ConditionalTask
5188
5359
  };
5189
5360
 
5190
- //# debugId=47367645DC674EAF64756E2164756E21
5361
+ //# debugId=365A916C098B8CB464756E2164756E21