fix(openai): align GPT-5.6 Codex context limits - #8306
Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit fa75494. Configure here.
There was a problem hiding this comment.
{
"body": "## TeXRA Code Review\n\n### Summary\n\nThis PR correctly aligns the Codex ChatGPT-subscription context budget for GPT-5.6 by introducing a model-family-specific dispatch in `resolveProviderCapabilities`. The changes are limited in scope, well-tested, and mathematically sound.\n\n### Findings\n\n**1. Arithmetic and dispatch logic verified (no issues)**\n\nThe new constant `CODEX_GPT56_SUBSCRIPTION_CONTEXT_WINDOW = 500_000` is documented as \"372k input plus 128k output\" (372,000 + 128,000 = 500,000 \checkmark). The dispatch function `codexSubscriptionContextWindow` uses `codexBackendModelId(model).startsWith('gpt-5.6')`, which correctly matches all GPT-5.6-family model IDs (e.g., `gpt-5.6-luna`) while leaving GPT-5.5 and earlier at the default 272,000. The `Math.min` guard in `resolveProviderCapabilities` ensures the Codex cap never exceeds the model's declared native `contextWindow`.\n\n**2. Constant rename is complete (no issues)**\n\n`CODEX_SUBSCRIPTION_CONTEXT_WINDOW` has been renamed to `CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW`. All references across the three test files (`CodexSubscriptionFallback.vitest.ts`, `ComputeModelOptions.vitest.ts`, `ProviderCapabilities.vitest.ts`) have been updated. A grep for the old name returns no matches.\n\n**3. Test coverage (no issues)**\n\n- `ProviderCapabilities.vitest.ts`: the existing GPT-5.5 test still asserts 272k; a new test asserts 500k for GPT-5.6.\n- `CodexSubscriptionFallback.vitest.ts`: all fallback-boundary tests use the renamed default constant; no new GPT-5.6-specific fallback tests are needed because the fallback logic is model-agnostic and the context cap is now sourced through `resolveProviderCapabilities`.\n- `ComputeModelOptions.vitest.ts`: the model-picker display test uses the renamed constant; the picker display for GPT-5.6 would automatically derive the correct 500k cap from `resolveProviderCapabilities` without additional test changes.\n\n**4. No regressions identified (no issues)**\n\nThe PR title reports 29 passing tests, 0 lint errors. The diff is self-contained and introduces no new abstraction layers or TypeScript anti-patterns.\n\n### Risk assessment\n\n- **Low risk.** The change is a narrowly scoped addition of a model-family dispatch with a new constant. No existing code path is removed or restructured.\n- **Future-proofing note:** The `startsWith('gpt-5.6')` dispatch will match any future GPT-5.6 variant (e.g., `gpt-5.6-mini`). If a future variant requires a different budget, the dispatch will need adjustment, but this is a straightforward extension point.\n",
"comments": [],
"thread_actions": []
}Reviewed by TeXRA agent review with model deepseekproT.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fa75494a61
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
fa75494 to
98536ad
Compare
There was a problem hiding this comment.
Findings
Suggestions
src/agent/modelHandlers/openai/modelHandlerOpenAIResponse.ts:637— JSDoc says "context window" but the implementation now usesgetEffectiveInputTokenLimit(). Update the comment to reference the input token limit.
Notes
src/model/providerCapabilities.ts:57—codexSubscriptionTokenLimits()is a single-caller private function (onlyresolveProviderCapabilities). It carries meaningful logic (model-family dispatch across two return fields), so it's defensible and not a trivial identity extraction. If this remains at one caller through future iterations, consider inlining.- The removed test case
'sends subscription requests when only the stripped output budget exceeds the Codex cap'is correctly dropped: the scenario was specific to the old single 272k cap where output budget could be squeezed but still sent. With the newinputTokenLimitguard inapplyTokenCountFailureFallback, the input-limit check catches this scenario before the output-budget reduction path, so the test is no longer meaningful. - The constant rename from
CODEX_SUBSCRIPTION_CONTEXT_WINDOWto the new split constants is complete — zero references to the old name remain in the tree. - No platform decoupling, Zod, security, PocketFlow, error-handling, or webview findings. All changes are in VS Code-free zones (
src/agent/modelHandlers/,src/model/) and test files.
Verified
src/model/providerCapabilities.ts:1-141— constant definitions, dispatch function, capability profile resolution; interface and export changessrc/agent/modelHandlers/openai/modelHandlerOpenAIResponse.ts:289-294, 635-644, 1378-1390— newgetEffectiveInputTokenLimit(),getCompactionTokenThresholdchange,applyTokenCountFailureFallbackguardsrc/test-kernel/agent/modelHandlers/CodexSubscriptionFallback.vitest.ts:1-270— constant import updates, test assertion updates, removed test casesrc/test-kernel/model/ComputeModelOptions.vitest.ts:13-250— constant import updatesrc/test-kernel/model/ProviderCapabilities.vitest.ts:7-89— constant imports, GPT-5.5 assertion update, new GPT-5.6 test- Confirmed
attachContextWindowErrorexists atsrc/common/errors/sdkError/errorMetadata.ts:102 - Confirmed no remaining references to
CODEX_SUBSCRIPTION_CONTEXT_WINDOW(without suffix) insrc/
There was a problem hiding this comment.
{
"body": "## TeXRA Code Review\n\n### Summary\n\nThis PR splits the ChatGPT-subscription (Codex) context budget into separate **context window** and **input token limit** fields, with model-specific constants for GPT-5.5/earlier (400k total / 272k input) and GPT-5.6 (500k total / 372k input). The arithmetic is internally consistent - the 128k output budget is correctly derived from the difference - and the clamping, fallback, and early-rejection logic is sound.\n\n### Finding 1 - PR description does not match code behavior (moderate)\n\nThe PR title says \"keep the existing 272k ChatGPT-subscription context cap for GPT-5.5 and earlier,\" and the CURSOR_SUMMARY says \"GPT-5.5 and earlier still use **272k** via `CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW`.\" But the code defines:\n\n```typescript\nexport const CODEX_DEFAULT_SUBSCRIPTION_CONTEXT_WINDOW = 400_000; // was 272_000\nexport const CODEX_DEFAULT_SUBSCRIPTION_INPUT_LIMIT = 272_000; // new\n```\n\nThe **context window cap** for pre-5.6 models has been raised from 272k to 400k. The 272k number now governs only the input side. This is a material behavioral change: a model with a large native window that previously had its effective context window clamped to 272k now gets 400k. The code and tests are self-consistent, but the PR description is wrong about what was preserved.\n\n### Finding 2 - Single-caller helper extraction (minor)\n\nThe new `codexSubscriptionTokenLimits` function in `src/model/providerCapabilities.ts` (lines 57-71) is called from exactly one site (`resolveProviderCapabilities`). The repository's anti-indirection rules (CLAUDE.md § \"Discouraged Factory Patterns\" → \"single-caller extractions are banned\") discourage this pattern. The function does contain meaningful logic (model-ID → budget-constant mapping), which is an explicit exception, but the extraction adds a private function where the same `if (codexBackendModelId(model).startsWith('gpt-5.6'))` test could be inlined directly in `resolveProviderCapabilities`. Consider inlining to reduce indirection.\n\n### Finding 3 - Removed test without a positive-case replacement (minor)\n\nThe test \"sends subscription requests when only the stripped output budget exceeds the Codex cap\" was removed (CodexSubscriptionFallback.vitest.ts, old lines 253-278). This test previously verified a boundary: input near the old 272k cap but with enough output budget to succeed. With the new split budget (400k total / 272k input limit), the same input level now leaves ~128k of output room, so the old assertion no longer applies. The removal is logically correct, but no corresponding test verifies the *positive* case - that a request with cumulative input near (but below) the input limit, where the output budget is ample, actually succeeds and sends the request. Without such a test, a future change could silently break this path.\n\n### Verified\n\n- **Constants**: 400k − 272k = 128k (default output budget) \checkmark; 500k − 372k = 128k (GPT-5.6 output budget) \checkmark.\n- **Clamping**: `contextWindow = min(tokenLimits.contextWindow, model.contextWindow)` and `inputTokenLimit = min(tokenLimits.inputTokenLimit, model.contextWindow)`. The invariant `resolved inputTokenLimit ≤ resolved contextWindow` holds for all model context windows because `tokenLimits.inputTokenLimit ≤ tokenLimits.contextWindow` and both are clamped to the same `model.contextWindow`.\n- **`getEffectiveInputTokenLimit` fallback**: returns `inputTokenLimit` from the active profile, else falls back to `getEffectiveContextWindow()` → correct for non-subscription paths.\n- **`applyTokenCountFailureFallback` early rejection**: `inputEstimate + buffer >= inputTokenLimit` correctly guards the input budget before computing `contextWindow − inputEstimate − buffer` for the output budget.\n- **`getCompactionTokenThreshold`**: now uses input limit rather than context window → semantically correct (compaction should trigger against the input budget).\n- **Test constants**: `ProviderCapabilities.vitest.ts` uses `gpt55Config.contextWindow = 1_050_000`, so the GPT-5.6 test correctly expects unclamped subscription constants. `CodexSubscriptionFallback.vitest.ts` correctly updates imports and expected values. `ComputeModelOptions.vitest.ts` correctly shows \"400K\" from the renamed constant.\n- No new ES2023+ regressions; no new pass-through layers beyond the single-caller helper noted above.\n- No pre-existing TeXRA threads to resolve.",
"comments": [
{
"path": "src/model/providerCapabilities.ts",
"line": 57,
"start_line": 57,
"side": "RIGHT",
"body": "The `codexSubscriptionTokenLimits` helper is called from exactly one site (`resolveProviderCapabilities`). Per the repository anti-indirection rules (CLAUDE.md § \"Discouraged Factory Patterns\" / Abstraction-cost guardrails), single-caller extractions are discouraged. The `if (codexBackendModelId(model).startsWith('gpt-5.6'))` test and the two-constant selection could be inlined directly in `resolveProviderCapabilities` (5 lines of logic). Consider inlining unless you expect additional callers imminently."
},
{
"path": "src/test-kernel/agent/modelHandlers/CodexSubscriptionFallback.vitest.ts",
"line": 253,
"start_line": 253,
"side": "LEFT",
"body": "This test verified that a request with input near the old 272k cap (but output budget still viable) would succeed. With the new split budget (400k context / 272k input), the same scenario now leaves ~128k of output room, so the old assertion is inapplicable. The removal is correct, but no replacement test covers the *positive* case: cumulative input near (but below) the input limit with ample output budget should successfully send the request. Without such a test, this path is untested."
}
],
"thread_actions": []
}Reviewed by TeXRA agent review with model deepseekproT.

