@verevoir/recipes 0.13.0 → 0.14.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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.14.0 — 2026-07-02
4
+
5
+ - **Plan-first execution engine** (`plan-execute.ts`), relocated from the mcp so it's a shared engine primitive alongside `buildPlanGraph`. Pure (no SDK/network — deps injected): `executePlanParallel` (layer the DAG, run each layer concurrently, thread upstream results, isolate failures), `layerPlan`, `buildExecutionPlan`, `gatePlan`, `parseEntrySelection`, `defaultBuildDirective`, and the `NodeRun` / `PlanExecDeps` / `PlanExecResult` / `GateVerdict` / `RecordedCall` types. Exported from the engine entry. The mcp keeps the LLM-specific bits (`selectEntryTypes`, `enactNode`, the coordinator harness) and consumes these. 101 tests.
6
+
3
7
  ## 0.13.0 — 2026-07-01
4
8
 
5
9
  - **The capability join lives here now — `capabilityWithRun` / `capabilitiesWithRun`** (STDIO-515). Recipes already owned a capability's DATA half (`parseCapability` → `CapabilityDescriptor`); the CODE half (a consumer's `run` executor, keyed by type) was joined to it in each consumer (aigency-web's `capabilities.ts`). That join is engine logic in the wrong place — and it must be **universally available to aigency AND the MCP**, which can't import aigency, so a shared lib is the only home. Lifted here: `capabilityWithRun<Run>(corpus, type, executors)` (single lookup) and `capabilitiesWithRun<Run>(corpus, executors)` (bulk), plus the `CapabilityWithRun<Run> = CapabilityDescriptor & { run?: Run }` type. **Generic over the executor signature** — recipes owns the join, not the executor shape, so each consumer plugs in its own (`run: undefined` for a conversation-only capability with no executor; `undefined` when no descriptor of that type exists). Consumers refactor to call it and drop their local copies.
package/dist/engine.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './retrieval.js';
2
2
  export * from './provisioning.js';
3
3
  export * from './plan.js';
4
+ export * from './plan-execute.js';
4
5
  export * from './verify.js';
5
6
  export * from './run-verify.js';
6
7
  export * from './adversarial-review.js';
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAIA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAIA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC"}
package/dist/engine.js CHANGED
@@ -5,6 +5,7 @@
5
5
  export * from './retrieval.js';
6
6
  export * from './provisioning.js';
7
7
  export * from './plan.js';
8
+ export * from './plan-execute.js';
8
9
  export * from './verify.js';
9
10
  export * from './run-verify.js';
10
11
  export * from './adversarial-review.js';
@@ -1 +1 @@
1
- {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,gFAAgF;AAChF,oFAAoF;AACpF,kFAAkF;AAClF,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC"}
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,gFAAgF;AAChF,oFAAoF;AACpF,kFAAkF;AAClF,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC"}
@@ -0,0 +1,110 @@
1
+ import type { CapabilityDescriptor } from './index.js';
2
+ import type { ExecutionPlan, PlanNode } from './plan.js';
3
+ /** One real tool call a node ran, with what it cost — the opaque accounting unit
4
+ * the executor threads through to a caller's cost aggregation. Recipes never
5
+ * interprets these; it only collects them per node and hands the union back. */
6
+ export interface RecordedCall {
7
+ /** The tool the call ran (`enact_capability`, `delegate`, …). */
8
+ tool: string;
9
+ /** The concrete model id that ran the work, or `'(none)'` for an inline call. */
10
+ model: string;
11
+ /** FRESH input tokens only — cache read/write are separate below so a caller
12
+ * can price them at their real (cheaper) rates. */
13
+ tokensIn: number;
14
+ tokensOut: number;
15
+ /** Cache-read / cache-write input tokens, SEPARATE from `tokensIn`. */
16
+ cacheRead?: number;
17
+ cacheWrite?: number;
18
+ /** Wall-clock for the call, ms. */
19
+ ms: number;
20
+ }
21
+ /** The outcome of running one plan node: its produced text, every model call it
22
+ * made (for the cost rollup), and whether it failed. A failed run's dependents
23
+ * can never satisfy their deps, so they are skipped. */
24
+ export interface NodeRun {
25
+ /** The node's produced output — threaded into its dependents' directives. */
26
+ text: string;
27
+ /** Every model call this node made, for the whole-run cost aggregation. */
28
+ calls: RecordedCall[];
29
+ /** True when the node's enact errored or its gate failed. */
30
+ failed?: boolean;
31
+ }
32
+ export interface PlanExecDeps {
33
+ /** Run ONE node: enact its capability with a directive already threaded from
34
+ * upstream results. Injected so the executor is testable without a network;
35
+ * the coordinator provides the real one (a wrapper over `enactCapability`). */
36
+ enactNode: (node: PlanNode, directive: string) => Promise<NodeRun>;
37
+ /** Build a node's directive from the request and its upstream results (the
38
+ * produced text of each capability in `node.dependsOn`). Optional — a sensible
39
+ * default grounds the request with a labelled block per upstream. */
40
+ buildDirective?: (node: PlanNode, request: string, upstream: Map<string, string>) => string;
41
+ }
42
+ export interface PlanExecResult {
43
+ /** Capability type → produced text, for every node that ran (not the skipped). */
44
+ results: Map<string, string>;
45
+ /** All RecordedCalls across all nodes that ran, for the cost aggregation. */
46
+ calls: RecordedCall[];
47
+ /** The layers as executed; each is the capability types run CONCURRENTLY.
48
+ * `layers.length` is the critical-path depth; the total size is the node
49
+ * count. Order within a layer is stable (sorted by capability). */
50
+ layers: string[][];
51
+ /** Nodes that failed — their transitive dependents were skipped, so a failure
52
+ * leaves a legible partial result rather than throwing. */
53
+ failed: string[];
54
+ }
55
+ /** The default directive builder: the request, followed by one labelled grounding
56
+ * block per upstream result, so a node sees what its prerequisites produced. */
57
+ export declare function defaultBuildDirective(_node: PlanNode, request: string, upstream: Map<string, string>): string;
58
+ /**
59
+ * Layer the plan's DAG: layer 0 is the nodes with no in-plan dependency, and
60
+ * layer k is the nodes whose every dependency sits in an earlier layer. PURE and
61
+ * deterministic — membership follows only from `dependsOn`, and each layer is
62
+ * sorted by capability so the order is stable across runs. A dependency naming a
63
+ * capability not in the plan is treated as already-satisfied (it can't be waited
64
+ * on). A cycle (which a well-formed plan never contains) leaves its nodes
65
+ * unlayered rather than looping.
66
+ */
67
+ export declare function layerPlan(plan: ExecutionPlan): PlanNode[][];
68
+ /**
69
+ * Execute a plan with its independent nodes running CONCURRENTLY. The DAG is
70
+ * layered (`layerPlan`); each layer runs via `Promise.all`, and a barrier between
71
+ * layers means a node never starts before its dependencies' results exist. Before
72
+ * a node runs, its upstream results are gathered and threaded into its directive
73
+ * (`deps.buildDirective`, or a labelled-grounding default).
74
+ *
75
+ * Failure is isolated: a node whose run reports `failed` — or whose `enactNode`
76
+ * throws (caught, treated as failed) — is recorded in `failed`, and its
77
+ * transitive dependents are SKIPPED (they can never satisfy their deps) while
78
+ * independent nodes and layers proceed. This never throws: a failure yields a
79
+ * legible partial result, not a dropped run.
80
+ */
81
+ export declare function executePlanParallel(plan: ExecutionPlan, deps: PlanExecDeps): Promise<PlanExecResult>;
82
+ /** A gate verdict over a plan: whether it's safe to spend on, and the findings
83
+ * that failed it. `ok` false means the plan should be aborted, not executed. */
84
+ export interface GateVerdict {
85
+ ok: boolean;
86
+ findings: string[];
87
+ }
88
+ /**
89
+ * Gate a plan before any spend — the "inspect before you spend" control point.
90
+ * PURE. A plan passes only when:
91
+ * - it has at least one node (an empty plan produces nothing);
92
+ * - every entry capability resolves to a node in the plan;
93
+ * - no node depends on a capability the plan doesn't contain (a dangling edge);
94
+ * - the plan is acyclic — topologically orderable via its `dependsOn` edges.
95
+ *
96
+ * buildPlanGraph already topologically orders and drops unresolvable edges, so a
97
+ * gate failure here signals a plan built some other way, or a corpus/entry
98
+ * mismatch. Findings name what failed so the caller can abort legibly.
99
+ */
100
+ export declare function gatePlan(plan: ExecutionPlan): GateVerdict;
101
+ /** Parse selected ids from a model reply, matching only against the supplied id
102
+ * set, order preserved by the corpus. Word-boundary anchored so a hyphenated id
103
+ * doesn't fire on its substrings (same rule as recipes' parseSelectedIds). PURE
104
+ * string parsing — no model call. */
105
+ export declare function parseEntrySelection(text: string, ids: string[]): string[];
106
+ /** Build an ExecutionPlan from buildPlanGraph's output. Practices are `[]` — this
107
+ * builds the DAG's cost + parallel structure, not per-node provisioning (that's
108
+ * `planExecution`'s job, which needs an embedder). PURE. */
109
+ export declare function buildExecutionPlan(request: string, entry: string[], corpus: CapabilityDescriptor[]): ExecutionPlan;
110
+ //# sourceMappingURL=plan-execute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-execute.d.ts","sourceRoot":"","sources":["../src/plan-execute.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEzD;;gFAEgF;AAChF,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC;IACd;uDACmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;wDAEwD;AACxD,MAAM,WAAW,OAAO;IACtB,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B;;mFAE+E;IAC/E,SAAS,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACnE;;yEAEqE;IACrE,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC;CAC7F;AAED,MAAM,WAAW,cAAc;IAC7B,kFAAkF;IAClF,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,6EAA6E;IAC7E,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB;;uEAEmE;IACnE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;IACnB;+DAC2D;IAC3D,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;gFACgF;AAChF,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B,MAAM,CAMR;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,QAAQ,EAAE,EAAE,CAkB3D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,cAAc,CAAC,CA4CzB;AAED;gFACgF;AAChF,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,WAAW,CA2BzD;AA2BD;;;qCAGqC;AACrC,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAOzE;AAED;;4DAE4D;AAC5D,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EAAE,EACf,MAAM,EAAE,oBAAoB,EAAE,GAC7B,aAAa,CAaf"}
@@ -0,0 +1,199 @@
1
+ // PLAN EXECUTION — the PURE, plan-first execution engine, sibling to
2
+ // `buildPlanGraph` in plan.ts. Where plan.ts turns a request into a dependency
3
+ // DAG of capability nodes, this module GATES that plan (inspect before you
4
+ // spend), LAYERS it, and EXECUTES it with independent nodes running CONCURRENTLY.
5
+ //
6
+ // Everything here is a PURE function of the plan (its `dependsOn` edges) plus
7
+ // INJECTED enactment — no LLM, no network, no SDK. A real coordinator wraps
8
+ // `enactCapability`; tests pass a mock. That purity is why these live in recipes
9
+ // as a shared engine primitive (aigency, the MCP, or anyone can drive them),
10
+ // rather than in any one consumer.
11
+ //
12
+ // `RecordedCall` is the executor's opaque cost-accounting unit — the executor
13
+ // threads a node's recorded calls through to the aggregate without interpreting
14
+ // them, so recipes stays free of any measurement machinery.
15
+ import { buildPlanGraph } from './plan.js';
16
+ /** The default directive builder: the request, followed by one labelled grounding
17
+ * block per upstream result, so a node sees what its prerequisites produced. */
18
+ export function defaultBuildDirective(_node, request, upstream) {
19
+ if (upstream.size === 0)
20
+ return request;
21
+ const grounding = [...upstream.entries()]
22
+ .map(([capability, text]) => `grounding: ${capability}:\n${text}`)
23
+ .join('\n\n');
24
+ return `${request}\n\n${grounding}`;
25
+ }
26
+ /**
27
+ * Layer the plan's DAG: layer 0 is the nodes with no in-plan dependency, and
28
+ * layer k is the nodes whose every dependency sits in an earlier layer. PURE and
29
+ * deterministic — membership follows only from `dependsOn`, and each layer is
30
+ * sorted by capability so the order is stable across runs. A dependency naming a
31
+ * capability not in the plan is treated as already-satisfied (it can't be waited
32
+ * on). A cycle (which a well-formed plan never contains) leaves its nodes
33
+ * unlayered rather than looping.
34
+ */
35
+ export function layerPlan(plan) {
36
+ const inPlan = new Set(plan.nodes.map((n) => n.capability));
37
+ const placed = new Set();
38
+ const layers = [];
39
+ while (placed.size < plan.nodes.length) {
40
+ const ready = plan.nodes.filter((n) => !placed.has(n.capability) && n.dependsOn.every((d) => !inPlan.has(d) || placed.has(d)));
41
+ // No node became ready but some remain unplaced → a dependency cycle. Stop
42
+ // rather than loop; the remaining nodes are left unlayered (never runnable).
43
+ if (ready.length === 0)
44
+ break;
45
+ ready.sort((a, b) => a.capability.localeCompare(b.capability));
46
+ for (const n of ready)
47
+ placed.add(n.capability);
48
+ layers.push(ready);
49
+ }
50
+ return layers;
51
+ }
52
+ /**
53
+ * Execute a plan with its independent nodes running CONCURRENTLY. The DAG is
54
+ * layered (`layerPlan`); each layer runs via `Promise.all`, and a barrier between
55
+ * layers means a node never starts before its dependencies' results exist. Before
56
+ * a node runs, its upstream results are gathered and threaded into its directive
57
+ * (`deps.buildDirective`, or a labelled-grounding default).
58
+ *
59
+ * Failure is isolated: a node whose run reports `failed` — or whose `enactNode`
60
+ * throws (caught, treated as failed) — is recorded in `failed`, and its
61
+ * transitive dependents are SKIPPED (they can never satisfy their deps) while
62
+ * independent nodes and layers proceed. This never throws: a failure yields a
63
+ * legible partial result, not a dropped run.
64
+ */
65
+ export async function executePlanParallel(plan, deps) {
66
+ const buildDirective = deps.buildDirective ?? defaultBuildDirective;
67
+ const layers = layerPlan(plan);
68
+ const results = new Map();
69
+ const calls = [];
70
+ const failed = new Set();
71
+ for (const layer of layers) {
72
+ // A node is skipped when any dependency failed or was itself skipped — the
73
+ // failure propagates transitively down the DAG, layer by layer.
74
+ const runnable = layer.filter((n) => !n.dependsOn.some((d) => failed.has(d)));
75
+ for (const n of layer)
76
+ if (!runnable.includes(n))
77
+ failed.add(n.capability);
78
+ const runs = await Promise.all(runnable.map(async (node) => {
79
+ const upstream = new Map();
80
+ for (const dep of node.dependsOn) {
81
+ const text = results.get(dep);
82
+ if (text !== undefined)
83
+ upstream.set(dep, text);
84
+ }
85
+ const directive = buildDirective(node, plan.request, upstream);
86
+ try {
87
+ return [node, await deps.enactNode(node, directive)];
88
+ }
89
+ catch (err) {
90
+ const message = `<enact ${node.capability} failed: ${String(err).slice(0, 200)}>`;
91
+ return [node, { text: message, calls: [], failed: true }];
92
+ }
93
+ }));
94
+ for (const [node, run] of runs) {
95
+ calls.push(...run.calls);
96
+ if (run.failed)
97
+ failed.add(node.capability);
98
+ else
99
+ results.set(node.capability, run.text);
100
+ }
101
+ }
102
+ return {
103
+ results,
104
+ calls,
105
+ layers: layers.map((layer) => layer.map((n) => n.capability)),
106
+ failed: [...failed],
107
+ };
108
+ }
109
+ /**
110
+ * Gate a plan before any spend — the "inspect before you spend" control point.
111
+ * PURE. A plan passes only when:
112
+ * - it has at least one node (an empty plan produces nothing);
113
+ * - every entry capability resolves to a node in the plan;
114
+ * - no node depends on a capability the plan doesn't contain (a dangling edge);
115
+ * - the plan is acyclic — topologically orderable via its `dependsOn` edges.
116
+ *
117
+ * buildPlanGraph already topologically orders and drops unresolvable edges, so a
118
+ * gate failure here signals a plan built some other way, or a corpus/entry
119
+ * mismatch. Findings name what failed so the caller can abort legibly.
120
+ */
121
+ export function gatePlan(plan) {
122
+ const findings = [];
123
+ const present = new Set(plan.nodes.map((n) => n.capability));
124
+ if (plan.nodes.length === 0) {
125
+ findings.push('plan is empty — no capabilities to execute');
126
+ }
127
+ for (const entry of plan.entry) {
128
+ if (!present.has(entry)) {
129
+ findings.push(`entry capability "${entry}" has no node in the plan`);
130
+ }
131
+ }
132
+ for (const node of plan.nodes) {
133
+ for (const dep of node.dependsOn) {
134
+ if (!present.has(dep)) {
135
+ findings.push(`node "${node.capability}" depends on missing capability "${dep}"`);
136
+ }
137
+ }
138
+ }
139
+ if (!isAcyclic(plan.nodes)) {
140
+ findings.push('plan has a dependency cycle — it cannot be topologically ordered');
141
+ }
142
+ return { ok: findings.length === 0, findings };
143
+ }
144
+ /** Whether a node set's `dependsOn` edges form a DAG — a Kahn peel that consumes
145
+ * every node iff there is no cycle. Edges to absent capabilities are ignored here
146
+ * (the dangling-dep check reports those); this asks only about cyclicity. */
147
+ function isAcyclic(nodes) {
148
+ const present = new Set(nodes.map((n) => n.capability));
149
+ const indeg = new Map();
150
+ for (const n of nodes) {
151
+ indeg.set(n.capability, n.dependsOn.filter((d) => present.has(d)).length);
152
+ }
153
+ const ready = nodes.filter((n) => (indeg.get(n.capability) ?? 0) === 0).map((n) => n.capability);
154
+ let consumed = 0;
155
+ while (ready.length > 0) {
156
+ const t = ready.pop();
157
+ consumed++;
158
+ for (const n of nodes) {
159
+ if (n.dependsOn.includes(t)) {
160
+ const d = (indeg.get(n.capability) ?? 0) - 1;
161
+ indeg.set(n.capability, d);
162
+ if (d === 0)
163
+ ready.push(n.capability);
164
+ }
165
+ }
166
+ }
167
+ return consumed === nodes.length;
168
+ }
169
+ /** Parse selected ids from a model reply, matching only against the supplied id
170
+ * set, order preserved by the corpus. Word-boundary anchored so a hyphenated id
171
+ * doesn't fire on its substrings (same rule as recipes' parseSelectedIds). PURE
172
+ * string parsing — no model call. */
173
+ export function parseEntrySelection(text, ids) {
174
+ const out = [];
175
+ for (const id of ids) {
176
+ const re = new RegExp(`(?<![a-z-])${id}(?![a-z-])`);
177
+ if (re.test(text) && !out.includes(id))
178
+ out.push(id);
179
+ }
180
+ return out;
181
+ }
182
+ /** Build an ExecutionPlan from buildPlanGraph's output. Practices are `[]` — this
183
+ * builds the DAG's cost + parallel structure, not per-node provisioning (that's
184
+ * `planExecution`'s job, which needs an embedder). PURE. */
185
+ export function buildExecutionPlan(request, entry, corpus) {
186
+ const graph = buildPlanGraph(entry, corpus);
187
+ const nodes = graph.map((g) => ({
188
+ capability: g.capability,
189
+ practices: [],
190
+ dependsOn: g.dependsOn,
191
+ source: g.source,
192
+ }));
193
+ return {
194
+ request,
195
+ entry: graph.filter((g) => g.source === 'retrieved').map((g) => g.capability),
196
+ nodes,
197
+ };
198
+ }
199
+ //# sourceMappingURL=plan-execute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-execute.js","sourceRoot":"","sources":["../src/plan-execute.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verevoir/recipes",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Recipe-descriptor format + zero-dependency parser: a flat-frontmatter .md describes a parameterised procedure (typed inputs → instructions → result) that a host compiles to a chat-time tool or an MCP prompt.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",