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