use serde::{Deserialize, Serialize};
pub const DEFAULT_MAX_CONCURRENT_SESSIONS: u32 = 5;
pub const DEFAULT_LAUNCH_STAGGER_MS: u64 = 2_000;
pub const DEFAULT_AUTH_TIMEOUT_SECS: u64 = 30;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default)]
pub struct ControlPlaneConfig {
pub max_concurrent_sessions: u32,
pub launch_stagger_ms: u64,
pub auth_timeout_secs: u64,
pub observability: ObservabilityConfig,
}
impl Default for ControlPlaneConfig {
fn default() -> Self {
Self {
max_concurrent_sessions: DEFAULT_MAX_CONCURRENT_SESSIONS,
launch_stagger_ms: DEFAULT_LAUNCH_STAGGER_MS,
auth_timeout_secs: DEFAULT_AUTH_TIMEOUT_SECS,
observability: ObservabilityConfig::default(),
}
}
}
impl ControlPlaneConfig {
pub fn stagger_duration(&self) -> std::time::Duration {
std::time::Duration::from_millis(self.launch_stagger_ms)
}
pub fn auth_timeout(&self) -> std::time::Duration {
std::time::Duration::from_secs(self.auth_timeout_secs)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default)]
pub struct ObservabilityConfig {
pub llm_classifier: bool,
}
impl Default for ObservabilityConfig {
fn default() -> Self {
Self {
llm_classifier: false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn control_plane_config_absent_is_default() {
let cfg: ControlPlaneConfig = toml::from_str("").expect("empty input parses");
assert_eq!(cfg, ControlPlaneConfig::default());
}
#[test]
fn control_plane_config_default_values() {
let cfg = ControlPlaneConfig::default();
assert_eq!(cfg.max_concurrent_sessions, 5);
assert_eq!(cfg.launch_stagger_ms, 2_000);
assert_eq!(cfg.auth_timeout_secs, 30);
assert!(!cfg.observability.llm_classifier);
}
#[test]
fn observability_classifier_default_off() {
assert!(!ObservabilityConfig::default().llm_classifier);
}
#[test]
fn control_plane_config_full_parsed() {
let toml = r#"
max_concurrent_sessions = 8
launch_stagger_ms = 500
auth_timeout_secs = 45
[observability]
llm_classifier = true
"#;
let cfg: ControlPlaneConfig = toml::from_str(toml).expect("full config parses");
assert_eq!(cfg.max_concurrent_sessions, 8);
assert_eq!(cfg.launch_stagger_ms, 500);
assert_eq!(cfg.auth_timeout_secs, 45);
assert!(cfg.observability.llm_classifier);
}
#[test]
fn control_plane_config_partial_takes_defaults() {
let toml = r#"
launch_stagger_ms = 0
"#;
let cfg: ControlPlaneConfig = toml::from_str(toml).expect("partial config parses");
assert_eq!(cfg.launch_stagger_ms, 0);
assert_eq!(cfg.max_concurrent_sessions, 5);
assert_eq!(cfg.auth_timeout_secs, 30);
assert_eq!(cfg.observability, ObservabilityConfig::default());
}
#[test]
fn control_plane_config_stagger_duration() {
let cfg = ControlPlaneConfig {
launch_stagger_ms: 1_500,
..Default::default()
};
assert_eq!(
cfg.stagger_duration(),
std::time::Duration::from_millis(1_500)
);
let zero = ControlPlaneConfig {
launch_stagger_ms: 0,
..Default::default()
};
assert_eq!(zero.stagger_duration(), std::time::Duration::ZERO);
}
#[test]
fn control_plane_config_auth_timeout_duration() {
let cfg = ControlPlaneConfig::default();
assert_eq!(cfg.auth_timeout(), std::time::Duration::from_secs(30));
}
}