use chrono::{DateTime, Utc};
use klieo_runlog::types::{Cost, RunStatus, Usage};
use serde::Serialize;
#[non_exhaustive]
#[derive(Debug, Clone, Serialize)]
pub struct RunLogSummary {
pub run_id: String,
#[allow(missing_docs)]
pub agent: String,
#[allow(missing_docs)]
pub status: RunStatus,
pub started_at: DateTime<Utc>,
pub finished_at: Option<DateTime<Utc>>,
pub tokens: Usage,
pub cost_estimate: Option<Cost>,
}
impl RunLogSummary {
pub fn from_run_log(log: &klieo_runlog::RunLog) -> Self {
Self {
run_id: log.run_id.to_string(),
agent: log.agent.clone(),
status: log.status,
started_at: log.started_at,
finished_at: log.finished_at,
tokens: log.tokens,
cost_estimate: log.cost_estimate,
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Serialize)]
pub struct AgentSummary {
pub agent: String,
pub last_seen: DateTime<Utc>,
#[allow(missing_docs)]
pub runs_running: u32,
#[allow(missing_docs)]
pub runs_completed: u32,
#[allow(missing_docs)]
pub runs_failed: u32,
#[allow(missing_docs)]
pub runs_cancelled: u32,
}
#[non_exhaustive]
#[derive(Debug, Clone, Serialize)]
pub struct StreamSummary {
pub stream_id: String,
pub is_terminal: bool,
pub next_id: u64,
pub last_write_unix_ms: u64,
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::Utc;
use klieo_core::ids::RunId;
use klieo_runlog::types::RunStatus;
#[test]
fn run_log_summary_serialises_run_id_as_string() {
let run_id = RunId::new();
let summary = RunLogSummary {
run_id: run_id.to_string(),
agent: "test-agent".into(),
status: RunStatus::Running,
started_at: Utc::now(),
finished_at: None,
tokens: Usage::default(),
cost_estimate: None,
};
let json = serde_json::to_string(&summary).unwrap();
assert!(
json.contains(&format!("\"run_id\":\"{}\"", run_id)),
"run_id not serialised as string, got: {json}"
);
assert!(json.contains("\"status\":\"running\""), "got: {json}");
assert!(json.contains("\"agent\":\"test-agent\""), "got: {json}");
}
#[test]
fn agent_summary_serialises() {
let summary = AgentSummary {
agent: "writer".into(),
last_seen: Utc::now(),
runs_running: 1,
runs_completed: 5,
runs_failed: 0,
runs_cancelled: 0,
};
let json = serde_json::to_string(&summary).unwrap();
assert!(json.contains("\"agent\":\"writer\""), "got: {json}");
assert!(json.contains("\"runs_completed\":5"), "got: {json}");
}
#[test]
fn stream_summary_serialises() {
let summary = StreamSummary {
stream_id: "s-001".into(),
is_terminal: false,
next_id: 7,
last_write_unix_ms: 1_000_000,
};
let json = serde_json::to_string(&summary).unwrap();
assert!(json.contains("\"stream_id\":\"s-001\""), "got: {json}");
assert!(json.contains("\"next_id\":7"), "got: {json}");
}
}