Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,14 @@ when your installed Codex catalog predates them.
| `gpt-6-sol` | 272,000 | 872,000 | `medium` | `low` through `ultra` |
| `gpt-6-luna` | 272,000 | 872,000 | `medium` | `low` through `max` (no `ultra`) |

[GPT-6.1 Sol](https://openai.com/index/introducing-gpt-6-1-sol/) (announced September 29, 2026) is
listed the same way as `gpt-6.1-sol`, shown as **GPT-6.1-Sol**. It carries its own roster row
(captured at `client_version` 0.159.0) rather than GPT-6 Sol's: its own Codex instructions, a `low`
default effort and the `low` through `ultra` ladder, with the same 272,000 / 872,000 context pair.

The same `providerContextCaps.openai`, `modelContextWindows` and `modelAutoCompactTokenLimits`
levers apply as for Astra. There are no `openai-apikey/` rows or built-in price estimates for Sol
or Luna yet.
levers apply as for Astra. There are no `openai-apikey/` rows or built-in price estimates for Sol,
GPT-6.1 Sol or Luna yet.

When OpenAI ships a GPT model that this release does not know yet, add it through config instead of
waiting for an update, the same way a new Claude id goes under `providers.anthropic.models`:
Expand Down
6 changes: 6 additions & 0 deletions src/codex/catalog/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
NATIVE_GPT6_ASTRA_MODEL,
NATIVE_GPT6_LUNA_MODEL,
NATIVE_GPT6_SOL_MODEL,
NATIVE_GPT61_SOL_MODEL,
NATIVE_RESERVE_MODEL,
NATIVE_OPENAI_CAPABILITY_ALIAS_MODELS,
NATIVE_OPENAI_MODELS,
Expand All @@ -70,6 +71,7 @@ export {
NATIVE_GPT6_ASTRA_MODEL,
NATIVE_GPT6_LUNA_MODEL,
NATIVE_GPT6_SOL_MODEL,
NATIVE_GPT61_SOL_MODEL,
NATIVE_OPENAI_CAPABILITY_ALIAS_MODELS,
NATIVE_OPENAI_MODELS,
SELF_DESCRIBED_NATIVE_OPENAI_MODELS,
Expand All @@ -89,6 +91,8 @@ export const DOCUMENTED_NATIVE_OPENAI_ADDITIONS = [
// client_version >= 0.155.0, so an installed catalog built by an older client lacks them.
// Astra Minor is deliberately absent: it is gated, and nativeOpenAiSlugs() would drop it anyway.
NATIVE_GPT6_SOL_MODEL, NATIVE_GPT6_LUNA_MODEL,
// GPT-6.1 Sol from the same roster pin (captured at client_version=0.159.0).
NATIVE_GPT61_SOL_MODEL,
];

export function configuredNativeAliasSlugs(
Expand Down Expand Up @@ -196,6 +200,8 @@ export const NATIVE_OPENAI_CONTEXT_OVERRIDES: Record<string, { contextWindow?: n
// the row's own ceiling rather than the GPT-5.6 family's measured 922,000.
[NATIVE_GPT6_SOL_MODEL]: { ...NATIVE_GPT6_CONTEXT },
[NATIVE_GPT6_LUNA_MODEL]: { ...NATIVE_GPT6_CONTEXT },
// GPT-6.1 Sol's roster row (client_version=0.159.0, 2026-09-29) ships the same pair.
[NATIVE_GPT61_SOL_MODEL]: { ...NATIVE_GPT6_CONTEXT },
// Astra Minor borrows Astra's row, so it inherits Astra's numbers. No account we hold can reach
// it, so this is inheritance, not a measurement.
[NATIVE_GPT6_ASTRA_MINOR_MODEL]: { ...NATIVE_GPT6_CONTEXT },
Expand Down
16 changes: 15 additions & 1 deletion src/codex/catalog/native-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ export const NATIVE_GPT6_ASTRA_MODEL = "gpt-6-astra";
export const NATIVE_GPT6_SOL_MODEL = "gpt-6-sol";
export const NATIVE_GPT6_LUNA_MODEL = "gpt-6-luna";

/**
* GPT-6.1 Sol, announced 2026-09-29 (https://openai.com/index/introducing-gpt-6-1-sol/).
*
* SELF-DESCRIBED from its own roster row (`/backend-api/codex/models?client_version=0.159.0`,
* main account, 2026-09-29), pinned in `src/codex/data/roster-pinned-models.json`. It is not a
* capability alias of `gpt-6-sol`: the row ships its own base instructions, a `low` default,
* `multi_agent_reasoning_effort: "xhigh"` and a different Fast tier, so a configured native
* borrowing Sol's row would misdescribe it. Ungated on the same owner decision as the flagships.
*/
export const NATIVE_GPT61_SOL_MODEL = "gpt-6.1-sol";

/**
* Unreleased GPT-6 Astra variant. No public row exists anywhere — neither the codex-rs bundle nor
* the 2026-09-23 main-account roster probe carries it — so it is ACCOUNT-GATED: hidden and
Expand Down Expand Up @@ -121,6 +132,7 @@ const NATIVE_OPENAI_CAPABILITY_SOURCES: Readonly<Record<string, string>> = Objec
export const SELF_DESCRIBED_NATIVE_OPENAI_MODELS: ReadonlySet<string> = new Set([
NATIVE_GPT6_ASTRA_MODEL,
// Rows come from roster-pinned-models.json via pinnedNativeModelRows(), not the codex-rs pin.
NATIVE_GPT61_SOL_MODEL,
NATIVE_GPT6_SOL_MODEL,
NATIVE_GPT6_LUNA_MODEL,
]);
Expand Down Expand Up @@ -222,6 +234,7 @@ const BUILT_IN_NATIVE_OPENAI_MODELS: readonly string[] = Object.freeze([
"gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna",
NATIVE_DAYBREAK_BLUE_MODEL,
NATIVE_GPT6_ASTRA_MODEL,
NATIVE_GPT61_SOL_MODEL,
NATIVE_GPT6_SOL_MODEL, NATIVE_GPT6_LUNA_MODEL,
NATIVE_GPT6_ASTRA_MINOR_MODEL,
]);
Expand Down Expand Up @@ -339,7 +352,8 @@ export const NATIVE_MAIN_DRAIN_SENTINEL_MODELS: ReadonlySet<string> = new Set([
"gpt-5.6-terra",
"gpt-5.6-luna",
NATIVE_GPT6_ASTRA_MODEL,
// Astra Minor arrives through the gated spread above; Sol and Luna are ungated flagships.
// Astra Minor arrives through the gated spread above; the Sol rows and Luna are ungated flagships.
NATIVE_GPT61_SOL_MODEL,
NATIVE_GPT6_SOL_MODEL,
NATIVE_GPT6_LUNA_MODEL,
]);
185 changes: 184 additions & 1 deletion src/codex/data/roster-pinned-models.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions structure/catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ provider-wide fallback. Exact model output limits precede the provider default o
(`src/codex/catalog/pinned-models.ts`): the codex-rs snapshot first, then rows from
`src/codex/data/roster-pinned-models.json` whose slug the snapshot lacks. The roster file holds
verbatim authenticated-roster rows for models codex-rs has not bundled yet (`gpt-6-sol`,
`gpt-6-luna`, captured 2026-09-23 at `client_version=0.155.0`), so a wholesale snapshot re-pin
`gpt-6-luna` at `client_version=0.155.0`; `gpt-6.1-sol` at 0.159.0), so a wholesale snapshot re-pin
never erases them and a snapshot row for the same slug always wins;
- excludes retired `gpt-5.3-codex-spark` from native fallback, observed/cache rows, and
account-selector projections, including retained sync and native restore;
Expand Down Expand Up @@ -324,9 +324,9 @@ rows: labels `GPT-6-Sol` / `GPT-6-Luna`, 272,000 default context and 872,000 opt
`medium` default. Sol ships low-through-ultra; Luna stops at `max`, and no path may add `ultra` to
it: `nativeLadderIncludesUltra` answers from the self-described row (or an alias's source row), so
`ensureGpt56ReasoningLevels` restores `max` everywhere but adds `ultra` only where the pinned row
ships it. Both are ungated flagships. `gpt-6-astra-minor` is an account-gated capability alias of
Astra with its own presentation (`GPT-6-Astra-Minor`); it has no pinned row of its own and stays
hidden and request-refused until an authenticated roster lists it.
ships it. Both are ungated flagships, as is `gpt-6.1-sol` (own roster row, not a Sol alias).
`gpt-6-astra-minor` is an account-gated capability alias of Astra with its own presentation
(`GPT-6-Astra-Minor`); no pinned row, hidden and request-refused until a roster lists it.

The API registry separately owns Astra's 1,050,000 context / 922,000 input / 128,000 output and
five API effort levels. Trusted discovery snapshots carry the output ceiling as well as input
Expand Down
42 changes: 29 additions & 13 deletions tests/codex-integration/gpt6-native-rows.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
/**
* GPT-6 Sol, Luna and Astra Minor native rows.
* GPT-6.1 Sol, GPT-6 Sol, Luna and Astra Minor native rows.
*
* Held in its own file because tests/codex-integration/codex-catalog.test.ts sits at its
* file-size ratchet cap (see AGENTS.md, "The file-size ratchet has almost no headroom").
*
* Evidence: the authenticated roster probe of 2026-09-23
* (`chatgpt.com/backend-api/codex/models?client_version=0.155.0`, main account), pinned verbatim
* in src/codex/data/roster-pinned-models.json, and
* https://openai.com/index/introducing-gpt-6-sol-and-luna/ (announced 2026-09-22).
* https://openai.com/index/introducing-gpt-6-sol-and-luna/ (announced 2026-09-22). GPT-6.1 Sol's row
* comes from the 2026-09-29 probe at `client_version=0.159.0`, the day
* https://openai.com/index/introducing-gpt-6-1-sol/ announced it.
*/
import { afterEach, describe, expect, test } from "bun:test";
import { readFileSync } from "node:fs";
Expand All @@ -28,6 +30,7 @@ import {
NATIVE_GPT6_ASTRA_MODEL,
NATIVE_GPT6_LUNA_MODEL,
NATIVE_GPT6_SOL_MODEL,
NATIVE_GPT61_SOL_MODEL,
NATIVE_MAIN_DRAIN_SENTINEL_MODELS,
SELF_DESCRIBED_NATIVE_OPENAI_MODELS,
hasNativeOpenAiCapabilityMetadata,
Expand Down Expand Up @@ -76,13 +79,14 @@ function nativeTemplate(): Record<string, unknown> {
const SOL_LADDER = ["low", "medium", "high", "xhigh", "max", "ultra"];
const LUNA_LADDER = ["low", "medium", "high", "xhigh", "max"];

describe("GPT-6 Sol and Luna are self-described flagship natives", () => {
describe("GPT-6.1 Sol, GPT-6 Sol and Luna are self-described flagship natives", () => {
test("each projects its own roster row with its own label, windows and exact ladder", () => {
const cases = [
{ slug: NATIVE_GPT6_SOL_MODEL, wire: "gpt-6-sol", displayName: "GPT-6-Sol", ladder: SOL_LADDER },
{ slug: NATIVE_GPT6_LUNA_MODEL, wire: "gpt-6-luna", displayName: "GPT-6-Luna", ladder: LUNA_LADDER },
{ slug: NATIVE_GPT61_SOL_MODEL, wire: "gpt-6.1-sol", displayName: "GPT-6.1-Sol", ladder: SOL_LADDER, defaultEffort: "low" },
{ slug: NATIVE_GPT6_SOL_MODEL, wire: "gpt-6-sol", displayName: "GPT-6-Sol", ladder: SOL_LADDER, defaultEffort: "medium" },
{ slug: NATIVE_GPT6_LUNA_MODEL, wire: "gpt-6-luna", displayName: "GPT-6-Luna", ladder: LUNA_LADDER, defaultEffort: "medium" },
];
for (const { slug, wire, displayName, ladder } of cases) {
for (const { slug, wire, displayName, ladder, defaultEffort } of cases) {
expect(slug).toBe(wire);
expect(SELF_DESCRIBED_NATIVE_OPENAI_MODELS.has(slug)).toBe(true);
expect(isNativeOpenAiCapabilityAliasModel(slug)).toBe(false);
Expand All @@ -100,11 +104,12 @@ describe("GPT-6 Sol and Luna are self-described flagship natives", () => {
expect(nativeOpenAiContextWindow(slug)).toBe(272_000);
expect(nativeOpenAiContextTier(slug)).toEqual({ defaultWindow: 272_000, longWindow: 872_000 });
expect(nativeReasoningEfforts(slug)).toEqual(ladder);
expect(nativeDefaultReasoningEffort(slug)).toBe("medium");
expect(nativeDefaultReasoningEffort(slug)).toBe(defaultEffort);
expect(nativeInputModalities(slug)).toEqual(["text", "image"]);
expect(isGpt56NativeSlug(slug)).toBe(true);
}
// The ultra rung follows the row: Sol ships it, Luna does not.
// The ultra rung follows the row: both Sol rows ship it, Luna does not.
expect(nativeLadderIncludesUltra(NATIVE_GPT61_SOL_MODEL)).toBe(true);
expect(nativeLadderIncludesUltra(NATIVE_GPT6_SOL_MODEL)).toBe(true);
expect(nativeLadderIncludesUltra(NATIVE_GPT6_LUNA_MODEL)).toBe(false);
});
Expand All @@ -120,8 +125,18 @@ describe("GPT-6 Sol and Luna are self-described flagship natives", () => {
expect(efforts(luna)).not.toContain("ultra");
});

test("both are listed natives and neither is account-gated", () => {
for (const slug of [NATIVE_GPT6_SOL_MODEL, NATIVE_GPT6_LUNA_MODEL]) {
test("GPT-6.1 Sol keeps its own instructions rather than borrowing GPT-6 Sol's", () => {
// A configured native (providers.openai.models) would borrow gpt-6-sol's row; 6.1 ships a
// different prompt and a different Fast tier, so it must resolve to its own pinned row.
const sol61 = upstreamNativeEntry(NATIVE_GPT61_SOL_MODEL);
const sol = upstreamNativeEntry(NATIVE_GPT6_SOL_MODEL);
expect(typeof sol61?.base_instructions).toBe("string");
expect(sol61?.base_instructions).not.toBe(sol?.base_instructions);
expect(sol61?.multi_agent_reasoning_effort).toBe("xhigh");
});

test("all three are listed natives and none is account-gated", () => {
for (const slug of [NATIVE_GPT61_SOL_MODEL, NATIVE_GPT6_SOL_MODEL, NATIVE_GPT6_LUNA_MODEL]) {
expect(NATIVE_OPENAI_MODELS).toContain(slug);
expect(ACCOUNT_GATED_NATIVE_OPENAI_MODELS.has(slug)).toBe(false);
expect(DOCUMENTED_NATIVE_OPENAI_ADDITIONS).toContain(slug);
Expand Down Expand Up @@ -175,11 +190,12 @@ describe("gpt-6-astra-minor is an account-gated capability alias of gpt-6-astra"
});

describe("roster-pinned-models.json", () => {
test("holds only Sol and Luna, verbatim roster rows", () => {
test("holds only GPT-6.1 Sol, Sol and Luna, verbatim roster rows", () => {
const roster = readRows("src/codex/data/roster-pinned-models.json");
expect(roster.map(row => row.slug)).toEqual([NATIVE_GPT6_SOL_MODEL, NATIVE_GPT6_LUNA_MODEL]);
expect(roster.map(row => row.slug)).toEqual([NATIVE_GPT61_SOL_MODEL, NATIVE_GPT6_SOL_MODEL, NATIVE_GPT6_LUNA_MODEL]);
expect(efforts(roster[0])).toEqual(SOL_LADDER);
expect(efforts(roster[1])).toEqual(LUNA_LADDER);
expect(efforts(roster[1])).toEqual(SOL_LADDER);
expect(efforts(roster[2])).toEqual(LUNA_LADDER);
});

test("never shadows a slug already in upstream-models.json", () => {
Expand Down
Loading