mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Default Fast service tier for eligible ChatGPT plans (#19053)
## Why Enterprise and business-like ChatGPT plans should get Codex's Fast service tier by default when the user or caller has not made an explicit service-tier choice. At the same time, callers need a durable way to choose standard routing without adding a new persisted `standard` service tier value. This keeps existing config compatibility while letting core own the managed default policy. ## What changed - Resolve the effective service tier in core at session creation: explicit `fast` or `flex` wins, explicit null/clear or `[notice].fast_default_opt_out = true` resolves to standard routing, and otherwise eligible ChatGPT plans resolve to Fast when FastMode is enabled. - Add `[notice].fast_default_opt_out` as the persisted opt-out marker for managed Fast defaults. - Treat app-server/TUI `service_tier: null` as an explicit standard/clear choice by preserving that intent through config loading. - Update TUI rendering to use core's effective service tier for startup and status surfaces while still keeping `config.service_tier` as the explicit configured choice. - Update `/fast off` to clear `service_tier`, persist the opt-out marker, and send explicit standard for subsequent turns. ## Verification - Added unit coverage for config override/notice handling, service-tier resolution, runtime null clearing, and `/fast off` turn propagation. - `cargo build -p codex-cli` Full test suite was not run locally per author request.
This commit is contained in:
@@ -39,6 +39,7 @@ use codex_config::types::McpServerTransportConfig;
|
||||
use codex_config::types::MemoriesConfig;
|
||||
use codex_config::types::MemoriesToml;
|
||||
use codex_config::types::ModelAvailabilityNuxConfig;
|
||||
use codex_config::types::Notice;
|
||||
use codex_config::types::NotificationCondition;
|
||||
use codex_config::types::NotificationMethod;
|
||||
use codex_config::types::Notifications;
|
||||
@@ -5298,6 +5299,50 @@ async fn metrics_exporter_defaults_to_statsig_when_missing() -> std::io::Result<
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn explicit_null_service_tier_override_sets_fast_default_opt_out() -> std::io::Result<()> {
|
||||
let fixture = create_test_fixture()?;
|
||||
|
||||
let config = Config::load_from_base_config_with_overrides(
|
||||
fixture.cfg.clone(),
|
||||
ConfigOverrides {
|
||||
cwd: Some(fixture.cwd_path()),
|
||||
service_tier: Some(None),
|
||||
..Default::default()
|
||||
},
|
||||
fixture.codex_home(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
assert_eq!(config.service_tier, None);
|
||||
assert_eq!(config.notices.fast_default_opt_out, Some(true));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn fast_default_opt_out_notice_config_is_respected() -> std::io::Result<()> {
|
||||
let fixture = create_test_fixture()?;
|
||||
let mut cfg = fixture.cfg.clone();
|
||||
cfg.notice = Some(Notice {
|
||||
fast_default_opt_out: Some(true),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let config = Config::load_from_base_config_with_overrides(
|
||||
cfg,
|
||||
ConfigOverrides {
|
||||
cwd: Some(fixture.cwd_path()),
|
||||
..Default::default()
|
||||
},
|
||||
fixture.codex_home(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
assert_eq!(config.service_tier, None);
|
||||
assert_eq!(config.notices.fast_default_opt_out, Some(true));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_precedence_fixture_with_gpt3_profile() -> std::io::Result<()> {
|
||||
let fixture = create_test_fixture()?;
|
||||
|
||||
@@ -37,6 +37,8 @@ pub enum ConfigEdit {
|
||||
SetNoticeHideFullAccessWarning(bool),
|
||||
/// Toggle the Windows world-writable directories warning acknowledgement flag.
|
||||
SetNoticeHideWorldWritableWarning(bool),
|
||||
/// Toggle the opt-out marker for Codex-managed fast defaults.
|
||||
SetNoticeFastDefaultOptOut(bool),
|
||||
/// Toggle the rate limit model nudge acknowledgement flag.
|
||||
SetNoticeHideRateLimitModelNudge(bool),
|
||||
/// Toggle the Windows onboarding acknowledgement flag.
|
||||
@@ -436,6 +438,11 @@ impl ConfigDocument {
|
||||
&[NOTICE_TABLE_KEY, "hide_world_writable_warning"],
|
||||
value(*acknowledged),
|
||||
)),
|
||||
ConfigEdit::SetNoticeFastDefaultOptOut(opted_out) => Ok(self.write_value(
|
||||
Scope::Global,
|
||||
&[NOTICE_TABLE_KEY, "fast_default_opt_out"],
|
||||
value(*opted_out),
|
||||
)),
|
||||
ConfigEdit::SetNoticeHideRateLimitModelNudge(acknowledged) => Ok(self.write_value(
|
||||
Scope::Global,
|
||||
&[NOTICE_TABLE_KEY, "hide_rate_limit_model_nudge"],
|
||||
@@ -978,6 +985,12 @@ impl ConfigEditsBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_fast_default_opt_out(mut self, opted_out: bool) -> Self {
|
||||
self.edits
|
||||
.push(ConfigEdit::SetNoticeFastDefaultOptOut(opted_out));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_hide_rate_limit_model_nudge(mut self, acknowledged: bool) -> Self {
|
||||
self.edits
|
||||
.push(ConfigEdit::SetNoticeHideRateLimitModelNudge(acknowledged));
|
||||
|
||||
@@ -2031,14 +2031,24 @@ impl Config {
|
||||
let forced_login_method = cfg.forced_login_method;
|
||||
|
||||
let model = model.or(config_profile.model).or(cfg.model);
|
||||
let service_tier = service_tier_override
|
||||
.unwrap_or_else(|| config_profile.service_tier.or(cfg.service_tier));
|
||||
let mut notices = cfg.notice.unwrap_or_default();
|
||||
let service_tier = match service_tier_override {
|
||||
Some(Some(service_tier)) => Some(service_tier),
|
||||
Some(None) => {
|
||||
// Preserve explicit standard/clear intent after the nested override
|
||||
// collapses into `Config.service_tier = None`.
|
||||
notices.fast_default_opt_out = Some(true);
|
||||
None
|
||||
}
|
||||
None => config_profile.service_tier.or(cfg.service_tier),
|
||||
};
|
||||
let service_tier = match service_tier {
|
||||
Some(ServiceTier::Fast) if features.enabled(Feature::FastMode) => {
|
||||
Some(ServiceTier::Fast)
|
||||
}
|
||||
Some(ServiceTier::Fast) => None,
|
||||
Some(ServiceTier::Flex) => Some(ServiceTier::Flex),
|
||||
_ => None,
|
||||
None => None,
|
||||
};
|
||||
|
||||
let compact_prompt = compact_prompt.or(cfg.compact_prompt).and_then(|value| {
|
||||
@@ -2414,7 +2424,7 @@ impl Config {
|
||||
active_profile: active_profile_name,
|
||||
active_project,
|
||||
windows_wsl_setup_acknowledged: cfg.windows_wsl_setup_acknowledged.unwrap_or(false),
|
||||
notices: cfg.notice.unwrap_or_default(),
|
||||
notices,
|
||||
check_for_update_on_startup,
|
||||
disable_paste_burst: cfg.disable_paste_burst.unwrap_or(false),
|
||||
analytics_enabled: config_profile
|
||||
|
||||
Reference in New Issue
Block a user