From 414e4528711a5784cd66c57bce8a0140534f366e Mon Sep 17 00:00:00 2001 From: RCD <90105158+Finesssee@users.noreply.github.com> Date: Tue, 29 Sep 2026 20:45:28 +0700 Subject: [PATCH 1/2] Port upstream 0.69.0: Grok local session scan covers exact local calendar days --- docs/PROVIDERS.md | 2 +- rust/src/providers/grok/local_sessions.rs | 87 +++++++++++++++++++++-- 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/docs/PROVIDERS.md b/docs/PROVIDERS.md index 237f7dab3d..f0a5e59e5f 100644 --- a/docs/PROVIDERS.md +++ b/docs/PROVIDERS.md @@ -71,7 +71,7 @@ Optional status polling (provider status pages) is available via CLI `--status` ## Usage & Spend -Desktop tab id: `usageSpend`. The desktop and Overview consume one shared spend catalog. Codex and Claude local logs are first-class; routed OpenCodex usage enriches the matching Codex, OpenCode Go, Kimi, or DeepSeek subscription instead of appearing as a second fake provider. xAI and OpenRouter can publish exact provider-metered daily USD spend when their management credentials are configured, while Grok local sessions contribute tokens only. Missing spend sources remain unknown rather than becoming a false `$0`. Do not invent cross-currency totals. +Desktop tab id: `usageSpend`. The desktop and Overview consume one shared spend catalog. Codex and Claude local logs are first-class; routed OpenCodex usage enriches the matching Codex, OpenCode Go, Kimi, or DeepSeek subscription instead of appearing as a second fake provider. xAI and OpenRouter can publish exact provider-metered daily USD spend when their management credentials are configured, while Grok local sessions contribute tokens only (the scan covers exactly the requested number of local calendar days, including today). Missing spend sources remain unknown rather than becoming a false `$0`. Do not invent cross-currency totals. ### AWS Bedrock monitoring diff --git a/rust/src/providers/grok/local_sessions.rs b/rust/src/providers/grok/local_sessions.rs index 262f1b9294..fa6f8b81b8 100644 --- a/rust/src/providers/grok/local_sessions.rs +++ b/rust/src/providers/grok/local_sessions.rs @@ -4,7 +4,7 @@ use std::collections::{BTreeMap, HashMap}; use std::fs; use std::path::{Path, PathBuf}; -use chrono::{DateTime, Duration, Local}; +use chrono::{DateTime, Days, Local, NaiveDate, TimeZone}; use serde_json::Value; #[derive(Debug, Clone, PartialEq, Eq)] @@ -38,7 +38,7 @@ fn grok_home() -> PathBuf { } fn summarize_root(root: &Path, lookback_days: u32, now: DateTime) -> Summary { - let cutoff = now - Duration::days(i64::from(lookback_days.max(1))); + let (window_start, window_end) = calendar_window(now, lookback_days); let mut stack = vec![root.to_path_buf()]; let mut session_count = 0u32; let mut total_tokens = 0u64; @@ -66,7 +66,7 @@ fn summarize_root(root: &Path, lookback_days: u32, now: DateTime) -> Summ continue; }; let modified: DateTime = modified.into(); - if modified < cutoff || modified > now { + if modified < window_start || modified >= window_end { continue; } let Ok(text) = fs::read_to_string(&path) else { @@ -145,6 +145,24 @@ fn summarize_root(root: &Path, lookback_days: u32, now: DateTime) -> Summ } } +/// Half-open window `[start, end)` covering exactly `days` local calendar days +/// ending with the day of `now`: local midnight `days - 1` days ago through the +/// next local midnight. +fn calendar_window(now: DateTime, days: u32) -> (DateTime, DateTime) { + let today = now.date_naive(); + let first = today + .checked_sub_days(Days::new(u64::from(days.max(1) - 1))) + .unwrap_or(today); + let tomorrow = today.checked_add_days(Days::new(1)).unwrap_or(today); + (local_midnight(first, now), local_midnight(tomorrow, now)) +} + +fn local_midnight(day: NaiveDate, fallback: DateTime) -> DateTime { + day.and_hms_opt(0, 0, 0) + .and_then(|midnight| Local.from_local_datetime(&midnight).earliest()) + .unwrap_or(fallback) +} + fn nonnegative_u64(value: &Value) -> Option { value .as_u64() @@ -165,11 +183,72 @@ mod tests { r#"{"totalTokensBeforeCompaction":100,"contextTokensUsed":25,"primaryModelId":"grok-4","modelsUsed":["grok-4-fast"]}"#, ) .unwrap(); - let summary = summarize_root(root.path(), 30, Local::now() + Duration::seconds(1)); + let summary = summarize_root(root.path(), 30, Local::now()); assert_eq!(summary.session_count, 1); assert_eq!(summary.total_tokens, 125); assert_eq!(summary.daily.len(), 1); assert_eq!(summary.daily[0].total_tokens, 125); assert_eq!(summary.daily[0].models, vec!["grok-4", "grok-4-fast"]); } + + fn write_signals_at(root: &Path, name: &str, tokens: u64, modified: DateTime) { + let session = root.join("project").join(name); + fs::create_dir_all(&session).unwrap(); + let path = session.join("signals.json"); + fs::write( + &path, + format!(r#"{{"totalTokensBeforeCompaction":{tokens},"contextTokensUsed":0}}"#), + ) + .unwrap(); + fs::File::options() + .write(true) + .open(&path) + .unwrap() + .set_modified(modified.into()) + .unwrap(); + } + + fn local_noon(today: NaiveDate, offset: i64) -> DateTime { + let day = if offset >= 0 { + today.checked_add_days(Days::new(offset.unsigned_abs())) + } else { + today.checked_sub_days(Days::new(offset.unsigned_abs())) + } + .unwrap(); + Local + .from_local_datetime(&day.and_hms_opt(12, 0, 0).unwrap()) + .earliest() + .unwrap() + } + + #[test] + fn scan_totals_cover_only_the_advertised_local_calendar_days() { + for days in [1u32, 7, 30] { + let root = tempfile::tempdir().unwrap(); + let now = Local::now(); + let today = now.date_naive(); + let back = i64::from(days); + write_signals_at(root.path(), "outside", 100, local_noon(today, -back)); + write_signals_at(root.path(), "first", 100, local_noon(today, -(back - 1))); + write_signals_at(root.path(), "today", 100, local_noon(today, 0)); + write_signals_at(root.path(), "tomorrow", 100, local_noon(today, 1)); + + let summary = summarize_root(root.path(), days, now); + assert_eq!(summary.session_count, 2, "days={days}"); + assert_eq!(summary.total_tokens, 200, "days={days}"); + let daily_total: u64 = summary.daily.iter().map(|d| d.total_tokens).sum(); + assert_eq!(daily_total, summary.total_tokens, "days={days}"); + } + } + + #[test] + fn calendar_window_starts_at_local_midnight() { + let now = Local::now(); + let (start, end) = calendar_window(now, 7); + assert!(start <= now && now < end); + assert_eq!(start.date_naive(), now.date_naive() - Days::new(6)); + assert_eq!(end.date_naive(), now.date_naive() + Days::new(1)); + let (zero_start, _) = calendar_window(now, 0); + assert_eq!(zero_start.date_naive(), now.date_naive()); + } } From 16bd184e565096a200ce4720d579d45523bebf6b Mon Sep 17 00:00:00 2001 From: RCD <90105158+Finesssee@users.noreply.github.com> Date: Wed, 30 Sep 2026 21:50:22 +0700 Subject: [PATCH 2/2] Address thermo review --- rust/src/providers/grok/local_sessions.rs | 61 ++++++++++------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/rust/src/providers/grok/local_sessions.rs b/rust/src/providers/grok/local_sessions.rs index fa6f8b81b8..db6b163bcb 100644 --- a/rust/src/providers/grok/local_sessions.rs +++ b/rust/src/providers/grok/local_sessions.rs @@ -4,7 +4,7 @@ use std::collections::{BTreeMap, HashMap}; use std::fs; use std::path::{Path, PathBuf}; -use chrono::{DateTime, Days, Local, NaiveDate, TimeZone}; +use chrono::{DateTime, Days, Local, NaiveDate}; use serde_json::Value; #[derive(Debug, Clone, PartialEq, Eq)] @@ -38,7 +38,7 @@ fn grok_home() -> PathBuf { } fn summarize_root(root: &Path, lookback_days: u32, now: DateTime) -> Summary { - let (window_start, window_end) = calendar_window(now, lookback_days); + let (first_day, last_day) = calendar_day_window(now, lookback_days); let mut stack = vec![root.to_path_buf()]; let mut session_count = 0u32; let mut total_tokens = 0u64; @@ -66,7 +66,8 @@ fn summarize_root(root: &Path, lookback_days: u32, now: DateTime) -> Summ continue; }; let modified: DateTime = modified.into(); - if modified < window_start || modified >= window_end { + let modified_day = modified.date_naive(); + if modified_day < first_day || modified_day > last_day { continue; } let Ok(text) = fs::read_to_string(&path) else { @@ -145,22 +146,13 @@ fn summarize_root(root: &Path, lookback_days: u32, now: DateTime) -> Summ } } -/// Half-open window `[start, end)` covering exactly `days` local calendar days -/// ending with the day of `now`: local midnight `days - 1` days ago through the -/// next local midnight. -fn calendar_window(now: DateTime, days: u32) -> (DateTime, DateTime) { +/// Inclusive local-date window covering `max(1, days)` days through today. +fn calendar_day_window(now: DateTime, days: u32) -> (NaiveDate, NaiveDate) { let today = now.date_naive(); - let first = today - .checked_sub_days(Days::new(u64::from(days.max(1) - 1))) - .unwrap_or(today); - let tomorrow = today.checked_add_days(Days::new(1)).unwrap_or(today); - (local_midnight(first, now), local_midnight(tomorrow, now)) -} - -fn local_midnight(day: NaiveDate, fallback: DateTime) -> DateTime { - day.and_hms_opt(0, 0, 0) - .and_then(|midnight| Local.from_local_datetime(&midnight).earliest()) - .unwrap_or(fallback) + let first_day = today + .checked_sub_days(Days::new(u64::from(days.saturating_sub(1)))) + .unwrap_or(NaiveDate::MIN); + (first_day, today) } fn nonnegative_u64(value: &Value) -> Option { @@ -172,6 +164,7 @@ fn nonnegative_u64(value: &Value) -> Option { #[cfg(test)] mod tests { use super::*; + use chrono::TimeZone; #[test] fn summarizes_signal_token_totals_by_local_day() { @@ -208,7 +201,7 @@ mod tests { .unwrap(); } - fn local_noon(today: NaiveDate, offset: i64) -> DateTime { + fn local_at(today: NaiveDate, offset: i64, hour: u32) -> DateTime { let day = if offset >= 0 { today.checked_add_days(Days::new(offset.unsigned_abs())) } else { @@ -216,7 +209,7 @@ mod tests { } .unwrap(); Local - .from_local_datetime(&day.and_hms_opt(12, 0, 0).unwrap()) + .from_local_datetime(&day.and_hms_opt(hour, 0, 0).unwrap()) .earliest() .unwrap() } @@ -225,13 +218,13 @@ mod tests { fn scan_totals_cover_only_the_advertised_local_calendar_days() { for days in [1u32, 7, 30] { let root = tempfile::tempdir().unwrap(); - let now = Local::now(); - let today = now.date_naive(); + let today = Local::now().date_naive(); + let now = local_at(today, 0, 11); let back = i64::from(days); - write_signals_at(root.path(), "outside", 100, local_noon(today, -back)); - write_signals_at(root.path(), "first", 100, local_noon(today, -(back - 1))); - write_signals_at(root.path(), "today", 100, local_noon(today, 0)); - write_signals_at(root.path(), "tomorrow", 100, local_noon(today, 1)); + write_signals_at(root.path(), "outside", 100, local_at(today, -back, 12)); + write_signals_at(root.path(), "first", 100, local_at(today, -(back - 1), 12)); + write_signals_at(root.path(), "today", 100, local_at(today, 0, 12)); + write_signals_at(root.path(), "tomorrow", 100, local_at(today, 1, 12)); let summary = summarize_root(root.path(), days, now); assert_eq!(summary.session_count, 2, "days={days}"); @@ -242,13 +235,13 @@ mod tests { } #[test] - fn calendar_window_starts_at_local_midnight() { - let now = Local::now(); - let (start, end) = calendar_window(now, 7); - assert!(start <= now && now < end); - assert_eq!(start.date_naive(), now.date_naive() - Days::new(6)); - assert_eq!(end.date_naive(), now.date_naive() + Days::new(1)); - let (zero_start, _) = calendar_window(now, 0); - assert_eq!(zero_start.date_naive(), now.date_naive()); + fn calendar_day_window_covers_the_requested_local_dates() { + let now = local_at(Local::now().date_naive(), 0, 11); + let today = now.date_naive(); + let (first_day, last_day) = calendar_day_window(now, 7); + assert_eq!(first_day, today - Days::new(6)); + assert_eq!(last_day, today); + let (zero_first_day, zero_last_day) = calendar_day_window(now, 0); + assert_eq!((zero_first_day, zero_last_day), (today, today)); } }