Vault / wiki/201/multi-turn-conversations.md
updated 2026-05-28Multi-Turn Conversations
The stateless model
Every API call must include the full conversation. The server keeps no session. This affects:
- Cost. Each turn pays for all prior turns as input tokens.
- Latency. Long histories slow down requests unless cached.
- Memory design. You are the storage layer.
Turn structure rules
- First message must be
user. - Roles strictly alternate
user→assistant→user→ ... - Tool results are sent as user turns containing
tool_resultblocks (not a separate role). - A single turn's
contentis an array of blocks (text, tool_use, tool_result, image, etc.).
Conversation compaction
When the history grows too large:
- Summarize older turns into a compact assistant message ("Here's what we've discussed so far: ...").
- Drop verbose tool results that are no longer needed; keep the summary.
- Keep a state object (e.g., JSON in the system prompt or first turn) representing canonical state, then prune old messages.
- Slide the window — keep the last N turns + a running summary.
This is a classic CCA-F exam topic: which compaction strategy is best for which scenario.
State object pattern
Instead of replaying the whole conversation, keep a compact JSON state:
{
"user": {"name": "Chris", "tier": "premium"},
"cart": [{"sku": "X", "qty": 2}],
"open_question": "Confirm shipping address"
}
Update it after each turn. Pass it in system prompt or initial user turn. The conversation becomes thin around a stable state.
Caching long histories
Mark the trailing-most cacheable boundary (e.g., after the last assistant turn) with cache_control. Each new user turn appends to that prefix. As long as the prefix stays stable, you get cache hits.
Common bugs
| Bug | Cause | Fix |
|---|---|---|
400 invalid_request_error: messages must alternate | Two user or two assistant in a row | Merge them or insert proper turn |
| Context window exhausted | Conversation too long | Compact / summarize |
| Lost reasoning across turns | Stripped thinking blocks | Keep them with signatures |
| Tool calls forgotten | Dropped tool_use/tool_result pair | Always keep matching pairs |