@sema-agent/core 7.40.1 → 7.41.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 +188 -0
- package/dist/agents/agent-transcript-tool.d.ts +10 -2
- package/dist/agents/agent-transcript-tool.js +52 -26
- package/dist/agents/list-agents-tool.d.ts +17 -2
- package/dist/agents/list-agents-tool.js +28 -16
- package/dist/agents/peer-session-drain.d.ts +3 -1
- package/dist/agents/peer-session-drain.js +1 -0
- package/dist/agents/subagent-steps.d.ts +12 -2
- package/dist/agents/subagent-steps.js +8 -4
- package/dist/agents/subagent.d.ts +1 -17
- package/dist/agents/subagent.js +12 -24
- package/dist/core/agent-definition.d.ts +19 -40
- package/dist/core/agent-state.d.ts +91 -0
- package/dist/core/agent-state.js +79 -0
- package/dist/core/ask-origin.d.ts +28 -6
- package/dist/core/ask-origin.js +9 -5
- package/dist/core/ask-unresolvable-notice.d.ts +27 -4
- package/dist/core/ask-unresolvable-notice.js +8 -0
- package/dist/core/auto-promote.d.ts +14 -27
- package/dist/core/auto-promote.js +5 -5
- package/dist/core/checkpoint-store.d.ts +11 -12
- package/dist/core/decision-receipt.d.ts +5 -2
- package/dist/core/decision-receipt.js +1 -1
- package/dist/core/engine-notice.d.ts +7 -1
- package/dist/core/gate-crash-trace.d.ts +1 -1
- package/dist/core/gate-fold.js +7 -3
- package/dist/core/gate-lanes.js +22 -3
- package/dist/core/governance-codes.d.ts +3 -1
- package/dist/core/governance-codes.js +3 -0
- package/dist/core/hooks.d.ts +20 -6
- package/dist/core/hooks.js +28 -28
- package/dist/core/mcp-tool-meta.d.ts +24 -0
- package/dist/core/mcp-tool-meta.js +17 -0
- package/dist/core/mcp.d.ts +1 -6
- package/dist/core/mcp.js +6 -7
- package/dist/core/mode-policy.d.ts +25 -0
- package/dist/core/mode-policy.js +8 -0
- package/dist/core/protocol-table.d.ts +3 -0
- package/dist/core/protocol-table.js +3 -0
- package/dist/core/reminder-mint.d.ts +21 -1
- package/dist/core/reminder-mint.js +20 -0
- package/dist/core/retired-keys.d.ts +2 -1
- package/dist/core/retired-keys.js +13 -2
- package/dist/core/rule-denial-sentence.d.ts +2 -2
- package/dist/core/runner/call-hook-stations.d.ts +106 -0
- package/dist/core/runner/call-hook-stations.js +118 -0
- package/dist/core/runner/contracts.d.ts +35 -25
- package/dist/core/runner/gate-exit.d.ts +5 -1
- package/dist/core/runner/gate-exit.js +10 -6
- package/dist/core/runner/prepare-delegation-surface.d.ts +1 -0
- package/dist/core/runner/prepare-delegation-surface.js +4 -4
- package/dist/core/runner/prepare-gate-stations.d.ts +8 -3
- package/dist/core/runner/prepare-gate-stations.js +13 -70
- package/dist/core/runner/prepare-inherited-gate.d.ts +6 -3
- package/dist/core/runner/prepare-inherited-gate.js +5 -3
- package/dist/core/runner/prepare-park-ask.d.ts +4 -0
- package/dist/core/runner/prepare-park-ask.js +4 -1
- package/dist/core/runner/prepare-policy-chain.d.ts +6 -5
- package/dist/core/runner/prepare-policy-chain.js +14 -25
- package/dist/core/runner/prepare-project-context.d.ts +15 -16
- package/dist/core/runner/prepare-project-context.js +15 -11
- package/dist/core/runner/prepare-run-refs.d.ts +8 -8
- package/dist/core/runner/prepare-run-refs.js +3 -3
- package/dist/core/runner/prepare-safety-scan.js +3 -3
- package/dist/core/runner/prepare-suspend-saga.d.ts +2 -1
- package/dist/core/runner/prepare-suspend-saga.js +2 -1
- package/dist/core/runner/prepare-task.js +14 -12
- package/dist/core/runner/prepare-turn-wiring.d.ts +3 -1
- package/dist/core/runner/prepare-turn-wiring.js +16 -13
- package/dist/core/runner/resume-admission.js +2 -1
- package/dist/core/runner/resume-apply.js +12 -23
- package/dist/core/runner/resume-checkpoint-screen.js +3 -0
- package/dist/core/runner/run-leg.js +61 -47
- package/dist/core/runner/runtask.d.ts +1 -1
- package/dist/core/runner/session-rule-policy.d.ts +7 -19
- package/dist/core/runner/session-rule-policy.js +1 -2
- package/dist/core/runner/skill-base-dir.d.ts +10 -0
- package/dist/core/runner/skill-base-dir.js +4 -0
- package/dist/core/runner/synthetic-tools.d.ts +11 -17
- package/dist/core/runner/synthetic-tools.js +7 -8
- package/dist/core/safety-axis-vocab.d.ts +2 -2
- package/dist/core/safety-axis-vocab.js +2 -0
- package/dist/core/session-policy-store.d.ts +63 -11
- package/dist/core/session-policy-store.js +52 -6
- package/dist/core/skill-grant.d.ts +239 -0
- package/dist/core/skill-grant.js +313 -0
- package/dist/core/skills-directory.d.ts +5 -34
- package/dist/core/skills-directory.js +9 -58
- package/dist/core/task-registry-agent.d.ts +14 -2
- package/dist/core/task-registry-agent.js +23 -8
- package/dist/core/task-registry-shared.d.ts +6 -0
- package/dist/core/task-registry.d.ts +16 -0
- package/dist/core/task-registry.js +19 -6
- package/dist/core/task-spec.d.ts +10 -0
- package/dist/core/tool-face.d.ts +3 -2
- package/dist/core/tool-name-aliases.d.ts +38 -12
- package/dist/core/tool-name-aliases.js +16 -0
- package/dist/core/tool-name-readings.d.ts +6 -2
- package/dist/core/tool-name-readings.js +6 -4
- package/dist/core/tool-policy.d.ts +2 -2
- package/dist/core/tool-registry.d.ts +1 -4
- package/dist/core/tool-registry.js +0 -3
- package/dist/core/tool-spec.d.ts +11 -13
- package/dist/core/tools.d.ts +1 -1
- package/dist/core/trace.d.ts +15 -0
- package/dist/core/types.d.ts +1 -1
- package/dist/engine/harness/agent-harness.d.ts +12 -1
- package/dist/engine/harness/agent-harness.js +17 -13
- package/dist/engine/loop/agent-loop.d.ts +16 -1
- package/dist/engine/loop/agent-loop.js +9 -15
- package/dist/engine/loop/types.d.ts +2 -0
- package/dist/index.d.ts +9 -4
- package/dist/index.js +4 -2
- package/dist/stores/file/adoption/adopt.js +23 -16
- package/dist/stores/file/index.d.ts +8 -2
- package/dist/stores/file/index.js +2 -2
- package/dist/stores/file/mailbox-store.js +2 -2
- package/dist/stores/file/permission-rule-adopt.js +10 -1
- package/dist/stores/file/permission-rule-store.d.ts +6 -4
- package/dist/stores/file/permission-rule-store.js +127 -59
- package/dist/stores/file/session-policy-store.d.ts +86 -14
- package/dist/stores/file/session-policy-store.js +135 -118
- package/dist/stores/file/task-list-store.d.ts +5 -0
- package/dist/stores/file/task-list-store.js +18 -4
- package/dist/stores/file/usage-window-store.d.ts +9 -1
- package/dist/stores/file/usage-window-store.js +47 -33
- package/dist/tools/fs/safety.d.ts +1 -1
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +45 -5
- package/wire-changes/core@7.41.0.json +1865 -0
- package/dist/core/runner/active-skill-scope.d.ts +0 -58
- package/dist/core/runner/active-skill-scope.js +0 -133
- package/dist/core/skill-tool-specifier.d.ts +0 -80
- package/dist/core/skill-tool-specifier.js +0 -57
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-call hook stations a tool call passes OUTSIDE the tool gate. ONE rule for every executed call, live or
|
|
3
|
+
* approved on a parked checkpoint: before it runs, the PreToolUse screening seat; after it runs, the `tool_result`
|
|
4
|
+
* station (the PostToolUse / PostToolUseFailure seats and the PreToolUse context drain).
|
|
5
|
+
* · a LIVE call meets the screening inside the gate and the station through the loop's finalize (the gate-stations
|
|
6
|
+
* phase registers the station on the harness);
|
|
7
|
+
* · an APPROVED call meets {@link createApprovedCallScreen} — the SAME seat (`createPreToolUseScreening`), folded under
|
|
8
|
+
* the decide that approved it — and the station through `AgentHarness.finalizeToolCall`, the loop's own finalize.
|
|
9
|
+
*/
|
|
10
|
+
import type { DocumentContent, ImageContent, TextContent } from "../../internal/llm.js";
|
|
11
|
+
import { type HookEnvCapabilities, type HookInvocationIdentity, type Hooks } from "../hooks.js";
|
|
12
|
+
import type { PermissionModeController } from "../mode-policy.js";
|
|
13
|
+
import type { TaskSpec } from "../types.js";
|
|
14
|
+
import type { CwdRef } from "../../tools/fs/fs-shared.js";
|
|
15
|
+
import { type ToolRosterDeltaSeat } from "../tool-roster.js";
|
|
16
|
+
import { type FrameSettlement } from "../frame-settlement.js";
|
|
17
|
+
import type { Prepared } from "./contracts.js";
|
|
18
|
+
import type { Checkpoint } from "../checkpoint-store.js";
|
|
19
|
+
/** One executed call's result as the station reads it (the harness `tool_result` event's members). */
|
|
20
|
+
export interface ToolResultSeatEvent {
|
|
21
|
+
toolCallId: string;
|
|
22
|
+
toolName: string;
|
|
23
|
+
input: Record<string, unknown>;
|
|
24
|
+
content: Array<TextContent | ImageContent | DocumentContent>;
|
|
25
|
+
details: unknown;
|
|
26
|
+
isError: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** The station: the patch the loop applies to the result (`undefined` = unchanged). */
|
|
29
|
+
export type ToolResultStation = (e: ToolResultSeatEvent) => Promise<{
|
|
30
|
+
content: Array<TextContent | ImageContent | DocumentContent>;
|
|
31
|
+
} | undefined>;
|
|
32
|
+
export interface ToolResultStationInput {
|
|
33
|
+
/** borrowed-readonly — the resolved hook record: the two post seats and the failure seat, called through the record. */
|
|
34
|
+
hooks: Hooks | undefined;
|
|
35
|
+
/** borrowed-mutable — the blocked/suspended call ids. Writer here: the one-shot `delete`. */
|
|
36
|
+
blockedToolCalls: Set<string>;
|
|
37
|
+
/** borrowed-readonly — the leg's delta seat: the post seats receive the call's wire name off its current roster. */
|
|
38
|
+
toolRosterDeltas: ToolRosterDeltaSeat;
|
|
39
|
+
/** borrowed-mutable — PreToolUse `additionalContext` per call id. Writer here: the one-shot drain (`delete`). */
|
|
40
|
+
preToolContexts: Map<string, string[]>;
|
|
41
|
+
/** borrowed-readonly — the validated per-prepare hook seat bound. */
|
|
42
|
+
hookTimeoutMs: number;
|
|
43
|
+
/** borrowed-readonly — prepare's abort seat; `.signal` bounds the post seats and is the failure seat's interrupt fact. */
|
|
44
|
+
abortController: {
|
|
45
|
+
readonly signal: AbortSignal;
|
|
46
|
+
};
|
|
47
|
+
/** borrowed-readonly — the REBOUND spec's `signal` (the failure seat's interrupt fact). */
|
|
48
|
+
spec: Pick<TaskSpec, "signal">;
|
|
49
|
+
/** borrowed-readonly — the hand's live tracked cwd, or undefined; `current` is read per post seat. */
|
|
50
|
+
handsCwdRef: CwdRef | undefined;
|
|
51
|
+
/** borrowed-readonly — the env face the post seats' contexts carry, or undefined. */
|
|
52
|
+
hookEnvFace: HookEnvCapabilities | undefined;
|
|
53
|
+
/** borrowed-readonly — the leg's identity envelope every HookToolContext carries. */
|
|
54
|
+
hookIdentity: HookInvocationIdentity;
|
|
55
|
+
/** borrowed-readonly — the leg's live permission-mode seat (each context reads `observed`). */
|
|
56
|
+
permissionMode: PermissionModeController;
|
|
57
|
+
/** borrowed-readonly — where an expired post seat is reported (the leg's own hook-crash lane). */
|
|
58
|
+
notifyOwnHookCrash: (err: unknown) => void;
|
|
59
|
+
/** borrowed-readonly — the leg's reminder provenance mark (every hook context line carries it). */
|
|
60
|
+
reminderMark: string;
|
|
61
|
+
/** borrowed-mutable — the leg's settlement seam. Writer here: a carrier whose output a host hook rewrote (`noteHostRewrite`). */
|
|
62
|
+
frameSettlement: FrameSettlement;
|
|
63
|
+
}
|
|
64
|
+
/** The `tool_result` station, or undefined when no post / screening hook is wired (nothing to register). */
|
|
65
|
+
export declare function createToolResultStation(input: ToolResultStationInput): ToolResultStation | undefined;
|
|
66
|
+
/** What the resumed leg does with the approved call: refuse it with a sentence (it is NOT executed), or run these bytes.
|
|
67
|
+
* `admit` stashes the screen's context for the result's drain — called only once the call is past every belt and about
|
|
68
|
+
* to run (a refused call stashes nothing, the live gate's rule). */
|
|
69
|
+
export type ApprovedCallScreen = NonNullable<Prepared["approvedCallScreen"]>;
|
|
70
|
+
export type ApprovedCallVerdict = Awaited<ReturnType<ApprovedCallScreen>>;
|
|
71
|
+
export interface ApprovedCallScreenInput {
|
|
72
|
+
/** borrowed-readonly — the face the gate screens with (the observational wrapper when declared; the leg's mode on every context). */
|
|
73
|
+
preToolUse: Hooks["preToolUse"] | undefined;
|
|
74
|
+
/** borrowed-readonly — the validated per-prepare hook seat bound. */
|
|
75
|
+
hookTimeoutMs: number;
|
|
76
|
+
/** borrowed-readonly — prepare's abort seat (the screening seat is abort-ended on it). */
|
|
77
|
+
abortController: {
|
|
78
|
+
readonly signal: AbortSignal;
|
|
79
|
+
};
|
|
80
|
+
/** borrowed-readonly — the hand's live tracked cwd, or undefined. */
|
|
81
|
+
handsCwdRef: CwdRef | undefined;
|
|
82
|
+
/** borrowed-readonly — the read-only env capability face, or undefined. */
|
|
83
|
+
hookEnvFace: HookEnvCapabilities | undefined;
|
|
84
|
+
/** borrowed-readonly — the leg's identity envelope. */
|
|
85
|
+
hookIdentity: HookInvocationIdentity;
|
|
86
|
+
/** borrowed-readonly — the own hook-crash reporter (a crashing or timed-out screening face is reported through it). */
|
|
87
|
+
notifyOwnHookCrash: (err: unknown) => void;
|
|
88
|
+
/** borrowed-mutable — PreToolUse `additionalContext` per call id. Writer here: `admit`'s stash (the station drains it). */
|
|
89
|
+
preToolContexts: Map<string, string[]>;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The approved call's PreToolUse screening — the gate's own seat, its answer FOLDED UNDER THE DECIDE that approved the
|
|
93
|
+
* call (the decide is the upper bound; the screen can only narrow): a deny, a crash, a silence or a refused answer
|
|
94
|
+
* refuses the call in the live gate's own sentences; an ask is the question the decide already answered — unless it
|
|
95
|
+
* demands a person and the decide was the deployment's policy (the one predicate every resume station holds a decide
|
|
96
|
+
* against); a rewrite is what executes when the decide carried none of its own (the person's bytes are the upper bound);
|
|
97
|
+
* context rides the result. Undefined when no face is wired.
|
|
98
|
+
*/
|
|
99
|
+
export declare function createApprovedCallScreen(input: ApprovedCallScreenInput): ApprovedCallScreen | undefined;
|
|
100
|
+
/**
|
|
101
|
+
* Why the frozen inherited chain cannot judge bytes no gate judged (an approver's edit, the re-screen's rewrite): the
|
|
102
|
+
* row predates the chain, a layer is opaque, or a layer declares a live remainder — undefined when the frozen
|
|
103
|
+
* projections can judge them, or when no parent constraint binds. ONE rule for the pre-claim edit rung (which refuses
|
|
104
|
+
* the edit, the row pending) and the resumed leg's belt (which refuses a rewrite, the approval spent).
|
|
105
|
+
*/
|
|
106
|
+
export declare function chainCannotJudge(ig: Checkpoint["state"]["inheritedGate"]): string | undefined;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { createPreToolUseScreening, formatHookFeedback, hookSeatExpiredError, runHookSeat } from "../hooks.js";
|
|
2
|
+
import { isEngineRefusal } from "../tool-policy.js";
|
|
3
|
+
import { policyCannotAnswer } from "../real-approval.js";
|
|
4
|
+
import { traceHookCrash } from "../gate-crash-trace.js";
|
|
5
|
+
import { createSafeNotifier } from "../safe-notify.js";
|
|
6
|
+
import { rosterToolName } from "../tool-roster.js";
|
|
7
|
+
import { wireOf } from "../tool-name-readings.js";
|
|
8
|
+
import { noteHostRewrite } from "../frame-settlement.js";
|
|
9
|
+
export function createToolResultStation(input) {
|
|
10
|
+
const { hooks, blockedToolCalls, toolRosterDeltas, preToolContexts, hookTimeoutMs, abortController, spec, handsCwdRef, hookEnvFace, hookIdentity, permissionMode, notifyOwnHookCrash, reminderMark, frameSettlement } = input;
|
|
11
|
+
const toolResultStationArmed = Boolean(hooks?.postToolUse || hooks?.preToolUse || hooks?.postToolUseFailure);
|
|
12
|
+
if (toolResultStationArmed) {
|
|
13
|
+
return async (e) => {
|
|
14
|
+
if (blockedToolCalls.delete(e.toolCallId)) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
let content = e.content;
|
|
18
|
+
let changed = false;
|
|
19
|
+
const post = { toolName: rosterToolName(toolRosterDeltas.current, e.toolName) };
|
|
20
|
+
if (e.isError) {
|
|
21
|
+
if (hooks?.postToolUseFailure) {
|
|
22
|
+
let clonedDetails = e.details;
|
|
23
|
+
try {
|
|
24
|
+
clonedDetails = structuredClone(e.details);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
}
|
|
28
|
+
const failedName = wireOf("hook.postToolUseFailure", post);
|
|
29
|
+
const failureSeat = await runHookSeat("postToolUseFailure", { timeoutMs: hookTimeoutMs, signal: abortController.signal }, (sig) => hooks.postToolUseFailure(failedName, e.input, {
|
|
30
|
+
error: e.content
|
|
31
|
+
.filter((c) => c.type === "text")
|
|
32
|
+
.map((c) => c.text)
|
|
33
|
+
.join("\n"),
|
|
34
|
+
isInterrupt: abortController.signal.aborted || spec.signal?.aborted === true,
|
|
35
|
+
content: e.content.map((c) => ({ ...c })),
|
|
36
|
+
details: clonedDetails,
|
|
37
|
+
}, { toolCallId: e.toolCallId, toolName: failedName, signal: sig, ...(handsCwdRef?.current !== undefined ? { cwd: handsCwdRef.current } : {}), ...(hookEnvFace !== undefined ? { env: hookEnvFace } : {}), identity: hookIdentity, permissionMode: permissionMode.observed }));
|
|
38
|
+
if (failureSeat.expired) {
|
|
39
|
+
notifyOwnHookCrash(hookSeatExpiredError("postToolUseFailure", hookTimeoutMs, failureSeat.cause, "the observation was abandoned and its additionalContext dropped; the failure result itself is unchanged"));
|
|
40
|
+
}
|
|
41
|
+
const patch = failureSeat.expired ? undefined : failureSeat.value;
|
|
42
|
+
if (patch?.additionalContext) {
|
|
43
|
+
content = [...content, { type: "text", text: formatHookFeedback(patch.additionalContext, reminderMark) }];
|
|
44
|
+
changed = true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else if (hooks?.postToolUse) {
|
|
49
|
+
const ranName = wireOf("hook.postToolUse", post);
|
|
50
|
+
const successSeat = await runHookSeat("postToolUse", { timeoutMs: hookTimeoutMs, signal: abortController.signal }, (sig) => hooks.postToolUse(ranName, e.input, { content: e.content, details: e.details, isError: e.isError }, { toolCallId: e.toolCallId, toolName: ranName, signal: sig, ...(handsCwdRef?.current !== undefined ? { cwd: handsCwdRef.current } : {}), ...(hookEnvFace !== undefined ? { env: hookEnvFace } : {}), identity: hookIdentity, permissionMode: permissionMode.observed }));
|
|
51
|
+
if (successSeat.expired) {
|
|
52
|
+
notifyOwnHookCrash(hookSeatExpiredError("postToolUse", hookTimeoutMs, successSeat.cause, "the seat was abandoned; the tool result is delivered to the model UNMODIFIED (no updatedOutput, no additionalContext)"));
|
|
53
|
+
}
|
|
54
|
+
const patch = successSeat.expired ? undefined : successSeat.value;
|
|
55
|
+
if (patch?.updatedOutput) {
|
|
56
|
+
content = patch.updatedOutput;
|
|
57
|
+
changed = true;
|
|
58
|
+
noteHostRewrite(frameSettlement, e.toolCallId);
|
|
59
|
+
}
|
|
60
|
+
if (patch?.additionalContext) {
|
|
61
|
+
content = [...content, { type: "text", text: formatHookFeedback(patch.additionalContext, reminderMark) }];
|
|
62
|
+
changed = true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const pre = preToolContexts.get(e.toolCallId);
|
|
66
|
+
if (pre) {
|
|
67
|
+
preToolContexts.delete(e.toolCallId);
|
|
68
|
+
content = [...content, ...pre.map((t) => ({ type: "text", text: formatHookFeedback(t, reminderMark) }))];
|
|
69
|
+
changed = true;
|
|
70
|
+
}
|
|
71
|
+
return changed ? { content } : undefined;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
export function createApprovedCallScreen(input) {
|
|
77
|
+
const { preToolUse, hookTimeoutMs, abortController, handsCwdRef, hookEnvFace, hookIdentity, notifyOwnHookCrash, preToolContexts } = input;
|
|
78
|
+
if (preToolUse === undefined)
|
|
79
|
+
return undefined;
|
|
80
|
+
return async ({ toolCallId, toolName, args, decidedBy }) => {
|
|
81
|
+
const notifier = createSafeNotifier();
|
|
82
|
+
const seatInput = { event: { toolCallId, toolName, input: args }, ...(handsCwdRef !== undefined ? { trackedCwd: () => handsCwdRef.current } : {}), ...(hookEnvFace !== undefined ? { hookEnv: hookEnvFace } : {}), identity: hookIdentity, onHookError: notifyOwnHookCrash, abortSignal: abortController.signal };
|
|
83
|
+
const screening = createPreToolUseScreening(preToolUse, seatInput, hookTimeoutMs, notifier);
|
|
84
|
+
const subject = `this call to "${toolName}"`;
|
|
85
|
+
let r;
|
|
86
|
+
try {
|
|
87
|
+
const seat = await screening.screen(args);
|
|
88
|
+
if (seat.expired)
|
|
89
|
+
return { refused: await screening.unansweredReason(subject, seat.cause) };
|
|
90
|
+
r = screening.screened(seat.value);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
traceHookCrash(seatInput, err, notifier);
|
|
94
|
+
return { refused: screening.crashReason(subject, err) };
|
|
95
|
+
}
|
|
96
|
+
if (r !== undefined && isEngineRefusal(r))
|
|
97
|
+
return { refused: screening.refusedReason(r) };
|
|
98
|
+
if (r?.action === "deny")
|
|
99
|
+
return { refused: screening.deniedReason(r) };
|
|
100
|
+
if (r !== undefined && policyCannotAnswer(r, decidedBy))
|
|
101
|
+
return { refused: `a PreToolUse hook requires a person's approval for ${subject}, and this approval was the deployment's policy — not executed` };
|
|
102
|
+
const context = r?.additionalContext;
|
|
103
|
+
return { args: r?.updatedInput !== undefined ? r.updatedInput : args, admit: () => {
|
|
104
|
+
if (context)
|
|
105
|
+
preToolContexts.set(toolCallId, [context]);
|
|
106
|
+
} };
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export function chainCannotJudge(ig) {
|
|
110
|
+
if (ig?.requiresParentConstraint !== true)
|
|
111
|
+
return undefined;
|
|
112
|
+
const chain = ig.constraintChain;
|
|
113
|
+
if (chain === undefined)
|
|
114
|
+
return "the checkpoint predates the frozen projection chain (no constraintChain recorded)";
|
|
115
|
+
if (chain.some((e) => "opaque" in e))
|
|
116
|
+
return "the inherited chain carries an OPAQUE layer (no projection exported)";
|
|
117
|
+
return chain.some((e) => !("opaque" in e) && e.requiresLiveRemainder) ? "an inherited chain layer declares a live remainder beyond its projection" : undefined;
|
|
118
|
+
}
|
|
@@ -55,7 +55,7 @@ import type { ToolDisclosureManifest } from "../trace.js";
|
|
|
55
55
|
import type { AgentDefinition, Brain, CompactOutcome, ModelRef, ModelRoles, NestedUsageAccum, PermissionMode, RunnerDeps, ShellGateDoctrine, TaskEvent, TaskEventIdentity, TaskResult, TaskSpec, TaskStream, ToolActivity, ToolEffect } from "../types.js";
|
|
56
56
|
import type { PermissionModeController } from "../mode-policy.js";
|
|
57
57
|
import type { WiringManifest } from "../wiring-manifest.js";
|
|
58
|
-
import type {
|
|
58
|
+
import type { SkillGateSeats, SkillGrantLane, SkillGrantRecord, SkillGrantSource } from "../skill-grant.js";
|
|
59
59
|
import type { BudgetAxis } from "./assemble-result.js";
|
|
60
60
|
import type { GitStatusLaneRef } from "./git-status-frame.js";
|
|
61
61
|
import type { SessionReadFileStates } from "./session-read-file-states.js";
|
|
@@ -239,6 +239,8 @@ export type StopForDenialLimit = (info: {
|
|
|
239
239
|
fallback: DenialLimitFallbackFace;
|
|
240
240
|
settlement?: SettlementKind;
|
|
241
241
|
}) => void;
|
|
242
|
+
/** The gate's seat inputs for one call (the static seat or the `Skill` tool's per-call reader, and the run's skill rows). */
|
|
243
|
+
export type GateSeatInputsFor = (calledName: string, wireName: string) => import("../mode-policy.js").PermissionSeatInputs & SkillGateSeats;
|
|
242
244
|
export interface Prepared {
|
|
243
245
|
harness: AgentHarness;
|
|
244
246
|
/** The CONCRETE built-in session (engine-internal: prepare constructs/acquires `StoredSession` itself,
|
|
@@ -418,9 +420,14 @@ export interface Prepared {
|
|
|
418
420
|
* the run's settle, every terminal (suspend included), under the session lock; undefined argument
|
|
419
421
|
* (no commits) is a no-op. Synchronous, never throws. Absent ⇔ hands-less / no seat channel. */
|
|
420
422
|
sealReadStateSeat?: (ownCommittedTailEntryId: string | undefined) => void;
|
|
421
|
-
/** The DENY-NARROWING layers (session rules
|
|
422
|
-
* before an approved pending tool executes, so a rule tightened during the suspend still applies. */
|
|
423
|
+
/** The DENY-NARROWING layers (session rules, inherited ancestor rules, the frozen constraint projections; deny-only).
|
|
424
|
+
* Re-checked on RESUME before an approved pending tool executes, so a rule tightened during the suspend still applies. */
|
|
423
425
|
denyNarrowingPolicy?: ToolPolicy;
|
|
426
|
+
/** The run's skill grant lane: its deny rows (a skill's `disallowed-tools`) are re-read on RESUME at the same station as the
|
|
427
|
+
* person's deny rows, on the bytes that will run. */
|
|
428
|
+
skillGrants: SkillGrantLane;
|
|
429
|
+
/** The skills this leg loads (normalized, past the load gate; empty when none) — the one list its `Skill` tool activates from, its park binds and the resumed execution boundary judges a parked Skill approval against. */
|
|
430
|
+
skillSpecs: readonly SkillGrantSource[];
|
|
424
431
|
/** The person's own persisted-rule lane (deny/ask rows), re-adjudicated on RESUME at the same
|
|
425
432
|
* station as the deny-narrowing layers: a deny row added while the call was parked vetoes the execution
|
|
426
433
|
* (`deniedBy: "persisted_rule"`), and so does a call the lane could not read against the rows (re-issue and
|
|
@@ -429,9 +436,19 @@ export interface Prepared {
|
|
|
429
436
|
persistedRuleLane?: {
|
|
430
437
|
adjudicate: (req: ToolCallRequest) => Promise<import("../hooks.js").PersistedRuleAnswer>;
|
|
431
438
|
};
|
|
432
|
-
/** The deployment's
|
|
433
|
-
* rewrote the pending call's args (see the composition site for why the edit case is special). */
|
|
439
|
+
/** The deployment's caller policy, re-checked on a durable resume when the bytes to execute are not the bytes the gate saw. */
|
|
434
440
|
basePolicyForResumeEdit?: ToolPolicy;
|
|
441
|
+
approvedCallScreen?: (call: {
|
|
442
|
+
toolCallId: string;
|
|
443
|
+
toolName: string;
|
|
444
|
+
args: unknown;
|
|
445
|
+
decidedBy: "person" | "sla_timeout" | "policy";
|
|
446
|
+
}) => Promise<{
|
|
447
|
+
readonly refused: string;
|
|
448
|
+
} | {
|
|
449
|
+
readonly args: unknown;
|
|
450
|
+
readonly admit: () => void;
|
|
451
|
+
}>;
|
|
435
452
|
/** The leg's shell READ STATION, re-run on a durable RESUME before an approved shell call executes: the parked leg's
|
|
436
453
|
* admission died with that leg, so the resumed bytes are judged (and admitted for their pre-spawn re-establishment)
|
|
437
454
|
* on THIS leg — a deny row found now vetoes, an operator's edit is judged on the `rejudge` seat. */
|
|
@@ -1608,10 +1625,10 @@ export interface RunInternals {
|
|
|
1608
1625
|
/**
|
|
1609
1626
|
* Parent effective-policy inheritance (tighten-only): the spawning parent's already-evaluated FINAL
|
|
1610
1627
|
* gate, threaded into a child task so the child inherits it as ADDITIONAL constraint layers — a child
|
|
1611
|
-
* can only ever be narrowed by this, never widened (its own session rules / skill
|
|
1628
|
+
* can only ever be narrowed by this, never widened (its own session rules / skill rows / caller policy
|
|
1612
1629
|
* still apply in full). Filled ONLY by core delegation callers (`createSubagentTool`'s execute via
|
|
1613
1630
|
* `ToolExecuteContext.inheritedGateForChildren`, the workflow spawn legs) — NEVER a {@link TaskSpec}
|
|
1614
|
-
* field (the untrusted-caller surface), mirroring `
|
|
1631
|
+
* field (the untrusted-caller surface), mirroring `inheritedSkillGrants`'s ctx-injection posture.
|
|
1615
1632
|
* Absent ⇒ no inheritance (a top-level task; fully backward-compatible).
|
|
1616
1633
|
*/
|
|
1617
1634
|
inheritedGate?: InheritedGate;
|
|
@@ -1686,7 +1703,7 @@ export interface RunInternals {
|
|
|
1686
1703
|
* itself inside a workflow (e.g. service's `/v1/workflows`), it threads `workflowDepth = parentDepth + 1`
|
|
1687
1704
|
* into `startWorkflow`/`runWorkflow` so the one-level nesting guard fires across the process boundary.
|
|
1688
1705
|
* In-process nesting needs nothing here — the engine's `AsyncLocalStorage` propagates depth automatically.
|
|
1689
|
-
* Mirrors how `repairBundle`/`
|
|
1706
|
+
* Mirrors how `repairBundle`/`inheritedSkillGrants` thread trusted run-scoped internals the Runner cannot
|
|
1690
1707
|
* see from `spec`. Consumed by the `run_workflow` tool wiring (S8c), not by `prepareTask` itself.
|
|
1691
1708
|
*/
|
|
1692
1709
|
workflowDepth?: number;
|
|
@@ -1711,7 +1728,7 @@ export interface RunInternals {
|
|
|
1711
1728
|
* child it spawns: this run IS a forked child. `prepareTask` threads it to tool ctx as `insideFork` so the
|
|
1712
1729
|
* child's own Agent tool refuses a nested fork (nesting guard — mirrors CC's "fork is not available inside a
|
|
1713
1730
|
* forked worker"; a fork can still delegate via `Agent`, just not fork again). TRUSTED internal (NOT a
|
|
1714
|
-
* `TaskSpec` field — the untrusted-caller surface), mirrors `
|
|
1731
|
+
* `TaskSpec` field — the untrusted-caller surface), mirrors `inheritedSkillGrants`.
|
|
1715
1732
|
*/
|
|
1716
1733
|
insideFork?: boolean;
|
|
1717
1734
|
/**
|
|
@@ -1783,23 +1800,16 @@ export interface RunInternals {
|
|
|
1783
1800
|
*/
|
|
1784
1801
|
goalMode?: boolean;
|
|
1785
1802
|
/**
|
|
1786
|
-
*
|
|
1787
|
-
*
|
|
1788
|
-
*
|
|
1789
|
-
*
|
|
1790
|
-
* a manifested skill is AT MOST as capable as the manifest (its own manifests can only narrow further,
|
|
1791
|
-
* never re-grant a tool/path the parent removed).
|
|
1792
|
-
*
|
|
1793
|
-
* This is a TRUSTED, run-scoped channel filled ONLY by `createSubagentTool`'s `execute` (a core caller),
|
|
1794
|
-
* NEVER a {@link TaskSpec} field (TaskSpec is the untrusted-caller surface). It mirrors
|
|
1795
|
-
* how `repairBundle`/`resume.seed` thread live per-task state the Runner cannot see from `spec`.
|
|
1803
|
+
* The skill grant rows the PARENT task held at the moment it spawned this child (its `allowed-tools` / `disallowed-tools`
|
|
1804
|
+
* rows of the run, whatever wrote them), captured by `createSubagentTool`'s `execute` from the parent's
|
|
1805
|
+
* `ctx.activeSkillGrants()` and seeded into this child's table as `inherited` rows: they hold until THIS child ends
|
|
1806
|
+
* (the parent's run ending ends the parent's rows, not this copy), beside the child's own activations.
|
|
1796
1807
|
*
|
|
1797
|
-
*
|
|
1798
|
-
*
|
|
1799
|
-
*
|
|
1800
|
-
* subagent spawned with no active parent manifest behaves exactly as before, backward-compatible).
|
|
1808
|
+
* A TRUSTED, run-scoped channel (never a {@link TaskSpec} field — TaskSpec is the untrusted-caller surface), in the
|
|
1809
|
+
* posture `repairBundle` / `resume.seed` keep. A capture the delegation could not read refuses the spawn rather than
|
|
1810
|
+
* seeding nothing (it carries refusals too). Absent or empty ⇒ nothing inherited.
|
|
1801
1811
|
*/
|
|
1802
|
-
|
|
1812
|
+
inheritedSkillGrants?: readonly SkillGrantRecord[];
|
|
1803
1813
|
/**
|
|
1804
1814
|
* When this task runs as a SUB-AGENT spawned under a parent task's
|
|
1805
1815
|
* tool call, the spawning tool's `ToolExecuteContext.toolCallId`. The Runner stamps it onto this task's
|
|
@@ -1807,7 +1817,7 @@ export interface RunInternals {
|
|
|
1807
1817
|
* content to the delegation subtree WITHOUT core merging the child stream into the parent (lightweight
|
|
1808
1818
|
* message-identity, not stream-merge). A TRUSTED, run-scoped channel filled by a core caller
|
|
1809
1819
|
* (`createSubagentTool`'s `execute`) — NEVER a {@link TaskSpec} field (the untrusted-caller surface),
|
|
1810
|
-
* mirroring `
|
|
1820
|
+
* mirroring `inheritedSkillGrants`/`workflowDepth`. Absent for a top-level (non-delegated) task.
|
|
1811
1821
|
*/
|
|
1812
1822
|
parentToolCallId?: string;
|
|
1813
1823
|
/**
|
|
@@ -138,6 +138,10 @@ export interface PreToolUseScreening {
|
|
|
138
138
|
/** The model-facing text for a face that never ANSWERED while screening `subject` (the timeout arm also
|
|
139
139
|
* reports on the deployment lane; a task-abort expiry does not). */
|
|
140
140
|
unansweredReason(subject: string, cause: "timeout" | "aborted"): Promise<string>;
|
|
141
|
+
/** The model-facing text for the face's OWN deny of this call (unwrapped; every exit wraps it with the leg's mark). */
|
|
142
|
+
deniedReason(answer: PreToolUseResult): string;
|
|
143
|
+
/** The model-facing text for an answer the decision receipt refused (an ENGINE fail-closed, not the face's deny). */
|
|
144
|
+
refusedReason(answer: PreToolUseResult): string;
|
|
141
145
|
}
|
|
142
146
|
/**
|
|
143
147
|
* ONE gate pass — the record the station groups (`runGateFold`, `runGateLanes`) and the exits read and write,
|
|
@@ -318,7 +322,7 @@ export interface GatePass {
|
|
|
318
322
|
export declare function engineFailClosedExit(pass: GatePass, reason: string): Promise<ToolGateResult>;
|
|
319
323
|
/** The hook's OWN deny in phase 1. A PreToolUse hook deny does NOT fire `permissionDenied`
|
|
320
324
|
* (the exclusion recorded on `Hooks.permissionDenied`) — this return stays observer-free. */
|
|
321
|
-
export declare function hookDenyExit(pass: GatePass,
|
|
325
|
+
export declare function hookDenyExit(pass: GatePass, deniedReason: string): ToolGateResult;
|
|
322
326
|
/**
|
|
323
327
|
* The exit of the adjudicate chain — the pass has a standing `deny` or `allow` (every ask was resolved or
|
|
324
328
|
* parked before this), and this is where it becomes the gate result and the ONE record of the pass.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { screenGateOutcome, SETTLEMENT_IS_REFUSAL } from "../gate-outcome.js";
|
|
2
|
-
import { headlessApprovalRemedy } from "../ask-origin.js";
|
|
2
|
+
import { classifyAsk, headlessApprovalRemedy } from "../ask-origin.js";
|
|
3
3
|
import { isProtectedWrite } from "../tool-registry.js";
|
|
4
4
|
import { askUnresolvableCauseOf, classifierDenyCauseOf, classifierRoundOf, decisionText, engineSettlementOf } from "../tool-policy.js";
|
|
5
|
+
import { askUnresolvableRemedySeat } from "../ask-unresolvable-notice.js";
|
|
5
6
|
import { inlineUntrusted } from "../untrusted-text.js";
|
|
6
7
|
import { formatHookFeedback } from "../reminder-mint.js";
|
|
7
8
|
export function mintGateOutcome(facts) {
|
|
@@ -102,15 +103,16 @@ export async function engineFailClosedExit(pass, reason) {
|
|
|
102
103
|
await notifyPermissionDenied({ toolName, input: cloneObserverInput(pass.currentInput), toolCallId, reason, gate, ...(input.identity !== undefined ? { identity: input.identity } : {}) });
|
|
103
104
|
return { block: true, reason: formatHookFeedback(reason, input.reminderMark), gate, preToolContext: pass.preToolContext };
|
|
104
105
|
}
|
|
105
|
-
export function hookDenyExit(pass,
|
|
106
|
-
const { input
|
|
106
|
+
export function hookDenyExit(pass, deniedReason) {
|
|
107
|
+
const { input } = pass;
|
|
107
108
|
return {
|
|
108
109
|
block: true,
|
|
109
|
-
reason: formatHookFeedback(
|
|
110
|
+
reason: formatHookFeedback(deniedReason, input.reminderMark),
|
|
110
111
|
gate: directDeny("hook"),
|
|
111
112
|
preToolContext: pass.preToolContext,
|
|
112
113
|
};
|
|
113
114
|
}
|
|
115
|
+
const ANCESTOR_UNRESOLVED_CLASSIFICATION = classifyAsk({ action: "ask", message: "" }, { contentQuestion: false, markedUnresolvable: true, org: undefined, tightened: undefined, mandateMarks: {} });
|
|
114
116
|
function unresolvableCauseOfSettlement(gate) {
|
|
115
117
|
if (gate.disposition.kind !== "denied" || gate.disposition.deniedBy !== "ask_resolution" || gate.settlement === undefined)
|
|
116
118
|
return undefined;
|
|
@@ -135,8 +137,10 @@ export async function exitGate(pass) {
|
|
|
135
137
|
ledger.supersede();
|
|
136
138
|
}
|
|
137
139
|
const gate = mintGateOutcome({ deniedBy: pass.deniedBy, ...(pass.denyCause !== undefined ? { cause: pass.denyCause } : {}), ...(ledger.settled !== undefined ? { settled: ledger.settled } : {}), ...(pass.classifierRound !== undefined ? { classifier: pass.classifierRound } : {}), ...(modeRefusal !== undefined ? { modeRefusal: { mode: modeRefusal.mode, askClass: modeRefusal.askClass, classes: modeRefusal.classes } } : {}) });
|
|
138
|
-
const
|
|
139
|
-
const
|
|
140
|
+
const foldCause = askUnresolvableCauseOf(pass.decision, { toolCallId, toolName });
|
|
141
|
+
const unresolvable = foldCause ?? unresolvableCauseOfSettlement(gate);
|
|
142
|
+
const remedySeat = unresolvable !== undefined ? askUnresolvableRemedySeat(unresolvable) : undefined;
|
|
143
|
+
const remedy = remedySeat !== undefined ? headlessApprovalRemedy({ mode: input.permissionMode?.(), classification: foldCause !== undefined ? ANCESTOR_UNRESOLVED_CLASSIFICATION : pass.askClassification, approverSeat: remedySeat, coveredWrite: isProtectedWrite(pass.req), ...(pass.shellUnplacedOptions !== undefined ? { unplacedOptions: pass.shellUnplacedOptions } : {}) }) : undefined;
|
|
140
144
|
const denyReason = withParkFailureCause(`${decisionText(pass.decision) ?? `tool "${toolName}" denied by policy`}${remedy !== undefined ? ` — ${remedy}` : ""}`, pass.parkFailed);
|
|
141
145
|
if (unresolvable !== undefined) {
|
|
142
146
|
const cause = unresolvable;
|
|
@@ -99,6 +99,7 @@ export interface PrepareDelegationSurfaceInput {
|
|
|
99
99
|
/** borrowed-readonly — the caller-tool ctx enrichment: the revival spawner re-enters the delegation tool through it, and
|
|
100
100
|
* the SendMessage / AgentTranscript mounts activate their ctx-first arms with it. */
|
|
101
101
|
enrichSpecToolCtx: (ctx: ToolExecuteContext) => ToolExecuteContext;
|
|
102
|
+
/** borrowed-readonly — the seat this run hands its children (`checkpointSeatOf`); the background-agent read faces read a parked agent's approval card through it. */ checkpointSeat: import("../checkpoint-seat.js").CheckpointSeat | undefined;
|
|
102
103
|
/** borrowed-mutable — the hands mount's tracked-cwd seat: present ⇔ real shell + write hands; the worktree pair's mount
|
|
103
104
|
* predicate. Not written by this phase, but the tools it mounts over it ARE its writers: EnterWorktree and
|
|
104
105
|
* ExitWorktree assign `current` at run time (the hands band's shared cwd then points at the worktree, and back); the
|
|
@@ -12,14 +12,14 @@ import { deliverEngineNotice } from "../types.js";
|
|
|
12
12
|
import { RosterBuilder } from "../tool-roster.js";
|
|
13
13
|
import { sendMessageContinuationSeats } from "./send-message-continuation.js";
|
|
14
14
|
export function prepareDelegationSurface(input) {
|
|
15
|
-
const { spec, deps, internals, resume, sessionId, hostTaskId, taskScope, taskRootFinal, taskRootCanonical, executionEnv, runnerSelf, backgroundTaskToolsActive, workflowToolsActive, peerLaneActive, peerSendMessageBuiltIn, peerLaneRefs, sessionBox, roster, toolEffects, axisExplicitNegatives, envHandToolNames, toolFaceSnapshot, firstPartyOffload, offloadStore, subagentRetain, enrichSpecToolCtx, handsCwdRef, wsSnapshot, rebaseWsPath, rebaseRestoredPath, workspaceStateSettle } = input;
|
|
15
|
+
const { spec, deps, internals, resume, sessionId, hostTaskId, taskScope, taskRootFinal, taskRootCanonical, executionEnv, runnerSelf, backgroundTaskToolsActive, workflowToolsActive, peerLaneActive, peerSendMessageBuiltIn, peerLaneRefs, sessionBox, roster, toolEffects, axisExplicitNegatives, envHandToolNames, toolFaceSnapshot, firstPartyOffload, offloadStore, subagentRetain, enrichSpecToolCtx, checkpointSeat, handsCwdRef, wsSnapshot, rebaseWsPath, rebaseRestoredPath, workspaceStateSettle } = input;
|
|
16
16
|
let worktreeSessionRef;
|
|
17
17
|
const delegationSurfaceActive = backgroundTaskToolsActive || workflowToolsActive;
|
|
18
18
|
let sendMessageTier;
|
|
19
19
|
if (delegationSurfaceActive || internals?.parentNotify !== undefined || peerLaneActive) {
|
|
20
20
|
if (delegationSurfaceActive) {
|
|
21
21
|
roster.mountAll([
|
|
22
|
-
firstPartyOffload(createTaskOutputTool({ registry: defaultTaskRegistry, owner: hostTaskId, scope: taskScope, sessionId, workflowStore: deps.workflowRunStore, agentStore: deps.backgroundAgentStore, notificationWired: internals?.onTaskNotification !== undefined, oneShot: spec.oneShot, toolResultStore: offloadStore })),
|
|
22
|
+
firstPartyOffload(createTaskOutputTool({ registry: defaultTaskRegistry, owner: hostTaskId, scope: taskScope, sessionId, workflowStore: deps.workflowRunStore, agentStore: deps.backgroundAgentStore, notificationWired: internals?.onTaskNotification !== undefined, oneShot: spec.oneShot, toolResultStore: offloadStore, ...(checkpointSeat !== undefined ? { checkpointSeat } : {}) })),
|
|
23
23
|
firstPartyOffload(createTaskStopTool({ registry: defaultTaskRegistry, owner: hostTaskId, scope: taskScope, sessionId, workflowStore: deps.workflowRunStore, agentStore: deps.backgroundAgentStore })),
|
|
24
24
|
], { source: "builtin", mountedBy: "delegation" });
|
|
25
25
|
}
|
|
@@ -66,7 +66,7 @@ export function prepareDelegationSurface(input) {
|
|
|
66
66
|
roster.mount(firstPartyOffload(createAgentTranscriptTool({
|
|
67
67
|
runner: runnerSelf,
|
|
68
68
|
registry: defaultTaskRegistry,
|
|
69
|
-
agentStore: deps.backgroundAgentStore,
|
|
69
|
+
agentStore: deps.backgroundAgentStore, ...(checkpointSeat !== undefined ? { checkpointSeat } : {}),
|
|
70
70
|
owner: hostTaskId,
|
|
71
71
|
scope: taskScope,
|
|
72
72
|
...(sessionId !== undefined ? { sessionId } : {}),
|
|
@@ -84,7 +84,7 @@ export function prepareDelegationSurface(input) {
|
|
|
84
84
|
toolEffects.set(READ_INBOX_TOOL_NAME, "read");
|
|
85
85
|
roster.mount(firstPartyOffload(createReadInboxTool({ pull: () => peerLaneRefs.pull })), { source: "builtin", mountedBy: "peerLane" });
|
|
86
86
|
}
|
|
87
|
-
const listAgents = (peerLaneActive || delegationSurfaceActive) && peerSendMessageBuiltIn && listAgentsMountable({ exclude: toolFaceSnapshot.exclude, specTools: spec.tools ?? [] }) ? mountListAgents({ ...(peerLaneActive ? { peerDirectory: deps.peerDirectory } : {}), freshWindowMs: resolvePeerLaneConfig(deps.peerLane, deps.onNotice).listingFreshWindowMs, sessionId, scope: taskScope, hostTaskId, ...(internals?.parentTaskId !== undefined ? { parentTaskId: internals.parentTaskId } : {}), ...(internals?.parentSessionId !== undefined ? { parentSessionId: internals.parentSessionId } : {}), registry: defaultTaskRegistry, ...(deps.rosterStore !== undefined ? { roster: deps.rosterStore } : {}), ...(sendMessageTier !== undefined ? { continuationTier: sendMessageTier } : {}), specTools: spec.tools ?? [], toolEffects }) : undefined;
|
|
87
|
+
const listAgents = (peerLaneActive || delegationSurfaceActive) && peerSendMessageBuiltIn && listAgentsMountable({ exclude: toolFaceSnapshot.exclude, specTools: spec.tools ?? [] }) ? mountListAgents({ ...(peerLaneActive ? { peerDirectory: deps.peerDirectory } : {}), freshWindowMs: resolvePeerLaneConfig(deps.peerLane, deps.onNotice).listingFreshWindowMs, sessionId, scope: taskScope, hostTaskId, ...(internals?.parentTaskId !== undefined ? { parentTaskId: internals.parentTaskId } : {}), ...(internals?.parentSessionId !== undefined ? { parentSessionId: internals.parentSessionId } : {}), registry: defaultTaskRegistry, ...(deps.rosterStore !== undefined ? { roster: deps.rosterStore } : {}), ...(sendMessageTier !== undefined ? { continuationTier: sendMessageTier } : {}), ...(checkpointSeat !== undefined ? { readSeats: { checkpointSeat } } : {}), specTools: spec.tools ?? [], toolEffects }) : undefined;
|
|
88
88
|
if (listAgents !== undefined)
|
|
89
89
|
roster.mount(firstPartyOffload(listAgents), { source: "builtin", mountedBy: "peerLane" });
|
|
90
90
|
if (backgroundTaskToolsActive) {
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* effect sync, the write-protection judge compiled once per task, the arming predicate, the compliance and plan-mode
|
|
4
4
|
* short-circuits, the `runToolGate` call with every seat it is handed, the lifecycle sweep, the deferred sandbox-admission
|
|
5
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
|
|
6
|
+
* `tool_result` station's registration (its body, the PostToolUse / PostToolUseFailure seats and the PreToolUse context
|
|
7
|
+
* drain, lives in call-hook-stations.ts). The two module-scope
|
|
7
8
|
* helpers only these stations called moved with them (the settlement screen, the rejection-boundary judgment). The
|
|
8
9
|
* interface is the dependency list the stations had implicitly.
|
|
9
10
|
*
|
|
@@ -36,11 +37,12 @@ import { type WiringManifest } from "../wiring-manifest.js";
|
|
|
36
37
|
import type { WriteProtectionCheck } from "../write-protect.js";
|
|
37
38
|
import type { ShellReadCheck } from "../../tools/fs/shell-read-check.js";
|
|
38
39
|
import type { CwdRef } from "../../tools/fs/fs-shared.js";
|
|
39
|
-
import type { AskLane, IrreversibilityTier, ParkAsk, Prepared, ReversibilityProbes, StopForDenialLimit } from "./contracts.js";
|
|
40
|
+
import type { AskLane, GateSeatInputsFor, IrreversibilityTier, ParkAsk, Prepared, ReversibilityProbes, StopForDenialLimit } from "./contracts.js";
|
|
40
41
|
import type { PermissionRuleLanes } from "./permission-rule-lanes.js";
|
|
41
42
|
import { type ToolRosterDeltaSeat } from "../tool-roster.js";
|
|
42
43
|
import type { ToolCallLike } from "../tool-registry.js";
|
|
43
|
-
import {
|
|
44
|
+
import type { FrameSettlement } from "../frame-settlement.js";
|
|
45
|
+
import { type ApprovedCallScreen } from "./call-hook-stations.js";
|
|
44
46
|
/**
|
|
45
47
|
* The parent-thread human-rejection boundary — judged ONCE here, from the pass's own record (CC parity:
|
|
46
48
|
* the reference CLI's reject path aborts exactly when there is no feedback and the run is not a
|
|
@@ -205,6 +207,7 @@ export interface PrepareGateStationsInput {
|
|
|
205
207
|
stopForDenialLimit: StopForDenialLimit;
|
|
206
208
|
/** borrowed-readonly — the persisted allow-rule lane, or undefined (absent entirely with no store). */
|
|
207
209
|
permissionRuleLane: PermissionRuleLanes["personal"];
|
|
210
|
+
/** borrowed-readonly — the call's seat inputs: the permission seat (static, or the `Skill` tool's per-call reader) and the run's skill rows. */ seatInputsFor: GateSeatInputsFor;
|
|
208
211
|
/** borrowed-readonly — the org rule lane, or undefined (absent on an ungoverned deployment). */
|
|
209
212
|
permissionRuleOrgLane: PermissionRuleLanes["org"];
|
|
210
213
|
/** borrowed-readonly — whether the ENGINE's question tool is what is mounted under the reserved name (the org lane's
|
|
@@ -239,6 +242,8 @@ export interface PrepareGateStationsResult {
|
|
|
239
242
|
toolCallStationArmed: boolean;
|
|
240
243
|
/** owned — whether the `tool_result` station registered (a post or screening hook is wired; observation seat only). */
|
|
241
244
|
toolResultStationArmed: boolean;
|
|
245
|
+
/** owned — the approved call's PreToolUse re-screen (the gate's face and seat), present exactly when a face is wired. */
|
|
246
|
+
approvedCallScreen?: ApprovedCallScreen;
|
|
242
247
|
}
|
|
243
248
|
/** The M20 phase body — prepareTask's two gate stations, verbatim (see the module header). */
|
|
244
249
|
export declare function prepareGateStations(input: PrepareGateStationsInput): PrepareGateStationsResult;
|