diff --git a/codex-rs/core/src/session/step_context.rs b/codex-rs/core/src/session/step_context.rs index fedbf884c2..e7647026ad 100644 --- a/codex-rs/core/src/session/step_context.rs +++ b/codex-rs/core/src/session/step_context.rs @@ -16,6 +16,7 @@ use codex_file_system::EnvironmentAccess; use codex_mcp::McpBinding; use codex_model_provider_info::AMAZON_BEDROCK_PROVIDER_ID; use codex_model_provider_info::AMAZON_BEDROCK_RUNTIME_PROVIDER_ID; +use codex_model_provider_info::GCP_PROVIDER_ID; use codex_otel::SessionTelemetry; use codex_plugin::ExecutorPluginHookSource; use codex_protocol::items::ModelInvocationContext; @@ -63,7 +64,7 @@ impl StepContext { } else { matches!( self.turn.config.model_provider_id.as_str(), - AMAZON_BEDROCK_PROVIDER_ID | AMAZON_BEDROCK_RUNTIME_PROVIDER_ID + AMAZON_BEDROCK_PROVIDER_ID | AMAZON_BEDROCK_RUNTIME_PROVIDER_ID | GCP_PROVIDER_ID ) .then_some(Feature::IncrementalToolsLegacy) } diff --git a/codex-rs/core/tests/suite/gcp.rs b/codex-rs/core/tests/suite/gcp.rs index 5ab77cd4eb..d2895cfc51 100644 --- a/codex-rs/core/tests/suite/gcp.rs +++ b/codex-rs/core/tests/suite/gcp.rs @@ -94,11 +94,13 @@ async fn vertex_credential_file_is_retained_when_refreshing_after_401() -> Resul Ok(()) } -#[test_case("gpt-6.1-sol"; "sol")] -#[test_case("gpt-6.1-terra"; "terra")] +#[test_case("gpt-6.1-sol", false; "sol")] +#[test_case("gpt-6.1-terra", false; "terra")] +#[test_case("gpt-6.1-sol", true; "sol_incremental")] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn vertex_requests_use_command_auth_with_namespaces_and_tool_search( model: &str, + incremental_tools: bool, ) -> Result<()> { skip_if_no_network!(Ok(())); @@ -132,6 +134,10 @@ async fn vertex_requests_use_command_auth_with_namespaces_and_tool_search( config.model_provider_id = GCP_PROVIDER_ID.to_string(); config.model_provider = provider; config.base_instructions = Some("Vertex test instructions".to_string()); + config + .features + .set_enabled(Feature::IncrementalToolsLegacy, incremental_tools) + .expect("configure incremental tools on Vertex"); }) .build_with_auto_env(&server) .await?; @@ -183,16 +189,22 @@ async fn vertex_requests_use_command_auth_with_namespaces_and_tool_search( request.header("x-openai-internal-codex-responses-lite"), None ); - assert!( - request.inputs_of_type("additional_tools").is_empty(), - "Vertex request must omit Responses Lite additional_tools inputs" - ); + let additional_tools = request.inputs_of_type("additional_tools"); + assert_eq!(additional_tools.len(), usize::from(incremental_tools)); let body = request.body_json(); assert_eq!(body["model"], model); assert_eq!(request.instructions_text(), "Vertex test instructions"); - let tools = body["tools"] + let top_level_tools = body["tools"] .as_array() .context("Vertex request should include model tools")?; + let tools = if incremental_tools { + assert!(top_level_tools.is_empty()); + additional_tools[0]["tools"] + .as_array() + .context("Vertex request should include incremental model tools")? + } else { + top_level_tools + }; assert_eq!( test.codex.multi_agent_version(), Some(MultiAgentVersion::V2) @@ -221,9 +233,14 @@ async fn vertex_requests_use_command_auth_with_namespaces_and_tool_search( "Vertex request should expose client-side tool search: {tools:?}" ); assert!( - tools - .iter() - .any(|tool| tool.get("name").and_then(Value::as_str) == Some("exec_command")), + if incremental_tools { + responses::namespace_child_tool(&additional_tools[0], "functions", "exec_command") + .is_some() + } else { + tools + .iter() + .any(|tool| tool.get("name").and_then(Value::as_str) == Some("exec_command")) + }, "Vertex request should preserve the exec_command function tool: {tools:?}" ); diff --git a/codex-rs/core/tests/suite/scenarios_incremental_tools.rs b/codex-rs/core/tests/suite/scenarios_incremental_tools.rs index 5c0a219cb4..adf50701bb 100644 --- a/codex-rs/core/tests/suite/scenarios_incremental_tools.rs +++ b/codex-rs/core/tests/suite/scenarios_incremental_tools.rs @@ -7,6 +7,7 @@ use codex_core::compact::AutoCompactionDisabled; use codex_features::Feature; use codex_model_provider_info::AMAZON_BEDROCK_PROVIDER_ID; use codex_model_provider_info::AMAZON_BEDROCK_RUNTIME_PROVIDER_ID; +use codex_model_provider_info::GCP_PROVIDER_ID; use codex_model_provider_info::OPENAI_PROVIDER_ID; use codex_otel::MetricsClient; use codex_otel::MetricsConfig; @@ -158,6 +159,8 @@ async fn prediction_fork_keeps_inherited_tools() -> Result<()> { #[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")] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn incremental_tools_append_changed_catalog_without_rewriting_history( use_responses_lite: bool, diff --git a/codex-rs/features/src/lib.rs b/codex-rs/features/src/lib.rs index ad9c53372a..5c2c64b44d 100644 --- a/codex-rs/features/src/lib.rs +++ b/codex-rs/features/src/lib.rs @@ -308,7 +308,7 @@ 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 Responses. + /// Publish incremental tool declarations on regular Amazon Bedrock and GCP Responses. IncrementalToolsLegacy, /// Suppress the model ID announcement in incremental context after a model switch. SuppressModelChangeAnnouncements,