b46e9d2e64
## Summary This PR adds user-friendly error handling for AI chat features, specifically for **billing credits exhausted** and **API key not configured** errors. ## Changes ### Backend - Added `BILLING_CREDITS_EXHAUSTED` exception code with 402 status - Added `API_KEY_NOT_CONFIGURED` exception code with 503 status - Added billing check before AI chat streaming in `agent-chat.controller.ts` - Added error code to HTTP exception response body for frontend error type detection - Created `AgentRestApiExceptionFilter` for agent-specific errors ### Frontend - Created `AIChatBanner` - reusable banner component for error/warning messages - Created `AIChatCreditsExhaustedMessage` - shows upgrade prompts based on user permissions - Created `AIChatApiKeyNotConfiguredMessage` - shows configuration guidance with docs link - Created `AIChatErrorRenderer` - encapsulates error type switching logic (fixes nested ternary) - Created `AIChatStandaloneError` - displays errors when there are no messages - Split `aiChatErrorUtils.ts` into separate files (1 export per file): - `AIChatErrorCode.ts` - `extractErrorCode.ts` - `isAIChatErrorOfType.ts` - `isBillingCreditsExhaustedError.ts` - `isApiKeyNotConfiguredError.ts` - Added comprehensive test coverage (27 tests) ### Other - Updated trial period banner messaging ## Testing - All lint checks pass - All 27 new tests pass - TypeScript typecheck passes
23 lines
703 B
TypeScript
23 lines
703 B
TypeScript
import { AIChatBanner } from '@/ai/components/AIChatBanner';
|
|
import { t } from '@lingui/core/macro';
|
|
import { IconExternalLink } from 'twenty-ui/display';
|
|
|
|
const DOCS_URL =
|
|
'https://twenty.com/developers/section/self-hosting/self-hosting-var#ai-features';
|
|
|
|
export const AIChatApiKeyNotConfiguredMessage = () => {
|
|
const handleDocsClick = () => {
|
|
window.open(DOCS_URL, '_blank', 'noopener,noreferrer');
|
|
};
|
|
|
|
return (
|
|
<AIChatBanner
|
|
message={t`AI not configured. Set OPENAI_API_KEY, ANTHROPIC_API_KEY, or XAI_API_KEY in your environment.`}
|
|
variant="warning"
|
|
buttonTitle={t`View Docs`}
|
|
buttonIcon={IconExternalLink}
|
|
buttonOnClick={handleDocsClick}
|
|
/>
|
|
);
|
|
};
|