Skip to content

fix(routing): read Codex max/ultra models from the alias sets in reasoning rules - #14720

Merged
diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.51from
QuangBlue:fix/codex-reasoning-rules-alias-sets
Sep 29, 2026
Merged

diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.51from
QuangBlue:fix/codex-reasoning-rules-alias-sets

Conversation

@QuangBlue

Copy link
Copy Markdown
Contributor

Problem

Reasoning-routing rules decide whether a Codex model accepts max / ultra with a hard-coded GPT-5.6 regex. The regex appears twice in src/lib/reasoningRouting/policy.ts and once more in the rules editor (src/shared/components/ReasoningRoutingRules.tsx). The Codex executor's suffix parsing reads CODEX_MAX_ALIAS_MODELS / CODEX_ULTRA_ALIAS_MODELS in open-sse/executors/codex/reasoningSuffix.ts instead, and its effort clamp table agrees with those sets. The sets already include gpt-6-astra, so the rule gate and the executor disagree about GPT-6 Astra:

  • Combo target: a rule that forces max or ultra counts cx/gpt-6-astra and its effort variants (e.g. cx/gpt-6-astra-high) as incompatible, and filterComboForReasoningDecision() removes them from the rule's target combo.
    • Example: with a combo [cx/gpt-6-astra, cx/gpt-5.6-sol, cx/gpt-5.6-luna, cx/gpt-6-astra-max], forced max reports "2 incompatible combo target(s) will be skipped", both of them Astra.
  • Single target: a single cx/gpt-6-astra target is reported unsupported, so applyDecision() in src/sse/handlers/reasoningRouting.ts rejects the request with 400 "Reasoning effort 'max' is not supported by the configured target". The executor serves Astra at both tiers.
  • Suffixes: cx/gpt-6-astra-max and cx/gpt-6-astra-ultra are not read as max / ultra requests. extractReasoningIntent() keeps the suffix in the model id and returns no effort, so a rule that matches on source effort max never matches them.
  • Editor: the rules editor hides max / ultra for GPT-6 Astra targets and shows the "unsupported" warning.

The review of #14677 found this gap. That PR adds gpt-6-sol (max and ultra) and gpt-6-luna (max only) to the same alias sets, and the regex would miss them too.

Changes

  • New src/shared/reasoning/codexExtendedEffort.ts reads the alias sets and exports two helpers:

    • isCodexExtendedEffortBaseModel(model, effort) matches only the exact base model, as the old ^gpt-5\.6-(?:sol|terra|luna)$ did. The suffix parser in policy.ts uses it.
    • codexModelFamilySupportsExtendedEffort(model, effort) also accepts <base>-<suffix> variants, as the old (?:-|$) regexes did. The capability gate in policy.ts and the rules editor use it.

    Both accept an optional codex/ or cx/ prefix and ignore case. The module lives in src/shared so that the client component does not import from open-sse/executors directly.

  • policy.ts and ReasoningRoutingRules.tsx call these helpers instead of their regex copies. The gate order in capabilityFor() is unchanged: static registry vocabulary, then declared efforts, then the operator override, and only then this fallback.

  • reasoningSuffix.ts itself is not touched, so this PR does not conflict with feat(sse): add GPT-6 Sol and Luna to the Codex catalog #14677. Once both are merged, Sol and Luna are covered here without another edit.

For GPT-5.6 models, every input the old regexes accepted or rejected gives the same result. The only difference is that the gate now also trims whitespace; the editor already did. The models whose result changes are the alias-set members the regex did not name (today: gpt-6-astra).

Out of scope:

  • The editor's extendedUnsupportedWarning text still says "suitable Codex GPT-5.6 models". Rewording it changes an English value, and check-ui-value-drift would then require every locale to be updated, so that is better done in a translation pass.
  • Once feat(sse): add GPT-6 Sol and Luna to the Codex catalog #14677 lands, getCodexAliasEffortCap() in reasoningSuffix.ts and this module both read the same sets. They could be merged in a follow-up.

Tests

  • New tests/unit/reasoning-routing-codex-extended-effort.test.ts (8 tests) covers:

    • forced max keeps Astra (the base id and a variant) in a combo;
    • forced ultra keeps Astra and still drops the max-only gpt-5.6-luna;
    • a single cx/gpt-6-astra target is supported for forced max and ultra;
    • every member of both alias sets passes the gate for its tiers, and the max-only members fail for ultra;
    • -max / -ultra suffix parsing for Astra and for every set member;
    • exact base-model matching (cx/gpt-6-astra-high-max and cx/gpt-6-astral-max are not split) and the helper edge cases.

    The combo and single-target cases use real rules and combos through resolveReasoningRoutingRule(). Six of the eight fail on the base commit; the two that pass there guard the exact-match behaviour. The tests iterate the sets, so new members are covered automatically.

  • On a local merge of this branch with feat(sse): add GPT-6 Sol and Luna to the Codex catalog #14677, the same tests pass. In that merge:

    • forced max keeps cx/gpt-6-sol and cx/gpt-6-luna;
    • forced ultra drops only cx/gpt-6-luna;
    • cx/gpt-6-sol-max is read as max.
  • Neighbouring tests all pass:

    • reasoning-routing (its comments now name the alias-set fallback instead of the old regex), reasoning-routing-decision-guards, reasoning-routing-api, codex-reasoning-suffix, codex-astra;
    • integration reasoning-routing-pipeline and reasoning-routing-reliability;
    • the rules editor UI test tests/unit/ui/api-key-routing-editor.test.tsx;
    • client-bundle-no-server-only-10692.
  • npm run test:vitest:ui: 2427 passed. The 18 failures come from suites that fail to load because vite cannot bundle node:sqlite / node:test (MCP server, autoCombo, memory, TLS clients, ComboSortSelect). None of them imports a file this PR changes.

  • ESLint (with suppressions), Prettier, check:cycles and check:file-size are clean.

  • typecheck:core reports only the pre-existing TS2322 in src/lib/services/cliproxyAccountHealth.ts:157, which is unchanged from the base. check:dashboard-typecheck reports only the pre-existing TS2698 in src/lib/combos/intelligentRouting.ts, which reproduces with this change reverted.

