@rulvar/core 1.0.0 → 1.2.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.d.ts +486 -531
- package/dist/index.js +316 -326
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
14
14
|
//#region src/l0/errors.ts
|
|
15
15
|
/**
|
|
16
16
|
* Base class for all engine-raised errors. "Retryable" means the engine's
|
|
17
|
-
* own retry machinery (RetryPolicy under the journal
|
|
17
|
+
* own retry machinery (RetryPolicy under the journal) MAY retry;
|
|
18
18
|
* it never means a provider SDK autoretry, which is disabled.
|
|
19
19
|
*/
|
|
20
20
|
var RulvarError = class extends Error {
|
|
@@ -79,8 +79,8 @@ var ScriptRejected = class extends RulvarError {
|
|
|
79
79
|
};
|
|
80
80
|
/**
|
|
81
81
|
* Refusal to open a journal whose hashVersion falls outside the engine's
|
|
82
|
-
* support window (
|
|
83
|
-
* The registry code is 'journal_compat'; the
|
|
82
|
+
* support window (producers ship in M2).
|
|
83
|
+
* The registry code is 'journal_compat'; the sub-codes live on
|
|
84
84
|
* `subCode` and in `data`.
|
|
85
85
|
*/
|
|
86
86
|
var JournalCompatibilityError = class extends RulvarError {
|
|
@@ -118,8 +118,7 @@ var JournalCompatibilityError = class extends RulvarError {
|
|
|
118
118
|
};
|
|
119
119
|
/**
|
|
120
120
|
* A resolution attempt against an already-closed suspension, rejected under
|
|
121
|
-
* the first-closing-wins fold; appends no entry (
|
|
122
|
-
* "Suspension and resolutions"; producers ship in M2).
|
|
121
|
+
* the first-closing-wins fold; appends no entry (producers ship in M2).
|
|
123
122
|
*/
|
|
124
123
|
var InvalidResolutionError = class extends RulvarError {
|
|
125
124
|
code = "invalid_resolution";
|
|
@@ -132,7 +131,7 @@ var InvalidResolutionError = class extends RulvarError {
|
|
|
132
131
|
};
|
|
133
132
|
/**
|
|
134
133
|
* A breach of the total per-run append order: an unfenced concurrent writer
|
|
135
|
-
* or a store violating contract A2 (docs/
|
|
134
|
+
* or a store violating contract A2 (https://docs.rulvar.com/guide/stores).
|
|
136
135
|
*/
|
|
137
136
|
var JournalOrderViolation = class extends RulvarError {
|
|
138
137
|
code = "journal_order_violation";
|
|
@@ -143,7 +142,7 @@ var JournalOrderViolation = class extends RulvarError {
|
|
|
143
142
|
});
|
|
144
143
|
}
|
|
145
144
|
};
|
|
146
|
-
/** PlanRunner plan-invariant rejection (
|
|
145
|
+
/** PlanRunner plan-invariant rejection (producers ship in M7). */
|
|
147
146
|
var PlanInvariantError = class extends RulvarError {
|
|
148
147
|
code = "plan_invariant";
|
|
149
148
|
constructor(message, opts) {
|
|
@@ -155,7 +154,7 @@ var PlanInvariantError = class extends RulvarError {
|
|
|
155
154
|
};
|
|
156
155
|
/**
|
|
157
156
|
* Raised at resume when the refolded plan state disagrees with the
|
|
158
|
-
* journaled planHash chain (
|
|
157
|
+
* journaled planHash chain (producers ship in M7).
|
|
159
158
|
*/
|
|
160
159
|
var ReplayPlanHashMismatch = class extends RulvarError {
|
|
161
160
|
code = "replay_plan_hash_mismatch";
|
|
@@ -168,8 +167,7 @@ var ReplayPlanHashMismatch = class extends RulvarError {
|
|
|
168
167
|
};
|
|
169
168
|
/**
|
|
170
169
|
* Invalid orchestrator cap and finalize-reserve configuration, thrown
|
|
171
|
-
* before the first LLM call (
|
|
172
|
-
* producers ship in M6/M7).
|
|
170
|
+
* before the first LLM call (DEF-7; producers ship in M6/M7).
|
|
173
171
|
*/
|
|
174
172
|
var OrchestratorCapConfigError = class extends RulvarError {
|
|
175
173
|
code = "orchestrator_cap_config";
|
|
@@ -196,8 +194,7 @@ var JournalMissError = class extends RulvarError {
|
|
|
196
194
|
/**
|
|
197
195
|
* The run budget ceiling blocked further work. The budget guard denial is
|
|
198
196
|
* a decision entry; ctx primitives throw this as AgentError kind 'budget';
|
|
199
|
-
* the run reports outcome 'exhausted', overriding 'error'
|
|
200
|
-
* "Three-layer budget").
|
|
197
|
+
* the run reports outcome 'exhausted', overriding 'error'.
|
|
201
198
|
*/
|
|
202
199
|
var BudgetExhaustedError = class extends RulvarError {
|
|
203
200
|
code = "budget_exhausted";
|
|
@@ -210,13 +207,12 @@ var BudgetExhaustedError = class extends RulvarError {
|
|
|
210
207
|
};
|
|
211
208
|
/**
|
|
212
209
|
* A structural admission rejection (maxDepth, maxChildrenPerNode,
|
|
213
|
-
* maxTotalSpawns) from the AdmissionController (
|
|
214
|
-
* "AdmissionController"; M6-T06). The rejection verdict is embedded in
|
|
210
|
+
* maxTotalSpawns) from the AdmissionController (M6-T06). The rejection verdict is embedded in
|
|
215
211
|
* the carrying spawn-admission decision entry and replays identically;
|
|
216
212
|
* the error surfaces the embedded AdmitRejectReason in `data` to the
|
|
217
213
|
* caller (a typed tool error for orchestrators) and MUST NOT tear down
|
|
218
214
|
* the run. Budget-code rejections throw BudgetExhaustedError instead,
|
|
219
|
-
* keeping the
|
|
215
|
+
* keeping the budget exhaustion semantics (https://docs.rulvar.com/guide/budgets).
|
|
220
216
|
*/
|
|
221
217
|
var AdmissionRejectedError = class extends RulvarError {
|
|
222
218
|
code = "admission_rejected";
|
|
@@ -228,8 +224,8 @@ var AdmissionRejectedError = class extends RulvarError {
|
|
|
228
224
|
}
|
|
229
225
|
};
|
|
230
226
|
/**
|
|
231
|
-
* A WorkerSandboxRunner resource-limit breach (
|
|
232
|
-
*
|
|
227
|
+
* A WorkerSandboxRunner resource-limit breach (M6-T02): crossing
|
|
228
|
+
* timeoutMs or memoryMb terminates the worker and the
|
|
233
229
|
* run completes with outcome 'error' carrying this error's WireError
|
|
234
230
|
* projection; `data` records { reason: 'timeout' | 'memory', limit }.
|
|
235
231
|
* The class itself is never journaled as an entry of its own.
|
|
@@ -245,8 +241,7 @@ var SandboxError = class extends RulvarError {
|
|
|
245
241
|
};
|
|
246
242
|
/**
|
|
247
243
|
* acquire() on a currently held lease. Retryable by contract: retry after
|
|
248
|
-
* the lease ttl elapses or the holder releases
|
|
249
|
-
* "Storage SPI").
|
|
244
|
+
* the lease ttl elapses or the holder releases.
|
|
250
245
|
*/
|
|
251
246
|
var LeaseHeldError = class extends RulvarError {
|
|
252
247
|
code = "lease_held";
|
|
@@ -260,8 +255,7 @@ var LeaseHeldError = class extends RulvarError {
|
|
|
260
255
|
/**
|
|
261
256
|
* commit() on a ModelKnowledgeStore against a snapshot version that is
|
|
262
257
|
* no longer current. Retryable by contract: re-read current(), rebase
|
|
263
|
-
* the ops, commit again, mirroring the lease fencing discipline
|
|
264
|
-
* (docs/05, section "Commit discipline").
|
|
258
|
+
* the ops, commit again, mirroring the lease fencing discipline.
|
|
265
259
|
*/
|
|
266
260
|
var KnowledgeCasError = class extends RulvarError {
|
|
267
261
|
code = "knowledge_cas";
|
|
@@ -274,8 +268,8 @@ var KnowledgeCasError = class extends RulvarError {
|
|
|
274
268
|
};
|
|
275
269
|
/**
|
|
276
270
|
* Projects an AgentError to its WireError form: code 'agent', with kind,
|
|
277
|
-
* retryAfterMs, and issues carried in data
|
|
278
|
-
*
|
|
271
|
+
* retryAfterMs, and issues carried in data. Issue paths are flattened to
|
|
272
|
+
* JSON-safe segments.
|
|
279
273
|
*/
|
|
280
274
|
function agentErrorToWire(error, message) {
|
|
281
275
|
const data = { kind: error.kind };
|
|
@@ -319,8 +313,7 @@ function agentErrorFromWire(wire) {
|
|
|
319
313
|
//#region src/l0/serialization.ts
|
|
320
314
|
/**
|
|
321
315
|
* The L0 serialization hook and the default secret-masking policy
|
|
322
|
-
* (M8-T04;
|
|
323
|
-
* "Redaction and sensitive data"; OQ-20/OQ-22 interim rules executed).
|
|
316
|
+
* (M8-T04; OQ-20/OQ-22 interim rules executed).
|
|
324
317
|
*
|
|
325
318
|
* The hook is the single policy point between the engine and
|
|
326
319
|
* persistence: redact/encrypt at the append and put boundaries,
|
|
@@ -336,13 +329,13 @@ function agentErrorFromWire(wire) {
|
|
|
336
329
|
* emitted WorkflowEvent passes it (opt out per engine via
|
|
337
330
|
* `redaction: { maskEvents: false }`); the OTel exporter applies it to
|
|
338
331
|
* string attributes. It masks strings that look like credentials; it is
|
|
339
|
-
* deliberately conservative (
|
|
332
|
+
* deliberately conservative (the pattern set is
|
|
340
333
|
* tuned on dogfood payloads, OQ-22 stays open for that).
|
|
341
334
|
*/
|
|
342
335
|
/**
|
|
343
336
|
* The kernel orders and matches on these BEFORE values are consulted;
|
|
344
337
|
* a hook that rewrites them would corrupt replay silently, so drift is
|
|
345
|
-
* a loud ConfigError at the boundary
|
|
338
|
+
* a loud ConfigError at the boundary.
|
|
346
339
|
*/
|
|
347
340
|
const PINNED_FIELDS = [
|
|
348
341
|
"hashVersion",
|
|
@@ -543,8 +536,7 @@ function monotonicUlidFactory(options) {
|
|
|
543
536
|
//#region src/l0/messages.ts
|
|
544
537
|
/**
|
|
545
538
|
* Returns a per-engine minter of CanonicalId values. Monotonic within the
|
|
546
|
-
* factory instance; never a module-level singleton (
|
|
547
|
-
* "Dependency rules": no module state).
|
|
539
|
+
* factory instance; never a module-level singleton (no module state).
|
|
548
540
|
*/
|
|
549
541
|
function createCanonicalIdMinter(options) {
|
|
550
542
|
return monotonicUlidFactory(options);
|
|
@@ -1442,8 +1434,7 @@ var Validator = class {
|
|
|
1442
1434
|
/**
|
|
1443
1435
|
* RFC 8785 (JSON Canonicalization Scheme) serializer.
|
|
1444
1436
|
*
|
|
1445
|
-
* Backs content-key derivation and schema hashing
|
|
1446
|
-
* "Identity model" and "schemaHash and toolsetHash derivation"):
|
|
1437
|
+
* Backs content-key derivation and schema hashing:
|
|
1447
1438
|
* lexicographically sorted object members (UTF-16 code units), minimal
|
|
1448
1439
|
* escaping, no insignificant whitespace, ECMAScript number formatting.
|
|
1449
1440
|
*
|
|
@@ -1488,8 +1479,8 @@ function jcsSerialize(value) {
|
|
|
1488
1479
|
* SchemaSpec, Out<S> inference, JSON Schema projection, canonical schema
|
|
1489
1480
|
* derivation, and the schemaHash/toolsetHash functions (M1-T03).
|
|
1490
1481
|
*
|
|
1491
|
-
*
|
|
1492
|
-
* docs/
|
|
1482
|
+
* Public contracts: https://docs.rulvar.com/guide/tools (SchemaSpec) and
|
|
1483
|
+
* https://docs.rulvar.com/guide/journal (hash derivation).
|
|
1493
1484
|
*/
|
|
1494
1485
|
/**
|
|
1495
1486
|
* Form-1 guard: the value implements the Standard Schema interface. Some
|
|
@@ -1504,8 +1495,7 @@ function isSchemaPairSpec(spec) {
|
|
|
1504
1495
|
return typeof spec === "object" && spec !== null && !("~standard" in spec) && "jsonSchema" in spec && typeof spec.validate === "function";
|
|
1505
1496
|
}
|
|
1506
1497
|
/**
|
|
1507
|
-
* Derives the JSON Schema of a SchemaSpec
|
|
1508
|
-
* derivation and acceptance rules"). Form 1 projects via the
|
|
1498
|
+
* Derives the JSON Schema of a SchemaSpec. Form 1 projects via the
|
|
1509
1499
|
* StandardJSONSchemaV1 input() converter, target draft 2020-12 with
|
|
1510
1500
|
* draft-07 fallback; a library without the projection is a typed
|
|
1511
1501
|
* ConfigError at definition time, never at first call. Transforming
|
|
@@ -1532,8 +1522,7 @@ function projectToJsonSchema(spec) {
|
|
|
1532
1522
|
}
|
|
1533
1523
|
/**
|
|
1534
1524
|
* Annotation-only keywords stripped by canonicalization; `format` is
|
|
1535
|
-
* retained because it is validation-relevant in the vendored validator
|
|
1536
|
-
* (docs/03, section "schemaHash and toolsetHash derivation").
|
|
1525
|
+
* retained because it is validation-relevant in the vendored validator.
|
|
1537
1526
|
*/
|
|
1538
1527
|
const ANNOTATION_KEYWORDS = /* @__PURE__ */ new Set([
|
|
1539
1528
|
"title",
|
|
@@ -1577,8 +1566,7 @@ const SUBSCHEMA_ARRAY_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
1577
1566
|
/**
|
|
1578
1567
|
* Keywords that are pure reference infrastructure: dead weight once every
|
|
1579
1568
|
* local $ref has been inlined, removed from the canonical form so that a
|
|
1580
|
-
* $defs rename or an unused definition never shifts a content key
|
|
1581
|
-
* (docs/03, section "schemaHash and toolsetHash derivation").
|
|
1569
|
+
* $defs rename or an unused definition never shifts a content key.
|
|
1582
1570
|
*/
|
|
1583
1571
|
const REF_INFRASTRUCTURE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
1584
1572
|
"$defs",
|
|
@@ -1652,8 +1640,7 @@ function canonicalizeNode(node, root, refStack) {
|
|
|
1652
1640
|
return out;
|
|
1653
1641
|
}
|
|
1654
1642
|
/**
|
|
1655
|
-
* Canonical schema derivation
|
|
1656
|
-
* toolsetHash derivation"): local fragment-only $ref inlined (recursion is
|
|
1643
|
+
* Canonical schema derivation: local fragment-only $ref inlined (recursion is
|
|
1657
1644
|
* a ConfigError), remote and dynamic references forbidden, annotation
|
|
1658
1645
|
* keywords stripped (format retained), reference infrastructure ($defs,
|
|
1659
1646
|
* definitions, $anchor) removed once inlined. The result feeds JCS
|
|
@@ -1667,8 +1654,7 @@ function sha256Hex$3(text) {
|
|
|
1667
1654
|
}
|
|
1668
1655
|
/**
|
|
1669
1656
|
* The schemaHash used when no structured-output schema is declared: the
|
|
1670
|
-
* hash of the canonical `true` schema
|
|
1671
|
-
* toolsetHash derivation").
|
|
1657
|
+
* hash of the canonical `true` schema.
|
|
1672
1658
|
*/
|
|
1673
1659
|
const EMPTY_SCHEMA_HASH = sha256Hex$3("true");
|
|
1674
1660
|
/** The toolsetHash of an empty toolset: the hash of the canonical empty contract array. */
|
|
@@ -1691,8 +1677,7 @@ function schemaHashOfSpec(spec) {
|
|
|
1691
1677
|
* contract tuples (name, description, canonical parameters, version)
|
|
1692
1678
|
* sorted by name. Tool description IS part of the contract; schema
|
|
1693
1679
|
* annotations inside parameters are not. An absent version participates as
|
|
1694
|
-
* absent
|
|
1695
|
-
* docs/08, section "toolsetHash contract").
|
|
1680
|
+
* absent.
|
|
1696
1681
|
*/
|
|
1697
1682
|
function toolsetHash(contracts) {
|
|
1698
1683
|
return sha256Hex$3(jcsSerialize([...contracts].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0).map((contract) => {
|
|
@@ -1714,7 +1699,7 @@ function pointerToPath(instanceLocation) {
|
|
|
1714
1699
|
});
|
|
1715
1700
|
}
|
|
1716
1701
|
/**
|
|
1717
|
-
* Runtime validation per form
|
|
1702
|
+
* Runtime validation per form:
|
|
1718
1703
|
* form 1 via the Standard Schema's own validate, form 2 via the pair's
|
|
1719
1704
|
* type guard, form 3 via the vendored draft 2020-12 validator. The same
|
|
1720
1705
|
* machinery backs the structured-output tiers of the Agent Runtime.
|
|
@@ -1767,8 +1752,7 @@ const CURRENT_HASH_VERSION = 2;
|
|
|
1767
1752
|
/**
|
|
1768
1753
|
* Round-1 normalization: hashVersion is taken from `hashVersion`, else
|
|
1769
1754
|
* from the legacy `v` field, else 1. Stores are never rewritten;
|
|
1770
|
-
* normalization happens at read
|
|
1771
|
-
* mechanism").
|
|
1755
|
+
* normalization happens at read.
|
|
1772
1756
|
*/
|
|
1773
1757
|
function normalizeEntry(raw) {
|
|
1774
1758
|
const record = raw;
|
|
@@ -1783,15 +1767,15 @@ function normalizeEntry(raw) {
|
|
|
1783
1767
|
//#endregion
|
|
1784
1768
|
//#region src/knowledge/decay.ts
|
|
1785
1769
|
/**
|
|
1786
|
-
* Grounding and decay (M11-T03
|
|
1787
|
-
*
|
|
1770
|
+
* Grounding and decay (M11-T03). The decay owner: the asymmetric
|
|
1771
|
+
* TTL table, the expiry
|
|
1788
1772
|
* filter the read path applies at every pin AND repin (M10-T03), the
|
|
1789
1773
|
* re-measurement queue (a STATUS FILTER, not infrastructure), and the
|
|
1790
1774
|
* archive-never-delete maintenance helpers (historical runs keep their
|
|
1791
1775
|
* audit trail).
|
|
1792
1776
|
*/
|
|
1793
1777
|
/**
|
|
1794
|
-
* The asymmetric TTL table
|
|
1778
|
+
* The asymmetric TTL table:
|
|
1795
1779
|
* a false negative is costlier through lock-in, so weaknesses expire
|
|
1796
1780
|
* sooner than strengths.
|
|
1797
1781
|
*/
|
|
@@ -1807,14 +1791,14 @@ const CLAIM_TTL_DAYS = {
|
|
|
1807
1791
|
};
|
|
1808
1792
|
/** Inbox proposals expire after 14 days (reserved for M12 phase 3). */
|
|
1809
1793
|
const INBOX_PROPOSAL_TTL_DAYS = 14;
|
|
1810
|
-
/** The
|
|
1794
|
+
/** The asymmetric TTL applied to an observedAt ISO date. */
|
|
1811
1795
|
function claimExpiry(claimClass, polarity, observedAt) {
|
|
1812
1796
|
const base = Date.parse(observedAt);
|
|
1813
1797
|
if (Number.isNaN(base)) throw new ConfigError(`claimExpiry: observedAt is not a date: '${observedAt}'`);
|
|
1814
1798
|
const days = CLAIM_TTL_DAYS[claimClass][polarity];
|
|
1815
1799
|
return new Date(base + days * 864e5).toISOString();
|
|
1816
1800
|
}
|
|
1817
|
-
/** True when the claim steers nothing at `at` (
|
|
1801
|
+
/** True when the claim steers nothing at `at` (the read-path filter). */
|
|
1818
1802
|
function claimExpired(claim, at) {
|
|
1819
1803
|
const expiry = Date.parse(claim.expiresAt);
|
|
1820
1804
|
const now = Date.parse(at);
|
|
@@ -1824,7 +1808,7 @@ function ttlState(claim, at) {
|
|
|
1824
1808
|
return claimExpired(claim, at) ? "expired" : "holds";
|
|
1825
1809
|
}
|
|
1826
1810
|
/**
|
|
1827
|
-
* The re-measurement queue
|
|
1811
|
+
* The re-measurement queue:
|
|
1828
1812
|
* expired eval-measured claims that are still ACTIVE. Just a status
|
|
1829
1813
|
* filter: the next sweep re-measures these subjects; nothing archives
|
|
1830
1814
|
* them (archiving would empty the queue and hide the decay).
|
|
@@ -1833,9 +1817,9 @@ function remeasureQueue(claims, at) {
|
|
|
1833
1817
|
return claims.filter((claim) => claim.status === "active" && claim.class === "eval-measured" && claimExpired(claim, at));
|
|
1834
1818
|
}
|
|
1835
1819
|
/**
|
|
1836
|
-
* Deprecation maintenance (
|
|
1837
|
-
*
|
|
1838
|
-
*
|
|
1820
|
+
* Deprecation maintenance (deprecations archive claims, never delete
|
|
1821
|
+
* them, so historical runs keep their audit trail): archive ops for
|
|
1822
|
+
* every non-terminal claim of the deprecated
|
|
1839
1823
|
* models. The caller commits them under its own gate-free archive ops.
|
|
1840
1824
|
*/
|
|
1841
1825
|
function archiveDeprecatedModelOps(claims, deprecated) {
|
|
@@ -1849,8 +1833,7 @@ function archiveDeprecatedModelOps(claims, deprecated) {
|
|
|
1849
1833
|
//#endregion
|
|
1850
1834
|
//#region src/knowledge/claims.ts
|
|
1851
1835
|
/**
|
|
1852
|
-
* Claim validators, the editorial path (M10-T02
|
|
1853
|
-
* "Data model", "The human gate", "Grounding and decay"). The types
|
|
1836
|
+
* Claim validators, the editorial path (M10-T02). The types
|
|
1854
1837
|
* live with the SPI (l0/spi/knowledge.ts); this module owns the
|
|
1855
1838
|
* RUNTIME enforcement that the types promise:
|
|
1856
1839
|
*
|
|
@@ -1864,9 +1847,9 @@ function archiveDeprecatedModelOps(claims, deprecated) {
|
|
|
1864
1847
|
* - statements stay bounded, evidence stays mandatory, TTL fields stay
|
|
1865
1848
|
* coherent.
|
|
1866
1849
|
*/
|
|
1867
|
-
/**
|
|
1850
|
+
/** Appendix A: KB active-claims cap, default 8 per (model, taskClass). */
|
|
1868
1851
|
const KB_ACTIVE_CLAIMS_CAP = 8;
|
|
1869
|
-
/**
|
|
1852
|
+
/** The committed data model bound: statement <= 200 chars. */
|
|
1870
1853
|
const CLAIM_STATEMENT_MAX_CHARS = 200;
|
|
1871
1854
|
const RULED_OUT_VOCABULARY = /* @__PURE__ */ new Set([
|
|
1872
1855
|
"prompt",
|
|
@@ -1913,8 +1896,8 @@ function claimIssues(claim, path, options) {
|
|
|
1913
1896
|
return issues;
|
|
1914
1897
|
}
|
|
1915
1898
|
/**
|
|
1916
|
-
* The coherence square of the committer identity (
|
|
1917
|
-
*
|
|
1899
|
+
* The coherence square of the committer identity (M11-T01): an
|
|
1900
|
+
* eval-committer-gated claim MUST be eval-measured,
|
|
1918
1901
|
* authored by the eval pipeline, and carry metrics; anything else is
|
|
1919
1902
|
* an identity mismatch, schema-enforced.
|
|
1920
1903
|
*/
|
|
@@ -1941,7 +1924,7 @@ function claimOpIssues(op, index) {
|
|
|
1941
1924
|
return issues;
|
|
1942
1925
|
}
|
|
1943
1926
|
/**
|
|
1944
|
-
* The commit-time cap (
|
|
1927
|
+
* The commit-time cap (Appendix A): active claims per
|
|
1945
1928
|
* (model, taskClass) after the batch applies. Supersede chains keep
|
|
1946
1929
|
* only the head active by construction (applyClaimOps flips the prior
|
|
1947
1930
|
* to 'superseded'), so a supersede never grows the count.
|
|
@@ -1971,8 +1954,7 @@ function validateEditorialCommit(ops, claimsAfter, options) {
|
|
|
1971
1954
|
//#endregion
|
|
1972
1955
|
//#region src/knowledge/epoch.ts
|
|
1973
1956
|
/**
|
|
1974
|
-
* modelEpoch capture (M11-T04
|
|
1975
|
-
* decay"). An HONESTLY COARSE signal: the registry version, the
|
|
1957
|
+
* modelEpoch capture (M11-T04). An HONESTLY COARSE signal: the registry version, the
|
|
1976
1958
|
* price-table version, and the caps hash catch overt model swaps and
|
|
1977
1959
|
* deprecations; silent alias re-pointing is a documented uncaught case
|
|
1978
1960
|
* absent probes (the canary fingerprint in @rulvar/evals compensates,
|
|
@@ -1999,8 +1981,7 @@ function modelEpochOf(inputs) {
|
|
|
1999
1981
|
* FileModelKnowledgeStore (M10-T01): the default ModelKnowledgeStore, a
|
|
2000
1982
|
* single JSON file in the project (`./rulvar.models.json`),
|
|
2001
1983
|
* git-diffable, serverless, embeddable. The git review of that file IS
|
|
2002
|
-
* the human gate's medium
|
|
2003
|
-
* decision rationale"); the store itself only enforces the mechanics:
|
|
1984
|
+
* the human gate's medium; the store itself only enforces the mechanics:
|
|
2004
1985
|
* CAS by monotonic version (mirroring the lease fencing discipline),
|
|
2005
1986
|
* append-only claim evolution (supersede and archive flip status, never
|
|
2006
1987
|
* delete), and atomic replace on write.
|
|
@@ -2130,7 +2111,7 @@ var FileModelKnowledgeStore = class {
|
|
|
2130
2111
|
*
|
|
2131
2112
|
* Named strong default models live ONLY in the umbrella `rulvar`
|
|
2132
2113
|
* package config, never here: the core ships the floor mechanism, the
|
|
2133
|
-
* umbrella ships opinions
|
|
2114
|
+
* umbrella ships opinions.
|
|
2134
2115
|
*/
|
|
2135
2116
|
function violates(ref, constraint) {
|
|
2136
2117
|
if (constraint === void 0) return;
|
|
@@ -2154,11 +2135,11 @@ function checkFloors(options) {
|
|
|
2154
2135
|
}
|
|
2155
2136
|
//#endregion
|
|
2156
2137
|
//#region src/knowledge/card.ts
|
|
2157
|
-
/**
|
|
2138
|
+
/** The KB card render budget (characters). */
|
|
2158
2139
|
const KB_CARD_RENDER_BUDGET_CHARS = 4096;
|
|
2159
2140
|
/**
|
|
2160
2141
|
* The ladders a run declares: every advertised profile whose model
|
|
2161
|
-
* spec is a ladder
|
|
2142
|
+
* spec is a ladder. The card is tier-relative to
|
|
2162
2143
|
* exactly these.
|
|
2163
2144
|
*/
|
|
2164
2145
|
function collectDeclaredLadders(profiles) {
|
|
@@ -2193,7 +2174,7 @@ function floored(model, taskClass, floors) {
|
|
|
2193
2174
|
}
|
|
2194
2175
|
}
|
|
2195
2176
|
/**
|
|
2196
|
-
* The admission filter
|
|
2177
|
+
* The admission filter: status active, unexpired at
|
|
2197
2178
|
* `now`, and the subject reachable through the run's declared ladders
|
|
2198
2179
|
* after the role-floor filter.
|
|
2199
2180
|
*/
|
|
@@ -2211,8 +2192,7 @@ function tiersOf(claim, ladders) {
|
|
|
2211
2192
|
return coordinates;
|
|
2212
2193
|
}
|
|
2213
2194
|
/**
|
|
2214
|
-
* The verified-layer compiler (M11-T06
|
|
2215
|
-
* and "Composition with the model layer"): start-tier recommendations
|
|
2195
|
+
* The verified-layer compiler (M11-T06): start-tier recommendations
|
|
2216
2196
|
* per (ladder, taskClass) compiled EXCLUSIVELY from eval-measured
|
|
2217
2197
|
* claims. A strength on a rung below the default votes down (start
|
|
2218
2198
|
* cheaper); a weakness on the default rung or below votes up. The net
|
|
@@ -2257,9 +2237,9 @@ function compileVerifiedLayer(claims, ladders) {
|
|
|
2257
2237
|
return rows;
|
|
2258
2238
|
}
|
|
2259
2239
|
/**
|
|
2260
|
-
* The deterministic card render
|
|
2240
|
+
* The deterministic card render. Pure: same filtered
|
|
2261
2241
|
* claims and ladders give byte-identical text. The render budget is
|
|
2262
|
-
*
|
|
2242
|
+
* 4096 chars; over it, the OLDEST-observed notes
|
|
2263
2243
|
* withhold first behind an explicit marker.
|
|
2264
2244
|
*/
|
|
2265
2245
|
function modelKnowledgeCard(claims, ladders, options) {
|
|
@@ -2271,6 +2251,30 @@ function modelKnowledgeCard(claims, ladders, options) {
|
|
|
2271
2251
|
lines.push("Verified layer (start-tier recommendations, clamped one rung from the default):");
|
|
2272
2252
|
for (const row of verified) lines.push(`- ladder '${row.ladder}', taskClass '${row.taskClass}': start tier ${String(row.recommendedTier)} (default ${String(row.defaultTier)}, eval evidence, ${String(row.votes)} claim${row.votes === 1 ? "" : "s"})`);
|
|
2273
2253
|
}
|
|
2254
|
+
const profileLines = [];
|
|
2255
|
+
for (const [name, profile] of Object.entries(options?.profiles ?? {}).sort(([left], [right]) => left < right ? -1 : 1)) {
|
|
2256
|
+
const model = profile.model;
|
|
2257
|
+
if (typeof model !== "string") continue;
|
|
2258
|
+
const matched = claims.filter((claim) => claim.class === "eval-measured" && claim.subject.model === model && (profile.effort === void 0 || claim.subject.effort === profile.effort));
|
|
2259
|
+
if (matched.length === 0) continue;
|
|
2260
|
+
const byClass = /* @__PURE__ */ new Map();
|
|
2261
|
+
for (const claim of [...matched].sort((left, right) => left.id < right.id ? -1 : 1)) {
|
|
2262
|
+
const verdict = claim.polarity === "strength" ? "strong" : "weak";
|
|
2263
|
+
const prior = byClass.get(claim.taskClass);
|
|
2264
|
+
byClass.set(claim.taskClass, prior === "weak" ? "weak" : verdict);
|
|
2265
|
+
}
|
|
2266
|
+
const strong = [...byClass.entries()].filter(([, verdict]) => verdict === "strong").map(([taskClass]) => taskClass).sort();
|
|
2267
|
+
const weak = [...byClass.entries()].filter(([, verdict]) => verdict === "weak").map(([taskClass]) => taskClass).sort();
|
|
2268
|
+
const parts = [];
|
|
2269
|
+
if (strong.length > 0) parts.push(`strong ${strong.join(", ")}`);
|
|
2270
|
+
if (weak.length > 0) parts.push(`weak ${weak.join(", ")}`);
|
|
2271
|
+
profileLines.push(`- ${name}: ${parts.join("; ")}`);
|
|
2272
|
+
}
|
|
2273
|
+
if (profileLines.length > 0) {
|
|
2274
|
+
lines.push("Profile evidence (eval-measured, folded over each profile model):");
|
|
2275
|
+
lines.push(...profileLines);
|
|
2276
|
+
lines.push("Spawn guidance: prefer the cheapest profile marked strong for the task at hand; avoid profiles marked weak at it.");
|
|
2277
|
+
}
|
|
2274
2278
|
const noteLines = claims.filter((claim) => claim.class === "human-editorial").sort((left, right) => left.observedAt === right.observedAt ? left.id < right.id ? -1 : 1 : left.observedAt < right.observedAt ? 1 : -1).map((claim) => {
|
|
2275
2279
|
return `- [${tiersOf(claim, ladders).join(", ")}] ${claim.taskClass} ${claim.polarity} (confidence ${claim.confidence}, observed ${claim.observedAt}, expires ${claim.expiresAt}): ${claim.statement}`;
|
|
2276
2280
|
});
|
|
@@ -2318,7 +2322,7 @@ function compilePermissionPreset(preset) {
|
|
|
2318
2322
|
//#endregion
|
|
2319
2323
|
//#region src/tools/shell-matcher.ts
|
|
2320
2324
|
/**
|
|
2321
|
-
* Lexes a command into segments per the
|
|
2325
|
+
* Lexes a command into segments per the matching algorithm above. Quotes
|
|
2322
2326
|
* and escapes are honored; nothing is expanded; `$(`, backticks, `<(`,
|
|
2323
2327
|
* `>(`, and `<<` (outside single quotes) poison their segment.
|
|
2324
2328
|
*/
|
|
@@ -2498,16 +2502,15 @@ function matchShellCommand(command, rules) {
|
|
|
2498
2502
|
* execute body never invalidates a journal; changing semantics is
|
|
2499
2503
|
* signaled by bumping version.
|
|
2500
2504
|
*
|
|
2501
|
-
*
|
|
2502
|
-
* definition and toolsetHash" and "SchemaSpec".
|
|
2505
|
+
* Public docs: https://docs.rulvar.com/guide/tools
|
|
2503
2506
|
*/
|
|
2504
|
-
/** First-party provider tool-name constraint intersection
|
|
2507
|
+
/** First-party provider tool-name constraint intersection. */
|
|
2505
2508
|
const TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]{1,64}$/;
|
|
2506
2509
|
/**
|
|
2507
2510
|
* Defines a tool. Definition-time failures are typed ConfigErrors, never
|
|
2508
2511
|
* first-call surprises: an illegal name, a Standard Schema without the
|
|
2509
2512
|
* JSON Schema projection, a recursive local $ref, or a remote/dynamic
|
|
2510
|
-
* reference all fail here
|
|
2513
|
+
* reference all fail here.
|
|
2511
2514
|
*/
|
|
2512
2515
|
function tool(init) {
|
|
2513
2516
|
if (!TOOL_NAME_PATTERN.test(init.name)) throw new ConfigError(`tool name '${init.name}' must match ^[a-zA-Z0-9_-]{1,64}$ (docs/08, section "tool() definition and ToolDef")`);
|
|
@@ -2526,8 +2529,7 @@ function tool(init) {
|
|
|
2526
2529
|
}
|
|
2527
2530
|
/**
|
|
2528
2531
|
* The identity projection: the contract tuple that enters toolsetHash.
|
|
2529
|
-
* parameters is the canonicalized derived JSON Schema
|
|
2530
|
-
* "schemaHash and toolsetHash derivation").
|
|
2532
|
+
* parameters is the canonicalized derived JSON Schema.
|
|
2531
2533
|
*/
|
|
2532
2534
|
function toolContract(def) {
|
|
2533
2535
|
const parameters = canonicalizeSchema(projectToJsonSchema(def.parameters));
|
|
@@ -2549,8 +2551,7 @@ function toolContract(def) {
|
|
|
2549
2551
|
* for the agent's lifetime; provider-side drift of a source's tools
|
|
2550
2552
|
* changes the content key of NEW spawns only.
|
|
2551
2553
|
*
|
|
2552
|
-
*
|
|
2553
|
-
* contract", "ToolSource seam", and "Filtering and prefixing".
|
|
2554
|
+
* Docs: https://docs.rulvar.com/guide/tools.
|
|
2554
2555
|
*/
|
|
2555
2556
|
/** The empty toolset (no tools declared anywhere). */
|
|
2556
2557
|
function emptyToolset() {
|
|
@@ -2565,8 +2566,8 @@ function isToolDef(spec) {
|
|
|
2565
2566
|
}
|
|
2566
2567
|
/**
|
|
2567
2568
|
* Expands sources, validates every tool name and duplicate names across
|
|
2568
|
-
* the whole toolset (ConfigError at spawn time
|
|
2569
|
-
*
|
|
2569
|
+
* the whole toolset (ConfigError at spawn time), and computes the
|
|
2570
|
+
* toolsetHash over contracts sorted by name.
|
|
2570
2571
|
*/
|
|
2571
2572
|
async function resolveToolset(specs, session) {
|
|
2572
2573
|
if (specs === void 0 || specs.length === 0) return emptyToolset();
|
|
@@ -2622,7 +2623,7 @@ function buildToolContext(seed) {
|
|
|
2622
2623
|
* contract. Pinned SDK line: @modelcontextprotocol/sdk ^1.29 (the v2
|
|
2623
2624
|
* migration is the explicit post-M3 task M5-T10; risk R1).
|
|
2624
2625
|
*
|
|
2625
|
-
*
|
|
2626
|
+
* Docs: https://docs.rulvar.com/guide/mcp.
|
|
2626
2627
|
*/
|
|
2627
2628
|
function validateConfig(cfg) {
|
|
2628
2629
|
const forbid = (key) => {
|
|
@@ -2674,7 +2675,7 @@ function errorText(result) {
|
|
|
2674
2675
|
* first tools() call; tools/list is fetched with cursor pagination until
|
|
2675
2676
|
* exhaustion and cached per session; a listChanged notification
|
|
2676
2677
|
* invalidates the cache, affecting subsequently spawned agents only (a
|
|
2677
|
-
* spawn's toolset snapshot is immutable by construction
|
|
2678
|
+
* spawn's toolset snapshot is immutable by construction).
|
|
2678
2679
|
*/
|
|
2679
2680
|
function mcp(cfg) {
|
|
2680
2681
|
validateConfig(cfg);
|
|
@@ -2773,13 +2774,12 @@ function mcp(cfg) {
|
|
|
2773
2774
|
* retain failed trees under the shared pin cap.
|
|
2774
2775
|
*
|
|
2775
2776
|
* The sandbox is a determinism and blast-radius boundary, NOT a security
|
|
2776
|
-
* boundary
|
|
2777
|
+
* boundary.
|
|
2777
2778
|
*
|
|
2778
|
-
*
|
|
2779
|
-
* worktree lifecycle".
|
|
2779
|
+
* Full contract: https://docs.rulvar.com/guide/tools
|
|
2780
2780
|
*/
|
|
2781
2781
|
const execFileAsync = promisify(execFile);
|
|
2782
|
-
/**
|
|
2782
|
+
/** Appendix A: the shared pin cap (park/unpark and retainWorktree). */
|
|
2783
2783
|
const DEFAULT_MAX_PINNED_WORKTREES = 4;
|
|
2784
2784
|
async function git(cwd, args) {
|
|
2785
2785
|
const { stdout } = await execFileAsync("git", [
|
|
@@ -2791,7 +2791,7 @@ async function git(cwd, args) {
|
|
|
2791
2791
|
}
|
|
2792
2792
|
/**
|
|
2793
2793
|
* The shipped git worktree lifecycle. A non-git host is a typed
|
|
2794
|
-
* ConfigError at acquire
|
|
2794
|
+
* ConfigError at acquire.
|
|
2795
2795
|
*/
|
|
2796
2796
|
var GitWorktreeProvider = class {
|
|
2797
2797
|
repoRoot;
|
|
@@ -2881,7 +2881,7 @@ var GitWorktreeProvider = class {
|
|
|
2881
2881
|
* spawn kind and content-key derivation, sha256 over RFC 8785 JCS
|
|
2882
2882
|
* canonical JSON. Frozen as part of the hashVersion 2 profile in M2.
|
|
2883
2883
|
*
|
|
2884
|
-
*
|
|
2884
|
+
* Identity model contract: https://docs.rulvar.com/guide/journal (DEF-6
|
|
2885
2885
|
* framing). Excluded from every content key: cosmetics (label, phase),
|
|
2886
2886
|
* handling policy (onError, retry, replay), policy fields
|
|
2887
2887
|
* (memoizeOutcome), lineage blocks, and spanId.
|
|
@@ -2889,8 +2889,8 @@ var GitWorktreeProvider = class {
|
|
|
2889
2889
|
/**
|
|
2890
2890
|
* The identity projection of a CanonicalModelSpec. For the plain-model
|
|
2891
2891
|
* kind the projection is `{ model, effort? }` WITHOUT the kind
|
|
2892
|
-
* discriminant, exactly as
|
|
2893
|
-
*
|
|
2892
|
+
* discriminant, exactly as frozen by the hashVersion 2 profile;
|
|
2893
|
+
* `effort` is omitted when unresolved. The ladder embedding lands
|
|
2894
2894
|
* with ladder execution (M7).
|
|
2895
2895
|
*/
|
|
2896
2896
|
function modelSpecIdentity(spec) {
|
|
@@ -2924,7 +2924,7 @@ function identityJcs(input) {
|
|
|
2924
2924
|
return jcsSerialize(projectIdentity(input));
|
|
2925
2925
|
}
|
|
2926
2926
|
/**
|
|
2927
|
-
* key = sha256(JCS(IdentityInput))
|
|
2927
|
+
* key = sha256(JCS(IdentityInput)).
|
|
2928
2928
|
*/
|
|
2929
2929
|
function deriveContentKey(input) {
|
|
2930
2930
|
return createHash("sha256").update(identityJcs(input), "utf8").digest("hex");
|
|
@@ -2936,7 +2936,7 @@ function deriveContentKey(input) {
|
|
|
2936
2936
|
* of wall-clock (invariant I3: structure comes from call-and-return only).
|
|
2937
2937
|
* The grammar is part of the hashVersion 2 profile.
|
|
2938
2938
|
*
|
|
2939
|
-
*
|
|
2939
|
+
* Full contract: https://docs.rulvar.com/guide/journal.
|
|
2940
2940
|
*
|
|
2941
2941
|
* Segment rules: a sequential body is ONE scope (sequential calls add no
|
|
2942
2942
|
* segment; they are distinguished by key and ordinal only). ctx.phase is
|
|
@@ -3071,12 +3071,12 @@ var ParallelSiteCounter = class {
|
|
|
3071
3071
|
* per-engine deriver registry, the support-window compatibility scan, and
|
|
3072
3072
|
* the versioned KeyRing for matching. A profile is immutable after
|
|
3073
3073
|
* release and versions the ENTIRE identity and replay pipeline as one
|
|
3074
|
-
* unit
|
|
3074
|
+
* unit. Full contract: https://docs.rulvar.com/guide/journal-compatibility.
|
|
3075
3075
|
*/
|
|
3076
3076
|
function sha256Hex$2(text) {
|
|
3077
3077
|
return createHash("sha256").update(text, "utf8").digest("hex");
|
|
3078
3078
|
}
|
|
3079
|
-
/** The full v2 table; the three kernel amendments live in these rules
|
|
3079
|
+
/** The full v2 table; the three kernel amendments live in these rules. */
|
|
3080
3080
|
const V2_TABLE = {
|
|
3081
3081
|
ok: "replay",
|
|
3082
3082
|
escalated: "replay",
|
|
@@ -3111,7 +3111,7 @@ const deriverV2 = {
|
|
|
3111
3111
|
budgetAccount: "root"
|
|
3112
3112
|
}
|
|
3113
3113
|
};
|
|
3114
|
-
/** Kinds that did not exist in round 1: incomparable under v1
|
|
3114
|
+
/** Kinds that did not exist in round 1: incomparable under v1. */
|
|
3115
3115
|
const V1_INEXPRESSIBLE_KINDS = /* @__PURE__ */ new Set([
|
|
3116
3116
|
"decision",
|
|
3117
3117
|
"plan.revision",
|
|
@@ -3159,8 +3159,8 @@ function isKeyDeriver(value) {
|
|
|
3159
3159
|
}
|
|
3160
3160
|
/**
|
|
3161
3161
|
* Builds the per-engine deriver registry: the shipped v1/v2 profiles plus
|
|
3162
|
-
* EngineOptions.extraDerivers, the ONLY window extender
|
|
3163
|
-
*
|
|
3162
|
+
* EngineOptions.extraDerivers, the ONLY window extender. A malformed
|
|
3163
|
+
* extra deriver is a ConfigError before any run effect.
|
|
3164
3164
|
*/
|
|
3165
3165
|
function buildDeriverRegistry(extraDerivers) {
|
|
3166
3166
|
const registry = /* @__PURE__ */ new Map([[deriverV1.hashVersion, deriverV1], [deriverV2.hashVersion, deriverV2]]);
|
|
@@ -3173,7 +3173,7 @@ function buildDeriverRegistry(extraDerivers) {
|
|
|
3173
3173
|
/**
|
|
3174
3174
|
* The one compatibility scan: immediately after load, strictly BEFORE any
|
|
3175
3175
|
* live call, any append, and any admission reserve; repeated at lease
|
|
3176
|
-
* acquire in queue mode
|
|
3176
|
+
* acquire in queue mode. Side-effect free.
|
|
3177
3177
|
*/
|
|
3178
3178
|
function scanJournalCompatibility(runId, entries, registry) {
|
|
3179
3179
|
const versions = [...registry.keys()];
|
|
@@ -3197,8 +3197,7 @@ function scanJournalCompatibility(runId, entries, registry) {
|
|
|
3197
3197
|
}
|
|
3198
3198
|
/**
|
|
3199
3199
|
* KeyRing over the registry: the live call is projected DOWN into the
|
|
3200
|
-
* profile of the stored entry; there is no upward canonization
|
|
3201
|
-
* section 4.7).
|
|
3200
|
+
* profile of the stored entry; there is no upward canonization.
|
|
3202
3201
|
*/
|
|
3203
3202
|
function registryKeyRing(registry) {
|
|
3204
3203
|
return { keyFor(identity, hashVersion) {
|
|
@@ -3219,11 +3218,11 @@ function registryKeyRing(registry) {
|
|
|
3219
3218
|
* addressable); step 2 applies the per-status table of the ENTRY'S OWN
|
|
3220
3219
|
* hashVersion profile, carrying the three kernel amendments:
|
|
3221
3220
|
* memoizeOutcome on task-class failures, abandon-derived skipped, and
|
|
3222
|
-
* escalated-replays-as-ok (docs/
|
|
3221
|
+
* escalated-replays-as-ok (https://docs.rulvar.com/guide/journal).
|
|
3223
3222
|
*/
|
|
3224
3223
|
/**
|
|
3225
3224
|
* task-class: schema-mismatch, terminal, non-retryable tool. transport,
|
|
3226
|
-
* rate-limit, and budget are never memoized
|
|
3225
|
+
* rate-limit, and budget are never memoized.
|
|
3227
3226
|
*/
|
|
3228
3227
|
function classifyAgentError(e) {
|
|
3229
3228
|
if (e.kind === "schema-mismatch" || e.kind === "terminal") return "task";
|
|
@@ -3232,7 +3231,7 @@ function classifyAgentError(e) {
|
|
|
3232
3231
|
}
|
|
3233
3232
|
/**
|
|
3234
3233
|
* The child scope-prefix an abandon over `target` covers transitively.
|
|
3235
|
-
* Agent spawns nest under agent:<seq
|
|
3234
|
+
* Agent spawns nest under agent:<seq>; a child
|
|
3236
3235
|
* workflow's subtree runs under the wf:<name>:<ordinal> scope recorded in
|
|
3237
3236
|
* its dispatch payload (M6-T06). A child entry without the payload
|
|
3238
3237
|
* (foreign journals) degrades to the agent:<seq> convention, which covers
|
|
@@ -3249,7 +3248,7 @@ function childCoveragePrefix(target) {
|
|
|
3249
3248
|
* Builds the AbandonFold in ONE pass at load, in append order, pinned for
|
|
3250
3249
|
* the entire resume (DEF-1 ordering rule 4). Coverage is the target seq
|
|
3251
3250
|
* itself plus, transitively, every entry under the target's child
|
|
3252
|
-
* scope-prefix
|
|
3251
|
+
* scope-prefix. Repeated abandons over an
|
|
3253
3252
|
* already-covered target fold to noop.
|
|
3254
3253
|
*/
|
|
3255
3254
|
function buildAbandonFold(entries) {
|
|
@@ -3335,8 +3334,8 @@ function dispositionHook(fold, registry, invalidated) {
|
|
|
3335
3334
|
* Lineage: LogicalTaskId, approach signatures, and the counter folds
|
|
3336
3335
|
* (M7-T02, DEF-3).
|
|
3337
3336
|
*
|
|
3338
|
-
*
|
|
3339
|
-
* docs/
|
|
3337
|
+
* Public contract: https://docs.rulvar.com/guide/journal and
|
|
3338
|
+
* https://docs.rulvar.com/guide/adaptive-orchestration.
|
|
3340
3339
|
*
|
|
3341
3340
|
* The LTID answers "is this the same logical task across rebirths".
|
|
3342
3341
|
* NodeId remains plan-node identity; the content key remains the identity
|
|
@@ -3349,9 +3348,9 @@ function dispositionHook(fold, registry, invalidated) {
|
|
|
3349
3348
|
* in decision entries are READ on replay, never recomputed; a fold
|
|
3350
3349
|
* recomputation over the same prefix serves only as an integrity assert.
|
|
3351
3350
|
*/
|
|
3352
|
-
/** approachSig/approachSigCoarse derivation version
|
|
3351
|
+
/** approachSig/approachSigCoarse derivation version. */
|
|
3353
3352
|
const LINEAGE_SIG_VERSION = 1;
|
|
3354
|
-
/** Deterministic LTIDs canonized onto legacy journals
|
|
3353
|
+
/** Deterministic LTIDs canonized onto legacy journals. */
|
|
3355
3354
|
const LEGACY_LTID_PREFIX = "legacy:";
|
|
3356
3355
|
const DEFAULT_ESCALATION_LIMITS = {
|
|
3357
3356
|
maxEscalationsPerLogicalTask: 2,
|
|
@@ -3377,7 +3376,7 @@ function sha256Hex$1(text) {
|
|
|
3377
3376
|
return createHash("sha256").update(text, "utf8").digest("hex");
|
|
3378
3377
|
}
|
|
3379
3378
|
/**
|
|
3380
|
-
* Approach-tag normalization
|
|
3379
|
+
* Approach-tag normalization: NFC, lowercase, runs of
|
|
3381
3380
|
* non-alphanumerics collapse into a hyphen, truncate to 32 characters; an
|
|
3382
3381
|
* empty value canonicalizes to 'default'. Prompt prose never enters any
|
|
3383
3382
|
* signature: rephrasings collide by construction, not by heuristic.
|
|
@@ -3386,7 +3385,7 @@ function normalizeApproachTag(raw) {
|
|
|
3386
3385
|
const collapsed = (raw ?? "").normalize("NFC").toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 32);
|
|
3387
3386
|
return collapsed === "" ? "default" : collapsed;
|
|
3388
3387
|
}
|
|
3389
|
-
/** The isolation string entering approachSigCoarse
|
|
3388
|
+
/** The isolation string entering approachSigCoarse. */
|
|
3390
3389
|
function canonicalIsolationTag(spec) {
|
|
3391
3390
|
if (spec === void 0) return "none";
|
|
3392
3391
|
return typeof spec === "string" ? spec : spec.kind;
|
|
@@ -3394,7 +3393,7 @@ function canonicalIsolationTag(spec) {
|
|
|
3394
3393
|
/**
|
|
3395
3394
|
* approachSigCoarse = sha256(JCS({ sigVersion, agentType, toolsetHash,
|
|
3396
3395
|
* schemaHash, isolation })). Feeds the stall detector and the oscillation
|
|
3397
|
-
* guard, which keys ACROSS LTID boundaries
|
|
3396
|
+
* guard, which keys ACROSS LTID boundaries.
|
|
3398
3397
|
*/
|
|
3399
3398
|
function approachSigCoarse(inputs) {
|
|
3400
3399
|
return sha256Hex$1(jcsSerialize({
|
|
@@ -3417,7 +3416,7 @@ function approachSigOf(coarse, tag) {
|
|
|
3417
3416
|
* The deterministic signature inputs assigned to legacy spawns (journals
|
|
3418
3417
|
* written before lineage existed) and to attempts whose producers did not
|
|
3419
3418
|
* record signature inputs: stable constants, never wall-clock, so replay
|
|
3420
|
-
* canonizes identically on every engine
|
|
3419
|
+
* canonizes identically on every engine.
|
|
3421
3420
|
*/
|
|
3422
3421
|
const LEGACY_SIGNATURE_INPUTS = {
|
|
3423
3422
|
agentType: "legacy",
|
|
@@ -3441,7 +3440,7 @@ function classifyAttemptOutcome(terminal) {
|
|
|
3441
3440
|
default: return "task-error";
|
|
3442
3441
|
}
|
|
3443
3442
|
}
|
|
3444
|
-
/** Outcome classes that lengthen the stall streak
|
|
3443
|
+
/** Outcome classes that lengthen the stall streak. */
|
|
3445
3444
|
const STALLING_OUTCOMES = /* @__PURE__ */ new Set([
|
|
3446
3445
|
"task-error",
|
|
3447
3446
|
"no-progress",
|
|
@@ -3459,7 +3458,7 @@ function asRecord$2(value) {
|
|
|
3459
3458
|
* Reads the computed SpawnLineage block of a decision payload, tolerating
|
|
3460
3459
|
* pre-DEF-3 producers (M6 journals): a verdict lineage block without
|
|
3461
3460
|
* signatures canonizes onto the deterministic legacy signature constants,
|
|
3462
|
-
* so folds over old journals stay byte-stable
|
|
3461
|
+
* so folds over old journals stay byte-stable.
|
|
3463
3462
|
*/
|
|
3464
3463
|
function readSpawnLineage(decision) {
|
|
3465
3464
|
if (decision === void 0) return;
|
|
@@ -3484,8 +3483,7 @@ function readSpawnLineage(decision) {
|
|
|
3484
3483
|
* The incremental lineage fold: attempts, escalation debits, stall
|
|
3485
3484
|
* streaks, single-live-attempt, and legacy canonization, computed from
|
|
3486
3485
|
* journal entries only. `absorb` is idempotent by seq cursor; every read
|
|
3487
|
-
* accepts an optional `uptoSeq` pin so renders stay snapshot-stable
|
|
3488
|
-
* (docs/03, 10.4; docs/07, 8.3).
|
|
3486
|
+
* accepts an optional `uptoSeq` pin so renders stay snapshot-stable.
|
|
3489
3487
|
*/
|
|
3490
3488
|
var LineageIndex = class {
|
|
3491
3489
|
attemptsByLtid = /* @__PURE__ */ new Map();
|
|
@@ -3671,7 +3669,7 @@ var LineageIndex = class {
|
|
|
3671
3669
|
* attempt whose bound key matches (an at-least-once redispatch of the
|
|
3672
3670
|
* same slot after cancelled/error/limit); else a legacy attempt is
|
|
3673
3671
|
* canonized with the deterministic 'legacy:' + contentHash LTID
|
|
3674
|
-
* (
|
|
3672
|
+
* (random ULIDs on replay are forbidden).
|
|
3675
3673
|
*/
|
|
3676
3674
|
bindRoot(slotScope, entry) {
|
|
3677
3675
|
const queue = this.queueByScope.get(slotScope) ?? [];
|
|
@@ -3721,13 +3719,13 @@ var LineageIndex = class {
|
|
|
3721
3719
|
* True while the LTID has an unsettled attempt (admitted, dispatched, or
|
|
3722
3720
|
* redispatched without a terminal), including admits whose decision
|
|
3723
3721
|
* entries have not landed yet. Backs the single-live-attempt invariant:
|
|
3724
|
-
* a competing admit gets `lineage_busy
|
|
3722
|
+
* a competing admit gets `lineage_busy`.
|
|
3725
3723
|
*/
|
|
3726
3724
|
hasLiveAttempt(logicalTaskId) {
|
|
3727
3725
|
if ((this.pendingAdmits.get(logicalTaskId) ?? 0) > 0) return true;
|
|
3728
3726
|
return (this.attemptsByLtid.get(logicalTaskId) ?? []).some((attempt) => attempt.outcome === void 0);
|
|
3729
3727
|
}
|
|
3730
|
-
/** The stall streak
|
|
3728
|
+
/** The stall streak (pinnable to a snapshot seq). */
|
|
3731
3729
|
stallStreak(logicalTaskId, uptoSeq = Number.POSITIVE_INFINITY) {
|
|
3732
3730
|
let streak = 0;
|
|
3733
3731
|
for (const attempt of this.attemptsOf(logicalTaskId, uptoSeq)) {
|
|
@@ -3741,7 +3739,7 @@ var LineageIndex = class {
|
|
|
3741
3739
|
}
|
|
3742
3740
|
return streak;
|
|
3743
3741
|
}
|
|
3744
|
-
/** The pinned LineageStats render
|
|
3742
|
+
/** The pinned LineageStats render. */
|
|
3745
3743
|
statsOf(logicalTaskId, uptoSeq = Number.POSITIVE_INFINITY) {
|
|
3746
3744
|
const attempts = this.attemptsOf(logicalTaskId, uptoSeq);
|
|
3747
3745
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -3781,8 +3779,8 @@ var LineageIndex = class {
|
|
|
3781
3779
|
/**
|
|
3782
3780
|
* TerminationAccount and the termination lemma (M7-T03, DEF-2).
|
|
3783
3781
|
*
|
|
3784
|
-
*
|
|
3785
|
-
*
|
|
3782
|
+
* Public contract: https://docs.rulvar.com/guide/budgets;
|
|
3783
|
+
* committed defaults declared below; XF-07/XF-09 cap fields.
|
|
3786
3784
|
*
|
|
3787
3785
|
* One construction is committed: a single per-run account with an
|
|
3788
3786
|
* exclusively DEBIT-ONLY API and a limits vector frozen at start in the
|
|
@@ -3808,7 +3806,7 @@ function sha256Hex(text) {
|
|
|
3808
3806
|
/**
|
|
3809
3807
|
* Reads the declared ladder length of one agent profile. Ladders are
|
|
3810
3808
|
* declared through the profile's ModelSpec (`model: { ladder }`, or the
|
|
3811
|
-
* loop-role routing entry
|
|
3809
|
+
* loop-role routing entry). The reader is defensive
|
|
3812
3810
|
* so the snapshot is total over every registry shape (an undeclared
|
|
3813
3811
|
* ladder has length 1: the single implicit rung).
|
|
3814
3812
|
*/
|
|
@@ -3829,7 +3827,7 @@ function kMaxOf(profiles) {
|
|
|
3829
3827
|
/**
|
|
3830
3828
|
* The deterministic profile-registry snapshot hash frozen inside
|
|
3831
3829
|
* termination.init: profile names mapped to their declared ladder
|
|
3832
|
-
* lengths, canonical JSON, sha256
|
|
3830
|
+
* lengths, canonical JSON, sha256.
|
|
3833
3831
|
*/
|
|
3834
3832
|
function profileRegistrySnapshotHash(profiles) {
|
|
3835
3833
|
const projection = {};
|
|
@@ -3871,11 +3869,11 @@ function validateTerminationLimits(raw) {
|
|
|
3871
3869
|
function lineageWeightOf(limits) {
|
|
3872
3870
|
return limits.maxEscalationsPerLogicalTask + limits.kMax;
|
|
3873
3871
|
}
|
|
3874
|
-
/** Phi0 = V0 + C * S0, finite and fixed in termination.init
|
|
3872
|
+
/** Phi0 = V0 + C * S0, finite and fixed in termination.init. */
|
|
3875
3873
|
function phiInitialOf(limits) {
|
|
3876
3874
|
return limits.maxRevisionsPerRun + lineageWeightOf(limits) * limits.maxTotalSpawns;
|
|
3877
3875
|
}
|
|
3878
|
-
/** Builds the termination.init value payload
|
|
3876
|
+
/** Builds the termination.init value payload. */
|
|
3879
3877
|
function buildTerminationInitValue(limits, registrySnapshotHash) {
|
|
3880
3878
|
return {
|
|
3881
3879
|
limits,
|
|
@@ -3891,7 +3889,7 @@ function readTerminationInit(entry) {
|
|
|
3891
3889
|
return value;
|
|
3892
3890
|
}
|
|
3893
3891
|
/**
|
|
3894
|
-
* Config-drift detection at resume
|
|
3892
|
+
* Config-drift detection at resume: the journaled vector
|
|
3895
3893
|
* always wins; every differing field is reported for the
|
|
3896
3894
|
* `termination:config-drift` event. Dynamic budget top-up via restart is
|
|
3897
3895
|
* excluded by construction.
|
|
@@ -3909,9 +3907,9 @@ function terminationConfigDrift(frozen, live) {
|
|
|
3909
3907
|
return drift;
|
|
3910
3908
|
}
|
|
3911
3909
|
/**
|
|
3912
|
-
* The single per-run TerminationAccount
|
|
3910
|
+
* The single per-run TerminationAccount: debit ONLY. No
|
|
3913
3911
|
* credit operation exists by construction; reclaim never replenishes
|
|
3914
|
-
* anything (DEF-5 interaction
|
|
3912
|
+
* anything (DEF-5 interaction). Live: the engine debits the
|
|
3915
3913
|
* in-memory account, writes the carrying entry with the balance-after,
|
|
3916
3914
|
* then applies effects. Resume state is rebuilt by TerminationFold from
|
|
3917
3915
|
* the journal, never from live config.
|
|
@@ -3950,7 +3948,7 @@ var TerminationAccount = class {
|
|
|
3950
3948
|
phi: this.phi()
|
|
3951
3949
|
};
|
|
3952
3950
|
}
|
|
3953
|
-
/** Phi = V + C * S + sum over live lineages (E + R)
|
|
3951
|
+
/** Phi = V + C * S + sum over live lineages (E + R). */
|
|
3954
3952
|
phi() {
|
|
3955
3953
|
let phi = this.revisionUnits + lineageWeightOf(this.limits) * this.spawnUnits;
|
|
3956
3954
|
for (const state of this.lineages.values()) phi += state.escalationUnitsRemaining + state.rungsRemaining;
|
|
@@ -3968,7 +3966,7 @@ var TerminationAccount = class {
|
|
|
3968
3966
|
return this.revisionUnits;
|
|
3969
3967
|
}
|
|
3970
3968
|
/**
|
|
3971
|
-
* The spawn-admission debit
|
|
3969
|
+
* The spawn-admission debit: minus one spawnUnit for
|
|
3972
3970
|
* an admitted spawn of ANY origin; a NEW lineage receives E0 escalation
|
|
3973
3971
|
* units and (K_l - 1) rung transitions in the same atomic step, so the
|
|
3974
3972
|
* lemma's per-spawn decrease is C - (E0 + K_l - 1) = kMax - K_l + 1,
|
|
@@ -3996,7 +3994,7 @@ var TerminationAccount = class {
|
|
|
3996
3994
|
};
|
|
3997
3995
|
}
|
|
3998
3996
|
/**
|
|
3999
|
-
* The plan_revise debit
|
|
3997
|
+
* The plan_revise debit: minus one
|
|
4000
3998
|
* revisionUnit on EVERY journaled plan.revision, regardless of the op
|
|
4001
3999
|
* count, guard verdicts, or the auto-rebase outcome; conflict spam is
|
|
4002
4000
|
* never a free retry.
|
|
@@ -4013,7 +4011,7 @@ var TerminationAccount = class {
|
|
|
4013
4011
|
};
|
|
4014
4012
|
}
|
|
4015
4013
|
/**
|
|
4016
|
-
* The escalation debit
|
|
4014
|
+
* The escalation debit: minus one escalationUnit of
|
|
4017
4015
|
* the affected lineage, including EACH lineage of a class-level
|
|
4018
4016
|
* decision and timeout defaultDecisions. Conditioned on the
|
|
4019
4017
|
* countsAgainstLimit flag embedded in the decision entry by the caller.
|
|
@@ -4031,7 +4029,7 @@ var TerminationAccount = class {
|
|
|
4031
4029
|
};
|
|
4032
4030
|
}
|
|
4033
4031
|
/**
|
|
4034
|
-
* The ladder-raise debit
|
|
4032
|
+
* The ladder-raise debit: minus one rung of the
|
|
4035
4033
|
* lineage; rungIndex is strictly monotone, there are no demotions and
|
|
4036
4034
|
* no runtime startTier promotion in v1.
|
|
4037
4035
|
*/
|
|
@@ -4050,7 +4048,7 @@ var TerminationAccount = class {
|
|
|
4050
4048
|
};
|
|
4051
4049
|
}
|
|
4052
4050
|
/**
|
|
4053
|
-
* The
|
|
4051
|
+
* The unified debit surface: attempts the named resource and, on
|
|
4054
4052
|
* underflow, writes `termination.denied` strictly BEFORE resolving with
|
|
4055
4053
|
* the typed failure (the caller surfaces the error only after this
|
|
4056
4054
|
* settles). Requires a deniedWriter; pure-fold contexts use the
|
|
@@ -4136,7 +4134,7 @@ var TerminationAccount = class {
|
|
|
4136
4134
|
return lineage;
|
|
4137
4135
|
}
|
|
4138
4136
|
};
|
|
4139
|
-
/** The typed error code surfaced after a denied debit
|
|
4137
|
+
/** The typed error code surfaced after a denied debit. */
|
|
4140
4138
|
function exhaustionCodeOf(resource) {
|
|
4141
4139
|
switch (resource) {
|
|
4142
4140
|
case "revisionUnits": return "revision_budget_exhausted";
|
|
@@ -4150,7 +4148,7 @@ function asRecord$1(value) {
|
|
|
4150
4148
|
return typeof value === "object" && value !== null ? value : void 0;
|
|
4151
4149
|
}
|
|
4152
4150
|
/**
|
|
4153
|
-
* The replay fold
|
|
4151
|
+
* The replay fold: rebuilds the account from
|
|
4154
4152
|
* termination.init and the debiting decision entries, asserting every
|
|
4155
4153
|
* embedded balance-after against the recomputation. A divergence raises
|
|
4156
4154
|
* the typed journal-integrity error at exactly the diverging entry;
|
|
@@ -4283,7 +4281,8 @@ function applySpawnDebit(account, entry, admission, assertBalance) {
|
|
|
4283
4281
|
* Reuse-by-reference: SpawnKey dedup, donor rules, node.link, and the
|
|
4284
4282
|
* abandoned-spend ledger (M7-T07, DEF-5).
|
|
4285
4283
|
*
|
|
4286
|
-
*
|
|
4284
|
+
* Full contract: https://docs.rulvar.com/guide/journal and
|
|
4285
|
+
* https://docs.rulvar.com/guide/adaptive-orchestration.
|
|
4287
4286
|
* Oscillation (cancel followed by a byte-identical re-add) no longer
|
|
4288
4287
|
* means full repayment: completed work under an abandoned scope comes
|
|
4289
4288
|
* back by reference, partially completed work grafts through a
|
|
@@ -4299,7 +4298,7 @@ function applySpawnDebit(account, entry, admission, assertBalance) {
|
|
|
4299
4298
|
*/
|
|
4300
4299
|
const DEFAULT_MAX_OSCILLATIONS_PER_KEY = 2;
|
|
4301
4300
|
/**
|
|
4302
|
-
* node.link identity
|
|
4301
|
+
* node.link identity: sha256 of {kind, spawnKey,
|
|
4303
4302
|
* donorScope, targetNodeId}; targetNodeId is deterministic on replay
|
|
4304
4303
|
* because NodeIds are assigned inside plan.revision.
|
|
4305
4304
|
*/
|
|
@@ -4433,7 +4432,7 @@ var DedupIndex = class DedupIndex {
|
|
|
4433
4432
|
allDonorsOf(spawnKey) {
|
|
4434
4433
|
return this.donors.get(spawnKey) ?? [];
|
|
4435
4434
|
}
|
|
4436
|
-
/** Link count per key: the oscillation counter
|
|
4435
|
+
/** Link count per key: the oscillation counter. */
|
|
4437
4436
|
oscillationCountOf(spawnKey) {
|
|
4438
4437
|
return this.links.get(spawnKey) ?? 0;
|
|
4439
4438
|
}
|
|
@@ -4446,7 +4445,7 @@ var DedupIndex = class DedupIndex {
|
|
|
4446
4445
|
};
|
|
4447
4446
|
}
|
|
4448
4447
|
};
|
|
4449
|
-
/** A plan-node scope
|
|
4448
|
+
/** A plan-node scope: its entries belong to one node. */
|
|
4450
4449
|
function isPlanNodeScope(scope) {
|
|
4451
4450
|
return /(^|\/)plan\/[0-9A-Z]{26}$/.test(scope);
|
|
4452
4451
|
}
|
|
@@ -4457,8 +4456,8 @@ function readIsolation(entry) {
|
|
|
4457
4456
|
return "none";
|
|
4458
4457
|
}
|
|
4459
4458
|
/**
|
|
4460
|
-
* The four-outcome verdict evaluation on a SpawnKey match
|
|
4461
|
-
*
|
|
4459
|
+
* The four-outcome verdict evaluation on a SpawnKey match, computed
|
|
4460
|
+
* once live at the fold head and embedded into the
|
|
4462
4461
|
* deciding entry; replay never re-evaluates.
|
|
4463
4462
|
*/
|
|
4464
4463
|
function evaluateReuse(index, spawnKey, config) {
|
|
@@ -4587,7 +4586,7 @@ function decodeCheckpoint(blob) {
|
|
|
4587
4586
|
* The journal append JSON-serializability check (M1-T04): every journaled
|
|
4588
4587
|
* value MUST be JSON-serializable; a violation raises a typed
|
|
4589
4588
|
* NonSerializableValueError at the calling site without journaling
|
|
4590
|
-
* anything
|
|
4589
|
+
* anything.
|
|
4591
4590
|
*/
|
|
4592
4591
|
function check(value, path) {
|
|
4593
4592
|
if (value === null) return;
|
|
@@ -4644,7 +4643,7 @@ const KNOWN_KINDS = /* @__PURE__ */ new Set([
|
|
|
4644
4643
|
"termination.init",
|
|
4645
4644
|
"termination.denied"
|
|
4646
4645
|
]);
|
|
4647
|
-
/** Legal stored statuses per kind
|
|
4646
|
+
/** Legal stored statuses per kind. */
|
|
4648
4647
|
const LEGAL_STATUSES = {
|
|
4649
4648
|
agent: [
|
|
4650
4649
|
"running",
|
|
@@ -4740,8 +4739,7 @@ function validateEntryShape(entry) {
|
|
|
4740
4739
|
* resolution and abandon are appends of new entries plus a pure
|
|
4741
4740
|
* deterministic fold; JournalStore stays exactly five methods.
|
|
4742
4741
|
*
|
|
4743
|
-
*
|
|
4744
|
-
* resolutions (DEF-4)" and "Abandon, derived skipped" (9.1).
|
|
4742
|
+
* Full contract: https://docs.rulvar.com/guide/durability
|
|
4745
4743
|
*/
|
|
4746
4744
|
/**
|
|
4747
4745
|
* The first-closing-wins fold over a loaded journal: one pass by seq,
|
|
@@ -4751,7 +4749,7 @@ function validateEntryShape(entry) {
|
|
|
4751
4749
|
* schema-invalid offline resolution classifies invalid and does NOT close
|
|
4752
4750
|
* the target. Abandon coverage is the target seq plus the transitive
|
|
4753
4751
|
* child scope-prefix; the AbandonFold consumed by the replay predicate is
|
|
4754
|
-
* a projection of THIS fold (
|
|
4752
|
+
* a projection of THIS fold (not a separate pass).
|
|
4755
4753
|
*/
|
|
4756
4754
|
var ResolutionFold = class {
|
|
4757
4755
|
targets = /* @__PURE__ */ new Map();
|
|
@@ -4891,8 +4889,8 @@ var ResolutionFold = class {
|
|
|
4891
4889
|
}
|
|
4892
4890
|
};
|
|
4893
4891
|
/**
|
|
4894
|
-
* Per-run, per-target FIFO serializer of resolution/abandon attempts
|
|
4895
|
-
*
|
|
4892
|
+
* Per-run, per-target FIFO serializer of resolution/abandon attempts:
|
|
4893
|
+
* classification against the in-memory fold ->
|
|
4896
4894
|
* durable append -> settle exactly once; losing attempts are ALSO
|
|
4897
4895
|
* appended and become journaled noops by fold classification. Winner
|
|
4898
4896
|
* effects run strictly after the critical section (the caller's job).
|
|
@@ -4985,7 +4983,7 @@ var ResolutionArbiter = class {
|
|
|
4985
4983
|
};
|
|
4986
4984
|
//#endregion
|
|
4987
4985
|
//#region src/journal/matching.ts
|
|
4988
|
-
/** Kinds excluded from forward-matching cursors
|
|
4986
|
+
/** Kinds excluded from forward-matching cursors. */
|
|
4989
4987
|
const REF_ENTRY_KINDS = /* @__PURE__ */ new Set(["resolution", "abandon"]);
|
|
4990
4988
|
function currentOnlyKeyRing() {
|
|
4991
4989
|
return { keyFor(identity, hashVersion) {
|
|
@@ -5009,7 +5007,7 @@ var JournalMatcher = class {
|
|
|
5009
5007
|
keyRing;
|
|
5010
5008
|
disposition;
|
|
5011
5009
|
aliasDisposition;
|
|
5012
|
-
/** Scope-prefix aliases (DEF-5
|
|
5010
|
+
/** Scope-prefix aliases (DEF-5): donor prefix -> target prefix. */
|
|
5013
5011
|
aliases = [];
|
|
5014
5012
|
keyCache = /* @__PURE__ */ new Map();
|
|
5015
5013
|
hitsInternal = 0;
|
|
@@ -5040,8 +5038,8 @@ var JournalMatcher = class {
|
|
|
5040
5038
|
this.disposition = disposition;
|
|
5041
5039
|
}
|
|
5042
5040
|
/**
|
|
5043
|
-
* The disposition applied to alias-sourced candidates (DEF-5
|
|
5044
|
-
*
|
|
5041
|
+
* The disposition applied to alias-sourced candidates (DEF-5): the
|
|
5042
|
+
* skipped overlay from abandon is bypassed ONLY through the
|
|
5045
5043
|
* alias, so entries regain their pre-abandon terminal status for
|
|
5046
5044
|
* matching in the NEW scope; the standalone old scope stays skipped.
|
|
5047
5045
|
*/
|
|
@@ -5097,7 +5095,7 @@ var JournalMatcher = class {
|
|
|
5097
5095
|
* Forward-matches one live call. A miss does not advance any cursor and
|
|
5098
5096
|
* does not extinguish future hits: the scan always starts at the scope
|
|
5099
5097
|
* head and skips consumed operations, so insertion stability holds by
|
|
5100
|
-
* construction
|
|
5098
|
+
* construction.
|
|
5101
5099
|
*/
|
|
5102
5100
|
match(scope, identity, mode) {
|
|
5103
5101
|
if (mode === "never") {
|
|
@@ -5208,19 +5206,17 @@ var JournalMatcher = class {
|
|
|
5208
5206
|
* The journal kernel write path (M1-T04): two-phase entries, ordinal
|
|
5209
5207
|
* assignment, the per-run serialized append queue with the JSON
|
|
5210
5208
|
* serializability check, and the budget-ledger fold. Scoped
|
|
5211
|
-
* forward-matching and the replay predicate land with resume in M2
|
|
5212
|
-
* (docs/03, sections "Scoped forward-matching" and "Replay predicate");
|
|
5209
|
+
* forward-matching and the replay predicate land with resume in M2;
|
|
5213
5210
|
* in M1 every lookup is live.
|
|
5214
5211
|
*
|
|
5215
|
-
*
|
|
5216
|
-
*
|
|
5217
|
-
* in docs/02-architecture.md, section "Journal Kernel".
|
|
5212
|
+
* Full contract: https://docs.rulvar.com/guide/journal; architecture
|
|
5213
|
+
* overview: https://docs.rulvar.com/guide/architecture.
|
|
5218
5214
|
*/
|
|
5219
|
-
/**
|
|
5215
|
+
/** Large-value soft warn threshold (committed for M2). */
|
|
5220
5216
|
const LARGE_VALUE_WARN_BYTES = 262144;
|
|
5221
5217
|
/**
|
|
5222
5218
|
* Per-run journal kernel front end. Everything is per instance: no module
|
|
5223
|
-
* state anywhere
|
|
5219
|
+
* state anywhere.
|
|
5224
5220
|
*/
|
|
5225
5221
|
var Replayer = class {
|
|
5226
5222
|
runId;
|
|
@@ -5266,8 +5262,8 @@ var Replayer = class {
|
|
|
5266
5262
|
}
|
|
5267
5263
|
}
|
|
5268
5264
|
/**
|
|
5269
|
-
* Forward-matches one live call against the prior journal
|
|
5270
|
-
*
|
|
5265
|
+
* Forward-matches one live call against the prior journal. Fresh
|
|
5266
|
+
* runs always miss; the M2-T06 predicate is injected
|
|
5271
5267
|
* through setDisposition once folds are built.
|
|
5272
5268
|
*/
|
|
5273
5269
|
match(scope, identity, mode) {
|
|
@@ -5283,7 +5279,7 @@ var Replayer = class {
|
|
|
5283
5279
|
this.matcher.setDisposition(disposition);
|
|
5284
5280
|
}
|
|
5285
5281
|
/**
|
|
5286
|
-
* The disposition for alias-sourced candidates (DEF-5
|
|
5282
|
+
* The disposition for alias-sourced candidates (DEF-5):
|
|
5287
5283
|
* bypasses the abandon overlay so donor entries regain their
|
|
5288
5284
|
* pre-abandon terminal status when matched through the alias.
|
|
5289
5285
|
*/
|
|
@@ -5291,7 +5287,7 @@ var Replayer = class {
|
|
|
5291
5287
|
this.matcher.setAliasDisposition(disposition);
|
|
5292
5288
|
}
|
|
5293
5289
|
/**
|
|
5294
|
-
* Registers a node.link scope-prefix rewrite (DEF-5
|
|
5290
|
+
* Registers a node.link scope-prefix rewrite (DEF-5):
|
|
5295
5291
|
* donorPrefix forward-matches into targetPrefix at every nested level.
|
|
5296
5292
|
* Idempotent; the alias map is rebuilt by fold on resume.
|
|
5297
5293
|
*/
|
|
@@ -5299,9 +5295,9 @@ var Replayer = class {
|
|
|
5299
5295
|
this.matcher.registerAlias(donorPrefix, targetPrefix);
|
|
5300
5296
|
}
|
|
5301
5297
|
/**
|
|
5302
|
-
* invalidate/retry
|
|
5298
|
+
* invalidate/retry: explicit unpinning of a
|
|
5303
5299
|
* memoized failure; the invalidated entry reruns on this resume. The
|
|
5304
|
-
* safety boundary is an open question
|
|
5300
|
+
* safety boundary is an open question.
|
|
5305
5301
|
*/
|
|
5306
5302
|
invalidate(seq) {
|
|
5307
5303
|
this.invalidated.add(seq);
|
|
@@ -5348,8 +5344,8 @@ var Replayer = class {
|
|
|
5348
5344
|
});
|
|
5349
5345
|
}
|
|
5350
5346
|
/**
|
|
5351
|
-
* Submits a resolution attempt through the per-target FIFO arbiter
|
|
5352
|
-
*
|
|
5347
|
+
* Submits a resolution attempt through the per-target FIFO arbiter.
|
|
5348
|
+
* Losing attempts are journaled noops.
|
|
5353
5349
|
*/
|
|
5354
5350
|
resolveSuspended(target, attempt) {
|
|
5355
5351
|
const targetEntry = this.entries.find((entry) => entry.seq === target);
|
|
@@ -5361,12 +5357,12 @@ var Replayer = class {
|
|
|
5361
5357
|
if (targetEntry === void 0) throw new ConfigError(`abandonBranch: seq ${attempt.target} does not exist`);
|
|
5362
5358
|
return this.arbiter.submitAbandon(targetEntry.scope, targetEntry.spanId, attempt);
|
|
5363
5359
|
}
|
|
5364
|
-
/** Pure fold view, snapshot-pinned
|
|
5360
|
+
/** Pure fold view, snapshot-pinned. */
|
|
5365
5361
|
suspensionState(target) {
|
|
5366
5362
|
return this.foldInternal.suspensionState(target);
|
|
5367
5363
|
}
|
|
5368
5364
|
/**
|
|
5369
|
-
* Value size policy
|
|
5365
|
+
* Value size policy:
|
|
5370
5366
|
* there is NO automatic offload in v1; oversized values warn and
|
|
5371
5367
|
* proceed. Large artifacts belong in TranscriptStore by reference.
|
|
5372
5368
|
*/
|
|
@@ -5393,7 +5389,7 @@ var Replayer = class {
|
|
|
5393
5389
|
* Two-phase dispatch: the running entry (kinds agent, step, child).
|
|
5394
5390
|
* `value` is legal on child dispatches only: the child payload
|
|
5395
5391
|
* `{ workflow, childScope }` lets the abandon fold compute the child's
|
|
5396
|
-
* transitive scope coverage (
|
|
5392
|
+
* transitive scope coverage (M6-T06). Values
|
|
5397
5393
|
* never enter identity.
|
|
5398
5394
|
*/
|
|
5399
5395
|
appendRunning(input) {
|
|
@@ -5457,8 +5453,7 @@ var Replayer = class {
|
|
|
5457
5453
|
});
|
|
5458
5454
|
}
|
|
5459
5455
|
/**
|
|
5460
|
-
* The budget ledger fold
|
|
5461
|
-
* resume"): usage sums over terminal entries exactly once; agentsSpawned
|
|
5456
|
+
* The budget ledger fold: usage sums over terminal entries exactly once; agentsSpawned
|
|
5462
5457
|
* counts agent dispatches.
|
|
5463
5458
|
*/
|
|
5464
5459
|
ledger() {
|
|
@@ -5545,7 +5540,7 @@ var Replayer = class {
|
|
|
5545
5540
|
* resolveExternal validates against the pinned schema BEFORE append on
|
|
5546
5541
|
* the live path and settles the waiting promise in place without replay.
|
|
5547
5542
|
*
|
|
5548
|
-
*
|
|
5543
|
+
* Full contract: https://docs.rulvar.com/guide/durability
|
|
5549
5544
|
*/
|
|
5550
5545
|
/**
|
|
5551
5546
|
* Normalizes a resolution value into an ApprovalDecision. Anything that
|
|
@@ -5562,7 +5557,7 @@ function toApprovalDecision(value) {
|
|
|
5562
5557
|
* Per-run registry of open external suspensions plus the run's activity
|
|
5563
5558
|
* counter: when every in-flight branch is blocked on suspensions
|
|
5564
5559
|
* (activity zero, waiters open), the run quiesces into outcome
|
|
5565
|
-
* 'suspended'
|
|
5560
|
+
* 'suspended'.
|
|
5566
5561
|
*/
|
|
5567
5562
|
var ExternalRegistry = class ExternalRegistry {
|
|
5568
5563
|
replayer;
|
|
@@ -5677,7 +5672,7 @@ var ExternalRegistry = class ExternalRegistry {
|
|
|
5677
5672
|
});
|
|
5678
5673
|
}
|
|
5679
5674
|
/**
|
|
5680
|
-
* Tool-approval suspension (M3-T03
|
|
5675
|
+
* Tool-approval suspension (M3-T03): journals (or
|
|
5681
5676
|
* re-matches) the suspended approval entry keyed by (toolName, input)
|
|
5682
5677
|
* in the agent's child scope and parks until a resolution closes it.
|
|
5683
5678
|
* The ask verdict is journaled together with the turn checkpoint; on
|
|
@@ -5735,7 +5730,7 @@ var ExternalRegistry = class ExternalRegistry {
|
|
|
5735
5730
|
});
|
|
5736
5731
|
}
|
|
5737
5732
|
/**
|
|
5738
|
-
* Flavor B escalation suspension (M3-T07
|
|
5733
|
+
* Flavor B escalation suspension (M3-T07): the
|
|
5739
5734
|
* escalate tool suspends the agent on the SAME machinery as approvals
|
|
5740
5735
|
* (kind 'approval', toolName 'escalate') with a journaled deadlineAt so
|
|
5741
5736
|
* deadlines survive resume; the resolution VALUE is the raw
|
|
@@ -5812,7 +5807,7 @@ var ExternalRegistry = class ExternalRegistry {
|
|
|
5812
5807
|
/**
|
|
5813
5808
|
* RunHandle.resolveExternal: the live path validates BEFORE append and
|
|
5814
5809
|
* throws InvalidResolutionError without journaling; a winning attempt
|
|
5815
|
-
* settles the waiting promise in place
|
|
5810
|
+
* settles the waiting promise in place.
|
|
5816
5811
|
*/
|
|
5817
5812
|
async resolveExternal(key, value) {
|
|
5818
5813
|
const waiter = [...this.waiters.values()].find((candidate) => candidate.key === key);
|
|
@@ -5917,7 +5912,7 @@ var InMemoryTranscriptStore = class {
|
|
|
5917
5912
|
* beside the journal and are replaced atomically, so listRuns never
|
|
5918
5913
|
* parses payloads.
|
|
5919
5914
|
*
|
|
5920
|
-
* Contract (
|
|
5915
|
+
* Contract (DEF-4 tightening):
|
|
5921
5916
|
* - A1 atomicity: a torn trailing line (crash mid-append) is never
|
|
5922
5917
|
* visible in load; it is dropped and overwritten by the next append.
|
|
5923
5918
|
* - A2 total per-run order: load returns append order, stable across
|
|
@@ -5928,7 +5923,7 @@ var InMemoryTranscriptStore = class {
|
|
|
5928
5923
|
*
|
|
5929
5924
|
* Leasing is NOT implemented here: LeasableStore ships with
|
|
5930
5925
|
* @rulvar/store-sqlite (M5); JsonlFileStore is single-writer by
|
|
5931
|
-
* convention
|
|
5926
|
+
* convention.
|
|
5932
5927
|
*/
|
|
5933
5928
|
const JOURNAL_SUFFIX = ".jsonl";
|
|
5934
5929
|
const META_SUFFIX = ".meta.json";
|
|
@@ -6012,7 +6007,7 @@ const TRANSCRIPT_SUFFIX = ".bin";
|
|
|
6012
6007
|
/**
|
|
6013
6008
|
* File-backed TranscriptStore (M6-T02): blobs (transcripts, checkpoints,
|
|
6014
6009
|
* persisted CompiledWorkflow sources) as one file per ref under `dir`,
|
|
6015
|
-
* so compiled runs resume across processes
|
|
6010
|
+
* so compiled runs resume across processes. Refs follow
|
|
6016
6011
|
* the `<runId>/<name>` convention; each path segment is checked
|
|
6017
6012
|
* filesystem-safe and nested segments become directories.
|
|
6018
6013
|
*/
|
|
@@ -6073,7 +6068,7 @@ var FileTranscriptStore = class {
|
|
|
6073
6068
|
//#endregion
|
|
6074
6069
|
//#region src/engine/cost-report.ts
|
|
6075
6070
|
/**
|
|
6076
|
-
* CostReport builders (M5-T03
|
|
6071
|
+
* CostReport builders (M5-T03). Two
|
|
6077
6072
|
* sources, one shape:
|
|
6078
6073
|
*
|
|
6079
6074
|
* - `buildCostReport` folds the LIVE per-run attribution buckets (ctx
|
|
@@ -6087,8 +6082,7 @@ var FileTranscriptStore = class {
|
|
|
6087
6082
|
* facts that entries do not carry, so those buckets are empty here;
|
|
6088
6083
|
* byRole and the orchestrator block complete in M7 (DEF-7).
|
|
6089
6084
|
*
|
|
6090
|
-
* Unpriced models surface in `unpriced`, never as a silent zero
|
|
6091
|
-
* (docs/04, section "Pricing").
|
|
6085
|
+
* Unpriced models surface in `unpriced`, never as a silent zero.
|
|
6092
6086
|
*/
|
|
6093
6087
|
const ROLES = [
|
|
6094
6088
|
"orchestrate",
|
|
@@ -6172,8 +6166,8 @@ function costReportFromJournal(entries, priceUsd) {
|
|
|
6172
6166
|
//#endregion
|
|
6173
6167
|
//#region src/engine/run-profiles.ts
|
|
6174
6168
|
/**
|
|
6175
|
-
* The shipped presets (
|
|
6176
|
-
*
|
|
6169
|
+
* The shipped presets (fast / standard / deep / ultra "and similar").
|
|
6170
|
+
* Data only; a review-time assertion checks the
|
|
6177
6171
|
* engine has zero behavioral branches keyed on these names.
|
|
6178
6172
|
*/
|
|
6179
6173
|
const RUN_PROFILES = {
|
|
@@ -6240,7 +6234,7 @@ const TIER_ORDER = {
|
|
|
6240
6234
|
/**
|
|
6241
6235
|
* Strict-schema compatibility as both first-class providers define it:
|
|
6242
6236
|
* every object node declares `additionalProperties: false` and lists every
|
|
6243
|
-
* property in `required
|
|
6237
|
+
* property in `required`. Boolean schemas and
|
|
6244
6238
|
* non-object shapes are trivially compatible.
|
|
6245
6239
|
*/
|
|
6246
6240
|
function isStrictCompatibleSchema(schema) {
|
|
@@ -6280,10 +6274,10 @@ function isStrictCompatibleSchema(schema) {
|
|
|
6280
6274
|
return true;
|
|
6281
6275
|
}
|
|
6282
6276
|
/**
|
|
6283
|
-
* Tier selection
|
|
6277
|
+
* Tier selection: the model's declared ceiling
|
|
6284
6278
|
* bounds the tier; the native tier additionally requires a
|
|
6285
|
-
* strict-compatible canonical schema (
|
|
6286
|
-
*
|
|
6279
|
+
* strict-compatible canonical schema (relying on silent server-side
|
|
6280
|
+
* fallback is forbidden), degrading to forced-tool.
|
|
6287
6281
|
* Prefill is not a tier.
|
|
6288
6282
|
*/
|
|
6289
6283
|
function selectStructuredOutputTier(caps, canonicalSchema) {
|
|
@@ -6301,10 +6295,10 @@ function tierWithinCaps(tier, caps) {
|
|
|
6301
6295
|
* Scheduler and concurrency (M1-T08): the per-run semaphore with a FIFO
|
|
6302
6296
|
* queue (default 12 concurrent model calls). The engine lifetime spawn cap
|
|
6303
6297
|
* is enforced by the budget layer at admission; parallel/pipeline
|
|
6304
|
-
* composition semantics live with ctx
|
|
6298
|
+
* composition semantics live with ctx.
|
|
6305
6299
|
* Per-provider concurrency keys land with M4.
|
|
6306
6300
|
*/
|
|
6307
|
-
/** FIFO semaphore; default per-run width is 12
|
|
6301
|
+
/** FIFO semaphore; default per-run width is 12. */
|
|
6308
6302
|
const DEFAULT_PER_RUN_CONCURRENCY = 12;
|
|
6309
6303
|
var Semaphore = class {
|
|
6310
6304
|
limit;
|
|
@@ -6350,7 +6344,7 @@ var Semaphore = class {
|
|
|
6350
6344
|
//#region src/model/concurrency.ts
|
|
6351
6345
|
/**
|
|
6352
6346
|
* Per-provider concurrency keys (M4-T07): a keyed limiter beside the
|
|
6353
|
-
* router, ENGINE-scoped (
|
|
6347
|
+
* router, ENGINE-scoped (keys constrain calls
|
|
6354
6348
|
* across a single engine per adapter). The Appendix A default is
|
|
6355
6349
|
* unlimited: an embeddable library must not surprise-throttle hosts, so
|
|
6356
6350
|
* the per-run semaphore stays the only default bound and provider 429s
|
|
@@ -6359,7 +6353,7 @@ var Semaphore = class {
|
|
|
6359
6353
|
*
|
|
6360
6354
|
* There is deliberately NO distributed cross-process limiter: two
|
|
6361
6355
|
* processes sharing one API key coordinate nothing here (a
|
|
6362
|
-
* process-global limiter is an open question
|
|
6356
|
+
* process-global limiter is an open question).
|
|
6363
6357
|
*/
|
|
6364
6358
|
var KeyedLimiter = class {
|
|
6365
6359
|
semaphores = /* @__PURE__ */ new Map();
|
|
@@ -6382,7 +6376,7 @@ var KeyedLimiter = class {
|
|
|
6382
6376
|
};
|
|
6383
6377
|
//#endregion
|
|
6384
6378
|
//#region src/model/failover.ts
|
|
6385
|
-
/** Normalizes the author-facing ModelChoice.fallbacks list
|
|
6379
|
+
/** Normalizes the author-facing ModelChoice.fallbacks list. */
|
|
6386
6380
|
function normalizeFallbacks(refs) {
|
|
6387
6381
|
return (refs ?? []).map((model) => ({ model }));
|
|
6388
6382
|
}
|
|
@@ -6407,8 +6401,8 @@ function nextFailover(targets, trigger, from) {
|
|
|
6407
6401
|
}
|
|
6408
6402
|
}
|
|
6409
6403
|
/**
|
|
6410
|
-
* Classifies a terminal agent outcome for the degenerate fallback
|
|
6411
|
-
*
|
|
6404
|
+
* Classifies a terminal agent outcome for the degenerate fallback:
|
|
6405
|
+
* schema-mismatch errors are
|
|
6412
6406
|
* 'schema-exhausted'; any other error is 'error'; limit terminals (the
|
|
6413
6407
|
* no-progress abort included) are 'limit'; cancelled, escalated, and
|
|
6414
6408
|
* skipped never trigger.
|
|
@@ -6428,11 +6422,11 @@ function resolvePricing(ref, table, capsPricing) {
|
|
|
6428
6422
|
return table?.models[ref] ?? capsPricing;
|
|
6429
6423
|
}
|
|
6430
6424
|
/**
|
|
6431
|
-
* Dollars from normalized usage against one pricing row (
|
|
6432
|
-
*
|
|
6425
|
+
* Dollars from normalized usage against one pricing row (the adapter
|
|
6426
|
+
* normalized the usage; inputTokens is the
|
|
6433
6427
|
* full prompt). Cache writes price at the 5m premium rate; the 1h rate
|
|
6434
6428
|
* applies where a provider distinguishes it in usage, which the
|
|
6435
|
-
* canonical Usage does not yet carry
|
|
6429
|
+
* canonical Usage does not yet carry.
|
|
6436
6430
|
*/
|
|
6437
6431
|
function priceUsdOf(pricing, usage) {
|
|
6438
6432
|
return usage.inputTokens / 1e6 * pricing.inputUsdPerMTok + usage.outputTokens / 1e6 * pricing.outputUsdPerMTok + usage.cacheReadTokens / 1e6 * (pricing.cacheReadUsdPerMTok ?? 0) + usage.cacheWriteTokens / 1e6 * (pricing.cacheWriteUsdPerMTok ?? 0);
|
|
@@ -6494,7 +6488,7 @@ function projectHistory(messages, targetProvider) {
|
|
|
6494
6488
|
}
|
|
6495
6489
|
/**
|
|
6496
6490
|
* Lifts the adapter-shipped retention payload of one finished turn into
|
|
6497
|
-
* provider-raw parts (
|
|
6491
|
+
* provider-raw parts (the retention transport). Reads
|
|
6498
6492
|
* providerMetadata[<adapter id>].retainedParts and tags each block with
|
|
6499
6493
|
* the adapter's provider family. Returns [] when the adapter shipped
|
|
6500
6494
|
* nothing.
|
|
@@ -6532,9 +6526,8 @@ const DEFAULT_RETRY_POLICY = {
|
|
|
6532
6526
|
/**
|
|
6533
6527
|
* Classifies a WireError for the retry engine. Task-class failures are
|
|
6534
6528
|
* never retryable by construction: adapters mark them retryable: false
|
|
6535
|
-
* and this returns undefined. The kind travels in WireError.data.kind
|
|
6536
|
-
*
|
|
6537
|
-
* transport.
|
|
6529
|
+
* and this returns undefined. The kind travels in WireError.data.kind;
|
|
6530
|
+
* anything retryable without a specific kind is transport.
|
|
6538
6531
|
*/
|
|
6539
6532
|
function retryClassOf(error) {
|
|
6540
6533
|
if (!error.retryable) return;
|
|
@@ -6575,7 +6568,7 @@ function canRideLoopTurn(tier, toolsAvailable) {
|
|
|
6575
6568
|
* to a different model OR the loop model's caps cannot serve the required
|
|
6576
6569
|
* tier OR finalize is routed, in which case the schema never rides a loop
|
|
6577
6570
|
* or synthesis turn). Otherwise the schema rides the last loop turn with
|
|
6578
|
-
* no extra call (
|
|
6571
|
+
* no extra call (as amended in M4-T01).
|
|
6579
6572
|
*/
|
|
6580
6573
|
function needsSeparateExtract(input) {
|
|
6581
6574
|
if (!input.schemaSet) return false;
|
|
@@ -6586,7 +6579,7 @@ function needsSeparateExtract(input) {
|
|
|
6586
6579
|
* map. This is the finalize TRIGGER: firing is decided by the presence of
|
|
6587
6580
|
* a routing entry at any layer; the model it fires ON still resolves
|
|
6588
6581
|
* through the full chain (a higher layer's all-roles `model` may override
|
|
6589
|
-
* the routed choice
|
|
6582
|
+
* the routed choice).
|
|
6590
6583
|
*/
|
|
6591
6584
|
function roleConfiguredInRouting(role, layers) {
|
|
6592
6585
|
return layers.some((layer) => layer?.routing?.[role] !== void 0);
|
|
@@ -6594,8 +6587,8 @@ function roleConfiguredInRouting(role, layers) {
|
|
|
6594
6587
|
/**
|
|
6595
6588
|
* The finalize firing rule: only if configured in routing, and only after
|
|
6596
6589
|
* tools stop, which presupposes a non-empty toolset. A no-tools agent's
|
|
6597
|
-
* single loop turn is already its synthesis (
|
|
6598
|
-
*
|
|
6590
|
+
* single loop turn is already its synthesis (as amended in M4-T01). The
|
|
6591
|
+
* caller additionally gates on the loop having
|
|
6599
6592
|
* ended without an abort: a limit/error/cancelled/escalated loop never
|
|
6600
6593
|
* reaches synthesis.
|
|
6601
6594
|
*/
|
|
@@ -6604,7 +6597,7 @@ function finalizeFires(options) {
|
|
|
6604
6597
|
}
|
|
6605
6598
|
/**
|
|
6606
6599
|
* The summarize trigger: the compaction threshold on the context window
|
|
6607
|
-
* (
|
|
6600
|
+
* (default 0.8). Pure predicate; the compaction
|
|
6608
6601
|
* pipeline that acts on it is M4-T03.
|
|
6609
6602
|
*/
|
|
6610
6603
|
function atCompactionThreshold(usedTokens, contextWindow, threshold) {
|
|
@@ -6613,12 +6606,12 @@ function atCompactionThreshold(usedTokens, contextWindow, threshold) {
|
|
|
6613
6606
|
}
|
|
6614
6607
|
//#endregion
|
|
6615
6608
|
//#region src/runtime/compaction.ts
|
|
6616
|
-
/**
|
|
6609
|
+
/** Compaction threshold default, 0.8 of contextWindow. */
|
|
6617
6610
|
const DEFAULT_COMPACTION_THRESHOLD = .8;
|
|
6618
6611
|
/** Deterministic marker opening every compaction summary message. */
|
|
6619
6612
|
const COMPACTION_SUMMARY_PREFIX = "Summary of the conversation so far:";
|
|
6620
6613
|
/**
|
|
6621
|
-
* The threshold check (
|
|
6614
|
+
* The threshold check (M4-T03 committed semantics): the context
|
|
6622
6615
|
* estimate is the last loop turn's inputTokens + outputTokens; the Usage
|
|
6623
6616
|
* invariant makes inputTokens the full prompt, and the turn's output
|
|
6624
6617
|
* joins the next prompt.
|
|
@@ -6664,14 +6657,11 @@ function compactMessages(messages, summaryText) {
|
|
|
6664
6657
|
* parsing, the per-invocation resolution chain, canonicalization into
|
|
6665
6658
|
* CanonicalModelSpec, and caps scrubbing with visible scrub notes.
|
|
6666
6659
|
*
|
|
6667
|
-
*
|
|
6668
|
-
* resolution chain", "Canonical effort", and "Caps scrubbing and
|
|
6669
|
-
* structured-output tier selection".
|
|
6660
|
+
* Public contract: https://docs.rulvar.com/guide/model-routing.
|
|
6670
6661
|
*/
|
|
6671
6662
|
/**
|
|
6672
6663
|
* Per-engine adapter registry: strictly per engine, no global mutable
|
|
6673
|
-
* registry exists. A duplicate adapterId is a typed ConfigError
|
|
6674
|
-
* (docs/04, section "Registry and ModelRef").
|
|
6664
|
+
* registry exists. A duplicate adapterId is a typed ConfigError.
|
|
6675
6665
|
*/
|
|
6676
6666
|
function buildAdapterRegistry(adapters) {
|
|
6677
6667
|
const registry = /* @__PURE__ */ new Map();
|
|
@@ -6695,12 +6685,10 @@ function parseModelRef(ref) {
|
|
|
6695
6685
|
};
|
|
6696
6686
|
}
|
|
6697
6687
|
/**
|
|
6698
|
-
* Role effort defaults
|
|
6699
|
-
* protocol"): orchestrate and plan default to high; summarize and extract
|
|
6688
|
+
* Role effort defaults: orchestrate and plan default to high; summarize and extract
|
|
6700
6689
|
* default to low. loop and finalize have NO role default: when the chain
|
|
6701
6690
|
* resolves nothing, the wire omits effort and identity records the spec
|
|
6702
|
-
* with the effort member absent
|
|
6703
|
-
* chain", as amended).
|
|
6691
|
+
* with the effort member absent.
|
|
6704
6692
|
*/
|
|
6705
6693
|
const ROLE_EFFORT_DEFAULTS = {
|
|
6706
6694
|
orchestrate: "high",
|
|
@@ -6755,7 +6743,7 @@ const SAMPLING_KEYS = [
|
|
|
6755
6743
|
* Resolution runs on every model invocation, not once per agent: a layered
|
|
6756
6744
|
* merge of { model, effort, providerOptions, fallbacks } in the order call
|
|
6757
6745
|
* override > agent profile > workflow defaults > engine defaults, with the
|
|
6758
|
-
* invocation role attached as a tag
|
|
6746
|
+
* invocation role attached as a tag.
|
|
6759
6747
|
* After resolution the router reads ModelCaps and scrubs illegal
|
|
6760
6748
|
* parameters visibly: unsupported effort is removed from the wire but
|
|
6761
6749
|
* kept in identity; sampling params rejected by the model are removed
|
|
@@ -6839,7 +6827,7 @@ function resolveModelInvocation(options) {
|
|
|
6839
6827
|
if (merged.fallbacks !== void 0) resolved.fallbacks = merged.fallbacks;
|
|
6840
6828
|
return resolved;
|
|
6841
6829
|
}
|
|
6842
|
-
/** The closed trigger vocabulary guard
|
|
6830
|
+
/** The closed trigger vocabulary guard. */
|
|
6843
6831
|
const TRIGGER_CLASSES = [
|
|
6844
6832
|
"error",
|
|
6845
6833
|
"limit",
|
|
@@ -6863,7 +6851,7 @@ function validateGate(gate, rungCount, index) {
|
|
|
6863
6851
|
if (!(gate.fraction > 0 && gate.fraction <= 1)) throw new ConfigError(`ladder acceptance gate ${String(index)}: a spot-check fraction lies in (0, 1], got ${String(gate.fraction)}`);
|
|
6864
6852
|
}
|
|
6865
6853
|
/**
|
|
6866
|
-
* Canonicalizes a declared LadderSpec
|
|
6854
|
+
* Canonicalizes a declared LadderSpec: validates the
|
|
6867
6855
|
* shape once (FR-119 judge declaration included) and resolves every rung's
|
|
6868
6856
|
* effort to an explicit value. `chainEffort` is the effort the resolution
|
|
6869
6857
|
* chain would contribute at the declaring layer; a rung that resolves no
|
|
@@ -6901,7 +6889,7 @@ function canonicalizeLadder(spec, options) {
|
|
|
6901
6889
|
/**
|
|
6902
6890
|
* The concrete ModelChoice of one rung attempt: each attempt is an
|
|
6903
6891
|
* ordinary agent scope whose CanonicalModelSpec is that rung's
|
|
6904
|
-
* `{ kind: 'model' }` form
|
|
6892
|
+
* `{ kind: 'model' }` form.
|
|
6905
6893
|
*/
|
|
6906
6894
|
function ladderRungChoice(ladder, index) {
|
|
6907
6895
|
const rung = ladder.rungs[index];
|
|
@@ -6917,7 +6905,7 @@ const DEFAULT_MAX_TURNS = 32;
|
|
|
6917
6905
|
const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 12e4;
|
|
6918
6906
|
/**
|
|
6919
6907
|
* Limits merge per spawn: AgentOpts.limits over profile limits over engine
|
|
6920
|
-
* defaults.limits
|
|
6908
|
+
* defaults.limits.
|
|
6921
6909
|
*/
|
|
6922
6910
|
function mergeUsageLimits(call, profile, engine) {
|
|
6923
6911
|
const pick = (key) => call?.[key] ?? profile?.[key] ?? engine?.[key];
|
|
@@ -6945,13 +6933,13 @@ var ModelRetry = class extends Error {
|
|
|
6945
6933
|
if (opts?.data !== void 0) this.data = opts.data;
|
|
6946
6934
|
}
|
|
6947
6935
|
};
|
|
6948
|
-
/** Bounded semantic retries per tool call chain
|
|
6936
|
+
/** Bounded semantic retries per tool call chain. */
|
|
6949
6937
|
const DEFAULT_MODEL_RETRY_ATTEMPTS = 2;
|
|
6950
6938
|
//#endregion
|
|
6951
6939
|
//#region src/runtime/escalation.ts
|
|
6952
6940
|
const ESCALATE_TOOL_NAME = "escalate";
|
|
6953
6941
|
/**
|
|
6954
|
-
* The
|
|
6942
|
+
* The escalate tool's exact request schema. costToDate and salvage
|
|
6955
6943
|
* MUST NOT appear here: additionalProperties false rejects model-authored
|
|
6956
6944
|
* values for them at argument validation.
|
|
6957
6945
|
*/
|
|
@@ -6995,7 +6983,7 @@ const ESCALATION_REQUEST_SCHEMA = {
|
|
|
6995
6983
|
}
|
|
6996
6984
|
}
|
|
6997
6985
|
};
|
|
6998
|
-
/** The full-report schema applied BEFORE append
|
|
6986
|
+
/** The full-report schema applied BEFORE append. */
|
|
6999
6987
|
const ESCALATION_REPORT_SCHEMA = {
|
|
7000
6988
|
type: "object",
|
|
7001
6989
|
additionalProperties: false,
|
|
@@ -7066,7 +7054,7 @@ const ESCALATION_REPORT_SCHEMA = {
|
|
|
7066
7054
|
}
|
|
7067
7055
|
};
|
|
7068
7056
|
/**
|
|
7069
|
-
* The engine opt-in tool
|
|
7057
|
+
* The engine opt-in tool: registered through the
|
|
7070
7058
|
* same path as any tool under escalation opt-in of EITHER flavor (the
|
|
7071
7059
|
* worker's only authoring channel for a report), never available without
|
|
7072
7060
|
* opt-in, and dispatched through the same permission chain. The loop
|
|
@@ -7088,7 +7076,7 @@ async function validateEscalationReport(report) {
|
|
|
7088
7076
|
return validation.valid ? [] : validation.issues;
|
|
7089
7077
|
}
|
|
7090
7078
|
/**
|
|
7091
|
-
* countsAgainstLimit derivation (
|
|
7079
|
+
* countsAgainstLimit derivation (XF-06): true iff
|
|
7092
7080
|
* scope_bigger; scope_different and blocked_with_evidence are exempt and
|
|
7093
7081
|
* never debit the escalation counter.
|
|
7094
7082
|
*/
|
|
@@ -7102,11 +7090,11 @@ function countsAgainstLimit(kind) {
|
|
|
7102
7090
|
* journaled as a first-class terminal abort distinct from user
|
|
7103
7091
|
* cancellation (a cancelled entry always reruns; a no-progress abort
|
|
7104
7092
|
* must replay, or every resume would re-pay the stuck turns). The
|
|
7105
|
-
* interim heuristic is committed
|
|
7093
|
+
* interim heuristic is committed: N consecutive
|
|
7106
7094
|
* turns without tool calls or artifact deltas, N = 3; the broader
|
|
7107
|
-
* heuristic stays OQ-15
|
|
7095
|
+
* heuristic stays OQ-15, revisited on dogfood traces.
|
|
7108
7096
|
*
|
|
7109
|
-
* Encoding
|
|
7097
|
+
* Encoding: the abort is the agent's
|
|
7110
7098
|
* terminal entry with status 'limit', an error payload carrying
|
|
7111
7099
|
* abortClass 'no-progress', and memoizeOutcome stamped by the ENGINE on
|
|
7112
7100
|
* the terminal entry, so the frozen memoize-limit rule replays it on
|
|
@@ -7114,7 +7102,7 @@ function countsAgainstLimit(kind) {
|
|
|
7114
7102
|
* per-turn artifact channel, so the tool-call test subsumes artifact
|
|
7115
7103
|
* deltas; per-turn artifact producers arrive with M4 compaction.
|
|
7116
7104
|
*/
|
|
7117
|
-
/**
|
|
7105
|
+
/** The committed no-progress detector N. */
|
|
7118
7106
|
const DEFAULT_NO_PROGRESS_TURNS = 3;
|
|
7119
7107
|
/**
|
|
7120
7108
|
* Counts consecutive progress-free turns. A turn with at least one tool
|
|
@@ -7154,14 +7142,14 @@ var NoProgressDetector = class {
|
|
|
7154
7142
|
* allow: allow is only ever falling through to canUseTool or the
|
|
7155
7143
|
* terminal default.
|
|
7156
7144
|
*
|
|
7157
|
-
*
|
|
7158
|
-
*
|
|
7145
|
+
* Full contract: https://docs.rulvar.com/guide/tools.
|
|
7146
|
+
* Risk presets, the argv shell matcher, domain rules, and the
|
|
7159
7147
|
* audit/dry-run surface land in M5.
|
|
7160
7148
|
*/
|
|
7161
7149
|
/**
|
|
7162
7150
|
* Merges the engine-wide config and the profile config into one chain.
|
|
7163
7151
|
* Layers concatenate engine-first; since rules only deny or ask, ordering
|
|
7164
|
-
* within a layer cannot change the verdict
|
|
7152
|
+
* within a layer cannot change the verdict. The
|
|
7165
7153
|
* profile's canUseTool wins over the engine's (a single slot by
|
|
7166
7154
|
* construction). A declared preset compiles INTO the same layers, after
|
|
7167
7155
|
* the host-authored rules, never as a fifth layer (M5-T05).
|
|
@@ -7189,7 +7177,7 @@ function compilePermissionChain(engine, profile) {
|
|
|
7189
7177
|
...canUseTool === void 0 ? {} : { canUseTool }
|
|
7190
7178
|
};
|
|
7191
7179
|
}
|
|
7192
|
-
/** The command text an argv rule matches against
|
|
7180
|
+
/** The command text an argv rule matches against. */
|
|
7193
7181
|
function commandOf(input) {
|
|
7194
7182
|
if (typeof input === "string") return input;
|
|
7195
7183
|
if (typeof input === "object" && input !== null) {
|
|
@@ -7214,7 +7202,7 @@ function ruleMatches(rule, toolName, risk, input) {
|
|
|
7214
7202
|
return true;
|
|
7215
7203
|
}
|
|
7216
7204
|
/**
|
|
7217
|
-
* Advisory domain-rule matches for the audit payload
|
|
7205
|
+
* Advisory domain-rule matches for the audit payload:
|
|
7218
7206
|
* reported, never enforced outside first-party fetch.
|
|
7219
7207
|
*/
|
|
7220
7208
|
function advisoryMatches(chain, toolName) {
|
|
@@ -7222,7 +7210,7 @@ function advisoryMatches(chain, toolName) {
|
|
|
7222
7210
|
}
|
|
7223
7211
|
/**
|
|
7224
7212
|
* Unmatchable segments (command/process substitution, here-docs) yield
|
|
7225
|
-
* ask, ALWAYS, for any tool that has argv rules
|
|
7213
|
+
* ask, ALWAYS, for any tool that has argv rules.
|
|
7226
7214
|
*/
|
|
7227
7215
|
function argvUnmatchableAsk(chain, toolName, input) {
|
|
7228
7216
|
if (![...chain.deny, ...chain.ask].some((rule) => "argv" in rule && (Array.isArray(rule.tool) ? rule.tool : [rule.tool]).includes(toolName))) return false;
|
|
@@ -7230,7 +7218,7 @@ function argvUnmatchableAsk(chain, toolName, input) {
|
|
|
7230
7218
|
if (command === void 0) return true;
|
|
7231
7219
|
return lexShellCommand(command).some((segment) => segment.unmatchable);
|
|
7232
7220
|
}
|
|
7233
|
-
/** A stub ToolContext for offline (dry-run) evaluations
|
|
7221
|
+
/** A stub ToolContext for offline (dry-run) evaluations. */
|
|
7234
7222
|
function offlineContext(toolName) {
|
|
7235
7223
|
return {
|
|
7236
7224
|
runId: "dry-run",
|
|
@@ -7244,14 +7232,14 @@ function offlineContext(toolName) {
|
|
|
7244
7232
|
}
|
|
7245
7233
|
/**
|
|
7246
7234
|
* Evaluates the chain for one dispatch, or OFFLINE against a
|
|
7247
|
-
* hypothetical call by tool name (the dry-run API
|
|
7248
|
-
*
|
|
7235
|
+
* hypothetical call by tool name (the dry-run API: nothing executes;
|
|
7236
|
+
* shells and tests read the verdict, the
|
|
7249
7237
|
* deciding layer, and the matched rule). Hooks run in deterministic
|
|
7250
7238
|
* registration order; { modifiedInput } substitutes the input and
|
|
7251
7239
|
* continues; the first decisive verdict wins. The returned input is what
|
|
7252
|
-
* execute receives and what the approval identity hashes (
|
|
7253
|
-
*
|
|
7254
|
-
* ride every verdict for the audit payload
|
|
7240
|
+
* execute receives and what the approval identity hashes (post hook
|
|
7241
|
+
* modification). Advisory domain-rule matches
|
|
7242
|
+
* ride every verdict for the audit payload.
|
|
7255
7243
|
*/
|
|
7256
7244
|
async function evaluatePermission(chain, tool, input, ctx) {
|
|
7257
7245
|
const def = typeof tool === "string" ? {
|
|
@@ -7439,8 +7427,8 @@ function formatRePrompt(issues, attempt, maxAttempts) {
|
|
|
7439
7427
|
* with M3/M4; the escalated status arrives in M3 as the flagged breaking
|
|
7440
7428
|
* change.
|
|
7441
7429
|
*
|
|
7442
|
-
*
|
|
7443
|
-
*
|
|
7430
|
+
* Docs: https://docs.rulvar.com/guide/agents (agent runtime binding);
|
|
7431
|
+
* https://docs.rulvar.com/guide/model-routing (roles, tiers, refusal).
|
|
7444
7432
|
*/
|
|
7445
7433
|
function isEscalated(r) {
|
|
7446
7434
|
return r.status === "escalated";
|
|
@@ -7466,8 +7454,7 @@ function addUsage(total, turn) {
|
|
|
7466
7454
|
}
|
|
7467
7455
|
/**
|
|
7468
7456
|
* The Usage invariant is verified at the adapter boundary: inputTokens is
|
|
7469
|
-
* the FULL prompt including cache reads and writes
|
|
7470
|
-
* "Usage invariant").
|
|
7457
|
+
* the FULL prompt including cache reads and writes.
|
|
7471
7458
|
*/
|
|
7472
7459
|
function assertUsageInvariant(usage, adapterId) {
|
|
7473
7460
|
if (usage.inputTokens < usage.cacheReadTokens + usage.cacheWriteTokens) throw new Error(`adapter '${adapterId}' violated the Usage invariant: inputTokens (${usage.inputTokens}) < cacheReadTokens + cacheWriteTokens (${usage.cacheReadTokens} + ${usage.cacheWriteTokens})`);
|
|
@@ -7612,7 +7599,7 @@ function buildRequest(resolved, messages, limits, tools) {
|
|
|
7612
7599
|
* parts go at the HEAD: on both first-class providers the retained
|
|
7613
7600
|
* blocks (thinking blocks, reasoning items) precede the turn's text and
|
|
7614
7601
|
* tool calls, and head placement reproduces that order on re-projection
|
|
7615
|
-
* (
|
|
7602
|
+
* (M4-T02).
|
|
7616
7603
|
*/
|
|
7617
7604
|
function assistantMsg(turn, retained = []) {
|
|
7618
7605
|
const parts = [...retained];
|
|
@@ -7636,8 +7623,7 @@ function assistantMsg(turn, retained = []) {
|
|
|
7636
7623
|
* surfaced to the model as error tool results and never thrown past
|
|
7637
7624
|
* policy: unknown names, argument-validation issues, ModelRetry (bounded
|
|
7638
7625
|
* per tool call chain), NonSerializableValueError, and arbitrary execute
|
|
7639
|
-
* throws all land as { isError: true } results
|
|
7640
|
-
* 2.4; docs/06, section "ModelRetry").
|
|
7626
|
+
* throws all land as { isError: true } results.
|
|
7641
7627
|
*/
|
|
7642
7628
|
async function executeToolCall(options) {
|
|
7643
7629
|
const { call, runtime } = options;
|
|
@@ -8581,7 +8567,7 @@ async function runAgent(options) {
|
|
|
8581
8567
|
* ceiling severing live streams, with partial usage written usageApprox.
|
|
8582
8568
|
* B0 is immutable after start: no API tops it up.
|
|
8583
8569
|
*
|
|
8584
|
-
* The account tree
|
|
8570
|
+
* The account tree: the run root plus one
|
|
8585
8571
|
* sub-account per admitted child workflow (and, from M7, the orchestrator
|
|
8586
8572
|
* account and plan/NodeId accounts). A child's spend propagates to ALL
|
|
8587
8573
|
* ancestors up to the run root; the root ceiling remains the true
|
|
@@ -8590,11 +8576,11 @@ async function runAgent(options) {
|
|
|
8590
8576
|
* reserves are recovered from spawn-admission decision entries); the
|
|
8591
8577
|
* per-account historical fold completes with DEF-7 in M7.
|
|
8592
8578
|
*
|
|
8593
|
-
*
|
|
8579
|
+
* Full contract: https://docs.rulvar.com/guide/budgets
|
|
8594
8580
|
*/
|
|
8595
|
-
/** Last resort of the admission reserve formula
|
|
8581
|
+
/** Last resort of the admission reserve formula. */
|
|
8596
8582
|
const DEFAULT_FLAT_RESERVE_USD = .5;
|
|
8597
|
-
/** The run-root account scope
|
|
8583
|
+
/** The run-root account scope. */
|
|
8598
8584
|
const ROOT_ACCOUNT = "run";
|
|
8599
8585
|
const ZERO_USAGE = {
|
|
8600
8586
|
inputTokens: 0,
|
|
@@ -8603,8 +8589,7 @@ const ZERO_USAGE = {
|
|
|
8603
8589
|
cacheWriteTokens: 0
|
|
8604
8590
|
};
|
|
8605
8591
|
/**
|
|
8606
|
-
* The admission reserve for a spawn
|
|
8607
|
-
* before spawn"): opts.estCost, else profile.estCost, else
|
|
8592
|
+
* The admission reserve for a spawn: opts.estCost, else profile.estCost, else
|
|
8608
8593
|
* price(countTokens(input) + caps.maxOutputTokens), else the engine flat
|
|
8609
8594
|
* default.
|
|
8610
8595
|
*/
|
|
@@ -8670,7 +8655,7 @@ var RunBudget = class {
|
|
|
8670
8655
|
return chain;
|
|
8671
8656
|
}
|
|
8672
8657
|
/**
|
|
8673
|
-
* Opens a child sub-account under `parentScope
|
|
8658
|
+
* Opens a child sub-account under `parentScope`.
|
|
8674
8659
|
* Re-opening an existing scope is the resume roll-forward path: the
|
|
8675
8660
|
* recorded ceiling wins once and the accumulated state is kept.
|
|
8676
8661
|
*/
|
|
@@ -8727,7 +8712,7 @@ var RunBudget = class {
|
|
|
8727
8712
|
/**
|
|
8728
8713
|
* Marks the run exhausted without a ceiling event: the orchestrator
|
|
8729
8714
|
* finalize fallback maps to outcome 'exhausted' with the synthesized
|
|
8730
|
-
* partial value (DEF-7
|
|
8715
|
+
* partial value (DEF-7; exhaustion is never null).
|
|
8731
8716
|
*/
|
|
8732
8717
|
markExhausted() {
|
|
8733
8718
|
this.exhaustedInternal = true;
|
|
@@ -8744,7 +8729,7 @@ var RunBudget = class {
|
|
|
8744
8729
|
* Layer 1: admission before spawn. Blocks when spent + committedReserve
|
|
8745
8730
|
* has reached the ceiling on ANY account in the ancestor chain of
|
|
8746
8731
|
* `accountScope`, otherwise commits the reserve along the whole chain.
|
|
8747
|
-
* Also enforces the engine lifetime spawn cap
|
|
8732
|
+
* Also enforces the engine lifetime spawn cap.
|
|
8748
8733
|
*/
|
|
8749
8734
|
admitSpawn(reserveUsd, accountScope = "run") {
|
|
8750
8735
|
if (this.agentsSpawnedInternal >= this.lifetimeSpawnCap) {
|
|
@@ -8768,7 +8753,7 @@ var RunBudget = class {
|
|
|
8768
8753
|
/**
|
|
8769
8754
|
* Resume roll-forward: commits a reserve recovered from a journaled
|
|
8770
8755
|
* spawn-admission decision entry without re-evaluating admission
|
|
8771
|
-
* (
|
|
8756
|
+
* (reserves are recovered, never re-estimated).
|
|
8772
8757
|
*/
|
|
8773
8758
|
admitRecovered(reserveUsd, accountScope = "run") {
|
|
8774
8759
|
this.agentsSpawnedInternal += 1;
|
|
@@ -8776,7 +8761,7 @@ var RunBudget = class {
|
|
|
8776
8761
|
this.emitUpdate();
|
|
8777
8762
|
}
|
|
8778
8763
|
/**
|
|
8779
|
-
* Registers the orchestrator finalize reserve (DEF-7
|
|
8764
|
+
* Registers the orchestrator finalize reserve (DEF-7):
|
|
8780
8765
|
* absolute dollars set on the named account AND the run root, so
|
|
8781
8766
|
* admission never lets any spawn eat the finalization money even
|
|
8782
8767
|
* against whole-run exhaustion. Kept SEPARATE from committedReserveUsd
|
|
@@ -8852,7 +8837,7 @@ var RunBudget = class {
|
|
|
8852
8837
|
agentsSpawned: this.agentsSpawnedInternal
|
|
8853
8838
|
};
|
|
8854
8839
|
}
|
|
8855
|
-
/** Null when the run has no USD ceiling
|
|
8840
|
+
/** Null when the run has no USD ceiling. */
|
|
8856
8841
|
remaining() {
|
|
8857
8842
|
const root = this.root;
|
|
8858
8843
|
if (root.ceilingUsd === void 0) return null;
|
|
@@ -8877,8 +8862,8 @@ var RunBudget = class {
|
|
|
8877
8862
|
/**
|
|
8878
8863
|
* AdmissionController v1 (M6-T06; DEF-2, DEF-3, DEF-5 substrate).
|
|
8879
8864
|
*
|
|
8880
|
-
*
|
|
8881
|
-
*
|
|
8865
|
+
* Public contract: https://docs.rulvar.com/guide/adaptive-orchestration.
|
|
8866
|
+
* The single admission point for ALL spawns of any
|
|
8882
8867
|
* origin: ctx.workflow, the orchestrator spawn tools (M6-T07), escalation
|
|
8883
8868
|
* decomposition and rung respawns (M7). `admit(spec)` is called BEFORE
|
|
8884
8869
|
* the carrying spawn-admission decision entry is journaled; the verdict
|
|
@@ -8941,8 +8926,8 @@ var AdmissionController = class {
|
|
|
8941
8926
|
return this.lineageLimits;
|
|
8942
8927
|
}
|
|
8943
8928
|
/**
|
|
8944
|
-
* Binds the run's TerminationAccount (DEF-2; PlanRunner runs only
|
|
8945
|
-
*
|
|
8929
|
+
* Binds the run's TerminationAccount (DEF-2; PlanRunner runs only):
|
|
8930
|
+
* from bind time on, every admitted spawn of any
|
|
8946
8931
|
* origin debits one spawnUnit atomically with its decision entry, and
|
|
8947
8932
|
* a declared ladder longer than the frozen kMax rejects with
|
|
8948
8933
|
* ladder_exceeds_frozen. Non-PlanRunner runs never bind an account and
|
|
@@ -8957,7 +8942,7 @@ var AdmissionController = class {
|
|
|
8957
8942
|
return this.terminationAccount;
|
|
8958
8943
|
}
|
|
8959
8944
|
/**
|
|
8960
|
-
* The lineage half of admission (DEF-3
|
|
8945
|
+
* The lineage half of admission (DEF-3): folds are
|
|
8961
8946
|
* computed live STRICTLY BEFORE the carrying decision entry is appended;
|
|
8962
8947
|
* the caller embeds the returned block in the entry and replay reads it
|
|
8963
8948
|
* back byte-exact. Enforces the single-live-attempt invariant
|
|
@@ -9170,7 +9155,7 @@ var AdmissionController = class {
|
|
|
9170
9155
|
* Resume roll-forward for a child that already SETTLED before the
|
|
9171
9156
|
* resume: re-registers the counters (maxChildrenPerNode, the lifetime
|
|
9172
9157
|
* cap, statsBefore fidelity) without committing any reserve; the spend
|
|
9173
|
-
* itself sits in the root ledger seed
|
|
9158
|
+
* itself sits in the root ledger seed.
|
|
9174
9159
|
*/
|
|
9175
9160
|
recoverSettled(parentAccountScope) {
|
|
9176
9161
|
this.budget.admitRecovered(0, parentAccountScope);
|
|
@@ -9180,8 +9165,8 @@ var AdmissionController = class {
|
|
|
9180
9165
|
/**
|
|
9181
9166
|
* Resume roll-forward for an admission whose decision entry exists but
|
|
9182
9167
|
* whose child has NOT settled: re-applies the recorded reserve and
|
|
9183
|
-
* counters without re-evaluating any limit (
|
|
9184
|
-
* re-evaluates admission;
|
|
9168
|
+
* counters without re-evaluating any limit (replay never
|
|
9169
|
+
* re-evaluates admission; reserves are recovered, never
|
|
9185
9170
|
* re-estimated).
|
|
9186
9171
|
*/
|
|
9187
9172
|
recoverInFlight(parentAccountScope, verdict) {
|
|
@@ -9195,7 +9180,7 @@ var AdmissionController = class {
|
|
|
9195
9180
|
//#endregion
|
|
9196
9181
|
//#region src/orchestrator/handles.ts
|
|
9197
9182
|
/**
|
|
9198
|
-
* The committed WakeDigest render budget (
|
|
9183
|
+
* The committed WakeDigest render budget (Appendix A: 400
|
|
9199
9184
|
* chars per outputSummary row, the character measure; committed at M10
|
|
9200
9185
|
* entry by adopting the implemented distillation cap unchanged, the
|
|
9201
9186
|
* value frozen into every cassette since M6). One value serves both
|
|
@@ -9205,8 +9190,8 @@ var AdmissionController = class {
|
|
|
9205
9190
|
const WAKE_SUMMARY_RENDER_BUDGET_CHARS = 400;
|
|
9206
9191
|
/**
|
|
9207
9192
|
* The M6 outputSummary: a deterministic truncation of the child's
|
|
9208
|
-
* output (or error message), identical live and on replay (
|
|
9209
|
-
*
|
|
9193
|
+
* output (or error message), identical live and on replay (distillation
|
|
9194
|
+
* lives with the child, ordered by
|
|
9210
9195
|
* spawn ordinal; the LLM distillation upgrade is M7 territory).
|
|
9211
9196
|
*/
|
|
9212
9197
|
function summarizeOutput(result) {
|
|
@@ -9226,7 +9211,7 @@ function digestOf(record, result) {
|
|
|
9226
9211
|
}
|
|
9227
9212
|
//#endregion
|
|
9228
9213
|
//#region src/orchestrator/wake.ts
|
|
9229
|
-
/**
|
|
9214
|
+
/** The wait_for_events parameter schema (normative). */
|
|
9230
9215
|
const WAIT_FOR_EVENTS_SCHEMA = {
|
|
9231
9216
|
type: "object",
|
|
9232
9217
|
additionalProperties: false,
|
|
@@ -9303,7 +9288,7 @@ function emptyDigestBlocks() {
|
|
|
9303
9288
|
}
|
|
9304
9289
|
//#endregion
|
|
9305
9290
|
//#region src/orchestrator/spawn-tools.ts
|
|
9306
|
-
/**
|
|
9291
|
+
/** The spawn_agent parameter schema (normative). */
|
|
9307
9292
|
const SPAWN_AGENT_SCHEMA = {
|
|
9308
9293
|
type: "object",
|
|
9309
9294
|
additionalProperties: false,
|
|
@@ -9354,7 +9339,7 @@ const SPAWN_AGENT_SCHEMA = {
|
|
|
9354
9339
|
taskClass: { type: "string" }
|
|
9355
9340
|
}
|
|
9356
9341
|
};
|
|
9357
|
-
/**
|
|
9342
|
+
/** parallel_agents wraps the spawn_agent params. */
|
|
9358
9343
|
const PARALLEL_AGENTS_SCHEMA = {
|
|
9359
9344
|
type: "object",
|
|
9360
9345
|
additionalProperties: false,
|
|
@@ -9366,7 +9351,7 @@ const PARALLEL_AGENTS_SCHEMA = {
|
|
|
9366
9351
|
} },
|
|
9367
9352
|
$defs: { spawnAgentParams: SPAWN_AGENT_SCHEMA }
|
|
9368
9353
|
};
|
|
9369
|
-
/**
|
|
9354
|
+
/** await_any and await_all share one parameter shape. */
|
|
9370
9355
|
const AWAIT_SCHEMA = {
|
|
9371
9356
|
type: "object",
|
|
9372
9357
|
additionalProperties: false,
|
|
@@ -9380,7 +9365,7 @@ const AWAIT_SCHEMA = {
|
|
|
9380
9365
|
}
|
|
9381
9366
|
} }
|
|
9382
9367
|
};
|
|
9383
|
-
/**
|
|
9368
|
+
/** The cancel_agent parameter schema. */
|
|
9384
9369
|
const CANCEL_AGENT_SCHEMA = {
|
|
9385
9370
|
type: "object",
|
|
9386
9371
|
additionalProperties: false,
|
|
@@ -9393,7 +9378,7 @@ const CANCEL_AGENT_SCHEMA = {
|
|
|
9393
9378
|
reason: { type: "string" }
|
|
9394
9379
|
}
|
|
9395
9380
|
};
|
|
9396
|
-
/**
|
|
9381
|
+
/** finish; result validates against the declared output schema. */
|
|
9397
9382
|
const FINISH_SCHEMA = {
|
|
9398
9383
|
type: "object",
|
|
9399
9384
|
additionalProperties: false,
|
|
@@ -9407,7 +9392,7 @@ const FINISH_TOOL_NAME = "finish";
|
|
|
9407
9392
|
/**
|
|
9408
9393
|
* Builds the mode (c) toolset over the per-call runtime. profileCardText
|
|
9409
9394
|
* rides the spawn tools' descriptions so both modes speak one agent
|
|
9410
|
-
* vocabulary (
|
|
9395
|
+
* vocabulary (M6-T04).
|
|
9411
9396
|
*/
|
|
9412
9397
|
function buildOrchestratorTools(runtime, profileCardText) {
|
|
9413
9398
|
return [
|
|
@@ -9508,15 +9493,13 @@ function runtimeOf(ctx) {
|
|
|
9508
9493
|
* log, budget, and the deterministic shims; workflow/orchestrate/
|
|
9509
9494
|
* awaitExternal/brief land with their milestones (M2/M6).
|
|
9510
9495
|
*
|
|
9511
|
-
*
|
|
9512
|
-
* interface", "Error policy and dropped results", "Scheduler".
|
|
9496
|
+
* Public contract: https://docs.rulvar.com/guide/workflows.
|
|
9513
9497
|
*/
|
|
9514
9498
|
/**
|
|
9515
9499
|
* The rejection carrier of ctx.agent value-form calls: a real Error that
|
|
9516
|
-
* structurally satisfies the typed AgentError
|
|
9517
|
-
*
|
|
9518
|
-
*
|
|
9519
|
-
* registry (docs/02, section "Error taxonomy").
|
|
9500
|
+
* structurally satisfies the typed AgentError and carries the full
|
|
9501
|
+
* AgentResult for Settled mapping. Deliberately not a RulvarError:
|
|
9502
|
+
* AgentError is not in the closed code registry.
|
|
9520
9503
|
*/
|
|
9521
9504
|
var AgentCallError = class extends Error {
|
|
9522
9505
|
kind;
|
|
@@ -9560,9 +9543,9 @@ function bump(map, key, usd) {
|
|
|
9560
9543
|
}
|
|
9561
9544
|
/**
|
|
9562
9545
|
* Completes a model-authored escalation request into the full report:
|
|
9563
|
-
* costToDate and salvage are runtime-filled, never model-filled
|
|
9564
|
-
*
|
|
9565
|
-
*
|
|
9546
|
+
* costToDate and salvage are runtime-filled, never model-filled. The
|
|
9547
|
+
* worktree patch ref lands after collect(); the pre-dispose preview for
|
|
9548
|
+
* flavor B decision-makers omits it.
|
|
9566
9549
|
*/
|
|
9567
9550
|
function buildEscalationReport(request, result, worktreePatchRef) {
|
|
9568
9551
|
return {
|
|
@@ -10528,7 +10511,7 @@ function createCtx(internals) {
|
|
|
10528
10511
|
}
|
|
10529
10512
|
/**
|
|
10530
10513
|
* Per-(scope, name) invocation ordinals of ctx.workflow, in execution
|
|
10531
|
-
* order (
|
|
10514
|
+
* order (nested workflow scopes).
|
|
10532
10515
|
*/
|
|
10533
10516
|
const workflowOrdinals = /* @__PURE__ */ new Map();
|
|
10534
10517
|
const nextWorkflowOrdinal = (scope, name) => {
|
|
@@ -10546,7 +10529,7 @@ function createCtx(internals) {
|
|
|
10546
10529
|
rebuilt.name = wire.code;
|
|
10547
10530
|
return rebuilt;
|
|
10548
10531
|
};
|
|
10549
|
-
/** Maps an embedded admission rejection onto its typed error
|
|
10532
|
+
/** Maps an embedded admission rejection onto its typed error. */
|
|
10550
10533
|
const rejectionError = (reason, name) => {
|
|
10551
10534
|
if (reason.code === "budget" || reason.code === "lifetime") return new BudgetExhaustedError(`admission rejected child workflow '${name}' (${reason.code})`, { data: { reason } });
|
|
10552
10535
|
return new AdmissionRejectedError(`admission rejected child workflow '${name}' (${reason.code}; maxDepth/maxChildrenPerNode are set via createEngine budgetDefaults)`, { data: { reason } });
|
|
@@ -10850,8 +10833,7 @@ async function executeWorkflow(internals, wf, args) {
|
|
|
10850
10833
|
/**
|
|
10851
10834
|
* The mode (c) dynamic orchestrator (M6-T07/T08).
|
|
10852
10835
|
*
|
|
10853
|
-
*
|
|
10854
|
-
* docs/07-adaptive-orchestration-spec.md sections 1 and 4. An ordinary
|
|
10836
|
+
* Full contract: https://docs.rulvar.com/guide/adaptive-orchestration. An ordinary
|
|
10855
10837
|
* workflow whose agent (role 'orchestrate') holds the typed spawn tools;
|
|
10856
10838
|
* both surfaces (top-level orchestrate() and ctx.orchestrate) share this
|
|
10857
10839
|
* one implementation, the nested surface riding ctx.workflow so the
|
|
@@ -10862,7 +10844,7 @@ async function executeWorkflow(internals, wf, args) {
|
|
|
10862
10844
|
* ordinary kind 'agent' entry; a crashed orchestrate() restores its
|
|
10863
10845
|
* history from the checkpoint and finds child results by content keys,
|
|
10864
10846
|
* WITHOUT regenerating spawn decisions and without re-paying children.
|
|
10865
|
-
* Non-PlanRunner applicability
|
|
10847
|
+
* Non-PlanRunner applicability: only the lifetime
|
|
10866
10848
|
* cap, maxDepth, and the budget layers apply; no termination.init is
|
|
10867
10849
|
* written; escalated children simply settle into their digests.
|
|
10868
10850
|
*/
|
|
@@ -10881,7 +10863,7 @@ function orchestratorPrompt(goal, maxSpawns, extensionLines) {
|
|
|
10881
10863
|
}
|
|
10882
10864
|
/**
|
|
10883
10865
|
* Resolves per-spawn dispatch options against the engine registries
|
|
10884
|
-
* (
|
|
10866
|
+
* (registered SchemaSpec and tool profile names; M7-T05). An
|
|
10885
10867
|
* unknown ref is a typed ConfigError, surfaced as a tool error to the
|
|
10886
10868
|
* orchestrator and never a run failure.
|
|
10887
10869
|
*/
|
|
@@ -10928,7 +10910,15 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
10928
10910
|
const admission = internals.admission;
|
|
10929
10911
|
const callingState = runtime.currentState();
|
|
10930
10912
|
const advertisedProfiles = filterProfiles(internals.defaults.profiles, opts?.profiles);
|
|
10931
|
-
const
|
|
10913
|
+
const spawnableProfiles = {};
|
|
10914
|
+
const declaredLadderNames = [];
|
|
10915
|
+
for (const [name, profile] of Object.entries(advertisedProfiles)) {
|
|
10916
|
+
const spec = profile.model;
|
|
10917
|
+
if (spec !== void 0 && typeof spec !== "string" && "ladder" in spec) declaredLadderNames.push(name);
|
|
10918
|
+
else spawnableProfiles[name] = profile;
|
|
10919
|
+
}
|
|
10920
|
+
declaredLadderNames.sort();
|
|
10921
|
+
const cardText = declaredLadderNames.length === 0 ? profileCard(advertisedProfiles) : `${profileCard(spawnableProfiles)}\nDeclared ladders (tier context for the knowledge card; NOT agentType values, never spawn them): ${declaredLadderNames.join(", ")}.`;
|
|
10932
10922
|
const extension = opts?.extension;
|
|
10933
10923
|
let orchestratorAccount;
|
|
10934
10924
|
let capState;
|
|
@@ -11156,7 +11146,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11156
11146
|
const forcedFinishController = new AbortController();
|
|
11157
11147
|
let capInFlight = false;
|
|
11158
11148
|
/**
|
|
11159
|
-
* The at-cap freeze
|
|
11149
|
+
* The at-cap freeze: EXACTLY one decision entry
|
|
11160
11150
|
* strictly before any effects; then the plan freezes for adaptation,
|
|
11161
11151
|
* wake triggers except quiescence disarm, and the orchestrator is
|
|
11162
11152
|
* driven to the reserved final wake. Crash between the entry and the
|
|
@@ -11203,7 +11193,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11203
11193
|
}, callingState.spanId);
|
|
11204
11194
|
forcedFinishController.abort("rulvar:forced-finish");
|
|
11205
11195
|
};
|
|
11206
|
-
/** Layer-1 soft boundary before delivering each wake
|
|
11196
|
+
/** Layer-1 soft boundary before delivering each wake. */
|
|
11207
11197
|
const overSoftBoundary = () => {
|
|
11208
11198
|
if (capState === void 0 || orchestratorAccount === void 0 || extension === void 0) return false;
|
|
11209
11199
|
return (internals.budget.accountView(orchestratorAccount)?.spentUsd ?? 0) + capState.turnEstimateUsd > capState.effectiveCapUsd - capState.finalizeReserveUsd;
|
|
@@ -11281,6 +11271,8 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11281
11271
|
if (opts?.maxSpawns !== void 0 && spawnOrdinal >= opts.maxSpawns) throw new AdmissionRejectedError(`orchestrate maxSpawns ${String(opts.maxSpawns)} reached`, { data: { reason: { code: "lifetime" } } });
|
|
11282
11272
|
const scope = childScopeOf();
|
|
11283
11273
|
const profile = internals.defaults.profiles?.[params.agentType];
|
|
11274
|
+
const profileModel = profile?.model;
|
|
11275
|
+
if (profileModel !== void 0 && typeof profileModel !== "string" && "ladder" in profileModel) throw new ConfigError(`agentType '${params.agentType}' declares a ladder; ladder execution is owned by the plan extension, which resolves each rung attempt to a concrete model override (docs/07, section 10); spawn a concrete profile instead`);
|
|
11284
11276
|
const decision = admission.admit({
|
|
11285
11277
|
origin: "spawn_agent",
|
|
11286
11278
|
name: params.agentType,
|
|
@@ -11453,7 +11445,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11453
11445
|
ladders,
|
|
11454
11446
|
...internals.floors === void 0 ? {} : { floors: internals.floors },
|
|
11455
11447
|
now: new Date(internals.now()).toISOString()
|
|
11456
|
-
}), ladders);
|
|
11448
|
+
}), ladders, { profiles: advertisedProfiles });
|
|
11457
11449
|
await internals.replayer.appendSinglePhase({
|
|
11458
11450
|
scope: callingState.scope,
|
|
11459
11451
|
key,
|
|
@@ -11510,6 +11502,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11510
11502
|
role: "orchestrate",
|
|
11511
11503
|
result: "full",
|
|
11512
11504
|
tools: [...buildOrchestratorTools(orchestratorRuntime, fullCardText), ...extension?.tools(io) ?? []],
|
|
11505
|
+
...capState === void 0 ? {} : { estCost: capState.effectiveCapUsd },
|
|
11513
11506
|
...opts?.model === void 0 ? {} : { model: opts.model },
|
|
11514
11507
|
...opts?.limits === void 0 ? {} : { limits: opts.limits },
|
|
11515
11508
|
[kOnRunning]: (seq) => {
|
|
@@ -11523,7 +11516,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11523
11516
|
if (orchestratorAccount !== void 0) orchestratorState.budgetScope = orchestratorAccount;
|
|
11524
11517
|
orchestratorState.signal = callingState.signal === void 0 ? forcedFinishController.signal : AbortSignal.any([callingState.signal, forcedFinishController.signal]);
|
|
11525
11518
|
/**
|
|
11526
|
-
* The reserved final wake
|
|
11519
|
+
* The reserved final wake: a FRESH agent entry on
|
|
11527
11520
|
* the restricted single-tool toolset (a different toolsetHash), a
|
|
11528
11521
|
* prompt deterministically derived from the journaled cap decision
|
|
11529
11522
|
* and the pinned digest, and a finalizeTurns limit, paid from the
|
|
@@ -11541,6 +11534,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11541
11534
|
result: "full",
|
|
11542
11535
|
tools: finishOnly,
|
|
11543
11536
|
limits: { maxTurns: capState?.finalizeTurns ?? 2 },
|
|
11537
|
+
...capState === void 0 ? {} : { estCost: capState.finalizeReserveUsd },
|
|
11544
11538
|
...opts?.model === void 0 ? {} : { model: opts.model },
|
|
11545
11539
|
[kTerminalTool]: { name: FINISH_TOOL_NAME }
|
|
11546
11540
|
};
|
|
@@ -11593,7 +11587,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11593
11587
|
return result.output;
|
|
11594
11588
|
});
|
|
11595
11589
|
}
|
|
11596
|
-
/** Top-level surface: creates a run
|
|
11590
|
+
/** Top-level surface: creates a run. */
|
|
11597
11591
|
function orchestrate(engine, goal, opts) {
|
|
11598
11592
|
return engine.run(makeOrchestratorWorkflow(goal, opts), void 0);
|
|
11599
11593
|
}
|
|
@@ -11603,16 +11597,13 @@ function orchestrate(engine, goal, opts) {
|
|
|
11603
11597
|
* Per-run event machinery (M1-T10): the span registry (run > phase >
|
|
11604
11598
|
* agent > tool > child hierarchy) and the event bus that stamps the
|
|
11605
11599
|
* WorkflowEvent envelope, feeds RunHandle.events / on(), and fans out to
|
|
11606
|
-
* subscribers. EventSink is deliberately not an SPI
|
|
11607
|
-
* "SPI seams and the 1.0 freeze").
|
|
11600
|
+
* subscribers. EventSink is deliberately not an SPI.
|
|
11608
11601
|
*
|
|
11609
|
-
*
|
|
11610
|
-
* stream".
|
|
11602
|
+
* Full contract: https://docs.rulvar.com/guide/observability.
|
|
11611
11603
|
*/
|
|
11612
11604
|
/**
|
|
11613
11605
|
* Spans form a tree per run; spanId values are engine-minted opaque
|
|
11614
|
-
* strings, unique per run, pure telemetry, never identity
|
|
11615
|
-
* section "Span hierarchy").
|
|
11606
|
+
* strings, unique per run, pure telemetry, never identity.
|
|
11616
11607
|
*/
|
|
11617
11608
|
var SpanRegistry = class {
|
|
11618
11609
|
parents = /* @__PURE__ */ new Map();
|
|
@@ -11777,15 +11768,14 @@ var InProcessRunner = class {
|
|
|
11777
11768
|
* Engine entry points (M1-T11): createEngine and engine.run over the
|
|
11778
11769
|
* InProcessRunner. Every registry hangs off the engine instance; nothing
|
|
11779
11770
|
* is module-global, so two engines in one process are fully isolated and
|
|
11780
|
-
* ctx is created per run
|
|
11781
|
-
* section "Engine and ops API"). engine.resume lands with the journal
|
|
11771
|
+
* ctx is created per run. engine.resume lands with the journal
|
|
11782
11772
|
* kernel in M2.
|
|
11783
11773
|
*/
|
|
11784
|
-
/** Content hash of an in-process workflow body (run-to-definition binding
|
|
11774
|
+
/** Content hash of an in-process workflow body (run-to-definition binding). */
|
|
11785
11775
|
function hashWorkflowBody(wf) {
|
|
11786
11776
|
return createHash("sha256").update(wf.body.toString(), "utf8").digest("hex");
|
|
11787
11777
|
}
|
|
11788
|
-
/** Content hash of a compiled workflow source (run-to-definition binding
|
|
11778
|
+
/** Content hash of a compiled workflow source (run-to-definition binding). */
|
|
11789
11779
|
function hashWorkflowSource(source) {
|
|
11790
11780
|
return createHash("sha256").update(source, "utf8").digest("hex");
|
|
11791
11781
|
}
|
|
@@ -12202,11 +12192,11 @@ function createEngine(options) {
|
|
|
12202
12192
|
/**
|
|
12203
12193
|
* The host half of the worker sandbox contract (M6-T02).
|
|
12204
12194
|
*
|
|
12205
|
-
*
|
|
12195
|
+
* Full contract: https://docs.rulvar.com/guide/planner. WorkerSandboxRunner
|
|
12206
12196
|
* (@rulvar/planner) owns the worker lifecycle and the MessagePort; this
|
|
12207
12197
|
* core-owned bridge serves every sandbox primitive against the canonical
|
|
12208
|
-
* ctx of the run, so the runner builds exclusively from the public API
|
|
12209
|
-
*
|
|
12198
|
+
* ctx of the run, so the runner builds exclusively from the public API.
|
|
12199
|
+
* The boundary is journal-compatible JSON
|
|
12210
12200
|
* validated on both sides; raw structured clone is NOT the contract.
|
|
12211
12201
|
*
|
|
12212
12202
|
* Responsibilities:
|