@sema-agent/core 7.56.0 → 7.57.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 +541 -0
- package/LICENSE +1 -1
- package/dist/agents/org-delivery-gate.js +3 -4
- package/dist/agents/peer-held-queue.d.ts +69 -49
- package/dist/agents/peer-held-queue.js +255 -106
- package/dist/agents/peer-session-drain.js +63 -43
- package/dist/agents/send-message-tool.js +3 -2
- package/dist/agents/subagent.js +8 -8
- package/dist/brain/anthropic.js +16 -8
- package/dist/brain/open-responses.js +10 -8
- package/dist/brain/openai.js +11 -9
- package/dist/brain/provider-dialect.d.ts +3 -2
- package/dist/brain/provider-dialect.js +2 -2
- package/dist/brain/request-params.d.ts +6 -0
- package/dist/brain/request-params.js +14 -1
- package/dist/brain/stream-engine.d.ts +9 -0
- package/dist/brain/stream-engine.js +24 -10
- package/dist/brain/stream-shared.d.ts +5 -4
- package/dist/brain/stream-shared.js +4 -4
- package/dist/core/allow-entry.d.ts +3 -10
- package/dist/core/allow-entry.js +17 -25
- package/dist/core/approval-object.d.ts +21 -5
- package/dist/core/approval-object.js +44 -17
- package/dist/core/ask-origin.d.ts +2 -2
- package/dist/core/auto-compaction.d.ts +71 -6
- package/dist/core/auto-compaction.js +42 -26
- package/dist/core/background-agent-store.d.ts +6 -2
- package/dist/core/background-agent-store.js +1 -1
- package/dist/core/checkpoint-requirements.d.ts +7 -1
- package/dist/core/checkpoint-requirements.js +2 -0
- package/dist/core/checkpoint-store.d.ts +17 -29
- package/dist/core/checkpoint-store.js +19 -11
- package/dist/core/cross-boundary-taint.js +4 -2
- package/dist/core/engine-notice.d.ts +3 -2
- package/dist/core/engine-notice.js +6 -0
- package/dist/core/file-history-store.d.ts +14 -8
- package/dist/core/file-history-store.js +14 -4
- package/dist/core/gate-lanes.js +2 -3
- package/dist/core/hooks.d.ts +2 -2
- package/dist/core/mailbox-store.d.ts +62 -1
- package/dist/core/mailbox-store.js +59 -0
- package/dist/core/mcp-name-judge.d.ts +46 -0
- package/dist/core/mcp-name-judge.js +61 -0
- package/dist/core/mcp-probe.d.ts +1 -1
- package/dist/core/mcp-probe.js +2 -5
- package/dist/core/mcp.js +10 -30
- package/dist/core/memory-engine/consolidation-driver.js +4 -3
- package/dist/core/memory-engine/distiller.js +26 -17
- package/dist/core/memory-engine/layout.js +5 -2
- package/dist/core/park-selfcheck.js +2 -0
- package/dist/core/permission-rule-consent.d.ts +5 -3
- package/dist/core/permission-rule-consent.js +20 -15
- package/dist/core/permission-rule-model.d.ts +43 -2
- package/dist/core/permission-rule-model.js +52 -8
- package/dist/core/permission-rule-org.js +1 -1
- package/dist/core/protocol-http-auth.d.ts +16 -2
- package/dist/core/protocol-http-auth.js +42 -11
- package/dist/core/protocol-naming.d.ts +20 -0
- package/dist/core/protocol-naming.js +20 -3
- package/dist/core/read-only-shell.d.ts +20 -5
- package/dist/core/read-only-shell.js +29 -14
- package/dist/core/remote-env.d.ts +37 -1
- package/dist/core/remote-env.js +11 -0
- package/dist/core/resume-startup-cause.d.ts +24 -2
- package/dist/core/resume-startup-cause.js +20 -1
- package/dist/core/roles.js +50 -7
- package/dist/core/runner/compact-session.d.ts +10 -0
- package/dist/core/runner/compact-session.js +202 -0
- package/dist/core/runner/compaction-call-options.d.ts +2 -2
- package/dist/core/runner/compaction-seams.d.ts +21 -1
- package/dist/core/runner/compaction-seams.js +11 -8
- package/dist/core/runner/contracts.d.ts +23 -16
- package/dist/core/runner/derived-route-fallback.d.ts +13 -0
- package/dist/core/runner/derived-route-fallback.js +6 -0
- package/dist/core/runner/env-capability-census.d.ts +3 -2
- package/dist/core/runner/env-capability-census.js +9 -3
- package/dist/core/runner/permission-rule-lanes.d.ts +7 -7
- package/dist/core/runner/permission-rule-lanes.js +17 -11
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +3 -0
- package/dist/core/runner/prepare-acquire-reconcile.js +2 -1
- package/dist/core/runner/prepare-config-doors.d.ts +6 -0
- package/dist/core/runner/prepare-config-doors.js +4 -3
- package/dist/core/runner/prepare-hands-readface.d.ts +3 -1
- package/dist/core/runner/prepare-hands-readface.js +2 -0
- package/dist/core/runner/prepare-park-ask.d.ts +2 -0
- package/dist/core/runner/prepare-park-ask.js +2 -2
- package/dist/core/runner/prepare-policy-chain.js +2 -4
- package/dist/core/runner/prepare-task.d.ts +4 -1
- package/dist/core/runner/prepare-task.js +23 -27
- package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +13 -0
- package/dist/core/runner/prepare-tool-disclosure-mount.js +13 -7
- package/dist/core/runner/rewind-files.d.ts +2 -5
- package/dist/core/runner/rewind-files.js +9 -51
- package/dist/core/runner/run-leg.js +10 -21
- package/dist/core/runner/run-notification-lane.d.ts +2 -0
- package/dist/core/runner/run-notification-lane.js +2 -2
- package/dist/core/runner/run-recovery-lanes.js +3 -4
- package/dist/core/runner/run-settle-and-teardown.js +5 -11
- package/dist/core/runner/run-terminal-adoption.js +3 -4
- package/dist/core/runner/run-turn-boundary.js +3 -5
- package/dist/core/runner/runtask.d.ts +8 -1
- package/dist/core/runner/runtask.js +28 -34
- package/dist/core/runner/send-message-continuation.js +1 -1
- package/dist/core/runner/session-verb-doors.d.ts +28 -0
- package/dist/core/runner/session-verb-doors.js +48 -0
- package/dist/core/runner/session-write-ledger.d.ts +30 -0
- package/dist/core/runner/session-write-ledger.js +101 -0
- package/dist/core/runner/stream-settle-backstop.js +11 -14
- package/dist/core/runner/sub-agent-deny-lists.d.ts +25 -3
- package/dist/core/runner/sub-agent-deny-lists.js +21 -10
- package/dist/core/runner/teardown-bounded.d.ts +1 -0
- package/dist/core/runner/teardown-bounded.js +1 -0
- package/dist/core/runner-deps.d.ts +2 -2
- package/dist/core/secret-env.d.ts +4 -0
- package/dist/core/secret-env.js +3 -0
- package/dist/core/session-policy-store.d.ts +7 -2
- package/dist/core/session-policy-store.js +1 -1
- package/dist/core/shell-wrapper-projection.d.ts +1 -1
- package/dist/core/store-contracts/background-agent-store-contract.js +1 -0
- package/dist/core/store-contracts/checkpoint-store-contract.js +2 -1
- package/dist/core/store-contracts/file-history-store-contract.js +9 -0
- package/dist/core/store-contracts/mailbox-store-contract.js +49 -1
- package/dist/core/task-registry-agent.d.ts +8 -4
- package/dist/core/task-registry-agent.js +14 -8
- package/dist/core/task-registry-shared.d.ts +35 -6
- package/dist/core/task-registry-shared.js +11 -0
- package/dist/core/task-registry.d.ts +1 -1
- package/dist/core/task-registry.js +1 -1
- package/dist/core/tool-catalog-entries.d.ts +6 -0
- package/dist/core/tool-catalog-entries.js +1 -0
- package/dist/core/tool-name-aliases.d.ts +32 -2
- package/dist/core/tool-name-aliases.js +23 -0
- package/dist/core/tool-name-readings.d.ts +4 -0
- package/dist/core/tool-name-readings.js +1 -0
- package/dist/core/tool-policy.d.ts +10 -6
- package/dist/core/tool-policy.js +4 -7
- package/dist/core/trace.d.ts +4 -1
- package/dist/core/trace.js +2 -1
- package/dist/core/untrusted-egress.d.ts +20 -0
- package/dist/core/untrusted-egress.js +77 -3
- package/dist/engine/harness/agent-harness.d.ts +7 -5
- package/dist/engine/harness/agent-harness.js +11 -2
- package/dist/engine/loop/agent-loop.d.ts +1 -4
- package/dist/engine/loop/agent-loop.js +26 -4
- package/dist/index.d.ts +12 -7
- package/dist/index.js +7 -4
- package/dist/internal/harness.d.ts +2 -1
- package/dist/internal/harness.js +1 -0
- package/dist/primitives/credential-ref.d.ts +89 -0
- package/dist/primitives/credential-ref.js +125 -0
- package/dist/primitives/index.d.ts +2 -0
- package/dist/primitives/index.js +1 -0
- package/dist/stores/file/checkpoint-store.d.ts +0 -4
- package/dist/stores/file/checkpoint-store.js +0 -1
- package/dist/stores/file/file-history-store.js +12 -4
- package/dist/stores/file/mailbox-store.d.ts +2 -1
- package/dist/stores/file/mailbox-store.js +26 -1
- package/dist/tools/fs/bash-readonly-classifier.d.ts +15 -19
- package/dist/tools/fs/bash-readonly-classifier.js +5 -10
- package/dist/tools/fs/fs-bash.js +10 -3
- package/dist/tools/fs/pattern-kill-guard.d.ts +3 -2
- package/dist/tools/fs/pattern-kill-guard.js +68 -36
- package/dist/tools/fs/shell-read-check.d.ts +10 -0
- package/dist/tools/fs/shell-read-check.js +7 -1
- package/dist/tools/fs/shell-read-identity.d.ts +12 -9
- package/dist/tools/fs/shell-read-identity.js +9 -4
- package/dist/tools/web.js +9 -7
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +79 -3
- package/wire-changes/core-stores-sql@7.57.0.json +29 -0
- package/wire-changes/core@7.57.0.json +1487 -0
- package/wire-changes/mods-kernel@7.57.0.json +29 -0
- package/wire-changes/primitives@7.57.0.json +245 -0
|
@@ -1,4 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The run loop's COMPACTION SEAMS, verbatim from three private methods of `Runner`: the Seam C
|
|
3
|
+
* cost-optimization options every `maybeCompact` call site spreads, the pre/postCompact hook-option wrapper and
|
|
4
|
+
* the consecutive-reuse counter fold. Layer-1 machinery under a name of its own (the S1 reading: a module the lanes stand
|
|
5
|
+
* on is not a lane) — the turn-boundary lane, the recovery lane and the terminal adoption's end-of-task pass reach DOWN
|
|
6
|
+
* for these three where the driver used to hand each lane the methods as delegates on its Input. Every function reads
|
|
7
|
+
* the Runner's deps LIVE through {@link RunnerDepsSeat}: `runner.deps.x` here is exactly `this.deps.x` in the method it
|
|
8
|
+
* came from, on the tick it is read.
|
|
9
|
+
*/
|
|
10
|
+
import type { HookInvocationIdentity } from "../hooks.js";
|
|
1
11
|
import type { MaybeCompactOptions } from "../auto-compaction.js";
|
|
12
|
+
import { type LegModBus } from "../mods/stations.js";
|
|
2
13
|
import type { Prepared, RunnerDepsSeat } from "./contracts.js";
|
|
3
14
|
/**
|
|
4
15
|
* The cost-optimization compaction options threaded into BOTH `maybeCompact` call
|
|
@@ -12,6 +23,11 @@ import type { Prepared, RunnerDepsSeat } from "./contracts.js";
|
|
|
12
23
|
* function itself always returns an object.
|
|
13
24
|
*/
|
|
14
25
|
export declare function seamCCompactionOptions(runner: RunnerDepsSeat, prepared: Prepared): Pick<MaybeCompactOptions, "summaryProvider" | "onCompaction" | "maxConsecutiveProviderReuse" | "consecutiveProviderReuse" | "onCommitted">;
|
|
26
|
+
/** The Seam C PROVIDER half — the deployment's summary provider, its observer and its drift guard, fed the caller's
|
|
27
|
+
* consecutive-reuse count (a run's counter; `0` for a pass outside a run, which has no earlier reuse to count). Still
|
|
28
|
+
* provider-gated: with no provider wired the four keys stay ABSENT, so every caller spreads exactly what it spread
|
|
29
|
+
* before. */
|
|
30
|
+
export declare function summaryProviderOptions(runner: RunnerDepsSeat, consecutive: number): Pick<MaybeCompactOptions, "summaryProvider" | "onCompaction" | "maxConsecutiveProviderReuse" | "consecutiveProviderReuse">;
|
|
15
31
|
/** The pre/postCompact stations threaded into maybeCompact: `classic.PreCompact` and `classic.PostCompact` raised on the
|
|
16
32
|
* leg's bus (a station is wired only when a handler hangs on its event). Their failure and abort columns are the
|
|
17
33
|
* bus's — a handler that throws or runs past its budget is skipped and reported, so a failed gate is "no block, no
|
|
@@ -19,7 +35,11 @@ export declare function seamCCompactionOptions(runner: RunnerDepsSeat, prepared:
|
|
|
19
35
|
* trigger is reported as ignored (maybeCompact enforces the ignore — blocking a compaction the provider/trim layer
|
|
20
36
|
* already demanded would kill the run). `signal` is the pass's abort (absent ⇒ each handler's own budget is the
|
|
21
37
|
* whole bound). */
|
|
22
|
-
export declare function compactionHookOptions(runner: RunnerDepsSeat, prepared:
|
|
38
|
+
export declare function compactionHookOptions(runner: RunnerDepsSeat, prepared: {
|
|
39
|
+
readonly modBus: LegModBus;
|
|
40
|
+
readonly hookIdentity: HookInvocationIdentity | undefined;
|
|
41
|
+
readonly sessionId: string;
|
|
42
|
+
}, trigger: "auto" | "manual" | "forced", signal: AbortSignal | undefined): Pick<MaybeCompactOptions, "trigger" | "preCompact" | "postCompact">;
|
|
23
43
|
/** Fold a finished compaction's `reused` flag into the run-scoped consecutive-reuse
|
|
24
44
|
* counter: a reused (provider) summary increments it, a real (LLM) summary resets it to 0. A no-op
|
|
25
45
|
* compaction (`compacted:false`) leaves the counter untouched. No-op when no provider is wired. */
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import { classicEventBase, dispatchClassic, observeClassic, stringMembersAnswer, stringMembersOf } from "../mods/stations.js";
|
|
2
2
|
export function seamCCompactionOptions(runner, prepared) {
|
|
3
3
|
return {
|
|
4
|
-
...(runner.
|
|
5
|
-
? {
|
|
6
|
-
summaryProvider: runner.deps.summaryProvider,
|
|
7
|
-
onCompaction: runner.deps.onCompaction,
|
|
8
|
-
maxConsecutiveProviderReuse: runner.deps.maxConsecutiveProviderReuse,
|
|
9
|
-
consecutiveProviderReuse: prepared.compactionReuseRef.consecutive,
|
|
10
|
-
}
|
|
11
|
-
: {}),
|
|
4
|
+
...summaryProviderOptions(runner, prepared.compactionReuseRef.consecutive),
|
|
12
5
|
onCommitted: (effect) => {
|
|
13
6
|
if (prepared.frameSettlement.wantsEffects?.() !== true)
|
|
14
7
|
return;
|
|
@@ -16,6 +9,16 @@ export function seamCCompactionOptions(runner, prepared) {
|
|
|
16
9
|
},
|
|
17
10
|
};
|
|
18
11
|
}
|
|
12
|
+
export function summaryProviderOptions(runner, consecutive) {
|
|
13
|
+
return runner.deps.summaryProvider
|
|
14
|
+
? {
|
|
15
|
+
summaryProvider: runner.deps.summaryProvider,
|
|
16
|
+
onCompaction: runner.deps.onCompaction,
|
|
17
|
+
maxConsecutiveProviderReuse: runner.deps.maxConsecutiveProviderReuse,
|
|
18
|
+
consecutiveProviderReuse: consecutive,
|
|
19
|
+
}
|
|
20
|
+
: {};
|
|
21
|
+
}
|
|
19
22
|
export function compactionHookOptions(runner, prepared, trigger, signal) {
|
|
20
23
|
const bus = prepared.modBus;
|
|
21
24
|
const base = classicEventBase(prepared.hookIdentity);
|
|
@@ -234,7 +234,7 @@ export interface FrameReceipt {
|
|
|
234
234
|
text: string;
|
|
235
235
|
/** Which frame this receipt settles. No collector renders a frame whose receipt is still pending (the frame is on
|
|
236
236
|
* its way, not yet in the transcript) — the one reading is `frameCarried` (compaction-restate.ts). */
|
|
237
|
-
source: "git_status" | "agent_listing" | "skills_listing" | "date_change" | "output_style" | "mcp_unavailable" | "posture" | "
|
|
237
|
+
source: "git_status" | "agent_listing" | "skills_listing" | "date_change" | "output_style" | "mcp_unavailable" | "posture" | "advisor_tool";
|
|
238
238
|
/** Runs inside the `message_end` walk (synchronous, never awaited): advances the run-local record
|
|
239
239
|
* and parks any session write for the next serialization point. */
|
|
240
240
|
commit: (entryId: string) => void;
|
|
@@ -480,6 +480,7 @@ export interface Prepared {
|
|
|
480
480
|
* admission died with that leg, so the resumed bytes are judged (and admitted for their pre-spawn re-establishment)
|
|
481
481
|
* on THIS leg — a deny row found now vetoes, an operator's edit is judged on the `rejudge` seat. */
|
|
482
482
|
shellReadCheck?: import("../../tools/fs/shell-read-check.js").ShellReadCheck;
|
|
483
|
+
shellReadLandings?: import("../../tools/fs/shell-read-check.js").ShellReadLandings;
|
|
483
484
|
crossBoundary?: {
|
|
484
485
|
readonly check: import("../cross-boundary-taint.js").CrossBoundaryCheck | undefined;
|
|
485
486
|
settle(owed: import("../cross-boundary-taint.js").OwedDeliveries): Promise<void>;
|
|
@@ -768,8 +769,8 @@ export interface Prepared {
|
|
|
768
769
|
current?: CommittedPause;
|
|
769
770
|
};
|
|
770
771
|
/** A resumed leg's continuation content that has NOT reached the transcript yet: EVERY input frame the
|
|
771
|
-
* prompt carries (parked steers, the
|
|
772
|
-
*
|
|
772
|
+
* prompt carries (parked steers, the wake message, the approver's words) and the orphans whose obituary rides it. Set
|
|
773
|
+
* before the prompt, emptied at the prompt's own receipt (never its hand-off); a re-park carries it forward (the saga folds the
|
|
773
774
|
* orphans in, the adoption re-parks the frames), and what no re-park carries the undrained account announces. */
|
|
774
775
|
undeliveredContinuationRef: {
|
|
775
776
|
current: UndeliveredContinuation;
|
|
@@ -2648,17 +2649,17 @@ export interface ResumeRun {
|
|
|
2648
2649
|
wakeMessageHookContext?: string;
|
|
2649
2650
|
/** The resumed leg's bus when the wake-message screen admitted it before the claim — prepare adopts it. */
|
|
2650
2651
|
legMods?: LegMods;
|
|
2651
|
-
/**
|
|
2652
|
-
*
|
|
2653
|
-
* the
|
|
2654
|
-
*
|
|
2655
|
-
*
|
|
2656
|
-
*
|
|
2657
|
-
*
|
|
2658
|
-
*
|
|
2659
|
-
|
|
2652
|
+
/** The claim's reversal, bound to THIS resume's token and scope by `resumeStream` — REQUIRED, as the store's
|
|
2653
|
+
* `reopen` is: called when the claimed leg ends before its approved action started (a failed restore, a
|
|
2654
|
+
* refusal at the leg's prepare, an abort, a leg that returned failed), it returns the row `resolved → pending`
|
|
2655
|
+
* under the failure's reason (`reopenReasonOf`), recorded on the row so the next re-resume validates per
|
|
2656
|
+
* reason — an `env_failed` reopen replays the persisted winner, the fresh-redecision reasons take a new
|
|
2657
|
+
* decision. Answers the store's own answer — `"reopened"` (it flipped the row) or `"declined"` (`reopen`
|
|
2658
|
+
* answered `false`) — and rejects only with what the store threw (the row's state is then unprovable);
|
|
2659
|
+
* every exit reads it through `compensateUnstarted` (resume-startup-cause.ts), the one reading. */
|
|
2660
|
+
reopenUnstarted: (reason: ReopenReason) => Promise<"reopened" | "declined">;
|
|
2660
2661
|
/** The row's execution-record verb, bound to THIS resume's token and scope by `resumeStream` (the
|
|
2661
|
-
* same closure form as {@link
|
|
2662
|
+
* same closure form as {@link reopenUnstarted}, and REQUIRED for the same reason: the store contract requires the
|
|
2662
2663
|
* verb, so there is no store this seat could be absent for). The pending-call resolver calls it
|
|
2663
2664
|
* exactly once per resolution, right after it emits the resolved call's `tool_end` frame, with the
|
|
2664
2665
|
* {@link import("../gate-outcome.js").GateOutcome} that frame carried — every disposition, the
|
|
@@ -2666,8 +2667,8 @@ export interface ResumeRun {
|
|
|
2666
2667
|
* allowed). The word it answers is read through `EXECUTION_RECORD_LEAVES_ROW_UNRECORDED`; a
|
|
2667
2668
|
* conflict throw propagates (an engine defect, not a store condition). */
|
|
2668
2669
|
recordExecutionOutcome: (gate: import("../gate-outcome.js").GateOutcome) => Promise<ExecutionOutcomeRecordWord>;
|
|
2669
|
-
/** Set
|
|
2670
|
-
* decision twin of `pendingActionStarted`. A reject/deny consumes its gate BY BEING DELIVERED, and
|
|
2670
|
+
/** Set right after `applyResumeDecision` completes (`policy_ask`), and at the continuation's own receipt for `plan_review` / `dry_run_review`
|
|
2671
|
+
* (its decision rides only that message): the negative-decision twin of `pendingActionStarted`. A reject/deny consumes its gate BY BEING DELIVERED, and
|
|
2671
2672
|
* this bit is the delivery fact — every throw-arm cause (prepare failure, `session_not_found`, a
|
|
2672
2673
|
* pre-delivery abort) and the walltime-exhausted settle fire BEFORE it is set, so an undelivered
|
|
2673
2674
|
* negative decision still reopens as `env_failed` (the retry replays the persisted decision; it
|
|
@@ -2869,7 +2870,13 @@ export interface RunnerSelfSeat {
|
|
|
2869
2870
|
*/
|
|
2870
2871
|
export type PrepareTaskFn = (spec: TaskSpec, deps: RunnerDeps, sessions: SessionStore, resume?: PrepareResume, internals?: RunInternals, runnerSelf?: RunnerSelfSeat, runIdSink?: {
|
|
2871
2872
|
runId?: string;
|
|
2872
|
-
}, holdSessionLock?: (sessionId: string) => Promise<void
|
|
2873
|
+
}, holdSessionLock?: (sessionId: string) => Promise<void>, legWrites?: LegWrites) => Promise<Prepared>;
|
|
2874
|
+
/** One leg's view of the Runner's session write ledger (`session-write-ledger.ts`): `issue` starts a write of the leg (`what` = the
|
|
2875
|
+
* entry type, for a report) or refuses it once `close` ran — the leg's hold ended; a write still in flight is reported when it settles. */
|
|
2876
|
+
export interface LegWrites {
|
|
2877
|
+
issue<T>(sessionId: string, what: string, start: () => Promise<T>): Promise<T>;
|
|
2878
|
+
close(): void;
|
|
2879
|
+
}
|
|
2873
2880
|
/**
|
|
2874
2881
|
* The Result of an INSTALLING phase: a lane whose every product is installed on a seat it borrowed
|
|
2875
2882
|
* (the harness's stop gate and recovery chain, the run state's counter groups, the stream's result setter, the claimed
|
|
@@ -14,6 +14,19 @@ export type DerivedSeatOutcome = {
|
|
|
14
14
|
readonly action: "fall_back" | "detach";
|
|
15
15
|
readonly cause: RouteRefusalCode;
|
|
16
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* Whether the compaction-summary model is ROLE-derived — the only one whose route is pre-flighted (an EXPLICIT
|
|
19
|
+
* compaction model is a named leg and keeps the request gate's loud refusal). Synchronous: a caller awaits the
|
|
20
|
+
* pre-flight only when this holds, so a run with nothing to judge takes no suspension point at the seat.
|
|
21
|
+
*/
|
|
22
|
+
export declare function compactionSummaryIsDerived(explicit: boolean, compModel: Model | undefined): compModel is Model;
|
|
23
|
+
/**
|
|
24
|
+
* The compaction-summary seat after its route pre-flight: a derived summary model whose key↔URL pairing is broken must
|
|
25
|
+
* not sink the pass at the brain's request gate — it falls back to the primary (`undefined`: the pass then summarizes
|
|
26
|
+
* on the main model, the documented absent-model behavior) and the fallback is announced. The one reading for a run's
|
|
27
|
+
* prepare and the out-of-run compaction.
|
|
28
|
+
*/
|
|
29
|
+
export declare function compactionSummaryFallback(args: Omit<Parameters<typeof derivedRouteFallsBack>[0], "seat" | "onBrokenPairing">): Promise<Model | undefined>;
|
|
17
30
|
/**
|
|
18
31
|
* Judge the derived model where its route differs from the primary's, announce what a broken pairing means for THIS seat
|
|
19
32
|
* (`onBrokenPairing`), and ABSTAIN (keep) on ANY throw. The pre-flight is advisory — the brain's request gate re-runs the
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { adjudicateDerivedRoute, fallbackToPrimaryNotice, sameRouteIdentity, seatDetachedNotice, unroutableSeatNotice } from "../../brain/route-adjudicator.js";
|
|
2
2
|
import { deliverEngineNotice } from "../types.js";
|
|
3
|
+
export function compactionSummaryIsDerived(explicit, compModel) {
|
|
4
|
+
return !explicit && compModel !== undefined;
|
|
5
|
+
}
|
|
6
|
+
export async function compactionSummaryFallback(args) {
|
|
7
|
+
return (await derivedRouteFallsBack({ ...args, seat: "compaction-summary" })).action === "fall_back" ? undefined : args.derived;
|
|
8
|
+
}
|
|
3
9
|
export async function derivedRouteFallsBack(args) {
|
|
4
10
|
try {
|
|
5
11
|
if (sameRouteIdentity(args.derived, args.primary))
|
|
@@ -13,8 +13,9 @@ export interface MalformedCapabilityDeclaration {
|
|
|
13
13
|
* The probe is the VALUE, not membership, because the value is what the readers get: a `capabilities`
|
|
14
14
|
* that answers `has` and `get` differently (a Proxy) would otherwise hide from the census exactly the
|
|
15
15
|
* value a reader goes on to act on. `undefined` is where absence lands — an absent key and an explicit
|
|
16
|
-
* `undefined` are the same word to every reader, and both are the documented silent reading
|
|
17
|
-
*
|
|
16
|
+
* `undefined` are the same word to every reader, and both are the documented silent reading of every key
|
|
17
|
+
* outside {@link NO_ABSENT_READING} (and announced, alike, for a key inside it) — so one test covers both and
|
|
18
|
+
* the census needs no membership rule at all.
|
|
18
19
|
*
|
|
19
20
|
* TOTAL by construction: a diagnostic may not be the thing that fails a run. Every read of the adapter
|
|
20
21
|
* can throw on a getter or a Proxy trap — the structural probe, the block acquisition and each key —
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { isRemoteExecutionEnv } from "../remote-env.js";
|
|
2
2
|
import { deliverEngineNotice } from "../engine-notice.js";
|
|
3
|
-
const BOOLEAN_CAPABILITY_KEYS = ["isolation", "suspendable", "canonicalPathAuthoritative"];
|
|
3
|
+
const BOOLEAN_CAPABILITY_KEYS = ["isolation", "suspendable", "canonicalPathAuthoritative", "sharesProcessTable"];
|
|
4
|
+
const NO_ABSENT_READING = {
|
|
5
|
+
sharesProcessTable: "whether the commands it runs are processes on this engine's own process table has no default, so the Bash tool refuses every pattern kill that needs the question (`pkill`, `killall`, a `kill` fed by `pgrep`; `pkill -P $$`, the shell's own children, runs) on this environment until the adapter declares it — `true` when its commands run on a table that holds the engine (a host lane, or a PID namespace that contains the engine's), `false` only when they run where the engine is not (another machine, a PID namespace that does not contain it)",
|
|
6
|
+
};
|
|
4
7
|
const OPTIONAL_METHOD_KEYS = ["writeFileExclusive", "writeFileGuarded", "setFileMode", "readLink", "canonicalChain", "fileIdentity", "openBound"];
|
|
5
8
|
export function malformedCapabilityDeclarations(env) {
|
|
6
9
|
const out = [];
|
|
@@ -36,7 +39,7 @@ export function malformedCapabilityDeclarations(env) {
|
|
|
36
39
|
out.push({ key, valueType: "unreadable", expected: "boolean" });
|
|
37
40
|
continue;
|
|
38
41
|
}
|
|
39
|
-
if (value ===
|
|
42
|
+
if (typeof value === "boolean" || (value === undefined && NO_ABSENT_READING[key] === undefined))
|
|
40
43
|
continue;
|
|
41
44
|
out.push({ key, valueType: value === null ? "null" : typeof value, expected: "boolean" });
|
|
42
45
|
}
|
|
@@ -44,11 +47,14 @@ export function malformedCapabilityDeclarations(env) {
|
|
|
44
47
|
}
|
|
45
48
|
export function announceMalformedCapabilities(env, onNotice) {
|
|
46
49
|
for (const { key, valueType, expected } of malformedCapabilityDeclarations(env)) {
|
|
50
|
+
const noAbsentReading = NO_ABSENT_READING[key];
|
|
47
51
|
deliverEngineNotice(onNotice, {
|
|
48
52
|
code: "config.execution_env_capability_invalid",
|
|
49
53
|
message: expected === "function"
|
|
50
54
|
? `The execution environment declares ${key} as a ${valueType}, not a function. This seat is declared by being present as a callable method and undeclared by being absent, so every reader takes the absent reading — the reach the adapter meant to declare is silently the old one. Fix the adapter — this is a wiring fault, not a supported way to leave the seat unset.`
|
|
51
|
-
:
|
|
55
|
+
: noAbsentReading !== undefined
|
|
56
|
+
? `The execution environment ${valueType === "undefined" ? `does not declare capabilities.${key}` : `declares capabilities.${key} as a ${valueType}, not a boolean`}: ${noAbsentReading}. Fix the adapter — this is a wiring fault, not a supported way to leave the capability unset.`
|
|
57
|
+
: `The execution environment declares capabilities.${key} as a ${valueType}, not a boolean. What a reader makes of that is the reader's own business and differs between them — the containment readers take only the boolean, so this reads as undeclared, while the suspend reader takes any truthy value, so a non-empty string reads as TRUE. That is why a declaration of the wrong shape cannot pass quietly: the engine may act on something other than what the adapter meant. Fix the adapter — this is a wiring fault, not a supported way to leave the capability unset.`,
|
|
52
58
|
detail: { key, valueType },
|
|
53
59
|
});
|
|
54
60
|
}
|
|
@@ -29,11 +29,8 @@ import { type OrgGateVerdict, type PersistedRuleAnswer, type PersistedRuleHit, t
|
|
|
29
29
|
import type { PersistedRule, PersistedRuleVerdict, RuleOffer, ScopeRootIdentity, SegmentCoverage } from "../permission-rule-model.js";
|
|
30
30
|
import { type PathRuleBases } from "../permission-rule-model.js";
|
|
31
31
|
import { type HeadLeads } from "../path-rule-binding.js";
|
|
32
|
-
import type { ToolCallLike } from "../tool-registry.js";
|
|
33
32
|
import { type OrgRuleResolution } from "../permission-rule-org.js";
|
|
34
33
|
import { type EffectivePermissionRules, type PermissionRuleStoreProvider, type PersonRowsRead } from "../permission-rule-provider.js";
|
|
35
|
-
/** The one SHELL tool the persisted-rule lane's COMMAND grammar speaks for (the rule-offer face mints for it, the name tools and the host tools); the other grammars' tools are derived (`ruleToolGrammarOf`). */
|
|
36
|
-
export declare const PERSISTED_RULE_TOOL = "Bash";
|
|
37
34
|
/**
|
|
38
35
|
* The evidence an INHERITED-lane ask carries.
|
|
39
36
|
*
|
|
@@ -203,9 +200,12 @@ interface RuleOffersAskFacts extends RuleClearanceFacts {
|
|
|
203
200
|
* approval-preview field is a standing example of what happens otherwise: it reached two of the
|
|
204
201
|
* five, so a delegated child's card was silently poorer than the top-level one).
|
|
205
202
|
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
203
|
+
* Silent (no offer and no reason) only where no rule speaks for the call: no lane armed, the anonymous floor,
|
|
204
|
+
* a call the lane never judges — offering an option that redemption would refuse is worse than offering none.
|
|
205
|
+
* Every other card offers the one rule its call's form mints ({@link cardRuleFormOf}: the shell card's
|
|
206
|
+
* command rules, a name or host tool's exact value rule, the whole-tool rule of a call no rule word speaks
|
|
207
|
+
* for) or names why it offers none (`lane_cannot_speak`: a compound, a redirection, a substitution, a path
|
|
208
|
+
* tool, a shell-face sibling, a tool answering to one of those under an alias).
|
|
209
209
|
*
|
|
210
210
|
* Empty, too, on any ask a persisted rule could never CLEAR — "allow rules silence the classifier's
|
|
211
211
|
* questions, never a mandated one". Two doors, matching the two halves of that boundary:
|
|
@@ -270,7 +270,7 @@ export declare function createRuleOffersOf(cfg: {
|
|
|
270
270
|
current: string;
|
|
271
271
|
} | undefined;
|
|
272
272
|
deniesDirectoryRead: ((directory: string) => boolean) | undefined;
|
|
273
|
-
}): (call: Pick<
|
|
273
|
+
}): (call: Pick<ToolCallRequest, "toolName" | "face">, args: unknown, ask: RuleOffersAskFacts | undefined) => {
|
|
274
274
|
ruleOffers?: readonly RuleOffer[];
|
|
275
275
|
ruleOffersAbsence?: RuleOffersAbsence;
|
|
276
276
|
execCwd?: string;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { persistedRuleMandateOf, ruleClearanceOf } from "../ask-origin.js";
|
|
2
2
|
import {} from "../hooks.js";
|
|
3
|
-
import { adjudicatePersistedDomainRules, adjudicatePersistedNameRules, adjudicatePersistedPathRules, adjudicatePersistedRules, callPathFaceOf, eligiblePersisted, escapeForDisclosure, faceRowsSpeakFor, parseRuleText, laneToolNamesOf, nameRuleSubjectOf, ruleToolGrammarOf, segmentCoverageOf, suggestRuleForHost, suggestRuleForName, suggestRulesForCommand } from "../permission-rule-model.js";
|
|
3
|
+
import { adjudicatePersistedDomainRules, adjudicatePersistedNameRules, adjudicatePersistedPathRules, adjudicatePersistedRules, adjudicatePersistedToolRules, callPathFaceOf, cardRuleFormOf, eligiblePersisted, escapeForDisclosure, faceRowsSpeakFor, parseRuleText, laneToolNamesOf, nameRuleSubjectOf, ruleToolGrammarOf, segmentCoverageOf, suggestRuleForHost, suggestRuleForName, suggestRuleForTool, suggestRulesForCommand, wholeToolRuleReaches } from "../permission-rule-model.js";
|
|
4
4
|
import { callHostTargetOf } from "../host-target.js";
|
|
5
5
|
import { callTargetViewsOf, validatePath } from "../effective-path-target.js";
|
|
6
6
|
import { bindPathRules, persistedRowAnchors, projectScopeIdentity } from "../path-rule-binding.js";
|
|
7
7
|
import { heldBy, seatOf, wireOf } from "../tool-name-readings.js";
|
|
8
8
|
import { describeUnreadableOrgRows, readOrgRules, settleOrgVerdictWithin } from "../permission-rule-org.js";
|
|
9
9
|
import { ASK_USER_QUESTION_TOOL_NAME } from "../ask-question.js";
|
|
10
|
+
import { routesContent } from "../tool-catalog-entries.js";
|
|
10
11
|
import { ownerStoreOf } from "../permission-rule-provider.js";
|
|
11
12
|
import { readPrincipal } from "../principal-name.js";
|
|
12
13
|
import { thrownText } from "../thrown-value.js";
|
|
13
14
|
import { strongestAnswer } from "../persisted-rule-arms.js";
|
|
14
15
|
import { ORG_ADJUDICATION_TIMEOUT_MS } from "../permission-rule-org.js";
|
|
15
|
-
export const PERSISTED_RULE_TOOL = "Bash";
|
|
16
16
|
const NO_LEADS = new Map();
|
|
17
17
|
export function inheritedAskRuleEvidence(provider) {
|
|
18
18
|
const org = provider?.partitions.org === true ? "not_adjudicated" : "not_wired";
|
|
@@ -123,21 +123,23 @@ export function createPermissionRuleLanes(cfg) {
|
|
|
123
123
|
if (!judged.some(([, g]) => g === "path") && faceRowsSpeakFor(callPathFaceOf(req)))
|
|
124
124
|
judged.push([req.toolName, "path"]);
|
|
125
125
|
const view = await reader.pin(req.toolCallId, req.args);
|
|
126
|
-
|
|
126
|
+
const ownRow = (r) => judged.some(([n]) => n === r.tool) || wholeToolRuleReaches(r.tool, req);
|
|
127
|
+
if (judged.length === 0 && !view.rules.some(ownRow))
|
|
127
128
|
return view.unreadable !== undefined ? { unreadable: true } : undefined;
|
|
128
129
|
try {
|
|
129
130
|
const stripped = view.rules.filter((r) => r.behavior !== "allow" || cfg.stripsAllow?.(r, req) !== true);
|
|
130
131
|
const judgesPath = judged.some(([, g]) => g === "path");
|
|
131
132
|
const noRule = [];
|
|
132
133
|
const table = stripped.filter((r) => {
|
|
133
|
-
const read =
|
|
134
|
+
const read = ownRow(r) || (judgesPath && (r.match === "path" || r.match === "subpath")) ? parseRuleText(r.rule, r.behavior) : undefined;
|
|
134
135
|
if (read !== undefined && "reject" in read)
|
|
135
136
|
noRule.push({ row: r, why: read.reject.message });
|
|
136
137
|
return read === undefined || !("reject" in read) || r.behavior !== "allow";
|
|
137
138
|
});
|
|
138
139
|
const leads = judgesPath ? await cfg.leads.resolve(bindPathRules(table.filter((r) => r.match === "path" || r.match === "subpath").map((r) => ({ parsed: r, ruleText: r.rule, rule: r })), (spec) => anchorsOf(spec.rule))) : NO_LEADS;
|
|
139
140
|
const scopeIdentity = await projectScopeIdentity(table, cfg.rootCanonical, cfg.leads);
|
|
140
|
-
const
|
|
141
|
+
const wholeTool = persistedRuleAnswerOf(adjudicatePersistedToolRules(table, { request: req, cwd: cfg.root, sessionId: cfg.sessionId, ...(scopeIdentity !== undefined ? { scopeIdentity } : {}) }));
|
|
142
|
+
const judgedAnswer = strongestAnswer([...judged.map(([n, grammar]) => judgeAgainst(table, { ...req, toolName: n }, grammar, leads, scopeIdentity)), wholeTool]);
|
|
141
143
|
const unjudged = noRule.find(({ row }) => (row.behavior === "deny" || row.behavior === "ask") && eligiblePersisted(row, { tool: row.tool, cwd: cfg.root, sessionId: cfg.sessionId, ...(scopeIdentity !== undefined ? { scopeIdentity } : {}) }, row.behavior));
|
|
142
144
|
const answer = unjudged !== undefined && !(judgedAnswer !== undefined && "behavior" in judgedAnswer && judgedAnswer.behavior === "deny") ? unjudgedRowAnswer(unjudged.row, unjudged.why, req.toolName) : judgedAnswer;
|
|
143
145
|
const stands = answer !== undefined && (("behavior" in answer && answer.behavior === "deny") || "unreadable" in answer);
|
|
@@ -180,11 +182,9 @@ export function createPermissionRuleLanes(cfg) {
|
|
|
180
182
|
export function createRuleOffersOf(cfg) {
|
|
181
183
|
return (call, args, ask) => {
|
|
182
184
|
const toolName = wireOf("offer.laneTool", call);
|
|
183
|
-
|
|
184
|
-
if (!cfg.laneArmed || (toolName !== PERSISTED_RULE_TOOL && grammar !== "name" && grammar !== "domain"))
|
|
185
|
-
return {};
|
|
186
|
-
if (readPrincipal(cfg.principal).kind === "absent" && !cfg.localOwnerDeclared)
|
|
185
|
+
if (!cfg.laneArmed || (readPrincipal(cfg.principal).kind === "absent" && !cfg.localOwnerDeclared) || routesContent(call.face))
|
|
187
186
|
return {};
|
|
187
|
+
const form = cardRuleFormOf(toolName, call);
|
|
188
188
|
const tierSeat = seatOf("offer.marks", cfg.irreversibilityTier, call);
|
|
189
189
|
const closedDoor = ruleClearanceOf(ask, {
|
|
190
190
|
egress: heldBy("offer.marks.egress", cfg.egressTools, call),
|
|
@@ -193,11 +193,17 @@ export function createRuleOffersOf(cfg) {
|
|
|
193
193
|
}).word;
|
|
194
194
|
if (closedDoor !== undefined)
|
|
195
195
|
return { ruleOffersAbsence: closedDoor };
|
|
196
|
-
if (
|
|
196
|
+
if (form === "tool") {
|
|
197
|
+
const offer = suggestRuleForTool(toolName);
|
|
198
|
+
return offer !== undefined ? { ruleOffers: [offer] } : { ruleOffersAbsence: "lane_cannot_speak" };
|
|
199
|
+
}
|
|
200
|
+
if (form === undefined)
|
|
201
|
+
return { ruleOffersAbsence: "lane_cannot_speak" };
|
|
202
|
+
if (form === "name") {
|
|
197
203
|
const offer = suggestRuleForName(toolName, nameRuleSubjectOf(toolName, args) ?? "");
|
|
198
204
|
return offer !== undefined ? { ruleOffers: [offer] } : { ruleOffersAbsence: "lane_cannot_speak" };
|
|
199
205
|
}
|
|
200
|
-
if (
|
|
206
|
+
if (form === "domain") {
|
|
201
207
|
const host = callHostTargetOf({ toolName: call.toolName, args, face: call.face }, "grant");
|
|
202
208
|
const offer = host !== undefined && "host" in host ? suggestRuleForHost(toolName, host.host) : undefined;
|
|
203
209
|
return offer !== undefined ? { ruleOffers: [offer] } : { ruleOffersAbsence: "lane_cannot_speak" };
|
|
@@ -24,6 +24,7 @@ import { type RecoveredOrphan } from "../session-reconcile.js";
|
|
|
24
24
|
import type { TaskSpec, ToolEffect } from "../types.js";
|
|
25
25
|
import type { PrepareResume } from "./contracts.js";
|
|
26
26
|
import { type ResumeAtBranch } from "./branch-writeback.js";
|
|
27
|
+
import { type LegWrites } from "./session-write-ledger.js";
|
|
27
28
|
export interface PrepareAcquireReconcileInput {
|
|
28
29
|
/** borrowed-mutable (service port) — the deployment's session store. This phase's verbs on it are
|
|
29
30
|
* the acquire/forget half of the session resource protocol: `acquire` per attempt, `forget` to
|
|
@@ -54,6 +55,8 @@ export interface PrepareAcquireReconcileInput {
|
|
|
54
55
|
durableParkGap?: string;
|
|
55
56
|
/** borrowed-readonly — the incident channel for this phase's own cleanup legs: a `resumeAt` branch it could not write back, a forget that did not settle. */
|
|
56
57
|
report?: (err: Error, sessionId: string) => void;
|
|
58
|
+
/** borrowed-mutable (the Runner's) — this leg's view of the session write ledger, every storage write issued through it ({@link writesThroughLeg}); absent for a standalone prepare. */
|
|
59
|
+
legWrites?: LegWrites;
|
|
57
60
|
}
|
|
58
61
|
/** The phase's outputs (four-class form). All six are fresh bindings —
|
|
59
62
|
* the driver destructures them into consts, so a consumer moved ahead of this call is a lexical
|
|
@@ -6,6 +6,7 @@ import { lastAttachmentFrameOf } from "../user-attachment.js";
|
|
|
6
6
|
import { reconcileInterruptedSession } from "../session-reconcile.js";
|
|
7
7
|
import { detectConflicts, settleBranchWriteBack } from "./branch-writeback.js";
|
|
8
8
|
import { settleTeardownLeg } from "./teardown-bounded.js";
|
|
9
|
+
import { writesThroughLeg } from "./session-write-ledger.js";
|
|
9
10
|
const RECONCILE_MAX_RETRIES = 3;
|
|
10
11
|
export async function prepareAcquireReconcile(input) {
|
|
11
12
|
const { sessions, spec, resume, wakeEffects } = input;
|
|
@@ -29,7 +30,7 @@ export async function prepareAcquireReconcile(input) {
|
|
|
29
30
|
}
|
|
30
31
|
conflictRef = { hit: false };
|
|
31
32
|
const own = { ids: undefined };
|
|
32
|
-
session = new StoredSession(detectConflicts(acquired.session.getStorage(), conflictRef, own));
|
|
33
|
+
session = new StoredSession(detectConflicts(input.legWrites !== undefined ? writesThroughLeg(acquired.session.getStorage(), input.legWrites, acquired.sessionId) : acquired.session.getStorage(), conflictRef, own));
|
|
33
34
|
if (!spec.sessionId) {
|
|
34
35
|
break;
|
|
35
36
|
}
|
|
@@ -36,6 +36,12 @@ import type { PrepareResume, RunInternals, ToolFaceLists } from "./contracts.js"
|
|
|
36
36
|
import { resolveHost } from "../../prompt-assembly/select.js";
|
|
37
37
|
import type { PromptTraitName } from "../../prompt-assembly/catalog/schema.js";
|
|
38
38
|
import { type RosterSpec } from "./caller-roster.js";
|
|
39
|
+
/**
|
|
40
|
+
* The model a compaction pass summarizes on: the explicit `compactionModel` wins (resolved at `seat`, the word a
|
|
41
|
+
* refusal names), else the `summarize` role when one is configured, else `undefined` — the pass then falls back to
|
|
42
|
+
* the main model inside `maybeCompact`. One reading for a run's prepare and the out-of-run `Runner.compactSession`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveCompactionModel(spec: Pick<TaskSpec, "compactionModel" | "roles">, deps: Pick<RunnerDeps, "models" | "roles">, seat: string): Model | undefined;
|
|
39
45
|
export declare function limitConfigError(code: string, message: string): Error & {
|
|
40
46
|
code?: string;
|
|
41
47
|
};
|
|
@@ -54,6 +54,9 @@ const RETIRED_TASK_LIMIT_KEYS = {
|
|
|
54
54
|
callCapByDeadline: "(retired — no replacement)",
|
|
55
55
|
gracefulFinalize: "(retired — the approach notice is the only end-of-budget prompt)",
|
|
56
56
|
};
|
|
57
|
+
export function resolveCompactionModel(spec, deps, seat) {
|
|
58
|
+
return spec.compactionModel !== undefined ? resolveModel(spec.compactionModel, deps.models, seat) : roleModelIfSet("summarize", spec, deps);
|
|
59
|
+
}
|
|
57
60
|
export function limitConfigError(code, message) {
|
|
58
61
|
const e = new Error(message);
|
|
59
62
|
e.code = code;
|
|
@@ -482,9 +485,7 @@ export function prepareConfigDoors(input) {
|
|
|
482
485
|
discardedEnvRaw: gateDecision.discardedEnvRaw,
|
|
483
486
|
});
|
|
484
487
|
const thinking = spec.thinking ?? resolvedRole.thinking ?? model.defaultThinking;
|
|
485
|
-
const compModel = spec.compactionModel
|
|
486
|
-
? resolveModel(spec.compactionModel, deps.models, "TaskSpec.compactionModel")
|
|
487
|
-
: roleModelIfSet("summarize", spec, deps);
|
|
488
|
+
const compModel = resolveCompactionModel(spec, deps, "TaskSpec.compactionModel");
|
|
488
489
|
return {
|
|
489
490
|
spec,
|
|
490
491
|
toolFaceLists,
|
|
@@ -2,7 +2,7 @@ import { type BeforeWriteHook, type CwdRef, type PathRuleDenyRow, type Containme
|
|
|
2
2
|
import { type ReadFileState } from "../../tools/fs/safety.js";
|
|
3
3
|
import { type PathTablesFacade, type PersonPathRows, type ReadRootsSeat } from "./person-path-rows.js";
|
|
4
4
|
import type { HeadLeads } from "../path-rule-binding.js";
|
|
5
|
-
import { type ShellReadAdmission, type ShellReadCheck } from "../../tools/fs/shell-read-check.js";
|
|
5
|
+
import { type ShellReadAdmission, type ShellReadCheck, type ShellReadLandings } from "../../tools/fs/shell-read-check.js";
|
|
6
6
|
import type { ShellReadBoundary } from "../../tools/fs/shell-read-judge.js";
|
|
7
7
|
import type { RunnerDeps, ShellGateDoctrine, TaskSpec } from "../types.js";
|
|
8
8
|
import type { Model } from "../../internal/llm.js";
|
|
@@ -215,6 +215,8 @@ export interface PrepareHandsReadFaceResult {
|
|
|
215
215
|
/** owned — the same station's pre-spawn ADMISSION, published for the P11 face that spawns a shell command
|
|
216
216
|
* and mounts LATER than the band (`Monitor`): the SAME function the band's shell faces got. ⇔ a real shell. */
|
|
217
217
|
shellReadAdmission: ShellReadAdmission | undefined;
|
|
218
|
+
/** owned — the same station's landings of a judged call (`ShellReadStation.landings`): the park binds them, the resumed leg's execution station compares. ⇔ a real shell. */
|
|
219
|
+
shellReadLandings: ShellReadLandings | undefined;
|
|
218
220
|
/** owned — the file read station's admission (`FileReadStation.admitted`) the band's read tools got, for the read tools mounted later (LSP). */
|
|
219
221
|
readAdmission: ((toolCallId: string | undefined, canonicalKey: string) => boolean) | undefined;
|
|
220
222
|
/** write-back (D-3 hold) — the run's RESOLVED read face where hands mount; undefined ⇔ no hands
|
|
@@ -86,6 +86,7 @@ export function resolveHandsLessReadFace(input) {
|
|
|
86
86
|
shellReadCheck: undefined,
|
|
87
87
|
shellReadStationArmed: false,
|
|
88
88
|
shellReadAdmission: undefined,
|
|
89
|
+
shellReadLandings: undefined,
|
|
89
90
|
readAdmission: undefined,
|
|
90
91
|
resolvedReadFace: undefined,
|
|
91
92
|
resolvedWriteFace: undefined,
|
|
@@ -411,6 +412,7 @@ export async function prepareHandsMount(input) {
|
|
|
411
412
|
shellReadCheck: onPinnedRead(input.personRows, [...(shellReadStation !== undefined ? [{ check: shellReadStation.check, tools: shellReadTools }] : []), ...(fileReadStation !== undefined ? [fileReadStation] : [])]),
|
|
412
413
|
shellReadStationArmed: shellReadStation !== undefined,
|
|
413
414
|
shellReadAdmission: shellReadStation?.admit,
|
|
415
|
+
shellReadLandings: shellReadStation?.landings,
|
|
414
416
|
readAdmission: fileReadStation?.admitted,
|
|
415
417
|
resolvedReadFace,
|
|
416
418
|
resolvedWriteFace,
|
|
@@ -102,6 +102,8 @@ export interface PrepareParkAskInput {
|
|
|
102
102
|
handsRoot: string | undefined;
|
|
103
103
|
/** borrowed-readonly — the live gate's target-reading stamp ({@link import("./prepare-ask-lane.js").PrepareAskLaneInput.stampCallTarget}). */
|
|
104
104
|
stampCallTarget: CallTargetStamp | undefined;
|
|
105
|
+
/** borrowed-readonly — where the leg's shell read station found a judged call's reads land (the approval object's targets). */
|
|
106
|
+
shellReadLandings: import("../../tools/fs/shell-read-check.js").ShellReadLandings | undefined;
|
|
105
107
|
/** borrowed-readonly — the SAME seat the live gate stamps from ({@link import("./prepare-ask-lane.js").PrepareAskLaneInput.advertisedWritableDirs}): a parked call's projection re-adjudication asks one question about one call, so it must ask it against the same admitted list. Read at park time, not written here. */
|
|
106
108
|
advertisedWritableDirs: Pick<AdvertisedWritableDirs, "roots"> | undefined;
|
|
107
109
|
/** borrowed-readonly — the leg's ONE exempt root, the SAME list the live gate stamps ({@link import("./prepare-ask-lane.js").PrepareAskLaneInput.exemptRoots}). */
|
|
@@ -29,7 +29,7 @@ const wordlessDemand = (toolName) => {
|
|
|
29
29
|
throw new Error(`a real-approval demand for "${toolName}" reached the park with no origin word — the origin stamp precedes every park`);
|
|
30
30
|
};
|
|
31
31
|
export function prepareParkAsk(input) {
|
|
32
|
-
const { askLane, saga, spec, deps, sessionId, checkpointStore, checkpointScope, toolRosterDeltas, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, handsRoot, stampCallTarget, advertisedWritableDirs, exemptRoots, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedTools, irreversibilityTier, toolMarkSources, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, ruleOffersOf, grantBindingOf, now, humanReviewRef, abortController, harness, pausedRef } = input;
|
|
32
|
+
const { askLane, saga, spec, deps, sessionId, checkpointStore, checkpointScope, toolRosterDeltas, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, handsRoot, stampCallTarget, shellReadLandings, advertisedWritableDirs, exemptRoots, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedTools, irreversibilityTier, toolMarkSources, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, ruleOffersOf, grantBindingOf, now, humanReviewRef, abortController, harness, pausedRef } = input;
|
|
33
33
|
if (askLane === undefined || saga === undefined)
|
|
34
34
|
return { parkAsk: undefined };
|
|
35
35
|
const { composedCallSignal, approvalPreviewOf } = askLane;
|
|
@@ -311,7 +311,7 @@ export function prepareParkAsk(input) {
|
|
|
311
311
|
toolCallId: req.toolCallId,
|
|
312
312
|
toolName: req.toolName,
|
|
313
313
|
...parkedToolIdentity(toolRosterDeltas.current, req.toolName), ...parkedToolFace(toolRosterDeltas.current, req),
|
|
314
|
-
...
|
|
314
|
+
...(licenseCovers(parkedHash, req.args) ? approvalTargetsOf(callTargetReadingOf(req), shellReadLandings?.(req.toolCallId)) : {}),
|
|
315
315
|
args: parkedArgs,
|
|
316
316
|
...(() => {
|
|
317
317
|
const p = approvalPreviewOf(req.toolName, parkedArgs);
|
|
@@ -10,7 +10,7 @@ import { isIsolated } from "../remote-env.js";
|
|
|
10
10
|
import { deliverEngineNotice } from "../engine-notice.js";
|
|
11
11
|
import { earlierGrammarNotice } from "../session-policy-store.js";
|
|
12
12
|
import { attest, attestationOf, checkToolPolicyProjection, combinePolicies, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, durableParkOptInDeclared, isLiveApproverSeat, mergeAttestation, refuseOutOfContractDecision, resolveAsk, toolPolicyNameSets, withAttestation, wrapToolPolicy } from "../tool-policy.js";
|
|
13
|
-
import { judgeRuleToolName, mountedToolNames } from "../tool-name-aliases.js";
|
|
13
|
+
import { judgeRuleToolName, mountedToolNames, nearMissSpellingOf } from "../tool-name-aliases.js";
|
|
14
14
|
import { approvalCardMemberOf } from "../tool-roster.js";
|
|
15
15
|
import { NAMESPACED_NAME_SHAPES } from "../protocol-table.js";
|
|
16
16
|
import { emitTrace } from "../trace.js";
|
|
@@ -18,7 +18,7 @@ import { skillGrantBindingMembers } from "../skill-grant.js";
|
|
|
18
18
|
import { SKILL_TOOL_NAME } from "./synthetic-tools.js";
|
|
19
19
|
import { delegationPoolReading } from "./sub-agent-deny-lists.js";
|
|
20
20
|
import { valveLeaves } from "../../agents/tool-filter.js";
|
|
21
|
-
import { autoStrippedRule, cardDisclosureOf,
|
|
21
|
+
import { autoStrippedRule, cardDisclosureOf, rootFacingToolNames } from "../allow-entry.js";
|
|
22
22
|
import { arbitrateByMode, askClassMembersOf, askFaceOf, askMandateMember } from "../ask-origin.js";
|
|
23
23
|
import { createModeGatePolicy, mountedToolDeclaresReadOnly } from "../mode-policy.js";
|
|
24
24
|
const ancestorFacts = (ask) => ({ ...(ask ?? {}), ancestorResolved: true });
|
|
@@ -216,8 +216,6 @@ export async function preparePolicyChain(input) {
|
|
|
216
216
|
const missing = [];
|
|
217
217
|
if (store === undefined)
|
|
218
218
|
missing.push("a wired CheckpointStore");
|
|
219
|
-
else if (store.redecision?.reopen !== true)
|
|
220
|
-
missing.push("a CheckpointStore that DECLARES redecision.reopen (declaration, never duck-typing)");
|
|
221
219
|
if (spec.durableApproval === undefined && runtimeCaps?.forceDurableGate !== true)
|
|
222
220
|
missing.push("a durable park (spec.durableApproval, or the forceDurableGate entitlement)");
|
|
223
221
|
if (missing.length === 0)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { SessionStore } from "../session.js";
|
|
2
2
|
export { runGuardChain, type GuardChainArgs, type GuardChainOutcome } from "./prepare-context-lane.js";
|
|
3
|
+
import type { LegWrites } from "./session-write-ledger.js";
|
|
3
4
|
export { gatedCallIdOf, USAGE_WINDOW_REAP_MARGIN_MS } from "./park-commit.js";
|
|
4
5
|
export { batchContextAt } from "./prepare-park-ask.js";
|
|
5
6
|
export { compensateUnparkedPause } from "./prepare-suspend-saga.js";
|
|
@@ -115,7 +116,9 @@ runIdSink?: {
|
|
|
115
116
|
runId?: string;
|
|
116
117
|
},
|
|
117
118
|
/** The Runner's lock on this leg's session, handed only when the spec named none: taken the moment the store mints the id. */
|
|
118
|
-
holdSessionLock?: (sessionId: string) => Promise<void
|
|
119
|
+
holdSessionLock?: (sessionId: string) => Promise<void>,
|
|
120
|
+
/** This leg's view of the Runner's session write ledger (`session-write-ledger.ts`): the acquired storage writes through it. */
|
|
121
|
+
legWrites?: LegWrites): Promise<Prepared>;
|
|
119
122
|
/** The entry IS the contract the notification lane's seat names ({@link PrepareTaskFn}, contracts.ts):
|
|
120
123
|
* a signature change reds HERE, at the declaration, as `false` failing the `true` bound. IDENTITY, not assignability:
|
|
121
124
|
* the parameter tuple (arity, optionality, each type) and the return type must be the SAME type in both directions —
|