@sema-agent/core 5.65.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -0
- package/dist/agents/subagent.d.ts +2 -2
- package/dist/agents/subagent.js +11 -0
- package/dist/agents/verify.d.ts +1 -1
- package/dist/brain/anthropic.js +1 -1
- package/dist/brain/errors.d.ts +29 -0
- package/dist/brain/errors.js +20 -0
- package/dist/brain/open-responses.js +2 -2
- package/dist/brain/route-adjudicator.d.ts +8 -1
- package/dist/brain/route-adjudicator.js +1 -0
- package/dist/brain/status-sink.js +12 -1
- package/dist/brain/stream-engine.js +17 -6
- package/dist/core/auto-compaction.d.ts +26 -0
- package/dist/core/auto-compaction.js +7 -2
- package/dist/core/auto-mode-arming.d.ts +138 -0
- package/dist/core/auto-mode-arming.js +181 -0
- package/dist/core/auto-mode-defaults.d.ts +13 -0
- package/dist/core/auto-mode-defaults.js +5 -0
- package/dist/core/auto-mode-prompt.d.ts +14 -3
- package/dist/core/auto-mode-prompt.js +10 -7
- package/dist/core/auto-mode-rebuild.d.ts +75 -0
- package/dist/core/auto-mode-rebuild.js +41 -0
- package/dist/core/auto-mode.d.ts +15 -0
- package/dist/core/auto-mode.js +4 -2
- package/dist/core/checkpoint-store.d.ts +18 -0
- package/dist/core/context-edit.d.ts +47 -5
- package/dist/core/context-guard.d.ts +1 -1
- package/dist/core/file-history-retention.d.ts +106 -0
- package/dist/core/file-history-retention.js +36 -0
- package/dist/core/file-history-store.d.ts +768 -0
- package/dist/core/file-history-store.js +880 -0
- package/dist/core/governance-codes.d.ts +13 -3
- package/dist/core/governance-codes.js +15 -0
- package/dist/core/hooks.d.ts +39 -7
- package/dist/core/hooks.js +38 -21
- package/dist/core/lsp.d.ts +2 -2
- package/dist/core/mcp.d.ts +29 -7
- package/dist/core/memory-engine/consolidation-driver.d.ts +11 -0
- package/dist/core/memory-engine/consolidation-driver.js +71 -4
- package/dist/core/memory-engine/consolidation.d.ts +25 -2
- package/dist/core/memory-engine/consolidation.js +4 -1
- package/dist/core/memory-engine/distiller.d.ts +84 -1
- package/dist/core/memory-engine/distiller.js +68 -0
- package/dist/core/memory-engine/dual-root.js +3 -0
- package/dist/core/memory-engine/engine.d.ts +328 -15
- package/dist/core/memory-engine/engine.js +355 -29
- package/dist/core/memory-engine/file-backend.d.ts +30 -0
- package/dist/core/memory-engine/file-backend.js +14 -13
- package/dist/core/memory-engine/frontmatter.d.ts +22 -1
- package/dist/core/memory-engine/frontmatter.js +3 -0
- package/dist/core/memory-engine/header-hints.d.ts +5 -0
- package/dist/core/memory-engine/index.d.ts +5 -4
- package/dist/core/memory-engine/index.js +5 -4
- package/dist/core/memory-engine/layout.d.ts +88 -2
- package/dist/core/memory-engine/layout.js +112 -3
- package/dist/core/memory-engine/provenance-wording.d.ts +7 -0
- package/dist/core/memory-engine/provenance-wording.js +3 -0
- package/dist/core/memory-engine/tools.d.ts +89 -8
- package/dist/core/memory-engine/tools.js +263 -22
- package/dist/core/memory-engine/types.d.ts +64 -1
- package/dist/core/memory-recall.d.ts +6 -0
- package/dist/core/memory.d.ts +27 -1
- package/dist/core/memory.js +16 -2
- package/dist/core/permission-rule-consent.d.ts +62 -2
- package/dist/core/permission-rule-consent.js +105 -14
- package/dist/core/permission-rule-model.d.ts +118 -16
- package/dist/core/permission-rule-model.js +57 -9
- package/dist/core/permission-rule-session.d.ts +124 -0
- package/dist/core/permission-rule-session.js +121 -0
- package/dist/core/permission-rule-store.d.ts +65 -2
- package/dist/core/permission-rule-store.js +75 -16
- package/dist/core/permission-rule-sync.d.ts +9 -0
- package/dist/core/permission-rule-sync.js +52 -19
- package/dist/core/retention-policy.d.ts +9 -0
- package/dist/core/retention-policy.js +5 -2
- package/dist/core/retention.d.ts +13 -2
- package/dist/core/runner/assemble-result.d.ts +19 -1
- package/dist/core/runner/assemble-result.js +17 -2
- package/dist/core/runner/compaction-call-options.d.ts +93 -0
- package/dist/core/runner/compaction-call-options.js +3 -0
- package/dist/core/runner/memory-capture-optout.d.ts +80 -0
- package/dist/core/runner/memory-capture-optout.js +53 -0
- package/dist/core/runner/prepare-config-doors.d.ts +5 -0
- package/dist/core/runner/prepare-config-doors.js +16 -0
- package/dist/core/runner/prepare-hands-readface.d.ts +110 -5
- package/dist/core/runner/prepare-hands-readface.js +99 -7
- package/dist/core/runner/prepare-memory.d.ts +88 -0
- package/dist/core/runner/prepare-memory.js +305 -24
- package/dist/core/runner/prepare-task.d.ts +141 -1
- package/dist/core/runner/prepare-task.js +478 -81
- package/dist/core/runner/runtask.d.ts +9 -20
- package/dist/core/runner/runtask.js +133 -96
- package/dist/core/runner/session-file-state-replay.d.ts +18 -10
- package/dist/core/runner/session-file-state-replay.js +52 -1
- package/dist/core/runner/tool-disclosure.js +2 -1
- package/dist/core/runner/turn-attachments.d.ts +22 -12
- package/dist/core/session-store.d.ts +1 -1
- package/dist/core/session-store.js +6 -1
- package/dist/core/session.d.ts +34 -1
- package/dist/core/store-contracts/file-history-store-contract.d.ts +3 -0
- package/dist/core/store-contracts/file-history-store-contract.js +720 -0
- package/dist/core/store-contracts/permission-rule-sync-contract.js +15 -1
- package/dist/core/task-registry-shared.js +11 -1
- package/dist/core/tool-errors.js +1 -0
- package/dist/core/tool-policy.d.ts +172 -1
- package/dist/core/tool-policy.js +32 -1
- package/dist/core/tool-result-store.js +2 -1
- package/dist/core/trace.d.ts +31 -2
- package/dist/core/types.d.ts +795 -89
- package/dist/core/types.js +4 -3
- package/dist/core/untrusted-text.d.ts +1 -1
- package/dist/core/untrusted-text.js +8 -0
- package/dist/core/workflow-run-store-contract.js +6 -2
- package/dist/core/workflow-run-store.d.ts +4 -1
- package/dist/engine/compaction/compaction.d.ts +88 -10
- package/dist/engine/compaction/compaction.js +109 -30
- package/dist/engine/execution-env/node-execution-env.d.ts +9 -1
- package/dist/engine/execution-env/node-execution-env.js +28 -0
- package/dist/engine/harness/agent-harness.d.ts +52 -1
- package/dist/engine/harness/agent-harness.js +36 -1
- package/dist/engine/harness/types.d.ts +26 -1
- package/dist/engine/llm/types.d.ts +50 -4
- package/dist/engine/loop/agent-loop.d.ts +5 -1
- package/dist/engine/loop/agent-loop.js +25 -0
- package/dist/engine/loop/types.d.ts +19 -0
- package/dist/engine/lsp/node-lsp-manager.d.ts +1 -1
- package/dist/engine/session/session.js +1 -1
- package/dist/index.d.ts +20 -9
- package/dist/index.js +16 -7
- package/dist/orchestration/run-workflow-tool.d.ts +20 -2
- package/dist/orchestration/run-workflow-tool.js +22 -3
- package/dist/orchestration/workflow-governance.d.ts +59 -1
- package/dist/orchestration/workflow-governance.js +61 -8
- package/dist/orchestration/workflow-meta.d.ts +4 -2
- package/dist/orchestration/workflow-primitives.js +56 -13
- package/dist/orchestration/workflow-types.d.ts +78 -2
- package/dist/orchestration/workflow.d.ts +20 -0
- package/dist/orchestration/workflow.js +163 -14
- package/dist/prompt-assembly/event-registry.js +1 -1
- package/dist/prompts/default.d.ts +7 -7
- package/dist/stores/file/file-history-store.d.ts +368 -0
- package/dist/stores/file/file-history-store.js +1248 -0
- package/dist/stores/file/index.d.ts +22 -13
- package/dist/stores/file/index.js +4 -4
- package/dist/stores/file/permission-rule-store.d.ts +11 -0
- package/dist/stores/file/permission-rule-store.js +23 -9
- package/dist/stores/file/strategy-store.d.ts +3 -3
- package/dist/tools/fs/bash-readonly-classifier.d.ts +87 -3
- package/dist/tools/fs/bash-readonly-classifier.js +106 -4
- package/dist/tools/fs/fs-bash.js +9 -5
- package/dist/tools/fs/fs-shared.d.ts +52 -1
- package/dist/tools/fs/fs-shared.js +14 -0
- package/dist/tools/fs/fs-write.d.ts +5 -5
- package/dist/tools/fs/fs-write.js +71 -14
- package/dist/tools/fs/index.d.ts +6 -1
- package/dist/tools/fs/index.js +1 -1
- package/dist/tools/web.js +2 -1
- package/package.json +5 -1
- package/test/export-surface.snapshot.json +169 -23
- package/dist/core/file-snapshot-store.d.ts +0 -165
- package/dist/core/file-snapshot-store.js +0 -259
- package/dist/core/store-contracts/file-snapshot-store-contract.d.ts +0 -13
- package/dist/core/store-contracts/file-snapshot-store-contract.js +0 -134
- package/dist/stores/file/file-snapshot-store.d.ts +0 -58
- package/dist/stores/file/file-snapshot-store.js +0 -353
|
@@ -474,6 +474,36 @@ export declare class FileMemoryEngineBackend implements MemoryBackend {
|
|
|
474
474
|
private enqueueExternalItems;
|
|
475
475
|
/** One-shot dedup for adopting-face notices (see {@link adoptionNoticeKeys}). */
|
|
476
476
|
private announceAdoptionNotice;
|
|
477
|
+
/**
|
|
478
|
+
* §3.4 — the standing unbound-row disclosure, in ONE spelling for BOTH faces that carry it (the
|
|
479
|
+
* harvest preflight `checkControlPlane` and the restricted sweep `auditRestrictedDivergence` used
|
|
480
|
+
* to hold drifting hand-built copies of this sentence; the sweep's copy had lost the remediation
|
|
481
|
+
* clause, which is if anything MORE apt there — a restricted session has no write channel of its
|
|
482
|
+
* own to converge the row).
|
|
483
|
+
*
|
|
484
|
+
* De-duplicated against what is ALREADY QUEUED, not against a per-instance latch. The repeat this
|
|
485
|
+
* closes was not merely noise: the queue is bounded ({@link MEMORY_ANNOUNCEMENTS_MAX}), so a
|
|
486
|
+
* long-lived instance with one stuck row folded REAL notices out of it to make room for copies of
|
|
487
|
+
* this one. But the latch the sibling adoption notices use ({@link announceAdoptionNotice}) is the
|
|
488
|
+
* wrong instrument HERE, twice over, and both were found in review:
|
|
489
|
+
* · a backend instance is a RUNNER-level dependency reused across every session it serves, so a
|
|
490
|
+
* per-instance latch would announce the standing condition to the first session and then hold
|
|
491
|
+
* its peace forever — turning a flood into silence, against this disclosure's own contract
|
|
492
|
+
* (「the STATE does not go silent」). The queue is DRAINED at each session's first injection, so
|
|
493
|
+
* "is an identical line still pending?" is exactly the right question: no repeat within a
|
|
494
|
+
* session, one fresh statement in every session that has not yet been told.
|
|
495
|
+
* · a latch key would have to encode the id set, and ledger row ids are arbitrary external
|
|
496
|
+
* strings (a comma is legal) — `join(",")` makes `["a,b","c"]` and `["a","b,c"]` the same key,
|
|
497
|
+
* so a real change of state could be suppressed. Comparing the RENDERED LINE has no such seam:
|
|
498
|
+
* two states that render the same sentence are, to every consumer, the same statement.
|
|
499
|
+
*
|
|
500
|
+
* The test runs INSIDE the queue's own locked read-modify-write
|
|
501
|
+
* ({@link enqueueMemoryAnnouncement}'s `supersedesPrefix`), not as a peek followed by an append: a
|
|
502
|
+
* peek-then-enqueue would race a concurrent drain, and two processes could both peek-miss and both
|
|
503
|
+
* append. Fail-open like every announce site — an unwritable queue never fails an operation that
|
|
504
|
+
* had something to say.
|
|
505
|
+
*/
|
|
506
|
+
private announceUnboundRows;
|
|
477
507
|
/** Resolve a binding's absolute projection path WITHOUT registering anything (probes must stay
|
|
478
508
|
* side-effect-free; `scopeDir` would register an unknown scope name from a hand-edited row). */
|
|
479
509
|
private bindingAbsPath;
|
|
@@ -179,6 +179,7 @@ function deleteRow(rows, id) {
|
|
|
179
179
|
function hasUnboundRows(rows) {
|
|
180
180
|
return rowsEntries(rows).some(([id]) => rowsBinding(rows, id) === undefined);
|
|
181
181
|
}
|
|
182
|
+
const UNBOUND_DISCLOSURE_PREFIX = "memory ledger has ";
|
|
182
183
|
function unboundRowIds(rows) {
|
|
183
184
|
return rowsEntries(rows)
|
|
184
185
|
.filter(([id]) => rowsBinding(rows, id) === undefined)
|
|
@@ -570,13 +571,8 @@ export class FileMemoryEngineBackend {
|
|
|
570
571
|
registeredScopes(this.controlPlaneRoot);
|
|
571
572
|
if (this.persistedSchemaVersion === "v1" || hasUnboundRows(this.loadLedger()))
|
|
572
573
|
this.tryOpportunisticMigrate();
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
const ids = unboundRowIds(rows);
|
|
576
|
-
this.enqueueExternalItems([
|
|
577
|
-
`memory ledger has ${ids.length} unbound row(s) (no derivable committed projection): ${ids.slice(0, 8).join(", ")}${ids.length > 8 ? ", …" : ""} — v2 binding guarantees do not cover them until they converge (duplicate projections need an unrestricted harvest or manual removal)`,
|
|
578
|
-
]);
|
|
579
|
-
}
|
|
574
|
+
if (this.persistedSchemaVersion === "v2")
|
|
575
|
+
this.announceUnboundRows(this.loadLedger());
|
|
580
576
|
}
|
|
581
577
|
drainInboundFindings() {
|
|
582
578
|
const out = this.inboundFindings;
|
|
@@ -642,6 +638,15 @@ export class FileMemoryEngineBackend {
|
|
|
642
638
|
this.adoptionNoticeKeys.add(key);
|
|
643
639
|
this.enqueueExternalItems([item]);
|
|
644
640
|
}
|
|
641
|
+
announceUnboundRows(rows) {
|
|
642
|
+
const ids = unboundRowIds(rows);
|
|
643
|
+
const item = ids.length === 0 ? undefined : `${UNBOUND_DISCLOSURE_PREFIX}${ids.length} unbound row(s) (no derivable committed projection): ${ids.slice(0, 8).join(", ")}${ids.length > 8 ? ", …" : ""} — v2 binding guarantees do not cover them until they converge (duplicate projections need an unrestricted harvest or manual removal)`;
|
|
644
|
+
try {
|
|
645
|
+
enqueueMemoryAnnouncement(this.controlPlaneRoot, { kind: "external", at: this.now(), items: item === undefined ? [] : [item] }, { supersedesPrefix: UNBOUND_DISCLOSURE_PREFIX });
|
|
646
|
+
}
|
|
647
|
+
catch {
|
|
648
|
+
}
|
|
649
|
+
}
|
|
645
650
|
bindingAbsPath(binding) {
|
|
646
651
|
return join(scopeDirFor(this.directoryRoot, this.controlPlaneRoot, binding.scope), `${binding.slug}.md`);
|
|
647
652
|
}
|
|
@@ -2033,12 +2038,8 @@ export class FileMemoryEngineBackend {
|
|
|
2033
2038
|
if (this.persistedSchemaVersion === "v1" || hasUnboundRows(this.loadLedger()))
|
|
2034
2039
|
this.tryOpportunisticMigrate();
|
|
2035
2040
|
const rows = { ...this.loadLedger() };
|
|
2036
|
-
if (this.persistedSchemaVersion === "v2"
|
|
2037
|
-
|
|
2038
|
-
this.enqueueExternalItems([
|
|
2039
|
-
`memory ledger has ${unboundIds.length} unbound row(s) (no derivable committed projection): ${unboundIds.slice(0, 8).join(", ")}${unboundIds.length > 8 ? ", …" : ""} — v2 binding guarantees do not cover them until they converge`,
|
|
2040
|
-
]);
|
|
2041
|
-
}
|
|
2041
|
+
if (this.persistedSchemaVersion === "v2")
|
|
2042
|
+
this.announceUnboundRows(rows);
|
|
2042
2043
|
const present = new Map();
|
|
2043
2044
|
let complete = true;
|
|
2044
2045
|
for (const scope of Object.keys(registeredScopes(this.controlPlaneRoot))) {
|
|
@@ -56,6 +56,27 @@ export declare function extraOriginCarriers(extra: readonly string[] | undefined
|
|
|
56
56
|
* so a committed multi-carrier shape always answers the one agreed value.
|
|
57
57
|
*/
|
|
58
58
|
export declare function committedOriginOf(fm: Pick<MemoryEntryFrontmatter, "origin" | "extra">): MemoryEntryOrigin | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* design/383 §1.6 — the CONSOLIDATION exposure predicate: is this entry's content untrusted for
|
|
61
|
+
* the purpose of the distillation fold? TWO axes, not one:
|
|
62
|
+
* - a committed external-origin marker ({@link committedOriginOf}) — the design/336 axis;
|
|
63
|
+
* - `trust: "untrusted"` — the design-A C-5 repo-ingest marker, which an ingested repo file can
|
|
64
|
+
* carry with NO origin marker at all. Such an entry is untrusted content by the same law that
|
|
65
|
+
* makes it un-whitewashable (the single-value marker has no `"trusted"` spelling to escalate
|
|
66
|
+
* to), and the origin-only predicate sorted it into the CLEAN arm — its bytes then authored
|
|
67
|
+
* clean products, and those products committed unmarked. That is exactly the marked-ingress
|
|
68
|
+
* laundering window the exposure partition exists to close.
|
|
69
|
+
*
|
|
70
|
+
* The direction is deliberately conservative (over-marking): an entry judged marked here is
|
|
71
|
+
* withheld from the clean arm and its products carry `external/derived`. Nothing here proves an
|
|
72
|
+
* unmarked entry clean — absence of both markers means "never judged exposed", as always.
|
|
73
|
+
*
|
|
74
|
+
* This is the consolidation lane's judgment only. The READ-face treatment (opaque handles, band
|
|
75
|
+
* ordering, the `MemoryEntryHeader.exposure` backend fact) stays on the origin axis alone: those
|
|
76
|
+
* faces answer "does the store carry an origin marker", a data question a third-party backend
|
|
77
|
+
* already answers, and widening them is a backend-contract change this predicate does not make.
|
|
78
|
+
*/
|
|
79
|
+
export declare function consolidationExposedFrontmatter(fm: Pick<MemoryEntryFrontmatter, "origin" | "extra" | "trust">): boolean;
|
|
59
80
|
/** Deep equality over the origin marker (every member, absence included) — the immutability law's
|
|
60
81
|
* comparator: a downgraded cause or a rewritten `at` is as refused as a strip. */
|
|
61
82
|
export declare function originEquals(a: MemoryEntryOrigin | undefined, b: MemoryEntryOrigin | undefined): boolean;
|
|
@@ -106,7 +127,7 @@ export declare function distilledEquals(a: MemoryEntryDistilled | undefined, b:
|
|
|
106
127
|
* design/339 §1.4.2-1 — the harvest-side STRIP of model-written distilled bytes (typed field AND
|
|
107
128
|
* distilled-form `extra` lines): the block is minted by the consolidation plan freeze EXCLUSIVELY —
|
|
108
129
|
* whatever a file on the model-writable plane says about its own lineage/supersession is not
|
|
109
|
-
* evidence (a model-writable edge would be the delete
|
|
130
|
+
* evidence (a model-writable edge would be the covert-delete channel add-only exists to close).
|
|
110
131
|
* Same seat and same disclosure discipline as {@link stripModelWrittenOrigin}. MUTATES the given
|
|
111
132
|
* (already-copied) frontmatter; returns true ⇔ anything was stripped.
|
|
112
133
|
*/
|
|
@@ -326,6 +326,9 @@ export function committedOriginOf(fm) {
|
|
|
326
326
|
return { taint: fm.origin.taint, ...(fm.origin.cause !== undefined ? { cause: fm.origin.cause } : {}), at: fm.origin.at };
|
|
327
327
|
return extraOriginCarriers(fm.extra)[0];
|
|
328
328
|
}
|
|
329
|
+
export function consolidationExposedFrontmatter(fm) {
|
|
330
|
+
return committedOriginOf(fm) !== undefined || fm.trust === "untrusted";
|
|
331
|
+
}
|
|
329
332
|
export function originEquals(a, b) {
|
|
330
333
|
if (a === undefined || b === undefined)
|
|
331
334
|
return a === b;
|
|
@@ -37,6 +37,11 @@ export interface V2HeaderHints {
|
|
|
37
37
|
* privilege AND walks through the exposure hard gate with it. ONE exported predicate on purpose:
|
|
38
38
|
* the write side (harvest hard gate) and any read-side consumer must judge through the same
|
|
39
39
|
* function, never through re-implementations that can drift.
|
|
40
|
+
*
|
|
41
|
+
* NAME COLLISION, not concept parity (test B12): `pinned` here is a
|
|
42
|
+
* WRITE-SIDE safety-privilege declaration (instruction-form ⇒ exposure hard gate / quarantine),
|
|
43
|
+
* while Claude Code's `pinned` is a RECALL-side display priority (up to 4 entries surfaced in a
|
|
44
|
+
* "# Pinned memories" block). Same word, different machines — do not read one as the other.
|
|
40
45
|
*/
|
|
41
46
|
export declare function isInstructionEntry(fm: {
|
|
42
47
|
type?: string;
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
export { MemoryEngine, buildMemoryInstruction, truncateIndex, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, memoryRecallDisciplineSegment, entryFileHeadCarriesOrigin, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, renderAnnouncements, type MemoryEngineOptions, type MemoryInjection, type EntryProvenanceAccount, memoryConsolidationRecommendedNotice, memoryConsolidationCommittedNotice, memoryConsolidationConflictNotice, memoryConsolidationIncompleteNotice, memoryConsolidationRefusedNotice, type ConsolidationCommitReceipt, type ConsolidationReconcileReport, type ConsolidationResolveReceipt, type ConsolidationPlanSummary, type ConsolidationPlanFoldEvidence, } from "./engine.js";
|
|
2
|
-
export { MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, type MemorySearchDetails, type MemorySearchHit, type CleanMemorySearchHit, type ExposedMemorySearchHit, type MemoryGetDetails, } from "./tools.js";
|
|
1
|
+
export { MemoryEngine, buildMemoryInstruction, truncateIndex, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, memoryRecallDisciplineSegment, entryFileHeadCarriesOrigin, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, renderAnnouncements, type MemoryEngineOptions, type MemoryInjection, type EntryProvenanceAccount, memoryConsolidationRecommendedNotice, memoryConsolidationCommittedNotice, memoryConsolidationConflictNotice, memoryConsolidationIncompleteNotice, memoryConsolidationRefusedNotice, memoryConsolidationWithheldNotice, MEMORY_CAPTURE_OPTOUT_NOTICE, memoryCaptureOptedOutNotice, memoryCaptureOptOutUnpersistedNotice, type ConsolidationCommitReceipt, type ConsolidationReconcileReport, type ConsolidationResolveReceipt, type ConsolidationPlanSummary, type ConsolidationPlanFoldEvidence, } from "./engine.js";
|
|
2
|
+
export { MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_INDEX_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, type MemorySearchDetails, type MemorySearchHit, type CleanMemorySearchHit, type ExposedMemorySearchHit, type MemoryGetDetails, type MemoryIndexDetails, type MemoryIndexRow, type CleanMemoryIndexRow, type ExposedMemoryIndexRow, } from "./tools.js";
|
|
3
3
|
export { MEMORY_EXPOSURE_BANNER, MEMORY_EXPOSURE_HANDLE_TAG, MEMORY_PROVENANCE_RECALL_SENTENCE, MEMORY_PROVENANCE_SEARCH_SENTENCE, memoryExposureIndexRow, parseMemoryExposureIndexRow, } from "./provenance-wording.js";
|
|
4
4
|
export { scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE } from "./scan.js";
|
|
5
5
|
export { FileMemoryEngineBackend, scanEntryFiles, MEMORY_INDEX_FILENAME, DEFAULT_MAX_ENTRY_DEPTH, type ScannedEntryFile, type TransferEvidence, type CommittedBinding, type CommittedEntrySnapshot, type CommittedScopeSnapshots, type EntryCustodyReport, erasureSelectHash, type EraseMemoryEntriesInput, type ErasureSelect, type ErasedBinding, type MemoryErasureAttestation, type MemoryExportSnapshot, } from "./file-backend.js";
|
|
6
6
|
export { computeBundleSectionHashes, computeMemoryBundleHash, memoryBundleInvalid, type MemoryExportBundle, type MemoryImportReport, type MemoryBundleImportPlan, type BundleChallengeRow, type BundleLineageRow, type BundlePollutedSession, } from "./export-bundle.js";
|
|
7
|
-
export { ControlPlaneCorruptError, deriveControlPlaneDir, deriveRepoControlPlaneDir, deriveRepoKey, deriveRepoMemoryDir, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, resolveMemoryEngineRoot, scopeDirFor, scopeDirName, claimRootScope, rootScopeOf, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, type ControlPlaneRebuildReceipt, type StrictControlPlaneLedger, type ChallengeAppendResult, type ChallengeAssignment, type ChallengeEvent, type ChallengedHistoryRow, type LineagePendingTxn, type LineagePromotion, } from "./layout.js";
|
|
7
|
+
export { ControlPlaneCorruptError, deriveControlPlaneDir, deriveRepoControlPlaneDir, deriveRepoKey, deriveRepoMemoryDir, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, resolveMemoryEngineRoot, scopeDirFor, scopeDirName, claimRootScope, rootScopeOf, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, type ControlPlaneRebuildReceipt, type StrictControlPlaneLedger, type ChallengeAppendResult, type ChallengeAssignment, type ChallengeEvent, type ChallengedHistoryRow, type LineagePendingTxn, type LineagePromotion, SESSION_CAPTURE_OPTOUT_DIR, markSessionCaptureOptOut, readSessionCaptureOptOut, listSessionCaptureOptOut, fileSessionCaptureRecordStore, type SessionCaptureOptOutRecord, type SessionCaptureOptOutMarkOutcome, type SessionCaptureRecordStore, } from "./layout.js";
|
|
8
8
|
export { readV2HeaderHints, isInstructionEntry, type V2HeaderHints } from "./header-hints.js";
|
|
9
9
|
export { parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, committedOriginOf, originEquals, ambiguousOriginRepresentation, type ParsedEntryFile } from "./frontmatter.js";
|
|
10
|
+
export { consolidationExposedFrontmatter } from "./frontmatter.js";
|
|
10
11
|
export { committedDistilledOf, distilledEquals } from "./frontmatter.js";
|
|
11
12
|
export { CONSOLIDATION_DEFAULTS, ConsolidationRefusedError, MEMORY_SEARCH_SUPERSEDED_TAG, consolidationTypeEligible, deriveSupersededSet, memorySupersededNote, readIntentCredentials, supersessionFuseCeiling, type ConsolidationGateRead, type ConsolidationGateRow, type ConsolidationIntent, type ConsolidationIntentCredentialRow, type ConsolidationLeaseSeat, type ConsolidationProductProposal, type ConsolidationProposal, type MemoryConsolidationOptions, CONSOLIDATION_RUN_STOP_REASONS, type ConsolidationRunStopReason, } from "./consolidation.js";
|
|
12
|
-
export { DISTILLER_DEFAULT_MAX_INPUTS_PER_PRODUCT, LLM_DISTILLER_CONTRACT, LLM_DISTILLER_CONTRACT_DL2, LLM_DISTILLER_CONTRACT_DL3, LLM_DISTILLER_CONTRACTS, MEMORY_DISTILLER_CONTRACT_V1, contractGroupingDiff, driveConsolidationToFixpoint, isAliasModelId, llmPlanDistiller, mintExposurePartitionedPlan, mintLlmConsolidationPlan, openAiCompatChatSeat, parseJsonAnswer, planParseRepairs, sanitizeLlmGroups, scheduleUnderFuse, type ConsolidationDistillFn, type ConsolidationDriveCycleRow, type ConsolidationDriveEngine, type ConsolidationDriveResult, type ConsolidationFoldState, type DistillerCandidate, type DistillerChatAnswer, type DistillerChatFn, type DistillerChatRequest, type FuseSchedule, type LlmConsolidationPlan, type LlmConsolidationPlanArm, type LlmConsolidationPlanProduct, type LlmDistillerContract, type MintLlmConsolidationPlanResult, type PlanParseRepairs, type SanitizedLlmGroups, } from "./distiller.js";
|
|
13
|
+
export { DISTILLER_DEFAULT_MAX_INPUTS_PER_PRODUCT, LLM_DISTILLER_CONTRACT, LLM_DISTILLER_CONTRACT_DL2, LLM_DISTILLER_CONTRACT_DL3, LLM_DISTILLER_CONTRACTS, MEMORY_DISTILLER_CONTRACT_V1, contractGroupingDiff, driveConsolidationToFixpoint, isAliasModelId, llmPlanDistiller, mintExposurePartitionedPlan, mintLlmConsolidationPlan, MEMORY_DISTILLER_PURITY_CONTRACT_V1, detectCleanArmVerbatimLeak, type CleanArmLeakFinding, type CleanArmLeakVerdict, type MemoryDistillerPurityContract, openAiCompatChatSeat, parseJsonAnswer, planParseRepairs, sanitizeLlmGroups, scheduleUnderFuse, type ConsolidationDistillFn, type ConsolidationDriveCycleRow, type ConsolidationDriveEngine, type ConsolidationDriveResult, type ConsolidationFoldState, type DistillerCandidate, type DistillerChatAnswer, type DistillerChatFn, type DistillerChatRequest, type FuseSchedule, type LlmConsolidationPlan, type LlmConsolidationPlanArm, type LlmConsolidationPlanProduct, type LlmDistillerContract, type MintLlmConsolidationPlanResult, type PlanParseRepairs, type SanitizedLlmGroups, } from "./distiller.js";
|
|
13
14
|
export { CONSOLIDATION_DRIVER_PLANS_DIR, CONSOLIDATION_DRIVER_RUNS_FILE, archiveDistillerPlan, readConsolidationDriverRun, runMemoryConsolidationDriver, type ConsolidationDriverEngine, type ConsolidationDriverRunRow, type ConsolidationRunReceipt, type RunMemoryConsolidationOptions, } from "./consolidation-driver.js";
|
|
14
15
|
export type { OriginClearanceRow, OriginClearanceEvent, OriginClearanceShadow } from "./origin-clearance.js";
|
|
15
16
|
export { MEMORY_ORIGIN_CAUSES } from "./types.js";
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
export { MemoryEngine, buildMemoryInstruction, truncateIndex, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, memoryRecallDisciplineSegment, entryFileHeadCarriesOrigin, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, renderAnnouncements, memoryConsolidationRecommendedNotice, memoryConsolidationCommittedNotice, memoryConsolidationConflictNotice, memoryConsolidationIncompleteNotice, memoryConsolidationRefusedNotice, } from "./engine.js";
|
|
2
|
-
export { MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, } from "./tools.js";
|
|
1
|
+
export { MemoryEngine, buildMemoryInstruction, truncateIndex, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, memoryRecallDisciplineSegment, entryFileHeadCarriesOrigin, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, renderAnnouncements, memoryConsolidationRecommendedNotice, memoryConsolidationCommittedNotice, memoryConsolidationConflictNotice, memoryConsolidationIncompleteNotice, memoryConsolidationRefusedNotice, memoryConsolidationWithheldNotice, MEMORY_CAPTURE_OPTOUT_NOTICE, memoryCaptureOptedOutNotice, memoryCaptureOptOutUnpersistedNotice, } from "./engine.js";
|
|
2
|
+
export { MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_INDEX_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, } from "./tools.js";
|
|
3
3
|
export { MEMORY_EXPOSURE_BANNER, MEMORY_EXPOSURE_HANDLE_TAG, MEMORY_PROVENANCE_RECALL_SENTENCE, MEMORY_PROVENANCE_SEARCH_SENTENCE, memoryExposureIndexRow, parseMemoryExposureIndexRow, } from "./provenance-wording.js";
|
|
4
4
|
export { scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE } from "./scan.js";
|
|
5
5
|
export { FileMemoryEngineBackend, scanEntryFiles, MEMORY_INDEX_FILENAME, DEFAULT_MAX_ENTRY_DEPTH, erasureSelectHash, } from "./file-backend.js";
|
|
6
6
|
export { computeBundleSectionHashes, computeMemoryBundleHash, memoryBundleInvalid, } from "./export-bundle.js";
|
|
7
|
-
export { ControlPlaneCorruptError, deriveControlPlaneDir, deriveRepoControlPlaneDir, deriveRepoKey, deriveRepoMemoryDir, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, resolveMemoryEngineRoot, scopeDirFor, scopeDirName, claimRootScope, rootScopeOf, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, } from "./layout.js";
|
|
7
|
+
export { ControlPlaneCorruptError, deriveControlPlaneDir, deriveRepoControlPlaneDir, deriveRepoKey, deriveRepoMemoryDir, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, resolveMemoryEngineRoot, scopeDirFor, scopeDirName, claimRootScope, rootScopeOf, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, SESSION_CAPTURE_OPTOUT_DIR, markSessionCaptureOptOut, readSessionCaptureOptOut, listSessionCaptureOptOut, fileSessionCaptureRecordStore, } from "./layout.js";
|
|
8
8
|
export { readV2HeaderHints, isInstructionEntry } from "./header-hints.js";
|
|
9
9
|
export { parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, committedOriginOf, originEquals, ambiguousOriginRepresentation } from "./frontmatter.js";
|
|
10
|
+
export { consolidationExposedFrontmatter } from "./frontmatter.js";
|
|
10
11
|
export { committedDistilledOf, distilledEquals } from "./frontmatter.js";
|
|
11
12
|
export { CONSOLIDATION_DEFAULTS, ConsolidationRefusedError, MEMORY_SEARCH_SUPERSEDED_TAG, consolidationTypeEligible, deriveSupersededSet, memorySupersededNote, readIntentCredentials, supersessionFuseCeiling, CONSOLIDATION_RUN_STOP_REASONS, } from "./consolidation.js";
|
|
12
|
-
export { DISTILLER_DEFAULT_MAX_INPUTS_PER_PRODUCT, LLM_DISTILLER_CONTRACT, LLM_DISTILLER_CONTRACT_DL2, LLM_DISTILLER_CONTRACT_DL3, LLM_DISTILLER_CONTRACTS, MEMORY_DISTILLER_CONTRACT_V1, contractGroupingDiff, driveConsolidationToFixpoint, isAliasModelId, llmPlanDistiller, mintExposurePartitionedPlan, mintLlmConsolidationPlan, openAiCompatChatSeat, parseJsonAnswer, planParseRepairs, sanitizeLlmGroups, scheduleUnderFuse, } from "./distiller.js";
|
|
13
|
+
export { DISTILLER_DEFAULT_MAX_INPUTS_PER_PRODUCT, LLM_DISTILLER_CONTRACT, LLM_DISTILLER_CONTRACT_DL2, LLM_DISTILLER_CONTRACT_DL3, LLM_DISTILLER_CONTRACTS, MEMORY_DISTILLER_CONTRACT_V1, contractGroupingDiff, driveConsolidationToFixpoint, isAliasModelId, llmPlanDistiller, mintExposurePartitionedPlan, mintLlmConsolidationPlan, MEMORY_DISTILLER_PURITY_CONTRACT_V1, detectCleanArmVerbatimLeak, openAiCompatChatSeat, parseJsonAnswer, planParseRepairs, sanitizeLlmGroups, scheduleUnderFuse, } from "./distiller.js";
|
|
13
14
|
export { CONSOLIDATION_DRIVER_PLANS_DIR, CONSOLIDATION_DRIVER_RUNS_FILE, archiveDistillerPlan, readConsolidationDriverRun, runMemoryConsolidationDriver, } from "./consolidation-driver.js";
|
|
14
15
|
export { MEMORY_ORIGIN_CAUSES } from "./types.js";
|
|
15
16
|
export { memoryBackendContract, assertMemoryBackendSearchEquivalence, } from "./memory-backend-contract.js";
|
|
@@ -268,8 +268,31 @@ interface AnnouncementsRecord {
|
|
|
268
268
|
folded: number;
|
|
269
269
|
queue: MemoryAnnouncement[];
|
|
270
270
|
}
|
|
271
|
-
/**
|
|
272
|
-
|
|
271
|
+
/**
|
|
272
|
+
* S2-B — enqueue one announcement (journaled + locked; bounded with overflow folding).
|
|
273
|
+
*
|
|
274
|
+
* `opts.supersedesPrefix` (#495) declares this announcement to be a STANDING CONDITION — one whose
|
|
275
|
+
* sentence is re-derived at every entry point until the condition clears — and names the family it
|
|
276
|
+
* belongs to by line prefix. Every queued line of that family is a STALE READING of the same
|
|
277
|
+
* condition, so the queue is made to hold exactly one of them, always the current one:
|
|
278
|
+
* · the identical line already queued unread ⇒ no-op, and no write at all;
|
|
279
|
+
* · otherwise every queued item with that prefix is dropped and this one appended.
|
|
280
|
+
* Merely SKIPPING a repeat is not enough, and that was the first form of this: a condition that goes
|
|
281
|
+
* A → B → A inside one unread window would leave `A, B` in the queue and a reader looking at B as the
|
|
282
|
+
* latest state — the fix for a flood turning into a wrong answer. Replacement makes the last word the
|
|
283
|
+
* true one.
|
|
284
|
+
*
|
|
285
|
+
* All of it runs INSIDE the locked read-modify-write, which is the point: a caller that peeked first
|
|
286
|
+
* and enqueued after would race a concurrent drain, and two processes could both peek-miss.
|
|
287
|
+
* Deliberately keyed on the LINE, not on a structural id — two states that render the same sentence
|
|
288
|
+
* are, to every consumer, the same statement. Deliberately opt-in: an ordinary event repeating IS
|
|
289
|
+
* news, and only its author knows which kind it is. Callers using it pass ONE item (a standing
|
|
290
|
+
* condition is one sentence), and the prefix must name the family precisely — anything else sharing
|
|
291
|
+
* it would be dropped as a stale sibling.
|
|
292
|
+
*/
|
|
293
|
+
export declare function enqueueMemoryAnnouncement(controlDir: string, ann: MemoryAnnouncement, opts?: {
|
|
294
|
+
supersedesPrefix?: string;
|
|
295
|
+
}): void;
|
|
273
296
|
/** S2-B — drain the queue (session-first inject, 时机①). Returns what was queued and resets it. */
|
|
274
297
|
export declare function drainMemoryAnnouncements(controlDir: string): AnnouncementsRecord;
|
|
275
298
|
/** Test/observability peek (journal-aware, non-destructive). */
|
|
@@ -330,6 +353,69 @@ export declare function listSessionPollution(controlDir: string): Record<string,
|
|
|
330
353
|
* write failure THROWS (the import aborts with its latch standing — §1-2⑤).
|
|
331
354
|
*/
|
|
332
355
|
export declare function importSessionPollution(controlDir: string, sessionId: string, record: SessionPollutionRecord): "written" | "already" | "divergent";
|
|
356
|
+
/** Directory (under the control plane) holding one record file per capture-opted-out session. */
|
|
357
|
+
export declare const SESSION_CAPTURE_OPTOUT_DIR = "session-capture-optout";
|
|
358
|
+
/** The durable capture opt-out record. `reason` is host/engine-authored (the declaring channel),
|
|
359
|
+
* never model text. */
|
|
360
|
+
export interface SessionCaptureOptOutRecord {
|
|
361
|
+
at: number;
|
|
362
|
+
reason: string;
|
|
363
|
+
}
|
|
364
|
+
/** Outcome vocabulary shared with the pollution marker (same `wx` one-way form): `"created"` ⇔ THIS
|
|
365
|
+
* call minted the record; `"existed"` ⇔ already recorded (a resumed session / an idempotent
|
|
366
|
+
* re-declaration); `"unpersisted"` ⇔ the record could not be written — the CALLER must refuse to
|
|
367
|
+
* run (design/383 §2.8: an opt-out that only holds in-process is broken by the first resume, so
|
|
368
|
+
* "could not persist" is a named refusal, never a silent in-process-only degrade — the deliberate
|
|
369
|
+
* divergence from the pollution marker's best-effort arm). */
|
|
370
|
+
export type SessionCaptureOptOutMarkOutcome = "created" | "existed" | "unpersisted";
|
|
371
|
+
/** Mark `sessionId` capture-opted-out (idempotent; the FIRST record wins — `wx` refuses overwrite). */
|
|
372
|
+
export declare function markSessionCaptureOptOut(controlDir: string, sessionId: string, reason: string, now: () => number): SessionCaptureOptOutMarkOutcome;
|
|
373
|
+
/** Read the durable capture opt-out record for `sessionId` (undefined = capture is on). Fail-closed
|
|
374
|
+
* exactly like the pollution read: a record that EXISTS but cannot be read or parsed still answers
|
|
375
|
+
* opted-out (a synthesized record stands in) — corruption must not launder a privacy request back
|
|
376
|
+
* into capture. Only ABSENCE reads as "capture on". A store state where existence itself cannot be
|
|
377
|
+
* established (dir-level IO fault) THROWS — the engine's `sessionCaptureOptOutOrFault` catch turns
|
|
378
|
+
* it into the INDETERMINATE fault axis (same fail-closed suppression, honest attribution — see the
|
|
379
|
+
* catch below). */
|
|
380
|
+
export declare function readSessionCaptureOptOut(controlDir: string, sessionId: string): SessionCaptureOptOutRecord | undefined;
|
|
381
|
+
/**
|
|
382
|
+
* Enumerate EVERY durable capture opt-out record (the consolidation eligibility arm's roster read —
|
|
383
|
+
* design/383 §2.4). Same fail-closed posture as {@link listSessionPollution}: a record that exists
|
|
384
|
+
* but cannot be read answers synthesized (never silently omitted); an absent directory is the
|
|
385
|
+
* genuine empty state (ENOENT only); any OTHER enumeration failure THROWS — a listing that silently
|
|
386
|
+
* dropped records would let the distiller amplify content its author asked to withhold.
|
|
387
|
+
*/
|
|
388
|
+
export declare function listSessionCaptureOptOut(controlDir: string): Record<string, SessionCaptureOptOutRecord>;
|
|
389
|
+
/**
|
|
390
|
+
* design/383 §2.1b — the control-plane carrier a HOST may substitute for the capture opt-out
|
|
391
|
+
* record's read/write/list (server F1: on a stateless multi-replica deployment the file form is
|
|
392
|
+
* invisible to the resume replica — "record not found" would break exactly toward capture). The
|
|
393
|
+
* core default is the file trio above, byte-identical for every deployment that supplies nothing.
|
|
394
|
+
* CONTRACT (each leg mirrors the file form's law):
|
|
395
|
+
* - `mark` is create-only/first-record-wins and must answer `"unpersisted"` (never throw) when the
|
|
396
|
+
* carrier cannot durably land the record;
|
|
397
|
+
* - `read` is fail-closed: a record that exists but cannot be decoded answers a synthesized
|
|
398
|
+
* record, never `undefined`; a store that cannot establish whether a record EXISTS (an outage)
|
|
399
|
+
* may THROW — the engine treats a throwing read as the INDETERMINATE fault axis (commit
|
|
400
|
+
* boundaries suppress fail-closed), which is the honest answer there: it must not fabricate a
|
|
401
|
+
* record ("a user request that never happened") and must not answer `undefined` ("no record"
|
|
402
|
+
* breaks exactly toward capture);
|
|
403
|
+
* - `list` throws on an enumeration failure (an unreadable roster is not an empty one).
|
|
404
|
+
* REGISTERED COMPANION (named, not silently absent): the session-POLLUTION marker has the same
|
|
405
|
+
* cloud-form invisibility (server F1 names both). It is NOT routed through this seat in this
|
|
406
|
+
* slice because the delegation-settlement lane's consumers are contractually PURE-DATA
|
|
407
|
+
* (`controlDir` + `sessionId` coordinates that outlive any live object — see the settlement handle
|
|
408
|
+
* doc in prepare-task.ts), and a live store object cannot ride that lane; its migration needs its
|
|
409
|
+
* own seam design and is registered here rather than half-built.
|
|
410
|
+
*/
|
|
411
|
+
export interface SessionCaptureRecordStore {
|
|
412
|
+
mark(sessionId: string, record: SessionCaptureOptOutRecord): SessionCaptureOptOutMarkOutcome;
|
|
413
|
+
read(sessionId: string): SessionCaptureOptOutRecord | undefined;
|
|
414
|
+
list(): Record<string, SessionCaptureOptOutRecord>;
|
|
415
|
+
}
|
|
416
|
+
/** The core-default {@link SessionCaptureRecordStore}: the file trio over `controlDir` (single-
|
|
417
|
+
* process / single-host deployments keep today's carrier byte-identical). */
|
|
418
|
+
export declare function fileSessionCaptureRecordStore(controlDir: string): SessionCaptureRecordStore;
|
|
333
419
|
/** The retrieved-account sidecar (control plane): entry id → { count, lastAt }. */
|
|
334
420
|
export declare const USAGE_RETRIEVED_FILE = "usage-retrieved.json";
|
|
335
421
|
/** Bound on tracked ids — over the cap, the entries with the OLDEST `lastAt` are evicted first
|
|
@@ -668,17 +668,34 @@ function coerceAnnouncements(raw) {
|
|
|
668
668
|
typeof a.at === "number" &&
|
|
669
669
|
Array.isArray(a.items) &&
|
|
670
670
|
a.items.every((i) => typeof i === "string")) {
|
|
671
|
-
rec.queue.push({
|
|
671
|
+
rec.queue.push({
|
|
672
|
+
kind: a.kind,
|
|
673
|
+
at: a.at,
|
|
674
|
+
...(typeof a.sessionId === "string" ? { sessionId: a.sessionId } : {}),
|
|
675
|
+
...(typeof a.reportId === "string" ? { reportId: a.reportId } : {}),
|
|
676
|
+
items: a.items,
|
|
677
|
+
});
|
|
672
678
|
}
|
|
673
679
|
}
|
|
674
680
|
}
|
|
675
681
|
return rec;
|
|
676
682
|
}
|
|
677
|
-
export function enqueueMemoryAnnouncement(controlDir, ann) {
|
|
678
|
-
|
|
683
|
+
export function enqueueMemoryAnnouncement(controlDir, ann, opts) {
|
|
684
|
+
const family = opts?.supersedesPrefix;
|
|
685
|
+
if (ann.items.length === 0 && family === undefined)
|
|
679
686
|
return;
|
|
680
687
|
lockedJournaledUpdate(controlDir, ANNOUNCEMENTS_FILE, (current) => {
|
|
681
688
|
const rec = coerceAnnouncements(current);
|
|
689
|
+
if (family !== undefined) {
|
|
690
|
+
const queued = rec.queue.flatMap((a) => a.items.filter((i) => i.startsWith(family)));
|
|
691
|
+
if (queued.length === ann.items.length && ann.items.every((i) => queued.includes(i)))
|
|
692
|
+
return undefined;
|
|
693
|
+
for (const a of rec.queue)
|
|
694
|
+
a.items = a.items.filter((i) => !i.startsWith(family));
|
|
695
|
+
rec.queue = rec.queue.filter((a) => a.items.length > 0);
|
|
696
|
+
if (ann.items.length === 0)
|
|
697
|
+
return rec;
|
|
698
|
+
}
|
|
682
699
|
rec.queue.push(ann);
|
|
683
700
|
if (rec.queue.length > MEMORY_ANNOUNCEMENTS_MAX) {
|
|
684
701
|
rec.folded += rec.queue.length - MEMORY_ANNOUNCEMENTS_MAX;
|
|
@@ -831,6 +848,98 @@ export function importSessionPollution(controlDir, sessionId, record) {
|
|
|
831
848
|
const standing = readSessionPollution(controlDir, sessionId);
|
|
832
849
|
return standing !== undefined && standing.at === record.at && standing.reason === record.reason ? "already" : "divergent";
|
|
833
850
|
}
|
|
851
|
+
export const SESSION_CAPTURE_OPTOUT_DIR = "session-capture-optout";
|
|
852
|
+
function captureOptOutPath(controlDir, sessionId) {
|
|
853
|
+
return join(controlDir, SESSION_CAPTURE_OPTOUT_DIR, `${encodeURIComponent(sessionId)}.json`);
|
|
854
|
+
}
|
|
855
|
+
export function markSessionCaptureOptOut(controlDir, sessionId, reason, now) {
|
|
856
|
+
const path = captureOptOutPath(controlDir, sessionId);
|
|
857
|
+
try {
|
|
858
|
+
ensureDirExists(dirname(path));
|
|
859
|
+
const record = { at: now(), reason };
|
|
860
|
+
writeFileSync(path, `${JSON.stringify(record, null, 2)}\n`, { encoding: "utf8", flag: "wx" });
|
|
861
|
+
return "created";
|
|
862
|
+
}
|
|
863
|
+
catch (err) {
|
|
864
|
+
if (err instanceof Error && "code" in err && err.code === "EEXIST")
|
|
865
|
+
return "existed";
|
|
866
|
+
return "unpersisted";
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
export function readSessionCaptureOptOut(controlDir, sessionId) {
|
|
870
|
+
const path = captureOptOutPath(controlDir, sessionId);
|
|
871
|
+
let raw;
|
|
872
|
+
try {
|
|
873
|
+
raw = readFileSync(path, "utf8");
|
|
874
|
+
}
|
|
875
|
+
catch (err) {
|
|
876
|
+
if (err.code === "ENOENT") {
|
|
877
|
+
try {
|
|
878
|
+
lstatSync(path);
|
|
879
|
+
}
|
|
880
|
+
catch (lerr) {
|
|
881
|
+
if (lerr.code === "ENOENT")
|
|
882
|
+
return undefined;
|
|
883
|
+
throw new ControlPlaneCorruptError(`session capture opt-out record state is INDETERMINATE (${lerr.code ?? "io error"}) at ${path} — the store cannot establish whether a record exists; consumers must suppress on the fault axis (an outage is never reported as a user request)`, { cause: lerr });
|
|
884
|
+
}
|
|
885
|
+
return { at: 0, reason: "capture opt-out record present but unreadable (kept fail-closed)" };
|
|
886
|
+
}
|
|
887
|
+
try {
|
|
888
|
+
statSync(path);
|
|
889
|
+
}
|
|
890
|
+
catch {
|
|
891
|
+
throw new ControlPlaneCorruptError(`session capture opt-out record state is INDETERMINATE (${err.code ?? "io error"}) at ${path} — the store cannot establish whether a record exists; consumers must suppress on the fault axis (an outage is never reported as a user request)`, { cause: err });
|
|
892
|
+
}
|
|
893
|
+
return { at: 0, reason: "capture opt-out record present but unreadable (kept fail-closed)" };
|
|
894
|
+
}
|
|
895
|
+
try {
|
|
896
|
+
const parsed = JSON.parse(raw);
|
|
897
|
+
if (parsed !== null && typeof parsed === "object") {
|
|
898
|
+
const at = parsed.at;
|
|
899
|
+
const reason = parsed.reason;
|
|
900
|
+
if (typeof at === "number" && typeof reason === "string")
|
|
901
|
+
return { at, reason };
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
catch {
|
|
905
|
+
}
|
|
906
|
+
return { at: 0, reason: "capture opt-out record present but unreadable (kept fail-closed)" };
|
|
907
|
+
}
|
|
908
|
+
export function listSessionCaptureOptOut(controlDir) {
|
|
909
|
+
const dir = join(controlDir, SESSION_CAPTURE_OPTOUT_DIR);
|
|
910
|
+
let names;
|
|
911
|
+
try {
|
|
912
|
+
names = readdirSync(dir);
|
|
913
|
+
}
|
|
914
|
+
catch (err) {
|
|
915
|
+
if (err.code === "ENOENT")
|
|
916
|
+
return {};
|
|
917
|
+
throw new ControlPlaneCorruptError(`session capture opt-out records could not be enumerated (${err.code ?? "io error"}) at ${dir} — an enumeration failure is not an empty set (fail-closed)`, { cause: err });
|
|
918
|
+
}
|
|
919
|
+
const out = Object.create(null);
|
|
920
|
+
for (const name of names.sort()) {
|
|
921
|
+
if (!name.endsWith(".json"))
|
|
922
|
+
continue;
|
|
923
|
+
let sessionId;
|
|
924
|
+
try {
|
|
925
|
+
sessionId = decodeURIComponent(name.slice(0, -".json".length));
|
|
926
|
+
}
|
|
927
|
+
catch {
|
|
928
|
+
continue;
|
|
929
|
+
}
|
|
930
|
+
const rec = readSessionCaptureOptOut(controlDir, sessionId);
|
|
931
|
+
if (rec !== undefined)
|
|
932
|
+
out[sessionId] = rec;
|
|
933
|
+
}
|
|
934
|
+
return out;
|
|
935
|
+
}
|
|
936
|
+
export function fileSessionCaptureRecordStore(controlDir) {
|
|
937
|
+
return {
|
|
938
|
+
mark: (sessionId, record) => markSessionCaptureOptOut(controlDir, sessionId, record.reason, () => record.at),
|
|
939
|
+
read: (sessionId) => readSessionCaptureOptOut(controlDir, sessionId),
|
|
940
|
+
list: () => listSessionCaptureOptOut(controlDir),
|
|
941
|
+
};
|
|
942
|
+
}
|
|
834
943
|
export const USAGE_RETRIEVED_FILE = "usage-retrieved.json";
|
|
835
944
|
export const USAGE_RETRIEVED_MAX_IDS = 4096;
|
|
836
945
|
function coerceRetrievedAccount(raw) {
|
|
@@ -62,3 +62,10 @@ export declare const MEMORY_SEARCH_BAND_ORDER_HEADER = "entries without the [ext
|
|
|
62
62
|
* memory_get instead of treating an id-only line as an empty result.
|
|
63
63
|
*/
|
|
64
64
|
export declare const MEMORY_PROVENANCE_SEARCH_SENTENCE: string;
|
|
65
|
+
/**
|
|
66
|
+
* #493 件① — the memory_index counterpart of {@link MEMORY_PROVENANCE_SEARCH_SENTENCE} (appended to
|
|
67
|
+
* the listing tool's description under "carry" only): same teaching, "rows" instead of "hits" —
|
|
68
|
+
* the enumeration face renders a marked entry as the same opaque id-only handle the search face
|
|
69
|
+
* does (§5.2's passive-face law: a marked entry's model-authored strings never ride untaxed).
|
|
70
|
+
*/
|
|
71
|
+
export declare const MEMORY_PROVENANCE_INDEX_SENTENCE: string;
|
|
@@ -14,3 +14,6 @@ export const MEMORY_SEARCH_BAND_ORDER_HEADER = `entries without the ${MEMORY_EXP
|
|
|
14
14
|
export const MEMORY_PROVENANCE_SEARCH_SENTENCE = "Hits tagged [external-origin] list only the entry id (their content came from a session that was exposed to " +
|
|
15
15
|
"external content): read them with memory_get by id as usual, then verify what they say against current sources " +
|
|
16
16
|
"before acting on it.";
|
|
17
|
+
export const MEMORY_PROVENANCE_INDEX_SENTENCE = "Rows tagged [external-origin] list only the entry id (their content came from a session that was exposed to " +
|
|
18
|
+
"external content): read them with memory_get by id as usual, then verify what they say against current sources " +
|
|
19
|
+
"before acting on it.";
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* design/178 v1 — the
|
|
2
|
+
* design/178 v1 — the engine-memory retrieval tools (`memory_search` / `memory_get`, and since
|
|
3
|
+
* #493 the `memory_index` enumeration face).
|
|
3
4
|
*
|
|
4
5
|
* These are the first runner-wired consumers of the `MemoryBackend.search()`/`getByIds()` contract:
|
|
5
|
-
* a deterministic keyword lookup over the session's mounted scopes plus a paged full-content read
|
|
6
|
-
*
|
|
6
|
+
* a deterministic keyword lookup over the session's mounted scopes plus a paged full-content read,
|
|
7
|
+
* plus (#493) a paged enumeration of EVERY mounted entry — the completeness floor under both: any
|
|
8
|
+
* committed entry is reachable through `memory_index` regardless of the injected index's truncation
|
|
9
|
+
* window and of whether its words match the question (chaos live S2-B: out-of-window ∧ lexically
|
|
10
|
+
* disjoint was structurally unreachable). Zero contract changes — the tools sit entirely ON TOP of
|
|
11
|
+
* the backend seam.
|
|
7
12
|
*
|
|
8
|
-
* READ-ONLY BY STRUCTURE.
|
|
13
|
+
* READ-ONLY BY STRUCTURE. No tool here can write; the write path stays the file channel + harvest
|
|
9
14
|
* gate. Entry content returned to the model is DATA, not instructions: every body fragment rides an
|
|
10
15
|
* untrusted fence (`delimitUntrusted`) and every header field a model could have authored
|
|
11
16
|
* (name/description/slug/scope) is neutralized inline. Results are byte-bounded.
|
|
12
17
|
*
|
|
13
|
-
* THE
|
|
14
|
-
* tool that is not there — the mount site (runner/prepare-task.ts) mounts
|
|
18
|
+
* THE TRIO IS ATOMIC. Each tool names the others in its description, so a partial mount would teach
|
|
19
|
+
* a tool that is not there — the mount site (runner/prepare-task.ts) mounts all or none.
|
|
15
20
|
*
|
|
16
21
|
* RESULT ORDER IS THE BACKEND CONTRACT ORDER: ascending cosine-distance score with the
|
|
17
22
|
* deterministic id tie-break, exactly what `MemoryBackend.search()` promises. Multi-plane sessions
|
|
@@ -30,11 +35,21 @@ import type { ToolSpec } from "../types.js";
|
|
|
30
35
|
import type { MemoryBackend } from "./types.js";
|
|
31
36
|
export declare const MEMORY_SEARCH_TOOL_NAME = "memory_search";
|
|
32
37
|
export declare const MEMORY_GET_TOOL_NAME = "memory_get";
|
|
33
|
-
/**
|
|
34
|
-
|
|
38
|
+
/** #493 件① — the enumeration face. NOT `memory_list`: that wire name (and the `core.memory_list@1`
|
|
39
|
+
* contract id) belongs to the design/177 shared-memory store pair, and both families can mount in
|
|
40
|
+
* one session. */
|
|
41
|
+
export declare const MEMORY_INDEX_TOOL_NAME = "memory_index";
|
|
42
|
+
/** The atomic trio, in mount order (same shape as SHARED_MEMORY_TOOL_NAMES). */
|
|
43
|
+
export declare const MEMORY_ENGINE_TOOL_NAMES: readonly ["memory_search", "memory_get", "memory_index"];
|
|
35
44
|
/** Default / maximum hit counts for one search call. */
|
|
36
45
|
export declare const MEMORY_SEARCH_DEFAULT_LIMIT = 8;
|
|
37
46
|
export declare const MEMORY_SEARCH_MAX_LIMIT = 20;
|
|
47
|
+
/** Default / maximum rows of one memory_index page (a row is ≲600 bytes by the inline caps, so the
|
|
48
|
+
* extremes stay well under one tool-result's budget; the per-page byte bound below is the backstop). */
|
|
49
|
+
export declare const MEMORY_INDEX_PAGE_ROWS = 100;
|
|
50
|
+
export declare const MEMORY_INDEX_MAX_PAGE_ROWS = 500;
|
|
51
|
+
/** Byte bound of one memory_index page (rows past it defer to the next page, disclosed). */
|
|
52
|
+
export declare const MEMORY_INDEX_PAGE_CAP_BYTES: number;
|
|
38
53
|
/** Per-hit body-fragment bound (code points, enforced by the fence itself). */
|
|
39
54
|
export declare const MEMORY_SEARCH_SNIPPET_CAP = 600;
|
|
40
55
|
/** Default / maximum lines of one memory_get page. */
|
|
@@ -78,6 +93,21 @@ export interface MemoryEnginePlane {
|
|
|
78
93
|
* settlement account's record-failure arm.
|
|
79
94
|
*/
|
|
80
95
|
onTaintedDelivery?: (ids: readonly string[]) => void;
|
|
96
|
+
/**
|
|
97
|
+
* design/383 §1.7 — the provenance mode of the WRITE-SIDE engine that owns this plane, read off
|
|
98
|
+
* the engine itself (`MemoryEngine.provenanceMode`), never re-declared by hand. Present ⇒ the
|
|
99
|
+
* factory ASSERTS it against its own {@link MemoryEngineToolsOptions.provenance}: a wiring that
|
|
100
|
+
* writes under `"carry"` while reading under `"off"` mints origin markers no read face will ever
|
|
101
|
+
* honour (marked entries served through the clean shape, no banner, no recall-taint propagation)
|
|
102
|
+
* — the two halves are one deployment posture and a split between them is a configuration fault,
|
|
103
|
+
* refused at construction (`config.memory_provenance`) rather than discovered as a quiet leak.
|
|
104
|
+
*
|
|
105
|
+
* Scope, stated honestly: this kills CONFIGURATION divergence only. It proves nothing about
|
|
106
|
+
* whether any individual entry is classified correctly — that is the 178 fail-closed default's
|
|
107
|
+
* job, not this assertion's. Absent ⇒ no engine mode is declared for this plane (engine-direct
|
|
108
|
+
* hosts and tests) and nothing is asserted: the factory's behaviour is byte-identical to before.
|
|
109
|
+
*/
|
|
110
|
+
enginePlaneProvenance?: "off" | "carry";
|
|
81
111
|
}
|
|
82
112
|
export interface MemoryEngineToolsOptions {
|
|
83
113
|
planes: ReadonlyArray<MemoryEnginePlane>;
|
|
@@ -191,6 +221,57 @@ export interface MemoryGetDetails {
|
|
|
191
221
|
* supersession is disclosure/ordering, never withholding. */
|
|
192
222
|
supersededBy?: string;
|
|
193
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* #493 件① — one row of the memory_index enumeration. The same discriminated shape law as the
|
|
226
|
+
* search hits (design/336 B5): a clean row carries the text seats, a marked row (carry mode) is an
|
|
227
|
+
* opaque id-only handle — a consumer must branch on `exposure` to touch the text seats. No score
|
|
228
|
+
* seat: the enumeration is structural, not ranked.
|
|
229
|
+
*/
|
|
230
|
+
export interface CleanMemoryIndexRow {
|
|
231
|
+
id: string;
|
|
232
|
+
scope: string;
|
|
233
|
+
slug: string;
|
|
234
|
+
name?: string;
|
|
235
|
+
description?: string;
|
|
236
|
+
mtimeMs: number;
|
|
237
|
+
sizeBytes: number;
|
|
238
|
+
exposure?: never;
|
|
239
|
+
/** Present ⇔ this row is SUPERSEDED (listed via `includeSuperseded`; the default face filters
|
|
240
|
+
* such rows out) — the value is the standing carrier entry's id. */
|
|
241
|
+
supersededBy?: string;
|
|
242
|
+
}
|
|
243
|
+
/** The opaque marked-row handle (carry mode) — same posture as {@link ExposedMemorySearchHit}. */
|
|
244
|
+
export interface ExposedMemoryIndexRow {
|
|
245
|
+
exposure: "external";
|
|
246
|
+
id: string;
|
|
247
|
+
scope: string;
|
|
248
|
+
mtimeMs: number;
|
|
249
|
+
sizeBytes: number;
|
|
250
|
+
slug?: never;
|
|
251
|
+
name?: never;
|
|
252
|
+
description?: never;
|
|
253
|
+
supersededBy?: string;
|
|
254
|
+
}
|
|
255
|
+
export type MemoryIndexRow = CleanMemoryIndexRow | ExposedMemoryIndexRow;
|
|
256
|
+
export interface MemoryIndexDetails {
|
|
257
|
+
outcome: "ok" | "refused" | "failed";
|
|
258
|
+
reason?: string;
|
|
259
|
+
entries?: MemoryIndexRow[];
|
|
260
|
+
/** Zero-based row offset this page started at (the enumeration order is deterministic). */
|
|
261
|
+
offset?: number;
|
|
262
|
+
/** Rows on THIS page. */
|
|
263
|
+
shown?: number;
|
|
264
|
+
/** Total rows the enumeration serves (after the exclusion/superseded filters). */
|
|
265
|
+
total?: number;
|
|
266
|
+
/** Superseded rows the default face hid (absent when zero or when `includeSuperseded` was passed). */
|
|
267
|
+
supersededHidden?: number;
|
|
268
|
+
/** Present ⇔ more rows follow — pass it as the next call's `offset`. */
|
|
269
|
+
nextOffset?: number;
|
|
270
|
+
/** The listing revision this page was served against (a stateless digest of the ordered id
|
|
271
|
+
* sequence the offsets address). Pass it back on continuation pages of a complete pass; a
|
|
272
|
+
* mismatch refuses with reason `listing_changed` instead of silently skipping shifted rows. */
|
|
273
|
+
listingRev?: string;
|
|
274
|
+
}
|
|
194
275
|
/** Cut `text` to at most `maxBytes` UTF-8 bytes on a CODE POINT boundary (a byte-wise slice would
|
|
195
276
|
* strand half a character), reporting how many bytes were dropped. Unchanged text reports 0.
|
|
196
277
|
* Exported for the truncation-invariant registry — a bound-taking function has to be provable. */
|