@sema-agent/core
Version:
Stateless, task-oriented AI agent core
72 lines (71 loc) • 5.53 kB
TypeScript
/**
* Why a resume could not run its approved action — ONE reading of the failure's code, shared by every
* consumer that has to act on it: the reopen compensation (which {@link ReopenReason} a consumed
* checkpoint returns to pending under) and the parked-resume receipt (the `cause` its caller branches on).
* The answer is read from the failure's CODE — a thrown value's `cause` chain, or a failed result's
* terminal code — never from its sentence; a code this table does not name reads as ABSENT (not known),
* which each consumer answers in its own documented way rather than with a guessed cause.
*
* · `environment` — the leg's infrastructure failed (the workspace restore, an abort): the decision is
* untouched, and a retry replays it;
* · `session_gone` — the resumed agent's transcript session is missing;
* · `transcript_corrupt` — the resumed agent's transcript session is THERE but cannot be read as a session: its log
* has no header its store wrote (`corrupt_session`), or its entry tree is structurally unusable — a leaf or parent
* entry that is not in the log (`invalid_session`). Distinct from `session_gone`: the bytes exist, so deleting or
* restoring the transcript is the remedy, not re-creating a session;
* · `tool_unavailable` — the approved tool is not available to the resumed leg (gone, replaced by a
* different contract, or an inherited tool the drive cannot hand over): this approval cannot run, and a
* fresh decision resolves it;
* · `configuration` — the deployment's configuration refuses the resumed leg (a `config.*` door, the
* pre-claim configuration screen, a re-supplied constraint chain that is missing or does not match its
* installation record): a retry under the same configuration fails the same way;
* · `decision_rejected` — the supplied decision does not fit the checkpoint (another gate's answer, an
* unsafe payload, an input the constraints refuse): correct the decision and resubmit.
*/
import type { AssertAllKeysHandled } from "./ask-origin.js";
/**
* design/80 D-1: why a consumed checkpoint was {@link import("./checkpoint-store.js").CheckpointStore.reopen | reopened}
* (resolved → pending). The reason drives re-resume validation (§3 invariant #1): an `env_failed` reopen is a SYSTEM
* RETRY of the ALREADY-APPROVED action — the re-resume MUST replay the persisted
* {@link import("./checkpoint-store.js").ResolvedOutcome} winner, never a new vote — while a `tool_unavailable` reopen
* (the action could not run, may now be invalid — P-7) lets a human RE-DECIDE with the tool present, so a fresh
* operator decision IS allowed.
*
* `constraint_rejected` (F-012 L3) carries the same FRESH-REDECISION semantics as `tool_unavailable`:
* a resolve was retracted because its decided INPUT failed a constraint re-adjudication (a frozen
* ancestor projection / resume-edit policy denied the approver's edit) — the ask itself is unconsumed,
* so the returned-to-pending row takes a fresh operator decision, never a forced replay of the
* rejected one. Core's own edit re-adjudication runs PRE-CAS (nothing to reopen there); this reason
* exists for a deployment lane that discovers the same rejection only after its own resolve landed
* and must return the row to pending without inventing an out-of-vocabulary reason.
*
* `config_refused` carries the same FRESH-REDECISION semantics: the deployment's configuration refused
* the resumed leg before its approved action started, so a retry under the same configuration fails the
* same way — it is not a system retry, and the row takes a fresh decision (or the same one again once the
* configuration is corrected). Which reason a failure reopens under is {@link reopenReasonOf}'s answer.
*/
export declare const REOPEN_REASONS: readonly ["env_failed", "tool_unavailable", "constraint_rejected", "config_refused"];
export type ReopenReason = (typeof REOPEN_REASONS)[number];
export declare const RESUME_STARTUP_CAUSES: readonly ["environment", "session_gone", "transcript_corrupt", "tool_unavailable", "configuration", "decision_rejected"];
export type ResumeStartupCause = (typeof RESUME_STARTUP_CAUSES)[number];
/** The cause a resume failure's code names; `undefined` when the code is absent or the table does not
* name it. Every `config.*` code is a configuration door's refusal. */
export declare function resumeStartupCauseOf(code: string | undefined): ResumeStartupCause | undefined;
declare const REOPEN_REASON_OF_CAUSE: {
readonly environment: "env_failed";
readonly session_gone: "env_failed";
readonly transcript_corrupt: "env_failed";
readonly tool_unavailable: "tool_unavailable";
readonly configuration: "config_refused";
readonly decision_rejected: "constraint_rejected";
};
export type ReopenReasonTableCoversEveryCause = AssertAllKeysHandled<Exclude<ResumeStartupCause, keyof typeof REOPEN_REASON_OF_CAUSE>>;
/**
* The reason a consumed checkpoint whose approved action never started returns to pending under. A failure
* whose cause is not known reopens as `env_failed`: the leg went away before the action ran, the human's
* decision is untouched, and the retry replays it.
*/
export declare function reopenReasonOf(cause: ResumeStartupCause | undefined): ReopenReason;
/** What the result of a returned resume leg says after its checkpoint was reopened, per reason. */
export declare function reopenedUnstartedSentence(reason: ReopenReason): string;
export {};