Skip to main content

llm/usage/
session.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4use super::{LlmCallPurpose, ModelIdentity, TokenUsage, UsageCost, UsageSource, Usd};
5
6/// Running token totals and cost estimate across every call an agent has seen.
7#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
8pub struct SessionUsageTotals {
9    pub tokens: TokenUsage,
10    /// Sum of every priced call's estimated cost.
11    pub estimated_usd: Usd,
12    /// Calls with nonzero usage but no catalog pricing, which `estimated_usd`
13    /// therefore leaves out.
14    pub unpriced_calls: u64,
15}
16
17impl SessionUsageTotals {
18    pub fn add(&mut self, tokens: TokenUsage, estimated_cost: Option<UsageCost>) {
19        if tokens.is_zero() {
20            return;
21        }
22        self.tokens += tokens;
23        match estimated_cost {
24            Some(cost) => self.estimated_usd += cost.total_usd,
25            None => self.unpriced_calls += 1,
26        }
27    }
28
29    /// Whether `estimated_usd` accounts for every call with nonzero usage.
30    pub fn is_fully_priced(&self) -> bool {
31        self.unpriced_calls == 0
32    }
33}
34
35/// One provider usage sample, its estimated cost, and the totals after it.
36#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
37pub struct SessionUsageEvent {
38    pub sequence: u64,
39    pub source: UsageSource,
40    pub purpose: LlmCallPurpose,
41    pub model: ModelIdentity,
42    pub tokens: TokenUsage,
43    pub estimated_cost: Option<UsageCost>,
44    pub totals: SessionUsageTotals,
45}