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
5 changes: 5 additions & 0 deletions docs-site/src/content/docs/guides/web-dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ Cost values in **Logs** and **Usage** are API list-price equivalents calculated
They are not billing receipts or evidence of an actual charge; subscription usage or provider credits
may apply instead.

## Model visibility

The **Models** switches show final Codex visibility: a routed model is on only when its provider allowlist includes it (or no allowlist is set) and it is not disabled. Turning a model on reconciles both filters atomically; **All on** clears the provider allowlist so newly discovered models are also on.

## Delegation picker vs spawn routing

The Dashboard's **Sub-agent delegation** picker stores `injectionModel` and, optionally,
Expand Down Expand Up @@ -98,6 +102,7 @@ The GUI is a thin client over the proxy's JSON management API. Useful endpoints
| `GET` / `PUT /api/v2` | Read or set the surface mode, Codex feature flag, and v2 thread limit. |
| `GET /api/providers` · `POST /api/providers` · `PATCH /api/providers?name=...` · `DELETE /api/providers?name=...` | List, add/replace, enable/disable, or remove providers. |
| `GET /api/models` · `PUT /api/disabled-models` | List native/routed model rows and update the shared disabled-model set. |
| `GET /api/selected-models` · `PUT /api/model-visibility` | Read provider allowlists and atomically change the final visibility of one model or provider group. |
| `GET /api/key-providers` · `GET /api/oauth/providers` | Read the API-key and OAuth provider catalogs. |
| `POST /api/oauth/login` · `GET /api/oauth/status` | Start a provider OAuth flow and poll for completion. |
| `GET /api/codex-auth/accounts?refresh=1` | List main and pool accounts, force quota refresh, and report main-account `hasCredential` / terminal `needsReauth` state. |
Expand Down
5 changes: 5 additions & 0 deletions docs-site/src/content/docs/ja/guides/web-dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ bun run dev:gui
**ログ**と**使用量**のコスト値は報告されたトークンで計算した API 定価換算値です。請求明細や
実際の請求証拠ではなく、サブスクリプション使用量またはプロバイダークレジットが代わりに適用される場合があります。

## モデルの表示

**モデル** スイッチは Codex での最終的な表示状態を示します。ルーティングモデルはプロバイダーの allowlist に含まれる(または allowlist がない)うえで、無効化されていない場合だけオンになります。オン操作は両方のフィルターを原子的に調整し、**すべてオン** は allowlist を解除して新しいモデルも含めます。

## 委任セレクターとスポーンルーティングの違い

ダッシュボードの **サブエージェント委任** セレクターは `injectionModel` とオプションの `injectionEffort` を
Expand Down Expand Up @@ -92,6 +96,7 @@ GUI はプロキシの JSON 管理 API を使うシンクライアントです
| `GET` / `PUT /api/v2` | サーフェスモード、Codex 機能フラグ、v2 スレッド上限を読むか変えます。 |
| `GET /api/providers` · `POST /api/providers` · `PATCH /api/providers?name=...` · `DELETE /api/providers?name=...` | プロバイダー一覧の参照、追加/差替、有効化/無効化、削除。 |
| `GET /api/models` · `PUT /api/disabled-models` | ネイティブ/ルーティングモデル行を参照し共有 disabled model 一覧を更新します。 |
| `GET /api/selected-models` · `PUT /api/model-visibility` | プロバイダー allowlist を読み取り、モデルまたはプロバイダーグループの最終表示状態を原子的に変更します。 |
| `GET /api/key-providers` · `GET /api/oauth/providers` | API キーおよび OAuth プロバイダーカタログを読みます。 |
| `POST /api/oauth/login` · `GET /api/oauth/status` | プロバイダー OAuth ログインを開始し完了可否を確認します。 |
| `GET /api/codex-auth/accounts?refresh=1` | メインおよびプールアカウントを参照しクォータを強制更新し、メインの `hasCredential` / terminal `needsReauth` 状態を返します。 |
Expand Down
5 changes: 5 additions & 0 deletions docs-site/src/content/docs/ko/guides/web-dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ bun run dev:gui
**Logs**와 **Usage**의 비용 값은 보고된 토큰으로 계산한 API 정가 환산치입니다. 결제 영수증이나
실제 청구 증거가 아니며, 구독 사용량 또는 프로바이더 크레딧이 대신 적용될 수 있습니다.

