Skip to content

Commit f0867e8

Browse files
authored
feat(codex): account pause controls and bulk exhaustion (#667)
Maintainer takeover of #565. Persisted pause exclusion, bulk pause-exhausted, GUI controls, docs. Integrated with account namespaces and Spark quota scopes on current dev.
1 parent c9bed7c commit f0867e8

36 files changed

Lines changed: 1237 additions & 47 deletions

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,15 @@ next Codex session. opencodex keeps these behaviors:
240240

241241
- **Existing sessions keep affinity.** A thread id is bound to the selected account and reused on
242242
later turns, so a long request or a mobile/SSH-attached session keeps using the same account.
243+
Pausing an account clears its affinity map: in-flight requests keep captured credentials, but
244+
subsequent turns are re-routed and cannot reuse the paused account.
243245
- **New sessions can auto-route.** When auto-switch is enabled, opencodex compares the hottest known
244246
quota window across 5h, weekly, and 30d usage, then picks a lower-usage eligible account for new
245247
sessions once the active account crosses the threshold.
246248
- **Quota lookup is built in.** The dashboard can refresh all account quotas in one click, and the
247-
request log labels pool traffic with non-PII account ordinals.
249+
request log labels pool traffic with non-PII account ordinals. **Pause exhausted** refreshes
250+
eligible accounts that have credentials and pauses only those whose relevant quota window is
251+
freshly confirmed at 100%; accounts without credentials and unknown or failed refreshes stay unchanged.
248252
- **Failures fail closed.** Token failures mark reauthentication instead of falling back to another
249253
credential silently; 429 quota responses put the account in cooldown and can fail over future work
250254
to another eligible pool account.

docs-site/src/content/docs/ja/reference/configuration.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ namespaced selected id を bare id に変えます。
5151
| `codexShimAutoRestore?` | `boolean` | `true` | 完了した外部 Codex 更新で以前にインストールした shim が置換された場合に復元します。無効にするには `false`、またはプロセスで `OPENCODEX_CODEX_SHIM_AUTO_RESTORE=0` を設定します。 |
5252
| `syncResumeHistory?` | `boolean` | `true` | 戻せる Codex App 履歴互換モード。opencodex は元の Codex thread metadata をバックアップし、旧 OpenAI interactive row を `opencodex` に再マッピングし、opencodex が作成した `exec` row を App に見えるソースとして一時的に昇格します。`ocx stop` / `ocx restore` はバックアップした OpenAI row を復元し、残った opencodex user thread を OpenAI に戻し、ネイティブ Codex が `config.toml` からプロキシを削除した後でも開き続けられるようにします。オフにするには `false` に設定します。 |
5353
| `codexAccounts?` | `CodexAccount[]` | `[]` | Codex Auth ダッシュボードが管理する ChatGPT/Codex pool アカウント metadata。secret は `codex-accounts.json` に別途置きます。 |
54+
| `pausedCodexAccountIds?` | `string[]` | `[]` | Codex Auth で再開するまで、今後のすべての Pool 選択から除外するアカウント ID。メインを一時停止した場合は `__main__` も含みます。 |
5455
| `codexAccountNamespaces?` | `Record<string,string>` || 公開 model selector namespace から保存済み Codex アカウント target への任意 map。この foundation layer は map を検証・保存しますが、picker row の追加や routing の変更は行いません。 |
5556
| `activeCodexAccountId?` | `string` || 手動選択した pool アカウント。既存 thread affinity を消去して次のリクエストから適用し、処理中のリクエストは現在のアカウントを維持します。 |
5657
| `autoSwitchThreshold?` | `number` | `80` | 新しいセッション自動切替用の使用量百分率 threshold。既知の 5 時間、週次、30 日 quota window のうち最も高いスコアを使います。`0` なら quota 自動切替をオフにします。`quota` 戦略と `fill-first` の drain threshold にも使います。 |
@@ -85,6 +86,10 @@ pool アカウントの追加と quota 更新はダッシュボードの **Codex
8586
ないアカウント metadata だけを保存し、access/refresh token は強化された Codex アカウント credential store に別途
8687
保管します。既存 thread id はアカウント affinity を維持し、新しいセッションは `accountPoolStrategy`、quota、cooldown、health に
8788
応じて自動ルーティングされます。
89+
一時停止したアカウントと quota metadata は表示されたままですが、自動切り替え、再試行/failover 選択、cooldown 復旧プローブ、手動有効化の対象外です。
90+
一時停止するとそのアカウントの thread affinity map も消去されます。処理中のリクエストは取得済み credential を維持しますが、以降のターンは再ルーティングされ、一時停止中のアカウントは再利用できません。
91+
状態は再起動後も保持され、すべてのアカウントが一時停止中なら Pool ルーティングは別のアカウントを暗黙に選ばず失敗します。
92+
**上限到達を一括停止** は credential がある適格アカウントだけを先に更新し、関連する quota window が今回 100% と確認できたアカウントだけを停止します。credential がないアカウントや、quota が不明、または更新に失敗したアカウントは変更しません。
8893

8994
**rotation 戦略**(新しいセッションのみ;bound thread は不変):`quota`(既定)— `autoSwitchThreshold` 超過時に最小 usage を選択;`round-robin` — 均等分散、`accountPoolStickyLimit`(既定 `1`、1–100)で 1 選択あたりの成功 bind 数;`fill-first` — アクティブアカウントを cooldown、再認証、または threshold まで使い切り(未知 usage は強制切替しない)後、安定ソート順で次へ。rotation は provider enforcement を回避しません — 複数アカウント利用は ToS 違反の可能性があります。
9095
:::

docs-site/src/content/docs/ko/reference/configuration.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ namespaced selected id를 bare id로 바꿉니다.
5252
| `codexShimAutoRestore?` | `boolean` | `true` | 완료된 외부 Codex 업데이트가 이전에 설치한 shim을 교체하면 자동으로 복구합니다. 끄려면 `false`로 설정하거나 프로세스에 `OPENCODEX_CODEX_SHIM_AUTO_RESTORE=0`을 설정합니다. |
5353
| `syncResumeHistory?` | `boolean` | `true` | 되돌릴 수 있는 Codex App 기록 호환 모드. opencodex가 원래 Codex thread metadata를 백업하고, 예전 OpenAI interactive row를 `opencodex`로 재매핑하며, opencodex가 만든 `exec` row를 App에 보이는 source로 잠시 승격합니다. `ocx stop` / `ocx restore`는 백업한 OpenAI row를 복원하고 남은 opencodex user thread를 OpenAI로 돌려 네이티브 Codex가 `config.toml`에서 프록시를 제거한 뒤에도 이어서 열 수 있게 합니다. 끄려면 `false`로 설정합니다. |
5454
| `codexAccounts?` | `CodexAccount[]` | `[]` | Codex Auth 대시보드에서 관리하는 ChatGPT/Codex pool 계정 metadata. secret은 `codex-accounts.json`에 따로 둡니다. |
55+
| `pausedCodexAccountIds?` | `string[]` | `[]` | Codex Auth에서 재개할 때까지 이후의 모든 Pool 선택에서 제외할 계정 ID. 메인 계정을 일시 중지하면 `__main__`도 포함됩니다. |
5556
| `codexAccountNamespaces?` | `Record<string,string>` || 공개 model selector namespace에서 저장된 Codex 계정 target으로 연결하는 선택적 map입니다. 이 foundation layer는 map을 검증하고 저장하지만 picker row를 추가하거나 routing을 변경하지 않습니다. |
5657
| `activeCodexAccountId?` | `string` || 수동으로 선택한 pool 계정. 선택 시 기존 thread affinity를 지우고 다음 요청부터 적용하며, 진행 중인 요청은 기존 계정을 유지합니다. |
5758
| `autoSwitchThreshold?` | `number` | `80` | 새 세션 자동 전환용 사용량 백분율 threshold. 알려진 5시간, 주간, 30일 quota window 중 가장 높은 점수를 씁니다. `0`이면 quota 자동 전환을 끕니다. `quota` 전략과 `fill-first` drain threshold에도 사용됩니다. |
@@ -87,6 +88,10 @@ pool 계정 추가와 quota 갱신은 대시보드의 **Codex Auth** 페이지
8788
아닌 계정 metadata만 저장하고, access/refresh token은 강화된 Codex 계정 credential store에 따로
8889
보관합니다. 기존 thread id는 계정 affinity를 유지하며, 새 세션은 `accountPoolStrategy`, quota,
8990
cooldown, health에 따라 자동 라우팅됩니다.
91+
일시 중지된 계정과 quota metadata는 계속 표시되지만 자동 전환, 재시도/failover 선택, cooldown 복구 probe, 수동 활성화에서는 제외됩니다.
92+
일시 중지는 해당 계정의 thread affinity map도 지웁니다. 진행 중인 요청은 이미 확보한 credential을 유지하지만, 이후 턴은 다시 라우팅되며 일시 중지된 계정은 재사용할 수 없습니다.
93+
상태는 재시작 후에도 유지되며, 모든 계정이 일시 중지되면 Pool 라우팅은 계정을 몰래 선택하지 않고 실패합니다.
94+
**한도 도달 계정 일시 중지**는 credential이 있는 적격 계정만 먼저 새로고친 뒤 관련 quota window가 이번 응답에서 100%로 확인된 계정만 일시 중지합니다. credential이 없는 계정과 quota가 없거나 새로고침에 실패한 계정은 변경하지 않습니다.
9095

9196
**rotation 전략**(새 세션만; bound thread는 변경 없음): `quota`(기본) — `autoSwitchThreshold` 초과 시
9297
최저 usage 선택; `round-robin` — 균등 분배, `accountPoolStickyLimit`(기본 `1`, 1–100)로 한 선택당

docs-site/src/content/docs/reference/configuration.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ differing backup and rewrites known legacy namespaced selected ids to bare ids.
5757
| `codexShimAutoRestore?` | `boolean` | `true` | Restore a previously installed Codex shim when a completed external Codex update replaces it. Set `false`, or set `OPENCODEX_CODEX_SHIM_AUTO_RESTORE=0` for a process-level opt-out. |
5858
| `syncResumeHistory?` | `boolean` | `true` | Reversible Codex App history compatibility mode. opencodex backs up original Codex thread metadata, remaps old OpenAI interactive rows to `opencodex`, and temporarily promotes opencodex-created `exec` rows to an app-visible source. `ocx stop` / `ocx restore` restore backed-up OpenAI rows and eject remaining opencodex user threads to OpenAI so native Codex can resume them after the proxy is removed from `config.toml`. Set `false` to opt out. |
5959
| `codexAccounts?` | `CodexAccount[]` | `[]` | ChatGPT/Codex pool account metadata managed by the Codex Auth dashboard. Secrets live separately in `codex-accounts.json`. |
60+
| `pausedCodexAccountIds?` | `string[]` | `[]` | Accounts excluded from every future Pool selection until resumed in Codex Auth. Includes the main `__main__` account when paused. |
6061
| `codexAccountNamespaces?` | `Record<string,string>` || Optional public model-selector namespace → stored Codex account target map. This foundation layer validates and persists the map but does not add picker rows or change routing. |
6162
| `activeCodexAccountId?` | `string` || Manually selected Pool account. Selection clears existing thread affinity and applies to the next request; in-flight requests keep their captured account. |
6263
| `autoSwitchThreshold?` | `number` | `80` | Usage percent threshold for new-session auto-switching. The score uses the hottest known 5h, weekly, or 30d quota window. Set `0` to disable quota auto-switching. Used by the `quota` strategy and as the drain threshold for `fill-first`. |
@@ -115,6 +116,14 @@ credential store. Existing thread ids keep account affinity, while new sessions
115116
`accountPoolStrategy`, quota, cooldown, and health. A pre-stream upstream **429**/**402** on one pool
116117
account is retried once on an eligible alternate account in the same request (so Codex CLI does not
117118
stall on a depleted primary while another account still has quota).
119+
Pause keeps an account and its quota metadata visible, but excludes it from automatic switching,
120+
retry/failover selection, cooldown recovery probes, and manual activation. Pausing also clears that
121+
account's thread-affinity map: in-flight requests keep their captured credentials, but subsequent
122+
turns are re-routed and cannot reuse the paused account. The exclusion survives
123+
restarts; if every account is paused, Pool routing fails instead of silently selecting one.
124+
**Pause exhausted** first refreshes eligible accounts that have credentials available and pauses
125+
only those whose relevant quota window is freshly confirmed at 100%; accounts without credentials
126+
and unknown or failed quota refreshes are left unchanged.
118127
:::
119128

120129
**Rotation strategies** (new sessions only; bound threads are unchanged):

docs-site/src/content/docs/ru/reference/configuration.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ opencodex настраивается файлом `~/.opencodex/config.json`. Е
5656
| `codexShimAutoRestore?` | `boolean` | `true` | Восстанавливает ранее установленный shim после того, как завершённое внешнее обновление Codex заменило его. Для отключения задайте `false` или установите процессу `OPENCODEX_CODEX_SHIM_AUTO_RESTORE=0`. |
5757
| `syncResumeHistory?` | `boolean` | `true` | Обратимый режим совместимости истории Codex App. opencodex резервирует исходные метаданные потоков Codex, переназначает старые интерактивные строки OpenAI на `opencodex` и временно повышает созданные opencodex строки `exec` до видимого в приложении источника. `ocx stop` / `ocx restore` восстанавливают зарезервированные строки OpenAI и возвращают оставшиеся пользовательские потоки opencodex обратно к OpenAI, чтобы нативный Codex мог возобновлять их после удаления прокси из `config.toml`. Установите `false`, чтобы отказаться. |
5858
| `codexAccounts?` | `CodexAccount[]` | `[]` | Метаданные аккаунтов пула ChatGPT/Codex, управляемые дашбордом Codex Auth. Секреты хранятся отдельно в `codex-accounts.json`. |
59+
| `pausedCodexAccountIds?` | `string[]` | `[]` | ID аккаунтов, исключённых из всех будущих выборов Pool до возобновления в Codex Auth. При паузе основного аккаунта включает `__main__`. |
5960
| `codexAccountNamespaces?` | `Record<string,string>` || Необязательная map публичного namespace селектора модели на сохранённую цель аккаунта Codex. Этот foundation layer проверяет и сохраняет map, но не добавляет строки picker и не меняет routing. |
6061
| `activeCodexAccountId?` | `string` || Вручную выбранный аккаунт пула. Выбор очищает существующие привязки потоков и действует со следующего запроса; выполняющиеся запросы сохраняют захваченный аккаунт. |
6162
| `autoSwitchThreshold?` | `number` | `80` | Порог процента использования для автопереключения новых сессий. Оценка использует самое «горячее» из известных окон квоты — 5-часовое, недельное или 30-дневное. Установите `0`, чтобы отключить автопереключение по квоте. Используется стратегией `quota` и как порог исчерпания для `fill-first`. |
@@ -94,6 +95,12 @@ raw id аккаунтов и email приватными, а селектор и
9495
защищённом хранилище учётных данных аккаунтов Codex. Существующие id потоков сохраняют привязку к
9596
аккаунту; новые сессии маршрутизируются по `accountPoolStrategy`, квоте, cooldown и
9697
работоспособности.
98+
Приостановленный аккаунт и его метаданные квоты остаются видимыми, но исключаются из автоматического переключения,
99+
повторов/failover, проб восстановления cooldown и ручной активации. Пауза также очищает карту affinity потоков
100+
этого аккаунта: выполняющиеся запросы сохраняют захваченные учётные данные, но последующие ходы
101+
перемаршрутизируются и не могут повторно использовать приостановленный аккаунт. Состояние сохраняется после перезапуска;
102+
если приостановлены все аккаунты, маршрутизация Pool завершается ошибкой, а не выбирает аккаунт скрытно.
103+
**Приостановить исчерпанные** сначала обновляет только подходящие аккаунты с доступными учётными данными и приостанавливает только те, для которых актуальное окно квоты в этом ответе подтверждено на уровне 100%. Аккаунты без учётных данных, с неизвестной квотой или неудачным обновлением не меняются.
97104

98105
**Стратегии ротации** (только новые сессии; привязанные потоки не меняются): `quota` (по умолчанию)
99106
— выбор наименьшего usage при превышении `autoSwitchThreshold`; `round-robin` — равномерное

0 commit comments

Comments
 (0)