@sema-agent/core 7.7.0 → 7.9.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 +88 -0
- package/dist/agents/agent-transcript-tool.js +2 -2
- package/dist/agents/list-agents-tool.js +2 -3
- package/dist/agents/observer.js +2 -2
- package/dist/agents/send-message-tool.js +2 -1
- package/dist/agents/subagent-steps.js +5 -4
- package/dist/agents/subagent.d.ts +1 -1
- package/dist/agents/subagent.js +2 -3
- package/dist/core/ask-origin.d.ts +12 -1
- package/dist/core/ask-origin.js +5 -1
- package/dist/core/ask-question.js +2 -2
- package/dist/core/checkpoint-store.d.ts +64 -24
- package/dist/core/context-edit.d.ts +0 -22
- package/dist/core/context-edit.js +2 -11
- package/dist/core/engine-notice.d.ts +6 -0
- package/dist/core/fs-write-gate-policy.d.ts +7 -1
- package/dist/core/fs-write-gate-policy.js +7 -7
- package/dist/core/gate-fold.js +2 -2
- package/dist/core/gate-lanes.js +53 -26
- package/dist/core/gate-outcome.d.ts +8 -4
- package/dist/core/gate-outcome.js +2 -1
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +6 -0
- package/dist/core/hooks.d.ts +64 -33
- package/dist/core/hooks.js +1 -1
- package/dist/core/lsp.js +2 -2
- package/dist/core/mcp-server-spec.d.ts +17 -0
- package/dist/core/mcp.js +3 -1
- package/dist/core/memory-engine/tools.js +4 -12
- package/dist/core/permission-rule-consent.d.ts +29 -36
- package/dist/core/permission-rule-consent.js +110 -60
- package/dist/core/permission-rule-model.d.ts +254 -55
- package/dist/core/permission-rule-model.js +323 -43
- package/dist/core/permission-rule-org.d.ts +9 -8
- package/dist/core/permission-rule-org.js +6 -15
- package/dist/core/permission-rule-provider.d.ts +10 -6
- package/dist/core/permission-rule-provider.js +12 -8
- package/dist/core/permission-rule-session.d.ts +7 -6
- package/dist/core/permission-rule-session.js +29 -10
- package/dist/core/permission-rule-store.d.ts +40 -18
- package/dist/core/permission-rule-store.js +68 -42
- package/dist/core/permission-rule-sync.d.ts +9 -3
- package/dist/core/permission-rule-sync.js +29 -25
- package/dist/core/permission-rule-syntax.d.ts +30 -0
- package/dist/core/permission-rule-syntax.js +44 -0
- package/dist/core/permission-rules.d.ts +85 -33
- package/dist/core/permission-rules.js +104 -88
- package/dist/core/persisted-rule-arms.d.ts +56 -0
- package/dist/core/persisted-rule-arms.js +48 -0
- package/dist/core/present-plan-tool.js +3 -4
- package/dist/core/runner/active-skill-scope.js +7 -4
- package/dist/core/runner/compaction-call-options.d.ts +1 -1
- package/dist/core/runner/contracts.d.ts +46 -3
- package/dist/core/runner/permission-rule-lanes.d.ts +33 -26
- package/dist/core/runner/permission-rule-lanes.js +27 -21
- package/dist/core/runner/prepare-ask-lane.d.ts +1 -1
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +5 -4
- package/dist/core/runner/prepare-caps-and-workflow.js +16 -11
- package/dist/core/runner/prepare-defer-classify.d.ts +5 -26
- package/dist/core/runner/prepare-defer-classify.js +10 -10
- package/dist/core/runner/prepare-delegation-surface.d.ts +5 -4
- package/dist/core/runner/prepare-delegation-surface.js +15 -17
- package/dist/core/runner/prepare-gate-stations.d.ts +4 -1
- package/dist/core/runner/prepare-gate-stations.js +4 -2
- package/dist/core/runner/prepare-hands-readface.d.ts +3 -2
- package/dist/core/runner/prepare-hands-readface.js +3 -2
- package/dist/core/runner/prepare-inherited-gate.d.ts +1 -1
- package/dist/core/runner/prepare-inherited-gate.js +1 -0
- package/dist/core/runner/prepare-lsp.d.ts +4 -3
- package/dist/core/runner/prepare-lsp.js +3 -2
- package/dist/core/runner/prepare-memory-engine-session.d.ts +4 -4
- package/dist/core/runner/prepare-memory-engine-session.js +4 -2
- package/dist/core/runner/prepare-offload-wrappers.js +7 -5
- 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-project-context.d.ts +5 -23
- package/dist/core/runner/prepare-project-context.js +7 -5
- package/dist/core/runner/prepare-prompt-assembly.d.ts +1 -1
- package/dist/core/runner/prepare-protocol-tools.d.ts +5 -1
- package/dist/core/runner/prepare-protocol-tools.js +38 -21
- package/dist/core/runner/prepare-question-face.d.ts +4 -3
- package/dist/core/runner/prepare-question-face.js +5 -3
- package/dist/core/runner/prepare-run-refs.d.ts +16 -0
- package/dist/core/runner/prepare-run-refs.js +6 -0
- package/dist/core/runner/prepare-safety-scan.js +48 -2
- package/dist/core/runner/prepare-task.js +37 -19
- package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +5 -2
- package/dist/core/runner/prepare-tool-disclosure-mount.js +3 -1
- package/dist/core/runner/prepare-wiring-manifest.d.ts +4 -0
- package/dist/core/runner/prepare-wiring-manifest.js +3 -8
- package/dist/core/runner/resume-admission.d.ts +53 -0
- package/dist/core/runner/resume-admission.js +83 -0
- package/dist/core/runner/resume-apply.d.ts +50 -0
- package/dist/core/runner/resume-apply.js +184 -0
- package/dist/core/runner/resume-checkpoint-screen.d.ts +18 -0
- package/dist/core/runner/resume-checkpoint-screen.js +108 -0
- package/dist/core/runner/resume-claim.d.ts +32 -0
- package/dist/core/runner/resume-claim.js +27 -0
- package/dist/core/runner/resume-internals-and-config.d.ts +33 -0
- package/dist/core/runner/resume-internals-and-config.js +50 -0
- package/dist/core/runner/resume-policy-outcome.d.ts +31 -0
- package/dist/core/runner/resume-policy-outcome.js +127 -0
- package/dist/core/runner/resume-preflight.d.ts +40 -0
- package/dist/core/runner/resume-preflight.js +122 -0
- package/dist/core/runner/resume-review-outcome.d.ts +30 -0
- package/dist/core/runner/resume-review-outcome.js +88 -0
- package/dist/core/runner/run-harness-handlers.d.ts +46 -0
- package/dist/core/runner/run-harness-handlers.js +345 -0
- package/dist/core/runner/run-turn-boundary.d.ts +69 -0
- package/dist/core/runner/run-turn-boundary.js +694 -0
- package/dist/core/runner/runtask.d.ts +20 -0
- package/dist/core/runner/runtask.js +129 -1774
- package/dist/core/runner/session-rule-policy.js +9 -4
- package/dist/core/runner/synthetic-tools.js +5 -8
- package/dist/core/runner/tool-disclosure.d.ts +4 -0
- package/dist/core/runner/tool-disclosure.js +9 -5
- package/dist/core/runner/tool-end-body.d.ts +12 -5
- package/dist/core/runner/tool-end-body.js +8 -7
- package/dist/core/runner/tool-face-overlay.d.ts +40 -0
- package/dist/core/runner/tool-face-overlay.js +125 -0
- package/dist/core/runner/tool-output-projection.d.ts +14 -1
- package/dist/core/runner/tool-output-projection.js +24 -18
- package/dist/core/runner/turn-attachments.d.ts +2 -2
- package/dist/core/sensitive-path-policy.d.ts +3 -0
- package/dist/core/sensitive-path-policy.js +6 -5
- package/dist/core/shared-memory/tools.js +3 -6
- package/dist/core/store-contracts/checkpoint-store-contract.js +23 -0
- package/dist/core/store-contracts/permission-rule-sync-contract.js +29 -10
- package/dist/core/task-event.d.ts +10 -0
- package/dist/core/task-registry.js +4 -5
- package/dist/core/task-spec.d.ts +8 -0
- package/dist/core/tool-catalog-entries.d.ts +48 -0
- package/dist/core/tool-catalog-entries.js +174 -0
- package/dist/core/tool-conformance.d.ts +22 -0
- package/dist/core/tool-conformance.js +37 -0
- package/dist/core/tool-face.d.ts +171 -0
- package/dist/core/tool-face.js +25 -0
- package/dist/core/tool-policy.d.ts +24 -0
- package/dist/core/tool-policy.js +4 -2
- package/dist/core/tool-registry.d.ts +114 -0
- package/dist/core/tool-registry.js +114 -0
- package/dist/core/tool-result-budget.d.ts +0 -3
- package/dist/core/tool-result-budget.js +4 -3
- package/dist/core/tool-result-store.d.ts +0 -18
- package/dist/core/tool-result-store.js +2 -18
- package/dist/core/tool-roster.d.ts +459 -0
- package/dist/core/tool-roster.js +507 -0
- package/dist/core/tool-spec.d.ts +54 -3
- package/dist/core/tools.js +7 -0
- package/dist/core/wiring-manifest.d.ts +13 -0
- package/dist/core/wiring-manifest.js +2 -1
- package/dist/core/write-protect.d.ts +2 -1
- package/dist/core/write-protect.js +5 -4
- package/dist/engine/compaction/utils.d.ts +6 -0
- package/dist/engine/compaction/utils.js +19 -19
- package/dist/engine/loop/types.d.ts +6 -0
- package/dist/index.d.ts +17 -6
- package/dist/index.js +17 -6
- package/dist/orchestration/goal.js +2 -1
- package/dist/orchestration/run-spec.js +3 -5
- package/dist/orchestration/run-workflow-tool.js +2 -2
- package/dist/prompt-assembly/event-registry.js +3 -3
- package/dist/prompt-assembly/tool-catalog.d.ts +2 -2
- package/dist/stores/file/checkpoint-store.js +1 -1
- package/dist/stores/file/permission-rule-store.d.ts +28 -23
- package/dist/stores/file/permission-rule-store.js +64 -16
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
- package/dist/tools/fs/fs-bash.d.ts +1 -1
- package/dist/tools/fs/fs-bash.js +7 -11
- package/dist/tools/fs/fs-pdf.d.ts +1 -1
- package/dist/tools/fs/fs-read.js +2 -2
- package/dist/tools/fs/fs-search-tools.d.ts +0 -7
- package/dist/tools/fs/fs-search-tools.js +3 -16
- package/dist/tools/fs/fs-write.js +4 -6
- package/dist/tools/fs/notebook.d.ts +1 -1
- package/dist/tools/fs/repo-map.js +2 -2
- package/dist/tools/fs/safety.d.ts +3 -2
- package/dist/tools/fs/safety.js +6 -5
- package/dist/tools/monitor.js +2 -2
- package/dist/tools/scheduler-tools.js +5 -8
- package/dist/tools/task-list.js +5 -8
- package/dist/tools/todo.js +2 -2
- package/dist/tools/web.js +3 -6
- package/dist/tools/worktree.js +3 -4
- package/package.json +4 -1
- package/test/export-surface.snapshot.json +189 -17
|
@@ -15,7 +15,7 @@ import type { Prepared } from "./contracts.js";
|
|
|
15
15
|
* end-of-task lane's deliberate ABSENCE of `signal`) is a legitimate per-lane difference and stays at
|
|
16
16
|
* the call site, where its reason is written down.
|
|
17
17
|
*
|
|
18
|
-
* Every export is a free function: the turn-boundary lane assembles its call inside `
|
|
18
|
+
* Every export is a free function: the turn-boundary lane assembles its call inside `createTurnBoundary`
|
|
19
19
|
* (a module-level function with no `this`), so a method would not be reachable from all three sites.
|
|
20
20
|
* Nothing here reads or writes runner state — pure assembly over `spec` + `Prepared`.
|
|
21
21
|
*/
|
|
@@ -315,6 +315,14 @@ export interface Prepared {
|
|
|
315
315
|
/** design/99 §E6 — the DENY-NARROWING layers (session rules + skill scope, deny-only). Re-checked on RESUME
|
|
316
316
|
* before an approved pending tool executes, so a rule tightened during the suspend still applies. */
|
|
317
317
|
denyNarrowingPolicy?: ToolPolicy;
|
|
318
|
+
/** #632 — the person's own persisted-rule lane (deny/ask rows), re-adjudicated on RESUME at the same
|
|
319
|
+
* station as the deny-narrowing layers: a deny row added while the call was parked vetoes the execution
|
|
320
|
+
* (`deniedBy: "persisted_rule"`); an ask row or an unreadable store fails closed the same way (the approval
|
|
321
|
+
* answered a question the person has since asked to be asked again — re-issue and re-approve). Absent when
|
|
322
|
+
* no rule store is wired. */
|
|
323
|
+
persistedRuleLane?: {
|
|
324
|
+
adjudicate: (req: ToolCallRequest) => Promise<import("../hooks.js").PersistedRuleAnswer>;
|
|
325
|
+
};
|
|
318
326
|
/** RB-63: the deployment's own caller policy, re-checked on a durable resume ONLY when the approver
|
|
319
327
|
* rewrote the pending call's args (see the composition site for why the edit case is special). */
|
|
320
328
|
basePolicyForResumeEdit?: ToolPolicy;
|
|
@@ -718,7 +726,10 @@ export interface Prepared {
|
|
|
718
726
|
* the human already adjudicated it). Same wrapping (offload + ctx) the harness runs with.
|
|
719
727
|
*
|
|
720
728
|
* ONE array, mutated in place; identity is the contract (every closure that resolves a name at run time
|
|
721
|
-
* reads this exact array).
|
|
729
|
+
* reads this exact array). Since design/388 the array is PRIVATE to the `RosterBuilder` (tool-roster.ts) —
|
|
730
|
+
* every station below writes through its verbs (`mount` / `mountAll` / `unmountWhere` / `replaceAt` /
|
|
731
|
+
* `replaceDomain`) and this field is the builder's read face. WRITER TABLE (design/238 R-3) — the only
|
|
732
|
+
* stations that write it, in prepare order:
|
|
722
733
|
* · caps-and-workflow — MINTS it (`spec.tools` through the ctx wrap + the large-result wrapper), then pushes
|
|
723
734
|
* ReportBlocked (enableBlockedReport ≠ false), ReportFindings (no caller tool of that name/alias),
|
|
724
735
|
* ExitPlanMode + EnterPlanMode (enablePlanMode ∧ the plan-review face), Workflow (self-orchestration active
|
|
@@ -740,7 +751,28 @@ export interface Prepared {
|
|
|
740
751
|
* memory session or a recorder channel); the refresh seam re-runs the same pass through `contentOriginWrapRef`
|
|
741
752
|
* after a re-splice (identity-tracked, so a wrapper is never wrapped again).
|
|
742
753
|
* tool-disclosure and listings only READ it (`harnessTools` is a derived list; placeholders never enter here). */
|
|
743
|
-
tools: AgentTool[];
|
|
754
|
+
tools: readonly AgentTool[];
|
|
755
|
+
/**
|
|
756
|
+
* design/388 §2.5 — this leg's minted TOOL ROSTER (the same object `wiringManifest.tools` carries):
|
|
757
|
+
* one row per mounted instance in wire order. Minted ONCE at the prompt-assembly station (the same
|
|
758
|
+
* pass that projects the prompt manifest's tool rows, so the two agree by construction); the park
|
|
759
|
+
* station reads the gated call's identity off it, the exemption probe hands it to the host.
|
|
760
|
+
*/
|
|
761
|
+
toolRoster: import("../tool-roster.js").ToolRoster;
|
|
762
|
+
/**
|
|
763
|
+
* design/388 §2.5 — the run-time delta seat: every roster change after prepare (the RefreshMcpTools
|
|
764
|
+
* seam) re-mints the roster here and publishes a `ToolRosterDelta`. The run loop subscribes at the
|
|
765
|
+
* point it emits `wiring_manifest` and forwards each delta as a `tool_roster_delta` event; until it
|
|
766
|
+
* does, deltas are buffered in order.
|
|
767
|
+
*/
|
|
768
|
+
toolRosterDeltas: import("../tool-roster.js").ToolRosterDeltaSeat;
|
|
769
|
+
/**
|
|
770
|
+
* design/388 L4 — the leg's `tool_end.structured` projector: the engine card set ∪ the caller rows' declared
|
|
771
|
+
* `renderHints.resultCards`; an undeclared `details.type` is dropped and announced ONCE per leg
|
|
772
|
+
* (`config.tool_card_undeclared`). The ONE card port: every tool_end body projection (the live loop, the resumed
|
|
773
|
+
* batch, the reconcile-recovered orphan) takes it as a parameter; no module-level card set exists to fall back to.
|
|
774
|
+
*/
|
|
775
|
+
structuredProjector: (result: unknown) => unknown;
|
|
744
776
|
/** Name→effect map for every tool this task can call (design/44 §3). Used by the abort-path orphan
|
|
745
777
|
* reconcile (design/64 §9) to make interrupted tool_results effect-aware (read/idempotent = safe to
|
|
746
778
|
* repeat; write/unknown = outcome unknown). Unknown names default to `write` (conservative). */
|
|
@@ -1985,7 +2017,7 @@ export interface ParkAsk {
|
|
|
1985
2017
|
* Grouped by lifecycle semantics per the B15 pre-recon partition. Function members start as inert
|
|
1986
2018
|
* placeholders and are assigned at their ORIGINAL declaration sites (the original code could not
|
|
1987
2019
|
* call them earlier either — TDZ proved it). Not on the npm face; this extraction is what enabled
|
|
1988
|
-
*
|
|
2020
|
+
* createTurnBoundary / createHarnessHandlers (三期, both in runtask.ts).
|
|
1989
2021
|
*/
|
|
1990
2022
|
export interface RunState {
|
|
1991
2023
|
telemetry: {
|
|
@@ -2331,6 +2363,17 @@ export interface HarnessHandlersDeps {
|
|
|
2331
2363
|
* Signatures are spelled out (not `Pick<Runner, …>`), because naming the class from here would be the
|
|
2332
2364
|
* very edge this seat exists to remove.
|
|
2333
2365
|
*/
|
|
2366
|
+
/**
|
|
2367
|
+
* The Runner's deployment deps as a LIVE read for the lanes that read them after an await (the resume ladder's
|
|
2368
|
+
* rungs). `Runner.deps` is not a constant: `swapModels` replaces the object, so a lane handed the object at its
|
|
2369
|
+
* call would read a stale catalog — and a stale anything — where the one-function ladder read `this.deps.x` at the
|
|
2370
|
+
* instant of the read. The seat is the Runner's own view (a getter over the private field), so `runner.deps.x`
|
|
2371
|
+
* in a lane is exactly `this.deps.x` in the method it came from.
|
|
2372
|
+
*/
|
|
2373
|
+
export interface RunnerDepsSeat {
|
|
2374
|
+
/** The deps object the Runner holds RIGHT NOW — never cache it across an await. */
|
|
2375
|
+
readonly deps: RunnerDeps;
|
|
2376
|
+
}
|
|
2334
2377
|
export interface RunnerSelfSeat {
|
|
2335
2378
|
/** The session store this Runner was constructed over — the delegation tools acquire / release / fork through it. */
|
|
2336
2379
|
readonly sessions: SessionStore;
|
|
@@ -9,13 +9,15 @@
|
|
|
9
9
|
*
|
|
10
10
|
* ## One read per adjudicated call
|
|
11
11
|
*
|
|
12
|
-
* The gate consults the org lane (`orgRules.adjudicate`)
|
|
13
|
-
* (`persistedRules.
|
|
12
|
+
* The gate consults the org lane (`orgRules.adjudicate`) and then the personal lane
|
|
13
|
+
* (`persistedRules.adjudicate`) on every decision, in that order (the personal lane's deny/ask rows must
|
|
14
|
+
* be able to tighten an allow, so it can no longer wait for a surviving ask). The org lane's read is
|
|
14
15
|
* HANDED to the personal lane by `toolCallId` (taken once, then forgotten), so a governed deployment pays
|
|
15
16
|
* one store query — one org-source fetch — per call, exactly as it did with two seams. An entry the
|
|
16
|
-
* personal lane never claims (
|
|
17
|
-
* evicted or never-handed entry simply costs the personal lane its own read. The
|
|
18
|
-
* device, not a semantic one: both lanes judge one snapshot, which is the honest shape
|
|
17
|
+
* personal lane never claims (a call on a tool it does not speak for) is evicted first-in-first-out past
|
|
18
|
+
* a small bound; an evicted or never-handed entry simply costs the personal lane its own read. The
|
|
19
|
+
* handoff is a cost device, not a semantic one: both lanes judge one snapshot, which is the honest shape
|
|
20
|
+
* for one decision.
|
|
19
21
|
*
|
|
20
22
|
* ## Where the lanes do NOT go
|
|
21
23
|
*
|
|
@@ -25,14 +27,12 @@
|
|
|
25
27
|
*/
|
|
26
28
|
import type { AskRuleEvidence, ToolCallRequest } from "../tool-policy.js";
|
|
27
29
|
import { persistedRuleMandateOf, type OrgGateVerdict, type PersistedRuleAnswer, type PersistedRuleHit } from "../hooks.js";
|
|
28
|
-
import type {
|
|
30
|
+
import type { PersistedRule, PersistedRuleVerdict, RuleOffer, SegmentCoverage } from "../permission-rule-model.js";
|
|
29
31
|
import { type OrgRuleResolution } from "../permission-rule-org.js";
|
|
30
32
|
import type { PermissionRuleStoreProvider } from "../permission-rule-provider.js";
|
|
31
|
-
/** The one SHELL tool the persisted-rule lane speaks for
|
|
33
|
+
/** The one SHELL tool the persisted-rule lane's COMMAND grammar speaks for (the rule-offer face mints for
|
|
34
|
+
* it alone). The PATH grammar's tools are derived from the catalog (`ruleToolGrammarOf`). */
|
|
32
35
|
export declare const PERSISTED_RULE_TOOL = "Bash";
|
|
33
|
-
/** design/382 §2.5 — the READ tool the directory-rule family speaks for (its one other admission
|
|
34
|
-
* point, the cd-segment notch, lives inside the model's own conjunction/coverage arms). */
|
|
35
|
-
export declare const DIRECTORY_RULE_TOOL = "Read";
|
|
36
36
|
/**
|
|
37
37
|
* design/252 G-2 — the evidence an INHERITED-lane ask carries.
|
|
38
38
|
*
|
|
@@ -67,28 +67,35 @@ export declare function orgRevisionEvidenceOf(resolution: OrgRuleResolution, onD
|
|
|
67
67
|
revision?: number;
|
|
68
68
|
};
|
|
69
69
|
/**
|
|
70
|
-
* design/252 G-2 / design/375 — project the
|
|
71
|
-
* each member's canonical text plus its own add DOTS.
|
|
72
|
-
*
|
|
73
|
-
* segment order
|
|
70
|
+
* design/252 G-2 / design/375 — project the model's verdict onto the gate's rule-lane answer: the
|
|
71
|
+
* behavior that spoke, and each member's canonical text plus its own add DOTS. For an allow the set is
|
|
72
|
+
* the admitting COVERAGE SET (a single rule admitting the whole command is a one-element set; a compound
|
|
73
|
+
* admitted by the per-segment conjunction is the set of covering rules in segment order — the model's
|
|
74
|
+
* own reporting-order contract); for a deny/ask it is the one reaching rule the precedence walk chose.
|
|
74
75
|
*
|
|
75
76
|
* `adds` on a listed rule are the LIVE adds — the store's read already dropped tombstoned dots — so
|
|
76
|
-
* this is the set that actually
|
|
77
|
+
* this is the set that actually decided the call, which is the identity a later audit reconciles a
|
|
77
78
|
* shadowed ask against. The sanitized display text deliberately is not one. Copied rather than
|
|
78
79
|
* aliased: the evidence must not change under a store that reuses its row objects.
|
|
79
80
|
*/
|
|
80
|
-
export declare function persistedRuleHitOf(
|
|
81
|
+
export declare function persistedRuleHitOf(verdict: PersistedRuleVerdict | undefined): PersistedRuleHit | undefined;
|
|
81
82
|
/**
|
|
82
|
-
* design/382 §2.5-1 — the persisted-rule lane's
|
|
83
|
-
* identity the rule family is defined over — absolute as spelled, relative
|
|
84
|
-
* tracked working directory (the very base the
|
|
85
|
-
* tracker moved), then normalized lexically, zero IO.
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
83
|
+
* design/382 §2.5-1, widened to every path-targeting tool — the persisted-rule lane's PATH arm: the call's
|
|
84
|
+
* target path in the SAME lexical identity the rule family is defined over — absolute as spelled, relative
|
|
85
|
+
* resolved against the LIVE tracked working directory (the very base the file tools themselves resolve
|
|
86
|
+
* against; task root when no tracker moved), then normalized lexically, zero IO.
|
|
87
|
+
*
|
|
88
|
+
* TWO readings of the call's path slot, one per direction (design/388 B6/B17): the tightening arms judge
|
|
89
|
+
* the PROTECTIVE target (the object face's declaration, the catalog's for the name as the floor — reading
|
|
90
|
+
* the catalog for an undeclared same-name tool can only tighten a deny); the allow arm judges the DECLARED
|
|
91
|
+
* target (the face's OWN declaration only — a same-name tool that declares no path target is unconfirmable
|
|
92
|
+
* and no grant admits it). The precedence walk, the admission predicates and the Read-only allow are the
|
|
93
|
+
* model's (`adjudicatePersistedPathRules`). An ALLOW here clears ASKS only — the read fences (workspace
|
|
94
|
+
* containment, the sensitive-read deny face) judge inside the tool exactly as they would with no rule
|
|
95
|
+
* anywhere — and an unresolvable path is simply no verdict (fail toward asking on the allow side, no
|
|
96
|
+
* refusal on the tightening side: a rule about a path speaks about no other shape).
|
|
90
97
|
*/
|
|
91
|
-
export declare function
|
|
98
|
+
export declare function pathRuleLaneAnswer(table: readonly PersistedRule[], req: Pick<ToolCallRequest, "toolName" | "args" | "face">, ctx: {
|
|
92
99
|
root: string | undefined;
|
|
93
100
|
sessionId: string | undefined;
|
|
94
101
|
liveCwd: string | undefined;
|
|
@@ -97,7 +104,7 @@ export declare function directoryRuleLaneAnswer(table: readonly PersistedAllowRu
|
|
|
97
104
|
* a deployment without one keeps a decision path byte-identical to a build without the feature. */
|
|
98
105
|
export interface PermissionRuleLanes {
|
|
99
106
|
personal: {
|
|
100
|
-
|
|
107
|
+
adjudicate: (req: ToolCallRequest) => Promise<PersistedRuleAnswer>;
|
|
101
108
|
} | undefined;
|
|
102
109
|
org: {
|
|
103
110
|
adjudicate: (req: ToolCallRequest) => Promise<OrgGateVerdict>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { persistedRuleMandateOf } from "../hooks.js";
|
|
2
|
-
import {
|
|
2
|
+
import { adjudicatePersistedPathRules, adjudicatePersistedRules, lexicalNormalAbsolutePathOf, ruleToolGrammarOf, segmentCoverageOf, suggestRulesForCommand } from "../permission-rule-model.js";
|
|
3
|
+
import { declaredPathTargetOf, pathTargetValue, protectivePathTargetOf } from "../tool-registry.js";
|
|
3
4
|
import { orgRuleVerdictFor } from "../permission-rule-org.js";
|
|
4
5
|
export const PERSISTED_RULE_TOOL = "Bash";
|
|
5
|
-
export const DIRECTORY_RULE_TOOL = "Read";
|
|
6
6
|
const HANDOFF_BOUND = 256;
|
|
7
7
|
export function inheritedAskRuleEvidence(provider) {
|
|
8
8
|
const org = provider?.partitions.org === true ? "not_adjudicated" : "not_wired";
|
|
@@ -19,21 +19,26 @@ export function orgRevisionEvidenceOf(resolution, onDefect) {
|
|
|
19
19
|
`the adjudication stands, but the ask carries no revision evidence for this call`);
|
|
20
20
|
return {};
|
|
21
21
|
}
|
|
22
|
-
export function persistedRuleHitOf(
|
|
23
|
-
return
|
|
22
|
+
export function persistedRuleHitOf(verdict) {
|
|
23
|
+
return verdict === undefined
|
|
24
24
|
? undefined
|
|
25
|
-
: { rules:
|
|
25
|
+
: { behavior: verdict.behavior, rules: verdict.rules.map((r) => ({ rule: r.rule, dots: r.adds.map((a) => ({ actor: a.dot.actor, counter: a.dot.counter })) })) };
|
|
26
26
|
}
|
|
27
|
-
export function
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
export function pathRuleLaneAnswer(table, req, ctx) {
|
|
28
|
+
const base = (ctx.liveCwd ?? ctx.root ?? "").replace(/\/+$/, "");
|
|
29
|
+
const resolve = (pt) => {
|
|
30
|
+
if (pt === undefined)
|
|
31
|
+
return undefined;
|
|
32
|
+
const spelled = pathTargetValue(req.args, pt);
|
|
33
|
+
if (spelled === undefined)
|
|
34
|
+
return undefined;
|
|
35
|
+
return lexicalNormalAbsolutePathOf(spelled.startsWith("/") ? spelled : `${base}/${spelled}`);
|
|
36
|
+
};
|
|
37
|
+
const tighten = resolve(protectivePathTargetOf(req));
|
|
38
|
+
const allow = resolve(declaredPathTargetOf(req));
|
|
39
|
+
if (tighten === undefined && allow === undefined)
|
|
34
40
|
return undefined;
|
|
35
|
-
|
|
36
|
-
return hit !== undefined ? persistedRuleHitOf([hit]) : undefined;
|
|
41
|
+
return persistedRuleHitOf(adjudicatePersistedPathRules(table, { tool: req.toolName, cwd: ctx.root, sessionId: ctx.sessionId }, { ...(tighten !== undefined ? { tighten } : {}), ...(allow !== undefined ? { allow } : {}) }, { ...(ctx.root !== undefined ? { root: ctx.root } : {}), ...(ctx.liveCwd !== undefined ? { cwd: ctx.liveCwd } : {}) }));
|
|
37
42
|
}
|
|
38
43
|
export function createPermissionRuleLanes(cfg) {
|
|
39
44
|
const provider = cfg.provider;
|
|
@@ -103,10 +108,11 @@ export function createPermissionRuleLanes(cfg) {
|
|
|
103
108
|
: undefined;
|
|
104
109
|
const personal = provider.partitions.durable
|
|
105
110
|
? {
|
|
106
|
-
|
|
111
|
+
adjudicate: async (req) => {
|
|
107
112
|
if (anonymous && !cfg.localOwnerDeclared)
|
|
108
113
|
return undefined;
|
|
109
|
-
|
|
114
|
+
const grammar = ruleToolGrammarOf(req.toolName);
|
|
115
|
+
if (grammar === undefined)
|
|
110
116
|
return undefined;
|
|
111
117
|
let view;
|
|
112
118
|
try {
|
|
@@ -122,16 +128,16 @@ export function createPermissionRuleLanes(cfg) {
|
|
|
122
128
|
}
|
|
123
129
|
const table = view.rules;
|
|
124
130
|
const liveCwd = cfg.liveCwd();
|
|
125
|
-
if (
|
|
126
|
-
return
|
|
131
|
+
if (grammar === "path") {
|
|
132
|
+
return pathRuleLaneAnswer(table, req, { root: cfg.root, sessionId: cfg.sessionId, liveCwd });
|
|
127
133
|
}
|
|
128
134
|
const command = req.args?.command;
|
|
129
135
|
if (typeof command !== "string")
|
|
130
136
|
return undefined;
|
|
131
137
|
const execCwd = liveCwd !== undefined ? { execCwd: liveCwd } : {};
|
|
132
|
-
const
|
|
133
|
-
if (
|
|
134
|
-
return persistedRuleHitOf(
|
|
138
|
+
const verdict = adjudicatePersistedRules(table, { tool: req.toolName, command, cwd: cfg.root, sessionId: cfg.sessionId, ...execCwd });
|
|
139
|
+
if (verdict !== undefined)
|
|
140
|
+
return persistedRuleHitOf(verdict);
|
|
135
141
|
const coverage = segmentCoverageOf(command, { persisted: table }, { tool: req.toolName, cwd: cfg.root, sessionId: cfg.sessionId, ...execCwd });
|
|
136
142
|
return coverage !== undefined ? { segmentCoverage: coverage } : undefined;
|
|
137
143
|
},
|
|
@@ -46,7 +46,7 @@ export interface PrepareAskLaneInput {
|
|
|
46
46
|
handsCwdRef: CwdRef | undefined;
|
|
47
47
|
/** borrowed-readonly — the shared mount roster; read at RUN time by the approval-preview projection (alias-aware
|
|
48
48
|
* lookup over whatever the roster holds when the ask is minted). Never mutated here. */
|
|
49
|
-
tools: AgentTool[];
|
|
49
|
+
tools: readonly AgentTool[];
|
|
50
50
|
/** borrowed-mutable — the inherited-unavailable marker set. Writer here: `resolveAskBound` consumes (`delete`) a
|
|
51
51
|
* marked call at its fail-closed intercept; the policy-chain phase records, the gate station sweeps. */
|
|
52
52
|
inheritedUnavailableAsks: Set<string>;
|
|
@@ -34,6 +34,7 @@ import type { AutoModeArmReason } from "../wiring-manifest.js";
|
|
|
34
34
|
import type { ReadFace } from "../../tools/fs/index.js";
|
|
35
35
|
import type { InheritedGate, Prepared, RunInternals, RunnerSelfSeat, ToolFaceSnapshot } from "./contracts.js";
|
|
36
36
|
import { type BlockedRef } from "./synthetic-tools.js";
|
|
37
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
37
38
|
export interface PrepareCapsAndWorkflowInput {
|
|
38
39
|
/** borrowed-readonly — the REBOUND spec, whole: the roster map reads `tools`; the mounts read `enableBlockedReport`,
|
|
39
40
|
* `enablePlanMode`, `interactiveTools`, `checkpointStore`; the caps/compliance stations read `principal`, `selfOrchestration`,
|
|
@@ -124,10 +125,10 @@ export interface PrepareCapsAndWorkflowInput {
|
|
|
124
125
|
}>;
|
|
125
126
|
}
|
|
126
127
|
export interface PrepareCapsAndWorkflowResult {
|
|
127
|
-
/** owned — THE run's roster
|
|
128
|
-
*
|
|
129
|
-
* ReportFindings, ExitPlanMode, EnterPlanMode and Workflow
|
|
130
|
-
|
|
128
|
+
/** owned — THE run's roster BUILDER (design/388: the mount array is private to it; `Prepared.tools` is its read face,
|
|
129
|
+
* whose JSDoc carries the writer table). Minted here from the caller's tools; every later mount goes through its verbs.
|
|
130
|
+
* Writers here: the caller mounts, then the ReportBlocked, ReportFindings, ExitPlanMode, EnterPlanMode and Workflow mounts. */
|
|
131
|
+
roster: RosterBuilder;
|
|
131
132
|
/** borrowed-mutable — the ReportBlocked tool's write seat (`Prepared.blockedRef`). Writer: the tool at run time; read at
|
|
132
133
|
* result assembly. */
|
|
133
134
|
blockedRef: BlockedRef;
|
|
@@ -2,7 +2,7 @@ import { isSyntheticApiErrorMessage } from "../../internal/harness.js";
|
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { forkGovernanceDenial } from "../../agents/subagent.js";
|
|
4
4
|
import { CROSS_SESSION_CLASSIFIER_RULE } from "../../agents/cross-session-envelope.js";
|
|
5
|
-
import { createRunWorkflowTool
|
|
5
|
+
import { createRunWorkflowTool } from "../../orchestration/run-workflow-tool.js";
|
|
6
6
|
import { isSelfOrchestrationActive } from "../../orchestration/workflow-script-runner.js";
|
|
7
7
|
import { resolveWorkflowSizeGuideline } from "../../orchestration/workflow-size-guideline.js";
|
|
8
8
|
import { thinkingOffExpressible } from "../../brain/reasoning.js";
|
|
@@ -20,6 +20,7 @@ import { emitTrace } from "../trace.js";
|
|
|
20
20
|
import { defineTool, isDefineToolProduct } from "../tools.js";
|
|
21
21
|
import { derivedRouteFallsBack } from "./derived-route-fallback.js";
|
|
22
22
|
import { REPORT_FINDINGS_TOOL_NAME, createReportBlockedTool, createReportFindingsTool } from "./synthetic-tools.js";
|
|
23
|
+
import { RosterBuilder, callerMountSource } from "../tool-roster.js";
|
|
23
24
|
function assembleParentCaptureState(o, i, ctl, ancestors) {
|
|
24
25
|
const build = (optedOut, indeterminate) => ({
|
|
25
26
|
optedOut: optedOut === true,
|
|
@@ -65,7 +66,12 @@ function autoModeArmReasonOf(intent, facePresent, capsAutoMode, capsFaulted) {
|
|
|
65
66
|
}
|
|
66
67
|
export async function prepareCapsAndWorkflow(input) {
|
|
67
68
|
const { spec, deps, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, frozenOnAsk, carrierReadFace, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, autoModeIntent, peerLaneActive, peerSendMessageBuiltIn, runnerSelf } = input;
|
|
68
|
-
const
|
|
69
|
+
const roster = new RosterBuilder(toolEffects);
|
|
70
|
+
for (const t of spec.tools ?? []) {
|
|
71
|
+
const mounted = mountCallerTool(t);
|
|
72
|
+
roster.mount(mounted, { source: callerMountSource(mounted), mountedBy: "scenario" });
|
|
73
|
+
}
|
|
74
|
+
function mountCallerTool(t) {
|
|
69
75
|
if (isDefineToolProduct(t)) {
|
|
70
76
|
return maybeOffload(t, t);
|
|
71
77
|
}
|
|
@@ -73,20 +79,20 @@ export async function prepareCapsAndWorkflow(input) {
|
|
|
73
79
|
...t,
|
|
74
80
|
execute: (args, ctx) => t.execute(args, enrichSpecToolCtx(ctx)),
|
|
75
81
|
}), t);
|
|
76
|
-
}
|
|
82
|
+
}
|
|
77
83
|
const blockedRef = {};
|
|
78
84
|
if (spec.enableBlockedReport !== false) {
|
|
79
|
-
|
|
85
|
+
roster.mount(createReportBlockedTool(blockedRef), { source: "builtin", mountedBy: "always" });
|
|
80
86
|
}
|
|
81
87
|
if (!(spec.tools ?? []).some((t) => t.name === REPORT_FINDINGS_TOOL_NAME || t.aliases?.includes(REPORT_FINDINGS_TOOL_NAME))) {
|
|
82
|
-
|
|
88
|
+
roster.mount(createReportFindingsTool(), { source: "builtin", mountedBy: "always" });
|
|
83
89
|
}
|
|
84
90
|
if (spec.enablePlanMode === true && spec.interactiveTools !== false) {
|
|
85
91
|
const planReviewFace = resolveCheckpointStore(spec, deps) !== undefined;
|
|
86
92
|
if (spec.interactiveTools === true || planReviewFace) {
|
|
87
|
-
|
|
93
|
+
roster.mount(defineTool(createPresentPlanTool(requestReview)), { source: "builtin", mountedBy: "optional" });
|
|
88
94
|
if (planReviewFace) {
|
|
89
|
-
|
|
95
|
+
roster.mount(defineTool(createEnterPlanModeTool(enterPlanMode)), { source: "builtin", mountedBy: "optional" });
|
|
90
96
|
}
|
|
91
97
|
}
|
|
92
98
|
}
|
|
@@ -210,8 +216,7 @@ export async function prepareCapsAndWorkflow(input) {
|
|
|
210
216
|
workflowToolsActive = true;
|
|
211
217
|
const currentSizeGuideline = () => resolveWorkflowSizeGuideline(deps.workflowLimits?.sizeGuideline).size;
|
|
212
218
|
workflowSizeGuideline = { legGuideline: currentSizeGuideline(), current: currentSizeGuideline };
|
|
213
|
-
|
|
214
|
-
tools.push(await createRunWorkflowTool({
|
|
219
|
+
roster.mount(await createRunWorkflowTool({
|
|
215
220
|
runner: runnerSelf,
|
|
216
221
|
scriptRunner: deps.workflowScriptRunner,
|
|
217
222
|
governanceBaseline: deps.workflowGovernanceBaseline,
|
|
@@ -266,7 +271,7 @@ export async function prepareCapsAndWorkflow(input) {
|
|
|
266
271
|
parentCenterSourceRevision: () => input.centerAdoption()?.sourceRevision,
|
|
267
272
|
...(forwardEvent ? { forwardEvent } : {}),
|
|
268
273
|
inheritedGateForChildren,
|
|
269
|
-
}));
|
|
274
|
+
}), { source: "builtin", mountedBy: "workflow" });
|
|
270
275
|
}
|
|
271
|
-
return {
|
|
276
|
+
return { roster, blockedRef, runtimeCaps, runtimeCapsFaulted, complianceDenies, complianceDegraded, agentForkDenial, observersActive, autoModeArmReason, autoModeDecider, autoModeDenialTracking, autoModeArming, selfOrchestrationActive, workflowToolsActive, workflowSizeGuideline };
|
|
272
277
|
}
|
|
@@ -1,43 +1,22 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* design/390 M11 — prepareTask's TOOL-FACE FOLD + DEFERRED CLASSIFICATION phase: the exclusion valve's
|
|
3
|
-
* true unmount (in place, on the shared mount array), the full-shell anti-drift invariant, the classic-
|
|
4
|
-
* profile description swap, `classifyDeferredOverFace` (the one classifier both counterfactual passes
|
|
5
|
-
* run), the built-in memory pairs' support-name pre-check (sole-cause counterfactual, whole-group
|
|
6
|
-
* retraction, the engine pair's recall paragraph stripped back out of the memory block) and the final
|
|
7
|
-
* `deferred` set. The body is the driver's stretch moved verbatim (one exception, named below); the
|
|
8
|
-
* interface is the dependency list it had implicitly (design/238 R-1).
|
|
9
|
-
*
|
|
10
|
-
* SYNCHRONOUS FUNCTION, SYNCHRONOUS CALL: the stretch has no await, so the phase adds no yield between
|
|
11
|
-
* the git-status probe before it and the content-origin wrap after it (design/390 §1.5 S1: a stretch
|
|
12
|
-
* with no await is extracted as a sync function — an `async` wrapper would open a microtask window).
|
|
13
|
-
*
|
|
14
|
-
* The one non-move: the stretch used to write `sharedMemoryPairMounted = false` /
|
|
15
|
-
* `memoryEnginePairMounted = false` on the retraction arm. Nothing reads either flag after this stretch
|
|
16
|
-
* (the driver's next reader was this stretch's own pair derivation, which runs first), so the two dead
|
|
17
|
-
* writes are not carried into the Result — the flags arrive as borrowed-readonly inputs.
|
|
18
|
-
*
|
|
19
|
-
* Throws pass through unchanged: `internal.full_shell_reachable_mismatch` (an engine invariant, never a
|
|
20
|
-
* configuration error). The reserved-name refusal for a standing ToolSearch collision is NOT here — it
|
|
21
|
-
* belongs to the disclosure mount downstream, which reads the `deferred` set this phase returns.
|
|
22
|
-
*/
|
|
23
|
-
import type { AgentTool } from "../../internal/harness.js";
|
|
24
1
|
import type { Model } from "../../internal/llm.js";
|
|
25
2
|
import type { MaterializedA2a } from "../a2a.js";
|
|
26
3
|
import type { MaterializedMcp } from "../mcp.js";
|
|
27
4
|
import type { RunnerDeps, TaskSpec } from "../types.js";
|
|
28
5
|
import type { AnnounceOnceSink, ToolFaceSnapshot } from "./contracts.js";
|
|
6
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
29
7
|
export interface PrepareDeferClassifyInput {
|
|
30
8
|
/** borrowed-readonly — the REBOUND spec (`spec′`); only `tools` is read (the caller roster the
|
|
31
9
|
* classifier judges: names for the full-schema filter, specs for the `defer` declarations). */
|
|
32
|
-
spec: Pick<TaskSpec, "tools">;
|
|
10
|
+
spec: Pick<TaskSpec, "tools" | "excludeAllTools">;
|
|
33
11
|
/** borrowed-readonly — deployment deps; only `deferMode` is read (the classifier's mode knob). */
|
|
34
12
|
deps: Pick<RunnerDeps, "deferMode">;
|
|
35
13
|
/** borrowed-mutable — the shared mount array (later refs alias it; in-place contract, never
|
|
36
14
|
* re-created). Mutated here, in order: `splice` of every excluded name; element REPLACEMENT with a
|
|
37
15
|
* shallow copy for the classic-profile description swap (the caller's ToolSpec object is never
|
|
38
16
|
* mutated); `splice` of a retracted memory group. After this phase: the content-origin wrap
|
|
39
|
-
* (element replacement with the wrapped object), the disclosure mount, the MCP refresh re-splice.
|
|
40
|
-
|
|
17
|
+
* (element replacement with the wrapped object), the disclosure mount, the MCP refresh re-splice. Since
|
|
18
|
+
* design/388 every one of those writes is a builder verb (`unmountWhere` / `replaceAt`). */
|
|
19
|
+
roster: RosterBuilder;
|
|
41
20
|
/** borrowed-readonly — the frozen task-start tool face: `exclude` (the valve), `defer` (operator
|
|
42
21
|
* defers, exact wire names), `alwaysLoad` (the inline pins). */
|
|
43
22
|
toolFaceSnapshot: Pick<ToolFaceSnapshot, "exclude" | "defer" | "alwaysLoad">;
|
|
@@ -4,6 +4,7 @@ import { ASK_USER_QUESTION_TOOL_NAME } from "../ask-question.js";
|
|
|
4
4
|
import { MEMORY_ENGINE_TOOL_NAMES } from "../memory-engine/tools.js";
|
|
5
5
|
import { SHARED_MEMORY_TOOL_NAMES } from "../shared-memory/types.js";
|
|
6
6
|
import { TOOL_SEARCH_NAME, classifyDeferred } from "./tool-disclosure.js";
|
|
7
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
7
8
|
function explicitlyDeferredMemoryTrio(mounted, roster, deferNames) {
|
|
8
9
|
return mounted ? MEMORY_ENGINE_TOOL_NAMES.filter((n) => roster.some((t) => t.name === n) && (deferNames ?? []).includes(n)) : [];
|
|
9
10
|
}
|
|
@@ -11,13 +12,15 @@ function memoryGroupRetractionSet(builtinDeferPairNames, engineTrioInPlay) {
|
|
|
11
12
|
return new Set([...builtinDeferPairNames, ...(engineTrioInPlay ? MEMORY_ENGINE_TOOL_NAMES : [])]);
|
|
12
13
|
}
|
|
13
14
|
export function prepareDeferClassify(input) {
|
|
14
|
-
const { spec, deps,
|
|
15
|
+
const { spec, deps, roster, toolFaceSnapshot, handsEnabled, fullShellReachable, promptProfile, model, mcp, a2a, sharedMemoryPairMounted, memoryEnginePairMounted, memoryRecallSegment, onceLedger, sessionId } = input;
|
|
16
|
+
const tools = roster.tools;
|
|
15
17
|
let memoryBlock = input.memoryBlock;
|
|
16
|
-
if (
|
|
18
|
+
if (spec.excludeAllTools === true) {
|
|
19
|
+
roster.unmountWhere(() => true);
|
|
20
|
+
}
|
|
21
|
+
else if (toolFaceSnapshot.exclude !== undefined && toolFaceSnapshot.exclude.length > 0) {
|
|
17
22
|
const excluded = new Set(toolFaceSnapshot.exclude);
|
|
18
|
-
|
|
19
|
-
if (excluded.has(tools[i].name))
|
|
20
|
-
tools.splice(i, 1);
|
|
23
|
+
roster.unmountWhere((t) => excluded.has(t.name));
|
|
21
24
|
}
|
|
22
25
|
if (handsEnabled) {
|
|
23
26
|
const fullShellOnRoster = tools.some((t) => t.name === "Bash" && getToolContract(t, "core").contractId === FULL_SHELL_CONTRACT_ID);
|
|
@@ -33,7 +36,7 @@ export function prepareDeferClassify(input) {
|
|
|
33
36
|
for (let i = 0; i < tools.length; i++) {
|
|
34
37
|
const t = tools[i];
|
|
35
38
|
if (t.descriptionClassic !== undefined)
|
|
36
|
-
|
|
39
|
+
roster.replaceAt(i, { ...t, description: t.descriptionClassic });
|
|
37
40
|
}
|
|
38
41
|
}
|
|
39
42
|
const userToolNames = (spec.tools ?? []).map((t) => t.name);
|
|
@@ -73,10 +76,7 @@ export function prepareDeferClassify(input) {
|
|
|
73
76
|
const supportNameTaken = tools.some((t) => t.name === TOOL_SEARCH_NAME || (t.aliases ?? []).includes(TOOL_SEARCH_NAME));
|
|
74
77
|
if (soleCause && supportNameTaken) {
|
|
75
78
|
const retractNames = memoryGroupRetractionSet(builtinDeferPairNames, memoryEnginePair.length > 0);
|
|
76
|
-
|
|
77
|
-
if (retractNames.has(tools[i].name))
|
|
78
|
-
tools.splice(i, 1);
|
|
79
|
-
}
|
|
79
|
+
roster.unmountWhere((t) => retractNames.has(t.name));
|
|
80
80
|
if (sharedMemoryPair.length > 0) {
|
|
81
81
|
onceLedger.onError(new Error(`Shared memory tools ${SHARED_MEMORY_TOOL_NAMES.join("/")} were NOT mounted: mounting them would inject ` +
|
|
82
82
|
`the "${TOOL_SEARCH_NAME}" tool, whose name this task already declares — the pair mounts together or not at all.`), { phase: "config", sessionId, classification: "shared-memory-not-mounted" });
|
|
@@ -6,6 +6,7 @@ import type { CwdRef } from "../../tools/fs/index.js";
|
|
|
6
6
|
import { type ToolResultStore } from "../tool-result-store.js";
|
|
7
7
|
import type { RunnerDeps, TaskSpec, ToolEffect, ToolExecuteContext } from "../types.js";
|
|
8
8
|
import type { PrepareResume, RunInternals, RunnerSelfSeat, ToolFaceSnapshot } from "./contracts.js";
|
|
9
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
9
10
|
export interface PrepareDelegationSurfaceInput {
|
|
10
11
|
/** borrowed-readonly — the REBOUND spec. Read: `tools` (the shadow checks and the revival spawner's delegation-tool
|
|
11
12
|
* lookup), `oneShot` (the read/kill faces' completion promises), `retainBackgroundProcesses` (the Monitor receipt),
|
|
@@ -44,10 +45,10 @@ export interface PrepareDelegationSurfaceInput {
|
|
|
44
45
|
/** borrowed-mutable — the lane's late-bound facts; the SendMessage mount hands the SAME object to its peer seats (identity is
|
|
45
46
|
* the contract: the wiring station fills `askEffective` later). Not written here. */
|
|
46
47
|
peerLaneRefs: PeerLaneRefs;
|
|
47
|
-
/** borrowed-mutable — the run's
|
|
48
|
-
* eight mounts (TaskOutput, TaskStop, SendMessage, AgentTranscript, ListAgents, Monitor, the worktree
|
|
49
|
-
* reader), every one a
|
|
50
|
-
|
|
48
|
+
/** borrowed-mutable — the run's roster builder (`Prepared.tools` is its read face; the writer table is on that field).
|
|
49
|
+
* Writers here: the eight mounts (TaskOutput, TaskStop, SendMessage, AgentTranscript, ListAgents, Monitor, the worktree
|
|
50
|
+
* pair, the offload reader), every one a `mount`. */
|
|
51
|
+
roster: RosterBuilder;
|
|
51
52
|
/** borrowed-mutable — the effect collection (`Prepared.toolEffects`). Writers here: TaskOutput → read, TaskStop / SendMessage
|
|
52
53
|
* (built-in mount only) / Monitor / EnterWorktree / ExitWorktree → write. */
|
|
53
54
|
toolEffects: Map<string, ToolEffect>;
|
|
@@ -8,6 +8,7 @@ import { createTaskOutputTool, createTaskStopTool, defaultTaskRegistry } from ".
|
|
|
8
8
|
import { createReadToolResultTool } from "../tool-result-store.js";
|
|
9
9
|
import { emitTrace } from "../trace.js";
|
|
10
10
|
import { deliverEngineNotice } from "../types.js";
|
|
11
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
11
12
|
function buildTier3ReviveSpawn(delegationForRevive, enrichSpecToolCtx) {
|
|
12
13
|
if (delegationForRevive === undefined)
|
|
13
14
|
return undefined;
|
|
@@ -29,21 +30,21 @@ function buildTier3ReviveSpawn(delegationForRevive, enrichSpecToolCtx) {
|
|
|
29
30
|
};
|
|
30
31
|
}
|
|
31
32
|
export function prepareDelegationSurface(input) {
|
|
32
|
-
const { spec, deps, internals, resume, sessionId, hostTaskId, taskScope, taskRootFinal, executionEnv, runnerSelf, backgroundTaskToolsActive, workflowToolsActive, peerLaneActive, peerSendMessageBuiltIn, peerLaneRefs,
|
|
33
|
+
const { spec, deps, internals, resume, sessionId, hostTaskId, taskScope, taskRootFinal, executionEnv, runnerSelf, backgroundTaskToolsActive, workflowToolsActive, peerLaneActive, peerSendMessageBuiltIn, peerLaneRefs, roster, toolEffects, axisExplicitNegatives, envHandToolNames, toolFaceSnapshot, firstPartyOffload, offloadStore, subagentRetain, enrichSpecToolCtx, handsCwdRef, wsSnapshot, rebaseWsPath, rebaseRestoredPath, workspaceStateSettle } = input;
|
|
33
34
|
let worktreeSessionRef;
|
|
34
35
|
const delegationSurfaceActive = backgroundTaskToolsActive || workflowToolsActive;
|
|
35
36
|
if (delegationSurfaceActive || internals?.parentNotify !== undefined || peerLaneActive) {
|
|
36
37
|
if (delegationSurfaceActive) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
roster.mountAll([
|
|
39
|
+
firstPartyOffload(createTaskOutputTool({ registry: defaultTaskRegistry, owner: hostTaskId, scope: taskScope, sessionId, workflowStore: deps.workflowRunStore, agentStore: deps.backgroundAgentStore, notificationWired: internals?.onTaskNotification !== undefined, oneShot: spec.oneShot, toolResultStore: offloadStore })),
|
|
40
|
+
firstPartyOffload(createTaskStopTool({ registry: defaultTaskRegistry, owner: hostTaskId, scope: taskScope, sessionId, workflowStore: deps.workflowRunStore, agentStore: deps.backgroundAgentStore })),
|
|
41
|
+
], { source: "builtin", mountedBy: "delegation" });
|
|
40
42
|
}
|
|
41
43
|
if (runnerSelf && !(spec.tools ?? []).some((t) => t.name === SEND_MESSAGE_TOOL_NAME)) {
|
|
42
|
-
toolEffects.set(SEND_MESSAGE_TOOL_NAME, "write");
|
|
43
44
|
axisExplicitNegatives.set(SEND_MESSAGE_TOOL_NAME, { ...axisExplicitNegatives.get(SEND_MESSAGE_TOOL_NAME), egress: false });
|
|
44
45
|
const delegationForRevive = (spec.tools ?? []).find((t) => t.agentListing !== undefined);
|
|
45
46
|
const reviveSpawn = deps.backgroundAgentStore !== undefined && deps.mailboxStore !== undefined ? buildTier3ReviveSpawn(delegationForRevive, enrichSpecToolCtx) : undefined;
|
|
46
|
-
|
|
47
|
+
roster.mount(firstPartyOffload(createSendMessageTool({
|
|
47
48
|
runner: runnerSelf,
|
|
48
49
|
registry: defaultTaskRegistry,
|
|
49
50
|
...(subagentRetain ? { retain: subagentRetain } : {}),
|
|
@@ -76,9 +77,9 @@ export function prepareDelegationSurface(input) {
|
|
|
76
77
|
message: `delegation transcript integrity: agent ${handle}'s durable row binds a transcript session the session store attests is gone — the declared transcript durability is being contradicted (check the session store wiring/retention)`,
|
|
77
78
|
detail: { handle, ...(scope !== undefined ? { scope } : {}) },
|
|
78
79
|
}),
|
|
79
|
-
})));
|
|
80
|
+
})), { source: "builtin", mountedBy: delegationSurfaceActive ? "delegation" : internals?.parentNotify !== undefined ? "hostInternals" : "peerLane" });
|
|
80
81
|
if (delegationSurfaceActive && !(spec.tools ?? []).some((t) => t.name === AGENT_TRANSCRIPT_TOOL_NAME)) {
|
|
81
|
-
|
|
82
|
+
roster.mount(firstPartyOffload(createAgentTranscriptTool({
|
|
82
83
|
runner: runnerSelf,
|
|
83
84
|
registry: defaultTaskRegistry,
|
|
84
85
|
agentStore: deps.backgroundAgentStore,
|
|
@@ -91,17 +92,16 @@ export function prepareDelegationSurface(input) {
|
|
|
91
92
|
message: `delegation transcript integrity: agent ${handle}'s durable row binds a transcript session the session store attests is gone — the declared transcript durability is being contradicted (check the session store wiring/retention)`,
|
|
92
93
|
detail: { handle, ...(scope !== undefined ? { scope } : {}) },
|
|
93
94
|
}),
|
|
94
|
-
})));
|
|
95
|
+
})), { source: "builtin", mountedBy: "delegation" });
|
|
95
96
|
}
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
99
|
const listAgents = peerLaneActive && peerSendMessageBuiltIn && listAgentsMountable({ exclude: toolFaceSnapshot.exclude, specTools: spec.tools ?? [] }) ? mountListAgents({ peerDirectory: deps.peerDirectory, sessionId, scope: taskScope, hostTaskId, ...(internals?.parentTaskId !== undefined ? { parentTaskId: internals.parentTaskId } : {}), ...(internals?.parentSessionId !== undefined ? { parentSessionId: internals.parentSessionId } : {}), registry: defaultTaskRegistry, ...(deps.rosterStore !== undefined ? { roster: deps.rosterStore } : {}), specTools: spec.tools ?? [], toolEffects }) : undefined;
|
|
99
100
|
if (listAgents !== undefined)
|
|
100
|
-
|
|
101
|
+
roster.mount(firstPartyOffload(listAgents), { source: "builtin", mountedBy: "peerLane" });
|
|
101
102
|
if (backgroundTaskToolsActive) {
|
|
102
|
-
toolEffects.set("Monitor", "write");
|
|
103
103
|
envHandToolNames.add("Monitor");
|
|
104
|
-
|
|
104
|
+
roster.mount(firstPartyOffload(createMonitorTool(executionEnv, {
|
|
105
105
|
registry: defaultTaskRegistry,
|
|
106
106
|
owner: hostTaskId,
|
|
107
107
|
scope: taskScope,
|
|
@@ -110,11 +110,9 @@ export function prepareDelegationSurface(input) {
|
|
|
110
110
|
...(handsCwdRef !== undefined ? { cwdRef: handsCwdRef } : {}),
|
|
111
111
|
...(offloadStore !== undefined ? { toolResultStore: offloadStore } : {}),
|
|
112
112
|
...(spec.retainBackgroundProcesses === true ? { retainBackgroundProcesses: true } : {}),
|
|
113
|
-
})));
|
|
113
|
+
})), { source: "builtin", mountedBy: "backgroundTasks" });
|
|
114
114
|
}
|
|
115
115
|
if (handsCwdRef !== undefined) {
|
|
116
|
-
toolEffects.set("EnterWorktree", "write");
|
|
117
|
-
toolEffects.set("ExitWorktree", "write");
|
|
118
116
|
worktreeSessionRef = {
|
|
119
117
|
...(resume?.seed.activeWorktree
|
|
120
118
|
? {
|
|
@@ -136,9 +134,9 @@ export function prepareDelegationSurface(input) {
|
|
|
136
134
|
};
|
|
137
135
|
if (workspaceStateSettle !== undefined)
|
|
138
136
|
workspaceStateSettle.restoredWorktreeDir = worktreeSessionRef.current?.worktreeDir;
|
|
139
|
-
|
|
137
|
+
roster.mountAll(createWorktreeTools(executionEnv, { repoRoot: taskRootFinal, cwdRef: handsCwdRef, session: worktreeSessionRef }).map((t) => (envHandToolNames.add(t.name), firstPartyOffload(t))), { source: "builtin", mountedBy: "hands" });
|
|
140
138
|
}
|
|
141
139
|
if (offloadStore)
|
|
142
|
-
|
|
140
|
+
roster.mount(createReadToolResultTool(offloadStore), { source: "builtin", mountedBy: "optional" });
|
|
143
141
|
return { delegationSurfaceActive, worktreeSessionRef };
|
|
144
142
|
}
|