diff --git a/codex-rs/backend-client/src/client.rs b/codex-rs/backend-client/src/client.rs index e7fe145987..553532ea71 100644 --- a/codex-rs/backend-client/src/client.rs +++ b/codex-rs/backend-client/src/client.rs @@ -477,6 +477,9 @@ impl Client { crate::types::PlanType::Business => AccountPlanType::Business, crate::types::PlanType::Enterprise => AccountPlanType::Enterprise, crate::types::PlanType::Edu | crate::types::PlanType::Education => AccountPlanType::Edu, + crate::types::PlanType::SelfServeBusinessUsage => { + AccountPlanType::SelfServeBusinessUsage + } crate::types::PlanType::Guest | crate::types::PlanType::FreeWorkspace | crate::types::PlanType::Quorum diff --git a/codex-rs/codex-backend-openapi-models/src/models/rate_limit_status_payload.rs b/codex-rs/codex-backend-openapi-models/src/models/rate_limit_status_payload.rs index 3d0492fa83..8cf54aedb2 100644 --- a/codex-rs/codex-backend-openapi-models/src/models/rate_limit_status_payload.rs +++ b/codex-rs/codex-backend-openapi-models/src/models/rate_limit_status_payload.rs @@ -81,4 +81,6 @@ pub enum PlanType { Enterprise, #[serde(rename = "edu")] Edu, + #[serde(rename = "self_serve_business_usage_based")] + SelfServeBusinessUsage, } diff --git a/codex-rs/core/src/error.rs b/codex-rs/core/src/error.rs index b84180d160..ac60d2c1e1 100644 --- a/codex-rs/core/src/error.rs +++ b/codex-rs/core/src/error.rs @@ -460,9 +460,7 @@ impl std::fmt::Display for UsageLimitReachedError { "You've hit your usage limit.{}", retry_suffix(self.resets_at.as_ref()) ), - Some(PlanType::Unknown(plan)) - if plan.eq_ignore_ascii_case("self_serve_business_usage_based") => - { + Some(PlanType::SelfServeBusinessUsage) => { match self .rate_limits .as_ref() diff --git a/codex-rs/exec/src/lib.rs b/codex-rs/exec/src/lib.rs index f648a63952..7ad3e6b6f2 100644 --- a/codex-rs/exec/src/lib.rs +++ b/codex-rs/exec/src/lib.rs @@ -1397,6 +1397,7 @@ fn local_external_chatgpt_tokens( AccountPlanType::Business => "business".to_string(), AccountPlanType::Enterprise => "enterprise".to_string(), AccountPlanType::Edu => "edu".to_string(), + AccountPlanType::SelfServeBusinessUsage => "self_serve_business_usage_based".to_string(), AccountPlanType::Unknown => "unknown".to_string(), }); diff --git a/codex-rs/login/src/auth/manager.rs b/codex-rs/login/src/auth/manager.rs index 1e4cd06d3a..a3dcbd17fb 100644 --- a/codex-rs/login/src/auth/manager.rs +++ b/codex-rs/login/src/auth/manager.rs @@ -275,6 +275,9 @@ impl CodexAuth { .chatgpt_plan_type .map(|pt| match pt { InternalPlanType::Known(k) => map_known(&k), + InternalPlanType::SelfServeBusinessUsage => { + AccountPlanType::SelfServeBusinessUsage + } InternalPlanType::Unknown(_) => AccountPlanType::Unknown, }) .unwrap_or(AccountPlanType::Unknown) diff --git a/codex-rs/login/src/token_data.rs b/codex-rs/login/src/token_data.rs index 304bf765f4..7b8b8f3316 100644 --- a/codex-rs/login/src/token_data.rs +++ b/codex-rs/login/src/token_data.rs @@ -39,6 +39,7 @@ impl IdTokenInfo { pub fn get_chatgpt_plan_type(&self) -> Option { self.chatgpt_plan_type.as_ref().map(|t| match t { PlanType::Known(plan) => format!("{plan:?}"), + PlanType::SelfServeBusinessUsage => "self_serve_business_usage_based".to_string(), PlanType::Unknown(s) => s.clone(), }) } @@ -48,15 +49,15 @@ impl IdTokenInfo { self.chatgpt_plan_type, Some(PlanType::Known( KnownPlan::Team | KnownPlan::Business | KnownPlan::Enterprise | KnownPlan::Edu - )) + ) | PlanType::SelfServeBusinessUsage) ) } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(untagged)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum PlanType { Known(KnownPlan), + SelfServeBusinessUsage, Unknown(String), } @@ -71,11 +72,46 @@ impl PlanType { "business" => Self::Known(KnownPlan::Business), "enterprise" => Self::Known(KnownPlan::Enterprise), "education" | "edu" => Self::Known(KnownPlan::Edu), + "self_serve_business_usage_based" => Self::SelfServeBusinessUsage, _ => Self::Unknown(raw.to_string()), } } } +impl Serialize for PlanType { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let value = match self { + Self::Known(plan) => match plan { + KnownPlan::Free => "free", + KnownPlan::Go => "go", + KnownPlan::Plus => "plus", + KnownPlan::Pro => "pro", + KnownPlan::Team => "team", + KnownPlan::Business => "business", + KnownPlan::Enterprise => "enterprise", + KnownPlan::Edu => "edu", + }, + Self::SelfServeBusinessUsage => "self_serve_business_usage_based", + Self::Unknown(raw) => raw, + }; + + serializer.serialize_str(value) + } +} + +impl<'de> Deserialize<'de> for PlanType { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let raw = String::deserialize(deserializer)?; + Ok(Self::from_raw_value(&raw)) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum KnownPlan { diff --git a/codex-rs/protocol/src/account.rs b/codex-rs/protocol/src/account.rs index 1cb58a020f..cf1e8a189d 100644 --- a/codex-rs/protocol/src/account.rs +++ b/codex-rs/protocol/src/account.rs @@ -16,6 +16,9 @@ pub enum PlanType { Business, Enterprise, Edu, + #[serde(rename = "self_serve_business_usage_based")] + #[ts(rename = "self_serve_business_usage_based")] + SelfServeBusinessUsage, #[serde(other)] Unknown, }