@particle-academy/fancy-flow 0.77.0 → 0.78.0

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 (82) hide show
  1. package/dist/{FlowViewer-Ak8kbY0e.d.cts → FlowViewer-BqYQl2vS.d.cts} +1 -1
  2. package/dist/{FlowViewer-BAV29Zpi.d.ts → FlowViewer-_Fq8AX9V.d.ts} +1 -1
  3. package/dist/{HumanPrompt-xYPCL2jO.d.cts → HumanPrompt-Sl1wD9Bx.d.cts} +2 -2
  4. package/dist/{HumanPrompt-Ge_ccCgS.d.ts → HumanPrompt-_SKIdSpx.d.ts} +2 -2
  5. package/dist/{chunk-MMCHYY6B.js → chunk-3EDB6ELL.js} +3 -3
  6. package/dist/{chunk-MMCHYY6B.js.map → chunk-3EDB6ELL.js.map} +1 -1
  7. package/dist/{chunk-KFC3BURT.js → chunk-4GNDRRJ3.js} +3 -3
  8. package/dist/{chunk-KFC3BURT.js.map → chunk-4GNDRRJ3.js.map} +1 -1
  9. package/dist/{chunk-44VXYZ4M.js → chunk-BBFHGAEN.js} +4 -4
  10. package/dist/{chunk-44VXYZ4M.js.map → chunk-BBFHGAEN.js.map} +1 -1
  11. package/dist/{chunk-OOQ2MMBE.js → chunk-GPFIJR2K.js} +4 -4
  12. package/dist/{chunk-OOQ2MMBE.js.map → chunk-GPFIJR2K.js.map} +1 -1
  13. package/dist/{chunk-YNKOEQLI.js → chunk-J5YUYDMK.js} +106 -6
  14. package/dist/chunk-J5YUYDMK.js.map +1 -0
  15. package/dist/{chunk-X2UHP2S5.js → chunk-S4MOUOG4.js} +3 -3
  16. package/dist/{chunk-X2UHP2S5.js.map → chunk-S4MOUOG4.js.map} +1 -1
  17. package/dist/{chunk-66JAEWPP.js → chunk-XO4ODEY2.js} +3 -3
  18. package/dist/{chunk-66JAEWPP.js.map → chunk-XO4ODEY2.js.map} +1 -1
  19. package/dist/connectors.d.cts +2 -2
  20. package/dist/connectors.d.ts +2 -2
  21. package/dist/durable/index.d.cts +2 -2
  22. package/dist/durable/index.d.ts +2 -2
  23. package/dist/durable.cjs +104 -4
  24. package/dist/durable.cjs.map +1 -1
  25. package/dist/durable.js +1 -1
  26. package/dist/engine.cjs +104 -4
  27. package/dist/engine.cjs.map +1 -1
  28. package/dist/engine.d.cts +6 -6
  29. package/dist/engine.d.ts +6 -6
  30. package/dist/engine.js +4 -4
  31. package/dist/fields/react-fancy.d.cts +3 -3
  32. package/dist/fields/react-fancy.d.ts +3 -3
  33. package/dist/index.cjs +104 -4
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +10 -10
  36. package/dist/index.d.ts +10 -10
  37. package/dist/index.js +12 -12
  38. package/dist/layout/index.d.cts +1 -1
  39. package/dist/layout/index.d.ts +1 -1
  40. package/dist/llm/prism.d.cts +1 -1
  41. package/dist/llm/prism.d.ts +1 -1
  42. package/dist/llm/vercel-ai.d.cts +1 -1
  43. package/dist/llm/vercel-ai.d.ts +1 -1
  44. package/dist/registry/index.d.cts +5 -5
  45. package/dist/registry/index.d.ts +5 -5
  46. package/dist/{registry-JUcN_xWK.d.ts → registry-C4GcH583.d.ts} +1 -1
  47. package/dist/{registry-B6SiTaLZ.d.cts → registry-DWIY3bMP.d.cts} +1 -1
  48. package/dist/registry.cjs +104 -4
  49. package/dist/registry.cjs.map +1 -1
  50. package/dist/registry.js +2 -2
  51. package/dist/{run-cohort-rgT_FX3V.d.ts → run-cohort-DAfhZm-p.d.ts} +2 -2
  52. package/dist/{run-cohort-DNpPa0mq.d.cts → run-cohort-DRJvUWO9.d.cts} +2 -2
  53. package/dist/{run-flow-pW0PllaZ.d.cts → run-flow-Bdrn4lQV.d.cts} +1 -1
  54. package/dist/{run-flow-BLP9rXfO.d.ts → run-flow-D2iOjWsj.d.ts} +1 -1
  55. package/dist/runtime/index.d.cts +5 -5
  56. package/dist/runtime/index.d.ts +5 -5
  57. package/dist/runtime.cjs +104 -4
  58. package/dist/runtime.cjs.map +1 -1
  59. package/dist/runtime.js +3 -3
  60. package/dist/schema/index.d.cts +1 -1
  61. package/dist/schema/index.d.ts +1 -1
  62. package/dist/schema.cjs +104 -4
  63. package/dist/schema.cjs.map +1 -1
  64. package/dist/schema.js +3 -3
  65. package/dist/screens.cjs +104 -4
  66. package/dist/screens.cjs.map +1 -1
  67. package/dist/screens.d.cts +2 -2
  68. package/dist/screens.d.ts +2 -2
  69. package/dist/screens.js +4 -4
  70. package/dist/terminal/fancy-term-host.d.cts +1 -1
  71. package/dist/terminal/fancy-term-host.d.ts +1 -1
  72. package/dist/{types-BdkXxjFh.d.cts → types-B1jftRa9.d.cts} +1 -1
  73. package/dist/{types-CbekKMMO.d.ts → types-D5SBBpbe.d.ts} +1 -1
  74. package/dist/{types-B-Syk9-M.d.cts → types-E48Dpesq.d.cts} +20 -0
  75. package/dist/{types-B-Syk9-M.d.ts → types-E48Dpesq.d.ts} +20 -0
  76. package/dist/ux.cjs +104 -4
  77. package/dist/ux.cjs.map +1 -1
  78. package/dist/ux.d.cts +2 -2
  79. package/dist/ux.d.ts +2 -2
  80. package/dist/ux.js +1 -1
  81. package/package.json +2 -2
  82. package/dist/chunk-YNKOEQLI.js.map +0 -1
