mirror of
https://github.com/openai/codex.git
synced 2026-10-18 17:18:52 +00:00
Add async compaction feature configuration (#53595)
## What changed Register the disabled-by-default `async_compaction` feature and accept either a boolean or a `[features.async_compaction]` table. Add `model_async_compact_threshold_percent` with a default of 65 and a valid range of 1–100, validated even when the feature is disabled. Setting a threshold alone does not enable the feature. Expose the threshold in the runtime configuration and update the JSON schema for both configuration forms. ## Testing Add configuration loader tests covering boolean and table forms, default and custom thresholds, explicit enablement, and rejection of out-of-range values. GitOrigin-RevId: cf33de76878e7044bc8cf5d146375a07ea9eb078
This commit is contained in:
@@ -99,6 +99,15 @@ pub fn features_schema(schema_gen: &mut SchemaGenerator) -> Schema {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if feature.id == codex_features::Feature::AsyncCompaction {
|
||||
validation.properties.insert(
|
||||
feature.key.to_string(),
|
||||
schema_gen.subschema_for::<codex_features::FeatureToml<
|
||||
codex_features::AsyncCompactionConfigToml,
|
||||
>>(),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if feature.id == codex_features::Feature::TokenBudget {
|
||||
validation.properties.insert(
|
||||
feature.key.to_string(),
|
||||
|
||||
@@ -353,6 +353,23 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"AsyncCompactionConfigToml": {
|
||||
"additionalProperties": false,
|
||||
"description": "Background compaction settings. A threshold alone does not enable the feature.",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"model_async_compact_threshold_percent": {
|
||||
"description": "Percentage of the model's full context window that starts background compaction. Defaults to 65; valid values are 1–100, including when disabled.",
|
||||
"format": "uint8",
|
||||
"maximum": 100.0,
|
||||
"minimum": 1.0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"AuthCredentialsStoreMode": {
|
||||
"description": "Determine where Codex should store CLI auth credentials.",
|
||||
"oneOf": [
|
||||
@@ -767,6 +784,9 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"async_compaction": {
|
||||
"$ref": "#/definitions/FeatureToml_for_AsyncCompactionConfigToml"
|
||||
},
|
||||
"auth_elicitation": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -1581,6 +1601,16 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"FeatureToml_for_AsyncCompactionConfigToml": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/AsyncCompactionConfigToml"
|
||||
}
|
||||
]
|
||||
},
|
||||
"FeatureToml_for_CodeModeConfigToml": {
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -7078,6 +7108,9 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"async_compaction": {
|
||||
"$ref": "#/definitions/FeatureToml_for_AsyncCompactionConfigToml"
|
||||
},
|
||||
"auth_elicitation": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
@@ -4827,3 +4827,55 @@ prefix_rules = []
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn async_compaction_config() {
|
||||
use std::io::ErrorKind::InvalidInput;
|
||||
|
||||
for (settings, expected) in [
|
||||
("[features]\nasync_compaction = true", Ok((true, 65))),
|
||||
("[features]\nasync_compaction = false", Ok((false, 65))),
|
||||
("[features.async_compaction]", Ok((false, 65))),
|
||||
(
|
||||
"[features.async_compaction]\nenabled = true",
|
||||
Ok((true, 65)),
|
||||
),
|
||||
(
|
||||
"[features.async_compaction]\nmodel_async_compact_threshold_percent = 80",
|
||||
Ok((false, 80)),
|
||||
),
|
||||
(
|
||||
"[features.async_compaction]\nenabled = false\nmodel_async_compact_threshold_percent = 80",
|
||||
Ok((false, 80)),
|
||||
),
|
||||
(
|
||||
"[features.async_compaction]\nenabled = true\nmodel_async_compact_threshold_percent = 75",
|
||||
Ok((true, 75)),
|
||||
),
|
||||
(
|
||||
"[features.async_compaction]\nmodel_async_compact_threshold_percent = 0",
|
||||
Err(InvalidInput),
|
||||
),
|
||||
(
|
||||
"[features.async_compaction]\nmodel_async_compact_threshold_percent = 101",
|
||||
Err(InvalidInput),
|
||||
),
|
||||
] {
|
||||
let tmp = tempdir().expect("tempdir");
|
||||
std::fs::write(tmp.path().join(CONFIG_TOML_FILE), settings).expect("write config");
|
||||
let actual = ConfigBuilder::default()
|
||||
.codex_home(tmp.path().to_path_buf())
|
||||
.fallback_cwd(Some(tmp.path().to_path_buf()))
|
||||
.loader_overrides(LoaderOverrides::without_managed_config_for_tests())
|
||||
.build()
|
||||
.await
|
||||
.map(|config| {
|
||||
(
|
||||
config.features.enabled(Feature::AsyncCompaction),
|
||||
config.async_compaction_threshold_percent,
|
||||
)
|
||||
})
|
||||
.map_err(|error| error.kind());
|
||||
assert_eq!(actual, expected, "{settings}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,6 +222,7 @@ pub use windows_sandbox_config::windows_mxc_allowed_by_config;
|
||||
|
||||
const DEFAULT_IGNORE_LARGE_UNTRACKED_DIRS: i64 = 200;
|
||||
const DEFAULT_IGNORE_LARGE_UNTRACKED_FILES: i64 = 10 * 1024 * 1024;
|
||||
const DEFAULT_ASYNC_COMPACTION_THRESHOLD_PERCENT: u8 = 65;
|
||||
|
||||
/// Signals that a public config selected the retired `untrusted` approval policy.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
@@ -660,6 +661,9 @@ pub struct Config {
|
||||
/// Zero disables turn-end compaction.
|
||||
pub model_post_turn_compact_threshold_percent: u8,
|
||||
|
||||
/// Percentage of the model's full context window at which background compaction starts.
|
||||
pub async_compaction_threshold_percent: u8,
|
||||
|
||||
/// Key into the model_providers map that specifies which provider to use.
|
||||
pub model_provider_id: String,
|
||||
|
||||
@@ -3303,6 +3307,19 @@ impl Config {
|
||||
"model_post_turn_compact_threshold_percent must be between 0 and 100",
|
||||
));
|
||||
}
|
||||
let async_compaction_threshold_percent = cfg.features.as_ref()
|
||||
.and_then(|features| features.async_compaction.as_ref())
|
||||
.and_then(|feature| match feature {
|
||||
FeatureToml::Enabled(_) => None,
|
||||
FeatureToml::Config(config) => config.model_async_compact_threshold_percent,
|
||||
})
|
||||
.unwrap_or(DEFAULT_ASYNC_COMPACTION_THRESHOLD_PERCENT);
|
||||
if !(1..=100).contains(&async_compaction_threshold_percent) {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"model_async_compact_threshold_percent must be between 1 and 100",
|
||||
));
|
||||
}
|
||||
if let Some(responses_api_metadata) = cfg.responses_api_metadata.as_ref() {
|
||||
validate_extra_metadata(responses_api_metadata.iter()).map_err(|message| {
|
||||
std::io::Error::new(std::io::ErrorKind::InvalidInput, message)
|
||||
@@ -4395,6 +4412,7 @@ impl Config {
|
||||
model_post_turn_compact_threshold_percent: cfg
|
||||
.model_post_turn_compact_threshold_percent
|
||||
.unwrap_or_default(),
|
||||
async_compaction_threshold_percent,
|
||||
model_provider_id,
|
||||
model_provider,
|
||||
cwd: resolved_cwd,
|
||||
|
||||
@@ -564,3 +564,22 @@ pub enum NetworkProxyUnixSocketPermissionToml {
|
||||
Allow,
|
||||
Deny,
|
||||
}
|
||||
|
||||
/// Background compaction settings. A threshold alone does not enable the feature.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct AsyncCompactionConfigToml {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enabled: Option<bool>,
|
||||
/// Percentage of the model's full context window that starts background compaction.
|
||||
/// Defaults to 65; valid values are 1–100, including when disabled.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[schemars(range(min = 1, max = 100))]
|
||||
pub model_async_compact_threshold_percent: Option<u8>,
|
||||
}
|
||||
|
||||
impl FeatureConfig for AsyncCompactionConfigToml {
|
||||
fn enabled(&self) -> Option<bool> {
|
||||
self.enabled
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ use toml::Table;
|
||||
|
||||
mod feature_configs;
|
||||
mod legacy;
|
||||
pub use feature_configs::AsyncCompactionConfigToml;
|
||||
pub use feature_configs::CodeModeConfigToml;
|
||||
pub use feature_configs::CodeModeHostConfigToml;
|
||||
pub use feature_configs::ContextManagementConfigToml;
|
||||
@@ -419,6 +420,8 @@ pub enum Feature {
|
||||
PreventIdleSleep,
|
||||
/// Removed compatibility key, still advertised to the Responses API.
|
||||
RemoteCompactionV2,
|
||||
/// Prepare remote compaction in the background before the foreground limit is reached.
|
||||
AsyncCompaction,
|
||||
/// Include retained images in the remote compaction context budget.
|
||||
CompactionImageBudget,
|
||||
/// Retain client-authored developer messages across compacted context windows.
|
||||
@@ -880,6 +883,8 @@ pub struct FeaturesToml {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub token_budget: Option<FeatureToml<TokenBudgetConfigToml>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub async_compaction: Option<FeatureToml<AsyncCompactionConfigToml>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub context_management: Option<FeatureToml<ContextManagementConfigToml>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub rollout_budget: Option<FeatureToml<RolloutBudgetConfigToml>>,
|
||||
@@ -906,6 +911,13 @@ impl Features {
|
||||
impl FeaturesToml {
|
||||
pub fn entries(&self) -> BTreeMap<String, bool> {
|
||||
let mut entries = self.entries.clone();
|
||||
if let Some(enabled) = self
|
||||
.async_compaction
|
||||
.as_ref()
|
||||
.and_then(FeatureToml::enabled)
|
||||
{
|
||||
entries.insert(Feature::AsyncCompaction.key().to_string(), enabled);
|
||||
}
|
||||
if let Some(enabled) = self.code_mode.as_ref().and_then(FeatureToml::enabled) {
|
||||
entries.insert(Feature::CodeMode.key().to_string(), enabled);
|
||||
}
|
||||
@@ -2042,6 +2054,12 @@ pub const FEATURES: &[FeatureSpec] = &[
|
||||
stage: Stage::Removed,
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::AsyncCompaction,
|
||||
key: "async_compaction",
|
||||
stage: Stage::UnderDevelopment,
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::CompactionImageBudget,
|
||||
key: "compaction_image_budget",
|
||||
|
||||
@@ -250,6 +250,7 @@ async fn new_config(
|
||||
model_auto_compact_token_limit: None,
|
||||
model_auto_compact_token_limit_scope: AutoCompactTokenLimitScope::Total,
|
||||
model_post_turn_compact_threshold_percent: 0,
|
||||
async_compaction_threshold_percent: 65,
|
||||
model_provider_id,
|
||||
model_provider,
|
||||
personality: None,
|
||||
|
||||
Reference in New Issue
Block a user