Skip to content

Commit b373ddd

Browse files
committed
feat(providers): add bounded model discovery contract
1 parent ca7b104 commit b373ddd

22 files changed

Lines changed: 1017 additions & 95 deletions

docs-site/src/content/docs/ja/reference/configuration.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ token の代わりに使えます。すべての候補は timing side channel
144144
| `apiKeyPool?` | `ApiKeyPoolEntry[]` | 複数キーを納める pool。`apiKey` はアクティブ項目を反映します。各項目には `id``key`、選択 `label`、選択数値 `addedAt` があります。 |
145145
| `defaultModel?` | `string` | 明示的なモデルなしでこのプロバイダーを選んだときに使うモデル。 |
146146
| `models?` | `string[]` | seed/fallback モデル一覧。`liveModels``false` ならここにあるモデルだけが発見されます。 |
147-
| `liveModels?` | `boolean` | 起動/同期時にプロバイダーのリアルタイム `/models` カタログを取得します(デフォルト `true`)。`false` なら設定された `models` だけを使います。 |
147+
| `liveModels?` | `boolean` | 起動/同期時にプロバイダーのライブモデルカタログを取得します(デフォルト `true`。組み込み preset は registry の信頼済み URL・クエリ・フィルターを使用でき、カスタム provider は `${baseUrl}/models` がデフォルトです`false` なら設定された `models` だけを使います。 |
148148
| `selectedModels?` | `string[]` | モデル発見後に適用するカタログ allowlist。空でなければその id だけを Codex に公開し、空または省略なら発見したモデルをすべて公開します。 |
149149
| `contextWindow?` | `number` | ルーティングカタログ項目に表示するプロバイダー単位の context-window cap。リアルタイム metadata がより小さければそのままにします。 |
150150
| `modelContextWindows?` | `Record<string,number>` | モデル別 context-window cap。一致するモデルでは `contextWindow` より優先し、より小さいリアルタイム metadata を上げません。 |
@@ -232,6 +232,11 @@ Codex の承認と sandbox ルールを迂回する Cursor ネイティブロー
232232
一部のプロバイダーはリアルタイムモデルカタログが非常に大きいか遅いです。Codex に `models` で固定したモデルだけ
233233
見せるには `liveModels``false` に設定してください。
234234

235+
ライブ discovery は 4 MiB または 2,000 件の生モデル行を超える応答をキャッシュ前に拒否します。
236+
組み込み preset は上限をさらに下げ、混在カタログをチャット対応行だけに絞れます。超過または
237+
不正な応答は stale/static fallback に戻り、不適格な行は除外されます。有効な応答に適格な行が
238+
なければ権威ある空カタログとなり、上限超過の応答が暗黙に切り詰められることはありません。
239+
235240
`liveModels``false``models` が空または省略されると opencodex はそのプロバイダーのルーティング
236241
モデルを 1 つも公開しません。
237242

docs-site/src/content/docs/ko/reference/configuration.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ token 대신 쓸 수 있습니다. 모든 후보는 timing side channel을 막
151151
| `apiKeyPool?` | `ApiKeyPoolEntry[]` | 여러 키를 담는 pool. `apiKey`는 활성 항목을 반영합니다. 각 항목에는 `id`, `key`, 선택 `label`, 선택 숫자 `addedAt`이 있습니다. |
152152
| `defaultModel?` | `string` | 명시적인 모델 없이 이 프로바이더를 선택했을 때 쓸 모델. |
153153
| `models?` | `string[]` | seed/fallback 모델 목록. `liveModels``false`이면 여기 있는 모델만 발견됩니다. |
154-
| `liveModels?` | `boolean` | 시작/동기화 시 프로바이더의 실시간 `/models` 카탈로그를 가져옵니다(기본 `true`). `false`이면 설정된 `models`만 사용합니다. |
154+
| `liveModels?` | `boolean` | 시작/동기화 시 프로바이더의 실시간 모델 카탈로그를 가져옵니다(기본 `true`). 기본 제공 preset은 registry의 신뢰된 URL·쿼리·필터를 사용할 수 있고, 사용자 지정 provider는 `${baseUrl}/models`가 기본입니다. `false`이면 설정된 `models`만 사용합니다. |
155155
| `selectedModels?` | `string[]` | 모델 발견 뒤 적용할 카탈로그 allowlist. 비어 있지 않으면 해당 id만 Codex에 노출하고, 비어 있거나 생략하면 발견한 모델을 모두 노출합니다. |
156156
| `contextWindow?` | `number` | 라우팅 카탈로그 항목에 표시할 프로바이더 단위 context-window cap. 실시간 metadata가 더 작으면 그대로 둡니다. |
157157
| `modelContextWindows?` | `Record<string,number>` | 모델별 context-window cap. 일치하는 모델에서는 `contextWindow`보다 우선하며 더 작은 실시간 metadata를 올리지 않습니다. |
@@ -259,6 +259,11 @@ OpenRouter에서 같은 모델을 제공하는 endpoint마다 prompt cache 지
259259
일부 프로바이더는 실시간 모델 카탈로그가 매우 크거나 느립니다. Codex에 `models`로 고정한 모델만
260260
보이게 하려면 `liveModels``false`로 설정하세요.
261261

262+
실시간 discovery 응답이 4 MiB 또는 원시 모델 행 2,000개를 넘으면 캐시 전에 거부됩니다. 기본 제공
263+
preset은 이 한도를 더 낮추고 혼합 카탈로그를 채팅 가능 행으로 필터링할 수 있습니다. 한도 초과 또는
264+
손상된 응답은 stale/static fallback을 사용하고, 부적격 행은 제외됩니다. 유효한 응답에 적격 행이
265+
없으면 권위 있는 빈 카탈로그가 되며, 한도 초과 응답을 조용히 잘라 사용하지 않습니다.
266+
262267
`liveModels``false`이고 `models`가 비어 있거나 생략되면 opencodex는 해당 프로바이더의 라우팅
263268
모델을 하나도 노출하지 않습니다.
264269

docs-site/src/content/docs/reference/configuration.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,15 +252,15 @@ or bind the forward explicitly to loopback (`ssh -L 127.0.0.1:20100:localhost:10
252252
| Field | Type | Meaning |
253253
| --- | --- | --- |
254254
| `adapter` | `string` | One of `openai-chat`, `openai-responses`, `anthropic`, `google`, `kiro`, `cursor`, `azure-openai` (or alias `azure`). |
255-
| `baseUrl` | `string` | Upstream API base URL. Built-in providers with a fixed endpoint ignore it — see [Fixed provider endpoints](#fixed-provider-endpoints). |
255+
| `baseUrl` | `string` | Upstream API base URL. Most built-in fixed endpoints ignore a mismatch; newly promoted collision-safe key presets preserve an older same-named custom destination. See [Fixed provider endpoints](#fixed-provider-endpoints). |
256256
| `responsesPath?` | `string` | Optional relative resource path for key-auth `openai-responses` requests. It must start with `/` and contain no URL scheme, query, or fragment. When omitted, the adapter keeps its legacy `/v1/responses` URL construction. |
257257
| `disabled?` | `boolean` | Keep the provider on disk but exclude it from routing and model/catalog listings. |
258258
| `apiKey?` | `string` | API key, or an `${ENV_VAR}` / `$ENV_VAR` reference resolved at request time. |
259259
| `apiKeyTransport?` | `"x-api-key" \| "bearer"` | Anthropic API-key header style. Defaults to native `x-api-key`; set `"bearer"` for compatible gateways that require `Authorization: Bearer <key>`. Valid only for key-auth `anthropic` providers. |
260260
| `apiKeyPool?` | `ApiKeyPoolEntry[]` | Multi-key pool. `apiKey` mirrors the active entry; each item has `id`, `key`, optional `label`, and optional numeric `addedAt`. |
261261
| `defaultModel?` | `string` | Model used when this provider is selected without an explicit model. |
262262
| `models?` | `string[]` | Seed/fallback model list. When `liveModels` is `false`, these are the only discovered models. |
263-
| `liveModels?` | `boolean` | Fetch the provider's live `/models` catalog on start/sync (default `true`). Set `false` to use only configured `models`. |
263+
| `liveModels?` | `boolean` | Fetch the provider's live model catalog on start/sync (default `true`). Built-in presets may use a trusted registry URL/query/filter; custom providers default to `${baseUrl}/models`. Set `false` to use only configured `models`. |
264264
| `selectedModels?` | `string[]` | Catalog allowlist applied after discovery. A non-empty list exposes only those ids to Codex; empty/omitted exposes all discovered models. |
265265
| `contextWindow?` | `number` | Provider-wide Codex-visible context-window cap for routed catalog entries. Live metadata below this value is kept. |
266266
| `modelContextWindows?` | `Record<string,number>` | Model-specific context-window caps. These override `contextWindow` for matching model ids and never raise smaller live metadata. |
@@ -304,13 +304,16 @@ or bind the forward explicitly to loopback (`ssh -L 127.0.0.1:20100:localhost:10
304304
### Fixed provider endpoints
305305

306306
Routing resolves a provider's endpoint before any adapter sees it, and for most built-in
307-
providers the registry's own endpoint wins over a `baseUrl` in your config. Three kinds of entry
307+
providers the registry's own endpoint wins over a `baseUrl` in your config. Four kinds of entry
308308
keep the configured URL at this stage:
309309

310310
- providers that opt into an override — `ollama`, `vllm`, `lm-studio`, `litellm`, `qwen-cloud`
311311
and `alibaba-token-plan-intl`;
312312
- providers whose registry endpoint is a template you fill in, such as `azure-openai` and
313313
`cloudflare-ai-gateway`;
314+
- newly promoted fixed API-key presets that protect name collisions: if an older same-named
315+
custom provider points somewhere else, it remains custom instead of sending that key to the new
316+
registry host;
314317
- providers you define yourself, which are not in the registry at all.
315318

316319
Adapters may adjust the resolved URL afterward. The `kiro` adapter, for example, follows the API
@@ -471,6 +474,12 @@ example above, select `openrouter/anthropic-claude-sonnet-5` in Codex; OpenCodex
471474
Some providers expose very large or slow live model catalogs. Set `liveModels` to `false` when you
472475
want Codex to see only the models pinned in `models`:
473476

477+
Live discovery rejects a response before caching when it exceeds 4 MiB or 2,000 raw model rows.
478+
Built-in presets may lower either limit and filter mixed catalogs to chat-eligible rows. An
479+
oversized or malformed response follows the normal stale/configured fallback path, while
480+
ineligible rows are excluded. A valid result with zero eligible rows remains an authoritative
481+
empty catalog; OpenCodex never silently truncates an over-limit response.
482+
474483
When `liveModels` is `false` and `models` is empty or omitted, opencodex exposes no routed models
475484
for that provider.
476485

docs-site/src/content/docs/ru/reference/configuration.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ x-opencodex-api-key: your-secret-token
171171
| `apiKeyPool?` | `ApiKeyPoolEntry[]` | Пул из нескольких ключей. `apiKey` отражает активную запись; каждый элемент содержит `id`, `key`, необязательный `label` и необязательное числовое `addedAt`. |
172172
| `defaultModel?` | `string` | Модель, используемая при выборе этого провайдера без явной модели. |
173173
| `models?` | `string[]` | Список seed/fallback-моделей. Когда `liveModels` равен `false`, обнаруживаются только эти модели. |
174-
| `liveModels?` | `boolean` | Получать живой каталог `/models` провайдера при старте/синхронизации (по умолчанию `true`). Установите `false`, чтобы использовать только настроенные `models`. |
174+
| `liveModels?` | `boolean` | Получать живой каталог моделей при старте/синхронизации (по умолчанию `true`). Встроенные preset могут использовать доверенные URL, query и фильтры из registry; пользовательские provider по умолчанию запрашивают `${baseUrl}/models`. Установите `false`, чтобы использовать только настроенные `models`. |
175175
| `selectedModels?` | `string[]` | Allowlist каталога, применяемый после обнаружения. Непустой список открывает Codex только эти id; пустой или опущенный открывает все обнаруженные модели. |
176176
| `contextWindow?` | `number` | Видимый Codex лимит контекстного окна на уровне провайдера для маршрутизируемых записей каталога. Живые метаданные ниже этого значения сохраняются. |
177177
| `modelContextWindows?` | `Record<string,number>` | Лимиты контекстного окна для конкретных моделей. Они перекрывают `contextWindow` для совпадающих id моделей и никогда не повышают меньшие живые метаданные. |
@@ -281,6 +281,12 @@ HTTP). Stdio-записи также принимают `args?: string[]`, `env?
281281
Некоторые провайдеры отдают очень большие или медленные живые каталоги моделей. Установите
282282
`liveModels` в `false`, когда хотите, чтобы Codex видел только модели, закреплённые в `models`:
283283

284+
Живой discovery отклоняет ответ до кэширования, если он превышает 4 MiB или 2 000 исходных строк
285+
моделей. Встроенный preset может снизить эти лимиты и отфильтровать смешанный каталог до chat-моделей.
286+
Слишком большой или повреждённый ответ использует обычный stale/static fallback, а неподходящие
287+
строки исключаются. Корректный ответ без подходящих строк остаётся авторитетным пустым каталогом;
288+
ответ сверх лимита никогда не обрезается молча.
289+
284290
Когда `liveModels` равен `false`, а `models` пуст или опущен, opencodex не открывает для этого
285291
провайдера ни одной маршрутизируемой модели.
286292

docs-site/src/content/docs/zh-cn/reference/configuration.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,15 +135,15 @@ x-opencodex-api-key: your-secret-token
135135
| Field | Type | 含义 |
136136
| --- | --- | --- |
137137
| `adapter` | `string` | `openai-chat``openai-responses``anthropic``google``kiro``cursor``azure-openai`(或别名 `azure`)之一。 |
138-
| `baseUrl` | `string` | 上游 API base URL。端点固定的内置 provider 会忽略它 —— [固定的 provider 端点](#固定的-provider-端点)|
138+
| `baseUrl` | `string` | 上游 API base URL。大多数固定端点的内置 provider 会忽略不一致的地址;新加入且启用冲突保护的 API-key preset 会保留旧有同名 custom provider 的目标。[固定的 provider 端点](#固定的-provider-端点)|
139139
| `responsesPath?` | `string` | `key` 认证的 `openai-responses` 请求可选相对 resource path。必须以 `/` 开头,且不得包含 URL scheme、query 或 fragment。省略时保留原有的 `/v1/responses` URL 构造。 |
140140
| `disabled?` | `boolean` | 配置保留在磁盘上,但从路由和模型/目录列表排除。 |
141141
| `apiKey?` | `string` | API key,或在请求时解析的 `${ENV_VAR}` / `$ENV_VAR` 引用。 |
142142
| `apiKeyTransport?` | `"x-api-key" \| "bearer"` | Anthropic API key 的请求头方式。默认使用原生 `x-api-key`;兼容 gateway 要求 `Authorization: Bearer <key>` 时设为 `"bearer"`。仅适用于使用 key 认证的 `anthropic` provider。 |
143143
| `apiKeyPool?` | `ApiKeyPoolEntry[]` | 多 key pool。`apiKey` 映射当前活动条目;每项包含 `id``key`、可选 `label` 和可选数字 `addedAt`|
144144
| `defaultModel?` | `string` | 选中该 provider 但未指定明确模型时使用的模型。 |
145145
| `models?` | `string[]` | seed/fallback 模型列表。`liveModels``false` 时,只会发现这些模型。 |
146-
| `liveModels?` | `boolean` | 启动/同步时获取 provider 的实时 `/models` 目录(默认 `true`)。设为 `false` 时只使用配置的 `models`|
146+
| `liveModels?` | `boolean` | 启动/同步时获取 provider 的实时模型目录(默认 `true`。内置 preset 可使用 registry 中受信任的 URL、查询参数和过滤规则;自定义 provider 默认请求 `${baseUrl}/models`。设为 `false` 时只使用配置的 `models`|
147147
| `selectedModels?` | `string[]` | 模型发现后应用的目录 allowlist。非空时只向 Codex 暴露这些 id;为空或省略时暴露所有发现的模型。 |
148148
| `contextWindow?` | `number` | 路由目录条目的 provider 级 Codex 可见 context-window cap。实时 metadata 更小时保留实时值。 |
149149
| `modelContextWindows?` | `Record<string,number>` | 模型级 context-window cap。匹配模型时优先于 `contextWindow`,且不会抬高更小的实时 metadata。 |
@@ -181,11 +181,13 @@ x-opencodex-api-key: your-secret-token
181181
### 固定的 provider 端点
182182

183183
路由会在任何 adapter 介入之前解析 provider 的端点;对大多数内置 provider 而言,registry 自带的端点
184-
优先于你在配置里写的 `baseUrl`。在这一步保留配置 URL 的只有三类
184+
优先于你在配置里写的 `baseUrl`。在这一步保留配置 URL 的有四类
185185

186186
- 显式开启覆盖的 provider —— `ollama``vllm``lm-studio``litellm``qwen-cloud`
187187
`alibaba-token-plan-intl`
188188
- registry 端点本身是待填模板的 provider,例如 `azure-openai``cloudflare-ai-gateway`
189+
- 新加入并启用同名冲突保护的固定 API-key preset:若旧有同名 custom provider 指向其他地址,
190+
它会继续作为 custom provider 使用原目标,不会把 key 发往新 registry host;
189191
- 你自己定义的 provider,它们根本不在 registry 中。
190192

191193
之后 adapter 仍可能调整已解析的 URL。例如 `kiro` adapter 在 host 为标准
@@ -268,6 +270,11 @@ MCP、屏幕录制和 computer-use 使用独立的 `mcpServers` / `desktopExecut
268270
部分 provider 的实时模型目录非常大或很慢。若只想让 Codex 看到 `models` 中固定的模型,请把
269271
`liveModels` 设为 `false`
270272

273+
实时发现响应超过 4 MiB 或包含超过 2,000 条原始模型记录时,会在缓存前被拒绝。内置 preset
274+
还可以降低这些上限,并把混合目录过滤为可用于聊天的模型。超限或格式错误的响应会沿用陈旧缓存/
275+
静态配置回退,不合格的记录则被排除。若合法响应中没有合格记录,结果仍是权威的空目录;超限响应
276+
不会被静默截断。
277+
271278
`liveModels``false``models` 为空或省略时,opencodex 不会为该 provider 暴露任何
272279
路由模型。
273280

src/codex/catalog/parsing.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ export interface CatalogModel {
110110
/** Whether Codex may send Responses text.verbosity for this routed model. */
111111
supportsVerbosity?: boolean;
112112
supportsReasoningSummaries?: boolean;
113+
/** Normalized upstream capability names retained for management/API consumers (#485 follow-up). */
114+
capabilities?: string[];
113115
}
114116

115117
export type RawEntry = Record<string, unknown>;

0 commit comments

Comments
 (0)