@sema-agent/core 7.16.0 → 7.17.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 +173 -0
- package/dist/agents/builtin-agents.d.ts +3 -3
- package/dist/agents/cross-session-envelope.d.ts +0 -1
- package/dist/agents/cross-session-envelope.js +0 -1
- package/dist/agents/peer-notices.d.ts +0 -9
- package/dist/agents/peer-notices.js +0 -63
- package/dist/agents/subagent.js +7 -15
- package/dist/brain/request-params.d.ts +2 -2
- package/dist/config/defaults.d.ts +0 -7
- package/dist/config/defaults.js +0 -2
- package/dist/core/artifact-host.d.ts +218 -0
- package/dist/core/artifact-host.js +92 -0
- package/dist/core/ask-origin.d.ts +29 -3
- package/dist/core/ask-origin.js +17 -9
- package/dist/core/ask-question.d.ts +25 -0
- package/dist/core/ask-question.js +4 -0
- package/dist/core/ask-unresolvable-notice.d.ts +30 -21
- package/dist/core/ask-unresolvable-notice.js +16 -8
- package/dist/core/auto-compaction.d.ts +10 -10
- package/dist/core/auto-mode-arming.d.ts +2 -2
- package/dist/core/background-agent-store.d.ts +5 -5
- package/dist/core/background-shell.d.ts +1 -1
- package/dist/core/checkpoint-execution-record.d.ts +0 -3
- package/dist/core/checkpoint-execution-record.js +0 -4
- package/dist/core/checkpoint-store.d.ts +71 -99
- package/dist/core/checkpoint-store.js +9 -16
- package/dist/core/context-edit.d.ts +36 -104
- package/dist/core/context-edit.js +37 -60
- package/dist/core/effective-path-target.d.ts +68 -8
- package/dist/core/effective-path-target.js +42 -30
- package/dist/core/engine-notice.d.ts +46 -32
- package/dist/core/env-budget.d.ts +31 -0
- package/dist/core/env-budget.js +39 -0
- package/dist/core/exec-output-tail.d.ts +5 -5
- package/dist/core/file-history-store.js +3 -6
- package/dist/core/fs-write-gate-policy.d.ts +1 -1
- package/dist/core/fs-write-gate-policy.js +3 -3
- package/dist/core/gate-lanes.js +9 -15
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hands-band.d.ts +1 -1
- package/dist/core/hooks.d.ts +18 -17
- package/dist/core/lsp-session.d.ts +1 -1
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/lsp.js +5 -4
- package/dist/core/mcp.d.ts +5 -5
- package/dist/core/mcp.js +4 -48
- package/dist/core/memory-recall.d.ts +0 -8
- package/dist/core/memory.d.ts +1 -1
- package/dist/core/oracle-isolation.js +2 -2
- package/dist/core/parent-spec-seat.d.ts +66 -0
- package/dist/core/parent-spec-seat.js +47 -0
- package/dist/core/permission-rule-model.d.ts +11 -6
- package/dist/core/permission-rule-model.js +53 -37
- package/dist/core/permission-rules.js +8 -3
- package/dist/core/protocol-naming.d.ts +2 -2
- package/dist/core/remote-env.d.ts +1 -1
- package/dist/core/retired-keys.d.ts +19 -0
- package/dist/core/retired-keys.js +15 -0
- package/dist/core/runner/active-skill-scope.js +3 -3
- package/dist/core/runner/assemble-result.d.ts +15 -13
- package/dist/core/runner/assemble-result.js +5 -4
- package/dist/core/runner/compaction-call-options.d.ts +25 -89
- package/dist/core/runner/contracts.d.ts +10 -9
- package/dist/core/runner/gate-exit.js +15 -1
- package/dist/core/runner/halt-attribution.d.ts +35 -0
- package/dist/core/runner/halt-attribution.js +16 -0
- package/dist/core/runner/memory-consolidation.d.ts +0 -2
- package/dist/core/runner/memory-consolidation.js +0 -1
- package/dist/core/runner/prepare-artifact.d.ts +53 -0
- package/dist/core/runner/prepare-artifact.js +77 -0
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -2
- package/dist/core/runner/prepare-caps-and-workflow.js +2 -3
- package/dist/core/runner/prepare-config-doors.d.ts +3 -3
- package/dist/core/runner/prepare-config-doors.js +5 -2
- package/dist/core/runner/prepare-context-lane.d.ts +2 -2
- package/dist/core/runner/prepare-context-lane.js +2 -13
- package/dist/core/runner/prepare-file-history.d.ts +1 -1
- package/dist/core/runner/prepare-file-history.js +3 -52
- package/dist/core/runner/prepare-hands-readface.d.ts +4 -7
- package/dist/core/runner/prepare-hands-readface.js +3 -2
- package/dist/core/runner/prepare-inherited-gate.d.ts +5 -2
- package/dist/core/runner/prepare-inherited-gate.js +7 -8
- package/dist/core/runner/prepare-memory.d.ts +4 -6
- package/dist/core/runner/prepare-memory.js +4 -2
- package/dist/core/runner/prepare-policy-chain.d.ts +3 -3
- package/dist/core/runner/prepare-policy-chain.js +15 -30
- package/dist/core/runner/prepare-prompt-assembly.js +1 -1
- package/dist/core/runner/prepare-safety-scan.d.ts +1 -1
- package/dist/core/runner/prepare-suspend-saga.js +0 -2
- package/dist/core/runner/prepare-task.js +10 -9
- package/dist/core/runner/prepare-wiring-manifest.js +9 -7
- package/dist/core/runner/resume-admission.js +2 -1
- package/dist/core/runner/resume-internals-and-config.js +4 -0
- package/dist/core/runner/retired-runner-deps.d.ts +3 -0
- package/dist/core/runner/retired-runner-deps.js +7 -0
- package/dist/core/runner/run-harness-handlers.js +2 -3
- package/dist/core/runner/run-settle-and-teardown.d.ts +1 -1
- package/dist/core/runner/run-settle-and-teardown.js +3 -1
- package/dist/core/runner/session-file-state-replay.js +3 -3
- package/dist/core/runner/session-rule-policy.js +3 -4
- package/dist/core/runner/stream-halt-verbs.js +1 -1
- package/dist/core/runner/stream-steer-verb.js +1 -4
- package/dist/core/runner/workspace-path.js +3 -0
- package/dist/core/runner-deps.d.ts +30 -49
- package/dist/core/safe-notify.d.ts +1 -1
- package/dist/core/sensitive-path-policy.d.ts +1 -1
- package/dist/core/sensitive-path-policy.js +4 -4
- package/dist/core/session.d.ts +2 -2
- package/dist/core/skill-tool-specifier.d.ts +1 -1
- package/dist/core/skills-directory.d.ts +1 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +1 -1
- package/dist/core/strategy-store.d.ts +8 -11
- package/dist/core/task-event.d.ts +20 -17
- package/dist/core/task-limits.d.ts +1 -1
- package/dist/core/task-notification.d.ts +5 -5
- package/dist/core/task-registry-agent.d.ts +5 -5
- package/dist/core/task-registry-monitor.d.ts +2 -2
- package/dist/core/task-registry-shared.d.ts +27 -27
- package/dist/core/task-registry-shared.js +3 -13
- package/dist/core/task-registry.d.ts +8 -8
- package/dist/core/task-result.d.ts +37 -37
- package/dist/core/task-spec.d.ts +5 -5
- package/dist/core/task-stream.d.ts +16 -11
- package/dist/core/tool-catalog-entries.d.ts +1 -0
- package/dist/core/tool-catalog-entries.js +5 -0
- package/dist/core/tool-conformance.d.ts +0 -2
- package/dist/core/tool-conformance.js +1 -3
- package/dist/core/tool-errors.d.ts +5 -0
- package/dist/core/tool-errors.js +1 -0
- package/dist/core/tool-policy.d.ts +51 -22
- package/dist/core/tool-policy.js +28 -5
- package/dist/core/tool-result-budget.d.ts +1 -1
- package/dist/core/tool-result-store.d.ts +11 -11
- package/dist/core/tool-spec.d.ts +34 -38
- package/dist/core/tools.d.ts +2 -2
- package/dist/core/trace.d.ts +12 -15
- package/dist/core/untrusted-text.d.ts +1 -1
- package/dist/core/wiring-manifest.d.ts +4 -3
- package/dist/core/workflow-journal-store.d.ts +11 -11
- package/dist/engine/execution-env/node-execution-env.d.ts +3 -2
- package/dist/engine/execution-env/node-execution-env.js +4 -2
- package/dist/engine/harness/agent-harness.d.ts +47 -4
- package/dist/engine/harness/agent-harness.js +52 -9
- package/dist/engine/loop/agent-loop.js +15 -8
- package/dist/engine/loop/types.d.ts +5 -0
- package/dist/index.d.ts +19 -14
- package/dist/index.js +15 -10
- package/dist/internal/harness.d.ts +1 -0
- package/dist/orchestration/run-spec.d.ts +3 -0
- package/dist/orchestration/run-spec.js +3 -3
- package/dist/orchestration/run-workflow-tool.d.ts +12 -6
- package/dist/orchestration/run-workflow-tool.js +23 -5
- package/dist/orchestration/workflow-primitives.d.ts +4 -2
- package/dist/orchestration/workflow-primitives.js +1 -4
- package/dist/orchestration/workflow-types.d.ts +34 -4
- package/dist/orchestration/workflow-types.js +2 -0
- package/dist/orchestration/workflow.d.ts +39 -7
- package/dist/orchestration/workflow.js +234 -113
- package/dist/prompt-assembly/assemble.d.ts +2 -2
- package/dist/prompt-assembly/assemble.js +9 -9
- package/dist/prompt-assembly/composer.d.ts +6 -7
- package/dist/prompt-assembly/composer.js +10 -10
- package/dist/prompt-assembly/epoch.js +1 -1
- package/dist/prompt-assembly/event-registry.d.ts +0 -21
- package/dist/prompt-assembly/packs/sema-default.js +30 -30
- package/dist/prompt-assembly/types.d.ts +14 -14
- package/dist/prompts/coordinator.d.ts +0 -13
- package/dist/prompts/coordinator.js +0 -3
- package/dist/stores/file/checkpoint-store.js +1 -5
- package/dist/stores/file/file-history-store.js +2 -2
- package/dist/stores/file/permission-rule-store.d.ts +4 -35
- package/dist/stores/file/permission-rule-store.js +4 -148
- package/dist/tools/artifact/artifact-text.d.ts +62 -0
- package/dist/tools/artifact/artifact-text.js +68 -0
- package/dist/tools/artifact/artifact-tool.d.ts +52 -0
- package/dist/tools/artifact/artifact-tool.js +351 -0
- package/dist/tools/artifact/local-stub.d.ts +26 -0
- package/dist/tools/artifact/local-stub.js +296 -0
- package/dist/tools/fs/bash-readonly-classifier.d.ts +74 -8
- package/dist/tools/fs/bash-readonly-classifier.js +171 -60
- package/dist/tools/fs/fs-bash.d.ts +14 -10
- package/dist/tools/fs/fs-bash.js +19 -27
- package/dist/tools/fs/fs-search-tools.js +5 -2
- package/dist/tools/fs/fs-shared.d.ts +2 -0
- package/dist/tools/fs/fs-shared.js +3 -11
- package/dist/tools/fs/index.d.ts +4 -0
- package/dist/tools/fs/index.js +4 -1
- package/dist/tools/fs/safety.d.ts +117 -1
- package/dist/tools/fs/safety.js +131 -31
- package/dist/tools/fs/search.js +8 -6
- package/package.json +2 -1
- package/test/export-surface.snapshot.json +115 -39
|
@@ -37,10 +37,11 @@ import type { ReadFace } from "../../tools/fs/index.js";
|
|
|
37
37
|
import type { InheritedGate, Prepared, RunInternals, RunnerSelfSeat, ToolFaceSnapshot } from "./contracts.js";
|
|
38
38
|
import { type BlockedRef } from "./synthetic-tools.js";
|
|
39
39
|
import { RosterBuilder } from "../tool-roster.js";
|
|
40
|
+
import type { ParentSpecSeat } from "../parent-spec-seat.js";
|
|
40
41
|
export interface PrepareCapsAndWorkflowInput {
|
|
41
42
|
/** borrowed-readonly — the REBOUND spec, whole: the roster map reads `tools`; the mounts read `enableBlockedReport`,
|
|
42
43
|
* `enablePlanMode`, `interactiveTools`; the caps/compliance stations read `principal`, `selfOrchestration`,
|
|
43
|
-
* `enableFork`, `getApiKeyAndHeaders`; the Workflow mount forwards `
|
|
44
|
+
* `enableFork`, `getApiKeyAndHeaders`; the Workflow mount forwards `handsReadOnly`, `interactiveTools`. The
|
|
44
45
|
* self-orchestration predicate takes the whole spec. Never mutated. */
|
|
45
46
|
spec: TaskSpec;
|
|
46
47
|
/** borrowed-readonly — the deployment seats, whole: `runtimeCapsResolver`, `compliancePostureResolver`, `onError`, `onNotice`,
|
|
@@ -54,7 +55,7 @@ export interface PrepareCapsAndWorkflowInput {
|
|
|
54
55
|
checkpointSeat: CheckpointSeat | undefined;
|
|
55
56
|
/** borrowed-readonly — the trusted spawn-side channel; the Workflow mount forwards `rootSessionId`, `placementRoot`,
|
|
56
57
|
* `onTaskNotification`, `workflowDepth`, and the capture-floor getter reads `memoryCaptureAncestors`. */
|
|
57
|
-
internals: Pick<RunInternals, "rootSessionId" | "placementRoot" | "onTaskNotification" | "workflowDepth" | "memoryCaptureAncestors" | "workflowParkedResume"> | undefined;
|
|
58
|
+
internals: Pick<RunInternals, "rootSessionId" | "placementRoot" | "onTaskNotification" | "workflowDepth" | "memoryCaptureAncestors" | "workflowParkedResume" | "questionFaceStripped"> | undefined;
|
|
58
59
|
/** borrowed-readonly — the acquired session; the classifier leg rebuilds its transcript window from `buildContext`. */
|
|
59
60
|
session: Pick<StoredSession, "buildContext">;
|
|
60
61
|
/** borrowed-readonly — the acquired session id (operator-line context, the refusal codes' phase record). */
|
|
@@ -88,6 +89,7 @@ export interface PrepareCapsAndWorkflowInput {
|
|
|
88
89
|
};
|
|
89
90
|
/** borrowed-readonly — the FROZEN approver seat (the Workflow mount's parentOnAsk). */
|
|
90
91
|
frozenOnAsk: OnAsk | undefined;
|
|
92
|
+
/** borrowed-readonly — the parent SPEC seat the children inherit (minted once by the inherited-gate phase; the Workflow mount's dep, the same value the delegation ctx carries). */ parentSpecSeat: ParentSpecSeat;
|
|
91
93
|
/** borrowed-readonly — the ONE read-face carrier expression (the Workflow mount's parentReadFace getter calls it). */
|
|
92
94
|
carrierReadFace: () => ReadFace | undefined;
|
|
93
95
|
/** borrowed-readonly — the filtered display-forwarding wrapper (the Workflow mount's forwardEvent; absent ⇒ no key). */
|
|
@@ -112,7 +112,7 @@ function autoModeArmReasonOf(intent, facePresent, caps, capsFaulted) {
|
|
|
112
112
|
return { armed: true, reason: "armed" };
|
|
113
113
|
}
|
|
114
114
|
export async function prepareCapsAndWorkflow(input) {
|
|
115
|
-
const { spec, deps, checkpointSeat, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, frozenOnAsk, carrierReadFace, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, autoModeIntent, peerLaneActive, peerSendMessageBuiltIn, runnerSelf } = input;
|
|
115
|
+
const { spec, deps, parentSpecSeat, checkpointSeat, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, frozenOnAsk, carrierReadFace, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, autoModeIntent, peerLaneActive, peerSendMessageBuiltIn, runnerSelf } = input;
|
|
116
116
|
const roster = new RosterBuilder(toolEffects);
|
|
117
117
|
for (const t of spec.tools ?? []) {
|
|
118
118
|
const mounted = mountCallerTool(t);
|
|
@@ -312,8 +312,7 @@ export async function prepareCapsAndWorkflow(input) {
|
|
|
312
312
|
return mine.length > 0 ? mine : undefined;
|
|
313
313
|
} }
|
|
314
314
|
: {}),
|
|
315
|
-
|
|
316
|
-
oneShot: spec.oneShot,
|
|
315
|
+
parentSpecSeat, ...(internals?.questionFaceStripped === true ? { parentQuestionFaceStripped: true } : {}),
|
|
317
316
|
...(resolvedInteractionPosture !== undefined ? { parentInteractionPosture: resolvedInteractionPosture } : {}),
|
|
318
317
|
parentMemoryCaptureState: () => {
|
|
319
318
|
const memoryEngineSession = input.memoryEngineSession();
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
import { type BrainCallGuardrailRef } from "../../brain/timeout.js";
|
|
23
23
|
import type { Model } from "../../internal/llm.js";
|
|
24
24
|
import type { ThinkingLevel } from "../../internal/harness.js";
|
|
25
|
-
import type
|
|
25
|
+
import { type MicroCompactMachine } from "../context-edit.js";
|
|
26
26
|
import { type LockedPreflight } from "../locked-config.js";
|
|
27
27
|
import { type ResolvedRole } from "../roles.js";
|
|
28
28
|
import type { SessionStore } from "../session.js";
|
|
@@ -150,7 +150,7 @@ export interface PrepareConfigDoorsResult {
|
|
|
150
150
|
* for the door + placement reasoning). The per-run state builder consumes exactly these values —
|
|
151
151
|
* the deps bag is never re-read after this door. */
|
|
152
152
|
microCompactKnob: {
|
|
153
|
-
machine:
|
|
153
|
+
machine: MicroCompactMachine;
|
|
154
154
|
clearOnRejection: boolean;
|
|
155
155
|
};
|
|
156
156
|
/** owned — the resolved role; its `systemPrompt` seat is still read at prompt-input time. */
|
|
@@ -213,7 +213,7 @@ export interface PrepareConfigDoorsResult {
|
|
|
213
213
|
* it must refuse exactly like a malformed field, never fold to the defaults. The RESOLVED values
|
|
214
214
|
* returned here are immutable and are the state builder's ONLY source — nothing re-reads the bag. */
|
|
215
215
|
export declare function resolveMicroCompactKnob(bag: RunnerDeps["microCompact"]): {
|
|
216
|
-
machine:
|
|
216
|
+
machine: MicroCompactMachine;
|
|
217
217
|
clearOnRejection: boolean;
|
|
218
218
|
};
|
|
219
219
|
export declare function prepareConfigDoors(input: PrepareConfigDoorsInput): PrepareConfigDoorsResult;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { resolveBrainCallGuardrailMs } from "../../brain/timeout.js";
|
|
2
2
|
import { assertReadFaceValue } from "../../tools/fs/index.js";
|
|
3
|
+
import { MICRO_COMPACT_MACHINES } from "../context-edit.js";
|
|
4
|
+
import { assertNoRetiredRunnerDeps } from "./retired-runner-deps.js";
|
|
3
5
|
import { resolveCheckpointStore } from "../checkpoint-store.js";
|
|
4
6
|
import { isModelPriced, malformedPricingField, modelCostToPricing } from "../pricing.js";
|
|
5
7
|
import { preflightLockedConfig } from "../locked-config.js";
|
|
@@ -133,8 +135,8 @@ export function resolveMicroCompactKnob(bag) {
|
|
|
133
135
|
throw microCompactConfigError(undefined, bag, "an object carrying optional machine/clearOnRejection keys");
|
|
134
136
|
}
|
|
135
137
|
const declaredMachine = bag?.machine;
|
|
136
|
-
if (declaredMachine !== undefined && declaredMachine
|
|
137
|
-
throw microCompactConfigError("machine", declaredMachine, `"
|
|
138
|
+
if (declaredMachine !== undefined && !MICRO_COMPACT_MACHINES.includes(declaredMachine)) {
|
|
139
|
+
throw microCompactConfigError("machine", declaredMachine, MICRO_COMPACT_MACHINES.map((m) => `"${m}"`).join(" | "));
|
|
138
140
|
}
|
|
139
141
|
return { machine: declaredMachine ?? "cc", clearOnRejection: resolveClearOnRejection(bag) };
|
|
140
142
|
}
|
|
@@ -148,6 +150,7 @@ function resolveClearOnRejection(bag) {
|
|
|
148
150
|
export function prepareConfigDoors(input) {
|
|
149
151
|
const { deps, sessions, resume, internals } = input;
|
|
150
152
|
let spec = input.spec;
|
|
153
|
+
assertNoRetiredRunnerDeps(deps);
|
|
151
154
|
assertRestoreGatedToolsValue(spec.restoreGatedTools);
|
|
152
155
|
const microCompactKnob = resolveMicroCompactKnob(deps.microCompact);
|
|
153
156
|
const assertToolNameListValue = (value, seat) => {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { type AgentHarness, type AgentMessage } from "../../internal/harness.js";
|
|
19
19
|
import type { Model } from "../../internal/llm.js";
|
|
20
|
-
import { type
|
|
20
|
+
import { type MicroCompactMachine, type OccurrenceIndex } from "../context-edit.js";
|
|
21
21
|
import { type ToolResultStore } from "../tool-result-store.js";
|
|
22
22
|
import { type RunnerDeps } from "../types.js";
|
|
23
23
|
import type { Prepared, PreparedMicroCompact } from "./contracts.js";
|
|
@@ -39,7 +39,7 @@ export interface PrepareContextLaneInput {
|
|
|
39
39
|
offloadStore: ToolResultStore | undefined;
|
|
40
40
|
/** borrowed-readonly — the doors' RESOLVED microCompact knob (immutable values, never the deps bag). */
|
|
41
41
|
microCompactKnob: {
|
|
42
|
-
machine:
|
|
42
|
+
machine: MicroCompactMachine;
|
|
43
43
|
clearOnRejection: boolean;
|
|
44
44
|
};
|
|
45
45
|
/** borrowed-mutable — the built harness. Writer here: `on("context", …)` — the ONE registration of the request-build
|
|
@@ -44,14 +44,8 @@ export function prepareContextLane(input) {
|
|
|
44
44
|
let ccPass;
|
|
45
45
|
const edited = microCompact.machine === "off" ? mediaCapped : clearStaleToolResults(mediaCapped, {
|
|
46
46
|
budgetTokens: editAt,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
...(microCompact.machine === "cc"
|
|
50
|
-
? {
|
|
51
|
-
clearSource: replayed,
|
|
52
|
-
onCleared: (pass) => { ccPass = pass; },
|
|
53
|
-
}
|
|
54
|
-
: {}),
|
|
47
|
+
clearSource: replayed,
|
|
48
|
+
onCleared: (pass) => { ccPass = pass; },
|
|
55
49
|
anchoredTotalTokens: estimateContextTokens(mediaCapped, charsPerToken).tokens,
|
|
56
50
|
charsPerToken,
|
|
57
51
|
...(offloadStore
|
|
@@ -193,15 +187,10 @@ export async function runGuardChain(args) {
|
|
|
193
187
|
};
|
|
194
188
|
let working = edited;
|
|
195
189
|
let anchoredWorking = estimateContextTokens(working, charsPerToken).tokens;
|
|
196
|
-
if (microCompact.machine === "legacy") {
|
|
197
|
-
const t = applyGuardTrim(working, anchoredWorking);
|
|
198
|
-
return { working, trimmed: t.trimmed, trimDroppedMessages: t.dropped };
|
|
199
|
-
}
|
|
200
190
|
if (microCompact.machine === "off" && anchoredWorking > guardAt) {
|
|
201
191
|
let blockingPass;
|
|
202
192
|
const blockingEdited = clearStaleToolResults(working, {
|
|
203
193
|
budgetTokens: guardAt,
|
|
204
|
-
machine: "cc",
|
|
205
194
|
clearSource: args.replayed,
|
|
206
195
|
onCleared: (pass) => { blockingPass = pass; },
|
|
207
196
|
anchoredTotalTokens: anchoredWorking,
|
|
@@ -25,7 +25,7 @@ import type { FileHistoryBoundarySeat, RunInternals } from "./contracts.js";
|
|
|
25
25
|
export interface PrepareFileHistoryInput {
|
|
26
26
|
/** borrowed-readonly — the deployment seats this phase reads: the first-touch failure policy and the
|
|
27
27
|
* history store (both validated HERE, once), the incident sink, and the retired-epoch diagnostic probe. */
|
|
28
|
-
deps: Pick<RunnerDeps, "onTrackFailure" | "fileHistoryStore" | "onError"
|
|
28
|
+
deps: Pick<RunnerDeps, "onTrackFailure" | "fileHistoryStore" | "onError">;
|
|
29
29
|
/** borrowed-readonly — the REBOUND spec's rewind request fields (the retired `rewindFiles` spelling is
|
|
30
30
|
* read off the same object as an unknown key) and the caller's cancel signal for the restore. */
|
|
31
31
|
spec: Pick<TaskSpec, "resumeAt" | "resumeAtMode" | "restoreFiles" | "rewindFilesTo" | "acceptPartialRestore" | "signal">;
|
|
@@ -63,7 +63,6 @@ export async function prepareFileHistory(input) {
|
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
const legacyEpochTail = (entryId, form = "at-or-above") => legacyRewindEpochTail(deps, sessionId, entryId, form);
|
|
67
66
|
let restoredFilePaths = [];
|
|
68
67
|
if (rewindTarget !== undefined && fileHistoryStore !== undefined && handsEnabled) {
|
|
69
68
|
const historyStore = fileHistoryStore;
|
|
@@ -85,7 +84,7 @@ export async function prepareFileHistory(input) {
|
|
|
85
84
|
}
|
|
86
85
|
}
|
|
87
86
|
if (anchor === undefined) {
|
|
88
|
-
const e = new Error(`rewind-files: no file-history boundary exists at or above the "before" branch point on session "${sessionId}" — cannot restore files consistent with the rewound context. ${
|
|
87
|
+
const e = new Error(`rewind-files: no file-history boundary exists at or above the "before" branch point on session "${sessionId}" — cannot restore files consistent with the rewound context. ${rewindRefusalTail("at-or-above")}`);
|
|
89
88
|
e.code = "rewind_snapshot.unresolvable";
|
|
90
89
|
throw e;
|
|
91
90
|
}
|
|
@@ -99,7 +98,7 @@ export async function prepareFileHistory(input) {
|
|
|
99
98
|
if (restored.error?.code === "not_found") {
|
|
100
99
|
const e = new Error(rewindBefore
|
|
101
100
|
? `rewind-files: the resolved "before" history anchor "${rewindTarget}" disappeared before restore — files were NOT rewound`
|
|
102
|
-
: `rewind-files: no file-history boundary exists for entry "${rewindTarget}" on session "${sessionId}" — the working tree was NOT rewound. ${
|
|
101
|
+
: `rewind-files: no file-history boundary exists for entry "${rewindTarget}" on session "${sessionId}" — the working tree was NOT rewound. ${rewindRefusalTail("keyed")}`);
|
|
103
102
|
e.code = "rewind_snapshot.unresolvable";
|
|
104
103
|
throw e;
|
|
105
104
|
}
|
|
@@ -192,55 +191,7 @@ function resolveWiredFileHistoryStore(candidate) {
|
|
|
192
191
|
}
|
|
193
192
|
return candidate;
|
|
194
193
|
}
|
|
195
|
-
|
|
196
|
-
const LEGACY_PROBE_TIMED_OUT = Symbol("legacy-rewind-probe-timeout");
|
|
197
|
-
async function legacyRewindEpochTail(deps, sessionId, entryId, form) {
|
|
198
|
-
const probe = deps.legacyRewindBoundaryProbe;
|
|
199
|
-
let verdict;
|
|
200
|
-
if (probe !== undefined) {
|
|
201
|
-
try {
|
|
202
|
-
let timer;
|
|
203
|
-
const timeout = new Promise((resolve) => {
|
|
204
|
-
timer = setTimeout(() => resolve(LEGACY_PROBE_TIMED_OUT), LEGACY_PROBE_TIMEOUT_MS);
|
|
205
|
-
});
|
|
206
|
-
try {
|
|
207
|
-
verdict = await Promise.race([Promise.resolve(probe({ sessionId, entryId })), timeout]);
|
|
208
|
-
}
|
|
209
|
-
finally {
|
|
210
|
-
clearTimeout(timer);
|
|
211
|
-
}
|
|
212
|
-
if (verdict === LEGACY_PROBE_TIMED_OUT) {
|
|
213
|
-
verdict = undefined;
|
|
214
|
-
try {
|
|
215
|
-
deps.onError?.(new Error(`RunnerDeps.legacyRewindBoundaryProbe did not answer within ${LEGACY_PROBE_TIMEOUT_MS}ms while explaining a rewind refusal — the refusal stands and names both possibilities`), { phase: "rewind", sessionId });
|
|
216
|
-
}
|
|
217
|
-
catch {
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
catch (err) {
|
|
222
|
-
verdict = undefined;
|
|
223
|
-
try {
|
|
224
|
-
deps.onError?.(new Error(`RunnerDeps.legacyRewindBoundaryProbe threw while explaining a rewind refusal (${err.message}) — the refusal stands and names both possibilities`), { phase: "rewind", sessionId });
|
|
225
|
-
}
|
|
226
|
-
catch {
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
if (verdict !== undefined && typeof verdict !== "boolean") {
|
|
230
|
-
try {
|
|
231
|
-
deps.onError?.(new Error(`RunnerDeps.legacyRewindBoundaryProbe answered ${JSON.stringify(String(verdict))} for entry "${entryId}" — only true/false/undefined are meaningful, so the refusal names both possibilities instead of trusting it`), { phase: "rewind", sessionId });
|
|
232
|
-
}
|
|
233
|
-
catch {
|
|
234
|
-
}
|
|
235
|
-
verdict = undefined;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
if (verdict === true) {
|
|
239
|
-
return `This deployment's legacy-epoch probe reports that entry "${entryId}" DOES carry a boundary from the retired whole-tree snapshot era, which this engine's per-edited-file seat does not restore — the two epochs are not interchangeable (a whole-tree manifest carries no tracked-set provenance, so replaying it here would converge files this session never edited). Restore it with the whole-tree-era tooling this deployment kept, or re-run the turns under the current engine.`;
|
|
240
|
-
}
|
|
241
|
-
if (verdict === false) {
|
|
242
|
-
return `This deployment's legacy-epoch probe reports no whole-tree-era boundary for entry "${entryId}" either, so the boundary simply does not exist: its turns ran without a RunnerDeps.fileHistoryStore wired, or it was reaped.`;
|
|
243
|
-
}
|
|
194
|
+
function rewindRefusalTail(form) {
|
|
244
195
|
return form === "keyed"
|
|
245
196
|
? `Boundaries are keyed by a turn's INITIAL entry and exist only for turns that ran with a RunnerDeps.fileHistoryStore wired; a boundary from the retired whole-tree snapshot era is not restorable by this seat, and reaped boundaries have none.`
|
|
246
197
|
: `Either the boundary does not exist (its turns ran without a RunnerDeps.fileHistoryStore, or it was reaped), or it was produced in the retired whole-tree snapshot era, which this engine's per-edited-file seat does not restore.`;
|
|
@@ -162,13 +162,10 @@ export interface PrepareHandsReadFaceInput {
|
|
|
162
162
|
* when no file restore ran. Fail-closed by construction — dropping a read record only ever
|
|
163
163
|
* produces refusals. */
|
|
164
164
|
restoredFilePaths?: readonly string[];
|
|
165
|
-
/** borrowed-readonly —
|
|
166
|
-
* the band's beforeWrite
|
|
167
|
-
*
|
|
168
|
-
|
|
169
|
-
memoryWriteGateRef: {
|
|
170
|
-
current?: BeforeWriteHook;
|
|
171
|
-
};
|
|
165
|
+
/** borrowed-readonly — the memory write gate the memory phase minted (it runs BEFORE this phase: the memory root
|
|
166
|
+
* must be known before the toolkit compiles), composed into the band's beforeWrite below; undefined for a
|
|
167
|
+
* memory-less run (every write passes the engine half). */
|
|
168
|
+
memoryWriteGate: BeforeWriteHook | undefined;
|
|
172
169
|
/** borrowed-mutable — the advertised-writable-directory seat (see its module header for the one
|
|
173
170
|
* rule). Present on the hands leg only (a fence exists). The memory phase, which runs BEFORE this one,
|
|
174
171
|
* has already admitted its write root through it; this phase admits the deployment's scratchpad and
|
|
@@ -123,7 +123,7 @@ export function resolveHandsLessReadFace(input) {
|
|
|
123
123
|
}
|
|
124
124
|
export async function prepareHandsMount(input) {
|
|
125
125
|
const envHandToolNames = new Set();
|
|
126
|
-
const { handsEnabled, executionEnv, taskRootFinal, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals,
|
|
126
|
+
const { handsEnabled, executionEnv, taskRootFinal, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals, memoryWriteGate, advertisedWritableDirs, firstPartyOffload, roster, egressTools, irreversibilityTier, irreversibleTools, reversibilityProbes } = input;
|
|
127
127
|
assertStringArraySeat(spec.additionalDirectories, "TaskSpec.additionalDirectories", "strings");
|
|
128
128
|
assertStringArraySeat(spec.additionalReadDirectories, "TaskSpec.additionalReadDirectories", "strings");
|
|
129
129
|
assertStringArraySeat(deps.readDenyPatterns, "RunnerDeps.readDenyPatterns", "compiler-owned");
|
|
@@ -328,7 +328,7 @@ export async function prepareHandsMount(input) {
|
|
|
328
328
|
if (verdict !== undefined && verdict.ok === false)
|
|
329
329
|
return verdict;
|
|
330
330
|
}
|
|
331
|
-
return
|
|
331
|
+
return memoryWriteGate?.(w);
|
|
332
332
|
},
|
|
333
333
|
mountBackgroundTaskTools: false,
|
|
334
334
|
monitorToolActive: backgroundTaskToolsActive && !(toolFaceSnapshot.exclude?.includes("Monitor") ?? false),
|
|
@@ -354,6 +354,7 @@ export async function prepareHandsMount(input) {
|
|
|
354
354
|
const shellReadBoundary = () => ({
|
|
355
355
|
roots: [rootCanonical, ...additionalRootsCanonical, ...additionalReadRootsCanonical],
|
|
356
356
|
...(handsCwdRef?.current !== undefined ? { cwd: handsCwdRef.current } : {}),
|
|
357
|
+
...(executionEnv.homeDir !== undefined ? { homeDir: executionEnv.homeDir } : {}),
|
|
357
358
|
denyMatch: (p) => readDenyMatcher?.matchPath(p)?.pattern ?? null,
|
|
358
359
|
...(resolvedReadFace !== undefined ? { face: resolvedReadFace } : {}),
|
|
359
360
|
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* freeze with its tighten-only intersection and the monotonic governed bit), the effective shellGate against the
|
|
6
6
|
* spec, the three cells later phases fill for the children's chain (own session rules, own admitted org scopes,
|
|
7
7
|
* own org verdict), the checkpoint-section closures the suspend serializer reads (face / org / F-012 stamps), the
|
|
8
|
-
* FROZEN ask and question seats (spec over deps), the two delegation refs the memory phase binds late, the ONE
|
|
8
|
+
* FROZEN ask and question seats (spec over deps), the parent SPEC seat the children inherit, the two delegation refs the memory phase binds late, the ONE
|
|
9
9
|
* child-chain assembly `inheritedGateForChildren`, the caller-tool ctx enrichment `enrichSpecToolCtx` shared by
|
|
10
10
|
* the roster wrap and the revival spawner, the denial-limit stop seat, and the full-shell reachability predicate.
|
|
11
11
|
* The interface is the dependency list the segment had implicitly.
|
|
@@ -36,6 +36,7 @@ import type { ReadFace } from "../../tools/fs/index.js";
|
|
|
36
36
|
import type { AutoModeArmingRecipe } from "../auto-mode-arming.js";
|
|
37
37
|
import type { AutoModeDecider, AutoModeDenialTracker } from "../auto-mode.js";
|
|
38
38
|
import { type OnQuestion } from "../ask-question.js";
|
|
39
|
+
import { type ParentSpecSeat } from "../parent-spec-seat.js";
|
|
39
40
|
import { type HookEnvCapabilities, type Hooks } from "../hooks.js";
|
|
40
41
|
import type { LockedPreflight } from "../locked-config.js";
|
|
41
42
|
import type { OwnOrgAdmissionVerdict } from "../memory-admission.js";
|
|
@@ -65,7 +66,7 @@ export interface PrepareInheritedGateInput {
|
|
|
65
66
|
/** borrowed-readonly — the trusted spawn-side channel: `inheritedGate` (the LIVE half of the chain fold), `ownOrgAdmissionRef`
|
|
66
67
|
* (the same-session continuation's freeze), `delegationProvenance` (the F-012 stamp), and the identity / peer / notification
|
|
67
68
|
* seats the ctx enrichment forwards. Never mutated. */
|
|
68
|
-
internals: Pick<RunInternals, "inheritedGate" | "ownOrgAdmissionRef" | "delegationProvenance" | "memoryCaptureAncestors" | "parentTaskId" | "parentSessionId" | "rootSessionId" | "placementRoot" | "explicitAgentName" | "peerSelfRef" | "peerInboundChainRef" | "onTaskNotification" | "onSubagentSpawn" | "insideFork"> | undefined;
|
|
69
|
+
internals: Pick<RunInternals, "inheritedGate" | "ownOrgAdmissionRef" | "delegationProvenance" | "memoryCaptureAncestors" | "parentTaskId" | "parentSessionId" | "rootSessionId" | "placementRoot" | "explicitAgentName" | "peerSelfRef" | "peerInboundChainRef" | "onTaskNotification" | "onSubagentSpawn" | "insideFork" | "questionFaceStripped"> | undefined;
|
|
69
70
|
/** borrowed-readonly — the resume leg, or undefined on a fresh one: `seed.inheritedGate` is the CHECKPOINT half of the chain
|
|
70
71
|
* fold (the trust floor the live half may only tighten), `seed.readFace` the hands-less re-park's carried section. */
|
|
71
72
|
resume: Pick<PrepareResume, "seed"> | undefined;
|
|
@@ -240,6 +241,8 @@ export interface PrepareInheritedGateResult {
|
|
|
240
241
|
notifyOwnHookCrash: (err: unknown) => void;
|
|
241
242
|
/** owned — the FROZEN question seat (spec over deps), the content-ask twin of `frozenOnAsk`. */
|
|
242
243
|
frozenOnQuestion: OnQuestion | undefined;
|
|
244
|
+
/** owned — the parent SPEC seat this run hands its children (`parentSpecSeatOf(spec, frozenOnQuestion)`): the ctx seat and the Workflow mount dep are this one value; both lanes apply it with `applyParentSpecSeat` (one law). */
|
|
245
|
+
parentSpecSeat: ParentSpecSeat;
|
|
243
246
|
/** borrowed-mutable — the delegation runtime-provenance arming face. Writer: the memory-engine-session phase
|
|
244
247
|
* (prepareMemoryEngineSession), once per leg when it arms. Read lazily by delegation tools through the ctx. */
|
|
245
248
|
provenanceForChildrenRef: {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { forkGovernanceDenial, resolveDelegationEntryCaps } from "../../agents/subagent.js";
|
|
2
2
|
import { isLiveQuestionFace } from "../ask-question.js";
|
|
3
|
+
import { parentSpecSeatOf } from "../parent-spec-seat.js";
|
|
3
4
|
import { createPreToolUseConstraintPolicy } from "../hooks.js";
|
|
4
5
|
import { StubExecutionEnv } from "../stub-env.js";
|
|
5
|
-
import { askApproverIdentity,
|
|
6
|
+
import { askApproverIdentity, durableMandateSourceOf } from "../tool-policy.js";
|
|
6
7
|
import { attachRebuiltDenialTrackers, createDenialLimitStop } from "./denial-limit-arms.js";
|
|
7
8
|
export function prepareInheritedGate(input) {
|
|
8
9
|
const { spec, deps, internals, resume, sessions, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, ownedEnv, lockedPreflight, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, autoModeSeat, handsEnabled, reportUsage, harnessRef, skillScope, forwardEvent, subagentRetain, worktreeIsolation, requestReview, requestStopAfterTurn, enterPlanMode, reminderMark, reminderDisclosureCounts, fileHistoryEnabled, historyScope, historyRoot, historyFs, abortRun } = input;
|
|
@@ -93,6 +94,7 @@ export function prepareInheritedGate(input) {
|
|
|
93
94
|
}
|
|
94
95
|
};
|
|
95
96
|
const frozenOnQuestion = spec.onQuestion ?? deps.onQuestion;
|
|
97
|
+
const parentSpecSeat = parentSpecSeatOf(spec, frozenOnQuestion);
|
|
96
98
|
const provenanceForChildrenRef = {};
|
|
97
99
|
const delegationProvenanceForChildren = () => provenanceForChildrenRef.current;
|
|
98
100
|
const delegationSettlementRef = {};
|
|
@@ -106,8 +108,7 @@ export function prepareInheritedGate(input) {
|
|
|
106
108
|
...(ownSessionRulesRef.current !== undefined ? [ownSessionRulesRef.current] : []),
|
|
107
109
|
];
|
|
108
110
|
const ownCallerPolicy = lockedPreflight.toolPolicy;
|
|
109
|
-
const durableMandate = input.runtimeCaps()?.forceDurableGate === true
|
|
110
|
-
(spec.durableApproval !== undefined && !isLiveApproverSeat(frozenOnAsk));
|
|
111
|
+
const durableMandate = durableMandateSourceOf({ forceDurableGate: input.runtimeCaps()?.forceDurableGate === true, durableApprovalDeclared: spec.durableApproval !== undefined, onAsk: frozenOnAsk }) !== undefined;
|
|
111
112
|
const contentMandate = input.runtimeCaps()?.forceDurableGate === true ||
|
|
112
113
|
(spec.durableApproval !== undefined && !isLiveQuestionFace(frozenOnQuestion));
|
|
113
114
|
const ownPreToolUse = input.preToolUseObservational() ? undefined : input.hooks()?.preToolUse;
|
|
@@ -186,15 +187,13 @@ export function prepareInheritedGate(input) {
|
|
|
186
187
|
...(readDenyAdditionsNormalized.length > 0 ? { readDenyPatterns: Object.freeze(readDenyAdditionsNormalized.map((e) => ({ ...e }))) } : {}),
|
|
187
188
|
...(spec.interactiveTools === false ? { interactiveTools: false } : {}),
|
|
188
189
|
oneShot: spec.oneShot,
|
|
189
|
-
|
|
190
|
+
parentSpecSeat,
|
|
191
|
+
...(internals?.questionFaceStripped === true ? { questionFaceStripped: true } : {}),
|
|
190
192
|
excludeTools: toolFaceSnapshot.exclude,
|
|
191
193
|
deferTools: toolFaceSnapshot.defer,
|
|
192
194
|
alwaysLoadTools: toolFaceSnapshot.alwaysLoad,
|
|
193
195
|
...(toolFaceSnapshot.restoreGated !== undefined ? { restoreGatedTools: toolFaceSnapshot.restoreGated } : {}),
|
|
194
196
|
promptProfile,
|
|
195
|
-
...(spec.additionalDirectories !== undefined ? { additionalDirectories: Object.freeze([...spec.additionalDirectories]) } : {}),
|
|
196
|
-
...(spec.additionalReadDirectories !== undefined ? { additionalReadDirectories: Object.freeze([...spec.additionalReadDirectories]) } : {}),
|
|
197
|
-
...(spec.envFacts !== undefined ? { envFacts: { ...spec.envFacts } } : {}),
|
|
198
197
|
...(spec.memoryPersistenceCapable !== undefined ? { memoryPersistenceCapable: spec.memoryPersistenceCapable } : {}),
|
|
199
198
|
get memoryCaptureOptedOut() {
|
|
200
199
|
return input.memoryEngineSession()?.captureOptOut?.optedOut() ?? false;
|
|
@@ -263,5 +262,5 @@ export function prepareInheritedGate(input) {
|
|
|
263
262
|
...(spec.enablePlanMode === true ? { enterPlanMode } : {}),
|
|
264
263
|
};
|
|
265
264
|
};
|
|
266
|
-
return { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, autoModeIntent, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx };
|
|
265
|
+
return { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, autoModeIntent, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, parentSpecSeat, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx };
|
|
267
266
|
}
|
|
@@ -18,12 +18,6 @@ export interface PrepareMemoryInput {
|
|
|
18
18
|
/** borrowed-readonly — the resolved task root: the containment boundary every derived memory dir
|
|
19
19
|
* is checked against, and the repo-root fallback when `deps.rootPath` is unset. */
|
|
20
20
|
taskRootPath: string;
|
|
21
|
-
/** borrowed-mutable — the caller's write-gate cell, and THIS phase is its writer: it installs the
|
|
22
|
-
* memory write gate into `.current` (the module header's one out-param effect). Identity is the
|
|
23
|
-
* contract — the caller's hands/read-face seat reads this exact cell. */
|
|
24
|
-
memoryWriteGateRef: {
|
|
25
|
-
current?: BeforeWriteHook;
|
|
26
|
-
};
|
|
27
21
|
/**
|
|
28
22
|
* borrowed-readonly — #181-F5: whether a tool NAMED `Write` (the tool the CC `# Memory` instruction names) is on the
|
|
29
23
|
* ASSEMBLED roster this run, not excluded, AND can actually REACH the host-side memory root:
|
|
@@ -199,6 +193,10 @@ export interface MemoryInjectionComposition {
|
|
|
199
193
|
export interface PrepareMemoryResult {
|
|
200
194
|
memoryEngineSession: Prepared["memoryEngineSession"];
|
|
201
195
|
memoryTools?: ToolSpec[];
|
|
196
|
+
/** owned — the memory WRITE gate (Write/Edit/NotebookEdit run their FINAL text through MemoryEngine.gateWrite when
|
|
197
|
+
* the target lands inside the memory writable root; the read-only plane refuses its own domain). Present iff a memory
|
|
198
|
+
* engine mounted; the hands phase composes it into the band's beforeWrite (a memory-less run: every write passes). */
|
|
199
|
+
memoryWriteGate?: BeforeWriteHook;
|
|
202
200
|
/**
|
|
203
201
|
* owned — #691: the injection's COMPOSITION step, run by the driver AFTER the hands phase (the mount above runs
|
|
204
202
|
* BEFORE it). It performs the one destructive read this phase has — `inject()` drains the announcement queue —
|
|
@@ -13,7 +13,8 @@ import { FileMemoryEngineBackend } from "../memory-engine/file-backend.js";
|
|
|
13
13
|
import { writableRootOf } from "../memory-engine/types.js";
|
|
14
14
|
let undeclaredCapturePostureAnnounced = false;
|
|
15
15
|
export async function prepareMemory(input) {
|
|
16
|
-
const { spec, deps, sessionId, taskRootPath,
|
|
16
|
+
const { spec, deps, sessionId, taskRootPath, admissionCtx } = input;
|
|
17
|
+
let memoryWriteGate;
|
|
17
18
|
const memorySpec = normalizeMemorySpec(spec.memory);
|
|
18
19
|
let admittedOrgScopes = [];
|
|
19
20
|
let ownOrgVerdict;
|
|
@@ -473,7 +474,7 @@ export async function prepareMemory(input) {
|
|
|
473
474
|
writeHandle.writeScope !== null &&
|
|
474
475
|
foreignUnderRoot.length === 0 &&
|
|
475
476
|
(input.advertisedWritableDirs === undefined || (await input.advertisedWritableDirs.admit({ path: writableRootOf(writeHandle), advertiser: "memory", expectCanonical: writableRootOf(writeHandle) })));
|
|
476
|
-
|
|
477
|
+
memoryWriteGate = async (w) => {
|
|
477
478
|
if (readOnlyEngine !== undefined && readOnlyHandle !== undefined) {
|
|
478
479
|
const ro = readOnlyEngine.gateWrite(readOnlyHandle, w.key, w.content);
|
|
479
480
|
if (!ro.ok)
|
|
@@ -776,6 +777,7 @@ export async function prepareMemory(input) {
|
|
|
776
777
|
ownOrgVerdict,
|
|
777
778
|
effectiveMemoryScopes,
|
|
778
779
|
...(memoryTools !== undefined ? { memoryTools } : {}),
|
|
780
|
+
...(memoryWriteGate !== undefined ? { memoryWriteGate } : {}),
|
|
779
781
|
composeInjection,
|
|
780
782
|
};
|
|
781
783
|
}
|
|
@@ -75,9 +75,9 @@ export interface PreparePolicyChainInput {
|
|
|
75
75
|
irreversible?: false;
|
|
76
76
|
egress?: false;
|
|
77
77
|
}>;
|
|
78
|
-
/** borrowed-readonly — the
|
|
79
|
-
*
|
|
80
|
-
|
|
78
|
+
/** borrowed-readonly — the ENGINE HAND roster: every tool whose effect dispatches through the task's execution env,
|
|
79
|
+
* membership minted at the mount sites (the sandbox boundary predicate's one containment fact). */
|
|
80
|
+
envHandToolNames: ReadonlySet<string>;
|
|
81
81
|
/** borrowed-readonly — the shell-seat provenance set (the offer factory's `shellGated` mandate term, read per call). */
|
|
82
82
|
shellGatedTools: ReadonlySet<string>;
|
|
83
83
|
/** borrowed-readonly — the tracked-cwd seat, read per call by the lanes and the offer factory (never written here). */
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { SEND_MESSAGE_TOOL_NAME } from "../../agents/send-message-tool.js";
|
|
2
1
|
import { policyAskClassOf } from "../ask-class.js";
|
|
3
2
|
import { ASK_USER_QUESTION_TOOL_NAME } from "../ask-question.js";
|
|
4
3
|
import { resolveCheckpointStore } from "../checkpoint-store.js";
|
|
5
4
|
import { cloneObserverInput, resolveHookTimeoutMs } from "../hooks.js";
|
|
6
5
|
import { isNamespacedCoveringRuleName, namespacedRuleNameCovers } from "../permission-rules.js";
|
|
7
6
|
import { isIsolated } from "../remote-env.js";
|
|
8
|
-
import { askApproverIdentity, carryEngineAttestations, carryPrecedingSettlement, checkToolPolicyProjection, combinePolicies, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, isLiveApproverSeat, resolveAsk, toolPolicyNameSets } from "../tool-policy.js";
|
|
7
|
+
import { askApproverIdentity, carryEngineAttestations, carryPrecedingSettlement, checkToolPolicyProjection, combinePolicies, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, isLiveApproverSeat, resolveAsk, toolPolicyNameSets, attestAskUnresolvableCause } from "../tool-policy.js";
|
|
9
8
|
import { RETIRED_TOOL_NAMES } from "../tool-name-aliases.js";
|
|
10
9
|
import { NAMESPACED_NAME_SHAPES, protocolOf } from "../protocol-table.js";
|
|
11
10
|
import { emitTrace } from "../trace.js";
|
|
@@ -16,7 +15,7 @@ import { askGrantShapeOf } from "./inherited-ask-grants.js";
|
|
|
16
15
|
import { createPermissionRuleLanes, inheritedAskRuleEvidence, createRuleOffersOf } from "./permission-rule-lanes.js";
|
|
17
16
|
import { createSessionRulePolicy } from "./session-rule-policy.js";
|
|
18
17
|
export async function preparePolicyChain(input) {
|
|
19
|
-
const { spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, lockedPreflight, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives,
|
|
18
|
+
const { spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, lockedPreflight, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives, shellGatedTools, envHandToolNames, handsCwdRef, readDenyMatcher, questionToolMounted, runtimeCaps, inheritedAncestorRules, inheritedParentConstraints, seedInheritedGate, hasSkillManifest, skillScope, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, autoModeDecider, stopForDenialLimit, delegation, abortController, now, ownSessionRulesRef } = input;
|
|
20
19
|
const policy = lockedPreflight.toolPolicy;
|
|
21
20
|
const auditPolicyNames = (auditee) => {
|
|
22
21
|
const nameGroups = toolPolicyNameSets(auditee);
|
|
@@ -144,6 +143,12 @@ export async function preparePolicyChain(input) {
|
|
|
144
143
|
inheritedUnavailableAsks.add(toolCallId);
|
|
145
144
|
return true;
|
|
146
145
|
};
|
|
146
|
+
const mandatedCallFloats = (toolCallId) => resolveCheckpointStore(spec, deps) !== undefined && (spec.durableApproval !== undefined || runtimeCaps?.forceDurableGate === true) && markInheritedUnavailable(toolCallId);
|
|
147
|
+
const mandateUnreconstructibleDeny = (creq) => attestAskUnresolvableCause({
|
|
148
|
+
action: "deny",
|
|
149
|
+
message: `inherited parent policy requires durable approval for "${creq.toolName}" — the parent's durable ask cannot be reconstructed in a delegated child; denied fail-closed (tighten-only)`,
|
|
150
|
+
}, "mandate_unreconstructible", creq);
|
|
151
|
+
const markerChannelFullDeny = (creq) => attestAskUnresolvableCause({ action: "deny", message: `no approver is reachable for the inherited approval of "${creq.toolName}" and the marker channel is at capacity — denied fail-closed` }, "approver_unavailable", creq);
|
|
147
152
|
const inheritedAskGrants = new Map();
|
|
148
153
|
const recordInheritedAskGrant = (toolCallId, approver, presented, waitMs) => {
|
|
149
154
|
if (typeof approver !== "function")
|
|
@@ -190,7 +195,7 @@ export async function preparePolicyChain(input) {
|
|
|
190
195
|
list.push({ cls, layer });
|
|
191
196
|
foldAskClasses.set(toolCallId, list);
|
|
192
197
|
};
|
|
193
|
-
const sandboxBoundaryCapable = (toolName) => egressTools.has(toolName) ||
|
|
198
|
+
const sandboxBoundaryCapable = (toolName) => egressTools.has(toolName) || !envHandToolNames.has(toolName);
|
|
194
199
|
const emitSandboxAdmitted = (info) => {
|
|
195
200
|
emitTrace(deps.tracer, () => ({
|
|
196
201
|
kind: "permission.sandbox_admitted",
|
|
@@ -358,16 +363,9 @@ export async function preparePolicyChain(input) {
|
|
|
358
363
|
};
|
|
359
364
|
}
|
|
360
365
|
if (pc.durableMandate === true) {
|
|
361
|
-
if (
|
|
362
|
-
(spec.durableApproval !== undefined || runtimeCaps?.forceDurableGate === true) &&
|
|
363
|
-
markInheritedUnavailable(creq.toolCallId)) {
|
|
366
|
+
if (mandatedCallFloats(creq.toolCallId))
|
|
364
367
|
return first;
|
|
365
|
-
|
|
366
|
-
return {
|
|
367
|
-
action: "deny",
|
|
368
|
-
message: `inherited parent policy requires durable approval for "${creq.toolName}" — the parent's durable ` +
|
|
369
|
-
`ask cannot be reconstructed in a delegated child; denied fail-closed (tighten-only)`,
|
|
370
|
-
};
|
|
368
|
+
return mandateUnreconstructibleDeny(creq);
|
|
371
369
|
}
|
|
372
370
|
const judged = await judgeInheritedClassifier({ autoMode: pc.autoMode, ask: first, req: creq, signal: csignal ?? abortController.signal, subject: "this call" });
|
|
373
371
|
if (judged.kind === "allow")
|
|
@@ -398,10 +396,7 @@ export async function preparePolicyChain(input) {
|
|
|
398
396
|
if (resolved.action === "deny" && resolved.approverUnavailable === true) {
|
|
399
397
|
if (markInheritedUnavailable(creq.toolCallId))
|
|
400
398
|
return inheritedAsk;
|
|
401
|
-
return
|
|
402
|
-
action: "deny",
|
|
403
|
-
message: `no approver is reachable for the inherited approval of "${creq.toolName}" and the marker channel is at capacity — denied fail-closed`,
|
|
404
|
-
};
|
|
399
|
+
return markerChannelFullDeny(creq);
|
|
405
400
|
}
|
|
406
401
|
settleDenialLimitFallback({ fallback, mintedHere, tracker: pc.autoMode?.denialTracking, resolved, headless: headlessDenyAtFold, stop: stopForDenialLimit, toolName: creq.toolName, toolCallId: creq.toolCallId });
|
|
407
402
|
if (resolved.action !== "allow")
|
|
@@ -437,16 +432,9 @@ export async function preparePolicyChain(input) {
|
|
|
437
432
|
};
|
|
438
433
|
}
|
|
439
434
|
if (pc.durableMandate === true) {
|
|
440
|
-
if (
|
|
441
|
-
(spec.durableApproval !== undefined || runtimeCaps?.forceDurableGate === true) &&
|
|
442
|
-
markInheritedUnavailable(creq.toolCallId)) {
|
|
435
|
+
if (mandatedCallFloats(creq.toolCallId))
|
|
443
436
|
return decision;
|
|
444
|
-
|
|
445
|
-
return {
|
|
446
|
-
action: "deny",
|
|
447
|
-
message: `inherited parent policy requires durable approval for "${creq.toolName}" — the parent's durable ` +
|
|
448
|
-
`ask cannot be reconstructed in a delegated child; denied fail-closed (tighten-only)`,
|
|
449
|
-
};
|
|
437
|
+
return mandateUnreconstructibleDeny(creq);
|
|
450
438
|
}
|
|
451
439
|
const presentedArgs = decision.updatedInput !== undefined ? decision.updatedInput : creq.args;
|
|
452
440
|
const judged = await judgeInheritedClassifier({ autoMode: pc.autoMode, ask: decision, req: { ...creq, args: presentedArgs }, signal: csignal ?? abortController.signal, subject: "this call" });
|
|
@@ -477,10 +465,7 @@ export async function preparePolicyChain(input) {
|
|
|
477
465
|
if (resolved.action === "deny" && resolved.approverUnavailable === true) {
|
|
478
466
|
if (markInheritedUnavailable(creq.toolCallId))
|
|
479
467
|
return inheritedAsk;
|
|
480
|
-
return
|
|
481
|
-
action: "deny",
|
|
482
|
-
message: `no approver is reachable for the inherited approval of "${creq.toolName}" and the marker channel is at capacity — denied fail-closed`,
|
|
483
|
-
};
|
|
468
|
+
return markerChannelFullDeny(creq);
|
|
484
469
|
}
|
|
485
470
|
settleDenialLimitFallback({ fallback, mintedHere, tracker: pc.autoMode?.denialTracking, resolved, headless: headlessDenyAtFold, stop: stopForDenialLimit, toolName: creq.toolName, toolCallId: creq.toolCallId });
|
|
486
471
|
if (resolved.action !== "allow")
|
|
@@ -95,7 +95,7 @@ export async function preparePromptAssembly(input) {
|
|
|
95
95
|
}
|
|
96
96
|
: undefined;
|
|
97
97
|
const promptConstitution = assembled.constitution;
|
|
98
|
-
const promptBlocks = assembled.
|
|
98
|
+
const promptBlocks = assembled.blocks;
|
|
99
99
|
const collisionAudit = auditToolCollisions(tools);
|
|
100
100
|
for (const y of collisionAudit.yields) {
|
|
101
101
|
onceLedger.onError(new Error(`tool mount: caller tool "${y.name}" shadows another tool with the same canonical name (deliberate last-write-wins yield — the later mount serves)`), { phase: "config", sessionId });
|
|
@@ -12,7 +12,7 @@ export interface PrepareSafetyScanInput {
|
|
|
12
12
|
* The scan's outputs. Ownership annotations (four-class form):
|
|
13
13
|
*
|
|
14
14
|
* `ownToolNames` is **borrowed-readonly** — a first-await snapshot with no mutation anywhere after
|
|
15
|
-
* the scan
|
|
15
|
+
* the scan (sandbox containment reads the env-hand roster, not this set).
|
|
16
16
|
*
|
|
17
17
|
* The six collections are **borrowed-mutable**: the driver and later phases fold into them IN
|
|
18
18
|
* PLACE (identity is part of the contract — closures alias these exact objects). Mutation owners
|
|
@@ -106,7 +106,6 @@ export function prepareSuspendSaga(input) {
|
|
|
106
106
|
activeTools: [...activeTools],
|
|
107
107
|
outputRef: { value: outputRef.value, set: outputRef.set },
|
|
108
108
|
nestedStats: { ...nestedStats },
|
|
109
|
-
consolidationNotes: undefined,
|
|
110
109
|
readFileState: readFileStateForCheckpoint ? [...readFileStateForCheckpoint.entries()] : undefined,
|
|
111
110
|
readFace: faceCheckpointSection(),
|
|
112
111
|
reminderMark,
|
|
@@ -121,7 +120,6 @@ export function prepareSuspendSaga(input) {
|
|
|
121
120
|
.map((t) => ({ id: t.task_id, ...(t.description !== undefined ? { description: t.description } : {}) }));
|
|
122
121
|
return live.length > 0 ? live : undefined;
|
|
123
122
|
})(),
|
|
124
|
-
pendingSteer: undefined,
|
|
125
123
|
pendingSteerQueue: undefined,
|
|
126
124
|
inheritedGate: (() => {
|
|
127
125
|
const requiresParentConstraint = (inheritedParentConstraints?.length ?? 0) > 0 || seedInheritedGate?.requiresParentConstraint === true;
|