feat(catalog): add modelPickerOrder to customize the Codex model-picker order - #1669
feat(catalog): add modelPickerOrder to customize the Codex model-picker order#1669TooSpace wants to merge 1 commit into
Conversation
…er order Large routed catalogs (10-20+ models across several providers) have no supported way to control the Codex model-picker display order beyond the 5-slot subagentModels list: every non-featured routed row is emitted at the same flat priority, so the picker order is undefined and reshuffles on each catalog rebuild (ocx sync / service restart / upgrade). Add an optional, display-only config.modelPickerOrder: string[]. Listed routed <provider>/<model> slugs are shown in array order in the picker; unlisted rows and subagentModels-featured rows keep their positions. When unset, catalog priority is byte-identical to before (the codex-catalog golden oracle is unchanged). Display and spawn_agent candidacy are fully decoupled: modelPickerOrder rewrites only the Codex-visible `priority`, while each moved row records its natural priority in an OpenCodex-private catalog field (opencodex_spawn_priority) that effectiveSubagentRoster uses to pick candidates. The spawn_agent candidate set is therefore provably unchanged by any display reordering — even reversing every row. Codex ignores the unknown field (same as opencodex_catalog_kind), so this is purely a user-facing picker feature. Fixes lidge-jun#1649
|
✅ Deterministic PR hygiene checks passed. |
⏳ DRAFT
What to do
Review readiness checklist
3/4 boxes ticked. This PR stays in draft until every box above is ticked. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThe PR adds ChangesModel picker ordering
Estimated code review effort: 3 (Moderate) | ~25 minutes Merge Risk: ⚪ Minimal · up to The change is localized to optional picker ordering and preserves existing behavior when unset; no actionable merge-blocking risk remains after normal checks and review. Sequence Diagram(s)sequenceDiagram
participant Config
participant prepareCatalog
participant CatalogBuilder
participant SpawnAgentSorter
Config->>prepareCatalog: Read modelPickerOrder
prepareCatalog->>CatalogBuilder: Pass modelPickerOrder
CatalogBuilder->>CatalogBuilder: Assign picker display priorities
CatalogBuilder->>SpawnAgentSorter: Preserve SPAWN_PRIORITY_FIELD
SpawnAgentSorter->>SpawnAgentSorter: Sort spawn-agent candidates by natural priority
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Wibias
left a comment
There was a problem hiding this comment.
Two changes are needed before merge:
- Major:
modelPickerOrdermust be runtime-validated, not only typed.
The PR relies on the top-level config schema's .passthrough() and therefore preserves an unknown modelPickerOrder value exactly as hand-edited. The runtime then does const modelPickerOrder = config.modelPickerOrder ?? [] and later (modelPickerOrder ?? []).filter(...) in the catalog builder.
That means a config such as:
{ "modelPickerOrder": "foo" }can successfully load and then fail catalog convergence/sync with TypeError: ...filter is not a function. This optional display preference should fail soft rather than take down catalog generation.
Please add modelPickerOrder to the config schema with the same degrade-don't-reject policy used for other optional preferences, and add regressions for at least a scalar, object, malformed array, and valid string array. Normalising/trimming/deduplicating through the existing non-blank string-array helpers would also keep the persisted/runtime representation canonical.
- Update the model-ordering documentation for the new public config surface.
docs-site/src/content/docs/guides/model-ordering.md still says subagentModels is the supported ordering field and that there is no general ordering field in OcxConfig. After this PR that is false. Please document modelPickerOrder, its routed <provider>/<model> scope, the fact that subagentModels remains the five-slot featured/spawn-agent list, and that native/account-qualified rows are unaffected.
Also please avoid carrying forward the claim that the current equal-priority routed order is "undefined" or "reshuffles on each rebuild" unless there is evidence for that. The existing guide describes the fallback order as deterministic provider/model alphabetical for equal-priority routed rows. The actual missing capability is user-controlled ordering beyond the five featured slots, not determinism itself.
What
Add an optional, display-only
config.modelPickerOrder: string[]that lets a usercustomize the order of the Codex model picker for large routed catalogs.
Fixes #1649. (Supersedes #1666, which carried the exploratory history; this is the
squashed, decoupled implementation.)
Why
With many routed providers (10-20+ models), the picker order is driven only by the
5-slot
subagentModelslist. Every non-featured routed row is emitted at the sameflat
priority, so the picker order is undefined and reshuffles on each catalogrebuild (
ocx sync,ocx servicerestart, upgrade). There is no supported way topin the order of more than five routed models.
Design
modelPickerOrderis display-only. It lists routed<provider>/<model>slugs;listed rows appear in array order in the picker, unlisted rows and
subagentModels-featured rows keep their positions. Native passthrough andaccount-qualified native rows are not reordered (use
subagentModelsfor those).When unset, catalog priority is byte-identical to before — the
codex-cataloggolden oracle is unchanged.
Display order and spawn_agent candidacy are fully decoupled:
modelPickerOrderrewrites only the Codex-visiblepriority.opencodex_spawn_priority.effectiveSubagentRosterranks the spawn_agent candidate window by that naturalpriority, so the candidate SET is provably unchanged by any display reordering —
even reversing every routed row. Codex ignores the unknown field (same as
opencodex_catalog_kind), so it is invisible to Codex.No config-schema change is needed: the top-level config schema is
.passthrough()(same as
subagentModels).Changes
src/types.ts: documented optionalmodelPickerOrder?: string[]onOcxConfig.src/codex/catalog/sync.ts: apply display order to listed routed rows; recordopencodex_spawn_priority;effectiveSubagentRosterranks candidates by thenatural priority. Adds
PICKER_ORDER_PRIORITY_BASE/SPAWN_PRIORITY_FIELD.src/codex/convergence.ts: passconfig.modelPickerOrderinto the routed build.tests/codex-catalog-model-picker-order.test.ts: unset = flat default; listedrows ordered; featured wins; bare native not reordered; and the decisive case —
six routed rows listed in reverse order leave the candidate set unchanged.
Testing
bun x tsc --noEmitclean on top ofdev.bun testforcodex-catalog-golden,codex-catalog,codex-catalog-sync-hardening,codex-catalog-model-picker-order(and broader catalog suites): all pass, 0 fail.Golden oracle unchanged.
Review readiness checklist
This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:
All CI tests are green on my local testing.
I pushed my PR to the latest dev commit.
I resolved all correct Codex and CodeRabbit findings.
My PR is ready for review.
Summary by CodeRabbit
New Features
Tests