1pub mod heatmap;
2pub mod overview;
3pub mod project;
4pub mod session;
5pub mod trend;
6pub mod validate;
7pub mod wrapped;
8
9use crate::data::models::{
10 AttributionData, GlobalDataQuality, HookUsage, PluginUsage, PrLinkInfo, SkillUsage,
11 SubagentTypeAggregate, TokenUsage,
12};
13use chrono::{DateTime, NaiveDate, Utc};
14use serde::Serialize;
15use std::collections::HashMap;
16
17#[derive(Debug, Default, Clone, Serialize)]
20pub struct AggregatedTokens {
21 pub input_tokens: u64,
22 pub output_tokens: u64,
23 pub cache_creation_tokens: u64, pub cache_write_5m_tokens: u64, pub cache_write_1h_tokens: u64, pub cache_read_tokens: u64,
27 pub turns: usize,
28}
29
30impl AggregatedTokens {
31 pub fn add_usage(&mut self, usage: &TokenUsage) {
32 self.input_tokens += usage.input_tokens.unwrap_or(0);
33 self.output_tokens += usage.output_tokens.unwrap_or(0);
34 self.cache_creation_tokens += usage.cache_creation_input_tokens.unwrap_or(0);
35 self.cache_read_tokens += usage.cache_read_input_tokens.unwrap_or(0);
36
37 if let Some(ref detail) = usage.cache_creation {
39 self.cache_write_5m_tokens += detail.ephemeral_5m_input_tokens.unwrap_or(0);
40 self.cache_write_1h_tokens += detail.ephemeral_1h_input_tokens.unwrap_or(0);
41 }
42
43 self.turns += 1;
44 }
45
46 pub fn context_tokens(&self) -> u64 {
47 self.input_tokens + self.cache_creation_tokens + self.cache_read_tokens
48 }
49}
50
51#[derive(Debug, Clone, Default, Serialize)]
54pub struct TurnCostBreakdown {
55 pub input_cost: f64,
56 pub output_cost: f64,
57 pub cache_write_5m_cost: f64,
58 pub cache_write_1h_cost: f64,
59 pub cache_read_cost: f64,
60 pub total: f64,
61}
62
63#[derive(Debug, Default, Serialize)]
64pub struct CostByCategory {
65 pub input_cost: f64,
66 pub output_cost: f64,
67 pub cache_write_5m_cost: f64,
68 pub cache_write_1h_cost: f64,
69 pub cache_read_cost: f64,
70}
71
72pub struct OverviewResult {
75 pub total_sessions: usize,
76 pub total_turns: usize,
77 pub total_agent_turns: usize,
78 pub tokens_by_model: HashMap<String, AggregatedTokens>,
79 pub cost_by_model: HashMap<String, f64>,
80 pub total_cost: f64,
81 pub hourly_distribution: [usize; 24],
82 pub quality: GlobalDataQuality,
83 pub subscription_value: Option<SubscriptionValue>,
84 pub weekday_hour_matrix: [[usize; 24]; 7], pub tool_counts: Vec<(String, usize)>, pub cost_by_category: CostByCategory, pub session_summaries: Vec<SessionSummary>, pub total_output_tokens: u64,
90 pub total_context_tokens: u64,
91 pub avg_cache_hit_rate: f64,
92 pub cache_savings: CacheSavings,
93 pub output_ratio: f64, pub cost_per_turn: f64, pub tokens_per_output_turn: u64, pub pricing_warnings: Vec<PricingWarning>,
101}
102
103#[derive(Debug, Clone, Serialize)]
105pub struct PricingWarning {
106 pub unknown_model: String,
108 pub fallback_to: String,
110 pub turn_count: u64,
112 pub fallback_cost: f64,
114}
115
116#[derive(Debug, Default, Serialize)]
118pub struct CacheSavings {
119 pub total_saved: f64, pub without_cache_cost: f64, pub with_cache_cost: f64, pub savings_pct: f64, pub by_model: Vec<(String, f64)>, }
125
126#[derive(Debug, Serialize)]
127pub struct SubscriptionValue {
128 pub monthly_price: f64,
129 pub api_equivalent: f64,
130 pub value_multiplier: f64,
131}
132
133#[derive(Debug, Serialize)]
136pub struct ProjectResult {
137 pub projects: Vec<ProjectSummary>,
138}
139
140#[derive(Debug, Serialize)]
141pub struct ProjectSummary {
142 pub name: String,
143 pub display_name: String,
144 pub session_count: usize,
145 pub total_turns: usize,
146 pub agent_turns: usize,
147 pub tokens: AggregatedTokens,
148 pub cost: f64,
149 pub primary_model: String,
150}
151
152#[derive(Debug, Serialize)]
155pub struct SessionResult {
156 pub session_id: String,
157 pub project: String,
158 pub turn_details: Vec<TurnDetail>,
159 pub agent_summary: AgentSummary,
160 pub total_tokens: AggregatedTokens,
161 pub total_cost: f64,
162 pub stop_reason_counts: HashMap<String, usize>,
163 pub duration_minutes: f64,
165 pub max_context: u64,
166 pub compaction_count: usize,
167 pub cache_write_5m_pct: f64, pub cache_write_1h_pct: f64, pub model: String, pub title: Option<String>,
172 pub tags: Vec<String>,
173 pub mode: Option<String>,
174 pub pr_links: Vec<PrLinkInfo>,
175 pub user_prompt_count: usize,
177 pub autonomy_ratio: f64, pub api_error_count: usize,
180 pub tool_error_count: usize,
181 pub truncated_count: usize, pub speculation_accepts: usize,
184 pub speculation_time_saved_ms: f64,
185 pub service_tiers: HashMap<String, usize>,
187 pub speeds: HashMap<String, usize>,
188 pub inference_geos: HashMap<String, usize>,
189 pub git_branches: HashMap<String, usize>,
191 pub collapse_count: usize,
193 pub collapse_summaries: Vec<String>,
194 pub collapse_avg_risk: f64,
195 pub collapse_max_risk: f64,
196 pub attribution: Option<AttributionData>,
198 pub subagents: Vec<SubagentSummary>,
201 pub plugins: Vec<PluginUsage>,
202 pub skills: Vec<SkillUsage>,
203 pub hooks: Vec<HookUsage>,
204 pub subagent_types: Vec<SubagentTypeAggregate>,
208 pub is_orphan: bool,
211}
212
213#[derive(Debug, Serialize, Clone)]
218pub struct SubagentSummary {
219 pub agent_id: String,
220 pub agent_type: Option<String>,
221 pub description: Option<String>,
222 pub turns: usize,
223 pub output_tokens: u64,
224 pub cost: f64,
225}
226
227#[derive(Debug, Serialize)]
228pub struct TurnDetail {
229 pub turn_number: usize,
230 pub timestamp: DateTime<Utc>,
231 pub model: String,
232 pub input_tokens: u64,
233 pub output_tokens: u64,
234 pub cache_write_5m_tokens: u64, pub cache_write_1h_tokens: u64, pub cache_read_tokens: u64,
237 pub context_size: u64,
238 pub cache_hit_rate: f64,
239 pub cost: f64,
240 pub cost_breakdown: TurnCostBreakdown, pub stop_reason: Option<String>,
242 pub is_agent: bool,
243 pub is_compaction: bool, pub context_delta: i64, pub user_text: Option<String>, pub assistant_text: Option<String>, pub tool_names: Vec<String>, }
249
250#[derive(Debug, Default, Serialize)]
251pub struct AgentSummary {
252 pub total_agent_turns: usize,
253 pub agent_output_tokens: u64,
254 pub agent_cost: f64,
255 pub agents: Vec<AgentDetail>,
256}
257
258#[derive(Debug, Serialize)]
259pub struct AgentDetail {
260 pub agent_id: String,
261 pub agent_type: String,
262 pub description: String,
263 pub turns: usize,
264 pub output_tokens: u64,
265 pub cost: f64,
266}
267
268#[derive(Debug, Serialize)]
272pub struct SessionSummary {
273 pub session_id: String,
274 pub project_display_name: String,
275 pub first_timestamp: Option<DateTime<Utc>>,
276 pub duration_minutes: f64,
277 pub model: String, pub turn_count: usize,
279 pub agent_turn_count: usize,
280 pub output_tokens: u64,
281 pub context_tokens: u64,
282 pub max_context: u64,
283 pub cache_hit_rate: f64, pub cache_write_5m_pct: f64, pub compaction_count: usize,
286 pub cost: f64,
287 pub tool_use_count: usize, pub top_tools: Vec<(String, usize)>, pub turn_details: Option<Vec<TurnDetail>>, pub output_ratio: f64, pub cost_per_turn: f64, pub is_orphan: bool,
296}
297
298#[derive(Debug, Serialize)]
301pub struct TrendResult {
302 pub entries: Vec<TrendEntry>,
303 pub group_label: String, }
305
306#[derive(Debug, Serialize)]
307pub struct TrendEntry {
308 pub label: String, pub date: NaiveDate,
310 pub session_count: usize,
311 pub turn_count: usize,
312 pub tokens: AggregatedTokens,
313 pub cost: f64,
314 pub models: HashMap<String, u64>,
315 pub cost_by_category: CostByCategory,
317}
318
319pub type DailyStats = TrendEntry;