Skip to content
Merged
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs-site/src/content/docs/fr/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ ocx logout <provider>
| `cursor` | `cursor` | `https://api2.cursor.sh` | Connexion PKCE expérimentale, transport HTTP/2 en direct et découverte de modèles filtrés par compte. |
| `github-copilot` | `openai-chat` | `https://api.githubcopilot.com` | Expérimental. Flux d'appareil GitHub et échange `copilot_internal` (client OAuth de VS Code). Nécessite un abonnement Copilot actif ; il ne s'agit pas d'une API tierce officielle. |

Les vérifications de quota Google Antigravity utilisent des points de terminaison Google fixes, y compris le repli vers la liste des modèles. Elles prennent en charge le DNS Fake-IP transparent pour ces destinations en conservant la vérification TLS, le refus des redirections et les contrôles des adresses privées. Une URL de base personnalisée ne modifie que les requêtes de modèles ; `NO_PROXY` conserve la politique de connexion directe.


Après un échec définitif d'actualisation de Nous, exécutez `ocx login nous` pour vous réauthentifier.

Pour les préréglages canoniques du forfait Kimi Coding (`kimi` pour la connexion au compte et `kimi-code`
Expand Down
3 changes: 3 additions & 0 deletions docs-site/src/content/docs/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ ocx logout <provider>
| `cursor` | `cursor` | `https://api2.cursor.sh` | Experimental PKCE login, live HTTP/2 transport with an opt-in HTTP/1.1 compatibility path, and account-filtered model discovery. |
| `github-copilot` | `openai-chat` | `https://api.githubcopilot.com` | Experimental. GitHub device flow + `copilot_internal` exchange (VS Code OAuth client). Requires an active Copilot subscription; not an official third-party API. |

Google Antigravity account and provider quota probes use fixed Google accounting endpoints, including the models fallback. They support transparent Fake-IP DNS for those destinations while retaining TLS verification, redirect rejection and private-address checks. A custom provider base URL changes model requests, not quota destinations; `NO_PROXY` continues to select the direct-route policy.


After a terminal Nous refresh failure, run `ocx login nous` to reauthenticate.

For the canonical Kimi Coding Plan presets (`kimi` account login and `kimi-code` API key),
Expand Down
3 changes: 3 additions & 0 deletions docs-site/src/content/docs/ja/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ ocx logout <provider>
| `cursor` | `cursor` | `https://api2.cursor.sh` | 実験的 PKCE ログイン、HTTP/2 トランスポート、アカウント別モデル探索をサポート。 |
| `github-copilot` | `openai-chat` | `https://api.githubcopilot.com` | 実験的。GitHub デバイスフロー + `copilot_internal` 交換(VS Code OAuth クライアント)。有効な Copilot サブスクリプションが必要で、公式のサードパーティ API ではありません。 |

Google Antigravity のアカウント・プロバイダーのクォータ確認は、モデル一覧へのフォールバックも含め、固定の Google エンドポイントを使用します。その宛先では透過 Fake-IP DNS に対応し、TLS 検証、リダイレクト拒否、プライベートアドレス検査を維持します。カスタム base URL はモデル要求にのみ適用されます。`NO_PROXY` は直接接続のポリシーを維持します。


Nous の refresh が終端失敗した場合は、再認証に `ocx login nous` を実行してください。

正規の Kimi Coding Plan プリセット(`kimi` アカウントログインと `kimi-code` API key)では、
Expand Down
3 changes: 3 additions & 0 deletions docs-site/src/content/docs/ko/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ ocx logout <provider>
| `cursor` | `cursor` | `https://api2.cursor.sh` | 실험적 PKCE 로그인, HTTP/2 전송, 계정별 모델 탐색을 지원합니다. |
| `github-copilot` | `openai-chat` | `https://api.githubcopilot.com` | 실험적. GitHub 디바이스 플로우 + `copilot_internal` 교환(VS Code OAuth 클라이언트). 활성 Copilot 구독 필요; 공식 서드파티 API가 아닙니다. |

Google Antigravity 계정·제공자 할당량 확인은 모델 목록 폴백을 포함해 고정된 Google 회계 엔드포인트를 사용합니다. 해당 목적지의 투명 Fake-IP DNS를 지원하며 TLS 검증, 리다이렉트 거부, 사설 주소 검사는 유지합니다. 사용자 지정 base URL은 모델 요청에만 적용되며 할당량 목적지는 바꾸지 않습니다. `NO_PROXY`는 기존 직접 연결 정책을 유지합니다.


Nous refresh가 종료 실패한 경우, `ocx login nous`로 재인증하세요.

정식 Kimi Coding Plan 프리셋(`kimi` 계정 로그인과 `kimi-code` API key)의 경우, opencodex는
Expand Down
3 changes: 3 additions & 0 deletions docs-site/src/content/docs/ru/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ ocx logout <provider>
| `cursor` | `cursor` | `https://api2.cursor.sh` | Экспериментальный PKCE-вход, живой транспорт HTTP/2 и обнаружение моделей с фильтрацией по аккаунту. |
| `github-copilot` | `openai-chat` | `https://api.githubcopilot.com` | Экспериментально. Device flow GitHub + обмен `copilot_internal` (OAuth-клиент VS Code). Требуется активная подписка Copilot; это не официальный сторонний API. |

Проверки квот аккаунтов и провайдера Google Antigravity используют фиксированные адреса Google, включая резервный запрос списка моделей. Для этих адресов поддерживается прозрачный Fake-IP DNS с сохранением проверки TLS, запрета перенаправлений и проверки частных адресов. Пользовательский base URL меняет только запросы моделей; `NO_PROXY` сохраняет политику прямого подключения.


После терминального сбоя обновления Nous выполните `ocx login nous`, чтобы пройти повторную аутентификацию.

Для канонических пресетов Kimi Coding Plan (вход через аккаунт `kimi` и API-ключ `kimi-code`)
Expand Down
3 changes: 3 additions & 0 deletions docs-site/src/content/docs/tr/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ ocx logout <saglayici>
| `cursor` | `cursor` | `https://api2.cursor.sh` | Deneysel PKCE girişi, canlı HTTP/2 aktarımı ve hesap filtreli model keşfi. |
| `github-copilot` | `openai-chat` | `https://api.githubcopilot.com` | Deneysel. GitHub cihaz akışı + `copilot_internal` değişimi (VS Code OAuth istemcisi). Aktif bir Copilot aboneliği gerektirir; resmi bir üçüncü taraf API değildir. |

Google Antigravity hesap ve sağlayıcı kota sorguları, model listesine geri dönüş dahil sabit Google uç noktalarını kullanır. Bu hedefler için şeffaf Fake-IP DNS desteklenirken TLS doğrulaması, yönlendirme reddi ve özel adres kontrolleri korunur. Özel base URL yalnızca model isteklerini değiştirir; `NO_PROXY` doğrudan bağlantı politikasını korur.


Uç bir Nous yenileme hatasından sonra yeniden kimlik doğrulamak için `ocx login
nous` çalıştırın.

Expand Down
3 changes: 3 additions & 0 deletions docs-site/src/content/docs/zh-cn/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ ocx logout <provider>
| `cursor` | `cursor` | `https://api2.cursor.sh` | 实验性 PKCE 登录、带可选 HTTP/1.1 兼容路径的 HTTP/2 传输,以及按账号筛选的模型发现。 |
| `github-copilot` | `openai-chat` | `https://api.githubcopilot.com` | 实验性。GitHub 设备流 + `copilot_internal` 交换(VS Code OAuth 客户端)。需要有效的 Copilot 订阅;不是官方第三方 API。 |

Google Antigravity 账户和提供方的配额查询(包括模型列表回退)使用固定的 Google 计量端点。这些目标支持透明 Fake-IP DNS,同时保留 TLS 验证、重定向拒绝和私有地址检查。自定义 base URL 仅改变模型请求,不改变配额目标;`NO_PROXY` 仍使用直连策略。


Nous refresh 发生终止性失败后,请运行 `ocx login nous` 重新认证。

对于规范的 Kimi Coding Plan 预设(`kimi` 账号登录和 `kimi-code` API key),opencodex
Expand Down
3 changes: 3 additions & 0 deletions docs-site/src/content/docs/zh-tw/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ ocx logout <provider>
| `cursor` | `cursor` | `https://api2.cursor.sh` | 實驗性 PKCE 登入、即時 HTTP/2 transport 與按帳號篩選的模型探索。 |
| `github-copilot` | `openai-chat` | `https://api.githubcopilot.com` | 實驗性。GitHub device flow + `copilot_internal` exchange(VS Code OAuth client)。需要有效 Copilot 訂閱;不是官方第三方 API。 |

Google Antigravity 帳戶與供應商的配額查詢(包括模型清單備援)使用固定的 Google 計量端點。這些目標支援透明 Fake-IP DNS,同時保留 TLS 驗證、重新導向拒絕與私有位址檢查。自訂 base URL 只改變模型請求,不改變配額目標;`NO_PROXY` 仍使用直連政策。


終端 Nous refresh 失敗後,執行 `ocx login nous` 重新認證。

對 canonical Kimi Coding Plan preset(`kimi` 帳號登入與 `kimi-code` API key),opencodex 只會把 caller
Expand Down
64 changes: 57 additions & 7 deletions gui/src/components/QuotaBars.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,38 @@ export type QuotaBarRow = {
/**
* Window ordering is computed from RAW wire identities BEFORE localization
* (ranking on translated labels breaks the moment a locale changes copy):
* shorter windows first — 5h, weekly, cursor first-party, cursor API, monthly.
* shorter windows first — 5h, weekly, cursor first-party, cursor API, monthly,
* then subscription credits before other custom windows.
*/
function rawCustomWindowRank(rawLabel: string): number {
if (rawLabel === "5h") return 0;
if (rawLabel === "First-party models") return 2;
if (rawLabel === "API usage") return 3;
if (rawLabel === "Total subscription credits") return 4.5;
return 5;
}

const SUBSCRIPTION_CREDITS_LABEL = "Total subscription credits";

function canonicalCustomWindowLabel(rawLabel: string): string {
return rawLabel.trim().toLowerCase() === SUBSCRIPTION_CREDITS_LABEL.toLowerCase()
? SUBSCRIPTION_CREDITS_LABEL
: rawLabel;
}

/** Coverage metadata carries raw labels, while subscription rows use a canonical identity. */
export function isCustomQuotaWindowIncomplete(
customLabel: string | undefined,
incompleteLabels?: ReadonlySet<string>,
): boolean {
if (customLabel === undefined || !incompleteLabels) return false;
const canonical = canonicalCustomWindowLabel(customLabel);
for (const label of incompleteLabels) {
if (canonicalCustomWindowLabel(label) === canonical) return true;
}
return false;
}

function localizeCustomQuotaLabel(rawLabel: string, t: TFn): string {
switch (rawLabel) {
case "First-party models":
Expand Down Expand Up @@ -84,18 +107,37 @@ export function buildQuotaRows(quota: AccountQuota | null, plan: string | null |
});
}
for (const w of displayQuota.customWindows ?? []) {
const localized = localizeCustomQuotaLabel(w.label, t);
const customLabel = canonicalCustomWindowLabel(w.label);
const localized = localizeCustomQuotaLabel(customLabel, t);
ranked.push({
rank: rawCustomWindowRank(w.label),
rank: rawCustomWindowRank(customLabel),
row: {
customLabel: w.label,
customLabel,
label: localized,
limitLabel: localized,
percent: w.percent,
resetAt: w.resetAt,
},
});
}
if (displayQuota.creditsUsd && typeof displayQuota.creditsUsd.percent === "number") {
const hasSubscriptionCreditsCustom = displayQuota.customWindows?.some(
w => canonicalCustomWindowLabel(w.label) === SUBSCRIPTION_CREDITS_LABEL,
);
if (!hasSubscriptionCreditsCustom) {
const localized = localizeCustomQuotaLabel(SUBSCRIPTION_CREDITS_LABEL, t);
ranked.push({
rank: rawCustomWindowRank(SUBSCRIPTION_CREDITS_LABEL),
row: {
customLabel: SUBSCRIPTION_CREDITS_LABEL,
label: localized,
limitLabel: localized,
percent: displayQuota.creditsUsd.percent,
resetAt: displayQuota.creditsUsd.expiresAt,
},
});
}
}
return ranked.sort((a, b) => a.rank - b.rank).map(entry => entry.row);
}

Expand All @@ -107,6 +149,12 @@ export function maxQuotaUtilisation(quota: AccountQuota | null): number {
for (const w of quota.customWindows ?? []) {
if (typeof w.percent === "number") vals.push(w.percent);
}
const hasSubscriptionCreditsCustom = quota.customWindows?.some(
w => canonicalCustomWindowLabel(w.label) === SUBSCRIPTION_CREDITS_LABEL,
);
if (!hasSubscriptionCreditsCustom && typeof quota.creditsUsd?.percent === "number") {
vals.push(quota.creditsUsd.percent);
}
return vals.length ? Math.max(...vals) : -1;
}

Expand Down Expand Up @@ -279,7 +327,7 @@ export default function QuotaBars({
locale={locale}
incomplete={row.windowKey
? incompleteWindowKeys?.has(row.windowKey) === true
: row.customLabel !== undefined && incompleteCustomWindowLabels?.has(row.customLabel) === true}
: isCustomQuotaWindowIncomplete(row.customLabel, incompleteCustomWindowLabels)}
/>
))}
</div>
Expand All @@ -291,6 +339,7 @@ export default function QuotaBars({
{rows.map(row => (
<QuotaRow
key={row.label}
credits={row.customLabel === SUBSCRIPTION_CREDITS_LABEL}
label={row.label}
percent={row.percent}
resetAt={row.resetAt}
Expand All @@ -303,7 +352,8 @@ export default function QuotaBars({
);
}

function QuotaRow({ label, percent, resetAt, threshold, t, locale }: {
function QuotaRow({ credits, label, percent, resetAt, threshold, t, locale }: {
credits?: boolean;
label: string;
percent: number;
resetAt?: number;
Expand All @@ -320,7 +370,7 @@ function QuotaRow({ label, percent, resetAt, threshold, t, locale }: {
: undefined;
const hasReset = reset.day !== "" || reset.time !== "";
return (
<div className={`quota-row${warn ? " quota-row--warn" : ""}${exhausted ? " quota-row--exhausted" : ""}`}>
<div className={`quota-row${credits ? " quota-row--credits" : ""}${warn ? " quota-row--warn" : ""}${exhausted ? " quota-row--exhausted" : ""}`}>
<span className="quota-label" title={resetTitle}>{label}</span>
<span className="quota-reset-label">{hasReset ? t("codexAuth.resets") : ""}</span>
<span className="quota-reset-day">{reset.day}</span>
Expand Down
15 changes: 15 additions & 0 deletions gui/src/styles/provider-quota.css
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,18 @@
color: var(--amber);
font-size: 12px;
}

/* Long subscription labels and reset/value text need separate rows in narrow cards. */
.quota-compact { container: quota-compact / inline-size; }
@container quota-compact (max-width: 440px) {
.quota-row--credits {
grid-template-columns: max-content max-content minmax(0, 1fr) max-content;
row-gap: 4px;
}
.quota-row--credits .quota-label { grid-column: 1 / -1; grid-row: 1; }
.quota-row--credits .quota-reset-label { grid-column: 1; grid-row: 2; }
.quota-row--credits .quota-reset-day { grid-column: 2; grid-row: 2; }
.quota-row--credits .quota-reset-time { grid-column: 3 / -1; grid-row: 2; }
.quota-row--credits .bar { grid-column: 1 / 4; grid-row: 3; }
.quota-row--credits .quota-val { grid-column: 4; grid-row: 3; white-space: nowrap; }
}
Loading
Loading