quickstart.md
July 16, 2026 ยท View on GitHub
Installation
npm install @statelyai/agent xstate ai @ai-sdk/openai zod
xstateis a required peer dependency.ai(the Vercel AI SDK) is optional: only needed for the shipped adapter,createAiSdkExecutors. Core has no runtime dependency besidesxstate.@ai-sdk/openaiandzodare used in the examples below.
Describe your models and schemas
Declare a models registry and the machine's schemas. Model keys remain explicit in requests, while the AI SDK host resolves them to provider models.
import { z } from "zod";
import { openai } from "@ai-sdk/openai";
import { defineModels } from "@statelyai/agent/ai-sdk";
// Model ids here are placeholders; use any model your provider offers.
const models = defineModels({ quick: openai("gpt-5.4-mini") });
const answerSchema = z.object({ answer: z.string() });
const contextSchema = z.object({ prompt: z.string(), answer: z.string().nullable() });
const inputSchema = z.object({ prompt: z.string() });
Set up the agent with a request
setupAgent takes your models, schema fields, and requests, and returns a setup (not a running agent) that you author machines from, just like XState's setup(). A text request is a typed model call: it names a model, declares its own input and output schemas, and builds a prompt from its input.
import { setupAgent } from "@statelyai/agent";
const agentSetup = setupAgent({
models,
context: contextSchema,
input: inputSchema,
output: answerSchema,
requests: {
answerQuestion: {
schemas: { input: z.object({ prompt: z.string() }), output: answerSchema },
model: "quick",
prompt: ({ input }) => input.prompt,
},
},
});
The model value is a key into the models registry, so a typo is a compile error. For a machine that must not name concrete models, use string refs the host resolves at run time. See Which authoring form when.
Author the machine
agentSetup.createMachine builds a typed XState machine. The answering state invokes answerQuestion; its onDone moves to done and writes the answer into context. output is already validated against the request's output schema and typed as { answer: string }, so you read output.answer directly.
const machine = agentSetup.createMachine({
context: ({ input }) => ({ prompt: input.prompt, answer: null }),
initial: "answering",
states: {
answering: {
invoke: {
id: "answer",
src: "answerQuestion",
input: ({ context }) => ({ prompt: context.prompt }),
onDone: ({ output }) => ({
target: "done",
context: { answer: output.answer },
}),
},
},
done: {
type: "final",
output: ({ context }) => ({ answer: context.answer ?? "" }),
},
},
});
The machine now fully describes the agent, but nothing has called a model yet. That is the host's job.
Run it against a host
runAgent from the AI SDK entry point is an explicit AI SDK host. It drives the machine and builds the adapter from the machine's declared models. Core runAgent remains provider-agnostic and requires executors explicitly.
import { runAgent } from "@statelyai/agent/ai-sdk";
const result = await runAgent(machine, {
input: { prompt: "Why state machines?" },
});
Check the result
runAgent settles with a status:
done: the machine reached a final state;result.outputmatches your output schema.idle: the machine is waiting on a human. See Human in the loop.error: something threw.
if (result.status === "done") {
console.log(result.output.answer);
// logs the model's answer to "Why state machines?"
}
Use runAgent when an idle pause is expected and you handle it (human-in-the-loop, resumable flows). For a run that is meant to go straight through to a final state, runAgentToCompletion(machine, options) returns the output directly: it throws AgentIdleError if the machine pauses and rethrows the underlying error otherwise:
import { runAgentToCompletion } from "@statelyai/agent";
import { createAiSdkExecutors } from "@statelyai/agent/ai-sdk";
const output = await runAgentToCompletion(machine, {
input: { prompt: "Why state machines?" },
executors: createAiSdkExecutors({ models }),
});
console.log(output.answer);
Next steps
- Agent machines: authoring states, transitions, and typed context.
- Decisions: let the model choose one of several legal machine events.
- Hosts: model aliases, the AI SDK adapter, and writing your own executors.