Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ account を削除しても mapping は保持され、同じ id を再追加す

`openaiProviderTierVersion: 2` は、現在の単一プロバイダーの投影をマークします。出荷された v1 設定を移行する前に、opencodex は別のバックアップを置き換えずに `config.json.pre-openai-tiers-v2.bak` を作成し、既知の名前空間で選択された既知のレガシー ID を裸の ID に書き換えます。

## プロバイダー名前空間のエイリアス

プロバイダーには、`google-antigravity` の `agy` のような組み込みの短縮名があります。設定済みのプロバイダー名または明示的なエイリアスが、大文字と小文字を区別せずにその短縮名を使用している場合、別のプロバイダーの組み込み短縮名はカタログ表示とエイリアスルーティングの両方で無効になります。たとえば、`agy` というプロバイダーを設定すると、Google のモデルは `google-antigravity/<model>` と表示され、`agy/<model>` は設定済みのプロバイダーを選択します。正規のプロバイダー名は引き続き大文字と小文字の完全一致が必要で、認識されない接頭辞には既存のモデルルーティングのフォールバックが適用されます。

## プロバイダーエントリー (`OcxProviderConfig`)

|フィールド |タイプ |意味 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ managed map을 활성화하면 privacy-safe selector를 만들고, 이후 계정

`openaiProviderTierVersion: 2`는 현재의 단일 공급자 투영을 표시합니다. 출시된 v1 설정을 마이그레이션하기 전에 opencodex는 `config.json.pre-openai-tiers-v2.bak`를 만들고, 기존에 다른 백업이 있더라도 덮어쓰지 않으며, 알려진 레거시 네임스페이스 지정 선택 id를 bare id로 다시 씁니다.

## 공급자 네임스페이스 별칭

공급자는 `google-antigravity`의 `agy`처럼 기본 축약 이름을 제공할 수 있습니다. 설정된 공급자 이름이나 명시적 별칭이 대소문자 구분 없이 그 이름을 사용하면, 다른 공급자의 기본 축약 이름은 카탈로그 표시와 별칭 라우팅 모두에서 비활성화됩니다. 예를 들어 `agy`라는 공급자를 설정하면 Google 모델은 `google-antigravity/<model>`로 표시되고, `agy/<model>`는 설정된 공급자를 선택합니다. 정식 공급자 이름은 계속 대소문자가 정확히 일치해야 하며, 인식되지 않는 접두사는 기존 모델 라우팅의 대체 경로를 따릅니다.

## 공급자 항목 (`OcxProviderConfig`)

| 필드 | 타입 | 의미 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ published long-context bands on `openai` and `openai-apikey`. The two Daybreak B
follow the Sol API reference. These are comparison estimates, not invoices or credit-balance
predictions. Explicit provider/model price overrides still take precedence.

## Provider namespace aliases

Providers can expose a built-in shorthand, such as `agy` for `google-antigravity`. A configured provider name or explicit alias claims that shorthand case-insensitively; a different provider's built-in shorthand is then suppressed in both catalog names and alias routing. For example, configuring a provider named `agy` keeps Google's models under `google-antigravity/<model>`, while `agy/<model>` selects the configured provider. Canonical provider names still require an exact case match, and unrecognized prefixes retain the existing model-routing fallback.

## Provider entries (`OcxProviderConfig`)

| Field | Type | Meaning |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ cross-route credential fallback не существует. Строки API GPT-
перезаписывая отличающуюся backup-копию, и переписывает известные legacy namespaced-id,
выбранные в `selectedModels`, в bare-id.

## Псевдонимы пространств имён провайдеров

У провайдеров могут быть встроенные сокращения, например `agy` для `google-antigravity`. Если имя настроенного провайдера или явный псевдоним занимает такое сокращение без учёта регистра, встроенное сокращение другого провайдера отключается и в каталоге, и при маршрутизации по псевдониму. Например, при настройке провайдера с именем `agy` модели Google отображаются как `google-antigravity/<model>`, а `agy/<model>` выбирает настроенного провайдера. Канонические имена провайдеров по-прежнему требуют точного совпадения регистра; для нераспознанных префиксов сохраняется существующий резервный путь маршрутизации модели.

## Записи провайдеров (`OcxProviderConfig`)

| Поле | Тип | Значение |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ selector,而不是分配一个新名称。

`openaiProviderTierVersion: 2` 标记当前的单提供者投影。对已发布的 v1 配置进行迁移之前,opencodex 会创建 `config.json.pre-openai-tiers-v2.bak`,且不会覆盖不同的备份文件,并会把已知的旧式命名空间选择 id 重写为裸 id。

