A typed wait: the agent names a reference it already holds, the tool waits (polling, if it must, where the agent cannot see it) until something happens or the time limit passes, and returns what happened with the cursor that resumes the wait. The agent waits with one call instead of a polling loop of its own.
npx shadcn@latest add ourostack/ouro-ui/ax-wait#v1.3.10It installs lib/ouro/ax/wait.ts, with ax-exit-codes, ax-outcome. Its tests are ax-wait-tests. Every item runs on Node 22.18 or later as it is copied: the files import each other as ./<file>.ts. The Ouro AX guide shows how they fit together.
Exports
AxEvent
One thing that happened, with the cursor that resumes after it.
interface AxEvent {
cursor: string;
type: string;
at: string;
by: string;
target: AxRef | null;
summary: string;
data?: Record<string, unknown>;
}DEFAULT_WAIT_EXITS
The default: a satisfied or open wait exits ok; a wait that timed out or can no longer happen exits error.
const DEFAULT_WAIT_EXITS: WaitExitsformatDuration
Milliseconds as the shortest exact duration parseDuration reads back: "2m", "90s", "500ms".
function formatDuration(ms: number): stringFresh
How current the source is, so an agent can tell "nothing happened" from "nothing was seen".
interface Fresh {
state: string;
asOf: string | null;
}isWait
Whether a value is a wait of this version (its shape only).
function isWait(v: unknown): v is WaitparseDuration
"90s", "2m", "1h", "500ms" or a bare number of seconds, as milliseconds; null when it is none of these.
function parseDuration(text: string): number | nullvalidateWait
Checks a wait: one that can go on names how to resume it, and a satisfied one carries what happened.
function validateWait(v: unknown): Validationwait
Builds a wait; a timed-out or waiting wait needs resume, which validateWait checks.
function wait(fields: WaitFields): WaitWait
The envelope a wait returns.
interface Wait {
ax: typeof WAIT_VERSION;
for: string;
target: AxRef | null;
state: WaitState;
since: string;
until: string | null;
cursor: string | null;
events: AxEvent[];
fresh: Fresh | null;
resume: NextStep | null;
reason: string | null;
callback: string | null;
next: NextStep[];
}WAIT_FLAGS
The flags a wait command takes, shaped as ax-command flags: how long to wait and where to resume from. Spread them into a command's flags.
const WAIT_FLAGS: Readonly<{ readonly timeout: { readonly type: "string"; readonly placeholder: "<duration>"; readonly description: "How long to wait, such as \"90s\" or \"5m\"; then it exits with a resume command."; }; readonly cursor: { readonly type: "string"; readonly placeholder: "<cursor>"; readonly descript...WAIT_STATES
How a wait ended.
satisfied: it happened;eventsholds what happened.waiting: still waiting (a stream's first line); keep reading or resume.timed-out: nothing happened in time;resumewaits again from the same cursor.gone: what was awaited cannot happen any more (deleted, left, closed).
const WAIT_STATES: readonly ["satisfied", "waiting", "timed-out", "gone"]WAIT_VERSION
A typed wait: the agent names a reference it already holds, the tool waits (polling, if it must, where the agent cannot see it) until something happens or the time limit passes, and returns what happened with the cursor that resumes the wait. The agent waits with one call instead of a polling loop of its own.
const WAIT_VERSION: "wait/1"waitExit
The exit code a wait gives, by its state's name in the tool's table.
function waitExit(w: Wait, exits: ExitTable, names?: Readonly<Record<"gone" | "satisfied" | "waiting" | "timed-out", string>>): numberWaitExits
Exit code names by wait state, in the tool's table.
type WaitExits = Readonly<Record<WaitState, string>>;WaitFields
What wait takes.
type WaitFields = Pick<Wait, "for" | "state" | "since"> & Partial<Omit<Wait, "ax" | "for" | "state" | "since">>;waitFor
Waits on a reference until a matching event, a time limit or the target is gone, reading the source as often as intervalMs allows, and returns the typed wait. Inside the tool, so the agent makes one call instead of a loop.
function waitFor(options: WaitForOptions): Promise<Wait>WaitForOptions
What waitFor takes.
interface WaitForOptions {
for: string;
target: AxRef | null;
cursor?: string | null;
timeoutMs: number;
read(cursor: string | null): Promise<WaitRead>;
match?(event: AxEvent): boolean;
resume(cursor: string | null): NextStep;
next?(events: readonly AxEvent[]): NextStep[];
callback?: string | null;
intervalMs?: number;
now?(): number;
sleep?(ms: number): Promise<void>;
signal?: AbortSignal;
}WaitRead
What one read of the source returns: the events after the cursor, the new cursor, freshness, and whether the target is gone.
interface WaitRead {
events: AxEvent[];
cursor: string | null;
fresh?: Fresh | null;
gone?: string | null;
}WaitState
type WaitState = (typeof WAIT_STATES)[number];waitText
The wait as text: what happened (one line per event), or that nothing did, then how to resume.
function waitText(w: Wait): string