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