Budget by tokens, not by message count, and summarize what you drop:
- Keep the system prompt + a running summary + the most recent messages that fit a budget (say 60k tokens). Count with the token counting endpoint or estimate ~4 chars per token and leave margin.
- When messages fall out of the window, ask a cheap model to fold them into the running summary ("facts the user told us, decisions made, open questions"). Store that summary on the conversation row.
- Pasted documents: don't resend them forever. Summarize them once or store them and only include them when relevant.
- Use prompt caching on the stable prefix (system prompt + summary). It cuts cost a lot for long chats.
This fixes the error, the cost, and the "forgets early stuff" problem at the same time.