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:
@@ -77,6 +77,7 @@ use codex_otel::current_span_w3c_trace_context;
|
||||
use codex_otel::set_parent_from_w3c_trace_context;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::ToolName;
|
||||
use codex_protocol::account::PlanType as AccountPlanType;
|
||||
use codex_protocol::approvals::ElicitationRequestEvent;
|
||||
use codex_protocol::approvals::ExecPolicyAmendment;
|
||||
use codex_protocol::approvals::NetworkPolicyAmendment;
|
||||
@@ -600,11 +601,20 @@ impl Codex {
|
||||
developer_instructions: None,
|
||||
},
|
||||
};
|
||||
let account_plan_type = auth_manager
|
||||
.auth_cached()
|
||||
.and_then(|auth| auth.account_plan_type());
|
||||
let service_tier = get_service_tier(
|
||||
config.service_tier,
|
||||
config.notices.fast_default_opt_out.unwrap_or(false),
|
||||
account_plan_type,
|
||||
config.features.enabled(Feature::FastMode),
|
||||
);
|
||||
let session_configuration = SessionConfiguration {
|
||||
provider: config.model_provider.clone(),
|
||||
collaboration_mode,
|
||||
model_reasoning_summary: config.model_reasoning_summary,
|
||||
service_tier: config.service_tier,
|
||||
service_tier,
|
||||
developer_instructions: config.developer_instructions.clone(),
|
||||
user_instructions,
|
||||
personality: config.personality,
|
||||
@@ -785,6 +795,27 @@ impl Codex {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_service_tier(
|
||||
configured_service_tier: Option<ServiceTier>,
|
||||
fast_default_opt_out: bool,
|
||||
account_plan_type: Option<AccountPlanType>,
|
||||
fast_mode_enabled: bool,
|
||||
) -> Option<ServiceTier> {
|
||||
if configured_service_tier.is_some() || fast_default_opt_out || !fast_mode_enabled {
|
||||
return configured_service_tier;
|
||||
}
|
||||
|
||||
account_plan_type
|
||||
.is_some_and(is_enterprise_default_service_tier_plan)
|
||||
.then_some(ServiceTier::Fast)
|
||||
}
|
||||
|
||||
fn is_enterprise_default_service_tier_plan(plan_type: AccountPlanType) -> bool {
|
||||
plan_type == AccountPlanType::Enterprise
|
||||
|| plan_type.is_business_like()
|
||||
|| plan_type.is_team_like()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn completed_session_loop_termination() -> SessionLoopTermination {
|
||||
futures::future::ready(()).boxed().shared()
|
||||
|
||||
@@ -26,6 +26,8 @@ use codex_models_manager::bundled_models_response;
|
||||
use codex_models_manager::model_info;
|
||||
use codex_protocol::AgentPath;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::account::PlanType as AccountPlanType;
|
||||
use codex_protocol::config_types::ServiceTier;
|
||||
use codex_protocol::config_types::TrustLevel;
|
||||
use codex_protocol::exec_output::ExecToolCallOutput;
|
||||
use codex_protocol::models::FileSystemPermissions;
|
||||
@@ -2643,6 +2645,104 @@ fn session_telemetry(
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_service_tier_defaults_enterprise_accounts_to_fast() {
|
||||
assert_eq!(
|
||||
get_service_tier(
|
||||
/*configured_service_tier*/ None,
|
||||
/*fast_default_opt_out*/ false,
|
||||
Some(AccountPlanType::Enterprise),
|
||||
/*fast_mode_enabled*/ true,
|
||||
),
|
||||
Some(ServiceTier::Fast)
|
||||
);
|
||||
assert_eq!(
|
||||
get_service_tier(
|
||||
/*configured_service_tier*/ None,
|
||||
/*fast_default_opt_out*/ false,
|
||||
Some(AccountPlanType::EnterpriseCbpUsageBased),
|
||||
/*fast_mode_enabled*/ true,
|
||||
),
|
||||
Some(ServiceTier::Fast)
|
||||
);
|
||||
assert_eq!(
|
||||
get_service_tier(
|
||||
/*configured_service_tier*/ None,
|
||||
/*fast_default_opt_out*/ false,
|
||||
Some(AccountPlanType::Business),
|
||||
/*fast_mode_enabled*/ true,
|
||||
),
|
||||
Some(ServiceTier::Fast)
|
||||
);
|
||||
assert_eq!(
|
||||
get_service_tier(
|
||||
/*configured_service_tier*/ None,
|
||||
/*fast_default_opt_out*/ false,
|
||||
Some(AccountPlanType::Team),
|
||||
/*fast_mode_enabled*/ true,
|
||||
),
|
||||
Some(ServiceTier::Fast)
|
||||
);
|
||||
assert_eq!(
|
||||
get_service_tier(
|
||||
/*configured_service_tier*/ None,
|
||||
/*fast_default_opt_out*/ false,
|
||||
Some(AccountPlanType::SelfServeBusinessUsageBased),
|
||||
/*fast_mode_enabled*/ true,
|
||||
),
|
||||
Some(ServiceTier::Fast)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_service_tier_respects_fast_default_opt_out() {
|
||||
assert_eq!(
|
||||
get_service_tier(
|
||||
/*configured_service_tier*/ None,
|
||||
/*fast_default_opt_out*/ true,
|
||||
Some(AccountPlanType::Enterprise),
|
||||
/*fast_mode_enabled*/ true,
|
||||
),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_service_tier_does_not_default_non_enterprise_or_disabled_fast_mode() {
|
||||
assert_eq!(
|
||||
get_service_tier(
|
||||
/*configured_service_tier*/ None,
|
||||
/*fast_default_opt_out*/ false,
|
||||
Some(AccountPlanType::Pro),
|
||||
/*fast_mode_enabled*/ true,
|
||||
),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
get_service_tier(
|
||||
/*configured_service_tier*/ None,
|
||||
/*fast_default_opt_out*/ false,
|
||||
Some(AccountPlanType::Enterprise),
|
||||
/*fast_mode_enabled*/ false,
|
||||
),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn session_settings_null_service_tier_update_clears_service_tier() {
|
||||
let session_configuration = make_session_configuration_for_tests().await;
|
||||
|
||||
let updated = session_configuration
|
||||
.apply(&SessionSettingsUpdate {
|
||||
service_tier: Some(None),
|
||||
..Default::default()
|
||||
})
|
||||
.expect("null service tier update should apply");
|
||||
|
||||
assert_eq!(updated.service_tier, None);
|
||||
}
|
||||
|
||||
pub(crate) async fn make_session_configuration_for_tests() -> SessionConfiguration {
|
||||
let codex_home = tempfile::tempdir().expect("create temp dir");
|
||||
let config = build_test_config(codex_home.path()).await;
|
||||
|
||||
Reference in New Issue
Block a user