How checkpointing works
TheCheckpointer class persists AgentCheckpoint objects into any StateStore (in-memory for tests, SQLite for production). The agent runtime writes a checkpoint:
- After each completed iteration — capturing the current message history and accumulated usage.
- When the run suspends for HITL approval — storing the pending payload and the results of all tools that already ran.
resumeAgent loads the checkpoint, restores the message history and counters, and re-enters the loop at the point it left off. Tool calls recorded in the approvals map are replayed from their stored results rather than re-executed.
Checkpointer API
The key-value store where checkpoints are persisted. Use
SqliteStateStore in production and MemoryStateStore in tests.A stable identifier for this run. Use a value you can look up later — a request ID, a database primary key, or a UUID generated at request time.
Methods
Persist the current run state. Called automatically by the Anvil runtime when you pass
checkpoint to runAgent or streamAgent; call it manually only if you are driving the loop yourself.Retrieve the most recently saved checkpoint. Returns
undefined if no checkpoint exists for this runId.Remove the checkpoint after a run completes successfully. Call this in your cleanup logic to avoid unbounded growth of the checkpoint store.
AgentCheckpoint fields
Current lifecycle state.
'suspended' means the run is waiting for human approval; 'done' means it completed (successfully or by hitting the iteration cap).Tool call results already persisted. When the run resumes, any tool call whose
callId appears in this map is not re-executed — its stored output is used directly. This prevents side-effect tools from running twice.Set when
status is 'suspended'. Contains the call ID and the payload the tool passed to ApprovalRequiredError, which the approver sees in the HITL queue.Marking tools as side effects
DeclaresideEffect: true on any tool that mutates external state — charges a card, sends an email, creates a database row. Anvil checkpoints after the tool completes and fences its result so a resume can never re-execute it:
Running an agent with a checkpoint
Passcheckpoint to runAgent or streamAgent. Anvil instantiates a Checkpointer internally and writes checkpoints throughout the run:
Resuming after a crash
If the process was interrupted, callresumeAgent with the same runId. It loads the checkpoint, restores message history and usage counters, and re-enters the loop from the last saved state:
resumeAgent returns immediately if the checkpoint has status: 'done' — handy for idempotent retry logic.
Listing all persisted runs
UselistRuns to retrieve every run ID that has an active checkpoint. This is useful for building an admin queue of in-progress or suspended runs:
listRuns returns only run IDs, not the full checkpoints. Load a specific checkpoint with new Checkpointer(store, runId).load() to inspect its state.The state store
Durable execution usesStateStore — a simple key-value interface separate from TraceStore. The production default is SqliteStateStore:
SqliteStateStore across multiple agent routes, since each run uses a unique runId-namespaced key.