Chat continuity
How the proxy groups requests into chats and sessions, and the headers to control it.
MarkDB stitches a stream of proxy requests into chats, sessions, and turns. Most clients need nothing to make this work, but you can control it with headers when you want explicit threading.
How grouping is derived
Clients like Cursor replay the whole conversation on every request and rotate
their session id each time. To keep that from fragmenting into one session per
request, the proxy derives a stable chat key by hashing the first couple of
messages of the conversation (it reads both the Chat Completions messages[] and
the Responses input[] shapes). Same opening, same chat key -- so the thread
stays one chat even as the client's ids churn.
Request headers
Send these to override the derived behavior:
| Header | Effect |
|---|---|
X-MarkDB-Chat-Key | Force the conversation thread id. Use this when you manage threading yourself and don't want the derived key. |
X-MarkDB-External-Session-ID | Your client's session id for this bout of work. |
Response headers
Every proxied response tells you where it landed:
| Header | Meaning |
|---|---|
X-MarkDB-Session-ID | The MarkDB session this exchange was recorded under. |
X-MarkDB-External-Session-ID | The external session id in effect. |
X-MarkDB-Chat-Key | The chat key this exchange grouped into. |
Idle rollover
Within a chat, MarkDB keeps appending to the active session while the
conversation is live. After an idle gap it rolls the next request into a new
session under the same chat key -- marking the natural break between sittings.
The gap is MARKDB_PROXY_CHAT_IDLE_TIMEOUT, default 3h.
Deduplication
Because clients replay history, the proxy de-duplicates by content hash, scoped to the chat key, so a message is stored once no matter how many requests replay it. The dedup set is kept in Redis with a rolling ~24h TTL, so an active chat never loses its dedup state mid-flight.
When you need the headers
If your client already has stable conversation and session ids -- or doesn't
replay history -- set X-MarkDB-Chat-Key (and optionally
X-MarkDB-External-Session-ID) so grouping matches your model exactly instead of
relying on the derived key.