@sema-agent/core
Version:
Stateless, task-oriented AI agent core
126 lines (125 loc) • 8.33 kB
JavaScript
import { isRemoteExecutionEnv, missingRestoreSurface } from "../remote-env.js";
import { remoteEnvFailureNote, restoreWorkspaceWithRetry } from "./remote-env-retry.js";
import { rebaseWorkspacePathAcross } from "./workspace-path.js";
export { remoteEnvFailureNote, restoreWorkspaceWithRetry } from "./remote-env-retry.js";
export async function prepareWorkspaceRestore(input) {
const { ownedEnv, deps, spec, internals, resume, abortController, sessionId } = input;
let taskRootPath = input.taskRootInitial;
let restoredRootRebase;
const rebaseRestoredPath = (p) => restoredRootRebase === undefined ? p : rebaseWorkspacePathAcross(p, restoredRootRebase.from, restoredRootRebase.to);
if (resume?.workspaceHandle !== undefined) {
const failResume = (message, cause, note) => {
const e = new Error(message, cause ? { cause } : undefined);
e.code = "resume.env_failed";
if (note !== undefined)
e.remoteEnvFailure = note;
throw e;
};
const handle = resume.workspaceHandle;
const refuseIdentityMismatch = (resumedHandle) => {
if (resumedHandle.provider !== handle.provider) {
failResume(`resume workspace identity mismatch: the checkpoint records provider "${handle.provider}" but the resumed env reports "${resumedHandle.provider}" — refusing to continue a workspace on a different backend (wire the factory to rebuild the checkpointed lane and re-resume)`);
}
if (handle.deviceId !== undefined && resumedHandle.deviceId !== handle.deviceId) {
failResume(resumedHandle.deviceId === undefined
? `resume workspace identity mismatch: the checkpoint records deviceId "${handle.deviceId}" but the resumed env reports none — a device-bound workspace cannot be verified on a handle that does not state its device (absence is not a match)`
: `resume workspace identity mismatch: the checkpoint records deviceId "${handle.deviceId}" but the resumed env reports "${resumedHandle.deviceId}" — refusing to continue on a different physical device`);
}
};
if (ownedEnv === undefined || !isRemoteExecutionEnv(ownedEnv)) {
failResume("resume needs a RemoteExecutionEnv from executionEnvFactory to restore the workspace snapshot");
}
else if (handle.snapshotId === undefined) {
if (handle.restoreMode !== "park_only" && ownedEnv.capabilities.suspendable) {
failResume("checkpoint workspaceHandle has no snapshotId and is not a park_only handle, but the resumed env is suspendable — refusing to resume on a possibly-unrestored workspace (corrupt checkpoint?)");
}
refuseIdentityMismatch(ownedEnv.workspaceHandle());
if (handle.mountPath && handle.mountPath !== taskRootPath) {
taskRootPath = handle.mountPath;
}
}
else {
const restoreSignal = spec.signal
? AbortSignal.any([abortController.signal, spec.signal])
: abortController.signal;
const missingHere = missingRestoreSurface(ownedEnv);
if (missingHere.length > 0) {
failResume(`the resumed execution env cannot restore a workspace snapshot: its adapter does not implement ${missingHere.join(" or ")}. The checkpoint holds snapshot "${handle.snapshotId}" — wire an adapter that implements the full RemoteExecutionEnv restore surface and re-resume.`);
}
refuseIdentityMismatch(ownedEnv.workspaceHandle());
const { outcome: restored, attempts: restoreAttempts } = await restoreWorkspaceWithRetry(ownedEnv, handle.snapshotId, {
abortSignal: restoreSignal,
priorHandle: handle,
});
if (!restored.ok) {
failResume(`resumeVM failed after ${restoreAttempts} attempt(s) (${restored.error.code}): ${restored.error.message}`, restored.error, remoteEnvFailureNote("resumeVM", restored.error, restoreAttempts));
}
else {
refuseIdentityMismatch(restored.value);
const restoredEnv = ownedEnv;
const canonicalInEnv = async (p) => {
try {
const r = await restoredEnv.canonicalPath(p, restoreSignal);
return r.ok ? r.value : undefined;
}
catch {
return undefined;
}
};
let checkpointedCanonical;
let sameRootUnderAlias = false;
if (restored.value.mountPath !== handle.mountPath) {
checkpointedCanonical = await canonicalInEnv(handle.mountPath);
const restoredCanonical = await canonicalInEnv(restored.value.mountPath);
sameRootUnderAlias =
checkpointedCanonical !== undefined && restoredCanonical !== undefined && checkpointedCanonical === restoredCanonical;
}
if (restored.value.mountPath !== handle.mountPath && !sameRootUnderAlias) {
if (resume.executesApprovedAction === true) {
failResume(`resumeVM workspace-root divergence with a pending approved action: checkpointed mountPath "${handle.mountPath}" but the restored handle reports "${restored.value.mountPath}" — the approved args are bound to the checkpointed root; refusing to execute them against a moved workspace (adapter should honor priorHandle)`);
}
try {
deps.onError?.(new Error(`resumeVM workspace-root divergence: checkpointed mountPath "${handle.mountPath}" but the restored handle reports "${restored.value.mountPath}" — the resumed task follows the restored root`), { phase: "config", sessionId });
}
catch {
}
}
if (restored.value.mountPath && restored.value.mountPath !== taskRootPath) {
taskRootPath = restored.value.mountPath;
}
if (restored.value.mountPath && restored.value.mountPath !== handle.mountPath && !sameRootUnderAlias) {
const from = checkpointedCanonical !== undefined && checkpointedCanonical !== handle.mountPath
? [handle.mountPath, checkpointedCanonical]
: [handle.mountPath];
restoredRootRebase = { from, to: restored.value.mountPath };
try {
deps.onError?.(new Error(from.length > 1
? `resumeVM workspace-root rebase accepts both spellings of the checkpointed root (${from.map((f) => `"${f}"`).join(" and ")}) when migrating persisted paths to "${restored.value.mountPath}"`
: `resumeVM workspace-root rebase is spelling-exact: it matches the checkpointed root "${handle.mountPath}" only, so persisted paths recorded under an equivalent alias of it are NOT migrated to "${restored.value.mountPath}" and stay as written`), { phase: "config", sessionId });
}
catch {
}
}
}
const init = await ownedEnv.postResumeInit();
if (!init.ok) {
failResume(`postResumeInit failed (${init.error.code}): ${init.error.message}`, init.error, remoteEnvFailureNote("postResumeInit", init.error, 1));
}
}
}
if (internals?.onWorkspaceResolved !== undefined) {
try {
const workspaceEnv = ownedEnv ?? deps.executionEnv;
internals.onWorkspaceResolved({
cwd: taskRootPath,
isolated: internals.isolation === "worktree",
remote: workspaceEnv !== undefined &&
(isRemoteExecutionEnv(workspaceEnv) || workspaceEnv.hostLocalPaths === false),
...(input.placement !== undefined ? { placement: input.placement } : {}),
});
}
catch {
}
}
return { taskRootFinal: taskRootPath, rebaseRestoredPath };
}