use super::types::*;
use agtrace_types::ContextWindowUsage;
use chrono::{DateTime, Utc};
pub fn calculate_session_stats(
turns: &[AgentTurn],
start_time: DateTime<Utc>,
end_time: Option<DateTime<Utc>>,
) -> SessionStats {
let total_turns = turns.len();
let duration_seconds = end_time
.map(|end| (end - start_time).num_seconds())
.unwrap_or(0);
let total_tokens: i64 = turns.iter().map(|t| t.stats.total_tokens as i64).sum();
SessionStats {
total_turns,
duration_seconds,
total_tokens,
}
}
pub fn calculate_turn_stats(steps: &[AgentStep], turn_start: DateTime<Utc>) -> TurnStats {
let step_count = steps.len();
let duration_ms = steps
.last()
.map(|last| (last.timestamp - turn_start).num_milliseconds())
.unwrap_or(0);
let total_tokens: i32 = steps
.iter()
.filter_map(|s| s.usage.as_ref())
.map(|u| u.total_tokens().as_u64() as i32)
.sum();
TurnStats {
duration_ms,
step_count,
total_tokens,
}
}
pub fn merge_usage(
target: &mut Option<ContextWindowUsage>,
source: &agtrace_types::TokenUsagePayload,
) {
let source_usage = ContextWindowUsage::from_raw(
source.input.uncached as i32,
0, source.input.cached as i32,
source.output.total() as i32,
);
if let Some(current) = target {
current.fresh_input.0 = current.fresh_input.0.max(source_usage.fresh_input.0);
current.cache_creation.0 = current.cache_creation.0.max(source_usage.cache_creation.0);
current.cache_read.0 = current.cache_read.0.max(source_usage.cache_read.0);
current.output.0 = current.output.0.max(source_usage.output.0);
} else {
*target = Some(source_usage);
}
}
#[cfg(test)]
mod tests {
use super::*;
use agtrace_types::{TokenInput, TokenOutput, TokenUsagePayload};
#[test]
fn test_merge_usage_with_none() {
let mut target = None;
let source = TokenUsagePayload::new(
TokenInput::new(0, 100), TokenOutput::new(50, 0, 0), );
merge_usage(&mut target, &source);
let result = target.unwrap();
assert_eq!(result.fresh_input.0, 100);
assert_eq!(result.output.0, 50);
assert_eq!(result.cache_creation.0, 0);
assert_eq!(result.cache_read.0, 0);
}
#[test]
fn test_merge_usage_with_existing() {
let mut target = Some(ContextWindowUsage::from_raw(100, 0, 0, 50));
let source = TokenUsagePayload::new(
TokenInput::new(0, 200), TokenOutput::new(100, 0, 0), );
merge_usage(&mut target, &source);
let result = target.unwrap();
assert_eq!(result.fresh_input.0, 200); assert_eq!(result.output.0, 100); assert_eq!(result.cache_creation.0, 0);
assert_eq!(result.cache_read.0, 0);
}
#[test]
fn test_merge_usage_with_cache() {
let mut target = Some(ContextWindowUsage::from_raw(100, 10, 20, 50));
let source = TokenUsagePayload::new(
TokenInput::new(40, 200), TokenOutput::new(70, 30, 0), );
merge_usage(&mut target, &source);
let result = target.unwrap();
assert_eq!(result.fresh_input.0, 200); assert_eq!(result.output.0, 100); assert_eq!(result.cache_creation.0, 10); assert_eq!(result.cache_read.0, 40); }
}