Repository navigation
[Feature]: Keep a JEV combo on one target per session so provider prompt caches stay warm #7525
Description
What are you trying to accomplish?
Keep provider-side prompt caching effective when a strategy: jev combo (jev-auto) is used for long agent sessions. Today JEV re-decides the target on almost every request, so consecutive turns of one conversation land on different providers and each switch starts with a cold prompt cache.
What prevents this today?
- JEV has no notion of session affinity. The only pinning knob,
stickyLimit, is accepted only forstrategy: round-robin(src/cli/combo.ts:--sticky applies only to round-robin). - Related but broader: [Feature]: Demand-level routing for JEV combos — orchestrator-chosen levels, per-session pinning, probability escalation (opt-in series on #6364) #6665 (demand-level routing, per-session pinning). This issue is the narrow cache-stability case and can be satisfied by a plain per-session pin.
Observed on a single-operator hub, last 24 h, jev-auto usage ledger (aggregated, no request bodies):
| JEV-selected target | Requests | Input tokens (M) | Cache read / input |
|---|---|---|---|
| anthropic/claude-haiku-5-5 | 635 | 90.7 | 85% |
| google-antigravity/gemini-3.8-flash | 412 | 56.2 | 90% |
| anthropic/claude-sonnet-5-5 | 135 | 21.8 | 78% |
| openai/gpt-6.1-sol | 381 | 36.4 | 23% |
| openai/gpt-5.6-terra | 251 | 17.4 | 18% |
Six different targets appear within a single day. In the OPENCODEX_CACHE_DEBUG=1 fingerprints (171 records, 36 min), the first divergent block is instructions[0] in 117 of 171 records, so consecutive requests from the same client often diverge at the very start of the prefix. Part of that is a separate problem (see "Related observation" below), part is switching targets.
What should OpenCodex do?
- Add a JEV combo option, for example
stickyTurns/sessionPin(default off), that keeps the last successful target for a session key (callerprompt_cache_key, or the existing session derivation) for N turns or T minutes. - Break the pin only on: upstream error or 429 that exhausts retries, the target being removed or disabled, or the request exceeding that target's context window.
- Expose the pin decision in the decision/usage record (
jevDecision.pinned: true,pinReason) so the ledger shows it. - Default behaviour must stay exactly as today.
Example usage or interface
Proposed interface (does not exist today):
ocx combo set jev-auto --strategy jev --session-pin 20m --json{ "id": "jev-auto", "strategy": "jev", "sessionPin": { "ttlMs": 1200000 } }Alternatives or workarounds
- Shrink the JEV target list to providers with high cache reuse. Works, but loses the cross-provider escalation JEV exists for.
- Split combos per client so each combo's instructions prefix stays stable. Helps the
instructions[0]divergence, does not fix target churn.
Related observation (separate, for triage)
Direct test through the hub, openai/gpt-6.1-sol, identical ~13.5k-token instructions repeated 3–4 times at 2 s and 20 s spacing, store: false:
- with
prompt_cache_keyforwarded (verifiedinbound == outboundin the cache-debug record):cached_tokens = 0on every request; - without the key:
cached_tokens = 0on every request; - all requests were served by the same pooled account.
So the forwarded key did not produce a hit in this run. It is unclear whether this is expected for pooled ChatGPT-backed accounts, or whether caching only engages for some accounts. Production shows partial OpenAI cache reads (18–33%), which suggests account-dependence. Happy to provide the exact request body and fingerprints on request; no keys included.
Activity
Ingwannu commentedon Oct 22, 2026
The current code confirms the narrow gap:
src/cli/combo.tspermits--stickyonly for round-robin, whilesrc/combos/jev-dispatch.tsresolves a JEV decision per invocation and has no session-pin option. This is a routing feature proposal, not an existing supported--session-pinflag. Keeping it open separately from the broader #6665 scope.A useful implementation contract would be opt-in and reuse the existing JEV dispatch/admission/decision-record owners. A pin must be namespaced by admitted caller plus combo/session identity (a caller-supplied
prompt_cache_keyalone is not an identity), bounded by TTL and capacity, and recorded only after an eligible target actually succeeds. Every reuse must still honor target availability, destination authorization, cancellation, quota/cooldown and context limits; configuration edits and removed targets must invalidate it. Deterministic tests should cover concurrent first requests, failed/cancelled sends, cross-caller separation, expiry, and unchanged default-off routing. A new public schema/CLI option and its default policy need an explicit design decision before implementation.Target stability can improve the opportunity for provider caching but does not establish cache hits. A changing
instructions[0]prefix and provider/account-specific cache behavior remain separate observations. The supplied counts do not prove an account-entitlement or upstream caching root cause. No request bodies, cache keys, credentials or paid live experiments are needed here; if more evidence is available, redacted prefix hashes, target/model and cache-read counters are sufficient.feat(jev): opt-in session pin keeps a JEV combo session on its decide…
lidge-jun commentedon Oct 23, 2026
Implemented on
devby #7567: JEV combos can now keep one target per session so provider prompt caches stay warm. The pin is opt-in and off by default, narrower than the demand-level routing proposed in #6665 (closed in favour of this). Closing manually because GitHub only auto-closes frommain; it ships in the next release.