@sema-agent/core 5.40.0 → 5.42.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 +101 -3
- package/dist/core/auto-mode-prompt.js +1 -1
- package/dist/core/checkpoint-store.d.ts +15 -0
- package/dist/core/checkpoint-store.js +5 -1
- package/dist/core/memory-engine/file-backend.js +13 -2
- package/dist/core/memory-engine/layout.d.ts +15 -0
- package/dist/core/memory-engine/layout.js +17 -8
- package/dist/core/park-selfcheck.js +3 -1
- package/dist/core/runner/prepare-config-doors.js +20 -0
- package/dist/core/runner/prepare-hands-readface.d.ts +192 -0
- package/dist/core/runner/prepare-hands-readface.js +283 -0
- package/dist/core/runner/prepare-task.d.ts +1 -5
- package/dist/core/runner/prepare-task.js +16 -229
- package/dist/core/runner/runtask.js +6 -1
- package/dist/core/types.d.ts +20 -0
- package/dist/core/types.js +20 -0
- package/dist/engine/harness/agent-harness.d.ts +17 -0
- package/dist/engine/harness/agent-harness.js +19 -1
- package/dist/engine/harness/types.d.ts +5 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/tools/fs/fs-search-tools.d.ts +8 -0
- package/dist/tools/fs/fs-search-tools.js +67 -58
- package/dist/tools/fs/search.d.ts +31 -9
- package/dist/tools/fs/search.js +110 -73
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +2 -1
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { emitTrace } from "../trace.js";
|
|
2
|
+
import { StubExecutionEnv } from "../stub-env.js";
|
|
3
|
+
import { hasBackgroundShell } from "../background-shell.js";
|
|
4
|
+
import { defaultTaskRegistry } from "../task-registry.js";
|
|
5
|
+
import { bashReversibilityProbe, compileReadDeny, createHandsToolkit, deploymentReadFaceClampNotice, pdfModelCapabilitiesOf, resolveReadDenyBuiltins, resolveReadFace, seedReadFileStateFromContext, seedReadFileStateFromTranscript, } from "../../tools/fs/index.js";
|
|
6
|
+
import { resolveKey } from "../../tools/fs/safety.js";
|
|
7
|
+
import { wholeFileRecordsFromTranscript } from "./session-file-state-replay.js";
|
|
8
|
+
import { deliverEngineNotice } from "../types.js";
|
|
9
|
+
import { rebaseWorkspacePath } from "./prepare-workspace-restore.js";
|
|
10
|
+
const readFaceClampAnnouncedSinks = new WeakSet();
|
|
11
|
+
let readFaceClampConsoleAnnounced = false;
|
|
12
|
+
export function __resetReadFaceClampAnnouncement() {
|
|
13
|
+
readFaceClampConsoleAnnounced = false;
|
|
14
|
+
}
|
|
15
|
+
export function resolveHandsLessReadFace(input) {
|
|
16
|
+
const { resume, fullShellReachable, spec, deps } = input;
|
|
17
|
+
let handsLessResolvedFace;
|
|
18
|
+
let readDenyAdditionsNormalized = [];
|
|
19
|
+
{
|
|
20
|
+
const liveFace = resolveReadFace({
|
|
21
|
+
specReadFace: spec.readFace,
|
|
22
|
+
depsReadFace: deps.readFace,
|
|
23
|
+
readOnlyMount: spec.handsReadOnly === true,
|
|
24
|
+
orgGoverned: deps.permissionRuleOrg !== undefined,
|
|
25
|
+
fullShellReachable,
|
|
26
|
+
});
|
|
27
|
+
const seed = resume?.seed.readFace;
|
|
28
|
+
handsLessResolvedFace = resume !== undefined && (seed === undefined || seed.face === "roots") ? "roots" : liveFace;
|
|
29
|
+
const denyAdditions = [...(deps.readDenyPatterns ?? []), ...(spec.readDenyPatterns ?? []), ...(seed?.denyEntries ?? [])];
|
|
30
|
+
resolveReadDenyBuiltins({
|
|
31
|
+
...(deps.readDenyBuiltinTiers !== undefined ? { tiers: deps.readDenyBuiltinTiers } : {}),
|
|
32
|
+
...(deps.readDenyBuiltinExclude !== undefined ? { exclude: deps.readDenyBuiltinExclude } : {}),
|
|
33
|
+
});
|
|
34
|
+
if (denyAdditions.length > 0) {
|
|
35
|
+
readDenyAdditionsNormalized = compileReadDeny(denyAdditions, "readDenyPatterns", { tiers: [] }).entries;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
readFileStateForCheckpoint: undefined,
|
|
40
|
+
seedContextFiles: undefined,
|
|
41
|
+
handsCwdRef: undefined,
|
|
42
|
+
workspaceStateSettle: undefined,
|
|
43
|
+
wsSnapshot: undefined,
|
|
44
|
+
rebaseWsPath: (p) => p,
|
|
45
|
+
backgroundTaskToolsActive: false,
|
|
46
|
+
resolvedReadFace: undefined,
|
|
47
|
+
readDenyAdditionsNormalized,
|
|
48
|
+
handsLessResolvedFace,
|
|
49
|
+
additionalRootsCanonical: [],
|
|
50
|
+
additionalReadRootsCanonical: [],
|
|
51
|
+
attachmentRootCanonical: undefined,
|
|
52
|
+
readDenyMatcher: undefined,
|
|
53
|
+
shellGatedBash: false,
|
|
54
|
+
shellGatedMonitor: false,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export async function prepareHandsMount(input) {
|
|
58
|
+
const { handsEnabled, executionEnv, taskRootFinal, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals, memoryWriteGateRef, firstPartyOffload, tools, egressTools, irreversibilityTier, irreversibleTools, reversibilityProbes } = input;
|
|
59
|
+
let readFileStateForCheckpoint;
|
|
60
|
+
let seedContextFiles;
|
|
61
|
+
let handsCwdRef;
|
|
62
|
+
let workspaceStateSettle;
|
|
63
|
+
let wsSnapshot;
|
|
64
|
+
let rebaseWsPath = (p) => p;
|
|
65
|
+
let backgroundTaskToolsActive = false;
|
|
66
|
+
let resolvedReadFace;
|
|
67
|
+
let readDenyAdditionsNormalized = [];
|
|
68
|
+
let handsLessResolvedFace;
|
|
69
|
+
let shellGatedBash = false;
|
|
70
|
+
let shellGatedMonitor = false;
|
|
71
|
+
const additionalRootsCanonical = [];
|
|
72
|
+
const additionalReadRootsCanonical = [];
|
|
73
|
+
let attachmentRootCanonical;
|
|
74
|
+
let readDenyMatcher;
|
|
75
|
+
if (handsEnabled) {
|
|
76
|
+
const rootRaw = taskRootFinal;
|
|
77
|
+
const canon = await executionEnv.canonicalPath(rootRaw);
|
|
78
|
+
const rootCanonical = canon.ok ? canon.value : rootRaw;
|
|
79
|
+
attachmentRootCanonical = rootCanonical;
|
|
80
|
+
const canonicalizeExtraDirs = async (dirs, field, sink) => {
|
|
81
|
+
for (const dir of dirs ?? []) {
|
|
82
|
+
if (!dir || !dir.trim())
|
|
83
|
+
continue;
|
|
84
|
+
const c = await executionEnv.canonicalPath(dir);
|
|
85
|
+
if (c.ok) {
|
|
86
|
+
sink.push(c.value);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
deps.onError?.(new Error(`${field} entry skipped (cannot canonicalize): ${dir}`), {
|
|
90
|
+
phase: "config",
|
|
91
|
+
sessionId,
|
|
92
|
+
});
|
|
93
|
+
emitTrace(deps.tracer, () => ({
|
|
94
|
+
kind: "config.additional_directory_skipped",
|
|
95
|
+
version: 1,
|
|
96
|
+
taskId: hostTaskId,
|
|
97
|
+
entry: dir,
|
|
98
|
+
...(field !== "additionalDirectories" ? { field } : {}),
|
|
99
|
+
reason: `${c.error.code}: ${c.error.message}`,
|
|
100
|
+
ts: Date.now(),
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
await canonicalizeExtraDirs(spec.additionalDirectories, "additionalDirectories", additionalRootsCanonical);
|
|
106
|
+
await canonicalizeExtraDirs(spec.additionalReadDirectories, "additionalReadDirectories", additionalReadRootsCanonical);
|
|
107
|
+
if (spec.envFacts?.scratchpadDir) {
|
|
108
|
+
let c = await executionEnv.canonicalPath(spec.envFacts.scratchpadDir);
|
|
109
|
+
if (!c.ok && c.error.code === "not_found") {
|
|
110
|
+
const marker = await executionEnv.joinPath([spec.envFacts.scratchpadDir, ".sema-scratchpad"]);
|
|
111
|
+
const exclusiveCreate = executionEnv.writeFileExclusive?.bind(executionEnv);
|
|
112
|
+
if (marker.ok && exclusiveCreate) {
|
|
113
|
+
const w = await exclusiveCreate(marker.value, "");
|
|
114
|
+
if (w.ok || w.error.code === "already_exists")
|
|
115
|
+
c = await executionEnv.canonicalPath(spec.envFacts.scratchpadDir);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (c.ok)
|
|
119
|
+
additionalRootsCanonical.push(c.value);
|
|
120
|
+
}
|
|
121
|
+
for (const a of [additionalRootsCanonical, additionalReadRootsCanonical])
|
|
122
|
+
a.splice(0, a.length, ...new Set(a));
|
|
123
|
+
const readFileState = new Map((resume?.seed.readFileState ?? []).map(([k, v]) => [rebaseRestoredPath(k), v]));
|
|
124
|
+
readFileStateForCheckpoint = readFileState;
|
|
125
|
+
seedContextFiles = async (files) => {
|
|
126
|
+
for (const f of files) {
|
|
127
|
+
const rk = await resolveKey(executionEnv, rootCanonical, f.path, undefined, undefined, [...additionalRootsCanonical, ...additionalReadRootsCanonical], undefined, undefined, resolvedReadFace);
|
|
128
|
+
if (rk.ok)
|
|
129
|
+
seedReadFileStateFromContext(readFileState, rk.key, f.content);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
const handsIncludeShell = !(executionEnv instanceof StubExecutionEnv);
|
|
133
|
+
const handsReadOnly = spec.handsReadOnly === true;
|
|
134
|
+
backgroundTaskToolsActive = handsIncludeShell && !handsReadOnly && hasBackgroundShell(executionEnv);
|
|
135
|
+
wsSnapshot = resume !== undefined || !(handsIncludeShell && !handsReadOnly) ? undefined : await session.getWorkspaceState().catch(() => undefined);
|
|
136
|
+
rebaseWsPath = (p) => (wsSnapshot === undefined || wsSnapshot.taskRoot === rootCanonical ? p : rebaseWorkspacePath(p, wsSnapshot.taskRoot, rootCanonical));
|
|
137
|
+
if (handsIncludeShell && !handsReadOnly) {
|
|
138
|
+
handsCwdRef = { current: rootCanonical };
|
|
139
|
+
if (resume?.seed.handsCwd !== undefined)
|
|
140
|
+
handsCwdRef.current = rebaseRestoredPath(resume.seed.handsCwd);
|
|
141
|
+
else if (wsSnapshot?.handsCwd !== undefined)
|
|
142
|
+
handsCwdRef.current = rebaseWsPath(wsSnapshot.handsCwd);
|
|
143
|
+
workspaceStateSettle = {
|
|
144
|
+
rootCanonical,
|
|
145
|
+
restoredHandsCwd: handsCwdRef.current !== rootCanonical ? handsCwdRef.current : undefined,
|
|
146
|
+
...(resume !== undefined ? { baselineUnknown: true } : {}),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const seedReadFaceSection = resume?.seed.readFace;
|
|
150
|
+
const readDenyAdditions = [...(deps.readDenyPatterns ?? []), ...(spec.readDenyPatterns ?? []), ...(seedReadFaceSection?.denyEntries ?? [])];
|
|
151
|
+
const readDenyBuiltinCfg = {
|
|
152
|
+
...(deps.readDenyBuiltinTiers !== undefined ? { tiers: [...deps.readDenyBuiltinTiers] } : {}),
|
|
153
|
+
...(deps.readDenyBuiltinExclude !== undefined ? { exclude: [...deps.readDenyBuiltinExclude] } : {}),
|
|
154
|
+
};
|
|
155
|
+
readDenyMatcher = compileReadDeny(readDenyAdditions, "readDenyPatterns", readDenyBuiltinCfg);
|
|
156
|
+
readDenyAdditionsNormalized = compileReadDeny(readDenyAdditions, "readDenyPatterns", { tiers: [] }).entries;
|
|
157
|
+
let liveReadFace = resolveReadFace({
|
|
158
|
+
specReadFace: spec.readFace,
|
|
159
|
+
depsReadFace: deps.readFace,
|
|
160
|
+
readOnlyMount: handsReadOnly,
|
|
161
|
+
orgGoverned: deps.permissionRuleOrg !== undefined,
|
|
162
|
+
fullShellReachable,
|
|
163
|
+
onDeploymentClamp: () => {
|
|
164
|
+
const sink = deps.onNotice;
|
|
165
|
+
if (typeof sink === "function") {
|
|
166
|
+
if (readFaceClampAnnouncedSinks.has(sink))
|
|
167
|
+
return;
|
|
168
|
+
readFaceClampAnnouncedSinks.add(sink);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
if (readFaceClampConsoleAnnounced)
|
|
172
|
+
return;
|
|
173
|
+
readFaceClampConsoleAnnounced = true;
|
|
174
|
+
}
|
|
175
|
+
deliverEngineNotice(sink, deploymentReadFaceClampNotice());
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
if (resume !== undefined && (seedReadFaceSection === undefined || seedReadFaceSection.face === "roots"))
|
|
179
|
+
liveReadFace = "roots";
|
|
180
|
+
resolvedReadFace = liveReadFace;
|
|
181
|
+
if (resume === undefined && spec.sessionId !== undefined) {
|
|
182
|
+
const prior = await session.buildContext().catch(() => undefined);
|
|
183
|
+
for (const rec of wholeFileRecordsFromTranscript(prior?.messages ?? [])) {
|
|
184
|
+
const rk = await resolveKey(executionEnv, rootCanonical, rec.path, undefined, undefined, [...additionalRootsCanonical, ...additionalReadRootsCanonical], undefined, undefined, liveReadFace);
|
|
185
|
+
if (rk.ok)
|
|
186
|
+
seedReadFileStateFromTranscript(readFileState, rk.key, rec.content, rec.at);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const band = createHandsToolkit(executionEnv, readFileState, rootCanonical, {
|
|
190
|
+
...(additionalRootsCanonical.length > 0 ? { additionalRoots: additionalRootsCanonical } : {}),
|
|
191
|
+
...(additionalReadRootsCanonical.length > 0 ? { additionalReadRoots: additionalReadRootsCanonical } : {}),
|
|
192
|
+
...(readDenyAdditions.length > 0 ? { readDenyPatterns: readDenyAdditions } : {}),
|
|
193
|
+
...(readDenyBuiltinCfg.tiers !== undefined ? { readDenyBuiltinTiers: readDenyBuiltinCfg.tiers } : {}),
|
|
194
|
+
...(readDenyBuiltinCfg.exclude !== undefined ? { readDenyBuiltinExclude: readDenyBuiltinCfg.exclude } : {}),
|
|
195
|
+
readFace: liveReadFace,
|
|
196
|
+
includeShell: handsIncludeShell,
|
|
197
|
+
readOnly: handsReadOnly,
|
|
198
|
+
...(handsCwdRef ? { cwdRef: handsCwdRef } : {}),
|
|
199
|
+
taskRegistry: defaultTaskRegistry,
|
|
200
|
+
taskOwner: hostTaskId,
|
|
201
|
+
taskScope,
|
|
202
|
+
oneShot: spec.oneShot,
|
|
203
|
+
...(sessionId !== undefined ? { sessionId } : {}),
|
|
204
|
+
...(internals?.onTaskNotification !== undefined ? { taskNotification: internals.onTaskNotification } : {}),
|
|
205
|
+
...(internals?.detachHub !== undefined ? { detachHub: internals.detachHub } : {}),
|
|
206
|
+
...(deps.onNotice !== undefined ? { onNotice: deps.onNotice } : {}),
|
|
207
|
+
pdfModelCapabilities: pdfModelCapabilitiesOf(model),
|
|
208
|
+
...(deps.hands?.bashReadonlyAllow !== undefined ? { bashReadonlyAllow: deps.hands.bashReadonlyAllow } : {}),
|
|
209
|
+
...(deps.hands?.commitCoAuthor !== undefined ? { commitCoAuthor: deps.hands.commitCoAuthor } : {}),
|
|
210
|
+
...(deps.hands?.readImageDownsampler !== undefined ? { readImageDownsampler: deps.hands.readImageDownsampler } : {}),
|
|
211
|
+
...(deps.hands?.autoBackgroundOnTimeout !== undefined ? { autoBackgroundOnTimeout: deps.hands.autoBackgroundOnTimeout } : {}),
|
|
212
|
+
...(deps.hands?.readCyberReminder !== undefined ? { readCyberReminder: deps.hands.readCyberReminder } : {}),
|
|
213
|
+
beforeWrite: async (w) => {
|
|
214
|
+
const deploymentGate = deps.hands?.beforeWrite;
|
|
215
|
+
if (deploymentGate) {
|
|
216
|
+
const verdict = await deploymentGate(w);
|
|
217
|
+
if (verdict !== undefined && verdict.ok === false)
|
|
218
|
+
return verdict;
|
|
219
|
+
}
|
|
220
|
+
return memoryWriteGateRef.current?.(w);
|
|
221
|
+
},
|
|
222
|
+
mountBackgroundTaskTools: false,
|
|
223
|
+
monitorToolActive: backgroundTaskToolsActive && !(toolFaceSnapshot.exclude?.includes("Monitor") ?? false),
|
|
224
|
+
});
|
|
225
|
+
{
|
|
226
|
+
const bandNames = new Set(band.flatMap((t) => [t.name, ...(t.aliases ?? [])]));
|
|
227
|
+
const shadowed = (spec.tools ?? []).filter((t) => [t.name, ...(t.aliases ?? [])].some((n) => bandNames.has(n)));
|
|
228
|
+
if (shadowed.length > 0) {
|
|
229
|
+
const names = shadowed.map((t) => `"${t.name}"`).join(", ");
|
|
230
|
+
deps.onError?.(new Error(`spec.tools ${shadowed.length > 1 ? "entries" : "entry"} ${names} collide${shadowed.length > 1 ? "" : "s"} with the built-in hands tool band — the built-in wins (registered later; the harness tool Map is last-write-wins) and the caller tool never dispatches this task. Rename the caller tool, or don't inject executionEnv if you intend to replace the band.`), { phase: "config", sessionId });
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
tools.push(...band.map((t) => firstPartyOffload(t)));
|
|
234
|
+
const shellGate = effectiveShellGate;
|
|
235
|
+
if (shellGate === "off" && !(executionEnv instanceof StubExecutionEnv) && spec.handsReadOnly !== true) {
|
|
236
|
+
deps.onError?.(new Error(`shell gate doctrine is "off" while a real writable shell (Bash) is mounted — no shell safety-axis ` +
|
|
237
|
+
`fold applies to this run (commands are adjudicated by the ordinary policy/hook chain only). ` +
|
|
238
|
+
`Set spec.shellGate to "classify" or "always" if this deployment expects doctrine-gated shell behavior.`), { phase: "config", sessionId, classification: "shell-gate-off" });
|
|
239
|
+
}
|
|
240
|
+
if (shellGate !== "off" && !(executionEnv instanceof StubExecutionEnv) && spec.handsReadOnly !== true) {
|
|
241
|
+
const bashTierBefore = irreversibilityTier.get("Bash");
|
|
242
|
+
shellGatedBash = !egressTools.has("Bash") && bashTierBefore !== "always" && bashTierBefore !== "maybe";
|
|
243
|
+
const bashEffectiveTier = shellGate === "always" || bashTierBefore === "always" ? "always" : "maybe";
|
|
244
|
+
irreversibilityTier.set("Bash", bashEffectiveTier);
|
|
245
|
+
irreversibleTools.add("Bash");
|
|
246
|
+
const shellReadBoundary = () => ({
|
|
247
|
+
roots: [rootCanonical, ...additionalRootsCanonical, ...additionalReadRootsCanonical],
|
|
248
|
+
...(handsCwdRef?.current !== undefined ? { cwd: handsCwdRef.current } : {}),
|
|
249
|
+
denyMatch: (p) => readDenyMatcher?.matchPath(p)?.pattern ?? null,
|
|
250
|
+
...(resolvedReadFace !== undefined ? { face: resolvedReadFace } : {}),
|
|
251
|
+
});
|
|
252
|
+
if (shellGate === "classify" && shellGatedBash)
|
|
253
|
+
reversibilityProbes.set("Bash", bashReversibilityProbe(undefined, shellReadBoundary));
|
|
254
|
+
if (backgroundTaskToolsActive) {
|
|
255
|
+
const monitorTierBefore = irreversibilityTier.get("Monitor");
|
|
256
|
+
shellGatedMonitor = !egressTools.has("Monitor") && monitorTierBefore !== "always" && monitorTierBefore !== "maybe";
|
|
257
|
+
const monitorEffectiveTier = shellGate === "always" || monitorTierBefore === "always" ? "always" : "maybe";
|
|
258
|
+
irreversibilityTier.set("Monitor", monitorEffectiveTier);
|
|
259
|
+
irreversibleTools.add("Monitor");
|
|
260
|
+
if (shellGate === "classify" && shellGatedMonitor)
|
|
261
|
+
reversibilityProbes.set("Monitor", bashReversibilityProbe(undefined, shellReadBoundary));
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
readFileStateForCheckpoint,
|
|
267
|
+
seedContextFiles,
|
|
268
|
+
handsCwdRef,
|
|
269
|
+
workspaceStateSettle,
|
|
270
|
+
wsSnapshot,
|
|
271
|
+
rebaseWsPath,
|
|
272
|
+
backgroundTaskToolsActive,
|
|
273
|
+
resolvedReadFace,
|
|
274
|
+
readDenyAdditionsNormalized,
|
|
275
|
+
handsLessResolvedFace,
|
|
276
|
+
additionalRootsCanonical,
|
|
277
|
+
additionalReadRootsCanonical,
|
|
278
|
+
attachmentRootCanonical,
|
|
279
|
+
readDenyMatcher,
|
|
280
|
+
shellGatedBash,
|
|
281
|
+
shellGatedMonitor,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
@@ -37,11 +37,7 @@ export declare function __resetMaterializeEnvAnnouncements(): void;
|
|
|
37
37
|
* seam below (console latch only): tests here legitimately reuse ONE sink across prepares to pin
|
|
38
38
|
* the per-sink dedup itself, so the seam must be able to re-arm a still-referenced sink. */
|
|
39
39
|
export declare function __resetToolModelGateAnnouncements(): void;
|
|
40
|
-
|
|
41
|
-
* Deliberately asymmetric — it resets only the console latch: the WeakSet arm needs no seam
|
|
42
|
-
* because a test resets it by minting a fresh sink function (identity IS the ledger key), while
|
|
43
|
-
* the console arm's key is the process itself, which only this seam can refresh. */
|
|
44
|
-
export declare function __resetReadFaceClampAnnouncement(): void;
|
|
40
|
+
export { __resetReadFaceClampAnnouncement } from "./prepare-hands-readface.js";
|
|
45
41
|
/**
|
|
46
42
|
* design/164 件四 — how long before an execution environment's declared `lifetimeMs` expires the engine
|
|
47
43
|
* stops the run and checkpoints it. The margin has to cover ONE suspend: pausing/snapshotting the
|
|
@@ -56,7 +56,8 @@ import { prepareMemory } from "./prepare-memory.js";
|
|
|
56
56
|
import { limitConfigError, prepareConfigDoors } from "./prepare-config-doors.js";
|
|
57
57
|
import { NAMESPACED_NAME_SHAPES, prepareSafetyScan } from "./prepare-safety-scan.js";
|
|
58
58
|
import { prepareAcquireReconcile } from "./prepare-acquire-reconcile.js";
|
|
59
|
-
import {
|
|
59
|
+
import { prepareHandsMount, resolveHandsLessReadFace } from "./prepare-hands-readface.js";
|
|
60
|
+
import { prepareWorkspaceRestore, remoteEnvFailureNote, restoreWorkspaceWithRetry } from "./prepare-workspace-restore.js";
|
|
60
61
|
import { defaultPromptProvider, buildEnvironmentContext, formatLocalDate, isValidTimeZone, PROJECT_CONTEXT_FRAMING } from "../../prompts/default.js";
|
|
61
62
|
import { applyGitFrameGuard, probeGitStatusLane } from "./git-status-frame.js";
|
|
62
63
|
import { assemblePrompt } from "../../prompt-assembly/assemble.js";
|
|
@@ -76,7 +77,7 @@ import { hasBackgroundShell, sweepBackgroundShells } from "../background-shell.j
|
|
|
76
77
|
import { createTaskOutputTool, createTaskStopTool, defaultTaskRegistry } from "../task-registry.js";
|
|
77
78
|
import { createMonitorTool } from "../../tools/monitor.js";
|
|
78
79
|
import { createWorktreeTools } from "../../tools/worktree.js";
|
|
79
|
-
import { applyCompactionToReadFileState,
|
|
80
|
+
import { applyCompactionToReadFileState, isReadDedupStubResult, FULL_SHELL_CONTRACT_ID, HAND_TOOL_EFFECTS } from "../../tools/fs/index.js";
|
|
80
81
|
import { decodeTextBytes } from "../../tools/fs/encoding.js";
|
|
81
82
|
import { ASK_USER_QUESTION_TOOL_NAME, createAskUserQuestionTool, classifyQuestionOutcome, isLiveQuestionFace, validateAskQuestions, } from "../ask-question.js";
|
|
82
83
|
import { createSchedulerTools } from "../../tools/scheduler-tools.js";
|
|
@@ -86,8 +87,7 @@ import { createRunWorkflowTool, RUN_WORKFLOW_TOOL_NAME } from "../../orchestrati
|
|
|
86
87
|
import { resolveWorkflowSizeGuideline } from "../../orchestration/workflow-size-guideline.js";
|
|
87
88
|
import { createLspTool, gitCheckIgnoreFilter, resolveLspPath } from "../lsp.js";
|
|
88
89
|
import { resolveKey } from "../../tools/fs/safety.js";
|
|
89
|
-
import {
|
|
90
|
-
import { BINDING_CHECKPOINT_VERSION, mintCheckpointToken, ORG_ADMISSION_CHECKPOINT_VERSION, F012_CHECKPOINT_VERSION, FACE_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, buildRiskDescriptor, debitLedger, encodeAtFidelity, remainingBudgetMicroUsd, resolveCheckpointStore, resolveDeclaredFidelity, samePlainValue, } from "../checkpoint-store.js";
|
|
90
|
+
import { BINDING_CHECKPOINT_VERSION, mintCheckpointId, mintCheckpointToken, ORG_ADMISSION_CHECKPOINT_VERSION, F012_CHECKPOINT_VERSION, FACE_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, buildRiskDescriptor, debitLedger, encodeAtFidelity, remainingBudgetMicroUsd, resolveCheckpointStore, resolveDeclaredFidelity, samePlainValue, } from "../checkpoint-store.js";
|
|
91
91
|
import { boundInputHashOf } from "../canonical-json.js";
|
|
92
92
|
import { countElicitOptIns, deriveWiringManifest, resolveAskSeamForm, resolveDeclaredDurability, resolveElicitSeam, resolveQuestionSeam } from "../wiring-manifest.js";
|
|
93
93
|
import { durableParkGapFor } from "../park-selfcheck.js";
|
|
@@ -191,11 +191,7 @@ function announceToolModelGate(onNotice, modelId, gate) {
|
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
|
-
|
|
195
|
-
let readFaceClampConsoleAnnounced = false;
|
|
196
|
-
export function __resetReadFaceClampAnnouncement() {
|
|
197
|
-
readFaceClampConsoleAnnounced = false;
|
|
198
|
-
}
|
|
194
|
+
export { __resetReadFaceClampAnnouncement } from "./prepare-hands-readface.js";
|
|
199
195
|
const DEFAULT_MAX_SUSPENDS = 5;
|
|
200
196
|
const ULTRA_REASONING_TIERS = new Set(["xhigh", "max"]);
|
|
201
197
|
const DEFAULT_RESOURCE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
@@ -1036,14 +1032,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1036
1032
|
resourceSpentMicroUsd: priorLedger?.spentMicroUsd ?? 0,
|
|
1037
1033
|
suspendCount: priorSuspendCount,
|
|
1038
1034
|
};
|
|
1039
|
-
let readFileStateForCheckpoint;
|
|
1040
|
-
let seedContextFiles;
|
|
1041
|
-
let handsCwdRef;
|
|
1042
|
-
let workspaceStateSettle;
|
|
1043
|
-
let wsSnapshot;
|
|
1044
|
-
let rebaseWsPath = (p) => p;
|
|
1045
1035
|
let worktreeSessionRef;
|
|
1046
|
-
let backgroundTaskToolsActive = false;
|
|
1047
1036
|
let suspendForResource;
|
|
1048
1037
|
let suspendForPlatformLimit;
|
|
1049
1038
|
let suspendForReview;
|
|
@@ -1209,219 +1198,14 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1209
1198
|
foldProtocolAxes(a2a.toolAxes, "A2A");
|
|
1210
1199
|
const callIssuedAtRef = {};
|
|
1211
1200
|
const memoryWriteGateRef = {};
|
|
1212
|
-
const
|
|
1213
|
-
const
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
attachmentRootCanonical = rootCanonical;
|
|
1221
|
-
const canonicalizeExtraDirs = async (dirs, field, sink) => {
|
|
1222
|
-
for (const dir of dirs ?? []) {
|
|
1223
|
-
if (!dir || !dir.trim())
|
|
1224
|
-
continue;
|
|
1225
|
-
const c = await executionEnv.canonicalPath(dir);
|
|
1226
|
-
if (c.ok) {
|
|
1227
|
-
sink.push(c.value);
|
|
1228
|
-
}
|
|
1229
|
-
else {
|
|
1230
|
-
deps.onError?.(new Error(`${field} entry skipped (cannot canonicalize): ${dir}`), {
|
|
1231
|
-
phase: "config",
|
|
1232
|
-
sessionId,
|
|
1233
|
-
});
|
|
1234
|
-
emitTrace(deps.tracer, () => ({
|
|
1235
|
-
kind: "config.additional_directory_skipped",
|
|
1236
|
-
version: 1,
|
|
1237
|
-
taskId: hostTaskId,
|
|
1238
|
-
entry: dir,
|
|
1239
|
-
...(field !== "additionalDirectories" ? { field } : {}),
|
|
1240
|
-
reason: `${c.error.code}: ${c.error.message}`,
|
|
1241
|
-
ts: Date.now(),
|
|
1242
|
-
}));
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
};
|
|
1246
|
-
await canonicalizeExtraDirs(spec.additionalDirectories, "additionalDirectories", additionalRootsCanonical);
|
|
1247
|
-
await canonicalizeExtraDirs(spec.additionalReadDirectories, "additionalReadDirectories", additionalReadRootsCanonical);
|
|
1248
|
-
if (spec.envFacts?.scratchpadDir) {
|
|
1249
|
-
let c = await executionEnv.canonicalPath(spec.envFacts.scratchpadDir);
|
|
1250
|
-
if (!c.ok && c.error.code === "not_found") {
|
|
1251
|
-
const marker = await executionEnv.joinPath([spec.envFacts.scratchpadDir, ".sema-scratchpad"]);
|
|
1252
|
-
const exclusiveCreate = executionEnv.writeFileExclusive?.bind(executionEnv);
|
|
1253
|
-
if (marker.ok && exclusiveCreate) {
|
|
1254
|
-
const w = await exclusiveCreate(marker.value, "");
|
|
1255
|
-
if (w.ok || w.error.code === "already_exists")
|
|
1256
|
-
c = await executionEnv.canonicalPath(spec.envFacts.scratchpadDir);
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
if (c.ok)
|
|
1260
|
-
additionalRootsCanonical.push(c.value);
|
|
1261
|
-
}
|
|
1262
|
-
for (const a of [additionalRootsCanonical, additionalReadRootsCanonical])
|
|
1263
|
-
a.splice(0, a.length, ...new Set(a));
|
|
1264
|
-
const readFileState = new Map((resume?.seed.readFileState ?? []).map(([k, v]) => [rebaseRestoredPath(k), v]));
|
|
1265
|
-
readFileStateForCheckpoint = readFileState;
|
|
1266
|
-
seedContextFiles = async (files) => {
|
|
1267
|
-
for (const f of files) {
|
|
1268
|
-
const rk = await resolveKey(executionEnv, rootCanonical, f.path, undefined, undefined, [...additionalRootsCanonical, ...additionalReadRootsCanonical], undefined, undefined, resolvedReadFace);
|
|
1269
|
-
if (rk.ok)
|
|
1270
|
-
seedReadFileStateFromContext(readFileState, rk.key, f.content);
|
|
1271
|
-
}
|
|
1272
|
-
};
|
|
1273
|
-
const handsIncludeShell = !(executionEnv instanceof StubExecutionEnv);
|
|
1274
|
-
const handsReadOnly = spec.handsReadOnly === true;
|
|
1275
|
-
backgroundTaskToolsActive = handsIncludeShell && !handsReadOnly && hasBackgroundShell(executionEnv);
|
|
1276
|
-
wsSnapshot = resume !== undefined || !(handsIncludeShell && !handsReadOnly) ? undefined : await session.getWorkspaceState().catch(() => undefined);
|
|
1277
|
-
rebaseWsPath = (p) => (wsSnapshot === undefined || wsSnapshot.taskRoot === rootCanonical ? p : rebaseWorkspacePath(p, wsSnapshot.taskRoot, rootCanonical));
|
|
1278
|
-
if (handsIncludeShell && !handsReadOnly) {
|
|
1279
|
-
handsCwdRef = { current: rootCanonical };
|
|
1280
|
-
if (resume?.seed.handsCwd !== undefined)
|
|
1281
|
-
handsCwdRef.current = rebaseRestoredPath(resume.seed.handsCwd);
|
|
1282
|
-
else if (wsSnapshot?.handsCwd !== undefined)
|
|
1283
|
-
handsCwdRef.current = rebaseWsPath(wsSnapshot.handsCwd);
|
|
1284
|
-
workspaceStateSettle = {
|
|
1285
|
-
rootCanonical,
|
|
1286
|
-
restoredHandsCwd: handsCwdRef.current !== rootCanonical ? handsCwdRef.current : undefined,
|
|
1287
|
-
...(resume !== undefined ? { baselineUnknown: true } : {}),
|
|
1288
|
-
};
|
|
1289
|
-
}
|
|
1290
|
-
const seedReadFaceSection = resume?.seed.readFace;
|
|
1291
|
-
const readDenyAdditions = [...(deps.readDenyPatterns ?? []), ...(spec.readDenyPatterns ?? []), ...(seedReadFaceSection?.denyEntries ?? [])];
|
|
1292
|
-
const readDenyBuiltinCfg = {
|
|
1293
|
-
...(deps.readDenyBuiltinTiers !== undefined ? { tiers: [...deps.readDenyBuiltinTiers] } : {}),
|
|
1294
|
-
...(deps.readDenyBuiltinExclude !== undefined ? { exclude: [...deps.readDenyBuiltinExclude] } : {}),
|
|
1295
|
-
};
|
|
1296
|
-
readDenyMatcher = compileReadDeny(readDenyAdditions, "readDenyPatterns", readDenyBuiltinCfg);
|
|
1297
|
-
readDenyAdditionsNormalized = compileReadDeny(readDenyAdditions, "readDenyPatterns", { tiers: [] }).entries;
|
|
1298
|
-
let liveReadFace = resolveReadFace({
|
|
1299
|
-
specReadFace: spec.readFace,
|
|
1300
|
-
depsReadFace: deps.readFace,
|
|
1301
|
-
readOnlyMount: handsReadOnly,
|
|
1302
|
-
orgGoverned: deps.permissionRuleOrg !== undefined,
|
|
1303
|
-
fullShellReachable,
|
|
1304
|
-
onDeploymentClamp: () => {
|
|
1305
|
-
const sink = deps.onNotice;
|
|
1306
|
-
if (typeof sink === "function") {
|
|
1307
|
-
if (readFaceClampAnnouncedSinks.has(sink))
|
|
1308
|
-
return;
|
|
1309
|
-
readFaceClampAnnouncedSinks.add(sink);
|
|
1310
|
-
}
|
|
1311
|
-
else {
|
|
1312
|
-
if (readFaceClampConsoleAnnounced)
|
|
1313
|
-
return;
|
|
1314
|
-
readFaceClampConsoleAnnounced = true;
|
|
1315
|
-
}
|
|
1316
|
-
deliverEngineNotice(sink, deploymentReadFaceClampNotice());
|
|
1317
|
-
},
|
|
1318
|
-
});
|
|
1319
|
-
if (resume !== undefined && (seedReadFaceSection === undefined || seedReadFaceSection.face === "roots"))
|
|
1320
|
-
liveReadFace = "roots";
|
|
1321
|
-
resolvedReadFace = liveReadFace;
|
|
1322
|
-
if (resume === undefined && spec.sessionId !== undefined) {
|
|
1323
|
-
const prior = await session.buildContext().catch(() => undefined);
|
|
1324
|
-
for (const rec of wholeFileRecordsFromTranscript(prior?.messages ?? [])) {
|
|
1325
|
-
const rk = await resolveKey(executionEnv, rootCanonical, rec.path, undefined, undefined, [...additionalRootsCanonical, ...additionalReadRootsCanonical], undefined, undefined, liveReadFace);
|
|
1326
|
-
if (rk.ok)
|
|
1327
|
-
seedReadFileStateFromTranscript(readFileState, rk.key, rec.content, rec.at);
|
|
1328
|
-
}
|
|
1329
|
-
}
|
|
1330
|
-
const band = createHandsToolkit(executionEnv, readFileState, rootCanonical, {
|
|
1331
|
-
...(additionalRootsCanonical.length > 0 ? { additionalRoots: additionalRootsCanonical } : {}),
|
|
1332
|
-
...(additionalReadRootsCanonical.length > 0 ? { additionalReadRoots: additionalReadRootsCanonical } : {}),
|
|
1333
|
-
...(readDenyAdditions.length > 0 ? { readDenyPatterns: readDenyAdditions } : {}),
|
|
1334
|
-
...(readDenyBuiltinCfg.tiers !== undefined ? { readDenyBuiltinTiers: readDenyBuiltinCfg.tiers } : {}),
|
|
1335
|
-
...(readDenyBuiltinCfg.exclude !== undefined ? { readDenyBuiltinExclude: readDenyBuiltinCfg.exclude } : {}),
|
|
1336
|
-
readFace: liveReadFace,
|
|
1337
|
-
includeShell: handsIncludeShell,
|
|
1338
|
-
readOnly: handsReadOnly,
|
|
1339
|
-
...(handsCwdRef ? { cwdRef: handsCwdRef } : {}),
|
|
1340
|
-
taskRegistry: defaultTaskRegistry,
|
|
1341
|
-
taskOwner: hostTaskId,
|
|
1342
|
-
taskScope,
|
|
1343
|
-
oneShot: spec.oneShot,
|
|
1344
|
-
...(sessionId !== undefined ? { sessionId } : {}),
|
|
1345
|
-
...(internals?.onTaskNotification !== undefined ? { taskNotification: internals.onTaskNotification } : {}),
|
|
1346
|
-
...(internals?.detachHub !== undefined ? { detachHub: internals.detachHub } : {}),
|
|
1347
|
-
...(deps.onNotice !== undefined ? { onNotice: deps.onNotice } : {}),
|
|
1348
|
-
pdfModelCapabilities: pdfModelCapabilitiesOf(model),
|
|
1349
|
-
...(deps.hands?.bashReadonlyAllow !== undefined ? { bashReadonlyAllow: deps.hands.bashReadonlyAllow } : {}),
|
|
1350
|
-
...(deps.hands?.commitCoAuthor !== undefined ? { commitCoAuthor: deps.hands.commitCoAuthor } : {}),
|
|
1351
|
-
...(deps.hands?.readImageDownsampler !== undefined ? { readImageDownsampler: deps.hands.readImageDownsampler } : {}),
|
|
1352
|
-
...(deps.hands?.autoBackgroundOnTimeout !== undefined ? { autoBackgroundOnTimeout: deps.hands.autoBackgroundOnTimeout } : {}),
|
|
1353
|
-
...(deps.hands?.readCyberReminder !== undefined ? { readCyberReminder: deps.hands.readCyberReminder } : {}),
|
|
1354
|
-
beforeWrite: async (w) => {
|
|
1355
|
-
const deploymentGate = deps.hands?.beforeWrite;
|
|
1356
|
-
if (deploymentGate) {
|
|
1357
|
-
const verdict = await deploymentGate(w);
|
|
1358
|
-
if (verdict !== undefined && verdict.ok === false)
|
|
1359
|
-
return verdict;
|
|
1360
|
-
}
|
|
1361
|
-
return memoryWriteGateRef.current?.(w);
|
|
1362
|
-
},
|
|
1363
|
-
mountBackgroundTaskTools: false,
|
|
1364
|
-
monitorToolActive: backgroundTaskToolsActive && !(toolFaceSnapshot.exclude?.includes("Monitor") ?? false),
|
|
1365
|
-
});
|
|
1366
|
-
{
|
|
1367
|
-
const bandNames = new Set(band.flatMap((t) => [t.name, ...(t.aliases ?? [])]));
|
|
1368
|
-
const shadowed = (spec.tools ?? []).filter((t) => [t.name, ...(t.aliases ?? [])].some((n) => bandNames.has(n)));
|
|
1369
|
-
if (shadowed.length > 0) {
|
|
1370
|
-
const names = shadowed.map((t) => `"${t.name}"`).join(", ");
|
|
1371
|
-
deps.onError?.(new Error(`spec.tools ${shadowed.length > 1 ? "entries" : "entry"} ${names} collide${shadowed.length > 1 ? "" : "s"} with the built-in hands tool band — the built-in wins (registered later; the harness tool Map is last-write-wins) and the caller tool never dispatches this task. Rename the caller tool, or don't inject executionEnv if you intend to replace the band.`), { phase: "config", sessionId });
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
tools.push(...band.map((t) => firstPartyOffload(t)));
|
|
1375
|
-
const shellGate = effectiveShellGate;
|
|
1376
|
-
if (shellGate === "off" && !(executionEnv instanceof StubExecutionEnv) && spec.handsReadOnly !== true) {
|
|
1377
|
-
deps.onError?.(new Error(`shell gate doctrine is "off" while a real writable shell (Bash) is mounted — no shell safety-axis ` +
|
|
1378
|
-
`fold applies to this run (commands are adjudicated by the ordinary policy/hook chain only). ` +
|
|
1379
|
-
`Set spec.shellGate to "classify" or "always" if this deployment expects doctrine-gated shell behavior.`), { phase: "config", sessionId, classification: "shell-gate-off" });
|
|
1380
|
-
}
|
|
1381
|
-
if (shellGate !== "off" && !(executionEnv instanceof StubExecutionEnv) && spec.handsReadOnly !== true) {
|
|
1382
|
-
const bashTierBefore = irreversibilityTier.get("Bash");
|
|
1383
|
-
shellGatedBash = !egressTools.has("Bash") && bashTierBefore !== "always" && bashTierBefore !== "maybe";
|
|
1384
|
-
const bashEffectiveTier = shellGate === "always" || bashTierBefore === "always" ? "always" : "maybe";
|
|
1385
|
-
irreversibilityTier.set("Bash", bashEffectiveTier);
|
|
1386
|
-
irreversibleTools.add("Bash");
|
|
1387
|
-
const shellReadBoundary = () => ({
|
|
1388
|
-
roots: [rootCanonical, ...additionalRootsCanonical, ...additionalReadRootsCanonical],
|
|
1389
|
-
...(handsCwdRef?.current !== undefined ? { cwd: handsCwdRef.current } : {}),
|
|
1390
|
-
denyMatch: (p) => readDenyMatcher?.matchPath(p)?.pattern ?? null,
|
|
1391
|
-
...(resolvedReadFace !== undefined ? { face: resolvedReadFace } : {}),
|
|
1392
|
-
});
|
|
1393
|
-
if (shellGate === "classify" && shellGatedBash)
|
|
1394
|
-
reversibilityProbes.set("Bash", bashReversibilityProbe(undefined, shellReadBoundary));
|
|
1395
|
-
if (backgroundTaskToolsActive) {
|
|
1396
|
-
const monitorTierBefore = irreversibilityTier.get("Monitor");
|
|
1397
|
-
shellGatedMonitor = !egressTools.has("Monitor") && monitorTierBefore !== "always" && monitorTierBefore !== "maybe";
|
|
1398
|
-
const monitorEffectiveTier = shellGate === "always" || monitorTierBefore === "always" ? "always" : "maybe";
|
|
1399
|
-
irreversibilityTier.set("Monitor", monitorEffectiveTier);
|
|
1400
|
-
irreversibleTools.add("Monitor");
|
|
1401
|
-
if (shellGate === "classify" && shellGatedMonitor)
|
|
1402
|
-
reversibilityProbes.set("Monitor", bashReversibilityProbe(undefined, shellReadBoundary));
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1406
|
-
else {
|
|
1407
|
-
const liveFace = resolveReadFace({
|
|
1408
|
-
specReadFace: spec.readFace,
|
|
1409
|
-
depsReadFace: deps.readFace,
|
|
1410
|
-
readOnlyMount: spec.handsReadOnly === true,
|
|
1411
|
-
orgGoverned: deps.permissionRuleOrg !== undefined,
|
|
1412
|
-
fullShellReachable,
|
|
1413
|
-
});
|
|
1414
|
-
const seed = resume?.seed.readFace;
|
|
1415
|
-
handsLessResolvedFace = resume !== undefined && (seed === undefined || seed.face === "roots") ? "roots" : liveFace;
|
|
1416
|
-
const denyAdditions = [...(deps.readDenyPatterns ?? []), ...(spec.readDenyPatterns ?? []), ...(seed?.denyEntries ?? [])];
|
|
1417
|
-
resolveReadDenyBuiltins({
|
|
1418
|
-
...(deps.readDenyBuiltinTiers !== undefined ? { tiers: deps.readDenyBuiltinTiers } : {}),
|
|
1419
|
-
...(deps.readDenyBuiltinExclude !== undefined ? { exclude: deps.readDenyBuiltinExclude } : {}),
|
|
1420
|
-
});
|
|
1421
|
-
if (denyAdditions.length > 0) {
|
|
1422
|
-
readDenyAdditionsNormalized = compileReadDeny(denyAdditions, "readDenyPatterns", { tiers: [] }).entries;
|
|
1423
|
-
}
|
|
1424
|
-
}
|
|
1201
|
+
const handsReadFaceInput = { handsEnabled, executionEnv, taskRootFinal, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals, memoryWriteGateRef, firstPartyOffload, tools, egressTools, irreversibilityTier, irreversibleTools, reversibilityProbes };
|
|
1202
|
+
const handsReadFace = handsEnabled ? await prepareHandsMount(handsReadFaceInput) : resolveHandsLessReadFace(handsReadFaceInput);
|
|
1203
|
+
const { readFileStateForCheckpoint, seedContextFiles, handsCwdRef, workspaceStateSettle, wsSnapshot, rebaseWsPath, backgroundTaskToolsActive, additionalRootsCanonical, additionalReadRootsCanonical, attachmentRootCanonical, readDenyMatcher } = handsReadFace;
|
|
1204
|
+
resolvedReadFace = handsReadFace.resolvedReadFace;
|
|
1205
|
+
readDenyAdditionsNormalized = handsReadFace.readDenyAdditionsNormalized;
|
|
1206
|
+
handsLessResolvedFace = handsReadFace.handsLessResolvedFace;
|
|
1207
|
+
shellGatedBash = handsReadFace.shellGatedBash;
|
|
1208
|
+
shellGatedMonitor = handsReadFace.shellGatedMonitor;
|
|
1425
1209
|
if (backgroundTaskToolsActive || workflowToolsActive) {
|
|
1426
1210
|
toolEffects.set("TaskOutput", "read");
|
|
1427
1211
|
toolEffects.set("TaskStop", "write");
|
|
@@ -3821,6 +3605,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3821
3605
|
const mintedAt = Date.now();
|
|
3822
3606
|
const cp = {
|
|
3823
3607
|
token,
|
|
3608
|
+
checkpointId: mintCheckpointId(),
|
|
3824
3609
|
version: faceCheckpointState() ? FACE_CHECKPOINT_VERSION : f012CheckpointState() ? F012_CHECKPOINT_VERSION : orgAdmissionCheckpointState() ? ORG_ADMISSION_CHECKPOINT_VERSION : resourceLedgerOut.totalTokens !== undefined ? TOKEN_CHECKPOINT_VERSION : RESOURCE_CHECKPOINT_VERSION,
|
|
3825
3610
|
scope,
|
|
3826
3611
|
sessionId,
|
|
@@ -3903,6 +3688,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3903
3688
|
const mintedAt = Date.now();
|
|
3904
3689
|
const cp = {
|
|
3905
3690
|
token,
|
|
3691
|
+
checkpointId: mintCheckpointId(),
|
|
3906
3692
|
version: faceCheckpointState() ? FACE_CHECKPOINT_VERSION : f012CheckpointState() ? F012_CHECKPOINT_VERSION : orgAdmissionCheckpointState() ? ORG_ADMISSION_CHECKPOINT_VERSION : reviewLedger.totalTokens !== undefined ? TOKEN_CHECKPOINT_VERSION : BINDING_CHECKPOINT_VERSION,
|
|
3907
3693
|
scope,
|
|
3908
3694
|
sessionId,
|
|
@@ -4164,6 +3950,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4164
3950
|
const mintedAt = Date.now();
|
|
4165
3951
|
cp = {
|
|
4166
3952
|
token,
|
|
3953
|
+
checkpointId: mintCheckpointId(),
|
|
4167
3954
|
version: faceCheckpointState() ? FACE_CHECKPOINT_VERSION : realApproval !== undefined ? REAL_APPROVAL_CHECKPOINT_VERSION : f012CheckpointState() ? F012_CHECKPOINT_VERSION : orgAdmissionCheckpointState() ? ORG_ADMISSION_CHECKPOINT_VERSION : approvalLedger.totalTokens !== undefined ? TOKEN_CHECKPOINT_VERSION : BINDING_CHECKPOINT_VERSION,
|
|
4168
3955
|
scope,
|
|
4169
3956
|
sessionId,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { persistedReadDenyEntryProblem } from "../../tools/fs/read-deny.js";
|
|
2
2
|
import { createSafeNotifier, observeThenableRejection } from "../safe-notify.js";
|
|
3
|
-
import { deliverDelegationLifecycle } from "../types.js";
|
|
3
|
+
import { deliverDelegationLifecycle, deliverEngineNotice, undrainedUserInputNotices } from "../types.js";
|
|
4
4
|
import { AgentHarness, DEFAULT_COMPACTION_SETTINGS, uuidv7 } from "../../internal/harness.js";
|
|
5
5
|
import { snapshotActorAssertion } from "../../internal/llm.js";
|
|
6
6
|
import { CheckpointError, BINDING_CHECKPOINT_VERSION, checkpointVersionOf, F012_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, FACE_CHECKPOINT_VERSION, remainingBudgetMicroUsd, readPendingSteerQueue, remainingTokens, LEGACY_PENDING_STEER_INPUT_ID, MAX_STEER_INPUT_ID_CHARS, validatePendingSteer, winnerFromOutcome, } from "../checkpoint-store.js";
|
|
@@ -2068,6 +2068,11 @@ export class Runner {
|
|
|
2068
2068
|
for (const p of payloads)
|
|
2069
2069
|
this.pendingSessionNotifications.pend(notificationSessionId, p);
|
|
2070
2070
|
};
|
|
2071
|
+
prepared.harness.onUndrainedUserInputs = (counts) => {
|
|
2072
|
+
for (const notice of undrainedUserInputNotices(counts, spec.taskId)) {
|
|
2073
|
+
deliverEngineNotice(this.deps.onNotice, notice);
|
|
2074
|
+
}
|
|
2075
|
+
};
|
|
2071
2076
|
prepared.harness.onEngineNoteConsumed = (p) => {
|
|
2072
2077
|
const peer = p?.peer;
|
|
2073
2078
|
if (peer !== undefined && Array.isArray(peer.hopChain))
|