feat: parse retry-after from errors, cache codex usage per account

- Parse "try again at" time from rate-limit errors instead of
  fixed 1-hour cooldown, with 3-min buffer after reset
- Pass error message to rotateToken/rotateCodexToken for parsing
- Cache usage % and reset time per Codex account for dashboard
- Persist cached usage in rotation state file across restarts
- Show rate-limited Codex accounts with cached 100% + reset time
- Fix dashboard text indicators (*!/space) for monospace alignment
This commit is contained in:
Eyejoker
2026-03-24 01:16:54 +09:00
parent 2e6fc4a08e
commit 60dab43a3f
5 changed files with 139 additions and 24 deletions

View File

@@ -309,7 +309,7 @@ export async function runAgentForGroup(
: detectFallbackTrigger(errMsg);
if (trigger.shouldFallback) {
// Try rotating token before falling back to another provider
if (getTokenCount() > 1 && rotateToken()) {
if (getTokenCount() > 1 && rotateToken(errMsg)) {
logger.info(
{ chatJid, group: group.name, runId, reason: trigger.reason },
'Rate-limited, retrying with rotated token',
@@ -383,7 +383,7 @@ export async function runAgentForGroup(
}
: detectFallbackTrigger(output.error);
if (trigger.shouldFallback) {
if (getTokenCount() > 1 && rotateToken()) {
if (getTokenCount() > 1 && rotateToken(output.error ?? undefined)) {
logger.info(
{ chatJid, group: group.name, runId, reason: trigger.reason },
'Rate-limited (output error), retrying with rotated token',
@@ -401,7 +401,7 @@ export async function runAgentForGroup(
// Codex rate-limit rotation (non-Claude agents)
if (!isClaudeCodeAgent && getCodexAccountCount() > 1) {
const trigger = detectFallbackTrigger(output.error);
if (trigger.shouldFallback && rotateCodexToken()) {
if (trigger.shouldFallback && rotateCodexToken(output.error ?? undefined)) {
logger.info(
{ chatJid, group: group.name, runId, reason: trigger.reason },
'Codex rate-limited, retrying with rotated account',
@@ -433,7 +433,7 @@ export async function runAgentForGroup(
!isClaudeCodeAgent &&
primaryAttempt.streamedTriggerReason &&
getCodexAccountCount() > 1 &&
rotateCodexToken()
rotateCodexToken(output.error ?? undefined)
) {
logger.info(
{