pub struct TokenUsage {
pub input_tokens: u32,
pub output_tokens: u32,
pub cache_read_tokens: Option<u32>,
pub cache_creation_tokens: Option<u32>,
pub actual_cost_usd: Option<f64>,
pub estimated_cost_usd: Option<f64>,
pub effective_cost_usd: Option<f64>,
}Expand description
Token usage statistics
Tracks token consumption per LLM call including cache tokens for cost optimization.
§Disjoint bucket convention
Prompt token buckets are disjoint (non-overlapping). Drivers normalize provider wire formats at the boundary so this holds for every provider:
total_prompt = input_tokens + cache_read_tokens + cache_creation_tokensinput_tokens— non-cached prompt tokens only.cache_read_tokens— tokens served from cache, never counted ininput_tokens.cache_creation_tokens— tokens written to cache, never counted ininput_tokens.
Inclusive providers (OpenAI Responses / Chat Completions, Gemini) report a
prompt count that includes cached reads; their drivers subtract the cached
subset so the value stored here is the non-cached remainder. Anthropic /
Bedrock already report disjoint buckets. Cost is therefore uniform across
providers (input·in + cache_read·cr + cache_creation·cw + output·out);
consumers must not re-derive a non-cached input by subtracting cache reads.
Fields§
§input_tokens: u32Number of non-cached prompt tokens (cached reads/writes are tracked separately; see the disjoint bucket convention on the struct)
output_tokens: u32Number of output/completion tokens
cache_read_tokens: Option<u32>Number of tokens read from cache (reduces cost), disjoint from input_tokens
cache_creation_tokens: Option<u32>Number of tokens written to cache, disjoint from input_tokens
actual_cost_usd: Option<f64>Actual cost of this generation in USD, as reported by the provider inline
(e.g. OpenRouter’s usage.cost, which reflects real post-routing/BYOK/cache
pricing). None for providers that do not return a cost.
estimated_cost_usd: Option<f64>Estimated cost of this generation in USD, derived from the model’s static
price-table profile. Computed whenever a profile with cost data exists,
independently of actual_cost_usd, so estimate-vs-actual drift can be
reconciled. None when there is no profile cost data for the model.
effective_cost_usd: Option<f64>Best-effort USD cost for already-aggregated usage. Per-generation usage leaves this unset and derives the effective cost from actual/estimated.
Implementations§
Source§impl TokenUsage
impl TokenUsage
Sourcepub fn new(input_tokens: u32, output_tokens: u32) -> Self
pub fn new(input_tokens: u32, output_tokens: u32) -> Self
Create a new TokenUsage with just input and output tokens
Sourcepub fn with_cache(
input_tokens: u32,
output_tokens: u32,
cache_read_tokens: Option<u32>,
cache_creation_tokens: Option<u32>,
) -> Self
pub fn with_cache( input_tokens: u32, output_tokens: u32, cache_read_tokens: Option<u32>, cache_creation_tokens: Option<u32>, ) -> Self
Create a TokenUsage with cache tokens
Sourcepub fn with_cost(
self,
actual_cost_usd: Option<f64>,
estimated_cost_usd: Option<f64>,
) -> Self
pub fn with_cost( self, actual_cost_usd: Option<f64>, estimated_cost_usd: Option<f64>, ) -> Self
Set the actual (provider-reported) and estimated (price-table) USD costs,
returning self for chaining. The two are tracked independently so an
authoritative charge stays distinguishable from an estimate.
Sourcepub fn with_effective_cost(self, effective_cost_usd: Option<f64>) -> Self
pub fn with_effective_cost(self, effective_cost_usd: Option<f64>) -> Self
Set the precomputed best-effort USD cost for aggregate usage, returning
self for chaining. Generation usage should leave this unset so the
best-effort cost remains actual-else-estimated for that generation.
Sourcepub fn effective_cost_usd(&self) -> Option<f64>
pub fn effective_cost_usd(&self) -> Option<f64>
Best-effort cost in USD. Aggregate usage can carry a precomputed total that sums actual-else-estimated per generation; otherwise this falls back to the generation-level actual-else-estimated behavior.
Sourcepub fn total_tokens(&self) -> u32
pub fn total_tokens(&self) -> u32
Get total tokens (input + output)
Sourcepub fn add(&mut self, other: &TokenUsage)
pub fn add(&mut self, other: &TokenUsage)
Add another TokenUsage to this one (for aggregation)
Trait Implementations§
Source§impl Clone for TokenUsage
impl Clone for TokenUsage
Source§fn clone(&self) -> TokenUsage
fn clone(&self) -> TokenUsage
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for TokenUsage
impl Debug for TokenUsage
Source§impl Default for TokenUsage
impl Default for TokenUsage
Source§fn default() -> TokenUsage
fn default() -> TokenUsage
Source§impl<'de> Deserialize<'de> for TokenUsage
impl<'de> Deserialize<'de> for TokenUsage
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for TokenUsage
impl RefUnwindSafe for TokenUsage
impl Send for TokenUsage
impl Sync for TokenUsage
impl Unpin for TokenUsage
impl UnsafeUnpin for TokenUsage
impl UnwindSafe for TokenUsage
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
Source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request