codex-multi-auth 2.19.1 → 2.21.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/.codex-plugin/plugin.json +9 -9
- package/LICENSE +21 -21
- package/README.md +149 -148
- package/assets/codex-multi-auth-icon.svg +39 -39
- package/assets/readme-hero.svg +31 -31
- package/config/README.md +31 -31
- package/config/codex-legacy.json +1021 -1021
- package/config/codex-modern.json +347 -347
- package/config/minimal-codex.json +15 -15
- package/dist/index.js +1 -1
- package/dist/lib/accounts/rate-limits.js +5 -0
- package/dist/lib/accounts.js +5 -4
- package/dist/lib/auth/account-access.js +2 -2
- package/dist/lib/codex-cli/version.d.ts +22 -0
- package/dist/lib/codex-cli/version.js +78 -0
- package/dist/lib/codex-manager/commands/limits.d.ts +2 -0
- package/dist/lib/codex-manager/commands/limits.js +31 -0
- package/dist/lib/codex-manager/commands/status.js +1 -1
- package/dist/lib/codex-manager.js +2 -0
- package/dist/lib/constants.d.ts +2 -0
- package/dist/lib/constants.js +2 -0
- package/dist/lib/context-budget/model-context-windows.d.ts +1 -1
- package/dist/lib/context-budget/model-context-windows.js +4 -0
- package/dist/lib/context-budget-response.js +8 -8
- package/dist/lib/context-overflow.js +10 -10
- package/dist/lib/luna-reserve.d.ts +26 -0
- package/dist/lib/luna-reserve.js +68 -0
- package/dist/lib/oauth-success.html +125 -125
- package/dist/lib/policy/runtime-policy.js +14 -0
- package/dist/lib/prompts/codex-host-bridge.js +138 -138
- package/dist/lib/prompts/codex.js +79 -79
- package/dist/lib/request/helpers/model-map.d.ts +1 -1
- package/dist/lib/request/helpers/model-map.js +12 -0
- package/dist/lib/request/response-outcome.d.ts +1 -1
- package/dist/lib/request/response-outcome.js +4 -1
- package/dist/lib/runtime/account-status.js +2 -1
- package/dist/lib/runtime/luna-reserve-usage.d.ts +9 -0
- package/dist/lib/runtime/luna-reserve-usage.js +68 -0
- package/dist/lib/runtime/model-discovery-status.d.ts +6 -2
- package/dist/lib/runtime/model-discovery-status.js +13 -5
- package/dist/lib/runtime/reset-credit-routing.js +4 -1
- package/dist/lib/runtime/rotation-server-types.d.ts +2 -0
- package/dist/lib/runtime/runtime-observability.d.ts +2 -0
- package/dist/lib/runtime/runtime-observability.js +1 -0
- package/dist/lib/runtime-rotation-proxy.js +200 -32
- package/dist/lib/usage/pricing.d.ts +1 -1
- package/dist/lib/usage/pricing.js +4 -0
- package/dist/lib/usage/usage-extraction.d.ts +2 -0
- package/dist/lib/usage/usage-extraction.js +25 -1
- package/dist/lib/utils.d.ts +1 -1
- package/dist/lib/utils.js +1 -1
- package/node_modules/@codex-ai/plugin/dist/index.d.ts +2 -2
- package/node_modules/@codex-ai/plugin/dist/index.js +2 -2
- package/node_modules/@codex-ai/plugin/dist/tool.d.ts +42 -42
- package/node_modules/@codex-ai/plugin/dist/tool.js +29 -29
- package/node_modules/@codex-ai/plugin/package.json +9 -9
- package/node_modules/@codex-ai/sdk/dist/index.d.ts +4 -4
- package/node_modules/@codex-ai/sdk/dist/index.js +2 -2
- package/node_modules/@codex-ai/sdk/package.json +8 -8
- package/package.json +207 -207
- package/scripts/codex-app-launcher.js +653 -653
- package/scripts/codex-app-router.js +374 -373
- package/scripts/codex-bin-resolver.js +332 -332
- package/scripts/codex-multi-auth.js +65 -65
- package/scripts/codex-routing.js +62 -62
- package/scripts/codex.js +7006 -7005
- package/scripts/install-codex-auth-utils.js +213 -213
- package/scripts/mcodex.js +367 -367
- package/scripts/postinstall.js +114 -114
- package/scripts/preuninstall.js +265 -265
- package/skills/codex-auth-setup/SKILL.md +73 -73
- package/vendor/codex-ai-plugin/dist/index.d.ts +2 -2
- package/vendor/codex-ai-plugin/dist/index.js +2 -2
- package/vendor/codex-ai-plugin/dist/tool.d.ts +42 -42
- package/vendor/codex-ai-plugin/dist/tool.js +29 -29
- package/vendor/codex-ai-plugin/package.json +9 -9
- package/vendor/codex-ai-sdk/dist/index.d.ts +4 -4
- package/vendor/codex-ai-sdk/dist/index.js +2 -2
- package/vendor/codex-ai-sdk/package.json +8 -8
|
@@ -381,83 +381,83 @@ export function prewarmCodexInstructions(models = []) {
|
|
|
381
381
|
/**
|
|
382
382
|
* Tool remapping instructions for host runtime tools
|
|
383
383
|
*/
|
|
384
|
-
export const TOOL_REMAP_MESSAGE = `<user_instructions priority="0">
|
|
385
|
-
<environment_override priority="0">
|
|
386
|
-
YOU ARE IN A DIFFERENT ENVIRONMENT. These instructions override ALL previous tool references.
|
|
387
|
-
</environment_override>
|
|
388
|
-
|
|
389
|
-
<tool_replacements priority="0">
|
|
390
|
-
<critical_rule priority="0">
|
|
391
|
-
apply_patch/applyPatch are Codex names, but host tool names vary by version.
|
|
392
|
-
- Inspect the actual tool list before editing.
|
|
393
|
-
- If edit exists: use edit for precise in-place string replacements and hashline edits.
|
|
394
|
-
- If edit is absent and apply_patch exists: use apply_patch for those precise/hashline edits in this plugin.
|
|
395
|
-
- For diff-style or multi-line structural edits: use patch if available, otherwise use apply_patch.
|
|
396
|
-
- In this plugin, edit/apply_patch support hashline refs (lineRef, endLineRef, operation, content)
|
|
397
|
-
</critical_rule>
|
|
398
|
-
|
|
399
|
-
<critical_rule priority="0">
|
|
400
|
-
UPDATE_PLAN DOES NOT EXIST -> USE "todowrite" INSTEAD
|
|
401
|
-
- NEVER use: update_plan, updatePlan
|
|
402
|
-
- ALWAYS use: todowrite for ALL task/plan operations
|
|
403
|
-
- Use todoread to read current plan
|
|
404
|
-
- Before plan operations: Verify you're using "todowrite", NOT "update_plan"
|
|
405
|
-
</critical_rule>
|
|
406
|
-
</tool_replacements>
|
|
407
|
-
|
|
408
|
-
<available_tools priority="0">
|
|
409
|
-
File Operations:
|
|
410
|
-
- write - Create new files (if available)
|
|
411
|
-
- edit - Modify existing files with string replacement (version-dependent)
|
|
412
|
-
- oldString must be literal text from the current file; never pass unresolved placeholders like \${TARGET_SNIPPET}
|
|
413
|
-
- apply_patch - May be the edit/patch tool name in newer host builds (version-dependent)
|
|
414
|
-
- hashline_read - Read lines with hashline refs (L<line>#<hash>) for deterministic edits
|
|
415
|
-
- patch - Apply diff patches (version-dependent)
|
|
416
|
-
- read - Read file contents
|
|
417
|
-
|
|
418
|
-
Search/Discovery:
|
|
419
|
-
- grep - Search file contents
|
|
420
|
-
- glob - Find files by pattern
|
|
421
|
-
- list - List directories (if available)
|
|
422
|
-
|
|
423
|
-
Execution:
|
|
424
|
-
- bash - Run shell commands
|
|
425
|
-
|
|
426
|
-
Network:
|
|
427
|
-
- webfetch - Fetch web content
|
|
428
|
-
|
|
429
|
-
Task Management:
|
|
430
|
-
- todowrite - Manage tasks/plans (REPLACES update_plan)
|
|
431
|
-
- todoread - Read current plan
|
|
432
|
-
</available_tools>
|
|
433
|
-
|
|
434
|
-
<substitution_rules priority="0">
|
|
435
|
-
Base instruction says: You MUST use instead:
|
|
436
|
-
apply_patch -> patch (preferred if available), otherwise edit/apply_patch based on actual tool list
|
|
437
|
-
update_plan -> todowrite
|
|
438
|
-
read_plan -> todoread
|
|
439
|
-
absolute paths -> relative paths
|
|
440
|
-
</substitution_rules>
|
|
441
|
-
|
|
442
|
-
<verification_checklist priority="0">
|
|
443
|
-
Before file/plan modifications:
|
|
444
|
-
1. Am I using the actual available edit tool name (edit, patch, or apply_patch)?
|
|
445
|
-
2. Am I using "todowrite" NOT "update_plan"?
|
|
446
|
-
3. Is this tool in the approved list above?
|
|
447
|
-
4. Am I using relative paths?
|
|
448
|
-
|
|
449
|
-
If ANY answer is NO -> STOP and correct before proceeding.
|
|
450
|
-
</verification_checklist>
|
|
451
|
-
|
|
452
|
-
<hashline_workflow priority="0">
|
|
453
|
-
When hashline_read is available:
|
|
454
|
-
1. call hashline_read on the file
|
|
455
|
-
2. edit/apply_patch using lineRef/endLineRef + operation + content
|
|
456
|
-
3. use oldString/newString only as fallback, and only with literal file text (no template placeholders)
|
|
457
|
-
</hashline_workflow>
|
|
458
|
-
|
|
459
|
-
<safety_rules priority="0">
|
|
460
|
-
- Never run destructive git commands (\`git reset --hard\`, \`git checkout --\`) unless explicitly requested by the user.
|
|
461
|
-
- Never call \`request_user_input\` unless collaboration mode is explicitly Plan mode.
|
|
462
|
-
</safety_rules>
|
|
384
|
+
export const TOOL_REMAP_MESSAGE = `<user_instructions priority="0">
|
|
385
|
+
<environment_override priority="0">
|
|
386
|
+
YOU ARE IN A DIFFERENT ENVIRONMENT. These instructions override ALL previous tool references.
|
|
387
|
+
</environment_override>
|
|
388
|
+
|
|
389
|
+
<tool_replacements priority="0">
|
|
390
|
+
<critical_rule priority="0">
|
|
391
|
+
apply_patch/applyPatch are Codex names, but host tool names vary by version.
|
|
392
|
+
- Inspect the actual tool list before editing.
|
|
393
|
+
- If edit exists: use edit for precise in-place string replacements and hashline edits.
|
|
394
|
+
- If edit is absent and apply_patch exists: use apply_patch for those precise/hashline edits in this plugin.
|
|
395
|
+
- For diff-style or multi-line structural edits: use patch if available, otherwise use apply_patch.
|
|
396
|
+
- In this plugin, edit/apply_patch support hashline refs (lineRef, endLineRef, operation, content)
|
|
397
|
+
</critical_rule>
|
|
398
|
+
|
|
399
|
+
<critical_rule priority="0">
|
|
400
|
+
UPDATE_PLAN DOES NOT EXIST -> USE "todowrite" INSTEAD
|
|
401
|
+
- NEVER use: update_plan, updatePlan
|
|
402
|
+
- ALWAYS use: todowrite for ALL task/plan operations
|
|
403
|
+
- Use todoread to read current plan
|
|
404
|
+
- Before plan operations: Verify you're using "todowrite", NOT "update_plan"
|
|
405
|
+
</critical_rule>
|
|
406
|
+
</tool_replacements>
|
|
407
|
+
|
|
408
|
+
<available_tools priority="0">
|
|
409
|
+
File Operations:
|
|
410
|
+
- write - Create new files (if available)
|
|
411
|
+
- edit - Modify existing files with string replacement (version-dependent)
|
|
412
|
+
- oldString must be literal text from the current file; never pass unresolved placeholders like \${TARGET_SNIPPET}
|
|
413
|
+
- apply_patch - May be the edit/patch tool name in newer host builds (version-dependent)
|
|
414
|
+
- hashline_read - Read lines with hashline refs (L<line>#<hash>) for deterministic edits
|
|
415
|
+
- patch - Apply diff patches (version-dependent)
|
|
416
|
+
- read - Read file contents
|
|
417
|
+
|
|
418
|
+
Search/Discovery:
|
|
419
|
+
- grep - Search file contents
|
|
420
|
+
- glob - Find files by pattern
|
|
421
|
+
- list - List directories (if available)
|
|
422
|
+
|
|
423
|
+
Execution:
|
|
424
|
+
- bash - Run shell commands
|
|
425
|
+
|
|
426
|
+
Network:
|
|
427
|
+
- webfetch - Fetch web content
|
|
428
|
+
|
|
429
|
+
Task Management:
|
|
430
|
+
- todowrite - Manage tasks/plans (REPLACES update_plan)
|
|
431
|
+
- todoread - Read current plan
|
|
432
|
+
</available_tools>
|
|
433
|
+
|
|
434
|
+
<substitution_rules priority="0">
|
|
435
|
+
Base instruction says: You MUST use instead:
|
|
436
|
+
apply_patch -> patch (preferred if available), otherwise edit/apply_patch based on actual tool list
|
|
437
|
+
update_plan -> todowrite
|
|
438
|
+
read_plan -> todoread
|
|
439
|
+
absolute paths -> relative paths
|
|
440
|
+
</substitution_rules>
|
|
441
|
+
|
|
442
|
+
<verification_checklist priority="0">
|
|
443
|
+
Before file/plan modifications:
|
|
444
|
+
1. Am I using the actual available edit tool name (edit, patch, or apply_patch)?
|
|
445
|
+
2. Am I using "todowrite" NOT "update_plan"?
|
|
446
|
+
3. Is this tool in the approved list above?
|
|
447
|
+
4. Am I using relative paths?
|
|
448
|
+
|
|
449
|
+
If ANY answer is NO -> STOP and correct before proceeding.
|
|
450
|
+
</verification_checklist>
|
|
451
|
+
|
|
452
|
+
<hashline_workflow priority="0">
|
|
453
|
+
When hashline_read is available:
|
|
454
|
+
1. call hashline_read on the file
|
|
455
|
+
2. edit/apply_patch using lineRef/endLineRef + operation + content
|
|
456
|
+
3. use oldString/newString only as fallback, and only with literal file text (no template placeholders)
|
|
457
|
+
</hashline_workflow>
|
|
458
|
+
|
|
459
|
+
<safety_rules priority="0">
|
|
460
|
+
- Never run destructive git commands (\`git reset --hard\`, \`git checkout --\`) unless explicitly requested by the user.
|
|
461
|
+
- Never call \`request_user_input\` unless collaboration mode is explicitly Plan mode.
|
|
462
|
+
</safety_rules>
|
|
463
463
|
</user_instructions>`;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* tool-surface metadata so routing logic stays consistent across the request
|
|
7
7
|
* transformer, prompt selection, and CLI diagnostics.
|
|
8
8
|
*/
|
|
9
|
-
import type
|
|
9
|
+
import { type ModelReasoningEffort, type WireReasoningEffort } from "../../constants.js";
|
|
10
10
|
export type { ModelReasoningEffort, WireReasoningEffort };
|
|
11
11
|
export type PromptModelFamily = "gpt-5-codex" | "codex-max" | "codex" | "gpt-5.2" | "gpt-5.1";
|
|
12
12
|
/**
|
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
* tool-surface metadata so routing logic stays consistent across the request
|
|
7
7
|
* transformer, prompt selection, and CLI diagnostics.
|
|
8
8
|
*/
|
|
9
|
+
// The effort union lives in the leaf constants module so the base types layer
|
|
10
|
+
// (`lib/types.ts`) can depend on it without importing this file, which would
|
|
11
|
+
// close a cycle through `lib/schemas.ts`. Re-exported here for existing callers.
|
|
12
|
+
import { LUNA_RESERVE_MODEL, } from "../../constants.js";
|
|
9
13
|
/**
|
|
10
14
|
* All supported model families
|
|
11
15
|
* Used for per-family account rotation and rate limit tracking
|
|
@@ -301,6 +305,13 @@ export const MODEL_PROFILES = {
|
|
|
301
305
|
supportedReasoningEfforts: GPT_6_LUNA_EFFORTS,
|
|
302
306
|
capabilities: TOOL_CAPABILITIES.full,
|
|
303
307
|
},
|
|
308
|
+
[LUNA_RESERVE_MODEL]: {
|
|
309
|
+
normalizedModel: LUNA_RESERVE_MODEL,
|
|
310
|
+
promptFamily: "gpt-5.2",
|
|
311
|
+
defaultReasoningEffort: "medium",
|
|
312
|
+
supportedReasoningEfforts: GPT_6_LUNA_EFFORTS,
|
|
313
|
+
capabilities: TOOL_CAPABILITIES.full,
|
|
314
|
+
},
|
|
304
315
|
[DAYBREAK_BLUE_MODEL]: {
|
|
305
316
|
normalizedModel: DAYBREAK_BLUE_MODEL,
|
|
306
317
|
promptFamily: "gpt-5.2",
|
|
@@ -392,6 +403,7 @@ function addGpt6Aliases() {
|
|
|
392
403
|
// user's model generation without asking.
|
|
393
404
|
addEffortAliases(GPT_6_SOL_MODEL, GPT_6_SOL_MODEL, GPT_6_SOL_EFFORTS);
|
|
394
405
|
addEffortAliases(GPT_6_LUNA_MODEL, GPT_6_LUNA_MODEL, GPT_6_LUNA_EFFORTS);
|
|
406
|
+
addEffortAliases(LUNA_RESERVE_MODEL, LUNA_RESERVE_MODEL, GPT_6_LUNA_EFFORTS);
|
|
395
407
|
addEffortAliases(GPT_6_1_SOL_MODEL, GPT_6_1_SOL_MODEL, GPT_6_1_SOL_EFFORTS);
|
|
396
408
|
addEffortAliases(GPT_6_1_FLAGSHIP_ALIAS, GPT_6_1_SOL_MODEL, GPT_6_1_SOL_EFFORTS);
|
|
397
409
|
}
|
|
@@ -13,7 +13,7 @@ export declare class ResponseOutcome {
|
|
|
13
13
|
param?: string;
|
|
14
14
|
};
|
|
15
15
|
} | undefined;
|
|
16
|
-
constructor(requireTerminal: boolean);
|
|
16
|
+
constructor(requireTerminal: boolean | (() => boolean));
|
|
17
17
|
observe(value: unknown): void;
|
|
18
18
|
/**
|
|
19
19
|
* `response.incomplete` (e.g. max_output_tokens) is a delivered response, not an
|
|
@@ -38,7 +38,10 @@ export class ResponseOutcome {
|
|
|
38
38
|
* type survives only as the usage annotation in `errorCode`.
|
|
39
39
|
*/
|
|
40
40
|
finish() {
|
|
41
|
-
const
|
|
41
|
+
const requireTerminal = typeof this.requireTerminal === "function"
|
|
42
|
+
? this.requireTerminal()
|
|
43
|
+
: this.requireTerminal;
|
|
44
|
+
const missingTerminal = requireTerminal && !this.terminal;
|
|
42
45
|
const success = !missingTerminal && (!this.terminal || this.terminal === "completed" || this.terminal === "incomplete");
|
|
43
46
|
return {
|
|
44
47
|
success,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getQuotaKey } from "../accounts/rate-limits.js";
|
|
2
|
+
import { LUNA_RESERVE_MODEL } from "../constants.js";
|
|
2
3
|
export function resolveActiveIndex(storage, family = "codex") {
|
|
3
4
|
const total = storage.accounts.length;
|
|
4
5
|
if (total === 0)
|
|
@@ -58,7 +59,7 @@ function laterBound(a, b) {
|
|
|
58
59
|
export function getAccountRecoveryBoundsForFamily(account, now, family, model) {
|
|
59
60
|
const times = account.rateLimitResetTimes;
|
|
60
61
|
const rateLimitAtMs = times
|
|
61
|
-
? laterBound(activeBound(times[getQuotaKey(family)], now), model ? activeBound(times[getQuotaKey(family, model)], now) : null)
|
|
62
|
+
? laterBound(model === LUNA_RESERVE_MODEL ? null : activeBound(times[getQuotaKey(family)], now), model ? activeBound(times[getQuotaKey(family, model)], now) : null)
|
|
62
63
|
: null;
|
|
63
64
|
return {
|
|
64
65
|
rateLimitAtMs,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type LunaReserveSnapshot } from "../luna-reserve.js";
|
|
2
|
+
import type { AccountStorageV3 } from "../storage.js";
|
|
3
|
+
export type LunaReserveUsageByAccount = Record<number, LunaReserveSnapshot>;
|
|
4
|
+
/**
|
|
5
|
+
* Read Luna Reserve usage through the same isolated native app-server bridge
|
|
6
|
+
* used for reset credits. Failures are per-account: one stale/revoked account
|
|
7
|
+
* never prevents other rows from reporting their Reserve percentage.
|
|
8
|
+
*/
|
|
9
|
+
export declare function refreshLunaReserveUsage(storage: AccountStorageV3, now?: () => number): Promise<LunaReserveUsageByAccount>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { AccountManager } from "../accounts.js";
|
|
2
|
+
import { LUNA_RESERVE_MODEL } from "../constants.js";
|
|
3
|
+
import { parseLunaReserveRateLimits, } from "../luna-reserve.js";
|
|
4
|
+
import { codexCliAccountIdFor } from "../auth/token-utils.js";
|
|
5
|
+
import { isRecord } from "../utils.js";
|
|
6
|
+
import { workspaceModelScopes } from "./workspace-model-scopes.js";
|
|
7
|
+
import { nativeRateLimitsRpc } from "./native-rate-limits.js";
|
|
8
|
+
import { ensureFreshAccessToken } from "./rotation-token-refresh.js";
|
|
9
|
+
/**
|
|
10
|
+
* Read Luna Reserve usage through the same isolated native app-server bridge
|
|
11
|
+
* used for reset credits. Failures are per-account: one stale/revoked account
|
|
12
|
+
* never prevents other rows from reporting their Reserve percentage.
|
|
13
|
+
*/
|
|
14
|
+
export async function refreshLunaReserveUsage(storage, now = Date.now) {
|
|
15
|
+
const manager = new AccountManager(undefined, storage);
|
|
16
|
+
const result = {};
|
|
17
|
+
try {
|
|
18
|
+
for (let index = 0; index < storage.accounts.length; index += 1) {
|
|
19
|
+
const stored = storage.accounts[index];
|
|
20
|
+
const account = manager.getAccountByIndex(index);
|
|
21
|
+
if (!stored || !account || account.enabled === false)
|
|
22
|
+
continue;
|
|
23
|
+
const scopes = workspaceModelScopes(account);
|
|
24
|
+
const targetScope = account.workspaces?.length
|
|
25
|
+
? scopes.find((scope) => scope.selected && scope.routable)
|
|
26
|
+
: scopes.find((scope) => scope.bound && scope.routable);
|
|
27
|
+
if (!targetScope)
|
|
28
|
+
continue;
|
|
29
|
+
try {
|
|
30
|
+
const fresh = await ensureFreshAccessToken({
|
|
31
|
+
accountManager: manager,
|
|
32
|
+
account,
|
|
33
|
+
family: "gpt-5.2",
|
|
34
|
+
model: LUNA_RESERVE_MODEL,
|
|
35
|
+
now: now(),
|
|
36
|
+
tokenRefreshSkewMs: 60_000,
|
|
37
|
+
tokenInvalidationCooldownMs: 300_000,
|
|
38
|
+
});
|
|
39
|
+
if (!fresh.ok)
|
|
40
|
+
continue;
|
|
41
|
+
const auth = {
|
|
42
|
+
accessToken: fresh.accessToken,
|
|
43
|
+
accountId: targetScope.accountId,
|
|
44
|
+
expiresAt: fresh.account.expires ?? 0,
|
|
45
|
+
codexCliMirror: account.codexCliMirror,
|
|
46
|
+
};
|
|
47
|
+
const sentAccountId = codexCliAccountIdFor(auth, fresh.accessToken) ?? targetScope.accountId;
|
|
48
|
+
const reply = await nativeRateLimitsRpc(auth, "account/rateLimits/read", {
|
|
49
|
+
supportsLunaReserve: true,
|
|
50
|
+
excludeResetCreditDetails: true,
|
|
51
|
+
});
|
|
52
|
+
if (isRecord(reply) &&
|
|
53
|
+
typeof reply.accountId === "string" &&
|
|
54
|
+
reply.accountId !== sentAccountId) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
result[index] = parseLunaReserveRateLimits(reply, now());
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Best-effort usage reporting; callers still emit normal quota.
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
await manager.flushPendingSave();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { type AccountStorageV3 } from "../storage.js";
|
|
3
|
-
import { type ApiRouteCredential, updateApiModelDiscovery } from "../api-route-store.js";
|
|
2
|
+
import { type AccountStorageV3, loadAccounts } from "../storage.js";
|
|
3
|
+
import { type ApiRouteCredential, loadApiRoutes, updateApiModelDiscovery } from "../api-route-store.js";
|
|
4
4
|
declare const schema: z.ZodObject<{
|
|
5
5
|
apiConfigurationUnavailable: z.ZodOptional<z.ZodBoolean>;
|
|
6
6
|
version: z.ZodLiteral<1>;
|
|
@@ -90,9 +90,13 @@ export declare function refreshAndPrintModelInventory(log: (message: string) =>
|
|
|
90
90
|
}>;
|
|
91
91
|
fetchImpl?: typeof fetch;
|
|
92
92
|
loadInventory?: typeof loadModelInventory;
|
|
93
|
+
loadAccounts?: typeof loadAccounts;
|
|
94
|
+
loadApiRoutes?: typeof loadApiRoutes;
|
|
93
95
|
now?: () => number;
|
|
94
96
|
/** Only an explicit `check capabilities` bypasses the 15-minute probe cache. */
|
|
95
97
|
forceProbes?: boolean;
|
|
98
|
+
/** Installed `codex --version` probe, used when the inventory stores no clientVersion. */
|
|
99
|
+
detectClientVersion?: () => Promise<string | null>;
|
|
96
100
|
}): Promise<boolean>;
|
|
97
101
|
/** Compare stable credential/workspace scopes, keeping the last successful baseline through outages. */
|
|
98
102
|
export declare function withInventoryChanges(current: ModelInventory, previous: ModelInventory | null): ModelInventory;
|
|
@@ -15,6 +15,7 @@ import { loadApiRoutes, updateApiModelDiscovery, } from "../api-route-store.js";
|
|
|
15
15
|
import { ApiModelRuntime, boundedJson } from "./api-model-runtime.js";
|
|
16
16
|
import { AccountModelCatalog } from "./account-model-catalog.js";
|
|
17
17
|
import { ensureFreshAccessToken } from "./rotation-token-refresh.js";
|
|
18
|
+
import { CLIENT_VERSION_PATTERN, detectInstalledCodexCliVersion, } from "../codex-cli/version.js";
|
|
18
19
|
import { createCodexHeaders } from "../request/headers.js";
|
|
19
20
|
import { CODEX_BASE_URL } from "../constants.js";
|
|
20
21
|
import { getCodexMultiAuthDir } from "../runtime-paths.js";
|
|
@@ -103,7 +104,7 @@ export async function discoverModelInventory(storage, routes, options = {}) {
|
|
|
103
104
|
throw Error("Identity unavailable");
|
|
104
105
|
const url = new URL(`${CODEX_BASE_URL}/codex/models`);
|
|
105
106
|
const version = options.clientVersion;
|
|
106
|
-
if (version &&
|
|
107
|
+
if (version && CLIENT_VERSION_PATTERN.test(version))
|
|
107
108
|
url.searchParams.set("client_version", version);
|
|
108
109
|
const response = await fetcher(url, {
|
|
109
110
|
headers: createCodexHeaders({
|
|
@@ -250,6 +251,11 @@ export async function refreshAndPrintModelInventory(log, deps = {}) {
|
|
|
250
251
|
try {
|
|
251
252
|
const load = deps.loadInventory ?? loadModelInventory;
|
|
252
253
|
const previous = await load();
|
|
254
|
+
// The catalog requires client_version (issue #733): the stored inventory
|
|
255
|
+
// version wins, otherwise probe the installed `codex --version` so a fresh
|
|
256
|
+
// inventory seeds one and saves it for the next check.
|
|
257
|
+
const detectClientVersion = async () => (await (deps.detectClientVersion ?? detectInstalledCodexCliVersion)().catch(() => null)) ?? undefined;
|
|
258
|
+
const clientVersion = previous?.clientVersion;
|
|
253
259
|
const binding = await (deps.getBinding ?? getAppBindStatus)();
|
|
254
260
|
if (binding.running && binding.state?.nativeOpenai) {
|
|
255
261
|
const started = (deps.now ?? Date.now)();
|
|
@@ -266,8 +272,9 @@ export async function refreshAndPrintModelInventory(log, deps = {}) {
|
|
|
266
272
|
url.searchParams.set("refresh_capabilities", "1");
|
|
267
273
|
if (deps.forceProbes)
|
|
268
274
|
url.searchParams.set("force_probes", "1");
|
|
269
|
-
|
|
270
|
-
|
|
275
|
+
const proxyClientVersion = clientVersion ?? (await detectClientVersion());
|
|
276
|
+
if (proxyClientVersion)
|
|
277
|
+
url.searchParams.set("client_version", proxyClientVersion);
|
|
271
278
|
const clientApiKey = binding.state.clientApiKey;
|
|
272
279
|
const current = await withCheckProgress("Refreshing workspace catalogs and API/ZDR probes", async () => {
|
|
273
280
|
const response = await (deps.fetchImpl ?? fetch)(url, {
|
|
@@ -294,8 +301,9 @@ export async function refreshAndPrintModelInventory(log, deps = {}) {
|
|
|
294
301
|
}
|
|
295
302
|
const value = await withCheckProgress("Discovering workspace models and API/ZDR capabilities", async () => {
|
|
296
303
|
let apiConfigurationUnavailable = false;
|
|
297
|
-
const value = await discoverModelInventory(await loadAccounts(), await loadApiRoutes().catch(() => { apiConfigurationUnavailable = true; log("API configuration unavailable; checking subscription models only."); return []; }), {
|
|
298
|
-
clientVersion:
|
|
304
|
+
const value = await discoverModelInventory(await (deps.loadAccounts ?? loadAccounts)(), await (deps.loadApiRoutes ?? loadApiRoutes)().catch(() => { apiConfigurationUnavailable = true; log("API configuration unavailable; checking subscription models only."); return []; }), {
|
|
305
|
+
clientVersion: clientVersion ?? (await detectClientVersion()),
|
|
306
|
+
fetchImpl: deps.fetchImpl,
|
|
299
307
|
updateApiDiscovery: updateApiModelDiscovery,
|
|
300
308
|
forceProbes: deps.forceProbes === true,
|
|
301
309
|
persistProbes: true,
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { extractAccountId } from '../accounts.js';
|
|
2
|
+
import { LUNA_RESERVE_MODEL } from '../constants.js';
|
|
2
3
|
import { parseModelRoute } from '../model-route-policy.js';
|
|
3
4
|
import { subscriptionQuotaPreference } from './subscription-quota-order.js';
|
|
4
5
|
import { resetSnapshotQuota } from './reset-credits.js';
|
|
5
6
|
export async function recoverResetQuota(options) {
|
|
6
|
-
if (!options.native || options.pinned || parseModelRoute(options.model).kind !== 'oauth')
|
|
7
|
+
if (options.model === LUNA_RESERVE_MODEL || !options.native || options.pinned || parseModelRoute(options.model).kind !== 'oauth')
|
|
7
8
|
return false;
|
|
8
9
|
const family = options.family ?? 'codex';
|
|
9
10
|
const candidates = [...options.scopes].flatMap(([index, scopes]) => { const account = options.manager.getAccountByIndex(index); return account && !account.authInvalidatedAt ? scopes.map(scope => ({ account, scope })) : []; });
|
|
@@ -50,6 +51,8 @@ export async function recoverResetQuota(options) {
|
|
|
50
51
|
}
|
|
51
52
|
/** Apply a confirmed earned reset once per workspace/model observation. */
|
|
52
53
|
export function applyConfirmedReset(options) {
|
|
54
|
+
if (options.model === LUNA_RESERVE_MODEL)
|
|
55
|
+
return false;
|
|
53
56
|
const s = options.snapshot;
|
|
54
57
|
if (!s || options.lastRedemptionAt === undefined || s.updatedAt < options.lastRedemptionAt || s.ordinaryUsageAllowed !== true || s.updatedAt <= (options.previous?.updatedAt ?? 0) || options.now - s.updatedAt > 60000 || s.updatedAt > options.now)
|
|
55
58
|
return false;
|
|
@@ -26,6 +26,8 @@ export interface RuntimeRotationProxyStatus {
|
|
|
26
26
|
totalRequests: number;
|
|
27
27
|
upstreamRequests: number;
|
|
28
28
|
retries: number;
|
|
29
|
+
/** Number of ordinary GPT-6 Luna requests retried through Luna Reserve. */
|
|
30
|
+
lunaReserveFallbacks?: number;
|
|
29
31
|
rotations: number;
|
|
30
32
|
streamsStarted: number;
|
|
31
33
|
lastError: string | null;
|
|
@@ -35,6 +35,8 @@ export interface RuntimeObservabilitySnapshot {
|
|
|
35
35
|
responsesRequests: number;
|
|
36
36
|
authRefreshRequests: number;
|
|
37
37
|
diagnosticProbeRequests: number;
|
|
38
|
+
/** Number of ordinary Luna requests that switched to the separately metered Reserve model. */
|
|
39
|
+
lunaReserveFallbacks: number;
|
|
38
40
|
poolExhaustionCooldownUntil: number | null;
|
|
39
41
|
serverBurstCooldownUntil: number | null;
|
|
40
42
|
lastAccountIndex?: number | null;
|