@workglow/task-graph 0.2.14 → 0.2.15

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 (69) hide show
  1. package/dist/__tests__/public-exports.test.d.ts +7 -0
  2. package/dist/__tests__/public-exports.test.d.ts.map +1 -0
  3. package/dist/browser.js +879 -374
  4. package/dist/browser.js.map +22 -13
  5. package/dist/bun.js +879 -374
  6. package/dist/bun.js.map +22 -13
  7. package/dist/common.d.ts +4 -0
  8. package/dist/common.d.ts.map +1 -1
  9. package/dist/node.js +879 -374
  10. package/dist/node.js.map +22 -13
  11. package/dist/task/EntitlementEnforcer.d.ts.map +1 -1
  12. package/dist/task/IteratorTask.d.ts +1 -1
  13. package/dist/task/IteratorTask.d.ts.map +1 -1
  14. package/dist/task/ReduceTask.d.ts +1 -0
  15. package/dist/task/ReduceTask.d.ts.map +1 -1
  16. package/dist/task/Task.d.ts +4 -1
  17. package/dist/task/Task.d.ts.map +1 -1
  18. package/dist/task/TaskJSON.d.ts +2 -0
  19. package/dist/task/TaskJSON.d.ts.map +1 -1
  20. package/dist/task/WhileTask.d.ts.map +1 -1
  21. package/dist/task/__tests__/DataflowJson.transforms.test.d.ts +7 -0
  22. package/dist/task/__tests__/DataflowJson.transforms.test.d.ts.map +1 -0
  23. package/dist/task-graph/ConditionalBuilder.d.ts.map +1 -1
  24. package/dist/task-graph/Dataflow.d.ts +41 -1
  25. package/dist/task-graph/Dataflow.d.ts.map +1 -1
  26. package/dist/task-graph/TaskGraphRunner.d.ts.map +1 -1
  27. package/dist/task-graph/TransformRegistry.d.ts +14 -0
  28. package/dist/task-graph/TransformRegistry.d.ts.map +1 -0
  29. package/dist/task-graph/TransformTypes.d.ts +51 -0
  30. package/dist/task-graph/TransformTypes.d.ts.map +1 -0
  31. package/dist/task-graph/Workflow.d.ts +13 -2
  32. package/dist/task-graph/Workflow.d.ts.map +1 -1
  33. package/dist/task-graph/__tests__/Dataflow.streaming.test.d.ts +7 -0
  34. package/dist/task-graph/__tests__/Dataflow.streaming.test.d.ts.map +1 -0
  35. package/dist/task-graph/__tests__/Dataflow.transforms.test.d.ts +7 -0
  36. package/dist/task-graph/__tests__/Dataflow.transforms.test.d.ts.map +1 -0
  37. package/dist/task-graph/__tests__/TaskGraphRunner.transforms.test.d.ts +7 -0
  38. package/dist/task-graph/__tests__/TaskGraphRunner.transforms.test.d.ts.map +1 -0
  39. package/dist/task-graph/__tests__/TransformRegistry.test.d.ts +6 -0
  40. package/dist/task-graph/__tests__/TransformRegistry.test.d.ts.map +1 -0
  41. package/dist/task-graph/__tests__/transforms/coalesce.test.d.ts +6 -0
  42. package/dist/task-graph/__tests__/transforms/coalesce.test.d.ts.map +1 -0
  43. package/dist/task-graph/__tests__/transforms/date-conversions.test.d.ts +6 -0
  44. package/dist/task-graph/__tests__/transforms/date-conversions.test.d.ts.map +1 -0
  45. package/dist/task-graph/__tests__/transforms/index-access.test.d.ts +6 -0
  46. package/dist/task-graph/__tests__/transforms/index-access.test.d.ts.map +1 -0
  47. package/dist/task-graph/__tests__/transforms/pick.test.d.ts +6 -0
  48. package/dist/task-graph/__tests__/transforms/pick.test.d.ts.map +1 -0
  49. package/dist/task-graph/__tests__/transforms/scalar-conversions.test.d.ts +6 -0
  50. package/dist/task-graph/__tests__/transforms/scalar-conversions.test.d.ts.map +1 -0
  51. package/dist/task-graph/__tests__/transforms/string-casts.test.d.ts +6 -0
  52. package/dist/task-graph/__tests__/transforms/string-casts.test.d.ts.map +1 -0
  53. package/dist/task-graph/autoConnect.d.ts +39 -0
  54. package/dist/task-graph/autoConnect.d.ts.map +1 -0
  55. package/dist/task-graph/transforms/coalesce.d.ts +11 -0
  56. package/dist/task-graph/transforms/coalesce.d.ts.map +1 -0
  57. package/dist/task-graph/transforms/date-conversions.d.ts +12 -0
  58. package/dist/task-graph/transforms/date-conversions.d.ts.map +1 -0
  59. package/dist/task-graph/transforms/index-access.d.ts +11 -0
  60. package/dist/task-graph/transforms/index-access.d.ts.map +1 -0
  61. package/dist/task-graph/transforms/index.d.ts +18 -0
  62. package/dist/task-graph/transforms/index.d.ts.map +1 -0
  63. package/dist/task-graph/transforms/pick.d.ts +11 -0
  64. package/dist/task-graph/transforms/pick.d.ts.map +1 -0
  65. package/dist/task-graph/transforms/scalar-conversions.d.ts +10 -0
  66. package/dist/task-graph/transforms/scalar-conversions.d.ts.map +1 -0
  67. package/dist/task-graph/transforms/string-casts.d.ts +18 -0
  68. package/dist/task-graph/transforms/string-casts.d.ts.map +1 -0
  69. package/package.json +7 -7
package/dist/bun.js CHANGED
@@ -3,6 +3,98 @@
3
3
  import { areSemanticallyCompatible } from "@workglow/util/schema";
4
4
  import { EventEmitter } from "@workglow/util";
5
5
 
6
+ // src/task/TaskError.ts
7
+ import { BaseError } from "@workglow/util";
8
+
9
+ class TaskError extends BaseError {
10
+ static type = "TaskError";
11
+ taskType;
12
+ taskId;
13
+ constructor(message) {
14
+ super(message);
15
+ }
16
+ }
17
+
18
+ class TaskConfigurationError extends TaskError {
19
+ static type = "TaskConfigurationError";
20
+ constructor(message) {
21
+ super(message);
22
+ }
23
+ }
24
+
25
+ class WorkflowError extends TaskError {
26
+ static type = "WorkflowError";
27
+ constructor(message) {
28
+ super(message);
29
+ }
30
+ }
31
+
32
+ class TaskAbortedError extends TaskError {
33
+ static type = "TaskAbortedError";
34
+ constructor(message = "Task aborted") {
35
+ super(message);
36
+ }
37
+ }
38
+
39
+ class TaskTimeoutError extends TaskAbortedError {
40
+ static type = "TaskTimeoutError";
41
+ constructor(timeoutMs) {
42
+ super(timeoutMs ? `Task timed out after ${timeoutMs}ms` : "Task timed out");
43
+ }
44
+ }
45
+
46
+ class TaskGraphTimeoutError extends TaskTimeoutError {
47
+ static type = "TaskGraphTimeoutError";
48
+ constructor(timeoutMs) {
49
+ super(timeoutMs);
50
+ this.message = timeoutMs ? `Graph execution timed out after ${timeoutMs}ms` : "Graph execution timed out";
51
+ }
52
+ }
53
+
54
+ class TaskFailedError extends TaskError {
55
+ static type = "TaskFailedError";
56
+ constructor(message = "Task failed") {
57
+ super(message);
58
+ }
59
+ }
60
+
61
+ class JobTaskFailedError extends TaskFailedError {
62
+ static type = "JobTaskFailedError";
63
+ jobError;
64
+ constructor(err) {
65
+ super(String(err));
66
+ this.jobError = err;
67
+ }
68
+ }
69
+
70
+ class TaskJSONError extends TaskError {
71
+ static type = "TaskJSONError";
72
+ constructor(message = "Error converting JSON to a Task") {
73
+ super(message);
74
+ }
75
+ }
76
+
77
+ class TaskInvalidInputError extends TaskError {
78
+ static type = "TaskInvalidInputError";
79
+ constructor(message = "Invalid input data") {
80
+ super(message);
81
+ }
82
+ }
83
+
84
+ class TaskEntitlementError extends TaskError {
85
+ static type = "TaskEntitlementError";
86
+ constructor(message = "Required entitlements denied") {
87
+ super(message);
88
+ }
89
+ }
90
+
91
+ class TaskSerializationError extends TaskError {
92
+ static type = "TaskSerializationError";
93
+ constructor(taskType) {
94
+ super(`Task "${taskType}" cannot be serialized: config contains non-serializable values. ` + `Use a declarative config alternative or remove function-valued config properties.`);
95
+ }
96
+ }
97
+
6
98
  // src/task/TaskTypes.ts
