@sema-agent/core
Version:
Stateless, task-oriented AI agent core
115 lines (114 loc) • 6.55 kB
JavaScript
import { errorCodeOf } from "./assemble-result.js";
import { resumeDecisionWasNegative } from "./decide-continuation.js";
import { drainForwardedFramesBeforeDone, forwardsSubagentEvents } from "./prepare-run-refs.js";
import { hasDestroy } from "../remote-env.js";
import { createSafeNotifier } from "../safe-notify.js";
import { settleTeardownLeg } from "./teardown-bounded.js";
import { emitTrace } from "../trace.js";
import { deliverDelegationLifecycle } from "../types.js";
import { asThrownError, readMember, thrownText } from "../thrown-value.js";
export function streamSettleBackstop(input) {
const { spec, resume, queue, taskIdRef, entryTracer, runStartedAt, live, runner, sessions, locallyClaimedTokens, parentConstraintRegistry, suspendedEnvReaps } = input;
const onRunRejected = async (err) => {
let code = errorCodeOf(err);
const reopenReason = code === "resume.tool_unavailable" || code === "resume.tool_contract_mismatch" ? "tool_unavailable" : "env_failed";
const reopenable = resume !== undefined && resume.pendingActionStarted !== true && reopenReason !== undefined && !(resumeDecisionWasNegative(resume) && resume.decisionDelivered === true);
let reopenCommitted = false;
let reopenStateUnknown = false;
if (reopenable && resume?.onEnvRestoreFailed) {
try {
await resume.onEnvRestoreFailed(reopenReason);
reopenCommitted = true;
}
catch (reopenErr) {
parentConstraintRegistry.delete(resume.cp.token);
const original = asThrownError(err);
const reopenMsg = thrownText(reopenErr);
const definitive = errorCodeOf(reopenErr) === "checkpoint.reopen_failed";
reopenStateUnknown = !definitive;
err = Object.assign(new Error(definitive
? `${reopenMsg} (original resume failure: ${original.message})`
: `checkpoint reopen threw mid-flight — state UNKNOWN, confirm via the checkpoint store before retrying: ${reopenMsg} (original resume failure: ${original.message})`, { cause: original }), { code: "checkpoint.reopen_failed" });
code = "checkpoint.reopen_failed";
}
}
if (resume)
locallyClaimedTokens.delete(resume.cp.token);
if (resume && !reopenCommitted) {
parentConstraintRegistry.delete(resume.cp.token);
await settleTeardownLeg(() => sessions.unpin?.(resume.cp.sessionId), "sessions.unpin (resume-failure leg)", (e) => runner.deps.onError?.(e, { phase: "config", sessionId: resume.cp.sessionId }));
if (!reopenStateUnknown) {
const failedReap = suspendedEnvReaps.get(resume.cp.token);
suspendedEnvReaps.delete(resume.cp.token);
if (failedReap?.env !== undefined && hasDestroy(failedReap.env)) {
const failedEnv = failedReap.env;
await settleTeardownLeg(() => failedEnv.destroy(), "terminal resume-failure env destroy", (e) => runner.deps.onError?.(e, { phase: "config", sessionId: resume.cp.sessionId }));
}
}
}
if (live.resultValue !== undefined) {
try {
runner.deps.onError?.(asThrownError(err), { phase: "config", sessionId: live.resultValue.sessionId });
}
catch {
}
queue.close();
return;
}
const remoteEnvFailure = (() => {
let cur = err;
for (let depth = 0; cur !== null && cur !== undefined && typeof cur === "object" && depth < 8; depth++) {
const note = readMember(cur, "remoteEnvFailure");
if (note !== undefined)
return [note];
cur = readMember(cur, "cause");
}
return undefined;
})();
live.resultValue = {
taskId: taskIdRef.current ?? "unknown",
sessionId: taskIdRef.sessionId ?? "unknown",
...(taskIdRef.runId !== undefined ? { runId: taskIdRef.runId } : {}),
terminal: { kind: "failed", ...(code !== undefined ? { code } : {}), message: thrownText(err) },
result: "",
...(remoteEnvFailure !== undefined ? { remoteEnvFailures: remoteEnvFailure } : {}),
...(taskIdRef.effectiveMemoryScopes !== undefined ? { effectiveMemoryScopes: taskIdRef.effectiveMemoryScopes } : {}),
...(taskIdRef.effectiveReasoning !== undefined ? { effectiveReasoning: taskIdRef.effectiveReasoning } : {}),
...(() => {
const observed = taskIdRef.editedFiles?.();
return observed !== undefined && observed.length > 0 ? { editedFiles: observed } : {};
})(),
...(() => {
const hinted = readMember(err, "retryAfterMs");
return code === "memory.admission_required" && typeof hinted === "number" && Number.isFinite(hinted) && hinted > 0
? { retryAfterMs: hinted }
: {};
})(),
stats: { turns: 0, tokens: 0, toolCalls: 0, cachedTokens: 0, costMicroUsd: 0, usageMissing: true },
};
emitTrace(entryTracer.tracer, () => ({
kind: "task.end",
version: 1,
taskId: taskIdRef.current ?? "unknown",
...(taskIdRef.runId !== undefined ? { runId: taskIdRef.runId } : {}),
status: "failed",
errorCode: code,
turns: 0,
tokens: 0,
durationMs: Date.now() - runStartedAt,
ts: Date.now(),
}));
const owedTerminal = taskIdRef.delegationTerminalOwed;
if (owedTerminal !== undefined) {
taskIdRef.delegationTerminalOwed = undefined;
deliverDelegationLifecycle(runner.deps.onDelegationLifecycle, { phase: "terminal", identity: owedTerminal, status: "failed", turns: 0, ...(code !== undefined ? { errorCode: code } : {}) }, createSafeNotifier({
onError: (f) => console.warn(`[sema-core] ${f.site}: delegation-lifecycle observer threw (contained; further failures counted, not re-disclosed): ${f.error.message}`),
}), "runtask.onDelegationLifecycle");
}
if (forwardsSubagentEvents(spec))
await drainForwardedFramesBeforeDone();
queue.push({ type: "done", result: live.resultValue });
queue.close();
};
return { onRunRejected };
}