diff --git a/codex-rs/core/src/session/turn.rs b/codex-rs/core/src/session/turn.rs index c7d7c63477..e3666553d6 100644 --- a/codex-rs/core/src/session/turn.rs +++ b/codex-rs/core/src/session/turn.rs @@ -1223,7 +1223,7 @@ async fn run_auto_compact( ) .await?; } - RemoteCompactionSupport::V1 | RemoteCompactionSupport::V2 => { + RemoteCompactionSupport::V2 => { emit_compact_metric( &sess.services.session_telemetry, "remote", diff --git a/codex-rs/core/src/tasks/compact.rs b/codex-rs/core/src/tasks/compact.rs index 1c7de737eb..99e2113485 100644 --- a/codex-rs/core/src/tasks/compact.rs +++ b/codex-rs/core/src/tasks/compact.rs @@ -49,7 +49,7 @@ impl SessionTask for CompactTask { ); crate::compact_remote_v2::run_remote_compact_task(session.clone(), ctx).await } - RemoteCompactionSupport::V1 | RemoteCompactionSupport::V2 => { + RemoteCompactionSupport::V2 => { emit_compact_metric( &session.services.session_telemetry, "remote", diff --git a/codex-rs/core/tests/suite/compact_remote.rs b/codex-rs/core/tests/suite/compact_remote.rs index 2012d1a5f5..fda36515ff 100644 --- a/codex-rs/core/tests/suite/compact_remote.rs +++ b/codex-rs/core/tests/suite/compact_remote.rs @@ -456,7 +456,7 @@ fn assert_compact_request_omits_harness_metadata(request: &responses::ResponsesR } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn amazon_bedrock_uses_remote_compaction_endpoint() -> Result<()> { +async fn amazon_bedrock_manual_compaction_uses_v2_responses_endpoint() -> Result<()> { skip_if_no_network!(Ok(())); let harness = TestCodexHarness::with_auto_env_builder(amazon_bedrock_test_codex()).await?; @@ -468,6 +468,16 @@ async fn amazon_bedrock_uses_remote_compaction_endpoint() -> Result<()> { responses::ev_assistant_message("message-1", "before compaction"), responses::ev_completed("response-1"), ]), + sse(vec![ + json!({ + "type": "response.output_item.done", + "item": { + "type": "compaction", + "encrypted_content": "BEDROCK_REMOTE_COMPACTED_SUMMARY", + } + }), + responses::ev_completed("response-compact"), + ]), sse(vec![ responses::ev_assistant_message("message-2", "after compaction"), responses::ev_completed("response-2"), @@ -475,19 +485,20 @@ async fn amazon_bedrock_uses_remote_compaction_endpoint() -> Result<()> { ], ) .await; - let compact_mock = responses::mount_compact_user_history_with_summary_once( - harness.server(), - "BEDROCK_REMOTE_COMPACTED_SUMMARY", - ) - .await; harness.test().submit_turn("before compact").await?; harness.test().codex.submit(Op::Compact).await?; wait_for_turn_complete(&harness.test().codex).await; harness.test().submit_turn("after compact").await?; - let compact_request = compact_mock.single_request(); - assert_eq!(compact_request.path(), "/v1/responses/compact"); + let response_requests = response_mock.requests(); + assert_eq!(response_requests.len(), 3); + assert!( + response_requests + .iter() + .all(|request| request.path() == "/v1/responses") + ); + let compact_request = &response_requests[1]; assert_eq!( compact_request.header("authorization").as_deref(), Some("Bearer bedrock-test-api-key") @@ -502,15 +513,11 @@ async fn amazon_bedrock_uses_remote_compaction_endpoint() -> Result<()> { compact_request.body_json()["model"], AMAZON_BEDROCK_GPT_5_5_MODEL_ID ); - - let response_requests = response_mock.requests(); - assert_eq!(response_requests.len(), 2); - assert!( - response_requests - .iter() - .all(|request| request.inputs_of_type("compaction_trigger").is_empty()) + assert_eq!( + compact_request.inputs_of_type("compaction_trigger").len(), + 1 ); - assert!(response_requests[1].input().iter().any(|item| { + assert!(response_requests[2].input().iter().any(|item| { item["type"] == "compaction" && item["encrypted_content"] == "BEDROCK_REMOTE_COMPACTED_SUMMARY" })); @@ -679,7 +686,7 @@ async fn remote_compact_v2_retains_only_client_developer_messages_when_enabled( } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn amazon_bedrock_automatic_compaction_uses_v1_endpoint_when_v2_is_enabled() -> Result<()> { +async fn amazon_bedrock_automatic_compaction_uses_v2_responses_endpoint() -> Result<()> { skip_if_no_network!(Ok(())); let harness = TestCodexHarness::with_auto_env_builder(amazon_bedrock_test_codex().with_config( @@ -695,6 +702,16 @@ async fn amazon_bedrock_automatic_compaction_uses_v1_endpoint_when_v2_is_enabled responses::ev_assistant_message("message-1", "before automatic compaction"), responses::ev_completed_with_tokens("response-1", /*total_tokens*/ 500), ]), + sse(vec![ + json!({ + "type": "response.output_item.done", + "item": { + "type": "compaction", + "encrypted_content": "BEDROCK_AUTOMATIC_REMOTE_COMPACTED_SUMMARY", + } + }), + responses::ev_completed("response-compact"), + ]), sse(vec![ responses::ev_assistant_message("message-2", "after automatic compaction"), responses::ev_completed("response-2"), @@ -702,11 +719,6 @@ async fn amazon_bedrock_automatic_compaction_uses_v1_endpoint_when_v2_is_enabled ], ) .await; - let compact_mock = responses::mount_compact_user_history_with_summary_once( - harness.server(), - "BEDROCK_AUTOMATIC_REMOTE_COMPACTED_SUMMARY", - ) - .await; harness .test() @@ -717,21 +729,33 @@ async fn amazon_bedrock_automatic_compaction_uses_v1_endpoint_when_v2_is_enabled .submit_turn("after automatic compact") .await?; - let compact_request = compact_mock.single_request(); - assert_eq!(compact_request.path(), "/v1/responses/compact"); + let response_requests = response_mock.requests(); + assert_eq!(response_requests.len(), 3); + assert!( + response_requests + .iter() + .all(|request| request.path() == "/v1/responses") + ); + let compact_request = &response_requests[1]; assert_eq!( compact_request.header("authorization").as_deref(), Some("Bearer bedrock-test-api-key") ); - - let response_requests = response_mock.requests(); - assert_eq!(response_requests.len(), 2); - assert!( - response_requests - .iter() - .all(|request| request.inputs_of_type("compaction_trigger").is_empty()) + assert_eq!( + compact_request + .header("x-amzn-mantle-client-agent") + .as_deref(), + Some("codex") ); - assert!(response_requests[1].input().iter().any(|item| { + assert_eq!( + compact_request.body_json()["model"], + AMAZON_BEDROCK_GPT_5_5_MODEL_ID + ); + assert_eq!( + compact_request.inputs_of_type("compaction_trigger").len(), + 1 + ); + assert!(response_requests[2].input().iter().any(|item| { item["type"] == "compaction" && item["encrypted_content"] == "BEDROCK_AUTOMATIC_REMOTE_COMPACTED_SUMMARY" })); diff --git a/codex-rs/model-provider/src/amazon_bedrock/mod.rs b/codex-rs/model-provider/src/amazon_bedrock/mod.rs index e2af6b3350..5c92cae264 100644 --- a/codex-rs/model-provider/src/amazon_bedrock/mod.rs +++ b/codex-rs/model-provider/src/amazon_bedrock/mod.rs @@ -182,7 +182,7 @@ impl ModelProvider for AmazonBedrockModelProvider { image_generation: false, web_search: self.endpoint == BedrockEndpoint::Mantle, external_web_access: false, - remote_compaction: RemoteCompactionSupport::V1, + remote_compaction: RemoteCompactionSupport::V2, } } @@ -477,13 +477,13 @@ mod tests { image_generation: false, web_search: true, external_web_access: false, - remote_compaction: RemoteCompactionSupport::V1, + remote_compaction: RemoteCompactionSupport::V2, } ); } #[test] - fn runtime_capabilities_disable_web_search_and_support_v1_remote_compaction() { + fn runtime_capabilities_disable_web_search_and_support_v2_remote_compaction() { let provider = AmazonBedrockModelProvider::new( ModelProviderInfo::create_amazon_bedrock_runtime_provider(/*aws*/ None), /*auth_manager*/ None, @@ -496,7 +496,7 @@ mod tests { image_generation: false, web_search: false, external_web_access: false, - remote_compaction: RemoteCompactionSupport::V1, + remote_compaction: RemoteCompactionSupport::V2, } ); } diff --git a/codex-rs/model-provider/src/provider.rs b/codex-rs/model-provider/src/provider.rs index 192c0eb0c1..df3755d937 100644 --- a/codex-rs/model-provider/src/provider.rs +++ b/codex-rs/model-provider/src/provider.rs @@ -46,9 +46,7 @@ pub(crate) fn enforce_managed_residency(provider: &mut Provider) { pub enum RemoteCompactionSupport { /// The provider does not support remote compaction. Unsupported, - /// The provider supports only the dedicated `/v1/responses/compact` endpoint. - V1, - /// The provider supports both the dedicated endpoint and `compaction_trigger` items. + /// The provider supports `compaction_trigger` items over the Responses endpoint. V2, } @@ -73,7 +71,7 @@ impl Default for ProviderCapabilities { image_generation: true, web_search: true, external_web_access: true, - remote_compaction: RemoteCompactionSupport::V2, + remote_compaction: RemoteCompactionSupport::Unsupported, } } } @@ -629,13 +627,19 @@ mod tests { } #[test] - fn configured_provider_uses_default_capabilities() { + fn openai_provider_enables_remote_compaction() { let provider = create_model_provider( ModelProviderInfo::create_openai_provider(/*base_url*/ None), /*auth_manager*/ None, ); - assert_eq!(provider.capabilities(), ProviderCapabilities::default()); + assert_eq!( + provider.capabilities(), + ProviderCapabilities { + remote_compaction: RemoteCompactionSupport::V2, + ..ProviderCapabilities::default() + } + ); } #[test]