Skip to content

Commit ab5b04a

Browse files
authored
feat(codex): carry account pause controls onto dev2-go (#667)
Carries #667 (and prerequisite account namespace foundation) onto dig2-go. Go port tracked in #670.
1 parent af30dd9 commit ab5b04a

63 files changed

Lines changed: 3703 additions & 122 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

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

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

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ 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__` も含みます。 |
55+
| `codexAccountNamespaces?` | `Record<string,string>` || 公開 model selector namespace から保存済み Codex アカウント target への任意 map。この foundation layer は map を検証・保存しますが、picker row の追加や routing の変更は行いません。 |
5456
| `activeCodexAccountId?` | `string` || 手動選択した pool アカウント。既存 thread affinity を消去して次のリクエストから適用し、処理中のリクエストは現在のアカウントを維持します。 |
5557
| `autoSwitchThreshold?` | `number` | `80` | 新しいセッション自動切替用の使用量百分率 threshold。既知の 5 時間、週次、30 日 quota window のうち最も高いスコアを使います。`0` なら quota 自動切替をオフにします。`quota` 戦略と `fill-first` の drain threshold にも使います。 |
5658
| `accountPoolStrategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | Codex pool の新しいセッション rotation 戦略。**新しいセッションのみ**に適用され、既存 thread id は affinity を維持します。`quota`(既定)— アクティブアカウントが `autoSwitchThreshold` を超えたら既知 usage 最小を選択。`round-robin` — 適格アカウント間を smooth weighted で均等分散。`fill-first` — cooldown、使用不可、または(設定時)`autoSwitchThreshold` までアクティブアカウントを使い切り(未知 usage は強制切替しない)、安定ソート順で次へ。 |
@@ -63,6 +65,15 @@ namespaced selected id を bare id に変えます。
6365
| `tokenGuardian?` | `OcxTokenGuardianConfig` | off | 選択型の proactive OAuth 更新と Codex アカウント warmup ポリシー。フィールドは下で説明します。 |
6466
| `corsAllowOrigins?` | `string[]` | `[]` | CORS で追加で許可する正確な origin。loopback origin は常に許可します。 |
6567

68+
`codexAccountNamespaces` のキーは公開 selector です。長さは 1〜64 文字、先頭と末尾は ASCII
69+
英数字、内部には英数字、`.``_``-` を使用でき、予約済み JavaScript object 名は拒否されます。
70+
値は有効な pool account id(内部 `__main__` は不可)、または Codex Desktop アカウントを示す
71+
`"@main"` です。provider と予約済み `openai` / `combo` との衝突は大文字小文字を区別せず検査され、
72+
namespace 付き combo alias はその namespace prefix に selector を再利用できません。設定済み pool id
73+
や他の selector target も selector と再利用できません。raw account id と email は
74+
非公開のままにし、selector を公開名として使ってください。この foundation layer では map は inert で、
75+
model picker entry の作成、session の固定、Pool / Direct routing の変更は行いません。
76+
6677
`maxConcurrentThreadsPerSession``config.json` キーではなく `PUT /api/v2` で使う camel-case
6778
フィールドです。`ocx v2 threads <n>` は対応する `max_concurrent_threads_per_session` 値を Codex の
6879
`$CODEX_HOME/config.toml``[features.multi_agent_v2]` に保存します。その table ができるように v2 を先にオンにしてください。
@@ -75,6 +86,10 @@ pool アカウントの追加と quota 更新はダッシュボードの **Codex
7586
ないアカウント metadata だけを保存し、access/refresh token は強化された Codex アカウント credential store に別途
7687
保管します。既存 thread id はアカウント affinity を維持し、新しいセッションは `accountPoolStrategy`、quota、cooldown、health に
7788
応じて自動ルーティングされます。
89+
一時停止したアカウントと quota metadata は表示されたままですが、自動切り替え、再試行/failover 選択、cooldown 復旧プローブ、手動有効化の対象外です。
90+
一時停止するとそのアカウントの thread affinity map も消去されます。処理中のリクエストは取得済み credential を維持しますが、以降のターンは再ルーティングされ、一時停止中のアカウントは再利用できません。
91+
状態は再起動後も保持され、すべてのアカウントが一時停止中なら Pool ルーティングは別のアカウントを暗黙に選ばず失敗します。
92+
**上限到達を一括停止** は credential がある適格アカウントだけを先に更新し、関連する quota window が今回 100% と確認できたアカウントだけを停止します。credential がないアカウントや、quota が不明、または更新に失敗したアカウントは変更しません。
7893

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

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ 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__`도 포함됩니다. |
56+
| `codexAccountNamespaces?` | `Record<string,string>` || 공개 model selector namespace에서 저장된 Codex 계정 target으로 연결하는 선택적 map입니다. 이 foundation layer는 map을 검증하고 저장하지만 picker row를 추가하거나 routing을 변경하지 않습니다. |
5557
| `activeCodexAccountId?` | `string` || 수동으로 선택한 pool 계정. 선택 시 기존 thread affinity를 지우고 다음 요청부터 적용하며, 진행 중인 요청은 기존 계정을 유지합니다. |
5658
| `autoSwitchThreshold?` | `number` | `80` | 새 세션 자동 전환용 사용량 백분율 threshold. 알려진 5시간, 주간, 30일 quota window 중 가장 높은 점수를 씁니다. `0`이면 quota 자동 전환을 끕니다. `quota` 전략과 `fill-first` drain threshold에도 사용됩니다. |
5759
| `accountPoolStrategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | Codex pool의 새 세션 rotation 전략. **새 세션에만** 적용되며 기존 thread id는 affinity를 유지합니다. `quota`(기본) — 활성 계정이 `autoSwitchThreshold`를 넘으면 알려진 usage가 가장 낮은 계정 선택. `round-robin` — 적격 계정 간 smooth weighted 균등 분배. `fill-first` — cooldown, 사용 불가 또는(설정 시) `autoSwitchThreshold`까지 활성 계정을 소진(알 수 없는 usage는 강제 전환하지 않음)한 뒤 안정 정렬 순으로 다음 계정. |
@@ -64,6 +66,15 @@ namespaced selected id를 bare id로 바꿉니다.
6466
| `tokenGuardian?` | `OcxTokenGuardianConfig` | off | 선택형 proactive OAuth 갱신 및 Codex 계정 warmup 정책. 필드는 아래에 설명합니다. |
6567
| `corsAllowOrigins?` | `string[]` | `[]` | CORS에서 추가로 허용할 정확한 origin. loopback origin은 항상 허용합니다. |
6668

69+
`codexAccountNamespaces` 키는 공개 selector입니다. 길이는 1~64자이고 시작과 끝은 ASCII 영숫자여야
70+
하며, 내부에는 영숫자, `.`, `_`, `-`를 사용할 수 있습니다. 예약된 JavaScript object 이름은 거부됩니다.
71+
값은 유효한 pool account id(내부 `__main__` 제외)이거나 Codex Desktop 계정을 나타내는 `"@main"`입니다.
72+
provider 및 예약된 `openai` / `combo` 충돌은 대소문자를 구분하지 않고 검사하며, namespace가 있는
73+
combo alias는 selector를 namespace prefix로 재사용할 수 없습니다. 설정된 pool id와 다른 selector
74+
target도 selector로 재사용할 수 없습니다. raw account id와 email은 비공개로
75+
유지하고 selector를 공개 이름으로 사용하세요. 이 foundation layer에서 map은 inert하며 model picker
76+
entry 생성, session 고정, Pool / Direct routing 변경을 수행하지 않습니다.
77+
6778
`maxConcurrentThreadsPerSession``config.json` 키가 아니라 `PUT /api/v2`에서 쓰는 camel-case
6879
필드입니다. `ocx v2 threads <n>`은 대응하는 `max_concurrent_threads_per_session` 값을 Codex의
6980
`$CODEX_HOME/config.toml``[features.multi_agent_v2]`에 저장합니다. 해당 table이 생기도록 v2를
@@ -77,6 +88,10 @@ pool 계정 추가와 quota 갱신은 대시보드의 **Codex Auth** 페이지
7788
아닌 계정 metadata만 저장하고, access/refresh token은 강화된 Codex 계정 credential store에 따로
7889
보관합니다. 기존 thread id는 계정 affinity를 유지하며, 새 세션은 `accountPoolStrategy`, quota,
7990
cooldown, health에 따라 자동 라우팅됩니다.
91+
일시 중지된 계정과 quota metadata는 계속 표시되지만 자동 전환, 재시도/failover 선택, cooldown 복구 probe, 수동 활성화에서는 제외됩니다.
92+
일시 중지는 해당 계정의 thread affinity map도 지웁니다. 진행 중인 요청은 이미 확보한 credential을 유지하지만, 이후 턴은 다시 라우팅되며 일시 중지된 계정은 재사용할 수 없습니다.
93+
상태는 재시작 후에도 유지되며, 모든 계정이 일시 중지되면 Pool 라우팅은 계정을 몰래 선택하지 않고 실패합니다.
94+
**한도 도달 계정 일시 중지**는 credential이 있는 적격 계정만 먼저 새로고친 뒤 관련 quota window가 이번 응답에서 100%로 확인된 계정만 일시 중지합니다. credential이 없는 계정과 quota가 없거나 새로고침에 실패한 계정은 변경하지 않습니다.
8095

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

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ 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. |
61+
| `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. |
6062
| `activeCodexAccountId?` | `string` || Manually selected Pool account. Selection clears existing thread affinity and applies to the next request; in-flight requests keep their captured account. |
6163
| `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`. |
6264
| `accountPoolStrategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | New-session rotation strategy for the Codex pool. Applies to **new sessions only**; existing thread ids keep affinity. `quota` — today's default: pick the lowest known usage when the active account crosses `autoSwitchThreshold`. `round-robin` — even spread across eligible accounts via smooth weighted selection. `fill-first` — keep the active account until it cools down, becomes unusable, or crosses `autoSwitchThreshold` when set (unknown usage does not force a switch), then advance to the next eligible account in stable sorted order. |
@@ -70,6 +72,15 @@ differing backup and rewrites known legacy namespaced selected ids to bare ids.
7072
| `tokenGuardian?` | `OcxTokenGuardianConfig` | off | Optional proactive OAuth refresh and Codex-account warmup policy; fields are listed below. |
7173
| `corsAllowOrigins?` | `string[]` | `[]` | Additional exact origins allowed by CORS. Loopback origins are always allowed. |
7274

75+
`codexAccountNamespaces` keys are public selectors: 1–64 characters, starting and ending with an
76+
ASCII letter or number, with letters, numbers, `.`, `_`, or `-` inside; reserved JavaScript object
77+
names are rejected. Each value is either a valid pool-account id (never the internal `__main__`) or
78+
`"@main"` for the Codex Desktop account. Provider and reserved `openai` / `combo` collisions are
79+
checked case-insensitively; a namespaced combo alias cannot reuse a selector as its namespace prefix,
80+
and configured pool ids or selector targets also cannot reuse a selector. Keep raw
81+
account ids and emails private—the selector is the public name. In this foundation layer the map is
82+
inert: it does not create model-picker entries, pin sessions, or alter Pool or Direct routing.
83+
7384
`maxConcurrentThreadsPerSession` is the camel-case field used by `PUT /api/v2`, not a
7485
`config.json` key. `ocx v2 threads <n>` persists the corresponding
7586
`max_concurrent_threads_per_session` value under `[features.multi_agent_v2]` in Codex's
@@ -105,6 +116,14 @@ credential store. Existing thread ids keep account affinity, while new sessions
105116
`accountPoolStrategy`, quota, cooldown, and health. A pre-stream upstream **429**/**402** on one pool
106117
account is retried once on an eligible alternate account in the same request (so Codex CLI does not
107118
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.
108127
:::
109128

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

0 commit comments

Comments
 (0)