Add configurable gating for the sleep tool (#41243)

## What changed

- Add a stable `sleep_tool` feature that can enable or disable registration of the built-in sleep tool independently of the clock tool.
- Support structured `features.sleep_tool` configuration with `model_driven` and `always_on` modes. The default `model_driven` mode preserves the existing model and `current_time_reminder` behavior, while `always_on` registers sleep whenever the feature is enabled.
- Preserve nested sleep-tool configuration across CLI overrides, config merges, and feature toggles, and expose the settings in the generated config schema.

## Testing

- Cover feature-map overrides, both selection modes, legacy clock settings, config merging and editing, and invalid mode rejection.

GitOrigin-RevId: 18eadc582f8a4445958c29d063e5be495276703e
This commit is contained in:
rka-oai authored and copyberry committed 2026-08-28 02:09:07 +00:00
1 parent 41d3dc56a0
commit ec9620c231
12 files changed
+313 -14

No files matched your search

+27
View File
@@ -136,6 +136,33 @@ fn multi_agent_v2_feature_toggle_preserves_nested_configuration() {
);
}
#[test]
fn sleep_tool_feature_toggle_preserves_mode() {
let tmp = tempdir().expect("tmpdir");
let codex_home = tmp.path();
let config_path = codex_home.join(CONFIG_TOML_FILE);
std::fs::write(
&config_path,
"[features.sleep_tool]\nmode = \"always_on\"\n",
)
.expect("write config");
for enabled in [false, true] {
ConfigEditsBuilder::new(codex_home)
.set_feature_enabled("sleep_tool", enabled)
.apply_blocking()
.expect("toggle feature");
let actual: TomlValue =
toml::from_str(&std::fs::read_to_string(&config_path).expect("read config"))
.expect("parse config");
let expected: TomlValue = toml::from_str(&format!(
"[features.sleep_tool]\nenabled = {enabled}\nmode = \"always_on\"\n",
))
.expect("parse expected config");
assert_eq!(actual, expected);
}
}
#[test]
fn network_proxy_feature_toggle_preserves_credential_broker_configuration() {
let tmp = tempdir().expect("tmpdir");
+13
View File
@@ -73,6 +73,7 @@ use codex_features::Features;
use codex_features::FeaturesToml;
use codex_features::MultiAgentV2ConfigToml;
use codex_features::NetworkProxyConfigToml;
use codex_features::SleepToolMode;
use codex_features::TokenBudgetConfigToml;
use codex_git_utils::resolve_root_git_project_for_trust;
use codex_http_client::HttpClientFactory;
@@ -1045,6 +1046,8 @@ pub struct Config {
pub rollout_budget: Option<RolloutBudgetConfig>,
/// Current-time reminder and clock tool configuration, when enabled.
pub current_time_reminder: Option<CurrentTimeReminderConfig>,
/// How the sleep tool is selected when its feature gate is enabled.
pub sleep_tool_mode: SleepToolMode,
/// Centralized feature flags; source of truth for feature gating.
pub features: ManagedFeatures,
@@ -3684,6 +3687,15 @@ impl Config {
let token_budget = resolve_token_budget_config(&cfg, &features)?;
let rollout_budget = resolve_rollout_budget_config(&cfg, &features)?;
let current_time_reminder = resolve_current_time_reminder_config(&cfg, &features)?;
let sleep_tool_mode = cfg
.features
.as_ref()
.and_then(|features| features.sleep_tool.as_ref())
.and_then(|feature| match feature {
FeatureToml::Enabled(_) => None,
FeatureToml::Config(config) => config.mode,
})
.unwrap_or_default();
let terminal_resize_reflow = resolve_terminal_resize_reflow_config(&cfg);
let agent_roles =
@@ -4282,6 +4294,7 @@ impl Config {
token_budget,
rollout_budget,
current_time_reminder,
sleep_tool_mode,
features,
suppress_unstable_features_warning: cfg
.suppress_unstable_features_warning