From 77741b7684304043421cb25c33676258d2d6de1b Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 2 Jul 2025 16:35:22 -0700 Subject: [PATCH] [Feat] UI - Allow adding team specific logging callbacks (#12261) * add arize logo * use correct struct * define dynamic params * add arize_space_id * update ui * ui - team logging --- litellm/types/utils.py | 1 + .../public/assets/logos/arize.png | Bin 0 -> 14249 bytes .../src/components/callback_info_helpers.tsx | 77 +++++- .../src/components/settings.tsx | 22 +- .../src/components/team/LoggingSettings.tsx | 259 ++++++++++++++++++ ui/litellm-dashboard/src/components/teams.tsx | 43 ++- 6 files changed, 373 insertions(+), 29 deletions(-) create mode 100644 ui/litellm-dashboard/public/assets/logos/arize.png create mode 100644 ui/litellm-dashboard/src/components/team/LoggingSettings.tsx diff --git a/litellm/types/utils.py b/litellm/types/utils.py index 9b3308a28fc..7b75784326c 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -2077,6 +2077,7 @@ class StandardCallbackDynamicParams(TypedDict, total=False): # Arize dynamic params arize_api_key: Optional[str] arize_space_key: Optional[str] + arize_space_id: Optional[str] # Logging settings turn_off_message_logging: Optional[bool] # when true will not log messages diff --git a/ui/litellm-dashboard/public/assets/logos/arize.png b/ui/litellm-dashboard/public/assets/logos/arize.png new file mode 100644 index 0000000000000000000000000000000000000000..92a7741141c99e1deba0d1f4d94ea7853587ae75 GIT binary patch literal 14249 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 = { @@ -20,18 +21,74 @@ export const callback_map: Record = { OpenMeter: "openmeter", OTel: "otel", S3: "s3", + Arize: "arize", } const asset_logos_folder = '/ui/assets/logos/'; -export const callbackLogoMap: Record = { - [Callbacks.Braintrust]: `${asset_logos_folder}braintrust.png`, - [Callbacks.Datadog]: `${asset_logos_folder}datadog.png`, - [Callbacks.Langfuse]: `${asset_logos_folder}langfuse.png`, - [Callbacks.LangSmith]: `${asset_logos_folder}langsmith.png`, - [Callbacks.Lago]: `${asset_logos_folder}lago.svg`, - [Callbacks.OpenMeter]: `${asset_logos_folder}openmeter.png`, - [Callbacks.OTel]: `${asset_logos_folder}otel.png`, - [Callbacks.S3]: `${asset_logos_folder}aws.svg`, - [Callbacks.CustomCallbackAPI]: `${asset_logos_folder}custom.svg`, +interface CallbackInfo { + logo: string; + supports_key_team_logging: boolean; + dynamic_params: Record; +} + +export const callbackInfo: Record = { + [Callbacks.Langfuse]: { + logo: `${asset_logos_folder}langfuse.png`, + supports_key_team_logging: true, + dynamic_params: { + "langfuse_public_key": "text", + "langfuse_secret_key": "password", + "langfuse_host": "text" + } + }, + [Callbacks.Arize]: { + logo: `${asset_logos_folder}arize.png`, + supports_key_team_logging: true, + dynamic_params: { + "arize_api_key": "password", + "arize_space_id": "text", + } + }, + [Callbacks.Braintrust]: { + logo: `${asset_logos_folder}braintrust.png`, + supports_key_team_logging: false, + dynamic_params: {} + }, + [Callbacks.CustomCallbackAPI]: { + logo: `${asset_logos_folder}custom.svg`, + supports_key_team_logging: false, + dynamic_params: {} + }, + [Callbacks.Datadog]: { + logo: `${asset_logos_folder}datadog.png`, + supports_key_team_logging: false, + dynamic_params: {} + }, + [Callbacks.LangSmith]: { + logo: `${asset_logos_folder}langsmith.png`, + supports_key_team_logging: false, + dynamic_params: {} + }, + [Callbacks.Lago]: { + logo: `${asset_logos_folder}lago.svg`, + supports_key_team_logging: false, + dynamic_params: {} + }, + [Callbacks.OpenMeter]: { + logo: `${asset_logos_folder}openmeter.png`, + supports_key_team_logging: false, + dynamic_params: {} + }, + [Callbacks.OTel]: { + logo: `${asset_logos_folder}otel.png`, + supports_key_team_logging: false, + dynamic_params: {} + }, + [Callbacks.S3]: { + logo: `${asset_logos_folder}aws.svg`, + supports_key_team_logging: false, + dynamic_params: {} + } }; + \ No newline at end of file diff --git a/ui/litellm-dashboard/src/components/settings.tsx b/ui/litellm-dashboard/src/components/settings.tsx index 8d03b92abc8..3c6e21a5de8 100644 --- a/ui/litellm-dashboard/src/components/settings.tsx +++ b/ui/litellm-dashboard/src/components/settings.tsx @@ -46,7 +46,7 @@ import AlertingSettings from "./alerting/alerting_settings"; import FormItem from "antd/es/form/FormItem"; import { callback_map, - callbackLogoMap, + callbackInfo, Callbacks, } from "./callback_info_helpers"; interface SettingsPageProps { @@ -620,28 +620,16 @@ const Settings: React.FC = ({ value={callback_map[callbackEnum]} >
- {callbackLogoMap[callbackDisplayName] ? ( + {callbackInfo[callbackDisplayName]?.logo ? (
{`${callbackEnum} { - if (callbackLogoMap[callbackDisplayName]) { - delete callbackLogoMap[callbackDisplayName]; - } - }} - style={{ - display: callbackLogoMap[callbackDisplayName] - ? "block" - : "none", + onError={(e) => { + e.currentTarget.style.display = 'none'; }} /> - {!callbackLogoMap[callbackDisplayName] && ( -
- {callbackDisplayName.charAt(0).toUpperCase()} -
- )}
) : (
diff --git a/ui/litellm-dashboard/src/components/team/LoggingSettings.tsx b/ui/litellm-dashboard/src/components/team/LoggingSettings.tsx new file mode 100644 index 00000000000..9521f683e5b --- /dev/null +++ b/ui/litellm-dashboard/src/components/team/LoggingSettings.tsx @@ -0,0 +1,259 @@ +import React, { useState } from 'react'; +import { Form, Select, Space, Tooltip, Divider } from 'antd'; +import { InfoCircleOutlined } from '@ant-design/icons'; +import { Button, Card } from '@tremor/react'; +import { PlusIcon, TrashIcon, CogIcon } from '@heroicons/react/outline'; +import { callbackInfo, Callbacks, callback_map } from '../callback_info_helpers'; + +const { Option } = Select; + +interface LoggingConfig { + callback_name: string; + callback_type: string; + callback_vars: Record; +} + +interface LoggingSettingsProps { + value?: LoggingConfig[]; + onChange?: (value: LoggingConfig[]) => void; +} + +const LoggingSettings: React.FC = ({ value = [], onChange }) => { + // Get callbacks that support team and key logging + const supportedCallbacks = Object.entries(callbackInfo) + .filter(([_, info]) => info.supports_key_team_logging) + .map(([name, _]) => name); + + const handleChange = (newValue: LoggingConfig[]) => { + onChange?.(newValue); + }; + + const addLoggingConfig = () => { + const newConfig: LoggingConfig = { + callback_name: '', + callback_type: 'success', + callback_vars: {} + }; + handleChange([...value, newConfig]); + }; + + const removeLoggingConfig = (index: number) => { + const newValue = value.filter((_, i) => i !== index); + handleChange(newValue); + }; + + const updateLoggingConfig = (index: number, field: keyof LoggingConfig, newValue: any) => { + const updatedConfigs = [...value]; + if (field === 'callback_name') { + // Convert display name to callback value and reset callback_vars when callback changes + const callbackValue = callback_map[newValue] || newValue; + updatedConfigs[index] = { + ...updatedConfigs[index], + [field]: callbackValue, + callback_vars: {} + }; + } else { + updatedConfigs[index] = { + ...updatedConfigs[index], + [field]: newValue + }; + } + handleChange(updatedConfigs); + }; + + const updateCallbackVar = (configIndex: number, varName: string, varValue: string) => { + const updatedConfigs = [...value]; + updatedConfigs[configIndex] = { + ...updatedConfigs[configIndex], + callback_vars: { + ...updatedConfigs[configIndex].callback_vars, + [varName]: varValue + } + }; + handleChange(updatedConfigs); + }; + + const renderDynamicParams = (config: LoggingConfig, configIndex: number) => { + if (!config.callback_name) return null; + + // Find the display name for the callback + const callbackDisplayName = Object.entries(callback_map).find( + ([_, value]) => value === config.callback_name + )?.[0]; + + if (!callbackDisplayName) return null; + + const dynamicParams = callbackInfo[callbackDisplayName]?.dynamic_params || {}; + + if (Object.keys(dynamicParams).length === 0) return null; + + return ( +
+
+
+
+
+ Integration Parameters +
+
+ {Object.entries(dynamicParams).map(([paramName, paramType]) => ( +
+ + updateCallbackVar(configIndex, paramName, e.target.value)} + /> +
+ ))} +
+
+ ); + }; + + return ( +
+
+
+ + Logging Integrations + + + +
+ +
+ +
+ {value.map((config, index) => { + const callbackDisplayName = config.callback_name + ? Object.entries(callback_map).find(([_, value]) => value === config.callback_name)?.[0] + : undefined; + const logoUrl = callbackDisplayName ? callbackInfo[callbackDisplayName]?.logo : null; + + return ( + +
+
+ {logoUrl && ( + {callbackDisplayName} + )} + + {callbackDisplayName || 'New Integration'} Configuration + +
+ +
+
+
+
+ + +
+ +
+ + +
+
+ + {renderDynamicParams(config, index)} +
+
+ ); + })} +
+ + {value.length === 0 && ( +
+ +
No logging integrations configured
+
Click "Add Integration" to configure logging for this team
+
+ )} +
+ ); +}; + +export default LoggingSettings; \ No newline at end of file diff --git a/ui/litellm-dashboard/src/components/teams.tsx b/ui/litellm-dashboard/src/components/teams.tsx index cba0c588e3d..11d56007416 100644 --- a/ui/litellm-dashboard/src/components/teams.tsx +++ b/ui/litellm-dashboard/src/components/teams.tsx @@ -60,6 +60,7 @@ import AvailableTeamsPanel from "@/components/team/available_teams"; import VectorStoreSelector from "./vector_store_management/VectorStoreSelector"; import PremiumVectorStoreSelector from "./common_components/PremiumVectorStoreSelector"; import PremiumMCPSelector from "./common_components/PremiumMCPSelector"; +import LoggingSettings from "./team/LoggingSettings"; import type { KeyResponse, Team } from "./key_team_helpers/key_list"; interface TeamProps { @@ -181,6 +182,7 @@ const Teams: React.FC = ({ // Add this state near the other useState declarations const [guardrailsList, setGuardrailsList] = useState([]); const [expandedAccordions, setExpandedAccordions] = useState>({}); + const [loggingSettings, setLoggingSettings] = useState([]); useEffect(() => { console.log(`currentOrgForCreateTeam: ${currentOrgForCreateTeam}`); @@ -234,6 +236,7 @@ const Teams: React.FC = ({ const handleOk = () => { setIsTeamModalVisible(false); form.resetFields(); + setLoggingSettings([]); }; const handleMemberOk = () => { @@ -244,8 +247,8 @@ const Teams: React.FC = ({ const handleCancel = () => { setIsTeamModalVisible(false); - form.resetFields(); + setLoggingSettings([]); }; const handleMemberCancel = () => { @@ -325,6 +328,27 @@ const Teams: React.FC = ({ } message.info("Creating Team"); + + // Handle logging settings in metadata + if (loggingSettings.length > 0) { + let metadata = {}; + if (formValues.metadata) { + try { + metadata = JSON.parse(formValues.metadata); + } catch (e) { + console.warn("Invalid JSON in metadata field, starting with empty object"); + } + } + + // Add logging settings to metadata + metadata = { + ...metadata, + logging: loggingSettings.filter(config => config.callback_name) // Only include configs with callback_name + }; + + formValues.metadata = JSON.stringify(metadata); + } + // Transform allowed_vector_store_ids and allowed_mcp_server_ids into object_permission if (formValues.allowed_vector_store_ids && formValues.allowed_vector_store_ids.length > 0) { formValues.object_permission = { @@ -350,6 +374,7 @@ const Teams: React.FC = ({ console.log(`response for team create call: ${response}`); message.success("Team created"); form.resetFields(); + setLoggingSettings([]); setIsTeamModalVisible(false); } } catch (error) { @@ -911,7 +936,7 @@ const Teams: React.FC = ({ = ({ + + + + Logging Settings + + +
+ +
+
+
Create Team