## 提供者命名空间别名

提供者可以有内置缩写,例如 `google-antigravity` 的 `agy`。如果已配置的提供者名称或显式别名占用了该缩写(不区分大小写),另一个提供者的内置缩写就会在目录名称和别名路由中同时禁用。例如,配置名为 `agy` 的提供者后,Google 模型会显示为 `google-antigravity/<model>`,而 `agy/<model>` 会选择已配置的提供者。规范提供者名称仍要求大小写完全一致;无法识别的前缀继续沿用现有的模型路由回退行为。

## 提供者条目(`OcxProviderConfig`)

| 字段 | 类型 | 含义 |
Expand Down
5 changes: 4 additions & 1 deletion src/providers/default-aliases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ export function effectiveProviderAlias(
if (config?.providers) {
const lower = regAlias.toLowerCase();
const claimedByOther = Object.entries(config.providers).some(([name, p]) =>
name !== providerName && typeof p.alias === "string" && p.alias.trim().toLowerCase() === lower
name !== providerName && (
name.toLowerCase() === lower
|| (typeof p.alias === "string" && p.alias.trim().toLowerCase() === lower)
)
);
if (claimedByOther) return undefined;
}
Expand Down
7 changes: 5 additions & 2 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -703,13 +703,16 @@ function routeModelInternal(
throw new Error("provider alias '" + requestedProvider + "' is ambiguous: " + configuredMatches.map(([n]) => n).sort().join(", "));
} else {
// Pass 2: built-in registry aliases, only for providers that do NOT have an explicit alias override
// and whose registry alias has not been claimed by another configured provider (#3531 review)
// and whose registry alias has not been claimed by another configured provider name or alias
const registryMatches = Object.entries(config.providers).filter(([name, provider]) => {
if (provider.alias !== undefined) return false;
const regAlias = PROVIDER_REGISTRY.find(e => e.id === name)?.alias;
if (!regAlias || regAlias.toLowerCase() !== requestedLower) return false;
const claimedByOther = Object.entries(config.providers).some(([otherName, p]) =>
otherName !== name && typeof p.alias === "string" && p.alias.trim().toLowerCase() === requestedLower
otherName !== name && (
otherName.toLowerCase() === requestedLower
|| (typeof p.alias === "string" && p.alias.trim().toLowerCase() === requestedLower)
)
);
return !claimedByOther;
});
Expand Down
44 changes: 44 additions & 0 deletions tests/providers/provider-model-aliases.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,50 @@ describe("provider and model aliases", () => {
routeReason: "explicit-provider-namespace",
});
});
test.each(["agy", "AgY"])("canonical provider name %s suppresses a colliding built-in alias", async canonicalName => {
const c = {
port: 10100,
defaultProvider: "google-antigravity",
providers: {
[canonicalName]: {
adapter: "openai-chat",
baseUrl: "https://custom.test/v1",
models: ["gemini-3.8-flash"],
liveModels: false,
},
"google-antigravity": {
adapter: "google",
baseUrl: "https://daily-cloudcode-pa.googleapis.com",
authMode: "oauth",
models: ["gemini-3.8-flash"],
liveModels: false,
},
},
} as unknown as OcxConfig;

const models = await gatherRoutedModels(c);
const googleModel = models.find(m => m.provider === "google-antigravity" && m.id === "gemini-3.8-flash")!;
expect(googleModel.providerAlias).toBeNull();

const [googleEntry] = buildCatalogEntries(null, [], [googleModel]);
expect(googleEntry!.display_name).toBe("google-antigravity/gemini-3.8-flash");
expect(routeModel(c, googleEntry!.display_name)).toMatchObject({
providerName: "google-antigravity",
modelId: "gemini-3.8-flash",
});
expect(routeModel(c, `${canonicalName}/gemini-3.8-flash`)).toMatchObject({
providerName: canonicalName,
modelId: "gemini-3.8-flash",
});

// Canonical names stay case-sensitive. A case variant must not activate the
// claimed registry alias; preserve the unknown slash-id default fallback.
expect(routeModel({ ...c, defaultProvider: canonicalName }, "AGY/gemini-3.8-flash")).toMatchObject({
providerName: canonicalName,
modelId: "AGY/gemini-3.8-flash",
routeReason: "default-provider",
});
});
test("static gather (liveModels: false) suppresses agy when other provider explicitly owns it", async () => {
const c = {
port: 10100,
Expand Down
Loading