7
99
  var TaskStatus = {
8
100
  PENDING: "PENDING",
@@ -49,6 +141,21 @@ var TaskConfigSchema = {
49
141
  additionalProperties: false
50
142
  };
51
143
 
144
+ // src/task-graph/TransformRegistry.ts
145
+ import { createServiceToken, globalServiceRegistry } from "@workglow/util";
146
+ var transformDefs = new Map;
147
+ var TransformRegistry = {
148
+ all: transformDefs,
149
+ registerTransform(def) {
150
+ transformDefs.set(def.id, def);
151
+ },
152
+ unregisterTransform(id) {
153
+ transformDefs.delete(id);
154
+ }
155
+ };
156
+ var TRANSFORM_DEFS = createServiceToken("transform.defs");
157
+ globalServiceRegistry.registerIfAbsent(TRANSFORM_DEFS, () => TransformRegistry.all, true);
158
+
52
159
  // src/task-graph/Dataflow.ts
53
160
  var DATAFLOW_ALL_PORTS = "*";
54
161
  var DATAFLOW_ERROR_PORT = "[error]";
@@ -178,18 +285,62 @@ class Dataflow {
178
285
  return result;
179
286
  }
180
287
  toJSON() {
181
- return {
288
+ const base = {
182
289
  sourceTaskId: this.sourceTaskId,
183
290
  sourceTaskPortId: this.sourceTaskPortId,
184
291
  targetTaskId: this.targetTaskId,
185
292
  targetTaskPortId: this.targetTaskPortId
186
293
  };
294
+ if (this._transforms.length > 0) {
295
+ base.transforms = this._transforms.map((s) => ({ id: s.id, params: s.params }));
296
+ }
297
+ return base;
187
298
  }
188
299
  _compatibilityCache;
300
+ _transforms = [];
301
+ getTransforms() {
302
+ return this._transforms;
303
+ }
304
+ setTransforms(steps) {
305
+ this._transforms = steps.map((s) => ({ id: s.id, params: s.params }));
306
+ this.invalidateCompatibilityCache();
307
+ }
308
+ addTransform(step) {
309
+ this._transforms.push({ id: step.id, params: step.params });
310
+ this.invalidateCompatibilityCache();
311
+ }
312
+ removeTransform(index) {
313
+ this._transforms.splice(index, 1);
314
+ this.invalidateCompatibilityCache();
315
+ }
316
+ async applyTransforms(registry) {
317
+ if (this._transforms.length === 0)
318
+ return;
319
+ const defs = registry.get(TRANSFORM_DEFS);
320
+ let cur = this.value;
321
+ try {
322
+ for (const step of this._transforms) {
323
+ const def = defs.get(step.id);
324
+ if (!def) {
325
+ throw new Error(`Unknown transform: ${step.id}`);
326
+ }
327
+ cur = await def.apply(cur, step.params ?? {});
328
+ }
329
+ this.value = cur;
330
+ } catch (e) {
331
+ const error = e instanceof TaskError ? e : new TaskError(e instanceof Error ? e.message : String(e));
332
+ if (!(e instanceof TaskError) && e instanceof Error && e.stack) {
333
+ error.stack = e.stack;
334
+ }
335
+ this.error = error;
336
+ this.setStatus(TaskStatus.FAILED);
337
+ throw e;
338
+ }
339
+ }
189
340
  invalidateCompatibilityCache() {
190
341
  this._compatibilityCache = undefined;
191
342
  }
192
- semanticallyCompatible(graph, dataflow) {
343
+ semanticallyCompatible(graph, dataflow, registry) {
193
344
  const sourceTask = graph.getTask(dataflow.sourceTaskId);
194
345
  const targetTask = graph.getTask(dataflow.targetTaskId);
195
346
  const shouldCache = !(sourceTask.constructor.hasDynamicSchemas ?? true) && !(targetTask.constructor.hasDynamicSchemas ?? true);
@@ -218,7 +369,26 @@ class Dataflow {
218
369
  if (sourceSchemaProperty === undefined && sourceSchema.additionalProperties === true) {
219
370
  sourceSchemaProperty = true;
220
371
  }
221
- const result = areSemanticallyCompatible(sourceSchemaProperty, targetSchemaProperty);
372
+ let effectiveSourceSchema = sourceSchemaProperty;
373
+ if (this._transforms.length > 0) {
374
+ const defs = registry ? registry.get(TRANSFORM_DEFS) : TransformRegistry.all;
375
+ try {
376
+ let cur = effectiveSourceSchema === true ? {} : effectiveSourceSchema;
377
+ for (const step of this._transforms) {
378
+ const def = defs.get(step.id);
379
+ if (!def) {
380
+ return "incompatible";
381
+ }
382
+ cur = def.inferOutputSchema(cur, step.params ?? {});
383
+ }
384
+ effectiveSourceSchema = cur;
385
+ } catch {
386
+ if (shouldCache)
387
+ this._compatibilityCache = "incompatible";
388
+ return "incompatible";
389
+ }
390
+ }
391
+ const result = areSemanticallyCompatible(effectiveSourceSchema, targetSchemaProperty);
222
392
  if (shouldCache) {
223
393
  this._compatibilityCache = result;
224
394
  }
@@ -959,15 +1129,15 @@ import {
959
1129
  collectPropertyValues,
960
1130
  getLogger as getLogger3,
961
1131
  getTelemetryProvider as getTelemetryProvider2,
962
- globalServiceRegistry as globalServiceRegistry2,
1132
+ globalServiceRegistry as globalServiceRegistry3,
963
1133
  ServiceRegistry as ServiceRegistry2,
964
1134
  SpanStatusCode as SpanStatusCode2,
965
1135
  uuid4 as uuid43
966
1136
  } from "@workglow/util";
967
1137
 
968
1138
  // src/storage/TaskOutputRepository.ts
969
- import { createServiceToken, EventEmitter as EventEmitter2 } from "@workglow/util";
970
- var TASK_OUTPUT_REPOSITORY = createServiceToken("taskgraph.taskOutputRepository");
1139
+ import { createServiceToken as createServiceToken2, EventEmitter as EventEmitter2 } from "@workglow/util";
1140
+ var TASK_OUTPUT_REPOSITORY = createServiceToken2("taskgraph.taskOutputRepository");
971
1141
 
972
1142
  class TaskOutputRepository {
973
1143
  outputCompression;
@@ -1069,103 +1239,11 @@ function getNestedValue(obj, path) {
1069
1239
  import { deepEqual, EventEmitter as EventEmitter3, uuid4 as uuid42 } from "@workglow/util";
1070
1240
  import { compileSchema } from "@workglow/util/schema";
1071
1241
 
1072
- // src/task/TaskError.ts
1073
- import { BaseError } from "@workglow/util";
1074
-
1075
- class TaskError extends BaseError {
1076
- static type = "TaskError";
1077
- taskType;
1078
- taskId;
1079
- constructor(message) {
1080
- super(message);
1081
- }
1082
- }
1083
-
1084
- class TaskConfigurationError extends TaskError {
1085
- static type = "TaskConfigurationError";
1086
- constructor(message) {
1087
- super(message);
1088
- }
1089
- }
1090
-
1091
- class WorkflowError extends TaskError {
1092
- static type = "WorkflowError";
1093
- constructor(message) {
1094
- super(message);
1095
- }
1096
- }
1097
-
1098
- class TaskAbortedError extends TaskError {
1099
- static type = "TaskAbortedError";
1100
- constructor(message = "Task aborted") {
1101
- super(message);
1102
- }
1103
- }
1104
-
1105
- class TaskTimeoutError extends TaskAbortedError {
1106
- static type = "TaskTimeoutError";
1107
- constructor(timeoutMs) {
1108
- super(timeoutMs ? `Task timed out after ${timeoutMs}ms` : "Task timed out");
1109
- }
1110
- }
1111
-
1112
- class TaskGraphTimeoutError extends TaskTimeoutError {
1113
- static type = "TaskGraphTimeoutError";
1114
- constructor(timeoutMs) {
1115
- super(timeoutMs);
1116
- this.message = timeoutMs ? `Graph execution timed out after ${timeoutMs}ms` : "Graph execution timed out";
1117
- }
1118
- }
1119
-
1120
- class TaskFailedError extends TaskError {
1121
- static type = "TaskFailedError";
1122
- constructor(message = "Task failed") {
1123
- super(message);
1124
- }
1125
- }
1126
-
1127
- class JobTaskFailedError extends TaskFailedError {
1128
- static type = "JobTaskFailedError";
1129
- jobError;
1130
- constructor(err) {
1131
- super(String(err));
1132
- this.jobError = err;
1133
- }
1134
- }
1135
-
1136
- class TaskJSONError extends TaskError {
1137
- static type = "TaskJSONError";
1138
- constructor(message = "Error converting JSON to a Task") {
1139
- super(message);
1140
- }
1141
- }
1142
-
1143
- class TaskInvalidInputError extends TaskError {
1144
- static type = "TaskInvalidInputError";
1145
- constructor(message = "Invalid input data") {
1146
- super(message);
1147
- }
1148
- }
1149
-
1150
- class TaskEntitlementError extends TaskError {
1151
- static type = "TaskEntitlementError";
1152
- constructor(message = "Required entitlements denied") {
1153
- super(message);
1154
- }
1155
- }
1156
-
1157
- class TaskSerializationError extends TaskError {
1158
- static type = "TaskSerializationError";
1159
- constructor(taskType) {
1160
- super(`Task "${taskType}" cannot be serialized: config contains non-serializable values. ` + `Use a declarative config alternative or remove function-valued config properties.`);
1161
- }
1162
- }
1163
-
1164
1242
  // src/task/TaskRunner.ts
1165
1243
  import {
1166
1244
  getLogger,
1167
1245
  getTelemetryProvider,
1168
- globalServiceRegistry,
1246
+ globalServiceRegistry as globalServiceRegistry2,
1169
1247
  SpanStatusCode
1170
1248
  } from "@workglow/util";
1171
1249
 
@@ -1281,7 +1359,7 @@ class TaskRunner {
1281
1359
  task;
1282
1360
  abortController;
1283
1361
  outputCache;
1284
- registry = globalServiceRegistry;
1362
+ registry = globalServiceRegistry2;
1285
1363
  resourceScope;
1286
1364
  inputStreams;
1287
1365
  timeoutTimer;
@@ -1552,7 +1630,7 @@ class TaskRunner {
1552
1630
  });
1553
1631
  const cache = config.outputCache ?? this.task.runConfig?.outputCache;
1554
1632
  if (cache === true) {
1555
- let instance = globalServiceRegistry.get(TASK_OUTPUT_REPOSITORY);
1633
+ let instance = globalServiceRegistry2.get(TASK_OUTPUT_REPOSITORY);
1556
1634
  this.outputCache = instance;
1557
1635
  } else if (cache === false) {
1558
1636
  this.outputCache = undefined;
@@ -2439,7 +2517,7 @@ class ConditionalTask extends Task {
2439
2517
  }
2440
2518
 
2441
2519
  // src/task/EntitlementEnforcer.ts
2442
- import { createServiceToken as createServiceToken3 } from "@workglow/util";
2520
+ import { createServiceToken as createServiceToken4 } from "@workglow/util";
2443
2521
 
2444
2522
  // src/task/EntitlementPolicy.ts
2445
2523
  var EMPTY_POLICY = Object.freeze({
@@ -2483,7 +2561,7 @@ function can(policy, id, resources) {
2483
2561
  }
2484
2562
 
2485
2563
  // src/task/EntitlementResolver.ts
2486
- import { createServiceToken as createServiceToken2 } from "@workglow/util";
2564
+ import { createServiceToken as createServiceToken3 } from "@workglow/util";
2487
2565
  var PERMISSIVE_RESOLVER = {
2488
2566
  lookup: () => "grant",
2489
2567
  prompt: async () => "grant",
@@ -2494,7 +2572,7 @@ var DENY_ALL_RESOLVER = {
2494
2572
  prompt: async () => "deny",
2495
2573
  save: () => {}
2496
2574
  };
2497
- var ENTITLEMENT_RESOLVER = createServiceToken2("workglow.entitlementResolver");
2575
+ var ENTITLEMENT_RESOLVER = createServiceToken3("workglow.entitlementResolver");
2498
2576
 
2499
2577
  // src/task/EntitlementEnforcer.ts
2500
2578
  function formatEntitlementDenial(denial) {
@@ -2518,7 +2596,11 @@ function createPolicyEnforcer(policy, resolver = PERMISSIVE_RESOLVER) {
2518
2596
  for (const result of results) {
2519
2597
  if (result.verdict === "denied") {
2520
2598
  if (result.matchedRule) {
2521
- denied.push({ entitlement: result.entitlement, reason: "policy-deny", matchedRule: result.matchedRule });
2599
+ denied.push({
2600
+ entitlement: result.entitlement,
2601
+ reason: "policy-deny",
2602
+ matchedRule: result.matchedRule
2603
+ });
2522
2604
  } else {
2523
2605
  denied.push({ entitlement: result.entitlement, reason: "default-deny" });
2524
2606
  }
@@ -2537,7 +2619,11 @@ function createPolicyEnforcer(policy, resolver = PERMISSIVE_RESOLVER) {
2537
2619
  if (!result.matchedRule) {
2538
2620
  throw new Error(`Invariant violation: ask verdict for "${result.entitlement.id}" is missing matchedRule`);
2539
2621
  }
2540
- denied.push({ entitlement: result.entitlement, reason: "user-deny", matchedRule: result.matchedRule });
2622
+ denied.push({
2623
+ entitlement: result.entitlement,
2624
+ reason: "user-deny",
2625
+ matchedRule: result.matchedRule
2626
+ });
2541
2627
  }
2542
2628
  }
2543
2629
  }
@@ -2559,7 +2645,7 @@ function createScopedEnforcer(grants) {
2559
2645
  function createGrantListEnforcer(grants) {
2560
2646
  return createScopedEnforcer(grants.map((id) => ({ id })));
2561
2647
  }
2562
- var ENTITLEMENT_ENFORCER = createServiceToken3("workglow.entitlementEnforcer");
2648
+ var ENTITLEMENT_ENFORCER = createServiceToken4("workglow.entitlementEnforcer");
2563
2649
 
2564
2650
  // src/task-graph/TaskGraphScheduler.ts
2565
2651
  class TopologicalScheduler {
@@ -2723,7 +2809,7 @@ class TaskGraphRunner {
2723
2809
  graph;
2724
2810
  outputCache;
2725
2811
  accumulateLeafOutputs = true;
2726
- registry = globalServiceRegistry2;
2812
+ registry = globalServiceRegistry3;
2727
2813
  resourceScope;
2728
2814
  abortController;
2729
2815
  inProgressTasks = new Map;
@@ -2805,6 +2891,21 @@ class TaskGraphRunner {
2805
2891
  }
2806
2892
  async runGraphReactive(input = {}, config) {
2807
2893
  await this.handleStartReactive(config);
2894
+ const telemetry = getTelemetryProvider2();
2895
+ const telemetryEnabled = telemetry.isEnabled;
2896
+ const reactiveRunId = telemetryEnabled ? uuid43() : "";
2897
+ let reactiveSpan;
2898
+ if (telemetryEnabled) {
2899
+ reactiveSpan = telemetry.startSpan("workglow.graph.runReactive", {
2900
+ attributes: {
2901
+ "workglow.graph.reactive.run_id": reactiveRunId,
2902
+ "workglow.graph.task_count": this.graph.getTasks().length,
2903
+ "workglow.graph.dataflow_count": this.graph.getDataflows().length
2904
+ }
2905
+ });
2906
+ }
2907
+ const t0 = telemetryEnabled ? performance.now() : 0;
2908
+ const taskTimings = [];
2808
2909
  const results = [];
2809
2910
  try {
2810
2911
  for await (const task of this.reactiveScheduler.tasks()) {
@@ -2814,20 +2915,68 @@ class TaskGraphRunner {
2814
2915
  this.copyInputFromEdgesToNode(task);
2815
2916
  }
2816
2917
  const taskInput = isRootTask ? input : {};
2817
- const taskResult = await task.runReactive(taskInput);
2818
- await this.pushOutputFromNodeToEdges(task, taskResult);
2819
- if (this.graph.getTargetDataflows(task.id).length === 0) {
2820
- results.push({
2821
- id: task.id,
2822
- type: task.constructor.runtype || task.constructor.type,
2823
- data: taskResult
2824
- });
2918
+ if (telemetryEnabled) {
2919
+ const taskType = String(task.constructor.runtype || task.constructor.type || "?");
2920
+ const tReactive = performance.now();
2921
+ const taskResult = await task.runReactive(taskInput);
2922
+ const runReactiveMs = performance.now() - tReactive;
2923
+ const tPush = performance.now();
2924
+ await this.pushOutputFromNodeToEdges(task, taskResult);
2925
+ const pushOutputMs = performance.now() - tPush;
2926
+ taskTimings.push({ id: task.id, type: taskType, runReactiveMs, pushOutputMs });
2927
+ if (this.graph.getTargetDataflows(task.id).length === 0) {
2928
+ results.push({
2929
+ id: task.id,
2930
+ type: task.constructor.runtype || task.constructor.type,
2931
+ data: taskResult
2932
+ });
2933
+ }
2934
+ } else {
2935
+ const taskResult = await task.runReactive(taskInput);
2936
+ await this.pushOutputFromNodeToEdges(task, taskResult);
2937
+ if (this.graph.getTargetDataflows(task.id).length === 0) {
2938
+ results.push({
2939
+ id: task.id,
2940
+ type: task.constructor.runtype || task.constructor.type,
2941
+ data: taskResult
2942
+ });
2943
+ }
2825
2944
  }
2826
2945
  }
2827
2946
  await this.handleCompleteReactive();
2947
+ if (reactiveSpan) {
2948
+ const totalMs = performance.now() - t0;
2949
+ reactiveSpan.setAttributes({
2950
+ "workglow.graph.reactive.duration_ms": Math.round(totalMs * 1000) / 1000,
2951
+ "workglow.graph.reactive.tasks_executed": taskTimings.length
2952
+ });
2953
+ reactiveSpan.setStatus(SpanStatusCode2.OK);
2954
+ reactiveSpan.end();
2955
+ getLogger3().debug("task graph runReactive timings", {
2956
+ reactiveRunId,
2957
+ totalMs: Math.round(totalMs * 1000) / 1000,
2958
+ taskTimings
2959
+ });
2960
+ }
2828
2961
  return this.filterLeafResults(results);
2829
2962
  } catch (error) {
2830
2963
  await this.handleErrorReactive();
2964
+ if (reactiveSpan) {
2965
+ const totalMs = performance.now() - t0;
2966
+ const message = error instanceof Error ? error.message : String(error);
2967
+ reactiveSpan.setAttributes({
2968
+ "workglow.graph.reactive.duration_ms": Math.round(totalMs * 1000) / 1000,
2969
+ "workglow.graph.reactive.tasks_executed": taskTimings.length
2970
+ });
2971
+ reactiveSpan.setStatus(SpanStatusCode2.ERROR, message);
2972
+ reactiveSpan.end();
2973
+ getLogger3().debug("task graph runReactive failed", {
2974
+ reactiveRunId,
2975
+ totalMs: Math.round(totalMs * 1000) / 1000,
2976
+ taskTimings,
2977
+ error
2978
+ });
2979
+ }
2831
2980
  throw error;
2832
2981
  }
2833
2982
  }
@@ -2895,13 +3044,17 @@ class TaskGraphRunner {
2895
3044
  async pushOutputFromNodeToEdges(node, results) {
2896
3045
  const dataflows = this.graph.getTargetDataflows(node.id);
2897
3046
  for (const dataflow of dataflows) {
2898
- const compatibility = dataflow.semanticallyCompatible(this.graph, dataflow);
3047
+ if (dataflow.stream !== undefined)
3048
+ continue;
3049
+ const compatibility = dataflow.semanticallyCompatible(this.graph, dataflow, this.registry);
2899
3050
  if (compatibility === "static") {
2900
3051
  dataflow.setPortData(results);
3052
+ await dataflow.applyTransforms(this.registry);
2901
3053
  } else if (compatibility === "runtime") {
2902
3054
  const task = this.graph.getTask(dataflow.targetTaskId);
2903
3055
  const narrowed = await task.narrowInput({ ...results }, this.registry);
2904
3056
  dataflow.setPortData(narrowed);
3057
+ await dataflow.applyTransforms(this.registry);
2905
3058
  } else {
2906
3059
  const resultsKeys = Object.keys(results);
2907
3060
  if (resultsKeys.length > 0) {
@@ -2927,6 +3080,8 @@ class TaskGraphRunner {
2927
3080
  }
2928
3081
  const activeBranches = node.getActiveBranches();
2929
3082
  for (const dataflow of dataflows) {
3083
+ if (dataflow.status === TaskStatus.FAILED)
3084
+ continue;
2930
3085
  const branchId = portToBranch.get(dataflow.sourceTaskPortId);
2931
3086
  if (branchId !== undefined) {
2932
3087
  if (activeBranches.has(branchId)) {
@@ -2942,6 +3097,8 @@ class TaskGraphRunner {
2942
3097
  return;
2943
3098
  }
2944
3099
  dataflows.forEach((dataflow) => {
3100
+ if (dataflow.status === TaskStatus.FAILED)
3101
+ return;
2945
3102
  dataflow.setStatus(effectiveStatus);
2946
3103
  });
2947
3104
  }
@@ -3066,10 +3223,13 @@ class TaskGraphRunner {
3066
3223
  }
3067
3224
  async awaitStreamInputs(task) {
3068
3225
  const dataflows = this.graph.getSourceDataflows(task.id);
3069
- const streamPromises = dataflows.filter((df) => df.stream !== undefined).map((df) => df.awaitStreamValue());
3070
- if (streamPromises.length > 0) {
3071
- await Promise.all(streamPromises);
3072
- }
3226
+ const streamingDataflows = dataflows.filter((df) => df.stream !== undefined);
3227
+ if (streamingDataflows.length === 0)
3228
+ return;
3229
+ await Promise.all(streamingDataflows.map(async (df) => {
3230
+ await df.awaitStreamValue();
3231
+ await df.applyTransforms(this.registry);
3232
+ }));
3073
3233
  }
3074
3234
  async runStreamingTask(task, input) {
3075
3235
  const streamMode = getOutputStreamMode(task.outputSchema());
@@ -3204,7 +3364,7 @@ class TaskGraphRunner {
3204
3364
  if (config?.registry !== undefined) {
3205
3365
  this.registry = config.registry;
3206
3366
  } else if (this.registry === undefined) {
3207
- this.registry = new ServiceRegistry2(globalServiceRegistry2.container.createChildContainer());
3367
+ this.registry = new ServiceRegistry2(globalServiceRegistry3.container.createChildContainer());
3208
3368
  }
3209
3369
  if (config?.resourceScope !== undefined) {
3210
3370
  this.resourceScope = config.resourceScope;
@@ -4170,6 +4330,246 @@ function serialGraph(tasks, inputHandle, outputHandle) {
4170
4330
  // src/task-graph/Workflow.ts
4171
4331
  import { EventEmitter as EventEmitter5, getLogger as getLogger5, uuid4 as uuid46 } from "@workglow/util";
4172
4332
 
4333
+ // src/task-graph/autoConnect.ts
4334
+ function autoConnect(graph, sourceTask, targetTask, options) {
4335
+ const matches = new Map;
4336
+ const sourceSchema = sourceTask.outputSchema();
4337
+ const targetSchema = targetTask.inputSchema();
4338
+ const providedInputKeys = options?.providedInputKeys ?? new Set;
4339
+ const connectedInputKeys = options?.connectedInputKeys ?? new Set;
4340
+ const earlierTasks = options?.earlierTasks ?? [];
4341
+ const dryRun = options?.dryRun ?? false;
4342
+ const addDataflow = (df) => {
4343
+ if (!dryRun)
4344
+ graph.addDataflow(df);
4345
+ };
4346
+ const getSpecificTypeIdentifiers = (schema) => {
4347
+ const formats = new Set;
4348
+ const ids = new Set;
4349
+ if (typeof schema === "boolean") {
4350
+ return { formats, ids };
4351
+ }
4352
+ const extractFromSchema = (s) => {
4353
+ if (!s || typeof s !== "object" || Array.isArray(s))
4354
+ return;
4355
+ if (s.format)
4356
+ formats.add(s.format);
4357
+ if (s.$id)
4358
+ ids.add(s.$id);
4359
+ };
4360
+ extractFromSchema(schema);
4361
+ const checkUnion = (schemas) => {
4362
+ if (!schemas)
4363
+ return;
4364
+ for (const s of schemas) {
4365
+ if (typeof s === "boolean")
4366
+ continue;
4367
+ extractFromSchema(s);
4368
+ if (s.items && typeof s.items === "object" && !Array.isArray(s.items)) {
4369
+ extractFromSchema(s.items);
4370
+ }
4371
+ }
4372
+ };
4373
+ checkUnion(schema.oneOf);
4374
+ checkUnion(schema.anyOf);
4375
+ if (schema.items && typeof schema.items === "object" && !Array.isArray(schema.items)) {
4376
+ extractFromSchema(schema.items);
4377
+ }
4378
+ return { formats, ids };
4379
+ };
4380
+ const isTypeCompatible = (fromPortOutputSchema, toPortInputSchema, requireSpecificType = false) => {
4381
+ if (typeof fromPortOutputSchema === "boolean" || typeof toPortInputSchema === "boolean") {
4382
+ return fromPortOutputSchema === true && toPortInputSchema === true;
4383
+ }
4384
+ const outputIds = getSpecificTypeIdentifiers(fromPortOutputSchema);
4385
+ const inputIds = getSpecificTypeIdentifiers(toPortInputSchema);
4386
+ for (const format of outputIds.formats) {
4387
+ if (inputIds.formats.has(format)) {
4388
+ return true;
4389
+ }
4390
+ }
4391
+ for (const id of outputIds.ids) {
4392
+ if (inputIds.ids.has(id)) {
4393
+ return true;
4394
+ }
4395
+ }
4396
+ if (requireSpecificType) {
4397
+ return false;
4398
+ }
4399
+ const idTypeBlank = fromPortOutputSchema.$id === undefined && toPortInputSchema.$id === undefined;
4400
+ if (!idTypeBlank)
4401
+ return false;
4402
+ if (fromPortOutputSchema.type === toPortInputSchema.type)
4403
+ return true;
4404
+ const matchesOneOf = toPortInputSchema.oneOf?.some((schema) => {
4405
+ if (typeof schema === "boolean")
4406
+ return schema;
4407
+ return schema.type === fromPortOutputSchema.type;
4408
+ }) ?? false;
4409
+ const matchesAnyOf = toPortInputSchema.anyOf?.some((schema) => {
4410
+ if (typeof schema === "boolean")
4411
+ return schema;
4412
+ return schema.type === fromPortOutputSchema.type;
4413
+ }) ?? false;
4414
+ return matchesOneOf || matchesAnyOf;
4415
+ };
4416
+ const makeMatch = (fromSchema, toSchema, fromTaskId, toTaskId, comparator) => {
4417
+ if (typeof fromSchema === "object") {
4418
+ if (toSchema === true || typeof toSchema === "object" && toSchema.additionalProperties === true) {
4419
+ const outputKeys = Object.keys(fromSchema.properties || {});
4420
+ if (outputKeys.length > 0) {
4421
+ for (const fromOutputPortId of outputKeys) {
4422
+ if (matches.has(fromOutputPortId))
4423
+ continue;
4424
+ matches.set(fromOutputPortId, fromOutputPortId);
4425
+ addDataflow(new Dataflow(fromTaskId, fromOutputPortId, toTaskId, fromOutputPortId));
4426
+ }
4427
+ } else if (fromSchema.additionalProperties === true) {
4428
+ const sourceGraphTask = graph.getTask(fromTaskId);
4429
+ if (sourceGraphTask && sourceGraphTask.constructor.passthroughInputsToOutputs === true) {
4430
+ const incomingDfs = graph.getSourceDataflows(fromTaskId);
4431
+ for (const df of incomingDfs) {
4432
+ const portId = df.targetTaskPortId;
4433
+ if (portId === DATAFLOW_ALL_PORTS)
4434
+ continue;
4435
+ if (matches.has(portId))
4436
+ continue;
4437
+ if (connectedInputKeys.has(portId))
4438
+ continue;
4439
+ matches.set(portId, portId);
4440
+ addDataflow(new Dataflow(fromTaskId, portId, toTaskId, portId));
4441
+ }
4442
+ }
4443
+ }
4444
+ return;
4445
+ }
4446
+ }
4447
+ if (typeof fromSchema === "object" && fromSchema.additionalProperties === true && typeof toSchema === "object" && (sourceTask.type === "InputTask" || sourceTask.type === "OutputTask")) {
4448
+ for (const toInputPortId of Object.keys(toSchema.properties || {})) {
4449
+ if (matches.has(toInputPortId))
4450
+ continue;
4451
+ if (connectedInputKeys.has(toInputPortId))
4452
+ continue;
4453
+ matches.set(toInputPortId, toInputPortId);
4454
+ addDataflow(new Dataflow(fromTaskId, toInputPortId, toTaskId, toInputPortId));
4455
+ }
4456
+ return;
4457
+ }
4458
+ if (typeof fromSchema === "boolean" || typeof toSchema === "boolean") {
4459
+ return;
4460
+ }
4461
+ for (const [toInputPortId, toPortInputSchema] of Object.entries(toSchema.properties || {})) {
4462
+ if (matches.has(toInputPortId))
4463
+ continue;
4464
+ if (connectedInputKeys.has(toInputPortId))
4465
+ continue;
4466
+ const candidates = [];
4467
+ for (const [fromOutputPortId, fromPortOutputSchema] of Object.entries(fromSchema.properties || {})) {
4468
+ if (comparator([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema])) {
4469
+ candidates.push(fromOutputPortId);
4470
+ }
4471
+ }
4472
+ if (candidates.length === 0)
4473
+ continue;
4474
+ let winner = candidates[0];
4475
+ if (candidates.length > 1) {
4476
+ const targetStreamMode = getPortStreamMode(toSchema, toInputPortId);
4477
+ const streamMatch = candidates.find((portId) => getPortStreamMode(fromSchema, portId) === targetStreamMode);
4478
+ if (streamMatch)
4479
+ winner = streamMatch;
4480
+ }
4481
+ matches.set(toInputPortId, winner);
4482
+ addDataflow(new Dataflow(fromTaskId, winner, toTaskId, toInputPortId));
4483
+ }
4484
+ };
4485
+ makeMatch(sourceSchema, targetSchema, sourceTask.id, targetTask.id, ([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema]) => {
4486
+ const outputPortIdMatch = fromOutputPortId === toInputPortId;
4487
+ const outputPortIdOutputInput = fromOutputPortId === "output" && toInputPortId === "input";
4488
+ const portIdsCompatible = outputPortIdMatch || outputPortIdOutputInput;
4489
+ return portIdsCompatible && isTypeCompatible(fromPortOutputSchema, toPortInputSchema, false);
4490
+ });
4491
+ makeMatch(sourceSchema, targetSchema, sourceTask.id, targetTask.id, ([_fromOutputPortId, fromPortOutputSchema], [_toInputPortId, toPortInputSchema]) => {
4492
+ return isTypeCompatible(fromPortOutputSchema, toPortInputSchema, true);
4493
+ });
4494
+ const requiredInputs = new Set(typeof targetSchema === "object" ? targetSchema.required || [] : []);
4495
+ const requiredInputsNeedingConnection = [...requiredInputs].filter((r) => !providedInputKeys.has(r) && !connectedInputKeys.has(r));
4496
+ let unmatchedRequired = requiredInputsNeedingConnection.filter((r) => !matches.has(r));
4497
+ if (unmatchedRequired.length > 0 && earlierTasks.length > 0) {
4498
+ for (let i = 0;i < earlierTasks.length && unmatchedRequired.length > 0; i++) {
4499
+ const earlierTask = earlierTasks[i];
4500
+ const earlierOutputSchema = earlierTask.outputSchema();
4501
+ if (earlierTask.type === "InputTask") {
4502
+ const inputConfig = earlierTask.config;
4503
+ const inputSchema = inputConfig?.inputSchema ?? inputConfig?.outputSchema;
4504
+ const isManualSchema = inputSchema && typeof inputSchema === "object" && inputSchema["x-ui-manual"] === true;
4505
+ const inputProperties = isManualSchema && inputSchema && typeof inputSchema === "object" && "properties" in inputSchema && inputSchema.properties && typeof inputSchema.properties === "object" ? new Set(Object.keys(inputSchema.properties)) : undefined;
4506
+ for (const requiredInputId of [...unmatchedRequired]) {
4507
+ if (matches.has(requiredInputId))
4508
+ continue;
4509
+ if (inputProperties && !inputProperties.has(requiredInputId))
4510
+ continue;
4511
+ matches.set(requiredInputId, requiredInputId);
4512
+ addDataflow(new Dataflow(earlierTask.id, requiredInputId, targetTask.id, requiredInputId));
4513
+ }
4514
+ unmatchedRequired = unmatchedRequired.filter((r) => !matches.has(r));
4515
+ continue;
4516
+ }
4517
+ const makeMatchFromEarlier = (comparator) => {
4518
+ if (typeof earlierOutputSchema === "boolean" || typeof targetSchema === "boolean") {
4519
+ return;
4520
+ }
4521
+ for (const [fromOutputPortId, fromPortOutputSchema] of Object.entries(earlierOutputSchema.properties || {})) {
4522
+ for (const requiredInputId of unmatchedRequired) {
4523
+ const toPortInputSchema = targetSchema.properties?.[requiredInputId];
4524
+ if (!matches.has(requiredInputId) && toPortInputSchema && comparator([fromOutputPortId, fromPortOutputSchema], [requiredInputId, toPortInputSchema])) {
4525
+ matches.set(requiredInputId, fromOutputPortId);
4526
+ addDataflow(new Dataflow(earlierTask.id, fromOutputPortId, targetTask.id, requiredInputId));
4527
+ }
4528
+ }
4529
+ }
4530
+ };
4531
+ makeMatchFromEarlier(([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema]) => {
4532
+ const outputPortIdMatch = fromOutputPortId === toInputPortId;
4533
+ const outputPortIdOutputInput = fromOutputPortId === "output" && toInputPortId === "input";
4534
+ const portIdsCompatible = outputPortIdMatch || outputPortIdOutputInput;
4535
+ return portIdsCompatible && isTypeCompatible(fromPortOutputSchema, toPortInputSchema, false);
4536
+ });
4537
+ makeMatchFromEarlier(([_fromOutputPortId, fromPortOutputSchema], [_toInputPortId, toPortInputSchema]) => {
4538
+ return isTypeCompatible(fromPortOutputSchema, toPortInputSchema, true);
4539
+ });
4540
+ unmatchedRequired = unmatchedRequired.filter((r) => !matches.has(r));
4541
+ }
4542
+ }
4543
+ const stillUnmatchedRequired = requiredInputsNeedingConnection.filter((r) => !matches.has(r));
4544
+ if (stillUnmatchedRequired.length > 0) {
4545
+ return {
4546
+ matches,
4547
+ error: `Could not find matches for required inputs [${stillUnmatchedRequired.join(", ")}] of ${targetTask.type}. ` + `Attempted to match from ${sourceTask.type} and earlier tasks.`,
4548
+ unmatchedRequired: stillUnmatchedRequired
4549
+ };
4550
+ }
4551
+ if (matches.size === 0 && requiredInputsNeedingConnection.length === 0) {
4552
+ const existingTargetConnections = graph.getSourceDataflows(targetTask.id);
4553
+ if (existingTargetConnections.length > 0) {
4554
+ return { matches, unmatchedRequired: [] };
4555
+ }
4556
+ const hasRequiredInputs = requiredInputs.size > 0;
4557
+ const allRequiredInputsProvided = hasRequiredInputs && [...requiredInputs].every((r) => providedInputKeys.has(r));
4558
+ const hasInputsWithDefaults = typeof targetSchema === "object" && targetSchema.properties && Object.values(targetSchema.properties).some((prop) => prop && typeof prop === "object" && ("default" in prop));
4559
+ if (!allRequiredInputsProvided && !hasInputsWithDefaults) {
4560
+ return {
4561
+ matches,
4562
+ error: `Could not find a match between the outputs of ${sourceTask.type} and the inputs of ${targetTask.type}. ` + `You may need to connect the outputs to the inputs via connect() manually.`,
4563
+ unmatchedRequired: []
4564
+ };
4565
+ }
4566
+ }
4567
+ return {
4568
+ matches,
4569
+ unmatchedRequired: []
4570
+ };
4571
+ }
4572
+
4173
4573
  // src/task-graph/ConditionalBuilder.ts
4174
4574
  import { uuid4 as uuid45 } from "@workglow/util";
4175
4575
  class ConditionalBuilder {
@@ -4533,8 +4933,10 @@ class Workflow {
4533
4933
  static parallel(args, mergeFn) {
4534
4934
  return parallel(args, mergeFn ?? PROPERTY_ARRAY, new Workflow);
4535
4935
  }
4536
- rename(source, target, index = -1) {
4936
+ rename(source, target, indexOrOptions = -1) {
4537
4937
  this._error = "";
4938
+ const index = typeof indexOrOptions === "number" ? indexOrOptions : indexOrOptions.index ?? -1;
4939
+ const transforms = typeof indexOrOptions === "number" ? undefined : indexOrOptions.transforms;
4538
4940
  const nodes = this._graph.getTasks();
4539
4941
  if (-index > nodes.length) {
4540
4942
  const errorMsg = `Back index greater than number of tasks`;
@@ -4557,7 +4959,10 @@ class Workflow {
4557
4959
  getLogger5().error(this._error);
4558
4960
  throw new WorkflowError(errorMsg);
4559
4961
  }
4560
- this._dataFlows.push(new Dataflow(lastNode.id, source, undefined, target));
4962
+ const df = new Dataflow(lastNode.id, source, undefined, target);
4963
+ if (transforms && transforms.length > 0)
4964
+ df.setTransforms(transforms);
4965
+ this._dataFlows.push(df);
4561
4966
  return this;
4562
4967
  }
4563
4968
  onError(handler) {
@@ -4660,7 +5065,11 @@ class Workflow {
4660
5065
  addLoopTask(taskClass, config = {}) {
4661
5066
  this._error = "";
4662
5067
  const parent = getLastTask(this);
4663
- const task = this.addTaskToGraph(taskClass, { id: uuid46(), ...config });
5068
+ const schema = taskClass.configSchema?.();
5069
+ const required = typeof schema === "object" && schema !== null ? schema.required : undefined;
5070
+ const needsMaxIterations = Array.isArray(required) && required.includes("maxIterations");
5071
+ const resolvedConfig = needsMaxIterations && config.maxIterations === undefined ? { ...config, maxIterations: "unbounded" } : config;
5072
+ const task = this.addTaskToGraph(taskClass, { id: uuid46(), ...resolvedConfig });
4664
5073
  if (this._dataFlows.length > 0) {
4665
5074
  this._dataFlows.forEach((dataflow) => {
4666
5075
  const taskSchema = task.inputSchema();
@@ -4803,237 +5212,7 @@ class Workflow {
4803
5212
  }
4804
5213
  static AutoConnectOptions = Symbol("AutoConnectOptions");
4805
5214
  static autoConnect(graph, sourceTask, targetTask, options) {
4806
- const matches = new Map;
4807
- const sourceSchema = sourceTask.outputSchema();
4808
- const targetSchema = targetTask.inputSchema();
4809
- const providedInputKeys = options?.providedInputKeys ?? new Set;
4810
- const connectedInputKeys = options?.connectedInputKeys ?? new Set;
4811
- const earlierTasks = options?.earlierTasks ?? [];
4812
- const getSpecificTypeIdentifiers = (schema) => {
4813
- const formats = new Set;
4814
- const ids = new Set;
4815
- if (typeof schema === "boolean") {
4816
- return { formats, ids };
4817
- }
4818
- const extractFromSchema = (s) => {
4819
- if (!s || typeof s !== "object" || Array.isArray(s))
4820
- return;
4821
- if (s.format)
4822
- formats.add(s.format);
4823
- if (s.$id)
4824
- ids.add(s.$id);
4825
- };
4826
- extractFromSchema(schema);
4827
- const checkUnion = (schemas) => {
4828
- if (!schemas)
4829
- return;
4830
- for (const s of schemas) {
4831
- if (typeof s === "boolean")
4832
- continue;
4833
- extractFromSchema(s);
4834
- if (s.items && typeof s.items === "object" && !Array.isArray(s.items)) {
4835
- extractFromSchema(s.items);
4836
- }
4837
- }
4838
- };
4839
- checkUnion(schema.oneOf);
4840
- checkUnion(schema.anyOf);
4841
- if (schema.items && typeof schema.items === "object" && !Array.isArray(schema.items)) {
4842
- extractFromSchema(schema.items);
4843
- }
4844
- return { formats, ids };
4845
- };
4846
- const isTypeCompatible = (fromPortOutputSchema, toPortInputSchema, requireSpecificType = false) => {
4847
- if (typeof fromPortOutputSchema === "boolean" || typeof toPortInputSchema === "boolean") {
4848
- return fromPortOutputSchema === true && toPortInputSchema === true;
4849
- }
4850
- const outputIds = getSpecificTypeIdentifiers(fromPortOutputSchema);
4851
- const inputIds = getSpecificTypeIdentifiers(toPortInputSchema);
4852
- for (const format of outputIds.formats) {
4853
- if (inputIds.formats.has(format)) {
4854
- return true;
4855
- }
4856
- }
4857
- for (const id of outputIds.ids) {
4858
- if (inputIds.ids.has(id)) {
4859
- return true;
4860
- }
4861
- }
4862
- if (requireSpecificType) {
4863
- return false;
4864
- }
4865
- const idTypeBlank = fromPortOutputSchema.$id === undefined && toPortInputSchema.$id === undefined;
4866
- if (!idTypeBlank)
4867
- return false;
4868
- if (fromPortOutputSchema.type === toPortInputSchema.type)
4869
- return true;
4870
- const matchesOneOf = toPortInputSchema.oneOf?.some((schema) => {
4871
- if (typeof schema === "boolean")
4872
- return schema;
4873
- return schema.type === fromPortOutputSchema.type;
4874
- }) ?? false;
4875
- const matchesAnyOf = toPortInputSchema.anyOf?.some((schema) => {
4876
- if (typeof schema === "boolean")
4877
- return schema;
4878
- return schema.type === fromPortOutputSchema.type;
4879
- }) ?? false;
4880
- return matchesOneOf || matchesAnyOf;
4881
- };
4882
- const makeMatch = (fromSchema, toSchema, fromTaskId, toTaskId, comparator) => {
4883
- if (typeof fromSchema === "object") {
4884
- if (toSchema === true || typeof toSchema === "object" && toSchema.additionalProperties === true) {
4885
- const outputKeys = Object.keys(fromSchema.properties || {});
4886
- if (outputKeys.length > 0) {
4887
- for (const fromOutputPortId of outputKeys) {
4888
- if (matches.has(fromOutputPortId))
4889
- continue;
4890
- matches.set(fromOutputPortId, fromOutputPortId);
4891
- graph.addDataflow(new Dataflow(fromTaskId, fromOutputPortId, toTaskId, fromOutputPortId));
4892
- }
4893
- } else if (fromSchema.additionalProperties === true) {
4894
- const sourceGraphTask = graph.getTask(fromTaskId);
4895
- if (sourceGraphTask && sourceGraphTask.constructor.passthroughInputsToOutputs === true) {
4896
- const incomingDfs = graph.getSourceDataflows(fromTaskId);
4897
- for (const df of incomingDfs) {
4898
- const portId = df.targetTaskPortId;
4899
- if (portId === DATAFLOW_ALL_PORTS)
4900
- continue;
4901
- if (matches.has(portId))
4902
- continue;
4903
- if (connectedInputKeys.has(portId))
4904
- continue;
4905
- matches.set(portId, portId);
4906
- graph.addDataflow(new Dataflow(fromTaskId, portId, toTaskId, portId));
4907
- }
4908
- }
4909
- }
4910
- return;
4911
- }
4912
- }
4913
- if (typeof fromSchema === "object" && fromSchema.additionalProperties === true && typeof toSchema === "object" && (sourceTask.type === "InputTask" || sourceTask.type === "OutputTask")) {
4914
- for (const toInputPortId of Object.keys(toSchema.properties || {})) {
4915
- if (matches.has(toInputPortId))
4916
- continue;
4917
- if (connectedInputKeys.has(toInputPortId))
4918
- continue;
4919
- matches.set(toInputPortId, toInputPortId);
4920
- graph.addDataflow(new Dataflow(fromTaskId, toInputPortId, toTaskId, toInputPortId));
4921
- }
4922
- return;
4923
- }
4924
- if (typeof fromSchema === "boolean" || typeof toSchema === "boolean") {
4925
- return;
4926
- }
4927
- for (const [toInputPortId, toPortInputSchema] of Object.entries(toSchema.properties || {})) {
4928
- if (matches.has(toInputPortId))
4929
- continue;
4930
- if (connectedInputKeys.has(toInputPortId))
4931
- continue;
4932
- const candidates = [];
4933
- for (const [fromOutputPortId, fromPortOutputSchema] of Object.entries(fromSchema.properties || {})) {
4934
- if (comparator([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema])) {
4935
- candidates.push(fromOutputPortId);
4936
- }
4937
- }
4938
- if (candidates.length === 0)
4939
- continue;
4940
- let winner = candidates[0];
4941
- if (candidates.length > 1) {
4942
- const targetStreamMode = getPortStreamMode(toSchema, toInputPortId);
4943
- const streamMatch = candidates.find((portId) => getPortStreamMode(fromSchema, portId) === targetStreamMode);
4944
- if (streamMatch)
4945
- winner = streamMatch;
4946
- }
4947
- matches.set(toInputPortId, winner);
4948
- graph.addDataflow(new Dataflow(fromTaskId, winner, toTaskId, toInputPortId));
4949
- }
4950
- };
4951
- makeMatch(sourceSchema, targetSchema, sourceTask.id, targetTask.id, ([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema]) => {
4952
- const outputPortIdMatch = fromOutputPortId === toInputPortId;
4953
- const outputPortIdOutputInput = fromOutputPortId === "output" && toInputPortId === "input";
4954
- const portIdsCompatible = outputPortIdMatch || outputPortIdOutputInput;
4955
- return portIdsCompatible && isTypeCompatible(fromPortOutputSchema, toPortInputSchema, false);
4956
- });
4957
- makeMatch(sourceSchema, targetSchema, sourceTask.id, targetTask.id, ([_fromOutputPortId, fromPortOutputSchema], [_toInputPortId, toPortInputSchema]) => {
4958
- return isTypeCompatible(fromPortOutputSchema, toPortInputSchema, true);
4959
- });
4960
- const requiredInputs = new Set(typeof targetSchema === "object" ? targetSchema.required || [] : []);
4961
- const requiredInputsNeedingConnection = [...requiredInputs].filter((r) => !providedInputKeys.has(r) && !connectedInputKeys.has(r));
4962
- let unmatchedRequired = requiredInputsNeedingConnection.filter((r) => !matches.has(r));
4963
- if (unmatchedRequired.length > 0 && earlierTasks.length > 0) {
4964
- for (let i = 0;i < earlierTasks.length && unmatchedRequired.length > 0; i++) {
4965
- const earlierTask = earlierTasks[i];
4966
- const earlierOutputSchema = earlierTask.outputSchema();
4967
- if (earlierTask.type === "InputTask") {
4968
- const inputConfig = earlierTask.config;
4969
- const inputSchema = inputConfig?.inputSchema ?? inputConfig?.outputSchema;
4970
- const isManualSchema = inputSchema && typeof inputSchema === "object" && inputSchema["x-ui-manual"] === true;
4971
- const inputProperties = isManualSchema && inputSchema && typeof inputSchema === "object" && "properties" in inputSchema && inputSchema.properties && typeof inputSchema.properties === "object" ? new Set(Object.keys(inputSchema.properties)) : undefined;
4972
- for (const requiredInputId of [...unmatchedRequired]) {
4973
- if (matches.has(requiredInputId))
4974
- continue;
4975
- if (inputProperties && !inputProperties.has(requiredInputId))
4976
- continue;
4977
- matches.set(requiredInputId, requiredInputId);
4978
- graph.addDataflow(new Dataflow(earlierTask.id, requiredInputId, targetTask.id, requiredInputId));
4979
- }
4980
- unmatchedRequired = unmatchedRequired.filter((r) => !matches.has(r));
4981
- continue;
4982
- }
4983
- const makeMatchFromEarlier = (comparator) => {
4984
- if (typeof earlierOutputSchema === "boolean" || typeof targetSchema === "boolean") {
4985
- return;
4986
- }
4987
- for (const [fromOutputPortId, fromPortOutputSchema] of Object.entries(earlierOutputSchema.properties || {})) {
4988
- for (const requiredInputId of unmatchedRequired) {
4989
- const toPortInputSchema = targetSchema.properties?.[requiredInputId];
4990
- if (!matches.has(requiredInputId) && toPortInputSchema && comparator([fromOutputPortId, fromPortOutputSchema], [requiredInputId, toPortInputSchema])) {
4991
- matches.set(requiredInputId, fromOutputPortId);
4992
- graph.addDataflow(new Dataflow(earlierTask.id, fromOutputPortId, targetTask.id, requiredInputId));
4993
- }
4994
- }
4995
- }
4996
- };
4997
- makeMatchFromEarlier(([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema]) => {
4998
- const outputPortIdMatch = fromOutputPortId === toInputPortId;
4999
- const outputPortIdOutputInput = fromOutputPortId === "output" && toInputPortId === "input";
5000
- const portIdsCompatible = outputPortIdMatch || outputPortIdOutputInput;
5001
- return portIdsCompatible && isTypeCompatible(fromPortOutputSchema, toPortInputSchema, false);
5002
- });
5003
- makeMatchFromEarlier(([_fromOutputPortId, fromPortOutputSchema], [_toInputPortId, toPortInputSchema]) => {
5004
- return isTypeCompatible(fromPortOutputSchema, toPortInputSchema, true);
5005
- });
5006
- unmatchedRequired = unmatchedRequired.filter((r) => !matches.has(r));
5007
- }
5008
- }
5009
- const stillUnmatchedRequired = requiredInputsNeedingConnection.filter((r) => !matches.has(r));
5010
- if (stillUnmatchedRequired.length > 0) {
5011
- return {
5012
- matches,
5013
- error: `Could not find matches for required inputs [${stillUnmatchedRequired.join(", ")}] of ${targetTask.type}. ` + `Attempted to match from ${sourceTask.type} and earlier tasks.`,
5014
- unmatchedRequired: stillUnmatchedRequired
5015
- };
5016
- }
5017
- if (matches.size === 0 && requiredInputsNeedingConnection.length === 0) {
5018
- const existingTargetConnections = graph.getSourceDataflows(targetTask.id);
5019
- if (existingTargetConnections.length > 0) {
5020
- return { matches, unmatchedRequired: [] };
5021
- }
5022
- const hasRequiredInputs = requiredInputs.size > 0;
5023
- const allRequiredInputsProvided = hasRequiredInputs && [...requiredInputs].every((r) => providedInputKeys.has(r));
5024
- const hasInputsWithDefaults = typeof targetSchema === "object" && targetSchema.properties && Object.values(targetSchema.properties).some((prop) => prop && typeof prop === "object" && ("default" in prop));
5025
- if (!allRequiredInputsProvided && !hasInputsWithDefaults) {
5026
- return {
5027
- matches,
5028
- error: `Could not find a match between the outputs of ${sourceTask.type} and the inputs of ${targetTask.type}. ` + `You may need to connect the outputs to the inputs via connect() manually.`,
5029
- unmatchedRequired: []
5030
- };
5031
- }
5032
- }
5033
- return {
5034
- matches,
5035
- unmatchedRequired: []
5036
- };
5215
+ return autoConnect(graph, sourceTask, targetTask, options);
5037
5216
  }
5038
5217
  finalizeTemplate() {
5039
5218
  if (!this._iteratorTask || this.graph.getTasks().length === 0) {
@@ -5397,6 +5576,304 @@ ${baseIndent}}`;
5397
5576
  function resetMethodNameCache() {
5398
5577
  methodNameCache = undefined;
5399
5578
  }
5579
+ // src/task-graph/transforms/pick.ts
5580
+ import { areSemanticallyCompatible as areSemanticallyCompatible2 } from "@workglow/util/schema";
5581
+ function walk(value, path) {
5582
+ if (value == null)
5583
+ return;
5584
+ const parts = path.split(".");
5585
+ let cur = value;
5586
+ for (const p of parts) {
5587
+ if (cur == null)
5588
+ return;
5589
+ cur = cur[p];
5590
+ }
5591
+ return cur;
5592
+ }
5593
+ function walkSchema(schema, path) {
5594
+ const parts = path.split(".");
5595
+ let cur = schema;
5596
+ for (const p of parts) {
5597
+ if (!cur || typeof cur !== "object")
5598
+ return {};
5599
+ if (cur.type !== "object" || !cur.properties || !cur.properties[p]) {
5600
+ return {};
5601
+ }
5602
+ cur = cur.properties[p];
5603
+ }
5604
+ return cur;
5605
+ }
5606
+ var pickTransform = {
5607
+ id: "pick",
5608
+ title: "Pick field",
5609
+ category: "Structural",
5610
+ paramsSchema: {
5611
+ type: "object",
5612
+ properties: {
5613
+ path: { type: "string", description: "Dotted property path" }
5614
+ },
5615
+ required: ["path"]
5616
+ },
5617
+ inferOutputSchema(inputSchema, params) {
5618
+ return walkSchema(inputSchema, params.path);
5619
+ },
5620
+ apply(value, params) {
5621
+ return walk(value, params.path);
5622
+ },
5623
+ suggestFromSchemas(source, target) {
5624
+ if (source.type !== "object" || !source.properties) {
5625
+ return;
5626
+ }
5627
+ const props = source.properties;
5628
+ for (const [name, propSchema] of Object.entries(props)) {
5629
+ const compat = areSemanticallyCompatible2(propSchema, target);
5630
+ if (compat === "static")
5631
+ return { score: 1, params: { path: name } };
5632
+ if (compat === "runtime")
5633
+ return { score: 0.6, params: { path: name } };
5634
+ }
5635
+ return;
5636
+ }
5637
+ };
5638
+
5639
+ // src/task-graph/transforms/index-access.ts
5640
+ import { areSemanticallyCompatible as areSemanticallyCompatible3 } from "@workglow/util/schema";
5641
+ function doIndex(value, idx) {
5642
+ if (!Array.isArray(value))
5643
+ return;
5644
+ const i = idx < 0 ? value.length + idx : idx;
5645
+ return value[i];
5646
+ }
5647
+ var indexTransform = {
5648
+ id: "index",
5649
+ title: "Array index",
5650
+ category: "Structural",
5651
+ paramsSchema: {
5652
+ type: "object",
5653
+ properties: {
5654
+ index: { type: "integer", description: "Array index (negative counts from end)" }
5655
+ },
5656
+ required: ["index"]
5657
+ },
5658
+ inferOutputSchema(inputSchema) {
5659
+ const s = inputSchema;
5660
+ if (s?.type === "array" && s.items)
5661
+ return s.items;
5662
+ return {};
5663
+ },
5664
+ apply(value, params) {
5665
+ return doIndex(value, params.index);
5666
+ },
5667
+ suggestFromSchemas(source, target) {
5668
+ const s = source;
5669
+ if (s?.type !== "array" || !s.items)
5670
+ return;
5671
+ const compat = areSemanticallyCompatible3(s.items, target);
5672
+ if (compat === "static")
5673
+ return { score: 0.9, params: { index: 0 } };
5674
+ if (compat === "runtime")
5675
+ return { score: 0.5, params: { index: 0 } };
5676
+ return;
5677
+ }
5678
+ };
5679
+
5680
+ // src/task-graph/transforms/coalesce.ts
5681
+ function stripNullable(schema) {
5682
+ const s = schema;
5683
+ if (!s || typeof s !== "object")
5684
+ return schema;
5685
+ if (Array.isArray(s.type)) {
5686
+ const nonNull = s.type.filter((t) => t !== "null");
5687
+ if (nonNull.length === 1)
5688
+ return { ...s, type: nonNull[0] };
5689
+ return { ...s, type: nonNull };
5690
+ }
5691
+ return schema;
5692
+ }
5693
+ var coalesceTransform = {
5694
+ id: "coalesce",
5695
+ title: "Coalesce null",
5696
+ category: "Conversion",
5697
+ paramsSchema: {
5698
+ type: "object",
5699
+ properties: { defaultValue: {} },
5700
+ required: ["defaultValue"]
5701
+ },
5702
+ inferOutputSchema: (input) => stripNullable(input),
5703
+ apply: (v, { defaultValue }) => v == null ? defaultValue : v
5704
+ };
5705
+
5706
+ // src/task-graph/transforms/string-casts.ts
5707
+ var stringSchema = { type: "string" };
5708
+ var uppercaseTransform = {
5709
+ id: "uppercase",
5710
+ title: "Uppercase",
5711
+ category: "String",
5712
+ paramsSchema: undefined,
5713
+ inferOutputSchema: () => stringSchema,
5714
+ apply: (v) => String(v ?? "").toUpperCase()
5715
+ };
5716
+ var lowercaseTransform = {
5717
+ id: "lowercase",
5718
+ title: "Lowercase",
5719
+ category: "String",
5720
+ paramsSchema: undefined,
5721
+ inferOutputSchema: () => stringSchema,
5722
+ apply: (v) => String(v ?? "").toLowerCase()
5723
+ };
5724
+ var truncateTransform = {
5725
+ id: "truncate",
5726
+ title: "Truncate",
5727
+ category: "String",
5728
+ paramsSchema: {
5729
+ type: "object",
5730
+ properties: { max: { type: "integer", minimum: 0 } },
5731
+ required: ["max"]
5732
+ },
5733
+ inferOutputSchema: () => stringSchema,
5734
+ apply: (v, { max }) => String(v ?? "").slice(0, max)
5735
+ };
5736
+ var substringTransform = {
5737
+ id: "substring",
5738
+ title: "Substring",
5739
+ category: "String",
5740
+ paramsSchema: {
5741
+ type: "object",
5742
+ properties: {
5743
+ start: { type: "integer" },
5744
+ end: { type: "integer" }
5745
+ },
5746
+ required: ["start"]
5747
+ },
5748
+ inferOutputSchema: () => stringSchema,
5749
+ apply: (v, { start, end }) => String(v ?? "").slice(start, end)
5750
+ };
5751
+
5752
+ // src/task-graph/transforms/date-conversions.ts
5753
+ var isoSchema = { type: "string", format: "date-time" };
5754
+ var numberSchema = { type: "number" };
5755
+ function hasDateTimeFormat(schema) {
5756
+ const s = schema;
5757
+ return s?.type === "string" && s.format === "date-time";
5758
+ }
5759
+ var unixToIsoDateTransform = {
5760
+ id: "unixToIsoDate",
5761
+ title: "Unix timestamp \u2192 ISO date",
5762
+ category: "Date",
5763
+ paramsSchema: {
5764
+ type: "object",
5765
+ properties: {
5766
+ unit: { type: "string", enum: ["s", "ms"] }
5767
+ },
5768
+ required: ["unit"]
5769
+ },
5770
+ inferOutputSchema: () => isoSchema,
5771
+ apply: (v, { unit }) => {
5772
+ const n = Number(v);
5773
+ return new Date(unit === "s" ? n * 1000 : n).toISOString();
5774
+ },
5775
+ suggestFromSchemas(source, target) {
5776
+ const s = source;
5777
+ if (s?.type !== "number" && s?.type !== "integer")
5778
+ return;
5779
+ if (!hasDateTimeFormat(target))
5780
+ return;
5781
+ return { score: 0.85, params: { unit: "s" } };
5782
+ }
5783
+ };
5784
+ var isoDateToUnixTransform = {
5785
+ id: "isoDateToUnix",
5786
+ title: "ISO date \u2192 Unix ms",
5787
+ category: "Date",
5788
+ paramsSchema: undefined,
5789
+ inferOutputSchema: () => numberSchema,
5790
+ apply: (v) => new Date(String(v)).getTime(),
5791
+ suggestFromSchemas(source, target) {
5792
+ if (!hasDateTimeFormat(source))
5793
+ return;
5794
+ const t = target;
5795
+ if (t?.type !== "number" && t?.type !== "integer")
5796
+ return;
5797
+ return { score: 0.9, params: {} };
5798
+ }
5799
+ };
5800
+
5801
+ // src/task-graph/transforms/scalar-conversions.ts
5802
+ var stringSchema2 = { type: "string" };
5803
+ var booleanSchema = { type: "boolean" };
5804
+ var numberToStringTransform = {
5805
+ id: "numberToString",
5806
+ title: "Number \u2192 String",
5807
+ category: "Conversion",
5808
+ paramsSchema: undefined,
5809
+ inferOutputSchema: () => stringSchema2,
5810
+ apply: (v) => String(v),
5811
+ suggestFromSchemas(source, target) {
5812
+ const s = source;
5813
+ const t = target;
5814
+ if ((s?.type === "number" || s?.type === "integer") && t?.type === "string") {
5815
+ return { score: 0.8, params: {} };
5816
+ }
5817
+ return;
5818
+ }
5819
+ };
5820
+ var toBooleanTransform = {
5821
+ id: "toBoolean",
5822
+ title: "To Boolean",
5823
+ category: "Conversion",
5824
+ paramsSchema: undefined,
5825
+ inferOutputSchema: () => booleanSchema,
5826
+ apply: (v) => {
5827
+ if (typeof v === "boolean")
5828
+ return v;
5829
+ if (typeof v === "number")
5830
+ return v !== 0;
5831
+ if (typeof v === "string")
5832
+ return v.toLowerCase() === "true" || v === "1";
5833
+ return Boolean(v);
5834
+ }
5835
+ };
5836
+ var stringifyTransform = {
5837
+ id: "stringify",
5838
+ title: "JSON.stringify",
5839
+ category: "Conversion",
5840
+ paramsSchema: undefined,
5841
+ inferOutputSchema: () => stringSchema2,
5842
+ apply: (v) => JSON.stringify(v),
5843
+ suggestFromSchemas(source, target) {
5844
+ const t = target;
5845
+ return t?.type === "string" ? { score: 0.4, params: {} } : undefined;
5846
+ }
5847
+ };
5848
+ var parseJsonTransform = {
5849
+ id: "parseJson",
5850
+ title: "Parse JSON",
5851
+ category: "Conversion",
5852
+ paramsSchema: undefined,
5853
+ inferOutputSchema: () => ({}),
5854
+ apply: (v) => JSON.parse(String(v))
5855
+ };
5856
+
5857
+ // src/task-graph/transforms/index.ts
5858
+ function registerBuiltInTransforms() {
5859
+ const all = [
5860
+ pickTransform,
5861
+ indexTransform,
5862
+ coalesceTransform,
5863
+ uppercaseTransform,
5864
+ lowercaseTransform,
5865
+ truncateTransform,
5866
+ substringTransform,
5867
+ unixToIsoDateTransform,
5868
+ isoDateToUnixTransform,
5869
+ numberToStringTransform,
5870
+ toBooleanTransform,
5871
+ stringifyTransform,
5872
+ parseJsonTransform
5873
+ ];
5874
+ for (const t of all)
5875
+ TransformRegistry.registerTransform(t);
5876
+ }
5400
5877
  // src/task/EntitlementProfiles.ts
5401
5878
  var BROWSER_GRANTS = [
5402
5879
  { id: Entitlements.NETWORK_HTTP },
@@ -5919,7 +6396,10 @@ var iteratorTaskConfigSchema = {
5919
6396
  concurrencyLimit: { type: "integer", minimum: 1 },
5920
6397
  batchSize: { type: "integer", minimum: 1 },
5921
6398
  maxIterations: {
5922
- oneOf: [{ type: "integer", minimum: 1 }, { type: "string", const: "unbounded" }]
6399
+ oneOf: [
6400
+ { type: "integer", minimum: 1 },
6401
+ { type: "string", const: "unbounded" }
6402
+ ]
5923
6403
  },
5924
6404
  iterationInputConfig: { type: "object", additionalProperties: true }
5925
6405
  },
@@ -6434,7 +6914,10 @@ var whileTaskConfigSchema = {
6434
6914
  ...graphAsTaskConfigSchema["properties"],
6435
6915
  condition: {},
6436
6916
  maxIterations: {
6437
- oneOf: [{ type: "integer", minimum: 1 }, { type: "string", const: "unbounded" }]
6917
+ oneOf: [
6918
+ { type: "integer", minimum: 1 },
6919
+ { type: "string", const: "unbounded" }
6920
+ ]
6438
6921
  },
6439
6922
  chainIterations: { type: "boolean" },
6440
6923
  conditionField: { type: "string" },
@@ -7009,8 +7492,8 @@ import {
7009
7492
  JobQueueServer
7010
7493
  } from "@workglow/job-queue";
7011
7494
  import { InMemoryQueueStorage } from "@workglow/storage";
7012
- import { createServiceToken as createServiceToken4, globalServiceRegistry as globalServiceRegistry3 } from "@workglow/util";
7013
- var JOB_QUEUE_FACTORY = createServiceToken4("taskgraph.jobQueueFactory");
7495
+ import { createServiceToken as createServiceToken5, globalServiceRegistry as globalServiceRegistry4 } from "@workglow/util";
7496
+ var JOB_QUEUE_FACTORY = createServiceToken5("taskgraph.jobQueueFactory");
7014
7497
  var defaultJobQueueFactory = async ({
7015
7498
  queueName,
7016
7499
  jobClass,
@@ -7037,7 +7520,7 @@ var defaultJobQueueFactory = async ({
7037
7520
  return { server, client, storage };
7038
7521
  };
7039
7522
  function registerJobQueueFactory(factory) {
7040
- globalServiceRegistry3.registerInstance(JOB_QUEUE_FACTORY, factory);
7523
+ globalServiceRegistry4.registerInstance(JOB_QUEUE_FACTORY, factory);
7041
7524
  }
7042
7525
  function createJobQueueFactoryWithOptions(defaultOptions = {}) {
7043
7526
  return async ({
@@ -7071,12 +7554,12 @@ function createJobQueueFactoryWithOptions(defaultOptions = {}) {
7071
7554
  };
7072
7555
  }
7073
7556
  function getJobQueueFactory() {
7074
- if (!globalServiceRegistry3.has(JOB_QUEUE_FACTORY)) {
7557
+ if (!globalServiceRegistry4.has(JOB_QUEUE_FACTORY)) {
7075
7558
  registerJobQueueFactory(defaultJobQueueFactory);
7076
7559
  }
7077
- return globalServiceRegistry3.get(JOB_QUEUE_FACTORY);
7560
+ return globalServiceRegistry4.get(JOB_QUEUE_FACTORY);
7078
7561
  }
7079
- if (!globalServiceRegistry3.has(JOB_QUEUE_FACTORY)) {
7562
+ if (!globalServiceRegistry4.has(JOB_QUEUE_FACTORY)) {
7080
7563
  registerJobQueueFactory(defaultJobQueueFactory);
7081
7564
  }
7082
7565
  // src/task/MapTask.ts
@@ -7183,6 +7666,7 @@ var reduceTaskConfigSchema = {
7183
7666
  ...iteratorTaskConfigSchema["properties"],
7184
7667
  initialValue: {}
7185
7668
  },
7669
+ required: iteratorTaskConfigSchema.required,
7186
7670
  additionalProperties: false
7187
7671
  };
7188
7672
 
@@ -7272,9 +7756,9 @@ queueMicrotask(() => {
7272
7756
  });
7273
7757
  // src/task/TaskRegistry.ts
7274
7758
  import {
7275
- createServiceToken as createServiceToken5,
7759
+ createServiceToken as createServiceToken6,
7276
7760
  getLogger as getLogger6,
7277
- globalServiceRegistry as globalServiceRegistry4,
7761
+ globalServiceRegistry as globalServiceRegistry5,
7278
7762
  registerInputCompactor,
7279
7763
  registerInputResolver
7280
7764
  } from "@workglow/util";
@@ -7312,13 +7796,13 @@ var TaskRegistry = {
7312
7796
  registerTask,
7313
7797
  unregisterTask
7314
7798
  };
7315
- var TASK_CONSTRUCTORS = createServiceToken5("task.constructors");
7316
- globalServiceRegistry4.registerIfAbsent(TASK_CONSTRUCTORS, () => TaskRegistry.all, true);
7799
+ var TASK_CONSTRUCTORS = createServiceToken6("task.constructors");
7800
+ globalServiceRegistry5.registerIfAbsent(TASK_CONSTRUCTORS, () => TaskRegistry.all, true);
7317
7801
  function getGlobalTaskConstructors() {
7318
- return globalServiceRegistry4.get(TASK_CONSTRUCTORS);
7802
+ return globalServiceRegistry5.get(TASK_CONSTRUCTORS);
7319
7803
  }
7320
7804
  function setGlobalTaskConstructors(map) {
7321
- globalServiceRegistry4.registerInstance(TASK_CONSTRUCTORS, map);
7805
+ globalServiceRegistry5.registerInstance(TASK_CONSTRUCTORS, map);
7322
7806
  }
7323
7807
  function getTaskConstructors(registry) {
7324
7808
  if (!registry)
@@ -7415,7 +7899,11 @@ var createGraphFromGraphJSON = (graphJsonObj, registry, options) => {
7415
7899
  subGraph.addTask(createTaskFromGraphJSON(subitem, registry, options));
7416
7900
  }
7417
7901
  for (const subitem of graphJsonObj.dataflows) {
7418
- subGraph.addDataflow(new Dataflow(subitem.sourceTaskId, subitem.sourceTaskPortId, subitem.targetTaskId, subitem.targetTaskPortId));
7902
+ const dataflow = new Dataflow(subitem.sourceTaskId, subitem.sourceTaskPortId, subitem.targetTaskId, subitem.targetTaskPortId);
7903
+ if (subitem.transforms && subitem.transforms.length > 0) {
7904
+ dataflow.setTransforms(subitem.transforms);
7905
+ }
7906
+ subGraph.addDataflow(dataflow);
7419
7907
  }
7420
7908
  return subGraph;
7421
7909
  };
@@ -7473,8 +7961,8 @@ var registerBaseTasks = () => {
7473
7961
  return tasks;
7474
7962
  };
7475
7963
  // src/storage/TaskGraphRepository.ts
7476
- import { createServiceToken as createServiceToken6, EventEmitter as EventEmitter7 } from "@workglow/util";
7477
- var TASK_GRAPH_REPOSITORY = createServiceToken6("taskgraph.taskGraphRepository");
7964
+ import { createServiceToken as createServiceToken7, EventEmitter as EventEmitter7 } from "@workglow/util";
7965
+ var TASK_GRAPH_REPOSITORY = createServiceToken7("taskgraph.taskGraphRepository");
7478
7966
 
7479
7967
  class TaskGraphRepository {
7480
7968
  type = "TaskGraphRepository";
@@ -7634,7 +8122,13 @@ class TaskOutputTabularRepository extends TaskOutputRepository {
7634
8122
  export {
7635
8123
  wrapSchemaInArray,
7636
8124
  whileTaskConfigSchema,
8125
+ uppercaseTransform,
8126
+ unixToIsoDateTransform,
8127
+ truncateTransform,
8128
+ toBooleanTransform,
7637
8129
  taskPrototypeHasOwnExecute,
8130
+ substringTransform,
8131
+ stringifyTransform,
7638
8132
  setTaskQueueRegistry,
7639
8133
  setGlobalTaskConstructors,
7640
8134
  serialGraph,
@@ -7648,20 +8142,27 @@ export {
7648
8142
  resetMethodNameCache,
7649
8143
  removeIterationProperties,
7650
8144
  registerJobQueueFactory,
8145
+ registerBuiltInTransforms,
7651
8146
  registerBaseTasks,
7652
8147
  reduceTaskConfigSchema,
7653
8148
  pipe,
8149
+ pickTransform,
8150
+ parseJsonTransform,
7654
8151
  parallel,
8152
+ numberToStringTransform,
7655
8153
  mergeResources,
7656
8154
  mergeEntitlements,
7657
8155
  mergeEntitlementPair,
7658
8156
  mergeChainedOutputToInput,
7659
8157
  mapTaskConfigSchema,
8158
+ lowercaseTransform,
7660
8159
  iteratorTaskConfigSchema,
8160
+ isoDateToUnixTransform,
7661
8161
  isTaskStreamable,
7662
8162
  isStrictArraySchema,
7663
8163
  isIterationProperty,
7664
8164
  isFlexibleSchema,
8165
+ indexTransform,
7665
8166
  hasVectorOutput,
7666
8167
  hasVectorLikeInput,
7667
8168
  hasStructuredOutput,
@@ -7716,9 +8217,11 @@ export {
7716
8217
  computeGraphInputSchema,
7717
8218
  computeGraphEntitlements,
7718
8219
  compactSchemaInputs,
8220
+ coalesceTransform,
7719
8221
  can,
7720
8222
  calculateNodeDepths,
7721
8223
  buildIterationInputSchema,
8224
+ autoConnect,
7722
8225
  addIterationContextToSchema,
7723
8226
  addBoundaryNodesToGraphJson,
7724
8227
  addBoundaryNodesToDependencyJson,
@@ -7727,6 +8230,7 @@ export {
7727
8230
  WhileTaskRunner,
7728
8231
  WhileTask,
7729
8232
  WHILE_CONTEXT_SCHEMA,
8233
+ TransformRegistry,
7730
8234
  TaskTimeoutError,
7731
8235
  TaskStatus,
7732
8236
  TaskSerializationError,
@@ -7752,6 +8256,7 @@ export {
7752
8256
  TaskConfigSchema,
7753
8257
  TaskAbortedError,
7754
8258
  Task,
8259
+ TRANSFORM_DEFS,
7755
8260
  TASK_OUTPUT_REPOSITORY,
7756
8261
  TASK_GRAPH_REPOSITORY,
7757
8262
  TASK_CONSTRUCTORS,
@@ -7793,4 +8298,4 @@ export {
7793
8298
  BROWSER_GRANTS
7794
8299
  };
7795
8300
 
7796
- //# debugId=ACCBFB832EC2FB9F64756E2164756E21
8301
+ //# debugId=2328438A94292C4964756E2164756E21