Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 30 additions & 13 deletions docs-site/src/content/docs/guides/codex-app-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,28 @@ opencodex does not patch Codex App. It writes the same Codex configuration and m
Codex CLI/TUI already use. Because Codex App reads that shared state, routed models can appear in the
App's model picker as normal Codex catalog entries.

OpenAI entries have two stable identities: one bare native `openai` group whose Pool(default) or
Direct account selection is controlled by `codexAccountMode`, and namespaced
`openai-apikey/<model>` API-key transport. Changing the account mode does not change picker ids.
OpenAI entries use two credential routes: native Codex login and the namespaced
`openai-apikey/<model>` API-key transport. Changing `codexAccountMode` between Pool and Direct by
itself does not change picker ids. When `codexAccountNamespaces` has eligible selectors whose
mapped accounts still exist, however,
opencodex adds separate `<selector>/<native-openai-model>` rows for the mapped accounts and hides

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Update model-routing docs for selector precedence

With account-qualified picker ids now documented here, the separate Model Routing guide still describes provider/model as the first routing rule and never mentions <selector>/<native-openai-model> (checked docs-site/src/content/docs/guides/model-routing.md lines 14-48). In configs with a selector, router.ts resolves that selector before provider namespaces and sends the bare native id to the mapped account, so users following the routing guide can reason about the wrong precedence; update that guide and its translations alongside this picker change.

AGENTS.md reference: docs-site/AGENTS.md:L7-L10

Useful? React with 👍 / 👎.

