use crate::types::Usage;
#[derive(Debug, Clone, Default)]
pub struct UsageTotals {
pub input: u64,
pub output: u64,
pub cache_read: u64,
pub cache_write: u64,
pub cost: f64,
pub context_window: u64,
pub context_tokens: Option<u64>,
pub is_subscription: bool,
}
impl UsageTotals {
pub fn add(&mut self, usage: &Usage) {
self.input += usage.input;
self.output += usage.output;
self.cache_read += usage.cache_read;
self.cache_write += usage.cache_write;
self.cost += usage.cost.total;
self.context_tokens = Some(usage.input + usage.cache_read + usage.cache_write);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::Cost;
fn usage(input: u64, output: u64, cache_read: u64, cache_write: u64, cost: f64) -> Usage {
Usage {
input,
output,
cache_read,
cache_write,
total_tokens: input + output + cache_read + cache_write,
cost: Cost {
input: 0.0,
output: 0.0,
cache_read: 0.0,
cache_write: 0.0,
total: cost,
},
}
}
#[test]
fn add_accumulates_tokens_and_cost() {
let mut t = UsageTotals::default();
t.add(&usage(10, 5, 2, 1, 0.01));
t.add(&usage(20, 7, 3, 0, 0.02));
assert_eq!(t.input, 30);
assert_eq!(t.output, 12);
assert_eq!(t.cache_read, 5);
assert_eq!(t.cache_write, 1);
assert!((t.cost - 0.03).abs() < 1e-9);
}
#[test]
fn add_replaces_context_tokens_with_last_response() {
let mut t = UsageTotals::default();
t.add(&usage(10, 5, 2, 1, 0.0));
assert_eq!(t.context_tokens, Some(13));
t.add(&usage(50, 5, 4, 0, 0.0));
assert_eq!(t.context_tokens, Some(54));
}
#[test]
fn default_has_no_context_tokens() {
let t = UsageTotals::default();
assert_eq!(t.context_tokens, None);
assert_eq!(t.input, 0);
assert_eq!(t.cost, 0.0);
assert!(!t.is_subscription);
}
}