From 5fb3de060b26cd7aba2589a9d0077be226e7ba83 Mon Sep 17 00:00:00 2001 From: Ahmed Ibrahim Date: Sun, 10 May 2026 05:46:54 +0300 Subject: [PATCH] Save priority service tier as fast config value --- codex-rs/core/src/client.rs | 6 ++-- codex-rs/core/src/config/edit.rs | 3 +- codex-rs/core/src/config/edit_tests.rs | 33 +++++++++++++++++++++ codex-rs/protocol/src/config_types.rs | 41 ++++++++++++++++++++++++++ codex-rs/protocol/src/openai_models.rs | 1 + 5 files changed, 81 insertions(+), 3 deletions(-) diff --git a/codex-rs/core/src/client.rs b/codex-rs/core/src/client.rs index 865c14e22a..b78bc84897 100644 --- a/codex-rs/core/src/client.rs +++ b/codex-rs/core/src/client.rs @@ -73,6 +73,7 @@ use codex_otel::current_span_w3c_trace_context; use codex_protocol::SessionId; use codex_protocol::ThreadId; use codex_protocol::config_types::ReasoningSummary as ReasoningSummaryConfig; +use codex_protocol::config_types::ServiceTier; use codex_protocol::config_types::Verbosity as VerbosityConfig; use codex_protocol::models::ResponseItem; use codex_protocol::openai_models::ModelInfo; @@ -740,8 +741,9 @@ impl ModelClient { prompt.output_schema_strict, ); let prompt_cache_key = Some(self.state.thread_id.to_string()); - let service_tier = - service_tier.filter(|service_tier| model_info.supports_service_tier(service_tier)); + let service_tier = service_tier + .map(|service_tier| ServiceTier::request_value_for(&service_tier).to_string()) + .filter(|service_tier| model_info.supports_service_tier(service_tier)); let request = ResponsesApiRequest { model: model_info.slug.clone(), instructions: instructions.clone(), diff --git a/codex-rs/core/src/config/edit.rs b/codex-rs/core/src/config/edit.rs index 02ec9dc898..d4997d8430 100644 --- a/codex-rs/core/src/config/edit.rs +++ b/codex-rs/core/src/config/edit.rs @@ -7,6 +7,7 @@ use codex_config::types::SessionPickerViewMode; use codex_config::types::ToolSuggestDisabledTool; use codex_features::FEATURES; use codex_protocol::config_types::Personality; +use codex_protocol::config_types::ServiceTier; use codex_protocol::config_types::TrustLevel; use codex_protocol::openai_models::ReasoningEffort; use std::collections::BTreeMap; @@ -537,7 +538,7 @@ impl ConfigDocument { &["service_tier"], service_tier .as_ref() - .map(|service_tier| value(service_tier.clone())), + .map(|service_tier| value(ServiceTier::config_value_for(service_tier))), )), ConfigEdit::SetModelPersonality { personality } => Ok(self.write_profile_value( &["personality"], diff --git a/codex-rs/core/src/config/edit_tests.rs b/codex-rs/core/src/config/edit_tests.rs index 45af723b8f..af56db9446 100644 --- a/codex-rs/core/src/config/edit_tests.rs +++ b/codex-rs/core/src/config/edit_tests.rs @@ -3,6 +3,7 @@ use codex_config::types::AppToolApproval; use codex_config::types::McpServerToolConfig; use codex_config::types::McpServerTransportConfig; use codex_config::types::SessionPickerViewMode; +use codex_protocol::config_types::ServiceTier; use codex_protocol::openai_models::ReasoningEffort; use pretty_assertions::assert_eq; #[cfg(unix)] @@ -49,6 +50,38 @@ fn builder_with_edits_applies_custom_paths() { assert_eq!(contents, "enabled = true\n"); } +#[test] +fn blocking_set_service_tier_persists_priority_alias_as_fast() { + let tmp = tempdir().expect("tmpdir"); + let codex_home = tmp.path(); + + ConfigEditsBuilder::new(codex_home) + .set_service_tier(Some(ServiceTier::Fast.request_value().to_string())) + .apply_blocking() + .expect("persist"); + + let contents = std::fs::read_to_string(codex_home.join(CONFIG_TOML_FILE)).expect("read config"); + let expected_service_tier = ServiceTier::Fast.config_value(); + assert_eq!( + contents, + format!("service_tier = {expected_service_tier:?}\n") + ); +} + +#[test] +fn blocking_set_service_tier_preserves_custom_value() { + let tmp = tempdir().expect("tmpdir"); + let codex_home = tmp.path(); + + ConfigEditsBuilder::new(codex_home) + .set_service_tier(Some("experimental-tier-id".to_string())) + .apply_blocking() + .expect("persist"); + + let contents = std::fs::read_to_string(codex_home.join(CONFIG_TOML_FILE)).expect("read config"); + assert_eq!(contents, "service_tier = \"experimental-tier-id\"\n"); +} + #[test] fn session_picker_view_edit_writes_root_tui_setting() { let tmp = tempdir().expect("tmpdir"); diff --git a/codex-rs/protocol/src/config_types.rs b/codex-rs/protocol/src/config_types.rs index 47dc15f183..eb00c78c3f 100644 --- a/codex-rs/protocol/src/config_types.rs +++ b/codex-rs/protocol/src/config_types.rs @@ -356,6 +356,13 @@ pub enum ServiceTier { } impl ServiceTier { + pub const fn config_value(self) -> &'static str { + match self { + Self::Fast => "fast", + Self::Flex => "flex", + } + } + pub const fn request_value(self) -> &'static str { match self { Self::Fast => "priority", @@ -363,6 +370,20 @@ impl ServiceTier { } } + pub fn config_value_for(value: &str) -> &str { + match Self::from_request_value(value) { + Some(service_tier) => service_tier.config_value(), + None => value, + } + } + + pub fn request_value_for(value: &str) -> &str { + match Self::from_request_value(value) { + Some(service_tier) => service_tier.request_value(), + None => value, + } + } + pub fn from_request_value(value: &str) -> Option { match value { "fast" | "priority" => Some(Self::Fast), @@ -678,6 +699,26 @@ mod tests { } } + #[test] + fn service_tier_aliases_have_distinct_config_and_request_values() { + let values = ["fast", "priority", "flex", "experimental-tier-id"].map(|value| { + ( + ServiceTier::config_value_for(value), + ServiceTier::request_value_for(value), + ) + }); + + assert_eq!( + values, + [ + ("fast", "priority"), + ("fast", "priority"), + ("flex", "flex"), + ("experimental-tier-id", "experimental-tier-id"), + ] + ); + } + #[test] fn approvals_reviewer_serializes_auto_review_and_accepts_legacy_guardian_subagent() { assert_eq!(ApprovalsReviewer::User.to_string(), "user"); diff --git a/codex-rs/protocol/src/openai_models.rs b/codex-rs/protocol/src/openai_models.rs index d51e70ddf1..40fa2df290 100644 --- a/codex-rs/protocol/src/openai_models.rs +++ b/codex-rs/protocol/src/openai_models.rs @@ -489,6 +489,7 @@ impl ModelPreset { impl ModelInfo { pub fn supports_service_tier(&self, service_tier: &str) -> bool { + let service_tier = ServiceTier::request_value_for(service_tier); self.service_tiers .iter() .any(|tier| tier.id == service_tier)