Stately
PackagesAgent

Choosing a run mode

The machine is the artifact. Runners only decide how one host executes its XState effects.

NeedUse
One request/response runrunAgent
Several idle/resume turnsrunAgent in a while loop over result.persist()
Async progress feedrunAgentStream
A long-lived actorprovideExecutors + XState createActor, see Advanced
A custom or durable runtimeThe step API, or createDurable from xstate/durable

Managed run

const result = await runAgent(machine, { input, executors });

if (result.status === "idle") {
  await storage.save(result.persist());
}

runAgent binds Agent request executors and runs an ordinary XState actor until it is done, idle, or errors. It does not own storage, retries, or a durable journal.

Idle/resume loop

let result = await runAgent(machine, { input, executors });

while (result.status === "idle") {
  const snapshot = result.persist();
  await storage.save(snapshot);
  const event = await nextExternalEvent(result.snapshot);
  result = await runAgent(machine, { snapshot, event, executors });
}

The continuation is always the native persisted XState snapshot, so the loop can span processes: persist after one call, resume in another.

Long-lived actor

When your application owns the actor, or the agent machine is a child in a larger XState system, bind the executors with provideExecutors and run a plain createActor. See Advanced.

The portable loop

Any host can run the same artifact with the pure step API. A step is the snapshot plus the model requests the machine is waiting on. Nothing executes until the host decides how:

let step = initialAgentStep(machine, input);

while (!step.done) {
  const [request] = step.requests;
  if (!request) break; // idle: waiting on an external event
  if (request.kind === "decision") {
    const event = await resolveDecision(request, executors, { canTake: (e) => step.snapshot.can(e) });
    step = transitionAgentStep(machine, step, event);
  } else {
    const { result, messages } = await executeAgentRequest(request, executors);
    step = resolveAgentStep(machine, step, request, { result, messages });
  }
}

return step.snapshot.output;

See The step API.

portable-xstate-loop expands this sketch into a runnable createDurable host. Its extra mailbox and wake-up plumbing is host implementation, while the Agent machine artifact stays unchanged.

A durable host should use XState's createDurable. Its adapter owns persistence, retries, messaging, timers, and child execution. Stately Agent does not wrap those framework responsibilities.

On this page