codex-multi-auth 1.2.6 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +41 -21
- package/dist/index.js.map +1 -1
- package/dist/lib/accounts.d.ts +47 -0
- package/dist/lib/accounts.d.ts.map +1 -1
- package/dist/lib/accounts.js +219 -33
- package/dist/lib/accounts.js.map +1 -1
- package/dist/lib/auth/auth.d.ts +16 -0
- package/dist/lib/auth/auth.d.ts.map +1 -1
- package/dist/lib/auth/auth.js +52 -6
- package/dist/lib/auth/auth.js.map +1 -1
- package/dist/lib/auth/server.d.ts +1 -1
- package/dist/lib/auth/server.d.ts.map +1 -1
- package/dist/lib/auth/server.js +10 -8
- package/dist/lib/auth/server.js.map +1 -1
- package/dist/lib/codex-manager/commands/status.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/status.js +13 -5
- package/dist/lib/codex-manager/commands/status.js.map +1 -1
- package/dist/lib/codex-manager/commands/verify.d.ts +59 -0
- package/dist/lib/codex-manager/commands/verify.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/verify.js +332 -0
- package/dist/lib/codex-manager/commands/verify.js.map +1 -0
- package/dist/lib/codex-manager/commands/why-selected.d.ts +57 -0
- package/dist/lib/codex-manager/commands/why-selected.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/why-selected.js +198 -0
- package/dist/lib/codex-manager/commands/why-selected.js.map +1 -0
- package/dist/lib/codex-manager/help.d.ts.map +1 -1
- package/dist/lib/codex-manager/help.js +4 -0
- package/dist/lib/codex-manager/help.js.map +1 -1
- package/dist/lib/codex-manager/settings-hub/backend.d.ts +9 -0
- package/dist/lib/codex-manager/settings-hub/backend.d.ts.map +1 -0
- package/dist/lib/codex-manager/settings-hub/backend.js +79 -0
- package/dist/lib/codex-manager/settings-hub/backend.js.map +1 -0
- package/dist/lib/codex-manager/settings-hub/dashboard.d.ts +24 -0
- package/dist/lib/codex-manager/settings-hub/dashboard.d.ts.map +1 -0
- package/dist/lib/codex-manager/settings-hub/dashboard.js +223 -0
- package/dist/lib/codex-manager/settings-hub/dashboard.js.map +1 -0
- package/dist/lib/codex-manager/settings-hub/experimental.d.ts +18 -0
- package/dist/lib/codex-manager/settings-hub/experimental.d.ts.map +1 -0
- package/dist/lib/codex-manager/settings-hub/experimental.js +78 -0
- package/dist/lib/codex-manager/settings-hub/experimental.js.map +1 -0
- package/dist/lib/codex-manager/settings-hub/index.d.ts +34 -0
- package/dist/lib/codex-manager/settings-hub/index.d.ts.map +1 -0
- package/dist/lib/codex-manager/settings-hub/index.js +81 -0
- package/dist/lib/codex-manager/settings-hub/index.js.map +1 -0
- package/dist/lib/codex-manager/settings-hub/shared.d.ts +40 -0
- package/dist/lib/codex-manager/settings-hub/shared.d.ts.map +1 -0
- package/dist/lib/codex-manager/settings-hub/shared.js +103 -0
- package/dist/lib/codex-manager/settings-hub/shared.js.map +1 -0
- package/dist/lib/codex-manager/settings-hub.d.ts +1 -64
- package/dist/lib/codex-manager/settings-hub.d.ts.map +1 -1
- package/dist/lib/codex-manager/settings-hub.js +4 -515
- package/dist/lib/codex-manager/settings-hub.js.map +1 -1
- package/dist/lib/codex-manager.d.ts.map +1 -1
- package/dist/lib/codex-manager.js +95 -13
- package/dist/lib/codex-manager.js.map +1 -1
- package/dist/lib/config.d.ts +14 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +21 -9
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/health.d.ts.map +1 -1
- package/dist/lib/health.js.map +1 -1
- package/dist/lib/recovery/storage.d.ts.map +1 -1
- package/dist/lib/recovery/storage.js +112 -8
- package/dist/lib/recovery/storage.js.map +1 -1
- package/dist/lib/request/response-handler.d.ts.map +1 -1
- package/dist/lib/request/response-handler.js +67 -23
- package/dist/lib/request/response-handler.js.map +1 -1
- package/dist/lib/rotation.d.ts +53 -1
- package/dist/lib/rotation.d.ts.map +1 -1
- package/dist/lib/rotation.js +135 -23
- package/dist/lib/rotation.js.map +1 -1
- package/dist/lib/routing-mutex.d.ts +107 -0
- package/dist/lib/routing-mutex.d.ts.map +1 -0
- package/dist/lib/routing-mutex.js +104 -0
- package/dist/lib/routing-mutex.js.map +1 -0
- package/dist/lib/runtime/storage-scope.d.ts.map +1 -1
- package/dist/lib/runtime/storage-scope.js +17 -1
- package/dist/lib/runtime/storage-scope.js.map +1 -1
- package/dist/lib/schemas.d.ts +125 -0
- package/dist/lib/schemas.d.ts.map +1 -1
- package/dist/lib/schemas.js +139 -5
- package/dist/lib/schemas.js.map +1 -1
- package/dist/lib/storage/account-clear.d.ts.map +1 -1
- package/dist/lib/storage/account-clear.js +7 -1
- package/dist/lib/storage/account-clear.js.map +1 -1
- package/dist/lib/storage/flagged-storage-file.d.ts.map +1 -1
- package/dist/lib/storage/flagged-storage-file.js +17 -1
- package/dist/lib/storage/flagged-storage-file.js.map +1 -1
- package/dist/lib/storage/flagged-storage-io.d.ts.map +1 -1
- package/dist/lib/storage/flagged-storage-io.js +24 -10
- package/dist/lib/storage/flagged-storage-io.js.map +1 -1
- package/dist/lib/storage/import-export.d.ts.map +1 -1
- package/dist/lib/storage/import-export.js +16 -4
- package/dist/lib/storage/import-export.js.map +1 -1
- package/dist/lib/storage/paths.d.ts.map +1 -1
- package/dist/lib/storage/paths.js +62 -7
- package/dist/lib/storage/paths.js.map +1 -1
- package/dist/lib/storage/snapshot-inspectors.d.ts.map +1 -1
- package/dist/lib/storage/snapshot-inspectors.js +23 -16
- package/dist/lib/storage/snapshot-inspectors.js.map +1 -1
- package/dist/lib/storage/storage-parser.d.ts +17 -0
- package/dist/lib/storage/storage-parser.d.ts.map +1 -1
- package/dist/lib/storage/storage-parser.js +30 -1
- package/dist/lib/storage/storage-parser.js.map +1 -1
- package/dist/lib/storage.d.ts +1 -1
- package/dist/lib/storage.d.ts.map +1 -1
- package/dist/lib/storage.js +45 -26
- package/dist/lib/storage.js.map +1 -1
- package/dist/lib/ui/copy.d.ts +1 -1
- package/dist/lib/ui/copy.d.ts.map +1 -1
- package/dist/lib/ui/copy.js +2 -1
- package/dist/lib/ui/copy.js.map +1 -1
- package/package.json +5 -5
- package/scripts/codex-bin-resolver.js +162 -7
- package/scripts/codex-multi-auth.js +1 -1
- package/scripts/codex.js +233 -226
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/codex-multi-auth)
|
|
4
4
|
[](https://www.npmjs.com/package/codex-multi-auth)
|
|
5
5
|
|
|
6
|
-
Codex CLI-first multi-account OAuth manager for the official `@openai/codex`
|
|
6
|
+
Codex CLI-first multi-account OAuth manager for the official Codex CLI, including the `@openai/codex` npm launcher and native `codex` installs.
|
|
7
7
|
|
|
8
8
|
<img width="1270" height="729" alt="2026-02-28 12_54_58-prompt txt - Notepads" src="https://github.com/user-attachments/assets/0cecb77e-a6d3-432a-ba48-3577db0c7093" />
|
|
9
9
|
|
|
@@ -11,6 +11,7 @@ Codex CLI-first multi-account OAuth manager for the official `@openai/codex` CLI
|
|
|
11
11
|
> [!NOTE]
|
|
12
12
|
> Legacy scoped prerelease package `@ndycode/codex-multi-auth` is migration-only.
|
|
13
13
|
> Use `codex-multi-auth` for all new installs.
|
|
14
|
+
|
|
14
15
|
## What You Get
|
|
15
16
|
|
|
16
17
|
- Canonical `codex auth ...` workflow for account login, switching, checks, and diagnostics
|
|
@@ -19,7 +20,7 @@ Codex CLI-first multi-account OAuth manager for the official `@openai/codex` CLI
|
|
|
19
20
|
- Interactive dashboard for account actions and settings
|
|
20
21
|
- Experimental settings tab for staged sync, backup, and refresh-guard controls
|
|
21
22
|
- Forecast, report, fix, and doctor commands for operational safety
|
|
22
|
-
- Runtime counters, budget/cooldown state, and multi-auth probe visibility in `codex auth status` / `codex auth report`
|
|
23
|
+
- Runtime counters, budget/cooldown state, and multi-auth probe visibility in `codex auth status` / `codex auth report`
|
|
23
24
|
- Flagged account verification and restore flow
|
|
24
25
|
- Session affinity and live account sync controls
|
|
25
26
|
- Proactive refresh and preemptive quota deferral controls
|
|
@@ -71,6 +72,8 @@ codex-multi-auth --version
|
|
|
71
72
|
codex auth status
|
|
72
73
|
```
|
|
73
74
|
|
|
75
|
+
Any official install path is fine as long as `codex` is on `PATH`: `npm i -g @openai/codex`, `brew install --cask codex`, or an official release binary.
|
|
76
|
+
|
|
74
77
|
</details>
|
|
75
78
|
|
|
76
79
|
<details>
|
|
@@ -105,6 +108,13 @@ npm i -g codex-multi-auth
|
|
|
105
108
|
codex auth login
|
|
106
109
|
```
|
|
107
110
|
|
|
111
|
+
If you already installed the official native CLI via Homebrew or a release binary, you only need:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
npm i -g codex-multi-auth
|
|
115
|
+
codex auth login
|
|
116
|
+
```
|
|
117
|
+
|
|
108
118
|
Verify the wrapper and the new account:
|
|
109
119
|
|
|
110
120
|
```bash
|
|
@@ -147,6 +157,7 @@ If browser launch is blocked, use the alternate login paths in [docs/getting-sta
|
|
|
147
157
|
| Command | What it answers |
|
|
148
158
|
| --- | --- |
|
|
149
159
|
| `codex auth verify-flagged` | Can any previously flagged account be restored? |
|
|
160
|
+
| `codex auth verify --paths` | Do my storage path chain and sandbox probes still pass self-test? |
|
|
150
161
|
| `codex auth fix --dry-run` | What safe storage or account repairs are available? |
|
|
151
162
|
| `codex auth doctor --fix` | Can the CLI diagnose and apply the safest fixes now? |
|
|
152
163
|
|
|
@@ -156,6 +167,7 @@ If browser launch is blocked, use the alternate login paths in [docs/getting-sta
|
|
|
156
167
|
| --- | --- |
|
|
157
168
|
| `codex auth report --live --json` | How do I get the full machine-readable health report? |
|
|
158
169
|
| `codex auth fix --live --model gpt-5-codex` | How do I run live repair probes with a chosen model? |
|
|
170
|
+
| `codex auth why-selected --json` | Which account does the selector pick now, and why? |
|
|
159
171
|
|
|
160
172
|
### Reliability behavior
|
|
161
173
|
|
|
@@ -163,7 +175,7 @@ If browser launch is blocked, use the alternate login paths in [docs/getting-sta
|
|
|
163
175
|
- active requests use a bounded outbound request budget so one prompt cannot walk the full pool indefinitely
|
|
164
176
|
- repeated cross-account 5xx bursts trigger a short cooldown instead of continuing aggressive rotation
|
|
165
177
|
- proactive refresh is staggered to reduce background refresh bursts
|
|
166
|
-
- `codex auth status` surfaces recent runtime request metrics in text output, and `codex auth report --json` exposes the machine-readable cooldown/runtime snapshot
|
|
178
|
+
- `codex auth status` surfaces recent runtime request metrics in text output, and `codex auth report --json` exposes the machine-readable cooldown/runtime snapshot
|
|
167
179
|
|
|
168
180
|
---
|
|
169
181
|
|
|
@@ -196,12 +208,12 @@ If browser launch is blocked, use the alternate login paths in [docs/getting-sta
|
|
|
196
208
|
| File | Default path |
|
|
197
209
|
| --- | --- |
|
|
198
210
|
| Settings | `~/.codex/multi-auth/settings.json` |
|
|
199
|
-
| Accounts | `~/.codex/multi-auth/openai-codex-accounts.json` |
|
|
200
|
-
| Flagged accounts | `~/.codex/multi-auth/openai-codex-flagged-accounts.json` |
|
|
201
|
-
| Quota cache | `~/.codex/multi-auth/quota-cache.json` |
|
|
202
|
-
| Runtime observability | `~/.codex/multi-auth/runtime-observability.json` |
|
|
203
|
-
| Logs | `~/.codex/multi-auth/logs/codex-plugin/` |
|
|
204
|
-
| Per-project accounts | `~/.codex/multi-auth/projects/<project-key>/openai-codex-accounts.json` |
|
|
211
|
+
| Accounts | `~/.codex/multi-auth/openai-codex-accounts.json` |
|
|
212
|
+
| Flagged accounts | `~/.codex/multi-auth/openai-codex-flagged-accounts.json` |
|
|
213
|
+
| Quota cache | `~/.codex/multi-auth/quota-cache.json` |
|
|
214
|
+
| Runtime observability | `~/.codex/multi-auth/runtime-observability.json` |
|
|
215
|
+
| Logs | `~/.codex/multi-auth/logs/codex-plugin/` |
|
|
216
|
+
| Per-project accounts | `~/.codex/multi-auth/projects/<project-key>/openai-codex-accounts.json` |
|
|
205
217
|
|
|
206
218
|
Override root with `CODEX_MULTI_AUTH_DIR=<path>`.
|
|
207
219
|
|
|
@@ -273,12 +285,12 @@ codex auth login
|
|
|
273
285
|
<details>
|
|
274
286
|
<summary><b>Common symptoms</b></summary>
|
|
275
287
|
|
|
276
|
-
- `codex auth` unrecognized: run `where codex`, then follow `docs/troubleshooting.md` for routing fallback commands
|
|
288
|
+
- `codex auth` unrecognized: run `where codex` or `which codex`, then follow `docs/troubleshooting.md` for routing fallback commands
|
|
277
289
|
- Switch succeeds but wrong account appears active: run `codex auth switch <index>`, then restart session
|
|
278
|
-
- Requests fail fast with a pool cooldown message: wait for the cooldown window or inspect `codex auth status`
|
|
279
|
-
- Requests fail fast after repeated upstream 5xx errors: inspect `codex auth report --json` for runtime traffic and cooldown details
|
|
280
|
-
- Storage cleanup fails with `EBUSY` / `EPERM` (Windows): run `codex auth doctor --fix` to retry, or manually remove `~/.codex/multi-auth/<project-key>/` and re-login
|
|
281
|
-
- OAuth callback on port `1455` fails: free the port and re-run `codex auth login`
|
|
290
|
+
- Requests fail fast with a pool cooldown message: wait for the cooldown window or inspect `codex auth status`
|
|
291
|
+
- Requests fail fast after repeated upstream 5xx errors: inspect `codex auth report --json` for runtime traffic and cooldown details
|
|
292
|
+
- Storage cleanup fails with `EBUSY` / `EPERM` (Windows): run `codex auth doctor --fix` to retry, or manually remove `~/.codex/multi-auth/<project-key>/` and re-login
|
|
293
|
+
- OAuth callback on port `1455` fails: free the port and re-run `codex auth login`
|
|
282
294
|
- Browser launch is blocked or you are in a headless shell: re-run `codex auth login --manual` or set `CODEX_AUTH_NO_BROWSER=1`
|
|
283
295
|
- `missing field id_token` / `token_expired` / `refresh_token_reused`: re-login affected account
|
|
284
296
|
|
|
@@ -321,10 +333,10 @@ codex auth doctor --json
|
|
|
321
333
|
|
|
322
334
|
## Release Notes
|
|
323
335
|
|
|
324
|
-
- Current stable: [docs/releases/v1.
|
|
325
|
-
-
|
|
326
|
-
-
|
|
327
|
-
-
|
|
336
|
+
- Current stable: [docs/releases/v1.3.0.md](docs/releases/v1.3.0.md)
|
|
337
|
+
- Previous stable: [docs/releases/v1.2.6.md](docs/releases/v1.2.6.md)
|
|
338
|
+
- Earlier stable: [docs/releases/v1.2.5.md](docs/releases/v1.2.5.md)
|
|
339
|
+
- Full release archive: [docs/README.md#release-history](docs/README.md#release-history)
|
|
328
340
|
- Archived prerelease: [docs/releases/v0.1.0-beta.0.md](docs/releases/v0.1.0-beta.0.md)
|
|
329
341
|
|
|
330
342
|
## License
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,kBAAkB,CAAC;AAwR5D;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,iBAAiB,EAAE,MA+hI/B,CAAC;AAEF,eAAO,MAAM,gBAAgB,KAAoB,CAAC;AAElD,eAAe,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
import { tool } from "@codex-ai/plugin/tool";
|
|
26
26
|
import { AccountManager, extractAccountEmail, extractAccountId, formatAccountLabel, formatCooldown, formatWaitTime, getAccountIdCandidates, isCodexCliSyncEnabled, lookupCodexCliTokensByEmail, parseRateLimitReason, resolveRequestAccountId, resolveRuntimeRequestIdentity, sanitizeEmail, selectBestAccountCandidate, shouldUpdateAccountIdFromToken, } from "./lib/accounts.js";
|
|
27
27
|
import { createAuthorizationFlow, exchangeAuthorizationCode, parseAuthorizationInput, redactOAuthUrlForLog, REDIRECT_URI, } from "./lib/auth/auth.js";
|
|
28
|
-
import { isBrowserLaunchSuppressed, openBrowserUrl } from "./lib/auth/browser.js";
|
|
28
|
+
import { isBrowserLaunchSuppressed, openBrowserUrl, } from "./lib/auth/browser.js";
|
|
29
29
|
import { startLocalOAuthServer } from "./lib/auth/server.js";
|
|
30
30
|
import { checkAndNotify } from "./lib/auto-update-checker.js";
|
|
31
31
|
import { CapabilityPolicyStore } from "./lib/capability-policy.js";
|
|
@@ -74,7 +74,7 @@ import { buildLoginMenuAccounts } from "./lib/runtime/login-menu-accounts.js";
|
|
|
74
74
|
import { ensureLiveAccountSyncEntry } from "./lib/runtime/live-sync-entry.js";
|
|
75
75
|
import { applyLoaderRuntimeSetup } from "./lib/runtime/loader-setup.js";
|
|
76
76
|
import { buildManualOAuthFlow } from "./lib/runtime/manual-oauth-flow.js";
|
|
77
|
-
import { applyPreemptiveQuotaSettingsFromConfig
|
|
77
|
+
import { applyPreemptiveQuotaSettingsFromConfig } from "./lib/runtime/quota-settings.js";
|
|
78
78
|
import { ensureLiveAccountSyncState, ensureRefreshGuardianState, ensureSessionAffinityState, } from "./lib/runtime/runtime-services.js";
|
|
79
79
|
import { mutateRuntimeObservabilitySnapshot } from "./lib/runtime/runtime-observability.js";
|
|
80
80
|
import { applyAccountStorageScopeFromConfig } from "./lib/runtime/storage-scope.js";
|
|
@@ -88,7 +88,7 @@ import { clearAccounts, clearFlaggedAccounts, exportAccounts, findMatchingAccoun
|
|
|
88
88
|
import { buildTableHeader, buildTableRow, } from "./lib/table-formatter.js";
|
|
89
89
|
import { createHashlineEditTool, createHashlineReadTool, } from "./lib/tools/hashline-tools.js";
|
|
90
90
|
import { formatUiBadge, formatUiHeader, formatUiItem, formatUiKeyValue, formatUiSection, paintUiText, } from "./lib/ui/format.js";
|
|
91
|
-
import { setUiRuntimeOptions
|
|
91
|
+
import { setUiRuntimeOptions } from "./lib/ui/runtime.js";
|
|
92
92
|
/**
|
|
93
93
|
* OpenAI Codex OAuth authentication plugin for Codex CLI host runtime
|
|
94
94
|
*
|
|
@@ -191,13 +191,9 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
191
191
|
const burstRemaining = getServerBurstCooldownRemaining(now);
|
|
192
192
|
snapshot.currentRequestId = requestId;
|
|
193
193
|
snapshot.poolExhaustionCooldownUntil =
|
|
194
|
-
poolRemaining > 0
|
|
195
|
-
? now + poolRemaining
|
|
196
|
-
: null;
|
|
194
|
+
poolRemaining > 0 ? now + poolRemaining : null;
|
|
197
195
|
snapshot.serverBurstCooldownUntil =
|
|
198
|
-
burstRemaining > 0
|
|
199
|
-
? now + burstRemaining
|
|
200
|
-
: null;
|
|
196
|
+
burstRemaining > 0 ? now + burstRemaining : null;
|
|
201
197
|
snapshot.responsesRequests = runtimeMetrics.responsesRequests;
|
|
202
198
|
snapshot.authRefreshRequests = runtimeMetrics.authRefreshRequests;
|
|
203
199
|
snapshot.diagnosticProbeRequests = runtimeMetrics.diagnosticProbeRequests;
|
|
@@ -300,8 +296,7 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
300
296
|
});
|
|
301
297
|
refreshGuardian = next.refreshGuardian;
|
|
302
298
|
refreshGuardianConfigKey = next.refreshGuardianConfigKey;
|
|
303
|
-
refreshGuardianCleanupRegistered =
|
|
304
|
-
next.refreshGuardianCleanupRegistered;
|
|
299
|
+
refreshGuardianCleanupRegistered = next.refreshGuardianCleanupRegistered;
|
|
305
300
|
};
|
|
306
301
|
const ensureSessionAffinity = (pluginConfig) => {
|
|
307
302
|
const next = ensureSessionAffinityState({
|
|
@@ -593,7 +588,12 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
593
588
|
error: {
|
|
594
589
|
message: `The account pool is cooling down after recent rate-limit exhaustion. Try again in ${formatWaitTime(poolCooldownRemainingMs)} or inspect \`codex auth status\`.`,
|
|
595
590
|
},
|
|
596
|
-
}), {
|
|
591
|
+
}), {
|
|
592
|
+
status: 429,
|
|
593
|
+
headers: {
|
|
594
|
+
"content-type": "application/json; charset=utf-8",
|
|
595
|
+
},
|
|
596
|
+
});
|
|
597
597
|
}
|
|
598
598
|
const serverBurstCooldownRemainingMs = getServerBurstCooldownRemaining();
|
|
599
599
|
if (serverBurstCooldownRemainingMs > 0) {
|
|
@@ -605,7 +605,12 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
605
605
|
error: {
|
|
606
606
|
message: `Multiple accounts recently failed with upstream server errors. Try again in ${formatWaitTime(serverBurstCooldownRemainingMs)} or inspect \`codex auth report --json\`.`,
|
|
607
607
|
},
|
|
608
|
-
}), {
|
|
608
|
+
}), {
|
|
609
|
+
status: 503,
|
|
610
|
+
headers: {
|
|
611
|
+
"content-type": "application/json; charset=utf-8",
|
|
612
|
+
},
|
|
613
|
+
});
|
|
609
614
|
}
|
|
610
615
|
const maxOutboundRequestAttempts = computeOutboundRequestAttemptBudget({
|
|
611
616
|
accountCount: accountManager.getAccountCount(),
|
|
@@ -628,8 +633,7 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
628
633
|
const tryConsumeOutboundRequestAttempt = (reason, accountIndex) => {
|
|
629
634
|
if (outboundRequestAttemptsRemaining <= 0) {
|
|
630
635
|
runtimeMetrics.requestAttemptBudgetExhaustions += 1;
|
|
631
|
-
runtimeMetrics.lastError =
|
|
632
|
-
`Request attempt budget exhausted after ${maxOutboundRequestAttempts} outbound request(s)`;
|
|
636
|
+
runtimeMetrics.lastError = `Request attempt budget exhausted after ${maxOutboundRequestAttempts} outbound request(s)`;
|
|
633
637
|
logWarn("Request attempt budget exhausted.", {
|
|
634
638
|
requestTraceId,
|
|
635
639
|
reason,
|
|
@@ -730,7 +734,8 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
730
734
|
if (retryableRefreshPolicy.recordFailure) {
|
|
731
735
|
accountManager.recordFailure(account, modelFamily, model);
|
|
732
736
|
}
|
|
733
|
-
if (typeof retryableRefreshPolicy.cooldownMs ===
|
|
737
|
+
if (typeof retryableRefreshPolicy.cooldownMs ===
|
|
738
|
+
"number" &&
|
|
734
739
|
retryableRefreshPolicy.cooldownReason) {
|
|
735
740
|
accountManager.markAccountCoolingDown(account, retryableRefreshPolicy.cooldownMs, retryableRefreshPolicy.cooldownReason);
|
|
736
741
|
accountManager.saveToDiskDebounced();
|
|
@@ -1224,10 +1229,18 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
1224
1229
|
preemptiveQuotaScheduler.markRateLimited(quotaScheduleKey, cooldownMs);
|
|
1225
1230
|
const waitLabel = formatWaitTime(cooldownMs);
|
|
1226
1231
|
const shortRetryThresholdMs = getConfiguredRateLimitShortRetryThresholdMs();
|
|
1227
|
-
if (cooldownMs <=
|
|
1228
|
-
shortRetryThresholdMs &&
|
|
1232
|
+
if (cooldownMs <= shortRetryThresholdMs &&
|
|
1229
1233
|
shortRateLimitRetryCount < MAX_SHORT_RETRY_ATTEMPTS) {
|
|
1230
1234
|
shortRateLimitRetryCount += 1;
|
|
1235
|
+
// Mark the account unavailable BEFORE we sleep so
|
|
1236
|
+
// concurrent in-flight requests do not select the
|
|
1237
|
+
// same freshly rate-limited account during the retry
|
|
1238
|
+
// window. Without this, the fetch loop amplifies the
|
|
1239
|
+
// throttling pressure instead of spreading load.
|
|
1240
|
+
// The current request will continue after the sleep
|
|
1241
|
+
// regardless of the cooldown mark (AUDIT-H3 / D-07).
|
|
1242
|
+
accountManager.markRateLimitedWithReason(account, cooldownMs, modelFamily, parseRateLimitReason(rateLimit?.code), model);
|
|
1243
|
+
accountManager.recordRateLimit(account, modelFamily, model);
|
|
1231
1244
|
if (accountManager.shouldShowAccountToast(account.index, rateLimitToastDebounceMs)) {
|
|
1232
1245
|
await showRuntimeToast(client, `Rate limited. Retrying in ${waitLabel} (attempt ${shortRateLimitRetryCount})...`, "warning", { duration: toastDurationMs });
|
|
1233
1246
|
accountManager.markToastShown(account.index);
|
|
@@ -1382,7 +1395,7 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
1382
1395
|
preemptiveQuotaScheduler.update(`${fallbackEntitlementAccountKey}:${model ?? modelFamily}`, fallbackSnapshot);
|
|
1383
1396
|
}
|
|
1384
1397
|
if (!fallbackResponse.ok) {
|
|
1385
|
-
const { response: handledFallbackResponse, rateLimit: fallbackRateLimit } = await handleErrorResponse(fallbackResponse);
|
|
1398
|
+
const { response: handledFallbackResponse, rateLimit: fallbackRateLimit, } = await handleErrorResponse(fallbackResponse);
|
|
1386
1399
|
try {
|
|
1387
1400
|
await fallbackResponse.body?.cancel();
|
|
1388
1401
|
}
|
|
@@ -1391,7 +1404,9 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
1391
1404
|
}
|
|
1392
1405
|
if (handledFallbackResponse.status === 429) {
|
|
1393
1406
|
const retryAfterMs = fallbackRateLimit?.retryAfterMs ?? 60_000;
|
|
1394
|
-
const fallbackQuotaKey = model
|
|
1407
|
+
const fallbackQuotaKey = model
|
|
1408
|
+
? `${modelFamily}:${model}`
|
|
1409
|
+
: modelFamily;
|
|
1395
1410
|
const { delayMs } = getRateLimitBackoff(fallbackAccount.index, fallbackQuotaKey, retryAfterMs);
|
|
1396
1411
|
const cooldownMs = Math.max(delayMs, retryAfterMs);
|
|
1397
1412
|
preemptiveQuotaScheduler.markRateLimited(`${fallbackEntitlementAccountKey}:${model ?? modelFamily}`, cooldownMs);
|
|
@@ -1502,7 +1517,12 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
1502
1517
|
error: {
|
|
1503
1518
|
message: `Upstream server failures were observed across multiple accounts. Pausing retries for ${formatWaitTime(serverBurstCooldownUntil - Date.now())}. Check \`codex auth report --json\` for runtime metrics.`,
|
|
1504
1519
|
},
|
|
1505
|
-
}), {
|
|
1520
|
+
}), {
|
|
1521
|
+
status: 503,
|
|
1522
|
+
headers: {
|
|
1523
|
+
"content-type": "application/json; charset=utf-8",
|
|
1524
|
+
},
|
|
1525
|
+
});
|
|
1506
1526
|
}
|
|
1507
1527
|
}
|
|
1508
1528
|
logWarn(`Empty response after ${emptyResponseMaxRetries} retries. Returning as-is.`);
|