use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use crate::model::types::{Message, Usage};
mod usage_serde {
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use super::Usage;
#[derive(Serialize, Deserialize)]
struct UsageRepr {
#[serde(default)]
input_tokens: u32,
#[serde(default)]
output_tokens: u32,
#[serde(default)]
cached_tokens: u32,
}
pub(super) fn serialize<S>(usage: &Usage, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
UsageRepr {
input_tokens: usage.input_tokens,
output_tokens: usage.output_tokens,
cached_tokens: usage.cached_tokens,
}
.serialize(serializer)
}
pub(super) fn deserialize<'de, D>(deserializer: D) -> Result<Usage, D::Error>
where
D: Deserializer<'de>,
{
let repr = UsageRepr::deserialize(deserializer)?;
Ok(Usage {
input_tokens: repr.input_tokens,
output_tokens: repr.output_tokens,
cached_tokens: repr.cached_tokens,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CheckpointState {
pub run_id: String,
pub messages: Vec<Message>,
pub iteration: usize,
pub completed: bool,
pub metadata: HashMap<String, serde_json::Value>,
pub created_at: u64,
#[serde(default)]
pub cumulative_cost: f64,
#[serde(default, with = "usage_serde")]
pub usage: Usage,
}
impl CheckpointState {
pub fn new(run_id: impl Into<String>, messages: Vec<Message>, iteration: usize) -> Self {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs();
Self {
run_id: run_id.into(),
messages,
iteration,
completed: false,
metadata: HashMap::new(),
created_at: now,
cumulative_cost: 0.0,
usage: Usage::default(),
}
}
pub fn with_cost_usage(mut self, cost: f64, usage: Usage) -> Self {
self.cumulative_cost = cost;
self.usage = usage;
self
}
pub fn mark_completed(mut self) -> Self {
self.completed = true;
self
}
pub fn with_metadata(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
self.metadata.insert(key.into(), value);
self
}
}