A complete agent, built on Restate. Every feature a modern agent needs is here as a small module you can read in one sitting, and Restate keeps each turn running through crashes and days-long waits.
agent-demo.mp4
A real session: the model writes a program whose web searches run at once, you steer it and approve its file writes, it hands work to four sub-agents, and then the service is killed mid-turn and the turn still finishes.
Features · One turn, start to finish · How a turn works · Quickstart · Documentation
| Parallel tool calls Every call in a model response runs at once; a failure goes back to the model. |
Background operations Timers and approvals run on while the model works. It can wait or cancel. |
| Steering and interrupts Redirect or stop a turn while it runs, without losing finished work. |
Sub-agents Delegate tasks to agents with their own history, sandbox and memory. |
| Guardrails Plain-language rules. A policy model allows, blocks or asks a person. |
Human approval A turn can wait days for a decision, holding no process. |
| Programmatic tool calls The model writes a small program; only its result enters the context. |
Compaction Long conversations and long turns are summarized, recent steps kept verbatim. |
| Schedules Messages to the agent later, once or on a recurrence. No cron. |
Memory A searchable index, so context does not grow with the memories. |
| Tool search MCP and discovered tools load on demand, keeping large catalogs out of context. |
Sandboxes A local directory or Modal sandbox for files and commands. |
| Extensible tools One module per tool, plus MCP servers and Restate handlers. |
Output recovery A truncated response gets one retry with a bigger output budget. |
Here is one turn, from the first message to the answer, and what Restate does for it along the way.
The model asks for three tools, the guardrails check them once, and they run together. Each result is recorded as it lands, and a call that fails goes back to the model as an error.
A new message does not have to wait for the turn to end. A steer reaches the next model step without cancelling tools in flight, and an interrupt stops the turn with a summary of what it did.
When a guardrail needs a person, the turn suspends: no process, only stored state. It can wait a day, through new versions of the service, and resumes where it stopped.
Every model call and tool result is in the turn's journal. If the process dies, Restate replays the journal: nothing is asked or run twice, and the turn finishes.
Every feature above gets the same guarantees, because they come from Restate rather than from each feature:
- A crash resumes the turn. Restate replays the turn's journal. Recorded model responses and tool results are reused, so the model is never asked to repeat a decision and completed tool calls are not re-run.
- New versions don't break running turns. Restate keeps each turn on the service version it started on; new turns use the new version.
- Waiting is free. A turn can wait hours or days for an approval, a timer or a sub-agent. While it waits it holds no process, only stored state.
- Always responsive.
ask,steerandinterruptreturn right away, even while a turn runs for minutes. - Nothing else to operate. State, messages, timers and notifications all live in Restate: no database, queue or scheduler of the agent's own. Each agent's state has a single owner, so there are no locks. The service is stateless: it scales out, or builds into a single bundle for serverless.
What replay does not do: make external side effects exactly-once. A crash between an MCP call completing and its result being recorded can repeat that call.
Each agent is two Restate Virtual Objects with the same key:
Agent, the controller. It decides what happens to each incoming message and owns the profile: instructions, guardrails, memories, tool grants, approvals, schedules and child agents. Its handlers are short, so it always answers.AgentSession, the turn. OnedoTurninvocation is one turn. It owns the append-only conversation log and runs the model/tool loop.
sequenceDiagram
autonumber
participant C as Client
participant A as Agent (controller)
participant S as AgentSession (turn)
participant M as Model, guardrails, tools
C->>A: ask("Weather in Berlin?")
A-)S: doTurn(profile snapshot), one way
A-->>C: started, turnId
S->>S: append to log, build context
S->>M: model step
M-->>S: proposal: call 3 tools
S->>M: guardrail check
par tool calls run concurrently
S->>M: getWeather
and
S->>M: webSearch
and
S->>M: runCommand
end
C->>A: steer("Use Fahrenheit")
A-)S: steering signal, addressed to turnId
Note over S: A crash anywhere here is harmless. Restate replays the journal and reuses every recorded result.
S->>M: model step, with tool results and steering
M-->>S: final answer
S-)A: onTurnEnd(outcome)
Note over A: Retire the turn. Start the next one if messages were queued.
C->>A: watch(afterRevision), long poll
A-->>C: history changed
C->>S: history(fromSequence)
S-->>C: new entries
The controller keeps track of the currently executing turn. steer,
interrupt and approval decisions reach the turn as durable signals
addressed to its invocation ID, the turnId, so they never land in the
wrong turn.
doTurn runs the model calls and tools itself, as in-process function calls.
Each result is appended to the turn's journal over one open, low-latency
stream to Restate. That append is the only persistence a step needs.
- Architecture: state owners, one request, notifications
- Protocol: every handler, ordering rules, clients
- Turn runtime: steps, guardrails, pending work, recovery
- Tools: built-ins, programmatic tool calls, dynamic tools, MCP
- Schedules and sandboxes
- Configuration: models, tools, environment variables, MCP servers and the reference UI
- Development: tests, debugging, packaging and the repository layout; PROJECT.md gives a file-by-file reading order
- Agent guide: read before changing runtime semantics
- AG-UI: connect AG-UI frontends such as CopilotKit
The documentation index has the full list.
plugins/restate-agent has two skills:
restate-agent: how to extend this agent. It covers tools, handlers, configuration and testing, and how to grow the agent into a full application with users, sessions and credentials.restate-gen-sdk: how to write the generator-SDK code the agent is built from.
The plugin bundles both skills and the Restate docs MCP server. Codex and Claude Code share the same skill files and MCP configuration.
For Codex, install the plugin from a terminal:
codex plugin marketplace add restatedev/agent
codex plugin add restate-agent@restate-agentStart a new Codex chat after installation. Opening the repository alone does
not enable the plugin. To install from a local checkout, run
codex plugin marketplace add . from the repository root instead of the
first command above. Codex supports the existing
marketplace catalog and uses the
Codex manifest to load the
skills and MCP server.
Claude Code offers to install the plugin when you open this repository. You can also install it by hand:
/plugin marketplace add restatedev/agent
/plugin install restate-agent@restate-agentFor other coding agents, install just the skills with
npx skills add restatedev/agent. That command does not configure the
Restate docs MCP server.
You need Node.js 22+, pnpm, the Restate server and CLI, and an OpenAI API key. The agent can also run on Anthropic, Google, xAI or DeepSeek models, or on open models through Ollama, vLLM or any OpenAI-compatible server; see models.
pnpm install
# Terminal 1: Restate, with the SDK features this example uses
RESTATE_EXPERIMENTAL_ENABLE_PROTOCOL_V7=true restate-server
# Terminal 2: the agent service on port 9080, registered with Restate
export OPENAI_API_KEY=your-api-key
pnpm dev:service
restate deployments register http://localhost:9080Talk to an agent through Restate ingress on port 8080. Any agent ID works; the first message creates the agent.
# Start a turn (or queue the message if one is running)
curl localhost:8080/Agent/demo/ask --json '{"message":"What is the weather in Berlin?"}'
# Redirect the running turn without cancelling its tools
curl localhost:8080/Agent/demo/steer --json '{"message":"Use Fahrenheit"}'
# Stop it, optionally queueing a replacement request
curl localhost:8080/Agent/demo/interrupt --json '{"reason":"Changed my mind"}'
# Read the conversation log
curl localhost:8080/AgentSession/demo/history --json '{"fromSequence":1,"limit":100}'Or chat in the reference UI: run pnpm dev:ui and open
http://127.0.0.1:3000/?agent=demo.
Try this: ask it to sleep for four minutes, then kill pnpm dev:service
and start it again. The turn picks up where it was, and the Restate UI
(http://localhost:9070) shows every model call and tool result in the
turn's journal.