@sema-agent/core
Version:
Stateless, task-oriented AI agent core
280 lines (279 loc) • 14.2 kB
JavaScript
import { isDurablePause, pauseFamily } from "./suspend-guard.js";
import { delimitUntrusted, sanitizeUntrustedText } from "../core/untrusted-text.js";
import { assertOracleIsolation } from "../core/oracle-isolation.js";
import { buildCumulativeStats } from "./cumulative-stats.js";
export function isolationPermitsAutoAccept(verdict) {
return verdict.protected && verdict.isolationClass === "out_of_process";
}
export function repairBundleFromCheckpoint(cp) {
return cp.state.repairBundle;
}
export function terminalForTier(oracle) {
if (oracle.tier === "none")
return "needs_human_oracle";
if (oracle.passed && !oracle.flaky) {
return "candidate_only";
}
return undefined;
}
function repairObjective(bundle) {
const diag = bundle.diagnostics.length
? bundle.diagnostics.map((d) => `- ${sanitizeUntrustedText(d)}`).join("\n")
: "(no prior diagnoses)";
return (`The oracle REJECTED the previous attempt. Diagnose and fix the underlying cause, then stop — do not ` +
`add anything else, and do NOT edit or weaken the oracle/tests to make them pass. If the spec and the ` +
`oracle genuinely conflict, say so explicitly rather than satisfying the test.\n\n` +
`## Prior diagnoses\n${diag}\n\n` +
`## Oracle failure trace (untrusted)\n${delimitUntrusted("ORACLE TRACE", bundle.failureTrace || "(no trace)")}`);
}
function freshBundle() {
return { failureTrace: "", diagnostics: [], rejectedHypotheses: [], attemptCount: 0, oracleTier: "none" };
}
function outcomeFor(terminal, oracle, rounds) {
const passed = terminal === "candidate_only" || terminal === "fixed";
return {
verdict: passed ? "PASS" : terminal === "needs_human_oracle" ? "unverified" : "FAIL",
...(passed ? {} : terminal === "needs_human_oracle" ? { unverifiedReason: "no_verdict" } : {}),
rounds,
findings: oracle?.trace ? [sanitizeUntrustedText(oracle.trace)] : [],
};
}
export async function runRepairLoop(runner, implSpec, config) {
if (config.workerEnv === undefined && config.immutableOraclePaths === undefined) {
config.onWarn?.(new Error("repair-loop §5.1: graderEnv was supplied but workerEnv is undefined — the grader/worker env identity " +
"check is SKIPPED. Pass config.workerEnv (the env runner.runTask runs the impl in) so an accidental " +
"shared-env misconfiguration is caught; omit it only when the envs provably cannot collide."));
}
const unprotectedResult = (reason, isolationClass) => {
const oracle = { tier: "none", passed: false, flaky: false, retries: 0 };
return {
taskId: implSpec.taskId ?? "",
result: `oracle isolation check failed: ${reason}`,
terminal: { kind: "failed", code: "oracle.unprotected", message: `oracle isolation check failed: ${reason}` },
sessionId: "",
stats: { tokens: 0, turns: 0, costMicroUsd: 0 },
repairTerminal: "oracle.unprotected",
...(isolationClass ? { isolationClass } : {}),
bundle: { ...freshBundle(), attemptCount: config.resumeBundle?.attemptCount ?? 0 },
oracleCostMicroUsd: 0,
verification: outcomeFor("oracle.unprotected", oracle, 0),
};
};
let isolationClass;
if (config.immutableOraclePaths !== undefined && config.workerEnv === undefined) {
return unprotectedResult("immutableOraclePaths requested the structural isolation assertion but workerEnv is undefined — cannot run it (fail-closed)");
}
if (config.immutableOraclePaths !== undefined && config.workerEnv !== undefined) {
const grader = {
env: config.graderEnv,
immutableOraclePaths: config.immutableOraclePaths,
provenance: "control_plane",
};
const verdict = await assertOracleIsolation(config.workerEnv, grader);
isolationClass = verdict.isolationClass;
if (!verdict.protected) {
return unprotectedResult(verdict.reason ?? "grader env failed the structural isolation assertion", isolationClass);
}
}
else if (config.workerEnv !== undefined && config.workerEnv === config.graderEnv) {
return unprotectedResult("graderEnv must not be the worker env");
}
const maxAttempts = Number.isFinite(config.maxAttempts) ? Math.max(1, Math.floor(config.maxAttempts)) : 1;
if (!Number.isFinite(config.maxAttempts)) {
config.onWarn?.(new Error(`repair-loop: maxAttempts must be a finite number (got ${config.maxAttempts}) — falling back to 1 attempt`));
}
const bundle = config.resumeBundle
? { ...config.resumeBundle, diagnostics: [...config.resumeBundle.diagnostics], rejectedHypotheses: [...config.resumeBundle.rejectedHypotheses] }
: freshBundle();
const startedAt = Date.now();
const seededSpend = config.resumeBundle?.spentMicroUsd;
const seededActiveMs = config.resumeBundle?.activeElapsedMs;
const priorActiveMs = typeof seededActiveMs === "number" && Number.isFinite(seededActiveMs) ? Math.max(0, seededActiveMs) : 0;
let spend = typeof seededSpend === "number" && Number.isFinite(seededSpend) ? Math.max(0, seededSpend) : 0;
const stampAccount = () => {
bundle.spentMicroUsd = spend;
bundle.activeElapsedMs = priorActiveMs + (Date.now() - startedAt);
};
let lastResult;
let lastOracle;
let ownTokens = 0, ownTurns = 0, ownPrompt = 0, ownTotalInput = 0, ownCached = 0, ownOutput = 0;
let ownCacheWrite = 0, ownCacheWriteLong = 0, ownCostMicro = 0;
let ownLlmRootMicro = 0, ownCompactionMicro = 0;
let ownSideCallMicro;
let anyAttemptUnpriced = false;
let nestedTokens = 0, nestedTurns = 0, nestedTasks = 0, nestedCostMicro = 0;
let hrCount = 0, hrWaitMs = 0;
const hrGates = [];
let oracleCostMicroUsd = 0;
const accumulate = (s) => {
ownTokens += s.tokens;
ownTurns += s.turns;
ownPrompt += s.promptTokens ?? 0;
ownTotalInput += s.totalInputTokens ?? 0;
ownCached += s.cachedTokens ?? 0;
ownOutput += s.outputTokens ?? 0;
ownCacheWrite += s.cacheWriteTokens ?? 0;
ownCacheWriteLong += s.cacheWriteTokensLong ?? 0;
ownCostMicro += s.costMicroUsd ?? 0;
if (s.costMicroUsd === undefined)
anyAttemptUnpriced = true;
if (s.costBreakdown) {
ownLlmRootMicro += s.costBreakdown.llmRootMicroUsd;
ownCompactionMicro += s.costBreakdown.compactionMicroUsd;
if (s.costBreakdown.sideCallMicroUsd !== undefined)
ownSideCallMicro = (ownSideCallMicro ?? 0) + s.costBreakdown.sideCallMicroUsd;
}
if (s.humanReview) {
hrCount += s.humanReview.count;
hrWaitMs += s.humanReview.totalWaitMs;
hrGates.push(...s.humanReview.gates);
}
if (s.nested) {
nestedTokens += s.nested.tokens;
nestedTurns += s.nested.turns;
nestedTasks += s.nested.tasks;
nestedCostMicro += s.nested.costMicroUsd ?? 0;
}
};
const cumulativeStats = (base) => buildCumulativeStats(base, {
tokens: ownTokens,
turns: ownTurns,
promptTokens: ownPrompt,
totalInputTokens: ownTotalInput,
cachedTokens: ownCached,
outputTokens: ownOutput,
cacheWriteTokens: ownCacheWrite,
cacheWriteTokensLong: ownCacheWriteLong,
costMicroUsd: ownCostMicro,
anyLegUnpriced: anyAttemptUnpriced,
llmRootMicroUsd: ownLlmRootMicro,
compactionMicroUsd: ownCompactionMicro,
...(ownSideCallMicro !== undefined ? { sideCallMicroUsd: ownSideCallMicro } : {}),
nested: { tokens: nestedTokens, turns: nestedTurns, tasks: nestedTasks, costMicroUsd: nestedCostMicro },
humanReview: { count: hrCount, totalWaitMs: hrWaitMs, gates: hrGates },
});
let restartedOnce = false;
let restartUsed = false;
const cleanRestartSpec = () => {
const { sessionId: _drop, ...rest } = implSpec;
return { ...rest, objective: `${implSpec.objective}\n\n${repairObjective(bundle)}` };
};
const exhaustedBeforeDispatch = (message, errorCode) => ({
taskId: implSpec.taskId ?? "",
result: message ?? `repair loop: attempt budget already spent (attemptCount ${bundle.attemptCount} >= maxAttempts ${maxAttempts}) — no attempt dispatched`,
terminal: { kind: "failed", code: errorCode ?? "repair.attempts_exhausted", message: message ?? `repair loop: attempt budget already spent (attemptCount ${bundle.attemptCount} >= maxAttempts ${maxAttempts}) — no attempt dispatched` },
sessionId: implSpec.sessionId ?? "",
stats: { tokens: 0, turns: 0, costMicroUsd: 0 },
repairTerminal: "gave_up",
bundle,
...(isolationClass ? { isolationClass } : {}),
oracleCostMicroUsd,
verification: outcomeFor("gave_up", undefined, bundle.attemptCount),
});
while (true) {
if (!restartedOnce && bundle.attemptCount >= maxAttempts)
return exhaustedBeforeDispatch();
if (config.costCeilingMicroUsd != null && spend >= config.costCeilingMicroUsd) {
return exhaustedBeforeDispatch(`repair loop: cost ceiling already spent (carried ${spend} >= ceiling ${config.costCeilingMicroUsd} micro-USD) — no attempt dispatched`, "repair.budget_exhausted");
}
if (config.totalTimeoutMs != null && priorActiveMs + (Date.now() - startedAt) >= config.totalTimeoutMs) {
return exhaustedBeforeDispatch(`repair loop: active time budget already spent (carried ${priorActiveMs + (Date.now() - startedAt)}ms >= ${config.totalTimeoutMs}ms) — no attempt dispatched`, "repair.budget_exhausted");
}
stampAccount();
const isRepair = bundle.attemptCount > 0 && lastResult !== undefined && !restartedOnce;
const isSeededResume = !restartedOnce &&
lastResult === undefined &&
config.resumeBundle !== undefined &&
(bundle.failureTrace.trim() !== "" || bundle.diagnostics.length > 0);
const spec = restartedOnce
? cleanRestartSpec()
: isRepair
? { ...implSpec, sessionId: lastResult.sessionId, objective: repairObjective(bundle) }
: isSeededResume
? {
...implSpec,
objective: implSpec.sessionId ? repairObjective(bundle) : `${implSpec.objective}\n\n${repairObjective(bundle)}`,
}
: implSpec;
restartedOnce = false;
const liveStamp = setInterval(stampAccount, 1_000);
liveStamp.unref?.();
let result;
try {
result = await runner.runTask(spec, { repairBundle: bundle });
}
finally {
clearInterval(liveStamp);
}
spend += (result.stats.costMicroUsd ?? 0) + (result.stats.nested?.costMicroUsd ?? 0);
stampAccount();
accumulate(result.stats);
lastResult = result;
bundle.attemptCount += 1;
if (isDurablePause(result.terminal)) {
return {
...result,
stats: cumulativeStats(result.stats),
repairTerminal: "gave_up",
bundle,
...(isolationClass ? { isolationClass } : {}),
oracleCostMicroUsd,
verification: { verdict: "unverified", unverifiedReason: pauseFamily(result.terminal), rounds: bundle.attemptCount, findings: [] },
};
}
if (result.terminal.kind !== "completed") {
return {
...result,
stats: cumulativeStats(result.stats),
repairTerminal: "gave_up",
bundle,
...(isolationClass ? { isolationClass } : {}),
oracleCostMicroUsd,
verification: { verdict: "unverified", unverifiedReason: "impl_incomplete", rounds: bundle.attemptCount, findings: [] },
};
}
const oracle = await config.oracle(config.graderEnv, result.result);
oracleCostMicroUsd += oracle.costMicroUsd ?? 0;
spend += oracle.costMicroUsd ?? 0;
stampAccount();
lastOracle = oracle;
bundle.oracleTier = oracle.tier;
const projected = terminalForTier(oracle);
config.onAttempt?.({ attempt: bundle.attemptCount, repairTerminal: projected, oracle });
if (projected !== undefined) {
return {
...result,
stats: cumulativeStats(result.stats),
repairTerminal: projected,
bundle,
...(isolationClass ? { isolationClass } : {}),
oracleCostMicroUsd,
verification: outcomeFor(projected, oracle, bundle.attemptCount),
};
}
if (oracle.trace && oracle.trace.trim() !== "") {
bundle.failureTrace = oracle.trace;
if (bundle.diagnostics.length < 3)
bundle.diagnostics.push(oracle.trace);
}
const overTime = config.totalTimeoutMs != null && priorActiveMs + (Date.now() - startedAt) >= config.totalTimeoutMs;
const overCost = config.costCeilingMicroUsd != null && spend >= config.costCeilingMicroUsd;
if (bundle.attemptCount >= maxAttempts || overTime || overCost) {
if (bundle.attemptCount >= maxAttempts && !overTime && !overCost && lastResult !== undefined && !restartUsed) {
restartUsed = true;
restartedOnce = true;
continue;
}
const terminal = "gave_up";
return {
...lastResult,
stats: cumulativeStats(lastResult.stats),
repairTerminal: terminal,
bundle,
...(isolationClass ? { isolationClass } : {}),
oracleCostMicroUsd,
verification: outcomeFor(terminal, lastOracle, bundle.attemptCount),
};
}
}
}