@sema-agent/core 7.5.1 → 7.6.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 +61 -0
- package/dist/agents/cascade.d.ts +2 -2
- package/dist/agents/cascade.js +12 -10
- package/dist/agents/repair-loop.d.ts +5 -3
- package/dist/agents/repair-loop.js +13 -15
- package/dist/agents/subagent.d.ts +24 -42
- package/dist/agents/subagent.js +119 -105
- package/dist/agents/suspend-guard.d.ts +31 -19
- package/dist/agents/suspend-guard.js +14 -8
- package/dist/agents/teacher.js +9 -9
- package/dist/agents/team.d.ts +4 -3
- package/dist/agents/team.js +10 -8
- package/dist/agents/verify.d.ts +3 -3
- package/dist/agents/verify.js +17 -17
- package/dist/core/a2a.js +2 -1
- package/dist/core/ask-origin.d.ts +60 -7
- package/dist/core/ask-origin.js +26 -1
- package/dist/core/checkpoint-store.d.ts +78 -76
- package/dist/core/checkpoint-store.js +17 -1
- package/dist/core/gate-outcome.d.ts +189 -0
- package/dist/core/gate-outcome.js +70 -0
- package/dist/core/hooks.d.ts +18 -92
- package/dist/core/hooks.js +88 -85
- package/dist/core/mcp-failure.d.ts +104 -0
- package/dist/core/mcp-failure.js +128 -0
- package/dist/core/mcp.d.ts +21 -77
- package/dist/core/mcp.js +76 -150
- package/dist/core/pause-registry.d.ts +131 -0
- package/dist/core/pause-registry.js +27 -0
- package/dist/core/protocol-table.d.ts +5 -0
- package/dist/core/protocol-table.js +1 -0
- package/dist/core/runner/abort-race.d.ts +41 -0
- package/dist/core/runner/abort-race.js +38 -0
- package/dist/core/runner/assemble-result.d.ts +32 -41
- package/dist/core/runner/assemble-result.js +55 -74
- package/dist/core/runner/checkpoint-scope.d.ts +15 -3
- package/dist/core/runner/checkpoint-scope.js +3 -0
- package/dist/core/runner/compaction-call-options.d.ts +1 -1
- package/dist/core/runner/content-ask-bindings.d.ts +27 -0
- package/dist/core/runner/content-ask-bindings.js +1 -0
- package/dist/core/runner/contracts.d.ts +144 -50
- package/dist/core/runner/denial-limit-arms.d.ts +24 -1
- package/dist/core/runner/denial-limit-arms.js +24 -3
- package/dist/core/runner/gate-exit.d.ts +74 -0
- package/dist/core/runner/gate-exit.js +55 -0
- package/dist/core/runner/inherited-ask-grants.d.ts +46 -0
- package/dist/core/runner/inherited-ask-grants.js +29 -0
- package/dist/core/runner/park-commit.d.ts +102 -0
- package/dist/core/runner/park-commit.js +31 -0
- package/dist/core/runner/{prepare-permission-rules.d.ts → permission-rule-lanes.d.ts} +109 -3
- package/dist/core/runner/{prepare-permission-rules.js → permission-rule-lanes.js} +47 -1
- package/dist/core/runner/prepare-ask-lane.d.ts +107 -0
- package/dist/core/runner/prepare-ask-lane.js +131 -0
- package/dist/core/runner/prepare-boundary-parks.d.ts +102 -0
- package/dist/core/runner/prepare-boundary-parks.js +169 -0
- package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
- package/dist/core/runner/prepare-context-lane.d.ts +119 -0
- package/dist/core/runner/prepare-context-lane.js +230 -0
- package/dist/core/runner/prepare-gate-stations.d.ts +174 -0
- package/dist/core/runner/prepare-gate-stations.js +265 -0
- package/dist/core/runner/prepare-hands-readface.d.ts +4 -4
- package/dist/core/runner/prepare-inherited-gate.d.ts +4 -4
- package/dist/core/runner/prepare-inherited-gate.js +1 -1
- package/dist/core/runner/prepare-memory-engine-session.d.ts +84 -0
- package/dist/core/runner/prepare-memory-engine-session.js +233 -0
- package/dist/core/runner/prepare-memory.d.ts +44 -26
- package/dist/core/runner/prepare-park-ask.d.ts +162 -0
- package/dist/core/runner/prepare-park-ask.js +377 -0
- package/dist/core/runner/prepare-policy-chain.d.ts +208 -0
- package/dist/core/runner/prepare-policy-chain.js +584 -0
- package/dist/core/runner/prepare-project-context.d.ts +1 -13
- package/dist/core/runner/prepare-project-context.js +1 -3
- package/dist/core/runner/prepare-prompt-assembly.d.ts +95 -0
- package/dist/core/runner/prepare-prompt-assembly.js +162 -0
- package/dist/core/runner/prepare-prompt-inputs.d.ts +1 -20
- package/dist/core/runner/prepare-protocol-tools.d.ts +3 -3
- package/dist/core/runner/prepare-protocol-tools.js +0 -3
- package/dist/core/runner/prepare-question-face.d.ts +3 -21
- package/dist/core/runner/prepare-question-face.js +2 -1
- package/dist/core/runner/prepare-safety-scan.d.ts +0 -5
- package/dist/core/runner/prepare-safety-scan.js +1 -2
- package/dist/core/runner/prepare-suspend-saga.d.ts +170 -0
- package/dist/core/runner/prepare-suspend-saga.js +308 -0
- package/dist/core/runner/prepare-task.d.ts +9 -136
- package/dist/core/runner/prepare-task.js +47 -2745
- package/dist/core/runner/prepare-turn-wiring.d.ts +154 -0
- package/dist/core/runner/prepare-turn-wiring.js +201 -0
- package/dist/core/runner/prepare-wiring-manifest.d.ts +17 -17
- package/dist/core/runner/prepare-wiring-manifest.js +16 -10
- package/dist/core/runner/prepare-workspace-restore.d.ts +2 -29
- package/dist/core/runner/prepare-workspace-restore.js +3 -16
- package/dist/core/runner/prompt-hash-salt.d.ts +1 -0
- package/dist/core/runner/prompt-hash-salt.js +2 -0
- package/dist/core/runner/remote-env-retry.d.ts +29 -0
- package/dist/core/runner/remote-env-retry.js +16 -0
- package/dist/core/runner/runtask.d.ts +16 -31
- package/dist/core/runner/runtask.js +110 -121
- package/dist/core/runner/terminal-projection.d.ts +22 -0
- package/dist/core/runner/terminal-projection.js +28 -0
- package/dist/core/session.d.ts +12 -0
- package/dist/core/session.js +3 -0
- package/dist/core/store-contracts/checkpoint-store-contract.d.ts +4 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +8 -2
- package/dist/core/terminal-cause.d.ts +137 -0
- package/dist/core/terminal-cause.js +9 -0
- package/dist/core/tool-policy.d.ts +43 -139
- package/dist/core/tool-policy.js +79 -112
- package/dist/core/types.d.ts +67 -164
- package/dist/core/wiring-manifest.d.ts +6 -3
- package/dist/core/workflow-journal-store.js +3 -4
- package/dist/engine/harness/agent-harness.d.ts +1 -1
- package/dist/index.d.ts +10 -7
- package/dist/index.js +8 -5
- package/dist/orchestration/builtin-workflows.d.ts +2 -2
- package/dist/orchestration/builtin-workflows.js +1 -1
- package/dist/orchestration/goal.js +8 -7
- package/dist/orchestration/run-spec.js +5 -3
- package/dist/orchestration/run-workflow-tool.d.ts +1 -1
- package/dist/orchestration/run-workflow-tool.js +4 -4
- package/dist/orchestration/workflow-governance.d.ts +4 -4
- package/dist/orchestration/workflow-governance.js +4 -2
- package/dist/orchestration/workflow-primitives.d.ts +1 -1
- package/dist/orchestration/workflow-primitives.js +1 -1
- package/dist/orchestration/workflow.d.ts +11 -0
- package/dist/orchestration/workflow.js +64 -39
- package/dist/prompts/supervisor.d.ts +1 -1
- package/dist/prompts/supervisor.js +3 -3
- package/dist/scenarios/scenario-registry.js +1 -1
- package/package.json +3 -1
- package/test/export-surface.snapshot.json +74 -22
- /package/dist/core/runner/{prepare-announce-once.d.ts → announce-once-ledger.d.ts} +0 -0
- /package/dist/core/runner/{prepare-announce-once.js → announce-once-ledger.js} +0 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import type { AgentHarness, AgentTool, ExecutionEnv, ThinkingLevel } from "../../internal/harness.js";
|
|
2
|
+
import type { Model } from "../../internal/llm.js";
|
|
3
|
+
import { type AssembledPrompt, type AssembleInputs } from "../../prompt-assembly/assemble.js";
|
|
4
|
+
import { type PromptEpochArtifact } from "../../prompt-assembly/artifact.js";
|
|
5
|
+
import type { EpochDeclaredSections } from "../../prompt-assembly/epoch.js";
|
|
6
|
+
import { type TurnPromptSnapshot } from "../../prompt-assembly/turn-snapshot.js";
|
|
7
|
+
import type { PromptTextDeclaration } from "../../prompts/default.js";
|
|
8
|
+
import { CacheBreakDetector, type ToolFingerprintInput } from "../cache-break-detector.js";
|
|
9
|
+
import { type ToolPolicy } from "../tool-policy.js";
|
|
10
|
+
import type { RunnerDeps, TaskSpec } from "../types.js";
|
|
11
|
+
import type { CwdRef } from "../../tools/fs/fs-shared.js";
|
|
12
|
+
import { type ReadFace } from "../../tools/fs/index.js";
|
|
13
|
+
import type { ReadDenyMatcher } from "../../tools/fs/read-deny.js";
|
|
14
|
+
import { type ReadFileState } from "../../tools/fs/safety.js";
|
|
15
|
+
import type { Prepared } from "./contracts.js";
|
|
16
|
+
export interface PrepareTurnWiringInput {
|
|
17
|
+
/** borrowed-readonly — the deployment seats: `cacheBreakDetection` (the detector knob), `onError` (the attachment-skip
|
|
18
|
+
* degraded line), `promptSource` (the center candidate's state and current artifact). Receiver preserved. */
|
|
19
|
+
deps: Pick<RunnerDeps, "cacheBreakDetection" | "onError" | "promptSource">;
|
|
20
|
+
/** borrowed-mutable — the LIVE system prompt (the prompt-assembly phase's accessor cell). Read: the fingerprint, the
|
|
21
|
+
* snapshot's stable text, the overhead term. Writer here: the center candidate's `apply` (the boundary swap). */
|
|
22
|
+
systemPromptSeat: {
|
|
23
|
+
current: string;
|
|
24
|
+
};
|
|
25
|
+
/** borrowed-readonly — the FINAL wire tool list (the fingerprint's and the snapshot's tool wire, the overhead sum). */
|
|
26
|
+
harnessTools: ReadonlyArray<AgentTool>;
|
|
27
|
+
/** borrowed-mutable — the fingerprint ref the tool-disclosure phase minted. Writers: THIS phase seeds `current`; the
|
|
28
|
+
* candidate's `apply` rewrites `current.systemPrompt`; the disclosure phase's rebuild seam refreshes `current.tools`. */
|
|
29
|
+
fpRef: {
|
|
30
|
+
current?: {
|
|
31
|
+
systemPrompt: string;
|
|
32
|
+
tools: ToolFingerprintInput[];
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/** borrowed-readonly — the task model: `provider` / `id` / `maxTokens` / `api` (the snapshot's identity elements). */
|
|
36
|
+
model: Pick<Model, "provider" | "id" | "maxTokens" | "api">;
|
|
37
|
+
/** borrowed-readonly — the resolved epoch's artifact digest (the snapshot's identity element). */
|
|
38
|
+
epochArtifactDigestForSnapshot: string;
|
|
39
|
+
/** borrowed-readonly — the resolved prompt profile (a snapshot element). */
|
|
40
|
+
promptProfile: "simple" | "classic";
|
|
41
|
+
/** borrowed-readonly — the fable mitigations switch (a snapshot element). */
|
|
42
|
+
fableMitigations: boolean;
|
|
43
|
+
/** borrowed-readonly — the assembled prompt's physical block face, or undefined (the snapshot's layout groups). */
|
|
44
|
+
systemBlocks: AssembledPrompt["systemBlocks"];
|
|
45
|
+
/** borrowed-readonly — the resolved thinking level, or undefined (a snapshot element). */
|
|
46
|
+
thinking: ThinkingLevel | undefined;
|
|
47
|
+
/** borrowed-readonly — the REBOUND spec; only `outputSchema` (presence) and `taskId` (the snapshot's identity). */
|
|
48
|
+
spec: Pick<TaskSpec, "outputSchema" | "taskId">;
|
|
49
|
+
/** borrowed-readonly — the acquired session id (the snapshot; the attachment-skip attribution). */
|
|
50
|
+
sessionId: string;
|
|
51
|
+
/** borrowed-mutable — the snapshot ref the tool-disclosure phase minted. Writers: THIS phase seeds `current`; the candidate's
|
|
52
|
+
* `apply` calls `refreshStableSystem`; the disclosure phase's rebuild seam calls `refreshTools`; the run loop assigns
|
|
53
|
+
* `current.onChange` (the snapshot-changed trace emitter) once Prepared is built. */
|
|
54
|
+
turnSnapshotRef: {
|
|
55
|
+
current?: TurnPromptSnapshot;
|
|
56
|
+
};
|
|
57
|
+
/** borrowed-mutable — the composition manifest (`Prepared.promptManifest`). Writer here: the identity/lowering BACKFILL
|
|
58
|
+
* (the snapshot needs the final wire list, which exists only now). */
|
|
59
|
+
promptManifest: Prepared["promptManifest"];
|
|
60
|
+
/** borrowed-readonly — the model's structural coefficient (the context lane's), the overhead term's coordinate. */
|
|
61
|
+
charsPerToken: number;
|
|
62
|
+
/** borrowed-readonly — whether an execution env is wired (every reader exists only then). */
|
|
63
|
+
handsEnabled: boolean;
|
|
64
|
+
/** borrowed-readonly — the run's resolved env (the readers read and stat through it). */
|
|
65
|
+
executionEnv: ExecutionEnv;
|
|
66
|
+
/** borrowed-readonly — the canonical attachment root, or undefined (the readers' containment fence). */
|
|
67
|
+
attachmentRootCanonical: string | undefined;
|
|
68
|
+
/** borrowed-readonly — the canonical extra write roots (the fence's root set). */
|
|
69
|
+
additionalRootsCanonical: ReadonlyArray<string>;
|
|
70
|
+
/** borrowed-readonly — the canonical extra read roots (the fence's root set). */
|
|
71
|
+
additionalReadRootsCanonical: ReadonlyArray<string>;
|
|
72
|
+
/** borrowed-readonly — the compiled read-deny judge, or undefined (the reader's withheld arm). */
|
|
73
|
+
readDenyMatcher: ReadDenyMatcher | undefined;
|
|
74
|
+
/** borrowed-readonly — the resolved read face, or undefined (the fence's ninth argument). */
|
|
75
|
+
resolvedReadFace: ReadFace | undefined;
|
|
76
|
+
/** borrowed-readonly — the tracked-cwd seat, read per call by the kept-tail normalizer (never written here). */
|
|
77
|
+
handsCwdRef: CwdRef | undefined;
|
|
78
|
+
/** borrowed-mutable — the live read-file state, or undefined. Writers here, at RUN time: `detectExternalChanges` evicts a
|
|
79
|
+
* not-found entry; `onCompactionApplied` applies a landed compaction to it. The hands phase mints it. */
|
|
80
|
+
readFileStateForCheckpoint: ReadFileState | undefined;
|
|
81
|
+
/** borrowed-readonly — the deny-narrowing fold, or undefined (the changed-files deny door's authority). */
|
|
82
|
+
denyNarrowingPolicy: ToolPolicy | undefined;
|
|
83
|
+
/** borrowed-readonly — the run's abort controller; only `signal` (the deny door's and the stat's signal). */
|
|
84
|
+
abortController: Pick<AbortController, "signal">;
|
|
85
|
+
/** borrowed-readonly — the per-task identity (the background listing's owner). */
|
|
86
|
+
hostTaskId: string;
|
|
87
|
+
/** borrowed-readonly — the registry scope the background listing reads under. */
|
|
88
|
+
taskScope: string;
|
|
89
|
+
/** borrowed-readonly — the prompt-assembly phase's re-invokable assemble-inputs builder (the candidate re-assembles). */
|
|
90
|
+
buildAssembleInputs: (centerDecls?: PromptTextDeclaration[]) => AssembleInputs;
|
|
91
|
+
/** borrowed-mutable — the LIVE center adoption (the prompt-assembly phase's accessor cell). Read: the candidate's arming and
|
|
92
|
+
* same-artifact test. Writer here: the candidate's `apply` (the boundary swap / the explicit-disable rollback). */
|
|
93
|
+
centerAdoptionRef: {
|
|
94
|
+
current: {
|
|
95
|
+
artifact: PromptEpochArtifact;
|
|
96
|
+
sourceRevision?: string;
|
|
97
|
+
} | undefined;
|
|
98
|
+
};
|
|
99
|
+
/** borrowed-readonly — the harness ref (the candidate's `apply` calls `setSystemPrompt` on the current harness). */
|
|
100
|
+
harnessRef: {
|
|
101
|
+
current?: AgentHarness;
|
|
102
|
+
};
|
|
103
|
+
/** borrowed-readonly — the provider-declared sections in the epoch shape (the candidate's declared-sections TYPE). */
|
|
104
|
+
epochDeclaredSections: EpochDeclaredSections;
|
|
105
|
+
/** borrowed-readonly — the ONE carrier-face expression both delegation mounts consume (the observation seat). */
|
|
106
|
+
carrierReadFace: () => ReadFace | undefined;
|
|
107
|
+
/** borrowed-readonly — the normalized deny additions (the observation seat copies them). */
|
|
108
|
+
readDenyAdditionsNormalized: ReadonlyArray<{
|
|
109
|
+
pattern: string;
|
|
110
|
+
caseSensitive: boolean;
|
|
111
|
+
}>;
|
|
112
|
+
/** borrowed-mutable — the holder of the built Prepared. Writer: the DRIVER fills `current` right after `buildPrepared()`;
|
|
113
|
+
* the candidate's `apply` then writes `current.epochDeclaredSections` and `current.promptOverheadTokens` at a boundary. */
|
|
114
|
+
preparedHolder: {
|
|
115
|
+
current?: Prepared;
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
export interface PrepareTurnWiringResult {
|
|
119
|
+
/** owned — the two-phase cache-break detector (`Prepared.cacheBreakDetector`), or undefined when the knob is off. */
|
|
120
|
+
cacheBreakDetector: CacheBreakDetector | undefined;
|
|
121
|
+
/** borrowed-mutable — the prefix fingerprint (`Prepared.cacheFingerprint`; the same object `fpRef.current` holds), or
|
|
122
|
+
* undefined. Writers after this phase: the candidate's `apply` (systemPrompt), the disclosure rebuild seam (tools). */
|
|
123
|
+
cacheFingerprint: {
|
|
124
|
+
systemPrompt: string;
|
|
125
|
+
tools: ToolFingerprintInput[];
|
|
126
|
+
} | undefined;
|
|
127
|
+
/** owned — the fixed prompt-overhead term in the compaction trigger's coordinate (`Prepared.promptOverheadTokens`). */
|
|
128
|
+
promptOverheadTokens: number;
|
|
129
|
+
/** owned — the fenced working-file reader, or undefined without hands (`Prepared.readTaskFile`). */
|
|
130
|
+
readTaskFile: Prepared["readTaskFile"];
|
|
131
|
+
/** owned — the kept-tail path normalizer, or undefined without hands. */
|
|
132
|
+
normalizeAttachmentPath: Prepared["normalizeAttachmentPath"];
|
|
133
|
+
/** owned — the Read tool's dedup-stub predicate, or undefined without hands. */
|
|
134
|
+
isDedupStubResult: Prepared["isDedupStubResult"];
|
|
135
|
+
/** owned — the most-recently-read files projection, or undefined without read state. */
|
|
136
|
+
recentlyReadFiles: Prepared["recentlyReadFiles"];
|
|
137
|
+
/** owned — the landed-compaction read-state hook, or undefined without read state. */
|
|
138
|
+
onCompactionApplied: Prepared["onCompactionApplied"];
|
|
139
|
+
/** owned — the boundary-time changed-files scan, or undefined without read state. */
|
|
140
|
+
detectExternalChanges: Prepared["detectExternalChanges"];
|
|
141
|
+
/** owned — the post-compact background-task listing (`Prepared.listBackgroundTasks`). */
|
|
142
|
+
listBackgroundTasks: Prepared["listBackgroundTasks"];
|
|
143
|
+
/** owned — the compaction-boundary center adoption candidate, or undefined (no source, or no adoption). */
|
|
144
|
+
centerCompactionCandidate: Prepared["centerCompactionCandidate"];
|
|
145
|
+
/** owned — the effective read face observed for the result seats (`Prepared.effectiveReadFace`), or undefined. */
|
|
146
|
+
effectiveReadFaceObserved: ReadFace | undefined;
|
|
147
|
+
/** owned — the effective read-deny patterns observed (fresh copies), or undefined when none. */
|
|
148
|
+
effectiveReadDenyObserved: Array<{
|
|
149
|
+
pattern: string;
|
|
150
|
+
caseSensitive: boolean;
|
|
151
|
+
}> | undefined;
|
|
152
|
+
}
|
|
153
|
+
/** The M22 phase body — prepareTask's turn-wiring stretch, verbatim (see the module header). */
|
|
154
|
+
export declare function prepareTurnWiring(input: PrepareTurnWiringInput): PrepareTurnWiringResult;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { assemblePrompt } from "../../prompt-assembly/assemble.js";
|
|
3
|
+
import { artifactDeclarations } from "../../prompt-assembly/artifact.js";
|
|
4
|
+
import { buildTurnPromptSnapshot } from "../../prompt-assembly/turn-snapshot.js";
|
|
5
|
+
import { CacheBreakDetector, toolsToFingerprintInputs } from "../cache-break-detector.js";
|
|
6
|
+
import { defaultTaskRegistry } from "../task-registry.js";
|
|
7
|
+
import { refuseOutOfContractDecision } from "../tool-policy.js";
|
|
8
|
+
import { decodeTextBytes } from "../../tools/fs/encoding.js";
|
|
9
|
+
import { applyCompactionToReadFileState, isReadDedupStubResult } from "../../tools/fs/index.js";
|
|
10
|
+
import { resolveKey } from "../../tools/fs/safety.js";
|
|
11
|
+
import { PROMPT_HASH_SALT } from "./prompt-hash-salt.js";
|
|
12
|
+
import { CHANGED_FILES_MTIME_EPS_MS } from "./turn-attachments.js";
|
|
13
|
+
export function prepareTurnWiring(input) {
|
|
14
|
+
const { deps, systemPromptSeat, harnessTools, fpRef, model, epochArtifactDigestForSnapshot, promptProfile, fableMitigations, systemBlocks, thinking, spec, sessionId, turnSnapshotRef, promptManifest, charsPerToken, handsEnabled, executionEnv, attachmentRootCanonical, additionalRootsCanonical, additionalReadRootsCanonical, readDenyMatcher, resolvedReadFace, handsCwdRef, readFileStateForCheckpoint, denyNarrowingPolicy, abortController, hostTaskId, taskScope, buildAssembleInputs, centerAdoptionRef, harnessRef, epochDeclaredSections, carrierReadFace, readDenyAdditionsNormalized, preparedHolder } = input;
|
|
15
|
+
const cacheBreakDetector = deps.cacheBreakDetection === false ? undefined : new CacheBreakDetector();
|
|
16
|
+
const cacheFingerprint = cacheBreakDetector
|
|
17
|
+
? { systemPrompt: systemPromptSeat.current, tools: toolsToFingerprintInputs(harnessTools) }
|
|
18
|
+
: undefined;
|
|
19
|
+
fpRef.current = cacheFingerprint;
|
|
20
|
+
const turnSnapshot = buildTurnPromptSnapshot({
|
|
21
|
+
provider: model.provider,
|
|
22
|
+
modelId: model.id,
|
|
23
|
+
artifactDigest: epochArtifactDigestForSnapshot,
|
|
24
|
+
promptProfile,
|
|
25
|
+
fableMitigations,
|
|
26
|
+
layoutGroups: (systemBlocks ?? [{ groupId: "body", cacheControlBoundary: true }]).map((b) => ({ groupId: b.groupId, cacheControlBoundary: b.cacheControlBoundary })),
|
|
27
|
+
stableSystemText: systemPromptSeat.current,
|
|
28
|
+
toolWire: toolsToFingerprintInputs(harnessTools),
|
|
29
|
+
thinkingLevel: (thinking ?? "off"),
|
|
30
|
+
maxTokens: model.maxTokens,
|
|
31
|
+
hasOutputSchema: spec.outputSchema !== undefined,
|
|
32
|
+
sessionId,
|
|
33
|
+
taskId: spec.taskId,
|
|
34
|
+
}, model.api, (text) => `salted:${createHash("sha256").update(PROMPT_HASH_SALT).update(text).digest("hex")}`);
|
|
35
|
+
turnSnapshotRef.current = turnSnapshot;
|
|
36
|
+
promptManifest.snapshot = { cacheIdentity: turnSnapshot.cacheIdentity, elements: { ...turnSnapshot.elements } };
|
|
37
|
+
promptManifest.lowering = turnSnapshot.lowering;
|
|
38
|
+
const promptOverheadTokens = Math.ceil((systemPromptSeat.current.length +
|
|
39
|
+
harnessTools.reduce((a, t) => a + t.name.length + (t.description?.length ?? 0) + JSON.stringify(t.parameters ?? {}).length, 0)) / charsPerToken);
|
|
40
|
+
const announceAttachmentSkip = (path, reason) => {
|
|
41
|
+
deps.onError?.(new Error(`working-file attachment skipped — ${path}: ${reason}`), {
|
|
42
|
+
phase: "degraded",
|
|
43
|
+
sessionId,
|
|
44
|
+
classification: "attachment-read",
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
const readTaskFile = handsEnabled
|
|
48
|
+
? async (path) => {
|
|
49
|
+
try {
|
|
50
|
+
let key = path;
|
|
51
|
+
if (attachmentRootCanonical !== undefined) {
|
|
52
|
+
const rk = await resolveKey(executionEnv, attachmentRootCanonical, path, undefined, undefined, [...additionalRootsCanonical, ...additionalReadRootsCanonical], undefined, readDenyMatcher, resolvedReadFace);
|
|
53
|
+
if (!rk.ok) {
|
|
54
|
+
announceAttachmentSkip(path, rk.violation.message);
|
|
55
|
+
if (rk.violation.code === "read_path_denied" && rk.violation.pattern !== undefined) {
|
|
56
|
+
return { withheld: { pattern: rk.violation.pattern } };
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
key = rk.key;
|
|
61
|
+
}
|
|
62
|
+
const r = await executionEnv.readBinaryFile(key);
|
|
63
|
+
if (!r.ok) {
|
|
64
|
+
announceAttachmentSkip(path, r.error.message);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const d = decodeTextBytes(r.value);
|
|
68
|
+
if (d.malformed) {
|
|
69
|
+
announceAttachmentSkip(path, "malformed text encoding (truncated UTF-16 body)");
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
return d.text;
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
announceAttachmentSkip(path, err instanceof Error ? err.message : String(err));
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
: undefined;
|
|
80
|
+
const normalizeAttachmentPath = handsEnabled
|
|
81
|
+
? async (path) => {
|
|
82
|
+
if (attachmentRootCanonical === undefined)
|
|
83
|
+
return path;
|
|
84
|
+
try {
|
|
85
|
+
const rk = await resolveKey(executionEnv, attachmentRootCanonical, path, undefined, handsCwdRef?.current, [...additionalRootsCanonical, ...additionalReadRootsCanonical], undefined, undefined, resolvedReadFace);
|
|
86
|
+
return rk.ok ? rk.key : path;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return path;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
: undefined;
|
|
93
|
+
const isDedupStubResult = handsEnabled ? isReadDedupStubResult : undefined;
|
|
94
|
+
const recentlyReadFiles = handsEnabled && readFileStateForCheckpoint
|
|
95
|
+
? () => [...readFileStateForCheckpoint.entries()]
|
|
96
|
+
.filter(([, v]) => v.seededFromContext !== true)
|
|
97
|
+
.sort((a, b) => (b[1].lastReadAt ?? 0) - (a[1].lastReadAt ?? 0))
|
|
98
|
+
.map(([path]) => path)
|
|
99
|
+
: undefined;
|
|
100
|
+
const onCompactionApplied = handsEnabled && readFileStateForCheckpoint
|
|
101
|
+
? (attachedComplete, preserveReadState) => applyCompactionToReadFileState(readFileStateForCheckpoint, attachedComplete, preserveReadState)
|
|
102
|
+
: undefined;
|
|
103
|
+
const changedFilesReadDenied = denyNarrowingPolicy === undefined
|
|
104
|
+
? undefined
|
|
105
|
+
: async (path) => {
|
|
106
|
+
try {
|
|
107
|
+
const d = refuseOutOfContractDecision(await denyNarrowingPolicy.check({ toolName: "Read", args: { file_path: path }, toolCallId: "changed-files-visibility-probe" }, abortController.signal));
|
|
108
|
+
return d.action === "deny";
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const detectExternalChanges = handsEnabled && readFileStateForCheckpoint
|
|
115
|
+
? async (maxFiles) => {
|
|
116
|
+
const candidates = [...readFileStateForCheckpoint.entries()]
|
|
117
|
+
.filter(([, e]) => e.lastReadAt !== undefined)
|
|
118
|
+
.filter(([, e]) => e.truncated !== true)
|
|
119
|
+
.sort((a, b) => (b[1].lastReadAt ?? 0) - (a[1].lastReadAt ?? 0))
|
|
120
|
+
.slice(0, Math.max(0, maxFiles));
|
|
121
|
+
const changed = [];
|
|
122
|
+
const evicted = [];
|
|
123
|
+
for (const [path, entry] of candidates) {
|
|
124
|
+
if (changedFilesReadDenied !== undefined && (await changedFilesReadDenied(path)))
|
|
125
|
+
continue;
|
|
126
|
+
try {
|
|
127
|
+
const info = await executionEnv.fileInfo(path, abortController.signal);
|
|
128
|
+
if (!info.ok) {
|
|
129
|
+
if (info.error.code === "not_found") {
|
|
130
|
+
readFileStateForCheckpoint.delete(path);
|
|
131
|
+
evicted.push(path);
|
|
132
|
+
}
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (info.value.mtimeMs > (entry.lastReadAt ?? 0) + CHANGED_FILES_MTIME_EPS_MS) {
|
|
136
|
+
changed.push({ path, mtimeMs: info.value.mtimeMs });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { changed, evicted };
|
|
143
|
+
}
|
|
144
|
+
: undefined;
|
|
145
|
+
const listBackgroundTasks = () => defaultTaskRegistry
|
|
146
|
+
.list({ owner: hostTaskId, scope: taskScope, sessionId })
|
|
147
|
+
.filter((t) => t.status === "pending" || t.status === "running" || t.status === "parked")
|
|
148
|
+
.map((t) => ({ id: t.task_id, ...(t.description !== undefined ? { description: t.description } : {}), status: t.status }));
|
|
149
|
+
const overheadState = { promptChars: 0 };
|
|
150
|
+
const centerCompactionCandidate = deps.promptSource !== undefined && centerAdoptionRef.current !== undefined
|
|
151
|
+
? () => {
|
|
152
|
+
const state = deps.promptSource.sourceState?.() ?? "unavailable";
|
|
153
|
+
const cand = deps.promptSource.current();
|
|
154
|
+
const toBundled = state === "disabled";
|
|
155
|
+
if (!toBundled && (cand === undefined || cand.artifact.artifactDigest === centerAdoptionRef.current.artifact.artifactDigest))
|
|
156
|
+
return undefined;
|
|
157
|
+
let a2;
|
|
158
|
+
try {
|
|
159
|
+
a2 = assemblePrompt(buildAssembleInputs(toBundled ? undefined : artifactDeclarations(cand.artifact)));
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
if (!toBundled && a2.centerMounted !== true)
|
|
165
|
+
return undefined;
|
|
166
|
+
const declared2 = (a2.sections ?? [])
|
|
167
|
+
.filter((sec) => sec.origin === "provider")
|
|
168
|
+
.map((sec) => ({ id: sec.id, slot: sec.slot, chars: sec.text.length, ...(sec.declaredContentHash !== undefined ? { contentHash: sec.declaredContentHash } : {}) }));
|
|
169
|
+
const overheadTokensAfter = preparedHolder.current.promptOverheadTokens -
|
|
170
|
+
Math.ceil(overheadState.promptChars / charsPerToken) +
|
|
171
|
+
Math.ceil(a2.systemPrompt.length / charsPerToken);
|
|
172
|
+
return {
|
|
173
|
+
...(toBundled
|
|
174
|
+
? { clear: true }
|
|
175
|
+
: {
|
|
176
|
+
centerArtifactDigest: cand.artifact.artifactDigest,
|
|
177
|
+
...(cand.sourceRevision !== undefined ? { sourceRevision: cand.sourceRevision } : {}),
|
|
178
|
+
}),
|
|
179
|
+
declaredSections: declared2,
|
|
180
|
+
overheadTokensAfter,
|
|
181
|
+
apply: (committedArtifactDigest) => {
|
|
182
|
+
systemPromptSeat.current = a2.systemPrompt;
|
|
183
|
+
harnessRef.current?.setSystemPrompt(a2.systemPrompt, a2.systemBlocks);
|
|
184
|
+
if (fpRef.current)
|
|
185
|
+
fpRef.current.systemPrompt = a2.systemPrompt;
|
|
186
|
+
turnSnapshotRef.current?.refreshStableSystem(a2.systemPrompt, committedArtifactDigest);
|
|
187
|
+
preparedHolder.current.epochDeclaredSections = declared2;
|
|
188
|
+
preparedHolder.current.promptOverheadTokens = overheadTokensAfter;
|
|
189
|
+
overheadState.promptChars = a2.systemPrompt.length;
|
|
190
|
+
centerAdoptionRef.current = toBundled
|
|
191
|
+
? undefined
|
|
192
|
+
: { artifact: cand.artifact, ...(cand.sourceRevision !== undefined ? { sourceRevision: cand.sourceRevision } : {}) };
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
: undefined;
|
|
197
|
+
overheadState.promptChars = systemPromptSeat.current.length;
|
|
198
|
+
const effectiveReadFaceObserved = carrierReadFace();
|
|
199
|
+
const effectiveReadDenyObserved = readDenyAdditionsNormalized.length > 0 ? readDenyAdditionsNormalized.map((e) => ({ ...e })) : undefined;
|
|
200
|
+
return { cacheBreakDetector, cacheFingerprint, promptOverheadTokens, readTaskFile, normalizeAttachmentPath, isDedupStubResult, recentlyReadFiles, onCompactionApplied, detectExternalChanges, listBackgroundTasks, centerCompactionCandidate, effectiveReadFaceObserved, effectiveReadDenyObserved };
|
|
201
|
+
}
|
|
@@ -25,7 +25,8 @@ import type { LockedPreflight } from "../locked-config.js";
|
|
|
25
25
|
import type { MaterializedMcp } from "../mcp.js";
|
|
26
26
|
import type { SessionStore } from "../session.js";
|
|
27
27
|
import { type ToolResultStore } from "../tool-result-store.js";
|
|
28
|
-
import { type
|
|
28
|
+
import { type OnAsk, type ToolPolicy } from "../tool-policy.js";
|
|
29
|
+
import type { GateOutcome } from "../gate-outcome.js";
|
|
29
30
|
import type { RunnerDeps, RuntimeCaps, TaskSpec, ToolEffect, ToolExecuteContext } from "../types.js";
|
|
30
31
|
import { type UsageWindow } from "../usage-window-store.js";
|
|
31
32
|
import { type AutoModeArmReason, type WiringManifest, type WiringManifestMcpEntry } from "../wiring-manifest.js";
|
|
@@ -33,8 +34,9 @@ import type { AnnounceOnceSink, Prepared, PrepareResume, RunInternals, UsageGove
|
|
|
33
34
|
export interface PrepareWiringManifestInput {
|
|
34
35
|
/** borrowed-readonly — the REBOUND spec. Read: `onAsk` (the own seat), `onQuestion` (the question seam), `handsReadOnly` / `tools` (the ungated scan),
|
|
35
36
|
* `resourceSuspend` (the task-axis lane), `durableApproval` / `principal` (the synthesis and the notice), `interactiveTools` /
|
|
36
|
-
* `mcp` / `checkpointStore` (manifest cells and the notice's cause)
|
|
37
|
-
|
|
37
|
+
* `mcp` / `checkpointStore` (manifest cells and the notice's cause), `enablePlanMode` (the gate-machinery predicate's
|
|
38
|
+
* plan-mode term). Never mutated. */
|
|
39
|
+
spec: Pick<TaskSpec, "onAsk" | "onQuestion" | "handsReadOnly" | "tools" | "resourceSuspend" | "durableApproval" | "principal" | "interactiveTools" | "mcp" | "checkpointStore" | "enablePlanMode">;
|
|
38
40
|
/** borrowed-readonly — the deployment seats, whole: `onAsk` (the seat's deps half), `onError` (the warning), `executionEnv`
|
|
39
41
|
* (the hook-env predicate), `checkpointStore` (durable infra), the manifest's dozen wiring facts (`backgroundAgentStore`,
|
|
40
42
|
* `permissionRuleStore`, `permissionRuleSyncWired`, `onBackgroundChildEvent`, `lockedConfig`, `compliancePostureResolver`,
|
|
@@ -61,6 +63,9 @@ export interface PrepareWiringManifestInput {
|
|
|
61
63
|
preToolUseObservational: boolean;
|
|
62
64
|
/** borrowed-readonly — the caller-facing policy layers; only their COUNT is read (an effect-aware gate exists). */
|
|
63
65
|
policyLayers: ReadonlyArray<unknown>;
|
|
66
|
+
/** borrowed-readonly — the policy chain's effective policy, or undefined; only its PRESENCE is read (the first term of the
|
|
67
|
+
* gate-machinery predicate below). Never called here. */
|
|
68
|
+
effectivePolicy: ToolPolicy | undefined;
|
|
64
69
|
/** borrowed-readonly — whether an execution env is wired (the hand band exists at all). */
|
|
65
70
|
handsEnabled: boolean;
|
|
66
71
|
/** borrowed-readonly — the materialized MCP handle: `tools` (the destructive-ungated scan) and `statuses` (the manifest face). */
|
|
@@ -109,9 +114,7 @@ export interface PrepareWiringManifestInput {
|
|
|
109
114
|
/** borrowed-readonly — the built harness the peer drain binds to. */
|
|
110
115
|
harness: AgentHarness;
|
|
111
116
|
/** borrowed-readonly — the durable-suspend holder; the drain's parked predicate reads `token` at run time. Not written here. */
|
|
112
|
-
|
|
113
|
-
/** borrowed-readonly — the review holder; same read. Not written here. */
|
|
114
|
-
reviewRef: Prepared["reviewRef"];
|
|
117
|
+
pausedRef: Prepared["pausedRef"];
|
|
115
118
|
/** borrowed-readonly — the FROZEN approver seat (the notice's liveApprover fact). */
|
|
116
119
|
frozenOnAsk: OnAsk | undefined;
|
|
117
120
|
/** borrowed-readonly — the LIVE half of the inherited chain (the notice reads its content mandates). */
|
|
@@ -130,16 +133,9 @@ export interface PrepareWiringManifestResult {
|
|
|
130
133
|
/** borrowed-mutable — the call ids the gate blocked or suspended (`Prepared.blockedToolCalls`). Writers: the gate; readers
|
|
131
134
|
* delete one-shot. */
|
|
132
135
|
blockedToolCalls: Set<string>;
|
|
133
|
-
/** borrowed-mutable — the
|
|
136
|
+
/** borrowed-mutable — the gate-outcome sideband (`Prepared.gateOutcomes`). Writer: the gate station; the frame mint reads and
|
|
134
137
|
* deletes. Nothing else may write it. */
|
|
135
|
-
|
|
136
|
-
settledBy?: ApprovalSettledBy;
|
|
137
|
-
approver?: string;
|
|
138
|
-
resolution?: import("../tool-policy.js").AskDenyResolution;
|
|
139
|
-
autoDenied?: true;
|
|
140
|
-
}>;
|
|
141
|
-
/** borrowed-mutable — the bare-human-rejection sideband. Writer: resolveAskBound; the gate handler consumes one-shot. */
|
|
142
|
-
humanBareRejections: Set<string>;
|
|
138
|
+
gateOutcomes: Map<string, GateOutcome>;
|
|
143
139
|
/** borrowed-mutable — the turn's halt fact (`Prepared.batchHaltRef`). Writer: the judgment site; cleared at the next request. */
|
|
144
140
|
batchHaltRef: Prepared["batchHaltRef"];
|
|
145
141
|
/** owned — whether any consumer of the blocked set is wired (populate only then). */
|
|
@@ -160,6 +156,10 @@ export interface PrepareWiringManifestResult {
|
|
|
160
156
|
wiringManifest: WiringManifest;
|
|
161
157
|
/** owned — THE park predicate as one named const (`parkLane.effective === true`). */
|
|
162
158
|
parkLaneArmed: boolean;
|
|
159
|
+
/** owned — THE gate-machinery activation predicate as one named const: a policy, a screening hook, an egress or
|
|
160
|
+
* irreversible tool, an eligible resource lane, an armed platform lane, or plan mode. The ask lane, the suspend saga,
|
|
161
|
+
* the boundary parks, the park closure and the gate station are built exactly when it holds. */
|
|
162
|
+
gateMachineryActive: boolean;
|
|
163
163
|
/** owned — THE identity mint of this leg (`Prepared.hookIdentity`), one frozen envelope every hook station reuses. */
|
|
164
164
|
hookIdentity: HookInvocationIdentity;
|
|
165
165
|
/** owned — the read-only env capability face every hook context carries, or undefined (no hook consumer, or no env wired). */
|
|
@@ -170,8 +170,8 @@ export interface PrepareWiringManifestResult {
|
|
|
170
170
|
* server the leg's FROZEN entry snapshot declared, in declaration order, joined by name to this leg's
|
|
171
171
|
* materialization statuses. Pure projection — no connection logic, no second look at any transport:
|
|
172
172
|
* · a status `connected` ⇒ `connected` with the mounted roster size (the intake's post-filter count);
|
|
173
|
-
* · a status `failed` ⇒ `failed` with the
|
|
174
|
-
* and the remote text SECRET-REDACTED (an HTTP endpoint's error body rides the SDK's message
|
|
173
|
+
* · a status `failed` ⇒ `failed` with the failure record the materialization stamped (`errorCode`/`delivered`/
|
|
174
|
+
* `httpStatus` = the MCP vocabulary's `McpFailure` spread flat) and the remote text SECRET-REDACTED (an HTTP endpoint's error body rides the SDK's message
|
|
175
175
|
* verbatim, and a body that echoes the bearer it rejected must not reach a stream consumer),
|
|
176
176
|
* then neutralized + bounded to the reminder's own 240 (the same bound the once-per-session
|
|
177
177
|
* ledger applies to that text — one face, one width);
|
|
@@ -22,7 +22,7 @@ export function mcpManifestEntries(entries, statuses) {
|
|
|
22
22
|
name: entry.name,
|
|
23
23
|
...source,
|
|
24
24
|
status: "failed",
|
|
25
|
-
...(status.errorCode !== undefined ? { errorCode: status.errorCode } : {}),
|
|
25
|
+
...(status.errorCode !== undefined ? { errorCode: status.errorCode, delivered: status.delivered, ...(status.httpStatus !== undefined ? { httpStatus: status.httpStatus } : {}) } : {}),
|
|
26
26
|
...(status.error !== undefined ? { error: inlineUntrusted(status.error, 240) } : {}),
|
|
27
27
|
toolCount: 0,
|
|
28
28
|
};
|
|
@@ -87,17 +87,17 @@ const ungatedWarnedShapes = new WeakMap();
|
|
|
87
87
|
function announceDurableGateUnavailable(args) {
|
|
88
88
|
if (!args.forceDurableGate || args.storeWired)
|
|
89
89
|
return;
|
|
90
|
-
const cause = args.
|
|
90
|
+
const cause = args.taskStoreDisabled ? "task_store_disabled" : "no_deployment_store";
|
|
91
91
|
const inheritedContentMandate = (args.parentConstraints ?? []).some((pc) => pc.contentMandate === true);
|
|
92
92
|
const liveQuestionFace = args.liveQuestionFace && !inheritedContentMandate;
|
|
93
93
|
deliverEngineNotice(args.onNotice, {
|
|
94
94
|
code: "config.durable_gate_unavailable",
|
|
95
95
|
message: `Durable approval gate mandated but unavailable: the runtime entitlement forceDurableGate is in force for this ` +
|
|
96
|
-
`principal, but ${cause === "
|
|
96
|
+
`principal, but ${cause === "task_store_disabled" ? 'this task disabled the checkpoint store (checkpointStore: "disabled")' : "this deployment wired no checkpoint store"}, ` +
|
|
97
97
|
`so no interactive ask of this task can be parked for a durable answer. Asks resolve on the live chain instead ` +
|
|
98
98
|
`(${args.liveApprover ? "a live approver answers permission asks in-stream" : "permission asks are denied fail-closed — no live approver is wired"}; ` +
|
|
99
99
|
`${liveQuestionFace ? "a live question face answers AskUserQuestion in-stream" : args.liveQuestionFace ? "AskUserQuestion is withheld from the live face by an inherited durable mandate and refused" : "AskUserQuestion has no live face and is refused"}) ` +
|
|
100
|
-
`and NO durable approval record is written. ${cause === "
|
|
100
|
+
`and NO durable approval record is written. ${cause === "task_store_disabled" ? "Run this task with its store, or withdraw the entitlement for principals whose runs are machine-started." : "Wire a checkpoint store on this deployment, or withdraw the entitlement for principals served here."}`,
|
|
101
101
|
detail: {
|
|
102
102
|
sessionId: args.sessionId,
|
|
103
103
|
runId: args.runId,
|
|
@@ -109,7 +109,7 @@ function announceDurableGateUnavailable(args) {
|
|
|
109
109
|
});
|
|
110
110
|
}
|
|
111
111
|
export function prepareWiringManifest(input) {
|
|
112
|
-
const { spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, handsEnabled, mcp, irreversibleTools, egressTools, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, lockedPreflight, peerLaneRefs, peerLaneActive, harness,
|
|
112
|
+
const { spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, mcp, irreversibleTools, egressTools, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, lockedPreflight, peerLaneRefs, peerLaneActive, harness, pausedRef, frozenOnAsk, liveInheritedGate, delegation } = input;
|
|
113
113
|
const onAsk = spec.onAsk ?? deps.onAsk;
|
|
114
114
|
const handWriteTools = handsEnabled && spec.handsReadOnly !== true
|
|
115
115
|
? Object.keys(HAND_TOOL_EFFECTS).filter((name) => {
|
|
@@ -144,8 +144,7 @@ export function prepareWiringManifest(input) {
|
|
|
144
144
|
}
|
|
145
145
|
const preToolContexts = new Map();
|
|
146
146
|
const blockedToolCalls = new Set();
|
|
147
|
-
const
|
|
148
|
-
const humanBareRejections = new Set();
|
|
147
|
+
const gateOutcomes = new Map();
|
|
149
148
|
const batchHaltRef = {};
|
|
150
149
|
const blockedTracked = Boolean(hooks?.postToolUse || hooks?.preToolUse || hooks?.postToolUseFailure || hooks?.postToolBatch);
|
|
151
150
|
const restoreSurfaceGap = ownedEnv !== undefined && isRemoteExecutionEnv(ownedEnv) && ownedEnv.capabilities.suspendable ? missingRestoreSurface(ownedEnv) : [];
|
|
@@ -220,11 +219,18 @@ export function prepareWiringManifest(input) {
|
|
|
220
219
|
ownTokens: () => internals?.peerSelfRef?.current.ownTokens ?? [],
|
|
221
220
|
refs: peerLaneRefs,
|
|
222
221
|
selfName: () => internals?.explicitAgentName,
|
|
223
|
-
parked: () =>
|
|
222
|
+
parked: () => pausedRef.current !== undefined,
|
|
224
223
|
});
|
|
225
224
|
}
|
|
226
225
|
const parkLaneArmed = wiringManifest.parkLane.effective === true;
|
|
227
|
-
|
|
226
|
+
const gateMachineryActive = effectivePolicy !== undefined ||
|
|
227
|
+
hooks?.preToolUse !== undefined ||
|
|
228
|
+
egressTools.size > 0 ||
|
|
229
|
+
irreversibleTools.size > 0 ||
|
|
230
|
+
resourceSuspendEligible ||
|
|
231
|
+
platformSuspendArmed ||
|
|
232
|
+
spec.enablePlanMode === true;
|
|
233
|
+
announceDurableGateUnavailable({ onNotice: deps.onNotice, forceDurableGate: runtimeCaps?.forceDurableGate === true, storeWired: checkpointStore !== undefined, taskStoreDisabled: spec.checkpointStore === "disabled", liveApprover: isLiveApproverSeat(frozenOnAsk), liveQuestionFace: liveQuestionFace !== undefined, parentConstraints: liveInheritedGate?.parentConstraints, sessionId, runId, principal: spec.principal });
|
|
228
234
|
const hookIdentity = mintHookInvocationIdentity({
|
|
229
235
|
sessionId,
|
|
230
236
|
taskId: hostTaskId,
|
|
@@ -236,5 +242,5 @@ export function prepareWiringManifest(input) {
|
|
|
236
242
|
});
|
|
237
243
|
const hookContextConsumerWired = hooks?.preToolUse !== undefined || hooks?.postToolUse !== undefined || hooks?.postToolUseFailure !== undefined;
|
|
238
244
|
const hookEnvFace = hookContextConsumerWired && (ownedEnv ?? deps.executionEnv) != null ? createHookEnvCapabilities(executionEnv) : undefined;
|
|
239
|
-
return { onAsk, preToolContexts, blockedToolCalls,
|
|
245
|
+
return { onAsk, preToolContexts, blockedToolCalls, gateOutcomes, batchHaltRef, blockedTracked, incompleteSuspendAdapter, durableSuspendInfraReady, resourceSuspendEligible, usageGovernance, platformSuspendArmed, durableApproval, wiringManifest, parkLaneArmed, gateMachineryActive, hookIdentity, hookEnvFace };
|
|
240
246
|
}
|
|
@@ -1,34 +1,7 @@
|
|
|
1
|
-
import type { RemoteExecutionEnv, RemoteExecutionError, SnapshotId, VmLifecycleOptions } from "../remote-env.js";
|
|
2
1
|
import type { ExecutionEnv } from "../../internal/harness.js";
|
|
3
|
-
import type {
|
|
2
|
+
import type { RunnerDeps, TaskSpec } from "../types.js";
|
|
4
3
|
import type { PrepareResume, RunInternals } from "./contracts.js";
|
|
5
|
-
|
|
6
|
-
* RB-439-a — project one failed remote lifecycle call onto the caller-facing note. ONE builder for all
|
|
7
|
-
* three ops so the `retryable` classification can never drift between the lane that reports a `suspendVM`
|
|
8
|
-
* refusal and the lane that reports a failed restore.
|
|
9
|
-
*/
|
|
10
|
-
export declare function remoteEnvFailureNote(op: RemoteEnvFailureNote["op"], error: RemoteExecutionError, attempts: number): RemoteEnvFailureNote;
|
|
11
|
-
/**
|
|
12
|
-
* RB-439-a — `resumeVM` with a bounded retry on the TRANSIENT codes, plus the attempt count for the
|
|
13
|
-
* caller-facing note.
|
|
14
|
-
*
|
|
15
|
-
* Why this op and no other: `resumeVM` is the one lifecycle call the seam documents as "idempotent +
|
|
16
|
-
* re-entrant" (a replica that crashed mid-suspend can be superseded by another resuming the SAME
|
|
17
|
-
* snapshot), which is exactly `withRetry`'s red line — retry idempotent establishment, never a
|
|
18
|
-
* side-effecting op. `suspendVM` TAKES a snapshot and `postResumeInit` re-injects secrets under an
|
|
19
|
-
* ordering red line; neither is retried here, they are disclosed with `retryable` instead so the caller
|
|
20
|
-
* decides. A code outside the retryable family (`unsupported`, `auth_failed`) returns on the first
|
|
21
|
-
* attempt — `withRetry` will not spend a second call on a permanent refusal.
|
|
22
|
-
*/
|
|
23
|
-
export declare function restoreWorkspaceWithRetry(env: RemoteExecutionEnv, snapshotId: SnapshotId, options: VmLifecycleOptions,
|
|
24
|
-
/** design/384 slice 2 (additive): observe each attempt AS IT STARTS. The returned `attempts` is
|
|
25
|
-
* only readable after settlement, and a caller whose wait on this promise is BOUNDED (the park
|
|
26
|
-
* compensation) must report the live attempt count when its bound fires mid-call — without this
|
|
27
|
-
* seat a deaf second attempt was reported as `attempts: 1`. */
|
|
28
|
-
onAttempt?: (attempt: number) => void): Promise<{
|
|
29
|
-
outcome: Awaited<ReturnType<RemoteExecutionEnv["resumeVM"]>>;
|
|
30
|
-
attempts: number;
|
|
31
|
-
}>;
|
|
4
|
+
export { remoteEnvFailureNote, restoreWorkspaceWithRetry } from "./remote-env-retry.js";
|
|
32
5
|
export interface PrepareWorkspaceRestoreInput {
|
|
33
6
|
/** borrowed-readonly (the ownership-ref PROTOCOL stays with the driver — D-8 案①): the env this
|
|
34
7
|
* task owns, when the factory minted one. This phase reads and drives it (`resumeVM`,
|
|
@@ -1,20 +1,7 @@
|
|
|
1
|
-
import { isRemoteExecutionEnv,
|
|
2
|
-
import {
|
|
1
|
+
import { isRemoteExecutionEnv, missingRestoreSurface } from "../remote-env.js";
|
|
2
|
+
import { remoteEnvFailureNote, restoreWorkspaceWithRetry } from "./remote-env-retry.js";
|
|
3
3
|
import { rebaseWorkspacePathAcross } from "./workspace-path.js";
|
|
4
|
-
export
|
|
5
|
-
return { op, code: error.code, retryable: isRetryableRemoteErrorCode(error.code), attempts, message: error.message };
|
|
6
|
-
}
|
|
7
|
-
const REMOTE_RESTORE_MAX_ATTEMPTS = 2;
|
|
8
|
-
const REMOTE_RESTORE_BACKOFF_MS = 200;
|
|
9
|
-
export async function restoreWorkspaceWithRetry(env, snapshotId, options, onAttempt) {
|
|
10
|
-
let attempts = 0;
|
|
11
|
-
const outcome = await withRetry(async (attempt) => {
|
|
12
|
-
attempts = attempt;
|
|
13
|
-
onAttempt?.(attempt);
|
|
14
|
-
return env.resumeVM(snapshotId, options);
|
|
15
|
-
}, { retryableCodes: RETRYABLE_REMOTE_ERROR_CODES, maxAttempts: REMOTE_RESTORE_MAX_ATTEMPTS, backoffMs: () => REMOTE_RESTORE_BACKOFF_MS }, { ...(options.abortSignal !== undefined ? { signal: options.abortSignal } : {}) });
|
|
16
|
-
return { outcome, attempts };
|
|
17
|
-
}
|
|
4
|
+
export { remoteEnvFailureNote, restoreWorkspaceWithRetry } from "./remote-env-retry.js";
|
|
18
5
|
export async function prepareWorkspaceRestore(input) {
|
|
19
6
|
const { ownedEnv, deps, spec, internals, resume, abortController, sessionId } = input;
|
|
20
7
|
let taskRootPath = input.taskRootInitial;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const PROMPT_HASH_SALT: Buffer<ArrayBufferLike>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { RemoteExecutionEnv, RemoteExecutionError, SnapshotId, VmLifecycleOptions } from "../remote-env.js";
|
|
2
|
+
import type { RemoteEnvFailureNote } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* RB-439-a — project one failed remote lifecycle call onto the caller-facing note. ONE builder for all
|
|
5
|
+
* three ops so the `retryable` classification can never drift between the lane that reports a `suspendVM`
|
|
6
|
+
* refusal and the lane that reports a failed restore.
|
|
7
|
+
*/
|
|
8
|
+
export declare function remoteEnvFailureNote(op: RemoteEnvFailureNote["op"], error: RemoteExecutionError, attempts: number): RemoteEnvFailureNote;
|
|
9
|
+
/**
|
|
10
|
+
* RB-439-a — `resumeVM` with a bounded retry on the TRANSIENT codes, plus the attempt count for the
|
|
11
|
+
* caller-facing note.
|
|
12
|
+
*
|
|
13
|
+
* Why this op and no other: `resumeVM` is the one lifecycle call the seam documents as "idempotent +
|
|
14
|
+
* re-entrant" (a replica that crashed mid-suspend can be superseded by another resuming the SAME
|
|
15
|
+
* snapshot), which is exactly `withRetry`'s red line — retry idempotent establishment, never a
|
|
16
|
+
* side-effecting op. `suspendVM` TAKES a snapshot and `postResumeInit` re-injects secrets under an
|
|
17
|
+
* ordering red line; neither is retried here, they are disclosed with `retryable` instead so the caller
|
|
18
|
+
* decides. A code outside the retryable family (`unsupported`, `auth_failed`) returns on the first
|
|
19
|
+
* attempt — `withRetry` will not spend a second call on a permanent refusal.
|
|
20
|
+
*/
|
|
21
|
+
export declare function restoreWorkspaceWithRetry(env: RemoteExecutionEnv, snapshotId: SnapshotId, options: VmLifecycleOptions,
|
|
22
|
+
/** design/384 slice 2 (additive): observe each attempt AS IT STARTS. The returned `attempts` is
|
|
23
|
+
* only readable after settlement, and a caller whose wait on this promise is BOUNDED (the park
|
|
24
|
+
* compensation) must report the live attempt count when its bound fires mid-call — without this
|
|
25
|
+
* seat a deaf second attempt was reported as `attempts: 1`. */
|
|
26
|
+
onAttempt?: (attempt: number) => void): Promise<{
|
|
27
|
+
outcome: Awaited<ReturnType<RemoteExecutionEnv["resumeVM"]>>;
|
|
28
|
+
attempts: number;
|
|
29
|
+
}>;
|