@sema-agent/core 7.6.3 → 7.8.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 +70 -10
- 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/peer-admission.d.ts +1 -1
- package/dist/agents/send-message-tool.js +2 -1
- package/dist/agents/subagent-steps.js +5 -4
- package/dist/agents/subagent.js +2 -3
- package/dist/brain/anthropic.js +8 -2
- package/dist/brain/open-responses.js +5 -3
- package/dist/brain/openai.js +31 -8
- package/dist/brain/reasoning.d.ts +32 -0
- package/dist/brain/reasoning.js +18 -0
- package/dist/core/ask-question.js +2 -2
- package/dist/core/auto-mode-defaults.d.ts +16 -0
- package/dist/core/auto-mode-defaults.js +1 -0
- package/dist/core/auto-mode.d.ts +19 -0
- package/dist/core/auto-mode.js +74 -56
- package/dist/core/checkpoint-execution-record.d.ts +110 -0
- package/dist/core/checkpoint-execution-record.js +49 -0
- package/dist/core/checkpoint-store.d.ts +114 -2
- package/dist/core/checkpoint-store.js +35 -2
- package/dist/core/context-edit.d.ts +0 -22
- package/dist/core/context-edit.js +2 -11
- package/dist/core/engine-notice.d.ts +17 -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 +4 -3
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +8 -0
- package/dist/core/hooks.d.ts +8 -2
- 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-rules.d.ts +32 -2
- package/dist/core/permission-rules.js +43 -37
- package/dist/core/present-plan-tool.js +3 -4
- package/dist/core/runner/active-skill-scope.js +7 -4
- package/dist/core/runner/clock-and-limits.d.ts +117 -0
- package/dist/core/runner/clock-and-limits.js +118 -0
- package/dist/core/runner/compaction-call-options.d.ts +1 -1
- package/dist/core/runner/contracts.d.ts +37 -3
- package/dist/core/runner/decide-continuation.d.ts +98 -0
- package/dist/core/runner/decide-continuation.js +133 -0
- package/dist/core/runner/execution-record.d.ts +26 -0
- package/dist/core/runner/execution-record.js +19 -0
- package/dist/core/runner/git-leg-delivery.d.ts +28 -0
- package/dist/core/runner/git-leg-delivery.js +94 -0
- package/dist/core/runner/initial-run-state.d.ts +14 -0
- package/dist/core/runner/initial-run-state.js +11 -0
- 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 +33 -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 +3 -1
- 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-safety-scan.js +42 -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/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 +0 -68
- package/dist/core/runner/runtask.js +66 -1486
- package/dist/core/runner/session-rule-policy.js +9 -4
- package/dist/core/runner/steer-admission.d.ts +17 -0
- package/dist/core/runner/steer-admission.js +17 -0
- 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 +71 -0
- package/dist/core/runner/tool-end-body.js +75 -0
- 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 +10 -0
- package/dist/core/runner/tool-output-projection.js +33 -10
- 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.d.ts +4 -0
- package/dist/core/store-contracts/checkpoint-store-contract.js +108 -0
- 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 +450 -0
- package/dist/core/tool-roster.js +497 -0
- package/dist/core/tool-spec.d.ts +54 -3
- package/dist/core/tools.js +7 -0
- package/dist/core/trace.d.ts +24 -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 +20 -8
- package/dist/index.js +19 -7
- 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.d.ts +7 -0
- package/dist/stores/file/checkpoint-store.js +20 -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-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/repo-map.js +2 -2
- package/dist/tools/fs/safety.d.ts +2 -1
- 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 +183 -7
|
@@ -53,7 +53,7 @@ export interface PrepareInheritedGateInput {
|
|
|
53
53
|
* / `oneShot` / `clientContext` / `principal` / `additionalDirectories` / `additionalReadDirectories` / `envFacts` /
|
|
54
54
|
* `memoryPersistenceCapable` / `getApiKeyAndHeaders` / `checkpointStore` / `backgroundScope` / `enablePlanMode` (the ctx
|
|
55
55
|
* enrichment's trusted seats). Never mutated. */
|
|
56
|
-
spec: Pick<TaskSpec, "shellGate" | "durableApproval" | "onAsk" | "onQuestion" | "handsReadOnly" | "interactiveTools" | "oneShot" | "clientContext" | "principal" | "additionalDirectories" | "additionalReadDirectories" | "envFacts" | "memoryPersistenceCapable" | "getApiKeyAndHeaders" | "checkpointStore" | "backgroundScope" | "enablePlanMode">;
|
|
56
|
+
spec: Pick<TaskSpec, "shellGate" | "durableApproval" | "onAsk" | "onQuestion" | "handsReadOnly" | "interactiveTools" | "oneShot" | "clientContext" | "principal" | "additionalDirectories" | "additionalReadDirectories" | "envFacts" | "memoryPersistenceCapable" | "getApiKeyAndHeaders" | "checkpointStore" | "backgroundScope" | "enablePlanMode" | "excludeAllTools">;
|
|
57
57
|
/** borrowed-readonly — the deployment seats: `autoMode.denialLimit` (the rebuilt trackers' bounds), `memoryScopeAdmission` /
|
|
58
58
|
* `deploymentMemoryScopes` / `compliancePostureResolver` (the governed-provenance bit), `onError` (the screening-face crash
|
|
59
59
|
* lane), `onNotice` (the stop seat's notice), `executionEnv` (the hook-env identity predicate), `delegationEntryCaps` (resolved
|
|
@@ -162,6 +162,7 @@ export function prepareInheritedGate(input) {
|
|
|
162
162
|
const fullShellReachable = handsEnabled &&
|
|
163
163
|
!(executionEnv instanceof StubExecutionEnv) &&
|
|
164
164
|
spec.handsReadOnly !== true &&
|
|
165
|
+
spec.excludeAllTools !== true &&
|
|
165
166
|
!(toolFaceSnapshot.exclude?.includes("Bash") ?? false);
|
|
166
167
|
const { gateStopRef, stopForDenialLimit } = createDenialLimitStop({ sessionId, runId, onNotice: deps.onNotice, abort: abortRun });
|
|
167
168
|
const delegationEntryCapsResolved = resolveDelegationEntryCaps(deps.delegationEntryCaps);
|
|
@@ -11,10 +11,11 @@
|
|
|
11
11
|
* with no await is extracted as a sync function — an `async` wrapper would open a microtask window).
|
|
12
12
|
* Read-stability of the host handles for the call: {@link RunInternals} (`@contract prepare.deps-read-stable`).
|
|
13
13
|
*/
|
|
14
|
-
import type {
|
|
14
|
+
import type { ExecutionEnv } from "../../internal/harness.js";
|
|
15
15
|
import type { LspDiagnosticsRegistry } from "../lsp-diagnostics.js";
|
|
16
16
|
import type { RunnerDeps, TaskSpec } from "../types.js";
|
|
17
17
|
import type { Prepared } from "./contracts.js";
|
|
18
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
18
19
|
export interface PrepareLspInput {
|
|
19
20
|
/** borrowed-readonly — the REBOUND spec. Read: `lspManager` (the per-task manager, outranks the deployment's),
|
|
20
21
|
* `lspDiagnostics` (the lane's opt-out), `handsReadOnly` (a read-only run has no lane). Never mutated. */
|
|
@@ -34,9 +35,9 @@ export interface PrepareLspInput {
|
|
|
34
35
|
/** borrowed-readonly — the tracked-cwd cell the hands band writes; the nudge READS `current` per call as its
|
|
35
36
|
* resolution base (identity is the contract — the band's `cd` handling writes this exact cell). */
|
|
36
37
|
handsCwdRef: Prepared["cwdRef"];
|
|
37
|
-
/** borrowed-mutable — the run's
|
|
38
|
+
/** borrowed-mutable — the run's roster builder (identity is the contract). Writer here: ONE mount (the LSP tool)
|
|
38
39
|
* when a manager exists. */
|
|
39
|
-
|
|
40
|
+
roster: RosterBuilder;
|
|
40
41
|
/** borrowed-mutable — the env-hand membership set the read-posture observer projects; writer here: `add("LSP")`
|
|
41
42
|
* on the mount. */
|
|
42
43
|
envHandToolNames: Set<string>;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { createLspTool, gitCheckIgnoreFilter, resolveLspPath } from "../lsp.js";
|
|
2
2
|
import { pathToUri } from "../lsp-protocol.js";
|
|
3
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
3
4
|
export function prepareLsp(input) {
|
|
4
|
-
const { spec, deps, executionEnv, taskRootFinal, handsEnabled, sessionId, handsCwdRef,
|
|
5
|
+
const { spec, deps, executionEnv, taskRootFinal, handsEnabled, sessionId, handsCwdRef, roster, envHandToolNames } = input;
|
|
5
6
|
const lspManager = spec.lspManager ?? deps.lspManager;
|
|
6
7
|
if (lspManager) {
|
|
7
8
|
const lspRoot = taskRootFinal;
|
|
8
|
-
|
|
9
|
+
roster.mount(createLspTool(lspManager, { isPathIgnored: gitCheckIgnoreFilter(executionEnv, lspRoot), env: executionEnv }), { source: "builtin", mountedBy: "optional" });
|
|
9
10
|
envHandToolNames.add("LSP");
|
|
10
11
|
}
|
|
11
12
|
const lspDiagnostics = spec.lspDiagnostics !== false && lspManager?.diagnostics !== undefined && handsEnabled && spec.handsReadOnly !== true
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
* One read changed spelling and nothing else: the declared-class announcement read `mcp?.statuses` while `mcp` had
|
|
17
17
|
* long been the protocol-tools phase's non-null handle; the optional chain was dead and is now the plain member read.
|
|
18
18
|
*/
|
|
19
|
-
import type { AgentTool } from "../../internal/harness.js";
|
|
20
19
|
import type { LockedPreflight } from "../locked-config.js";
|
|
21
20
|
import type { MaterializedMcp } from "../mcp.js";
|
|
22
21
|
import { type DelegationContentSafety } from "../memory-engine/delegation-provenance.js";
|
|
23
22
|
import type { RunnerDeps, TaskSpec } from "../types.js";
|
|
24
23
|
import type { Prepared, RunInternals } from "./contracts.js";
|
|
24
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
25
25
|
export interface PrepareMemoryEngineSessionInput {
|
|
26
26
|
/** borrowed-readonly — the mounted engine session, or undefined (the ARMING fact's first half). Read: `pollution`
|
|
27
27
|
* (the mark face), `contentSafety` (the own half of the narrowing), `settlement` (the seat + the receipt ledger),
|
|
@@ -64,10 +64,10 @@ export interface PrepareMemoryEngineSessionInput {
|
|
|
64
64
|
spec: Pick<TaskSpec, "tools">;
|
|
65
65
|
/** borrowed-readonly — the env-hand roster (membership minted at the mount sites); read by the classification. */
|
|
66
66
|
envHandToolNames: ReadonlySet<string>;
|
|
67
|
-
/** borrowed-mutable — the run's
|
|
68
|
-
* (`
|
|
67
|
+
/** borrowed-mutable — the run's roster builder. Writer here: the wrap pass REPLACES entries in place
|
|
68
|
+
* (`roster.replaceAt(i, wrapped)`, identity-tracked so a re-run never stacks wrappers); see the roster's writer table on
|
|
69
69
|
* {@link Prepared.tools}. */
|
|
70
|
-
|
|
70
|
+
roster: RosterBuilder;
|
|
71
71
|
/** borrowed-mutable — the re-runnable wrap pass's seat (the protocol-tools phase mints it; the rebuild seam re-runs it
|
|
72
72
|
* after a refresh re-splice). Writer: THIS phase installs the pass and runs it once. */
|
|
73
73
|
contentOriginWrapRef: {
|
|
@@ -5,8 +5,10 @@ import { protocolOf } from "../protocol-table.js";
|
|
|
5
5
|
import { deliverEngineNotice } from "../types.js";
|
|
6
6
|
import { inlineUntrusted } from "../untrusted-text.js";
|
|
7
7
|
import { fileArgPath } from "../../tools/fs/safety.js";
|
|
8
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
8
9
|
export function prepareMemoryEngineSession(input) {
|
|
9
|
-
const { memoryEngineSession, internals, memoryDelegationEvidence, externalContentTargetActive, lockedPreflight, mcp, sessionId, runId, deps, provenanceForChildrenRef, delegationSettlementRef, spec, envHandToolNames,
|
|
10
|
+
const { memoryEngineSession, internals, memoryDelegationEvidence, externalContentTargetActive, lockedPreflight, mcp, sessionId, runId, deps, provenanceForChildrenRef, delegationSettlementRef, spec, envHandToolNames, roster, contentOriginWrapRef } = input;
|
|
11
|
+
const tools = roster.tools;
|
|
10
12
|
const delegationProvenanceChannel = internals?.delegationProvenance;
|
|
11
13
|
if (memoryEngineSession !== undefined || delegationProvenanceChannel !== undefined) {
|
|
12
14
|
const pollution = memoryEngineSession?.pollution;
|
|
@@ -196,7 +198,7 @@ export function prepareMemoryEngineSession(input) {
|
|
|
196
198
|
},
|
|
197
199
|
};
|
|
198
200
|
contentOriginWrapped.add(wrapped);
|
|
199
|
-
|
|
201
|
+
roster.replaceAt(i, wrapped);
|
|
200
202
|
}
|
|
201
203
|
};
|
|
202
204
|
contentOriginWrapRef.current();
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { DEFAULT_TOOL_RESULT_THRESHOLD_CHARS,
|
|
1
|
+
import { DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, InMemoryToolResultStore, RunnerSharedToolResultStore, ScopedToolResultStore, withToolResultOffload, } from "../tool-result-store.js";
|
|
2
|
+
import { faceOf } from "../tool-roster.js";
|
|
3
|
+
const FIRST_PARTY_OFFLOAD_THRESHOLD_CHARS = 50_000;
|
|
2
4
|
export function prepareOffloadWrappers(input) {
|
|
3
5
|
const { spec, deps, resume, offloadScope, sessionId } = input;
|
|
4
6
|
const nestedStats = { tokens: 0, turns: 0, tasks: 0, costMicroUsd: 0, anyUnpriced: false };
|
|
@@ -31,10 +33,10 @@ export function prepareOffloadWrappers(input) {
|
|
|
31
33
|
return withToolResultOffload(tool, offloadStore, perTool?.offloadThresholdChars ?? offloadThreshold, sessionId, () => offloadReachableToolsRef.current?.());
|
|
32
34
|
};
|
|
33
35
|
const firstPartyOffload = (tool) => {
|
|
34
|
-
const
|
|
35
|
-
if (
|
|
36
|
-
return maybeOffload(tool,
|
|
37
|
-
return maybeOffload(tool, explicitGlobalThreshold === undefined ?
|
|
36
|
+
const face = faceOf(tool);
|
|
37
|
+
if (face.offload === false)
|
|
38
|
+
return maybeOffload(tool, { offload: false });
|
|
39
|
+
return maybeOffload(tool, explicitGlobalThreshold === undefined ? { offloadThresholdChars: face.offloadThresholdChars ?? FIRST_PARTY_OFFLOAD_THRESHOLD_CHARS } : undefined);
|
|
38
40
|
};
|
|
39
41
|
const remoteToolOffload = (tool) => {
|
|
40
42
|
if (explicitGlobalThreshold !== undefined)
|
|
@@ -30,6 +30,7 @@ import type { CwdRef } from "../../tools/fs/fs-shared.js";
|
|
|
30
30
|
import { type ContentAskBinding } from "./content-ask-bindings.js";
|
|
31
31
|
import type { AskLane, ParkAsk, Prepared, SuspendSaga } from "./contracts.js";
|
|
32
32
|
import type { createRuleOffersOf } from "./permission-rule-lanes.js";
|
|
33
|
+
import { type ToolRosterDeltaSeat } from "../tool-roster.js";
|
|
33
34
|
export interface PrepareParkAskInput {
|
|
34
35
|
/** borrowed-readonly — the in-stream ask lane, or undefined when the gate machinery is inactive (then both closures are
|
|
35
36
|
* absent). Read: `composedCallSignal` (the fence and the delivery race), `approvalPreviewOf` (the row's preview). */
|
|
@@ -49,6 +50,9 @@ export interface PrepareParkAskInput {
|
|
|
49
50
|
/** borrowed-readonly — the leg's checkpoint store, or undefined (then `suspendAsk` is absent — the park predicate's store
|
|
50
51
|
* term). Read: the declared fidelity; the saga writes to it. */
|
|
51
52
|
checkpointStore: CheckpointStore | undefined;
|
|
53
|
+
/** borrowed-readonly — the leg's delta seat (design/388 B18): the park reads the gated tool's identity off its
|
|
54
|
+
* CURRENT roster snapshot so the row carries who the action was minted against. */
|
|
55
|
+
toolRosterDeltas: ToolRosterDeltaSeat;
|
|
52
56
|
/** borrowed-readonly — the wiring-manifest phase's park predicate (`parkLane.effective`): arms `suspendAsk`. */
|
|
53
57
|
parkLaneArmed: boolean;
|
|
54
58
|
/** borrowed-readonly — the question-face phase's routability predicate (the mounted question tool is the engine's own,
|
|
@@ -14,6 +14,7 @@ import { checkpointScopeOf } from "./checkpoint-scope.js";
|
|
|
14
14
|
import { CONTENT_ASK_BINDING_CAP } from "./content-ask-bindings.js";
|
|
15
15
|
import { DEFAULT_UNATTENDED_APPROVAL_TTL_MS, publishCommittedSuspend, sanitizedTtlMs } from "./park-commit.js";
|
|
16
16
|
import { remoteEnvFailureNote } from "./remote-env-retry.js";
|
|
17
|
+
import { callFaceSeat, parkedToolIdentity, parkedToolFace } from "../tool-roster.js";
|
|
17
18
|
class ParkRefusal extends Error {
|
|
18
19
|
constructor(message, options) {
|
|
19
20
|
super(message, options);
|
|
@@ -21,7 +22,7 @@ class ParkRefusal extends Error {
|
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
export function prepareParkAsk(input) {
|
|
24
|
-
const { askLane, saga, spec, deps, sessionId, checkpointStore, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedBash, shellGatedMonitor, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, ruleOffersOf, now, humanReviewRef, abortController, harness, pausedRef } = input;
|
|
25
|
+
const { askLane, saga, spec, deps, sessionId, checkpointStore, toolRosterDeltas, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedBash, shellGatedMonitor, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, ruleOffersOf, now, humanReviewRef, abortController, harness, pausedRef } = input;
|
|
25
26
|
if (askLane === undefined || saga === undefined)
|
|
26
27
|
return { parkAsk: undefined };
|
|
27
28
|
const { composedCallSignal, approvalPreviewOf } = askLane;
|
|
@@ -157,6 +158,7 @@ export function prepareParkAsk(input) {
|
|
|
157
158
|
args: presented.value,
|
|
158
159
|
toolCallId: req.toolCallId,
|
|
159
160
|
budget: budgetSnapshot,
|
|
161
|
+
...callFaceSeat(req.face),
|
|
160
162
|
...(handsCwdRef !== undefined ? { cwd: handsCwdRef.current } : {}),
|
|
161
163
|
}, cutSignal)), cutSignal);
|
|
162
164
|
if (reprojectedRaced.tag === "aborted")
|
|
@@ -277,6 +279,7 @@ export function prepareParkAsk(input) {
|
|
|
277
279
|
kind: "tool_approval",
|
|
278
280
|
toolCallId: req.toolCallId,
|
|
279
281
|
toolName: req.toolName,
|
|
282
|
+
...parkedToolIdentity(toolRosterDeltas.current, req.toolName), ...parkedToolFace(toolRosterDeltas.current, req.toolName),
|
|
280
283
|
args: parkedArgs,
|
|
281
284
|
...(() => {
|
|
282
285
|
const p = approvalPreviewOf(req.toolName, parkedArgs);
|
|
@@ -1,27 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* design/390 M9 — prepareTask's PROJECT-CONTEXT phase: the deployment's project memory snapshot (the
|
|
3
|
-
* `loadProjectMemory` seam: phase derivation, instruction sources, the framed + fenced project layer
|
|
4
|
-
* appended to the memory block), the skills roster (declaration rank, normalization, the 1MB load gate,
|
|
5
|
-
* the manifest-scope door, the `skill` tool mount), the two built-in memory pairs' mount-or-yield
|
|
6
|
-
* (shared-memory pair, engine-memory pair), and the skills-listing projection the run loop announces.
|
|
7
|
-
* The body is the driver's stretch moved verbatim; the interface below is the dependency list it had
|
|
8
|
-
* implicitly (design/238 R-1: a new read is an Input field, i.e. a review event).
|
|
9
|
-
*
|
|
10
|
-
* ASYNC BY CONTENT: the stretch awaits the session branch read, the seam itself and the read-state
|
|
11
|
-
* seeding (all inside the `loadProjectMemory` arm). It already sits past prepareTask's first await, so
|
|
12
|
-
* the one extra microtask the driver's `await` adds on the seam-less path opens no window any caller
|
|
13
|
-
* could reach (design/390 §1.5 S1 synchronicity rule: only pre-first-await stretches must stay sync).
|
|
14
|
-
*
|
|
15
|
-
* Throws pass through unchanged: `config.reserved_tool_name` (a caller tool named like the skill tool
|
|
16
|
-
* while skills are present) is the only refusal here; the seam's own throw and the seeding's are
|
|
17
|
-
* caught and forwarded to `deps.onError` (best-effort, never block the task).
|
|
18
|
-
*/
|
|
19
|
-
import type { AgentTool } from "../../internal/harness.js";
|
|
20
1
|
import { type StoredSession } from "../session.js";
|
|
21
2
|
import type { RunnerDeps, TaskSpec, ToolSpec } from "../types.js";
|
|
22
3
|
import type { ActiveSkillScope } from "./active-skill-scope.js";
|
|
23
4
|
import type { AnnounceOnceSink, Prepared, PrepareResume, RunInternals, ToolFaceSnapshot } from "./contracts.js";
|
|
24
5
|
import { normalizeSkills } from "./synthetic-tools.js";
|
|
6
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
25
7
|
export interface PrepareProjectContextInput {
|
|
26
8
|
/** borrowed-readonly — the deployment seams this phase reads: `loadProjectMemory` (the snapshot),
|
|
27
9
|
* `onError` (the operator lane for a throwing seam / seeding / oversize skill), `sharedMemoryStores`
|
|
@@ -64,10 +46,10 @@ export interface PrepareProjectContextInput {
|
|
|
64
46
|
* and the `skill` tool alias this exact object). Mutated here: `push` of every inherited parent
|
|
65
47
|
* frame; after this phase only the `skill` tool's execute pushes/pops. */
|
|
66
48
|
skillScope: ActiveSkillScope;
|
|
67
|
-
/** borrowed-mutable — the
|
|
68
|
-
* here: `
|
|
69
|
-
* is judged on
|
|
70
|
-
|
|
49
|
+
/** borrowed-mutable — the run's roster builder (later refs alias its read face; in-place contract). Mutated
|
|
50
|
+
* here: `mount` of the `skill` tool, the shared-memory pair and the engine-memory pair. Occupancy
|
|
51
|
+
* is judged on the ALREADY-MOUNTED read face (names + aliases). */
|
|
52
|
+
roster: RosterBuilder;
|
|
71
53
|
/** borrowed-readonly — the frozen task-start tool face; only `exclude` is read (pair yield ①). */
|
|
72
54
|
toolFaceSnapshot: Pick<ToolFaceSnapshot, "exclude">;
|
|
73
55
|
/** borrowed-readonly — the once-per-session announcement ledger; only its deduplicated `onError`
|
|
@@ -6,8 +6,10 @@ import { createSharedMemoryTools } from "../shared-memory/tools.js";
|
|
|
6
6
|
import { SHARED_MEMORY_TOOL_NAMES } from "../shared-memory/types.js";
|
|
7
7
|
import { defineTool } from "../tools.js";
|
|
8
8
|
import { SKILL_CONTENT_MAX_CHARS, SKILL_TOOL_NAME, createSkillTool, normalizeSkills } from "./synthetic-tools.js";
|
|
9
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
9
10
|
export async function prepareProjectContext(input) {
|
|
10
|
-
const { deps, spec, internals, session, sessionId, hostTaskId, taskRootFinal, handsEnabled, delegation, seedContextFiles, memoryBlockFromEngine, skillScope,
|
|
11
|
+
const { deps, spec, internals, session, sessionId, hostTaskId, taskRootFinal, handsEnabled, delegation, seedContextFiles, memoryBlockFromEngine, skillScope, roster, toolFaceSnapshot, onceLedger, memoryTools, memoryEngineSession, memorySearchToolsPlanned, memoryPairExcludedName, memoryPairOccupiedName, resume } = input;
|
|
12
|
+
const tools = roster.tools;
|
|
11
13
|
let memoryBlock = memoryBlockFromEngine;
|
|
12
14
|
let instructionSources;
|
|
13
15
|
let projectInstructionContent;
|
|
@@ -88,7 +90,7 @@ export async function prepareProjectContext(input) {
|
|
|
88
90
|
e.code = "config.reserved_tool_name";
|
|
89
91
|
throw e;
|
|
90
92
|
}
|
|
91
|
-
|
|
93
|
+
roster.mount(createSkillTool(skillSpecs, skillScope), { source: "builtin", mountedBy: "optional" });
|
|
92
94
|
}
|
|
93
95
|
const sharedMemoryProvider = deps.sharedMemoryStores;
|
|
94
96
|
let sharedMemoryPairMounted = false;
|
|
@@ -110,16 +112,16 @@ export async function prepareProjectContext(input) {
|
|
|
110
112
|
" — the pair mounts together or not at all."), { phase: "config", sessionId, classification: "shared-memory-not-mounted" });
|
|
111
113
|
}
|
|
112
114
|
else {
|
|
113
|
-
|
|
115
|
+
roster.mountAll(createSharedMemoryTools({
|
|
114
116
|
provider: sharedMemoryProvider,
|
|
115
117
|
context: { sessionId, taskId: hostTaskId, ...(spec.principal !== undefined ? { principal: spec.principal } : {}) },
|
|
116
|
-
}).map((s) => defineTool(s)));
|
|
118
|
+
}).map((s) => defineTool(s)), { source: "builtin", mountedBy: "memory" });
|
|
117
119
|
sharedMemoryPairMounted = true;
|
|
118
120
|
}
|
|
119
121
|
}
|
|
120
122
|
let memoryEnginePairMounted = false;
|
|
121
123
|
if (memoryTools !== undefined && memoryTools.length > 0) {
|
|
122
|
-
|
|
124
|
+
roster.mountAll(memoryTools.map((s) => defineTool(s)), { source: "builtin", mountedBy: "memory" });
|
|
123
125
|
memoryEnginePairMounted = true;
|
|
124
126
|
}
|
|
125
127
|
else if (memoryEngineSession !== undefined && !memorySearchToolsPlanned) {
|
|
@@ -48,7 +48,7 @@ export interface PreparePromptAssemblyInput {
|
|
|
48
48
|
fableMitigations: boolean;
|
|
49
49
|
/** borrowed-readonly — the run's ONE tool roster, read only: the assembly receives DETACHED copies, the audit and the
|
|
50
50
|
* manifest read it in place. Never mutated here. */
|
|
51
|
-
tools: AgentTool[];
|
|
51
|
+
tools: readonly AgentTool[];
|
|
52
52
|
/** borrowed-readonly — the task model; only `promptGuidance` (the model-guidance section). */
|
|
53
53
|
model: Pick<Model, "promptGuidance">;
|
|
54
54
|
/** borrowed-readonly — the acquired session id (every operator line's attribution). */
|
|
@@ -4,6 +4,7 @@ import { type MaterializedA2a } from "../a2a.js";
|
|
|
4
4
|
import type { LockedPreflight } from "../locked-config.js";
|
|
5
5
|
import type { RunnerDeps, TaskSpec, ToolEffect } from "../types.js";
|
|
6
6
|
import type { AnnounceOnceSink, IrreversibilityTier, Prepared, RollbackStack, ToolFaceSnapshot } from "./contracts.js";
|
|
7
|
+
import { RosterBuilder, type ToolRosterDeltaSeat } from "../tool-roster.js";
|
|
7
8
|
export interface PrepareProtocolToolsInput {
|
|
8
9
|
/** borrowed-readonly — the frozen preflight; only `mcp` (the declared server entries) is read: the
|
|
9
10
|
* materialize input, the RefreshMcpTools mount predicate, and whether a real client was acquired. */
|
|
@@ -34,7 +35,10 @@ export interface PrepareProtocolToolsInput {
|
|
|
34
35
|
* Writers here: three pushes (the MCP tools through the wrapper, RefreshMcpTools, the A2A tools through the
|
|
35
36
|
* wrapper) and, at RUN time, the refresh closure's splice within a server's name-prefix domain. Later
|
|
36
37
|
* phases push their own mounts; the roster's full writer table is the delegation-surface phase's. */
|
|
37
|
-
|
|
38
|
+
roster: RosterBuilder;
|
|
39
|
+
/** borrowed-mutable — the run-time delta seat (design/388 §2.5): the refresh closure re-mints the roster through it after
|
|
40
|
+
* every re-splice so the stream learns of the change. Armed by the driver after the roster is minted. */
|
|
41
|
+
rosterSeat: ToolRosterDeltaSeat;
|
|
38
42
|
/** borrowed-readonly — the large-result wrapper for protocol tools (per-tool `_meta` bar, 50K default). */
|
|
39
43
|
remoteToolOffload: (tool: AgentTool) => AgentTool;
|
|
40
44
|
/** borrowed-readonly — the frozen tool face; `exclude` is read at REFRESH time so a deployment-excluded
|
|
@@ -2,8 +2,13 @@ import { Type } from "typebox";
|
|
|
2
2
|
import { materializeMcpTools } from "../mcp.js";
|
|
3
3
|
import { materializeA2aTools } from "../a2a.js";
|
|
4
4
|
import { deliverEngineNotice } from "../types.js";
|
|
5
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
6
|
+
import { REFRESH_MCP_TOOLS_TOOL_NAME, toolFace } from "../tool-catalog-entries.js";
|
|
7
|
+
import { MCP_NAMESPACE, A2A_NAMESPACE } from "../protocol-table.js";
|
|
8
|
+
import { mintNamespacePrefix } from "../protocol-naming.js";
|
|
9
|
+
import { applyMcpToolFaces } from "./tool-face-overlay.js";
|
|
5
10
|
export async function prepareProtocolTools(input) {
|
|
6
|
-
const { lockedPreflight, spec, deps, reminderMark, reminderDisclosureCounts, runId, sessionId, onceLedger,
|
|
11
|
+
const { lockedPreflight, spec, deps, reminderMark, reminderDisclosureCounts, runId, sessionId, onceLedger, roster, rosterSeat, remoteToolOffload, toolFaceSnapshot, toolEffects, axisExplicitNegatives, irreversibilityTier, irreversibleTools, egressTools, abortController, rollback } = input;
|
|
7
12
|
const mcp = lockedPreflight.mcp?.length
|
|
8
13
|
? await materializeMcpTools(lockedPreflight.mcp, spec.principal, deps.onElicit, deps.mcpImageResizer, { reminderMark, counts: reminderDisclosureCounts }, mcpRevocationWiring(deps, runId))
|
|
9
14
|
: { tools: [], toolAxes: [], warnings: [], serverInstructions: [], instructionsDelta: { pendingAdds: [], pendingRemovals: [] }, droppedTools: [], statuses: [], refresh: async () => [], dispose: async () => { } };
|
|
@@ -24,14 +29,35 @@ export async function prepareProtocolTools(input) {
|
|
|
24
29
|
throw e;
|
|
25
30
|
}
|
|
26
31
|
}
|
|
27
|
-
|
|
32
|
+
const faceAnnounced = new Set();
|
|
33
|
+
const withFaces = (tools, serverName) => {
|
|
34
|
+
const server = (lockedPreflight.mcp ?? []).find((s) => s.name === serverName);
|
|
35
|
+
return server === undefined ? [...tools] : applyMcpToolFaces({ tools, server, onNotice: deps.onNotice, announced: faceAnnounced, sessionId: sessionId ?? "", runId });
|
|
36
|
+
};
|
|
37
|
+
{
|
|
38
|
+
const servers = (lockedPreflight.mcp ?? []).map((s) => ({ name: s.name, prefix: mintNamespacePrefix(MCP_NAMESPACE, s.name) }));
|
|
39
|
+
const faced = new Map();
|
|
40
|
+
for (const server of servers) {
|
|
41
|
+
const own = mcp.tools.filter((x) => x.name.startsWith(server.prefix));
|
|
42
|
+
for (const t of withFaces(own, server.name))
|
|
43
|
+
faced.set(t.name, t);
|
|
44
|
+
}
|
|
45
|
+
for (const t of mcp.tools) {
|
|
46
|
+
const server = servers.find((s) => t.name.startsWith(s.prefix));
|
|
47
|
+
const mounted = server === undefined ? t : faced.get(t.name);
|
|
48
|
+
if (mounted === undefined)
|
|
49
|
+
continue;
|
|
50
|
+
roster.mount(remoteToolOffload(mounted), { source: "mcp", mountedBy: "optional", origin: { peer: server?.name ?? MCP_NAMESPACE.parse(t.name)?.peer ?? t.name } });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
28
53
|
const rebuildHarnessToolsRef = {};
|
|
29
54
|
const contentOriginWrapRef = {};
|
|
30
55
|
const toolCallGateArmedRef = { armed: false };
|
|
31
56
|
if (lockedPreflight.mcp?.length) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
57
|
+
roster.mount({
|
|
58
|
+
...toolFace("refresh-mcp-tools"),
|
|
59
|
+
name: REFRESH_MCP_TOOLS_TOOL_NAME,
|
|
60
|
+
label: REFRESH_MCP_TOOLS_TOOL_NAME,
|
|
35
61
|
description: "Refresh the tool list of connected MCP servers. Never dials or re-dials connections — it only re-reads the tool list over the existing connection. The refreshed tools are available immediately; you can call them on your next step. Use when a server's expected tool is missing, or the tool list looks stale after a connection recovered. Omit `server` to refresh every connected server.",
|
|
36
62
|
parameters: Type.Object({
|
|
37
63
|
server: Type.Optional(Type.String({ description: "Name of a single MCP server to refresh; omit to refresh all connected servers." })),
|
|
@@ -76,19 +102,8 @@ export async function prepareProtocolTools(input) {
|
|
|
76
102
|
anyActiveFailure = true;
|
|
77
103
|
continue;
|
|
78
104
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const t = tools[i];
|
|
82
|
-
if (t.name.startsWith(r.prefix)) {
|
|
83
|
-
domainAnchor = i;
|
|
84
|
-
tools.splice(i, 1);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
const refreshedMounts = pushable.map((t) => remoteToolOffload(t));
|
|
88
|
-
if (domainAnchor >= 0)
|
|
89
|
-
tools.splice(domainAnchor, 0, ...refreshedMounts);
|
|
90
|
-
else
|
|
91
|
-
tools.push(...refreshedMounts);
|
|
105
|
+
const refreshedMounts = withFaces(pushable, r.server).map((t) => remoteToolOffload(t));
|
|
106
|
+
roster.replaceDomain(r.prefix, refreshedMounts, { source: "mcp", mountedBy: "optional", origin: { peer: r.server } });
|
|
92
107
|
changed = true;
|
|
93
108
|
const detail = [];
|
|
94
109
|
const shownAdded = r.added.filter((n) => !excludedSet.has(n));
|
|
@@ -104,6 +119,8 @@ export async function prepareProtocolTools(input) {
|
|
|
104
119
|
}
|
|
105
120
|
if (changed)
|
|
106
121
|
await rebuildHarnessToolsRef.current?.();
|
|
122
|
+
if (changed)
|
|
123
|
+
rosterSeat.republish();
|
|
107
124
|
if (changed && !toolCallGateArmedRef.armed && (irreversibleTools.size > 0 || egressTools.size > 0)) {
|
|
108
125
|
lines.push("WARNING: refreshed tools declare irreversible/egress safety hints, but this task started with no approval gate registered (no policy/hooks and no gated tools at start) — these hints cannot arm a gate mid-task (RB-46); the refreshed tools run ungated on this deployment shape.");
|
|
109
126
|
}
|
|
@@ -115,8 +132,7 @@ export async function prepareProtocolTools(input) {
|
|
|
115
132
|
...(anyActiveFailure && !changed ? { isError: true } : {}),
|
|
116
133
|
};
|
|
117
134
|
},
|
|
118
|
-
});
|
|
119
|
-
toolEffects.set("RefreshMcpTools", "read");
|
|
135
|
+
}, { source: "builtin", mountedBy: "optional" });
|
|
120
136
|
}
|
|
121
137
|
const foldProtocolAxes = (axes, protocolLabel) => {
|
|
122
138
|
for (const axis of axes) {
|
|
@@ -160,7 +176,8 @@ export async function prepareProtocolTools(input) {
|
|
|
160
176
|
throw e;
|
|
161
177
|
}
|
|
162
178
|
}
|
|
163
|
-
|
|
179
|
+
for (const t of a2a.tools)
|
|
180
|
+
roster.mount(remoteToolOffload(t), { source: "a2a", mountedBy: "optional", origin: { peer: A2A_NAMESPACE.parse(t.name)?.peer ?? t.name } });
|
|
164
181
|
foldProtocolAxes(a2a.toolAxes, "A2A");
|
|
165
182
|
return { mcp, a2a, rebuildHarnessToolsRef, contentOriginWrapRef, toolCallGateArmedRef };
|
|
166
183
|
}
|
|
@@ -22,6 +22,7 @@ import { type CheckpointStore } from "../checkpoint-store.js";
|
|
|
22
22
|
import type { RunnerDeps, RuntimeCaps, TaskSpec } from "../types.js";
|
|
23
23
|
import type { PrepareResume } from "./contracts.js";
|
|
24
24
|
import { type ContentAskBinding } from "./content-ask-bindings.js";
|
|
25
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
25
26
|
export { CONTENT_ASK_BINDING_CAP, type ContentAskBinding } from "./content-ask-bindings.js";
|
|
26
27
|
export interface PrepareQuestionFaceInput {
|
|
27
28
|
/** borrowed-readonly — the run's frozen question seat (spec > deps), resolved once at the top of prepare;
|
|
@@ -45,10 +46,10 @@ export interface PrepareQuestionFaceInput {
|
|
|
45
46
|
resume: Pick<PrepareResume, "redeemedContentAskCallId" | "redeemedContentAskQuestionsHash"> | undefined;
|
|
46
47
|
/** borrowed-readonly — the acquired session id (the tool's source task id; operator-line context). */
|
|
47
48
|
sessionId: string;
|
|
48
|
-
/** borrowed-mutable — the run's
|
|
49
|
+
/** borrowed-mutable — the run's roster builder (identity is the contract). Writer here: ONE mount (the question
|
|
49
50
|
* tool) when the mount predicate holds; `contentAskRoutable` reads `includes` per call against the LIVE
|
|
50
|
-
*
|
|
51
|
-
|
|
51
|
+
* read face (the roster is edited in place after the mount). */
|
|
52
|
+
roster: RosterBuilder;
|
|
52
53
|
/** borrowed-readonly — LIVE GETTER over the inherited-unavailable marker set (declared by the driver's
|
|
53
54
|
* gate-fold section after this phase; `has` only, per call at run time). See the module header. */
|
|
54
55
|
inheritedUnavailableAsks: () => ReadonlySet<string>;
|
|
@@ -2,9 +2,11 @@ import { createAskUserQuestionTool, isLiveQuestionFace } from "../ask-question.j
|
|
|
2
2
|
import { boundInputHashOf } from "../canonical-json.js";
|
|
3
3
|
import { resolveCheckpointStore } from "../checkpoint-store.js";
|
|
4
4
|
import { CONTENT_ASK_BINDING_CAP } from "./content-ask-bindings.js";
|
|
5
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
5
6
|
export { CONTENT_ASK_BINDING_CAP } from "./content-ask-bindings.js";
|
|
6
7
|
export function prepareQuestionFace(input) {
|
|
7
|
-
const { frozenOnQuestion, spec, deps, runtimeCaps, resolvedInteractionPosture, resume, sessionId,
|
|
8
|
+
const { frozenOnQuestion, spec, deps, runtimeCaps, resolvedInteractionPosture, resume, sessionId, roster, inheritedUnavailableAsks } = input;
|
|
9
|
+
const tools = roster.tools;
|
|
8
10
|
const onQuestion = frozenOnQuestion;
|
|
9
11
|
const liveQuestionFace = isLiveQuestionFace(onQuestion) ? onQuestion : undefined;
|
|
10
12
|
const contentAskBindings = new Map();
|
|
@@ -60,7 +62,7 @@ export function prepareQuestionFace(input) {
|
|
|
60
62
|
const questionToolMounted = spec.interactiveTools === true || (spec.interactiveTools !== false && (onQuestion !== undefined || durableQuestionFace));
|
|
61
63
|
let mountedQuestionTool;
|
|
62
64
|
if (questionToolMounted)
|
|
63
|
-
|
|
65
|
+
roster.mount((mountedQuestionTool =
|
|
64
66
|
createAskUserQuestionTool(mountedQuestionFace, { principal: spec.principal, sourceTaskId: sessionId }, {
|
|
65
67
|
...(resume?.redeemedContentAskCallId !== undefined
|
|
66
68
|
? {
|
|
@@ -79,6 +81,6 @@ export function prepareQuestionFace(input) {
|
|
|
79
81
|
: "the wired question channel failed") +
|
|
80
82
|
`) — the model was instructed to self-answer and the run CONTINUES (warning, not a failure).`), { phase: "degraded", sessionId, classification: "no-human-autoanswered" });
|
|
81
83
|
},
|
|
82
|
-
})));
|
|
84
|
+
})), { source: "builtin", mountedBy: "optional" });
|
|
83
85
|
return { checkpointStore, liveQuestionFace, contentAskBindings, contentAskRoutable, lateStrandedAnswers, discloseStrandedAnswers, settleContentAskBindings, durableQuestionFace, mountedQuestionFace, questionToolMounted, mountedQuestionTool };
|
|
84
86
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { NAMESPACED_NAME_SHAPES } from "../protocol-table.js";
|
|
2
|
-
import {
|
|
2
|
+
import { handBandEffects } from "../tool-registry.js";
|
|
3
|
+
import { TOOL_CONTRACT_MAX_CHARS, TOOL_WIRE_NAME_MAX_CHARS } from "../tool-face.js";
|
|
4
|
+
import { schemaKeyBoundProblem } from "../tool-roster.js";
|
|
5
|
+
import { toolFaceProblem } from "./tool-face-overlay.js";
|
|
3
6
|
import { OFFLOAD_TOOL_NAME } from "../tool-result-store.js";
|
|
4
7
|
import { PRESENT_PLAN_TOOL_NAME, ENTER_PLAN_MODE_TOOL_NAME } from "../present-plan-tool.js";
|
|
5
8
|
export function prepareSafetyScan(input) {
|
|
@@ -13,6 +16,43 @@ export function prepareSafetyScan(input) {
|
|
|
13
16
|
const axisExplicitNegatives = new Map();
|
|
14
17
|
const reversibilityProbes = new Map();
|
|
15
18
|
for (const t of spec.tools ?? []) {
|
|
19
|
+
if (t.name.length > TOOL_WIRE_NAME_MAX_CHARS) {
|
|
20
|
+
const e = new Error(`Tool name "${t.name.slice(0, 40)}…" is invalid: ${t.name.length} characters, the roster's bound is ${TOOL_WIRE_NAME_MAX_CHARS}.`);
|
|
21
|
+
e.code = "config.tool_name_too_long";
|
|
22
|
+
throw e;
|
|
23
|
+
}
|
|
24
|
+
for (const alias of t.aliases ?? []) {
|
|
25
|
+
if (alias.length > TOOL_WIRE_NAME_MAX_CHARS) {
|
|
26
|
+
const e = new Error(`Tool alias "${alias.slice(0, 40)}…" (of "${t.name}") is invalid: ${alias.length} characters, the roster's bound is ${TOOL_WIRE_NAME_MAX_CHARS}.`);
|
|
27
|
+
e.code = "config.tool_name_too_long";
|
|
28
|
+
throw e;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (t.contract !== undefined && (t.contract.contractId.length > TOOL_CONTRACT_MAX_CHARS || t.contract.implementationRevision.length > TOOL_CONTRACT_MAX_CHARS)) {
|
|
32
|
+
const e = new Error(`Tool "${t.name}" declares a contract member over ${TOOL_CONTRACT_MAX_CHARS} characters (contractId ${t.contract.contractId.length}, implementationRevision ${t.contract.implementationRevision.length}) — the roster's bound.`);
|
|
33
|
+
e.code = "config.tool_contract_too_long";
|
|
34
|
+
throw e;
|
|
35
|
+
}
|
|
36
|
+
{
|
|
37
|
+
const keyProblem = schemaKeyBoundProblem(t.parameters);
|
|
38
|
+
if (keyProblem !== undefined) {
|
|
39
|
+
const e = new Error(`Tool "${t.name}" cannot ride a roster row: ${keyProblem}.`);
|
|
40
|
+
e.code = "config.tool_schema_bound";
|
|
41
|
+
throw e;
|
|
42
|
+
}
|
|
43
|
+
const declared = {
|
|
44
|
+
...(t.family !== undefined ? { family: t.family } : {}),
|
|
45
|
+
...(t.pathTarget !== undefined ? { pathTarget: t.pathTarget } : {}),
|
|
46
|
+
...(t.ruleFace !== undefined ? { ruleFace: t.ruleFace } : {}),
|
|
47
|
+
...(t.renderHints !== undefined ? { renderHints: t.renderHints } : {}),
|
|
48
|
+
};
|
|
49
|
+
const faceProblem = toolFaceProblem(declared, t.parameters);
|
|
50
|
+
if (faceProblem !== undefined) {
|
|
51
|
+
const e = new Error(`Tool "${t.name}" declares a face its schema cannot carry: ${faceProblem}.`);
|
|
52
|
+
e.code = "config.tool_face_invalid";
|
|
53
|
+
throw e;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
16
56
|
if (t.name.includes("__")) {
|
|
17
57
|
const e = new Error(`Tool name "${t.name}" is invalid: "__" is reserved for the engine's protocol tool namespaces (${NAMESPACED_NAME_SHAPES}) and must not appear in a caller tool name.`);
|
|
18
58
|
e.code = "config.tool_name_invalid";
|
|
@@ -65,7 +105,7 @@ export function prepareSafetyScan(input) {
|
|
|
65
105
|
}
|
|
66
106
|
toolEffects.set(OFFLOAD_TOOL_NAME, "read");
|
|
67
107
|
if (deps.executionEnvFactory || deps.executionEnv) {
|
|
68
|
-
for (const [name, effect] of
|
|
108
|
+
for (const [name, effect] of handBandEffects())
|
|
69
109
|
toolEffects.set(name, effect);
|
|
70
110
|
if (spec.handsReadOnly === true)
|
|
71
111
|
toolEffects.set("Bash", "read");
|