Unify paired status transitions and retry handling

This commit is contained in:
ejclaw
2026-04-07 02:49:02 +09:00
parent 4511ca5692
commit b8e8c9dabf
13 changed files with 574 additions and 280 deletions

View File

@@ -23,6 +23,7 @@ import { classifyRotationTrigger } from './agent-error-detection.js';
import { detectCodexRotationTrigger } from './codex-token-rotation.js';
import {
isRetryableClaudeSessionFailureAttempt,
resolveAttemptRetryAction,
resolveClaudeRetryTrigger,
resolveCodexRetryTrigger,
resolvePairedFollowUpQueueAction,
@@ -88,6 +89,47 @@ describe('message-agent-executor-rules', () => {
expect(detectCodexRotationTrigger).not.toHaveBeenCalled();
});
it('resolves a shared Claude retry action from fallback output text', () => {
vi.mocked(classifyRotationTrigger).mockReturnValue({
shouldRetry: true,
reason: '429',
retryAfterMs: 30000,
});
expect(
resolveAttemptRetryAction({
provider: 'claude',
canRetryClaudeCredentials: true,
canRetryCodex: false,
attempt: { sawOutput: false },
rotationMessage: '429 rate limit',
}),
).toEqual({
kind: 'claude',
trigger: { reason: '429', retryAfterMs: 30000 },
rotationMessage: '429 rate limit',
});
});
it('resolves a shared Codex retry action from streamed state', () => {
expect(
resolveAttemptRetryAction({
provider: 'codex',
canRetryClaudeCredentials: false,
canRetryCodex: true,
attempt: {
sawOutput: false,
streamedTriggerReason: { reason: 'auth-expired' },
},
rotationMessage: 'oauth token expired',
}),
).toEqual({
kind: 'codex',
trigger: { reason: 'auth-expired' },
rotationMessage: 'oauth token expired',
});
});
it('detects retryable Claude session failures from either flag or classifier', () => {
expect(
isRetryableClaudeSessionFailureAttempt({