use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "snake_case")]
#[derive(Default)]
pub enum AiMode {
GenerateOnceFreeze,
#[default]
Live,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub struct AiStudioConfig {
#[serde(default)]
pub deterministic_mode: DeterministicModeConfig,
#[serde(default)]
pub budgets: BudgetConfig,
#[serde(default)]
pub features: FeatureConfig,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "snake_case")]
#[derive(Default)]
pub enum FreezeMode {
Auto,
#[default]
Manual,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub struct DeterministicModeConfig {
#[serde(default = "default_false")]
pub enabled: bool,
#[serde(default)]
pub mode: FreezeMode,
#[serde(default = "default_true")]
pub auto_freeze: bool,
#[serde(default = "default_freeze_format")]
pub freeze_format: String,
#[serde(default = "default_freeze_directory")]
pub freeze_directory: String,
#[serde(default = "default_true")]
pub track_metadata: bool,
}
impl DeterministicModeConfig {
pub fn is_auto_freeze_enabled(&self) -> bool {
self.mode == FreezeMode::Auto || self.auto_freeze
}
}
impl Default for DeterministicModeConfig {
fn default() -> Self {
Self {
enabled: false,
mode: FreezeMode::Manual,
auto_freeze: true, freeze_format: "yaml".to_string(),
freeze_directory: ".mockforge/frozen".to_string(),
track_metadata: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub struct BudgetConfig {
#[serde(default = "default_max_tokens")]
pub max_tokens_per_workspace: u64,
#[serde(default = "default_max_calls")]
pub max_ai_calls_per_day: u64,
#[serde(default = "default_rate_limit")]
pub rate_limit_per_minute: u64,
#[serde(default = "default_alert_threshold")]
pub alert_threshold: f64,
}
impl Default for BudgetConfig {
fn default() -> Self {
Self {
max_tokens_per_workspace: 100_000,
max_ai_calls_per_day: 1_000,
rate_limit_per_minute: 10,
alert_threshold: 0.8, }
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub struct FeatureConfig {
#[serde(default = "default_true")]
pub mock_generation: bool,
#[serde(default = "default_true")]
pub contract_diff: bool,
#[serde(default = "default_true")]
pub persona_generation: bool,
#[serde(default = "default_true")]
pub free_form_generation: bool,
#[serde(default = "default_true")]
pub debug_analysis: bool,
}
impl Default for FeatureConfig {
fn default() -> Self {
Self {
mock_generation: true,
contract_diff: true,
persona_generation: true,
free_form_generation: true,
debug_analysis: true,
}
}
}
fn default_false() -> bool {
false
}
fn default_true() -> bool {
true
}
fn default_freeze_format() -> String {
"yaml".to_string()
}
fn default_freeze_directory() -> String {
".mockforge/frozen".to_string()
}
fn default_max_tokens() -> u64 {
100_000
}
fn default_max_calls() -> u64 {
1_000
}
fn default_rate_limit() -> u64 {
10
}
fn default_alert_threshold() -> f64 {
0.8
}