Skip to main content

codex_codes/io/
options.rs

1use serde::{Deserialize, Serialize};
2
3/// Approval mode for tool execution.
4#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
5#[serde(rename_all = "kebab-case")]
6pub enum ApprovalMode {
7    Never,
8    OnRequest,
9    OnFailure,
10    Untrusted,
11}
12
13/// Sandbox mode controlling file system access.
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15#[serde(rename_all = "kebab-case")]
16pub enum SandboxMode {
17    ReadOnly,
18    WorkspaceWrite,
19    DangerFullAccess,
20}
21
22/// Model reasoning effort level.
23#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
24#[serde(rename_all = "snake_case")]
25pub enum ModelReasoningEffort {
26    Minimal,
27    Low,
28    Medium,
29    High,
30    Xhigh,
31}
32
33/// Web search mode.
34#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
35#[serde(rename_all = "snake_case")]
36pub enum WebSearchMode {
37    Disabled,
38    Cached,
39    Live,
40}
41
42/// Per-thread options controlling model, sandbox, and behavior.
43#[derive(Debug, Clone, Default, Serialize, Deserialize)]
44pub struct ThreadOptions {
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub model: Option<String>,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub sandbox_mode: Option<SandboxMode>,
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub working_directory: Option<String>,
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub skip_git_repo_check: Option<bool>,
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub model_reasoning_effort: Option<ModelReasoningEffort>,
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub network_access_enabled: Option<bool>,
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub web_search_mode: Option<WebSearchMode>,
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub web_search_enabled: Option<bool>,
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub approval_policy: Option<ApprovalMode>,
63    #[serde(default, skip_serializing_if = "Vec::is_empty")]
64    pub additional_directories: Vec<String>,
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn test_thread_options_default() {
73        let opts = ThreadOptions::default();
74        assert!(opts.model.is_none());
75        assert!(opts.sandbox_mode.is_none());
76        assert!(opts.additional_directories.is_empty());
77    }
78
79    #[test]
80    fn test_approval_mode_serde() {
81        let json = r#""on-request""#;
82        let mode: ApprovalMode = serde_json::from_str(json).unwrap();
83        assert_eq!(mode, ApprovalMode::OnRequest);
84    }
85
86    #[test]
87    fn test_sandbox_mode_serde() {
88        let json = r#""workspace-write""#;
89        let mode: SandboxMode = serde_json::from_str(json).unwrap();
90        assert_eq!(mode, SandboxMode::WorkspaceWrite);
91    }
92
93    #[test]
94    fn test_reasoning_effort_serde() {
95        let json = r#""xhigh""#;
96        let effort: ModelReasoningEffort = serde_json::from_str(json).unwrap();
97        assert_eq!(effort, ModelReasoningEffort::Xhigh);
98    }
99
100    #[test]
101    fn test_web_search_mode_serde() {
102        let json = r#""live""#;
103        let mode: WebSearchMode = serde_json::from_str(json).unwrap();
104        assert_eq!(mode, WebSearchMode::Live);
105    }
106}