pub mod ledger;
pub mod rates;
pub mod reserve;
pub mod window;
use jiff::Timestamp;
use serde::{Deserialize, Serialize};
use crate::agent::AgentName;
use crate::flight::{ItineraryId, RunId};
pub use ledger::{Ledger, Summary};
pub use rates::{ModelRates, RateCard};
pub use reserve::{Reserve, ReserveState};
pub use window::{RETENTION_DAYS, Span, Window};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize)]
pub struct TokenUsage {
pub input: u64,
pub output: u64,
pub cache_read: u64,
pub cache_write: u64,
}
impl TokenUsage {
#[must_use]
pub fn total(&self) -> u64 {
self.input
.saturating_add(self.output)
.saturating_add(self.cache_read)
.saturating_add(self.cache_write)
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.total() == 0
}
#[must_use]
pub fn saturating_add(self, other: Self) -> Self {
Self {
input: self.input.saturating_add(other.input),
output: self.output.saturating_add(other.output),
cache_read: self.cache_read.saturating_add(other.cache_read),
cache_write: self.cache_write.saturating_add(other.cache_write),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum CostSource {
Reported,
RateCard,
Unreported,
}
impl CostSource {
#[must_use]
pub fn is_measured(&self) -> bool {
matches!(self, Self::Reported)
}
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct RunCost {
pub run: RunId,
pub itinerary: ItineraryId,
pub agent: AgentName,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pipeline: Option<crate::pipeline::PipelineName>,
pub model: Option<String>,
pub usage: TokenUsage,
pub usd: f64,
pub source: CostSource,
pub at: Timestamp,
}
impl RunCost {
#[must_use]
pub fn reported(
run: RunId,
itinerary: ItineraryId,
agent: AgentName,
model: Option<String>,
usage: TokenUsage,
usd: f64,
) -> Self {
let implausible = usd == 0.0 && !usage.is_empty();
let (usd, source) = if usd.is_finite() && usd >= 0.0 && !implausible {
(usd, CostSource::Reported)
} else {
(0.0, CostSource::Unreported)
};
Self {
run,
itinerary,
agent,
pipeline: None,
model,
usage,
usd,
source,
at: Timestamp::now(),
}
}
#[must_use]
pub fn unreported(
run: RunId,
itinerary: ItineraryId,
agent: AgentName,
model: Option<String>,
) -> Self {
Self {
run,
itinerary,
agent,
pipeline: None,
model,
usage: TokenUsage::default(),
usd: 0.0,
source: CostSource::Unreported,
at: Timestamp::now(),
}
}
#[must_use]
pub fn from_pipeline(mut self, pipeline: crate::pipeline::PipelineName) -> Self {
self.pipeline = Some(pipeline);
self
}
#[must_use]
pub fn at(mut self, at: Timestamp) -> Self {
self.at = at;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
fn usage() -> TokenUsage {
TokenUsage {
input: 1_000,
output: 500,
cache_read: 250,
cache_write: 100,
}
}
fn run_cost(usd: f64) -> RunCost {
RunCost::reported(
RunId::generate(),
ItineraryId::generate(),
"analyst".into(),
Some("claude-opus-5".to_owned()),
usage(),
usd,
)
}
#[test]
fn token_totals_cover_every_billed_kind() {
assert_eq!(usage().total(), 1_850);
assert!(!usage().is_empty());
assert!(TokenUsage::default().is_empty());
}
#[test]
fn token_usage_adds_without_wrapping() {
let huge = TokenUsage {
input: u64::MAX,
..TokenUsage::default()
};
assert_eq!(huge.saturating_add(usage()).input, u64::MAX);
}
#[test]
fn a_reported_cost_is_marked_as_measured() {
let cost = run_cost(1.25);
assert_eq!(cost.source, CostSource::Reported);
assert!(cost.source.is_measured());
assert!((cost.usd - 1.25).abs() < 1e-9);
}
#[test]
fn a_genuine_zero_is_still_a_report() {
let cost = RunCost::reported(
RunId::generate(),
ItineraryId::generate(),
"analyst".into(),
None,
TokenUsage::default(),
0.0,
);
assert_eq!(cost.source, CostSource::Reported);
}
#[test]
fn zero_dollars_alongside_real_tokens_is_silence_rather_than_a_measurement() {
let cost = run_cost(0.0);
assert_eq!(cost.source, CostSource::Unreported);
assert!(
!cost.usage.is_empty(),
"the tokens are kept so a rate card can price it"
);
}
#[test]
fn an_implausible_report_is_downgraded_rather_than_trusted() {
for bad in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY, -1.0] {
let cost = run_cost(bad);
assert_eq!(
cost.source,
CostSource::Unreported,
"{bad} must not be treated as a measured cost"
);
assert!((cost.usd - 0.0).abs() < f64::EPSILON);
}
}
#[test]
fn an_unreported_run_carries_no_figures_at_all() {
let cost = RunCost::unreported(
RunId::generate(),
ItineraryId::generate(),
"analyst".into(),
None,
);
assert_eq!(cost.source, CostSource::Unreported);
assert!(!cost.source.is_measured());
assert!(cost.usage.is_empty());
}
#[test]
fn sources_order_from_most_to_least_trustworthy() {
assert!(CostSource::Reported < CostSource::RateCard);
assert!(CostSource::RateCard < CostSource::Unreported);
}
}