the bare native rows from the Codex picker. Selector labels are user-chosen public names with no
built-in account-role meaning. Selecting a qualified row uses only its mapped account, does not
change the active Pool account, and fails closed instead of switching accounts when the target is
unavailable. See [Exact Codex account selectors](/reference/configuration/routing/#exact-codex-account-selectors).
API GPT-5.6 entries use
1,050,000 context / 922,000 max input, and `*-pro` picker ids resolve to the base wire model with
`reasoning.mode: "pro"` while logs, usage, and picker state keep the virtual id.
The API catalog is fixed to exactly eight ids: `gpt-5.5`, `gpt-5.6`, Sol/Terra/Luna, and their
three Pro virtual ids; there is no generic `gpt-5.6-pro` alias.
Compact requests keep the selected tier but send the base model without a reasoning object.

Select a credential route explicitly; change Pool/Direct on the Providers page:
Select the credential route represented by the picker id. Change Pool/Direct on the Providers page;
`<selector>` below is a user-chosen public label mapped through `codexAccountNamespaces`:

```text
gpt-5.6-sol # openai (Pool or Direct option)
gpt-5.6-sol # bare Codex-login route via Pool or Direct
<selector>/gpt-5.6-sol # stored Codex account mapped by that selector
openai-apikey/gpt-5.6-sol # API key
```

Expand Down Expand Up @@ -64,7 +72,8 @@ metadata instead of an older-template approximation.

| Route | Picker ids and catalog metadata |
| --- | --- |
| Codex login (Pool or Direct) | `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna` (372,000-token catalog window) |
| Codex login (no eligible account selectors) | Bare native ids such as `gpt-5.6-sol`, `gpt-5.6-terra`, and `gpt-5.6-luna`; Pool or Direct is selected through `codexAccountMode`. GPT-5.6 rows use a 372,000-token catalog window. |
| Codex login (eligible account selectors) | One `<selector>/<native-openai-model>` row per eligible selector and supported native model; each row uses only its mapped account, and bare native rows are hidden from the picker. Native metadata and context windows are preserved. |
| OpenAI (API key) | Exactly eight namespaced rows: `gpt-5.5`, `gpt-5.6`, Sol/Terra/Luna, and the three `*-pro` virtual ids (1,050,000 context; 922,000 max input for all eight) |
| OpenRouter | `openrouter/openai/gpt-5.6-sol`, `openrouter/openai/gpt-5.6-terra`, `openrouter/openai/gpt-5.6-luna` (1,050,000) |
| Cursor | Static fallback includes `cursor/gpt-5.6-sol`, `cursor/gpt-5.6-terra`, and `cursor/gpt-5.6-luna` (1,000,000), plus `cursor/grok-4.5` and `cursor/grok-4.5-fast` (500,000); live account discovery decides which remain visible. |
Expand All @@ -78,13 +87,18 @@ must still be entitled to use that model.

## Native and routed model toggles

The dashboard Models page uses `disabledModels` for both model families:
The dashboard Models page exposes `disabledModels` toggles for bare native ids and routed
`provider/model` ids. Account-qualified `<selector>/<native-openai-model>` ids are also supported by
`disabledModels`, but the dashboard does not list or toggle those exact selector rows; add them to
the configuration manually:

- Routed ids are namespaced (`provider/model`). Disabling one excludes it from the synced catalog
and `/v1/models`.
- Native GPT ids are bare slugs. Disabling one keeps its catalog entry but changes
`visibility` to `hide`, preserving the exact entry for a later re-enable; the bare OpenAI list
shape omits it while disabled.
- Account-qualified native ids use `<selector>/<native-openai-model>`. Adding one to
`disabledModels` hides only that selector row.
- Native GPT ids are bare slugs. Disabling one keeps its catalog entry but changes `visibility` to
`hide`, preserving the exact entry for a later re-enable; it hides the bare row and every
selector-qualified clone for that model from discovery.
- Native rows come from the supported static set, so a disabled native model stays visible in the
dashboard and can be turned back on.

Expand Down Expand Up @@ -129,9 +143,12 @@ never advertised where it cannot be honored, and custom gateways can opt in expl
## Subagent selection

Codex sorts picker-visible catalog entries by ascending `priority` and advertises the first five as
`spawn_agent` model overrides. Pick up to five bare native ids or namespaced `provider/model` ids
through `subagentModels` or the dashboard Subagents page; opencodex gives those entries priorities
0-4 in the chosen order. Other models remain callable by exact id.
`spawn_agent` model overrides. The dashboard Subagents page can select and save up to five bare
native ids or routed `provider/model` ids. Manually configured `subagentModels` also accepts
account-qualified `<selector>/<native-openai-model>` ids, but the dashboard does not offer those
exact ids; saving the page replaces the list with dashboard-visible choices. opencodex assigns low
catalog priorities in the selected order; when account selectors are active, bare native selections
expand into selector-qualified groups. Other models remain callable by exact id.

The featured-model list is separate from the Dashboard's **Sub-agent delegation** selection. It
controls which overrides Codex offers first; it does not select a model or trigger delegation by
Expand Down
31 changes: 21 additions & 10 deletions docs-site/src/content/docs/guides/model-ordering.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@ it earlier in the picker. The implementation records this constraint directly in
`src/codex/catalog/sync.ts`.

opencodex therefore controls featured placement by assigning lower priorities, not by relying on
array position. The relevant priorities are:
array position. Unless noted otherwise, the fixed priorities and worked example below describe a
catalog with no eligible Codex account selectors. With `N` eligible selectors, featured priorities
use `N` as a stride: a bare native choice at configured rank `i` expands to selector rows at
priorities `i * N + j`, where `j` is the selector's zero-based position; a routed choice uses
`i * N`; and an exact selector-qualified choice uses `i * N + j` for its selector. Unselected routed
rows are moved outside those selector groups. Codex still advertises only the first five
picker-visible rows.

The relevant no-selector priorities are:

| Catalog entry | Priority | Source |
| --- | ---: | --- |
Expand Down Expand Up @@ -57,7 +65,7 @@ only change whether a model is included.

## Effective picker pattern

With a non-empty featured list, the resulting order is:
With no eligible account selectors and a non-empty featured list, the resulting order is:

1. Models in the exact configured `subagentModels` order, with priorities `0` through `4`.
2. All remaining routed models, ordered alphabetically by provider and then model id, at priority `5`.
Expand Down Expand Up @@ -95,16 +103,19 @@ The picker begins as follows:
| After routed models | Remaining native models | `featured.length + 100` or higher | Unselected natives are moved below the featured block |

The first five entries are the overrides advertised to `spawn_agent`; the rest continue in the
normal picker order.
normal picker order. With account selectors, the five-entry limit applies after bare native choices
have expanded into selector-qualified groups.

## Changing the order

The only supported way to customize leading model order is to reorder `subagentModels`. You can do
that on the dashboard's **Sub-agents** page or in the opencodex configuration. The list accepts at
most five models, and its order is significant.
The supported way to customize leading model order is to reorder `subagentModels`. The dashboard's
**Sub-agents** page can reorder bare native and routed ids. Use `ocx agent subagents set` or edit the
opencodex configuration for exact `<selector>/<native-openai-model>` choices; the dashboard does not
list those choices and omits them if it saves the roster. Use at most five configured ids. With
account selectors, one bare native choice can expand into multiple selector-qualified catalog rows,
so configured choices and advertised rows are not necessarily one-to-one.

There is currently no general `modelOrder`, `providerOrder`, or priority-map setting in `OcxConfig`.
The supported ordering field is `subagentModels` (`src/types.ts:238-246`); `disabledModels` and each
provider's `selectedModels` are visibility fields (`src/types.ts:276-282` and
`src/types.ts:439-446`). To change the rest of the picker order would require a code-level behavior
change rather than a configuration edit.
The supported ordering field is `subagentModels`; `disabledModels` and each provider's
`selectedModels` are visibility fields. Changing the remaining picker order would require a
code-level behavior change rather than a configuration edit.
59 changes: 41 additions & 18 deletions docs-site/src/content/docs/guides/model-routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,31 @@ description: How opencodex decides which provider serves a given model id.
When Codex asks for a model, `router.ts` resolves it to exactly one configured provider. The rules are
checked **in order**; the first match wins.

