refactor: remove some unused files and add tests

This commit is contained in:
yuneng-jiang
2026-02-09 11:50:40 -08:00
parent 9532ad0fab
commit fb4daad8d4
13 changed files with 200 additions and 2611 deletions
@@ -0,0 +1,94 @@
/* @vitest-environment jsdom */
import React from "react";
import { renderHook, waitFor } from "@testing-library/react";
import { describe, it, expect, vi, beforeEach } from "vitest";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { useMCPAccessGroups } from "./useMCPAccessGroups";
import * as networking from "@/components/networking";
vi.mock("@/components/networking", () => ({
fetchMCPAccessGroups: vi.fn(),
}));
vi.mock("@/app/(dashboard)/hooks/useAuthorized", () => ({
default: vi.fn(() => ({
accessToken: "test-token-456",
})),
}));
const createQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: {
retry: false,
gcTime: 0,
},
},
});
const wrapper = ({ children }: { children: React.ReactNode }) => {
const queryClient = createQueryClient();
return React.createElement(QueryClientProvider, { client: queryClient }, children);
};
const mockAccessGroups = ["group-1", "group-2", "group-3"];
describe("useMCPAccessGroups", () => {
beforeEach(async () => {
vi.clearAllMocks();
const useAuthorizedModule = await import("@/app/(dashboard)/hooks/useAuthorized");
vi.mocked(useAuthorizedModule.default).mockReturnValue({
accessToken: "test-token-456",
} as any);
});
it("should return MCP access groups when access token is present", async () => {
vi.mocked(networking.fetchMCPAccessGroups).mockResolvedValue(mockAccessGroups);
const { result } = renderHook(() => useMCPAccessGroups(), { wrapper });
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
expect(networking.fetchMCPAccessGroups).toHaveBeenCalledWith("test-token-456");
expect(result.current.data).toEqual(mockAccessGroups);
});
it("should not fetch when access token is not available", async () => {
const useAuthorizedModule = await import("@/app/(dashboard)/hooks/useAuthorized");
vi.mocked(useAuthorizedModule.default).mockReturnValue({
accessToken: null,
} as any);
const { result } = renderHook(() => useMCPAccessGroups(), { wrapper });
expect(result.current.status).toBe("pending");
expect(networking.fetchMCPAccessGroups).not.toHaveBeenCalled();
});
it("should expose error state when fetch fails", async () => {
const mockError = new Error("Failed to fetch MCP access groups");
vi.mocked(networking.fetchMCPAccessGroups).mockRejectedValue(mockError);
const { result } = renderHook(() => useMCPAccessGroups(), { wrapper });
await waitFor(() => {
expect(result.current.isError).toBe(true);
});
expect(result.current.error).toEqual(mockError);
});
it("should return empty array when API returns no groups", async () => {
vi.mocked(networking.fetchMCPAccessGroups).mockResolvedValue([]);
const { result } = renderHook(() => useMCPAccessGroups(), { wrapper });
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
expect(result.current.data).toEqual([]);
});
});
@@ -0,0 +1,104 @@
/* @vitest-environment jsdom */
import React from "react";
import { renderHook, waitFor } from "@testing-library/react";
import { describe, it, expect, vi, beforeEach } from "vitest";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { useMCPServers } from "./useMCPServers";
import * as networking from "@/components/networking";
vi.mock("@/components/networking", () => ({
fetchMCPServers: vi.fn(),
}));
vi.mock("../useAuthorized", () => ({
default: vi.fn(() => ({
accessToken: "test-token-123",
})),
}));
const createQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: {
retry: false,
gcTime: 0,
},
},
});
const wrapper = ({ children }: { children: React.ReactNode }) => {
const queryClient = createQueryClient();
return React.createElement(QueryClientProvider, { client: queryClient }, children);
};
const mockServers = [
{
server_id: "server-1",
server_name: "Server One",
url: "http://localhost:4000",
created_at: "2025-01-01T00:00:00Z",
created_by: "user-1",
updated_at: "2025-01-01T00:00:00Z",
updated_by: "user-1",
},
];
describe("useMCPServers", () => {
beforeEach(async () => {
vi.clearAllMocks();
const useAuthorizedModule = await import("../useAuthorized");
vi.mocked(useAuthorizedModule.default).mockReturnValue({
accessToken: "test-token-123",
} as any);
});
it("should return MCP servers when access token is present", async () => {
vi.mocked(networking.fetchMCPServers).mockResolvedValue(mockServers);
const { result } = renderHook(() => useMCPServers(), { wrapper });
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
expect(networking.fetchMCPServers).toHaveBeenCalledWith("test-token-123");
expect(result.current.data).toEqual(mockServers);
});
it("should not fetch when access token is not available", async () => {
const useAuthorizedModule = await import("../useAuthorized");
vi.mocked(useAuthorizedModule.default).mockReturnValue({
accessToken: null,
} as any);
const { result } = renderHook(() => useMCPServers(), { wrapper });
expect(result.current.status).toBe("pending");
expect(networking.fetchMCPServers).not.toHaveBeenCalled();
});
it("should expose error state when fetch fails", async () => {
const mockError = new Error("Failed to fetch MCP servers");
vi.mocked(networking.fetchMCPServers).mockRejectedValue(mockError);
const { result } = renderHook(() => useMCPServers(), { wrapper });
await waitFor(() => {
expect(result.current.isError).toBe(true);
});
expect(result.current.error).toEqual(mockError);
});
it("should return empty array when API returns empty list", async () => {
vi.mocked(networking.fetchMCPServers).mockResolvedValue([]);
const { result } = renderHook(() => useMCPServers(), { wrapper });
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
expect(result.current.data).toEqual([]);
});
});
@@ -1,103 +0,0 @@
import React, { useState, useEffect } from "react";
import { Select, SelectItem, Text, Title } from "@tremor/react";
import { ProxySettings, UserInfo } from "./user_dashboard";
import { getProxyUISettings } from "./networking";
interface DashboardTeamProps {
teams: object[] | null;
setSelectedTeam: React.Dispatch<React.SetStateAction<any | null>>;
userRole: string | null;
proxySettings: ProxySettings | null;
setProxySettings: React.Dispatch<React.SetStateAction<ProxySettings | null>>;
userInfo: UserInfo | null;
accessToken: string | null;
setKeys: React.Dispatch<React.SetStateAction<any | null>>;
}
type TeamInterface = {
models: any[];
team_id: null;
team_alias: string;
max_budget: number | null;
};
const DashboardTeam: React.FC<DashboardTeamProps> = ({
teams,
setSelectedTeam,
userRole,
proxySettings,
setProxySettings,
userInfo,
accessToken,
setKeys,
}) => {
console.log(`userInfo: ${JSON.stringify(userInfo)}`);
const defaultTeam: TeamInterface = {
models: userInfo?.models || [],
team_id: null,
team_alias: "Default Team",
max_budget: userInfo?.max_budget || null,
};
const getProxySettings = async () => {
if (proxySettings === null && accessToken) {
const proxy_settings: ProxySettings = await getProxyUISettings(accessToken);
setProxySettings(proxy_settings);
}
};
useEffect(() => {
getProxySettings();
}, [proxySettings]);
const [value, setValue] = useState(defaultTeam);
let updatedTeams;
console.log(`userRole: ${userRole}`);
console.log(`proxySettings: ${JSON.stringify(proxySettings)}`);
if (userRole === "App User") {
// Non-Admin SSO users should only see their own team - they should not see "Default Team"
updatedTeams = teams;
} else if (proxySettings && proxySettings.DEFAULT_TEAM_DISABLED === true) {
updatedTeams = teams ? [...teams] : [defaultTeam];
} else {
updatedTeams = teams ? [...teams, defaultTeam] : [defaultTeam];
}
return (
<div className="mt-5 mb-5">
<Title>Select Team</Title>
<Text>
If you belong to multiple teams, this setting controls which team is used by default when creating new Virtual
Keys.
</Text>
<Text className="mt-3 mb-3">
<b>Default Team:</b> If no team_id is set for a key, it will be grouped under here.
</Text>
{updatedTeams && updatedTeams.length > 0 ? (
<Select defaultValue="0">
{updatedTeams.map((team: any, index) => (
<SelectItem
key={index}
value={String(index)}
onClick={() => {
setSelectedTeam(team);
// setKeys(team["keys"]);
}}
>
{team["team_alias"]}
</SelectItem>
))}
</Select>
) : (
<Text>
No team created. <b>Defaulting to personal account.</b>
</Text>
)}
</div>
);
};
export default DashboardTeam;
@@ -1,69 +0,0 @@
"use client";
import React, { useState, ChangeEvent } from "react";
import { Button, Col, Grid, TextInput } from "@tremor/react";
import { Card, Text } from "@tremor/react";
const EnterProxyUrl: React.FC = () => {
const [proxyUrl, setProxyUrl] = useState<string>("");
const [isUrlSaved, setIsUrlSaved] = useState<boolean>(false);
const handleUrlChange = (event: ChangeEvent<HTMLInputElement>) => {
setProxyUrl(event.target.value);
// Reset the saved status when the URL changes
setIsUrlSaved(false);
};
const handleSaveClick = () => {
// You can perform any additional validation or actions here
// For now, let's just display the message
setIsUrlSaved(true);
};
// Construct the URL for clicking
const clickableUrl = `${window.location.href}?proxyBaseUrl=${proxyUrl}`;
return (
<div>
<Card decoration="top" decorationColor="blue" style={{ width: "1000px" }}>
<Text>Admin Configuration</Text>
<label htmlFor="proxyUrl">Enter Proxy URL:</label>
<TextInput
type="text"
id="proxyUrl"
value={proxyUrl}
onChange={handleUrlChange}
placeholder="https://your-proxy-endpoint.com"
/>
<Button onClick={handleSaveClick} className="gap-2">
Save
</Button>
{/* Display message if the URL is saved */}
{isUrlSaved && (
<div>
<Grid numItems={1} className="gap-2">
<Col>
<p>Proxy Admin UI (Save this URL): {clickableUrl}</p>
</Col>
<Col>
<p>
Get Started with Proxy Admin UI 👉
<a
href={clickableUrl}
target="_blank"
rel="noopener noreferrer"
style={{ color: "blue", textDecoration: "underline" }}
>
{clickableUrl}
</a>
</p>
</Col>
</Grid>
</div>
)}
</Card>
</div>
);
};
export default EnterProxyUrl;
@@ -1,19 +0,0 @@
import { Team } from "./key_list";
export const createTeamSearchFunction = (teams: Team[] | null) => {
return async (searchText: string): Promise<Array<{ label: string; value: string }>> => {
// Return empty array if teams is null or searchText is empty
if (!teams || !searchText.trim()) {
return [];
}
// Filter teams where team_alias contains the search text (case insensitive)
const filteredTeams = teams.filter((team) => team.team_alias.toLowerCase().includes(searchText.toLowerCase()));
// Map filtered teams to the required format
return filteredTeams.map((team) => ({
label: `${team.team_alias} (${team.team_id.substring(0, 8)}...)`,
value: team.team_id,
}));
};
};
@@ -1,279 +0,0 @@
import React from "react";
import { Typography, Space, Button, Divider } from "antd";
import { WarningOutlined, InfoCircleOutlined, CopyOutlined } from "@ant-design/icons";
import { testMCPConnectionRequest } from "./networking";
import NotificationsManager from "./molecules/notifications_manager";
const { Text } = Typography;
interface MCPConnectionTestProps {
formValues: Record<string, any>;
accessToken: string;
serverName?: string;
onClose?: () => void;
onTestComplete?: () => void;
}
const MCPConnectionTest: React.FC<MCPConnectionTestProps> = ({
formValues,
accessToken,
serverName = "this MCP server",
onClose,
onTestComplete,
}) => {
const [connectionError, setConnectionError] = React.useState<Error | string | null>(null);
const [rawRequest, setRawRequest] = React.useState<any>(null);
const [rawResponse, setRawResponse] = React.useState<any>(null);
const [isLoading, setIsLoading] = React.useState<boolean>(true);
const [connectionSuccess, setConnectionSuccess] = React.useState<boolean>(false);
const [showDetails, setShowDetails] = React.useState<boolean>(false);
const testMCPConnection = async () => {
setIsLoading(true);
setShowDetails(false);
setConnectionError(null);
setRawRequest(null);
setRawResponse(null);
setConnectionSuccess(false);
// Add a small delay to ensure form values are fully populated
await new Promise((resolve) => setTimeout(resolve, 100));
try {
console.log("Testing MCP connection with form values:", formValues);
// Prepare the MCP server config from form values
const mcpServerConfig = {
server_id: formValues.server_id || "",
alias: formValues.alias || "",
url: formValues.url,
transport: formValues.transport,
auth_type: formValues.auth_type,
mcp_info: formValues.mcp_info,
};
setRawRequest(mcpServerConfig);
// Test connection
const connectionResponse = await testMCPConnectionRequest(accessToken, mcpServerConfig);
console.log("Connection test response:", connectionResponse);
if (connectionResponse.status === "ok") {
setConnectionError(null);
setConnectionSuccess(true);
} else {
const errorMessage = connectionResponse.message || "Unknown connection error";
setConnectionError(errorMessage);
setRawResponse(connectionResponse);
}
} catch (error) {
console.error("MCP connection test error:", error);
setConnectionError(error instanceof Error ? error.message : String(error));
} finally {
setIsLoading(false);
if (onTestComplete) onTestComplete();
}
};
React.useEffect(() => {
// Run the test once when component mounts
// Add a small timeout to ensure form values are ready
const timer = setTimeout(() => {
testMCPConnection();
}, 200);
return () => clearTimeout(timer);
}, []); // Empty dependency array means this runs once on mount
const getCleanErrorMessage = (errorMsg: string) => {
if (!errorMsg) return "Unknown error";
const mainError = errorMsg.split("stack trace:")[0].trim();
const cleanedError = mainError.replace(/^(.*?)Error: /, "");
return cleanedError;
};
const connectionErrorMessage =
typeof connectionError === "string"
? getCleanErrorMessage(connectionError)
: connectionError?.message
? getCleanErrorMessage(connectionError.message)
: "Unknown error";
const formatMCPRequest = (mcpConfig: Record<string, any>) => {
return JSON.stringify(mcpConfig, null, 2);
};
const isOverallSuccess = connectionSuccess && !connectionError;
return (
<div style={{ padding: "24px", borderRadius: "8px", backgroundColor: "#fff" }}>
{isLoading ? (
<div style={{ textAlign: "center", padding: "32px 20px" }}>
<div className="loading-spinner" style={{ marginBottom: "16px" }}>
{/* Simple CSS spinner */}
<div
style={{
border: "3px solid #f3f3f3",
borderTop: "3px solid #1890ff",
borderRadius: "50%",
width: "30px",
height: "30px",
animation: "spin 1s linear infinite",
margin: "0 auto",
}}
/>
</div>
<Text style={{ fontSize: "16px" }}>Testing connection to {serverName}...</Text>
<style jsx>{`
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
`}</style>
</div>
) : isOverallSuccess ? (
<div>
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", padding: "32px 20px" }}>
<div style={{ color: "#52c41a", fontSize: "24px", display: "flex", alignItems: "center" }}>
<svg
viewBox="64 64 896 896"
focusable="false"
data-icon="check-circle"
width="1em"
height="1em"
fill="currentColor"
aria-hidden="true"
>
<path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"></path>
</svg>
</div>
<Text type="success" style={{ fontSize: "18px", fontWeight: 500, marginLeft: "10px" }}>
Connection to {serverName} successful!
</Text>
</div>
</div>
) : (
<>
<div>
<div style={{ display: "flex", alignItems: "center", marginBottom: "20px" }}>
<WarningOutlined style={{ color: "#ff4d4f", fontSize: "24px", marginRight: "12px" }} />
<Text type="danger" style={{ fontSize: "18px", fontWeight: 500 }}>
Connection to {serverName} failed
</Text>
</div>
<div
style={{
backgroundColor: "#fff2f0",
border: "1px solid #ffccc7",
borderRadius: "8px",
padding: "16px",
marginBottom: "20px",
boxShadow: "0 1px 2px rgba(0, 0, 0, 0.03)",
}}
>
<Text strong style={{ display: "block", marginBottom: "8px" }}>
Error:{" "}
</Text>
<Text type="danger" style={{ fontSize: "14px", lineHeight: "1.5" }}>
{connectionErrorMessage}
</Text>
{connectionError && (
<div style={{ marginTop: "12px" }}>
<Button
type="link"
onClick={() => setShowDetails(!showDetails)}
style={{ paddingLeft: 0, height: "auto" }}
>
{showDetails ? "Hide Details" : "Show Details"}
</Button>
</div>
)}
</div>
{showDetails && (
<div style={{ marginBottom: "20px" }}>
<Text strong style={{ display: "block", marginBottom: "8px", fontSize: "15px" }}>
Troubleshooting Details
</Text>
<pre
style={{
backgroundColor: "#f5f5f5",
padding: "16px",
borderRadius: "8px",
fontSize: "13px",
maxHeight: "200px",
overflow: "auto",
border: "1px solid #e8e8e8",
lineHeight: "1.5",
}}
>
{typeof connectionError === "string" ? connectionError : JSON.stringify(connectionError, null, 2)}
</pre>
</div>
)}
<div>
<Text strong style={{ display: "block", marginBottom: "8px", fontSize: "15px" }}>
MCP Server Configuration
</Text>
<pre
style={{
backgroundColor: "#f5f5f5",
padding: "16px",
borderRadius: "8px",
fontSize: "13px",
maxHeight: "250px",
overflow: "auto",
border: "1px solid #e8e8e8",
lineHeight: "1.5",
}}
>
{formatMCPRequest(rawRequest || {})}
</pre>
<Button
style={{ marginTop: "8px" }}
icon={<CopyOutlined />}
onClick={() => {
navigator.clipboard.writeText(formatMCPRequest(rawRequest || {}));
NotificationsManager.success("Copied to clipboard");
}}
>
Copy Configuration
</Button>
</div>
</div>
</>
)}
<Divider style={{ margin: "24px 0 16px" }} />
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<Button
type="link"
href="https://docs.litellm.ai/docs/proxy/mcp_server"
target="_blank"
icon={<InfoCircleOutlined />}
>
View MCP Documentation
</Button>
<Space>
<Button onClick={testMCPConnection} loading={isLoading}>
Test Again
</Button>
<Button type="primary" onClick={onClose}>
Close
</Button>
</Space>
</div>
</div>
);
};
export default MCPConnectionTest;
@@ -1,90 +0,0 @@
import React, { useState } from "react";
import { Modal } from "antd";
import { Button as TremorButton } from "@tremor/react";
import { ExclamationIcon } from "@heroicons/react/outline";
interface CredentialDeleteModalProps {
isVisible: boolean;
onCancel: () => void;
onConfirm: () => void;
credentialName: string;
}
const CredentialDeleteModal: React.FC<CredentialDeleteModalProps> = ({
isVisible,
onCancel,
onConfirm,
credentialName,
}) => {
const [deleteConfirmInput, setDeleteConfirmInput] = useState("");
const isValid = deleteConfirmInput === credentialName;
const handleCancel = () => {
setDeleteConfirmInput("");
onCancel();
};
const handleConfirm = () => {
if (isValid) {
setDeleteConfirmInput("");
onConfirm();
}
};
return (
<Modal
title={
<div className="flex items-center">
<ExclamationIcon className="h-6 w-6 text-red-600 mr-2" />
Delete Credential
</div>
}
open={isVisible}
footer={null}
onCancel={handleCancel}
closable={true}
destroyOnHidden={true}
maskClosable={false}
>
<div className="mt-4">
<div className="flex items-start gap-3 p-4 bg-red-50 border border-red-100 rounded-md mb-5">
<div className="text-red-500 mt-0.5">
<ExclamationIcon className="h-5 w-5" />
</div>
<div>
<p className="text-base font-medium text-red-600">
This action cannot be undone and may break existing integrations.
</p>
</div>
</div>
<div className="mb-5">
<label className="block text-base font-medium text-gray-700 mb-2">
{`Type `}
<span className="underline italic">&apos;{credentialName}&apos;</span>
{` to confirm deletion:`}
</label>
<input
type="text"
value={deleteConfirmInput}
onChange={(e) => setDeleteConfirmInput(e.target.value)}
placeholder="Enter credential name exactly"
className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-base"
autoFocus
/>
</div>
<div className="flex justify-end space-x-2">
<TremorButton onClick={handleCancel} variant="secondary" className="mr-2">
Cancel
</TremorButton>
<TremorButton onClick={handleConfirm} color="red" className="focus:ring-red-500" disabled={!isValid}>
Delete Credential
</TremorButton>
</div>
</div>
</Modal>
);
};
export default CredentialDeleteModal;
@@ -83,7 +83,7 @@ const defaultServerRootPath = "/";
export let serverRootPath = defaultServerRootPath;
export let proxyBaseUrl = defaultProxyBaseUrl;
if (isLocal != true) {
console.log = function () {};
console.log = function () { };
}
const getWindowLocation = () => {
@@ -136,8 +136,6 @@ const HTTP_REQUEST = {
DELETE: "DELETE",
};
export const DEFAULT_ORGANIZATION = "default_organization";
export interface Model {
model_name: string;
litellm_params: object;
@@ -533,38 +531,6 @@ export const modelCreateCall = async (accessToken: string, formValues: Model) =>
}
};
export const modelSettingsCall = async (accessToken: string) => {
/**
* Get all configurable params for setting a model
*/
try {
let url = proxyBaseUrl ? `${proxyBaseUrl}/model/settings` : `/model/settings`;
//NotificationsManager.info("Requesting model data");
const response = await fetch(url, {
method: "GET",
headers: {
[globalLitellmHeaderName]: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
});
if (!response.ok) {
const errorData = await response.json();
const errorMessage = deriveErrorMessage(errorData);
handleError(errorMessage);
throw new Error(errorMessage);
}
const data = await response.json();
//NotificationsManager.info("Received model data");
return data;
// Handle success - you might want to update some state or UI based on the created key
} catch (error: any) {
console.error("Failed to get model settings:", error);
}
};
export const modelDeleteCall = async (accessToken: string, model_id: string) => {
console.log(`model_id in model delete call: ${model_id}`);
try {
@@ -2301,178 +2267,6 @@ export const deleteAllowedIP = async (accessToken: string, ip: string) => {
}
};
export const modelMetricsCall = async (
accessToken: string,
userID: string,
userRole: string,
modelGroup: string | null,
startTime: string | undefined,
endTime: string | undefined,
apiKey: string | null,
customer: string | null,
) => {
/**
* Get all models on proxy
*/
try {
let url = proxyBaseUrl ? `${proxyBaseUrl}/model/metrics` : `/model/metrics`;
if (modelGroup) {
url = `${url}?_selected_model_group=${modelGroup}&startTime=${startTime}&endTime=${endTime}&api_key=${apiKey}&customer=${customer}`;
}
// NotificationsManager.info("Requesting model data");
const response = await fetch(url, {
method: "GET",
headers: {
[globalLitellmHeaderName]: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
});
if (!response.ok) {
const errorData = await response.json();
const errorMessage = deriveErrorMessage(errorData);
handleError(errorMessage);
throw new Error(errorMessage);
}
const data = await response.json();
// NotificationsManager.info("Received model data");
return data;
// Handle success - you might want to update some state or UI based on the created key
} catch (error) {
console.error("Failed to create key:", error);
throw error;
}
};
export const streamingModelMetricsCall = async (
accessToken: string,
modelGroup: string | null,
startTime: string | undefined,
endTime: string | undefined,
) => {
/**
* Get all models on proxy
*/
try {
let url = proxyBaseUrl ? `${proxyBaseUrl}/model/streaming_metrics` : `/model/streaming_metrics`;
if (modelGroup) {
url = `${url}?_selected_model_group=${modelGroup}&startTime=${startTime}&endTime=${endTime}`;
}
// NotificationsManager.info("Requesting model data");
const response = await fetch(url, {
method: "GET",
headers: {
[globalLitellmHeaderName]: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
});
if (!response.ok) {
const errorData = await response.json();
const errorMessage = deriveErrorMessage(errorData);
handleError(errorMessage);
throw new Error(errorMessage);
}
const data = await response.json();
// NotificationsManager.info("Received model data");
return data;
// Handle success - you might want to update some state or UI based on the created key
} catch (error) {
console.error("Failed to create key:", error);
throw error;
}
};
export const modelMetricsSlowResponsesCall = async (
accessToken: string,
userID: string,
userRole: string,
modelGroup: string | null,
startTime: string | undefined,
endTime: string | undefined,
apiKey: string | null,
customer: string | null,
) => {
/**
* Get all models on proxy
*/
try {
let url = proxyBaseUrl ? `${proxyBaseUrl}/model/metrics/slow_responses` : `/model/metrics/slow_responses`;
if (modelGroup) {
url = `${url}?_selected_model_group=${modelGroup}&startTime=${startTime}&endTime=${endTime}&api_key=${apiKey}&customer=${customer}`;
}
// NotificationsManager.info("Requesting model data");
const response = await fetch(url, {
method: "GET",
headers: {
[globalLitellmHeaderName]: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
});
if (!response.ok) {
const errorData = await response.json();
const errorMessage = deriveErrorMessage(errorData);
handleError(errorMessage);
throw new Error(errorMessage);
}
const data = await response.json();
// NotificationsManager.info("Received model data");
return data;
// Handle success - you might want to update some state or UI based on the created key
} catch (error) {
console.error("Failed to create key:", error);
throw error;
}
};
export const modelExceptionsCall = async (
accessToken: string,
userID: string,
userRole: string,
modelGroup: string | null,
startTime: string | undefined,
endTime: string | undefined,
apiKey: string | null,
customer: string | null,
) => {
/**
* Get all models on proxy
*/
try {
let url = proxyBaseUrl ? `${proxyBaseUrl}/model/metrics/exceptions` : `/model/metrics/exceptions`;
if (modelGroup) {
url = `${url}?_selected_model_group=${modelGroup}&startTime=${startTime}&endTime=${endTime}&api_key=${apiKey}&customer=${customer}`;
}
const response = await fetch(url, {
method: "GET",
headers: {
[globalLitellmHeaderName]: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
});
if (!response.ok) {
const errorData = await response.json();
const errorMessage = deriveErrorMessage(errorData);
handleError(errorMessage);
throw new Error(errorMessage);
}
const data = await response.json();
// NotificationsManager.info("Received model data");
return data;
// Handle success - you might want to update some state or UI based on the created key
} catch (error) {
console.error("Failed to create key:", error);
throw error;
}
};
export const updateUsefulLinksCall = async (
accessToken: string,
useful_links: Record<string, string | { url: string; index: number }>,
@@ -1,61 +1,3 @@
export interface Delta {
content?: string;
reasoning_content?: string;
role?: string;
function_call?: any;
tool_calls?: any;
audio?: any;
refusal?: any;
provider_specific_fields?: any;
image?: {
url: string;
detail: string;
};
}
export interface CompletionTokensDetails {
accepted_prediction_tokens?: number;
audio_tokens?: number;
reasoning_tokens?: number;
rejected_prediction_tokens?: number;
text_tokens?: number | null;
}
export interface PromptTokensDetails {
audio_tokens?: number;
cached_tokens?: number;
text_tokens?: number;
image_tokens?: number;
}
export interface Usage {
completion_tokens: number;
prompt_tokens: number;
total_tokens: number;
completion_tokens_details?: CompletionTokensDetails;
prompt_tokens_details?: PromptTokensDetails;
}
export interface StreamingChoices {
finish_reason?: string | null;
index: number;
delta: Delta;
logprobs?: any;
}
export interface StreamingResponse {
id: string;
created: number;
model: string;
object: string;
system_fingerprint?: string;
choices: StreamingChoices[];
provider_specific_fields?: any;
stream_options?: any;
citations?: any;
usage?: Usage;
}
export interface VectorStoreSearchResult {
score: number;
content: Array<{ text: string; type: string }>;
File diff suppressed because it is too large Load Diff
@@ -29,7 +29,6 @@ export const FONT_SIZE_HEADER = 16;
// Colors
export const COLOR_BORDER = "#f0f0f0";
export const COLOR_BACKGROUND = "#fff";
export const COLOR_SECONDARY = "#8c8c8c";
export const COLOR_BG_LIGHT = "#fafafa";
// Spacing
@@ -38,5 +37,3 @@ export const SPACING_MEDIUM = 8;
export const SPACING_LARGE = 12;
export const SPACING_XLARGE = 16;
export const SPACING_XXLARGE = 24;
// Messages (kept for backwards compatibility if needed elsewhere)
@@ -1,29 +0,0 @@
import * as React from "react";
import { getCountryFromIP } from "./ip_lookup";
interface CountryCellProps {
ipAddress: string | null;
}
export const CountryCell: React.FC<CountryCellProps> = ({ ipAddress }) => {
const [country, setCountry] = React.useState<string>("-");
React.useEffect(() => {
if (!ipAddress) return;
let mounted = true;
getCountryFromIP(ipAddress)
.then((result) => {
if (mounted) setCountry(result);
})
.catch(() => {
if (mounted) setCountry("-");
});
return () => {
mounted = false;
};
}, [ipAddress]);
return <span>{country}</span>;
};
@@ -8,7 +8,7 @@ import { debounce } from "lodash";
import { defaultPageSize } from "../constants";
import { PaginatedResponse } from ".";
export const FILTER_KEYS = {
const FILTER_KEYS = {
TEAM_ID: "Team ID",
KEY_HASH: "Key Hash",
REQUEST_ID: "Request ID",