UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

54 lines (53 loc) • 4.17 kB
import { traceHookCrash } from "./gate-crash-trace.js"; import type { WriteProtectionVerdict } from "./write-protect.js"; /** * design/77 §4: resolve `p`, but REJECT (so the caller catches and fails closed) if it hasn't settled within * `ms` OR the `signal` aborts first (the task timed out / was cancelled — its real deadline). A rejection of * `p` propagates with its true cause. Both `ms` and `signal` undefined ⇒ no deadline (await `p`) — the * helper stays generic; every gate call site supplies a finite `ms` ({@link createGateDeadline}), so the * no-deadline arm is unreachable from the gate. Mirrors `tool-policy.ts withTimeout`, but REJECTS on * timeout (no bounded await here has a safe fallback VALUE — the gate's only safe action on an unsettled * one is its own fail-closed arm). `label` names the wait in the rejection, so the arm that catches it can * say which one elapsed. */ /** WHY a bounded wait ended with no answer, stated by the WAIT rather than read off an error's text: * `timeout` — the bound elapsed; `aborted` — the task ended. Neither mark ⇒ the awaited work's own. */ export type GateWaitFailure = "timeout" | "aborted"; /** The mark above, read back off a rejection. `undefined` ⇒ the awaited work's own rejection. */ export declare function gateWaitFailureOf(err: unknown): GateWaitFailure | undefined; export declare function withGateTimeout<T>(p: Promise<T>, ms: number | undefined, signal?: AbortSignal, label?: string): Promise<T>; /** * The deadline used when the caller supplies no `approvalTimeoutMs`. The wait must be bounded EVERYWHERE: * the engine's own assembly never passes `approvalTimeoutMs`, and its only other bound is the task abort * signal, which a task with no walltime limit and no external cancel never fires — so a host driving the * public `runToolGate` with neither knob had NO bound at all and one hung probe froze the call forever. A * probe is an args inspection and a judgment is a path resolution, not an approval wait: 30s is generous * for any legitimate one, and an elapse simply takes the caller's own fail-closed arm. */ export declare const DEFAULT_GATE_AWAIT_TIMEOUT_MS = 30000; /** * The gate's ONE deadline seat, resolved LAZILY and at most once per gate pass: a pass that makes no * bounded await must not sound about a seat it never read. A garbage value (NaN/Infinity/negative, or * above setTimeout's 2^31-1 ceiling, which it would silently clamp to ~1ms — an instant fail-closed the * deployment never asked for) is refused LOUDLY to the default rather than silently reinterpreted * (bad-value loudness discipline; the same ceiling the approve-wait seat refuses). */ export declare function createGateDeadline(input: { approvalTimeoutMs?: number; }, notifier: Parameters<typeof traceHookCrash>[2]): () => number; /** * The write-protection judge's wait, at both of its call sites — and the ONE minter of the `unresolvable` * verdict. An elapsed or aborted judgment is not "a target the environment could not resolve" (the judge * answers that one itself, by dropping the view that could not contribute and letting the lexical half * stand); it is NO judgment at all — not even the lexical half's answer came back — and there is nothing * for the fold or the approved-edit arm to act on but their own fail-closed arm. A wait that produced * nothing knows nothing about what it was waiting for, which is why `unresolvedSymlink` is `false` here * and not a guess. * * KNOWN, AND NARROWER THAN IT LOOKS: the lexical half is computed synchronously at the top of `judge`, so * a spelling HIT is already on a settled promise before this wait begins and cannot elapse; what this arm * refuses is a spelling MISS whose environment half never came back. Closing even that would mean handing * the deadline INTO the judge so the missing half could be dropped there too — a seat change on a public * type, deliberately not taken here. */ export declare function awaitWriteProtectionJudgment(judged: Promise<WriteProtectionVerdict>, ms: number, signal?: AbortSignal, onFailure?: (err: unknown) => void): Promise<WriteProtectionVerdict>;