@workglow/task-graph 0.0.90 → 0.0.91

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 (37) hide show
  1. package/dist/browser.js +402 -12
  2. package/dist/browser.js.map +13 -12
  3. package/dist/bun.js +402 -12
  4. package/dist/bun.js.map +13 -12
  5. package/dist/node.js +402 -12
  6. package/dist/node.js.map +13 -12
  7. package/dist/task/ITask.d.ts +7 -0
  8. package/dist/task/ITask.d.ts.map +1 -1
  9. package/dist/task/StreamTypes.d.ts +96 -0
  10. package/dist/task/StreamTypes.d.ts.map +1 -0
  11. package/dist/task/TaskEvents.d.ts +7 -0
  12. package/dist/task/TaskEvents.d.ts.map +1 -1
  13. package/dist/task/TaskJSON.d.ts +3 -2
  14. package/dist/task/TaskJSON.d.ts.map +1 -1
  15. package/dist/task/TaskRunner.d.ts +7 -0
  16. package/dist/task/TaskRunner.d.ts.map +1 -1
  17. package/dist/task/TaskTypes.d.ts +4 -1
  18. package/dist/task/TaskTypes.d.ts.map +1 -1
  19. package/dist/task/index.d.ts +1 -0
  20. package/dist/task/index.d.ts.map +1 -1
  21. package/dist/task-graph/Dataflow.d.ts +34 -0
  22. package/dist/task-graph/Dataflow.d.ts.map +1 -1
  23. package/dist/task-graph/DataflowEvents.d.ts +2 -0
  24. package/dist/task-graph/DataflowEvents.d.ts.map +1 -1
  25. package/dist/task-graph/ITaskGraph.d.ts +6 -0
  26. package/dist/task-graph/ITaskGraph.d.ts.map +1 -1
  27. package/dist/task-graph/TaskGraph.d.ts +14 -0
  28. package/dist/task-graph/TaskGraph.d.ts.map +1 -1
  29. package/dist/task-graph/TaskGraphEvents.d.ts +7 -0
  30. package/dist/task-graph/TaskGraphEvents.d.ts.map +1 -1
  31. package/dist/task-graph/TaskGraphRunner.d.ts +25 -0
  32. package/dist/task-graph/TaskGraphRunner.d.ts.map +1 -1
  33. package/dist/task-graph/TaskGraphScheduler.d.ts +9 -0
  34. package/dist/task-graph/TaskGraphScheduler.d.ts.map +1 -1
  35. package/dist/task-graph/Workflow.d.ts +36 -1
  36. package/dist/task-graph/Workflow.d.ts.map +1 -1
  37. package/package.json +7 -7
