mirror of
https://github.com/openai/codex.git
synced 2026-09-13 11:47:17 +00:00
## What changed - Recognize `edu_plus` and `edu_pro` as distinct education workspace plans across authentication, backend rate-limit mapping, and app-server account schemas. - Include both plans in cloud configuration eligibility and use the education usage-limit behavior. - Display the plans as `Edu Plus` and `Edu Pro` in the TUI status view. ## Testing - Cover parsing, workspace classification, account and rate-limit responses, cloud configuration eligibility, usage-limit messages, and TUI display names for the new variants. GitOrigin-RevId: bf8add780ae03a3c6d10c4f4afa0da262c37928e
260 lines
8.9 KiB
Rust
260 lines
8.9 KiB
Rust
use schemars::JsonSchema;
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use ts_rs::TS;
|
|
|
|
use crate::auth::KnownPlan;
|
|
use crate::auth::PlanType as AuthPlanType;
|
|
|
|
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
|
|
#[serde(rename_all = "lowercase")]
|
|
#[ts(rename_all = "lowercase")]
|
|
pub enum PlanType {
|
|
#[default]
|
|
Free,
|
|
Go,
|
|
Plus,
|
|
Pro,
|
|
ProLite,
|
|
Team,
|
|
#[serde(rename = "self_serve_business_prolite")]
|
|
#[ts(rename = "self_serve_business_prolite")]
|
|
SelfServeBusinessProLite,
|
|
#[serde(rename = "self_serve_business_usage_based")]
|
|
#[ts(rename = "self_serve_business_usage_based")]
|
|
SelfServeBusinessUsageBased,
|
|
Business,
|
|
Ent26,
|
|
#[serde(rename = "enterprise_cbp_automation")]
|
|
#[ts(rename = "enterprise_cbp_automation")]
|
|
EnterpriseCbpAutomation,
|
|
#[serde(rename = "enterprise_cbp_usage_based")]
|
|
#[ts(rename = "enterprise_cbp_usage_based")]
|
|
EnterpriseCbpUsageBased,
|
|
Enterprise,
|
|
Edu,
|
|
#[serde(rename = "edu_plus")]
|
|
#[ts(rename = "edu_plus")]
|
|
EduPlus,
|
|
#[serde(rename = "edu_pro")]
|
|
#[ts(rename = "edu_pro")]
|
|
EduPro,
|
|
#[serde(other)]
|
|
Unknown,
|
|
}
|
|
|
|
/// Account state returned by a model provider before it is adapted to an app-facing wire type.
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub enum ProviderAccount {
|
|
ApiKey,
|
|
Chatgpt {
|
|
email: Option<String>,
|
|
plan_type: PlanType,
|
|
},
|
|
AmazonBedrock {
|
|
uses_codex_managed_credentials: bool,
|
|
},
|
|
}
|
|
|
|
impl PlanType {
|
|
pub fn is_team_like(self) -> bool {
|
|
matches!(
|
|
self,
|
|
Self::Team | Self::SelfServeBusinessProLite | Self::SelfServeBusinessUsageBased
|
|
)
|
|
}
|
|
|
|
pub fn is_business_like(self) -> bool {
|
|
matches!(
|
|
self,
|
|
Self::Business
|
|
| Self::Ent26
|
|
| Self::EnterpriseCbpAutomation
|
|
| Self::EnterpriseCbpUsageBased
|
|
)
|
|
}
|
|
|
|
/// Groups education plans by workspace capabilities without losing their SKU identity.
|
|
pub fn is_education_like(self) -> bool {
|
|
matches!(self, Self::Edu | Self::EduPlus | Self::EduPro)
|
|
}
|
|
|
|
pub fn is_workspace_account(self) -> bool {
|
|
self.is_team_like()
|
|
|| self.is_business_like()
|
|
|| self.is_education_like()
|
|
|| self == Self::Enterprise
|
|
}
|
|
}
|
|
|
|
impl From<AuthPlanType> for PlanType {
|
|
fn from(plan_type: AuthPlanType) -> Self {
|
|
match plan_type {
|
|
AuthPlanType::Known(plan) => plan.into(),
|
|
AuthPlanType::Unknown(_) => Self::Unknown,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<KnownPlan> for PlanType {
|
|
fn from(plan: KnownPlan) -> Self {
|
|
match plan {
|
|
KnownPlan::Free => Self::Free,
|
|
KnownPlan::Go => Self::Go,
|
|
KnownPlan::Plus => Self::Plus,
|
|
KnownPlan::Pro => Self::Pro,
|
|
KnownPlan::ProLite => Self::ProLite,
|
|
KnownPlan::Team => Self::Team,
|
|
KnownPlan::SelfServeBusinessProLite => Self::SelfServeBusinessProLite,
|
|
KnownPlan::SelfServeBusinessUsageBased => Self::SelfServeBusinessUsageBased,
|
|
KnownPlan::Business => Self::Business,
|
|
KnownPlan::Ent26 => Self::Ent26,
|
|
KnownPlan::EnterpriseCbpAutomation => Self::EnterpriseCbpAutomation,
|
|
KnownPlan::EnterpriseCbpUsageBased => Self::EnterpriseCbpUsageBased,
|
|
KnownPlan::Enterprise => Self::Enterprise,
|
|
KnownPlan::Edu => Self::Edu,
|
|
KnownPlan::EduPlus => Self::EduPlus,
|
|
KnownPlan::EduPro => Self::EduPro,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::PlanType;
|
|
use crate::auth::KnownPlan;
|
|
use crate::auth::PlanType as AuthPlanType;
|
|
use pretty_assertions::assert_eq;
|
|
|
|
#[test]
|
|
fn business_plan_types_use_expected_wire_names() {
|
|
assert_eq!(
|
|
serde_json::to_string(&PlanType::SelfServeBusinessProLite)
|
|
.expect("self-serve business ProLite should serialize"),
|
|
"\"self_serve_business_prolite\""
|
|
);
|
|
assert_eq!(
|
|
serde_json::to_string(&PlanType::SelfServeBusinessUsageBased)
|
|
.expect("self-serve business usage based should serialize"),
|
|
"\"self_serve_business_usage_based\""
|
|
);
|
|
assert_eq!(
|
|
serde_json::to_string(&PlanType::EnterpriseCbpUsageBased)
|
|
.expect("enterprise cbp usage based should serialize"),
|
|
"\"enterprise_cbp_usage_based\""
|
|
);
|
|
assert_eq!(
|
|
serde_json::to_string(&PlanType::EnterpriseCbpAutomation)
|
|
.expect("enterprise cbp automation should serialize"),
|
|
"\"enterprise_cbp_automation\""
|
|
);
|
|
assert_eq!(
|
|
serde_json::to_string(&PlanType::Ent26).expect("ent26 should serialize"),
|
|
"\"ent26\""
|
|
);
|
|
assert_eq!(
|
|
serde_json::to_string(&PlanType::ProLite).expect("prolite should serialize"),
|
|
"\"prolite\""
|
|
);
|
|
assert_eq!(
|
|
serde_json::from_str::<PlanType>("\"self_serve_business_prolite\"")
|
|
.expect("self-serve business ProLite should deserialize"),
|
|
PlanType::SelfServeBusinessProLite
|
|
);
|
|
assert_eq!(
|
|
serde_json::from_str::<PlanType>("\"self_serve_business_usage_based\"")
|
|
.expect("self-serve business usage based should deserialize"),
|
|
PlanType::SelfServeBusinessUsageBased
|
|
);
|
|
assert_eq!(
|
|
serde_json::from_str::<PlanType>("\"prolite\"").expect("prolite should deserialize"),
|
|
PlanType::ProLite
|
|
);
|
|
assert_eq!(
|
|
serde_json::from_str::<PlanType>("\"enterprise_cbp_usage_based\"")
|
|
.expect("enterprise cbp usage based should deserialize"),
|
|
PlanType::EnterpriseCbpUsageBased
|
|
);
|
|
assert_eq!(
|
|
serde_json::from_str::<PlanType>("\"enterprise_cbp_automation\"")
|
|
.expect("enterprise cbp automation should deserialize"),
|
|
PlanType::EnterpriseCbpAutomation
|
|
);
|
|
assert_eq!(
|
|
serde_json::from_str::<PlanType>("\"ent26\"").expect("ent26 should deserialize"),
|
|
PlanType::Ent26
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn plan_family_helpers_group_business_variants_with_existing_plans() {
|
|
assert_eq!(PlanType::Team.is_team_like(), true);
|
|
assert_eq!(PlanType::SelfServeBusinessProLite.is_team_like(), true);
|
|
assert_eq!(PlanType::SelfServeBusinessUsageBased.is_team_like(), true);
|
|
assert_eq!(PlanType::Business.is_team_like(), false);
|
|
assert_eq!(PlanType::Ent26.is_team_like(), false);
|
|
|
|
assert_eq!(PlanType::Business.is_business_like(), true);
|
|
assert_eq!(PlanType::Ent26.is_business_like(), true);
|
|
assert_eq!(PlanType::EnterpriseCbpAutomation.is_business_like(), true);
|
|
assert_eq!(PlanType::EnterpriseCbpUsageBased.is_business_like(), true);
|
|
assert_eq!(PlanType::Team.is_business_like(), false);
|
|
}
|
|
|
|
#[test]
|
|
fn workspace_account_helper_includes_business_workspace_plans() {
|
|
assert_eq!(PlanType::Team.is_workspace_account(), true);
|
|
assert_eq!(
|
|
PlanType::SelfServeBusinessProLite.is_workspace_account(),
|
|
true
|
|
);
|
|
assert_eq!(
|
|
PlanType::SelfServeBusinessUsageBased.is_workspace_account(),
|
|
true
|
|
);
|
|
assert_eq!(PlanType::Business.is_workspace_account(), true);
|
|
assert_eq!(PlanType::Ent26.is_workspace_account(), true);
|
|
assert_eq!(
|
|
PlanType::EnterpriseCbpAutomation.is_workspace_account(),
|
|
true
|
|
);
|
|
assert_eq!(
|
|
PlanType::EnterpriseCbpUsageBased.is_workspace_account(),
|
|
true
|
|
);
|
|
assert_eq!(PlanType::Enterprise.is_workspace_account(), true);
|
|
assert_eq!(PlanType::Edu.is_workspace_account(), true);
|
|
assert_eq!(PlanType::EduPlus.is_workspace_account(), true);
|
|
assert_eq!(PlanType::EduPro.is_workspace_account(), true);
|
|
assert_eq!(PlanType::Pro.is_workspace_account(), false);
|
|
}
|
|
|
|
#[test]
|
|
fn auth_plan_type_converts_to_account_plan_type() {
|
|
assert_eq!(
|
|
PlanType::from(AuthPlanType::Known(KnownPlan::SelfServeBusinessProLite)),
|
|
PlanType::SelfServeBusinessProLite
|
|
);
|
|
assert_eq!(
|
|
PlanType::from(AuthPlanType::Known(KnownPlan::EnterpriseCbpUsageBased)),
|
|
PlanType::EnterpriseCbpUsageBased
|
|
);
|
|
assert_eq!(
|
|
PlanType::from(AuthPlanType::Known(KnownPlan::EnterpriseCbpAutomation)),
|
|
PlanType::EnterpriseCbpAutomation
|
|
);
|
|
assert_eq!(
|
|
PlanType::from(AuthPlanType::Known(KnownPlan::Ent26)),
|
|
PlanType::Ent26
|
|
);
|
|
assert_eq!(
|
|
PlanType::from(AuthPlanType::Known(KnownPlan::Enterprise)),
|
|
PlanType::Enterprise
|
|
);
|
|
assert_eq!(
|
|
PlanType::from(AuthPlanType::Unknown("mystery-tier".to_string())),
|
|
PlanType::Unknown
|
|
);
|
|
}
|
|
}
|