Use Responses compaction for Amazon Bedrock (#39825)

## What changed

- Switch Amazon Bedrock remote compaction to `compaction_trigger` items sent through `/v1/responses`.
- Remove the legacy dedicated compaction protocol from provider capabilities.
- Default remote compaction to unsupported and explicitly enable it for OpenAI, Azure Responses, and Amazon Bedrock providers.

## Testing

- Cover manual and automatic Amazon Bedrock compaction requests and their compacted history.
- Verify remote-compaction capabilities for configured and Amazon Bedrock providers.

GitOrigin-RevId: cf9ba314595367518b37a85f334f0c105ce47e45
This commit is contained in:
rka-oai
2026-08-21 00:48:47 +00:00
committed by celia-oai
parent 86ba987b54
commit 1e0ad41f8b
5 changed files with 72 additions and 44 deletions

View File

@@ -1223,7 +1223,7 @@ async fn run_auto_compact(
)
.await?;
}
RemoteCompactionSupport::V1 | RemoteCompactionSupport::V2 => {
RemoteCompactionSupport::V2 => {
emit_compact_metric(
&sess.services.session_telemetry,
"remote",

View File

@@ -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",

View File

@@ -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"
}));

View File

@@ -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,
}
);
}

View File

@@ -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]