package/dist/browser.js CHANGED
@@ -6,6 +6,7 @@ var TaskStatus = {
6
6
  PENDING: "PENDING",
7
7
  DISABLED: "DISABLED",
8
8
  PROCESSING: "PROCESSING",
9
+ STREAMING: "STREAMING",
9
10
  COMPLETED: "COMPLETED",
10
11
  ABORTING: "ABORTING",
11
12
  FAILED: "FAILED"
@@ -35,10 +36,62 @@ class Dataflow {
35
36
  value = undefined;
36
37
  status = TaskStatus.PENDING;
37
38
  error;
39
+ stream = undefined;
40
+ setStream(stream) {
41
+ this.stream = stream;
42
+ }
43
+ getStream() {
44
+ return this.stream;
45
+ }
46
+ async awaitStreamValue() {
47
+ if (!this.stream)
48
+ return;
49
+ const reader = this.stream.getReader();
50
+ let accumulatedText = "";
51
+ let lastSnapshotData = undefined;
52
+ let finishData = undefined;
53
+ let hasTextDelta = false;
54
+ try {
55
+ while (true) {
56
+ const { done, value: event } = await reader.read();
57
+ if (done)
58
+ break;
59
+ switch (event.type) {
60
+ case "text-delta":
61
+ hasTextDelta = true;
62
+ accumulatedText += event.textDelta;
63
+ break;
64
+ case "snapshot":
65
+ lastSnapshotData = event.data;
66
+ break;
67
+ case "finish":
68
+ finishData = event.data;
69
+ break;
70
+ case "error":
71
+ break;
72
+ }
73
+ }
74
+ } finally {
75
+ reader.releaseLock();
76
+ this.stream = undefined;
77
+ }
78
+ if (lastSnapshotData !== undefined) {
79
+ this.setPortData(lastSnapshotData);
80
+ } else if (finishData && Object.keys(finishData).length > 0) {
81
+ this.setPortData(finishData);
82
+ } else if (hasTextDelta) {
83
+ if (this.sourceTaskPortId === DATAFLOW_ALL_PORTS) {
84
+ this.value = { text: accumulatedText };
85
+ } else {
86
+ this.value = accumulatedText;
87
+ }
88
+ }
89
+ }
38
90
  reset() {
39
91
  this.status = TaskStatus.PENDING;
40
92
  this.error = undefined;
41
93
  this.value = undefined;
94
+ this.stream = undefined;
42
95
  this.emit("reset");
43
96
  this.emit("status", this.status);
44
97
  }
@@ -50,6 +103,9 @@ class Dataflow {
50
103
  case TaskStatus.PROCESSING:
51
104
  this.emit("start");
52
105
  break;
106
+ case TaskStatus.STREAMING:
107
+ this.emit("streaming");
108
+ break;
53
109
  case TaskStatus.COMPLETED:
54
110
  this.emit("complete");
55
111
  break;
@@ -397,6 +453,49 @@ async function resolveSchemaInputs(input, schema, config) {
397
453
  return resolved;
398
454
  }
399
455
 
456
+ // src/task/StreamTypes.ts
457
+ function getPortStreamMode(schema, portId) {
458
+ if (typeof schema === "boolean")
459
+ return "none";
460
+ const prop = schema.properties?.[portId];
461
+ if (!prop || typeof prop === "boolean")
462
+ return "none";
463
+ const xStream = prop["x-stream"];
464
+ if (xStream === "append" || xStream === "replace")
465
+ return xStream;
466
+ return "none";
467
+ }
468
+ function getOutputStreamMode(outputSchema) {
469
+ if (typeof outputSchema === "boolean")
470
+ return "none";
471
+ const props = outputSchema.properties;
472
+ if (!props)
473
+ return "none";
474
+ let found = "none";
475
+ for (const prop of Object.values(props)) {
476
+ if (!prop || typeof prop === "boolean")
477
+ continue;
478
+ const xStream = prop["x-stream"];
479
+ if (xStream === "append")
480
+ return "append";
481
+ if (xStream === "replace")
482
+ found = "replace";
483
+ }
484
+ return found;
485
+ }
486
+ function isTaskStreamable(task) {
487
+ if (typeof task.executeStream !== "function")
488
+ return false;
489
+ return getOutputStreamMode(task.outputSchema()) !== "none";
490
+ }
491
+ function edgeNeedsAccumulation(sourceSchema, sourcePort, targetSchema, targetPort) {
492
+ const sourceMode = getPortStreamMode(sourceSchema, sourcePort);
493
+ if (sourceMode === "none")
494
+ return false;
495
+ const targetMode = getPortStreamMode(targetSchema, targetPort);
496
+ return sourceMode !== targetMode;
497
+ }
498
+
400
499
  // src/task/TaskRunner.ts
401
500
  class TaskRunner {
402
501
  running = false;
@@ -426,14 +525,27 @@ class TaskRunner {
426
525
  }
427
526
  const inputs = this.task.runInputData;
428
527
  let outputs;
528
+ const isStreamable = isTaskStreamable(this.task);
429
529
  if (this.task.cacheable) {
430
530
  outputs = await this.outputCache?.getOutput(this.task.type, inputs);
431
531
  if (outputs) {
432
- this.task.runOutputData = await this.executeTaskReactive(inputs, outputs);
532
+ if (isStreamable) {
533
+ this.task.runOutputData = outputs;
534
+ this.task.emit("stream_start");
535
+ this.task.emit("stream_chunk", { type: "finish", data: outputs });
536
+ this.task.emit("stream_end", outputs);
537
+ this.task.runOutputData = await this.executeTaskReactive(inputs, outputs);
538
+ } else {
539
+ this.task.runOutputData = await this.executeTaskReactive(inputs, outputs);
540
+ }
433
541
  }
434
542
  }
435
543
  if (!outputs) {
436
- outputs = await this.executeTask(inputs);
544
+ if (isStreamable) {
545
+ outputs = await this.executeStreamingTask(inputs);
546
+ } else {
547
+ outputs = await this.executeTask(inputs);
548
+ }
437
549
  if (this.task.cacheable && outputs !== undefined) {
438
550
  await this.outputCache?.saveOutput(this.task.type, inputs, outputs);
439
551
  }
@@ -492,6 +604,64 @@ class TaskRunner {
492
604
  const reactiveResult = await this.task.executeReactive(input, output, { own: this.own });
493
605
  return Object.assign({}, output, reactiveResult ?? {});
494
606
  }
607
+ async executeStreamingTask(input) {
608
+ const streamMode = getOutputStreamMode(this.task.outputSchema());
609
+ let accumulated = "";
610
+ let chunkCount = 0;
611
+ let finalOutput;
612
+ this.task.emit("stream_start");
613
+ const stream = this.task.executeStream(input, {
614
+ signal: this.abortController.signal,
615
+ updateProgress: this.handleProgress.bind(this),
616
+ own: this.own,
617
+ registry: this.registry
618
+ });
619
+ for await (const event of stream) {
620
+ chunkCount++;
621
+ if (chunkCount === 1) {
622
+ this.task.status = TaskStatus.STREAMING;
623
+ this.task.emit("status", this.task.status);
624
+ }
625
+ if (event.type === "snapshot") {
626
+ this.task.runOutputData = event.data;
627
+ }
628
+ this.task.emit("stream_chunk", event);
629
+ switch (event.type) {
630
+ case "text-delta": {
631
+ accumulated += event.textDelta;
632
+ const progress = Math.min(99, Math.round(100 * (1 - Math.exp(-0.02 * chunkCount))));
633
+ await this.handleProgress(progress);
634
+ break;
635
+ }
636
+ case "snapshot": {
637
+ const progress = Math.min(99, Math.round(100 * (1 - Math.exp(-0.02 * chunkCount))));
638
+ await this.handleProgress(progress);
639
+ break;
640
+ }
641
+ case "finish": {
642
+ if (streamMode === "append") {
643
+ const text = accumulated.length > 0 ? accumulated : event.data?.text ?? "";
644
+ finalOutput = { ...event.data || {}, text };
645
+ } else if (streamMode === "replace") {
646
+ finalOutput = event.data;
647
+ }
648
+ break;
649
+ }
650
+ case "error": {
651
+ throw event.error;
652
+ }
653
+ }
654
+ }
655
+ if (this.abortController?.signal.aborted) {
656
+ throw new TaskAbortedError("Task aborted during streaming");
657
+ }
658
+ if (finalOutput !== undefined) {
659
+ this.task.runOutputData = finalOutput;
660
+ }
661
+ this.task.emit("stream_end", this.task.runOutputData);
662
+ const reactiveResult = await this.executeTaskReactive(input, this.task.runOutputData || {});
663
+ return reactiveResult;
664
+ }
495
665
  async handleStart(config = {}) {
496
666
  if (this.task.status === TaskStatus.PROCESSING)
497
667
  return;
@@ -1185,6 +1355,7 @@ class TopologicalScheduler {
1185
1355
  }
1186
1356
  }
1187
1357
  onTaskCompleted(taskId) {}
1358
+ onTaskStreaming(taskId) {}
1188
1359
  reset() {
1189
1360
  this.sortedNodes = this.dag.topologicallySortedNodes();
1190
1361
  this.currentIndex = 0;
@@ -1194,11 +1365,13 @@ class TopologicalScheduler {
1194
1365
  class DependencyBasedScheduler {
1195
1366
  dag;
1196
1367
  completedTasks;
1368
+ streamingTasks;
1197
1369
  pendingTasks;
1198
1370
  nextResolver = null;
1199
1371
  constructor(dag) {
1200
1372
  this.dag = dag;
1201
1373
  this.completedTasks = new Set;
1374
+ this.streamingTasks = new Set;
1202
1375
  this.pendingTasks = new Set;
1203
1376
  this.reset();
1204
1377
  }
@@ -1213,8 +1386,23 @@ class DependencyBasedScheduler {
1213
1386
  return false;
1214
1387
  }
1215
1388
  }
1216
- const dependencies = sourceDataflows.filter((df) => df.status !== TaskStatus.DISABLED).map((dataflow) => dataflow.sourceTaskId);
1217
- return dependencies.every((dep) => this.completedTasks.has(dep));
1389
+ const activeDataflows = sourceDataflows.filter((df) => df.status !== TaskStatus.DISABLED);
1390
+ return activeDataflows.every((df) => {
1391
+ const depId = df.sourceTaskId;
1392
+ if (this.completedTasks.has(depId))
1393
+ return true;
1394
+ if (this.streamingTasks.has(depId)) {
1395
+ const sourceTask = this.dag.getTask(depId);
1396
+ if (sourceTask) {
1397
+ const sourceMode = getPortStreamMode(sourceTask.outputSchema(), df.sourceTaskPortId);
1398
+ const targetMode = getPortStreamMode(task.inputSchema(), df.targetTaskPortId);
1399
+ if (sourceMode !== "none" && sourceMode === targetMode) {
1400
+ return true;
1401
+ }
1402
+ }
1403
+ }
1404
+ return false;
1405
+ });
1218
1406
  }
1219
1407
  async waitForNextTask() {
1220
1408
  if (this.pendingTasks.size === 0)
@@ -1269,8 +1457,26 @@ class DependencyBasedScheduler {
1269
1457
  }
1270
1458
  }
1271
1459
  }
1460
+ onTaskStreaming(taskId) {
1461
+ this.streamingTasks.add(taskId);
1462
+ for (const task of Array.from(this.pendingTasks)) {
1463
+ if (task.status === TaskStatus.DISABLED) {
1464
+ this.pendingTasks.delete(task);
1465
+ }
1466
+ }
1467
+ if (this.nextResolver) {
1468
+ const readyTask = Array.from(this.pendingTasks).find((task) => this.isTaskReady(task));
1469
+ if (readyTask) {
1470
+ this.pendingTasks.delete(readyTask);
1471
+ const resolver = this.nextResolver;
1472
+ this.nextResolver = null;
1473
+ resolver(readyTask);
1474
+ }
1475
+ }
1476
+ }
1272
1477
  reset() {
1273
1478
  this.completedTasks.clear();
1479
+ this.streamingTasks.clear();
1274
1480
  this.pendingTasks = new Set(this.dag.topologicallySortedNodes());
1275
1481
  this.nextResolver = null;
1276
1482
  }
@@ -1507,7 +1713,12 @@ class TaskGraphRunner {
1507
1713
  }
1508
1714
  }
1509
1715
  async runTask(task, input) {
1716
+ const isStreamable = isTaskStreamable(task);
1717
+ await this.awaitStreamInputs(task);
1510
1718
  this.copyInputFromEdgesToNode(task);
1719
+ if (isStreamable) {
1720
+ return this.runStreamingTask(task, input);
1721
+ }
1511
1722
  const results = await task.runner.run(input, {
1512
1723
  outputCache: this.outputCache,
1513
1724
  updateProgress: async (task2, progress, message, ...args) => await this.handleProgress(task2, progress, message, ...args),
@@ -1520,6 +1731,93 @@ class TaskGraphRunner {
1520
1731
  data: results
1521
1732
  };
1522
1733
  }
1734
+ async awaitStreamInputs(task) {
1735
+ const dataflows = this.graph.getSourceDataflows(task.config.id);
1736
+ const streamPromises = dataflows.filter((df) => df.stream !== undefined).map((df) => df.awaitStreamValue());
1737
+ if (streamPromises.length > 0) {
1738
+ await Promise.all(streamPromises);
1739
+ }
1740
+ }
1741
+ async runStreamingTask(task, input) {
1742
+ const streamMode = getOutputStreamMode(task.outputSchema());
1743
+ let streamingNotified = false;
1744
+ const onStatus = (status) => {
1745
+ if (status === TaskStatus.STREAMING && !streamingNotified) {
1746
+ streamingNotified = true;
1747
+ this.pushStatusFromNodeToEdges(this.graph, task, TaskStatus.STREAMING);
1748
+ this.pushStreamToEdges(task, streamMode);
1749
+ this.processScheduler.onTaskStreaming(task.config.id);
1750
+ }
1751
+ };
1752
+ const onStreamStart = () => {
1753
+ this.graph.emit("task_stream_start", task.config.id);
1754
+ };
1755
+ const onStreamChunk = (event) => {
1756
+ this.graph.emit("task_stream_chunk", task.config.id, event);
1757
+ };
1758
+ const onStreamEnd = (output) => {
1759
+ this.graph.emit("task_stream_end", task.config.id, output);
1760
+ };
1761
+ task.on("status", onStatus);
1762
+ task.on("stream_start", onStreamStart);
1763
+ task.on("stream_chunk", onStreamChunk);
1764
+ task.on("stream_end", onStreamEnd);
1765
+ try {
1766
+ const results = await task.runner.run(input, {
1767
+ outputCache: this.outputCache,
1768
+ updateProgress: async (task2, progress, message, ...args) => await this.handleProgress(task2, progress, message, ...args),
1769
+ registry: this.registry
1770
+ });
1771
+ await this.pushOutputFromNodeToEdges(task, results);
1772
+ return {
1773
+ id: task.config.id,
1774
+ type: task.constructor.runtype || task.constructor.type,
1775
+ data: results
1776
+ };
1777
+ } finally {
1778
+ task.off("status", onStatus);
1779
+ task.off("stream_start", onStreamStart);
1780
+ task.off("stream_chunk", onStreamChunk);
1781
+ task.off("stream_end", onStreamEnd);
1782
+ }
1783
+ }
1784
+ pushStreamToEdges(task, streamMode) {
1785
+ const targetDataflows = this.graph.getTargetDataflows(task.config.id);
1786
+ if (targetDataflows.length === 0)
1787
+ return;
1788
+ const stream = new ReadableStream({
1789
+ start: (controller) => {
1790
+ const onChunk = (event) => {
1791
+ try {
1792
+ controller.enqueue(event);
1793
+ } catch {}
1794
+ };
1795
+ const onEnd = () => {
1796
+ try {
1797
+ controller.close();
1798
+ } catch {}
1799
+ task.off("stream_chunk", onChunk);
1800
+ task.off("stream_end", onEnd);
1801
+ };
1802
+ task.on("stream_chunk", onChunk);
1803
+ task.on("stream_end", onEnd);
1804
+ }
1805
+ });
1806
+ if (targetDataflows.length === 1) {
1807
+ targetDataflows[0].setStream(stream);
1808
+ } else {
1809
+ let currentStream = stream;
1810
+ for (let i = 0;i < targetDataflows.length; i++) {
1811
+ if (i === targetDataflows.length - 1) {
1812
+ targetDataflows[i].setStream(currentStream);
1813
+ } else {
1814
+ const [s1, s2] = currentStream.tee();
1815
+ targetDataflows[i].setStream(s1);
1816
+ currentStream = s2;
1817
+ }
1818
+ }
1819
+ }
1820
+ }
1523
1821
  resetTask(graph, task, runId) {
1524
1822
  task.status = TaskStatus.PENDING;
1525
1823
  task.resetInputData();
@@ -1603,7 +1901,7 @@ class TaskGraphRunner {
1603
1901
  }
1604
1902
  async handleError(error) {
1605
1903
  await Promise.allSettled(this.graph.getTasks().map(async (task) => {
1606
- if (task.status === TaskStatus.PROCESSING) {
1904
+ if (task.status === TaskStatus.PROCESSING || task.status === TaskStatus.STREAMING) {
1607
1905
  task.abort();
1608
1906
  }
1609
1907
  }));
@@ -1615,7 +1913,7 @@ class TaskGraphRunner {
1615
1913
  }
1616
1914
  async handleAbort() {
1617
1915
  this.graph.getTasks().map(async (task) => {
1618
- if (task.status === TaskStatus.PROCESSING) {
1916
+ if (task.status === TaskStatus.PROCESSING || task.status === TaskStatus.STREAMING) {
1619
1917
  task.abort();
1620
1918
  }
1621
1919
  });
@@ -1892,6 +2190,54 @@ function CreateEndLoopWorkflow(methodName) {
1892
2190
  return this.finalizeAndReturn();
1893
2191
  };
1894
2192
  }
2193
+ var TYPED_ARRAY_FORMAT_PREFIX = "TypedArray";
2194
+ function schemaHasTypedArrayFormat(schema) {
2195
+ if (typeof schema === "boolean")
2196
+ return false;
2197
+ if (!schema || typeof schema !== "object" || Array.isArray(schema))
2198
+ return false;
2199
+ const s = schema;
2200
+ if (typeof s.format === "string" && s.format.startsWith(TYPED_ARRAY_FORMAT_PREFIX)) {
2201
+ return true;
2202
+ }
2203
+ const checkUnion = (schemas) => {
2204
+ if (!Array.isArray(schemas))
2205
+ return false;
2206
+ return schemas.some((sub) => schemaHasTypedArrayFormat(sub));
2207
+ };
2208
+ if (checkUnion(s.oneOf) || checkUnion(s.anyOf))
2209
+ return true;
2210
+ const items = s.items;
2211
+ if (items && typeof items === "object" && !Array.isArray(items)) {
2212
+ if (schemaHasTypedArrayFormat(items))
2213
+ return true;
2214
+ }
2215
+ return false;
2216
+ }
2217
+ function hasVectorOutput(task) {
2218
+ const outputSchema = task.outputSchema();
2219
+ if (typeof outputSchema === "boolean" || !outputSchema?.properties)
2220
+ return false;
2221
+ return Object.values(outputSchema.properties).some((prop) => schemaHasTypedArrayFormat(prop));
2222
+ }
2223
+ function hasVectorLikeInput(input) {
2224
+ if (!input || typeof input !== "object")
2225
+ return false;
2226
+ const v = input.vectors;
2227
+ return Array.isArray(v) && v.length > 0 && typeof v[0] === "object" && v[0] !== null && ArrayBuffer.isView(v[0]);
2228
+ }
2229
+ function CreateAdaptiveWorkflow(scalarClass, vectorClass) {
2230
+ const scalarHelper = Workflow.createWorkflow(scalarClass);
2231
+ const vectorHelper = Workflow.createWorkflow(vectorClass);
2232
+ return function(input = {}, config = {}) {
2233
+ const parent = getLastTask(this);
2234
+ const useVector = parent !== undefined && hasVectorOutput(parent) || hasVectorLikeInput(input);
2235
+ if (useVector) {
2236
+ return vectorHelper.call(this, input, config);
2237
+ }
2238
+ return scalarHelper.call(this, input, config);
2239
+ };
2240
+ }
1895
2241
 
1896
2242
  class WorkflowTask extends GraphAsTask {
1897
2243
  static type = "Workflow";
@@ -2012,6 +2358,11 @@ class Workflow {
2012
2358
  }
2013
2359
  this.events.emit("start");
2014
2360
  this._abortController = new AbortController;
2361
+ const unsubStreaming = this.graph.subscribeToTaskStreaming({
2362
+ onStreamStart: (taskId) => this.events.emit("stream_start", taskId),
2363
+ onStreamChunk: (taskId, event) => this.events.emit("stream_chunk", taskId, event),
2364
+ onStreamEnd: (taskId, output) => this.events.emit("stream_end", taskId, output)
2365
+ });
2015
2366
  try {
2016
2367
  const output = await this.graph.run(input, {
2017
2368
  parentSignal: this._abortController.signal,
@@ -2024,6 +2375,7 @@ class Workflow {
2024
2375
  this.events.emit("error", String(error));
2025
2376
  throw error;
2026
2377
  } finally {
2378
+ unsubStreaming();
2027
2379
  this._abortController = undefined;
2028
2380
  }
2029
2381
  }
@@ -2303,13 +2655,26 @@ class Workflow {
2303
2655
  if (typeof fromSchema === "boolean" || typeof toSchema === "boolean") {
2304
2656
  return;
2305
2657
  }
2306
- for (const [fromOutputPortId, fromPortOutputSchema] of Object.entries(fromSchema.properties || {})) {
2307
- for (const [toInputPortId, toPortInputSchema] of Object.entries(toSchema.properties || {})) {
2308
- if (!matches.has(toInputPortId) && comparator([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema])) {
2309
- matches.set(toInputPortId, fromOutputPortId);
2310
- graph.addDataflow(new Dataflow(fromTaskId, fromOutputPortId, toTaskId, toInputPortId));
2658
+ for (const [toInputPortId, toPortInputSchema] of Object.entries(toSchema.properties || {})) {
2659
+ if (matches.has(toInputPortId))
2660
+ continue;
2661
+ const candidates = [];
2662
+ for (const [fromOutputPortId, fromPortOutputSchema] of Object.entries(fromSchema.properties || {})) {
2663
+ if (comparator([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema])) {
2664
+ candidates.push(fromOutputPortId);
2311
2665
  }
2312
2666
  }
2667
+ if (candidates.length === 0)
2668
+ continue;
2669
+ let winner = candidates[0];
2670
+ if (candidates.length > 1) {
2671
+ const targetStreamMode = getPortStreamMode(toSchema, toInputPortId);
2672
+ const streamMatch = candidates.find((portId) => getPortStreamMode(fromSchema, portId) === targetStreamMode);
2673
+ if (streamMatch)
2674
+ winner = streamMatch;
2675
+ }
2676
+ matches.set(toInputPortId, winner);
2677
+ graph.addDataflow(new Dataflow(fromTaskId, winner, toTaskId, toInputPortId));
2313
2678
  }
2314
2679
  };
2315
2680
  makeMatch(sourceSchema, targetSchema, sourceTask.config.id, targetTask.config.id, ([fromOutputPortId, fromPortOutputSchema], [toInputPortId, toPortInputSchema]) => {
@@ -2757,6 +3122,24 @@ class TaskGraph {
2757
3122
  unsubscribes.forEach((unsub) => unsub());
2758
3123
  };
2759
3124
  }
3125
+ subscribeToTaskStreaming(callbacks) {
3126
+ const unsubscribes = [];
3127
+ if (callbacks.onStreamStart) {
3128
+ const unsub = this.subscribe("task_stream_start", callbacks.onStreamStart);
3129
+ unsubscribes.push(unsub);
3130
+ }
3131
+ if (callbacks.onStreamChunk) {
3132
+ const unsub = this.subscribe("task_stream_chunk", callbacks.onStreamChunk);
3133
+ unsubscribes.push(unsub);
3134
+ }
3135
+ if (callbacks.onStreamEnd) {
3136
+ const unsub = this.subscribe("task_stream_end", callbacks.onStreamEnd);
3137
+ unsubscribes.push(unsub);
3138
+ }
3139
+ return () => {
3140
+ unsubscribes.forEach((unsub) => unsub());
3141
+ };
3142
+ }
2760
3143
  on(name, fn) {
2761
3144
  const dagEvent = EventTaskGraphToDagMapping[name];
2762
3145
  if (dagEvent) {
@@ -4514,10 +4897,15 @@ export {
4514
4897
  pipe,
4515
4898
  parallel,
4516
4899
  mergeChainedOutputToInput,
4900
+ isTaskStreamable,
4517
4901
  isStrictArraySchema,
4518
4902
  isIterationProperty,
4519
4903
  isFlexibleSchema,
4904
+ hasVectorOutput,
4905
+ hasVectorLikeInput,
4520
4906
  getTaskQueueRegistry,
4907
+ getPortStreamMode,
4908
+ getOutputStreamMode,
4521
4909
  getNestedValue,
4522
4910
  getLastTask,
4523
4911
  getJobQueueFactory,
@@ -4529,6 +4917,7 @@ export {
4529
4917
  extractBaseSchema,
4530
4918
  evaluateCondition,
4531
4919
  ensureTask,
4920
+ edgeNeedsAccumulation,
4532
4921
  createTaskFromGraphJSON,
4533
4922
  createTaskFromDependencyJSON,
4534
4923
  createJobQueueFactoryWithOptions,
@@ -4587,7 +4976,8 @@ export {
4587
4976
  CreateWorkflow,
4588
4977
  CreateLoopWorkflow,
4589
4978
  CreateEndLoopWorkflow,
4979
+ CreateAdaptiveWorkflow,
4590
4980
  ConditionalTask
4591
4981
  };
4592
4982
 
4593
- //# debugId=8CD145E1258087DF64756E2164756E21
4983
+ //# debugId=C8B7F47334D5CDD864756E2164756E21