use serde::{Deserialize, Serialize};
use crate::agent::Agent;
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Usage {
pub input_tokens: Option<u64>,
pub output_tokens: Option<u64>,
pub cache_read_tokens: Option<u64>,
pub cache_write_tokens: Option<u64>,
pub cost_usd: Option<f64>,
pub premium_requests: Option<u64>,
}
impl Usage {
#[must_use]
pub fn is_empty(&self) -> bool {
*self == Usage::default()
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct RateLimit {
pub status: String,
pub window: Option<String>,
pub resets_at: Option<i64>,
}
impl RateLimit {
#[must_use]
pub fn is_blocking(&self) -> bool {
!self.status.eq_ignore_ascii_case("allowed")
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum Stop {
#[default]
Completed,
Error,
Other(String),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Outcome {
pub agent: Agent,
pub session: Option<String>,
pub text: String,
pub usage: Usage,
pub stop: Stop,
pub rate_limit: Option<RateLimit>,
pub exit_code: i32,
pub stderr: String,
pub unparsed: usize,
pub first_unparsed: Option<String>,
pub structured: Option<serde_json::Value>,
}
impl Outcome {
#[must_use]
pub fn is_ok(&self) -> bool {
self.exit_code == 0 && self.stop == Stop::Completed
}
#[must_use]
pub fn looks_like_a_format_change(&self) -> bool {
self.exit_code == 0 && self.unparsed > 0 && self.text.trim().is_empty()
}
}