use std::time::Instant;
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct UsageStats {
pub input_tokens: u64,
pub output_tokens: u64,
pub total_input: u64,
pub total_output: u64,
pub last_latency_ms: u64,
}
impl UsageStats {
pub fn record(&mut self, input_tokens: u64, output_tokens: u64) {
self.input_tokens = input_tokens;
self.output_tokens = output_tokens;
self.total_input = self.total_input.saturating_add(input_tokens);
self.total_output = self.total_output.saturating_add(output_tokens);
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct TurnState {
pub running: bool,
pub started_at: Option<Instant>,
pub spinner_verb: &'static str,
}
impl Default for TurnState {
fn default() -> Self {
Self {
running: false,
started_at: None,
spinner_verb: "Thinking",
}
}
}
impl TurnState {
pub fn start(&mut self) {
self.running = true;
self.started_at = Some(Instant::now());
self.spinner_verb = "Thinking";
}
pub fn finish(&mut self) {
self.running = false;
self.started_at = None;
self.spinner_verb = "Thinking";
}
}
pub fn detect_model_name() -> String {
crate::config::Config::from_env()
.map(|c| c.model)
.unwrap_or_else(|_| "gpt-4o-mini".to_string())
}
pub fn estimate_cost(model: &str, total_input: u64, total_output: u64) -> Option<f64> {
let pricing = crate::llm::pricing_for(model)?;
let in_cost = (total_input as f64) * pricing.input_per_million / 1_000_000.0;
let out_cost = (total_output as f64) * pricing.output_per_million / 1_000_000.0;
Some(in_cost + out_cost)
}