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