{"slug": "stately-agent-build-agents-as-state-machines", "title": "Stately Agent: Build agents as state machines", "summary": "Stately released Stately Agent 2, an alpha framework that lets developers build AI agents as state machines using XState, providing explicit control flow that can be inspected, tested, and visualized. The framework separates model decisions from control logic, allowing developers to define agent behavior through states, events, and guards while the model proposes actions within those constraints. Stately Agent 2 is available as an npm package and supports any model provider via executor functions.", "body_md": "**The logic layer for AI agents.**\n\nBuild agents as state machines, with explicit control flow you can inspect, test, visualize, and run anywhere.\n\nStately Agent adds model requests and decisions to XState. The state machine defines what the agent can do. Your application chooses the model, runs the requests, and stores the state.\n\nAny agent workflow or loop can be modeled as a state machine. Model calls and tools run as effects inside it. The model proposes an event. The machine decides whether it is allowed and what happens next.\n\nStately Agent 2 is in alpha. APIs may change before the stable release.\n\n[Documentation](https://stately.ai/docs/agents) · [Examples](/statelyai/agent/blob/next/examples/README.md) · [XState](https://github.com/statelyai/xstate)\n\n```\npnpm add @statelyai/agent@alpha xstate@alpha zod ai @ai-sdk/openai\n```\n\nNode 22.18 or newer is required.\n\nThis agent reviews refund requests. The model may propose an automatic refund, but the state machine owns the $100 limit.\n\n``` js\nimport { openai } from \"@ai-sdk/openai\";\nimport { defineModels, runAgent } from \"@statelyai/agent/ai-sdk\";\nimport { setupAgent } from \"@statelyai/agent\";\nimport { z } from \"zod\";\n\nconst models = defineModels({\n  fast: openai(\"gpt-5.4-mini\"),\n});\n\nconst agent = setupAgent({\n  models,\n  context: z.object({\n    request: z.string(),\n    amount: z.number(),\n  }),\n  input: z.object({\n    request: z.string(),\n    amount: z.number(),\n  }),\n  output: z.object({\n    outcome: z.enum([\"refunded\", \"review\"]),\n  }),\n  events: {\n    AUTO_REFUND: {},\n    REVIEW: z.object({ reason: z.string() }),\n  },\n});\n\nconst refundMachine = agent.createMachine({\n  context: ({ input }) => input,\n  initial: \"deciding\",\n  states: {\n    deciding: {\n      invoke: {\n        src: \"agent.decide\",\n        input: ({ context }) => ({\n          model: \"fast\",\n          system: \"Choose AUTO_REFUND for eligible requests. Otherwise choose REVIEW.\",\n          prompt: `${context.request}\\nAmount: $${context.amount}`,\n          allowedEvents: [\"AUTO_REFUND\", \"REVIEW\"],\n        }),\n      },\n      on: {\n        AUTO_REFUND: ({ context }) => (context.amount <= 100 ? { target: \"refunded\" } : undefined),\n        REVIEW: { target: \"review\" },\n      },\n    },\n    refunded: {\n      type: \"final\",\n      output: () => ({ outcome: \"refunded\" }),\n    },\n    review: {\n      type: \"final\",\n      output: () => ({ outcome: \"review\" }),\n    },\n  },\n});\n\nconst result = await runAgent(refundMachine, {\n  input: {\n    request: \"I was charged twice for the same order.\",\n    amount: 75,\n  },\n});\n\nif (result.status === \"done\") {\n  console.log(result.output);\n}\n```\n\nWhen the machine reaches `refunded`\n\n, the result is:\n\n```\n{ outcome: 'refunded' }\n```\n\nThe model chooses between the events allowed in `deciding`\n\n. The `AUTO_REFUND`\n\ntransition only works when the amount is at most $100. If the model chooses it for a larger amount, the guard rejects the choice and the decision is tried again.\n\nThe example has one model decision and two final outcomes. Real machines can add approval states, retries, parallel work, child agents, and long-running waits without changing how the control flow is represented.\n\n**Machines own control flow.** States, events, transitions, and guards define what can happen.**Models make bounded decisions.**`agent.decide`\n\nasks a model to choose one of the events accepted by the current state.**Requests are typed.** Inputs, outputs, context, and events use Standard Schema. Zod works out of the box.**Your code runs the model.**`runAgent`\n\naccepts executor functions. The example uses the Vercel AI SDK adapter, but the machine does not depend on a provider.**Snapshots can be stored.** An agent can stop for human input, save its XState snapshot, and resume later in another process.**Machines can be checked without model calls.** Lint their structure, simulate scripted decisions, and explore paths without an API key.**Agents are XState machines.** Guards, actors, parallel states, inspection, testing, and visualization work as usual.\n\n[Twenty Questions](/statelyai/agent/blob/next/examples/twenty-questions)shows a model choosing legal events in a loop.[Go Fish](/statelyai/agent/blob/next/examples/go-fish)pits a model against a human while the machine enforces hidden-information game rules.[Human in the loop](/statelyai/agent/blob/next/examples/human-in-the-loop)pauses, stores a snapshot, and resumes after review.[Ticket triage](/statelyai/agent/blob/next/examples/triage)returns structured data from a model request.[JSON agent](/statelyai/agent/blob/next/examples/json-agent)runs a machine defined as data.\n\nSee [all examples](/statelyai/agent/blob/next/examples/README.md).", "url": "https://wpnews.pro/news/stately-agent-build-agents-as-state-machines", "canonical_source": "https://github.com/statelyai/agent", "published_at": "2026-07-18 17:10:51+00:00", "updated_at": "2026-07-18 17:21:11.821791+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools"], "entities": ["Stately", "XState", "Stately Agent", "Vercel AI SDK", "OpenAI", "Zod"], "alternates": {"html": "https://wpnews.pro/news/stately-agent-build-agents-as-state-machines", "markdown": "https://wpnews.pro/news/stately-agent-build-agents-as-state-machines.md", "text": "https://wpnews.pro/news/stately-agent-build-agents-as-state-machines.txt", "jsonld": "https://wpnews.pro/news/stately-agent-build-agents-as-state-machines.jsonld"}}