use super::{Currency, ResetPeriod};
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc::UnboundedSender;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BudgetConfig {
pub name: String,
pub max_budget: f64,
pub soft_limit: Option<f64>,
pub reset_period: Option<ResetPeriod>,
pub currency: Option<Currency>,
pub enabled: Option<bool>,
pub metadata: Option<std::collections::HashMap<String, String>>,
}
impl BudgetConfig {
pub fn new(name: impl Into<String>, max_budget: f64) -> Self {
Self {
name: name.into(),
max_budget,
soft_limit: None,
reset_period: None,
currency: None,
enabled: None,
metadata: None,
}
}
pub fn with_soft_limit(mut self, soft_limit: f64) -> Self {
self.soft_limit = Some(soft_limit);
self
}
pub fn with_reset_period(mut self, period: ResetPeriod) -> Self {
self.reset_period = Some(period);
self
}
pub fn with_currency(mut self, currency: Currency) -> Self {
self.currency = Some(currency);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderLimitConfig {
pub max_budget: f64,
pub reset_period: ResetPeriod,
#[serde(default = "default_soft_limit_percentage")]
pub soft_limit_percentage: f64,
#[serde(default)]
pub currency: Currency,
#[serde(default = "default_enabled")]
pub enabled: bool,
}
fn default_soft_limit_percentage() -> f64 {
0.8
}
fn default_enabled() -> bool {
true
}
impl ProviderLimitConfig {
pub fn new(max_budget: f64, reset_period: ResetPeriod) -> Self {
Self {
max_budget,
reset_period,
soft_limit_percentage: 0.8,
currency: Currency::default(),
enabled: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModelLimitConfig {
pub max_budget: f64,
pub reset_period: ResetPeriod,
#[serde(default = "default_soft_limit_percentage")]
pub soft_limit_percentage: f64,
#[serde(default)]
pub currency: Currency,
#[serde(default = "default_enabled")]
pub enabled: bool,
}
impl ModelLimitConfig {
pub fn new(max_budget: f64, reset_period: ResetPeriod) -> Self {
Self {
max_budget,
reset_period,
soft_limit_percentage: 0.8,
currency: Currency::default(),
enabled: true,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum BudgetLimitKind {
Provider,
Model,
}
impl BudgetLimitKind {
pub fn as_str(self) -> &'static str {
match self {
Self::Provider => "provider",
Self::Model => "model",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BudgetLimitSnapshot {
pub kind: BudgetLimitKind,
pub name: String,
pub max_budget: f64,
pub current_spend: f64,
pub soft_limit: f64,
pub reset_period: ResetPeriod,
pub currency: Currency,
pub enabled: bool,
pub last_reset_at: Option<chrono::DateTime<chrono::Utc>>,
pub request_count: u64,
}
impl BudgetLimitSnapshot {
pub fn scope_key(&self) -> String {
format!("{}:{}", self.kind.as_str(), self.name)
}
}
#[derive(Debug, Clone)]
pub enum BudgetPersistenceEvent {
Upsert(BudgetLimitSnapshot),
Delete { kind: BudgetLimitKind, name: String },
}
pub type BudgetPersistenceSender = UnboundedSender<BudgetPersistenceEvent>;