For OpenAI, bare `gpt-*` ids select one `openai` provider. Its `codexAccountMode` chooses
Pool(default, main plus added accounts) or Direct(current caller/main bearer) without changing the
model id. `openai-apikey/<model>` explicitly selects API-key transport. The two credential routes
do not fall through to one another.
For OpenAI, a configured `<selector>/gpt-*` id maps through `codexAccountNamespaces` to exactly one
stored Codex account before combo or provider namespaces are considered. Bare `gpt-*` ids select
the canonical `openai` provider instead. Its `codexAccountMode` chooses Pool (default, main plus
added accounts) or Direct (current caller/main bearer) without changing the model id.
`openai-apikey/<model>` explicitly selects API-key transport. These credential routes do not fall
through to one another.

## Precedence

1. **Explicit `provider/model`** — if the id contains `/` and the part before it is the name of a
1. **Exact Codex account selector** — if the id is
`<selector>/<native-openai-model>` and the selector is configured in `codexAccountNamespaces`,
the request uses only the mapped stored account and sends the bare native model upstream.
Unavailable exact targets fail closed instead of continuing through Pool, Direct, or provider
routing.

```text
side/gpt-5.6-sol → provider "openai", model "gpt-5.6-sol", account selector "side"
```

2. **Combo id or alias** — while at least one combo is configured, a canonical `combo/<id>` or
configured combo alias selects its concrete target before provider namespaces are checked. With
no configured combos, a legacy physical provider literally named `combo` remains a normal
provider namespace. See [Combos](/guides/combos/) for target selection and failover behavior.

3. **Explicit `provider/model`** — if the id contains `/` and the part before it is the name of a
configured provider, that provider is used and the id is stripped to the part after the slash.

```text
Expand All @@ -22,29 +39,32 @@ do not fall through to one another.
openrouter/openai/gpt-5.6-sol → provider "openrouter", model "openai/gpt-5.6-sol"
```

This is the unambiguous form, and the one Codex's model picker uses for routed models.
If the named provider is disabled, this explicit form throws instead of routing.
This is the explicit routed-provider form, and the one Codex's model picker uses for routed
models. If the same public id is a configured combo alias, rule 2 wins. If the named provider is
disabled, this explicit form throws instead of routing.

4. **Bare native OpenAI-family id** — an id such as `gpt-*`, `o1-*`, `o3-*`, or `o4-*` uses the
canonical enabled `openai` provider and its configured Pool or Direct account mode.

2. **A provider's `defaultModel`** — if any provider's `defaultModel` equals the id, that provider
5. **A provider's `defaultModel`** — if any provider's `defaultModel` equals the id, that provider
is used (id passed through unchanged).

