UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

84 lines (83 loc) • 2.74 kB
export const DEFAULT_MOD_BUDGET_MS = 10_000; export const CATCH_BUDGET_MS = 1_000; export const RUNAWAY_AFTER_MS = 5_000; export const POST_ABORT_GRACE_MS = 1_000; export const MAX_TIMER_MS = 2_147_483_647; export function resolveModBudgetMs(supplied, report, name) { if (supplied === undefined) return DEFAULT_MOD_BUDGET_MS; if (typeof supplied === "number" && Number.isFinite(supplied) && supplied >= 0 && supplied <= MAX_TIMER_MS) return supplied; const got = typeof supplied === "number" ? String(supplied) : typeof supplied; report(new Error(`${name}: budgetMs must be a non-negative finite number no greater than ${MAX_TIMER_MS} (got ${got}) — ` + `every handler of this registration falls back to the ${DEFAULT_MOD_BUDGET_MS}ms default`)); return DEFAULT_MOD_BUDGET_MS; } export function createSelfBudget(ms, onExpire) { let remaining = ms; let runningSince; let timer; let pauses = 0; let done = false; let expired = false; let fire = () => { }; const expiredP = new Promise((res) => (fire = res)); const left = () => (runningSince === undefined ? remaining : Math.max(0, remaining - (Date.now() - runningSince))); const arm = () => { runningSince = Date.now(); timer = setTimeout(() => { if (done) return; expired = true; done = true; remaining = 0; runningSince = undefined; fire("expired"); onExpire(); }, remaining); }; arm(); return { expired: expiredP, isExpired: () => expired, pause() { if (pauses++ !== 0 || done) return; clearTimeout(timer); remaining = left(); runningSince = undefined; }, resume() { if (pauses === 0) return; if (--pauses !== 0 || done) return; arm(); }, clear() { if (done) return; remaining = left(); runningSince = undefined; done = true; clearTimeout(timer); }, usedMs: () => ms - left(), reading: () => Object.freeze({ ms, remainingMs: left() }), }; } export function watchRunaway(settled, onRunaway) { let over = false; const mark = () => { over = true; }; settled.then(mark, mark); unrefTimer(setTimeout(() => { if (!over) onRunaway(); }, RUNAWAY_AFTER_MS)); } export function unrefTimer(timer) { if (typeof timer === "object" && timer !== null && "unref" in timer && typeof timer.unref === "function") timer.unref(); }