@particle-academy/fancy-flow 0.71.0 → 0.72.1
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/{chunk-3L47KJ6Q.js → chunk-3RXQGYGH.js} +3 -3
- package/dist/{chunk-3L47KJ6Q.js.map → chunk-3RXQGYGH.js.map} +1 -1
- package/dist/{chunk-PNTDTSMR.js → chunk-7DJ56PUA.js} +4 -4
- package/dist/{chunk-PNTDTSMR.js.map → chunk-7DJ56PUA.js.map} +1 -1
- package/dist/{chunk-EVGSL2EM.js → chunk-EX34GCKK.js} +162 -151
- package/dist/chunk-EX34GCKK.js.map +1 -0
- package/dist/{chunk-XI4AZD2S.js → chunk-GQ5LEA7Q.js} +3 -3
- package/dist/{chunk-XI4AZD2S.js.map → chunk-GQ5LEA7Q.js.map} +1 -1
- package/dist/{chunk-D2OBU3CE.js → chunk-K7KO3UJ3.js} +3 -3
- package/dist/{chunk-D2OBU3CE.js.map → chunk-K7KO3UJ3.js.map} +1 -1
- package/dist/{chunk-FPWJYSXX.js → chunk-LYYQO7EY.js} +4 -4
- package/dist/{chunk-FPWJYSXX.js.map → chunk-LYYQO7EY.js.map} +1 -1
- package/dist/{chunk-KQCX6KN7.js → chunk-VAF2SWTC.js} +3 -3
- package/dist/{chunk-KQCX6KN7.js.map → chunk-VAF2SWTC.js.map} +1 -1
- package/dist/durable/index.d.cts +90 -16
- package/dist/durable/index.d.ts +90 -16
- package/dist/durable.cjs +160 -83
- package/dist/durable.cjs.map +1 -1
- package/dist/durable.js +79 -14
- package/dist/durable.js.map +1 -1
- package/dist/engine.cjs +82 -71
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.cts +2 -2
- package/dist/engine.d.ts +2 -2
- package/dist/engine.js +4 -4
- package/dist/index.cjs +128 -117
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +12 -12
- package/dist/registry.cjs +82 -71
- package/dist/registry.cjs.map +1 -1
- package/dist/registry.js +2 -2
- package/dist/{run-cohort-DL9JzzPU.d.cts → run-cohort-DNpPa0mq.d.cts} +1 -1
- package/dist/{run-cohort-CjUBWg6X.d.ts → run-cohort-rgT_FX3V.d.ts} +1 -1
- package/dist/{run-flow-B_8hgO5_.d.cts → run-flow-BLP9rXfO.d.ts} +22 -1
- package/dist/{run-flow-CxEGBOxd.d.ts → run-flow-pW0PllaZ.d.cts} +22 -1
- package/dist/runtime/index.d.cts +3 -3
- package/dist/runtime/index.d.ts +3 -3
- package/dist/runtime.cjs +82 -71
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +3 -3
- package/dist/schema.cjs +82 -71
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.js +3 -3
- package/dist/screens.cjs +82 -71
- package/dist/screens.cjs.map +1 -1
- package/dist/screens.js +4 -4
- package/dist/ux.cjs +82 -71
- package/dist/ux.cjs.map +1 -1
- package/dist/ux.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-EVGSL2EM.js.map +0 -1
package/dist/registry.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { ANY_PORT_TYPE, BUILTIN_KINDS, RegistryNode, buildNodeTypes, createConnectionValidator, defaultPortCompatibility, registerBuiltinKinds } from './chunk-
|
|
1
|
+
export { ANY_PORT_TYPE, BUILTIN_KINDS, RegistryNode, buildNodeTypes, createConnectionValidator, defaultPortCompatibility, registerBuiltinKinds } from './chunk-3RXQGYGH.js';
|
|
2
2
|
export { RichInputPreview, getRichInputAdapter, isRichInputEnabled, onRichInputAdapterChanged, registerRichInputAdapter } from './chunk-F5RPRB7A.js';
|
|
3
3
|
import './chunk-OWENS2H5.js';
|
|
4
4
|
export { LEGACY_PAUSE_PREFIXES, PAUSE_PREFIX, decodePause, encodePause, isPause, pauseForHuman } from './chunk-UEOE6B52.js';
|
|
5
|
-
export { DEFAULT_MAX_DEPTH, applyKindSchemaOverlay, categoryAccent, clearKindSchemaOverlays, clearNodeKindOverrides, declaredRoutes, defaultConfigFor, ensureBuiltinKinds, getNodeKind, kindIds, listNodeKinds, llmRouterExecutor as llmBranchExecutor, llmRouterExecutor, nodeConfig, onNodeKindsChanged, overrideNodeKind, registerNodeKind, resolveFallbackPort, resolveKindId, resolveNodePorts, resolvePortSpec, subflowExecutor, subflowMode, subflowPorts, unregisterNodeKind, validateConfig } from './chunk-
|
|
5
|
+
export { DEFAULT_MAX_DEPTH, applyKindSchemaOverlay, categoryAccent, clearKindSchemaOverlays, clearNodeKindOverrides, declaredRoutes, defaultConfigFor, ensureBuiltinKinds, getNodeKind, kindIds, listNodeKinds, llmRouterExecutor as llmBranchExecutor, llmRouterExecutor, nodeConfig, onNodeKindsChanged, overrideNodeKind, registerNodeKind, resolveFallbackPort, resolveKindId, resolveNodePorts, resolvePortSpec, subflowExecutor, subflowMode, subflowPorts, unregisterNodeKind, validateConfig } from './chunk-EX34GCKK.js';
|
|
6
6
|
export { capabilityStatus, getLlmClient, getTerminalHost, getWorkflowResolver, isResolutionFailure, registerLlmClient, registerTerminalHost, registerWorkflowResolver } from './chunk-2QXKDLGT.js';
|
|
7
7
|
//# sourceMappingURL=registry.js.map
|
|
8
8
|
//# sourceMappingURL=registry.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { F as FlowGraph, E as ExecutorRegistry, R as RunEvent } from './types-B-Syk9-M.cjs';
|
|
2
|
-
import { R as RunOptions, a as RunResult } from './run-flow-
|
|
2
|
+
import { R as RunOptions, a as RunResult } from './run-flow-pW0PllaZ.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* How the flows one trigger fired should treat each other.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { F as FlowGraph, E as ExecutorRegistry, R as RunEvent } from './types-B-Syk9-M.js';
|
|
2
|
-
import { R as RunOptions, a as RunResult } from './run-flow-
|
|
2
|
+
import { R as RunOptions, a as RunResult } from './run-flow-BLP9rXfO.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* How the flows one trigger fired should treat each other.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as RunIdentity, d as RunIdentityJson, F as FlowGraph, E as ExecutorRegistry, R as RunEvent } from './types-B-Syk9-M.
|
|
1
|
+
import { c as RunIdentity, d as RunIdentityJson, N as NodeExecutor, F as FlowGraph, E as ExecutorRegistry, R as RunEvent } from './types-B-Syk9-M.js';
|
|
2
2
|
|
|
3
3
|
type RunOptions = {
|
|
4
4
|
/** Stop the run after this many ms. Default: no timeout. */
|
|
@@ -69,6 +69,27 @@ type RunOptions = {
|
|
|
69
69
|
* and Python runtimes have always resumed.
|
|
70
70
|
*/
|
|
71
71
|
resumeOutputs?: Record<string, unknown>;
|
|
72
|
+
/**
|
|
73
|
+
* Executors bound to ONE node id each, matched against `node.id` and nothing
|
|
74
|
+
* else. They outrank every entry of the executor registry.
|
|
75
|
+
*
|
|
76
|
+
* The registry cannot say this. It is one flat object, and `executorLookupIds`
|
|
77
|
+
* tries a key as the node's id AND as its kind, so a key that is both is both:
|
|
78
|
+
* binding `host_kind` to pin the node CALLED `host_kind` also rebinds every
|
|
79
|
+
* node whose kind is `host_kind`. That is the registry's contract (pinned by
|
|
80
|
+
* `flow/executor-resolution`) and it stays. This is the separate channel for a
|
|
81
|
+
* binding that must not leak into the kind namespace -- the PHP twin's
|
|
82
|
+
* `bindNode`, which has always been kept apart from `bind`.
|
|
83
|
+
*
|
|
84
|
+
* The durable replay fences every node but its target through this. Through
|
|
85
|
+
* the registry, a node whose id matched a kind fenced every node of that kind,
|
|
86
|
+
* and the durable run reported success having run nothing.
|
|
87
|
+
*
|
|
88
|
+
* NOT handed down to a nested run. Node ids belong to one graph: a `subflow`
|
|
89
|
+
* child's `t` is not its parent's `t`, so `ctx.executors` stays the registry
|
|
90
|
+
* alone.
|
|
91
|
+
*/
|
|
92
|
+
nodeExecutors?: Record<string, NodeExecutor>;
|
|
72
93
|
};
|
|
73
94
|
type RunResult = {
|
|
74
95
|
ok: boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as RunIdentity, d as RunIdentityJson, F as FlowGraph, E as ExecutorRegistry, R as RunEvent } from './types-B-Syk9-M.
|
|
1
|
+
import { c as RunIdentity, d as RunIdentityJson, N as NodeExecutor, F as FlowGraph, E as ExecutorRegistry, R as RunEvent } from './types-B-Syk9-M.cjs';
|
|
2
2
|
|
|
3
3
|
type RunOptions = {
|
|
4
4
|
/** Stop the run after this many ms. Default: no timeout. */
|
|
@@ -69,6 +69,27 @@ type RunOptions = {
|
|
|
69
69
|
* and Python runtimes have always resumed.
|
|
70
70
|
*/
|
|
71
71
|
resumeOutputs?: Record<string, unknown>;
|
|
72
|
+
/**
|
|
73
|
+
* Executors bound to ONE node id each, matched against `node.id` and nothing
|
|
74
|
+
* else. They outrank every entry of the executor registry.
|
|
75
|
+
*
|
|
76
|
+
* The registry cannot say this. It is one flat object, and `executorLookupIds`
|
|
77
|
+
* tries a key as the node's id AND as its kind, so a key that is both is both:
|
|
78
|
+
* binding `host_kind` to pin the node CALLED `host_kind` also rebinds every
|
|
79
|
+
* node whose kind is `host_kind`. That is the registry's contract (pinned by
|
|
80
|
+
* `flow/executor-resolution`) and it stays. This is the separate channel for a
|
|
81
|
+
* binding that must not leak into the kind namespace -- the PHP twin's
|
|
82
|
+
* `bindNode`, which has always been kept apart from `bind`.
|
|
83
|
+
*
|
|
84
|
+
* The durable replay fences every node but its target through this. Through
|
|
85
|
+
* the registry, a node whose id matched a kind fenced every node of that kind,
|
|
86
|
+
* and the durable run reported success having run nothing.
|
|
87
|
+
*
|
|
88
|
+
* NOT handed down to a nested run. Node ids belong to one graph: a `subflow`
|
|
89
|
+
* child's `t` is not its parent's `t`, so `ctx.executors` stays the registry
|
|
90
|
+
* alone.
|
|
91
|
+
*/
|
|
92
|
+
nodeExecutors?: Record<string, NodeExecutor>;
|
|
72
93
|
};
|
|
73
94
|
type RunResult = {
|
|
74
95
|
ok: boolean;
|
package/dist/runtime/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { a as RunResult, R as RunOptions } from '../run-flow-
|
|
2
|
-
export { r as runFlow } from '../run-flow-
|
|
1
|
+
import { a as RunResult, R as RunOptions } from '../run-flow-pW0PllaZ.cjs';
|
|
2
|
+
export { r as runFlow } from '../run-flow-pW0PllaZ.cjs';
|
|
3
3
|
import { h as NodeRunStatus, F as FlowGraph, E as ExecutorRegistry, a as FlowNode, e as FlowEdge } from '../types-B-Syk9-M.cjs';
|
|
4
4
|
export { c as RunIdentity, d as RunIdentityJson, k as escapeSegment } from '../types-B-Syk9-M.cjs';
|
|
5
|
-
export { C as CohortGuard, a as CohortOptions, b as CohortPolicy, c as CohortResult, r as runCohort } from '../run-cohort-
|
|
5
|
+
export { C as CohortGuard, a as CohortOptions, b as CohortPolicy, c as CohortResult, r as runCohort } from '../run-cohort-DNpPa0mq.cjs';
|
|
6
6
|
import { NodeChange, EdgeChange, Connection } from '@xyflow/react';
|
|
7
7
|
|
|
8
8
|
type FlowRunFeedEntry = {
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { a as RunResult, R as RunOptions } from '../run-flow-
|
|
2
|
-
export { r as runFlow } from '../run-flow-
|
|
1
|
+
import { a as RunResult, R as RunOptions } from '../run-flow-BLP9rXfO.js';
|
|
2
|
+
export { r as runFlow } from '../run-flow-BLP9rXfO.js';
|
|
3
3
|
import { h as NodeRunStatus, F as FlowGraph, E as ExecutorRegistry, a as FlowNode, e as FlowEdge } from '../types-B-Syk9-M.js';
|
|
4
4
|
export { c as RunIdentity, d as RunIdentityJson, k as escapeSegment } from '../types-B-Syk9-M.js';
|
|
5
|
-
export { C as CohortGuard, a as CohortOptions, b as CohortPolicy, c as CohortResult, r as runCohort } from '../run-cohort-
|
|
5
|
+
export { C as CohortGuard, a as CohortOptions, b as CohortPolicy, c as CohortResult, r as runCohort } from '../run-cohort-rgT_FX3V.js';
|
|
6
6
|
import { NodeChange, EdgeChange, Connection } from '@xyflow/react';
|
|
7
7
|
|
|
8
8
|
type FlowRunFeedEntry = {
|
package/dist/runtime.cjs
CHANGED
|
@@ -1827,24 +1827,6 @@ function resolveNodePorts(node, kind) {
|
|
|
1827
1827
|
};
|
|
1828
1828
|
}
|
|
1829
1829
|
|
|
1830
|
-
// src/expressions/variables.ts
|
|
1831
|
-
function outputFieldsFor(node) {
|
|
1832
|
-
const kindName = node.data?.kind ?? node.type;
|
|
1833
|
-
if (!kindName) return [];
|
|
1834
|
-
const kind = getNodeKind(kindName);
|
|
1835
|
-
const shape = kind?.outputShape;
|
|
1836
|
-
if (!shape) return [];
|
|
1837
|
-
if (typeof shape === "function") {
|
|
1838
|
-
try {
|
|
1839
|
-
const config = node.data?.config ?? {};
|
|
1840
|
-
return shape(config) ?? [];
|
|
1841
|
-
} catch {
|
|
1842
|
-
return [];
|
|
1843
|
-
}
|
|
1844
|
-
}
|
|
1845
|
-
return shape;
|
|
1846
|
-
}
|
|
1847
|
-
|
|
1848
1830
|
// src/runtime/run-identity.ts
|
|
1849
1831
|
function escapeSegment(value) {
|
|
1850
1832
|
return value.replace(/%/g, "%25").replace(/\//g, "%2F").replace(/#/g, "%23");
|
|
@@ -2188,6 +2170,81 @@ function specForLane(lane) {
|
|
|
2188
2170
|
};
|
|
2189
2171
|
}
|
|
2190
2172
|
|
|
2173
|
+
// src/expressions/variables.ts
|
|
2174
|
+
function outputFieldsFor(node) {
|
|
2175
|
+
const kindName = node.data?.kind ?? node.type;
|
|
2176
|
+
if (!kindName) return [];
|
|
2177
|
+
const kind = getNodeKind(kindName);
|
|
2178
|
+
const shape = kind?.outputShape;
|
|
2179
|
+
if (!shape) return [];
|
|
2180
|
+
if (typeof shape === "function") {
|
|
2181
|
+
try {
|
|
2182
|
+
const config = node.data?.config ?? {};
|
|
2183
|
+
return shape(config) ?? [];
|
|
2184
|
+
} catch {
|
|
2185
|
+
return [];
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
return shape;
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
// src/runtime/undelivered-edges.ts
|
|
2192
|
+
function undeliveredEdgeWarnings(target, incoming, portValues, completed, nodesById) {
|
|
2193
|
+
const events = [];
|
|
2194
|
+
for (const e of incoming) {
|
|
2195
|
+
const handle = e.sourceHandle ?? "out";
|
|
2196
|
+
if (portValues.has(`${e.source}:${handle}`) || !completed.has(e.source)) continue;
|
|
2197
|
+
if (possiblePortIds(nodesById.get(e.source)).includes(handle)) continue;
|
|
2198
|
+
events.push({
|
|
2199
|
+
type: "log",
|
|
2200
|
+
nodeId: target.id,
|
|
2201
|
+
level: "warn",
|
|
2202
|
+
message: undeliveredEdgeMessage(e, target, portValues, nodesById),
|
|
2203
|
+
detail: { edge: e.id, source: e.source, sourceHandle: handle }
|
|
2204
|
+
});
|
|
2205
|
+
}
|
|
2206
|
+
return events;
|
|
2207
|
+
}
|
|
2208
|
+
function possiblePortIds(node) {
|
|
2209
|
+
if (!node) return ["out"];
|
|
2210
|
+
const own = node.data?.outputs;
|
|
2211
|
+
if (Array.isArray(own)) return own.map((p) => p.id);
|
|
2212
|
+
const kind = getNodeKind(node.data?.kind ?? node.type ?? "");
|
|
2213
|
+
if (!kind) return ["out"];
|
|
2214
|
+
const config = nodeConfig(node);
|
|
2215
|
+
const representative = typeof kind.outputs === "function" && !configDeclaresPorts(kind.name, config);
|
|
2216
|
+
const ids = (resolvePortSpec(kind.outputs, representative ? defaultConfigFor(kind) : config) ?? []).map((p) => p.id);
|
|
2217
|
+
return ids.length > 0 ? ids : ["out"];
|
|
2218
|
+
}
|
|
2219
|
+
function configDeclaresPorts(kindName, config) {
|
|
2220
|
+
const bare = kindName.startsWith("@") ? kindName.slice(kindName.lastIndexOf("/") + 1) : kindName;
|
|
2221
|
+
if (bare === "switch_case") {
|
|
2222
|
+
const cases = config.cases;
|
|
2223
|
+
return !!cases && typeof cases === "object" && Object.values(cases).some((port) => typeof port === "string" && port !== "");
|
|
2224
|
+
}
|
|
2225
|
+
if (bare === "llm_router") {
|
|
2226
|
+
const routes = config.routes;
|
|
2227
|
+
return Array.isArray(routes) && routes.some((route) => route?.port != null && route.port !== "");
|
|
2228
|
+
}
|
|
2229
|
+
return true;
|
|
2230
|
+
}
|
|
2231
|
+
function undeliveredEdgeMessage(edge, target, portValues, nodesById) {
|
|
2232
|
+
const handle = edge.sourceHandle ?? "out";
|
|
2233
|
+
const prefix = `${edge.source}:`;
|
|
2234
|
+
const available = [];
|
|
2235
|
+
for (const key of portValues.keys()) {
|
|
2236
|
+
if (key.startsWith(prefix)) available.push(key.slice(prefix.length));
|
|
2237
|
+
}
|
|
2238
|
+
let message = `Edge ${edge.id} reads port "${handle}" from node ${edge.source}, which never publishes it \u2014 nothing would reach ${target.id} at run time.`;
|
|
2239
|
+
if (available.length > 0) message += ` Available: ${available.join(", ")}.`;
|
|
2240
|
+
const source = nodesById.get(edge.source);
|
|
2241
|
+
if (source && outputFieldsFor(source).some((field) => field?.path === handle)) {
|
|
2242
|
+
message += ` Note: "${handle}" is a FIELD this node emits, not a port \u2014 read it downstream as {{ in.${handle} }} rather than naming it as a source handle.`;
|
|
2243
|
+
}
|
|
2244
|
+
if (edge.sourceHandle != null) message += " Leave sourceHandle off to read the node's output.";
|
|
2245
|
+
return message;
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2191
2248
|
// src/runtime/workflow-props.ts
|
|
2192
2249
|
function typeOf(value) {
|
|
2193
2250
|
if (value === null) return "null";
|
|
@@ -2246,7 +2303,7 @@ function resolveWorkflowProps(declared, passed) {
|
|
|
2246
2303
|
// src/runtime/run-flow.ts
|
|
2247
2304
|
async function runFlow(graph, executors, onEvent = () => {
|
|
2248
2305
|
}, options = {}) {
|
|
2249
|
-
const { signal, initialInputs = {}, timeoutMs, depth = 0, resumeOutputs = {}, entryNodes } = options;
|
|
2306
|
+
const { signal, initialInputs = {}, timeoutMs, depth = 0, resumeOutputs = {}, entryNodes, nodeExecutors } = options;
|
|
2250
2307
|
const run = options.run === void 0 ? void 0 : RunIdentity.from(options.run);
|
|
2251
2308
|
const outputs = {};
|
|
2252
2309
|
const portValues = /* @__PURE__ */ new Map();
|
|
@@ -2309,17 +2366,8 @@ async function runFlow(graph, executors, onEvent = () => {
|
|
|
2309
2366
|
onEvent({ type: "node-status", nodeId: node.id, status: "idle", text: "skipped" });
|
|
2310
2367
|
continue;
|
|
2311
2368
|
}
|
|
2312
|
-
for (const
|
|
2313
|
-
|
|
2314
|
-
if (portValues.has(`${e.source}:${handle}`) || !completed.has(e.source)) continue;
|
|
2315
|
-
if (possiblePortIds(nodesById.get(e.source)).includes(handle)) continue;
|
|
2316
|
-
onEvent({
|
|
2317
|
-
type: "log",
|
|
2318
|
-
nodeId: node.id,
|
|
2319
|
-
level: "warn",
|
|
2320
|
-
message: undeliveredEdgeMessage(e, node, portValues, nodesById),
|
|
2321
|
-
detail: { edge: e.id, source: e.source, sourceHandle: handle }
|
|
2322
|
-
});
|
|
2369
|
+
for (const warning of undeliveredEdgeWarnings(node, incoming, portValues, completed, nodesById)) {
|
|
2370
|
+
onEvent(warning);
|
|
2323
2371
|
}
|
|
2324
2372
|
if (incoming.length > 0) {
|
|
2325
2373
|
const anyActive = incoming.some((e) => portValues.has(`${e.source}:${e.sourceHandle ?? "out"}`));
|
|
@@ -2343,7 +2391,7 @@ async function runFlow(graph, executors, onEvent = () => {
|
|
|
2343
2391
|
onEvent({ type: "node-status", nodeId: node.id, status: "running" });
|
|
2344
2392
|
announce(onEvent, node, "start");
|
|
2345
2393
|
const inputs = collectInputs(node, incoming, portValues, initialInputs, props, declaresProps);
|
|
2346
|
-
const exec = pickExecutor(executors, node);
|
|
2394
|
+
const exec = pickExecutor(executors, node, nodeExecutors);
|
|
2347
2395
|
if (!exec) {
|
|
2348
2396
|
const tried = executorLookupIds(node);
|
|
2349
2397
|
const msg = `No executor registered for kind=${node.type} \u2014 tried ${tried.map((id2) => `"${id2}"`).join(", ")}. Key your registry by one of those.`;
|
|
@@ -2463,7 +2511,9 @@ function executorLookupIds(node) {
|
|
|
2463
2511
|
ids.push("*");
|
|
2464
2512
|
return [...new Set(ids)];
|
|
2465
2513
|
}
|
|
2466
|
-
function pickExecutor(executors, node) {
|
|
2514
|
+
function pickExecutor(executors, node, nodeExecutors) {
|
|
2515
|
+
const pinned = nodeExecutors && Object.prototype.hasOwnProperty.call(nodeExecutors, node.id) ? nodeExecutors[node.id] : void 0;
|
|
2516
|
+
if (pinned) return pinned;
|
|
2467
2517
|
for (const id2 of executorLookupIds(node)) {
|
|
2468
2518
|
if (executors[id2]) return executors[id2];
|
|
2469
2519
|
}
|
|
@@ -2483,45 +2533,6 @@ function activatedPorts(node, result) {
|
|
|
2483
2533
|
const declared = resolveNodePorts(node, kind).outputs?.map((p) => p.id);
|
|
2484
2534
|
return { ports: declared?.length ? declared : ["out"], value: result };
|
|
2485
2535
|
}
|
|
2486
|
-
function possiblePortIds(node) {
|
|
2487
|
-
if (!node) return ["out"];
|
|
2488
|
-
const own = node.data?.outputs;
|
|
2489
|
-
if (Array.isArray(own)) return own.map((p) => p.id);
|
|
2490
|
-
const kind = getNodeKind(node.data?.kind ?? node.type ?? "");
|
|
2491
|
-
if (!kind) return ["out"];
|
|
2492
|
-
const config = nodeConfig(node);
|
|
2493
|
-
const representative = typeof kind.outputs === "function" && !configDeclaresPorts(kind.name, config);
|
|
2494
|
-
const ids = (resolvePortSpec(kind.outputs, representative ? defaultConfigFor(kind) : config) ?? []).map((p) => p.id);
|
|
2495
|
-
return ids.length > 0 ? ids : ["out"];
|
|
2496
|
-
}
|
|
2497
|
-
function configDeclaresPorts(kindName, config) {
|
|
2498
|
-
const bare = kindName.startsWith("@") ? kindName.slice(kindName.lastIndexOf("/") + 1) : kindName;
|
|
2499
|
-
if (bare === "switch_case") {
|
|
2500
|
-
const cases = config.cases;
|
|
2501
|
-
return !!cases && typeof cases === "object" && Object.values(cases).some((port) => typeof port === "string" && port !== "");
|
|
2502
|
-
}
|
|
2503
|
-
if (bare === "llm_router") {
|
|
2504
|
-
const routes = config.routes;
|
|
2505
|
-
return Array.isArray(routes) && routes.some((route) => route?.port != null && route.port !== "");
|
|
2506
|
-
}
|
|
2507
|
-
return true;
|
|
2508
|
-
}
|
|
2509
|
-
function undeliveredEdgeMessage(edge, target, portValues, nodesById) {
|
|
2510
|
-
const handle = edge.sourceHandle ?? "out";
|
|
2511
|
-
const prefix = `${edge.source}:`;
|
|
2512
|
-
const available = [];
|
|
2513
|
-
for (const key of portValues.keys()) {
|
|
2514
|
-
if (key.startsWith(prefix)) available.push(key.slice(prefix.length));
|
|
2515
|
-
}
|
|
2516
|
-
let message = `Edge ${edge.id} reads port "${handle}" from node ${edge.source}, which never publishes it \u2014 nothing would reach ${target.id} at run time.`;
|
|
2517
|
-
if (available.length > 0) message += ` Available: ${available.join(", ")}.`;
|
|
2518
|
-
const source = nodesById.get(edge.source);
|
|
2519
|
-
if (source && outputFieldsFor(source).some((field) => field?.path === handle)) {
|
|
2520
|
-
message += ` Note: "${handle}" is a FIELD this node emits, not a port \u2014 read it downstream as {{ in.${handle} }} rather than naming it as a source handle.`;
|
|
2521
|
-
}
|
|
2522
|
-
if (edge.sourceHandle != null) message += " Leave sourceHandle off to read the node's output.";
|
|
2523
|
-
return message;
|
|
2524
|
-
}
|
|
2525
2536
|
function announce(onEvent, node, phase) {
|
|
2526
2537
|
const data = node.data;
|
|
2527
2538
|
const raw = phase === "start" ? data?.startingMsg : data?.stoppingMsg;
|