@sema-agent/core 7.16.0 → 7.17.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 +209 -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-engine/engine.js +2 -1
- package/dist/core/memory-engine/layout.d.ts +18 -6
- package/dist/core/memory-engine/layout.js +40 -21
- 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/physical-path.d.ts +37 -0
- package/dist/core/physical-path.js +30 -0
- 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 +11 -10
- 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 +52 -0
- package/dist/core/runner/prepare-artifact.js +63 -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-question-face.js +2 -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 +12 -11
- 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 +5 -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 +11 -12
- 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/skills-directory.js +4 -3
- package/dist/core/spec-contract.js +5 -4
- 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 +32 -28
- package/dist/core/task-registry-shared.js +4 -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 +6 -1
- 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 +66 -22
- package/dist/core/tool-policy.js +31 -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 +8 -5
- 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 +20 -14
- package/dist/index.js +16 -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-script-store.js +9 -25
- 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 +237 -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/cc/task-list-store.js +2 -10
- package/dist/stores/file/checkpoint-store.js +1 -5
- package/dist/stores/file/file-history-store.js +2 -2
- package/dist/stores/file/fs-atomic.d.ts +15 -18
- package/dist/stores/file/fs-atomic.js +4 -14
- package/dist/stores/file/mailbox-store.d.ts +7 -11
- package/dist/stores/file/mailbox-store.js +4 -11
- 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 +297 -0
- package/dist/tools/fs/bash-readonly-classifier.d.ts +90 -8
- package/dist/tools/fs/bash-readonly-classifier.js +294 -70
- package/dist/tools/fs/fs-bash.d.ts +14 -10
- package/dist/tools/fs/fs-bash.js +50 -33
- 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 +119 -39
|
@@ -7,6 +7,7 @@ export const TASK_UPDATE_TOOL_NAME = "TaskUpdate";
|
|
|
7
7
|
export const TASK_LIST_TOOL_NAME = "TaskList";
|
|
8
8
|
export const TODO_WRITE_TOOL_NAME = "TodoWrite";
|
|
9
9
|
export const REFRESH_MCP_TOOLS_TOOL_NAME = "RefreshMcpTools";
|
|
10
|
+
export const ARTIFACT_TOOL_NAME = "Artifact";
|
|
10
11
|
const SHELL_RULE_FACE = { primaryParams: ["command"], params: ["command", "timeout", "description", "run_in_background"] };
|
|
11
12
|
const c = (contractId, implementationRevision = "1") => ({ contractId, implementationRevision });
|
|
12
13
|
export const TOOL_CATALOG_ENTRIES = [
|
|
@@ -97,6 +98,10 @@ export const TOOL_CATALOG_ENTRIES = [
|
|
|
97
98
|
},
|
|
98
99
|
{ id: "repo-map", name: "RepoMap", source: "builtin", definedIn: "src/tools/fs/repo-map.ts", mountedBy: ["hands"], cards: ["repo-map"], face: { family: "search", effect: "read", contract: c("core.repo_map@1") } },
|
|
99
100
|
{ id: "lsp", name: "LSP", source: "builtin", definedIn: "src/core/lsp.ts", mountedBy: ["optional"], cards: [], face: { family: "search", effect: "read", contract: c("core.lsp@1") } },
|
|
101
|
+
{
|
|
102
|
+
id: "artifact", name: ARTIFACT_TOOL_NAME, source: "builtin", definedIn: "src/tools/artifact/artifact-tool.ts", mountedBy: ["optional"], cards: ["artifact"],
|
|
103
|
+
face: { family: "other", effect: "write", contract: c("core.artifact@1"), ruleFace: { primaryParams: ["action"] }, renderHints: { summaryParams: ["action", "file_path", "url"] } },
|
|
104
|
+
},
|
|
100
105
|
{ id: "enter-worktree", name: "EnterWorktree", source: "builtin", definedIn: "src/tools/worktree.ts", mountedBy: ["hands"], cards: ["worktree"], face: { family: "other", effect: "write", contract: c("core.enter_worktree@1") } },
|
|
101
106
|
{ id: "exit-worktree", name: "ExitWorktree", source: "builtin", definedIn: "src/tools/worktree.ts", mountedBy: ["hands"], cards: ["worktree"], face: { family: "other", effect: "write", contract: c("core.exit_worktree@1") } },
|
|
102
107
|
{ id: "task-output-hands", name: "TaskOutput", source: "builtin", definedIn: "src/tools/fs/fs-bash.ts", mountedBy: ["hands"], cards: [], face: { family: "delegate", effect: "read", contract: TASK_OUTPUT_CONTRACT } },
|
|
@@ -160,7 +165,7 @@ export function toolFace(id) {
|
|
|
160
165
|
const e = byId.get(id);
|
|
161
166
|
if (e === undefined)
|
|
162
167
|
throw new Error(`tool catalog: no definition ${JSON.stringify(id)}`);
|
|
163
|
-
return structuredClone(e.face);
|
|
168
|
+
return { contentOrigin: "local", ...structuredClone(e.face) };
|
|
164
169
|
}
|
|
165
170
|
function deepFreeze(value) {
|
|
166
171
|
if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
|
|
@@ -18,5 +18,3 @@ export interface ToolConformanceVector {
|
|
|
18
18
|
}
|
|
19
19
|
/** The matrix. Vector ids are stable (a host's own conformance test keys on them). */
|
|
20
20
|
export declare const TOOL_CONFORMANCE_VECTORS: readonly ToolConformanceVector[];
|
|
21
|
-
/** The matrix as a host reads it (a frozen copy). */
|
|
22
|
-
export declare function describeToolConformanceVectors(): readonly ToolConformanceVector[];
|
|
@@ -25,6 +25,7 @@ export const TOOL_CONFORMANCE_VECTORS = [
|
|
|
25
25
|
], [OFFLOAD_READER]),
|
|
26
26
|
vector("plan-mode", ["always", "optional"], [
|
|
27
27
|
{ name: "LSP", why: "needs a wired LSP manager" },
|
|
28
|
+
{ name: "Artifact", why: "needs a wired artifact host" },
|
|
28
29
|
{ name: "Skill", why: "needs a skills listing" },
|
|
29
30
|
{ name: "StructuredOutput", why: "needs an output schema" },
|
|
30
31
|
{ name: "ToolSearch", why: "needs a deferred tool" },
|
|
@@ -32,6 +33,3 @@ export const TOOL_CONFORMANCE_VECTORS = [
|
|
|
32
33
|
{ name: "EnterPlanMode", why: "needs a checkpoint store beside plan mode" },
|
|
33
34
|
]),
|
|
34
35
|
];
|
|
35
|
-
export function describeToolConformanceVectors() {
|
|
36
|
-
return TOOL_CONFORMANCE_VECTORS;
|
|
37
|
-
}
|
|
@@ -27,6 +27,11 @@ export declare function truncateError(s: string): string;
|
|
|
27
27
|
* a file, legacy head+tail middle-omission (there is no path to point at, and the head often carries
|
|
28
28
|
* status a bare tail-keep would drop).
|
|
29
29
|
*/
|
|
30
|
+
/** The smallest output budget the clip primitives are given: below it a clip cannot carry its own
|
|
31
|
+
* truncation banner plus any content, so the operator knobs that feed {@link clipWithFilePointer}
|
|
32
|
+
* (`BASH_MAX_OUTPUT_LENGTH`, `TASK_MAX_OUTPUT_LENGTH`) are raised to it, loudly, never honored as a
|
|
33
|
+
* budget of one character. */
|
|
34
|
+
export declare const OUTPUT_BUDGET_MIN_CHARS = 512;
|
|
30
35
|
export declare function clipWithFilePointer(s: string, limit: number, fullOutputPath?: string): string;
|
|
31
36
|
/**
|
|
32
37
|
* Format a thrown tool error into model-facing text (design/64 §11.1/§11.2): a shell/exec error becomes
|
package/dist/core/tool-errors.js
CHANGED
|
@@ -10,6 +10,7 @@ export function truncateError(s) {
|
|
|
10
10
|
const removed = s.length - head.length - tail.length;
|
|
11
11
|
return `${head}\n\n... [${removed} characters truncated] ...\n\n${tail}`;
|
|
12
12
|
}
|
|
13
|
+
export const OUTPUT_BUDGET_MIN_CHARS = 512;
|
|
13
14
|
export function clipWithFilePointer(s, limit, fullOutputPath) {
|
|
14
15
|
if (s.length <= limit)
|
|
15
16
|
return s;
|
|
@@ -27,7 +27,7 @@ export interface ToolCallRequest {
|
|
|
27
27
|
*/
|
|
28
28
|
face?: ToolCallFace;
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
30
|
+
* The LIVE working directory this call's RELATIVE path arguments will actually resolve
|
|
31
31
|
* against, read at adjudication time from the same tracked `cwdRef` the fs hand tools resolve with
|
|
32
32
|
* (design/64 §16.3: a resident shell's `cd` persists and moves the fs tools' relative base with it).
|
|
33
33
|
*
|
|
@@ -127,6 +127,17 @@ export declare function classifierDenyCauseOf(d: unknown, call: {
|
|
|
127
127
|
toolCallId: string;
|
|
128
128
|
toolName: string;
|
|
129
129
|
}): import("./gate-outcome.js").ClassifierDenyCause | undefined;
|
|
130
|
+
/** Attest that `d` is an in-fold deny of an ask nobody could resolve, for `call`, for the named cause. */
|
|
131
|
+
export declare function attestAskUnresolvableCause<T extends object>(d: T, cause: import("./ask-unresolvable-notice.js").AskUnresolvableCause, call: {
|
|
132
|
+
toolCallId: string;
|
|
133
|
+
toolName: string;
|
|
134
|
+
}): T;
|
|
135
|
+
/** Read the attested unresolvable cause off a deny FOR the named call (the gate's exit is the consumer); a
|
|
136
|
+
* binding to a different call is a replayed object and answers absence. Internal seam — not re-exported. */
|
|
137
|
+
export declare function askUnresolvableCauseOf(d: unknown, call: {
|
|
138
|
+
toolCallId: string;
|
|
139
|
+
toolName: string;
|
|
140
|
+
}): import("./ask-unresolvable-notice.js").AskUnresolvableCause | undefined;
|
|
130
141
|
/** Read the engine-attested settlement off a funneled decision FOR the named call (the gate's exit is the
|
|
131
142
|
* one consumer): an attestation bound to a different call is a replayed object and answers absence.
|
|
132
143
|
* Exported for the gate module only — deliberately NOT re-exported from `src/index.ts` (an internal seam
|
|
@@ -215,7 +226,7 @@ export type PermissionResult = {
|
|
|
215
226
|
message?: string;
|
|
216
227
|
decisionReason?: DecisionReason;
|
|
217
228
|
requiresRealApproval?: boolean;
|
|
218
|
-
/**
|
|
229
|
+
/** This ask is the classifier DENIAL-LIMIT fallback — the block that reached a
|
|
219
230
|
* bound (CC 2.1.250 `FO`, count-then-judge) handed to a person instead of being denied.
|
|
220
231
|
* ENGINE-STAMPED beside `requiresRealApproval: true` and `decisionReason: "classifier"` at the
|
|
221
232
|
* classifier block sites (the gate's own and the inherited-lane arms); carries the COUNTS ONLY —
|
|
@@ -249,7 +260,7 @@ export type PermissionResult = {
|
|
|
249
260
|
* understands (see {@link import("./checkpoint-store.js").ProbeCause}). Engine-stamped and
|
|
250
261
|
* validated at the irreversibility tighten; same display-only posture as the prose sibling. */
|
|
251
262
|
probeCause?: import("./checkpoint-store.js").ProbeCause;
|
|
252
|
-
/**
|
|
263
|
+
/** The reversibility probe declared this demotion STRUCTURAL — see
|
|
253
264
|
* {@link import("./types.js").ReversibilityVerdict.mandated}. Unlike its two `probe*` neighbours
|
|
254
265
|
* this is NOT display metadata: it joins the #144 mandate family, so the persisted-rule lane
|
|
255
266
|
* discloses a matching allow rule as shadowed instead of clearing the ask, and the card's
|
|
@@ -474,7 +485,7 @@ export interface ToolPolicyProjection {
|
|
|
474
485
|
* `session-rule-policy.ts`. Not part of the public API (`src/index.ts` re-exports by name and does not
|
|
475
486
|
* list these two): every publisher of {@link ToolPolicyNameSets} must resolve a covering entry the same
|
|
476
487
|
* way, because the prepare-time audit's exemption for these spellings speaks for ALL published name sets
|
|
477
|
-
* at once — the four in-engine lanes do so by sharing this module's matcher.
|
|
488
|
+
* at once — the four in-engine lanes do so by sharing this module's matcher. That premise is NOT
|
|
478
489
|
* structural for an OUT-OF-ENGINE publisher (a host compiling its own settings into an exact-match ask
|
|
479
490
|
* closure is fail-open on these spellings while the audit stays silent) — which is why the underlying
|
|
480
491
|
* judgment predicates (`isNamespacedCoveringRuleName` / `namespacedRuleNameCovers`) ARE exported from
|
|
@@ -517,7 +528,7 @@ export type ConstraintChainEntryMeta = {
|
|
|
517
528
|
/** True iff the layer carried a frozen auto-mode classifier (`autoMode`). */
|
|
518
529
|
autoModeArmed?: true;
|
|
519
530
|
/**
|
|
520
|
-
*
|
|
531
|
+
* The layer's serializable auto-mode ARMING RECIPE: the criteria half of the frozen classifier
|
|
521
532
|
* (assembly inputs + knobs + the deployment's settings epoch), recorded so a CROSS-PROCESS redemption
|
|
522
533
|
* can rebuild an equivalent decider over its own fresh model leg
|
|
523
534
|
* ({@link import("./auto-mode-arming.js").rebuildAutoModeDecider}) instead of answering `unavailable`
|
|
@@ -753,7 +764,7 @@ export declare function combinePolicies(...policies: ToolPolicy[]): ToolPolicy;
|
|
|
753
764
|
/**
|
|
754
765
|
* The shell tools whose `{ command }` arg a coarse command-name policy parses. Other tools are out of scope.
|
|
755
766
|
*
|
|
756
|
-
*
|
|
767
|
+
* `Monitor` belongs here. It takes a `command` and runs it through the
|
|
757
768
|
* SAME `env.spawnBackground` seam as Bash, and prepare-task's own note says so in as many words — "Monitor
|
|
758
769
|
* runs an arbitrary shell `command` through the SAME env seam — it must sit behind the SAME shellGate
|
|
759
770
|
* tighten (else it becomes a policy side-door around a gated Bash)". The shellGate half was implemented;
|
|
@@ -763,7 +774,7 @@ export declare function combinePolicies(...policies: ToolPolicy[]): ToolPolicy;
|
|
|
763
774
|
* gate at all; the same substitution makes `rm -rf ~/.ai-agent/sessions` a way to erase the audit trail.
|
|
764
775
|
*/
|
|
765
776
|
/**
|
|
766
|
-
*
|
|
777
|
+
* EXPORTED. A downstream governance layer keeps its own copy of this list so its
|
|
767
778
|
* per-command ask-list gates the same tools core does, and it had no way to read the real one — its guard
|
|
768
779
|
* had to probe a hand-written candidate list of names, which stays green for any name nobody thought to
|
|
769
780
|
* put in it. The list itself is the fact; publishing it removes the guess.
|
|
@@ -805,13 +816,11 @@ export declare const COARSE_SHELL_TOOLS: string[];
|
|
|
805
816
|
* you MUST compose explicitly: `combinePolicies(deploymentBaseline, createCoarseCommandNamePolicy(…))`
|
|
806
817
|
* (deny-wins — both policies' denies still fire). {@link tightenTaskSpec} does this for you.
|
|
807
818
|
*
|
|
808
|
-
*
|
|
809
|
-
*
|
|
810
|
-
*
|
|
811
|
-
* command
|
|
812
|
-
*
|
|
813
|
-
* give you a budgetable normal-ask on `bash`; it gives a hard human-approval suspend. Choose `shellGate` and a
|
|
814
|
-
* `defaultAction:"ask"` deliberately.
|
|
819
|
+
* Under `TaskSpec.shellGate: "classify"` a plain `ask` from this policy stays a plain ask: the shell seat's
|
|
820
|
+
* `"maybe"` tier is the doctrine's probe instrument, not a risk label, so the park is the budgetable kind
|
|
821
|
+
* (`human` under `durableApproval`) unless the probe mandated the call (an out-of-root read) or could not
|
|
822
|
+
* answer. A command the doctrine's OWN tighten refuses (`rm -rf …` with no policy asking first) still parks
|
|
823
|
+
* non-budgetable — the safety axis is judged per call by `safetyAxisOf`.
|
|
815
824
|
*/
|
|
816
825
|
export declare function createCoarseCommandNamePolicy(opts: {
|
|
817
826
|
/** Command names (argv[0]) explicitly allowed. If provided, a name NOT listed falls to `defaultAction`. */
|
|
@@ -832,7 +841,7 @@ export declare function findUnverifiableRecursiveDelete(command: string, safeVar
|
|
|
832
841
|
* message carries the CC-sanctioned remediation (re-run with the resolved LITERAL path written into the
|
|
833
842
|
* command, or assign the variable in the same command) — it doubles as the `askMessage` a classifier sees.
|
|
834
843
|
*
|
|
835
|
-
*
|
|
844
|
+
* This used to be an unconditional `deny`, on the theory that the CC rule text forbids
|
|
836
845
|
* auto-allow («must be explicitly approved … cannot be auto-allowed by a permission rule»).
|
|
837
846
|
*
|
|
838
847
|
* RB-341 (2026-07-29) re-checked that citation against the 220 corpus and corrected it in BOTH directions.
|
|
@@ -883,7 +892,7 @@ export declare function findUnverifiableRecursiveDelete(command: string, safeVar
|
|
|
883
892
|
* (already denied). Core wires this policy ALWAYS-ON in the runner's gate composition (prepare-task); it is
|
|
884
893
|
* exported so deployments can also compose/test it directly.
|
|
885
894
|
*
|
|
886
|
-
*
|
|
895
|
+
* `requiresRealApproval` also turns out to be the correct sema analog of the one thing
|
|
887
896
|
* `classifierApprovable: false` still buys in 220 that a `circuitBreaker` does NOT take back — 220's
|
|
888
897
|
* bypassPermissions arm refuses to auto-allow an ask carrying `circuitBreaker === "dangerousRemoval"`
|
|
889
898
|
* (603856-603869), i.e. a blanket MODE setting cannot clear it, only judgment can. That is exactly the
|
|
@@ -942,21 +951,21 @@ export interface AskDelegationProvenance {
|
|
|
942
951
|
* (see {@link OnAsk} for the full detached-settlement contract). */
|
|
943
952
|
export interface AskRequest {
|
|
944
953
|
toolName: string;
|
|
945
|
-
/**
|
|
954
|
+
/** A persisted allow rule MATCHED this call but could not clear the ask (mandated — see
|
|
946
955
|
* {@link PermissionResult}'s ask arm). The matched rule text — or, when a covering SET admitted the
|
|
947
956
|
* command segment-wise (the conjunction arm), a comma-joined display list of up to five sanitized
|
|
948
957
|
* rule texts with an "and N more" tail — so the approval card renders "your rule is alive, just
|
|
949
958
|
* outranked" instead of leaving the person to regex the message prose. A DISPLAY value, not an
|
|
950
959
|
* identity channel: per-rule identity travels on {@link AskRuleEvidence.personalRuleDots}. */
|
|
951
960
|
persistedRuleShadowed?: string;
|
|
952
|
-
/**
|
|
961
|
+
/** WHY the reversibility probe did not clear this call — the account of the tighten the
|
|
953
962
|
* card was showing WITHOUT until now (the gate knew the cause and dropped it at this seam, leaving the
|
|
954
963
|
* approver the action but not the reason it is being asked about). Present only for a `"maybe"`-tier
|
|
955
964
|
* tighten whose probe supplied a cause; the durable park route carries the same string as
|
|
956
965
|
* `RiskDescriptor.probeReason`. Neutralized + length-capped by the gate. UNTRUSTED-for-display,
|
|
957
966
|
* never adjudication input. */
|
|
958
967
|
readonly probeReason?: string;
|
|
959
|
-
/**
|
|
968
|
+
/** The STRUCTURED cause behind the tighten — a machine-readable code plus the operand
|
|
960
969
|
* families as arrays with honest totals, so this surface renders its OWN sentence rather than one the
|
|
961
970
|
* engine had to write before the check's edge cases were known. See
|
|
962
971
|
* {@link import("./checkpoint-store.js").ProbeCause}, whose contract is that the ARRAY is the
|
|
@@ -1149,12 +1158,12 @@ export interface AskRequest {
|
|
|
1149
1158
|
* - `isDelegatedChild` — REFUSAL POSTURE: "no user turn ever lands in this run's transcript";
|
|
1150
1159
|
* drives which deny text the model is told (stop-and-wait vs adapt-or-report), forks included. */
|
|
1151
1160
|
readonly isDelegatedChild?: true;
|
|
1152
|
-
/**
|
|
1161
|
+
/** Carried from the originating {@link PermissionResult}'s ask
|
|
1153
1162
|
* variant of the same name: `true` ⇒ {@link resolveAsk} must not let a blanket `onAsk: "allow"`
|
|
1154
1163
|
* clear this ask (see that field's doc). `readonly`, filled by the gate from the decision, never a
|
|
1155
1164
|
* caller/worker-settable field. */
|
|
1156
1165
|
readonly requiresRealApproval?: boolean;
|
|
1157
|
-
/**
|
|
1166
|
+
/** Present ⇔ this ask is the classifier DENIAL-LIMIT fallback (see the
|
|
1158
1167
|
* {@link PermissionResult} ask-arm member of the same name): the counts that tripped the bound and
|
|
1159
1168
|
* this ask's own auto-deny window. Two readers: a card renders it as a countdown; {@link resolveAsk}
|
|
1160
1169
|
* arms its deadline from `autoDenyAfterMs` (> 0 ⇒ an unanswered function approver auto-denies at
|
|
@@ -1304,7 +1313,7 @@ export type OnAsk = "deny" | "allow" | ((req: AskRequest, signal?: AbortSignal)
|
|
|
1304
1313
|
* (abort, throw, unavailable, out-of-contract value), each already stamped at its own arm, and a
|
|
1305
1314
|
* self-reported one would let a host relabel its refusal as an engine failure.
|
|
1306
1315
|
*
|
|
1307
|
-
*
|
|
1316
|
+
* The ONE ask on this leg the engine DOES time: a classifier denial-limit fallback (the ask
|
|
1308
1317
|
* carrying `denialLimitFallback` with a non-zero `autoDenyAfterMs`). Its window is core's, because
|
|
1309
1318
|
* the fallback exists to bound a classifier that would otherwise deny without end. When it elapses
|
|
1310
1319
|
* the approver's promise is DETACHED (design/384: the wait is released, not cancelled — an approver
|
|
@@ -1390,6 +1399,41 @@ export declare function askApproverIdentity(onAsk: unknown): unknown;
|
|
|
1390
1399
|
* fold and the wiring station) plus the orchestrator, and each reaches DOWN for the one definition.
|
|
1391
1400
|
*/
|
|
1392
1401
|
export declare function isLiveApproverSeat(onAsk: OnAsk | undefined): boolean;
|
|
1402
|
+
/** Where a durable-approval MANDATE on a leg comes from — the closed set of its two sources. */
|
|
1403
|
+
export declare const DURABLE_MANDATE_SOURCES: readonly ["force_durable_gate", "durable_approval"];
|
|
1404
|
+
export type DurableMandateSource = (typeof DURABLE_MANDATE_SOURCES)[number];
|
|
1405
|
+
/**
|
|
1406
|
+
* Is every interactive permission ask of this leg MANDATED to gate durably — and by which source?
|
|
1407
|
+
* `force_durable_gate`: the per-principal control-plane entitlement, in force regardless of any seat.
|
|
1408
|
+
* `durable_approval`: the task's own opt-in with NO live approver seat (a blanket string or nobody at all
|
|
1409
|
+
* cannot answer an ask, so the park is the only honest resolution). A live seat beside the opt-in is not a
|
|
1410
|
+
* mandate: the leg's asks — and its children's, at the same frozen seat — resolve there.
|
|
1411
|
+
*
|
|
1412
|
+
* ONE definition on purpose, like {@link isLiveApproverSeat} beside it: the chain a parent freezes for its
|
|
1413
|
+
* children and the loud "mandated but no store" disclosure at the wiring station used to derive the same
|
|
1414
|
+
* fact with two hand-written conditions, and the second one read only the entitlement — a task that opted
|
|
1415
|
+
* in and had no store degraded to the live chain in silence.
|
|
1416
|
+
*/
|
|
1417
|
+
export declare function durableMandateSourceOf(args: {
|
|
1418
|
+
forceDurableGate: boolean;
|
|
1419
|
+
durableApprovalDeclared: boolean;
|
|
1420
|
+
onAsk: OnAsk | undefined;
|
|
1421
|
+
}): DurableMandateSource | undefined;
|
|
1422
|
+
/**
|
|
1423
|
+
* Has this leg DECLARED a durable park opt-in, from EITHER source (the per-principal
|
|
1424
|
+
* entitlement or the task's own `durableApproval`) — with NO live-seat narrowing. Deliberately
|
|
1425
|
+
* NOT {@link durableMandateSourceOf}: that one asks "is every ask MANDATED to gate durably" (a
|
|
1426
|
+
* live approver seat beside a mere `durableApproval` opt-in defeats the mandate), while this one
|
|
1427
|
+
* asks "does this leg have a durable park FACILITY at all" — the question-face mount decision and
|
|
1428
|
+
* the inherited-mandate float both need the bare declaration, seat or no seat, and had each spelled
|
|
1429
|
+
* `forceDurableGate === true || durableApprovalDeclared` by hand (two call sites, `prepare-
|
|
1430
|
+
* question-face.ts` and `prepare-policy-chain.ts`, one drifting from the other silently if either
|
|
1431
|
+
* grows a third source or a typo'd operator).
|
|
1432
|
+
*/
|
|
1433
|
+
export declare function durableParkOptInDeclared(args: {
|
|
1434
|
+
forceDurableGate: boolean;
|
|
1435
|
+
durableApprovalDeclared: boolean;
|
|
1436
|
+
}): boolean;
|
|
1393
1437
|
/** EXACT structural clone for the approval boundary (alias isolation) — fail-closed, never lossy,
|
|
1394
1438
|
* never identity: a JSON round-trip would silently DROP unclonable members (presented ≠ executing =
|
|
1395
1439
|
* consent misrepresentation) and an identity fallback would hand the approver the live executing
|
package/dist/core/tool-policy.js
CHANGED
|
@@ -2,14 +2,14 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { brandPolicyAskClass } from "./ask-class.js";
|
|
4
4
|
import { sanitizeAutoModeArmingRecipe } from "./auto-mode-arming.js";
|
|
5
|
-
import { join, normalize as normalizePath,
|
|
5
|
+
import { join, normalize as normalizePath, sep } from "node:path";
|
|
6
6
|
import { BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName } from "../tools/fs/index.js";
|
|
7
7
|
import { protectivePathTargetOf } from "./tool-registry.js";
|
|
8
8
|
import { boundInputHashOf } from "./canonical-json.js";
|
|
9
9
|
import { delimitUntrusted, inlineUntrusted, REVIEWER_NOTE_MAX_BODY } from "./untrusted-text.js";
|
|
10
10
|
import { isNamespacedCoveringRuleName, namespacedRuleNameCovers, parsePermissionRule } from "./permission-rules.js";
|
|
11
11
|
import { protocolOf } from "./protocol-table.js";
|
|
12
|
-
import { isAbsolutePathForm,
|
|
12
|
+
import { isAbsoluteForFamily, isAbsolutePathForm, joinForFamily, normalizeAbsPathLexically, pathFamilyOf, writeTargetPath } from "../tools/fs/safety.js";
|
|
13
13
|
const DECISION_REASONS = ["rule", "mode", "hook", "safety", "classifier", "persisted_rule", "sandbox", "org_rule", "org_unavailable", "read_only"];
|
|
14
14
|
const DECISION_REASON_SET = new Set(DECISION_REASONS);
|
|
15
15
|
function settledByNobody(kind) {
|
|
@@ -32,6 +32,9 @@ function transferEngineSettlement(from, to) {
|
|
|
32
32
|
const c = CLASSIFIER_DENY_CAUSES_SEAT.get(from);
|
|
33
33
|
if (c !== undefined)
|
|
34
34
|
CLASSIFIER_DENY_CAUSES_SEAT.set(to, c);
|
|
35
|
+
const u = ASK_UNRESOLVABLE_CAUSES_SEAT.get(from);
|
|
36
|
+
if (u !== undefined)
|
|
37
|
+
ASK_UNRESOLVABLE_CAUSES_SEAT.set(to, u);
|
|
35
38
|
}
|
|
36
39
|
export function carryEngineAttestations(from, to) {
|
|
37
40
|
transferEngineSettlement(from, to);
|
|
@@ -56,6 +59,19 @@ export function classifierDenyCauseOf(d, call) {
|
|
|
56
59
|
return undefined;
|
|
57
60
|
return v.cause;
|
|
58
61
|
}
|
|
62
|
+
const ASK_UNRESOLVABLE_CAUSES_SEAT = new WeakMap();
|
|
63
|
+
export function attestAskUnresolvableCause(d, cause, call) {
|
|
64
|
+
ASK_UNRESOLVABLE_CAUSES_SEAT.set(d, { cause, toolCallId: call.toolCallId, toolName: call.toolName });
|
|
65
|
+
return d;
|
|
66
|
+
}
|
|
67
|
+
export function askUnresolvableCauseOf(d, call) {
|
|
68
|
+
if (typeof d !== "object" || d === null)
|
|
69
|
+
return undefined;
|
|
70
|
+
const v = ASK_UNRESOLVABLE_CAUSES_SEAT.get(d);
|
|
71
|
+
if (v === undefined || v.toolCallId !== call.toolCallId || v.toolName !== call.toolName)
|
|
72
|
+
return undefined;
|
|
73
|
+
return v.cause;
|
|
74
|
+
}
|
|
59
75
|
export function engineSettlementOf(d, call) {
|
|
60
76
|
if (typeof d !== "object" || d === null)
|
|
61
77
|
return undefined;
|
|
@@ -807,9 +823,8 @@ export function createTranscriptIntegrityPolicy(opts) {
|
|
|
807
823
|
const shellTools = canonicalToolNameSet(opts?.tools);
|
|
808
824
|
const dirSegs = dirs.map((d) => pathSegments(d).map(foldPathCase));
|
|
809
825
|
const inProtectedDir = (p, liveCwd) => {
|
|
810
|
-
const rawRelative = !isAbsolutePathForm(p);
|
|
811
|
-
const
|
|
812
|
-
const abs = liveCwd !== undefined && rawRelative ? lexicalPath(joinInFamily(liveCwd, p), home) : lexicalPath(p, home);
|
|
826
|
+
const rawRelative = liveCwd === undefined ? !isAbsolutePathForm(p) : !isAbsoluteForFamily(pathFamilyOf({ root: liveCwd }), p);
|
|
827
|
+
const abs = liveCwd !== undefined && rawRelative ? lexicalPath(normalizeAbsPathLexically(joinForFamily(pathFamilyOf({ root: liveCwd }), liveCwd, p)), home) : lexicalPath(p, home);
|
|
813
828
|
const segs = pathSegments(abs).map(foldPathCase);
|
|
814
829
|
if (isAbsolutePathForm(abs) && dirSegs.some((d) => d.length <= segs.length && d.every((s, i) => s === segs[i])))
|
|
815
830
|
return true;
|
|
@@ -891,6 +906,17 @@ export function askApproverIdentity(onAsk) {
|
|
|
891
906
|
export function isLiveApproverSeat(onAsk) {
|
|
892
907
|
return typeof onAsk === "function";
|
|
893
908
|
}
|
|
909
|
+
export const DURABLE_MANDATE_SOURCES = ["force_durable_gate", "durable_approval"];
|
|
910
|
+
export function durableMandateSourceOf(args) {
|
|
911
|
+
if (args.forceDurableGate)
|
|
912
|
+
return "force_durable_gate";
|
|
913
|
+
if (args.durableApprovalDeclared && !isLiveApproverSeat(args.onAsk))
|
|
914
|
+
return "durable_approval";
|
|
915
|
+
return undefined;
|
|
916
|
+
}
|
|
917
|
+
export function durableParkOptInDeclared(args) {
|
|
918
|
+
return args.forceDurableGate || args.durableApprovalDeclared;
|
|
919
|
+
}
|
|
894
920
|
export function tryCloneArgs(v) {
|
|
895
921
|
try {
|
|
896
922
|
const value = structuredClone(v);
|
|
@@ -35,7 +35,7 @@ export interface AggregateBudgetOptions {
|
|
|
35
35
|
sizeChars: number;
|
|
36
36
|
storeFallback: boolean;
|
|
37
37
|
}) => void;
|
|
38
|
-
/**
|
|
38
|
+
/** Fired once per batch that is STILL over budget after both passes — i.e. the cap did what it
|
|
39
39
|
* could and the request is going out oversized anyway. Reachable when a batch holds more results than
|
|
40
40
|
* the budget can hold even at the minimum preview size (a compact preview has a floor, and N of them
|
|
41
41
|
* cannot be smaller than N × that floor). Before this existed the shortfall was entirely silent, so a
|
|
@@ -25,7 +25,7 @@ export interface ToolResultStore {
|
|
|
25
25
|
* deterministic ref, so `put` for an already-stored ref MUST be a no-op — re-writing would risk a
|
|
26
26
|
* non-identical preview and break the prompt cache). A durable backend treats `ref` as the primary key
|
|
27
27
|
* and should validate/sanitize it (it is composed from sessionId+toolCallId, not raw model input, but a
|
|
28
|
-
* durable store still owns key hygiene for its storage layer).
|
|
28
|
+
* durable store still owns key hygiene for its storage layer). The floor of that hygiene is
|
|
29
29
|
* NOT per-backend — every implementation rejects the unsafe ref set via {@link assertSafeToolResultRef}
|
|
30
30
|
* (a volatile backend silently accepting what a durable one rejects is the drift this closes).
|
|
31
31
|
*
|
|
@@ -139,7 +139,7 @@ export interface ToolResultDeletionReport {
|
|
|
139
139
|
* the read face authorizes by COMPARING fields it already knows; `taskId` is present when the write site
|
|
140
140
|
* has one (it is a narrowing of the session, never a substitute for it).
|
|
141
141
|
*
|
|
142
|
-
*
|
|
142
|
+
* A stamped `taskId` must name a coordinate the read face's CALLER presents —
|
|
143
143
|
* the host's own task/run id — never an engine-internal registry handle id. A handle id lives in a
|
|
144
144
|
* namespace only the engine's in-memory registry can resolve, so an owner stamped with one compares
|
|
145
145
|
* unequal to every caller coordinate forever: the entry becomes readable by NOBODY across the wire
|
|
@@ -181,7 +181,7 @@ export declare function assertToolResultProvenanceMatch(ref: string, stored: Too
|
|
|
181
181
|
* round-tripping through a durable backend (NULL column, missing JSON key) compares equal. */
|
|
182
182
|
export declare function normalizeToolResultProvenance(p: ToolResultProvenance): ToolResultProvenance;
|
|
183
183
|
/**
|
|
184
|
-
*
|
|
184
|
+
* The ref-safety half of the {@link ToolResultStore} contract, shared by every backend.
|
|
185
185
|
*
|
|
186
186
|
* Why it is central and not per-backend: the file backend has always rejected these refs (its path
|
|
187
187
|
* component guard, `stores/file/fs-atomic.ts:48`), while the in-memory backend accepted them
|
|
@@ -207,7 +207,7 @@ export declare function normalizeToolResultProvenance(p: ToolResultProvenance):
|
|
|
207
207
|
*/
|
|
208
208
|
export declare function assertSafeToolResultRef(ref: string): void;
|
|
209
209
|
/**
|
|
210
|
-
*
|
|
210
|
+
* The SINGLE mint point for a tool-result `ref`. Three call sites compose the same
|
|
211
211
|
* `tr_<sessionId>~<toolCallId>` string (`withToolResultOffload` here, the aggregate budget's preview
|
|
212
212
|
* pass, and the runner's clear-with-offload persist); this is that string's one definition.
|
|
213
213
|
*
|
|
@@ -320,7 +320,7 @@ export declare class InMemoryToolResultStore implements ToolResultStore {
|
|
|
320
320
|
private readonly opts?;
|
|
321
321
|
/** put/get only — no scheduled deletion contract: honestly `"none"` (retention.ts). */
|
|
322
322
|
readonly retention: "none";
|
|
323
|
-
/**
|
|
323
|
+
/** The entry is content AND owner as ONE value — the write-once election that decides the
|
|
324
324
|
* content decides the owner in the same step (no window where an entry exists ownerless). */
|
|
325
325
|
private readonly map;
|
|
326
326
|
private totalChars;
|
|
@@ -328,7 +328,7 @@ export declare class InMemoryToolResultStore implements ToolResultStore {
|
|
|
328
328
|
maxTotalChars?: number;
|
|
329
329
|
} | undefined);
|
|
330
330
|
put(ref: string, content: string, provenance?: ToolResultProvenance): void;
|
|
331
|
-
/**
|
|
331
|
+
/** The owner recorded at the winning write; `undefined` for unknown AND for unowned entries,
|
|
332
332
|
* which a read face treats identically (fail-closed). */
|
|
333
333
|
ownerOf(ref: string): ToolResultProvenance | undefined;
|
|
334
334
|
/** Erase this session's entries, selected on the owner recorded at the winning write (the interface
|
|
@@ -370,7 +370,7 @@ export declare class ScopedToolResultStore implements ToolResultStore {
|
|
|
370
370
|
readonly volatileBacking: boolean;
|
|
371
371
|
constructor(inner: ToolResultStore, scope: string);
|
|
372
372
|
/** Length-prefixed namespace — unambiguous for any scope string (no delimiter-injection ambiguity).
|
|
373
|
-
*
|
|
373
|
+
* The scope segment is ENCODED (injective, and its output charset carries no path separator
|
|
374
374
|
* or control character), so a deployment whose trust scope contains one cannot compose a key the
|
|
375
375
|
* inner store must reject — the ref-safety rule then applies to the caller's ref alone. */
|
|
376
376
|
private key;
|
|
@@ -379,7 +379,7 @@ export declare class ScopedToolResultStore implements ToolResultStore {
|
|
|
379
379
|
offset?: number;
|
|
380
380
|
limit?: number;
|
|
381
381
|
}): Promise<ToolResultSlice | undefined> | ToolResultSlice | undefined;
|
|
382
|
-
/**
|
|
382
|
+
/** Same namespacing as {@link get}. `undefined` when the inner store predates the operation
|
|
383
383
|
* (an unowned answer, which the read face reads fail-closed — never a fabricated owner). */
|
|
384
384
|
ownerOf(ref: string): Promise<ToolResultProvenance | undefined> | ToolResultProvenance | undefined;
|
|
385
385
|
/** THIS task's offload count only — the D-2 gate's per-task semantics (see class doc). */
|
|
@@ -390,10 +390,10 @@ export declare function isVolatileOffloadStore(store: ToolResultStore): boolean;
|
|
|
390
390
|
/** Reserved name of the injected large-result reader (design/108 PascalCase: `read_tool_result`→`ReadToolResult`). */
|
|
391
391
|
export declare const OFFLOAD_TOOL_NAME = "ReadToolResult";
|
|
392
392
|
/**
|
|
393
|
-
*
|
|
393
|
+
* The runner's clear-with-offload persist, as ONE construction point (the closure used to
|
|
394
394
|
* live inline in prepare-task). Fire-and-forget by design (the caller returns the ref synchronously).
|
|
395
395
|
*
|
|
396
|
-
*
|
|
396
|
+
* A failed put REPORTS the loss, it never writes under the ref. The previous arm
|
|
397
397
|
* wrote a lost-marker row under the SAME ref "so the page-back face reports the true cause", and that
|
|
398
398
|
* one write carried two defects:
|
|
399
399
|
* - **revival**: the put and a session purge can race. When the put loses, the marker write lands
|
|
@@ -450,7 +450,7 @@ export declare const DEFAULT_TOOL_RESULT_THRESHOLD_CHARS = 20000;
|
|
|
450
450
|
* the per-message aggregate budget (design/64 §17.2) produces the SAME preview format (deterministic →
|
|
451
451
|
* byte-identical across queries → prompt-cache safe).
|
|
452
452
|
*
|
|
453
|
-
*
|
|
453
|
+
* The truncation line states WHERE the rest is, not what anyone can do with it.
|
|
454
454
|
* "read more" alone reads as a promise that the full output is retrievable, and the model relays that
|
|
455
455
|
* promise to the person it is talking to; what is actually guaranteed is narrower and exactly two
|
|
456
456
|
* things: the text is retained in this run's tool-result store, and THIS chain can page it back. A
|
package/dist/core/tool-spec.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ export interface ReversibilityVerdict {
|
|
|
48
48
|
* a malformed value costs the DISCLOSURE only, never the ask. */
|
|
49
49
|
cause?: import("./checkpoint-store.js").ProbeCause;
|
|
50
50
|
/**
|
|
51
|
-
*
|
|
51
|
+
* This demotion is STRUCTURAL, not the probe hesitating: the call crosses a
|
|
52
52
|
* boundary the deployment declared, so a persisted allow rule must not retire the resulting ask.
|
|
53
53
|
* The gate folds it into the #144 mandate family ("allow rules silence the CLASSIFIER's questions,
|
|
54
54
|
* never a MANDATED one") beside an operator `shellGate:"always"` and the tool's own
|
|
@@ -385,7 +385,7 @@ export interface ToolSpec<TParams extends TSchema = TSchema> {
|
|
|
385
385
|
*/
|
|
386
386
|
defer?: boolean;
|
|
387
387
|
/**
|
|
388
|
-
*
|
|
388
|
+
* Inline-keep override, judged FIRST in the deferral chain (CC 220 counterpart:
|
|
389
389
|
* `alwaysLoad`, declared per MCP tool via `_meta["anthropic/alwaysLoad"]`, whose `isDeferredTool`
|
|
390
390
|
* checks it before every deferral arm): `true` pins this tool's full schema inline in every
|
|
391
391
|
* request — it is never deferred, regardless of its own {@link defer}, {@link TaskSpec.deferTools},
|
|
@@ -493,7 +493,7 @@ export type ToolReturn = string | {
|
|
|
493
493
|
/** Hint the agent to stop after this tool batch. */
|
|
494
494
|
terminate?: boolean;
|
|
495
495
|
/**
|
|
496
|
-
*
|
|
496
|
+
* A `ToolSpec.execute` can RETURN a failure
|
|
497
497
|
* receipt instead of throwing (teaching errors that carry structured `details`, e.g. an
|
|
498
498
|
* unrecoverable-but-informative rejection). Before this field existed, `ToolReturn` had NO
|
|
499
499
|
* isError channel at all — `defineTool`'s wrapper builds a fresh `{content,details,terminate}`
|
|
@@ -872,21 +872,15 @@ export interface ToolExecuteContext {
|
|
|
872
872
|
*/
|
|
873
873
|
interactiveTools?: false;
|
|
874
874
|
/**
|
|
875
|
-
*
|
|
875
|
+
* Read-only mirror of {@link "./types.js".TaskSpec.oneShot} (same trust tier/seat as
|
|
876
876
|
* `principal`): this RUN has no later turn for an async background notification to land in (a
|
|
877
877
|
* headless `-p` process exits once the turn ends). A delegation tool (`createSubagentTool`) reads
|
|
878
878
|
* it to branch its background-launch RECEIPT toward an active block-wait instruction instead of
|
|
879
|
-
* "end your turn and wait" —
|
|
880
|
-
*
|
|
879
|
+
* "end your turn and wait" — the Workflow tool branches its launch receipt the same way off the seat it is
|
|
880
|
+
* mounted with (`RunWorkflowToolDeps.parentSpecSeat.oneShot`). The CHILDREN's copy rides {@link parentSpecSeat}
|
|
881
|
+
* (only `true` travels there). Undefined when the tool runs outside a Runner task.
|
|
881
882
|
*/
|
|
882
883
|
oneShot?: boolean;
|
|
883
|
-
/**
|
|
884
|
-
* design/112 C1/C5 — read-only SNAPSHOT of the parent task's client-supplied USER facts (timeZone/userEmail),
|
|
885
|
-
* inherited verbatim down the delegation tree like `principal`, so a subagent/fork child's
|
|
886
|
-
* `# Environment` block localizes "today" to the SAME user zone (not the container's UTC) and names the same
|
|
887
|
-
* user. Runner-filled (NOT a tool argument). Undefined when the task carries no clientContext.
|
|
888
|
-
*/
|
|
889
|
-
clientContext?: TaskSpec["clientContext"];
|
|
890
884
|
/** — the parent's tool-face controls ({@link TaskSpec.excludeTools} /
|
|
891
885
|
* {@link TaskSpec.deferTools}), inherited down the delegation tree like `principal` (Runner-filled,
|
|
892
886
|
* read-only): a scenario-wide roster must not be escapable by delegating to a child that remounts
|
|
@@ -911,30 +905,32 @@ export interface ToolExecuteContext {
|
|
|
911
905
|
* tool-face controls (Runner-filled): a classic-profile parent's children speak classic too
|
|
912
906
|
* unless the child spec says otherwise (child spec wins — profile is presentation, not policy). */
|
|
913
907
|
promptProfile?: "simple" | "classic";
|
|
914
|
-
/**
|
|
915
|
-
*
|
|
916
|
-
*
|
|
917
|
-
*
|
|
918
|
-
*
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
*
|
|
922
|
-
*
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
*
|
|
926
|
-
*
|
|
927
|
-
*
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
*
|
|
933
|
-
*
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
*
|
|
937
|
-
*
|
|
908
|
+
/**
|
|
909
|
+
* The parent SPEC seat this run hands its children ({@link import("./parent-spec-seat.js").ParentSpecSeat}):
|
|
910
|
+
* `principal`, `oneShot` (only `true`), `clientContext` (the user's TZ/email facts), `onQuestion` (the FROZEN
|
|
911
|
+
* question face — `AskUserQuestion` mounts on it), `additionalDirectories` / `additionalReadDirectories` (the
|
|
912
|
+
* fs-fence widening; the read-only half stays read-only in transit), `envFacts` (the sandbox facts), and the
|
|
913
|
+
* DECLARED `memoryPersistenceCapable`. Runner-filled, read-only, NEVER a model/tool argument; minted ONCE per
|
|
914
|
+
* prepare from the run's rebound spec + frozen question face (arrays and the facts object frozen copies). ABSENT
|
|
915
|
+
* when the tool runs outside a Runner task.
|
|
916
|
+
*
|
|
917
|
+
* A delegation tool applies it onto every child spec it builds with `applyParentSpecSeat` — the ONE law both
|
|
918
|
+
* delegation lanes (Task and Workflow) share: a value the child spec already carries WINS (an agent definition's
|
|
919
|
+
* own declaration, a deployment baseline, a trusted script), the seat FILLS an unset one, and the two REMOVAL
|
|
920
|
+
* values (`oneShot: true`, `memoryPersistenceCapable: false`) land unconditionally. A deployment that widened the
|
|
921
|
+
* fs fence widened it for the TASK, a per-request question face is the child's face too, a one-shot process is
|
|
922
|
+
* one-shot for the whole tree — none of that stops at one level.
|
|
923
|
+
*/
|
|
924
|
+
parentSpecSeat?: import("./parent-spec-seat.js").ParentSpecSeat;
|
|
925
|
+
/** This run's per-request question face was STRIPPED by the engine (`RunInternals.questionFaceStripped` — the leg outlives
|
|
926
|
+
* the request that spawned it), Runner-filled read-only. A delegation tool forwards it onto every descendant's internals:
|
|
927
|
+
* the descendants are faceless by the same engine act, so the posture door's exemption travels with them. */
|
|
928
|
+
questionFaceStripped?: true;
|
|
929
|
+
/**
|
|
930
|
+
* The parent task's DECLARED {@link TaskSpec.memoryPersistenceCapable} as THIS run's own fact — present ONLY when
|
|
931
|
+
* the spec set it (an inferred run's ctx gains no key), Runner-filled on the same trusted seat as {@link principal}:
|
|
932
|
+
* never a model/tool argument. Read by the revival spawner as the waking run's own clamp (a declared `false` forces
|
|
933
|
+
* the read-only-memory disclosure onto the cycle it wakes). The CHILDREN's copy rides {@link parentSpecSeat}.
|
|
938
934
|
*/
|
|
939
935
|
memoryPersistenceCapable?: boolean;
|
|
940
936
|
/**
|
|
@@ -954,7 +950,7 @@ export interface ToolExecuteContext {
|
|
|
954
950
|
*/
|
|
955
951
|
memoryCaptureOptedOut?: boolean | Promise<boolean>;
|
|
956
952
|
/**
|
|
957
|
-
* design/383 §2.5
|
|
953
|
+
* design/383 §2.5 — the floor seat's THIRD state: TRUE ⇔ the spawning
|
|
958
954
|
* session's capture opt-out state is INDETERMINATE at the moment a delegation tool reads this
|
|
959
955
|
* seat (its capture record store is faulting, and no genuine record is known in-process). The
|
|
960
956
|
* delegation lanes forward it into the child's trusted internals as the floor's indeterminate
|
package/dist/core/tools.d.ts
CHANGED
|
@@ -44,7 +44,7 @@ export declare function stampDefineToolBrand<T extends object>(tool: T, rebind:
|
|
|
44
44
|
*/
|
|
45
45
|
export declare function rebindDefineToolCtx(product: AgentTool, enrich: ToolCtxEnricher): AgentTool;
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
47
|
+
* A per-call ctx builder a MOUNT hands to {@link defineTool}.
|
|
48
48
|
*
|
|
49
49
|
* Why the seat exists: the adapter below feeds the inner `ToolSpec.execute` a `{toolCallId, signal}`
|
|
50
50
|
* ctx, because `AgentTool.execute(toolCallId, rawParams, signal, onUpdate)` — the contract every
|
|
@@ -72,7 +72,7 @@ export type ToolCtxEnricher = (base: ToolExecuteContext) => ToolExecuteContext;
|
|
|
72
72
|
* typing accepts without needing the name.
|
|
73
73
|
*/
|
|
74
74
|
export interface DefineToolOptions {
|
|
75
|
-
/**
|
|
75
|
+
/** See {@link ToolCtxEnricher}. Absent ⇒ the inner spec sees exactly the pre-RB-409
|
|
76
76
|
* `{toolCallId, signal}` ctx, so every mount that does not opt in stays byte-identical. */
|
|
77
77
|
enrichCtx?: ToolCtxEnricher;
|
|
78
78
|
}
|