@sema-agent/core
Version:
Stateless, task-oriented AI agent core
65 lines (64 loc) • 2.53 kB
JavaScript
import { traceHookCrash } from "./gate-crash-trace.js";
import { thrownText } from "./thrown-value.js";
export function gateWaitFailureOf(err) {
const mark = err?.gateWait;
return mark === "timeout" || mark === "aborted" ? mark : undefined;
}
function gateWaitError(message, kind) {
const err = new Error(message);
err.gateWait = kind;
return err;
}
export function withGateTimeout(p, ms, signal, label = "reversibilityProbe") {
if (ms === undefined && signal === undefined)
return p;
return new Promise((resolve, reject) => {
let settled = false;
const done = (fn, v) => {
if (settled)
return;
settled = true;
if (timer !== undefined)
clearTimeout(timer);
signal?.removeEventListener("abort", onAbort);
fn(v);
};
const onAbort = () => done(reject, gateWaitError(`${label} aborted (task ended)`, "aborted"));
const timer = ms !== undefined
? setTimeout(() => done(reject, gateWaitError(`${label} timed out after ${ms}ms`, "timeout")), ms)
: undefined;
p.then((v) => done(resolve, v), (err) => done(reject, err));
if (signal?.aborted) {
onAbort();
return;
}
signal?.addEventListener("abort", onAbort);
});
}
export const DEFAULT_GATE_AWAIT_TIMEOUT_MS = 30_000;
export function createGateDeadline(input, notifier) {
let resolved;
return () => {
if (resolved !== undefined)
return resolved;
const supplied = input.approvalTimeoutMs;
if (supplied === undefined)
resolved = DEFAULT_GATE_AWAIT_TIMEOUT_MS;
else if (Number.isFinite(supplied) && supplied >= 0 && supplied <= 2_147_483_647)
resolved = supplied;
else {
resolved = DEFAULT_GATE_AWAIT_TIMEOUT_MS;
traceHookCrash(input, new Error(`approvalTimeoutMs must be a non-negative finite number no greater than 2147483647 (got ${String(supplied)}) — the gate's bounded awaits fall back to the ${DEFAULT_GATE_AWAIT_TIMEOUT_MS}ms default`), notifier);
}
return resolved;
};
}
export async function awaitWriteProtectionJudgment(judged, ms, signal, onFailure) {
try {
return await withGateTimeout(judged, ms, signal, "writeProtectionJudge");
}
catch (err) {
onFailure?.(err);
return { kind: "unresolvable", cause: thrownText(err), unresolvedSymlink: false };
}
}