diff --git a/codex-rs/core/config.schema.json b/codex-rs/core/config.schema.json index c51b05185f..5f72e108ec 100644 --- a/codex-rs/core/config.schema.json +++ b/codex-rs/core/config.schema.json @@ -1130,6 +1130,9 @@ "incremental_tools_legacy": { "type": "boolean" }, + "incremental_tools_legacy_gcp": { + "type": "boolean" + }, "instant_interrupt": { "type": "boolean" }, @@ -8197,6 +8200,9 @@ "incremental_tools_legacy": { "type": "boolean" }, + "incremental_tools_legacy_gcp": { + "type": "boolean" + }, "instant_interrupt": { "type": "boolean" }, diff --git a/codex-rs/core/src/session/step_context.rs b/codex-rs/core/src/session/step_context.rs index e7647026ad..4da137bc3f 100644 --- a/codex-rs/core/src/session/step_context.rs +++ b/codex-rs/core/src/session/step_context.rs @@ -62,11 +62,13 @@ impl StepContext { if self.settings.model_info.use_responses_lite { Some(Feature::IncrementalTools) } else { - matches!( - self.turn.config.model_provider_id.as_str(), - AMAZON_BEDROCK_PROVIDER_ID | AMAZON_BEDROCK_RUNTIME_PROVIDER_ID | GCP_PROVIDER_ID - ) - .then_some(Feature::IncrementalToolsLegacy) + match self.turn.config.model_provider_id.as_str() { + AMAZON_BEDROCK_PROVIDER_ID | AMAZON_BEDROCK_RUNTIME_PROVIDER_ID => { + Some(Feature::IncrementalToolsLegacy) + } + GCP_PROVIDER_ID => Some(Feature::IncrementalToolsLegacyGcp), + _ => None, + } } } diff --git a/codex-rs/core/tests/suite/compact_remote.rs b/codex-rs/core/tests/suite/compact_remote.rs index faa68b07f0..2f65cf709d 100644 --- a/codex-rs/core/tests/suite/compact_remote.rs +++ b/codex-rs/core/tests/suite/compact_remote.rs @@ -581,6 +581,10 @@ async fn provider_automatic_compaction_uses_v2_responses_endpoint( config.model_provider_id = GCP_PROVIDER_ID.to_string(); config.model_provider = provider; config.model_reasoning_summary = Some(ReasoningSummary::Detailed); + config + .features + .enable(Feature::IncrementalToolsLegacyGcp) + .expect("enable incremental tools on Vertex"); config .features .enable(Feature::RemoteCompactionV2) @@ -652,7 +656,7 @@ async fn provider_automatic_compaction_uses_v2_responses_endpoint( request.header("x-openai-internal-codex-responses-lite"), None ); - assert!(request.inputs_of_type("additional_tools").is_empty()); + assert!(!request.inputs_of_type("additional_tools").is_empty()); } } } diff --git a/codex-rs/core/tests/suite/gcp.rs b/codex-rs/core/tests/suite/gcp.rs index d2895cfc51..6cb6322970 100644 --- a/codex-rs/core/tests/suite/gcp.rs +++ b/codex-rs/core/tests/suite/gcp.rs @@ -136,8 +136,12 @@ async fn vertex_requests_use_command_auth_with_namespaces_and_tool_search( config.base_instructions = Some("Vertex test instructions".to_string()); config .features - .set_enabled(Feature::IncrementalToolsLegacy, incremental_tools) + .set_enabled(Feature::IncrementalToolsLegacyGcp, incremental_tools) .expect("configure incremental tools on Vertex"); + config + .features + .set_enabled(Feature::IncrementalToolsLegacy, !incremental_tools) + .expect("configure independent Bedrock flag"); }) .build_with_auto_env(&server) .await?; diff --git a/codex-rs/core/tests/suite/scenarios_incremental_tools.rs b/codex-rs/core/tests/suite/scenarios_incremental_tools.rs index adf50701bb..ddebaf69c1 100644 --- a/codex-rs/core/tests/suite/scenarios_incremental_tools.rs +++ b/codex-rs/core/tests/suite/scenarios_incremental_tools.rs @@ -152,21 +152,25 @@ async fn prediction_fork_keeps_inherited_tools() -> Result<()> { Ok(()) } -#[test_case(true, None, true, OPENAI_PROVIDER_ID; "responses_lite")] -#[test_case(true, Some(true), true, OPENAI_PROVIDER_ID; "announcements_suppressed")] -#[test_case(false, None, false, OPENAI_PROVIDER_ID; "responses_api")] -#[test_case(false, None, false, AMAZON_BEDROCK_PROVIDER_ID; "mantle_provider_id")] -#[test_case(false, None, true, AMAZON_BEDROCK_PROVIDER_ID; "mantle_provider_id_incremental")] -#[test_case(false, None, false, AMAZON_BEDROCK_RUNTIME_PROVIDER_ID; "runtime_provider_id")] -#[test_case(false, None, true, AMAZON_BEDROCK_RUNTIME_PROVIDER_ID; "runtime_provider_id_incremental")] -#[test_case(false, None, false, GCP_PROVIDER_ID; "gcp_provider_id")] -#[test_case(false, None, true, GCP_PROVIDER_ID; "gcp_provider_id_incremental")] +#[test_case(true, None, true, OPENAI_PROVIDER_ID, &[]; "responses_lite")] +#[test_case(true, Some(true), true, OPENAI_PROVIDER_ID, &[]; "announcements_suppressed")] +#[test_case(false, None, false, OPENAI_PROVIDER_ID, &[]; "responses_api")] +#[test_case(false, None, false, AMAZON_BEDROCK_PROVIDER_ID, &[]; "mantle_default")] +#[test_case(false, None, true, AMAZON_BEDROCK_PROVIDER_ID, + &[(Feature::IncrementalToolsLegacy, true), (Feature::IncrementalToolsLegacyGcp, false)]; "mantle_enabled")] +#[test_case(false, None, false, AMAZON_BEDROCK_RUNTIME_PROVIDER_ID, &[]; "runtime_default")] +#[test_case(false, None, true, AMAZON_BEDROCK_RUNTIME_PROVIDER_ID, + &[(Feature::IncrementalToolsLegacy, true), (Feature::IncrementalToolsLegacyGcp, false)]; "runtime_enabled")] +#[test_case(false, None, true, GCP_PROVIDER_ID, &[]; "gcp_default")] +#[test_case(false, None, false, GCP_PROVIDER_ID, + &[(Feature::IncrementalToolsLegacyGcp, false), (Feature::IncrementalToolsLegacy, true)]; "gcp_opt_out")] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn incremental_tools_append_changed_catalog_without_rewriting_history( use_responses_lite: bool, suppress_model_change_announcements: Option, incremental_tools: bool, provider_id: &'static str, + feature_overrides: &'static [(Feature, bool)], ) -> Result<()> { skip_if_no_network!(Ok(())); let server = responses::start_mock_server().await; @@ -214,15 +218,11 @@ async fn incremental_tools_append_changed_catalog_without_rewriting_history( }) .with_config(move |config| { config.model_provider_id = provider_id.to_string(); - if !use_responses_lite && incremental_tools { + for &(feature, enabled) in feature_overrides { config .features - .disable(Feature::IncrementalTools) - .expect("disable the Lite flag"); - config - .features - .enable(Feature::IncrementalToolsLegacy) - .expect("enable incremental tools on regular Responses"); + .set_enabled(feature, enabled) + .expect("configure independent provider flags"); } if let Some(suppress) = suppress_model_change_announcements { config diff --git a/codex-rs/features/src/lib.rs b/codex-rs/features/src/lib.rs index 3b0eeed8c0..253164a8e3 100644 --- a/codex-rs/features/src/lib.rs +++ b/codex-rs/features/src/lib.rs @@ -310,8 +310,10 @@ pub enum Feature { CommandSessionsWorldState, /// Track top-level tool definitions in world state and emit incremental context updates. IncrementalTools, - /// Publish incremental tool declarations on regular Amazon Bedrock and GCP Responses. + /// Publish incremental tool declarations on regular Amazon Bedrock Responses. IncrementalToolsLegacy, + /// Publish incremental tool declarations on regular GCP Responses. + IncrementalToolsLegacyGcp, /// Suppress the model ID announcement in incremental context after a model switch. SuppressModelChangeAnnouncements, /// Preserve inherited tool declarations in MCP-disabled prediction forks. @@ -1821,9 +1823,15 @@ pub const FEATURES: &[FeatureSpec] = &[ FeatureSpec { id: Feature::IncrementalToolsLegacy, key: "incremental_tools_legacy", - stage: Stage::UnderDevelopment, + stage: Stage::Stable, default_enabled: false, }, + FeatureSpec { + id: Feature::IncrementalToolsLegacyGcp, + key: "incremental_tools_legacy_gcp", + stage: Stage::Stable, + default_enabled: true, + }, FeatureSpec { id: Feature::SuppressModelChangeAnnouncements, key: "suppress_model_change_announcements",