Cadence-aware prompt-cache TTL: 1h caching for sparse sessions#169
Open
pufit wants to merge 1 commit into
Open
Cadence-aware prompt-cache TTL: 1h caching for sparse sessions#169pufit wants to merge 1 commit into
pufit wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Anthropic prompt caching defaults to a 5-minute write TTL. A large class of Nerve sessions has a turn cadence beyond 5 minutes by design — persistent crons (30–60 min apart), ScheduleWakeup monitoring loops (20–30 min re-arms), and spaced web conversations. Every such turn finds a cold cache and re-writes the entire accumulated prefix at 1.25× base input instead of reading it at 0.1×. Last week: 119M cache-write tokens,
cache_creation_1h = 0always — despite the schema/usage pipeline already tracking the 1h split end-to-end.Backtest (28 days of real
session_usagetraffic, real pricing table)Last-7-days (current model mix): +$432/wk. Blanket-1h would lose $5.79/wk on web — hence a cadence-aware policy, not a global flip. Reproduce with
scripts/backtest_cache_ttl.py.What this does
agent.cache_ttlconfig:"5m"(default — zero behavior change),"1h", or"auto". Per-cron-job override viacache_ttlin jobs.yaml. Model exclusion list mirrorscontext_1m_excluded_models.nerve/agent/cache_policy.py— resolution at client-build time: observed cadence wins (median of recent turn gaps in (5min, 1h] → 1h); no-history priors: wakeup turns and persistent-mode cron sessions → 1h, everything else 5m. Recomputed on every client (re)build, so the idle-sweep recycle naturally tracks cadence changes.ENABLE_PROMPT_CACHING_1H=1(+ENABLE_PROMPT_CACHING_1H_BEDROCKon Bedrock); it adds theextended-cache-ttl-2025-04-11beta andcache_controlttl itself. Verified empirically: probe turn returnedephemeral_1h_input_tokens > 0, the exact shapeextract_cache_ttl_split()already parses. Resolved TTL is logged at INFO and stamped into session metadata./api/diagnosticsusage block gainscache_ttl: 1h write share + estimated savings vs a 5m baseline per source; a source where 1h traffic costs more than the baseline is flagged inregressionsand logged at WARNING. Verified against live data: all-5m traffic → exactly zero delta, no false positives.Prompt byte-stability (required for the cron win to materialize)
Persistent crons discard their SDK client after each run; the next run rebuilds the system prompt. Live data shows each run cold-rewrites its full ~170k prefix. A 1h TTL only converts that if the rebuilt prompt is byte-identical, so:
Current date(day resolution) instead of a minute-level timestamp; precise wall-clock time moves to a trailing<system-reminder>on each user message — fresher than the old build-time stamp (per turn, not per client build), invisible in the UI (not persisted to the DB message), and free cache-wise.memory_recalltool.Rollout
cache_ttl: "5m"— zero behavior change.inbox-processor+bee-ambientgetcache_ttl: "1h"(both */30 persistent — backtest ~$220/wk and ~$40/wk respectively). Deviation from the original plan:self-improvementwas named as a canary but runs daily — 24h gaps expire a 1h cache anyway, so flipping it would only pay the 2× write premium.cache_creation_1hgo nonzero and the diagnosticscache_ttl.savingsfor a week; if it matches the backtest, flip the global default toauto. Revert = one config line.Tests
tests/test_cache_policy.py(33 tests): resolution matrix (mode × source × exclusion × cadence × no-data fallback), env wiring iff 1h, hand-computed simulator costs (dense/sparse/mixed/model-switch/compaction cap), live-counterfactual estimator + regression guardrail. Full suite: 1433 passed.