@rulvar/plan 1.3.0 → 1.3.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/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # @rulvar/plan
2
+
3
+ The adaptive orchestration extension for dynamic rulvar runs:
4
+ `PlanRunner` treats the task plan as typed, engine-owned data with
5
+ journaled revisions, reuse, escalations, and model ladders. Built
6
+ entirely on the public core API. Exports `planRunner`,
7
+ `orchestratePlanned`, and `buildPlanTools`.
8
+
9
+ The one-line mnemonic against its sibling: `@rulvar/planner` plans
10
+ before the run (it writes the script); `@rulvar/plan` replans during the
11
+ run (it revises the task plan).
12
+
13
+ Part of [rulvar](https://rulvar.com), an embeddable TypeScript engine
14
+ for durable, budget-bounded multi-agent LLM workflows, where a completed
15
+ LLM call is never paid for twice. Full documentation:
16
+ [docs.rulvar.com](https://docs.rulvar.com).
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ pnpm add @rulvar/core @rulvar/plan
22
+ ```
23
+
24
+ ## Documentation
25
+
26
+ - [Adaptive orchestration](https://docs.rulvar.com/guide/adaptive-orchestration)
27
+ - [Orchestration modes](https://docs.rulvar.com/guide/orchestration-modes)
28
+ - [API reference](https://docs.rulvar.com/api/%40rulvar/plan/)
29
+
30
+ ## License
31
+
32
+ [Apache-2.0](https://github.com/o-stepper/rulvar/blob/main/LICENSE)
package/dist/index.js CHANGED
@@ -60,7 +60,7 @@ function isTerminalPlanStatus(status) {
60
60
  * (never a silent brick).
61
61
  */
62
62
  function assertPlanTransition(node, to) {
63
- if (isTerminalPlanStatus(node.status)) throw new PlanInvariantError(`plan node ${node.nodeId} is terminal '${node.status}' and cannot become '${to}' (docs/07, 3.1: the status machine is closed and 'done' is immutable)`, { data: {
63
+ if (isTerminalPlanStatus(node.status)) throw new PlanInvariantError(`plan node ${node.nodeId} is terminal '${node.status}' and cannot become '${to}' (the status machine is closed and 'done' is immutable)`, { data: {
64
64
  nodeId: node.nodeId,
65
65
  from: node.status,
66
66
  to
@@ -70,7 +70,7 @@ function assertPlanTransition(node, to) {
70
70
  from: node.status,
71
71
  to
72
72
  } });
73
- if (to === "running" && node.status !== "ready") throw new PlanInvariantError(`plan node ${node.nodeId} cannot start running from '${node.status}' (the engine schedules ready nodes only; docs/07, 3.1)`, { data: {
73
+ if (to === "running" && node.status !== "ready") throw new PlanInvariantError(`plan node ${node.nodeId} cannot start running from '${node.status}' (the engine schedules ready nodes only)`, { data: {
74
74
  nodeId: node.nodeId,
75
75
  from: node.status,
76
76
  to
@@ -335,7 +335,7 @@ function effectiveDroppedStreak(state) {
335
335
  }
336
336
  function verifyHash(entry, which, expected, plan, deriverFor) {
337
337
  const actual = planHash(plan, deriverFor?.(entry.hashVersion) ?? deriverV2);
338
- if (actual !== expected) throw new ReplayPlanHashMismatch(`plan fold ${which} mismatch at seq ${String(entry.seq)}: recomputed ${actual}, entry carries ${expected} (hashVersion ${String(entry.hashVersion)}); the resume is rejected without corrupting the journal (docs/07, 3.4)`, { data: {
338
+ if (actual !== expected) throw new ReplayPlanHashMismatch(`plan fold ${which} mismatch at seq ${String(entry.seq)}: recomputed ${actual}, entry carries ${expected} (hashVersion ${String(entry.hashVersion)}); the resume is rejected without corrupting the journal`, { data: {
339
339
  entryRef: entry.seq,
340
340
  expected,
341
341
  actual,
@@ -1267,11 +1267,11 @@ function boundLedgerRender(view, budgetChars = LEDGER_RENDER_BUDGET_CHARS) {
1267
1267
  bounded[section].shift();
1268
1268
  droppedRows += 1;
1269
1269
  }
1270
- if (droppedRows > 0) bounded.discrepancies.push(`renderBudget: dropped the ${String(droppedRows)} oldest ${section} rows (docs/06, Appendix A)`);
1270
+ if (droppedRows > 0) bounded.discrepancies.push(`renderBudget: dropped the ${String(droppedRows)} oldest ${section} rows `);
1271
1271
  if (size(bounded) <= budgetChars) return bounded;
1272
1272
  }
1273
1273
  if (bounded.brief !== void 0 && size(bounded) > budgetChars) {
1274
- bounded.discrepancies.push("renderBudget: the mission brief was sliced (docs/06, Appendix A)");
1274
+ bounded.discrepancies.push("renderBudget: the mission brief was sliced");
1275
1275
  const over = size(bounded) - budgetChars;
1276
1276
  const keep = Math.max(0, bounded.brief.text.length - over);
1277
1277
  bounded.brief = {
@@ -2139,7 +2139,7 @@ function planRunner(options) {
2139
2139
  logicalTaskId,
2140
2140
  isNew: false
2141
2141
  });
2142
- if (!debited.ok) throw new ConfigError("termination_exhausted: maxTotalSpawns reached at a reuse link (docs/07, 11.3)");
2142
+ if (!debited.ok) throw new ConfigError("termination_exhausted: maxTotalSpawns reached at a reuse link");
2143
2143
  decision = {
2144
2144
  verdict: {
2145
2145
  kind: "reuse_full",
@@ -2336,7 +2336,7 @@ function planRunner(options) {
2336
2336
  * against the per-engine registry BEFORE paying for the attempt.
2337
2337
  */
2338
2338
  const ladderDispatchFields = (node, spec, ladder) => {
2339
- for (const gate of ladder.acceptance ?? []) if (gate.kind === "mechanical" && io.gates[gate.profile] === void 0) throw new ConfigError(`mechanical gate profile '${gate.profile}' is not registered under defaults.gates (docs/07, section 10)`);
2339
+ for (const gate of ladder.acceptance ?? []) if (gate.kind === "mechanical" && io.gates[gate.profile] === void 0) throw new ConfigError(`mechanical gate profile '${gate.profile}' is not registered under defaults.gates `);
2340
2340
  const rungIndex = executingRungOf(ladder, clampStartTier(ladder, spec.model_hint?.startTier), requireAccount().rungIndexOf(node.logicalTaskId));
2341
2341
  const rung = ladder.rungs[rungIndex];
2342
2342
  if (rung === void 0) throw new ConfigError(`ladder rung ${String(rungIndex)} is undeclared`);
@@ -3178,10 +3178,10 @@ function planRunner(options) {
3178
3178
  ledgerScope: rootScope,
3179
3179
  planScope
3180
3180
  }), op);
3181
- if (violation !== void 0) throw new ConfigError(`ledger_append rejected: ${violation} (docs/06, Appendix A)`);
3181
+ if (violation !== void 0) throw new ConfigError(`ledger_append rejected: ${violation}`);
3182
3182
  if (op.op === "lesson_add") {
3183
3183
  const stats = io.admission.lineage()?.statsOf(op.key.logicalTaskId);
3184
- if (!(stats !== void 0 && stats.attemptsUsed > 0 && stats.approaches.some((approach) => approach.approachSig === op.key.approachSig))) throw new ConfigError("lesson_add rejected: the key matches no journaled attempt of that logical task (docs/07, 9.2)");
3184
+ if (!(stats !== void 0 && stats.attemptsUsed > 0 && stats.approaches.some((approach) => approach.approachSig === op.key.approachSig))) throw new ConfigError("lesson_add rejected: the key matches no journaled attempt of that logical task ");
3185
3185
  }
3186
3186
  const entry = await io.append({
3187
3187
  scope: rootScope,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/plan",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "rulvar adaptive orchestration extension: PlanRunner, RunLedger, escalation extensions, ModelLadder configuration.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -22,13 +22,13 @@
22
22
  "access": "public"
23
23
  },
24
24
  "dependencies": {
25
- "@rulvar/core": "1.3.0"
25
+ "@rulvar/core": "1.3.2"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.20.0",
29
29
  "tsdown": "^0.22.3",
30
30
  "typescript": "~6.0.3",
31
- "@rulvar/store-sqlite": "1.3.0"
31
+ "@rulvar/store-sqlite": "1.3.2"
32
32
  },
33
33
  "repository": {
34
34
  "type": "git",