@kernloop/workflows 0.1.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.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/dist/budget.d.ts +111 -0
  3. package/dist/budget.d.ts.map +1 -0
  4. package/dist/budget.js +146 -0
  5. package/dist/budget.js.map +1 -0
  6. package/dist/checkpoints.d.ts +40 -0
  7. package/dist/checkpoints.d.ts.map +1 -0
  8. package/dist/checkpoints.js +92 -0
  9. package/dist/checkpoints.js.map +1 -0
  10. package/dist/child-iterate-fixtures.d.ts +36 -0
  11. package/dist/child-iterate-fixtures.d.ts.map +1 -0
  12. package/dist/child-iterate-fixtures.js +86 -0
  13. package/dist/child-iterate-fixtures.js.map +1 -0
  14. package/dist/child-iterate.d.ts +71 -0
  15. package/dist/child-iterate.d.ts.map +1 -0
  16. package/dist/child-iterate.js +61 -0
  17. package/dist/child-iterate.js.map +1 -0
  18. package/dist/child-spend.d.ts +41 -0
  19. package/dist/child-spend.d.ts.map +1 -0
  20. package/dist/child-spend.js +76 -0
  21. package/dist/child-spend.js.map +1 -0
  22. package/dist/config.d.ts +43 -0
  23. package/dist/config.d.ts.map +1 -0
  24. package/dist/config.js +90 -0
  25. package/dist/config.js.map +1 -0
  26. package/dist/engine-errors.d.ts +11 -0
  27. package/dist/engine-errors.d.ts.map +1 -0
  28. package/dist/engine-errors.js +23 -0
  29. package/dist/engine-errors.js.map +1 -0
  30. package/dist/engine-testkit.d.ts +44 -0
  31. package/dist/engine-testkit.d.ts.map +1 -0
  32. package/dist/engine-testkit.js +93 -0
  33. package/dist/engine-testkit.js.map +1 -0
  34. package/dist/engine-types.d.ts +78 -0
  35. package/dist/engine-types.d.ts.map +1 -0
  36. package/dist/engine-types.js +2 -0
  37. package/dist/engine-types.js.map +1 -0
  38. package/dist/engine.d.ts +12 -0
  39. package/dist/engine.d.ts.map +1 -0
  40. package/dist/engine.js +262 -0
  41. package/dist/engine.js.map +1 -0
  42. package/dist/graph.d.ts +87 -0
  43. package/dist/graph.d.ts.map +1 -0
  44. package/dist/graph.js +72 -0
  45. package/dist/graph.js.map +1 -0
  46. package/dist/index.d.ts +14 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +14 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/manifest.d.ts +19 -0
  51. package/dist/manifest.d.ts.map +1 -0
  52. package/dist/manifest.js +41 -0
  53. package/dist/manifest.js.map +1 -0
  54. package/dist/state.d.ts +1078 -0
  55. package/dist/state.d.ts.map +1 -0
  56. package/dist/state.js +151 -0
  57. package/dist/state.js.map +1 -0
  58. package/dist/steps.d.ts +77 -0
  59. package/dist/steps.d.ts.map +1 -0
  60. package/dist/steps.js +270 -0
  61. package/dist/steps.js.map +1 -0
  62. package/dist/verdict-disposition.d.ts +23 -0
  63. package/dist/verdict-disposition.d.ts.map +1 -0
  64. package/dist/verdict-disposition.js +28 -0
  65. package/dist/verdict-disposition.js.map +1 -0
  66. package/package.json +38 -0
