You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Anthropic prompt cache: turn after a 5–60 min user pause rewrites the whole prefix (idle gap never selects the 1h TTL) #1898
In an interactive chat on an Anthropic model (claude-opus-5-5 via the Codegraff gateway), the first request of a user turn reads nothing from the prompt cache whenever the user replied more than ~5 minutes after the previous turn ended. The trace reports cache_miss: "first_request" with prefix_changed: false, so this is a TTL expiry of an unchanged prefix, not a prefix bust. The prompt and toolset hashes (prompt_sha, toolset_sha) are identical across the turns.
From one long chat (11 traced runs, ~180 model calls, context growing to ~270k tokens):
Turn opener
Count
Cache read
Cache write per opener
User replied within ~5 min
6
29k–218k
42–2,053 tokens
User replied after a 10+ min gap
4
0
67k–217k tokens
The 4 cold openers wrote 582k tokens, 31% of all cache writes in the chat. In conversational use, where people reply a few minutes to an hour later, this is the common case.
Repro
Start a chat on an Anthropic model and build up 100k+ tokens of context.
Wait 10 minutes, then send a short follow-up.
In .graff/traces/<run>.jsonl, the first usage event has cache_read_tokens: 0, cache_write_tokens ≈ the whole context, and cache_miss: "first_request".
Root cause
This is the documented policy, not a bug. v0.302.74.65:src/cache_ttl.zig:1-14 asks for the 1-hour TTL only after a slow call inside a turn (#1320). ADR 0220 (docs/adr/0220-claude-prompt-cache-forks-and-pricing.md; src/cache_ttl.zig:10-14, test at :138) has the turn-opening request inherit the last in-turn gap and ignore the user's idle time. So a turn made of fast calls ends on 5-minute breakpoints, and any user pause longer than 5 minutes forces a full prefix rewrite at 1.25× (src/pricing_cache.zig:6).
Fix (proposal)
Use the user's idle gaps as a signal too. For example: if the previous user idle gap fell between 5 and 60 minutes, or the session is an interactive ACP chat above some context size (say 64k), mark the requests in this turn with the 1-hour TTL, so the prefix survives the next pause.
Rough economics for a prefix of P tokens, gap between 5 and 60 minutes:
Today: about 1.25·P per pause (a full rewrite).
1-hour TTL: about 0.1·P per pause (a read), plus the extra cost of writing new tokens at 2× instead of 1.25× (src/pricing_cache.zig:8), and possibly a one-time 2× write when the prefix first moves from a 5-minute to a 1-hour entry.
So the change pays for itself after the first pause longer than 5 minutes. A user who never comes back costs only the 2× premium on the last turn's writes, or a one-time prefix upgrade.
Open question: whether reading a 5-minute entry with a 1-hour breakpoint refreshes it or re-writes it. That decides whether the one-time 2·P upgrade happens.
Activity
justrach commentedon Nov 14, 2026
Implemented in #1900 (not yet merged); current-head CI is green.