diff --git a/litellm/proxy/management_endpoints/common_utils.py b/litellm/proxy/management_endpoints/common_utils.py index 8f2ba37a9d..149ca6e2f6 100644 --- a/litellm/proxy/management_endpoints/common_utils.py +++ b/litellm/proxy/management_endpoints/common_utils.py @@ -43,7 +43,7 @@ def _set_object_metadata_field( value: Value to set for the field """ if field_name in LiteLLM_ManagementEndpoint_MetadataFields_Premium: - _premium_user_check() + _premium_user_check(field_name) object_data.metadata = object_data.metadata or {} object_data.metadata[field_name] = value diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index 007c0164be..7ce38c2d68 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -903,7 +903,7 @@ def prepare_metadata_fields( if k in LiteLLM_ManagementEndpoint_MetadataFields_Premium: from litellm.proxy.utils import _premium_user_check - _premium_user_check() + _premium_user_check(k) casted_metadata[k] = v except Exception as e: diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index d3d2972abf..f2652ba2c6 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -3575,17 +3575,22 @@ def handle_exception_on_proxy(e: Exception) -> ProxyException: ) -def _premium_user_check(): +def _premium_user_check(feature:str=None): """ Raises an HTTPException if the user is not a premium user """ from litellm.proxy.proxy_server import premium_user + if feature: + detail_msg = f"This feature is only available for LiteLLM Enterprise users: {feature}. {CommonProxyErrors.not_premium_user.value}" + else: + detail_msg = f"This feature is only available for LiteLLM Enterprise users. {CommonProxyErrors.not_premium_user.value}" + if not premium_user: raise HTTPException( status_code=403, detail={ - "error": f"This feature is only available for LiteLLM Enterprise users. {CommonProxyErrors.not_premium_user.value}" + "error": detail_msg }, ) diff --git a/ui/litellm-dashboard/src/app/page.tsx b/ui/litellm-dashboard/src/app/page.tsx index c2479aa175..0503e5c608 100644 --- a/ui/litellm-dashboard/src/app/page.tsx +++ b/ui/litellm-dashboard/src/app/page.tsx @@ -22,7 +22,7 @@ import SpendLogsTable from "@/components/view_logs" import ModelHubTable from "@/components/model_hub_table" import NewUsagePage from "@/components/new_usage" import APIRef from "@/components/api_ref" -import ChatUI from "@/components/chat_ui" +import ChatUI from "@/components/chat_ui/ChatUI" import Sidebar from "@/components/leftnav" import Usage from "@/components/usage" import CacheDashboard from "@/components/cache_dashboard" diff --git a/ui/litellm-dashboard/src/components/chat_ui.tsx b/ui/litellm-dashboard/src/components/chat_ui/ChatUI.tsx similarity index 96% rename from ui/litellm-dashboard/src/components/chat_ui.tsx rename to ui/litellm-dashboard/src/components/chat_ui/ChatUI.tsx index 6504576578..1eb5f58c14 100644 --- a/ui/litellm-dashboard/src/components/chat_ui.tsx +++ b/ui/litellm-dashboard/src/components/chat_ui/ChatUI.tsx @@ -25,34 +25,34 @@ import { import { v4 as uuidv4 } from 'uuid'; import { message, Select, Spin, Typography, Tooltip, Input, Upload, Modal, Button } from "antd"; -import { makeOpenAIChatCompletionRequest } from "./chat_ui/llm_calls/chat_completion"; -import { makeOpenAIImageGenerationRequest } from "./chat_ui/llm_calls/image_generation"; -import { makeOpenAIImageEditsRequest } from "./chat_ui/llm_calls/image_edits"; -import { makeOpenAIResponsesRequest } from "./chat_ui/llm_calls/responses_api"; -import { makeAnthropicMessagesRequest } from "./chat_ui/llm_calls/anthropic_messages"; -import { fetchAvailableModels, ModelGroup } from "./chat_ui/llm_calls/fetch_models"; -import { fetchAvailableMCPTools } from "./chat_ui/llm_calls/fetch_mcp_tools"; -import type { MCPTool } from "./chat_ui/llm_calls/fetch_mcp_tools"; -import { litellmModeMapping, ModelMode, EndpointType, getEndpointType } from "./chat_ui/mode_endpoint_mapping"; +import { makeOpenAIChatCompletionRequest } from "./llm_calls/chat_completion"; +import { makeOpenAIImageGenerationRequest } from "./llm_calls/image_generation"; +import { makeOpenAIImageEditsRequest } from "./llm_calls/image_edits"; +import { makeOpenAIResponsesRequest } from "./llm_calls/responses_api"; +import { makeAnthropicMessagesRequest } from "./llm_calls/anthropic_messages"; +import { fetchAvailableModels, ModelGroup } from "./llm_calls/fetch_models"; +import { fetchAvailableMCPTools } from "./llm_calls/fetch_mcp_tools"; +import type { MCPTool } from "./llm_calls/fetch_mcp_tools"; +import { litellmModeMapping, ModelMode, EndpointType, getEndpointType } from "./mode_endpoint_mapping"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { coy } from 'react-syntax-highlighter/dist/esm/styles/prism'; -import EndpointSelector from "./chat_ui/EndpointSelector"; -import TagSelector from "./tag_management/TagSelector"; -import VectorStoreSelector from "./vector_store_management/VectorStoreSelector"; -import GuardrailSelector from "./guardrails/GuardrailSelector"; -import { determineEndpointType } from "./chat_ui/EndpointUtils"; -import { generateCodeSnippet } from "./chat_ui/CodeSnippets"; -import { MessageType } from "./chat_ui/types"; -import ReasoningContent from "./chat_ui/ReasoningContent"; -import ResponseMetrics, { TokenUsage } from "./chat_ui/ResponseMetrics"; -import ResponsesImageUpload from "./chat_ui/ResponsesImageUpload"; -import ResponsesImageRenderer from "./chat_ui/ResponsesImageRenderer"; -import { convertImageToBase64, createMultimodalMessage, createDisplayMessage } from "./chat_ui/ResponsesImageUtils"; -import ChatImageUpload from "./chat_ui/ChatImageUpload"; -import ChatImageRenderer from "./chat_ui/ChatImageRenderer"; -import { createChatMultimodalMessage, createChatDisplayMessage } from "./chat_ui/ChatImageUtils"; -import SessionManagement from "./chat_ui/SessionManagement"; -import MCPEventsDisplay, { MCPEvent } from "./chat_ui/MCPEventsDisplay"; +import EndpointSelector from "./EndpointSelector"; +import TagSelector from "../tag_management/TagSelector"; +import VectorStoreSelector from "../vector_store_management/VectorStoreSelector"; +import GuardrailSelector from "../guardrails/GuardrailSelector"; +import { determineEndpointType } from "./EndpointUtils"; +import { generateCodeSnippet } from "./CodeSnippets"; +import { MessageType } from "./types"; +import ReasoningContent from "./ReasoningContent"; +import ResponseMetrics, { TokenUsage } from "./ResponseMetrics"; +import ResponsesImageUpload from "./ResponsesImageUpload"; +import ResponsesImageRenderer from "./ResponsesImageRenderer"; +import { convertImageToBase64, createMultimodalMessage, createDisplayMessage } from "./ResponsesImageUtils"; +import ChatImageUpload from "./ChatImageUpload"; +import ChatImageRenderer from "./ChatImageRenderer"; +import { createChatMultimodalMessage, createChatDisplayMessage } from "./ChatImageUtils"; +import SessionManagement from "./SessionManagement"; +import MCPEventsDisplay, { MCPEvent } from "./MCPEventsDisplay"; import { SendOutlined, ApiOutlined, @@ -73,7 +73,7 @@ import { FilePdfOutlined, ArrowUpOutlined } from "@ant-design/icons"; -import NotificationsManager from "./molecules/notifications_manager"; +import NotificationsManager from "../molecules/notifications_manager"; const { TextArea } = Input; const { Dragger } = Upload; @@ -282,13 +282,17 @@ const ChatUI: React.FC = ({ ); console.log("Fetched models:", uniqueModels); - - if (uniqueModels.length > 0) { - setModelInfo(uniqueModels); - if (!selectedModel) { - setSelectedModel(uniqueModels[0].model_group); - } + + setModelInfo(uniqueModels); + + // check for selection overlap or empty model list + const hasSelection = uniqueModels.some(m => m.model_group === selectedModel); + if (!uniqueModels.length) { + setSelectedModel(undefined); + } else if (!hasSelection) { + setSelectedModel(uniqueModels[0].model_group); } + } catch (error) { console.error("Error fetching model info:", error); } diff --git a/ui/litellm-dashboard/src/components/guardrails/GuardrailSelector.tsx b/ui/litellm-dashboard/src/components/guardrails/GuardrailSelector.tsx index b6f072cdfa..d111a1d8b3 100644 --- a/ui/litellm-dashboard/src/components/guardrails/GuardrailSelector.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/GuardrailSelector.tsx @@ -9,13 +9,15 @@ interface GuardrailSelectorProps { value?: string[]; className?: string; accessToken: string; + disabled?: boolean; } const GuardrailSelector: React.FC = ({ onChange, value, className, - accessToken + accessToken, + disabled }) => { const [guardrails, setGuardrails] = useState([]); const [loading, setLoading] = useState(false); @@ -51,7 +53,8 @@ const GuardrailSelector: React.FC = ({