## 모델 노출

**Models** 스위치는 Codex의 최종 노출 상태를 나타냅니다. 라우팅 모델은 프로바이더 allowlist에 포함되거나 allowlist가 없고, 동시에 비활성화되지 않았을 때만 켜집니다. 모델을 켜면 두 필터를 원자적으로 조정하며, **모두 활성화**는 allowlist를 해제해 새로 발견되는 모델도 켭니다.

## 위임 선택기와 스폰 라우팅의 차이

Dashboard의 **Sub-agent delegation** 선택기는 `injectionModel`과 선택적인 `injectionEffort`를
Expand Down Expand Up @@ -94,6 +98,7 @@ GUI는 프록시의 JSON 관리 API를 사용하는 얇은 클라이언트입니
| `GET` / `PUT /api/v2` | 서피스 모드, Codex 기능 플래그, v2 thread 상한을 읽거나 바꿉니다. |
| `GET /api/providers` · `POST /api/providers` · `PATCH /api/providers?name=...` · `DELETE /api/providers?name=...` | 프로바이더 목록 조회, 추가/교체, 활성화/비활성화, 제거. |
| `GET /api/models` · `PUT /api/disabled-models` | 네이티브/라우팅 모델 행을 조회하고 공용 disabled model 목록을 갱신합니다. |
| `GET /api/selected-models` · `PUT /api/model-visibility` | 프로바이더 allowlist를 읽고 개별 모델 또는 프로바이더 그룹의 최종 노출 상태를 원자적으로 변경합니다. |
| `GET /api/key-providers` · `GET /api/oauth/providers` | API key 및 OAuth 프로바이더 카탈로그를 읽습니다. |
| `POST /api/oauth/login` · `GET /api/oauth/status` | 프로바이더 OAuth 로그인을 시작하고 완료 여부를 확인합니다. |
| `GET /api/codex-auth/accounts?refresh=1` | main 및 pool 계정을 조회하고 할당량을 강제로 갱신하며 main 계정의 `hasCredential` / terminal `needsReauth` 상태를 표시합니다. |
Expand Down
5 changes: 5 additions & 0 deletions docs-site/src/content/docs/ru/guides/web-dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ bun run dev:gui
рассчитанные на основе сообщённых токенов. Они не являются счётом и не подтверждают фактическое
списание; расходы могут покрываться подпиской или кредитами провайдера.

## Видимость моделей

Переключатели **Models** показывают итоговую видимость в Codex. Маршрутизируемая модель включена, только если она входит в allowlist провайдера (или allowlist отсутствует) и не отключена. Включение атомарно согласует оба фильтра, а **Включить все** удаляет allowlist и включает новые модели.

## Селектор делегирования и маршрутизация порождений

Селектор **Sub-agent delegation** в дашборде сохраняет `injectionModel` и, при желании,
Expand Down Expand Up @@ -97,6 +101,7 @@ GUI — это тонкий клиент поверх JSON-API управлен
| `GET` / `PUT /api/v2` | Чтение или настройка режима поверхности, фиче-флага Codex и лимита потоков v2. |
| `GET /api/providers` · `POST /api/providers` · `PATCH /api/providers?name=...` · `DELETE /api/providers?name=...` | Список, добавление/замена, включение/отключение или удаление провайдеров. |
| `GET /api/models` · `PUT /api/disabled-models` | Список строк нативных/маршрутизируемых моделей и обновление общего набора отключённых моделей. |
| `GET /api/selected-models` · `PUT /api/model-visibility` | Чтение allowlist провайдера и атомарное изменение итоговой видимости модели или группы провайдера. |
| `GET /api/key-providers` · `GET /api/oauth/providers` | Чтение каталогов провайдеров с API-ключом и OAuth. |
| `POST /api/oauth/login` · `GET /api/oauth/status` | Запуск OAuth-процесса провайдера и опрос его завершения. |
| `GET /api/codex-auth/accounts?refresh=1` | Список основного и пуловых аккаунтов с принудительным обновлением квот и состояниями `hasCredential` / terminal `needsReauth` основного аккаунта. |
Expand Down
5 changes: 5 additions & 0 deletions docs-site/src/content/docs/zh-cn/guides/web-dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ bun run dev:gui
**Logs** 和 **Usage** 中的费用是根据已报告 token 计算的 API 标价折算值,不是账单,也不能证明
实际发生了扣费;实际可能计入订阅用量或消耗服务商额度。

