Skip to content

feat(web): add the Codex client model catalog page - #741

Open
StellarWarp wants to merge 18 commits into
seakee:devfrom
StellarWarp:codex/codex-client-models-override
Open

StellarWarp wants to merge 18 commits into
seakee:devfrom
StellarWarp:codex/codex-client-models-override

Conversation

@StellarWarp

@StellarWarp StellarWarp commented Sep 11, 2026

Copy link
Copy Markdown

Summary

Adds a Model Catalog page (#/codex-client-models) that lists the model catalog CPA serves to Codex clients and lets an operator override entries locally. Overrides are field-level and can inherit from any other catalog entry, so a variant model no longer has to repeat a whole entry.

The page only appears when CPA advertises the new capability flags, and it falls back to Configuration on older CPA versions.

Scope

  • Frontend panel
  • Docs / Wiki

Changes

  • New codexClientModels feature: a catalog table whose rows expand in place, with origin filters, per-field source control, collapsible prompt fields, an advanced field tree, and a JSON patch panel that stays collapsed until needed.
  • The table lists each model's origin, whether it is currently served (with the providing providers on hover), the context window, the default reasoning level, and the visibility. The values shown are the ones clients receive, read from the served summary CPA reports.
  • Origins: base, auto-assembled, overridden, unserved, and removed. A null patch hides an entry; expanding a hidden entry and editing a field rebuilds it.
  • Field-level inheritance: $inherit directives are read and written per dotted path, sources are validated against the live catalog, and inheritance chains resolve to the effective entry. Identity, catalog position, and the context and reasoning fields never inherit.
  • Every field can independently stay on its default, be overridden locally, inherit from another model, or be removed; the source marker says which one is in effect, and an inherited value that differs from the model's own default is marked, so an inheritance that changes nothing is visible as such.
  • Prompts render real line breaks with a short preview and fold per item instead of escaped JSON, and base instructions plus the model message template can be overridden together through a single input.
  • The prompt section also carries the three switches that decide whether the client hands the model the usage instructions for skills, apps, and plugins.
  • New API client and capability headers (x-cpa-support-codex-client-model-override, x-cpa-support-codex-client-model-inherit), wired through useAuthStore the same way plugin support already is.
  • Sidebar entry and route gate, demo fixtures and demo API coverage, and zh-CN / zh-TW / en / ru strings.
  • Documentation: manual/codex-client-models in both languages, linked from the 日常使用 and Daily Use sidebar sections next to AI providers.
  • chore(web): the dev server now proxies /v0 to http://127.0.0.1:8317 so the panel can talk to a locally running CPA without configuring an API address. This is an independent dev-tooling commit and can be dropped on its own.

User Impact

  • Operators can inspect the Codex client model catalog in the panel and adjust a single model without editing CPA's catalog file by hand.
  • The list shows what clients actually receive, so an override is visible where it lands, and an edit no longer needs a side panel to stay readable.
  • Long prompts are readable in the form, and rarely used fields stay out of the way until the advanced section or the JSON panel is opened.
  • Older CPA versions keep the previous behavior: no sidebar entry, and a direct visit returns to Configuration.

Compatibility / Runtime Notes

  • CPA panel mode: the page requires CPA to send x-cpa-support-codex-client-model-override. Without it the sidebar entry is hidden and the route redirects to Configuration.
  • Manager Server mode: not involved; the page talks to the CPA management API only.
  • Full Docker / native packages: no packaging or runtime change. The Vite dev proxy only affects local development.
  • Field inheritance additionally needs x-cpa-support-codex-client-model-inherit. When it is missing, the editor keeps working without inheritance controls.

Data / Security Notes

  • The page reads and writes CPA's local override file through the existing management API, using the same management key and API base as the rest of the panel.
  • No new credentials, storage, or logging paths were added, and provider credentials are never read by this page.

Risk / Rollback

Risk level: Low

Rollback notes: revert the branch. The change is additive and gated behind a capability flag, so no existing route, store, or API call changes behavior when the flag is absent.

Verification

  • Type check
  • Lint
  • Tests
  • Build
  • Manual UI check
  • Docs/link check
  • Not applicable, docs-only

Commands / evidence:

npm run type-check -> tsc --noEmit, no errors
npm run lint       -> 0 errors, 5 pre-existing warnings under features/accounts
npm run test:web   -> 235 test files, 3577 tests passed
npm run docs:build -> vitepress build complete, both manual pages in the sitemap

Manual check ran against a local CPA backend on 127.0.0.1:8317 during development, covering the catalog list and filters, inline editing, field sources, prompt merge and preview, the advanced tree, the JSON patch, override removal, and the rejected-override list. The current UI was reviewed in the demo site (npm run dev:demo, #/demo/codex-client-models), including the served column, list expansion, the inherited-value marker, prompt folding, and the usage instruction switches.

Screenshots / Recordings

Catalog list with one entry expanded, field-level source markers, and the collapsed prompt and advanced sections:

Model catalog page

Inline editor detail, with the merged prompt preview and the advanced sections collapsed:

Model catalog inline editor

Docs

  • Matching docs manual and navigation updated
  • README / README_CN updated for user-visible capabilities
  • Demo fixtures, screenshots, and deep links reviewed
  • Release notes needed
  • Not needed — explanation included below

Docs decision: both language manual pages were added and linked from the sidebar. The README task table only lists cross-cutting workflows (choosing a panel, install, capability matrix, runtime model, providers/accounts/plugins, Manager Server, backup, migration, troubleshooting); page-specific manuals such as Model Prices and Monitoring are not listed there, so the model catalog stays consistent with that structure. Release notes are left to the maintainer's release process.

Related

Requires the companion CPA change: router-for-me/CLIProxyAPI#5748

Surface the local Codex client model catalog in the panel so entries can be
inspected and overridden without editing the override JSON by hand.

- show the effective catalog with per-entry origin, context window, reasoning
  level, and visibility, and expand an entry inline for editing
- expose the common fields in localized sections (basic info, context and
  reasoning, capability flags, tools and modalities, prompts) and keep the
  remaining fields in a collapsed advanced field tree
- override a single field, point any field at another entry with $inherit, or
  drop a local field, with the effective value and its source shown per field
- merge base_instructions and model_messages.instructions_template behind one
  toggle that is on by default, and collapse long prompts into a short preview
  with real line breaks
- report entries the backend could not apply instead of failing the whole page
- gate the page and its navigation entry on the new management capability
  headers, and add the i18n keys to all four locales

The model layer lives in features/codexClientModels with unit tests for the
tree, the inheritance rules, and the quick-field views.
The dev server now forwards /v0 to http://127.0.0.1:8317 by default, so the
panel can talk to a locally running CPA backend without configuring a separate
API address. VITE_CPA_DEV_TARGET overrides the target.
The manual now covers what the page edits, how common and advanced fields are laid out, field-level inheritance sources, the prompt merge switch, the override file format, and what happens when an override does not apply.

The Chinese and English pages stay aligned so the docs integrity check keeps passing, and both sidebar sections link the new page next to AI providers.
The backend watches the override file, so a manual edit is applied without
reloading the configuration.
The page listed only catalog entries, so a model Codex clients can request
stayed invisible whenever the catalog has no entry for it and the client
reuses the default template as a whole. Those models are the ones worth
overriding, and they were the ones the page could not show.

Read the served list the management API returns, mark each entry as served
with its providers, and list the served models the catalog does not describe
yet. Expanding one adopts it: the new entry pins the display name,
description, context window, and order clients see today while inheriting the
rest from the template it currently uses, and the slug stays fixed because
clients request the model by it.
The manual still said the page shows four origins and only catalog entries.
Document the fifth origin, what the Served column reports, and how a model
served without its own entry is adopted into one.
Setting a whole-entry inherit source marked every field in the basic section as
"inherited from", including the display name and description that the backend
never takes from a source, so the marks contradicted the values beside them.

Report the source only for fields inheritance actually reaches: a whole-entry
directive stops at the identity fields, and a directive written on one of them
stays visible as an issue without being previewed as applied.
A draft input read the effective value once, when it mounted. Changing the
inherit source replaces the effective value without remounting the editor, so
the inputs kept the previous numbers on screen: a model inheriting its order
from another one still showed its own priority, which made the source marks
look wrong for every field in that section.

Resynchronize the draft when the value underneath changes, while keeping text
the user typed that normalizes differently from the stored value, such as a
blank line in a prompt.
Some of the fields an entry carries are decided by the server for the client
rather than read from the entry: model metadata supplies the context window and
the reasoning levels, and a model without an entry of its own gets its
capabilities, its visibility and its position from provider rules. The editor
showed those values as ordinary entry fields, so a whole-entry inherit source
looked like it had supplied them, and the reasoning levels clients offer were
not editable at all.

The served list now carries the value clients receive for every field that
differs from the catalog entry, and the editor overlays those values, so the
default shown for a field is what clients actually get. Whole-entry inheritance
leaves those fields alone while a directive written on the field itself still
applies, and adopting a served model no longer pins them down: the new entry
only carries its own identity, and the remaining fields stay inherited.

The demo catalog carries the same entry and summary shapes, so the page can be
reviewed without a backend.
The manual listed the common fields without the reasoning levels and described
inheritance as if every field followed the entry's source. Document the levels
list, that a field's default is the value clients receive, and that the fields
the server decides for itself do not follow a whole-entry inherit while a
directive on the field itself still applies.
The management API now lists the entry the server assembles for every model it
can serve, which is the default configuration, and applies the override layer
after that. The editor therefore treats the catalog entry as the default
directly and the served-field overlay is gone, together with the field set the
server used to decide for the client.

Origins come from the server as well: the row state is read instead of being
inferred from the patch and the served list, so an override for a model no
provider serves shows up as unserved instead of as a locally defined entry.
A new entry was seeded by inheriting the default template as a whole, so saving
one wrote an $inherit directive that named gpt-5.5 and reported every field as
inherited from it. That described the layering the server no longer has: the
assembled entry is the default configuration, so the seed only has to say which
slug the local entry is for, and the editor reads the default values from that
entry instead of from a template it picked.

The editor also stopped hiding a whole-entry directive that names the default
template, since nothing writes one any more: a source in the patch is always a
source the user chose, and it is shown as one. Adopting a served model needs no
summary either, because the entry the row already carries is the default.
The served summaries named the catalog template an entry was assembled from and
the page showed it beside the served badge, which described an inheritance
relation the server no longer has. The origin a model carries already says
whether the catalog had an entry of its own, so the page reports that instead:
the origin reads "assembled" rather than naming a template, and the served
column states whether clients can request the model and which accounts serve it.

The demo catalog is built from one table of assembled entries now, so it reports
the same origins a live server does, including a model hidden by a null override
and an override for a model nothing serves.
The manual still split the origins into a catalog entry and a default template,
and described adopting a model as inheriting the template it currently uses
while an entry may hold nothing but its slug. Document what the page does now:
the assembled entries are the default configuration, a new entry declares only
its slug, and field inheritance always names a source the user picked.
The non-inheritable list covered the identity fields and the model's
position in the catalog; the context and reasoning envelope now joins them,
which matches what the override layer accepts. The field source menu offers
no inheritance source for those fields, and under a whole-entry source the
panel reports them as default values.

The manual and the inheritance hint describe the wider set.
@StellarWarp
StellarWarp force-pushed the codex/codex-client-models-override branch from e7c7016 to 803fc82 Compare September 13, 2026 18:02
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.

1 participant