Overview
Agent state is:- Persistent - Automatically saved to SQLite, survives restarts and hibernation
- Synchronized - Changes broadcast to all connected WebSocket clients instantly
- Bidirectional - Both server and clients can update state
- Type-safe - Full TypeScript support with generics
Defining Initial State
Use theinitialState property to define default values for new agent instances:
Type Safety
The second generic parameter toAgent<Env, State> defines your state type:
When Initial State Applies
Initial state is applied lazily on first access, not on every wake:1
New agent
initialState is used and persisted2
Existing agent
Persisted state is loaded from SQLite
3
No initialState defined
this.state is undefinedReading State
Access the current state via thethis.state getter:
Undefined State
If you don’t defineinitialState, this.state returns undefined:
Updating State
UsesetState() to update state. This:
1
Saves to SQLite
State is persisted to storage
2
Broadcasts to all clients
All connected WebSocket clients receive the update
3
Triggers onStateChanged()
After broadcast; best-effort notification
State Must Be Serializable
State is stored as JSON, so it must be serializable:Responding to State Changes
OverrideonStateChanged() to react when state changes (notifications/side-effects):
Validating State Updates
If you want to validate or reject state updates, overridevalidateStateChange():
- Runs before persistence and broadcast
- Must be synchronous
- Throwing aborts the update
onStateChanged() is not intended for validation; it is a notification hook and should not block broadcasts.Migration note: onStateChanged replaces the deprecated onStateUpdate (server-side hook). If you’re using onStateUpdate on your agent class, rename it to onStateChanged — the signature and behavior are identical. A console warning will fire once per class until you rename it.The source Parameter
Thesource tells you who triggered the update:
This is useful for:
- Avoiding infinite loops (don’t react to your own updates)
- Validating client input
- Triggering side effects only on client actions
Common Pattern: Client-Driven Actions
Client-Side State Sync
State synchronizes automatically with connected clients.React (useAgent)
Vanilla JS (AgentClient)
State from Workflows
When using Workflows, you can update agent state from workflow steps:Patterns and Best Practices
Keep State Small
State is broadcast to all clients on every change. For large data:Optimistic Updates
For responsive UIs, update client state immediately:State vs SQL
Avoid Infinite Loops
Be careful not to trigger state updates in response to your own updates:API Reference
Properties
State
Current state (getter)
State
Default state for new agents
Methods
(state: State) => void
Update state, persist, and broadcast
(state: State, source: Connection | 'server') => void
Called after state is persisted and broadcast
Workflow Step Methods
(state) => Promise<void>
Replace agent state from workflow
(partial) => Promise<void>
Merge partial state from workflow
() => Promise<void>
Reset to
initialState from workflow