Summary
Validation
npm test -- --run src/test-kernel/model/ProviderCapabilities.vitest.ts src/test-kernel/agent/modelHandlers/CodexSubscriptionFallback.vitest.ts src/test-kernel/model/ComputeModelOptions.vitest.ts(29 tests)npm run typechecknpm run lint(0 errors; 47 pre-existing warnings)git diff --checkReference: anomalyco/opencode#36248
Closes #8305
Note
Medium Risk
Changes pre-flight rejection and compaction math on the ChatGPT-subscription path where token counting is unavailable; wrong limits would block valid turns or allow backend failures, but scope is limited to Codex capability profiles and the OpenAI Responses handler.
Overview
ChatGPT-subscription (Codex) limits are split so GPT-5.5 and earlier keep a 400k total window with a 272k input cap, while GPT-5.6 uses 500k total and 372k input (per Codex-reported budgets).
ProviderCapabilityProfilegains optionalinputTokenLimit, resolved fromcodexBackendModelIdwhen the model id starts withgpt-5.6.ModelHandlerOpenAIResponseusesgetEffectiveInputTokenLimit()for automatic compaction thresholds and, on routes without token counting, rejects requests locally when input estimate + safety buffer hits the input cap—before relying on shrinkingmax_output_tokens. The model picker still shows the profilecontextWindow(now the larger default/GPT-5.6 totals).Tests rename constants, assert GPT-5.6 limits, and drop the case that allowed a subscription request when only the output budget was trimmed past the old single ceiling.
Reviewed by Cursor Bugbot for commit 98536ad. Bugbot is set up for automated code reviews on this repo. Configure here.