"use client" import { useState, useEffect } from 'react' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { Textarea } from '@/components/ui/textarea' import { Separator } from '@/components/ui/separator' import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog' import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from '@/components/ui/alert-dialog' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' import { Key, Plus, Settings, Trash2, Calendar, Lock, Unlock, RefreshCw, AlertTriangle } from 'lucide-react' import { useToast } from '@/hooks/use-toast' import { apiClient } from '@/lib/api-client' import { ProtectedRoute } from '@/components/auth/ProtectedRoute' import { useRouter } from 'next/navigation' interface APIKey { id: number name: string key_prefix: string description?: string scopes: string[] is_active: boolean expires_at?: string created_at: string last_used_at?: string total_requests: number total_tokens: number total_cost: number rate_limit_per_minute?: number rate_limit_per_hour?: number rate_limit_per_day?: number allowed_ips: string[] allowed_models: string[] tags: string[] } interface Model { id: string object: string created?: number owned_by?: string permission?: any[] root?: string parent?: string provider?: string capabilities?: string[] context_window?: number max_output_tokens?: number supports_streaming?: boolean supports_function_calling?: boolean } export default function LLMPage() { return ( ) } function LLMPageContent() { const [activeTab, setActiveTab] = useState('api-keys') const [apiKeys, setApiKeys] = useState([]) const [models, setModels] = useState([]) const [loading, setLoading] = useState(true) const [showEditDialog, setShowEditDialog] = useState(false) const [editingKey, setEditingKey] = useState(null) const { toast } = useToast() const router = useRouter() // Edit API Key form state const [editKey, setEditKey] = useState({ name: '', description: '', is_active: true }) useEffect(() => { fetchData() }, []) // eslint-disable-line react-hooks/exhaustive-deps const fetchData = async () => { try { setLoading(true) const token = await import('@/lib/token-manager').then(m => m.tokenManager.getAccessToken()) if (!token) { throw new Error('No authentication token found') } // Fetch API keys and models using API client const [keysData, modelsData] = await Promise.all([ apiClient.get('/api-internal/v1/api-keys').catch(e => { return { data: [] } }), apiClient.get('/api-internal/v1/llm/models').catch(e => { return { data: [] } }) ]) setApiKeys(keysData.api_keys || []) setModels(modelsData.data || []) } catch (error) { toast({ title: "Error", description: "Failed to load data", variant: "destructive" }) } finally { setLoading(false) } } const openEditDialog = (apiKey: APIKey) => { setEditingKey(apiKey) setEditKey({ name: apiKey.name, description: apiKey.description || '', is_active: apiKey.is_active }) setShowEditDialog(true) } const updateAPIKey = async () => { if (!editingKey) return try { await apiClient.put(`/api-internal/v1/api-keys/${editingKey.id}`, editKey) toast({ title: "Success", description: "API key updated successfully" }) setShowEditDialog(false) setEditingKey(null) fetchData() } catch (error) { toast({ title: "Error", description: "Failed to update API key", variant: "destructive" }) } } const deleteAPIKey = async (keyId: number) => { try { setLoading(true) const responseData = await apiClient.delete(`/api-internal/v1/api-keys/${keyId}`) toast({ title: "Success", description: "API key deleted successfully" }) // Force refresh data and wait for it to complete await fetchData() } catch (error) { toast({ title: "Error", description: error instanceof Error ? error.message : "Failed to delete API key", variant: "destructive" }) } finally { setLoading(false) } } const formatCurrency = (cents: number) => { return `$${(cents / 100).toFixed(4)}` } const formatDate = (dateStr?: string) => { if (!dateStr) return 'Never' return new Date(dateStr).toLocaleDateString() } return (

LLM Configuration

Manage API keys and model access for your LLM integrations.

API Keys Models
API Keys
OpenAI-compatible API keys for accessing your LLM endpoints.
{loading ? (
Loading...
) : ( Name Key Model Expires Usage Status Actions {apiKeys.map((apiKey) => ( {apiKey.name}
{apiKey.key_prefix || 'N/A'} Secret key hidden for security
{apiKey.allowed_models && apiKey.allowed_models.length > 0 ? ( {apiKey.allowed_models[0]} ) : ( All Models )} {formatDate(apiKey.expires_at)}
{apiKey.total_requests} requests
{formatCurrency(apiKey.total_cost)}
{apiKey.is_active ? ( Active ) : ( Inactive )}
Delete API Key Are you sure you want to delete this API key? This action cannot be undone. Cancel deleteAPIKey(apiKey.id)}> Delete
))} {apiKeys.length === 0 && ( No API keys created yet. Create your first API key to get started. )}
)}
Available Models Models available through your LLM platform.
{models.map((model) => { // Helper function to get provider from model ID const getProviderFromModel = (modelId: string): string => { if (modelId.startsWith('privatemode-')) return 'PrivateMode.ai' if (modelId.startsWith('gpt-') || modelId.includes('openai')) return 'OpenAI' if (modelId.startsWith('claude-') || modelId.includes('anthropic')) return 'Anthropic' if (modelId.startsWith('gemini-') || modelId.includes('google')) return 'Google' if (modelId.includes('cohere')) return 'Cohere' if (modelId.includes('mistral')) return 'Mistral' if (modelId.includes('llama') && !modelId.startsWith('privatemode-')) return 'Meta' return model.owned_by || 'Unknown' } return (

{model.id}

Provider: {getProviderFromModel(model.id)}

{model.object || 'model'} {model.supports_streaming && ( Streaming )} {model.supports_function_calling && ( Functions )} {model.capabilities?.includes('tee') && ( TEE )}
{model.context_window && (

Context: {model.context_window.toLocaleString()} tokens

)}
) })} {models.length === 0 && (
No models available. Check your LLM platform configuration.
)}
{/* Edit API Key Dialog */} Edit API Key Update the name, description, and status of your API key.
setEditKey(prev => ({ ...prev, name: e.target.value }))} placeholder="e.g., Frontend Application" />