diff --git a/docs-site/src/content/docs/fr/guides/claude-code.md b/docs-site/src/content/docs/fr/guides/claude-code.md index 8a5ccf79b2..671c22c233 100644 --- a/docs-site/src/content/docs/fr/guides/claude-code.md +++ b/docs-site/src/content/docs/fr/guides/claude-code.md @@ -15,7 +15,8 @@ ajouter un compte). Par défaut, chaque requête utilise uniquement le compte ** Un groupe de comptes Claude **expérimental et facultatif** (`anthropicAccountPool.enabled`) ajoute l'affinité de session et le basculement en cas de délai de récupération 429 entre ces comptes OAuth. Pour les **nouvelles** sessions uniquement, `anthropicAccountPool.strategy` sélectionne un compte éligible : `quota` (par défaut) -choisit la plus faible utilisation connue sur 5 heures lorsqu'elle dépasse `autoSwitchThreshold` ; `round-robin` +choisit la plus faible utilisation connue dans la fenêtre configurée par `anthropicAccountPool.quotaWindow` +(`five-hour` par défaut, `weekly` ou `max-utilization`) lorsqu'elle dépasse `autoSwitchThreshold` ; `round-robin` répartit les sessions uniformément (`stickyLimit`, `1` par défaut) ; `fill-first` utilise le compte actif jusqu'à un délai de récupération, une réauthentification ou le seuil, puis passe au suivant. Cette fonction est **désactivée par défaut**, affiche un avertissement dans l'interface et n'a pas été éprouvée en production. @@ -31,6 +32,9 @@ Comportement lorsque cette option est activée : sélection jusqu'à sa réauthentification. - Si chaque compte éligible est en temporisation, le proxy renvoie **429** (et non 401) avec `Retry-After` lorsqu'il est connu. +- La récupération, y compris le basculement 429, utilise `quotaWindow` pour classer les comptes de + remplacement admissibles, sans modifier les limites existantes de temporisation ou de basculement ; + `round-robin` ignore `quotaWindow`. Voir [Configuration](/fr/reference/configuration/providers/#anthropicaccountpool-expérimental). diff --git a/docs-site/src/content/docs/fr/reference/configuration/providers.md b/docs-site/src/content/docs/fr/reference/configuration/providers.md index 47029ee45b..f02c66defc 100644 --- a/docs-site/src/content/docs/fr/reference/configuration/providers.md +++ b/docs-site/src/content/docs/fr/reference/configuration/providers.md @@ -193,8 +193,9 @@ rotation automatique peut déclencher des restrictions du fournisseur. | Clé | Type | Par défaut | Description | | --- | --- | --- | --- | | `anthropicAccountPool.enabled?` | `boolean` | `false` | Active l'affinité persistante et le basculement après une temporisation 429. | -| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | Pour les nouvelles sessions, choisir la plus faible utilisation connue et mise en cache sur 5 heures qui atteint ou dépasse ce seuil. `0` désactive la sélection selon le quota. | -| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | Stratégie des nouvelles sessions ; quota utilise uniquement les barres sur 5 heures. | +| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | Pour les nouvelles sessions, lorsque le compte actif atteint ce seuil, choisir la plus faible utilisation connue et mise en cache dans la fenêtre configurée. `0` désactive la sélection selon le quota. | +| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | Stratégie des nouvelles sessions ; `quota` classe les comptes selon la fenêtre définie par `quotaWindow`, par défaut les barres sur 5 heures, et `fill-first` évalue son seuil d'évacuation dans cette même fenêtre. | +| `anthropicAccountPool.quotaWindow?` | `"five-hour" \| "weekly" \| "max-utilization"` | `"five-hour"` | Barre d'utilisation signalée par le fournisseur, mise en cache et utilisée pour la sélection selon l'utilisation. `five-hour` conserve le comportement actuel. `weekly` utilise la barre hebdomadaire et ignore les comptes dont la barre sur 5 heures est épuisée tant qu'un autre compte admissible reste disponible, mais y revient si aucun autre ne reste. `max-utilization` utilise la valeur connue la plus élevée et peut donc employer la barre sur 5 heures avant que la barre hebdomadaire soit disponible ; si aucune n'est connue, le compte suit l'ordre des utilisations inconnues. Les utilisations connues précèdent les inconnues, mais si tous les comptes admissibles sont inconnus, la sélection en renvoie tout de même un dans leur ordre admissible. Après le départage documenté par la plus faible utilisation sur 5 heures, une égalité exacte conserve cet ordre. Une session saine avec affinité n'est pas rééquilibrée de manière proactive. Pour l'affectation des nouvelles sessions et la reprise du routage après un remplacement admissible à la suite d'un 429, `quota` classe directement les candidats admissibles avec cette fenêtre ; `fill-first` avance dans un ordre stable selon le seuil et les règles d'épuisement de cette fenêtre ; `round-robin` l'ignore. Le délai de récupération, les limites de basculement et l'éligibilité de réauthentification restent des états locaux distincts. Les barres hebdomadaires ne sont connues qu'après leur interrogation dans la page Fournisseurs du tableau de bord. | | `anthropicAccountPool.stickyLimit?` | `number` | `1` | Liaisons de nouvelle session réussies conservées sur une sélection à tour de rôle. Portée 1–100. | Lorsque cette option est activée, un 429 enregistre une temporisation bornée à partir de `Retry-After` ou d'un délai de repli, puis peut diff --git a/docs-site/src/content/docs/guides/claude-code.md b/docs-site/src/content/docs/guides/claude-code.md index 07f989ef5f..d991c3a889 100644 --- a/docs-site/src/content/docs/guides/claude-code.md +++ b/docs-site/src/content/docs/guides/claude-code.md @@ -13,9 +13,10 @@ You can log in multiple Claude accounts via the Providers dashboard (`ocx login add-account). By default every request uses the **active** account only. An **experimental, opt-in** Claude account pool (`anthropicAccountPool.enabled`) adds sticky -session affinity and 429 cooldown failover across those OAuth accounts. For **new** sessions -only, `anthropicAccountPool.strategy` selects among eligible accounts: `quota` (default) picks -lowest known 5-hour usage when above `autoSwitchThreshold`; `round-robin` spreads evenly +session affinity and 429 cooldown failover across those OAuth accounts. For **new** sessions, +`anthropicAccountPool.strategy` selects among eligible accounts: `quota` (default) picks the +lowest known usage in the window set by `quotaWindow` (`five-hour` by default, or `weekly` / +`max-utilization`) when above `autoSwitchThreshold`; `round-robin` spreads evenly (`stickyLimit`, default `1`); `fill-first` drains the active account until cooldown, reauthentication, or threshold, then advances. It is **off by default**, shows a GUI warning, and is not battle-tested — Anthropic may restrict accounts that look like automated rotation; @@ -31,6 +32,11 @@ Operational contract when enabled: selection until re-authenticated. - If every eligible account is cooling, the proxy returns **429** (not 401) with `Retry-After` when known. +- Recovery, including 429 failover, uses `quotaWindow` to rank eligible replacements without + changing the existing cooldown or failover limits; `round-robin` ignores `quotaWindow`. +- `autoSwitchThreshold: 0` turns off **proactive** usage-based switching only. New-session + selection and 429 recovery still consult `quotaWindow`, so the window is inert only under + `round-robin`. `fill-first` evaluates its drain threshold in the selected window. See [Configuration](/reference/configuration/#anthropicaccountpool-experimental). diff --git a/docs-site/src/content/docs/ja/reference/configuration/providers.md b/docs-site/src/content/docs/ja/reference/configuration/providers.md index b51e8a2e32..7bc1a00ba8 100644 --- a/docs-site/src/content/docs/ja/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ja/reference/configuration/providers.md @@ -159,8 +159,9 @@ affinity を維持します。これらの戦略は provider enforcement を回 |キー |タイプ |デフォルト |説明 | | --- | --- | --- | --- | | `anthropicAccountPool.enabled?` | `boolean` | `false` |スティッキー アフィニティと 429 クールダウン フェイルオーバーを有効にします。 | -| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` |新しいセッションの場合は、このしきい値以上の、既知の最も低いキャッシュされた 5 時間の使用量を選択します。 `0` はクォータの選択を無効にします。 | -| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` |新しいセッション戦略。クォータでは 5 時間足のみを使用します。 | +| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` |新しいセッションでは、アクティブなアカウントがこのしきい値に達すると、設定した期間で既知のキャッシュ使用量が最も低いアカウントを選択します。 `0` はクォータ選択を無効にします。 | +| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` |新しいセッション戦略。`quota` は `quotaWindow` で指定した期間(既定は 5 時間足)でアカウントを順位付けし、`fill-first` も同じ期間で使い切りのしきい値を判定します。 | +| `anthropicAccountPool.quotaWindow?` | `"five-hour" \| "weekly" \| "max-utilization"` | `"five-hour"` |使用量ベースのアカウント選択で使う、プロバイダー報告のキャッシュ済み使用率です。`five-hour` は従来の動作を維持します。`weekly` は週次使用量を使い、他に対象アカウントが残る間だけ 5 時間使用量が上限に達したアカウントを除外し、残らない場合はそれらへフォールバックします。`max-utilization` は判明している値のうち最も高いものを使うため、週次使用量が未取得でも 5 時間使用量を利用できます。どちらも不明なら unknown の順位付けに従います。既知の使用量は unknown より先ですが、対象がすべて unknown でも対象順の先頭を選択します。記載した 5 時間使用量による同点判定後も完全に同点なら、対象順を維持します。正常な affinity セッションを先回りして再配置することはありません。新規セッションの割り当てと、対象となる 429 代替後のルーティング復旧では、`quota` はこの期間で対象候補を直接順位付けし、`fill-first` はこの期間のしきい値と上限到達ルールを使って安定順に進み、`round-robin` はこの設定を無視します。クールダウン、フェイルオーバー上限、再認証の適格性は別のローカル状態です。アカウント別の週次使用量は、ダッシュボードのプロバイダーページで取得した後にのみ利用できます。 | | `anthropicAccountPool.stickyLimit?` | `number` | `1` |成功した新しいセッションのバインドは 1 つのラウンドロビン選択で保持されます。範囲は 1 ~ 100。 | 有効にすると、429 レコードは `Retry-After` またはデフォルトのバックオフからの制限されたクールダウンを記録し、リクエスト内でローテーションする可能性があります。アフィニティはプロセスローカルであり、サイズ制限があります。資格情報 401/403 は、アカウントに再認証が必要であることをマークします。すべての対象となるアカウントが冷却されている場合、クライアントは、既知の場合、認証エラーではなく、`Retry-After` を含む 429 を受け取ります。 diff --git a/docs-site/src/content/docs/ko/reference/configuration/providers.md b/docs-site/src/content/docs/ko/reference/configuration/providers.md index b9eb746726..d7f92d08bb 100644 --- a/docs-site/src/content/docs/ko/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ko/reference/configuration/providers.md @@ -163,8 +163,9 @@ affinity 초기화 뒤의 기존 작업도 포함될 수 있습니다. 출력 | 키 | 타입 | 기본값 | 설명 | | --- | --- | --- | --- | | `anthropicAccountPool.enabled?` | `boolean` | `false` | sticky 결속과 429 쿨다운 failover를 켭니다. | -| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | 새 세션에서는 이 임계값 이상에서 알려진 캐시 5시간 사용량이 가장 낮은 계정을 고릅니다. `0`이면 quota 선택을 끕니다. | -| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | 새 세션 전략입니다. quota는 5시간 막대만 사용합니다. | +| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | 새 세션에서는 활성 계정이 이 임계값에 도달하면 설정된 창의 알려진 캐시 사용량이 가장 낮은 계정을 고릅니다. `0`이면 quota 선택을 끕니다. | +| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | 새 세션 전략입니다. `quota`는 `quotaWindow`로 지정한 창(기본값은 5시간 막대)으로 계정 순위를 매기고, `fill-first`도 같은 창에서 소진 임계값을 판정합니다. | +| `anthropicAccountPool.quotaWindow?` | `"five-hour" \| "weekly" \| "max-utilization"` | `"five-hour"` | 사용량 기반 계정 선택에 사용하는, 공급자가 보고한 캐시 사용률 막대입니다. `five-hour`는 기존 동작을 유지합니다. `weekly`는 주간 막대를 사용하며 다른 사용 가능한 계정이 남아 있을 때만 5시간 막대가 소진된 계정을 건너뛰고, 아무 계정도 남지 않으면 해당 계정으로 폴백합니다. `max-utilization`은 알려진 값 중 가장 높은 값을 사용하므로 주간 사용량을 알기 전에도 5시간 사용량을 쓸 수 있고, 둘 다 모르면 unknown 순서를 따릅니다. 알려진 사용량은 unknown보다 앞서지만, 사용 가능한 계정이 모두 unknown이어도 사용 가능한 순서의 계정을 선택합니다. 앞서 설명한 5시간 사용량 동점 판정 뒤에도 완전히 같으면 사용 가능한 순서를 유지합니다. 정상 affinity 세션을 선제적으로 재배치하지 않습니다. 새 세션 배정과 가능한 429 대체 이후 라우팅 복구에서 `quota`는 이 창으로 사용 가능한 후보의 순위를 직접 매기고, `fill-first`는 이 창의 임계값과 소진 규칙에 따라 안정 순서로 이동하며, `round-robin`은 이 설정을 무시합니다. 쿨다운, failover 한도, 재인증 가능 여부는 별도의 로컬 상태로 유지됩니다. 계정별 주간 막대는 대시보드의 프로바이더 페이지에서 조회한 뒤에만 알 수 있습니다. | | `anthropicAccountPool.stickyLimit?` | `number` | `1` | 성공한 새 세션 결속이 한 번의 라운드로빈 선택에 유지되는 횟수입니다. 범위는 1–100입니다. | 활성화되면 429 레코드가 `Retry-After` 또는 기본 backoff에서 제한된 쿨다운을 기록하고, 요청 안에서 회전할 수 있습니다. 결속은 프로세스 로컬이며 크기가 제한됩니다. 자격 증명 401/403은 해당 계정이 재인증이 필요함을 표시합니다. 적격한 계정이 모두 쿨다운 중이면, 클라이언트는 인증 오류가 아니라 알려진 경우 `Retry-After`가 포함된 429를 받습니다. diff --git a/docs-site/src/content/docs/reference/configuration/providers.md b/docs-site/src/content/docs/reference/configuration/providers.md index 8840acf900..11a6e9c256 100644 --- a/docs-site/src/content/docs/reference/configuration/providers.md +++ b/docs-site/src/content/docs/reference/configuration/providers.md @@ -283,8 +283,9 @@ rotation may trigger provider restrictions. | Key | Type | Default | Description | | --- | --- | --- | --- | | `anthropicAccountPool.enabled?` | `boolean` | `false` | Enable sticky affinity and 429 cooldown failover. | -| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | For new sessions, choose the lowest known cached 5-hour usage at or above this threshold. `0` disables quota picking. | -| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | New-session strategy; quota uses 5-hour bars only. | +| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | For new sessions, when the active account reaches this threshold, choose the lowest known cached usage in the configured window; the account chosen does not itself have to be at or above the threshold. `0` disables **proactive** usage-based switching only — new-session selection and routing recovery after an eligible 429 still consult `quotaWindow`. | +| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | New-session strategy; `quota` ranks accounts by the window set by `quotaWindow`, and `fill-first` evaluates its drain threshold in that same window. | +| `anthropicAccountPool.quotaWindow?` | `"five-hour" \| "weekly" \| "max-utilization"` | `"five-hour"` | The cached provider-reported utilization bar used for usage-aware account selection. `five-hour` keeps the original behavior. `weekly` scores the weekly bar and skips accounts whose 5-hour bar is exhausted while another eligible account remains, but falls back to exhausted candidates when none do. `max-utilization` scores the highest known bar, so it can use 5-hour usage before weekly usage is available; if neither is known, the account follows unknown-usage ordering. Known usage ranks before unknown usage under the opt-in `weekly` and `max-utilization` windows only; an omitted or explicit `five-hour` preserves the legacy ordering. If every eligible account is unknown, selection still returns one in eligible order. After the documented lower-5-hour tie-break, exact ties preserve eligible order. A healthy affinity-bound session is not proactively rebalanced. For new-session assignment and routing recovery after an eligible 429 replacement, `quota` ranks eligible candidates directly with this window; `fill-first` advances in stable order using this window's threshold and exhaustion rules; `round-robin` ignores it. Cooldown, failover limits, and reauthentication eligibility remain separate local state. Per-account weekly bars are only known once the dashboard Providers page has polled them. | | `anthropicAccountPool.stickyLimit?` | `number` | `1` | Successful new-session binds retained on one round-robin selection. Range 1–100. | When enabled, 429 records bounded cooldown from `Retry-After` or a default backoff and may rotate diff --git a/docs-site/src/content/docs/ru/reference/configuration/providers.md b/docs-site/src/content/docs/ru/reference/configuration/providers.md index 94334dae06..4714edee39 100644 --- a/docs-site/src/content/docs/ru/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ru/reference/configuration/providers.md @@ -194,8 +194,9 @@ reauth или порога исчерпания; здоровые привяза | Ключ | Тип | По умолчанию | Описание | | --- | --- | --- | --- | | `anthropicAccountPool.enabled?` | `boolean` | `false` | Включить sticky affinity и cooldown failover на 429. | -| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | Для новых сессий выбирать аккаунт с наименьшим известным cached 5-hour usage, если активный аккаунт достиг порога. `0` отключает выбор по quota. | -| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | Стратегия для новых сессий; quota смотрит только на 5-hour bar'ы. | +| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | Для новых сессий выбирать аккаунт с наименьшим известным cached usage в настроенном окне, если активный аккаунт достиг порога. `0` отключает выбор по quota. | +| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | Стратегия для новых сессий; `quota` ранжирует аккаунты по окну, заданному в `quotaWindow` (по умолчанию это 5-hour bar'ы), а `fill-first` в этом же окне оценивает свой порог исчерпания. | +| `anthropicAccountPool.quotaWindow?` | `"five-hour" \| "weekly" \| "max-utilization"` | `"five-hour"` | Кешированная полоса использования, сообщённая провайдером и применяемая при выборе по использованию. `five-hour` сохраняет прежнее поведение. `weekly` использует недельный bar и пропускает аккаунты с исчерпанным 5-hour bar, пока остаётся другой доступный аккаунт, но возвращается к ним, если других нет. `max-utilization` использует наибольшее известное значение, поэтому до появления недельных данных может использовать 5-hour usage; если неизвестны оба значения, аккаунт следует порядку unknown usage. Известное использование ранжируется раньше unknown, но если у всех доступных аккаунтов оно неизвестно, выбирается аккаунт в доступном порядке. После описанного сравнения по меньшему значению 5-hour usage полное равенство также сохраняет этот порядок. Здоровая сессия с affinity не перебалансируется заранее. При назначении новой сессии и восстановлении маршрутизации после допустимой замены при 429 `quota` напрямую ранжирует доступных кандидатов по этому окну, `fill-first` идёт в стабильном порядке с учётом порога и правил исчерпания этого окна, а `round-robin` игнорирует настройку. Cooldown, лимиты failover и допустимость повторной аутентификации остаются отдельным локальным состоянием. Недельные bar'ы аккаунтов известны только после опроса на странице Providers в dashboard. | | `anthropicAccountPool.stickyLimit?` | `number` | `1` | Сколько успешных bind'ов новых сессий удерживать на одном выборе round-robin. Диапазон 1–100. | Если функция включена, 429 записывает ограниченный cooldown из `Retry-After` или из default diff --git a/docs-site/src/content/docs/tr/guides/claude-code.md b/docs-site/src/content/docs/tr/guides/claude-code.md index e335bea33e..1fe4fd0393 100644 --- a/docs-site/src/content/docs/tr/guides/claude-code.md +++ b/docs-site/src/content/docs/tr/guides/claude-code.md @@ -19,7 +19,8 @@ fazla Claude hesabına giriş yapabilirsiniz. Varsayılan olarak her istek yaln bağlılığı ve 429 bekleme süresi (cooldown) yük devretmesi ekler. Yalnızca **yeni** oturumlar için `anthropicAccountPool.strategy` uygun hesaplar arasından seçim yapar: `quota` (varsayılan), `autoSwitchThreshold` üzerinde olduğunda -bilinen en düşük 5 saatlik kullanımı seçer; `round-robin` eşit olarak dağıtır +`anthropicAccountPool.quotaWindow` ile yapılandırılan penceredeki bilinen en düşük kullanımı +seçer (`five-hour` varsayılandır; `weekly` ve `max-utilization` da kullanılabilir); `round-robin` eşit olarak dağıtır (`stickyLimit`, varsayılan `1`); `fill-first`, bekleme süresi, yeniden kimlik doğrulama veya eşiğe kadar aktif hesabı tüketir, ardından ilerler. **Varsayılan olarak kapalıdır**, bir GUI uyarısı gösterir ve sahada kapsamlı olarak test @@ -37,6 +38,9 @@ Etkinleştirildiğinde operasyonel sözleşme: böylece yeniden kimlik doğrulanana kadar seçimden hariç tutulur. - Uygun tüm hesaplar soğutuluyorsa, proxy bilindiğinde `Retry-After` ile birlikte **429** (401 değil) döndürür. +- 429 yük devretmesi dahil kurtarma, mevcut soğuma ve yük devretme sınırlarını + değiştirmeden uygun yedek hesapları sıralamak için `quotaWindow` kullanır; + `round-robin` ise `quotaWindow` ayarını yok sayar. Bkz. [Yapılandırma](/tr/reference/configuration/#anthropicaccountpool-experimental). @@ -607,4 +611,3 @@ modellerde opencodex varsayılan olarak bunu taslakla değiştirir (`blockedSkil aracının `model` argümanını değil, `` yönergelerini kullanır. Yönergenin hedeflenen rotayla eşleştiğinden emin olun. Model yer tutucusu olarak `"haiku"` iletin. - diff --git a/docs-site/src/content/docs/tr/reference/configuration/providers.md b/docs-site/src/content/docs/tr/reference/configuration/providers.md index e4f5497f8c..ee05f61387 100644 --- a/docs-site/src/content/docs/tr/reference/configuration/providers.md +++ b/docs-site/src/content/docs/tr/reference/configuration/providers.md @@ -219,8 +219,9 @@ ve otomatik rotasyon sağlayıcı kısıtlamalarını tetikleyebilir. | Anahtar | Tip | Varsayılan | Açıklama | | --- | --- | --- | --- | | `anthropicAccountPool.enabled?` | `boolean` | `false` | Yapışkan bağlılığı ve 429 soğuma yük devretmesini etkinleştirin. | -| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | Yeni oturumlar için bu eşikte veya üzerinde bilinen en düşük önbelleğe alınmış 5 saatlik kullanımı seçin. `0` kota seçimini devre dışı bırakır. | -| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | Yeni oturum stratejisi; kota yalnızca 5 saatlik çubukları kullanır. | +| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | Yeni oturumlarda etkin hesap bu eşiğe ulaştığında, yapılandırılan penceredeki bilinen en düşük önbelleğe alınmış kullanımı seçin. `0` kota seçimini devre dışı bırakır. | +| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | Yeni oturum stratejisi; `quota`, `quotaWindow` ile belirlenen pencereye (varsayılan 5 saatlik çubuklar) göre hesapları sıralar ve `fill-first` de tükenme eşiğini aynı pencerede değerlendirir. | +| `anthropicAccountPool.quotaWindow?` | `"five-hour" \| "weekly" \| "max-utilization"` | `"five-hour"` | Kullanıma dayalı hesap seçiminde kullanılan, sağlayıcının bildirdiği önbelleğe alınmış kullanım çubuğu. `five-hour` mevcut davranışı korur. `weekly` haftalık çubuğu kullanır ve başka uygun hesap kaldığı sürece 5 saatlik çubuğu tükenmiş hesapları atlar; hiçbiri kalmazsa bu hesaplara geri döner. `max-utilization` bilinen en yüksek değeri kullanır; haftalık değer henüz yokken 5 saatlik değeri kullanabilir, ikisi de bilinmiyorsa hesap unknown kullanım sırasını izler. Bilinen kullanım unknown değerlerden önce gelir; tüm uygun hesaplar unknown olsa bile uygun sıradaki bir hesap seçilir. Belgelenen daha düşük 5 saatlik kullanım eşitlik bozmasından sonra tam eşitlikte de uygun sıra korunur. Sağlıklı affinity oturumları önceden yeniden dengelenmez. Yeni oturum ataması ve uygun bir 429 yedeğine geçildikten sonraki yönlendirme kurtarmasında `quota`, uygun adayları doğrudan bu pencereye göre sıralar; `fill-first`, bu pencerenin eşik ve tükenme kurallarıyla kararlı sırada ilerler; `round-robin` ayarı yok sayar. Cooldown, yük devretme sınırları ve yeniden kimlik doğrulama uygunluğu ayrı yerel durum olarak kalır. Hesap başına haftalık çubuklar ancak dashboard Sağlayıcılar sayfasında sorgulandıktan sonra bilinir. | | `anthropicAccountPool.stickyLimit?` | `number` | `1` | Bir round-robin seçiminde tutulan başarılı yeni oturum bağlamaları. Aralık 1–100. | Etkinleştirildiğinde 429, `Retry-After`'dan veya varsayılan bir geri çekilmeden @@ -479,4 +480,3 @@ bildirir; senkronize edilen katalog `xhigh`'ı ayrı tutarken `max` bildirir. "visionSidecar": { "enabled": true } } ``` - diff --git a/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md b/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md index ef827e9d32..969df072f7 100644 --- a/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md +++ b/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md @@ -157,8 +157,9 @@ affinity。这些策略不能规避 provider enforcement。 | 键 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | `anthropicAccountPool.enabled?` | `boolean` | `false` | 启用粘性亲和性和 429 冷却故障转移。 | -| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | 对于新会话,选择已知缓存的、5 小时使用率最低且达到或超过此阈值的账户。`0` 会禁用配额选择。 | -| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | 新会话策略;quota 只使用 5 小时条形数据。 | +| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | 对于新会话,当活动账户达到此阈值时,选择配置窗口中已知缓存使用率最低的账户。`0` 会禁用配额选择。 | +| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | 新会话策略;`quota` 按 `quotaWindow` 指定的窗口(默认是 5 小时条形数据)对账户排序,`fill-first` 也在同一窗口中判定其耗尽阈值。 | +| `anthropicAccountPool.quotaWindow?` | `"five-hour" \| "weekly" \| "max-utilization"` | `"five-hour"` | 基于用量选择账户时使用的、由提供商报告并缓存的用量条。`five-hour` 保持原有行为。`weekly` 使用每周用量条,并在仍有其他可用账户时跳过 5 小时用量已耗尽的账户;若没有其他账户,则回退使用这些账户。`max-utilization` 使用已知值中的最高值,因此每周用量尚不可用时仍可使用 5 小时用量;两者都未知时,账户遵循 unknown 用量排序。已知用量排在 unknown 之前,但如果所有可用账户都未知,仍会按可用顺序选择一个账户。在前述较低 5 小时用量的同分判定之后,完全相同时也保留可用顺序。不会主动重新平衡健康且已建立亲和性的会话。在新会话分配和符合条件的 429 替代后的路由恢复中,`quota` 直接按此窗口对可用候选账户排序;`fill-first` 按此窗口的阈值和耗尽规则以稳定顺序前进;`round-robin` 忽略此设置。冷却状态、故障转移上限和重新认证资格仍是独立的本地状态。各账户的每周用量只有在控制面板的提供商页面完成查询后才可用。 | | `anthropicAccountPool.stickyLimit?` | `number` | `1` | 在一次轮询选择中保留的成功新会话绑定次数。范围 1–100。 | 启用后,429 会根据 `Retry-After` 记录有界冷却,或者使用默认退避,并且可能在同一请求内轮换。亲和性是进程本地的,并且有大小上限。凭据 401/403 会将账户标记为需要重新认证。如果所有合格账户都在冷却,客户端会在已知时收到带 `Retry-After` 的 429,而不是身份验证错误。 diff --git a/docs-site/src/content/docs/zh-tw/guides/claude-code.md b/docs-site/src/content/docs/zh-tw/guides/claude-code.md index be06746fba..2663cb3647 100644 --- a/docs-site/src/content/docs/zh-tw/guides/claude-code.md +++ b/docs-site/src/content/docs/zh-tw/guides/claude-code.md @@ -14,7 +14,9 @@ Code 可以使用每一個已路由的供應商——包括 OAuth 登入、帳 **實驗性、opt-in** 的 Claude 帳號池(`anthropicAccountPool.enabled`)會在這些 OAuth 帳號之間加入 sticky session affinity 與 429 冷卻故障轉移。僅對**新**工作階段,`anthropicAccountPool.strategy` -會在合格帳號之間選擇:`quota`(預設)在用量高於 `autoSwitchThreshold` 時挑選已知 5 小時用量最低者; +會在合格帳號之間選擇:`quota`(預設)在用量高於 `autoSwitchThreshold` 時,依 +`anthropicAccountPool.quotaWindow` 所設定的視窗挑選已知用量最低者(`five-hour` 為預設,亦可選 +`weekly` 或 `max-utilization`); `round-robin` 平均分散(`stickyLimit`,預設 `1`);`fill-first` 一直使用作用中帳號直到冷卻、重新認證 或達到閾值,然後前進。它**預設關閉**、會在 GUI 顯示警告,而且尚未經過實戰驗證——Anthropic 可能 限制看起來像自動輪換的帳號;輪換並不能保護你免受供應商執行機制的處置。 @@ -26,6 +28,8 @@ sticky session affinity 與 429 冷卻故障轉移。僅對**新**工作階段 - Affinity 是**程序本機**的(proxy 重啟後就會遺失)。 - **401/403** 憑證失敗會隔離該帳號(`needsReauth`),直到重新認證前都不會參與選擇。 - 如果每個合格帳號都在冷卻,proxy 會回傳 **429**(不是 401),並在已知時附上 `Retry-After`。 +- 復原(包括 429 容錯移轉)會使用 `quotaWindow` 為合格的替代帳號排序,且不改變現有的冷卻或 + 容錯移轉上限;`round-robin` 會忽略 `quotaWindow`。 請見 [Configuration](/zh-tw/reference/configuration/#anthropicaccountpool-experimental)。 diff --git a/docs-site/src/content/docs/zh-tw/reference/configuration/providers.md b/docs-site/src/content/docs/zh-tw/reference/configuration/providers.md index 398a396dc7..166e105ac9 100644 --- a/docs-site/src/content/docs/zh-tw/reference/configuration/providers.md +++ b/docs-site/src/content/docs/zh-tw/reference/configuration/providers.md @@ -126,8 +126,9 @@ API-key 供應商可持有字面值金鑰或環境參考。OAuth 供應商使用 | Key | 型別 | 預設值 | 說明 | | --- | --- | --- | --- | | `anthropicAccountPool.enabled?` | `boolean` | `false` | 啟用 sticky 親和性與 429 冷卻容錯移轉。 | -| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | 對於新 session,選擇在此閾值或以上的最低已知快取 5 小時用量。`0` 停用量量挑選。 | -| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | 新 session 策略;quota 僅使用 5 小時列。 | +| `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | 對於新 session,當目前帳號達到此閾值時,選擇設定視窗中最低的已知快取用量。`0` 停用配額挑選。 | +| `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | 新 session 策略;`quota` 依 `quotaWindow` 指定的視窗(預設為 5 小時列)為帳號排序,`fill-first` 也在同一視窗中判定其排空閾值。 | +| `anthropicAccountPool.quotaWindow?` | `"five-hour" \| "weekly" \| "max-utilization"` | `"five-hour"` | 使用量型帳號選擇所採用、由供應商回報並快取的用量列。`five-hour` 保留原有行為。`weekly` 使用每週用量列,並在仍有其他可用帳號時略過 5 小時用量已用盡的帳號;若沒有其他帳號,則退回使用這些帳號。`max-utilization` 使用已知值中的最高值,因此每週用量尚未取得時仍可使用 5 小時用量;兩者都未知時,帳號遵循 unknown 用量排序。已知用量排在 unknown 之前,但若所有可用帳號都是 unknown,仍會依可用順序選出一個。完成前述較低 5 小時用量的同分判定後,完全相同時也保留可用順序。不會主動重新平衡健康且已有 affinity 的 session。在分配新 session 與符合條件的 429 替代後進行路由復原時,`quota` 直接依此視窗排序可用候選帳號;`fill-first` 依此視窗的門檻與用盡規則按穩定順序前進;`round-robin` 忽略此設定。冷卻狀態、容錯移轉上限與重新驗證資格仍是獨立的本機狀態。每個帳號的每週用量只有在 dashboard 的供應商頁面完成查詢後才可得知。 | | `anthropicAccountPool.stickyLimit?` | `number` | `1` | 在一次 round-robin 選擇上保留的成功新 session 綁定。範圍 1–100。 | 啟用時,429 記錄來自 `Retry-After` 或預設 backoff 的有界冷卻,並可能在請求內輪換。親和性為行程本地且有界。憑證 401/403 將帳號標記為需要重新認證。若所有合格帳號都在冷卻,客戶端收到附帶已知 `Retry-After` 的 429,而非認證錯誤。 diff --git a/gui/src/account-pool-strategy.ts b/gui/src/account-pool-strategy.ts index 4ff6b860c2..4dbc7b9e2b 100644 --- a/gui/src/account-pool-strategy.ts +++ b/gui/src/account-pool-strategy.ts @@ -6,12 +6,23 @@ export const ACCOUNT_POOL_STRATEGIES: readonly AccountPoolStrategy[] = [ "fill-first", ] as const; +/** Which cached usage bar the `quota` strategy scores. Mirrors `OcxAccountPoolQuotaWindow`. */ +export type AccountPoolQuotaWindow = "five-hour" | "weekly" | "max-utilization"; + +export const ACCOUNT_POOL_QUOTA_WINDOWS: readonly AccountPoolQuotaWindow[] = [ + "five-hour", + "weekly", + "max-utilization", +] as const; + export const DEFAULT_ACCOUNT_POOL_STRATEGY: AccountPoolStrategy = "quota"; +export const DEFAULT_ACCOUNT_POOL_QUOTA_WINDOW: AccountPoolQuotaWindow = "five-hour"; export const DEFAULT_ACCOUNT_POOL_STICKY_LIMIT = 1; export const MIN_ACCOUNT_POOL_STICKY_LIMIT = 1; export const MAX_ACCOUNT_POOL_STICKY_LIMIT = 100; const STRATEGY_SET = new Set(ACCOUNT_POOL_STRATEGIES); +const QUOTA_WINDOW_SET = new Set(ACCOUNT_POOL_QUOTA_WINDOWS); export function normalizeAccountPoolStrategy(value: unknown): AccountPoolStrategy { return typeof value === "string" && STRATEGY_SET.has(value) @@ -19,6 +30,12 @@ export function normalizeAccountPoolStrategy(value: unknown): AccountPoolStrateg : DEFAULT_ACCOUNT_POOL_STRATEGY; } +export function normalizeAccountPoolQuotaWindow(value: unknown): AccountPoolQuotaWindow { + return typeof value === "string" && QUOTA_WINDOW_SET.has(value) + ? value as AccountPoolQuotaWindow + : DEFAULT_ACCOUNT_POOL_QUOTA_WINDOW; +} + export function normalizeAccountPoolStickyLimit(value: unknown): number { return typeof value === "number" && Number.isInteger(value) diff --git a/gui/src/components/provider-workspace/AnthropicAccountPoolSettings.tsx b/gui/src/components/provider-workspace/AnthropicAccountPoolSettings.tsx index d0ef91fab5..4d7c66b970 100644 --- a/gui/src/components/provider-workspace/AnthropicAccountPoolSettings.tsx +++ b/gui/src/components/provider-workspace/AnthropicAccountPoolSettings.tsx @@ -5,20 +5,32 @@ import { useCallback, useEffect, useState } from "react"; import { useT } from "../../i18n/shared"; import { + ACCOUNT_POOL_QUOTA_WINDOWS, + DEFAULT_ACCOUNT_POOL_QUOTA_WINDOW, DEFAULT_ACCOUNT_POOL_STICKY_LIMIT, DEFAULT_ACCOUNT_POOL_STRATEGY, + normalizeAccountPoolQuotaWindow, normalizeAccountPoolStickyLimit, normalizeAccountPoolStrategy, parseAccountPoolStickyLimitDraft, + type AccountPoolQuotaWindow, type AccountPoolStrategy, } from "../../account-pool-strategy"; import AccountPoolStrategyControls from "../AccountPoolStrategyControls"; +import { Select } from "../../ui"; + +const QUOTA_WINDOW_LABEL_KEYS = { + "five-hour": "accountPool.quotaWindowFiveHour", + weekly: "accountPool.quotaWindowWeekly", + "max-utilization": "accountPool.quotaWindowMaxUtilization", +} as const; type PoolState = { enabled: boolean; threshold: number; strategy: AccountPoolStrategy; stickyLimit: number; + quotaWindow: AccountPoolQuotaWindow; }; export default function AnthropicAccountPoolSettings({ @@ -56,6 +68,7 @@ export default function AnthropicAccountPoolSettings({ autoSwitchThreshold?: number; strategy?: unknown; stickyLimit?: unknown; + quotaWindow?: unknown; }>; }) .then(json => { @@ -67,6 +80,7 @@ export default function AnthropicAccountPoolSettings({ threshold: nextThreshold, strategy: normalizeAccountPoolStrategy(json.strategy), stickyLimit: nextSticky, + quotaWindow: normalizeAccountPoolQuotaWindow(json.quotaWindow), }); setDraft(String(nextThreshold)); setStickyDraft(String(nextSticky)); @@ -87,6 +101,7 @@ export default function AnthropicAccountPoolSettings({ threshold: number; strategy: AccountPoolStrategy; stickyLimit: number; + quotaWindow: AccountPoolQuotaWindow; }) => { const previousState = state; setState({ @@ -94,6 +109,7 @@ export default function AnthropicAccountPoolSettings({ threshold: next.threshold, strategy: next.strategy, stickyLimit: next.stickyLimit, + quotaWindow: next.quotaWindow, }); setSaving(true); setError(null); @@ -107,20 +123,24 @@ export default function AnthropicAccountPoolSettings({ autoSwitchThreshold: next.threshold, strategy: next.strategy, stickyLimit: next.stickyLimit, + quotaWindow: next.quotaWindow, }), }); if (!res.ok) throw new Error("save"); const json = await res.json().catch(() => null) as { strategy?: unknown; stickyLimit?: unknown; + quotaWindow?: unknown; } | null; const savedStrategy = normalizeAccountPoolStrategy(json?.strategy ?? next.strategy); const savedSticky = normalizeAccountPoolStickyLimit(json?.stickyLimit ?? next.stickyLimit); + const savedWindow = normalizeAccountPoolQuotaWindow(json?.quotaWindow ?? next.quotaWindow); setState({ enabled: next.enabled, threshold: next.threshold, strategy: savedStrategy, stickyLimit: savedSticky, + quotaWindow: savedWindow, }); setDraft(String(next.threshold)); setStickyDraft(String(savedSticky)); @@ -140,6 +160,14 @@ export default function AnthropicAccountPoolSettings({ const threshold = state?.threshold ?? 80; const strategy = state?.strategy ?? DEFAULT_ACCOUNT_POOL_STRATEGY; const stickyLimit = state?.stickyLimit ?? DEFAULT_ACCOUNT_POOL_STICKY_LIMIT; + const quotaWindow = state?.quotaWindow ?? DEFAULT_ACCOUNT_POOL_QUOTA_WINDOW; + // The window is inert ONLY under round-robin, which never scores a usage bar at any stage. + // + // A 0 threshold is not inertness: it disables PROACTIVE usage-based switching, but + // new-session selection and 429 recovery still consult the configured window (see + // pickLowestUsage / rotateAnthropicAccountOn429). Treating fill-first + threshold 0 as + // inert told operators the window had no effect when it still governed two routing stages. + const quotaWindowInert = strategy === "round-robin"; const loading = state === null && !loadError; // Always allow turning the pool off; only block enabling when fewer than 2 accounts. const toggleDisabled = loading || saving || loadError || (!enabled && accountCount < 2); @@ -155,7 +183,14 @@ export default function AnthropicAccountPoolSettings({ : loading ? t("common.loading") : enabled - ? t("anthropicPool.enabledDesc", { threshold }) + ? threshold === 0 + ? t("anthropicPool.enabledNoProactiveDesc", { + window: t(QUOTA_WINDOW_LABEL_KEYS[quotaWindow]), + }) + : t("anthropicPool.enabledDesc", { + threshold, + window: t(QUOTA_WINDOW_LABEL_KEYS[quotaWindow]), + }) : t("anthropicPool.disabledDesc")} @@ -172,6 +207,7 @@ export default function AnthropicAccountPoolSettings({ threshold, strategy, stickyLimit, + quotaWindow, }); }} > @@ -214,6 +250,7 @@ export default function AnthropicAccountPoolSettings({ threshold: parsed, strategy, stickyLimit, + quotaWindow, }); } }} @@ -234,6 +271,7 @@ export default function AnthropicAccountPoolSettings({ threshold, strategy: next, stickyLimit, + quotaWindow, }); }} onStickyDraftChange={setStickyDraft} @@ -253,9 +291,39 @@ export default function AnthropicAccountPoolSettings({ threshold, strategy, stickyLimit: parsed, + quotaWindow, }); }} /> + +
+ {t("accountPool.quotaWindow")} +