Senior · Core path · 8 chapters
Conversation state
Stateless APIs, owning history yourself
If state ownership is vague, retries, multiple tabs, and process restarts turn ordinary requests into corrupted conversations.
Read these first
What you will know
Trace a request from stored turns to outbound messages and verify that no conversation state is held by the API process between requests
A restart, retry, or second application instance must produce the same input from durable data rather than an in-memory session.
Implement multi-turn conversation without a framework
A list, a loop, and a database table is genuinely all it takes. Do it once before reaching for a framework.
Run concurrent turns against one conversation and verify that their persisted ordering and ownership remain correct
Without transactional updates or an explicit sequencing policy, two tabs can lose messages or expose one turn's response to another conversation.
Instrument history assembly and reproduce a stale, duplicated, or cross-conversation message in the outbound request
Logging conversation IDs, message IDs, revisions, and the final payload makes apparent model memory failures diagnosable as application bugs.
Decide what to do when history outgrows the context window
Summarise, drop old turns, or retrieve selectively — but decide deliberately rather than letting it truncate.
Chapters
- 1
Server-owned conversation history
A chat endpoint retains nothing between calls, so multi-turn conversation is a messages row per turn, an ordered read scoped to one conversation, and an array assembled fresh from those rows on every call. The property that proves the design is honest is that restarting the process between turn one and turn two leaves turn two's request body byte-identical, and this chapter shows how to check it and what a sixty-second cache of assembled arrays does to it.
- 2
Client-owned conversation history
Letting the browser hold the conversation and post the full array each request keeps the backend thin, and it moves ownership to a place the user can edit, so every turn arrives as user-controlled input rather than as your own record. Beyond the obvious loss on a cleared cache, you lose the ability to evaluate, audit or bill against what was really sent. This chapter works out what changes, which products it is genuinely right for, and what an HMAC over the transcript does and does not buy.
- 3
Debugging history assembly
When users report that the assistant forgot an order number, the first artefact to produce is the serialised array you actually sent for that conversation. Instrument assembly with conversation id, message ids, sequence range, revision and a payload fingerprint, then work the classic bugs: a query filtered by user rather than conversation, a LIMIT that clips the front, duplicate rows from a retry, and stale revisions that reach the wire unnoticed. This chapter also shows how to tell those apart from a genuine attention failure.
- 4
Concurrent turns and lost updates
Two turns sent on one conversation within a few seconds each read the same stored history, call the model, then append, and their appends collide: a turn goes missing, a reply is stored against the wrong user question, or one conversation's answer is delivered into another. This chapter walks the collision, reproduces it deterministically with a barrier and a slow fake model, adds the in_reply_to column and audit queries that make the corruption assertable, and separates it from a stale read-path cache.
- 5
Sequencing policies for concurrent turns
Three answers to the question of what happens to the second turn on a conversation: optimistic concurrency on a version column rejects it and retries against fresh history, a per-conversation lock serialises turns but must be held across a call whose p99 is twenty seconds, and branching lets both succeed and defers reconciliation. Compare them by wasted calls, added latency, failure mode and audit story, and decide what each fate renders in the tab that lost.
- 6
The context window budget
Assembly has a budget: count the tokens of the array you are about to send, reserve room for the reply, and compare the total against the model's window, so crossing the line is an event you detect rather than a 400 or a silently truncated prompt you learn about from a user. This chapter does the arithmetic, shows what tool schemas and images take out of the window before your history does, explains how prompt caching interacts with anything that shortens history, and separates detection from a policy.
- 7
Summarisation, pinned facts, and retrieval
Once the budget check says a conversation is at the limit, silence is not a policy. Compare a rolling summary of old turns, dropping oldest turns while pinning extracted facts, and retrieving only past turns relevant to the current message — by per-turn cost, by added latency, and by what each one destroys. In a refund conversation the details a summary drops are the consequential ones: the exact amount, the condition attached, the order id.
- 8
Reproducing a past model input
Asked six weeks later for the exact input behind a complaint, storing every message is not enough. Assembly depends on the code version, the window config in effect that day, and a summarisation step that is itself a non-deterministic model call, so re-running it produces a reconstruction rather than the original. This chapter models the six inputs that feed an outbound array, specifies a per-call record that captures them, and prices the archive against a metadata-only tier.
External resources
- Conversation state — OpenAI API guidedevelopers.openai.com
Official statement of what the API remembers and what you must carry.
- Manage LLM Message History — RedisVLdocs.redisvl.com
Working code for storing, trimming and replaying turns from a real store.
- Understanding State and State Management in LLM-Based AI Agentsgithub.com
Shows how stateless APIs require applications to own and manage conversation history.
- Conversational Memory for LLMspinecone.io
Compares buffer, window and summary strategies for owning history.
- How to Implement Continuous Chat Conversations Using OpenAI's API | Python | Ollama | Llama 3.2CloudOpsDirect
Builds the append-and-resend loop end to end in Python.
- Chat Application using LLMs - Chat History and Types of MessagesLearn With Yash Agrawal
Focuses on history handling choices once conversations get long.
- The Four Types of Memory Every AI Agent NeedsIBM Technology
Explains four memory types for agents, including managing conversation history outside stateless APIs.