Add usage-based business plan types (#15934)

## Summary
- add `self_serve_business_usage_based` and `enterprise_cbp_usage_based`
to the public/internal plan enums and regenerate the app-server + Python
SDK artifacts
- map both plans through JWT login and backend rate-limit payloads, then
bucket them with the existing Team/Business entitlement behavior in
cloud requirements, usage-limit copy, tooltips, and status display
- keep the earlier display-label remap commit on this branch so the new
Team-like and Business-like plans render consistently in the UI

## Testing
- `just write-app-server-schema`
- `uv run --project sdk/python python
sdk/python/scripts/update_sdk_artifacts.py generate-types`
- `just fix -p codex-protocol -p codex-login -p codex-core -p
codex-backend-client -p codex-cloud-requirements -p codex-tui -p
codex-tui-app-server -p codex-backend-openapi-models`
- `just fmt`
- `just argument-comment-lint`
- `cargo test -p codex-protocol
usage_based_plan_types_use_expected_wire_names`
- `cargo test -p codex-login usage_based`
- `cargo test -p codex-backend-client usage_based`
- `cargo test -p codex-cloud-requirements usage_based`
- `cargo test -p codex-core usage_limit_reached_error_formats_`
- `cargo test -p codex-tui plan_type_display_name_remaps_display_labels`
- `cargo test -p codex-tui remapped`
- `cargo test -p codex-tui-app-server
plan_type_display_name_remaps_display_labels`
- `cargo test -p codex-tui-app-server remapped`
- `cargo test -p codex-tui-app-server
preserves_usage_based_plan_type_wire_name`

## Notes
- a broader multi-crate `cargo test` run still hits unrelated existing
guardian-approval config failures in
`codex-rs/core/src/config/config_tests.rs`
This commit is contained in:
bwanner-oai authored and GitHub committed 2026-03-27 14:25:13 -07:00
1 parent 81abb44f68
commit 82e8031338
27 files changed
+1177 -388

No files matched your search

+46
View File
@@ -458,6 +458,52 @@ fn plan_type_maps_known_plan() {
pretty_assertions::assert_eq!(auth.account_plan_type(), Some(AccountPlanType::Pro));
}
#[test]
fn plan_type_maps_self_serve_business_usage_based_plan() {
let codex_home = tempdir().unwrap();
let _jwt = write_auth_file(
AuthFileParams {
openai_api_key: None,
chatgpt_plan_type: Some("self_serve_business_usage_based".to_string()),
chatgpt_account_id: None,
},
codex_home.path(),
)
.expect("failed to write auth file");
let auth = super::load_auth(codex_home.path(), false, AuthCredentialsStoreMode::File)
.expect("load auth")
.expect("auth available");
pretty_assertions::assert_eq!(
auth.account_plan_type(),
Some(AccountPlanType::SelfServeBusinessUsageBased)
);
}
#[test]
fn plan_type_maps_enterprise_cbp_usage_based_plan() {
let codex_home = tempdir().unwrap();
let _jwt = write_auth_file(
AuthFileParams {
openai_api_key: None,
chatgpt_plan_type: Some("enterprise_cbp_usage_based".to_string()),
chatgpt_account_id: None,
},
codex_home.path(),
)
.expect("failed to write auth file");
let auth = super::load_auth(codex_home.path(), false, AuthCredentialsStoreMode::File)
.expect("load auth")
.expect("auth available");
pretty_assertions::assert_eq!(
auth.account_plan_type(),
Some(AccountPlanType::EnterpriseCbpUsageBased)
);
}
#[test]
fn plan_type_maps_unknown_to_unknown() {
let codex_home = tempdir().unwrap();
+4
View File
@@ -266,7 +266,11 @@ impl CodexAuth {
InternalKnownPlan::Plus => AccountPlanType::Plus,
InternalKnownPlan::Pro => AccountPlanType::Pro,
InternalKnownPlan::Team => AccountPlanType::Team,
InternalKnownPlan::SelfServeBusinessUsageBased => {
AccountPlanType::SelfServeBusinessUsageBased
}
InternalKnownPlan::Business => AccountPlanType::Business,
InternalKnownPlan::EnterpriseCbpUsageBased => AccountPlanType::EnterpriseCbpUsageBased,
InternalKnownPlan::Enterprise => AccountPlanType::Enterprise,
InternalKnownPlan::Edu => AccountPlanType::Edu,
};