BillingErrorAlert component in Suna, an open source generalist AI agent.
In this article, we review a component BillingErrorAlert in Suna codebase. Suna is an open source generalist AI agent. We will look at: Where this BillingErroAlert component is used? BillingErrorAlert component Where this BillingErrorAlert component is used? This component is called at the end of the [threadId]/page.tsx component in the function, ThreadPage. {/* Billing Alert for usage limit */} setShowBillingAlert(false)} isOpen={showBillingAlert} /> BillingErrorAlert component Below code is picked from components/billing/usage-limit-alert.tsx 'use client'; import { AlertTriangle } from "lucide-react"; import { Button } from "@/components/ui/button"; import { useRouter } from "next/navigation"; interface BillingErrorAlertProps { message?: string; currentUsage?: number; limit?: number; accountId?: string | null; onDismiss: () => void; isOpen: boolean; } export function BillingErrorAlert({ message, currentUsage, limit, accountId, onDismiss, isOpen }: BillingErrorAlertProps) { const router = useRouter(); if (!isOpen) return null; return ( Usage Limit Reached {message} Dismiss router.push(`/settings/billing?accountId=${accountId}`)} className="text-xs" > Upgrade Plan ); } setShowBillingAlert This function decides if this BillingAlert should be rendered because of this check below in usage-limit-alert.tsx. export function BillingErrorAlert({ message, currentUsage, limit, accountId, onDismiss, isOpen }: BillingErrorAlertProps) { const router = useRouter(); if (!isOpen) return null; isOpen prop is passed from file-viewer-modal isOpen={showBillingAlert} From L618 to L634, you will see the below code snippet in [threadId]/page.tsx. // Check if it's our custom BillingError (402) if (error instanceof BillingError) { console.log("Caught BillingError:", error.detail); // Extract billing details setBillingData({ // Note: currentUsage and limit might not be in the detail from the backend yet currentUsage: error.detail.currentUsage as number | undefined, limit: error.detail.limit as number | undefined, message: error.detail.message || 'Monthly usage limit reached. Please upgrade.', // Use message from error detail accountId: project?.account_id || null // Pass account ID }); setShowBillingAlert(true); // Remove the optimistic message since the agent couldn't start setMessages(prev => prev.filter(m => m.message_id !== optimisticUserMessage.message_id)); return; // Stop further execution in this case } About me: Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos. Want me to review your codebase architecture? book a meeting — https://thinkthroo.com/consultation/codebase-architecture-review Business enquiries — ramu@thinkthroo.com My Github — https://github.com/ramu-narasinga My website — https://ramunarasinga.com My YouTube channel — https://www.youtube.com/@ramu-narasinga Learning platform — https://thinkthroo.com Codebase Architecture — https://app.thinkthroo.com/architecture Best practices — https://app.thinkthroo.com/best-practices Production-grade projects — https://app.thinkthroo.com/production-grade-projects References: https://github.com/kortix-ai/suna/blob/main/frontend/src/app/(dashboard)/agents/%5BthreadId%5D/page.tsx#L1620C8-L1620C26 https://github.com/kortix-ai/suna/blob/main/frontend/src/components/billing/usage-limit-alert.tsx#L19

In this article, we review a component BillingErrorAlert
in Suna codebase. Suna is an open source generalist AI agent. We will look at:
Where this BillingErroAlert component is used?
BillingErrorAlert component
Where this BillingErrorAlert component is used?
This component is called at the end of the [threadId]/page.tsx component in the function, ThreadPage.
{/* Billing Alert for usage limit */}
<BillingErrorAlert
message={billingData.message}
currentUsage={billingData.currentUsage}
limit={billingData.limit}
accountId={billingData.accountId}
onDismiss={() => setShowBillingAlert(false)}
isOpen={showBillingAlert}
/>
BillingErrorAlert component
Below code is picked from components/billing/usage-limit-alert.tsx
'use client';
import { AlertTriangle } from "lucide-react";
import { Button } from "@/components/ui/button";
import { useRouter } from "next/navigation";
interface BillingErrorAlertProps {
message?: string;
currentUsage?: number;
limit?: number;
accountId?: string | null;
onDismiss: () => void;
isOpen: boolean;
}
export function BillingErrorAlert({
message,
currentUsage,
limit,
accountId,
onDismiss,
isOpen
}: BillingErrorAlertProps) {
const router = useRouter();
if (!isOpen) return null;
return (
<div className="fixed bottom-4 right-4 z-50">
<div className="bg-destructive/10 border border-destructive/20 rounded-lg p-4 shadow-lg max-w-md">
<div className="flex items-start gap-3">
<div className="flex-shrink-0">
<AlertTriangle className="h-5 w-5 text-destructive" />
</div>
<div className="flex-1">
<h3 className="text-sm font-medium text-destructive mb-1">Usage Limit Reached</h3>
<p className="text-sm text-muted-foreground mb-3">{message}</p>
<div className="flex gap-2">
<Button
variant="outline"
size="sm"
onClick={onDismiss}
className="text-xs"
>
Dismiss
</Button>
<Button
size="sm"
onClick={() => router.push(`/settings/billing?accountId=${accountId}`)}
className="text-xs"
>
Upgrade Plan
</Button>
</div>
</div>
</div>
</div>
</div>
);
}
setShowBillingAlert
This function decides if this BillingAlert should be rendered because of this check below in usage-limit-alert.tsx.
export function BillingErrorAlert({
message,
currentUsage,
limit,
accountId,
onDismiss,
isOpen
}: BillingErrorAlertProps) {
const router = useRouter();
if (!isOpen) return null;
isOpen prop is passed from file-viewer-modal
isOpen={showBillingAlert}
From L618 to L634, you will see the below code snippet in [threadId]/page.tsx.
// Check if it's our custom BillingError (402)
if (error instanceof BillingError) {
console.log("Caught BillingError:", error.detail);
// Extract billing details
setBillingData({
// Note: currentUsage and limit might not be in the detail from the backend yet
currentUsage: error.detail.currentUsage as number | undefined,
limit: error.detail.limit as number | undefined,
message: error.detail.message || 'Monthly usage limit reached. Please upgrade.', // Use message from error detail
accountId: project?.account_id || null // Pass account ID
});
setShowBillingAlert(true);
// Remove the optimistic message since the agent couldn't start
setMessages(prev => prev.filter(m => m.message_id !== optimisticUserMessage.message_id));
return; // Stop further execution in this case
}
About me:
Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.
Want me to review your codebase architecture? book a meeting — https://thinkthroo.com/consultation/codebase-architecture-review
Business enquiries — ramu@thinkthroo.com
My Github — https://github.com/ramu-narasinga
My website — https://ramunarasinga.com
My YouTube channel — https://www.youtube.com/@ramu-narasinga
Learning platform — https://thinkthroo.com
Codebase Architecture — https://app.thinkthroo.com/architecture
Best practices — https://app.thinkthroo.com/best-practices
Production-grade projects — https://app.thinkthroo.com/production-grade-projects