use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Usage {
pub input_tokens: Option<u32>,
pub output_tokens: Option<u32>,
pub cache_read_tokens: Option<u32>,
pub cache_write_tokens: Option<u32>,
pub input_total_tokens: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub thinking_tokens: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub context_window: Option<u32>,
}
impl Usage {
pub(crate) fn with_input_total(mut self, cache_outside_input: bool) -> Self {
self.input_total_tokens = match (self.input_tokens, cache_outside_input) {
(Some(n), true) => Some(
n.saturating_add(self.cache_read_tokens.unwrap_or(0))
.saturating_add(self.cache_write_tokens.unwrap_or(0)),
),
(n, _) => n,
};
self
}
pub(crate) fn with_thinking(
mut self,
thinking: Option<u32>,
output_contains_thinking: bool,
) -> Self {
if let (Some(out), Some(t), true) = (self.output_tokens, thinking, output_contains_thinking)
{
self.output_tokens = Some(out.saturating_sub(t));
}
self.thinking_tokens = thinking;
self
}
pub fn fold_thinking(mut self) -> Self {
if let (Some(out), Some(t)) = (self.output_tokens, self.thinking_tokens) {
self.output_tokens = Some(out.saturating_add(t));
}
self
}
}