From 568835ed50b80f78174e350459b829b5a2ea6b79 Mon Sep 17 00:00:00 2001 From: texra-ai <207051187+texra-ai@users.noreply.github.com> Date: Mon, 17 Aug 2026 17:30:58 +0200 Subject: [PATCH 1/4] fix: cap GPT-5.6 ChatGPT sessions at the Codex 272k input budget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codex CLI 0.145.0 lists 272k for Sol, Terra, and Luna — the same as GPT-5.5. The old 372k/500k split delayed compaction until the unofficial backend rejected the turn. --- CHANGELOG.md | 3 ++ src/model/providerCapabilities.ts | 45 ++++++++----------- src/test-kernel/cli/StatusBar.vitest.ts | 6 +-- .../model/ProviderCapabilities.vitest.ts | 41 +++++++++-------- 4 files changed, 44 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 664fa7fd6df..6b322090333 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,9 @@ All notable changes to this project will be documented in this file. #### Bug Fixes +- **GPT-5.6 ChatGPT-subscription sessions use the same 272k input budget as GPT-5.5** — + matching the current Codex catalog, so history is compacted before the + unofficial backend rejects a turn. - **A missing helper model falls back to DeepSeek V4 Flash** — disabling or removing the helper no longer silently switches auxiliary tasks to the first picker model. diff --git a/src/model/providerCapabilities.ts b/src/model/providerCapabilities.ts index 14fcb0f507a..aaf96fc70a2 100644 --- a/src/model/providerCapabilities.ts +++ b/src/model/providerCapabilities.ts @@ -45,13 +45,15 @@ export interface ProviderCapabilityKey { readonly useOpenRouter: boolean; } -/** Default Codex budget (GPT-5.5 and earlier). */ -export const CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW = 400_000; +/** + * ChatGPT-subscription Codex input budget. Matches Codex CLI 0.145.0's + * `context_window` / `max_context_window` for GPT-5.5 and GPT-5.6 Sol / + * Terra / Luna. Displayed context is this plus the registry `maxOutputTokens` + * (128k → 400k), same split OpenCode uses. + */ export const CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT = 272_000; - -/** GPT-5.6 Codex budget: 372k input plus 128k output. */ -export const CODEX_GPT56_SUBSCRIPTION_CONTEXT_WINDOW = 500_000; -export const CODEX_GPT56_SUBSCRIPTION_INPUT_LIMIT = 372_000; +export const CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW = + CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT + 128_000; /** Trailing llm-zoo date pin (`-2026-04-23`) on a model `fullName`. */ const CODEX_MODEL_DATE_PIN = /-\d{4}-\d{2}-\d{2}$/; @@ -67,22 +69,6 @@ export function codexBackendModelId(config: { return config.shortName || config.fullName.replace(CODEX_MODEL_DATE_PIN, ''); } -function codexSubscriptionTokenLimits(model: ModelConfig): { - contextWindow: number; - inputTokenLimit: number; -} { - if (codexBackendModelId(model).startsWith('gpt-5.6')) { - return { - contextWindow: CODEX_GPT56_SUBSCRIPTION_CONTEXT_WINDOW, - inputTokenLimit: CODEX_GPT56_SUBSCRIPTION_INPUT_LIMIT, - }; - } - return { - contextWindow: CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW, - inputTokenLimit: CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT, - }; -} - /** * Whether `model` is eligible to route through the ChatGPT-subscription * (Codex) backend. @@ -122,14 +108,19 @@ export function resolveCodexSubscriptionProfile({ if (model.provider !== ModelProvider.OPENAI) return null; if (model.openRouterOnly) return null; if (!isCodexSubscriptionEligible(model)) return null; - const tokenLimits = codexSubscriptionTokenLimits(model); + const inputTokenLimit = Math.min( + CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT, + model.contextWindow, + ); + const contextWindow = Math.min( + inputTokenLimit + model.maxOutputTokens, + model.contextWindow, + ); return { authMode: 'chatgpt-subscription', - ...zeroCostAccessOverrides( - Math.min(tokenLimits.contextWindow, model.contextWindow), - ), - inputTokenLimit: Math.min(tokenLimits.inputTokenLimit, model.contextWindow), + ...zeroCostAccessOverrides(contextWindow), + inputTokenLimit, usageRoute: 'chatgpt-subscription', openAIResponses: { backgroundMode: 'disabled', diff --git a/src/test-kernel/cli/StatusBar.vitest.ts b/src/test-kernel/cli/StatusBar.vitest.ts index 0e74471830f..5aa3305ac70 100644 --- a/src/test-kernel/cli/StatusBar.vitest.ts +++ b/src/test-kernel/cli/StatusBar.vitest.ts @@ -733,9 +733,9 @@ describe('CLI StatusBar display model', () => { }), ); - // gpt-5.6's Codex subscription budget caps to 500k - // (CODEX_GPT56_SUBSCRIPTION_CONTEXT_WINDOW), not the raw 1.05M API window. - expect(leftTexts(display)).toContain('187k/500k (37%)'); + // gpt-5.6's Codex subscription budget caps to 400k + // (CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW), not the raw 1.05M API window. + expect(leftTexts(display)).toContain('187k/400k (47%)'); }); it('uses the default 400k subscription budget for earlier Codex models', () => { diff --git a/src/test-kernel/model/ProviderCapabilities.vitest.ts b/src/test-kernel/model/ProviderCapabilities.vitest.ts index dab8ee5cc71..e84e5436aaa 100644 --- a/src/test-kernel/model/ProviderCapabilities.vitest.ts +++ b/src/test-kernel/model/ProviderCapabilities.vitest.ts @@ -16,8 +16,6 @@ import { installTexraModelAccess } from '@controllers/modelAccess/installTexraMo import { CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT, CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW, - CODEX_GPT56_SUBSCRIPTION_INPUT_LIMIT, - CODEX_GPT56_SUBSCRIPTION_CONTEXT_WINDOW, isCodexSubscriptionActive, resolveCodexSubscriptionCapabilities, resolveCodexSubscriptionProfile, @@ -44,14 +42,6 @@ const gpt55Config: ModelConfig = { codexSubscription: true, }; -const gpt56Config: ModelConfig = { - ...gpt55Config, - name: 'gpt56--', - label: 'GPT-5.6 Luna', - fullName: 'gpt-5.6-luna', - shortName: 'gpt-5.6-luna', -}; - const signedInSession: CodexSession = { accessToken: 'access-token', refreshToken: 'refresh-token', @@ -112,17 +102,26 @@ describe('provider capabilities', () => { }); }); - it('uses the larger Codex input budget for GPT-5.6', () => { - const capabilities = resolveCodexSubscriptionProfile({ - model: gpt56Config, - useOpenRouter: false, - }); - - expect(capabilities).toMatchObject({ - contextWindow: CODEX_GPT56_SUBSCRIPTION_CONTEXT_WINDOW, - inputTokenLimit: CODEX_GPT56_SUBSCRIPTION_INPUT_LIMIT, - }); - }); + it.each(['gpt56', 'gpt56-', 'gpt56--'] as const)( + 'caps ChatGPT-subscription %s to the Codex 272k input / 400k context budget', + (id) => { + const model = MODEL_CONFIGS[id]; + const capabilities = resolveCodexSubscriptionProfile({ + model, + useOpenRouter: false, + }); + + expect(model.codexSubscription).toBe(true); + expect(capabilities).toMatchObject({ + contextWindow: + CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT + model.maxOutputTokens, + inputTokenLimit: CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT, + }); + expect(capabilities?.contextWindow).toBe( + CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW, + ); + }, + ); }); describe('ChatGPT subscription model routing', () => { From cdc505916cbf6c8441cd8904873322b2c787a460 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 17 Aug 2026 17:43:05 +0200 Subject: [PATCH 2/4] test(model): assert dynamic subscription context --- .../CodexSubscriptionFallback.vitest.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/test-kernel/agent/modelHandlers/CodexSubscriptionFallback.vitest.ts b/src/test-kernel/agent/modelHandlers/CodexSubscriptionFallback.vitest.ts index a3de5a4d908..5a9f5b6e518 100644 --- a/src/test-kernel/agent/modelHandlers/CodexSubscriptionFallback.vitest.ts +++ b/src/test-kernel/agent/modelHandlers/CodexSubscriptionFallback.vitest.ts @@ -7,10 +7,7 @@ import type { ModelCredentialRoute } from '@agent/types/ModelHandlerContracts'; import { CODEX_BACKEND_BASE_URL, resetCodexCoordinator } from '@auth/codex'; import { setServerSideKeyService } from '@auth/serverKeys'; import { apiKeySecretName, invalidateApiKeyCache } from '@model/apiProviders'; -import { - CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW, - CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT, -} from '@model/providerCapabilities'; +import { CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT } from '@model/providerCapabilities'; import { setPreferCodexSubscription, isPreferCodexSubscription, @@ -58,6 +55,9 @@ const largeWindowConfig: ModelConfig = { contextWindow: 1_050_000, }; +const LARGE_WINDOW_SUBSCRIPTION_CONTEXT = + CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT + largeWindowConfig.maxOutputTokens; + const ONE_MILLION_INPUT_TOKENS = { input_tokens: 1_000_000, output_tokens: 0, @@ -142,16 +142,17 @@ describe('ModelHandlerCodex subscription fallback', () => { const handler = await newSubscriptionHandler(largeWindowConfig); // The model's own 1.05M API window must not leak through on the - // subscription path, where the backend rejects requests past the ceiling. + // subscription path. The displayed ceiling includes this fixture's output + // allowance in addition to the shared Codex input budget. expect(handler.getEffectiveContextWindow()).toBe( - CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW, + LARGE_WINDOW_SUBSCRIPTION_CONTEXT, ); }); it('restores the full model window after falling back to the API key', async () => { const handler = await newSubscriptionHandler(largeWindowConfig); expect(handler.getEffectiveContextWindow()).toBe( - CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW, + LARGE_WINDOW_SUBSCRIPTION_CONTEXT, ); // "Use your own API key" routes to the real OpenAI API, which honors the @@ -252,7 +253,7 @@ describe('ModelHandlerCodex subscription fallback', () => { await setPreferCodexSubscription(false); expect(handler.getEffectiveContextWindow()).toBe( - CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW, + LARGE_WINDOW_SUBSCRIPTION_CONTEXT, ); expect(handler.computePrice(RAW_USAGE)).toBe(0); expect(handler.getLastCredentialUsageRoute()).toBe('chatgpt-subscription'); From 053b9245c6def8a5d0e72d36c3c6fe223e833e4e Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 17 Aug 2026 17:44:56 +0200 Subject: [PATCH 3/4] refactor(model): remove fixed subscription context --- src/model/providerCapabilities.ts | 2 -- src/test-kernel/cli/StatusBar.vitest.ts | 4 ++-- src/test-kernel/model/ComputeModelOptions.vitest.ts | 8 ++++++-- src/test-kernel/model/ProviderCapabilities.vitest.ts | 7 ++----- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/model/providerCapabilities.ts b/src/model/providerCapabilities.ts index aaf96fc70a2..ee105723c20 100644 --- a/src/model/providerCapabilities.ts +++ b/src/model/providerCapabilities.ts @@ -52,8 +52,6 @@ export interface ProviderCapabilityKey { * (128k → 400k), same split OpenCode uses. */ export const CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT = 272_000; -export const CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW = - CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT + 128_000; /** Trailing llm-zoo date pin (`-2026-04-23`) on a model `fullName`. */ const CODEX_MODEL_DATE_PIN = /-\d{4}-\d{2}-\d{2}$/; diff --git a/src/test-kernel/cli/StatusBar.vitest.ts b/src/test-kernel/cli/StatusBar.vitest.ts index 5aa3305ac70..fda3ae84824 100644 --- a/src/test-kernel/cli/StatusBar.vitest.ts +++ b/src/test-kernel/cli/StatusBar.vitest.ts @@ -733,8 +733,8 @@ describe('CLI StatusBar display model', () => { }), ); - // gpt-5.6's Codex subscription budget caps to 400k - // (CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW), not the raw 1.05M API window. + // gpt-5.6's Codex subscription budget caps to 400k (272k input plus its + // 128k output allowance), not the raw 1.05M API window. expect(leftTexts(display)).toContain('187k/400k (47%)'); }); diff --git a/src/test-kernel/model/ComputeModelOptions.vitest.ts b/src/test-kernel/model/ComputeModelOptions.vitest.ts index dacb861e475..1b0b8af3e8f 100644 --- a/src/test-kernel/model/ComputeModelOptions.vitest.ts +++ b/src/test-kernel/model/ComputeModelOptions.vitest.ts @@ -19,7 +19,7 @@ import { shouldRouteModelThroughOpenRouter, } from '@model/openRouterRouting'; import { - CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW, + CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT, isCodexSubscriptionEligible, } from '@model/providerCapabilities'; import { apiKeySecretName, invalidateApiKeyCache } from '@model/apiProviders'; @@ -399,7 +399,11 @@ describe('computeModelOptionsData relay quota state', () => { expect(model.availability).toBe('subscription-access'); expect(model.context).toBe( - `${Math.round(CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW / 1000)}K`, + `${Math.round( + (CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT + + MODEL_CONFIGS.gpt55.maxOutputTokens) / + 1000, + )}K`, ); expect(model.cost).toBe('$0.000/$0.000'); expect(model.hint).not.toContain(FAST_FIRST_RESPONSE_HINT); diff --git a/src/test-kernel/model/ProviderCapabilities.vitest.ts b/src/test-kernel/model/ProviderCapabilities.vitest.ts index e84e5436aaa..c32d06140df 100644 --- a/src/test-kernel/model/ProviderCapabilities.vitest.ts +++ b/src/test-kernel/model/ProviderCapabilities.vitest.ts @@ -15,7 +15,6 @@ import { import { installTexraModelAccess } from '@controllers/modelAccess/installTexraModelAccess'; import { CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT, - CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW, isCodexSubscriptionActive, resolveCodexSubscriptionCapabilities, resolveCodexSubscriptionProfile, @@ -78,7 +77,8 @@ describe('provider capabilities', () => { expect(capabilities).toMatchObject({ authMode: 'chatgpt-subscription', - contextWindow: CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW, + contextWindow: + CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT + gpt55Config.maxOutputTokens, inputTokenLimit: CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT, inputPrice: 0, outputPrice: 0, @@ -117,9 +117,6 @@ describe('provider capabilities', () => { CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT + model.maxOutputTokens, inputTokenLimit: CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT, }); - expect(capabilities?.contextWindow).toBe( - CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW, - ); }, ); }); From c9cc3a4a8472fe5b624e96124f97ea1eac807904 Mon Sep 17 00:00:00 2001 From: texra-ai <207051187+texra-ai@users.noreply.github.com> Date: Mon, 17 Aug 2026 17:47:22 +0200 Subject: [PATCH 4/4] fix: align Codex subscription fixture maxOutputTokens Give the large-window Codex fixture the real 128k output budget so the displayed subscription window stays 400k. --- .../agent/modelHandlers/CodexSubscriptionFallback.vitest.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test-kernel/agent/modelHandlers/CodexSubscriptionFallback.vitest.ts b/src/test-kernel/agent/modelHandlers/CodexSubscriptionFallback.vitest.ts index 5a9f5b6e518..d88ed87b4d4 100644 --- a/src/test-kernel/agent/modelHandlers/CodexSubscriptionFallback.vitest.ts +++ b/src/test-kernel/agent/modelHandlers/CodexSubscriptionFallback.vitest.ts @@ -50,9 +50,11 @@ const config: ModelConfig = buildTestModelConfig({ // gpt-5.5 declares a 1,050,000-token window over the OpenAI API, but the Codex // subscription backend enforces a far smaller ceiling — the override must clamp // the effective window to that ceiling while the subscription drives requests. +// Use the real Codex output budget so the displayed window is 272k + 128k = 400k. const largeWindowConfig: ModelConfig = { ...config, contextWindow: 1_050_000, + maxOutputTokens: 128_000, }; const LARGE_WINDOW_SUBSCRIPTION_CONTEXT = @@ -142,8 +144,7 @@ describe('ModelHandlerCodex subscription fallback', () => { const handler = await newSubscriptionHandler(largeWindowConfig); // The model's own 1.05M API window must not leak through on the - // subscription path. The displayed ceiling includes this fixture's output - // allowance in addition to the shared Codex input budget. + // subscription path, where the backend rejects requests past the ceiling. expect(handler.getEffectiveContextWindow()).toBe( LARGE_WINDOW_SUBSCRIPTION_CONTEXT, );