@sema-agent/core
Version:
Stateless, task-oriented AI agent core
33 lines (32 loc) • 2.25 kB
TypeScript
/**
* The prepare-FAILURE rollback stack — the implementation of {@link RollbackStack} (declared beside the
* other prepare contracts in ./contracts.ts, whose JSDoc carries the contract this file keeps).
*
* Why a stack and not a `finally`: prepare acquires resources in sequence (an execution env, MCP
* clients, A2A peers) and every one of them belongs to the RUN once prepare succeeds — the Runner's
* finish/teardown releases them. Only a prepare that THROWS must release what it already took, in
* reverse acquisition order. Today the orchestrator sees those handles because they are hoisted
* `let`s at function scope; a phase module that acquires a handle inside its own body has no such
* hoist, so it registers the cleanup HERE, immediately after the acquisition, and the driver unwinds
* the whole stack from its one catch.
*
* Posture (identical to the teardown leg the catch already uses — {@link settleTeardownLeg}):
* · reverse order, each cleanup exactly once — the entry is removed before it runs, so a second
* `unwindAll` (or a re-entrant one) finds nothing;
* · no cleanup can stop another — a throw is routed to `report`, a hang is BOUNDED and reported as a
* `TeardownLegTimeoutError` naming the leg; the unwind proceeds either way;
* · `unwindAll` NEVER throws — it runs inside the driver's catch, where a throw would replace the
* prepare error the caller is owed.
*
* States: `armed` (accepting pushes) → `committed` (prepare succeeded; the stack is emptied and
* ownership has passed to `Prepared`) or → `unwinding`/`unwound` (the failure path ran). A `push`
* outside `armed` is a PROGRAMMING error and is refused loudly: a resource acquired after commit
* would have no owner on the failure path, and one pushed during an unwind would never run.
*/
import type { RollbackStack } from "./contracts.js";
/**
* Mint one stack per prepare. `report` is the incident channel for a cleanup that throws or times out
* (wire it to `deps.onError`); with none, failures of the failure path are dropped — the same
* contract `settleTeardownLeg` states for its own `report`.
*/
export declare function createRollbackStack(report?: (err: Error) => void): RollbackStack;