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