## 模型可见性

**Models** 开关表示 Codex 中的最终可见状态。路由模型只有在 provider allowlist 中(或未设置 allowlist)且未被禁用时才会开启。开启模型会原子地协调两个过滤条件;**全部开启** 会清除 allowlist,因此以后新发现的模型也会开启。

## 委派选择器与生成路由的区别

Dashboard 的 **Sub-agent delegation** 选择器会保存 `injectionModel`,以及可选的
Expand Down Expand Up @@ -89,6 +93,7 @@ GUI 是代理 JSON 管理 API 之上的轻量客户端。常用 endpoint 包括
| `GET` / `PUT /api/v2` | 读取或设置界面模式、Codex feature flag 和 v2 thread 上限。 |
| `GET /api/providers` · `POST /api/providers` · `PATCH /api/providers?name=...` · `DELETE /api/providers?name=...` | 列出、添加/替换、启用/禁用或删除 provider。 |
| `GET /api/models` · `PUT /api/disabled-models` | 列出原生/路由模型,并更新共享的 disabled-model 集合。 |
| `GET /api/selected-models` · `PUT /api/model-visibility` | 读取 provider allowlist,并原子地更改单个模型或 provider 分组的最终可见状态。 |
| `GET /api/key-providers` · `GET /api/oauth/providers` | 读取 API key 和 OAuth provider 目录。 |
| `POST /api/oauth/login` · `GET /api/oauth/status` | 启动 provider OAuth 流程并轮询完成状态。 |
| `GET /api/codex-auth/accounts?refresh=1` | 列出主账号与池账号、强制刷新配额,并返回主账号的 `hasCredential` / terminal `needsReauth` 状态。 |
Expand Down
74 changes: 74 additions & 0 deletions gui/src/model-visibility.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
export type ProviderModelMap = Record<string, string[]>;

export interface ModelVisibilityTarget { id: string; native?: boolean; }

export type ModelVisibilityScope = "models" | "provider";

function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}

function uniqueStrings(value: unknown): string[] {
if (!Array.isArray(value) || value.some(item => typeof item !== "string")) {
throw new Error("invalid model list");
}
return [...new Set(value)];
}

export function parseSelectedModels(value: unknown): ProviderModelMap {
if (!isRecord(value)) throw new Error("invalid selected models response");
const selected = value.selected;
if (!isRecord(selected)) throw new Error("invalid selected models response");
return Object.fromEntries(
Object.entries(selected).map(([provider, ids]) => [provider, uniqueStrings(ids)]),
);
}

export async function fetchSelectedModels(
apiBase: string,
fetchImpl: typeof fetch = fetch,
): Promise<ProviderModelMap> {
const response = await fetchImpl(`${apiBase}/api/selected-models`);
if (!response.ok) throw new Error(`selected models HTTP ${response.status}`);
return parseSelectedModels(await response.json());
}

export function modelIncluded(
selected: ProviderModelMap,
provider: string,
modelId: string,
native = false,
): boolean {
if (native) return true;
const allowlist = selected[provider];
return !allowlist || allowlist.length === 0 || allowlist.includes(modelId);
}

export function modelVisible(
selected: ProviderModelMap,
provider: string,
modelId: string,
native: boolean,
blocked: boolean,
): boolean {
return modelIncluded(selected, provider, modelId, native) && !blocked;
}

export async function putModelVisibility(
apiBase: string,
scope: ModelVisibilityScope,
provider: string,
targets: ModelVisibilityTarget[],
enabled: boolean,
fetchImpl: typeof fetch = fetch,
): Promise<Response> {
return fetchImpl(`${apiBase}/api/model-visibility`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ scope, provider, targets, enabled }),
});
}

export function shouldApplyLoadGeneration(request: number, current: number): boolean {
return request === current;
}
Loading
Loading