@prompd/core 0.5.0-beta.19 → 0.5.2
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 +167 -1
- 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 +163 -2
- 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.",
|
|
@@ -4923,6 +4924,166 @@ function getExecutionOrder(workflow) {
|
|
|
4923
4924
|
return order;
|
|
4924
4925
|
}
|
|
4925
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
|
+
|
|
4926
5087
|
exports.AnthropicFormatter = AnthropicFormatter;
|
|
4927
5088
|
exports.BUILTIN_COMMAND_EXECUTABLES = BUILTIN_COMMAND_EXECUTABLES;
|
|
4928
5089
|
exports.CODE_EXTENSIONS = CODE_EXTENSIONS;
|
|
@@ -4932,6 +5093,7 @@ exports.CompilationContext = CompilationContext;
|
|
|
4932
5093
|
exports.CompilationError = CompilationError;
|
|
4933
5094
|
exports.CompilationStage = CompilationStage;
|
|
4934
5095
|
exports.CompilerPipeline = CompilerPipeline;
|
|
5096
|
+
exports.DEFAULT_MAX_CONCURRENCY = DEFAULT_MAX_CONCURRENCY;
|
|
4935
5097
|
exports.DEFAULT_SECURITY_CONFIG = DEFAULT_SECURITY_CONFIG;
|
|
4936
5098
|
exports.DOCKABLE_HANDLES = DOCKABLE_HANDLES;
|
|
4937
5099
|
exports.DOCKABLE_NODE_TYPES = DOCKABLE_NODE_TYPES;
|
|
@@ -4968,6 +5130,7 @@ exports.createWorkflowNode = createWorkflowNode;
|
|
|
4968
5130
|
exports.dirnamePosix = dirnamePosix;
|
|
4969
5131
|
exports.extname = extname;
|
|
4970
5132
|
exports.extractPdpkg = extractPdpkg;
|
|
5133
|
+
exports.forkJoinId = forkJoinId;
|
|
4971
5134
|
exports.getContentType = getContentType;
|
|
4972
5135
|
exports.getExecutionOrder = getExecutionOrder;
|
|
4973
5136
|
exports.getInstallDirForType = getInstallDirForType;
|
|
@@ -4979,6 +5142,7 @@ exports.isPrompdFile = isPrompdFile;
|
|
|
4979
5142
|
exports.isValidPackageReference = isValidPackageReference;
|
|
4980
5143
|
exports.isValidPackageType = isValidPackageType;
|
|
4981
5144
|
exports.joinPosix = joinPosix;
|
|
5145
|
+
exports.mergeBranchResults = mergeBranchResults;
|
|
4982
5146
|
exports.needsFrontmatterProtection = needsFrontmatterProtection;
|
|
4983
5147
|
exports.normalizePosix = normalizePosix;
|
|
4984
5148
|
exports.parsePackageReference = parsePackageReference;
|
|
@@ -4986,8 +5150,10 @@ exports.parsePackageReferenceWithPath = parsePackageReferenceWithPath;
|
|
|
4986
5150
|
exports.parseWorkflow = parseWorkflow;
|
|
4987
5151
|
exports.resolvePackageFile = resolvePackageFile;
|
|
4988
5152
|
exports.resolvePosix = resolvePosix;
|
|
5153
|
+
exports.runBranches = runBranches;
|
|
4989
5154
|
exports.serializeWorkflow = serializeWorkflow;
|
|
4990
5155
|
exports.stripFilePath = stripFilePath;
|
|
5156
|
+
exports.traceForkBranches = traceForkBranches;
|
|
4991
5157
|
exports.uninstallPackage = uninstallPackage;
|
|
4992
5158
|
exports.validateWorkflow = validateWorkflow;
|
|
4993
5159
|
exports.validateWorkflowQuick = validateWorkflowQuick;
|