Skip to content

Conversation history

Agent chat history is stored in browser localStorage by default. No server setup is needed. Enable server-side persistence when you want history shared across devices, preserved after a browser clear, or visible to multiple users.

flowchart TD
A[User sends message] --> B{VITE_FEATURE_CONVERSATION_DB=true?}
B -- No --> C[Browser localStorage]
B -- Yes --> D{Authenticated?}
D -- No --> C
D -- Yes --> E{Store configured?}
E -- auto --> F[Auto-select backend]
E -- explicit --> G[Use named backend]
F --> H[(Server store)]
G --> H
  • Persistence off — every conversation is local to the browser. Clearing browser data loses history.
  • Persistence on, unauthenticated user — falls back to localStorage. Server stores require a user identity to scope history correctly.
  • Persistence on, authenticated user — history is read and written to the configured server store.

Server-side persistence requires two things:

  1. VITE_FEATURE_CONVERSATION_DB=true must be set at build time (before bun run build). This is a VITE_* variable — it is baked into the bundle and cannot be changed at runtime. It also requires Clerk auth to be active (VITE_AUTH_PROVIDER=clerk).
  2. A backend must be reachable at runtime.
Terminal window
## In CI / build environment (before bun run build):
VITE_FEATURE_CONVERSATION_DB=true
VITE_AUTH_PROVIDER=clerk
VITE_CLERK_PUBLISHABLE_KEY=pk_live_...
Terminal window
## Runtime — select or force a backend:
CONVERSATION_STORE_BACKEND=postgres # or: agentstate, d1, memory
DATABASE_URL=postgresql://user:pass@host:5432/db

When CONVERSATION_STORE_BACKEND is not set, the server auto-selects the first available backend in the order described below.

When CONVERSATION_STORE_BACKEND is not set (or set to an unrecognized value), the server picks the first available backend in this order:

  1. AgentState — when AGENTSTATE_API_KEY is set and CONVERSATION_STORE_BACKEND is not d1, postgres, or memory.
  2. Cloudflare D1 — when the CONVERSATIONS_D1 binding is present (Cloudflare Workers only).
  3. Postgres — when DATABASE_URL is set.
  4. Memory — fallback in development/CI. Conversations are lost on process restart.

You can force a specific backend by setting CONVERSATION_STORE_BACKEND to agentstate, d1, postgres, or memory.

AgentState is a cloud-hosted conversation store. It works on any deployment target (Cloudflare Workers, Docker, Kubernetes, Vercel).

  1. Get an API key at agentstate.app.

  2. Set at build time:

Terminal window
VITE_FEATURE_CONVERSATION_DB=true
VITE_AUTH_PROVIDER=clerk
VITE_CLERK_PUBLISHABLE_KEY=pk_live_...
  1. Set at runtime:
Terminal window
AGENTSTATE_API_KEY=as_live_...
## CONVERSATION_STORE_BACKEND=agentstate # optional — auto-selected when key is present
  1. Optional: enable AI enrichment of stored conversation titles:
Terminal window
AGENTSTATE_AI_ENRICH=true
  1. Deploy. No migrations needed — AgentState manages the schema.

Cloudflare Workers — add via wrangler secret put:

Terminal window
wrangler secret put AGENTSTATE_API_KEY
## wrangler.toml [vars]
CONVERSATION_STORE_BACKEND = "agentstate"

Docker:

Terminal window
docker run -d --name chmonitor -p 3000:3000 \
-e AGENTSTATE_API_KEY='as_live_...' \
-e CONVERSATION_STORE_BACKEND='agentstate' \
ghcr.io/duyet/chmonitor:vX.Y.Z

Kubernetes:

Terminal window
kubectl create secret generic chmonitor-agentstate \
--from-literal=AGENTSTATE_API_KEY='as_live_...'
## in ConfigMap
CONVERSATION_STORE_BACKEND: "agentstate"
sequenceDiagram
participant B as Browser
participant A as /api/v1/agent
participant S as Store backend
B->>A: POST {message, hostId} + auth token
A->>S: Read conversation thread
S-->>A: Existing messages
A->>A: Run agent (tool loop)
A->>S: Append new messages
S-->>A: OK
A-->>B: Streamed response

On each request the server loads the thread from the store, runs the agent, then writes the updated thread back before streaming the response to the browser.

Server stores require an authenticated user identity to namespace threads. If the request is unauthenticated, the server skips persistence and the browser keeps local history. To enable server persistence, configure an auth provider — see Authentication.

NEXT_PUBLIC_FEATURE_CONVERSATION_DB=true is accepted as an alias for VITE_FEATURE_CONVERSATION_DB=true but is deprecated. Do not use it for new deployments.

  • Store Backends — exact config for each backend with platform recommendations