@particle-academy/fancy-flow 0.77.1 → 0.79.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.
- package/dist/{FlowViewer-Ak8kbY0e.d.cts → FlowViewer-BqYQl2vS.d.cts} +1 -1
- package/dist/{FlowViewer-BAV29Zpi.d.ts → FlowViewer-_Fq8AX9V.d.ts} +1 -1
- package/dist/{HumanPrompt-xYPCL2jO.d.cts → HumanPrompt-Sl1wD9Bx.d.cts} +2 -2
- package/dist/{HumanPrompt-Ge_ccCgS.d.ts → HumanPrompt-_SKIdSpx.d.ts} +2 -2
- package/dist/{chunk-T6WIIGSK.js → chunk-I5EPWHNM.js} +3 -3
- package/dist/{chunk-T6WIIGSK.js.map → chunk-I5EPWHNM.js.map} +1 -1
- package/dist/{chunk-EGXA4SYJ.js → chunk-J66LOLJR.js} +4 -4
- package/dist/{chunk-EGXA4SYJ.js.map → chunk-J66LOLJR.js.map} +1 -1
- package/dist/{chunk-G5RAGPVD.js → chunk-KMONOPAK.js} +3 -3
- package/dist/{chunk-G5RAGPVD.js.map → chunk-KMONOPAK.js.map} +1 -1
- package/dist/{chunk-ARSOSEJV.js → chunk-LBE4L3DS.js} +4 -4
- package/dist/{chunk-ARSOSEJV.js.map → chunk-LBE4L3DS.js.map} +1 -1
- package/dist/{chunk-EEIWAIXW.js → chunk-OZHBAXMA.js} +125 -8
- package/dist/chunk-OZHBAXMA.js.map +1 -0
- package/dist/{chunk-2VI24UPB.js → chunk-QMJVUT7C.js} +3 -3
- package/dist/{chunk-2VI24UPB.js.map → chunk-QMJVUT7C.js.map} +1 -1
- package/dist/{chunk-CQAMEPPI.js → chunk-R4G7SPLD.js} +3 -3
- package/dist/{chunk-CQAMEPPI.js.map → chunk-R4G7SPLD.js.map} +1 -1
- package/dist/connectors.d.cts +2 -2
- package/dist/connectors.d.ts +2 -2
- package/dist/durable/index.d.cts +2 -2
- package/dist/durable/index.d.ts +2 -2
- package/dist/durable.cjs +123 -6
- package/dist/durable.cjs.map +1 -1
- package/dist/durable.js +1 -1
- package/dist/engine.cjs +123 -6
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.cts +6 -6
- package/dist/engine.d.ts +6 -6
- package/dist/engine.js +4 -4
- package/dist/fields/react-fancy.d.cts +3 -3
- package/dist/fields/react-fancy.d.ts +3 -3
- package/dist/index.cjs +123 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -10
- package/dist/index.d.ts +10 -10
- package/dist/index.js +12 -12
- package/dist/layout/index.d.cts +1 -1
- package/dist/layout/index.d.ts +1 -1
- package/dist/llm/prism.d.cts +1 -1
- package/dist/llm/prism.d.ts +1 -1
- package/dist/llm/vercel-ai.d.cts +1 -1
- package/dist/llm/vercel-ai.d.ts +1 -1
- package/dist/registry/index.d.cts +5 -5
- package/dist/registry/index.d.ts +5 -5
- package/dist/{registry-JUcN_xWK.d.ts → registry-C4GcH583.d.ts} +1 -1
- package/dist/{registry-B6SiTaLZ.d.cts → registry-DWIY3bMP.d.cts} +1 -1
- package/dist/registry.cjs +123 -6
- package/dist/registry.cjs.map +1 -1
- package/dist/registry.js +2 -2
- package/dist/{run-cohort-rgT_FX3V.d.ts → run-cohort-DAfhZm-p.d.ts} +2 -2
- package/dist/{run-cohort-DNpPa0mq.d.cts → run-cohort-DRJvUWO9.d.cts} +2 -2
- package/dist/{run-flow-pW0PllaZ.d.cts → run-flow-Bdrn4lQV.d.cts} +1 -1
- package/dist/{run-flow-BLP9rXfO.d.ts → run-flow-D2iOjWsj.d.ts} +1 -1
- package/dist/runtime/index.d.cts +5 -5
- package/dist/runtime/index.d.ts +5 -5
- package/dist/runtime.cjs +123 -6
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +3 -3
- package/dist/schema/index.d.cts +1 -1
- package/dist/schema/index.d.ts +1 -1
- package/dist/schema.cjs +123 -6
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.js +3 -3
- package/dist/screens.cjs +123 -6
- package/dist/screens.cjs.map +1 -1
- package/dist/screens.d.cts +2 -2
- package/dist/screens.d.ts +2 -2
- package/dist/screens.js +4 -4
- package/dist/terminal/fancy-term-host.d.cts +1 -1
- package/dist/terminal/fancy-term-host.d.ts +1 -1
- package/dist/{types-BdkXxjFh.d.cts → types-B1jftRa9.d.cts} +1 -1
- package/dist/{types-CbekKMMO.d.ts → types-D5SBBpbe.d.ts} +1 -1
- package/dist/{types-B-Syk9-M.d.ts → types-E48Dpesq.d.cts} +20 -0
- package/dist/{types-B-Syk9-M.d.cts → types-E48Dpesq.d.ts} +20 -0
- package/dist/ux.cjs +123 -6
- package/dist/ux.cjs.map +1 -1
- package/dist/ux.d.cts +2 -2
- package/dist/ux.d.ts +2 -2
- package/dist/ux.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-EEIWAIXW.js.map +0 -1
|
@@ -745,6 +745,9 @@ async function runFlow(graph, executors, onEvent = () => {
|
|
|
745
745
|
executors,
|
|
746
746
|
depth,
|
|
747
747
|
run,
|
|
748
|
+
// Structural executors derive a nested lane from the graph they are
|
|
749
|
+
// in; `for_each`'s `item` port cannot be implemented without it.
|
|
750
|
+
graph,
|
|
748
751
|
terminal: terminalAccessorFor(node)
|
|
749
752
|
})
|
|
750
753
|
);
|
|
@@ -1199,6 +1202,7 @@ var branchExecutor = (ctx) => {
|
|
|
1199
1202
|
const inputs = ctx.inputs;
|
|
1200
1203
|
let taken;
|
|
1201
1204
|
const raw = config.condition;
|
|
1205
|
+
validateRoutingExpression(ctx, raw, "branch", "condition");
|
|
1202
1206
|
if (typeof raw === "string" && raw.trim() !== "") {
|
|
1203
1207
|
taken = truthy(resolve(raw, inputs));
|
|
1204
1208
|
warnIfUnresolved(ctx, raw, taken ? "true" : "false");
|
|
@@ -1253,14 +1257,102 @@ var mergeExecutor = (ctx) => {
|
|
|
1253
1257
|
}
|
|
1254
1258
|
return merged;
|
|
1255
1259
|
};
|
|
1256
|
-
var
|
|
1257
|
-
|
|
1260
|
+
var FOR_EACH_DEFAULT_MAX_ITEMS = 1e3;
|
|
1261
|
+
var FOR_EACH_HARD_MAX_ITEMS = 1e4;
|
|
1262
|
+
function reachable(adjacency, starts) {
|
|
1263
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1264
|
+
const queue = [...starts];
|
|
1265
|
+
for (let cursor = 0; cursor < queue.length; cursor += 1) {
|
|
1266
|
+
const id = queue[cursor];
|
|
1267
|
+
if (seen.has(id)) continue;
|
|
1268
|
+
seen.add(id);
|
|
1269
|
+
for (const target of adjacency.get(id) ?? []) queue.push(target);
|
|
1270
|
+
}
|
|
1271
|
+
return seen;
|
|
1272
|
+
}
|
|
1273
|
+
function forEachLane(graph, nodeId) {
|
|
1274
|
+
const handleOf = (edge) => edge.sourceHandle ?? "out";
|
|
1275
|
+
const itemEdges = graph.edges.filter((e) => e.source === nodeId && handleOf(e) === "item");
|
|
1276
|
+
if (itemEdges.length === 0) return null;
|
|
1277
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
1278
|
+
for (const edge of graph.edges) {
|
|
1279
|
+
const list = adjacency.get(edge.source) ?? [];
|
|
1280
|
+
list.push(edge.target);
|
|
1281
|
+
adjacency.set(edge.source, list);
|
|
1282
|
+
}
|
|
1283
|
+
const done = reachable(
|
|
1284
|
+
adjacency,
|
|
1285
|
+
graph.edges.filter((e) => e.source === nodeId && handleOf(e) === "done").map((e) => e.target)
|
|
1286
|
+
);
|
|
1287
|
+
const body = new Set(
|
|
1288
|
+
[...reachable(adjacency, itemEdges.map((e) => e.target))].filter(
|
|
1289
|
+
(id) => !done.has(id) && id !== nodeId
|
|
1290
|
+
)
|
|
1291
|
+
);
|
|
1292
|
+
return {
|
|
1293
|
+
graph: {
|
|
1294
|
+
nodes: graph.nodes.filter((n) => body.has(n.id)),
|
|
1295
|
+
edges: graph.edges.filter((e) => body.has(e.source) && body.has(e.target)),
|
|
1296
|
+
...graph.inputs === void 0 ? {} : { inputs: graph.inputs }
|
|
1297
|
+
},
|
|
1298
|
+
entries: itemEdges.filter((e) => body.has(e.target))
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
var forEachExecutor = async (ctx) => {
|
|
1302
|
+
const config = configOf(ctx.node);
|
|
1303
|
+
const source = resolve(config.source, ctx.inputs);
|
|
1258
1304
|
let items;
|
|
1259
1305
|
if (Array.isArray(source)) items = source;
|
|
1260
1306
|
else if (source === null || source === void 0) items = [];
|
|
1261
1307
|
else if (typeof source === "object") items = Object.values(source);
|
|
1262
1308
|
else items = [source];
|
|
1263
|
-
|
|
1309
|
+
const lane = ctx.graph ? forEachLane(ctx.graph, ctx.node.id) : null;
|
|
1310
|
+
if (lane === null || config.mode === "collect") {
|
|
1311
|
+
return { items, count: items.length };
|
|
1312
|
+
}
|
|
1313
|
+
if (lane.graph.nodes.length === 0) {
|
|
1314
|
+
ctx.abort(`for_each "${ctx.node.id}" has an item edge but its derived lane is empty`);
|
|
1315
|
+
}
|
|
1316
|
+
const maxItems = Number(config.maxItems ?? FOR_EACH_DEFAULT_MAX_ITEMS);
|
|
1317
|
+
if (!Number.isFinite(maxItems) || maxItems < 1 || maxItems > FOR_EACH_HARD_MAX_ITEMS) {
|
|
1318
|
+
ctx.abort(`for_each "${ctx.node.id}" maxItems must be between 1 and ${FOR_EACH_HARD_MAX_ITEMS}`);
|
|
1319
|
+
}
|
|
1320
|
+
if (items.length > maxItems) {
|
|
1321
|
+
ctx.abort(
|
|
1322
|
+
`for_each "${ctx.node.id}" resolved ${items.length} items exceeds its maxItems cap of ${maxItems}`
|
|
1323
|
+
);
|
|
1324
|
+
}
|
|
1325
|
+
const results = [];
|
|
1326
|
+
const failures = [];
|
|
1327
|
+
for (const [index, item] of items.entries()) {
|
|
1328
|
+
const initialInputs = {};
|
|
1329
|
+
for (const edge of lane.entries) {
|
|
1330
|
+
initialInputs[edge.target] = {
|
|
1331
|
+
...initialInputs[edge.target] ?? {},
|
|
1332
|
+
[edge.targetHandle ?? "in"]: item
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
const nested = await runFlow(lane.graph, { ...ctx.executors ?? {} }, () => {
|
|
1336
|
+
}, {
|
|
1337
|
+
initialInputs,
|
|
1338
|
+
depth: (ctx.depth ?? 0) + 1,
|
|
1339
|
+
// The index rides on the identity, so a node in iteration 3 cannot share
|
|
1340
|
+
// an idempotency key with the same node in iteration 4.
|
|
1341
|
+
run: ctx.run?.descend(ctx.node.id, index)
|
|
1342
|
+
});
|
|
1343
|
+
if (!nested.ok) {
|
|
1344
|
+
const reason = nested.error ?? "unknown error";
|
|
1345
|
+
if (decodePause(reason)) ctx.abort(reason);
|
|
1346
|
+
results.push(null);
|
|
1347
|
+
failures.push({ index, item, error: reason });
|
|
1348
|
+
continue;
|
|
1349
|
+
}
|
|
1350
|
+
results.push(nested.outputs);
|
|
1351
|
+
}
|
|
1352
|
+
return {
|
|
1353
|
+
__port: "done",
|
|
1354
|
+
value: { items, results, failures, count: items.length }
|
|
1355
|
+
};
|
|
1264
1356
|
};
|
|
1265
1357
|
var manualTriggerExecutor = (ctx) => ctx.inputs;
|
|
1266
1358
|
var outputExecutor = (ctx) => {
|
|
@@ -1280,6 +1372,7 @@ var switchCaseExecutor = (ctx) => {
|
|
|
1280
1372
|
const config = configOf(ctx.node);
|
|
1281
1373
|
const inputs = ctx.inputs;
|
|
1282
1374
|
const expression = config.value;
|
|
1375
|
+
validateRoutingExpression(ctx, expression, "switch_case", "value");
|
|
1283
1376
|
const value = text(resolve(expression, inputs));
|
|
1284
1377
|
const cases = config.cases ?? {};
|
|
1285
1378
|
const matched = Object.prototype.hasOwnProperty.call(cases, value);
|
|
@@ -1287,6 +1380,21 @@ var switchCaseExecutor = (ctx) => {
|
|
|
1287
1380
|
warnIfUnresolved(ctx, expression, port, "value");
|
|
1288
1381
|
return { __port: port, value: inputs.in ?? inputs };
|
|
1289
1382
|
};
|
|
1383
|
+
function validateRoutingExpression(ctx, value, kind, field) {
|
|
1384
|
+
if (typeof value !== "string" || value.trim() === "") return;
|
|
1385
|
+
const bare = value.trim();
|
|
1386
|
+
const subject = `${kind} "${ctx.node.id}" ${field} "${bare}"`;
|
|
1387
|
+
if (!value.includes("{{")) {
|
|
1388
|
+
ctx.abort(`${subject} is not an expression -- wrap it: {{ ${bare} }}`);
|
|
1389
|
+
}
|
|
1390
|
+
let open = 0;
|
|
1391
|
+
for (const [delimiter] of value.matchAll(/\{\{|\}\}/g)) {
|
|
1392
|
+
open = delimiter === "{{" ? open + 1 : Math.max(0, open - 1);
|
|
1393
|
+
}
|
|
1394
|
+
if (open > 0) {
|
|
1395
|
+
ctx.abort(`${subject} has an unclosed expression -- close every {{ with }}`);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1290
1398
|
|
|
1291
1399
|
// src/registry/terminal-nodes.ts
|
|
1292
1400
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
@@ -1778,7 +1886,7 @@ var KINDS = [
|
|
|
1778
1886
|
key: "condition",
|
|
1779
1887
|
label: "Raw expression (advanced)",
|
|
1780
1888
|
example: "{{ $json.active && $json.score > 10 }}",
|
|
1781
|
-
description: "Escape hatch for logic the builder can't express. Overrides the conditions above when set."
|
|
1889
|
+
description: "Escape hatch for logic the builder can't express. Overrides the conditions above when set. String values must be {{ }}-wrapped expressions; bare strings and unclosed templates abort the run."
|
|
1782
1890
|
}
|
|
1783
1891
|
]
|
|
1784
1892
|
},
|
|
@@ -1798,7 +1906,7 @@ var KINDS = [
|
|
|
1798
1906
|
// moves the ports on the canvas and the ports the runtime activates.
|
|
1799
1907
|
outputs: (config) => casePorts(config?.cases),
|
|
1800
1908
|
configSchema: [
|
|
1801
|
-
{ type: "expression", key: "value", label: "Switch on", example: "{{ $json.kind }}", required: true },
|
|
1909
|
+
{ type: "expression", key: "value", label: "Switch on", description: "String values must be {{ }}-wrapped expressions; bare strings and unclosed templates abort the run.", example: "{{ $json.kind }}", required: true },
|
|
1802
1910
|
{
|
|
1803
1911
|
type: "keyvalue",
|
|
1804
1912
|
key: "cases",
|
|
@@ -1817,6 +1925,15 @@ var KINDS = [
|
|
|
1817
1925
|
name: "@particle-academy/for_each",
|
|
1818
1926
|
outputShape: [
|
|
1819
1927
|
{ path: "items", type: "array" },
|
|
1928
|
+
// `results` and `failures` are the WIRED shape -- what a lane produces
|
|
1929
|
+
// when the `item` port is connected. Declared unconditionally because a
|
|
1930
|
+
// declaration describes the kind, not one graph's use of it, and because
|
|
1931
|
+
// the shared table requires them: fancy-conformance 0.30.0 added
|
|
1932
|
+
// `results` and 0.31.0 added `failures`, both BREAKING, both so that a
|
|
1933
|
+
// runtime which has not implemented iteration fails here rather than
|
|
1934
|
+
// reporting surface parity it does not have.
|
|
1935
|
+
{ path: "results", type: "array" },
|
|
1936
|
+
{ path: "failures", type: "array" },
|
|
1820
1937
|
{ path: "count", type: "number" }
|
|
1821
1938
|
],
|
|
1822
1939
|
aliases: ["for_each", "@fancy/for_each"],
|
|
@@ -1825,7 +1942,7 @@ var KINDS = [
|
|
|
1825
1942
|
executor: forEachExecutor,
|
|
1826
1943
|
category: "logic",
|
|
1827
1944
|
label: "For Each",
|
|
1828
|
-
description: "
|
|
1945
|
+
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.",
|
|
1829
1946
|
icon: "\u21BB",
|
|
1830
1947
|
inputs: [{ id: "in" }],
|
|
1831
1948
|
outputs: [{ id: "item", label: "item" }, { id: "done", label: "done" }],
|
|
@@ -2894,5 +3011,5 @@ function describeExpressionGrammar() {
|
|
|
2894
3011
|
}
|
|
2895
3012
|
|
|
2896
3013
|
export { BUILTIN_KIND_DATA, DEFAULT_MAX_DEPTH, LEGACY_PAUSE_PREFIXES, PAUSE_PREFIX, RunIdentity, UnresolvedPathError, applyKindSchemaOverlay, availableVariables, baseVariables, categoryAccent, clearKindSchemaOverlays, clearNodeKindOverrides, declaredRoutes, decodePause, defaultConfigFor, describeExpressionGrammar, encodePause, ensureBuiltinKinds, escapeSegment, evaluateConfig, evaluateExpression, getNodeKind, humanInputFields, isPause, kindIds, listNodeKinds, llmRouterExecutor, nodeConfig, onNodeKindsChanged, outputFieldsFor, overrideNodeKind, pauseForHuman, registerBuiltinKindInternal, registerNodeKind, resolveFallbackPort, resolveKindId, resolveNodePorts, resolvePath, resolvePortSpec, runFlow, subflowExecutor, subflowMode, subflowPorts, text, truthy, tryResolvePath, undeliveredEdgeWarnings, unregisterNodeKind, validateConfig };
|
|
2897
|
-
//# sourceMappingURL=chunk-
|
|
2898
|
-
//# sourceMappingURL=chunk-
|
|
3014
|
+
//# sourceMappingURL=chunk-OZHBAXMA.js.map
|
|
3015
|
+
//# sourceMappingURL=chunk-OZHBAXMA.js.map
|