Skip to content
Merged
88 changes: 64 additions & 24 deletions codex-rs/app-server/src/codex_message_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1668,14 +1668,23 @@ impl CodexMessageProcessor {
..Default::default()
};

// Persist windows sandbox feature.
// Persist Windows sandbox mode.
// TODO: persist default config in general.
let mut request_overrides = request_overrides.unwrap_or_default();
if cfg!(windows) && self.config.features.enabled(Feature::WindowsSandbox) {
request_overrides.insert(
"features.experimental_windows_sandbox".to_string(),
serde_json::json!(true),
);
if cfg!(windows) {
match WindowsSandboxLevel::from_config(&self.config) {
WindowsSandboxLevel::Elevated => {
request_overrides
.insert("windows.sandbox".to_string(), serde_json::json!("elevated"));
}
WindowsSandboxLevel::RestrictedToken => {
request_overrides.insert(
"windows.sandbox".to_string(),
serde_json::json!("unelevated"),
);
}
WindowsSandboxLevel::Disabled => {}
}
}

let cloud_requirements = self.current_cloud_requirements();
Expand Down Expand Up @@ -2770,13 +2779,22 @@ impl CodexMessageProcessor {
read_history_cwd_from_state_db(&self.config, source_thread_id, rollout_path.as_path())
.await;

// Persist windows sandbox feature.
// Persist Windows sandbox mode.
let mut cli_overrides = cli_overrides.unwrap_or_default();
if cfg!(windows) && self.config.features.enabled(Feature::WindowsSandbox) {
cli_overrides.insert(
"features.experimental_windows_sandbox".to_string(),
serde_json::json!(true),
);
if cfg!(windows) {
match WindowsSandboxLevel::from_config(&self.config) {
WindowsSandboxLevel::Elevated => {
cli_overrides
.insert("windows.sandbox".to_string(), serde_json::json!("elevated"));
}
WindowsSandboxLevel::RestrictedToken => {
cli_overrides.insert(
"windows.sandbox".to_string(),
serde_json::json!("unelevated"),
);
}
WindowsSandboxLevel::Disabled => {}
}
}
let request_overrides = if cli_overrides.is_empty() {
None
Expand Down Expand Up @@ -3681,13 +3699,24 @@ impl CodexMessageProcessor {
include_apply_patch_tool,
} = overrides;

// Persist windows sandbox feature.
// Persist Windows sandbox mode.
let mut request_overrides = request_overrides.unwrap_or_default();
if cfg!(windows) && self.config.features.enabled(Feature::WindowsSandbox) {
request_overrides.insert(
"features.experimental_windows_sandbox".to_string(),
serde_json::json!(true),
);
if cfg!(windows) {
match WindowsSandboxLevel::from_config(&self.config) {
WindowsSandboxLevel::Elevated => {
request_overrides.insert(
"windows.sandbox".to_string(),
serde_json::json!("elevated"),
);
}
WindowsSandboxLevel::RestrictedToken => {
request_overrides.insert(
"windows.sandbox".to_string(),
serde_json::json!("unelevated"),
);
}
WindowsSandboxLevel::Disabled => {}
}
}

let typesafe_overrides = ConfigOverrides {
Expand Down Expand Up @@ -3860,13 +3889,24 @@ impl CodexMessageProcessor {
include_apply_patch_tool,
} = overrides;

// Persist windows sandbox feature.
// Persist Windows sandbox mode.
let mut cli_overrides = cli_overrides.unwrap_or_default();
if cfg!(windows) && self.config.features.enabled(Feature::WindowsSandbox) {
cli_overrides.insert(
"features.experimental_windows_sandbox".to_string(),
serde_json::json!(true),
);
if cfg!(windows) {
match WindowsSandboxLevel::from_config(&self.config) {
WindowsSandboxLevel::Elevated => {
cli_overrides.insert(
"windows.sandbox".to_string(),
serde_json::json!("elevated"),
);
}
WindowsSandboxLevel::RestrictedToken => {
cli_overrides.insert(
"windows.sandbox".to_string(),
serde_json::json!("unelevated"),
);
}
WindowsSandboxLevel::Disabled => {}
}
}
let request_overrides = if cli_overrides.is_empty() {
None
Expand Down
33 changes: 33 additions & 0 deletions codex-rs/core/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,14 @@
},
"web_search": {
"$ref": "#/definitions/WebSearchMode"
},
"windows": {
"allOf": [
{
"$ref": "#/definitions/WindowsToml"
}
],
"default": null
}
},
"type": "object"
Expand Down Expand Up @@ -1144,6 +1152,22 @@
],
"type": "string"
},
"WindowsSandboxModeToml": {
"enum": [
"elevated",
"unelevated"
],
"type": "string"
},
"WindowsToml": {
"additionalProperties": false,
"properties": {
"sandbox": {
"$ref": "#/definitions/WindowsSandboxModeToml"
}
},
"type": "object"
},
"WireApi": {
"description": "Wire protocol that the provider speaks.",
"oneOf": [
Expand Down Expand Up @@ -1636,6 +1660,15 @@
],
"description": "Controls the web search tool mode: disabled, cached, or live."
},
"windows": {
"allOf": [
{
"$ref": "#/definitions/WindowsToml"
}
],
"default": null,
"description": "Windows-specific configuration."
},
"windows_wsl_setup_acknowledged": {
"description": "Tracks whether the Windows onboarding screen has been acknowledged.",
"type": "boolean"
Expand Down
38 changes: 38 additions & 0 deletions codex-rs/core/src/config/edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,44 @@ impl ConfigEditsBuilder {
self
}

pub fn set_windows_sandbox_mode(mut self, mode: &str) -> Self {
let segments = if let Some(profile) = self.profile.as_ref() {
vec![
"profiles".to_string(),
profile.clone(),
"windows".to_string(),
"sandbox".to_string(),
]
} else {
vec!["windows".to_string(), "sandbox".to_string()]
};
self.edits.push(ConfigEdit::SetPath {
segments,
value: value(mode),
});
self
}

pub fn clear_legacy_windows_sandbox_keys(mut self) -> Self {
for key in [
"experimental_windows_sandbox",
"elevated_windows_sandbox",
"enable_experimental_windows_sandbox",
] {
let mut segments = vec!["features".to_string(), key.to_string()];
if let Some(profile) = self.profile.as_ref() {
segments = vec![
"profiles".to_string(),
profile.clone(),
"features".to_string(),
key.to_string(),
];
}
self.edits.push(ConfigEdit::ClearPath { segments });
}
self
}

pub fn with_edits<I>(mut self, edits: I) -> Self
where
I: IntoIterator<Item = ConfigEdit>,
Expand Down
Loading
Loading