package/dist/runtime.js CHANGED
@@ -1,7 +1,7 @@
1
- export { applyOutputsToNodes, applyStatusesToNodes, createHistory, useFlowHistory, useFlowRun, useFlowState } from './chunk-X2UHP2S5.js';
2
- export { runCohort } from './chunk-KFC3BURT.js';
1
+ export { applyOutputsToNodes, applyStatusesToNodes, createHistory, useFlowHistory, useFlowRun, useFlowState } from './chunk-S4MOUOG4.js';
2
+ export { runCohort } from './chunk-4GNDRRJ3.js';
3
3
  import './chunk-OWENS2H5.js';
4
- export { RunIdentity, escapeSegment, runFlow } from './chunk-YNKOEQLI.js';
4
+ export { RunIdentity, escapeSegment, runFlow } from './chunk-J5YUYDMK.js';
5
5
  import './chunk-2QXKDLGT.js';
6
6
  //# sourceMappingURL=runtime.js.map
7
7
  //# sourceMappingURL=runtime.js.map
@@ -1,4 +1,4 @@
1
- import { G as WorkflowInput, P as PortDescriptor, F as FlowGraph } from '../types-B-Syk9-M.cjs';
1
+ import { G as WorkflowInput, P as PortDescriptor, F as FlowGraph } from '../types-E48Dpesq.cjs';
2
2
  import '@xyflow/react';
3
3
 
4
4
  /** Schema version. Bump on breaking shape changes; add migrations as needed. */
