@workglow/task-graph 0.2.20 → 0.2.22

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