openai-codex.ts 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. export * as OpenAICodex from "./openai-codex"
  2. // TEMPORARY SEAM (#34765): plugins have no hook into LLM route construction, so
  3. // codex routing lives in SessionRunnerModel.fromCatalogModel and catalog filtering
  4. // in OpenAIPlugin, sharing this module. Once the native provider packages land
  5. // (#33689/#33925/#34462) this should collapse into the native OpenAI provider.
  6. // The eligibility rules mirror V1's CodexAuthPlugin allowlist; models.dev has no
  7. // plan-eligibility data for OpenAI today, but models other vendors' subscriptions
  8. // as dedicated providers (e.g. zai-coding-plan) - a future openai-chatgpt-plan
  9. // provider entry could replace the hardcoded rules with catalog data.
  10. /** ChatGPT-plan requests must target the codex backend instead of the public API. */
  11. export const baseURL = "https://chatgpt.com/backend-api/codex"
  12. const methodIDs: readonly string[] = ["chatgpt-browser", "chatgpt-headless"]
  13. /** Structural credential shape so both core and plugin-facing credential types fit. */
  14. type CredentialLike = {
  15. readonly type: string
  16. readonly methodID?: string
  17. readonly metadata?: Record<string, unknown> | undefined
  18. }
  19. export const isChatGPT = (credential: CredentialLike | undefined) =>
  20. credential?.type === "oauth" && credential.methodID !== undefined && methodIDs.includes(credential.methodID)
  21. export const accountID = (credential: CredentialLike | undefined) => {
  22. if (!isChatGPT(credential)) return undefined
  23. const value = credential?.metadata?.accountID
  24. return typeof value === "string" ? value : undefined
  25. }
  26. const allowed = new Set(["gpt-5.5", "gpt-5.3-codex-spark", "gpt-5.4", "gpt-5.4-mini"])
  27. const disallowed = new Set(["gpt-5.5-pro", "gpt-5.6"])
  28. /** Which API model ids a ChatGPT subscription may call through the codex backend. */
  29. export const eligible = (apiID: string) => {
  30. if (allowed.has(apiID)) return true
  31. if (disallowed.has(apiID)) return false
  32. const match = apiID.match(/^gpt-(\d+\.\d+)/)
  33. return match ? Number.parseFloat(match[1]) > 5.4 : false
  34. }