# How to Persist Agent State with Different State Stores in Aisuite

> Learn to persist agent state in Aisuite using InMemory, File, or Postgres state stores. Easily save conversations to memory, files, or a PostgreSQL database with a unified protocol.

- Repository: [Andrew Ng/aisuite](https://github.com/andrewyng/aisuite)
- Tags: how-to-guide
- Published: 2026-07-30

---

**Aisuite provides three built-in state store implementations—`InMemoryStateStore`, `FileStateStore`, and `PostgresStateStore`—that enable you to persist agent conversations to memory, local JSON files, or PostgreSQL using a unified protocol.**

The aisuite library (by Andrew Ng) includes a pluggable persistence layer that serializes an agent’s `RunState` so conversations can survive process restarts. By implementing the `StateStore` protocol defined in [`aisuite/agents/state_store.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/state_store.py), you can swap between ephemeral, file-based, and database-backed storage without modifying agent logic.

## The State Store Protocol and Available Implementations

All state stores implement the **`StateStore`** protocol from [`aisuite/agents/state_store.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/state_store.py), which requires three methods: `save_state`, `load_state`, and `delete_state`. The library ships with three concrete implementations:

| Store | Module | Persistence | Use Case |
|-------|--------|-------------|----------|
| **InMemoryStateStore** | [`aisuite/agents/state_store.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/state_store.py) | Ephemeral Python dict | Unit tests, single-process prototyping |
| **FileStateStore** | [`aisuite/agents/state_store.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/state_store.py) | JSON files on disk | Local debugging, simple scripts |
| **PostgresStateStore** | [`aisuite/agents/postgres_state_store.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/postgres_state_store.py) | PostgreSQL tables (`agent_thread_heads`, `agent_messages`, `agent_compactions`) | Production services, multi-worker deployments |

When initializing a store, you pass it to any `Runner.run*` or `Runner.continue_*` method along with a unique `thread_id` to activate persistence.

## Persisting Agent State with InMemoryStateStore

The `InMemoryStateStore` keeps state in a process-local dictionary. Data is lost when the process exits, making this ideal for unit tests or short-lived interactions.

```python
import aisuite as ai

agent = ai.Agent(name="assistant", model="gpt-4")
store = ai.InMemoryStateStore()

# First run creates thread "demo/1"

run = ai.Runner.run_sync(
    agent, 
    "Tell me a joke", 
    state_store=store, 
    thread_id="demo/1"
)
print(run.final_output)

# Continue within the same process

run2 = ai.Runner.continue_sync(
    agent, 
    "Another one?", 
    state_store=store, 
    thread_id="demo/1"
)

```

## Persisting Agent State with FileStateStore

The `FileStateStore` writes each thread to a JSON file under a configurable root directory. This requires no external dependencies and persists across process restarts.

```python
from pathlib import Path
import aisuite as ai

store = ai.FileStateStore(root=Path("./state_files"))

# Writes to ./state_files/demo%2F1.json

result = ai.Runner.run_sync(
    agent, 
    "Explain recursion", 
    state_store=store, 
    thread_id="demo/1"
)

# Later, in a new process, resume from the same file

new_store = ai.FileStateStore(root=Path("./state_files"))
result2 = ai.Runner.continue_sync(
    agent, 
    "Give an example", 
    state_store=new_store, 
    thread_id="demo/1"
)

```

## Persisting Agent State with PostgresStateStore

The `PostgresStateStore` provides ACID guarantees and multi-process access via PostgreSQL. It stores data in three tables—`agent_thread_heads`, `agent_messages`, and `agent_compactions`—managed in [`aisuite/agents/postgres_state_store.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/postgres_state_store.py).

```python
import aisuite as ai

pg_store = ai.PostgresStateStore.from_dsn(
    dsn="postgresql://user:pass@localhost:5432/aisuite",
    create_schema=True,  # Creates tables on first run

)

run = ai.Runner.run_sync(
    agent, 
    "Summarize this text", 
    state_store=pg_store, 
    thread_id="sql_demo/42"
)

# Resumed from another machine using the same DSN

run2 = ai.Runner.continue_sync(
    agent, 
    "Add a title", 
    state_store=pg_store, 
    thread_id="sql_demo/42"
)

```

## Optimistic Concurrency and StateConflictError

All stores implement **optimistic concurrency control**. Each `save_state` call must include the expected revision number (handled automatically by the `Runner`). If two processes write the same `thread_id` concurrently, the second write raises `StateConflictError`.

```python
store = ai.InMemoryStateStore()

# Simulate first write

first_state = store.load_state("thread/1")  # revision 1

store.save_state("thread/1", updated_state, revision=first_state.revision)

# Attempt stale write

try:
    store.save_state("thread/1", newer_state, revision=first_state.revision)
except ai.StateConflictError as exc:
    print("Write rejected:", exc)  # Revision mismatch

```

## How the Runner Handles State Hydration

When persisting, the `Runner` (in [`aisuite/agents/runner.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/runner.py)) dehydrates message artifacts to JSON-compatible structures before calling `save_state`. On load, it rehydrates them back to objects. This ensures `FileStateStore` JSON and `PostgresStateStore` rows contain serializable data while full objects are restored to the agent context.

## Summary

- **Three built-in stores**: `InMemoryStateStore` (ephemeral), `FileStateStore` (JSON files), and `PostgresStateStore` (PostgreSQL).
- **Unified protocol**: All implement `save_state`, `load_state`, and `delete_state` defined in [`aisuite/agents/state_store.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/state_store.py).
- **Simple activation**: Pass `state_store` and `thread_id` to `Runner.run_sync()` or `Runner.continue_sync()`.
- **Production ready**: `PostgresStateStore` uses tables `agent_thread_heads`, `agent_messages`, and `agent_compactions` with ACID guarantees.
- **Conflict safety**: Optimistic locking via revision numbers raises `StateConflictError` on concurrent writes.

## Frequently Asked Questions

### What is the StateStore protocol in aisuite?

The `StateStore` protocol defines the interface for persisting `RunState` objects, requiring `save_state`, `load_state`, and `delete_state` methods. It is implemented by `InMemoryStateStore`, `FileStateStore`, and `PostgresStateStore` in [`aisuite/agents/state_store.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/state_store.py) and [`aisuite/agents/postgres_state_store.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/postgres_state_store.py).

### How do I resume a conversation after restarting my application?

Use `Runner.continue_sync()` with the same `thread_id` and a state store instance containing the saved state. For `FileStateStore`, ensure the same root directory path. For `PostgresStateStore`, use the same database DSN and thread identifier.

### Can multiple processes share the same agent state?

Yes, when using `PostgresStateStore`, multiple workers can share state via PostgreSQL. The store implements optimistic concurrency control using atomic revision checks to prevent write conflicts between processes.

### What happens if two processes try to update the same thread simultaneously?

The second write will fail with `StateConflictError`. Each `save_state` call must include the expected revision number, and if the stored revision has changed since loading, the update is rejected to prevent data loss.