Skip to main content
An Agent is a StatefulActor — understanding four properties of that execution model explains why the SDK looks the way it does.

One actor per conversation

You address an agent by name: env.CONVOS.idFromName("+15550001111") always routes to the same actor instance, anywhere in the fleet. That makes the phone number (or user id, or session id) the unit of isolation — each conversation gets its own history, state, and timers, with no cross-talk and no shared database to partition. See Addressing.

Turns are serialized

An actor runs one method call at a time. While process() is thinking, a second inbound message waits — it never interleaves. That is what makes the read-modify-write patterns in agent code safe without locks: this.messages.add() then this.queue("process") can’t race another webhook for the same customer. See Execution model.

Think in the background

Inbound RPC methods run under a 30-second wall-clock budget — fine for receive(), tight for an LLM round-trip plus tool calls. That’s why the quickstart acks the webhook and defers the thinking:
Queued and scheduled tasks fire inside the actor’s alarm() handler, which has a larger budget — on the order of minutes — and retries on failure. Put LLM calls, tool use, and outbound API work there.

Everything durable survives restarts

History, state, and pending tasks live in the actor’s durable storage, not in memory. If the actor is evicted, crashes, or the pod restarts, a pending task’s timer re-fires after recovery, and the scheduler re-arms to the earliest pending task whenever the actor wakes. A 24-hour follow-up scheduled today fires tomorrow no matter what happens in between. See Lifecycle.