claude_code_acp/types/
session.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10pub struct TokenUsage {
11 pub input_tokens: u64,
13
14 pub output_tokens: u64,
16
17 #[serde(skip_serializing_if = "Option::is_none")]
19 pub cache_read_input_tokens: Option<u64>,
20
21 #[serde(skip_serializing_if = "Option::is_none")]
23 pub cache_creation_input_tokens: Option<u64>,
24}
25
26impl TokenUsage {
27 pub fn new() -> Self {
29 Self::default()
30 }
31
32 pub fn from_sdk_usage(usage: &serde_json::Value) -> Self {
38 Self {
39 input_tokens: usage["input_tokens"].as_u64().unwrap_or(0),
40 output_tokens: usage["output_tokens"].as_u64().unwrap_or(0),
41 cache_read_input_tokens: usage["cache_read_input_tokens"].as_u64(),
42 cache_creation_input_tokens: usage["cache_creation_input_tokens"].as_u64(),
43 }
44 }
45
46 pub fn add(&mut self, other: &TokenUsage) {
48 self.input_tokens += other.input_tokens;
49 self.output_tokens += other.output_tokens;
50
51 if let Some(v) = other.cache_read_input_tokens {
52 *self.cache_read_input_tokens.get_or_insert(0) += v;
53 }
54 if let Some(v) = other.cache_creation_input_tokens {
55 *self.cache_creation_input_tokens.get_or_insert(0) += v;
56 }
57 }
58
59 pub fn total(&self) -> u64 {
61 self.input_tokens + self.output_tokens
62 }
63
64 pub fn is_empty(&self) -> bool {
66 self.input_tokens == 0 && self.output_tokens == 0
67 }
68}
69
70#[derive(Debug, Clone, Default)]
72pub struct SessionStats {
73 pub active_sessions: usize,
75
76 pub total_usage: TokenUsage,
78
79 pub total_cost_usd: f64,
81}
82
83impl SessionStats {
84 pub fn new() -> Self {
86 Self::default()
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 use serde_json::json;
94
95 #[test]
96 fn test_token_usage_default() {
97 let usage = TokenUsage::default();
98 assert_eq!(usage.input_tokens, 0);
99 assert_eq!(usage.output_tokens, 0);
100 assert!(usage.cache_read_input_tokens.is_none());
101 assert!(usage.is_empty());
102 assert_eq!(usage.total(), 0);
103 }
104
105 #[test]
106 fn test_token_usage_from_sdk() {
107 let sdk_usage = json!({
108 "input_tokens": 1000,
109 "output_tokens": 500,
110 "cache_read_input_tokens": 200,
111 "cache_creation_input_tokens": 100
112 });
113
114 let usage = TokenUsage::from_sdk_usage(&sdk_usage);
115 assert_eq!(usage.input_tokens, 1000);
116 assert_eq!(usage.output_tokens, 500);
117 assert_eq!(usage.cache_read_input_tokens, Some(200));
118 assert_eq!(usage.cache_creation_input_tokens, Some(100));
119 assert_eq!(usage.total(), 1500);
120 assert!(!usage.is_empty());
121 }
122
123 #[test]
124 fn test_token_usage_add() {
125 let mut usage1 = TokenUsage {
126 input_tokens: 100,
127 output_tokens: 50,
128 cache_read_input_tokens: Some(10),
129 cache_creation_input_tokens: None,
130 };
131
132 let usage2 = TokenUsage {
133 input_tokens: 200,
134 output_tokens: 100,
135 cache_read_input_tokens: Some(20),
136 cache_creation_input_tokens: Some(5),
137 };
138
139 usage1.add(&usage2);
140
141 assert_eq!(usage1.input_tokens, 300);
142 assert_eq!(usage1.output_tokens, 150);
143 assert_eq!(usage1.cache_read_input_tokens, Some(30));
144 assert_eq!(usage1.cache_creation_input_tokens, Some(5));
145 }
146
147 #[test]
148 fn test_token_usage_serialization() {
149 let usage = TokenUsage {
150 input_tokens: 100,
151 output_tokens: 50,
152 cache_read_input_tokens: None,
153 cache_creation_input_tokens: None,
154 };
155
156 let json = serde_json::to_string(&usage).unwrap();
157 let parsed: TokenUsage = serde_json::from_str(&json).unwrap();
158
159 assert_eq!(parsed.input_tokens, 100);
160 assert_eq!(parsed.output_tokens, 50);
161 }
162}