= ({ value = {}, onChange }) => {
+ const [pairs, setPairs] = useState<[string, string][]>(Object.entries(value));
+
+ const handleAdd = () => {
+ setPairs([...pairs, ['', '']]);
+ };
+
+ const handleRemove = (index: number) => {
+ const newPairs = pairs.filter((_, i) => i !== index);
+ setPairs(newPairs);
+ onChange?.(Object.fromEntries(newPairs));
+ };
+
+ const handleChange = (index: number, key: string, val: string) => {
+ const newPairs = [...pairs];
+ newPairs[index] = [key, val];
+ setPairs(newPairs);
+ onChange?.(Object.fromEntries(newPairs));
+ };
+
+ return (
+
+ {pairs.map(([key, val], index) => (
+
+ handleChange(index, e.target.value, val)}
+ />
+ handleChange(index, key, e.target.value)}
+ />
+ handleRemove(index)} />
+
+ ))}
+ }>
+ Add Header
+
+
+ );
+};
+
+export default KeyValueInput;
diff --git a/ui/litellm-dashboard/src/components/leftnav.tsx b/ui/litellm-dashboard/src/components/leftnav.tsx
index b33dda982..c8f5745ed 100644
--- a/ui/litellm-dashboard/src/components/leftnav.tsx
+++ b/ui/litellm-dashboard/src/components/leftnav.tsx
@@ -102,15 +102,21 @@ const Sidebar: React.FC = ({
Router Settings
) : null}
+
{userRole == "Admin" ? (
- setPage("admin-panel")}>
+ setPage("pass-through-settings")}>
+ Pass-Through
+
+ ) : null}
+ {userRole == "Admin" ? (
+ setPage("admin-panel")}>
Admin Settings
) : null}
- setPage("api_ref")}>
+ setPage("api_ref")}>
API Reference
- setPage("model-hub")}>
+ setPage("model-hub")}>
Model Hub
diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx
index 263616c91..f55076478 100644
--- a/ui/litellm-dashboard/src/components/networking.tsx
+++ b/ui/litellm-dashboard/src/components/networking.tsx
@@ -2388,6 +2388,38 @@ export const getGeneralSettingsCall = async (accessToken: String) => {
}
};
+
+export const getPassThroughEndpointsCall = async (accessToken: String) => {
+ try {
+ let url = proxyBaseUrl
+ ? `${proxyBaseUrl}/config/pass_through_endpoint`
+ : `/config/pass_through_endpoint`;
+
+ //message.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.text();
+ handleError(errorData);
+ throw new Error("Network response was not ok");
+ }
+
+ const data = await response.json();
+ //message.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 get callbacks:", error);
+ throw error;
+ }
+};
+
export const getConfigFieldSetting = async (
accessToken: String,
fieldName: string
@@ -2420,6 +2452,85 @@ export const getConfigFieldSetting = async (
}
};
+export const updatePassThroughFieldSetting = async (
+ accessToken: String,
+ fieldName: string,
+ fieldValue: any
+) => {
+ try {
+ let url = proxyBaseUrl
+ ? `${proxyBaseUrl}/config/pass_through_endpoint`
+ : `/config/pass_through_endpoint`;
+
+ let formData = {
+ field_name: fieldName,
+ field_value: fieldValue,
+ };
+ //message.info("Requesting model data");
+ const response = await fetch(url, {
+ method: "POST",
+ headers: {
+ [globalLitellmHeaderName]: `Bearer ${accessToken}`,
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(formData),
+ });
+
+ if (!response.ok) {
+ const errorData = await response.text();
+ handleError(errorData);
+ throw new Error("Network response was not ok");
+ }
+
+ const data = await response.json();
+ //message.info("Received model data");
+ message.success("Successfully updated value!");
+ return data;
+ // Handle success - you might want to update some state or UI based on the created key
+ } catch (error) {
+ console.error("Failed to set callbacks:", error);
+ throw error;
+ }
+};
+
+export const createPassThroughEndpoint = async (
+ accessToken: String,
+ formValues: Record
+) => {
+ /**
+ * Set callbacks on proxy
+ */
+ try {
+ let url = proxyBaseUrl ? `${proxyBaseUrl}/config/pass_through_endpoint` : `/config/pass_through_endpoint`;
+
+ //message.info("Requesting model data");
+ const response = await fetch(url, {
+ method: "POST",
+ headers: {
+ [globalLitellmHeaderName]: `Bearer ${accessToken}`,
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ ...formValues, // Include formValues in the request body
+ }),
+ });
+
+ if (!response.ok) {
+ const errorData = await response.text();
+ handleError(errorData);
+ throw new Error("Network response was not ok");
+ }
+
+ const data = await response.json();
+ //message.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 set callbacks:", error);
+ throw error;
+ }
+};
+
export const updateConfigFieldSetting = async (
accessToken: String,
fieldName: string,
@@ -2500,6 +2611,38 @@ export const deleteConfigFieldSetting = async (
throw error;
}
};
+
+export const deletePassThroughEndpointsCall = async (accessToken: String, endpointId: string) => {
+ try {
+ let url = proxyBaseUrl
+ ? `${proxyBaseUrl}/config/pass_through_endpoint?endpoint_id=${endpointId}`
+ : `/config/pass_through_endpoint${endpointId}`;
+
+ //message.info("Requesting model data");
+ const response = await fetch(url, {
+ method: "DELETE",
+ headers: {
+ [globalLitellmHeaderName]: `Bearer ${accessToken}`,
+ "Content-Type": "application/json",
+ },
+ });
+
+ if (!response.ok) {
+ const errorData = await response.text();
+ handleError(errorData);
+ throw new Error("Network response was not ok");
+ }
+
+ const data = await response.json();
+ //message.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 get callbacks:", error);
+ throw error;
+ }
+};
+
export const setCallbacksCall = async (
accessToken: String,
formValues: Record
diff --git a/ui/litellm-dashboard/src/components/pass_through_settings.tsx b/ui/litellm-dashboard/src/components/pass_through_settings.tsx
new file mode 100644
index 000000000..c979076a2
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/pass_through_settings.tsx
@@ -0,0 +1,196 @@
+import React, { useState, useEffect } from "react";
+import {
+ Card,
+ Title,
+ Subtitle,
+ Table,
+ TableHead,
+ TableRow,
+ Badge,
+ TableHeaderCell,
+ TableCell,
+ TableBody,
+ Metric,
+ Text,
+ Grid,
+ Button,
+ TextInput,
+ Select as Select2,
+ SelectItem,
+ Col,
+ Accordion,
+ AccordionBody,
+ AccordionHeader,
+ AccordionList,
+} from "@tremor/react";
+import {
+ TabPanel,
+ TabPanels,
+ TabGroup,
+ TabList,
+ Tab,
+ Icon,
+} from "@tremor/react";
+import {
+ getCallbacksCall,
+ setCallbacksCall,
+ getGeneralSettingsCall,
+ deletePassThroughEndpointsCall,
+ getPassThroughEndpointsCall,
+ serviceHealthCheck,
+ updateConfigFieldSetting,
+ deleteConfigFieldSetting,
+} from "./networking";
+import {
+ Modal,
+ Form,
+ Input,
+ Select,
+ Button as Button2,
+ message,
+ InputNumber,
+} from "antd";
+import {
+ InformationCircleIcon,
+ PencilAltIcon,
+ PencilIcon,
+ StatusOnlineIcon,
+ TrashIcon,
+ RefreshIcon,
+ CheckCircleIcon,
+ XCircleIcon,
+ QuestionMarkCircleIcon,
+} from "@heroicons/react/outline";
+import StaticGenerationSearchParamsBailoutProvider from "next/dist/client/components/static-generation-searchparams-bailout-provider";
+import AddFallbacks from "./add_fallbacks";
+import AddPassThroughEndpoint from "./add_pass_through";
+import openai from "openai";
+import Paragraph from "antd/es/skeleton/Paragraph";
+interface GeneralSettingsPageProps {
+ accessToken: string | null;
+ userRole: string | null;
+ userID: string | null;
+ modelData: any;
+}
+
+
+interface routingStrategyArgs {
+ ttl?: number;
+ lowest_latency_buffer?: number;
+}
+
+interface nestedFieldItem {
+ field_name: string;
+ field_type: string;
+ field_value: any;
+ field_description: string;
+ stored_in_db: boolean | null;
+}
+
+export interface passThroughItem {
+ path: string
+ target: string
+ headers: object
+}
+
+
+
+
+const PassThroughSettings: React.FC = ({
+ accessToken,
+ userRole,
+ userID,
+ modelData,
+}) => {
+ const [generalSettings, setGeneralSettings] = useState(
+ []
+ );
+ useEffect(() => {
+ if (!accessToken || !userRole || !userID) {
+ return;
+ }
+ getPassThroughEndpointsCall(accessToken).then((data) => {
+ let general_settings = data["endpoints"];
+ setGeneralSettings(general_settings);
+ });
+ }, [accessToken, userRole, userID]);
+
+
+ const handleResetField = (fieldName: string, idx: number) => {
+ if (!accessToken) {
+ return;
+ }
+
+ try {
+ deletePassThroughEndpointsCall(accessToken, fieldName);
+ // update value in state
+
+ const updatedSettings = generalSettings.filter((setting) => setting.path !== fieldName);
+ setGeneralSettings(updatedSettings);
+
+ message.success("Endpoint deleted successfully.");
+
+ } catch (error) {
+ // do something
+ }
+ };
+
+
+ if (!accessToken) {
+ return null;
+ }
+
+
+
+ return (
+
+
+
+
+
+
+ Path
+ Target
+ Headers
+ Action
+
+
+
+ {generalSettings.map((value, index) => (
+
+
+ {value.path}
+
+
+ {
+ value.target
+ }
+
+
+ {
+ JSON.stringify(value.headers)
+ }
+
+
+
+ handleResetField(value.path, index)
+ }
+ >
+ Reset
+
+
+
+ ))}
+
+
+
+
+
+
+ );
+};
+
+export default PassThroughSettings;