Skip to content
Open
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
3 changes: 2 additions & 1 deletion docs-site/src/content/docs/fr/guides/web-dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ la connexion du compte appelant/principal. Les requêtes en cours conservent les
capturés. Une réauthentification 401/403 ou un temps de recharge 429 peut effacer l'affinité et faire passer
la route à un autre compte Pool admissible. Ce mécanisme est distinct d'`openai-apikey` et des autres fournisseurs.

- Choisir manuellement un compte s'applique immédiatement : un fil déjà associé y passe à sa prochaine requête, et seules les requêtes déjà en cours conservent le compte capturé. Le choix manuel est aussi épinglé : la fiche affiche le badge **ÉPINGLÉ**, et un ordre de sélection supérieur ne peut pas prendre la priorité sur ce compte avant son épuisement, la sélection d'un autre compte ou la modification de l'ordre de sélection de n'importe quel compte.
- Choisir manuellement un compte s'applique immédiatement : un fil déjà associé y passe à sa prochaine requête, et seules les requêtes déjà en cours conservent le compte capturé. Le choix manuel est aussi épinglé : la fiche affiche le badge **ÉPINGLÉ**, et un ordre de sélection supérieur ne peut pas prendre la priorité sur ce compte avant son épuisement, la sélection d'un autre compte ou la modification de l'ordre de sélection de n'importe quel compte. Sélectionner à nouveau le badge demande de confirmer la libération de l'épingle : une fois confirmée, la sélection est effacée, les fils déjà associés conservent le compte capturé, et les requêtes nouvelles ou sans association repassent à l'ordre de sélection et aux seuils.
Si le compte épinglé change pendant la confirmation, celle-ci ne peut pas libérer le nouveau compte épinglé. Après un refus ou un résultat incertain, la vue des comptes est actualisée ; vérifiez la sélection actuelle avant de confirmer à nouveau.
- Chaque fiche de compte possède un contrôle **Ordre de sélection** (**Premier**, **Plus tôt**, **Normal**, **Plus tard**, **Dernier**). Les ordres supérieurs sont utilisés en premier ; le pool ne descend à un ordre inférieur qu'une fois tous les comptes supérieurs épuisés ou indisponibles. Un changement d'ordre s'applique dès la prochaine requête sans association et ne déplace jamais un fil déjà associé. Le compte Codex Desktop principal est ordonné comme les autres : il peut être placé en **Dernier** et conservé comme réserve. Un ordre défini avec `ocx account priority` en dehors de ces cinq préréglages reste visible et sélectionnable sur la fiche.
- L'affinité des fils évite les changements à chaque requête. Avec `pool.cacheAffinity` activé (par défaut), un fil de longue durée n'est pas réassocié simplement parce que l'utilisation a atteint le seuil ; il reste jusqu'à ce que le compte soit épuisé ou ne puisse plus servir, puis seulement vers un compte dont l'utilisation est strictement inférieure et qui dispose d'une véritable marge de quota. Définissez le drapeau à `false` pour rétablir la réaffectation au seuil lorsqu'un compte admissible strictement moins utilisé existe.
- Les nouvelles sessions peuvent choisir le compte admissible le moins utilisé. Pour les forfaits payants, le score retient la fenêtre connue la plus sollicitée parmi 5 h, une semaine et 30 jours ; les forfaits Go/Free utilisent uniquement la fenêtre de 30 jours.
Expand Down
4 changes: 4 additions & 0 deletions docs-site/src/content/docs/guides/web-dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,10 @@ maintainers do not provide policy advice and cannot resolve provider enforcement
request, and only requests already in flight keep the account they captured. A manual choice is also
pinned: the card shows a **PINNED** badge, and a higher selection order cannot preempt that account
until it is drained, you select another account, or you change any account's selection order.
Selecting the badge again asks to release the pin: confirming clears the selection, bound threads
keep their captured account, and new or unbound requests return to the selection order and
thresholds.
If the pin changes while confirmation is open, that confirmation cannot release the newer pin. After a refused or uncertain release, the account view is refreshed; review the current selection before confirming again.
- Each account card carries a **Selection order** control (First, Earlier, Normal, Later, Last).
Higher order is used first, and the pool drops to a lower order only once every account above it is
drained or unavailable. A changed order applies from the next unbound request and never moves a
Expand Down
3 changes: 3 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 @@ -160,6 +160,9 @@ Codex タスクだけに適用され、このオプション自体が委任を
アカウントに移り、すでに送信中のリクエストだけが取得済みのアカウントを使い続けます。手動で選んだアカウントは固定もされます。
カードに **固定中** バッジが付き、そのアカウントが使い切られるか、別のアカウントを選ぶか、いずれかの
アカウントの選択順序を変更するまで、より上位の選択順序が割り込むことはありません。
バッジをもう一度選ぶと固定解除の確認が開き、確定すると選択がクリアされます。紐付いた thread は取得済みの
アカウントを使い続け、新規・未バインドのリクエストは選択順序としきい値による自動選択に戻ります。
確認画面を開いている間に固定アカウントが変わった場合、その確認で新しい固定は解除されません。解除が拒否された場合や結果が不明な場合はアカウント表示を更新し、現在の選択を確認してから再度確定してください。
- 各アカウントカードには **選択順序** のコントロール(最初 / 早め / 標準 / 遅め / 最後)があります。
順序が上のものから使われ、その上にあるアカウントがすべて使い切られるか利用できなくなって初めて
下の順序へ下がります。順序を変更すると **次の未バインドリクエスト** から適用され、すでにアカウントに
Expand Down
3 changes: 3 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 @@ -178,6 +178,9 @@ Dashboard의 **Sub-agent delegation** 선택기는 `injectionModel`과 선택적
옮겨가고, 이미 전송 중인 요청만 가져간 계정을 그대로 씁니다. 직접 고른 계정은 고정되기도 합니다. 카드에 **고정됨** 배지가
붙고, 그 계정이 소진되거나, 다른 계정을 고르거나, 어느 계정의 선택 순서를 바꿀 때까지 더 높은 선택
순서가 끼어들지 못합니다. 계정이 제외되거나 삭제되거나 명시적으로 failover/promotion 되면 고정도 함께 풀립니다.
배지를 다시 누르면 고정 해제 확인이 열리고, 확인하면 선택이 지워집니다. 바인딩된 thread는 가져간 계정을 그대로 쓰고,
새 요청과 바인딩 없는 요청은 선택 순서와 임계값에 따른 자동 선택으로 돌아갑니다.
확인 창이 열린 동안 고정된 계정이 바뀌면 그 확인으로 새 고정은 해제되지 않습니다. 해제가 거절되거나 결과가 불확실하면 계정 보기를 새로고침하므로, 현재 선택을 확인하고 다시 승인하세요.
- 각 계정 카드에는 **선택 순서** 컨트롤(가장 먼저 / 먼저 / 기본 / 나중에 / 가장 마지막)이 있습니다.
순서가 높은 계정부터 쓰이며, 그 위의 계정이 모두 소진되거나 사용할 수 없게 된 뒤에야 낮은 순서로
내려갑니다. 순서를 바꾸면 **다음 미바인딩 요청** 부터 적용되며, 이미 계정에 바인딩된 thread를 옮기지
Expand Down
4 changes: 4 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 @@ -165,6 +165,10 @@ loopback IP-адресу привязки сервера. Если панель
аккаунт, пока он не исчерпан, пока вы не выберете другой аккаунт или пока не измените порядок
выбора любого аккаунта. Закрепление также снимается при исключении или удалении аккаунта, а также
при явном failover/promotion.
Повторное нажатие на бейдж предлагает снять закрепление: после подтверждения выбор очищается,
привязанные потоки сохраняют свой аккаунт, а новые или непривязанные запросы снова следуют порядку
выбора и порогам.
Если закреплённый аккаунт изменился во время подтверждения, это подтверждение не снимет новое закрепление. После отказа или неопределённого результата список аккаунтов обновляется; проверьте текущий выбор перед новым подтверждением.
- На карточке каждого аккаунта есть элемент управления **Порядок выбора** (Первым, Раньше,
По умолчанию, Позже, Последним). Аккаунты с более высоким порядком используются раньше, а на более
низкий порядок пул опускается лишь тогда, когда все аккаунты выше исчерпаны или недоступны.
Expand Down
4 changes: 4 additions & 0 deletions docs-site/src/content/docs/tr/guides/web-dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ ve diğer sağlayıcılardan ayrıdır.
**PINNED** rozeti gösterir ve boşaltılana, başka bir hesap seçene kadar veya
herhangi bir hesabın seçim sırasını değiştirene kadar daha yüksek bir seçim
sırası bu hesabı öncelikleyemez.
Rozete yeniden tıklamak sabitlemeyi kaldırmak için onay ister. Onay seçim bilgisini temizler;
bağlı iş parçacıkları mevcut hesaplarını korur, yeni veya bağlanmamış istekler yeniden seçim
sırasını ve eşikleri izler.
Onay açıkken sabitlenen hesap değişirse bu onay yeni sabitlemeyi kaldıramaz. İşlem reddedilirse veya sonuç belirsizse hesap görünümü yenilenir; yeniden onaylamadan önce mevcut seçimi kontrol edin.
- Her hesap kartı bir **Seçim sırası (Selection order)** kontrolü taşır (İlk,
Daha Önce, Normal, Daha Sonra, Son). Daha yüksek sıra önce kullanılır ve havuz
ancak üzerindeki her hesap boşaldığında veya kullanılamaz olduğunda daha düşük
Expand Down
3 changes: 3 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 @@ -147,6 +147,9 @@ Pool 模式会在主账号和已添加的 Codex 账号之间选择;Direct 只
- 手动选择账号会立即生效:已经绑定账号的 thread 会在下一次请求时切换到所选账号,只有已经在传输中的
请求会继续使用它们捕获的账号。手动选择的账号还会被固定:卡片上会出现 **已固定** 徽章,在该账号被耗尽、你改选
其他账号,或你改动任意账号的选择顺序之前,更高的选择顺序都无法抢占它。
再次点击徽章会请求确认解除固定。确认后会清除选择,已绑定的 thread 保留其账号,
新建或未绑定的请求则恢复按选择顺序和阈值自动选择账号。
如果确认窗口打开期间固定账户发生变化,该确认不会解除新的固定。操作被拒绝或结果不确定后,账户视图会刷新;再次确认前请检查当前选择。
- 每张账号卡片都带有 **选择顺序** 控件(最先 / 较先 / 默认 / 较后 / 最后)。顺序靠前的账号先被使用,
只有当它上面的账号全部耗尽或不可用时才会降到更靠后的顺序。改动顺序会从**下一个未绑定请求**起生效,
且不会移动已经绑定的 thread。Codex Desktop(主)账号同样参与排序,可以设为 **最后** 留作备用。
Expand Down
7 changes: 5 additions & 2 deletions docs-site/src/content/docs/zh-tw/guides/web-dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,11 @@ Dashboard 的 **Sub-agent delegation** 選擇器會儲存 `injectionModel`,以