⚠️ base-red inherited: #14547

…oning rules

Reasoning-routing rules decided which Codex models accept `max` / `ultra`
with a hard-coded gpt-5.6 regex, in two places in policy.ts and once more in
the rules editor. The Codex executor's suffix parsing reads
CODEX_MAX_ALIAS_MODELS / CODEX_ULTRA_ALIAS_MODELS instead (its effort clamp
table agrees with them), and those sets already include gpt-6-astra, so the
rule gate and the executor disagreed:

- a rule forcing `max` or `ultra` counted cx/gpt-6-astra (and its effort
  variants) as incompatible: filterComboForReasoningDecision dropped it
  from the target combo, and a single cx/gpt-6-astra target was reported
  unsupported, although the executor serves it at both tiers;
- cx/gpt-6-astra-max / -ultra were not read as max / ultra requests, so a
  rule matching on source effort `max` never matched them;
- the rules editor hid `max` / `ultra` for GPT-6 Astra targets and warned
  they were unsupported.

Both checks now go through src/shared/reasoning/codexExtendedEffort.ts,
which reads the alias sets. Suffix parsing still requires the exact base
model; the capability gate and the editor still accept `<base>` or
`<base>-<suffix>`. Models added to the sets later are picked up without
another copy of the list.

Tests: tests/unit/reasoning-routing-codex-extended-effort.test.ts fails on
the previous policy.ts (6 of 8 cases) and passes now; it iterates the alias
sets, so new members are covered automatically. Comments in
reasoning-routing.test.ts that named the "legacy gpt-5.6 regex" now name the
alias-set fallback.
@diegosouzapw

Copy link
Copy Markdown
Owner

Thanks @QuangBlue — nice cleanup. Reading the max/ultra models from the executor's alias sets removes the drift that made Astra targets get skipped/400ed under forced max/ultra, and the shared helper keeps the rules editor honest too. The diff looks good to me; I could not run the tests locally in this pass, so I'm relying on CI for the two reasoning-routing suites.

@diegosouzapw
diegosouzapw merged commit a439a96 into diegosouzapw:release/v3.8.51 Sep 29, 2026
3 checks passed
diegosouzapw added a commit to lorenzozanee/OmniRoute that referenced this pull request Sep 29, 2026
…s sets

Merge the release tip (diegosouzapw#14720 moved the Codex max/ultra capability check to
the executor alias sets) and keep this PR's openai/ prefix fix on top: the
rules-editor helper now strips openai/ and delegates to
codexModelFamilySupportsExtendedEffort, so the dashboard and the executor
share one model list. Adds a case for an openai/ gpt-6 variant.
diegosouzapw pushed a commit that referenced this pull request Sep 29, 2026
Maintainer rework: merged the tip, where #14720 moved the Codex max/ultra check to the executor alias sets; the rules-editor helper now strips openai/ and delegates to that shared check (red->green proven: without the openai/ strip 2/4 fail, with it 4/4; reasoning-routing suites 20/20). Boarded on the release/v3.8.51 tip (3a2678f) with the b3 release-drain batch (26 PRs): typecheck:core and the open-sse typecheck are clean, ESLint is clean on every changed file, migration numbering OK, and the focused tests of the whole board pass 611/611 (51 files). File-size ceiling growth is reconciled in the wave follow-up. Thank you @lorenzozanee!
diegosouzapw added a commit to kang-heewon/OmniRoute that referenced this pull request Sep 29, 2026
diegosouzapw pushed a commit that referenced this pull request Sep 29, 2026
…6-luna (#14059)

Maintainer rework (release drain 2026-09-28): reconciled with the release/v3.8.51 tip three times — kept the tip's opencode-zen Responses routing (#14230) and layered the PR's reasoning metadata on it; ported the provider-namespace fix onto the shared Codex alias-set helpers from #14720/#14964 (policy now checks modelIdForRegistry; rules editor strips any provider prefix, luna coerces a saved ultra to max) and fixed the tip's leftover STANDARD_EFFORTS reference in the simulator select. Red->green: luna-reasoning-effort-400 fails 2/5 on the tip, 5/5 here; new github/opencode-zen efforts case fails on the tip, passes here. Focused suites 114/114 (13 files) + api-key-routing-editor vitest 6/6; typecheck:core, open-sse typecheck and ESLint clean; eslint-suppressions.json byte-identical to the tip. Thank you @kang-heewon!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants