use super::stats::DailyActivity;
use std::collections::HashMap;
#[derive(Debug, Clone, Default)]
pub struct ModelTokenDetail {
pub total_tokens: u64,
pub input_tokens: u64,
pub output_tokens: u64,
pub cache_read_input_tokens: u64,
pub cache_creation_input_tokens: u64,
pub web_search_requests: u64,
pub web_fetch_requests: u64,
pub tool_call_count: u64,
pub tool_calls: HashMap<String, u64>,
}
impl ModelTokenDetail {
pub fn cache_hit_rate(&self) -> f64 {
let denom = self.input_tokens + self.cache_read_input_tokens;
if denom > 0 {
self.cache_read_input_tokens as f64 / denom as f64
} else {
0.0
}
}
#[allow(dead_code)]
pub fn total_tool_requests(&self) -> u64 {
self.tool_call_count + self.web_search_requests + self.web_fetch_requests
}
}
#[derive(Debug, Clone)]
pub struct SessionSummary {
pub project_name: String,
pub model: String,
pub total_tokens: u64,
pub input_tokens: u64,
pub output_tokens: u64,
pub cache_read_input_tokens: u64,
pub cache_creation_input_tokens: u64,
pub web_search_requests: u64,
pub web_fetch_requests: u64,
pub tool_call_count: u64,
pub tool_calls: HashMap<String, u64>,
}
#[derive(Debug, Clone, Default)]
pub struct ViewData {
pub total_sessions: u64,
pub total_messages: u64,
pub total_tokens: u64,
pub model_tokens: HashMap<String, u64>,
pub model_token_detail: HashMap<String, ModelTokenDetail>,
pub project_tokens: HashMap<String, u64>,
pub daily_activity: Vec<DailyActivity>,
pub total_web_search_requests: u64,
pub total_web_fetch_requests: u64,
pub total_tool_calls: u64,
pub tool_calls: HashMap<String, u64>,
pub longest_session_secs: u64,
pub avg_session_secs: u64,
pub peak_period: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_model_token_detail_cache_hit_rate() {
let mut detail = ModelTokenDetail::default();
detail.input_tokens = 800;
detail.cache_read_input_tokens = 200;
let rate = detail.cache_hit_rate();
assert!((rate - 0.2).abs() < 1e-9);
}
#[test]
fn test_model_token_detail_cache_hit_rate_zero() {
let detail = ModelTokenDetail::default();
assert_eq!(detail.cache_hit_rate(), 0.0);
}
#[test]
fn test_model_token_detail_cache_hit_rate_full() {
let mut detail = ModelTokenDetail::default();
detail.input_tokens = 0;
detail.cache_read_input_tokens = 1000;
assert_eq!(detail.cache_hit_rate(), 1.0);
}
#[test]
fn test_model_token_detail_total_tool_requests() {
let mut detail = ModelTokenDetail::default();
detail.tool_call_count = 50;
detail.web_search_requests = 10;
detail.web_fetch_requests = 5;
assert_eq!(detail.total_tool_requests(), 65);
}
#[test]
fn test_model_token_detail_total_tool_requests_zero() {
let detail = ModelTokenDetail::default();
assert_eq!(detail.total_tool_requests(), 0);
}
#[test]
fn test_view_data_default() {
let vd = ViewData::default();
assert_eq!(vd.total_sessions, 0);
assert_eq!(vd.total_messages, 0);
assert_eq!(vd.total_tokens, 0);
assert!(vd.model_tokens.is_empty());
assert!(vd.model_token_detail.is_empty());
assert!(vd.project_tokens.is_empty());
assert!(vd.daily_activity.is_empty());
assert_eq!(vd.peak_period, "");
}
}