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

@@ -6,8 +6,8 @@ use std::path::Path;
use crate::schema::{messages, preferences, projects, sessions};
use crate::settings::{
DiagnosticPreferences, ExecutionPreferences, GenerationPreferences, ReasoningMode,
RuntimePreferences, SpeculativePreferences, SsdPreferences, SteeringPreferences,
DiagnosticPreferences, ExecutionPreferences, GenerationPreferences, KvCachePreferences,
ReasoningMode, RuntimePreferences, SpeculativePreferences, SsdPreferences, SteeringPreferences,
StreamingCacheBudget,
};
@@ -58,6 +58,10 @@ pub struct AppPreferences {
/// Project the app reopens on. Cleared when that project goes away.
pub last_project_id: Option<i32>,
pub sidebar_width: i32,
pub kv_budget_gib: Option<i64>,
pub kv_min_tokens: Option<i32>,
pub kv_cold_max_tokens: Option<i32>,
pub kv_continued_interval_tokens: Option<i32>,
}
impl Default for AppPreferences {
@@ -103,6 +107,10 @@ impl Default for AppPreferences {
sidebar_collapsed: false,
last_project_id: None,
sidebar_width: 276,
kv_budget_gib: None,
kv_min_tokens: None,
kv_cold_max_tokens: None,
kv_continued_interval_tokens: None,
}
}
}
@@ -207,6 +215,28 @@ impl AppPreferences {
.map_err(|_| "Saved simulated memory is invalid.")?,
expert_profile_path: self.expert_profile_path.clone(),
},
kv_cache: KvCachePreferences {
budget_gib: self
.kv_budget_gib
.map(u64::try_from)
.transpose()
.map_err(|_| "Saved KV cache budget is invalid.")?,
min_tokens: self
.kv_min_tokens
.map(u32::try_from)
.transpose()
.map_err(|_| "Saved KV cache minimum tokens is invalid.")?,
cold_max_tokens: self
.kv_cold_max_tokens
.map(u32::try_from)
.transpose()
.map_err(|_| "Saved KV cache cold maximum is invalid.")?,
continued_interval_tokens: self
.kv_continued_interval_tokens
.map(u32::try_from)
.transpose()
.map_err(|_| "Saved KV cache continued interval is invalid.")?,
},
})
}
}
@@ -250,6 +280,10 @@ struct PreferenceChanges<'a> {
endpoint_port: i32,
endpoint_enabled: bool,
endpoint_cors: bool,
kv_budget_gib: Option<i64>,
kv_min_tokens: Option<i32>,
kv_cold_max_tokens: Option<i32>,
kv_continued_interval_tokens: Option<i32>,
}
#[derive(Clone, Debug, Identifiable, Queryable, Selectable)]
@@ -534,6 +568,18 @@ impl Database {
endpoint_port,
endpoint_enabled,
endpoint_cors,
kv_budget_gib: runtime
.kv_cache
.budget_gib
.map(i64::try_from)
.transpose()
.map_err(|_| "KV cache budget is too large.")?,
kv_min_tokens: runtime.kv_cache.min_tokens.map(|value| value as i32),
kv_cold_max_tokens: runtime.kv_cache.cold_max_tokens.map(|value| value as i32),
kv_continued_interval_tokens: runtime
.kv_cache
.continued_interval_tokens
.map(|value| value as i32),
})
.returning(AppPreferences::as_returning())
.get_result(&mut self.connection)
@@ -832,6 +878,12 @@ mod tests {
simulated_used_memory_gib: Some(8),
expert_profile_path: Some("/tmp/experts.json".into()),
},
kv_cache: KvCachePreferences {
budget_gib: Some(16),
min_tokens: Some(256),
cold_max_tokens: Some(0),
continued_interval_tokens: Some(4_096),
},
..RuntimePreferences::default()
};
database