@prompd/core 0.5.0-beta.18 → 0.5.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/index.cjs +173 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +83 -2
- package/dist/index.d.ts +83 -2
- package/dist/index.js +169 -5
- package/dist/index.js.map +1 -1
- package/package.json +70 -70
package/dist/index.cjs
CHANGED
|
@@ -3726,8 +3726,9 @@ function validateNode(node, workflow) {
|
|
|
3726
3726
|
break;
|
|
3727
3727
|
}
|
|
3728
3728
|
if (["loop", "parallel", "tool-call-router", "chat-agent"].includes(node.type)) {
|
|
3729
|
+
const isForkParallel = node.type === "parallel" && node.data.mode === "fork";
|
|
3729
3730
|
const children = workflow.nodes.filter((n) => n.parentId === node.id);
|
|
3730
|
-
if (children.length === 0 && node.type !== "chat-agent") {
|
|
3731
|
+
if (children.length === 0 && node.type !== "chat-agent" && !isForkParallel) {
|
|
3731
3732
|
const containerTypeHelp = {
|
|
3732
3733
|
"loop": "Drag nodes inside this loop container to define the loop body.",
|
|
3733
3734
|
"parallel": "Drag nodes inside this parallel container to run them concurrently.",
|
|
@@ -4576,16 +4577,19 @@ function validateNodeData(node, errors, warnings) {
|
|
|
4576
4577
|
return;
|
|
4577
4578
|
}
|
|
4578
4579
|
switch (node.type) {
|
|
4579
|
-
case "prompt":
|
|
4580
|
-
|
|
4580
|
+
case "prompt": {
|
|
4581
|
+
const d = node.data;
|
|
4582
|
+
const inline = (v) => typeof v === "string" && v.trim() !== "";
|
|
4583
|
+
if (!("source" in node.data) && !inline(d.rawPrompt) && !inline(d.content)) {
|
|
4581
4584
|
errors.push({
|
|
4582
4585
|
nodeId: node.id,
|
|
4583
4586
|
field: "source",
|
|
4584
|
-
message: "Prompt node
|
|
4587
|
+
message: "Prompt node has no source: attach a .prmd file (source) or enter inline prompt text (rawPrompt)",
|
|
4585
4588
|
code: "MISSING_PROMPT_SOURCE"
|
|
4586
4589
|
});
|
|
4587
4590
|
}
|
|
4588
4591
|
break;
|
|
4592
|
+
}
|
|
4589
4593
|
case "condition":
|
|
4590
4594
|
if (!("conditions" in node.data) || !Array.isArray(node.data.conditions)) {
|
|
4591
4595
|
errors.push({
|
|
@@ -4920,6 +4924,166 @@ function getExecutionOrder(workflow) {
|
|
|
4920
4924
|
return order;
|
|
4921
4925
|
}
|
|
4922
4926
|
|
|
4927
|
+
// src/lib/parallel.ts
|
|
4928
|
+
var DEFAULT_MAX_CONCURRENCY = 4;
|
|
4929
|
+
var errMsg = (e) => e instanceof Error ? e.message : String(e);
|
|
4930
|
+
function runBranches(branches, run, opts) {
|
|
4931
|
+
const n = branches.length;
|
|
4932
|
+
if (n === 0) return Promise.resolve({ ok: true, results: [], selected: [] });
|
|
4933
|
+
const now = opts.now ?? (() => Date.now());
|
|
4934
|
+
const need = opts.waitFor === "quorum" ? Math.max(1, Math.min(n, Math.floor(opts.quorumCount ?? 1))) : opts.waitFor === "all" ? n : 1;
|
|
4935
|
+
const limit = Math.max(1, Math.floor(opts.maxConcurrency ?? DEFAULT_MAX_CONCURRENCY));
|
|
4936
|
+
const timeoutMs = opts.timeoutMs && opts.timeoutMs > 0 ? opts.timeoutMs : 0;
|
|
4937
|
+
const results = new Array(n);
|
|
4938
|
+
const controllers = new Array(n);
|
|
4939
|
+
const timers = new Array(n);
|
|
4940
|
+
const startedAt = new Array(n).fill(0);
|
|
4941
|
+
const order = [];
|
|
4942
|
+
return new Promise((resolve) => {
|
|
4943
|
+
let nextIdx = 0;
|
|
4944
|
+
let running = 0;
|
|
4945
|
+
let okCount = 0;
|
|
4946
|
+
let failCount = 0;
|
|
4947
|
+
let done = false;
|
|
4948
|
+
const finish = (ok, error) => {
|
|
4949
|
+
if (done) return;
|
|
4950
|
+
done = true;
|
|
4951
|
+
opts.signal?.removeEventListener("abort", onParentAbort);
|
|
4952
|
+
const t = now();
|
|
4953
|
+
for (let i = 0; i < n; i++) {
|
|
4954
|
+
if (timers[i]) clearTimeout(timers[i]);
|
|
4955
|
+
if (results[i]) continue;
|
|
4956
|
+
controllers[i]?.abort();
|
|
4957
|
+
results[i] = { key: branches[i].key, label: branches[i].label, status: "cancelled", ms: controllers[i] ? t - startedAt[i] : 0 };
|
|
4958
|
+
}
|
|
4959
|
+
const all = results;
|
|
4960
|
+
let selected;
|
|
4961
|
+
if (opts.waitFor === "all") selected = all;
|
|
4962
|
+
else if (opts.waitFor === "race") selected = order.length ? [all[order[0]]] : [];
|
|
4963
|
+
else if (opts.waitFor === "any") {
|
|
4964
|
+
const i = order.find((k) => all[k].status === "ok");
|
|
4965
|
+
selected = i === void 0 ? [] : [all[i]];
|
|
4966
|
+
} else selected = ok ? all.filter((r) => r.status === "ok") : [];
|
|
4967
|
+
resolve({ ok, results: all, selected, ...error ? { error } : {} });
|
|
4968
|
+
};
|
|
4969
|
+
const onParentAbort = () => finish(false, "Aborted");
|
|
4970
|
+
const decide = () => {
|
|
4971
|
+
if (opts.waitFor === "race") {
|
|
4972
|
+
const w = results[order[0]];
|
|
4973
|
+
finish(w.status === "ok", w.status === "ok" ? void 0 : `First branch to finish (${w.label}) ended with ${w.status}${w.error ? `: ${w.error}` : ""}`);
|
|
4974
|
+
return;
|
|
4975
|
+
}
|
|
4976
|
+
if (opts.waitFor === "all") {
|
|
4977
|
+
if (order.length === n) finish(okCount > 0, okCount > 0 ? void 0 : "All branches failed");
|
|
4978
|
+
return;
|
|
4979
|
+
}
|
|
4980
|
+
if (okCount >= need) finish(true);
|
|
4981
|
+
else if (failCount > n - need) {
|
|
4982
|
+
finish(false, opts.waitFor === "any" ? "All branches failed" : `Quorum not reached: ${okCount} of ${need} required branches succeeded`);
|
|
4983
|
+
}
|
|
4984
|
+
};
|
|
4985
|
+
const settle = (i, part) => {
|
|
4986
|
+
if (done || results[i]) return;
|
|
4987
|
+
if (timers[i]) clearTimeout(timers[i]);
|
|
4988
|
+
results[i] = { key: branches[i].key, label: branches[i].label, ...part, ms: now() - startedAt[i] };
|
|
4989
|
+
running--;
|
|
4990
|
+
order.push(i);
|
|
4991
|
+
if (part.status === "ok") okCount++;
|
|
4992
|
+
else failCount++;
|
|
4993
|
+
decide();
|
|
4994
|
+
pump();
|
|
4995
|
+
};
|
|
4996
|
+
const start = (i) => {
|
|
4997
|
+
const ac = new AbortController();
|
|
4998
|
+
controllers[i] = ac;
|
|
4999
|
+
startedAt[i] = now();
|
|
5000
|
+
running++;
|
|
5001
|
+
if (timeoutMs) {
|
|
5002
|
+
timers[i] = setTimeout(() => {
|
|
5003
|
+
ac.abort();
|
|
5004
|
+
settle(i, { status: "timeout", error: `timed out after ${timeoutMs}ms` });
|
|
5005
|
+
}, timeoutMs);
|
|
5006
|
+
}
|
|
5007
|
+
let p;
|
|
5008
|
+
try {
|
|
5009
|
+
p = run(branches[i], ac.signal);
|
|
5010
|
+
} catch (e) {
|
|
5011
|
+
p = Promise.reject(e);
|
|
5012
|
+
}
|
|
5013
|
+
p.then(
|
|
5014
|
+
(output) => settle(i, { status: "ok", output }),
|
|
5015
|
+
(e) => settle(i, { status: "error", error: errMsg(e) })
|
|
5016
|
+
);
|
|
5017
|
+
};
|
|
5018
|
+
function pump() {
|
|
5019
|
+
while (!done && running < limit && nextIdx < n) start(nextIdx++);
|
|
5020
|
+
}
|
|
5021
|
+
if (opts.signal?.aborted) {
|
|
5022
|
+
finish(false, "Aborted");
|
|
5023
|
+
return;
|
|
5024
|
+
}
|
|
5025
|
+
opts.signal?.addEventListener("abort", onParentAbort, { once: true });
|
|
5026
|
+
pump();
|
|
5027
|
+
});
|
|
5028
|
+
}
|
|
5029
|
+
function mergeBranchResults(outcome, strategy) {
|
|
5030
|
+
const sel = outcome.selected;
|
|
5031
|
+
if (strategy === "object") {
|
|
5032
|
+
const merged = {};
|
|
5033
|
+
for (const r of sel) merged[r.key] = r.status === "ok" ? r.output : null;
|
|
5034
|
+
return merged;
|
|
5035
|
+
}
|
|
5036
|
+
if (strategy === "first") {
|
|
5037
|
+
const first = sel.find((r) => r.status === "ok");
|
|
5038
|
+
return first ? { result: first.output } : { error: "All branches failed" };
|
|
5039
|
+
}
|
|
5040
|
+
return sel.map((r) => r.status === "ok" ? r.output : null);
|
|
5041
|
+
}
|
|
5042
|
+
var EVENT_HANDLES = ["onError", "onCheckpoint", "onProgress", "toolResult"];
|
|
5043
|
+
var forkIndex = (handle) => {
|
|
5044
|
+
const k = parseInt((handle ?? "").replace("fork-", ""), 10);
|
|
5045
|
+
return Number.isFinite(k) ? k : 0;
|
|
5046
|
+
};
|
|
5047
|
+
function traceForkBranches(file, parallelId) {
|
|
5048
|
+
const node = file.nodes.find((n) => n.id === parallelId);
|
|
5049
|
+
if (!node || node.type !== "parallel") return [];
|
|
5050
|
+
const data = node.data;
|
|
5051
|
+
const mergeIds = new Set(file.nodes.filter((n) => n.type === "merge").map((n) => n.id));
|
|
5052
|
+
const forkEdges = file.edges.filter((e) => e.source === parallelId && e.sourceHandle?.startsWith("fork-")).sort((a, b) => forkIndex(a.sourceHandle) - forkIndex(b.sourceHandle));
|
|
5053
|
+
const labelUses = /* @__PURE__ */ new Map();
|
|
5054
|
+
return forkEdges.map((fe) => {
|
|
5055
|
+
const idx = forkIndex(fe.sourceHandle);
|
|
5056
|
+
const nodeIds = [];
|
|
5057
|
+
if (!fe.targetHandle?.startsWith("input-")) {
|
|
5058
|
+
const visited = /* @__PURE__ */ new Set();
|
|
5059
|
+
const queue = [fe.target];
|
|
5060
|
+
while (queue.length > 0) {
|
|
5061
|
+
const id = queue.shift();
|
|
5062
|
+
if (visited.has(id) || mergeIds.has(id)) continue;
|
|
5063
|
+
visited.add(id);
|
|
5064
|
+
nodeIds.push(id);
|
|
5065
|
+
for (const e of file.edges) {
|
|
5066
|
+
if (e.source !== id) continue;
|
|
5067
|
+
if (e.sourceHandle === "loop-end" || e.sourceHandle === "parallel-end") continue;
|
|
5068
|
+
if (e.targetHandle?.startsWith("fork-")) continue;
|
|
5069
|
+
if (e.sourceHandle && EVENT_HANDLES.includes(e.sourceHandle)) continue;
|
|
5070
|
+
if (e.targetHandle?.startsWith("input-")) continue;
|
|
5071
|
+
if (!visited.has(e.target) && !mergeIds.has(e.target)) queue.push(e.target);
|
|
5072
|
+
}
|
|
5073
|
+
}
|
|
5074
|
+
}
|
|
5075
|
+
const base = data.forkLabels?.[idx]?.trim() || `Branch ${idx + 1}`;
|
|
5076
|
+
const uses = labelUses.get(base) ?? 0;
|
|
5077
|
+
labelUses.set(base, uses + 1);
|
|
5078
|
+
const label = uses === 0 ? base : `${base} (${uses + 1})`;
|
|
5079
|
+
return { key: label, label, nodeIds };
|
|
5080
|
+
});
|
|
5081
|
+
}
|
|
5082
|
+
function forkJoinId(file, parallelId) {
|
|
5083
|
+
const members = /* @__PURE__ */ new Set([parallelId, ...traceForkBranches(file, parallelId).flatMap((b) => b.nodeIds)]);
|
|
5084
|
+
return file.edges.find((e) => members.has(e.source) && e.targetHandle?.startsWith("input-"))?.target;
|
|
5085
|
+
}
|
|
5086
|
+
|
|
4923
5087
|
exports.AnthropicFormatter = AnthropicFormatter;
|
|
4924
5088
|
exports.BUILTIN_COMMAND_EXECUTABLES = BUILTIN_COMMAND_EXECUTABLES;
|
|
4925
5089
|
exports.CODE_EXTENSIONS = CODE_EXTENSIONS;
|
|
@@ -4929,6 +5093,7 @@ exports.CompilationContext = CompilationContext;
|
|
|
4929
5093
|
exports.CompilationError = CompilationError;
|
|
4930
5094
|
exports.CompilationStage = CompilationStage;
|
|
4931
5095
|
exports.CompilerPipeline = CompilerPipeline;
|
|
5096
|
+
exports.DEFAULT_MAX_CONCURRENCY = DEFAULT_MAX_CONCURRENCY;
|
|
4932
5097
|
exports.DEFAULT_SECURITY_CONFIG = DEFAULT_SECURITY_CONFIG;
|
|
4933
5098
|
exports.DOCKABLE_HANDLES = DOCKABLE_HANDLES;
|
|
4934
5099
|
exports.DOCKABLE_NODE_TYPES = DOCKABLE_NODE_TYPES;
|
|
@@ -4965,6 +5130,7 @@ exports.createWorkflowNode = createWorkflowNode;
|
|
|
4965
5130
|
exports.dirnamePosix = dirnamePosix;
|
|
4966
5131
|
exports.extname = extname;
|
|
4967
5132
|
exports.extractPdpkg = extractPdpkg;
|
|
5133
|
+
exports.forkJoinId = forkJoinId;
|
|
4968
5134
|
exports.getContentType = getContentType;
|
|
4969
5135
|
exports.getExecutionOrder = getExecutionOrder;
|
|
4970
5136
|
exports.getInstallDirForType = getInstallDirForType;
|
|
@@ -4976,6 +5142,7 @@ exports.isPrompdFile = isPrompdFile;
|
|
|
4976
5142
|
exports.isValidPackageReference = isValidPackageReference;
|
|
4977
5143
|
exports.isValidPackageType = isValidPackageType;
|
|
4978
5144
|
exports.joinPosix = joinPosix;
|
|
5145
|
+
exports.mergeBranchResults = mergeBranchResults;
|
|
4979
5146
|
exports.needsFrontmatterProtection = needsFrontmatterProtection;
|
|
4980
5147
|
exports.normalizePosix = normalizePosix;
|
|
4981
5148
|
exports.parsePackageReference = parsePackageReference;
|
|
@@ -4983,8 +5150,10 @@ exports.parsePackageReferenceWithPath = parsePackageReferenceWithPath;
|
|
|
4983
5150
|
exports.parseWorkflow = parseWorkflow;
|
|
4984
5151
|
exports.resolvePackageFile = resolvePackageFile;
|
|
4985
5152
|
exports.resolvePosix = resolvePosix;
|
|
5153
|
+
exports.runBranches = runBranches;
|
|
4986
5154
|
exports.serializeWorkflow = serializeWorkflow;
|
|
4987
5155
|
exports.stripFilePath = stripFilePath;
|
|
5156
|
+
exports.traceForkBranches = traceForkBranches;
|
|
4988
5157
|
exports.uninstallPackage = uninstallPackage;
|
|
4989
5158
|
exports.validateWorkflow = validateWorkflow;
|
|
4990
5159
|
exports.validateWorkflowQuick = validateWorkflowQuick;
|