@sema-agent/core 7.5.1 → 7.6.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 +61 -0
- package/dist/agents/cascade.d.ts +2 -2
- package/dist/agents/cascade.js +12 -10
- package/dist/agents/repair-loop.d.ts +5 -3
- package/dist/agents/repair-loop.js +13 -15
- package/dist/agents/subagent.d.ts +24 -42
- package/dist/agents/subagent.js +119 -105
- package/dist/agents/suspend-guard.d.ts +31 -19
- package/dist/agents/suspend-guard.js +14 -8
- package/dist/agents/teacher.js +9 -9
- package/dist/agents/team.d.ts +4 -3
- package/dist/agents/team.js +10 -8
- package/dist/agents/verify.d.ts +3 -3
- package/dist/agents/verify.js +17 -17
- package/dist/core/a2a.js +2 -1
- package/dist/core/ask-origin.d.ts +60 -7
- package/dist/core/ask-origin.js +26 -1
- package/dist/core/checkpoint-store.d.ts +78 -76
- package/dist/core/checkpoint-store.js +17 -1
- package/dist/core/gate-outcome.d.ts +189 -0
- package/dist/core/gate-outcome.js +70 -0
- package/dist/core/hooks.d.ts +18 -92
- package/dist/core/hooks.js +88 -85
- package/dist/core/mcp-failure.d.ts +104 -0
- package/dist/core/mcp-failure.js +128 -0
- package/dist/core/mcp.d.ts +21 -77
- package/dist/core/mcp.js +76 -150
- package/dist/core/pause-registry.d.ts +131 -0
- package/dist/core/pause-registry.js +27 -0
- package/dist/core/protocol-table.d.ts +5 -0
- package/dist/core/protocol-table.js +1 -0
- package/dist/core/runner/abort-race.d.ts +41 -0
- package/dist/core/runner/abort-race.js +38 -0
- package/dist/core/runner/assemble-result.d.ts +32 -41
- package/dist/core/runner/assemble-result.js +55 -74
- package/dist/core/runner/checkpoint-scope.d.ts +15 -3
- package/dist/core/runner/checkpoint-scope.js +3 -0
- package/dist/core/runner/compaction-call-options.d.ts +1 -1
- package/dist/core/runner/content-ask-bindings.d.ts +27 -0
- package/dist/core/runner/content-ask-bindings.js +1 -0
- package/dist/core/runner/contracts.d.ts +144 -50
- package/dist/core/runner/denial-limit-arms.d.ts +24 -1
- package/dist/core/runner/denial-limit-arms.js +24 -3
- package/dist/core/runner/gate-exit.d.ts +74 -0
- package/dist/core/runner/gate-exit.js +55 -0
- package/dist/core/runner/inherited-ask-grants.d.ts +46 -0
- package/dist/core/runner/inherited-ask-grants.js +29 -0
- package/dist/core/runner/park-commit.d.ts +102 -0
- package/dist/core/runner/park-commit.js +31 -0
- package/dist/core/runner/{prepare-permission-rules.d.ts → permission-rule-lanes.d.ts} +109 -3
- package/dist/core/runner/{prepare-permission-rules.js → permission-rule-lanes.js} +47 -1
- package/dist/core/runner/prepare-ask-lane.d.ts +107 -0
- package/dist/core/runner/prepare-ask-lane.js +131 -0
- package/dist/core/runner/prepare-boundary-parks.d.ts +102 -0
- package/dist/core/runner/prepare-boundary-parks.js +169 -0
- package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
- package/dist/core/runner/prepare-context-lane.d.ts +119 -0
- package/dist/core/runner/prepare-context-lane.js +230 -0
- package/dist/core/runner/prepare-gate-stations.d.ts +174 -0
- package/dist/core/runner/prepare-gate-stations.js +265 -0
- package/dist/core/runner/prepare-hands-readface.d.ts +4 -4
- package/dist/core/runner/prepare-inherited-gate.d.ts +4 -4
- package/dist/core/runner/prepare-inherited-gate.js +1 -1
- package/dist/core/runner/prepare-memory-engine-session.d.ts +84 -0
- package/dist/core/runner/prepare-memory-engine-session.js +233 -0
- package/dist/core/runner/prepare-memory.d.ts +44 -26
- package/dist/core/runner/prepare-park-ask.d.ts +162 -0
- package/dist/core/runner/prepare-park-ask.js +377 -0
- package/dist/core/runner/prepare-policy-chain.d.ts +208 -0
- package/dist/core/runner/prepare-policy-chain.js +584 -0
- package/dist/core/runner/prepare-project-context.d.ts +1 -13
- package/dist/core/runner/prepare-project-context.js +1 -3
- package/dist/core/runner/prepare-prompt-assembly.d.ts +95 -0
- package/dist/core/runner/prepare-prompt-assembly.js +162 -0
- package/dist/core/runner/prepare-prompt-inputs.d.ts +1 -20
- package/dist/core/runner/prepare-protocol-tools.d.ts +3 -3
- package/dist/core/runner/prepare-protocol-tools.js +0 -3
- package/dist/core/runner/prepare-question-face.d.ts +3 -21
- package/dist/core/runner/prepare-question-face.js +2 -1
- package/dist/core/runner/prepare-safety-scan.d.ts +0 -5
- package/dist/core/runner/prepare-safety-scan.js +1 -2
- package/dist/core/runner/prepare-suspend-saga.d.ts +170 -0
- package/dist/core/runner/prepare-suspend-saga.js +308 -0
- package/dist/core/runner/prepare-task.d.ts +9 -136
- package/dist/core/runner/prepare-task.js +47 -2745
- package/dist/core/runner/prepare-turn-wiring.d.ts +154 -0
- package/dist/core/runner/prepare-turn-wiring.js +201 -0
- package/dist/core/runner/prepare-wiring-manifest.d.ts +17 -17
- package/dist/core/runner/prepare-wiring-manifest.js +16 -10
- package/dist/core/runner/prepare-workspace-restore.d.ts +2 -29
- package/dist/core/runner/prepare-workspace-restore.js +3 -16
- package/dist/core/runner/prompt-hash-salt.d.ts +1 -0
- package/dist/core/runner/prompt-hash-salt.js +2 -0
- package/dist/core/runner/remote-env-retry.d.ts +29 -0
- package/dist/core/runner/remote-env-retry.js +16 -0
- package/dist/core/runner/runtask.d.ts +16 -31
- package/dist/core/runner/runtask.js +110 -121
- package/dist/core/runner/terminal-projection.d.ts +22 -0
- package/dist/core/runner/terminal-projection.js +28 -0
- package/dist/core/session.d.ts +12 -0
- package/dist/core/session.js +3 -0
- package/dist/core/store-contracts/checkpoint-store-contract.d.ts +4 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +8 -2
- package/dist/core/terminal-cause.d.ts +137 -0
- package/dist/core/terminal-cause.js +9 -0
- package/dist/core/tool-policy.d.ts +43 -139
- package/dist/core/tool-policy.js +79 -112
- package/dist/core/types.d.ts +67 -164
- package/dist/core/wiring-manifest.d.ts +6 -3
- package/dist/core/workflow-journal-store.js +3 -4
- package/dist/engine/harness/agent-harness.d.ts +1 -1
- package/dist/index.d.ts +10 -7
- package/dist/index.js +8 -5
- package/dist/orchestration/builtin-workflows.d.ts +2 -2
- package/dist/orchestration/builtin-workflows.js +1 -1
- package/dist/orchestration/goal.js +8 -7
- package/dist/orchestration/run-spec.js +5 -3
- package/dist/orchestration/run-workflow-tool.d.ts +1 -1
- package/dist/orchestration/run-workflow-tool.js +4 -4
- package/dist/orchestration/workflow-governance.d.ts +4 -4
- package/dist/orchestration/workflow-governance.js +4 -2
- package/dist/orchestration/workflow-primitives.d.ts +1 -1
- package/dist/orchestration/workflow-primitives.js +1 -1
- package/dist/orchestration/workflow.d.ts +11 -0
- package/dist/orchestration/workflow.js +64 -39
- package/dist/prompts/supervisor.d.ts +1 -1
- package/dist/prompts/supervisor.js +3 -3
- package/dist/scenarios/scenario-registry.js +1 -1
- package/package.json +3 -1
- package/test/export-surface.snapshot.json +74 -22
- /package/dist/core/runner/{prepare-announce-once.d.ts → announce-once-ledger.d.ts} +0 -0
- /package/dist/core/runner/{prepare-announce-once.js → announce-once-ledger.js} +0 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/390 §1.2 M20 — prepareTask's two GATE STATIONS, verbatim from the driver: the `tool_call` station (the final-roster
|
|
3
|
+
* effect sync, the write-protection judge compiled once per task, the arming predicate, the compliance and plan-mode
|
|
4
|
+
* short-circuits, the `runToolGate` call with every seat it is handed, the lifecycle sweep, the deferred sandbox-admission
|
|
5
|
+
* disclosure, the PreToolUse context stash, the settlement sideband write and the bare-human-rejection boundary) and the
|
|
6
|
+
* `tool_result` station (the PostToolUse / PostToolUseFailure seats and the PreToolUse context drain). The two module-scope
|
|
7
|
+
* helpers only these stations called moved with them (the settlement screen, the rejection-boundary judgment). The
|
|
8
|
+
* interface is the dependency list the stations had implicitly (design/238 R-1).
|
|
9
|
+
*
|
|
10
|
+
* The stations REGISTER handlers on the harness (the side effect this phase exists for) and report only two observation
|
|
11
|
+
* seats back; the order they register in — after the file-history boundary lease the driver registers, and in this order
|
|
12
|
+
* (call before result) — is the order handlers run in.
|
|
13
|
+
*
|
|
14
|
+
* SYNCHRONOUS FUNCTION, SYNCHRONOUS CALL: the stretch has no await of its own (the handlers run per tool call / per tool
|
|
15
|
+
* result), so the phase adds no yield between the park closure before it and the context lane after it (design/390 §1.5).
|
|
16
|
+
* Read-stability of the host handles for the call: {@link RunInternals} (`@contract prepare.deps-read-stable`).
|
|
17
|
+
*
|
|
18
|
+
* The `tool_call` station is built exactly when the ask lane and the park closure are (the same predicate as the whole
|
|
19
|
+
* gate-machinery block, kept as the block's one guard here); the `tool_result` station keys off the hook record alone, as
|
|
20
|
+
* it always did.
|
|
21
|
+
*
|
|
22
|
+
* Every station this file holds is a `denySource` / settlement WRITE site the decomposition's next slice maps onto one
|
|
23
|
+
* gate outcome; nothing here changes a word, a source or an order — the stations are moved, not re-adjudicated.
|
|
24
|
+
*/
|
|
25
|
+
import type { AgentHarness, AgentTool } from "../../internal/harness.js";
|
|
26
|
+
import type { AskClass } from "../ask-class.js";
|
|
27
|
+
import type { AutoModeDecider, AutoModeDenialTracker } from "../auto-mode.js";
|
|
28
|
+
import { type ComplianceCapability } from "../compliance.js";
|
|
29
|
+
import { type HookEnvCapabilities, type HookInvocationIdentity, type Hooks } from "../hooks.js";
|
|
30
|
+
import type { ToolPolicy } from "../tool-policy.js";
|
|
31
|
+
import type { RunnerDeps, TaskSpec, ToolEffect } from "../types.js";
|
|
32
|
+
import type { CwdRef } from "../../tools/fs/fs-shared.js";
|
|
33
|
+
import type { AskLane, IrreversibilityTier, ParkAsk, Prepared, ReversibilityProbes } from "./contracts.js";
|
|
34
|
+
import type { StopForDenialLimit } from "./denial-limit-arms.js";
|
|
35
|
+
import type { PermissionRuleLanes } from "./permission-rule-lanes.js";
|
|
36
|
+
export interface PrepareGateStationsInput {
|
|
37
|
+
/** borrowed-readonly — the in-stream ask lane, or undefined when the gate machinery is inactive (then no `tool_call`
|
|
38
|
+
* station is built). Read: `adjudicate`, `resolveAskBound`, `notifyPermissionDenied`, `notifyHookError`. */
|
|
39
|
+
askLane: AskLane | undefined;
|
|
40
|
+
/** borrowed-readonly — the park closure and the content-ask routing closure, or undefined (same law). Handed to the gate. */
|
|
41
|
+
parkAsk: ParkAsk | undefined;
|
|
42
|
+
/** borrowed-readonly — the FINAL mount roster: iterated once for the effect sync and the write-protection arming. Never
|
|
43
|
+
* mutated here. */
|
|
44
|
+
tools: AgentTool[];
|
|
45
|
+
/** borrowed-mutable — the effect collection. Writer here: the final-roster sync fills MISSING entries from each
|
|
46
|
+
* first-party tool's declared effect (never overrides a scanned one); the plan-mode deny reads it per call. */
|
|
47
|
+
toolEffects: Map<string, ToolEffect>;
|
|
48
|
+
/** borrowed-readonly — the deployment seats these stations read, as a Pick over the SAME `deps` object (receiver
|
|
49
|
+
* preserved for `deps.onError?.()`): the write-protection table and its data root, the tracer, the error face. */
|
|
50
|
+
deps: Pick<RunnerDeps, "writeProtectedPaths" | "memoryEngineDir" | "tracer" | "onError">;
|
|
51
|
+
/** borrowed-mutable — the protocol-tools phase's arming belt. Writer here: `armed` ← the registration predicate, the
|
|
52
|
+
* one write; the refresh seam reads it. */
|
|
53
|
+
toolCallGateArmedRef: {
|
|
54
|
+
armed: boolean;
|
|
55
|
+
};
|
|
56
|
+
/** borrowed-readonly — the policy chain's effective policy, or undefined; presence only (the arming predicate). */
|
|
57
|
+
effectivePolicy: ToolPolicy | undefined;
|
|
58
|
+
/** borrowed-readonly — the resolved hook record: `preToolUse` presence (arming), the two post seats and the failure seat
|
|
59
|
+
* (the `tool_result` station), called through the record so a class-instance keeps its receiver. */
|
|
60
|
+
hooks: Hooks | undefined;
|
|
61
|
+
/** borrowed-readonly — the egress vocabulary: arming, and the per-call `egress` flag handed to the gate. */
|
|
62
|
+
egressTools: ReadonlySet<string>;
|
|
63
|
+
/** borrowed-readonly — the irreversible vocabulary: arming only. */
|
|
64
|
+
irreversibleTools: ReadonlySet<string>;
|
|
65
|
+
/** borrowed-readonly — the REBOUND spec: `enablePlanMode` (arming) and `signal` (the failure seat's interrupt fact). */
|
|
66
|
+
spec: Pick<TaskSpec, "enablePlanMode" | "signal">;
|
|
67
|
+
/** borrowed-readonly — the compliance denials (the web_fetch veto's call-time lock, and its arming term). */
|
|
68
|
+
complianceDenies: ReadonlySet<ComplianceCapability>;
|
|
69
|
+
/** borrowed-mutable — the built harness. Writer here: `on("tool_call")` / `on("tool_result")` — the registrations this
|
|
70
|
+
* phase exists for, in this order, after the driver's boundary-lease handler. */
|
|
71
|
+
harness: Pick<AgentHarness, "on">;
|
|
72
|
+
/** borrowed-mutable — the blocked/suspended call ids (`Prepared.blockedToolCalls`). Writers here: the head-of-evaluation
|
|
73
|
+
* hygiene `delete`, the two short-circuits' and the gate outcome's `add`, the `tool_result` station's one-shot `delete`. */
|
|
74
|
+
blockedToolCalls: Set<string>;
|
|
75
|
+
/** borrowed-mutable — the duplicate-frame ask-grant record. Writer here: the head-of-evaluation and lifecycle-end `delete`. */
|
|
76
|
+
inheritedAskGrants: Map<string, unknown>;
|
|
77
|
+
/** borrowed-mutable — the inherited-unavailable marker set. Writer here: the lifecycle-end `delete`; `has` is handed to
|
|
78
|
+
* the gate as the read-only `isMarkedUnresolvable`. */
|
|
79
|
+
inheritedUnavailableAsks: Set<string>;
|
|
80
|
+
/** borrowed-mutable — the per-call ask-class record the sandbox admission reads. Writer here: the lifecycle-end `delete`. */
|
|
81
|
+
foldAskClasses: Map<string, Array<{
|
|
82
|
+
cls: AskClass;
|
|
83
|
+
layer: string;
|
|
84
|
+
}>>;
|
|
85
|
+
/** borrowed-mutable — the deferred ancestor sandbox admissions. Writer here: the unconditional read-and-`delete` after the
|
|
86
|
+
* fold settles. */
|
|
87
|
+
ancestorSandboxAdmissions: Map<string, Array<{
|
|
88
|
+
cls: AskClass;
|
|
89
|
+
layer: string;
|
|
90
|
+
}>>;
|
|
91
|
+
/** borrowed-mutable — PreToolUse `additionalContext` per call id. Writers here: the `tool_call` station's stash (`set`, only
|
|
92
|
+
* for calls that will execute) and the `tool_result` station's one-shot drain (`delete`). */
|
|
93
|
+
preToolContexts: Map<string, string[]>;
|
|
94
|
+
/** borrowed-mutable — the gate-outcome sideband (`Prepared.gateOutcomes`). Writer here: the single screened write per
|
|
95
|
+
* gated call (the two short-circuits and the gate's terminal exits); the frame mint reads and deletes. */
|
|
96
|
+
gateOutcomes: Prepared["gateOutcomes"];
|
|
97
|
+
/** borrowed-mutable — the turn halt fact (`Prepared.batchHaltRef`). Writer here: the bare-rejection boundary (`current`). */
|
|
98
|
+
batchHaltRef: Prepared["batchHaltRef"];
|
|
99
|
+
/** borrowed-readonly — whether blocked/suspended ids are tracked at all (the post-tool callbacks exist). */
|
|
100
|
+
blockedTracked: boolean;
|
|
101
|
+
/** borrowed-readonly — the leg's identity envelope every HookToolContext and PermissionDeniedPayload carries. */
|
|
102
|
+
hookIdentity: HookInvocationIdentity;
|
|
103
|
+
/** borrowed-readonly — the leg's reminder provenance mark (every model-facing deny reason and hook context carries it). */
|
|
104
|
+
reminderMark: string;
|
|
105
|
+
/** borrowed-readonly — the plan-mode latch (`Prepared.planModeRef`); `active` is read per call. Not written here. */
|
|
106
|
+
planModeRef: Prepared["planModeRef"];
|
|
107
|
+
/** borrowed-readonly — the per-task identity (the trace rows' taskId). */
|
|
108
|
+
hostTaskId: string;
|
|
109
|
+
/** borrowed-readonly — the acquired session id (the settlement defects' error tag). */
|
|
110
|
+
sessionId: string;
|
|
111
|
+
/** borrowed-readonly — the screening face as the gate must see it (the observational wrapper or the face itself). */
|
|
112
|
+
ownGatePreToolUse: Hooks["preToolUse"] | undefined;
|
|
113
|
+
/** borrowed-readonly — the validated per-prepare hook seat bound. */
|
|
114
|
+
hookTimeoutMs: number;
|
|
115
|
+
/** borrowed-readonly — the hand's live tracked cwd, or undefined; `current` is read per screening / per post seat. Not
|
|
116
|
+
* written here. */
|
|
117
|
+
handsCwdRef: CwdRef | undefined;
|
|
118
|
+
/** borrowed-readonly — the read-only env capability face every hook context carries, or undefined. */
|
|
119
|
+
hookEnvFace: HookEnvCapabilities | undefined;
|
|
120
|
+
/** borrowed-readonly — the per-tool irreversibility tier handed to the gate per call. */
|
|
121
|
+
irreversibilityTier: IrreversibilityTier;
|
|
122
|
+
/** borrowed-readonly — the per-tool reversibility probes handed to the gate per call. */
|
|
123
|
+
reversibilityProbes: ReversibilityProbes;
|
|
124
|
+
/** borrowed-readonly — prepare's abort seat; only `.signal` is read (the gate's probe bound, the post seats' bound, the
|
|
125
|
+
* failure seat's interrupt fact). */
|
|
126
|
+
abortController: {
|
|
127
|
+
readonly signal: AbortSignal;
|
|
128
|
+
};
|
|
129
|
+
/** borrowed-readonly — whether Bash is coarsely shell-gated (the gate's `shellGated` attribution). */
|
|
130
|
+
shellGatedBash: boolean;
|
|
131
|
+
/** borrowed-readonly — whether Monitor is coarsely shell-gated (same). */
|
|
132
|
+
shellGatedMonitor: boolean;
|
|
133
|
+
/** borrowed-readonly — the auto-mode decider, or undefined (the classifier lane the gate routes a surviving ask through). */
|
|
134
|
+
autoModeDecider: AutoModeDecider | undefined;
|
|
135
|
+
/** borrowed-readonly — the auto-mode denial tracker, or undefined (handed to the gate beside the decider). */
|
|
136
|
+
autoModeDenialTracking: AutoModeDenialTracker | undefined;
|
|
137
|
+
/** borrowed-readonly — the headless denial-limit stop seat (wired unconditionally). */
|
|
138
|
+
stopForDenialLimit: StopForDenialLimit;
|
|
139
|
+
/** borrowed-readonly — the persisted allow-rule lane, or undefined (absent entirely with no store). */
|
|
140
|
+
permissionRuleLane: PermissionRuleLanes["personal"];
|
|
141
|
+
/** borrowed-readonly — the org rule lane, or undefined (absent on an ungoverned deployment). */
|
|
142
|
+
permissionRuleOrgLane: PermissionRuleLanes["org"];
|
|
143
|
+
/** borrowed-readonly — whether the ENGINE's question tool is what is mounted under the reserved name (the org lane's
|
|
144
|
+
* content-ask exemption predicate). */
|
|
145
|
+
questionToolMounted: boolean;
|
|
146
|
+
/** borrowed-readonly — whether sandbox admission is armed (isolated env + park prerequisites). */
|
|
147
|
+
sandboxAdmissionArmed: boolean;
|
|
148
|
+
/** borrowed-readonly — the per-tool boundary-capability fact the sandbox admission reads. */
|
|
149
|
+
sandboxBoundaryCapable: (toolName: string) => boolean;
|
|
150
|
+
/** borrowed-readonly — the sandbox-admission trace sink (the deferred ancestor disclosure and the gate's own). */
|
|
151
|
+
emitSandboxAdmitted: (info: {
|
|
152
|
+
toolCallId: string;
|
|
153
|
+
toolName: string;
|
|
154
|
+
askClasses: ReadonlyArray<{
|
|
155
|
+
cls: AskClass;
|
|
156
|
+
layer: string;
|
|
157
|
+
}>;
|
|
158
|
+
boundary: "sandbox_internal";
|
|
159
|
+
}) => void;
|
|
160
|
+
/** borrowed-readonly — the effective delegation facts (the rejection boundary's isDelegatedChild). */
|
|
161
|
+
delegation: {
|
|
162
|
+
isDelegatedChild: boolean;
|
|
163
|
+
};
|
|
164
|
+
/** borrowed-readonly — the own hook-crash reporter (an expired post seat is reported through it). */
|
|
165
|
+
notifyOwnHookCrash: (err: unknown) => void;
|
|
166
|
+
}
|
|
167
|
+
export interface PrepareGateStationsResult {
|
|
168
|
+
/** owned — whether the `tool_call` station registered (the arming predicate's value; observation seat only). */
|
|
169
|
+
toolCallStationArmed: boolean;
|
|
170
|
+
/** owned — whether the `tool_result` station registered (a post or screening hook is wired; observation seat only). */
|
|
171
|
+
toolResultStationArmed: boolean;
|
|
172
|
+
}
|
|
173
|
+
/** The M20 phase body — prepareTask's two gate stations, verbatim (see the module header). */
|
|
174
|
+
export declare function prepareGateStations(input: PrepareGateStationsInput): PrepareGateStationsResult;
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { SEND_MESSAGE_TOOL_NAME } from "../../agents/send-message-tool.js";
|
|
2
|
+
import { complianceCallDenial } from "../compliance.js";
|
|
3
|
+
import { cloneObserverInput, formatHookFeedback, hookSeatExpiredError, runHookSeat, runToolGate } from "../hooks.js";
|
|
4
|
+
import { PRESENT_PLAN_TOOL_NAME } from "../present-plan-tool.js";
|
|
5
|
+
import { screenGateOutcome } from "../gate-outcome.js";
|
|
6
|
+
import { directDeny } from "./gate-exit.js";
|
|
7
|
+
import { emitTrace } from "../trace.js";
|
|
8
|
+
import { createWriteProtectionCheck } from "../write-protect.js";
|
|
9
|
+
import { PATH_CONFINABLE_WRITE_TOOLS } from "./session-rule-policy.js";
|
|
10
|
+
function screenGateResult(result) {
|
|
11
|
+
if (result.suspend !== undefined)
|
|
12
|
+
return { defects: [] };
|
|
13
|
+
const gate = result.gate;
|
|
14
|
+
if (gate === undefined)
|
|
15
|
+
return { defects: ["a tool-gate result carried no outcome record on a terminal exit — every terminal exit mints one; the frame carries none"] };
|
|
16
|
+
const defects = screenGateOutcome(gate);
|
|
17
|
+
const blocked = result.block === true;
|
|
18
|
+
if ((gate.disposition.kind === "denied") !== blocked) {
|
|
19
|
+
defects.push(`a tool-gate result's outcome reads "${gate.disposition.kind}" on ${blocked ? "a blocked" : "an executing"} call — the two faces of one verdict disagree; the frame carries no outcome`);
|
|
20
|
+
}
|
|
21
|
+
return defects.length > 0 ? { defects } : { gate, defects };
|
|
22
|
+
}
|
|
23
|
+
function maybeHumanRejectionHalt(input) {
|
|
24
|
+
const d = input.gate?.disposition;
|
|
25
|
+
const s = input.gate?.settlement;
|
|
26
|
+
const bare = d?.kind === "denied" && d.deniedBy === "ask_resolution" && s?.kind === "human_refused" && s.note === undefined;
|
|
27
|
+
if (!bare || input.isDelegatedChild)
|
|
28
|
+
return undefined;
|
|
29
|
+
return {
|
|
30
|
+
reason: `This tool call was NOT executed: the user rejected the "${input.toolName}" tool call in the same ` +
|
|
31
|
+
`assistant message, which stops the rest of the batch. Nothing was run for this call — ` +
|
|
32
|
+
`re-issue it after the user's direction only if it is still needed.`,
|
|
33
|
+
details: {
|
|
34
|
+
error: "gate.batch_halted",
|
|
35
|
+
code: "gate.batch_halted",
|
|
36
|
+
rejectedToolCallId: input.toolCallId,
|
|
37
|
+
rejectedToolName: input.toolName,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function prepareGateStations(input) {
|
|
42
|
+
const { askLane, parkAsk, tools, toolEffects, deps, toolCallGateArmedRef, effectivePolicy, hooks, egressTools, irreversibleTools, spec, complianceDenies, harness, blockedToolCalls, inheritedAskGrants, inheritedUnavailableAsks, foldAskClasses, ancestorSandboxAdmissions, preToolContexts, gateOutcomes, batchHaltRef, blockedTracked, hookIdentity, reminderMark, planModeRef, hostTaskId, sessionId, ownGatePreToolUse, hookTimeoutMs, handsCwdRef, hookEnvFace, irreversibilityTier, reversibilityProbes, abortController, shellGatedBash, shellGatedMonitor, autoModeDecider, autoModeDenialTracking, stopForDenialLimit, permissionRuleLane, permissionRuleOrgLane, questionToolMounted, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, delegation, notifyOwnHookCrash } = input;
|
|
43
|
+
if (askLane !== undefined && parkAsk !== undefined) {
|
|
44
|
+
const { adjudicate, resolveAskBound, notifyPermissionDenied, notifyHookError } = askLane;
|
|
45
|
+
const { resolveContentAsk, suspendAsk } = parkAsk;
|
|
46
|
+
for (const t of tools) {
|
|
47
|
+
const eff = t.effect;
|
|
48
|
+
if (eff !== undefined && !toolEffects.has(t.name))
|
|
49
|
+
toolEffects.set(t.name, eff);
|
|
50
|
+
}
|
|
51
|
+
const writeProtectionCheck = createWriteProtectionCheck(deps.writeProtectedPaths, deps.memoryEngineDir !== undefined ? { dataRoot: deps.memoryEngineDir } : undefined);
|
|
52
|
+
const writeProtectionArmed = writeProtectionCheck !== undefined && tools.some((t) => PATH_CONFINABLE_WRITE_TOOLS.has(t.name));
|
|
53
|
+
toolCallGateArmedRef.armed =
|
|
54
|
+
effectivePolicy !== undefined ||
|
|
55
|
+
hooks?.preToolUse !== undefined ||
|
|
56
|
+
egressTools.size > 0 ||
|
|
57
|
+
irreversibleTools.size > 0 ||
|
|
58
|
+
spec.enablePlanMode === true ||
|
|
59
|
+
complianceDenies.has("web_fetch") ||
|
|
60
|
+
writeProtectionArmed;
|
|
61
|
+
if (toolCallGateArmedRef.armed) {
|
|
62
|
+
harness.on("tool_call", async (e) => {
|
|
63
|
+
blockedToolCalls.delete(e.toolCallId);
|
|
64
|
+
inheritedAskGrants.delete(e.toolCallId);
|
|
65
|
+
{
|
|
66
|
+
const complianceDeny = complianceCallDenial(complianceDenies, e.toolName);
|
|
67
|
+
if (complianceDeny !== undefined) {
|
|
68
|
+
if (blockedTracked)
|
|
69
|
+
blockedToolCalls.add(e.toolCallId);
|
|
70
|
+
const gate = directDeny("compliance");
|
|
71
|
+
gateOutcomes.set(e.toolCallId, gate);
|
|
72
|
+
if (notifyPermissionDenied) {
|
|
73
|
+
await notifyPermissionDenied({ toolName: e.toolName, input: cloneObserverInput(e.input), toolCallId: e.toolCallId, reason: complianceDeny, gate, identity: hookIdentity });
|
|
74
|
+
}
|
|
75
|
+
return { block: true, reason: formatHookFeedback(complianceDeny, reminderMark), preToolContext: [] };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (planModeRef.active && (toolEffects.get(e.toolName) ?? "write") !== "read") {
|
|
79
|
+
if (blockedTracked)
|
|
80
|
+
blockedToolCalls.add(e.toolCallId);
|
|
81
|
+
const planDenyReason = `Plan mode is active — "${e.toolName}" is a write/mutating tool and is read-only-blocked. ` +
|
|
82
|
+
`Research with read-only tools, then call ${PRESENT_PLAN_TOOL_NAME} with your plan to get it approved before acting.`;
|
|
83
|
+
const gate = directDeny("plan_mode");
|
|
84
|
+
gateOutcomes.set(e.toolCallId, gate);
|
|
85
|
+
if (notifyPermissionDenied) {
|
|
86
|
+
await notifyPermissionDenied({ toolName: e.toolName, input: cloneObserverInput(e.input), toolCallId: e.toolCallId, reason: planDenyReason, gate, identity: hookIdentity });
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
block: true,
|
|
90
|
+
reason: formatHookFeedback(planDenyReason, reminderMark),
|
|
91
|
+
preToolContext: [],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
let result;
|
|
95
|
+
try {
|
|
96
|
+
result = await runToolGate({
|
|
97
|
+
onNotifyError: (f) => emitTrace(deps.tracer, () => ({ kind: "observer.notify_failed", version: 1, taskId: hostTaskId, site: f.site, message: f.error.message, ts: Date.now() })),
|
|
98
|
+
event: e,
|
|
99
|
+
...(e.signal !== undefined ? { callSignal: e.signal } : {}),
|
|
100
|
+
identity: hookIdentity,
|
|
101
|
+
reminderMark,
|
|
102
|
+
preToolUse: ownGatePreToolUse,
|
|
103
|
+
hookTimeoutMs,
|
|
104
|
+
...(handsCwdRef !== undefined ? { trackedCwd: () => handsCwdRef.current } : {}),
|
|
105
|
+
...(hookEnvFace !== undefined ? { hookEnv: hookEnvFace } : {}),
|
|
106
|
+
adjudicate,
|
|
107
|
+
resolveAsk: resolveAskBound,
|
|
108
|
+
suspendAsk,
|
|
109
|
+
resolveContentAsk,
|
|
110
|
+
egress: egressTools.has(e.toolName),
|
|
111
|
+
peerMessage: e.toolName === SEND_MESSAGE_TOOL_NAME,
|
|
112
|
+
...(writeProtectionCheck !== undefined ? { writeProtectionCheck } : {}),
|
|
113
|
+
irreversibility: irreversibilityTier.get(e.toolName),
|
|
114
|
+
reversibilityProbe: reversibilityProbes.get(e.toolName),
|
|
115
|
+
abortSignal: abortController.signal,
|
|
116
|
+
...(notifyPermissionDenied ? { permissionDenied: notifyPermissionDenied } : {}),
|
|
117
|
+
onHookError: notifyHookError,
|
|
118
|
+
shellGated: (e.toolName === "Bash" && shellGatedBash) || (e.toolName === "Monitor" && shellGatedMonitor),
|
|
119
|
+
...(autoModeDecider ? { autoMode: { decider: autoModeDecider, ...(autoModeDenialTracking !== undefined ? { denialTracking: autoModeDenialTracking } : {}) } } : {}),
|
|
120
|
+
onHeadlessDenialLimit: stopForDenialLimit,
|
|
121
|
+
...(permissionRuleLane
|
|
122
|
+
? {
|
|
123
|
+
persistedRules: {
|
|
124
|
+
admits: permissionRuleLane.admits,
|
|
125
|
+
onResolved: (info) => emitTrace(deps.tracer, () => ({
|
|
126
|
+
kind: "permission.persisted_rule_allowed",
|
|
127
|
+
version: 2,
|
|
128
|
+
taskId: hostTaskId,
|
|
129
|
+
toolName: info.toolName,
|
|
130
|
+
toolCallId: info.toolCallId,
|
|
131
|
+
rules: [...info.rules],
|
|
132
|
+
ts: Date.now(),
|
|
133
|
+
})),
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
: {}),
|
|
137
|
+
...(permissionRuleOrgLane
|
|
138
|
+
? {
|
|
139
|
+
orgRules: {
|
|
140
|
+
adjudicate: permissionRuleOrgLane.adjudicate,
|
|
141
|
+
contentAskToolMounted: questionToolMounted,
|
|
142
|
+
onUnavailable: (info) => emitTrace(deps.tracer, () => ({
|
|
143
|
+
kind: "permission.org_snapshot_unavailable",
|
|
144
|
+
version: 1,
|
|
145
|
+
taskId: hostTaskId,
|
|
146
|
+
toolName: info.toolName,
|
|
147
|
+
toolCallId: info.toolCallId,
|
|
148
|
+
message: info.message,
|
|
149
|
+
ts: Date.now(),
|
|
150
|
+
})),
|
|
151
|
+
},
|
|
152
|
+
}
|
|
153
|
+
: {}),
|
|
154
|
+
isMarkedUnresolvable: (toolCallId) => inheritedUnavailableAsks.has(toolCallId),
|
|
155
|
+
...(sandboxAdmissionArmed
|
|
156
|
+
? {
|
|
157
|
+
sandboxAdmission: {
|
|
158
|
+
askClassesOf: (toolCallId) => foldAskClasses.get(toolCallId),
|
|
159
|
+
boundaryCapable: sandboxBoundaryCapable(e.toolName),
|
|
160
|
+
onAdmitted: emitSandboxAdmitted,
|
|
161
|
+
},
|
|
162
|
+
}
|
|
163
|
+
: {}),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
finally {
|
|
167
|
+
inheritedUnavailableAsks.delete(e.toolCallId);
|
|
168
|
+
inheritedAskGrants.delete(e.toolCallId);
|
|
169
|
+
foldAskClasses.delete(e.toolCallId);
|
|
170
|
+
}
|
|
171
|
+
const ancestorAdmitted = ancestorSandboxAdmissions.get(e.toolCallId);
|
|
172
|
+
ancestorSandboxAdmissions.delete(e.toolCallId);
|
|
173
|
+
if (ancestorAdmitted !== undefined && !result.block && !result.suspend) {
|
|
174
|
+
emitSandboxAdmitted({ toolCallId: e.toolCallId, toolName: e.toolName, askClasses: ancestorAdmitted, boundary: "sandbox_internal" });
|
|
175
|
+
result.preToolContext.push(`permission.sandbox_admitted: this call's inherited pending approval was auto-admitted because the deployment declares an isolated sandbox execution env and the request stays inside it. Recorded for audit.`);
|
|
176
|
+
}
|
|
177
|
+
if (!result.block && !result.suspend && result.preToolContext.length > 0) {
|
|
178
|
+
preToolContexts.set(e.toolCallId, result.preToolContext);
|
|
179
|
+
}
|
|
180
|
+
if (blockedTracked && (result.block || result.suspend)) {
|
|
181
|
+
blockedToolCalls.add(e.toolCallId);
|
|
182
|
+
}
|
|
183
|
+
const screened = screenGateResult(result);
|
|
184
|
+
for (const defect of screened.defects)
|
|
185
|
+
deps.onError?.(new Error(defect), { phase: "config", sessionId });
|
|
186
|
+
if (screened.gate !== undefined)
|
|
187
|
+
gateOutcomes.set(e.toolCallId, screened.gate);
|
|
188
|
+
if (result.block) {
|
|
189
|
+
const haltRemaining = maybeHumanRejectionHalt({
|
|
190
|
+
gate: screened.gate,
|
|
191
|
+
isDelegatedChild: delegation.isDelegatedChild === true,
|
|
192
|
+
toolName: e.toolName,
|
|
193
|
+
toolCallId: e.toolCallId,
|
|
194
|
+
});
|
|
195
|
+
if (haltRemaining !== undefined) {
|
|
196
|
+
batchHaltRef.current = { rejectedToolCallId: e.toolCallId };
|
|
197
|
+
return { block: true, reason: result.reason, haltRemaining };
|
|
198
|
+
}
|
|
199
|
+
return { block: true, reason: result.reason };
|
|
200
|
+
}
|
|
201
|
+
return result.updatedInput !== undefined ? { updatedInput: result.updatedInput } : undefined;
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const toolResultStationArmed = Boolean(hooks?.postToolUse || hooks?.preToolUse || hooks?.postToolUseFailure);
|
|
206
|
+
if (toolResultStationArmed) {
|
|
207
|
+
harness.on("tool_result", async (e) => {
|
|
208
|
+
if (blockedToolCalls.delete(e.toolCallId)) {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
let content = e.content;
|
|
212
|
+
let changed = false;
|
|
213
|
+
if (e.isError) {
|
|
214
|
+
if (hooks?.postToolUseFailure) {
|
|
215
|
+
let clonedDetails = e.details;
|
|
216
|
+
try {
|
|
217
|
+
clonedDetails = structuredClone(e.details);
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
}
|
|
221
|
+
const failureSeat = await runHookSeat("postToolUseFailure", { timeoutMs: hookTimeoutMs, signal: abortController.signal }, (sig) => hooks.postToolUseFailure(e.toolName, e.input, {
|
|
222
|
+
error: e.content
|
|
223
|
+
.filter((c) => c.type === "text")
|
|
224
|
+
.map((c) => c.text)
|
|
225
|
+
.join("\n"),
|
|
226
|
+
isInterrupt: abortController.signal.aborted || spec.signal?.aborted === true,
|
|
227
|
+
content: e.content.map((c) => ({ ...c })),
|
|
228
|
+
details: clonedDetails,
|
|
229
|
+
}, { toolCallId: e.toolCallId, toolName: e.toolName, signal: sig, ...(handsCwdRef?.current !== undefined ? { cwd: handsCwdRef.current } : {}), ...(hookEnvFace !== undefined ? { env: hookEnvFace } : {}), identity: hookIdentity }));
|
|
230
|
+
if (failureSeat.expired) {
|
|
231
|
+
notifyOwnHookCrash(hookSeatExpiredError("postToolUseFailure", hookTimeoutMs, failureSeat.cause, "the observation was abandoned and its additionalContext dropped; the failure result itself is unchanged"));
|
|
232
|
+
}
|
|
233
|
+
const patch = failureSeat.expired ? undefined : failureSeat.value;
|
|
234
|
+
if (patch?.additionalContext) {
|
|
235
|
+
content = [...content, { type: "text", text: formatHookFeedback(patch.additionalContext, reminderMark) }];
|
|
236
|
+
changed = true;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
else if (hooks?.postToolUse) {
|
|
241
|
+
const successSeat = await runHookSeat("postToolUse", { timeoutMs: hookTimeoutMs, signal: abortController.signal }, (sig) => hooks.postToolUse(e.toolName, e.input, { content: e.content, details: e.details, isError: e.isError }, { toolCallId: e.toolCallId, toolName: e.toolName, signal: sig, ...(handsCwdRef?.current !== undefined ? { cwd: handsCwdRef.current } : {}), ...(hookEnvFace !== undefined ? { env: hookEnvFace } : {}), identity: hookIdentity }));
|
|
242
|
+
if (successSeat.expired) {
|
|
243
|
+
notifyOwnHookCrash(hookSeatExpiredError("postToolUse", hookTimeoutMs, successSeat.cause, "the seat was abandoned; the tool result is delivered to the model UNMODIFIED (no updatedOutput, no additionalContext)"));
|
|
244
|
+
}
|
|
245
|
+
const patch = successSeat.expired ? undefined : successSeat.value;
|
|
246
|
+
if (patch?.updatedOutput) {
|
|
247
|
+
content = patch.updatedOutput;
|
|
248
|
+
changed = true;
|
|
249
|
+
}
|
|
250
|
+
if (patch?.additionalContext) {
|
|
251
|
+
content = [...content, { type: "text", text: formatHookFeedback(patch.additionalContext, reminderMark) }];
|
|
252
|
+
changed = true;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const pre = preToolContexts.get(e.toolCallId);
|
|
256
|
+
if (pre) {
|
|
257
|
+
preToolContexts.delete(e.toolCallId);
|
|
258
|
+
content = [...content, ...pre.map((t) => ({ type: "text", text: formatHookFeedback(t, reminderMark) }))];
|
|
259
|
+
changed = true;
|
|
260
|
+
}
|
|
261
|
+
return changed ? { content } : undefined;
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
return { toolCallStationArmed: toolCallGateArmedRef.armed, toolResultStationArmed };
|
|
265
|
+
}
|
|
@@ -160,9 +160,9 @@ export interface PrepareHandsReadFaceInput {
|
|
|
160
160
|
* when no file restore ran. Fail-closed by construction — dropping a read record only ever
|
|
161
161
|
* produces refusals. */
|
|
162
162
|
restoredFilePaths?: readonly string[];
|
|
163
|
-
/** borrowed (ref cell; the REF itself is never replaced)
|
|
163
|
+
/** borrowed-readonly — (ref cell; the REF itself is never replaced) design/138 S2-C late-bound memory
|
|
164
164
|
* write gate: the band's beforeWrite closure reads `.current` call-time; prepareMemory (driver,
|
|
165
|
-
* after this phase) installs the gate. Declared in the driver because the SAME ref feeds
|
|
165
|
+
* after this phase) installs the gate — the one writer; this phase only reads. Declared in the driver because the SAME ref feeds
|
|
166
166
|
* prepareMemory. */
|
|
167
167
|
memoryWriteGateRef: {
|
|
168
168
|
current?: BeforeWriteHook;
|
|
@@ -199,10 +199,10 @@ export interface PrepareHandsReadFaceInput {
|
|
|
199
199
|
* band's Read/notebook/PDF trailer outlets bump keys on it at tool-execute time (the driver owns
|
|
200
200
|
* the object and folds it into result stats). */
|
|
201
201
|
reminderDisclosureCounts: import("../reminder-disclosure.js").ReminderDisclosureCounts;
|
|
202
|
-
/** design/381
|
|
202
|
+
/** borrowed-readonly — design/381: the first-touch history hook prepare built (present iff a fileHistoryStore is
|
|
203
203
|
* wired and the run mounts a real fs env); threaded to the write band's trackFileEdit seat. */
|
|
204
204
|
trackFileEdit?: import("../types.js").TrackFileEditHook;
|
|
205
|
-
/** borrowed — the mutation lane's LANDED observation seat (the accumulator behind
|
|
205
|
+
/** borrowed-readonly — the mutation lane's LANDED observation seat (the accumulator behind
|
|
206
206
|
* `TaskResult.editedFiles`); threaded to the write band's onFileEdited seat. Unlike
|
|
207
207
|
* `trackFileEdit` it does NOT depend on a wired history store: it observes what this run's hands
|
|
208
208
|
* did, so it is present on every run that mounts the band. */
|
|
@@ -238,13 +238,13 @@ export interface PrepareInheritedGateResult {
|
|
|
238
238
|
notifyOwnHookCrash: (err: unknown) => void;
|
|
239
239
|
/** owned — the FROZEN question seat (spec over deps), the content-ask twin of `frozenOnAsk`. */
|
|
240
240
|
frozenOnQuestion: OnQuestion | undefined;
|
|
241
|
-
/** borrowed-mutable — the delegation runtime-provenance arming face.
|
|
242
|
-
* once per leg when
|
|
241
|
+
/** borrowed-mutable — the delegation runtime-provenance arming face. Writer: the memory-engine-session phase
|
|
242
|
+
* (prepareMemoryEngineSession), once per leg when it arms. Read lazily by delegation tools through the ctx. */
|
|
243
243
|
provenanceForChildrenRef: {
|
|
244
244
|
current?: DelegationContentSafety;
|
|
245
245
|
};
|
|
246
|
-
/** borrowed-mutable — the delegation-settlement coordinates.
|
|
247
|
-
* Read lazily by delegation tools through the ctx. */
|
|
246
|
+
/** borrowed-mutable — the delegation-settlement coordinates. Writer: the memory-engine-session phase, once per leg when the
|
|
247
|
+
* mounted session carries a settlement seat. Read lazily by delegation tools through the ctx. */
|
|
248
248
|
delegationSettlementRef: {
|
|
249
249
|
current?: {
|
|
250
250
|
controlDir: string;
|
|
@@ -221,7 +221,7 @@ export function prepareInheritedGate(input) {
|
|
|
221
221
|
delegationSettlement: delegationSettlementForChildren,
|
|
222
222
|
...(autoModeDecider ? { autoModeReview: { decider: autoModeDecider } } : {}),
|
|
223
223
|
...(spec.durableApproval !== undefined ? { durableApprovalForChildren: { ...spec.durableApproval } } : {}),
|
|
224
|
-
...(spec.checkpointStore ===
|
|
224
|
+
...(spec.checkpointStore === "disabled" ? { checkpointStoreDisabledForChildren: true } : {}),
|
|
225
225
|
taskId: hostTaskId,
|
|
226
226
|
...(internals?.parentTaskId !== undefined ? { parentTaskId: internals.parentTaskId } : {}),
|
|
227
227
|
...(internals?.parentSessionId !== undefined ? { parentSessionId: internals.parentSessionId } : {}),
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/390 §1.2 M12 — prepareTask's MEMORY-ENGINE-SESSION phase, verbatim from the driver: the content-origin
|
|
3
|
+
* classification + one-way session pollution wrap section (design/178 §3 / design/180 half A / design/324 /
|
|
4
|
+
* design/336 §3.3 + §5.5 / design/378 D-4 / design/380 O9a). Its arming predicate (a mounted memory session OR an
|
|
5
|
+
* upstream recorder channel), the chain-narrowed classification config, the children's provenance seat, the
|
|
6
|
+
* declared-MCP-class announcement, the settlement seat, the per-tool wrap with its three record verbs (mark /
|
|
7
|
+
* recordExternal / recordIncomplete), the Read tool's recall-taint arm and the delegation arm's three-valued
|
|
8
|
+
* attestation judgment all live here; the announcement helper only this section called moved with it. The
|
|
9
|
+
* interface is the dependency list the segment had implicitly (design/238 R-1).
|
|
10
|
+
*
|
|
11
|
+
* SYNCHRONOUS FUNCTION, SYNCHRONOUS CALL: the stretch has no await of its own (the awaits sit inside the wrappers it
|
|
12
|
+
* installs, which run at tool-call time), so the phase adds no yield between the deferred classification before it
|
|
13
|
+
* and the prompt assembly after it (design/390 §1.5: a stretch with no await is extracted as a sync function).
|
|
14
|
+
* Read-stability of the host handles for the call: {@link RunInternals} (`@contract prepare.deps-read-stable`).
|
|
15
|
+
*
|
|
16
|
+
* One read changed spelling and nothing else: the declared-class announcement read `mcp?.statuses` while `mcp` had
|
|
17
|
+
* long been the protocol-tools phase's non-null handle; the optional chain was dead and is now the plain member read.
|
|
18
|
+
*/
|
|
19
|
+
import type { AgentTool } from "../../internal/harness.js";
|
|
20
|
+
import type { LockedPreflight } from "../locked-config.js";
|
|
21
|
+
import type { MaterializedMcp } from "../mcp.js";
|
|
22
|
+
import { type DelegationContentSafety } from "../memory-engine/delegation-provenance.js";
|
|
23
|
+
import type { RunnerDeps, TaskSpec } from "../types.js";
|
|
24
|
+
import type { Prepared, RunInternals } from "./contracts.js";
|
|
25
|
+
export interface PrepareMemoryEngineSessionInput {
|
|
26
|
+
/** borrowed-readonly — the mounted engine session, or undefined (the ARMING fact's first half). Read: `pollution`
|
|
27
|
+
* (the mark face), `contentSafety` (the own half of the narrowing), `settlement` (the seat + the receipt ledger),
|
|
28
|
+
* `recallTaint` (the Read arm's judge). Never mutated; the wrappers call `pollution.markPolluted` at tool-call time. */
|
|
29
|
+
memoryEngineSession: Prepared["memoryEngineSession"];
|
|
30
|
+
/** borrowed-mutable — the trusted spawn-side channel; only `delegationProvenance` (the ARMING fact's second half: the
|
|
31
|
+
* recorder channel with the chain's frozen `contentSafety`). Writers: the wrappers this phase installs set
|
|
32
|
+
* `delegationProvenance.ref.current.sawExternal` / `.incomplete` at tool-call time (monotonic, never cleared). */
|
|
33
|
+
internals: Pick<RunInternals, "delegationProvenance"> | undefined;
|
|
34
|
+
/** borrowed-readonly — the doors' per-leg SNAPSHOT of `RunnerDeps.memoryDelegationEvidence` (screened in the
|
|
35
|
+
* synchronous pre-await stretch; never a live deps re-read here). */
|
|
36
|
+
memoryDelegationEvidence: "static-face" | "attested-only";
|
|
37
|
+
/** borrowed-readonly — the run's external-content-target fold (live adapter declaration OR the persisted bit). */
|
|
38
|
+
externalContentTargetActive: boolean;
|
|
39
|
+
/** borrowed-readonly — the frozen preflight; only `mcp` (the declared entries the announcement walks). */
|
|
40
|
+
lockedPreflight: Pick<LockedPreflight, "mcp">;
|
|
41
|
+
/** borrowed-readonly — the materialized MCP handle; only `statuses` (the announcement's mounted-tool count). */
|
|
42
|
+
mcp: Pick<MaterializedMcp, "statuses">;
|
|
43
|
+
/** borrowed-readonly — the acquired session id (notice detail). */
|
|
44
|
+
sessionId: string;
|
|
45
|
+
/** borrowed-readonly — the run's invocation id (notice detail; the once-per-leg claims are per-RUN claims). */
|
|
46
|
+
runId: string;
|
|
47
|
+
/** borrowed-readonly — the deployment seats; only `onNotice` (the declared-class line and the waiver notice). */
|
|
48
|
+
deps: Pick<RunnerDeps, "onNotice">;
|
|
49
|
+
/** borrowed-mutable — the children's provenance seat (the inherited-gate phase mints it; `inheritedGateForChildren`
|
|
50
|
+
* reads it late). Writer: THIS phase, once at arming, to the effective (chain-narrowed) config. */
|
|
51
|
+
provenanceForChildrenRef: {
|
|
52
|
+
current?: DelegationContentSafety;
|
|
53
|
+
};
|
|
54
|
+
/** borrowed-mutable — the children's settlement seat (the inherited-gate phase mints it). Writer: THIS phase, once at
|
|
55
|
+
* arming, when the memory session mounted a settlement (memoryProvenance "carry"). */
|
|
56
|
+
delegationSettlementRef: {
|
|
57
|
+
current?: {
|
|
58
|
+
controlDir: string;
|
|
59
|
+
sessionId: string;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
/** borrowed-readonly — the REBOUND spec; only `tools` (the RAW caller specs: caller-tool names and the marker-bearing
|
|
63
|
+
* delegation entries — the assembled roster objects carry neither marker). Never mutated. */
|
|
64
|
+
spec: Pick<TaskSpec, "tools">;
|
|
65
|
+
/** borrowed-readonly — the env-hand roster (membership minted at the mount sites); read by the classification. */
|
|
66
|
+
envHandToolNames: ReadonlySet<string>;
|
|
67
|
+
/** borrowed-mutable — the run's ONE tool roster. Writer here: the wrap pass REPLACES entries in place
|
|
68
|
+
* (`tools[i] = wrapped`, identity-tracked so a re-run never stacks wrappers); see the roster's writer table on
|
|
69
|
+
* {@link Prepared.tools}. */
|
|
70
|
+
tools: AgentTool[];
|
|
71
|
+
/** borrowed-mutable — the re-runnable wrap pass's seat (the protocol-tools phase mints it; the rebuild seam re-runs it
|
|
72
|
+
* after a refresh re-splice). Writer: THIS phase installs the pass and runs it once. */
|
|
73
|
+
contentOriginWrapRef: {
|
|
74
|
+
current?: () => void;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export interface PrepareMemoryEngineSessionResult {
|
|
78
|
+
/** owned — whether the section ARMED on this leg (a memory session or a recorder channel existed): armed ⇒ every
|
|
79
|
+
* roster tool was classified and the polluting/delegation/Read-plane ones wrapped; not armed ⇒ zero wraps, zero
|
|
80
|
+
* announcements, both children's seats untouched. */
|
|
81
|
+
armed: boolean;
|
|
82
|
+
}
|
|
83
|
+
/** The M12 phase body — prepareTask's content-origin wrap stretch, verbatim (see the module header). */
|
|
84
|
+
export declare function prepareMemoryEngineSession(input: PrepareMemoryEngineSessionInput): PrepareMemoryEngineSessionResult;
|