UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

47 lines (46 loc) • 3.36 kB
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 / teacher / team) * 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;