Skip to content

fix(openai): align GPT-5.6 Codex context limits - #8306

Merged
LionSR merged 1 commit into
mainfrom
agent/codex-gpt56-context-limits
Jul 12, 2026
Merged

fix(openai): align GPT-5.6 Codex context limits#8306
LionSR merged 1 commit into
mainfrom
agent/codex-gpt56-context-limits

Conversation

@LionSR

@LionSR LionSR commented Jul 12, 2026

Copy link
Copy Markdown
Owner

Summary

  • keep the existing 272k ChatGPT-subscription context cap for GPT-5.5 and earlier
  • use the Codex-reported 372k input plus 128k output budget for GPT-5.6
  • drive runtime and model-picker context from the same capability profile
  • add one focused GPT-5.6 profile assertion

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 typecheck
  • npm run lint (0 errors; 47 pre-existing warnings)
  • targeted Prettier and ESLint
  • git diff --check

Reference: 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). ProviderCapabilityProfile gains optional inputTokenLimit, resolved from codexBackendModelId when the model id starts with gpt-5.6.

ModelHandlerOpenAIResponse uses getEffectiveInputTokenLimit() 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 shrinking max_output_tokens. The model picker still shows the profile contextWindow (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.

Copilot AI review requested due to automatic review settings July 12, 2026 22:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added area:model-handlers Model providers, SDK handlers, streaming, pricing, and model registry behavior bug Something isn't working labels Jul 12, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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.

Comment thread src/model/providerCapabilities.ts Outdated

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{
  "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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread src/model/providerCapabilities.ts
@LionSR
LionSR force-pushed the agent/codex-gpt56-context-limits branch from fa75494 to 98536ad Compare July 12, 2026 22:21

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

Suggestions

  • src/agent/modelHandlers/openai/modelHandlerOpenAIResponse.ts:637 — JSDoc says "context window" but the implementation now uses getEffectiveInputTokenLimit(). Update the comment to reference the input token limit.

Notes

  • src/model/providerCapabilities.ts:57codexSubscriptionTokenLimits() is a single-caller private function (only resolveProviderCapabilities). 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 new inputTokenLimit guard in applyTokenCountFailureFallback, 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_WINDOW to 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 changes
  • src/agent/modelHandlers/openai/modelHandlerOpenAIResponse.ts:289-294, 635-644, 1378-1390 — new getEffectiveInputTokenLimit(), getCompactionTokenThreshold change, applyTokenCountFailureFallback guard
  • src/test-kernel/agent/modelHandlers/CodexSubscriptionFallback.vitest.ts:1-270 — constant import updates, test assertion updates, removed test case
  • src/test-kernel/model/ComputeModelOptions.vitest.ts:13-250 — constant import update
  • src/test-kernel/model/ProviderCapabilities.vitest.ts:7-89 — constant imports, GPT-5.5 assertion update, new GPT-5.6 test
  • Confirmed attachContextWindowError exists at src/common/errors/sdkError/errorMetadata.ts:102
  • Confirmed no remaining references to CODEX_SUBSCRIPTION_CONTEXT_WINDOW (without suffix) in src/

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{
  "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.

@LionSR
LionSR merged commit 5719f27 into main Jul 12, 2026
17 checks passed
@LionSR
LionSR deleted the agent/codex-gpt56-context-limits branch July 25, 2026 22:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:model-handlers Model providers, SDK handlers, streaming, pricing, and model registry behavior bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(openai): align GPT-5.6 Codex context limits

2 participants