@@ -1,4 +1,4 @@
1
- import { G as WorkflowInput, P as PortDescriptor, F as FlowGraph } from '../types-B-Syk9-M.js';
1
+ import { G as WorkflowInput, P as PortDescriptor, F as FlowGraph } from '../types-E48Dpesq.js';
2
2
  import '@xyflow/react';
3
3
 
4
4
  /** Schema version. Bump on breaking shape changes; add migrations as needed. */
package/dist/schema.cjs CHANGED
@@ -724,6 +724,9 @@ async function runFlow(graph, executors, onEvent = () => {
724
724
  executors,
725
725
  depth,
726
726
  run,
727
+ // Structural executors derive a nested lane from the graph they are
728
+ // in; `for_each`'s `item` port cannot be implemented without it.
729
+ graph,
727
730
  terminal: terminalAccessorFor(node)
728
731
  })
729
732
  );
@@ -1212,14 +1215,102 @@ var mergeExecutor = (ctx) => {
1212
1215
  }
1213
1216
  return merged;
1214
1217
  };
1215
- var forEachExecutor = (ctx) => {
1216
- const source = resolve(configOf(ctx.node).source, ctx.inputs);
1218
+ var FOR_EACH_DEFAULT_MAX_ITEMS = 1e3;
1219
+ var FOR_EACH_HARD_MAX_ITEMS = 1e4;
1220
+ function reachable(adjacency, starts) {
1221
+ const seen = /* @__PURE__ */ new Set();
1222
+ const queue = [...starts];
1223
+ for (let cursor = 0; cursor < queue.length; cursor += 1) {
1224
+ const id = queue[cursor];
1225
+ if (seen.has(id)) continue;
1226
+ seen.add(id);
1227
+ for (const target of adjacency.get(id) ?? []) queue.push(target);
1228
+ }
1229
+ return seen;
1230
+ }
1231
+ function forEachLane(graph, nodeId) {
1232
+ const handleOf = (edge) => edge.sourceHandle ?? "out";
1233
+ const itemEdges = graph.edges.filter((e) => e.source === nodeId && handleOf(e) === "item");
1234
+ if (itemEdges.length === 0) return null;
1235
+ const adjacency = /* @__PURE__ */ new Map();
1236
+ for (const edge of graph.edges) {
1237
+ const list = adjacency.get(edge.source) ?? [];
1238
+ list.push(edge.target);
1239
+ adjacency.set(edge.source, list);
1240
+ }
1241
+ const done = reachable(
1242
+ adjacency,
1243
+ graph.edges.filter((e) => e.source === nodeId && handleOf(e) === "done").map((e) => e.target)
1244
+ );
1245
+ const body = new Set(
1246
+ [...reachable(adjacency, itemEdges.map((e) => e.target))].filter(
1247
+ (id) => !done.has(id) && id !== nodeId
1248
+ )
1249
+ );
1250
+ return {
1251
+ graph: {
1252
+ nodes: graph.nodes.filter((n) => body.has(n.id)),
1253
+ edges: graph.edges.filter((e) => body.has(e.source) && body.has(e.target)),
1254
+ ...graph.inputs === void 0 ? {} : { inputs: graph.inputs }
1255
+ },
1256
+ entries: itemEdges.filter((e) => body.has(e.target))
1257
+ };
1258
+ }
1259
+ var forEachExecutor = async (ctx) => {
1260
+ const config = configOf(ctx.node);
1261
+ const source = resolve(config.source, ctx.inputs);
1217
1262
  let items;
1218
1263
  if (Array.isArray(source)) items = source;
1219
1264
  else if (source === null || source === void 0) items = [];
1220
1265
  else if (typeof source === "object") items = Object.values(source);
1221
1266
  else items = [source];
1222
- return { items, count: items.length };
1267
+ const lane = ctx.graph ? forEachLane(ctx.graph, ctx.node.id) : null;
1268
+ if (lane === null || config.mode === "collect") {
1269
+ return { items, count: items.length };
1270
+ }
1271
+ if (lane.graph.nodes.length === 0) {
1272
+ ctx.abort(`for_each "${ctx.node.id}" has an item edge but its derived lane is empty`);
1273
+ }
1274
+ const maxItems = Number(config.maxItems ?? FOR_EACH_DEFAULT_MAX_ITEMS);
1275
+ if (!Number.isFinite(maxItems) || maxItems < 1 || maxItems > FOR_EACH_HARD_MAX_ITEMS) {
1276
+ ctx.abort(`for_each "${ctx.node.id}" maxItems must be between 1 and ${FOR_EACH_HARD_MAX_ITEMS}`);
1277
+ }
1278
+ if (items.length > maxItems) {
1279
+ ctx.abort(
1280
+ `for_each "${ctx.node.id}" resolved ${items.length} items exceeds its maxItems cap of ${maxItems}`
1281
+ );
1282
+ }
1283
+ const results = [];
1284
+ const failures = [];
1285
+ for (const [index, item] of items.entries()) {
1286
+ const initialInputs = {};
1287
+ for (const edge of lane.entries) {
1288
+ initialInputs[edge.target] = {
1289
+ ...initialInputs[edge.target] ?? {},
1290
+ [edge.targetHandle ?? "in"]: item
1291
+ };
1292
+ }
1293
+ const nested = await runFlow(lane.graph, { ...ctx.executors ?? {} }, () => {
1294
+ }, {
1295
+ initialInputs,
1296
+ depth: (ctx.depth ?? 0) + 1,
1297
+ // The index rides on the identity, so a node in iteration 3 cannot share
1298
+ // an idempotency key with the same node in iteration 4.
1299
+ run: ctx.run?.descend(ctx.node.id, index)
1300
+ });
1301
+ if (!nested.ok) {
1302
+ const reason = nested.error ?? "unknown error";
1303
+ if (decodePause(reason)) ctx.abort(reason);
1304
+ results.push(null);
1305
+ failures.push({ index, item, error: reason });
1306
+ continue;
1307
+ }
1308
+ results.push(nested.outputs);
1309
+ }
1310
+ return {
1311
+ __port: "done",
1312
+ value: { items, results, failures, count: items.length }
1313
+ };
1223
1314
  };
1224
1315
  var manualTriggerExecutor = (ctx) => ctx.inputs;
1225
1316
  var outputExecutor = (ctx) => {
@@ -1776,6 +1867,15 @@ var KINDS = [
1776
1867
  name: "@particle-academy/for_each",
1777
1868
  outputShape: [
1778
1869
  { path: "items", type: "array" },
1870
+ // `results` and `failures` are the WIRED shape -- what a lane produces
1871
+ // when the `item` port is connected. Declared unconditionally because a
1872
+ // declaration describes the kind, not one graph's use of it, and because
1873
+ // the shared table requires them: fancy-conformance 0.30.0 added
1874
+ // `results` and 0.31.0 added `failures`, both BREAKING, both so that a
1875
+ // runtime which has not implemented iteration fails here rather than
1876
+ // reporting surface parity it does not have.
1877
+ { path: "results", type: "array" },
1878
+ { path: "failures", type: "array" },
1779
1879
  { path: "count", type: "number" }
1780
1880
  ],
1781
1881
  aliases: ["for_each", "@fancy/for_each"],
@@ -1784,7 +1884,7 @@ var KINDS = [
1784
1884
  executor: forEachExecutor,
1785
1885
  category: "logic",
1786
1886
  label: "For Each",
1787
- description: "Iterate over a list, emitting each item on `item`.",
1887
+ description: "Wire `item` to a lane and it runs once per item, aggregating `results` and `failures` on `done`. Leave `item` unwired (or set `mode: collect`) and it just publishes the list and its size -- one node, one checkpoint.",
1788
1888
  icon: "\u21BB",
1789
1889
  inputs: [{ id: "in" }],
1790
1890
  outputs: [{ id: "item", label: "item" }, { id: "done", label: "done" }],