diff --git a/apps/server/src/provider/Layers/CodexProvider.test.ts b/apps/server/src/provider/Layers/CodexProvider.test.ts index 0c7a40d9bd9ef84a4b076b137da5507ddb553e15..2c67b6f144dbb998716bcef4a30bde9de345e0a7 100644 --- a/apps/server/src/provider/Layers/CodexProvider.test.ts +++ b/apps/server/src/provider/Layers/CodexProvider.test.ts @@ -81,6 +81,11 @@ it("uses standard routing when the catalog has no default service tier", () => { name: "Fast", description: "1.5x speed, increased usage", }, + { + id: "ultrafast", + name: "Ultrafast", + description: "The fastest available responses for latency-sensitive work.", + }, ], supportedReasoningEfforts: [], }); @@ -97,6 +102,11 @@ it("uses standard routing when the catalog has no default service tier", () => { label: "Fast", description: "1.5x speed, increased usage", }, + { + id: "ultrafast", + label: "Ultrafast", + description: "Even faster, more expensive", + }, ], currentValue: "default", }, diff --git a/apps/server/src/provider/Layers/CodexProvider.ts b/apps/server/src/provider/Layers/CodexProvider.ts index 57b0cab334bbe5e18e713bc4dfe730429e9866c4..72ca3fd74f0d18036005f7f85741b20ea7d77b9b 100644 --- a/apps/server/src/provider/Layers/CodexProvider.ts +++ b/apps/server/src/provider/Layers/CodexProvider.ts @@ -90,6 +90,11 @@ const REASONING_EFFORT_LABELS: Readonly> = { const DEFAULT_SERVICE_TIER_ID = "default"; +/** Shorter copy for tiers whose catalog description wraps in the traits menu. */ +const SERVICE_TIER_DESCRIPTIONS: Readonly> = { + ultrafast: "Even faster, more expensive", +}; + function reasoningEffortLabel(reasoningEffort: string): string { return REASONING_EFFORT_LABELS[reasoningEffort] ?? reasoningEffort; } @@ -115,6 +120,8 @@ export function codexPlanLabel(planType: string | null | undefined): string | un return "ChatGPT Pro 20x Subscription"; case "prolite": return "ChatGPT Pro 5x Subscription"; + case "promax": + return "ChatGPT Pro Max Subscription"; case "team": return "ChatGPT Team Subscription"; case "self_serve_business_prolite": @@ -195,12 +202,15 @@ export function mapCodexModelCapabilities( label: "Standard", ...(defaultServiceTier === DEFAULT_SERVICE_TIER_ID ? { isDefault: true } : {}), }, - ...serviceTiers.map((tier) => ({ - id: tier.id, - label: tier.name, - ...(tier.description ? { description: tier.description } : {}), - ...(defaultServiceTier === tier.id ? { isDefault: true } : {}), - })), + ...serviceTiers.map((tier) => { + const description = SERVICE_TIER_DESCRIPTIONS[tier.id] ?? tier.description; + return { + id: tier.id, + label: tier.name, + ...(description ? { description } : {}), + ...(defaultServiceTier === tier.id ? { isDefault: true } : {}), + }; + }), ], currentValue: defaultServiceTier, }); diff --git a/packages/effect-codex-app-server/scripts/generate.ts b/packages/effect-codex-app-server/scripts/generate.ts index b2696097ef8c7872acb20ea6ca40a3850e8e0292..8825f6044fc271d492c1eaf990487168c1c46b82 100644 --- a/packages/effect-codex-app-server/scripts/generate.ts +++ b/packages/effect-codex-app-server/scripts/generate.ts @@ -145,6 +145,13 @@ const ManualSchemas: Record = { }, }; +// Codex adds plan slugs between our protocol refreshes (0.159 added `promax`). +// T3 Code only uses the plan for labels, so an unknown slug must not fail the +// whole `account/read` decode and take the provider down with it. +const DefinitionOverrides: Record = { + PlanType: { type: "string" }, +}; + const getGeneratedPaths = Effect.fn("getGeneratedPaths")(function* () { const path = yield* Path.Path; const generatedDir = path.join(import.meta.dirname, "..", "src", "_generated"); @@ -643,7 +650,7 @@ const generateFiles = Effect.fn("generateFiles")(function* () { aggregateSchemas[localDefinitionNames.get(definitionName)!] = stripNullDefaults( normalizeNullableTypes( rewriteExternalRefs( - definitionSchema, + DefinitionOverrides[definitionName] ?? definitionSchema, localDefinitionNames, file.namespace, exportNameByQualifiedName, diff --git a/packages/effect-codex-app-server/src/_generated/schema.gen.ts b/packages/effect-codex-app-server/src/_generated/schema.gen.ts index 9bc7b1ec1e9edbd4d95f76e94b3aaebc648e61a6..e9ac22ec120b9c6ca92cf4d9320e9bd141bae79f 100644 --- a/packages/effect-codex-app-server/src/_generated/schema.gen.ts +++ b/packages/effect-codex-app-server/src/_generated/schema.gen.ts @@ -3204,43 +3204,10 @@ export const ServerNotification__AuthMode = Schema.Union( identifier: "ServerNotification__AuthMode", }); -export type ServerNotification__PlanType = - | "free" - | "go" - | "plus" - | "pro" - | "prolite" - | "team" - | "self_serve_business_prolite" - | "self_serve_business_usage_based" - | "business" - | "ent26" - | "enterprise_cbp_automation" - | "enterprise_cbp_usage_based" - | "enterprise" - | "edu" - | "edu_plus" - | "edu_pro" - | "unknown"; -export const ServerNotification__PlanType = Schema.Literals([ - "free", - "go", - "plus", - "pro", - "prolite", - "team", - "self_serve_business_prolite", - "self_serve_business_usage_based", - "business", - "ent26", - "enterprise_cbp_automation", - "enterprise_cbp_usage_based", - "enterprise", - "edu", - "edu_plus", - "edu_pro", - "unknown", -]).annotate({ identifier: "ServerNotification__PlanType" }); +export type ServerNotification__PlanType = string; +export const ServerNotification__PlanType = Schema.String.annotate({ + identifier: "ServerNotification__PlanType", +}); export type ServerNotification__CreditsSnapshot = { readonly balance?: string | null; @@ -4138,43 +4105,10 @@ export const V2AccountRateLimitsUpdatedNotification__SpendControlLimitSnapshot = used: Schema.String, }).annotate({ identifier: "V2AccountRateLimitsUpdatedNotification__SpendControlLimitSnapshot" }); -export type V2AccountRateLimitsUpdatedNotification__PlanType = - | "free" - | "go" - | "plus" - | "pro" - | "prolite" - | "team" - | "self_serve_business_prolite" - | "self_serve_business_usage_based" - | "business" - | "ent26" - | "enterprise_cbp_automation" - | "enterprise_cbp_usage_based" - | "enterprise" - | "edu" - | "edu_plus" - | "edu_pro" - | "unknown"; -export const V2AccountRateLimitsUpdatedNotification__PlanType = Schema.Literals([ - "free", - "go", - "plus", - "pro", - "prolite", - "team", - "self_serve_business_prolite", - "self_serve_business_usage_based", - "business", - "ent26", - "enterprise_cbp_automation", - "enterprise_cbp_usage_based", - "enterprise", - "edu", - "edu_plus", - "edu_pro", - "unknown", -]).annotate({ identifier: "V2AccountRateLimitsUpdatedNotification__PlanType" }); +export type V2AccountRateLimitsUpdatedNotification__PlanType = string; +export const V2AccountRateLimitsUpdatedNotification__PlanType = Schema.String.annotate({ + identifier: "V2AccountRateLimitsUpdatedNotification__PlanType", +}); export type V2AccountRateLimitsUpdatedNotification__RateLimitWindow = { readonly resetsAt?: number | null; @@ -4260,43 +4194,10 @@ export const V2AccountUpdatedNotification__AuthMode = Schema.Union( identifier: "V2AccountUpdatedNotification__AuthMode", }); -export type V2AccountUpdatedNotification__PlanType = - | "free" - | "go" - | "plus" - | "pro" - | "prolite" - | "team" - | "self_serve_business_prolite" - | "self_serve_business_usage_based" - | "business" - | "ent26" - | "enterprise_cbp_automation" - | "enterprise_cbp_usage_based" - | "enterprise" - | "edu" - | "edu_plus" - | "edu_pro" - | "unknown"; -export const V2AccountUpdatedNotification__PlanType = Schema.Literals([ - "free", - "go", - "plus", - "pro", - "prolite", - "team", - "self_serve_business_prolite", - "self_serve_business_usage_based", - "business", - "ent26", - "enterprise_cbp_automation", - "enterprise_cbp_usage_based", - "enterprise", - "edu", - "edu_plus", - "edu_pro", - "unknown", -]).annotate({ identifier: "V2AccountUpdatedNotification__PlanType" }); +export type V2AccountUpdatedNotification__PlanType = string; +export const V2AccountUpdatedNotification__PlanType = Schema.String.annotate({ + identifier: "V2AccountUpdatedNotification__PlanType", +}); export type V2AppListUpdatedNotification__AppReview = { readonly status: string }; export const V2AppListUpdatedNotification__AppReview = Schema.Struct({ @@ -5484,43 +5385,10 @@ export const V2GetAccountRateLimitsResponse__SpendControlLimitSnapshot = Schema. used: Schema.String, }).annotate({ identifier: "V2GetAccountRateLimitsResponse__SpendControlLimitSnapshot" }); -export type V2GetAccountRateLimitsResponse__PlanType = - | "free" - | "go" - | "plus" - | "pro" - | "prolite" - | "team" - | "self_serve_business_prolite" - | "self_serve_business_usage_based" - | "business" - | "ent26" - | "enterprise_cbp_automation" - | "enterprise_cbp_usage_based" - | "enterprise" - | "edu" - | "edu_plus" - | "edu_pro" - | "unknown"; -export const V2GetAccountRateLimitsResponse__PlanType = Schema.Literals([ - "free", - "go", - "plus", - "pro", - "prolite", - "team", - "self_serve_business_prolite", - "self_serve_business_usage_based", - "business", - "ent26", - "enterprise_cbp_automation", - "enterprise_cbp_usage_based", - "enterprise", - "edu", - "edu_plus", - "edu_pro", - "unknown", -]).annotate({ identifier: "V2GetAccountRateLimitsResponse__PlanType" }); +export type V2GetAccountRateLimitsResponse__PlanType = string; +export const V2GetAccountRateLimitsResponse__PlanType = Schema.String.annotate({ + identifier: "V2GetAccountRateLimitsResponse__PlanType", +}); export type V2GetAccountRateLimitsResponse__RateLimitWindow = { readonly resetsAt?: number | null; @@ -5563,43 +5431,10 @@ export const V2GetAccountRateLimitsResponse__RateLimitReachedType = Schema.Liter "workspace_member_usage_limit_reached", ]).annotate({ identifier: "V2GetAccountRateLimitsResponse__RateLimitReachedType" }); -export type V2GetAccountResponse__PlanType = - | "free" - | "go" - | "plus" - | "pro" - | "prolite" - | "team" - | "self_serve_business_prolite" - | "self_serve_business_usage_based" - | "business" - | "ent26" - | "enterprise_cbp_automation" - | "enterprise_cbp_usage_based" - | "enterprise" - | "edu" - | "edu_plus" - | "edu_pro" - | "unknown"; -export const V2GetAccountResponse__PlanType = Schema.Literals([ - "free", - "go", - "plus", - "pro", - "prolite", - "team", - "self_serve_business_prolite", - "self_serve_business_usage_based", - "business", - "ent26", - "enterprise_cbp_automation", - "enterprise_cbp_usage_based", - "enterprise", - "edu", - "edu_plus", - "edu_pro", - "unknown", -]).annotate({ identifier: "V2GetAccountResponse__PlanType" }); +export type V2GetAccountResponse__PlanType = string; +export const V2GetAccountResponse__PlanType = Schema.String.annotate({ + identifier: "V2GetAccountResponse__PlanType", +}); export type V2GetAccountResponse__AccountRoutingOverride = "NO_CONSTRAINT" | "us" | "us_cr"; export const V2GetAccountResponse__AccountRoutingOverride = Schema.Literals([ diff --git a/packages/effect-codex-app-server/src/schema.test.ts b/packages/effect-codex-app-server/src/schema.test.ts index b12b33e0285409056bda21a5e7680ea6a422bc4c..cc88b9e383635982ce530fb997cc36517e994f2b 100644 --- a/packages/effect-codex-app-server/src/schema.test.ts +++ b/packages/effect-codex-app-server/src/schema.test.ts @@ -201,13 +201,15 @@ it("accepts Codex misalignment policy errors for thread responses", () => { ); }); -it("accepts Codex 0.150 account plan values", () => { +it("accepts account plan slugs newer than the pinned protocol", () => { const planTypes = [ "self_serve_business_prolite", "ent26", "enterprise_cbp_automation", "edu_plus", "edu_pro", + "promax", + "some_future_plan", ]; for (const planType of planTypes) {