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
Agent clients (Hermes, OpenCode, Pi, etc.) almost never send prompt_cache_breakpoint. On current master, that means sibling conversations that share a long system/tools head always miss and re-prefill the whole head.
The official catalog already has the right hit path (shared_stable_prefix). The gap is the default OpenAI write candidate, which lands on the last content part (usually the unique user turn), not on the stable system block.
This is not a request to merge #73 / #90 as a second store. It is a request to place one automatic write candidate at the rendered system-block frontier, so the existing planner can publish a shared prefix that those clients actually share.
Measured on RTX 5090, Qwen3.8-27B NVFP4, master 3d9fda2
Chat Completions, reasoning_effort=low, max_tokens=8. Authoritative numbers from the serve done line.
scenario
reuse=
cache/prompt
TTFT
same conversation, next turn (~2k)
private_turn_closure
2188/2209
92 ms (cold 559 ms)
16k shared system, no breakpoint, two sibling users
both root
0/16484
2363 / 2363 ms
same 16k system + prompt_cache_breakpoint on the system part
shared_stable_prefix
16466/16485
91 ms
C=2 concurrent siblings after that prefix was published
both shared_stable_prefix
16466
89 / 223 ms
same conversation, reasoning_effort low → xhigh
root
0
347 ms
3×32k private then return to A
private_turn_closure
32776/32797
125 ms (cold 5365 ms)
So: same-turn reuse is already excellent. Shared-prefix reuse is also excellent once a legal write exists. Default OpenAI implicit write does not create that write for the agent-sibling shape.
Why the default implicit candidate misses
docs/serving.md (OpenAI prompt caching): omitted prompt_cache_options creates a default implicit candidate at the latest representable content boundary. In apply_openai_prompt_cache_policy that is the last content part of the last turn — for a normal chat request, the unique user message.
Request A is then system(16k) + user("SIBA") published as one prefix. Request B is system(16k) + user("SIBB"). Exact prefix identity diverges at the last user tokens, so B is root even though 16k tokens are identical.
allow_engine_automatic_shared_prefixes is also forced off after OpenAI policy is applied (openai_common.cpp), which is consistent with “OpenAI already defined the write policy” — but that policy’s implicit target is the wrong frontier for this workload.
Fork #90 (seed_prefix / --prefix-cache-mib) solved the same gap with a separate GPU seed store. That is a second catalog and would fight the current planner. The behavior we want is only: capture at the system-block frontier using the existing shared-prefix machinery.
Suggestion (smallest change)
Keep the OpenAI explicit-breakpoint contract. Add an extra default write candidate when Chat Completions / Responses has a leading system (or tools+system) block and the client did not already mark it:
If that frontier is above a floor (256 tokens, or whatever the value model already uses), emit a SharedStablePrefix candidate with DefaultAutomatic / RequestedAutomatic evidence.
Do not disable the existing last-content implicit candidate; a same-turn continuation still wants a later frontier.
Reads of an already-published prefix should keep working without the client repeating a marker (this already matches serving.md).
That is one extra legal write (still ≤ 4). It does not add PrefixSeedStore, --prefix-cache-mib, --kv-host-cache-mib, or overlay.
Optional serve flag if you want it opt-in: --auto-system-shared-prefix default on for agent serving, off for strict OpenAI-implicit-only.
Summary
Agent clients (Hermes, OpenCode, Pi, etc.) almost never send
prompt_cache_breakpoint. On current master, that means sibling conversations that share a long system/tools head always miss and re-prefill the whole head.The official catalog already has the right hit path (
shared_stable_prefix). The gap is the default OpenAI write candidate, which lands on the last content part (usually the unique user turn), not on the stable system block.This is not a request to merge #73 / #90 as a second store. It is a request to place one automatic write candidate at the rendered system-block frontier, so the existing planner can publish a shared prefix that those clients actually share.
Measured on RTX 5090, Qwen3.8-27B NVFP4, master
3d9fda2Serve flags (exclusive one-GPU lane):
--max-concurrency 2 --kv-dtype int8 --vision --host-kv-mib 16384 --host-state-slots 8 --device-state-slots 2 --max-shared-prefixes 4 --max-private-continuations 4 --spec mtp --draft-tokens 3 --lm-head-draft, ctx/kv 245760.Chat Completions,
reasoning_effort=low,max_tokens=8. Authoritative numbers from the servedoneline.reuse=private_turn_closurerootprompt_cache_breakpointon the system partshared_stable_prefixshared_stable_prefixreasoning_effortlow → xhighrootprivate_turn_closureSo: same-turn reuse is already excellent. Shared-prefix reuse is also excellent once a legal write exists. Default OpenAI implicit write does not create that write for the agent-sibling shape.
Why the default implicit candidate misses
docs/serving.md(OpenAI prompt caching): omittedprompt_cache_optionscreates a default implicit candidate at the latest representable content boundary. Inapply_openai_prompt_cache_policythat is the last content part of the last turn — for a normal chat request, the unique user message.Request A is then
system(16k) + user("SIBA")published as one prefix. Request B issystem(16k) + user("SIBB"). Exact prefix identity diverges at the last user tokens, so B isrooteven though 16k tokens are identical.allow_engine_automatic_shared_prefixesis also forced off after OpenAI policy is applied (openai_common.cpp), which is consistent with “OpenAI already defined the write policy” — but that policy’s implicit target is the wrong frontier for this workload.Fork #90 (
seed_prefix/--prefix-cache-mib) solved the same gap with a separate GPU seed store. That is a second catalog and would fight the current planner. The behavior we want is only: capture at the system-block frontier using the existing shared-prefix machinery.Suggestion (smallest change)
Keep the OpenAI explicit-breakpoint contract. Add an extra default write candidate when Chat Completions / Responses has a leading system (or tools+system) block and the client did not already mark it:
SharedStablePrefixcandidate withDefaultAutomatic/RequestedAutomaticevidence.That is one extra legal write (still ≤ 4). It does not add
PrefixSeedStore,--prefix-cache-mib,--kv-host-cache-mib, or overlay.Optional serve flag if you want it opt-in:
--auto-system-shared-prefixdefault on for agent serving, off for strict OpenAI-implicit-only.What we are not asking for
--host-kv-mib. Same-axis, two eviction policies.Private continuation + host-kv already covers “same conversation came back.” The remaining hole at C=2 is two chats, one long head, no client marker.
Happy to re-run the sibling probe on a patch.