@workglow/task-graph 0.2.20 → 0.2.21

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 (39) hide show
  1. package/dist/browser.js +221 -98
  2. package/dist/browser.js.map +17 -19
  3. package/dist/bun.js +221 -98
  4. package/dist/bun.js.map +17 -19
  5. package/dist/common.d.ts +0 -1
  6. package/dist/common.d.ts.map +1 -1
  7. package/dist/node.js +221 -98
  8. package/dist/node.js.map +17 -19
  9. package/dist/task/FallbackTaskRunner.d.ts.map +1 -1
  10. package/dist/task/GraphAsTaskRunner.d.ts.map +1 -1
  11. package/dist/task/ITask.d.ts +18 -9
  12. package/dist/task/ITask.d.ts.map +1 -1
  13. package/dist/task/ITaskRunner.d.ts +15 -0
  14. package/dist/task/ITaskRunner.d.ts.map +1 -1
  15. package/dist/task/StreamTypes.d.ts +23 -1
  16. package/dist/task/StreamTypes.d.ts.map +1 -1
  17. package/dist/task/Task.d.ts +9 -2
  18. package/dist/task/Task.d.ts.map +1 -1
  19. package/dist/task/TaskEvents.d.ts +2 -2
  20. package/dist/task/TaskEvents.d.ts.map +1 -1
  21. package/dist/task/TaskRunner.d.ts +17 -8
  22. package/dist/task/TaskRunner.d.ts.map +1 -1
  23. package/dist/task/WhileTask.d.ts.map +1 -1
  24. package/dist/task-graph/Dataflow.d.ts +20 -0
  25. package/dist/task-graph/Dataflow.d.ts.map +1 -1
  26. package/dist/task-graph/ITaskGraph.d.ts +1 -1
  27. package/dist/task-graph/ITaskGraph.d.ts.map +1 -1
  28. package/dist/task-graph/IWorkflow.d.ts +0 -2
  29. package/dist/task-graph/IWorkflow.d.ts.map +1 -1
  30. package/dist/task-graph/TaskGraph.d.ts +1 -13
  31. package/dist/task-graph/TaskGraph.d.ts.map +1 -1
  32. package/dist/task-graph/TaskGraphEvents.d.ts +1 -1
  33. package/dist/task-graph/TaskGraphEvents.d.ts.map +1 -1
  34. package/dist/task-graph/TaskGraphRunner.d.ts +5 -8
  35. package/dist/task-graph/TaskGraphRunner.d.ts.map +1 -1
  36. package/dist/task-graph/Workflow.d.ts.map +1 -1
  37. package/package.json +7 -7
  38. package/dist/refcountable.d.ts +0 -29
  39. package/dist/refcountable.d.ts.map +0 -1
