@sema-agent/core
Version:
Stateless, task-oriented AI agent core
47 lines (46 loc) • 3.36 kB
TypeScript
import type { PausedCause, TaskResult, TerminalCause } from "../core/types.js";
/**
* design/45 §11 Q6 — the **durable-suspend hard boundary** (v1). A `paused` terminal is only safe to
* handle at the **top-level `runTask`** boundary: the orchestrators (cascade / verify / repair-loop)
* run their work as *nested* `runTask`s, and none of them can drive a resume from the inside. If a nested
* task pauses on a durable gate, the orchestrator must **fail fast** — not silently treat it as an
* ordinary failure (which would escalate/re-run side effects) and not release its pinned session (which
* would orphan the checkpoint). It maps `paused → failed` with the code `"unexpected.suspended"` (an
* approval / resource pause) or `"unexpected.needs_review"` (a review pause) and **carries the pause's own
* cause on the failed terminal's `nestedPause` seat** so the top-level caller can still resume.
*
* The structural prevention is upstream — an orchestrator should run nested tasks under a **non-durable**
* approval policy (e.g. the verifier already forces `handsReadOnly` + headless auto-deny, DESIGN#5) so a
* suspension can't arise. This mapping is the defense-in-depth the council made a must-fix: "write it as
* a hard boundary, or a deployment wires durable-suspend into verify and produces silent errors."
*/
export declare const UNEXPECTED_SUSPENDED = "unexpected.suspended";
/** design/80 D-B: the review durable-pause family (dry-run `needs_review` AND `plan_review`) hits the SAME
* nested hard boundary as an approval pause — a distinct code so a caller can tell a review pause from an
* approval. */
export declare const UNEXPECTED_NEEDS_REVIEW = "unexpected.needs_review";
/**
* design/80 D-B: the durable-pause hard boundary covers EVERY `paused` cause — an approval gate, a resource
* slice, a dry-run review, a `plan_review` plan-gate. All of them persist a checkpoint + PIN their session,
* and a nested orchestrator can't drive their resume — so it must surface the pause and NOT release the
* pinned session (releasing it orphans the checkpoint). A type guard, so the caller reads the token/gate
* off the narrowed cause.
*/
export declare function isDurablePause(terminal: TerminalCause): terminal is PausedCause;
/** A result whose terminal is known to be a pause — what {@link isDurablePause} narrows a result's
* `terminal` to, spelled as a type so an orchestrator can HOLD a paused result without re-checking. */
export type PausedResult = TaskResult & {
terminal: PausedCause;
};
/**
* Which family a pause belongs to — its gate kind's registry row: `"suspended"` (an approval gate, a
* resource slice, a platform park) or `"needs_review"` (a dry-run or plan review). The same row the
* status word is projected from; read here by the orchestrators that name the family in their own faces.
*/
export declare function pauseFamily(t: PausedCause): "suspended" | "needs_review";
/**
* If `result` durably paused, return it mapped to a `failed` result whose terminal carries the pause on
* `nestedPause`; otherwise return it unchanged. The orchestrator should also **stop** (not escalate/re-run)
* and **not release** the session when this maps a pause — the checkpoint still references that session.
*/
export declare function mapNestedSuspend(result: TaskResult): TaskResult;