@sema-agent/core 7.6.0 → 7.6.1
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 +26 -0
- package/dist/agents/agent-transcript-tool.d.ts +2 -2
- package/dist/agents/cascade.d.ts +2 -3
- package/dist/agents/repair-loop.d.ts +2 -2
- package/dist/agents/retain-ledger.d.ts +2 -3
- package/dist/agents/send-message-tool.d.ts +2 -2
- package/dist/agents/session-util.d.ts +2 -2
- package/dist/agents/subagent.d.ts +3 -4
- package/dist/agents/teacher.d.ts +2 -2
- package/dist/agents/team.d.ts +2 -2
- package/dist/agents/verify.d.ts +5 -6
- package/dist/core/agent-definition.d.ts +172 -0
- package/dist/core/agent-definition.js +1 -0
- package/dist/core/delegation-frames.d.ts +298 -0
- package/dist/core/delegation-frames.js +21 -0
- package/dist/core/engine-notice.d.ts +555 -0
- package/dist/core/engine-notice.js +55 -0
- package/dist/core/gate-fold.d.ts +12 -0
- package/dist/core/gate-fold.js +158 -0
- package/dist/core/gate-lanes.d.ts +93 -0
- package/dist/core/gate-lanes.js +626 -0
- package/dist/core/hands-band.d.ts +134 -0
- package/dist/core/hands-band.js +1 -0
- package/dist/core/hooks.d.ts +20 -101
- package/dist/core/hooks.js +53 -854
- package/dist/core/mcp-failure.d.ts +43 -5
- package/dist/core/mcp-failure.js +31 -14
- package/dist/core/mcp-server-spec.d.ts +217 -0
- package/dist/core/mcp-server-spec.js +1 -0
- package/dist/core/model-seat.d.ts +99 -0
- package/dist/core/model-seat.js +1 -0
- package/dist/core/reminder-mint.d.ts +10 -0
- package/dist/core/reminder-mint.js +3 -0
- package/dist/core/runner/contracts.d.ts +382 -6
- package/dist/core/runner/gate-exit.d.ts +177 -9
- package/dist/core/runner/gate-exit.js +70 -1
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +2 -7
- package/dist/core/runner/prepare-delegation-surface.d.ts +2 -7
- package/dist/core/runner/prepare-task.d.ts +2 -2
- package/dist/core/runner/runtask.d.ts +4 -71
- package/dist/core/runner/runtask.js +14 -5
- package/dist/core/runner-deps.d.ts +1416 -0
- package/dist/core/runner-deps.js +1 -0
- package/dist/core/runtime-caps.d.ts +164 -0
- package/dist/core/runtime-caps.js +1 -0
- package/dist/core/task-event.d.ts +910 -0
- package/dist/core/task-event.js +1 -0
- package/dist/core/task-limits.d.ts +110 -0
- package/dist/core/task-limits.js +1 -0
- package/dist/core/task-result.d.ts +809 -0
- package/dist/core/task-result.js +1 -0
- package/dist/core/task-spec.d.ts +1370 -0
- package/dist/core/task-spec.js +1 -0
- package/dist/core/task-stream.d.ts +382 -0
- package/dist/core/task-stream.js +1 -0
- package/dist/core/tool-spec.d.ts +1174 -0
- package/dist/core/tool-spec.js +1 -0
- package/dist/core/types.d.ts +26 -7691
- package/dist/core/types.js +2 -76
- package/dist/core/warm-resume.d.ts +2 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/orchestration/goal.d.ts +2 -2
- package/dist/orchestration/run-spec.d.ts +2 -2
- package/dist/orchestration/run-workflow-tool.d.ts +3 -3
- package/dist/orchestration/workflow.d.ts +4 -4
- package/dist/scenarios/scenario-registry.d.ts +3 -3
- package/dist/scenarios/teacher-quickstart.d.ts +2 -2
- package/dist/server/http.d.ts +2 -2
- package/dist/stores/file/fs-atomic.d.ts +88 -12
- package/dist/stores/file/fs-atomic.js +184 -55
- package/dist/stores/file/index.d.ts +1 -0
- package/dist/stores/file/index.js +1 -0
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +9 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/138 S2-C — the hands band's write-time CONTENT hook (single source; `src/tools/fs` re-exports
|
|
3
|
+
* these so its import surface is unchanged — moved here by design/141 件2 because `RunnerDeps.hands`
|
|
4
|
+
* carries the deployment-composable half of the hook). Called before EVERY `env.writeFile` in
|
|
5
|
+
* Write/Edit/NotebookEdit with the resolved containment key and the exact final text; `{ ok:false }`
|
|
6
|
+
* fails the tool with a structured error and NOTHING is written. A THROWING hook fails CLOSED.
|
|
7
|
+
*/
|
|
8
|
+
export interface BeforeWriteRequest {
|
|
9
|
+
tool: "Write" | "Edit" | "NotebookEdit";
|
|
10
|
+
/** The model-supplied path argument (for the error-message coordinate the model knows). */
|
|
11
|
+
path: string;
|
|
12
|
+
/** The resolved canonical containment key — what the hook should judge. */
|
|
13
|
+
key: string;
|
|
14
|
+
/** The FINAL full text about to be written (Edit/NotebookEdit: after application). */
|
|
15
|
+
content: string;
|
|
16
|
+
}
|
|
17
|
+
export type BeforeWriteResult = {
|
|
18
|
+
ok: true;
|
|
19
|
+
} | {
|
|
20
|
+
ok: false;
|
|
21
|
+
code: string;
|
|
22
|
+
reason: string;
|
|
23
|
+
};
|
|
24
|
+
export type BeforeWriteHook = (req: BeforeWriteRequest) => BeforeWriteResult | undefined | Promise<BeforeWriteResult | undefined>;
|
|
25
|
+
/**
|
|
26
|
+
* design/381 — the hands band's FIRST-TOUCH HISTORY hook, called before EVERY file mutation in
|
|
27
|
+
* Write/Edit/NotebookEdit (after the `beforeWrite` content gate passed, immediately before the
|
|
28
|
+
* final env write) with the resolved canonical containment key. The Runner wires it to
|
|
29
|
+
* `FileHistoryStore.trackEdit` (backup-before-first-edit, the CC FileHistory trigger-point set
|
|
30
|
+
* minus the bash simulation arm sema does not have — DV-7); later calls for an already-tracked
|
|
31
|
+
* path are cheap store no-ops. `{ok:false}` carries the REFUSAL TEXT the tool must answer instead
|
|
32
|
+
* of writing (DV-14 default: no durable first-touch state ⇒ the edit is refused, typed and loud —
|
|
33
|
+
* any proceed-unprotected policy is resolved INSIDE the hook by the Runner, never by the band).
|
|
34
|
+
* A THROWING hook fails CLOSED (same posture as the write gate). Absent hook ⇒ byte-identical
|
|
35
|
+
* behavior (no history store wired).
|
|
36
|
+
*/
|
|
37
|
+
export interface TrackEditRequest {
|
|
38
|
+
tool: "Write" | "Edit" | "NotebookEdit";
|
|
39
|
+
/** The model-supplied path argument (for the error-message coordinate the model knows). */
|
|
40
|
+
path: string;
|
|
41
|
+
/** The resolved canonical containment key — the identity the history record is keyed on. */
|
|
42
|
+
key: string;
|
|
43
|
+
/** The tool call's abort signal, threaded into the store's env read. */
|
|
44
|
+
signal?: AbortSignal;
|
|
45
|
+
}
|
|
46
|
+
export type TrackEditResult = {
|
|
47
|
+
ok: true;
|
|
48
|
+
/**
|
|
49
|
+
* #491 — the compensating handle for the ordering the topology cannot avoid: the pre-image
|
|
50
|
+
* capture runs BEFORE the write, so a write that then FAILS (lost create race, ENOSPC,
|
|
51
|
+
* EACCES, read-only mount) would leave a first-touch record for an edit that never happened —
|
|
52
|
+
* and an `existed-not` record makes an untouched path a rewind DELETE target, removing bytes
|
|
53
|
+
* whoever writes them next (the user, a peer process) owns. Present ONLY when THIS call minted
|
|
54
|
+
* the record (an already-tracked path belongs to the edit that first touched it and must never
|
|
55
|
+
* be discarded); the band calls it on the write-failure arm of every mutation lane. `proof`
|
|
56
|
+
* says which retraction rule applies: `"proven"` = the write's own error code guarantees
|
|
57
|
+
* nothing was written, `"verify"` = ambiguous, so the history seat must re-read the path and
|
|
58
|
+
* retract only if it still matches what the first touch recorded. It never throws and never
|
|
59
|
+
* blocks the failure it accompanies — the original write error is the answer.
|
|
60
|
+
*/
|
|
61
|
+
annul?: (proof: "proven" | "verify") => Promise<void>;
|
|
62
|
+
} | {
|
|
63
|
+
ok: false;
|
|
64
|
+
refusal: string;
|
|
65
|
+
};
|
|
66
|
+
export type TrackFileEditHook = (req: TrackEditRequest) => Promise<TrackEditResult>;
|
|
67
|
+
/**
|
|
68
|
+
* The hands band's MUTATION-EDITED observation seat — the counterpart of {@link TrackEditRequest},
|
|
69
|
+
* fired at the other end of the same lane. Called once per Write/Edit/NotebookEdit call whose FINAL
|
|
70
|
+
* env write did not PROVABLY write nothing, at the single point every mutation lane funnels through,
|
|
71
|
+
* under the same three-valued law as the first-touch record's own retraction:
|
|
72
|
+
* - a call the argument checks, the read-before-edit gate, the write gate or the first-touch
|
|
73
|
+
* history seat refused never fires it (nothing was written);
|
|
74
|
+
* - a call whose write FAILED with a code whose contract says nothing was written never fires it;
|
|
75
|
+
* - a call whose write failed AMBIGUOUSLY (a non-atomic env that truncated and then errored) or
|
|
76
|
+
* THREW fires it — exactly the arm where the retraction KEEPS the first-touch record because the
|
|
77
|
+
* file may really have changed. The two seats agree on purpose: a file whose baseline was kept
|
|
78
|
+
* for a possible modification must also be listed as possibly modified;
|
|
79
|
+
* - a `Bash` command that changed a file never fires it: bash does not run through this band's
|
|
80
|
+
* write lanes at all, which is the whole reason this seat is not a tool-name table.
|
|
81
|
+
* PURE OBSERVATION: it returns nothing and it cannot refuse. A FAULT in it is contained in both
|
|
82
|
+
* shapes an observer can fail in — a synchronous throw, and (the return type is `void`, but an
|
|
83
|
+
* `async` function still type-checks there) a rejected promise, which is sunk rather than left
|
|
84
|
+
* unhandled. Neither is awaited: an observer must never turn a landed write into a failed tool
|
|
85
|
+
* answer, nor delay one.
|
|
86
|
+
*/
|
|
87
|
+
export interface FileEditedNotice {
|
|
88
|
+
tool: "Write" | "Edit" | "NotebookEdit";
|
|
89
|
+
/** The model-supplied path argument — the SAME coordinate the delegated-child projection's
|
|
90
|
+
* `SubagentEditedFile.path` carries, so the two seats can be read side by side. */
|
|
91
|
+
path: string;
|
|
92
|
+
/** The resolved canonical containment key the bytes actually landed on. */
|
|
93
|
+
key: string;
|
|
94
|
+
}
|
|
95
|
+
export type FileEditedHook = (notice: FileEditedNotice) => void;
|
|
96
|
+
/**
|
|
97
|
+
* design/141 件2 — the SAFE deployment-configurable subset of the hands toolkit ({@link RunnerDeps.hands}).
|
|
98
|
+
* Only fields whose injection is purely additive for a deployment are here; Runner-internal orchestration
|
|
99
|
+
* state (taskRegistry/detachHub/execClamp/cwdRef/mount coordination) is deliberately NOT configurable.
|
|
100
|
+
*/
|
|
101
|
+
export interface HandsBandOptions {
|
|
102
|
+
/** Override the `bash_readonly` command allowlist (read-only band). Default: the built-in read-only set. */
|
|
103
|
+
bashReadonlyAllow?: readonly string[];
|
|
104
|
+
/** Co-Authored-By trailer for the bash git protocol. Default NONE ([c209] BREAKING: attribution is a
|
|
105
|
+
* deployment identity asset — the branded scenario sets `"Name <email>"`); `false` ≡ unset. */
|
|
106
|
+
commitCoAuthor?: string | false;
|
|
107
|
+
/** Read-tool image downsampler: inject your own, or `false` to force-disable (deterministic no-sharp).
|
|
108
|
+
* Omitted ⇒ auto-detect sharp. Same contract as the MCP-side {@link import("./mcp.js").ImageDownsampler}. */
|
|
109
|
+
readImageDownsampler?: ((input: Buffer, mimeType: string) => Promise<import("./mcp.js").DownsampledImage | undefined>) | false;
|
|
110
|
+
/** Deployment write gate — COMPOSED with (never replacing) the engine's MemoryEngine write-scan gate:
|
|
111
|
+
* this hook judges first (a rejection short-circuits), the engine gate then still runs in full. */
|
|
112
|
+
beforeWrite?: BeforeWriteHook;
|
|
113
|
+
/** RB-198 F1 (CC 220 `Zry`/`WZi.#m` parity): on a foreground Bash command's OWN timeout, an eligible
|
|
114
|
+
* command (see `canAutoBackground` — no `git` anywhere in the command, not a `sleep`-first-word wait) is
|
|
115
|
+
* adopted as a background task instead of being killed — CC's own posture ("received no response for
|
|
116
|
+
* Nms" would otherwise force a wasteful blind re-run of a non-idempotent long command). Default `false`
|
|
117
|
+
* (byte-compat): this is a deployment-level opt-in, deliberately NOT inferred from background-task
|
|
118
|
+
* plumbing (`detachHub`/`taskRegistry`) merely being present, since the Runner wires those unconditionally
|
|
119
|
+
* for every task — tying eligibility to their mere presence would silently flip the timeout outcome for
|
|
120
|
+
* every existing caller with no explicit signal at all. */
|
|
121
|
+
autoBackgroundOnTimeout?: boolean;
|
|
122
|
+
/** Append the per-read content-safety reminder after a successful text read (the ~50-token
|
|
123
|
+
* `<system-reminder>` the Read tool adds to a text body — the plain-text and notebook read paths;
|
|
124
|
+
* PDF text extraction has its own result builder and has never carried the reminder, so this switch
|
|
125
|
+
* does not govern it). Default TRUE, and an omitted field keeps
|
|
126
|
+
* that default: a BYOM engine cannot assume its serving model carries that mitigation internally, and
|
|
127
|
+
* the reminder only works because it sits next to the bytes it is about — not in a system prompt
|
|
128
|
+
* hundreds of turns back.
|
|
129
|
+
*
|
|
130
|
+
* Pass `false` to state that THIS deployment's serving model does carry it, and stop paying the
|
|
131
|
+
* reminder's tokens on every text read for advice the model already applies. Absent and `false` are
|
|
132
|
+
* deliberately different decisions: absent means "unknown, so assume not". */
|
|
133
|
+
readCyberReminder?: boolean;
|
|
134
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/core/hooks.d.ts
CHANGED
|
@@ -2,8 +2,11 @@ import type { ActorAssertion, DocumentContent, ImageContent, TextContent } from
|
|
|
2
2
|
import type { ExecutionEnv, FileError, Result, SessionTreeEntry } from "../internal/harness-types.js";
|
|
3
3
|
import type { DecisionReason, PermissionResult, ResolvedAsk, ToolCallRequest, ToolPolicy } from "./tool-policy.js";
|
|
4
4
|
import type { GateOutcome } from "./gate-outcome.js";
|
|
5
|
+
export { normalizeOrgGateVerdict, normalizePersistedRuleHit, persistedRuleMandateOf } from "./gate-lanes.js";
|
|
6
|
+
export { cloneObserverInput } from "./runner/gate-exit.js";
|
|
5
7
|
import { type AskClass } from "./ask-class.js";
|
|
6
|
-
import {
|
|
8
|
+
import type { AutoModeDenialTracker } from "./auto-mode.js";
|
|
9
|
+
export { formatHookFeedback } from "./reminder-mint.js";
|
|
7
10
|
import type { WiringLegKind } from "./wiring-manifest.js";
|
|
8
11
|
/**
|
|
9
12
|
* In-process hook seam (design/37) — a provider-agnostic interception layer modeled on CC's hooks,
|
|
@@ -413,15 +416,6 @@ export interface PermissionDeniedPayload {
|
|
|
413
416
|
* thing: stop reading, nobody is waiting for your answer any more. */
|
|
414
417
|
signal?: AbortSignal;
|
|
415
418
|
}
|
|
416
|
-
/**
|
|
417
|
-
* 1.256 复审 MED-1 — observe-only payload isolation for {@link Hooks.permissionDenied}: clone the tool
|
|
418
|
-
* args before they ride the observer payload, so a hook mutating `payload.input` can never pollute the
|
|
419
|
-
* LIVE args object (later events / audit records share it). Same posture as the postToolUseFailure
|
|
420
|
-
* details clone (prepare-task): `structuredClone` first; a non-structured-cloneable graph
|
|
421
|
-
* (functions/handles) falls back to a SHALLOW plain object/array copy (top-level mutation isolated);
|
|
422
|
-
* a non-object primitive passes through as-is (immutable anyway).
|
|
423
|
-
*/
|
|
424
|
-
export declare function cloneObserverInput(input: unknown): unknown;
|
|
425
419
|
/** Context for {@link Hooks.stopFailure} — aligned with the TaskResult error face (observe-only). */
|
|
426
420
|
export interface StopFailureContext {
|
|
427
421
|
/** #281 件A — the run/leg identity envelope (always present on the engine's emission; the seat is
|
|
@@ -901,15 +895,6 @@ export interface UserPromptSubmitResult {
|
|
|
901
895
|
/** Injected ahead of the user's prompt (wrapped as a `<system-reminder>`). */
|
|
902
896
|
additionalContext?: string;
|
|
903
897
|
}
|
|
904
|
-
/** Wrap model-facing hook/gate feedback in a `<system-reminder>` so it reads as guidance, not data.
|
|
905
|
-
* NOTE (council design/74 #6): this does NOT escape a literal `</system-reminder>` in `text` — callers MUST
|
|
906
|
-
* pass trusted, first-party strings (every current caller does: fixed gate/limit messages). If a future
|
|
907
|
-
* caller needs to relay UNTRUSTED content (tool output, user data), it must sanitize the close tag first
|
|
908
|
-
* (or use the `delimitUntrusted` fence), or a crafted payload could break out of the reminder framing.
|
|
909
|
-
* design/319 (A ticket): `mark` is the session's reminder provenance mark — run-scoped callers thread it
|
|
910
|
-
* so the open tag carries the value the system-prompt declaration names (rendered by the mint home; the
|
|
911
|
-
* body is byte-untouched). Absent ⇒ the historic bare open tag (a caller outside a run). */
|
|
912
|
-
export declare function formatHookFeedback(text: string, mark?: string): string;
|
|
913
898
|
/** The outcome of the two-phase tool gate, mapped onto the harness `tool_call` hook return shape. */
|
|
914
899
|
export interface ToolGateResult {
|
|
915
900
|
/** Block execution (the loop emits an error tool result with `reason`). */
|
|
@@ -1082,53 +1067,6 @@ export interface PersistedRuleCoverage {
|
|
|
1082
1067
|
}
|
|
1083
1068
|
/** Every shape a lane may answer with. A bare string stays valid and unchanged. */
|
|
1084
1069
|
export type PersistedRuleAnswer = string | PersistedRuleHit | PersistedRuleCoverage | PersistedRuleUnreadable | undefined;
|
|
1085
|
-
/**
|
|
1086
|
-
* design/252 review r3 — read a foreign {@link OrgGateVerdict} the way the personal-rule answer is read:
|
|
1087
|
-
* OWN DATA properties only, never the prototype chain, never an accessor.
|
|
1088
|
-
*
|
|
1089
|
-
* Unlike the personal-rule normalizer below, this one accepts ANY non-array object as the carrier —
|
|
1090
|
-
* not only a plain record. The two seams tighten in opposite directions when a shape is refused: the
|
|
1091
|
-
* personal lane is a LOOSENING seam, so refusing a class instance degrades toward asking; this answer
|
|
1092
|
-
* carries the org's DENY, and folding a structurally valid `{status:"available", verdict:{behavior:
|
|
1093
|
-
* "deny"}}` class instance into `unavailable` would LOOSEN it — from a deny nobody can approve into a
|
|
1094
|
-
* real-approval ask a person can clear. A class instance's fields are its own data properties, so the
|
|
1095
|
-
* own-data read below already gives the full pollution guarantee (inherited members never authorize);
|
|
1096
|
-
* the prototype test added nothing here but the downgrade.
|
|
1097
|
-
*
|
|
1098
|
-
* The two seams are the same class of trust boundary and were not being read the same way. What that
|
|
1099
|
-
* cost here is worse than on the personal lane, because this answer is GOVERNANCE:
|
|
1100
|
-
* · an inherited `revision` (a polluted `Object.prototype`) stamped a fabricated snapshot version onto
|
|
1101
|
-
* a human's approval request — a WRONG record, which is worse than an absent one;
|
|
1102
|
-
* · an inherited `verdict` invented an org rule, and with it an org ask or deny the lane never gave;
|
|
1103
|
-
* · an answer that is not a record at all read as "available, nothing to say", i.e. the governance
|
|
1104
|
-
* fail-open the availability contract exists to prevent.
|
|
1105
|
-
* Anything this function cannot read as a well-formed answer becomes `unavailable` — the fail-CLOSED
|
|
1106
|
-
* word, never the empty one.
|
|
1107
|
-
*/
|
|
1108
|
-
export declare function normalizeOrgGateVerdict(answer: unknown, unreadable: string): OrgGateVerdict;
|
|
1109
|
-
/**
|
|
1110
|
-
* Normalize the accepted {@link ToolGateInput.persistedRules} answers into one reading.
|
|
1111
|
-
*
|
|
1112
|
-
* `{}` = a clean negative (no rule admits this call). `{ unreadable: true }` = the lane could not read
|
|
1113
|
-
* its source. `{ hit }` = a match, whose `rules` is the non-empty coverage set (design/375). An answer
|
|
1114
|
-
* outside every accepted shape — a number, `null`, an object with neither `rules` nor `unreadable`, an
|
|
1115
|
-
* EMPTY `rules` array, the retired pre-375 `{ rule, dots? }` single-rule object — is read as a clean
|
|
1116
|
-
* negative rather than a match: this is a LOOSENING seam, so an answer nobody can name degrades toward
|
|
1117
|
-
* asking, never toward an allow built on it. All-or-nothing across the set's TEXTS for the same
|
|
1118
|
-
* reason: a set with one unreadable member is a different (smaller) claim than the lane made, and a
|
|
1119
|
-
* decision must not stand on a claim nobody made — one bad member drops the whole answer to the clean
|
|
1120
|
-
* negative. Per-member DOTS stay individually optional (identity lost ⇒ `"not_reported"`, exactly the
|
|
1121
|
-
* single-rule contract).
|
|
1122
|
-
*
|
|
1123
|
-
* The hit's dots are COPIED, not aliased. The array travels onto an ask that may sit in front of a
|
|
1124
|
-
* person for a long time; a lane that retains and mutates its own array would otherwise change what the
|
|
1125
|
-
* approver is looking at, and what an audit later reads, after the evidence was stamped.
|
|
1126
|
-
*/
|
|
1127
|
-
export declare function normalizePersistedRuleHit(hit: PersistedRuleAnswer): {
|
|
1128
|
-
hit?: PersistedRuleHit;
|
|
1129
|
-
unreadable?: true;
|
|
1130
|
-
coverage?: readonly import("./permission-rule-model.js").SegmentCoverage[];
|
|
1131
|
-
};
|
|
1132
1070
|
/** Inputs to the two-phase tool gate. `adjudicate`/`resolveAsk` are pre-bound to the task abort
|
|
1133
1071
|
* signal; when the caller also supplies {@link ToolGateInput.callSignal}, the Runner's closures
|
|
1134
1072
|
* additionally bind their waits to that per-call signal (`AbortSignal.any` of the two), so a turn
|
|
@@ -1645,41 +1583,6 @@ export declare function createPreToolUseConstraintPolicy(preToolUse: NonNullable
|
|
|
1645
1583
|
* walltime and no cancel, the race never fires. So the same seat bound rides here too, and the two
|
|
1646
1584
|
* installations of one callback are now bounded the same way for the same reason. */
|
|
1647
1585
|
timeoutMs?: number): ToolPolicy;
|
|
1648
|
-
/**
|
|
1649
|
-
* The mandate provenance of one call, judged from the SAME mark inputs the gate is driven with —
|
|
1650
|
-
* the single source for "could a persisted allow rule clear this ask?". Allow rules silence the
|
|
1651
|
-
* classifier's questions, never a mandated one, and this predicate is the mandated-family half of
|
|
1652
|
-
* that boundary (the real-approval/governance half rides the decision's own `requiresRealApproval`
|
|
1653
|
-
* bit, which the org layer stamps):
|
|
1654
|
-
* · `probeMandated` — this CALL's own reversibility probe declared its demotion STRUCTURAL
|
|
1655
|
-
* (`"probe_mandate"`), judged FIRST because it is the only per-call member here: the three below
|
|
1656
|
-
* are properties of the TOOL and are true of every call on the seat, so a mandate that is true of
|
|
1657
|
-
* this one call must not be shadowed by the tier that happens to carry it (#502: the built-in
|
|
1658
|
-
* shell probe raises it for a listed reader naming a path outside the session's roots — a boundary
|
|
1659
|
-
* the deployment declared, which is exactly what the classify tier alone cannot say);
|
|
1660
|
-
* · `egress` — the tool's own external-write mark, judged next: it is the tool's declaration even
|
|
1661
|
-
* when the coarse doctrine also installed a shell tier on the same seat;
|
|
1662
|
-
* · `shellGated` + tier `"always"` — the operator's per-call confirmation doctrine
|
|
1663
|
-
* (`"operator_always"`); the classify doctrine installs `"maybe"`, and THOSE asks stay the rule
|
|
1664
|
-
* lane's home turf (`undefined`) — that is the don't-ask-again main case, and the per-call member
|
|
1665
|
-
* above is deliberately the ONLY thing that carves a mandate out of it;
|
|
1666
|
-
* · a tool's OWN `"always"`/`"maybe"` irreversibility tier without the doctrine (`"tool_marks"`).
|
|
1667
|
-
*
|
|
1668
|
-
* Two consumers, one derivation: the gate's silencing arm (a matching rule is disclosed as shadowed
|
|
1669
|
-
* instead of clearing the ask) and the runner's suggestion factory (a mandated ask offers no
|
|
1670
|
-
* "stop asking me this" option — a rule minted from it would never clear it). A drift between the
|
|
1671
|
-
* two would let a card offer a rule the lane then refuses to honor. The per-call member reaches both
|
|
1672
|
-
* the same way every other per-call fact does: the gate stamps it on the surviving ask, the
|
|
1673
|
-
* synchronous sites read it off the decision they spread, and the park leg threads its own parameter.
|
|
1674
|
-
*/
|
|
1675
|
-
export declare function persistedRuleMandateOf(marks: {
|
|
1676
|
-
egress?: boolean;
|
|
1677
|
-
shellGated?: boolean;
|
|
1678
|
-
irreversibility?: "never" | "maybe" | "always";
|
|
1679
|
-
/** #502: the surviving ask's engine-stamped `probeMandated` — see
|
|
1680
|
-
* {@link import("./types.js").ReversibilityVerdict.mandated}. */
|
|
1681
|
-
probeMandated?: boolean;
|
|
1682
|
-
}): "operator_always" | "tool_marks" | "probe_mandate" | undefined;
|
|
1683
1586
|
/**
|
|
1684
1587
|
* The park closure's ONE structural seat — what the gate hands the durable park beyond the twelve
|
|
1685
1588
|
* positional seats. Every member is optional and read by name, so a new thing the park must know
|
|
@@ -1709,4 +1612,20 @@ export declare function askCarryRowMembers(carry: AskCarry | undefined): {
|
|
|
1709
1612
|
denialLimitFallback?: import("./auto-mode.js").DenialLimitFallback;
|
|
1710
1613
|
origin?: import("./ask-origin.js").AskOrigin;
|
|
1711
1614
|
};
|
|
1615
|
+
/**
|
|
1616
|
+
* The design/37 **two-phase tool gate** — the single chokepoint that makes the load-bearing invariant
|
|
1617
|
+
* structural ("a hook's `allow` cannot bypass the policy's `deny`/`ask`"):
|
|
1618
|
+
*
|
|
1619
|
+
* 1. **collect** — run the PreToolUse hook, threading any `updatedInput` rewrite into `currentInput`
|
|
1620
|
+
* and collecting `additionalContext`. A hook `deny` short-circuits to a block immediately; a hook
|
|
1621
|
+
* `ask` is remembered (it does not short-circuit — a later policy `deny` outranks it).
|
|
1622
|
+
* 2. **adjudicate** — run the tool policy on the FINAL `currentInput` (never the model's stale args),
|
|
1623
|
+
* fold it with any remembered hook-ask via `deny > ask > allow`, and resolve a surviving `ask`
|
|
1624
|
+
* through `onAsk`. The policy ALWAYS runs regardless of the hook's verdict. A policy `allow` may
|
|
1625
|
+
* itself carry an `updatedInput` rewrite (redact/clamp), applied last over any hook rewrite.
|
|
1626
|
+
*
|
|
1627
|
+
* Because both phases run in this one linear function, the ordering — and the "policy is final"
|
|
1628
|
+
* invariant — is enforced by the call stack, not by registration convention. Returns the gate result
|
|
1629
|
+
* for the harness `tool_call` hook plus the PreToolUse context to attach to the tool result.
|
|
1630
|
+
*/
|
|
1712
1631
|
export declare function runToolGate(input: ToolGateInput): Promise<ToolGateResult>;
|