use std::fmt;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
pub const HEAVY_MODEL: &str = "gpt-5.5";
pub const HEAVY_REASONING_EFFORT: &str = "low";
pub const MAIN_MODEL: &str = "gpt-5.4-mini";
pub const MAIN_REASONING_EFFORT: &str = "low";
pub const WORKER_MODEL: &str = "gpt-5.3-codex-spark";
pub const WORKER_REASONING_EFFORT: &str = "medium";
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Tier {
Heavy,
Main,
Worker,
}
impl Tier {
pub fn escalate(self) -> Option<Tier> {
match self {
Tier::Worker => Some(Tier::Main),
Tier::Main => Some(Tier::Heavy),
Tier::Heavy => None,
}
}
pub fn downgrade(self) -> Option<Tier> {
match self {
Tier::Heavy => Some(Tier::Main),
Tier::Main => Some(Tier::Worker),
Tier::Worker => None,
}
}
pub fn spec(self) -> TierSpec {
match self {
Tier::Heavy => TierSpec {
model_id: HEAVY_MODEL,
reasoning_effort: HEAVY_REASONING_EFFORT,
},
Tier::Main => TierSpec {
model_id: MAIN_MODEL,
reasoning_effort: MAIN_REASONING_EFFORT,
},
Tier::Worker => TierSpec {
model_id: WORKER_MODEL,
reasoning_effort: WORKER_REASONING_EFFORT,
},
}
}
}
impl fmt::Display for Tier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let value = match self {
Tier::Heavy => "heavy",
Tier::Main => "main",
Tier::Worker => "worker",
};
f.write_str(value)
}
}
impl FromStr for Tier {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"heavy" => Ok(Tier::Heavy),
"main" => Ok(Tier::Main),
"worker" => Ok(Tier::Worker),
other => Err(format!("invalid tier {other}: use heavy, main, or worker")),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct TierSpec {
pub model_id: &'static str,
pub reasoning_effort: &'static str,
}