Repository navigation
feat(cli-tools): write an OmniRoute model catalog when applying Codex settings - #16910
Merged
diegosouzapw merged 4 commits intoOct 17, 2026
Merged
diegosouzapw merged 4 commits into
diegosouzapw merged 4 commits into
Conversation
… settings Codex's /model picker only lists its bundled catalog, so picking a bare slug sends e.g. gpt-5.5 to OmniRoute, which may not route it. On Apply (opt-out checkbox, on by default) the Codex settings route now runs `codex debug models --bundled`, clones each bundled entry (they carry version-specific system prompts Codex validates strictly) into ~/.codex/omniroute-models.json under OmniRoute's provider-prefixed ids, and points `model_catalog_json` at it. - non-Codex upstreams get code-mode flags cleared; inherited upgrade notices are dropped; bundled entries stay as hidden so internal slugs resolve - selected models lead the picker; listed block capped at 300 entries - fail-open: if Codex is missing/old, Apply still succeeds and returns catalogWarning (shown as a warning in the dashboard) - Reset removes the key only when it points to OmniRoute's file, then deletes the file - spawn via execFile with an argv array (Hard Rule #13) and CODEX_HOME pinned to the directory OmniRoute writes into Co-authored-by: Kalfian <hi@kalfian.com> Inspired-by: decolua/9router#4406
The catalog file grows ~60 KB per model in ~/.codex, so the Apply checkbox now starts unchecked. The route already writes only on modelCatalog === true; an explicit modelCatalog: false test joins the omitted-flag test.
Contributor
CI Coverage Report
Coverage artifact was not available for this run. |
diegosouzapw
deleted the
feat/port-pr-4406-codex-model-catalog-on-apply
branch
October 18, 2026 23:48
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
~/.codex/omniroute-models.json) and setsmodel_catalog_json, so Codex's/modelpicker lists routable provider-prefixed ids (cx/gpt-5.5,kr/claude-sonnet-4.5, combos) instead of bare bundled slugs that OmniRoute may not route.codex debug models --bundledoutput, not synthesized, because each one carries a version-specific system prompt that Codex validates strictly.catalogWarning. The dashboard shows it as a warning, not an error.Attribution
Thanks to @kalfian for the original implementation.
Changes
src/lib/cliTools/codexModelCatalog.ts(new): purebuildCodexModelCatalog()plusloadBundledCodexCatalog().gpt-5.5, then the first plain listed entry.codexthrough the provider registry, so bothcodex/andcx/count as Codex) have their code-mode flags cleared.upgradenotices are nulled. Bundled entries are kept asvisibility: "hide"with shifted priority.execFileand an argv array (Hard Rule deps: bump qs from 6.14.1 to 6.14.2 #13), with a 15 s timeout, a 16 MB maxBuffer andCODEX_HOMEpinned to the directory OmniRoute writes into. The binary is resolved throughlocateCommandCandidate/getLookupEnv(CLI_CODEX_BINis honoured).src/lib/cliTools/codexModelCatalogWriter.ts(new): fail-open orchestration./v1/modelsserves: chat models only, hidden models excluded, combos included, the caller's credentials forwarded.src/app/api/cli-tools/codex-settings/route.ts:modelCatalog: trueand returnscatalogPath/catalogModelCountorcatalogWarning.model_catalog_jsononly when it points to OmniRoute's file, then deletes the file. A user-owned catalog is left alone.src/shared/validation/schemas/cli.ts:codexSettingsConfigSchema=cliModelConfigSchema+ optionalmodelCatalogboolean.CodexToolCard.tsx: an opt-out checkbox "List OmniRoute models in Codex's /model picker" (on by default, with a tooltip about the file size and re-applying after a Codex upgrade), plus an amber warning state.cliTools.*keys, translated in all 66 locales (no__MISSING__markers).createMultiBackup: it is regenerated on every Apply, and backing up about 17 MB per Apply would only add to the backups' disk pressure.config.tomlandauth.jsonare still backed up.Test plan
node --import tsx/esm --test tests/unit/codex-model-catalog.test.ts tests/unit/codex-settings-model-catalog.test.ts. Before the change: builder suiteERR_MODULE_NOT_FOUND, route suiteℹ tests 4 ℹ pass 1 ℹ fail 3. After:ℹ tests 18 ℹ pass 18 ℹ fail 0.codexshell script selected throughCLI_CODEX_BIN, so the real~/.codexis never touched.CODEX_HOMEand that the API key is absent from the catalog.npx vitest run --config vitest.config.ts tests/unit/ui/codex-tool-card-model-catalog.test.tsx tests/unit/ui/codex-tool-card-wire-api-default.test.tsx tests/unit/ui/ToolDetailClient.test.tsx:Tests 11 passed (11). The new UI test fails on the base card (2 failed).ℹ tests 208 ℹ pass 208 ℹ fail 0.tests/integration/security-hardening.test.ts:ℹ tests 20 ℹ pass 20 ℹ fail 0.HOME/CODEX_HOME: generated the catalog from its real bundle (11 entries), then rancodex debug modelswithmodel_catalog_jsonpointing at it. rc=0, and Codex loaded 16 models:cx/gpt-5.5,kr/claude-sonnet-4.5,glm/glm-5.3,cc/claude-opus-4.7andmy-combolisted with priorities 1-5, and the 11 bundled entries hidden.npm run typecheck:core: EXIT=0. ESLint (with--suppressions-location config/quality/eslint-suppressions.json) on the changed files: clean.npx prettier --check: clean.npm run i18n:check-keys: OK (66 locales).npm run i18n:check-ratio: OK.npm run i18n:check-new-keys: PASS.tests/unit/i18n-vi-completeness.test.ts:ℹ tests 5 ℹ pass 5.node scripts/check/check-pr-test-policy.mjs: PASS.npm run check:test-masking: OK (no weakening).