codex-multi-auth 2.8.5 → 2.8.6

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-multi-auth",
3
- "version": "2.8.5",
3
+ "version": "2.8.6",
4
4
  "description": "Install and operate codex-multi-auth for the official @openai/codex CLI with multi-account OAuth rotation, switching, health checks, and recovery tools.",
5
5
  "interface": {
6
6
  "composerIcon": "./assets/codex-multi-auth-icon.svg"
package/README.md CHANGED
@@ -392,7 +392,7 @@ codex-multi-auth doctor --json
392
392
 
393
393
  ## Release Notes
394
394
 
395
- - Current stable: [docs/releases/v2.8.5.md](docs/releases/v2.8.5.md) — install via `npm i -g codex-multi-auth`
395
+ - Current stable: [docs/releases/v2.8.6.md](docs/releases/v2.8.6.md) — install via `npm i -g codex-multi-auth`
396
396
  - Previous stable: [docs/releases/v2.8.3.md](docs/releases/v2.8.3.md)
397
397
  - Previous stable: [docs/releases/v2.8.2.md](docs/releases/v2.8.2.md)
398
398
  - Previous stable: [docs/releases/v2.7.1.md](docs/releases/v2.7.1.md)
@@ -193,6 +193,13 @@ export declare class AccountManager {
193
193
  isAccountCoolingDown(account: ManagedAccount): boolean;
194
194
  clearAccountCooldown(account: ManagedAccount): void;
195
195
  private isCircuitAvailable;
196
+ /**
197
+ * When the account's circuit breaker will admit an attempt again, as an
198
+ * epoch-ms deadline — null when it already would. Lets the pinned-503
199
+ * recovery metadata cover circuit-open skips, whose deadline lives in the
200
+ * breaker rather than the persisted account record.
201
+ */
202
+ getCircuitRecoveryTime(account: ManagedAccount, now?: number): number | null;
196
203
  incrementAuthFailures(account: ManagedAccount): number;
197
204
  clearAuthFailures(account: ManagedAccount): void;
198
205
  markAuthInvalidated(account: ManagedAccount, errorCode?: string, invalidatedAt?: number): void;
@@ -1 +1 @@
1
- {"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../lib/accounts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../lib/accounts.ts"],"names":[],"mappings":"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"}
@@ -926,6 +926,16 @@ export class AccountManager {
926
926
  isCircuitAvailable(account) {
927
927
  return getCircuitBreaker(getAccountCircuitKey(account)).isAvailable();
928
928
  }
929
+ /**
930
+ * When the account's circuit breaker will admit an attempt again, as an
931
+ * epoch-ms deadline — null when it already would. Lets the pinned-503
932
+ * recovery metadata cover circuit-open skips, whose deadline lives in the
933
+ * breaker rather than the persisted account record.
934
+ */
935
+ getCircuitRecoveryTime(account, now = Date.now()) {
936
+ const waitMs = getCircuitBreaker(getAccountCircuitKey(account)).getTimeUntilAvailable(now);
937
+ return waitMs > 0 ? now + waitMs : null;
938
+ }
929
939
  incrementAuthFailures(account) {
930
940
  account.consecutiveAuthFailures =
931
941
  (account.consecutiveAuthFailures ?? 0) + 1;
@@ -1,5 +1,6 @@
1
1
  import type { ForecastAccountResult } from "../../forecast.js";
2
2
  import { type CodexQuotaSnapshot } from "../../quota-probe.js";
3
+ import { type ModelFamily } from "../../request/helpers/model-map.js";
3
4
  import type { AccountStorageV3 } from "../../storage.js";
4
5
  import type { TokenFailure, TokenResult } from "../../types.js";
5
6
  export interface BestCliOptions {
@@ -56,6 +57,8 @@ export interface BestCommandDeps {
56
57
  now: number;
57
58
  refreshFailure?: TokenFailure;
58
59
  liveQuota?: CodexQuotaSnapshot;
60
+ family?: ModelFamily;
61
+ model?: string | null;
59
62
  }>) => ForecastAccountResult[];
60
63
  recommendForecastAccount: (results: ForecastAccountResult[]) => {
61
64
  recommendedIndex: number | null;
@@ -1 +1 @@
1
- {"version":3,"file":"best.d.ts","sourceRoot":"","sources":["../../../../lib/codex-manager/commands/best.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"best.d.ts","sourceRoot":"","sources":["../../../../lib/codex-manager/commands/best.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { describeCodexProbeFailure } from "../../quota-probe.js";
2
- import { resolveNormalizedModel } from "../../request/helpers/model-map.js";
2
+ import { getModelProfile, resolveNormalizedModel, } from "../../request/helpers/model-map.js";
3
3
  import { DEFAULT_LIVE_PROBE_MODEL } from "../quota-cache-helpers.js";
4
4
  /**
5
5
  * Usage text and argument parsing for `best`. Previously module-private in
@@ -173,6 +173,13 @@ export async function runBestCommand(args, deps) {
173
173
  probeErrors.push(`${deps.formatAccountLabel(account, i)}: ${message}`);
174
174
  }
175
175
  }
176
+ // Only an explicit --model moves the recommendation off the codex family;
177
+ // see the note in the forecast command. `best` exists to pick the account
178
+ // for wrapper traffic, which is codex-family.
179
+ const forecastFamily = options.modelProvided
180
+ ? getModelProfile(probeModel).promptFamily
181
+ : undefined;
182
+ const forecastModel = options.modelProvided ? probeModel : undefined;
176
183
  const forecastInputs = storage.accounts.map((account, index) => ({
177
184
  index,
178
185
  account,
@@ -180,6 +187,8 @@ export async function runBestCommand(args, deps) {
180
187
  now,
181
188
  refreshFailure: refreshFailures.get(index),
182
189
  liveQuota: liveQuotaByIndex.get(index),
190
+ family: forecastFamily,
191
+ model: forecastModel,
183
192
  }));
184
193
  const forecastResults = deps.evaluateForecastAccounts(forecastInputs);
185
194
  const recommendation = deps.recommendForecastAccount(forecastResults);
@@ -2,6 +2,7 @@ import type { DashboardDisplaySettings } from "../../dashboard-settings.js";
2
2
  import { type ForecastAccountResult, type RuntimeForecastOverlay } from "../../forecast.js";
3
3
  import type { QuotaCacheData } from "../../quota-cache.js";
4
4
  import { type CodexQuotaSnapshot } from "../../quota-probe.js";
5
+ import { type ModelFamily } from "../../request/helpers/model-map.js";
5
6
  import { type AccountMetadataV3, type AccountStorageV3 } from "../../storage.js";
6
7
  import type { TokenFailure, TokenResult } from "../../types.js";
7
8
  type PromptTone = "accent" | "success" | "warning" | "danger" | "muted";
@@ -40,6 +41,8 @@ export interface ForecastCommandDeps {
40
41
  quotaCache?: QuotaCacheData | null;
41
42
  allAccounts?: readonly AccountMetadataV3[];
42
43
  runtimeOverlay?: RuntimeForecastOverlay | null;
44
+ family?: ModelFamily;
45
+ model?: string | null;
43
46
  }>) => ForecastAccountResult[];
44
47
  summarizeForecast: (results: ForecastAccountResult[]) => {
45
48
  total: number;
@@ -1 +1 @@
1
- {"version":3,"file":"forecast.d.ts","sourceRoot":"","sources":["../../../../lib/codex-manager/commands/forecast.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"forecast.d.ts","sourceRoot":"","sources":["../../../../lib/codex-manager/commands/forecast.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@ import { extractAccountEmail, sanitizeEmail } from "../../accounts.js";
2
2
  import { buildForecastExplanation, } from "../../forecast.js";
3
3
  import { applyRefreshedAccountPatch, persistRefreshedAccountPatch, serializeForecastResults, } from "../forecast-report-shared.js";
4
4
  import { describeCodexProbeFailure } from "../../quota-probe.js";
5
- import { DEFAULT_PROBE_MODEL, resolveNormalizedModel } from "../../request/helpers/model-map.js";
5
+ import { DEFAULT_PROBE_MODEL, getModelProfile, resolveNormalizedModel, } from "../../request/helpers/model-map.js";
6
6
  function joinStyledSegments(parts, styleText) {
7
7
  if (parts.length === 0)
8
8
  return "";
@@ -27,6 +27,7 @@ function parseForecastArgs(args) {
27
27
  json: false,
28
28
  explain: false,
29
29
  model: DEFAULT_PROBE_MODEL,
30
+ modelProvided: false,
30
31
  runtimeOverlay: true,
31
32
  };
32
33
  for (let i = 0; i < args.length; i += 1) {
@@ -55,6 +56,7 @@ function parseForecastArgs(args) {
55
56
  return { ok: false, message: "Missing value for --model" };
56
57
  }
57
58
  options.model = value;
59
+ options.modelProvided = true;
58
60
  i += 1;
59
61
  continue;
60
62
  }
@@ -64,6 +66,7 @@ function parseForecastArgs(args) {
64
66
  return { ok: false, message: "Missing value for --model" };
65
67
  }
66
68
  options.model = value;
69
+ options.modelProvided = true;
67
70
  continue;
68
71
  }
69
72
  return { ok: false, message: `Unknown option: ${arg}` };
@@ -195,6 +198,18 @@ export async function runForecastCommand(args, deps) {
195
198
  probeErrors.push(`${deps.formatAccountLabel(account, i)}: ${message}`);
196
199
  }
197
200
  }
201
+ // Only an explicit --model moves the forecast off the codex family. The
202
+ // default probe model is gpt-5.6-sol, whose family is gpt-5.2, so keying a
203
+ // bare `forecast` on it would evaluate every account against a family no
204
+ // wrapper request uses - /codex/responses buckets into codex.
205
+ //
206
+ // probeModel, not requestedModel: rate-limit records are keyed by the
207
+ // normalized model the proxy routes on. Resolved once rather than per
208
+ // account: getModelProfile re-parses the model string on every call.
209
+ const forecastFamily = options.modelProvided
210
+ ? getModelProfile(requestedModel).promptFamily
211
+ : undefined;
212
+ const forecastModel = options.modelProvided ? probeModel : undefined;
198
213
  const forecastInputs = storage.accounts.map((account, index) => ({
199
214
  index,
200
215
  account,
@@ -205,6 +220,8 @@ export async function runForecastCommand(args, deps) {
205
220
  quotaCache,
206
221
  allAccounts: storage.accounts,
207
222
  runtimeOverlay,
223
+ family: forecastFamily,
224
+ model: forecastModel,
208
225
  }));
209
226
  const forecastResults = deps.evaluateForecastAccounts(forecastInputs);
210
227
  const summary = deps.summarizeForecast(forecastResults);
@@ -1 +1 @@
1
- {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../../lib/codex-manager/commands/report.ts"],"names":[],"mappings":"AAoBA,OAAO,EACN,KAAK,kBAAkB,EAGvB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,EACN,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,wCAAwC,CAAC;AAC3F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAgB,WAAW,EAAE,MAAM,gBAAgB,CAAC;AA2ChE,MAAM,WAAW,iBAAiB;IACjC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC9C,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,YAAY,EAAE,MAAM,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACrD,YAAY,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,kBAAkB,EAAE,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,MAAM,CAAC;IAC5E,oBAAoB,EAAE,CACrB,OAAO,EAAE,IAAI,CAAC,iBAAiB,EAAE,aAAa,GAAG,WAAW,CAAC,EAC7D,GAAG,EAAE,MAAM,KACP,OAAO,CAAC;IACb,aAAa,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9D,uBAAuB,EAAE,CAAC,KAAK,EAAE;QAChC,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;KACd,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAClC,oBAAoB,EAAE,CACrB,OAAO,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,EAC7C,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,OAAO,KACX,MAAM,GAAG,IAAI,CAAC;IACnB,oBAAoB,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC3D,sBAAsB,EAAE,CACvB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,MAAM,EAAE,MAAM,GAAG,SAAS,KACtB,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,gCAAgC,CAAC,EAAE,MAAM,OAAO,CAAC,4BAA4B,GAAG,IAAI,CAAC,CAAC;IACtF,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;CACtD;AAoLD,wBAAsB,gBAAgB,CACrC,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,EAAE,iBAAiB,GACrB,OAAO,CAAC,MAAM,CAAC,CAmVjB"}
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../../lib/codex-manager/commands/report.ts"],"names":[],"mappings":"AAoBA,OAAO,EACN,KAAK,kBAAkB,EAGvB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,EACN,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,wCAAwC,CAAC;AAC3F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAgB,WAAW,EAAE,MAAM,gBAAgB,CAAC;AA6ChE,MAAM,WAAW,iBAAiB;IACjC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC9C,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,YAAY,EAAE,MAAM,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACrD,YAAY,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,kBAAkB,EAAE,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,MAAM,CAAC;IAC5E,oBAAoB,EAAE,CACrB,OAAO,EAAE,IAAI,CAAC,iBAAiB,EAAE,aAAa,GAAG,WAAW,CAAC,EAC7D,GAAG,EAAE,MAAM,KACP,OAAO,CAAC;IACb,aAAa,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9D,uBAAuB,EAAE,CAAC,KAAK,EAAE;QAChC,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;KACd,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAClC,oBAAoB,EAAE,CACrB,OAAO,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,EAC7C,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,OAAO,KACX,MAAM,GAAG,IAAI,CAAC;IACnB,oBAAoB,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC3D,sBAAsB,EAAE,CACvB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,MAAM,EAAE,MAAM,GAAG,SAAS,KACtB,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,gCAAgC,CAAC,EAAE,MAAM,OAAO,CAAC,4BAA4B,GAAG,IAAI,CAAC,CAAC;IACtF,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;CACtD;AAuLD,wBAAsB,gBAAgB,CACrC,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,EAAE,iBAAiB,GACrB,OAAO,CAAC,MAAM,CAAC,CA8VjB"}
@@ -44,6 +44,7 @@ function parseReportArgs(args) {
44
44
  json: false,
45
45
  explain: false,
46
46
  model: DEFAULT_PROBE_MODEL,
47
+ modelProvided: false,
47
48
  cachedOnly: false,
48
49
  };
49
50
  for (let i = 0; i < args.length; i += 1) {
@@ -72,6 +73,7 @@ function parseReportArgs(args) {
72
73
  return { ok: false, message: "Missing value for --model" };
73
74
  }
74
75
  options.model = value;
76
+ options.modelProvided = true;
75
77
  i += 1;
76
78
  continue;
77
79
  }
@@ -81,6 +83,7 @@ function parseReportArgs(args) {
81
83
  return { ok: false, message: "Missing value for --model" };
82
84
  }
83
85
  options.model = value;
86
+ options.modelProvided = true;
84
87
  continue;
85
88
  }
86
89
  if (arg === "--max-accounts") {
@@ -328,6 +331,15 @@ export async function runReportCommand(args, deps) {
328
331
  }
329
332
  }
330
333
  }
334
+ // Only an explicit --model moves the report off the codex family; see the
335
+ // note in the forecast command. promptFamily is reused from the inspection
336
+ // rather than re-resolved per account.
337
+ const forecastFamily = options.modelProvided
338
+ ? modelInspection.promptFamily
339
+ : undefined;
340
+ const forecastModel = options.modelProvided
341
+ ? modelInspection.normalized
342
+ : undefined;
331
343
  const forecastResults = storage
332
344
  ? evaluateForecastAccounts(storage.accounts.map((account, index) => ({
333
345
  index,
@@ -339,6 +351,8 @@ export async function runReportCommand(args, deps) {
339
351
  quotaCache,
340
352
  allAccounts: storage.accounts,
341
353
  runtimeOverlay: runtimeSnapshot,
354
+ family: forecastFamily,
355
+ model: forecastModel,
342
356
  })))
343
357
  : [];
344
358
  const forecastSummary = summarizeForecast(forecastResults);
@@ -1,5 +1,6 @@
1
1
  import type { CodexQuotaSnapshot } from "./quota-probe.js";
2
2
  import type { QuotaCacheData } from "./quota-cache.js";
3
+ import type { ModelFamily } from "./request/helpers/model-map.js";
3
4
  import type { AccountMetadataV3 } from "./storage.js";
4
5
  import type { TokenFailure } from "./types.js";
5
6
  type ForecastAvailability = "ready" | "delayed" | "unavailable";
@@ -14,6 +15,18 @@ export interface ForecastAccountInput {
14
15
  quotaCache?: QuotaCacheData | null;
15
16
  allAccounts?: readonly AccountMetadataV3[];
16
17
  runtimeOverlay?: RuntimeForecastOverlay | null;
18
+ /**
19
+ * Prompt family whose per-family rate-limit records gate this forecast.
20
+ * Callers with a model in hand resolve it via getModelProfile; the codex
21
+ * default preserves the historical behavior for model-less surfaces.
22
+ */
23
+ family?: ModelFamily;
24
+ /**
25
+ * Normalized model the forecast is about, when the caller has one. Selection
26
+ * keys token/concurrency limits under `family:<model>`, so without it a
27
+ * sibling model's record would be read as gating this one.
28
+ */
29
+ model?: string | null;
17
30
  }
18
31
  export interface RuntimeForecastOverlay {
19
32
  accountSkipReasons?: Record<string, string>;
@@ -1 +1 @@
1
- {"version":3,"file":"forecast.d.ts","sourceRoot":"","sources":["../../lib/forecast.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAOvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,KAAK,oBAAoB,GAAG,OAAO,GAAG,SAAS,GAAG,aAAa,CAAC;AAChE,KAAK,iBAAiB,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEnD,MAAM,WAAW,oBAAoB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,iBAAiB,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,UAAU,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC3C,cAAc,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAC;CAC/C;AAED,MAAM,WAAW,sBAAsB;IACtC,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,6BAA6B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvD,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,oBAAoB,CAAC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAKlB,SAAS,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACtC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;CACf;AAED,UAAU,0BAA0B;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,oBAAoB,CAAC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IACnC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,UAAU,EAAE,0BAA0B,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAuFD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAUnE;AAWD,wBAAgB,uBAAuB,CACtC,KAAK,EAAE,oBAAoB,GACzB,qBAAqB,CAmOvB;AAED,wBAAgB,wBAAwB,CACvC,MAAM,EAAE,oBAAoB,EAAE,GAC5B,qBAAqB,EAAE,CAEzB;AAkCD,wBAAgB,wBAAwB,CACvC,OAAO,EAAE,qBAAqB,EAAE,GAC9B,sBAAsB,CAuDxB;AAED,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,qBAAqB,EAAE,GAC9B,eAAe,CAWjB;AAED,wBAAgB,wBAAwB,CACvC,OAAO,EAAE,qBAAqB,EAAE,EAChC,cAAc,EAAE,sBAAsB,GACpC,mBAAmB,CAgBrB"}
1
+ {"version":3,"file":"forecast.d.ts","sourceRoot":"","sources":["../../lib/forecast.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { AUTH_INVALIDATION_MARKER, formatAccountLabel, formatWaitTime, } from "./accounts.js";
2
2
  import { findQuotaCacheEntryForAccount, isQuotaCacheEntryExhausted, quotaUsedPercentIsExhausted, } from "./quota-readiness.js";
3
- import { getRateLimitResetTimeForFamily } from "./runtime/account-status.js";
3
+ import { getRateLimitResetTimeForFamily, getRateLimitResetTimeForModel, } from "./runtime/account-status.js";
4
4
  function clampRisk(score) {
5
5
  if (!Number.isFinite(score))
6
6
  return 100;
@@ -132,7 +132,18 @@ export function evaluateForecastAccount(input) {
132
132
  riskScore += 45;
133
133
  appendWaitReason(reasons, "cooldown remaining", remaining);
134
134
  }
135
- const rateLimitResetAt = getRateLimitResetTimeForFamily(account, now, "codex");
135
+ // With a model in hand, gate on exactly the keys selection consults for that
136
+ // family/model pair, and on the LATEST of them: a sibling model's record does
137
+ // not gate this request, and while both the family-wide and model-scoped keys
138
+ // are active the account stays skipped until the later one expires.
139
+ //
140
+ // Without one (status, fix) no model key can be singled out, so keep the
141
+ // family-wide union - the conservative answer, and the behavior those
142
+ // surfaces have always had.
143
+ const forecastFamily = input.family ?? "codex";
144
+ const rateLimitResetAt = input.model
145
+ ? getRateLimitResetTimeForModel(account, now, forecastFamily, input.model)
146
+ : getRateLimitResetTimeForFamily(account, now, forecastFamily);
136
147
  if (typeof rateLimitResetAt === "number") {
137
148
  const remaining = Math.max(0, rateLimitResetAt - now);
138
149
  waitMs = Math.max(waitMs, remaining);
@@ -176,7 +187,11 @@ export function evaluateForecastAccount(input) {
176
187
  // drop the overlay reason when the condition it describes is no longer
177
188
  // active. Each reason validates only against its own backing disk state
178
189
  // ("rate-limited" -> rateLimitResetTimes, "cooling-down" -> coolingDownUntil)
179
- // so we never substitute a misleading reason string. Non-time-bounded
190
+ // so we never substitute a misleading reason string. The rate-limited
191
+ // cross-check inherits rateLimitResetAt's scope above: a record under one of
192
+ // the keys that actually gates this family/model request keeps the reason,
193
+ // while a record for another family - or another model in the same family -
194
+ // neither sustains it nor gates this request. Non-time-bounded
180
195
  // reasons ("circuit-open", "token-exhausted", "policy-blocked") have no disk
181
196
  // expiry to check and are always applied.
182
197
  const coolingDownActive = typeof account.coolingDownUntil === "number" &&
@@ -22,7 +22,25 @@ export interface PinnedUnavailableErrorBody {
22
22
  code: "codex_pinned_account_unavailable";
23
23
  pinnedAccountIndex: number | null;
24
24
  reason: string | null;
25
+ /** How the pin was set; forced pins are not cleared by `unpin`. */
26
+ pin_source: "forced" | "manual" | null;
27
+ /** When the blocking record ends, when the skip reason is time-bounded. */
28
+ reset_at: string | null;
29
+ retry_after_ms: number | null;
25
30
  account_skip_reasons: Record<string, string>;
26
31
  }
27
- export declare function buildPinnedUnavailableErrorBody(pinnedIndex: number | null | undefined, accountSkipReasons: ReadonlyMap<number, string>): PinnedUnavailableErrorBody;
32
+ export interface PinnedUnavailableContext {
33
+ /**
34
+ * "forced" when the pin came from the wrapper's forced-account mode
35
+ * (`--account` / CODEX_MULTI_AUTH_FORCE_ACCOUNT, which the wrapper resolves
36
+ * into the internal CODEX_MULTI_AUTH_FORCE_ACCOUNT_INDEX), "manual" when it
37
+ * came from `switch`. `unpin` clears only the manual kind, so the remedy
38
+ * line must not suggest it for a forced pin.
39
+ */
40
+ pinSource?: "forced" | "manual" | null;
41
+ /** Epoch ms when the blocking record ends (rate limit or cooldown). */
42
+ resetAtMs?: number | null;
43
+ now?: number;
44
+ }
45
+ export declare function buildPinnedUnavailableErrorBody(pinnedIndex: number | null | undefined, accountSkipReasons: ReadonlyMap<number, string>, context?: PinnedUnavailableContext): PinnedUnavailableErrorBody;
28
46
  //# sourceMappingURL=rate-limit-decision.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit-decision.d.ts","sourceRoot":"","sources":["../../../lib/request/rate-limit-decision.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAe/C,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGlE;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,GAAG,OAAO,CAWjG;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAapF;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoBlF;AAYD,wBAAgB,0BAA0B,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAuB3E;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBxE;AA0BD,wBAAgB,4BAA4B,CAC3C,OAAO,EAAE,OAAO,EAChB,kBAAkB,EAAE,MAAM,EAC1B,GAAG,EAAE,MAAM,GACT,MAAM,CAcR;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAE1E;AAED;;;;;;GAMG;AACH,MAAM,WAAW,0BAA0B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,kCAAkC,CAAC;IACzC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7C;AAED,wBAAgB,+BAA+B,CAC9C,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACtC,kBAAkB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7C,0BAA0B,CA0B5B"}
1
+ {"version":3,"file":"rate-limit-decision.d.ts","sourceRoot":"","sources":["../../../lib/request/rate-limit-decision.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAe/C,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGlE;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,GAAG,OAAO,CAWjG;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAapF;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoBlF;AAYD,wBAAgB,0BAA0B,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAuB3E;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBxE;AA0BD,wBAAgB,4BAA4B,CAC3C,OAAO,EAAE,OAAO,EAChB,kBAAkB,EAAE,MAAM,EAC1B,GAAG,EAAE,MAAM,GACT,MAAM,CAcR;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAE1E;AAED;;;;;;GAMG;AACH,MAAM,WAAW,0BAA0B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,kCAAkC,CAAC;IACzC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,mEAAmE;IACnE,UAAU,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAAC;IACvC,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7C;AAQD,MAAM,WAAW,wBAAwB;IACxC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAAC;IACvC,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,+BAA+B,CAC9C,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACtC,kBAAkB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/C,OAAO,CAAC,EAAE,wBAAwB,GAChC,0BAA0B,CAwD5B"}
@@ -172,7 +172,12 @@ export function getQuotaNearExhaustionWaitMs(headers, remainingThreshold, now) {
172
172
  export function normalizeExhaustionStatus(reason) {
173
173
  return reason === "rate-limit" ? HTTP_STATUS.TOO_MANY_REQUESTS : 503;
174
174
  }
175
- export function buildPinnedUnavailableErrorBody(pinnedIndex, accountSkipReasons) {
175
+ /**
176
+ * Largest epoch-ms value `new Date(...).toISOString()` accepts; anything beyond
177
+ * throws RangeError (ECMAScript time-value limit, ±100,000,000 days).
178
+ */
179
+ const MAX_ECMASCRIPT_TIME_VALUE = 8_640_000_000_000_000;
180
+ export function buildPinnedUnavailableErrorBody(pinnedIndex, accountSkipReasons, context) {
176
181
  const normalizedPinnedIndex = typeof pinnedIndex === "number" ? pinnedIndex : null;
177
182
  const skipReason = normalizedPinnedIndex !== null
178
183
  ? accountSkipReasons.get(normalizedPinnedIndex) ?? null
@@ -183,11 +188,38 @@ export function buildPinnedUnavailableErrorBody(pinnedIndex, accountSkipReasons)
183
188
  const accountPhrase = normalizedPinnedIndex === null
184
189
  ? "The pinned account"
185
190
  : `Pinned account ${normalizedPinnedIndex + 1}`;
191
+ const pinSource = context?.pinSource ?? null;
192
+ // Upper bound as well as lower: resetAtMs comes from persisted account state
193
+ // (rateLimitResetTimes, coolingDownUntil), and markAccountCoolingDown clamps
194
+ // only the low side while nothing re-validates either on load. A finite but
195
+ // absurd deadline past the ECMAScript time limit would make toISOString below
196
+ // throw a RangeError inside handleRequestInner, collapsing this diagnostic 503
197
+ // into a generic 500 that carries no pinnedAccountIndex, reason, or skip map —
198
+ // the exact payload this branch exists to deliver. Such a value bounds nothing
199
+ // usable anyway, so treat it as "no known recovery" instead.
200
+ const resetAtMs = typeof context?.resetAtMs === "number" &&
201
+ Number.isFinite(context.resetAtMs) &&
202
+ context.resetAtMs > 0 &&
203
+ context.resetAtMs <= MAX_ECMASCRIPT_TIME_VALUE
204
+ ? context.resetAtMs
205
+ : null;
206
+ const now = context?.now ?? Date.now();
207
+ const retryAfterMs = resetAtMs !== null ? Math.max(0, resetAtMs - now) : null;
208
+ const resetAt = resetAtMs !== null ? new Date(resetAtMs).toISOString() : null;
209
+ const waitSuffix = resetAt !== null ? `; the recorded limit resets at ${resetAt}` : "";
210
+ // A forced pin belongs to the launching process, not to the persisted pin
211
+ // state, so `unpin` would clear nothing — say what actually helps.
212
+ const remedy = pinSource === "forced"
213
+ ? "the pin was set by this session's launcher, so relaunch to select a different account"
214
+ : "run `codex-multi-auth status` for details, or `codex-multi-auth unpin` to allow rotation";
186
215
  return {
187
- message: `${accountPhrase} is currently unavailable${reasonSuffix}; run \`codex-multi-auth status\` for details, or \`codex-multi-auth unpin\` to allow rotation.`,
216
+ message: `${accountPhrase} is currently unavailable${reasonSuffix}${waitSuffix}; ${remedy}.`,
188
217
  code: "codex_pinned_account_unavailable",
189
218
  pinnedAccountIndex: normalizedPinnedIndex,
190
219
  reason: skipReason,
220
+ pin_source: pinSource,
221
+ reset_at: resetAt,
222
+ retry_after_ms: retryAfterMs,
191
223
  account_skip_reasons: Object.fromEntries([...accountSkipReasons.entries()].map(([index, reason]) => [
192
224
  String(index),
193
225
  reason,
@@ -7,7 +7,45 @@ export declare function resolveActiveIndex(storage: {
7
7
  export declare function getRateLimitResetTimeForFamily(account: {
8
8
  rateLimitResetTimes?: Record<string, number | undefined>;
9
9
  }, now: number, family: ModelFamily): number | null;
10
+ /**
11
+ * The moment the account becomes usable again for a `family`/`model`
12
+ * request: the LATEST bound among the records that actually gate that
13
+ * request plus any active cooldown. Two deliberate differences from
14
+ * getRateLimitResetTimeForFamily, whose earliest-reset answer feeds wait
15
+ * displays: the account stays skipped while ANY gating record is active,
16
+ * so the earliest reset would send clients back into a 503 — and only the
17
+ * keys selection consults (`family`, plus `family:<model>` when a model is
18
+ * known; see isRateLimitedForFamily) may contribute, because another
19
+ * model's record does not block this request and would overstate its
20
+ * recovery. Null when nothing bounds recovery.
21
+ */
22
+ export declare function getAccountRecoveryTimeForFamily(account: {
23
+ rateLimitResetTimes?: Record<string, number | undefined>;
24
+ coolingDownUntil?: number;
25
+ }, now: number, family: ModelFamily, model?: string | null): number | null;
10
26
  export declare function formatRateLimitEntry(account: {
11
27
  rateLimitResetTimes?: Record<string, number | undefined>;
12
28
  }, now: number, formatWaitTime: (ms: number) => string, family?: ModelFamily): string | null;
29
+ /**
30
+ * When a request for `family`/`model` stops being rate limited: the LATEST
31
+ * active bound among exactly the two keys selection consults — the family-wide
32
+ * key and `family:<model>` (see `isRateLimitedForFamily`). Null when neither is
33
+ * active.
34
+ *
35
+ * Deliberately narrower and later than `getRateLimitResetTimeForFamily`, whose
36
+ * earliest-reset-across-every-`family:*`-key answer feeds wait displays and
37
+ * model-less callers:
38
+ *
39
+ * - narrower, because `markRateLimitedWithReason` keys token/concurrency limits
40
+ * under `family:<model>`, and a sibling model's record does not gate this
41
+ * request — folding it in reports a delay the runtime proxy would not impose;
42
+ * - later, because the account stays skipped while EITHER key is active, so the
43
+ * earliest reset understates the wait when both are set.
44
+ *
45
+ * Requires a model by construction: a caller without one cannot know which
46
+ * model key applies and should keep the family-wide union above.
47
+ */
48
+ export declare function getRateLimitResetTimeForModel(account: {
49
+ rateLimitResetTimes?: Record<string, number | undefined>;
50
+ }, now: number, family: ModelFamily, model: string): number | null;
13
51
  //# sourceMappingURL=account-status.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"account-status.d.ts","sourceRoot":"","sources":["../../../lib/runtime/account-status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,wBAAgB,kBAAkB,CACjC,OAAO,EAAE;IACR,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3D,QAAQ,EAAE,OAAO,EAAE,CAAC;CACpB,EACD,MAAM,GAAE,WAAqB,GAC3B,MAAM,CAOR;AAED,wBAAgB,8BAA8B,CAC7C,OAAO,EAAE;IAAE,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CAAE,EACrE,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,WAAW,GACjB,MAAM,GAAG,IAAI,CAgBf;AAED,wBAAgB,oBAAoB,CACnC,OAAO,EAAE;IAAE,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CAAE,EACrE,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,EACtC,MAAM,GAAE,WAAqB,GAC3B,MAAM,GAAG,IAAI,CAMf"}
1
+ {"version":3,"file":"account-status.d.ts","sourceRoot":"","sources":["../../../lib/runtime/account-status.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,wBAAgB,kBAAkB,CACjC,OAAO,EAAE;IACR,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3D,QAAQ,EAAE,OAAO,EAAE,CAAC;CACpB,EACD,MAAM,GAAE,WAAqB,GAC3B,MAAM,CAOR;AAED,wBAAgB,8BAA8B,CAC7C,OAAO,EAAE;IAAE,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CAAE,EACrE,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,WAAW,GACjB,MAAM,GAAG,IAAI,CAgBf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,+BAA+B,CAC9C,OAAO,EAAE;IACR,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B,EACD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,GAAG,IAAI,CAcf;AAED,wBAAgB,oBAAoB,CACnC,OAAO,EAAE;IAAE,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CAAE,EACrE,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,EACtC,MAAM,GAAE,WAAqB,GAC3B,MAAM,GAAG,IAAI,CAMf;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,6BAA6B,CAC5C,OAAO,EAAE;IAAE,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CAAE,EACrE,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,MAAM,GACX,MAAM,GAAG,IAAI,CAcf"}
@@ -1,3 +1,4 @@
1
+ import { getQuotaKey } from "../accounts/rate-limits.js";
1
2
  export function resolveActiveIndex(storage, family = "codex") {
2
3
  const total = storage.accounts.length;
3
4
  if (total === 0)
@@ -25,6 +26,37 @@ export function getRateLimitResetTimeForFamily(account, now, family) {
25
26
  }
26
27
  return minReset;
27
28
  }
29
+ /**
30
+ * The moment the account becomes usable again for a `family`/`model`
31
+ * request: the LATEST bound among the records that actually gate that
32
+ * request plus any active cooldown. Two deliberate differences from
33
+ * getRateLimitResetTimeForFamily, whose earliest-reset answer feeds wait
34
+ * displays: the account stays skipped while ANY gating record is active,
35
+ * so the earliest reset would send clients back into a 503 — and only the
36
+ * keys selection consults (`family`, plus `family:<model>` when a model is
37
+ * known; see isRateLimitedForFamily) may contribute, because another
38
+ * model's record does not block this request and would overstate its
39
+ * recovery. Null when nothing bounds recovery.
40
+ */
41
+ export function getAccountRecoveryTimeForFamily(account, now, family, model) {
42
+ let latest = null;
43
+ const consider = (value) => {
44
+ if (typeof value !== "number" || !Number.isFinite(value))
45
+ return;
46
+ if (value <= now)
47
+ return;
48
+ if (latest === null || value > latest)
49
+ latest = value;
50
+ };
51
+ const times = account.rateLimitResetTimes;
52
+ if (times) {
53
+ consider(times[getQuotaKey(family)]);
54
+ if (model)
55
+ consider(times[getQuotaKey(family, model)]);
56
+ }
57
+ consider(account.coolingDownUntil);
58
+ return latest;
59
+ }
28
60
  export function formatRateLimitEntry(account, now, formatWaitTime, family = "codex") {
29
61
  const resetAt = getRateLimitResetTimeForFamily(account, now, family);
30
62
  if (typeof resetAt !== "number")
@@ -34,3 +66,39 @@ export function formatRateLimitEntry(account, now, formatWaitTime, family = "cod
34
66
  return null;
35
67
  return `resets in ${formatWaitTime(remaining)}`;
36
68
  }
69
+ /**
70
+ * When a request for `family`/`model` stops being rate limited: the LATEST
71
+ * active bound among exactly the two keys selection consults — the family-wide
72
+ * key and `family:<model>` (see `isRateLimitedForFamily`). Null when neither is
73
+ * active.
74
+ *
75
+ * Deliberately narrower and later than `getRateLimitResetTimeForFamily`, whose
76
+ * earliest-reset-across-every-`family:*`-key answer feeds wait displays and
77
+ * model-less callers:
78
+ *
79
+ * - narrower, because `markRateLimitedWithReason` keys token/concurrency limits
80
+ * under `family:<model>`, and a sibling model's record does not gate this
81
+ * request — folding it in reports a delay the runtime proxy would not impose;
82
+ * - later, because the account stays skipped while EITHER key is active, so the
83
+ * earliest reset understates the wait when both are set.
84
+ *
85
+ * Requires a model by construction: a caller without one cannot know which
86
+ * model key applies and should keep the family-wide union above.
87
+ */
88
+ export function getRateLimitResetTimeForModel(account, now, family, model) {
89
+ const times = account.rateLimitResetTimes;
90
+ if (!times)
91
+ return null;
92
+ let latest = null;
93
+ const consider = (value) => {
94
+ if (typeof value !== "number" || !Number.isFinite(value))
95
+ return;
96
+ if (value <= now)
97
+ return;
98
+ if (latest === null || value > latest)
99
+ latest = value;
100
+ };
101
+ consider(times[getQuotaKey(family)]);
102
+ consider(times[getQuotaKey(family, model)]);
103
+ return latest;
104
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-rotation-proxy.d.ts","sourceRoot":"","sources":["../../lib/runtime-rotation-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EAGN,KAAK,cAAc,EACnB,MAAM,eAAe,CAAC;AA8BvB,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA2CtE,OAAO,KAAK,EAKX,2BAA2B,EAC3B,0BAA0B,EAE1B,MAAM,oCAAoC,CAAC;AAe5C,YAAY,EACX,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,GAC1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACN,+BAA+B,EAC/B,0BAA0B,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,OAAO,EACN,+BAA+B,EAC/B,8BAA8B,EAC9B,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AAiDtE,kFAAkF;AAClF,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GAAG;IACvE,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,EACD,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,CAmBR;AA8bD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAC1C,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GACvC,MAAM,GAAG,IAAI,CAUf;AAED,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,2BAA2B,GAClC,OAAO,CAAC,0BAA0B,CAAC,CA4KrC"}
1
+ {"version":3,"file":"runtime-rotation-proxy.d.ts","sourceRoot":"","sources":["../../lib/runtime-rotation-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EAIN,KAAK,cAAc,EACnB,MAAM,eAAe,CAAC;AA8BvB,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA4CtE,OAAO,KAAK,EAKX,2BAA2B,EAC3B,0BAA0B,EAE1B,MAAM,oCAAoC,CAAC;AAe5C,YAAY,EACX,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,GAC1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACN,+BAA+B,EAC/B,0BAA0B,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,OAAO,EACN,+BAA+B,EAC/B,8BAA8B,EAC9B,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AA8DtE,kFAAkF;AAClF,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GAAG;IACvE,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,EACD,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,CAmBR;AA8bD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAC1C,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GACvC,MAAM,GAAG,IAAI,CAUf;AAED,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,2BAA2B,GAClC,OAAO,CAAC,0BAA0B,CAAC,CA4KrC"}
@@ -1,6 +1,6 @@
1
1
  import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
2
2
  import { createServer } from "node:http";
3
- import { AccountManager, extractAccountId, } from "./accounts.js";
3
+ import { AccountManager, AUTH_INVALIDATION_MARKER, extractAccountId, } from "./accounts.js";
4
4
  import { withRoutingMutex } from "./routing-mutex.js";
5
5
  import { getFetchTimeoutMs, getNetworkErrorCooldownMs, getRetryAllAccountsMaxRetries, getServerErrorCooldownMs, getSessionAffinity, getSessionAffinityMaxEntries, getSessionAffinityTtlMs, getStreamStallTimeoutMs, getMinRotationIntervalMs, getTokenInvalidationCooldownMs, getTokenRefreshSkewMs, getPidOffsetEnabled, getPreemptiveQuotaEnabled, getPreemptiveQuotaMaxDeferralMs, getPreemptiveQuotaRemainingPercent5h, getPreemptiveQuotaRemainingPercent7d, getRoutingMutexMode, getSchedulingStrategy, loadPluginConfig, } from "./config.js";
6
6
  import { CODEX_BASE_URL, HTTP_STATUS, OPENAI_HEADERS, OPENAI_HEADER_VALUES, URL_PATHS, } from "./constants.js";
@@ -15,6 +15,7 @@ import { CodexValidationError } from "./errors.js";
15
15
  import { normalizeEmailKey } from "./storage/identity.js";
16
16
  import { buildPinnedUnavailableErrorBody, buildTokenInvalidationBody, extractErrorCodeFromBody, isTokenInvalidationError, normalizeExhaustionStatus, parseRetryAfterBodyMs, parseRetryAfterHeaderMs, } from "./request/rate-limit-decision.js";
17
17
  import { forwardStreamingResponse, HOP_BY_HOP_HEADERS, readErrorBody, responseHeadersForClient, withTimeout, } from "./request/stream-failover-runtime.js";
18
+ import { getAccountRecoveryTimeForFamily } from "./runtime/account-status.js";
18
19
  import { chooseAccount } from "./runtime/rotation-account-selection.js";
19
20
  import { createRotationProxyState, recoverStaleRuntimeState, } from "./runtime/rotation-proxy-state.js";
20
21
  import { readStorageMetaFromDisk } from "./runtime/rotation-storage-meta.js";
@@ -62,6 +63,18 @@ function toUrlHost(host) {
62
63
  // failures surfaced only as a last-write-wins status.lastError string. Logs are
63
64
  // level-gated and carry the per-request correlation id set in handleRequest.
64
65
  const proxyLog = createLogger("runtime-proxy");
66
+ /**
67
+ * Pinned skip reasons that no timer clears: the account stays unselectable
68
+ * after any concurrent rate-limit record or cooldown expires, so the pinned
69
+ * 503 must not advertise that record's expiry as a recovery time.
70
+ */
71
+ const PINNED_PERMANENT_SKIP_REASONS = new Set([
72
+ "missing",
73
+ "disabled",
74
+ "workspace-disabled",
75
+ "policy-blocked",
76
+ AUTH_INVALIDATION_MARKER,
77
+ ]);
65
78
  const DEFAULT_QUOTA_REMAINING_THRESHOLD = 10;
66
79
  /** @internal Stable identity key for in-memory quota snapshots across reloads. */
67
80
  export function buildQuotaScheduleKey(account, family, model) {
@@ -1170,7 +1183,60 @@ async function handleRequestInner(state, req, res, traceId) {
1170
1183
  // null reason indicates a forecast/runtime state desync (the pinned
1171
1184
  // account was selected but no skip reason was recorded) — see #486.
1172
1185
  if (isPinned) {
1173
- const errorBody = buildPinnedUnavailableErrorBody(pinnedIndex, accountSkipReasons);
1186
+ const pinnedAccount = typeof pinnedIndex === "number"
1187
+ ? accountManager.getAccountByIndex(pinnedIndex)
1188
+ : null;
1189
+ const pinnedSkipReason = typeof pinnedIndex === "number"
1190
+ ? accountSkipReasons.get(pinnedIndex) ?? null
1191
+ : null;
1192
+ // A permanent blocker (disabled, no enabled workspace, invalidated
1193
+ // auth, policy block, out-of-range pin) outlives every timed record,
1194
+ // so advertising a record's expiry would invite a retry into another
1195
+ // 503.
1196
+ //
1197
+ // The recorded reason alone is not enough to detect one. It is the
1198
+ // SELECTION verdict, and this request can make the pin permanently
1199
+ // unselectable after selection already ran: a workspace-disabled
1200
+ // 402/403 calls setAccountEnabled(index, false) above and then
1201
+ // continues, so the next pass records "already-attempted" and the
1202
+ // disable never surfaces. With a breaker tripped by the same failure
1203
+ // the 503 would then advertise the circuit's ~30s reset for an
1204
+ // account no timer will ever re-admit. Re-read the pin's CURRENT
1205
+ // runtime state so a permanent blocker cannot hide behind the
1206
+ // verdict; the recorded reason still covers the selection-only
1207
+ // verdicts ("missing", "policy-blocked") that state cannot express.
1208
+ const pinnedCurrentSkipReason = pinnedAccount === null
1209
+ ? null
1210
+ : accountManager.getManagedAccountRuntimeSkipReason(pinnedAccount, context.family, context.model);
1211
+ const pinnedBlockedPermanently = (pinnedSkipReason !== null &&
1212
+ PINNED_PERMANENT_SKIP_REASONS.has(pinnedSkipReason)) ||
1213
+ (pinnedCurrentSkipReason !== null &&
1214
+ PINNED_PERMANENT_SKIP_REASONS.has(pinnedCurrentSkipReason));
1215
+ // Otherwise recovery comes from the pinned account's persisted state, not the
1216
+ // recorded skip reason: a direct 429/cooldown on the pinned account
1217
+ // reaches this 503 as "already-attempted" (the retry loop's selection
1218
+ // verdict) while the record it just wrote is what actually bounds
1219
+ // recovery — and with several overlapping records the account stays
1220
+ // skipped until the LAST one expires, so the latest bound is the one
1221
+ // worth advertising.
1222
+ const pinnedStateRecoveryAtMs = pinnedAccount === null
1223
+ ? null
1224
+ : getAccountRecoveryTimeForFamily(pinnedAccount, state.now(), context.family, context.model);
1225
+ // An open circuit outlives the short failure cooldowns that tripped
1226
+ // it; its deadline lives in the breaker, not the account record.
1227
+ const pinnedCircuitRecoveryAtMs = pinnedAccount === null
1228
+ ? null
1229
+ : accountManager.getCircuitRecoveryTime(pinnedAccount, state.now());
1230
+ const pinnedResetAtMs = pinnedBlockedPermanently ||
1231
+ (pinnedStateRecoveryAtMs === null && pinnedCircuitRecoveryAtMs === null)
1232
+ ? null
1233
+ : Math.max(pinnedStateRecoveryAtMs ?? 0, pinnedCircuitRecoveryAtMs ?? 0);
1234
+ const errorBody = buildPinnedUnavailableErrorBody(pinnedIndex, accountSkipReasons, {
1235
+ // typeof check so a forced index of 0 still reads as forced.
1236
+ pinSource: typeof state.forcedAccountIndex === "number" ? "forced" : "manual",
1237
+ resetAtMs: pinnedResetAtMs,
1238
+ now: state.now(),
1239
+ });
1174
1240
  if (errorBody.reason === null) {
1175
1241
  state.status.lastError = `pinned-503 missing skip reason (pinnedIndex=${pinnedIndex})`;
1176
1242
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-multi-auth",
3
- "version": "2.8.5",
3
+ "version": "2.8.6",
4
4
  "description": "Codex CLI multi-account OAuth manager with account switching, health checks, runtime rotation, diagnostics, and recovery tools for @openai/codex",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",