@sema-agent/core 5.46.0 → 5.47.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 +41 -0
- package/dist/agents/subagent.js +129 -2
- package/dist/core/governance-codes.d.ts +13 -0
- package/dist/core/governance-codes.js +33 -0
- package/dist/core/memory-engine/delegation-settlement.d.ts +318 -0
- package/dist/core/memory-engine/delegation-settlement.js +661 -0
- package/dist/core/memory-engine/engine.d.ts +159 -1
- package/dist/core/memory-engine/engine.js +699 -15
- package/dist/core/memory-engine/file-backend.d.ts +1 -0
- package/dist/core/memory-engine/file-backend.js +3 -1
- package/dist/core/memory-engine/frontmatter.d.ts +46 -19
- package/dist/core/memory-engine/frontmatter.js +91 -77
- package/dist/core/memory-engine/index.d.ts +4 -3
- package/dist/core/memory-engine/index.js +3 -2
- package/dist/core/memory-engine/layout.d.ts +14 -0
- package/dist/core/memory-engine/layout.js +2 -2
- package/dist/core/memory-engine/memory-backend-contract.js +43 -0
- package/dist/core/memory-engine/origin-clearance.d.ts +66 -0
- package/dist/core/memory-engine/origin-clearance.js +84 -0
- package/dist/core/memory-engine/provenance-wording.d.ts +50 -0
- package/dist/core/memory-engine/provenance-wording.js +15 -0
- package/dist/core/memory-engine/tools.d.ts +61 -7
- package/dist/core/memory-engine/tools.js +34 -9
- package/dist/core/memory-engine/types.d.ts +70 -2
- package/dist/core/runner/prepare-memory.js +50 -15
- package/dist/core/runner/prepare-task.d.ts +24 -0
- package/dist/core/runner/prepare-task.js +80 -10
- package/dist/core/session-reconcile.js +3 -2
- package/dist/core/types.d.ts +38 -3
- package/dist/core/types.js +3 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/tools/task-list.d.ts +5 -1
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +10 -2
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { EngineNotice } from "../types.js";
|
|
2
|
+
import { foreignDanglingSessionAccounts, type EffectiveSettlement, type HoldRow } from "./delegation-settlement.js";
|
|
3
|
+
import { type OriginClearanceRow } from "./origin-clearance.js";
|
|
2
4
|
import { type CommittedBinding, type EraseMemoryEntriesInput, type MemoryErasureAttestation, type TransferEvidence } from "./file-backend.js";
|
|
3
5
|
import { type MemoryExportBundle, type MemoryImportReport } from "./export-bundle.js";
|
|
4
6
|
import { type ChallengeAssignment, type ChallengeEvent, type ControlPlaneRebuildReceipt, type StrictControlPlaneLedger, type ChallengedHistoryRow, type LineagePendingTxn, type LineagePromotion, type MemoryPartitionIncidentSink, type RetrievedAccountRow, type SessionPollutionMarkOutcome, type SessionPollutionRecord } from "./layout.js";
|
|
5
|
-
import type { HarvestReport, MemoryAnnouncement, MemoryBackend, MemorySessionHandle, ScanFinding } from "./types.js";
|
|
7
|
+
import type { HarvestReport, MemoryAnnouncement, MemoryBackend, MemoryEntryOrigin, MemorySessionHandle, ScanFinding } from "./types.js";
|
|
6
8
|
/**
|
|
7
9
|
* The CC `# Memory` instruction section — VERBATIM from the live capture
|
|
8
10
|
* (bench/cc-parity-toolsuite/reminders/live-capture-main-session-2026-07-08.md §12), with the
|
|
@@ -34,6 +36,34 @@ export declare function buildMemoryInstruction(memoryDir: string, instructionFil
|
|
|
34
36
|
* dual-root instruction merge ("the write plane's instruction wins") never sees a second candidate.
|
|
35
37
|
*/
|
|
36
38
|
export declare const MEMORY_RECALL_DISCIPLINE = "Before answering questions about earlier work, decisions, dates, people, or the user's preferences, look them up: `memory_search` finds entries by keyword and `memory_get` reads a full entry \u2014 the injected memory index only lists what exists. When a lookup comes up empty, say that you checked memory and found nothing instead of guessing.";
|
|
39
|
+
/**
|
|
40
|
+
* design/336 §5.4 — the recall-discipline SEGMENT as the runner composes (and, on a retracted tool
|
|
41
|
+
* pair, strips) it: the base paragraph, plus — under `provenance: "carry"` only — the
|
|
42
|
+
* label-semantics sentence ({@link MEMORY_PROVENANCE_RECALL_SENTENCE}: what a `⚠ext` handle row /
|
|
43
|
+
* external-origin note means, "stays usable, verify before acting"). ONE function on purpose:
|
|
44
|
+
* prepare-memory appends this exact string and prepare-task's pair-retraction removes this exact
|
|
45
|
+
* string — two compositions would drift the moment either mode's wording moved. Under "off" this
|
|
46
|
+
* is byte-identical to {@link MEMORY_RECALL_DISCIPLINE} (the pre-336 segment).
|
|
47
|
+
*/
|
|
48
|
+
export declare function memoryRecallDisciplineSegment(provenance: "off" | "carry"): string;
|
|
49
|
+
/**
|
|
50
|
+
* design/336 §5.5 (file-face half) — does the entry file at `absPath` carry a committed
|
|
51
|
+
* external-origin marker? A BOUNDED head read (default 64 KiB — an engine-projected frontmatter
|
|
52
|
+
* block sits at the head and is orders of magnitude smaller; the per-file store cap is 100 KB) +
|
|
53
|
+
* the one marker normalization ({@link committedOriginOf}: typed field or extra-form carrier).
|
|
54
|
+
* Consumed by the runner's Read-tool recall-taint judgment: a model that bypasses `memory_get` and
|
|
55
|
+
* Reads a marked entry file straight off a zero-copy plane takes up the same content, so the same
|
|
56
|
+
* derived mark must follow the delivery.
|
|
57
|
+
*
|
|
58
|
+
* FAIL-OPEN by design (`false` on any read/parse failure): this is a taint-propagation widening
|
|
59
|
+
* over a disclosure the file bytes already make themselves (the origin block is IN the file the
|
|
60
|
+
* model just read), not a gate — a refusal here would break ordinary reads on I/O hiccups. Named
|
|
61
|
+
* residuals (§5.5's standing bypass-channel class, disclosed): a frontmatter block larger than the
|
|
62
|
+
* bound reads as unmarked, and a file swapped between the tool's read and this one is judged on
|
|
63
|
+
* the swapped bytes (either direction; a spurious derived mark is the safe side — marks are
|
|
64
|
+
* over-approximations by law, and a missed one is exactly the residual Bash reads already carry).
|
|
65
|
+
*/
|
|
66
|
+
export declare function entryFileHeadCarriesOrigin(absPath: string, maxBytes?: number): boolean;
|
|
37
67
|
/**
|
|
38
68
|
* design/180 B-3 — the preference-header discipline paragraph. Same carriage as
|
|
39
69
|
* {@link MEMORY_RECALL_DISCIPLINE}: a runner-appended segment OUTSIDE `inject()`, so the
|
|
@@ -89,6 +119,12 @@ export declare const DEFAULT_HARVEST_DEADLINE_MS = 5000;
|
|
|
89
119
|
/** M7 — default per-harvest processed-file budget (deliberately above the file-count cap, so it is
|
|
90
120
|
* inert unless configured tighter). */
|
|
91
121
|
export declare const DEFAULT_HARVEST_FILE_BUDGET = 2000;
|
|
122
|
+
/** design/336 §4.2 — the default settlement window: how long a delegation may stay `pending`
|
|
123
|
+
* before reconciliation judges it `expired` (holds disposed as unproven — LOUDLY, never silently
|
|
124
|
+
* dropped — and the session's unprovable window closes exposed). 72h = a comfortable upper bound
|
|
125
|
+
* on background-child lifetimes; the cost of the window is that a held instruction entry is
|
|
126
|
+
* delayed at most this long, never lost. */
|
|
127
|
+
export declare const DEFAULT_HOLD_SETTLE_TIMEOUT_MS: number;
|
|
92
128
|
/** design/138 §2.4 删除防线 — the mass-deletion fuse threshold (fraction of materialized writable
|
|
93
129
|
* entries missing at harvest above which the whole harvest is judged an incident and refused). The
|
|
94
130
|
* fuse guards the BACKEND from having a wipe written back; renames (same id re-appearing elsewhere)
|
|
@@ -137,6 +173,16 @@ export interface MemoryEngineOptions {
|
|
|
137
173
|
* spellings, never truthiness).
|
|
138
174
|
*/
|
|
139
175
|
provenance?: "off" | "carry";
|
|
176
|
+
/**
|
|
177
|
+
* design/336 §4.2 — the delegation settlement window in ms (default
|
|
178
|
+
* {@link DEFAULT_HOLD_SETTLE_TIMEOUT_MS} = 72h): a `pending` settlement row older than this is
|
|
179
|
+
* judged `expired` at the next harvest reconciliation — the session's unprovable window closes
|
|
180
|
+
* exposed, and its instruction holds dispose (announced explicitly as a TIMEOUT, never a
|
|
181
|
+
* conviction; the `resolveHold` valve can still release them with a `"static"`-cause marker).
|
|
182
|
+
* A bad value (non-finite, zero, negative, non-number) refuses loudly at construction
|
|
183
|
+
* (`config.memory_hold_timeout`, #123 — never folded to the default).
|
|
184
|
+
*/
|
|
185
|
+
holdSettleTimeoutMs?: number;
|
|
140
186
|
/** M7 — harvest deadline in ms (default {@link DEFAULT_HARVEST_DEADLINE_MS}); over-deadline files
|
|
141
187
|
* are deferred to the next harvest (report.degraded), never dropped. */
|
|
142
188
|
harvestDeadlineMs?: number;
|
|
@@ -370,7 +416,16 @@ export declare function memoryHarvestQuarantinedNotice(input: {
|
|
|
370
416
|
reason?: string;
|
|
371
417
|
sessionId?: string;
|
|
372
418
|
provenance?: "off" | "carry";
|
|
419
|
+
indexRolledBack?: boolean;
|
|
373
420
|
}): EngineNotice;
|
|
421
|
+
/**
|
|
422
|
+
* design/336 §6.3 — the hold family's operator notices, derived from ONE harvest report's
|
|
423
|
+
* structured containment signal (`report.containment`), the same runner-minted posture as
|
|
424
|
+
* `memory.session_polluted`. Factual wording only (§13-2 model-psyche guardrail: no threat
|
|
425
|
+
* vocabulary — a hold is a sequencing fact, not an accusation); paths are model-controlled
|
|
426
|
+
* identifiers, neutralized and length-capped before they ride the message or the detail.
|
|
427
|
+
*/
|
|
428
|
+
export declare function memoryHoldNotices(report: HarvestReport, sessionId?: string): EngineNotice[];
|
|
374
429
|
export declare class MemoryEngine {
|
|
375
430
|
private readonly backend;
|
|
376
431
|
private readonly memoryDir;
|
|
@@ -382,6 +437,8 @@ export declare class MemoryEngine {
|
|
|
382
437
|
private readonly maxDepth;
|
|
383
438
|
private readonly harvestDeadlineMs;
|
|
384
439
|
private readonly harvestFileBudget;
|
|
440
|
+
/** {@link MemoryEngineOptions.holdSettleTimeoutMs} (screened at construction, #123). */
|
|
441
|
+
private readonly holdSettleTimeoutMs;
|
|
385
442
|
/** {@link MemoryEngineOptions.provenance} — the design/336 master switch (screened at construction). */
|
|
386
443
|
private readonly provenance;
|
|
387
444
|
/** {@link MemoryEngineOptions.onIncident} — the advisory disclosure seat (partition + announce codes). */
|
|
@@ -400,6 +457,10 @@ export declare class MemoryEngine {
|
|
|
400
457
|
* failure produces no second-order disclosure — the alternative (announcing the announce failure)
|
|
401
458
|
* would recurse through the very lane that just failed.
|
|
402
459
|
*/
|
|
460
|
+
/** design/336 §3.6 (slice 2) — the session-account incident channel (`memory.session_account_failed`):
|
|
461
|
+
* a degraded residue classification is DISCLOSED, never quiet (the behavioral fail-closed half —
|
|
462
|
+
* harvest refusing on `handle.sessionAccountFailed` — is enforced at the write boundary). */
|
|
463
|
+
private discloseSessionAccountIncident;
|
|
403
464
|
private discloseAnnounceFailure;
|
|
404
465
|
/**
|
|
405
466
|
* Record retrieval hits (entries a memory tool actually RETURNED to the model) into this engine's
|
|
@@ -616,6 +677,7 @@ export declare class MemoryEngine {
|
|
|
616
677
|
private settlePromotions;
|
|
617
678
|
materialize(scopes: readonly string[], writeScope: string | null, opts?: {
|
|
618
679
|
adoptionRestricted?: boolean;
|
|
680
|
+
sessionId?: string;
|
|
619
681
|
}): Promise<MemorySessionHandle>;
|
|
620
682
|
inject(handle: MemorySessionHandle, opts?: {
|
|
621
683
|
writeToolMounted?: boolean;
|
|
@@ -658,6 +720,102 @@ export declare class MemoryEngine {
|
|
|
658
720
|
};
|
|
659
721
|
}): Promise<HarvestReport>;
|
|
660
722
|
private harvestCore;
|
|
723
|
+
/**
|
|
724
|
+
* Settle every DUE hold at harvest opening (the reconciliation leg): a hold whose session's
|
|
725
|
+
* account is all-clean releases (the captured bytes re-walk the FULL gate set — content scan,
|
|
726
|
+
* size cap, origin strip — and commit under the ORIGINAL session's lineage: the true writer is
|
|
727
|
+
* who the retroaction machinery must find); a dirty/unprovable account disposes to quarantine
|
|
728
|
+
* (host-auditable, LOUD — a timeout is announced as a timeout, never as a conviction); the host
|
|
729
|
+
* valve's standing verdicts execute here. A hold whose settlements are still pending stays held.
|
|
730
|
+
* Throws only on a corrupt hold/settlement ledger — the caller's fail-closed reconciliation arm
|
|
731
|
+
* refuses the harvest (integrity unknown must not read as "no holds").
|
|
732
|
+
*/
|
|
733
|
+
private settleDueHolds;
|
|
734
|
+
/**
|
|
735
|
+
* The release leg: re-walk the captured bytes through the FULL gate set and commit them under
|
|
736
|
+
* the ORIGINAL writer session's lineage. Returns the released relPath, or undefined when the
|
|
737
|
+
* hold did not release (disposed on a gate refusal / CAS conflict / lost capture, or kept held
|
|
738
|
+
* on a transient backend refusal — retried next harvest, never silently dropped).
|
|
739
|
+
*/
|
|
740
|
+
private releaseHold;
|
|
741
|
+
/** §3.3 — the settlement valve: an audited host ruling over one delegation's outcome. `"clean"`
|
|
742
|
+
* releases the post-expiry gates (effective only — the history bit never flips, and a LATER
|
|
743
|
+
* observed `external` overrides the ruling); `"external"` convicts. Advisory trust plane. */
|
|
744
|
+
resolveSettlement(settleId: string, to: "clean" | "external", requestId: string): void;
|
|
745
|
+
/** §4.2③ — the hold valve: `"release"` commits the held entry at the next harvest WITH a
|
|
746
|
+
* `"static"`-cause marker (a valve release is not a cleanliness proof); `"discard"` disposes it
|
|
747
|
+
* to quarantine. Audited (requestId required). */
|
|
748
|
+
resolveHold(holdId: string, action: "release" | "discard", requestId: string): void;
|
|
749
|
+
/** §3.6 — the session-account valve: close a dangling foreign row WITHOUT adjudication (the
|
|
750
|
+
* residue arm keeps firing until the next full-domain harvest closes normally — a valve close
|
|
751
|
+
* must not launder the window it covers). Audited (requestId required). */
|
|
752
|
+
resolveSessionAccount(sessionId: string, requestId: string): void;
|
|
753
|
+
/** The engine's control-plane directory (the sidecar home: pollution markers, lineage/challenge
|
|
754
|
+
* ledgers, and the design/336 settlement/hold/session accounts). Exposed so a host (and the
|
|
755
|
+
* runner's settlement handle) can address the SAME plane the engine writes — a second derivation
|
|
756
|
+
* would be a drift seam. */
|
|
757
|
+
get controlPlaneDir(): string;
|
|
758
|
+
/** Read face: every delegation settlement row with its folded effective status (host audit). */
|
|
759
|
+
readDelegationSettlements(): EffectiveSettlement[];
|
|
760
|
+
/** Read face: every instruction-hold row (host audit; custody bytes are addressable through
|
|
761
|
+
* `captureName`/`disposition.quarantineName` under the control plane). */
|
|
762
|
+
readInstructionHolds(): HoldRow[];
|
|
763
|
+
/** Read face: the dangling foreign session-account rows a given session would classify residue
|
|
764
|
+
* against (host audit for the §3.6 valve). */
|
|
765
|
+
readDanglingSessionAccounts(selfSessionId: string): ReturnType<typeof foreignDanglingSessionAccounts>;
|
|
766
|
+
/** The committed, side-effect-free audit read: the adoption-restricted committed view when the
|
|
767
|
+
* backend offers one (zero-copy File — ledger+shadow, no disk adoption), else the non-adopting
|
|
768
|
+
* retrieval view (copy-out File), else the backend itself (Pg/TiDB shapes — naturally committed
|
|
769
|
+
* and side-effect-free per the getByIds contract clause). */
|
|
770
|
+
private committedAuditFace;
|
|
771
|
+
private static originClearRefusal;
|
|
772
|
+
/**
|
|
773
|
+
* §13-4① — the VIEW face: every marked entry in the given scopes, each with its marker (what /
|
|
774
|
+
* cause / when) and its assembled provenance account (来源委派: the lineage contributors joined
|
|
775
|
+
* with their sessions' pollution records — `provenanceOf`'s answer, one authority, never a
|
|
776
|
+
* second store). Committed state only; a marked entry that is also challenged still lists here
|
|
777
|
+
* (the exclusion rides inside the provenance account) — the host must SEE it to adjudicate it.
|
|
778
|
+
*
|
|
779
|
+
* Enumeration trusts the backend's `MemoryEntryHeader.exposure` clause (§6.2): a third-party
|
|
780
|
+
* backend that violates it UNDER-REPORTS here — the conformance suite is the acceptance
|
|
781
|
+
* contract (its exposure-carriage case reds on exactly that backend), and the B3 upgrade-order
|
|
782
|
+
* duty covers mixed fleets; the engine deliberately does not re-fetch whole scopes to
|
|
783
|
+
* second-guess a header face it published a contract for.
|
|
784
|
+
*/
|
|
785
|
+
listExternalOriginEntries(scopes: readonly string[]): Promise<Array<{
|
|
786
|
+
id: string;
|
|
787
|
+
slug: string;
|
|
788
|
+
scope: string;
|
|
789
|
+
origin: MemoryEntryOrigin;
|
|
790
|
+
provenance: EntryProvenanceAccount;
|
|
791
|
+
}>>;
|
|
792
|
+
/** §13-4② read half — the clearance audit trail (pending rows are crash-recovery seats: their
|
|
793
|
+
* custody carries the cleared bytes; a later {@link clearEntryOrigin} call resumes them). */
|
|
794
|
+
listOriginClearances(): OriginClearanceRow[];
|
|
795
|
+
/**
|
|
796
|
+
* §13-4② — the audited UN-MARK valve. There is deliberately NO in-place strip spelling anywhere
|
|
797
|
+
* (the backend immutability law stands untouched); the clear rides the law's own single legal
|
|
798
|
+
* exit (§2.3-2): write-ahead clearance row (custody = the full cleared-entry text) → COMMITTED
|
|
799
|
+
* tombstone (CAS on the judged rev) → later-batch re-record of the SAME id with the marker
|
|
800
|
+
* stripped (the host's explicit vouching starts the entry's unmarked life; same id on purpose —
|
|
801
|
+
* links, usage accounts and the clearance join keep their key). Terminals are appended events
|
|
802
|
+
* (who/when/why stay queryable beside the entry); every failure leaves the custody row standing
|
|
803
|
+
* and a re-call RESUMES it idempotently. Refusals (#123 coded, caller-shape):
|
|
804
|
+
* unattributed/invalid input, unknown/unmarked entry, and a CHALLENGED entry — the clear valve
|
|
805
|
+
* is not a challenge exit (adjudicate the challenge first; clearing a challenged entry would
|
|
806
|
+
* launder the exclusion through the weaker credential).
|
|
807
|
+
*/
|
|
808
|
+
clearEntryOrigin(entryId: string, input: {
|
|
809
|
+
requestId: string;
|
|
810
|
+
reason: string;
|
|
811
|
+
}): Promise<{
|
|
812
|
+
entryId: string;
|
|
813
|
+
clearanceId: string;
|
|
814
|
+
origin: MemoryEntryOrigin;
|
|
815
|
+
landedSlug: string;
|
|
816
|
+
}>;
|
|
817
|
+
/** The clear's effect half — replayable from the row alone (the resume arm re-enters here). */
|
|
818
|
+
private completeOriginClearance;
|
|
661
819
|
/**
|
|
662
820
|
* @param keepBaseline RB-440 (2026-07-31, hardening probe P3) — relative paths whose baseline must NOT
|
|
663
821
|
* advance: the files a DEGRADED harvest deferred (`report.degraded.pending`).
|