Skip to main content

mockforge_core/ai_studio/
config.rs

1//! Configuration for AI Studio
2//!
3//! This module defines configuration structures for the AI Studio, including
4//! deterministic mode settings, budget controls, and feature toggles.
5
6use serde::{Deserialize, Serialize};
7
8/// AI mode for workspace
9///
10/// Controls how AI-generated artifacts are used at runtime.
11#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
12#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
13#[serde(rename_all = "snake_case")]
14#[derive(Default)]
15pub enum AiMode {
16    /// Generate once and freeze - AI is only used to produce config/templates.
17    /// Runtime mocks use frozen artifacts (no LLM calls).
18    GenerateOnceFreeze,
19
20    /// Live mode - AI is used dynamically at runtime for each request.
21    #[default]
22    Live,
23}
24
25/// AI Studio configuration
26#[derive(Debug, Clone, Serialize, Deserialize, Default)]
27#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
28pub struct AiStudioConfig {
29    /// Deterministic mode configuration
30    #[serde(default)]
31    pub deterministic_mode: DeterministicModeConfig,
32
33    /// Budget and cost controls
34    #[serde(default)]
35    pub budgets: BudgetConfig,
36
37    /// Feature toggles
38    #[serde(default)]
39    pub features: FeatureConfig,
40}
41
42/// Freeze mode for deterministic artifacts
43#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
44#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
45#[serde(rename_all = "snake_case")]
46#[derive(Default)]
47pub enum FreezeMode {
48    /// Auto-freeze: Automatically freeze artifacts after generation
49    Auto,
50    /// Manual freeze: Require explicit user action to freeze artifacts
51    #[default]
52    Manual,
53}
54
55/// Deterministic mode configuration
56///
57/// When enabled, AI-generated artifacts are frozen to deterministic YAML/JSON files
58/// for version control and reproducible testing. Supports both auto and manual freeze modes.
59#[derive(Debug, Clone, Serialize, Deserialize)]
60#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
61pub struct DeterministicModeConfig {
62    /// Whether deterministic mode is enabled
63    #[serde(default = "default_false")]
64    pub enabled: bool,
65
66    /// Freeze mode: auto (freeze immediately) or manual (require explicit action)
67    #[serde(default)]
68    pub mode: FreezeMode,
69
70    /// Automatically freeze AI-generated artifacts after creation
71    /// (deprecated: use mode instead, but kept for backward compatibility)
72    #[serde(default = "default_true")]
73    pub auto_freeze: bool,
74
75    /// Format for frozen artifacts (yaml or json)
76    #[serde(default = "default_freeze_format")]
77    pub freeze_format: String,
78
79    /// Directory to store frozen artifacts
80    #[serde(default = "default_freeze_directory")]
81    pub freeze_directory: String,
82
83    /// Whether to track metadata (LLM version, prompt hash, output hash)
84    #[serde(default = "default_true")]
85    pub track_metadata: bool,
86}
87
88impl DeterministicModeConfig {
89    /// Check if auto-freeze is enabled (either via mode or legacy auto_freeze flag)
90    pub fn is_auto_freeze_enabled(&self) -> bool {
91        self.mode == FreezeMode::Auto || self.auto_freeze
92    }
93}
94
95impl Default for DeterministicModeConfig {
96    fn default() -> Self {
97        Self {
98            enabled: false,
99            mode: FreezeMode::Manual,
100            auto_freeze: true, // Legacy support
101            freeze_format: "yaml".to_string(),
102            freeze_directory: ".mockforge/frozen".to_string(),
103            track_metadata: true,
104        }
105    }
106}
107
108/// Budget configuration for AI usage
109#[derive(Debug, Clone, Serialize, Deserialize)]
110#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
111pub struct BudgetConfig {
112    /// Maximum tokens per workspace
113    #[serde(default = "default_max_tokens")]
114    pub max_tokens_per_workspace: u64,
115
116    /// Maximum AI calls per day
117    #[serde(default = "default_max_calls")]
118    pub max_ai_calls_per_day: u64,
119
120    /// Rate limit per minute
121    #[serde(default = "default_rate_limit")]
122    pub rate_limit_per_minute: u64,
123
124    /// Budget alerts threshold (percentage)
125    #[serde(default = "default_alert_threshold")]
126    pub alert_threshold: f64,
127}
128
129impl Default for BudgetConfig {
130    fn default() -> Self {
131        Self {
132            max_tokens_per_workspace: 100_000,
133            max_ai_calls_per_day: 1_000,
134            rate_limit_per_minute: 10,
135            alert_threshold: 0.8, // Alert at 80% usage
136        }
137    }
138}
139
140/// Feature configuration for enabling/disabling specific AI features
141#[derive(Debug, Clone, Serialize, Deserialize)]
142#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
143pub struct FeatureConfig {
144    /// Enable mock generation from natural language
145    #[serde(default = "default_true")]
146    pub mock_generation: bool,
147
148    /// Enable AI contract diff analysis
149    #[serde(default = "default_true")]
150    pub contract_diff: bool,
151
152    /// Enable persona generation
153    #[serde(default = "default_true")]
154    pub persona_generation: bool,
155
156    /// Enable free-form generation (general chat)
157    #[serde(default = "default_true")]
158    pub free_form_generation: bool,
159
160    /// Enable AI-guided debugging
161    #[serde(default = "default_true")]
162    pub debug_analysis: bool,
163}
164
165impl Default for FeatureConfig {
166    fn default() -> Self {
167        Self {
168            mock_generation: true,
169            contract_diff: true,
170            persona_generation: true,
171            free_form_generation: true,
172            debug_analysis: true,
173        }
174    }
175}
176
177// Helper functions for default values
178
179fn default_false() -> bool {
180    false
181}
182
183fn default_true() -> bool {
184    true
185}
186
187fn default_freeze_format() -> String {
188    "yaml".to_string()
189}
190
191fn default_freeze_directory() -> String {
192    ".mockforge/frozen".to_string()
193}
194
195fn default_max_tokens() -> u64 {
196    100_000
197}
198
199fn default_max_calls() -> u64 {
200    1_000
201}
202
203fn default_rate_limit() -> u64 {
204    10
205}
206
207fn default_alert_threshold() -> f64 {
208    0.8
209}