@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
|
@@ -4,10 +4,13 @@ import { admitMemoryScopes } from "../memory-admission.js";
|
|
|
4
4
|
import { adoptLegacyRepoDirs, canonicalize, deriveRepoControlPlaneDir, deriveProjectControlDir, deriveProjectMemoryDir, deriveRepoMemoryDir, drainMemoryAnnouncements, enqueueMemoryAnnouncement, isContainedIn, lookupProjectIdHint, recordProjectIdHint, resolveMemoryEngineRoot } from "../memory-engine/layout.js";
|
|
5
5
|
import { classifyScopePlanes, derivePersonalControlDir, derivePersonalMemoryDir, mergeHarvestReports, mergeInjections, needsDualRoots, parsedProjectPlane } from "../memory-engine/dual-root.js";
|
|
6
6
|
import { normalizeMemorySpec } from "../memory.js";
|
|
7
|
-
import { MEMORY_ANNOUNCEMENT_READONLY_CODA, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MemoryEngine, entryFileHeadCarriesOrigin, memoryConsolidationRecommendedNotice, memoryHarvestQuarantinedNotice, memoryHoldNotices, memoryRecallDisciplineSegment, memorySessionPollutedNotice, pollutionContainmentCounts, } from "../memory-engine/engine.js";
|
|
7
|
+
import { MEMORY_ANNOUNCEMENT_CAPTURE_OPTOUT_CODA, MEMORY_ANNOUNCEMENT_READONLY_CODA, MEMORY_CAPTURE_INDETERMINATE_NOTICE, MEMORY_CAPTURE_OPTOUT_NOTICE, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MemoryEngine, entryFileHeadCarriesOrigin, memoryCaptureOptedOutNotice, memoryCaptureOptOutUnpersistedNotice, memoryConsolidationRecommendedNotice, memoryHarvestQuarantinedNotice, memoryHoldNotices, memoryRecallDisciplineSegment, memorySessionPollutedNotice, pollutionContainmentCounts, } from "../memory-engine/engine.js";
|
|
8
|
+
import { adjudicateCaptureOptOut, captureOptOutDeniedError, captureOptOutUnpersistedError } from "./memory-capture-optout.js";
|
|
9
|
+
import { readSessionCaptureOptOut } from "../memory-engine/layout.js";
|
|
8
10
|
import { createMemoryEngineTools } from "../memory-engine/tools.js";
|
|
9
11
|
import { assertScopeContractPlacement, parseScopeKey, resolveProjectId } from "../memory-engine/scope-contract.js";
|
|
10
12
|
import { FileMemoryEngineBackend } from "../memory-engine/file-backend.js";
|
|
13
|
+
let undeclaredCapturePostureAnnounced = false;
|
|
11
14
|
export async function prepareMemory(input) {
|
|
12
15
|
const { spec, deps, sessionId, taskRootPath, memoryWriteGateRef, admissionCtx } = input;
|
|
13
16
|
const memorySpec = normalizeMemorySpec(spec.memory);
|
|
@@ -41,8 +44,37 @@ export async function prepareMemory(input) {
|
|
|
41
44
|
memorySpec.writeScope = outcome.writeScope;
|
|
42
45
|
}
|
|
43
46
|
const useMemoryEngine = Boolean(memorySpec && memorySpec.enabled && deps.memoryBackend);
|
|
47
|
+
const capturePosture = input.memoryCapturePolicy ?? "open";
|
|
48
|
+
const captureEntitlement = input.captureEntitlement ?? { value: undefined, faulted: false };
|
|
49
|
+
const captureDeclaredRaw = memorySpec?.capture === "off";
|
|
50
|
+
if (captureDeclaredRaw && memorySpec !== undefined && !memorySpec.enabled) {
|
|
51
|
+
deps.onError?.(new Error(`memory.capture:"off" appears beside memory.enabled:false — not a contradiction (memory is off entirely, so nothing is captured either way); the opt-out declaration is covered by enabled:false this run.`), { phase: "config", sessionId });
|
|
52
|
+
}
|
|
53
|
+
const captureDeclared = captureDeclaredRaw && useMemoryEngine;
|
|
54
|
+
const captureFloored = input.captureFloor === true && useMemoryEngine;
|
|
55
|
+
if (captureDeclared && !captureFloored) {
|
|
56
|
+
const verdict = adjudicateCaptureOptOut({ posture: capturePosture, entitlement: captureEntitlement, subject: "declaration" });
|
|
57
|
+
if (!verdict.allowed)
|
|
58
|
+
throw captureOptOutDeniedError(verdict.detail);
|
|
59
|
+
if (verdict.faultDisclosure !== undefined) {
|
|
60
|
+
deps.onError?.(new Error(verdict.faultDisclosure), { phase: "config", sessionId });
|
|
61
|
+
}
|
|
62
|
+
if (input.captureCarrierUnsupported === true) {
|
|
63
|
+
const e = new Error(`memory.capture:"off" cannot be honored on this deployment shape: the execution environment is remote/per-run ` +
|
|
64
|
+
`and no RunnerDeps.memoryCaptureRecordStore is supplied, so core cannot know the control plane survives to a ` +
|
|
65
|
+
`resume replica — a privacy promise that silently expires at the first resume is refused rather than made. A ` +
|
|
66
|
+
`deployment whose control plane IS durable (a single persistent host using a remote sandbox) opts back in by ` +
|
|
67
|
+
`supplying the store explicitly — fileSessionCaptureRecordStore(controlDir) is that one-line declaration.`);
|
|
68
|
+
e.code = "config.memory_capture_unsupported";
|
|
69
|
+
throw e;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
let captureOptedOut = false;
|
|
73
|
+
let captureIndeterminate = false;
|
|
74
|
+
let captureLineageIndeterminate = false;
|
|
44
75
|
let memoryEngineSession;
|
|
45
76
|
let memoryTools;
|
|
77
|
+
let memoryMarkedEntriesServed = false;
|
|
46
78
|
let effectiveMemoryScopes;
|
|
47
79
|
const originOf = (scope) => scopeOriginsSnapshot !== undefined
|
|
48
80
|
? scopeOriginsSnapshot[scope] === "deployment"
|
|
@@ -132,15 +164,106 @@ export async function prepareMemory(input) {
|
|
|
132
164
|
const pinnedCtl = b.controlPlaneRoot;
|
|
133
165
|
return typeof pinnedCtl === "string" && pinnedCtl ? pinnedCtl : fallback;
|
|
134
166
|
};
|
|
167
|
+
const captureStoreOpt = (b, fallback) => deps.memoryCaptureRecordStore !== undefined ? { captureRecordStore: deps.memoryCaptureRecordStore({ controlDir: effectiveControlDir(b, fallback) }) } : {};
|
|
135
168
|
const choosePersonalBackend = () => typeof pinned === "string" && pinned ? new FileMemoryEngineBackend(personalMemoryDir, { controlDir: personalControlDir }) : backend;
|
|
136
169
|
const createPersonalEngine = (personalBackend) => {
|
|
137
170
|
return {
|
|
138
|
-
engine: new MemoryEngine({ backend: personalBackend, memoryDir: personalMemoryDir, controlDir: personalControlDir, onIncident: onEngineIncident, provenance: input.memoryProvenance, ...(input.deps.memoryConsolidation !== undefined ? { consolidation: input.deps.memoryConsolidation } : {}) }),
|
|
171
|
+
engine: new MemoryEngine({ backend: personalBackend, memoryDir: personalMemoryDir, controlDir: personalControlDir, onIncident: onEngineIncident, provenance: input.memoryProvenance, ...captureStoreOpt(personalBackend, personalControlDir), ...(input.deps.memoryConsolidation !== undefined ? { consolidation: input.deps.memoryConsolidation } : {}) }),
|
|
139
172
|
backend: personalBackend,
|
|
140
173
|
};
|
|
141
174
|
};
|
|
142
175
|
const onEngineIncident = (err) => deps.onError?.(err, { phase: "memory", sessionId });
|
|
143
176
|
const adoptionRestricted = input.memoryPersistenceDeclared === false;
|
|
177
|
+
const armCaptureOptOut = (eng) => {
|
|
178
|
+
const standingRead = eng.sessionCaptureOptOutOrFault(sessionId);
|
|
179
|
+
if (standingRead.fault) {
|
|
180
|
+
captureIndeterminate = true;
|
|
181
|
+
deps.onError?.(new Error(`the capture opt-out record store is unreadable at prepare — this session's capture state is indeterminate, and every memory commit boundary (read-side adoption included) suppresses fail-closed until the store answers.`), { phase: "memory", sessionId });
|
|
182
|
+
}
|
|
183
|
+
if (input.captureLineageFault === true) {
|
|
184
|
+
const firstIndeterminate = !captureIndeterminate;
|
|
185
|
+
captureIndeterminate = true;
|
|
186
|
+
captureLineageIndeterminate = true;
|
|
187
|
+
if (firstIndeterminate) {
|
|
188
|
+
deps.onError?.(new Error(`this session's fork-lineage metadata is unreadable — whether it continues an opted-out source session cannot be established, so its capture state is indeterminate: every memory commit boundary (read-side adoption included) suppresses fail-closed; no opt-out record is minted from an unreadable state.`), { phase: "memory", sessionId });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const standing = standingRead.record;
|
|
192
|
+
let floored = captureFloored;
|
|
193
|
+
if (!floored && !captureDeclared && standing === undefined && input.captureFloorIndeterminate === true) {
|
|
194
|
+
const rows = new Map();
|
|
195
|
+
for (const row of input.captureAncestors ?? [])
|
|
196
|
+
rows.set(row.sessionId, row.controlDir);
|
|
197
|
+
if (input.parentSessionId !== undefined && !rows.has(input.parentSessionId))
|
|
198
|
+
rows.set(input.parentSessionId, input.parentCaptureQueryDir);
|
|
199
|
+
let anyFault = standingRead.fault;
|
|
200
|
+
let found = false;
|
|
201
|
+
for (const [ancestorId, ancestorDir] of rows) {
|
|
202
|
+
const samePlane = eng.sessionCaptureOptOutOrFault(ancestorId);
|
|
203
|
+
if (samePlane.record !== undefined) {
|
|
204
|
+
found = true;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
if (samePlane.fault)
|
|
208
|
+
anyFault = true;
|
|
209
|
+
if (ancestorDir !== undefined && ancestorDir !== eng.controlPlaneDir) {
|
|
210
|
+
try {
|
|
211
|
+
const crossPlane = deps.memoryCaptureRecordStore !== undefined ? deps.memoryCaptureRecordStore({ controlDir: ancestorDir }).read(ancestorId) : readSessionCaptureOptOut(ancestorDir, ancestorId);
|
|
212
|
+
if (crossPlane !== undefined) {
|
|
213
|
+
found = true;
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
anyFault = true;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (found)
|
|
223
|
+
floored = true;
|
|
224
|
+
else if (anyFault) {
|
|
225
|
+
if (!captureIndeterminate) {
|
|
226
|
+
captureIndeterminate = true;
|
|
227
|
+
deps.onError?.(new Error(`the spawning session's capture opt-out state was INDETERMINATE at spawn (its record store faulted) and the live re-query still cannot answer — this delegated session inherits the suppression: every memory commit boundary (read-side adoption included) suppresses fail-closed until the store answers; no opt-out record is minted from an unreadable state.`), { phase: "memory", sessionId });
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
let forkInherited = false;
|
|
232
|
+
if (!floored && !captureDeclared && standing === undefined && input.captureForkOrigin !== undefined) {
|
|
233
|
+
const src = eng.sessionCaptureOptOutOrFault(input.captureForkOrigin);
|
|
234
|
+
if (src.record !== undefined)
|
|
235
|
+
forkInherited = true;
|
|
236
|
+
else if (src.fault && !captureIndeterminate) {
|
|
237
|
+
captureIndeterminate = true;
|
|
238
|
+
deps.onError?.(new Error(`this session is a FORK of session "${input.captureForkOrigin}" whose capture opt-out record store is unreadable — the fork's capture state is indeterminate (the copied transcript may be governed by a standing opt-out), so every memory commit boundary suppresses fail-closed until the store answers; no opt-out record is minted from an unreadable state.`), { phase: "memory", sessionId });
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (standing === undefined && !captureDeclared && !floored && !forkInherited)
|
|
242
|
+
return;
|
|
243
|
+
if (standing !== undefined && !captureDeclared && !floored && capturePosture !== "open") {
|
|
244
|
+
const verdict = adjudicateCaptureOptOut({ posture: capturePosture, entitlement: captureEntitlement, subject: "standing-record" });
|
|
245
|
+
if (!verdict.allowed)
|
|
246
|
+
throw captureOptOutDeniedError(verdict.detail);
|
|
247
|
+
}
|
|
248
|
+
if (standing === undefined) {
|
|
249
|
+
const outcome = eng.markSessionCaptureOptOut(sessionId, captureDeclared ? `declared on TaskSpec.memory.capture` : forkInherited ? `inherited capture opt-out from the forked source session` : `inherited capture opt-out floor from the spawning session`);
|
|
250
|
+
if (outcome === "unpersisted") {
|
|
251
|
+
deliverEngineNotice(deps.onNotice, memoryCaptureOptOutUnpersistedNotice({ sessionId, ingress: "declaration" }));
|
|
252
|
+
throw captureOptOutUnpersistedError(sessionId, "declaration");
|
|
253
|
+
}
|
|
254
|
+
if (outcome === "created")
|
|
255
|
+
deliverEngineNotice(deps.onNotice, memoryCaptureOptedOutNotice({ sessionId, origin: captureDeclared ? "declaration" : forkInherited ? "fork-origin" : "delegation-floor" }));
|
|
256
|
+
}
|
|
257
|
+
else if (!captureDeclared) {
|
|
258
|
+
deliverEngineNotice(deps.onNotice, memoryCaptureOptedOutNotice({ sessionId, origin: "standing-record" }));
|
|
259
|
+
}
|
|
260
|
+
captureOptedOut = true;
|
|
261
|
+
if (input.memoryCapturePolicyDeclared !== true && !undeclaredCapturePostureAnnounced) {
|
|
262
|
+
undeclaredCapturePostureAnnounced = true;
|
|
263
|
+
deps.onError?.(new Error(`a session memory-capture opt-out was honored under the DEFAULT capture posture (no RunnerDeps.memoryCapturePolicy configured) — ` +
|
|
264
|
+
`the switch is now in use; declare "open", "governed" or "capture-required" to make the deployment's stance explicit.`), { phase: "config", sessionId });
|
|
265
|
+
}
|
|
266
|
+
};
|
|
144
267
|
const retrievalBackend = (b, planeRestricted) => planeRestricted
|
|
145
268
|
? (b.restrictedAdoptionView?.({ audit: false }) ??
|
|
146
269
|
b.retrievalView?.() ??
|
|
@@ -164,9 +287,47 @@ export async function prepareMemory(input) {
|
|
|
164
287
|
let injectFn;
|
|
165
288
|
let harvestBoth;
|
|
166
289
|
let toolPlanes;
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
290
|
+
const admitNothingOptsNow = () => {
|
|
291
|
+
if (input.memoryPersistenceDeclared === false) {
|
|
292
|
+
return { admitNothing: { reason: "harvest admitted nothing: memory persistence is declared unavailable for this session (memoryPersistenceCapable: false)" } };
|
|
293
|
+
}
|
|
294
|
+
if (captureLineageIndeterminate) {
|
|
295
|
+
return { admitNothing: { reason: `harvest admitted nothing: this session's fork-lineage metadata is unreadable — whether it continues an opted-out source cannot be established, so commits are suppressed fail-closed` } };
|
|
296
|
+
}
|
|
297
|
+
const own = captureOptedOut ? { record: { at: 0, reason: "in-run state" }, fault: false } : writeEngine.sessionCaptureOptOutOrFault(sessionId);
|
|
298
|
+
if (own.record !== undefined) {
|
|
299
|
+
return { admitNothing: { reason: `harvest admitted nothing: this session declared memory capture opt-out (memory.capture: "off")` } };
|
|
300
|
+
}
|
|
301
|
+
if (own.fault) {
|
|
302
|
+
return { admitNothing: { reason: `harvest admitted nothing: the capture opt-out record store is unreadable — the opt-out state is indeterminate and commits are suppressed fail-closed` } };
|
|
303
|
+
}
|
|
304
|
+
const ancestors = new Map();
|
|
305
|
+
for (const row of input.captureAncestors ?? [])
|
|
306
|
+
ancestors.set(row.sessionId, row.controlDir);
|
|
307
|
+
if (input.parentSessionId !== undefined && !ancestors.has(input.parentSessionId))
|
|
308
|
+
ancestors.set(input.parentSessionId, input.parentCaptureQueryDir);
|
|
309
|
+
if (input.captureForkOrigin !== undefined && !ancestors.has(input.captureForkOrigin))
|
|
310
|
+
ancestors.set(input.captureForkOrigin, undefined);
|
|
311
|
+
for (const [ancestorId, ancestorDir] of ancestors) {
|
|
312
|
+
const samePlane = writeEngine.sessionCaptureOptOutOrFault(ancestorId);
|
|
313
|
+
let crossPlane;
|
|
314
|
+
if (ancestorDir !== undefined && ancestorDir !== writeEngine.controlPlaneDir) {
|
|
315
|
+
try {
|
|
316
|
+
crossPlane = deps.memoryCaptureRecordStore !== undefined ? deps.memoryCaptureRecordStore({ controlDir: ancestorDir }).read(ancestorId) : readSessionCaptureOptOut(ancestorDir, ancestorId);
|
|
317
|
+
}
|
|
318
|
+
catch {
|
|
319
|
+
return { admitNothing: { reason: `harvest admitted nothing: a spawning session's capture record store is unreadable — the floor state is indeterminate and commits are suppressed fail-closed` } };
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (samePlane.record !== undefined || crossPlane !== undefined) {
|
|
323
|
+
return { admitNothing: { reason: `harvest admitted nothing: a spawning session declared memory capture opt-out — the opt-out is a delegation floor no descendant loosens`, cause: "capture_optout_inherited" } };
|
|
324
|
+
}
|
|
325
|
+
if (samePlane.fault) {
|
|
326
|
+
return { admitNothing: { reason: `harvest admitted nothing: the capture opt-out record store is unreadable while a spawning session's floor is in question — suppressed fail-closed` } };
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return {};
|
|
330
|
+
};
|
|
170
331
|
if (dual) {
|
|
171
332
|
const personalBackendChosen = choosePersonalBackend();
|
|
172
333
|
{
|
|
@@ -195,16 +356,19 @@ export async function prepareMemory(input) {
|
|
|
195
356
|
controlDir: identityKey !== undefined ? deriveProjectControlDir(engineRoot, identityKey) : deriveRepoControlPlaneDir(engineRoot, repoRoot),
|
|
196
357
|
onIncident: onEngineIncident,
|
|
197
358
|
provenance: input.memoryProvenance,
|
|
359
|
+
...captureStoreOpt(backend, identityKey !== undefined ? deriveProjectControlDir(engineRoot, identityKey) : deriveRepoControlPlaneDir(engineRoot, repoRoot)),
|
|
198
360
|
...(input.deps.memoryConsolidation !== undefined ? { consolidation: input.deps.memoryConsolidation } : {}),
|
|
199
361
|
});
|
|
200
362
|
const personal = createPersonalEngine(personalBackendChosen);
|
|
201
363
|
const personalEngine = personal.engine;
|
|
202
364
|
const p = planes;
|
|
203
|
-
|
|
365
|
+
armCaptureOptOut(p.writePlane === "personal" ? personalEngine : projectEngine);
|
|
366
|
+
const projectHandle = await projectEngine.materialize(p.project, p.writePlane === "project" ? memorySpec.writeScope : null, { adoptionRestricted: adoptionRestricted || captureOptedOut || captureIndeterminate, sessionId });
|
|
204
367
|
materializedResidue.push(...planeScopes(p.project, p.writePlane === "project" ? memorySpec.writeScope : null));
|
|
205
|
-
const personalHandle = await personalEngine.materialize(p.personal, p.writePlane === "personal" ? memorySpec.writeScope : null, { adoptionRestricted, sessionId });
|
|
368
|
+
const personalHandle = await personalEngine.materialize(p.personal, p.writePlane === "personal" ? memorySpec.writeScope : null, { adoptionRestricted: adoptionRestricted || captureOptedOut || captureIndeterminate, sessionId });
|
|
206
369
|
materializedResidue.push(...planeScopes(p.personal, p.writePlane === "personal" ? memorySpec.writeScope : null));
|
|
207
370
|
const writeIsPersonal = p.writePlane === "personal";
|
|
371
|
+
memoryMarkedEntriesServed = projectHandle.markedEntriesPresent === true || personalHandle.markedEntriesPresent === true;
|
|
208
372
|
writeEngine = writeIsPersonal ? personalEngine : projectEngine;
|
|
209
373
|
writeHandle = writeIsPersonal ? personalHandle : projectHandle;
|
|
210
374
|
readOnlyEngine = writeIsPersonal ? projectEngine : personalEngine;
|
|
@@ -212,22 +376,24 @@ export async function prepareMemory(input) {
|
|
|
212
376
|
injectFn = () => mergeInjections(projectEngine.inject(projectHandle, { writeToolMounted: input.writeToolsMounted, reminderMark: input.reminderMark }), personalEngine.inject(personalHandle, { writeToolMounted: input.writeToolsMounted, reminderMark: input.reminderMark }));
|
|
213
377
|
toolPlanes = [
|
|
214
378
|
{
|
|
215
|
-
backend: retrievalBackend(backend, adoptionRestricted || p.writePlane !== "project"),
|
|
379
|
+
backend: retrievalBackend(backend, adoptionRestricted || captureOptedOut || captureIndeterminate || p.writePlane !== "project"),
|
|
216
380
|
scopes: planeScopes(p.project, p.writePlane === "project" ? memorySpec.writeScope : null),
|
|
217
381
|
recordRetrieved: (ids) => projectEngine.recordRetrieved(ids),
|
|
218
382
|
challengeExclusions: () => projectEngine.readChallengeExclusions(),
|
|
383
|
+
enginePlaneProvenance: projectEngine.provenanceMode,
|
|
219
384
|
},
|
|
220
385
|
{
|
|
221
|
-
backend: retrievalBackend(personal.backend, adoptionRestricted || p.writePlane !== "personal"),
|
|
386
|
+
backend: retrievalBackend(personal.backend, adoptionRestricted || captureOptedOut || captureIndeterminate || p.writePlane !== "personal"),
|
|
222
387
|
scopes: planeScopes(p.personal, p.writePlane === "personal" ? memorySpec.writeScope : null),
|
|
223
388
|
recordRetrieved: (ids) => personalEngine.recordRetrieved(ids),
|
|
224
389
|
challengeExclusions: () => personalEngine.readChallengeExclusions(),
|
|
390
|
+
enginePlaneProvenance: personalEngine.provenanceMode,
|
|
225
391
|
},
|
|
226
392
|
];
|
|
227
393
|
harvestBoth = async () => {
|
|
228
394
|
const writeFirst = writeIsPersonal ? [personalEngine, personalHandle] : [projectEngine, projectHandle];
|
|
229
395
|
const readOther = writeIsPersonal ? [projectEngine, projectHandle] : [personalEngine, personalHandle];
|
|
230
|
-
const writeReport = await writeFirst[0].harvest(writeFirst[1], { ...pollutedOpts(writeFirst[0]), sessionId, ...
|
|
396
|
+
const writeReport = await writeFirst[0].harvest(writeFirst[1], { ...pollutedOpts(writeFirst[0]), sessionId, ...admitNothingOptsNow() });
|
|
231
397
|
let readReport;
|
|
232
398
|
let readFailure;
|
|
233
399
|
try {
|
|
@@ -245,18 +411,21 @@ export async function prepareMemory(input) {
|
|
|
245
411
|
else if (personalOnly) {
|
|
246
412
|
const personal = createPersonalEngine(choosePersonalBackend());
|
|
247
413
|
const personalEngine = personal.engine;
|
|
248
|
-
|
|
414
|
+
armCaptureOptOut(personalEngine);
|
|
415
|
+
const handle = await personalEngine.materialize(memorySpec.scopes, memorySpec.writeScope, { adoptionRestricted: adoptionRestricted || captureOptedOut || captureIndeterminate, sessionId });
|
|
249
416
|
materializedResidue.push(...planeScopes(memorySpec.scopes, memorySpec.writeScope));
|
|
417
|
+
memoryMarkedEntriesServed = handle.markedEntriesPresent === true;
|
|
250
418
|
writeEngine = personalEngine;
|
|
251
419
|
writeHandle = handle;
|
|
252
420
|
injectFn = () => personalEngine.inject(handle, { writeToolMounted: input.writeToolsMounted, reminderMark: input.reminderMark });
|
|
253
|
-
harvestBoth = () => personalEngine.harvest(handle, { ...pollutedOpts(personalEngine), sessionId, ...
|
|
421
|
+
harvestBoth = () => personalEngine.harvest(handle, { ...pollutedOpts(personalEngine), sessionId, ...admitNothingOptsNow() });
|
|
254
422
|
toolPlanes = [
|
|
255
423
|
{
|
|
256
|
-
backend: retrievalBackend(personal.backend, adoptionRestricted || memorySpec.writeScope === null),
|
|
424
|
+
backend: retrievalBackend(personal.backend, adoptionRestricted || captureOptedOut || captureIndeterminate || memorySpec.writeScope === null),
|
|
257
425
|
scopes: planeScopes(memorySpec.scopes, memorySpec.writeScope),
|
|
258
426
|
recordRetrieved: (ids) => personalEngine.recordRetrieved(ids),
|
|
259
427
|
challengeExclusions: () => personalEngine.readChallengeExclusions(),
|
|
428
|
+
enginePlaneProvenance: personalEngine.provenanceMode,
|
|
260
429
|
},
|
|
261
430
|
];
|
|
262
431
|
}
|
|
@@ -267,20 +436,24 @@ export async function prepareMemory(input) {
|
|
|
267
436
|
controlDir: identityKey !== undefined ? deriveProjectControlDir(engineRoot, identityKey) : deriveRepoControlPlaneDir(engineRoot, repoRoot),
|
|
268
437
|
onIncident: onEngineIncident,
|
|
269
438
|
provenance: input.memoryProvenance,
|
|
439
|
+
...captureStoreOpt(backend, identityKey !== undefined ? deriveProjectControlDir(engineRoot, identityKey) : deriveRepoControlPlaneDir(engineRoot, repoRoot)),
|
|
270
440
|
...(input.deps.memoryConsolidation !== undefined ? { consolidation: input.deps.memoryConsolidation } : {}),
|
|
271
441
|
});
|
|
272
|
-
|
|
442
|
+
armCaptureOptOut(engine);
|
|
443
|
+
const handle = await engine.materialize(memorySpec.scopes, memorySpec.writeScope, { adoptionRestricted: adoptionRestricted || captureOptedOut || captureIndeterminate, sessionId });
|
|
273
444
|
materializedResidue.push(...planeScopes(memorySpec.scopes, memorySpec.writeScope));
|
|
445
|
+
memoryMarkedEntriesServed = handle.markedEntriesPresent === true;
|
|
274
446
|
writeEngine = engine;
|
|
275
447
|
writeHandle = handle;
|
|
276
448
|
injectFn = () => engine.inject(handle, { writeToolMounted: input.writeToolsMounted, reminderMark: input.reminderMark });
|
|
277
|
-
harvestBoth = () => engine.harvest(handle, { ...pollutedOpts(engine), sessionId, ...
|
|
449
|
+
harvestBoth = () => engine.harvest(handle, { ...pollutedOpts(engine), sessionId, ...admitNothingOptsNow() });
|
|
278
450
|
toolPlanes = [
|
|
279
451
|
{
|
|
280
|
-
backend: retrievalBackend(backend, adoptionRestricted || memorySpec.writeScope === null),
|
|
452
|
+
backend: retrievalBackend(backend, adoptionRestricted || captureOptedOut || captureIndeterminate || memorySpec.writeScope === null),
|
|
281
453
|
scopes: planeScopes(memorySpec.scopes, memorySpec.writeScope),
|
|
282
454
|
recordRetrieved: (ids) => engine.recordRetrieved(ids),
|
|
283
455
|
challengeExclusions: () => engine.readChallengeExclusions(),
|
|
456
|
+
enginePlaneProvenance: engine.provenanceMode,
|
|
284
457
|
},
|
|
285
458
|
];
|
|
286
459
|
}
|
|
@@ -301,6 +474,22 @@ export async function prepareMemory(input) {
|
|
|
301
474
|
};
|
|
302
475
|
}
|
|
303
476
|
}
|
|
477
|
+
{
|
|
478
|
+
const root = writeHandle.writableRoot;
|
|
479
|
+
if (w.key === root || w.key.startsWith(`${root}${sep}`)) {
|
|
480
|
+
const state = captureOptedOut ? { record: { at: 0, reason: "in-run state" }, fault: false } : writeEngine.sessionCaptureOptOutOrFault(sessionId);
|
|
481
|
+
if (state.record !== undefined || state.fault) {
|
|
482
|
+
return {
|
|
483
|
+
ok: false,
|
|
484
|
+
code: "read_only_layering",
|
|
485
|
+
reason: state.record !== undefined
|
|
486
|
+
? `memory capture is off for this session at the user's request (memory.capture: "off") — writes into the memory store are refused. Nothing was written.`
|
|
487
|
+
: `the capture opt-out record store is unreadable, so this session's capture state is indeterminate — writes into the memory store are refused fail-closed. Nothing was written.`,
|
|
488
|
+
muted: false,
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
304
493
|
return writeEngine.gateWrite(writeHandle, w.key, w.content);
|
|
305
494
|
};
|
|
306
495
|
let pollutionAnnounced = false;
|
|
@@ -326,7 +515,8 @@ export async function prepareMemory(input) {
|
|
|
326
515
|
try {
|
|
327
516
|
const report = await harvestBoth();
|
|
328
517
|
if (!report.ok && report.incident) {
|
|
329
|
-
|
|
518
|
+
const named = report.reportId !== undefined ? `${report.incident.kind}, report ${report.reportId}` : report.incident.kind;
|
|
519
|
+
deps.onError?.(new Error(`memory harvest refused (${named}): ${report.incident.detail}`), { phase: "memory", sessionId });
|
|
330
520
|
}
|
|
331
521
|
announceHarvestContainment(report);
|
|
332
522
|
try {
|
|
@@ -345,11 +535,76 @@ export async function prepareMemory(input) {
|
|
|
345
535
|
return undefined;
|
|
346
536
|
}
|
|
347
537
|
};
|
|
538
|
+
const resolveCaptureEntitlementFresh = async () => {
|
|
539
|
+
if (deps.runtimeCapsResolver === undefined)
|
|
540
|
+
return { value: undefined, faulted: false };
|
|
541
|
+
try {
|
|
542
|
+
const caps = (await deps.runtimeCapsResolver(spec.principal)) ?? undefined;
|
|
543
|
+
const v = caps?.allowMemoryOptOut;
|
|
544
|
+
if (v !== undefined && typeof v !== "boolean")
|
|
545
|
+
return { value: undefined, faulted: true };
|
|
546
|
+
return { value: v, faulted: false };
|
|
547
|
+
}
|
|
548
|
+
catch {
|
|
549
|
+
return { value: undefined, faulted: true };
|
|
550
|
+
}
|
|
551
|
+
};
|
|
348
552
|
memoryEngineSession = {
|
|
349
553
|
engine: writeEngine,
|
|
350
554
|
handle: writeHandle,
|
|
351
555
|
inject: injectFn,
|
|
352
556
|
harvest: harvestSafe,
|
|
557
|
+
captureOptOut: {
|
|
558
|
+
optedOut: () => captureOptedOut || writeEngine.sessionCaptureOptOutOrFault(sessionId).record !== undefined,
|
|
559
|
+
indeterminate: () => {
|
|
560
|
+
if (captureOptedOut)
|
|
561
|
+
return false;
|
|
562
|
+
const s = writeEngine.sessionCaptureOptOutOrFault(sessionId);
|
|
563
|
+
return s.record === undefined && (captureIndeterminate || s.fault);
|
|
564
|
+
},
|
|
565
|
+
flip: async (reason) => {
|
|
566
|
+
const entitlement = await resolveCaptureEntitlementFresh();
|
|
567
|
+
const verdict = adjudicateCaptureOptOut({ posture: capturePosture, entitlement, subject: "declaration" });
|
|
568
|
+
if (!verdict.allowed)
|
|
569
|
+
throw captureOptOutDeniedError(verdict.detail);
|
|
570
|
+
if (verdict.faultDisclosure !== undefined)
|
|
571
|
+
deps.onError?.(new Error(verdict.faultDisclosure), { phase: "config", sessionId });
|
|
572
|
+
if (input.captureCarrierUnsupported === true) {
|
|
573
|
+
const e = new Error(`memory capture opt-out cannot be honored on this deployment shape: the execution environment is remote/per-run ` +
|
|
574
|
+
`and no RunnerDeps.memoryCaptureRecordStore is supplied — the record would not survive to a resume replica. Nothing was recorded.`);
|
|
575
|
+
e.code = "config.memory_capture_unsupported";
|
|
576
|
+
throw e;
|
|
577
|
+
}
|
|
578
|
+
const trimmed = reason?.trim();
|
|
579
|
+
const outcome = writeEngine.markSessionCaptureOptOut(sessionId, trimmed !== undefined && trimmed !== "" ? `host flip verb: ${trimmed.slice(0, 200)}` : "host flip verb");
|
|
580
|
+
if (outcome === "unpersisted") {
|
|
581
|
+
deliverEngineNotice(deps.onNotice, memoryCaptureOptOutUnpersistedNotice({ sessionId, ingress: "flip-verb" }));
|
|
582
|
+
throw captureOptOutUnpersistedError(sessionId, "flip-verb");
|
|
583
|
+
}
|
|
584
|
+
captureOptedOut = true;
|
|
585
|
+
if (outcome === "created") {
|
|
586
|
+
deliverEngineNotice(deps.onNotice, memoryCaptureOptedOutNotice({ sessionId, origin: "flip-verb" }));
|
|
587
|
+
if (input.memoryCapturePolicyDeclared !== true && !undeclaredCapturePostureAnnounced) {
|
|
588
|
+
undeclaredCapturePostureAnnounced = true;
|
|
589
|
+
deps.onError?.(new Error(`a session memory-capture opt-out was honored under the DEFAULT capture posture (no RunnerDeps.memoryCapturePolicy configured) — ` +
|
|
590
|
+
`the switch is now in use; declare "open", "governed" or "capture-required" to make the deployment's stance explicit.`), { phase: "config", sessionId });
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
const sweep = await writeEngine.sweepSessionCaptureResidue(writeHandle);
|
|
594
|
+
if (sweep.failures.length > 0) {
|
|
595
|
+
const named = sweep.failures
|
|
596
|
+
.slice(0, 5)
|
|
597
|
+
.map((f) => `${f.path} (${f.detail})`)
|
|
598
|
+
.join("; ");
|
|
599
|
+
const e = new Error(`memory capture opt-out is ON (the one-way record stands) but the boundary sweep could not contain ` +
|
|
600
|
+
`${sweep.failures.length} path(s) on the writable memory root — the named residue stays on the authoritative ` +
|
|
601
|
+
`plane until a retry or host action clears it: ${named}${sweep.failures.length > 5 ? "; …" : ""}`);
|
|
602
|
+
e.code = "memory.capture_optout_sweep_failed";
|
|
603
|
+
throw e;
|
|
604
|
+
}
|
|
605
|
+
return { outcome };
|
|
606
|
+
},
|
|
607
|
+
},
|
|
353
608
|
pollution: {
|
|
354
609
|
polluted: () => writeEngine.sessionPollution(sessionId),
|
|
355
610
|
markPolluted: (reason, cause) => {
|
|
@@ -409,7 +664,10 @@ export async function prepareMemory(input) {
|
|
|
409
664
|
if (typeof err.code === "string" &&
|
|
410
665
|
(err.code.startsWith("config.memory_scope") ||
|
|
411
666
|
err.code.startsWith("config.memory_project") ||
|
|
412
|
-
err.code === "config.memory_dual_root_overlap"
|
|
667
|
+
err.code === "config.memory_dual_root_overlap" ||
|
|
668
|
+
err.code === "memory.capture_optout_denied" ||
|
|
669
|
+
err.code === "memory.capture_optout_unpersisted" ||
|
|
670
|
+
err.code.startsWith("config.memory_capture"))) {
|
|
413
671
|
throw err;
|
|
414
672
|
}
|
|
415
673
|
deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "memory", sessionId });
|
|
@@ -427,6 +685,7 @@ export async function prepareMemory(input) {
|
|
|
427
685
|
}
|
|
428
686
|
let memoryBlock;
|
|
429
687
|
let seedFiles;
|
|
688
|
+
let recallDisciplineSegment;
|
|
430
689
|
if (memorySpec && memorySpec.enabled && !useMemoryEngine) {
|
|
431
690
|
const detail = "TaskSpec.memory is enabled but RunnerDeps.memoryBackend is not configured; memory is inactive for this task (the legacy memoryStore fallback was retired in design/138 S4 and the dep was removed in design/157 B19).";
|
|
432
691
|
deps.onError?.(new Error(detail), { phase: "config", sessionId });
|
|
@@ -434,7 +693,13 @@ export async function prepareMemory(input) {
|
|
|
434
693
|
if (memoryEngineSession) {
|
|
435
694
|
const injection = memoryEngineSession.inject();
|
|
436
695
|
let blockBody = injection.block;
|
|
437
|
-
if (
|
|
696
|
+
if (captureOptedOut) {
|
|
697
|
+
blockBody = [MEMORY_CAPTURE_OPTOUT_NOTICE, injection.index, injection.announceBlock].filter((s) => Boolean(s && s.trim())).join("\n\n");
|
|
698
|
+
}
|
|
699
|
+
else if (captureIndeterminate && input.rosterCanPersist) {
|
|
700
|
+
blockBody = [MEMORY_CAPTURE_INDETERMINATE_NOTICE, injection.index, injection.announceBlock].filter((s) => Boolean(s && s.trim())).join("\n\n");
|
|
701
|
+
}
|
|
702
|
+
else if (!input.rosterCanPersist && injection.instruction === "" && injection.readOnlyNotice === undefined) {
|
|
438
703
|
blockBody = blockBody.trim() ? `${MEMORY_READONLY_NOTICE}\n\n${blockBody}` : MEMORY_READONLY_NOTICE;
|
|
439
704
|
}
|
|
440
705
|
else if (!input.rosterCanPersist && injection.instruction !== "") {
|
|
@@ -449,16 +714,23 @@ export async function prepareMemory(input) {
|
|
|
449
714
|
!blockBody.trimEnd().endsWith(MEMORY_ANNOUNCEMENT_READONLY_CODA)) {
|
|
450
715
|
blockBody = `${blockBody}\n\n${MEMORY_ANNOUNCEMENT_READONLY_CODA}`;
|
|
451
716
|
}
|
|
717
|
+
if (captureOptedOut &&
|
|
718
|
+
input.rosterCanPersist &&
|
|
719
|
+
(injection.announceBlock?.trim() ?? "") !== "" &&
|
|
720
|
+
blockBody.includes(injection.announceBlock) &&
|
|
721
|
+
!blockBody.trimEnd().endsWith(MEMORY_ANNOUNCEMENT_CAPTURE_OPTOUT_CODA)) {
|
|
722
|
+
blockBody = `${blockBody}\n\n${MEMORY_ANNOUNCEMENT_CAPTURE_OPTOUT_CODA}`;
|
|
723
|
+
}
|
|
452
724
|
if (blockBody.trim())
|
|
453
725
|
memoryBlock = blockBody;
|
|
454
726
|
if (memoryTools !== undefined) {
|
|
455
|
-
|
|
456
|
-
memoryBlock = memoryBlock !== undefined ? `${memoryBlock}\n\n${
|
|
727
|
+
recallDisciplineSegment = memoryRecallDisciplineSegment(input.memoryProvenance, { markedEntriesServed: memoryMarkedEntriesServed });
|
|
728
|
+
memoryBlock = memoryBlock !== undefined ? `${memoryBlock}\n\n${recallDisciplineSegment}` : recallDisciplineSegment;
|
|
457
729
|
}
|
|
458
|
-
if (memoryEngineSession.handle.writeScope !== null && input.writeToolsMounted && input.rosterCanPersist) {
|
|
730
|
+
if (memoryEngineSession.handle.writeScope !== null && input.writeToolsMounted && input.rosterCanPersist && !captureOptedOut && !captureIndeterminate) {
|
|
459
731
|
memoryBlock = memoryBlock !== undefined ? `${memoryBlock}\n\n${MEMORY_PREFERENCE_DISCIPLINE}` : MEMORY_PREFERENCE_DISCIPLINE;
|
|
460
732
|
}
|
|
461
|
-
if (memoryBlock !== undefined && injection.indexSeed !== undefined && input.rosterCanPersist)
|
|
733
|
+
if (memoryBlock !== undefined && injection.indexSeed !== undefined && input.rosterCanPersist && !captureOptedOut && !captureIndeterminate)
|
|
462
734
|
seedFiles = [injection.indexSeed];
|
|
463
735
|
}
|
|
464
736
|
if (effectiveMemoryScopes === undefined) {
|
|
@@ -468,5 +740,14 @@ export async function prepareMemory(input) {
|
|
|
468
740
|
: { state: "none", reason: "disabled", scopes: [], writeScope: null }
|
|
469
741
|
: { state: "none", reason: "no-spec", scopes: [], writeScope: null };
|
|
470
742
|
}
|
|
471
|
-
return {
|
|
743
|
+
return {
|
|
744
|
+
memoryEngineSession,
|
|
745
|
+
memoryBlock,
|
|
746
|
+
admittedOrgScopes,
|
|
747
|
+
ownOrgVerdict,
|
|
748
|
+
effectiveMemoryScopes,
|
|
749
|
+
...(memoryTools !== undefined ? { memoryTools } : {}),
|
|
750
|
+
...(recallDisciplineSegment !== undefined ? { recallDisciplineSegment } : {}),
|
|
751
|
+
...(seedFiles !== undefined ? { seedFiles } : {}),
|
|
752
|
+
};
|
|
472
753
|
}
|