@particle-academy/fancy-flow 0.11.0 → 0.13.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/capabilities-B6r1Snfj.d.ts +77 -0
- package/dist/capabilities-D-V9Rxv1.d.cts +77 -0
- package/dist/chunk-BB45F6S3.js +38 -0
- package/dist/chunk-BB45F6S3.js.map +1 -0
- package/dist/{chunk-2NQT2A3I.js → chunk-L4AX73Q6.js} +5 -4
- package/dist/chunk-L4AX73Q6.js.map +1 -0
- package/dist/{chunk-3GMBLHTM.js → chunk-MFMRTRPO.js} +3 -3
- package/dist/{chunk-3GMBLHTM.js.map → chunk-MFMRTRPO.js.map} +1 -1
- package/dist/{chunk-YNOI7ONN.js → chunk-WEZJFMLV.js} +224 -51
- package/dist/chunk-WEZJFMLV.js.map +1 -0
- package/dist/engine.cjs +3 -2
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.cts +4 -2
- package/dist/engine.d.ts +4 -2
- package/dist/engine.js +1 -1
- package/dist/index.cjs +396 -215
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/llm/vercel-ai.cjs +59 -0
- package/dist/llm/vercel-ai.cjs.map +1 -0
- package/dist/llm/vercel-ai.d.cts +59 -0
- package/dist/llm/vercel-ai.d.ts +59 -0
- package/dist/llm/vercel-ai.js +49 -0
- package/dist/llm/vercel-ai.js.map +1 -0
- package/dist/registry/index.d.cts +60 -4
- package/dist/registry/index.d.ts +60 -4
- package/dist/registry.cjs +455 -93
- package/dist/registry.cjs.map +1 -1
- package/dist/registry.js +3 -1
- package/dist/runtime/index.d.cts +1 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime.cjs +3 -2
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +2 -2
- package/dist/schema/index.d.cts +1 -1
- package/dist/schema/index.d.ts +1 -1
- package/dist/{types-CsEe3EQl.d.ts → types-CnnKPnpt.d.ts} +1 -1
- package/dist/{types-BwLr5tZV.d.cts → types-H60tQAxr.d.cts} +1 -1
- package/dist/{types-BS3Gwnkq.d.cts → types-fc0fFKkf.d.cts} +7 -1
- package/dist/{types-BS3Gwnkq.d.ts → types-fc0fFKkf.d.ts} +7 -1
- package/dist/ux.d.cts +2 -2
- package/dist/ux.d.ts +2 -2
- package/package.json +19 -3
- package/dist/chunk-2NQT2A3I.js.map +0 -1
- package/dist/chunk-YNOI7ONN.js.map +0 -1
package/dist/registry.cjs
CHANGED
|
@@ -30,60 +30,46 @@ function resolveNodePorts(node, kind) {
|
|
|
30
30
|
outputs: data?.outputs ?? resolvePortSpec(kind?.outputs, config)
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
|
|
34
|
+
// src/registry/capabilities.ts
|
|
35
|
+
var llmClient = null;
|
|
36
|
+
function registerLlmClient(client) {
|
|
37
|
+
llmClient = client;
|
|
38
38
|
return () => {
|
|
39
|
-
if (
|
|
40
|
-
adapter = null;
|
|
41
|
-
for (const l of listeners) l();
|
|
42
|
-
}
|
|
39
|
+
if (llmClient === client) llmClient = null;
|
|
43
40
|
};
|
|
44
41
|
}
|
|
45
|
-
function
|
|
46
|
-
return
|
|
42
|
+
function getLlmClient() {
|
|
43
|
+
return llmClient;
|
|
47
44
|
}
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
var workflowResolver = null;
|
|
46
|
+
function registerWorkflowResolver(resolver) {
|
|
47
|
+
workflowResolver = resolver;
|
|
48
|
+
return () => {
|
|
49
|
+
if (workflowResolver === resolver) workflowResolver = null;
|
|
50
|
+
};
|
|
50
51
|
}
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
return () => listeners.delete(fn);
|
|
52
|
+
function getWorkflowResolver() {
|
|
53
|
+
return workflowResolver;
|
|
54
54
|
}
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ff-rich-preview__title", children: title }),
|
|
62
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ff-rich-preview__unavailable", children: [
|
|
63
|
-
"Add ",
|
|
64
|
-
/* @__PURE__ */ jsxRuntime.jsx("code", { children: "@particle-academy/fancy-cms-ui" }),
|
|
65
|
-
" +",
|
|
66
|
-
" ",
|
|
67
|
-
/* @__PURE__ */ jsxRuntime.jsx("code", { children: "@particle-academy/react-fancy" }),
|
|
68
|
-
", then",
|
|
69
|
-
" ",
|
|
70
|
-
/* @__PURE__ */ jsxRuntime.jsx("code", { children: 'import "@particle-academy/fancy-flow/rich-input"' }),
|
|
71
|
-
"."
|
|
72
|
-
] })
|
|
73
|
-
] });
|
|
55
|
+
function capabilityStatus() {
|
|
56
|
+
let documentReady = false;
|
|
57
|
+
try {
|
|
58
|
+
documentReady = Boolean(globalThis.__fancyFlowDocumentAdapter);
|
|
59
|
+
} catch {
|
|
60
|
+
documentReady = false;
|
|
74
61
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
] });
|
|
62
|
+
return {
|
|
63
|
+
llm: llmClient !== null,
|
|
64
|
+
workflow_resolver: workflowResolver !== null,
|
|
65
|
+
document: documentReady
|
|
66
|
+
};
|
|
81
67
|
}
|
|
82
68
|
|
|
83
69
|
// src/registry/registry.ts
|
|
84
70
|
var kinds = /* @__PURE__ */ new Map();
|
|
85
71
|
var aliases = /* @__PURE__ */ new Map();
|
|
86
|
-
var
|
|
72
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
87
73
|
function registerNodeKind(definition) {
|
|
88
74
|
kinds.set(definition.name, definition);
|
|
89
75
|
for (const alias of definition.aliases ?? []) aliases.set(alias, definition.name);
|
|
@@ -115,11 +101,11 @@ function listNodeKinds(category) {
|
|
|
115
101
|
return category ? all.filter((k) => k.category === category) : all;
|
|
116
102
|
}
|
|
117
103
|
function onNodeKindsChanged(listener) {
|
|
118
|
-
|
|
119
|
-
return () =>
|
|
104
|
+
listeners.add(listener);
|
|
105
|
+
return () => listeners.delete(listener);
|
|
120
106
|
}
|
|
121
107
|
function notify() {
|
|
122
|
-
for (const l of
|
|
108
|
+
for (const l of listeners) l();
|
|
123
109
|
}
|
|
124
110
|
function defaultConfigFor(kind) {
|
|
125
111
|
const fromKind = kind.defaultConfig ? { ...kind.defaultConfig } : {};
|
|
@@ -233,6 +219,315 @@ function categoryAccent(category) {
|
|
|
233
219
|
}
|
|
234
220
|
}
|
|
235
221
|
|
|
222
|
+
// src/runtime/run-flow.ts
|
|
223
|
+
async function runFlow(graph, executors, onEvent = () => {
|
|
224
|
+
}, options = {}) {
|
|
225
|
+
const { signal, initialInputs = {}, timeoutMs, depth = 0 } = options;
|
|
226
|
+
const outputs = {};
|
|
227
|
+
const portValues = /* @__PURE__ */ new Map();
|
|
228
|
+
const completed = /* @__PURE__ */ new Set();
|
|
229
|
+
const errors = [];
|
|
230
|
+
const order = topoSort(graph);
|
|
231
|
+
if (order === null) {
|
|
232
|
+
const msg = "Cycle detected in flow graph \u2014 aborting.";
|
|
233
|
+
onEvent({ type: "run-error", error: msg });
|
|
234
|
+
return { ok: false, outputs, error: msg };
|
|
235
|
+
}
|
|
236
|
+
const incomingByNode = indexIncoming(graph.edges);
|
|
237
|
+
const timer2 = timeoutMs ? setTimeout(() => errors.push(`Run timed out after ${timeoutMs}ms`), timeoutMs) : null;
|
|
238
|
+
onEvent({ type: "run-start" });
|
|
239
|
+
try {
|
|
240
|
+
for (const node of order) {
|
|
241
|
+
if (signal?.aborted) throw new Error("aborted");
|
|
242
|
+
if (errors.length) break;
|
|
243
|
+
const incoming = incomingByNode.get(node.id) ?? [];
|
|
244
|
+
if (incoming.length > 0) {
|
|
245
|
+
const anyActive = incoming.some((e) => portValues.has(`${e.source}:${e.sourceHandle ?? "out"}`));
|
|
246
|
+
if (!anyActive) {
|
|
247
|
+
onEvent({ type: "node-status", nodeId: node.id, status: "idle", text: "skipped" });
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (node.type === "note") {
|
|
252
|
+
onEvent({ type: "node-status", nodeId: node.id, status: "idle", text: "annotation" });
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
onEvent({ type: "node-status", nodeId: node.id, status: "running" });
|
|
256
|
+
const inputs = collectInputs(node, incoming, portValues, initialInputs);
|
|
257
|
+
const exec = pickExecutor(executors, node);
|
|
258
|
+
if (!exec) {
|
|
259
|
+
const msg = `No executor registered for kind=${node.type}`;
|
|
260
|
+
errors.push(msg);
|
|
261
|
+
onEvent({ type: "node-status", nodeId: node.id, status: "error", text: msg });
|
|
262
|
+
onEvent({ type: "log", nodeId: node.id, level: "error", message: msg });
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
const result = await Promise.resolve(
|
|
267
|
+
exec({
|
|
268
|
+
node,
|
|
269
|
+
inputs,
|
|
270
|
+
abort: (reason) => {
|
|
271
|
+
throw new Error(reason ?? "aborted");
|
|
272
|
+
},
|
|
273
|
+
emit: onEvent,
|
|
274
|
+
depth
|
|
275
|
+
})
|
|
276
|
+
);
|
|
277
|
+
outputs[node.id] = result;
|
|
278
|
+
const activated = activatedPorts(node, result);
|
|
279
|
+
for (const portId of activated.ports) {
|
|
280
|
+
portValues.set(`${node.id}:${portId}`, activated.value);
|
|
281
|
+
onEvent({ type: "node-output", nodeId: node.id, portId, value: activated.value });
|
|
282
|
+
}
|
|
283
|
+
completed.add(node.id);
|
|
284
|
+
onEvent({ type: "node-status", nodeId: node.id, status: "done" });
|
|
285
|
+
} catch (e) {
|
|
286
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
287
|
+
errors.push(msg);
|
|
288
|
+
onEvent({ type: "node-status", nodeId: node.id, status: "error", text: msg });
|
|
289
|
+
onEvent({ type: "log", nodeId: node.id, level: "error", message: msg });
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
} finally {
|
|
294
|
+
if (timer2) clearTimeout(timer2);
|
|
295
|
+
}
|
|
296
|
+
const ok = errors.length === 0;
|
|
297
|
+
onEvent({ type: "run-end", ok });
|
|
298
|
+
return ok ? { ok, outputs } : { ok, outputs, error: errors[0] };
|
|
299
|
+
}
|
|
300
|
+
function indexIncoming(edges) {
|
|
301
|
+
const map = /* @__PURE__ */ new Map();
|
|
302
|
+
for (const e of edges) {
|
|
303
|
+
const list = map.get(e.target) ?? [];
|
|
304
|
+
list.push(e);
|
|
305
|
+
map.set(e.target, list);
|
|
306
|
+
}
|
|
307
|
+
return map;
|
|
308
|
+
}
|
|
309
|
+
function topoSort(graph) {
|
|
310
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
311
|
+
for (const n of graph.nodes) inDegree.set(n.id, 0);
|
|
312
|
+
for (const e of graph.edges) inDegree.set(e.target, (inDegree.get(e.target) ?? 0) + 1);
|
|
313
|
+
const queue = [];
|
|
314
|
+
for (const [id2, d] of inDegree) if (d === 0) queue.push(id2);
|
|
315
|
+
const ordered = [];
|
|
316
|
+
while (queue.length) {
|
|
317
|
+
const id2 = queue.shift();
|
|
318
|
+
ordered.push(id2);
|
|
319
|
+
for (const e of graph.edges) {
|
|
320
|
+
if (e.source !== id2) continue;
|
|
321
|
+
const next = (inDegree.get(e.target) ?? 0) - 1;
|
|
322
|
+
inDegree.set(e.target, next);
|
|
323
|
+
if (next === 0) queue.push(e.target);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (ordered.length !== graph.nodes.length) return null;
|
|
327
|
+
const byId = new Map(graph.nodes.map((n) => [n.id, n]));
|
|
328
|
+
return ordered.map((id2) => byId.get(id2)).filter(Boolean);
|
|
329
|
+
}
|
|
330
|
+
function collectInputs(node, incoming, portValues, initial) {
|
|
331
|
+
const inputs = { ...initial[node.id] ?? {} };
|
|
332
|
+
for (const e of incoming) {
|
|
333
|
+
const portId = e.targetHandle ?? "in";
|
|
334
|
+
const val = portValues.get(`${e.source}:${e.sourceHandle ?? "out"}`);
|
|
335
|
+
inputs[portId] = val;
|
|
336
|
+
}
|
|
337
|
+
return inputs;
|
|
338
|
+
}
|
|
339
|
+
function pickExecutor(executors, node) {
|
|
340
|
+
if (executors[node.id]) return executors[node.id];
|
|
341
|
+
if (node.type && executors[node.type]) return executors[node.type];
|
|
342
|
+
const kind = node.type ? getNodeKind(node.type) : null;
|
|
343
|
+
if (kind) {
|
|
344
|
+
for (const id2 of kindIds(kind)) {
|
|
345
|
+
if (executors[id2]) return executors[id2];
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return executors["*"];
|
|
349
|
+
}
|
|
350
|
+
function activatedPorts(node, result) {
|
|
351
|
+
if (result && typeof result === "object") {
|
|
352
|
+
const r = result;
|
|
353
|
+
if (typeof r.__port === "string") {
|
|
354
|
+
return { ports: [r.__port], value: r.value };
|
|
355
|
+
}
|
|
356
|
+
if (typeof r.branch === "string") {
|
|
357
|
+
return { ports: [r.branch], value: r.value ?? r };
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
const kind = getNodeKind(node.data?.kind ?? node.type ?? "") ?? void 0;
|
|
361
|
+
const declared = resolveNodePorts(node, kind).outputs?.map((p) => p.id);
|
|
362
|
+
return { ports: declared?.length ? declared : ["out"], value: result };
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// src/registry/subflow.ts
|
|
366
|
+
var DEFAULT_MAX_DEPTH = 8;
|
|
367
|
+
function subflowMode(config) {
|
|
368
|
+
const mode = config.mode;
|
|
369
|
+
return mode === "stream" || mode === "both" ? mode : "output";
|
|
370
|
+
}
|
|
371
|
+
function subflowPorts(config) {
|
|
372
|
+
const mode = subflowMode(config);
|
|
373
|
+
const ports = [{ id: "out", label: "result" }];
|
|
374
|
+
if (mode === "stream" || mode === "both") ports.unshift({ id: "stream", label: "stream" });
|
|
375
|
+
return ports;
|
|
376
|
+
}
|
|
377
|
+
var subflowExecutor = async (ctx) => {
|
|
378
|
+
const config = ctx.node.data?.config ?? {};
|
|
379
|
+
const ref = String(config.workflow ?? "").trim();
|
|
380
|
+
if (!ref) ctx.abort("subflow has no workflow reference configured");
|
|
381
|
+
const resolver = getWorkflowResolver();
|
|
382
|
+
if (!resolver) {
|
|
383
|
+
ctx.abort(
|
|
384
|
+
"No workflow resolver registered. Call registerWorkflowResolver() so subflow can find the workflow it references."
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
const maxDepth = Number.isFinite(config.maxDepth) ? Number(config.maxDepth) : DEFAULT_MAX_DEPTH;
|
|
388
|
+
const depth = ctx.depth ?? 0;
|
|
389
|
+
if (depth + 1 > maxDepth) {
|
|
390
|
+
ctx.abort(
|
|
391
|
+
`subflow depth limit reached (${maxDepth}) at "${ref}" \u2014 a workflow is referencing itself, directly or through a chain.`
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
const child = await resolver(ref);
|
|
395
|
+
if (!child) ctx.abort(`subflow could not resolve workflow "${ref}"`);
|
|
396
|
+
const mode = subflowMode(config);
|
|
397
|
+
const streaming = mode === "stream" || mode === "both";
|
|
398
|
+
const forward = (event) => {
|
|
399
|
+
if (!streaming) return;
|
|
400
|
+
const detail = event.type === "node-status" ? `${event.nodeId} ${event.status}` : event.type === "run-end" ? `finished (${event.ok ? "ok" : "failed"})` : event.type;
|
|
401
|
+
ctx.emit({
|
|
402
|
+
type: "log",
|
|
403
|
+
nodeId: ctx.node.id,
|
|
404
|
+
level: "info",
|
|
405
|
+
message: `[${ref}] ${detail}`
|
|
406
|
+
});
|
|
407
|
+
};
|
|
408
|
+
const result = await runFlow(
|
|
409
|
+
child,
|
|
410
|
+
config.executors ?? {},
|
|
411
|
+
forward,
|
|
412
|
+
{
|
|
413
|
+
initialInputs: config.inputs ?? {
|
|
414
|
+
// With no explicit mapping, hand the parent's inputs to the child's
|
|
415
|
+
// entry points — the obvious default, and it makes the simple case
|
|
416
|
+
// require no configuration at all.
|
|
417
|
+
__parent: ctx.inputs
|
|
418
|
+
},
|
|
419
|
+
depth: depth + 1
|
|
420
|
+
}
|
|
421
|
+
);
|
|
422
|
+
if (!result.ok) {
|
|
423
|
+
ctx.abort(`subflow "${ref}" failed: ${result.error ?? "unknown error"}`);
|
|
424
|
+
}
|
|
425
|
+
if (mode === "stream") {
|
|
426
|
+
return { __port: "stream", value: result.outputs };
|
|
427
|
+
}
|
|
428
|
+
if (mode === "both") {
|
|
429
|
+
return result.outputs;
|
|
430
|
+
}
|
|
431
|
+
return { __port: "out", value: result.outputs };
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
// src/registry/llm-branch.ts
|
|
435
|
+
function declaredRoutes(config) {
|
|
436
|
+
const raw = config.routes;
|
|
437
|
+
if (!Array.isArray(raw)) return [];
|
|
438
|
+
return raw.map((r) => ({ port: String(r?.port ?? "").trim(), description: r?.description })).filter((r) => r.port !== "");
|
|
439
|
+
}
|
|
440
|
+
function resolveFallbackPort(routes, fallbackEnabled) {
|
|
441
|
+
if (fallbackEnabled) return "fallback";
|
|
442
|
+
return routes[0]?.port ?? "out";
|
|
443
|
+
}
|
|
444
|
+
var llmBranchExecutor = async (ctx) => {
|
|
445
|
+
const config = ctx.node.data?.config ?? {};
|
|
446
|
+
const routes = declaredRoutes(config);
|
|
447
|
+
if (routes.length === 0) {
|
|
448
|
+
ctx.abort("llm_branch has no routes configured");
|
|
449
|
+
}
|
|
450
|
+
const client = getLlmClient();
|
|
451
|
+
if (!client) {
|
|
452
|
+
ctx.abort(
|
|
453
|
+
"No LLM client registered. Call registerLlmClient() with your provider adapter \u2014 fancy-flow ships the routing, not the model call."
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
const fallbackEnabled = config.fallback !== false;
|
|
457
|
+
const choice = await client.chooseRoute({
|
|
458
|
+
system: typeof config.system === "string" ? config.system : void 0,
|
|
459
|
+
prompt: String(config.prompt ?? ctx.inputs ?? ""),
|
|
460
|
+
routes,
|
|
461
|
+
provider: typeof config.provider === "string" ? config.provider : void 0,
|
|
462
|
+
model: typeof config.model === "string" ? config.model : void 0,
|
|
463
|
+
credential: typeof config.credential === "string" ? config.credential : void 0
|
|
464
|
+
});
|
|
465
|
+
const offered = new Set(routes.map((r) => r.port));
|
|
466
|
+
let port = choice?.port ?? "";
|
|
467
|
+
let reason = choice?.reason;
|
|
468
|
+
if (!offered.has(port)) {
|
|
469
|
+
const safe = resolveFallbackPort(routes, fallbackEnabled);
|
|
470
|
+
ctx.emit({
|
|
471
|
+
type: "log",
|
|
472
|
+
nodeId: ctx.node.id,
|
|
473
|
+
level: "warn",
|
|
474
|
+
message: `llm_branch: model returned "${port || "(nothing)"}", which is not a declared route. Routing to "${safe}".`
|
|
475
|
+
});
|
|
476
|
+
reason = reason ?? `unrecognised route "${port}"`;
|
|
477
|
+
port = safe;
|
|
478
|
+
}
|
|
479
|
+
return { __port: port, value: { route: port, reason, input: ctx.inputs } };
|
|
480
|
+
};
|
|
481
|
+
var adapter = null;
|
|
482
|
+
var listeners2 = /* @__PURE__ */ new Set();
|
|
483
|
+
function registerRichInputAdapter(next) {
|
|
484
|
+
adapter = next;
|
|
485
|
+
for (const l of listeners2) l();
|
|
486
|
+
return () => {
|
|
487
|
+
if (adapter === next) {
|
|
488
|
+
adapter = null;
|
|
489
|
+
for (const l of listeners2) l();
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
function getRichInputAdapter() {
|
|
494
|
+
return adapter;
|
|
495
|
+
}
|
|
496
|
+
function isRichInputEnabled() {
|
|
497
|
+
return adapter !== null && (adapter.renderDocument !== void 0 || adapter.renderEditor !== void 0);
|
|
498
|
+
}
|
|
499
|
+
function onRichInputAdapterChanged(fn) {
|
|
500
|
+
listeners2.add(fn);
|
|
501
|
+
return () => listeners2.delete(fn);
|
|
502
|
+
}
|
|
503
|
+
function RichInputPreview({ config }) {
|
|
504
|
+
const a = getRichInputAdapter();
|
|
505
|
+
const title = typeof config.title === "string" && config.title.trim() !== "" ? config.title : "Untitled step";
|
|
506
|
+
const doc = config.document;
|
|
507
|
+
if (!a || !a.renderDocument && !a.renderEditor) {
|
|
508
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ff-rich-preview", children: [
|
|
509
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ff-rich-preview__title", children: title }),
|
|
510
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ff-rich-preview__unavailable", children: [
|
|
511
|
+
"Add ",
|
|
512
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { children: "@particle-academy/fancy-cms-ui" }),
|
|
513
|
+
" +",
|
|
514
|
+
" ",
|
|
515
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { children: "@particle-academy/react-fancy" }),
|
|
516
|
+
", then",
|
|
517
|
+
" ",
|
|
518
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { children: 'import "@particle-academy/fancy-flow/rich-input"' }),
|
|
519
|
+
"."
|
|
520
|
+
] })
|
|
521
|
+
] });
|
|
522
|
+
}
|
|
523
|
+
const body = doc === void 0 || doc === null ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "ff-rich-preview__unavailable", children: "Nothing authored yet." }) : a.renderDocument?.(doc) ?? null;
|
|
524
|
+
const Frame = a.FauxClient;
|
|
525
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ff-rich-preview", children: [
|
|
526
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ff-rich-preview__title", children: title }),
|
|
527
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "ff-rich-preview__frame", children: Frame ? /* @__PURE__ */ jsxRuntime.jsx(Frame, { ...a.frameProps ?? { variant: "browser" }, children: body }) : body })
|
|
528
|
+
] });
|
|
529
|
+
}
|
|
530
|
+
|
|
236
531
|
// node_modules/classcat/index.js
|
|
237
532
|
function cc(names) {
|
|
238
533
|
if (typeof names === "string" || typeof names === "number") return "" + names;
|
|
@@ -9290,8 +9585,8 @@ var HTTP_METHODS = [
|
|
|
9290
9585
|
var KINDS = [
|
|
9291
9586
|
// ───────────── Triggers ─────────────
|
|
9292
9587
|
{
|
|
9293
|
-
name: "@
|
|
9294
|
-
aliases: ["manual_trigger"],
|
|
9588
|
+
name: "@particle-academy/manual_trigger",
|
|
9589
|
+
aliases: ["manual_trigger", "@fancy/manual_trigger"],
|
|
9295
9590
|
category: "trigger",
|
|
9296
9591
|
label: "Manual",
|
|
9297
9592
|
description: "Entry point fired when the user clicks Run.",
|
|
@@ -9300,8 +9595,8 @@ var KINDS = [
|
|
|
9300
9595
|
outputs: [{ id: "out" }]
|
|
9301
9596
|
},
|
|
9302
9597
|
{
|
|
9303
|
-
name: "@
|
|
9304
|
-
aliases: ["webhook_trigger"],
|
|
9598
|
+
name: "@particle-academy/webhook_trigger",
|
|
9599
|
+
aliases: ["webhook_trigger", "@fancy/webhook_trigger"],
|
|
9305
9600
|
category: "trigger",
|
|
9306
9601
|
label: "Webhook",
|
|
9307
9602
|
description: "Triggered by an inbound HTTP request to a host-provided URL.",
|
|
@@ -9318,8 +9613,8 @@ var KINDS = [
|
|
|
9318
9613
|
]
|
|
9319
9614
|
},
|
|
9320
9615
|
{
|
|
9321
|
-
name: "@
|
|
9322
|
-
aliases: ["schedule_trigger"],
|
|
9616
|
+
name: "@particle-academy/schedule_trigger",
|
|
9617
|
+
aliases: ["schedule_trigger", "@fancy/schedule_trigger"],
|
|
9323
9618
|
category: "trigger",
|
|
9324
9619
|
label: "Schedule",
|
|
9325
9620
|
description: "Fires on a cron schedule (host-implemented).",
|
|
@@ -9339,8 +9634,8 @@ var KINDS = [
|
|
|
9339
9634
|
]
|
|
9340
9635
|
},
|
|
9341
9636
|
{
|
|
9342
|
-
name: "@
|
|
9343
|
-
aliases: ["user_input"],
|
|
9637
|
+
name: "@particle-academy/user_input",
|
|
9638
|
+
aliases: ["user_input", "@fancy/user_input"],
|
|
9344
9639
|
category: "human",
|
|
9345
9640
|
label: "User Input",
|
|
9346
9641
|
description: "Pause the flow until the user submits the configured form.",
|
|
@@ -9380,8 +9675,8 @@ var KINDS = [
|
|
|
9380
9675
|
]
|
|
9381
9676
|
},
|
|
9382
9677
|
{
|
|
9383
|
-
name: "@
|
|
9384
|
-
aliases: ["rich_user_input"],
|
|
9678
|
+
name: "@particle-academy/rich_user_input",
|
|
9679
|
+
aliases: ["rich_user_input", "@fancy/rich_user_input"],
|
|
9385
9680
|
category: "human",
|
|
9386
9681
|
label: "Rich User Input",
|
|
9387
9682
|
description: "Pause the flow on a fully authored page \u2014 content, required reading, multi-section forms.",
|
|
@@ -9404,10 +9699,61 @@ var KINDS = [
|
|
|
9404
9699
|
// what the person hitting this step will actually see.
|
|
9405
9700
|
renderBody: (ctx) => ReactExports.createElement(RichInputPreview, { config: ctx.config ?? {} })
|
|
9406
9701
|
},
|
|
9702
|
+
{
|
|
9703
|
+
name: "@particle-academy/subflow",
|
|
9704
|
+
aliases: ["subflow", "@fancy/subflow"],
|
|
9705
|
+
category: "logic",
|
|
9706
|
+
label: "SubFlow",
|
|
9707
|
+
description: "Run another workflow and bring its result \u2014 or its live progress \u2014 back into this one.",
|
|
9708
|
+
icon: "\u29C9",
|
|
9709
|
+
inputs: [{ id: "in" }],
|
|
9710
|
+
// The stream port only exists when something actually streams.
|
|
9711
|
+
outputs: (config) => subflowPorts(config ?? {}),
|
|
9712
|
+
// Core, not marketplace: it runs a child graph through this same engine and
|
|
9713
|
+
// needs nothing from outside except where workflows live.
|
|
9714
|
+
executor: subflowExecutor,
|
|
9715
|
+
configSchema: [
|
|
9716
|
+
{
|
|
9717
|
+
type: "text",
|
|
9718
|
+
key: "workflow",
|
|
9719
|
+
label: "Workflow",
|
|
9720
|
+
required: true,
|
|
9721
|
+
placeholder: "onboarding-v2",
|
|
9722
|
+
description: "Reference resolved by the host's registerWorkflowResolver()."
|
|
9723
|
+
},
|
|
9724
|
+
{
|
|
9725
|
+
type: "select",
|
|
9726
|
+
key: "mode",
|
|
9727
|
+
label: "Return",
|
|
9728
|
+
default: "output",
|
|
9729
|
+
options: [
|
|
9730
|
+
{ value: "output", label: "Output when it finishes" },
|
|
9731
|
+
{ value: "stream", label: "Stream progress as it runs" },
|
|
9732
|
+
{ value: "both", label: "Both \u2014 stream, then output" }
|
|
9733
|
+
],
|
|
9734
|
+
description: "Streaming adds a second port so a parent can show progress instead of a spinner."
|
|
9735
|
+
},
|
|
9736
|
+
{
|
|
9737
|
+
type: "json",
|
|
9738
|
+
key: "inputs",
|
|
9739
|
+
label: "Input mapping",
|
|
9740
|
+
description: "Entry-point inputs for the child run. Omit to pass this node's inputs straight through."
|
|
9741
|
+
},
|
|
9742
|
+
{
|
|
9743
|
+
type: "number",
|
|
9744
|
+
key: "maxDepth",
|
|
9745
|
+
label: "Max nesting depth",
|
|
9746
|
+
default: DEFAULT_MAX_DEPTH,
|
|
9747
|
+
min: 1,
|
|
9748
|
+
max: 32,
|
|
9749
|
+
description: "Guards against a workflow referencing itself."
|
|
9750
|
+
}
|
|
9751
|
+
]
|
|
9752
|
+
},
|
|
9407
9753
|
// ───────────── Logic ─────────────
|
|
9408
9754
|
{
|
|
9409
|
-
name: "@
|
|
9410
|
-
aliases: ["branch"],
|
|
9755
|
+
name: "@particle-academy/branch",
|
|
9756
|
+
aliases: ["branch", "@fancy/branch"],
|
|
9411
9757
|
category: "logic",
|
|
9412
9758
|
label: "Branch",
|
|
9413
9759
|
description: "Multi-way branch on a condition or value.",
|
|
@@ -9419,8 +9765,8 @@ var KINDS = [
|
|
|
9419
9765
|
]
|
|
9420
9766
|
},
|
|
9421
9767
|
{
|
|
9422
|
-
name: "@
|
|
9423
|
-
aliases: ["switch_case"],
|
|
9768
|
+
name: "@particle-academy/switch_case",
|
|
9769
|
+
aliases: ["switch_case", "@fancy/switch_case"],
|
|
9424
9770
|
category: "logic",
|
|
9425
9771
|
label: "Switch",
|
|
9426
9772
|
description: "Route to one of N labelled outputs based on a key.",
|
|
@@ -9447,8 +9793,8 @@ var KINDS = [
|
|
|
9447
9793
|
]
|
|
9448
9794
|
},
|
|
9449
9795
|
{
|
|
9450
|
-
name: "@
|
|
9451
|
-
aliases: ["for_each"],
|
|
9796
|
+
name: "@particle-academy/for_each",
|
|
9797
|
+
aliases: ["for_each", "@fancy/for_each"],
|
|
9452
9798
|
category: "logic",
|
|
9453
9799
|
label: "For Each",
|
|
9454
9800
|
description: "Iterate over a list, emitting each item on `item`.",
|
|
@@ -9461,8 +9807,8 @@ var KINDS = [
|
|
|
9461
9807
|
]
|
|
9462
9808
|
},
|
|
9463
9809
|
{
|
|
9464
|
-
name: "@
|
|
9465
|
-
aliases: ["merge"],
|
|
9810
|
+
name: "@particle-academy/merge",
|
|
9811
|
+
aliases: ["merge", "@fancy/merge"],
|
|
9466
9812
|
category: "logic",
|
|
9467
9813
|
label: "Merge",
|
|
9468
9814
|
description: "Combine multiple inputs into one object or array.",
|
|
@@ -9480,8 +9826,8 @@ var KINDS = [
|
|
|
9480
9826
|
]
|
|
9481
9827
|
},
|
|
9482
9828
|
{
|
|
9483
|
-
name: "@
|
|
9484
|
-
aliases: ["wait"],
|
|
9829
|
+
name: "@particle-academy/wait",
|
|
9830
|
+
aliases: ["wait", "@fancy/wait"],
|
|
9485
9831
|
category: "logic",
|
|
9486
9832
|
label: "Wait",
|
|
9487
9833
|
description: "Sleep or wait for an external event.",
|
|
@@ -9498,8 +9844,8 @@ var KINDS = [
|
|
|
9498
9844
|
]
|
|
9499
9845
|
},
|
|
9500
9846
|
{
|
|
9501
|
-
name: "@
|
|
9502
|
-
aliases: ["transform"],
|
|
9847
|
+
name: "@particle-academy/transform",
|
|
9848
|
+
aliases: ["transform", "@fancy/transform"],
|
|
9503
9849
|
category: "logic",
|
|
9504
9850
|
label: "Transform",
|
|
9505
9851
|
description: "Reshape data with an expression.",
|
|
@@ -9516,8 +9862,8 @@ var KINDS = [
|
|
|
9516
9862
|
},
|
|
9517
9863
|
// ───────────── Data ─────────────
|
|
9518
9864
|
{
|
|
9519
|
-
name: "@
|
|
9520
|
-
aliases: ["memory_store"],
|
|
9865
|
+
name: "@particle-academy/memory_store",
|
|
9866
|
+
aliases: ["memory_store", "@fancy/memory_store"],
|
|
9521
9867
|
category: "data",
|
|
9522
9868
|
label: "Memory Store",
|
|
9523
9869
|
description: "Read or write per-conversation memory.",
|
|
@@ -9537,8 +9883,8 @@ var KINDS = [
|
|
|
9537
9883
|
]
|
|
9538
9884
|
},
|
|
9539
9885
|
{
|
|
9540
|
-
name: "@
|
|
9541
|
-
aliases: ["data_store"],
|
|
9886
|
+
name: "@particle-academy/data_store",
|
|
9887
|
+
aliases: ["data_store", "@fancy/data_store"],
|
|
9542
9888
|
category: "data",
|
|
9543
9889
|
label: "Data Store",
|
|
9544
9890
|
description: "Key-value or table read/write against a host store.",
|
|
@@ -9566,8 +9912,8 @@ var KINDS = [
|
|
|
9566
9912
|
]
|
|
9567
9913
|
},
|
|
9568
9914
|
{
|
|
9569
|
-
name: "@
|
|
9570
|
-
aliases: ["variable"],
|
|
9915
|
+
name: "@particle-academy/variable",
|
|
9916
|
+
aliases: ["variable", "@fancy/variable"],
|
|
9571
9917
|
category: "data",
|
|
9572
9918
|
label: "Variable",
|
|
9573
9919
|
description: "Workflow-scoped value used by other nodes.",
|
|
@@ -9579,8 +9925,8 @@ var KINDS = [
|
|
|
9579
9925
|
},
|
|
9580
9926
|
// ───────────── AI ─────────────
|
|
9581
9927
|
{
|
|
9582
|
-
name: "@
|
|
9583
|
-
aliases: ["llm_call"],
|
|
9928
|
+
name: "@particle-academy/llm_call",
|
|
9929
|
+
aliases: ["llm_call", "@fancy/llm_call"],
|
|
9584
9930
|
category: "ai",
|
|
9585
9931
|
label: "LLM Call",
|
|
9586
9932
|
description: "Send a prompt + context to a model and receive a response.",
|
|
@@ -9607,8 +9953,8 @@ var KINDS = [
|
|
|
9607
9953
|
]
|
|
9608
9954
|
},
|
|
9609
9955
|
{
|
|
9610
|
-
name: "@
|
|
9611
|
-
aliases: ["llm_branch"],
|
|
9956
|
+
name: "@particle-academy/llm_branch",
|
|
9957
|
+
aliases: ["llm_branch", "@fancy/llm_branch"],
|
|
9612
9958
|
category: "ai",
|
|
9613
9959
|
label: "LLM Router",
|
|
9614
9960
|
description: "Let a model choose which route the flow takes.",
|
|
@@ -9617,6 +9963,10 @@ var KINDS = [
|
|
|
9617
9963
|
// Each declared route is a port. The executor returns `{ __port: id }`
|
|
9618
9964
|
// (or `Port.only(id)` on the PHP runtime) to pick one.
|
|
9619
9965
|
outputs: (config) => routePorts(config?.routes, config?.fallback),
|
|
9966
|
+
// A shuttle, not an engine: it carries the routes out to whatever LLM
|
|
9967
|
+
// client the host registered and carries the choice back. No provider SDK
|
|
9968
|
+
// reaches core, so this stays a builtin without adding a dependency.
|
|
9969
|
+
executor: llmBranchExecutor,
|
|
9620
9970
|
configSchema: [
|
|
9621
9971
|
{
|
|
9622
9972
|
type: "textarea",
|
|
@@ -9678,8 +10028,8 @@ var KINDS = [
|
|
|
9678
10028
|
]
|
|
9679
10029
|
},
|
|
9680
10030
|
{
|
|
9681
|
-
name: "@
|
|
9682
|
-
aliases: ["tool_use"],
|
|
10031
|
+
name: "@particle-academy/tool_use",
|
|
10032
|
+
aliases: ["tool_use", "@fancy/tool_use"],
|
|
9683
10033
|
category: "ai",
|
|
9684
10034
|
label: "Tool Use",
|
|
9685
10035
|
description: "Hand control to a host-registered tool by name.",
|
|
@@ -9690,8 +10040,8 @@ var KINDS = [
|
|
|
9690
10040
|
]
|
|
9691
10041
|
},
|
|
9692
10042
|
{
|
|
9693
|
-
name: "@
|
|
9694
|
-
aliases: ["embed_search"],
|
|
10043
|
+
name: "@particle-academy/embed_search",
|
|
10044
|
+
aliases: ["embed_search", "@fancy/embed_search"],
|
|
9695
10045
|
category: "ai",
|
|
9696
10046
|
label: "Embed & Search",
|
|
9697
10047
|
description: "Embed a query and search a vector store.",
|
|
@@ -9704,8 +10054,8 @@ var KINDS = [
|
|
|
9704
10054
|
},
|
|
9705
10055
|
// ───────────── IO ─────────────
|
|
9706
10056
|
{
|
|
9707
|
-
name: "@
|
|
9708
|
-
aliases: ["api_request"],
|
|
10057
|
+
name: "@particle-academy/api_request",
|
|
10058
|
+
aliases: ["api_request", "@fancy/api_request"],
|
|
9709
10059
|
category: "io",
|
|
9710
10060
|
label: "API Request",
|
|
9711
10061
|
description: "HTTP request to any URL.",
|
|
@@ -9719,8 +10069,8 @@ var KINDS = [
|
|
|
9719
10069
|
]
|
|
9720
10070
|
},
|
|
9721
10071
|
{
|
|
9722
|
-
name: "@
|
|
9723
|
-
aliases: ["webhook_out"],
|
|
10072
|
+
name: "@particle-academy/webhook_out",
|
|
10073
|
+
aliases: ["webhook_out", "@fancy/webhook_out"],
|
|
9724
10074
|
category: "io",
|
|
9725
10075
|
label: "Send Webhook",
|
|
9726
10076
|
description: "POST a payload to a configured URL.",
|
|
@@ -9733,8 +10083,8 @@ var KINDS = [
|
|
|
9733
10083
|
},
|
|
9734
10084
|
// ───────────── Human ─────────────
|
|
9735
10085
|
{
|
|
9736
|
-
name: "@
|
|
9737
|
-
aliases: ["human_approval"],
|
|
10086
|
+
name: "@particle-academy/human_approval",
|
|
10087
|
+
aliases: ["human_approval", "@fancy/human_approval"],
|
|
9738
10088
|
category: "human",
|
|
9739
10089
|
label: "Human Approval",
|
|
9740
10090
|
description: "Pause until a human approves or denies.",
|
|
@@ -9748,8 +10098,8 @@ var KINDS = [
|
|
|
9748
10098
|
]
|
|
9749
10099
|
},
|
|
9750
10100
|
{
|
|
9751
|
-
name: "@
|
|
9752
|
-
aliases: ["notify"],
|
|
10101
|
+
name: "@particle-academy/notify",
|
|
10102
|
+
aliases: ["notify", "@fancy/notify"],
|
|
9753
10103
|
category: "human",
|
|
9754
10104
|
label: "Notify",
|
|
9755
10105
|
description: "Send a message via Slack / email / SMS / etc.",
|
|
@@ -9773,8 +10123,8 @@ var KINDS = [
|
|
|
9773
10123
|
},
|
|
9774
10124
|
// ───────────── Output ─────────────
|
|
9775
10125
|
{
|
|
9776
|
-
name: "@
|
|
9777
|
-
aliases: ["output"],
|
|
10126
|
+
name: "@particle-academy/output",
|
|
10127
|
+
aliases: ["output", "@fancy/output"],
|
|
9778
10128
|
category: "output",
|
|
9779
10129
|
label: "Output",
|
|
9780
10130
|
description: "Terminal node \u2014 captures the workflow's result.",
|
|
@@ -9783,8 +10133,8 @@ var KINDS = [
|
|
|
9783
10133
|
outputs: []
|
|
9784
10134
|
},
|
|
9785
10135
|
{
|
|
9786
|
-
name: "@
|
|
9787
|
-
aliases: ["log"],
|
|
10136
|
+
name: "@particle-academy/log",
|
|
10137
|
+
aliases: ["log", "@fancy/log"],
|
|
9788
10138
|
category: "output",
|
|
9789
10139
|
label: "Log",
|
|
9790
10140
|
description: "Send to the run feed.",
|
|
@@ -9818,25 +10168,37 @@ function buildNodeTypes() {
|
|
|
9818
10168
|
}
|
|
9819
10169
|
|
|
9820
10170
|
exports.BUILTIN_KINDS = BUILTIN_KINDS;
|
|
10171
|
+
exports.DEFAULT_MAX_DEPTH = DEFAULT_MAX_DEPTH;
|
|
9821
10172
|
exports.RegistryNode = RegistryNode;
|
|
9822
10173
|
exports.RichInputPreview = RichInputPreview;
|
|
9823
10174
|
exports.buildNodeTypes = buildNodeTypes;
|
|
10175
|
+
exports.capabilityStatus = capabilityStatus;
|
|
9824
10176
|
exports.categoryAccent = categoryAccent;
|
|
10177
|
+
exports.declaredRoutes = declaredRoutes;
|
|
9825
10178
|
exports.defaultConfigFor = defaultConfigFor;
|
|
10179
|
+
exports.getLlmClient = getLlmClient;
|
|
9826
10180
|
exports.getNodeKind = getNodeKind;
|
|
9827
10181
|
exports.getRichInputAdapter = getRichInputAdapter;
|
|
10182
|
+
exports.getWorkflowResolver = getWorkflowResolver;
|
|
9828
10183
|
exports.isRichInputEnabled = isRichInputEnabled;
|
|
9829
10184
|
exports.kindIds = kindIds;
|
|
9830
10185
|
exports.listNodeKinds = listNodeKinds;
|
|
10186
|
+
exports.llmBranchExecutor = llmBranchExecutor;
|
|
9831
10187
|
exports.nodeConfig = nodeConfig;
|
|
9832
10188
|
exports.onNodeKindsChanged = onNodeKindsChanged;
|
|
9833
10189
|
exports.onRichInputAdapterChanged = onRichInputAdapterChanged;
|
|
9834
10190
|
exports.registerBuiltinKinds = registerBuiltinKinds;
|
|
10191
|
+
exports.registerLlmClient = registerLlmClient;
|
|
9835
10192
|
exports.registerNodeKind = registerNodeKind;
|
|
9836
10193
|
exports.registerRichInputAdapter = registerRichInputAdapter;
|
|
10194
|
+
exports.registerWorkflowResolver = registerWorkflowResolver;
|
|
10195
|
+
exports.resolveFallbackPort = resolveFallbackPort;
|
|
9837
10196
|
exports.resolveKindId = resolveKindId;
|
|
9838
10197
|
exports.resolveNodePorts = resolveNodePorts;
|
|
9839
10198
|
exports.resolvePortSpec = resolvePortSpec;
|
|
10199
|
+
exports.subflowExecutor = subflowExecutor;
|
|
10200
|
+
exports.subflowMode = subflowMode;
|
|
10201
|
+
exports.subflowPorts = subflowPorts;
|
|
9840
10202
|
exports.validateConfig = validateConfig;
|
|
9841
10203
|
//# sourceMappingURL=registry.cjs.map
|
|
9842
10204
|
//# sourceMappingURL=registry.cjs.map
|