@sema-agent/core
Version:
Stateless, task-oriented AI agent core
170 lines (169 loc) • 10.2 kB
JavaScript
import { hasBackgroundShell, sweepBackgroundShells, sweepRunBoundaryBackgroundShells } from "../background-shell.js";
import { checkpointVersionFor, debitLedger, mintCheckpointId, mintCheckpointToken, } from "../checkpoint-store.js";
import { defaultTaskRegistry } from "../task-registry.js";
import { checkpointScopeOf } from "./checkpoint-scope.js";
import { DEFAULT_RESOURCE_TTL_MS, publishCommittedSuspend, sanitizedTtlMs, USAGE_WINDOW_REAP_MARGIN_MS } from "./park-commit.js";
import { remoteEnvFailureNote } from "./remote-env-retry.js";
export function prepareBoundaryParks(input) {
const { saga, spec, checkpointStore, abortController, harness, session, sessions, sessionId, deps, priorLedger, maxSlices, maxSuspends, resourceTotal, priorSuspendCount, suspendChainBase, humanReviewRef, liveSpendRef, now, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, pausedRef, remoteEnvFailures, resourceSuspendEligible, durableSuspendInfraReady, incompleteSuspendAdapter } = input;
if (saga === undefined)
return { suspendForResource: undefined, suspendForPlatformLimit: undefined, suspendForReview: undefined };
const { inFlightSpendMicroUsd, serializeCheckpointState, commitSuspendSaga, suspendLoopCapHit, suspendableEnv, parkOnlyRemoteEnv, parkOnlyHandle } = saga;
const mintResourceSuspend = async (reason, sliceSpend, hint) => {
const rs = spec.resourceSuspend;
if (!checkpointStore)
return false;
const scope = rs?.scope ?? checkpointScopeOf(spec);
if (abortController.signal.aborted)
return false;
if (suspendLoopCapHit(priorLedger?.sliceCount ?? 0, maxSlices, " (resource slice limit)"))
return false;
const leafId = await session.getLeafId();
if (!leafId)
return false;
if (abortController.signal.aborted)
return false;
let remoteHandle;
if (suspendableEnv !== undefined) {
if (hasBackgroundShell(suspendableEnv))
await sweepBackgroundShells(suspendableEnv, defaultTaskRegistry);
const snap = await suspendableEnv.suspendVM({ abortSignal: abortController.signal });
if (!snap.ok) {
remoteEnvFailures.push(remoteEnvFailureNote("suspendVM", snap.error, 1));
deps.onError?.(new Error(`resource suspendVM failed (${snap.error.code}): ${snap.error.message}`, { cause: snap.error }), { phase: "config", sessionId });
return false;
}
remoteHandle = { ...suspendableEnv.workspaceHandle(), snapshotId: snap.value };
}
else if (parkOnlyRemoteEnv !== undefined) {
if (hasBackgroundShell(parkOnlyRemoteEnv))
await sweepRunBoundaryBackgroundShells(parkOnlyRemoteEnv, defaultTaskRegistry, { task: spec.retainBackgroundProcesses === true });
remoteHandle = parkOnlyHandle(parkOnlyRemoteEnv);
}
const token = mintCheckpointToken();
const gate = { kind: "resource_limit", reason, ...(hint !== undefined ? { resumeAfterMs: hint.resumeAfterMs } : {}) };
const resourceLedgerOut = debitLedger(priorLedger, sliceSpend, resourceTotal);
const mintedAt = Date.now();
const cp = {
token,
checkpointId: mintCheckpointId(),
version: checkpointVersionFor({ resource: true, binding: false, token: resourceLedgerOut.totalTokens !== undefined, orgAdmission: orgAdmissionCheckpointState(), f012: f012CheckpointState(), realApproval: false, face: faceCheckpointState() }),
scope,
sessionId,
leafId,
gate,
pendingAction: { kind: "resource_limit", reason },
state: serializeCheckpointState(remoteHandle),
status: "pending",
createdAt: mintedAt,
deadline: mintedAt + Math.max(sanitizedTtlMs(rs?.ttlMs) ?? DEFAULT_RESOURCE_TTL_MS, hint !== undefined ? hint.resumeAfterMs + USAGE_WINDOW_REAP_MARGIN_MS : 0),
suspendCount: priorSuspendCount,
humanReview: humanReviewRef.count > 0
? { count: humanReviewRef.count, totalWaitMs: humanReviewRef.totalWaitMs, gates: [...humanReviewRef.gates] }
: undefined,
resourceLedger: resourceLedgerOut,
...(spec.durableApproval !== undefined ? { durableApproval: { ...spec.durableApproval } } : {}),
...(spec.principal ? { principal: spec.principal } : {}),
};
if ((await commitSuspendSaga(token, cp, suspendableEnv, remoteHandle)).tag !== "committed")
return false;
publishCommittedSuspend({ pausedRef }, token, gate, scope, remoteHandle, cp.checkpointId, cp.pendingAction);
try {
await sessions.pin?.(sessionId);
}
catch (pinErr) {
deps.onError?.(pinErr, { phase: "config", sessionId });
}
harness.requestStopAfterTurn();
return true;
};
const suspendForResource = resourceSuspendEligible ? mintResourceSuspend : undefined;
const suspendForPlatformLimit = durableSuspendInfraReady ? mintResourceSuspend : undefined;
const suspendForReview = checkpointStore
? async (reason) => {
if (!checkpointStore)
return false;
if (abortController.signal.aborted)
return false;
if (incompleteSuspendAdapter !== undefined) {
try {
deps.onError?.(new Error(`plan_review park skipped: the per-task execution env declares capabilities.suspendable but its adapter does not implement ${incompleteSuspendAdapter.join(" or ")}, so its workspace could not be restored on resume (the plan-review request was dropped; the run continues without pausing)`), { phase: "config", sessionId });
}
catch {
}
return false;
}
if (suspendLoopCapHit(suspendChainBase(), maxSuspends, " for a plan_review (likely a resume/restart loop)."))
return false;
const leafId = await session.getLeafId();
if (!leafId) {
try {
deps.onError?.(new Error("plan_review park skipped: no committed session leaf (the plan-review request was dropped; the run continues without pausing)"), { phase: "config", sessionId });
}
catch {
}
return false;
}
if (abortController.signal.aborted)
return false;
let remoteHandle;
if (suspendableEnv !== undefined) {
if (hasBackgroundShell(suspendableEnv))
await sweepBackgroundShells(suspendableEnv, defaultTaskRegistry);
const snap = await suspendableEnv.suspendVM({ abortSignal: abortController.signal });
if (!snap.ok) {
remoteEnvFailures.push(remoteEnvFailureNote("suspendVM", snap.error, 1));
deps.onError?.(new Error(`plan_review suspendVM failed (${snap.error.code}): ${snap.error.message}`, { cause: snap.error }), { phase: "config", sessionId });
return false;
}
remoteHandle = { ...suspendableEnv.workspaceHandle(), snapshotId: snap.value };
}
else if (parkOnlyRemoteEnv !== undefined) {
if (hasBackgroundShell(parkOnlyRemoteEnv))
await sweepRunBoundaryBackgroundShells(parkOnlyRemoteEnv, defaultTaskRegistry, { task: spec.retainBackgroundProcesses === true });
remoteHandle = parkOnlyHandle(parkOnlyRemoteEnv);
}
const token = mintCheckpointToken();
const scope = checkpointScopeOf(spec);
const gate = { kind: "plan_review", reason: reason ?? `plan review requested` };
const reviewLedger = debitLedger(priorLedger, liveSpendRef.get?.() ?? { costMicroUsd: 0, tokens: 0, turns: 0, walltimeMs: 0 }, resourceTotal, { countSlice: false });
const mintedAt = Date.now();
const cp = {
token,
checkpointId: mintCheckpointId(),
version: checkpointVersionFor({ resource: false, binding: true, token: reviewLedger.totalTokens !== undefined, orgAdmission: orgAdmissionCheckpointState(), f012: f012CheckpointState(), realApproval: false, face: faceCheckpointState() }),
scope,
sessionId,
leafId,
gate,
pendingAction: { kind: "plan_review" },
state: serializeCheckpointState(remoteHandle, inFlightSpendMicroUsd()),
status: "pending",
createdAt: mintedAt,
suspendedAt: now(),
deadline: mintedAt + (sanitizedTtlMs(spec.durableApproval?.ttlMs) ?? DEFAULT_RESOURCE_TTL_MS),
suspendCount: suspendChainBase() + 1,
humanReview: humanReviewRef.count > 0
? { count: humanReviewRef.count, totalWaitMs: humanReviewRef.totalWaitMs, gates: [...humanReviewRef.gates] }
: undefined,
resourceLedger: reviewLedger,
sourceTaskId: sessionId,
...(spec.principal ? { principal: spec.principal } : {}),
...(spec.durableApproval !== undefined ? { durableApproval: { ...spec.durableApproval } } : {}),
};
if ((await commitSuspendSaga(token, cp, suspendableEnv, remoteHandle)).tag !== "committed")
return false;
publishCommittedSuspend({ pausedRef }, token, gate, scope, remoteHandle, cp.checkpointId, cp.pendingAction);
try {
await sessions.pin?.(sessionId);
}
catch (pinErr) {
deps.onError?.(pinErr, { phase: "config", sessionId });
}
abortController.abort();
void harness.abort();
return true;
}
: undefined;
return { suspendForResource, suspendForPlatformLimit, suspendForReview };
}