@foxden-app/foxclaw 0.5.21 → 0.5.23
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/CHANGELOG.md +20 -0
- package/dist/controller/controller.js +59 -23
- package/dist/i18n.d.ts +12 -0
- package/dist/i18n.js +12 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
All notable FoxClaw changes are listed here. Each release note is bilingual so GitHub Releases and the npm package are useful to both Chinese and English readers.
|
|
4
4
|
|
|
5
|
+
## 0.5.23 - 2026-06-09
|
|
6
|
+
|
|
7
|
+
### 中文
|
|
8
|
+
- 补齐切换后验证路径:如果目标候选在验证 rate-limit usage 时返回 usage/rate/quota/billing/credits limit,FoxClaw 会恢复到原 auth,但不会把目标候选标记为 `?`,也不会触发自动剔除。
|
|
9
|
+
- 这让额度耗尽在自动轮换、手动切换和验证失败提示里都保持同一语义:它只是暂时没额度,不是凭据失效。
|
|
10
|
+
|
|
11
|
+
### English
|
|
12
|
+
- Completed the post-switch validation path: if the selected candidate returns a usage/rate/quota/billing/credits limit while validating rate-limit usage, FoxClaw restores the previous auth but does not mark the selected candidate `?` or auto-delete it.
|
|
13
|
+
- Quota exhaustion now has the same meaning across automatic rotation, manual switching, and validation failure messages: temporarily out of quota, not an invalid credential.
|
|
14
|
+
|
|
15
|
+
## 0.5.22 - 2026-06-09
|
|
16
|
+
|
|
17
|
+
### 中文
|
|
18
|
+
- Codex 报 `usageLimitExceeded`、`You've hit your usage limit`、usage/rate/quota/billing/credits limit 这类额度耗尽时,不再把当前 auth 候选标记为需要修复,也不会触发 `AUTH_AUTO_DELETE_NEEDS_REPAIR` 的自动剔除和跨节点删除。
|
|
19
|
+
- 额度耗尽仍会临时避开当前候选,切到另一个维护中的候选重试;提示文案改为“Codex 额度限制”,不再误写成 “Codex auth 问题”。
|
|
20
|
+
|
|
21
|
+
### English
|
|
22
|
+
- Codex quota exhaustion such as `usageLimitExceeded`, `You've hit your usage limit`, usage/rate/quota/billing/credits limit is no longer treated as an invalid auth candidate, so it does not mark `needs_repair` or trigger `AUTH_AUTO_DELETE_NEEDS_REPAIR` auto-delete / cross-node delete.
|
|
23
|
+
- Quota exhaustion still temporarily skips the current candidate and retries with another maintained candidate; notifications now call this a Codex usage limit instead of an auth problem.
|
|
24
|
+
|
|
5
25
|
## 0.5.21 - 2026-06-09
|
|
6
26
|
|
|
7
27
|
### 中文
|
|
@@ -1390,7 +1390,8 @@ export class BridgeSessionCore {
|
|
|
1390
1390
|
: threadId
|
|
1391
1391
|
? this.findActiveTurnsByThreadId(threadId)
|
|
1392
1392
|
: [];
|
|
1393
|
-
const
|
|
1393
|
+
const authRotationReason = classifyCodexAuthRotationError(params);
|
|
1394
|
+
const isAuthRotationError = authRotationReason !== null;
|
|
1394
1395
|
const willRetry = params?.willRetry === true;
|
|
1395
1396
|
const active = isAuthRotationError
|
|
1396
1397
|
? activeTurns.find(turn => turn.authRetry !== null) ?? activeTurns.find(turn => !turn.isObserved) ?? activeTurns[0] ?? null
|
|
@@ -1403,12 +1404,13 @@ export class BridgeSessionCore {
|
|
|
1403
1404
|
else if (turnId) {
|
|
1404
1405
|
this.pendingTurnErrors.set(turnId, message);
|
|
1405
1406
|
}
|
|
1406
|
-
if (
|
|
1407
|
+
if (authRotationReason && !willRetry && active?.authRetry) {
|
|
1407
1408
|
const scopeId = active.scopeId;
|
|
1408
1409
|
if (scopeId) {
|
|
1409
1410
|
this.pendingAuthRotation = {
|
|
1410
1411
|
scopeId,
|
|
1411
1412
|
reason: message,
|
|
1413
|
+
reasonKind: authRotationReason,
|
|
1412
1414
|
retry: cloneAuthRetryContext(active.authRetry),
|
|
1413
1415
|
};
|
|
1414
1416
|
}
|
|
@@ -5504,7 +5506,7 @@ export class BridgeSessionCore {
|
|
|
5504
5506
|
const failedTargets = rotation.retry?.failedAuthTargets ?? this.authRotationFailedTargets;
|
|
5505
5507
|
const locale = this.localeForChat(rotation.scopeId);
|
|
5506
5508
|
const current = (await this.listCodexAuthState()).candidates.find(candidate => candidate.isCurrent) ?? null;
|
|
5507
|
-
if (current) {
|
|
5509
|
+
if (current && rotation.reasonKind === 'auth_invalid') {
|
|
5508
5510
|
const recoveredCurrent = await this.recoverCodexAuthCandidate(current.name);
|
|
5509
5511
|
if (recoveredCurrent) {
|
|
5510
5512
|
await this.sendMessage(rotation.scopeId, t(locale, 'auth_auto_recovered_current', {
|
|
@@ -5528,19 +5530,22 @@ export class BridgeSessionCore {
|
|
|
5528
5530
|
}
|
|
5529
5531
|
const selection = await this.selectNextCodexAuthCandidate(failedTargets);
|
|
5530
5532
|
if (!selection) {
|
|
5531
|
-
await this.sendMessage(rotation.scopeId, t(locale, 'auth_auto_no_candidate', {
|
|
5533
|
+
await this.sendMessage(rotation.scopeId, t(locale, rotation.reasonKind === 'quota_limited' ? 'auth_quota_no_candidate' : 'auth_auto_no_candidate', {
|
|
5532
5534
|
error: formatShortStatusError(rotation.reason),
|
|
5533
5535
|
}));
|
|
5534
5536
|
return false;
|
|
5535
5537
|
}
|
|
5536
5538
|
const { candidate, fromLabel, toLabel } = selection;
|
|
5539
|
+
const switchingKey = rotation.reasonKind === 'quota_limited'
|
|
5540
|
+
? (this.config.authAutoDeleteNeedsRepair ? 'auth_quota_switching_quiet' : 'auth_quota_switching')
|
|
5541
|
+
: (this.config.authAutoDeleteNeedsRepair ? 'auth_auto_switching_quiet' : 'auth_auto_switching');
|
|
5537
5542
|
await this.sendMessage(rotation.scopeId, this.config.authAutoDeleteNeedsRepair
|
|
5538
|
-
? t(locale,
|
|
5539
|
-
: t(locale,
|
|
5543
|
+
? t(locale, switchingKey, { error: formatShortStatusError(rotation.reason) })
|
|
5544
|
+
: t(locale, switchingKey, {
|
|
5540
5545
|
...this.codexAuthSwitchParams(locale, fromLabel, toLabel),
|
|
5541
5546
|
error: formatShortStatusError(rotation.reason),
|
|
5542
5547
|
}));
|
|
5543
|
-
const outcome = await this.switchCodexAuthAndRestart(rotation.scopeId, locale, candidate, true);
|
|
5548
|
+
const outcome = await this.switchCodexAuthAndRestart(rotation.scopeId, locale, candidate, true, true, rotation.reasonKind);
|
|
5544
5549
|
if (!outcome.ok) {
|
|
5545
5550
|
return false;
|
|
5546
5551
|
}
|
|
@@ -5659,7 +5664,7 @@ export class BridgeSessionCore {
|
|
|
5659
5664
|
to: toLabel,
|
|
5660
5665
|
};
|
|
5661
5666
|
}
|
|
5662
|
-
async switchCodexAuthAndRestart(scopeId, locale, candidate, automatic, sendResult = true) {
|
|
5667
|
+
async switchCodexAuthAndRestart(scopeId, locale, candidate, automatic, sendResult = true, automaticReason = 'auth_invalid') {
|
|
5663
5668
|
const authDir = this.resolveAuthDir();
|
|
5664
5669
|
const initialState = await listCodexAuthState(new Set(), new Map(), authDir);
|
|
5665
5670
|
const authStat = await fs.lstat(initialState.authPath).catch(() => null);
|
|
@@ -5688,13 +5693,19 @@ export class BridgeSessionCore {
|
|
|
5688
5693
|
error: toErrorMeta(error),
|
|
5689
5694
|
});
|
|
5690
5695
|
}
|
|
5691
|
-
const
|
|
5696
|
+
const validationFailureKind = isCodexQuotaLimitError(validation.error)
|
|
5697
|
+
? 'quota_limited'
|
|
5698
|
+
: 'auth_invalid';
|
|
5699
|
+
const repairDisposition = validationFailureKind === 'auth_invalid'
|
|
5700
|
+
? await this.markCodexAuthCandidateNeedsRepair(candidate.name)
|
|
5701
|
+
: { deleted: false, restarted: false };
|
|
5692
5702
|
const outcome = {
|
|
5693
5703
|
...result,
|
|
5694
5704
|
ok: false,
|
|
5695
5705
|
candidateName: candidate.name,
|
|
5696
5706
|
recovered,
|
|
5697
5707
|
error: validation.error,
|
|
5708
|
+
validationFailureKind,
|
|
5698
5709
|
restoredPrevious,
|
|
5699
5710
|
autoDeleted: repairDisposition.deleted,
|
|
5700
5711
|
deleteRestarted: repairDisposition.restarted,
|
|
@@ -5713,6 +5724,7 @@ export class BridgeSessionCore {
|
|
|
5713
5724
|
candidateName: candidate.name,
|
|
5714
5725
|
recovered,
|
|
5715
5726
|
error: null,
|
|
5727
|
+
validationFailureKind: null,
|
|
5716
5728
|
restoredPrevious: false,
|
|
5717
5729
|
autoDeleted: false,
|
|
5718
5730
|
deleteRestarted: false,
|
|
@@ -5720,9 +5732,11 @@ export class BridgeSessionCore {
|
|
|
5720
5732
|
if (!sendResult) {
|
|
5721
5733
|
return outcome;
|
|
5722
5734
|
}
|
|
5735
|
+
const doneKey = automaticReason === 'quota_limited' ? 'auth_quota_done' : 'auth_auto_done';
|
|
5736
|
+
const doneQuietKey = automaticReason === 'quota_limited' ? 'auth_quota_done_quiet' : 'auth_auto_done_quiet';
|
|
5723
5737
|
const lines = [automatic && this.config.authAutoDeleteNeedsRepair
|
|
5724
|
-
? t(locale,
|
|
5725
|
-
: t(locale, automatic ?
|
|
5738
|
+
? t(locale, doneQuietKey)
|
|
5739
|
+
: t(locale, automatic ? doneKey : 'auth_switch_done', this.codexAuthSwitchParams(locale, result.fromLabel, result.toLabel))];
|
|
5726
5740
|
if (recovered) {
|
|
5727
5741
|
lines.push(t(locale, 'auth_recovered_newer_candidate', { value: candidate.name }));
|
|
5728
5742
|
}
|
|
@@ -5771,11 +5785,13 @@ export class BridgeSessionCore {
|
|
|
5771
5785
|
if (outcome.ok) {
|
|
5772
5786
|
return [];
|
|
5773
5787
|
}
|
|
5774
|
-
const validationKey = outcome.
|
|
5775
|
-
? '
|
|
5776
|
-
: outcome.autoDeleted
|
|
5777
|
-
? '
|
|
5778
|
-
:
|
|
5788
|
+
const validationKey = outcome.validationFailureKind === 'quota_limited'
|
|
5789
|
+
? 'auth_switch_validation_quota_limited'
|
|
5790
|
+
: outcome.autoDeleted && this.config.authAutoDeleteNeedsRepair
|
|
5791
|
+
? 'auth_switch_validation_auto_deleted_quiet'
|
|
5792
|
+
: outcome.autoDeleted
|
|
5793
|
+
? 'auth_switch_validation_auto_deleted'
|
|
5794
|
+
: 'auth_switch_validation_failed';
|
|
5779
5795
|
return [
|
|
5780
5796
|
t(locale, validationKey, {
|
|
5781
5797
|
value: outcome.candidateName,
|
|
@@ -9337,16 +9353,36 @@ function cloneAuthRetryContext(context) {
|
|
|
9337
9353
|
failedAuthTargets: new Set(context.failedAuthTargets),
|
|
9338
9354
|
};
|
|
9339
9355
|
}
|
|
9340
|
-
function
|
|
9341
|
-
|
|
9342
|
-
|
|
9356
|
+
function classifyCodexAuthRotationError(params) {
|
|
9357
|
+
const collected = collectCodexErrorText(params);
|
|
9358
|
+
if (isChatGptBackendAccessBlocked(collected)) {
|
|
9359
|
+
return null;
|
|
9343
9360
|
}
|
|
9344
9361
|
const code = stringOrNull(params?.error?.codexErrorInfo) ?? stringOrNull(params?.error?.code);
|
|
9345
|
-
if (code && /usageLimitExceeded|auth|unauthorized|forbidden|login/i.test(code)) {
|
|
9346
|
-
return true;
|
|
9347
|
-
}
|
|
9348
9362
|
const message = stringOrNull(params?.error?.message) ?? '';
|
|
9349
|
-
|
|
9363
|
+
const text = `${code ?? ''}\n${message}\n${collected}`;
|
|
9364
|
+
if (isCodexQuotaLimitError(text)) {
|
|
9365
|
+
return 'quota_limited';
|
|
9366
|
+
}
|
|
9367
|
+
if (code && /auth|unauthorized|forbidden|login/i.test(code)) {
|
|
9368
|
+
return 'auth_invalid';
|
|
9369
|
+
}
|
|
9370
|
+
return /(not authenticated|unauthorized|forbidden|sign in|log in|login|auth)/i.test(message)
|
|
9371
|
+
? 'auth_invalid'
|
|
9372
|
+
: null;
|
|
9373
|
+
}
|
|
9374
|
+
function isCodexQuotaLimitError(text) {
|
|
9375
|
+
return /usageLimitExceeded/i.test(text)
|
|
9376
|
+
|| /you['’]?ve hit your usage limit/i.test(text)
|
|
9377
|
+
|| /\busage limit(?:s)?\b/i.test(text)
|
|
9378
|
+
|| /\brate limit(?:ed|s)?\b/i.test(text)
|
|
9379
|
+
|| /\btoo many requests\b/i.test(text)
|
|
9380
|
+
|| /\binsufficient[_\s-]?quota\b/i.test(text)
|
|
9381
|
+
|| /\bquota exceeded\b/i.test(text)
|
|
9382
|
+
|| /\bbilling hard limit\b/i.test(text)
|
|
9383
|
+
|| /\bcredits? exhausted\b/i.test(text)
|
|
9384
|
+
|| /\bout of credits?\b/i.test(text)
|
|
9385
|
+
|| /\bcredits? limit\b/i.test(text);
|
|
9350
9386
|
}
|
|
9351
9387
|
function formatCodexNotificationError(params) {
|
|
9352
9388
|
const collected = collectCodexErrorText(params);
|
package/dist/i18n.d.ts
CHANGED
|
@@ -199,6 +199,7 @@ declare const MESSAGES: {
|
|
|
199
199
|
readonly auth_switch_validation_failed: "Selected auth failed validation: {error}. Marked {value} for login repair.";
|
|
200
200
|
readonly auth_switch_validation_auto_deleted: "Selected auth failed validation: {error}. Auto-deleted {value}.";
|
|
201
201
|
readonly auth_switch_validation_auto_deleted_quiet: "Selected auth failed validation and was auto-deleted.";
|
|
202
|
+
readonly auth_switch_validation_quota_limited: "Selected auth hit a Codex usage limit: {error}. It was not marked invalid.";
|
|
202
203
|
readonly auth_switch_validation_reverted: "Restored the previous auth after the failed switch.";
|
|
203
204
|
readonly auth_recovered_newer_candidate: "Recovered a newer same-account credential for {value} from another Codex home before reload.";
|
|
204
205
|
readonly auth_refresh_all_confirm_short: "Review refresh all risk first.";
|
|
@@ -219,9 +220,14 @@ declare const MESSAGES: {
|
|
|
219
220
|
readonly auth_auto_recovered_current: "Codex auth problem detected ({error}). Recovered a newer same-account credential for {value} and restarted Codex app-server.";
|
|
220
221
|
readonly auth_auto_done: "Auto-switched Codex auth: {from} -> {to}.";
|
|
221
222
|
readonly auth_auto_done_quiet: "Codex auth problem handled with another maintained candidate.";
|
|
223
|
+
readonly auth_quota_switching: "Codex usage limit detected ({error}). Switching: {from} -> {to}...";
|
|
224
|
+
readonly auth_quota_switching_quiet: "Codex usage limit detected ({error}). Selecting another maintained candidate...";
|
|
225
|
+
readonly auth_quota_done: "Switched Codex auth after usage limit: {from} -> {to}.";
|
|
226
|
+
readonly auth_quota_done_quiet: "Codex usage limit handled with another maintained candidate.";
|
|
222
227
|
readonly auth_auto_retrying: "Retrying the same request with the new auth...";
|
|
223
228
|
readonly auth_auto_retry_thread_missing: "Auth was switched, but the original thread is no longer available ({threadId}). Retry was stopped to avoid creating duplicate sessions.";
|
|
224
229
|
readonly auth_auto_no_candidate: "Codex auth problem detected ({error}), but no unused auth candidate is available.";
|
|
230
|
+
readonly auth_quota_no_candidate: "Codex usage limit detected ({error}), but no unused auth candidate is available.";
|
|
225
231
|
readonly auth_add_exists: "Auth candidate already exists: {value}";
|
|
226
232
|
readonly auth_add_preparing: "Preparing new Codex auth candidate {value}...";
|
|
227
233
|
readonly auth_add_started: "New auth login started for {value}.";
|
|
@@ -887,6 +893,7 @@ declare const MESSAGES: {
|
|
|
887
893
|
readonly auth_switch_validation_failed: "选中的 auth 验证失败:{error}。已将 {value} 标记为需要登录修复。";
|
|
888
894
|
readonly auth_switch_validation_auto_deleted: "选中的 auth 验证失败:{error}。已自动剔除 {value}。";
|
|
889
895
|
readonly auth_switch_validation_auto_deleted_quiet: "选中的 auth 验证失败,已自动剔除。";
|
|
896
|
+
readonly auth_switch_validation_quota_limited: "选中的 auth 已触发 Codex 额度限制:{error}。没有把它标记为失效。";
|
|
890
897
|
readonly auth_switch_validation_reverted: "已在切换失败后恢复到之前的 auth。";
|
|
891
898
|
readonly auth_recovered_newer_candidate: "重载前已从其他 Codex home 恢复 {value} 的同账号较新凭据。";
|
|
892
899
|
readonly auth_refresh_all_confirm_short: "请先确认刷新全部风险。";
|
|
@@ -907,9 +914,14 @@ declare const MESSAGES: {
|
|
|
907
914
|
readonly auth_auto_recovered_current: "检测到 Codex auth 问题({error}),已为 {value} 恢复同账号较新凭据并重启 Codex app-server。";
|
|
908
915
|
readonly auth_auto_done: "已自动切换 Codex auth:{from} -> {to}。";
|
|
909
916
|
readonly auth_auto_done_quiet: "Codex auth 问题已用另一个维护中的候选处理。";
|
|
917
|
+
readonly auth_quota_switching: "检测到 Codex 额度限制({error}),正在切换:{from} -> {to}...";
|
|
918
|
+
readonly auth_quota_switching_quiet: "检测到 Codex 额度限制({error}),正在选择另一个维护中的候选...";
|
|
919
|
+
readonly auth_quota_done: "已因 Codex 额度限制自动切换 auth:{from} -> {to}。";
|
|
920
|
+
readonly auth_quota_done_quiet: "Codex 额度限制已用另一个维护中的候选处理。";
|
|
910
921
|
readonly auth_auto_retrying: "正在用新的 auth 重试同一条请求...";
|
|
911
922
|
readonly auth_auto_retry_thread_missing: "Auth 已切换,但原线程已经不可用({threadId})。已停止重试,避免创建重复 session。";
|
|
912
923
|
readonly auth_auto_no_candidate: "检测到 Codex auth 问题({error}),但没有可用的未失败候选 auth。";
|
|
924
|
+
readonly auth_quota_no_candidate: "检测到 Codex 额度限制({error}),但没有可用的未失败候选 auth。";
|
|
913
925
|
readonly auth_add_exists: "auth 候选已经存在:{value}";
|
|
914
926
|
readonly auth_add_preparing: "正在准备新的 Codex auth 候选 {value}...";
|
|
915
927
|
readonly auth_add_started: "{value} 的新 auth 登录已开始。";
|
package/dist/i18n.js
CHANGED
|
@@ -197,6 +197,7 @@ const MESSAGES = {
|
|
|
197
197
|
auth_switch_validation_failed: 'Selected auth failed validation: {error}. Marked {value} for login repair.',
|
|
198
198
|
auth_switch_validation_auto_deleted: 'Selected auth failed validation: {error}. Auto-deleted {value}.',
|
|
199
199
|
auth_switch_validation_auto_deleted_quiet: 'Selected auth failed validation and was auto-deleted.',
|
|
200
|
+
auth_switch_validation_quota_limited: 'Selected auth hit a Codex usage limit: {error}. It was not marked invalid.',
|
|
200
201
|
auth_switch_validation_reverted: 'Restored the previous auth after the failed switch.',
|
|
201
202
|
auth_recovered_newer_candidate: 'Recovered a newer same-account credential for {value} from another Codex home before reload.',
|
|
202
203
|
auth_refresh_all_confirm_short: 'Review refresh all risk first.',
|
|
@@ -217,9 +218,14 @@ const MESSAGES = {
|
|
|
217
218
|
auth_auto_recovered_current: 'Codex auth problem detected ({error}). Recovered a newer same-account credential for {value} and restarted Codex app-server.',
|
|
218
219
|
auth_auto_done: 'Auto-switched Codex auth: {from} -> {to}.',
|
|
219
220
|
auth_auto_done_quiet: 'Codex auth problem handled with another maintained candidate.',
|
|
221
|
+
auth_quota_switching: 'Codex usage limit detected ({error}). Switching: {from} -> {to}...',
|
|
222
|
+
auth_quota_switching_quiet: 'Codex usage limit detected ({error}). Selecting another maintained candidate...',
|
|
223
|
+
auth_quota_done: 'Switched Codex auth after usage limit: {from} -> {to}.',
|
|
224
|
+
auth_quota_done_quiet: 'Codex usage limit handled with another maintained candidate.',
|
|
220
225
|
auth_auto_retrying: 'Retrying the same request with the new auth...',
|
|
221
226
|
auth_auto_retry_thread_missing: 'Auth was switched, but the original thread is no longer available ({threadId}). Retry was stopped to avoid creating duplicate sessions.',
|
|
222
227
|
auth_auto_no_candidate: 'Codex auth problem detected ({error}), but no unused auth candidate is available.',
|
|
228
|
+
auth_quota_no_candidate: 'Codex usage limit detected ({error}), but no unused auth candidate is available.',
|
|
223
229
|
auth_add_exists: 'Auth candidate already exists: {value}',
|
|
224
230
|
auth_add_preparing: 'Preparing new Codex auth candidate {value}...',
|
|
225
231
|
auth_add_started: 'New auth login started for {value}.',
|
|
@@ -885,6 +891,7 @@ const MESSAGES = {
|
|
|
885
891
|
auth_switch_validation_failed: '选中的 auth 验证失败:{error}。已将 {value} 标记为需要登录修复。',
|
|
886
892
|
auth_switch_validation_auto_deleted: '选中的 auth 验证失败:{error}。已自动剔除 {value}。',
|
|
887
893
|
auth_switch_validation_auto_deleted_quiet: '选中的 auth 验证失败,已自动剔除。',
|
|
894
|
+
auth_switch_validation_quota_limited: '选中的 auth 已触发 Codex 额度限制:{error}。没有把它标记为失效。',
|
|
888
895
|
auth_switch_validation_reverted: '已在切换失败后恢复到之前的 auth。',
|
|
889
896
|
auth_recovered_newer_candidate: '重载前已从其他 Codex home 恢复 {value} 的同账号较新凭据。',
|
|
890
897
|
auth_refresh_all_confirm_short: '请先确认刷新全部风险。',
|
|
@@ -905,9 +912,14 @@ const MESSAGES = {
|
|
|
905
912
|
auth_auto_recovered_current: '检测到 Codex auth 问题({error}),已为 {value} 恢复同账号较新凭据并重启 Codex app-server。',
|
|
906
913
|
auth_auto_done: '已自动切换 Codex auth:{from} -> {to}。',
|
|
907
914
|
auth_auto_done_quiet: 'Codex auth 问题已用另一个维护中的候选处理。',
|
|
915
|
+
auth_quota_switching: '检测到 Codex 额度限制({error}),正在切换:{from} -> {to}...',
|
|
916
|
+
auth_quota_switching_quiet: '检测到 Codex 额度限制({error}),正在选择另一个维护中的候选...',
|
|
917
|
+
auth_quota_done: '已因 Codex 额度限制自动切换 auth:{from} -> {to}。',
|
|
918
|
+
auth_quota_done_quiet: 'Codex 额度限制已用另一个维护中的候选处理。',
|
|
908
919
|
auth_auto_retrying: '正在用新的 auth 重试同一条请求...',
|
|
909
920
|
auth_auto_retry_thread_missing: 'Auth 已切换,但原线程已经不可用({threadId})。已停止重试,避免创建重复 session。',
|
|
910
921
|
auth_auto_no_candidate: '检测到 Codex auth 问题({error}),但没有可用的未失败候选 auth。',
|
|
922
|
+
auth_quota_no_candidate: '检测到 Codex 额度限制({error}),但没有可用的未失败候选 auth。',
|
|
911
923
|
auth_add_exists: 'auth 候选已经存在:{value}',
|
|
912
924
|
auth_add_preparing: '正在准备新的 Codex auth 候选 {value}...',
|
|
913
925
|
auth_add_started: '{value} 的新 auth 登录已开始。',
|