Skip to main content

codex/builder/
types.rs

1use std::path::PathBuf;
2
3const REASONING_CONFIG_KEYS: &[&str] = &[
4    "model_reasoning_effort",
5    "model_reasoning_summary",
6    "model_verbosity",
7    "model_reasoning_summary_format",
8    "model_supports_reasoning_summaries",
9];
10
11/// ANSI color behavior for `codex exec` output.
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13pub enum ColorMode {
14    /// Match upstream defaults: use color codes when stdout/stderr look like terminals.
15    Auto,
16    /// Force colorful output even when piping.
17    Always,
18    /// Fully disable ANSI sequences for deterministic parsing/logging (default).
19    Never,
20}
21
22impl ColorMode {
23    pub(crate) const fn as_str(self) -> &'static str {
24        match self {
25            ColorMode::Auto => "auto",
26            ColorMode::Always => "always",
27            ColorMode::Never => "never",
28        }
29    }
30}
31
32/// Approval policy used by `--ask-for-approval`.
33#[derive(Clone, Copy, Debug, Eq, PartialEq)]
34pub enum ApprovalPolicy {
35    Untrusted,
36    OnFailure,
37    OnRequest,
38    Never,
39}
40
41impl ApprovalPolicy {
42    pub(super) const fn as_str(self) -> &'static str {
43        match self {
44            ApprovalPolicy::Untrusted => "untrusted",
45            ApprovalPolicy::OnFailure => "on-failure",
46            ApprovalPolicy::OnRequest => "on-request",
47            ApprovalPolicy::Never => "never",
48        }
49    }
50}
51
52/// Sandbox isolation level.
53#[derive(Clone, Copy, Debug, Eq, PartialEq)]
54pub enum SandboxMode {
55    ReadOnly,
56    WorkspaceWrite,
57    DangerFullAccess,
58}
59
60impl SandboxMode {
61    pub(super) const fn as_str(self) -> &'static str {
62        match self {
63            SandboxMode::ReadOnly => "read-only",
64            SandboxMode::WorkspaceWrite => "workspace-write",
65            SandboxMode::DangerFullAccess => "danger-full-access",
66        }
67    }
68}
69
70/// Safety overrides that collapse approval/sandbox behavior.
71#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
72pub enum SafetyOverride {
73    #[default]
74    Inherit,
75    FullAuto,
76    DangerouslyBypass,
77}
78
79/// Local provider selection for OSS backends.
80#[derive(Clone, Copy, Debug, Eq, PartialEq)]
81pub enum LocalProvider {
82    LmStudio,
83    Ollama,
84    Custom,
85}
86
87impl LocalProvider {
88    pub(super) const fn as_str(self) -> &'static str {
89        match self {
90            LocalProvider::LmStudio => "lmstudio",
91            LocalProvider::Ollama => "ollama",
92            LocalProvider::Custom => "custom",
93        }
94    }
95}
96
97/// Three-state flag used when requests can override builder defaults.
98#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
99pub enum FlagState {
100    #[default]
101    Inherit,
102    Enable,
103    Disable,
104}
105
106/// Feature toggles forwarded to `--enable/--disable`.
107#[derive(Clone, Debug, Default, Eq, PartialEq)]
108pub struct FeatureToggles {
109    pub enable: Vec<String>,
110    pub disable: Vec<String>,
111}
112
113/// Config values for `model_reasoning_effort`.
114#[derive(Clone, Copy, Debug, Eq, PartialEq)]
115pub enum ReasoningEffort {
116    Minimal,
117    Low,
118    Medium,
119    High,
120}
121
122impl ReasoningEffort {
123    pub(super) const fn as_str(self) -> &'static str {
124        match self {
125            ReasoningEffort::Minimal => "minimal",
126            ReasoningEffort::Low => "low",
127            ReasoningEffort::Medium => "medium",
128            ReasoningEffort::High => "high",
129        }
130    }
131}
132
133/// Config values for `model_reasoning_summary`.
134#[derive(Clone, Copy, Debug, Eq, PartialEq)]
135pub enum ReasoningSummary {
136    Auto,
137    Concise,
138    Detailed,
139    None,
140}
141
142impl ReasoningSummary {
143    pub(super) const fn as_str(self) -> &'static str {
144        match self {
145            ReasoningSummary::Auto => "auto",
146            ReasoningSummary::Concise => "concise",
147            ReasoningSummary::Detailed => "detailed",
148            ReasoningSummary::None => "none",
149        }
150    }
151}
152
153/// Config values for `model_verbosity`.
154#[derive(Clone, Copy, Debug, Eq, PartialEq)]
155pub enum ModelVerbosity {
156    Low,
157    Medium,
158    High,
159}
160
161impl ModelVerbosity {
162    pub(super) const fn as_str(self) -> &'static str {
163        match self {
164            ModelVerbosity::Low => "low",
165            ModelVerbosity::Medium => "medium",
166            ModelVerbosity::High => "high",
167        }
168    }
169}
170
171/// Config values for `model_reasoning_summary_format`.
172#[derive(Clone, Copy, Debug, Eq, PartialEq)]
173pub enum ReasoningSummaryFormat {
174    None,
175    Experimental,
176}
177
178impl ReasoningSummaryFormat {
179    pub(super) const fn as_str(self) -> &'static str {
180        match self {
181            ReasoningSummaryFormat::None => "none",
182            ReasoningSummaryFormat::Experimental => "experimental",
183        }
184    }
185}
186
187/// Represents a single `--config key=value` override.
188#[derive(Clone, Debug, Eq, PartialEq)]
189pub struct ConfigOverride {
190    pub key: String,
191    pub value: String,
192}
193
194impl ConfigOverride {
195    pub fn new(key: impl Into<String>, value: impl Into<String>) -> Self {
196        Self {
197            key: key.into(),
198            value: value.into(),
199        }
200    }
201
202    pub fn from_raw(raw: impl Into<String>) -> Self {
203        let raw = raw.into();
204        let (key, value) = raw
205            .split_once('=')
206            .map(|(key, value)| (key.to_string(), value.to_string()))
207            .unwrap_or_else(|| (raw.clone(), String::new()));
208        ConfigOverride { key, value }
209    }
210
211    pub(super) fn is_reasoning_key(&self) -> bool {
212        REASONING_CONFIG_KEYS.contains(&self.key.as_str())
213    }
214}
215
216/// Structured reasoning overrides converted into config entries.
217#[derive(Clone, Debug, Default, Eq, PartialEq)]
218pub struct ReasoningOverrides {
219    pub effort: Option<ReasoningEffort>,
220    pub summary: Option<ReasoningSummary>,
221    pub verbosity: Option<ModelVerbosity>,
222    pub summary_format: Option<ReasoningSummaryFormat>,
223    pub supports_summaries: Option<bool>,
224}
225
226impl ReasoningOverrides {
227    pub(crate) fn has_overrides(&self) -> bool {
228        self.effort.is_some()
229            || self.summary.is_some()
230            || self.verbosity.is_some()
231            || self.summary_format.is_some()
232            || self.supports_summaries.is_some()
233    }
234
235    pub(super) fn append_overrides(&self, configs: &mut Vec<ConfigOverride>) {
236        if let Some(value) = self.effort {
237            configs.push(ConfigOverride::new(
238                "model_reasoning_effort",
239                value.as_str(),
240            ));
241        }
242        if let Some(value) = self.summary {
243            configs.push(ConfigOverride::new(
244                "model_reasoning_summary",
245                value.as_str(),
246            ));
247        }
248        if let Some(value) = self.verbosity {
249            configs.push(ConfigOverride::new("model_verbosity", value.as_str()));
250        }
251        if let Some(value) = self.summary_format {
252            configs.push(ConfigOverride::new(
253                "model_reasoning_summary_format",
254                value.as_str(),
255            ));
256        }
257        if let Some(value) = self.supports_summaries {
258            configs.push(ConfigOverride::new(
259                "model_supports_reasoning_summaries",
260                value.to_string(),
261            ));
262        }
263    }
264}
265
266/// Builder-scoped CLI overrides.
267#[derive(Clone, Debug, Eq, PartialEq)]
268pub struct CliOverrides {
269    pub config_overrides: Vec<ConfigOverride>,
270    pub feature_toggles: FeatureToggles,
271    pub reasoning: ReasoningOverrides,
272    pub approval_policy: Option<ApprovalPolicy>,
273    pub sandbox_mode: Option<SandboxMode>,
274    pub safety_override: SafetyOverride,
275    pub profile: Option<String>,
276    pub cd: Option<PathBuf>,
277    pub local_provider: Option<LocalProvider>,
278    pub oss: FlagState,
279    pub search: FlagState,
280    pub auto_reasoning_defaults: bool,
281}
282
283impl Default for CliOverrides {
284    fn default() -> Self {
285        Self {
286            config_overrides: Vec::new(),
287            feature_toggles: FeatureToggles::default(),
288            reasoning: ReasoningOverrides::default(),
289            approval_policy: None,
290            sandbox_mode: None,
291            safety_override: SafetyOverride::Inherit,
292            profile: None,
293            cd: None,
294            local_provider: None,
295            oss: FlagState::Inherit,
296            search: FlagState::Inherit,
297            auto_reasoning_defaults: true,
298        }
299    }
300}
301
302/// Request-level overlay of builder overrides.
303#[derive(Clone, Debug, Default, Eq, PartialEq)]
304pub struct CliOverridesPatch {
305    pub config_overrides: Vec<ConfigOverride>,
306    pub feature_toggles: FeatureToggles,
307    pub reasoning: ReasoningOverrides,
308    pub approval_policy: Option<ApprovalPolicy>,
309    pub sandbox_mode: Option<SandboxMode>,
310    pub safety_override: Option<SafetyOverride>,
311    pub profile: Option<String>,
312    pub cd: Option<PathBuf>,
313    pub local_provider: Option<LocalProvider>,
314    pub oss: FlagState,
315    pub search: FlagState,
316    pub auto_reasoning_defaults: Option<bool>,
317}