Manage the KV cache disc usage from preferences and stats

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Georg Bauer
2026-07-26 09:10:18 +02:00
parent b182e7007c
commit 63e2a74ad5
14 changed files with 794 additions and 35 deletions

View File

@@ -313,6 +313,9 @@ impl Model {
pub(crate) struct Generator {
executor: metal::Executor,
checkpoint: Option<PathBuf>,
/// Token frontier of the last transient store, so continued checkpoints are
/// spaced like ds4's `continued_last_store_tokens`.
last_store_tokens: u32,
metrics: Arc<Metrics>,
}
@@ -358,6 +361,7 @@ impl Generator {
Ok(Self {
executor,
checkpoint: None,
last_store_tokens: 0,
metrics,
})
}
@@ -414,7 +418,7 @@ impl Generator {
let history = messages
.split_last()
.map_or(messages, |(_, history)| history);
let store = KvStore::open(directory)?;
let store = KvStore::open(directory, settings.kv_cache.budget_bytes)?;
let history_key =
conversation_key(&settings.system_prompt, settings.reasoning_mode, history);
let history_tag: [u8; 32] = Sha256::digest(&history_key).into();
@@ -423,14 +427,17 @@ impl Generator {
if let Some(entry) = store.find(&history_key, self.executor.context()) {
if self.select_checkpoint(&entry.checkpoint, entry.tag)? {
store.touch(&entry)?;
self.last_store_tokens = entry.tokens;
previous_checkpoint = Some(entry.checkpoint);
} else {
store.discard(&entry);
self.last_store_tokens = 0;
previous_checkpoint = None;
}
} else {
self.executor.reset()?;
self.checkpoint = None;
self.last_store_tokens = 0;
previous_checkpoint = None;
self.metrics.kv_lookup(KvLookup::Miss);
}
@@ -450,6 +457,17 @@ impl Generator {
let completed_key =
conversation_key(&settings.system_prompt, settings.reasoning_mode, &completed);
let completed_tag: [u8; 32] = Sha256::digest(&completed_key).into();
if !settings.kv_cache.stores(
self.executor.position(),
history.is_empty(),
self.last_store_tokens,
) {
// A gated store still leaves the finished conversation in the
// live KV, so mark it and drop the stale file association.
self.executor.note_checkpoint_tag(completed_tag);
self.checkpoint = None;
return Ok(output);
}
let completed_checkpoint = store.checkpoint_path(&completed_key);
self.save_checkpoint(&completed_checkpoint, completed_tag)?;
let retained = store.record(
@@ -468,6 +486,9 @@ impl Generator {
.then(|| std::fs::metadata(&completed_checkpoint).ok())
.flatten()
.map_or(0, |item| item.len());
if retained {
self.last_store_tokens = self.executor.position();
}
self.checkpoint = retained.then_some(completed_checkpoint);
}
Ok(output)