Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions packages/opencode/src/plugin/codex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,20 @@ export const OAUTH_ALLOWED_MODELS = new Set([
"gpt-5.6-luna",
"gpt-5.6-sol",
"gpt-5.6-terra",
// altimate_change start — GPT-6 family, allowlisted on catalog evidence and
// NOT backend-probed: the one exception to "every entry was verified" above.
// openai/codex's shipped codex-rs/models-manager/models.json lists all four
// with visibility "list", upgrade null, and plus/pro in available_in_plans;
// models.dev carries all four under openai. That catalog also names them as
// the upgrade targets for the gpt-5.x ids above (gpt-5.5, gpt-5.6-sol,
// gpt-5.6-terra -> gpt-6-sol; gpt-5.6-luna -> gpt-6-luna) with retirement_at
// null, so the gpt-5.x ids stay. Probe these against the endpoint above and
// move each into VERIFIED_ACCEPTED (or out of this set) in the test file.
"gpt-6-astra",
"gpt-6-luna",
"gpt-6-sol",
"gpt-6.1-sol",
// altimate_change end
])

/** OAuth (ChatGPT-subscription) model-filter policy for the ACTIVE plugin
Expand Down
33 changes: 30 additions & 3 deletions packages/opencode/test/plugin/codex-allowlist.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ import { OAUTH_ALLOWED_MODELS, disallowedOAuthModelKeys, shouldAllowOAuthModel }
/** Verified HTTP 200 on a ChatGPT Pro subscription credential. */
const VERIFIED_ACCEPTED = ["gpt-5.3-codex-spark", "gpt-5.5", "gpt-5.6-luna", "gpt-5.6-sol", "gpt-5.6-terra"]

/** Catalog-verified, NOT backend-probed.
*
* `openai/codex`'s shipped codex-rs/models-manager/models.json lists each with
* `visibility: "list"` and `plus`/`pro` in `available_in_plans`, and models.dev
* carries each under `openai`. Nobody has sent these to the live endpoint yet,
* so they are kept apart from VERIFIED_ACCEPTED. Once probed, move each into
* VERIFIED_ACCEPTED (HTTP 200) or VERIFIED_REJECTED (HTTP 400, and drop it from
* OAUTH_ALLOWED_MODELS). */
const CATALOG_VERIFIED_UNPROBED = ["gpt-6-astra", "gpt-6-luna", "gpt-6-sol", "gpt-6.1-sol"]

/** Retired from the ChatGPT-subscription picker on 2026-08-31T19:00:00Z.
*
* Both probed HTTP 200 before the deadline, so they are not in
Expand Down Expand Up @@ -94,10 +104,27 @@ describe("OAUTH_ALLOWED_MODELS — verified subscription truth table", () => {
}
})

test("the allowlist contains nothing beyond the verified-accepted set", () => {
test("every catalog-verified id is allowlisted", () => {
// The Codex catalog lists these for Plus/Pro; hiding them is a false
// negative on the current flagship models.
for (const id of CATALOG_VERIFIED_UNPROBED) {
expect(OAUTH_ALLOWED_MODELS.has(id)).toBe(true)
}
})

test("catalog-verified ids are kept apart from the probed lists", () => {
// An id belongs in exactly one bucket. Probing one moves it out of here.
for (const id of CATALOG_VERIFIED_UNPROBED) {
expect(VERIFIED_ACCEPTED).not.toContain(id)
expect(VERIFIED_REJECTED).not.toContain(id)
}
})

test("the allowlist contains nothing beyond the verified-accepted and catalog-verified sets", () => {
// Trip-wire against speculative additions. To add an id here, probe it
// against the live endpoint first and land it in VERIFIED_ACCEPTED too.
expect([...OAUTH_ALLOWED_MODELS].sort()).toEqual([...VERIFIED_ACCEPTED].sort())
// against the live endpoint and land it in VERIFIED_ACCEPTED, or cite the
// Codex catalog and land it in CATALOG_VERIFIED_UNPROBED.
expect([...OAUTH_ALLOWED_MODELS].sort()).toEqual([...VERIFIED_ACCEPTED, ...CATALOG_VERIFIED_UNPROBED].sort())
})

test("ids retired from the subscription picker are not offered", () => {
Expand Down
Loading