3. **Built-in prefix patterns** — the id is matched against known model-family prefixes, then routed
6. **Built-in prefix patterns** — the id is matched against known model-family prefixes, then routed
to a configured provider of that name (or name-prefix):

| Prefixes | Provider |
| --- | --- |
| `claude-`, `claude-sonnet-`, `claude-opus-`, `claude-haiku-` | `anthropic` |
| `gpt-`, `o1-`, `o3-`, `o4-` | bare ids use the configured `openai` account mode; use `openai-apikey/` for API-key transport |
| `llama-`, `mixtral-`, `gemma-` | `groq` |

This matcher is name-based and, unlike the `defaultModel` / `models[]` scans, currently does not
filter a matching provider whose `disabled` flag is true.

4. **A provider's `models[]`** — if no prefix rule won and an active provider lists the id in its
`models[]`, that provider is used. This order matters: with an OpenAI-named provider configured,
a bare `gpt-*` id reaches it before another provider's `models[]` claim.
7. **A provider's `models[]`** — if no prefix rule won and an active provider lists the id in its
`models[]`, that provider is used. Rule 4 already sends a bare `gpt-*` id to the canonical enabled
`openai` provider before another provider's `models[]` claim can match.

5. **Default provider** — if nothing matched, the id is sent to `config.defaultProvider` unchanged.
8. **Default provider** — if nothing matched, the id is sent to `config.defaultProvider` unchanged.
(If no default provider is configured, or it is disabled, routing throws.)

## API keys and environment variables
Expand Down Expand Up @@ -81,11 +101,14 @@ Routing and catalog visibility are separate controls:

## Tips

- **Be explicit for routed models.** Prefer `provider/model` (rule 1) — it's unambiguous and
matches what Codex shows in its picker after a catalog sync.
- **Seed `models[]` or `defaultModel`** on a provider so short ids (rule 2/4) resolve without the
- **Target a Codex account explicitly** with `<selector>/<native-openai-model>` (rule 1). That route
is exact and fails closed; it never silently switches to another account.
- **Be explicit for routed models.** Prefer `provider/model` (rule 3) when that exact public id is
not a combo alias. It directly names the provider and matches what Codex shows in its picker after
a catalog sync.
- **Seed `models[]` or `defaultModel`** on a provider so short ids (rules 5/7) resolve without the
`provider/` prefix.
- **Prefix patterns are a convenience**, not a guarantee: they only resolve if a provider with that
name (e.g. `anthropic`, `openai`, `groq`) is actually configured.
name (e.g. `anthropic` or `groq`) is actually configured.

See [Configuration](/reference/configuration/) for the provider fields these rules read.
9 changes: 5 additions & 4 deletions docs-site/src/content/docs/guides/sub-agent-surface.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,16 @@ Custom `injectionPrompt` text can use all four placeholders:

| Placeholder | Replaced with |
| --- | --- |
| `{{model}}` | The configured `injectionModel`, or an empty string |
| `{{model}}` | The effective preferred model for this request. A bare native `injectionModel` is account-qualified only when the request itself targets an explicit account selector. An unresolved or ambiguous bare value becomes an empty string; an unresolved explicit account-qualified or routed id remains unchanged |
| `{{effort}}` | The configured `injectionEffort`, or an empty string |
| `{{roster}}` | The resolved picker-visible, surface-compatible roster |
| `{{fallback}}` | The configured global fallback guidance |

The built-in v2 guidance has a 700-character budget. If it would exceed the budget, opencodex drops
the roster first rather than truncating the core spawn instructions. Guidance fires only when a
preferred model, eligible roster, or fallback chain resolves. A custom prompt does not bypass that
gate.
the roster first rather than truncating the core spawn instructions. Built-in guidance fires only
when a preferred model, eligible roster, or fallback chain resolves. A configured `injectionModel`
is sufficient to render a custom prompt; if a bare value cannot resolve uniquely, `{{model}}`
expands to an empty string.

On v1, opencodex injects only the upstream-style proactive delegation guidance at `max` or `ultra`
effort. It does not add a preferred model, roster, fallback list, or custom prompt on v1.
Expand Down
Loading
Loading