import React, { useState, useEffect } from "react"; import { Card, Subtitle, Table, TableHead, TableRow, Badge, TableHeaderCell, TableCell, TableBody, Metric, Text, Grid, Button, TextInput, Switch, Col, TabPanel, TabPanels, TabGroup, TabList, Tab, Callout, SelectItem, Icon, } from "@tremor/react"; import { PencilAltIcon } from "@heroicons/react/outline"; import { Modal, Typography, Form, Input, Select, Button as Button2, message } from "antd"; const { Title, Paragraph } = Typography; const isLocal = process.env.NODE_ENV === "development"; const proxyBaseUrl = isLocal ? "http://localhost:4000" : null; if (isLocal != true) { console.log = function() {}; } import { getCallbacksCall, setCallbacksCall, serviceHealthCheck, } from "./networking"; import AlertingSettings from "./alerting/alerting_settings"; import FormItem from "antd/es/form/FormItem"; interface SettingsPageProps { accessToken: string | null; userRole: string | null; userID: string | null; premiumUser: boolean; } interface genericCallbackParams { litellm_callback_name: string // what to send in request ui_callback_name: string // what to show on UI litellm_callback_params: string[] | null // known required params for this callback } interface AlertingVariables { SLACK_WEBHOOK_URL: string | null; LANGFUSE_PUBLIC_KEY: string | null; LANGFUSE_SECRET_KEY: string | null; LANGFUSE_HOST: string | null; OPENMETER_API_KEY: string | null; } interface AlertingObject { name: string; variables: AlertingVariables; } const defaultLoggingObject: AlertingObject[] = [ { name: "slack", variables: { LANGFUSE_HOST: null, LANGFUSE_PUBLIC_KEY: null, LANGFUSE_SECRET_KEY: null, OPENMETER_API_KEY: null, SLACK_WEBHOOK_URL: null, }, }, { name: "langfuse", variables: { LANGFUSE_HOST: null, LANGFUSE_PUBLIC_KEY: null, LANGFUSE_SECRET_KEY: null, OPENMETER_API_KEY: null, SLACK_WEBHOOK_URL: null, }, }, { name: "openmeter", variables: { LANGFUSE_HOST: null, LANGFUSE_PUBLIC_KEY: null, LANGFUSE_SECRET_KEY: null, OPENMETER_API_KEY: null, SLACK_WEBHOOK_URL: null, }, }, ]; const Settings: React.FC = ({ accessToken, userRole, userID, premiumUser, }) => { const [callbacks, setCallbacks] = useState([]); const [alerts, setAlerts] = useState([]); const [isModalVisible, setIsModalVisible] = useState(false); const [form] = Form.useForm(); const [selectedCallback, setSelectedCallback] = useState(null); const [selectedAlertValues, setSelectedAlertValues] = useState([]); const [catchAllWebhookURL, setCatchAllWebhookURL] = useState(""); const [alertToWebhooks, setAlertToWebhooks] = useState< Record >({}); const [activeAlerts, setActiveAlerts] = useState([]); const [showAddCallbacksModal, setShowAddCallbacksModal] = useState(false); const [allCallbacks, setAllCallbacks] = useState([]); const [selectedCallbacktoAdd, setSelectedCallbacktoAdd] = useState(null); const [selectedCallbackParams, setSelectedCallbackParams] = useState([]); const [showEditCallback, setShowEditCallback] = useState(false); const [selectedEditCallback, setSelectedEditCallback] = useState(null); const handleSwitchChange = (alertName: string) => { if (activeAlerts.includes(alertName)) { setActiveAlerts(activeAlerts.filter((alert) => alert !== alertName)); } else { setActiveAlerts([...activeAlerts, alertName]); } }; const alerts_to_UI_NAME: Record = { llm_exceptions: "LLM Exceptions", llm_too_slow: "LLM Responses Too Slow", llm_requests_hanging: "LLM Requests Hanging", budget_alerts: "Budget Alerts (API Keys, Users)", db_exceptions: "Database Exceptions (Read/Write)", daily_reports: "Weekly/Monthly Spend Reports", outage_alerts: "Outage Alerts", region_outage_alerts: "Region Outage Alerts", }; useEffect(() => { if (!accessToken || !userRole || !userID) { return; } getCallbacksCall(accessToken, userID, userRole).then((data) => { console.log("callbacks", data); setCallbacks(data.callbacks); setAllCallbacks(data.available_callbacks); // setCallbacks(callbacks_data); let alerts_data = data.alerts; console.log("alerts_data", alerts_data); if (alerts_data) { if (alerts_data.length > 0) { let _alert_info = alerts_data[0]; console.log("_alert_info", _alert_info); let catch_all_webhook = _alert_info.variables.SLACK_WEBHOOK_URL; console.log("catch_all_webhook", catch_all_webhook); let active_alerts = _alert_info.active_alerts; setActiveAlerts(active_alerts); setCatchAllWebhookURL(catch_all_webhook); setAlertToWebhooks(_alert_info.alerts_to_webhook); } } setAlerts(alerts_data); }); }, [accessToken, userRole, userID]); const isAlertOn = (alertName: string) => { return activeAlerts && activeAlerts.includes(alertName); }; const handleAddCallback = () => { console.log("Add callback clicked"); setIsModalVisible(true); }; const handleCancel = () => { setIsModalVisible(false); form.resetFields(); setSelectedCallback(null); }; const handleChange = (values: any) => { setSelectedAlertValues(values); // Here, you can perform any additional logic with the selected values console.log("Selected values:", values); }; const handleSaveEmailSettings = () => { if (!accessToken) { return; } let updatedVariables: Record = {}; alerts .filter((alert) => alert.name === "email") .forEach((alert) => { Object.entries(alert.variables ?? {}).forEach(([key, value]) => { const inputElement = document.querySelector(`input[name="${key}"]`) as HTMLInputElement; if (inputElement && inputElement.value) { updatedVariables[key] = inputElement?.value; } }); }); console.log("updatedVariables", updatedVariables); //filter out null / undefined values for updatedVariables const payload = { general_settings: { alerting: ["email"], }, environment_variables: updatedVariables, }; try { setCallbacksCall(accessToken, payload); } catch (error) { message.error("Failed to update alerts: " + error, 20); } message.success("Email settings updated successfully"); } const updateCallbackCall = async (formValues: Record) => { if (!accessToken) { return; } let env_vars: Record = {}; // add all other variables Object.entries(formValues).forEach(([key, value]) => { if (key !== "callback") { env_vars[key] = value } }); let payload = { environment_variables: env_vars, } try { let newCallback = await setCallbacksCall(accessToken, payload); message.success(`Callback added successfully`); setIsModalVisible(false); form.resetFields(); setSelectedCallback(null); } catch (error) { message.error("Failed to add callback: " + error, 20); } } const addNewCallbackCall = async (formValues: Record) => { if (!accessToken) { return; } let new_callback = formValues?.callback let env_vars: Record = {}; // add all other variables Object.entries(formValues).forEach(([key, value]) => { if (key !== "callback") { env_vars[key] = value } }); let payload = { environment_variables: env_vars, litellm_settings: { success_callback: [new_callback], }, } try { let newCallback = await setCallbacksCall(accessToken, payload); message.success(`Callback ${new_callback} added successfully`); setIsModalVisible(false); form.resetFields(); setSelectedCallback(null); } catch (error) { message.error("Failed to add callback: " + error, 20); } } const handleSelectedCallbackChange = (callbackObject: genericCallbackParams) => { console.log("inside handleSelectedCallbackChange", callbackObject); setSelectedCallback(callbackObject.litellm_callback_name); console.log("all callbacks", allCallbacks); if (callbackObject && callbackObject.litellm_callback_params) { setSelectedCallbackParams(callbackObject.litellm_callback_params); console.log("selectedCallbackParams", selectedCallbackParams); } else { setSelectedCallbackParams([]); } }; const handleSaveAlerts = () => { if (!accessToken) { return; } const updatedAlertToWebhooks: Record = {}; Object.entries(alerts_to_UI_NAME).forEach(([key, value]) => { const webhookInput = document.querySelector( `input[name="${key}"]` ) as HTMLInputElement; console.log("key", key); console.log("webhookInput", webhookInput); const newWebhookValue = webhookInput?.value || ""; console.log("newWebhookValue", newWebhookValue); updatedAlertToWebhooks[key] = newWebhookValue; }); console.log("updatedAlertToWebhooks", updatedAlertToWebhooks); const payload = { general_settings: { alert_to_webhook_url: updatedAlertToWebhooks, alert_types: activeAlerts, }, }; console.log("payload", payload); try { setCallbacksCall(accessToken, payload); } catch (error) { message.error("Failed to update alerts: " + error, 20); } message.success("Alerts updated successfully"); }; const handleSaveChanges = (callback: any) => { if (!accessToken) { return; } const updatedVariables = Object.fromEntries( Object.entries(callback.variables).map(([key, value]) => [ key, (document.querySelector(`input[name="${key}"]`) as HTMLInputElement) ?.value || value, ]) ); console.log("updatedVariables", updatedVariables); console.log("updateAlertTypes", selectedAlertValues); const payload = { environment_variables: updatedVariables, litellm_settings: { success_callback: [callback.name], }, }; try { setCallbacksCall(accessToken, payload); } catch (error) { message.error("Failed to update callback: " + error, 20); } message.success("Callback updated successfully"); }; const handleOk = () => { if (!accessToken) { return; } // Handle form submission form.validateFields().then((values) => { // Call API to add the callback console.log("Form values:", values); let payload; if (values.callback === "langfuse") { payload = { environment_variables: { LANGFUSE_PUBLIC_KEY: values.langfusePublicKey, LANGFUSE_SECRET_KEY: values.langfusePrivateKey, }, litellm_settings: { success_callback: [values.callback], }, }; setCallbacksCall(accessToken, payload); let newCallback: AlertingObject = { name: values.callback, variables: { SLACK_WEBHOOK_URL: null, LANGFUSE_HOST: null, LANGFUSE_PUBLIC_KEY: values.langfusePublicKey, LANGFUSE_SECRET_KEY: values.langfusePrivateKey, OPENMETER_API_KEY: null, }, }; // add langfuse to callbacks setCallbacks(callbacks ? [...callbacks, newCallback] : [newCallback]); } else if (values.callback === "slack") { console.log(`values.slackWebhookUrl: ${values.slackWebhookUrl}`); payload = { general_settings: { alerting: ["slack"], alerting_threshold: 300, }, environment_variables: { SLACK_WEBHOOK_URL: values.slackWebhookUrl, }, }; setCallbacksCall(accessToken, payload); // add slack to callbacks console.log(`values.callback: ${values.callback}`); let newCallback: AlertingObject = { name: values.callback, variables: { SLACK_WEBHOOK_URL: values.slackWebhookUrl, LANGFUSE_HOST: null, LANGFUSE_PUBLIC_KEY: null, LANGFUSE_SECRET_KEY: null, OPENMETER_API_KEY: null, }, }; setCallbacks(callbacks ? [...callbacks, newCallback] : [newCallback]); } else if (values.callback == "openmeter") { console.log(`values.openMeterApiKey: ${values.openMeterApiKey}`); payload = { environment_variables: { OPENMETER_API_KEY: values.openMeterApiKey, }, litellm_settings: { success_callback: [values.callback], }, }; setCallbacksCall(accessToken, payload); let newCallback: AlertingObject = { name: values.callback, variables: { SLACK_WEBHOOK_URL: null, LANGFUSE_HOST: null, LANGFUSE_PUBLIC_KEY: null, LANGFUSE_SECRET_KEY: null, OPENMETER_API_KEY: values.openMeterAPIKey, }, }; // add langfuse to callbacks setCallbacks(callbacks ? [...callbacks, newCallback] : [newCallback]); } else { payload = { error: "Invalid callback value", }; } setIsModalVisible(false); form.resetFields(); setSelectedCallback(null); }); }; const handleCallbackChange = (value: string) => { setSelectedCallback(value); }; if (!accessToken) { return null; } console.log(`callbacks: ${callbacks}`); return (
Logging Callbacks Alerting Types Alerting Settings Email Alerts Active Logging Callbacks Callback Name {/* Callback Env Vars */} {callbacks .map((callback, index) => ( {callback.name} { setSelectedEditCallback(callback); setShowEditCallback(true); }} /> ))}
Alerts are only supported for Slack Webhook URLs. Get your webhook urls from{" "} here Slack Webhook URL {Object.entries(alerts_to_UI_NAME).map( ([key, value], index) => ( {key == "region_outage_alerts" ? ( premiumUser ? ( handleSwitchChange(key)} /> ) : ( ) ) : ( handleSwitchChange(key)} /> )} {value} ) )}
Email Settings LiteLLM Docs: email alerts
{alerts .filter((alert) => alert.name === "email") .map((alert, index) => (
    {Object.entries(alert.variables ?? {}).map(([key, value]) => (
  • { premiumUser!= true && (key === "EMAIL_LOGO_URL" || key === "EMAIL_SUPPORT_CONTACT") ? ( ) : (
    {key}
    )} {/* Added descriptions for input fields */}

    {key === "SMTP_HOST" && (

    Enter the SMTP host address, e.g. `smtp.resend.com` Required *
    )} {key === "SMTP_PORT" && (
    Enter the SMTP port number, e.g. `587` Required *
    )} {key === "SMTP_USERNAME" && (
    Enter the SMTP username, e.g. `username` Required *
    )} {key === "SMTP_PASSWORD" && ( Required * )} {key === "SMTP_SENDER_EMAIL" && (
    Enter the sender email address, e.g. `sender@berri.ai` Required *
    )} {key === "TEST_EMAIL_ADDRESS" && (
    Email Address to send `Test Email Alert` to. example: `info@berri.ai` Required *
    ) } {key === "EMAIL_LOGO_URL" && (
    (Optional) Customize the Logo that appears in the email, pass a url to your logo
    ) } {key === "EMAIL_SUPPORT_CONTACT" && (
    (Optional) Customize the support email address that appears in the email. Default is support@berri.ai
    ) }

  • ))}
))}
setShowAddCallbacksModal(false)} footer={null} > LiteLLM Docs: Logging
<> { selectedCallbackParams && selectedCallbackParams.map((param) => ( )) }
Save
setShowEditCallback(false)} footer={null} >
<> { selectedEditCallback && selectedEditCallback.variables && Object.entries(selectedEditCallback.variables).map(([param, value]) => ( )) }
Save
); }; export default Settings;