fix for stats and model selection
Some checks failed
Weekly OSV dependency audit / dependency-audit (push) Failing after 5s
Some checks failed
Weekly OSV dependency audit / dependency-audit (push) Failing after 5s
This commit is contained in:
13
migrations/20260905090000_allow_qwen_session_model/down.sql
Normal file
13
migrations/20260905090000_allow_qwen_session_model/down.sql
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
ALTER TABLE sessions ADD COLUMN model_without_qwen TEXT
|
||||||
|
CHECK (model_without_qwen IS NULL OR model_without_qwen IN (
|
||||||
|
'deepseek-v4-flash-0731',
|
||||||
|
'deepseek-v4-pro',
|
||||||
|
'glm-5.2',
|
||||||
|
'glm-5.3-flash'
|
||||||
|
));
|
||||||
|
UPDATE sessions SET model_without_qwen = CASE
|
||||||
|
WHEN model = 'qwen3.8-flash-next' THEN NULL
|
||||||
|
ELSE model
|
||||||
|
END;
|
||||||
|
ALTER TABLE sessions DROP COLUMN model;
|
||||||
|
ALTER TABLE sessions RENAME COLUMN model_without_qwen TO model;
|
||||||
11
migrations/20260905090000_allow_qwen_session_model/up.sql
Normal file
11
migrations/20260905090000_allow_qwen_session_model/up.sql
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
ALTER TABLE sessions ADD COLUMN model_with_qwen TEXT
|
||||||
|
CHECK (model_with_qwen IS NULL OR model_with_qwen IN (
|
||||||
|
'deepseek-v4-flash-0731',
|
||||||
|
'deepseek-v4-pro',
|
||||||
|
'glm-5.2',
|
||||||
|
'glm-5.3-flash',
|
||||||
|
'qwen3.8-flash-next'
|
||||||
|
));
|
||||||
|
UPDATE sessions SET model_with_qwen = model;
|
||||||
|
ALTER TABLE sessions DROP COLUMN model;
|
||||||
|
ALTER TABLE sessions RENAME COLUMN model_with_qwen TO model;
|
||||||
46
src/app.rs
46
src/app.rs
@@ -148,8 +148,9 @@ pub(crate) struct App {
|
|||||||
pub(super) kv_cache_report: KvCacheReport,
|
pub(super) kv_cache_report: KvCacheReport,
|
||||||
last_cache_scan: Instant,
|
last_cache_scan: Instant,
|
||||||
last_http_requests: u64,
|
last_http_requests: u64,
|
||||||
last_ssd_selected_requests: u64,
|
last_ssd_cache_misses: u64,
|
||||||
last_ssd_requested_bytes: u64,
|
last_ssd_cache_evictions: u64,
|
||||||
|
last_ssd_pread_bytes: u64,
|
||||||
last_ssd_wait_ms: u64,
|
last_ssd_wait_ms: u64,
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
generation_service: Option<GenerationService>,
|
generation_service: Option<GenerationService>,
|
||||||
@@ -344,8 +345,9 @@ pub(super) struct MetricsPoint {
|
|||||||
pub(super) http_requests_per_second: f32,
|
pub(super) http_requests_per_second: f32,
|
||||||
pub(super) kv_read_bytes_per_second: f32,
|
pub(super) kv_read_bytes_per_second: f32,
|
||||||
pub(super) kv_write_bytes_per_second: f32,
|
pub(super) kv_write_bytes_per_second: f32,
|
||||||
pub(super) ssd_requests_per_second: f32,
|
pub(super) ssd_misses_per_second: f32,
|
||||||
pub(super) ssd_bytes_per_second: f32,
|
pub(super) ssd_evictions_per_second: f32,
|
||||||
|
pub(super) ssd_pread_bytes_per_second: f32,
|
||||||
pub(super) ssd_wait_ms_per_second: f32,
|
pub(super) ssd_wait_ms_per_second: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,8 +687,9 @@ impl App {
|
|||||||
kv_cache_report: KvCacheReport::default(),
|
kv_cache_report: KvCacheReport::default(),
|
||||||
last_cache_scan: Instant::now() - CACHE_SCAN_INTERVAL,
|
last_cache_scan: Instant::now() - CACHE_SCAN_INTERVAL,
|
||||||
last_http_requests: 0,
|
last_http_requests: 0,
|
||||||
last_ssd_selected_requests: 0,
|
last_ssd_cache_misses: 0,
|
||||||
last_ssd_requested_bytes: 0,
|
last_ssd_cache_evictions: 0,
|
||||||
|
last_ssd_pread_bytes: 0,
|
||||||
last_ssd_wait_ms: 0,
|
last_ssd_wait_ms: 0,
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
generation_service,
|
generation_service,
|
||||||
@@ -848,8 +851,9 @@ impl App {
|
|||||||
kv_cache_report: KvCacheReport::default(),
|
kv_cache_report: KvCacheReport::default(),
|
||||||
last_cache_scan: Instant::now() - CACHE_SCAN_INTERVAL,
|
last_cache_scan: Instant::now() - CACHE_SCAN_INTERVAL,
|
||||||
last_http_requests: 0,
|
last_http_requests: 0,
|
||||||
last_ssd_selected_requests: 0,
|
last_ssd_cache_misses: 0,
|
||||||
last_ssd_requested_bytes: 0,
|
last_ssd_cache_evictions: 0,
|
||||||
|
last_ssd_pread_bytes: 0,
|
||||||
last_ssd_wait_ms: 0,
|
last_ssd_wait_ms: 0,
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
generation_service,
|
generation_service,
|
||||||
@@ -2280,21 +2284,26 @@ impl App {
|
|||||||
let kv_write_bytes_per_second =
|
let kv_write_bytes_per_second =
|
||||||
kv_write_bytes as f32 / METRICS_SAMPLE_INTERVAL.as_secs_f32();
|
kv_write_bytes as f32 / METRICS_SAMPLE_INTERVAL.as_secs_f32();
|
||||||
let sample_seconds = METRICS_SAMPLE_INTERVAL.as_secs_f32();
|
let sample_seconds = METRICS_SAMPLE_INTERVAL.as_secs_f32();
|
||||||
let ssd_requests_per_second = snapshot
|
let ssd_misses_per_second = snapshot
|
||||||
.ssd_selected_requests
|
.ssd_cache_misses
|
||||||
.saturating_sub(self.last_ssd_selected_requests)
|
.saturating_sub(self.last_ssd_cache_misses) as f32
|
||||||
|
/ sample_seconds;
|
||||||
|
let ssd_evictions_per_second = snapshot
|
||||||
|
.ssd_cache_evictions
|
||||||
|
.saturating_sub(self.last_ssd_cache_evictions)
|
||||||
as f32
|
as f32
|
||||||
/ sample_seconds;
|
/ sample_seconds;
|
||||||
let ssd_bytes_per_second = snapshot
|
let ssd_pread_bytes_per_second = snapshot
|
||||||
.ssd_requested_bytes
|
.ssd_pread_bytes
|
||||||
.saturating_sub(self.last_ssd_requested_bytes)
|
.saturating_sub(self.last_ssd_pread_bytes)
|
||||||
as f32
|
as f32
|
||||||
/ sample_seconds;
|
/ sample_seconds;
|
||||||
let ssd_wait_ms_per_second =
|
let ssd_wait_ms_per_second =
|
||||||
snapshot.ssd_wait_ms.saturating_sub(self.last_ssd_wait_ms) as f32 / sample_seconds;
|
snapshot.ssd_wait_ms.saturating_sub(self.last_ssd_wait_ms) as f32 / sample_seconds;
|
||||||
self.last_http_requests = snapshot.http_requests;
|
self.last_http_requests = snapshot.http_requests;
|
||||||
self.last_ssd_selected_requests = snapshot.ssd_selected_requests;
|
self.last_ssd_cache_misses = snapshot.ssd_cache_misses;
|
||||||
self.last_ssd_requested_bytes = snapshot.ssd_requested_bytes;
|
self.last_ssd_cache_evictions = snapshot.ssd_cache_evictions;
|
||||||
|
self.last_ssd_pread_bytes = snapshot.ssd_pread_bytes;
|
||||||
self.last_ssd_wait_ms = snapshot.ssd_wait_ms;
|
self.last_ssd_wait_ms = snapshot.ssd_wait_ms;
|
||||||
self.metrics_history.push_back(MetricsPoint {
|
self.metrics_history.push_back(MetricsPoint {
|
||||||
decode_tokens_per_second: if snapshot.phase == crate::metrics::RuntimePhase::Generating
|
decode_tokens_per_second: if snapshot.phase == crate::metrics::RuntimePhase::Generating
|
||||||
@@ -2307,8 +2316,9 @@ impl App {
|
|||||||
http_requests_per_second,
|
http_requests_per_second,
|
||||||
kv_read_bytes_per_second,
|
kv_read_bytes_per_second,
|
||||||
kv_write_bytes_per_second,
|
kv_write_bytes_per_second,
|
||||||
ssd_requests_per_second,
|
ssd_misses_per_second,
|
||||||
ssd_bytes_per_second,
|
ssd_evictions_per_second,
|
||||||
|
ssd_pread_bytes_per_second,
|
||||||
ssd_wait_ms_per_second,
|
ssd_wait_ms_per_second,
|
||||||
});
|
});
|
||||||
if self.metrics_history.len() > 120 {
|
if self.metrics_history.len() > 120 {
|
||||||
|
|||||||
@@ -250,29 +250,43 @@ impl App {
|
|||||||
column![
|
column![
|
||||||
mini_chart(
|
mini_chart(
|
||||||
&self.metrics_history,
|
&self.metrics_history,
|
||||||
|point| point.ssd_requests_per_second,
|
|point| point.ssd_misses_per_second,
|
||||||
Color::from_rgb8(240, 180, 70),
|
Color::from_rgb8(240, 180, 70),
|
||||||
),
|
),
|
||||||
row![
|
row![
|
||||||
text("Selected loads")
|
text("Cache misses")
|
||||||
.size(12)
|
.size(12)
|
||||||
.color(Color::from_rgb8(240, 180, 70)),
|
.color(Color::from_rgb8(240, 180, 70)),
|
||||||
Space::new().width(Length::Fill),
|
Space::new().width(Length::Fill),
|
||||||
text(format!("{:.1}/s", latest.ssd_requests_per_second))
|
text(format!("{:.1}/s", latest.ssd_misses_per_second))
|
||||||
.size(12)
|
.size(12)
|
||||||
.color(muted_text()),
|
.color(muted_text()),
|
||||||
],
|
],
|
||||||
mini_chart(
|
mini_chart(
|
||||||
&self.metrics_history,
|
&self.metrics_history,
|
||||||
|point| point.ssd_bytes_per_second,
|
|point| point.ssd_pread_bytes_per_second,
|
||||||
Color::from_rgb8(67, 194, 203),
|
Color::from_rgb8(67, 194, 203),
|
||||||
),
|
),
|
||||||
row![
|
row![
|
||||||
text("Requested expert data")
|
text("Direct SSD reads")
|
||||||
.size(12)
|
.size(12)
|
||||||
.color(Color::from_rgb8(67, 194, 203)),
|
.color(Color::from_rgb8(67, 194, 203)),
|
||||||
Space::new().width(Length::Fill),
|
Space::new().width(Length::Fill),
|
||||||
text(format_rate(latest.ssd_bytes_per_second))
|
text(format_rate(latest.ssd_pread_bytes_per_second))
|
||||||
|
.size(12)
|
||||||
|
.color(muted_text()),
|
||||||
|
],
|
||||||
|
mini_chart(
|
||||||
|
&self.metrics_history,
|
||||||
|
|point| point.ssd_evictions_per_second,
|
||||||
|
Color::from_rgb8(157, 119, 255),
|
||||||
|
),
|
||||||
|
row![
|
||||||
|
text("Cache evictions")
|
||||||
|
.size(12)
|
||||||
|
.color(Color::from_rgb8(157, 119, 255)),
|
||||||
|
Space::new().width(Length::Fill),
|
||||||
|
text(format!("{:.1}/s", latest.ssd_evictions_per_second))
|
||||||
.size(12)
|
.size(12)
|
||||||
.color(muted_text()),
|
.color(muted_text()),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -945,6 +945,50 @@ mod tests {
|
|||||||
fs::remove_file(path).unwrap();
|
fs::remove_file(path).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn session_model_migration_preserves_data_and_accepts_catalog() {
|
||||||
|
let id = SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_nanos();
|
||||||
|
let path = std::env::temp_dir().join(format!("ds4-session-models-{id}.sqlite3"));
|
||||||
|
let mut database = Database::open(&path).unwrap();
|
||||||
|
let project = database
|
||||||
|
.create_project("DS4", "/tmp/ds4-session-models")
|
||||||
|
.unwrap();
|
||||||
|
let existing = database
|
||||||
|
.create_session(
|
||||||
|
project.id,
|
||||||
|
"Existing",
|
||||||
|
PermissionMode::Ai,
|
||||||
|
crate::model::ModelChoice::DeepSeekV4Flash0731,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
database
|
||||||
|
.connection
|
||||||
|
.revert_last_migration(MIGRATIONS)
|
||||||
|
.unwrap();
|
||||||
|
database
|
||||||
|
.connection
|
||||||
|
.run_pending_migrations(MIGRATIONS)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
database.load_projects().unwrap()[0].sessions[0].model(),
|
||||||
|
existing.model()
|
||||||
|
);
|
||||||
|
|
||||||
|
for model in crate::model::MODEL_CHOICES {
|
||||||
|
let session = database
|
||||||
|
.create_session(project.id, model.id(), PermissionMode::Ai, model)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(session.model(), Some(model));
|
||||||
|
}
|
||||||
|
|
||||||
|
drop(database);
|
||||||
|
fs::remove_file(path).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sessions_are_ordered_by_recent_use_within_sidebar_groups() {
|
fn sessions_are_ordered_by_recent_use_within_sidebar_groups() {
|
||||||
let id = SystemTime::now()
|
let id = SystemTime::now()
|
||||||
|
|||||||
Reference in New Issue
Block a user