fix: detect org-access-denied errors, suppress chat output, and rotate Claude tokens
When a Claude account is suspended, the API returns "Your organization does not have access to Claude" on the success path or "Failed to authenticate. API Error: 403 terminated" on the error path. Both are now classified as 'org-access-denied', suppressed from Discord output, and trigger automatic token rotation. If all tokens are exhausted, enters cooldown without Kimi fallback (same as usage-exhausted and auth-expired). Changes: - agent-error-detection: add isClaudeOrgAccessDeniedMessage(), expand classifyClaudeAuthError() and shouldRotateClaudeToken() - streamed-output-evaluator: detect org-access-denied in success-path chain - provider-fallback: add NO_FALLBACK_COOLDOWN_REASONS set and isPrimaryNoFallbackCooldownActive() helper - provider-retry: handle org-access-denied in rotation loop - message-agent-executor / task-scheduler: use generalized no-fallback cooldown check - Tests: +8 test cases across 5 test files (415 total passing) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,7 @@ import {
|
||||
detectFallbackTrigger,
|
||||
getActiveProvider,
|
||||
getCooldownInfo,
|
||||
isPrimaryNoFallbackCooldownActive,
|
||||
markPrimaryCooldown,
|
||||
resetFallbackConfig,
|
||||
} from './provider-fallback.js';
|
||||
@@ -133,4 +134,36 @@ describe('provider fallback usage recovery', () => {
|
||||
reason: 'auth-expired',
|
||||
});
|
||||
});
|
||||
|
||||
it('treats Claude org access denied banners as an org-access-denied fallback trigger', () => {
|
||||
expect(
|
||||
detectFallbackTrigger(
|
||||
'Your organization does not have access to Claude. Please login again or contact your administrator.',
|
||||
),
|
||||
).toEqual({
|
||||
shouldFallback: true,
|
||||
reason: 'org-access-denied',
|
||||
});
|
||||
});
|
||||
|
||||
it('treats terminated 403 auth failures as an org-access-denied fallback trigger', () => {
|
||||
expect(
|
||||
detectFallbackTrigger(
|
||||
'Failed to authenticate. API Error: 403 terminated',
|
||||
),
|
||||
).toEqual({
|
||||
shouldFallback: true,
|
||||
reason: 'org-access-denied',
|
||||
});
|
||||
});
|
||||
|
||||
it('marks org-access-denied as a no-fallback cooldown reason', () => {
|
||||
markPrimaryCooldown('org-access-denied', 60_000);
|
||||
|
||||
expect(isPrimaryNoFallbackCooldownActive()).toBe(true);
|
||||
expect(getCooldownInfo()).toMatchObject({
|
||||
active: true,
|
||||
reason: 'org-access-denied',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user