use serde::{Deserialize, Serialize};
use agent_sdk_core::{AgentError, RunId, RunTrace};
use crate::{CostPolicy, CostReport, UsageReport};
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct RunReportLimitations {
pub items: Vec<String>,
}
impl RunReportLimitations {
pub fn from_parts(usage: &UsageReport, cost: Option<&CostReport>) -> Self {
let mut items = usage.limitations.clone();
if let Some(cost) = cost {
items.extend(cost.limitations.clone());
} else {
items.push("cost report was not requested".to_string());
}
items.sort();
items.dedup();
Self { items }
}
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct RunReport {
pub run_id: RunId,
pub usage: UsageReport,
pub cost: Option<CostReport>,
pub limitations: RunReportLimitations,
}
impl RunReport {
pub fn from_run_trace(
trace: &RunTrace,
cost_policy: Option<&dyn CostPolicy>,
) -> Result<Self, AgentError> {
let run_id = trace.run_id.clone().ok_or_else(|| {
AgentError::contract_violation("run report requires a run trace with run_id")
})?;
let usage = UsageReport::from_run_trace(trace)?;
let cost = cost_policy.map(|policy| policy.estimate_cost(&usage));
let limitations = RunReportLimitations::from_parts(&usage, cost.as_ref());
Ok(Self {
run_id,
usage,
cost,
limitations,
})
}
}