From 38156eafcf081831a1d37ce7d2e5b16e81cab18e Mon Sep 17 00:00:00 2001 From: Nico Albanese <49612682+nicoalbanese@users.noreply.github.com> Date: Sat, 13 Sep 2025 20:40:08 +0100 Subject: [PATCH] fix: add dialog for vercel ai gateway activation (#1195) --- app/(chat)/api/chat/route.ts | 10 +++++++ components/chat.tsx | 56 +++++++++++++++++++++++++++++++++--- lib/errors.ts | 7 ++++- 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/app/(chat)/api/chat/route.ts b/app/(chat)/api/chat/route.ts index d54875e..80c0ad3 100644 --- a/app/(chat)/api/chat/route.ts +++ b/app/(chat)/api/chat/route.ts @@ -242,6 +242,16 @@ export async function POST(request: Request) { return error.toResponse(); } + // Check for Vercel AI Gateway credit card error + if ( + error instanceof Error && + error.message?.includes( + 'AI Gateway requires a valid credit card on file to service requests', + ) + ) { + return new ChatSDKError('bad_request:activate_gateway').toResponse(); + } + console.error('Unhandled error in chat API:', error); return new ChatSDKError('offline:chat').toResponse(); } diff --git a/components/chat.tsx b/components/chat.tsx index 0d588ed..5e6f3fb 100644 --- a/components/chat.tsx +++ b/components/chat.tsx @@ -22,6 +22,16 @@ import { useAutoResume } from '@/hooks/use-auto-resume'; import { ChatSDKError } from '@/lib/errors'; import type { Attachment, ChatMessage } from '@/lib/types'; import { useDataStream } from './data-stream-provider'; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from '@/components/ui/alert-dialog'; export function Chat({ id, @@ -54,6 +64,7 @@ export function Chat({ const [usage, setUsage] = useState( initialLastContext, ); + const [showCreditCardAlert, setShowCreditCardAlert] = useState(false); const { messages, @@ -94,10 +105,17 @@ export function Chat({ }, onError: (error) => { if (error instanceof ChatSDKError) { - toast({ - type: 'error', - description: error.message, - }); + // Check if it's a credit card error + if ( + error.message?.includes('AI Gateway requires a valid credit card') + ) { + setShowCreditCardAlert(true); + } else { + toast({ + type: 'error', + description: error.message, + }); + } } }, }); @@ -194,6 +212,36 @@ export function Chat({ selectedVisibilityType={visibilityType} selectedModelId={initialChatModel} /> + + + + + Activate AI Gateway + + This application requires{' '} + {process.env.NODE_ENV === 'production' ? 'the owner' : 'you'} to + activate Vercel AI Gateway. + + + + Cancel + { + window.open( + 'https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai%3Fmodal%3Dadd-credit-card', + '_blank', + ); + window.location.href = '/'; + }} + > + Activate + + + + ); } diff --git a/lib/errors.ts b/lib/errors.ts index 339a272..b0ccdb8 100644 --- a/lib/errors.ts +++ b/lib/errors.ts @@ -15,7 +15,8 @@ export type Surface = | 'history' | 'vote' | 'document' - | 'suggestions'; + | 'suggestions' + | 'activate_gateway'; export type ErrorCode = `${ErrorType}:${Surface}`; @@ -31,6 +32,7 @@ export const visibilityBySurface: Record = { vote: 'response', document: 'response', suggestions: 'response', + activate_gateway: 'response', }; export class ChatSDKError extends Error { @@ -82,6 +84,9 @@ export function getMessageByErrorCode(errorCode: ErrorCode): string { case 'bad_request:api': return "The request couldn't be processed. Please check your input and try again."; + case 'bad_request:activate_gateway': + return 'AI Gateway requires a valid credit card on file to service requests. Please visit https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai%3Fmodal%3Dadd-credit-card to add a card and unlock your free credits.'; + case 'unauthorized:auth': return 'You need to sign in before continuing.'; case 'forbidden:auth':