@@ -0,0 +1,12 @@
1
+ import type { EngineDeps, Engine } from './engine-types.js';
2
+ export { EngineConfigSchema, type EngineConfig, type EngineConfigInput } from './config.js';
3
+ export { BudgetModeSchema, type BudgetGuard, type BudgetMode } from './budget.js';
4
+ export type { ChildIterateEvent } from './child-iterate.js';
5
+ export type { NodeContext, NodeExecutor, EngineDeps, RunOptions, Engine } from './engine-types.js';
6
+ /**
7
+ * Create a loop engine over the CANONICAL_LOOP. Throws `unwired_node` if
8
+ * any executable node lacks an executor (wiring-complete or absent — a
9
+ * graph that could fail mid-run on a missing executor is a stub).
10
+ */
11
+ export declare function createEngine(deps: EngineDeps): Engine;
12
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAA6B,UAAU,EAAc,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEnG,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,gBAAgB,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAClF,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG5D,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAmRnG;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAErD"}
package/dist/engine.js ADDED
@@ -0,0 +1,262 @@
1
+ /**
2
+ * The loop execution engine. `createEngine({executors, checkpoints, config})`
3
+ * binds the CANONICAL_LOOP to injected node executors and a checkpoint store —
4
+ * all real work (model calls, gates, memory) arrives through `executors`; this
5
+ * package never imports the kernel, a faculty, or the cli (workflows talks
6
+ * contracts, not plugins). The config schema lives in config.ts; it mirrors the
7
+ * cli OverlaySchema field-for-field [CLM-0045]. Overrides change behavior
8
+ * against the SAME frozen graph (a `gate` override swaps a gate executor;
9
+ * `specialists` adds fan-out children) — the graph is never duplicated. Fan-out
10
+ * children run SEQUENTIALLY: deterministic trace, unambiguous cursor, no budget
11
+ * race (per-child spend is sliced off that order, #56); concurrency via a claim.
12
+ */
13
+ import { randomUUID } from 'node:crypto';
14
+ import { z } from 'zod';
15
+ import { TaskContractSchema } from '@kernloop/contracts';
16
+ import { CANONICAL_LOOP } from './graph.js';
17
+ import { RunStateSchema, WorkflowError } from './state.js';
18
+ import { asWorkflowError } from './engine-errors.js';
19
+ import { advance, advanceToNextChild, initialState, nextStep, validateEmission, } from './steps.js';
20
+ import { enforceBudget, enforceBudgetPreNode, foldNodeSpend, overBudget, } from './budget.js';
21
+ import { ChildSpendTracker, childSpends } from './child-spend.js';
22
+ import { EngineConfigSchema } from './config.js';
23
+ export { EngineConfigSchema } from './config.js';
24
+ export { BudgetModeSchema } from './budget.js';
25
+ /** Engine implementation; see {@link createEngine}. */
26
+ class LoopEngine {
27
+ graph = CANONICAL_LOOP;
28
+ executors;
29
+ checkpoints;
30
+ config;
31
+ /** Pre-node budget reserve floor fraction (#342), hoisted for a short call site. */
32
+ headroom;
33
+ budget;
34
+ onChildIterate;
35
+ /** Slices the run-global meter per fan-out child for attribution + halt (#56). */
36
+ childSpend;
37
+ constructor(deps) {
38
+ this.executors = deps.executors;
39
+ this.checkpoints = deps.checkpoints;
40
+ this.config = EngineConfigSchema.parse(deps.config);
41
+ this.headroom = this.config.budgetHeadroomFraction;
42
+ this.budget = deps.budget;
43
+ this.childSpend = new ChildSpendTracker(deps.meteredSpend);
44
+ this.onChildIterate = deps.onChildIterate;
45
+ // Wiring-complete or absent: every executable node must resolve NOW.
46
+ // The fan-out node is structural (the engine itself runs the sub-chain).
47
+ for (const node of [...this.graph.nodes, ...this.graph.childChain]) {
48
+ if (node.kind !== 'fanout' && this.executorFor(node) === undefined) {
49
+ throw new WorkflowError('unwired_node', `no executor for node "${node.name}" (kind "${node.kind}"${node.gate === undefined ? '' : `, gate "${this.config.nodeOverrides[node.name]?.gate ?? node.gate}"`})`, { node: node.name });
50
+ }
51
+ }
52
+ }
53
+ async run(task, options = {}) {
54
+ const parsed = TaskContractSchema.safeParse(task);
55
+ if (!parsed.success) {
56
+ throw new WorkflowError('invalid_task', `run() input is not a TaskContract: ${z.prettifyError(parsed.error)}`, {
57
+ contract: 'TaskContract',
58
+ });
59
+ }
60
+ const runId = options.runId ?? randomUUID();
61
+ const state = initialState(parsed.data, this.graph.entry);
62
+ return this.loop(runId, state, 0, options.signal);
63
+ }
64
+ async resume(runId, options = {}) {
65
+ const checkpoint = await this.checkpoints.latest(runId);
66
+ if (checkpoint === undefined) {
67
+ throw new WorkflowError('no_checkpoint', `no checkpoint found for run "${runId}"`);
68
+ }
69
+ const parsed = RunStateSchema.safeParse(checkpoint.state);
70
+ if (!parsed.success) {
71
+ throw new WorkflowError('corrupt_checkpoint', `checkpoint ${String(checkpoint.seq)} of run "${runId}" does not parse: ${z.prettifyError(parsed.error)}`);
72
+ }
73
+ const state = parsed.data;
74
+ if (state.status === 'completed')
75
+ return this.finish(runId, state, childSpends(state));
76
+ if (state.status === 'escalated') {
77
+ // Vote escalation: the human edited the plan; continue from plan with a
78
+ // fresh K budget [CLM-0043]. Budget halt [CLM-0077]: continue from the
79
+ // cursor where spend tripped the limit — iteration is NOT reset (no plan
80
+ // re-edit), and the budget guard re-evaluates as the run proceeds.
81
+ if (state.haltReason !== 'budget')
82
+ state.iteration = 0;
83
+ state.status = 'running';
84
+ state.haltReason = undefined;
85
+ }
86
+ return this.loop(runId, state, checkpoint.seq, options.signal);
87
+ }
88
+ /** Run nodes from the cursor until terminal, checkpointing each completion. */
89
+ async loop(runId, state, seqStart, signal) {
90
+ let seq = seqStart;
91
+ this.childSpend.reset(state); // per-process attribution; drops pre-resume spend (#212)
92
+ while (state.status === 'running') {
93
+ const step = nextStep(this.graph, state);
94
+ // #342: halt before dispatch if the next node would overshoot (a near-ceiling).
95
+ if (enforceBudgetPreNode(state, this.budget, state.observedMaxNodeSpend, this.headroom))
96
+ break;
97
+ const executor = this.executorFor(step.node);
98
+ if (executor === undefined) {
99
+ throw new WorkflowError('unwired_node', `no executor for node "${step.node.name}"`);
100
+ }
101
+ const fanoutIndex = state.cursor.phase === 'fanout' ? state.cursor.childIndex : undefined;
102
+ if (fanoutIndex !== undefined)
103
+ this.childSpend.ensureBaseline(fanoutIndex);
104
+ const iteration = state.iteration;
105
+ const spentBefore = this.budget?.spent();
106
+ let output;
107
+ let childFailed = false;
108
+ try {
109
+ if (signal?.aborted === true)
110
+ throw new WorkflowError('aborted', 'abort signal fired');
111
+ output = validateEmission(step.node, await executor(step.input, this.context(runId, state, step, signal)));
112
+ }
113
+ catch (error) {
114
+ const failure = this.classify(error, state, step, signal);
115
+ if (failure !== undefined) {
116
+ return { runId, status: 'failed', nodeTrace: state.trace, error: failure };
117
+ }
118
+ // A child executor failed: recorded honestly (classify advanced the cursor), fan-out continues.
119
+ childFailed = true;
120
+ }
121
+ foldNodeSpend(state, this.budget, spentBefore); // #342: per-node delta → observed-max
122
+ if (!childFailed)
123
+ advance(this.graph, state, step.node, output, this.advanceOptions(state));
124
+ if (fanoutIndex !== undefined)
125
+ this.childSpend.attribute(state, fanoutIndex);
126
+ enforceBudget(state, this.budget);
127
+ seq += 1;
128
+ state.trace.push(this.traceEntry(seq, iteration, step));
129
+ const persistFailure = await this.persist(runId, seq, iteration, state, step.node.name);
130
+ if (persistFailure !== undefined) {
131
+ return { runId, status: 'failed', nodeTrace: state.trace, error: persistFailure };
132
+ }
133
+ }
134
+ return this.terminalResult(runId, state);
135
+ }
136
+ /** The escalated-or-completed result, carrying per-child spend attribution (#56). */
137
+ terminalResult(runId, state) {
138
+ const childSpend = childSpends(state);
139
+ if (state.status !== 'escalated')
140
+ return this.finish(runId, state, childSpend);
141
+ return {
142
+ runId,
143
+ status: 'escalated',
144
+ nodeTrace: state.trace,
145
+ findings: state.findings,
146
+ ...(state.haltReason === undefined ? {} : { haltReason: state.haltReason }),
147
+ ...(childSpend === undefined ? {} : { childSpend }),
148
+ };
149
+ }
150
+ /** The loop-shaping inputs for one {@link advance} call, resolved from config + seams. */
151
+ advanceOptions(state) {
152
+ return {
153
+ k: this.config.K,
154
+ kc: this.config.Kc,
155
+ specialists: this.specialists(),
156
+ reviewDrivesIteration: this.config.reviewDrivesIteration,
157
+ parsimonyDrivesIteration: this.config.parsimonyDrivesIteration,
158
+ // Re-implement allowed only within BOTH the run budget AND the child's own
159
+ // slice (#56); over either forces escalation before Kc.
160
+ childWithinBudget: !overBudget(this.budget) &&
161
+ this.childSpend.withinOwnBudget(this.budget?.mode === 'enforce', state),
162
+ ...(this.onChildIterate === undefined ? {} : { onIterate: this.onChildIterate }),
163
+ };
164
+ }
165
+ /** Classify a node throw: undefined means "recorded as child failure, continue". */
166
+ classify(error, state, step, signal) {
167
+ const wrapped = asWorkflowError(error, step.node.name, signal);
168
+ if (wrapped.code === 'executor_failed' && state.cursor.phase === 'fanout') {
169
+ const { childIndex } = state.cursor;
170
+ const result = state.childResults[childIndex];
171
+ if (result !== undefined)
172
+ result.error = wrapped.message;
173
+ advanceToNextChild(this.graph, state, childIndex);
174
+ return undefined;
175
+ }
176
+ return wrapped;
177
+ }
178
+ context(runId, state, step, signal) {
179
+ // Fan-out: a node reads its CHILD's findings [CLM-0043]; main chain: the
180
+ // run-level vote-iterate findings. A snapshot, never the live array.
181
+ const inFanout = step.child !== undefined;
182
+ const findings = inFanout ? [...(step.childFindings ?? [])] : [...state.findings];
183
+ const childIteration = step.child === undefined ? undefined : (this.childIterationFor(state, step.child.id) ?? 0);
184
+ return {
185
+ runId,
186
+ taskId: state.task.id,
187
+ iteration: state.iteration,
188
+ config: this.config,
189
+ node: step.node.name,
190
+ findings,
191
+ ...(step.child === undefined ? {} : { child: step.child }),
192
+ ...(childIteration === undefined ? {} : { childIteration }),
193
+ ...(signal === undefined ? {} : { signal }),
194
+ };
195
+ }
196
+ /** This child's current actor-critic iteration, from the run state. */
197
+ childIterationFor(state, childId) {
198
+ return state.childResults.find((r) => r.child.id === childId)?.iteration;
199
+ }
200
+ /** Trace/checkpoint rows record the iteration at which the node RAN. */
201
+ traceEntry(seq, iteration, step) {
202
+ return {
203
+ seq,
204
+ node: step.node.name,
205
+ iteration,
206
+ ...(step.child === undefined ? {} : { childId: step.child.id }),
207
+ };
208
+ }
209
+ /**
210
+ * Persist one checkpoint [CLM-0044]. A rejected save is a run failure:
211
+ * silently losing a checkpoint would let `resume` lie about what re-runs.
212
+ */
213
+ async persist(runId, seq, iteration, state, node) {
214
+ try {
215
+ await this.checkpoints.save({
216
+ runId,
217
+ seq,
218
+ node,
219
+ iteration,
220
+ state: structuredClone(state),
221
+ createdAt: new Date().toISOString(),
222
+ });
223
+ return undefined;
224
+ }
225
+ catch (error) {
226
+ return new WorkflowError('checkpoint_failed', `checkpoint ${String(seq)} failed to persist: ${error instanceof Error ? error.message : String(error)}`, { node, cause: error });
227
+ }
228
+ }
229
+ /** Resolve a node's executor: gate overrides swap gate executors [CLM-0045]. */
230
+ executorFor(node) {
231
+ if (node.kind === 'gate' && node.gate !== undefined) {
232
+ const gateName = this.config.nodeOverrides[node.name]?.gate ?? node.gate;
233
+ return this.executors[gateName];
234
+ }
235
+ return this.executors[node.name] ?? this.executors[node.kind];
236
+ }
237
+ specialists() {
238
+ const fanout = this.graph.nodes.find((n) => n.kind === 'fanout');
239
+ if (fanout === undefined)
240
+ return [];
241
+ return this.config.nodeOverrides[fanout.name]?.specialists ?? [];
242
+ }
243
+ finish(runId, state, childSpend) {
244
+ const retrospect = this.graph.nodes.find((n) => n.kind === 'retrospect');
245
+ return {
246
+ runId,
247
+ status: 'completed',
248
+ nodeTrace: state.trace,
249
+ outcome: state.values[retrospect?.name ?? 'retrospect'],
250
+ ...(childSpend === undefined ? {} : { childSpend }),
251
+ };
252
+ }
253
+ }
254
+ /**
255
+ * Create a loop engine over the CANONICAL_LOOP. Throws `unwired_node` if
256
+ * any executable node lacks an executor (wiring-complete or absent — a
257
+ * graph that could fail mid-run on a missing executor is a stub).
258
+ */
259
+ export function createEngine(deps) {
260
+ return new LoopEngine(deps);
261
+ }
262
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * The canonical loop as DATA (spec §6): one blessed graph, declared here and
3
+ * never duplicated. Overlays change behavior through engine config (gate
4
+ * swaps, added specialists, K) against this SAME object [CLM-0045]; the
5
+ * graph itself is frozen.
6
+ *
7
+ * Frame → Research → Plan → VOTE —approved→ Decompose
8
+ * → FanOut(children: each implement → quality gate) → Integrate
9
+ * → Retrospect
10
+ * VOTE —rejected+findings→ Plan (at most K re-entries, then escalate)
11
+ *
12
+ * EVERY edge declares the contract that crosses it [CLM-0042]; the engine
13
+ * zod-validates each node's emission against its declared contract before
14
+ * the value crosses the edge. Gate nodes always emit a Verdict.
15
+ */
16
+ import type { ContractRef } from '@kernloop/contracts';
17
+ /** Node kinds in the canonical loop (spec §6). */
18
+ export type LoopNodeKind = 'task' | 'gate' | 'decompose' | 'fanout' | 'integrate' | 'retrospect';
19
+ /** The gates the loop invokes. */
20
+ export type LoopGateName = 'vote' | 'quality' | 'review' | 'parsimony';
21
+ /**
22
+ * One node of the loop. `consumes` is the contract of the node's primary
23
+ * input (`null` for the entry node, whose input is the run's TaskContract);
24
+ * `emits` is the contract the node's output must satisfy — the engine
25
+ * validates it at the outgoing edge. Nodes whose output is a collection
26
+ * (decompose → children, fanout → child verdicts) validate element-wise.
27
+ */
28
+ export interface LoopNode {
29
+ readonly name: string;
30
+ readonly kind: LoopNodeKind;
31
+ readonly consumes: ContractRef | null;
32
+ readonly emits: ContractRef;
33
+ /** For gate nodes: which gate executor to call (overlay may swap it). */
34
+ readonly gate?: LoopGateName;
35
+ }
36
+ /**
37
+ * One edge of the loop. `contract` names which of the frozen five crosses
38
+ * it [CLM-0042]. Gate nodes branch: `when` selects the edge taken for an
39
+ * approving vs. rejecting Verdict.
40
+ */
41
+ export interface LoopEdge {
42
+ readonly from: string;
43
+ readonly to: string;
44
+ readonly contract: ContractRef;
45
+ readonly when?: 'approved' | 'rejected';
46
+ }
47
+ /** The canonical loop: main chain, branch edges, and the fan-out sub-chain. */
48
+ export interface LoopGraph {
49
+ /** Name of the entry node. */
50
+ readonly entry: string;
51
+ readonly nodes: readonly LoopNode[];
52
+ readonly edges: readonly LoopEdge[];
53
+ /**
54
+ * The per-child sub-chain run inside the fan-out node, in order. Each
55
+ * decomposed child TaskContract flows through these nodes sequentially.
56
+ */
57
+ readonly childChain: readonly LoopNode[];
58
+ }
59
+ /**
60
+ * THE canonical loop (spec §6) [CLM-0042]. Edge contracts, honestly:
61
+ *
62
+ * - frame emits the framed TaskContract (refined goal/constraints);
63
+ * - research compiles context into a Brief;
64
+ * - plan emits the plan as a Brief (a reproducible, provenance-tagged
65
+ * artifact — spec §4);
66
+ * - vote judges the plan Brief and emits a Verdict; the approved edge
67
+ * carries that Verdict into decompose, the rejected edge carries it back
68
+ * to plan (the engine feeds its findings to the plan executor and bounds
69
+ * the cycle at K re-entries [CLM-0043]);
70
+ * - decompose emits child TaskContracts (element-wise validated);
71
+ * - fanout runs each child through implement → quality → review → parsimony
72
+ * and emits the per-child Verdicts (element-wise validated); child failures travel
73
+ * alongside as structured error records — see the engine's ChildResult;
74
+ * - integrate merges child results into an Outcome;
75
+ * - retrospect closes the run with the final Outcome (memory writes and
76
+ * Observer feeds are the injected executor's job, not the engine's).
77
+ */
78
+ export declare const CANONICAL_LOOP: LoopGraph;
79
+ /** Look up a node by name in the main chain or the child sub-chain. */
80
+ export declare function nodeByName(graph: LoopGraph, name: string): LoopNode | undefined;
81
+ /**
82
+ * The successor of a node along the main chain. For gate nodes pass the
83
+ * branch taken (`approved`/`rejected`); plain nodes have exactly one
84
+ * outgoing edge. Returns undefined for the terminal node.
85
+ */
86
+ export declare function successor(graph: LoopGraph, from: string, branch?: 'approved' | 'rejected'): LoopEdge | undefined;
87
+ //# sourceMappingURL=graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,kDAAkD;AAClD,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,GAAG,YAAY,CAAC;AAEjG,kCAAkC;AAClC,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEvE;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,yEAAyE;IACzE,QAAQ,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC;CAC9B;AAED;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;CACzC;AAED,+EAA+E;AAC/E,MAAM,WAAW,SAAS;IACxB,8BAA8B;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IACpC;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,QAAQ,EAAE,CAAC;CAC1C;AAYD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,cAAc,EAAE,SA4B3B,CAAC;AAEH,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAE/E;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,SAAS,EAChB,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,UAAU,GAAG,UAAU,GAC/B,QAAQ,GAAG,SAAS,CAEtB"}
package/dist/graph.js ADDED
@@ -0,0 +1,72 @@
1
+ /** Deep-freeze a graph so the canonical loop is immutable data. */
2
+ function freezeGraph(graph) {
3
+ for (const node of [...graph.nodes, ...graph.childChain])
4
+ Object.freeze(node);
5
+ for (const edge of graph.edges)
6
+ Object.freeze(edge);
7
+ Object.freeze(graph.nodes);
8
+ Object.freeze(graph.edges);
9
+ Object.freeze(graph.childChain);
10
+ return Object.freeze(graph);
11
+ }
12
+ /**
13
+ * THE canonical loop (spec §6) [CLM-0042]. Edge contracts, honestly:
14
+ *
15
+ * - frame emits the framed TaskContract (refined goal/constraints);
16
+ * - research compiles context into a Brief;
17
+ * - plan emits the plan as a Brief (a reproducible, provenance-tagged
18
+ * artifact — spec §4);
19
+ * - vote judges the plan Brief and emits a Verdict; the approved edge
20
+ * carries that Verdict into decompose, the rejected edge carries it back
21
+ * to plan (the engine feeds its findings to the plan executor and bounds
22
+ * the cycle at K re-entries [CLM-0043]);
23
+ * - decompose emits child TaskContracts (element-wise validated);
24
+ * - fanout runs each child through implement → quality → review → parsimony
25
+ * and emits the per-child Verdicts (element-wise validated); child failures travel
26
+ * alongside as structured error records — see the engine's ChildResult;
27
+ * - integrate merges child results into an Outcome;
28
+ * - retrospect closes the run with the final Outcome (memory writes and
29
+ * Observer feeds are the injected executor's job, not the engine's).
30
+ */
31
+ export const CANONICAL_LOOP = freezeGraph({
32
+ entry: 'frame',
33
+ nodes: [
34
+ { name: 'frame', kind: 'task', consumes: null, emits: 'TaskContract' },
35
+ { name: 'research', kind: 'task', consumes: 'TaskContract', emits: 'Brief' },
36
+ { name: 'plan', kind: 'task', consumes: 'Brief', emits: 'Brief' },
37
+ { name: 'vote', kind: 'gate', consumes: 'Brief', emits: 'Verdict', gate: 'vote' },
38
+ { name: 'decompose', kind: 'decompose', consumes: 'Verdict', emits: 'TaskContract' },
39
+ { name: 'fanout', kind: 'fanout', consumes: 'TaskContract', emits: 'Verdict' },
40
+ { name: 'integrate', kind: 'integrate', consumes: 'Verdict', emits: 'Outcome' },
41
+ { name: 'retrospect', kind: 'retrospect', consumes: 'Outcome', emits: 'Outcome' },
42
+ ],
43
+ edges: [
44
+ { from: 'frame', to: 'research', contract: 'TaskContract' },
45
+ { from: 'research', to: 'plan', contract: 'Brief' },
46
+ { from: 'plan', to: 'vote', contract: 'Brief' },
47
+ { from: 'vote', to: 'decompose', contract: 'Verdict', when: 'approved' },
48
+ { from: 'vote', to: 'plan', contract: 'Verdict', when: 'rejected' },
49
+ { from: 'decompose', to: 'fanout', contract: 'TaskContract' },
50
+ { from: 'fanout', to: 'integrate', contract: 'Verdict' },
51
+ { from: 'integrate', to: 'retrospect', contract: 'Outcome' },
52
+ ],
53
+ childChain: [
54
+ { name: 'implement', kind: 'task', consumes: 'TaskContract', emits: 'Outcome' },
55
+ { name: 'quality', kind: 'gate', consumes: 'Outcome', emits: 'Verdict', gate: 'quality' },
56
+ { name: 'review', kind: 'gate', consumes: 'Outcome', emits: 'Verdict', gate: 'review' },
57
+ { name: 'parsimony', kind: 'gate', consumes: 'Outcome', emits: 'Verdict', gate: 'parsimony' },
58
+ ],
59
+ });
60
+ /** Look up a node by name in the main chain or the child sub-chain. */
61
+ export function nodeByName(graph, name) {
62
+ return graph.nodes.find((n) => n.name === name) ?? graph.childChain.find((n) => n.name === name);
63
+ }
64
+ /**
65
+ * The successor of a node along the main chain. For gate nodes pass the
66
+ * branch taken (`approved`/`rejected`); plain nodes have exactly one
67
+ * outgoing edge. Returns undefined for the terminal node.
68
+ */
69
+ export function successor(graph, from, branch) {
70
+ return graph.edges.find((e) => e.from === from && (e.when === undefined || e.when === branch));
71
+ }
72
+ //# sourceMappingURL=graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @kernloop/workflows — Layer 3 (spec §2, §6): the canonical loop as data
3
+ * plus the execution engine. One blessed graph [CLM-0042]; a K-bounded
4
+ * vote-iterate cycle [CLM-0043]; per-node checkpoints making any run
5
+ * resumable [CLM-0044]; overlay-shaped config overriding gates and
6
+ * specialists against the same graph object [CLM-0045].
7
+ */
8
+ export { CANONICAL_LOOP, nodeByName, successor, type LoopGraph, type LoopNode, type LoopEdge, type LoopNodeKind, type LoopGateName, } from './graph.js';
9
+ export { createEngine, EngineConfigSchema, BudgetModeSchema, type Engine, type EngineConfig, type EngineConfigInput, type EngineDeps, type NodeContext, type NodeExecutor, type RunOptions, type BudgetGuard, type BudgetMode, type ChildIterateEvent, } from './engine.js';
10
+ export { InMemoryCheckpointStore, JsonlCheckpointStore, type CheckpointStore, } from './checkpoints.js';
11
+ export { CheckpointRecordSchema, ChildResultSchema, CursorSchema, RunStateSchema, TraceEntrySchema, WorkflowError, type CheckpointRecord, type ChildResult, type Cursor, type RunResult, type RunState, type TraceEntry, type WorkflowErrorCode, } from './state.js';
12
+ export { workflowsManifest } from './manifest.js';
13
+ export { verdictDisposition, type VerdictDisposition } from './verdict-disposition.js';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,cAAc,EACd,UAAU,EACV,SAAS,EACT,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,iBAAiB,GACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @kernloop/workflows — Layer 3 (spec §2, §6): the canonical loop as data
3
+ * plus the execution engine. One blessed graph [CLM-0042]; a K-bounded
4
+ * vote-iterate cycle [CLM-0043]; per-node checkpoints making any run
5
+ * resumable [CLM-0044]; overlay-shaped config overriding gates and
6
+ * specialists against the same graph object [CLM-0045].
7
+ */
8
+ export { CANONICAL_LOOP, nodeByName, successor, } from './graph.js';
9
+ export { createEngine, EngineConfigSchema, BudgetModeSchema, } from './engine.js';
10
+ export { InMemoryCheckpointStore, JsonlCheckpointStore, } from './checkpoints.js';
11
+ export { CheckpointRecordSchema, ChildResultSchema, CursorSchema, RunStateSchema, TraceEntrySchema, WorkflowError, } from './state.js';
12
+ export { workflowsManifest } from './manifest.js';
13
+ export { verdictDisposition } from './verdict-disposition.js';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,cAAc,EACd,UAAU,EACV,SAAS,GAMV,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,GAWjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,uBAAuB,EACvB,oBAAoB,GAErB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,aAAa,GAQd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAA2B,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The workflows package's registration record (spec §4). Kind is
3
+ * `strategy`: the canonical loop is strategy-as-data (spec §2 lists L3 as
4
+ * "data: graphs"), not an L2 plugin — `faculty` would claim a peer of
5
+ * compiler/memory/gates, `gate` and `agentTemplate` are roles the loop
6
+ * INVOKES, and skills/workshopTools are something else entirely. Of the
7
+ * frozen ManifestKind values, `strategy` is the honest one.
8
+ */
9
+ import { type Manifest } from '@kernloop/contracts';
10
+ /**
11
+ * The workflows registration manifest. Consumes a TaskContract (the run
12
+ * entry), emits an Outcome (retrospect's close). Tier `suggest`: the engine
13
+ * orchestrates and proposes; every blocking decision inside the loop is a
14
+ * gate's, under the gate's own tier. Zero token cost — the engine never
15
+ * calls a model (all work is injected executors); latency is dominated by
16
+ * the executors themselves.
17
+ */
18
+ export declare const workflowsManifest: Manifest;
19
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpE;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,QAuB9B,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The workflows package's registration record (spec §4). Kind is
3
+ * `strategy`: the canonical loop is strategy-as-data (spec §2 lists L3 as
4
+ * "data: graphs"), not an L2 plugin — `faculty` would claim a peer of
5
+ * compiler/memory/gates, `gate` and `agentTemplate` are roles the loop
6
+ * INVOKES, and skills/workshopTools are something else entirely. Of the
7
+ * frozen ManifestKind values, `strategy` is the honest one.
8
+ */
9
+ import { ManifestSchema } from '@kernloop/contracts';
10
+ /**
11
+ * The workflows registration manifest. Consumes a TaskContract (the run
12
+ * entry), emits an Outcome (retrospect's close). Tier `suggest`: the engine
13
+ * orchestrates and proposes; every blocking decision inside the loop is a
14
+ * gate's, under the gate's own tier. Zero token cost — the engine never
15
+ * calls a model (all work is injected executors); latency is dominated by
16
+ * the executors themselves.
17
+ */
18
+ export const workflowsManifest = ManifestSchema.parse({
19
+ name: '@kernloop/workflows',
20
+ version: '0.1.0',
21
+ kind: 'strategy',
22
+ capabilities: [
23
+ {
24
+ name: 'workflow.canonical',
25
+ description: 'Run the canonical loop (spec §6) over injected executors with per-node checkpoint/resume and the K-bounded vote-iterate cycle',
26
+ },
27
+ ],
28
+ contracts: {
29
+ consumes: ['TaskContract'],
30
+ emits: ['Outcome'],
31
+ },
32
+ cost: {
33
+ tokens: 0,
34
+ usd: 0,
35
+ latencyMs: 0,
36
+ },
37
+ tier: 'suggest',
38
+ claims: ['CLM-0042', 'CLM-0043', 'CLM-0044', 'CLM-0045'],
39
+ maturity: 'stable',
40
+ });
41
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,cAAc,EAAiB,MAAM,qBAAqB,CAAC;AAEpE;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAa,cAAc,CAAC,KAAK,CAAC;IAC9D,IAAI,EAAE,qBAAqB;IAC3B,OAAO,EAAE,OAAO;IAChB,IAAI,EAAE,UAAU;IAChB,YAAY,EAAE;QACZ;YACE,IAAI,EAAE,oBAAoB;YAC1B,WAAW,EACT,+HAA+H;SAClI;KACF;IACD,SAAS,EAAE;QACT,QAAQ,EAAE,CAAC,cAAc,CAAC;QAC1B,KAAK,EAAE,CAAC,SAAS,CAAC;KACnB;IACD,IAAI,EAAE;QACJ,MAAM,EAAE,CAAC;QACT,GAAG,EAAE,CAAC;QACN,SAAS,EAAE,CAAC;KACb;IACD,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC;IACxD,QAAQ,EAAE,QAAQ;CACnB,CAAC,CAAC"}