diff --git a/changelog.d/fixes/15164-gpt6-sol-luna-context-window.md b/changelog.d/fixes/15164-gpt6-sol-luna-context-window.md new file mode 100644 index 000000000000..02b2880e851d --- /dev/null +++ b/changelog.d/fixes/15164-gpt6-sol-luna-context-window.md @@ -0,0 +1 @@ +- fix(providers): add `gpt-6-sol` and `gpt-6-luna` to the OpenAI public API registry with the correct 1,050,000-token context window — they were missing and fell back to the 128k `defaultContextLength`, causing combos that included either model to advertise a capped-8x context window (#15023, #15164 — thanks @shipsfromrio) diff --git a/open-sse/config/providers/registry/openai/index.ts b/open-sse/config/providers/registry/openai/index.ts index d978fc5fe29d..4aa30a174274 100644 --- a/open-sse/config/providers/registry/openai/index.ts +++ b/open-sse/config/providers/registry/openai/index.ts @@ -21,6 +21,11 @@ export const openaiProvider: RegistryEntry = { supportedThinkingEfforts: ["low", "medium", "high", "xhigh", "max"], unsupportedParams: ["temperature", "top_p", "top_logprobs", "logprobs"], }, + // #15023: Sol and Luna are GPT-6 siblings with the same public API context window as + // Astra (1,050,000). They were missing from this registry, causing the importer to + // fall back to defaultContextLength (128k) and corrupting combo context advertising. + { id: "gpt-6-sol", name: "GPT-6 Sol", ...GPT_5_6_API_CAPABILITIES }, + { id: "gpt-6-luna", name: "GPT-6 Luna", ...GPT_5_6_API_CAPABILITIES }, // #11489: per OpenAI's model reference `gpt-5.6` is an ALIAS of `gpt-5.6-sol`, // not a distinct model — quality scores point forward, which no suffix // stripper can express. Siblings `-terra`/`-luna` are their own models. diff --git a/src/shared/constants/modelSpecs.ts b/src/shared/constants/modelSpecs.ts index cb1a45a06df2..7a7ae5bd5f20 100644 --- a/src/shared/constants/modelSpecs.ts +++ b/src/shared/constants/modelSpecs.ts @@ -134,6 +134,18 @@ export const MODEL_SPECS: Record = { ...GPT_5_6_MODEL_SPEC, aliases: ["openai/gpt-6-astra"], }, + // #15023: Sol and Luna were missing from the spec map; the public API context + // window is 1,050,000 (same as Astra). Without an entry, getModelSpec() returned + // undefined and any spec-aware path (capability filter, compaction guard) fell + // back to 128k, the same wrong value advertised by the importer. + "gpt-6-sol": { + ...GPT_5_6_MODEL_SPEC, + aliases: ["openai/gpt-6-sol"], + }, + "gpt-6-luna": { + ...GPT_5_6_MODEL_SPEC, + aliases: ["openai/gpt-6-luna"], + }, "gpt-6.1-sol": GPT_5_6_MODEL_SPEC, "gpt-5.6": { ...GPT_5_6_MODEL_SPEC, diff --git a/src/shared/constants/pricing/frontier-labs.ts b/src/shared/constants/pricing/frontier-labs.ts index 6ccbdc268bbe..dfe8a894cdaf 100644 --- a/src/shared/constants/pricing/frontier-labs.ts +++ b/src/shared/constants/pricing/frontier-labs.ts @@ -24,6 +24,17 @@ import { export const DEFAULT_PRICING_FRONTIER = { openai: { "gpt-6-astra": GPT_6_ASTRA_PRICING, + // Sol/Luna mirror the dollar-equivalent Codex Standard rates already used for the + // codex provider (oauth-subscriptions.ts) until OpenAI publishes distinct API rates; + // without these rows the openai registry entries resolved to $0 (catalog pricing gate). + "gpt-6-sol": { input: 2.0, output: 10.0, cached: 0.2, reasoning: 10.0, cache_creation: 2.5 }, + "gpt-6-luna": { + input: 0.1, + output: 0.5, + cached: 0.01, + reasoning: 0.5, + cache_creation: 0.125, + }, "gpt-6.1-sol": GPT_6_SOL_PRICING, "gpt-5.6": GPT_5_6_SOL_PRICING, "gpt-5.6-sol": GPT_5_6_SOL_PRICING, diff --git a/tests/unit/openai-gpt56-catalog.test.ts b/tests/unit/openai-gpt56-catalog.test.ts index c675af48fe78..4beb61b97bbd 100644 --- a/tests/unit/openai-gpt56-catalog.test.ts +++ b/tests/unit/openai-gpt56-catalog.test.ts @@ -9,9 +9,49 @@ import { DefaultExecutor } from "../../open-sse/executors/default.ts"; import { resolveChatCoreTargetFormat } from "../../open-sse/handlers/chatCore/targetFormat.ts"; import { openaiToOpenAIResponsesRequest } from "../../open-sse/translator/request/openai-responses/toResponses.ts"; -const EXPECTED_MODELS = ["gpt-6-astra", "gpt-5.6", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"]; +// Full GPT-6/5.6 family that the OpenAI public-API registry must expose in order. +// gpt-6-sol and gpt-6-luna were added by #15023 (they were missing and fell back to +// the 128k default, corrupting combo context windows). +const EXPECTED_MODELS = [ + "gpt-6-astra", + "gpt-6-sol", + "gpt-6-luna", + "gpt-5.6", + "gpt-5.6-sol", + "gpt-5.6-terra", + "gpt-5.6-luna", +]; -test("OpenAI API catalog puts Astra before GPT-5.6 and keeps GPT-5.4", () => { +// #15023: gpt-6-sol and gpt-6-luna were absent from the OpenAI registry; imported +// instances fell back to defaultContextLength (128k). These must now appear with the +// correct 1,050,000 context window, matching the rest of the GPT-6 / GPT-5.6 family. +const GPT6_SIBLINGS = ["gpt-6-sol", "gpt-6-luna"] as const; + +test("OpenAI API catalog exposes gpt-6-sol and gpt-6-luna with 1050000 context (#15023)", () => { + const models = getModelsByProviderId("openai"); + + for (const modelId of GPT6_SIBLINGS) { + const model = models.find((entry) => entry.id === modelId); + assert.ok(model, `openai registry must include ${modelId} (was missing — fell back to 128k)`); + assert.equal( + model!.contextLength, + 1050000, + `${modelId} contextLength must be 1050000, not the 128k import fallback` + ); + assert.equal(model!.maxInputTokens, 922000, `${modelId} maxInputTokens`); + assert.equal(model!.maxOutputTokens, 128000, `${modelId} maxOutputTokens`); + assert.equal(model!.toolCalling, true, `${modelId} toolCalling`); + assert.equal(model!.supportsReasoning, true, `${modelId} supportsReasoning`); + assert.equal(model!.supportsVision, true, `${modelId} supportsVision`); + + const spec = getModelSpec(modelId); + assert.ok(spec, `MODEL_SPECS must include ${modelId}`); + assert.equal(spec!.contextWindow, 1050000, `${modelId} spec contextWindow`); + assert.equal(spec!.maxOutputTokens, 128000, `${modelId} spec maxOutputTokens`); + } +}); + +test("OpenAI API catalog puts Astra/Sol/Luna before GPT-5.6 family and keeps GPT-5.4", () => { const models = getModelsByProviderId("openai"); assert.deepEqual(