diff --git a/codex-rs/core/config.schema.json b/codex-rs/core/config.schema.json index 420d39e44..828120f9d 100644 --- a/codex-rs/core/config.schema.json +++ b/codex-rs/core/config.schema.json @@ -350,6 +350,9 @@ "apps": { "type": "boolean" }, + "browser_use": { + "type": "boolean" + }, "child_agents_md": { "type": "boolean" }, @@ -422,6 +425,9 @@ "image_generation": { "type": "boolean" }, + "in_app_browser": { + "type": "boolean" + }, "include_apply_patch_tool": { "type": "boolean" }, @@ -2362,6 +2368,9 @@ "apps": { "type": "boolean" }, + "browser_use": { + "type": "boolean" + }, "child_agents_md": { "type": "boolean" }, @@ -2434,6 +2443,9 @@ "image_generation": { "type": "boolean" }, + "in_app_browser": { + "type": "boolean" + }, "include_apply_patch_tool": { "type": "boolean" }, diff --git a/codex-rs/core/src/config/config_tests.rs b/codex-rs/core/src/config/config_tests.rs index 3765e31f5..a0d0583cb 100644 --- a/codex-rs/core/src/config/config_tests.rs +++ b/codex-rs/core/src/config/config_tests.rs @@ -6564,6 +6564,32 @@ async fn feature_requirements_normalize_effective_feature_values() -> std::io::R Ok(()) } +#[tokio::test] +async fn browser_feature_requirements_are_valid() -> std::io::Result<()> { + let codex_home = TempDir::new()?; + + let config = ConfigBuilder::without_managed_config_for_tests() + .codex_home(codex_home.path().to_path_buf()) + .cloud_requirements(CloudRequirementsLoader::new(async { + Ok(Some(crate::config_loader::ConfigRequirementsToml { + feature_requirements: Some(crate::config_loader::FeatureRequirementsToml { + entries: BTreeMap::from([ + ("in_app_browser".to_string(), false), + ("browser_use".to_string(), false), + ]), + }), + ..Default::default() + })) + })) + .build() + .await?; + + assert!(!config.features.enabled(Feature::InAppBrowser)); + assert!(!config.features.enabled(Feature::BrowserUse)); + + Ok(()) +} + #[tokio::test] async fn explicit_feature_config_is_normalized_by_requirements() -> std::io::Result<()> { let codex_home = TempDir::new()?; diff --git a/codex-rs/features/src/lib.rs b/codex-rs/features/src/lib.rs index b8a062f05..18f3eef9e 100644 --- a/codex-rs/features/src/lib.rs +++ b/codex-rs/features/src/lib.rs @@ -156,6 +156,14 @@ pub enum Feature { ToolSuggest, /// Enable plugins. Plugins, + /// Allow the in-app browser pane in desktop apps. + /// + /// Requirements-only gate: this should be set from requirements, not user config. + InAppBrowser, + /// Allow Browser Use agent integration in desktop apps. + /// + /// Requirements-only gate: this should be set from requirements, not user config. + BrowserUse, /// Temporary internal-only flag for PS-backed remote plugin catalog development. RemotePlugin, /// Show the startup prompt for migrating external agent config into Codex. @@ -848,6 +856,18 @@ pub const FEATURES: &[FeatureSpec] = &[ stage: Stage::Stable, default_enabled: true, }, + FeatureSpec { + id: Feature::InAppBrowser, + key: "in_app_browser", + stage: Stage::Stable, + default_enabled: true, + }, + FeatureSpec { + id: Feature::BrowserUse, + key: "browser_use", + stage: Stage::Stable, + default_enabled: true, + }, FeatureSpec { id: Feature::RemotePlugin, key: "remote_plugin", diff --git a/codex-rs/features/src/tests.rs b/codex-rs/features/src/tests.rs index 3f865e316..276e573ab 100644 --- a/codex-rs/features/src/tests.rs +++ b/codex-rs/features/src/tests.rs @@ -150,6 +150,20 @@ fn tool_search_is_stable_and_enabled_by_default() { assert_eq!(Feature::ToolSearch.default_enabled(), true); } +#[test] +fn browser_controls_are_stable_and_enabled_by_default() { + assert_eq!(Feature::InAppBrowser.stage(), Stage::Stable); + assert_eq!(Feature::InAppBrowser.default_enabled(), true); + assert_eq!( + feature_for_key("in_app_browser"), + Some(Feature::InAppBrowser) + ); + + assert_eq!(Feature::BrowserUse.stage(), Stage::Stable); + assert_eq!(Feature::BrowserUse.default_enabled(), true); + assert_eq!(feature_for_key("browser_use"), Some(Feature::BrowserUse)); +} + #[test] fn unavailable_dummy_tools_is_under_development_and_disabled_by_default() { assert_eq!(