feat: Codex account rotation + fix rate-limit detection
- New codex-token-rotation module: rotates between multiple
~/.codex-accounts/{n}/auth.json on rate-limit
- Copies active account auth to session dir before each spawn
- Fix detectFallbackTrigger to match "usage limit" / "hit your limit"
- Fix streamed error detection: remove claude-only guard so codex
rate-limit errors are caught even when output.status is "success"
- Add rotation in both task-scheduler and message-agent-executor
This commit is contained in:
@@ -21,7 +21,16 @@ import {
|
||||
markPrimaryCooldown,
|
||||
} from './provider-fallback.js';
|
||||
import { shouldResetSessionOnAgentFailure } from './session-recovery.js';
|
||||
import { rotateToken, getTokenCount, markTokenHealthy } from './token-rotation.js';
|
||||
import {
|
||||
rotateCodexToken,
|
||||
getCodexAccountCount,
|
||||
markCodexTokenHealthy,
|
||||
} from './codex-token-rotation.js';
|
||||
import {
|
||||
rotateToken,
|
||||
getTokenCount,
|
||||
markTokenHealthy,
|
||||
} from './token-rotation.js';
|
||||
import type { RegisteredGroup } from './types.js';
|
||||
|
||||
export interface MessageAgentExecutorDeps {
|
||||
@@ -138,7 +147,6 @@ export async function runAgentForGroup(
|
||||
sawSuccessNullResultWithoutOutput = true;
|
||||
}
|
||||
if (
|
||||
provider === 'claude' &&
|
||||
output.status === 'error' &&
|
||||
!sawOutput &&
|
||||
!streamedTriggerReason
|
||||
@@ -390,6 +398,22 @@ export async function runAgentForGroup(
|
||||
}
|
||||
}
|
||||
|
||||
// Codex rate-limit rotation (non-Claude agents)
|
||||
if (!isClaudeCodeAgent && getCodexAccountCount() > 1) {
|
||||
const trigger = detectFallbackTrigger(output.error);
|
||||
if (trigger.shouldFallback && rotateCodexToken()) {
|
||||
logger.info(
|
||||
{ chatJid, group: group.name, runId, reason: trigger.reason },
|
||||
'Codex rate-limited, retrying with rotated account',
|
||||
);
|
||||
const retryAttempt = await runAttempt('codex');
|
||||
if (!retryAttempt.error) {
|
||||
markCodexTokenHealthy();
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.error(
|
||||
{
|
||||
group: group.name,
|
||||
@@ -403,5 +427,25 @@ export async function runAgentForGroup(
|
||||
return 'error';
|
||||
}
|
||||
|
||||
// Codex may report success but have streamed a rate-limit error.
|
||||
// Rotate token so the NEXT request uses a fresh account.
|
||||
if (
|
||||
!isClaudeCodeAgent &&
|
||||
primaryAttempt.streamedTriggerReason &&
|
||||
getCodexAccountCount() > 1
|
||||
) {
|
||||
if (rotateCodexToken()) {
|
||||
logger.info(
|
||||
{
|
||||
chatJid,
|
||||
group: group.name,
|
||||
runId,
|
||||
reason: primaryAttempt.streamedTriggerReason.reason,
|
||||
},
|
||||
'Codex rate-limited (streamed), rotated account for next request',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return 'success';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user