mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-13 02:22:50 +00:00
Revert "feat: add UI support for displaying and managing guardrails on virtual keys"
This reverts commit 83654c5608.
This commit is contained in:
@@ -97,9 +97,7 @@ async def get_guardrails_for_virtual_key(
|
||||
"""
|
||||
Get all guardrails associated with a virtual key
|
||||
"""
|
||||
verbose_proxy_logger.debug(f"Getting guardrails for virtual key: {virtual_key_id}")
|
||||
guardrails = IN_MEMORY_GUARDRAIL_HANDLER.get_guardrails_for_virtual_key(virtual_key_id)
|
||||
verbose_proxy_logger.debug(f"Found {len(guardrails)} guardrails for virtual key {virtual_key_id}")
|
||||
|
||||
return VirtualKeyGuardrailsResponse(
|
||||
virtual_key_id=virtual_key_id,
|
||||
|
||||
@@ -567,7 +567,6 @@ class InMemoryGuardrailHandler:
|
||||
Get all guardrails associated with a virtual key
|
||||
"""
|
||||
guardrail_ids = self.virtual_key_to_guardrails.get(virtual_key_id, [])
|
||||
verbose_proxy_logger.debug(f"Getting guardrails for virtual key {virtual_key_id}: {guardrail_ids}")
|
||||
return [self.IN_MEMORY_GUARDRAILS[gid] for gid in guardrail_ids if gid in self.IN_MEMORY_GUARDRAILS]
|
||||
|
||||
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Card, Flex, Text, Heading, Button, Dialog, TextField, Select, Box, Tabs } from '@radix-ui/themes';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { VirtualKey } from '../../types/virtual_key';
|
||||
import { fetchVirtualKey, updateVirtualKey } from '../../services/virtual_keys';
|
||||
import { VirtualKeyGuardrails } from './virtual_key_guardrails';
|
||||
import { fetchGuardrails } from '../../services/guardrails';
|
||||
import { Guardrail } from '../../types/guardrail';
|
||||
import { associateGuardrailWithVirtualKey } from '../../services/virtual_key_guardrails';
|
||||
|
||||
interface VirtualKeyDetailProps {
|
||||
virtualKeyId: string;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const VirtualKeyDetail: React.FC<VirtualKeyDetailProps> = ({ virtualKeyId, onClose }) => {
|
||||
const [virtualKey, setVirtualKey] = useState<VirtualKey | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [availableGuardrails, setAvailableGuardrails] = useState<Guardrail[]>([]);
|
||||
const [selectedGuardrailId, setSelectedGuardrailId] = useState<string>('');
|
||||
const [refreshTrigger, setRefreshTrigger] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const loadVirtualKey = async () => {
|
||||
try {
|
||||
const data = await fetchVirtualKey(virtualKeyId);
|
||||
setVirtualKey(data);
|
||||
} catch (error) {
|
||||
console.error('Error loading virtual key:', error);
|
||||
toast.error('Failed to load virtual key details');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const loadGuardrails = async () => {
|
||||
try {
|
||||
const data = await fetchGuardrails();
|
||||
setAvailableGuardrails(data.guardrails);
|
||||
} catch (error) {
|
||||
console.error('Error loading guardrails:', error);
|
||||
}
|
||||
};
|
||||
|
||||
loadVirtualKey();
|
||||
loadGuardrails();
|
||||
}, [virtualKeyId]);
|
||||
|
||||
const handleAddGuardrail = async () => {
|
||||
if (!selectedGuardrailId) {
|
||||
toast.error('Please select a guardrail');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await associateGuardrailWithVirtualKey(virtualKeyId, selectedGuardrailId);
|
||||
toast.success('Guardrail added to virtual key');
|
||||
setSelectedGuardrailId('');
|
||||
setRefreshTrigger(prev => prev + 1);
|
||||
} catch (error) {
|
||||
console.error('Error adding guardrail:', error);
|
||||
toast.error('Failed to add guardrail');
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Dialog.Root open={true} onOpenChange={onClose}>
|
||||
<Dialog.Content>
|
||||
<Dialog.Title>Virtual Key Details</Dialog.Title>
|
||||
<Text>Loading...</Text>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
);
|
||||
}
|
||||
|
||||
if (!virtualKey) {
|
||||
return (
|
||||
<Dialog.Root open={true} onOpenChange={onClose}>
|
||||
<Dialog.Content>
|
||||
<Dialog.Title>Error</Dialog.Title>
|
||||
<Text>Virtual key not found</Text>
|
||||
<Dialog.Close>
|
||||
<Button>Close</Button>
|
||||
</Dialog.Close>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog.Root open={true} onOpenChange={onClose}>
|
||||
<Dialog.Content style={{ maxWidth: '600px' }}>
|
||||
<Dialog.Title>Virtual Key: {virtualKey.key_name || 'Unnamed Key'}</Dialog.Title>
|
||||
|
||||
<Tabs.Root defaultValue="details">
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="details">Details</Tabs.Trigger>
|
||||
<Tabs.Trigger value="guardrails">Guardrails</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
|
||||
<Box py="4">
|
||||
<Tabs.Content value="details">
|
||||
<Card>
|
||||
<Flex direction="column" gap="3">
|
||||
<Flex justify="between">
|
||||
<Text weight="bold">Key ID:</Text>
|
||||
<Text>{virtualKey.key_id}</Text>
|
||||
</Flex>
|
||||
<Flex justify="between">
|
||||
<Text weight="bold">Team ID:</Text>
|
||||
<Text>{virtualKey.team_id || 'N/A'}</Text>
|
||||
</Flex>
|
||||
<Flex justify="between">
|
||||
<Text weight="bold">Models:</Text>
|
||||
<Text>{virtualKey.models?.join(', ') || 'All models'}</Text>
|
||||
</Flex>
|
||||
<Flex justify="between">
|
||||
<Text weight="bold">Spend:</Text>
|
||||
<Text>${virtualKey.spend?.toFixed(2) || '0.00'}</Text>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Card>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="guardrails">
|
||||
<Flex direction="column" gap="3">
|
||||
<Card>
|
||||
<Heading size="3" mb="2">Add Guardrail</Heading>
|
||||
<Flex gap="2">
|
||||
<Select.Root value={selectedGuardrailId} onValueChange={setSelectedGuardrailId}>
|
||||
<Select.Trigger placeholder="Select a guardrail" />
|
||||
<Select.Content>
|
||||
{availableGuardrails.map(guardrail => (
|
||||
<Select.Item key={guardrail.guardrail_id} value={guardrail.guardrail_id}>
|
||||
{guardrail.guardrail_name || `Guardrail ${guardrail.guardrail_id.substring(0, 8)}`}
|
||||
</Select.Item>
|
||||
))}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
<Button onClick={handleAddGuardrail}>Add</Button>
|
||||
</Flex>
|
||||
</Card>
|
||||
|
||||
<VirtualKeyGuardrails
|
||||
virtualKeyId={virtualKeyId}
|
||||
refreshTrigger={refreshTrigger}
|
||||
/>
|
||||
</Flex>
|
||||
</Tabs.Content>
|
||||
</Box>
|
||||
</Tabs.Root>
|
||||
|
||||
<Dialog.Close asChild>
|
||||
<Button color="gray" variant="soft" mt="4">Close</Button>
|
||||
</Dialog.Close>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
);
|
||||
};
|
||||
@@ -1,93 +0,0 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Badge, Button, Card, Flex, Heading, Text, Box, Spinner } from '@radix-ui/themes';
|
||||
import { fetchGuardrailsForVirtualKey, associateGuardrailWithVirtualKey, disassociateGuardrailFromVirtualKey } from '../../services/virtual_key_guardrails';
|
||||
import { Guardrail } from '../../types/guardrail';
|
||||
import { toast } from 'react-hot-toast';
|
||||
|
||||
interface VirtualKeyGuardrailsProps {
|
||||
virtualKeyId: string;
|
||||
refreshTrigger?: number;
|
||||
}
|
||||
|
||||
export const VirtualKeyGuardrails: React.FC<VirtualKeyGuardrailsProps> = ({
|
||||
virtualKeyId,
|
||||
refreshTrigger = 0
|
||||
}) => {
|
||||
const [guardrails, setGuardrails] = useState<Guardrail[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const loadGuardrails = async () => {
|
||||
if (!virtualKeyId) return;
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const data = await fetchGuardrailsForVirtualKey(virtualKeyId);
|
||||
setGuardrails(data.guardrails);
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
console.error('Error loading guardrails for virtual key:', err);
|
||||
setError('Failed to load guardrails');
|
||||
setGuardrails([]);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
loadGuardrails();
|
||||
}, [virtualKeyId, refreshTrigger]);
|
||||
|
||||
const handleRemoveGuardrail = async (guardrailId: string) => {
|
||||
try {
|
||||
await disassociateGuardrailFromVirtualKey(virtualKeyId, guardrailId);
|
||||
setGuardrails(guardrails.filter(g => g.guardrail_id !== guardrailId));
|
||||
toast.success('Guardrail removed from virtual key');
|
||||
} catch (err) {
|
||||
console.error('Error removing guardrail:', err);
|
||||
toast.error('Failed to remove guardrail');
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Box py="4">
|
||||
<Flex align="center" justify="center">
|
||||
<Spinner size="large" />
|
||||
</Flex>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<Box py="4">
|
||||
<Text color="red">{error}</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Heading size="3" mb="2">Attached Guardrails</Heading>
|
||||
{guardrails.length === 0 ? (
|
||||
<Text color="gray">No guardrails attached to this virtual key</Text>
|
||||
) : (
|
||||
<Flex direction="column" gap="2">
|
||||
{guardrails.map((guardrail) => (
|
||||
<Flex key={guardrail.guardrail_id} justify="between" align="center" p="2" style={{ borderBottom: '1px solid var(--gray-4)' }}>
|
||||
<Flex direction="column" gap="1">
|
||||
<Text weight="bold">{guardrail.guardrail_name || 'Unnamed Guardrail'}</Text>
|
||||
<Text size="1" color="gray">Type: {guardrail.litellm_params?.guardrail}</Text>
|
||||
<Text size="1" color="gray">Mode: {guardrail.litellm_params?.mode}</Text>
|
||||
</Flex>
|
||||
<Button color="red" variant="soft" onClick={() => handleRemoveGuardrail(guardrail.guardrail_id)}>
|
||||
Remove
|
||||
</Button>
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
import { Guardrail } from '../types/guardrail';
|
||||
|
||||
interface GuardrailsResponse {
|
||||
guardrails: Guardrail[];
|
||||
}
|
||||
|
||||
export async function fetchGuardrails(): Promise<GuardrailsResponse> {
|
||||
const response = await fetch('/api/guardrails');
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`Failed to fetch guardrails: ${errorText}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
export async function fetchGuardrail(guardrailId: string): Promise<Guardrail> {
|
||||
const response = await fetch(`/api/guardrails/${guardrailId}`);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`Failed to fetch guardrail: ${errorText}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import { Guardrail } from '../types/guardrail';
|
||||
|
||||
interface VirtualKeyGuardrailsResponse {
|
||||
virtual_key_id: string;
|
||||
guardrails: Guardrail[];
|
||||
}
|
||||
|
||||
export async function fetchGuardrailsForVirtualKey(virtualKeyId: string): Promise<VirtualKeyGuardrailsResponse> {
|
||||
const response = await fetch(`/api/guardrails/virtual_key/${virtualKeyId}`);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`Failed to fetch guardrails: ${errorText}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
export async function associateGuardrailWithVirtualKey(virtualKeyId: string, guardrailId: string): Promise<{ message: string }> {
|
||||
const response = await fetch('/api/guardrails/virtual_key/associate', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
virtual_key_id: virtualKeyId,
|
||||
guardrail_id: guardrailId,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`Failed to associate guardrail: ${errorText}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
export async function disassociateGuardrailFromVirtualKey(virtualKeyId: string, guardrailId: string): Promise<{ message: string }> {
|
||||
const response = await fetch('/api/guardrails/virtual_key/disassociate', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
virtual_key_id: virtualKeyId,
|
||||
guardrail_id: guardrailId,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`Failed to disassociate guardrail: ${errorText}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
export interface Guardrail {
|
||||
guardrail_id: string;
|
||||
guardrail_name: string | null;
|
||||
litellm_params: {
|
||||
guardrail: string;
|
||||
mode: string;
|
||||
default_on: boolean;
|
||||
[key: string]: any;
|
||||
};
|
||||
guardrail_info?: Record<string, any>;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
export interface VirtualKey {
|
||||
key_id: string;
|
||||
key_name?: string;
|
||||
team_id?: string;
|
||||
models?: string[];
|
||||
spend?: number;
|
||||
max_budget?: number;
|
||||
max_parallel_requests?: number;
|
||||
metadata?: Record<string, any>;
|
||||
expires?: string;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
}
|
||||
Reference in New Issue
Block a user