package/dist/bun.js CHANGED
@@ -181,7 +181,14 @@ class Dataflow {
181
181
  status = TaskStatus.PENDING;
182
182
  error;
183
183
  stream = undefined;
184
+ latestSnapshot = undefined;
185
+ getCurrentValue() {
186
+ if (this.value !== undefined)
187
+ return this.value;
188
+ return this.latestSnapshot;
189
+ }
184
190
  setStream(stream) {
191
+ this.latestSnapshot = undefined;
185
192
  this.stream = stream;
186
193
  }
187
194
  getStream() {
@@ -227,6 +234,7 @@ class Dataflow {
227
234
  }
228
235
  }
229
236
  reset() {
237
+ this.latestSnapshot = undefined;
230
238
  this.status = TaskStatus.PENDING;
231
239
  this.error = undefined;
232
240
  this.value = undefined;
@@ -272,6 +280,7 @@ class Dataflow {
272
280
  } else {
273
281
  this.value = entireDataBlock[this.sourceTaskPortId];
274
282
  }
283
+ this.latestSnapshot = undefined;
275
284
  }
276
285
  getPortData() {
277
286
  let result;
@@ -1143,31 +1152,7 @@ import {
1143
1152
  SpanStatusCode as SpanStatusCode2,
1144
1153
  uuid4 as uuid43
1145
1154
  } from "@workglow/util";
1146
-
1147
- // src/refcountable.ts
1148
- var GLOBAL_KEY = Symbol.for("@workglow/task-graph/refcountable.predicates");
1149
- var _g = globalThis;
1150
- if (!Array.isArray(_g[GLOBAL_KEY])) {
1151
- _g[GLOBAL_KEY] = [];
1152
- }
1153
- var predicates = _g[GLOBAL_KEY];
1154
- function registerRefcountablePredicate(p) {
1155
- predicates.push(p);
1156
- }
1157
- function asRefcountable(v) {
1158
- if (v === null || v === undefined)
1159
- return null;
1160
- if (typeof v !== "object")
1161
- return null;
1162
- for (const p of predicates) {
1163
- if (p(v))
1164
- return v;
1165
- }
1166
- return null;
1167
- }
1168
- function _resetRefcountablePredicatesForTests() {
1169
- predicates.length = 0;
1170
- }
1155
+ import { previewSource } from "@workglow/util/media";
1171
1156
 
1172
1157
  // src/storage/TaskOutputRepository.ts
1173
1158
  import { createServiceToken as createServiceToken2, EventEmitter as EventEmitter2 } from "@workglow/util";
@@ -1436,7 +1421,6 @@ class TaskRunner {
1436
1421
  timeoutTimer;
1437
1422
  pendingTimeoutError;
1438
1423
  shouldAccumulate = true;
1439
- runWithPreviews = false;
1440
1424
  telemetrySpan;
1441
1425
  constructor(task) {
1442
1426
  this.task = task;
@@ -1545,6 +1529,100 @@ class TaskRunner {
1545
1529
  return this.task.runOutputData;
1546
1530
  }
1547
1531
  }
1532
+ async* runPreviewStream(overrides = {}) {
1533
+ const graph = this.task.parentGraph;
1534
+ const dataflowInfos = [];
1535
+ if (graph) {
1536
+ for (const df of graph.getSourceDataflows(this.task.id)) {
1537
+ const upstream = graph.getTask(df.sourceTaskId);
1538
+ if (upstream) {
1539
+ dataflowInfos.push({
1540
+ upstream,
1541
+ sourcePort: df.sourceTaskPortId,
1542
+ targetPort: df.targetTaskPortId
1543
+ });
1544
+ }
1545
+ }
1546
+ }
1547
+ const upstreamTasks = new Set(dataflowInfos.map((d) => d.upstream));
1548
+ const pendingUpstreams = new Set([...upstreamTasks].filter((u) => u.status === TaskStatus.STREAMING || u.status === TaskStatus.PENDING || u.status === TaskStatus.PROCESSING));
1549
+ let dirty = true;
1550
+ let wakeResolve;
1551
+ const wakeNext = () => new Promise((resolve) => {
1552
+ wakeResolve = resolve;
1553
+ });
1554
+ const wake = () => {
1555
+ const r = wakeResolve;
1556
+ wakeResolve = undefined;
1557
+ if (r)
1558
+ r();
1559
+ };
1560
+ const cleanupFns = [];
1561
+ for (const upstream of pendingUpstreams) {
1562
+ const myDataflows = dataflowInfos.filter((d) => d.upstream === upstream);
1563
+ const onChunk = (event) => {
1564
+ if (event.type !== "snapshot")
1565
+ return;
1566
+ const snapshotData = event.data;
1567
+ if (snapshotData) {
1568
+ for (const { sourcePort, targetPort } of myDataflows) {
1569
+ const value = sourcePort === "*" ? snapshotData : snapshotData[sourcePort];
1570
+ if (value !== undefined) {
1571
+ this.task.runInputData[targetPort] = value;
1572
+ }
1573
+ }
1574
+ }
1575
+ dirty = true;
1576
+ wake();
1577
+ };
1578
+ const onEnd = () => {
1579
+ pendingUpstreams.delete(upstream);
1580
+ wake();
1581
+ };
1582
+ const onStatus = (status) => {
1583
+ if (status === TaskStatus.COMPLETED || status === TaskStatus.FAILED || status === TaskStatus.DISABLED) {
1584
+ pendingUpstreams.delete(upstream);
1585
+ wake();
1586
+ }
1587
+ };
1588
+ upstream.on("stream_chunk", onChunk);
1589
+ upstream.on("stream_end", onEnd);
1590
+ upstream.on("status", onStatus);
1591
+ cleanupFns.push(() => {
1592
+ upstream.off("stream_chunk", onChunk);
1593
+ upstream.off("stream_end", onEnd);
1594
+ upstream.off("status", onStatus);
1595
+ });
1596
+ }
1597
+ for (const upstream of [...pendingUpstreams]) {
1598
+ if (upstream.status === TaskStatus.COMPLETED || upstream.status === TaskStatus.FAILED || upstream.status === TaskStatus.DISABLED) {
1599
+ pendingUpstreams.delete(upstream);
1600
+ }
1601
+ }
1602
+ try {
1603
+ while (true) {
1604
+ if (dirty) {
1605
+ dirty = false;
1606
+ try {
1607
+ const out = await this.runPreview(overrides);
1608
+ yield out;
1609
+ } catch (err) {
1610
+ getLogger().debug("runPreviewStream iteration failed", {
1611
+ taskId: this.task.config?.id,
1612
+ error: err
1613
+ });
1614
+ }
1615
+ continue;
1616
+ }
1617
+ if (pendingUpstreams.size === 0)
1618
+ return;
1619
+ await wakeNext();
1620
+ }
1621
+ } finally {
1622
+ for (const off of cleanupFns)
1623
+ off();
1624
+ }
1625
+ }
1548
1626
  abort() {
1549
1627
  if (this.task.hasChildren()) {
1550
1628
  this.task.subGraph.abort();
@@ -1595,7 +1673,7 @@ class TaskRunner {
1595
1673
  }
1596
1674
  const accumulated = this.shouldAccumulate ? new Map : undefined;
1597
1675
  const accumulatedObjects = this.shouldAccumulate ? new Map : undefined;
1598
- let chunkCount = 0;
1676
+ let streamingStarted = false;
1599
1677
  let finalOutput;
1600
1678
  this.task.emit("stream_start");
1601
1679
  const stream = this.task.executeStream(input, {
@@ -1607,25 +1685,33 @@ class TaskRunner {
1607
1685
  inputStreams: this.inputStreams
1608
1686
  });
1609
1687
  for await (const event of stream) {
1610
- chunkCount++;
1611
- if (chunkCount === 1) {
1612
- this.task.status = TaskStatus.STREAMING;
1613
- this.task.emit("status", this.task.status);
1614
- }
1615
1688
  if (event.type === "snapshot") {
1616
1689
  this.task.runOutputData = event.data;
1617
1690
  }
1618
1691
  switch (event.type) {
1692
+ case "phase": {
1693
+ this.task.emit("stream_chunk", event);
1694
+ await this.handleProgress(event.progress, event.message);
1695
+ break;
1696
+ }
1619
1697
  case "text-delta": {
1698
+ if (!streamingStarted) {
1699
+ streamingStarted = true;
1700
+ this.task.status = TaskStatus.STREAMING;
1701
+ this.task.emit("status", this.task.status);
1702
+ }
1620
1703
  if (accumulated) {
1621
1704
  accumulated.set(event.port, (accumulated.get(event.port) ?? "") + event.textDelta);
1622
1705
  }
1623
1706
  this.task.emit("stream_chunk", event);
1624
- const progress = Math.min(99, Math.round(100 * (1 - Math.exp(-0.05 * chunkCount))));
1625
- await this.handleProgress(progress);
1626
1707
  break;
1627
1708
  }
1628
1709
  case "object-delta": {
1710
+ if (!streamingStarted) {
1711
+ streamingStarted = true;
1712
+ this.task.status = TaskStatus.STREAMING;
1713
+ this.task.emit("status", this.task.status);
1714
+ }
1629
1715
  if (accumulatedObjects) {
1630
1716
  const existing = accumulatedObjects.get(event.port);
1631
1717
  if (Array.isArray(event.objectDelta)) {
@@ -1652,14 +1738,15 @@ class TaskRunner {
1652
1738
  [event.port]: accumulatedObjects?.get(event.port) ?? event.objectDelta
1653
1739
  };
1654
1740
  this.task.emit("stream_chunk", event);
1655
- const progress = Math.min(99, Math.round(100 * (1 - Math.exp(-0.05 * chunkCount))));
1656
- await this.handleProgress(progress);
1657
1741
  break;
1658
1742
  }
1659
1743
  case "snapshot": {
1744
+ if (!streamingStarted) {
1745
+ streamingStarted = true;
1746
+ this.task.status = TaskStatus.STREAMING;
1747
+ this.task.emit("status", this.task.status);
1748
+ }
1660
1749
  this.task.emit("stream_chunk", event);
1661
- const progress = Math.min(99, Math.round(100 * (1 - Math.exp(-0.05 * chunkCount))));
1662
- await this.handleProgress(progress);
1663
1750
  break;
1664
1751
  }
1665
1752
  case "finish": {
@@ -1676,9 +1763,32 @@ class TaskRunner {
1676
1763
  merged[port] = obj;
1677
1764
  }
1678
1765
  }
1766
+ if (streamMode === "replace" && Object.keys(merged).length === 0) {
1767
+ const lastSnapshot = this.task.runOutputData;
1768
+ if (lastSnapshot && Object.keys(lastSnapshot).length > 0) {
1769
+ finalOutput = lastSnapshot;
1770
+ this.task.emit("stream_chunk", {
1771
+ type: "finish",
1772
+ data: lastSnapshot
1773
+ });
1774
+ break;
1775
+ }
1776
+ }
1679
1777
  finalOutput = merged;
1680
1778
  this.task.emit("stream_chunk", { type: "finish", data: merged });
1681
1779
  } else {
1780
+ const finishData = event.data ?? {};
1781
+ if (streamMode === "replace" && Object.keys(finishData).length === 0) {
1782
+ const lastSnapshot = this.task.runOutputData;
1783
+ if (lastSnapshot && Object.keys(lastSnapshot).length > 0) {
1784
+ finalOutput = lastSnapshot;
1785
+ this.task.emit("stream_chunk", {
1786
+ type: "finish",
1787
+ data: lastSnapshot
1788
+ });
1789
+ break;
1790
+ }
1791
+ }
1682
1792
  finalOutput = event.data;
1683
1793
  this.task.emit("stream_chunk", event);
1684
1794
  }
@@ -1719,7 +1829,6 @@ class TaskRunner {
1719
1829
  this.outputCache = cache;
1720
1830
  }
1721
1831
  this.shouldAccumulate = config.shouldAccumulate !== false;
1722
- this.runWithPreviews = config.runWithPreviews === true;
1723
1832
  if (config.updateProgress) {
1724
1833
  this.updateProgress = config.updateProgress;
1725
1834
  }
@@ -1774,7 +1883,7 @@ class TaskRunner {
1774
1883
  return;
1775
1884
  this.clearTimeoutTimer();
1776
1885
  this.task.status = TaskStatus.ABORTING;
1777
- this.task.progress = 100;
1886
+ await this.handleProgress(100);
1778
1887
  this.task.error = this.pendingTimeoutError ?? new TaskAbortedError;
1779
1888
  this.pendingTimeoutError = undefined;
1780
1889
  if (this.telemetrySpan) {
@@ -1802,9 +1911,9 @@ class TaskRunner {
1802
1911
  this.clearTimeoutTimer();
1803
1912
  this.pendingTimeoutError = undefined;
1804
1913
  this.task.completedAt = new Date;
1805
- this.task.progress = 100;
1806
1914
  this.task.status = TaskStatus.COMPLETED;
1807
1915
  this.abortController = undefined;
1916
+ await this.handleProgress(100);
1808
1917
  if (this.telemetrySpan) {
1809
1918
  this.telemetrySpan.setStatus(SpanStatusCode.OK);
1810
1919
  this.telemetrySpan.end();
@@ -1820,7 +1929,7 @@ class TaskRunner {
1820
1929
  if (this.task.status === TaskStatus.DISABLED)
1821
1930
  return;
1822
1931
  this.task.status = TaskStatus.DISABLED;
1823
- this.task.progress = 100;
1932
+ await this.handleProgress(100);
1824
1933
  this.task.completedAt = new Date;
1825
1934
  this.abortController = undefined;
1826
1935
  this.task.emit("disabled");
@@ -1840,8 +1949,6 @@ class TaskRunner {
1840
1949
  this.task.subGraph.abort();
1841
1950
  }
1842
1951
  this.task.completedAt = new Date;
1843
- this.task.progress = 100;
1844
- this.task.status = TaskStatus.FAILED;
1845
1952
  if (err instanceof TaskError) {
1846
1953
  this.task.error = err;
1847
1954
  } else {
@@ -1851,7 +1958,9 @@ class TaskRunner {
1851
1958
  this.task.error.taskType ??= this.task.type;
1852
1959
  this.task.error.taskId ??= this.task.id;
1853
1960
  }
1961
+ this.task.status = TaskStatus.FAILED;
1854
1962
  this.abortController = undefined;
1963
+ await this.handleProgress(100);
1855
1964
  if (this.telemetrySpan) {
1856
1965
  this.telemetrySpan.setStatus(SpanStatusCode.ERROR, this.task.error.message);
1857
1966
  this.telemetrySpan.setAttributes({ "workglow.task.error": this.task.error.message });
@@ -1913,6 +2022,7 @@ class Task {
1913
2022
  async executePreview(_input, _context) {
1914
2023
  return;
1915
2024
  }
2025
+ parentGraph;
1916
2026
  _runner;
1917
2027
  get runner() {
1918
2028
  if (!this._runner) {
@@ -2292,6 +2402,10 @@ class Task {
2292
2402
  return obj.map((item) => this.stripSymbols(item));
2293
2403
  }
2294
2404
  if (typeof obj === "object") {
2405
+ const proto = Object.getPrototypeOf(obj);
2406
+ if (proto !== Object.prototype && proto !== null) {
2407
+ return obj;
2408
+ }
2295
2409
  const result = {};
2296
2410
  for (const key in obj) {
2297
2411
  if (Object.prototype.hasOwnProperty.call(obj, key)) {
@@ -2882,6 +2996,12 @@ function taskPrototypeHasOwnExecute(task) {
2882
2996
  }
2883
2997
  var PROPERTY_ARRAY = "PROPERTY_ARRAY";
2884
2998
  var GRAPH_RESULT_ARRAY = "GRAPH_RESULT_ARRAY";
2999
+ function isImageValueShape(v) {
3000
+ if (v === null || typeof v !== "object")
3001
+ return false;
3002
+ const o = v;
3003
+ return typeof o.width === "number" && typeof o.height === "number" && typeof o.previewScale === "number";
3004
+ }
2885
3005
 
2886
3006
  class TaskGraphRunner {
2887
3007
  processScheduler;
@@ -2891,7 +3011,6 @@ class TaskGraphRunner {
2891
3011
  graph;
2892
3012
  outputCache;
2893
3013
  accumulateLeafOutputs = true;
2894
- runWithPreviews = false;
2895
3014
  registry = globalServiceRegistry3;
2896
3015
  resourceScope;
2897
3016
  abortController;
@@ -3121,27 +3240,27 @@ class TaskGraphRunner {
3121
3240
  const dataflows = this.graph.getSourceDataflows(task.id);
3122
3241
  dataflows.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
3123
3242
  for (const dataflow of dataflows) {
3124
- this.addInputData(task, dataflow.getPortData());
3243
+ const live = dataflow.getCurrentValue();
3244
+ const port = dataflow.targetTaskPortId;
3245
+ let portData;
3246
+ if (port === DATAFLOW_ALL_PORTS) {
3247
+ portData = live;
3248
+ } else if (port === DATAFLOW_ERROR_PORT) {
3249
+ portData = { [DATAFLOW_ERROR_PORT]: dataflow.error };
3250
+ } else {
3251
+ portData = { [port]: live };
3252
+ }
3253
+ this.addInputData(task, portData);
3125
3254
  }
3126
3255
  }
3127
3256
  async pushOutputFromNodeToEdges(node, results) {
3128
3257
  const dataflows = this.graph.getTargetDataflows(node.id);
3129
- if (Object.keys(results).length > 0) {
3130
- const consumerCounts = new Map;
3131
- for (const dataflow of dataflows) {
3132
- if (dataflow.stream !== undefined)
3133
- continue;
3134
- const port = dataflow.sourceTaskPortId;
3135
- consumerCounts.set(port, (consumerCounts.get(port) ?? 0) + 1);
3136
- }
3137
- for (const [port, count] of consumerCounts) {
3138
- const extra = this.runWithPreviews ? count : count - 1;
3139
- if (extra <= 0)
3140
- continue;
3258
+ if (this.previewRunning && Object.keys(results).length > 0) {
3259
+ for (const port of Object.keys(results)) {
3141
3260
  const value = results[port];
3142
- const ref = asRefcountable(value);
3143
- if (ref)
3144
- ref.retain(extra);
3261
+ if (isImageValueShape(value)) {
3262
+ results[port] = await previewSource(value);
3263
+ }
3145
3264
  }
3146
3265
  }
3147
3266
  for (const dataflow of dataflows) {
@@ -3313,8 +3432,7 @@ class TaskGraphRunner {
3313
3432
  outputCache: this.outputCache ?? false,
3314
3433
  updateProgress: async (task2, progress, message, ...args) => await this.handleProgress(task2, progress, message, ...args),
3315
3434
  registry: this.registry,
3316
- resourceScope: this.resourceScope,
3317
- runWithPreviews: this.runWithPreviews
3435
+ resourceScope: this.resourceScope
3318
3436
  });
3319
3437
  await this.pushOutputFromNodeToEdges(task, results);
3320
3438
  return {
@@ -3364,8 +3482,7 @@ class TaskGraphRunner {
3364
3482
  shouldAccumulate,
3365
3483
  updateProgress: async (task2, progress, message, ...args) => await this.handleProgress(task2, progress, message, ...args),
3366
3484
  registry: this.registry,
3367
- resourceScope: this.resourceScope,
3368
- runWithPreviews: this.runWithPreviews
3485
+ resourceScope: this.resourceScope
3369
3486
  });
3370
3487
  await this.pushOutputFromNodeToEdges(task, results);
3371
3488
  return {
@@ -3383,7 +3500,7 @@ class TaskGraphRunner {
3383
3500
  static isPortDelta(event) {
3384
3501
  return event.type === "text-delta" || event.type === "object-delta";
3385
3502
  }
3386
- createStreamFromTaskEvents(task, portId) {
3503
+ createStreamFromTaskEvents(task, portId, edgesForGroup) {
3387
3504
  return new ReadableStream({
3388
3505
  start: (controller) => {
3389
3506
  const onChunk = (event) => {
@@ -3391,6 +3508,15 @@ class TaskGraphRunner {
3391
3508
  if (portId !== undefined && TaskGraphRunner.isPortDelta(event) && event.port !== portId) {
3392
3509
  return;
3393
3510
  }
3511
+ if (event.type === "snapshot") {
3512
+ const data = event.data;
3513
+ if (data) {
3514
+ for (const edge of edgesForGroup) {
3515
+ const portValue = edge.sourceTaskPortId === DATAFLOW_ALL_PORTS ? data : data[edge.sourceTaskPortId];
3516
+ edge.latestSnapshot = portValue;
3517
+ }
3518
+ }
3519
+ }
3394
3520
  controller.enqueue(event);
3395
3521
  } catch {}
3396
3522
  };
@@ -3422,7 +3548,7 @@ class TaskGraphRunner {
3422
3548
  }
3423
3549
  for (const [portKey, edges] of groups) {
3424
3550
  const filterPort = portKey === DATAFLOW_ALL_PORTS ? undefined : portKey;
3425
- const stream = this.createStreamFromTaskEvents(task, filterPort);
3551
+ const stream = this.createStreamFromTaskEvents(task, filterPort, edges);
3426
3552
  if (edges.length === 1) {
3427
3553
  edges[0].setStream(stream);
3428
3554
  } else {
@@ -3440,17 +3566,6 @@ class TaskGraphRunner {
3440
3566
  }
3441
3567
  }
3442
3568
  resetTask(graph, task, runId) {
3443
- const previous = task.runOutputData;
3444
- if (previous) {
3445
- for (const port of Object.keys(previous)) {
3446
- const ref = asRefcountable(previous[port]);
3447
- if (!ref)
3448
- continue;
3449
- try {
3450
- ref.release();
3451
- } catch {}
3452
- }
3453
- }
3454
3569
  task.status = TaskStatus.PENDING;
3455
3570
  task.resetInputData();
3456
3571
  task.runOutputData = {};
@@ -3484,7 +3599,6 @@ class TaskGraphRunner {
3484
3599
  this.resourceScope = config.resourceScope;
3485
3600
  }
3486
3601
  this.accumulateLeafOutputs = config?.accumulateLeafOutputs !== false;
3487
- this.runWithPreviews = config?.runWithPreviews === true;
3488
3602
  if (config?.outputCache !== undefined) {
3489
3603
  if (typeof config.outputCache === "boolean") {
3490
3604
  if (config.outputCache === true) {
@@ -3584,7 +3698,6 @@ class TaskGraphRunner {
3584
3698
  throw new TaskConfigurationError(`Graph has ${taskCount} tasks, exceeding the limit of ${config.maxTasks}`);
3585
3699
  }
3586
3700
  }
3587
- this.runWithPreviews = false;
3588
3701
  this.previewScheduler.reset();
3589
3702
  this.previewRunning = true;
3590
3703
  }
@@ -3660,15 +3773,21 @@ class TaskGraphRunner {
3660
3773
  async handleProgress(task, progress, message, ...args) {
3661
3774
  const contributors = this.graph.getTasks().filter(taskPrototypeHasOwnExecute);
3662
3775
  if (contributors.length > 1) {
3663
- const sum = contributors.reduce((acc, t) => acc + t.progress, 0);
3664
- progress = Math.round(sum / contributors.length);
3776
+ const determinate = contributors.filter((t) => t.progress !== undefined);
3777
+ if (determinate.length === 0) {
3778
+ progress = undefined;
3779
+ } else {
3780
+ const sum = determinate.reduce((acc, t) => acc + t.progress, 0);
3781
+ progress = Math.round(sum / determinate.length);
3782
+ }
3665
3783
  } else if (contributors.length === 1) {
3666
3784
  const [only] = contributors;
3667
3785
  progress = only.progress;
3668
3786
  }
3669
3787
  this.pushStatusFromNodeToEdges(this.graph, task);
3670
3788
  this.graph.emit("graph_progress", progress, message, args);
3671
- if (task.runOutputData && Object.keys(task.runOutputData).length > 0) {
3789
+ const isActive = task.status === TaskStatus.PROCESSING || task.status === TaskStatus.STREAMING;
3790
+ if (isActive && task.runOutputData && Object.keys(task.runOutputData).length > 0) {
3672
3791
  await this.pushOutputFromNodeToEdges(task, task.runOutputData);
3673
3792
  }
3674
3793
  }
@@ -3684,8 +3803,7 @@ class GraphAsTaskRunner extends TaskRunner {
3684
3803
  parentSignal: this.abortController?.signal,
3685
3804
  outputCache: this.outputCache,
3686
3805
  registry: this.registry,
3687
- resourceScope: this.resourceScope,
3688
- runWithPreviews: this.runWithPreviews
3806
+ resourceScope: this.resourceScope
3689
3807
  });
3690
3808
  unsubscribe();
3691
3809
  return results;
@@ -4148,8 +4266,7 @@ class TaskGraph {
4148
4266
  registry: config?.registry,
4149
4267
  timeout: config?.timeout,
4150
4268
  maxTasks: config?.maxTasks,
4151
- resourceScope: config?.resourceScope,
4152
- runWithPreviews: config?.runWithPreviews
4269
+ resourceScope: config?.resourceScope
4153
4270
  });
4154
4271
  }
4155
4272
  runPreview(input = {}, config = {}) {
@@ -4177,10 +4294,16 @@ class TaskGraph {
4177
4294
  return this._dag.isAcyclic();
4178
4295
  }
4179
4296
  addTask(task, config) {
4180
- return this._dag.addNode(ensureTask(task, config));
4297
+ const t = ensureTask(task, config);
4298
+ t.parentGraph = this;
4299
+ return this._dag.addNode(t);
4181
4300
  }
4182
4301
  addTasks(tasks) {
4183
- return this._dag.addNodes(tasks.map(ensureTask));
4302
+ const resolved = tasks.map(ensureTask);
4303
+ for (const t of resolved) {
4304
+ t.parentGraph = this;
4305
+ }
4306
+ return this._dag.addNodes(resolved);
4184
4307
  }
4185
4308
  addDataflow(dataflow) {
4186
4309
  return this._dag.addEdge(dataflow.sourceTaskId, dataflow.targetTaskId, dataflow);
@@ -5002,8 +5125,7 @@ class Workflow {
5002
5125
  parentSignal: this._abortController.signal,
5003
5126
  outputCache: this._outputCache,
5004
5127
  registry: config?.registry ?? this._registry,
5005
- resourceScope: config?.resourceScope,
5006
- runWithPreviews: config?.runWithPreviews
5128
+ resourceScope: config?.resourceScope
5007
5129
  });
5008
5130
  const results = this.graph.mergeExecuteOutputsToRunOutput(output, PROPERTY_ARRAY);
5009
5131
  this.events.emit("complete");
@@ -6084,6 +6206,8 @@ class FallbackTaskRunner extends GraphAsTaskRunner {
6084
6206
  const totalAttempts = alternatives.length;
6085
6207
  let currentAttemptIndex = 0;
6086
6208
  const onSubgraphProgress = (innerProgress, message) => {
6209
+ if (innerProgress === undefined)
6210
+ return;
6087
6211
  const blended = Math.round((currentAttemptIndex + innerProgress / 100) / totalAttempts * 100);
6088
6212
  this.handleProgress(blended, message ?? `Data alternative ${currentAttemptIndex + 1}/${totalAttempts}`);
6089
6213
  };
@@ -6457,7 +6581,7 @@ class IteratorTaskRunner extends GraphAsTaskRunner {
6457
6581
  this.task.emit("iteration_start", index, iterationCount);
6458
6582
  const onGraphProgress = (p, message) => {
6459
6583
  this.task.emit("iteration_progress", index, iterationCount, p, message);
6460
- if (this.aggregatingParentMapProgress && this.mapPartialIterationCount > 0) {
6584
+ if (p !== undefined && this.aggregatingParentMapProgress && this.mapPartialIterationCount > 0) {
6461
6585
  this.mapPartialProgress[index] = Math.max(this.mapPartialProgress[index] ?? 0, p);
6462
6586
  this.emitMapParentProgressFromPartials(message);
6463
6587
  }
@@ -7168,6 +7292,8 @@ class WhileTask extends GraphAsTask {
7168
7292
  let currentOutput = {};
7169
7293
  const effectiveMax = arrayAnalysis ? Math.min(this.maxIterations, arrayAnalysis.iterationCount) : this.maxIterations;
7170
7294
  const onInnerGraphProgress = (innerProgress, innerMessage) => {
7295
+ if (innerProgress === undefined)
7296
+ return;
7171
7297
  const blended = Math.min(Math.round((this._currentIteration + innerProgress / 100) / effectiveMax * 100), 99);
7172
7298
  const message = innerMessage ? `Iteration ${this._currentIteration + 1}/${effectiveMax}: ${innerMessage}` : `Iteration ${this._currentIteration + 1}/${effectiveMax}`;
7173
7299
  context.updateProgress(blended, message);
@@ -7243,6 +7369,8 @@ ${err.stack}`;
7243
7369
  let currentOutput = {};
7244
7370
  const effectiveMax = arrayAnalysis ? Math.min(this.maxIterations, arrayAnalysis.iterationCount) : this.maxIterations;
7245
7371
  const onInnerGraphProgress = (innerProgress, innerMessage) => {
7372
+ if (innerProgress === undefined)
7373
+ return;
7246
7374
  const blended = Math.min(Math.round((this._currentIteration + innerProgress / 100) / effectiveMax * 100), 99);
7247
7375
  const message = innerMessage ? `Iteration ${this._currentIteration + 1}/${effectiveMax}: ${innerMessage}` : `Iteration ${this._currentIteration + 1}/${effectiveMax}`;
7248
7376
  context.updateProgress(blended, message);
@@ -8243,8 +8371,6 @@ import {
8243
8371
  getPortCodec as getPortCodec2,
8244
8372
  _resetPortCodecsForTests
8245
8373
  } from "@workglow/util";
8246
- // src/bun.ts
8247
- registerRefcountablePredicate((v) => !!v && typeof v === "object" && ("backend" in v) && ("retain" in v) && ("release" in v) && ("materialize" in v));
8248
8374
  export {
8249
8375
  wrapSchemaInArray,
8250
8376
  whileTaskConfigSchema,
@@ -8267,7 +8393,6 @@ export {
8267
8393
  resolveIterationBound,
8268
8394
  resetMethodNameCache,
8269
8395
  removeIterationProperties,
8270
- registerRefcountablePredicate,
8271
8396
  registerPortCodec,
8272
8397
  registerJobQueueFactory,
8273
8398
  registerBuiltInTransforms,
@@ -8351,11 +8476,9 @@ export {
8351
8476
  calculateNodeDepths,
8352
8477
  buildIterationInputSchema,
8353
8478
  autoConnect,
8354
- asRefcountable,
8355
8479
  addIterationContextToSchema,
8356
8480
  addBoundaryNodesToGraphJson,
8357
8481
  addBoundaryNodesToDependencyJson,
8358
- _resetRefcountablePredicatesForTests,
8359
8482
  _resetPortCodecsForTests,
8360
8483
  WorkflowError,
8361
8484
  Workflow,
@@ -8430,4 +8553,4 @@ export {
8430
8553
  BROWSER_GRANTS
8431
8554
  };
8432
8555
 
8433
- //# debugId=AA782C3ACDE0213064756E2164756E21
8556
+ //# debugId=22AE56374368DB4A64756E2164756E21