UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

65 lines (64 loc) • 2.53 kB
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 }; } }