Skip to main content

Ouro AX

ax-wait

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.10

It 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: WaitExits

formatDuration

Milliseconds as the shortest exact duration parseDuration reads back: "2m", "90s", "500ms".

function formatDuration(ms: number): string

Fresh

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 Wait

parseDuration

"90s", "2m", "1h", "500ms" or a bare number of seconds, as milliseconds; null when it is none of these.

function parseDuration(text: string): number | null

validateWait

Checks a wait: one that can go on names how to resume it, and a satisfied one carries what happened.

function validateWait(v: unknown): Validation

wait

Builds a wait; a timed-out or waiting wait needs resume, which validateWait checks.

function wait(fields: WaitFields): Wait

Wait

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; events holds what happened.
  • waiting: still waiting (a stream's first line); keep reading or resume.
  • timed-out: nothing happened in time; resume waits 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>>): number

WaitExits

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