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.
How persistence works
Section titled “How persistence works”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.
Enable server persistence
Section titled “Enable server persistence”Server-side persistence requires two things:
VITE_FEATURE_CONVERSATION_DB=truemust be set at build time (beforebun run build). This is aVITE_*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).- A backend must be reachable at runtime.
## In CI / build environment (before bun run build):VITE_FEATURE_CONVERSATION_DB=trueVITE_AUTH_PROVIDER=clerkVITE_CLERK_PUBLISHABLE_KEY=pk_live_...## Runtime — select or force a backend:CONVERSATION_STORE_BACKEND=postgres # or: agentstate, d1, memoryDATABASE_URL=postgresql://user:pass@host:5432/dbWhen CONVERSATION_STORE_BACKEND is not set, the server auto-selects the first available backend in the order described below.
Backend resolution order
Section titled “Backend resolution order”When CONVERSATION_STORE_BACKEND is not set (or set to an unrecognized value), the server picks the first available backend in this order:
- AgentState — when
AGENTSTATE_API_KEYis set andCONVERSATION_STORE_BACKENDis notd1,postgres, ormemory. - Cloudflare D1 — when the
CONVERSATIONS_D1binding is present (Cloudflare Workers only). - Postgres — when
DATABASE_URLis set. - 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 self-host quickstart
Section titled “AgentState self-host quickstart”AgentState is a cloud-hosted conversation store. It works on any deployment target (Cloudflare Workers, Docker, Kubernetes, Vercel).
-
Get an API key at agentstate.app.
-
Set at build time:
VITE_FEATURE_CONVERSATION_DB=trueVITE_AUTH_PROVIDER=clerkVITE_CLERK_PUBLISHABLE_KEY=pk_live_...- Set at runtime:
AGENTSTATE_API_KEY=as_live_...## CONVERSATION_STORE_BACKEND=agentstate # optional — auto-selected when key is present- Optional: enable AI enrichment of stored conversation titles:
AGENTSTATE_AI_ENRICH=true- Deploy. No migrations needed — AgentState manages the schema.
Cloudflare Workers — add via wrangler secret put:
wrangler secret put AGENTSTATE_API_KEY## wrangler.toml [vars]CONVERSATION_STORE_BACKEND = "agentstate"Docker:
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.ZKubernetes:
kubectl create secret generic chmonitor-agentstate \ --from-literal=AGENTSTATE_API_KEY='as_live_...'## in ConfigMapCONVERSATION_STORE_BACKEND: "agentstate"Request / response flow
Section titled “Request / response flow”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 responseOn 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.
Auth requirement
Section titled “Auth requirement”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.
Deprecated alias
Section titled “Deprecated alias”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.
Next steps
Section titled “Next steps”- Store Backends — exact config for each backend with platform recommendations