Skip to content

feat(catalog): add modelPickerOrder to customize the Codex model-picker order - #1669

Draft
TooSpace wants to merge 1 commit into
lidge-jun:devfrom
TooSpace:feat/model-picker-order
Draft

feat(catalog): add modelPickerOrder to customize the Codex model-picker order#1669
TooSpace wants to merge 1 commit into
lidge-jun:devfrom
TooSpace:feat/model-picker-order

Conversation

@TooSpace

@TooSpace TooSpace commented Aug 14, 2026

Copy link
Copy Markdown

What

Add an optional, display-only config.modelPickerOrder: string[] that lets a user
customize 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 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, ocx service restart, upgrade). There is no supported way to
pin the order of more than five routed models.

Design

modelPickerOrder is 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 and
account-qualified native rows are not reordered (use subagentModels for those).
When unset, catalog priority is byte-identical to before — the codex-catalog
golden oracle is unchanged.

Display order and spawn_agent candidacy are fully decoupled:

  • modelPickerOrder rewrites only the Codex-visible priority.
  • Each moved row records its natural priority in an OpenCodex-private catalog field
    opencodex_spawn_priority.
  • effectiveSubagentRoster ranks the spawn_agent candidate window by that natural
    priority, 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 optional modelPickerOrder?: string[] on OcxConfig.
  • src/codex/catalog/sync.ts: apply display order to listed routed rows; record
    opencodex_spawn_priority; effectiveSubagentRoster ranks candidates by the
    natural priority. Adds PICKER_ORDER_PRIORITY_BASE / SPAWN_PRIORITY_FIELD.
  • src/codex/convergence.ts: pass config.modelPickerOrder into the routed build.
  • tests/codex-catalog-model-picker-order.test.ts: unset = flat default; listed
    rows 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 --noEmit clean on top of dev.
  • bun test for codex-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

    • Added an optional model picker ordering setting for routed models.
    • Configured models now appear in the picker according to the specified display order.
    • Existing featured, native, and account-qualified model ordering remains unchanged.
    • Spawn-agent prioritization and eligible model candidates are preserved independently.
  • Tests

    • Added coverage for custom ordering, default behavior, featured-model precedence, and candidate eligibility.

…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
@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the enhancement New feature or request label Aug 14, 2026
@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • review readiness checklist open (3/4 boxes ticked).

What to do

  • Tick all four boxes in the PR description once you're done (currently 3/4).

Review readiness checklist

  • ✅ 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.

3/4 boxes ticked.

This PR stays in draft until every box above is ticked.

@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8f2f5213-d2f3-4067-9f92-8eb002cf1539

📥 Commits

Reviewing files that changed from the base of the PR and between a1e5192 and 68d44b4.

📒 Files selected for processing (4)
  • src/codex/catalog/sync.ts
  • src/codex/convergence.ts
  • src/types.ts
  • tests/codex-catalog-model-picker-order.test.ts

📝 Walkthrough

Walkthrough

The PR adds modelPickerOrder as an uncapped display-order setting for routed models. Catalog generation applies picker priorities separately from spawn-agent priorities. Featured and native rows retain their existing behavior, with tests covering ordering and candidate stability.

Changes

Model picker ordering

Layer / File(s) Summary
Configuration and catalog input
src/types.ts, src/codex/convergence.ts, src/codex/catalog/sync.ts
Adds OcxConfig.modelPickerOrder and passes it through prepareCatalog into catalog entry construction.
Picker and spawn-agent priority separation
src/codex/catalog/sync.ts
Assigns a high display-priority band to listed routed models while preserving natural spawn-agent priority through SPAWN_PRIORITY_FIELD. Featured and native rows are excluded from picker reordering.
Ordering behavior validation
tests/codex-catalog-model-picker-order.test.ts
Tests default and configured ordering, featured and native row behavior, candidate limits, and stable spawn-agent membership.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: ⚪ Minimal · up to 68d44

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
Loading

Possibly related PRs

Suggested labels: review-ready

Suggested reviewers: ingwannu, lidge-jun, wibias

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes satisfy #1649 by adding uncapped picker ordering, preserving native behavior, and separating display priority from spawn_agent candidacy.
Out of Scope Changes check ✅ Passed All changes support #1649 through configuration, catalog wiring, priority separation, and focused tests; no unrelated changes are evident.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding configurable model-picker ordering through modelPickerOrder.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions
github-actions Bot marked this pull request as draft August 14, 2026 05:45
@github-actions
github-actions Bot marked this pull request as ready for review August 14, 2026 05:50

@Wibias Wibias left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Two changes are needed before merge:

  1. Major: modelPickerOrder must 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.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants