diff --git a/codex-rs/core/src/features.rs b/codex-rs/core/src/features.rs index 12abb6fd6..37e0256ed 100644 --- a/codex-rs/core/src/features.rs +++ b/codex-rs/core/src/features.rs @@ -711,12 +711,8 @@ pub const FEATURES: &[FeatureSpec] = &[ FeatureSpec { id: Feature::Collab, key: "multi_agent", - stage: Stage::Experimental { - name: "Subagents", - menu_description: "Ask Codex to spawn subagents to parallelize the work and move faster.", - announcement: "NEW: Subagents can now be spawned by Codex. Enable in /experimental and restart Codex!", - }, - default_enabled: false, + stage: Stage::Stable, + default_enabled: true, }, FeatureSpec { id: Feature::SpawnCsv, diff --git a/codex-rs/core/src/features_tests.rs b/codex-rs/core/src/features_tests.rs index 4098279c4..98ffbadaf 100644 --- a/codex-rs/core/src/features_tests.rs +++ b/codex-rs/core/src/features_tests.rs @@ -145,6 +145,12 @@ fn collab_is_legacy_alias_for_multi_agent() { assert_eq!(feature_for_key("collab"), Some(Feature::Collab)); } +#[test] +fn multi_agent_is_stable_and_enabled_by_default() { + assert_eq!(Feature::Collab.stage(), Stage::Stable); + assert_eq!(Feature::Collab.default_enabled(), true); +} + #[test] fn enable_fanout_is_under_development() { assert_eq!(Feature::SpawnCsv.stage(), Stage::UnderDevelopment); diff --git a/codex-rs/core/src/tools/spec_tests.rs b/codex-rs/core/src/tools/spec_tests.rs index 856861f69..2f2256813 100644 --- a/codex-rs/core/src/tools/spec_tests.rs +++ b/codex-rs/core/src/tools/spec_tests.rs @@ -459,6 +459,11 @@ fn test_full_toolset_specs_for_gpt5_codex_unified_exec_web_search() { search_content_types: None, }, create_view_image_tool(config.can_request_original_image_detail), + create_spawn_agent_tool(&config), + create_send_input_tool(), + create_resume_agent_tool(), + create_wait_tool(), + create_close_agent_tool(), ] { expected.insert(tool_name(&spec).to_string(), spec); } @@ -1184,6 +1189,11 @@ fn test_build_specs_gpt5_codex_default() { "apply_patch", "web_search", "view_image", + "spawn_agent", + "send_input", + "resume_agent", + "wait", + "close_agent", ], ); } @@ -1202,6 +1212,11 @@ fn test_build_specs_gpt51_codex_default() { "apply_patch", "web_search", "view_image", + "spawn_agent", + "send_input", + "resume_agent", + "wait", + "close_agent", ], ); } @@ -1222,6 +1237,11 @@ fn test_build_specs_gpt5_codex_unified_exec_web_search() { "apply_patch", "web_search", "view_image", + "spawn_agent", + "send_input", + "resume_agent", + "wait", + "close_agent", ], ); } @@ -1242,6 +1262,11 @@ fn test_build_specs_gpt51_codex_unified_exec_web_search() { "apply_patch", "web_search", "view_image", + "spawn_agent", + "send_input", + "resume_agent", + "wait", + "close_agent", ], ); } @@ -1260,6 +1285,11 @@ fn test_gpt_5_1_codex_max_defaults() { "apply_patch", "web_search", "view_image", + "spawn_agent", + "send_input", + "resume_agent", + "wait", + "close_agent", ], ); } @@ -1278,6 +1308,11 @@ fn test_codex_5_1_mini_defaults() { "apply_patch", "web_search", "view_image", + "spawn_agent", + "send_input", + "resume_agent", + "wait", + "close_agent", ], ); } @@ -1295,6 +1330,11 @@ fn test_gpt_5_defaults() { "request_user_input", "web_search", "view_image", + "spawn_agent", + "send_input", + "resume_agent", + "wait", + "close_agent", ], ); } @@ -1313,6 +1353,11 @@ fn test_gpt_5_1_defaults() { "apply_patch", "web_search", "view_image", + "spawn_agent", + "send_input", + "resume_agent", + "wait", + "close_agent", ], ); } @@ -1333,6 +1378,11 @@ fn test_gpt_5_1_codex_max_unified_exec_web_search() { "apply_patch", "web_search", "view_image", + "spawn_agent", + "send_input", + "resume_agent", + "wait", + "close_agent", ], ); } diff --git a/codex-rs/core/tests/suite/prompt_caching.rs b/codex-rs/core/tests/suite/prompt_caching.rs index d8fd96ddf..28bebf117 100644 --- a/codex-rs/core/tests/suite/prompt_caching.rs +++ b/codex-rs/core/tests/suite/prompt_caching.rs @@ -177,6 +177,11 @@ async fn prompt_tools_are_consistent_across_requests() -> anyhow::Result<()> { "apply_patch", "web_search", "view_image", + "spawn_agent", + "send_input", + "resume_agent", + "wait", + "close_agent", ]); let body0 = req1.single_request().body_json(); diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index 9f1eaa795..a125ed7d7 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -5074,6 +5074,7 @@ mod tests { #[tokio::test] async fn open_agent_picker_prompts_to_enable_multi_agent_when_disabled() -> Result<()> { let (mut app, mut app_event_rx, _op_rx) = make_test_app_with_channels().await; + let _ = app.config.features.disable(Feature::Collab); app.open_agent_picker().await; app.chat_widget