Skip to content

Keep prompt history byte-stable so the cache prefix survives - #5789

Draft
jurgenwerk wants to merge 1 commit into
mainfrom
prompt-cache-stability
Draft

Keep prompt history byte-stable so the cache prefix survives#5789
jurgenwerk wants to merge 1 commit into
mainfrom
prompt-cache-stability

Conversation

@jurgenwerk

Copy link
Copy Markdown
Contributor

Replaying two real assistant sessions turn by turn through the prompt builder and byte-diffing consecutive prompts showed 40-60% of session cost going to avoidable prompt-cache misses. The prompt's cache design (volatile context trailing a moving history breakpoint) is sound, but three things kept breaking the prefix:

tools ──► system+skills ──► history ──► [cache marker] ──► volatile context
  │             │               │
  │             │               └── attachment/tool-result content was dropped
  │             │                   retroactively when a newer version arrived
  │             │                   → history bytes changed mid-prompt
  │             └── survived (its breakpoint was the only hit on such turns)
  └── changed when a card attach inserted a per-card tool → full re-bill

The main change: a message's attachments now render from that message's own snapshot alone. Previously an attached card or file lost its content in the prompt once a newer version was attached later, and read-file tool results lost theirs the same way — rewriting already-sent history and re-billing everything after the change point at full input price on every subsequent turn. Superseded content now stays, and the attachment headers tell the model that a later attachment of the same card/file supersedes earlier ones. The carried content is billed at the cached-read rate, an order of magnitude below the re-bills it replaces. Replaying the same sessions with this change shows every turn diverging only at the trailing context message, as designed.

Two supporting ai-bot changes: Anthropic-model requests carry an OpenRouter provider preference for Anthropic (caches live per provider, and one observed request was routed to a cold instance mid-session), and per-turn usage now records the serving provider and generation id so a cache miss is attributable from the room timeline.

Known, accepted misses not addressed here: the first turn of a room runs before skill tools are discovered (small prompt, one-time), and attaching a card inserts its patch tool (semantic, once per session). Making per-card patch schemas byte-stable would need a tool-definition redesign and is left out deliberately.

Prompt caching is an exact prefix match, but attachment rendering rewrote
already-sent history: a message's attached card/file content was dropped
retroactively once a newer version was attached later, and read-file tool
results lost their content the same way. Every rewrite re-billed the whole
prompt after the change point at full input price on every later turn —
in observed sessions 40-60% of the total cost. A message's attachments now
render from its own snapshot alone, with the attachment headers telling
the model that later attachments of the same card/file supersede earlier
ones. Carrying the superseded content forward costs cached-read tokens, a
fraction of the re-bill.

Two supporting changes in the ai-bot: Anthropic-model requests are biased
to Anthropic itself (caches live per provider, so spreading a room's
requests across providers turns a warm prefix into a full-price miss),
and the usage recorded on each turn now carries the serving provider and
generation id so cache misses are attributable from the room timeline.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Host Test Results

    1 files      1 suites   2h 3m 42s ⏱️
4 192 tests 4 178 ✅ 14 💤 0 ❌
4 211 runs  4 197 ✅ 14 💤 0 ❌

Results for commit 0ae799e.

Realm Server Test Results

    1 files      1 suites   15m 47s ⏱️
2 173 tests 2 173 ✅ 0 💤 0 ❌
2 253 runs  2 253 ✅ 0 💤 0 ❌

Results for commit 0ae799e.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant