mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
core: enable remote compaction v2 by default (#27573)
## Why Remote compaction v2 is ready to become the default for providers that already support remote compaction. Leaving it behind an under-development opt-in keeps eligible sessions on the legacy remote-compaction path. This does not broaden provider eligibility: OpenAI and Azure move to v2, while Bedrock and OSS providers retain their existing local-compaction behavior. ## What changed - Mark `remote_compaction_v2` stable and enable it by default. - Make tests that intentionally cover legacy remote compaction explicitly disable v2. - Update parity coverage so v2 exercises the production default and only legacy mode opts out. ## Verification - `just test -p codex-core auto_compact_runs_after_resume_when_token_usage_is_over_limit auto_compact_counts_encrypted_reasoning_before_last_user auto_compact_runs_when_reasoning_header_clears_between_turns responses_lite_compact_request_uses_lite_transport_contract`
This commit is contained in:
8 files changed
+55
-58
No files matched your search
@@ -29,6 +29,7 @@ use codex_app_server_protocol::TurnStartParams;
|
|||||||
use codex_app_server_protocol::TurnStartResponse;
|
use codex_app_server_protocol::TurnStartResponse;
|
||||||
use codex_app_server_protocol::UserInput as V2UserInput;
|
use codex_app_server_protocol::UserInput as V2UserInput;
|
||||||
use codex_config::types::AuthCredentialsStoreMode;
|
use codex_config::types::AuthCredentialsStoreMode;
|
||||||
|
use codex_features::Feature;
|
||||||
use codex_protocol::models::ContentItem;
|
use codex_protocol::models::ContentItem;
|
||||||
use codex_protocol::models::ResponseItem;
|
use codex_protocol::models::ResponseItem;
|
||||||
use core_test_support::responses;
|
use core_test_support::responses;
|
||||||
@@ -150,7 +151,7 @@ async fn auto_compaction_remote_emits_started_and_completed_items() -> Result<()
|
|||||||
write_mock_responses_config_toml(
|
write_mock_responses_config_toml(
|
||||||
codex_home.path(),
|
codex_home.path(),
|
||||||
&server.uri(),
|
&server.uri(),
|
||||||
&BTreeMap::default(),
|
&BTreeMap::from([(Feature::RemoteCompactionV2, false)]),
|
||||||
REMOTE_AUTO_COMPACT_LIMIT,
|
REMOTE_AUTO_COMPACT_LIMIT,
|
||||||
Some(true),
|
Some(true),
|
||||||
"mock_provider",
|
"mock_provider",
|
||||||
|
|||||||
@@ -2015,6 +2015,7 @@ async fn auto_compact_runs_after_resume_when_token_usage_is_over_limit() {
|
|||||||
let mut builder = test_codex().with_config(move |config| {
|
let mut builder = test_codex().with_config(move |config| {
|
||||||
set_test_compact_prompt(config);
|
set_test_compact_prompt(config);
|
||||||
config.model_auto_compact_token_limit = Some(limit);
|
config.model_auto_compact_token_limit = Some(limit);
|
||||||
|
let _ = config.features.disable(Feature::RemoteCompactionV2);
|
||||||
});
|
});
|
||||||
let initial = builder.build(&server).await.unwrap();
|
let initial = builder.build(&server).await.unwrap();
|
||||||
let home = initial.home.clone();
|
let home = initial.home.clone();
|
||||||
@@ -2043,6 +2044,7 @@ async fn auto_compact_runs_after_resume_when_token_usage_is_over_limit() {
|
|||||||
let mut resume_builder = test_codex().with_config(move |config| {
|
let mut resume_builder = test_codex().with_config(move |config| {
|
||||||
set_test_compact_prompt(config);
|
set_test_compact_prompt(config);
|
||||||
config.model_auto_compact_token_limit = Some(limit);
|
config.model_auto_compact_token_limit = Some(limit);
|
||||||
|
let _ = config.features.disable(Feature::RemoteCompactionV2);
|
||||||
});
|
});
|
||||||
let resumed = resume_builder
|
let resumed = resume_builder
|
||||||
.resume(&server, home, rollout_path)
|
.resume(&server, home, rollout_path)
|
||||||
@@ -4023,6 +4025,7 @@ async fn auto_compact_counts_encrypted_reasoning_before_last_user() {
|
|||||||
config.chatgpt_base_url = chatgpt_base_url;
|
config.chatgpt_base_url = chatgpt_base_url;
|
||||||
set_test_compact_prompt(config);
|
set_test_compact_prompt(config);
|
||||||
config.model_auto_compact_token_limit = Some(300);
|
config.model_auto_compact_token_limit = Some(300);
|
||||||
|
let _ = config.features.disable(Feature::RemoteCompactionV2);
|
||||||
})
|
})
|
||||||
.build(&server)
|
.build(&server)
|
||||||
.await
|
.await
|
||||||
@@ -4145,6 +4148,7 @@ async fn auto_compact_runs_when_reasoning_header_clears_between_turns() {
|
|||||||
.with_config(|config| {
|
.with_config(|config| {
|
||||||
set_test_compact_prompt(config);
|
set_test_compact_prompt(config);
|
||||||
config.model_auto_compact_token_limit = Some(300);
|
config.model_auto_compact_token_limit = Some(300);
|
||||||
|
let _ = config.features.disable(Feature::RemoteCompactionV2);
|
||||||
})
|
})
|
||||||
.build(&server)
|
.build(&server)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ use core_test_support::responses::start_websocket_server;
|
|||||||
use core_test_support::skip_if_no_network;
|
use core_test_support::skip_if_no_network;
|
||||||
use core_test_support::test_codex::TestCodexBuilder;
|
use core_test_support::test_codex::TestCodexBuilder;
|
||||||
use core_test_support::test_codex::TestCodexHarness;
|
use core_test_support::test_codex::TestCodexHarness;
|
||||||
use core_test_support::test_codex::test_codex;
|
use core_test_support::test_codex::test_codex as base_test_codex;
|
||||||
use core_test_support::test_path_buf;
|
use core_test_support::test_path_buf;
|
||||||
use core_test_support::wait_for_event;
|
use core_test_support::wait_for_event;
|
||||||
use core_test_support::wait_for_event_match;
|
use core_test_support::wait_for_event_match;
|
||||||
@@ -160,6 +160,12 @@ fn compacted_summary_only_output(summary: &str) -> Vec<ResponseItem> {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_codex() -> TestCodexBuilder {
|
||||||
|
base_test_codex().with_config(|config| {
|
||||||
|
let _ = config.features.disable(Feature::RemoteCompactionV2);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn remote_realtime_test_codex_builder(
|
fn remote_realtime_test_codex_builder(
|
||||||
realtime_server: &responses::WebSocketTestServer,
|
realtime_server: &responses::WebSocketTestServer,
|
||||||
) -> TestCodexBuilder {
|
) -> TestCodexBuilder {
|
||||||
|
|||||||
@@ -529,8 +529,8 @@ async fn build_harness_inner(
|
|||||||
if hooks {
|
if hooks {
|
||||||
trust_discovered_hooks(config);
|
trust_discovered_hooks(config);
|
||||||
}
|
}
|
||||||
if mode == Mode::V2 {
|
if mode == Mode::Legacy {
|
||||||
let _ = config.features.enable(Feature::RemoteCompactionV2);
|
let _ = config.features.disable(Feature::RemoteCompactionV2);
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ use core_test_support::responses::ev_function_call;
|
|||||||
use core_test_support::responses::ev_message_item_added;
|
use core_test_support::responses::ev_message_item_added;
|
||||||
use core_test_support::responses::ev_output_text_delta;
|
use core_test_support::responses::ev_output_text_delta;
|
||||||
use core_test_support::responses::ev_response_created;
|
use core_test_support::responses::ev_response_created;
|
||||||
use core_test_support::responses::mount_compact_json_once;
|
|
||||||
use core_test_support::responses::mount_sse_once;
|
use core_test_support::responses::mount_sse_once;
|
||||||
use core_test_support::responses::mount_sse_sequence;
|
use core_test_support::responses::mount_sse_sequence;
|
||||||
use core_test_support::responses::sse;
|
use core_test_support::responses::sse;
|
||||||
@@ -1441,21 +1440,32 @@ async fn resumed_thread_runs_resume_then_compact_session_start_hooks() -> Result
|
|||||||
let remote_summary = "remote compact summary";
|
let remote_summary = "remote compact summary";
|
||||||
let resume_context = "remember the resumed reef";
|
let resume_context = "remember the resumed reef";
|
||||||
let compact_context = "remember the compacted reef";
|
let compact_context = "remember the compacted reef";
|
||||||
let compacted_history = vec![
|
let responses_mock = mount_sse_sequence(
|
||||||
ResponseItem::Message {
|
&server,
|
||||||
id: None,
|
vec![
|
||||||
role: "assistant".to_string(),
|
sse(vec![
|
||||||
content: vec![ContentItem::OutputText {
|
ev_response_created("resp-1"),
|
||||||
text: remote_summary.to_string(),
|
ev_assistant_message("msg-1", "hello before resume"),
|
||||||
}],
|
ev_completed_with_tokens("resp-1", over_limit_tokens),
|
||||||
phase: None,
|
]),
|
||||||
},
|
sse(vec![
|
||||||
ResponseItem::Compaction {
|
serde_json::json!({
|
||||||
encrypted_content: "encrypted compact summary".to_string(),
|
"type": "response.output_item.done",
|
||||||
},
|
"item": {
|
||||||
];
|
"type": "compaction",
|
||||||
let compact_mock =
|
"encrypted_content": remote_summary,
|
||||||
mount_compact_json_once(&server, serde_json::json!({ "output": compacted_history })).await;
|
}
|
||||||
|
}),
|
||||||
|
ev_completed("resp-compact"),
|
||||||
|
]),
|
||||||
|
sse(vec![
|
||||||
|
ev_response_created("resp-2"),
|
||||||
|
ev_assistant_message("msg-2", "hello after resume"),
|
||||||
|
ev_completed("resp-2"),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
let mut builder = test_codex()
|
let mut builder = test_codex()
|
||||||
.with_pre_build_hook(move |home| {
|
.with_pre_build_hook(move |home| {
|
||||||
@@ -1479,37 +1489,19 @@ async fn resumed_thread_runs_resume_then_compact_session_start_hooks() -> Result
|
|||||||
.clone()
|
.clone()
|
||||||
.context("rollout path")?;
|
.context("rollout path")?;
|
||||||
|
|
||||||
mount_sse_once(
|
|
||||||
&server,
|
|
||||||
sse(vec![
|
|
||||||
ev_response_created("resp-1"),
|
|
||||||
ev_assistant_message("msg-1", "hello before resume"),
|
|
||||||
ev_completed_with_tokens("resp-1", over_limit_tokens),
|
|
||||||
]),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
initial.submit_turn("hello before resume").await?;
|
initial.submit_turn("hello before resume").await?;
|
||||||
assert!(compact_mock.requests().is_empty());
|
assert_eq!(responses_mock.requests().len(), 1);
|
||||||
|
|
||||||
let mut resume_builder = test_codex().with_config(move |config| {
|
let mut resume_builder = test_codex().with_config(move |config| {
|
||||||
config.model_auto_compact_token_limit = Some(limit);
|
config.model_auto_compact_token_limit = Some(limit);
|
||||||
trust_discovered_hooks(config);
|
trust_discovered_hooks(config);
|
||||||
});
|
});
|
||||||
let resumed = resume_builder.resume(&server, home, rollout_path).await?;
|
let resumed = resume_builder.resume(&server, home, rollout_path).await?;
|
||||||
let follow_up = mount_sse_once(
|
|
||||||
&server,
|
|
||||||
sse(vec![
|
|
||||||
ev_response_created("resp-2"),
|
|
||||||
ev_assistant_message("msg-2", "hello after resume"),
|
|
||||||
ev_completed("resp-2"),
|
|
||||||
]),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
resumed.submit_turn("hello after resume").await?;
|
resumed.submit_turn("hello after resume").await?;
|
||||||
|
|
||||||
assert_eq!(compact_mock.requests().len(), 1);
|
let requests = responses_mock.requests();
|
||||||
let developer_messages = follow_up.single_request().message_input_texts("developer");
|
assert_eq!(requests.len(), 3);
|
||||||
|
let developer_messages = requests[2].message_input_texts("developer");
|
||||||
assert!(
|
assert!(
|
||||||
developer_messages
|
developer_messages
|
||||||
.iter()
|
.iter()
|
||||||
|
|||||||
@@ -177,10 +177,14 @@ async fn responses_lite_compact_request_uses_lite_transport_contract() -> Result
|
|||||||
let compact_mock =
|
let compact_mock =
|
||||||
responses::mount_compact_json_once(&server, serde_json::json!({ "output": [] })).await;
|
responses::mount_compact_json_once(&server, serde_json::json!({ "output": [] })).await;
|
||||||
|
|
||||||
let mut builder = test_codex().with_model_info_override("gpt-5.4", |model_info| {
|
let mut builder = test_codex()
|
||||||
model_info.use_responses_lite = true;
|
.with_model_info_override("gpt-5.4", |model_info| {
|
||||||
model_info.supports_parallel_tool_calls = true;
|
model_info.use_responses_lite = true;
|
||||||
});
|
model_info.supports_parallel_tool_calls = true;
|
||||||
|
})
|
||||||
|
.with_config(|config| {
|
||||||
|
let _ = config.features.disable(Feature::RemoteCompactionV2);
|
||||||
|
});
|
||||||
let test = builder.build(&server).await?;
|
let test = builder.build(&server).await?;
|
||||||
|
|
||||||
test.submit_turn("Compact this conversation").await?;
|
test.submit_turn("Compact this conversation").await?;
|
||||||
|
|||||||
@@ -1249,8 +1249,8 @@ pub const FEATURES: &[FeatureSpec] = &[
|
|||||||
FeatureSpec {
|
FeatureSpec {
|
||||||
id: Feature::RemoteCompactionV2,
|
id: Feature::RemoteCompactionV2,
|
||||||
key: "remote_compaction_v2",
|
key: "remote_compaction_v2",
|
||||||
stage: Stage::UnderDevelopment,
|
stage: Stage::Stable,
|
||||||
default_enabled: false,
|
default_enabled: true,
|
||||||
},
|
},
|
||||||
FeatureSpec {
|
FeatureSpec {
|
||||||
id: Feature::WorkspaceDependencies,
|
id: Feature::WorkspaceDependencies,
|
||||||
|
|||||||
@@ -150,16 +150,6 @@ fn request_permissions_tool_is_under_development() {
|
|||||||
assert_eq!(Feature::RequestPermissionsTool.default_enabled(), false);
|
assert_eq!(Feature::RequestPermissionsTool.default_enabled(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn remote_compaction_v2_is_under_development() {
|
|
||||||
assert_eq!(Feature::RemoteCompactionV2.stage(), Stage::UnderDevelopment);
|
|
||||||
assert_eq!(Feature::RemoteCompactionV2.default_enabled(), false);
|
|
||||||
assert_eq!(
|
|
||||||
feature_for_key("remote_compaction_v2"),
|
|
||||||
Some(Feature::RemoteCompactionV2)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn terminal_resize_reflow_is_experimental_and_enabled_by_default() {
|
fn terminal_resize_reflow_is_experimental_and_enabled_by_default() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
Reference in new issue
Block a user