**Codex Auth** 頁面用於管理原生 ChatGPT/Codex 路由:

- 手動選擇帳號會影響下一次新建的 Codex session;已經繫結帳號的 thread 不會因為這次手動切換而
在中途轉移。
- 手動選擇帳號會立即生效:已經繫結帳號的 thread 會在下一次請求時切換到所選帳號,
只有進行中的請求會保留已取得的帳號。手動選擇會固定該帳號,卡片上會顯示**已固定**徽章。
再次點選徽章會要求確認解除固定。確認後會清除選擇,已繫結的 thread 保留其帳號,
新建或未繫結的請求則恢復依選擇順序與閾值自動選擇帳號。
如果確認視窗開啟期間固定帳戶發生變化,該確認不會解除新的固定。操作遭拒或結果不確定後,帳戶檢視會重新整理;再次確認前請檢查目前選擇。
- Thread affinity 可避免每個請求都來回切換帳號。預設開啟 `pool.cacheAffinity` 後,長時間執行的
thread 不會只因 usage 達到閾值就重新繫結;只有帳號耗盡或無法繼續服務時才會離開,並且只重新繫結到
確有額度餘裕且使用率確實更低的帳號。關閉該設定後,才會在存在使用率確實更低且確有額度餘裕的
Expand Down
33 changes: 33 additions & 0 deletions gui/src/components/CodexAccountPool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ export default function CodexAccountPool({ apiBase, accountModeState = null, ban
|| mainReauth.state.phase === "pending"
|| mainReauth.state.phase === "committing";
const [confirm, setConfirm] = useState<CodexAccountEntry | null>(null);
// The pinned card whose badge was selected again: the release goes through the same
// /active write as a switch, just with a null id, which the server reads as unpin.
const [unpinFor, setUnpinFor] = useState<CodexAccountEntry | null>(null);
const [showAdd, setShowAdd] = useState(false);
const [modelsNotice, setModelsNotice] = useState<{ catalogRefreshPending: boolean } | null>(null);
const [advancedOpen, setAdvancedOpen] = useState(false);
Expand Down Expand Up @@ -252,6 +255,21 @@ export default function CodexAccountPool({ apiBase, accountModeState = null, ban
: t("codexAuth.switched", { email: label }));
};

const unpinAccount = async () => {
if (!unpinFor) return;
const result = await controller.switchAccount(null, { expectedPinnedAccountId: unpinFor.id });
if (!result.ok) {
if (result.reason === "busy") return;
// The confirmation described an old pin, or the saved result is uncertain.
// A fresh attempt must start from the refreshed card and a new confirmation.
setUnpinFor(null);
showActionFeedback(t(result.reason === "pin_changed" ? "codexAuth.unpinChanged" : "codexAuth.unpinFailed"), "err");
return;
}
setUnpinFor(null);
showActionFeedback(t("codexAuth.unpinned"), "ok");
};

const editAlias = async (account: CodexAccountEntry) => {
const entered = await requestTextValue({
message: t("prov.aliasPrompt"),
Expand Down Expand Up @@ -543,6 +561,7 @@ export default function CodexAccountPool({ apiBase, accountModeState = null, ban
threshold={autoSwitchThreshold}
switchActionLabel={switchActionLabel}
onSwitch={setConfirm}
onUnpin={setUnpinFor}
onTogglePause={togglePaused}
pauseUpdatingId={pauseUpdatingId}
pauseBusy={pauseBusy}
Expand Down Expand Up @@ -591,6 +610,7 @@ export default function CodexAccountPool({ apiBase, accountModeState = null, ban
threshold={autoSwitchThreshold}
onOpenReset={openResetPopup}
onSwitch={setConfirm}
onUnpin={setUnpinFor}
onTogglePause={togglePaused}
pauseUpdatingId={pauseUpdatingId}
pauseBusy={pauseBusy}
Expand Down Expand Up @@ -676,6 +696,19 @@ export default function CodexAccountPool({ apiBase, accountModeState = null, ban
/>
)}

{unpinFor && (
<CodexAccountSwitchModal
unpin
confirm={unpinFor}
mainEmail={main?.email}
accountModeState={accountModeState}
switchingId={switchingId}
orderBusy={priorityUpdatingId !== null}
onCancel={() => setUnpinFor(null)}
onConfirm={() => { void unpinAccount(); }}
/>
)}

{resetPopup && (
<CodexAccountResetModal
resetPopup={resetPopup}
Expand Down
7 changes: 5 additions & 2 deletions gui/src/components/codex-account-pool-cards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type { CodexAccountEntry } from "./codex-account-pool-types";
import type { CodexAccountModeState } from "../codex-multi-state";
import QuotaBars from "./QuotaBars";
import CodexCreditsRow from "./CodexCreditsRow";
import { CodexPauseToggleLabel, CodexTicketBadge } from "./codex-account-pool-helpers";
import { CodexPauseToggleLabel, CodexPinnedBadge, CodexTicketBadge } from "./codex-account-pool-helpers";
import {
doctorCopyButtonLabel,
formatOAuthHealthLabel,
Expand Down Expand Up @@ -41,6 +41,7 @@ export function CodexAccountPoolCards({
autoSwitchDisabled,
switchingId,
pinnedId = null,
onUnpin,
onReauth,
onEditAlias,
onRemove,
Expand Down Expand Up @@ -74,6 +75,8 @@ export function CodexAccountPoolCards({
* badge on the account the operator actually chose.
*/
pinnedId?: string | null;
/** Opens the release confirm for the pinned card: selecting the badge again unpins. */
onUnpin: (account: CodexAccountEntry) => void;
onReauth: (id: string) => void;
onEditAlias: (account: CodexAccountEntry) => void;
onRemove: (id: string) => void;
Expand Down Expand Up @@ -121,7 +124,7 @@ export function CodexAccountPoolCards({
)}
<AccountPriorityBadge value={a.priority} />
<CreditsOnBadge enabled={a.creditsAfterLimit} />
{a.id === pinnedId && !a.paused && <span className="badge badge-muted">{t("codexAuth.pinned")}</span>}
{a.id === pinnedId && !a.paused && <CodexPinnedBadge t={t} onUnpin={() => onUnpin(a)} />}
<CodexTicketBadge t={t} account={a} onClick={() => onOpenReset(a)} />
{healthLabel && (
<span className={oauthHealthBadgeClass(healthStatus)}>{healthLabel}</span>
Expand Down
18 changes: 18 additions & 0 deletions gui/src/components/codex-account-pool-helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@ export function CodexCreditItem({ index, grantedAt, expiresAt, isNext, locale, t
);
}

/**
* The pin marker is the release affordance too: selecting it again asks the operator to
* confirm dropping the manual selection, which the server resolves as an unpin back to
* automatic selection. Kept as a badge-button like the reset-credit one above.
*/
export function CodexPinnedBadge({ t, onUnpin }: { t: TFn; onUnpin: () => void }) {
return (
<button type="button"
className="badge badge-muted badge-clickable"
onClick={(e) => { e.stopPropagation(); onUnpin(); }}
title={`${t("codexAuth.pinnedHint")} ${t("codexAuth.unpinHint")}`}
aria-label={`${t("codexAuth.pinned")} — ${t("codexAuth.unpinHint")}`}
>
{t("codexAuth.pinned")}
</button>
);
}

export function CodexTicketBadge({ account, onClick, t }: { account: CodexAccountEntry; onClick: () => void; t: TFn }) {
const credits = account.quota?.resetCredits;
// Reserve badge width while WHAM quota is still null so the card-head does not grow
Expand Down
Loading
Loading