From 4cf7a74e6092b7f73d4da12f1bdd3d57e3857a86 Mon Sep 17 00:00:00 2001 From: abi_jey Date: Fri, 28 Nov 2025 14:27:57 +0000 Subject: [PATCH 01/47] fix: Azure OpenAI GA path relies soley on model paramter as deployment --- litellm/llms/azure/realtime/handler.py | 10 ++++++---- .../azure/realtime/test_azure_realtime_handler.py | 13 +++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/litellm/llms/azure/realtime/handler.py b/litellm/llms/azure/realtime/handler.py index 0dc42dad43e..217a05c83a4 100644 --- a/litellm/llms/azure/realtime/handler.py +++ b/litellm/llms/azure/realtime/handler.py @@ -12,6 +12,7 @@ from ....litellm_core_utils.litellm_logging import Logging as LiteLLMLogging from ....litellm_core_utils.realtime_streaming import RealTimeStreaming from ....llms.custom_httpx.http_handler import get_shared_realtime_ssl_context from ..azure import AzureChatCompletion +from litellm._logging import verbose_proxy_logger # BACKEND_WS_URL = "ws://localhost:8080/v1/realtime?model=gpt-4o-realtime-preview-2024-10-01" @@ -51,18 +52,18 @@ class AzureOpenAIRealtime(AzureChatCompletion): Examples: beta/default: "wss://.../openai/realtime?api-version=2024-10-01-preview&deployment=gpt-4o-realtime-preview" - GA/v1: "wss://.../openai/v1/realtime?api-version=2024-10-01-preview&deployment=gpt-4o-realtime-preview" + GA/v1: "wss://.../openai/v1/realtime?model=gpt-realtime-deployment" """ api_base = api_base.replace("https://", "wss://") # Determine path based on realtime_protocol if realtime_protocol in ("GA", "v1"): - path = "/openai/v1/realtime" + path = "/openai/v1/realtime" + return f"{api_base}{path}?model={model}" else: # Default to beta path for backwards compatibility path = "/openai/realtime" - - return f"{api_base}{path}?api-version={api_version}&deployment={model}" + return f"{api_base}{path}?api-version={api_version}&deployment={model}" async def async_realtime( self, @@ -107,4 +108,5 @@ class AzureOpenAIRealtime(AzureChatCompletion): except websockets.exceptions.InvalidStatusCode as e: # type: ignore await websocket.close(code=e.status_code, reason=str(e)) except Exception: + verbose_proxy_logger.exception("Error in AzureOpenAIRealtime.async_realtime") pass diff --git a/tests/test_litellm/llms/azure/realtime/test_azure_realtime_handler.py b/tests/test_litellm/llms/azure/realtime/test_azure_realtime_handler.py index ca8d01e158f..2a110c8f9a7 100644 --- a/tests/test_litellm/llms/azure/realtime/test_azure_realtime_handler.py +++ b/tests/test_litellm/llms/azure/realtime/test_azure_realtime_handler.py @@ -117,6 +117,7 @@ async def test_construct_url_beta_protocol_explicit(): async def test_construct_url_ga_protocol(): """ Test that realtime_protocol='GA' uses /openai/v1/realtime (GA path). + GA path uses ?model= instead of ?api-version=&deployment= format. """ from litellm.llms.azure.realtime.handler import AzureOpenAIRealtime @@ -132,8 +133,10 @@ async def test_construct_url_ga_protocol(): assert "/openai/v1/realtime?" in url # Ensure it doesn't have both paths assert url.count("/realtime") == 1 - assert "api-version=2024-10-01-preview" in url - assert "deployment=gpt-4o-realtime-preview" in url + # GA path uses model= query param, not api-version and deployment + assert "model=gpt-4o-realtime-preview" in url + assert "api-version" not in url + assert "deployment" not in url @pytest.mark.asyncio @@ -203,8 +206,10 @@ async def test_async_realtime_uses_ga_protocol_end_to_end(): called_url = mock_ws_connect.call_args[0][0] assert "/openai/v1/realtime" in called_url assert called_url.startswith("wss://") - assert "api-version=2024-10-01-preview" in called_url - assert "deployment=gpt-4o-realtime-preview" in called_url + # GA path uses model= query param, not api-version and deployment + assert "model=gpt-4o-realtime-preview" in called_url + assert "api-version" not in called_url + assert "deployment" not in called_url @pytest.mark.asyncio From 9edc50efbd117b38e54c038cbc1af1dd32572206 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Mon, 1 Dec 2025 10:21:44 +0530 Subject: [PATCH 02/47] Fix 500 error for malformed request --- litellm/proxy/common_request_processing.py | 19 ++++++++- tests/proxy_unit_tests/test_proxy_server.py | 44 +++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/litellm/proxy/common_request_processing.py b/litellm/proxy/common_request_processing.py index d2b04410026..1c6c9b97173 100644 --- a/litellm/proxy/common_request_processing.py +++ b/litellm/proxy/common_request_processing.py @@ -809,7 +809,24 @@ class ProxyBaseLLMRequestProcessing: status_code=e.response.status_code, detail={"error": error_text}, ) - error_msg = f"{str(e)}" + error_msg = f"{str(e)}" + # Check for AttributeError in various places: + # 1. Direct AttributeError (already handled above) + # 2. In underlying exception (__cause__, __context__, original_exception) + has_attribute_error = ( + (isinstance(e, Exception) and isinstance(getattr(e, "__cause__", None), AttributeError)) + or (isinstance(e, Exception) and isinstance(getattr(e, "__context__", None), AttributeError)) + or (isinstance(e, Exception) and isinstance(getattr(e, "original_exception", None), AttributeError)) + ) + + if has_attribute_error: + raise ProxyException( + message=f"Invalid request format: {error_msg}", + type="invalid_request_error", + param=None, + code=status.HTTP_400_BAD_REQUEST, + headers=headers, + ) raise ProxyException( message=getattr(e, "message", error_msg), type=getattr(e, "type", "None"), diff --git a/tests/proxy_unit_tests/test_proxy_server.py b/tests/proxy_unit_tests/test_proxy_server.py index 6dad7cb08d0..dc34a50f87e 100644 --- a/tests/proxy_unit_tests/test_proxy_server.py +++ b/tests/proxy_unit_tests/test_proxy_server.py @@ -175,6 +175,50 @@ def test_chat_completion(mock_acompletion, client_no_auth): pytest.fail(f"LiteLLM Proxy test failed. Exception - {str(e)}") +def test_chat_completion_malformed_messages_returns_400(client_no_auth): + """ + Test that malformed messages (strings instead of dicts) return 400 instead of 500. + + This test verifies that when a client sends messages as raw strings instead of + {role, content} objects, LiteLLM returns a 400 invalid_request_error instead + of a 500 Internal Server Error. + """ + global headers + try: + # Test data with malformed messages (string instead of dict) + test_data = { + "model": "gpt-3.5-turbo", + "messages": ["hi how are you"], # Invalid: should be [{"role": "user", "content": "hi how are you"}] + } + + print("testing proxy server with malformed messages") + response = client_no_auth.post("/v1/chat/completions", json=test_data, headers=headers) + + print(f"response status: {response.status_code}") + print(f"response text: {response.text}") + + # Should return 400, not 500 + assert response.status_code == 400, f"Expected 400, got {response.status_code}. Response: {response.text}" + + # Verify error format + result = response.json() + assert "error" in result, "Response should contain 'error' key" + error = result["error"] + + # Verify error type and message + assert error.get("type") == "invalid_request_error" or error.get("type") is None, \ + f"Expected invalid_request_error or None, got {error.get('type')}" + assert error.get("code") == "400" or error.get("code") == 400, \ + f"Expected code 400, got {error.get('code')}" + + # Error message should indicate invalid request format + error_message = error.get("message", "") + assert len(error_message) > 0, "Error message should not be empty" + + except Exception as e: + pytest.fail(f"LiteLLM Proxy test failed. Exception - {str(e)}") + + def test_get_settings_request_timeout(client_no_auth): """ When no timeout is set, it should use the litellm.request_timeout value From 6de610767340cadd6df1c5508325128045c8fae5 Mon Sep 17 00:00:00 2001 From: YutaSaito <36355491+uc4w6c@users.noreply.github.com> Date: Tue, 2 Dec 2025 02:59:01 +0900 Subject: [PATCH 03/47] fix: respect guardrail mock_response during during_call to return blocked output (#17247) --- litellm/proxy/common_request_processing.py | 23 +++-- .../proxy/test_common_request_processing.py | 99 ++++++++++++++++++- 2 files changed, 111 insertions(+), 11 deletions(-) diff --git a/litellm/proxy/common_request_processing.py b/litellm/proxy/common_request_processing.py index d2b04410026..ed4c451f8d3 100644 --- a/litellm/proxy/common_request_processing.py +++ b/litellm/proxy/common_request_processing.py @@ -536,7 +536,11 @@ class ProxyBaseLLMRequestProcessing: responses = await llm_responses - response = responses[1] + # Guardrails (pre/during-call) can inject a mock response to short-circuit the LLM call. + # Prefer it when present so blocked/filtered output is returned instead of the model response. + response = self.data.get("mock_response") + if response is None: + response = responses[1] hidden_params = getattr(response, "_hidden_params", {}) or {} model_id = hidden_params.get("model_id", None) or "" @@ -804,7 +808,7 @@ class ProxyBaseLLMRequestProcessing: # This matches the original behavior before the refactor in commit 511d435f6f error_body = await e.response.aread() error_text = error_body.decode("utf-8") - + raise HTTPException( status_code=e.response.status_code, detail={"error": error_text}, @@ -1072,9 +1076,9 @@ class ProxyBaseLLMRequestProcessing: # Add cache-related fields to **params (handled by Usage.__init__) if cache_creation_input_tokens is not None: - usage_kwargs["cache_creation_input_tokens"] = ( - cache_creation_input_tokens - ) + usage_kwargs[ + "cache_creation_input_tokens" + ] = cache_creation_input_tokens if cache_read_input_tokens is not None: usage_kwargs["cache_read_input_tokens"] = cache_read_input_tokens @@ -1093,7 +1097,9 @@ class ProxyBaseLLMRequestProcessing: return obj return None - def maybe_get_model_id(self, _logging_obj: Optional[LiteLLMLoggingObj]) -> Optional[str]: + def maybe_get_model_id( + self, _logging_obj: Optional[LiteLLMLoggingObj] + ) -> Optional[str]: """ Get model_id from logging object or request metadata. @@ -1103,10 +1109,7 @@ class ProxyBaseLLMRequestProcessing: model_id = None if _logging_obj: # 1. Try getting from litellm_params (updated during call) - if ( - hasattr(_logging_obj, "litellm_params") - and _logging_obj.litellm_params - ): + if hasattr(_logging_obj, "litellm_params") and _logging_obj.litellm_params: # First check direct model_info path (set by router.py with selected deployment) model_info = _logging_obj.litellm_params.get("model_info") or {} model_id = model_info.get("id", None) diff --git a/tests/test_litellm/proxy/test_common_request_processing.py b/tests/test_litellm/proxy/test_common_request_processing.py index 4768ec42ff6..8f5f182f429 100644 --- a/tests/test_litellm/proxy/test_common_request_processing.py +++ b/tests/test_litellm/proxy/test_common_request_processing.py @@ -1,11 +1,13 @@ import copy +from types import SimpleNamespace from unittest.mock import AsyncMock, MagicMock import pytest -from fastapi import Request, status +from fastapi import Request, Response, status from fastapi.responses import StreamingResponse import litellm +import litellm.proxy.common_request_processing as common_request_processing from litellm._uuid import uuid from litellm.integrations.opentelemetry import UserAPIKeyAuth from litellm.proxy.common_request_processing import ( @@ -75,6 +77,101 @@ class TestProxyBaseLLMRequestProcessing: pytest.fail("litellm_call_id is not a valid UUID") assert data_passed["litellm_call_id"] == returned_data["litellm_call_id"] + @pytest.mark.asyncio + async def test_base_process_llm_request_prefers_guardrail_mock_response( + self, monkeypatch + ): + processing_obj = ProxyBaseLLMRequestProcessing( + data={ + "messages": [], + "metadata": {}, + "litellm_metadata": {"model_info": {"id": "fallback-model"}}, + } + ) + + guardrail_response = litellm.ModelResponse( + model="bedrock-guardrail", + hidden_params={"model_id": "guardrail-model"}, + ) + llm_response = litellm.ModelResponse( + model="real-model", + hidden_params={"model_id": "real-model"}, + ) + + async def mock_common_processing(self, *args, **kwargs): + logging_obj = SimpleNamespace(litellm_call_id="test-call-id") + self.data["litellm_call_id"] = "test-call-id" + self.data["litellm_logging_obj"] = logging_obj + return self.data, logging_obj + + monkeypatch.setattr( + ProxyBaseLLMRequestProcessing, + "common_processing_pre_call_logic", + mock_common_processing, + ) + + async def mock_route_request(*args, **kwargs): + async def _inner(): + return llm_response + + return _inner() + + monkeypatch.setattr( + common_request_processing, + "route_request", + mock_route_request, + ) + + check_response_size_is_safe_mock = AsyncMock() + monkeypatch.setattr( + common_request_processing, + "check_response_size_is_safe", + check_response_size_is_safe_mock, + ) + + async def mock_during_call_hook(*args, **kwargs): + kwargs["data"]["mock_response"] = guardrail_response + + proxy_logging_obj = MagicMock(spec=ProxyLogging) + proxy_logging_obj.during_call_hook = AsyncMock( + side_effect=mock_during_call_hook + ) + proxy_logging_obj.update_request_status = AsyncMock(return_value=None) + proxy_logging_obj.post_call_success_hook = AsyncMock( + return_value=guardrail_response + ) + + user_api_key_dict = MagicMock(spec=UserAPIKeyAuth) + user_api_key_dict.tpm_limit = None + user_api_key_dict.rpm_limit = None + user_api_key_dict.max_budget = None + user_api_key_dict.spend = 0 + user_api_key_dict.allowed_model_region = None + + fastapi_response = Response() + proxy_config = MagicMock(spec=ProxyConfig) + + result = await processing_obj.base_process_llm_request( + request=MagicMock(spec=Request), + fastapi_response=fastapi_response, + user_api_key_dict=user_api_key_dict, + route_type="acompletion", + proxy_logging_obj=proxy_logging_obj, + general_settings={}, + proxy_config=proxy_config, + select_data_generator=lambda **kwargs: None, + ) + + assert result is guardrail_response + assert ( + proxy_logging_obj.post_call_success_hook.await_args.kwargs["response"] + is guardrail_response + ) + assert ( + check_response_size_is_safe_mock.await_args.kwargs["response"] + is guardrail_response + ) + @pytest.mark.asyncio async def test_stream_timeout_header_processing(self): """ From 7808a610f8a95ddb4449eae1b0af67d4e5b2e50d Mon Sep 17 00:00:00 2001 From: orgersh92 Date: Mon, 1 Dec 2025 20:03:51 +0200 Subject: [PATCH 04/47] Fix session consistency, move Lasso API version away from source code (#17316) * store and fetch lasso-conversation id from cache * include gateway/v# in the baseUrl to allow simpler version migrations in the future * add tests for cached conversation ID --- .../docs/proxy/guardrails/lasso_security.md | 4 +- .../guardrails/guardrail_hooks/lasso/lasso.py | 68 +++++++------------ .../guardrails/guardrail_hooks/test_lasso.py | 29 +++++--- 3 files changed, 47 insertions(+), 54 deletions(-) diff --git a/docs/my-website/docs/proxy/guardrails/lasso_security.md b/docs/my-website/docs/proxy/guardrails/lasso_security.md index 21528790afe..113e3f8974a 100644 --- a/docs/my-website/docs/proxy/guardrails/lasso_security.md +++ b/docs/my-website/docs/proxy/guardrails/lasso_security.md @@ -35,7 +35,7 @@ guardrails: guardrail: lasso mode: "pre_call" api_key: os.environ/LASSO_API_KEY - api_base: "https://server.lasso.security" + api_base: "https://server.lasso.security/gateway/v3" - guardrail_name: "lasso-post-guard" litellm_params: guardrail: lasso @@ -228,7 +228,7 @@ Expected response: ## PII Masking with Lasso -Lasso supports automatic PII detection and masking using the `/gateway/v1/classifix` endpoint. When enabled, sensitive information like emails, phone numbers, and other PII will be automatically masked with appropriate placeholders. +Lasso supports automatic PII detection and masking using the `/classifix` endpoint. When enabled, sensitive information like emails, phone numbers, and other PII will be automatically masked with appropriate placeholders. ### Enabling PII Masking diff --git a/litellm/proxy/guardrails/guardrail_hooks/lasso/lasso.py b/litellm/proxy/guardrails/guardrail_hooks/lasso/lasso.py index 99d2b82400f..ea8f1b0a97f 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/lasso/lasso.py +++ b/litellm/proxy/guardrails/guardrail_hooks/lasso/lasso.py @@ -33,6 +33,8 @@ from litellm.integrations.custom_guardrail import ( CustomGuardrail, log_guardrail_information, ) +from litellm.integrations.custom_guardrail import dc as global_cache + from litellm.llms.custom_httpx.http_handler import ( get_async_httpx_client, httpxSpecialProvider, @@ -100,7 +102,7 @@ class LassoGuardrail(CustomGuardrail): ) self.api_base = ( - api_base or os.getenv("LASSO_API_BASE") or "https://server.lasso.security" + api_base or os.getenv("LASSO_API_BASE") or "https://server.lasso.security/gateway/v3" ) verbose_proxy_logger.debug( @@ -125,7 +127,7 @@ class LassoGuardrail(CustomGuardrail): async def async_pre_call_hook( self, user_api_key_dict: UserAPIKeyAuth, - cache: DualCache, + cache: DualCache, # Deprecated, use global_cache instead (kept to align with CustomGuardrail interface) data: dict, call_type: Literal[ "completion", @@ -150,10 +152,10 @@ class LassoGuardrail(CustomGuardrail): return data # Get or generate conversation_id and store it in data for post-call consistency - conversation_id = self._get_or_generate_conversation_id(data, cache) - data.setdefault("_lasso_internal", {})["conversation_id"] = conversation_id + # The conversation_id is being stored in the cache so it can be used by the post_call hook + self._get_or_generate_conversation_id(data, global_cache) - return await self._run_lasso_guardrail(data, cache, message_type="PROMPT") + return await self._run_lasso_guardrail(data, global_cache, message_type="PROMPT") @log_guardrail_information async def async_moderation_hook( @@ -213,17 +215,12 @@ class LassoGuardrail(CustomGuardrail): "litellm_call_id": data.get("litellm_call_id"), } - # Copy stored conversation_id from pre-call hook - if data.get("_lasso_internal", {}).get("conversation_id") and isinstance(response_data, dict): - response_data.setdefault("_lasso_internal", {})["conversation_id"] = data["_lasso_internal"][ - "conversation_id" - ] # Handle masking for post-call if self.mask: - headers = self._prepare_headers(response_data) - payload = self._prepare_payload(response_messages, "COMPLETION", response_data) - api_url = f"{self.api_base}/gateway/v3/classifix" + headers = self._prepare_headers(response_data, global_cache) + payload = self._prepare_payload(response_messages, response_data, global_cache, "COMPLETION") + api_url = f"{self.api_base}/classifix" try: lasso_response = await self._call_lasso_api(headers=headers, payload=payload, api_url=api_url) @@ -241,7 +238,7 @@ class LassoGuardrail(CustomGuardrail): raise LassoGuardrailAPIError(f"Failed to apply post-call masking: {str(e)}") else: # Use the same data for conversation_id consistency (no cache access needed) - await self._run_lasso_guardrail(response_data, cache=None, message_type="COMPLETION") + await self._run_lasso_guardrail(response_data, cache=global_cache, message_type="COMPLETION") verbose_proxy_logger.debug("Post-call Lasso validation completed") else: verbose_proxy_logger.warning("No response messages found to validate") @@ -306,7 +303,7 @@ class LassoGuardrail(CustomGuardrail): async def _run_lasso_guardrail( self, data: dict, - cache: Optional[DualCache], + cache: DualCache, message_type: Literal["PROMPT", "COMPLETION"] = "PROMPT", ): """ @@ -345,14 +342,14 @@ class LassoGuardrail(CustomGuardrail): async def _handle_classification( self, data: dict, - cache: Optional[DualCache], + cache: DualCache, message_type: Literal["PROMPT", "COMPLETION"], messages: List[Dict[str, str]], ) -> dict: """Handle classification without masking.""" try: headers = self._prepare_headers(data, cache) - payload = self._prepare_payload(messages, message_type, data, cache) + payload = self._prepare_payload(messages, data, cache, message_type) response = await self._call_lasso_api(headers=headers, payload=payload) self._process_lasso_response(response) return data @@ -363,15 +360,15 @@ class LassoGuardrail(CustomGuardrail): async def _handle_masking( self, data: dict, - cache: Optional[DualCache], + cache: DualCache, message_type: Literal["PROMPT", "COMPLETION"], messages: List[Dict[str, str]], ) -> dict: """Handle masking with classifix endpoint.""" try: headers = self._prepare_headers(data, cache) - payload = self._prepare_payload(messages, message_type, data, cache) - api_url = f"{self.api_base}/gateway/v3/classifix" + payload = self._prepare_payload(messages, data, cache, message_type) + api_url = f"{self.api_base}/classifix" response = await self._call_lasso_api(headers=headers, payload=payload, api_url=api_url) self._process_lasso_response(response) @@ -437,7 +434,7 @@ class LassoGuardrail(CustomGuardrail): }, ) - def _prepare_headers(self, data: dict, cache: Optional[DualCache] = None) -> Dict[str, str]: + def _prepare_headers(self, data: dict, cache: DualCache) -> Dict[str, str]: """Prepare headers for the Lasso API request.""" if not self.lasso_api_key: raise LassoGuardrailMissingSecrets( @@ -455,13 +452,7 @@ class LassoGuardrail(CustomGuardrail): headers["lasso-user-id"] = self.user_id # Always include conversation_id (generated or provided) - if cache is not None: - conversation_id = self._get_or_generate_conversation_id(data, cache) - else: - # For post-call hook, use stored conversation_id or generate a new one - conversation_id = ( - data.get("_lasso_internal", {}).get("conversation_id") or self.conversation_id or self._generate_ulid() - ) + conversation_id = self._get_or_generate_conversation_id(data, cache) headers["lasso-conversation-id"] = conversation_id @@ -470,9 +461,9 @@ class LassoGuardrail(CustomGuardrail): def _prepare_payload( self, messages: List[Dict[str, str]], + data: dict, + cache: DualCache, message_type: Literal["PROMPT", "COMPLETION"] = "PROMPT", - data: Optional[dict] = None, - cache: Optional[DualCache] = None, ) -> Dict[str, Any]: """ Prepare the payload for the Lasso API request. @@ -490,20 +481,9 @@ class LassoGuardrail(CustomGuardrail): payload["userId"] = self.user_id # Always include sessionId (conversation_id - generated or provided) - if data is not None: - if cache is not None: - conversation_id = self._get_or_generate_conversation_id(data, cache) - else: - # For post-call hook, use stored conversation_id or fallback - conversation_id = ( - data.get("_lasso_internal", {}).get("conversation_id") - or self.conversation_id - or self._generate_ulid() - ) + conversation_id = self._get_or_generate_conversation_id(data, cache) - payload["sessionId"] = conversation_id - elif self.conversation_id: - payload["sessionId"] = self.conversation_id + payload["sessionId"] = conversation_id return payload @@ -514,7 +494,7 @@ class LassoGuardrail(CustomGuardrail): api_url: Optional[str] = None, ) -> LassoResponse: """Call the Lasso API and return the response.""" - url = api_url or f"{self.api_base}/gateway/v3/classify" + url = api_url or f"{self.api_base}/classify" verbose_proxy_logger.debug(f"Calling Lasso API with messageType: {payload.get('messageType')}") response = await self.async_handler.post( url=url, diff --git a/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_lasso.py b/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_lasso.py index c63974ac3f2..87542c974a5 100644 --- a/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_lasso.py +++ b/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_lasso.py @@ -1,6 +1,7 @@ import os import sys import pytest +import uuid from unittest.mock import patch, MagicMock from httpx import Response, Request from fastapi import HTTPException @@ -77,10 +78,11 @@ class TestLassoGuardrail: assert guardrail.lasso_api_key == "test-api-key" assert guardrail.user_id == "test-user" assert guardrail.conversation_id == "test-conversation" - assert guardrail.api_base == "https://server.lasso.security" + assert guardrail.api_base == "https://server.lasso.security/gateway/v3" @pytest.mark.asyncio async def test_pre_call_no_violations(self): + from litellm.integrations.custom_guardrail import dc as global_cache """Test pre-call hook with no violations detected.""" # Setup guardrail guardrail = LassoGuardrail( @@ -90,12 +92,16 @@ class TestLassoGuardrail: default_on=True ) + test_call_id = str(uuid.uuid4()) + assert global_cache.get_cache(f"lasso_conversation_id:{test_call_id}") is None + # Test data data = { "messages": [ {"role": "user", "content": "Hello, how are you?"} ], - "metadata": {} + "metadata": {}, + "litellm_call_id": test_call_id } # Mock successful API response with no violations @@ -118,13 +124,14 @@ class TestLassoGuardrail: request=Request(method="POST", url="https://server.lasso.security/gateway/v3/classify"), ) + local_cache = DualCache() with patch( "litellm.llms.custom_httpx.http_handler.AsyncHTTPHandler.post", return_value=mock_response ): result = await guardrail.async_pre_call_hook( user_api_key_dict=UserAPIKeyAuth(), - cache=DualCache(), + cache=local_cache, data=data, call_type="completion" ) @@ -132,6 +139,11 @@ class TestLassoGuardrail: # Should return original data when no violations detected assert result == data + # Verify that the conversation_id is stored in the global cache but not the local cache + cache_key = f"lasso_conversation_id:{test_call_id}" + assert global_cache.get_cache(cache_key) is not None + assert local_cache.get_cache(cache_key) is None + @pytest.mark.asyncio async def test_pre_call_with_violations(self): """Test pre-call hook with violations detected.""" @@ -466,9 +478,10 @@ class TestLassoGuardrail: ) messages = [{"role": "user", "content": "Test message"}] + cache = DualCache() # Test PROMPT payload - prompt_payload = guardrail._prepare_payload(messages, "PROMPT") + prompt_payload = guardrail._prepare_payload(messages, {}, cache, "PROMPT") assert prompt_payload["messageType"] == "PROMPT" assert prompt_payload["messages"] == messages assert prompt_payload["userId"] == "test-user" @@ -476,7 +489,7 @@ class TestLassoGuardrail: # Test COMPLETION payload completion_messages = [{"role": "assistant", "content": "Test response"}] - completion_payload = guardrail._prepare_payload(completion_messages, "COMPLETION") + completion_payload = guardrail._prepare_payload(completion_messages, {}, cache, "COMPLETION") assert completion_payload["messageType"] == "COMPLETION" assert completion_payload["messages"] == completion_messages assert completion_payload["userId"] == "test-user" @@ -489,9 +502,9 @@ class TestLassoGuardrail: user_id="test-user", conversation_id="test-conversation" ) - + cache = DualCache() data = {"litellm_call_id": "test-call-id"} - headers = guardrail._prepare_headers(data) + headers = guardrail._prepare_headers(data, cache) assert headers["lasso-api-key"] == "test-api-key" assert headers["Content-Type"] == "application/json" assert headers["lasso-user-id"] == "test-user" @@ -499,7 +512,7 @@ class TestLassoGuardrail: # Test without optional fields guardrail_minimal = LassoGuardrail(lasso_api_key="test-api-key") - headers_minimal = guardrail_minimal._prepare_headers(data) + headers_minimal = guardrail_minimal._prepare_headers(data, cache) assert headers_minimal["lasso-api-key"] == "test-api-key" assert headers_minimal["Content-Type"] == "application/json" assert "lasso-user-id" not in headers_minimal From c588e7854d7a8d03363b1b203af8650d37ab9b57 Mon Sep 17 00:00:00 2001 From: Colin Lin Date: Thu, 27 Nov 2025 16:36:04 -0500 Subject: [PATCH 05/47] use kwargs --- litellm/llms/custom_httpx/llm_http_handler.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/litellm/llms/custom_httpx/llm_http_handler.py b/litellm/llms/custom_httpx/llm_http_handler.py index fdd504e2f57..10353c68b97 100644 --- a/litellm/llms/custom_httpx/llm_http_handler.py +++ b/litellm/llms/custom_httpx/llm_http_handler.py @@ -1804,15 +1804,23 @@ class BaseLLMHTTPHandler: Optional[litellm.types.utils.ProviderSpecificHeader], kwargs.get("provider_specific_header", None), ) - extra_headers = ProviderSpecificHeaderUtils.get_provider_specific_headers( + provider_specific_headers = ProviderSpecificHeaderUtils.get_provider_specific_headers( provider_specific_header=provider_specific_header, custom_llm_provider=custom_llm_provider, ) forwarded_headers = kwargs.get("headers", None) - if forwarded_headers and extra_headers: - merged_headers = {**forwarded_headers, **extra_headers} - else: - merged_headers = forwarded_headers or extra_headers + # Also check for extra_headers in kwargs (from config or direct calls) + extra_headers_from_kwargs = kwargs.get("extra_headers", None) + print("extra_headers_from_kwargs", extra_headers_from_kwargs) + print("provider_specific_headers", provider_specific_headers) + # Merge all header sources: forwarded < extra_headers < provider_specific + merged_headers = {} + if forwarded_headers: + merged_headers.update(forwarded_headers) + if extra_headers_from_kwargs: + merged_headers.update(extra_headers_from_kwargs) + if provider_specific_headers: + merged_headers.update(provider_specific_headers) ( headers, api_base, From 2a5082e6cf2e00c64faea984e587c314fac2731d Mon Sep 17 00:00:00 2001 From: Colin Lin Date: Thu, 27 Nov 2025 16:58:32 -0500 Subject: [PATCH 06/47] remove logs --- litellm/llms/custom_httpx/llm_http_handler.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/litellm/llms/custom_httpx/llm_http_handler.py b/litellm/llms/custom_httpx/llm_http_handler.py index 10353c68b97..701cefb771e 100644 --- a/litellm/llms/custom_httpx/llm_http_handler.py +++ b/litellm/llms/custom_httpx/llm_http_handler.py @@ -1811,8 +1811,6 @@ class BaseLLMHTTPHandler: forwarded_headers = kwargs.get("headers", None) # Also check for extra_headers in kwargs (from config or direct calls) extra_headers_from_kwargs = kwargs.get("extra_headers", None) - print("extra_headers_from_kwargs", extra_headers_from_kwargs) - print("provider_specific_headers", provider_specific_headers) # Merge all header sources: forwarded < extra_headers < provider_specific merged_headers = {} if forwarded_headers: From e420b633a1ac8eaaf33fc2024d4ad70e7b8d688a Mon Sep 17 00:00:00 2001 From: Colin Lin Date: Fri, 28 Nov 2025 17:06:10 -0500 Subject: [PATCH 07/47] add tests --- .../custom_httpx/test_llm_http_handler.py | 150 +++++++++++++++++- 1 file changed, 145 insertions(+), 5 deletions(-) diff --git a/tests/test_litellm/llms/custom_httpx/test_llm_http_handler.py b/tests/test_litellm/llms/custom_httpx/test_llm_http_handler.py index 26fc18de16d..17b4243da1d 100644 --- a/tests/test_litellm/llms/custom_httpx/test_llm_http_handler.py +++ b/tests/test_litellm/llms/custom_httpx/test_llm_http_handler.py @@ -1,17 +1,14 @@ -import io import os -import pathlib -import ssl import sys -from unittest.mock import MagicMock +from unittest.mock import AsyncMock, Mock, patch import pytest sys.path.insert( 0, os.path.abspath("../../../..") ) # Adds the parent directory to the system path -import litellm from litellm.llms.custom_httpx.llm_http_handler import BaseLLMHTTPHandler +from litellm.types.router import GenericLiteLLMParams def test_prepare_fake_stream_request(): @@ -75,3 +72,146 @@ def test_prepare_fake_stream_request(): assert "stream" not in result_data assert result_data["model"] == "gpt-4" assert result_data["messages"] == [{"role": "user", "content": "Hello"}] + + +@pytest.mark.asyncio +async def test_async_anthropic_messages_handler_extra_headers(): + """ + Test that async_anthropic_messages_handler correctly extracts and merges + extra_headers from kwargs with proper priority. + """ + handler = BaseLLMHTTPHandler() + + # Mock the config + mock_config = Mock() + mock_config.validate_anthropic_messages_environment = Mock( + return_value=({"x-api-key": "test-key"}, "https://api.anthropic.com") + ) + mock_config.transform_anthropic_messages_request = Mock( + return_value={"model": "claude-3-opus-20240229", "messages": []} + ) + + # Mock the client + mock_client = AsyncMock() + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "id": "msg_123", + "type": "message", + "role": "assistant", + "content": [{"type": "text", "text": "Hello!"}], + "model": "claude-3-opus-20240229", + "stop_reason": "end_turn", + } + mock_client.post = AsyncMock(return_value=mock_response) + + # Mock logging object + mock_logging_obj = Mock() + mock_logging_obj.update_environment_variables = Mock() + mock_logging_obj.model_call_details = {} + mock_logging_obj.stream = False + + # Test case 1: Only extra_headers in kwargs + kwargs = { + "extra_headers": { + "X-Custom-Header": "from-kwargs", + "X-Auth-Token": "token123", + } + } + + with patch( + "litellm.litellm_core_utils.get_provider_specific_headers.ProviderSpecificHeaderUtils.get_provider_specific_headers" + ) as mock_provider_headers: + mock_provider_headers.return_value = None + + # Capture what headers are passed to validate_anthropic_messages_environment + captured_headers = {} + def capture_validate(*args, **kwargs): + captured_headers.update(kwargs.get("headers", {})) + return ({"x-api-key": "test-key"}, "https://api.anthropic.com") + + mock_config.validate_anthropic_messages_environment = capture_validate + + try: + await handler.async_anthropic_messages_handler( + model="claude-3-opus-20240229", + messages=[{"role": "user", "content": "Hello"}], + anthropic_messages_provider_config=mock_config, + anthropic_messages_optional_request_params={}, + custom_llm_provider="anthropic", + litellm_params=GenericLiteLLMParams(), + logging_obj=mock_logging_obj, + client=mock_client, + kwargs=kwargs, + ) + except Exception: + pass # We're testing header extraction, not the full flow + + # Verify extra_headers were extracted and merged + assert "X-Custom-Header" in captured_headers + assert captured_headers["X-Custom-Header"] == "from-kwargs" + assert "X-Auth-Token" in captured_headers + assert captured_headers["X-Auth-Token"] == "token123" + + +@pytest.mark.asyncio +async def test_async_anthropic_messages_handler_header_priority(): + """ + Test that async_anthropic_messages_handler respects header priority: + forwarded < extra_headers < provider_specific + """ + handler = BaseLLMHTTPHandler() + + # Mock the config + mock_config = Mock() + mock_client = AsyncMock() + mock_logging_obj = Mock() + mock_logging_obj.update_environment_variables = Mock() + mock_logging_obj.model_call_details = {} + mock_logging_obj.stream = False + + # Test with all three header sources + kwargs = { + "headers": {"X-Priority": "forwarded", "X-Forwarded-Only": "keep"}, + "extra_headers": {"X-Priority": "extra", "X-Extra-Only": "also-keep"}, + } + + with patch( + "litellm.litellm_core_utils.get_provider_specific_headers.ProviderSpecificHeaderUtils.get_provider_specific_headers" + ) as mock_provider_headers: + mock_provider_headers.return_value = { + "X-Priority": "provider", + "X-Provider-Only": "keep-this-too" + } + + captured_headers = {} + def capture_validate(*args, **kwargs): + captured_headers.update(kwargs.get("headers", {})) + return ({"x-api-key": "test-key"}, "https://api.anthropic.com") + + mock_config.validate_anthropic_messages_environment = capture_validate + mock_config.transform_anthropic_messages_request = Mock( + return_value={"model": "claude-3-opus-20240229", "messages": []} + ) + + try: + await handler.async_anthropic_messages_handler( + model="claude-3-opus-20240229", + messages=[{"role": "user", "content": "Hello"}], + anthropic_messages_provider_config=mock_config, + anthropic_messages_optional_request_params={}, + custom_llm_provider="anthropic", + litellm_params=GenericLiteLLMParams(), + logging_obj=mock_logging_obj, + client=mock_client, + kwargs=kwargs, + ) + except Exception: + pass + + # Verify priority: provider_specific should win + assert captured_headers["X-Priority"] == "provider" + # Verify all unique headers from different sources are present + assert captured_headers["X-Forwarded-Only"] == "keep" + assert captured_headers["X-Extra-Only"] == "also-keep" + assert captured_headers["X-Provider-Only"] == "keep-this-too" From 661bccbc3984396b13900ee9069754dca244e83d Mon Sep 17 00:00:00 2001 From: Colin Lin Date: Mon, 1 Dec 2025 14:15:54 -0500 Subject: [PATCH 08/47] fixed flaky test by sorting list --- .../llms/bedrock/test_anthropic_beta_support.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py b/tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py index bd64670517c..7de2294954c 100644 --- a/tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py +++ b/tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py @@ -80,7 +80,8 @@ class TestAnthropicBetaHeaderSupport: assert "additionalModelRequestFields" in result additional_fields = result["additionalModelRequestFields"] assert "anthropic_beta" in additional_fields - assert additional_fields["anthropic_beta"] == ["context-1m-2025-08-07", "interleaved-thinking-2025-05-14"] + # Sort both arrays before comparing to avoid flakiness from ordering differences + assert sorted(additional_fields["anthropic_beta"]) == sorted(["context-1m-2025-08-07", "interleaved-thinking-2025-05-14"]) def test_messages_transformation_anthropic_beta(self): """Test that Messages API transformation includes anthropic_beta in request.""" @@ -96,7 +97,8 @@ class TestAnthropicBetaHeaderSupport: ) assert "anthropic_beta" in result - assert result["anthropic_beta"] == ["output-128k-2025-02-19"] + # Sort both arrays before comparing to avoid flakiness from ordering differences + assert sorted(result["anthropic_beta"]) == sorted(["output-128k-2025-02-19"]) def test_converse_computer_use_compatibility(self): """Test that user anthropic_beta headers work with computer use tools.""" @@ -287,4 +289,4 @@ class TestAnthropicBetaHeaderSupport: assert "prompt-caching-2024-07-31" not in result["anthropic_beta"] else: # If no beta headers, that's also fine - assert True \ No newline at end of file + assert True From a73bd751fcc6895fa27b801d61b11acb03f91e65 Mon Sep 17 00:00:00 2001 From: YutaSaito <36355491+uc4w6c@users.noreply.github.com> Date: Tue, 2 Dec 2025 05:38:49 +0900 Subject: [PATCH 09/47] doc: add images for tool permission guardrail (#17322) --- .../img/create_guard_tool_permission.png | Bin 0 -> 51115 bytes .../img/create_rule_tool_permission.png | Bin 0 -> 76256 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/my-website/img/create_guard_tool_permission.png create mode 100644 docs/my-website/img/create_rule_tool_permission.png diff --git a/docs/my-website/img/create_guard_tool_permission.png b/docs/my-website/img/create_guard_tool_permission.png new file mode 100644 index 0000000000000000000000000000000000000000..f6e0e77b1aa8c64447170b1db78bbde4ee4714a7 GIT binary patch literal 51115 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⁢iQJIr|hfF_P-@E@2gTV8yAc)*w^!Iq_C&1j(fVx zHYoHvcg4!3_%elHF=E1Is^Wky`$pCp&MU}66cM6b!8(Q-mwbsJB&rWqdLaFqOy9YA z{0;Ql<$5!k zd(I<6HoK$9i7bX0g|a#m)e3qlEjl5t_Xd1U7qJwfqh3fnShnK(Q$_Ru#BQLNC)pq$ z0mm_NnEE+PGJiWiFMR7=?#OcRGP&$UY$p8BezN@v<@cKD06Df2%ih>#Dcwj zVG7SLlFLu=7X|r`sj*sW`)BYy{|a}#Z#yW)-^Asx=>;I$^0f>szuplPmZ9brC^Hb8 zFhgcs4k5nHmO3Dp)9iZ4v;JnV@+>Hv2i2i_()=XMEwESuwD2@t&aB;hkE!ccLUGB*Jhf{ZAqq6LxEDYc|x4r*rI5cxxRi@en+LsOYacgLVugj{oz@9!0*$3 znyrDjxUT&p+MIBSZg>I0@5BCSK|f+Wl!~M6v3*>gs_5iDq_OINfxg&u6qwe!op3_ye`}37d_rbiXrT4VuB6U;qK21r> z=#VS@;yt20u$?^T{5F@5C>d?$cVaP>w^m#+(*j`Q{$+(x+>v!dJ2ZekpLg=d&L4u8 z#16Pmvl$w&LC}ctE6=#boo*G~NE7Jmw-OGA5&E$iUbQvsbPaB6t3S!pG+8&rR?Q0|!|=piI0+SX|+ z1p$o_sU~r13g{(N3SB$7Nk&`utzd(!eYDs~7j+fsblxIw)*6~jjC7}7n)QWU_;(hZ z?Y7Rk?&!3d^f+u5%)e&z4{vw62O~QhoO*_4#GdL|1|O8KuBBxyDFF1}`ER8HQUJjD z{R@Ky_$v~xzrUB`vvuzBhojj#CEoq#^37qq4DN&e6w-SPXc9eoz;?zJeY!Lngc9mUyShU!4=9pbn zcoqz*SrPtjlWb`{haBZ%Mf*z5mc%Ir3+9HrvyQu?vhX*U*;^-3v&{E2IS#{XDlA;| z&$fEol6o}*u~f!vQd*L7W3aIDniIlG66w!Ao5c&9{f~YUS^3T)YXX^c znzn}lbyq9JOAmui0JV5i?Q_!{g`RZMP0(G<_apMQ75S@(j>DZ!HbmFul=KdDXJ#}! zx4nzSt?S`^GW?7T?20TK;EotK-XF?-`yVoML>e@|q+ilcaT!+?j28&tr5Gv!U+tA0 zLD4q)rO{87e!SB1;+Yc0VXmmxo1|c=Hi=*|>&?84yv*gH$p7xRduU-Dm-Cl|<<>|# z+c576ThEllf@3REoovAU!AwC0V=Bj{-wf}m6#9u3R=IdU^V;2&;k!?o z7o!;+%YuQHel_T2-7saRX`2;bXa2Km(%8StbSBWT&TsxIhMspz$RxyAgqpFgm<*cK zF_CR9H{i4Bz!SKiH}Tl1l&qTTg_RAe#rVs$g2y^$`)9T)7HgJdkR5!A*;2h&zC(QS zc$^ihvs&|3LL%{~;NySU8o)q1Y4n-LSX&Dsc%b^t#$s=(6m6>d$w85BnN`4$^#DGB zW%6$KOkyB*joDxM{D@PRQD+>Exqs}yX9l8d>K_eMF9`^{pG10UQdi<(6Qyr_=?D?f z@Oywxixh3P`P^ztcS5ZKoTJ{l$`lPvl3?WiUdI8vPF+Tn5S>`hNFfcT@jU|; z;S^VBs4IYEd(Ocs{-{A4d2%xNCR$!2Kt4r%2xdP4`b~Kl4^eE(({FXibpWDGLN`50 z8WxQ_t!nwWWG(EZN45kS+s+fqqU|!uk2${@Rx1CG?<9-4txkWYxqk+L_=Ri|J{txK z3VKdQJ4p6VE}LIUlrT?TZpM_z9ctx+e#zae8$vP;`2}J_A`q|~U@1cnYCz56n`2|qQ>-AiDW)i%{MDSQ2YiJVe(NSq9r9IB8<7n|Lp7zAtIPrK~Y7C$lHa`75 zKjyH*IzF2{K`l>7clvl=0rbsGT@WS0M_iJx1y=daL@}a25yBSHKxFU3* zNxPM=tXlAKOw2mNyzAR3Rx6GMYk4vMg6m8Eygn-=Z85l>W#8y^>%NgHGl&njv;wdM z=cMzvJ9nj%&%!@BO1^(<3TX1Kd9z!BHYuc1X`uINn*}BERi55QcNV>jQY_h_`2&3h z7V{tdID1WAxpZG`gL#HSR44j8E_gcl2SbKk=ln zC#UoTw_IQNhISr`7c7wudwzf`?zI~BI}i92;Y|Ej`;ii*_ZR+fE&Z^*5m~u!jqymc zAa%~V%Y0NuAV}pWH?6tfteR;^+#`+80tYAfNw7Q1KJK0HDdHM064`zX{HVIg4f?& zI6X~S{s@)Kn(^EbWoW@h&Kj<*Ifei-K<$U!`?$VZVtMK&$mO~aY`bV-=beu;@t;hN z-voK~@5020dQHl3`X+VDtH1*gUg(hY$Ib1%_#Fj&)<)q_D2<{UGDfquOPUpiGPv_~ z^}`Gj&<{)lwxs?e-?w3SpJ5Xbr?CaL!3a^X3X`p{% zvAq`9z`H{88ooHHR$C#T^neMHPxcTfF%tRcM3kzgakjBqQp6tcPn53`Au*+Cdf>fB z#E!Enr$M`wh}OK;$-{|W6*p5@(i#U0cv#^8kA#c{Xi-yhM-}ZomV_3 z@ejwm7ZZ^GZyI#>rufwOb$DQq%wD?31o<}8sd2U|*f~x|f;ODrl!$_r;lB!}fC&K} zIPMEvYO}t?ztHRdn{(s85Z6{fW_?{0AMEXUXrN^{K-rPc+E5K;2i(S z<$(qCMF5z|qk9t7zW)jvh_(W}<`P)UT-mO+_e|!u7?kmOn z|49=W@VA!13?k++@!t%azp?Ll;O}5JbAYiP|L>wNLhIXdMaW(g@VRqm%Ew;)t0v$D zCq~G`#3VSqpt1+>e+4s8Q}Ei&|Cl+iO^Vip&+g96>CX zHHTcLbE5R2>DqtGvVrj0#+-7tNiIrU zaNCvnA{k(z+zqo;yhib=8xZHqhTw3J z#s{c<92mZB-~My0K#F|zhkgOlAcTN`0C@2O z7>V9jP?MDkqeT#30^N-70v zb#S5EI1qppg*~yb*%u263yvv|baEv3x>3{*|92y7b%a=@g@g5pXA>A7A16Cg{@ocH zGN!r0kJL=2dWnt50AV>dYZMenxz*qZPWSJQ#UFtbC@=jbP}`_5SVsqJ?ToH$5iN>*&`U;f-2 zHNZ!eM^#7F$#`N#$4rk|kp@DXE&MZgkEw4e6$u}&KL?>VJwKD{ zJp4N~o)C{dz>0f>zE%4lT?s)Tw0M0bCjK1K^JgHm_`1D{{zKgPJG6*^&?0EhHvV@= zgkUd(Kxh$cv?~4?TDO2EdI{p%_@_TZ%LCYLufnah|Hqog70_9q39vFw`eSQpfbm3oQU-^OwRqg%fkOF`&a)XY~`DdbmdHsLSboxGsF#kJ8UfP66 zhGB{-~@hedFcAGG9MG4yvw>|11I0ErbAt^aqui z41N*8>B6`aB`xIlE8s?;)(~K3mRi+oLHR)GtW%MisXX*ko|0NICMf@lkkDKh*Mf4T zej=?}v!bT^GjdRvgVwT%;Yst`^P!rS{`|^MPN&Do*{W6j(`FX`SqA<-lF{tXX^DjPw{z@m-gE@}5YV*J96R&(RF=8Z#p{lzi z99DOMX1Auy#wPZ(h58?x+%INrt`s5y^>&emIQ~JK+v2^&8pK-R@udL-k%uKM=rAzW zHt2{@BtX0%iZmJ449k^R&}rNc)$m0M2B46!T=}Mm$tW$)28}l;DH%`vP8@z&jkW|b zco3G&l_&VL^>8KDh5o|u5(PqSMcA~zt`a}v;;KA(Zx@Hz0?`#k=3ZO{2;DzwuezzNhY#vDSBsR(d0}l7KHNL zr4-d*6H9p#yLr85e(@<_D20s4Fl^J|n3M?BW2nM~4N}r+=B+08z$@%Rc6C!9oEZ8K&XHy-xw0J6EZsv3%cSHd-dQ(uit~ZE3fh zt{Sy=jTv0MDFfQ5g6X2MIGb3UYAl%u3IRVdORtYr!bM)Wec27l{NXzZ3G=t*Cs0bE zdV{QLjS+RO!YqJOdm&zMAWa~yo^i2g(e(Rz8EMrGwvb@;x3bO8O%zY48IAL-P%a#s z)59CfSZZP{ER^d-*r*2chRtR7~$B|Xor(I zioPDXY^`*Q@vC1B<4vX_PFp_^H%|;qvt-}evzdsYQODFAT1WqPXK5w!N`*n;^k_b> z+!o)xzlwTjND9bQ^zK!-unz=xbTG4rxt`+KBX02{>0a4L<;tz7shxsM#3@qnnORjp zI(70|AdVhQ*1EfnPEEY`_Y{8BmRa=e`deUs#21i~;382`nNvOOR-mM~SC0kI!&{9;d-$f?pc&p{$< zwxw_US~B^e+{|zD`jChS79;3#p9%$=+G61scb8=It6&n*%0V$!o}RPT!$^q)3zk)U=kl(xzIg@Kn>ngHAR$kWxjacvD3(nWFcZ>c_LZt!A7 zBYw@uaf2sPoD7)#2R6y3ZG0I8Vph(Pm?TG^n2@gl6;zw+A!IeK916S?C!$6~ai|Jw zD7sq9t^tByM81fM?hK=p8%1tbnoyNHmTYq0@@w)O&kGEh`u7@^$gBB%ak)Z!+Ke7) zj@5EcB|=>CDCq1_8bt@_J9KDM*I~X((sa7S>PDbE$@D5w-AO1Wj;-29PV;IzlNDiq z^{JITr@?E=7SjhWN$nBeEKuw_c{yJ4pq@PPQW{vhBCEqKV@c zaOi`>=98iV?Y4Bq3TYNO0Y zB}(uNKWaQ*Kf%K|F5~gMw8=tQ1&91uO-cR`c>?Uh#WyF%0KH3o&@~6WI_&G`-DQv5 zq^A7woelS>7pWwwE0dX+&+!`TdF=o7%i*^|{%U%QPO)WoL@k$J?(2T-7j`xzTR={j z!+Mz=PbTjaCCF+KGa4B#K0CmGk)M>Z{o9SYk?0Vus`%6&9;MtY(YN^~EiZ_d80|bo zyUwHvY7*=G$dS0|VRrw_LCws+ZjBMl*?H+_eW8qFTRO`R*Ik5zVz}LzZ}*zcWhjkU z@7zmuXCvCY`J(p=2&yr!2BANPS}B7PzSIV-VSQSaYa{qCn>fY@yz4_H{*?yDZ=2&< z1pzIOZvq%E^c+hK`3B=Lt6eDHM|g9an&on<_4TkAvyiHW6DX)Q3&X$Cg~we)ov(*s zkz|atL^y808zSAw?-@~%J!=>*$n6bHjLKYhHiy}%Hwh^sWOEfFBvm4_#0lt2Nx|iC z{iO0+>FSx`m-3NP=!i?>>JjfK{(tW$o;T15_8<+FK?T#f`4`pXf^)wQJR!Ipe+Fzh z?n2C#aX-%glUG_v5-QP=_!Hz>#eVHp>QmF5sVrf?4z?}MPcQMKXg&3BXWqd2=K>}~ zxGEv5=DU3wLrBsZWcHbL^^pF*BYgt{0i1!$+PL=De|X?{hXSR72zd5}KScT3UR`xC zMN-}Vy_$Iu0=Wr}{@dZ>f0gw3KfY49yJZd2|GjPz_5ybl$T`o7hJVIHiWCamJ$$Su z=M4Y7{y{SV8`=Lqy#K4S=f=Gc+>ka`+d6oQ{kC7HyOqTYh|RfLr-rPYG%Jl!L|fG8 zFqq=(W$C%OxpM6@IWeANF7oTe8Z(KA%@}!0N55;}F3e4cbo@E-Cw=+m2pW^yG&qh= z!mg3=bY(MKePO(>UqcVuS}v7buA+UN)2sq3PMTTc={}c@SWVb?g^OXCrQlRQTDEM5 zGjL?O1O*45cj68J`9us7IFN>(A4=%qR}i%>Cq(?*5V7wli$}&X9Ga-EK%~-x;&XVB;IZPR*WNi zUx>-Pw$RaW&rJ-2%#OrhI;HD;I6w=QKJPUL^b&j{0G)3CSY09j?8^dR z#Tv|=(Ye!=%0OFfE(3pgJSP-}FBLUq%I4(!egG&PgMvI=l(OTgsrSBf+8Y&|^sl|+ zaI$GETq+fEG;TV_1^~$N&-N=;O&;nRDLqoRLdCd?A^?F}^XG!;w0R8QvnpAxOtx6a zwp5l(Npb(c>ReM#m&W`7tNO3T792Kn;FP1>lX)^Z3*{-2?n`IF|)6gnc%3mMz6{ayM zL`yi^#hED3xWH{xl(j&yfF&}zWZ;T%lY`bjm1@a&S#dk<$GF~Ijo8Tc zu$HSk1%wwM1-rY|OC*kG8_b8^)mx|^s8%)dTV`@w0CBrO#`0TXT&B{bfI>HH{55FWgL3l0cz%(c*@`gikY)3W0zopnQ(S#UEx)t+ z;%E0qgCqx|){w)XBYX_U7^h%Md3`K#aJ#3U-wTJT0H@WC{Z*PMYS#(oC}QSVB&&ob+(s@IXoU zyZ7HoDHiZ@b9bnZ}ee#_95Isf6oEMm*J_f32CkipKe8`HH90~y&>t%!M} zt2P52LT)CQv|reH)Yc(luW<@)`2G9d!Scwyv!dG4;SOcb=?p6Q zK80?rVs>`!fYQbbg>k=aVFw!Ty|5ycjA73;-Ij8{wbRXpwRiOb#q4s$j_0RJUzXZ^ zkKg+g#XT#oY_b42Bj56U^NVp3prat$|0OQYAAWzA+GM8i_q>W!dAW_Sa#-B7qUzwrUzV{1Hl8-R?XB}bumTRL z2uvL^;^J?f$kf>Q3%~f4NI=T3fPGof0&B8BP0g7m{4m8yBFm|w`>sD;QFFmC9mL-s z8xjk2>!@&WG6mm7g^?Y&eZZfs$+c6`fd&O%g`xB+A?%Z2{2mSUhc_7zNq46anbdny zpMv6Eewk@vlSt)c$ySRGJHO0(=}odv-W*TUxR`>84E<2Tohf>JUjm!&(NT<-)znY< zvad$)+X;D~N~x;CS@-543e85RL2+E($>>afm{i7m#bKffyu_{|2j0H$j1?_CzUuHVOYy7SGCtHnN7kl4euiOe%olyOCGV4Vwgy>Hz;1K57 zjLmLV1`5tqt4FgL_Ff?s6yI0N_?-{)XU@@Nq@`ouqxJ7_ZTAgFl8DLG$u&|4srUn` z&2OM_6?EQ-+Q%w?g25kZi7OhTK_aXqDi+|N14RZMY){13!U;550fV-8UxFi_ zQg}aWuY%9ReuzR~(p8Av{-kkGSQv`rqgC9g-&Yllj{z$nsb*rKx?Q5`<5H9+p8C7* z-PX;JHh@c7D+6?AEJN->kp2$>&uh`wmA{c72&H@&AB`K~uttrstO>mJp2eT&9eB>LihTkOjAu(sb9?-nc{ z?GQO=Kc(?9bk|3%51wX}m8D08qEuYi*YDD$$JMZzZ+<28bELAk!P8*X{nn}8P7WcG z*D>D-d!K$a`^9CX*x$B6SqPkJ{cxzQ4%Y%WPi~|5+X_M%Okv+F%;bHA;EqdjbBOXi ztCUW!`s(xzp||AQcdjD?H5O~#i?~$hBFWC#r_+lMPHuxe_mQa+(X?0zjn#@g;3=QX ztHZoP!h)hSO~^k2_i=tJBu~-bvQ5E~$sAfi!w~j7b3_$804{%jX4*O{Fum&vrmPAm zRLQMDefyMK`Sae4k9B@|+An^okGN-BYtVWZ{bq;Z{+kSK!%yS4sc3Ev z^xeS<2b&4+2TI9h%+*F17qGCfoKabsD$1vZ+Fhf!POo;yzEEk9duPBS?41(A+`g6w z{PaUu9Fsp4=YE%Am?|^^gjq6Yw zHM8=>!U7CqVePOElbSUu{zW`J+VOdSdmIhoX-&W0(|QGo84+yWjO6}+%bwR#rG!aW4rOKH^GW?2n4MC~cITaW*00Whr`yxb`t%M+0% zyy^J@PUgq2D;F%E{~?zTAaUzkR=u=ld`X`t;Bl_}*w`kKslZ9xzU4Qp3Qu48p;3|e zRf>#~7A%m%&>N!~P}kbSI+9Fcv+%!+_NlGe-D zr1hDO|IHuIZh>b{W}%LUvqXURdi3F;SxFTw8JW<6q@?6!k`!ite?Q9X;Ly<3Zw>5M z?10xg3cJH$0x1PW!zUk8lIP&$*Grp7IR2AJv7cJCnf1cR`gQnDH2=@nrb|VndbxfO z_vNTyRAS;@Rou}^i`IgqsOV|%kYE5ppLxv^Ibc5?2{;jo0R}{yfW2I7XlSUwf>w=1 z>S}lpa5lL>yt)knrscVZa}_-1X1tC?brdfXJ`jEqaey9dk)w--2|rg71V2RIye-EhnA zRZs(Voj>250Hu_zewvcWE4zbfDJ?U=cuLI)@JuA5r5!Z9n)nD@3T(k^rwI$E2Y^ z?rV7TfO!^o>gs~qT>3#x#lxw`w^R=Lp_aos_2LzYg5fBE+z>^s0abgTK{ zct8meUn;Tuj)|5F@E47ZBoPt!frQ_TQ?rN!>>m4~4(`ag-!U{@Mpc?GC<1d!0T|mg zH-A;7TaC=ihs9q)=-N(78U_txzXrmNC&9s=K%YXFp(tRz=~bXxUt)z&9jhC9d$ z)ShV>UHT(}SRL^+c;pc<&#sz5vd*t{U&F*tTnM0Dvke&`K9@xx9^f7im~FR5C_$Rf zf#Z%_4to%3Kq{^ROc0-H98WayzJ=Tmxk6Wh8JybnR}NGno0pRhN+~xu6cw#(bNVxt z!lO^?o6YyYZE!=&U%EZrU(J8k<{6nd%FCn7m(BDqVzT3t*yog)s$KBQap8TX{7;T`!yij`efHJs7=!6KPgU z=~t18??d{735@5L6EX|UqV$cY0$xz>!11+`L~q-1`P>`f@VRHNG0}AKuZvrro!!dZ z*Mlf7<5BjXH^TWyiHQY@>$b6vGCbqK7wA+gN3XXB6EpQ9&iuR`v~7QFtReoE0d z0!W&gu4%e@diG!>X{Sa6I*6i3W+3h`u?i$<%Ji6+EFtVK#O*|1zk!}^&=ws@@F!>Si{>Qq1Hl@b!_2?(aRn{em}i`c3(keppg5*Fm@nKD#`{PpjsqIiDHmP zXW$mI8Hre-@~tI9C%dnM4vK~F$IqBgzJghRTj*Uk;*8DaXMK{kx8Yv{+N*0mn(L~d zKtq6EUfx@Mc(^$MxShAeZ9?$T7^hv}CyHB;F1dy(8Yn`6FW z93tXzPLhKnjn^H1#Di%ff&#|UiZvSg;n@~{`kezufC1p&JfC*8QZ=J#y3iF*B=BLC zhe-#edawfLcD)OOu3v>=73uc1!Zi%Ddht#N3qNfo9&9XNqx->>R#{K;$EvLz9NRpS z|LJLah!F(CA^%s$d4r5F%zXhLSJV zVLERZtaVV?lYMdCmA+~CHQUavJ81RROCL|E5)cyBp(Q6;?DWk~(0dJ}UKzrdDMk6V1Y~z`alhmn`FL_ZD`u{pxO=V;!{61g(;oZta;@-e7%Qifm?L4xpc!8EzIPc zl5O0I@aAOm=$$?qi;snDSktyvxHC%Z@2#4Aa|wo_T~87Y3ahwZxm%bMF3T%#L2w3A z#m&&6+OCghJqA<172Z8NUmqH?YyqfFc~d4nMX(bHZWPh)iltNm*F+YD4oCC%NPulz zA#x*oUoiWAGP1$XoQcIT=eJg+<9hjdREiPmU*$G&E` zPE0x3FX@@}t7F1=*K63I#ghVkEewlGJThBb?Q=NTjuBjjVH!}otj-ZbW9woAPS5M@KJVF;Y&fz-ZWtG3}ISz>`D zT`Yr=Q61I~rf<0;MW?OE+et(Okf7Hk?n^;t)N z_HaOzV*Z!L_m$-bbB{Fp6%8ClbZxjb()bFcCfnFj*Vzt4K3Zib9l#gwJ_T?V{+6zb7E^4N(D)7(eK*M7?csWA?S1Jh z`Bp8VO)s1$M@b3DRWwoqp`{tv_CBIH+!XzCW<(LQ~pRppoRbOa*RqtLY@3 zxgP_ux(LX>f7bpCTC?VaC_1wda21GH??#_tFFf_^Iq^ewFLs6*3#le-90(MT>9Nt6 zc5}gDM?`>n)R}?;h4P4f&xX2$nPG=E_eEwGH$t^|uZ@$TdMl`QB*=)H8lqRLxK4%9 zSiQZM~4tQmbzlay%$V)L*K5< z2UrJ^WCFvVj?A^45cDFivRGSZC_Lb)&4=xi z$71lcrHWoM?H2H9zjSUv>LdRgqZY^lEL`guOyYi0%;QpZrv!>|>yv#`MT0AgLy znx|}8U$2kJ7gC$fS_x)`L_HuyBP1m?y4KnpFj4;DV+(CEkPRA%;D(r*s4Y$s^pe=(6d|{i#kQSi}JfUiVd+&Uv z_b9abY#BESP-to8lX&AjtWnP3Qwp^aYiCEl{;kaHm&&gJSuEU+MsSeaS%4{caV}CU zhD{ zj|b7y{Rbwaz$vU@@i?D7qc5g#sD&(w`z<)eOW*%t@2!Kf?4oyJDFKld5RncAq@`23 z5s)qc0i{E_rCX(?lo09e=b<}9x=Xsd>+I+CRe67N=9@F$neV@EhG7`sx%a-;UVE># zu63=oBOi6uY}e+HPRtQZfECiM_*wP%aQ7iB=ELmcM*TPEwhT58mBUWycA2JtFGLs|qA;l-(;@auP{ zyCIF`n0lrsEO)NR#PmCg_)stG5O)weWQXks?*#H#=@jg|LZPTgPfvA;m65(4mB)EZ zi&*(eLyC~L{11Hv1n-~Q!S)Ra4S)1EUfX#uGC;3LGP6a4U z&ktgvJ{a)+4WzvggJr!^E816_ZZcDaqyQaVOG!L<^KS?bEG;Vt(kRmAgZ{?SLI9ls zndkr0iCz#IV2ZB+1cL8z3kB>cARPnQa*Cj401)TX1L z!yTRb|G9U{3!L^R0)Jl;qzjzDyTb`KZ;;(UO>T)X&D@~U3c26R6pyVYaBie_B;k5b&}9q*D-^dzu5INXW&gPb8U1KASz5aHlZ#2#+t%RE#f=@pF4kFwO6 zkZC!&gM*L1^s_tF#D49E=BKCGOjVuD1(7CFY2x-7ElAG7d2UsssYHwm@gTdWav2(V zcDQzLulrrg^7m^IC8h8QQLBo4;*2+u{z@6PyUlMKK0PF*&8#f57?AZyJV^*mU9rC# zB=PU!kktcCt0tVa)Ztyh*-;ffD7P5U1`WKkBFJU+ryB)dP5I~He1!z%X+HfxGR24! zXq4`Lj@kK6OvY&YstKg^*{jkeOtMtVioe?(6&US*Ky%xv*uZu|iN<){6BZ4xqA&gNVM=jl71X!n~AGC)n0^~lY@$aj+9%UUp zHGeL_xIQ3fU}$jXDK#&>42St7&E?qws>eMp`?aX<#1eIIX%zLY^j*iT(cvZbq`DOa zZd)oT)4^|aGFR&P`>t8F!v$(uUoSZn9Ja>k$FlRb-Ji-^K6I&~qKD&iUxJ4=JB@K-JG* zf4eMdG$J@SN@;GcKUIU0HciwrICxb|%dWVjImx2=r@Yb^tjB7~hi{H1XN>wjE>^oI zRBXJr@{D`3i}y3#V%@mdpyxK>^^|Cm$u*{-FX(tma{grNuinD}(pCsp`%W<|t$MIA zt;k3^DxuY(h+6_KZldu)K8V4~;gFP94G(piRb>$7bu^`Cf?R~>>Qrd7?3U9h<;f9^ z#42IW6-ztYuG2EDWwR%wzl}%PMCUMgaCo=M#j895>u%}pnHh4&p31ttD@oBoWc&rWQTa1Tm!ylKE-Jbva*}2L=%>C&x5r;*|rwWU<#KYG_^5u7bbC3ap3JGS& zF!uYJ4bNof(Ocx9)$C<$Y=&mv9&g4huszaaU z*ZySH$l^;Nus1hE%M>EQQhJF~PVPc}fED9)FlcABsk~xt(a)i^-C>~H4ei;!gb(k-}m29)P5BW?>yBtF-BTz$3 zgqug>9UYrDfm@16uLP$mkm1Vp)YPINZE6j(gO--#ylqfP zNAk5o*qREJelKVabShzSI{H{8dsge#9EzmL_jEIIE%JQGbU+-Zb0M)F`8F4;LXtq< zIf{OGM!S3xAA`+e=i0vZ<$iN{&r&*z2V3~H zpPh~n()rH5cRQZHr-Q4?@K|10n;w!qbNy6qR;oPZKBtHrhgOAt$yEZoRgtA(WpJjL zE0!gTL>YGS%*?em4b#;OukFHXCGVvu`h*JU=Dy}vNoo}i=&0zJ(c7NMbgqNr(2y4> zZOQz|2hIF;tmYBdS88}UHEJ{$%u=M5{pqzH3^^ObDl9FtzV>!`9k>(2d&8S-tAs8U zZ$*8>>HU`{G+50jQhM>26U+SC{@CE}g5K{eYxigTakS?79Wf#m1g~`k&JMJu0;=sz z+bt^Y_DzI67>vwe+@@DH=^jYdXr9&;eDxUvt)2(kBBjGq78zecAVq*zXO=QvW=b<( zoAeEdG3H^7;fZ~<aD} zt!iX*Yj&CIhmq4%2V1G*@8xS<(Ge=s(@)EUn?`s@=>@&ulqwiEjU*aLdRB|D9ml_W zBah%tm=H7-CYf-Y9j|^-^LILjGTEE6(QI$3(7zz_^Iw?i^-DZN-yVfp(sXvETqa+!6HT{RNShgb|EWG4 z2HL$nGQNDzoFN=>e$GaGiG;+DbWC+ewUYuDn$$0dP<`#weKKmEXHev{7;8HO?|$yGM_Mzp2Xu3+jr9FfJRC($=LYPhmnl2R)^8`H>|RYQ zRJrimuaz#DSwy;@_O@MqgN(N=WVLOT_5Kw2J$El6_#i1-(4Zypip25IeZ4hwU;`ll z$KBNPV5Lv#IcN@!!Ip>}_}pM5ezt{s8V7=PuE2Nfj}KAz9O-*d^9{4HKYmusgl<*;*JeqFF3bZi#ZbHI0@kk*fsY1_-H^tph=iej4S^x#{U1lr`ba_7MXA93K zc6&Z-4Bf#sQ@`6*U+=^W5o(XwKMK}KauwK{9c%r=)&+@hoR>}_JK_AUH*PY1CITow zoFe>tL26S`FaNp3ZQ&8~Qkcme>Fh6BZM~p8C^zyUck=8;BZ)G=hPk;|&LEsM_~pXy zh=4@qPSZ2}$iF!}FGPq8_)rbso8Q-c!~RzPPwCLy=R&EQzWFqao34{w`ln177Ei!R zhc2z3k5b)qs<&Y^N{kAce+q%Y1igKb*iS zu>>F9;{Zs`pNOHp1`Gu4iX8s?D^Q~ZtHdJ3xRdZdYSKV8;i8n;&AEGkpy8O5Bx-U} zTS`g_RIp%l04VNiZg@e(b7Pc6N?!ixjTQz8-(!%*J9^oHR5g(}BpbF5Gva#;(7 z)I4A}mE0UJLwf-~hYWY0kdSt6ZVrc-Sm$#n6J{cpjc`IlSlCbj)*MJvegGV(RRC*^ z4^L@5{%yAk@l1hLoy904ae8JQAiw&U#?rrq6LBvA_` zrH@fedb*62v+$&)_0SG}*P|6-kYyYx!1^-Unp2^ysv2WHTKEiPNG;gV8H0j?`g1kd zKn@^ulM9w&`}eCp0rCFytlTGjt(~|nkiB!Yo@4QQWPg6N`7tumklv3KFh6*D9e!YP zbjC2OM{Cbhv0o# z;dozPMDO>a{DG(fZYPBpc+5s*PZVhYW!H2lJ43IJ@nIXwV34}zg+9@y(7RHM!LalV%XYdg8G59j6VpZs(2*sq0gdj@tj>2p6Jzu0@pYG&_N z{OWx_``!0P@vR`3L)>woNaD6@bqVgWXs&PEM}tGd+yqG^BzmU%3XJAWIlPXA9HiDRQ|XR>ti%47Q|Ai*Q95? zH+D=dto9J0THU*$kM8bHltBi(RYqkc7lTt6{|3=^j>gs9pTktL^7I?N+=j@)<5Z&! z0*D-ZkR1ccDpSn8KF`2|!NC{LP>^wG${U&{KR-hN#F~a1%!XMp*ttW|y>F5IB1`Es zyZNID4PgXJWecdrvQriBX<4l~5mJ_|=hIEqm`6M+ zldY!wNABaUh92K{#@b(@H*k&r&m+I{V;-xZmufwR4|Mf=58e%{K5oY!K*n+J;T7(t zKKU82Yi1=G_vE%sP&5(qo1Tjk#PBAB5J4xMO|e`JqsHpy`;g*5VsQwwFdg5aaGGxO zK1fClJ79=%L;CEiz@6VsoveS3GBL1LTB6p|d_5@74RLd*W;4BtUfjold{#fb^{$8+ zRT#L(Pr^?8p0^Ym(&(%BM@8Lh=!F+?GvL=h_lnFsLyY@Qe~;e+vvXei zNx|&|tg*Nstv7X$1`K1?*ivZ4O(;8^EAT4&etkC9~rQto4s$8&Z634hCuwmqfTJhbx#P zGb0hWdE@lPdCUP8#(**%5QP4Ic>?5beVelR=%xd4F9Be9McDm+&JOT{R~>lE!((iN z|I~~J%K;=GAbN#!X9n(-`P#P`Gx>KwRV@-pS0QvzF#`nBdHM$gCQL67;D!LQT zYp6(NqCbJYbc+bCGN-miMq|Z8#n(Tu2{~RB=9|r2`G9KzmBwnW3qgxcImXpK4bZeQ zcfS_EU2E#U;I8fIM|qmMWc-X<&&>-;qmh1J84Z^Db2|1*Su1Su+%crEbYW0b{h?4I z1?q4~L&)io8Wk3Vzd-(QE>_QE1(GHaxsVjm+95#wd;-*YoMSwU;cWAuBP5Lfm}=mH z3!tlqi_ZiAY6rRAbqac{BJFYrk;I952?(XT)Z9uz2e_Q7K8C#RerKImWx{e?qebhi?y}0 zvzKL#c_b2u(5Z#{)6?p{i=Vc$v*1{fU94<8hl0TAhL-bubX#6adTKV>7mQY2dHL|< z*8wiF!W%_W%jMnJH{1@P9iSow0fylnW@aN6AEgG2yJ|=yB3I%bc(!RIz4J49yT1g z0E$GY?M>BUf9yO*EkjXH^opAUWxb~wEq9xy9R=n4918Csf_&YdbIi*Suw8hTlxA08 z7-yS7SF7YiOwTK!y5x61;M4!%TL*U}?aWg#SYulO~H( zP&*9q01<_1N{Hu9H;1XZTHc73UhSoRv4Aceg|?+q@=W25b&?e*(>AeMl?LQ*;fbbT zbegf%S9Wm)e@{fLQbgfF!#!=QV-lLVMZSN?&GyjS7K&@-fZXiiDaA8Lwizla!F$yg z4Dye>J#6kmCryN9GzDx#UmxnS^fA!U^}7U4{C(oA{ckwHVMU|qF;u0`TO>%JOwi@v zwZ4;2g}BU^H|KD)x_z|CCv1>B==Y}$P`jf`kN&%{0_>2t13L13j2RRh{5jFdgg|6< zyIrW5=H5ayl=spEt4U1{KYMSm zeGxB$gjV}AsLRbYKoEGCXycXBa`Ie&c`4p_($pE!Ni z%pj^}DX}y2cIy5zz=%|EtsvJjoZEeOb1q}n9wB(_naHgaB)&tTO3dG?{7(keQhW`N zO_lPsxj8dH?y*7aRtjo!1>3)N{GWvAx^X)5n=lrLB^e9v3d$^718UMU&W#PgLIqja z*Fdz?E+?Z-H)slV+{01C;H*>z5i|_~-MgA|%e?4pPy40U;iERrq zyJae*#023!>f9|UnNiEvrtOMhI7ilOr2A{7$+*BkXV!^&PIE|aeth=U?Viy@$3OPm zC~8CO`a%x)#!?<XgXHY!N;dtHQRSoy2i`Q7Uu#;W57*loq*o_mA`@c z{f7_a2)FOH6Wn1jXhtDqGY;*!TIh&eoOazV+qCmRybGt6>M-9L_VvErzi&ZC26J;> zt9za<5>(Ck6Qw(DPs1p;V?~Am66~8}B@+Iaq>La9xi_q3^=1wLx{~pLGA1f2D%lc@ zXOYSY2;5)gljvsL_QODvq}S(Y_)p${VmEVnL4byY3AdkYP36|ZqD~E4+v2B5Eu{wBi>onT`nogVHHKwtHt!CNv!Xax~z~hysJC;iRSJRLBjtE z=(US0sDA5*INM#0@{p51Lz_9>UzS<^p2VLW;`c7(mgwd*)OFvFTWIH}Iv}CGL%Z$z zt1=twEm&xG<^`;LNkFvgC()HPc0J#$C_5h30Zib$0SZE0oyh99s}%IAxj*L6iFw|> zrF=G;6&LS-31XoO7evUr-gFM zDLTOaj)DlT1oF`8`*WJV;P_*(}uXqC4|(JH@v-TdQ=h{ZCPyIgA+QD)NvvUlX#4>-)f zZGt-uI#k1nsAfZNCEtI(!;{wZZ(!yP>yFfw7QEQuf0t0Ho{r`-IfHiPj~D_R9Ho~; z$rB2KmoH!x)!0X_SEtK|dqx$Lwjp`u0JA#eXfBY#>XO{K$M(VN5hB)f{qIn+L6}Um z<@1tDO$l=lbtwj^T+EsZy~_jy)`Ng)+x}eDrv}GC8f=8TfbSDWV3SkP(1_>$Jb|cu z50cmrQlga?77=kzmBDx@eURmz8{86P?r|X>8Wwgq zKV01{ve1}Z!isscOR85nwClLO5s>P_HN(Eq6y0wxU5S7870B3HBPDLebn|I@$7%I3Z@ zHj=WnEl&8@P2)XF=G6-?fO}%j{P*Oow|C*cpLKHLBqc5V@!;Ssty+GfsJOU`HGar@ zp_kY~k_dbdEXaxM-;cmRf`-?A0kI$HRI)n(47UIy$X~cvKLDQ)!WO#AB>aG`+4Wit zAK}hDUXg!fGYboq(O8~1C3Zr{s^JL_^2IB+~mO+fCWJNdV1qG=FoWVS{8n%r=~L2o?Tq`v3;4h4qf(EiaY5v0Pwu5Z1jS z8~sldH3Ql(9TID4{%!66Fl}70upX>f=Krzp+pvMc8E*7n19L|OTS|}+h2vMppI_by zXy*pbrnZ=vzlH^1+Q7LeNV$uc@E_-b7YtNuDAV;r^ko33lnoC87N4S1)_kCRZ^#wcW|(=u|=WAYQIL!1#`%I`p{fthh(%) z;paTP^dg-Kanvk1u&bVrtbd-^Typ2@rqTEn)M4WP3f%=L0DYbFoMC**m31`p{<4?w!~;W*`c z1&i|q01CL1ojhb<5PxI z+$Ck)UuJq=wZGJrQ*f2CF7O4fIVB3+1++kNCw@5QcyN~Oh1K$EQ5t{Qnm?AKH1$rPnRPnoM- zC2d(ZAKv(h&fzpUR+}P2+OMks_YwXC{=d)JQ!DxG$zu0wz(Om#iixs~EKl64VY;V6;aBM^Pe#H42ebvvshW=+k!vUlu zppDkX$Z5rlLr!-Ruf#Iu%8VXxZN8Es8M*=}*!ECGt%KNck`WyIkzYo19!Z2hEE-GN zov^a)opLlwaAKeSc|7B(FztTKKP504&y(@_v%?FfyG^Zz5#fUziUpTdE6enq^PwK8 z7Nj0K-mi>|#>W>-5!{7l8g6a698Wn?@$zb=u)3c;b)LOCH-bFC9KHG((tBvbhf%jZ z?RvmXN$M>69OL0`pa-nvCVa?@%Wg@wr@0itBJmqyOwn%he1sY1r3_P8KgWkUr#=d0 z?TY0A1;IZ1&tZl$9urH^qFlGadlGonB8muQ=64;N2Zu%{=*rBWydarAJ0y|>=Ey=q zCoJgA0IBDNzS)4Xf&gvJ_gbbTD8UwFALI1$xTTz@9&bKOK>uPSS0j=M(-0wiMX>W? zSNdZw`C&4BpC>2TPOAJ40lSS0TMaV0BZ=X3CP=WZV_k!+>1>{(W(AiilXlxscis95Qg zV)>nBy$&`f6c}rAQ<__21~?|l%`(@Euk2nhiCzHrl~F^w8M52D-d}E^<-AcOfh3HB z`g2bYQ-G{1=8{3-vA#X@&iTn+SHVKq$V}lUhf4I_bbk6B-NI<8qbGuTw zY?MMg1HXKT5TKi?wg)7m@^<2i85)+NqP-<8E9o9hcBDpvwh#RSy{~Cht zncv&$Kw_yKNSr+OXp5nj|2kLp(?O2*@HT4;o3eO>hfKCg4vpiKeI|)WR6y)uU5W=y zQ@~8NrTJDQDsFA`$j~Ucej*EFnmF_^=UpNiO#TBVjlFZyahg417JK$1t~LSCG%xe* ziuLz|ZA)3%1aZEn!e?0?(2G5pVv(|4k0FO&C2;T9h z2i4@|T-t0L%7deP+0&RJ1$FWQ=i8nZjZR@^b(%i?SXrmc^ z=uEnl^5Pra)sfv*45IHozYNB5^exX1n~|s*YdWHQI*x87iUK*~NbEtM>QnuNK-R4(CFcwrF5ZJ-FB0EMey!qfT|H zmz-gfA{3VS9vyhv_$Jgz`D#%5Hg23r}$1C>DfdND44Olu31FdqMXxAYSF4HK`43c)+9i2b_ z{CG1udnmh0g4F#nsoTkyTGR$qyr1)BJ01r`o)c>>8qNnGKm6qwlaxCbGN-(FG_h^X z6_ejOZTzFyW?@JFO&`Q>vmLn2+TlU8C+(D&>qMv<6_x|y;F?I0n4DvyV-o(dk|N~IYk65)LC963m}fd|LPbqIcBEU#)a3qeI1C{DCD+;2%;Xoz zor~jlAg`Tr&q0aC%B4Q%-GQGiig+m0UTT=D%|S1!G@Z+m-H*7TR(ugV9`Oe~oOv+?OztbWDRog$VIXvmDGvAST^|d$h zftkyr>Hmx1Y#D!S#|9ItAsTX4@+u zX>as>V{8vZSnac2OtBTyXAyajH1uXc9_cZYN4j2`1<8Q&-P%XKKT3>5Nv1xu(DjK?<*_)=uVElMs>W z>{Y9d7F{S?hwH;;t}7Drt#WT=&7`G4<#_d>xtj&_>~KGb>fB}I+xz!TYkilEej#rk zKHV#V#L~}A7putN9iM*)_N$f1&S6H(EoHe%urmKj*(JKR38kxjkSv$(?s~jBl6sL- zaOO2A;)fVlsX1Bt61Ds!c-OQg+^(oGe?u$Yh4n~POJykSdT`Kg{b3CeuHBY+S-K9e zVTX*uW>{Tr*9gZ6=9$|_eB`e)EIWtuHPV_Stl@2o6mR^8!m>Wj1SoDlpkmv94Sm*h+ePeFpn8sDk4h$1T5#JM z)(>8XjUUs7xw2l1pWm+yX61>|G@_Cz5mTSLxYEO+@9uB$Znp#7J{0B4Eo5G({&IGp zD(y>w2uEUzLKHY`68*zFpg`Dh?ya}zsaWcQ_i}q$tp1}qU=Z9@_qK9iL z8L@XTPh*1_pt*W8ZY^d*`FY1h`J4E7oM9dAz*|zRW%V0_#iz4U^#cn08R!07YifEb z^tJ~pTf6-ZN3v64Q1^4dn5GRRi?e0=CKXW`)O5Z*W|BO-UEp9!LGiKXxDm7k zNE2I&>WH*|vh4~gRGLh%e72;rGk*4gnlmQ6np&xXD{mD=ZR(O@QSHepYgDzx_+NQU ztVE!_P_C`OoII@p%P$O#Xu%zdfri=;rw=&yjTXBKYWqp1atdmt^Px+optH9sJq9Gh zVx|CpK0t!dnZR+ALfwCzjUBtk_x7xfAYXG+J}DhL1aEXOW3W}Q_nCMlwsk72|to zCHir7XKOkAUoD8HDz2n&QI;Qr`s5LJP9spA88OCY&k59gwD#m@i2Vi^U$^8|t0-tv zbai=R=%Pe9ZRi?ZagNI_kN0!mAa@E%0ILpnR?nOEGHPdrL+6yeBNt~wwMO|YEv9XjvRFCSSKpmXd(t1RO9d7+e>9{) zZ2W{Q9(Q0&s`Z9p{x#8Z5}&hh2&=@Y(;!Jc&AWJOq;uBqYb}&}pg#N&JfGDmt1rz< z_TWaU1MJY;BFOjeZJI?gFDhGlDkcr+BiLUTQH?|hUcKT)hsQ3eJLyAm#WtmX(T*Of ztog}gvy^i)Fe|61A{oX>TkSukIK2uWZSg2hOJixEl5Un}QWX?`hxMSD&&MZip~DsK zAwMCJ#L@2lfZ_+mQyP--*e3PE>h#Q7eG%=Nnga#TH&nDv6yhjT76m?zUEZ`5y^q z|9HSld=TMEfwL7uQ}(J+sEr1P` z9gEo%O9K#p&=vd^CX+zh3E#gN5X46y!seV0�Xi|ViYoZ*4fAou1UpoI<2L}v5U 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 Date: Mon, 1 Dec 2025 12:55:47 -0800 Subject: [PATCH 10/47] [Feat] WatsonX - allow passing zen_api_key dynamically (#16655) * test_watsonx_zen_api_key_from_client * zen api key * docs using zen api key --- .../docs/providers/watsonx/index.md | 53 ++++ litellm/llms/anthropic/skills/readme.md | 286 +++++++++++++++++- litellm/llms/watsonx/common_utils.py | 6 +- .../test_litellm/llms/watsonx/test_watsonx.py | 90 ++++++ 4 files changed, 422 insertions(+), 13 deletions(-) diff --git a/docs/my-website/docs/providers/watsonx/index.md b/docs/my-website/docs/providers/watsonx/index.md index 279d2d1024e..14e0c07c081 100644 --- a/docs/my-website/docs/providers/watsonx/index.md +++ b/docs/my-website/docs/providers/watsonx/index.md @@ -175,3 +175,56 @@ For all available models, see [watsonx.ai documentation](https://dataplatform.cl For all available embedding models, see [watsonx.ai embedding documentation](https://dataplatform.cloud.ibm.com/docs/content/wsj/analyze-data/fm-models-embed.html?context=wx). + +## Advanced + +### Using Zen API Key + +You can use a Zen API key for long-term authentication instead of generating IAM tokens. Pass it either as an environment variable or as a parameter: + +```python +import os +from litellm import completion + +# Option 1: Set as environment variable +os.environ["WATSONX_ZENAPIKEY"] = "your-zen-api-key" + +response = completion( + model="watsonx/ibm/granite-13b-chat-v2", + messages=[{"content": "What is your favorite color?", "role": "user"}], + project_id="your-project-id" +) + +# Option 2: Pass as parameter +response = completion( + model="watsonx/ibm/granite-13b-chat-v2", + messages=[{"content": "What is your favorite color?", "role": "user"}], + zen_api_key="your-zen-api-key", + project_id="your-project-id" +) +``` + +**Using with LiteLLM Proxy via OpenAI client:** + +```python +import openai + +client = openai.OpenAI( + api_key="sk-1234", # LiteLLM proxy key + base_url="http://0.0.0.0:4000" +) + +response = client.chat.completions.create( + model="watsonx/ibm/granite-3-3-8b-instruct", + messages=[{"role": "user", "content": "What is your favorite color?"}], + max_tokens=2048, + extra_body={ + "project_id": "your-project-id", + "zen_api_key": "your-zen-api-key" + } +) +``` + +See [IBM documentation](https://www.ibm.com/docs/en/watsonx/w-and-w/2.2.0?topic=keys-generating-zenapikey-authorization-tokens) for more information on generating Zen API keys. + + diff --git a/litellm/llms/anthropic/skills/readme.md b/litellm/llms/anthropic/skills/readme.md index 898639cd44b..0602272256c 100644 --- a/litellm/llms/anthropic/skills/readme.md +++ b/litellm/llms/anthropic/skills/readme.md @@ -1,17 +1,279 @@ -# Anthropic Skills API +# Anthropic Skills API Integration -This folder maintains the integration for the Anthropic Skills API. +This module provides comprehensive support for the Anthropic Skills API through LiteLLM. -You can do the following with the Anthropic Skills API: +## Features -1. Create a new skill -2. List all skills -3. Get a skill -4. Delete a skill +The Skills API allows you to: +- **Create skills**: Define reusable AI capabilities +- **List skills**: Browse all available skills +- **Get skills**: Retrieve detailed information about a specific skill +- **Delete skills**: Remove skills that are no longer needed +## Quick Start -Versions: - - Create Skill Version - - List Skill Versions - - Get Skill Version - - Delete Skill Version \ No newline at end of file +### Prerequisites + +Set your Anthropic API key: +```python +import os +os.environ["ANTHROPIC_API_KEY"] = "your-api-key-here" +``` + +### Basic Usage + +#### Create a Skill + +```python +import litellm + +# Create a skill with files +# Note: All files must be in the same top-level directory +# and must include a SKILL.md file at the root +skill = litellm.create_skill( + files=[ + # List of file objects to upload + # Must include SKILL.md + ], + display_title="Python Code Generator", + custom_llm_provider="anthropic" +) +print(f"Created skill: {skill.id}") + +# Asynchronous version +skill = await litellm.acreate_skill( + files=[...], # Your files here + display_title="Python Code Generator", + custom_llm_provider="anthropic" +) +``` + +#### List Skills + +```python +# List all skills +skills = litellm.list_skills( + custom_llm_provider="anthropic" +) + +for skill in skills.data: + print(f"{skill.display_title}: {skill.id}") + +# With pagination and filtering +skills = litellm.list_skills( + limit=20, + source="custom", # Filter by 'custom' or 'anthropic' + custom_llm_provider="anthropic" +) + +# Get next page if available +if skills.has_more: + next_page = litellm.list_skills( + page=skills.next_page, + custom_llm_provider="anthropic" + ) +``` + +#### Get a Skill + +```python +skill = litellm.get_skill( + skill_id="skill_abc123", + custom_llm_provider="anthropic" +) + +print(f"Skill: {skill.display_title}") +print(f"Created: {skill.created_at}") +print(f"Latest version: {skill.latest_version}") +print(f"Source: {skill.source}") +``` + +#### Delete a Skill + +```python +result = litellm.delete_skill( + skill_id="skill_abc123", + custom_llm_provider="anthropic" +) + +print(f"Deleted skill {result.id}, type: {result.type}") +``` + +## API Reference + +### `create_skill()` + +Create a new skill. + +**Parameters:** +- `files` (List[Any], optional): Files to upload for the skill. All files must be in the same top-level directory and must include a SKILL.md file at the root. +- `display_title` (str, optional): Display title for the skill +- `custom_llm_provider` (str, optional): Provider name (default: "anthropic") +- `extra_headers` (dict, optional): Additional HTTP headers +- `timeout` (float, optional): Request timeout + +**Returns:** +- `Skill`: The created skill object + +**Async version:** `acreate_skill()` + +### `list_skills()` + +List all skills. + +**Parameters:** +- `limit` (int, optional): Number of results to return per page (max 100, default 20) +- `page` (str, optional): Pagination token for fetching a specific page of results +- `source` (str, optional): Filter skills by source ('custom' or 'anthropic') +- `custom_llm_provider` (str, optional): Provider name (default: "anthropic") +- `extra_headers` (dict, optional): Additional HTTP headers +- `timeout` (float, optional): Request timeout + +**Returns:** +- `ListSkillsResponse`: Object containing a list of skills and pagination info + +**Async version:** `alist_skills()` + +### `get_skill()` + +Get a specific skill by ID. + +**Parameters:** +- `skill_id` (str, required): The skill ID +- `custom_llm_provider` (str, optional): Provider name (default: "anthropic") +- `extra_headers` (dict, optional): Additional HTTP headers +- `timeout` (float, optional): Request timeout + +**Returns:** +- `Skill`: The requested skill object + +**Async version:** `aget_skill()` + +### `delete_skill()` + +Delete a skill. + +**Parameters:** +- `skill_id` (str, required): The skill ID to delete +- `custom_llm_provider` (str, optional): Provider name (default: "anthropic") +- `extra_headers` (dict, optional): Additional HTTP headers +- `timeout` (float, optional): Request timeout + +**Returns:** +- `DeleteSkillResponse`: Object with `id` and `type` fields + +**Async version:** `adelete_skill()` + +## Response Types + +### `Skill` + +Represents a skill from the Anthropic Skills API. + +**Fields:** +- `id` (str): Unique identifier +- `created_at` (str): ISO 8601 timestamp +- `display_title` (str, optional): Display title +- `latest_version` (str, optional): Latest version identifier +- `source` (str): Source ("custom" or "anthropic") +- `type` (str): Object type (always "skill") +- `updated_at` (str): ISO 8601 timestamp + +### `ListSkillsResponse` + +Response from listing skills. + +**Fields:** +- `data` (List[Skill]): List of skills +- `next_page` (str, optional): Pagination token for the next page +- `has_more` (bool): Whether more skills are available + +### `DeleteSkillResponse` + +Response from deleting a skill. + +**Fields:** +- `id` (str): The deleted skill ID +- `type` (str): Deleted object type (always "skill_deleted") + +## Architecture + +The Skills API implementation follows LiteLLM's standard patterns: + +1. **Type Definitions** (`litellm/types/llms/anthropic_skills.py`) + - Pydantic models for request/response types + - TypedDict definitions for request parameters + +2. **Base Configuration** (`litellm/llms/base_llm/skills/transformation.py`) + - Abstract base class `BaseSkillsAPIConfig` + - Defines transformation interface for provider-specific implementations + +3. **Provider Implementation** (`litellm/llms/anthropic/skills/transformation.py`) + - `AnthropicSkillsConfig` - Anthropic-specific transformations + - Handles API authentication, URL construction, and response mapping + +4. **Main Handler** (`litellm/skills/main.py`) + - Public API functions (sync and async) + - Request validation and routing + - Error handling + +5. **HTTP Handlers** (`litellm/llms/custom_httpx/llm_http_handler.py`) + - Low-level HTTP request/response handling + - Connection pooling and retry logic + +## Beta API Support + +The Skills API is in beta. The beta header (`skills-2025-10-02`) is automatically added by the Anthropic provider configuration. You can customize it if needed: + +```python +skill = litellm.create_skill( + display_title="My Skill", + extra_headers={ + "anthropic-beta": "skills-2025-10-02" # Or any other beta version + }, + custom_llm_provider="anthropic" +) +``` + +The default beta version is configured in `litellm.constants.ANTHROPIC_SKILLS_API_BETA_VERSION`. + +## Error Handling + +All Skills API functions follow LiteLLM's standard error handling: + +```python +import litellm + +try: + skill = litellm.create_skill( + display_title="My Skill", + custom_llm_provider="anthropic" + ) +except litellm.exceptions.AuthenticationError as e: + print(f"Authentication failed: {e}") +except litellm.exceptions.RateLimitError as e: + print(f"Rate limit exceeded: {e}") +except litellm.exceptions.APIError as e: + print(f"API error: {e}") +``` + +## Contributing + +To add support for Skills API to a new provider: + +1. Create provider-specific configuration class inheriting from `BaseSkillsAPIConfig` +2. Implement all abstract methods for request/response transformations +3. Register the config in `ProviderConfigManager.get_provider_skills_api_config()` +4. Add appropriate tests + +## Related Documentation + +- [Anthropic Skills API Documentation](https://platform.claude.com/docs/en/api/beta/skills/create) +- [LiteLLM Responses API](../../../responses/) +- [Provider Configuration System](../../base_llm/) + +## Support + +For issues or questions: +- GitHub Issues: https://github.com/BerriAI/litellm/issues +- Discord: https://discord.gg/wuPM9dRgDw diff --git a/litellm/llms/watsonx/common_utils.py b/litellm/llms/watsonx/common_utils.py index 58b33097cbd..0207020534c 100644 --- a/litellm/llms/watsonx/common_utils.py +++ b/litellm/llms/watsonx/common_utils.py @@ -252,9 +252,13 @@ class IBMWatsonXMixin: Optional[str], optional_params.get("token") or get_secret_str("WATSONX_TOKEN"), ) + zen_api_key = cast( + Optional[str], + optional_params.pop("zen_api_key", None) or get_secret_str("WATSONX_ZENAPIKEY"), + ) if token: headers["Authorization"] = f"Bearer {token}" - elif zen_api_key := get_secret_str("WATSONX_ZENAPIKEY"): + elif zen_api_key: headers["Authorization"] = f"ZenApiKey {zen_api_key}" else: token = _generate_watsonx_token(api_key=api_key, token=token) diff --git a/tests/test_litellm/llms/watsonx/test_watsonx.py b/tests/test_litellm/llms/watsonx/test_watsonx.py index a41316bb47e..fc45a13c2c1 100644 --- a/tests/test_litellm/llms/watsonx/test_watsonx.py +++ b/tests/test_litellm/llms/watsonx/test_watsonx.py @@ -414,3 +414,93 @@ def test_watsonx_chat_completion_with_reasoning_effort(monkeypatch): assert ( json_data["reasoning_effort"] == "low" ), "The value of 'reasoning_effort' should be 'low'." + + +def test_watsonx_zen_api_key_from_client(monkeypatch, watsonx_chat_completion_call): + """ + Test that zen_api_key can be passed from client code and is used in Authorization header. + """ + monkeypatch.setenv("WATSONX_PROJECT_ID", "test-project-id") + monkeypatch.setenv("WATSONX_API_BASE", "https://test-api.watsonx.ai") + + model = "watsonx/ibm/granite-3-3-8b-instruct" + messages = [{"role": "user", "content": "What is your favorite color?"}] + + client = HTTPHandler() + + zen_api_key = "U1ZDLWQo=" + + # No need to patch token call since zen_api_key should skip token generation + with patch.object(client, "post") as mock_post: + try: + completion( + model=model, + messages=messages, + api_key="test_api_key", + client=client, + zen_api_key=zen_api_key, + ) + except Exception as e: + print(f"Caught expected exception: {e}") + + # Verify the request was made + assert mock_post.call_count == 1, "The completion endpoint should have been called once." + + # Get the headers sent in the POST request + request_kwargs = mock_post.call_args.kwargs + headers = request_kwargs["headers"] + + print("\nHeaders sent to WatsonX API:") + print(json.dumps(dict(headers), indent=2)) + + # Verify Authorization header uses ZenApiKey format + assert "Authorization" in headers, "Authorization header should be present." + assert headers["Authorization"] == f"ZenApiKey {zen_api_key}", ( + f"Authorization header should use ZenApiKey format. " + f"Expected: 'ZenApiKey {zen_api_key}', Got: '{headers['Authorization']}'" + ) + + +def test_watsonx_zen_api_key_from_env(monkeypatch, watsonx_chat_completion_call): + """ + Test that zen_api_key from environment variable is used in Authorization header. + """ + monkeypatch.setenv("WATSONX_PROJECT_ID", "test-project-id") + monkeypatch.setenv("WATSONX_API_BASE", "https://test-api.watsonx.ai") + + zen_api_key = "U1ZDLWxpdG--===" + monkeypatch.setenv("WATSONX_ZENAPIKEY", zen_api_key) + + model = "watsonx/ibm/granite-3-3-8b-instruct" + messages = [{"role": "user", "content": "What is your favorite color?"}] + + client = HTTPHandler() + + # No need to patch token call since zen_api_key should skip token generation + with patch.object(client, "post") as mock_post: + try: + completion( + model=model, + messages=messages, + api_key="test_api_key", + client=client, + ) + except Exception as e: + print(f"Caught expected exception: {e}") + + # Verify the request was made + assert mock_post.call_count == 1, "The completion endpoint should have been called once." + + # Get the headers sent in the POST request + request_kwargs = mock_post.call_args.kwargs + headers = request_kwargs["headers"] + + print("\nHeaders sent to WatsonX API:") + print(json.dumps(dict(headers), indent=2)) + + # Verify Authorization header uses ZenApiKey format + assert "Authorization" in headers, "Authorization header should be present." + assert headers["Authorization"] == f"ZenApiKey {zen_api_key}", ( + f"Authorization header should use ZenApiKey format. " + f"Expected: 'ZenApiKey {zen_api_key}', Got: '{headers['Authorization']}'" + ) From 24f847b84c947e13b765edaf172f646fd1b06297 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Mon, 1 Dec 2025 13:59:00 -0800 Subject: [PATCH 11/47] [Feat] JWT Auth - AI Gateway, allow using regular OIDC flow with user info endpoints (#17324) * feat: allow fetching OIDC user info * test: use test_auth_builder_with_oidc_userinfo_enabled gets user info when enabled * fix tool permission doc * docs fix diagram --- .../docs/proxy/guardrails/tool_permission.md | 5 - docs/my-website/docs/proxy/token_auth.md | 66 +++++ litellm/proxy/_types.py | 18 ++ litellm/proxy/auth/handle_jwt.py | 76 +++++- .../proxy/auth/test_handle_jwt.py | 227 +++++++++++++++++- 5 files changed, 385 insertions(+), 7 deletions(-) diff --git a/docs/my-website/docs/proxy/guardrails/tool_permission.md b/docs/my-website/docs/proxy/guardrails/tool_permission.md index 897c31d9dab..1827333654f 100644 --- a/docs/my-website/docs/proxy/guardrails/tool_permission.md +++ b/docs/my-website/docs/proxy/guardrails/tool_permission.md @@ -1,4 +1,3 @@ -import Image from '@theme/IdealImage'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -14,8 +13,6 @@ LiteLLM provides the LiteLLM Tool Permission Guardrail that lets you control whi Open the LiteLLM Dashboard, click **Add New Guardrail**, and choose **LiteLLM Tool Permission Guardrail**. This loads the rule builder UI. -Configure tool permission guardrail in LiteLLM UI - #### Step 2: Define Regex Rules 1. Click **Add Rule**. @@ -24,8 +21,6 @@ Open the LiteLLM Dashboard, click **Add New Guardrail**, and choose **LiteLLM To 4. Optionally add a regex for tool type (e.g., `^function$`). 5. Pick **Allow** or **Deny**. -Configure tool permission guardrail in LiteLLM UI - #### Step 3: Restrict Tool Arguments (Optional) Select **+ Restrict tool arguments** to attach regex validations to nested paths (dot + `[]` notation). This enforces that sensitive parameters (such as `arguments.to[]`) conform to pre-approved formats. diff --git a/docs/my-website/docs/proxy/token_auth.md b/docs/my-website/docs/proxy/token_auth.md index c2a88010d79..c465c1022e4 100644 --- a/docs/my-website/docs/proxy/token_auth.md +++ b/docs/my-website/docs/proxy/token_auth.md @@ -407,6 +407,72 @@ general_settings: user_id_upsert: true # 👈 upserts the user to db, if valid email but not in db ``` +## OIDC UserInfo Endpoint + +Use this when your JWT/access token doesn't contain user-identifying information. LiteLLM will call your identity provider's UserInfo endpoint to fetch user details. + +### When to Use + +- Your JWT is opaque (not self-contained) or lacks user claims +- You need to fetch fresh user information from your identity provider +- Your access tokens don't include email, roles, or other identifying data + +### Configuration + +```yaml title="config.yaml" showLineNumbers +general_settings: + enable_jwt_auth: True + litellm_jwtauth: + # Enable OIDC UserInfo endpoint + oidc_userinfo_enabled: true + oidc_userinfo_endpoint: "https://your-idp.com/oauth2/userinfo" + oidc_userinfo_cache_ttl: 300 # Cache for 5 minutes (default: 300) + + # Map fields from UserInfo response + user_id_jwt_field: "sub" + user_email_jwt_field: "email" + user_roles_jwt_field: "roles" +``` + +### Flow Diagram + +```mermaid +sequenceDiagram + participant Client + participant LiteLLM + participant IdP as Identity Provider + + Client->>LiteLLM: Request with Bearer token + Note over LiteLLM: Check cache for UserInfo + + LiteLLM->>IdP: GET /userinfo (if not cached)
Authorization: Bearer {token} + IdP-->>LiteLLM: User data (sub, email, roles) + + Note over LiteLLM: Cache response (TTL: 5min)
Extract user_id, email, roles
Perform RBAC checks + + LiteLLM-->>Client: Authorized/Denied +``` + +### Example: Azure AD + +```yaml title="config.yaml" showLineNumbers +litellm_jwtauth: + oidc_userinfo_enabled: true + oidc_userinfo_endpoint: "https://graph.microsoft.com/oidc/userinfo" + user_id_jwt_field: "sub" + user_email_jwt_field: "email" +``` + +### Example: Keycloak + +```yaml title="config.yaml" showLineNumbers +litellm_jwtauth: + oidc_userinfo_enabled: true + oidc_userinfo_endpoint: "https://keycloak.example.com/realms/your-realm/protocol/openid-connect/userinfo" + user_id_jwt_field: "sub" + user_roles_jwt_field: "resource_access.your-client.roles" +``` + ## [BETA] Control Access with OIDC Roles Allow JWT tokens with supported roles to access the proxy. diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index fe87a70b244..b5b0bd80602 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -3422,6 +3422,9 @@ class LiteLLM_JWTAuth(LiteLLMPydanticObjectBase): - public_allowed_routes: list of allowed routes for authenticated but unknown litellm role jwt tokens. - enforce_rbac: If true, enforce RBAC for all routes. - custom_validate: A custom function to validates the JWT token. + - oidc_userinfo_endpoint: OIDC UserInfo endpoint URL. When set along with oidc_userinfo_enabled, LiteLLM will call this endpoint with the access token to retrieve user identity information. + - oidc_userinfo_enabled: Enable fetching user info from OIDC UserInfo endpoint instead of just decoding JWT token. Default: False. + - oidc_userinfo_cache_ttl: TTL (in seconds) for caching UserInfo responses. Default: 300s (5 minutes). See `auth_checks.py` for the specific routes """ @@ -3472,6 +3475,21 @@ class LiteLLM_JWTAuth(LiteLLMPydanticObjectBase): jwt_litellm_role_map: Optional[List[JWTLiteLLMRoleMap]] = None sync_user_role_and_teams: bool = False ######################################################### + ######################################################### + # OIDC UserInfo Endpoint Configuration + oidc_userinfo_endpoint: Optional[str] = Field( + default=None, + description="OIDC UserInfo endpoint URL. If set, LiteLLM will call this endpoint with the access token to retrieve user identity information.", + ) + oidc_userinfo_enabled: bool = Field( + default=False, + description="Enable fetching user info from OIDC UserInfo endpoint instead of just decoding JWT token.", + ) + oidc_userinfo_cache_ttl: float = Field( + default=300, + description="TTL (in seconds) for caching UserInfo responses. Default: 300s (5 minutes).", + ) + ######################################################### def __init__(self, **kwargs: Any) -> None: # get the attribute names for this Pydantic model diff --git a/litellm/proxy/auth/handle_jwt.py b/litellm/proxy/auth/handle_jwt.py index 3e18db2d025..ed6877d1469 100644 --- a/litellm/proxy/auth/handle_jwt.py +++ b/litellm/proxy/auth/handle_jwt.py @@ -480,6 +480,71 @@ class JWTHandler: else: return False + async def get_oidc_userinfo(self, token: str) -> dict: + """ + Fetch user information from OIDC UserInfo endpoint. + + This follows the OpenID Connect protocol where an access token + is sent to the identity provider's UserInfo endpoint to retrieve + user identity information. + + Args: + token: The access token to use for authentication + + Returns: + dict: User information from the UserInfo endpoint + + Raises: + Exception: If UserInfo endpoint is not configured or request fails + """ + if not self.litellm_jwtauth.oidc_userinfo_endpoint: + raise Exception( + "OIDC UserInfo endpoint not configured. Set 'oidc_userinfo_endpoint' in JWT auth config." + ) + + # Check cache first + cache_key = f"oidc_userinfo_{token[:20]}" # Use first 20 chars of token as cache key + cached_userinfo = await self.user_api_key_cache.async_get_cache(cache_key) + + if cached_userinfo is not None: + verbose_proxy_logger.debug("Returning cached OIDC UserInfo") + return cached_userinfo + + verbose_proxy_logger.debug( + f"Calling OIDC UserInfo endpoint: {self.litellm_jwtauth.oidc_userinfo_endpoint}" + ) + + try: + # Call the UserInfo endpoint with the access token + response = await self.http_handler.get( + url=self.litellm_jwtauth.oidc_userinfo_endpoint, + headers={ + "Authorization": f"Bearer {token}", + "Accept": "application/json", + }, + ) + + if response.status_code != 200: + raise Exception( + f"OIDC UserInfo endpoint returned status {response.status_code}: {response.text}" + ) + + userinfo = response.json() + verbose_proxy_logger.debug(f"Received OIDC UserInfo: {userinfo}") + + # Cache the userinfo response + await self.user_api_key_cache.async_set_cache( + key=cache_key, + value=userinfo, + ttl=self.litellm_jwtauth.oidc_userinfo_cache_ttl, + ) + + return userinfo + + except Exception as e: + verbose_proxy_logger.error(f"Error fetching OIDC UserInfo: {str(e)}") + raise Exception(f"Failed to fetch OIDC UserInfo: {str(e)}") + async def auth_jwt(self, token: str) -> dict: # Supported algos: https://pyjwt.readthedocs.io/en/stable/algorithms.html # "Warning: Make sure not to mix symmetric and asymmetric algorithms that interpret @@ -1077,7 +1142,16 @@ class JWTAuthManager: proxy_logging_obj: ProxyLogging, ) -> JWTAuthBuilderResult: """Main authentication and authorization builder""" - jwt_valid_token: dict = await jwt_handler.auth_jwt(token=api_key) + # Check if OIDC UserInfo endpoint is enabled + if jwt_handler.litellm_jwtauth.oidc_userinfo_enabled: + verbose_proxy_logger.debug( + "OIDC UserInfo is enabled. Fetching user info from UserInfo endpoint." + ) + # Use the access token to fetch user info from OIDC UserInfo endpoint + jwt_valid_token: dict = await jwt_handler.get_oidc_userinfo(token=api_key) + else: + # Default behavior: decode and validate the JWT token + jwt_valid_token = await jwt_handler.auth_jwt(token=api_key) # Check custom validate if jwt_handler.litellm_jwtauth.custom_validate: diff --git a/tests/test_litellm/proxy/auth/test_handle_jwt.py b/tests/test_litellm/proxy/auth/test_handle_jwt.py index 8f8f3ced074..603a6928f88 100644 --- a/tests/test_litellm/proxy/auth/test_handle_jwt.py +++ b/tests/test_litellm/proxy/auth/test_handle_jwt.py @@ -846,4 +846,229 @@ async def test_auth_builder_returns_team_membership_object(): assert result["team_membership"].user_id == _user_id, "team_membership user_id should match" assert result["team_membership"].team_id == _team_id, "team_membership team_id should match" assert result["team_membership"].budget_id == "budget_123", "team_membership budget_id should match" - assert result["team_membership"].spend == 10.5, "team_membership spend should match" \ No newline at end of file + assert result["team_membership"].spend == 10.5, "team_membership spend should match" + + +@pytest.mark.asyncio +async def test_auth_builder_with_oidc_userinfo_enabled(): + """Test that auth_builder uses OIDC UserInfo endpoint when enabled""" + from unittest.mock import MagicMock + + from litellm.caching import DualCache + from litellm.proxy.utils import ProxyLogging + + # Setup test data + api_key = "test_access_token" + request_data = {"model": "gpt-4"} + general_settings = {"enforce_rbac": False} + route = "/chat/completions" + + user_object = LiteLLM_UserTable( + user_id="test_user_1", user_role=LitellmUserRoles.INTERNAL_USER + ) + + # Create JWT handler with OIDC UserInfo enabled + jwt_handler = JWTHandler() + user_api_key_cache = DualCache() + proxy_logging_obj = ProxyLogging(user_api_key_cache=user_api_key_cache) + + jwt_handler.update_environment( + prisma_client=None, + user_api_key_cache=user_api_key_cache, + litellm_jwtauth=LiteLLM_JWTAuth( + oidc_userinfo_enabled=True, + oidc_userinfo_endpoint="https://example.com/oauth2/userinfo", + user_id_jwt_field="sub", + user_email_jwt_field="email", + ), + ) + + # Mock OIDC UserInfo response + userinfo_response = { + "sub": "test_user_1", + "email": "test@example.com", + "scope": "", + } + + # Mock all the dependencies + with patch.object( + jwt_handler, "get_oidc_userinfo", new_callable=AsyncMock + ) as mock_get_userinfo, patch.object( + jwt_handler, "auth_jwt", new_callable=AsyncMock + ) as mock_auth_jwt, patch.object( + JWTAuthManager, "check_rbac_role", new_callable=AsyncMock + ) as mock_check_rbac, patch.object( + jwt_handler, "get_rbac_role", return_value=None + ) as mock_get_rbac, patch.object( + jwt_handler, "get_scopes", return_value=[] + ) as mock_get_scopes, patch.object( + jwt_handler, "get_object_id", return_value=None + ) as mock_get_object_id, patch.object( + JWTAuthManager, + "get_user_info", + new_callable=AsyncMock, + return_value=("test_user_1", "test@example.com", True), + ) as mock_get_user_info, patch.object( + jwt_handler, "get_org_id", return_value=None + ) as mock_get_org_id, patch.object( + jwt_handler, "get_end_user_id", return_value=None + ) as mock_get_end_user_id, patch.object( + JWTAuthManager, "check_admin_access", new_callable=AsyncMock, return_value=None + ) as mock_check_admin, patch.object( + JWTAuthManager, + "find_and_validate_specific_team_id", + new_callable=AsyncMock, + return_value=(None, None), + ) as mock_find_team, patch.object( + JWTAuthManager, "get_all_team_ids", return_value=set() + ) as mock_get_all_team_ids, patch.object( + JWTAuthManager, + "find_team_with_model_access", + new_callable=AsyncMock, + return_value=(None, None), + ) as mock_find_team_access, patch.object( + JWTAuthManager, + "get_objects", + new_callable=AsyncMock, + return_value=(user_object, None, None, None), + ) as mock_get_objects, patch.object( + JWTAuthManager, "map_user_to_teams", new_callable=AsyncMock + ) as mock_map_user, patch.object( + JWTAuthManager, "validate_object_id", return_value=True + ) as mock_validate_object, patch.object( + JWTAuthManager, "sync_user_role_and_teams", new_callable=AsyncMock + ) as mock_sync_user: + # Set up mock return values + mock_get_userinfo.return_value = userinfo_response + + # Call auth_builder + result = await JWTAuthManager.auth_builder( + api_key=api_key, + jwt_handler=jwt_handler, + request_data=request_data, + general_settings=general_settings, + route=route, + prisma_client=None, + user_api_key_cache=user_api_key_cache, + parent_otel_span=None, + proxy_logging_obj=proxy_logging_obj, + ) + + # Verify that get_oidc_userinfo was called instead of auth_jwt + mock_get_userinfo.assert_called_once_with(token=api_key) + mock_auth_jwt.assert_not_called() # Should not be called when OIDC is enabled + + # Verify the result + assert result["user_id"] == "test_user_1" + assert result["user_object"] == user_object + + +@pytest.mark.asyncio +async def test_auth_builder_with_oidc_userinfo_disabled(): + """Test that auth_builder uses JWT validation when OIDC UserInfo is disabled""" + from unittest.mock import MagicMock + + from litellm.caching import DualCache + from litellm.proxy.utils import ProxyLogging + + # Setup test data + api_key = "test_jwt_token" + request_data = {"model": "gpt-4"} + general_settings = {"enforce_rbac": False} + route = "/chat/completions" + + user_object = LiteLLM_UserTable( + user_id="test_user_1", user_role=LitellmUserRoles.INTERNAL_USER + ) + + # Create JWT handler with OIDC UserInfo disabled + jwt_handler = JWTHandler() + user_api_key_cache = DualCache() + proxy_logging_obj = ProxyLogging(user_api_key_cache=user_api_key_cache) + + jwt_handler.update_environment( + prisma_client=None, + user_api_key_cache=user_api_key_cache, + litellm_jwtauth=LiteLLM_JWTAuth( + oidc_userinfo_enabled=False, # Disabled + user_id_jwt_field="sub", + ), + ) + + # Mock JWT validation response + jwt_response = { + "sub": "test_user_1", + "scope": "", + } + + # Mock all the dependencies + with patch.object( + jwt_handler, "get_oidc_userinfo", new_callable=AsyncMock + ) as mock_get_userinfo, patch.object( + jwt_handler, "auth_jwt", new_callable=AsyncMock + ) as mock_auth_jwt, patch.object( + JWTAuthManager, "check_rbac_role", new_callable=AsyncMock + ) as mock_check_rbac, patch.object( + jwt_handler, "get_rbac_role", return_value=None + ) as mock_get_rbac, patch.object( + jwt_handler, "get_scopes", return_value=[] + ) as mock_get_scopes, patch.object( + jwt_handler, "get_object_id", return_value=None + ) as mock_get_object_id, patch.object( + JWTAuthManager, + "get_user_info", + new_callable=AsyncMock, + return_value=("test_user_1", None, None), + ) as mock_get_user_info, patch.object( + jwt_handler, "get_org_id", return_value=None + ) as mock_get_org_id, patch.object( + jwt_handler, "get_end_user_id", return_value=None + ) as mock_get_end_user_id, patch.object( + JWTAuthManager, "check_admin_access", new_callable=AsyncMock, return_value=None + ) as mock_check_admin, patch.object( + JWTAuthManager, + "find_and_validate_specific_team_id", + new_callable=AsyncMock, + return_value=(None, None), + ) as mock_find_team, patch.object( + JWTAuthManager, "get_all_team_ids", return_value=set() + ) as mock_get_all_team_ids, patch.object( + JWTAuthManager, + "find_team_with_model_access", + new_callable=AsyncMock, + return_value=(None, None), + ) as mock_find_team_access, patch.object( + JWTAuthManager, + "get_objects", + new_callable=AsyncMock, + return_value=(user_object, None, None, None), + ) as mock_get_objects, patch.object( + JWTAuthManager, "map_user_to_teams", new_callable=AsyncMock + ) as mock_map_user, patch.object( + JWTAuthManager, "validate_object_id", return_value=True + ) as mock_validate_object, patch.object( + JWTAuthManager, "sync_user_role_and_teams", new_callable=AsyncMock + ) as mock_sync_user: + # Set up mock return values + mock_auth_jwt.return_value = jwt_response + + # Call auth_builder + result = await JWTAuthManager.auth_builder( + api_key=api_key, + jwt_handler=jwt_handler, + request_data=request_data, + general_settings=general_settings, + route=route, + prisma_client=None, + user_api_key_cache=user_api_key_cache, + parent_otel_span=None, + proxy_logging_obj=proxy_logging_obj, + ) + + # Verify that auth_jwt was called instead of get_oidc_userinfo + mock_auth_jwt.assert_called_once_with(token=api_key) + mock_get_userinfo.assert_not_called() # Should not be called when OIDC is disabled + + # Verify the result + assert result["user_id"] == "test_user_1" + assert result["user_object"] == user_object \ No newline at end of file From 7a46f3a0830c1f8a5635a6635f02dc7556ce0d30 Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Mon, 1 Dec 2025 14:05:54 -0800 Subject: [PATCH 12/47] docs: document azure ai provider for anthropic --- .../blog/anthropic_opus_4_5_and_advanced_features/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/my-website/blog/anthropic_opus_4_5_and_advanced_features/index.md b/docs/my-website/blog/anthropic_opus_4_5_and_advanced_features/index.md index be2c0b5dc5d..1e5f968b2ca 100644 --- a/docs/my-website/blog/anthropic_opus_4_5_and_advanced_features/index.md +++ b/docs/my-website/blog/anthropic_opus_4_5_and_advanced_features/index.md @@ -33,7 +33,7 @@ This guide covers Anthropic's latest model (Claude Opus 4.5) and its advanced fe | Input Examples | Claude Opus 4.5, Sonnet 4.5 | | Effort Parameter | Claude Opus 4.5 only | -Supported Providers: [Anthropic](../../docs/providers/anthropic), [Bedrock](../../docs/providers/bedrock), [Vertex AI](../../docs/providers/vertex_partner#vertex-ai---anthropic-claude). +Supported Providers: [Anthropic](../../docs/providers/anthropic), [Bedrock](../../docs/providers/bedrock), [Vertex AI](../../docs/providers/vertex_partner#vertex-ai---anthropic-claude), [Azure AI](../../docs/providers/azure_ai). ## Usage From c9afb869940ae2de27846ed5263ab27a4461d2b7 Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Mon, 1 Dec 2025 14:06:31 -0800 Subject: [PATCH 13/47] docs(azure_ai.md): document anthropic model usage on azure ai --- docs/my-website/docs/providers/azure_ai.md | 79 +++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/docs/my-website/docs/providers/azure_ai.md b/docs/my-website/docs/providers/azure_ai.md index b1b5de5bb34..68e2df676e6 100644 --- a/docs/my-website/docs/providers/azure_ai.md +++ b/docs/my-website/docs/providers/azure_ai.md @@ -312,6 +312,82 @@ LiteLLM supports **ALL** azure ai models. Here's a few examples: | mistral-large-latest | `completion(model="azure_ai/mistral-large-latest", messages)` | | AI21-Jamba-Instruct | `completion(model="azure_ai/ai21-jamba-instruct", messages)` | +## Usage - Azure Anthropic (Azure Foundry Claude) + +LiteLLM funnels Azure Claude deployments through the `azure_ai/` provider so Claude Opus models on Azure Foundry keep working with Tool Search, Effort, streaming, and the rest of the advanced feature set. Point `AZURE_AI_API_BASE` to `https://.services.ai.azure.com/anthropic` (LiteLLM appends `/v1/messages` automatically) and authenticate with `AZURE_AI_API_KEY` or an Azure AD token. + + + + +```python +import os +from litellm import completion + +# Configure Azure credentials +os.environ["AZURE_AI_API_KEY"] = "your-azure-ai-api-key" +os.environ["AZURE_AI_API_BASE"] = "https://my-resource.services.ai.azure.com/anthropic" + +response = completion( + model="azure_ai/claude-opus-4-1", + messages=[{"role": "user", "content": "Explain how Azure Anthropic hosts Claude Opus differently from the public Anthropic API."}], + max_tokens=1200, + temperature=0.7, + stream=True, +) + +for chunk in response: + if chunk.choices[0].delta.content: + print(chunk.choices[0].delta.content, end="", flush=True) +``` + + + + +**1. Set environment variables** + +```bash +export AZURE_AI_API_KEY="your-azure-ai-api-key" +export AZURE_AI_API_BASE="https://my-resource.services.ai.azure.com/anthropic" +``` + +**2. Configure the proxy** + +```yaml +model_list: + - model_name: claude-4-azure + litellm_params: + model: azure_ai/claude-opus-4-1 + api_key: os.environ/AZURE_AI_API_KEY + api_base: os.environ/AZURE_AI_API_BASE +``` + +**3. Start LiteLLM** + +```bash +litellm --config /path/to/config.yaml +``` + +**4. Test the Azure Claude route** + +```bash +curl --location 'http://0.0.0.0:4000/chat/completions' \ + --header 'Content-Type: application/json' \ + --header 'Authorization: Bearer $LITELLM_KEY' \ + --data '{ + "model": "claude-4-azure", + "messages": [ + { + "role": "user", + "content": "How do I use Claude Opus 4 via Azure Anthropic in LiteLLM?" + } + ], + "max_tokens": 1024 + }' +``` + + + + ## Rerank Endpoint @@ -397,4 +473,5 @@ curl http://0.0.0.0:4000/rerank \ ``` - \ No newline at end of file + + From f434ca61ec0c637ba676fb90336ff154a992793b Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Mon, 1 Dec 2025 14:14:41 -0800 Subject: [PATCH 14/47] add kimi-k2-instruct-0905 (#17328) --- litellm/model_prices_and_context_window_backup.json | 13 +++++++++++++ model_prices_and_context_window.json | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index f4f6b94fd18..af63d1e2592 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -10198,6 +10198,19 @@ "supports_response_schema": true, "supports_tool_choice": true }, + "fireworks_ai/accounts/fireworks/models/kimi-k2-instruct-0905": { + "input_cost_per_token": 6e-07, + "litellm_provider": "fireworks_ai", + "max_input_tokens": 262144, + "max_output_tokens": 32768, + "max_tokens": 262144, + "mode": "chat", + "output_cost_per_token": 2.5e-06, + "source": "https://app.fireworks.ai/models/fireworks/kimi-k2-instruct-0905", + "supports_function_calling": true, + "supports_response_schema": true, + "supports_tool_choice": true + }, "fireworks_ai/accounts/fireworks/models/kimi-k2-thinking": { "input_cost_per_token": 6e-07, "litellm_provider": "fireworks_ai", diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index f4f6b94fd18..af63d1e2592 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -10198,6 +10198,19 @@ "supports_response_schema": true, "supports_tool_choice": true }, + "fireworks_ai/accounts/fireworks/models/kimi-k2-instruct-0905": { + "input_cost_per_token": 6e-07, + "litellm_provider": "fireworks_ai", + "max_input_tokens": 262144, + "max_output_tokens": 32768, + "max_tokens": 262144, + "mode": "chat", + "output_cost_per_token": 2.5e-06, + "source": "https://app.fireworks.ai/models/fireworks/kimi-k2-instruct-0905", + "supports_function_calling": true, + "supports_response_schema": true, + "supports_tool_choice": true + }, "fireworks_ai/accounts/fireworks/models/kimi-k2-thinking": { "input_cost_per_token": 6e-07, "litellm_provider": "fireworks_ai", From b6d6f834e059e1cb0d9062f99189c4f521fe3e1e Mon Sep 17 00:00:00 2001 From: Krish Dholakia Date: Mon, 1 Dec 2025 14:29:52 -0800 Subject: [PATCH 15/47] (feat) Generic Guardrail API - allows guardrail providers to add INSTANT support for LiteLLM w/out PR to repo (#17175) * feat(generic_guardrail_api.py): new generic api for guardrails Allows guardrail providers to work with litellm for guardrails without needing to make a PR to LiteLLM * docs(generic_guardrail_api.md): document new generic guardrail api * Fix: Improve PII detection and guardrail API integration Co-authored-by: krrishdholakia * feat: correctly extract raw request from guardrail api * docs(generic_guardrail_api.md): document this is a beta feature --------- Co-authored-by: Cursor Agent --- .../mock_bedrock_guardrail_server.py | 564 ++++++++++++++++++ .../adding_provider/generic_guardrail_api.md | 160 +++++ docs/my-website/sidebars.js | 1 + litellm/proxy/_new_secret_config.yaml | 2 +- .../generic_guardrail_api/__init__.py | 37 ++ .../generic_guardrail_api/example_config.yaml | 52 ++ .../generic_guardrail_api.py | 235 ++++++++ litellm/types/guardrails.py | 11 +- .../guardrail_hooks/generic_guardrail_api.py | 29 + 9 files changed, 1089 insertions(+), 2 deletions(-) create mode 100644 cookbook/mock_guardrail_server/mock_bedrock_guardrail_server.py create mode 100644 docs/my-website/docs/adding_provider/generic_guardrail_api.md create mode 100644 litellm/proxy/guardrails/guardrail_hooks/generic_guardrail_api/__init__.py create mode 100644 litellm/proxy/guardrails/guardrail_hooks/generic_guardrail_api/example_config.yaml create mode 100644 litellm/proxy/guardrails/guardrail_hooks/generic_guardrail_api/generic_guardrail_api.py create mode 100644 litellm/types/proxy/guardrails/guardrail_hooks/generic_guardrail_api.py diff --git a/cookbook/mock_guardrail_server/mock_bedrock_guardrail_server.py b/cookbook/mock_guardrail_server/mock_bedrock_guardrail_server.py new file mode 100644 index 00000000000..9cfbb11feb5 --- /dev/null +++ b/cookbook/mock_guardrail_server/mock_bedrock_guardrail_server.py @@ -0,0 +1,564 @@ +#!/usr/bin/env python3 +""" +Mock Bedrock Guardrail API Server + +This is a FastAPI server that mimics the AWS Bedrock Guardrail API for testing purposes. +It follows the same API spec as the real Bedrock guardrail endpoint. + +Usage: + python mock_bedrock_guardrail_server.py + +The server will start on http://localhost:8080 +""" + +import os +import re +from typing import Any, Dict, List, Literal, Optional + +from fastapi import Depends, FastAPI, Header, HTTPException, status +from fastapi.responses import JSONResponse +from pydantic import BaseModel, Field + +# ============================================================================ +# Request/Response Models (matching Bedrock API spec) +# ============================================================================ + + +class BedrockTextContent(BaseModel): + text: str + + +class BedrockContentItem(BaseModel): + text: BedrockTextContent + + +class BedrockRequest(BaseModel): + source: Literal["INPUT", "OUTPUT"] + content: List[BedrockContentItem] = Field(default_factory=list) + + +class BedrockGuardrailOutput(BaseModel): + text: Optional[str] = None + + +class TopicPolicyItem(BaseModel): + name: str + type: str + action: Literal["BLOCKED", "NONE"] + + +class TopicPolicy(BaseModel): + topics: List[TopicPolicyItem] = Field(default_factory=list) + + +class ContentFilterItem(BaseModel): + type: str + confidence: str + action: Literal["BLOCKED", "NONE"] + + +class ContentPolicy(BaseModel): + filters: List[ContentFilterItem] = Field(default_factory=list) + + +class CustomWord(BaseModel): + match: str + action: Literal["BLOCKED", "NONE"] + + +class WordPolicy(BaseModel): + customWords: List[CustomWord] = Field(default_factory=list) + managedWordLists: List[Dict[str, Any]] = Field(default_factory=list) + + +class PiiEntity(BaseModel): + type: str + match: str + action: Literal["BLOCKED", "ANONYMIZED", "NONE"] + + +class RegexMatch(BaseModel): + name: str + match: str + regex: str + action: Literal["BLOCKED", "ANONYMIZED", "NONE"] + + +class SensitiveInformationPolicy(BaseModel): + piiEntities: List[PiiEntity] = Field(default_factory=list) + regexes: List[RegexMatch] = Field(default_factory=list) + + +class ContextualGroundingFilter(BaseModel): + type: str + threshold: float + score: float + action: Literal["BLOCKED", "NONE"] + + +class ContextualGroundingPolicy(BaseModel): + filters: List[ContextualGroundingFilter] = Field(default_factory=list) + + +class Assessment(BaseModel): + topicPolicy: Optional[TopicPolicy] = None + contentPolicy: Optional[ContentPolicy] = None + wordPolicy: Optional[WordPolicy] = None + sensitiveInformationPolicy: Optional[SensitiveInformationPolicy] = None + contextualGroundingPolicy: Optional[ContextualGroundingPolicy] = None + + +class BedrockGuardrailResponse(BaseModel): + usage: Dict[str, int] = Field( + default_factory=lambda: {"topicPolicyUnits": 1, "contentPolicyUnits": 1} + ) + action: Literal["NONE", "GUARDRAIL_INTERVENED"] = "NONE" + outputs: List[BedrockGuardrailOutput] = Field(default_factory=list) + assessments: List[Assessment] = Field(default_factory=list) + + +# ============================================================================ +# Mock Guardrail Configuration +# ============================================================================ + + +class GuardrailConfig(BaseModel): + """Configuration for mock guardrail behavior""" + + blocked_words: List[str] = Field( + default_factory=lambda: ["offensive", "inappropriate", "badword"] + ) + blocked_topics: List[str] = Field(default_factory=lambda: ["violence", "illegal"]) + pii_patterns: Dict[str, str] = Field( + default_factory=lambda: { + "EMAIL": r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b", + "PHONE": r"\b\d{3}[-.]?\d{3}[-.]?\d{4}\b", + "SSN": r"\b\d{3}-\d{2}-\d{4}\b", + "CREDIT_CARD": r"\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b", + } + ) + anonymize_pii: bool = True # If True, ANONYMIZE PII; if False, BLOCK it + bearer_token: str = "mock-bedrock-token-12345" + + +# Global config +GUARDRAIL_CONFIG = GuardrailConfig() + +# ============================================================================ +# FastAPI App Setup +# ============================================================================ + +app = FastAPI( + title="Mock Bedrock Guardrail API", + description="Mock server mimicking AWS Bedrock Guardrail API", + version="1.0.0", +) + + +# ============================================================================ +# Authentication +# ============================================================================ + + +async def verify_bearer_token(authorization: Optional[str] = Header(None)) -> str: + """ + Verify the Bearer token from the Authorization header. + + Args: + authorization: The Authorization header value + + Returns: + The token if valid + + Raises: + HTTPException: If token is missing or invalid + """ + if authorization is None: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Missing Authorization header", + headers={"WWW-Authenticate": "Bearer"}, + ) + + # Check if it's a Bearer token + parts = authorization.split() + print(f"parts: {parts}") + if len(parts) != 2 or parts[0].lower() != "bearer": + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Invalid Authorization header format. Expected: Bearer ", + headers={"WWW-Authenticate": "Bearer"}, + ) + + token = parts[1] + + # Verify token + if token != GUARDRAIL_CONFIG.bearer_token: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Invalid bearer token", + ) + + return token + + +# ============================================================================ +# Guardrail Logic +# ============================================================================ + + +def check_blocked_words(text: str) -> Optional[WordPolicy]: + """Check if text contains blocked words""" + found_words = [] + text_lower = text.lower() + + for word in GUARDRAIL_CONFIG.blocked_words: + if word.lower() in text_lower: + found_words.append(CustomWord(match=word, action="BLOCKED")) + + if found_words: + return WordPolicy(customWords=found_words) + return None + + +def check_blocked_topics(text: str) -> Optional[TopicPolicy]: + """Check if text contains blocked topics""" + found_topics = [] + text_lower = text.lower() + + for topic in GUARDRAIL_CONFIG.blocked_topics: + if topic.lower() in text_lower: + found_topics.append( + TopicPolicyItem(name=topic, type=topic.upper(), action="BLOCKED") + ) + + if found_topics: + return TopicPolicy(topics=found_topics) + return None + + +def check_pii(text: str) -> tuple[Optional[SensitiveInformationPolicy], str]: + """ + Check for PII in text and return policy + anonymized text + + Returns: + Tuple of (SensitiveInformationPolicy or None, anonymized_text) + """ + pii_entities = [] + anonymized_text = text + action = "ANONYMIZED" if GUARDRAIL_CONFIG.anonymize_pii else "BLOCKED" + + for pii_type, pattern in GUARDRAIL_CONFIG.pii_patterns.items(): + try: + # Compile the regex pattern with a timeout to prevent ReDoS attacks + compiled_pattern = re.compile(pattern) + matches = compiled_pattern.finditer(text) + for match in matches: + matched_text = match.group() + pii_entities.append( + PiiEntity(type=pii_type, match=matched_text, action=action) + ) + + # Anonymize the text if configured + if GUARDRAIL_CONFIG.anonymize_pii: + anonymized_text = anonymized_text.replace( + matched_text, f"[{pii_type}_REDACTED]" + ) + except re.error: + # Invalid regex pattern - skip it and log a warning + print(f"Warning: Invalid regex pattern for PII type {pii_type}: {pattern}") + continue + + if pii_entities: + return SensitiveInformationPolicy(piiEntities=pii_entities), anonymized_text + + return None, text + + +def process_guardrail_request( + request: BedrockRequest, +) -> tuple[BedrockGuardrailResponse, List[str]]: + """ + Process a guardrail request and return the response. + + Returns: + Tuple of (response, list of output texts) + """ + all_text_content = [] + output_texts = [] + + # Extract all text from content items + for content_item in request.content: + if content_item.text and content_item.text.text: + all_text_content.append(content_item.text.text) + + # Combine all text for analysis + combined_text = " ".join(all_text_content) + + # Initialize response + response = BedrockGuardrailResponse() + assessment = Assessment() + has_intervention = False + + # Check for blocked words + word_policy = check_blocked_words(combined_text) + if word_policy: + assessment.wordPolicy = word_policy + has_intervention = True + + # Check for blocked topics + topic_policy = check_blocked_topics(combined_text) + if topic_policy: + assessment.topicPolicy = topic_policy + has_intervention = True + + # Check for PII + for text in all_text_content: + pii_policy, anonymized_text = check_pii(text) + if pii_policy: + assessment.sensitiveInformationPolicy = pii_policy + if GUARDRAIL_CONFIG.anonymize_pii: + # If anonymizing, we don't block, we modify the text + output_texts.append(anonymized_text) + has_intervention = True + else: + # If not anonymizing PII, we block it + output_texts.append(text) + has_intervention = True + else: + output_texts.append(text) + + # Build response + if has_intervention: + response.action = "GUARDRAIL_INTERVENED" + # Only add assessment if there were interventions + response.assessments = [assessment] + + # Add outputs (modified or original text) + response.outputs = [BedrockGuardrailOutput(text=txt) for txt in output_texts] + + return response, output_texts + + +# ============================================================================ +# API Endpoints +# ============================================================================ + + +@app.get("/") +async def root(): + """Health check endpoint""" + return { + "service": "Mock Bedrock Guardrail API", + "status": "running", + "endpoint_format": "/guardrail/{guardrailIdentifier}/version/{guardrailVersion}/apply", + } + + +@app.get("/health") +async def health(): + """Health check endpoint""" + return {"status": "healthy"} + + +@app.post( + "/guardrail/{guardrailIdentifier}/version/{guardrailVersion}/apply", + response_model=BedrockGuardrailResponse, +) +async def apply_guardrail( + guardrailIdentifier: str, + guardrailVersion: str, + request: BedrockRequest, + token: str = Depends(verify_bearer_token), +) -> BedrockGuardrailResponse: + """ + Apply guardrail to input or output content. + + This endpoint mimics the AWS Bedrock ApplyGuardrail API. + + Args: + guardrailIdentifier: The guardrail ID + guardrailVersion: The guardrail version + request: The guardrail request containing content to analyze + token: Bearer token (verified by dependency) + + Returns: + BedrockGuardrailResponse with analysis results + """ + # Process the request + response, output_texts = process_guardrail_request(request) + + # Log the request (optional, for debugging) + print(f"Guardrail applied: {guardrailIdentifier} v{guardrailVersion}") + print(f"Source: {request.source}") + print(f"Action: {response.action}") + + return response + + +""" +LiteLLM exposes a basic guardrail API with the text extracted from the request and sent to the guardrail API, as well as the received request body for any further processing. + +This works across all LiteLLM endpoints (completion, anthropic /v1/messages, responses api, image generation, embedding, etc.) + +This makes it easy to support your own guardrail API without having to make a PR to LiteLLM. + +LiteLLM supports passing any provider specific params from LiteLLM config.yaml to the guardrail API. + +Example: + +```yaml +guardrails: + - guardrail_name: "bedrock-content-guard" + litellm_params: + guardrail: generic_guardrail_api + mode: "pre_call" + api_key: os.environ/GUARDRAIL_API_KEY + api_base: os.environ/GUARDRAIL_API_BASE + additional_provider_specific_params: + api_version: os.environ/GUARDRAIL_API_VERSION # additional provider specific params +``` + +This is a beta API. Please help us improve it. +""" + + +class LitellmBasicGuardrailRequest(BaseModel): + text: str + request_body: Dict[str, Any] = Field(default_factory=dict) + additional_provider_specific_params: Dict[str, Any] = Field(default_factory=dict) + + +class LitellmBasicGuardrailResponse(BaseModel): + action: Literal[ + "BLOCKED", "NONE", "GUARDRAIL_INTERVENED" + ] # BLOCKED = litellm will raise an error, NONE = litellm will continue, GUARDRAIL_INTERVENED = litellm will continue, but the text was modified by the guardrail + blocked_reason: Optional[str] = None # only if action is BLOCKED, otherwise None + text: Optional[str] = None + + +@app.post( + "/beta/litellm_basic_guardrail_api", + response_model=LitellmBasicGuardrailResponse, +) +async def beta_litellm_basic_guardrail_api( + request: LitellmBasicGuardrailRequest, +) -> LitellmBasicGuardrailResponse: + """ + Apply guardrail to input or output content. + + This endpoint mimics the AWS Bedrock ApplyGuardrail API. + + Args: + request: The guardrail request containing content to analyze + token: Bearer token (verified by dependency) + + Returns: + LitellmBasicGuardrailResponse with analysis results + """ + print(f"request: {request}") + if "ishaan" in request.text.lower(): + return LitellmBasicGuardrailResponse( + action="BLOCKED", blocked_reason="Ishaan is not allowed" + ) + elif "pii_value" in request.text: + return LitellmBasicGuardrailResponse( + action="GUARDRAIL_INTERVENED", + text=request.text.replace("pii_value", "pii_value_redacted"), + ) + return LitellmBasicGuardrailResponse(action="NONE") + + +@app.post("/config/update") +async def update_config( + config: GuardrailConfig, token: str = Depends(verify_bearer_token) +): + """ + Update the guardrail configuration. + + This is a testing endpoint to modify the mock guardrail behavior. + + Args: + config: New guardrail configuration + token: Bearer token (verified by dependency) + + Returns: + Updated configuration + """ + global GUARDRAIL_CONFIG + GUARDRAIL_CONFIG = config + return {"status": "updated", "config": GUARDRAIL_CONFIG} + + +@app.get("/config") +async def get_config(token: str = Depends(verify_bearer_token)): + """ + Get the current guardrail configuration. + + Args: + token: Bearer token (verified by dependency) + + Returns: + Current configuration + """ + return GUARDRAIL_CONFIG + + +# ============================================================================ +# Error Handlers +# ============================================================================ + + +@app.exception_handler(HTTPException) +async def http_exception_handler(request, exc: HTTPException): + """Custom error handler for HTTP exceptions""" + return JSONResponse( + status_code=exc.status_code, + content={"error": exc.detail}, + headers=exc.headers, + ) + + +# ============================================================================ +# Main +# ============================================================================ + +if __name__ == "__main__": + import uvicorn + + # Get configuration from environment + host = os.getenv("MOCK_BEDROCK_HOST", "0.0.0.0") + port = int(os.getenv("MOCK_BEDROCK_PORT", "8080")) + bearer_token = os.getenv("MOCK_BEDROCK_TOKEN", "mock-bedrock-token-12345") + + # Update config with environment token + GUARDRAIL_CONFIG.bearer_token = bearer_token + + print("=" * 80) + print("Mock Bedrock Guardrail API Server") + print("=" * 80) + print(f"Server starting on: http://{host}:{port}") + print(f"Bearer Token: {bearer_token}") + print(f"Endpoint: POST /guardrail/{{id}}/version/{{version}}/apply") + print("=" * 80) + print("\nExample curl command:") + print( + f""" +curl -X POST "http://{host}:{port}/guardrail/test-guardrail/version/1/apply" \\ + -H "Authorization: Bearer {bearer_token}" \\ + -H "Content-Type: application/json" \\ + -d '{{ + "source": "INPUT", + "content": [ + {{ + "text": {{ + "text": "Hello, my email is test@example.com" + }} + }} + ] + }}' + """ + ) + print("=" * 80) + + uvicorn.run(app, host=host, port=port) diff --git a/docs/my-website/docs/adding_provider/generic_guardrail_api.md b/docs/my-website/docs/adding_provider/generic_guardrail_api.md new file mode 100644 index 00000000000..70b39d3c397 --- /dev/null +++ b/docs/my-website/docs/adding_provider/generic_guardrail_api.md @@ -0,0 +1,160 @@ +# [BETA] Generic Guardrail API - Integrate Without a PR + +## The Problem + +As a guardrail provider, integrating with LiteLLM traditionally requires: +- Making a PR to the LiteLLM repository +- Waiting for review and merge +- Maintaining provider-specific code in LiteLLM's codebase +- Updating the integration for changes to your API + +## The Solution + +The **Generic Guardrail API** lets you integrate with LiteLLM **instantly** by implementing a simple API endpoint. No PR required. + +### Key Benefits + +1. **No PR Needed** - Deploy and integrate immediately +2. **Universal Support** - Works across ALL LiteLLM endpoints (chat, embeddings, image generation, etc.) +3. **Simple Contract** - One endpoint, three response types +4. **Custom Parameters** - Pass provider-specific params via config +5. **Full Control** - You own and maintain your guardrail API + +## How It Works + +1. LiteLLM extracts text from any request (chat messages, embeddings, image prompts, etc.) +2. Sends extracted text + original request to your API endpoint +3. Your API responds with: `BLOCKED`, `NONE`, or `GUARDRAIL_INTERVENED` +4. LiteLLM enforces the decision + +## API Contract + +### Endpoint + +Implement `POST /beta/litellm_basic_guardrail_api` + +### Request Format + +```json +{ + "text": "extracted text from the request", + "request_body": {}, // full original request for context + "additional_provider_specific_params": { + // your custom params from config + } +} +``` + +### Response Format + +```json +{ + "action": "BLOCKED" | "NONE" | "GUARDRAIL_INTERVENED", + "blocked_reason": "why content was blocked", // required if action=BLOCKED + "text": "modified text" // required if action=GUARDRAIL_INTERVENED +} +``` + +**Actions:** +- `BLOCKED` - LiteLLM raises error and blocks request +- `NONE` - Request proceeds unchanged +- `GUARDRAIL_INTERVENED` - Request proceeds with modified text + +## LiteLLM Configuration + +Add to `config.yaml`: + +```yaml +litellm_settings: + guardrails: + - guardrail_name: "my-guardrail" + litellm_params: + guardrail: generic_guardrail_api + mode: pre_call # or post_call, during_call + api_base: https://your-guardrail-api.com + api_key: os.environ/YOUR_GUARDRAIL_API_KEY # optional + additional_provider_specific_params: + # your custom parameters + threshold: 0.8 + language: "en" +``` + +## Usage + +Users apply your guardrail by name: + +```python +response = client.chat.completions.create( + model="gpt-4", + messages=[{"role": "user", "content": "hello"}], + guardrails=["my-guardrail"] +) +``` + +Or with dynamic parameters: + +```python +response = client.chat.completions.create( + model="gpt-4", + messages=[{"role": "user", "content": "hello"}], + guardrails=[{ + "my-guardrail": { + "extra_body": { + "custom_threshold": 0.9 + } + } + }] +) +``` + +## Implementation Example + +See [mock_bedrock_guardrail_server.py](https://github.com/BerriAI/litellm/blob/main/cookbook/mock_guardrail_server/mock_bedrock_guardrail_server.py) for a complete reference implementation. + +**Minimal FastAPI example:** + +```python +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + +class GuardrailRequest(BaseModel): + text: str + request_body: dict + additional_provider_specific_params: dict + +class GuardrailResponse(BaseModel): + action: str # BLOCKED, NONE, or GUARDRAIL_INTERVENED + blocked_reason: str | None = None + text: str | None = None + +@app.post("/beta/litellm_basic_guardrail_api") +async def apply_guardrail(request: GuardrailRequest): + # Your guardrail logic here + if "badword" in request.text.lower(): + return GuardrailResponse( + action="BLOCKED", + blocked_reason="Content contains prohibited terms" + ) + + return GuardrailResponse(action="NONE") +``` + +## When to Use This + +✅ **Use Generic Guardrail API when:** +- You want instant integration without waiting for PRs +- You maintain your own guardrail service +- You need full control over updates and features +- You want to support all LiteLLM endpoints automatically + +❌ **Make a PR when:** +- You want deeper integration with LiteLLM internals +- Your guardrail requires complex LiteLLM-specific logic +- You want to be featured as a built-in provider + +## Questions? + +This is a **beta API**. We're actively improving it based on feedback. Open an issue or PR if you need additional capabilities. + diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index 802ffdd5bb1..2039d01186c 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -45,6 +45,7 @@ const sidebars = { type: "category", "label": "Contributing to Guardrails", items: [ + "adding_provider/generic_guardrail_api", "adding_provider/simple_guardrail_tutorial", "adding_provider/adding_guardrail_support", ] diff --git a/litellm/proxy/_new_secret_config.yaml b/litellm/proxy/_new_secret_config.yaml index 68761524794..c11848a8623 100644 --- a/litellm/proxy/_new_secret_config.yaml +++ b/litellm/proxy/_new_secret_config.yaml @@ -16,4 +16,4 @@ callback_settings: callback_type: generic_api endpoint: https://webhook.site/efc57707-9018-478c-bdf1-2ffaabb2b315 headers: - Authorization: Bearer sk-1234 \ No newline at end of file + Authorization: Bearer sk-1234 diff --git a/litellm/proxy/guardrails/guardrail_hooks/generic_guardrail_api/__init__.py b/litellm/proxy/guardrails/guardrail_hooks/generic_guardrail_api/__init__.py new file mode 100644 index 00000000000..c762f0cbfc6 --- /dev/null +++ b/litellm/proxy/guardrails/guardrail_hooks/generic_guardrail_api/__init__.py @@ -0,0 +1,37 @@ +from typing import TYPE_CHECKING + +from litellm.types.guardrails import SupportedGuardrailIntegrations + +from .generic_guardrail_api import GenericGuardrailAPI + +if TYPE_CHECKING: + from litellm.types.guardrails import Guardrail, LitellmParams + + +def initialize_guardrail(litellm_params: "LitellmParams", guardrail: "Guardrail"): + import litellm + + _generic_guardrail_api_callback = GenericGuardrailAPI( + api_base=litellm_params.api_base, + headers=getattr(litellm_params, "headers", None), + additional_provider_specific_params=getattr( + litellm_params, "additional_provider_specific_params", {} + ), + guardrail_name=guardrail.get("guardrail_name", ""), + event_hook=litellm_params.mode, + default_on=litellm_params.default_on, + ) + + litellm.logging_callback_manager.add_litellm_callback( + _generic_guardrail_api_callback + ) + return _generic_guardrail_api_callback + + +guardrail_initializer_registry = { + SupportedGuardrailIntegrations.GENERIC_GUARDRAIL_API.value: initialize_guardrail, +} + +guardrail_class_registry = { + SupportedGuardrailIntegrations.GENERIC_GUARDRAIL_API.value: GenericGuardrailAPI, +} diff --git a/litellm/proxy/guardrails/guardrail_hooks/generic_guardrail_api/example_config.yaml b/litellm/proxy/guardrails/guardrail_hooks/generic_guardrail_api/example_config.yaml new file mode 100644 index 00000000000..7ad33b24608 --- /dev/null +++ b/litellm/proxy/guardrails/guardrail_hooks/generic_guardrail_api/example_config.yaml @@ -0,0 +1,52 @@ +# Example configuration for Generic Guardrail API + +model_list: + - model_name: gpt-4 + litellm_params: + model: gpt-4 + api_key: os.environ/OPENAI_API_KEY + +litellm_settings: + guardrails: + - guardrail_name: "my-generic-guardrail" + litellm_params: + guardrail: generic_guardrail_api + mode: pre_call # Options: pre_call, post_call, during_call, [pre_call, post_call] + api_key: os.environ/GENERIC_GUARDRAIL_API_KEY # Optional if using Bearer auth + api_base: http://localhost:8080 # Required. Endpoint /beta/litellm_basic_guardrail_api is automatically appended + default_on: false # Set to true to apply to all requests by default + additional_provider_specific_params: + # Any additional parameters your guardrail API needs + api_version: "v1" + custom_param: "value" + +# Usage examples: + +# 1. Apply guardrail to a specific request: +# curl --location 'http://localhost:4000/chat/completions' \ +# --header 'Authorization: Bearer sk-1234' \ +# --header 'Content-Type: application/json' \ +# --data '{ +# "model": "gpt-4", +# "messages": [{"role": "user", "content": "Test message"}], +# "guardrails": ["my-generic-guardrail"] +# }' + +# 2. Apply guardrail with dynamic parameters: +# curl --location 'http://localhost:4000/chat/completions' \ +# --header 'Authorization: Bearer sk-1234' \ +# --header 'Content-Type: application/json' \ +# --data '{ +# "model": "gpt-4", +# "messages": [{"role": "user", "content": "Test message"}], +# "guardrails": [ +# { +# "my-generic-guardrail": { +# "extra_body": { +# "custom_threshold": 0.8 +# } +# } +# } +# ] +# }' + diff --git a/litellm/proxy/guardrails/guardrail_hooks/generic_guardrail_api/generic_guardrail_api.py b/litellm/proxy/guardrails/guardrail_hooks/generic_guardrail_api/generic_guardrail_api.py new file mode 100644 index 00000000000..e94306e172e --- /dev/null +++ b/litellm/proxy/guardrails/guardrail_hooks/generic_guardrail_api/generic_guardrail_api.py @@ -0,0 +1,235 @@ +# +-------------------------------------------------------------+ +# +# Use Generic Guardrail API for your LLM calls +# +# +-------------------------------------------------------------+ +# Thank you users! We ❤️ you! - Krrish & Ishaan + +import os +from typing import Any, Dict, List, Optional + +from litellm._logging import verbose_proxy_logger +from litellm.integrations.custom_guardrail import CustomGuardrail +from litellm.llms.custom_httpx.http_handler import ( + get_async_httpx_client, + httpxSpecialProvider, +) +from litellm.types.guardrails import GuardrailEventHooks + +GUARDRAIL_NAME = "generic_guardrail_api" + + +class GenericGuardrailAPIRequest: + """Request model for the Generic Guardrail API""" + + def __init__( + self, + text: str, + request_body: Dict[str, Any], + additional_provider_specific_params: Optional[Dict[str, Any]] = None, + ): + self.text = text + self.request_body = request_body + self.additional_provider_specific_params = ( + additional_provider_specific_params or {} + ) + + def to_dict(self) -> dict: + return { + "text": self.text, + "request_body": self.request_body, + "additional_provider_specific_params": self.additional_provider_specific_params, + } + + +class GenericGuardrailAPIResponse: + """Response model for the Generic Guardrail API""" + + def __init__( + self, + action: str, + blocked_reason: Optional[str] = None, + text: Optional[str] = None, + ): + self.action = action + self.blocked_reason = blocked_reason + self.text = text + + @classmethod + def from_dict(cls, data: dict) -> "GenericGuardrailAPIResponse": + return cls( + action=data.get("action", "NONE"), + blocked_reason=data.get("blocked_reason"), + text=data.get("text"), + ) + + +class GenericGuardrailAPI(CustomGuardrail): + """ + Generic Guardrail API integration for LiteLLM. + + This integration allows you to use any guardrail API that follows the + LiteLLM Basic Guardrail API spec without needing to write custom integration code. + + The API should accept a POST request with: + { + "text": str, + "request_body": dict, + "additional_provider_specific_params": dict + } + + And return: + { + "action": "BLOCKED" | "NONE" | "GUARDRAIL_INTERVENED", + "blocked_reason": str (optional, only if action is BLOCKED), + "text": str (optional, modified text if action is GUARDRAIL_INTERVENED) + } + """ + + def __init__( + self, + headers: Optional[Dict[str, Any]] = None, + api_base: Optional[str] = None, + additional_provider_specific_params: Optional[Dict[str, Any]] = None, + **kwargs, + ): + self.async_handler = get_async_httpx_client( + llm_provider=httpxSpecialProvider.GuardrailCallback + ) + self.headers = headers or {} + base_url = api_base or os.environ.get("GENERIC_GUARDRAIL_API_BASE") + + if not base_url: + raise ValueError( + "api_base is required for Generic Guardrail API. " + "Set GENERIC_GUARDRAIL_API_BASE environment variable or pass it in litellm_params" + ) + + # Append the endpoint path if not already present + if not base_url.endswith("/beta/litellm_basic_guardrail_api"): + base_url = base_url.rstrip("/") + self.api_base = f"{base_url}/beta/litellm_basic_guardrail_api" + else: + self.api_base = base_url + + self.additional_provider_specific_params = ( + additional_provider_specific_params or {} + ) + + # Set supported event hooks + if "supported_event_hooks" not in kwargs: + kwargs["supported_event_hooks"] = [ + GuardrailEventHooks.pre_call, + GuardrailEventHooks.post_call, + GuardrailEventHooks.during_call, + ] + + super().__init__(**kwargs) + + verbose_proxy_logger.debug( + "Generic Guardrail API initialized with api_base: %s", self.api_base + ) + + async def apply_guardrail( + self, + text: str, + language: Optional[str] = None, + entities: Optional[List] = None, + request_data: Optional[dict] = None, + ) -> str: + """ + Apply the Generic Guardrail API to the given text. + + This is the main method that gets called by the framework. + + Args: + text: The text to check + language: Optional language parameter (not used by Generic API) + entities: Optional entities parameter (not used by Generic API) + request_data: Optional request data dictionary for logging metadata + + Returns: + The processed text (original or modified) + + Raises: + Exception: If the guardrail blocks the request + """ + verbose_proxy_logger.debug("Generic Guardrail API: Applying guardrail to text") + + # Use provided request_data or create an empty dict + if request_data is None: + request_data = {} + + request_body = request_data.get("body") or {} + + # Merge additional provider specific params from config and dynamic params + additional_params = {**self.additional_provider_specific_params} + + # Get dynamic params from request if available + dynamic_params = self.get_guardrail_dynamic_request_body_params(request_body) + if dynamic_params: + additional_params.update(dynamic_params) + + # Create request payload + guardrail_request = GenericGuardrailAPIRequest( + text=text, + request_body=request_body, + additional_provider_specific_params=additional_params, + ) + + # Prepare headers + headers = {"Content-Type": "application/json"} + if self.headers: + headers.update(self.headers) + + verbose_proxy_logger.debug( + "Generic Guardrail API request to %s: %s", + self.api_base, + {"text_length": len(text), "has_request_body": bool(request_data)}, + ) + + try: + # Make the API request + response = await self.async_handler.post( + url=self.api_base, + json=guardrail_request.to_dict(), + headers=headers, + ) + + response.raise_for_status() + response_json = response.json() + + verbose_proxy_logger.debug( + "Generic Guardrail API response: %s", response_json + ) + + guardrail_response = GenericGuardrailAPIResponse.from_dict(response_json) + + # Handle the response + if guardrail_response.action == "BLOCKED": + # Block the request + error_message = ( + guardrail_response.blocked_reason or "Content violates policy" + ) + verbose_proxy_logger.warning( + "Generic Guardrail API blocked request: %s", error_message + ) + raise Exception(f"Content blocked by guardrail: {error_message}") + + elif guardrail_response.action == "GUARDRAIL_INTERVENED": + # Content was modified by the guardrail + if guardrail_response.text: + verbose_proxy_logger.debug("Generic Guardrail API modified text") + return guardrail_response.text + + # Action is NONE or no modifications needed + return text + + except Exception as e: + # Check if it's already an exception we raised + if "Content blocked by guardrail" in str(e): + raise + verbose_proxy_logger.error( + "Generic Guardrail API: failed to make request: %s", str(e) + ) + raise Exception(f"Generic Guardrail API failed: {str(e)}") diff --git a/litellm/types/guardrails.py b/litellm/types/guardrails.py index 24a235def59..31e301ed4de 100644 --- a/litellm/types/guardrails.py +++ b/litellm/types/guardrails.py @@ -8,6 +8,9 @@ from typing_extensions import Required, TypedDict from litellm.types.proxy.guardrails.guardrail_hooks.enkryptai import ( EnkryptAIGuardrailConfigs, ) +from litellm.types.proxy.guardrails.guardrail_hooks.generic_guardrail_api import ( + GenericGuardrailAPIOptionalParams, +) from litellm.types.proxy.guardrails.guardrail_hooks.grayswan import ( GraySwanGuardrailConfigModel, ) @@ -18,7 +21,6 @@ from litellm.types.proxy.guardrails.guardrail_hooks.tool_permission import ( ToolPermissionGuardrailConfigModel, ) - """ Pydantic object defining how to set guardrails on litellm proxy @@ -59,6 +61,7 @@ class SupportedGuardrailIntegrations(Enum): IBM_GUARDRAILS = "ibm_guardrails" LITELLM_CONTENT_FILTER = "litellm_content_filter" PROMPT_SECURITY = "prompt_security" + GENERIC_GUARDRAIL_API = "generic_guardrail_api" class Role(Enum): @@ -590,6 +593,12 @@ class BaseLitellmParams(BaseModel): # works for new and patch update guardrails description="Whether to fail the request if Model Armor encounters an error", ) + # Generic Guardrail API params + additional_provider_specific_params: Optional[Dict[str, Any]] = Field( + default=None, + description="Additional provider-specific parameters for generic guardrail APIs", + ) + model_config = ConfigDict(extra="allow", protected_namespaces=()) diff --git a/litellm/types/proxy/guardrails/guardrail_hooks/generic_guardrail_api.py b/litellm/types/proxy/guardrails/guardrail_hooks/generic_guardrail_api.py new file mode 100644 index 00000000000..a00fe76a0f0 --- /dev/null +++ b/litellm/types/proxy/guardrails/guardrail_hooks/generic_guardrail_api.py @@ -0,0 +1,29 @@ +from typing import Any, Dict, Literal, Optional + +from pydantic import BaseModel, Field + +from litellm.types.proxy.guardrails.guardrail_hooks.base import GuardrailConfigModel + + +class GenericGuardrailAPIOptionalParams(BaseModel): + """Optional parameters for the Generic Guardrail API""" + + additional_provider_specific_params: Optional[Dict[str, Any]] = Field( + default=None, + description="Additional provider-specific parameters to send with the guardrail request", + ) + + +class GenericGuardrailAPIConfigModel( + GuardrailConfigModel[GenericGuardrailAPIOptionalParams], +): + """Configuration parameters for the Generic Guardrail API guardrail""" + + optional_params: Optional[GenericGuardrailAPIOptionalParams] = Field( + default_factory=GenericGuardrailAPIOptionalParams, + description="Optional parameters for the Generic Guardrail API guardrail", + ) + + @staticmethod + def ui_friendly_name() -> str: + return "Generic Guardrail API" From 1eb06f803101d7e82761a3b3a36d6a61de22fc6f Mon Sep 17 00:00:00 2001 From: Krish Dholakia Date: Mon, 1 Dec 2025 15:40:28 -0800 Subject: [PATCH 16/47] =?UTF-8?q?Revert=20"fix:=20respect=20guardrail=20mo?= =?UTF-8?q?ck=5Fresponse=20during=20during=5Fcall=20to=20return=20blo?= =?UTF-8?q?=E2=80=A6"=20(#17332)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 6de610767340cadd6df1c5508325128045c8fae5. --- litellm/proxy/common_request_processing.py | 23 ++--- .../proxy/test_common_request_processing.py | 99 +------------------ 2 files changed, 11 insertions(+), 111 deletions(-) diff --git a/litellm/proxy/common_request_processing.py b/litellm/proxy/common_request_processing.py index ed4c451f8d3..d2b04410026 100644 --- a/litellm/proxy/common_request_processing.py +++ b/litellm/proxy/common_request_processing.py @@ -536,11 +536,7 @@ class ProxyBaseLLMRequestProcessing: responses = await llm_responses - # Guardrails (pre/during-call) can inject a mock response to short-circuit the LLM call. - # Prefer it when present so blocked/filtered output is returned instead of the model response. - response = self.data.get("mock_response") - if response is None: - response = responses[1] + response = responses[1] hidden_params = getattr(response, "_hidden_params", {}) or {} model_id = hidden_params.get("model_id", None) or "" @@ -808,7 +804,7 @@ class ProxyBaseLLMRequestProcessing: # This matches the original behavior before the refactor in commit 511d435f6f error_body = await e.response.aread() error_text = error_body.decode("utf-8") - + raise HTTPException( status_code=e.response.status_code, detail={"error": error_text}, @@ -1076,9 +1072,9 @@ class ProxyBaseLLMRequestProcessing: # Add cache-related fields to **params (handled by Usage.__init__) if cache_creation_input_tokens is not None: - usage_kwargs[ - "cache_creation_input_tokens" - ] = cache_creation_input_tokens + usage_kwargs["cache_creation_input_tokens"] = ( + cache_creation_input_tokens + ) if cache_read_input_tokens is not None: usage_kwargs["cache_read_input_tokens"] = cache_read_input_tokens @@ -1097,9 +1093,7 @@ class ProxyBaseLLMRequestProcessing: return obj return None - def maybe_get_model_id( - self, _logging_obj: Optional[LiteLLMLoggingObj] - ) -> Optional[str]: + def maybe_get_model_id(self, _logging_obj: Optional[LiteLLMLoggingObj]) -> Optional[str]: """ Get model_id from logging object or request metadata. @@ -1109,7 +1103,10 @@ class ProxyBaseLLMRequestProcessing: model_id = None if _logging_obj: # 1. Try getting from litellm_params (updated during call) - if hasattr(_logging_obj, "litellm_params") and _logging_obj.litellm_params: + if ( + hasattr(_logging_obj, "litellm_params") + and _logging_obj.litellm_params + ): # First check direct model_info path (set by router.py with selected deployment) model_info = _logging_obj.litellm_params.get("model_info") or {} model_id = model_info.get("id", None) diff --git a/tests/test_litellm/proxy/test_common_request_processing.py b/tests/test_litellm/proxy/test_common_request_processing.py index 8f5f182f429..4768ec42ff6 100644 --- a/tests/test_litellm/proxy/test_common_request_processing.py +++ b/tests/test_litellm/proxy/test_common_request_processing.py @@ -1,13 +1,11 @@ import copy -from types import SimpleNamespace from unittest.mock import AsyncMock, MagicMock import pytest -from fastapi import Request, Response, status +from fastapi import Request, status from fastapi.responses import StreamingResponse import litellm -import litellm.proxy.common_request_processing as common_request_processing from litellm._uuid import uuid from litellm.integrations.opentelemetry import UserAPIKeyAuth from litellm.proxy.common_request_processing import ( @@ -77,101 +75,6 @@ class TestProxyBaseLLMRequestProcessing: pytest.fail("litellm_call_id is not a valid UUID") assert data_passed["litellm_call_id"] == returned_data["litellm_call_id"] - @pytest.mark.asyncio - async def test_base_process_llm_request_prefers_guardrail_mock_response( - self, monkeypatch - ): - processing_obj = ProxyBaseLLMRequestProcessing( - data={ - "messages": [], - "metadata": {}, - "litellm_metadata": {"model_info": {"id": "fallback-model"}}, - } - ) - - guardrail_response = litellm.ModelResponse( - model="bedrock-guardrail", - hidden_params={"model_id": "guardrail-model"}, - ) - llm_response = litellm.ModelResponse( - model="real-model", - hidden_params={"model_id": "real-model"}, - ) - - async def mock_common_processing(self, *args, **kwargs): - logging_obj = SimpleNamespace(litellm_call_id="test-call-id") - self.data["litellm_call_id"] = "test-call-id" - self.data["litellm_logging_obj"] = logging_obj - return self.data, logging_obj - - monkeypatch.setattr( - ProxyBaseLLMRequestProcessing, - "common_processing_pre_call_logic", - mock_common_processing, - ) - - async def mock_route_request(*args, **kwargs): - async def _inner(): - return llm_response - - return _inner() - - monkeypatch.setattr( - common_request_processing, - "route_request", - mock_route_request, - ) - - check_response_size_is_safe_mock = AsyncMock() - monkeypatch.setattr( - common_request_processing, - "check_response_size_is_safe", - check_response_size_is_safe_mock, - ) - - async def mock_during_call_hook(*args, **kwargs): - kwargs["data"]["mock_response"] = guardrail_response - - proxy_logging_obj = MagicMock(spec=ProxyLogging) - proxy_logging_obj.during_call_hook = AsyncMock( - side_effect=mock_during_call_hook - ) - proxy_logging_obj.update_request_status = AsyncMock(return_value=None) - proxy_logging_obj.post_call_success_hook = AsyncMock( - return_value=guardrail_response - ) - - user_api_key_dict = MagicMock(spec=UserAPIKeyAuth) - user_api_key_dict.tpm_limit = None - user_api_key_dict.rpm_limit = None - user_api_key_dict.max_budget = None - user_api_key_dict.spend = 0 - user_api_key_dict.allowed_model_region = None - - fastapi_response = Response() - proxy_config = MagicMock(spec=ProxyConfig) - - result = await processing_obj.base_process_llm_request( - request=MagicMock(spec=Request), - fastapi_response=fastapi_response, - user_api_key_dict=user_api_key_dict, - route_type="acompletion", - proxy_logging_obj=proxy_logging_obj, - general_settings={}, - proxy_config=proxy_config, - select_data_generator=lambda **kwargs: None, - ) - - assert result is guardrail_response - assert ( - proxy_logging_obj.post_call_success_hook.await_args.kwargs["response"] - is guardrail_response - ) - assert ( - check_response_size_is_safe_mock.await_args.kwargs["response"] - is guardrail_response - ) - @pytest.mark.asyncio async def test_stream_timeout_header_processing(self): """ From be920d75d361519b61f43809b771bc7b107eaf85 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Tue, 2 Dec 2025 04:25:26 +0200 Subject: [PATCH 17/47] Add `claude-opus-4-5` alias (#17313) Similar to `claude-sonnet-4-5`. --- model_prices_and_context_window.json | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index af63d1e2592..6b9b8beed80 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -6717,6 +6717,33 @@ "supports_vision": true, "tool_use_system_prompt_tokens": 159 }, + "claude-opus-4-5": { + "cache_creation_input_token_cost": 6.25e-06, + "cache_creation_input_token_cost_above_1hr": 1e-05, + "cache_read_input_token_cost": 5e-07, + "input_cost_per_token": 5e-06, + "litellm_provider": "anthropic", + "max_input_tokens": 200000, + "max_output_tokens": 64000, + "max_tokens": 64000, + "mode": "chat", + "output_cost_per_token": 2.5e-05, + "search_context_cost_per_query": { + "search_context_size_high": 0.01, + "search_context_size_low": 0.01, + "search_context_size_medium": 0.01 + }, + "supports_assistant_prefill": true, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true, + "tool_use_system_prompt_tokens": 159 + }, "claude-sonnet-4-20250514": { "deprecation_date": "2026-05-14", "cache_creation_input_token_cost": 3.75e-06, From 37ecb03d4f0b8bd9695126c8f0beb68ed978f7d1 Mon Sep 17 00:00:00 2001 From: Elias <55650958+eliasto@users.noreply.github.com> Date: Mon, 1 Dec 2025 21:26:39 -0500 Subject: [PATCH 18/47] Add support of audio transcription for OVHcloud (#17305) --- docs/my-website/docs/audio_transcription.md | 3 +- docs/my-website/docs/providers/ovhcloud.md | 15 ++ .../get_supported_openai_params.py | 9 + .../audio_transcription/transformation.py | 156 ++++++++++++++++++ litellm/utils.py | 6 + provider_endpoints_support.json | 2 +- ...loud_audio_transcription_transformation.py | 59 +++++++ 7 files changed, 248 insertions(+), 2 deletions(-) create mode 100644 litellm/llms/ovhcloud/audio_transcription/transformation.py create mode 100644 tests/test_litellm/llms/ovhcloud/test_ovhcloud_audio_transcription_transformation.py diff --git a/docs/my-website/docs/audio_transcription.md b/docs/my-website/docs/audio_transcription.md index fd55cc66e92..5853b5c1872 100644 --- a/docs/my-website/docs/audio_transcription.md +++ b/docs/my-website/docs/audio_transcription.md @@ -13,7 +13,7 @@ import TabItem from '@theme/TabItem'; | Fallbacks | ✅ | Works between supported models | | Loadbalancing | ✅ | Works between supported models | | Guardrails | ✅ | Applies to output transcribed text (non-streaming only) | -| Supported Providers | `openai`, `azure`, `vertex_ai`, `gemini`, `deepgram`, `groq`, `fireworks_ai` | | +| Supported Providers | `openai`, `azure`, `vertex_ai`, `gemini`, `deepgram`, `groq`, `fireworks_ai`, `ovhcloud` | | ## Quick Start @@ -126,6 +126,7 @@ transcript = client.audio.transcriptions.create( - [Fireworks AI](./providers/fireworks_ai.md#audio-transcription) - [Groq](./providers/groq.md#speech-to-text---whisper) - [Deepgram](./providers/deepgram.md) +- [OVHcloud AI Endpoints](./providers/ovhcloud.md) --- diff --git a/docs/my-website/docs/providers/ovhcloud.md b/docs/my-website/docs/providers/ovhcloud.md index 6c42208f2cc..94625b0f2ed 100644 --- a/docs/my-website/docs/providers/ovhcloud.md +++ b/docs/my-website/docs/providers/ovhcloud.md @@ -311,6 +311,21 @@ response = embedding( print(response.data) ``` +### Audio Transcription + +```python +from litellm import transcription + +audio_file = open("path/to/your/audio.wav", "rb") + +response = transcription( + model="ovhcloud/whisper-large-v3-turbo", + file=audio_file +) + +print(response.text) +``` + ## Usage with LiteLLM Proxy Server Here's how to call a OVHCloud AI Endpoints model with the LiteLLM Proxy Server diff --git a/litellm/litellm_core_utils/get_supported_openai_params.py b/litellm/litellm_core_utils/get_supported_openai_params.py index 06e650f938d..19b52d2dace 100644 --- a/litellm/litellm_core_utils/get_supported_openai_params.py +++ b/litellm/litellm_core_utils/get_supported_openai_params.py @@ -266,6 +266,15 @@ def get_supported_openai_params( # noqa: PLR0915 model=model ) ) + elif custom_llm_provider == "ovhcloud": + if request_type == "transcription": + from litellm.llms.ovhcloud.audio_transcription.transformation import ( + OVHCloudAudioTranscriptionConfig, + ) + + return OVHCloudAudioTranscriptionConfig().get_supported_openai_params( + model=model + ) elif custom_llm_provider == "elevenlabs": if request_type == "transcription": from litellm.llms.elevenlabs.audio_transcription.transformation import ( diff --git a/litellm/llms/ovhcloud/audio_transcription/transformation.py b/litellm/llms/ovhcloud/audio_transcription/transformation.py new file mode 100644 index 00000000000..7233d911b07 --- /dev/null +++ b/litellm/llms/ovhcloud/audio_transcription/transformation.py @@ -0,0 +1,156 @@ +""" +Support for OVHCloud AI Endpoints `/v1/audio/transcriptions` endpoint. + +Our unified API follows the OpenAI standard. +More information on our website: https://endpoints.ai.cloud.ovh.net +""" + +from typing import List, Optional, Union + +import httpx + +from litellm.litellm_core_utils.audio_utils.utils import process_audio_file +from litellm.llms.base_llm.audio_transcription.transformation import ( + AudioTranscriptionRequestData, + BaseAudioTranscriptionConfig, +) +from litellm.llms.base_llm.chat.transformation import BaseLLMException +from litellm.secret_managers.main import get_secret_str +from litellm.types.llms.openai import ( + AllMessageValues, + OpenAIAudioTranscriptionOptionalParams, +) +from litellm.types.utils import FileTypes, TranscriptionResponse + +from ..utils import OVHCloudException + + +class OVHCloudAudioTranscriptionConfig(BaseAudioTranscriptionConfig): + def get_supported_openai_params( + self, model: str + ) -> List[OpenAIAudioTranscriptionOptionalParams]: + # OVHCloud implements the OpenAI-compatible Whisper interface. + # We pass through the same optional params as the OpenAI Whisper API. + return ["language", "prompt", "response_format", "timestamp_granularities", "temperature"] + + def map_openai_params( + self, + non_default_params: dict, + optional_params: dict, + model: str, + drop_params: bool, + ) -> dict: + supported_params = self.get_supported_openai_params(model) + for k, v in non_default_params.items(): + if k in supported_params: + optional_params[k] = v + return optional_params + + def get_complete_url( + self, + api_base: Optional[str], + api_key: Optional[str], + model: str, + optional_params: dict, + litellm_params: dict, + stream: Optional[bool] = None, + ) -> str: + api_base = ( + "https://oai.endpoints.kepler.ai.cloud.ovh.net/v1" + if api_base is None + else api_base.rstrip("/") + ) + complete_url = f"{api_base}/audio/transcriptions" + return complete_url + + def get_error_class( + self, error_message: str, status_code: int, headers: Union[dict, httpx.Headers] + ) -> BaseLLMException: + return OVHCloudException( + message=error_message, + status_code=status_code, + headers=headers, + ) + + def validate_environment( + self, + headers: dict, + model: str, + messages: List[AllMessageValues], + optional_params: dict, + litellm_params: dict, + api_key: Optional[str] = None, + api_base: Optional[str] = None, + ) -> dict: + if api_key is None: + api_key = get_secret_str("OVHCLOUD_API_KEY") + + default_headers = { + "Authorization": f"Bearer {api_key}", + "accept": "application/json", + } + + # Caller can override / extend headers if needed + default_headers.update(headers or {}) + return default_headers + + def transform_audio_transcription_request( + self, + model: str, + audio_file: FileTypes, + optional_params: dict, + litellm_params: dict, + ) -> AudioTranscriptionRequestData: + """ + Transform the audio transcription request into OpenAI-compatible form-data. + + OVHCloud follows OpenAI's `/audio/transcriptions` format, so we: + - Build a multipart form-data body with `file`, `model`, and optional params + - Let the shared HTTP handler set the proper content-type boundary + """ + processed_audio = process_audio_file(audio_file) + + # Base form fields: model + OpenAI-compatible optional params + form_fields: dict = { + "model": model, + } + + # Include OpenAI-compatible optional params + for key in self.get_supported_openai_params(model): + value = optional_params.get(key) + if value is not None: + form_fields[key] = value + + files = { + "file": ( + processed_audio.filename, + processed_audio.file_content, + processed_audio.content_type, + ) + } + + return AudioTranscriptionRequestData(data=form_fields, files=files) + + def transform_audio_transcription_response( + self, + raw_response: httpx.Response, + ) -> TranscriptionResponse: + """ + Transform OVHCloud audio transcription response to OpenAI-compatible TranscriptionResponse. + """ + try: + response_json = raw_response.json() + except Exception: + raise OVHCloudException( + message=raw_response.text, + status_code=raw_response.status_code, + headers=raw_response.headers, + ) + + text = response_json.get("text") or response_json.get("transcript") or "" + response = TranscriptionResponse(text=text) + + response._hidden_params = response_json + return response + + diff --git a/litellm/utils.py b/litellm/utils.py index f74c3aa0693..37a71b43476 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -7384,6 +7384,12 @@ class ProviderConfigManager: ) return IBMWatsonXAudioTranscriptionConfig() + elif litellm.LlmProviders.OVHCLOUD == provider: + from litellm.llms.ovhcloud.audio_transcription.transformation import ( + OVHCloudAudioTranscriptionConfig, + ) + + return OVHCloudAudioTranscriptionConfig() return None @staticmethod diff --git a/provider_endpoints_support.json b/provider_endpoints_support.json index 5eab130cdd3..b5bde3e5ce4 100644 --- a/provider_endpoints_support.json +++ b/provider_endpoints_support.json @@ -1272,7 +1272,7 @@ "responses": true, "embeddings": false, "image_generations": false, - "audio_transcriptions": false, + "audio_transcriptions": true, "audio_speech": false, "moderations": false, "batches": false, diff --git a/tests/test_litellm/llms/ovhcloud/test_ovhcloud_audio_transcription_transformation.py b/tests/test_litellm/llms/ovhcloud/test_ovhcloud_audio_transcription_transformation.py new file mode 100644 index 00000000000..fc5e310e71b --- /dev/null +++ b/tests/test_litellm/llms/ovhcloud/test_ovhcloud_audio_transcription_transformation.py @@ -0,0 +1,59 @@ +import os +from typing import Dict + +import litellm +import pytest + +from litellm.llms.base_llm.audio_transcription.transformation import ( + BaseAudioTranscriptionConfig, +) +from litellm.utils import ProviderConfigManager +from tests.llm_translation.base_audio_transcription_unit_tests import ( + BaseLLMAudioTranscriptionTest, +) + + +@pytest.mark.skipif( + not os.getenv("OVHCLOUD_API_KEY"), + reason="OVHCLOUD_API_KEY not set, skipping OVHCloud audio transcription tests", +) +class TestOVHCloudAudioTranscription(BaseLLMAudioTranscriptionTest): + def get_base_audio_transcription_call_args(self) -> Dict: + return { + "model": "ovhcloud/whisper-large-v3-turbo", + } + + def get_custom_llm_provider(self) -> litellm.LlmProviders: + return litellm.LlmProviders.OVHCLOUD + + # Override the async base test with a sync no-op to avoid + # 'async def functions are not natively supported' failures when + # running this file in isolation without pytest-asyncio. + def test_audio_transcription_async(self): # type: ignore[override] + pytest.skip( + "Async audio transcription test for OVHCloud is skipped in this suite; " + "async test plugins (e.g. pytest-asyncio/anyio) are not configured here." + ) + + +@pytest.mark.skipif( + not os.getenv("OVHCLOUD_API_KEY"), + reason="OVHCLOUD_API_KEY not set, skipping OVHCloud audio transcription config test", +) +def test_ovhcloud_audio_transcription_config_installed(): + """ + Ensure OVHCloud audio transcription config is registered with ProviderConfigManager. + """ + model = "ovhcloud/whisper-large-v3-turbo" + provider = litellm.LlmProviders.OVHCLOUD + + config = ProviderConfigManager.get_provider_audio_transcription_config( + model=model, + provider=provider, + ) + + assert config is not None + assert isinstance(config, BaseAudioTranscriptionConfig) + + + From 860cdc81d3a540c64d17cc6112ac577f1f9dd926 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Mon, 1 Dec 2025 18:26:56 -0800 Subject: [PATCH 19/47] [Fix] Fix Watsonx Audio Transcription API (#17326) * """ add * fix transform_audio_transcription_request * fix tests * test_watsonx_transcription_request_body --- .../audio_transcription/transformation.py | 78 ++++++++++++++++--- litellm/types/llms/watsonx.py | 36 ++++++++- ...sonx_audio_transcription_transformation.py | 35 ++++++++- 3 files changed, 131 insertions(+), 18 deletions(-) diff --git a/litellm/llms/watsonx/audio_transcription/transformation.py b/litellm/llms/watsonx/audio_transcription/transformation.py index 8c8324cb72d..8fe8b4a4248 100644 --- a/litellm/llms/watsonx/audio_transcription/transformation.py +++ b/litellm/llms/watsonx/audio_transcription/transformation.py @@ -4,11 +4,17 @@ Translates from OpenAI's `/v1/audio/transcriptions` to IBM WatsonX's `/ml/v1/aud WatsonX follows the OpenAI spec for audio transcription. """ -from typing import List, Optional +from typing import Any, Dict, List, Optional import litellm +from litellm.litellm_core_utils.audio_utils.utils import process_audio_file from litellm.types.llms.openai import OpenAIAudioTranscriptionOptionalParams +from litellm.types.llms.watsonx import WatsonXAudioTranscriptionRequestBody +from litellm.types.utils import FileTypes +from ...base_llm.audio_transcription.transformation import ( + AudioTranscriptionRequestData, +) from ...openai.transcriptions.whisper_transformation import ( OpenAIWhisperAudioTranscriptionConfig, ) @@ -40,6 +46,60 @@ class IBMWatsonXAudioTranscriptionConfig( "timestamp_granularities", ] + def transform_audio_transcription_request( + self, + model: str, + audio_file: FileTypes, + optional_params: dict, + litellm_params: dict, + ) -> AudioTranscriptionRequestData: + """ + Transform the audio transcription request for WatsonX. + + WatsonX expects multipart/form-data with: + - file: the audio file + - model: the model name (without watsonx/ prefix) + - project_id: the project ID (as form field, not query param) + - other optional params + """ + # Use common utility to process the audio file + processed_audio = process_audio_file(audio_file) + + # Get API params to extract project_id + api_params = _get_api_params(params=optional_params.copy()) + + # Initialize form data with required fields + form_data: WatsonXAudioTranscriptionRequestBody = { + "model": model, + "project_id": api_params.get("project_id", ""), + } + + # Add supported OpenAI params to form data + supported_params = self.get_supported_openai_params(model) + for key, value in optional_params.items(): + if key in supported_params and value is not None: + form_data[key] = value # type: ignore + + # Set default response_format for cost calculation + if "response_format" not in form_data or ( + form_data.get("response_format") in ["text", "json"] + ): + form_data["response_format"] = "verbose_json" + + # Prepare files dict with the audio file + files = { + "file": ( + processed_audio.filename, + processed_audio.file_content, + processed_audio.content_type, + ) + } + + # Convert TypedDict to regular dict for AudioTranscriptionRequestData + form_data_dict: Dict[str, Any] = dict(form_data) + + return AudioTranscriptionRequestData(data=form_data_dict, files=files) + def get_complete_url( self, api_base: Optional[str], @@ -52,7 +112,9 @@ class IBMWatsonXAudioTranscriptionConfig( """ Construct the complete URL for WatsonX audio transcription. - URL format: {api_base}/ml/v1/audio/transcriptions?version={version}&project_id={project_id} + URL format: {api_base}/ml/v1/audio/transcriptions?version={version} + + Note: project_id is sent as form data, not as a query parameter """ # Get base URL url = self._get_base_url(api_base=api_base) @@ -61,18 +123,10 @@ class IBMWatsonXAudioTranscriptionConfig( # Add the audio transcription endpoint url = f"{url}/ml/v1/audio/transcriptions" - # Get API params for project_id - api_params = _get_api_params(params=optional_params.copy()) - - # Add version parameter - api_version = optional_params.pop( + # Add version parameter (only version in query string, not project_id) + api_version = optional_params.get( "api_version", None ) or litellm.WATSONX_DEFAULT_API_VERSION url = f"{url}?version={api_version}" - # Add project_id parameter - project_id = api_params.get("project_id") - if project_id: - url = f"{url}&project_id={project_id}" - return url diff --git a/litellm/types/llms/watsonx.py b/litellm/types/llms/watsonx.py index 4eb2f2531a0..6c42c3ecea0 100644 --- a/litellm/types/llms/watsonx.py +++ b/litellm/types/llms/watsonx.py @@ -1,9 +1,7 @@ -import json from enum import Enum -from typing import Any, List, Optional, Union +from typing import List, Optional -from pydantic import BaseModel -from typing_extensions import TypedDict +from typing_extensions import NotRequired, TypedDict class WatsonXAPIParams(TypedDict): @@ -18,6 +16,36 @@ class WatsonXCredentials(TypedDict): token: Optional[str] +class WatsonXAudioTranscriptionRequestBody(TypedDict): + """ + WatsonX Audio Transcription API request body. + + Follows multipart/form-data format for WatsonX Whisper models. + See: https://cloud.ibm.com/apidocs/watsonx-ai + """ + + model: str + """Model name (e.g., 'whisper-large-v3-turbo')""" + + project_id: str + """WatsonX project ID (required)""" + + language: NotRequired[str] + """Language code (e.g., 'en', 'es')""" + + prompt: NotRequired[str] + """Optional prompt to guide transcription""" + + response_format: NotRequired[str] + """Response format: 'json', 'text', 'srt', 'verbose_json', 'vtt'""" + + temperature: NotRequired[float] + """Sampling temperature (0-1)""" + + timestamp_granularities: NotRequired[List[str]] + """Timestamp granularities: ['word', 'segment']""" + + class WatsonXAIEndpoint(str, Enum): TEXT_GENERATION = "/ml/v1/text/generation" TEXT_GENERATION_STREAM = "/ml/v1/text/generation_stream" diff --git a/tests/test_litellm/llms/watsonx/audio_transcription/test_watsonx_audio_transcription_transformation.py b/tests/test_litellm/llms/watsonx/audio_transcription/test_watsonx_audio_transcription_transformation.py index 84a9d25d98e..1286c2d4fe6 100644 --- a/tests/test_litellm/llms/watsonx/audio_transcription/test_watsonx_audio_transcription_transformation.py +++ b/tests/test_litellm/llms/watsonx/audio_transcription/test_watsonx_audio_transcription_transformation.py @@ -4,6 +4,7 @@ Tests for IBM WatsonX Audio Transcription. Validates that litellm.transcription transforms requests correctly for WatsonX. """ +import json import os import sys from unittest.mock import AsyncMock, MagicMock, patch @@ -29,6 +30,7 @@ class TestWatsonXAudioTranscription: captured_request["url"] = str(kwargs.get("url", args[0] if args else None)) captured_request["headers"] = kwargs.get("headers", {}) captured_request["data"] = kwargs.get("data", {}) + captured_request["files"] = kwargs.get("files", {}) mock_response = MagicMock() mock_response.json.return_value = { @@ -54,16 +56,30 @@ class TestWatsonXAudioTranscription: # Validate URL contains WatsonX audio transcription endpoint assert "/ml/v1/audio/transcriptions" in captured_request["url"] assert "version=" in captured_request["url"] - assert "project_id=test-project-123" in captured_request["url"] + # project_id should NOT be in URL (it should be in form data instead) + assert "project_id=test-project-123" not in captured_request["url"] # Validate headers contain WatsonX auth assert "Authorization" in captured_request["headers"] assert "Bearer test-bearer-token" in captured_request["headers"]["Authorization"] + + # Validate project_id is in form data, not URL + assert captured_request["data"].get("project_id") == "test-project-123" + + # Validate file is in files dict + assert "file" in captured_request["files"] @pytest.mark.asyncio async def test_watsonx_transcription_request_body(self): """ Test that litellm.transcription sends correct request body for WatsonX. + + Validates that: + - Request uses multipart/form-data (data + files) + - Model name has watsonx/ prefix removed + - project_id is in form data, not URL + - Audio file is in files dict + - OpenAI params are included in form data """ captured_request = {} @@ -94,9 +110,24 @@ class TestWatsonXAudioTranscription: except Exception: pass # We just want to capture the request - # Validate request body contains expected fields + # Validate form data contains expected fields data = captured_request.get("data", {}) + + print("JSON DUMPS captured_request:") + print(json.dumps(captured_request, indent=4, default=str)) + + # Model name should NOT have watsonx/ prefix assert data.get("model") == "whisper-large-v3-turbo" + + # project_id should be in form data + assert data.get("project_id") == "test-project-123" + + # OpenAI params should be in form data assert data.get("language") == "en" assert data.get("temperature") == 0.5 assert data.get("response_format") == "verbose_json" # Default for cost calculation + + # Validate file is in files dict (multipart/form-data) + files = captured_request.get("files", {}) + assert "file" in files + assert isinstance(files["file"], tuple) # Should be (filename, content, content_type) From 1cdfb3da8fb81c293ed94a8628ce9dafbc703542 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Mon, 1 Dec 2025 19:14:12 -0800 Subject: [PATCH 20/47] [Bug Fix] - Fix `litellm_enterprise` ensure imported routes exist (#17337) * test_enterprise_routes.py * test_enterprise_routes_all_imports_exist --- .../proxy/enterprise_routes.py | 4 - .../test_litellm/enterprise/proxy/__init__.py | 0 .../proxy/test_enterprise_routes.py | 78 +++++++++++++++++++ 3 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 tests/test_litellm/enterprise/proxy/__init__.py create mode 100644 tests/test_litellm/enterprise/proxy/test_enterprise_routes.py diff --git a/enterprise/litellm_enterprise/proxy/enterprise_routes.py b/enterprise/litellm_enterprise/proxy/enterprise_routes.py index f3227892bbd..e28d8b8a4c6 100644 --- a/enterprise/litellm_enterprise/proxy/enterprise_routes.py +++ b/enterprise/litellm_enterprise/proxy/enterprise_routes.py @@ -5,14 +5,10 @@ from litellm_enterprise.enterprise_callbacks.send_emails.endpoints import ( ) from .audit_logging_endpoints import router as audit_logging_router -from .guardrails.endpoints import router as guardrails_router from .management_endpoints import management_endpoints_router from .utils import _should_block_robots -from .vector_stores.endpoints import router as vector_stores_router router = APIRouter() -router.include_router(vector_stores_router) -router.include_router(guardrails_router) router.include_router(email_events_router) router.include_router(audit_logging_router) router.include_router(management_endpoints_router) diff --git a/tests/test_litellm/enterprise/proxy/__init__.py b/tests/test_litellm/enterprise/proxy/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/test_litellm/enterprise/proxy/test_enterprise_routes.py b/tests/test_litellm/enterprise/proxy/test_enterprise_routes.py new file mode 100644 index 00000000000..a9bf33a21ac --- /dev/null +++ b/tests/test_litellm/enterprise/proxy/test_enterprise_routes.py @@ -0,0 +1,78 @@ +""" +Test enterprise_routes imports work correctly + +This validates that all imports can be resolved to prevent broken imports +from breaking the enterprise proxy initialization. +""" + +import ast +import os + +import pytest + + +def test_enterprise_routes_all_imports_exist(): + """ + Validate that all relative imports in enterprise_routes.py exist in the filesystem. + + This catches any import errors from moved/deleted modules without hardcoding + specific module names. Works by checking that imported files actually exist. + """ + # Path to the enterprise_routes.py source file + enterprise_routes_path = os.path.join( + os.path.dirname(__file__), + "..", "..", "..", "..", + "enterprise", "litellm_enterprise", "proxy", "enterprise_routes.py" + ) + + enterprise_routes_path = os.path.normpath(enterprise_routes_path) + enterprise_proxy_dir = os.path.dirname(enterprise_routes_path) + + if not os.path.exists(enterprise_routes_path): + pytest.skip(f"Enterprise routes file not found at {enterprise_routes_path}") + + # Read and parse the source file + with open(enterprise_routes_path, "r") as f: + source_code = f.read() + + try: + tree = ast.parse(source_code) + except SyntaxError as e: + pytest.fail(f"Syntax error in enterprise_routes.py: {e}") + + # Check all relative imports + missing_imports = [] + + for node in ast.walk(tree): + if isinstance(node, ast.ImportFrom): + # level > 0 means it's a relative import (. or .. etc) + if node.level and node.level > 0: + module = node.module or "" + + # Convert relative import to file path + # e.g., "audit_logging_endpoints" -> "audit_logging_endpoints.py" + # e.g., "vector_stores.endpoints" -> "vector_stores/endpoints.py" + module_path = module.replace(".", os.sep) if module else "" + + # Check both .py file and package directory + file_path = os.path.join(enterprise_proxy_dir, module_path + ".py") if module_path else None + package_path = os.path.join(enterprise_proxy_dir, module_path, "__init__.py") if module_path else None + + # If module is empty (e.g., "from . import something"), skip check + if not module: + continue + + file_exists = file_path and os.path.exists(file_path) + package_exists = package_path and os.path.exists(package_path) + + if not file_exists and not package_exists: + missing_imports.append( + f"Line {node.lineno}: Cannot find '.{module}' " + f"(checked: {file_path} and {package_path})" + ) + + if missing_imports: + error_msg = "Found imports in enterprise_routes.py that don't exist:\n" + error_msg += "\n".join(missing_imports) + error_msg += "\n\nThis usually means a module was moved or deleted but the import wasn't updated." + pytest.fail(error_msg) From 70126d91302233bdb4e4b6aecf5d81b462a94527 Mon Sep 17 00:00:00 2001 From: rioiart Date: Tue, 2 Dec 2025 04:51:42 +0100 Subject: [PATCH 21/47] Fix/new org team validate against org (#17333) * fix: skip user budget/model validation for org-scoped teams When creating a team with organization_id, budget and model constraints should be validated against the organization's limits, not the user's personal limits. This allows org admins with restrictive personal budgets to create teams within their organization's more generous limits. Adds 4 unit tests to verify: - Org-scoped teams bypass user budget validation - Org-scoped teams bypass user model validation - Standalone teams still validate against user limits * fix: enforce user budget/model limits for standalone teams in update_team - Add user-level budget and model validation to update_team endpoint for standalone teams, matching the existing pattern in new_team - Org-scoped teams correctly bypass user validation and use organization limits instead - Add 5 new comprehensive tests covering standalone/org team budget/model validation * fix: Add direct TPM/RPM org limit validation and consolidate user team limit checks - Add direct TPM/RPM comparison against org limits in _check_org_team_limits() - Consolidate budget/models/TPM/RPM user validation into _check_user_team_limits() helper - Ensure user limits only apply to standalone teams (organization_id=None) - Org-scoped teams now validate TPM/RPM against org limits (not user limits) - Add 8 tests for TPM/RPM validation scenarios (org and user limits) - Reduce code duplication between new_team() and update_team() --- .../management_endpoints/team_endpoints.py | 496 +++-- .../test_team_endpoints.py | 1602 +++++++++++++++++ 2 files changed, 1901 insertions(+), 197 deletions(-) diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py index 6d4faae5fd8..b697e01a6ef 100644 --- a/litellm/proxy/management_endpoints/team_endpoints.py +++ b/litellm/proxy/management_endpoints/team_endpoints.py @@ -461,11 +461,65 @@ async def _check_org_team_limits( prisma_client: PrismaClient, ) -> None: """ - Check if the organization team is allocating guaranteed throughput limits. If so, raise an error if we're overallocating. - - Only runs check if tpm_limit_type or rpm_limit_type is "guaranteed_throughput" + Check organization team limits including: + - Team budget vs organization's max_budget + - Team models vs organization's allowed models + - Guaranteed throughput limits (tpm/rpm) if applicable """ + # Validate team budget against organization's max_budget + if ( + data.max_budget is not None + and org_table.litellm_budget_table is not None + and org_table.litellm_budget_table.max_budget is not None + and data.max_budget > org_table.litellm_budget_table.max_budget + ): + raise HTTPException( + status_code=400, + detail={ + "error": f"Team max_budget ({data.max_budget}) exceeds organization's max_budget ({org_table.litellm_budget_table.max_budget}). Organization: {org_table.organization_id}" + }, + ) + + # Validate team models against organization's allowed models + if data.models is not None and len(org_table.models) > 0: + for m in data.models: + if m not in org_table.models: + raise HTTPException( + status_code=400, + detail={ + "error": f"Model '{m}' not in organization's allowed models. Organization allowed models={org_table.models}. Organization: {org_table.organization_id}" + }, + ) + + # Validate team TPM/RPM against organization's TPM/RPM limits (direct comparison) + if ( + data.tpm_limit is not None + and org_table.litellm_budget_table is not None + and org_table.litellm_budget_table.tpm_limit is not None + and data.tpm_limit > org_table.litellm_budget_table.tpm_limit + ): + raise HTTPException( + status_code=400, + detail={ + "error": f"Team tpm_limit ({data.tpm_limit}) exceeds organization's tpm_limit ({org_table.litellm_budget_table.tpm_limit}). Organization: {org_table.organization_id}" + }, + ) + + if ( + data.rpm_limit is not None + and org_table.litellm_budget_table is not None + and org_table.litellm_budget_table.rpm_limit is not None + and data.rpm_limit > org_table.litellm_budget_table.rpm_limit + ): + raise HTTPException( + status_code=400, + detail={ + "error": f"Team rpm_limit ({data.rpm_limit}) exceeds organization's rpm_limit ({org_table.litellm_budget_table.rpm_limit}). Organization: {org_table.organization_id}" + }, + ) + + # Check guaranteed throughput limits (only if applicable) rpm_limit_type = getattr(data, "rpm_limit_type", None) or ( data.metadata.get("rpm_limit_type", None) if data.metadata else None ) @@ -503,6 +557,80 @@ async def _check_org_team_limits( ) +async def _check_user_team_limits( + data: Union[NewTeamRequest, UpdateTeamRequest], + user_api_key_dict: UserAPIKeyAuth, + prisma_client: PrismaClient, + user_api_key_cache: Any, +) -> None: + """ + Check user team limits for standalone teams (not org-scoped). + + This validates: + - Team budget vs user's max_budget + - Team models vs user's allowed models + + Should only be called for standalone teams (when organization_id is None). + For org-scoped teams, use _check_org_team_limits() instead. + """ + # Validate team budget against user's max_budget + if data.max_budget is not None and user_api_key_dict.user_id is not None: + user_obj = await get_user_object( + user_id=user_api_key_dict.user_id, + prisma_client=prisma_client, + user_api_key_cache=user_api_key_cache, + user_id_upsert=False, + ) + + if ( + user_obj is not None + and user_obj.max_budget is not None + and data.max_budget > user_obj.max_budget + ): + raise HTTPException( + status_code=400, + detail={ + "error": f"max budget higher than user max. User max budget={user_obj.max_budget}. User role={user_api_key_dict.user_role}" + }, + ) + + # Validate team models against user's allowed models + if data.models is not None and len(user_api_key_dict.models) > 0: + for m in data.models: + if m not in user_api_key_dict.models: + raise HTTPException( + status_code=400, + detail={ + "error": f"Model not in allowed user models. User allowed models={user_api_key_dict.models}. User id={user_api_key_dict.user_id}" + }, + ) + + # Validate team TPM/RPM against user's TPM/RPM limits + if ( + data.tpm_limit is not None + and user_api_key_dict.tpm_limit is not None + and data.tpm_limit > user_api_key_dict.tpm_limit + ): + raise HTTPException( + status_code=400, + detail={ + "error": f"tpm limit higher than user max. User tpm limit={user_api_key_dict.tpm_limit}. User role={user_api_key_dict.user_role}" + }, + ) + + if ( + data.rpm_limit is not None + and user_api_key_dict.rpm_limit is not None + and data.rpm_limit > user_api_key_dict.rpm_limit + ): + raise HTTPException( + status_code=400, + detail={ + "error": f"rpm limit higher than user max. User rpm limit={user_api_key_dict.rpm_limit}. User role={user_api_key_dict.user_role}" + }, + ) + + #### TEAM MANAGEMENT #### @router.post( "/team/new", @@ -665,61 +793,16 @@ async def new_team( # noqa: PLR0915 user_api_key_dict.user_role is None or user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN ): # don't restrict proxy admin - if ( - data.tpm_limit is not None - and user_api_key_dict.tpm_limit is not None - and data.tpm_limit > user_api_key_dict.tpm_limit - ): - raise HTTPException( - status_code=400, - detail={ - "error": f"tpm limit higher than user max. User tpm limit={user_api_key_dict.tpm_limit}. User role={user_api_key_dict.user_role}" - }, - ) - - if ( - data.rpm_limit is not None - and user_api_key_dict.rpm_limit is not None - and data.rpm_limit > user_api_key_dict.rpm_limit - ): - raise HTTPException( - status_code=400, - detail={ - "error": f"rpm limit higher than user max. User rpm limit={user_api_key_dict.rpm_limit}. User role={user_api_key_dict.user_role}" - }, - ) - - if data.max_budget is not None and user_api_key_dict.user_id is not None: - # Fetch user object to get max_budget - user_obj = await get_user_object( - user_id=user_api_key_dict.user_id, + # Only validate user budget/models/tpm/rpm for standalone teams (not org-scoped) + # For org-scoped teams, validation is done by _check_org_team_limits() + if data.organization_id is None: + await _check_user_team_limits( + data=data, + user_api_key_dict=user_api_key_dict, prisma_client=prisma_client, user_api_key_cache=user_api_key_cache, - user_id_upsert=False, ) - if ( - user_obj is not None - and user_obj.max_budget is not None - and data.max_budget > user_obj.max_budget - ): - raise HTTPException( - status_code=400, - detail={ - "error": f"max budget higher than user max. User max budget={user_obj.max_budget}. User role={user_api_key_dict.user_role}" - }, - ) - - if data.models is not None and len(user_api_key_dict.models) > 0: - for m in data.models: - if m not in user_api_key_dict.models: - raise HTTPException( - status_code=400, - detail={ - "error": f"Model not in allowed user models. User allowed models={user_api_key_dict.models}. User id={user_api_key_dict.user_id}" - }, - ) - if user_api_key_dict.user_id is not None: creating_user_in_list = False for member in data.members_with_roles: @@ -1151,168 +1234,187 @@ async def update_team( }' ``` """ - from litellm.proxy.auth.auth_checks import _cache_team_object - from litellm.proxy.proxy_server import ( - litellm_proxy_admin_name, - llm_router, - prisma_client, - proxy_logging_obj, - user_api_key_cache, - ) - - if prisma_client is None: - raise HTTPException( - status_code=500, - detail={"error": CommonProxyErrors.db_not_connected_error.value}, + try: + from litellm.proxy.auth.auth_checks import _cache_team_object + from litellm.proxy.proxy_server import ( + litellm_proxy_admin_name, + llm_router, + prisma_client, + proxy_logging_obj, + user_api_key_cache, ) - if data.team_id is None: - raise HTTPException(status_code=400, detail={"error": "No team id passed in"}) - verbose_proxy_logger.debug("/team/update - %s", data) - - existing_team_row = await prisma_client.db.litellm_teamtable.find_unique( - where={"team_id": data.team_id} - ) - - if existing_team_row is None: - raise HTTPException( - status_code=404, - detail={"error": f"Team not found, passed team_id={data.team_id}"}, - ) - - if ( - data.organization_id is not None and len(data.organization_id) > 0 - ): # allow unsetting the organization_id - await fetch_and_validate_organization( - organization_id=data.organization_id, - existing_team_row=existing_team_row, - llm_router=llm_router, - prisma_client=prisma_client, - ) - elif data.organization_id is not None and len(data.organization_id) == 0: - # unsetting the organization_id - data.organization_id = None - - # check org team limits - if updating team that belongs to an org - org_id_to_check = ( - data.organization_id - if data.organization_id is not None - else existing_team_row.organization_id - ) - if ( - org_id_to_check is not None - and isinstance(org_id_to_check, str) - and prisma_client is not None - ): - org_table = await get_org_object( - org_id=org_id_to_check, - user_api_key_cache=user_api_key_cache, - prisma_client=prisma_client, - ) - if org_table is not None: - await _check_org_team_limits( - org_table=org_table, - data=data, - prisma_client=prisma_client, + if prisma_client is None: + raise HTTPException( + status_code=500, + detail={"error": CommonProxyErrors.db_not_connected_error.value}, ) - updated_kv = data.json(exclude_unset=True) + if data.team_id is None: + raise HTTPException(status_code=400, detail={"error": "No team id passed in"}) + verbose_proxy_logger.debug("/team/update - %s", data) - # Check budget_duration and budget_reset_at - if data.budget_duration is not None: - from litellm.proxy.common_utils.timezone_utils import get_budget_reset_time + existing_team_row = await prisma_client.db.litellm_teamtable.find_unique( + where={"team_id": data.team_id} + ) - reset_at = get_budget_reset_time(budget_duration=data.budget_duration) + if existing_team_row is None: + raise HTTPException( + status_code=404, + detail={"error": f"Team not found, passed team_id={data.team_id}"}, + ) - # set the budget_reset_at in DB - updated_kv["budget_reset_at"] = reset_at + if ( + data.organization_id is not None and len(data.organization_id) > 0 + ): # allow unsetting the organization_id + await fetch_and_validate_organization( + organization_id=data.organization_id, + existing_team_row=existing_team_row, + llm_router=llm_router, + prisma_client=prisma_client, + ) + elif data.organization_id is not None and len(data.organization_id) == 0: + # unsetting the organization_id + data.organization_id = None - if TeamMemberBudgetHandler.should_create_budget( - team_member_budget=data.team_member_budget, - team_member_rpm_limit=data.team_member_rpm_limit, - team_member_tpm_limit=data.team_member_tpm_limit, - ): - updated_kv = await TeamMemberBudgetHandler.upsert_team_member_budget_table( - team_table=existing_team_row, - user_api_key_dict=user_api_key_dict, - updated_kv=updated_kv, + # check org team limits - if updating team that belongs to an org + org_id_to_check = ( + data.organization_id + if data.organization_id is not None + else existing_team_row.organization_id + ) + if ( + org_id_to_check is not None + and isinstance(org_id_to_check, str) + and prisma_client is not None + ): + org_table = await get_org_object( + org_id=org_id_to_check, + user_api_key_cache=user_api_key_cache, + prisma_client=prisma_client, + ) + if org_table is not None: + await _check_org_team_limits( + org_table=org_table, + data=data, + prisma_client=prisma_client, + ) + + # Check user limits for standalone teams (not org-scoped) + # Skip for PROXY_ADMIN users + if ( + user_api_key_dict.user_role is None + or user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN + ): + # Only validate user budget/models for standalone teams + # For org-scoped teams, validation is done by _check_org_team_limits() above + if org_id_to_check is None: + await _check_user_team_limits( + data=data, + user_api_key_dict=user_api_key_dict, + prisma_client=prisma_client, + user_api_key_cache=user_api_key_cache, + ) + + updated_kv = data.json(exclude_unset=True) + + # Check budget_duration and budget_reset_at + if data.budget_duration is not None: + from litellm.proxy.common_utils.timezone_utils import get_budget_reset_time + + reset_at = get_budget_reset_time(budget_duration=data.budget_duration) + + # set the budget_reset_at in DB + updated_kv["budget_reset_at"] = reset_at + + if TeamMemberBudgetHandler.should_create_budget( team_member_budget=data.team_member_budget, team_member_rpm_limit=data.team_member_rpm_limit, team_member_tpm_limit=data.team_member_tpm_limit, - ) - else: - TeamMemberBudgetHandler._clean_team_member_fields(updated_kv) - - # Check object permission - if data.object_permission is not None: - updated_kv = await handle_update_object_permission( - data_json=updated_kv, - existing_team_row=existing_team_row, - ) - - # update team metadata fields - _team_metadata_fields = LiteLLM_ManagementEndpoint_MetadataFields_Premium - for field in _team_metadata_fields: - if field in updated_kv and updated_kv[field] is not None: - _update_metadata_field( + ): + updated_kv = await TeamMemberBudgetHandler.upsert_team_member_budget_table( + team_table=existing_team_row, + user_api_key_dict=user_api_key_dict, updated_kv=updated_kv, - field_name=field, + team_member_budget=data.team_member_budget, + team_member_rpm_limit=data.team_member_rpm_limit, + team_member_tpm_limit=data.team_member_tpm_limit, + ) + else: + TeamMemberBudgetHandler._clean_team_member_fields(updated_kv) + + # Check object permission + if data.object_permission is not None: + updated_kv = await handle_update_object_permission( + data_json=updated_kv, + existing_team_row=existing_team_row, ) - for field in LiteLLM_ManagementEndpoint_MetadataFields: - if field in updated_kv and updated_kv[field] is not None: - _update_metadata_field( - updated_kv=updated_kv, - field_name=field, + # update team metadata fields + _team_metadata_fields = LiteLLM_ManagementEndpoint_MetadataFields_Premium + for field in _team_metadata_fields: + if field in updated_kv and updated_kv[field] is not None: + _update_metadata_field( + updated_kv=updated_kv, + field_name=field, + ) + + for field in LiteLLM_ManagementEndpoint_MetadataFields: + if field in updated_kv and updated_kv[field] is not None: + _update_metadata_field( + updated_kv=updated_kv, + field_name=field, + ) + + if "model_aliases" in updated_kv: + updated_kv.pop("model_aliases") + _model_id = await _update_model_table( + data=data, + model_id=existing_team_row.model_id, + prisma_client=prisma_client, + user_api_key_dict=user_api_key_dict, + litellm_proxy_admin_name=litellm_proxy_admin_name, + ) + if _model_id is not None: + updated_kv["model_id"] = _model_id + + updated_kv = prisma_client.jsonify_team_object(db_data=updated_kv) + team_row: Optional[LiteLLM_TeamTable] = ( + await prisma_client.db.litellm_teamtable.update( + where={"team_id": data.team_id}, + data=updated_kv, + include={"litellm_model_table": True}, # type: ignore + ) + ) + + if team_row is None or team_row.team_id is None: + raise HTTPException( + status_code=400, + detail={"error": "Team doesn't exist. Got={}".format(team_row)}, ) - if "model_aliases" in updated_kv: - updated_kv.pop("model_aliases") - _model_id = await _update_model_table( - data=data, - model_id=existing_team_row.model_id, - prisma_client=prisma_client, - user_api_key_dict=user_api_key_dict, - litellm_proxy_admin_name=litellm_proxy_admin_name, - ) - if _model_id is not None: - updated_kv["model_id"] = _model_id - - updated_kv = prisma_client.jsonify_team_object(db_data=updated_kv) - team_row: Optional[LiteLLM_TeamTable] = ( - await prisma_client.db.litellm_teamtable.update( - where={"team_id": data.team_id}, - data=updated_kv, - include={"litellm_model_table": True}, # type: ignore - ) - ) - - if team_row is None or team_row.team_id is None: - raise HTTPException( - status_code=400, - detail={"error": "Team doesn't exist. Got={}".format(team_row)}, + verbose_proxy_logger.info("Successfully updated team - %s, info", team_row.team_id) + await _cache_team_object( + team_id=team_row.team_id, + team_table=LiteLLM_TeamTableCachedObj(**team_row.model_dump()), + user_api_key_cache=user_api_key_cache, + proxy_logging_obj=proxy_logging_obj, ) - verbose_proxy_logger.info("Successfully updated team - %s, info", team_row.team_id) - await _cache_team_object( - team_id=team_row.team_id, - team_table=LiteLLM_TeamTableCachedObj(**team_row.model_dump()), - user_api_key_cache=user_api_key_cache, - proxy_logging_obj=proxy_logging_obj, - ) + # Enterprise Feature - Audit Logging. Enable with litellm.store_audit_logs = True + if litellm.store_audit_logs is True: + await _create_team_update_audit_log( + existing_team_row=existing_team_row, + updated_kv=updated_kv, + team_id=data.team_id, + litellm_changed_by=litellm_changed_by, + user_api_key_dict=user_api_key_dict, + litellm_proxy_admin_name=litellm_proxy_admin_name, + ) - # Enterprise Feature - Audit Logging. Enable with litellm.store_audit_logs = True - if litellm.store_audit_logs is True: - await _create_team_update_audit_log( - existing_team_row=existing_team_row, - updated_kv=updated_kv, - team_id=data.team_id, - litellm_changed_by=litellm_changed_by, - user_api_key_dict=user_api_key_dict, - litellm_proxy_admin_name=litellm_proxy_admin_name, - ) - - return {"team_id": team_row.team_id, "data": team_row} + return {"team_id": team_row.team_id, "data": team_row} + except Exception as e: + raise handle_exception_on_proxy(e) async def handle_update_object_permission( diff --git a/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py index 86b23c98ba5..06ec71a84f8 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py @@ -2015,3 +2015,1605 @@ async def test_new_team_max_budget_within_user_limit(): assert result is not None assert result["team_id"] == "team-within-budget-789" assert result["max_budget"] == 50.0 + + +@pytest.mark.asyncio +async def test_new_team_org_scoped_budget_bypasses_user_limit(): + """ + Test that /team/new with organization_id does NOT validate budget against user's personal max_budget. + + This is the bug fix for: When an org admin creates an org-scoped team, the team's budget should + be validated against the organization's limits, not the user's personal limits. + + Scenario: + - Organization has max_budget=$100 + - User (org admin) has personal max_budget=$3 + - Team is created with organization_id and max_budget=$50 + - Expected: Should succeed (within org's $100 limit) + - Bug behavior: Would fail with "max budget higher than user max. User max budget=3.0" + """ + from fastapi import Request + + from litellm.proxy._types import NewTeamRequest, UserAPIKeyAuth, LiteLLM_UserTable, LiteLLM_OrganizationTable + from litellm.proxy.management_endpoints.team_endpoints import new_team + + # Create non-admin user with very restrictive personal budget ($3) + org_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org-admin-user-123", + user_max_budget=3.0, # Restrictive personal budget + models=[], # Empty models list to bypass model validation + ) + + # Create team request with budget ($50) that's within org's limit but exceeds user's personal limit + team_request = NewTeamRequest( + team_alias="org-scoped-team", + max_budget=50.0, # Within org's $100 limit, but exceeds user's $3 limit + organization_id="test-org-123", # This makes it an org-scoped team + ) + + dummy_request = MagicMock(spec=Request) + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server._license_check" + ) as mock_license, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server.create_audit_log_for_update", new=AsyncMock() + ) as mock_audit, patch( + "litellm.proxy.management_endpoints.team_endpoints.get_org_object" + ) as mock_get_org: + + # Setup mocks + mock_prisma.db.litellm_teamtable.count = AsyncMock(return_value=0) + mock_license.is_team_count_over_limit.return_value = False + mock_prisma.jsonify_team_object = lambda db_data: db_data + mock_prisma.get_data = AsyncMock(return_value=None) + mock_prisma.update_data = AsyncMock() + + # Mock organization with $100 budget + mock_org = MagicMock(spec=LiteLLM_OrganizationTable) + mock_org.organization_id = "test-org-123" + mock_org.max_budget = 100.0 + mock_org.models = ["gpt-4", "gpt-3.5-turbo", "claude-3-opus"] + mock_org.litellm_budget_table = None # No budget table for this test + mock_get_org.return_value = mock_org + + # Mock user cache to return user with restrictive personal budget + mock_user_obj = LiteLLM_UserTable( + user_id="org-admin-user-123", + max_budget=3.0, # Restrictive personal budget + ) + mock_cache.async_get_cache = AsyncMock(return_value=mock_user_obj) + + # Mock team creation + mock_created_team = MagicMock() + mock_created_team.team_id = "team-org-scoped-789" + mock_created_team.team_alias = "org-scoped-team" + mock_created_team.max_budget = 50.0 + mock_created_team.organization_id = "test-org-123" + mock_created_team.members_with_roles = [] + mock_created_team.metadata = None + mock_created_team.model_dump.return_value = { + "team_id": "team-org-scoped-789", + "team_alias": "org-scoped-team", + "max_budget": 50.0, + "organization_id": "test-org-123", + "members_with_roles": [], + } + mock_prisma.db.litellm_teamtable.create = AsyncMock(return_value=mock_created_team) + mock_prisma.db.litellm_teamtable.update = AsyncMock(return_value=mock_created_team) + + # Mock model table + mock_prisma.db.litellm_modeltable = MagicMock() + mock_prisma.db.litellm_modeltable.create = AsyncMock(return_value=MagicMock(id="model123")) + + # Mock user table operations + mock_user = MagicMock() + mock_user.user_id = "org-admin-user-123" + mock_user.model_dump.return_value = {"user_id": "org-admin-user-123", "teams": ["team-org-scoped-789"]} + mock_prisma.db.litellm_usertable = MagicMock() + mock_prisma.db.litellm_usertable.upsert = AsyncMock(return_value=mock_user) + mock_prisma.db.litellm_usertable.update = AsyncMock(return_value=mock_user) + + # Mock team membership table + mock_membership = MagicMock() + mock_membership.model_dump.return_value = { + "team_id": "team-org-scoped-789", + "user_id": "org-admin-user-123", + "budget_id": None, + } + mock_prisma.db.litellm_teammembership = MagicMock() + mock_prisma.db.litellm_teammembership.create = AsyncMock(return_value=mock_membership) + + # Should NOT raise an exception - the fix should bypass user budget validation for org-scoped teams + result = await new_team( + data=team_request, + http_request=dummy_request, + user_api_key_dict=org_admin_user, + ) + + # Verify the team was created successfully with the higher budget + assert result is not None + assert result["team_id"] == "team-org-scoped-789" + assert result["max_budget"] == 50.0 + assert result["organization_id"] == "test-org-123" + + +@pytest.mark.asyncio +async def test_new_team_org_scoped_models_bypasses_user_limit(): + """ + Test that /team/new with organization_id does NOT validate models against user's personal models. + + This is the bug fix for: When an org admin creates an org-scoped team, the team's models should + be validated against the organization's models, not the user's personal models. + + Scenario: + - Organization has models=['gpt-4', 'gpt-3.5-turbo', 'claude-3-opus'] + - User (org admin) has personal models=['no-default-models'] + - Team is created with organization_id and models=['gpt-4'] + - Expected: Should succeed (within org's allowed models) + - Bug behavior: Would fail with "Model not in allowed user models" + """ + from fastapi import Request + + from litellm.proxy._types import NewTeamRequest, UserAPIKeyAuth, LiteLLM_UserTable, LiteLLM_OrganizationTable + from litellm.proxy.management_endpoints.team_endpoints import new_team + + # Create non-admin user with restrictive personal models + org_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org-admin-user-456", + user_max_budget=None, # No budget restriction for this test + models=["no-default-models"], # Restrictive personal models + ) + + # Create team request with models that are within org's allowed models but not user's + team_request = NewTeamRequest( + team_alias="org-scoped-models-team", + models=["gpt-4"], # Within org's allowed models, but not in user's personal models + organization_id="test-org-456", # This makes it an org-scoped team + ) + + dummy_request = MagicMock(spec=Request) + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server._license_check" + ) as mock_license, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server.create_audit_log_for_update", new=AsyncMock() + ) as mock_audit, patch( + "litellm.proxy.management_endpoints.team_endpoints.get_org_object" + ) as mock_get_org: + + # Setup mocks + mock_prisma.db.litellm_teamtable.count = AsyncMock(return_value=0) + mock_license.is_team_count_over_limit.return_value = False + mock_prisma.jsonify_team_object = lambda db_data: db_data + mock_prisma.get_data = AsyncMock(return_value=None) + mock_prisma.update_data = AsyncMock() + + # Mock organization with allowed models + mock_org = MagicMock(spec=LiteLLM_OrganizationTable) + mock_org.organization_id = "test-org-456" + mock_org.max_budget = 100.0 + mock_org.models = ["gpt-4", "gpt-3.5-turbo", "claude-3-opus"] + mock_org.litellm_budget_table = None + mock_get_org.return_value = mock_org + + # Mock user cache + mock_user_obj = LiteLLM_UserTable( + user_id="org-admin-user-456", + max_budget=None, + ) + mock_cache.async_get_cache = AsyncMock(return_value=mock_user_obj) + + # Mock team creation + mock_created_team = MagicMock() + mock_created_team.team_id = "team-org-scoped-models-789" + mock_created_team.team_alias = "org-scoped-models-team" + mock_created_team.max_budget = None + mock_created_team.organization_id = "test-org-456" + mock_created_team.models = ["gpt-4"] + mock_created_team.members_with_roles = [] + mock_created_team.metadata = None + mock_created_team.model_dump.return_value = { + "team_id": "team-org-scoped-models-789", + "team_alias": "org-scoped-models-team", + "max_budget": None, + "organization_id": "test-org-456", + "models": ["gpt-4"], + "members_with_roles": [], + } + mock_prisma.db.litellm_teamtable.create = AsyncMock(return_value=mock_created_team) + mock_prisma.db.litellm_teamtable.update = AsyncMock(return_value=mock_created_team) + + # Mock model table + mock_prisma.db.litellm_modeltable = MagicMock() + mock_prisma.db.litellm_modeltable.create = AsyncMock(return_value=MagicMock(id="model123")) + + # Mock user table operations + mock_user = MagicMock() + mock_user.user_id = "org-admin-user-456" + mock_user.model_dump.return_value = {"user_id": "org-admin-user-456", "teams": ["team-org-scoped-models-789"]} + mock_prisma.db.litellm_usertable = MagicMock() + mock_prisma.db.litellm_usertable.upsert = AsyncMock(return_value=mock_user) + mock_prisma.db.litellm_usertable.update = AsyncMock(return_value=mock_user) + + # Mock team membership table + mock_membership = MagicMock() + mock_membership.model_dump.return_value = { + "team_id": "team-org-scoped-models-789", + "user_id": "org-admin-user-456", + "budget_id": None, + } + mock_prisma.db.litellm_teammembership = MagicMock() + mock_prisma.db.litellm_teammembership.create = AsyncMock(return_value=mock_membership) + + # Should NOT raise an exception - the fix should bypass user model validation for org-scoped teams + result = await new_team( + data=team_request, + http_request=dummy_request, + user_api_key_dict=org_admin_user, + ) + + # Verify the team was created successfully with the org's models + assert result is not None + assert result["team_id"] == "team-org-scoped-models-789" + assert result["models"] == ["gpt-4"] + assert result["organization_id"] == "test-org-456" + + +@pytest.mark.asyncio +async def test_new_team_standalone_validates_against_user_models(): + """ + Test that /team/new WITHOUT organization_id still validates models against user's personal models. + + This ensures that standalone teams (not org-scoped) still use user-level validation. + + Scenario: + - User has personal models=['no-default-models'] + - Team is created WITHOUT organization_id and models=['gpt-4'] + - Expected: Should fail with "Model not in allowed user models" + """ + from fastapi import Request + + from litellm.proxy._types import NewTeamRequest, ProxyException, UserAPIKeyAuth + from litellm.proxy.management_endpoints.team_endpoints import new_team + + # Create non-admin user with restrictive personal models + non_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="non-admin-user-789", + user_max_budget=None, + models=["no-default-models"], # Restrictive personal models + ) + + # Create standalone team request (no organization_id) with models not in user's list + team_request = NewTeamRequest( + team_alias="standalone-team", + models=["gpt-4"], # Not in user's allowed models + # Note: No organization_id - this is a standalone team + ) + + dummy_request = MagicMock(spec=Request) + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server._license_check" + ) as mock_license, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server.create_audit_log_for_update", new=AsyncMock() + ) as mock_audit: + # Setup basic mocks + mock_prisma.db.litellm_teamtable.count = AsyncMock(return_value=0) + mock_license.is_team_count_over_limit.return_value = False + mock_prisma.get_data = AsyncMock(return_value=None) + + # Should raise ProxyException because gpt-4 is not in user's allowed models + with pytest.raises(ProxyException) as exc_info: + await new_team( + data=team_request, + http_request=dummy_request, + user_api_key_dict=non_admin_user, + ) + + # Verify exception details + assert exc_info.value.code == '400' + assert "Model not in allowed user models" in str(exc_info.value.message) + assert "no-default-models" in str(exc_info.value.message) + + +@pytest.mark.asyncio +async def test_new_team_standalone_validates_against_user_budget(): + """ + Test that /team/new WITHOUT organization_id still validates budget against user's personal max_budget. + + This ensures that standalone teams (not org-scoped) still use user-level validation. + This is essentially the same as test_new_team_max_budget_exceeds_user_max_budget but + explicitly showing the contrast with org-scoped teams. + + Scenario: + - User has personal max_budget=$3 + - Team is created WITHOUT organization_id and max_budget=$50 + - Expected: Should fail with "max budget higher than user max" + """ + from fastapi import Request + + from litellm.proxy._types import NewTeamRequest, ProxyException, UserAPIKeyAuth, LiteLLM_UserTable + from litellm.proxy.management_endpoints.team_endpoints import new_team + + # Create non-admin user with restrictive personal budget + non_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="non-admin-user-budget-789", + user_max_budget=100.0, # This is for key auth, actual budget is from user object + models=[], # Empty models list to bypass model validation + ) + + # Create standalone team request (no organization_id) with budget exceeding user's limit + team_request = NewTeamRequest( + team_alias="standalone-budget-team", + max_budget=50.0, # Exceeds user's personal budget + # Note: No organization_id - this is a standalone team + ) + + dummy_request = MagicMock(spec=Request) + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server._license_check" + ) as mock_license, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server.create_audit_log_for_update", new=AsyncMock() + ) as mock_audit: + # Setup basic mocks + mock_prisma.db.litellm_teamtable.count = AsyncMock(return_value=0) + mock_license.is_team_count_over_limit.return_value = False + mock_prisma.get_data = AsyncMock(return_value=None) + + # Mock user cache to return user with restrictive personal budget ($3) + mock_user_obj = LiteLLM_UserTable( + user_id="non-admin-user-budget-789", + max_budget=3.0, # Restrictive personal budget + ) + mock_cache.async_get_cache = AsyncMock(return_value=mock_user_obj) + + # Should raise ProxyException because budget exceeds user's max_budget + with pytest.raises(ProxyException) as exc_info: + await new_team( + data=team_request, + http_request=dummy_request, + user_api_key_dict=non_admin_user, + ) + + # Verify exception details + assert exc_info.value.code == '400' + assert "max budget higher than user max" in str(exc_info.value.message) + assert "3.0" in str(exc_info.value.message) # User's max_budget should be mentioned + + +@pytest.mark.asyncio +async def test_new_team_org_scoped_budget_exceeds_org_limit(): + """ + Test that /team/new with organization_id fails when team budget exceeds organization's max_budget. + + Scenario: + - Organization has max_budget=$100 + - Team is created with organization_id and max_budget=$150 + - Expected: Should fail with error about exceeding org budget + """ + from fastapi import Request + + from litellm.proxy._types import NewTeamRequest, ProxyException, UserAPIKeyAuth, LiteLLM_OrganizationTable, LiteLLM_BudgetTable + from litellm.proxy.management_endpoints.team_endpoints import new_team + + # Create user (org admin) + org_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org-admin-user-budget-test", + models=[], + ) + + # Create team request with budget ($150) that exceeds org's limit ($100) + team_request = NewTeamRequest( + team_alias="org-team-exceeds-budget", + max_budget=150.0, # Exceeds org's $100 limit + organization_id="test-org-budget-limit", + ) + + dummy_request = MagicMock(spec=Request) + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server._license_check" + ) as mock_license, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server.create_audit_log_for_update", new=AsyncMock() + ) as mock_audit, patch( + "litellm.proxy.management_endpoints.team_endpoints.get_org_object" + ) as mock_get_org: + + # Setup mocks + mock_prisma.db.litellm_teamtable.count = AsyncMock(return_value=0) + mock_license.is_team_count_over_limit.return_value = False + mock_prisma.get_data = AsyncMock(return_value=None) + + # Mock organization with $100 budget limit + mock_budget_table = MagicMock(spec=LiteLLM_BudgetTable) + mock_budget_table.max_budget = 100.0 + + mock_org = MagicMock(spec=LiteLLM_OrganizationTable) + mock_org.organization_id = "test-org-budget-limit" + mock_org.models = ["gpt-4", "gpt-3.5-turbo"] + mock_org.litellm_budget_table = mock_budget_table + mock_get_org.return_value = mock_org + + # Should raise ProxyException because team budget exceeds org budget + with pytest.raises(ProxyException) as exc_info: + await new_team( + data=team_request, + http_request=dummy_request, + user_api_key_dict=org_admin_user, + ) + + # Verify exception details + assert exc_info.value.code == '400' + assert "exceeds organization" in str(exc_info.value.message).lower() or "organization" in str(exc_info.value.message).lower() + + +@pytest.mark.asyncio +async def test_new_team_org_scoped_models_not_in_org_models(): + """ + Test that /team/new with organization_id fails when team models are not in organization's allowed models. + + Scenario: + - Organization has models=['gpt-4', 'gpt-3.5-turbo'] + - Team is created with organization_id and models=['claude-3-opus'] + - Expected: Should fail with error about model not in org's allowed models + """ + from fastapi import Request + + from litellm.proxy._types import NewTeamRequest, ProxyException, UserAPIKeyAuth, LiteLLM_OrganizationTable, LiteLLM_BudgetTable + from litellm.proxy.management_endpoints.team_endpoints import new_team + + # Create user (org admin) + org_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org-admin-user-models-test", + models=[], + ) + + # Create team request with model not in org's allowed list + team_request = NewTeamRequest( + team_alias="org-team-invalid-model", + models=["claude-3-opus"], # Not in org's allowed models + organization_id="test-org-models-limit", + ) + + dummy_request = MagicMock(spec=Request) + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server._license_check" + ) as mock_license, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server.create_audit_log_for_update", new=AsyncMock() + ) as mock_audit, patch( + "litellm.proxy.management_endpoints.team_endpoints.get_org_object" + ) as mock_get_org: + + # Setup mocks + mock_prisma.db.litellm_teamtable.count = AsyncMock(return_value=0) + mock_license.is_team_count_over_limit.return_value = False + mock_prisma.get_data = AsyncMock(return_value=None) + + # Mock organization with specific allowed models (not including claude-3-opus) + mock_org = MagicMock(spec=LiteLLM_OrganizationTable) + mock_org.organization_id = "test-org-models-limit" + mock_org.models = ["gpt-4", "gpt-3.5-turbo"] # claude-3-opus is NOT allowed + mock_org.litellm_budget_table = None + mock_get_org.return_value = mock_org + + # Should raise ProxyException because claude-3-opus is not in org's allowed models + with pytest.raises(ProxyException) as exc_info: + await new_team( + data=team_request, + http_request=dummy_request, + user_api_key_dict=org_admin_user, + ) + + # Verify exception details + assert exc_info.value.code == '400' + assert "claude-3-opus" in str(exc_info.value.message) or "organization" in str(exc_info.value.message).lower() + + +@pytest.mark.asyncio +async def test_update_team_standalone_budget_exceeds_user_limit(): + """ + Test that /team/update for a standalone team fails when new budget exceeds user's max_budget. + + Scenario: + - User has personal max_budget=$50 + - Standalone team exists (no organization_id) + - User tries to update team budget to $100 + - Expected: Should fail with error about exceeding user budget + """ + from fastapi import Request + + from litellm.proxy._types import UpdateTeamRequest, ProxyException, UserAPIKeyAuth, LiteLLM_UserTable + from litellm.proxy.management_endpoints.team_endpoints import update_team + + # Create non-admin user with restrictive personal budget + non_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="non-admin-update-test", + models=[], + ) + + # Create update request with budget exceeding user's limit + update_request = UpdateTeamRequest( + team_id="standalone-team-123", + max_budget=100.0, # Exceeds user's $50 limit + ) + + dummy_request = MagicMock(spec=Request) + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server.create_audit_log_for_update", new=AsyncMock() + ) as mock_audit: + + # Mock existing standalone team (no organization_id) + mock_existing_team = MagicMock() + mock_existing_team.team_id = "standalone-team-123" + mock_existing_team.organization_id = None # Standalone team + mock_existing_team.max_budget = 30.0 + mock_existing_team.model_dump.return_value = { + "team_id": "standalone-team-123", + "organization_id": None, + "max_budget": 30.0, + } + mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=mock_existing_team) + + # Mock user cache to return user with restrictive budget + mock_user_obj = LiteLLM_UserTable( + user_id="non-admin-update-test", + max_budget=50.0, # User's budget limit + ) + mock_cache.async_get_cache = AsyncMock(return_value=mock_user_obj) + + # Should raise ProxyException because new budget exceeds user's max_budget + with pytest.raises(ProxyException) as exc_info: + await update_team( + data=update_request, + http_request=dummy_request, + user_api_key_dict=non_admin_user, + ) + + # Verify exception details + assert exc_info.value.code == '400' + assert "budget" in str(exc_info.value.message).lower() + + +@pytest.mark.asyncio +async def test_update_team_org_scoped_budget_exceeds_org_limit(): + """ + Test that /team/update for an org-scoped team fails when new budget exceeds organization's max_budget. + + Scenario: + - Organization has max_budget=$100 + - Org-scoped team exists + - User tries to update team budget to $150 + - Expected: Should fail with error about exceeding org budget + """ + from fastapi import Request + + from litellm.proxy._types import UpdateTeamRequest, ProxyException, UserAPIKeyAuth, LiteLLM_OrganizationTable, LiteLLM_BudgetTable + from litellm.proxy.management_endpoints.team_endpoints import update_team + + # Create user (org admin) + org_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org-admin-update-test", + models=[], + ) + + # Create update request with budget exceeding org's limit + update_request = UpdateTeamRequest( + team_id="org-team-456", + max_budget=150.0, # Exceeds org's $100 limit + ) + + dummy_request = MagicMock(spec=Request) + + # Mock organization with $100 budget limit + mock_budget_table = MagicMock(spec=LiteLLM_BudgetTable) + mock_budget_table.max_budget = 100.0 + + mock_org = MagicMock(spec=LiteLLM_OrganizationTable) + mock_org.organization_id = "test-org-update" + mock_org.models = ["gpt-4"] + mock_org.litellm_budget_table = mock_budget_table + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server.create_audit_log_for_update", new=AsyncMock() + ) as mock_audit, patch( + "litellm.proxy.management_endpoints.team_endpoints.get_org_object", + new=AsyncMock(return_value=mock_org) + ) as mock_get_org: + + # Mock existing org-scoped team + mock_existing_team = MagicMock() + mock_existing_team.team_id = "org-team-456" + mock_existing_team.organization_id = "test-org-update" + mock_existing_team.max_budget = 80.0 + mock_existing_team.model_dump.return_value = { + "team_id": "org-team-456", + "organization_id": "test-org-update", + "max_budget": 80.0, + } + mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=mock_existing_team) + + # Should raise ProxyException because new budget exceeds org's max_budget + with pytest.raises(ProxyException) as exc_info: + await update_team( + data=update_request, + http_request=dummy_request, + user_api_key_dict=org_admin_user, + ) + + # Verify exception details + assert exc_info.value.code == '400' + assert "organization" in str(exc_info.value.message).lower() or "budget" in str(exc_info.value.message).lower() + + +@pytest.mark.asyncio +async def test_update_team_standalone_models_exceeds_user_limit(): + """ + Test that /team/update for a standalone team fails when models are not in user's allowed models. + + Scenario: + - User has personal models=['gpt-3.5-turbo'] + - Standalone team exists (no organization_id) + - User tries to update team models to ['gpt-4'] (not in user's allowed models) + - Expected: Should fail with error about model not in user's allowed models + """ + from fastapi import Request + + from litellm.proxy._types import UpdateTeamRequest, ProxyException, UserAPIKeyAuth + from litellm.proxy.management_endpoints.team_endpoints import update_team + + # Create non-admin user with restrictive personal models + non_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="non-admin-update-models-test", + models=["gpt-3.5-turbo"], # Restrictive model list + ) + + # Create update request with model not in user's allowed list + update_request = UpdateTeamRequest( + team_id="standalone-team-models-123", + models=["gpt-4"], # Not in user's allowed models + ) + + dummy_request = MagicMock(spec=Request) + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server.create_audit_log_for_update", new=AsyncMock() + ) as mock_audit: + + # Mock existing standalone team (no organization_id) + mock_existing_team = MagicMock() + mock_existing_team.team_id = "standalone-team-models-123" + mock_existing_team.organization_id = None # Standalone team + mock_existing_team.models = ["gpt-3.5-turbo"] + mock_existing_team.model_dump.return_value = { + "team_id": "standalone-team-models-123", + "organization_id": None, + "models": ["gpt-3.5-turbo"], + } + mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=mock_existing_team) + + # Should raise ProxyException because model not in user's allowed models + with pytest.raises(ProxyException) as exc_info: + await update_team( + data=update_request, + http_request=dummy_request, + user_api_key_dict=non_admin_user, + ) + + # Verify exception details + assert exc_info.value.code == '400' + assert "model" in str(exc_info.value.message).lower() + + +@pytest.mark.asyncio +async def test_update_team_org_scoped_budget_bypasses_user_limit(): + """ + Test that /team/update for an org-scoped team does NOT validate budget against user's personal max_budget. + + Scenario: + - Organization has max_budget=$100 + - User (org admin) has personal max_budget=$3 + - Org-scoped team exists with current budget=$30 + - User tries to update team budget to $50 (within org limit, exceeds user limit) + - Expected: Should succeed (validated against org, not user) + """ + from fastapi import Request + + from litellm.proxy._types import UpdateTeamRequest, UserAPIKeyAuth, LiteLLM_UserTable, LiteLLM_OrganizationTable, LiteLLM_BudgetTable + from litellm.proxy.management_endpoints.team_endpoints import update_team + + # Create user with very restrictive personal budget ($3) + org_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org-admin-update-budget-test", + models=[], + ) + + # Create update request with budget within org limit but exceeding user limit + update_request = UpdateTeamRequest( + team_id="org-team-update-budget-123", + max_budget=50.0, # Within org's $100 limit, exceeds user's $3 limit + ) + + dummy_request = MagicMock(spec=Request) + + # Mock organization with $100 budget limit + mock_budget_table = MagicMock(spec=LiteLLM_BudgetTable) + mock_budget_table.max_budget = 100.0 + + mock_org = MagicMock(spec=LiteLLM_OrganizationTable) + mock_org.organization_id = "test-org-update-budget" + mock_org.models = ["gpt-4", "gpt-3.5-turbo"] + mock_org.litellm_budget_table = mock_budget_table + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server.create_audit_log_for_update", new=AsyncMock() + ) as mock_audit, patch( + "litellm.proxy.management_endpoints.team_endpoints.get_org_object", + new=AsyncMock(return_value=mock_org) + ) as mock_get_org: + + # Mock existing org-scoped team + mock_existing_team = MagicMock() + mock_existing_team.team_id = "org-team-update-budget-123" + mock_existing_team.organization_id = "test-org-update-budget" + mock_existing_team.max_budget = 30.0 + mock_existing_team.model_id = None + mock_existing_team.model_dump.return_value = { + "team_id": "org-team-update-budget-123", + "organization_id": "test-org-update-budget", + "max_budget": 30.0, + } + mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=mock_existing_team) + mock_prisma.jsonify_team_object = lambda db_data: db_data + + # Mock user cache to return user with restrictive budget + mock_user_obj = LiteLLM_UserTable( + user_id="org-admin-update-budget-test", + max_budget=3.0, # Restrictive personal budget + ) + mock_cache.async_get_cache = AsyncMock(return_value=mock_user_obj) + mock_cache.async_set_cache = AsyncMock() # Mock cache set for _cache_team_object + + # Mock team update + mock_updated_team = MagicMock() + mock_updated_team.team_id = "org-team-update-budget-123" + mock_updated_team.organization_id = "test-org-update-budget" + mock_updated_team.max_budget = 50.0 + mock_updated_team.litellm_model_table = None + mock_updated_team.model_dump.return_value = { + "team_id": "org-team-update-budget-123", + "organization_id": "test-org-update-budget", + "max_budget": 50.0, + } + mock_prisma.db.litellm_teamtable.update = AsyncMock(return_value=mock_updated_team) + + # Should NOT raise an exception - bypass user budget validation for org-scoped teams + result = await update_team( + data=update_request, + http_request=dummy_request, + user_api_key_dict=org_admin_user, + ) + + # Verify the team was updated successfully with the higher budget + assert result is not None + assert result["data"].max_budget == 50.0 + + +@pytest.mark.asyncio +async def test_update_team_org_scoped_models_bypasses_user_limit(): + """ + Test that /team/update for an org-scoped team does NOT validate models against user's personal models. + + Scenario: + - Organization has models=['gpt-4', 'gpt-3.5-turbo', 'claude-3-opus'] + - User (org admin) has personal models=['no-default-models'] + - Org-scoped team exists + - User tries to update team models to ['gpt-4'] (in org's allowed, not in user's) + - Expected: Should succeed (validated against org, not user) + """ + from fastapi import Request + + from litellm.proxy._types import UpdateTeamRequest, UserAPIKeyAuth, LiteLLM_OrganizationTable + from litellm.proxy.management_endpoints.team_endpoints import update_team + + # Create user with very restrictive personal models + org_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org-admin-update-models-test", + models=["no-default-models"], # Restrictive model list + ) + + # Create update request with models in org's allowed but not in user's + update_request = UpdateTeamRequest( + team_id="org-team-update-models-123", + models=["gpt-4"], # In org's allowed, not in user's + ) + + dummy_request = MagicMock(spec=Request) + + # Mock organization with generous model list + mock_org = MagicMock(spec=LiteLLM_OrganizationTable) + mock_org.organization_id = "test-org-update-models" + mock_org.models = ["gpt-4", "gpt-3.5-turbo", "claude-3-opus"] + mock_org.litellm_budget_table = None + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server.create_audit_log_for_update", new=AsyncMock() + ) as mock_audit, patch( + "litellm.proxy.management_endpoints.team_endpoints.get_org_object", + new=AsyncMock(return_value=mock_org) + ) as mock_get_org: + + # Mock existing org-scoped team + mock_existing_team = MagicMock() + mock_existing_team.team_id = "org-team-update-models-123" + mock_existing_team.organization_id = "test-org-update-models" + mock_existing_team.models = ["gpt-3.5-turbo"] + mock_existing_team.model_id = None + mock_existing_team.model_dump.return_value = { + "team_id": "org-team-update-models-123", + "organization_id": "test-org-update-models", + "models": ["gpt-3.5-turbo"], + } + mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=mock_existing_team) + mock_prisma.jsonify_team_object = lambda db_data: db_data + mock_cache.async_set_cache = AsyncMock() # Mock cache set for _cache_team_object + + # Mock team update + mock_updated_team = MagicMock() + mock_updated_team.team_id = "org-team-update-models-123" + mock_updated_team.organization_id = "test-org-update-models" + mock_updated_team.models = ["gpt-4"] + mock_updated_team.litellm_model_table = None + mock_updated_team.model_dump.return_value = { + "team_id": "org-team-update-models-123", + "organization_id": "test-org-update-models", + "models": ["gpt-4"], + } + mock_prisma.db.litellm_teamtable.update = AsyncMock(return_value=mock_updated_team) + + # Should NOT raise an exception - bypass user models validation for org-scoped teams + result = await update_team( + data=update_request, + http_request=dummy_request, + user_api_key_dict=org_admin_user, + ) + + # Verify the team was updated successfully with the new models + assert result is not None + assert result["data"].models == ["gpt-4"] + + +@pytest.mark.asyncio +async def test_update_team_org_scoped_models_not_in_org_models(): + """ + Test that /team/update for an org-scoped team fails when models are not in organization's allowed models. + + Scenario: + - Organization has models=['gpt-4', 'gpt-3.5-turbo'] + - Org-scoped team exists + - User tries to update team models to ['claude-3-opus'] (not in org's allowed models) + - Expected: Should fail with error about model not in org's allowed models + """ + from fastapi import Request + + from litellm.proxy._types import UpdateTeamRequest, ProxyException, UserAPIKeyAuth, LiteLLM_OrganizationTable + from litellm.proxy.management_endpoints.team_endpoints import update_team + + # Create user (org admin) + org_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org-admin-update-models-fail-test", + models=[], + ) + + # Create update request with model not in org's allowed list + update_request = UpdateTeamRequest( + team_id="org-team-update-models-fail-123", + models=["claude-3-opus"], # Not in org's allowed models + ) + + dummy_request = MagicMock(spec=Request) + + # Mock organization with restricted model list (no claude-3-opus) + mock_org = MagicMock(spec=LiteLLM_OrganizationTable) + mock_org.organization_id = "test-org-update-models-fail" + mock_org.models = ["gpt-4", "gpt-3.5-turbo"] # claude-3-opus is NOT allowed + mock_org.litellm_budget_table = None + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server.create_audit_log_for_update", new=AsyncMock() + ) as mock_audit, patch( + "litellm.proxy.management_endpoints.team_endpoints.get_org_object", + new=AsyncMock(return_value=mock_org) + ) as mock_get_org: + + # Mock existing org-scoped team + mock_existing_team = MagicMock() + mock_existing_team.team_id = "org-team-update-models-fail-123" + mock_existing_team.organization_id = "test-org-update-models-fail" + mock_existing_team.models = ["gpt-4"] + mock_existing_team.model_dump.return_value = { + "team_id": "org-team-update-models-fail-123", + "organization_id": "test-org-update-models-fail", + "models": ["gpt-4"], + } + mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=mock_existing_team) + + # Should raise ProxyException because claude-3-opus is not in org's allowed models + with pytest.raises(ProxyException) as exc_info: + await update_team( + data=update_request, + http_request=dummy_request, + user_api_key_dict=org_admin_user, + ) + + # Verify exception details + assert exc_info.value.code == '400' + assert "claude-3-opus" in str(exc_info.value.message) or "organization" in str(exc_info.value.message).lower() + + +@pytest.mark.asyncio +async def test_update_team_tpm_limit_exceeds_user_limit(): + """ + Test that /team/update fails when TPM limit exceeds user's TPM limit. + + Scenario: + - User has tpm_limit=1000 + - User tries to update team with tpm_limit=5000 + - Expected: Should fail with error about exceeding user TPM limit + """ + from fastapi import Request + + from litellm.proxy._types import UpdateTeamRequest, ProxyException, UserAPIKeyAuth + from litellm.proxy.management_endpoints.team_endpoints import update_team + + # Create non-admin user with TPM limit + non_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="tpm-limit-user", + models=[], + tpm_limit=1000, # User's TPM limit + ) + + # Create update request with TPM exceeding user's limit + update_request = UpdateTeamRequest( + team_id="team-tpm-test-123", + tpm_limit=5000, # Exceeds user's 1000 limit + ) + + dummy_request = MagicMock(spec=Request) + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ): + + # Mock existing standalone team + mock_existing_team = MagicMock() + mock_existing_team.team_id = "team-tpm-test-123" + mock_existing_team.organization_id = None + mock_existing_team.tpm_limit = 500 + mock_existing_team.model_dump.return_value = { + "team_id": "team-tpm-test-123", + "organization_id": None, + "tpm_limit": 500, + } + mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=mock_existing_team) + + # Should raise ProxyException because new TPM exceeds user's limit + with pytest.raises(ProxyException) as exc_info: + await update_team( + data=update_request, + http_request=dummy_request, + user_api_key_dict=non_admin_user, + ) + + # Verify exception details + assert exc_info.value.code == '400' + assert "tpm" in str(exc_info.value.message).lower() + + +@pytest.mark.asyncio +async def test_update_team_rpm_limit_exceeds_user_limit(): + """ + Test that /team/update fails when RPM limit exceeds user's RPM limit. + + Scenario: + - User has rpm_limit=100 + - User tries to update team with rpm_limit=500 + - Expected: Should fail with error about exceeding user RPM limit + """ + from fastapi import Request + + from litellm.proxy._types import UpdateTeamRequest, ProxyException, UserAPIKeyAuth + from litellm.proxy.management_endpoints.team_endpoints import update_team + + # Create non-admin user with RPM limit + non_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="rpm-limit-user", + models=[], + rpm_limit=100, # User's RPM limit + ) + + # Create update request with RPM exceeding user's limit + update_request = UpdateTeamRequest( + team_id="team-rpm-test-123", + rpm_limit=500, # Exceeds user's 100 limit + ) + + dummy_request = MagicMock(spec=Request) + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ): + + # Mock existing standalone team + mock_existing_team = MagicMock() + mock_existing_team.team_id = "team-rpm-test-123" + mock_existing_team.organization_id = None + mock_existing_team.rpm_limit = 50 + mock_existing_team.model_dump.return_value = { + "team_id": "team-rpm-test-123", + "organization_id": None, + "rpm_limit": 50, + } + mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=mock_existing_team) + + # Should raise ProxyException because new RPM exceeds user's limit + with pytest.raises(ProxyException) as exc_info: + await update_team( + data=update_request, + http_request=dummy_request, + user_api_key_dict=non_admin_user, + ) + + # Verify exception details + assert exc_info.value.code == '400' + assert "rpm" in str(exc_info.value.message).lower() + + +@pytest.mark.asyncio +async def test_new_team_org_scoped_tpm_exceeds_org_limit(): + """ + Test that /team/new for an org-scoped team fails when TPM exceeds organization's TPM limit. + + Scenario: + - Organization has tpm_limit=10000 + - User tries to create org-scoped team with tpm_limit=20000 + - Expected: Should fail with error about exceeding org TPM limit + """ + from fastapi import Request + + from litellm.proxy._types import NewTeamRequest, ProxyException, UserAPIKeyAuth, LiteLLM_OrganizationTable, LiteLLM_BudgetTable + from litellm.proxy.management_endpoints.team_endpoints import new_team + + # Create user (with restrictive personal TPM limit that should be bypassed) + org_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org-admin-tpm-test", + models=[], + tpm_limit=1000, # User's personal limit (should be bypassed for org teams) + ) + + # Create team request with TPM exceeding org's limit + team_request = NewTeamRequest( + team_alias="org-tpm-test-team", + organization_id="test-org-tpm", + tpm_limit=20000, # Exceeds org's 10000 limit + ) + + dummy_request = MagicMock(spec=Request) + + # Mock organization with TPM limit + mock_budget_table = MagicMock(spec=LiteLLM_BudgetTable) + mock_budget_table.tpm_limit = 10000 # Org's TPM limit + mock_budget_table.rpm_limit = None + mock_budget_table.max_budget = None + + mock_org = MagicMock(spec=LiteLLM_OrganizationTable) + mock_org.organization_id = "test-org-tpm" + mock_org.models = ["gpt-4"] + mock_org.litellm_budget_table = mock_budget_table + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server._license_check" + ) as mock_license, patch( + "litellm.proxy.management_endpoints.team_endpoints.get_org_object", + new=AsyncMock(return_value=mock_org) + ): + mock_license.is_team_count_over_limit.return_value = False + mock_prisma.db.litellm_teamtable.count = AsyncMock(return_value=0) + mock_prisma.get_data = AsyncMock(return_value=None) + + # Should raise ProxyException because TPM exceeds org limit + with pytest.raises(ProxyException) as exc_info: + await new_team( + data=team_request, + http_request=dummy_request, + user_api_key_dict=org_admin_user, + ) + + # Verify exception details + assert exc_info.value.code == '400' + assert "tpm" in str(exc_info.value.message).lower() + + +@pytest.mark.asyncio +async def test_new_team_org_scoped_rpm_exceeds_org_limit(): + """ + Test that /team/new for an org-scoped team fails when RPM exceeds organization's RPM limit. + + Scenario: + - Organization has rpm_limit=1000 + - User tries to create org-scoped team with rpm_limit=2000 + - Expected: Should fail with error about exceeding org RPM limit + """ + from fastapi import Request + + from litellm.proxy._types import NewTeamRequest, ProxyException, UserAPIKeyAuth, LiteLLM_OrganizationTable, LiteLLM_BudgetTable + from litellm.proxy.management_endpoints.team_endpoints import new_team + + # Create user (with restrictive personal RPM limit that should be bypassed) + org_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org-admin-rpm-test", + models=[], + rpm_limit=100, # User's personal limit (should be bypassed for org teams) + ) + + # Create team request with RPM exceeding org's limit + team_request = NewTeamRequest( + team_alias="org-rpm-test-team", + organization_id="test-org-rpm", + rpm_limit=2000, # Exceeds org's 1000 limit + ) + + dummy_request = MagicMock(spec=Request) + + # Mock organization with RPM limit + mock_budget_table = MagicMock(spec=LiteLLM_BudgetTable) + mock_budget_table.tpm_limit = None + mock_budget_table.rpm_limit = 1000 # Org's RPM limit + mock_budget_table.max_budget = None + + mock_org = MagicMock(spec=LiteLLM_OrganizationTable) + mock_org.organization_id = "test-org-rpm" + mock_org.models = ["gpt-4"] + mock_org.litellm_budget_table = mock_budget_table + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server._license_check" + ) as mock_license, patch( + "litellm.proxy.management_endpoints.team_endpoints.get_org_object", + new=AsyncMock(return_value=mock_org) + ): + mock_license.is_team_count_over_limit.return_value = False + mock_prisma.db.litellm_teamtable.count = AsyncMock(return_value=0) + mock_prisma.get_data = AsyncMock(return_value=None) + + # Should raise ProxyException because RPM exceeds org limit + with pytest.raises(ProxyException) as exc_info: + await new_team( + data=team_request, + http_request=dummy_request, + user_api_key_dict=org_admin_user, + ) + + # Verify exception details + assert exc_info.value.code == '400' + assert "rpm" in str(exc_info.value.message).lower() + + +@pytest.mark.asyncio +async def test_new_team_org_scoped_tpm_rpm_bypasses_user_limit(): + """ + Test that /team/new for an org-scoped team bypasses user's TPM/RPM limits. + + Scenario: + - User has tpm_limit=1000, rpm_limit=100 + - Organization has tpm_limit=50000, rpm_limit=5000 + - User creates org-scoped team with tpm_limit=10000, rpm_limit=1000 + - Expected: Should succeed (bypasses user limits, within org limits) + """ + from fastapi import Request + + from litellm.proxy._types import NewTeamRequest, UserAPIKeyAuth, LiteLLM_OrganizationTable, LiteLLM_BudgetTable, LiteLLM_TeamTable + from litellm.proxy.management_endpoints.team_endpoints import new_team + + # Create user with restrictive personal limits + org_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org-admin-bypass-test", + models=[], + tpm_limit=1000, # Restrictive user TPM limit + rpm_limit=100, # Restrictive user RPM limit + ) + + # Create team request exceeding user limits but within org limits + team_request = NewTeamRequest( + team_alias="org-bypass-test-team", + organization_id="test-org-bypass", + tpm_limit=10000, # Exceeds user's 1000 but within org's 50000 + rpm_limit=1000, # Exceeds user's 100 but within org's 5000 + ) + + dummy_request = MagicMock(spec=Request) + + # Mock organization with generous limits + mock_budget_table = MagicMock(spec=LiteLLM_BudgetTable) + mock_budget_table.tpm_limit = 50000 # Generous org TPM limit + mock_budget_table.rpm_limit = 5000 # Generous org RPM limit + mock_budget_table.max_budget = None + + mock_org = MagicMock(spec=LiteLLM_OrganizationTable) + mock_org.organization_id = "test-org-bypass" + mock_org.models = ["gpt-4"] + mock_org.litellm_budget_table = mock_budget_table + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server._license_check" + ) as mock_license, patch( + "litellm.proxy.proxy_server.create_audit_log_for_update", new=AsyncMock() + ), patch( + "litellm.proxy.management_endpoints.team_endpoints.get_org_object", + new=AsyncMock(return_value=mock_org) + ), patch( + "litellm.proxy.management_endpoints.team_endpoints._add_team_members_to_team", + new=AsyncMock() + ): + mock_license.is_team_count_over_limit.return_value = False + mock_prisma.db.litellm_teamtable.count = AsyncMock(return_value=0) + mock_prisma.get_data = AsyncMock(return_value=None) + + # Mock team creation + mock_created_team = MagicMock(spec=LiteLLM_TeamTable) + mock_created_team.team_id = "new-bypass-team-id" + mock_created_team.team_alias = "org-bypass-test-team" + mock_created_team.tpm_limit = 10000 + mock_created_team.rpm_limit = 1000 + mock_created_team.metadata = None + mock_created_team.members_with_roles = [] + mock_created_team.model_dump.return_value = { + "team_id": "new-bypass-team-id", + "team_alias": "org-bypass-test-team", + "tpm_limit": 10000, + "rpm_limit": 1000, + "metadata": None, + "members_with_roles": [], + } + mock_prisma.db.litellm_teamtable.create = AsyncMock(return_value=mock_created_team) + mock_prisma.db.litellm_teamtable.update = AsyncMock(return_value=mock_created_team) + mock_prisma.jsonify_team_object = MagicMock(side_effect=lambda db_data: db_data) + + # Should succeed - bypasses user limits since org-scoped + result = await new_team( + data=team_request, + http_request=dummy_request, + user_api_key_dict=org_admin_user, + ) + + # Verify team was created + assert result["team_id"] == "new-bypass-team-id" + + +@pytest.mark.asyncio +async def test_update_team_org_scoped_tpm_exceeds_org_limit(): + """ + Test that /team/update for an org-scoped team fails when TPM exceeds organization's TPM limit. + + Scenario: + - Organization has tpm_limit=10000 + - User tries to update org-scoped team with tpm_limit=20000 + - Expected: Should fail with error about exceeding org TPM limit + """ + from fastapi import Request + + from litellm.proxy._types import UpdateTeamRequest, ProxyException, UserAPIKeyAuth, LiteLLM_OrganizationTable, LiteLLM_BudgetTable + from litellm.proxy.management_endpoints.team_endpoints import update_team + + # Create user (with restrictive personal TPM limit that should be bypassed) + org_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org-admin-update-tpm-test", + models=[], + tpm_limit=1000, # User's personal limit (should be bypassed for org teams) + ) + + # Create update request with TPM exceeding org's limit + update_request = UpdateTeamRequest( + team_id="org-team-update-tpm-123", + tpm_limit=20000, # Exceeds org's 10000 limit + ) + + dummy_request = MagicMock(spec=Request) + + # Mock organization with TPM limit + mock_budget_table = MagicMock(spec=LiteLLM_BudgetTable) + mock_budget_table.tpm_limit = 10000 # Org's TPM limit + mock_budget_table.rpm_limit = None + mock_budget_table.max_budget = None + + mock_org = MagicMock(spec=LiteLLM_OrganizationTable) + mock_org.organization_id = "test-org-update-tpm" + mock_org.models = ["gpt-4"] + mock_org.litellm_budget_table = mock_budget_table + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.management_endpoints.team_endpoints.get_org_object", + new=AsyncMock(return_value=mock_org) + ): + + # Mock existing org-scoped team + mock_existing_team = MagicMock() + mock_existing_team.team_id = "org-team-update-tpm-123" + mock_existing_team.organization_id = "test-org-update-tpm" + mock_existing_team.tpm_limit = 5000 + mock_existing_team.model_dump.return_value = { + "team_id": "org-team-update-tpm-123", + "organization_id": "test-org-update-tpm", + "tpm_limit": 5000, + } + mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=mock_existing_team) + + # Should raise ProxyException because TPM exceeds org limit + with pytest.raises(ProxyException) as exc_info: + await update_team( + data=update_request, + http_request=dummy_request, + user_api_key_dict=org_admin_user, + ) + + # Verify exception details + assert exc_info.value.code == '400' + assert "tpm" in str(exc_info.value.message).lower() + + +@pytest.mark.asyncio +async def test_update_team_org_scoped_rpm_exceeds_org_limit(): + """ + Test that /team/update for an org-scoped team fails when RPM exceeds organization's RPM limit. + + Scenario: + - Organization has rpm_limit=1000 + - User tries to update org-scoped team with rpm_limit=2000 + - Expected: Should fail with error about exceeding org RPM limit + """ + from fastapi import Request + + from litellm.proxy._types import UpdateTeamRequest, ProxyException, UserAPIKeyAuth, LiteLLM_OrganizationTable, LiteLLM_BudgetTable + from litellm.proxy.management_endpoints.team_endpoints import update_team + + # Create user (with restrictive personal RPM limit that should be bypassed) + org_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org-admin-update-rpm-test", + models=[], + rpm_limit=100, # User's personal limit (should be bypassed for org teams) + ) + + # Create update request with RPM exceeding org's limit + update_request = UpdateTeamRequest( + team_id="org-team-update-rpm-123", + rpm_limit=2000, # Exceeds org's 1000 limit + ) + + dummy_request = MagicMock(spec=Request) + + # Mock organization with RPM limit + mock_budget_table = MagicMock(spec=LiteLLM_BudgetTable) + mock_budget_table.tpm_limit = None + mock_budget_table.rpm_limit = 1000 # Org's RPM limit + mock_budget_table.max_budget = None + + mock_org = MagicMock(spec=LiteLLM_OrganizationTable) + mock_org.organization_id = "test-org-update-rpm" + mock_org.models = ["gpt-4"] + mock_org.litellm_budget_table = mock_budget_table + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.management_endpoints.team_endpoints.get_org_object", + new=AsyncMock(return_value=mock_org) + ): + + # Mock existing org-scoped team + mock_existing_team = MagicMock() + mock_existing_team.team_id = "org-team-update-rpm-123" + mock_existing_team.organization_id = "test-org-update-rpm" + mock_existing_team.rpm_limit = 500 + mock_existing_team.model_dump.return_value = { + "team_id": "org-team-update-rpm-123", + "organization_id": "test-org-update-rpm", + "rpm_limit": 500, + } + mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=mock_existing_team) + + # Should raise ProxyException because RPM exceeds org limit + with pytest.raises(ProxyException) as exc_info: + await update_team( + data=update_request, + http_request=dummy_request, + user_api_key_dict=org_admin_user, + ) + + # Verify exception details + assert exc_info.value.code == '400' + assert "rpm" in str(exc_info.value.message).lower() + + +@pytest.mark.asyncio +async def test_update_team_org_scoped_tpm_rpm_bypasses_user_limit(): + """ + Test that /team/update for an org-scoped team bypasses user's TPM/RPM limits. + + Scenario: + - User has tpm_limit=1000, rpm_limit=100 + - Organization has tpm_limit=50000, rpm_limit=5000 + - User updates org-scoped team with tpm_limit=10000, rpm_limit=1000 + - Expected: Should succeed (bypasses user limits, within org limits) + """ + from fastapi import Request + + from litellm.proxy._types import UpdateTeamRequest, UserAPIKeyAuth, LiteLLM_OrganizationTable, LiteLLM_BudgetTable, LiteLLM_TeamTable + from litellm.proxy.management_endpoints.team_endpoints import update_team + + # Create user with restrictive personal limits + org_admin_user = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org-admin-update-bypass-test", + models=[], + tpm_limit=1000, # Restrictive user TPM limit + rpm_limit=100, # Restrictive user RPM limit + ) + + # Create update request exceeding user limits but within org limits + update_request = UpdateTeamRequest( + team_id="org-team-update-bypass-123", + tpm_limit=10000, # Exceeds user's 1000 but within org's 50000 + rpm_limit=1000, # Exceeds user's 100 but within org's 5000 + ) + + dummy_request = MagicMock(spec=Request) + + # Mock organization with generous limits + mock_budget_table = MagicMock(spec=LiteLLM_BudgetTable) + mock_budget_table.tpm_limit = 50000 # Generous org TPM limit + mock_budget_table.rpm_limit = 5000 # Generous org RPM limit + mock_budget_table.max_budget = None + + mock_org = MagicMock(spec=LiteLLM_OrganizationTable) + mock_org.organization_id = "test-org-update-bypass" + mock_org.models = ["gpt-4"] + mock_org.litellm_budget_table = mock_budget_table + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, patch( + "litellm.proxy.proxy_server.user_api_key_cache" + ) as mock_cache, patch( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", "admin" + ), patch( + "litellm.proxy.proxy_server.proxy_logging_obj" + ) as mock_logging, patch( + "litellm.proxy.management_endpoints.team_endpoints.get_org_object", + new=AsyncMock(return_value=mock_org) + ): + + # Mock existing org-scoped team + mock_existing_team = MagicMock() + mock_existing_team.team_id = "org-team-update-bypass-123" + mock_existing_team.organization_id = "test-org-update-bypass" + mock_existing_team.tpm_limit = 5000 + mock_existing_team.rpm_limit = 500 + mock_existing_team.model_id = None + mock_existing_team.model_dump.return_value = { + "team_id": "org-team-update-bypass-123", + "organization_id": "test-org-update-bypass", + "tpm_limit": 5000, + "rpm_limit": 500, + } + mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=mock_existing_team) + mock_cache.async_set_cache = AsyncMock() + + # Mock team update + mock_updated_team = MagicMock(spec=LiteLLM_TeamTable) + mock_updated_team.team_id = "org-team-update-bypass-123" + mock_updated_team.tpm_limit = 10000 + mock_updated_team.rpm_limit = 1000 + mock_updated_team.model_dump.return_value = { + "team_id": "org-team-update-bypass-123", + "tpm_limit": 10000, + "rpm_limit": 1000, + } + mock_prisma.db.litellm_teamtable.update = AsyncMock(return_value=mock_updated_team) + mock_prisma.jsonify_team_object = MagicMock(side_effect=lambda db_data: db_data) + + # Should succeed - bypasses user limits since org-scoped + result = await update_team( + data=update_request, + http_request=dummy_request, + user_api_key_dict=org_admin_user, + ) + + # Verify team was updated + assert result["team_id"] == "org-team-update-bypass-123" \ No newline at end of file From 98a244450e1d14649f9edbd43c4ace5962d605c7 Mon Sep 17 00:00:00 2001 From: rioiart Date: Tue, 2 Dec 2025 04:53:30 +0100 Subject: [PATCH 22/47] Fix sso users not added to entra synced team (#17331) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: add failing tests for SSO user not added to Entra-synced teams bug Adds tests reproducing the bug where new SSO users with teams=None (from NewUserResponse) are not added to Entra ID synced teams because add_missing_team_member() returns early when teams is None. Tests demonstrate: - NewUserResponse with teams=None fails to add user to teams (bug) - LiteLLM_UserTable with teams=[] correctly adds user to teams (control) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude * fix: treat None as empty list in add_missing_team_member for new SSO users Fixed bug where new SSO users logging in via Microsoft SSO were not added to their Entra-synced teams. The issue was an early return when user_info.teams is None (default for NewUserResponse). Now treats None as an empty list so new users are properly added to all their SSO teams. Location: litellm/proxy/management_endpoints/ui_sso.py:438-440 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --------- Co-authored-by: Claude --- litellm/proxy/management_endpoints/ui_sso.py | 6 +- .../proxy/management_endpoints/test_ui_sso.py | 209 +++++++++++++++++- 2 files changed, 211 insertions(+), 4 deletions(-) diff --git a/litellm/proxy/management_endpoints/ui_sso.py b/litellm/proxy/management_endpoints/ui_sso.py index a033e2cf5f4..59a93f3c486 100644 --- a/litellm/proxy/management_endpoints/ui_sso.py +++ b/litellm/proxy/management_endpoints/ui_sso.py @@ -435,9 +435,9 @@ async def add_missing_team_member( - Get missing teams (diff b/w user_info.team_ids and sso_teams) - Add missing user to missing teams """ - if user_info.teams is None: - return - missing_teams = set(sso_teams) - set(user_info.teams) + # Handle None as empty list for new users + user_teams = user_info.teams if user_info.teams is not None else [] + missing_teams = set(sso_teams) - set(user_teams) missing_teams_list = list(missing_teams) tasks = [] tasks = [ diff --git a/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py b/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py index f01813fa587..8d7aa51fa0f 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py +++ b/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py @@ -16,7 +16,7 @@ sys.path.insert( ) # Adds the parent directory to the system path import litellm -from litellm.proxy._types import NewTeamRequest +from litellm.proxy._types import LiteLLM_UserTable, NewTeamRequest, NewUserResponse from litellm.proxy.auth.handle_jwt import JWTHandler from litellm.proxy.management_endpoints.types import CustomOpenID from litellm.proxy.management_endpoints.ui_sso import ( @@ -2573,3 +2573,210 @@ class TestPKCEFunctionality: assert "code_challenge=" in updated_location assert "code_challenge_method=S256" in updated_location assert f"state={test_state}" in updated_location + + +# Tests for SSO user team assignment bug (Issue: SSO Users Not Added to Entra-Synced Teams on First Login) +class TestAddMissingTeamMember: + """Tests for the add_missing_team_member function""" + + @pytest.mark.asyncio + async def test_add_missing_team_member_with_new_user_response_teams_none(self): + """ + Bug reproduction: When a NewUserResponse has teams=None (new SSO user), + add_missing_team_member() should still add the user to the SSO teams. + + Currently FAILS: The function returns early when teams is None. + """ + from litellm.proxy._types import NewUserResponse + from litellm.proxy.management_endpoints.ui_sso import add_missing_team_member + + # Simulate a new SSO user - NewUserResponse has teams=None by default + new_user = NewUserResponse( + user_id="new-sso-user-123", + key="sk-xxxxx", + teams=None, # This is the default for NewUserResponse + ) + + sso_teams = ["team-from-entra-1", "team-from-entra-2"] + + with patch( + "litellm.proxy.management_endpoints.ui_sso.create_team_member_add_task" + ) as mock_add_task: + mock_add_task.return_value = AsyncMock() + + await add_missing_team_member(user_info=new_user, sso_teams=sso_teams) + + # Bug: This assertion currently FAILS - no teams are added + # because function returns early when teams is None + assert ( + mock_add_task.call_count == 2 + ), f"Expected 2 calls to add user to teams, but got {mock_add_task.call_count}" + called_team_ids = [call.args[0] for call in mock_add_task.call_args_list] + assert set(called_team_ids) == { + "team-from-entra-1", + "team-from-entra-2", + } + + @pytest.mark.asyncio + async def test_add_missing_team_member_with_litellm_user_table_empty_teams(self): + """ + Control test: When a LiteLLM_UserTable has teams=[] (existing user, no teams), + add_missing_team_member() should add the user to SSO teams. + + This test PASSES because LiteLLM_UserTable defaults teams to [] not None. + """ + from litellm.proxy._types import LiteLLM_UserTable + from litellm.proxy.management_endpoints.ui_sso import add_missing_team_member + + # Existing user has teams=[] by default (not None) + existing_user = LiteLLM_UserTable( + user_id="existing-user-456", + teams=[], # Empty list, not None + ) + + sso_teams = ["team-from-entra-1", "team-from-entra-2"] + + with patch( + "litellm.proxy.management_endpoints.ui_sso.create_team_member_add_task" + ) as mock_add_task: + mock_add_task.return_value = AsyncMock() + + await add_missing_team_member(user_info=existing_user, sso_teams=sso_teams) + + # This PASSES - teams are added because teams=[] not None + assert mock_add_task.call_count == 2 + + @pytest.mark.asyncio + async def test_add_user_to_teams_from_sso_response_new_user(self): + """ + Integration test: Simulates the SSO response handler with a new user + that has teams=None from NewUserResponse. + """ + from litellm.proxy._types import NewUserResponse + from litellm.proxy.management_endpoints.types import CustomOpenID + from litellm.proxy.management_endpoints.ui_sso import ( + SSOAuthenticationHandler, + ) + + # SSO response with team_ids from Entra ID + sso_result = CustomOpenID( + id="new-sso-user-id", + email="newuser@example.com", + team_ids=["entra-group-1", "entra-group-2"], + ) + + # New user response (simulates what new_user() returns) + new_user_info = NewUserResponse( + user_id="new-sso-user-id", + key="sk-xxxxx", + teams=None, # Bug: NewUserResponse defaults to None + ) + + with patch( + "litellm.proxy.management_endpoints.ui_sso.add_missing_team_member" + ) as mock_add_member: + await SSOAuthenticationHandler.add_user_to_teams_from_sso_response( + result=sso_result, + user_info=new_user_info, + ) + + # Verify add_missing_team_member was called with correct args + mock_add_member.assert_called_once_with( + user_info=new_user_info, sso_teams=["entra-group-1", "entra-group-2"] + ) + + @pytest.mark.asyncio + async def test_sso_first_login_full_flow_adds_user_to_teams(self): + """ + End-to-end test: Simulates complete first-time SSO login with Entra groups. + Verifies teams are created AND user is added as a member. + """ + from litellm.proxy._types import NewUserResponse + from litellm.proxy.management_endpoints.ui_sso import add_missing_team_member + + team_member_calls = [] + + async def track_team_member_add(team_id, user_info): + team_member_calls.append( + {"team_id": team_id, "user_id": user_info.user_id} + ) + + # New SSO user with Entra groups + new_user = NewUserResponse( + user_id="first-time-sso-user", + key="sk-xxxxx", + teams=None, # The problematic default + ) + + sso_teams = ["entra-team-alpha", "entra-team-beta"] + + with patch( + "litellm.proxy.management_endpoints.ui_sso.create_team_member_add_task", + side_effect=track_team_member_add, + ): + await add_missing_team_member(user_info=new_user, sso_teams=sso_teams) + + # Bug: With current code, team_member_calls will be empty + # After fix: Should have 2 entries + assert ( + len(team_member_calls) == 2 + ), f"Expected 2 teams to be added, but got {len(team_member_calls)}" + assert {c["team_id"] for c in team_member_calls} == { + "entra-team-alpha", + "entra-team-beta", + } + assert all(c["user_id"] == "first-time-sso-user" for c in team_member_calls) + + @pytest.mark.asyncio + @pytest.mark.parametrize( + "user_info_factory,teams_value,expected_teams_added", + [ + # Bug case: NewUserResponse with teams=None + pytest.param( + lambda uid: NewUserResponse(user_id=uid, key="sk-xxx", teams=None), + None, + ["team-1", "team-2"], # Should still add teams + id="new_user_teams_none", + ), + # Working case: LiteLLM_UserTable with teams=[] + pytest.param( + lambda uid: LiteLLM_UserTable(user_id=uid, teams=[]), + [], + ["team-1", "team-2"], + id="existing_user_empty_teams", + ), + # Existing user with some teams already + pytest.param( + lambda uid: LiteLLM_UserTable(user_id=uid, teams=["team-1"]), + ["team-1"], + ["team-2"], # Only missing team should be added + id="existing_user_partial_teams", + ), + ], + ) + async def test_add_missing_team_member_handles_all_user_types( + self, user_info_factory, teams_value, expected_teams_added + ): + """ + Parametrized test ensuring add_missing_team_member works for all user types. + """ + from litellm.proxy._types import LiteLLM_UserTable + from litellm.proxy.management_endpoints.ui_sso import add_missing_team_member + + user_info = user_info_factory("test-user-id") + sso_teams = ["team-1", "team-2"] + + added_teams = [] + + async def mock_create_task(team_id, user): + added_teams.append(team_id) + + with patch( + "litellm.proxy.management_endpoints.ui_sso.create_team_member_add_task", + side_effect=mock_create_task, + ): + await add_missing_team_member(user_info=user_info, sso_teams=sso_teams) + + assert set(added_teams) == set( + expected_teams_added + ), f"Expected teams {expected_teams_added}, but got {added_teams}" From 71efcb71151aedb216e411815ce871376605da55 Mon Sep 17 00:00:00 2001 From: idola9 Date: Tue, 2 Dec 2025 05:56:14 +0200 Subject: [PATCH 23/47] Refactor Noma guardrail to use shared Responses transformation and include system instructions (#17315) * Support system prompts in noma guardrails * Use litellm util to covert chat completions to responses api --- .../transformation.py | 6 +- .../guardrails/guardrail_hooks/noma/noma.py | 78 ++-- .../guardrails/guardrail_hooks/test_noma.py | 335 ++++++++++++------ 3 files changed, 263 insertions(+), 156 deletions(-) diff --git a/litellm/completion_extras/litellm_responses_transformation/transformation.py b/litellm/completion_extras/litellm_responses_transformation/transformation.py index 07d9de5a016..2045836387f 100644 --- a/litellm/completion_extras/litellm_responses_transformation/transformation.py +++ b/litellm/completion_extras/litellm_responses_transformation/transformation.py @@ -148,7 +148,11 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): if role == "system": # Extract system message as instructions if isinstance(content, str): - instructions = content + if instructions: + # Concatenate multiple system prompts with a space + instructions = f"{instructions} {content}" + else: + instructions = content else: input_items.append( { diff --git a/litellm/proxy/guardrails/guardrail_hooks/noma/noma.py b/litellm/proxy/guardrails/guardrail_hooks/noma/noma.py index 3ae2d519c45..a0ea90ccf21 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/noma/noma.py +++ b/litellm/proxy/guardrails/guardrail_hooks/noma/noma.py @@ -28,6 +28,9 @@ from fastapi import HTTPException import litellm from litellm import DualCache, ModelResponse from litellm._logging import verbose_proxy_logger +from litellm.completion_extras.litellm_responses_transformation.transformation import ( + LiteLLMResponsesTransformationHandler, +) from litellm.integrations.custom_guardrail import CustomGuardrail from litellm.llms.base_llm.base_model_iterator import MockResponseIterator from litellm.llms.custom_httpx.http_handler import ( @@ -111,6 +114,7 @@ class NomaGuardrail(CustomGuardrail): self.async_handler = get_async_httpx_client( llm_provider=httpxSpecialProvider.GuardrailCallback ) + self._responses_transform_handler = LiteLLMResponsesTransformationHandler() self.api_key = api_key or os.environ.get("NOMA_API_KEY") self.api_base = api_base or os.environ.get( "NOMA_API_BASE", NomaGuardrail._DEFAULT_API_BASE @@ -164,13 +168,28 @@ class NomaGuardrail(CustomGuardrail): start_time = datetime.now() extra_data = self.get_guardrail_dynamic_request_body_params(request_data) - user_message = await self._extract_user_message(request_data) - if not user_message: + messages = request_data.get("messages") or [] + if not messages: return None - payload = { - "input": [{"type": "message", "role": "user", "content": user_message}] - } + input_items, instructions = self._responses_transform_handler.convert_chat_completion_messages_to_responses_api( # type: ignore[arg-type] + messages + ) + + if instructions: + system_message = { + "type": "message", + "role": "system", + "content": [ + {"type": "input_text", "text": instructions}, + ], + } + input_items.insert(0, system_message) + + if not input_items: + return None + + payload = {"input": input_items} response_json = await self._call_noma_api( payload=payload, llm_request_id=None, @@ -198,9 +217,9 @@ class NomaGuardrail(CustomGuardrail): if self.monitor_mode: await self._handle_verdict_background( - USER_ROLE, json.dumps(user_message), response_json + USER_ROLE, json.dumps(input_items), response_json ) - return json.dumps(user_message) + return json.dumps(input_items) # Check if we should anonymize content if self._should_anonymize(response_json, USER_ROLE): @@ -215,8 +234,8 @@ class NomaGuardrail(CustomGuardrail): ) return anonymized_content - await self._check_verdict(USER_ROLE, json.dumps(user_message), response_json) - return json.dumps(user_message) + await self._check_verdict(USER_ROLE, json.dumps(input_items), response_json) + return json.dumps(input_items) async def _process_llm_response_check( self, @@ -732,47 +751,6 @@ class NomaGuardrail(CustomGuardrail): return response - async def _extract_user_message(self, data: dict) -> Optional[List[dict]]: - """Extract the last user message from request data""" - messages = data.get("messages", []) - if not messages: - return None - - # Get the last user message - user_messages = [msg for msg in messages if msg.get("role") == USER_ROLE] - if not user_messages: - return None - - last_user_message = user_messages[-1].get("content", "") - if isinstance(last_user_message, str): - return [{"type": "input_text", "text": last_user_message}] - elif isinstance(last_user_message, list): - converted_messages = [] - for message in last_user_message: - converted_message = self._convert_single_user_message_to_payload( - message - ) - if converted_message is not None: - converted_messages.append(converted_message) - return converted_messages - else: - return None - - def _convert_single_user_message_to_payload( - self, user_message: Any - ) -> Optional[dict]: - if isinstance(user_message, str): - return {"type": "input_text", "text": user_message} - elif user_message.get("type", "") == "image_url": - return { - "type": "input_image", - "image_url": user_message.get("image_url", {}).get("url", ""), - } - elif user_message.get("type", "") == "text": - return {"type": "input_text", "text": user_message.get("text", "")} - else: - return None - async def _call_noma_api( self, payload: dict, diff --git a/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_noma.py b/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_noma.py index 94cb831a30c..f1ac6ef14b1 100644 --- a/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_noma.py +++ b/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_noma.py @@ -1,5 +1,6 @@ import copy import os +from typing import cast from unittest.mock import AsyncMock, MagicMock, patch import httpx @@ -14,6 +15,7 @@ from litellm.proxy.guardrails.guardrail_hooks.noma import ( ) from litellm.proxy.guardrails.guardrail_hooks.noma.noma import NomaBlockedMessage from litellm.proxy.guardrails.init_guardrails import init_guardrails_v2 +from litellm.types.llms.openai import AllMessageValues from litellm.types.utils import Choices, Message @@ -413,7 +415,7 @@ class TestNomaGuardrailHooks: # Verify API call details call_args = mock_post.call_args - # Verify the URL endpoint + # Verify the URL endpoint assert call_args.args[0].endswith("/ai-dr/v2/prompt/scan") # Verify headers and JSON payload if "headers" in call_args.kwargs: @@ -426,6 +428,130 @@ class TestNomaGuardrailHooks: assert "x-noma-context" in json_payload assert json_payload["x-noma-context"]["applicationId"] == "test-app" + @pytest.mark.asyncio + async def test_pre_call_hook_with_system_prompt( + self, noma_guardrail, mock_user_api_key_dict + ): + """Test pre-call hook includes system prompt in Noma API request""" + request_data = { + "messages": [ + {"role": "system", "content": "You are a helpful assistant"}, + {"role": "user", "content": "Hello, how are you?"}, + ], + "litellm_call_id": "test-call-id", + "metadata": {"requester_ip_address": "192.168.1.1"}, + } + + mock_response = MagicMock() + mock_response.json.return_value = { + "aggregatedScanResult": False, # False means safe + "scanResult": [ + { + "role": "system", + "type": "message", + "results": {} + }, + { + "role": "user", + "type": "message", + "results": {} + } + ] + } + mock_response.raise_for_status = MagicMock() + + with patch.object( + noma_guardrail.async_handler, "post", return_value=mock_response + ) as mock_post: + result = await noma_guardrail.async_pre_call_hook( + user_api_key_dict=mock_user_api_key_dict, + cache=MagicMock(), + data=request_data, + call_type="completion", + ) + + assert result == request_data + mock_post.assert_called_once() + + # Verify the payload includes both system and user messages + call_args = mock_post.call_args + json_payload = call_args.kwargs["json"] + assert "input" in json_payload + messages = json_payload["input"] + + # Should have 2 messages: system and user + assert len(messages) == 2 + + # First message should be system + assert messages[0]["type"] == "message" + assert messages[0]["role"] == "system" + assert messages[0]["content"][0]["type"] == "input_text" + assert messages[0]["content"][0]["text"] == "You are a helpful assistant" + + # Second message should be user + assert messages[1]["type"] == "message" + assert messages[1]["role"] == "user" + assert messages[1]["content"][0]["type"] == "input_text" + assert messages[1]["content"][0]["text"] == "Hello, how are you?" + + @pytest.mark.asyncio + async def test_pre_call_hook_with_multiple_system_prompts( + self, noma_guardrail, mock_user_api_key_dict + ): + """Test pre-call hook combines multiple system prompts into single message""" + request_data = { + "messages": [ + {"role": "system", "content": "You are a helpful assistant"}, + {"role": "system", "content": "You should be polite and respectful"}, + {"role": "user", "content": "Hello, how are you?"}, + ], + "litellm_call_id": "test-call-id", + } + + mock_response = MagicMock() + mock_response.json.return_value = { + "aggregatedScanResult": False, + "scanResult": [ + {"role": "system", "type": "message", "results": {}}, + {"role": "user", "type": "message", "results": {}} + ] + } + mock_response.raise_for_status = MagicMock() + + with patch.object( + noma_guardrail.async_handler, "post", return_value=mock_response + ) as mock_post: + result = await noma_guardrail.async_pre_call_hook( + user_api_key_dict=mock_user_api_key_dict, + cache=MagicMock(), + data=request_data, + call_type="completion", + ) + + assert result == request_data + mock_post.assert_called_once() + + # Verify the payload combines system prompts into single message + call_args = mock_post.call_args + json_payload = call_args.kwargs["json"] + messages = json_payload["input"] + + # Should have 2 messages: 1 combined system and 1 user + assert len(messages) == 2 + + # First message should be system with combined content + assert messages[0]["role"] == "system" + assert messages[0]["content"][0]["type"] == "input_text" + assert ( + messages[0]["content"][0]["text"] + == "You are a helpful assistant You should be polite and respectful" + ) + + # Second message should be user + assert messages[1]["role"] == "user" + assert messages[1]["content"][0]["type"] == "input_text" + assert messages[1]["content"][0]["text"] == "Hello, how are you?" + @pytest.mark.asyncio async def test_pre_call_hook_blocked( self, noma_guardrail, mock_user_api_key_dict, mock_request_data @@ -644,34 +770,6 @@ class TestNomaGuardrailHooks: assert result == mock_request_data - def test_extract_user_message(self, noma_guardrail): - data = { - "messages": [ - {"role": "system", "content": "System prompt"}, - {"role": "user", "content": "First user message"}, - {"role": "assistant", "content": "Assistant response"}, - {"role": "user", "content": "Second user message"}, - ] - } - - import asyncio - - message = asyncio.run(noma_guardrail._extract_user_message(data)) - assert message == [{"type": "input_text", "text": "Second user message"}] - - data = {"messages": [{"role": "system", "content": "System prompt"}]} - message = asyncio.run(noma_guardrail._extract_user_message(data)) - assert message is None - - data = {"messages": []} - message = asyncio.run(noma_guardrail._extract_user_message(data)) - assert message is None - - data = {} - message = asyncio.run(noma_guardrail._extract_user_message(data)) - assert message is None - - class TestBackgroundProcessing: """Test the new background processing functionality""" @@ -1025,57 +1123,66 @@ class TestNomaImageProcessing: metadata={}, ) - def test_extract_user_message_with_image_url(self, noma_guardrail): - """Test extracting user message with image_url content""" - import asyncio - - data = { - "messages": [ - { - "role": "user", - "content": [ - { - "type": "image_url", - "image_url": { - "url": "https://example.com/image.jpg" - } - } - ] - } - ] - } + def test_extract_user_message_with_image_url(self): + """User message with only image_url becomes a single input_image content item.""" + from litellm.completion_extras.litellm_responses_transformation.transformation import ( + LiteLLMResponsesTransformationHandler, + ) - message = asyncio.run(noma_guardrail._extract_user_message(data)) + handler = LiteLLMResponsesTransformationHandler() + messages: list[AllMessageValues] = [ + { + "role": "user", + "content": [ + { + "type": "image_url", + "image_url": { + "url": "https://example.com/image.jpg" + } + } + ] + } + ] + + input_items, _ = handler.convert_chat_completion_messages_to_responses_api(messages) + + assert len(input_items) == 1 + message = input_items[0]["content"] assert message is not None assert len(message) == 1 assert message[0]["type"] == "input_image" assert message[0]["image_url"] == "https://example.com/image.jpg" - def test_extract_user_message_with_mixed_content(self, noma_guardrail): - """Test extracting user message with mixed text and image content""" - import asyncio - - data = { - "messages": [ - { - "role": "user", - "content": [ - { - "type": "text", - "text": "What's in this image?" - }, - { - "type": "image_url", - "image_url": { - "url": "https://example.com/image.jpg" - } - } - ] - } - ] - } + def test_extract_user_message_with_mixed_content(self): + """User message with text + image becomes input_text then input_image in content list.""" + from litellm.completion_extras.litellm_responses_transformation.transformation import ( + LiteLLMResponsesTransformationHandler, + ) - message = asyncio.run(noma_guardrail._extract_user_message(data)) + handler = LiteLLMResponsesTransformationHandler() + messages: list[AllMessageValues] = [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "What's in this image?", + }, + { + "type": "image_url", + "image_url": { + "url": "https://example.com/image.jpg" + } + } + ] + } + ] + + input_items, _ = handler.convert_chat_completion_messages_to_responses_api(messages) + + # Match the original assertions: `message` is the content list + assert len(input_items) == 1 + message = input_items[0]["content"] assert message is not None assert len(message) == 2 # First item should be text @@ -1085,37 +1192,43 @@ class TestNomaImageProcessing: assert message[1]["type"] == "input_image" assert message[1]["image_url"] == "https://example.com/image.jpg" - def test_extract_user_message_with_multiple_images(self, noma_guardrail): - """Test extracting user message with multiple images""" - import asyncio - - data = { - "messages": [ - { - "role": "user", - "content": [ - { - "type": "text", - "text": "Compare these images" - }, - { - "type": "image_url", - "image_url": { - "url": "https://example.com/image1.jpg" - } - }, - { - "type": "image_url", - "image_url": { - "url": "https://example.com/image2.jpg" - } - } - ] - } - ] - } + def test_extract_user_message_with_multiple_images(self): + """User message with multiple images becomes multiple input_image items.""" + from litellm.completion_extras.litellm_responses_transformation.transformation import ( + LiteLLMResponsesTransformationHandler, + ) - message = asyncio.run(noma_guardrail._extract_user_message(data)) + handler = LiteLLMResponsesTransformationHandler() + + messages: list[AllMessageValues] = [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Compare these images", + }, + { + "type": "image_url", + "image_url": { + "url": "https://example.com/image1.jpg" + } + }, + { + "type": "image_url", + "image_url": { + "url": "https://example.com/image2.jpg" + } + } + ] + } + ] + + input_items, _ = handler.convert_chat_completion_messages_to_responses_api(messages) + + # Match the original assertions + assert len(input_items) == 1 + message = input_items[0]["content"] assert message is not None assert len(message) == 3 assert message[0]["type"] == "input_text" @@ -1301,8 +1414,14 @@ class TestNomaImageProcessing: assert exc_info.value.status_code == 400 @pytest.mark.asyncio - async def test_image_with_base64_data(self, noma_guardrail): + async def test_image_with_base64_data( + self, noma_guardrail, mock_user_api_key_dict + ): """Test extracting image with base64 data URL""" + from litellm.completion_extras.litellm_responses_transformation.transformation import ( + LiteLLMResponsesTransformationHandler, + ) + data = { "messages": [ { @@ -1319,7 +1438,13 @@ class TestNomaImageProcessing: ] } - message = await noma_guardrail._extract_user_message(data) + handler = LiteLLMResponsesTransformationHandler() + messages = cast(list[AllMessageValues], data["messages"]) + + input_items, _ = handler.convert_chat_completion_messages_to_responses_api(messages) + + assert len(input_items) == 1 + message = input_items[0]["content"] assert message is not None assert len(message) == 1 assert message[0]["type"] == "input_image" From 965406c643077dc5375a2c7bcd28c801caf807a6 Mon Sep 17 00:00:00 2001 From: Cesar Garcia <128240629+Chesars@users.noreply.github.com> Date: Tue, 2 Dec 2025 00:56:47 -0300 Subject: [PATCH 24/47] feat(provider): add Z.AI (Zhipu AI) as built-in provider (#17307) * feat(provider): add Z.AI (Zhipu AI) as built-in provider Add support for Z.AI GLM models as a native OpenAI-compatible provider. - Add "zai" to openai_compatible_providers list - Add ZAI enum to LlmProviders - Add provider URL resolution for https://api.z.ai/api/paas/v4 - Add 8 GLM models with pricing to model cost maps: - glm-4.6 (200K context, $0.6/$2.2 per 1M tokens) - glm-4.5, glm-4.5v, glm-4.5-x, glm-4.5-air, glm-4.5-airx - glm-4-32b-0414-128k - glm-4.5-flash (free tier) - Add unit tests for provider integration Closes #17289 * docs: add Z.AI provider documentation - Add zai.md with usage examples, model list, and pricing - Add to sidebars.js navigation --- docs/my-website/docs/providers/zai.md | 135 ++++++++++++++++ docs/my-website/sidebars.js | 1 + litellm/constants.py | 1 + .../get_llm_provider_logic.py | 7 + ...odel_prices_and_context_window_backup.json | 89 +++++++++++ litellm/types/utils.py | 1 + model_prices_and_context_window.json | 89 +++++++++++ .../llms/zai/test_zai_provider.py | 144 ++++++++++++++++++ 8 files changed, 467 insertions(+) create mode 100644 docs/my-website/docs/providers/zai.md create mode 100644 tests/test_litellm/llms/zai/test_zai_provider.py diff --git a/docs/my-website/docs/providers/zai.md b/docs/my-website/docs/providers/zai.md new file mode 100644 index 00000000000..5055d0c1cdd --- /dev/null +++ b/docs/my-website/docs/providers/zai.md @@ -0,0 +1,135 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Z.AI (Zhipu AI) +https://z.ai/ + +**We support Z.AI GLM text/chat models, just set `zai/` as a prefix when sending completion requests** + +## API Key +```python +# env variable +os.environ['ZAI_API_KEY'] +``` + +## Sample Usage +```python +from litellm import completion +import os + +os.environ['ZAI_API_KEY'] = "" +response = completion( + model="zai/glm-4.6", + messages=[ + {"role": "user", "content": "hello from litellm"} + ], +) +print(response) +``` + +## Sample Usage - Streaming +```python +from litellm import completion +import os + +os.environ['ZAI_API_KEY'] = "" +response = completion( + model="zai/glm-4.6", + messages=[ + {"role": "user", "content": "hello from litellm"} + ], + stream=True +) + +for chunk in response: + print(chunk) +``` + +## Supported Models + +We support ALL Z.AI GLM models, just set `zai/` as a prefix when sending completion requests. + +| Model Name | Function Call | Notes | +|------------|---------------|-------| +| glm-4.6 | `completion(model="zai/glm-4.6", messages)` | Latest flagship model, 200K context | +| glm-4.5 | `completion(model="zai/glm-4.5", messages)` | 128K context | +| glm-4.5v | `completion(model="zai/glm-4.5v", messages)` | Vision model | +| glm-4.5-x | `completion(model="zai/glm-4.5-x", messages)` | Premium tier | +| glm-4.5-air | `completion(model="zai/glm-4.5-air", messages)` | Lightweight | +| glm-4.5-airx | `completion(model="zai/glm-4.5-airx", messages)` | Fast lightweight | +| glm-4-32b-0414-128k | `completion(model="zai/glm-4-32b-0414-128k", messages)` | 32B parameter model | +| glm-4.5-flash | `completion(model="zai/glm-4.5-flash", messages)` | **FREE tier** | + +## Model Pricing + +| Model | Input ($/1M tokens) | Output ($/1M tokens) | Context Window | +|-------|---------------------|----------------------|----------------| +| glm-4.6 | $0.60 | $2.20 | 200K | +| glm-4.5 | $0.60 | $2.20 | 128K | +| glm-4.5v | $0.60 | $1.80 | 128K | +| glm-4.5-x | $2.20 | $8.90 | 128K | +| glm-4.5-air | $0.20 | $1.10 | 128K | +| glm-4.5-airx | $1.10 | $4.50 | 128K | +| glm-4-32b-0414-128k | $0.10 | $0.10 | 128K | +| glm-4.5-flash | **FREE** | **FREE** | 128K | + +## Using with LiteLLM Proxy + + + + +```python +from litellm import completion +import os + +os.environ['ZAI_API_KEY'] = "" +response = completion( + model="zai/glm-4.6", + messages=[{"role": "user", "content": "Hello, how are you?"}], +) + +print(response.choices[0].message.content) +``` + + + + +1. Setup config.yaml + +```yaml +model_list: + - model_name: glm-4.6 + litellm_params: + model: zai/glm-4.6 + api_key: os.environ/ZAI_API_KEY + - model_name: glm-4.5-flash # Free tier + litellm_params: + model: zai/glm-4.5-flash + api_key: os.environ/ZAI_API_KEY +``` + +2. Run proxy + +```bash +litellm --config config.yaml +``` + +3. Test it! + +```bash +curl -L -X POST 'http://0.0.0.0:4000/v1/chat/completions' \ +-H 'Content-Type: application/json' \ +-H 'Authorization: Bearer sk-1234' \ +-d '{ + "model": "glm-4.6", + "messages": [ + { + "role": "user", + "content": "Hello, how are you?" + } + ] +}' +``` + + + diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index 2039d01186c..e467711b59d 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -656,6 +656,7 @@ const sidebars = { }, "providers/xai", "providers/xinference", + "providers/zai", ], }, { diff --git a/litellm/constants.py b/litellm/constants.py index 65de5d7b555..e3de7368c8a 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -555,6 +555,7 @@ openai_compatible_providers: List = [ "perplexity", "xinference", "xai", + "zai", "together_ai", "fireworks_ai", "empower", diff --git a/litellm/litellm_core_utils/get_llm_provider_logic.py b/litellm/litellm_core_utils/get_llm_provider_logic.py index 4d29a74ddbc..b10011befcd 100644 --- a/litellm/litellm_core_utils/get_llm_provider_logic.py +++ b/litellm/litellm_core_utils/get_llm_provider_logic.py @@ -662,6 +662,13 @@ def _get_openai_compatible_provider_info( # noqa: PLR0915 ) = litellm.XAIChatConfig()._get_openai_compatible_provider_info( api_base, api_key ) + elif custom_llm_provider == "zai": + api_base = ( + api_base + or get_secret_str("ZAI_API_BASE") + or "https://api.z.ai/api/paas/v4" + ) + dynamic_api_key = api_key or get_secret_str("ZAI_API_KEY") elif custom_llm_provider == "together_ai": api_base = ( api_base diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index af63d1e2592..9fdc1704f41 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -26855,6 +26855,95 @@ "supports_vision": true, "supports_web_search": true }, + "zai/glm-4.6": { + "input_cost_per_token": 6e-07, + "output_cost_per_token": 2.2e-06, + "litellm_provider": "zai", + "max_input_tokens": 200000, + "max_output_tokens": 128000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-4.5": { + "input_cost_per_token": 6e-07, + "output_cost_per_token": 2.2e-06, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-4.5v": { + "input_cost_per_token": 6e-07, + "output_cost_per_token": 1.8e-06, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_vision": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-4.5-x": { + "input_cost_per_token": 2.2e-06, + "output_cost_per_token": 8.9e-06, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-4.5-air": { + "input_cost_per_token": 2e-07, + "output_cost_per_token": 1.1e-06, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-4.5-airx": { + "input_cost_per_token": 1.1e-06, + "output_cost_per_token": 4.5e-06, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-4-32b-0414-128k": { + "input_cost_per_token": 1e-07, + "output_cost_per_token": 1e-07, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-4.5-flash": { + "input_cost_per_token": 0, + "output_cost_per_token": 0, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, "vertex_ai/search_api": { "input_cost_per_query": 1.5e-03, "litellm_provider": "vertex_ai", diff --git a/litellm/types/utils.py b/litellm/types/utils.py index 2456c87044c..58267fdfea9 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -2553,6 +2553,7 @@ class LlmProviders(str, Enum): OPENAI_LIKE = "openai_like" # embedding only JINA_AI = "jina_ai" XAI = "xai" + ZAI = "zai" CUSTOM_OPENAI = "custom_openai" TEXT_COMPLETION_OPENAI = "text-completion-openai" COHERE = "cohere" diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 6b9b8beed80..1f8f1c7511e 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -26882,6 +26882,95 @@ "supports_vision": true, "supports_web_search": true }, + "zai/glm-4.6": { + "input_cost_per_token": 6e-07, + "output_cost_per_token": 2.2e-06, + "litellm_provider": "zai", + "max_input_tokens": 200000, + "max_output_tokens": 128000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-4.5": { + "input_cost_per_token": 6e-07, + "output_cost_per_token": 2.2e-06, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-4.5v": { + "input_cost_per_token": 6e-07, + "output_cost_per_token": 1.8e-06, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_vision": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-4.5-x": { + "input_cost_per_token": 2.2e-06, + "output_cost_per_token": 8.9e-06, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-4.5-air": { + "input_cost_per_token": 2e-07, + "output_cost_per_token": 1.1e-06, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-4.5-airx": { + "input_cost_per_token": 1.1e-06, + "output_cost_per_token": 4.5e-06, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-4-32b-0414-128k": { + "input_cost_per_token": 1e-07, + "output_cost_per_token": 1e-07, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-4.5-flash": { + "input_cost_per_token": 0, + "output_cost_per_token": 0, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32000, + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, "vertex_ai/search_api": { "input_cost_per_query": 1.5e-03, "litellm_provider": "vertex_ai", diff --git a/tests/test_litellm/llms/zai/test_zai_provider.py b/tests/test_litellm/llms/zai/test_zai_provider.py new file mode 100644 index 00000000000..a3d47d666bc --- /dev/null +++ b/tests/test_litellm/llms/zai/test_zai_provider.py @@ -0,0 +1,144 @@ +""" +Tests for Z.AI (Zhipu AI) provider - GLM models +""" +import json +import math + +import pytest +import respx + +import litellm +from litellm import completion +from litellm.cost_calculator import cost_per_token + + +@pytest.fixture +def zai_response(): + """Mock response from Z.AI API""" + return { + "id": "chatcmpl-zai-123", + "object": "chat.completion", + "created": 1677652288, + "model": "glm-4.6", + "choices": [ + { + "index": 0, + "message": {"role": "assistant", "content": "Hello! How can I help you today?"}, + "finish_reason": "stop", + } + ], + "usage": {"prompt_tokens": 10, "completion_tokens": 15, "total_tokens": 25}, + } + + +def test_get_llm_provider_zai(): + """Test that get_llm_provider correctly identifies zai provider""" + from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider + + model, provider, api_key, api_base = get_llm_provider("zai/glm-4.6") + assert model == "glm-4.6" + assert provider == "zai" + assert api_base == "https://api.z.ai/api/paas/v4" + + +def test_zai_in_provider_lists(): + """Test that zai is registered in all necessary provider lists""" + assert "zai" in litellm.openai_compatible_providers + assert "zai" in litellm.provider_list + + +def test_zai_models_in_model_cost(): + """Test that ZAI models are in the model cost map""" + import os + os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True" + litellm.model_cost = litellm.get_model_cost_map(url="") + + zai_models = [ + "zai/glm-4.6", + "zai/glm-4.5", + "zai/glm-4.5v", + "zai/glm-4.5-x", + "zai/glm-4.5-air", + "zai/glm-4.5-airx", + "zai/glm-4-32b-0414-128k", + "zai/glm-4.5-flash", + ] + + for model in zai_models: + assert model in litellm.model_cost, f"Model {model} not found in model_cost" + assert litellm.model_cost[model]["litellm_provider"] == "zai" + + +def test_zai_glm46_cost_calculation(): + """Test the cost calculation for glm-4.6""" + import os + os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True" + litellm.model_cost = litellm.get_model_cost_map(url="") + + key = "zai/glm-4.6" + info = litellm.model_cost[key] + + prompt_cost, completion_cost = cost_per_token( + model="zai/glm-4.6", + prompt_tokens=1000000, # 1M tokens + completion_tokens=1000000, + ) + + # GLM-4.6: $0.6/M input, $2.2/M output + assert math.isclose(prompt_cost, 0.6, rel_tol=1e-6) + assert math.isclose(completion_cost, 2.2, rel_tol=1e-6) + + +def test_zai_flash_model_is_free(): + """Test that glm-4.5-flash has zero cost""" + import os + os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True" + litellm.model_cost = litellm.get_model_cost_map(url="") + + key = "zai/glm-4.5-flash" + info = litellm.model_cost[key] + + assert info["input_cost_per_token"] == 0 + assert info["output_cost_per_token"] == 0 + + +@pytest.mark.asyncio +async def test_zai_completion_call(respx_mock, zai_response, monkeypatch): + """Test completion call with zai provider using mocked response""" + monkeypatch.setenv("ZAI_API_KEY", "test-api-key") + litellm.disable_aiohttp_transport = True + + respx_mock.post("https://api.z.ai/api/paas/v4/chat/completions").respond(json=zai_response) + + response = await litellm.acompletion( + model="zai/glm-4.6", + messages=[{"role": "user", "content": "Hello"}], + max_tokens=20, + ) + + assert response.choices[0].message.content == "Hello! How can I help you today?" + assert response.usage.total_tokens == 25 + + assert len(respx_mock.calls) == 1 + request = respx_mock.calls[0].request + assert request.method == "POST" + assert "api.z.ai" in str(request.url) + assert "Authorization" in request.headers + assert request.headers["Authorization"] == "Bearer test-api-key" + + +def test_zai_sync_completion(respx_mock, zai_response, monkeypatch): + """Test synchronous completion call""" + monkeypatch.setenv("ZAI_API_KEY", "test-api-key") + litellm.disable_aiohttp_transport = True + + respx_mock.post("https://api.z.ai/api/paas/v4/chat/completions").respond(json=zai_response) + + response = completion( + model="zai/glm-4.6", + messages=[{"role": "user", "content": "Hello"}], + max_tokens=20, + ) + + assert response.choices[0].message.content == "Hello! How can I help you today?" + assert response.usage.total_tokens == 25 From 01dfc3561acb1baf60209786fc24e19d77384b08 Mon Sep 17 00:00:00 2001 From: Cesar Garcia <128240629+Chesars@users.noreply.github.com> Date: Tue, 2 Dec 2025 00:58:27 -0300 Subject: [PATCH 25/47] Fix AttributeError when metadata is null in request body (#17263) (#17306) Handle the case where metadata is explicitly set to null/None in the request body. This was causing a 401 error with "'NoneType' object has no attribute 'get'" when calling /v1/batches with metadata: null. The fix uses `or {}` instead of a default dict value since the key exists but has a None value. --- .../proxy/common_utils/http_parsing_utils.py | 2 +- .../common_utils/test_http_parsing_utils.py | 23 +++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/litellm/proxy/common_utils/http_parsing_utils.py b/litellm/proxy/common_utils/http_parsing_utils.py index 59b3ec20b4a..259755f5ef9 100644 --- a/litellm/proxy/common_utils/http_parsing_utils.py +++ b/litellm/proxy/common_utils/http_parsing_utils.py @@ -309,7 +309,7 @@ def get_tags_from_request_body(request_body: dict) -> List[str]: List of tag names (strings), empty list if no valid tags found """ metadata_variable_name = get_metadata_variable_name_from_kwargs(request_body) - metadata = request_body.get(metadata_variable_name, {}) + metadata = request_body.get(metadata_variable_name) or {} tags_in_metadata: Any = metadata.get("tags", []) tags_in_request_body: Any = request_body.get("tags", []) combined_tags: List[str] = [] diff --git a/tests/test_litellm/proxy/common_utils/test_http_parsing_utils.py b/tests/test_litellm/proxy/common_utils/test_http_parsing_utils.py index 85858866dda..2361decc5af 100644 --- a/tests/test_litellm/proxy/common_utils/test_http_parsing_utils.py +++ b/tests/test_litellm/proxy/common_utils/test_http_parsing_utils.py @@ -606,8 +606,27 @@ def test_get_tags_from_request_body_with_dict_tags(): } } } - + result = get_tags_from_request_body(request_body=request_body) - + + assert result == [] + assert isinstance(result, list) + + +def test_get_tags_from_request_body_with_null_metadata(): + """ + Test that function handles null metadata gracefully without crashing. + + This is a regression test for https://github.com/BerriAI/litellm/issues/17263 + When metadata is explicitly set to null/None, the function should return + an empty list instead of raising AttributeError. + """ + request_body = { + "model": "gpt-4", + "metadata": None # OpenAI API accepts metadata: null + } + + result = get_tags_from_request_body(request_body=request_body) + assert result == [] assert isinstance(result, list) From 860270a7927b0d13319bead2fdff9a4c00e3d00f Mon Sep 17 00:00:00 2001 From: Saar wintrov Date: Tue, 2 Dec 2025 06:01:36 +0200 Subject: [PATCH 26/47] SSO: Clear sso integration for all users (#17287) --- .../_buildManifest.js | 0 .../_ssgManifest.js | 0 .../static/chunks/1518-21c80a799b5c426e.js | 1 - .../static/chunks/1518-4475f8385da5ac78.js | 1 + ...6050ee3518d4.js => 1529-59ce29afdf8ccc9b.js} | 2 +- ...971a192714f2.js => 1674-de8248fbd0c554ba.js} | 2 +- .../static/chunks/1973-26a414084f96c69b.js | 1 + .../static/chunks/1994-6637a121c9ee1602.js | 1 - .../static/chunks/1994-a4d0b99849c16b62.js | 1 + .../static/chunks/2004-294ce010a90069b4.js | 1 + .../static/chunks/2004-8b1ad3d8c195646a.js | 1 - .../static/chunks/2012-9200c205d5b0405a.js | 1 - .../static/chunks/2012-c09fa25a9cbf6028.js | 1 + .../static/chunks/2019-15183fcc4c29249f.js | 1 - .../static/chunks/2249-01a36f26b1cecba3.js | 1 + .../static/chunks/2249-3e3c0a9e241e35dc.js | 1 - ...0eb77e9f4fa7.js => 3250-6c57da6c11f342fa.js} | 2 +- .../static/chunks/3325-4a3c766c7d12465e.js | 1 - .../static/chunks/3341-852c4599adcc0f2b.js | 1 + ...9f5df18d8716.js => 3705-124a560b74decaa8.js} | 2 +- .../static/chunks/3801-9878b21c4f9ae250.js | 1 - .../static/chunks/3801-ff2404f6d0c38247.js | 1 + .../static/chunks/4182-1ec11708566c0483.js | 1 - .../static/chunks/4267-eb59bdfbffb79a80.js | 1 - .../static/chunks/4292-28669d6dfecbbf62.js | 1 + .../static/chunks/4292-913ecd28879b76a8.js | 1 - .../static/chunks/4612-06e9d10957e990c0.js | 1 + .../_next/static/chunks/475-3985fee235e827f8.js | 1 + .../static/chunks/4865-c1c0885a93c327fa.js | 1 - .../static/chunks/5074-51f1824c21869900.js | 1 - .../static/chunks/5096-d9222b69b30b3d56.js | 1 + ...9ffa75db75f8.js => 5170-eddf033da66a3d25.js} | 2 +- .../_next/static/chunks/544-3d98fdc8d64554e8.js | 1 - .../static/chunks/5572-9290ae3dc2551207.js | 1 - .../static/chunks/5572-d4f8dc9b2bf09618.js | 1 + .../static/chunks/5830-30dbbe6913297258.js | 1 + ...68ba6ad0ce0c.js => 5869-99bf8c2997f4811f.js} | 2 +- .../static/chunks/5945-8b3b7713d7f416a2.js | 1 + .../_next/static/chunks/605-102c0e6d8bb7517c.js | 1 + .../static/chunks/6062-89f63f71675c6a08.js | 1 - .../static/chunks/6264-a48a17494c2e1d26.js | 1 - .../_next/static/chunks/630-1e0342aa26bb0fe8.js | 1 - .../_next/static/chunks/630-f305780b75c36612.js | 1 + ...e6266dea9539.js => 6600-1c55511ad9da9e4d.js} | 2 +- .../static/chunks/6609-3e081758ffbe3786.js | 1 - .../static/chunks/6609-d93906f43161f066.js | 1 + .../_next/static/chunks/667-213a9fbd82e0ada7.js | 1 + .../static/chunks/6843-98abf1271c25c6e0.js | 1 + .../static/chunks/6843-b8ebdf2bb4fe5c67.js | 1 - .../static/chunks/7155-1a3e4c5a6aefae2b.js | 1 - .../static/chunks/7155-459bc53437553b96.js | 1 + .../static/chunks/7164-8de9ea967cd5d031.js | 1 + .../static/chunks/7164-b089dfb991cc1d8c.js | 1 - .../static/chunks/7187-d4c57193fb558148.js | 1 + ...1f347ea9707a.js => 7526-9d5ec51e0920ffc6.js} | 2 +- .../static/chunks/7641-f70830b7a61a3f9c.js | 1 - .../static/chunks/7641-fa9cc1f68c670e1c.js | 1 + ...579c5c97ecaba.js => 773-b02e89f4d1193982.js} | 2 +- ...16ddcb35e063.js => 7975-d5ed9d0e73f8f3a9.js} | 2 +- .../static/chunks/8008-851877152eb2be38.js | 1 - .../static/chunks/8541-04c822145b2301f8.js | 1 + .../static/chunks/8661-1cf4178f6bffc981.js | 1 - .../static/chunks/9028-2bfc9f09930a0d61.js | 1 - .../static/chunks/9111-3cb8240098962e8a.js | 1 - .../static/chunks/9111-9b9192c9fb4809ff.js | 1 + ...dfb8fa3d2ed7.js => 9611-8bd2ffcee22edc34.js} | 2 +- .../static/chunks/9798-a47f1a4423863a8a.js | 1 + .../static/chunks/9877-f58702e3cb433729.js | 1 - .../static/chunks/9877-ff2a01b39a318119.js | 1 + .../api-reference/page-6ead8448e1510439.js | 1 - .../api-reference/page-efca3b67652c1db6.js | 1 + .../api-playground/page-8047d2cef33b9999.js | 1 - .../api-playground/page-e66957ea53741305.js | 1 + ...cab0cb418464.js => page-349dab403faa8586.js} | 2 +- ...6b7e7489b565.js => page-29593a3a38ff72cd.js} | 2 +- ...6697f4d6f550.js => page-392368af0265ebf3.js} | 2 +- .../prompts/page-843a18f5283af912.js | 1 - .../prompts/page-a188489df21ffc96.js | 1 + ...5395c754c862.js => page-04b44e5847f0e275.js} | 2 +- ...350eb16ca3ba.js => page-df254f7363ecac47.js} | 2 +- .../app/(dashboard)/layout-a0258e2243643336.js | 1 + .../app/(dashboard)/layout-a928c135835301f0.js | 1 - .../(dashboard)/logs/page-24f7ccafa5658895.js | 1 + .../(dashboard)/logs/page-974be1d69803befc.js | 1 - ...b2d51a5f5567.js => page-cb5b5c184df1920f.js} | 2 +- .../page-7526ca663daec9bf.js | 1 + .../page-a11b969ee66b82c0.js | 1 - ...977ecb7e4aea.js => page-c5c54ec599dda90a.js} | 2 +- ...e021acdc06f3.js => page-f66c8c75efc80fa3.js} | 2 +- .../admin-settings/page-41bcefda7b19fcbe.js | 1 - .../admin-settings/page-b14017f2434341b6.js | 1 + ...c91c28de94ff.js => page-73e2aa132fcafea5.js} | 2 +- .../router-settings/page-7e77ec8e3ff58278.js | 1 - .../router-settings/page-ce416427bf19a1dc.js | 1 + ...0a8b43105b4e.js => page-e723d4c81fc7d9a9.js} | 2 +- ...d0b0d541c84f.js => page-464d4ef166df7211.js} | 2 +- ...2c9c481d0375.js => page-4dd219948b528c92.js} | 2 +- ...df83dfce71fa.js => page-4a1119ecd30d2b39.js} | 2 +- ...498724555fa1.js => page-c4aed80b18ca0651.js} | 2 +- ...feee0752e151.js => page-2098a2b6e214223c.js} | 2 +- .../(dashboard)/users/page-607b92cfac56e9f9.js | 1 - .../(dashboard)/users/page-80eaf816a6ca5c75.js | 1 + .../virtual-keys/page-52c22b525906afcf.js | 1 + .../virtual-keys/page-681e2e7643e3068c.js | 1 - .../chunks/app/layout-4e0c2c971ccc1e6d.js | 1 - .../chunks/app/layout-5681449b28aa197a.js | 1 + ...c0d632ab220d.js => page-e50863ece139886b.js} | 2 +- ...17915c7f9cff.js => page-ca976de28014d49a.js} | 2 +- ...536062f9ecd9.js => page-623abbf7f2315887.js} | 2 +- .../app/onboarding/page-6f2572027a406495.js | 1 + .../app/onboarding/page-7cc24917468a90ab.js | 1 - .../static/chunks/app/page-28eb040917ca1710.js | 1 + .../static/chunks/app/page-dda848d817541095.js | 1 - ...04ee9adf.js => main-app-ce1f29ef0860719b.js} | 2 +- ...ed3b4a921.js => webpack-134f5d194761e240.js} | 2 +- .../out/_next/static/css/0fc668a8750043fe.css | 1 + .../proxy/_experimental/out/api-reference.html | 1 - .../proxy/_experimental/out/api-reference.txt | 17 ++++++++--------- .../_experimental/out/api-reference/index.html | 1 + .../out/experimental/api-playground.html | 2 +- .../out/experimental/api-playground.txt | 17 ++++++++--------- .../_experimental/out/experimental/budgets.html | 2 +- .../_experimental/out/experimental/budgets.txt | 17 ++++++++--------- .../_experimental/out/experimental/caching.html | 2 +- .../_experimental/out/experimental/caching.txt | 17 ++++++++--------- .../out/experimental/old-usage.html | 2 +- .../out/experimental/old-usage.txt | 17 ++++++++--------- .../_experimental/out/experimental/prompts.html | 2 +- .../_experimental/out/experimental/prompts.txt | 17 ++++++++--------- .../out/experimental/tag-management.html | 2 +- .../out/experimental/tag-management.txt | 17 ++++++++--------- litellm/proxy/_experimental/out/guardrails.html | 1 - litellm/proxy/_experimental/out/guardrails.txt | 17 ++++++++--------- litellm/proxy/_experimental/out/index.html | 2 +- litellm/proxy/_experimental/out/index.txt | 11 +++++------ litellm/proxy/_experimental/out/logs.html | 1 - litellm/proxy/_experimental/out/logs.txt | 17 ++++++++--------- litellm/proxy/_experimental/out/logs/index.html | 1 + .../_experimental/out/mcp/oauth/callback.html | 2 +- .../_experimental/out/mcp/oauth/callback.txt | 7 +++---- litellm/proxy/_experimental/out/model-hub.html | 1 - litellm/proxy/_experimental/out/model-hub.txt | 17 ++++++++--------- .../_experimental/out/model-hub/index.html | 1 + litellm/proxy/_experimental/out/model_hub.txt | 7 +++---- .../_experimental/out/model_hub_table.html | 1 - .../proxy/_experimental/out/model_hub_table.txt | 7 +++---- .../out/model_hub_table/index.html | 1 + .../_experimental/out/models-and-endpoints.html | 1 - .../_experimental/out/models-and-endpoints.txt | 17 ++++++++--------- .../out/models-and-endpoints/index.html | 1 + litellm/proxy/_experimental/out/onboarding.html | 1 - litellm/proxy/_experimental/out/onboarding.txt | 7 +++---- .../proxy/_experimental/out/organizations.html | 1 - .../proxy/_experimental/out/organizations.txt | 17 ++++++++--------- .../_experimental/out/organizations/index.html | 1 + litellm/proxy/_experimental/out/playground.html | 1 - litellm/proxy/_experimental/out/playground.txt | 17 ++++++++--------- .../_experimental/out/playground/index.html | 1 + .../out/settings/admin-settings.html | 2 +- .../out/settings/admin-settings.txt | 17 ++++++++--------- .../out/settings/logging-and-alerts.html | 2 +- .../out/settings/logging-and-alerts.txt | 17 ++++++++--------- .../out/settings/router-settings.html | 2 +- .../out/settings/router-settings.txt | 17 ++++++++--------- .../_experimental/out/settings/ui-theme.html | 2 +- .../_experimental/out/settings/ui-theme.txt | 17 ++++++++--------- litellm/proxy/_experimental/out/teams.html | 1 - litellm/proxy/_experimental/out/teams.txt | 17 ++++++++--------- .../proxy/_experimental/out/teams/index.html | 1 + litellm/proxy/_experimental/out/test-key.html | 1 - litellm/proxy/_experimental/out/test-key.txt | 17 ++++++++--------- .../proxy/_experimental/out/test-key/index.html | 1 + .../_experimental/out/tools/mcp-servers.html | 2 +- .../_experimental/out/tools/mcp-servers.txt | 17 ++++++++--------- .../_experimental/out/tools/vector-stores.html | 2 +- .../_experimental/out/tools/vector-stores.txt | 17 ++++++++--------- litellm/proxy/_experimental/out/usage.html | 1 - litellm/proxy/_experimental/out/usage.txt | 17 ++++++++--------- .../proxy/_experimental/out/usage/index.html | 1 + litellm/proxy/_experimental/out/users.html | 1 - litellm/proxy/_experimental/out/users.txt | 17 ++++++++--------- .../proxy/_experimental/out/users/index.html | 1 + .../proxy/_experimental/out/virtual-keys.html | 1 - .../proxy/_experimental/out/virtual-keys.txt | 17 ++++++++--------- .../_experimental/out/virtual-keys/index.html | 1 + ui/litellm-dashboard/src/components/admins.tsx | 2 +- 186 files changed, 309 insertions(+), 339 deletions(-) rename litellm/proxy/_experimental/out/_next/static/{V73dwfVXi9kkAaHXHHR5u => 6DVsIIQxhiSKdAYpN-pIf}/_buildManifest.js (100%) rename litellm/proxy/_experimental/out/_next/static/{V73dwfVXi9kkAaHXHHR5u => 6DVsIIQxhiSKdAYpN-pIf}/_ssgManifest.js (100%) delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/1518-21c80a799b5c426e.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/1518-4475f8385da5ac78.js rename litellm/proxy/_experimental/out/_next/static/chunks/{1529-aa686050ee3518d4.js => 1529-59ce29afdf8ccc9b.js} (99%) rename litellm/proxy/_experimental/out/_next/static/chunks/{1674-475a971a192714f2.js => 1674-de8248fbd0c554ba.js} (99%) create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/1973-26a414084f96c69b.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/1994-6637a121c9ee1602.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/1994-a4d0b99849c16b62.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/2004-294ce010a90069b4.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/2004-8b1ad3d8c195646a.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/2012-9200c205d5b0405a.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/2012-c09fa25a9cbf6028.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/2019-15183fcc4c29249f.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/2249-01a36f26b1cecba3.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/2249-3e3c0a9e241e35dc.js rename litellm/proxy/_experimental/out/_next/static/chunks/{3250-d3d70eb77e9f4fa7.js => 3250-6c57da6c11f342fa.js} (99%) delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/3325-4a3c766c7d12465e.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/3341-852c4599adcc0f2b.js rename litellm/proxy/_experimental/out/_next/static/chunks/{3705-05649f5df18d8716.js => 3705-124a560b74decaa8.js} (99%) delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/3801-9878b21c4f9ae250.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/3801-ff2404f6d0c38247.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/4182-1ec11708566c0483.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/4267-eb59bdfbffb79a80.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/4292-28669d6dfecbbf62.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/4292-913ecd28879b76a8.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/4612-06e9d10957e990c0.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/475-3985fee235e827f8.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/4865-c1c0885a93c327fa.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/5074-51f1824c21869900.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/5096-d9222b69b30b3d56.js rename litellm/proxy/_experimental/out/_next/static/chunks/{5170-56859ffa75db75f8.js => 5170-eddf033da66a3d25.js} (99%) delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/544-3d98fdc8d64554e8.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/5572-9290ae3dc2551207.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/5572-d4f8dc9b2bf09618.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/5830-30dbbe6913297258.js rename litellm/proxy/_experimental/out/_next/static/chunks/{5869-426268ba6ad0ce0c.js => 5869-99bf8c2997f4811f.js} (99%) create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/5945-8b3b7713d7f416a2.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/605-102c0e6d8bb7517c.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/6062-89f63f71675c6a08.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/6264-a48a17494c2e1d26.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/630-1e0342aa26bb0fe8.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/630-f305780b75c36612.js rename litellm/proxy/_experimental/out/_next/static/chunks/{6600-3c16e6266dea9539.js => 6600-1c55511ad9da9e4d.js} (99%) delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/6609-3e081758ffbe3786.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/6609-d93906f43161f066.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/667-213a9fbd82e0ada7.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/6843-98abf1271c25c6e0.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/6843-b8ebdf2bb4fe5c67.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/7155-1a3e4c5a6aefae2b.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/7155-459bc53437553b96.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/7164-8de9ea967cd5d031.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/7164-b089dfb991cc1d8c.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/7187-d4c57193fb558148.js rename litellm/proxy/_experimental/out/_next/static/chunks/{7526-e29a1f347ea9707a.js => 7526-9d5ec51e0920ffc6.js} (51%) delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/7641-f70830b7a61a3f9c.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/7641-fa9cc1f68c670e1c.js rename litellm/proxy/_experimental/out/_next/static/chunks/{773-870579c5c97ecaba.js => 773-b02e89f4d1193982.js} (74%) rename litellm/proxy/_experimental/out/_next/static/chunks/{7975-afe816ddcb35e063.js => 7975-d5ed9d0e73f8f3a9.js} (65%) delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/8008-851877152eb2be38.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/8541-04c822145b2301f8.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/8661-1cf4178f6bffc981.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/9028-2bfc9f09930a0d61.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/9111-3cb8240098962e8a.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/9111-9b9192c9fb4809ff.js rename litellm/proxy/_experimental/out/_next/static/chunks/{9611-e0c4dfb8fa3d2ed7.js => 9611-8bd2ffcee22edc34.js} (99%) create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/9798-a47f1a4423863a8a.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/9877-f58702e3cb433729.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/9877-ff2a01b39a318119.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/api-reference/page-6ead8448e1510439.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/api-reference/page-efca3b67652c1db6.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/experimental/api-playground/page-8047d2cef33b9999.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/experimental/api-playground/page-e66957ea53741305.js rename litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/experimental/budgets/{page-3234cab0cb418464.js => page-349dab403faa8586.js} (96%) rename litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/experimental/caching/{page-0a286b7e7489b565.js => page-29593a3a38ff72cd.js} (92%) rename litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/experimental/old-usage/{page-bdfb6697f4d6f550.js => page-392368af0265ebf3.js} (98%) delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/experimental/prompts/page-843a18f5283af912.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/experimental/prompts/page-a188489df21ffc96.js rename litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/experimental/tag-management/{page-e5395395c754c862.js => page-04b44e5847f0e275.js} (96%) rename litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/guardrails/{page-fbd5350eb16ca3ba.js => page-df254f7363ecac47.js} (93%) create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/layout-a0258e2243643336.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/layout-a928c135835301f0.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/logs/page-24f7ccafa5658895.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/logs/page-974be1d69803befc.js rename litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/model-hub/{page-a4e1b2d51a5f5567.js => page-cb5b5c184df1920f.js} (95%) create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/models-and-endpoints/page-7526ca663daec9bf.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/models-and-endpoints/page-a11b969ee66b82c0.js rename litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/organizations/{page-c9a9977ecb7e4aea.js => page-c5c54ec599dda90a.js} (97%) rename litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/playground/{page-6729e021acdc06f3.js => page-f66c8c75efc80fa3.js} (97%) delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/settings/admin-settings/page-41bcefda7b19fcbe.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/settings/admin-settings/page-b14017f2434341b6.js rename litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/settings/logging-and-alerts/{page-2470c91c28de94ff.js => page-73e2aa132fcafea5.js} (97%) delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/settings/router-settings/page-7e77ec8e3ff58278.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/settings/router-settings/page-ce416427bf19a1dc.js rename litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/settings/ui-theme/{page-ee5d0a8b43105b4e.js => page-e723d4c81fc7d9a9.js} (98%) rename litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/teams/{page-866cd0b0d541c84f.js => page-464d4ef166df7211.js} (99%) rename litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/test-key/{page-69022c9c481d0375.js => page-4dd219948b528c92.js} (98%) rename litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/tools/mcp-servers/{page-9474df83dfce71fa.js => page-4a1119ecd30d2b39.js} (93%) rename litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/tools/vector-stores/{page-6ddf498724555fa1.js => page-c4aed80b18ca0651.js} (96%) rename litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/usage/{page-6882feee0752e151.js => page-2098a2b6e214223c.js} (95%) delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/users/page-607b92cfac56e9f9.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/users/page-80eaf816a6ca5c75.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/virtual-keys/page-52c22b525906afcf.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/(dashboard)/virtual-keys/page-681e2e7643e3068c.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/layout-4e0c2c971ccc1e6d.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/layout-5681449b28aa197a.js rename litellm/proxy/_experimental/out/_next/static/chunks/app/mcp/oauth/callback/{page-4cdcc0d632ab220d.js => page-e50863ece139886b.js} (89%) rename litellm/proxy/_experimental/out/_next/static/chunks/app/model_hub/{page-16d517915c7f9cff.js => page-ca976de28014d49a.js} (84%) rename litellm/proxy/_experimental/out/_next/static/chunks/app/model_hub_table/{page-e60a536062f9ecd9.js => page-623abbf7f2315887.js} (95%) create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/onboarding/page-6f2572027a406495.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/onboarding/page-7cc24917468a90ab.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/page-28eb040917ca1710.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/page-dda848d817541095.js rename litellm/proxy/_experimental/out/_next/static/chunks/{main-app-77a6ca3c04ee9adf.js => main-app-ce1f29ef0860719b.js} (81%) rename litellm/proxy/_experimental/out/_next/static/chunks/{webpack-db32e14ed3b4a921.js => webpack-134f5d194761e240.js} (77%) create mode 100644 litellm/proxy/_experimental/out/_next/static/css/0fc668a8750043fe.css delete mode 100644 litellm/proxy/_experimental/out/api-reference.html create mode 100644 litellm/proxy/_experimental/out/api-reference/index.html delete mode 100644 litellm/proxy/_experimental/out/guardrails.html delete mode 100644 litellm/proxy/_experimental/out/logs.html create mode 100644 litellm/proxy/_experimental/out/logs/index.html delete mode 100644 litellm/proxy/_experimental/out/model-hub.html create mode 100644 litellm/proxy/_experimental/out/model-hub/index.html delete mode 100644 litellm/proxy/_experimental/out/model_hub_table.html create mode 100644 litellm/proxy/_experimental/out/model_hub_table/index.html delete mode 100644 litellm/proxy/_experimental/out/models-and-endpoints.html create mode 100644 litellm/proxy/_experimental/out/models-and-endpoints/index.html delete mode 100644 litellm/proxy/_experimental/out/onboarding.html delete mode 100644 litellm/proxy/_experimental/out/organizations.html create mode 100644 litellm/proxy/_experimental/out/organizations/index.html delete mode 100644 litellm/proxy/_experimental/out/playground.html create mode 100644 litellm/proxy/_experimental/out/playground/index.html delete mode 100644 litellm/proxy/_experimental/out/teams.html create mode 100644 litellm/proxy/_experimental/out/teams/index.html delete mode 100644 litellm/proxy/_experimental/out/test-key.html create mode 100644 litellm/proxy/_experimental/out/test-key/index.html delete mode 100644 litellm/proxy/_experimental/out/usage.html create mode 100644 litellm/proxy/_experimental/out/usage/index.html delete mode 100644 litellm/proxy/_experimental/out/users.html create mode 100644 litellm/proxy/_experimental/out/users/index.html delete mode 100644 litellm/proxy/_experimental/out/virtual-keys.html create mode 100644 litellm/proxy/_experimental/out/virtual-keys/index.html diff --git a/litellm/proxy/_experimental/out/_next/static/V73dwfVXi9kkAaHXHHR5u/_buildManifest.js b/litellm/proxy/_experimental/out/_next/static/6DVsIIQxhiSKdAYpN-pIf/_buildManifest.js similarity index 100% rename from litellm/proxy/_experimental/out/_next/static/V73dwfVXi9kkAaHXHHR5u/_buildManifest.js rename to litellm/proxy/_experimental/out/_next/static/6DVsIIQxhiSKdAYpN-pIf/_buildManifest.js diff --git a/litellm/proxy/_experimental/out/_next/static/V73dwfVXi9kkAaHXHHR5u/_ssgManifest.js b/litellm/proxy/_experimental/out/_next/static/6DVsIIQxhiSKdAYpN-pIf/_ssgManifest.js similarity index 100% rename from litellm/proxy/_experimental/out/_next/static/V73dwfVXi9kkAaHXHHR5u/_ssgManifest.js rename to litellm/proxy/_experimental/out/_next/static/6DVsIIQxhiSKdAYpN-pIf/_ssgManifest.js diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/1518-21c80a799b5c426e.js b/litellm/proxy/_experimental/out/_next/static/chunks/1518-21c80a799b5c426e.js deleted file mode 100644 index 52544b97059..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/1518-21c80a799b5c426e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1518],{81518:function(e,s,a){a.r(s),a.d(s,{default:function(){return Y}});var t=a(57437),r=a(2265),n=a(85572),l=a(93837),i=a(37592),o=a(4260),d=a(99981),c=a(5545),m=a(26430),u=a(96473),x=a(9114),h=a(10703),p=a(95459),g=a(32489),f=a(98728),v=a(62831),j=a(17906),y=a(94263),b=a(79862),N=a(82222),k=a(51817),w=a(94331),A=a(38398),S=a(33152);function C(e){let{messages:s,isLoading:a}=e;if(0===s.length)return(0,t.jsx)("div",{className:"h-full"});let r=[],n=0;for(;n(0,t.jsx)("div",{className:"whitespace-pre-wrap break-words",style:{wordWrap:"break-word",overflowWrap:"break-word",wordBreak:"break-word",hyphens:"auto"},children:(0,t.jsx)(v.UG,{components:{code(e){let{node:s,inline:a,className:r,children:n,...l}=e,i=/language-(\w+)/.exec(r||"");return!a&&i?(0,t.jsx)(j.Z,{style:y.Z,language:i[1],PreTag:"div",className:"rounded-md my-2",wrapLines:!0,wrapLongLines:!0,...l,children:String(n).replace(/\n$/,"")}):(0,t.jsx)("code",{className:"".concat(r," px-1.5 py-0.5 rounded bg-gray-100 text-sm font-mono"),...l,children:n})},pre:e=>{let{node:s,...a}=e;return(0,t.jsx)("pre",{style:{overflowX:"auto",maxWidth:"100%"},...a})}},children:"string"==typeof e.content?e.content:""})});return(0,t.jsxs)("div",{className:"flex flex-col gap-6 min-w-0 w-full p-4",children:[r.map((e,s)=>{let n=e.assistant,i=(null==n?void 0:n.model)||"Assistant";return(0,t.jsxs)("div",{className:"space-y-4",children:[e.user&&(0,t.jsxs)("div",{className:"space-y-2 min-w-0",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-blue-100 text-blue-600",children:(0,t.jsx)(b.Z,{size:16})}),(0,t.jsx)("div",{className:"text-sm font-semibold text-gray-700",children:"You"})]}),l(e.user)]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),n?(0,t.jsxs)("div",{className:"space-y-3 min-w-0",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-gray-100 text-gray-600",children:(0,t.jsx)(N.Z,{size:16})}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"text-sm font-semibold text-gray-700",children:i}),n.toolName&&(0,t.jsx)("span",{className:"rounded bg-gray-100 px-2 py-0.5 text-xs text-gray-600",children:n.toolName})]})]}),n.reasoningContent&&(0,t.jsx)(w.Z,{reasoningContent:n.reasoningContent}),n.searchResults&&(0,t.jsx)(S.J,{searchResults:n.searchResults}),l(n),(n.timeToFirstToken||n.totalLatency||n.usage)&&(0,t.jsx)(A.Z,{timeToFirstToken:n.timeToFirstToken,totalLatency:n.totalLatency,usage:n.usage,toolName:n.toolName})]}):a&&s===r.length-1?(0,t.jsxs)("div",{className:"flex items-center gap-2 text-sm text-gray-500",children:[(0,t.jsx)(k.Z,{size:18,className:"animate-spin"}),(0,t.jsx)("span",{children:"Generating response..."})]}):(0,t.jsx)("div",{className:"text-sm text-gray-500",children:"Waiting for a response..."})]},s)}),a&&0===r.length&&(0,t.jsxs)("div",{className:"flex items-center gap-2 text-gray-500",children:[(0,t.jsx)(k.Z,{size:18,className:"animate-spin"}),(0,t.jsx)("span",{children:"Generating response..."})]})]})}var T=a(31283);function P(e){let{value:s,onChange:a,models:n,loading:l,disabled:o}=e,[d,c]=(0,r.useState)(!1),[m,u]=(0,r.useState)(""),x=(0,r.useMemo)(()=>Array.from(new Set(n)).sort(),[n]),h=(0,r.useMemo)(()=>s&&!x.includes(s)?[s,...x]:x,[x,s]),p=d?"__custom__":s||void 0,g=()=>{let e=m.trim();if(!e){c(!1),u("");return}a(e),c(!1),u("")};return(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,t.jsxs)(i.default,{value:p,onChange:e=>{if("__custom__"===e){c(!0),s&&!x.includes(s)?u(s):u("");return}c(!1),u(""),a(e)},disabled:o,loading:l,placeholder:l?"Loading models...":"Select a model",className:"w-full rounded-md",showSearch:!0,optionFilterProp:"children",children:[h.map(e=>(0,t.jsx)(i.default.Option,{value:e,children:e},e)),(0,t.jsx)(i.default.Option,{value:"__custom__",children:"+ Add custom model"})]}),d&&(0,t.jsx)(T.o,{className:"mt-2",placeholder:"Custom Model Name (Enter to add)",value:m,onValueChange:u,onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),g())},onBlur:g,autoFocus:!0})]})}var Z=a(99020),_=a(97415),L=a(67479),E=a(4156),M=a(23496),I=a(85847),O=a(79326);function R(e){let{comparison:s,onUpdate:a,onRemove:n,canRemove:l,modelOptions:i,isLoadingModels:o,apiKey:d}=e,[c,m]=(0,r.useState)(!1),u=e=>{e?a({applyAcrossModels:!0,temperature:s.temperature,maxTokens:s.maxTokens,tags:[...s.tags],vectorStores:[...s.vectorStores],guardrails:[...s.guardrails],useAdvancedParams:s.useAdvancedParams},{applyToAll:!0,keysToApply:["temperature","maxTokens","tags","vectorStores","guardrails","useAdvancedParams"]}):a({applyAcrossModels:!1})},x=e=>{a({useAdvancedParams:e},s.applyAcrossModels?{applyToAll:!0,keysToApply:["useAdvancedParams"]}:void 0)},h=(e,t)=>{a({[e]:t},s.applyAcrossModels?{applyToAll:!0,keysToApply:[e]}:void 0)},p=s.useAdvancedParams?1:.4,v=s.useAdvancedParams?"text-gray-700":"text-gray-400",j=()=>{m(e=>!e)},y=(0,t.jsxs)("div",{className:"w-[300px] max-h-[65vh] overflow-y-auto relative",children:[(0,t.jsx)("button",{onClick:()=>{m(!1)},className:"absolute top-0 right-0 p-1 hover:bg-gray-100 rounded transition-colors text-gray-500 hover:text-gray-700 z-10",children:(0,t.jsx)(g.Z,{size:14})}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)("div",{className:"flex items-center gap-2",children:(0,t.jsx)(E.Z,{checked:s.applyAcrossModels,onChange:e=>u(e.target.checked),children:(0,t.jsx)("span",{className:"text-xs font-medium",children:"Sync Settings Across Models"})})}),(0,t.jsx)(M.Z,{className:"border-gray-200"}),(0,t.jsxs)("div",{children:[(0,t.jsx)("h4",{className:"text-xs font-semibold text-gray-700 mb-1.5 uppercase tracking-wide",children:"General Settings"}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-600 block mb-0.5",children:"Tags"}),(0,t.jsx)(Z.Z,{value:s.tags,onChange:e=>h("tags",e),accessToken:d})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-600 block mb-0.5",children:"Vector Stores"}),(0,t.jsx)(_.Z,{value:s.vectorStores,onChange:e=>h("vectorStores",e),accessToken:d})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-600 block mb-0.5",children:"Guardrails"}),(0,t.jsx)(L.Z,{value:s.guardrails,onChange:e=>h("guardrails",e),accessToken:d})]})]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("h4",{className:"text-xs font-semibold text-gray-700 mb-1.5 uppercase tracking-wide",children:"Advanced Settings"}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)("div",{className:"flex items-center gap-2 pb-1",children:(0,t.jsx)(E.Z,{checked:s.useAdvancedParams,onChange:e=>x(e.target.checked),children:(0,t.jsx)("span",{className:"text-sm font-medium",children:"Use Advanced Parameters"})})}),(0,t.jsxs)("div",{className:"space-y-2 transition-opacity duration-200",style:{opacity:p},children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium ".concat(v),children:"Temperature"}),(0,t.jsx)("span",{className:"text-xs ".concat(v),children:s.temperature.toFixed(2)})]}),(0,t.jsx)(I.Z,{min:0,max:2,step:.01,value:s.temperature,onChange:e=>{h("temperature",Math.min(2,Math.max(0,Number((Array.isArray(e)?e[0]:e).toFixed(2)))))},disabled:!s.useAdvancedParams})]}),(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium ".concat(v),children:"Max Tokens"}),(0,t.jsx)("span",{className:"text-xs ".concat(v),children:s.maxTokens})]}),(0,t.jsx)(I.Z,{min:1,max:32768,step:1,value:s.maxTokens,onChange:e=>{h("maxTokens",Math.min(32768,Math.max(1,Math.round(Array.isArray(e)?e[0]:e))))},disabled:!s.useAdvancedParams})]})]})]})]})]})]});return(0,t.jsxs)("div",{className:"bg-white first:border-l-0 border-l border-gray-200 flex flex-col min-h-0",children:[(0,t.jsxs)("div",{className:"border-b flex items-center justify-between gap-3 px-4 py-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3 flex-1",children:[(0,t.jsx)(P,{value:s.model,models:i,loading:o,onChange:e=>a({model:e})}),(0,t.jsx)("div",{className:"flex items-center gap-2",children:(0,t.jsx)(O.Z,{content:y,trigger:[],open:c,onOpenChange:()=>{},placement:"bottomRight",destroyTooltipOnHide:!1,children:(0,t.jsx)("button",{onClick:e=>{e.stopPropagation(),j()},className:"p-2 rounded-lg transition-colors ".concat(c?"bg-gray-200 text-gray-700":"hover:bg-gray-100 text-gray-600"),children:(0,t.jsx)(f.Z,{size:18})})})})]}),l&&(0,t.jsx)("button",{onClick:e=>{e.stopPropagation(),n()},className:"p-2 hover:bg-red-50 text-red-600 rounded-lg transition-colors",children:(0,t.jsx)(g.Z,{size:18})})]}),(0,t.jsx)("div",{className:"relative flex-1 flex flex-col min-h-0",children:(0,t.jsx)("div",{className:"flex-1 max-h-[calc(100vh-385px)] overflow-auto rounded-b-2xl",children:(0,t.jsx)(C,{messages:s.messages,isLoading:s.isLoading})})})]})}var z=a(79276);let{TextArea:U}=o.default;function K(e){let{value:s,onChange:a,onSend:r,disabled:n}=e;return(0,t.jsx)("div",{className:"flex items-center gap-2",children:(0,t.jsxs)("div",{className:"flex items-center flex-1 bg-white border border-gray-300 rounded-xl px-3 py-1 min-h-[44px]",children:[(0,t.jsx)(U,{value:s,onChange:e=>a(e.target.value),onKeyDown:e=>{"Enter"===e.key&&!e.shiftKey&&(e.preventDefault(),!n&&s.trim()&&r())},placeholder:"Type your message... (Shift+Enter for new line)",disabled:n,className:"flex-1",autoSize:{minRows:1,maxRows:4},style:{resize:"none",border:"none",boxShadow:"none",background:"transparent",padding:"4px 0",fontSize:"14px",lineHeight:"20px"}}),(0,t.jsx)(c.ZP,{onClick:r,disabled:n||!s.trim(),icon:(0,t.jsx)(z.Z,{}),shape:"circle"})]})})}let B=["Can you summarize the key points?","What assumptions did you make?","What are the next steps?"],D=["Write me a poem","Explain quantum computing","Draft a polite email requesting a meeting"],F="/v1/chat/completions";function W(e){let{accessToken:s,disabledPersonalKeyCreation:a}=e,[n,g]=(0,r.useState)([{id:"1",model:"",messages:[],isLoading:!1,tags:[],mcpTools:[],vectorStores:[],guardrails:[],temperature:1,maxTokens:2048,applyAcrossModels:!1,useAdvancedParams:!1},{id:"2",model:"",messages:[],isLoading:!1,tags:[],mcpTools:[],vectorStores:[],guardrails:[],temperature:1,maxTokens:2048,applyAcrossModels:!1,useAdvancedParams:!1}]),[f,v]=(0,r.useState)([]),[j,y]=(0,r.useState)(!1),[b,N]=(0,r.useState)(""),[k,w]=(0,r.useState)(a?"custom":"session"),[A,S]=(0,r.useState)(""),[C,T]=(0,r.useState)("");(0,r.useEffect)(()=>{let e=setTimeout(()=>{T(A)},300);return()=>clearTimeout(e)},[A]);let P=(0,r.useMemo)(()=>"session"===k?s||"":C.trim(),[k,s,C]),Z=(0,r.useMemo)(()=>n.length>0&&n.every(e=>!e.isLoading&&e.messages.some(e=>"assistant"===e.role)),[n]);(0,r.useEffect)(()=>{let e=!0;return(async()=>{if(!P){v([]);return}y(!0);try{let s=await (0,h.p)(P);if(!e)return;let a=Array.from(new Set(s.map(e=>e.model_group)));v(a)}catch(s){console.error("CompareUI: failed to fetch models",s),e&&v([])}finally{e&&y(!1)}})(),()=>{e=!1}},[P]),(0,r.useEffect)(()=>{0!==f.length&&g(e=>e.map((e,s)=>{var a,t,r,n,l;return{...e,temperature:null!==(a=e.temperature)&&void 0!==a?a:1,maxTokens:null!==(t=e.maxTokens)&&void 0!==t?t:2048,applyAcrossModels:null!==(r=e.applyAcrossModels)&&void 0!==r&&r,useAdvancedParams:null!==(n=e.useAdvancedParams)&&void 0!==n&&n,...e.model?{}:{model:null!==(l=f[s%f.length])&&void 0!==l?l:""}}}))},[f]);let _=e=>{n.length>1&&g(s=>s.filter(s=>s.id!==e))},L=(e,s,a)=>{g(t=>{var r;if((null==a?void 0:a.applyToAll)&&(null===(r=a.keysToApply)||void 0===r?void 0:r.length)){let r={};a.keysToApply.forEach(e=>{let a=s[e];void 0!==a&&(r[e]=Array.isArray(a)?[...a]:a)});let n=Object.keys(r).length>0;return t.map(a=>a.id===e?{...a,...s}:n?{...a,...r}:a)}return t.map(a=>a.id===e?{...a,...s}:a)})},E=(e,s,a)=>{s&&g(t=>t.map(t=>{if(t.id!==e)return t;let r=[...t.messages],n=r[r.length-1];if(n&&"assistant"===n.role){var l;let e="string"==typeof n.content?n.content:"";r[r.length-1]={...n,content:e+s,model:null!==(l=n.model)&&void 0!==l?l:a}}else r.push({role:"assistant",content:s,model:a});return{...t,messages:r}}))},M=(e,s)=>{s&&g(a=>a.map(a=>{if(a.id!==e)return a;let t=[...a.messages],r=t[t.length-1];return r&&"assistant"===r.role?t[t.length-1]={...r,reasoningContent:(r.reasoningContent||"")+s}:r&&"user"===r.role&&t.push({role:"assistant",content:"",reasoningContent:s}),{...a,messages:t}}))},I=(e,s)=>{g(a=>a.map(a=>{if(a.id!==e)return a;let t=[...a.messages],r=t[t.length-1];return r&&"assistant"===r.role?t[t.length-1]={...r,timeToFirstToken:s}:r&&"user"===r.role&&t.push({role:"assistant",content:"",timeToFirstToken:s}),{...a,messages:t}}))},O=(e,s)=>{g(a=>a.map(a=>{if(a.id!==e)return a;let t=[...a.messages],r=t[t.length-1];return r&&"assistant"===r.role?t[t.length-1]={...r,totalLatency:s}:r&&"user"===r.role&&t.push({role:"assistant",content:"",totalLatency:s}),{...a,messages:t}}))},z=(e,s,a)=>{g(t=>t.map(t=>{if(t.id!==e)return t;let r=[...t.messages],n=r[r.length-1];return n&&"assistant"===n.role&&(r[r.length-1]={...n,usage:s,toolName:a}),{...t,messages:r}}))},U=(e,s)=>{s&&g(a=>a.map(a=>{if(a.id!==e)return a;let t=[...a.messages],r=t[t.length-1];return r&&"assistant"===r.role&&(t[t.length-1]={...r,searchResults:s}),{...a,messages:t}}))},W=!!s,G=e=>{let s=e.trim();if(!s)return;if(!P){x.Z.fromBackend("Please provide an API key or select Current UI Session");return}if(0===n.length)return;if(n.some(e=>!e.model)){x.Z.fromBackend("Select a model before sending a message.");return}let a=new Map;n.forEach(e=>{var t;let r=null!==(t=e.traceId)&&void 0!==t?t:(0,l.Z)();a.set(e.id,{id:e.id,model:e.model,traceId:r,tags:e.tags,vectorStores:e.vectorStores,guardrails:e.guardrails,temperature:e.temperature,maxTokens:e.maxTokens,messages:[...e.messages,{role:"user",content:s}]})}),0!==a.size&&(g(e=>e.map(e=>{let s=a.get(e.id);return s?{...e,traceId:s.traceId,messages:s.messages,isLoading:!0}:e})),a.forEach(e=>{var s;let a=e.messages.map(e=>{let{role:s,content:a}=e;return{role:s,content:"string"==typeof a?a:""}}),t=e.tags.length>0?e.tags:void 0,r=e.vectorStores.length>0?e.vectorStores:void 0,l=e.guardrails.length>0?e.guardrails:void 0,i=n.find(s=>s.id===e.id),o=null!==(s=null==i?void 0:i.useAdvancedParams)&&void 0!==s&&s;(0,p.n)(a,(s,a)=>E(e.id,s,a),e.model,P,t,void 0,s=>M(e.id,s),s=>I(e.id,s),s=>z(e.id,s),e.traceId,r,l,void 0,void 0,s=>U(e.id,s),o?e.temperature:void 0,o?e.maxTokens:void 0,s=>O(e.id,s)).catch(s=>{let a=s instanceof Error?s.message:String(s);console.error("CompareUI: failed to fetch response",s),x.Z.fromBackend(a),g(s=>s.map(s=>{if(s.id!==e.id)return s;let t=[...s.messages],r=t[t.length-1],n=r&&"assistant"===r.role&&"string"==typeof r.content?r.content:"";return r&&"assistant"===r.role?t[t.length-1]={...r,content:n?"".concat(n,"\nError fetching response: ").concat(a):"Error fetching response: ".concat(a)}:t.push({role:"assistant",content:"Error fetching response: ".concat(a)}),{...s,messages:t}}))}).finally(()=>{g(s=>s.map(s=>s.id===e.id?{...s,isLoading:!1}:s))})}))},V=e=>{N(e)},X=n.some(e=>e.messages.length>0),Y=n.some(e=>e.isLoading);return(0,t.jsx)("div",{className:"w-full h-full p-4 bg-white",children:(0,t.jsxs)("div",{className:"rounded-2xl border border-gray-200 bg-white shadow-sm min-h-[calc(100vh-140px)] flex flex-col",children:[(0,t.jsx)("div",{className:"border-b px-4 py-2",children:(0,t.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-600",children:"API Key Source"}),(0,t.jsxs)(i.default,{value:k,onChange:e=>w(e),disabled:a,className:"w-48",children:[(0,t.jsx)(i.default.Option,{value:"session",disabled:!W,children:"Current UI Session"}),(0,t.jsx)(i.default.Option,{value:"custom",children:"Virtual Key"})]}),"custom"===k&&(0,t.jsx)(o.default.Password,{value:A,onChange:e=>S(e.target.value),placeholder:"Enter API key",className:"w-56"})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-600",children:"Endpoint"}),(0,t.jsx)(d.Z,{title:"Other endpoints will be available soon",children:(0,t.jsx)(i.default,{value:F,disabled:!0,className:"w-56",children:(0,t.jsx)(i.default.Option,{value:F,children:F})})})]}),(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)(c.ZP,{onClick:()=>{g(e=>e.map(e=>({...e,messages:[],traceId:void 0,isLoading:!1}))),N("")},disabled:!X,icon:(0,t.jsx)(m.Z,{}),children:"Clear All Chats"}),(0,t.jsx)(d.Z,{title:n.length>=3?"Compare up to 3 models at a time":"Add another comparison",children:(0,t.jsx)(c.ZP,{onClick:()=>{var e;if(n.length>=3)return;let s=null!==(e=f[n.length%(f.length||1)])&&void 0!==e?e:"",a={id:Date.now().toString(),model:s,messages:[],isLoading:!1,tags:[],mcpTools:[],vectorStores:[],guardrails:[],temperature:1,maxTokens:2048,applyAcrossModels:!1,useAdvancedParams:!1};g(e=>[...e,a])},disabled:n.length>=3,icon:(0,t.jsx)(u.Z,{}),children:"Add Comparison"})})]})]})}),(0,t.jsx)("div",{className:"grid flex-1 min-h-0 auto-rows-[minmax(0,1fr)]",style:{gridTemplateColumns:"repeat(".concat(n.length,", minmax(0, 1fr))")},children:n.map(e=>(0,t.jsx)(R,{comparison:e,onUpdate:(s,a)=>L(e.id,s,a),onRemove:()=>_(e.id),canRemove:n.length>1,modelOptions:f,isLoadingModels:j,apiKey:P},e.id))}),(0,t.jsx)("div",{className:"flex justify-center pb-4",children:(0,t.jsx)("div",{className:"w-full max-w-3xl px-4",children:(0,t.jsxs)("div",{className:"border border-gray-200 shadow-lg rounded-xl bg-white p-4",children:[(0,t.jsx)("div",{className:"flex items-center justify-between gap-4 mb-3 min-h-8",children:X||Y?Z?(0,t.jsx)("div",{className:"flex items-center gap-2 overflow-x-auto",children:B.map(e=>(0,t.jsx)("button",{type:"button",onClick:()=>V(e),className:"shrink-0 rounded-full border border-gray-200 px-3 py-1 text-xs font-medium text-gray-600 transition-colors hover:bg-gray-100 cursor-pointer",children:e},e))}):Y?(0,t.jsxs)("span",{className:"flex items-center gap-2 text-sm text-gray-500",children:[(0,t.jsx)("span",{className:"h-2 w-2 rounded-full bg-blue-500 animate-pulse","aria-hidden":!0}),"Gathering responses from all models..."]}):(0,t.jsx)("span",{className:"text-sm text-gray-500",children:"Send a prompt to compare models"}):(0,t.jsx)("div",{className:"flex items-center gap-2 overflow-x-auto",children:D.map(e=>(0,t.jsx)("button",{type:"button",onClick:()=>V(e),className:"shrink-0 rounded-full border border-gray-200 px-3 py-1 text-xs font-medium text-gray-600 transition-colors hover:bg-gray-100 cursor-pointer",children:e},e))})}),(0,t.jsx)(K,{value:b,onChange:e=>{N(e)},onSend:()=>{G(b),N("")},disabled:0===n.length||n.every(e=>e.isLoading)})]})})})]})})}var G=a(58643),V=a(80443),X=a(91624);function Y(){let{accessToken:e,userRole:s,userId:a,disabledPersonalKeyCreation:l,token:i}=(0,V.Z)(),[o,d]=(0,r.useState)(void 0);return(0,r.useEffect)(()=>{(async()=>{if(e){let s=await (0,X.C)(e);s&&d({PROXY_BASE_URL:s.PROXY_BASE_URL,LITELLM_UI_API_DOC_BASE_URL:s.LITELLM_UI_API_DOC_BASE_URL})}})()},[e]),(0,t.jsxs)(G.v0,{className:"h-full w-full",children:[(0,t.jsxs)(G.td,{className:"mb-0",children:[(0,t.jsx)(G.OK,{children:"Chat"}),(0,t.jsx)(G.OK,{children:"Compare"})]}),(0,t.jsxs)(G.nP,{className:"h-full",children:[(0,t.jsx)(G.x4,{className:"h-full",children:(0,t.jsx)(n.Z,{accessToken:e,token:i,userRole:s,userID:a,disabledPersonalKeyCreation:l,proxySettings:o})}),(0,t.jsx)(G.x4,{className:"h-full",children:(0,t.jsx)(W,{accessToken:e,disabledPersonalKeyCreation:l})})]})]})}}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/1518-4475f8385da5ac78.js b/litellm/proxy/_experimental/out/_next/static/chunks/1518-4475f8385da5ac78.js new file mode 100644 index 00000000000..476fabcb02f --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/1518-4475f8385da5ac78.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1518],{81518:function(e,s,a){a.r(s),a.d(s,{default:function(){return Y}});var t=a(57437),r=a(2265),n=a(85572),l=a(93837),i=a(37592),o=a(4260),d=a(99981),c=a(5545),m=a(26430),u=a(96473),x=a(9114),h=a(10703),p=a(95459),g=a(32489),f=a(98728),v=a(62831),j=a(17906),y=a(94263),b=a(79862),N=a(82222),k=a(51817),w=a(94331),A=a(38398),S=a(33152);function C(e){let{messages:s,isLoading:a}=e;if(0===s.length)return(0,t.jsx)("div",{className:"h-full"});let r=[],n=0;for(;n(0,t.jsx)("div",{className:"whitespace-pre-wrap break-words",style:{wordWrap:"break-word",overflowWrap:"break-word",wordBreak:"break-word",hyphens:"auto"},children:(0,t.jsx)(v.UG,{components:{code(e){let{node:s,inline:a,className:r,children:n,...l}=e,i=/language-(\w+)/.exec(r||"");return!a&&i?(0,t.jsx)(j.Z,{style:y.Z,language:i[1],PreTag:"div",className:"rounded-md my-2",wrapLines:!0,wrapLongLines:!0,...l,children:String(n).replace(/\n$/,"")}):(0,t.jsx)("code",{className:"".concat(r," px-1.5 py-0.5 rounded bg-gray-100 text-sm font-mono"),...l,children:n})},pre:e=>{let{node:s,...a}=e;return(0,t.jsx)("pre",{style:{overflowX:"auto",maxWidth:"100%"},...a})}},children:"string"==typeof e.content?e.content:""})});return(0,t.jsxs)("div",{className:"flex flex-col gap-6 min-w-0 w-full p-4",children:[r.map((e,s)=>{let n=e.assistant,i=(null==n?void 0:n.model)||"Assistant";return(0,t.jsxs)("div",{className:"space-y-4",children:[e.user&&(0,t.jsxs)("div",{className:"space-y-2 min-w-0",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-blue-100 text-blue-600",children:(0,t.jsx)(b.Z,{size:16})}),(0,t.jsx)("div",{className:"text-sm font-semibold text-gray-700",children:"You"})]}),l(e.user)]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),n?(0,t.jsxs)("div",{className:"space-y-3 min-w-0",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-gray-100 text-gray-600",children:(0,t.jsx)(N.Z,{size:16})}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"text-sm font-semibold text-gray-700",children:i}),n.toolName&&(0,t.jsx)("span",{className:"rounded bg-gray-100 px-2 py-0.5 text-xs text-gray-600",children:n.toolName})]})]}),n.reasoningContent&&(0,t.jsx)(w.Z,{reasoningContent:n.reasoningContent}),n.searchResults&&(0,t.jsx)(S.J,{searchResults:n.searchResults}),l(n),(n.timeToFirstToken||n.totalLatency||n.usage)&&(0,t.jsx)(A.Z,{timeToFirstToken:n.timeToFirstToken,totalLatency:n.totalLatency,usage:n.usage,toolName:n.toolName})]}):a&&s===r.length-1?(0,t.jsxs)("div",{className:"flex items-center gap-2 text-sm text-gray-500",children:[(0,t.jsx)(k.Z,{size:18,className:"animate-spin"}),(0,t.jsx)("span",{children:"Generating response..."})]}):(0,t.jsx)("div",{className:"text-sm text-gray-500",children:"Waiting for a response..."})]},s)}),a&&0===r.length&&(0,t.jsxs)("div",{className:"flex items-center gap-2 text-gray-500",children:[(0,t.jsx)(k.Z,{size:18,className:"animate-spin"}),(0,t.jsx)("span",{children:"Generating response..."})]})]})}var T=a(31283);function P(e){let{value:s,onChange:a,models:n,loading:l,disabled:o}=e,[d,c]=(0,r.useState)(!1),[m,u]=(0,r.useState)(""),x=(0,r.useMemo)(()=>Array.from(new Set(n)).sort(),[n]),h=(0,r.useMemo)(()=>s&&!x.includes(s)?[s,...x]:x,[x,s]),p=d?"__custom__":s||void 0,g=()=>{let e=m.trim();if(!e){c(!1),u("");return}a(e),c(!1),u("")};return(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,t.jsxs)(i.default,{value:p,onChange:e=>{if("__custom__"===e){c(!0),s&&!x.includes(s)?u(s):u("");return}c(!1),u(""),a(e)},disabled:o,loading:l,placeholder:l?"Loading models...":"Select a model",className:"w-full rounded-md",showSearch:!0,optionFilterProp:"children",children:[h.map(e=>(0,t.jsx)(i.default.Option,{value:e,children:e},e)),(0,t.jsx)(i.default.Option,{value:"__custom__",children:"+ Add custom model"})]}),d&&(0,t.jsx)(T.o,{className:"mt-2",placeholder:"Custom Model Name (Enter to add)",value:m,onValueChange:u,onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),g())},onBlur:g,autoFocus:!0})]})}var Z=a(99020),_=a(97415),L=a(67479),E=a(61994),M=a(23496),I=a(85847),O=a(79326);function R(e){let{comparison:s,onUpdate:a,onRemove:n,canRemove:l,modelOptions:i,isLoadingModels:o,apiKey:d}=e,[c,m]=(0,r.useState)(!1),u=e=>{e?a({applyAcrossModels:!0,temperature:s.temperature,maxTokens:s.maxTokens,tags:[...s.tags],vectorStores:[...s.vectorStores],guardrails:[...s.guardrails],useAdvancedParams:s.useAdvancedParams},{applyToAll:!0,keysToApply:["temperature","maxTokens","tags","vectorStores","guardrails","useAdvancedParams"]}):a({applyAcrossModels:!1})},x=e=>{a({useAdvancedParams:e},s.applyAcrossModels?{applyToAll:!0,keysToApply:["useAdvancedParams"]}:void 0)},h=(e,t)=>{a({[e]:t},s.applyAcrossModels?{applyToAll:!0,keysToApply:[e]}:void 0)},p=s.useAdvancedParams?1:.4,v=s.useAdvancedParams?"text-gray-700":"text-gray-400",j=()=>{m(e=>!e)},y=(0,t.jsxs)("div",{className:"w-[300px] max-h-[65vh] overflow-y-auto relative",children:[(0,t.jsx)("button",{onClick:()=>{m(!1)},className:"absolute top-0 right-0 p-1 hover:bg-gray-100 rounded transition-colors text-gray-500 hover:text-gray-700 z-10",children:(0,t.jsx)(g.Z,{size:14})}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)("div",{className:"flex items-center gap-2",children:(0,t.jsx)(E.Z,{checked:s.applyAcrossModels,onChange:e=>u(e.target.checked),children:(0,t.jsx)("span",{className:"text-xs font-medium",children:"Sync Settings Across Models"})})}),(0,t.jsx)(M.Z,{className:"border-gray-200"}),(0,t.jsxs)("div",{children:[(0,t.jsx)("h4",{className:"text-xs font-semibold text-gray-700 mb-1.5 uppercase tracking-wide",children:"General Settings"}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-600 block mb-0.5",children:"Tags"}),(0,t.jsx)(Z.Z,{value:s.tags,onChange:e=>h("tags",e),accessToken:d})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-600 block mb-0.5",children:"Vector Stores"}),(0,t.jsx)(_.Z,{value:s.vectorStores,onChange:e=>h("vectorStores",e),accessToken:d})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-600 block mb-0.5",children:"Guardrails"}),(0,t.jsx)(L.Z,{value:s.guardrails,onChange:e=>h("guardrails",e),accessToken:d})]})]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("h4",{className:"text-xs font-semibold text-gray-700 mb-1.5 uppercase tracking-wide",children:"Advanced Settings"}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)("div",{className:"flex items-center gap-2 pb-1",children:(0,t.jsx)(E.Z,{checked:s.useAdvancedParams,onChange:e=>x(e.target.checked),children:(0,t.jsx)("span",{className:"text-sm font-medium",children:"Use Advanced Parameters"})})}),(0,t.jsxs)("div",{className:"space-y-2 transition-opacity duration-200",style:{opacity:p},children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium ".concat(v),children:"Temperature"}),(0,t.jsx)("span",{className:"text-xs ".concat(v),children:s.temperature.toFixed(2)})]}),(0,t.jsx)(I.Z,{min:0,max:2,step:.01,value:s.temperature,onChange:e=>{h("temperature",Math.min(2,Math.max(0,Number((Array.isArray(e)?e[0]:e).toFixed(2)))))},disabled:!s.useAdvancedParams})]}),(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium ".concat(v),children:"Max Tokens"}),(0,t.jsx)("span",{className:"text-xs ".concat(v),children:s.maxTokens})]}),(0,t.jsx)(I.Z,{min:1,max:32768,step:1,value:s.maxTokens,onChange:e=>{h("maxTokens",Math.min(32768,Math.max(1,Math.round(Array.isArray(e)?e[0]:e))))},disabled:!s.useAdvancedParams})]})]})]})]})]})]});return(0,t.jsxs)("div",{className:"bg-white first:border-l-0 border-l border-gray-200 flex flex-col min-h-0",children:[(0,t.jsxs)("div",{className:"border-b flex items-center justify-between gap-3 px-4 py-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3 flex-1",children:[(0,t.jsx)(P,{value:s.model,models:i,loading:o,onChange:e=>a({model:e})}),(0,t.jsx)("div",{className:"flex items-center gap-2",children:(0,t.jsx)(O.Z,{content:y,trigger:[],open:c,onOpenChange:()=>{},placement:"bottomRight",destroyTooltipOnHide:!1,children:(0,t.jsx)("button",{onClick:e=>{e.stopPropagation(),j()},className:"p-2 rounded-lg transition-colors ".concat(c?"bg-gray-200 text-gray-700":"hover:bg-gray-100 text-gray-600"),children:(0,t.jsx)(f.Z,{size:18})})})})]}),l&&(0,t.jsx)("button",{onClick:e=>{e.stopPropagation(),n()},className:"p-2 hover:bg-red-50 text-red-600 rounded-lg transition-colors",children:(0,t.jsx)(g.Z,{size:18})})]}),(0,t.jsx)("div",{className:"relative flex-1 flex flex-col min-h-0",children:(0,t.jsx)("div",{className:"flex-1 max-h-[calc(100vh-385px)] overflow-auto rounded-b-2xl",children:(0,t.jsx)(C,{messages:s.messages,isLoading:s.isLoading})})})]})}var z=a(79276);let{TextArea:U}=o.default;function K(e){let{value:s,onChange:a,onSend:r,disabled:n}=e;return(0,t.jsx)("div",{className:"flex items-center gap-2",children:(0,t.jsxs)("div",{className:"flex items-center flex-1 bg-white border border-gray-300 rounded-xl px-3 py-1 min-h-[44px]",children:[(0,t.jsx)(U,{value:s,onChange:e=>a(e.target.value),onKeyDown:e=>{"Enter"===e.key&&!e.shiftKey&&(e.preventDefault(),!n&&s.trim()&&r())},placeholder:"Type your message... (Shift+Enter for new line)",disabled:n,className:"flex-1",autoSize:{minRows:1,maxRows:4},style:{resize:"none",border:"none",boxShadow:"none",background:"transparent",padding:"4px 0",fontSize:"14px",lineHeight:"20px"}}),(0,t.jsx)(c.ZP,{onClick:r,disabled:n||!s.trim(),icon:(0,t.jsx)(z.Z,{}),shape:"circle"})]})})}let B=["Can you summarize the key points?","What assumptions did you make?","What are the next steps?"],D=["Write me a poem","Explain quantum computing","Draft a polite email requesting a meeting"],F="/v1/chat/completions";function W(e){let{accessToken:s,disabledPersonalKeyCreation:a}=e,[n,g]=(0,r.useState)([{id:"1",model:"",messages:[],isLoading:!1,tags:[],mcpTools:[],vectorStores:[],guardrails:[],temperature:1,maxTokens:2048,applyAcrossModels:!1,useAdvancedParams:!1},{id:"2",model:"",messages:[],isLoading:!1,tags:[],mcpTools:[],vectorStores:[],guardrails:[],temperature:1,maxTokens:2048,applyAcrossModels:!1,useAdvancedParams:!1}]),[f,v]=(0,r.useState)([]),[j,y]=(0,r.useState)(!1),[b,N]=(0,r.useState)(""),[k,w]=(0,r.useState)(a?"custom":"session"),[A,S]=(0,r.useState)(""),[C,T]=(0,r.useState)("");(0,r.useEffect)(()=>{let e=setTimeout(()=>{T(A)},300);return()=>clearTimeout(e)},[A]);let P=(0,r.useMemo)(()=>"session"===k?s||"":C.trim(),[k,s,C]),Z=(0,r.useMemo)(()=>n.length>0&&n.every(e=>!e.isLoading&&e.messages.some(e=>"assistant"===e.role)),[n]);(0,r.useEffect)(()=>{let e=!0;return(async()=>{if(!P){v([]);return}y(!0);try{let s=await (0,h.p)(P);if(!e)return;let a=Array.from(new Set(s.map(e=>e.model_group)));v(a)}catch(s){console.error("CompareUI: failed to fetch models",s),e&&v([])}finally{e&&y(!1)}})(),()=>{e=!1}},[P]),(0,r.useEffect)(()=>{0!==f.length&&g(e=>e.map((e,s)=>{var a,t,r,n,l;return{...e,temperature:null!==(a=e.temperature)&&void 0!==a?a:1,maxTokens:null!==(t=e.maxTokens)&&void 0!==t?t:2048,applyAcrossModels:null!==(r=e.applyAcrossModels)&&void 0!==r&&r,useAdvancedParams:null!==(n=e.useAdvancedParams)&&void 0!==n&&n,...e.model?{}:{model:null!==(l=f[s%f.length])&&void 0!==l?l:""}}}))},[f]);let _=e=>{n.length>1&&g(s=>s.filter(s=>s.id!==e))},L=(e,s,a)=>{g(t=>{var r;if((null==a?void 0:a.applyToAll)&&(null===(r=a.keysToApply)||void 0===r?void 0:r.length)){let r={};a.keysToApply.forEach(e=>{let a=s[e];void 0!==a&&(r[e]=Array.isArray(a)?[...a]:a)});let n=Object.keys(r).length>0;return t.map(a=>a.id===e?{...a,...s}:n?{...a,...r}:a)}return t.map(a=>a.id===e?{...a,...s}:a)})},E=(e,s,a)=>{s&&g(t=>t.map(t=>{if(t.id!==e)return t;let r=[...t.messages],n=r[r.length-1];if(n&&"assistant"===n.role){var l;let e="string"==typeof n.content?n.content:"";r[r.length-1]={...n,content:e+s,model:null!==(l=n.model)&&void 0!==l?l:a}}else r.push({role:"assistant",content:s,model:a});return{...t,messages:r}}))},M=(e,s)=>{s&&g(a=>a.map(a=>{if(a.id!==e)return a;let t=[...a.messages],r=t[t.length-1];return r&&"assistant"===r.role?t[t.length-1]={...r,reasoningContent:(r.reasoningContent||"")+s}:r&&"user"===r.role&&t.push({role:"assistant",content:"",reasoningContent:s}),{...a,messages:t}}))},I=(e,s)=>{g(a=>a.map(a=>{if(a.id!==e)return a;let t=[...a.messages],r=t[t.length-1];return r&&"assistant"===r.role?t[t.length-1]={...r,timeToFirstToken:s}:r&&"user"===r.role&&t.push({role:"assistant",content:"",timeToFirstToken:s}),{...a,messages:t}}))},O=(e,s)=>{g(a=>a.map(a=>{if(a.id!==e)return a;let t=[...a.messages],r=t[t.length-1];return r&&"assistant"===r.role?t[t.length-1]={...r,totalLatency:s}:r&&"user"===r.role&&t.push({role:"assistant",content:"",totalLatency:s}),{...a,messages:t}}))},z=(e,s,a)=>{g(t=>t.map(t=>{if(t.id!==e)return t;let r=[...t.messages],n=r[r.length-1];return n&&"assistant"===n.role&&(r[r.length-1]={...n,usage:s,toolName:a}),{...t,messages:r}}))},U=(e,s)=>{s&&g(a=>a.map(a=>{if(a.id!==e)return a;let t=[...a.messages],r=t[t.length-1];return r&&"assistant"===r.role&&(t[t.length-1]={...r,searchResults:s}),{...a,messages:t}}))},W=!!s,G=e=>{let s=e.trim();if(!s)return;if(!P){x.Z.fromBackend("Please provide an API key or select Current UI Session");return}if(0===n.length)return;if(n.some(e=>!e.model)){x.Z.fromBackend("Select a model before sending a message.");return}let a=new Map;n.forEach(e=>{var t;let r=null!==(t=e.traceId)&&void 0!==t?t:(0,l.Z)();a.set(e.id,{id:e.id,model:e.model,traceId:r,tags:e.tags,vectorStores:e.vectorStores,guardrails:e.guardrails,temperature:e.temperature,maxTokens:e.maxTokens,messages:[...e.messages,{role:"user",content:s}]})}),0!==a.size&&(g(e=>e.map(e=>{let s=a.get(e.id);return s?{...e,traceId:s.traceId,messages:s.messages,isLoading:!0}:e})),a.forEach(e=>{var s;let a=e.messages.map(e=>{let{role:s,content:a}=e;return{role:s,content:"string"==typeof a?a:""}}),t=e.tags.length>0?e.tags:void 0,r=e.vectorStores.length>0?e.vectorStores:void 0,l=e.guardrails.length>0?e.guardrails:void 0,i=n.find(s=>s.id===e.id),o=null!==(s=null==i?void 0:i.useAdvancedParams)&&void 0!==s&&s;(0,p.n)(a,(s,a)=>E(e.id,s,a),e.model,P,t,void 0,s=>M(e.id,s),s=>I(e.id,s),s=>z(e.id,s),e.traceId,r,l,void 0,void 0,s=>U(e.id,s),o?e.temperature:void 0,o?e.maxTokens:void 0,s=>O(e.id,s)).catch(s=>{let a=s instanceof Error?s.message:String(s);console.error("CompareUI: failed to fetch response",s),x.Z.fromBackend(a),g(s=>s.map(s=>{if(s.id!==e.id)return s;let t=[...s.messages],r=t[t.length-1],n=r&&"assistant"===r.role&&"string"==typeof r.content?r.content:"";return r&&"assistant"===r.role?t[t.length-1]={...r,content:n?"".concat(n,"\nError fetching response: ").concat(a):"Error fetching response: ".concat(a)}:t.push({role:"assistant",content:"Error fetching response: ".concat(a)}),{...s,messages:t}}))}).finally(()=>{g(s=>s.map(s=>s.id===e.id?{...s,isLoading:!1}:s))})}))},V=e=>{N(e)},X=n.some(e=>e.messages.length>0),Y=n.some(e=>e.isLoading);return(0,t.jsx)("div",{className:"w-full h-full p-4 bg-white",children:(0,t.jsxs)("div",{className:"rounded-2xl border border-gray-200 bg-white shadow-sm min-h-[calc(100vh-140px)] flex flex-col",children:[(0,t.jsx)("div",{className:"border-b px-4 py-2",children:(0,t.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-600",children:"API Key Source"}),(0,t.jsxs)(i.default,{value:k,onChange:e=>w(e),disabled:a,className:"w-48",children:[(0,t.jsx)(i.default.Option,{value:"session",disabled:!W,children:"Current UI Session"}),(0,t.jsx)(i.default.Option,{value:"custom",children:"Virtual Key"})]}),"custom"===k&&(0,t.jsx)(o.default.Password,{value:A,onChange:e=>S(e.target.value),placeholder:"Enter API key",className:"w-56"})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-600",children:"Endpoint"}),(0,t.jsx)(d.Z,{title:"Other endpoints will be available soon",children:(0,t.jsx)(i.default,{value:F,disabled:!0,className:"w-56",children:(0,t.jsx)(i.default.Option,{value:F,children:F})})})]}),(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)(c.ZP,{onClick:()=>{g(e=>e.map(e=>({...e,messages:[],traceId:void 0,isLoading:!1}))),N("")},disabled:!X,icon:(0,t.jsx)(m.Z,{}),children:"Clear All Chats"}),(0,t.jsx)(d.Z,{title:n.length>=3?"Compare up to 3 models at a time":"Add another comparison",children:(0,t.jsx)(c.ZP,{onClick:()=>{var e;if(n.length>=3)return;let s=null!==(e=f[n.length%(f.length||1)])&&void 0!==e?e:"",a={id:Date.now().toString(),model:s,messages:[],isLoading:!1,tags:[],mcpTools:[],vectorStores:[],guardrails:[],temperature:1,maxTokens:2048,applyAcrossModels:!1,useAdvancedParams:!1};g(e=>[...e,a])},disabled:n.length>=3,icon:(0,t.jsx)(u.Z,{}),children:"Add Comparison"})})]})]})}),(0,t.jsx)("div",{className:"grid flex-1 min-h-0 auto-rows-[minmax(0,1fr)]",style:{gridTemplateColumns:"repeat(".concat(n.length,", minmax(0, 1fr))")},children:n.map(e=>(0,t.jsx)(R,{comparison:e,onUpdate:(s,a)=>L(e.id,s,a),onRemove:()=>_(e.id),canRemove:n.length>1,modelOptions:f,isLoadingModels:j,apiKey:P},e.id))}),(0,t.jsx)("div",{className:"flex justify-center pb-4",children:(0,t.jsx)("div",{className:"w-full max-w-3xl px-4",children:(0,t.jsxs)("div",{className:"border border-gray-200 shadow-lg rounded-xl bg-white p-4",children:[(0,t.jsx)("div",{className:"flex items-center justify-between gap-4 mb-3 min-h-8",children:X||Y?Z?(0,t.jsx)("div",{className:"flex items-center gap-2 overflow-x-auto",children:B.map(e=>(0,t.jsx)("button",{type:"button",onClick:()=>V(e),className:"shrink-0 rounded-full border border-gray-200 px-3 py-1 text-xs font-medium text-gray-600 transition-colors hover:bg-gray-100 cursor-pointer",children:e},e))}):Y?(0,t.jsxs)("span",{className:"flex items-center gap-2 text-sm text-gray-500",children:[(0,t.jsx)("span",{className:"h-2 w-2 rounded-full bg-blue-500 animate-pulse","aria-hidden":!0}),"Gathering responses from all models..."]}):(0,t.jsx)("span",{className:"text-sm text-gray-500",children:"Send a prompt to compare models"}):(0,t.jsx)("div",{className:"flex items-center gap-2 overflow-x-auto",children:D.map(e=>(0,t.jsx)("button",{type:"button",onClick:()=>V(e),className:"shrink-0 rounded-full border border-gray-200 px-3 py-1 text-xs font-medium text-gray-600 transition-colors hover:bg-gray-100 cursor-pointer",children:e},e))})}),(0,t.jsx)(K,{value:b,onChange:e=>{N(e)},onSend:()=>{G(b),N("")},disabled:0===n.length||n.every(e=>e.isLoading)})]})})})]})})}var G=a(58643),V=a(39760),X=a(91624);function Y(){let{accessToken:e,userRole:s,userId:a,disabledPersonalKeyCreation:l,token:i}=(0,V.Z)(),[o,d]=(0,r.useState)(void 0);return(0,r.useEffect)(()=>{(async()=>{if(e){let s=await (0,X.C)(e);s&&d({PROXY_BASE_URL:s.PROXY_BASE_URL,LITELLM_UI_API_DOC_BASE_URL:s.LITELLM_UI_API_DOC_BASE_URL})}})()},[e]),(0,t.jsxs)(G.v0,{className:"h-full w-full",children:[(0,t.jsxs)(G.td,{className:"mb-0",children:[(0,t.jsx)(G.OK,{children:"Chat"}),(0,t.jsx)(G.OK,{children:"Compare"})]}),(0,t.jsxs)(G.nP,{className:"h-full",children:[(0,t.jsx)(G.x4,{className:"h-full",children:(0,t.jsx)(n.Z,{accessToken:e,token:i,userRole:s,userID:a,disabledPersonalKeyCreation:l,proxySettings:o})}),(0,t.jsx)(G.x4,{className:"h-full",children:(0,t.jsx)(W,{accessToken:e,disabledPersonalKeyCreation:l})})]})]})}}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/1529-aa686050ee3518d4.js b/litellm/proxy/_experimental/out/_next/static/chunks/1529-59ce29afdf8ccc9b.js similarity index 99% rename from litellm/proxy/_experimental/out/_next/static/chunks/1529-aa686050ee3518d4.js rename to litellm/proxy/_experimental/out/_next/static/chunks/1529-59ce29afdf8ccc9b.js index e0d9b0cf48c..c98ed86dee5 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/1529-aa686050ee3518d4.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/1529-59ce29afdf8ccc9b.js @@ -1 +1 @@ -"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1529],{39760:function(e,n,t){t.d(n,{Z:function(){return a}});var r=t(1119),o=t(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M176 511a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0z"}}]},name:"ellipsis",theme:"outlined"},l=t(55015),a=o.forwardRef(function(e,n){return o.createElement(l.Z,(0,r.Z)({},e,{ref:n,icon:i}))})},77565:function(e,n,t){t.d(n,{Z:function(){return a}});var r=t(1119),o=t(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"}}]},name:"right",theme:"outlined"},l=t(55015),a=o.forwardRef(function(e,n){return o.createElement(l.Z,(0,r.Z)({},e,{ref:n,icon:i}))})},71030:function(e,n,t){t.d(n,{Z:function(){return C}});var r=t(1119),o=t(11993),i=t(26365),l=t(6989),a=t(97821),u=t(36760),c=t.n(u),s=t(28791),f=t(2265),d=t(95814),p=t(53346),v=d.Z.ESC,m=d.Z.TAB,b=(0,f.forwardRef)(function(e,n){var t=e.overlay,r=e.arrow,o=e.prefixCls,i=(0,f.useMemo)(function(){return"function"==typeof t?t():t},[t]),l=(0,s.sQ)(n,(0,s.C4)(i));return f.createElement(f.Fragment,null,r&&f.createElement("div",{className:"".concat(o,"-arrow")}),f.cloneElement(i,{ref:(0,s.Yr)(i)?l:void 0}))}),y={adjustX:1,adjustY:1},h=[0,0],g={topLeft:{points:["bl","tl"],overflow:y,offset:[0,-4],targetOffset:h},top:{points:["bc","tc"],overflow:y,offset:[0,-4],targetOffset:h},topRight:{points:["br","tr"],overflow:y,offset:[0,-4],targetOffset:h},bottomLeft:{points:["tl","bl"],overflow:y,offset:[0,4],targetOffset:h},bottom:{points:["tc","bc"],overflow:y,offset:[0,4],targetOffset:h},bottomRight:{points:["tr","br"],overflow:y,offset:[0,4],targetOffset:h}},Z=["arrow","prefixCls","transitionName","animation","align","placement","placements","getPopupContainer","showAction","hideAction","overlayClassName","overlayStyle","visible","trigger","autoFocus","overlay","children","onVisibleChange"],C=f.forwardRef(function(e,n){var t,u,d,y,h,C,E,w,k,M,R,x,N,P,S=e.arrow,I=void 0!==S&&S,K=e.prefixCls,A=void 0===K?"rc-dropdown":K,O=e.transitionName,T=e.animation,L=e.align,D=e.placement,_=e.placements,V=e.getPopupContainer,z=e.showAction,F=e.hideAction,j=e.overlayClassName,B=e.overlayStyle,W=e.visible,H=e.trigger,Y=void 0===H?["hover"]:H,q=e.autoFocus,X=e.overlay,G=e.children,Q=e.onVisibleChange,U=(0,l.Z)(e,Z),J=f.useState(),$=(0,i.Z)(J,2),ee=$[0],en=$[1],et="visible"in e?W:ee,er=f.useRef(null),eo=f.useRef(null),ei=f.useRef(null);f.useImperativeHandle(n,function(){return er.current});var el=function(e){en(e),null==Q||Q(e)};u=(t={visible:et,triggerRef:ei,onVisibleChange:el,autoFocus:q,overlayRef:eo}).visible,d=t.triggerRef,y=t.onVisibleChange,h=t.autoFocus,C=t.overlayRef,E=f.useRef(!1),w=function(){if(u){var e,n;null===(e=d.current)||void 0===e||null===(n=e.focus)||void 0===n||n.call(e),null==y||y(!1)}},k=function(){var e;return null!==(e=C.current)&&void 0!==e&&!!e.focus&&(C.current.focus(),E.current=!0,!0)},M=function(e){switch(e.keyCode){case v:w();break;case m:var n=!1;E.current||(n=k()),n?e.preventDefault():w()}},f.useEffect(function(){return u?(window.addEventListener("keydown",M),h&&(0,p.Z)(k,3),function(){window.removeEventListener("keydown",M),E.current=!1}):function(){E.current=!1}},[u]);var ea=function(){return f.createElement(b,{ref:eo,overlay:X,prefixCls:A,arrow:I})},eu=f.cloneElement(G,{className:c()(null===(P=G.props)||void 0===P?void 0:P.className,et&&(void 0!==(R=e.openClassName)?R:"".concat(A,"-open"))),ref:(0,s.Yr)(G)?(0,s.sQ)(ei,(0,s.C4)(G)):void 0}),ec=F;return ec||-1===Y.indexOf("contextMenu")||(ec=["click"]),f.createElement(a.Z,(0,r.Z)({builtinPlacements:void 0===_?g:_},U,{prefixCls:A,ref:er,popupClassName:c()(j,(0,o.Z)({},"".concat(A,"-show-arrow"),I)),popupStyle:B,action:Y,showAction:z,hideAction:ec,popupPlacement:void 0===D?"bottomLeft":D,popupAlign:L,popupTransitionName:O,popupAnimation:T,popupVisible:et,stretch:(x=e.minOverlayWidthMatchTrigger,N=e.alignPoint,"minOverlayWidthMatchTrigger"in e?x:!N)?"minWidth":"",popup:"function"==typeof X?ea:ea(),onPopupVisibleChange:el,onPopupClick:function(n){var t=e.onOverlayClick;en(!1),t&&t(n)},getPopupContainer:V}),eu)})},33082:function(e,n,t){t.d(n,{iz:function(){return eA},ck:function(){return ev},BW:function(){return eL},sN:function(){return ev},Wd:function(){return eI},ZP:function(){return ej},Xl:function(){return x}});var r=t(1119),o=t(11993),i=t(31686),l=t(83145),a=t(26365),u=t(6989),c=t(36760),s=t.n(c),f=t(1699),d=t(50506),p=t(16671),v=t(32559),m=t(2265),b=t(54887),y=m.createContext(null);function h(e,n){return void 0===e?null:"".concat(e,"-").concat(n)}function g(e){return h(m.useContext(y),e)}var Z=t(6397),C=["children","locked"],E=m.createContext(null);function w(e){var n=e.children,t=e.locked,r=(0,u.Z)(e,C),o=m.useContext(E),l=(0,Z.Z)(function(){var e;return e=(0,i.Z)({},o),Object.keys(r).forEach(function(n){var t=r[n];void 0!==t&&(e[n]=t)}),e},[o,r],function(e,n){return!t&&(e[0]!==n[0]||!(0,p.Z)(e[1],n[1],!0))});return m.createElement(E.Provider,{value:l},n)}var k=m.createContext(null);function M(){return m.useContext(k)}var R=m.createContext([]);function x(e){var n=m.useContext(R);return m.useMemo(function(){return void 0!==e?[].concat((0,l.Z)(n),[e]):n},[n,e])}var N=m.createContext(null),P=m.createContext({}),S=t(2857);function I(e){var n=arguments.length>1&&void 0!==arguments[1]&&arguments[1];if((0,S.Z)(e)){var t=e.nodeName.toLowerCase(),r=["input","select","textarea","button"].includes(t)||e.isContentEditable||"a"===t&&!!e.getAttribute("href"),o=e.getAttribute("tabindex"),i=Number(o),l=null;return o&&!Number.isNaN(i)?l=i:r&&null===l&&(l=0),r&&e.disabled&&(l=null),null!==l&&(l>=0||n&&l<0)}return!1}var K=t(95814),A=t(53346),O=K.Z.LEFT,T=K.Z.RIGHT,L=K.Z.UP,D=K.Z.DOWN,_=K.Z.ENTER,V=K.Z.ESC,z=K.Z.HOME,F=K.Z.END,j=[L,D,O,T];function B(e,n){return(function(e){var n=arguments.length>1&&void 0!==arguments[1]&&arguments[1],t=(0,l.Z)(e.querySelectorAll("*")).filter(function(e){return I(e,n)});return I(e,n)&&t.unshift(e),t})(e,!0).filter(function(e){return n.has(e)})}function W(e,n,t){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:1;if(!e)return null;var o=B(e,n),i=o.length,l=o.findIndex(function(e){return t===e});return r<0?-1===l?l=i-1:l-=1:r>0&&(l+=1),o[l=(l+i)%i]}var H=function(e,n){var t=new Set,r=new Map,o=new Map;return e.forEach(function(e){var i=document.querySelector("[data-menu-id='".concat(h(n,e),"']"));i&&(t.add(i),o.set(i,e),r.set(e,i))}),{elements:t,key2element:r,element2key:o}},Y="__RC_UTIL_PATH_SPLIT__",q=function(e){return e.join(Y)},X="rc-menu-more";function G(e){var n=m.useRef(e);n.current=e;var t=m.useCallback(function(){for(var e,t=arguments.length,r=Array(t),o=0;o1&&(k.motionAppear=!1);var M=k.onVisibleChanged;return(k.onVisibleChanged=function(e){return b.current||e||Z(!0),null==M?void 0:M(e)},g)?null:m.createElement(w,{mode:u,locked:!b.current},m.createElement(eR.ZP,(0,r.Z)({visible:C},k,{forceRender:f,removeOnLeave:!1,leavedClassName:"".concat(s,"-hidden")}),function(e){var t=e.className,r=e.style;return m.createElement(eb,{id:n,className:t,style:r},l)}))}var eN=["style","className","title","eventKey","warnKey","disabled","internalPopupClose","children","itemIcon","expandIcon","popupClassName","popupOffset","popupStyle","onClick","onMouseEnter","onMouseLeave","onTitleClick","onTitleMouseEnter","onTitleMouseLeave"],eP=["active"],eS=m.forwardRef(function(e,n){var t=e.style,l=e.className,c=e.title,d=e.eventKey,p=(e.warnKey,e.disabled),v=e.internalPopupClose,b=e.children,y=e.itemIcon,h=e.expandIcon,Z=e.popupClassName,C=e.popupOffset,k=e.popupStyle,M=e.onClick,R=e.onMouseEnter,S=e.onMouseLeave,I=e.onTitleClick,K=e.onTitleMouseEnter,A=e.onTitleMouseLeave,O=(0,u.Z)(e,eN),T=g(d),L=m.useContext(E),D=L.prefixCls,_=L.mode,V=L.openKeys,z=L.disabled,F=L.overflowDisabled,j=L.activeKey,B=L.selectedKeys,W=L.itemIcon,H=L.expandIcon,Y=L.onItemClick,q=L.onOpenChange,X=L.onActive,Q=m.useContext(P)._internalRenderSubMenuItem,U=m.useContext(N).isSubPathKey,J=x(),$="".concat(D,"-submenu"),ee=z||p,en=m.useRef(),et=m.useRef(),er=null!=h?h:H,ea=V.includes(d),ec=!F&&ea,es=U(B,d),ef=eo(d,ee,K,A),ed=ef.active,ep=(0,u.Z)(ef,eP),ev=m.useState(!1),em=(0,a.Z)(ev,2),ey=em[0],eh=em[1],eg=function(e){ee||eh(e)},eZ=m.useMemo(function(){return ed||"inline"!==_&&(ey||U([j],d))},[_,ed,j,ey,d,U]),eC=ei(J.length),eE=G(function(e){null==M||M(eu(e)),Y(e)}),ew=T&&"".concat(T,"-popup"),ek=m.useMemo(function(){return m.createElement(el,{icon:"horizontal"!==_?er:void 0,props:(0,i.Z)((0,i.Z)({},e),{},{isOpen:ec,isSubMenu:!0})},m.createElement("i",{className:"".concat($,"-arrow")}))},[_,er,e,ec,$]),eR=m.createElement("div",(0,r.Z)({role:"menuitem",style:eC,className:"".concat($,"-title"),tabIndex:ee?null:-1,ref:en,title:"string"==typeof c?c:null,"data-menu-id":F&&T?null:T,"aria-expanded":ec,"aria-haspopup":!0,"aria-controls":ew,"aria-disabled":ee,onClick:function(e){ee||(null==I||I({key:d,domEvent:e}),"inline"===_&&q(d,!ea))},onFocus:function(){X(d)}},ep),c,ek),eS=m.useRef(_);if("inline"!==_&&J.length>1?eS.current="vertical":eS.current=_,!F){var eI=eS.current;eR=m.createElement(eM,{mode:eI,prefixCls:$,visible:!v&&ec&&"inline"!==_,popupClassName:Z,popupOffset:C,popupStyle:k,popup:m.createElement(w,{mode:"horizontal"===eI?"vertical":eI},m.createElement(eb,{id:ew,ref:et},b)),disabled:ee,onVisibleChange:function(e){"inline"!==_&&q(d,e)}},eR)}var eK=m.createElement(f.Z.Item,(0,r.Z)({ref:n,role:"none"},O,{component:"li",style:t,className:s()($,"".concat($,"-").concat(_),l,(0,o.Z)((0,o.Z)((0,o.Z)((0,o.Z)({},"".concat($,"-open"),ec),"".concat($,"-active"),eZ),"".concat($,"-selected"),es),"".concat($,"-disabled"),ee)),onMouseEnter:function(e){eg(!0),null==R||R({key:d,domEvent:e})},onMouseLeave:function(e){eg(!1),null==S||S({key:d,domEvent:e})}}),eR,!F&&m.createElement(ex,{id:ew,open:ec,keyPath:J},b));return Q&&(eK=Q(eK,e,{selected:es,active:eZ,open:ec,disabled:ee})),m.createElement(w,{onItemClick:eE,mode:"horizontal"===_?"vertical":_,itemIcon:null!=y?y:W,expandIcon:er},eK)}),eI=m.forwardRef(function(e,n){var t,o=e.eventKey,i=e.children,l=x(o),a=eh(i,l),u=M();return m.useEffect(function(){if(u)return u.registerPath(o,l),function(){u.unregisterPath(o,l)}},[l]),t=u?a:m.createElement(eS,(0,r.Z)({ref:n},e),a),m.createElement(R.Provider,{value:l},t)}),eK=t(41154);function eA(e){var n=e.className,t=e.style,r=m.useContext(E).prefixCls;return M()?null:m.createElement("li",{role:"separator",className:s()("".concat(r,"-item-divider"),n),style:t})}var eO=["className","title","eventKey","children"],eT=m.forwardRef(function(e,n){var t=e.className,o=e.title,i=(e.eventKey,e.children),l=(0,u.Z)(e,eO),a=m.useContext(E).prefixCls,c="".concat(a,"-item-group");return m.createElement("li",(0,r.Z)({ref:n,role:"presentation"},l,{onClick:function(e){return e.stopPropagation()},className:s()(c,t)}),m.createElement("div",{role:"presentation",className:"".concat(c,"-title"),title:"string"==typeof o?o:void 0},o),m.createElement("ul",{role:"group",className:"".concat(c,"-list")},i))}),eL=m.forwardRef(function(e,n){var t=e.eventKey,o=eh(e.children,x(t));return M()?o:m.createElement(eT,(0,r.Z)({ref:n},(0,et.Z)(e,["warnKey"])),o)}),eD=["label","children","key","type","extra"];function e_(e,n,t,o,l){var a=e,c=(0,i.Z)({divider:eA,item:ev,group:eL,submenu:eI},o);return n&&(a=function e(n,t,o){var i=t.item,l=t.group,a=t.submenu,c=t.divider;return(n||[]).map(function(n,s){if(n&&"object"===(0,eK.Z)(n)){var f=n.label,d=n.children,p=n.key,v=n.type,b=n.extra,y=(0,u.Z)(n,eD),h=null!=p?p:"tmp-".concat(s);return d||"group"===v?"group"===v?m.createElement(l,(0,r.Z)({key:h},y,{title:f}),e(d,t,o)):m.createElement(a,(0,r.Z)({key:h},y,{title:f}),e(d,t,o)):"divider"===v?m.createElement(c,(0,r.Z)({key:h},y)):m.createElement(i,(0,r.Z)({key:h},y,{extra:b}),f,(!!b||0===b)&&m.createElement("span",{className:"".concat(o,"-item-extra")},b))}return null}).filter(function(e){return e})}(n,c,l)),eh(a,t)}var eV=["prefixCls","rootClassName","style","className","tabIndex","items","children","direction","id","mode","inlineCollapsed","disabled","disabledOverflow","subMenuOpenDelay","subMenuCloseDelay","forceSubMenuRender","defaultOpenKeys","openKeys","activeKey","defaultActiveFirst","selectable","multiple","defaultSelectedKeys","selectedKeys","onSelect","onDeselect","inlineIndent","motion","defaultMotions","triggerSubMenuAction","builtinPlacements","itemIcon","expandIcon","overflowedIndicator","overflowedIndicatorPopupClassName","getPopupContainer","onClick","onOpenChange","onKeyDown","openAnimation","openTransitionName","_internalRenderMenuItem","_internalRenderSubMenuItem","_internalComponents"],ez=[],eF=m.forwardRef(function(e,n){var t,c,v,h,g,Z,C,E,M,R,x,S,I,K,J,$,ee,en,et,er,eo,ei,el,ea,ec,es,ef=e.prefixCls,ed=void 0===ef?"rc-menu":ef,ep=e.rootClassName,em=e.style,eb=e.className,ey=e.tabIndex,eh=e.items,eg=e.children,eZ=e.direction,eC=e.id,eE=e.mode,ew=void 0===eE?"vertical":eE,ek=e.inlineCollapsed,eM=e.disabled,eR=e.disabledOverflow,ex=e.subMenuOpenDelay,eN=e.subMenuCloseDelay,eP=e.forceSubMenuRender,eS=e.defaultOpenKeys,eK=e.openKeys,eA=e.activeKey,eO=e.defaultActiveFirst,eT=e.selectable,eL=void 0===eT||eT,eD=e.multiple,eF=void 0!==eD&&eD,ej=e.defaultSelectedKeys,eB=e.selectedKeys,eW=e.onSelect,eH=e.onDeselect,eY=e.inlineIndent,eq=e.motion,eX=e.defaultMotions,eG=e.triggerSubMenuAction,eQ=e.builtinPlacements,eU=e.itemIcon,eJ=e.expandIcon,e$=e.overflowedIndicator,e0=void 0===e$?"...":e$,e1=e.overflowedIndicatorPopupClassName,e6=e.getPopupContainer,e2=e.onClick,e5=e.onOpenChange,e9=e.onKeyDown,e3=(e.openAnimation,e.openTransitionName,e._internalRenderMenuItem),e4=e._internalRenderSubMenuItem,e7=e._internalComponents,e8=(0,u.Z)(e,eV),ne=m.useMemo(function(){return[e_(eg,eh,ez,e7,ed),e_(eg,eh,ez,{},ed)]},[eg,eh,e7]),nn=(0,a.Z)(ne,2),nt=nn[0],nr=nn[1],no=m.useState(!1),ni=(0,a.Z)(no,2),nl=ni[0],na=ni[1],nu=m.useRef(),nc=(t=(0,d.Z)(eC,{value:eC}),v=(c=(0,a.Z)(t,2))[0],h=c[1],m.useEffect(function(){U+=1;var e="".concat(Q,"-").concat(U);h("rc-menu-uuid-".concat(e))},[]),v),ns="rtl"===eZ,nf=(0,d.Z)(eS,{value:eK,postState:function(e){return e||ez}}),nd=(0,a.Z)(nf,2),np=nd[0],nv=nd[1],nm=function(e){var n=arguments.length>1&&void 0!==arguments[1]&&arguments[1];function t(){nv(e),null==e5||e5(e)}n?(0,b.flushSync)(t):t()},nb=m.useState(np),ny=(0,a.Z)(nb,2),nh=ny[0],ng=ny[1],nZ=m.useRef(!1),nC=m.useMemo(function(){return("inline"===ew||"vertical"===ew)&&ek?["vertical",ek]:[ew,!1]},[ew,ek]),nE=(0,a.Z)(nC,2),nw=nE[0],nk=nE[1],nM="inline"===nw,nR=m.useState(nw),nx=(0,a.Z)(nR,2),nN=nx[0],nP=nx[1],nS=m.useState(nk),nI=(0,a.Z)(nS,2),nK=nI[0],nA=nI[1];m.useEffect(function(){nP(nw),nA(nk),nZ.current&&(nM?nv(nh):nm(ez))},[nw,nk]);var nO=m.useState(0),nT=(0,a.Z)(nO,2),nL=nT[0],nD=nT[1],n_=nL>=nt.length-1||"horizontal"!==nN||eR;m.useEffect(function(){nM&&ng(np)},[np]),m.useEffect(function(){return nZ.current=!0,function(){nZ.current=!1}},[]);var nV=(g=m.useState({}),Z=(0,a.Z)(g,2)[1],C=(0,m.useRef)(new Map),E=(0,m.useRef)(new Map),M=m.useState([]),x=(R=(0,a.Z)(M,2))[0],S=R[1],I=(0,m.useRef)(0),K=(0,m.useRef)(!1),J=function(){K.current||Z({})},$=(0,m.useCallback)(function(e,n){var t,r=q(n);E.current.set(r,e),C.current.set(e,r),I.current+=1;var o=I.current;t=function(){o===I.current&&J()},Promise.resolve().then(t)},[]),ee=(0,m.useCallback)(function(e,n){var t=q(n);E.current.delete(t),C.current.delete(e)},[]),en=(0,m.useCallback)(function(e){S(e)},[]),et=(0,m.useCallback)(function(e,n){var t=(C.current.get(e)||"").split(Y);return n&&x.includes(t[0])&&t.unshift(X),t},[x]),er=(0,m.useCallback)(function(e,n){return e.filter(function(e){return void 0!==e}).some(function(e){return et(e,!0).includes(n)})},[et]),eo=(0,m.useCallback)(function(e){var n="".concat(C.current.get(e)).concat(Y),t=new Set;return(0,l.Z)(E.current.keys()).forEach(function(e){e.startsWith(n)&&t.add(E.current.get(e))}),t},[]),m.useEffect(function(){return function(){K.current=!0}},[]),{registerPath:$,unregisterPath:ee,refreshOverflowKeys:en,isSubPathKey:er,getKeyPath:et,getKeys:function(){var e=(0,l.Z)(C.current.keys());return x.length&&e.push(X),e},getSubPathKeys:eo}),nz=nV.registerPath,nF=nV.unregisterPath,nj=nV.refreshOverflowKeys,nB=nV.isSubPathKey,nW=nV.getKeyPath,nH=nV.getKeys,nY=nV.getSubPathKeys,nq=m.useMemo(function(){return{registerPath:nz,unregisterPath:nF}},[nz,nF]),nX=m.useMemo(function(){return{isSubPathKey:nB}},[nB]);m.useEffect(function(){nj(n_?ez:nt.slice(nL+1).map(function(e){return e.key}))},[nL,n_]);var nG=(0,d.Z)(eA||eO&&(null===(es=nt[0])||void 0===es?void 0:es.key),{value:eA}),nQ=(0,a.Z)(nG,2),nU=nQ[0],nJ=nQ[1],n$=G(function(e){nJ(e)}),n0=G(function(){nJ(void 0)});(0,m.useImperativeHandle)(n,function(){return{list:nu.current,focus:function(e){var n,t,r=H(nH(),nc),o=r.elements,i=r.key2element,l=r.element2key,a=B(nu.current,o),u=null!=nU?nU:a[0]?l.get(a[0]):null===(n=nt.find(function(e){return!e.props.disabled}))||void 0===n?void 0:n.key,c=i.get(u);u&&c&&(null==c||null===(t=c.focus)||void 0===t||t.call(c,e))}}});var n1=(0,d.Z)(ej||[],{value:eB,postState:function(e){return Array.isArray(e)?e:null==e?ez:[e]}}),n6=(0,a.Z)(n1,2),n2=n6[0],n5=n6[1],n9=function(e){if(eL){var n,t=e.key,r=n2.includes(t);n5(n=eF?r?n2.filter(function(e){return e!==t}):[].concat((0,l.Z)(n2),[t]):[t]);var o=(0,i.Z)((0,i.Z)({},e),{},{selectedKeys:n});r?null==eH||eH(o):null==eW||eW(o)}!eF&&np.length&&"inline"!==nN&&nm(ez)},n3=G(function(e){null==e2||e2(eu(e)),n9(e)}),n4=G(function(e,n){var t=np.filter(function(n){return n!==e});if(n)t.push(e);else if("inline"!==nN){var r=nY(e);t=t.filter(function(e){return!r.has(e)})}(0,p.Z)(np,t,!0)||nm(t,!0)}),n7=(ei=function(e,n){var t=null!=n?n:!np.includes(e);n4(e,t)},el=m.useRef(),(ea=m.useRef()).current=nU,ec=function(){A.Z.cancel(el.current)},m.useEffect(function(){return function(){ec()}},[]),function(e){var n=e.which;if([].concat(j,[_,V,z,F]).includes(n)){var t=nH(),r=H(t,nc),i=r,l=i.elements,a=i.key2element,u=i.element2key,c=function(e,n){for(var t=e||document.activeElement;t;){if(n.has(t))return t;t=t.parentElement}return null}(a.get(nU),l),s=u.get(c),f=function(e,n,t,r){var i,l="prev",a="next",u="children",c="parent";if("inline"===e&&r===_)return{inlineTrigger:!0};var s=(0,o.Z)((0,o.Z)({},L,l),D,a),f=(0,o.Z)((0,o.Z)((0,o.Z)((0,o.Z)({},O,t?a:l),T,t?l:a),D,u),_,u),d=(0,o.Z)((0,o.Z)((0,o.Z)((0,o.Z)((0,o.Z)((0,o.Z)({},L,l),D,a),_,u),V,c),O,t?u:c),T,t?c:u);switch(null===(i=({inline:s,horizontal:f,vertical:d,inlineSub:s,horizontalSub:d,verticalSub:d})["".concat(e).concat(n?"":"Sub")])||void 0===i?void 0:i[r]){case l:return{offset:-1,sibling:!0};case a:return{offset:1,sibling:!0};case c:return{offset:-1,sibling:!1};case u:return{offset:1,sibling:!1};default:return null}}(nN,1===nW(s,!0).length,ns,n);if(!f&&n!==z&&n!==F)return;(j.includes(n)||[z,F].includes(n))&&e.preventDefault();var d=function(e){if(e){var n=e,t=e.querySelector("a");null!=t&&t.getAttribute("href")&&(n=t);var r=u.get(e);nJ(r),ec(),el.current=(0,A.Z)(function(){ea.current===r&&n.focus()})}};if([z,F].includes(n)||f.sibling||!c){var p,v=B(p=c&&"inline"!==nN?function(e){for(var n=e;n;){if(n.getAttribute("data-menu-list"))return n;n=n.parentElement}return null}(c):nu.current,l);d(n===z?v[0]:n===F?v[v.length-1]:W(p,l,c,f.offset))}else if(f.inlineTrigger)ei(s);else if(f.offset>0)ei(s,!0),ec(),el.current=(0,A.Z)(function(){r=H(t,nc);var e=c.getAttribute("aria-controls");d(W(document.getElementById(e),r.elements))},5);else if(f.offset<0){var m=nW(s,!0),b=m[m.length-2],y=a.get(b);ei(b,!1),d(y)}}null==e9||e9(e)});m.useEffect(function(){na(!0)},[]);var n8=m.useMemo(function(){return{_internalRenderMenuItem:e3,_internalRenderSubMenuItem:e4}},[e3,e4]),te="horizontal"!==nN||eR?nt:nt.map(function(e,n){return m.createElement(w,{key:e.key,overflowDisabled:n>nL},e)}),tn=m.createElement(f.Z,(0,r.Z)({id:eC,ref:nu,prefixCls:"".concat(ed,"-overflow"),component:"ul",itemComponent:ev,className:s()(ed,"".concat(ed,"-root"),"".concat(ed,"-").concat(nN),eb,(0,o.Z)((0,o.Z)({},"".concat(ed,"-inline-collapsed"),nK),"".concat(ed,"-rtl"),ns),ep),dir:eZ,style:em,role:"menu",tabIndex:void 0===ey?0:ey,data:te,renderRawItem:function(e){return e},renderRawRest:function(e){var n=e.length,t=n?nt.slice(-n):null;return m.createElement(eI,{eventKey:X,title:e0,disabled:n_,internalPopupClose:0===n,popupClassName:e1},t)},maxCount:"horizontal"!==nN||eR?f.Z.INVALIDATE:f.Z.RESPONSIVE,ssr:"full","data-menu-list":!0,onVisibleChange:function(e){nD(e)},onKeyDown:n7},e8));return m.createElement(P.Provider,{value:n8},m.createElement(y.Provider,{value:nc},m.createElement(w,{prefixCls:ed,rootClassName:ep,mode:nN,openKeys:np,rtl:ns,disabled:eM,motion:nl?eq:null,defaultMotions:nl?eX:null,activeKey:nU,onActive:n$,onInactive:n0,selectedKeys:n2,inlineIndent:void 0===eY?24:eY,subMenuOpenDelay:void 0===ex?.1:ex,subMenuCloseDelay:void 0===eN?.1:eN,forceSubMenuRender:eP,builtinPlacements:eQ,triggerSubMenuAction:void 0===eG?"hover":eG,getPopupContainer:e6,itemIcon:eU,expandIcon:eJ,onItemClick:n3,onOpenChange:n4},m.createElement(N.Provider,{value:nX},tn),m.createElement("div",{style:{display:"none"},"aria-hidden":!0},m.createElement(k.Provider,{value:nq},nr)))))});eF.Item=ev,eF.SubMenu=eI,eF.ItemGroup=eL,eF.Divider=eA;var ej=eF}}]); \ No newline at end of file +"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1529],{60440:function(e,n,t){t.d(n,{Z:function(){return a}});var r=t(1119),o=t(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M176 511a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0z"}}]},name:"ellipsis",theme:"outlined"},l=t(55015),a=o.forwardRef(function(e,n){return o.createElement(l.Z,(0,r.Z)({},e,{ref:n,icon:i}))})},77565:function(e,n,t){t.d(n,{Z:function(){return a}});var r=t(1119),o=t(2265),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"}}]},name:"right",theme:"outlined"},l=t(55015),a=o.forwardRef(function(e,n){return o.createElement(l.Z,(0,r.Z)({},e,{ref:n,icon:i}))})},71030:function(e,n,t){t.d(n,{Z:function(){return C}});var r=t(1119),o=t(11993),i=t(26365),l=t(6989),a=t(97821),u=t(36760),c=t.n(u),s=t(28791),f=t(2265),d=t(95814),p=t(53346),v=d.Z.ESC,m=d.Z.TAB,b=(0,f.forwardRef)(function(e,n){var t=e.overlay,r=e.arrow,o=e.prefixCls,i=(0,f.useMemo)(function(){return"function"==typeof t?t():t},[t]),l=(0,s.sQ)(n,(0,s.C4)(i));return f.createElement(f.Fragment,null,r&&f.createElement("div",{className:"".concat(o,"-arrow")}),f.cloneElement(i,{ref:(0,s.Yr)(i)?l:void 0}))}),y={adjustX:1,adjustY:1},h=[0,0],g={topLeft:{points:["bl","tl"],overflow:y,offset:[0,-4],targetOffset:h},top:{points:["bc","tc"],overflow:y,offset:[0,-4],targetOffset:h},topRight:{points:["br","tr"],overflow:y,offset:[0,-4],targetOffset:h},bottomLeft:{points:["tl","bl"],overflow:y,offset:[0,4],targetOffset:h},bottom:{points:["tc","bc"],overflow:y,offset:[0,4],targetOffset:h},bottomRight:{points:["tr","br"],overflow:y,offset:[0,4],targetOffset:h}},Z=["arrow","prefixCls","transitionName","animation","align","placement","placements","getPopupContainer","showAction","hideAction","overlayClassName","overlayStyle","visible","trigger","autoFocus","overlay","children","onVisibleChange"],C=f.forwardRef(function(e,n){var t,u,d,y,h,C,E,w,k,M,R,x,N,P,S=e.arrow,I=void 0!==S&&S,K=e.prefixCls,A=void 0===K?"rc-dropdown":K,O=e.transitionName,T=e.animation,L=e.align,D=e.placement,_=e.placements,V=e.getPopupContainer,z=e.showAction,F=e.hideAction,j=e.overlayClassName,B=e.overlayStyle,W=e.visible,H=e.trigger,Y=void 0===H?["hover"]:H,q=e.autoFocus,X=e.overlay,G=e.children,Q=e.onVisibleChange,U=(0,l.Z)(e,Z),J=f.useState(),$=(0,i.Z)(J,2),ee=$[0],en=$[1],et="visible"in e?W:ee,er=f.useRef(null),eo=f.useRef(null),ei=f.useRef(null);f.useImperativeHandle(n,function(){return er.current});var el=function(e){en(e),null==Q||Q(e)};u=(t={visible:et,triggerRef:ei,onVisibleChange:el,autoFocus:q,overlayRef:eo}).visible,d=t.triggerRef,y=t.onVisibleChange,h=t.autoFocus,C=t.overlayRef,E=f.useRef(!1),w=function(){if(u){var e,n;null===(e=d.current)||void 0===e||null===(n=e.focus)||void 0===n||n.call(e),null==y||y(!1)}},k=function(){var e;return null!==(e=C.current)&&void 0!==e&&!!e.focus&&(C.current.focus(),E.current=!0,!0)},M=function(e){switch(e.keyCode){case v:w();break;case m:var n=!1;E.current||(n=k()),n?e.preventDefault():w()}},f.useEffect(function(){return u?(window.addEventListener("keydown",M),h&&(0,p.Z)(k,3),function(){window.removeEventListener("keydown",M),E.current=!1}):function(){E.current=!1}},[u]);var ea=function(){return f.createElement(b,{ref:eo,overlay:X,prefixCls:A,arrow:I})},eu=f.cloneElement(G,{className:c()(null===(P=G.props)||void 0===P?void 0:P.className,et&&(void 0!==(R=e.openClassName)?R:"".concat(A,"-open"))),ref:(0,s.Yr)(G)?(0,s.sQ)(ei,(0,s.C4)(G)):void 0}),ec=F;return ec||-1===Y.indexOf("contextMenu")||(ec=["click"]),f.createElement(a.Z,(0,r.Z)({builtinPlacements:void 0===_?g:_},U,{prefixCls:A,ref:er,popupClassName:c()(j,(0,o.Z)({},"".concat(A,"-show-arrow"),I)),popupStyle:B,action:Y,showAction:z,hideAction:ec,popupPlacement:void 0===D?"bottomLeft":D,popupAlign:L,popupTransitionName:O,popupAnimation:T,popupVisible:et,stretch:(x=e.minOverlayWidthMatchTrigger,N=e.alignPoint,"minOverlayWidthMatchTrigger"in e?x:!N)?"minWidth":"",popup:"function"==typeof X?ea:ea(),onPopupVisibleChange:el,onPopupClick:function(n){var t=e.onOverlayClick;en(!1),t&&t(n)},getPopupContainer:V}),eu)})},33082:function(e,n,t){t.d(n,{iz:function(){return eA},ck:function(){return ev},BW:function(){return eL},sN:function(){return ev},Wd:function(){return eI},ZP:function(){return ej},Xl:function(){return x}});var r=t(1119),o=t(11993),i=t(31686),l=t(83145),a=t(26365),u=t(6989),c=t(36760),s=t.n(c),f=t(1699),d=t(50506),p=t(16671),v=t(32559),m=t(2265),b=t(54887),y=m.createContext(null);function h(e,n){return void 0===e?null:"".concat(e,"-").concat(n)}function g(e){return h(m.useContext(y),e)}var Z=t(6397),C=["children","locked"],E=m.createContext(null);function w(e){var n=e.children,t=e.locked,r=(0,u.Z)(e,C),o=m.useContext(E),l=(0,Z.Z)(function(){var e;return e=(0,i.Z)({},o),Object.keys(r).forEach(function(n){var t=r[n];void 0!==t&&(e[n]=t)}),e},[o,r],function(e,n){return!t&&(e[0]!==n[0]||!(0,p.Z)(e[1],n[1],!0))});return m.createElement(E.Provider,{value:l},n)}var k=m.createContext(null);function M(){return m.useContext(k)}var R=m.createContext([]);function x(e){var n=m.useContext(R);return m.useMemo(function(){return void 0!==e?[].concat((0,l.Z)(n),[e]):n},[n,e])}var N=m.createContext(null),P=m.createContext({}),S=t(2857);function I(e){var n=arguments.length>1&&void 0!==arguments[1]&&arguments[1];if((0,S.Z)(e)){var t=e.nodeName.toLowerCase(),r=["input","select","textarea","button"].includes(t)||e.isContentEditable||"a"===t&&!!e.getAttribute("href"),o=e.getAttribute("tabindex"),i=Number(o),l=null;return o&&!Number.isNaN(i)?l=i:r&&null===l&&(l=0),r&&e.disabled&&(l=null),null!==l&&(l>=0||n&&l<0)}return!1}var K=t(95814),A=t(53346),O=K.Z.LEFT,T=K.Z.RIGHT,L=K.Z.UP,D=K.Z.DOWN,_=K.Z.ENTER,V=K.Z.ESC,z=K.Z.HOME,F=K.Z.END,j=[L,D,O,T];function B(e,n){return(function(e){var n=arguments.length>1&&void 0!==arguments[1]&&arguments[1],t=(0,l.Z)(e.querySelectorAll("*")).filter(function(e){return I(e,n)});return I(e,n)&&t.unshift(e),t})(e,!0).filter(function(e){return n.has(e)})}function W(e,n,t){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:1;if(!e)return null;var o=B(e,n),i=o.length,l=o.findIndex(function(e){return t===e});return r<0?-1===l?l=i-1:l-=1:r>0&&(l+=1),o[l=(l+i)%i]}var H=function(e,n){var t=new Set,r=new Map,o=new Map;return e.forEach(function(e){var i=document.querySelector("[data-menu-id='".concat(h(n,e),"']"));i&&(t.add(i),o.set(i,e),r.set(e,i))}),{elements:t,key2element:r,element2key:o}},Y="__RC_UTIL_PATH_SPLIT__",q=function(e){return e.join(Y)},X="rc-menu-more";function G(e){var n=m.useRef(e);n.current=e;var t=m.useCallback(function(){for(var e,t=arguments.length,r=Array(t),o=0;o1&&(k.motionAppear=!1);var M=k.onVisibleChanged;return(k.onVisibleChanged=function(e){return b.current||e||Z(!0),null==M?void 0:M(e)},g)?null:m.createElement(w,{mode:u,locked:!b.current},m.createElement(eR.ZP,(0,r.Z)({visible:C},k,{forceRender:f,removeOnLeave:!1,leavedClassName:"".concat(s,"-hidden")}),function(e){var t=e.className,r=e.style;return m.createElement(eb,{id:n,className:t,style:r},l)}))}var eN=["style","className","title","eventKey","warnKey","disabled","internalPopupClose","children","itemIcon","expandIcon","popupClassName","popupOffset","popupStyle","onClick","onMouseEnter","onMouseLeave","onTitleClick","onTitleMouseEnter","onTitleMouseLeave"],eP=["active"],eS=m.forwardRef(function(e,n){var t=e.style,l=e.className,c=e.title,d=e.eventKey,p=(e.warnKey,e.disabled),v=e.internalPopupClose,b=e.children,y=e.itemIcon,h=e.expandIcon,Z=e.popupClassName,C=e.popupOffset,k=e.popupStyle,M=e.onClick,R=e.onMouseEnter,S=e.onMouseLeave,I=e.onTitleClick,K=e.onTitleMouseEnter,A=e.onTitleMouseLeave,O=(0,u.Z)(e,eN),T=g(d),L=m.useContext(E),D=L.prefixCls,_=L.mode,V=L.openKeys,z=L.disabled,F=L.overflowDisabled,j=L.activeKey,B=L.selectedKeys,W=L.itemIcon,H=L.expandIcon,Y=L.onItemClick,q=L.onOpenChange,X=L.onActive,Q=m.useContext(P)._internalRenderSubMenuItem,U=m.useContext(N).isSubPathKey,J=x(),$="".concat(D,"-submenu"),ee=z||p,en=m.useRef(),et=m.useRef(),er=null!=h?h:H,ea=V.includes(d),ec=!F&&ea,es=U(B,d),ef=eo(d,ee,K,A),ed=ef.active,ep=(0,u.Z)(ef,eP),ev=m.useState(!1),em=(0,a.Z)(ev,2),ey=em[0],eh=em[1],eg=function(e){ee||eh(e)},eZ=m.useMemo(function(){return ed||"inline"!==_&&(ey||U([j],d))},[_,ed,j,ey,d,U]),eC=ei(J.length),eE=G(function(e){null==M||M(eu(e)),Y(e)}),ew=T&&"".concat(T,"-popup"),ek=m.useMemo(function(){return m.createElement(el,{icon:"horizontal"!==_?er:void 0,props:(0,i.Z)((0,i.Z)({},e),{},{isOpen:ec,isSubMenu:!0})},m.createElement("i",{className:"".concat($,"-arrow")}))},[_,er,e,ec,$]),eR=m.createElement("div",(0,r.Z)({role:"menuitem",style:eC,className:"".concat($,"-title"),tabIndex:ee?null:-1,ref:en,title:"string"==typeof c?c:null,"data-menu-id":F&&T?null:T,"aria-expanded":ec,"aria-haspopup":!0,"aria-controls":ew,"aria-disabled":ee,onClick:function(e){ee||(null==I||I({key:d,domEvent:e}),"inline"===_&&q(d,!ea))},onFocus:function(){X(d)}},ep),c,ek),eS=m.useRef(_);if("inline"!==_&&J.length>1?eS.current="vertical":eS.current=_,!F){var eI=eS.current;eR=m.createElement(eM,{mode:eI,prefixCls:$,visible:!v&&ec&&"inline"!==_,popupClassName:Z,popupOffset:C,popupStyle:k,popup:m.createElement(w,{mode:"horizontal"===eI?"vertical":eI},m.createElement(eb,{id:ew,ref:et},b)),disabled:ee,onVisibleChange:function(e){"inline"!==_&&q(d,e)}},eR)}var eK=m.createElement(f.Z.Item,(0,r.Z)({ref:n,role:"none"},O,{component:"li",style:t,className:s()($,"".concat($,"-").concat(_),l,(0,o.Z)((0,o.Z)((0,o.Z)((0,o.Z)({},"".concat($,"-open"),ec),"".concat($,"-active"),eZ),"".concat($,"-selected"),es),"".concat($,"-disabled"),ee)),onMouseEnter:function(e){eg(!0),null==R||R({key:d,domEvent:e})},onMouseLeave:function(e){eg(!1),null==S||S({key:d,domEvent:e})}}),eR,!F&&m.createElement(ex,{id:ew,open:ec,keyPath:J},b));return Q&&(eK=Q(eK,e,{selected:es,active:eZ,open:ec,disabled:ee})),m.createElement(w,{onItemClick:eE,mode:"horizontal"===_?"vertical":_,itemIcon:null!=y?y:W,expandIcon:er},eK)}),eI=m.forwardRef(function(e,n){var t,o=e.eventKey,i=e.children,l=x(o),a=eh(i,l),u=M();return m.useEffect(function(){if(u)return u.registerPath(o,l),function(){u.unregisterPath(o,l)}},[l]),t=u?a:m.createElement(eS,(0,r.Z)({ref:n},e),a),m.createElement(R.Provider,{value:l},t)}),eK=t(41154);function eA(e){var n=e.className,t=e.style,r=m.useContext(E).prefixCls;return M()?null:m.createElement("li",{role:"separator",className:s()("".concat(r,"-item-divider"),n),style:t})}var eO=["className","title","eventKey","children"],eT=m.forwardRef(function(e,n){var t=e.className,o=e.title,i=(e.eventKey,e.children),l=(0,u.Z)(e,eO),a=m.useContext(E).prefixCls,c="".concat(a,"-item-group");return m.createElement("li",(0,r.Z)({ref:n,role:"presentation"},l,{onClick:function(e){return e.stopPropagation()},className:s()(c,t)}),m.createElement("div",{role:"presentation",className:"".concat(c,"-title"),title:"string"==typeof o?o:void 0},o),m.createElement("ul",{role:"group",className:"".concat(c,"-list")},i))}),eL=m.forwardRef(function(e,n){var t=e.eventKey,o=eh(e.children,x(t));return M()?o:m.createElement(eT,(0,r.Z)({ref:n},(0,et.Z)(e,["warnKey"])),o)}),eD=["label","children","key","type","extra"];function e_(e,n,t,o,l){var a=e,c=(0,i.Z)({divider:eA,item:ev,group:eL,submenu:eI},o);return n&&(a=function e(n,t,o){var i=t.item,l=t.group,a=t.submenu,c=t.divider;return(n||[]).map(function(n,s){if(n&&"object"===(0,eK.Z)(n)){var f=n.label,d=n.children,p=n.key,v=n.type,b=n.extra,y=(0,u.Z)(n,eD),h=null!=p?p:"tmp-".concat(s);return d||"group"===v?"group"===v?m.createElement(l,(0,r.Z)({key:h},y,{title:f}),e(d,t,o)):m.createElement(a,(0,r.Z)({key:h},y,{title:f}),e(d,t,o)):"divider"===v?m.createElement(c,(0,r.Z)({key:h},y)):m.createElement(i,(0,r.Z)({key:h},y,{extra:b}),f,(!!b||0===b)&&m.createElement("span",{className:"".concat(o,"-item-extra")},b))}return null}).filter(function(e){return e})}(n,c,l)),eh(a,t)}var eV=["prefixCls","rootClassName","style","className","tabIndex","items","children","direction","id","mode","inlineCollapsed","disabled","disabledOverflow","subMenuOpenDelay","subMenuCloseDelay","forceSubMenuRender","defaultOpenKeys","openKeys","activeKey","defaultActiveFirst","selectable","multiple","defaultSelectedKeys","selectedKeys","onSelect","onDeselect","inlineIndent","motion","defaultMotions","triggerSubMenuAction","builtinPlacements","itemIcon","expandIcon","overflowedIndicator","overflowedIndicatorPopupClassName","getPopupContainer","onClick","onOpenChange","onKeyDown","openAnimation","openTransitionName","_internalRenderMenuItem","_internalRenderSubMenuItem","_internalComponents"],ez=[],eF=m.forwardRef(function(e,n){var t,c,v,h,g,Z,C,E,M,R,x,S,I,K,J,$,ee,en,et,er,eo,ei,el,ea,ec,es,ef=e.prefixCls,ed=void 0===ef?"rc-menu":ef,ep=e.rootClassName,em=e.style,eb=e.className,ey=e.tabIndex,eh=e.items,eg=e.children,eZ=e.direction,eC=e.id,eE=e.mode,ew=void 0===eE?"vertical":eE,ek=e.inlineCollapsed,eM=e.disabled,eR=e.disabledOverflow,ex=e.subMenuOpenDelay,eN=e.subMenuCloseDelay,eP=e.forceSubMenuRender,eS=e.defaultOpenKeys,eK=e.openKeys,eA=e.activeKey,eO=e.defaultActiveFirst,eT=e.selectable,eL=void 0===eT||eT,eD=e.multiple,eF=void 0!==eD&&eD,ej=e.defaultSelectedKeys,eB=e.selectedKeys,eW=e.onSelect,eH=e.onDeselect,eY=e.inlineIndent,eq=e.motion,eX=e.defaultMotions,eG=e.triggerSubMenuAction,eQ=e.builtinPlacements,eU=e.itemIcon,eJ=e.expandIcon,e$=e.overflowedIndicator,e0=void 0===e$?"...":e$,e1=e.overflowedIndicatorPopupClassName,e6=e.getPopupContainer,e2=e.onClick,e5=e.onOpenChange,e9=e.onKeyDown,e3=(e.openAnimation,e.openTransitionName,e._internalRenderMenuItem),e4=e._internalRenderSubMenuItem,e7=e._internalComponents,e8=(0,u.Z)(e,eV),ne=m.useMemo(function(){return[e_(eg,eh,ez,e7,ed),e_(eg,eh,ez,{},ed)]},[eg,eh,e7]),nn=(0,a.Z)(ne,2),nt=nn[0],nr=nn[1],no=m.useState(!1),ni=(0,a.Z)(no,2),nl=ni[0],na=ni[1],nu=m.useRef(),nc=(t=(0,d.Z)(eC,{value:eC}),v=(c=(0,a.Z)(t,2))[0],h=c[1],m.useEffect(function(){U+=1;var e="".concat(Q,"-").concat(U);h("rc-menu-uuid-".concat(e))},[]),v),ns="rtl"===eZ,nf=(0,d.Z)(eS,{value:eK,postState:function(e){return e||ez}}),nd=(0,a.Z)(nf,2),np=nd[0],nv=nd[1],nm=function(e){var n=arguments.length>1&&void 0!==arguments[1]&&arguments[1];function t(){nv(e),null==e5||e5(e)}n?(0,b.flushSync)(t):t()},nb=m.useState(np),ny=(0,a.Z)(nb,2),nh=ny[0],ng=ny[1],nZ=m.useRef(!1),nC=m.useMemo(function(){return("inline"===ew||"vertical"===ew)&&ek?["vertical",ek]:[ew,!1]},[ew,ek]),nE=(0,a.Z)(nC,2),nw=nE[0],nk=nE[1],nM="inline"===nw,nR=m.useState(nw),nx=(0,a.Z)(nR,2),nN=nx[0],nP=nx[1],nS=m.useState(nk),nI=(0,a.Z)(nS,2),nK=nI[0],nA=nI[1];m.useEffect(function(){nP(nw),nA(nk),nZ.current&&(nM?nv(nh):nm(ez))},[nw,nk]);var nO=m.useState(0),nT=(0,a.Z)(nO,2),nL=nT[0],nD=nT[1],n_=nL>=nt.length-1||"horizontal"!==nN||eR;m.useEffect(function(){nM&&ng(np)},[np]),m.useEffect(function(){return nZ.current=!0,function(){nZ.current=!1}},[]);var nV=(g=m.useState({}),Z=(0,a.Z)(g,2)[1],C=(0,m.useRef)(new Map),E=(0,m.useRef)(new Map),M=m.useState([]),x=(R=(0,a.Z)(M,2))[0],S=R[1],I=(0,m.useRef)(0),K=(0,m.useRef)(!1),J=function(){K.current||Z({})},$=(0,m.useCallback)(function(e,n){var t,r=q(n);E.current.set(r,e),C.current.set(e,r),I.current+=1;var o=I.current;t=function(){o===I.current&&J()},Promise.resolve().then(t)},[]),ee=(0,m.useCallback)(function(e,n){var t=q(n);E.current.delete(t),C.current.delete(e)},[]),en=(0,m.useCallback)(function(e){S(e)},[]),et=(0,m.useCallback)(function(e,n){var t=(C.current.get(e)||"").split(Y);return n&&x.includes(t[0])&&t.unshift(X),t},[x]),er=(0,m.useCallback)(function(e,n){return e.filter(function(e){return void 0!==e}).some(function(e){return et(e,!0).includes(n)})},[et]),eo=(0,m.useCallback)(function(e){var n="".concat(C.current.get(e)).concat(Y),t=new Set;return(0,l.Z)(E.current.keys()).forEach(function(e){e.startsWith(n)&&t.add(E.current.get(e))}),t},[]),m.useEffect(function(){return function(){K.current=!0}},[]),{registerPath:$,unregisterPath:ee,refreshOverflowKeys:en,isSubPathKey:er,getKeyPath:et,getKeys:function(){var e=(0,l.Z)(C.current.keys());return x.length&&e.push(X),e},getSubPathKeys:eo}),nz=nV.registerPath,nF=nV.unregisterPath,nj=nV.refreshOverflowKeys,nB=nV.isSubPathKey,nW=nV.getKeyPath,nH=nV.getKeys,nY=nV.getSubPathKeys,nq=m.useMemo(function(){return{registerPath:nz,unregisterPath:nF}},[nz,nF]),nX=m.useMemo(function(){return{isSubPathKey:nB}},[nB]);m.useEffect(function(){nj(n_?ez:nt.slice(nL+1).map(function(e){return e.key}))},[nL,n_]);var nG=(0,d.Z)(eA||eO&&(null===(es=nt[0])||void 0===es?void 0:es.key),{value:eA}),nQ=(0,a.Z)(nG,2),nU=nQ[0],nJ=nQ[1],n$=G(function(e){nJ(e)}),n0=G(function(){nJ(void 0)});(0,m.useImperativeHandle)(n,function(){return{list:nu.current,focus:function(e){var n,t,r=H(nH(),nc),o=r.elements,i=r.key2element,l=r.element2key,a=B(nu.current,o),u=null!=nU?nU:a[0]?l.get(a[0]):null===(n=nt.find(function(e){return!e.props.disabled}))||void 0===n?void 0:n.key,c=i.get(u);u&&c&&(null==c||null===(t=c.focus)||void 0===t||t.call(c,e))}}});var n1=(0,d.Z)(ej||[],{value:eB,postState:function(e){return Array.isArray(e)?e:null==e?ez:[e]}}),n6=(0,a.Z)(n1,2),n2=n6[0],n5=n6[1],n9=function(e){if(eL){var n,t=e.key,r=n2.includes(t);n5(n=eF?r?n2.filter(function(e){return e!==t}):[].concat((0,l.Z)(n2),[t]):[t]);var o=(0,i.Z)((0,i.Z)({},e),{},{selectedKeys:n});r?null==eH||eH(o):null==eW||eW(o)}!eF&&np.length&&"inline"!==nN&&nm(ez)},n3=G(function(e){null==e2||e2(eu(e)),n9(e)}),n4=G(function(e,n){var t=np.filter(function(n){return n!==e});if(n)t.push(e);else if("inline"!==nN){var r=nY(e);t=t.filter(function(e){return!r.has(e)})}(0,p.Z)(np,t,!0)||nm(t,!0)}),n7=(ei=function(e,n){var t=null!=n?n:!np.includes(e);n4(e,t)},el=m.useRef(),(ea=m.useRef()).current=nU,ec=function(){A.Z.cancel(el.current)},m.useEffect(function(){return function(){ec()}},[]),function(e){var n=e.which;if([].concat(j,[_,V,z,F]).includes(n)){var t=nH(),r=H(t,nc),i=r,l=i.elements,a=i.key2element,u=i.element2key,c=function(e,n){for(var t=e||document.activeElement;t;){if(n.has(t))return t;t=t.parentElement}return null}(a.get(nU),l),s=u.get(c),f=function(e,n,t,r){var i,l="prev",a="next",u="children",c="parent";if("inline"===e&&r===_)return{inlineTrigger:!0};var s=(0,o.Z)((0,o.Z)({},L,l),D,a),f=(0,o.Z)((0,o.Z)((0,o.Z)((0,o.Z)({},O,t?a:l),T,t?l:a),D,u),_,u),d=(0,o.Z)((0,o.Z)((0,o.Z)((0,o.Z)((0,o.Z)((0,o.Z)({},L,l),D,a),_,u),V,c),O,t?u:c),T,t?c:u);switch(null===(i=({inline:s,horizontal:f,vertical:d,inlineSub:s,horizontalSub:d,verticalSub:d})["".concat(e).concat(n?"":"Sub")])||void 0===i?void 0:i[r]){case l:return{offset:-1,sibling:!0};case a:return{offset:1,sibling:!0};case c:return{offset:-1,sibling:!1};case u:return{offset:1,sibling:!1};default:return null}}(nN,1===nW(s,!0).length,ns,n);if(!f&&n!==z&&n!==F)return;(j.includes(n)||[z,F].includes(n))&&e.preventDefault();var d=function(e){if(e){var n=e,t=e.querySelector("a");null!=t&&t.getAttribute("href")&&(n=t);var r=u.get(e);nJ(r),ec(),el.current=(0,A.Z)(function(){ea.current===r&&n.focus()})}};if([z,F].includes(n)||f.sibling||!c){var p,v=B(p=c&&"inline"!==nN?function(e){for(var n=e;n;){if(n.getAttribute("data-menu-list"))return n;n=n.parentElement}return null}(c):nu.current,l);d(n===z?v[0]:n===F?v[v.length-1]:W(p,l,c,f.offset))}else if(f.inlineTrigger)ei(s);else if(f.offset>0)ei(s,!0),ec(),el.current=(0,A.Z)(function(){r=H(t,nc);var e=c.getAttribute("aria-controls");d(W(document.getElementById(e),r.elements))},5);else if(f.offset<0){var m=nW(s,!0),b=m[m.length-2],y=a.get(b);ei(b,!1),d(y)}}null==e9||e9(e)});m.useEffect(function(){na(!0)},[]);var n8=m.useMemo(function(){return{_internalRenderMenuItem:e3,_internalRenderSubMenuItem:e4}},[e3,e4]),te="horizontal"!==nN||eR?nt:nt.map(function(e,n){return m.createElement(w,{key:e.key,overflowDisabled:n>nL},e)}),tn=m.createElement(f.Z,(0,r.Z)({id:eC,ref:nu,prefixCls:"".concat(ed,"-overflow"),component:"ul",itemComponent:ev,className:s()(ed,"".concat(ed,"-root"),"".concat(ed,"-").concat(nN),eb,(0,o.Z)((0,o.Z)({},"".concat(ed,"-inline-collapsed"),nK),"".concat(ed,"-rtl"),ns),ep),dir:eZ,style:em,role:"menu",tabIndex:void 0===ey?0:ey,data:te,renderRawItem:function(e){return e},renderRawRest:function(e){var n=e.length,t=n?nt.slice(-n):null;return m.createElement(eI,{eventKey:X,title:e0,disabled:n_,internalPopupClose:0===n,popupClassName:e1},t)},maxCount:"horizontal"!==nN||eR?f.Z.INVALIDATE:f.Z.RESPONSIVE,ssr:"full","data-menu-list":!0,onVisibleChange:function(e){nD(e)},onKeyDown:n7},e8));return m.createElement(P.Provider,{value:n8},m.createElement(y.Provider,{value:nc},m.createElement(w,{prefixCls:ed,rootClassName:ep,mode:nN,openKeys:np,rtl:ns,disabled:eM,motion:nl?eq:null,defaultMotions:nl?eX:null,activeKey:nU,onActive:n$,onInactive:n0,selectedKeys:n2,inlineIndent:void 0===eY?24:eY,subMenuOpenDelay:void 0===ex?.1:ex,subMenuCloseDelay:void 0===eN?.1:eN,forceSubMenuRender:eP,builtinPlacements:eQ,triggerSubMenuAction:void 0===eG?"hover":eG,getPopupContainer:e6,itemIcon:eU,expandIcon:eJ,onItemClick:n3,onOpenChange:n4},m.createElement(N.Provider,{value:nX},tn),m.createElement("div",{style:{display:"none"},"aria-hidden":!0},m.createElement(k.Provider,{value:nq},nr)))))});eF.Item=ev,eF.SubMenu=eI,eF.ItemGroup=eL,eF.Divider=eA;var ej=eF}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/1674-475a971a192714f2.js b/litellm/proxy/_experimental/out/_next/static/chunks/1674-de8248fbd0c554ba.js similarity index 99% rename from litellm/proxy/_experimental/out/_next/static/chunks/1674-475a971a192714f2.js rename to litellm/proxy/_experimental/out/_next/static/chunks/1674-de8248fbd0c554ba.js index cd70c451170..e8fa6e80e42 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/1674-475a971a192714f2.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/1674-de8248fbd0c554ba.js @@ -1 +1 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1674],{14042:function(e,t,n){"use strict";n.d(t,{Z:function(){return eM}});var r=n(5853),o=n(7084),i=n(26898),a=n(13241),c=n(1153),l=n(2265),s=n(60474),u=n(47625),p=n(93765),f=n(86757),d=n.n(f),y=n(61994),m=n(9841),v=n(81889),h=n(82944),b=["points","className","baseLinePoints","connectNulls"];function g(){return(g=Object.assign?Object.assign.bind():function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:[],t=[[]];return e.forEach(function(e){k(e)?t[t.length-1].push(e):t[t.length-1].length>0&&t.push([])}),k(e[0])&&t[t.length-1].push(e[0]),t[t.length-1].length<=0&&(t=t.slice(0,-1)),t},j=function(e,t){var n=x(e);t&&(n=[n.reduce(function(e,t){return[].concat(A(e),A(t))},[])]);var r=n.map(function(e){return e.reduce(function(e,t,n){return"".concat(e).concat(0===n?"M":"L").concat(t.x,",").concat(t.y)},"")}).join("");return 1===n.length?"".concat(r,"Z"):r},w=function(e,t,n){var r=j(e,n);return"".concat("Z"===r.slice(-1)?r.slice(0,-1):r,"L").concat(j(t.reverse(),n).slice(1))},P=function(e){var t=e.points,n=e.className,r=e.baseLinePoints,o=e.connectNulls,i=function(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n={};for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r)){if(t.indexOf(r)>=0)continue;n[r]=e[r]}return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}(e,b);if(!t||!t.length)return null;var a=(0,y.Z)("recharts-polygon",n);if(r&&r.length){var c=i.stroke&&"none"!==i.stroke,s=w(t,r,o);return l.createElement("g",{className:a},l.createElement("path",g({},(0,h.L6)(i,!0),{fill:"Z"===s.slice(-1)?i.fill:"none",stroke:"none",d:s})),c?l.createElement("path",g({},(0,h.L6)(i,!0),{fill:"none",d:j(t,o)})):null,c?l.createElement("path",g({},(0,h.L6)(i,!0),{fill:"none",d:j(r,o)})):null)}var u=j(t,o);return l.createElement("path",g({},(0,h.L6)(i,!0),{fill:"Z"===u.slice(-1)?i.fill:"none",className:a,d:u}))},E=n(58811),S=n(41637),T=n(39206);function L(e){return(L="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function R(){return(R=Object.assign?Object.assign.bind():function(e){for(var t=1;t1e-5?"outer"===t?"start":"end":n<-.00001?"outer"===t?"end":"start":"middle"}},{key:"renderAxisLine",value:function(){var e=this.props,t=e.cx,n=e.cy,r=e.radius,o=e.axisLine,i=e.axisLineType,a=I(I({},(0,h.L6)(this.props,!1)),{},{fill:"none"},(0,h.L6)(o,!1));if("circle"===i)return l.createElement(v.o,R({className:"recharts-polar-angle-axis-line"},a,{cx:t,cy:n,r:r}));var c=this.props.ticks.map(function(e){return(0,T.op)(t,n,r,e.coordinate)});return l.createElement(P,R({className:"recharts-polar-angle-axis-line"},a,{points:c}))}},{key:"renderTicks",value:function(){var e=this,t=this.props,n=t.ticks,o=t.tick,i=t.tickLine,a=t.tickFormatter,c=t.stroke,s=(0,h.L6)(this.props,!1),u=(0,h.L6)(o,!1),p=I(I({},s),{},{fill:"none"},(0,h.L6)(i,!1)),f=n.map(function(t,n){var f=e.getTickLineCoord(t),d=I(I(I({textAnchor:e.getTickTextAnchor(t)},s),{},{stroke:"none",fill:c},u),{},{index:n,payload:t,x:f.x2,y:f.y2});return l.createElement(m.m,R({className:(0,y.Z)("recharts-polar-angle-axis-tick",(0,T.$S)(o)),key:"tick-".concat(t.coordinate)},(0,S.bw)(e.props,t,n)),i&&l.createElement("line",R({className:"recharts-polar-angle-axis-tick-line"},p,f)),o&&r.renderTickItem(o,d,a?a(t.value,n):t.value))});return l.createElement(m.m,{className:"recharts-polar-angle-axis-ticks"},f)}},{key:"render",value:function(){var e=this.props,t=e.ticks,n=e.radius,r=e.axisLine;return!(n<=0)&&t&&t.length?l.createElement(m.m,{className:(0,y.Z)("recharts-polar-angle-axis",this.props.className)},r&&this.renderAxisLine(),this.renderTicks()):null}}],n=[{key:"renderTickItem",value:function(e,t,n){return l.isValidElement(e)?l.cloneElement(e,t):d()(e)?e(t):l.createElement(E.x,R({},t,{className:"recharts-polar-angle-axis-tick-value"}),n)}}],t&&C(r.prototype,t),n&&C(r,n),Object.defineProperty(r,"prototype",{writable:!1}),r}(l.PureComponent);Z(M,"displayName","PolarAngleAxis"),Z(M,"axisType","angleAxis"),Z(M,"defaultProps",{type:"category",angleAxisId:0,scale:"auto",cx:0,cy:0,orientation:"outer",axisLine:!0,tickLine:!0,tickSize:8,tick:!0,hide:!1,allowDuplicatedCategory:!0});var V=n(35802),$=n.n(V),q=n(37891),z=n.n(q),G=n(26680),W=["cx","cy","angle","ticks","axisLine"],Y=["ticks","tick","angle","tickFormatter","stroke"];function H(e){return(H="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function U(){return(U=Object.assign?Object.assign.bind():function(e){for(var t=1;t=0)continue;n[r]=e[r]}return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function ee(e,t){for(var n=0;n0?es()(e,"paddingAngle",0):0;if(n){var c=(0,eb.k4)(n.endAngle-n.startAngle,e.endAngle-e.startAngle),l=ew(ew({},e),{},{startAngle:i+a,endAngle:i+c(r)+a});o.push(l),i=l.endAngle}else{var s=e.endAngle,p=e.startAngle,f=(0,eb.k4)(0,s-p)(r),d=ew(ew({},e),{},{startAngle:i+a,endAngle:i+f+a});o.push(d),i=d.endAngle}}),l.createElement(m.m,null,e.renderSectorsStatically(o))})}},{key:"attachKeyboardHandlers",value:function(e){var t=this;e.onkeydown=function(e){if(!e.altKey)switch(e.key){case"ArrowLeft":var n=++t.state.sectorToFocus%t.sectorRefs.length;t.sectorRefs[n].focus(),t.setState({sectorToFocus:n});break;case"ArrowRight":var r=--t.state.sectorToFocus<0?t.sectorRefs.length-1:t.state.sectorToFocus%t.sectorRefs.length;t.sectorRefs[r].focus(),t.setState({sectorToFocus:r});break;case"Escape":t.sectorRefs[t.state.sectorToFocus].blur(),t.setState({sectorToFocus:0})}}}},{key:"renderSectors",value:function(){var e=this.props,t=e.sectors,n=e.isAnimationActive,r=this.state.prevSectors;return n&&t&&t.length&&(!r||!ep()(r,t))?this.renderSectorsWithAnimation():this.renderSectorsStatically(t)}},{key:"componentDidMount",value:function(){this.pieRef&&this.attachKeyboardHandlers(this.pieRef)}},{key:"render",value:function(){var e=this,t=this.props,n=t.hide,r=t.sectors,o=t.className,i=t.label,a=t.cx,c=t.cy,s=t.innerRadius,u=t.outerRadius,p=t.isAnimationActive,f=this.state.isAnimationFinished;if(n||!r||!r.length||!(0,eb.hj)(a)||!(0,eb.hj)(c)||!(0,eb.hj)(s)||!(0,eb.hj)(u))return null;var d=(0,y.Z)("recharts-pie",o);return l.createElement(m.m,{tabIndex:this.props.rootTabIndex,className:d,ref:function(t){e.pieRef=t}},this.renderSectors(),i&&this.renderLabels(r),G._.renderCallByParent(this.props,null,!1),(!p||f)&&em.e.renderCallByParent(this.props,r,!1))}}],n=[{key:"getDerivedStateFromProps",value:function(e,t){return t.prevIsAnimationActive!==e.isAnimationActive?{prevIsAnimationActive:e.isAnimationActive,prevAnimationId:e.animationId,curSectors:e.sectors,prevSectors:[],isAnimationFinished:!0}:e.isAnimationActive&&e.animationId!==t.prevAnimationId?{prevAnimationId:e.animationId,curSectors:e.sectors,prevSectors:t.curSectors,isAnimationFinished:!0}:e.sectors!==t.curSectors?{curSectors:e.sectors,isAnimationFinished:!0}:null}},{key:"getTextAnchor",value:function(e,t){return e>t?"start":e=360?A:A-1)*u,k=a.reduce(function(e,t){var n=(0,eg.F$)(t,g,0);return e+((0,eb.hj)(n)?n:0)},0);return k>0&&(t=a.map(function(e,t){var r,o=(0,eg.F$)(e,g,0),i=(0,eg.F$)(e,f,t),a=((0,eb.hj)(o)?o:0)/k,s=(r=t?n.endAngle+(0,eb.uY)(h)*u*(0!==o?1:0):l)+(0,eb.uY)(h)*((0!==o?m:0)+a*O),p=(r+s)/2,d=(v.innerRadius+v.outerRadius)/2,b=[{name:i,value:o,payload:e,dataKey:g,type:y}],A=(0,T.op)(v.cx,v.cy,d,p);return n=ew(ew(ew({percent:a,cornerRadius:c,name:i,tooltipPayload:b,midAngle:p,middleRadius:d,tooltipPosition:A},e),v),{},{value:(0,eg.F$)(e,g),startAngle:r,endAngle:s,payload:e,paddingAngle:(0,eb.uY)(h)*u})})),ew(ew({},v),{},{sectors:t,data:a})});var eI=(0,p.z)({chartName:"PieChart",GraphicalChild:eN,validateTooltipEventTypes:["item"],defaultTooltipEventType:"item",legendContent:"children",axisComponents:[{axisType:"angleAxis",AxisComp:M},{axisType:"radiusAxis",AxisComp:ea}],formatAxisMap:T.t9,defaultProps:{layout:"centric",startAngle:0,endAngle:360,cx:"50%",cy:"50%",innerRadius:0,outerRadius:"80%"}}),eC=n(8147),eD=n(92666),eF=n(98593);let e_=e=>{let{active:t,payload:n,valueFormatter:r}=e;if(t&&(null==n?void 0:n[0])){let e=null==n?void 0:n[0];return l.createElement(eF.$B,null,l.createElement("div",{className:(0,a.q)("px-4 py-2")},l.createElement(eF.zX,{value:r(e.value),name:e.name,color:e.payload.color})))}return null},eZ=(e,t)=>e.map((e,n)=>{let r=ne||t((0,c.vP)(n.map(e=>e[r]))),eK=e=>{let{cx:t,cy:n,innerRadius:r,outerRadius:o,startAngle:i,endAngle:a,className:c}=e;return l.createElement("g",null,l.createElement(s.L,{cx:t,cy:n,innerRadius:r,outerRadius:o,startAngle:i,endAngle:a,className:c,fill:"",opacity:.3,style:{outline:"none"}}))},eM=l.forwardRef((e,t)=>{let{data:n=[],category:s="value",index:p="name",colors:f=i.s,variant:d="donut",valueFormatter:y=c.Cj,label:m,showLabel:v=!0,animationDuration:h=900,showAnimation:b=!1,showTooltip:g=!0,noDataText:A,onValueChange:O,customTooltip:k,className:x}=e,j=(0,r._T)(e,["data","category","index","colors","variant","valueFormatter","label","showLabel","animationDuration","showAnimation","showTooltip","noDataText","onValueChange","customTooltip","className"]),w="donut"==d,P=eB(m,y,n,s),[E,S]=l.useState(void 0),T=!!O;return(0,l.useEffect)(()=>{let e=document.querySelectorAll(".recharts-pie-sector");e&&e.forEach(e=>{e.setAttribute("style","outline: none")})},[E]),l.createElement("div",Object.assign({ref:t,className:(0,a.q)("w-full h-40",x)},j),l.createElement(u.h,{className:"h-full w-full"},(null==n?void 0:n.length)?l.createElement(eI,{onClick:T&&E?()=>{S(void 0),null==O||O(null)}:void 0,margin:{top:0,left:0,right:0,bottom:0}},v&&w?l.createElement("text",{className:(0,a.q)("fill-tremor-content-emphasis","dark:fill-dark-tremor-content-emphasis"),x:"50%",y:"50%",textAnchor:"middle",dominantBaseline:"middle"},P):null,l.createElement(eN,{className:(0,a.q)("stroke-tremor-background dark:stroke-dark-tremor-background",O?"cursor-pointer":"cursor-default"),data:eZ(n,f),cx:"50%",cy:"50%",startAngle:90,endAngle:-270,innerRadius:w?"75%":"0%",outerRadius:"100%",stroke:"",strokeLinejoin:"round",dataKey:s,nameKey:p,isAnimationActive:b,animationDuration:h,onClick:function(e,t,n){n.stopPropagation(),T&&(E===t?(S(void 0),null==O||O(null)):(S(t),null==O||O(Object.assign({eventType:"slice"},e.payload.payload))))},activeIndex:E,inactiveShape:eK,style:{outline:"none"}}),l.createElement(eC.u,{wrapperStyle:{outline:"none"},isAnimationActive:!1,content:g?e=>{var t;let{active:n,payload:r}=e;return k?l.createElement(k,{payload:null==r?void 0:r.map(e=>{var t,n,i;return Object.assign(Object.assign({},e),{color:null!==(i=null===(n=null===(t=null==r?void 0:r[0])||void 0===t?void 0:t.payload)||void 0===n?void 0:n.color)&&void 0!==i?i:o.fr.Gray})}),active:n,label:null===(t=null==r?void 0:r[0])||void 0===t?void 0:t.name}):l.createElement(e_,{active:n,payload:r,valueFormatter:y})}:l.createElement(l.Fragment,null)})):l.createElement(eD.Z,{noDataText:A})))});eM.displayName="DonutChart"},35802:function(e,t,n){var r=n(67646),o=n(58905),i=n(88157);e.exports=function(e,t){return e&&e.length?r(e,i(t,2),o):void 0}},37891:function(e,t,n){var r=n(67646),o=n(88157),i=n(20121);e.exports=function(e,t){return e&&e.length?r(e,o(t,2),i):void 0}},44633:function(e,t,n){"use strict";var r=n(2265);let o=r.forwardRef(function(e,t){return r.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:2,stroke:"currentColor","aria-hidden":"true",ref:t},e),r.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 15l7-7 7 7"}))});t.Z=o},58710:function(e,t,n){"use strict";var r=n(2265);let o=r.forwardRef(function(e,t){return r.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:2,stroke:"currentColor","aria-hidden":"true",ref:t},e),r.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"}))});t.Z=o},92668:function(e,t,n){"use strict";n.d(t,{I:function(){return c}});var r=n(59121),o=n(31091),i=n(63497),a=n(99649);function c(e,t){let{years:n=0,months:c=0,weeks:l=0,days:s=0,hours:u=0,minutes:p=0,seconds:f=0}=t,d=(0,a.Q)(e),y=c||n?(0,o.z)(d,c+12*n):d,m=s||l?(0,r.E)(y,s+7*l):y;return(0,i.L)(e,m.getTime()+1e3*(f+60*(p+60*u)))}}}]); \ No newline at end of file +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1674],{14042:function(e,t,n){"use strict";n.d(t,{Z:function(){return eM}});var r=n(5853),o=n(7084),i=n(26898),a=n(13241),c=n(1153),l=n(2265),s=n(60474),u=n(47625),p=n(93765),f=n(86757),d=n.n(f),y=n(87602),m=n(9841),v=n(81889),h=n(82944),b=["points","className","baseLinePoints","connectNulls"];function g(){return(g=Object.assign?Object.assign.bind():function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:[],t=[[]];return e.forEach(function(e){k(e)?t[t.length-1].push(e):t[t.length-1].length>0&&t.push([])}),k(e[0])&&t[t.length-1].push(e[0]),t[t.length-1].length<=0&&(t=t.slice(0,-1)),t},j=function(e,t){var n=x(e);t&&(n=[n.reduce(function(e,t){return[].concat(A(e),A(t))},[])]);var r=n.map(function(e){return e.reduce(function(e,t,n){return"".concat(e).concat(0===n?"M":"L").concat(t.x,",").concat(t.y)},"")}).join("");return 1===n.length?"".concat(r,"Z"):r},w=function(e,t,n){var r=j(e,n);return"".concat("Z"===r.slice(-1)?r.slice(0,-1):r,"L").concat(j(t.reverse(),n).slice(1))},P=function(e){var t=e.points,n=e.className,r=e.baseLinePoints,o=e.connectNulls,i=function(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n={};for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r)){if(t.indexOf(r)>=0)continue;n[r]=e[r]}return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}(e,b);if(!t||!t.length)return null;var a=(0,y.Z)("recharts-polygon",n);if(r&&r.length){var c=i.stroke&&"none"!==i.stroke,s=w(t,r,o);return l.createElement("g",{className:a},l.createElement("path",g({},(0,h.L6)(i,!0),{fill:"Z"===s.slice(-1)?i.fill:"none",stroke:"none",d:s})),c?l.createElement("path",g({},(0,h.L6)(i,!0),{fill:"none",d:j(t,o)})):null,c?l.createElement("path",g({},(0,h.L6)(i,!0),{fill:"none",d:j(r,o)})):null)}var u=j(t,o);return l.createElement("path",g({},(0,h.L6)(i,!0),{fill:"Z"===u.slice(-1)?i.fill:"none",className:a,d:u}))},E=n(58811),S=n(41637),T=n(39206);function L(e){return(L="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function R(){return(R=Object.assign?Object.assign.bind():function(e){for(var t=1;t1e-5?"outer"===t?"start":"end":n<-.00001?"outer"===t?"end":"start":"middle"}},{key:"renderAxisLine",value:function(){var e=this.props,t=e.cx,n=e.cy,r=e.radius,o=e.axisLine,i=e.axisLineType,a=I(I({},(0,h.L6)(this.props,!1)),{},{fill:"none"},(0,h.L6)(o,!1));if("circle"===i)return l.createElement(v.o,R({className:"recharts-polar-angle-axis-line"},a,{cx:t,cy:n,r:r}));var c=this.props.ticks.map(function(e){return(0,T.op)(t,n,r,e.coordinate)});return l.createElement(P,R({className:"recharts-polar-angle-axis-line"},a,{points:c}))}},{key:"renderTicks",value:function(){var e=this,t=this.props,n=t.ticks,o=t.tick,i=t.tickLine,a=t.tickFormatter,c=t.stroke,s=(0,h.L6)(this.props,!1),u=(0,h.L6)(o,!1),p=I(I({},s),{},{fill:"none"},(0,h.L6)(i,!1)),f=n.map(function(t,n){var f=e.getTickLineCoord(t),d=I(I(I({textAnchor:e.getTickTextAnchor(t)},s),{},{stroke:"none",fill:c},u),{},{index:n,payload:t,x:f.x2,y:f.y2});return l.createElement(m.m,R({className:(0,y.Z)("recharts-polar-angle-axis-tick",(0,T.$S)(o)),key:"tick-".concat(t.coordinate)},(0,S.bw)(e.props,t,n)),i&&l.createElement("line",R({className:"recharts-polar-angle-axis-tick-line"},p,f)),o&&r.renderTickItem(o,d,a?a(t.value,n):t.value))});return l.createElement(m.m,{className:"recharts-polar-angle-axis-ticks"},f)}},{key:"render",value:function(){var e=this.props,t=e.ticks,n=e.radius,r=e.axisLine;return!(n<=0)&&t&&t.length?l.createElement(m.m,{className:(0,y.Z)("recharts-polar-angle-axis",this.props.className)},r&&this.renderAxisLine(),this.renderTicks()):null}}],n=[{key:"renderTickItem",value:function(e,t,n){return l.isValidElement(e)?l.cloneElement(e,t):d()(e)?e(t):l.createElement(E.x,R({},t,{className:"recharts-polar-angle-axis-tick-value"}),n)}}],t&&C(r.prototype,t),n&&C(r,n),Object.defineProperty(r,"prototype",{writable:!1}),r}(l.PureComponent);Z(M,"displayName","PolarAngleAxis"),Z(M,"axisType","angleAxis"),Z(M,"defaultProps",{type:"category",angleAxisId:0,scale:"auto",cx:0,cy:0,orientation:"outer",axisLine:!0,tickLine:!0,tickSize:8,tick:!0,hide:!1,allowDuplicatedCategory:!0});var V=n(35802),$=n.n(V),q=n(37891),z=n.n(q),G=n(26680),W=["cx","cy","angle","ticks","axisLine"],Y=["ticks","tick","angle","tickFormatter","stroke"];function H(e){return(H="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function U(){return(U=Object.assign?Object.assign.bind():function(e){for(var t=1;t=0)continue;n[r]=e[r]}return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function ee(e,t){for(var n=0;n0?es()(e,"paddingAngle",0):0;if(n){var c=(0,eb.k4)(n.endAngle-n.startAngle,e.endAngle-e.startAngle),l=ew(ew({},e),{},{startAngle:i+a,endAngle:i+c(r)+a});o.push(l),i=l.endAngle}else{var s=e.endAngle,p=e.startAngle,f=(0,eb.k4)(0,s-p)(r),d=ew(ew({},e),{},{startAngle:i+a,endAngle:i+f+a});o.push(d),i=d.endAngle}}),l.createElement(m.m,null,e.renderSectorsStatically(o))})}},{key:"attachKeyboardHandlers",value:function(e){var t=this;e.onkeydown=function(e){if(!e.altKey)switch(e.key){case"ArrowLeft":var n=++t.state.sectorToFocus%t.sectorRefs.length;t.sectorRefs[n].focus(),t.setState({sectorToFocus:n});break;case"ArrowRight":var r=--t.state.sectorToFocus<0?t.sectorRefs.length-1:t.state.sectorToFocus%t.sectorRefs.length;t.sectorRefs[r].focus(),t.setState({sectorToFocus:r});break;case"Escape":t.sectorRefs[t.state.sectorToFocus].blur(),t.setState({sectorToFocus:0})}}}},{key:"renderSectors",value:function(){var e=this.props,t=e.sectors,n=e.isAnimationActive,r=this.state.prevSectors;return n&&t&&t.length&&(!r||!ep()(r,t))?this.renderSectorsWithAnimation():this.renderSectorsStatically(t)}},{key:"componentDidMount",value:function(){this.pieRef&&this.attachKeyboardHandlers(this.pieRef)}},{key:"render",value:function(){var e=this,t=this.props,n=t.hide,r=t.sectors,o=t.className,i=t.label,a=t.cx,c=t.cy,s=t.innerRadius,u=t.outerRadius,p=t.isAnimationActive,f=this.state.isAnimationFinished;if(n||!r||!r.length||!(0,eb.hj)(a)||!(0,eb.hj)(c)||!(0,eb.hj)(s)||!(0,eb.hj)(u))return null;var d=(0,y.Z)("recharts-pie",o);return l.createElement(m.m,{tabIndex:this.props.rootTabIndex,className:d,ref:function(t){e.pieRef=t}},this.renderSectors(),i&&this.renderLabels(r),G._.renderCallByParent(this.props,null,!1),(!p||f)&&em.e.renderCallByParent(this.props,r,!1))}}],n=[{key:"getDerivedStateFromProps",value:function(e,t){return t.prevIsAnimationActive!==e.isAnimationActive?{prevIsAnimationActive:e.isAnimationActive,prevAnimationId:e.animationId,curSectors:e.sectors,prevSectors:[],isAnimationFinished:!0}:e.isAnimationActive&&e.animationId!==t.prevAnimationId?{prevAnimationId:e.animationId,curSectors:e.sectors,prevSectors:t.curSectors,isAnimationFinished:!0}:e.sectors!==t.curSectors?{curSectors:e.sectors,isAnimationFinished:!0}:null}},{key:"getTextAnchor",value:function(e,t){return e>t?"start":e=360?A:A-1)*u,k=a.reduce(function(e,t){var n=(0,eg.F$)(t,g,0);return e+((0,eb.hj)(n)?n:0)},0);return k>0&&(t=a.map(function(e,t){var r,o=(0,eg.F$)(e,g,0),i=(0,eg.F$)(e,f,t),a=((0,eb.hj)(o)?o:0)/k,s=(r=t?n.endAngle+(0,eb.uY)(h)*u*(0!==o?1:0):l)+(0,eb.uY)(h)*((0!==o?m:0)+a*O),p=(r+s)/2,d=(v.innerRadius+v.outerRadius)/2,b=[{name:i,value:o,payload:e,dataKey:g,type:y}],A=(0,T.op)(v.cx,v.cy,d,p);return n=ew(ew(ew({percent:a,cornerRadius:c,name:i,tooltipPayload:b,midAngle:p,middleRadius:d,tooltipPosition:A},e),v),{},{value:(0,eg.F$)(e,g),startAngle:r,endAngle:s,payload:e,paddingAngle:(0,eb.uY)(h)*u})})),ew(ew({},v),{},{sectors:t,data:a})});var eI=(0,p.z)({chartName:"PieChart",GraphicalChild:eN,validateTooltipEventTypes:["item"],defaultTooltipEventType:"item",legendContent:"children",axisComponents:[{axisType:"angleAxis",AxisComp:M},{axisType:"radiusAxis",AxisComp:ea}],formatAxisMap:T.t9,defaultProps:{layout:"centric",startAngle:0,endAngle:360,cx:"50%",cy:"50%",innerRadius:0,outerRadius:"80%"}}),eC=n(8147),eD=n(92666),eF=n(98593);let e_=e=>{let{active:t,payload:n,valueFormatter:r}=e;if(t&&(null==n?void 0:n[0])){let e=null==n?void 0:n[0];return l.createElement(eF.$B,null,l.createElement("div",{className:(0,a.q)("px-4 py-2")},l.createElement(eF.zX,{value:r(e.value),name:e.name,color:e.payload.color})))}return null},eZ=(e,t)=>e.map((e,n)=>{let r=ne||t((0,c.vP)(n.map(e=>e[r]))),eK=e=>{let{cx:t,cy:n,innerRadius:r,outerRadius:o,startAngle:i,endAngle:a,className:c}=e;return l.createElement("g",null,l.createElement(s.L,{cx:t,cy:n,innerRadius:r,outerRadius:o,startAngle:i,endAngle:a,className:c,fill:"",opacity:.3,style:{outline:"none"}}))},eM=l.forwardRef((e,t)=>{let{data:n=[],category:s="value",index:p="name",colors:f=i.s,variant:d="donut",valueFormatter:y=c.Cj,label:m,showLabel:v=!0,animationDuration:h=900,showAnimation:b=!1,showTooltip:g=!0,noDataText:A,onValueChange:O,customTooltip:k,className:x}=e,j=(0,r._T)(e,["data","category","index","colors","variant","valueFormatter","label","showLabel","animationDuration","showAnimation","showTooltip","noDataText","onValueChange","customTooltip","className"]),w="donut"==d,P=eB(m,y,n,s),[E,S]=l.useState(void 0),T=!!O;return(0,l.useEffect)(()=>{let e=document.querySelectorAll(".recharts-pie-sector");e&&e.forEach(e=>{e.setAttribute("style","outline: none")})},[E]),l.createElement("div",Object.assign({ref:t,className:(0,a.q)("w-full h-40",x)},j),l.createElement(u.h,{className:"h-full w-full"},(null==n?void 0:n.length)?l.createElement(eI,{onClick:T&&E?()=>{S(void 0),null==O||O(null)}:void 0,margin:{top:0,left:0,right:0,bottom:0}},v&&w?l.createElement("text",{className:(0,a.q)("fill-tremor-content-emphasis","dark:fill-dark-tremor-content-emphasis"),x:"50%",y:"50%",textAnchor:"middle",dominantBaseline:"middle"},P):null,l.createElement(eN,{className:(0,a.q)("stroke-tremor-background dark:stroke-dark-tremor-background",O?"cursor-pointer":"cursor-default"),data:eZ(n,f),cx:"50%",cy:"50%",startAngle:90,endAngle:-270,innerRadius:w?"75%":"0%",outerRadius:"100%",stroke:"",strokeLinejoin:"round",dataKey:s,nameKey:p,isAnimationActive:b,animationDuration:h,onClick:function(e,t,n){n.stopPropagation(),T&&(E===t?(S(void 0),null==O||O(null)):(S(t),null==O||O(Object.assign({eventType:"slice"},e.payload.payload))))},activeIndex:E,inactiveShape:eK,style:{outline:"none"}}),l.createElement(eC.u,{wrapperStyle:{outline:"none"},isAnimationActive:!1,content:g?e=>{var t;let{active:n,payload:r}=e;return k?l.createElement(k,{payload:null==r?void 0:r.map(e=>{var t,n,i;return Object.assign(Object.assign({},e),{color:null!==(i=null===(n=null===(t=null==r?void 0:r[0])||void 0===t?void 0:t.payload)||void 0===n?void 0:n.color)&&void 0!==i?i:o.fr.Gray})}),active:n,label:null===(t=null==r?void 0:r[0])||void 0===t?void 0:t.name}):l.createElement(e_,{active:n,payload:r,valueFormatter:y})}:l.createElement(l.Fragment,null)})):l.createElement(eD.Z,{noDataText:A})))});eM.displayName="DonutChart"},35802:function(e,t,n){var r=n(67646),o=n(58905),i=n(88157);e.exports=function(e,t){return e&&e.length?r(e,i(t,2),o):void 0}},37891:function(e,t,n){var r=n(67646),o=n(88157),i=n(20121);e.exports=function(e,t){return e&&e.length?r(e,o(t,2),i):void 0}},44633:function(e,t,n){"use strict";var r=n(2265);let o=r.forwardRef(function(e,t){return r.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:2,stroke:"currentColor","aria-hidden":"true",ref:t},e),r.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 15l7-7 7 7"}))});t.Z=o},58710:function(e,t,n){"use strict";var r=n(2265);let o=r.forwardRef(function(e,t){return r.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:2,stroke:"currentColor","aria-hidden":"true",ref:t},e),r.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"}))});t.Z=o},92668:function(e,t,n){"use strict";n.d(t,{I:function(){return c}});var r=n(59121),o=n(31091),i=n(63497),a=n(99649);function c(e,t){let{years:n=0,months:c=0,weeks:l=0,days:s=0,hours:u=0,minutes:p=0,seconds:f=0}=t,d=(0,a.Q)(e),y=c||n?(0,o.z)(d,c+12*n):d,m=s||l?(0,r.E)(y,s+7*l):y;return(0,i.L)(e,m.getTime()+1e3*(f+60*(p+60*u)))}}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/1973-26a414084f96c69b.js b/litellm/proxy/_experimental/out/_next/static/chunks/1973-26a414084f96c69b.js new file mode 100644 index 00000000000..8ba0b21bc05 --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/1973-26a414084f96c69b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1973],{83669:function(e,t,n){n.d(t,{Z:function(){return l}});var a=n(1119),c=n(2265),o={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M699 353h-46.9c-10.2 0-19.9 4.9-25.9 13.3L469 584.3l-71.2-98.8c-6-8.3-15.6-13.3-25.9-13.3H325c-6.5 0-10.3 7.4-6.5 12.7l124.6 172.8a31.8 31.8 0 0051.7 0l210.6-292c3.9-5.3.1-12.7-6.4-12.7z"}},{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"}}]},name:"check-circle",theme:"outlined"},r=n(55015),l=c.forwardRef(function(e,t){return c.createElement(r.Z,(0,a.Z)({},e,{ref:t,icon:o}))})},5540:function(e,t,n){n.d(t,{Z:function(){return l}});var a=n(1119),c=n(2265),o={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"}},{tag:"path",attrs:{d:"M686.7 638.6L544.1 535.5V288c0-4.4-3.6-8-8-8H488c-4.4 0-8 3.6-8 8v275.4c0 2.6 1.2 5 3.3 6.5l165.4 120.6c3.6 2.6 8.6 1.8 11.2-1.7l28.6-39c2.6-3.7 1.8-8.7-1.8-11.2z"}}]},name:"clock-circle",theme:"outlined"},r=n(55015),l=c.forwardRef(function(e,t){return c.createElement(r.Z,(0,a.Z)({},e,{ref:t,icon:o}))})},41169:function(e,t,n){n.d(t,{Z:function(){return l}});var a=n(1119),c=n(2265),o={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 472a40 40 0 1080 0 40 40 0 10-80 0zm367 352.9L696.3 352V178H768v-68H256v68h71.7v174L145 824.9c-2.8 7.4-4.3 15.2-4.3 23.1 0 35.3 28.7 64 64 64h614.6c7.9 0 15.7-1.5 23.1-4.3 33-12.7 49.4-49.8 36.6-82.8zM395.7 364.7V180h232.6v184.7L719.2 600c-20.7-5.3-42.1-8-63.9-8-61.2 0-119.2 21.5-165.3 60a188.78 188.78 0 01-121.3 43.9c-32.7 0-64.1-8.3-91.8-23.7l118.8-307.5zM210.5 844l41.7-107.8c35.7 18.1 75.4 27.8 116.6 27.8 61.2 0 119.2-21.5 165.3-60 33.9-28.2 76.3-43.9 121.3-43.9 35 0 68.4 9.5 97.6 27.1L813.5 844h-603z"}}]},name:"experiment",theme:"outlined"},r=n(55015),l=c.forwardRef(function(e,t){return c.createElement(r.Z,(0,a.Z)({},e,{ref:t,icon:o}))})},10798:function(e,t,n){n.d(t,{Z:function(){return l}});var a=n(1119),c=n(2265),o={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M880.1 154H143.9c-24.5 0-39.8 26.7-27.5 48L349 597.4V838c0 17.7 14.2 32 31.8 32h262.4c17.6 0 31.8-14.3 31.8-32V597.4L907.7 202c12.2-21.3-3.1-48-27.6-48zM603.4 798H420.6V642h182.9v156zm9.6-236.6l-9.5 16.6h-183l-9.5-16.6L212.7 226h598.6L613 561.4z"}}]},name:"filter",theme:"outlined"},r=n(55015),l=c.forwardRef(function(e,t){return c.createElement(r.Z,(0,a.Z)({},e,{ref:t,icon:o}))})},8881:function(e,t,n){n.d(t,{Z:function(){return l}});var a=n(1119),c=n(2265),o={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372 0-89 31.3-170.8 83.5-234.8l523.3 523.3C682.8 852.7 601 884 512 884zm288.5-137.2L277.2 223.5C341.2 171.3 423 140 512 140c205.4 0 372 166.6 372 372 0 89-31.3 170.8-83.5 234.8z"}}]},name:"stop",theme:"outlined"},r=n(55015),l=c.forwardRef(function(e,t){return c.createElement(r.Z,(0,a.Z)({},e,{ref:t,icon:o}))})},3632:function(e,t,n){n.d(t,{Z:function(){return l}});var a=n(1119),c=n(2265),o={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"}}]},name:"upload",theme:"outlined"},r=n(55015),l=c.forwardRef(function(e,t){return c.createElement(r.Z,(0,a.Z)({},e,{ref:t,icon:o}))})},30150:function(e,t,n){n.d(t,{Z:function(){return u}});var a=n(5853),c=n(2265);let o=e=>{var t=(0,a._T)(e,[]);return c.createElement("svg",Object.assign({},t,{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:"2.5"}),c.createElement("path",{d:"M12 4v16m8-8H4"}))},r=e=>{var t=(0,a._T)(e,[]);return c.createElement("svg",Object.assign({},t,{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:"2.5"}),c.createElement("path",{d:"M20 12H4"}))};var l=n(13241),i=n(1153),s=n(69262);let d="flex mx-auto text-tremor-content-subtle dark:text-dark-tremor-content-subtle",m="cursor-pointer hover:text-tremor-content dark:hover:text-dark-tremor-content",u=c.forwardRef((e,t)=>{let{onSubmit:n,enableStepper:u=!0,disabled:g,onValueChange:p,onChange:f}=e,h=(0,a._T)(e,["onSubmit","enableStepper","disabled","onValueChange","onChange"]),v=(0,c.useRef)(null),[b,x]=c.useState(!1),y=c.useCallback(()=>{x(!0)},[]),k=c.useCallback(()=>{x(!1)},[]),[S,w]=c.useState(!1),E=c.useCallback(()=>{w(!0)},[]),C=c.useCallback(()=>{w(!1)},[]);return c.createElement(s.Z,Object.assign({type:"number",ref:(0,i.lq)([v,t]),disabled:g,makeInputClassName:(0,i.fn)("NumberInput"),onKeyDown:e=>{var t;if("Enter"===e.key&&!e.ctrlKey&&!e.altKey&&!e.shiftKey){let e=null===(t=v.current)||void 0===t?void 0:t.value;null==n||n(parseFloat(null!=e?e:""))}"ArrowDown"===e.key&&y(),"ArrowUp"===e.key&&E()},onKeyUp:e=>{"ArrowDown"===e.key&&k(),"ArrowUp"===e.key&&C()},onChange:e=>{g||(null==p||p(parseFloat(e.target.value)),null==f||f(e))},stepper:u?c.createElement("div",{className:(0,l.q)("flex justify-center align-middle")},c.createElement("div",{tabIndex:-1,onClick:e=>e.preventDefault(),onMouseDown:e=>e.preventDefault(),onTouchStart:e=>{e.cancelable&&e.preventDefault()},onMouseUp:()=>{var e,t;g||(null===(e=v.current)||void 0===e||e.stepDown(),null===(t=v.current)||void 0===t||t.dispatchEvent(new Event("input",{bubbles:!0})))},className:(0,l.q)(!g&&m,d,"group py-[10px] px-2.5 border-l border-tremor-border dark:border-dark-tremor-border")},c.createElement(r,{"data-testid":"step-down",className:(b?"scale-95":"")+" h-4 w-4 duration-75 transition group-active:scale-95"})),c.createElement("div",{tabIndex:-1,onClick:e=>e.preventDefault(),onMouseDown:e=>e.preventDefault(),onTouchStart:e=>{e.cancelable&&e.preventDefault()},onMouseUp:()=>{var e,t;g||(null===(e=v.current)||void 0===e||e.stepUp(),null===(t=v.current)||void 0===t||t.dispatchEvent(new Event("input",{bubbles:!0})))},className:(0,l.q)(!g&&m,d,"group py-[10px] px-2.5 border-l border-tremor-border dark:border-dark-tremor-border")},c.createElement(o,{"data-testid":"step-up",className:(S?"scale-95":"")+" h-4 w-4 duration-75 transition group-active:scale-95"}))):null},h))});u.displayName="NumberInput"},16853:function(e,t,n){n.d(t,{Z:function(){return d}});var a=n(5853),c=n(96398),o=n(44140),r=n(2265),l=n(13241),i=n(1153);let s=(0,i.fn)("Textarea"),d=r.forwardRef((e,t)=>{let{value:n,defaultValue:d="",placeholder:m="Type...",error:u=!1,errorMessage:g,disabled:p=!1,className:f,onChange:h,onValueChange:v,autoHeight:b=!1}=e,x=(0,a._T)(e,["value","defaultValue","placeholder","error","errorMessage","disabled","className","onChange","onValueChange","autoHeight"]),[y,k]=(0,o.Z)(d,n),S=(0,r.useRef)(null),w=(0,c.Uh)(y);return(0,r.useEffect)(()=>{let e=S.current;if(b&&e){e.style.height="60px";let t=e.scrollHeight;e.style.height=t+"px"}},[b,S,y]),r.createElement(r.Fragment,null,r.createElement("textarea",Object.assign({ref:(0,i.lq)([S,t]),value:y,placeholder:m,disabled:p,className:(0,l.q)(s("Textarea"),"w-full flex items-center outline-none rounded-tremor-default px-3 py-2 text-tremor-default focus:ring-2 transition duration-100 border","shadow-tremor-input focus:border-tremor-brand-subtle focus:ring-tremor-brand-muted","dark:shadow-dark-tremor-input focus:dark:border-dark-tremor-brand-subtle focus:dark:ring-dark-tremor-brand-muted",(0,c.um)(w,p,u),p?"placeholder:text-tremor-content-subtle dark:placeholder:text-dark-tremor-content-subtle":"placeholder:text-tremor-content dark:placeholder:text-dark-tremor-content",f),"data-testid":"text-area",onChange:e=>{null==h||h(e),k(e.target.value),null==v||v(e.target.value)}},x)),u&&g?r.createElement("p",{className:(0,l.q)(s("errorMessage"),"text-sm text-red-500 mt-1")},g):null)});d.displayName="Textarea"},67101:function(e,t,n){n.d(t,{Z:function(){return d}});var a=n(5853),c=n(13241),o=n(1153),r=n(2265),l=n(9496);let i=(0,o.fn)("Grid"),s=(e,t)=>e&&Object.keys(t).includes(String(e))?t[e]:"",d=r.forwardRef((e,t)=>{let{numItems:n=1,numItemsSm:o,numItemsMd:d,numItemsLg:m,children:u,className:g}=e,p=(0,a._T)(e,["numItems","numItemsSm","numItemsMd","numItemsLg","children","className"]),f=s(n,l._m),h=s(o,l.LH),v=s(d,l.l5),b=s(m,l.N4),x=(0,c.q)(f,h,v,b);return r.createElement("div",Object.assign({ref:t,className:(0,c.q)(i("root"),"grid",x,g)},p),u)});d.displayName="Grid"},9496:function(e,t,n){n.d(t,{LH:function(){return c},N4:function(){return r},PT:function(){return l},SP:function(){return i},VS:function(){return s},_m:function(){return a},_w:function(){return d},l5:function(){return o}});let a={0:"grid-cols-none",1:"grid-cols-1",2:"grid-cols-2",3:"grid-cols-3",4:"grid-cols-4",5:"grid-cols-5",6:"grid-cols-6",7:"grid-cols-7",8:"grid-cols-8",9:"grid-cols-9",10:"grid-cols-10",11:"grid-cols-11",12:"grid-cols-12"},c={0:"sm:grid-cols-none",1:"sm:grid-cols-1",2:"sm:grid-cols-2",3:"sm:grid-cols-3",4:"sm:grid-cols-4",5:"sm:grid-cols-5",6:"sm:grid-cols-6",7:"sm:grid-cols-7",8:"sm:grid-cols-8",9:"sm:grid-cols-9",10:"sm:grid-cols-10",11:"sm:grid-cols-11",12:"sm:grid-cols-12"},o={0:"md:grid-cols-none",1:"md:grid-cols-1",2:"md:grid-cols-2",3:"md:grid-cols-3",4:"md:grid-cols-4",5:"md:grid-cols-5",6:"md:grid-cols-6",7:"md:grid-cols-7",8:"md:grid-cols-8",9:"md:grid-cols-9",10:"md:grid-cols-10",11:"md:grid-cols-11",12:"md:grid-cols-12"},r={0:"lg:grid-cols-none",1:"lg:grid-cols-1",2:"lg:grid-cols-2",3:"lg:grid-cols-3",4:"lg:grid-cols-4",5:"lg:grid-cols-5",6:"lg:grid-cols-6",7:"lg:grid-cols-7",8:"lg:grid-cols-8",9:"lg:grid-cols-9",10:"lg:grid-cols-10",11:"lg:grid-cols-11",12:"lg:grid-cols-12"},l={1:"col-span-1",2:"col-span-2",3:"col-span-3",4:"col-span-4",5:"col-span-5",6:"col-span-6",7:"col-span-7",8:"col-span-8",9:"col-span-9",10:"col-span-10",11:"col-span-11",12:"col-span-12",13:"col-span-13"},i={1:"sm:col-span-1",2:"sm:col-span-2",3:"sm:col-span-3",4:"sm:col-span-4",5:"sm:col-span-5",6:"sm:col-span-6",7:"sm:col-span-7",8:"sm:col-span-8",9:"sm:col-span-9",10:"sm:col-span-10",11:"sm:col-span-11",12:"sm:col-span-12",13:"sm:col-span-13"},s={1:"md:col-span-1",2:"md:col-span-2",3:"md:col-span-3",4:"md:col-span-4",5:"md:col-span-5",6:"md:col-span-6",7:"md:col-span-7",8:"md:col-span-8",9:"md:col-span-9",10:"md:col-span-10",11:"md:col-span-11",12:"md:col-span-12",13:"md:col-span-13"},d={1:"lg:col-span-1",2:"lg:col-span-2",3:"lg:col-span-3",4:"lg:col-span-4",5:"lg:col-span-5",6:"lg:col-span-6",7:"lg:col-span-7",8:"lg:col-span-8",9:"lg:col-span-9",10:"lg:col-span-10",11:"lg:col-span-11",12:"lg:col-span-12",13:"lg:col-span-13"}},44140:function(e,t,n){n.d(t,{Z:function(){return c}});var a=n(2265);let c=(e,t)=>{let n=void 0!==t,[c,o]=(0,a.useState)(e);return[n?t:c,e=>{n||o(e)}]}},35631:function(e,t,n){n.d(t,{Z:function(){return I}});var a=n(83145),c=n(2265),o=n(36760),r=n.n(o),l=n(53253),i=n(6543),s=n(71744),d=n(91086),m=n(33759),u=n(77774),g=n(28617),p=n(40049),f=n(10353);let h=c.createContext({});h.Consumer;var v=n(19722),b=n(54998),x=function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var c=0,a=Object.getOwnPropertySymbols(e);ct.indexOf(a[c])&&Object.prototype.propertyIsEnumerable.call(e,a[c])&&(n[a[c]]=e[a[c]]);return n};let y=c.forwardRef((e,t)=>{let n;let{prefixCls:a,children:o,actions:l,extra:i,styles:d,className:m,classNames:u,colStyle:g}=e,p=x(e,["prefixCls","children","actions","extra","styles","className","classNames","colStyle"]),{grid:f,itemLayout:y}=(0,c.useContext)(h),{getPrefixCls:k,list:S}=(0,c.useContext)(s.E_),w=e=>{var t,n;return r()(null===(n=null===(t=null==S?void 0:S.item)||void 0===t?void 0:t.classNames)||void 0===n?void 0:n[e],null==u?void 0:u[e])},E=e=>{var t,n;return Object.assign(Object.assign({},null===(n=null===(t=null==S?void 0:S.item)||void 0===t?void 0:t.styles)||void 0===n?void 0:n[e]),null==d?void 0:d[e])},C=k("list",a),N=l&&l.length>0&&c.createElement("ul",{className:r()("".concat(C,"-item-action"),w("actions")),key:"actions",style:E("actions")},l.map((e,t)=>c.createElement("li",{key:"".concat(C,"-item-action-").concat(t)},e,t!==l.length-1&&c.createElement("em",{className:"".concat(C,"-item-action-split")})))),z=c.createElement(f?"div":"li",Object.assign({},p,f?{}:{ref:t},{className:r()("".concat(C,"-item"),{["".concat(C,"-item-no-flex")]:!("vertical"===y?!!i:(n=!1,c.Children.forEach(o,e=>{"string"==typeof e&&(n=!0)}),!(n&&c.Children.count(o)>1)))},m)}),"vertical"===y&&i?[c.createElement("div",{className:"".concat(C,"-item-main"),key:"content"},o,N),c.createElement("div",{className:r()("".concat(C,"-item-extra"),w("extra")),key:"extra",style:E("extra")},i)]:[o,N,(0,v.Tm)(i,{key:"extra"})]);return f?c.createElement(b.Z,{ref:t,flex:1,style:g},z):z});y.Meta=e=>{var{prefixCls:t,className:n,avatar:a,title:o,description:l}=e,i=x(e,["prefixCls","className","avatar","title","description"]);let{getPrefixCls:d}=(0,c.useContext)(s.E_),m=d("list",t),u=r()("".concat(m,"-item-meta"),n),g=c.createElement("div",{className:"".concat(m,"-item-meta-content")},o&&c.createElement("h4",{className:"".concat(m,"-item-meta-title")},o),l&&c.createElement("div",{className:"".concat(m,"-item-meta-description")},l));return c.createElement("div",Object.assign({},i,{className:u}),a&&c.createElement("div",{className:"".concat(m,"-item-meta-avatar")},a),(o||l)&&g)};var k=n(93463),S=n(12918),w=n(99320),E=n(71140);let C=e=>{let{listBorderedCls:t,componentCls:n,paddingLG:a,margin:c,itemPaddingSM:o,itemPaddingLG:r,marginLG:l,borderRadiusLG:i}=e,s=(0,k.bf)(e.calc(i).sub(e.lineWidth).equal());return{[t]:{border:"".concat((0,k.bf)(e.lineWidth)," ").concat(e.lineType," ").concat(e.colorBorder),borderRadius:i,["".concat(n,"-header")]:{borderRadius:"".concat(s," ").concat(s," 0 0")},["".concat(n,"-footer")]:{borderRadius:"0 0 ".concat(s," ").concat(s)},["".concat(n,"-header,").concat(n,"-footer,").concat(n,"-item")]:{paddingInline:a},["".concat(n,"-pagination")]:{margin:"".concat((0,k.bf)(c)," ").concat((0,k.bf)(l))}},["".concat(t).concat(n,"-sm")]:{["".concat(n,"-item,").concat(n,"-header,").concat(n,"-footer")]:{padding:o}},["".concat(t).concat(n,"-lg")]:{["".concat(n,"-item,").concat(n,"-header,").concat(n,"-footer")]:{padding:r}}}},N=e=>{let{componentCls:t,screenSM:n,screenMD:a,marginLG:c,marginSM:o,margin:r}=e;return{["@media screen and (max-width:".concat(a,"px)")]:{[t]:{["".concat(t,"-item")]:{["".concat(t,"-item-action")]:{marginInlineStart:c}}},["".concat(t,"-vertical")]:{["".concat(t,"-item")]:{["".concat(t,"-item-extra")]:{marginInlineStart:c}}}},["@media screen and (max-width: ".concat(n,"px)")]:{[t]:{["".concat(t,"-item")]:{flexWrap:"wrap",["".concat(t,"-action")]:{marginInlineStart:o}}},["".concat(t,"-vertical")]:{["".concat(t,"-item")]:{flexWrap:"wrap-reverse",["".concat(t,"-item-main")]:{minWidth:e.contentWidth},["".concat(t,"-item-extra")]:{margin:"auto auto ".concat((0,k.bf)(r))}}}}}},z=e=>{let{componentCls:t,antCls:n,controlHeight:a,minHeight:c,paddingSM:o,marginLG:r,padding:l,itemPadding:i,colorPrimary:s,itemPaddingSM:d,itemPaddingLG:m,paddingXS:u,margin:g,colorText:p,colorTextDescription:f,motionDurationSlow:h,lineWidth:v,headerBg:b,footerBg:x,emptyTextPadding:y,metaMarginBottom:w,avatarMarginRight:E,titleMarginBottom:C,descriptionFontSize:N}=e;return{[t]:Object.assign(Object.assign({},(0,S.Wf)(e)),{position:"relative","--rc-virtual-list-scrollbar-bg":e.colorSplit,"*":{outline:"none"},["".concat(t,"-header")]:{background:b},["".concat(t,"-footer")]:{background:x},["".concat(t,"-header, ").concat(t,"-footer")]:{paddingBlock:o},["".concat(t,"-pagination")]:{marginBlockStart:r,["".concat(n,"-pagination-options")]:{textAlign:"start"}},["".concat(t,"-spin")]:{minHeight:c,textAlign:"center"},["".concat(t,"-items")]:{margin:0,padding:0,listStyle:"none"},["".concat(t,"-item")]:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:i,color:p,["".concat(t,"-item-meta")]:{display:"flex",flex:1,alignItems:"flex-start",maxWidth:"100%",["".concat(t,"-item-meta-avatar")]:{marginInlineEnd:E},["".concat(t,"-item-meta-content")]:{flex:"1 0",width:0,color:p},["".concat(t,"-item-meta-title")]:{margin:"0 0 ".concat((0,k.bf)(e.marginXXS)," 0"),color:p,fontSize:e.fontSize,lineHeight:e.lineHeight,"> a":{color:p,transition:"all ".concat(h),"&:hover":{color:s}}},["".concat(t,"-item-meta-description")]:{color:f,fontSize:N,lineHeight:e.lineHeight}},["".concat(t,"-item-action")]:{flex:"0 0 auto",marginInlineStart:e.marginXXL,padding:0,fontSize:0,listStyle:"none","& > li":{position:"relative",display:"inline-block",padding:"0 ".concat((0,k.bf)(u)),color:f,fontSize:e.fontSize,lineHeight:e.lineHeight,textAlign:"center","&:first-child":{paddingInlineStart:0}},["".concat(t,"-item-action-split")]:{position:"absolute",insetBlockStart:"50%",insetInlineEnd:0,width:v,height:e.calc(e.fontHeight).sub(e.calc(e.marginXXS).mul(2)).equal(),transform:"translateY(-50%)",backgroundColor:e.colorSplit}}},["".concat(t,"-empty")]:{padding:"".concat((0,k.bf)(l)," 0"),color:f,fontSize:e.fontSizeSM,textAlign:"center"},["".concat(t,"-empty-text")]:{padding:y,color:e.colorTextDisabled,fontSize:e.fontSize,textAlign:"center"},["".concat(t,"-item-no-flex")]:{display:"block"}}),["".concat(t,"-grid ").concat(n,"-col > ").concat(t,"-item")]:{display:"block",maxWidth:"100%",marginBlockEnd:g,paddingBlock:0,borderBlockEnd:"none"},["".concat(t,"-vertical ").concat(t,"-item")]:{alignItems:"initial",["".concat(t,"-item-main")]:{display:"block",flex:1},["".concat(t,"-item-extra")]:{marginInlineStart:r},["".concat(t,"-item-meta")]:{marginBlockEnd:w,["".concat(t,"-item-meta-title")]:{marginBlockStart:0,marginBlockEnd:C,color:p,fontSize:e.fontSizeLG,lineHeight:e.lineHeightLG}},["".concat(t,"-item-action")]:{marginBlockStart:l,marginInlineStart:"auto","> li":{padding:"0 ".concat((0,k.bf)(l)),"&:first-child":{paddingInlineStart:0}}}},["".concat(t,"-split ").concat(t,"-item")]:{borderBlockEnd:"".concat((0,k.bf)(e.lineWidth)," ").concat(e.lineType," ").concat(e.colorSplit),"&:last-child":{borderBlockEnd:"none"}},["".concat(t,"-split ").concat(t,"-header")]:{borderBlockEnd:"".concat((0,k.bf)(e.lineWidth)," ").concat(e.lineType," ").concat(e.colorSplit)},["".concat(t,"-split").concat(t,"-empty ").concat(t,"-footer")]:{borderTop:"".concat((0,k.bf)(e.lineWidth)," ").concat(e.lineType," ").concat(e.colorSplit)},["".concat(t,"-loading ").concat(t,"-spin-nested-loading")]:{minHeight:a},["".concat(t,"-split").concat(t,"-something-after-last-item ").concat(n,"-spin-container > ").concat(t,"-items > ").concat(t,"-item:last-child")]:{borderBlockEnd:"".concat((0,k.bf)(e.lineWidth)," ").concat(e.lineType," ").concat(e.colorSplit)},["".concat(t,"-lg ").concat(t,"-item")]:{padding:m},["".concat(t,"-sm ").concat(t,"-item")]:{padding:d},["".concat(t,":not(").concat(t,"-vertical)")]:{["".concat(t,"-item-no-flex")]:{["".concat(t,"-item-action")]:{float:"right"}}}}};var M=(0,w.I$)("List",e=>{let t=(0,E.IX)(e,{listBorderedCls:"".concat(e.componentCls,"-bordered"),minHeight:e.controlHeightLG});return[z(t),C(t),N(t)]},e=>({contentWidth:220,itemPadding:"".concat((0,k.bf)(e.paddingContentVertical)," 0"),itemPaddingSM:"".concat((0,k.bf)(e.paddingContentVerticalSM)," ").concat((0,k.bf)(e.paddingContentHorizontal)),itemPaddingLG:"".concat((0,k.bf)(e.paddingContentVerticalLG)," ").concat((0,k.bf)(e.paddingContentHorizontalLG)),headerBg:"transparent",footerBg:"transparent",emptyTextPadding:e.padding,metaMarginBottom:e.padding,avatarMarginRight:e.padding,titleMarginBottom:e.paddingSM,descriptionFontSize:e.fontSize})),O=function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var c=0,a=Object.getOwnPropertySymbols(e);ct.indexOf(a[c])&&Object.prototype.propertyIsEnumerable.call(e,a[c])&&(n[a[c]]=e[a[c]]);return n};let Z=c.forwardRef(function(e,t){let{pagination:n=!1,prefixCls:o,bordered:v=!1,split:b=!0,className:x,rootClassName:y,style:k,children:S,itemLayout:w,loadMore:E,grid:C,dataSource:N=[],size:z,header:Z,footer:I,loading:j=!1,rowKey:H,renderItem:B,locale:L}=e,T=O(e,["pagination","prefixCls","bordered","split","className","rootClassName","style","children","itemLayout","loadMore","grid","dataSource","size","header","footer","loading","rowKey","renderItem","locale"]),V=n&&"object"==typeof n?n:{},[R,W]=c.useState(V.defaultCurrent||1),[_,P]=c.useState(V.defaultPageSize||10),{getPrefixCls:D,direction:q,className:A,style:G}=(0,s.dj)("list"),{renderEmpty:U}=c.useContext(s.E_),X=e=>(t,a)=>{var c;W(t),P(a),n&&(null===(c=null==n?void 0:n[e])||void 0===c||c.call(n,t,a))},K=X("onChange"),F=X("onShowSizeChange"),J=!!(E||n||I),Y=D("list",o),[$,Q,ee]=M(Y),et=j;"boolean"==typeof et&&(et={spinning:et});let en=!!(null==et?void 0:et.spinning),ea=(0,m.Z)(z),ec="";switch(ea){case"large":ec="lg";break;case"small":ec="sm"}let eo=r()(Y,{["".concat(Y,"-vertical")]:"vertical"===w,["".concat(Y,"-").concat(ec)]:ec,["".concat(Y,"-split")]:b,["".concat(Y,"-bordered")]:v,["".concat(Y,"-loading")]:en,["".concat(Y,"-grid")]:!!C,["".concat(Y,"-something-after-last-item")]:J,["".concat(Y,"-rtl")]:"rtl"===q},A,x,y,Q,ee),er=(0,l.Z)({current:1,total:0,position:"bottom"},{total:N.length,current:R,pageSize:_},n||{}),el=Math.ceil(er.total/er.pageSize);er.current=Math.min(er.current,el);let ei=n&&c.createElement("div",{className:r()("".concat(Y,"-pagination"))},c.createElement(p.Z,Object.assign({align:"end"},er,{onChange:K,onShowSizeChange:F}))),es=(0,a.Z)(N);n&&N.length>(er.current-1)*er.pageSize&&(es=(0,a.Z)(N).splice((er.current-1)*er.pageSize,er.pageSize));let ed=Object.keys(C||{}).some(e=>["xs","sm","md","lg","xl","xxl"].includes(e)),em=(0,g.Z)(ed),eu=c.useMemo(()=>{for(let e=0;e{if(!C)return;let e=eu&&C[eu]?C[eu]:C.column;if(e)return{width:"".concat(100/e,"%"),maxWidth:"".concat(100/e,"%")}},[JSON.stringify(C),eu]),ep=en&&c.createElement("div",{style:{minHeight:53}});if(es.length>0){let e=es.map((e,t)=>{let n;return B?((n="function"==typeof H?H(e):H?e[H]:e.key)||(n="list-item-".concat(t)),c.createElement(c.Fragment,{key:n},B(e,t))):null});ep=C?c.createElement(u.Z,{gutter:C.gutter},c.Children.map(e,e=>c.createElement("div",{key:null==e?void 0:e.key,style:eg},e))):c.createElement("ul",{className:"".concat(Y,"-items")},e)}else S||en||(ep=c.createElement("div",{className:"".concat(Y,"-empty-text")},(null==L?void 0:L.emptyText)||(null==U?void 0:U("List"))||c.createElement(d.Z,{componentName:"List"})));let ef=er.position,eh=c.useMemo(()=>({grid:C,itemLayout:w}),[JSON.stringify(C),w]);return $(c.createElement(h.Provider,{value:eh},c.createElement("div",Object.assign({ref:t,style:Object.assign(Object.assign({},G),k),className:eo},T),("top"===ef||"both"===ef)&&ei,Z&&c.createElement("div",{className:"".concat(Y,"-header")},Z),c.createElement(f.Z,Object.assign({},et),ep,S),I&&c.createElement("div",{className:"".concat(Y,"-footer")},I),E||("bottom"===ef||"both"===ef)&&ei)))});Z.Item=y;var I=Z},30401:function(e,t,n){n.d(t,{Z:function(){return a}});let a=(0,n(79205).Z)("check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]])},10900:function(e,t,n){var a=n(2265);let c=a.forwardRef(function(e,t){return a.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:2,stroke:"currentColor","aria-hidden":"true",ref:t},e),a.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M10 19l-7-7m0 0l7-7m-7 7h18"}))});t.Z=c}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/1994-6637a121c9ee1602.js b/litellm/proxy/_experimental/out/_next/static/chunks/1994-6637a121c9ee1602.js deleted file mode 100644 index 90f29480d63..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/1994-6637a121c9ee1602.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1994],{4156:function(e,n,t){t.d(n,{Z:function(){return O}});var o=t(2265),a=t(36760),r=t.n(a),c=t(20873),l=t(28791),i=t(6694),s=t(34709),u=t(71744),d=t(86586),b=t(64024),p=t(39109);let f=o.createContext(null);var v=t(23159),m=t(66531),h=function(e,n){var t={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>n.indexOf(o)&&(t[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var a=0,o=Object.getOwnPropertySymbols(e);an.indexOf(o[a])&&Object.prototype.propertyIsEnumerable.call(e,o[a])&&(t[o[a]]=e[o[a]]);return t};let g=o.forwardRef((e,n)=>{var t;let{prefixCls:a,className:g,rootClassName:C,children:y,indeterminate:k=!1,style:x,onMouseEnter:O,onMouseLeave:E,skipGroup:S=!1,disabled:w}=e,Z=h(e,["prefixCls","className","rootClassName","children","indeterminate","style","onMouseEnter","onMouseLeave","skipGroup","disabled"]),{getPrefixCls:P,direction:N,checkbox:j}=o.useContext(u.E_),I=o.useContext(f),{isFormItemInput:R}=o.useContext(p.aM),z=o.useContext(d.Z),B=null!==(t=(null==I?void 0:I.disabled)||w)&&void 0!==t?t:z,D=o.useRef(Z.value),M=o.useRef(null),_=(0,l.sQ)(n,M);o.useEffect(()=>{null==I||I.registerValue(Z.value)},[]),o.useEffect(()=>{if(!S)return Z.value!==D.current&&(null==I||I.cancelValue(D.current),null==I||I.registerValue(Z.value),D.current=Z.value),()=>null==I?void 0:I.cancelValue(Z.value)},[Z.value]),o.useEffect(()=>{var e;(null===(e=M.current)||void 0===e?void 0:e.input)&&(M.current.input.indeterminate=k)},[k]);let W=P("checkbox",a),q=(0,b.Z)(W),[H,T,G]=(0,v.ZP)(W,q),V=Object.assign({},Z);I&&!S&&(V.onChange=function(){for(var e=arguments.length,n=Array(e),t=0;tn.indexOf(o)&&(t[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var a=0,o=Object.getOwnPropertySymbols(e);an.indexOf(o[a])&&Object.prototype.propertyIsEnumerable.call(e,o[a])&&(t[o[a]]=e[o[a]]);return t};let x=o.forwardRef((e,n)=>{let{defaultValue:t,children:a,options:c=[],prefixCls:l,className:i,rootClassName:s,style:d,onChange:p}=e,m=k(e,["defaultValue","children","options","prefixCls","className","rootClassName","style","onChange"]),{getPrefixCls:h,direction:x}=o.useContext(u.E_),[O,E]=o.useState(m.value||t||[]),[S,w]=o.useState([]);o.useEffect(()=>{"value"in m&&E(m.value||[])},[m.value]);let Z=o.useMemo(()=>c.map(e=>"string"==typeof e||"number"==typeof e?{label:e,value:e}:e),[c]),P=e=>{w(n=>n.filter(n=>n!==e))},N=e=>{w(n=>[].concat((0,C.Z)(n),[e]))},j=e=>{let n=O.indexOf(e.value),t=(0,C.Z)(O);-1===n?t.push(e.value):t.splice(n,1),"value"in m||E(t),null==p||p(t.filter(e=>S.includes(e)).sort((e,n)=>Z.findIndex(n=>n.value===e)-Z.findIndex(e=>e.value===n)))},I=h("checkbox",l),R="".concat(I,"-group"),z=(0,b.Z)(I),[B,D,M]=(0,v.ZP)(I,z),_=(0,y.Z)(m,["value","disabled"]),W=c.length?Z.map(e=>o.createElement(g,{prefixCls:I,key:e.value.toString(),disabled:"disabled"in e?e.disabled:m.disabled,value:e.value,checked:O.includes(e.value),onChange:e.onChange,className:r()("".concat(R,"-item"),e.className),style:e.style,title:e.title,id:e.id,required:e.required},e.label)):a,q=o.useMemo(()=>({toggleOption:j,value:O,disabled:m.disabled,name:m.name,registerValue:N,cancelValue:P}),[j,O,m.disabled,m.name,N,P]),H=r()(R,{["".concat(R,"-rtl")]:"rtl"===x},i,s,M,z,D);return B(o.createElement("div",Object.assign({className:H,style:d},_,{ref:n}),o.createElement(f.Provider,{value:q},W)))});g.Group=x,g.__ANT_CHECKBOX=!0;var O=g},23159:function(e,n,t){t.d(n,{C2:function(){return i}});var o=t(93463),a=t(12918),r=t(71140),c=t(99320);let l=e=>{let{checkboxCls:n}=e,t="".concat(n,"-wrapper");return[{["".concat(n,"-group")]:Object.assign(Object.assign({},(0,a.Wf)(e)),{display:"inline-flex",flexWrap:"wrap",columnGap:e.marginXS,["> ".concat(e.antCls,"-row")]:{flex:1}}),[t]:Object.assign(Object.assign({},(0,a.Wf)(e)),{display:"inline-flex",alignItems:"baseline",cursor:"pointer","&:after":{display:"inline-block",width:0,overflow:"hidden",content:"'\\a0'"},["& + ".concat(t)]:{marginInlineStart:0},["&".concat(t,"-in-form-item")]:{'input[type="checkbox"]':{width:14,height:14}}}),[n]:Object.assign(Object.assign({},(0,a.Wf)(e)),{position:"relative",whiteSpace:"nowrap",lineHeight:1,cursor:"pointer",borderRadius:e.borderRadiusSM,alignSelf:"center",["".concat(n,"-input")]:{position:"absolute",inset:0,zIndex:1,cursor:"pointer",opacity:0,margin:0,["&:focus-visible + ".concat(n,"-inner")]:(0,a.oN)(e)},["".concat(n,"-inner")]:{boxSizing:"border-box",display:"block",width:e.checkboxSize,height:e.checkboxSize,direction:"ltr",backgroundColor:e.colorBgContainer,border:"".concat((0,o.bf)(e.lineWidth)," ").concat(e.lineType," ").concat(e.colorBorder),borderRadius:e.borderRadiusSM,borderCollapse:"separate",transition:"all ".concat(e.motionDurationSlow),"&:after":{boxSizing:"border-box",position:"absolute",top:"50%",insetInlineStart:"25%",display:"table",width:e.calc(e.checkboxSize).div(14).mul(5).equal(),height:e.calc(e.checkboxSize).div(14).mul(8).equal(),border:"".concat((0,o.bf)(e.lineWidthBold)," solid ").concat(e.colorWhite),borderTop:0,borderInlineStart:0,transform:"rotate(45deg) scale(0) translate(-50%,-50%)",opacity:0,content:'""',transition:"all ".concat(e.motionDurationFast," ").concat(e.motionEaseInBack,", opacity ").concat(e.motionDurationFast)}},"& + span":{paddingInlineStart:e.paddingXS,paddingInlineEnd:e.paddingXS}})},{["\n ".concat(t,":not(").concat(t,"-disabled),\n ").concat(n,":not(").concat(n,"-disabled)\n ")]:{["&:hover ".concat(n,"-inner")]:{borderColor:e.colorPrimary}},["".concat(t,":not(").concat(t,"-disabled)")]:{["&:hover ".concat(n,"-checked:not(").concat(n,"-disabled) ").concat(n,"-inner")]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"},["&:hover ".concat(n,"-checked:not(").concat(n,"-disabled):after")]:{borderColor:e.colorPrimaryHover}}},{["".concat(n,"-checked")]:{["".concat(n,"-inner")]:{backgroundColor:e.colorPrimary,borderColor:e.colorPrimary,"&:after":{opacity:1,transform:"rotate(45deg) scale(1) translate(-50%,-50%)",transition:"all ".concat(e.motionDurationMid," ").concat(e.motionEaseOutBack," ").concat(e.motionDurationFast)}}},["\n ".concat(t,"-checked:not(").concat(t,"-disabled),\n ").concat(n,"-checked:not(").concat(n,"-disabled)\n ")]:{["&:hover ".concat(n,"-inner")]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"}}},{[n]:{"&-indeterminate":{"&":{["".concat(n,"-inner")]:{backgroundColor:"".concat(e.colorBgContainer),borderColor:"".concat(e.colorBorder),"&:after":{top:"50%",insetInlineStart:"50%",width:e.calc(e.fontSizeLG).div(2).equal(),height:e.calc(e.fontSizeLG).div(2).equal(),backgroundColor:e.colorPrimary,border:0,transform:"translate(-50%, -50%) scale(1)",opacity:1,content:'""'}},["&:hover ".concat(n,"-inner")]:{backgroundColor:"".concat(e.colorBgContainer),borderColor:"".concat(e.colorPrimary)}}}}},{["".concat(t,"-disabled")]:{cursor:"not-allowed"},["".concat(n,"-disabled")]:{["&, ".concat(n,"-input")]:{cursor:"not-allowed",pointerEvents:"none"},["".concat(n,"-inner")]:{background:e.colorBgContainerDisabled,borderColor:e.colorBorder,"&:after":{borderColor:e.colorTextDisabled}},"&:after":{display:"none"},"& + span":{color:e.colorTextDisabled},["&".concat(n,"-indeterminate ").concat(n,"-inner::after")]:{background:e.colorTextDisabled}}}]};function i(e,n){return l((0,r.IX)(n,{checkboxCls:".".concat(e),checkboxSize:n.controlInteractiveSize}))}n.ZP=(0,c.I$)("Checkbox",(e,n)=>{let{prefixCls:t}=n;return[i(t,e)]})},66531:function(e,n,t){t.d(n,{Z:function(){return r}});var o=t(2265),a=t(53346);function r(e){let n=o.useRef(null),t=()=>{a.Z.cancel(n.current),n.current=null};return[()=>{t(),n.current=(0,a.Z)(()=>{n.current=null})},o=>{n.current&&(o.stopPropagation(),t()),null==e||e(o)}]}},20873:function(e,n,t){var o=t(1119),a=t(31686),r=t(11993),c=t(26365),l=t(6989),i=t(36760),s=t.n(i),u=t(50506),d=t(2265),b=["prefixCls","className","style","checked","disabled","defaultChecked","type","title","onChange"],p=(0,d.forwardRef)(function(e,n){var t=e.prefixCls,i=void 0===t?"rc-checkbox":t,p=e.className,f=e.style,v=e.checked,m=e.disabled,h=e.defaultChecked,g=e.type,C=void 0===g?"checkbox":g,y=e.title,k=e.onChange,x=(0,l.Z)(e,b),O=(0,d.useRef)(null),E=(0,d.useRef)(null),S=(0,u.Z)(void 0!==h&&h,{value:v}),w=(0,c.Z)(S,2),Z=w[0],P=w[1];(0,d.useImperativeHandle)(n,function(){return{focus:function(e){var n;null===(n=O.current)||void 0===n||n.focus(e)},blur:function(){var e;null===(e=O.current)||void 0===e||e.blur()},input:O.current,nativeElement:E.current}});var N=s()(i,p,(0,r.Z)((0,r.Z)({},"".concat(i,"-checked"),Z),"".concat(i,"-disabled"),m));return d.createElement("span",{className:N,title:y,style:f,ref:E},d.createElement("input",(0,o.Z)({},x,{className:"".concat(i,"-input"),ref:O,onChange:function(n){m||("checked"in e||P(n.target.checked),null==k||k({target:(0,a.Z)((0,a.Z)({},e),{},{type:C,checked:n.target.checked}),stopPropagation:function(){n.stopPropagation()},preventDefault:function(){n.preventDefault()},nativeEvent:n.nativeEvent}))},disabled:m,checked:!!Z,type:C})),d.createElement("span",{className:"".concat(i,"-inner")}))});n.Z=p}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/1994-a4d0b99849c16b62.js b/litellm/proxy/_experimental/out/_next/static/chunks/1994-a4d0b99849c16b62.js new file mode 100644 index 00000000000..3211472683d --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/1994-a4d0b99849c16b62.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1994],{61994:function(e,n,t){t.d(n,{Z:function(){return O}});var o=t(2265),a=t(36760),r=t.n(a),c=t(20873),l=t(28791),i=t(6694),s=t(34709),u=t(71744),d=t(86586),b=t(64024),p=t(39109);let f=o.createContext(null);var v=t(23159),m=t(66531),h=function(e,n){var t={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&0>n.indexOf(o)&&(t[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var a=0,o=Object.getOwnPropertySymbols(e);an.indexOf(o[a])&&Object.prototype.propertyIsEnumerable.call(e,o[a])&&(t[o[a]]=e[o[a]]);return t};let g=o.forwardRef((e,n)=>{var t;let{prefixCls:a,className:g,rootClassName:C,children:y,indeterminate:k=!1,style:x,onMouseEnter:O,onMouseLeave:E,skipGroup:S=!1,disabled:w}=e,Z=h(e,["prefixCls","className","rootClassName","children","indeterminate","style","onMouseEnter","onMouseLeave","skipGroup","disabled"]),{getPrefixCls:P,direction:N,checkbox:j}=o.useContext(u.E_),I=o.useContext(f),{isFormItemInput:R}=o.useContext(p.aM),z=o.useContext(d.Z),B=null!==(t=(null==I?void 0:I.disabled)||w)&&void 0!==t?t:z,D=o.useRef(Z.value),M=o.useRef(null),_=(0,l.sQ)(n,M);o.useEffect(()=>{null==I||I.registerValue(Z.value)},[]),o.useEffect(()=>{if(!S)return Z.value!==D.current&&(null==I||I.cancelValue(D.current),null==I||I.registerValue(Z.value),D.current=Z.value),()=>null==I?void 0:I.cancelValue(Z.value)},[Z.value]),o.useEffect(()=>{var e;(null===(e=M.current)||void 0===e?void 0:e.input)&&(M.current.input.indeterminate=k)},[k]);let W=P("checkbox",a),q=(0,b.Z)(W),[H,T,G]=(0,v.ZP)(W,q),V=Object.assign({},Z);I&&!S&&(V.onChange=function(){for(var e=arguments.length,n=Array(e),t=0;tn.indexOf(o)&&(t[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var a=0,o=Object.getOwnPropertySymbols(e);an.indexOf(o[a])&&Object.prototype.propertyIsEnumerable.call(e,o[a])&&(t[o[a]]=e[o[a]]);return t};let x=o.forwardRef((e,n)=>{let{defaultValue:t,children:a,options:c=[],prefixCls:l,className:i,rootClassName:s,style:d,onChange:p}=e,m=k(e,["defaultValue","children","options","prefixCls","className","rootClassName","style","onChange"]),{getPrefixCls:h,direction:x}=o.useContext(u.E_),[O,E]=o.useState(m.value||t||[]),[S,w]=o.useState([]);o.useEffect(()=>{"value"in m&&E(m.value||[])},[m.value]);let Z=o.useMemo(()=>c.map(e=>"string"==typeof e||"number"==typeof e?{label:e,value:e}:e),[c]),P=e=>{w(n=>n.filter(n=>n!==e))},N=e=>{w(n=>[].concat((0,C.Z)(n),[e]))},j=e=>{let n=O.indexOf(e.value),t=(0,C.Z)(O);-1===n?t.push(e.value):t.splice(n,1),"value"in m||E(t),null==p||p(t.filter(e=>S.includes(e)).sort((e,n)=>Z.findIndex(n=>n.value===e)-Z.findIndex(e=>e.value===n)))},I=h("checkbox",l),R="".concat(I,"-group"),z=(0,b.Z)(I),[B,D,M]=(0,v.ZP)(I,z),_=(0,y.Z)(m,["value","disabled"]),W=c.length?Z.map(e=>o.createElement(g,{prefixCls:I,key:e.value.toString(),disabled:"disabled"in e?e.disabled:m.disabled,value:e.value,checked:O.includes(e.value),onChange:e.onChange,className:r()("".concat(R,"-item"),e.className),style:e.style,title:e.title,id:e.id,required:e.required},e.label)):a,q=o.useMemo(()=>({toggleOption:j,value:O,disabled:m.disabled,name:m.name,registerValue:N,cancelValue:P}),[j,O,m.disabled,m.name,N,P]),H=r()(R,{["".concat(R,"-rtl")]:"rtl"===x},i,s,M,z,D);return B(o.createElement("div",Object.assign({className:H,style:d},_,{ref:n}),o.createElement(f.Provider,{value:q},W)))});g.Group=x,g.__ANT_CHECKBOX=!0;var O=g},23159:function(e,n,t){t.d(n,{C2:function(){return i}});var o=t(93463),a=t(12918),r=t(71140),c=t(99320);let l=e=>{let{checkboxCls:n}=e,t="".concat(n,"-wrapper");return[{["".concat(n,"-group")]:Object.assign(Object.assign({},(0,a.Wf)(e)),{display:"inline-flex",flexWrap:"wrap",columnGap:e.marginXS,["> ".concat(e.antCls,"-row")]:{flex:1}}),[t]:Object.assign(Object.assign({},(0,a.Wf)(e)),{display:"inline-flex",alignItems:"baseline",cursor:"pointer","&:after":{display:"inline-block",width:0,overflow:"hidden",content:"'\\a0'"},["& + ".concat(t)]:{marginInlineStart:0},["&".concat(t,"-in-form-item")]:{'input[type="checkbox"]':{width:14,height:14}}}),[n]:Object.assign(Object.assign({},(0,a.Wf)(e)),{position:"relative",whiteSpace:"nowrap",lineHeight:1,cursor:"pointer",borderRadius:e.borderRadiusSM,alignSelf:"center",["".concat(n,"-input")]:{position:"absolute",inset:0,zIndex:1,cursor:"pointer",opacity:0,margin:0,["&:focus-visible + ".concat(n,"-inner")]:(0,a.oN)(e)},["".concat(n,"-inner")]:{boxSizing:"border-box",display:"block",width:e.checkboxSize,height:e.checkboxSize,direction:"ltr",backgroundColor:e.colorBgContainer,border:"".concat((0,o.bf)(e.lineWidth)," ").concat(e.lineType," ").concat(e.colorBorder),borderRadius:e.borderRadiusSM,borderCollapse:"separate",transition:"all ".concat(e.motionDurationSlow),"&:after":{boxSizing:"border-box",position:"absolute",top:"50%",insetInlineStart:"25%",display:"table",width:e.calc(e.checkboxSize).div(14).mul(5).equal(),height:e.calc(e.checkboxSize).div(14).mul(8).equal(),border:"".concat((0,o.bf)(e.lineWidthBold)," solid ").concat(e.colorWhite),borderTop:0,borderInlineStart:0,transform:"rotate(45deg) scale(0) translate(-50%,-50%)",opacity:0,content:'""',transition:"all ".concat(e.motionDurationFast," ").concat(e.motionEaseInBack,", opacity ").concat(e.motionDurationFast)}},"& + span":{paddingInlineStart:e.paddingXS,paddingInlineEnd:e.paddingXS}})},{["\n ".concat(t,":not(").concat(t,"-disabled),\n ").concat(n,":not(").concat(n,"-disabled)\n ")]:{["&:hover ".concat(n,"-inner")]:{borderColor:e.colorPrimary}},["".concat(t,":not(").concat(t,"-disabled)")]:{["&:hover ".concat(n,"-checked:not(").concat(n,"-disabled) ").concat(n,"-inner")]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"},["&:hover ".concat(n,"-checked:not(").concat(n,"-disabled):after")]:{borderColor:e.colorPrimaryHover}}},{["".concat(n,"-checked")]:{["".concat(n,"-inner")]:{backgroundColor:e.colorPrimary,borderColor:e.colorPrimary,"&:after":{opacity:1,transform:"rotate(45deg) scale(1) translate(-50%,-50%)",transition:"all ".concat(e.motionDurationMid," ").concat(e.motionEaseOutBack," ").concat(e.motionDurationFast)}}},["\n ".concat(t,"-checked:not(").concat(t,"-disabled),\n ").concat(n,"-checked:not(").concat(n,"-disabled)\n ")]:{["&:hover ".concat(n,"-inner")]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"}}},{[n]:{"&-indeterminate":{"&":{["".concat(n,"-inner")]:{backgroundColor:"".concat(e.colorBgContainer),borderColor:"".concat(e.colorBorder),"&:after":{top:"50%",insetInlineStart:"50%",width:e.calc(e.fontSizeLG).div(2).equal(),height:e.calc(e.fontSizeLG).div(2).equal(),backgroundColor:e.colorPrimary,border:0,transform:"translate(-50%, -50%) scale(1)",opacity:1,content:'""'}},["&:hover ".concat(n,"-inner")]:{backgroundColor:"".concat(e.colorBgContainer),borderColor:"".concat(e.colorPrimary)}}}}},{["".concat(t,"-disabled")]:{cursor:"not-allowed"},["".concat(n,"-disabled")]:{["&, ".concat(n,"-input")]:{cursor:"not-allowed",pointerEvents:"none"},["".concat(n,"-inner")]:{background:e.colorBgContainerDisabled,borderColor:e.colorBorder,"&:after":{borderColor:e.colorTextDisabled}},"&:after":{display:"none"},"& + span":{color:e.colorTextDisabled},["&".concat(n,"-indeterminate ").concat(n,"-inner::after")]:{background:e.colorTextDisabled}}}]};function i(e,n){return l((0,r.IX)(n,{checkboxCls:".".concat(e),checkboxSize:n.controlInteractiveSize}))}n.ZP=(0,c.I$)("Checkbox",(e,n)=>{let{prefixCls:t}=n;return[i(t,e)]})},66531:function(e,n,t){t.d(n,{Z:function(){return r}});var o=t(2265),a=t(53346);function r(e){let n=o.useRef(null),t=()=>{a.Z.cancel(n.current),n.current=null};return[()=>{t(),n.current=(0,a.Z)(()=>{n.current=null})},o=>{n.current&&(o.stopPropagation(),t()),null==e||e(o)}]}},20873:function(e,n,t){var o=t(1119),a=t(31686),r=t(11993),c=t(26365),l=t(6989),i=t(36760),s=t.n(i),u=t(50506),d=t(2265),b=["prefixCls","className","style","checked","disabled","defaultChecked","type","title","onChange"],p=(0,d.forwardRef)(function(e,n){var t=e.prefixCls,i=void 0===t?"rc-checkbox":t,p=e.className,f=e.style,v=e.checked,m=e.disabled,h=e.defaultChecked,g=e.type,C=void 0===g?"checkbox":g,y=e.title,k=e.onChange,x=(0,l.Z)(e,b),O=(0,d.useRef)(null),E=(0,d.useRef)(null),S=(0,u.Z)(void 0!==h&&h,{value:v}),w=(0,c.Z)(S,2),Z=w[0],P=w[1];(0,d.useImperativeHandle)(n,function(){return{focus:function(e){var n;null===(n=O.current)||void 0===n||n.focus(e)},blur:function(){var e;null===(e=O.current)||void 0===e||e.blur()},input:O.current,nativeElement:E.current}});var N=s()(i,p,(0,r.Z)((0,r.Z)({},"".concat(i,"-checked"),Z),"".concat(i,"-disabled"),m));return d.createElement("span",{className:N,title:y,style:f,ref:E},d.createElement("input",(0,o.Z)({},x,{className:"".concat(i,"-input"),ref:O,onChange:function(n){m||("checked"in e||P(n.target.checked),null==k||k({target:(0,a.Z)((0,a.Z)({},e),{},{type:C,checked:n.target.checked}),stopPropagation:function(){n.stopPropagation()},preventDefault:function(){n.preventDefault()},nativeEvent:n.nativeEvent}))},disabled:m,checked:!!Z,type:C})),d.createElement("span",{className:"".concat(i,"-inner")}))});n.Z=p}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/2004-294ce010a90069b4.js b/litellm/proxy/_experimental/out/_next/static/chunks/2004-294ce010a90069b4.js new file mode 100644 index 00000000000..280fafea373 --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/2004-294ce010a90069b4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[2004],{22004:function(e,l,s){s.d(l,{Z:function(){return ee},g:function(){return X}});var i=s(57437),a=s(2265),r=s(41649),t=s(78489),n=s(12514),o=s(49804),d=s(67101),c=s(47323),m=s(12485),u=s(18135),x=s(35242),h=s(29706),_=s(77991),g=s(21626),j=s(97214),p=s(28241),v=s(58834),Z=s(69552),b=s(71876),f=s(84264),w=s(24199),z=s(4260),y=s(10032),N=s(99981),C=s(22116),S=s(37592),O=s(15424),M=s(23628),k=s(86462),I=s(47686),P=s(53410),A=s(74998),T=s(31283),D=s(46468),F=s(59872),L=s(10900),R=s(49566),U=s(96761),E=s(5545),B=s(30401),V=s(78867),q=s(33860),G=s(95920),W=s(9114),$=s(19250),J=s(98015),Q=s(10901),Y=s(97415),H=e=>{var l,s,o,N,C;let{organizationId:O,onClose:M,accessToken:k,is_org_admin:I,is_proxy_admin:T,userModels:H,editOrg:K}=e,[X,ee]=(0,a.useState)(null),[el,es]=(0,a.useState)(!0),[ei]=y.Z.useForm(),[ea,er]=(0,a.useState)(!1),[et,en]=(0,a.useState)(!1),[eo,ed]=(0,a.useState)(!1),[ec,em]=(0,a.useState)(null),[eu,ex]=(0,a.useState)({}),[eh,e_]=(0,a.useState)(!1),eg=I||T,ej=async()=>{try{if(es(!0),!k)return;let e=await (0,$.organizationInfoCall)(k,O);ee(e)}catch(e){W.Z.fromBackend("Failed to load organization information"),console.error("Error fetching organization info:",e)}finally{es(!1)}};(0,a.useEffect)(()=>{ej()},[O,k]);let ep=async e=>{try{if(null==k)return;let l={user_email:e.user_email,user_id:e.user_id,role:e.role};await (0,$.organizationMemberAddCall)(k,O,l),W.Z.success("Organization member added successfully"),en(!1),ei.resetFields(),ej()}catch(e){W.Z.fromBackend("Failed to add organization member"),console.error("Error adding organization member:",e)}},ev=async e=>{try{if(!k)return;let l={user_email:e.user_email,user_id:e.user_id,role:e.role};await (0,$.organizationMemberUpdateCall)(k,O,l),W.Z.success("Organization member updated successfully"),ed(!1),ei.resetFields(),ej()}catch(e){W.Z.fromBackend("Failed to update organization member"),console.error("Error updating organization member:",e)}},eZ=async e=>{try{if(!k)return;await (0,$.organizationMemberDeleteCall)(k,O,e.user_id),W.Z.success("Organization member deleted successfully"),ed(!1),ei.resetFields(),ej()}catch(e){W.Z.fromBackend("Failed to delete organization member"),console.error("Error deleting organization member:",e)}},eb=async e=>{try{if(!k)return;e_(!0);let l={organization_id:O,organization_alias:e.organization_alias,models:e.models,litellm_budget_table:{tpm_limit:e.tpm_limit,rpm_limit:e.rpm_limit,max_budget:e.max_budget,budget_duration:e.budget_duration},metadata:e.metadata?JSON.parse(e.metadata):null};if((void 0!==e.vector_stores||void 0!==e.mcp_servers_and_groups)&&(l.object_permission={...null==X?void 0:X.object_permission,vector_stores:e.vector_stores||[]},void 0!==e.mcp_servers_and_groups)){let{servers:s,accessGroups:i}=e.mcp_servers_and_groups||{servers:[],accessGroups:[]};s&&s.length>0&&(l.object_permission.mcp_servers=s),i&&i.length>0&&(l.object_permission.mcp_access_groups=i)}await (0,$.organizationUpdateCall)(k,l),W.Z.success("Organization settings updated successfully"),er(!1),ej()}catch(e){W.Z.fromBackend("Failed to update organization settings"),console.error("Error updating organization:",e)}finally{e_(!1)}};if(el)return(0,i.jsx)("div",{className:"p-4",children:"Loading..."});if(!X)return(0,i.jsx)("div",{className:"p-4",children:"Organization not found"});let ef=async(e,l)=>{await (0,F.vQ)(e)&&(ex(e=>({...e,[l]:!0})),setTimeout(()=>{ex(e=>({...e,[l]:!1}))},2e3))};return(0,i.jsxs)("div",{className:"w-full h-screen p-4 bg-white",children:[(0,i.jsx)("div",{className:"flex justify-between items-center mb-6",children:(0,i.jsxs)("div",{children:[(0,i.jsx)(t.Z,{icon:L.Z,onClick:M,variant:"light",className:"mb-4",children:"Back to Organizations"}),(0,i.jsx)(U.Z,{children:X.organization_alias}),(0,i.jsxs)("div",{className:"flex items-center cursor-pointer",children:[(0,i.jsx)(f.Z,{className:"text-gray-500 font-mono",children:X.organization_id}),(0,i.jsx)(E.ZP,{type:"text",size:"small",icon:eu["org-id"]?(0,i.jsx)(B.Z,{size:12}):(0,i.jsx)(V.Z,{size:12}),onClick:()=>ef(X.organization_id,"org-id"),className:"left-2 z-10 transition-all duration-200 ".concat(eu["org-id"]?"text-green-600 bg-green-50 border-green-200":"text-gray-500 hover:text-gray-700 hover:bg-gray-100")})]})]})}),(0,i.jsxs)(u.Z,{defaultIndex:K?2:0,children:[(0,i.jsxs)(x.Z,{className:"mb-4",children:[(0,i.jsx)(m.Z,{children:"Overview"}),(0,i.jsx)(m.Z,{children:"Members"}),(0,i.jsx)(m.Z,{children:"Settings"})]}),(0,i.jsxs)(_.Z,{children:[(0,i.jsx)(h.Z,{children:(0,i.jsxs)(d.Z,{numItems:1,numItemsSm:2,numItemsLg:3,className:"gap-6",children:[(0,i.jsxs)(n.Z,{children:[(0,i.jsx)(f.Z,{children:"Organization Details"}),(0,i.jsxs)("div",{className:"mt-2",children:[(0,i.jsxs)(f.Z,{children:["Created: ",new Date(X.created_at).toLocaleDateString()]}),(0,i.jsxs)(f.Z,{children:["Updated: ",new Date(X.updated_at).toLocaleDateString()]}),(0,i.jsxs)(f.Z,{children:["Created By: ",X.created_by]})]})]}),(0,i.jsxs)(n.Z,{children:[(0,i.jsx)(f.Z,{children:"Budget Status"}),(0,i.jsxs)("div",{className:"mt-2",children:[(0,i.jsxs)(U.Z,{children:["$",(0,F.pw)(X.spend,4)]}),(0,i.jsxs)(f.Z,{children:["of"," ",null===X.litellm_budget_table.max_budget?"Unlimited":"$".concat((0,F.pw)(X.litellm_budget_table.max_budget,4))]}),X.litellm_budget_table.budget_duration&&(0,i.jsxs)(f.Z,{className:"text-gray-500",children:["Reset: ",X.litellm_budget_table.budget_duration]})]})]}),(0,i.jsxs)(n.Z,{children:[(0,i.jsx)(f.Z,{children:"Rate Limits"}),(0,i.jsxs)("div",{className:"mt-2",children:[(0,i.jsxs)(f.Z,{children:["TPM: ",X.litellm_budget_table.tpm_limit||"Unlimited"]}),(0,i.jsxs)(f.Z,{children:["RPM: ",X.litellm_budget_table.rpm_limit||"Unlimited"]}),X.litellm_budget_table.max_parallel_requests&&(0,i.jsxs)(f.Z,{children:["Max Parallel Requests: ",X.litellm_budget_table.max_parallel_requests]})]})]}),(0,i.jsxs)(n.Z,{children:[(0,i.jsx)(f.Z,{children:"Models"}),(0,i.jsx)("div",{className:"mt-2 flex flex-wrap gap-2",children:0===X.models.length?(0,i.jsx)(r.Z,{color:"red",children:"All proxy models"}):X.models.map((e,l)=>(0,i.jsx)(r.Z,{color:"red",children:e},l))})]}),(0,i.jsxs)(n.Z,{children:[(0,i.jsx)(f.Z,{children:"Teams"}),(0,i.jsx)("div",{className:"mt-2 flex flex-wrap gap-2",children:null===(l=X.teams)||void 0===l?void 0:l.map((e,l)=>(0,i.jsx)(r.Z,{color:"red",children:e.team_id},l))})]}),(0,i.jsx)(J.Z,{objectPermission:X.object_permission,variant:"card",accessToken:k})]})}),(0,i.jsx)(h.Z,{children:(0,i.jsxs)("div",{className:"space-y-4",children:[(0,i.jsx)(n.Z,{className:"w-full mx-auto flex-auto overflow-y-auto max-h-[75vh]",children:(0,i.jsxs)(g.Z,{children:[(0,i.jsx)(v.Z,{children:(0,i.jsxs)(b.Z,{children:[(0,i.jsx)(Z.Z,{children:"User ID"}),(0,i.jsx)(Z.Z,{children:"Role"}),(0,i.jsx)(Z.Z,{children:"Spend"}),(0,i.jsx)(Z.Z,{children:"Created At"}),(0,i.jsx)(Z.Z,{})]})}),(0,i.jsx)(j.Z,{children:null===(s=X.members)||void 0===s?void 0:s.map((e,l)=>(0,i.jsxs)(b.Z,{children:[(0,i.jsx)(p.Z,{children:(0,i.jsx)(f.Z,{className:"font-mono",children:e.user_id})}),(0,i.jsx)(p.Z,{children:(0,i.jsx)(f.Z,{className:"font-mono",children:e.user_role})}),(0,i.jsx)(p.Z,{children:(0,i.jsxs)(f.Z,{children:["$",(0,F.pw)(e.spend,4)]})}),(0,i.jsx)(p.Z,{children:(0,i.jsx)(f.Z,{children:new Date(e.created_at).toLocaleString()})}),(0,i.jsx)(p.Z,{children:eg&&(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(c.Z,{icon:P.Z,size:"sm",onClick:()=>{em({role:e.user_role,user_email:e.user_email,user_id:e.user_id}),ed(!0)}}),(0,i.jsx)(c.Z,{icon:A.Z,size:"sm",onClick:()=>{eZ(e)}})]})})]},l))})]})}),eg&&(0,i.jsx)(t.Z,{onClick:()=>{en(!0)},children:"Add Member"})]})}),(0,i.jsx)(h.Z,{children:(0,i.jsxs)(n.Z,{className:"overflow-y-auto max-h-[65vh]",children:[(0,i.jsxs)("div",{className:"flex justify-between items-center mb-4",children:[(0,i.jsx)(U.Z,{children:"Organization Settings"}),eg&&!ea&&(0,i.jsx)(t.Z,{onClick:()=>er(!0),children:"Edit Settings"})]}),ea?(0,i.jsxs)(y.Z,{form:ei,onFinish:eb,initialValues:{organization_alias:X.organization_alias,models:X.models,tpm_limit:X.litellm_budget_table.tpm_limit,rpm_limit:X.litellm_budget_table.rpm_limit,max_budget:X.litellm_budget_table.max_budget,budget_duration:X.litellm_budget_table.budget_duration,metadata:X.metadata?JSON.stringify(X.metadata,null,2):"",vector_stores:(null===(o=X.object_permission)||void 0===o?void 0:o.vector_stores)||[],mcp_servers_and_groups:{servers:(null===(N=X.object_permission)||void 0===N?void 0:N.mcp_servers)||[],accessGroups:(null===(C=X.object_permission)||void 0===C?void 0:C.mcp_access_groups)||[]}},layout:"vertical",children:[(0,i.jsx)(y.Z.Item,{label:"Organization Name",name:"organization_alias",rules:[{required:!0,message:"Please input an organization name"}],children:(0,i.jsx)(R.Z,{})}),(0,i.jsx)(y.Z.Item,{label:"Models",name:"models",children:(0,i.jsxs)(S.default,{mode:"multiple",placeholder:"Select models",children:[(0,i.jsx)(S.default.Option,{value:"all-proxy-models",children:"All Proxy Models"},"all-proxy-models"),H.map(e=>(0,i.jsx)(S.default.Option,{value:e,children:(0,D.W0)(e)},e))]})}),(0,i.jsx)(y.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,i.jsx)(w.Z,{step:.01,precision:2,style:{width:"100%"}})}),(0,i.jsx)(y.Z.Item,{label:"Reset Budget",name:"budget_duration",children:(0,i.jsxs)(S.default,{placeholder:"n/a",children:[(0,i.jsx)(S.default.Option,{value:"24h",children:"daily"}),(0,i.jsx)(S.default.Option,{value:"7d",children:"weekly"}),(0,i.jsx)(S.default.Option,{value:"30d",children:"monthly"})]})}),(0,i.jsx)(y.Z.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,i.jsx)(w.Z,{step:1,style:{width:"100%"}})}),(0,i.jsx)(y.Z.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,i.jsx)(w.Z,{step:1,style:{width:"100%"}})}),(0,i.jsx)(y.Z.Item,{label:"Vector Stores",name:"vector_stores",children:(0,i.jsx)(Y.Z,{onChange:e=>ei.setFieldValue("vector_stores",e),value:ei.getFieldValue("vector_stores"),accessToken:k||"",placeholder:"Select vector stores"})}),(0,i.jsx)(y.Z.Item,{label:"MCP Servers & Access Groups",name:"mcp_servers_and_groups",children:(0,i.jsx)(G.Z,{onChange:e=>ei.setFieldValue("mcp_servers_and_groups",e),value:ei.getFieldValue("mcp_servers_and_groups"),accessToken:k||"",placeholder:"Select MCP servers and access groups"})}),(0,i.jsx)(y.Z.Item,{label:"Metadata",name:"metadata",children:(0,i.jsx)(z.default.TextArea,{rows:4})}),(0,i.jsx)("div",{className:"sticky z-10 bg-white p-4 border-t border-gray-200 bottom-[-1.5rem] inset-x-[-1.5rem]",children:(0,i.jsxs)("div",{className:"flex justify-end items-center gap-2",children:[(0,i.jsx)(t.Z,{variant:"secondary",onClick:()=>er(!1),disabled:eh,children:"Cancel"}),(0,i.jsx)(t.Z,{type:"submit",loading:eh,children:"Save Changes"})]})})]}):(0,i.jsxs)("div",{className:"space-y-4",children:[(0,i.jsxs)("div",{children:[(0,i.jsx)(f.Z,{className:"font-medium",children:"Organization Name"}),(0,i.jsx)("div",{children:X.organization_alias})]}),(0,i.jsxs)("div",{children:[(0,i.jsx)(f.Z,{className:"font-medium",children:"Organization ID"}),(0,i.jsx)("div",{className:"font-mono",children:X.organization_id})]}),(0,i.jsxs)("div",{children:[(0,i.jsx)(f.Z,{className:"font-medium",children:"Created At"}),(0,i.jsx)("div",{children:new Date(X.created_at).toLocaleString()})]}),(0,i.jsxs)("div",{children:[(0,i.jsx)(f.Z,{className:"font-medium",children:"Models"}),(0,i.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:X.models.map((e,l)=>(0,i.jsx)(r.Z,{color:"red",children:e},l))})]}),(0,i.jsxs)("div",{children:[(0,i.jsx)(f.Z,{className:"font-medium",children:"Rate Limits"}),(0,i.jsxs)("div",{children:["TPM: ",X.litellm_budget_table.tpm_limit||"Unlimited"]}),(0,i.jsxs)("div",{children:["RPM: ",X.litellm_budget_table.rpm_limit||"Unlimited"]})]}),(0,i.jsxs)("div",{children:[(0,i.jsx)(f.Z,{className:"font-medium",children:"Budget"}),(0,i.jsxs)("div",{children:["Max:"," ",null!==X.litellm_budget_table.max_budget?"$".concat((0,F.pw)(X.litellm_budget_table.max_budget,4)):"No Limit"]}),(0,i.jsxs)("div",{children:["Reset: ",X.litellm_budget_table.budget_duration||"Never"]})]}),(0,i.jsx)(J.Z,{objectPermission:X.object_permission,variant:"inline",className:"pt-4 border-t border-gray-200",accessToken:k})]})]})})]})]}),(0,i.jsx)(q.Z,{isVisible:et,onCancel:()=>en(!1),onSubmit:ep,accessToken:k,title:"Add Organization Member",roles:[{label:"org_admin",value:"org_admin",description:"Can add and remove members, and change their roles."},{label:"internal_user",value:"internal_user",description:"Can view/create keys for themselves within organization."},{label:"internal_user_viewer",value:"internal_user_viewer",description:"Can only view their keys within organization."}],defaultRole:"internal_user"}),(0,i.jsx)(Q.Z,{visible:eo,onCancel:()=>ed(!1),onSubmit:ev,initialData:ec,mode:"edit",config:{title:"Edit Member",showEmail:!0,showUserId:!0,roleOptions:[{label:"Org Admin",value:"org_admin"},{label:"Internal User",value:"internal_user"},{label:"Internal User Viewer",value:"internal_user_viewer"}]}})]})},K=s(21609);let X=async(e,l)=>{l(await (0,$.organizationListCall)(e))};var ee=e=>{let{organizations:l,userRole:s,userModels:L,accessToken:R,lastRefreshed:U,handleRefreshClick:E,currentOrg:B,guardrailsList:V=[],setOrganizations:q,premiumUser:J}=e,[Q,ee]=(0,a.useState)(null),[el,es]=(0,a.useState)(!1),[ei,ea]=(0,a.useState)(!1),[er,et]=(0,a.useState)(null),[en,eo]=(0,a.useState)(!1),[ed,ec]=(0,a.useState)(!1),[em]=y.Z.useForm(),[eu,ex]=(0,a.useState)({});(0,a.useEffect)(()=>{R&&X(R,q)},[R]);let eh=e=>{e&&(et(e),ea(!0))},e_=async()=>{if(er&&R)try{eo(!0),await (0,$.organizationDeleteCall)(R,er),W.Z.success("Organization deleted successfully"),ea(!1),et(null),await X(R,q)}catch(e){console.error("Error deleting organization:",e)}finally{eo(!1)}},eg=async e=>{try{var l,s,i,a;if(!R)return;console.log("values in organizations new create call: ".concat(JSON.stringify(e))),(e.allowed_vector_store_ids&&e.allowed_vector_store_ids.length>0||e.allowed_mcp_servers_and_groups&&((null===(l=e.allowed_mcp_servers_and_groups.servers)||void 0===l?void 0:l.length)>0||(null===(s=e.allowed_mcp_servers_and_groups.accessGroups)||void 0===s?void 0:s.length)>0))&&(e.object_permission={},e.allowed_vector_store_ids&&e.allowed_vector_store_ids.length>0&&(e.object_permission.vector_stores=e.allowed_vector_store_ids,delete e.allowed_vector_store_ids),e.allowed_mcp_servers_and_groups&&((null===(i=e.allowed_mcp_servers_and_groups.servers)||void 0===i?void 0:i.length)>0&&(e.object_permission.mcp_servers=e.allowed_mcp_servers_and_groups.servers),(null===(a=e.allowed_mcp_servers_and_groups.accessGroups)||void 0===a?void 0:a.length)>0&&(e.object_permission.mcp_access_groups=e.allowed_mcp_servers_and_groups.accessGroups),delete e.allowed_mcp_servers_and_groups)),await (0,$.organizationCreateCall)(R,e),W.Z.success("Organization created successfully"),ec(!1),em.resetFields(),X(R,q)}catch(e){console.error("Error creating organization:",e)}};return J?(0,i.jsxs)("div",{className:"w-full mx-4 h-[75vh]",children:[(0,i.jsx)(d.Z,{numItems:1,className:"gap-2 p-8 w-full mt-2",children:(0,i.jsxs)(o.Z,{numColSpan:1,className:"flex flex-col gap-2",children:[("Admin"===s||"Org Admin"===s)&&(0,i.jsx)(t.Z,{className:"w-fit",onClick:()=>ec(!0),children:"+ Create New Organization"}),Q?(0,i.jsx)(H,{organizationId:Q,onClose:()=>{ee(null),es(!1)},accessToken:R,is_org_admin:!0,is_proxy_admin:"Admin"===s,userModels:L,editOrg:el}):(0,i.jsxs)(u.Z,{className:"gap-2 h-[75vh] w-full",children:[(0,i.jsxs)(x.Z,{className:"flex justify-between mt-2 w-full items-center",children:[(0,i.jsx)("div",{className:"flex",children:(0,i.jsx)(m.Z,{children:"Your Organizations"})}),(0,i.jsxs)("div",{className:"flex items-center space-x-2",children:[U&&(0,i.jsxs)(f.Z,{children:["Last Refreshed: ",U]}),(0,i.jsx)(c.Z,{icon:M.Z,variant:"shadow",size:"xs",className:"self-center",onClick:E})]})]}),(0,i.jsx)(_.Z,{children:(0,i.jsxs)(h.Z,{children:[(0,i.jsx)(f.Z,{children:"Click on “Organization ID” to view organization details."}),(0,i.jsx)(d.Z,{numItems:1,className:"gap-2 pt-2 pb-2 h-[75vh] w-full mt-2",children:(0,i.jsx)(o.Z,{numColSpan:1,children:(0,i.jsx)(n.Z,{className:"w-full mx-auto flex-auto overflow-y-auto max-h-[50vh]",children:(0,i.jsxs)(g.Z,{children:[(0,i.jsx)(v.Z,{children:(0,i.jsxs)(b.Z,{children:[(0,i.jsx)(Z.Z,{children:"Organization ID"}),(0,i.jsx)(Z.Z,{children:"Organization Name"}),(0,i.jsx)(Z.Z,{children:"Created"}),(0,i.jsx)(Z.Z,{children:"Spend (USD)"}),(0,i.jsx)(Z.Z,{children:"Budget (USD)"}),(0,i.jsx)(Z.Z,{children:"Models"}),(0,i.jsx)(Z.Z,{children:"TPM / RPM Limits"}),(0,i.jsx)(Z.Z,{children:"Info"}),(0,i.jsx)(Z.Z,{children:"Actions"})]})}),(0,i.jsx)(j.Z,{children:l&&l.length>0?l.sort((e,l)=>new Date(l.created_at).getTime()-new Date(e.created_at).getTime()).map(e=>{var l,a,n,o,d,m,u,x,h;return(0,i.jsxs)(b.Z,{children:[(0,i.jsx)(p.Z,{children:(0,i.jsx)("div",{className:"overflow-hidden",children:(0,i.jsx)(N.Z,{title:e.organization_id,children:(0,i.jsxs)(t.Z,{size:"xs",variant:"light",className:"font-mono text-blue-500 bg-blue-50 hover:bg-blue-100 text-xs font-normal px-2 py-0.5 text-left overflow-hidden truncate max-w-[200px]",onClick:()=>ee(e.organization_id),children:[null===(l=e.organization_id)||void 0===l?void 0:l.slice(0,7),"..."]})})})}),(0,i.jsx)(p.Z,{children:e.organization_alias}),(0,i.jsx)(p.Z,{children:e.created_at?new Date(e.created_at).toLocaleDateString():"N/A"}),(0,i.jsx)(p.Z,{children:(0,F.pw)(e.spend,4)}),(0,i.jsx)(p.Z,{children:(null===(a=e.litellm_budget_table)||void 0===a?void 0:a.max_budget)!==null&&(null===(n=e.litellm_budget_table)||void 0===n?void 0:n.max_budget)!==void 0?null===(o=e.litellm_budget_table)||void 0===o?void 0:o.max_budget:"No limit"}),(0,i.jsx)(p.Z,{style:{maxWidth:"8-x",whiteSpace:"pre-wrap",overflow:"hidden"},className:e.models.length>3?"px-0":"",children:(0,i.jsx)("div",{className:"flex flex-col",children:Array.isArray(e.models)?(0,i.jsx)("div",{className:"flex flex-col",children:0===e.models.length?(0,i.jsx)(r.Z,{size:"xs",className:"mb-1",color:"red",children:(0,i.jsx)(f.Z,{children:"All Proxy Models"})}):(0,i.jsx)(i.Fragment,{children:(0,i.jsxs)("div",{className:"flex items-start",children:[e.models.length>3&&(0,i.jsx)("div",{children:(0,i.jsx)(c.Z,{icon:eu[e.organization_id||""]?k.Z:I.Z,className:"cursor-pointer",size:"xs",onClick:()=>{ex(l=>({...l,[e.organization_id||""]:!l[e.organization_id||""]}))}})}),(0,i.jsxs)("div",{className:"flex flex-wrap gap-1",children:[e.models.slice(0,3).map((e,l)=>"all-proxy-models"===e?(0,i.jsx)(r.Z,{size:"xs",color:"red",children:(0,i.jsx)(f.Z,{children:"All Proxy Models"})},l):(0,i.jsx)(r.Z,{size:"xs",color:"blue",children:(0,i.jsx)(f.Z,{children:e.length>30?"".concat((0,D.W0)(e).slice(0,30),"..."):(0,D.W0)(e)})},l)),e.models.length>3&&!eu[e.organization_id||""]&&(0,i.jsx)(r.Z,{size:"xs",color:"gray",className:"cursor-pointer",children:(0,i.jsxs)(f.Z,{children:["+",e.models.length-3," ",e.models.length-3==1?"more model":"more models"]})}),eu[e.organization_id||""]&&(0,i.jsx)("div",{className:"flex flex-wrap gap-1",children:e.models.slice(3).map((e,l)=>"all-proxy-models"===e?(0,i.jsx)(r.Z,{size:"xs",color:"red",children:(0,i.jsx)(f.Z,{children:"All Proxy Models"})},l+3):(0,i.jsx)(r.Z,{size:"xs",color:"blue",children:(0,i.jsx)(f.Z,{children:e.length>30?"".concat((0,D.W0)(e).slice(0,30),"..."):(0,D.W0)(e)})},l+3))})]})]})})}):null})}),(0,i.jsx)(p.Z,{children:(0,i.jsxs)(f.Z,{children:["TPM:"," ",(null===(d=e.litellm_budget_table)||void 0===d?void 0:d.tpm_limit)?null===(m=e.litellm_budget_table)||void 0===m?void 0:m.tpm_limit:"Unlimited",(0,i.jsx)("br",{}),"RPM:"," ",(null===(u=e.litellm_budget_table)||void 0===u?void 0:u.rpm_limit)?null===(x=e.litellm_budget_table)||void 0===x?void 0:x.rpm_limit:"Unlimited"]})}),(0,i.jsx)(p.Z,{children:(0,i.jsxs)(f.Z,{children:[(null===(h=e.members)||void 0===h?void 0:h.length)||0," Members"]})}),(0,i.jsx)(p.Z,{children:"Admin"===s&&(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(N.Z,{title:"Edit organization",children:[" ",(0,i.jsx)(c.Z,{icon:P.Z,size:"sm",className:"cursor-pointer hover:text-blue-600",onClick:()=>{ee(e.organization_id),es(!0)}})]}),(0,i.jsxs)(N.Z,{title:"Delete organization",children:[" ",(0,i.jsx)(c.Z,{onClick:()=>eh(e.organization_id),icon:A.Z,size:"sm",className:"cursor-pointer hover:text-red-600"})]})]})})]},e.organization_id)}):null})]})})})})]})})]})]})}),(0,i.jsx)(C.Z,{title:"Create Organization",visible:ed,width:800,footer:null,onCancel:()=>{ec(!1),em.resetFields()},children:(0,i.jsxs)(y.Z,{form:em,onFinish:eg,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[(0,i.jsx)(y.Z.Item,{label:"Organization Name",name:"organization_alias",rules:[{required:!0,message:"Please input an organization name"}],children:(0,i.jsx)(T.o,{placeholder:""})}),(0,i.jsx)(y.Z.Item,{label:"Models",name:"models",children:(0,i.jsxs)(S.default,{mode:"multiple",placeholder:"Select models",style:{width:"100%"},children:[(0,i.jsx)(S.default.Option,{value:"all-proxy-models",children:"All Proxy Models"},"all-proxy-models"),L&&L.length>0&&L.map(e=>(0,i.jsx)(S.default.Option,{value:e,children:(0,D.W0)(e)},e))]})}),(0,i.jsx)(y.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,i.jsx)(w.Z,{step:.01,precision:2,width:200})}),(0,i.jsx)(y.Z.Item,{label:"Reset Budget",name:"budget_duration",children:(0,i.jsxs)(S.default,{defaultValue:null,placeholder:"n/a",children:[(0,i.jsx)(S.default.Option,{value:"24h",children:"daily"}),(0,i.jsx)(S.default.Option,{value:"7d",children:"weekly"}),(0,i.jsx)(S.default.Option,{value:"30d",children:"monthly"})]})}),(0,i.jsx)(y.Z.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,i.jsx)(w.Z,{step:1,width:400})}),(0,i.jsx)(y.Z.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,i.jsx)(w.Z,{step:1,width:400})}),(0,i.jsx)(y.Z.Item,{label:(0,i.jsxs)("span",{children:["Allowed Vector Stores"," ",(0,i.jsx)(N.Z,{title:"Select which vector stores this organization can access by default. Leave empty for access to all vector stores",children:(0,i.jsx)(O.Z,{style:{marginLeft:"4px"}})})]}),name:"allowed_vector_store_ids",className:"mt-4",help:"Select vector stores this organization can access. Leave empty for access to all vector stores",children:(0,i.jsx)(Y.Z,{onChange:e=>em.setFieldValue("allowed_vector_store_ids",e),value:em.getFieldValue("allowed_vector_store_ids"),accessToken:R||"",placeholder:"Select vector stores (optional)"})}),(0,i.jsx)(y.Z.Item,{label:(0,i.jsxs)("span",{children:["Allowed MCP Servers"," ",(0,i.jsx)(N.Z,{title:"Select which MCP servers and access groups this organization can access by default.",children:(0,i.jsx)(O.Z,{style:{marginLeft:"4px"}})})]}),name:"allowed_mcp_servers_and_groups",className:"mt-4",help:"Select MCP servers and access groups this organization can access.",children:(0,i.jsx)(G.Z,{onChange:e=>em.setFieldValue("allowed_mcp_servers_and_groups",e),value:em.getFieldValue("allowed_mcp_servers_and_groups"),accessToken:R||"",placeholder:"Select MCP servers and access groups (optional)"})}),(0,i.jsx)(y.Z.Item,{label:"Metadata",name:"metadata",children:(0,i.jsx)(z.default.TextArea,{rows:4})}),(0,i.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,i.jsx)(t.Z,{type:"submit",children:"Create Organization"})})]})}),(0,i.jsx)(K.Z,{isOpen:ei,title:"Delete Organization?",message:"Are you sure you want to delete this organization? This action cannot be undone.",resourceInformationTitle:"Organization Information",resourceInformation:[{label:"Organization ID",value:er,code:!0}],onCancel:()=>{ea(!1),et(null)},onOk:e_,confirmLoading:en})]}):(0,i.jsx)("div",{children:(0,i.jsxs)(f.Z,{children:["This is a LiteLLM Enterprise feature, and requires a valid key to use. Get a trial key"," ",(0,i.jsx)("a",{href:"https://www.litellm.ai/#pricing",target:"_blank",rel:"noopener noreferrer",children:"here"}),"."]})})}}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/2004-8b1ad3d8c195646a.js b/litellm/proxy/_experimental/out/_next/static/chunks/2004-8b1ad3d8c195646a.js deleted file mode 100644 index 59075bdbc32..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/2004-8b1ad3d8c195646a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[2004],{22004:function(e,l,s){s.d(l,{Z:function(){return ee},g:function(){return X}});var i=s(57437),a=s(2265),r=s(41649),t=s(78489),n=s(12514),o=s(49804),d=s(67101),c=s(47323),m=s(12485),u=s(18135),x=s(35242),h=s(29706),_=s(77991),g=s(21626),j=s(97214),p=s(28241),v=s(58834),Z=s(69552),b=s(71876),f=s(84264),w=s(24199),z=s(4260),y=s(10032),N=s(99981),C=s(22116),S=s(37592),O=s(15424),M=s(23628),k=s(86462),I=s(47686),P=s(53410),A=s(74998),T=s(31283),D=s(46468),F=s(59872),L=s(10900),R=s(49566),U=s(96761),E=s(5545),B=s(30401),V=s(78867),q=s(33860),G=s(95920),W=s(9114),$=s(19250),J=s(98015),Q=s(10901),Y=s(97415),H=e=>{var l,s,o,N,C;let{organizationId:O,onClose:M,accessToken:k,is_org_admin:I,is_proxy_admin:T,userModels:H,editOrg:K}=e,[X,ee]=(0,a.useState)(null),[el,es]=(0,a.useState)(!0),[ei]=y.Z.useForm(),[ea,er]=(0,a.useState)(!1),[et,en]=(0,a.useState)(!1),[eo,ed]=(0,a.useState)(!1),[ec,em]=(0,a.useState)(null),[eu,ex]=(0,a.useState)({}),eh=I||T,e_=async()=>{try{if(es(!0),!k)return;let e=await (0,$.organizationInfoCall)(k,O);ee(e)}catch(e){W.Z.fromBackend("Failed to load organization information"),console.error("Error fetching organization info:",e)}finally{es(!1)}};(0,a.useEffect)(()=>{e_()},[O,k]);let eg=async e=>{try{if(null==k)return;let l={user_email:e.user_email,user_id:e.user_id,role:e.role};await (0,$.organizationMemberAddCall)(k,O,l),W.Z.success("Organization member added successfully"),en(!1),ei.resetFields(),e_()}catch(e){W.Z.fromBackend("Failed to add organization member"),console.error("Error adding organization member:",e)}},ej=async e=>{try{if(!k)return;let l={user_email:e.user_email,user_id:e.user_id,role:e.role};await (0,$.organizationMemberUpdateCall)(k,O,l),W.Z.success("Organization member updated successfully"),ed(!1),ei.resetFields(),e_()}catch(e){W.Z.fromBackend("Failed to update organization member"),console.error("Error updating organization member:",e)}},ep=async e=>{try{if(!k)return;await (0,$.organizationMemberDeleteCall)(k,O,e.user_id),W.Z.success("Organization member deleted successfully"),ed(!1),ei.resetFields(),e_()}catch(e){W.Z.fromBackend("Failed to delete organization member"),console.error("Error deleting organization member:",e)}},ev=async e=>{try{if(!k)return;let l={organization_id:O,organization_alias:e.organization_alias,models:e.models,litellm_budget_table:{tpm_limit:e.tpm_limit,rpm_limit:e.rpm_limit,max_budget:e.max_budget,budget_duration:e.budget_duration},metadata:e.metadata?JSON.parse(e.metadata):null};if((void 0!==e.vector_stores||void 0!==e.mcp_servers_and_groups)&&(l.object_permission={...null==X?void 0:X.object_permission,vector_stores:e.vector_stores||[]},void 0!==e.mcp_servers_and_groups)){let{servers:s,accessGroups:i}=e.mcp_servers_and_groups||{servers:[],accessGroups:[]};s&&s.length>0&&(l.object_permission.mcp_servers=s),i&&i.length>0&&(l.object_permission.mcp_access_groups=i)}await (0,$.organizationUpdateCall)(k,l),W.Z.success("Organization settings updated successfully"),er(!1),e_()}catch(e){W.Z.fromBackend("Failed to update organization settings"),console.error("Error updating organization:",e)}};if(el)return(0,i.jsx)("div",{className:"p-4",children:"Loading..."});if(!X)return(0,i.jsx)("div",{className:"p-4",children:"Organization not found"});let eZ=async(e,l)=>{await (0,F.vQ)(e)&&(ex(e=>({...e,[l]:!0})),setTimeout(()=>{ex(e=>({...e,[l]:!1}))},2e3))};return(0,i.jsxs)("div",{className:"w-full h-screen p-4 bg-white",children:[(0,i.jsx)("div",{className:"flex justify-between items-center mb-6",children:(0,i.jsxs)("div",{children:[(0,i.jsx)(t.Z,{icon:L.Z,onClick:M,variant:"light",className:"mb-4",children:"Back to Organizations"}),(0,i.jsx)(U.Z,{children:X.organization_alias}),(0,i.jsxs)("div",{className:"flex items-center cursor-pointer",children:[(0,i.jsx)(f.Z,{className:"text-gray-500 font-mono",children:X.organization_id}),(0,i.jsx)(E.ZP,{type:"text",size:"small",icon:eu["org-id"]?(0,i.jsx)(B.Z,{size:12}):(0,i.jsx)(V.Z,{size:12}),onClick:()=>eZ(X.organization_id,"org-id"),className:"left-2 z-10 transition-all duration-200 ".concat(eu["org-id"]?"text-green-600 bg-green-50 border-green-200":"text-gray-500 hover:text-gray-700 hover:bg-gray-100")})]})]})}),(0,i.jsxs)(u.Z,{defaultIndex:K?2:0,children:[(0,i.jsxs)(x.Z,{className:"mb-4",children:[(0,i.jsx)(m.Z,{children:"Overview"}),(0,i.jsx)(m.Z,{children:"Members"}),(0,i.jsx)(m.Z,{children:"Settings"})]}),(0,i.jsxs)(_.Z,{children:[(0,i.jsx)(h.Z,{children:(0,i.jsxs)(d.Z,{numItems:1,numItemsSm:2,numItemsLg:3,className:"gap-6",children:[(0,i.jsxs)(n.Z,{children:[(0,i.jsx)(f.Z,{children:"Organization Details"}),(0,i.jsxs)("div",{className:"mt-2",children:[(0,i.jsxs)(f.Z,{children:["Created: ",new Date(X.created_at).toLocaleDateString()]}),(0,i.jsxs)(f.Z,{children:["Updated: ",new Date(X.updated_at).toLocaleDateString()]}),(0,i.jsxs)(f.Z,{children:["Created By: ",X.created_by]})]})]}),(0,i.jsxs)(n.Z,{children:[(0,i.jsx)(f.Z,{children:"Budget Status"}),(0,i.jsxs)("div",{className:"mt-2",children:[(0,i.jsxs)(U.Z,{children:["$",(0,F.pw)(X.spend,4)]}),(0,i.jsxs)(f.Z,{children:["of"," ",null===X.litellm_budget_table.max_budget?"Unlimited":"$".concat((0,F.pw)(X.litellm_budget_table.max_budget,4))]}),X.litellm_budget_table.budget_duration&&(0,i.jsxs)(f.Z,{className:"text-gray-500",children:["Reset: ",X.litellm_budget_table.budget_duration]})]})]}),(0,i.jsxs)(n.Z,{children:[(0,i.jsx)(f.Z,{children:"Rate Limits"}),(0,i.jsxs)("div",{className:"mt-2",children:[(0,i.jsxs)(f.Z,{children:["TPM: ",X.litellm_budget_table.tpm_limit||"Unlimited"]}),(0,i.jsxs)(f.Z,{children:["RPM: ",X.litellm_budget_table.rpm_limit||"Unlimited"]}),X.litellm_budget_table.max_parallel_requests&&(0,i.jsxs)(f.Z,{children:["Max Parallel Requests: ",X.litellm_budget_table.max_parallel_requests]})]})]}),(0,i.jsxs)(n.Z,{children:[(0,i.jsx)(f.Z,{children:"Models"}),(0,i.jsx)("div",{className:"mt-2 flex flex-wrap gap-2",children:0===X.models.length?(0,i.jsx)(r.Z,{color:"red",children:"All proxy models"}):X.models.map((e,l)=>(0,i.jsx)(r.Z,{color:"red",children:e},l))})]}),(0,i.jsxs)(n.Z,{children:[(0,i.jsx)(f.Z,{children:"Teams"}),(0,i.jsx)("div",{className:"mt-2 flex flex-wrap gap-2",children:null===(l=X.teams)||void 0===l?void 0:l.map((e,l)=>(0,i.jsx)(r.Z,{color:"red",children:e.team_id},l))})]}),(0,i.jsx)(J.Z,{objectPermission:X.object_permission,variant:"card",accessToken:k})]})}),(0,i.jsx)(h.Z,{children:(0,i.jsxs)("div",{className:"space-y-4",children:[(0,i.jsx)(n.Z,{className:"w-full mx-auto flex-auto overflow-y-auto max-h-[75vh]",children:(0,i.jsxs)(g.Z,{children:[(0,i.jsx)(v.Z,{children:(0,i.jsxs)(b.Z,{children:[(0,i.jsx)(Z.Z,{children:"User ID"}),(0,i.jsx)(Z.Z,{children:"Role"}),(0,i.jsx)(Z.Z,{children:"Spend"}),(0,i.jsx)(Z.Z,{children:"Created At"}),(0,i.jsx)(Z.Z,{})]})}),(0,i.jsx)(j.Z,{children:null===(s=X.members)||void 0===s?void 0:s.map((e,l)=>(0,i.jsxs)(b.Z,{children:[(0,i.jsx)(p.Z,{children:(0,i.jsx)(f.Z,{className:"font-mono",children:e.user_id})}),(0,i.jsx)(p.Z,{children:(0,i.jsx)(f.Z,{className:"font-mono",children:e.user_role})}),(0,i.jsx)(p.Z,{children:(0,i.jsxs)(f.Z,{children:["$",(0,F.pw)(e.spend,4)]})}),(0,i.jsx)(p.Z,{children:(0,i.jsx)(f.Z,{children:new Date(e.created_at).toLocaleString()})}),(0,i.jsx)(p.Z,{children:eh&&(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(c.Z,{icon:P.Z,size:"sm",onClick:()=>{em({role:e.user_role,user_email:e.user_email,user_id:e.user_id}),ed(!0)}}),(0,i.jsx)(c.Z,{icon:A.Z,size:"sm",onClick:()=>{ep(e)}})]})})]},l))})]})}),eh&&(0,i.jsx)(t.Z,{onClick:()=>{en(!0)},children:"Add Member"})]})}),(0,i.jsx)(h.Z,{children:(0,i.jsxs)(n.Z,{className:"overflow-y-auto max-h-[65vh]",children:[(0,i.jsxs)("div",{className:"flex justify-between items-center mb-4",children:[(0,i.jsx)(U.Z,{children:"Organization Settings"}),eh&&!ea&&(0,i.jsx)(t.Z,{onClick:()=>er(!0),children:"Edit Settings"})]}),ea?(0,i.jsxs)(y.Z,{form:ei,onFinish:ev,initialValues:{organization_alias:X.organization_alias,models:X.models,tpm_limit:X.litellm_budget_table.tpm_limit,rpm_limit:X.litellm_budget_table.rpm_limit,max_budget:X.litellm_budget_table.max_budget,budget_duration:X.litellm_budget_table.budget_duration,metadata:X.metadata?JSON.stringify(X.metadata,null,2):"",vector_stores:(null===(o=X.object_permission)||void 0===o?void 0:o.vector_stores)||[],mcp_servers_and_groups:{servers:(null===(N=X.object_permission)||void 0===N?void 0:N.mcp_servers)||[],accessGroups:(null===(C=X.object_permission)||void 0===C?void 0:C.mcp_access_groups)||[]}},layout:"vertical",children:[(0,i.jsx)(y.Z.Item,{label:"Organization Name",name:"organization_alias",rules:[{required:!0,message:"Please input an organization name"}],children:(0,i.jsx)(R.Z,{})}),(0,i.jsx)(y.Z.Item,{label:"Models",name:"models",children:(0,i.jsxs)(S.default,{mode:"multiple",placeholder:"Select models",children:[(0,i.jsx)(S.default.Option,{value:"all-proxy-models",children:"All Proxy Models"},"all-proxy-models"),H.map(e=>(0,i.jsx)(S.default.Option,{value:e,children:(0,D.W0)(e)},e))]})}),(0,i.jsx)(y.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,i.jsx)(w.Z,{step:.01,precision:2,style:{width:"100%"}})}),(0,i.jsx)(y.Z.Item,{label:"Reset Budget",name:"budget_duration",children:(0,i.jsxs)(S.default,{placeholder:"n/a",children:[(0,i.jsx)(S.default.Option,{value:"24h",children:"daily"}),(0,i.jsx)(S.default.Option,{value:"7d",children:"weekly"}),(0,i.jsx)(S.default.Option,{value:"30d",children:"monthly"})]})}),(0,i.jsx)(y.Z.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,i.jsx)(w.Z,{step:1,style:{width:"100%"}})}),(0,i.jsx)(y.Z.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,i.jsx)(w.Z,{step:1,style:{width:"100%"}})}),(0,i.jsx)(y.Z.Item,{label:"Vector Stores",name:"vector_stores",children:(0,i.jsx)(Y.Z,{onChange:e=>ei.setFieldValue("vector_stores",e),value:ei.getFieldValue("vector_stores"),accessToken:k||"",placeholder:"Select vector stores"})}),(0,i.jsx)(y.Z.Item,{label:"MCP Servers & Access Groups",name:"mcp_servers_and_groups",children:(0,i.jsx)(G.Z,{onChange:e=>ei.setFieldValue("mcp_servers_and_groups",e),value:ei.getFieldValue("mcp_servers_and_groups"),accessToken:k||"",placeholder:"Select MCP servers and access groups"})}),(0,i.jsx)(y.Z.Item,{label:"Metadata",name:"metadata",children:(0,i.jsx)(z.default.TextArea,{rows:4})}),(0,i.jsx)("div",{className:"sticky z-10 bg-white p-4 border-t border-gray-200 bottom-[-1.5rem] inset-x-[-1.5rem]",children:(0,i.jsxs)("div",{className:"flex justify-end items-center gap-2",children:[(0,i.jsx)(t.Z,{variant:"secondary",onClick:()=>er(!1),children:"Cancel"}),(0,i.jsx)(t.Z,{type:"submit",children:"Save Changes"})]})})]}):(0,i.jsxs)("div",{className:"space-y-4",children:[(0,i.jsxs)("div",{children:[(0,i.jsx)(f.Z,{className:"font-medium",children:"Organization Name"}),(0,i.jsx)("div",{children:X.organization_alias})]}),(0,i.jsxs)("div",{children:[(0,i.jsx)(f.Z,{className:"font-medium",children:"Organization ID"}),(0,i.jsx)("div",{className:"font-mono",children:X.organization_id})]}),(0,i.jsxs)("div",{children:[(0,i.jsx)(f.Z,{className:"font-medium",children:"Created At"}),(0,i.jsx)("div",{children:new Date(X.created_at).toLocaleString()})]}),(0,i.jsxs)("div",{children:[(0,i.jsx)(f.Z,{className:"font-medium",children:"Models"}),(0,i.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:X.models.map((e,l)=>(0,i.jsx)(r.Z,{color:"red",children:e},l))})]}),(0,i.jsxs)("div",{children:[(0,i.jsx)(f.Z,{className:"font-medium",children:"Rate Limits"}),(0,i.jsxs)("div",{children:["TPM: ",X.litellm_budget_table.tpm_limit||"Unlimited"]}),(0,i.jsxs)("div",{children:["RPM: ",X.litellm_budget_table.rpm_limit||"Unlimited"]})]}),(0,i.jsxs)("div",{children:[(0,i.jsx)(f.Z,{className:"font-medium",children:"Budget"}),(0,i.jsxs)("div",{children:["Max:"," ",null!==X.litellm_budget_table.max_budget?"$".concat((0,F.pw)(X.litellm_budget_table.max_budget,4)):"No Limit"]}),(0,i.jsxs)("div",{children:["Reset: ",X.litellm_budget_table.budget_duration||"Never"]})]}),(0,i.jsx)(J.Z,{objectPermission:X.object_permission,variant:"inline",className:"pt-4 border-t border-gray-200",accessToken:k})]})]})})]})]}),(0,i.jsx)(q.Z,{isVisible:et,onCancel:()=>en(!1),onSubmit:eg,accessToken:k,title:"Add Organization Member",roles:[{label:"org_admin",value:"org_admin",description:"Can add and remove members, and change their roles."},{label:"internal_user",value:"internal_user",description:"Can view/create keys for themselves within organization."},{label:"internal_user_viewer",value:"internal_user_viewer",description:"Can only view their keys within organization."}],defaultRole:"internal_user"}),(0,i.jsx)(Q.Z,{visible:eo,onCancel:()=>ed(!1),onSubmit:ej,initialData:ec,mode:"edit",config:{title:"Edit Member",showEmail:!0,showUserId:!0,roleOptions:[{label:"Org Admin",value:"org_admin"},{label:"Internal User",value:"internal_user"},{label:"Internal User Viewer",value:"internal_user_viewer"}]}})]})},K=s(21609);let X=async(e,l)=>{l(await (0,$.organizationListCall)(e))};var ee=e=>{let{organizations:l,userRole:s,userModels:L,accessToken:R,lastRefreshed:U,handleRefreshClick:E,currentOrg:B,guardrailsList:V=[],setOrganizations:q,premiumUser:J}=e,[Q,ee]=(0,a.useState)(null),[el,es]=(0,a.useState)(!1),[ei,ea]=(0,a.useState)(!1),[er,et]=(0,a.useState)(null),[en,eo]=(0,a.useState)(!1),[ed,ec]=(0,a.useState)(!1),[em]=y.Z.useForm(),[eu,ex]=(0,a.useState)({});(0,a.useEffect)(()=>{R&&X(R,q)},[R]);let eh=e=>{e&&(et(e),ea(!0))},e_=async()=>{if(er&&R)try{eo(!0),await (0,$.organizationDeleteCall)(R,er),W.Z.success("Organization deleted successfully"),ea(!1),et(null),await X(R,q)}catch(e){console.error("Error deleting organization:",e)}finally{eo(!1)}},eg=async e=>{try{var l,s,i,a;if(!R)return;console.log("values in organizations new create call: ".concat(JSON.stringify(e))),(e.allowed_vector_store_ids&&e.allowed_vector_store_ids.length>0||e.allowed_mcp_servers_and_groups&&((null===(l=e.allowed_mcp_servers_and_groups.servers)||void 0===l?void 0:l.length)>0||(null===(s=e.allowed_mcp_servers_and_groups.accessGroups)||void 0===s?void 0:s.length)>0))&&(e.object_permission={},e.allowed_vector_store_ids&&e.allowed_vector_store_ids.length>0&&(e.object_permission.vector_stores=e.allowed_vector_store_ids,delete e.allowed_vector_store_ids),e.allowed_mcp_servers_and_groups&&((null===(i=e.allowed_mcp_servers_and_groups.servers)||void 0===i?void 0:i.length)>0&&(e.object_permission.mcp_servers=e.allowed_mcp_servers_and_groups.servers),(null===(a=e.allowed_mcp_servers_and_groups.accessGroups)||void 0===a?void 0:a.length)>0&&(e.object_permission.mcp_access_groups=e.allowed_mcp_servers_and_groups.accessGroups),delete e.allowed_mcp_servers_and_groups)),await (0,$.organizationCreateCall)(R,e),W.Z.success("Organization created successfully"),ec(!1),em.resetFields(),X(R,q)}catch(e){console.error("Error creating organization:",e)}};return J?(0,i.jsxs)("div",{className:"w-full mx-4 h-[75vh]",children:[(0,i.jsx)(d.Z,{numItems:1,className:"gap-2 p-8 w-full mt-2",children:(0,i.jsxs)(o.Z,{numColSpan:1,className:"flex flex-col gap-2",children:[("Admin"===s||"Org Admin"===s)&&(0,i.jsx)(t.Z,{className:"w-fit",onClick:()=>ec(!0),children:"+ Create New Organization"}),Q?(0,i.jsx)(H,{organizationId:Q,onClose:()=>{ee(null),es(!1)},accessToken:R,is_org_admin:!0,is_proxy_admin:"Admin"===s,userModels:L,editOrg:el}):(0,i.jsxs)(u.Z,{className:"gap-2 h-[75vh] w-full",children:[(0,i.jsxs)(x.Z,{className:"flex justify-between mt-2 w-full items-center",children:[(0,i.jsx)("div",{className:"flex",children:(0,i.jsx)(m.Z,{children:"Your Organizations"})}),(0,i.jsxs)("div",{className:"flex items-center space-x-2",children:[U&&(0,i.jsxs)(f.Z,{children:["Last Refreshed: ",U]}),(0,i.jsx)(c.Z,{icon:M.Z,variant:"shadow",size:"xs",className:"self-center",onClick:E})]})]}),(0,i.jsx)(_.Z,{children:(0,i.jsxs)(h.Z,{children:[(0,i.jsx)(f.Z,{children:"Click on “Organization ID” to view organization details."}),(0,i.jsx)(d.Z,{numItems:1,className:"gap-2 pt-2 pb-2 h-[75vh] w-full mt-2",children:(0,i.jsx)(o.Z,{numColSpan:1,children:(0,i.jsx)(n.Z,{className:"w-full mx-auto flex-auto overflow-y-auto max-h-[50vh]",children:(0,i.jsxs)(g.Z,{children:[(0,i.jsx)(v.Z,{children:(0,i.jsxs)(b.Z,{children:[(0,i.jsx)(Z.Z,{children:"Organization ID"}),(0,i.jsx)(Z.Z,{children:"Organization Name"}),(0,i.jsx)(Z.Z,{children:"Created"}),(0,i.jsx)(Z.Z,{children:"Spend (USD)"}),(0,i.jsx)(Z.Z,{children:"Budget (USD)"}),(0,i.jsx)(Z.Z,{children:"Models"}),(0,i.jsx)(Z.Z,{children:"TPM / RPM Limits"}),(0,i.jsx)(Z.Z,{children:"Info"}),(0,i.jsx)(Z.Z,{children:"Actions"})]})}),(0,i.jsx)(j.Z,{children:l&&l.length>0?l.sort((e,l)=>new Date(l.created_at).getTime()-new Date(e.created_at).getTime()).map(e=>{var l,a,n,o,d,m,u,x,h;return(0,i.jsxs)(b.Z,{children:[(0,i.jsx)(p.Z,{children:(0,i.jsx)("div",{className:"overflow-hidden",children:(0,i.jsx)(N.Z,{title:e.organization_id,children:(0,i.jsxs)(t.Z,{size:"xs",variant:"light",className:"font-mono text-blue-500 bg-blue-50 hover:bg-blue-100 text-xs font-normal px-2 py-0.5 text-left overflow-hidden truncate max-w-[200px]",onClick:()=>ee(e.organization_id),children:[null===(l=e.organization_id)||void 0===l?void 0:l.slice(0,7),"..."]})})})}),(0,i.jsx)(p.Z,{children:e.organization_alias}),(0,i.jsx)(p.Z,{children:e.created_at?new Date(e.created_at).toLocaleDateString():"N/A"}),(0,i.jsx)(p.Z,{children:(0,F.pw)(e.spend,4)}),(0,i.jsx)(p.Z,{children:(null===(a=e.litellm_budget_table)||void 0===a?void 0:a.max_budget)!==null&&(null===(n=e.litellm_budget_table)||void 0===n?void 0:n.max_budget)!==void 0?null===(o=e.litellm_budget_table)||void 0===o?void 0:o.max_budget:"No limit"}),(0,i.jsx)(p.Z,{style:{maxWidth:"8-x",whiteSpace:"pre-wrap",overflow:"hidden"},className:e.models.length>3?"px-0":"",children:(0,i.jsx)("div",{className:"flex flex-col",children:Array.isArray(e.models)?(0,i.jsx)("div",{className:"flex flex-col",children:0===e.models.length?(0,i.jsx)(r.Z,{size:"xs",className:"mb-1",color:"red",children:(0,i.jsx)(f.Z,{children:"All Proxy Models"})}):(0,i.jsx)(i.Fragment,{children:(0,i.jsxs)("div",{className:"flex items-start",children:[e.models.length>3&&(0,i.jsx)("div",{children:(0,i.jsx)(c.Z,{icon:eu[e.organization_id||""]?k.Z:I.Z,className:"cursor-pointer",size:"xs",onClick:()=>{ex(l=>({...l,[e.organization_id||""]:!l[e.organization_id||""]}))}})}),(0,i.jsxs)("div",{className:"flex flex-wrap gap-1",children:[e.models.slice(0,3).map((e,l)=>"all-proxy-models"===e?(0,i.jsx)(r.Z,{size:"xs",color:"red",children:(0,i.jsx)(f.Z,{children:"All Proxy Models"})},l):(0,i.jsx)(r.Z,{size:"xs",color:"blue",children:(0,i.jsx)(f.Z,{children:e.length>30?"".concat((0,D.W0)(e).slice(0,30),"..."):(0,D.W0)(e)})},l)),e.models.length>3&&!eu[e.organization_id||""]&&(0,i.jsx)(r.Z,{size:"xs",color:"gray",className:"cursor-pointer",children:(0,i.jsxs)(f.Z,{children:["+",e.models.length-3," ",e.models.length-3==1?"more model":"more models"]})}),eu[e.organization_id||""]&&(0,i.jsx)("div",{className:"flex flex-wrap gap-1",children:e.models.slice(3).map((e,l)=>"all-proxy-models"===e?(0,i.jsx)(r.Z,{size:"xs",color:"red",children:(0,i.jsx)(f.Z,{children:"All Proxy Models"})},l+3):(0,i.jsx)(r.Z,{size:"xs",color:"blue",children:(0,i.jsx)(f.Z,{children:e.length>30?"".concat((0,D.W0)(e).slice(0,30),"..."):(0,D.W0)(e)})},l+3))})]})]})})}):null})}),(0,i.jsx)(p.Z,{children:(0,i.jsxs)(f.Z,{children:["TPM:"," ",(null===(d=e.litellm_budget_table)||void 0===d?void 0:d.tpm_limit)?null===(m=e.litellm_budget_table)||void 0===m?void 0:m.tpm_limit:"Unlimited",(0,i.jsx)("br",{}),"RPM:"," ",(null===(u=e.litellm_budget_table)||void 0===u?void 0:u.rpm_limit)?null===(x=e.litellm_budget_table)||void 0===x?void 0:x.rpm_limit:"Unlimited"]})}),(0,i.jsx)(p.Z,{children:(0,i.jsxs)(f.Z,{children:[(null===(h=e.members)||void 0===h?void 0:h.length)||0," Members"]})}),(0,i.jsx)(p.Z,{children:"Admin"===s&&(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(N.Z,{title:"Edit organization",children:[" ",(0,i.jsx)(c.Z,{icon:P.Z,size:"sm",className:"cursor-pointer hover:text-blue-600",onClick:()=>{ee(e.organization_id),es(!0)}})]}),(0,i.jsxs)(N.Z,{title:"Delete organization",children:[" ",(0,i.jsx)(c.Z,{onClick:()=>eh(e.organization_id),icon:A.Z,size:"sm",className:"cursor-pointer hover:text-red-600"})]})]})})]},e.organization_id)}):null})]})})})})]})})]})]})}),(0,i.jsx)(C.Z,{title:"Create Organization",visible:ed,width:800,footer:null,onCancel:()=>{ec(!1),em.resetFields()},children:(0,i.jsxs)(y.Z,{form:em,onFinish:eg,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[(0,i.jsx)(y.Z.Item,{label:"Organization Name",name:"organization_alias",rules:[{required:!0,message:"Please input an organization name"}],children:(0,i.jsx)(T.o,{placeholder:""})}),(0,i.jsx)(y.Z.Item,{label:"Models",name:"models",children:(0,i.jsxs)(S.default,{mode:"multiple",placeholder:"Select models",style:{width:"100%"},children:[(0,i.jsx)(S.default.Option,{value:"all-proxy-models",children:"All Proxy Models"},"all-proxy-models"),L&&L.length>0&&L.map(e=>(0,i.jsx)(S.default.Option,{value:e,children:(0,D.W0)(e)},e))]})}),(0,i.jsx)(y.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,i.jsx)(w.Z,{step:.01,precision:2,width:200})}),(0,i.jsx)(y.Z.Item,{label:"Reset Budget",name:"budget_duration",children:(0,i.jsxs)(S.default,{defaultValue:null,placeholder:"n/a",children:[(0,i.jsx)(S.default.Option,{value:"24h",children:"daily"}),(0,i.jsx)(S.default.Option,{value:"7d",children:"weekly"}),(0,i.jsx)(S.default.Option,{value:"30d",children:"monthly"})]})}),(0,i.jsx)(y.Z.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,i.jsx)(w.Z,{step:1,width:400})}),(0,i.jsx)(y.Z.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,i.jsx)(w.Z,{step:1,width:400})}),(0,i.jsx)(y.Z.Item,{label:(0,i.jsxs)("span",{children:["Allowed Vector Stores"," ",(0,i.jsx)(N.Z,{title:"Select which vector stores this organization can access by default. Leave empty for access to all vector stores",children:(0,i.jsx)(O.Z,{style:{marginLeft:"4px"}})})]}),name:"allowed_vector_store_ids",className:"mt-4",help:"Select vector stores this organization can access. Leave empty for access to all vector stores",children:(0,i.jsx)(Y.Z,{onChange:e=>em.setFieldValue("allowed_vector_store_ids",e),value:em.getFieldValue("allowed_vector_store_ids"),accessToken:R||"",placeholder:"Select vector stores (optional)"})}),(0,i.jsx)(y.Z.Item,{label:(0,i.jsxs)("span",{children:["Allowed MCP Servers"," ",(0,i.jsx)(N.Z,{title:"Select which MCP servers and access groups this organization can access by default.",children:(0,i.jsx)(O.Z,{style:{marginLeft:"4px"}})})]}),name:"allowed_mcp_servers_and_groups",className:"mt-4",help:"Select MCP servers and access groups this organization can access.",children:(0,i.jsx)(G.Z,{onChange:e=>em.setFieldValue("allowed_mcp_servers_and_groups",e),value:em.getFieldValue("allowed_mcp_servers_and_groups"),accessToken:R||"",placeholder:"Select MCP servers and access groups (optional)"})}),(0,i.jsx)(y.Z.Item,{label:"Metadata",name:"metadata",children:(0,i.jsx)(z.default.TextArea,{rows:4})}),(0,i.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,i.jsx)(t.Z,{type:"submit",children:"Create Organization"})})]})}),(0,i.jsx)(K.Z,{isOpen:ei,title:"Delete Organization?",message:"Are you sure you want to delete this organization? This action cannot be undone.",resourceInformationTitle:"Organization Information",resourceInformation:[{label:"Organization ID",value:er,code:!0}],onCancel:()=>{ea(!1),et(null)},onOk:e_,confirmLoading:en})]}):(0,i.jsx)("div",{children:(0,i.jsxs)(f.Z,{children:["This is a LiteLLM Enterprise feature, and requires a valid key to use. Get a trial key"," ",(0,i.jsx)("a",{href:"https://www.litellm.ai/#pricing",target:"_blank",rel:"noopener noreferrer",children:"here"}),"."]})})}}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/2012-9200c205d5b0405a.js b/litellm/proxy/_experimental/out/_next/static/chunks/2012-9200c205d5b0405a.js deleted file mode 100644 index 600ee05936e..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/2012-9200c205d5b0405a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[2012],{26210:function(e,l,s){s.d(l,{UQ:function(){return t.Z},X1:function(){return i.Z},_m:function(){return a.Z},oi:function(){return n.Z},xv:function(){return r.Z}});var t=s(87452),i=s(88829),a=s(72208),r=s(84264),n=s(49566)},30078:function(e,l,s){s.d(l,{Ct:function(){return t.Z},Dx:function(){return x.Z},OK:function(){return n.Z},Zb:function(){return a.Z},nP:function(){return c.Z},oi:function(){return h.Z},rj:function(){return r.Z},td:function(){return d.Z},v0:function(){return m.Z},x4:function(){return o.Z},xv:function(){return u.Z},zx:function(){return i.Z}});var t=s(41649),i=s(78489),a=s(12514),r=s(67101),n=s(12485),m=s(18135),d=s(35242),o=s(29706),c=s(77991),u=s(84264),h=s(49566),x=s(96761)},62490:function(e,l,s){s.d(l,{Ct:function(){return t.Z},RM:function(){return n.Z},SC:function(){return c.Z},Zb:function(){return a.Z},iA:function(){return r.Z},pj:function(){return m.Z},ss:function(){return d.Z},xs:function(){return o.Z},xv:function(){return u.Z},zx:function(){return i.Z}});var t=s(41649),i=s(78489),a=s(12514),r=s(21626),n=s(97214),m=s(28241),d=s(58834),o=s(69552),c=s(71876),u=s(84264)},11318:function(e,l,s){s.d(l,{Z:function(){return n}});var t=s(2265),i=s(80443),a=s(19250);let r=async(e,l,s,t)=>"Admin"!=s&&"Admin Viewer"!=s?await (0,a.teamListCall)(e,(null==t?void 0:t.organization_id)||null,l):await (0,a.teamListCall)(e,(null==t?void 0:t.organization_id)||null);var n=()=>{let[e,l]=(0,t.useState)([]),{accessToken:s,userId:a,userRole:n}=(0,i.Z)();return(0,t.useEffect)(()=>{(async()=>{l(await r(s,a,n,null))})()},[s,a,n]),{teams:e,setTeams:l}}},21609:function(e,l,s){s.d(l,{Z:function(){return o}});var t=s(57437),i=s(57840),a=s(22116),r=s(51653),n=s(76188),m=s(4260),d=s(2265);function o(e){let{isOpen:l,title:s,alertMessage:o,message:c,resourceInformationTitle:u,resourceInformation:h,onCancel:x,onOk:b,confirmLoading:p,requiredConfirmation:g}=e,{Title:_,Text:v}=i.default,[j,f]=(0,d.useState)("");return(0,d.useEffect)(()=>{l&&f("")},[l]),(0,t.jsx)(a.Z,{title:s,open:l,onOk:b,onCancel:x,confirmLoading:p,okText:p?"Deleting...":"Delete",cancelText:"Cancel",okButtonProps:{danger:!0,disabled:!!g&&j!==g||p},cancelButtonProps:{disabled:p},children:(0,t.jsxs)("div",{className:"space-y-4",children:[o&&(0,t.jsx)(r.Z,{message:o,type:"warning"}),(0,t.jsxs)("div",{className:"mt-4 p-4 bg-red-50 rounded-lg border border-red-200",children:[(0,t.jsx)(_,{level:5,className:"mb-3 text-gray-900",children:u}),(0,t.jsx)(n.Z,{column:1,size:"small",children:h&&h.map(e=>{let{label:l,value:s,...i}=e;return(0,t.jsx)(n.Z.Item,{label:(0,t.jsx)("span",{className:"font-semibold text-gray-700",children:l}),children:(0,t.jsx)(v,{...i,children:null!=s?s:"-"})},l)})})]}),(0,t.jsx)("div",{children:(0,t.jsx)(v,{children:c})}),g&&(0,t.jsxs)("div",{className:"mb-6 mt-4 pt-4 border-t border-gray-200",children:[(0,t.jsxs)(v,{className:"block text-base font-medium text-gray-700 mb-2",children:[(0,t.jsx)(v,{children:"Type "}),(0,t.jsx)(v,{strong:!0,type:"danger",children:g}),(0,t.jsx)(v,{children:" to confirm deletion:"})]}),(0,t.jsx)(m.default,{value:j,onChange:e=>f(e.target.value),placeholder:g,className:"rounded-md text-base border-gray-200",autoFocus:!0})]})]})})}},33860:function(e,l,s){var t=s(57437),i=s(2265),a=s(10032),r=s(22116),n=s(37592),m=s(99981),d=s(5545),o=s(7310),c=s.n(o),u=s(19250);l.Z=e=>{let{isVisible:l,onCancel:s,onSubmit:o,accessToken:h,title:x="Add Team Member",roles:b=[{label:"admin",value:"admin",description:"Admin role. Can create team keys, add members, and manage settings."},{label:"user",value:"user",description:"User role. Can view team info, but not manage it."}],defaultRole:p="user"}=e,[g]=a.Z.useForm(),[_,v]=(0,i.useState)([]),[j,f]=(0,i.useState)(!1),[Z,y]=(0,i.useState)("user_email"),N=async(e,l)=>{if(!e){v([]);return}f(!0);try{let s=new URLSearchParams;if(s.append(l,e),null==h)return;let t=(await (0,u.userFilterUICall)(h,s)).map(e=>({label:"user_email"===l?"".concat(e.user_email):"".concat(e.user_id),value:"user_email"===l?e.user_email:e.user_id,user:e}));v(t)}catch(e){console.error("Error fetching users:",e)}finally{f(!1)}},w=(0,i.useCallback)(c()((e,l)=>N(e,l),300),[]),k=(e,l)=>{y(l),w(e,l)},M=(e,l)=>{let s=l.user;g.setFieldsValue({user_email:s.user_email,user_id:s.user_id,role:g.getFieldValue("role")})};return(0,t.jsx)(r.Z,{title:x,open:l,onCancel:()=>{g.resetFields(),v([]),s()},footer:null,width:800,children:(0,t.jsxs)(a.Z,{form:g,onFinish:o,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",initialValues:{role:p},children:[(0,t.jsx)(a.Z.Item,{label:"Email",name:"user_email",className:"mb-4",children:(0,t.jsx)(n.default,{showSearch:!0,className:"w-full",placeholder:"Search by email",filterOption:!1,onSearch:e=>k(e,"user_email"),onSelect:(e,l)=>M(e,l),options:"user_email"===Z?_:[],loading:j,allowClear:!0})}),(0,t.jsx)("div",{className:"text-center mb-4",children:"OR"}),(0,t.jsx)(a.Z.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,t.jsx)(n.default,{showSearch:!0,className:"w-full",placeholder:"Search by user ID",filterOption:!1,onSearch:e=>k(e,"user_id"),onSelect:(e,l)=>M(e,l),options:"user_id"===Z?_:[],loading:j,allowClear:!0})}),(0,t.jsx)(a.Z.Item,{label:"Member Role",name:"role",className:"mb-4",children:(0,t.jsx)(n.default,{defaultValue:p,children:b.map(e=>(0,t.jsx)(n.default.Option,{value:e.value,children:(0,t.jsxs)(m.Z,{title:e.description,children:[(0,t.jsx)("span",{className:"font-medium",children:e.label}),(0,t.jsxs)("span",{className:"ml-2 text-gray-500 text-sm",children:["- ",e.description]})]})},e.value))})}),(0,t.jsx)("div",{className:"text-right mt-4",children:(0,t.jsx)(d.ZP,{type:"default",htmlType:"submit",children:"Add Member"})})]})})}},10901:function(e,l,s){s.d(l,{Z:function(){return h}});var t=s(57437),i=s(2265),a=s(10032),r=s(22116),n=s(5545),m=s(27281),d=s(57365),o=s(49566),c=s(92280),u=s(24199),h=e=>{var l,s,h;let{visible:x,onCancel:b,onSubmit:p,initialData:g,mode:_,config:v}=e,[j]=a.Z.useForm();console.log("Initial Data:",g),(0,i.useEffect)(()=>{if(x){if("edit"===_&&g){let e={...g,role:g.role||v.defaultRole,max_budget_in_team:g.max_budget_in_team||null,tpm_limit:g.tpm_limit||null,rpm_limit:g.rpm_limit||null};console.log("Setting form values:",e),j.setFieldsValue(e)}else{var e;j.resetFields(),j.setFieldsValue({role:v.defaultRole||(null===(e=v.roleOptions[0])||void 0===e?void 0:e.value)})}}},[x,g,_,j,v.defaultRole,v.roleOptions]);let f=async e=>{try{let l=Object.entries(e).reduce((e,l)=>{let[s,t]=l;if("string"==typeof t){let l=t.trim();return""===l&&("max_budget_in_team"===s||"tpm_limit"===s||"rpm_limit"===s)?{...e,[s]:null}:{...e,[s]:l}}return{...e,[s]:t}},{});console.log("Submitting form data:",l),p(l),j.resetFields()}catch(e){console.error("Form submission error:",e)}},Z=e=>{switch(e.type){case"input":return(0,t.jsx)(o.Z,{placeholder:e.placeholder});case"numerical":return(0,t.jsx)(u.Z,{step:e.step||1,min:e.min||0,style:{width:"100%"},placeholder:e.placeholder||"Enter a numerical value"});case"select":var l;return(0,t.jsx)(m.Z,{children:null===(l=e.options)||void 0===l?void 0:l.map(e=>(0,t.jsx)(d.Z,{value:e.value,children:e.label},e.value))});default:return null}};return(0,t.jsx)(r.Z,{title:v.title||("add"===_?"Add Member":"Edit Member"),open:x,width:1e3,footer:null,onCancel:b,children:(0,t.jsxs)(a.Z,{form:j,onFinish:f,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[v.showEmail&&(0,t.jsx)(a.Z.Item,{label:"Email",name:"user_email",className:"mb-4",rules:[{type:"email",message:"Please enter a valid email!"}],children:(0,t.jsx)(o.Z,{placeholder:"user@example.com"})}),v.showEmail&&v.showUserId&&(0,t.jsx)("div",{className:"text-center mb-4",children:(0,t.jsx)(c.x,{children:"OR"})}),v.showUserId&&(0,t.jsx)(a.Z.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,t.jsx)(o.Z,{placeholder:"user_123"})}),(0,t.jsx)(a.Z.Item,{label:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{children:"Role"}),"edit"===_&&g&&(0,t.jsxs)("span",{className:"text-gray-500 text-sm",children:["(Current: ",(s=g.role,(null===(h=v.roleOptions.find(e=>e.value===s))||void 0===h?void 0:h.label)||s),")"]})]}),name:"role",className:"mb-4",rules:[{required:!0,message:"Please select a role!"}],children:(0,t.jsx)(m.Z,{children:"edit"===_&&g?[...v.roleOptions.filter(e=>e.value===g.role),...v.roleOptions.filter(e=>e.value!==g.role)].map(e=>(0,t.jsx)(d.Z,{value:e.value,children:e.label},e.value)):v.roleOptions.map(e=>(0,t.jsx)(d.Z,{value:e.value,children:e.label},e.value))})}),null===(l=v.additionalFields)||void 0===l?void 0:l.map(e=>(0,t.jsx)(a.Z.Item,{label:e.label,name:e.name,className:"mb-4",rules:e.rules,children:Z(e)},e.name)),(0,t.jsxs)("div",{className:"text-right mt-6",children:[(0,t.jsx)(n.ZP,{onClick:b,className:"mr-2",children:"Cancel"}),(0,t.jsx)(n.ZP,{type:"default",htmlType:"submit",children:"add"===_?"Add Member":"Save Changes"})]})]})})}},33293:function(e,l,s){s.d(l,{Z:function(){return el}});var t=s(57437),i=s(33860),a=s(19250),r=s(59872),n=s(33304),m=s(15424),d=s(10900),o=s(30078),c=s(10032),u=s(42264),h=s(5545),x=s(4260),b=s(37592),p=s(99981),g=s(63709),_=s(30401),v=s(78867),j=s(2265),f=s(21609),Z=s(95096),y=s(46468),N=s(27799),w=s(95920),k=s(68473),M=s(9114),C=s(98015),S=s(24199),T=s(97415),I=s(10901),P=s(21425),L=s(78489),F=s(12514),E=s(21626),O=s(97214),D=s(28241),A=s(58834),R=s(69552),U=s(71876),z=s(84264),B=s(96761),V=s(4156),q=s(85180),G=s(89245),K=s(78355);let $={"/key/generate":"Member can generate a virtual key for this team","/key/service-account/generate":"Member can generate a service account key (not belonging to any user) for this team","/key/update":"Member can update a virtual key belonging to this team","/key/delete":"Member can delete a virtual key belonging to this team","/key/info":"Member can get info about a virtual key belonging to this team","/key/regenerate":"Member can regenerate a virtual key belonging to this team","/key/{key_id}/regenerate":"Member can regenerate a virtual key belonging to this team","/key/list":"Member can list virtual keys belonging to this team","/key/block":"Member can block a virtual key belonging to this team","/key/unblock":"Member can unblock a virtual key belonging to this team"},J=e=>e.includes("/info")||e.includes("/list")?"GET":"POST",Q=e=>{let l=J(e),s=$[e];if(!s){for(let[l,t]of Object.entries($))if(e.includes(l)){s=t;break}}return s||(s="Access ".concat(e)),{method:l,endpoint:e,description:s,route:e}};var W=e=>{let{teamId:l,accessToken:s,canEditTeam:i}=e,[r,n]=(0,j.useState)([]),[m,d]=(0,j.useState)([]),[o,c]=(0,j.useState)(!0),[u,x]=(0,j.useState)(!1),[b,p]=(0,j.useState)(!1),g=async()=>{try{if(c(!0),!s)return;let e=await (0,a.getTeamPermissionsCall)(s,l),t=e.all_available_permissions||[];n(t);let i=e.team_member_permissions||[];d(i),p(!1)}catch(e){M.Z.fromBackend("Failed to load permissions"),console.error("Error fetching permissions:",e)}finally{c(!1)}};(0,j.useEffect)(()=>{g()},[l,s]);let _=(e,l)=>{d(l?[...m,e]:m.filter(l=>l!==e)),p(!0)},v=async()=>{try{if(!s)return;x(!0),await (0,a.teamPermissionsUpdateCall)(s,l,m),M.Z.success("Permissions updated successfully"),p(!1)}catch(e){M.Z.fromBackend("Failed to update permissions"),console.error("Error updating permissions:",e)}finally{x(!1)}};if(o)return(0,t.jsx)("div",{className:"p-6 text-center",children:"Loading permissions..."});let f=r.length>0;return(0,t.jsxs)(F.Z,{className:"bg-white shadow-md rounded-md p-6",children:[(0,t.jsxs)("div",{className:"flex flex-col sm:flex-row justify-between items-start sm:items-center border-b pb-4 mb-6",children:[(0,t.jsx)(B.Z,{className:"mb-2 sm:mb-0",children:"Member Permissions"}),i&&b&&(0,t.jsxs)("div",{className:"flex gap-3",children:[(0,t.jsx)(h.ZP,{icon:(0,t.jsx)(G.Z,{}),onClick:()=>{g()},children:"Reset"}),(0,t.jsxs)(L.Z,{onClick:v,loading:u,className:"flex items-center gap-2",children:[(0,t.jsx)(K.Z,{})," Save Changes"]})]})]}),(0,t.jsx)(z.Z,{className:"mb-6 text-gray-600",children:"Control what team members can do when they are not team admins."}),f?(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)(E.Z,{className:" min-w-full",children:[(0,t.jsx)(A.Z,{children:(0,t.jsxs)(U.Z,{children:[(0,t.jsx)(R.Z,{children:"Method"}),(0,t.jsx)(R.Z,{children:"Endpoint"}),(0,t.jsx)(R.Z,{children:"Description"}),(0,t.jsx)(R.Z,{className:"sticky right-0 bg-white shadow-[-4px_0_4px_-4px_rgba(0,0,0,0.1)] text-center",children:"Allow Access"})]})}),(0,t.jsx)(O.Z,{children:r.map(e=>{let l=Q(e);return(0,t.jsxs)(U.Z,{className:"hover:bg-gray-50 transition-colors",children:[(0,t.jsx)(D.Z,{children:(0,t.jsx)("span",{className:"px-2 py-1 rounded text-xs font-medium ".concat("GET"===l.method?"bg-blue-100 text-blue-800":"bg-green-100 text-green-800"),children:l.method})}),(0,t.jsx)(D.Z,{children:(0,t.jsx)("span",{className:"font-mono text-sm text-gray-800",children:l.endpoint})}),(0,t.jsx)(D.Z,{className:"text-gray-700",children:l.description}),(0,t.jsx)(D.Z,{className:"sticky right-0 bg-white shadow-[-4px_0_4px_-4px_rgba(0,0,0,0.1)] text-center",children:(0,t.jsx)(V.Z,{checked:m.includes(e),onChange:l=>_(e,l.target.checked),disabled:!i})})]},e)})})]})}):(0,t.jsx)("div",{className:"py-12",children:(0,t.jsx)(q.Z,{description:"No permissions available"})})]})},X=s(47323),Y=s(53410),H=s(74998),ee=e=>{let{teamData:l,canEditTeam:s,handleMemberDelete:i,setSelectedEditMember:a,setIsEditMemberModalVisible:n,setIsAddMemberModalVisible:d}=e,o=e=>{if(null==e)return"0";if("number"==typeof e){let l=Number(e);return l===Math.floor(l)?l.toString():(0,r.pw)(l,8).replace(/\.?0+$/,"")}return"0"},c=e=>{if(!e)return 0;let s=l.team_memberships.find(l=>l.user_id===e);return(null==s?void 0:s.spend)||0},u=e=>{var s;if(!e)return null;let t=l.team_memberships.find(l=>l.user_id===e);console.log("membership=".concat(t));let i=null==t?void 0:null===(s=t.litellm_budget_table)||void 0===s?void 0:s.max_budget;return null==i?null:o(i)},h=e=>{var s,t;if(!e)return"No Limits";let i=l.team_memberships.find(l=>l.user_id===e),a=null==i?void 0:null===(s=i.litellm_budget_table)||void 0===s?void 0:s.rpm_limit,r=null==i?void 0:null===(t=i.litellm_budget_table)||void 0===t?void 0:t.tpm_limit,n=[a?"".concat(o(a)," RPM"):null,r?"".concat(o(r)," TPM"):null].filter(Boolean);return n.length>0?n.join(" / "):"No Limits"};return(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsx)(F.Z,{className:"w-full mx-auto flex-auto overflow-auto max-h-[50vh]",children:(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)(E.Z,{className:"min-w-full",children:[(0,t.jsx)(A.Z,{children:(0,t.jsxs)(U.Z,{children:[(0,t.jsx)(R.Z,{children:"User ID"}),(0,t.jsx)(R.Z,{children:"User Email"}),(0,t.jsx)(R.Z,{children:"Role"}),(0,t.jsxs)(R.Z,{children:["Team Member Spend (USD)"," ",(0,t.jsx)(p.Z,{title:"This is the amount spent by a user in the team.",children:(0,t.jsx)(m.Z,{})})]}),(0,t.jsx)(R.Z,{children:"Team Member Budget (USD)"}),(0,t.jsxs)(R.Z,{children:["Team Member Rate Limits"," ",(0,t.jsx)(p.Z,{title:"Rate limits for this member's usage within this team.",children:(0,t.jsx)(m.Z,{})})]}),(0,t.jsx)(R.Z,{className:"sticky right-0 bg-white z-10 border-l border-gray-200",children:"Actions"})]})}),(0,t.jsx)(O.Z,{children:l.team_info.members_with_roles.map((e,m)=>(0,t.jsxs)(U.Z,{children:[(0,t.jsx)(D.Z,{children:(0,t.jsx)(z.Z,{className:"font-mono",children:e.user_id})}),(0,t.jsx)(D.Z,{children:(0,t.jsx)(z.Z,{className:"font-mono",children:e.user_email?e.user_email:"No Email"})}),(0,t.jsx)(D.Z,{children:(0,t.jsx)(z.Z,{className:"font-mono",children:e.role})}),(0,t.jsx)(D.Z,{children:(0,t.jsxs)(z.Z,{className:"font-mono",children:["$",(0,r.pw)(c(e.user_id),4)]})}),(0,t.jsx)(D.Z,{children:(0,t.jsx)(z.Z,{className:"font-mono",children:u(e.user_id)?"$".concat((0,r.pw)(Number(u(e.user_id)),4)):"No Limit"})}),(0,t.jsx)(D.Z,{children:(0,t.jsx)(z.Z,{className:"font-mono",children:h(e.user_id)})}),(0,t.jsx)(D.Z,{className:"sticky right-0 bg-white z-10 border-l border-gray-200",children:s&&(0,t.jsxs)("div",{className:"flex gap-2",children:[(0,t.jsx)(X.Z,{icon:Y.Z,size:"sm",onClick:()=>{var s,t,i;let r=l.team_memberships.find(l=>l.user_id===e.user_id);a({...e,max_budget_in_team:(null==r?void 0:null===(s=r.litellm_budget_table)||void 0===s?void 0:s.max_budget)||null,tpm_limit:(null==r?void 0:null===(t=r.litellm_budget_table)||void 0===t?void 0:t.tpm_limit)||null,rpm_limit:(null==r?void 0:null===(i=r.litellm_budget_table)||void 0===i?void 0:i.rpm_limit)||null}),n(!0)},className:"cursor-pointer hover:text-blue-600"}),(0,t.jsx)(X.Z,{icon:H.Z,size:"sm",onClick:()=>i(e),className:"cursor-pointer hover:text-red-600"})]})})]},m))})]})})}),(0,t.jsx)(L.Z,{onClick:()=>d(!0),children:"Add Member"})]})},el=e=>{var l,s,L,F,E,O,D,A,R,U,z,B,V,q,G,K,$,J;let{teamId:Q,onClose:X,accessToken:Y,is_team_admin:H,is_proxy_admin:el,userModels:es,editTeam:et,premiumUser:ei=!1,onUpdate:ea}=e,[er,en]=(0,j.useState)(null),[em,ed]=(0,j.useState)(!0),[eo,ec]=(0,j.useState)(!1),[eu]=c.Z.useForm(),[eh,ex]=(0,j.useState)(!1),[eb,ep]=(0,j.useState)(null),[eg,e_]=(0,j.useState)(!1),[ev,ej]=(0,j.useState)([]),[ef,eZ]=(0,j.useState)(!1),[ey,eN]=(0,j.useState)({}),[ew,ek]=(0,j.useState)([]),[eM,eC]=(0,j.useState)(null),[eS,eT]=(0,j.useState)(!1),[eI,eP]=(0,j.useState)(!1);console.log("userModels in team info",es);let eL=H||el,eF=async()=>{try{if(ed(!0),!Y)return;let e=await (0,a.teamInfoCall)(Y,Q);en(e)}catch(e){M.Z.fromBackend("Failed to load team information"),console.error("Error fetching team info:",e)}finally{ed(!1)}};(0,j.useEffect)(()=>{eF()},[Q,Y]),(0,j.useEffect)(()=>{(async()=>{try{if(!Y)return;let e=(await (0,a.getGuardrailsList)(Y)).guardrails.map(e=>e.guardrail_name);ek(e)}catch(e){console.error("Failed to fetch guardrails:",e)}})()},[Y]);let eE=async e=>{try{if(null==Y)return;let l={user_email:e.user_email,user_id:e.user_id,role:e.role};await (0,a.teamMemberAddCall)(Y,Q,l),M.Z.success("Team member added successfully"),ec(!1),eu.resetFields();let s=await (0,a.teamInfoCall)(Y,Q);en(s),ea(s)}catch(i){var l,s,t;let e="Failed to add team member";(null==i?void 0:null===(t=i.raw)||void 0===t?void 0:null===(s=t.detail)||void 0===s?void 0:null===(l=s.error)||void 0===l?void 0:l.includes("Assigning team admins is a premium feature"))?e="Assigning admins is an enterprise-only feature. Please upgrade your LiteLLM plan to enable this.":(null==i?void 0:i.message)&&(e=i.message),M.Z.fromBackend(e),console.error("Error adding team member:",i)}},eO=async e=>{try{if(null==Y)return;let l={user_email:e.user_email,user_id:e.user_id,role:e.role,max_budget_in_team:e.max_budget_in_team,tpm_limit:e.tpm_limit,rpm_limit:e.rpm_limit};console.log("Updating member with values:",l),u.ZP.destroy(),await (0,a.teamMemberUpdateCall)(Y,Q,l),M.Z.success("Team member updated successfully"),ex(!1);let s=await (0,a.teamInfoCall)(Y,Q);en(s),ea(s)}catch(t){var l,s;let e="Failed to update team member";(null==t?void 0:null===(s=t.raw)||void 0===s?void 0:null===(l=s.detail)||void 0===l?void 0:l.includes("Assigning team admins is a premium feature"))?e="Assigning admins is an enterprise-only feature. Please upgrade your LiteLLM plan to enable this.":(null==t?void 0:t.message)&&(e=t.message),ex(!1),u.ZP.destroy(),M.Z.fromBackend(e),console.error("Error updating team member:",t)}},eD=async()=>{if(eM&&Y){eP(!0);try{await (0,a.teamMemberDeleteCall)(Y,Q,eM),M.Z.success("Team member removed successfully");let e=await (0,a.teamInfoCall)(Y,Q);en(e),ea(e)}catch(e){M.Z.fromBackend("Failed to remove team member"),console.error("Error removing team member:",e)}finally{eP(!1),eT(!1),eC(null)}}},eA=async e=>{try{if(!Y)return;let l={};try{l=e.metadata?JSON.parse(e.metadata):{}}catch(e){M.Z.fromBackend("Invalid JSON in metadata field");return}let s=e=>null==e||"string"==typeof e&&""===e.trim()||"number"==typeof e&&Number.isNaN(e)?null:e,t={team_id:Q,team_alias:e.team_alias,models:e.models,tpm_limit:s(e.tpm_limit),rpm_limit:s(e.rpm_limit),max_budget:e.max_budget,budget_duration:e.budget_duration,metadata:{...l,guardrails:e.guardrails||[],logging:e.logging_settings||[]},organization_id:e.organization_id};t.max_budget=(0,n.C)(t.max_budget),void 0!==e.team_member_budget&&(t.team_member_budget=Number(e.team_member_budget)),void 0!==e.team_member_key_duration&&(t.team_member_key_duration=e.team_member_key_duration),(void 0!==e.team_member_tpm_limit||void 0!==e.team_member_rpm_limit)&&(t.team_member_tpm_limit=s(e.team_member_tpm_limit),t.team_member_rpm_limit=s(e.team_member_rpm_limit));let{servers:i,accessGroups:r}=e.mcp_servers_and_groups||{servers:[],accessGroups:[]},m=new Set(i||[]),d=Object.fromEntries(Object.entries(e.mcp_tool_permissions||{}).filter(e=>{let[l]=e;return m.has(l)}));t.object_permission={},i&&(t.object_permission.mcp_servers=i),r&&(t.object_permission.mcp_access_groups=r),d&&(t.object_permission.mcp_tool_permissions=d),delete e.mcp_servers_and_groups,delete e.mcp_tool_permissions,await (0,a.teamUpdateCall)(Y,t),M.Z.success("Team settings updated successfully"),e_(!1),eF()}catch(e){console.error("Error updating team:",e)}};if(em)return(0,t.jsx)("div",{className:"p-4",children:"Loading..."});if(!(null==er?void 0:er.team_info))return(0,t.jsx)("div",{className:"p-4",children:"Team not found"});let{team_info:eR}=er,eU=async(e,l)=>{await (0,r.vQ)(e)&&(eN(e=>({...e,[l]:!0})),setTimeout(()=>{eN(e=>({...e,[l]:!1}))},2e3))};return(0,t.jsxs)("div",{className:"p-4",children:[(0,t.jsx)("div",{className:"flex justify-between items-center mb-6",children:(0,t.jsxs)("div",{children:[(0,t.jsx)(o.zx,{icon:d.Z,variant:"light",onClick:X,className:"mb-4",children:"Back to Teams"}),(0,t.jsx)(o.Dx,{children:eR.team_alias}),(0,t.jsxs)("div",{className:"flex items-center cursor-pointer",children:[(0,t.jsx)(o.xv,{className:"text-gray-500 font-mono",children:eR.team_id}),(0,t.jsx)(h.ZP,{type:"text",size:"small",icon:ey["team-id"]?(0,t.jsx)(_.Z,{size:12}):(0,t.jsx)(v.Z,{size:12}),onClick:()=>eU(eR.team_id,"team-id"),className:"left-2 z-10 transition-all duration-200 ".concat(ey["team-id"]?"text-green-600 bg-green-50 border-green-200":"text-gray-500 hover:text-gray-700 hover:bg-gray-100")})]})]})}),(0,t.jsxs)(o.v0,{defaultIndex:et?3:0,children:[(0,t.jsx)(o.td,{className:"mb-4",children:[(0,t.jsx)(o.OK,{children:"Overview"},"overview"),...eL?[(0,t.jsx)(o.OK,{children:"Members"},"members"),(0,t.jsx)(o.OK,{children:"Member Permissions"},"member-permissions"),(0,t.jsx)(o.OK,{children:"Settings"},"settings")]:[]]}),(0,t.jsxs)(o.nP,{children:[(0,t.jsx)(o.x4,{children:(0,t.jsxs)(o.rj,{numItems:1,numItemsSm:2,numItemsLg:3,className:"gap-6",children:[(0,t.jsxs)(o.Zb,{children:[(0,t.jsx)(o.xv,{children:"Budget Status"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(o.Dx,{children:["$",(0,r.pw)(eR.spend,4)]}),(0,t.jsxs)(o.xv,{children:["of ",null===eR.max_budget?"Unlimited":"$".concat((0,r.pw)(eR.max_budget,4))]}),eR.budget_duration&&(0,t.jsxs)(o.xv,{className:"text-gray-500",children:["Reset: ",eR.budget_duration]}),(0,t.jsx)("br",{}),eR.team_member_budget_table&&(0,t.jsxs)(o.xv,{className:"text-gray-500",children:["Team Member Budget: $",(0,r.pw)(eR.team_member_budget_table.max_budget,4)]})]})]}),(0,t.jsxs)(o.Zb,{children:[(0,t.jsx)(o.xv,{children:"Rate Limits"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(o.xv,{children:["TPM: ",eR.tpm_limit||"Unlimited"]}),(0,t.jsxs)(o.xv,{children:["RPM: ",eR.rpm_limit||"Unlimited"]}),eR.max_parallel_requests&&(0,t.jsxs)(o.xv,{children:["Max Parallel Requests: ",eR.max_parallel_requests]})]})]}),(0,t.jsxs)(o.Zb,{children:[(0,t.jsx)(o.xv,{children:"Models"}),(0,t.jsx)("div",{className:"mt-2 flex flex-wrap gap-2",children:0===eR.models.length?(0,t.jsx)(o.Ct,{color:"red",children:"All proxy models"}):eR.models.map((e,l)=>(0,t.jsx)(o.Ct,{color:"red",children:e},l))})]}),(0,t.jsxs)(o.Zb,{children:[(0,t.jsx)(o.xv,{className:"font-semibold text-gray-900",children:"Virtual Keys"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(o.xv,{children:["User Keys: ",er.keys.filter(e=>e.user_id).length]}),(0,t.jsxs)(o.xv,{children:["Service Account Keys: ",er.keys.filter(e=>!e.user_id).length]}),(0,t.jsxs)(o.xv,{className:"text-gray-500",children:["Total: ",er.keys.length]})]})]}),(0,t.jsx)(C.Z,{objectPermission:eR.object_permission,variant:"card",accessToken:Y}),(0,t.jsx)(N.Z,{loggingConfigs:(null===(l=eR.metadata)||void 0===l?void 0:l.logging)||[],disabledCallbacks:[],variant:"card"})]})}),(0,t.jsx)(o.x4,{children:(0,t.jsx)(ee,{teamData:er,canEditTeam:eL,handleMemberDelete:e=>{eC(e),eT(!0)},setSelectedEditMember:ep,setIsEditMemberModalVisible:ex,setIsAddMemberModalVisible:ec})}),eL&&(0,t.jsx)(o.x4,{children:(0,t.jsx)(W,{teamId:Q,accessToken:Y,canEditTeam:eL})}),(0,t.jsx)(o.x4,{children:(0,t.jsxs)(o.Zb,{className:"overflow-y-auto max-h-[65vh]",children:[(0,t.jsxs)("div",{className:"flex justify-between items-center mb-4",children:[(0,t.jsx)(o.Dx,{children:"Team Settings"}),eL&&!eg&&(0,t.jsx)(o.zx,{onClick:()=>e_(!0),children:"Edit Settings"})]}),eg?(0,t.jsxs)(c.Z,{form:eu,onFinish:eA,initialValues:{...eR,team_alias:eR.team_alias,models:eR.models,tpm_limit:eR.tpm_limit,rpm_limit:eR.rpm_limit,max_budget:eR.max_budget,budget_duration:eR.budget_duration,team_member_tpm_limit:null===(s=eR.team_member_budget_table)||void 0===s?void 0:s.tpm_limit,team_member_rpm_limit:null===(L=eR.team_member_budget_table)||void 0===L?void 0:L.rpm_limit,guardrails:(null===(F=eR.metadata)||void 0===F?void 0:F.guardrails)||[],disable_global_guardrails:(null===(E=eR.metadata)||void 0===E?void 0:E.disable_global_guardrails)||!1,metadata:eR.metadata?JSON.stringify((e=>{let{logging:l,...s}=e;return s})(eR.metadata),null,2):"",logging_settings:(null===(O=eR.metadata)||void 0===O?void 0:O.logging)||[],organization_id:eR.organization_id,vector_stores:(null===(D=eR.object_permission)||void 0===D?void 0:D.vector_stores)||[],mcp_servers:(null===(A=eR.object_permission)||void 0===A?void 0:A.mcp_servers)||[],mcp_access_groups:(null===(R=eR.object_permission)||void 0===R?void 0:R.mcp_access_groups)||[],mcp_servers_and_groups:{servers:(null===(U=eR.object_permission)||void 0===U?void 0:U.mcp_servers)||[],accessGroups:(null===(z=eR.object_permission)||void 0===z?void 0:z.mcp_access_groups)||[]},mcp_tool_permissions:(null===(B=eR.object_permission)||void 0===B?void 0:B.mcp_tool_permissions)||{}},layout:"vertical",children:[(0,t.jsx)(c.Z.Item,{label:"Team Name",name:"team_alias",rules:[{required:!0,message:"Please input a team name"}],children:(0,t.jsx)(x.default,{type:""})}),(0,t.jsx)(c.Z.Item,{label:"Models",name:"models",rules:[{required:!0,message:"Please select at least one model"}],children:(0,t.jsxs)(b.default,{mode:"multiple",placeholder:"Select models",children:[(el||es.includes("all-proxy-models"))&&(0,t.jsx)(b.default.Option,{value:"all-proxy-models",children:"All Proxy Models"},"all-proxy-models"),(0,t.jsx)(b.default.Option,{value:"no-default-models",children:"No Default Models"},"no-default-models"),Array.from(new Set(es)).map((e,l)=>(0,t.jsx)(b.default.Option,{value:e,children:(0,y.W0)(e)},l))]})}),(0,t.jsx)(c.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,t.jsx)(S.Z,{step:.01,precision:2,style:{width:"100%"}})}),(0,t.jsx)(c.Z.Item,{label:"Team Member Budget (USD)",name:"team_member_budget",tooltip:"This is the individual budget for a user in the team.",children:(0,t.jsx)(S.Z,{step:.01,precision:2,style:{width:"100%"}})}),(0,t.jsx)(c.Z.Item,{label:"Team Member Key Duration (eg: 1d, 1mo)",name:"team_member_key_duration",tooltip:"Set a limit to the duration of a team member's key. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days), 1mo (month)",children:(0,t.jsx)(o.oi,{placeholder:"e.g., 30d"})}),(0,t.jsx)(c.Z.Item,{label:"Team Member TPM Limit",name:"team_member_tpm_limit",tooltip:"Default tokens per minute limit for an individual team member. This limit applies to all requests the user makes within this team. Can be overridden per member.",children:(0,t.jsx)(S.Z,{step:1,style:{width:"100%"},placeholder:"e.g., 1000"})}),(0,t.jsx)(c.Z.Item,{label:"Team Member RPM Limit",name:"team_member_rpm_limit",tooltip:"Default requests per minute limit for an individual team member. This limit applies to all requests the user makes within this team. Can be overridden per member.",children:(0,t.jsx)(S.Z,{step:1,style:{width:"100%"},placeholder:"e.g., 100"})}),(0,t.jsx)(c.Z.Item,{label:"Reset Budget",name:"budget_duration",children:(0,t.jsxs)(b.default,{placeholder:"n/a",children:[(0,t.jsx)(b.default.Option,{value:"24h",children:"daily"}),(0,t.jsx)(b.default.Option,{value:"7d",children:"weekly"}),(0,t.jsx)(b.default.Option,{value:"30d",children:"monthly"})]})}),(0,t.jsx)(c.Z.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,t.jsx)(S.Z,{step:1,style:{width:"100%"}})}),(0,t.jsx)(c.Z.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,t.jsx)(S.Z,{step:1,style:{width:"100%"}})}),(0,t.jsx)(c.Z.Item,{label:(0,t.jsxs)("span",{children:["Guardrails"," ",(0,t.jsx)(p.Z,{title:"Setup your first guardrail",children:(0,t.jsx)("a",{href:"https://docs.litellm.ai/docs/proxy/guardrails/quick_start",target:"_blank",rel:"noopener noreferrer",onClick:e=>e.stopPropagation(),children:(0,t.jsx)(m.Z,{style:{marginLeft:"4px"}})})})]}),name:"guardrails",help:"Select existing guardrails or enter new ones",children:(0,t.jsx)(b.default,{mode:"tags",placeholder:"Select or enter guardrails",options:ew.map(e=>({value:e,label:e}))})}),(0,t.jsx)(c.Z.Item,{label:(0,t.jsxs)("span",{children:["Disable Global Guardrails"," ",(0,t.jsx)(p.Z,{title:"When enabled, this team will bypass any guardrails configured to run on every request (global guardrails)",children:(0,t.jsx)(m.Z,{style:{marginLeft:"4px"}})})]}),name:"disable_global_guardrails",valuePropName:"checked",help:"Bypass global guardrails for this team",children:(0,t.jsx)(g.Z,{checkedChildren:"Yes",unCheckedChildren:"No"})}),(0,t.jsx)(c.Z.Item,{label:"Vector Stores",name:"vector_stores",children:(0,t.jsx)(T.Z,{onChange:e=>eu.setFieldValue("vector_stores",e),value:eu.getFieldValue("vector_stores"),accessToken:Y||"",placeholder:"Select vector stores"})}),(0,t.jsx)(c.Z.Item,{label:"Allowed Pass Through Routes",name:"allowed_passthrough_routes",children:(0,t.jsx)(Z.Z,{onChange:e=>eu.setFieldValue("allowed_passthrough_routes",e),value:eu.getFieldValue("allowed_passthrough_routes"),accessToken:Y||"",placeholder:"Select pass through routes"})}),(0,t.jsx)(c.Z.Item,{label:"MCP Servers / Access Groups",name:"mcp_servers_and_groups",children:(0,t.jsx)(w.Z,{onChange:e=>eu.setFieldValue("mcp_servers_and_groups",e),value:eu.getFieldValue("mcp_servers_and_groups"),accessToken:Y||"",placeholder:"Select MCP servers or access groups (optional)"})}),(0,t.jsx)(c.Z.Item,{name:"mcp_tool_permissions",initialValue:{},hidden:!0,children:(0,t.jsx)(x.default,{type:"hidden"})}),(0,t.jsx)(c.Z.Item,{noStyle:!0,shouldUpdate:(e,l)=>e.mcp_servers_and_groups!==l.mcp_servers_and_groups||e.mcp_tool_permissions!==l.mcp_tool_permissions,children:()=>{var e;return(0,t.jsx)("div",{className:"mb-6",children:(0,t.jsx)(k.Z,{accessToken:Y||"",selectedServers:(null===(e=eu.getFieldValue("mcp_servers_and_groups"))||void 0===e?void 0:e.servers)||[],toolPermissions:eu.getFieldValue("mcp_tool_permissions")||{},onChange:e=>eu.setFieldsValue({mcp_tool_permissions:e})})})}}),(0,t.jsx)(c.Z.Item,{label:"Organization ID",name:"organization_id",children:(0,t.jsx)(x.default,{type:""})}),(0,t.jsx)(c.Z.Item,{label:"Logging Settings",name:"logging_settings",children:(0,t.jsx)(P.Z,{value:eu.getFieldValue("logging_settings"),onChange:e=>eu.setFieldValue("logging_settings",e)})}),(0,t.jsx)(c.Z.Item,{label:"Metadata",name:"metadata",children:(0,t.jsx)(x.default.TextArea,{rows:10})}),(0,t.jsx)("div",{className:"sticky z-10 bg-white p-4 border-t border-gray-200 bottom-[-1.5rem] inset-x-[-1.5rem]",children:(0,t.jsxs)("div",{className:"flex justify-end items-center gap-2",children:[(0,t.jsx)(o.zx,{variant:"secondary",onClick:()=>e_(!1),children:"Cancel"}),(0,t.jsx)(o.zx,{type:"submit",children:"Save Changes"})]})})]}):(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Team Name"}),(0,t.jsx)("div",{children:eR.team_alias})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Team ID"}),(0,t.jsx)("div",{className:"font-mono",children:eR.team_id})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Created At"}),(0,t.jsx)("div",{children:new Date(eR.created_at).toLocaleString()})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Models"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:eR.models.map((e,l)=>(0,t.jsx)(o.Ct,{color:"red",children:e},l))})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Rate Limits"}),(0,t.jsxs)("div",{children:["TPM: ",eR.tpm_limit||"Unlimited"]}),(0,t.jsxs)("div",{children:["RPM: ",eR.rpm_limit||"Unlimited"]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Team Budget"}),(0,t.jsxs)("div",{children:["Max Budget:"," ",null!==eR.max_budget?"$".concat((0,r.pw)(eR.max_budget,4)):"No Limit"]}),(0,t.jsxs)("div",{children:["Budget Reset: ",eR.budget_duration||"Never"]})]}),(0,t.jsxs)("div",{children:[(0,t.jsxs)(o.xv,{className:"font-medium",children:["Team Member Settings"," ",(0,t.jsx)(p.Z,{title:"These are limits on individual team members",children:(0,t.jsx)(m.Z,{style:{marginLeft:"4px"}})})]}),(0,t.jsxs)("div",{children:["Max Budget: ",(null===(V=eR.team_member_budget_table)||void 0===V?void 0:V.max_budget)||"No Limit"]}),(0,t.jsxs)("div",{children:["Key Duration: ",(null===(q=eR.metadata)||void 0===q?void 0:q.team_member_key_duration)||"No Limit"]}),(0,t.jsxs)("div",{children:["TPM Limit: ",(null===(G=eR.team_member_budget_table)||void 0===G?void 0:G.tpm_limit)||"No Limit"]}),(0,t.jsxs)("div",{children:["RPM Limit: ",(null===(K=eR.team_member_budget_table)||void 0===K?void 0:K.rpm_limit)||"No Limit"]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Organization ID"}),(0,t.jsx)("div",{children:eR.organization_id})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Status"}),(0,t.jsx)(o.Ct,{color:eR.blocked?"red":"green",children:eR.blocked?"Blocked":"Active"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Disable Global Guardrails"}),(0,t.jsx)("div",{children:(null===($=eR.metadata)||void 0===$?void 0:$.disable_global_guardrails)===!0?(0,t.jsx)(o.Ct,{color:"yellow",children:"Enabled - Global guardrails bypassed"}):(0,t.jsx)(o.Ct,{color:"green",children:"Disabled - Global guardrails active"})})]}),(0,t.jsx)(C.Z,{objectPermission:eR.object_permission,variant:"inline",className:"pt-4 border-t border-gray-200",accessToken:Y}),(0,t.jsx)(N.Z,{loggingConfigs:(null===(J=eR.metadata)||void 0===J?void 0:J.logging)||[],disabledCallbacks:[],variant:"inline",className:"pt-4 border-t border-gray-200"})]})]})})]})]}),(0,t.jsx)(I.Z,{visible:eh,onCancel:()=>ex(!1),onSubmit:eO,initialData:eb,mode:"edit",config:{title:"Edit Member",showEmail:!0,showUserId:!0,roleOptions:[{label:"Admin",value:"admin"},{label:"User",value:"user"}],additionalFields:[{name:"max_budget_in_team",label:(0,t.jsxs)("span",{children:["Team Member Budget (USD)"," ",(0,t.jsx)(p.Z,{title:"Maximum amount in USD this member can spend within this team. This is separate from any global user budget limits",children:(0,t.jsx)(m.Z,{style:{marginLeft:"4px"}})})]}),type:"numerical",step:.01,min:0,placeholder:"Budget limit for this member within this team"},{name:"tpm_limit",label:(0,t.jsxs)("span",{children:["Team Member TPM Limit"," ",(0,t.jsx)(p.Z,{title:"Maximum tokens per minute this member can use within this team. This is separate from any global user TPM limit",children:(0,t.jsx)(m.Z,{style:{marginLeft:"4px"}})})]}),type:"numerical",step:1,min:0,placeholder:"Tokens per minute limit for this member in this team"},{name:"rpm_limit",label:(0,t.jsxs)("span",{children:["Team Member RPM Limit"," ",(0,t.jsx)(p.Z,{title:"Maximum requests per minute this member can make within this team. This is separate from any global user RPM limit",children:(0,t.jsx)(m.Z,{style:{marginLeft:"4px"}})})]}),type:"numerical",step:1,min:0,placeholder:"Requests per minute limit for this member in this team"}]}}),(0,t.jsx)(i.Z,{isVisible:eo,onCancel:()=>ec(!1),onSubmit:eE,accessToken:Y}),(0,t.jsx)(f.Z,{isOpen:eS,title:"Delete Team Member",alertMessage:"Removing team members will also delete any keys created by or created for this member.",message:"Are you sure you want to remove this member from the team? This action cannot be undone.",resourceInformationTitle:"Team Member Information",resourceInformation:[{label:"User ID",value:null==eM?void 0:eM.user_id,code:!0},{label:"Email",value:null==eM?void 0:eM.user_email},{label:"Role",value:null==eM?void 0:eM.role}],onCancel:()=>{eT(!1),eC(null)},onOk:eD,confirmLoading:eI})]})}}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/2012-c09fa25a9cbf6028.js b/litellm/proxy/_experimental/out/_next/static/chunks/2012-c09fa25a9cbf6028.js new file mode 100644 index 00000000000..fc87e2ebf09 --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/2012-c09fa25a9cbf6028.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[2012],{26210:function(e,l,s){s.d(l,{UQ:function(){return t.Z},X1:function(){return i.Z},_m:function(){return a.Z},oi:function(){return n.Z},xv:function(){return r.Z}});var t=s(87452),i=s(88829),a=s(72208),r=s(84264),n=s(49566)},30078:function(e,l,s){s.d(l,{Ct:function(){return t.Z},Dx:function(){return x.Z},OK:function(){return n.Z},Zb:function(){return a.Z},nP:function(){return c.Z},oi:function(){return h.Z},rj:function(){return r.Z},td:function(){return d.Z},v0:function(){return m.Z},x4:function(){return o.Z},xv:function(){return u.Z},zx:function(){return i.Z}});var t=s(41649),i=s(78489),a=s(12514),r=s(67101),n=s(12485),m=s(18135),d=s(35242),o=s(29706),c=s(77991),u=s(84264),h=s(49566),x=s(96761)},62490:function(e,l,s){s.d(l,{Ct:function(){return t.Z},RM:function(){return n.Z},SC:function(){return c.Z},Zb:function(){return a.Z},iA:function(){return r.Z},pj:function(){return m.Z},ss:function(){return d.Z},xs:function(){return o.Z},xv:function(){return u.Z},zx:function(){return i.Z}});var t=s(41649),i=s(78489),a=s(12514),r=s(21626),n=s(97214),m=s(28241),d=s(58834),o=s(69552),c=s(71876),u=s(84264)},11318:function(e,l,s){s.d(l,{Z:function(){return n}});var t=s(2265),i=s(39760),a=s(19250);let r=async(e,l,s,t)=>"Admin"!=s&&"Admin Viewer"!=s?await (0,a.teamListCall)(e,(null==t?void 0:t.organization_id)||null,l):await (0,a.teamListCall)(e,(null==t?void 0:t.organization_id)||null);var n=()=>{let[e,l]=(0,t.useState)([]),{accessToken:s,userId:a,userRole:n}=(0,i.Z)();return(0,t.useEffect)(()=>{(async()=>{l(await r(s,a,n,null))})()},[s,a,n]),{teams:e,setTeams:l}}},21609:function(e,l,s){s.d(l,{Z:function(){return o}});var t=s(57437),i=s(57840),a=s(22116),r=s(51653),n=s(76188),m=s(4260),d=s(2265);function o(e){let{isOpen:l,title:s,alertMessage:o,message:c,resourceInformationTitle:u,resourceInformation:h,onCancel:x,onOk:b,confirmLoading:p,requiredConfirmation:g}=e,{Title:_,Text:v}=i.default,[j,f]=(0,d.useState)("");return(0,d.useEffect)(()=>{l&&f("")},[l]),(0,t.jsx)(a.Z,{title:s,open:l,onOk:b,onCancel:x,confirmLoading:p,okText:p?"Deleting...":"Delete",cancelText:"Cancel",okButtonProps:{danger:!0,disabled:!!g&&j!==g||p},cancelButtonProps:{disabled:p},children:(0,t.jsxs)("div",{className:"space-y-4",children:[o&&(0,t.jsx)(r.Z,{message:o,type:"warning"}),(0,t.jsxs)("div",{className:"mt-4 p-4 bg-red-50 rounded-lg border border-red-200",children:[(0,t.jsx)(_,{level:5,className:"mb-3 text-gray-900",children:u}),(0,t.jsx)(n.Z,{column:1,size:"small",children:h&&h.map(e=>{let{label:l,value:s,...i}=e;return(0,t.jsx)(n.Z.Item,{label:(0,t.jsx)("span",{className:"font-semibold text-gray-700",children:l}),children:(0,t.jsx)(v,{...i,children:null!=s?s:"-"})},l)})})]}),(0,t.jsx)("div",{children:(0,t.jsx)(v,{children:c})}),g&&(0,t.jsxs)("div",{className:"mb-6 mt-4 pt-4 border-t border-gray-200",children:[(0,t.jsxs)(v,{className:"block text-base font-medium text-gray-700 mb-2",children:[(0,t.jsx)(v,{children:"Type "}),(0,t.jsx)(v,{strong:!0,type:"danger",children:g}),(0,t.jsx)(v,{children:" to confirm deletion:"})]}),(0,t.jsx)(m.default,{value:j,onChange:e=>f(e.target.value),placeholder:g,className:"rounded-md text-base border-gray-200",autoFocus:!0})]})]})})}},33860:function(e,l,s){var t=s(57437),i=s(2265),a=s(10032),r=s(22116),n=s(37592),m=s(99981),d=s(5545),o=s(7310),c=s.n(o),u=s(19250);l.Z=e=>{let{isVisible:l,onCancel:s,onSubmit:o,accessToken:h,title:x="Add Team Member",roles:b=[{label:"admin",value:"admin",description:"Admin role. Can create team keys, add members, and manage settings."},{label:"user",value:"user",description:"User role. Can view team info, but not manage it."}],defaultRole:p="user"}=e,[g]=a.Z.useForm(),[_,v]=(0,i.useState)([]),[j,f]=(0,i.useState)(!1),[Z,y]=(0,i.useState)("user_email"),N=async(e,l)=>{if(!e){v([]);return}f(!0);try{let s=new URLSearchParams;if(s.append(l,e),null==h)return;let t=(await (0,u.userFilterUICall)(h,s)).map(e=>({label:"user_email"===l?"".concat(e.user_email):"".concat(e.user_id),value:"user_email"===l?e.user_email:e.user_id,user:e}));v(t)}catch(e){console.error("Error fetching users:",e)}finally{f(!1)}},w=(0,i.useCallback)(c()((e,l)=>N(e,l),300),[]),k=(e,l)=>{y(l),w(e,l)},M=(e,l)=>{let s=l.user;g.setFieldsValue({user_email:s.user_email,user_id:s.user_id,role:g.getFieldValue("role")})};return(0,t.jsx)(r.Z,{title:x,open:l,onCancel:()=>{g.resetFields(),v([]),s()},footer:null,width:800,children:(0,t.jsxs)(a.Z,{form:g,onFinish:o,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",initialValues:{role:p},children:[(0,t.jsx)(a.Z.Item,{label:"Email",name:"user_email",className:"mb-4",children:(0,t.jsx)(n.default,{showSearch:!0,className:"w-full",placeholder:"Search by email",filterOption:!1,onSearch:e=>k(e,"user_email"),onSelect:(e,l)=>M(e,l),options:"user_email"===Z?_:[],loading:j,allowClear:!0})}),(0,t.jsx)("div",{className:"text-center mb-4",children:"OR"}),(0,t.jsx)(a.Z.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,t.jsx)(n.default,{showSearch:!0,className:"w-full",placeholder:"Search by user ID",filterOption:!1,onSearch:e=>k(e,"user_id"),onSelect:(e,l)=>M(e,l),options:"user_id"===Z?_:[],loading:j,allowClear:!0})}),(0,t.jsx)(a.Z.Item,{label:"Member Role",name:"role",className:"mb-4",children:(0,t.jsx)(n.default,{defaultValue:p,children:b.map(e=>(0,t.jsx)(n.default.Option,{value:e.value,children:(0,t.jsxs)(m.Z,{title:e.description,children:[(0,t.jsx)("span",{className:"font-medium",children:e.label}),(0,t.jsxs)("span",{className:"ml-2 text-gray-500 text-sm",children:["- ",e.description]})]})},e.value))})}),(0,t.jsx)("div",{className:"text-right mt-4",children:(0,t.jsx)(d.ZP,{type:"default",htmlType:"submit",children:"Add Member"})})]})})}},10901:function(e,l,s){s.d(l,{Z:function(){return h}});var t=s(57437),i=s(2265),a=s(10032),r=s(22116),n=s(5545),m=s(27281),d=s(57365),o=s(49566),c=s(92280),u=s(24199),h=e=>{var l,s,h;let{visible:x,onCancel:b,onSubmit:p,initialData:g,mode:_,config:v}=e,[j]=a.Z.useForm();console.log("Initial Data:",g),(0,i.useEffect)(()=>{if(x){if("edit"===_&&g){let e={...g,role:g.role||v.defaultRole,max_budget_in_team:g.max_budget_in_team||null,tpm_limit:g.tpm_limit||null,rpm_limit:g.rpm_limit||null};console.log("Setting form values:",e),j.setFieldsValue(e)}else{var e;j.resetFields(),j.setFieldsValue({role:v.defaultRole||(null===(e=v.roleOptions[0])||void 0===e?void 0:e.value)})}}},[x,g,_,j,v.defaultRole,v.roleOptions]);let f=async e=>{try{let l=Object.entries(e).reduce((e,l)=>{let[s,t]=l;if("string"==typeof t){let l=t.trim();return""===l&&("max_budget_in_team"===s||"tpm_limit"===s||"rpm_limit"===s)?{...e,[s]:null}:{...e,[s]:l}}return{...e,[s]:t}},{});console.log("Submitting form data:",l),p(l),j.resetFields()}catch(e){console.error("Form submission error:",e)}},Z=e=>{switch(e.type){case"input":return(0,t.jsx)(o.Z,{placeholder:e.placeholder});case"numerical":return(0,t.jsx)(u.Z,{step:e.step||1,min:e.min||0,style:{width:"100%"},placeholder:e.placeholder||"Enter a numerical value"});case"select":var l;return(0,t.jsx)(m.Z,{children:null===(l=e.options)||void 0===l?void 0:l.map(e=>(0,t.jsx)(d.Z,{value:e.value,children:e.label},e.value))});default:return null}};return(0,t.jsx)(r.Z,{title:v.title||("add"===_?"Add Member":"Edit Member"),open:x,width:1e3,footer:null,onCancel:b,children:(0,t.jsxs)(a.Z,{form:j,onFinish:f,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[v.showEmail&&(0,t.jsx)(a.Z.Item,{label:"Email",name:"user_email",className:"mb-4",rules:[{type:"email",message:"Please enter a valid email!"}],children:(0,t.jsx)(o.Z,{placeholder:"user@example.com"})}),v.showEmail&&v.showUserId&&(0,t.jsx)("div",{className:"text-center mb-4",children:(0,t.jsx)(c.x,{children:"OR"})}),v.showUserId&&(0,t.jsx)(a.Z.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,t.jsx)(o.Z,{placeholder:"user_123"})}),(0,t.jsx)(a.Z.Item,{label:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{children:"Role"}),"edit"===_&&g&&(0,t.jsxs)("span",{className:"text-gray-500 text-sm",children:["(Current: ",(s=g.role,(null===(h=v.roleOptions.find(e=>e.value===s))||void 0===h?void 0:h.label)||s),")"]})]}),name:"role",className:"mb-4",rules:[{required:!0,message:"Please select a role!"}],children:(0,t.jsx)(m.Z,{children:"edit"===_&&g?[...v.roleOptions.filter(e=>e.value===g.role),...v.roleOptions.filter(e=>e.value!==g.role)].map(e=>(0,t.jsx)(d.Z,{value:e.value,children:e.label},e.value)):v.roleOptions.map(e=>(0,t.jsx)(d.Z,{value:e.value,children:e.label},e.value))})}),null===(l=v.additionalFields)||void 0===l?void 0:l.map(e=>(0,t.jsx)(a.Z.Item,{label:e.label,name:e.name,className:"mb-4",rules:e.rules,children:Z(e)},e.name)),(0,t.jsxs)("div",{className:"text-right mt-6",children:[(0,t.jsx)(n.ZP,{onClick:b,className:"mr-2",children:"Cancel"}),(0,t.jsx)(n.ZP,{type:"default",htmlType:"submit",children:"add"===_?"Add Member":"Save Changes"})]})]})})}},33293:function(e,l,s){s.d(l,{Z:function(){return el}});var t=s(57437),i=s(33860),a=s(19250),r=s(59872),n=s(33304),m=s(15424),d=s(10900),o=s(30078),c=s(10032),u=s(42264),h=s(5545),x=s(4260),b=s(37592),p=s(99981),g=s(63709),_=s(30401),v=s(78867),j=s(2265),f=s(21609),Z=s(95096),y=s(46468),N=s(27799),w=s(95920),k=s(68473),M=s(9114),C=s(98015),S=s(24199),T=s(97415),I=s(10901),P=s(21425),L=s(78489),F=s(12514),E=s(21626),O=s(97214),D=s(28241),A=s(58834),R=s(69552),U=s(71876),z=s(84264),B=s(96761),V=s(61994),q=s(85180),G=s(89245),K=s(78355);let $={"/key/generate":"Member can generate a virtual key for this team","/key/service-account/generate":"Member can generate a service account key (not belonging to any user) for this team","/key/update":"Member can update a virtual key belonging to this team","/key/delete":"Member can delete a virtual key belonging to this team","/key/info":"Member can get info about a virtual key belonging to this team","/key/regenerate":"Member can regenerate a virtual key belonging to this team","/key/{key_id}/regenerate":"Member can regenerate a virtual key belonging to this team","/key/list":"Member can list virtual keys belonging to this team","/key/block":"Member can block a virtual key belonging to this team","/key/unblock":"Member can unblock a virtual key belonging to this team"},J=e=>e.includes("/info")||e.includes("/list")?"GET":"POST",Q=e=>{let l=J(e),s=$[e];if(!s){for(let[l,t]of Object.entries($))if(e.includes(l)){s=t;break}}return s||(s="Access ".concat(e)),{method:l,endpoint:e,description:s,route:e}};var W=e=>{let{teamId:l,accessToken:s,canEditTeam:i}=e,[r,n]=(0,j.useState)([]),[m,d]=(0,j.useState)([]),[o,c]=(0,j.useState)(!0),[u,x]=(0,j.useState)(!1),[b,p]=(0,j.useState)(!1),g=async()=>{try{if(c(!0),!s)return;let e=await (0,a.getTeamPermissionsCall)(s,l),t=e.all_available_permissions||[];n(t);let i=e.team_member_permissions||[];d(i),p(!1)}catch(e){M.Z.fromBackend("Failed to load permissions"),console.error("Error fetching permissions:",e)}finally{c(!1)}};(0,j.useEffect)(()=>{g()},[l,s]);let _=(e,l)=>{d(l?[...m,e]:m.filter(l=>l!==e)),p(!0)},v=async()=>{try{if(!s)return;x(!0),await (0,a.teamPermissionsUpdateCall)(s,l,m),M.Z.success("Permissions updated successfully"),p(!1)}catch(e){M.Z.fromBackend("Failed to update permissions"),console.error("Error updating permissions:",e)}finally{x(!1)}};if(o)return(0,t.jsx)("div",{className:"p-6 text-center",children:"Loading permissions..."});let f=r.length>0;return(0,t.jsxs)(F.Z,{className:"bg-white shadow-md rounded-md p-6",children:[(0,t.jsxs)("div",{className:"flex flex-col sm:flex-row justify-between items-start sm:items-center border-b pb-4 mb-6",children:[(0,t.jsx)(B.Z,{className:"mb-2 sm:mb-0",children:"Member Permissions"}),i&&b&&(0,t.jsxs)("div",{className:"flex gap-3",children:[(0,t.jsx)(h.ZP,{icon:(0,t.jsx)(G.Z,{}),onClick:()=>{g()},children:"Reset"}),(0,t.jsxs)(L.Z,{onClick:v,loading:u,className:"flex items-center gap-2",children:[(0,t.jsx)(K.Z,{})," Save Changes"]})]})]}),(0,t.jsx)(z.Z,{className:"mb-6 text-gray-600",children:"Control what team members can do when they are not team admins."}),f?(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)(E.Z,{className:" min-w-full",children:[(0,t.jsx)(A.Z,{children:(0,t.jsxs)(U.Z,{children:[(0,t.jsx)(R.Z,{children:"Method"}),(0,t.jsx)(R.Z,{children:"Endpoint"}),(0,t.jsx)(R.Z,{children:"Description"}),(0,t.jsx)(R.Z,{className:"sticky right-0 bg-white shadow-[-4px_0_4px_-4px_rgba(0,0,0,0.1)] text-center",children:"Allow Access"})]})}),(0,t.jsx)(O.Z,{children:r.map(e=>{let l=Q(e);return(0,t.jsxs)(U.Z,{className:"hover:bg-gray-50 transition-colors",children:[(0,t.jsx)(D.Z,{children:(0,t.jsx)("span",{className:"px-2 py-1 rounded text-xs font-medium ".concat("GET"===l.method?"bg-blue-100 text-blue-800":"bg-green-100 text-green-800"),children:l.method})}),(0,t.jsx)(D.Z,{children:(0,t.jsx)("span",{className:"font-mono text-sm text-gray-800",children:l.endpoint})}),(0,t.jsx)(D.Z,{className:"text-gray-700",children:l.description}),(0,t.jsx)(D.Z,{className:"sticky right-0 bg-white shadow-[-4px_0_4px_-4px_rgba(0,0,0,0.1)] text-center",children:(0,t.jsx)(V.Z,{checked:m.includes(e),onChange:l=>_(e,l.target.checked),disabled:!i})})]},e)})})]})}):(0,t.jsx)("div",{className:"py-12",children:(0,t.jsx)(q.Z,{description:"No permissions available"})})]})},X=s(47323),Y=s(53410),H=s(74998),ee=e=>{let{teamData:l,canEditTeam:s,handleMemberDelete:i,setSelectedEditMember:a,setIsEditMemberModalVisible:n,setIsAddMemberModalVisible:d}=e,o=e=>{if(null==e)return"0";if("number"==typeof e){let l=Number(e);return l===Math.floor(l)?l.toString():(0,r.pw)(l,8).replace(/\.?0+$/,"")}return"0"},c=e=>{if(!e)return 0;let s=l.team_memberships.find(l=>l.user_id===e);return(null==s?void 0:s.spend)||0},u=e=>{var s;if(!e)return null;let t=l.team_memberships.find(l=>l.user_id===e);console.log("membership=".concat(t));let i=null==t?void 0:null===(s=t.litellm_budget_table)||void 0===s?void 0:s.max_budget;return null==i?null:o(i)},h=e=>{var s,t;if(!e)return"No Limits";let i=l.team_memberships.find(l=>l.user_id===e),a=null==i?void 0:null===(s=i.litellm_budget_table)||void 0===s?void 0:s.rpm_limit,r=null==i?void 0:null===(t=i.litellm_budget_table)||void 0===t?void 0:t.tpm_limit,n=[a?"".concat(o(a)," RPM"):null,r?"".concat(o(r)," TPM"):null].filter(Boolean);return n.length>0?n.join(" / "):"No Limits"};return(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsx)(F.Z,{className:"w-full mx-auto flex-auto overflow-auto max-h-[50vh]",children:(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)(E.Z,{className:"min-w-full",children:[(0,t.jsx)(A.Z,{children:(0,t.jsxs)(U.Z,{children:[(0,t.jsx)(R.Z,{children:"User ID"}),(0,t.jsx)(R.Z,{children:"User Email"}),(0,t.jsx)(R.Z,{children:"Role"}),(0,t.jsxs)(R.Z,{children:["Team Member Spend (USD)"," ",(0,t.jsx)(p.Z,{title:"This is the amount spent by a user in the team.",children:(0,t.jsx)(m.Z,{})})]}),(0,t.jsx)(R.Z,{children:"Team Member Budget (USD)"}),(0,t.jsxs)(R.Z,{children:["Team Member Rate Limits"," ",(0,t.jsx)(p.Z,{title:"Rate limits for this member's usage within this team.",children:(0,t.jsx)(m.Z,{})})]}),(0,t.jsx)(R.Z,{className:"sticky right-0 bg-white z-10 border-l border-gray-200",children:"Actions"})]})}),(0,t.jsx)(O.Z,{children:l.team_info.members_with_roles.map((e,m)=>(0,t.jsxs)(U.Z,{children:[(0,t.jsx)(D.Z,{children:(0,t.jsx)(z.Z,{className:"font-mono",children:e.user_id})}),(0,t.jsx)(D.Z,{children:(0,t.jsx)(z.Z,{className:"font-mono",children:e.user_email?e.user_email:"No Email"})}),(0,t.jsx)(D.Z,{children:(0,t.jsx)(z.Z,{className:"font-mono",children:e.role})}),(0,t.jsx)(D.Z,{children:(0,t.jsxs)(z.Z,{className:"font-mono",children:["$",(0,r.pw)(c(e.user_id),4)]})}),(0,t.jsx)(D.Z,{children:(0,t.jsx)(z.Z,{className:"font-mono",children:u(e.user_id)?"$".concat((0,r.pw)(Number(u(e.user_id)),4)):"No Limit"})}),(0,t.jsx)(D.Z,{children:(0,t.jsx)(z.Z,{className:"font-mono",children:h(e.user_id)})}),(0,t.jsx)(D.Z,{className:"sticky right-0 bg-white z-10 border-l border-gray-200",children:s&&(0,t.jsxs)("div",{className:"flex gap-2",children:[(0,t.jsx)(X.Z,{icon:Y.Z,size:"sm",onClick:()=>{var s,t,i;let r=l.team_memberships.find(l=>l.user_id===e.user_id);a({...e,max_budget_in_team:(null==r?void 0:null===(s=r.litellm_budget_table)||void 0===s?void 0:s.max_budget)||null,tpm_limit:(null==r?void 0:null===(t=r.litellm_budget_table)||void 0===t?void 0:t.tpm_limit)||null,rpm_limit:(null==r?void 0:null===(i=r.litellm_budget_table)||void 0===i?void 0:i.rpm_limit)||null}),n(!0)},className:"cursor-pointer hover:text-blue-600"}),(0,t.jsx)(X.Z,{icon:H.Z,size:"sm",onClick:()=>i(e),className:"cursor-pointer hover:text-red-600"})]})})]},m))})]})})}),(0,t.jsx)(L.Z,{onClick:()=>d(!0),children:"Add Member"})]})},el=e=>{var l,s,L,F,E,O,D,A,R,U,z,B,V,q,G,K,$,J;let{teamId:Q,onClose:X,accessToken:Y,is_team_admin:H,is_proxy_admin:el,userModels:es,editTeam:et,premiumUser:ei=!1,onUpdate:ea}=e,[er,en]=(0,j.useState)(null),[em,ed]=(0,j.useState)(!0),[eo,ec]=(0,j.useState)(!1),[eu]=c.Z.useForm(),[eh,ex]=(0,j.useState)(!1),[eb,ep]=(0,j.useState)(null),[eg,e_]=(0,j.useState)(!1),[ev,ej]=(0,j.useState)([]),[ef,eZ]=(0,j.useState)(!1),[ey,eN]=(0,j.useState)({}),[ew,ek]=(0,j.useState)([]),[eM,eC]=(0,j.useState)(null),[eS,eT]=(0,j.useState)(!1),[eI,eP]=(0,j.useState)(!1),[eL,eF]=(0,j.useState)(!1);console.log("userModels in team info",es);let eE=H||el,eO=async()=>{try{if(ed(!0),!Y)return;let e=await (0,a.teamInfoCall)(Y,Q);en(e)}catch(e){M.Z.fromBackend("Failed to load team information"),console.error("Error fetching team info:",e)}finally{ed(!1)}};(0,j.useEffect)(()=>{eO()},[Q,Y]),(0,j.useEffect)(()=>{(async()=>{try{if(!Y)return;let e=(await (0,a.getGuardrailsList)(Y)).guardrails.map(e=>e.guardrail_name);ek(e)}catch(e){console.error("Failed to fetch guardrails:",e)}})()},[Y]);let eD=async e=>{try{if(null==Y)return;let l={user_email:e.user_email,user_id:e.user_id,role:e.role};await (0,a.teamMemberAddCall)(Y,Q,l),M.Z.success("Team member added successfully"),ec(!1),eu.resetFields();let s=await (0,a.teamInfoCall)(Y,Q);en(s),ea(s)}catch(i){var l,s,t;let e="Failed to add team member";(null==i?void 0:null===(t=i.raw)||void 0===t?void 0:null===(s=t.detail)||void 0===s?void 0:null===(l=s.error)||void 0===l?void 0:l.includes("Assigning team admins is a premium feature"))?e="Assigning admins is an enterprise-only feature. Please upgrade your LiteLLM plan to enable this.":(null==i?void 0:i.message)&&(e=i.message),M.Z.fromBackend(e),console.error("Error adding team member:",i)}},eA=async e=>{try{if(null==Y)return;let l={user_email:e.user_email,user_id:e.user_id,role:e.role,max_budget_in_team:e.max_budget_in_team,tpm_limit:e.tpm_limit,rpm_limit:e.rpm_limit};console.log("Updating member with values:",l),u.ZP.destroy(),await (0,a.teamMemberUpdateCall)(Y,Q,l),M.Z.success("Team member updated successfully"),ex(!1);let s=await (0,a.teamInfoCall)(Y,Q);en(s),ea(s)}catch(t){var l,s;let e="Failed to update team member";(null==t?void 0:null===(s=t.raw)||void 0===s?void 0:null===(l=s.detail)||void 0===l?void 0:l.includes("Assigning team admins is a premium feature"))?e="Assigning admins is an enterprise-only feature. Please upgrade your LiteLLM plan to enable this.":(null==t?void 0:t.message)&&(e=t.message),ex(!1),u.ZP.destroy(),M.Z.fromBackend(e),console.error("Error updating team member:",t)}},eR=async()=>{if(eM&&Y){eP(!0);try{await (0,a.teamMemberDeleteCall)(Y,Q,eM),M.Z.success("Team member removed successfully");let e=await (0,a.teamInfoCall)(Y,Q);en(e),ea(e)}catch(e){M.Z.fromBackend("Failed to remove team member"),console.error("Error removing team member:",e)}finally{eP(!1),eT(!1),eC(null)}}},eU=async e=>{try{if(!Y)return;eF(!0);let l={};try{l=e.metadata?JSON.parse(e.metadata):{}}catch(e){M.Z.fromBackend("Invalid JSON in metadata field");return}let s=e=>null==e||"string"==typeof e&&""===e.trim()||"number"==typeof e&&Number.isNaN(e)?null:e,t={team_id:Q,team_alias:e.team_alias,models:e.models,tpm_limit:s(e.tpm_limit),rpm_limit:s(e.rpm_limit),max_budget:e.max_budget,budget_duration:e.budget_duration,metadata:{...l,guardrails:e.guardrails||[],logging:e.logging_settings||[]},organization_id:e.organization_id};t.max_budget=(0,n.C)(t.max_budget),void 0!==e.team_member_budget&&(t.team_member_budget=Number(e.team_member_budget)),void 0!==e.team_member_key_duration&&(t.team_member_key_duration=e.team_member_key_duration),(void 0!==e.team_member_tpm_limit||void 0!==e.team_member_rpm_limit)&&(t.team_member_tpm_limit=s(e.team_member_tpm_limit),t.team_member_rpm_limit=s(e.team_member_rpm_limit));let{servers:i,accessGroups:r}=e.mcp_servers_and_groups||{servers:[],accessGroups:[]},m=new Set(i||[]),d=Object.fromEntries(Object.entries(e.mcp_tool_permissions||{}).filter(e=>{let[l]=e;return m.has(l)}));t.object_permission={},i&&(t.object_permission.mcp_servers=i),r&&(t.object_permission.mcp_access_groups=r),d&&(t.object_permission.mcp_tool_permissions=d),delete e.mcp_servers_and_groups,delete e.mcp_tool_permissions,await (0,a.teamUpdateCall)(Y,t),M.Z.success("Team settings updated successfully"),e_(!1),eO()}catch(e){console.error("Error updating team:",e)}finally{eF(!1)}};if(em)return(0,t.jsx)("div",{className:"p-4",children:"Loading..."});if(!(null==er?void 0:er.team_info))return(0,t.jsx)("div",{className:"p-4",children:"Team not found"});let{team_info:ez}=er,eB=async(e,l)=>{await (0,r.vQ)(e)&&(eN(e=>({...e,[l]:!0})),setTimeout(()=>{eN(e=>({...e,[l]:!1}))},2e3))};return(0,t.jsxs)("div",{className:"p-4",children:[(0,t.jsx)("div",{className:"flex justify-between items-center mb-6",children:(0,t.jsxs)("div",{children:[(0,t.jsx)(o.zx,{icon:d.Z,variant:"light",onClick:X,className:"mb-4",children:"Back to Teams"}),(0,t.jsx)(o.Dx,{children:ez.team_alias}),(0,t.jsxs)("div",{className:"flex items-center cursor-pointer",children:[(0,t.jsx)(o.xv,{className:"text-gray-500 font-mono",children:ez.team_id}),(0,t.jsx)(h.ZP,{type:"text",size:"small",icon:ey["team-id"]?(0,t.jsx)(_.Z,{size:12}):(0,t.jsx)(v.Z,{size:12}),onClick:()=>eB(ez.team_id,"team-id"),className:"left-2 z-10 transition-all duration-200 ".concat(ey["team-id"]?"text-green-600 bg-green-50 border-green-200":"text-gray-500 hover:text-gray-700 hover:bg-gray-100")})]})]})}),(0,t.jsxs)(o.v0,{defaultIndex:et?3:0,children:[(0,t.jsx)(o.td,{className:"mb-4",children:[(0,t.jsx)(o.OK,{children:"Overview"},"overview"),...eE?[(0,t.jsx)(o.OK,{children:"Members"},"members"),(0,t.jsx)(o.OK,{children:"Member Permissions"},"member-permissions"),(0,t.jsx)(o.OK,{children:"Settings"},"settings")]:[]]}),(0,t.jsxs)(o.nP,{children:[(0,t.jsx)(o.x4,{children:(0,t.jsxs)(o.rj,{numItems:1,numItemsSm:2,numItemsLg:3,className:"gap-6",children:[(0,t.jsxs)(o.Zb,{children:[(0,t.jsx)(o.xv,{children:"Budget Status"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(o.Dx,{children:["$",(0,r.pw)(ez.spend,4)]}),(0,t.jsxs)(o.xv,{children:["of ",null===ez.max_budget?"Unlimited":"$".concat((0,r.pw)(ez.max_budget,4))]}),ez.budget_duration&&(0,t.jsxs)(o.xv,{className:"text-gray-500",children:["Reset: ",ez.budget_duration]}),(0,t.jsx)("br",{}),ez.team_member_budget_table&&(0,t.jsxs)(o.xv,{className:"text-gray-500",children:["Team Member Budget: $",(0,r.pw)(ez.team_member_budget_table.max_budget,4)]})]})]}),(0,t.jsxs)(o.Zb,{children:[(0,t.jsx)(o.xv,{children:"Rate Limits"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(o.xv,{children:["TPM: ",ez.tpm_limit||"Unlimited"]}),(0,t.jsxs)(o.xv,{children:["RPM: ",ez.rpm_limit||"Unlimited"]}),ez.max_parallel_requests&&(0,t.jsxs)(o.xv,{children:["Max Parallel Requests: ",ez.max_parallel_requests]})]})]}),(0,t.jsxs)(o.Zb,{children:[(0,t.jsx)(o.xv,{children:"Models"}),(0,t.jsx)("div",{className:"mt-2 flex flex-wrap gap-2",children:0===ez.models.length?(0,t.jsx)(o.Ct,{color:"red",children:"All proxy models"}):ez.models.map((e,l)=>(0,t.jsx)(o.Ct,{color:"red",children:e},l))})]}),(0,t.jsxs)(o.Zb,{children:[(0,t.jsx)(o.xv,{className:"font-semibold text-gray-900",children:"Virtual Keys"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(o.xv,{children:["User Keys: ",er.keys.filter(e=>e.user_id).length]}),(0,t.jsxs)(o.xv,{children:["Service Account Keys: ",er.keys.filter(e=>!e.user_id).length]}),(0,t.jsxs)(o.xv,{className:"text-gray-500",children:["Total: ",er.keys.length]})]})]}),(0,t.jsx)(C.Z,{objectPermission:ez.object_permission,variant:"card",accessToken:Y}),(0,t.jsx)(N.Z,{loggingConfigs:(null===(l=ez.metadata)||void 0===l?void 0:l.logging)||[],disabledCallbacks:[],variant:"card"})]})}),(0,t.jsx)(o.x4,{children:(0,t.jsx)(ee,{teamData:er,canEditTeam:eE,handleMemberDelete:e=>{eC(e),eT(!0)},setSelectedEditMember:ep,setIsEditMemberModalVisible:ex,setIsAddMemberModalVisible:ec})}),eE&&(0,t.jsx)(o.x4,{children:(0,t.jsx)(W,{teamId:Q,accessToken:Y,canEditTeam:eE})}),(0,t.jsx)(o.x4,{children:(0,t.jsxs)(o.Zb,{className:"overflow-y-auto max-h-[65vh]",children:[(0,t.jsxs)("div",{className:"flex justify-between items-center mb-4",children:[(0,t.jsx)(o.Dx,{children:"Team Settings"}),eE&&!eg&&(0,t.jsx)(o.zx,{onClick:()=>e_(!0),children:"Edit Settings"})]}),eg?(0,t.jsxs)(c.Z,{form:eu,onFinish:eU,initialValues:{...ez,team_alias:ez.team_alias,models:ez.models,tpm_limit:ez.tpm_limit,rpm_limit:ez.rpm_limit,max_budget:ez.max_budget,budget_duration:ez.budget_duration,team_member_tpm_limit:null===(s=ez.team_member_budget_table)||void 0===s?void 0:s.tpm_limit,team_member_rpm_limit:null===(L=ez.team_member_budget_table)||void 0===L?void 0:L.rpm_limit,guardrails:(null===(F=ez.metadata)||void 0===F?void 0:F.guardrails)||[],disable_global_guardrails:(null===(E=ez.metadata)||void 0===E?void 0:E.disable_global_guardrails)||!1,metadata:ez.metadata?JSON.stringify((e=>{let{logging:l,...s}=e;return s})(ez.metadata),null,2):"",logging_settings:(null===(O=ez.metadata)||void 0===O?void 0:O.logging)||[],organization_id:ez.organization_id,vector_stores:(null===(D=ez.object_permission)||void 0===D?void 0:D.vector_stores)||[],mcp_servers:(null===(A=ez.object_permission)||void 0===A?void 0:A.mcp_servers)||[],mcp_access_groups:(null===(R=ez.object_permission)||void 0===R?void 0:R.mcp_access_groups)||[],mcp_servers_and_groups:{servers:(null===(U=ez.object_permission)||void 0===U?void 0:U.mcp_servers)||[],accessGroups:(null===(z=ez.object_permission)||void 0===z?void 0:z.mcp_access_groups)||[]},mcp_tool_permissions:(null===(B=ez.object_permission)||void 0===B?void 0:B.mcp_tool_permissions)||{}},layout:"vertical",children:[(0,t.jsx)(c.Z.Item,{label:"Team Name",name:"team_alias",rules:[{required:!0,message:"Please input a team name"}],children:(0,t.jsx)(x.default,{type:""})}),(0,t.jsx)(c.Z.Item,{label:"Models",name:"models",rules:[{required:!0,message:"Please select at least one model"}],children:(0,t.jsxs)(b.default,{mode:"multiple",placeholder:"Select models",children:[(el||es.includes("all-proxy-models"))&&(0,t.jsx)(b.default.Option,{value:"all-proxy-models",children:"All Proxy Models"},"all-proxy-models"),(0,t.jsx)(b.default.Option,{value:"no-default-models",children:"No Default Models"},"no-default-models"),Array.from(new Set(es)).map((e,l)=>(0,t.jsx)(b.default.Option,{value:e,children:(0,y.W0)(e)},l))]})}),(0,t.jsx)(c.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,t.jsx)(S.Z,{step:.01,precision:2,style:{width:"100%"}})}),(0,t.jsx)(c.Z.Item,{label:"Team Member Budget (USD)",name:"team_member_budget",tooltip:"This is the individual budget for a user in the team.",children:(0,t.jsx)(S.Z,{step:.01,precision:2,style:{width:"100%"}})}),(0,t.jsx)(c.Z.Item,{label:"Team Member Key Duration (eg: 1d, 1mo)",name:"team_member_key_duration",tooltip:"Set a limit to the duration of a team member's key. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days), 1mo (month)",children:(0,t.jsx)(o.oi,{placeholder:"e.g., 30d"})}),(0,t.jsx)(c.Z.Item,{label:"Team Member TPM Limit",name:"team_member_tpm_limit",tooltip:"Default tokens per minute limit for an individual team member. This limit applies to all requests the user makes within this team. Can be overridden per member.",children:(0,t.jsx)(S.Z,{step:1,style:{width:"100%"},placeholder:"e.g., 1000"})}),(0,t.jsx)(c.Z.Item,{label:"Team Member RPM Limit",name:"team_member_rpm_limit",tooltip:"Default requests per minute limit for an individual team member. This limit applies to all requests the user makes within this team. Can be overridden per member.",children:(0,t.jsx)(S.Z,{step:1,style:{width:"100%"},placeholder:"e.g., 100"})}),(0,t.jsx)(c.Z.Item,{label:"Reset Budget",name:"budget_duration",children:(0,t.jsxs)(b.default,{placeholder:"n/a",children:[(0,t.jsx)(b.default.Option,{value:"24h",children:"daily"}),(0,t.jsx)(b.default.Option,{value:"7d",children:"weekly"}),(0,t.jsx)(b.default.Option,{value:"30d",children:"monthly"})]})}),(0,t.jsx)(c.Z.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,t.jsx)(S.Z,{step:1,style:{width:"100%"}})}),(0,t.jsx)(c.Z.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,t.jsx)(S.Z,{step:1,style:{width:"100%"}})}),(0,t.jsx)(c.Z.Item,{label:(0,t.jsxs)("span",{children:["Guardrails"," ",(0,t.jsx)(p.Z,{title:"Setup your first guardrail",children:(0,t.jsx)("a",{href:"https://docs.litellm.ai/docs/proxy/guardrails/quick_start",target:"_blank",rel:"noopener noreferrer",onClick:e=>e.stopPropagation(),children:(0,t.jsx)(m.Z,{style:{marginLeft:"4px"}})})})]}),name:"guardrails",help:"Select existing guardrails or enter new ones",children:(0,t.jsx)(b.default,{mode:"tags",placeholder:"Select or enter guardrails",options:ew.map(e=>({value:e,label:e}))})}),(0,t.jsx)(c.Z.Item,{label:(0,t.jsxs)("span",{children:["Disable Global Guardrails"," ",(0,t.jsx)(p.Z,{title:"When enabled, this team will bypass any guardrails configured to run on every request (global guardrails)",children:(0,t.jsx)(m.Z,{style:{marginLeft:"4px"}})})]}),name:"disable_global_guardrails",valuePropName:"checked",help:"Bypass global guardrails for this team",children:(0,t.jsx)(g.Z,{checkedChildren:"Yes",unCheckedChildren:"No"})}),(0,t.jsx)(c.Z.Item,{label:"Vector Stores",name:"vector_stores",children:(0,t.jsx)(T.Z,{onChange:e=>eu.setFieldValue("vector_stores",e),value:eu.getFieldValue("vector_stores"),accessToken:Y||"",placeholder:"Select vector stores"})}),(0,t.jsx)(c.Z.Item,{label:"Allowed Pass Through Routes",name:"allowed_passthrough_routes",children:(0,t.jsx)(Z.Z,{onChange:e=>eu.setFieldValue("allowed_passthrough_routes",e),value:eu.getFieldValue("allowed_passthrough_routes"),accessToken:Y||"",placeholder:"Select pass through routes"})}),(0,t.jsx)(c.Z.Item,{label:"MCP Servers / Access Groups",name:"mcp_servers_and_groups",children:(0,t.jsx)(w.Z,{onChange:e=>eu.setFieldValue("mcp_servers_and_groups",e),value:eu.getFieldValue("mcp_servers_and_groups"),accessToken:Y||"",placeholder:"Select MCP servers or access groups (optional)"})}),(0,t.jsx)(c.Z.Item,{name:"mcp_tool_permissions",initialValue:{},hidden:!0,children:(0,t.jsx)(x.default,{type:"hidden"})}),(0,t.jsx)(c.Z.Item,{noStyle:!0,shouldUpdate:(e,l)=>e.mcp_servers_and_groups!==l.mcp_servers_and_groups||e.mcp_tool_permissions!==l.mcp_tool_permissions,children:()=>{var e;return(0,t.jsx)("div",{className:"mb-6",children:(0,t.jsx)(k.Z,{accessToken:Y||"",selectedServers:(null===(e=eu.getFieldValue("mcp_servers_and_groups"))||void 0===e?void 0:e.servers)||[],toolPermissions:eu.getFieldValue("mcp_tool_permissions")||{},onChange:e=>eu.setFieldsValue({mcp_tool_permissions:e})})})}}),(0,t.jsx)(c.Z.Item,{label:"Organization ID",name:"organization_id",children:(0,t.jsx)(x.default,{type:""})}),(0,t.jsx)(c.Z.Item,{label:"Logging Settings",name:"logging_settings",children:(0,t.jsx)(P.Z,{value:eu.getFieldValue("logging_settings"),onChange:e=>eu.setFieldValue("logging_settings",e)})}),(0,t.jsx)(c.Z.Item,{label:"Metadata",name:"metadata",children:(0,t.jsx)(x.default.TextArea,{rows:10})}),(0,t.jsx)("div",{className:"sticky z-10 bg-white p-4 border-t border-gray-200 bottom-[-1.5rem] inset-x-[-1.5rem]",children:(0,t.jsxs)("div",{className:"flex justify-end items-center gap-2",children:[(0,t.jsx)(o.zx,{variant:"secondary",onClick:()=>e_(!1),disabled:eL,children:"Cancel"}),(0,t.jsx)(o.zx,{type:"submit",loading:eL,children:"Save Changes"})]})})]}):(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Team Name"}),(0,t.jsx)("div",{children:ez.team_alias})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Team ID"}),(0,t.jsx)("div",{className:"font-mono",children:ez.team_id})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Created At"}),(0,t.jsx)("div",{children:new Date(ez.created_at).toLocaleString()})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Models"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:ez.models.map((e,l)=>(0,t.jsx)(o.Ct,{color:"red",children:e},l))})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Rate Limits"}),(0,t.jsxs)("div",{children:["TPM: ",ez.tpm_limit||"Unlimited"]}),(0,t.jsxs)("div",{children:["RPM: ",ez.rpm_limit||"Unlimited"]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Team Budget"}),(0,t.jsxs)("div",{children:["Max Budget:"," ",null!==ez.max_budget?"$".concat((0,r.pw)(ez.max_budget,4)):"No Limit"]}),(0,t.jsxs)("div",{children:["Budget Reset: ",ez.budget_duration||"Never"]})]}),(0,t.jsxs)("div",{children:[(0,t.jsxs)(o.xv,{className:"font-medium",children:["Team Member Settings"," ",(0,t.jsx)(p.Z,{title:"These are limits on individual team members",children:(0,t.jsx)(m.Z,{style:{marginLeft:"4px"}})})]}),(0,t.jsxs)("div",{children:["Max Budget: ",(null===(V=ez.team_member_budget_table)||void 0===V?void 0:V.max_budget)||"No Limit"]}),(0,t.jsxs)("div",{children:["Key Duration: ",(null===(q=ez.metadata)||void 0===q?void 0:q.team_member_key_duration)||"No Limit"]}),(0,t.jsxs)("div",{children:["TPM Limit: ",(null===(G=ez.team_member_budget_table)||void 0===G?void 0:G.tpm_limit)||"No Limit"]}),(0,t.jsxs)("div",{children:["RPM Limit: ",(null===(K=ez.team_member_budget_table)||void 0===K?void 0:K.rpm_limit)||"No Limit"]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Organization ID"}),(0,t.jsx)("div",{children:ez.organization_id})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Status"}),(0,t.jsx)(o.Ct,{color:ez.blocked?"red":"green",children:ez.blocked?"Blocked":"Active"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(o.xv,{className:"font-medium",children:"Disable Global Guardrails"}),(0,t.jsx)("div",{children:(null===($=ez.metadata)||void 0===$?void 0:$.disable_global_guardrails)===!0?(0,t.jsx)(o.Ct,{color:"yellow",children:"Enabled - Global guardrails bypassed"}):(0,t.jsx)(o.Ct,{color:"green",children:"Disabled - Global guardrails active"})})]}),(0,t.jsx)(C.Z,{objectPermission:ez.object_permission,variant:"inline",className:"pt-4 border-t border-gray-200",accessToken:Y}),(0,t.jsx)(N.Z,{loggingConfigs:(null===(J=ez.metadata)||void 0===J?void 0:J.logging)||[],disabledCallbacks:[],variant:"inline",className:"pt-4 border-t border-gray-200"})]})]})})]})]}),(0,t.jsx)(I.Z,{visible:eh,onCancel:()=>ex(!1),onSubmit:eA,initialData:eb,mode:"edit",config:{title:"Edit Member",showEmail:!0,showUserId:!0,roleOptions:[{label:"Admin",value:"admin"},{label:"User",value:"user"}],additionalFields:[{name:"max_budget_in_team",label:(0,t.jsxs)("span",{children:["Team Member Budget (USD)"," ",(0,t.jsx)(p.Z,{title:"Maximum amount in USD this member can spend within this team. This is separate from any global user budget limits",children:(0,t.jsx)(m.Z,{style:{marginLeft:"4px"}})})]}),type:"numerical",step:.01,min:0,placeholder:"Budget limit for this member within this team"},{name:"tpm_limit",label:(0,t.jsxs)("span",{children:["Team Member TPM Limit"," ",(0,t.jsx)(p.Z,{title:"Maximum tokens per minute this member can use within this team. This is separate from any global user TPM limit",children:(0,t.jsx)(m.Z,{style:{marginLeft:"4px"}})})]}),type:"numerical",step:1,min:0,placeholder:"Tokens per minute limit for this member in this team"},{name:"rpm_limit",label:(0,t.jsxs)("span",{children:["Team Member RPM Limit"," ",(0,t.jsx)(p.Z,{title:"Maximum requests per minute this member can make within this team. This is separate from any global user RPM limit",children:(0,t.jsx)(m.Z,{style:{marginLeft:"4px"}})})]}),type:"numerical",step:1,min:0,placeholder:"Requests per minute limit for this member in this team"}]}}),(0,t.jsx)(i.Z,{isVisible:eo,onCancel:()=>ec(!1),onSubmit:eD,accessToken:Y}),(0,t.jsx)(f.Z,{isOpen:eS,title:"Delete Team Member",alertMessage:"Removing team members will also delete any keys created by or created for this member.",message:"Are you sure you want to remove this member from the team? This action cannot be undone.",resourceInformationTitle:"Team Member Information",resourceInformation:[{label:"User ID",value:null==eM?void 0:eM.user_id,code:!0},{label:"Email",value:null==eM?void 0:eM.user_email},{label:"Role",value:null==eM?void 0:eM.role}],onCancel:()=>{eT(!1),eC(null)},onOk:eR,confirmLoading:eI})]})}}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/2019-15183fcc4c29249f.js b/litellm/proxy/_experimental/out/_next/static/chunks/2019-15183fcc4c29249f.js deleted file mode 100644 index 742a5c6e359..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/2019-15183fcc4c29249f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[2019],{92019:function(e,s,t){var a=t(57437),r=t(13817),l=t(18310),i=t(60985),n=t(92403),o=t(28595),c=t(68208),d=t(9775),m=t(41361),g=t(37527),u=t(15883),x=t(12660),y=t(88009),h=t(48231),p=t(57400),f=t(58630),b=t(44625),j=t(41169),N=t(38434),v=t(71891),L=t(55322),w=t(2265),k=t(99376),Z=t(20347),S=t(79262),_=t(19250);let{Sider:z}=r.default,O=()=>{let e="ui/".replace(/^\/+|\/+$/g,""),s=e?"/".concat(e,"/"):"/";if(_.serverRootPath&&"/"!==_.serverRootPath){let e=_.serverRootPath.replace(/\/+$/,""),t=s.replace(/^\/+/,"");return"".concat(e,"/").concat(t)}return s},P=e=>{switch(e){case"api-keys":return"virtual-keys";case"llm-playground":return"test-key";case"models":return"models-and-endpoints";case"new_usage":return"usage";case"teams":return"teams";case"organizations":return"organizations";case"users":return"users";case"api_ref":return"api-reference";case"model-hub-table":return"model-hub";case"logs":return"logs";case"guardrails":return"guardrails";case"mcp-servers":return"tools/mcp-servers";case"vector-stores":return"tools/vector-stores";case"caching":return"experimental/caching";case"prompts":return"experimental/prompts";case"budgets":return"experimental/budgets";case"transform-request":return"experimental/api-playground";case"tag-management":return"experimental/tag-management";case"usage":return"experimental/old-usage";case"general-settings":return"settings/router-settings";case"settings":return"settings/logging-and-alerts";case"admin-panel":return"settings/admin-settings";case"ui-theme":return"settings/ui-theme";default:return e.replace(/^\/+/,"")}},M=e=>{let s=O(),t=P(e).replace(/^\/+|\/+$/g,"");return"".concat(s).concat(t)},C=[{key:"1",page:"api-keys",label:"Virtual Keys",icon:(0,a.jsx)(n.Z,{style:{fontSize:18}})},{key:"3",page:"llm-playground",label:"Test Key",icon:(0,a.jsx)(o.Z,{style:{fontSize:18}}),roles:Z.LQ},{key:"2",page:"models",label:"Models + Endpoints",icon:(0,a.jsx)(c.Z,{style:{fontSize:18}}),roles:Z.LQ},{key:"12",page:"new_usage",label:"Usage",icon:(0,a.jsx)(d.Z,{style:{fontSize:18}}),roles:[...Z.ZL,...Z.lo]},{key:"6",page:"teams",label:"Teams",icon:(0,a.jsx)(m.Z,{style:{fontSize:18}})},{key:"17",page:"organizations",label:"Organizations",icon:(0,a.jsx)(g.Z,{style:{fontSize:18}}),roles:Z.ZL},{key:"5",page:"users",label:"Internal Users",icon:(0,a.jsx)(u.Z,{style:{fontSize:18}}),roles:Z.ZL},{key:"14",page:"api_ref",label:"API Reference",icon:(0,a.jsx)(x.Z,{style:{fontSize:18}})},{key:"16",page:"model-hub-table",label:"Model Hub",icon:(0,a.jsx)(y.Z,{style:{fontSize:18}})},{key:"15",page:"logs",label:"Logs",icon:(0,a.jsx)(h.Z,{style:{fontSize:18}})},{key:"11",page:"guardrails",label:"Guardrails",icon:(0,a.jsx)(p.Z,{style:{fontSize:18}}),roles:Z.ZL},{key:"26",page:"tools",label:"Tools",icon:(0,a.jsx)(f.Z,{style:{fontSize:18}}),children:[{key:"18",page:"mcp-servers",label:"MCP Servers",icon:(0,a.jsx)(f.Z,{style:{fontSize:18}})},{key:"21",page:"vector-stores",label:"Vector Stores",icon:(0,a.jsx)(b.Z,{style:{fontSize:18}}),roles:Z.ZL}]},{key:"experimental",page:"experimental",label:"Experimental",icon:(0,a.jsx)(j.Z,{style:{fontSize:18}}),children:[{key:"9",page:"caching",label:"Caching",icon:(0,a.jsx)(b.Z,{style:{fontSize:18}}),roles:Z.ZL},{key:"25",page:"prompts",label:"Prompts",icon:(0,a.jsx)(N.Z,{style:{fontSize:18}}),roles:Z.ZL},{key:"10",page:"budgets",label:"Budgets",icon:(0,a.jsx)(g.Z,{style:{fontSize:18}}),roles:Z.ZL},{key:"20",page:"transform-request",label:"API Playground",icon:(0,a.jsx)(x.Z,{style:{fontSize:18}}),roles:[...Z.ZL,...Z.lo]},{key:"19",page:"tag-management",label:"Tag Management",icon:(0,a.jsx)(v.Z,{style:{fontSize:18}}),roles:Z.ZL},{key:"4",page:"usage",label:"Old Usage",icon:(0,a.jsx)(d.Z,{style:{fontSize:18}})}]},{key:"settings",page:"settings",label:"Settings",icon:(0,a.jsx)(L.Z,{style:{fontSize:18}}),roles:Z.ZL,children:[{key:"11",page:"general-settings",label:"Router Settings",icon:(0,a.jsx)(L.Z,{style:{fontSize:18}}),roles:Z.ZL},{key:"8",page:"settings",label:"Logging & Alerts",icon:(0,a.jsx)(L.Z,{style:{fontSize:18}}),roles:Z.ZL},{key:"13",page:"admin-panel",label:"Admin Settings",icon:(0,a.jsx)(L.Z,{style:{fontSize:18}}),roles:Z.ZL},{key:"14",page:"ui-theme",label:"UI Theme",icon:(0,a.jsx)(L.Z,{style:{fontSize:18}}),roles:Z.ZL}]}];s.Z=e=>{let{accessToken:s,userRole:t,defaultSelectedKey:n,collapsed:o=!1}=e,c=(0,k.useRouter)(),d=(0,k.usePathname)()||"/",m=w.useMemo(()=>C.filter(e=>!e.roles||e.roles.includes(t)).map(e=>({...e,children:e.children?e.children.filter(e=>!e.roles||e.roles.includes(t)):void 0})),[t]),g=w.useMemo(()=>{var e,s;let t=O(),a=(d.startsWith(t)?d.slice(t.length):d.replace(/^\/+/,"")).toLowerCase(),r=e=>{let s=P(e).toLowerCase();return a===s||a.startsWith("".concat(s,"/"))};for(let e of m){if(!e.children&&r(e.page))return e.key;if(e.children){for(let s of e.children)if(r(s.page))return s.key}}let l=null===(e=m.find(e=>e.page===n))||void 0===e?void 0:e.key;if(l)return l;for(let e of m)if(null===(s=e.children)||void 0===s?void 0:s.some(e=>e.page===n))return e.children.find(e=>e.page===n).key;return"1"},[d,m,n]),u=e=>{let s=M(e);c.push(s)};return(0,a.jsx)(r.default,{style:{minHeight:"100vh"},children:(0,a.jsxs)(z,{theme:"light",width:220,collapsed:o,collapsedWidth:80,collapsible:!0,trigger:null,style:{transition:"all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",position:"relative"},children:[(0,a.jsx)(l.ZP,{theme:{components:{Menu:{iconSize:18,fontSize:14}}},children:(0,a.jsx)(i.Z,{mode:"inline",selectedKeys:[g],defaultOpenKeys:o?[]:["llm-tools"],inlineCollapsed:o,className:"custom-sidebar-menu",style:{borderRight:0,backgroundColor:"transparent",fontSize:"14px"},items:m.map(e=>{var s;return{key:e.key,icon:e.icon,label:e.label,children:null===(s=e.children)||void 0===s?void 0:s.map(e=>({key:e.key,icon:e.icon,label:e.label,onClick:()=>u(e.page)})),onClick:e.children?void 0:()=>u(e.page)}})})}),(0,Z.tY)(t)&&!o&&(0,a.jsx)(S.Z,{accessToken:s,width:220})]})})}},79262:function(e,s,t){t.d(s,{Z:function(){return u}});var a=t(57437);t(1309);var r=t(76865),l=t(70525),i=t(95805),n=t(51817),o=t(21047);t(22135),t(40875);var c=t(49663),d=t(2265),m=t(19250);let g=function(){for(var e=arguments.length,s=Array(e),t=0;t{(async()=>{if(s){j(!0),v(null);try{let e=await (0,m.getRemainingUsers)(s);f(e)}catch(e){console.error("Failed to fetch usage data:",e),v("Failed to load usage data")}finally{j(!1)}}})()},[s]);let{isOverLimit:L,isNearLimit:w,usagePercentage:k,userMetrics:Z,teamMetrics:S}=(e=>{if(!e)return{isOverLimit:!1,isNearLimit:!1,usagePercentage:0,userMetrics:{isOverLimit:!1,isNearLimit:!1,usagePercentage:0},teamMetrics:{isOverLimit:!1,isNearLimit:!1,usagePercentage:0}};let s=e.total_users?e.total_users_used/e.total_users*100:0,t=s>100,a=s>=80&&s<=100,r=e.total_teams?e.total_teams_used/e.total_teams*100:0,l=r>100,i=r>=80&&r<=100,n=t||l;return{isOverLimit:n,isNearLimit:(a||i)&&!n,usagePercentage:Math.max(s,r),userMetrics:{isOverLimit:t,isNearLimit:a,usagePercentage:s},teamMetrics:{isOverLimit:l,isNearLimit:i,usagePercentage:r}}})(p),_=()=>L?(0,a.jsx)(r.Z,{className:"h-3 w-3"}):w?(0,a.jsx)(l.Z,{className:"h-3 w-3"}):null;return s&&((null==p?void 0:p.total_users)!==null||(null==p?void 0:p.total_teams)!==null)?(0,a.jsx)("div",{className:"fixed bottom-4 left-4 z-50",style:{width:"".concat(Math.min(t,220),"px")},children:(0,a.jsx)(()=>y?(0,a.jsx)("button",{onClick:()=>h(!1),className:g("bg-white border border-gray-200 rounded-lg shadow-sm p-3 hover:shadow-md transition-all w-full"),title:"Show usage details",children:(0,a.jsxs)("div",{className:"flex items-center gap-2",children:[(0,a.jsx)(i.Z,{className:"h-4 w-4 flex-shrink-0"}),(L||w)&&(0,a.jsx)("span",{className:"flex-shrink-0",children:_()}),(0,a.jsxs)("div",{className:"flex items-center gap-2 text-sm font-medium truncate",children:[p&&null!==p.total_users&&(0,a.jsxs)("span",{className:g("flex-shrink-0 px-1.5 py-0.5 rounded text-xs border",Z.isOverLimit&&"bg-red-50 text-red-700 border-red-200",Z.isNearLimit&&"bg-yellow-50 text-yellow-700 border-yellow-200",!Z.isOverLimit&&!Z.isNearLimit&&"bg-gray-50 text-gray-700 border-gray-200"),children:["U: ",p.total_users_used,"/",p.total_users]}),p&&null!==p.total_teams&&(0,a.jsxs)("span",{className:g("flex-shrink-0 px-1.5 py-0.5 rounded text-xs border",S.isOverLimit&&"bg-red-50 text-red-700 border-red-200",S.isNearLimit&&"bg-yellow-50 text-yellow-700 border-yellow-200",!S.isOverLimit&&!S.isNearLimit&&"bg-gray-50 text-gray-700 border-gray-200"),children:["T: ",p.total_teams_used,"/",p.total_teams]}),!p||null===p.total_users&&null===p.total_teams&&(0,a.jsx)("span",{className:"truncate",children:"Usage"})]})]})}):b?(0,a.jsx)("div",{className:"bg-white border border-gray-200 rounded-lg shadow-sm p-4 w-full",children:(0,a.jsxs)("div",{className:"flex items-center justify-center gap-2 py-2",children:[(0,a.jsx)(n.Z,{className:"h-4 w-4 animate-spin"}),(0,a.jsx)("span",{className:"text-sm text-gray-500 truncate",children:"Loading..."})]})}):N||!p?(0,a.jsx)("div",{className:"bg-white border border-gray-200 rounded-lg shadow-sm p-4 group w-full",children:(0,a.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,a.jsx)("div",{className:"flex-1 min-w-0",children:(0,a.jsx)("span",{className:"text-sm text-gray-500 truncate block",children:N||"No data"})}),(0,a.jsx)("button",{onClick:()=>h(!0),className:"opacity-0 group-hover:opacity-100 p-1 hover:bg-gray-100 rounded transition-all flex-shrink-0",title:"Minimize",children:(0,a.jsx)(o.Z,{className:"h-3 w-3 text-gray-400"})})]})}):(0,a.jsxs)("div",{className:g("bg-white border rounded-lg shadow-sm p-3 transition-all duration-200 group w-full"),children:[(0,a.jsxs)("div",{className:"flex items-center justify-between gap-2 mb-3",children:[(0,a.jsxs)("div",{className:"flex items-center gap-2 min-w-0 flex-1",children:[(0,a.jsx)(i.Z,{className:"h-4 w-4 flex-shrink-0"}),(0,a.jsx)("span",{className:"font-medium text-sm truncate",children:"Usage"})]}),(0,a.jsx)("button",{onClick:()=>h(!0),className:"opacity-0 group-hover:opacity-100 p-1 hover:bg-gray-100 rounded transition-all flex-shrink-0",title:"Minimize",children:(0,a.jsx)(o.Z,{className:"h-3 w-3 text-gray-400"})})]}),(0,a.jsxs)("div",{className:"space-y-3 text-sm",children:[null!==p.total_users&&(0,a.jsxs)("div",{className:g("space-y-1 border rounded-md p-2",Z.isOverLimit&&"border-red-200 bg-red-50",Z.isNearLimit&&"border-yellow-200 bg-yellow-50"),children:[(0,a.jsxs)("div",{className:"flex items-center gap-2 text-xs text-gray-600 mb-1",children:[(0,a.jsx)(i.Z,{className:"h-3 w-3"}),(0,a.jsx)("span",{className:"font-medium",children:"Users"}),(0,a.jsx)("span",{className:g("ml-1 px-1.5 py-0.5 rounded border",Z.isOverLimit&&"bg-red-50 text-red-700 border-red-200",Z.isNearLimit&&"bg-yellow-50 text-yellow-700 border-yellow-200",!Z.isOverLimit&&!Z.isNearLimit&&"bg-gray-50 text-gray-600 border-gray-200"),children:Z.isOverLimit?"Over limit":Z.isNearLimit?"Near limit":"OK"})]}),(0,a.jsxs)("div",{className:"flex justify-between items-center",children:[(0,a.jsx)("span",{className:"text-gray-600 text-xs",children:"Used:"}),(0,a.jsxs)("span",{className:"font-medium text-right",children:[p.total_users_used,"/",p.total_users]})]}),(0,a.jsxs)("div",{className:"flex justify-between items-center",children:[(0,a.jsx)("span",{className:"text-gray-600 text-xs",children:"Remaining:"}),(0,a.jsx)("span",{className:g("font-medium text-right",Z.isOverLimit&&"text-red-600",Z.isNearLimit&&"text-yellow-600"),children:p.total_users_remaining})]}),(0,a.jsxs)("div",{className:"flex justify-between items-center",children:[(0,a.jsx)("span",{className:"text-gray-600 text-xs",children:"Usage:"}),(0,a.jsxs)("span",{className:"font-medium text-right",children:[Math.round(Z.usagePercentage),"%"]})]}),(0,a.jsx)("div",{className:"w-full bg-gray-200 rounded-full h-2",children:(0,a.jsx)("div",{className:g("h-2 rounded-full transition-all duration-300",Z.isOverLimit&&"bg-red-500",Z.isNearLimit&&"bg-yellow-500",!Z.isOverLimit&&!Z.isNearLimit&&"bg-green-500"),style:{width:"".concat(Math.min(Z.usagePercentage,100),"%")}})})]}),null!==p.total_teams&&(0,a.jsxs)("div",{className:g("space-y-1 border rounded-md p-2",S.isOverLimit&&"border-red-200 bg-red-50",S.isNearLimit&&"border-yellow-200 bg-yellow-50"),children:[(0,a.jsxs)("div",{className:"flex items-center gap-2 text-xs text-gray-600 mb-1",children:[(0,a.jsx)(c.Z,{className:"h-3 w-3"}),(0,a.jsx)("span",{className:"font-medium",children:"Teams"}),(0,a.jsx)("span",{className:g("ml-1 px-1.5 py-0.5 rounded border",S.isOverLimit&&"bg-red-50 text-red-700 border-red-200",S.isNearLimit&&"bg-yellow-50 text-yellow-700 border-yellow-200",!S.isOverLimit&&!S.isNearLimit&&"bg-gray-50 text-gray-600 border-gray-200"),children:S.isOverLimit?"Over limit":S.isNearLimit?"Near limit":"OK"})]}),(0,a.jsxs)("div",{className:"flex justify-between items-center",children:[(0,a.jsx)("span",{className:"text-gray-600 text-xs",children:"Used:"}),(0,a.jsxs)("span",{className:"font-medium text-right",children:[p.total_teams_used,"/",p.total_teams]})]}),(0,a.jsxs)("div",{className:"flex justify-between items-center",children:[(0,a.jsx)("span",{className:"text-gray-600 text-xs",children:"Remaining:"}),(0,a.jsx)("span",{className:g("font-medium text-right",S.isOverLimit&&"text-red-600",S.isNearLimit&&"text-yellow-600"),children:p.total_teams_remaining})]}),(0,a.jsxs)("div",{className:"flex justify-between items-center",children:[(0,a.jsx)("span",{className:"text-gray-600 text-xs",children:"Usage:"}),(0,a.jsxs)("span",{className:"font-medium text-right",children:[Math.round(S.usagePercentage),"%"]})]}),(0,a.jsx)("div",{className:"w-full bg-gray-200 rounded-full h-2",children:(0,a.jsx)("div",{className:g("h-2 rounded-full transition-all duration-300",S.isOverLimit&&"bg-red-500",S.isNearLimit&&"bg-yellow-500",!S.isOverLimit&&!S.isNearLimit&&"bg-green-500"),style:{width:"".concat(Math.min(S.usagePercentage,100),"%")}})})]})]})]}),{})}):null}}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/2249-01a36f26b1cecba3.js b/litellm/proxy/_experimental/out/_next/static/chunks/2249-01a36f26b1cecba3.js new file mode 100644 index 00000000000..b21241beec0 --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/2249-01a36f26b1cecba3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[2249],{64748:function(e,s,l){l.d(s,{Ct:function(){return a.Z},Dx:function(){return m.Z},OK:function(){return n.Z},Zb:function(){return r.Z},nP:function(){return o.Z},td:function(){return c.Z},v0:function(){return i.Z},x4:function(){return d.Z},xv:function(){return x.Z},zx:function(){return t.Z}});var a=l(41649),t=l(78489),r=l(12514),n=l(12485),i=l(18135),c=l(35242),d=l(29706),o=l(77991),x=l(84264),m=l(96761)},78801:function(e,s,l){l.d(s,{Z:function(){return a.Z},x:function(){return t.Z}});var a=l(12514),t=l(84264)},92249:function(e,s,l){l.d(s,{Z:function(){return W}});var a=l(57437),t=l(23639),r=l(64748),n=l(22116),i=l(78867),c=l(99376),d=l(2265),o=l(17906),x=l(20347),m=l(41649),h=l(78489),u=l(84264),p=l(99981),g=l(3810),j=l(15424),v=l(15690),b=l(10032),N=l(61994),f=l(5545),y=l(96761),_=l(19250),k=l(9114);let{Step:w}=v.default;var Z=e=>{let{visible:s,onClose:l,accessToken:t,agentHubData:r,onSuccess:i}=e,[c,o]=(0,d.useState)(0),[x,h]=(0,d.useState)(new Set),[p,g]=(0,d.useState)(!1),[j]=b.Z.useForm(),Z=()=>{o(0),h(new Set),j.resetFields(),l()},C=(e,s)=>{let l=new Set(x);s?l.add(e):l.delete(e),h(l)},S=e=>{e?h(new Set(r.map(e=>e.agent_id||e.name))):h(new Set)};(0,d.useEffect)(()=>{s&&r.length>0&&h(new Set(r.filter(e=>!0===e.is_public).map(e=>e.agent_id||e.name)))},[s,r]);let P=async()=>{if(0===x.size){k.Z.fromBackend("Please select at least one agent to make public");return}g(!0);try{let e=Array.from(x);await (0,_.makeAgentsPublicCall)(t,e),k.Z.success("Successfully made ".concat(e.length," agent(s) public!")),Z(),i()}catch(e){console.error("Error making agents public:",e),k.Z.fromBackend("Failed to make agents public. Please try again.")}finally{g(!1)}},M=()=>{let e=r.length>0&&r.every(e=>x.has(e.agent_id||e.name)),s=x.size>0&&!e;return(0,a.jsxs)("div",{className:"space-y-4",children:[(0,a.jsxs)("div",{className:"flex items-center justify-between",children:[(0,a.jsx)(y.Z,{children:"Select Agents to Make Public"}),(0,a.jsx)("div",{className:"flex items-center space-x-2",children:(0,a.jsxs)(N.Z,{checked:e,indeterminate:s,onChange:e=>S(e.target.checked),disabled:0===r.length,children:["Select All ",r.length>0&&"(".concat(r.length,")")]})})]}),(0,a.jsx)(u.Z,{className:"text-sm text-gray-600",children:"Select the agents you want to be visible on the public model hub. Users will still require a valid API key to use these agents."}),(0,a.jsx)("div",{className:"max-h-96 overflow-y-auto border rounded-lg p-4",children:(0,a.jsx)("div",{className:"space-y-3",children:0===r.length?(0,a.jsx)("div",{className:"text-center py-8 text-gray-500",children:(0,a.jsx)(u.Z,{children:"No agents available."})}):r.map(e=>{let s=e.agent_id||e.name;return(0,a.jsxs)("div",{className:"flex items-center space-x-3 p-3 border rounded-lg hover:bg-gray-50",children:[(0,a.jsx)(N.Z,{checked:x.has(s),onChange:e=>C(s,e.target.checked)}),(0,a.jsxs)("div",{className:"flex-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:e.name}),(0,a.jsxs)(m.Z,{color:"blue",size:"sm",children:["v",e.version]})]}),(0,a.jsx)(u.Z,{className:"text-xs text-gray-600 mt-1",children:e.description}),e.skills&&e.skills.length>0&&(0,a.jsxs)("div",{className:"flex flex-wrap gap-1 mt-1",children:[e.skills.slice(0,3).map(e=>(0,a.jsx)(m.Z,{color:"purple",size:"xs",children:e.name},e.id)),e.skills.length>3&&(0,a.jsxs)(u.Z,{className:"text-xs text-gray-500",children:["+",e.skills.length-3," more"]})]})]})]},s)})})}),x.size>0&&(0,a.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-3",children:(0,a.jsxs)(u.Z,{className:"text-sm text-blue-800",children:[(0,a.jsx)("strong",{children:x.size})," agent",1!==x.size?"s":""," selected"]})})]})},z=()=>(0,a.jsxs)("div",{className:"space-y-4",children:[(0,a.jsx)(y.Z,{children:"Confirm Making Agents Public"}),(0,a.jsx)("div",{className:"bg-yellow-50 border border-yellow-200 rounded-lg p-4",children:(0,a.jsxs)(u.Z,{className:"text-sm text-yellow-800",children:[(0,a.jsx)("strong",{children:"Warning:"})," Once you make these agents public, anyone who can go to the"," ",(0,a.jsx)("code",{children:"/ui/model_hub_table"})," will be able to know they exist on the proxy."]})}),(0,a.jsxs)("div",{className:"space-y-3",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:"Agents to be made public:"}),(0,a.jsx)("div",{className:"max-h-48 overflow-y-auto border rounded-lg p-3",children:(0,a.jsx)("div",{className:"space-y-2",children:Array.from(x).map(e=>{let s=r.find(s=>(s.agent_id||s.name)===e);return(0,a.jsx)("div",{className:"flex items-center justify-between p-2 bg-gray-50 rounded",children:(0,a.jsxs)("div",{className:"flex-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:(null==s?void 0:s.name)||e}),s&&(0,a.jsxs)(m.Z,{color:"blue",size:"xs",children:["v",s.version]})]}),(null==s?void 0:s.description)&&(0,a.jsx)(u.Z,{className:"text-xs text-gray-600 mt-1",children:s.description})]})},e)})})})]}),(0,a.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-3",children:(0,a.jsxs)(u.Z,{className:"text-sm text-blue-800",children:["Total: ",(0,a.jsx)("strong",{children:x.size})," agent",1!==x.size?"s":""," will be made public"]})})]});return(0,a.jsx)(n.Z,{title:"Make Agents Public",open:s,onCancel:Z,footer:null,width:1200,maskClosable:!1,children:(0,a.jsxs)(b.Z,{form:j,layout:"vertical",children:[(0,a.jsxs)(v.default,{current:c,className:"mb-6",children:[(0,a.jsx)(w,{title:"Select Agents"}),(0,a.jsx)(w,{title:"Confirm"})]}),(()=>{switch(c){case 0:return M();case 1:return z();default:return null}})(),(0,a.jsxs)("div",{className:"flex justify-between mt-6",children:[(0,a.jsx)(f.ZP,{onClick:0===c?Z:()=>{1===c&&o(0)},children:0===c?"Cancel":"Previous"}),(0,a.jsxs)("div",{className:"flex space-x-2",children:[0===c&&(0,a.jsx)(f.ZP,{onClick:()=>{if(0===c){if(0===x.size){k.Z.fromBackend("Please select at least one agent to make public");return}o(1)}},disabled:0===x.size,children:"Next"}),1===c&&(0,a.jsx)(f.ZP,{onClick:P,loading:p,children:"Make Public"})]})]})]})})};let{Step:C}=v.default;var S=e=>{let{visible:s,onClose:l,accessToken:t,mcpHubData:r,onSuccess:i}=e,[c,o]=(0,d.useState)(0),[x,h]=(0,d.useState)(new Set),[p,g]=(0,d.useState)(!1),[j]=b.Z.useForm(),w=()=>{o(0),h(new Set),j.resetFields(),l()},Z=(e,s)=>{let l=new Set(x);s?l.add(e):l.delete(e),h(l)},S=e=>{e?h(new Set(r.map(e=>e.server_id))):h(new Set)};(0,d.useEffect)(()=>{s&&r.length>0&&h(new Set(r.filter(e=>{var s;return(null===(s=e.mcp_info)||void 0===s?void 0:s.is_public)===!0}).map(e=>e.server_id)))},[s]);let P=async()=>{if(0===x.size){k.Z.fromBackend("Please select at least one MCP server to make public");return}g(!0);try{let e=Array.from(x);await (0,_.makeMCPPublicCall)(t,e),k.Z.success("Successfully made ".concat(e.length," MCP server(s) public!")),w(),i()}catch(e){console.error("Error making MCP servers public:",e),k.Z.fromBackend("Failed to make MCP servers public. Please try again.")}finally{g(!1)}},M=()=>{let e=r.length>0&&r.every(e=>x.has(e.server_id)),s=x.size>0&&!e;return(0,a.jsxs)("div",{className:"space-y-4",children:[(0,a.jsxs)("div",{className:"flex items-center justify-between",children:[(0,a.jsx)(y.Z,{children:"Select MCP Servers to Make Public"}),(0,a.jsx)("div",{className:"flex items-center space-x-2",children:(0,a.jsxs)(N.Z,{checked:e,indeterminate:s,onChange:e=>S(e.target.checked),disabled:0===r.length,children:["Select All ",r.length>0&&"(".concat(r.length,")")]})})]}),(0,a.jsx)(u.Z,{className:"text-sm text-gray-600",children:"Select the MCP servers you want to be visible on the public model hub. Users will still require a valid API key to use these servers."}),(0,a.jsx)("div",{className:"max-h-96 overflow-y-auto border rounded-lg p-4",children:(0,a.jsx)("div",{className:"space-y-3",children:0===r.length?(0,a.jsx)("div",{className:"text-center py-8 text-gray-500",children:(0,a.jsx)(u.Z,{children:"No MCP servers available."})}):r.map(e=>{var s;let l=(null===(s=e.mcp_info)||void 0===s?void 0:s.is_public)===!0;return(0,a.jsxs)("div",{className:"flex items-center space-x-3 p-3 border rounded-lg hover:bg-gray-50",children:[(0,a.jsx)(N.Z,{checked:x.has(e.server_id),onChange:s=>Z(e.server_id,s.target.checked)}),(0,a.jsxs)("div",{className:"flex-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:e.server_name}),l&&(0,a.jsx)(m.Z,{color:"emerald",size:"sm",children:"Public"}),(0,a.jsx)(m.Z,{color:"blue",size:"sm",children:e.transport}),(0,a.jsx)(m.Z,{color:"active"===e.status||"healthy"===e.status?"green":"inactive"===e.status||"unhealthy"===e.status?"red":"gray",size:"sm",children:e.status||"unknown"})]}),(0,a.jsx)(u.Z,{className:"text-xs text-gray-600 mt-1",children:e.description||e.url}),e.allowed_tools&&e.allowed_tools.length>0&&(0,a.jsxs)("div",{className:"flex flex-wrap gap-1 mt-1",children:[e.allowed_tools.slice(0,3).map((e,s)=>(0,a.jsx)(m.Z,{color:"purple",size:"xs",children:e},s)),e.allowed_tools.length>3&&(0,a.jsxs)(u.Z,{className:"text-xs text-gray-500",children:["+",e.allowed_tools.length-3," more"]})]})]})]},e.server_id)})})}),x.size>0&&(0,a.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-3",children:(0,a.jsxs)(u.Z,{className:"text-sm text-blue-800",children:[(0,a.jsx)("strong",{children:x.size})," MCP server",1!==x.size?"s":""," selected"]})})]})},z=()=>(0,a.jsxs)("div",{className:"space-y-4",children:[(0,a.jsx)(y.Z,{children:"Confirm Making MCP Servers Public"}),(0,a.jsx)("div",{className:"bg-yellow-50 border border-yellow-200 rounded-lg p-4",children:(0,a.jsxs)(u.Z,{className:"text-sm text-yellow-800",children:[(0,a.jsx)("strong",{children:"Warning:"})," Once you make these MCP servers public, anyone who can go to the"," ",(0,a.jsx)("code",{children:"/ui/model_hub_table"})," will be able to know they exist on the proxy."]})}),(0,a.jsxs)("div",{className:"space-y-3",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:"MCP Servers to be made public:"}),(0,a.jsx)("div",{className:"max-h-48 overflow-y-auto border rounded-lg p-3",children:(0,a.jsx)("div",{className:"space-y-2",children:Array.from(x).map(e=>{let s=r.find(s=>s.server_id===e);return(0,a.jsx)("div",{className:"flex items-center justify-between p-2 bg-gray-50 rounded",children:(0,a.jsxs)("div",{className:"flex-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:(null==s?void 0:s.server_name)||e}),s&&(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(m.Z,{color:"blue",size:"xs",children:s.transport}),(0,a.jsx)(m.Z,{color:"active"===s.status||"healthy"===s.status?"green":"inactive"===s.status||"unhealthy"===s.status?"red":"gray",size:"xs",children:s.status||"unknown"})]})]}),(null==s?void 0:s.description)&&(0,a.jsx)(u.Z,{className:"text-xs text-gray-600 mt-1",children:s.description}),(null==s?void 0:s.url)&&(0,a.jsx)(u.Z,{className:"text-xs text-gray-500 mt-1",children:s.url})]})},e)})})})]}),(0,a.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-3",children:(0,a.jsxs)(u.Z,{className:"text-sm text-blue-800",children:["Total: ",(0,a.jsx)("strong",{children:x.size})," MCP server",1!==x.size?"s":""," will be made public"]})})]});return(0,a.jsx)(n.Z,{title:"Make MCP Servers Public",open:s,onCancel:w,footer:null,width:1200,maskClosable:!1,children:(0,a.jsxs)(b.Z,{form:j,layout:"vertical",children:[(0,a.jsxs)(v.default,{current:c,className:"mb-6",children:[(0,a.jsx)(C,{title:"Select Servers"}),(0,a.jsx)(C,{title:"Confirm"})]}),(()=>{switch(c){case 0:return M();case 1:return z();default:return null}})(),(0,a.jsxs)("div",{className:"flex justify-between mt-6",children:[(0,a.jsx)(f.ZP,{onClick:0===c?w:()=>{1===c&&o(0)},children:0===c?"Cancel":"Previous"}),(0,a.jsxs)("div",{className:"flex space-x-2",children:[0===c&&(0,a.jsx)(f.ZP,{onClick:()=>{if(0===c){if(0===x.size){k.Z.fromBackend("Please select at least one MCP server to make public");return}o(1)}},disabled:0===x.size,children:"Next"}),1===c&&(0,a.jsx)(f.ZP,{onClick:P,loading:p,children:"Make Public"})]})]})]})})},P=l(78801),M=e=>{let{modelHubData:s,onFilteredDataChange:l,showFiltersCard:t=!0,className:r=""}=e,[n,i]=(0,d.useState)(""),[c,o]=(0,d.useState)(""),[x,m]=(0,d.useState)(""),[h,u]=(0,d.useState)(""),p=(0,d.useRef)([]),g=(0,d.useMemo)(()=>(null==s?void 0:s.filter(e=>{let s=e.model_group.toLowerCase().includes(n.toLowerCase()),l=""===c||e.providers.includes(c),a=""===x||e.mode===x,t=""===h||Object.entries(e).filter(e=>{let[s,l]=e;return s.startsWith("supports_")&&!0===l}).some(e=>{let[s]=e;return s.replace(/^supports_/,"").split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")===h});return s&&l&&a&&t}))||[],[s,n,c,x,h]);(0,d.useEffect)(()=>{(g.length!==p.current.length||g.some((e,s)=>{var l;return e.model_group!==(null===(l=p.current[s])||void 0===l?void 0:l.model_group)}))&&(p.current=g,l(g))},[g,l]);let j=(0,a.jsxs)("div",{className:"flex flex-wrap gap-4 items-center",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(P.x,{className:"text-sm font-medium mb-2",children:"Search Models:"}),(0,a.jsx)("input",{type:"text",placeholder:"Search model names...",value:n,onChange:e=>i(e.target.value),className:"border rounded px-3 py-2 w-64 h-10 text-sm"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(P.x,{className:"text-sm font-medium mb-2",children:"Provider:"}),(0,a.jsxs)("select",{value:c,onChange:e=>o(e.target.value),className:"border rounded px-3 py-2 text-sm text-gray-600 w-40 h-10",children:[(0,a.jsx)("option",{value:"",className:"text-sm text-gray-600",children:"All Providers"}),s&&(e=>{let s=new Set;return e.forEach(e=>{e.providers.forEach(e=>s.add(e))}),Array.from(s)})(s).map(e=>(0,a.jsx)("option",{value:e,className:"text-sm text-gray-800",children:e},e))]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(P.x,{className:"text-sm font-medium mb-2",children:"Mode:"}),(0,a.jsxs)("select",{value:x,onChange:e=>m(e.target.value),className:"border rounded px-3 py-2 text-sm text-gray-600 w-32 h-10",children:[(0,a.jsx)("option",{value:"",className:"text-sm text-gray-600",children:"All Modes"}),s&&(e=>{let s=new Set;return e.forEach(e=>{e.mode&&s.add(e.mode)}),Array.from(s)})(s).map(e=>(0,a.jsx)("option",{value:e,className:"text-sm text-gray-800",children:e},e))]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(P.x,{className:"text-sm font-medium mb-2",children:"Features:"}),(0,a.jsxs)("select",{value:h,onChange:e=>u(e.target.value),className:"border rounded px-3 py-2 text-sm text-gray-600 w-48 h-10",children:[(0,a.jsx)("option",{value:"",className:"text-sm text-gray-600",children:"All Features"}),s&&(e=>{let s=new Set;return e.forEach(e=>{Object.entries(e).filter(e=>{let[s,l]=e;return s.startsWith("supports_")&&!0===l}).forEach(e=>{let[l]=e,a=l.replace(/^supports_/,"").split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ");s.add(a)})}),Array.from(s).sort()})(s).map(e=>(0,a.jsx)("option",{value:e,className:"text-sm text-gray-800",children:e},e))]})]}),(n||c||x||h)&&(0,a.jsx)("div",{className:"flex items-end",children:(0,a.jsx)("button",{onClick:()=>{i(""),o(""),m(""),u("")},className:"text-blue-600 hover:text-blue-800 text-sm underline h-10 flex items-center",children:"Clear Filters"})})]});return t?(0,a.jsx)(P.Z,{className:"mb-6 ".concat(r),children:j}):(0,a.jsx)("div",{className:r,children:j})};let{Step:z}=v.default;var A=e=>{let{visible:s,onClose:l,accessToken:t,modelHubData:r,onSuccess:i}=e,[c,o]=(0,d.useState)(0),[x,h]=(0,d.useState)(new Set),[p,g]=(0,d.useState)([]),[j,w]=(0,d.useState)(!1),[Z]=b.Z.useForm(),C=()=>{o(0),h(new Set),g([]),Z.resetFields(),l()},S=(e,s)=>{let l=new Set(x);s?l.add(e):l.delete(e),h(l)},P=e=>{e?h(new Set(p.map(e=>e.model_group))):h(new Set)},A=(0,d.useCallback)(e=>{g(e)},[]);(0,d.useEffect)(()=>{s&&r.length>0&&(g(r),h(new Set(r.filter(e=>!0===e.is_public_model_group).map(e=>e.model_group))))},[s,r]);let F=async()=>{if(0===x.size){k.Z.fromBackend("Please select at least one model to make public");return}w(!0);try{let e=Array.from(x);await (0,_.makeModelGroupPublic)(t,e),k.Z.success("Successfully made ".concat(e.length," model group(s) public!")),C(),i()}catch(e){console.error("Error making model groups public:",e),k.Z.fromBackend("Failed to make model groups public. Please try again.")}finally{w(!1)}},L=()=>{let e=p.length>0&&p.every(e=>x.has(e.model_group)),s=x.size>0&&!e;return(0,a.jsxs)("div",{className:"space-y-4",children:[(0,a.jsxs)("div",{className:"flex items-center justify-between",children:[(0,a.jsx)(y.Z,{children:"Select Models to Make Public"}),(0,a.jsx)("div",{className:"flex items-center space-x-2",children:(0,a.jsxs)(N.Z,{checked:e,indeterminate:s,onChange:e=>P(e.target.checked),disabled:0===p.length,children:["Select All ",p.length>0&&"(".concat(p.length,")")]})})]}),(0,a.jsx)(u.Z,{className:"text-sm text-gray-600",children:"Select the models you want to be visible on the public model hub. Users will still require a valid API key to use these models."}),(0,a.jsx)(M,{modelHubData:r,onFilteredDataChange:A,showFiltersCard:!1,className:"border rounded-lg p-4 bg-gray-50"}),(0,a.jsx)("div",{className:"max-h-96 overflow-y-auto border rounded-lg p-4",children:(0,a.jsx)("div",{className:"space-y-3",children:0===p.length?(0,a.jsx)("div",{className:"text-center py-8 text-gray-500",children:(0,a.jsx)(u.Z,{children:"No models match the current filters."})}):p.map(e=>(0,a.jsxs)("div",{className:"flex items-center space-x-3 p-3 border rounded-lg hover:bg-gray-50",children:[(0,a.jsx)(N.Z,{checked:x.has(e.model_group),onChange:s=>S(e.model_group,s.target.checked)}),(0,a.jsxs)("div",{className:"flex-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:e.model_group}),e.mode&&(0,a.jsx)(m.Z,{color:"green",size:"sm",children:e.mode})]}),(0,a.jsx)("div",{className:"flex flex-wrap gap-1 mt-1",children:e.providers.map(e=>(0,a.jsx)(m.Z,{color:"blue",size:"xs",children:e},e))})]})]},e.model_group))})}),x.size>0&&(0,a.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-3",children:(0,a.jsxs)(u.Z,{className:"text-sm text-blue-800",children:[(0,a.jsx)("strong",{children:x.size})," model",1!==x.size?"s":""," selected"]})})]})},D=()=>(0,a.jsxs)("div",{className:"space-y-4",children:[(0,a.jsx)(y.Z,{children:"Confirm Making Models Public"}),(0,a.jsx)("div",{className:"bg-yellow-50 border border-yellow-200 rounded-lg p-4",children:(0,a.jsxs)(u.Z,{className:"text-sm text-yellow-800",children:[(0,a.jsx)("strong",{children:"Warning:"})," Once you make these models public, anyone who can go to the"," ",(0,a.jsx)("code",{children:"/ui/model_hub_table"})," will be able to know they exist on the proxy."]})}),(0,a.jsxs)("div",{className:"space-y-3",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:"Models to be made public:"}),(0,a.jsx)("div",{className:"max-h-48 overflow-y-auto border rounded-lg p-3",children:(0,a.jsx)("div",{className:"space-y-2",children:Array.from(x).map(e=>{let s=r.find(s=>s.model_group===e);return(0,a.jsx)("div",{className:"flex items-center justify-between p-2 bg-gray-50 rounded",children:(0,a.jsxs)("div",{children:[(0,a.jsx)(u.Z,{className:"font-medium",children:e}),s&&(0,a.jsx)("div",{className:"flex flex-wrap gap-1 mt-1",children:s.providers.map(e=>(0,a.jsx)(m.Z,{color:"blue",size:"xs",children:e},e))})]})},e)})})})]}),(0,a.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-3",children:(0,a.jsxs)(u.Z,{className:"text-sm text-blue-800",children:["Total: ",(0,a.jsx)("strong",{children:x.size})," model",1!==x.size?"s":""," will be made public"]})})]});return(0,a.jsx)(n.Z,{title:"Make Models Public",open:s,onCancel:C,footer:null,width:1200,maskClosable:!1,children:(0,a.jsxs)(b.Z,{form:Z,layout:"vertical",children:[(0,a.jsxs)(v.default,{current:c,className:"mb-6",children:[(0,a.jsx)(z,{title:"Select Models"}),(0,a.jsx)(z,{title:"Confirm"})]}),(()=>{switch(c){case 0:return L();case 1:return D();default:return null}})(),(0,a.jsxs)("div",{className:"flex justify-between mt-6",children:[(0,a.jsx)(f.ZP,{onClick:0===c?C:()=>{1===c&&o(0)},children:0===c?"Cancel":"Previous"}),(0,a.jsxs)("div",{className:"flex space-x-2",children:[0===c&&(0,a.jsx)(f.ZP,{onClick:()=>{if(0===c){if(0===x.size){k.Z.fromBackend("Please select at least one model to make public");return}o(1)}},disabled:0===x.size,children:"Next"}),1===c&&(0,a.jsx)(f.ZP,{onClick:F,loading:j,children:"Make Public"})]})]})]})})},F=l(8048);let L=e=>e.replace(/^supports_/,"").split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" "),D=e=>Object.entries(e).filter(e=>{let[s,l]=e;return s.startsWith("supports_")&&!0===l}).map(e=>{let[s]=e;return s}),O=e=>"$".concat((1e6*e).toFixed(2)),U=e=>e>=1e6?"".concat((e/1e6).toFixed(1),"M"):e>=1e3?"".concat((e/1e3).toFixed(1),"K"):e.toString(),E=function(e,s){let l=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=[{header:"Public Model Name",accessorKey:"model_group",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:l}=e,r=l.original;return(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium text-sm",children:r.model_group}),(0,a.jsx)(p.Z,{title:"Copy model name",children:(0,a.jsx)(t.Z,{onClick:()=>s(r.model_group),className:"cursor-pointer text-gray-500 hover:text-blue-500 text-xs"})})]}),(0,a.jsx)("div",{className:"md:hidden",children:(0,a.jsx)(u.Z,{className:"text-xs text-gray-600",children:r.providers.join(", ")})})]})}},{header:"Provider",accessorKey:"providers",enableSorting:!0,sortingFn:(e,s)=>{let l=e.original.providers.join(", "),a=s.original.providers.join(", ");return l.localeCompare(a)},cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsxs)("div",{className:"flex flex-wrap gap-1",children:[l.providers.slice(0,2).map(e=>(0,a.jsx)(g.Z,{color:"blue",className:"text-xs",children:e},e)),l.providers.length>2&&(0,a.jsxs)(u.Z,{className:"text-xs text-gray-500",children:["+",l.providers.length-2]})]})},meta:{className:"hidden md:table-cell"}},{header:"Mode",accessorKey:"mode",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original;return l.mode?(0,a.jsx)(m.Z,{color:"green",size:"sm",children:l.mode}):(0,a.jsx)(u.Z,{className:"text-gray-500",children:"-"})},meta:{className:"hidden lg:table-cell"}},{header:"Tokens",accessorKey:"max_input_tokens",enableSorting:!0,sortingFn:(e,s)=>(e.original.max_input_tokens||0)+(e.original.max_output_tokens||0)-((s.original.max_input_tokens||0)+(s.original.max_output_tokens||0)),cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsx)("div",{className:"space-y-1",children:(0,a.jsxs)(u.Z,{className:"text-xs",children:[l.max_input_tokens?U(l.max_input_tokens):"-"," /"," ",l.max_output_tokens?U(l.max_output_tokens):"-"]})})},meta:{className:"hidden lg:table-cell"}},{header:"Cost/1M",accessorKey:"input_cost_per_token",enableSorting:!0,sortingFn:(e,s)=>(e.original.input_cost_per_token||0)+(e.original.output_cost_per_token||0)-((s.original.input_cost_per_token||0)+(s.original.output_cost_per_token||0)),cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsx)(u.Z,{className:"text-xs",children:l.input_cost_per_token?O(l.input_cost_per_token):"-"}),(0,a.jsx)(u.Z,{className:"text-xs text-gray-500",children:l.output_cost_per_token?O(l.output_cost_per_token):"-"})]})}},{header:"Features",accessorKey:"capabilities",enableSorting:!1,cell:e=>{let{row:s}=e,l=D(s.original),t=["green","blue","purple","orange","red","yellow"];return(0,a.jsx)("div",{className:"flex flex-wrap gap-1",children:0===l.length?(0,a.jsx)(u.Z,{className:"text-gray-500 text-xs",children:"-"}):l.map((e,s)=>(0,a.jsx)(m.Z,{color:t[s%t.length],size:"xs",children:L(e)},e))})}},{header:"Public",accessorKey:"is_public_model_group",enableSorting:!0,sortingFn:(e,s)=>(!0===e.original.is_public_model_group?1:0)-(!0===s.original.is_public_model_group?1:0),cell:e=>{let{row:s}=e;return!0===s.original.is_public_model_group?(0,a.jsx)(m.Z,{color:"green",size:"xs",children:"Yes"}):(0,a.jsx)(m.Z,{color:"gray",size:"xs",children:"No"})},meta:{className:"hidden md:table-cell"}},{header:"Details",id:"details",enableSorting:!1,cell:s=>{let{row:l}=s,t=l.original;return(0,a.jsxs)(h.Z,{size:"xs",variant:"secondary",onClick:()=>e(t),icon:j.Z,children:[(0,a.jsx)("span",{className:"hidden lg:inline",children:"Details"}),(0,a.jsx)("span",{className:"lg:hidden",children:"Info"})]})}}];return l?r.filter(e=>!("accessorKey"in e)||"is_public_model_group"!==e.accessorKey):r};var K=l(87526),T=l(86462),H=l(47686),I=l(77355),R=l(93416),B=l(74998),Y=l(95704),V=e=>{let{accessToken:s,userRole:l}=e,[t,r]=(0,d.useState)([]),[i,c]=(0,d.useState)({url:"",displayName:""}),[o,m]=(0,d.useState)(null),[h,u]=(0,d.useState)(!1),[p,g]=(0,d.useState)(!0),j=async()=>{if(s)try{u(!0);let e=await (0,_.getPublicModelHubInfo)();if(e&&e.useful_links){let s=e.useful_links||{},l=Object.entries(s).map((e,s)=>{let[l,a]=e;return{id:"".concat(s,"-").concat(l),displayName:l,url:a}});r(l)}else r([])}catch(e){console.error("Error fetching useful links:",e),r([])}finally{u(!1)}};if((0,d.useEffect)(()=>{j()},[s]),!(0,x.tY)(l||""))return null;let v=async e=>{if(!s)return!1;try{let l={};return e.forEach(e=>{l[e.displayName]=e.url}),await (0,_.updateUsefulLinksCall)(s,l),n.Z.success({title:"Links Saved Successfully",content:(0,a.jsxs)("div",{className:"py-4",children:[(0,a.jsx)("p",{className:"text-gray-600 mb-4",children:"Your useful links have been saved and are now visible on the public model hub."}),(0,a.jsxs)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-4",children:[(0,a.jsx)("p",{className:"text-sm text-blue-800 mb-2 font-medium",children:"View your updated model hub:"}),(0,a.jsx)("a",{href:"".concat((0,_.getProxyBaseUrl)(),"/ui/model_hub_table"),target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center text-blue-600 hover:text-blue-800 underline text-sm font-medium",children:"Open Public Model Hub →"})]})]}),width:500,okText:"Close",maskClosable:!0,keyboard:!0}),!0}catch(e){return console.error("Error saving links:",e),k.Z.fromBackend("Failed to save links - ".concat(e)),!1}},b=async()=>{if(!i.url||!i.displayName)return;try{new URL(i.url)}catch(e){k.Z.fromBackend("Please enter a valid URL");return}if(t.some(e=>e.displayName===i.displayName)){k.Z.fromBackend("A link with this display name already exists");return}let e=[...t,{id:"".concat(Date.now(),"-").concat(i.displayName),displayName:i.displayName,url:i.url}];await v(e)&&(r(e),c({url:"",displayName:""}),k.Z.success("Link added successfully"))},N=e=>{m({...e})},f=async()=>{if(!o)return;try{new URL(o.url)}catch(e){k.Z.fromBackend("Please enter a valid URL");return}if(t.some(e=>e.id!==o.id&&e.displayName===o.displayName)){k.Z.fromBackend("A link with this display name already exists");return}let e=t.map(e=>e.id===o.id?o:e);await v(e)&&(r(e),m(null),k.Z.success("Link updated successfully"))},y=()=>{m(null)},w=async e=>{let s=t.filter(s=>s.id!==e);await v(s)&&(r(s),k.Z.success("Link deleted successfully"))},Z=e=>{window.open(e,"_blank")};return(0,a.jsxs)(Y.Zb,{className:"mb-6",children:[(0,a.jsxs)("div",{className:"flex items-center justify-between cursor-pointer",onClick:()=>g(!p),children:[(0,a.jsxs)("div",{className:"flex flex-col",children:[(0,a.jsx)(Y.Dx,{className:"mb-0",children:"Link Management"}),(0,a.jsx)("p",{className:"text-sm text-gray-500",children:"Manage the links that are displayed under 'Useful Links' on the public model hub."})]}),(0,a.jsx)("div",{className:"flex items-center",children:p?(0,a.jsx)(T.Z,{className:"w-5 h-5 text-gray-500"}):(0,a.jsx)(H.Z,{className:"w-5 h-5 text-gray-500"})})]}),p&&(0,a.jsxs)("div",{className:"mt-4",children:[(0,a.jsxs)("div",{className:"mb-6",children:[(0,a.jsx)(Y.xv,{className:"text-sm font-medium text-gray-700 mb-2",children:"Add New Link"}),(0,a.jsxs)("div",{className:"grid grid-cols-3 gap-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("label",{className:"block text-xs text-gray-500 mb-1",children:"URL"}),(0,a.jsx)("input",{type:"text",value:i.url,onChange:e=>c({...i,url:e.target.value}),placeholder:"https://example.com",className:"w-full px-3 py-2 border border-gray-300 rounded-md text-sm"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("label",{className:"block text-xs text-gray-500 mb-1",children:"Display Name"}),(0,a.jsx)("input",{type:"text",value:i.displayName,onChange:e=>c({...i,displayName:e.target.value}),placeholder:"Friendly name",className:"w-full px-3 py-2 border border-gray-300 rounded-md text-sm"})]}),(0,a.jsx)("div",{className:"flex items-end",children:(0,a.jsxs)("button",{onClick:b,disabled:!i.url||!i.displayName,className:"flex items-center px-4 py-2 rounded-md text-sm ".concat(i.url&&i.displayName?"bg-green-600 text-white hover:bg-green-700":"bg-gray-300 text-gray-500 cursor-not-allowed"),children:[(0,a.jsx)(I.Z,{className:"w-4 h-4 mr-1"}),"Add Link"]})})]})]}),(0,a.jsx)(Y.xv,{className:"text-sm font-medium text-gray-700 mb-2",children:"Manage Existing Links"}),(0,a.jsx)("div",{className:"rounded-lg custom-border relative",children:(0,a.jsx)("div",{className:"overflow-x-auto",children:(0,a.jsxs)(Y.iA,{className:"[&_td]:py-0.5 [&_th]:py-1",children:[(0,a.jsx)(Y.ss,{children:(0,a.jsxs)(Y.SC,{children:[(0,a.jsx)(Y.xs,{className:"py-1 h-8",children:"Display Name"}),(0,a.jsx)(Y.xs,{className:"py-1 h-8",children:"URL"}),(0,a.jsx)(Y.xs,{className:"py-1 h-8",children:"Actions"})]})}),(0,a.jsxs)(Y.RM,{children:[t.map(e=>(0,a.jsx)(Y.SC,{className:"h-8",children:o&&o.id===e.id?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(Y.pj,{className:"py-0.5",children:(0,a.jsx)("input",{type:"text",value:o.displayName,onChange:e=>m({...o,displayName:e.target.value}),className:"w-full px-2 py-1 border border-gray-300 rounded-md text-sm"})}),(0,a.jsx)(Y.pj,{className:"py-0.5",children:(0,a.jsx)("input",{type:"text",value:o.url,onChange:e=>m({...o,url:e.target.value}),className:"w-full px-2 py-1 border border-gray-300 rounded-md text-sm"})}),(0,a.jsx)(Y.pj,{className:"py-0.5 whitespace-nowrap",children:(0,a.jsxs)("div",{className:"flex space-x-2",children:[(0,a.jsx)("button",{onClick:f,className:"text-xs bg-blue-50 text-blue-600 px-2 py-1 rounded hover:bg-blue-100",children:"Save"}),(0,a.jsx)("button",{onClick:y,className:"text-xs bg-gray-50 text-gray-600 px-2 py-1 rounded hover:bg-gray-100",children:"Cancel"})]})})]}):(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(Y.pj,{className:"py-0.5 text-sm text-gray-900",children:e.displayName}),(0,a.jsx)(Y.pj,{className:"py-0.5 text-sm text-gray-500",children:e.url}),(0,a.jsx)(Y.pj,{className:"py-0.5 whitespace-nowrap",children:(0,a.jsxs)("div",{className:"flex space-x-2",children:[(0,a.jsx)("button",{onClick:()=>Z(e.url),className:"text-xs bg-green-50 text-green-600 px-2 py-1 rounded hover:bg-green-100",children:"Use"}),(0,a.jsx)("button",{onClick:()=>N(e),className:"text-xs bg-blue-50 text-blue-600 px-2 py-1 rounded hover:bg-blue-100",children:(0,a.jsx)(R.Z,{className:"w-3 h-3"})}),(0,a.jsx)("button",{onClick:()=>w(e.id),className:"text-xs bg-red-50 text-red-600 px-2 py-1 rounded hover:bg-red-100",children:(0,a.jsx)(B.Z,{className:"w-3 h-3"})})]})})]})},e.id)),0===t.length&&(0,a.jsx)(Y.SC,{children:(0,a.jsx)(Y.pj,{colSpan:3,className:"py-0.5 text-sm text-gray-500 text-center",children:"No links added yet. Add a new link above."})})]})]})})})]})]})},W=e=>{var s,l,v,b;let{accessToken:N,publicPage:f,premiumUser:y,userRole:w}=e,[C,P]=(0,d.useState)(!1),[z,L]=(0,d.useState)(null),[D,O]=(0,d.useState)(!0),[U,T]=(0,d.useState)(!1),[H,I]=(0,d.useState)(!1),[R,B]=(0,d.useState)(null),[Y,W]=(0,d.useState)([]),[q,G]=(0,d.useState)(!1),[J,$]=(0,d.useState)(null),[Q,X]=(0,d.useState)(!1),[ee,es]=(0,d.useState)(!0),[el,ea]=(0,d.useState)(null),[et,er]=(0,d.useState)(!1),[en,ei]=(0,d.useState)(null),[ec,ed]=(0,d.useState)(!0),[eo,ex]=(0,d.useState)(null),[em,eh]=(0,d.useState)(!1),[eu,ep]=(0,d.useState)(!1),eg=(0,c.useRouter)(),ej=(0,d.useRef)(null),ev=(0,d.useRef)(null),eb=(0,d.useRef)(null);(0,d.useEffect)(()=>{let e=async e=>{try{O(!0);let s=await (0,_.modelHubCall)(e);console.log("ModelHubData:",s),L(s.data),(0,_.getConfigFieldSetting)(e,"enable_public_model_hub").then(e=>{console.log("data: ".concat(JSON.stringify(e))),!0==e.field_value&&P(!0)}).catch(e=>{})}catch(e){console.error("There was an error fetching the model data",e)}finally{O(!1)}},s=async()=>{try{var e,s;O(!0),await (0,_.getUiConfig)();let l=await (0,_.modelHubPublicModelsCall)();console.log("ModelHubData:",l),console.log("First model structure:",l[0]),console.log("Model has model_group?",null===(e=l[0])||void 0===e?void 0:e.model_group),console.log("Model has providers?",null===(s=l[0])||void 0===s?void 0:s.providers),L(l),P(!0)}catch(e){console.error("There was an error fetching the public model data",e)}finally{O(!1)}};N?e(N):f&&s()},[N,f]),(0,d.useEffect)(()=>{let e=async()=>{if(N)try{es(!0);let e=await (0,_.getAgentsList)(N);console.log("AgentHubData:",e);let s=e.agents.map(e=>({agent_id:e.agent_id,...e.agent_card_params,is_public:e.litellm_params.is_public}));$(s)}catch(e){console.error("There was an error fetching the agent data",e)}finally{es(!1)}};f||e()},[f,N]),(0,d.useEffect)(()=>{let e=async()=>{if(N)try{ed(!0);let e=await (0,_.fetchMCPServers)(N);console.log("MCPHubData:",e),ei(e)}catch(e){console.error("There was an error fetching the MCP server data",e)}finally{ed(!1)}};f||e()},[f,N]);let eN=()=>{N&&G(!0)},ef=()=>{N&&X(!0)},ey=()=>{N&&ep(!0)},e_=()=>{T(!1),I(!1),B(null),er(!1),ea(null),eh(!1),ex(null)},ek=()=>{T(!1),I(!1),B(null),er(!1),ea(null),eh(!1),ex(null)},ew=e=>{navigator.clipboard.writeText(e),k.Z.success("Copied to clipboard!")},eZ=e=>e.replace(/^supports_/,"").split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" "),eC=e=>Object.entries(e).filter(e=>{let[s,l]=e;return s.startsWith("supports_")&&!0===l}).map(e=>{let[s]=e;return s}),eS=e=>"$".concat((1e6*e).toFixed(2)),eP=(0,d.useCallback)(e=>{W(e)},[]);return(console.log("publicPage: ",f),console.log("publicPageAllowed: ",C),f&&C)?(0,a.jsx)(K.Z,{accessToken:N}):(0,a.jsxs)("div",{className:"w-full mx-4 h-[75vh]",children:[!1==f?(0,a.jsxs)("div",{className:"w-full m-2 mt-2 p-8",children:[(0,a.jsxs)("div",{className:"flex justify-between items-center mb-6",children:[(0,a.jsxs)("div",{className:"flex flex-col items-start",children:[(0,a.jsx)(r.Dx,{className:"text-center",children:"AI Hub"}),(0,x.tY)(w||"")?(0,a.jsx)("p",{className:"text-sm text-gray-600",children:"Make models, agents, and MCP servers public for developers to know what's available."}):(0,a.jsx)("p",{className:"text-sm text-gray-600",children:"A list of all public model names personally available to you."})]}),(0,a.jsxs)("div",{className:"flex items-center space-x-4",children:[(0,a.jsx)(r.xv,{children:"Model Hub URL:"}),(0,a.jsxs)("div",{className:"flex items-center bg-gray-200 px-2 py-1 rounded",children:[(0,a.jsx)(r.xv,{className:"mr-2",children:"".concat((0,_.getProxyBaseUrl)(),"/ui/model_hub_table")}),(0,a.jsx)("button",{onClick:()=>ew("".concat((0,_.getProxyBaseUrl)(),"/ui/model_hub_table")),className:"p-1 hover:bg-gray-300 rounded transition-colors",title:"Copy URL",children:(0,a.jsx)(i.Z,{size:16,className:"text-gray-600"})})]})]})]}),(0,x.tY)(w||"")&&(0,a.jsx)("div",{className:"mt-8 mb-2",children:(0,a.jsx)(V,{accessToken:N,userRole:w})}),(0,a.jsxs)(r.v0,{children:[(0,a.jsxs)(r.td,{className:"mb-4",children:[(0,a.jsx)(r.OK,{children:"Model Hub"}),(0,a.jsx)(r.OK,{children:"Agent Hub"}),(0,a.jsx)(r.OK,{children:"MCP Hub"})]}),(0,a.jsxs)(r.nP,{children:[(0,a.jsxs)(r.x4,{children:[(0,a.jsxs)(r.Zb,{children:[!1==f&&(0,x.tY)(w||"")&&(0,a.jsx)("div",{className:"flex justify-end mb-4",children:(0,a.jsx)(r.zx,{onClick:()=>eN(),children:"Select Models to Make Public"})}),(0,a.jsx)(M,{modelHubData:z||[],onFilteredDataChange:eP}),(0,a.jsx)(F.C,{columns:E(e=>{B(e),T(!0)},ew,f),data:Y,isLoading:D,table:ej,defaultSorting:[{id:"model_group",desc:!1}]})]}),(0,a.jsx)("div",{className:"mt-4 text-center space-y-2",children:(0,a.jsxs)(r.xv,{className:"text-sm text-gray-600",children:["Showing ",Y.length," of ",(null==z?void 0:z.length)||0," models"]})})]}),(0,a.jsxs)(r.x4,{children:[(0,a.jsxs)(r.Zb,{children:[!1==f&&(0,x.tY)(w||"")&&(0,a.jsx)("div",{className:"flex justify-end mb-4",children:(0,a.jsx)(r.zx,{onClick:()=>ef(),children:"Select Agents to Make Public"})}),(0,a.jsx)(F.C,{columns:function(e,s){return arguments.length>2&&void 0!==arguments[2]&&arguments[2],[{header:"Agent Name",accessorKey:"name",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:l}=e,r=l.original;return(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium text-sm",children:r.name}),(0,a.jsx)(p.Z,{title:"Copy agent name",children:(0,a.jsx)(t.Z,{onClick:()=>s(r.name),className:"cursor-pointer text-gray-500 hover:text-blue-500 text-xs"})})]}),(0,a.jsx)("div",{className:"md:hidden",children:(0,a.jsx)(u.Z,{className:"text-xs text-gray-600",children:r.description})})]})}},{header:"Description",accessorKey:"description",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsx)(u.Z,{className:"text-xs line-clamp-2",children:l.description||"-"})},meta:{className:"hidden md:table-cell"}},{header:"Version",accessorKey:"version",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsxs)(m.Z,{color:"blue",size:"sm",children:["v",l.version]})},meta:{className:"hidden lg:table-cell"}},{header:"Protocol",accessorKey:"protocolVersion",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsx)(u.Z,{className:"text-xs",children:l.protocolVersion||"-"})},meta:{className:"hidden lg:table-cell"}},{header:"Skills",accessorKey:"skills",enableSorting:!1,cell:e=>{let{row:s}=e,l=s.original.skills||[];return(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsxs)(u.Z,{className:"text-xs font-medium",children:[l.length," skill",1!==l.length?"s":""]}),l.length>0&&(0,a.jsxs)("div",{className:"flex flex-wrap gap-1",children:[l.slice(0,2).map(e=>(0,a.jsx)(g.Z,{color:"purple",className:"text-xs",children:e.name},e.id)),l.length>2&&(0,a.jsxs)(u.Z,{className:"text-xs text-gray-500",children:["+",l.length-2]})]})]})}},{header:"Capabilities",accessorKey:"capabilities",enableSorting:!1,cell:e=>{let{row:s}=e,l=Object.entries(s.original.capabilities||{}).filter(e=>{let[s,l]=e;return!0===l}).map(e=>{let[s]=e;return s});return(0,a.jsx)("div",{className:"flex flex-wrap gap-1",children:0===l.length?(0,a.jsx)(u.Z,{className:"text-gray-500 text-xs",children:"-"}):l.map(e=>(0,a.jsx)(m.Z,{color:"green",size:"xs",children:e},e))})}},{header:"I/O Modes",accessorKey:"defaultInputModes",enableSorting:!1,cell:e=>{let{row:s}=e,l=s.original,t=l.defaultInputModes||[],r=l.defaultOutputModes||[];return(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsxs)(u.Z,{className:"text-xs",children:[(0,a.jsx)("span",{className:"font-medium",children:"In:"})," ",t.join(", ")||"-"]}),(0,a.jsxs)(u.Z,{className:"text-xs",children:[(0,a.jsx)("span",{className:"font-medium",children:"Out:"})," ",r.join(", ")||"-"]})]})},meta:{className:"hidden xl:table-cell"}},{header:"Public",accessorKey:"is_public",enableSorting:!0,sortingFn:(e,s)=>(!0===e.original.is_public?1:0)-(!0===s.original.is_public?1:0),cell:e=>{let{row:s}=e;return console.log("CHECKPOINT 1: ".concat(JSON.stringify(s.original))),!0===s.original.is_public?(0,a.jsx)(m.Z,{color:"green",size:"xs",children:"Yes"}):(0,a.jsx)(m.Z,{color:"gray",size:"xs",children:"No"})},meta:{className:"hidden md:table-cell"}},{header:"Details",id:"details",enableSorting:!1,cell:s=>{let{row:l}=s,t=l.original;return(0,a.jsxs)(h.Z,{size:"xs",variant:"secondary",onClick:()=>e(t),icon:j.Z,children:[(0,a.jsx)("span",{className:"hidden lg:inline",children:"Details"}),(0,a.jsx)("span",{className:"lg:hidden",children:"Info"})]})}}]}(e=>{ea(e),er(!0)},ew,f),data:J||[],isLoading:ee,table:ev,defaultSorting:[{id:"name",desc:!1}]})]}),(0,a.jsx)("div",{className:"mt-4 text-center space-y-2",children:(0,a.jsxs)(r.xv,{className:"text-sm text-gray-600",children:["Showing ",(null==J?void 0:J.length)||0," agent",(null==J?void 0:J.length)!==1?"s":""]})})]}),(0,a.jsxs)(r.x4,{children:[(0,a.jsxs)(r.Zb,{children:[!1==f&&(0,x.tY)(w||"")&&(0,a.jsx)("div",{className:"flex justify-end mb-4",children:(0,a.jsx)(r.zx,{onClick:()=>ey(),children:"Select MCP Servers to Make Public"})}),(0,a.jsx)(F.C,{columns:function(e,s){return arguments.length>2&&void 0!==arguments[2]&&arguments[2],[{header:"Server Name",accessorKey:"server_name",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:l}=e,r=l.original;return(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium text-sm",children:r.server_name}),(0,a.jsx)(p.Z,{title:"Copy server name",children:(0,a.jsx)(t.Z,{onClick:()=>s(r.server_name),className:"cursor-pointer text-gray-500 hover:text-blue-500 text-xs"})})]}),(0,a.jsx)("div",{className:"md:hidden",children:(0,a.jsx)(u.Z,{className:"text-xs text-gray-600",children:r.description||"-"})})]})}},{header:"Description",accessorKey:"description",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsx)(u.Z,{className:"text-xs line-clamp-2",children:l.description||"-"})},meta:{className:"hidden md:table-cell"}},{header:"URL",accessorKey:"url",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:l}=e,r=l.original;return(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"text-xs truncate max-w-xs",children:r.url}),(0,a.jsx)(p.Z,{title:"Copy URL",children:(0,a.jsx)(t.Z,{onClick:()=>s(r.url),className:"cursor-pointer text-gray-500 hover:text-blue-500 text-xs flex-shrink-0"})})]})},meta:{className:"hidden lg:table-cell"}},{header:"Transport",accessorKey:"transport",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsx)(m.Z,{color:"blue",size:"sm",children:l.transport})},meta:{className:"hidden md:table-cell"}},{header:"Auth Type",accessorKey:"auth_type",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original,t="none"===l.auth_type?"gray":"green";return(0,a.jsx)(m.Z,{color:t,size:"sm",children:l.auth_type})},meta:{className:"hidden md:table-cell"}},{header:"Status",accessorKey:"status",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original,t={active:"green",inactive:"red",unknown:"gray",healthy:"green",unhealthy:"red"}[l.status]||"gray";return(0,a.jsx)(m.Z,{color:t,size:"sm",children:l.status||"unknown"})}},{header:"Tools",accessorKey:"allowed_tools",enableSorting:!1,cell:e=>{let{row:s}=e,l=s.original.allowed_tools||[];return(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsx)(u.Z,{className:"text-xs font-medium",children:l.length>0?"".concat(l.length," tool").concat(1!==l.length?"s":""):"All tools"}),l.length>0&&(0,a.jsxs)("div",{className:"flex flex-wrap gap-1",children:[l.slice(0,2).map((e,s)=>(0,a.jsx)(g.Z,{color:"purple",className:"text-xs",children:e},s)),l.length>2&&(0,a.jsxs)(u.Z,{className:"text-xs text-gray-500",children:["+",l.length-2]})]})]})},meta:{className:"hidden lg:table-cell"}},{header:"Created By",accessorKey:"created_by",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsx)(u.Z,{className:"text-xs",children:l.created_by||"-"})},meta:{className:"hidden xl:table-cell"}},{header:"Public",accessorKey:"mcp_info.is_public",enableSorting:!0,sortingFn:(e,s)=>{var l,a;return((null===(l=e.original.mcp_info)||void 0===l?void 0:l.is_public)===!0?1:0)-((null===(a=s.original.mcp_info)||void 0===a?void 0:a.is_public)===!0?1:0)},cell:e=>{var s;let{row:l}=e;return(null===(s=l.original.mcp_info)||void 0===s?void 0:s.is_public)===!0?(0,a.jsx)(m.Z,{color:"green",size:"xs",children:"Yes"}):(0,a.jsx)(m.Z,{color:"gray",size:"xs",children:"No"})},meta:{className:"hidden md:table-cell"}},{header:"Details",id:"details",enableSorting:!1,cell:s=>{let{row:l}=s,t=l.original;return(0,a.jsxs)(h.Z,{size:"xs",variant:"secondary",onClick:()=>e(t),icon:j.Z,children:[(0,a.jsx)("span",{className:"hidden lg:inline",children:"Details"}),(0,a.jsx)("span",{className:"lg:hidden",children:"Info"})]})}}]}(e=>{ex(e),eh(!0)},ew,f),data:en||[],isLoading:ec,table:eb,defaultSorting:[{id:"server_name",desc:!1}]})]}),(0,a.jsx)("div",{className:"mt-4 text-center space-y-2",children:(0,a.jsxs)(r.xv,{className:"text-sm text-gray-600",children:["Showing ",(null==en?void 0:en.length)||0," MCP server",(null==en?void 0:en.length)!==1?"s":""]})})]})]})]})]}):(0,a.jsxs)(r.Zb,{className:"mx-auto max-w-xl mt-10",children:[(0,a.jsx)(r.xv,{className:"text-xl text-center mb-2 text-black",children:"Public Model Hub not enabled."}),(0,a.jsx)("p",{className:"text-base text-center text-slate-800",children:"Ask your proxy admin to enable this on their Admin UI."})]}),(0,a.jsx)(n.Z,{title:"Public Model Hub",width:600,visible:H,footer:null,onOk:e_,onCancel:ek,children:(0,a.jsxs)("div",{className:"pt-5 pb-5",children:[(0,a.jsxs)("div",{className:"flex justify-between mb-4",children:[(0,a.jsx)(r.xv,{className:"text-base mr-2",children:"Shareable Link:"}),(0,a.jsx)(r.xv,{className:"max-w-sm ml-2 bg-gray-200 pr-2 pl-2 pt-1 pb-1 text-center rounded",children:"".concat((0,_.getProxyBaseUrl)(),"/ui/model_hub_table")})]}),(0,a.jsx)("div",{className:"flex justify-end",children:(0,a.jsx)(r.zx,{onClick:()=>{eg.replace("/model_hub_table?key=".concat(N))},children:"See Page"})})]})}),(0,a.jsx)(n.Z,{title:(null==R?void 0:R.model_group)||"Model Details",width:1e3,visible:U,footer:null,onOk:e_,onCancel:ek,children:R&&(0,a.jsxs)("div",{className:"space-y-6",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Model Overview"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4 mb-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Model Group:"}),(0,a.jsx)(r.xv,{children:R.model_group})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Mode:"}),(0,a.jsx)(r.xv,{children:R.mode||"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Providers:"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-1 mt-1",children:R.providers.map(e=>(0,a.jsx)(r.Ct,{color:"blue",children:e},e))})]})]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Token & Cost Information"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Max Input Tokens:"}),(0,a.jsx)(r.xv,{children:(null===(s=R.max_input_tokens)||void 0===s?void 0:s.toLocaleString())||"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Max Output Tokens:"}),(0,a.jsx)(r.xv,{children:(null===(l=R.max_output_tokens)||void 0===l?void 0:l.toLocaleString())||"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Input Cost per 1M Tokens:"}),(0,a.jsx)(r.xv,{children:R.input_cost_per_token?eS(R.input_cost_per_token):"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Output Cost per 1M Tokens:"}),(0,a.jsx)(r.xv,{children:R.output_cost_per_token?eS(R.output_cost_per_token):"Not specified"})]})]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Capabilities"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:(()=>{let e=eC(R),s=["green","blue","purple","orange","red","yellow"];return 0===e.length?(0,a.jsx)(r.xv,{className:"text-gray-500",children:"No special capabilities listed"}):e.map((e,l)=>(0,a.jsx)(r.Ct,{color:s[l%s.length],children:eZ(e)},e))})()})]}),(R.tpm||R.rpm)&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Rate Limits"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[R.tpm&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Tokens per Minute:"}),(0,a.jsx)(r.xv,{children:R.tpm.toLocaleString()})]}),R.rpm&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Requests per Minute:"}),(0,a.jsx)(r.xv,{children:R.rpm.toLocaleString()})]})]})]}),R.supported_openai_params&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Supported OpenAI Parameters"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:R.supported_openai_params.map(e=>(0,a.jsx)(r.Ct,{color:"green",children:e},e))})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Usage Example"}),(0,a.jsx)(o.Z,{language:"python",className:"text-sm",children:'import openai\n\nclient = openai.OpenAI(\n api_key="your_api_key",\n base_url="http://0.0.0.0:4000" # Your LiteLLM Proxy URL\n)\n\nresponse = client.chat.completions.create(\n model="'.concat(R.model_group,'",\n messages=[\n {\n "role": "user",\n "content": "Hello, how are you?"\n }\n ]\n)\n\nprint(response.choices[0].message.content)')})]})]})}),(0,a.jsx)(n.Z,{title:(null==el?void 0:el.name)||"Agent Details",width:1e3,visible:et,footer:null,onOk:e_,onCancel:ek,children:el&&(0,a.jsxs)("div",{className:"space-y-6",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Agent Overview"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4 mb-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Name:"}),(0,a.jsx)(r.xv,{children:el.name})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Version:"}),(0,a.jsxs)(r.Ct,{color:"blue",children:["v",el.version]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Protocol Version:"}),(0,a.jsx)(r.xv,{children:el.protocolVersion})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"URL:"}),(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(r.xv,{className:"truncate",children:el.url}),(0,a.jsx)(t.Z,{onClick:()=>ew(el.url),className:"cursor-pointer text-gray-500 hover:text-blue-500"})]})]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Description:"}),(0,a.jsx)(r.xv,{className:"mt-1",children:el.description})]})]}),el.capabilities&&Object.keys(el.capabilities).length>0&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Capabilities"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:Object.entries(el.capabilities).filter(e=>{let[s,l]=e;return!0===l}).map(e=>{let[s]=e;return(0,a.jsx)(r.Ct,{color:"green",children:s},s)})})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Input/Output Modes"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Input Modes:"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-1 mt-1",children:(null===(v=el.defaultInputModes)||void 0===v?void 0:v.map(e=>(0,a.jsx)(r.Ct,{color:"blue",children:e},e)))||(0,a.jsx)(r.xv,{children:"Not specified"})})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Output Modes:"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-1 mt-1",children:(null===(b=el.defaultOutputModes)||void 0===b?void 0:b.map(e=>(0,a.jsx)(r.Ct,{color:"purple",children:e},e)))||(0,a.jsx)(r.xv,{children:"Not specified"})})]})]})]}),el.skills&&el.skills.length>0&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Skills"}),(0,a.jsx)("div",{className:"space-y-4",children:el.skills.map(e=>(0,a.jsxs)("div",{className:"border border-gray-200 rounded p-4",children:[(0,a.jsxs)("div",{className:"flex justify-between items-start mb-2",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium text-base",children:e.name}),(0,a.jsxs)(r.xv,{className:"text-xs text-gray-500",children:["ID: ",e.id]})]}),e.tags&&e.tags.length>0&&(0,a.jsx)("div",{className:"flex flex-wrap gap-1",children:e.tags.map(e=>(0,a.jsx)(r.Ct,{color:"purple",size:"xs",children:e},e))})]}),(0,a.jsx)(r.xv,{className:"text-sm mb-2",children:e.description}),e.examples&&e.examples.length>0&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-xs font-medium text-gray-700",children:"Examples:"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-1 mt-1",children:e.examples.map((e,s)=>(0,a.jsx)(r.Ct,{color:"gray",size:"xs",children:e},s))})]})]},e.id))})]}),el.supportsAuthenticatedExtendedCard&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Additional Features"}),(0,a.jsx)(r.Ct,{color:"green",children:"Supports Authenticated Extended Card"})]})]})}),(0,a.jsx)(n.Z,{title:(null==eo?void 0:eo.server_name)||"MCP Server Details",width:1e3,visible:em,footer:null,onOk:e_,onCancel:ek,children:eo&&(0,a.jsxs)("div",{className:"space-y-6",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Server Overview"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4 mb-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Server Name:"}),(0,a.jsx)(r.xv,{children:eo.server_name})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Server ID:"}),(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(r.xv,{className:"text-xs truncate",children:eo.server_id}),(0,a.jsx)(t.Z,{onClick:()=>ew(eo.server_id),className:"cursor-pointer text-gray-500 hover:text-blue-500"})]})]}),eo.alias&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Alias:"}),(0,a.jsx)(r.xv,{children:eo.alias})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Transport:"}),(0,a.jsx)(r.Ct,{color:"blue",children:eo.transport})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Auth Type:"}),(0,a.jsx)(r.Ct,{color:"none"===eo.auth_type?"gray":"green",children:eo.auth_type})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Status:"}),(0,a.jsx)(r.Ct,{color:"active"===eo.status||"healthy"===eo.status?"green":"inactive"===eo.status||"unhealthy"===eo.status?"red":"gray",children:eo.status||"unknown"})]})]}),eo.description&&(0,a.jsxs)("div",{className:"mt-2",children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Description:"}),(0,a.jsx)(r.xv,{className:"mt-1",children:eo.description})]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Connection Details"}),(0,a.jsxs)("div",{className:"space-y-2",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"URL:"}),(0,a.jsxs)("div",{className:"flex items-center space-x-2 mt-1",children:[(0,a.jsx)(r.xv,{className:"text-sm break-all bg-gray-100 p-2 rounded flex-1",children:eo.url}),(0,a.jsx)(t.Z,{onClick:()=>ew(eo.url),className:"cursor-pointer text-gray-500 hover:text-blue-500 flex-shrink-0"})]})]}),eo.command&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Command:"}),(0,a.jsx)(r.xv,{className:"text-sm bg-gray-100 p-2 rounded mt-1 font-mono",children:eo.command})]})]})]}),eo.allowed_tools&&eo.allowed_tools.length>0&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Allowed Tools"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:eo.allowed_tools.map((e,s)=>(0,a.jsx)(r.Ct,{color:"purple",children:e},s))})]}),eo.teams&&eo.teams.length>0&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Teams"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:eo.teams.map((e,s)=>(0,a.jsx)(r.Ct,{color:"blue",children:e},s))})]}),eo.mcp_access_groups&&eo.mcp_access_groups.length>0&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Access Groups"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:eo.mcp_access_groups.map((e,s)=>(0,a.jsx)(r.Ct,{color:"green",children:e},s))})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Metadata"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Created By:"}),(0,a.jsx)(r.xv,{children:eo.created_by})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Updated By:"}),(0,a.jsx)(r.xv,{children:eo.updated_by})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Created At:"}),(0,a.jsx)(r.xv,{className:"text-sm",children:new Date(eo.created_at).toLocaleString()})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Updated At:"}),(0,a.jsx)(r.xv,{className:"text-sm",children:new Date(eo.updated_at).toLocaleString()})]}),eo.last_health_check&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Last Health Check:"}),(0,a.jsx)(r.xv,{className:"text-sm",children:new Date(eo.last_health_check).toLocaleString()})]})]}),eo.health_check_error&&(0,a.jsxs)("div",{className:"mt-2 p-2 bg-red-50 rounded",children:[(0,a.jsx)(r.xv,{className:"font-medium text-red-700",children:"Health Check Error:"}),(0,a.jsx)(r.xv,{className:"text-sm text-red-600 mt-1",children:eo.health_check_error})]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Usage Example"}),(0,a.jsx)(o.Z,{language:"python",className:"text-sm",children:'from fastmcp import Client\nimport asyncio\n\n# Standard MCP configuration\nconfig = {\n "mcpServers": {\n "'.concat(eo.server_name,'": {\n "url": "http://localhost:4000/').concat(eo.server_name,'/mcp",\n "headers": {\n "x-litellm-api-key": "Bearer sk-1234"\n }\n }\n }\n}\n\n# Create a client that connects to the server\nclient = Client(config)\n\nasync def main():\n async with client:\n # List available tools\n tools = await client.list_tools()\n print(f"Available tools: {[tool.name for tool in tools]}")\n\n # Call a tool\n response = await client.call_tool(\n name="tool_name", \n arguments={"arg": "value"}\n )\n print(f"Response: {response}")\n\nif __name__ == "__main__":\n asyncio.run(main())')})]})]})}),(0,a.jsx)(A,{visible:q,onClose:()=>G(!1),accessToken:N||"",modelHubData:z||[],onSuccess:()=>{N&&(async()=>{try{let e=await (0,_.modelHubCall)(N);L(e.data)}catch(e){console.error("Error refreshing model data:",e)}})()}}),(0,a.jsx)(Z,{visible:Q,onClose:()=>X(!1),accessToken:N||"",agentHubData:J||[],onSuccess:()=>{N&&(async()=>{try{let e=(await (0,_.getAgentsList)(N)).agents.map(e=>({agent_id:e.agent_id,...e.agent_card_params,is_public:e.is_public}));$(e)}catch(e){console.error("Error refreshing agent data:",e)}})()}}),(0,a.jsx)(S,{visible:eu,onClose:()=>ep(!1),accessToken:N||"",mcpHubData:en||[],onSuccess:()=>{N&&(async()=>{try{let e=await (0,_.fetchMCPServers)(N);ei(e)}catch(e){console.error("Error refreshing MCP server data:",e)}})()}})]})}}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/2249-3e3c0a9e241e35dc.js b/litellm/proxy/_experimental/out/_next/static/chunks/2249-3e3c0a9e241e35dc.js deleted file mode 100644 index 1c6e112db48..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/2249-3e3c0a9e241e35dc.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[2249],{64748:function(e,s,l){l.d(s,{Ct:function(){return a.Z},Dx:function(){return m.Z},OK:function(){return n.Z},Zb:function(){return r.Z},nP:function(){return o.Z},td:function(){return c.Z},v0:function(){return i.Z},x4:function(){return d.Z},xv:function(){return x.Z},zx:function(){return t.Z}});var a=l(41649),t=l(78489),r=l(12514),n=l(12485),i=l(18135),c=l(35242),d=l(29706),o=l(77991),x=l(84264),m=l(96761)},78801:function(e,s,l){l.d(s,{Z:function(){return a.Z},x:function(){return t.Z}});var a=l(12514),t=l(84264)},92249:function(e,s,l){l.d(s,{Z:function(){return W}});var a=l(57437),t=l(23639),r=l(64748),n=l(22116),i=l(78867),c=l(99376),d=l(2265),o=l(17906),x=l(20347),m=l(41649),h=l(78489),u=l(84264),p=l(99981),g=l(3810),j=l(15424),v=l(15690),b=l(10032),N=l(4156),f=l(5545),y=l(96761),_=l(19250),k=l(9114);let{Step:w}=v.default;var Z=e=>{let{visible:s,onClose:l,accessToken:t,agentHubData:r,onSuccess:i}=e,[c,o]=(0,d.useState)(0),[x,h]=(0,d.useState)(new Set),[p,g]=(0,d.useState)(!1),[j]=b.Z.useForm(),Z=()=>{o(0),h(new Set),j.resetFields(),l()},C=(e,s)=>{let l=new Set(x);s?l.add(e):l.delete(e),h(l)},S=e=>{e?h(new Set(r.map(e=>e.agent_id||e.name))):h(new Set)};(0,d.useEffect)(()=>{s&&r.length>0&&h(new Set(r.filter(e=>!0===e.is_public).map(e=>e.agent_id||e.name)))},[s,r]);let P=async()=>{if(0===x.size){k.Z.fromBackend("Please select at least one agent to make public");return}g(!0);try{let e=Array.from(x);await (0,_.makeAgentsPublicCall)(t,e),k.Z.success("Successfully made ".concat(e.length," agent(s) public!")),Z(),i()}catch(e){console.error("Error making agents public:",e),k.Z.fromBackend("Failed to make agents public. Please try again.")}finally{g(!1)}},M=()=>{let e=r.length>0&&r.every(e=>x.has(e.agent_id||e.name)),s=x.size>0&&!e;return(0,a.jsxs)("div",{className:"space-y-4",children:[(0,a.jsxs)("div",{className:"flex items-center justify-between",children:[(0,a.jsx)(y.Z,{children:"Select Agents to Make Public"}),(0,a.jsx)("div",{className:"flex items-center space-x-2",children:(0,a.jsxs)(N.Z,{checked:e,indeterminate:s,onChange:e=>S(e.target.checked),disabled:0===r.length,children:["Select All ",r.length>0&&"(".concat(r.length,")")]})})]}),(0,a.jsx)(u.Z,{className:"text-sm text-gray-600",children:"Select the agents you want to be visible on the public model hub. Users will still require a valid API key to use these agents."}),(0,a.jsx)("div",{className:"max-h-96 overflow-y-auto border rounded-lg p-4",children:(0,a.jsx)("div",{className:"space-y-3",children:0===r.length?(0,a.jsx)("div",{className:"text-center py-8 text-gray-500",children:(0,a.jsx)(u.Z,{children:"No agents available."})}):r.map(e=>{let s=e.agent_id||e.name;return(0,a.jsxs)("div",{className:"flex items-center space-x-3 p-3 border rounded-lg hover:bg-gray-50",children:[(0,a.jsx)(N.Z,{checked:x.has(s),onChange:e=>C(s,e.target.checked)}),(0,a.jsxs)("div",{className:"flex-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:e.name}),(0,a.jsxs)(m.Z,{color:"blue",size:"sm",children:["v",e.version]})]}),(0,a.jsx)(u.Z,{className:"text-xs text-gray-600 mt-1",children:e.description}),e.skills&&e.skills.length>0&&(0,a.jsxs)("div",{className:"flex flex-wrap gap-1 mt-1",children:[e.skills.slice(0,3).map(e=>(0,a.jsx)(m.Z,{color:"purple",size:"xs",children:e.name},e.id)),e.skills.length>3&&(0,a.jsxs)(u.Z,{className:"text-xs text-gray-500",children:["+",e.skills.length-3," more"]})]})]})]},s)})})}),x.size>0&&(0,a.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-3",children:(0,a.jsxs)(u.Z,{className:"text-sm text-blue-800",children:[(0,a.jsx)("strong",{children:x.size})," agent",1!==x.size?"s":""," selected"]})})]})},z=()=>(0,a.jsxs)("div",{className:"space-y-4",children:[(0,a.jsx)(y.Z,{children:"Confirm Making Agents Public"}),(0,a.jsx)("div",{className:"bg-yellow-50 border border-yellow-200 rounded-lg p-4",children:(0,a.jsxs)(u.Z,{className:"text-sm text-yellow-800",children:[(0,a.jsx)("strong",{children:"Warning:"})," Once you make these agents public, anyone who can go to the"," ",(0,a.jsx)("code",{children:"/ui/model_hub_table"})," will be able to know they exist on the proxy."]})}),(0,a.jsxs)("div",{className:"space-y-3",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:"Agents to be made public:"}),(0,a.jsx)("div",{className:"max-h-48 overflow-y-auto border rounded-lg p-3",children:(0,a.jsx)("div",{className:"space-y-2",children:Array.from(x).map(e=>{let s=r.find(s=>(s.agent_id||s.name)===e);return(0,a.jsx)("div",{className:"flex items-center justify-between p-2 bg-gray-50 rounded",children:(0,a.jsxs)("div",{className:"flex-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:(null==s?void 0:s.name)||e}),s&&(0,a.jsxs)(m.Z,{color:"blue",size:"xs",children:["v",s.version]})]}),(null==s?void 0:s.description)&&(0,a.jsx)(u.Z,{className:"text-xs text-gray-600 mt-1",children:s.description})]})},e)})})})]}),(0,a.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-3",children:(0,a.jsxs)(u.Z,{className:"text-sm text-blue-800",children:["Total: ",(0,a.jsx)("strong",{children:x.size})," agent",1!==x.size?"s":""," will be made public"]})})]});return(0,a.jsx)(n.Z,{title:"Make Agents Public",open:s,onCancel:Z,footer:null,width:1200,maskClosable:!1,children:(0,a.jsxs)(b.Z,{form:j,layout:"vertical",children:[(0,a.jsxs)(v.default,{current:c,className:"mb-6",children:[(0,a.jsx)(w,{title:"Select Agents"}),(0,a.jsx)(w,{title:"Confirm"})]}),(()=>{switch(c){case 0:return M();case 1:return z();default:return null}})(),(0,a.jsxs)("div",{className:"flex justify-between mt-6",children:[(0,a.jsx)(f.ZP,{onClick:0===c?Z:()=>{1===c&&o(0)},children:0===c?"Cancel":"Previous"}),(0,a.jsxs)("div",{className:"flex space-x-2",children:[0===c&&(0,a.jsx)(f.ZP,{onClick:()=>{if(0===c){if(0===x.size){k.Z.fromBackend("Please select at least one agent to make public");return}o(1)}},disabled:0===x.size,children:"Next"}),1===c&&(0,a.jsx)(f.ZP,{onClick:P,loading:p,children:"Make Public"})]})]})]})})};let{Step:C}=v.default;var S=e=>{let{visible:s,onClose:l,accessToken:t,mcpHubData:r,onSuccess:i}=e,[c,o]=(0,d.useState)(0),[x,h]=(0,d.useState)(new Set),[p,g]=(0,d.useState)(!1),[j]=b.Z.useForm(),w=()=>{o(0),h(new Set),j.resetFields(),l()},Z=(e,s)=>{let l=new Set(x);s?l.add(e):l.delete(e),h(l)},S=e=>{e?h(new Set(r.map(e=>e.server_id))):h(new Set)};(0,d.useEffect)(()=>{s&&r.length>0&&h(new Set(r.filter(e=>{var s;return(null===(s=e.mcp_info)||void 0===s?void 0:s.is_public)===!0}).map(e=>e.server_id)))},[s]);let P=async()=>{if(0===x.size){k.Z.fromBackend("Please select at least one MCP server to make public");return}g(!0);try{let e=Array.from(x);await (0,_.makeMCPPublicCall)(t,e),k.Z.success("Successfully made ".concat(e.length," MCP server(s) public!")),w(),i()}catch(e){console.error("Error making MCP servers public:",e),k.Z.fromBackend("Failed to make MCP servers public. Please try again.")}finally{g(!1)}},M=()=>{let e=r.length>0&&r.every(e=>x.has(e.server_id)),s=x.size>0&&!e;return(0,a.jsxs)("div",{className:"space-y-4",children:[(0,a.jsxs)("div",{className:"flex items-center justify-between",children:[(0,a.jsx)(y.Z,{children:"Select MCP Servers to Make Public"}),(0,a.jsx)("div",{className:"flex items-center space-x-2",children:(0,a.jsxs)(N.Z,{checked:e,indeterminate:s,onChange:e=>S(e.target.checked),disabled:0===r.length,children:["Select All ",r.length>0&&"(".concat(r.length,")")]})})]}),(0,a.jsx)(u.Z,{className:"text-sm text-gray-600",children:"Select the MCP servers you want to be visible on the public model hub. Users will still require a valid API key to use these servers."}),(0,a.jsx)("div",{className:"max-h-96 overflow-y-auto border rounded-lg p-4",children:(0,a.jsx)("div",{className:"space-y-3",children:0===r.length?(0,a.jsx)("div",{className:"text-center py-8 text-gray-500",children:(0,a.jsx)(u.Z,{children:"No MCP servers available."})}):r.map(e=>{var s;let l=(null===(s=e.mcp_info)||void 0===s?void 0:s.is_public)===!0;return(0,a.jsxs)("div",{className:"flex items-center space-x-3 p-3 border rounded-lg hover:bg-gray-50",children:[(0,a.jsx)(N.Z,{checked:x.has(e.server_id),onChange:s=>Z(e.server_id,s.target.checked)}),(0,a.jsxs)("div",{className:"flex-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:e.server_name}),l&&(0,a.jsx)(m.Z,{color:"emerald",size:"sm",children:"Public"}),(0,a.jsx)(m.Z,{color:"blue",size:"sm",children:e.transport}),(0,a.jsx)(m.Z,{color:"active"===e.status||"healthy"===e.status?"green":"inactive"===e.status||"unhealthy"===e.status?"red":"gray",size:"sm",children:e.status||"unknown"})]}),(0,a.jsx)(u.Z,{className:"text-xs text-gray-600 mt-1",children:e.description||e.url}),e.allowed_tools&&e.allowed_tools.length>0&&(0,a.jsxs)("div",{className:"flex flex-wrap gap-1 mt-1",children:[e.allowed_tools.slice(0,3).map((e,s)=>(0,a.jsx)(m.Z,{color:"purple",size:"xs",children:e},s)),e.allowed_tools.length>3&&(0,a.jsxs)(u.Z,{className:"text-xs text-gray-500",children:["+",e.allowed_tools.length-3," more"]})]})]})]},e.server_id)})})}),x.size>0&&(0,a.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-3",children:(0,a.jsxs)(u.Z,{className:"text-sm text-blue-800",children:[(0,a.jsx)("strong",{children:x.size})," MCP server",1!==x.size?"s":""," selected"]})})]})},z=()=>(0,a.jsxs)("div",{className:"space-y-4",children:[(0,a.jsx)(y.Z,{children:"Confirm Making MCP Servers Public"}),(0,a.jsx)("div",{className:"bg-yellow-50 border border-yellow-200 rounded-lg p-4",children:(0,a.jsxs)(u.Z,{className:"text-sm text-yellow-800",children:[(0,a.jsx)("strong",{children:"Warning:"})," Once you make these MCP servers public, anyone who can go to the"," ",(0,a.jsx)("code",{children:"/ui/model_hub_table"})," will be able to know they exist on the proxy."]})}),(0,a.jsxs)("div",{className:"space-y-3",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:"MCP Servers to be made public:"}),(0,a.jsx)("div",{className:"max-h-48 overflow-y-auto border rounded-lg p-3",children:(0,a.jsx)("div",{className:"space-y-2",children:Array.from(x).map(e=>{let s=r.find(s=>s.server_id===e);return(0,a.jsx)("div",{className:"flex items-center justify-between p-2 bg-gray-50 rounded",children:(0,a.jsxs)("div",{className:"flex-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:(null==s?void 0:s.server_name)||e}),s&&(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(m.Z,{color:"blue",size:"xs",children:s.transport}),(0,a.jsx)(m.Z,{color:"active"===s.status||"healthy"===s.status?"green":"inactive"===s.status||"unhealthy"===s.status?"red":"gray",size:"xs",children:s.status||"unknown"})]})]}),(null==s?void 0:s.description)&&(0,a.jsx)(u.Z,{className:"text-xs text-gray-600 mt-1",children:s.description}),(null==s?void 0:s.url)&&(0,a.jsx)(u.Z,{className:"text-xs text-gray-500 mt-1",children:s.url})]})},e)})})})]}),(0,a.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-3",children:(0,a.jsxs)(u.Z,{className:"text-sm text-blue-800",children:["Total: ",(0,a.jsx)("strong",{children:x.size})," MCP server",1!==x.size?"s":""," will be made public"]})})]});return(0,a.jsx)(n.Z,{title:"Make MCP Servers Public",open:s,onCancel:w,footer:null,width:1200,maskClosable:!1,children:(0,a.jsxs)(b.Z,{form:j,layout:"vertical",children:[(0,a.jsxs)(v.default,{current:c,className:"mb-6",children:[(0,a.jsx)(C,{title:"Select Servers"}),(0,a.jsx)(C,{title:"Confirm"})]}),(()=>{switch(c){case 0:return M();case 1:return z();default:return null}})(),(0,a.jsxs)("div",{className:"flex justify-between mt-6",children:[(0,a.jsx)(f.ZP,{onClick:0===c?w:()=>{1===c&&o(0)},children:0===c?"Cancel":"Previous"}),(0,a.jsxs)("div",{className:"flex space-x-2",children:[0===c&&(0,a.jsx)(f.ZP,{onClick:()=>{if(0===c){if(0===x.size){k.Z.fromBackend("Please select at least one MCP server to make public");return}o(1)}},disabled:0===x.size,children:"Next"}),1===c&&(0,a.jsx)(f.ZP,{onClick:P,loading:p,children:"Make Public"})]})]})]})})},P=l(78801),M=e=>{let{modelHubData:s,onFilteredDataChange:l,showFiltersCard:t=!0,className:r=""}=e,[n,i]=(0,d.useState)(""),[c,o]=(0,d.useState)(""),[x,m]=(0,d.useState)(""),[h,u]=(0,d.useState)(""),p=(0,d.useRef)([]),g=(0,d.useMemo)(()=>(null==s?void 0:s.filter(e=>{let s=e.model_group.toLowerCase().includes(n.toLowerCase()),l=""===c||e.providers.includes(c),a=""===x||e.mode===x,t=""===h||Object.entries(e).filter(e=>{let[s,l]=e;return s.startsWith("supports_")&&!0===l}).some(e=>{let[s]=e;return s.replace(/^supports_/,"").split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")===h});return s&&l&&a&&t}))||[],[s,n,c,x,h]);(0,d.useEffect)(()=>{(g.length!==p.current.length||g.some((e,s)=>{var l;return e.model_group!==(null===(l=p.current[s])||void 0===l?void 0:l.model_group)}))&&(p.current=g,l(g))},[g,l]);let j=(0,a.jsxs)("div",{className:"flex flex-wrap gap-4 items-center",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(P.x,{className:"text-sm font-medium mb-2",children:"Search Models:"}),(0,a.jsx)("input",{type:"text",placeholder:"Search model names...",value:n,onChange:e=>i(e.target.value),className:"border rounded px-3 py-2 w-64 h-10 text-sm"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(P.x,{className:"text-sm font-medium mb-2",children:"Provider:"}),(0,a.jsxs)("select",{value:c,onChange:e=>o(e.target.value),className:"border rounded px-3 py-2 text-sm text-gray-600 w-40 h-10",children:[(0,a.jsx)("option",{value:"",className:"text-sm text-gray-600",children:"All Providers"}),s&&(e=>{let s=new Set;return e.forEach(e=>{e.providers.forEach(e=>s.add(e))}),Array.from(s)})(s).map(e=>(0,a.jsx)("option",{value:e,className:"text-sm text-gray-800",children:e},e))]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(P.x,{className:"text-sm font-medium mb-2",children:"Mode:"}),(0,a.jsxs)("select",{value:x,onChange:e=>m(e.target.value),className:"border rounded px-3 py-2 text-sm text-gray-600 w-32 h-10",children:[(0,a.jsx)("option",{value:"",className:"text-sm text-gray-600",children:"All Modes"}),s&&(e=>{let s=new Set;return e.forEach(e=>{e.mode&&s.add(e.mode)}),Array.from(s)})(s).map(e=>(0,a.jsx)("option",{value:e,className:"text-sm text-gray-800",children:e},e))]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(P.x,{className:"text-sm font-medium mb-2",children:"Features:"}),(0,a.jsxs)("select",{value:h,onChange:e=>u(e.target.value),className:"border rounded px-3 py-2 text-sm text-gray-600 w-48 h-10",children:[(0,a.jsx)("option",{value:"",className:"text-sm text-gray-600",children:"All Features"}),s&&(e=>{let s=new Set;return e.forEach(e=>{Object.entries(e).filter(e=>{let[s,l]=e;return s.startsWith("supports_")&&!0===l}).forEach(e=>{let[l]=e,a=l.replace(/^supports_/,"").split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ");s.add(a)})}),Array.from(s).sort()})(s).map(e=>(0,a.jsx)("option",{value:e,className:"text-sm text-gray-800",children:e},e))]})]}),(n||c||x||h)&&(0,a.jsx)("div",{className:"flex items-end",children:(0,a.jsx)("button",{onClick:()=>{i(""),o(""),m(""),u("")},className:"text-blue-600 hover:text-blue-800 text-sm underline h-10 flex items-center",children:"Clear Filters"})})]});return t?(0,a.jsx)(P.Z,{className:"mb-6 ".concat(r),children:j}):(0,a.jsx)("div",{className:r,children:j})};let{Step:z}=v.default;var A=e=>{let{visible:s,onClose:l,accessToken:t,modelHubData:r,onSuccess:i}=e,[c,o]=(0,d.useState)(0),[x,h]=(0,d.useState)(new Set),[p,g]=(0,d.useState)([]),[j,w]=(0,d.useState)(!1),[Z]=b.Z.useForm(),C=()=>{o(0),h(new Set),g([]),Z.resetFields(),l()},S=(e,s)=>{let l=new Set(x);s?l.add(e):l.delete(e),h(l)},P=e=>{e?h(new Set(p.map(e=>e.model_group))):h(new Set)},A=(0,d.useCallback)(e=>{g(e)},[]);(0,d.useEffect)(()=>{s&&r.length>0&&(g(r),h(new Set(r.filter(e=>!0===e.is_public_model_group).map(e=>e.model_group))))},[s,r]);let F=async()=>{if(0===x.size){k.Z.fromBackend("Please select at least one model to make public");return}w(!0);try{let e=Array.from(x);await (0,_.makeModelGroupPublic)(t,e),k.Z.success("Successfully made ".concat(e.length," model group(s) public!")),C(),i()}catch(e){console.error("Error making model groups public:",e),k.Z.fromBackend("Failed to make model groups public. Please try again.")}finally{w(!1)}},L=()=>{let e=p.length>0&&p.every(e=>x.has(e.model_group)),s=x.size>0&&!e;return(0,a.jsxs)("div",{className:"space-y-4",children:[(0,a.jsxs)("div",{className:"flex items-center justify-between",children:[(0,a.jsx)(y.Z,{children:"Select Models to Make Public"}),(0,a.jsx)("div",{className:"flex items-center space-x-2",children:(0,a.jsxs)(N.Z,{checked:e,indeterminate:s,onChange:e=>P(e.target.checked),disabled:0===p.length,children:["Select All ",p.length>0&&"(".concat(p.length,")")]})})]}),(0,a.jsx)(u.Z,{className:"text-sm text-gray-600",children:"Select the models you want to be visible on the public model hub. Users will still require a valid API key to use these models."}),(0,a.jsx)(M,{modelHubData:r,onFilteredDataChange:A,showFiltersCard:!1,className:"border rounded-lg p-4 bg-gray-50"}),(0,a.jsx)("div",{className:"max-h-96 overflow-y-auto border rounded-lg p-4",children:(0,a.jsx)("div",{className:"space-y-3",children:0===p.length?(0,a.jsx)("div",{className:"text-center py-8 text-gray-500",children:(0,a.jsx)(u.Z,{children:"No models match the current filters."})}):p.map(e=>(0,a.jsxs)("div",{className:"flex items-center space-x-3 p-3 border rounded-lg hover:bg-gray-50",children:[(0,a.jsx)(N.Z,{checked:x.has(e.model_group),onChange:s=>S(e.model_group,s.target.checked)}),(0,a.jsxs)("div",{className:"flex-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:e.model_group}),e.mode&&(0,a.jsx)(m.Z,{color:"green",size:"sm",children:e.mode})]}),(0,a.jsx)("div",{className:"flex flex-wrap gap-1 mt-1",children:e.providers.map(e=>(0,a.jsx)(m.Z,{color:"blue",size:"xs",children:e},e))})]})]},e.model_group))})}),x.size>0&&(0,a.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-3",children:(0,a.jsxs)(u.Z,{className:"text-sm text-blue-800",children:[(0,a.jsx)("strong",{children:x.size})," model",1!==x.size?"s":""," selected"]})})]})},D=()=>(0,a.jsxs)("div",{className:"space-y-4",children:[(0,a.jsx)(y.Z,{children:"Confirm Making Models Public"}),(0,a.jsx)("div",{className:"bg-yellow-50 border border-yellow-200 rounded-lg p-4",children:(0,a.jsxs)(u.Z,{className:"text-sm text-yellow-800",children:[(0,a.jsx)("strong",{children:"Warning:"})," Once you make these models public, anyone who can go to the"," ",(0,a.jsx)("code",{children:"/ui/model_hub_table"})," will be able to know they exist on the proxy."]})}),(0,a.jsxs)("div",{className:"space-y-3",children:[(0,a.jsx)(u.Z,{className:"font-medium",children:"Models to be made public:"}),(0,a.jsx)("div",{className:"max-h-48 overflow-y-auto border rounded-lg p-3",children:(0,a.jsx)("div",{className:"space-y-2",children:Array.from(x).map(e=>{let s=r.find(s=>s.model_group===e);return(0,a.jsx)("div",{className:"flex items-center justify-between p-2 bg-gray-50 rounded",children:(0,a.jsxs)("div",{children:[(0,a.jsx)(u.Z,{className:"font-medium",children:e}),s&&(0,a.jsx)("div",{className:"flex flex-wrap gap-1 mt-1",children:s.providers.map(e=>(0,a.jsx)(m.Z,{color:"blue",size:"xs",children:e},e))})]})},e)})})})]}),(0,a.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-3",children:(0,a.jsxs)(u.Z,{className:"text-sm text-blue-800",children:["Total: ",(0,a.jsx)("strong",{children:x.size})," model",1!==x.size?"s":""," will be made public"]})})]});return(0,a.jsx)(n.Z,{title:"Make Models Public",open:s,onCancel:C,footer:null,width:1200,maskClosable:!1,children:(0,a.jsxs)(b.Z,{form:Z,layout:"vertical",children:[(0,a.jsxs)(v.default,{current:c,className:"mb-6",children:[(0,a.jsx)(z,{title:"Select Models"}),(0,a.jsx)(z,{title:"Confirm"})]}),(()=>{switch(c){case 0:return L();case 1:return D();default:return null}})(),(0,a.jsxs)("div",{className:"flex justify-between mt-6",children:[(0,a.jsx)(f.ZP,{onClick:0===c?C:()=>{1===c&&o(0)},children:0===c?"Cancel":"Previous"}),(0,a.jsxs)("div",{className:"flex space-x-2",children:[0===c&&(0,a.jsx)(f.ZP,{onClick:()=>{if(0===c){if(0===x.size){k.Z.fromBackend("Please select at least one model to make public");return}o(1)}},disabled:0===x.size,children:"Next"}),1===c&&(0,a.jsx)(f.ZP,{onClick:F,loading:j,children:"Make Public"})]})]})]})})},F=l(8048);let L=e=>e.replace(/^supports_/,"").split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" "),D=e=>Object.entries(e).filter(e=>{let[s,l]=e;return s.startsWith("supports_")&&!0===l}).map(e=>{let[s]=e;return s}),O=e=>"$".concat((1e6*e).toFixed(2)),U=e=>e>=1e6?"".concat((e/1e6).toFixed(1),"M"):e>=1e3?"".concat((e/1e3).toFixed(1),"K"):e.toString(),E=function(e,s){let l=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=[{header:"Public Model Name",accessorKey:"model_group",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:l}=e,r=l.original;return(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium text-sm",children:r.model_group}),(0,a.jsx)(p.Z,{title:"Copy model name",children:(0,a.jsx)(t.Z,{onClick:()=>s(r.model_group),className:"cursor-pointer text-gray-500 hover:text-blue-500 text-xs"})})]}),(0,a.jsx)("div",{className:"md:hidden",children:(0,a.jsx)(u.Z,{className:"text-xs text-gray-600",children:r.providers.join(", ")})})]})}},{header:"Provider",accessorKey:"providers",enableSorting:!0,sortingFn:(e,s)=>{let l=e.original.providers.join(", "),a=s.original.providers.join(", ");return l.localeCompare(a)},cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsxs)("div",{className:"flex flex-wrap gap-1",children:[l.providers.slice(0,2).map(e=>(0,a.jsx)(g.Z,{color:"blue",className:"text-xs",children:e},e)),l.providers.length>2&&(0,a.jsxs)(u.Z,{className:"text-xs text-gray-500",children:["+",l.providers.length-2]})]})},meta:{className:"hidden md:table-cell"}},{header:"Mode",accessorKey:"mode",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original;return l.mode?(0,a.jsx)(m.Z,{color:"green",size:"sm",children:l.mode}):(0,a.jsx)(u.Z,{className:"text-gray-500",children:"-"})},meta:{className:"hidden lg:table-cell"}},{header:"Tokens",accessorKey:"max_input_tokens",enableSorting:!0,sortingFn:(e,s)=>(e.original.max_input_tokens||0)+(e.original.max_output_tokens||0)-((s.original.max_input_tokens||0)+(s.original.max_output_tokens||0)),cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsx)("div",{className:"space-y-1",children:(0,a.jsxs)(u.Z,{className:"text-xs",children:[l.max_input_tokens?U(l.max_input_tokens):"-"," /"," ",l.max_output_tokens?U(l.max_output_tokens):"-"]})})},meta:{className:"hidden lg:table-cell"}},{header:"Cost/1M",accessorKey:"input_cost_per_token",enableSorting:!0,sortingFn:(e,s)=>(e.original.input_cost_per_token||0)+(e.original.output_cost_per_token||0)-((s.original.input_cost_per_token||0)+(s.original.output_cost_per_token||0)),cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsx)(u.Z,{className:"text-xs",children:l.input_cost_per_token?O(l.input_cost_per_token):"-"}),(0,a.jsx)(u.Z,{className:"text-xs text-gray-500",children:l.output_cost_per_token?O(l.output_cost_per_token):"-"})]})}},{header:"Features",accessorKey:"capabilities",enableSorting:!1,cell:e=>{let{row:s}=e,l=D(s.original),t=["green","blue","purple","orange","red","yellow"];return(0,a.jsx)("div",{className:"flex flex-wrap gap-1",children:0===l.length?(0,a.jsx)(u.Z,{className:"text-gray-500 text-xs",children:"-"}):l.map((e,s)=>(0,a.jsx)(m.Z,{color:t[s%t.length],size:"xs",children:L(e)},e))})}},{header:"Public",accessorKey:"is_public_model_group",enableSorting:!0,sortingFn:(e,s)=>(!0===e.original.is_public_model_group?1:0)-(!0===s.original.is_public_model_group?1:0),cell:e=>{let{row:s}=e;return!0===s.original.is_public_model_group?(0,a.jsx)(m.Z,{color:"green",size:"xs",children:"Yes"}):(0,a.jsx)(m.Z,{color:"gray",size:"xs",children:"No"})},meta:{className:"hidden md:table-cell"}},{header:"Details",id:"details",enableSorting:!1,cell:s=>{let{row:l}=s,t=l.original;return(0,a.jsxs)(h.Z,{size:"xs",variant:"secondary",onClick:()=>e(t),icon:j.Z,children:[(0,a.jsx)("span",{className:"hidden lg:inline",children:"Details"}),(0,a.jsx)("span",{className:"lg:hidden",children:"Info"})]})}}];return l?r.filter(e=>!("accessorKey"in e)||"is_public_model_group"!==e.accessorKey):r};var K=l(87526),T=l(86462),H=l(47686),I=l(77355),R=l(93416),B=l(74998),Y=l(95704),V=e=>{let{accessToken:s,userRole:l}=e,[t,r]=(0,d.useState)([]),[i,c]=(0,d.useState)({url:"",displayName:""}),[o,m]=(0,d.useState)(null),[h,u]=(0,d.useState)(!1),[p,g]=(0,d.useState)(!0),j=async()=>{if(s)try{u(!0);let e=await (0,_.getPublicModelHubInfo)();if(e&&e.useful_links){let s=e.useful_links||{},l=Object.entries(s).map((e,s)=>{let[l,a]=e;return{id:"".concat(s,"-").concat(l),displayName:l,url:a}});r(l)}else r([])}catch(e){console.error("Error fetching useful links:",e),r([])}finally{u(!1)}};if((0,d.useEffect)(()=>{j()},[s]),!(0,x.tY)(l||""))return null;let v=async e=>{if(!s)return!1;try{let l={};return e.forEach(e=>{l[e.displayName]=e.url}),await (0,_.updateUsefulLinksCall)(s,l),n.Z.success({title:"Links Saved Successfully",content:(0,a.jsxs)("div",{className:"py-4",children:[(0,a.jsx)("p",{className:"text-gray-600 mb-4",children:"Your useful links have been saved and are now visible on the public model hub."}),(0,a.jsxs)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-4",children:[(0,a.jsx)("p",{className:"text-sm text-blue-800 mb-2 font-medium",children:"View your updated model hub:"}),(0,a.jsx)("a",{href:"".concat((0,_.getProxyBaseUrl)(),"/ui/model_hub_table"),target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center text-blue-600 hover:text-blue-800 underline text-sm font-medium",children:"Open Public Model Hub →"})]})]}),width:500,okText:"Close",maskClosable:!0,keyboard:!0}),!0}catch(e){return console.error("Error saving links:",e),k.Z.fromBackend("Failed to save links - ".concat(e)),!1}},b=async()=>{if(!i.url||!i.displayName)return;try{new URL(i.url)}catch(e){k.Z.fromBackend("Please enter a valid URL");return}if(t.some(e=>e.displayName===i.displayName)){k.Z.fromBackend("A link with this display name already exists");return}let e=[...t,{id:"".concat(Date.now(),"-").concat(i.displayName),displayName:i.displayName,url:i.url}];await v(e)&&(r(e),c({url:"",displayName:""}),k.Z.success("Link added successfully"))},N=e=>{m({...e})},f=async()=>{if(!o)return;try{new URL(o.url)}catch(e){k.Z.fromBackend("Please enter a valid URL");return}if(t.some(e=>e.id!==o.id&&e.displayName===o.displayName)){k.Z.fromBackend("A link with this display name already exists");return}let e=t.map(e=>e.id===o.id?o:e);await v(e)&&(r(e),m(null),k.Z.success("Link updated successfully"))},y=()=>{m(null)},w=async e=>{let s=t.filter(s=>s.id!==e);await v(s)&&(r(s),k.Z.success("Link deleted successfully"))},Z=e=>{window.open(e,"_blank")};return(0,a.jsxs)(Y.Zb,{className:"mb-6",children:[(0,a.jsxs)("div",{className:"flex items-center justify-between cursor-pointer",onClick:()=>g(!p),children:[(0,a.jsxs)("div",{className:"flex flex-col",children:[(0,a.jsx)(Y.Dx,{className:"mb-0",children:"Link Management"}),(0,a.jsx)("p",{className:"text-sm text-gray-500",children:"Manage the links that are displayed under 'Useful Links' on the public model hub."})]}),(0,a.jsx)("div",{className:"flex items-center",children:p?(0,a.jsx)(T.Z,{className:"w-5 h-5 text-gray-500"}):(0,a.jsx)(H.Z,{className:"w-5 h-5 text-gray-500"})})]}),p&&(0,a.jsxs)("div",{className:"mt-4",children:[(0,a.jsxs)("div",{className:"mb-6",children:[(0,a.jsx)(Y.xv,{className:"text-sm font-medium text-gray-700 mb-2",children:"Add New Link"}),(0,a.jsxs)("div",{className:"grid grid-cols-3 gap-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("label",{className:"block text-xs text-gray-500 mb-1",children:"URL"}),(0,a.jsx)("input",{type:"text",value:i.url,onChange:e=>c({...i,url:e.target.value}),placeholder:"https://example.com",className:"w-full px-3 py-2 border border-gray-300 rounded-md text-sm"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("label",{className:"block text-xs text-gray-500 mb-1",children:"Display Name"}),(0,a.jsx)("input",{type:"text",value:i.displayName,onChange:e=>c({...i,displayName:e.target.value}),placeholder:"Friendly name",className:"w-full px-3 py-2 border border-gray-300 rounded-md text-sm"})]}),(0,a.jsx)("div",{className:"flex items-end",children:(0,a.jsxs)("button",{onClick:b,disabled:!i.url||!i.displayName,className:"flex items-center px-4 py-2 rounded-md text-sm ".concat(i.url&&i.displayName?"bg-green-600 text-white hover:bg-green-700":"bg-gray-300 text-gray-500 cursor-not-allowed"),children:[(0,a.jsx)(I.Z,{className:"w-4 h-4 mr-1"}),"Add Link"]})})]})]}),(0,a.jsx)(Y.xv,{className:"text-sm font-medium text-gray-700 mb-2",children:"Manage Existing Links"}),(0,a.jsx)("div",{className:"rounded-lg custom-border relative",children:(0,a.jsx)("div",{className:"overflow-x-auto",children:(0,a.jsxs)(Y.iA,{className:"[&_td]:py-0.5 [&_th]:py-1",children:[(0,a.jsx)(Y.ss,{children:(0,a.jsxs)(Y.SC,{children:[(0,a.jsx)(Y.xs,{className:"py-1 h-8",children:"Display Name"}),(0,a.jsx)(Y.xs,{className:"py-1 h-8",children:"URL"}),(0,a.jsx)(Y.xs,{className:"py-1 h-8",children:"Actions"})]})}),(0,a.jsxs)(Y.RM,{children:[t.map(e=>(0,a.jsx)(Y.SC,{className:"h-8",children:o&&o.id===e.id?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(Y.pj,{className:"py-0.5",children:(0,a.jsx)("input",{type:"text",value:o.displayName,onChange:e=>m({...o,displayName:e.target.value}),className:"w-full px-2 py-1 border border-gray-300 rounded-md text-sm"})}),(0,a.jsx)(Y.pj,{className:"py-0.5",children:(0,a.jsx)("input",{type:"text",value:o.url,onChange:e=>m({...o,url:e.target.value}),className:"w-full px-2 py-1 border border-gray-300 rounded-md text-sm"})}),(0,a.jsx)(Y.pj,{className:"py-0.5 whitespace-nowrap",children:(0,a.jsxs)("div",{className:"flex space-x-2",children:[(0,a.jsx)("button",{onClick:f,className:"text-xs bg-blue-50 text-blue-600 px-2 py-1 rounded hover:bg-blue-100",children:"Save"}),(0,a.jsx)("button",{onClick:y,className:"text-xs bg-gray-50 text-gray-600 px-2 py-1 rounded hover:bg-gray-100",children:"Cancel"})]})})]}):(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(Y.pj,{className:"py-0.5 text-sm text-gray-900",children:e.displayName}),(0,a.jsx)(Y.pj,{className:"py-0.5 text-sm text-gray-500",children:e.url}),(0,a.jsx)(Y.pj,{className:"py-0.5 whitespace-nowrap",children:(0,a.jsxs)("div",{className:"flex space-x-2",children:[(0,a.jsx)("button",{onClick:()=>Z(e.url),className:"text-xs bg-green-50 text-green-600 px-2 py-1 rounded hover:bg-green-100",children:"Use"}),(0,a.jsx)("button",{onClick:()=>N(e),className:"text-xs bg-blue-50 text-blue-600 px-2 py-1 rounded hover:bg-blue-100",children:(0,a.jsx)(R.Z,{className:"w-3 h-3"})}),(0,a.jsx)("button",{onClick:()=>w(e.id),className:"text-xs bg-red-50 text-red-600 px-2 py-1 rounded hover:bg-red-100",children:(0,a.jsx)(B.Z,{className:"w-3 h-3"})})]})})]})},e.id)),0===t.length&&(0,a.jsx)(Y.SC,{children:(0,a.jsx)(Y.pj,{colSpan:3,className:"py-0.5 text-sm text-gray-500 text-center",children:"No links added yet. Add a new link above."})})]})]})})})]})]})},W=e=>{var s,l,v,b;let{accessToken:N,publicPage:f,premiumUser:y,userRole:w}=e,[C,P]=(0,d.useState)(!1),[z,L]=(0,d.useState)(null),[D,O]=(0,d.useState)(!0),[U,T]=(0,d.useState)(!1),[H,I]=(0,d.useState)(!1),[R,B]=(0,d.useState)(null),[Y,W]=(0,d.useState)([]),[q,G]=(0,d.useState)(!1),[J,$]=(0,d.useState)(null),[Q,X]=(0,d.useState)(!1),[ee,es]=(0,d.useState)(!0),[el,ea]=(0,d.useState)(null),[et,er]=(0,d.useState)(!1),[en,ei]=(0,d.useState)(null),[ec,ed]=(0,d.useState)(!0),[eo,ex]=(0,d.useState)(null),[em,eh]=(0,d.useState)(!1),[eu,ep]=(0,d.useState)(!1),eg=(0,c.useRouter)(),ej=(0,d.useRef)(null),ev=(0,d.useRef)(null),eb=(0,d.useRef)(null);(0,d.useEffect)(()=>{let e=async e=>{try{O(!0);let s=await (0,_.modelHubCall)(e);console.log("ModelHubData:",s),L(s.data),(0,_.getConfigFieldSetting)(e,"enable_public_model_hub").then(e=>{console.log("data: ".concat(JSON.stringify(e))),!0==e.field_value&&P(!0)}).catch(e=>{})}catch(e){console.error("There was an error fetching the model data",e)}finally{O(!1)}},s=async()=>{try{var e,s;O(!0),await (0,_.getUiConfig)();let l=await (0,_.modelHubPublicModelsCall)();console.log("ModelHubData:",l),console.log("First model structure:",l[0]),console.log("Model has model_group?",null===(e=l[0])||void 0===e?void 0:e.model_group),console.log("Model has providers?",null===(s=l[0])||void 0===s?void 0:s.providers),L(l),P(!0)}catch(e){console.error("There was an error fetching the public model data",e)}finally{O(!1)}};N?e(N):f&&s()},[N,f]),(0,d.useEffect)(()=>{let e=async()=>{if(N)try{es(!0);let e=await (0,_.getAgentsList)(N);console.log("AgentHubData:",e);let s=e.agents.map(e=>({agent_id:e.agent_id,...e.agent_card_params,is_public:e.litellm_params.is_public}));$(s)}catch(e){console.error("There was an error fetching the agent data",e)}finally{es(!1)}};f||e()},[f,N]),(0,d.useEffect)(()=>{let e=async()=>{if(N)try{ed(!0);let e=await (0,_.fetchMCPServers)(N);console.log("MCPHubData:",e),ei(e)}catch(e){console.error("There was an error fetching the MCP server data",e)}finally{ed(!1)}};f||e()},[f,N]);let eN=()=>{N&&G(!0)},ef=()=>{N&&X(!0)},ey=()=>{N&&ep(!0)},e_=()=>{T(!1),I(!1),B(null),er(!1),ea(null),eh(!1),ex(null)},ek=()=>{T(!1),I(!1),B(null),er(!1),ea(null),eh(!1),ex(null)},ew=e=>{navigator.clipboard.writeText(e),k.Z.success("Copied to clipboard!")},eZ=e=>e.replace(/^supports_/,"").split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" "),eC=e=>Object.entries(e).filter(e=>{let[s,l]=e;return s.startsWith("supports_")&&!0===l}).map(e=>{let[s]=e;return s}),eS=e=>"$".concat((1e6*e).toFixed(2)),eP=(0,d.useCallback)(e=>{W(e)},[]);return(console.log("publicPage: ",f),console.log("publicPageAllowed: ",C),f&&C)?(0,a.jsx)(K.Z,{accessToken:N}):(0,a.jsxs)("div",{className:"w-full mx-4 h-[75vh]",children:[!1==f?(0,a.jsxs)("div",{className:"w-full m-2 mt-2 p-8",children:[(0,a.jsxs)("div",{className:"flex justify-between items-center mb-6",children:[(0,a.jsxs)("div",{className:"flex flex-col items-start",children:[(0,a.jsx)(r.Dx,{className:"text-center",children:"AI Hub"}),(0,x.tY)(w||"")?(0,a.jsx)("p",{className:"text-sm text-gray-600",children:"Make models, agents, and MCP servers public for developers to know what's available."}):(0,a.jsx)("p",{className:"text-sm text-gray-600",children:"A list of all public model names personally available to you."})]}),(0,a.jsxs)("div",{className:"flex items-center space-x-4",children:[(0,a.jsx)(r.xv,{children:"Model Hub URL:"}),(0,a.jsxs)("div",{className:"flex items-center bg-gray-200 px-2 py-1 rounded",children:[(0,a.jsx)(r.xv,{className:"mr-2",children:"".concat((0,_.getProxyBaseUrl)(),"/ui/model_hub_table")}),(0,a.jsx)("button",{onClick:()=>ew("".concat((0,_.getProxyBaseUrl)(),"/ui/model_hub_table")),className:"p-1 hover:bg-gray-300 rounded transition-colors",title:"Copy URL",children:(0,a.jsx)(i.Z,{size:16,className:"text-gray-600"})})]})]})]}),(0,x.tY)(w||"")&&(0,a.jsx)("div",{className:"mt-8 mb-2",children:(0,a.jsx)(V,{accessToken:N,userRole:w})}),(0,a.jsxs)(r.v0,{children:[(0,a.jsxs)(r.td,{className:"mb-4",children:[(0,a.jsx)(r.OK,{children:"Model Hub"}),(0,a.jsx)(r.OK,{children:"Agent Hub"}),(0,a.jsx)(r.OK,{children:"MCP Hub"})]}),(0,a.jsxs)(r.nP,{children:[(0,a.jsxs)(r.x4,{children:[(0,a.jsxs)(r.Zb,{children:[!1==f&&(0,x.tY)(w||"")&&(0,a.jsx)("div",{className:"flex justify-end mb-4",children:(0,a.jsx)(r.zx,{onClick:()=>eN(),children:"Select Models to Make Public"})}),(0,a.jsx)(M,{modelHubData:z||[],onFilteredDataChange:eP}),(0,a.jsx)(F.C,{columns:E(e=>{B(e),T(!0)},ew,f),data:Y,isLoading:D,table:ej,defaultSorting:[{id:"model_group",desc:!1}]})]}),(0,a.jsx)("div",{className:"mt-4 text-center space-y-2",children:(0,a.jsxs)(r.xv,{className:"text-sm text-gray-600",children:["Showing ",Y.length," of ",(null==z?void 0:z.length)||0," models"]})})]}),(0,a.jsxs)(r.x4,{children:[(0,a.jsxs)(r.Zb,{children:[!1==f&&(0,x.tY)(w||"")&&(0,a.jsx)("div",{className:"flex justify-end mb-4",children:(0,a.jsx)(r.zx,{onClick:()=>ef(),children:"Select Agents to Make Public"})}),(0,a.jsx)(F.C,{columns:function(e,s){return arguments.length>2&&void 0!==arguments[2]&&arguments[2],[{header:"Agent Name",accessorKey:"name",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:l}=e,r=l.original;return(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium text-sm",children:r.name}),(0,a.jsx)(p.Z,{title:"Copy agent name",children:(0,a.jsx)(t.Z,{onClick:()=>s(r.name),className:"cursor-pointer text-gray-500 hover:text-blue-500 text-xs"})})]}),(0,a.jsx)("div",{className:"md:hidden",children:(0,a.jsx)(u.Z,{className:"text-xs text-gray-600",children:r.description})})]})}},{header:"Description",accessorKey:"description",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsx)(u.Z,{className:"text-xs line-clamp-2",children:l.description||"-"})},meta:{className:"hidden md:table-cell"}},{header:"Version",accessorKey:"version",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsxs)(m.Z,{color:"blue",size:"sm",children:["v",l.version]})},meta:{className:"hidden lg:table-cell"}},{header:"Protocol",accessorKey:"protocolVersion",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsx)(u.Z,{className:"text-xs",children:l.protocolVersion||"-"})},meta:{className:"hidden lg:table-cell"}},{header:"Skills",accessorKey:"skills",enableSorting:!1,cell:e=>{let{row:s}=e,l=s.original.skills||[];return(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsxs)(u.Z,{className:"text-xs font-medium",children:[l.length," skill",1!==l.length?"s":""]}),l.length>0&&(0,a.jsxs)("div",{className:"flex flex-wrap gap-1",children:[l.slice(0,2).map(e=>(0,a.jsx)(g.Z,{color:"purple",className:"text-xs",children:e.name},e.id)),l.length>2&&(0,a.jsxs)(u.Z,{className:"text-xs text-gray-500",children:["+",l.length-2]})]})]})}},{header:"Capabilities",accessorKey:"capabilities",enableSorting:!1,cell:e=>{let{row:s}=e,l=Object.entries(s.original.capabilities||{}).filter(e=>{let[s,l]=e;return!0===l}).map(e=>{let[s]=e;return s});return(0,a.jsx)("div",{className:"flex flex-wrap gap-1",children:0===l.length?(0,a.jsx)(u.Z,{className:"text-gray-500 text-xs",children:"-"}):l.map(e=>(0,a.jsx)(m.Z,{color:"green",size:"xs",children:e},e))})}},{header:"I/O Modes",accessorKey:"defaultInputModes",enableSorting:!1,cell:e=>{let{row:s}=e,l=s.original,t=l.defaultInputModes||[],r=l.defaultOutputModes||[];return(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsxs)(u.Z,{className:"text-xs",children:[(0,a.jsx)("span",{className:"font-medium",children:"In:"})," ",t.join(", ")||"-"]}),(0,a.jsxs)(u.Z,{className:"text-xs",children:[(0,a.jsx)("span",{className:"font-medium",children:"Out:"})," ",r.join(", ")||"-"]})]})},meta:{className:"hidden xl:table-cell"}},{header:"Public",accessorKey:"is_public",enableSorting:!0,sortingFn:(e,s)=>(!0===e.original.is_public?1:0)-(!0===s.original.is_public?1:0),cell:e=>{let{row:s}=e;return console.log("CHECKPOINT 1: ".concat(JSON.stringify(s.original))),!0===s.original.is_public?(0,a.jsx)(m.Z,{color:"green",size:"xs",children:"Yes"}):(0,a.jsx)(m.Z,{color:"gray",size:"xs",children:"No"})},meta:{className:"hidden md:table-cell"}},{header:"Details",id:"details",enableSorting:!1,cell:s=>{let{row:l}=s,t=l.original;return(0,a.jsxs)(h.Z,{size:"xs",variant:"secondary",onClick:()=>e(t),icon:j.Z,children:[(0,a.jsx)("span",{className:"hidden lg:inline",children:"Details"}),(0,a.jsx)("span",{className:"lg:hidden",children:"Info"})]})}}]}(e=>{ea(e),er(!0)},ew,f),data:J||[],isLoading:ee,table:ev,defaultSorting:[{id:"name",desc:!1}]})]}),(0,a.jsx)("div",{className:"mt-4 text-center space-y-2",children:(0,a.jsxs)(r.xv,{className:"text-sm text-gray-600",children:["Showing ",(null==J?void 0:J.length)||0," agent",(null==J?void 0:J.length)!==1?"s":""]})})]}),(0,a.jsxs)(r.x4,{children:[(0,a.jsxs)(r.Zb,{children:[!1==f&&(0,x.tY)(w||"")&&(0,a.jsx)("div",{className:"flex justify-end mb-4",children:(0,a.jsx)(r.zx,{onClick:()=>ey(),children:"Select MCP Servers to Make Public"})}),(0,a.jsx)(F.C,{columns:function(e,s){return arguments.length>2&&void 0!==arguments[2]&&arguments[2],[{header:"Server Name",accessorKey:"server_name",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:l}=e,r=l.original;return(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"font-medium text-sm",children:r.server_name}),(0,a.jsx)(p.Z,{title:"Copy server name",children:(0,a.jsx)(t.Z,{onClick:()=>s(r.server_name),className:"cursor-pointer text-gray-500 hover:text-blue-500 text-xs"})})]}),(0,a.jsx)("div",{className:"md:hidden",children:(0,a.jsx)(u.Z,{className:"text-xs text-gray-600",children:r.description||"-"})})]})}},{header:"Description",accessorKey:"description",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsx)(u.Z,{className:"text-xs line-clamp-2",children:l.description||"-"})},meta:{className:"hidden md:table-cell"}},{header:"URL",accessorKey:"url",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:l}=e,r=l.original;return(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(u.Z,{className:"text-xs truncate max-w-xs",children:r.url}),(0,a.jsx)(p.Z,{title:"Copy URL",children:(0,a.jsx)(t.Z,{onClick:()=>s(r.url),className:"cursor-pointer text-gray-500 hover:text-blue-500 text-xs flex-shrink-0"})})]})},meta:{className:"hidden lg:table-cell"}},{header:"Transport",accessorKey:"transport",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsx)(m.Z,{color:"blue",size:"sm",children:l.transport})},meta:{className:"hidden md:table-cell"}},{header:"Auth Type",accessorKey:"auth_type",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original,t="none"===l.auth_type?"gray":"green";return(0,a.jsx)(m.Z,{color:t,size:"sm",children:l.auth_type})},meta:{className:"hidden md:table-cell"}},{header:"Status",accessorKey:"status",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original,t={active:"green",inactive:"red",unknown:"gray",healthy:"green",unhealthy:"red"}[l.status]||"gray";return(0,a.jsx)(m.Z,{color:t,size:"sm",children:l.status||"unknown"})}},{header:"Tools",accessorKey:"allowed_tools",enableSorting:!1,cell:e=>{let{row:s}=e,l=s.original.allowed_tools||[];return(0,a.jsxs)("div",{className:"space-y-1",children:[(0,a.jsx)(u.Z,{className:"text-xs font-medium",children:l.length>0?"".concat(l.length," tool").concat(1!==l.length?"s":""):"All tools"}),l.length>0&&(0,a.jsxs)("div",{className:"flex flex-wrap gap-1",children:[l.slice(0,2).map((e,s)=>(0,a.jsx)(g.Z,{color:"purple",className:"text-xs",children:e},s)),l.length>2&&(0,a.jsxs)(u.Z,{className:"text-xs text-gray-500",children:["+",l.length-2]})]})]})},meta:{className:"hidden lg:table-cell"}},{header:"Created By",accessorKey:"created_by",enableSorting:!0,sortingFn:"alphanumeric",cell:e=>{let{row:s}=e,l=s.original;return(0,a.jsx)(u.Z,{className:"text-xs",children:l.created_by||"-"})},meta:{className:"hidden xl:table-cell"}},{header:"Public",accessorKey:"mcp_info.is_public",enableSorting:!0,sortingFn:(e,s)=>{var l,a;return((null===(l=e.original.mcp_info)||void 0===l?void 0:l.is_public)===!0?1:0)-((null===(a=s.original.mcp_info)||void 0===a?void 0:a.is_public)===!0?1:0)},cell:e=>{var s;let{row:l}=e;return(null===(s=l.original.mcp_info)||void 0===s?void 0:s.is_public)===!0?(0,a.jsx)(m.Z,{color:"green",size:"xs",children:"Yes"}):(0,a.jsx)(m.Z,{color:"gray",size:"xs",children:"No"})},meta:{className:"hidden md:table-cell"}},{header:"Details",id:"details",enableSorting:!1,cell:s=>{let{row:l}=s,t=l.original;return(0,a.jsxs)(h.Z,{size:"xs",variant:"secondary",onClick:()=>e(t),icon:j.Z,children:[(0,a.jsx)("span",{className:"hidden lg:inline",children:"Details"}),(0,a.jsx)("span",{className:"lg:hidden",children:"Info"})]})}}]}(e=>{ex(e),eh(!0)},ew,f),data:en||[],isLoading:ec,table:eb,defaultSorting:[{id:"server_name",desc:!1}]})]}),(0,a.jsx)("div",{className:"mt-4 text-center space-y-2",children:(0,a.jsxs)(r.xv,{className:"text-sm text-gray-600",children:["Showing ",(null==en?void 0:en.length)||0," MCP server",(null==en?void 0:en.length)!==1?"s":""]})})]})]})]})]}):(0,a.jsxs)(r.Zb,{className:"mx-auto max-w-xl mt-10",children:[(0,a.jsx)(r.xv,{className:"text-xl text-center mb-2 text-black",children:"Public Model Hub not enabled."}),(0,a.jsx)("p",{className:"text-base text-center text-slate-800",children:"Ask your proxy admin to enable this on their Admin UI."})]}),(0,a.jsx)(n.Z,{title:"Public Model Hub",width:600,visible:H,footer:null,onOk:e_,onCancel:ek,children:(0,a.jsxs)("div",{className:"pt-5 pb-5",children:[(0,a.jsxs)("div",{className:"flex justify-between mb-4",children:[(0,a.jsx)(r.xv,{className:"text-base mr-2",children:"Shareable Link:"}),(0,a.jsx)(r.xv,{className:"max-w-sm ml-2 bg-gray-200 pr-2 pl-2 pt-1 pb-1 text-center rounded",children:"".concat((0,_.getProxyBaseUrl)(),"/ui/model_hub_table")})]}),(0,a.jsx)("div",{className:"flex justify-end",children:(0,a.jsx)(r.zx,{onClick:()=>{eg.replace("/model_hub_table?key=".concat(N))},children:"See Page"})})]})}),(0,a.jsx)(n.Z,{title:(null==R?void 0:R.model_group)||"Model Details",width:1e3,visible:U,footer:null,onOk:e_,onCancel:ek,children:R&&(0,a.jsxs)("div",{className:"space-y-6",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Model Overview"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4 mb-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Model Group:"}),(0,a.jsx)(r.xv,{children:R.model_group})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Mode:"}),(0,a.jsx)(r.xv,{children:R.mode||"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Providers:"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-1 mt-1",children:R.providers.map(e=>(0,a.jsx)(r.Ct,{color:"blue",children:e},e))})]})]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Token & Cost Information"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Max Input Tokens:"}),(0,a.jsx)(r.xv,{children:(null===(s=R.max_input_tokens)||void 0===s?void 0:s.toLocaleString())||"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Max Output Tokens:"}),(0,a.jsx)(r.xv,{children:(null===(l=R.max_output_tokens)||void 0===l?void 0:l.toLocaleString())||"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Input Cost per 1M Tokens:"}),(0,a.jsx)(r.xv,{children:R.input_cost_per_token?eS(R.input_cost_per_token):"Not specified"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Output Cost per 1M Tokens:"}),(0,a.jsx)(r.xv,{children:R.output_cost_per_token?eS(R.output_cost_per_token):"Not specified"})]})]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Capabilities"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:(()=>{let e=eC(R),s=["green","blue","purple","orange","red","yellow"];return 0===e.length?(0,a.jsx)(r.xv,{className:"text-gray-500",children:"No special capabilities listed"}):e.map((e,l)=>(0,a.jsx)(r.Ct,{color:s[l%s.length],children:eZ(e)},e))})()})]}),(R.tpm||R.rpm)&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Rate Limits"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[R.tpm&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Tokens per Minute:"}),(0,a.jsx)(r.xv,{children:R.tpm.toLocaleString()})]}),R.rpm&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Requests per Minute:"}),(0,a.jsx)(r.xv,{children:R.rpm.toLocaleString()})]})]})]}),R.supported_openai_params&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Supported OpenAI Parameters"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:R.supported_openai_params.map(e=>(0,a.jsx)(r.Ct,{color:"green",children:e},e))})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Usage Example"}),(0,a.jsx)(o.Z,{language:"python",className:"text-sm",children:'import openai\n\nclient = openai.OpenAI(\n api_key="your_api_key",\n base_url="http://0.0.0.0:4000" # Your LiteLLM Proxy URL\n)\n\nresponse = client.chat.completions.create(\n model="'.concat(R.model_group,'",\n messages=[\n {\n "role": "user",\n "content": "Hello, how are you?"\n }\n ]\n)\n\nprint(response.choices[0].message.content)')})]})]})}),(0,a.jsx)(n.Z,{title:(null==el?void 0:el.name)||"Agent Details",width:1e3,visible:et,footer:null,onOk:e_,onCancel:ek,children:el&&(0,a.jsxs)("div",{className:"space-y-6",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Agent Overview"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4 mb-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Name:"}),(0,a.jsx)(r.xv,{children:el.name})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Version:"}),(0,a.jsxs)(r.Ct,{color:"blue",children:["v",el.version]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Protocol Version:"}),(0,a.jsx)(r.xv,{children:el.protocolVersion})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"URL:"}),(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(r.xv,{className:"truncate",children:el.url}),(0,a.jsx)(t.Z,{onClick:()=>ew(el.url),className:"cursor-pointer text-gray-500 hover:text-blue-500"})]})]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Description:"}),(0,a.jsx)(r.xv,{className:"mt-1",children:el.description})]})]}),el.capabilities&&Object.keys(el.capabilities).length>0&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Capabilities"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:Object.entries(el.capabilities).filter(e=>{let[s,l]=e;return!0===l}).map(e=>{let[s]=e;return(0,a.jsx)(r.Ct,{color:"green",children:s},s)})})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Input/Output Modes"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Input Modes:"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-1 mt-1",children:(null===(v=el.defaultInputModes)||void 0===v?void 0:v.map(e=>(0,a.jsx)(r.Ct,{color:"blue",children:e},e)))||(0,a.jsx)(r.xv,{children:"Not specified"})})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Output Modes:"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-1 mt-1",children:(null===(b=el.defaultOutputModes)||void 0===b?void 0:b.map(e=>(0,a.jsx)(r.Ct,{color:"purple",children:e},e)))||(0,a.jsx)(r.xv,{children:"Not specified"})})]})]})]}),el.skills&&el.skills.length>0&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Skills"}),(0,a.jsx)("div",{className:"space-y-4",children:el.skills.map(e=>(0,a.jsxs)("div",{className:"border border-gray-200 rounded p-4",children:[(0,a.jsxs)("div",{className:"flex justify-between items-start mb-2",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium text-base",children:e.name}),(0,a.jsxs)(r.xv,{className:"text-xs text-gray-500",children:["ID: ",e.id]})]}),e.tags&&e.tags.length>0&&(0,a.jsx)("div",{className:"flex flex-wrap gap-1",children:e.tags.map(e=>(0,a.jsx)(r.Ct,{color:"purple",size:"xs",children:e},e))})]}),(0,a.jsx)(r.xv,{className:"text-sm mb-2",children:e.description}),e.examples&&e.examples.length>0&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-xs font-medium text-gray-700",children:"Examples:"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-1 mt-1",children:e.examples.map((e,s)=>(0,a.jsx)(r.Ct,{color:"gray",size:"xs",children:e},s))})]})]},e.id))})]}),el.supportsAuthenticatedExtendedCard&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Additional Features"}),(0,a.jsx)(r.Ct,{color:"green",children:"Supports Authenticated Extended Card"})]})]})}),(0,a.jsx)(n.Z,{title:(null==eo?void 0:eo.server_name)||"MCP Server Details",width:1e3,visible:em,footer:null,onOk:e_,onCancel:ek,children:eo&&(0,a.jsxs)("div",{className:"space-y-6",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Server Overview"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4 mb-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Server Name:"}),(0,a.jsx)(r.xv,{children:eo.server_name})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Server ID:"}),(0,a.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,a.jsx)(r.xv,{className:"text-xs truncate",children:eo.server_id}),(0,a.jsx)(t.Z,{onClick:()=>ew(eo.server_id),className:"cursor-pointer text-gray-500 hover:text-blue-500"})]})]}),eo.alias&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Alias:"}),(0,a.jsx)(r.xv,{children:eo.alias})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Transport:"}),(0,a.jsx)(r.Ct,{color:"blue",children:eo.transport})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Auth Type:"}),(0,a.jsx)(r.Ct,{color:"none"===eo.auth_type?"gray":"green",children:eo.auth_type})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Status:"}),(0,a.jsx)(r.Ct,{color:"active"===eo.status||"healthy"===eo.status?"green":"inactive"===eo.status||"unhealthy"===eo.status?"red":"gray",children:eo.status||"unknown"})]})]}),eo.description&&(0,a.jsxs)("div",{className:"mt-2",children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Description:"}),(0,a.jsx)(r.xv,{className:"mt-1",children:eo.description})]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Connection Details"}),(0,a.jsxs)("div",{className:"space-y-2",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"URL:"}),(0,a.jsxs)("div",{className:"flex items-center space-x-2 mt-1",children:[(0,a.jsx)(r.xv,{className:"text-sm break-all bg-gray-100 p-2 rounded flex-1",children:eo.url}),(0,a.jsx)(t.Z,{onClick:()=>ew(eo.url),className:"cursor-pointer text-gray-500 hover:text-blue-500 flex-shrink-0"})]})]}),eo.command&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Command:"}),(0,a.jsx)(r.xv,{className:"text-sm bg-gray-100 p-2 rounded mt-1 font-mono",children:eo.command})]})]})]}),eo.allowed_tools&&eo.allowed_tools.length>0&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Allowed Tools"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:eo.allowed_tools.map((e,s)=>(0,a.jsx)(r.Ct,{color:"purple",children:e},s))})]}),eo.teams&&eo.teams.length>0&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Teams"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:eo.teams.map((e,s)=>(0,a.jsx)(r.Ct,{color:"blue",children:e},s))})]}),eo.mcp_access_groups&&eo.mcp_access_groups.length>0&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Access Groups"}),(0,a.jsx)("div",{className:"flex flex-wrap gap-2",children:eo.mcp_access_groups.map((e,s)=>(0,a.jsx)(r.Ct,{color:"green",children:e},s))})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Metadata"}),(0,a.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Created By:"}),(0,a.jsx)(r.xv,{children:eo.created_by})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Updated By:"}),(0,a.jsx)(r.xv,{children:eo.updated_by})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Created At:"}),(0,a.jsx)(r.xv,{className:"text-sm",children:new Date(eo.created_at).toLocaleString()})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Updated At:"}),(0,a.jsx)(r.xv,{className:"text-sm",children:new Date(eo.updated_at).toLocaleString()})]}),eo.last_health_check&&(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"font-medium",children:"Last Health Check:"}),(0,a.jsx)(r.xv,{className:"text-sm",children:new Date(eo.last_health_check).toLocaleString()})]})]}),eo.health_check_error&&(0,a.jsxs)("div",{className:"mt-2 p-2 bg-red-50 rounded",children:[(0,a.jsx)(r.xv,{className:"font-medium text-red-700",children:"Health Check Error:"}),(0,a.jsx)(r.xv,{className:"text-sm text-red-600 mt-1",children:eo.health_check_error})]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)(r.xv,{className:"text-lg font-semibold mb-4",children:"Usage Example"}),(0,a.jsx)(o.Z,{language:"python",className:"text-sm",children:'from fastmcp import Client\nimport asyncio\n\n# Standard MCP configuration\nconfig = {\n "mcpServers": {\n "'.concat(eo.server_name,'": {\n "url": "http://localhost:4000/').concat(eo.server_name,'/mcp",\n "headers": {\n "x-litellm-api-key": "Bearer sk-1234"\n }\n }\n }\n}\n\n# Create a client that connects to the server\nclient = Client(config)\n\nasync def main():\n async with client:\n # List available tools\n tools = await client.list_tools()\n print(f"Available tools: {[tool.name for tool in tools]}")\n\n # Call a tool\n response = await client.call_tool(\n name="tool_name", \n arguments={"arg": "value"}\n )\n print(f"Response: {response}")\n\nif __name__ == "__main__":\n asyncio.run(main())')})]})]})}),(0,a.jsx)(A,{visible:q,onClose:()=>G(!1),accessToken:N||"",modelHubData:z||[],onSuccess:()=>{N&&(async()=>{try{let e=await (0,_.modelHubCall)(N);L(e.data)}catch(e){console.error("Error refreshing model data:",e)}})()}}),(0,a.jsx)(Z,{visible:Q,onClose:()=>X(!1),accessToken:N||"",agentHubData:J||[],onSuccess:()=>{N&&(async()=>{try{let e=(await (0,_.getAgentsList)(N)).agents.map(e=>({agent_id:e.agent_id,...e.agent_card_params,is_public:e.is_public}));$(e)}catch(e){console.error("Error refreshing agent data:",e)}})()}}),(0,a.jsx)(S,{visible:eu,onClose:()=>ep(!1),accessToken:N||"",mcpHubData:en||[],onSuccess:()=>{N&&(async()=>{try{let e=await (0,_.fetchMCPServers)(N);ei(e)}catch(e){console.error("Error refreshing MCP server data:",e)}})()}})]})}}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/3250-d3d70eb77e9f4fa7.js b/litellm/proxy/_experimental/out/_next/static/chunks/3250-6c57da6c11f342fa.js similarity index 99% rename from litellm/proxy/_experimental/out/_next/static/chunks/3250-d3d70eb77e9f4fa7.js rename to litellm/proxy/_experimental/out/_next/static/chunks/3250-6c57da6c11f342fa.js index 0416de210bc..c8c793ed69b 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/3250-d3d70eb77e9f4fa7.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/3250-6c57da6c11f342fa.js @@ -1 +1 @@ -"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[3250],{49634:function(e,r,o){o.d(r,{Z:function(){return s}});var t=o(1119),l=o(2265),a={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"}}]},name:"calendar",theme:"outlined"},n=o(55015),s=l.forwardRef(function(e,r){return l.createElement(n.Z,(0,t.Z)({},e,{ref:r,icon:a}))})},94789:function(e,r,o){o.d(r,{Z:function(){return d}});var t=o(5853),l=o(2265),a=o(26898),n=o(13241),s=o(1153);let i=(0,s.fn)("Callout"),d=l.forwardRef((e,r)=>{let{title:o,icon:d,color:c,className:m,children:p}=e,u=(0,t._T)(e,["title","icon","color","className","children"]);return l.createElement("div",Object.assign({ref:r,className:(0,n.q)(i("root"),"flex flex-col overflow-hidden rounded-tremor-default text-tremor-default border-l-4 py-3 pr-3 pl-4",c?(0,n.q)((0,s.bM)(c,a.K.background).bgColor,(0,s.bM)(c,a.K.darkBorder).borderColor,(0,s.bM)(c,a.K.darkText).textColor,"dark:bg-opacity-10 bg-opacity-10"):(0,n.q)("bg-tremor-brand-faint border-tremor-brand-emphasis text-tremor-brand-emphasis","dark:bg-dark-tremor-brand-muted/70 dark:border-dark-tremor-brand-emphasis dark:text-dark-tremor-brand-emphasis"),m)},u),l.createElement("div",{className:(0,n.q)(i("header"),"flex items-start")},d?l.createElement(d,{className:(0,n.q)(i("icon"),"flex-none h-5 w-5 mr-1.5")}):null,l.createElement("h4",{className:(0,n.q)(i("title"),"font-semibold")},o)),l.createElement("p",{className:(0,n.q)(i("body"),"overflow-y-auto",p?"mt-2":"")},p))});d.displayName="Callout"},35829:function(e,r,o){o.d(r,{Z:function(){return i}});var t=o(5853),l=o(26898),a=o(13241),n=o(1153),s=o(2265);let i=s.forwardRef((e,r)=>{let{color:o,children:i,className:d}=e,c=(0,t._T)(e,["color","children","className"]);return s.createElement("p",Object.assign({ref:r,className:(0,a.q)("font-semibold text-tremor-metric",o?(0,n.bM)(o,l.K.darkText).textColor:"text-tremor-content-strong dark:text-dark-tremor-content-strong",d)},c),i)});i.displayName="Metric"},49096:function(e,r,o){o.d(r,{ZD:function(){return a}});var t=o(61994);let l=e=>"boolean"==typeof e?`${e}`:0===e?"0":e,a=e=>{let r=function(){for(var r,o,l=arguments.length,a=Array(l),n=0;n{let t=Object.fromEntries(Object.entries(e||{}).filter(e=>{let[r]=e;return!["class","className"].includes(r)}));return r(o.map(e=>e(t)),null==e?void 0:e.class,null==e?void 0:e.className)}},cva:e=>o=>{var t;if((null==e?void 0:e.variants)==null)return r(null==e?void 0:e.base,null==o?void 0:o.class,null==o?void 0:o.className);let{variants:a,defaultVariants:n}=e,s=Object.keys(a).map(e=>{let r=null==o?void 0:o[e],t=null==n?void 0:n[e],s=l(r)||l(t);return a[e][s]}),i={...n,...o&&Object.entries(o).reduce((e,r)=>{let[o,t]=r;return void 0===t?e:{...e,[o]:t}},{})},d=null==e?void 0:null===(t=e.compoundVariants)||void 0===t?void 0:t.reduce((e,r)=>{let{class:o,className:t,...l}=r;return Object.entries(l).every(e=>{let[r,o]=e,t=i[r];return Array.isArray(o)?o.includes(t):t===o})?[...e,o,t]:e},[]);return r(null==e?void 0:e.base,s,d,null==o?void 0:o.class,null==o?void 0:o.className)},cx:r}},{compose:n,cva:s,cx:i}=a()},53335:function(e,r,o){o.d(r,{m6:function(){return ev}});let t=(e,r)=>{let o=Array(e.length+r.length);for(let r=0;r({classGroupId:e,validator:r}),a=(e=new Map,r=null,o)=>({nextPart:e,validators:r,classGroupId:o}),n=[],s=e=>{let r=c(e),{conflictingClassGroups:o,conflictingClassGroupModifiers:l}=e;return{getClassGroupId:e=>{if(e.startsWith("[")&&e.endsWith("]"))return d(e);let o=e.split("-"),t=""===o[0]&&o.length>1?1:0;return i(o,t,r)},getConflictingClassGroupIds:(e,r)=>{if(r){let r=l[e],a=o[e];return r?a?t(a,r):r:a||n}return o[e]||n}}},i=(e,r,o)=>{if(0==e.length-r)return o.classGroupId;let t=e[r],l=o.nextPart.get(t);if(l){let o=i(e,r+1,l);if(o)return o}let a=o.validators;if(null===a)return;let n=0===r?e.join("-"):e.slice(r).join("-"),s=a.length;for(let e=0;e-1===e.slice(1,-1).indexOf(":")?void 0:(()=>{let r=e.slice(1,-1),o=r.indexOf(":"),t=r.slice(0,o);return t?"arbitrary.."+t:void 0})(),c=e=>{let{theme:r,classGroups:o}=e;return m(o,r)},m=(e,r)=>{let o=a();for(let t in e)p(e[t],o,t,r);return o},p=(e,r,o,t)=>{let l=e.length;for(let a=0;a{if("string"==typeof e){b(e,r,o);return}if("function"==typeof e){f(e,r,o,t);return}g(e,r,o,t)},b=(e,r,o)=>{(""===e?r:h(r,e)).classGroupId=o},f=(e,r,o,t)=>{if(k(e)){p(e(t),r,o,t);return}null===r.validators&&(r.validators=[]),r.validators.push(l(o,e))},g=(e,r,o,t)=>{let l=Object.entries(e),a=l.length;for(let e=0;e{let o=e,t=r.split("-"),l=t.length;for(let e=0;e"isThemeGetter"in e&&!0===e.isThemeGetter,v=e=>{if(e<1)return{get:()=>void 0,set:()=>{}};let r=0,o=Object.create(null),t=Object.create(null),l=(l,a)=>{o[l]=a,++r>e&&(r=0,t=o,o=Object.create(null))};return{get(e){let r=o[e];return void 0!==r?r:void 0!==(r=t[e])?(l(e,r),r):void 0},set(e,r){e in o?o[e]=r:l(e,r)}}},x=[],w=(e,r,o,t,l)=>({modifiers:e,hasImportantModifier:r,baseClassName:o,maybePostfixModifierPosition:t,isExternal:l}),y=e=>{let{prefix:r,experimentalParseClassName:o}=e,t=e=>{let r;let o=[],t=0,l=0,a=0,n=e.length;for(let s=0;sa?r-a:void 0)};if(r){let e=r+":",o=t;t=r=>r.startsWith(e)?o(r.slice(e.length)):w(x,!1,r,void 0,!0)}if(o){let e=t;t=r=>o({className:r,parseClassName:e})}return t},z=e=>{let r=new Map;return e.orderSensitiveModifiers.forEach((e,o)=>{r.set(e,1e6+o)}),e=>{let o=[],t=[];for(let l=0;l0&&(t.sort(),o.push(...t),t=[]),o.push(a)):t.push(a)}return t.length>0&&(t.sort(),o.push(...t)),o}},j=e=>({cache:v(e.cacheSize),parseClassName:y(e),sortModifiers:z(e),...s(e)}),N=/\s+/,C=(e,r)=>{let{parseClassName:o,getClassGroupId:t,getConflictingClassGroupIds:l,sortModifiers:a}=r,n=[],s=e.trim().split(N),i="";for(let e=s.length-1;e>=0;e-=1){let r=s[e],{isExternal:d,modifiers:c,hasImportantModifier:m,baseClassName:p,maybePostfixModifierPosition:u}=o(r);if(d){i=r+(i.length>0?" "+i:i);continue}let b=!!u,f=t(b?p.substring(0,u):p);if(!f){if(!b||!(f=t(p))){i=r+(i.length>0?" "+i:i);continue}b=!1}let g=0===c.length?"":1===c.length?c[0]:a(c).join(":"),h=m?g+"!":g,k=h+f;if(n.indexOf(k)>-1)continue;n.push(k);let v=l(f,b);for(let e=0;e0?" "+i:i)}return i},O=(...e)=>{let r,o,t=0,l="";for(;t{let r;if("string"==typeof e)return e;let o="";for(let t=0;t{let r=r=>r[e]||E;return r.isThemeGetter=!0,r},q=/^\[(?:(\w[\w-]*):)?(.+)\]$/i,W=/^\((?:(\w[\w-]*):)?(.+)\)$/i,$=/^\d+\/\d+$/,_=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,T=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,I=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,Z=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,A=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,H=e=>$.test(e),K=e=>!!e&&!Number.isNaN(Number(e)),S=e=>!!e&&Number.isInteger(Number(e)),V=e=>e.endsWith("%")&&K(e.slice(0,-1)),P=e=>_.test(e),R=()=>!0,B=e=>T.test(e)&&!I.test(e),D=()=>!1,F=e=>Z.test(e),J=e=>A.test(e),L=e=>!U(e)&&!et(e),Q=e=>ec(e,eb,D),U=e=>q.test(e),X=e=>ec(e,ef,B),Y=e=>ec(e,eg,K),ee=e=>ec(e,ep,D),er=e=>ec(e,eu,J),eo=e=>ec(e,ek,F),et=e=>W.test(e),el=e=>em(e,ef),ea=e=>em(e,eh),en=e=>em(e,ep),es=e=>em(e,eb),ei=e=>em(e,eu),ed=e=>em(e,ek,!0),ec=(e,r,o)=>{let t=q.exec(e);return!!t&&(t[1]?r(t[1]):o(t[2]))},em=(e,r,o=!1)=>{let t=W.exec(e);return!!t&&(t[1]?r(t[1]):o)},ep=e=>"position"===e||"percentage"===e,eu=e=>"image"===e||"url"===e,eb=e=>"length"===e||"size"===e||"bg-size"===e,ef=e=>"length"===e,eg=e=>"number"===e,eh=e=>"family-name"===e,ek=e=>"shadow"===e,ev=((e,...r)=>{let o,t,l,a;let n=e=>{let r=t(e);if(r)return r;let a=C(e,o);return l(e,a),a};return a=s=>(t=(o=j(r.reduce((e,r)=>r(e),e()))).cache.get,l=o.cache.set,a=n,n(s)),(...e)=>a(O(...e))})(()=>{let e=G("color"),r=G("font"),o=G("text"),t=G("font-weight"),l=G("tracking"),a=G("leading"),n=G("breakpoint"),s=G("container"),i=G("spacing"),d=G("radius"),c=G("shadow"),m=G("inset-shadow"),p=G("text-shadow"),u=G("drop-shadow"),b=G("blur"),f=G("perspective"),g=G("aspect"),h=G("ease"),k=G("animate"),v=()=>["auto","avoid","all","avoid-page","page","left","right","column"],x=()=>["center","top","bottom","left","right","top-left","left-top","top-right","right-top","bottom-right","right-bottom","bottom-left","left-bottom"],w=()=>[...x(),et,U],y=()=>["auto","hidden","clip","visible","scroll"],z=()=>["auto","contain","none"],j=()=>[et,U,i],N=()=>[H,"full","auto",...j()],C=()=>[S,"none","subgrid",et,U],O=()=>["auto",{span:["full",S,et,U]},S,et,U],M=()=>[S,"auto",et,U],E=()=>["auto","min","max","fr",et,U],q=()=>["start","end","center","between","around","evenly","stretch","baseline","center-safe","end-safe"],W=()=>["start","end","center","stretch","center-safe","end-safe"],$=()=>["auto",...j()],_=()=>[H,"auto","full","dvw","dvh","lvw","lvh","svw","svh","min","max","fit",...j()],T=()=>[e,et,U],I=()=>[...x(),en,ee,{position:[et,U]}],Z=()=>["no-repeat",{repeat:["","x","y","space","round"]}],A=()=>["auto","cover","contain",es,Q,{size:[et,U]}],B=()=>[V,el,X],D=()=>["","none","full",d,et,U],F=()=>["",K,el,X],J=()=>["solid","dashed","dotted","double"],ec=()=>["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"],em=()=>[K,V,en,ee],ep=()=>["","none",b,et,U],eu=()=>["none",K,et,U],eb=()=>["none",K,et,U],ef=()=>[K,et,U],eg=()=>[H,"full",...j()];return{cacheSize:500,theme:{animate:["spin","ping","pulse","bounce"],aspect:["video"],blur:[P],breakpoint:[P],color:[R],container:[P],"drop-shadow":[P],ease:["in","out","in-out"],font:[L],"font-weight":["thin","extralight","light","normal","medium","semibold","bold","extrabold","black"],"inset-shadow":[P],leading:["none","tight","snug","normal","relaxed","loose"],perspective:["dramatic","near","normal","midrange","distant","none"],radius:[P],shadow:[P],spacing:["px",K],text:[P],"text-shadow":[P],tracking:["tighter","tight","normal","wide","wider","widest"]},classGroups:{aspect:[{aspect:["auto","square",H,U,et,g]}],container:["container"],columns:[{columns:[K,U,et,s]}],"break-after":[{"break-after":v()}],"break-before":[{"break-before":v()}],"break-inside":[{"break-inside":["auto","avoid","avoid-page","avoid-column"]}],"box-decoration":[{"box-decoration":["slice","clone"]}],box:[{box:["border","content"]}],display:["block","inline-block","inline","flex","inline-flex","table","inline-table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row-group","table-row","flow-root","grid","inline-grid","contents","list-item","hidden"],sr:["sr-only","not-sr-only"],float:[{float:["right","left","none","start","end"]}],clear:[{clear:["left","right","both","none","start","end"]}],isolation:["isolate","isolation-auto"],"object-fit":[{object:["contain","cover","fill","none","scale-down"]}],"object-position":[{object:w()}],overflow:[{overflow:y()}],"overflow-x":[{"overflow-x":y()}],"overflow-y":[{"overflow-y":y()}],overscroll:[{overscroll:z()}],"overscroll-x":[{"overscroll-x":z()}],"overscroll-y":[{"overscroll-y":z()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:N()}],"inset-x":[{"inset-x":N()}],"inset-y":[{"inset-y":N()}],start:[{start:N()}],end:[{end:N()}],top:[{top:N()}],right:[{right:N()}],bottom:[{bottom:N()}],left:[{left:N()}],visibility:["visible","invisible","collapse"],z:[{z:[S,"auto",et,U]}],basis:[{basis:[H,"full","auto",s,...j()]}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["nowrap","wrap","wrap-reverse"]}],flex:[{flex:[K,H,"auto","initial","none",U]}],grow:[{grow:["",K,et,U]}],shrink:[{shrink:["",K,et,U]}],order:[{order:[S,"first","last","none",et,U]}],"grid-cols":[{"grid-cols":C()}],"col-start-end":[{col:O()}],"col-start":[{"col-start":M()}],"col-end":[{"col-end":M()}],"grid-rows":[{"grid-rows":C()}],"row-start-end":[{row:O()}],"row-start":[{"row-start":M()}],"row-end":[{"row-end":M()}],"grid-flow":[{"grid-flow":["row","col","dense","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":E()}],"auto-rows":[{"auto-rows":E()}],gap:[{gap:j()}],"gap-x":[{"gap-x":j()}],"gap-y":[{"gap-y":j()}],"justify-content":[{justify:[...q(),"normal"]}],"justify-items":[{"justify-items":[...W(),"normal"]}],"justify-self":[{"justify-self":["auto",...W()]}],"align-content":[{content:["normal",...q()]}],"align-items":[{items:[...W(),{baseline:["","last"]}]}],"align-self":[{self:["auto",...W(),{baseline:["","last"]}]}],"place-content":[{"place-content":q()}],"place-items":[{"place-items":[...W(),"baseline"]}],"place-self":[{"place-self":["auto",...W()]}],p:[{p:j()}],px:[{px:j()}],py:[{py:j()}],ps:[{ps:j()}],pe:[{pe:j()}],pt:[{pt:j()}],pr:[{pr:j()}],pb:[{pb:j()}],pl:[{pl:j()}],m:[{m:$()}],mx:[{mx:$()}],my:[{my:$()}],ms:[{ms:$()}],me:[{me:$()}],mt:[{mt:$()}],mr:[{mr:$()}],mb:[{mb:$()}],ml:[{ml:$()}],"space-x":[{"space-x":j()}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":j()}],"space-y-reverse":["space-y-reverse"],size:[{size:_()}],w:[{w:[s,"screen",..._()]}],"min-w":[{"min-w":[s,"screen","none",..._()]}],"max-w":[{"max-w":[s,"screen","none","prose",{screen:[n]},..._()]}],h:[{h:["screen","lh",..._()]}],"min-h":[{"min-h":["screen","lh","none",..._()]}],"max-h":[{"max-h":["screen","lh",..._()]}],"font-size":[{text:["base",o,el,X]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:[t,et,Y]}],"font-stretch":[{"font-stretch":["ultra-condensed","extra-condensed","condensed","semi-condensed","normal","semi-expanded","expanded","extra-expanded","ultra-expanded",V,U]}],"font-family":[{font:[ea,U,r]}],"fvn-normal":["normal-nums"],"fvn-ordinal":["ordinal"],"fvn-slashed-zero":["slashed-zero"],"fvn-figure":["lining-nums","oldstyle-nums"],"fvn-spacing":["proportional-nums","tabular-nums"],"fvn-fraction":["diagonal-fractions","stacked-fractions"],tracking:[{tracking:[l,et,U]}],"line-clamp":[{"line-clamp":[K,"none",et,Y]}],leading:[{leading:[a,...j()]}],"list-image":[{"list-image":["none",et,U]}],"list-style-position":[{list:["inside","outside"]}],"list-style-type":[{list:["disc","decimal","none",et,U]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"placeholder-color":[{placeholder:T()}],"text-color":[{text:T()}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...J(),"wavy"]}],"text-decoration-thickness":[{decoration:[K,"from-font","auto",et,X]}],"text-decoration-color":[{decoration:T()}],"underline-offset":[{"underline-offset":[K,"auto",et,U]}],"text-transform":["uppercase","lowercase","capitalize","normal-case"],"text-overflow":["truncate","text-ellipsis","text-clip"],"text-wrap":[{text:["wrap","nowrap","balance","pretty"]}],indent:[{indent:j()}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",et,U]}],whitespace:[{whitespace:["normal","nowrap","pre","pre-line","pre-wrap","break-spaces"]}],break:[{break:["normal","words","all","keep"]}],wrap:[{wrap:["break-word","anywhere","normal"]}],hyphens:[{hyphens:["none","manual","auto"]}],content:[{content:["none",et,U]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:I()}],"bg-repeat":[{bg:Z()}],"bg-size":[{bg:A()}],"bg-image":[{bg:["none",{linear:[{to:["t","tr","r","br","b","bl","l","tl"]},S,et,U],radial:["",et,U],conic:[S,et,U]},ei,er]}],"bg-color":[{bg:T()}],"gradient-from-pos":[{from:B()}],"gradient-via-pos":[{via:B()}],"gradient-to-pos":[{to:B()}],"gradient-from":[{from:T()}],"gradient-via":[{via:T()}],"gradient-to":[{to:T()}],rounded:[{rounded:D()}],"rounded-s":[{"rounded-s":D()}],"rounded-e":[{"rounded-e":D()}],"rounded-t":[{"rounded-t":D()}],"rounded-r":[{"rounded-r":D()}],"rounded-b":[{"rounded-b":D()}],"rounded-l":[{"rounded-l":D()}],"rounded-ss":[{"rounded-ss":D()}],"rounded-se":[{"rounded-se":D()}],"rounded-ee":[{"rounded-ee":D()}],"rounded-es":[{"rounded-es":D()}],"rounded-tl":[{"rounded-tl":D()}],"rounded-tr":[{"rounded-tr":D()}],"rounded-br":[{"rounded-br":D()}],"rounded-bl":[{"rounded-bl":D()}],"border-w":[{border:F()}],"border-w-x":[{"border-x":F()}],"border-w-y":[{"border-y":F()}],"border-w-s":[{"border-s":F()}],"border-w-e":[{"border-e":F()}],"border-w-t":[{"border-t":F()}],"border-w-r":[{"border-r":F()}],"border-w-b":[{"border-b":F()}],"border-w-l":[{"border-l":F()}],"divide-x":[{"divide-x":F()}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":F()}],"divide-y-reverse":["divide-y-reverse"],"border-style":[{border:[...J(),"hidden","none"]}],"divide-style":[{divide:[...J(),"hidden","none"]}],"border-color":[{border:T()}],"border-color-x":[{"border-x":T()}],"border-color-y":[{"border-y":T()}],"border-color-s":[{"border-s":T()}],"border-color-e":[{"border-e":T()}],"border-color-t":[{"border-t":T()}],"border-color-r":[{"border-r":T()}],"border-color-b":[{"border-b":T()}],"border-color-l":[{"border-l":T()}],"divide-color":[{divide:T()}],"outline-style":[{outline:[...J(),"none","hidden"]}],"outline-offset":[{"outline-offset":[K,et,U]}],"outline-w":[{outline:["",K,el,X]}],"outline-color":[{outline:T()}],shadow:[{shadow:["","none",c,ed,eo]}],"shadow-color":[{shadow:T()}],"inset-shadow":[{"inset-shadow":["none",m,ed,eo]}],"inset-shadow-color":[{"inset-shadow":T()}],"ring-w":[{ring:F()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:T()}],"ring-offset-w":[{"ring-offset":[K,X]}],"ring-offset-color":[{"ring-offset":T()}],"inset-ring-w":[{"inset-ring":F()}],"inset-ring-color":[{"inset-ring":T()}],"text-shadow":[{"text-shadow":["none",p,ed,eo]}],"text-shadow-color":[{"text-shadow":T()}],opacity:[{opacity:[K,et,U]}],"mix-blend":[{"mix-blend":[...ec(),"plus-darker","plus-lighter"]}],"bg-blend":[{"bg-blend":ec()}],"mask-clip":[{"mask-clip":["border","padding","content","fill","stroke","view"]},"mask-no-clip"],"mask-composite":[{mask:["add","subtract","intersect","exclude"]}],"mask-image-linear-pos":[{"mask-linear":[K]}],"mask-image-linear-from-pos":[{"mask-linear-from":em()}],"mask-image-linear-to-pos":[{"mask-linear-to":em()}],"mask-image-linear-from-color":[{"mask-linear-from":T()}],"mask-image-linear-to-color":[{"mask-linear-to":T()}],"mask-image-t-from-pos":[{"mask-t-from":em()}],"mask-image-t-to-pos":[{"mask-t-to":em()}],"mask-image-t-from-color":[{"mask-t-from":T()}],"mask-image-t-to-color":[{"mask-t-to":T()}],"mask-image-r-from-pos":[{"mask-r-from":em()}],"mask-image-r-to-pos":[{"mask-r-to":em()}],"mask-image-r-from-color":[{"mask-r-from":T()}],"mask-image-r-to-color":[{"mask-r-to":T()}],"mask-image-b-from-pos":[{"mask-b-from":em()}],"mask-image-b-to-pos":[{"mask-b-to":em()}],"mask-image-b-from-color":[{"mask-b-from":T()}],"mask-image-b-to-color":[{"mask-b-to":T()}],"mask-image-l-from-pos":[{"mask-l-from":em()}],"mask-image-l-to-pos":[{"mask-l-to":em()}],"mask-image-l-from-color":[{"mask-l-from":T()}],"mask-image-l-to-color":[{"mask-l-to":T()}],"mask-image-x-from-pos":[{"mask-x-from":em()}],"mask-image-x-to-pos":[{"mask-x-to":em()}],"mask-image-x-from-color":[{"mask-x-from":T()}],"mask-image-x-to-color":[{"mask-x-to":T()}],"mask-image-y-from-pos":[{"mask-y-from":em()}],"mask-image-y-to-pos":[{"mask-y-to":em()}],"mask-image-y-from-color":[{"mask-y-from":T()}],"mask-image-y-to-color":[{"mask-y-to":T()}],"mask-image-radial":[{"mask-radial":[et,U]}],"mask-image-radial-from-pos":[{"mask-radial-from":em()}],"mask-image-radial-to-pos":[{"mask-radial-to":em()}],"mask-image-radial-from-color":[{"mask-radial-from":T()}],"mask-image-radial-to-color":[{"mask-radial-to":T()}],"mask-image-radial-shape":[{"mask-radial":["circle","ellipse"]}],"mask-image-radial-size":[{"mask-radial":[{closest:["side","corner"],farthest:["side","corner"]}]}],"mask-image-radial-pos":[{"mask-radial-at":x()}],"mask-image-conic-pos":[{"mask-conic":[K]}],"mask-image-conic-from-pos":[{"mask-conic-from":em()}],"mask-image-conic-to-pos":[{"mask-conic-to":em()}],"mask-image-conic-from-color":[{"mask-conic-from":T()}],"mask-image-conic-to-color":[{"mask-conic-to":T()}],"mask-mode":[{mask:["alpha","luminance","match"]}],"mask-origin":[{"mask-origin":["border","padding","content","fill","stroke","view"]}],"mask-position":[{mask:I()}],"mask-repeat":[{mask:Z()}],"mask-size":[{mask:A()}],"mask-type":[{"mask-type":["alpha","luminance"]}],"mask-image":[{mask:["none",et,U]}],filter:[{filter:["","none",et,U]}],blur:[{blur:ep()}],brightness:[{brightness:[K,et,U]}],contrast:[{contrast:[K,et,U]}],"drop-shadow":[{"drop-shadow":["","none",u,ed,eo]}],"drop-shadow-color":[{"drop-shadow":T()}],grayscale:[{grayscale:["",K,et,U]}],"hue-rotate":[{"hue-rotate":[K,et,U]}],invert:[{invert:["",K,et,U]}],saturate:[{saturate:[K,et,U]}],sepia:[{sepia:["",K,et,U]}],"backdrop-filter":[{"backdrop-filter":["","none",et,U]}],"backdrop-blur":[{"backdrop-blur":ep()}],"backdrop-brightness":[{"backdrop-brightness":[K,et,U]}],"backdrop-contrast":[{"backdrop-contrast":[K,et,U]}],"backdrop-grayscale":[{"backdrop-grayscale":["",K,et,U]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[K,et,U]}],"backdrop-invert":[{"backdrop-invert":["",K,et,U]}],"backdrop-opacity":[{"backdrop-opacity":[K,et,U]}],"backdrop-saturate":[{"backdrop-saturate":[K,et,U]}],"backdrop-sepia":[{"backdrop-sepia":["",K,et,U]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":j()}],"border-spacing-x":[{"border-spacing-x":j()}],"border-spacing-y":[{"border-spacing-y":j()}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["","all","colors","opacity","shadow","transform","none",et,U]}],"transition-behavior":[{transition:["normal","discrete"]}],duration:[{duration:[K,"initial",et,U]}],ease:[{ease:["linear","initial",h,et,U]}],delay:[{delay:[K,et,U]}],animate:[{animate:["none",k,et,U]}],backface:[{backface:["hidden","visible"]}],perspective:[{perspective:[f,et,U]}],"perspective-origin":[{"perspective-origin":w()}],rotate:[{rotate:eu()}],"rotate-x":[{"rotate-x":eu()}],"rotate-y":[{"rotate-y":eu()}],"rotate-z":[{"rotate-z":eu()}],scale:[{scale:eb()}],"scale-x":[{"scale-x":eb()}],"scale-y":[{"scale-y":eb()}],"scale-z":[{"scale-z":eb()}],"scale-3d":["scale-3d"],skew:[{skew:ef()}],"skew-x":[{"skew-x":ef()}],"skew-y":[{"skew-y":ef()}],transform:[{transform:[et,U,"","none","gpu","cpu"]}],"transform-origin":[{origin:w()}],"transform-style":[{transform:["3d","flat"]}],translate:[{translate:eg()}],"translate-x":[{"translate-x":eg()}],"translate-y":[{"translate-y":eg()}],"translate-z":[{"translate-z":eg()}],"translate-none":["translate-none"],accent:[{accent:T()}],appearance:[{appearance:["none","auto"]}],"caret-color":[{caret:T()}],"color-scheme":[{scheme:["normal","dark","light","light-dark","only-dark","only-light"]}],cursor:[{cursor:["auto","default","pointer","wait","text","move","help","not-allowed","none","context-menu","progress","cell","crosshair","vertical-text","alias","copy","no-drop","grab","grabbing","all-scroll","col-resize","row-resize","n-resize","e-resize","s-resize","w-resize","ne-resize","nw-resize","se-resize","sw-resize","ew-resize","ns-resize","nesw-resize","nwse-resize","zoom-in","zoom-out",et,U]}],"field-sizing":[{"field-sizing":["fixed","content"]}],"pointer-events":[{"pointer-events":["auto","none"]}],resize:[{resize:["none","","y","x"]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scroll-m":[{"scroll-m":j()}],"scroll-mx":[{"scroll-mx":j()}],"scroll-my":[{"scroll-my":j()}],"scroll-ms":[{"scroll-ms":j()}],"scroll-me":[{"scroll-me":j()}],"scroll-mt":[{"scroll-mt":j()}],"scroll-mr":[{"scroll-mr":j()}],"scroll-mb":[{"scroll-mb":j()}],"scroll-ml":[{"scroll-ml":j()}],"scroll-p":[{"scroll-p":j()}],"scroll-px":[{"scroll-px":j()}],"scroll-py":[{"scroll-py":j()}],"scroll-ps":[{"scroll-ps":j()}],"scroll-pe":[{"scroll-pe":j()}],"scroll-pt":[{"scroll-pt":j()}],"scroll-pr":[{"scroll-pr":j()}],"scroll-pb":[{"scroll-pb":j()}],"scroll-pl":[{"scroll-pl":j()}],"snap-align":[{snap:["start","end","center","align-none"]}],"snap-stop":[{snap:["normal","always"]}],"snap-type":[{snap:["none","x","y","both"]}],"snap-strictness":[{snap:["mandatory","proximity"]}],touch:[{touch:["auto","none","manipulation"]}],"touch-x":[{"touch-pan":["x","left","right"]}],"touch-y":[{"touch-pan":["y","up","down"]}],"touch-pz":["touch-pinch-zoom"],select:[{select:["none","text","all","auto"]}],"will-change":[{"will-change":["auto","scroll","contents","transform",et,U]}],fill:[{fill:["none",...T()]}],"stroke-w":[{stroke:[K,el,X,Y]}],stroke:[{stroke:["none",...T()]}],"forced-color-adjust":[{"forced-color-adjust":["auto","none"]}]},conflictingClassGroups:{overflow:["overflow-x","overflow-y"],overscroll:["overscroll-x","overscroll-y"],inset:["inset-x","inset-y","start","end","top","right","bottom","left"],"inset-x":["right","left"],"inset-y":["top","bottom"],flex:["basis","grow","shrink"],gap:["gap-x","gap-y"],p:["px","py","ps","pe","pt","pr","pb","pl"],px:["pr","pl"],py:["pt","pb"],m:["mx","my","ms","me","mt","mr","mb","ml"],mx:["mr","ml"],my:["mt","mb"],size:["w","h"],"font-size":["leading"],"fvn-normal":["fvn-ordinal","fvn-slashed-zero","fvn-figure","fvn-spacing","fvn-fraction"],"fvn-ordinal":["fvn-normal"],"fvn-slashed-zero":["fvn-normal"],"fvn-figure":["fvn-normal"],"fvn-spacing":["fvn-normal"],"fvn-fraction":["fvn-normal"],"line-clamp":["display","overflow"],rounded:["rounded-s","rounded-e","rounded-t","rounded-r","rounded-b","rounded-l","rounded-ss","rounded-se","rounded-ee","rounded-es","rounded-tl","rounded-tr","rounded-br","rounded-bl"],"rounded-s":["rounded-ss","rounded-es"],"rounded-e":["rounded-se","rounded-ee"],"rounded-t":["rounded-tl","rounded-tr"],"rounded-r":["rounded-tr","rounded-br"],"rounded-b":["rounded-br","rounded-bl"],"rounded-l":["rounded-tl","rounded-bl"],"border-spacing":["border-spacing-x","border-spacing-y"],"border-w":["border-w-x","border-w-y","border-w-s","border-w-e","border-w-t","border-w-r","border-w-b","border-w-l"],"border-w-x":["border-w-r","border-w-l"],"border-w-y":["border-w-t","border-w-b"],"border-color":["border-color-x","border-color-y","border-color-s","border-color-e","border-color-t","border-color-r","border-color-b","border-color-l"],"border-color-x":["border-color-r","border-color-l"],"border-color-y":["border-color-t","border-color-b"],translate:["translate-x","translate-y","translate-none"],"translate-none":["translate","translate-x","translate-y","translate-z"],"scroll-m":["scroll-mx","scroll-my","scroll-ms","scroll-me","scroll-mt","scroll-mr","scroll-mb","scroll-ml"],"scroll-mx":["scroll-mr","scroll-ml"],"scroll-my":["scroll-mt","scroll-mb"],"scroll-p":["scroll-px","scroll-py","scroll-ps","scroll-pe","scroll-pt","scroll-pr","scroll-pb","scroll-pl"],"scroll-px":["scroll-pr","scroll-pl"],"scroll-py":["scroll-pt","scroll-pb"],touch:["touch-x","touch-y","touch-pz"],"touch-x":["touch"],"touch-y":["touch"],"touch-pz":["touch"]},conflictingClassGroupModifiers:{"font-size":["leading"]},orderSensitiveModifiers:["*","**","after","backdrop","before","details-content","file","first-letter","first-line","marker","placeholder","selection"]}})}}]); \ No newline at end of file +"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[3250],{49634:function(e,r,o){o.d(r,{Z:function(){return s}});var t=o(1119),l=o(2265),a={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"}}]},name:"calendar",theme:"outlined"},n=o(55015),s=l.forwardRef(function(e,r){return l.createElement(n.Z,(0,t.Z)({},e,{ref:r,icon:a}))})},94789:function(e,r,o){o.d(r,{Z:function(){return d}});var t=o(5853),l=o(2265),a=o(26898),n=o(13241),s=o(1153);let i=(0,s.fn)("Callout"),d=l.forwardRef((e,r)=>{let{title:o,icon:d,color:c,className:m,children:p}=e,u=(0,t._T)(e,["title","icon","color","className","children"]);return l.createElement("div",Object.assign({ref:r,className:(0,n.q)(i("root"),"flex flex-col overflow-hidden rounded-tremor-default text-tremor-default border-l-4 py-3 pr-3 pl-4",c?(0,n.q)((0,s.bM)(c,a.K.background).bgColor,(0,s.bM)(c,a.K.darkBorder).borderColor,(0,s.bM)(c,a.K.darkText).textColor,"dark:bg-opacity-10 bg-opacity-10"):(0,n.q)("bg-tremor-brand-faint border-tremor-brand-emphasis text-tremor-brand-emphasis","dark:bg-dark-tremor-brand-muted/70 dark:border-dark-tremor-brand-emphasis dark:text-dark-tremor-brand-emphasis"),m)},u),l.createElement("div",{className:(0,n.q)(i("header"),"flex items-start")},d?l.createElement(d,{className:(0,n.q)(i("icon"),"flex-none h-5 w-5 mr-1.5")}):null,l.createElement("h4",{className:(0,n.q)(i("title"),"font-semibold")},o)),l.createElement("p",{className:(0,n.q)(i("body"),"overflow-y-auto",p?"mt-2":"")},p))});d.displayName="Callout"},35829:function(e,r,o){o.d(r,{Z:function(){return i}});var t=o(5853),l=o(26898),a=o(13241),n=o(1153),s=o(2265);let i=s.forwardRef((e,r)=>{let{color:o,children:i,className:d}=e,c=(0,t._T)(e,["color","children","className"]);return s.createElement("p",Object.assign({ref:r,className:(0,a.q)("font-semibold text-tremor-metric",o?(0,n.bM)(o,l.K.darkText).textColor:"text-tremor-content-strong dark:text-dark-tremor-content-strong",d)},c),i)});i.displayName="Metric"},49096:function(e,r,o){o.d(r,{ZD:function(){return a}});var t=o(87602);let l=e=>"boolean"==typeof e?`${e}`:0===e?"0":e,a=e=>{let r=function(){for(var r,o,l=arguments.length,a=Array(l),n=0;n{let t=Object.fromEntries(Object.entries(e||{}).filter(e=>{let[r]=e;return!["class","className"].includes(r)}));return r(o.map(e=>e(t)),null==e?void 0:e.class,null==e?void 0:e.className)}},cva:e=>o=>{var t;if((null==e?void 0:e.variants)==null)return r(null==e?void 0:e.base,null==o?void 0:o.class,null==o?void 0:o.className);let{variants:a,defaultVariants:n}=e,s=Object.keys(a).map(e=>{let r=null==o?void 0:o[e],t=null==n?void 0:n[e],s=l(r)||l(t);return a[e][s]}),i={...n,...o&&Object.entries(o).reduce((e,r)=>{let[o,t]=r;return void 0===t?e:{...e,[o]:t}},{})},d=null==e?void 0:null===(t=e.compoundVariants)||void 0===t?void 0:t.reduce((e,r)=>{let{class:o,className:t,...l}=r;return Object.entries(l).every(e=>{let[r,o]=e,t=i[r];return Array.isArray(o)?o.includes(t):t===o})?[...e,o,t]:e},[]);return r(null==e?void 0:e.base,s,d,null==o?void 0:o.class,null==o?void 0:o.className)},cx:r}},{compose:n,cva:s,cx:i}=a()},53335:function(e,r,o){o.d(r,{m6:function(){return ev}});let t=(e,r)=>{let o=Array(e.length+r.length);for(let r=0;r({classGroupId:e,validator:r}),a=(e=new Map,r=null,o)=>({nextPart:e,validators:r,classGroupId:o}),n=[],s=e=>{let r=c(e),{conflictingClassGroups:o,conflictingClassGroupModifiers:l}=e;return{getClassGroupId:e=>{if(e.startsWith("[")&&e.endsWith("]"))return d(e);let o=e.split("-"),t=""===o[0]&&o.length>1?1:0;return i(o,t,r)},getConflictingClassGroupIds:(e,r)=>{if(r){let r=l[e],a=o[e];return r?a?t(a,r):r:a||n}return o[e]||n}}},i=(e,r,o)=>{if(0==e.length-r)return o.classGroupId;let t=e[r],l=o.nextPart.get(t);if(l){let o=i(e,r+1,l);if(o)return o}let a=o.validators;if(null===a)return;let n=0===r?e.join("-"):e.slice(r).join("-"),s=a.length;for(let e=0;e-1===e.slice(1,-1).indexOf(":")?void 0:(()=>{let r=e.slice(1,-1),o=r.indexOf(":"),t=r.slice(0,o);return t?"arbitrary.."+t:void 0})(),c=e=>{let{theme:r,classGroups:o}=e;return m(o,r)},m=(e,r)=>{let o=a();for(let t in e)p(e[t],o,t,r);return o},p=(e,r,o,t)=>{let l=e.length;for(let a=0;a{if("string"==typeof e){b(e,r,o);return}if("function"==typeof e){f(e,r,o,t);return}g(e,r,o,t)},b=(e,r,o)=>{(""===e?r:h(r,e)).classGroupId=o},f=(e,r,o,t)=>{if(k(e)){p(e(t),r,o,t);return}null===r.validators&&(r.validators=[]),r.validators.push(l(o,e))},g=(e,r,o,t)=>{let l=Object.entries(e),a=l.length;for(let e=0;e{let o=e,t=r.split("-"),l=t.length;for(let e=0;e"isThemeGetter"in e&&!0===e.isThemeGetter,v=e=>{if(e<1)return{get:()=>void 0,set:()=>{}};let r=0,o=Object.create(null),t=Object.create(null),l=(l,a)=>{o[l]=a,++r>e&&(r=0,t=o,o=Object.create(null))};return{get(e){let r=o[e];return void 0!==r?r:void 0!==(r=t[e])?(l(e,r),r):void 0},set(e,r){e in o?o[e]=r:l(e,r)}}},x=[],w=(e,r,o,t,l)=>({modifiers:e,hasImportantModifier:r,baseClassName:o,maybePostfixModifierPosition:t,isExternal:l}),y=e=>{let{prefix:r,experimentalParseClassName:o}=e,t=e=>{let r;let o=[],t=0,l=0,a=0,n=e.length;for(let s=0;sa?r-a:void 0)};if(r){let e=r+":",o=t;t=r=>r.startsWith(e)?o(r.slice(e.length)):w(x,!1,r,void 0,!0)}if(o){let e=t;t=r=>o({className:r,parseClassName:e})}return t},z=e=>{let r=new Map;return e.orderSensitiveModifiers.forEach((e,o)=>{r.set(e,1e6+o)}),e=>{let o=[],t=[];for(let l=0;l0&&(t.sort(),o.push(...t),t=[]),o.push(a)):t.push(a)}return t.length>0&&(t.sort(),o.push(...t)),o}},j=e=>({cache:v(e.cacheSize),parseClassName:y(e),sortModifiers:z(e),...s(e)}),N=/\s+/,C=(e,r)=>{let{parseClassName:o,getClassGroupId:t,getConflictingClassGroupIds:l,sortModifiers:a}=r,n=[],s=e.trim().split(N),i="";for(let e=s.length-1;e>=0;e-=1){let r=s[e],{isExternal:d,modifiers:c,hasImportantModifier:m,baseClassName:p,maybePostfixModifierPosition:u}=o(r);if(d){i=r+(i.length>0?" "+i:i);continue}let b=!!u,f=t(b?p.substring(0,u):p);if(!f){if(!b||!(f=t(p))){i=r+(i.length>0?" "+i:i);continue}b=!1}let g=0===c.length?"":1===c.length?c[0]:a(c).join(":"),h=m?g+"!":g,k=h+f;if(n.indexOf(k)>-1)continue;n.push(k);let v=l(f,b);for(let e=0;e0?" "+i:i)}return i},O=(...e)=>{let r,o,t=0,l="";for(;t{let r;if("string"==typeof e)return e;let o="";for(let t=0;t{let r=r=>r[e]||E;return r.isThemeGetter=!0,r},q=/^\[(?:(\w[\w-]*):)?(.+)\]$/i,W=/^\((?:(\w[\w-]*):)?(.+)\)$/i,$=/^\d+\/\d+$/,_=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,T=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,I=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,Z=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,A=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,H=e=>$.test(e),K=e=>!!e&&!Number.isNaN(Number(e)),S=e=>!!e&&Number.isInteger(Number(e)),V=e=>e.endsWith("%")&&K(e.slice(0,-1)),P=e=>_.test(e),R=()=>!0,B=e=>T.test(e)&&!I.test(e),D=()=>!1,F=e=>Z.test(e),J=e=>A.test(e),L=e=>!U(e)&&!et(e),Q=e=>ec(e,eb,D),U=e=>q.test(e),X=e=>ec(e,ef,B),Y=e=>ec(e,eg,K),ee=e=>ec(e,ep,D),er=e=>ec(e,eu,J),eo=e=>ec(e,ek,F),et=e=>W.test(e),el=e=>em(e,ef),ea=e=>em(e,eh),en=e=>em(e,ep),es=e=>em(e,eb),ei=e=>em(e,eu),ed=e=>em(e,ek,!0),ec=(e,r,o)=>{let t=q.exec(e);return!!t&&(t[1]?r(t[1]):o(t[2]))},em=(e,r,o=!1)=>{let t=W.exec(e);return!!t&&(t[1]?r(t[1]):o)},ep=e=>"position"===e||"percentage"===e,eu=e=>"image"===e||"url"===e,eb=e=>"length"===e||"size"===e||"bg-size"===e,ef=e=>"length"===e,eg=e=>"number"===e,eh=e=>"family-name"===e,ek=e=>"shadow"===e,ev=((e,...r)=>{let o,t,l,a;let n=e=>{let r=t(e);if(r)return r;let a=C(e,o);return l(e,a),a};return a=s=>(t=(o=j(r.reduce((e,r)=>r(e),e()))).cache.get,l=o.cache.set,a=n,n(s)),(...e)=>a(O(...e))})(()=>{let e=G("color"),r=G("font"),o=G("text"),t=G("font-weight"),l=G("tracking"),a=G("leading"),n=G("breakpoint"),s=G("container"),i=G("spacing"),d=G("radius"),c=G("shadow"),m=G("inset-shadow"),p=G("text-shadow"),u=G("drop-shadow"),b=G("blur"),f=G("perspective"),g=G("aspect"),h=G("ease"),k=G("animate"),v=()=>["auto","avoid","all","avoid-page","page","left","right","column"],x=()=>["center","top","bottom","left","right","top-left","left-top","top-right","right-top","bottom-right","right-bottom","bottom-left","left-bottom"],w=()=>[...x(),et,U],y=()=>["auto","hidden","clip","visible","scroll"],z=()=>["auto","contain","none"],j=()=>[et,U,i],N=()=>[H,"full","auto",...j()],C=()=>[S,"none","subgrid",et,U],O=()=>["auto",{span:["full",S,et,U]},S,et,U],M=()=>[S,"auto",et,U],E=()=>["auto","min","max","fr",et,U],q=()=>["start","end","center","between","around","evenly","stretch","baseline","center-safe","end-safe"],W=()=>["start","end","center","stretch","center-safe","end-safe"],$=()=>["auto",...j()],_=()=>[H,"auto","full","dvw","dvh","lvw","lvh","svw","svh","min","max","fit",...j()],T=()=>[e,et,U],I=()=>[...x(),en,ee,{position:[et,U]}],Z=()=>["no-repeat",{repeat:["","x","y","space","round"]}],A=()=>["auto","cover","contain",es,Q,{size:[et,U]}],B=()=>[V,el,X],D=()=>["","none","full",d,et,U],F=()=>["",K,el,X],J=()=>["solid","dashed","dotted","double"],ec=()=>["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"],em=()=>[K,V,en,ee],ep=()=>["","none",b,et,U],eu=()=>["none",K,et,U],eb=()=>["none",K,et,U],ef=()=>[K,et,U],eg=()=>[H,"full",...j()];return{cacheSize:500,theme:{animate:["spin","ping","pulse","bounce"],aspect:["video"],blur:[P],breakpoint:[P],color:[R],container:[P],"drop-shadow":[P],ease:["in","out","in-out"],font:[L],"font-weight":["thin","extralight","light","normal","medium","semibold","bold","extrabold","black"],"inset-shadow":[P],leading:["none","tight","snug","normal","relaxed","loose"],perspective:["dramatic","near","normal","midrange","distant","none"],radius:[P],shadow:[P],spacing:["px",K],text:[P],"text-shadow":[P],tracking:["tighter","tight","normal","wide","wider","widest"]},classGroups:{aspect:[{aspect:["auto","square",H,U,et,g]}],container:["container"],columns:[{columns:[K,U,et,s]}],"break-after":[{"break-after":v()}],"break-before":[{"break-before":v()}],"break-inside":[{"break-inside":["auto","avoid","avoid-page","avoid-column"]}],"box-decoration":[{"box-decoration":["slice","clone"]}],box:[{box:["border","content"]}],display:["block","inline-block","inline","flex","inline-flex","table","inline-table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row-group","table-row","flow-root","grid","inline-grid","contents","list-item","hidden"],sr:["sr-only","not-sr-only"],float:[{float:["right","left","none","start","end"]}],clear:[{clear:["left","right","both","none","start","end"]}],isolation:["isolate","isolation-auto"],"object-fit":[{object:["contain","cover","fill","none","scale-down"]}],"object-position":[{object:w()}],overflow:[{overflow:y()}],"overflow-x":[{"overflow-x":y()}],"overflow-y":[{"overflow-y":y()}],overscroll:[{overscroll:z()}],"overscroll-x":[{"overscroll-x":z()}],"overscroll-y":[{"overscroll-y":z()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:N()}],"inset-x":[{"inset-x":N()}],"inset-y":[{"inset-y":N()}],start:[{start:N()}],end:[{end:N()}],top:[{top:N()}],right:[{right:N()}],bottom:[{bottom:N()}],left:[{left:N()}],visibility:["visible","invisible","collapse"],z:[{z:[S,"auto",et,U]}],basis:[{basis:[H,"full","auto",s,...j()]}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["nowrap","wrap","wrap-reverse"]}],flex:[{flex:[K,H,"auto","initial","none",U]}],grow:[{grow:["",K,et,U]}],shrink:[{shrink:["",K,et,U]}],order:[{order:[S,"first","last","none",et,U]}],"grid-cols":[{"grid-cols":C()}],"col-start-end":[{col:O()}],"col-start":[{"col-start":M()}],"col-end":[{"col-end":M()}],"grid-rows":[{"grid-rows":C()}],"row-start-end":[{row:O()}],"row-start":[{"row-start":M()}],"row-end":[{"row-end":M()}],"grid-flow":[{"grid-flow":["row","col","dense","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":E()}],"auto-rows":[{"auto-rows":E()}],gap:[{gap:j()}],"gap-x":[{"gap-x":j()}],"gap-y":[{"gap-y":j()}],"justify-content":[{justify:[...q(),"normal"]}],"justify-items":[{"justify-items":[...W(),"normal"]}],"justify-self":[{"justify-self":["auto",...W()]}],"align-content":[{content:["normal",...q()]}],"align-items":[{items:[...W(),{baseline:["","last"]}]}],"align-self":[{self:["auto",...W(),{baseline:["","last"]}]}],"place-content":[{"place-content":q()}],"place-items":[{"place-items":[...W(),"baseline"]}],"place-self":[{"place-self":["auto",...W()]}],p:[{p:j()}],px:[{px:j()}],py:[{py:j()}],ps:[{ps:j()}],pe:[{pe:j()}],pt:[{pt:j()}],pr:[{pr:j()}],pb:[{pb:j()}],pl:[{pl:j()}],m:[{m:$()}],mx:[{mx:$()}],my:[{my:$()}],ms:[{ms:$()}],me:[{me:$()}],mt:[{mt:$()}],mr:[{mr:$()}],mb:[{mb:$()}],ml:[{ml:$()}],"space-x":[{"space-x":j()}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":j()}],"space-y-reverse":["space-y-reverse"],size:[{size:_()}],w:[{w:[s,"screen",..._()]}],"min-w":[{"min-w":[s,"screen","none",..._()]}],"max-w":[{"max-w":[s,"screen","none","prose",{screen:[n]},..._()]}],h:[{h:["screen","lh",..._()]}],"min-h":[{"min-h":["screen","lh","none",..._()]}],"max-h":[{"max-h":["screen","lh",..._()]}],"font-size":[{text:["base",o,el,X]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:[t,et,Y]}],"font-stretch":[{"font-stretch":["ultra-condensed","extra-condensed","condensed","semi-condensed","normal","semi-expanded","expanded","extra-expanded","ultra-expanded",V,U]}],"font-family":[{font:[ea,U,r]}],"fvn-normal":["normal-nums"],"fvn-ordinal":["ordinal"],"fvn-slashed-zero":["slashed-zero"],"fvn-figure":["lining-nums","oldstyle-nums"],"fvn-spacing":["proportional-nums","tabular-nums"],"fvn-fraction":["diagonal-fractions","stacked-fractions"],tracking:[{tracking:[l,et,U]}],"line-clamp":[{"line-clamp":[K,"none",et,Y]}],leading:[{leading:[a,...j()]}],"list-image":[{"list-image":["none",et,U]}],"list-style-position":[{list:["inside","outside"]}],"list-style-type":[{list:["disc","decimal","none",et,U]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"placeholder-color":[{placeholder:T()}],"text-color":[{text:T()}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...J(),"wavy"]}],"text-decoration-thickness":[{decoration:[K,"from-font","auto",et,X]}],"text-decoration-color":[{decoration:T()}],"underline-offset":[{"underline-offset":[K,"auto",et,U]}],"text-transform":["uppercase","lowercase","capitalize","normal-case"],"text-overflow":["truncate","text-ellipsis","text-clip"],"text-wrap":[{text:["wrap","nowrap","balance","pretty"]}],indent:[{indent:j()}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",et,U]}],whitespace:[{whitespace:["normal","nowrap","pre","pre-line","pre-wrap","break-spaces"]}],break:[{break:["normal","words","all","keep"]}],wrap:[{wrap:["break-word","anywhere","normal"]}],hyphens:[{hyphens:["none","manual","auto"]}],content:[{content:["none",et,U]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:I()}],"bg-repeat":[{bg:Z()}],"bg-size":[{bg:A()}],"bg-image":[{bg:["none",{linear:[{to:["t","tr","r","br","b","bl","l","tl"]},S,et,U],radial:["",et,U],conic:[S,et,U]},ei,er]}],"bg-color":[{bg:T()}],"gradient-from-pos":[{from:B()}],"gradient-via-pos":[{via:B()}],"gradient-to-pos":[{to:B()}],"gradient-from":[{from:T()}],"gradient-via":[{via:T()}],"gradient-to":[{to:T()}],rounded:[{rounded:D()}],"rounded-s":[{"rounded-s":D()}],"rounded-e":[{"rounded-e":D()}],"rounded-t":[{"rounded-t":D()}],"rounded-r":[{"rounded-r":D()}],"rounded-b":[{"rounded-b":D()}],"rounded-l":[{"rounded-l":D()}],"rounded-ss":[{"rounded-ss":D()}],"rounded-se":[{"rounded-se":D()}],"rounded-ee":[{"rounded-ee":D()}],"rounded-es":[{"rounded-es":D()}],"rounded-tl":[{"rounded-tl":D()}],"rounded-tr":[{"rounded-tr":D()}],"rounded-br":[{"rounded-br":D()}],"rounded-bl":[{"rounded-bl":D()}],"border-w":[{border:F()}],"border-w-x":[{"border-x":F()}],"border-w-y":[{"border-y":F()}],"border-w-s":[{"border-s":F()}],"border-w-e":[{"border-e":F()}],"border-w-t":[{"border-t":F()}],"border-w-r":[{"border-r":F()}],"border-w-b":[{"border-b":F()}],"border-w-l":[{"border-l":F()}],"divide-x":[{"divide-x":F()}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":F()}],"divide-y-reverse":["divide-y-reverse"],"border-style":[{border:[...J(),"hidden","none"]}],"divide-style":[{divide:[...J(),"hidden","none"]}],"border-color":[{border:T()}],"border-color-x":[{"border-x":T()}],"border-color-y":[{"border-y":T()}],"border-color-s":[{"border-s":T()}],"border-color-e":[{"border-e":T()}],"border-color-t":[{"border-t":T()}],"border-color-r":[{"border-r":T()}],"border-color-b":[{"border-b":T()}],"border-color-l":[{"border-l":T()}],"divide-color":[{divide:T()}],"outline-style":[{outline:[...J(),"none","hidden"]}],"outline-offset":[{"outline-offset":[K,et,U]}],"outline-w":[{outline:["",K,el,X]}],"outline-color":[{outline:T()}],shadow:[{shadow:["","none",c,ed,eo]}],"shadow-color":[{shadow:T()}],"inset-shadow":[{"inset-shadow":["none",m,ed,eo]}],"inset-shadow-color":[{"inset-shadow":T()}],"ring-w":[{ring:F()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:T()}],"ring-offset-w":[{"ring-offset":[K,X]}],"ring-offset-color":[{"ring-offset":T()}],"inset-ring-w":[{"inset-ring":F()}],"inset-ring-color":[{"inset-ring":T()}],"text-shadow":[{"text-shadow":["none",p,ed,eo]}],"text-shadow-color":[{"text-shadow":T()}],opacity:[{opacity:[K,et,U]}],"mix-blend":[{"mix-blend":[...ec(),"plus-darker","plus-lighter"]}],"bg-blend":[{"bg-blend":ec()}],"mask-clip":[{"mask-clip":["border","padding","content","fill","stroke","view"]},"mask-no-clip"],"mask-composite":[{mask:["add","subtract","intersect","exclude"]}],"mask-image-linear-pos":[{"mask-linear":[K]}],"mask-image-linear-from-pos":[{"mask-linear-from":em()}],"mask-image-linear-to-pos":[{"mask-linear-to":em()}],"mask-image-linear-from-color":[{"mask-linear-from":T()}],"mask-image-linear-to-color":[{"mask-linear-to":T()}],"mask-image-t-from-pos":[{"mask-t-from":em()}],"mask-image-t-to-pos":[{"mask-t-to":em()}],"mask-image-t-from-color":[{"mask-t-from":T()}],"mask-image-t-to-color":[{"mask-t-to":T()}],"mask-image-r-from-pos":[{"mask-r-from":em()}],"mask-image-r-to-pos":[{"mask-r-to":em()}],"mask-image-r-from-color":[{"mask-r-from":T()}],"mask-image-r-to-color":[{"mask-r-to":T()}],"mask-image-b-from-pos":[{"mask-b-from":em()}],"mask-image-b-to-pos":[{"mask-b-to":em()}],"mask-image-b-from-color":[{"mask-b-from":T()}],"mask-image-b-to-color":[{"mask-b-to":T()}],"mask-image-l-from-pos":[{"mask-l-from":em()}],"mask-image-l-to-pos":[{"mask-l-to":em()}],"mask-image-l-from-color":[{"mask-l-from":T()}],"mask-image-l-to-color":[{"mask-l-to":T()}],"mask-image-x-from-pos":[{"mask-x-from":em()}],"mask-image-x-to-pos":[{"mask-x-to":em()}],"mask-image-x-from-color":[{"mask-x-from":T()}],"mask-image-x-to-color":[{"mask-x-to":T()}],"mask-image-y-from-pos":[{"mask-y-from":em()}],"mask-image-y-to-pos":[{"mask-y-to":em()}],"mask-image-y-from-color":[{"mask-y-from":T()}],"mask-image-y-to-color":[{"mask-y-to":T()}],"mask-image-radial":[{"mask-radial":[et,U]}],"mask-image-radial-from-pos":[{"mask-radial-from":em()}],"mask-image-radial-to-pos":[{"mask-radial-to":em()}],"mask-image-radial-from-color":[{"mask-radial-from":T()}],"mask-image-radial-to-color":[{"mask-radial-to":T()}],"mask-image-radial-shape":[{"mask-radial":["circle","ellipse"]}],"mask-image-radial-size":[{"mask-radial":[{closest:["side","corner"],farthest:["side","corner"]}]}],"mask-image-radial-pos":[{"mask-radial-at":x()}],"mask-image-conic-pos":[{"mask-conic":[K]}],"mask-image-conic-from-pos":[{"mask-conic-from":em()}],"mask-image-conic-to-pos":[{"mask-conic-to":em()}],"mask-image-conic-from-color":[{"mask-conic-from":T()}],"mask-image-conic-to-color":[{"mask-conic-to":T()}],"mask-mode":[{mask:["alpha","luminance","match"]}],"mask-origin":[{"mask-origin":["border","padding","content","fill","stroke","view"]}],"mask-position":[{mask:I()}],"mask-repeat":[{mask:Z()}],"mask-size":[{mask:A()}],"mask-type":[{"mask-type":["alpha","luminance"]}],"mask-image":[{mask:["none",et,U]}],filter:[{filter:["","none",et,U]}],blur:[{blur:ep()}],brightness:[{brightness:[K,et,U]}],contrast:[{contrast:[K,et,U]}],"drop-shadow":[{"drop-shadow":["","none",u,ed,eo]}],"drop-shadow-color":[{"drop-shadow":T()}],grayscale:[{grayscale:["",K,et,U]}],"hue-rotate":[{"hue-rotate":[K,et,U]}],invert:[{invert:["",K,et,U]}],saturate:[{saturate:[K,et,U]}],sepia:[{sepia:["",K,et,U]}],"backdrop-filter":[{"backdrop-filter":["","none",et,U]}],"backdrop-blur":[{"backdrop-blur":ep()}],"backdrop-brightness":[{"backdrop-brightness":[K,et,U]}],"backdrop-contrast":[{"backdrop-contrast":[K,et,U]}],"backdrop-grayscale":[{"backdrop-grayscale":["",K,et,U]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[K,et,U]}],"backdrop-invert":[{"backdrop-invert":["",K,et,U]}],"backdrop-opacity":[{"backdrop-opacity":[K,et,U]}],"backdrop-saturate":[{"backdrop-saturate":[K,et,U]}],"backdrop-sepia":[{"backdrop-sepia":["",K,et,U]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":j()}],"border-spacing-x":[{"border-spacing-x":j()}],"border-spacing-y":[{"border-spacing-y":j()}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["","all","colors","opacity","shadow","transform","none",et,U]}],"transition-behavior":[{transition:["normal","discrete"]}],duration:[{duration:[K,"initial",et,U]}],ease:[{ease:["linear","initial",h,et,U]}],delay:[{delay:[K,et,U]}],animate:[{animate:["none",k,et,U]}],backface:[{backface:["hidden","visible"]}],perspective:[{perspective:[f,et,U]}],"perspective-origin":[{"perspective-origin":w()}],rotate:[{rotate:eu()}],"rotate-x":[{"rotate-x":eu()}],"rotate-y":[{"rotate-y":eu()}],"rotate-z":[{"rotate-z":eu()}],scale:[{scale:eb()}],"scale-x":[{"scale-x":eb()}],"scale-y":[{"scale-y":eb()}],"scale-z":[{"scale-z":eb()}],"scale-3d":["scale-3d"],skew:[{skew:ef()}],"skew-x":[{"skew-x":ef()}],"skew-y":[{"skew-y":ef()}],transform:[{transform:[et,U,"","none","gpu","cpu"]}],"transform-origin":[{origin:w()}],"transform-style":[{transform:["3d","flat"]}],translate:[{translate:eg()}],"translate-x":[{"translate-x":eg()}],"translate-y":[{"translate-y":eg()}],"translate-z":[{"translate-z":eg()}],"translate-none":["translate-none"],accent:[{accent:T()}],appearance:[{appearance:["none","auto"]}],"caret-color":[{caret:T()}],"color-scheme":[{scheme:["normal","dark","light","light-dark","only-dark","only-light"]}],cursor:[{cursor:["auto","default","pointer","wait","text","move","help","not-allowed","none","context-menu","progress","cell","crosshair","vertical-text","alias","copy","no-drop","grab","grabbing","all-scroll","col-resize","row-resize","n-resize","e-resize","s-resize","w-resize","ne-resize","nw-resize","se-resize","sw-resize","ew-resize","ns-resize","nesw-resize","nwse-resize","zoom-in","zoom-out",et,U]}],"field-sizing":[{"field-sizing":["fixed","content"]}],"pointer-events":[{"pointer-events":["auto","none"]}],resize:[{resize:["none","","y","x"]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scroll-m":[{"scroll-m":j()}],"scroll-mx":[{"scroll-mx":j()}],"scroll-my":[{"scroll-my":j()}],"scroll-ms":[{"scroll-ms":j()}],"scroll-me":[{"scroll-me":j()}],"scroll-mt":[{"scroll-mt":j()}],"scroll-mr":[{"scroll-mr":j()}],"scroll-mb":[{"scroll-mb":j()}],"scroll-ml":[{"scroll-ml":j()}],"scroll-p":[{"scroll-p":j()}],"scroll-px":[{"scroll-px":j()}],"scroll-py":[{"scroll-py":j()}],"scroll-ps":[{"scroll-ps":j()}],"scroll-pe":[{"scroll-pe":j()}],"scroll-pt":[{"scroll-pt":j()}],"scroll-pr":[{"scroll-pr":j()}],"scroll-pb":[{"scroll-pb":j()}],"scroll-pl":[{"scroll-pl":j()}],"snap-align":[{snap:["start","end","center","align-none"]}],"snap-stop":[{snap:["normal","always"]}],"snap-type":[{snap:["none","x","y","both"]}],"snap-strictness":[{snap:["mandatory","proximity"]}],touch:[{touch:["auto","none","manipulation"]}],"touch-x":[{"touch-pan":["x","left","right"]}],"touch-y":[{"touch-pan":["y","up","down"]}],"touch-pz":["touch-pinch-zoom"],select:[{select:["none","text","all","auto"]}],"will-change":[{"will-change":["auto","scroll","contents","transform",et,U]}],fill:[{fill:["none",...T()]}],"stroke-w":[{stroke:[K,el,X,Y]}],stroke:[{stroke:["none",...T()]}],"forced-color-adjust":[{"forced-color-adjust":["auto","none"]}]},conflictingClassGroups:{overflow:["overflow-x","overflow-y"],overscroll:["overscroll-x","overscroll-y"],inset:["inset-x","inset-y","start","end","top","right","bottom","left"],"inset-x":["right","left"],"inset-y":["top","bottom"],flex:["basis","grow","shrink"],gap:["gap-x","gap-y"],p:["px","py","ps","pe","pt","pr","pb","pl"],px:["pr","pl"],py:["pt","pb"],m:["mx","my","ms","me","mt","mr","mb","ml"],mx:["mr","ml"],my:["mt","mb"],size:["w","h"],"font-size":["leading"],"fvn-normal":["fvn-ordinal","fvn-slashed-zero","fvn-figure","fvn-spacing","fvn-fraction"],"fvn-ordinal":["fvn-normal"],"fvn-slashed-zero":["fvn-normal"],"fvn-figure":["fvn-normal"],"fvn-spacing":["fvn-normal"],"fvn-fraction":["fvn-normal"],"line-clamp":["display","overflow"],rounded:["rounded-s","rounded-e","rounded-t","rounded-r","rounded-b","rounded-l","rounded-ss","rounded-se","rounded-ee","rounded-es","rounded-tl","rounded-tr","rounded-br","rounded-bl"],"rounded-s":["rounded-ss","rounded-es"],"rounded-e":["rounded-se","rounded-ee"],"rounded-t":["rounded-tl","rounded-tr"],"rounded-r":["rounded-tr","rounded-br"],"rounded-b":["rounded-br","rounded-bl"],"rounded-l":["rounded-tl","rounded-bl"],"border-spacing":["border-spacing-x","border-spacing-y"],"border-w":["border-w-x","border-w-y","border-w-s","border-w-e","border-w-t","border-w-r","border-w-b","border-w-l"],"border-w-x":["border-w-r","border-w-l"],"border-w-y":["border-w-t","border-w-b"],"border-color":["border-color-x","border-color-y","border-color-s","border-color-e","border-color-t","border-color-r","border-color-b","border-color-l"],"border-color-x":["border-color-r","border-color-l"],"border-color-y":["border-color-t","border-color-b"],translate:["translate-x","translate-y","translate-none"],"translate-none":["translate","translate-x","translate-y","translate-z"],"scroll-m":["scroll-mx","scroll-my","scroll-ms","scroll-me","scroll-mt","scroll-mr","scroll-mb","scroll-ml"],"scroll-mx":["scroll-mr","scroll-ml"],"scroll-my":["scroll-mt","scroll-mb"],"scroll-p":["scroll-px","scroll-py","scroll-ps","scroll-pe","scroll-pt","scroll-pr","scroll-pb","scroll-pl"],"scroll-px":["scroll-pr","scroll-pl"],"scroll-py":["scroll-pt","scroll-pb"],touch:["touch-x","touch-y","touch-pz"],"touch-x":["touch"],"touch-y":["touch"],"touch-pz":["touch"]},conflictingClassGroupModifiers:{"font-size":["leading"]},orderSensitiveModifiers:["*","**","after","backdrop","before","details-content","file","first-letter","first-line","marker","placeholder","selection"]}})}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/3325-4a3c766c7d12465e.js b/litellm/proxy/_experimental/out/_next/static/chunks/3325-4a3c766c7d12465e.js deleted file mode 100644 index 3b9478ef07f..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/3325-4a3c766c7d12465e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[3325],{41649:function(e,r,t){t.d(r,{Z:function(){return f}});var n=t(5853),o=t(2265),a=t(47187),l=t(7084),i=t(26898),d=t(13241),s=t(1153);let c={xs:{paddingX:"px-2",paddingY:"py-0.5",fontSize:"text-xs"},sm:{paddingX:"px-2.5",paddingY:"py-0.5",fontSize:"text-sm"},md:{paddingX:"px-3",paddingY:"py-0.5",fontSize:"text-md"},lg:{paddingX:"px-3.5",paddingY:"py-0.5",fontSize:"text-lg"},xl:{paddingX:"px-4",paddingY:"py-1",fontSize:"text-xl"}},u={xs:{height:"h-4",width:"w-4"},sm:{height:"h-4",width:"w-4"},md:{height:"h-4",width:"w-4"},lg:{height:"h-5",width:"w-5"},xl:{height:"h-6",width:"w-6"}},m=(0,s.fn)("Badge"),f=o.forwardRef((e,r)=>{let{color:t,icon:f,size:p=l.u8.SM,tooltip:g,className:b,children:h}=e,k=(0,n._T)(e,["color","icon","size","tooltip","className","children"]),v=f||null,{tooltipProps:x,getReferenceProps:w}=(0,a.l)();return o.createElement("span",Object.assign({ref:(0,s.lq)([r,x.refs.setReference]),className:(0,d.q)(m("root"),"w-max shrink-0 inline-flex justify-center items-center cursor-default rounded-tremor-small ring-1 ring-inset",t?(0,d.q)((0,s.bM)(t,i.K.background).bgColor,(0,s.bM)(t,i.K.iconText).textColor,(0,s.bM)(t,i.K.iconRing).ringColor,"bg-opacity-10 ring-opacity-20","dark:bg-opacity-5 dark:ring-opacity-60"):(0,d.q)("bg-tremor-brand-faint text-tremor-brand-emphasis ring-tremor-brand/20","dark:bg-dark-tremor-brand-muted/50 dark:text-dark-tremor-brand dark:ring-dark-tremor-subtle/20"),c[p].paddingX,c[p].paddingY,c[p].fontSize,b)},w,k),o.createElement(a.Z,Object.assign({text:g},x)),v?o.createElement(v,{className:(0,d.q)(m("icon"),"shrink-0 -ml-1 mr-1.5",u[p].height,u[p].width)}):null,o.createElement("span",{className:(0,d.q)(m("text"),"whitespace-nowrap")},h))});f.displayName="Badge"},47323:function(e,r,t){t.d(r,{Z:function(){return g}});var n=t(5853),o=t(2265),a=t(47187),l=t(7084),i=t(13241),d=t(1153),s=t(26898);let c={xs:{paddingX:"px-1.5",paddingY:"py-1.5"},sm:{paddingX:"px-1.5",paddingY:"py-1.5"},md:{paddingX:"px-2",paddingY:"py-2"},lg:{paddingX:"px-2",paddingY:"py-2"},xl:{paddingX:"px-2.5",paddingY:"py-2.5"}},u={xs:{height:"h-3",width:"w-3"},sm:{height:"h-5",width:"w-5"},md:{height:"h-5",width:"w-5"},lg:{height:"h-7",width:"w-7"},xl:{height:"h-9",width:"w-9"}},m={simple:{rounded:"",border:"",ring:"",shadow:""},light:{rounded:"rounded-tremor-default",border:"",ring:"",shadow:""},shadow:{rounded:"rounded-tremor-default",border:"border",ring:"",shadow:"shadow-tremor-card dark:shadow-dark-tremor-card"},solid:{rounded:"rounded-tremor-default",border:"border-2",ring:"ring-1",shadow:""},outlined:{rounded:"rounded-tremor-default",border:"border",ring:"ring-2",shadow:""}},f=(e,r)=>{switch(e){case"simple":return{textColor:r?(0,d.bM)(r,s.K.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:"",borderColor:"",ringColor:""};case"light":return{textColor:r?(0,d.bM)(r,s.K.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:r?(0,i.q)((0,d.bM)(r,s.K.background).bgColor,"bg-opacity-20"):"bg-tremor-brand-muted dark:bg-dark-tremor-brand-muted",borderColor:"",ringColor:""};case"shadow":return{textColor:r?(0,d.bM)(r,s.K.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:r?(0,i.q)((0,d.bM)(r,s.K.background).bgColor,"bg-opacity-20"):"bg-tremor-background dark:bg-dark-tremor-background",borderColor:"border-tremor-border dark:border-dark-tremor-border",ringColor:""};case"solid":return{textColor:r?(0,d.bM)(r,s.K.text).textColor:"text-tremor-brand-inverted dark:text-dark-tremor-brand-inverted",bgColor:r?(0,i.q)((0,d.bM)(r,s.K.background).bgColor,"bg-opacity-20"):"bg-tremor-brand dark:bg-dark-tremor-brand",borderColor:"border-tremor-brand-inverted dark:border-dark-tremor-brand-inverted",ringColor:"ring-tremor-ring dark:ring-dark-tremor-ring"};case"outlined":return{textColor:r?(0,d.bM)(r,s.K.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:r?(0,i.q)((0,d.bM)(r,s.K.background).bgColor,"bg-opacity-20"):"bg-tremor-background dark:bg-dark-tremor-background",borderColor:r?(0,d.bM)(r,s.K.ring).borderColor:"border-tremor-brand-subtle dark:border-dark-tremor-brand-subtle",ringColor:r?(0,i.q)((0,d.bM)(r,s.K.ring).ringColor,"ring-opacity-40"):"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"}}},p=(0,d.fn)("Icon"),g=o.forwardRef((e,r)=>{let{icon:t,variant:s="simple",tooltip:g,size:b=l.u8.SM,color:h,className:k}=e,v=(0,n._T)(e,["icon","variant","tooltip","size","color","className"]),x=f(s,h),{tooltipProps:w,getReferenceProps:C}=(0,a.l)();return o.createElement("span",Object.assign({ref:(0,d.lq)([r,w.refs.setReference]),className:(0,i.q)(p("root"),"inline-flex shrink-0 items-center justify-center",x.bgColor,x.textColor,x.borderColor,x.ringColor,m[s].rounded,m[s].border,m[s].shadow,m[s].ring,c[b].paddingX,c[b].paddingY,k)},C,v),o.createElement(a.Z,Object.assign({text:g},w)),o.createElement(t,{className:(0,i.q)(p("icon"),"shrink-0",u[b].height,u[b].width)}))});g.displayName="Icon"},59341:function(e,r,t){t.d(r,{Z:function(){return R}});var n=t(5853),o=t(71049),a=t(11323),l=t(2265),i=t(66797),d=t(40099),s=t(74275),c=t(59456),u=t(93980),m=t(65573),f=t(67561),p=t(87550),g=t(628),b=t(80281),h=t(31370),k=t(20131),v=t(38929),x=t(52307),w=t(52724),C=t(7935);let y=(0,l.createContext)(null);y.displayName="GroupContext";let E=l.Fragment,N=Object.assign((0,v.yV)(function(e,r){var t;let n=(0,l.useId)(),E=(0,b.Q)(),N=(0,p.B)(),{id:T=E||"headlessui-switch-".concat(n),disabled:M=N||!1,checked:S,defaultChecked:q,onChange:L,name:j,value:R,form:O,autoFocus:P=!1,...F}=e,z=(0,l.useContext)(y),[I,_]=(0,l.useState)(null),K=(0,l.useRef)(null),B=(0,f.T)(K,r,null===z?null:z.setSwitch,_),H=(0,s.L)(q),[Z,D]=(0,d.q)(S,L,null!=H&&H),Y=(0,c.G)(),[X,A]=(0,l.useState)(!1),G=(0,u.z)(()=>{A(!0),null==D||D(!Z),Y.nextFrame(()=>{A(!1)})}),U=(0,u.z)(e=>{if((0,h.P)(e.currentTarget))return e.preventDefault();e.preventDefault(),G()}),V=(0,u.z)(e=>{e.key===w.R.Space?(e.preventDefault(),G()):e.key===w.R.Enter&&(0,k.g)(e.currentTarget)}),$=(0,u.z)(e=>e.preventDefault()),Q=(0,C.wp)(),W=(0,x.zH)(),{isFocusVisible:J,focusProps:ee}=(0,o.F)({autoFocus:P}),{isHovered:er,hoverProps:et}=(0,a.X)({isDisabled:M}),{pressed:en,pressProps:eo}=(0,i.x)({disabled:M}),ea=(0,l.useMemo)(()=>({checked:Z,disabled:M,hover:er,focus:J,active:en,autofocus:P,changing:X}),[Z,er,J,en,M,X,P]),el=(0,v.dG)({id:T,ref:B,role:"switch",type:(0,m.f)(e,I),tabIndex:-1===e.tabIndex?0:null!=(t=e.tabIndex)?t:0,"aria-checked":Z,"aria-labelledby":Q,"aria-describedby":W,disabled:M||void 0,autoFocus:P,onClick:U,onKeyUp:V,onKeyPress:$},ee,et,eo),ei=(0,l.useCallback)(()=>{if(void 0!==H)return null==D?void 0:D(H)},[D,H]),ed=(0,v.L6)();return l.createElement(l.Fragment,null,null!=j&&l.createElement(g.Mt,{disabled:M,data:{[j]:R||"on"},overrides:{type:"checkbox",checked:Z},form:O,onReset:ei}),ed({ourProps:el,theirProps:F,slot:ea,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var r;let[t,n]=(0,l.useState)(null),[o,a]=(0,C.bE)(),[i,d]=(0,x.fw)(),s=(0,l.useMemo)(()=>({switch:t,setSwitch:n}),[t,n]),c=(0,v.L6)();return l.createElement(d,{name:"Switch.Description",value:i},l.createElement(a,{name:"Switch.Label",value:o,props:{htmlFor:null==(r=s.switch)?void 0:r.id,onClick(e){t&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),t.click(),t.focus({preventScroll:!0}))}}},l.createElement(y.Provider,{value:s},c({ourProps:{},theirProps:e,slot:{},defaultTag:E,name:"Switch.Group"}))))},Label:C.__,Description:x.dk});var T=t(44140),M=t(26898),S=t(13241),q=t(1153),L=t(47187);let j=(0,q.fn)("Switch"),R=l.forwardRef((e,r)=>{let{checked:t,defaultChecked:o=!1,onChange:a,color:i,name:d,error:s,errorMessage:c,disabled:u,required:m,tooltip:f,id:p}=e,g=(0,n._T)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),b={bgColor:i?(0,q.bM)(i,M.K.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:i?(0,q.bM)(i,M.K.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[h,k]=(0,T.Z)(o,t),[v,x]=(0,l.useState)(!1),{tooltipProps:w,getReferenceProps:C}=(0,L.l)(300);return l.createElement("div",{className:"flex flex-row items-center justify-start"},l.createElement(L.Z,Object.assign({text:f},w)),l.createElement("div",Object.assign({ref:(0,q.lq)([r,w.refs.setReference]),className:(0,S.q)(j("root"),"flex flex-row relative h-5")},g,C),l.createElement("input",{type:"checkbox",className:(0,S.q)(j("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:d,required:m,checked:h,onChange:e=>{e.preventDefault()}}),l.createElement(N,{checked:h,onChange:e=>{k(e),null==a||a(e)},disabled:u,className:(0,S.q)(j("switch"),"w-10 h-5 group relative inline-flex shrink-0 cursor-pointer items-center justify-center rounded-tremor-full","focus:outline-none",u?"cursor-not-allowed":""),onFocus:()=>x(!0),onBlur:()=>x(!1),id:p},l.createElement("span",{className:(0,S.q)(j("sr-only"),"sr-only")},"Switch ",h?"on":"off"),l.createElement("span",{"aria-hidden":"true",className:(0,S.q)(j("background"),h?b.bgColor:"bg-tremor-border dark:bg-dark-tremor-border","pointer-events-none absolute mx-auto h-3 w-9 rounded-tremor-full transition-colors duration-100 ease-in-out")}),l.createElement("span",{"aria-hidden":"true",className:(0,S.q)(j("round"),h?(0,S.q)(b.bgColor,"translate-x-5 border-tremor-background dark:border-dark-tremor-background"):"translate-x-0 bg-tremor-border dark:bg-dark-tremor-border border-tremor-background dark:border-dark-tremor-background","pointer-events-none absolute left-0 inline-block h-5 w-5 transform rounded-tremor-full border-2 shadow-tremor-input duration-100 ease-in-out transition",v?(0,S.q)("ring-2",b.ringColor):"")}))),s&&c?l.createElement("p",{className:(0,S.q)(j("errorMessage"),"text-sm text-red-500 mt-1 ")},c):null)});R.displayName="Switch"},21626:function(e,r,t){t.d(r,{Z:function(){return i}});var n=t(5853),o=t(2265),a=t(13241);let l=(0,t(1153).fn)("Table"),i=o.forwardRef((e,r)=>{let{children:t,className:i}=e,d=(0,n._T)(e,["children","className"]);return o.createElement("div",{className:(0,a.q)(l("root"),"overflow-auto",i)},o.createElement("table",Object.assign({ref:r,className:(0,a.q)(l("table"),"w-full text-tremor-default","text-tremor-content","dark:text-dark-tremor-content")},d),t))});i.displayName="Table"},97214:function(e,r,t){t.d(r,{Z:function(){return i}});var n=t(5853),o=t(2265),a=t(13241);let l=(0,t(1153).fn)("TableBody"),i=o.forwardRef((e,r)=>{let{children:t,className:i}=e,d=(0,n._T)(e,["children","className"]);return o.createElement(o.Fragment,null,o.createElement("tbody",Object.assign({ref:r,className:(0,a.q)(l("root"),"align-top divide-y","divide-tremor-border","dark:divide-dark-tremor-border",i)},d),t))});i.displayName="TableBody"},28241:function(e,r,t){t.d(r,{Z:function(){return i}});var n=t(5853),o=t(2265),a=t(13241);let l=(0,t(1153).fn)("TableCell"),i=o.forwardRef((e,r)=>{let{children:t,className:i}=e,d=(0,n._T)(e,["children","className"]);return o.createElement(o.Fragment,null,o.createElement("td",Object.assign({ref:r,className:(0,a.q)(l("root"),"align-middle whitespace-nowrap text-left p-4",i)},d),t))});i.displayName="TableCell"},58834:function(e,r,t){t.d(r,{Z:function(){return i}});var n=t(5853),o=t(2265),a=t(13241);let l=(0,t(1153).fn)("TableHead"),i=o.forwardRef((e,r)=>{let{children:t,className:i}=e,d=(0,n._T)(e,["children","className"]);return o.createElement(o.Fragment,null,o.createElement("thead",Object.assign({ref:r,className:(0,a.q)(l("root"),"text-left","text-tremor-content","dark:text-dark-tremor-content",i)},d),t))});i.displayName="TableHead"},69552:function(e,r,t){t.d(r,{Z:function(){return i}});var n=t(5853),o=t(2265),a=t(13241);let l=(0,t(1153).fn)("TableHeaderCell"),i=o.forwardRef((e,r)=>{let{children:t,className:i}=e,d=(0,n._T)(e,["children","className"]);return o.createElement(o.Fragment,null,o.createElement("th",Object.assign({ref:r,className:(0,a.q)(l("root"),"whitespace-nowrap text-left font-semibold top-0 px-4 py-3.5","text-tremor-content-strong","dark:text-dark-tremor-content-strong",i)},d),t))});i.displayName="TableHeaderCell"},71876:function(e,r,t){t.d(r,{Z:function(){return i}});var n=t(5853),o=t(2265),a=t(13241);let l=(0,t(1153).fn)("TableRow"),i=o.forwardRef((e,r)=>{let{children:t,className:i}=e,d=(0,n._T)(e,["children","className"]);return o.createElement(o.Fragment,null,o.createElement("tr",Object.assign({ref:r,className:(0,a.q)(l("row"),i)},d),t))});i.displayName="TableRow"},44140:function(e,r,t){t.d(r,{Z:function(){return o}});var n=t(2265);let o=(e,r)=>{let t=void 0!==r,[o,a]=(0,n.useState)(e);return[t?r:o,e=>{t||a(e)}]}},44643:function(e,r,t){var n=t(2265);let o=n.forwardRef(function(e,r){return n.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:2,stroke:"currentColor","aria-hidden":"true",ref:r},e),n.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"}))});r.Z=o},91126:function(e,r,t){var n=t(2265);let o=n.forwardRef(function(e,r){return n.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:2,stroke:"currentColor","aria-hidden":"true",ref:r},e),n.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"}),n.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M21 12a9 9 0 11-18 0 9 9 0 0118 0z"}))});r.Z=o},74998:function(e,r,t){var n=t(2265);let o=n.forwardRef(function(e,r){return n.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:2,stroke:"currentColor","aria-hidden":"true",ref:r},e),n.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"}))});r.Z=o},52307:function(e,r,t){t.d(r,{dk:function(){return m},fw:function(){return u},zH:function(){return c}});var n=t(2265),o=t(93980),a=t(73389),l=t(67561),i=t(87550),d=t(38929);let s=(0,n.createContext)(null);function c(){var e,r;return null!=(r=null==(e=(0,n.useContext)(s))?void 0:e.value)?r:void 0}function u(){let[e,r]=(0,n.useState)([]);return[e.length>0?e.join(" "):void 0,(0,n.useMemo)(()=>function(e){let t=(0,o.z)(e=>(r(r=>[...r,e]),()=>r(r=>{let t=r.slice(),n=t.indexOf(e);return -1!==n&&t.splice(n,1),t}))),a=(0,n.useMemo)(()=>({register:t,slot:e.slot,name:e.name,props:e.props,value:e.value}),[t,e.slot,e.name,e.props,e.value]);return n.createElement(s.Provider,{value:a},e.children)},[r])]}s.displayName="DescriptionContext";let m=Object.assign((0,d.yV)(function(e,r){let t=(0,n.useId)(),o=(0,i.B)(),{id:c="headlessui-description-".concat(t),...u}=e,m=function e(){let r=(0,n.useContext)(s);if(null===r){let r=Error("You used a component, but it is not inside a relevant parent.");throw Error.captureStackTrace&&Error.captureStackTrace(r,e),r}return r}(),f=(0,l.T)(r);(0,a.e)(()=>m.register(c),[c,m.register]);let p=o||!1,g=(0,n.useMemo)(()=>({...m.slot,disabled:p}),[m.slot,p]),b={ref:f,...m.props,id:c};return(0,d.L6)()({ourProps:b,theirProps:u,slot:g,defaultTag:"p",name:m.name||"Description"})}),{})},7935:function(e,r,t){t.d(r,{__:function(){return f},bE:function(){return m},wp:function(){return u}});var n=t(2265),o=t(93980),a=t(73389),l=t(67561),i=t(87550),d=t(80281),s=t(38929);let c=(0,n.createContext)(null);function u(e){var r,t,o;let a=null!=(t=null==(r=(0,n.useContext)(c))?void 0:r.value)?t:void 0;return(null!=(o=null==e?void 0:e.length)?o:0)>0?[a,...e].filter(Boolean).join(" "):a}function m(){let{inherit:e=!1}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},r=u(),[t,a]=(0,n.useState)([]),l=e?[r,...t].filter(Boolean):t;return[l.length>0?l.join(" "):void 0,(0,n.useMemo)(()=>function(e){let r=(0,o.z)(e=>(a(r=>[...r,e]),()=>a(r=>{let t=r.slice(),n=t.indexOf(e);return -1!==n&&t.splice(n,1),t}))),t=(0,n.useMemo)(()=>({register:r,slot:e.slot,name:e.name,props:e.props,value:e.value}),[r,e.slot,e.name,e.props,e.value]);return n.createElement(c.Provider,{value:t},e.children)},[a])]}c.displayName="LabelContext";let f=Object.assign((0,s.yV)(function(e,r){var t;let u=(0,n.useId)(),m=function e(){let r=(0,n.useContext)(c);if(null===r){let r=Error("You used a