oc-codex-multi-auth 6.14.2 → 6.14.3
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/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -13
- package/dist/index.js.map +1 -1
- package/dist/lib/accounts/rate-limits.d.ts +11 -0
- package/dist/lib/accounts/rate-limits.d.ts.map +1 -1
- package/dist/lib/accounts/rate-limits.js +19 -2
- package/dist/lib/accounts/rate-limits.js.map +1 -1
- package/dist/lib/accounts/rotation.d.ts +33 -2
- package/dist/lib/accounts/rotation.d.ts.map +1 -1
- package/dist/lib/accounts/rotation.js +38 -3
- package/dist/lib/accounts/rotation.js.map +1 -1
- package/dist/lib/quota-windows.d.ts +17 -0
- package/dist/lib/quota-windows.d.ts.map +1 -1
- package/dist/lib/quota-windows.js +38 -3
- package/dist/lib/quota-windows.js.map +1 -1
- package/dist/lib/request/fetch-helpers.d.ts +5 -0
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
- package/dist/lib/request/fetch-helpers.js +57 -19
- package/dist/lib/request/fetch-helpers.js.map +1 -1
- package/dist/lib/rotation.d.ts.map +1 -1
- package/dist/lib/rotation.js +6 -1
- package/dist/lib/rotation.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAMH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAsU/D;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAMH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAsU/D;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,iBAAiB,EAAE,MAq8H/B,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAoB,CAAC;AAElD,eAAe,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -429,26 +429,43 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
429
429
|
* Take an account out of rotation whenever the backend reports one of its
|
|
430
430
|
* quota windows as fully spent (issue #218).
|
|
431
431
|
*
|
|
432
|
-
*
|
|
433
|
-
* and
|
|
434
|
-
* can record it instead of rediscovering it with a failed request
|
|
435
|
-
* subsequent prompt. The block lands on the persisted
|
|
436
|
-
* map, so it is remembered across restarts and shared
|
|
437
|
-
* and it clears itself once the window rolls over.
|
|
432
|
+
* Codex carries `x-codex-*-used-percent` and the matching reset time on a
|
|
433
|
+
* served request and on a refused one alike, so the moment an account hits
|
|
434
|
+
* 0% left we can record it instead of rediscovering it with a failed request
|
|
435
|
+
* on every subsequent prompt. The block lands on the persisted
|
|
436
|
+
* `rateLimitResetTimes` map, so it is remembered across restarts and shared
|
|
437
|
+
* with other processes, and it clears itself once the window rolls over.
|
|
438
|
+
*
|
|
439
|
+
* Call this only for responses whose headers are authoritative: one the
|
|
440
|
+
* backend served, or one it refused for a confirmed usage limit. Every other
|
|
441
|
+
* error class — entitlement (issues #16/#17), auth, 5xx, or an upstream
|
|
442
|
+
* overload dressed up as a 429 — can echo a stale quota snapshot next to an
|
|
443
|
+
* unrelated failure, and writing that echo locked healthy accounts out for
|
|
444
|
+
* hours. `handleErrorResponse` makes that call once and reports it back as
|
|
445
|
+
* `quotaHeadersAuthoritative`.
|
|
446
|
+
*
|
|
447
|
+
* The resulting gap is deliberate: an account that really is spent but gets
|
|
448
|
+
* a 5xx stays selectable until its next genuine 429, which costs one wasted
|
|
449
|
+
* request — cheaper than a false multi-hour block on a healthy account.
|
|
450
|
+
*
|
|
451
|
+
* @returns true when the headers report a spent window, whether or not the
|
|
452
|
+
* stored block moved. Callers use it to stop retrying this account.
|
|
438
453
|
*/
|
|
439
454
|
const applyQuotaExhaustion = (manager, headers, account, family, model) => {
|
|
440
455
|
try {
|
|
441
456
|
const resetAtMs = getQuotaExhaustedResetAtMs(headers);
|
|
442
457
|
if (resetAtMs === undefined)
|
|
443
|
-
return;
|
|
458
|
+
return false;
|
|
444
459
|
if (!manager.markQuotaExhausted(account, resetAtMs, family, model))
|
|
445
|
-
return;
|
|
460
|
+
return true;
|
|
446
461
|
account.lastSwitchReason = "rate-limit";
|
|
447
462
|
manager.saveToDiskDebounced();
|
|
448
463
|
logWarn(`Account ${account.index + 1} (${account.email ?? "unknown"}) has no ${family} quota left; skipping it for ${formatWaitTime(resetAtMs - Date.now())}.`);
|
|
464
|
+
return true;
|
|
449
465
|
}
|
|
450
466
|
catch (error) {
|
|
451
467
|
logDebug(`[${PLUGIN_NAME}] Failed to apply quota exhaustion: ${error instanceof Error ? error.message : String(error)}`);
|
|
468
|
+
return false;
|
|
452
469
|
}
|
|
453
470
|
};
|
|
454
471
|
const resolveActiveIndex = (storage, family = "codex") => {
|
|
@@ -1937,17 +1954,27 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
1937
1954
|
latencyMs: fetchLatencyMs,
|
|
1938
1955
|
headers: Object.fromEntries(response.headers.entries()),
|
|
1939
1956
|
});
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1957
|
+
// The TUI snapshot and the durable rotation block read the same
|
|
1958
|
+
// `x-codex-*` headers, so they share one authority decision — gating
|
|
1959
|
+
// only the block would leave the status line reporting "0% left" for
|
|
1960
|
+
// an account the router considers healthy.
|
|
1961
|
+
const recordQuotaHeaders = () => {
|
|
1962
|
+
void recordPromptQuotaHeaders(response, account, accountCount);
|
|
1963
|
+
return applyQuotaExhaustion(accountManager, response.headers, account, modelFamily, model);
|
|
1964
|
+
};
|
|
1965
|
+
if (response.ok) {
|
|
1966
|
+
recordQuotaHeaders();
|
|
1967
|
+
}
|
|
1968
|
+
else {
|
|
1943
1969
|
const contextOverflowResult = await handleContextOverflow(response, model);
|
|
1944
1970
|
if (contextOverflowResult.handled) {
|
|
1945
1971
|
return contextOverflowResult.response;
|
|
1946
1972
|
}
|
|
1947
|
-
const { response: errorResponse, rateLimit, errorBody, retryAsServerError } = await handleErrorResponse(response, {
|
|
1973
|
+
const { response: errorResponse, rateLimit, errorBody, retryAsServerError, quotaHeadersAuthoritative, } = await handleErrorResponse(response, {
|
|
1948
1974
|
requestCorrelationId,
|
|
1949
1975
|
threadId: threadIdCandidate,
|
|
1950
1976
|
});
|
|
1977
|
+
const quotaExhausted = quotaHeadersAuthoritative === true && recordQuotaHeaders();
|
|
1951
1978
|
const workspaceDeactivated = isDeactivatedWorkspaceError(errorBody, response.status);
|
|
1952
1979
|
if (workspaceDeactivated) {
|
|
1953
1980
|
const accountLabel = formatAccountLabel(account, account.index, {
|
|
@@ -2190,7 +2217,12 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
2190
2217
|
runtimeMetrics.rateLimitedResponses++;
|
|
2191
2218
|
const { attempt, delayMs } = getRateLimitBackoff(account.index, quotaKey, rateLimit.retryAfterMs);
|
|
2192
2219
|
const waitLabel = formatWaitTime(delayMs);
|
|
2193
|
-
|
|
2220
|
+
// A spent window will still be spent in a second, and the block
|
|
2221
|
+
// just written for it is monotonic — a short retry that happened
|
|
2222
|
+
// to succeed could not walk it back, so the account would serve
|
|
2223
|
+
// traffic while rotation still considers it blocked. Rotate.
|
|
2224
|
+
if (!quotaExhausted &&
|
|
2225
|
+
delayMs <= RATE_LIMIT_SHORT_RETRY_THRESHOLD_MS &&
|
|
2194
2226
|
consumeRetryBudget("rateLimitShort", `Short 429 retry for account ${account.index + 1} after ${delayMs}ms`)) {
|
|
2195
2227
|
if (accountManager.shouldShowAccountToast(account.index, rateLimitToastDebounceMs)) {
|
|
2196
2228
|
await showToast(`Rate limited. Retrying in ${waitLabel} (attempt ${attempt})...`, "warning", { duration: toastDurationMs });
|