From 43054a239059cbc695a0f0215aedfa15615750cc Mon Sep 17 00:00:00 2001 From: Harshit Jain Date: Thu, 26 Feb 2026 19:03:49 +0530 Subject: [PATCH 001/289] fix: langfuse trace leak key on model params --- litellm/integrations/langfuse/langfuse.py | 31 +++++++++++++++++------ 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/litellm/integrations/langfuse/langfuse.py b/litellm/integrations/langfuse/langfuse.py index 7bf97665fd..e2db8be045 100644 --- a/litellm/integrations/langfuse/langfuse.py +++ b/litellm/integrations/langfuse/langfuse.py @@ -25,6 +25,7 @@ from litellm.litellm_core_utils.core_helpers import ( reconstruct_model_name, filter_exceptions_from_params, ) +from litellm.litellm_core_utils.model_param_helper import ModelParamHelper from litellm.litellm_core_utils.redact_messages import redact_user_api_key_info from litellm.integrations.langfuse.langfuse_mock_client import ( create_mock_langfuse_client, @@ -123,7 +124,7 @@ class LangFuseLogger: self.langfuse_flush_interval = LangFuseLogger._get_langfuse_flush_interval( flush_interval ) - + if should_use_langfuse_mock(): self.langfuse_client = create_mock_langfuse_client() self.is_mock_mode = True @@ -291,8 +292,6 @@ class LangFuseLogger: functions = optional_params.pop("functions", None) tools = optional_params.pop("tools", None) - # Remove secret_fields to prevent leaking sensitive data (e.g., authorization headers) - optional_params.pop("secret_fields", None) if functions is not None: prompt["functions"] = functions if tools is not None: @@ -505,13 +504,18 @@ class LangFuseLogger: kwargs.get("model", ""), custom_llm_provider, metadata ) + # Use whitelisted model parameters to prevent leaking secrets + sanitized_model_params = ModelParamHelper.get_standard_logging_model_parameters( + optional_params + ) + trace.generation( CreateGeneration( name=metadata.get("generation_name", "litellm-completion"), startTime=start_time, endTime=end_time, model=model_name, - modelParameters=optional_params, + modelParameters=sanitized_model_params, prompt=input, completion=output, usage={ @@ -607,9 +611,7 @@ class LangFuseLogger: # Use standard_logging_object.trace_id if available (when trace_id from metadata is None) # This allows standard trace_id to be used when provided in standard_logging_object if trace_id is None and standard_logging_object is not None: - trace_id = cast( - Optional[str], standard_logging_object.get("trace_id") - ) + trace_id = cast(Optional[str], standard_logging_object.get("trace_id")) # Fallback to litellm_call_id if no trace_id found if trace_id is None: trace_id = litellm_call_id @@ -833,13 +835,26 @@ class LangFuseLogger: kwargs.get("model", ""), custom_llm_provider, metadata ) + # Use whitelisted model_parameters from StandardLoggingPayload + # to prevent leaking secrets (api_key, auth headers, etc.) + if standard_logging_object is not None: + sanitized_model_params = standard_logging_object.get( + "model_parameters", optional_params + ) + else: + sanitized_model_params = ( + ModelParamHelper.get_standard_logging_model_parameters( + optional_params + ) + ) + generation_params = { "name": generation_name, "id": clean_metadata.pop("generation_id", generation_id), "start_time": start_time, "end_time": end_time, "model": model_name, - "model_parameters": optional_params, + "model_parameters": sanitized_model_params, "input": input if not mask_input else "redacted-by-litellm", "output": output if not mask_output else "redacted-by-litellm", "usage": usage, From 7e9930cc3b4dbee6970124eb6122fd351f1593db Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Sat, 28 Feb 2026 17:22:01 +0530 Subject: [PATCH 002/289] Fix Langfuse trace_id mapping for failed logs and prioritize session_id This fix addresses Bug 1 where failed LiteLLM logs were using request_id instead of session_id for Langfuse trace mapping, breaking trace correlation. Changes: 1. Fix kwargs inconsistency in failure path (litellm_logging.py:2956) - Changed from passing self.model_call_details to passing local kwargs variable - Matches success path behavior and excludes original_response (potentially a coroutine) 2. Prioritize session_id as trace_id fallback (langfuse.py:607-615) - When no explicit trace_id is provided, now uses session_id from metadata - This ensures traces with the same session_id are grouped together in Langfuse - Maintains backward compatibility: only activates when session_id is set Testing: - All 28 existing Langfuse tests pass (excluding pre-existing test_langfuse_e2e_sync which fails due to missing API key) - Specifically verified trace_id resolution tests still pass Co-Authored-By: Claude Haiku 4.5 --- litellm/integrations/langfuse/langfuse.py | 5 ++++- litellm/litellm_core_utils/litellm_logging.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/litellm/integrations/langfuse/langfuse.py b/litellm/integrations/langfuse/langfuse.py index 7bf97665fd..70f1161792 100644 --- a/litellm/integrations/langfuse/langfuse.py +++ b/litellm/integrations/langfuse/langfuse.py @@ -604,9 +604,12 @@ class LangFuseLogger: session_id = clean_metadata.pop("session_id", None) trace_name = cast(Optional[str], clean_metadata.pop("trace_name", None)) trace_id = clean_metadata.pop("trace_id", None) + # If session_id is provided, use it as trace_id for consistent trace mapping + if trace_id is None and session_id is not None: + trace_id = session_id # Use standard_logging_object.trace_id if available (when trace_id from metadata is None) # This allows standard trace_id to be used when provided in standard_logging_object - if trace_id is None and standard_logging_object is not None: + elif trace_id is None and standard_logging_object is not None: trace_id = cast( Optional[str], standard_logging_object.get("trace_id") ) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index e450b233c7..d5419c9868 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -2953,7 +2953,7 @@ class Logging(LiteLLMLoggingBaseClass): user_id=kwargs.get("user", None), status_message=str(exception), level="ERROR", - kwargs=self.model_call_details, + kwargs=kwargs, ) if _response is not None and isinstance(_response, dict): _trace_id = _response.get("trace_id", None) From 315b00fd193a361e581877253c545a127ad5f31c Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Sat, 28 Feb 2026 17:34:59 +0530 Subject: [PATCH 003/289] Fix Langfuse failure path kwargs and add session_id trace tests Fix: The Langfuse failure logging path was passing self.model_call_details (which includes original_response, potentially a coroutine) instead of the clean local kwargs copy. This aligns the failure path with the success path behavior (litellm_logging.py:2956). Reverted the session_id-as-trace_id approach as it causes trace collisions in Langfuse (multiple calls in the same session would overwrite each other). Instead, session_id is correctly used only for Langfuse session grouping via trace_params["session_id"], while each call retains its own unique trace_id. Added 4 tests: - session_id correctly passed as trace session_id (not trace_id) - session_id preserved for ERROR level (failure) logs - explicit trace_id takes priority over session_id - failure path kwargs excludes original_response Co-Authored-By: Claude Opus 4.6 --- litellm/integrations/langfuse/langfuse.py | 5 +- .../integrations/test_langfuse.py | 182 ++++++++++++++++++ 2 files changed, 183 insertions(+), 4 deletions(-) diff --git a/litellm/integrations/langfuse/langfuse.py b/litellm/integrations/langfuse/langfuse.py index 70f1161792..7bf97665fd 100644 --- a/litellm/integrations/langfuse/langfuse.py +++ b/litellm/integrations/langfuse/langfuse.py @@ -604,12 +604,9 @@ class LangFuseLogger: session_id = clean_metadata.pop("session_id", None) trace_name = cast(Optional[str], clean_metadata.pop("trace_name", None)) trace_id = clean_metadata.pop("trace_id", None) - # If session_id is provided, use it as trace_id for consistent trace mapping - if trace_id is None and session_id is not None: - trace_id = session_id # Use standard_logging_object.trace_id if available (when trace_id from metadata is None) # This allows standard trace_id to be used when provided in standard_logging_object - elif trace_id is None and standard_logging_object is not None: + if trace_id is None and standard_logging_object is not None: trace_id = cast( Optional[str], standard_logging_object.get("trace_id") ) diff --git a/tests/test_litellm/integrations/test_langfuse.py b/tests/test_litellm/integrations/test_langfuse.py index 10d3323a25..1c47087e52 100644 --- a/tests/test_litellm/integrations/test_langfuse.py +++ b/tests/test_litellm/integrations/test_langfuse.py @@ -468,6 +468,188 @@ class TestLangfuseUsageDetails(unittest.TestCase): assert self.last_trace_kwargs.get("id") == "call-id-xyz" + def test_log_langfuse_v2_session_id_passed_as_trace_session_id(self): + """ + Test that metadata.session_id is correctly passed as trace_params["session_id"] + for Langfuse session grouping, and does NOT override trace_id. + Each LLM call should get its own unique trace_id while sharing the session_id. + """ + payload = self._build_standard_logging_payload(trace_id="std-trace-123") + kwargs = self._build_langfuse_kwargs(payload) + self.last_trace_kwargs = {} + + with patch( + "litellm.integrations.langfuse.langfuse._add_prompt_to_generation_params", + side_effect=lambda generation_params, **kwargs: generation_params, + create=True, + ): + self.logger._log_langfuse_v2( + user_id="user-1", + metadata={"session_id": "my-session-abc"}, + litellm_params={"metadata": {"session_id": "my-session-abc"}}, + output=None, + start_time=datetime.datetime.utcnow(), + end_time=datetime.datetime.utcnow(), + kwargs=kwargs, + optional_params={}, + input=None, + response_obj=None, + level="INFO", + litellm_call_id="call-id-456", + ) + + # session_id should be set for Langfuse session grouping + assert self.last_trace_kwargs.get("session_id") == "my-session-abc" + # trace_id should remain the standard trace_id, NOT the session_id + assert self.last_trace_kwargs.get("id") == "std-trace-123" + + def test_log_langfuse_v2_session_id_preserved_for_error_level(self): + """ + Test that session_id is correctly passed in trace_params even when + the log level is ERROR (failure case). This verifies the fix for + failed requests losing session_id mapping in Langfuse. + """ + payload = self._build_standard_logging_payload(trace_id="std-trace-err") + kwargs = self._build_langfuse_kwargs(payload) + self.last_trace_kwargs = {} + + with patch( + "litellm.integrations.langfuse.langfuse._add_prompt_to_generation_params", + side_effect=lambda generation_params, **kwargs: generation_params, + create=True, + ): + self.logger._log_langfuse_v2( + user_id="user-1", + metadata={"session_id": "error-session-xyz"}, + litellm_params={"metadata": {"session_id": "error-session-xyz"}}, + output="BadRequestError: model not found", + start_time=datetime.datetime.utcnow(), + end_time=datetime.datetime.utcnow(), + kwargs=kwargs, + optional_params={}, + input={"messages": [{"role": "user", "content": "test"}]}, + response_obj=None, + level="ERROR", + litellm_call_id="call-id-err-789", + ) + + # session_id must be preserved even for ERROR level logs + assert self.last_trace_kwargs.get("session_id") == "error-session-xyz" + # trace_id should be the standard trace_id, not the session_id + assert self.last_trace_kwargs.get("id") == "std-trace-err" + # status_message should be set for error traces + assert self.last_trace_kwargs.get("status_message") is not None + + def test_log_langfuse_v2_explicit_trace_id_takes_priority_over_session_id(self): + """ + Test that when both trace_id and session_id are provided in metadata, + trace_id takes priority as the trace identifier. + """ + payload = self._build_standard_logging_payload() + kwargs = self._build_langfuse_kwargs(payload) + self.last_trace_kwargs = {} + + with patch( + "litellm.integrations.langfuse.langfuse._add_prompt_to_generation_params", + side_effect=lambda generation_params, **kwargs: generation_params, + create=True, + ): + self.logger._log_langfuse_v2( + user_id="user-1", + metadata={ + "session_id": "session-999", + "trace_id": "explicit-trace-id-777", + }, + litellm_params={ + "metadata": { + "session_id": "session-999", + "trace_id": "explicit-trace-id-777", + } + }, + output=None, + start_time=datetime.datetime.utcnow(), + end_time=datetime.datetime.utcnow(), + kwargs=kwargs, + optional_params={}, + input=None, + response_obj=None, + level="DEFAULT", + litellm_call_id="call-id-aaa", + ) + + # Explicit trace_id must take priority + assert self.last_trace_kwargs.get("id") == "explicit-trace-id-777" + # session_id must still be set for session grouping + assert self.last_trace_kwargs.get("session_id") == "session-999" + + +def test_failure_handler_langfuse_kwargs_excludes_original_response(): + """ + Test that the Langfuse failure logging path passes the local kwargs copy + (which excludes 'original_response') rather than self.model_call_details directly. + This prevents passing coroutines or large response objects to the Langfuse logger. + """ + from litellm.litellm_core_utils.litellm_logging import Logging + + # Create a mock coroutine to simulate original_response + mock_coroutine = MagicMock() + mock_coroutine.__class__.__name__ = "coroutine" + + model_call_details = { + "litellm_call_id": "test-call-id", + "litellm_trace_id": None, + "model": "gpt-4", + "messages": [{"role": "user", "content": "test"}], + "litellm_params": { + "metadata": {"session_id": "test-session"}, + "litellm_session_id": None, + }, + "original_response": mock_coroutine, + "optional_params": {}, + "stream": False, + "call_type": "completion", + "input": [{"role": "user", "content": "test"}], + } + + captured_kwargs = {} + + class MockLangfuseLogger: + def log_event_on_langfuse(self, **log_kwargs): + captured_kwargs.update(log_kwargs) + return {"trace_id": "mock-trace-id", "generation_id": "mock-gen-id"} + + mock_logger = MockLangfuseLogger() + + # Simulate the failure path logic from litellm_logging.py + # This mirrors lines 2937-2957 of the failure_handler + kwargs = {} + for k, v in model_call_details.items(): + if k != "original_response": + kwargs[k] = v + + # Verify the local kwargs does NOT contain original_response + assert "original_response" not in kwargs + # Verify session_id is present in kwargs metadata + assert kwargs["litellm_params"]["metadata"]["session_id"] == "test-session" + + # Call with the local kwargs (as the fix does) + mock_logger.log_event_on_langfuse( + start_time=datetime.datetime.utcnow(), + end_time=datetime.datetime.utcnow(), + response_obj=None, + user_id=kwargs.get("user", None), + status_message="TestError: something failed", + level="ERROR", + kwargs=kwargs, + ) + + # Verify original_response is NOT in the kwargs passed to Langfuse + assert "original_response" not in captured_kwargs.get("kwargs", {}) + # Verify session_id metadata is preserved in the kwargs passed to Langfuse + langfuse_metadata = captured_kwargs["kwargs"]["litellm_params"]["metadata"] + assert langfuse_metadata["session_id"] == "test-session" + + def test_max_langfuse_clients_limit(): """ Test that the max langfuse clients limit is respected when initializing multiple clients From 83cab3f54a3f68f5bddac633e2184953f4dfbc2a Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Sat, 28 Feb 2026 17:47:25 +0530 Subject: [PATCH 004/289] Rewrite test to exercise actual failure_handler code path Replace simulated test with one that invokes the real Logging.failure_handler(), mocks LangFuseHandler to capture kwargs, and asserts original_response is excluded and session_id is preserved. This ensures the test catches regressions if the production code changes. Co-Authored-By: Claude Opus 4.6 --- .../integrations/test_langfuse.py | 133 ++++++++++-------- 1 file changed, 76 insertions(+), 57 deletions(-) diff --git a/tests/test_litellm/integrations/test_langfuse.py b/tests/test_litellm/integrations/test_langfuse.py index 1c47087e52..15874113b4 100644 --- a/tests/test_litellm/integrations/test_langfuse.py +++ b/tests/test_litellm/integrations/test_langfuse.py @@ -585,69 +585,88 @@ class TestLangfuseUsageDetails(unittest.TestCase): def test_failure_handler_langfuse_kwargs_excludes_original_response(): """ - Test that the Langfuse failure logging path passes the local kwargs copy - (which excludes 'original_response') rather than self.model_call_details directly. - This prevents passing coroutines or large response objects to the Langfuse logger. + Test that the actual Logging.failure_handler() passes kwargs without + 'original_response' to the Langfuse logger. Exercises the real code path + rather than simulating the filtering logic. """ + import litellm from litellm.litellm_core_utils.litellm_logging import Logging - # Create a mock coroutine to simulate original_response - mock_coroutine = MagicMock() - mock_coroutine.__class__.__name__ = "coroutine" - - model_call_details = { - "litellm_call_id": "test-call-id", - "litellm_trace_id": None, - "model": "gpt-4", - "messages": [{"role": "user", "content": "test"}], - "litellm_params": { - "metadata": {"session_id": "test-session"}, - "litellm_session_id": None, - }, - "original_response": mock_coroutine, - "optional_params": {}, - "stream": False, - "call_type": "completion", - "input": [{"role": "user", "content": "test"}], - } - - captured_kwargs = {} - - class MockLangfuseLogger: - def log_event_on_langfuse(self, **log_kwargs): - captured_kwargs.update(log_kwargs) - return {"trace_id": "mock-trace-id", "generation_id": "mock-gen-id"} - - mock_logger = MockLangfuseLogger() - - # Simulate the failure path logic from litellm_logging.py - # This mirrors lines 2937-2957 of the failure_handler - kwargs = {} - for k, v in model_call_details.items(): - if k != "original_response": - kwargs[k] = v - - # Verify the local kwargs does NOT contain original_response - assert "original_response" not in kwargs - # Verify session_id is present in kwargs metadata - assert kwargs["litellm_params"]["metadata"]["session_id"] == "test-session" - - # Call with the local kwargs (as the fix does) - mock_logger.log_event_on_langfuse( + # Create a Logging instance + logging_obj = Logging( + model="gpt-4", + messages=[{"role": "user", "content": "test"}], + stream=False, + call_type="completion", start_time=datetime.datetime.utcnow(), - end_time=datetime.datetime.utcnow(), - response_obj=None, - user_id=kwargs.get("user", None), - status_message="TestError: something failed", - level="ERROR", - kwargs=kwargs, + litellm_call_id="test-call-id-failure", + function_id="test-function-id", ) - # Verify original_response is NOT in the kwargs passed to Langfuse - assert "original_response" not in captured_kwargs.get("kwargs", {}) - # Verify session_id metadata is preserved in the kwargs passed to Langfuse - langfuse_metadata = captured_kwargs["kwargs"]["litellm_params"]["metadata"] - assert langfuse_metadata["session_id"] == "test-session" + # Set up model_call_details with original_response (simulates a coroutine) + mock_coroutine = MagicMock() + logging_obj.model_call_details["original_response"] = mock_coroutine + logging_obj.model_call_details["litellm_params"] = { + "metadata": {"session_id": "test-session-failure"}, + "litellm_session_id": None, + } + logging_obj.model_call_details["optional_params"] = {} + + # Capture what gets passed to log_event_on_langfuse + captured_kwargs = {} + mock_langfuse_logger = MagicMock() + + def capture_log_event(**log_kwargs): + captured_kwargs.update(log_kwargs) + return {"trace_id": "mock-trace-id", "generation_id": "mock-gen-id"} + + mock_langfuse_logger.log_event_on_langfuse.side_effect = capture_log_event + + # Set "langfuse" as a failure callback so the failure_handler processes it + original_failure_callback = litellm.failure_callback + litellm.failure_callback = ["langfuse"] + + try: + # Mock LangFuseHandler to return our capturing mock logger + with patch( + "litellm.litellm_core_utils.litellm_logging.LangFuseHandler" + ) as mock_handler_class: + mock_handler_class.get_langfuse_logger_for_request.return_value = ( + mock_langfuse_logger + ) + + # Call the actual failure_handler + test_exception = Exception("TestError: model not found") + logging_obj.failure_handler( + exception=test_exception, + traceback_exception="Traceback: test", + start_time=datetime.datetime.utcnow(), + end_time=datetime.datetime.utcnow(), + ) + + # Verify log_event_on_langfuse was actually called + assert mock_langfuse_logger.log_event_on_langfuse.called, ( + "log_event_on_langfuse was not called" + ) + + # Verify original_response is NOT in the kwargs passed to Langfuse + langfuse_kwargs = captured_kwargs.get("kwargs", {}) + assert "original_response" not in langfuse_kwargs, ( + "original_response should be excluded from kwargs passed to Langfuse" + ) + + # Verify session_id metadata is preserved in the kwargs + langfuse_metadata = langfuse_kwargs.get("litellm_params", {}).get( + "metadata", {} + ) + assert langfuse_metadata.get("session_id") == "test-session-failure", ( + "session_id should be preserved in kwargs passed to Langfuse" + ) + + # Verify level is ERROR + assert captured_kwargs.get("level") == "ERROR" + finally: + litellm.failure_callback = original_failure_callback def test_max_langfuse_clients_limit(): From 016a4fd6089b038e66843c11bd776ef82e7138aa Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Mon, 2 Mar 2026 20:20:27 +0530 Subject: [PATCH 005/289] Fix async failure path not logging to Langfuse (proxy bug) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The proxy uses async_failure_handler → LangfusePromptManagement.async_log_failure_event(), which silently returned when standard_logging_object was None. This meant failed LLM calls never created traces in Langfuse. Remove the early return and fall back to extracting the error message from kwargs["exception"] when standard_logging_object is unavailable. Co-Authored-By: Claude Opus 4.6 --- .../langfuse/langfuse_prompt_management.py | 9 +- .../integrations/test_langfuse.py | 130 ++++++++++++++++++ 2 files changed, 136 insertions(+), 3 deletions(-) diff --git a/litellm/integrations/langfuse/langfuse_prompt_management.py b/litellm/integrations/langfuse/langfuse_prompt_management.py index 3986fc6a6e..d3de59c8e6 100644 --- a/litellm/integrations/langfuse/langfuse_prompt_management.py +++ b/litellm/integrations/langfuse/langfuse_prompt_management.py @@ -338,14 +338,17 @@ class LangfusePromptManagement(LangFuseLogger, PromptManagementBase, CustomLogge Optional[StandardLoggingPayload], kwargs.get("standard_logging_object", None), ) - if standard_logging_object is None: - return + status_message = str(kwargs.get("exception", "Unknown error")) + if standard_logging_object is not None: + status_message = standard_logging_object.get( + "error_str", status_message + ) langfuse_logger_to_use.log_event_on_langfuse( start_time=start_time, end_time=end_time, response_obj=None, user_id=kwargs.get("user", None), - status_message=standard_logging_object["error_str"], + status_message=status_message, level="ERROR", kwargs=kwargs, ) diff --git a/tests/test_litellm/integrations/test_langfuse.py b/tests/test_litellm/integrations/test_langfuse.py index 15874113b4..084fd7d048 100644 --- a/tests/test_litellm/integrations/test_langfuse.py +++ b/tests/test_litellm/integrations/test_langfuse.py @@ -669,6 +669,136 @@ def test_failure_handler_langfuse_kwargs_excludes_original_response(): litellm.failure_callback = original_failure_callback +@pytest.mark.asyncio +async def test_async_log_failure_event_logs_to_langfuse(): + """ + Test that LangfusePromptManagement.async_log_failure_event() calls + log_event_on_langfuse with level=ERROR even when standard_logging_object + is present. This is the code path the proxy uses for failed LLM calls. + """ + from litellm.integrations.langfuse.langfuse_prompt_management import ( + LangfusePromptManagement, + ) + + mock_langfuse_module = MagicMock() + mock_langfuse_module.version.__version__ = "3.0.0" + + with patch.dict( + "os.environ", + { + "LANGFUSE_SECRET_KEY": "test-secret", + "LANGFUSE_PUBLIC_KEY": "test-public", + "LANGFUSE_HOST": "https://test.langfuse.com", + }, + ), patch.dict("sys.modules", {"langfuse": mock_langfuse_module}): + prompt_mgmt = LangfusePromptManagement() + + # Mock the langfuse logger returned by get_langfuse_logger_for_request + mock_logger = MagicMock() + mock_logger.log_event_on_langfuse.return_value = { + "trace_id": "mock-trace", + "generation_id": "mock-gen", + } + + with patch( + "litellm.integrations.langfuse.langfuse_prompt_management.LangFuseHandler" + ) as mock_handler: + mock_handler.get_langfuse_logger_for_request.return_value = mock_logger + + kwargs = { + "litellm_params": { + "metadata": {"session_id": "test-session-fail"}, + }, + "litellm_call_id": "call-fail-123", + "user": "test-user", + "exception": Exception("API error: model not found"), + "standard_logging_object": { + "error_str": "API error: model not found", + "trace_id": "std-trace-fail", + "metadata": {}, + }, + } + + await prompt_mgmt.async_log_failure_event( + kwargs=kwargs, + response_obj=None, + start_time=datetime.datetime.utcnow(), + end_time=datetime.datetime.utcnow(), + ) + + # Verify log_event_on_langfuse was called + assert mock_logger.log_event_on_langfuse.called, ( + "log_event_on_langfuse was not called for failure event" + ) + call_kwargs = mock_logger.log_event_on_langfuse.call_args[1] + assert call_kwargs["level"] == "ERROR" + assert call_kwargs["status_message"] == "API error: model not found" + assert call_kwargs["response_obj"] is None + + +@pytest.mark.asyncio +async def test_async_log_failure_event_works_without_standard_logging_object(): + """ + Test that async_log_failure_event() still logs to Langfuse even when + standard_logging_object is None (e.g. when get_standard_logging_object_payload + threw an exception). This is the critical fix — before, it silently returned. + """ + from litellm.integrations.langfuse.langfuse_prompt_management import ( + LangfusePromptManagement, + ) + + mock_langfuse_module = MagicMock() + mock_langfuse_module.version.__version__ = "3.0.0" + + with patch.dict( + "os.environ", + { + "LANGFUSE_SECRET_KEY": "test-secret", + "LANGFUSE_PUBLIC_KEY": "test-public", + "LANGFUSE_HOST": "https://test.langfuse.com", + }, + ), patch.dict("sys.modules", {"langfuse": mock_langfuse_module}): + prompt_mgmt = LangfusePromptManagement() + + mock_logger = MagicMock() + mock_logger.log_event_on_langfuse.return_value = { + "trace_id": "mock-trace", + "generation_id": "mock-gen", + } + + with patch( + "litellm.integrations.langfuse.langfuse_prompt_management.LangFuseHandler" + ) as mock_handler: + mock_handler.get_langfuse_logger_for_request.return_value = mock_logger + + kwargs = { + "litellm_params": { + "metadata": {"session_id": "test-session-no-slo"}, + }, + "litellm_call_id": "call-no-slo-456", + "user": "test-user", + "exception": Exception("InternalServerError: something broke"), + "standard_logging_object": None, # This is the key — it's None + } + + await prompt_mgmt.async_log_failure_event( + kwargs=kwargs, + response_obj=None, + start_time=datetime.datetime.utcnow(), + end_time=datetime.datetime.utcnow(), + ) + + # CRITICAL: log_event_on_langfuse MUST still be called + assert mock_logger.log_event_on_langfuse.called, ( + "log_event_on_langfuse was NOT called when standard_logging_object " + "is None — failure trace would be silently dropped" + ) + call_kwargs = mock_logger.log_event_on_langfuse.call_args[1] + assert call_kwargs["level"] == "ERROR" + # Falls back to exception from kwargs + assert "InternalServerError" in call_kwargs["status_message"] + + def test_max_langfuse_clients_limit(): """ Test that the max langfuse clients limit is respected when initializing multiple clients From cac041c9447a798fe611ef4f433142ed90c63cbc Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Mon, 2 Mar 2026 20:55:31 +0530 Subject: [PATCH 006/289] Align Langfuse trace_id fallback with DB session_id for failed requests When standard_logging_object is None (failure case), Langfuse was falling back to litellm_call_id while the DB used litellm_trace_id as session_id. This caused the Session ID in LiteLLM logs to not match the trace in Langfuse. Now Langfuse checks litellm_trace_id first, matching the DB. Co-Authored-By: Claude Opus 4.6 --- litellm/integrations/langfuse/langfuse.py | 5 +- .../integrations/test_langfuse.py | 73 +++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/litellm/integrations/langfuse/langfuse.py b/litellm/integrations/langfuse/langfuse.py index 7bf97665fd..afad3f5094 100644 --- a/litellm/integrations/langfuse/langfuse.py +++ b/litellm/integrations/langfuse/langfuse.py @@ -610,9 +610,10 @@ class LangFuseLogger: trace_id = cast( Optional[str], standard_logging_object.get("trace_id") ) - # Fallback to litellm_call_id if no trace_id found + # Fallback: use litellm_trace_id from kwargs (matches DB session_id), + # then litellm_call_id as last resort if trace_id is None: - trace_id = litellm_call_id + trace_id = kwargs.get("litellm_trace_id") or litellm_call_id existing_trace_id = clean_metadata.pop("existing_trace_id", None) # If existing_trace_id is provided, use it as the trace_id to return # This allows continuing an existing trace while still returning the correct trace_id diff --git a/tests/test_litellm/integrations/test_langfuse.py b/tests/test_litellm/integrations/test_langfuse.py index 084fd7d048..b402870921 100644 --- a/tests/test_litellm/integrations/test_langfuse.py +++ b/tests/test_litellm/integrations/test_langfuse.py @@ -467,6 +467,79 @@ class TestLangfuseUsageDetails(unittest.TestCase): assert self.last_trace_kwargs.get("id") == "call-id-xyz" + def test_log_langfuse_v2_uses_litellm_trace_id_fallback_over_call_id(self): + """ + When standard_logging_object has no trace_id, but kwargs contains + litellm_trace_id (the same ID the DB stores as Session ID), Langfuse + should use litellm_trace_id — NOT litellm_call_id. This ensures the + trace_id in Langfuse matches the Session ID shown in LiteLLM logs. + """ + payload = self._build_standard_logging_payload() # no trace_id + kwargs = self._build_langfuse_kwargs(payload) + kwargs["litellm_trace_id"] = "trace-id-from-kwargs" + self.last_trace_kwargs = {} + + with patch( + "litellm.integrations.langfuse.langfuse._add_prompt_to_generation_params", + side_effect=lambda generation_params, **kwargs: generation_params, + create=True, + ): + self.logger._log_langfuse_v2( + user_id="user-1", + metadata={}, + litellm_params={"metadata": {}}, + output=None, + start_time=datetime.datetime.utcnow(), + end_time=datetime.datetime.utcnow(), + kwargs=kwargs, + optional_params={}, + input=None, + response_obj=None, + level="ERROR", + litellm_call_id="call-id-xyz", + ) + + # litellm_trace_id should be preferred over litellm_call_id + assert self.last_trace_kwargs.get("id") == "trace-id-from-kwargs" + + def test_log_langfuse_v2_uses_litellm_trace_id_when_standard_logging_object_none(self): + """ + When standard_logging_object is None (failure case where + get_standard_logging_object_payload threw), litellm_trace_id from kwargs + should be used as the Langfuse trace_id. This matches the DB Session ID. + """ + kwargs = { + "standard_logging_object": None, + "model": "gpt-4", + "call_type": "completion", + "cache_hit": False, + "messages": [], + "litellm_trace_id": "trace-id-failure", + } + self.last_trace_kwargs = {} + + with patch( + "litellm.integrations.langfuse.langfuse._add_prompt_to_generation_params", + side_effect=lambda generation_params, **kwargs: generation_params, + create=True, + ): + self.logger._log_langfuse_v2( + user_id="user-1", + metadata={}, + litellm_params={"metadata": {}}, + output=None, + start_time=datetime.datetime.utcnow(), + end_time=datetime.datetime.utcnow(), + kwargs=kwargs, + optional_params={}, + input=None, + response_obj=None, + level="ERROR", + litellm_call_id="call-id-different", + ) + + # Must use litellm_trace_id, not litellm_call_id + assert self.last_trace_kwargs.get("id") == "trace-id-failure" def test_log_langfuse_v2_session_id_passed_as_trace_session_id(self): """ From 2f927fef3bcf662e221bb3b9b8cf8147291d4e6e Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Mon, 2 Mar 2026 21:15:52 +0530 Subject: [PATCH 007/289] Fix root cause: model_call_details stored None for litellm_trace_id Logging.__init__ stored the raw litellm_trace_id parameter (None when not explicitly provided) in model_call_details, while self.litellm_trace_id always held a valid UUID. When get_standard_logging_object_payload() failed, both the DB and Langfuse fell back to kwargs["litellm_trace_id"] which was None, causing each to generate different random UUIDs. Now model_call_details stores self.litellm_trace_id (always valid), so all fallback paths use the same ID. Co-Authored-By: Claude Opus 4.6 --- litellm/litellm_core_utils/litellm_logging.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index d5419c9868..73512f7a12 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -405,7 +405,7 @@ class Logging(LiteLLMLoggingBaseClass): self.passthrough_guardrails_config: Optional[Dict[str, Any]] = None self.model_call_details: Dict[str, Any] = { - "litellm_trace_id": litellm_trace_id, + "litellm_trace_id": self.litellm_trace_id, "litellm_call_id": litellm_call_id, "input": _input, "litellm_params": litellm_params, From 46c4d5b37dac5577a860c434900fd79985e6c3cf Mon Sep 17 00:00:00 2001 From: Harshit Jain <48647625+Harshit28j@users.noreply.github.com> Date: Mon, 2 Mar 2026 21:28:36 +0530 Subject: [PATCH 008/289] Update litellm/integrations/langfuse/langfuse_prompt_management.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- litellm/integrations/langfuse/langfuse_prompt_management.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litellm/integrations/langfuse/langfuse_prompt_management.py b/litellm/integrations/langfuse/langfuse_prompt_management.py index d3de59c8e6..8b0c64d563 100644 --- a/litellm/integrations/langfuse/langfuse_prompt_management.py +++ b/litellm/integrations/langfuse/langfuse_prompt_management.py @@ -341,8 +341,8 @@ class LangfusePromptManagement(LangFuseLogger, PromptManagementBase, CustomLogge status_message = str(kwargs.get("exception", "Unknown error")) if standard_logging_object is not None: status_message = standard_logging_object.get( - "error_str", status_message - ) + "error_str", None + ) or status_message langfuse_logger_to_use.log_event_on_langfuse( start_time=start_time, end_time=end_time, From 338a634762d7dac2801a169dae7dbe9c7098aa3b Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Mon, 2 Mar 2026 21:31:35 +0530 Subject: [PATCH 009/289] Fix root cause: DB spend log session_id didn't match Langfuse trace_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The proxy has two separate failure paths: 1. async_failure_handler → Langfuse callback (uses model_call_details with standard_logging_object containing the correct trace_id) 2. post_call_failure_hook → _ProxyDBLogger → spend log (uses request_data which did NOT have standard_logging_object, so session_id fell to random uuid4()) These two paths used different data dicts, so the DB session_id was a random UUID unrelated to the Langfuse trace_id. Users could not search by the Session ID from LiteLLM logs in Langfuse for failed requests. Fix: In _ProxyDBLogger.async_post_call_failure_hook, propagate standard_logging_object and litellm_trace_id from the litellm_logging_obj (already present in request_data) before writing the spend log. Co-Authored-By: Claude Opus 4.6 --- .../proxy/hooks/proxy_track_cost_callback.py | 16 +++++ .../hooks/test_proxy_track_cost_callback.py | 62 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/litellm/proxy/hooks/proxy_track_cost_callback.py b/litellm/proxy/hooks/proxy_track_cost_callback.py index 0734756d8e..9a806fa4f8 100644 --- a/litellm/proxy/hooks/proxy_track_cost_callback.py +++ b/litellm/proxy/hooks/proxy_track_cost_callback.py @@ -110,6 +110,22 @@ class _ProxyDBLogger(CustomLogger): "custom_llm_provider" ) or request_data.get("custom_llm_provider", "") + # Propagate standard_logging_object and litellm_trace_id from the + # Logging instance so that _get_session_id_for_spend_log uses the same + # trace_id that Langfuse received (via async_failure_handler). + # Without this, the DB session_id would be a random UUID that doesn't + # match the Langfuse trace_id, making failed requests unsearchable. + _litellm_logging_obj = request_data.get("litellm_logging_obj") + if _litellm_logging_obj is not None: + if "standard_logging_object" not in request_data: + request_data["standard_logging_object"] = getattr( + _litellm_logging_obj, "model_call_details", {} + ).get("standard_logging_object") + if request_data.get("litellm_trace_id") is None: + request_data["litellm_trace_id"] = getattr( + _litellm_logging_obj, "litellm_trace_id", None + ) + await proxy_logging_obj.db_spend_update_writer.update_database( token=user_api_key_dict.api_key, response_cost=0.0, diff --git a/tests/test_litellm/proxy/hooks/test_proxy_track_cost_callback.py b/tests/test_litellm/proxy/hooks/test_proxy_track_cost_callback.py index c46b8df5ef..d269a9531f 100644 --- a/tests/test_litellm/proxy/hooks/test_proxy_track_cost_callback.py +++ b/tests/test_litellm/proxy/hooks/test_proxy_track_cost_callback.py @@ -169,6 +169,68 @@ async def test_track_cost_callback_skips_when_no_standard_logging_object(): mock_proxy_logging.failed_tracking_alert.assert_not_called() +@pytest.mark.asyncio +async def test_async_post_call_failure_hook_propagates_trace_id_from_logging_obj(): + """ + When an LLM call fails, the proxy calls post_call_failure_hook with + request_data that doesn't contain standard_logging_object. But the + litellm_logging_obj (set by function_setup) is in request_data and + holds the standard_logging_object with the correct trace_id. + + The failure hook should propagate this so the DB spend log's session_id + matches the Langfuse trace_id. + """ + logger = _ProxyDBLogger() + + user_api_key_dict = UserAPIKeyAuth( + api_key="test_api_key", + user_id="test_user_id", + team_id="test_team_id", + ) + + # Simulate a litellm_logging_obj with model_call_details containing + # the standard_logging_object (as set by _failure_handler_helper_fn) + mock_logging_obj = MagicMock() + mock_logging_obj.litellm_trace_id = "trace-id-from-logging-obj" + mock_logging_obj.model_call_details = { + "standard_logging_object": { + "trace_id": "trace-id-from-logging-obj", + "error_str": "InternalServerError", + } + } + + request_data = { + "model": "gpt-4", + "messages": [{"role": "user", "content": "Hello"}], + "metadata": {}, + "litellm_params": {}, + "litellm_logging_obj": mock_logging_obj, + # Note: no "standard_logging_object" and no "litellm_trace_id" + } + + with patch( + "litellm.proxy.db.db_spend_update_writer.DBSpendUpdateWriter.update_database", + new_callable=AsyncMock, + ) as mock_update_database: + await logger.async_post_call_failure_hook( + request_data=request_data, + original_exception=Exception("Provider error"), + user_api_key_dict=user_api_key_dict, + ) + + mock_update_database.assert_called_once() + call_kwargs = mock_update_database.call_args[1]["kwargs"] + + # standard_logging_object should have been propagated from logging obj + assert call_kwargs.get("standard_logging_object") is not None + assert ( + call_kwargs["standard_logging_object"]["trace_id"] + == "trace-id-from-logging-obj" + ) + # litellm_trace_id should also be propagated as a fallback + assert call_kwargs.get("litellm_trace_id") == "trace-id-from-logging-obj" + + @pytest.mark.asyncio async def test_enrich_failure_metadata_with_team_alias(): """ From fb69de98e5fe3552fc3d9c53a7a17b4fff781b25 Mon Sep 17 00:00:00 2001 From: Harshit Jain <48647625+Harshit28j@users.noreply.github.com> Date: Tue, 3 Mar 2026 00:33:22 +0530 Subject: [PATCH 010/289] Update litellm/proxy/hooks/proxy_track_cost_callback.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- litellm/proxy/hooks/proxy_track_cost_callback.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litellm/proxy/hooks/proxy_track_cost_callback.py b/litellm/proxy/hooks/proxy_track_cost_callback.py index 9a806fa4f8..8cddaed5be 100644 --- a/litellm/proxy/hooks/proxy_track_cost_callback.py +++ b/litellm/proxy/hooks/proxy_track_cost_callback.py @@ -117,7 +117,7 @@ class _ProxyDBLogger(CustomLogger): # match the Langfuse trace_id, making failed requests unsearchable. _litellm_logging_obj = request_data.get("litellm_logging_obj") if _litellm_logging_obj is not None: - if "standard_logging_object" not in request_data: + if not request_data.get("standard_logging_object"): request_data["standard_logging_object"] = getattr( _litellm_logging_obj, "model_call_details", {} ).get("standard_logging_object") From 20bf3aa8070a4dc150bb8edaddb6bd3306b83a53 Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Tue, 10 Mar 2026 17:16:46 +0530 Subject: [PATCH 011/289] fix: pop sensitive keys from langfuse --- litellm/litellm_core_utils/litellm_logging.py | 50 +++++++++---------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index e450b233c7..73a8b92c1b 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -1653,9 +1653,7 @@ class Logging(LiteLLMLoggingBaseClass): self.model_call_details[ "standard_logging_object" - ] = self._build_standard_logging_payload( - logging_result, start_time, end_time - ) + ] = self._build_standard_logging_payload(logging_result, start_time, end_time) if ( standard_logging_payload := self.model_call_details.get( @@ -2518,9 +2516,7 @@ class Logging(LiteLLMLoggingBaseClass): ## STANDARDIZED LOGGING PAYLOAD self.model_call_details[ "standard_logging_object" - ] = self._build_standard_logging_payload( - result, start_time, end_time - ) + ] = self._build_standard_logging_payload(result, start_time, end_time) # print standard logging payload if ( @@ -4195,8 +4191,7 @@ def _maybe_auto_initialize_arize_phoenix(_in_memory_loggers: list) -> None: litellm.logging_callback_manager.add_litellm_callback(phoenix_logger) verbose_logger.info( - "Auto-initialized Arize Phoenix logger alongside otel " - "(endpoint=%s)", + "Auto-initialized Arize Phoenix logger alongside otel " "(endpoint=%s)", arize_phoenix_config.endpoint, ) except Exception as e: @@ -4755,9 +4750,11 @@ class StandardLoggingPayloadSetup: ).model_dump() if isinstance(_raw, dict): if ResponseAPILoggingUtils._is_response_api_usage(_raw): - return ResponseAPILoggingUtils._transform_response_api_usage_to_chat_usage( - _raw - ).model_dump() + return ( + ResponseAPILoggingUtils._transform_response_api_usage_to_chat_usage( + _raw + ).model_dump() + ) return _raw if isinstance(_raw, Usage): return _raw.model_dump() @@ -5482,21 +5479,23 @@ def scrub_sensitive_keys_in_metadata(litellm_params: Optional[dict]): litellm_params["_langfuse_masking_function"] = masking_fn litellm_params["metadata"] = metadata - ## check user_api_key_metadata for sensitive logging keys - cleaned_user_api_key_metadata = {} - if "user_api_key_metadata" in metadata and isinstance( - metadata["user_api_key_metadata"], dict - ): - for k, v in metadata["user_api_key_metadata"].items(): - if k == "logging": # prevent logging user logging keys - cleaned_user_api_key_metadata[ - k - ] = "scrubbed_by_litellm_for_sensitive_keys" - else: - cleaned_user_api_key_metadata[k] = v + ## remove sensitive logging/callback keys from metadata dicts + ## these contain credentials (langfuse_secret_key, langfuse_public_key, etc.) + _sensitive_keys = {"logging", "callback_settings"} - metadata["user_api_key_metadata"] = cleaned_user_api_key_metadata - litellm_params["metadata"] = metadata + for metadata_field in ( + "user_api_key_metadata", + "user_api_key_auth_metadata", + "user_api_key_team_metadata", + ): + if metadata_field in metadata and isinstance(metadata[metadata_field], dict): + for sensitive_key in _sensitive_keys: + metadata[metadata_field].pop(sensitive_key, None) + + ## remove user_api_key_auth entirely - contains full auth object with nested credentials + metadata.pop("user_api_key_auth", None) + + litellm_params["metadata"] = metadata return litellm_params @@ -5603,4 +5602,3 @@ def create_dummy_standard_logging_payload() -> StandardLoggingPayload: model_parameters={"stream": True}, hidden_params=hidden_params, ) - From 69a94a873c1a7f286b3e1249348b92046702c410 Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 13:51:36 +0530 Subject: [PATCH 012/289] Add Vantage integration for FOCUS CSV export Adds a pluggable Vantage destination to the existing FOCUS export pipeline, enabling LiteLLM to export spend data in FOCUS format directly to Vantage's cost-import API. Supports automatic hourly exports via scheduled background job, with admin API endpoints for manual control and configuration. Includes CSV serializer, batching for 10K row / 2MB API limits, and enriched Tags JSON with team/user/key metadata for Vantage Token Allocation feature. - Add CSV serializer (FocusCsvSerializer) for FOCUS data - Add Vantage API destination with automatic batching - Add VantageLogger that wraps FocusLogger with Vantage defaults - Add proxy endpoints: /vantage/{init,settings,export,dry-run,delete} - Register "vantage" callback in logger registry and literal type - Wire up background job in proxy_server.py startup - Populate Tags column with JSON metadata (team_id, user_id, user_email, etc.) - Add 14 unit tests covering serializer, destination, and factory All tests pass (23 focus tests total, no regressions). Co-Authored-By: Claude Haiku 4.5 --- litellm/__init__.py | 1 + .../focus/destinations/__init__.py | 2 + .../focus/destinations/factory.py | 21 + .../focus/destinations/vantage_destination.py | 136 +++++ litellm/integrations/focus/export_engine.py | 12 +- litellm/integrations/focus/schema.py | 2 +- .../focus/serializers/__init__.py | 3 +- litellm/integrations/focus/serializers/csv.py | 22 + litellm/integrations/focus/transformer.py | 40 +- litellm/integrations/vantage/__init__.py | 0 .../integrations/vantage/vantage_logger.py | 105 ++++ .../custom_logger_registry.py | 2 + litellm/proxy/proxy_server.py | 11 + .../proxy/spend_tracking/vantage_endpoints.py | 488 ++++++++++++++++++ litellm/types/proxy/vantage_endpoints.py | 81 +++ .../integrations/focus/test_csv_serializer.py | 34 ++ .../focus/test_destination_factory.py | 48 ++ .../focus/test_vantage_destination.py | 138 +++++ 18 files changed, 1139 insertions(+), 7 deletions(-) create mode 100644 litellm/integrations/focus/destinations/vantage_destination.py create mode 100644 litellm/integrations/focus/serializers/csv.py create mode 100644 litellm/integrations/vantage/__init__.py create mode 100644 litellm/integrations/vantage/vantage_logger.py create mode 100644 litellm/proxy/spend_tracking/vantage_endpoints.py create mode 100644 litellm/types/proxy/vantage_endpoints.py create mode 100644 tests/test_litellm/integrations/focus/test_csv_serializer.py create mode 100644 tests/test_litellm/integrations/focus/test_destination_factory.py create mode 100644 tests/test_litellm/integrations/focus/test_vantage_destination.py diff --git a/litellm/__init__.py b/litellm/__init__.py index 4fc71e1270..2334858a05 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -143,6 +143,7 @@ _custom_logger_compatible_callbacks_literal = Literal[ "gitlab", "cloudzero", "focus", + "vantage", "posthog", "levo", ] diff --git a/litellm/integrations/focus/destinations/__init__.py b/litellm/integrations/focus/destinations/__init__.py index 233f1da0c9..775d3a259d 100644 --- a/litellm/integrations/focus/destinations/__init__.py +++ b/litellm/integrations/focus/destinations/__init__.py @@ -3,10 +3,12 @@ from .base import FocusDestination, FocusTimeWindow from .factory import FocusDestinationFactory from .s3_destination import FocusS3Destination +from .vantage_destination import FocusVantageDestination __all__ = [ "FocusDestination", "FocusDestinationFactory", "FocusTimeWindow", "FocusS3Destination", + "FocusVantageDestination", ] diff --git a/litellm/integrations/focus/destinations/factory.py b/litellm/integrations/focus/destinations/factory.py index cb7696a11d..01ea6ca9cb 100644 --- a/litellm/integrations/focus/destinations/factory.py +++ b/litellm/integrations/focus/destinations/factory.py @@ -7,6 +7,7 @@ from typing import Any, Dict, Optional from .base import FocusDestination from .s3_destination import FocusS3Destination +from .vantage_destination import FocusVantageDestination class FocusDestinationFactory: @@ -26,6 +27,8 @@ class FocusDestinationFactory: ) if provider_lower == "s3": return FocusS3Destination(prefix=prefix, config=normalized_config) + if provider_lower == "vantage": + return FocusVantageDestination(prefix=prefix, config=normalized_config) raise NotImplementedError( f"Provider '{provider}' not supported for Focus export" ) @@ -54,6 +57,24 @@ class FocusDestinationFactory: if not resolved.get("bucket_name"): raise ValueError("FOCUS_S3_BUCKET_NAME must be provided for S3 exports") return {k: v for k, v in resolved.items() if v is not None} + if provider == "vantage": + resolved = { + "api_key": overrides.get("api_key") + or os.getenv("VANTAGE_API_KEY"), + "integration_token": overrides.get("integration_token") + or os.getenv("VANTAGE_INTEGRATION_TOKEN"), + "base_url": overrides.get("base_url") + or os.getenv("VANTAGE_BASE_URL", "https://api.vantage.sh"), + } + if not resolved.get("api_key"): + raise ValueError( + "VANTAGE_API_KEY must be provided for Vantage exports" + ) + if not resolved.get("integration_token"): + raise ValueError( + "VANTAGE_INTEGRATION_TOKEN must be provided for Vantage exports" + ) + return {k: v for k, v in resolved.items() if v is not None} raise NotImplementedError( f"Provider '{provider}' not supported for Focus export configuration" ) diff --git a/litellm/integrations/focus/destinations/vantage_destination.py b/litellm/integrations/focus/destinations/vantage_destination.py new file mode 100644 index 0000000000..5612a513d6 --- /dev/null +++ b/litellm/integrations/focus/destinations/vantage_destination.py @@ -0,0 +1,136 @@ +"""Vantage API destination for Focus export.""" + +from __future__ import annotations + +from typing import Any, Optional + +import httpx + +from litellm._logging import verbose_logger + +from .base import FocusDestination, FocusTimeWindow + +# Vantage enforces a 10,000-row / 2 MB limit per upload. +VANTAGE_MAX_ROWS_PER_UPLOAD = 10_000 +VANTAGE_MAX_BYTES_PER_UPLOAD = 2 * 1024 * 1024 # 2 MB + + +class FocusVantageDestination(FocusDestination): + """Upload FOCUS CSV exports to the Vantage cost-import API.""" + + def __init__( + self, + *, + prefix: str, + config: Optional[dict[str, Any]] = None, + ) -> None: + config = config or {} + api_key = config.get("api_key") + integration_token = config.get("integration_token") + if not api_key: + raise ValueError( + "api_key must be provided for Vantage destination " + "(set VANTAGE_API_KEY env var or pass in destination_config)" + ) + if not integration_token: + raise ValueError( + "integration_token must be provided for Vantage destination " + "(set VANTAGE_INTEGRATION_TOKEN env var or pass in destination_config)" + ) + self.api_key = api_key + self.integration_token = integration_token + self.base_url = config.get( + "base_url", "https://api.vantage.sh" + ) + self.prefix = prefix + + async def deliver( + self, + *, + content: bytes, + time_window: FocusTimeWindow, + filename: str, + ) -> None: + """Upload CSV content to the Vantage API, batching if needed.""" + if not content: + verbose_logger.debug("Vantage destination: empty content, skipping upload") + return + + # If the payload is within limits, send in one shot + if len(content) <= VANTAGE_MAX_BYTES_PER_UPLOAD: + await self._upload_csv(content, filename) + return + + # Otherwise split into chunks by line count + await self._upload_batched(content, filename) + + async def _upload_csv(self, csv_bytes: bytes, filename: str) -> None: + url = ( + f"{self.base_url}/v2/integrations/" + f"{self.integration_token}/costs.csv" + ) + headers = { + "Authorization": f"Bearer {self.api_key}", + } + + async with httpx.AsyncClient(timeout=60.0) as client: + response = await client.post( + url, + headers=headers, + files={"file": (filename, csv_bytes, "text/csv")}, + ) + response.raise_for_status() + + verbose_logger.debug( + "Vantage destination: uploaded %d bytes (%s)", + len(csv_bytes), + filename, + ) + + async def _upload_batched(self, csv_bytes: bytes, filename: str) -> None: + """Split the CSV into batches and upload each.""" + lines = csv_bytes.split(b"\n") + header = lines[0] + data_lines = [line for line in lines[1:] if line.strip()] + + batch_num = 0 + for start in range(0, len(data_lines), VANTAGE_MAX_ROWS_PER_UPLOAD): + batch_lines = data_lines[start : start + VANTAGE_MAX_ROWS_PER_UPLOAD] + batch_csv = header + b"\n" + b"\n".join(batch_lines) + b"\n" + + # If a single batch still exceeds 2 MB, split further by size + if len(batch_csv) > VANTAGE_MAX_BYTES_PER_UPLOAD: + await self._upload_size_limited(header, batch_lines, filename, batch_num) + else: + batch_filename = f"{filename}.part{batch_num}" if batch_num > 0 else filename + await self._upload_csv(batch_csv, batch_filename) + batch_num += 1 + + async def _upload_size_limited( + self, + header: bytes, + data_lines: list[bytes], + filename: str, + batch_offset: int, + ) -> None: + """Upload lines in chunks that stay under the 2 MB size limit.""" + current_chunk: list[bytes] = [] + current_size = len(header) + 1 # header + newline + sub_batch = 0 + + for line in data_lines: + line_size = len(line) + 1 # line + newline + if current_size + line_size > VANTAGE_MAX_BYTES_PER_UPLOAD and current_chunk: + batch_csv = header + b"\n" + b"\n".join(current_chunk) + b"\n" + batch_filename = f"{filename}.part{batch_offset}_{sub_batch}" + await self._upload_csv(batch_csv, batch_filename) + current_chunk = [] + current_size = len(header) + 1 + sub_batch += 1 + current_chunk.append(line) + current_size += line_size + + if current_chunk: + batch_csv = header + b"\n" + b"\n".join(current_chunk) + b"\n" + batch_filename = f"{filename}.part{batch_offset}_{sub_batch}" + await self._upload_csv(batch_csv, batch_filename) diff --git a/litellm/integrations/focus/export_engine.py b/litellm/integrations/focus/export_engine.py index 22ebce2a16..a9361d0e98 100644 --- a/litellm/integrations/focus/export_engine.py +++ b/litellm/integrations/focus/export_engine.py @@ -10,7 +10,7 @@ from litellm._logging import verbose_logger from .database import FocusLiteLLMDatabase from .destinations import FocusDestinationFactory, FocusTimeWindow -from .serializers import FocusParquetSerializer, FocusSerializer +from .serializers import FocusCsvSerializer, FocusParquetSerializer, FocusSerializer from .transformer import FocusTransformer @@ -38,9 +38,13 @@ class FocusExportEngine: self._database = FocusLiteLLMDatabase() def _init_serializer(self) -> FocusSerializer: - if self.export_format != "parquet": - raise NotImplementedError("Only parquet export supported currently") - return FocusParquetSerializer() + if self.export_format == "csv": + return FocusCsvSerializer() + if self.export_format == "parquet": + return FocusParquetSerializer() + raise NotImplementedError( + f"Export format '{self.export_format}' not supported. Use 'parquet' or 'csv'." + ) async def dry_run_export_usage_data(self, limit: Optional[int]) -> Dict[str, Any]: data = await self._database.get_usage_data(limit=limit) diff --git a/litellm/integrations/focus/schema.py b/litellm/integrations/focus/schema.py index ac2f33dad0..6ad725f367 100644 --- a/litellm/integrations/focus/schema.py +++ b/litellm/integrations/focus/schema.py @@ -43,7 +43,7 @@ FOCUS_NORMALIZED_SCHEMA = pl.Schema( ("SubAccountId", pl.String), ("SubAccountName", pl.String), ("SubAccountType", pl.String), - ("Tags", pl.Object), + ("Tags", pl.String), ] ) diff --git a/litellm/integrations/focus/serializers/__init__.py b/litellm/integrations/focus/serializers/__init__.py index 18187bf73e..bdbf520454 100644 --- a/litellm/integrations/focus/serializers/__init__.py +++ b/litellm/integrations/focus/serializers/__init__.py @@ -1,6 +1,7 @@ """Serializer package exports for Focus integration.""" from .base import FocusSerializer +from .csv import FocusCsvSerializer from .parquet import FocusParquetSerializer -__all__ = ["FocusSerializer", "FocusParquetSerializer"] +__all__ = ["FocusSerializer", "FocusCsvSerializer", "FocusParquetSerializer"] diff --git a/litellm/integrations/focus/serializers/csv.py b/litellm/integrations/focus/serializers/csv.py new file mode 100644 index 0000000000..30e7f3283d --- /dev/null +++ b/litellm/integrations/focus/serializers/csv.py @@ -0,0 +1,22 @@ +"""CSV serializer for Focus export.""" + +from __future__ import annotations + +import io + +import polars as pl + +from .base import FocusSerializer + + +class FocusCsvSerializer(FocusSerializer): + """Serialize normalized Focus frames to CSV bytes.""" + + extension = "csv" + + def serialize(self, frame: pl.DataFrame) -> bytes: + """Encode the provided frame as a CSV payload.""" + target = frame if not frame.is_empty() else pl.DataFrame(schema=frame.schema) + buffer = io.BytesIO() + target.write_csv(buffer) + return buffer.getvalue() diff --git a/litellm/integrations/focus/transformer.py b/litellm/integrations/focus/transformer.py index cac12b7be1..1e4a17796d 100644 --- a/litellm/integrations/focus/transformer.py +++ b/litellm/integrations/focus/transformer.py @@ -2,6 +2,7 @@ from __future__ import annotations +import json from datetime import timedelta import polars as pl @@ -9,6 +10,29 @@ import polars as pl from .schema import FOCUS_NORMALIZED_SCHEMA +def _build_tags_json(row: dict) -> str: + """Build a JSON string of metadata tags from a DB row. + + Vantage uses this for Token Allocation — enriching billing data with + team, user, and API key metadata. + """ + tags: dict[str, str] = {} + for key in ( + "team_id", + "team_alias", + "user_id", + "user_email", + "api_key_alias", + "model", + "model_group", + "custom_llm_provider", + ): + val = row.get(key) + if val is not None: + tags[key] = str(val) + return json.dumps(tags) if tags else "{}" + + class FocusTransformer: """Transforms LiteLLM DB rows into Focus-compatible schema.""" @@ -19,6 +43,20 @@ class FocusTransformer: if frame.is_empty(): return pl.DataFrame(schema=self.schema) + # Build Tags JSON from metadata columns + tag_col = "Tags" + tag_keys = [ + "team_id", "team_alias", "user_id", "user_email", + "api_key_alias", "model", "model_group", "custom_llm_provider", + ] + available_keys = [k for k in tag_keys if k in frame.columns] + if available_keys: + tags_series = frame.select(available_keys).to_dicts() + tags_json = [_build_tags_json(row) for row in tags_series] + frame = frame.with_columns(pl.Series(tag_col, tags_json)) + else: + frame = frame.with_columns(pl.lit("{}").alias(tag_col)) + # derive period start/end from usage date frame = frame.with_columns( pl.col("date") @@ -86,5 +124,5 @@ class FocusTransformer: pl.col("team_id").cast(pl.String).alias("SubAccountId"), pl.col("team_alias").cast(pl.String).alias("SubAccountName"), none_str.alias("SubAccountType"), - none_str.alias("Tags"), + pl.col(tag_col).cast(pl.String).alias("Tags"), ) diff --git a/litellm/integrations/vantage/__init__.py b/litellm/integrations/vantage/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/litellm/integrations/vantage/vantage_logger.py b/litellm/integrations/vantage/vantage_logger.py new file mode 100644 index 0000000000..01529d537f --- /dev/null +++ b/litellm/integrations/vantage/vantage_logger.py @@ -0,0 +1,105 @@ +"""Vantage logger — thin wrapper around the Focus export pipeline. + +Configures FocusLogger to use the Vantage API destination with CSV format +so users can simply set ``success_callback: ["vantage"]`` in their proxy config. +""" + +from __future__ import annotations + +import os +from typing import TYPE_CHECKING, Any, Dict, List, Optional, cast + +import litellm +from litellm._logging import verbose_logger +from litellm.integrations.custom_logger import CustomLogger +from litellm.integrations.focus.focus_logger import FocusLogger + +if TYPE_CHECKING: + from apscheduler.schedulers.asyncio import AsyncIOScheduler +else: + AsyncIOScheduler = Any + +VANTAGE_USAGE_DATA_JOB_NAME = "vantage_export_usage_data" + + +class VantageLogger(FocusLogger): + """FocusLogger pre-configured for Vantage (CSV format, Vantage API destination). + + Environment Variables: + VANTAGE_API_KEY: Vantage API key for authentication + VANTAGE_INTEGRATION_TOKEN: Vantage integration token for the cost-import endpoint + VANTAGE_BASE_URL: Optional base URL override (default: https://api.vantage.sh) + VANTAGE_EXPORT_FREQUENCY: Export frequency — "hourly" (default), "daily", or "interval" + VANTAGE_EXPORT_INTERVAL_SECONDS: Interval in seconds when frequency is "interval" + """ + + def __init__( + self, + *, + api_key: Optional[str] = None, + integration_token: Optional[str] = None, + base_url: Optional[str] = None, + frequency: Optional[str] = None, + interval_seconds: Optional[int] = None, + **kwargs: Any, + ) -> None: + resolved_api_key = api_key or os.getenv("VANTAGE_API_KEY") + resolved_token = integration_token or os.getenv("VANTAGE_INTEGRATION_TOKEN") + resolved_base_url = base_url or os.getenv( + "VANTAGE_BASE_URL", "https://api.vantage.sh" + ) + resolved_frequency = ( + frequency or os.getenv("VANTAGE_EXPORT_FREQUENCY") or "hourly" + ).lower() + + raw_interval = interval_seconds or os.getenv("VANTAGE_EXPORT_INTERVAL_SECONDS") + resolved_interval = int(raw_interval) if raw_interval is not None else None + + destination_config: Dict[str, Any] = {} + if resolved_api_key: + destination_config["api_key"] = resolved_api_key + if resolved_token: + destination_config["integration_token"] = resolved_token + if resolved_base_url: + destination_config["base_url"] = resolved_base_url + + super().__init__( + provider="vantage", + export_format="csv", + frequency=resolved_frequency, + interval_seconds=resolved_interval, + prefix="vantage_exports", + destination_config=destination_config, + **kwargs, + ) + + verbose_logger.debug( + "VantageLogger initialized (integration_token=%s)", + resolved_token[:8] + "..." if resolved_token else "None", + ) + + @staticmethod + async def init_vantage_background_job( + scheduler: AsyncIOScheduler, + ) -> None: + """Register the Vantage export job with the provided scheduler.""" + vantage_loggers: List[ + CustomLogger + ] = litellm.logging_callback_manager.get_custom_loggers_for_type( + callback_type=VantageLogger + ) + if not vantage_loggers: + verbose_logger.debug( + "No Vantage logger registered; skipping scheduler" + ) + return + + vantage_logger = cast(VantageLogger, vantage_loggers[0]) + trigger_kwargs = vantage_logger._build_scheduler_trigger() + scheduler.add_job( + vantage_logger.initialize_focus_export_job, + **trigger_kwargs, + ) + + +__all__ = ["VantageLogger"] diff --git a/litellm/litellm_core_utils/custom_logger_registry.py b/litellm/litellm_core_utils/custom_logger_registry.py index 2d483f7861..f873bfeece 100644 --- a/litellm/litellm_core_utils/custom_logger_registry.py +++ b/litellm/litellm_core_utils/custom_logger_registry.py @@ -24,6 +24,7 @@ from litellm.integrations.datadog.datadog_metrics import DatadogMetricsLogger from litellm.integrations.deepeval import DeepEvalLogger from litellm.integrations.dotprompt import DotpromptManager from litellm.integrations.focus.focus_logger import FocusLogger +from litellm.integrations.vantage.vantage_logger import VantageLogger from litellm.integrations.galileo import GalileoObserve from litellm.integrations.gcs_bucket.gcs_bucket import GCSBucketLogger from litellm.integrations.gcs_pubsub.pub_sub import GcsPubSubLogger @@ -99,6 +100,7 @@ class CustomLoggerRegistry: "gitlab": GitLabPromptManager, "cloudzero": CloudZeroLogger, "focus": FocusLogger, + "vantage": VantageLogger, "posthog": PostHogLogger, } diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index f3bc4b0803..91196ce5b9 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -473,6 +473,7 @@ from litellm.proxy.search_endpoints.search_tool_management import ( router as search_tool_management_router, ) from litellm.proxy.spend_tracking.cloudzero_endpoints import router as cloudzero_router +from litellm.proxy.spend_tracking.vantage_endpoints import router as vantage_router from litellm.proxy.spend_tracking.spend_management_endpoints import ( router as spend_management_router, ) @@ -6127,6 +6128,15 @@ class ProxyStartupEvent: ######################################################## await FocusLogger.init_focus_export_background_job(scheduler=scheduler) + ######################################################## + # Vantage Background Job + ######################################################## + from litellm.integrations.vantage.vantage_logger import VantageLogger + from litellm.proxy.spend_tracking.vantage_endpoints import is_vantage_setup + + if await is_vantage_setup(): + await VantageLogger.init_vantage_background_job(scheduler=scheduler) + ######################################################## # Prometheus Background Job ######################################################## @@ -13180,6 +13190,7 @@ app.include_router(project_router) app.include_router(customer_router) app.include_router(spend_management_router) app.include_router(cloudzero_router) +app.include_router(vantage_router) app.include_router(caching_router) app.include_router(analytics_router) app.include_router(guardrails_router) diff --git a/litellm/proxy/spend_tracking/vantage_endpoints.py b/litellm/proxy/spend_tracking/vantage_endpoints.py new file mode 100644 index 0000000000..842ca9a258 --- /dev/null +++ b/litellm/proxy/spend_tracking/vantage_endpoints.py @@ -0,0 +1,488 @@ +import json + +from fastapi import APIRouter, Depends, HTTPException + +from litellm._logging import verbose_proxy_logger +from litellm.litellm_core_utils.sensitive_data_masker import SensitiveDataMasker +from litellm.proxy._types import CommonProxyErrors, LitellmUserRoles, UserAPIKeyAuth +from litellm.proxy.auth.user_api_key_auth import user_api_key_auth +from litellm.proxy.common_utils.encrypt_decrypt_utils import ( + decrypt_value_helper, + encrypt_value_helper, +) +from litellm.types.proxy.vantage_endpoints import ( + VantageExportRequest, + VantageExportResponse, + VantageInitRequest, + VantageInitResponse, + VantageSettingsUpdate, + VantageSettingsView, +) + +router = APIRouter() + +_sensitive_masker = SensitiveDataMasker() + +VANTAGE_SETTINGS_PARAM_NAME = "vantage_settings" + + +async def _set_vantage_settings( + api_key: str, integration_token: str, base_url: str +): + """Store Vantage settings in the database with encrypted API key.""" + from litellm.proxy.proxy_server import prisma_client + + if prisma_client is None: + raise HTTPException( + status_code=500, + detail={"error": CommonProxyErrors.db_not_connected_error.value}, + ) + + encrypted_api_key = encrypt_value_helper(api_key) + + vantage_settings = { + "api_key": encrypted_api_key, + "integration_token": integration_token, + "base_url": base_url, + } + + await prisma_client.db.litellm_config.upsert( + where={"param_name": VANTAGE_SETTINGS_PARAM_NAME}, + data={ + "create": { + "param_name": VANTAGE_SETTINGS_PARAM_NAME, + "param_value": json.dumps(vantage_settings), + }, + "update": {"param_value": json.dumps(vantage_settings)}, + }, + ) + + +async def _get_vantage_settings(): + """Retrieve Vantage settings from the database with decrypted API key.""" + from litellm.proxy.proxy_server import prisma_client + + if prisma_client is None: + raise HTTPException( + status_code=500, + detail={"error": CommonProxyErrors.db_not_connected_error.value}, + ) + + vantage_config = await prisma_client.db.litellm_config.find_first( + where={"param_name": VANTAGE_SETTINGS_PARAM_NAME} + ) + if vantage_config is None or vantage_config.param_value is None: + return {} + + if isinstance(vantage_config.param_value, dict): + settings = vantage_config.param_value + elif isinstance(vantage_config.param_value, str): + settings = json.loads(vantage_config.param_value) + else: + settings = dict(vantage_config.param_value) + + encrypted_api_key = settings.get("api_key") + if encrypted_api_key: + decrypted_api_key = decrypt_value_helper( + encrypted_api_key, key="vantage_api_key", exception_type="error" + ) + if decrypted_api_key is None: + raise HTTPException( + status_code=500, + detail={ + "error": "Failed to decrypt Vantage API key. Check your salt key configuration." + }, + ) + settings["api_key"] = decrypted_api_key + + return settings + + +@router.get( + "/vantage/settings", + tags=["Vantage"], + dependencies=[Depends(user_api_key_auth)], + response_model=VantageSettingsView, +) +async def get_vantage_settings( + user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth), +): + """ + View current Vantage settings. + + Returns the current Vantage configuration with the API key masked for security. + Only admin users can view Vantage settings. + """ + if user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN: + raise HTTPException( + status_code=403, + detail={"error": CommonProxyErrors.not_allowed_access.value}, + ) + + try: + settings = await _get_vantage_settings() + + if not settings: + return VantageSettingsView( + api_key_masked=None, + integration_token=None, + base_url=None, + status=None, + ) + + masked_settings = _sensitive_masker.mask_dict(settings) + + return VantageSettingsView( + api_key_masked=masked_settings.get("api_key"), + integration_token=settings.get("integration_token"), + base_url=settings.get("base_url"), + status="configured", + ) + + except HTTPException: + raise + except Exception as e: + verbose_proxy_logger.error(f"Error retrieving Vantage settings: {str(e)}") + raise HTTPException( + status_code=500, + detail={"error": f"Failed to retrieve Vantage settings: {str(e)}"}, + ) + + +@router.put( + "/vantage/settings", + tags=["Vantage"], + dependencies=[Depends(user_api_key_auth)], + response_model=VantageInitResponse, +) +async def update_vantage_settings( + request: VantageSettingsUpdate, + user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth), +): + """ + Update existing Vantage settings. + + Allows updating individual Vantage configuration fields without requiring all fields. + Only admin users can update Vantage settings. + """ + if user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN: + raise HTTPException( + status_code=403, + detail={"error": CommonProxyErrors.not_allowed_access.value}, + ) + + if not any([request.api_key, request.integration_token, request.base_url]): + raise HTTPException( + status_code=400, + detail={"error": "At least one field must be provided for update"}, + ) + + try: + current_settings = await _get_vantage_settings() + + updated_api_key = ( + request.api_key + if request.api_key is not None + else current_settings["api_key"] + ) + updated_token = ( + request.integration_token + if request.integration_token is not None + else current_settings["integration_token"] + ) + updated_base_url = ( + request.base_url + if request.base_url is not None + else current_settings["base_url"] + ) + + await _set_vantage_settings( + api_key=updated_api_key, + integration_token=updated_token, + base_url=updated_base_url, + ) + + verbose_proxy_logger.info("Vantage settings updated successfully") + + return VantageInitResponse( + message="Vantage settings updated successfully", status="success" + ) + + except HTTPException as e: + if e.status_code == 400: + raise HTTPException( + status_code=404, + detail={ + "error": "Vantage settings not found. Please initialize settings first using /vantage/init" + }, + ) + raise + except Exception as e: + verbose_proxy_logger.error(f"Error updating Vantage settings: {str(e)}") + raise HTTPException( + status_code=500, + detail={"error": f"Failed to update Vantage settings: {str(e)}"}, + ) + + +async def is_vantage_setup_in_db() -> bool: + """Check if Vantage is setup in the database.""" + try: + from litellm.proxy.proxy_server import prisma_client + + if prisma_client is None: + return False + + vantage_config = await prisma_client.db.litellm_config.find_first( + where={"param_name": VANTAGE_SETTINGS_PARAM_NAME} + ) + + return vantage_config is not None and vantage_config.param_value is not None + + except Exception as e: + verbose_proxy_logger.error(f"Error checking Vantage status: {str(e)}") + return False + + +def is_vantage_setup_in_config() -> bool: + """Check if Vantage is setup in config.yaml or environment variables.""" + import litellm + + return "vantage" in litellm.callbacks + + +async def is_vantage_setup() -> bool: + """Check if Vantage is setup in either config or database.""" + try: + if is_vantage_setup_in_config(): + return True + if await is_vantage_setup_in_db(): + return True + return False + except Exception as e: + verbose_proxy_logger.error(f"Error checking Vantage setup: {str(e)}") + return False + + +@router.post( + "/vantage/init", + tags=["Vantage"], + dependencies=[Depends(user_api_key_auth)], + response_model=VantageInitResponse, +) +async def init_vantage_settings( + request: VantageInitRequest, + user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth), +): + """ + Initialize Vantage settings and store in the database. + + Parameters: + - api_key: Vantage API key for authentication + - integration_token: Vantage integration token for the cost-import endpoint + - base_url: Vantage API base URL (default: https://api.vantage.sh) + + Only admin users can configure Vantage settings. + """ + if user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN: + raise HTTPException( + status_code=403, + detail={"error": CommonProxyErrors.not_allowed_access.value}, + ) + + try: + await _set_vantage_settings( + api_key=request.api_key, + integration_token=request.integration_token, + base_url=request.base_url, + ) + + verbose_proxy_logger.info("Vantage settings initialized successfully") + + return VantageInitResponse( + message="Vantage settings initialized successfully", status="success" + ) + + except Exception as e: + verbose_proxy_logger.error( + f"Error initializing Vantage settings: {str(e)}" + ) + raise HTTPException( + status_code=500, + detail={"error": f"Failed to initialize Vantage settings: {str(e)}"}, + ) + + +@router.post( + "/vantage/dry-run", + tags=["Vantage"], + dependencies=[Depends(user_api_key_auth)], + response_model=VantageExportResponse, +) +async def vantage_dry_run_export( + request: VantageExportRequest, + user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth), +): + """ + Perform a dry run export using the Vantage logger. + + Returns the data that would be exported without actually sending it to Vantage. + + Parameters: + - limit: Optional limit on number of records to process (default: 500) + + Only admin users can perform Vantage exports. + """ + if user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN: + raise HTTPException( + status_code=403, + detail={"error": CommonProxyErrors.not_allowed_access.value}, + ) + + try: + from litellm.integrations.vantage.vantage_logger import VantageLogger + + logger = VantageLogger() + dry_run_result = await logger.dry_run_export_usage_data( + limit=request.limit + ) + + verbose_proxy_logger.info("Vantage dry run export completed successfully") + + return VantageExportResponse( + message="Vantage dry run export completed successfully.", + status="success", + dry_run_data=dry_run_result, + summary=dry_run_result.get("summary") if dry_run_result else None, + ) + + except Exception as e: + verbose_proxy_logger.error( + f"Error performing Vantage dry run export: {str(e)}" + ) + raise HTTPException( + status_code=500, + detail={ + "error": f"Failed to perform Vantage dry run export: {str(e)}" + }, + ) + + +@router.post( + "/vantage/export", + tags=["Vantage"], + dependencies=[Depends(user_api_key_auth)], + response_model=VantageExportResponse, +) +async def vantage_export( + request: VantageExportRequest, + user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth), +): + """ + Perform an actual export using the Vantage logger. + + Exports usage data in FOCUS CSV format to the Vantage API. + + Parameters: + - limit: Optional limit on number of records to export + - start_time_utc: Optional start time for data export + - end_time_utc: Optional end time for data export + + Only admin users can perform Vantage exports. + """ + if user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN: + raise HTTPException( + status_code=403, + detail={"error": CommonProxyErrors.not_allowed_access.value}, + ) + + try: + settings = await _get_vantage_settings() + + from litellm.integrations.vantage.vantage_logger import VantageLogger + + logger = VantageLogger( + api_key=settings.get("api_key"), + integration_token=settings.get("integration_token"), + base_url=settings.get("base_url"), + ) + await logger.export_usage_data( + limit=request.limit, + start_time_utc=request.start_time_utc, + end_time_utc=request.end_time_utc, + ) + + verbose_proxy_logger.info("Vantage export completed successfully") + + return VantageExportResponse( + message="Vantage export completed successfully", + status="success", + dry_run_data=None, + summary=None, + ) + + except Exception as e: + verbose_proxy_logger.error(f"Error performing Vantage export: {str(e)}") + raise HTTPException( + status_code=500, + detail={"error": f"Failed to perform Vantage export: {str(e)}"}, + ) + + +@router.delete( + "/vantage/delete", + tags=["Vantage"], + dependencies=[Depends(user_api_key_auth)], + response_model=VantageInitResponse, +) +async def delete_vantage_settings( + user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth), +): + """ + Delete Vantage settings from the database. + + Only admin users can delete Vantage settings. + """ + if user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN: + raise HTTPException( + status_code=403, + detail={"error": CommonProxyErrors.not_allowed_access.value}, + ) + + try: + from litellm.proxy.proxy_server import prisma_client + + if prisma_client is None: + raise HTTPException( + status_code=500, + detail={"error": CommonProxyErrors.db_not_connected_error.value}, + ) + + vantage_config = await prisma_client.db.litellm_config.find_first( + where={"param_name": VANTAGE_SETTINGS_PARAM_NAME} + ) + + if vantage_config is None: + raise HTTPException( + status_code=404, + detail={"error": "Vantage settings not found"}, + ) + + await prisma_client.db.litellm_config.delete( + where={"param_name": VANTAGE_SETTINGS_PARAM_NAME} + ) + + verbose_proxy_logger.info("Vantage settings deleted successfully") + + return VantageInitResponse( + message="Vantage settings deleted successfully", status="success" + ) + + except HTTPException: + raise + except Exception as e: + verbose_proxy_logger.error(f"Error deleting Vantage settings: {str(e)}") + raise HTTPException( + status_code=500, + detail={"error": f"Failed to delete Vantage settings: {str(e)}"}, + ) diff --git a/litellm/types/proxy/vantage_endpoints.py b/litellm/types/proxy/vantage_endpoints.py new file mode 100644 index 0000000000..394677d1e8 --- /dev/null +++ b/litellm/types/proxy/vantage_endpoints.py @@ -0,0 +1,81 @@ +""" +Vantage endpoint types for LiteLLM Proxy +""" + +from datetime import datetime +from typing import Any, Dict, Optional + +from pydantic import BaseModel, Field + + +class VantageInitRequest(BaseModel): + """Request model for initializing Vantage settings""" + + api_key: str = Field(..., description="Vantage API key for authentication") + integration_token: str = Field( + ..., description="Vantage integration token for the cost-import endpoint" + ) + base_url: str = Field( + default="https://api.vantage.sh", + description="Vantage API base URL (default: https://api.vantage.sh)", + ) + + +class VantageInitResponse(BaseModel): + """Response model for Vantage initialization""" + + message: str + status: str + + +class VantageExportRequest(BaseModel): + """Request model for Vantage export operations""" + + limit: Optional[int] = Field( + None, description="Optional limit on number of records to export" + ) + start_time_utc: Optional[datetime] = Field( + None, description="Start time for data export in UTC" + ) + end_time_utc: Optional[datetime] = Field( + None, description="End time for data export in UTC" + ) + + +class VantageExportResponse(BaseModel): + """Response model for Vantage export operations""" + + message: str + status: str + dry_run_data: Optional[Dict[str, Any]] = Field( + None, description="Dry run data including usage data and FOCUS transformed data" + ) + summary: Optional[Dict[str, Any]] = Field( + None, description="Summary statistics for dry run" + ) + + +class VantageSettingsView(BaseModel): + """Response model for viewing Vantage settings with masked API key""" + + api_key_masked: Optional[str] = Field( + None, + description="Masked API key showing only first 4 and last 4 characters", + ) + integration_token: Optional[str] = Field( + None, description="Vantage integration token" + ) + base_url: Optional[str] = Field(None, description="Vantage API base URL") + status: Optional[str] = Field(None, description="Configuration status") + + +class VantageSettingsUpdate(BaseModel): + """Request model for updating Vantage settings""" + + api_key: Optional[str] = Field( + None, description="New Vantage API key for authentication" + ) + integration_token: Optional[str] = Field( + None, description="New Vantage integration token" + ) + base_url: Optional[str] = Field(None, description="New Vantage API base URL") diff --git a/tests/test_litellm/integrations/focus/test_csv_serializer.py b/tests/test_litellm/integrations/focus/test_csv_serializer.py new file mode 100644 index 0000000000..f527a9dceb --- /dev/null +++ b/tests/test_litellm/integrations/focus/test_csv_serializer.py @@ -0,0 +1,34 @@ +"""Tests for FocusCsvSerializer.""" + +from __future__ import annotations + +import polars as pl + +from litellm.integrations.focus.serializers.csv import FocusCsvSerializer + + +def test_should_serialize_dataframe_to_csv(): + frame = pl.DataFrame({"BilledCost": [1.5, 2.0], "ServiceName": ["openai", "anthropic"]}) + serializer = FocusCsvSerializer() + result = serializer.serialize(frame) + + assert isinstance(result, bytes) + lines = result.decode("utf-8").strip().split("\n") + assert lines[0] == "BilledCost,ServiceName" + assert len(lines) == 3 # header + 2 data rows + + +def test_should_return_header_only_for_empty_frame(): + frame = pl.DataFrame( + schema={"BilledCost": pl.Float64, "ServiceName": pl.Utf8} + ) + serializer = FocusCsvSerializer() + result = serializer.serialize(frame) + + lines = result.decode("utf-8").strip().split("\n") + assert lines[0] == "BilledCost,ServiceName" + assert len(lines) == 1 # header only + + +def test_extension_should_be_csv(): + assert FocusCsvSerializer.extension == "csv" diff --git a/tests/test_litellm/integrations/focus/test_destination_factory.py b/tests/test_litellm/integrations/focus/test_destination_factory.py new file mode 100644 index 0000000000..4888e8231b --- /dev/null +++ b/tests/test_litellm/integrations/focus/test_destination_factory.py @@ -0,0 +1,48 @@ +"""Tests for FocusDestinationFactory with vantage provider.""" + +from __future__ import annotations + +import pytest + +from litellm.integrations.focus.destinations.factory import FocusDestinationFactory +from litellm.integrations.focus.destinations.vantage_destination import ( + FocusVantageDestination, +) + + +def test_should_create_vantage_destination(): + dest = FocusDestinationFactory.create( + provider="vantage", + prefix="exports", + config={ + "api_key": "test-key", + "integration_token": "test-token", + }, + ) + assert isinstance(dest, FocusVantageDestination) + + +def test_should_raise_when_vantage_missing_api_key(): + with pytest.raises(ValueError, match="VANTAGE_API_KEY"): + FocusDestinationFactory.create( + provider="vantage", + prefix="exports", + config={"integration_token": "tok"}, + ) + + +def test_should_raise_when_vantage_missing_token(): + with pytest.raises(ValueError, match="VANTAGE_INTEGRATION_TOKEN"): + FocusDestinationFactory.create( + provider="vantage", + prefix="exports", + config={"api_key": "key"}, + ) + + +def test_should_raise_for_unsupported_provider(): + with pytest.raises(NotImplementedError): + FocusDestinationFactory.create( + provider="unknown_provider", + prefix="exports", + ) diff --git a/tests/test_litellm/integrations/focus/test_vantage_destination.py b/tests/test_litellm/integrations/focus/test_vantage_destination.py new file mode 100644 index 0000000000..181d3d1381 --- /dev/null +++ b/tests/test_litellm/integrations/focus/test_vantage_destination.py @@ -0,0 +1,138 @@ +"""Tests for FocusVantageDestination behavior.""" + +from __future__ import annotations + +from datetime import datetime, timezone +from typing import Any, Dict, List +from unittest.mock import AsyncMock, patch + +import pytest + +from litellm.integrations.focus.destinations.base import FocusTimeWindow +from litellm.integrations.focus.destinations.vantage_destination import ( + FocusVantageDestination, + VANTAGE_MAX_BYTES_PER_UPLOAD, +) + + +def _window(freq: str = "hourly", hour: int = 5) -> FocusTimeWindow: + start = datetime(2024, 1, 2, hour, tzinfo=timezone.utc) + end = start.replace(hour=hour + 1) + return FocusTimeWindow(start_time=start, end_time=end, frequency=freq) + + +def _config(**overrides: Any) -> dict[str, Any]: + base = { + "api_key": "test-api-key", + "integration_token": "test-token-123", + } + base.update(overrides) + return base + + +def test_should_require_api_key(): + with pytest.raises(ValueError, match="api_key"): + FocusVantageDestination( + prefix="exports", + config={"integration_token": "tok"}, + ) + + +def test_should_require_integration_token(): + with pytest.raises(ValueError, match="integration_token"): + FocusVantageDestination( + prefix="exports", + config={"api_key": "key"}, + ) + + +def test_should_initialize_with_valid_config(): + dest = FocusVantageDestination(prefix="exports", config=_config()) + assert dest.api_key == "test-api-key" + assert dest.integration_token == "test-token-123" + assert dest.base_url == "https://api.vantage.sh" + + +def test_should_use_custom_base_url(): + dest = FocusVantageDestination( + prefix="exports", + config=_config(base_url="https://custom.vantage.sh"), + ) + assert dest.base_url == "https://custom.vantage.sh" + + +@pytest.mark.asyncio +async def test_should_skip_empty_content(): + dest = FocusVantageDestination(prefix="exports", config=_config()) + # Should not raise + await dest.deliver(content=b"", time_window=_window(), filename="usage.csv") + + +@pytest.mark.asyncio +async def test_should_upload_csv_to_correct_url(): + dest = FocusVantageDestination(prefix="exports", config=_config()) + captured: Dict[str, Any] = {} + + mock_response = AsyncMock() + mock_response.raise_for_status = lambda: None + + mock_client = AsyncMock() + mock_client.post = AsyncMock(return_value=mock_response) + mock_client.__aenter__ = AsyncMock(return_value=mock_client) + mock_client.__aexit__ = AsyncMock(return_value=False) + + with patch("litellm.integrations.focus.destinations.vantage_destination.httpx.AsyncClient", return_value=mock_client): + await dest.deliver( + content=b"header\nrow1\n", + time_window=_window(), + filename="usage.csv", + ) + + mock_client.post.assert_called_once() + call_args = mock_client.post.call_args + assert "test-token-123" in call_args[0][0] + assert "costs.csv" in call_args[0][0] + assert call_args[1]["headers"]["Authorization"] == "Bearer test-api-key" + + +@pytest.mark.asyncio +async def test_should_batch_large_content(): + dest = FocusVantageDestination(prefix="exports", config=_config()) + + # Create content larger than 2 MB + header = b"col1,col2,col3" + row = b"a" * 100 + b"," + b"b" * 100 + b"," + b"c" * 100 + num_rows = (VANTAGE_MAX_BYTES_PER_UPLOAD // len(row)) + 100 + large_content = header + b"\n" + b"\n".join([row] * num_rows) + b"\n" + + assert len(large_content) > VANTAGE_MAX_BYTES_PER_UPLOAD + + upload_calls: List[bytes] = [] + + mock_response = AsyncMock() + mock_response.raise_for_status = lambda: None + + mock_client = AsyncMock() + mock_client.__aenter__ = AsyncMock(return_value=mock_client) + mock_client.__aexit__ = AsyncMock(return_value=False) + + async def capture_post(url, **kwargs): + files = kwargs.get("files", {}) + if "file" in files: + upload_calls.append(files["file"][1]) + return mock_response + + mock_client.post = capture_post + + with patch("litellm.integrations.focus.destinations.vantage_destination.httpx.AsyncClient", return_value=mock_client): + await dest.deliver( + content=large_content, + time_window=_window(), + filename="usage.csv", + ) + + # Should have made multiple uploads + assert len(upload_calls) > 1 + # Each upload should be within limits + for chunk in upload_calls: + assert len(chunk) <= VANTAGE_MAX_BYTES_PER_UPLOAD From f683befeed0a01695b3ab4250724e8626433d516 Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 14:02:05 +0530 Subject: [PATCH 013/289] Fix Greptile review issues in Vantage integration - Enforce 10K row limit in single-shot upload path (not just 2MB size) - Fix KeyError crash in update_vantage_settings when no settings exist - Remove unreachable status_code==400 dead code branch - Make dry-run endpoint work without Vantage credentials by using FOCUS database + transformer directly instead of VantageLogger Co-Authored-By: Claude Opus 4.6 --- .../focus/destinations/vantage_destination.py | 12 +++- .../proxy/spend_tracking/vantage_endpoints.py | 55 +++++++++++++------ 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/litellm/integrations/focus/destinations/vantage_destination.py b/litellm/integrations/focus/destinations/vantage_destination.py index 5612a513d6..32ba6df8ea 100644 --- a/litellm/integrations/focus/destinations/vantage_destination.py +++ b/litellm/integrations/focus/destinations/vantage_destination.py @@ -56,12 +56,18 @@ class FocusVantageDestination(FocusDestination): verbose_logger.debug("Vantage destination: empty content, skipping upload") return - # If the payload is within limits, send in one shot - if len(content) <= VANTAGE_MAX_BYTES_PER_UPLOAD: + # Check both size and row-count limits before single-shot upload + lines = content.split(b"\n") + data_line_count = sum(1 for line in lines[1:] if line.strip()) + within_limits = ( + len(content) <= VANTAGE_MAX_BYTES_PER_UPLOAD + and data_line_count <= VANTAGE_MAX_ROWS_PER_UPLOAD + ) + if within_limits: await self._upload_csv(content, filename) return - # Otherwise split into chunks by line count + # Otherwise split into batches respecting both limits await self._upload_batched(content, filename) async def _upload_csv(self, csv_bytes: bytes, filename: str) -> None: diff --git a/litellm/proxy/spend_tracking/vantage_endpoints.py b/litellm/proxy/spend_tracking/vantage_endpoints.py index 842ca9a258..47838158b9 100644 --- a/litellm/proxy/spend_tracking/vantage_endpoints.py +++ b/litellm/proxy/spend_tracking/vantage_endpoints.py @@ -180,20 +180,28 @@ async def update_vantage_settings( try: current_settings = await _get_vantage_settings() + if not current_settings: + raise HTTPException( + status_code=404, + detail={ + "error": "Vantage settings not found. Please initialize settings first using /vantage/init" + }, + ) + updated_api_key = ( request.api_key if request.api_key is not None - else current_settings["api_key"] + else current_settings.get("api_key", "") ) updated_token = ( request.integration_token if request.integration_token is not None - else current_settings["integration_token"] + else current_settings.get("integration_token", "") ) updated_base_url = ( request.base_url if request.base_url is not None - else current_settings["base_url"] + else current_settings.get("base_url", "https://api.vantage.sh") ) await _set_vantage_settings( @@ -208,14 +216,7 @@ async def update_vantage_settings( message="Vantage settings updated successfully", status="success" ) - except HTTPException as e: - if e.status_code == 400: - raise HTTPException( - status_code=404, - detail={ - "error": "Vantage settings not found. Please initialize settings first using /vantage/init" - }, - ) + except HTTPException: raise except Exception as e: verbose_proxy_logger.error(f"Error updating Vantage settings: {str(e)}") @@ -340,12 +341,32 @@ async def vantage_dry_run_export( ) try: - from litellm.integrations.vantage.vantage_logger import VantageLogger + # Dry-run uses the FOCUS database + transformer directly, + # bypassing the destination so no Vantage credentials are required. + from litellm.integrations.focus.database import FocusLiteLLMDatabase + from litellm.integrations.focus.transformer import FocusTransformer - logger = VantageLogger() - dry_run_result = await logger.dry_run_export_usage_data( - limit=request.limit - ) + database = FocusLiteLLMDatabase() + transformer = FocusTransformer() + + data = await database.get_usage_data(limit=request.limit) + normalized = transformer.transform(data) + + usage_sample = data.head(min(50, len(data))).to_dicts() if not data.is_empty() else [] + normalized_sample = normalized.head(min(50, len(normalized))).to_dicts() if not normalized.is_empty() else [] + + summary = { + "total_records": len(normalized), + "total_spend": float(normalized.select("BilledCost").sum().item()) if not normalized.is_empty() and "BilledCost" in normalized.columns else 0.0, + "unique_teams": normalized["SubAccountId"].n_unique() if not normalized.is_empty() and "SubAccountId" in normalized.columns else 0, + "unique_models": normalized["ResourceType"].n_unique() if not normalized.is_empty() and "ResourceType" in normalized.columns else 0, + } + + dry_run_result = { + "usage_data": usage_sample, + "normalized_data": normalized_sample, + "summary": summary, + } verbose_proxy_logger.info("Vantage dry run export completed successfully") @@ -353,7 +374,7 @@ async def vantage_dry_run_export( message="Vantage dry run export completed successfully.", status="success", dry_run_data=dry_run_result, - summary=dry_run_result.get("summary") if dry_run_result else None, + summary=summary, ) except Exception as e: From e1c44fe0881ed714d91942d9751c9505e8eaccc4 Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 14:17:03 +0530 Subject: [PATCH 014/289] Fix Greptile round 2 review issues - DB-only Vantage config now registers VantageLogger at startup so background job actually schedules (was silently skipping) - Add missing `except HTTPException: raise` in /vantage/init endpoint - Use consistent batch filenames (always .partN suffix) - Document Tags schema change from pl.Object to pl.String Co-Authored-By: Claude Opus 4.6 --- .../focus/destinations/vantage_destination.py | 2 +- litellm/integrations/focus/schema.py | 3 +++ litellm/proxy/proxy_server.py | 24 ++++++++++++++++++- .../proxy/spend_tracking/vantage_endpoints.py | 2 ++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/litellm/integrations/focus/destinations/vantage_destination.py b/litellm/integrations/focus/destinations/vantage_destination.py index 32ba6df8ea..e8d9532c41 100644 --- a/litellm/integrations/focus/destinations/vantage_destination.py +++ b/litellm/integrations/focus/destinations/vantage_destination.py @@ -108,7 +108,7 @@ class FocusVantageDestination(FocusDestination): if len(batch_csv) > VANTAGE_MAX_BYTES_PER_UPLOAD: await self._upload_size_limited(header, batch_lines, filename, batch_num) else: - batch_filename = f"{filename}.part{batch_num}" if batch_num > 0 else filename + batch_filename = f"{filename}.part{batch_num}" await self._upload_csv(batch_csv, batch_filename) batch_num += 1 diff --git a/litellm/integrations/focus/schema.py b/litellm/integrations/focus/schema.py index 6ad725f367..127e8ee03a 100644 --- a/litellm/integrations/focus/schema.py +++ b/litellm/integrations/focus/schema.py @@ -43,6 +43,9 @@ FOCUS_NORMALIZED_SCHEMA = pl.Schema( ("SubAccountId", pl.String), ("SubAccountName", pl.String), ("SubAccountType", pl.String), + # Changed from pl.Object to pl.String to hold JSON metadata + # (team_id, user_id, etc.) needed by Vantage Token Allocation. + # Previously Tags was always None so no existing data is lost. ("Tags", pl.String), ] ) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 91196ce5b9..9bd4cd7f14 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -6132,9 +6132,31 @@ class ProxyStartupEvent: # Vantage Background Job ######################################################## from litellm.integrations.vantage.vantage_logger import VantageLogger - from litellm.proxy.spend_tracking.vantage_endpoints import is_vantage_setup + from litellm.proxy.spend_tracking.vantage_endpoints import ( + _get_vantage_settings, + is_vantage_setup, + is_vantage_setup_in_config, + is_vantage_setup_in_db, + ) if await is_vantage_setup(): + # If configured via DB but not in config.yaml callbacks, + # instantiate and register a VantageLogger so the scheduler + # can find it. + if not is_vantage_setup_in_config() and await is_vantage_setup_in_db(): + try: + db_settings = await _get_vantage_settings() + if db_settings: + vantage_logger = VantageLogger( + api_key=db_settings.get("api_key"), + integration_token=db_settings.get("integration_token"), + base_url=db_settings.get("base_url"), + ) + litellm.callbacks.append(vantage_logger) # type: ignore[arg-type] + except Exception as e: + verbose_proxy_logger.warning( + "Failed to register VantageLogger from DB settings: %s", e + ) await VantageLogger.init_vantage_background_job(scheduler=scheduler) ######################################################## diff --git a/litellm/proxy/spend_tracking/vantage_endpoints.py b/litellm/proxy/spend_tracking/vantage_endpoints.py index 47838158b9..d0e01fe325 100644 --- a/litellm/proxy/spend_tracking/vantage_endpoints.py +++ b/litellm/proxy/spend_tracking/vantage_endpoints.py @@ -304,6 +304,8 @@ async def init_vantage_settings( message="Vantage settings initialized successfully", status="success" ) + except HTTPException: + raise except Exception as e: verbose_proxy_logger.error( f"Error initializing Vantage settings: {str(e)}" From e07297fa8731676b0de83ae3443ceb2b037e216a Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 14:27:24 +0530 Subject: [PATCH 015/289] Address Greptile round 3 feedback for improved security and consistency - Encrypt integration_token alongside api_key in Vantage settings storage - Align dry-run summary with FocusExportEngine helper methods - Vectorize Tags JSON building using pl.struct + map_elements - Reuse registered VantageLogger in /export endpoint instead of creating fresh instances Co-Authored-By: Claude Opus 4.6 --- litellm/integrations/focus/transformer.py | 62 +++++++++---------- .../proxy/spend_tracking/vantage_endpoints.py | 57 +++++++++++++---- 2 files changed, 77 insertions(+), 42 deletions(-) diff --git a/litellm/integrations/focus/transformer.py b/litellm/integrations/focus/transformer.py index 1e4a17796d..adac158651 100644 --- a/litellm/integrations/focus/transformer.py +++ b/litellm/integrations/focus/transformer.py @@ -10,27 +10,34 @@ import polars as pl from .schema import FOCUS_NORMALIZED_SCHEMA -def _build_tags_json(row: dict) -> str: - """Build a JSON string of metadata tags from a DB row. +_TAG_KEYS = ( + "team_id", + "team_alias", + "user_id", + "user_email", + "api_key_alias", + "model", + "model_group", + "custom_llm_provider", +) - Vantage uses this for Token Allocation — enriching billing data with - team, user, and API key metadata. + +def _build_tags_expr(available_keys: list[str]) -> pl.Expr: + """Build a Polars expression that produces a JSON Tags string per row. + + Uses ``pl.struct`` + ``map_elements`` so the heavy iteration stays inside + Polars rather than materialising every row to a Python dict first. """ - tags: dict[str, str] = {} - for key in ( - "team_id", - "team_alias", - "user_id", - "user_email", - "api_key_alias", - "model", - "model_group", - "custom_llm_provider", - ): - val = row.get(key) - if val is not None: - tags[key] = str(val) - return json.dumps(tags) if tags else "{}" + + def _struct_to_json(row: dict) -> str: + tags = {k: str(v) for k, v in row.items() if v is not None} + return json.dumps(tags) if tags else "{}" + + return ( + pl.struct(available_keys) + .map_elements(_struct_to_json, return_dtype=pl.String) + .alias("Tags") + ) class FocusTransformer: @@ -43,19 +50,12 @@ class FocusTransformer: if frame.is_empty(): return pl.DataFrame(schema=self.schema) - # Build Tags JSON from metadata columns - tag_col = "Tags" - tag_keys = [ - "team_id", "team_alias", "user_id", "user_email", - "api_key_alias", "model", "model_group", "custom_llm_provider", - ] - available_keys = [k for k in tag_keys if k in frame.columns] + # Build Tags JSON from metadata columns using vectorized Polars expression + available_keys = [k for k in _TAG_KEYS if k in frame.columns] if available_keys: - tags_series = frame.select(available_keys).to_dicts() - tags_json = [_build_tags_json(row) for row in tags_series] - frame = frame.with_columns(pl.Series(tag_col, tags_json)) + frame = frame.with_columns(_build_tags_expr(available_keys)) else: - frame = frame.with_columns(pl.lit("{}").alias(tag_col)) + frame = frame.with_columns(pl.lit("{}").alias("Tags")) # derive period start/end from usage date frame = frame.with_columns( @@ -124,5 +124,5 @@ class FocusTransformer: pl.col("team_id").cast(pl.String).alias("SubAccountId"), pl.col("team_alias").cast(pl.String).alias("SubAccountName"), none_str.alias("SubAccountType"), - pl.col(tag_col).cast(pl.String).alias("Tags"), + pl.col("Tags").cast(pl.String).alias("Tags"), ) diff --git a/litellm/proxy/spend_tracking/vantage_endpoints.py b/litellm/proxy/spend_tracking/vantage_endpoints.py index d0e01fe325..a553d1061e 100644 --- a/litellm/proxy/spend_tracking/vantage_endpoints.py +++ b/litellm/proxy/spend_tracking/vantage_endpoints.py @@ -1,5 +1,6 @@ import json +import litellm from fastapi import APIRouter, Depends, HTTPException from litellm._logging import verbose_proxy_logger @@ -26,6 +27,18 @@ _sensitive_masker = SensitiveDataMasker() VANTAGE_SETTINGS_PARAM_NAME = "vantage_settings" +def _get_registered_vantage_logger(): + """Return the VantageLogger already registered in litellm.callbacks, if any.""" + from litellm.integrations.vantage.vantage_logger import VantageLogger + + vantage_loggers = litellm.logging_callback_manager.get_custom_loggers_for_type( + callback_type=VantageLogger + ) + if vantage_loggers: + return vantage_loggers[0] + return None + + async def _set_vantage_settings( api_key: str, integration_token: str, base_url: str ): @@ -39,10 +52,11 @@ async def _set_vantage_settings( ) encrypted_api_key = encrypt_value_helper(api_key) + encrypted_integration_token = encrypt_value_helper(integration_token) vantage_settings = { "api_key": encrypted_api_key, - "integration_token": integration_token, + "integration_token": encrypted_integration_token, "base_url": base_url, } @@ -95,6 +109,22 @@ async def _get_vantage_settings(): ) settings["api_key"] = decrypted_api_key + encrypted_integration_token = settings.get("integration_token") + if encrypted_integration_token: + decrypted_integration_token = decrypt_value_helper( + encrypted_integration_token, + key="vantage_integration_token", + exception_type="error", + ) + if decrypted_integration_token is None: + raise HTTPException( + status_code=500, + detail={ + "error": "Failed to decrypt Vantage integration token. Check your salt key configuration." + }, + ) + settings["integration_token"] = decrypted_integration_token + return settings @@ -346,6 +376,7 @@ async def vantage_dry_run_export( # Dry-run uses the FOCUS database + transformer directly, # bypassing the destination so no Vantage credentials are required. from litellm.integrations.focus.database import FocusLiteLLMDatabase + from litellm.integrations.focus.export_engine import FocusExportEngine from litellm.integrations.focus.transformer import FocusTransformer database = FocusLiteLLMDatabase() @@ -357,11 +388,12 @@ async def vantage_dry_run_export( usage_sample = data.head(min(50, len(data))).to_dicts() if not data.is_empty() else [] normalized_sample = normalized.head(min(50, len(normalized))).to_dicts() if not normalized.is_empty() else [] + # Use the same column names as FocusExportEngine.dry_run_export_usage_data summary = { "total_records": len(normalized), - "total_spend": float(normalized.select("BilledCost").sum().item()) if not normalized.is_empty() and "BilledCost" in normalized.columns else 0.0, - "unique_teams": normalized["SubAccountId"].n_unique() if not normalized.is_empty() and "SubAccountId" in normalized.columns else 0, - "unique_models": normalized["ResourceType"].n_unique() if not normalized.is_empty() and "ResourceType" in normalized.columns else 0, + "total_spend": FocusExportEngine._sum_column(normalized, "BilledCost"), + "unique_teams": FocusExportEngine._count_unique(normalized, "SubAccountId"), + "unique_models": FocusExportEngine._count_unique(normalized, "ResourceType"), } dry_run_result = { @@ -420,15 +452,18 @@ async def vantage_export( ) try: - settings = await _get_vantage_settings() - from litellm.integrations.vantage.vantage_logger import VantageLogger - logger = VantageLogger( - api_key=settings.get("api_key"), - integration_token=settings.get("integration_token"), - base_url=settings.get("base_url"), - ) + # Prefer the already-registered logger to avoid recreating HTTP clients + # on every export call. + logger = _get_registered_vantage_logger() + if logger is None: + settings = await _get_vantage_settings() + logger = VantageLogger( + api_key=settings.get("api_key"), + integration_token=settings.get("integration_token"), + base_url=settings.get("base_url"), + ) await logger.export_usage_data( limit=request.limit, start_time_utc=request.start_time_utc, From 4583c90194c56c4bbc299589fa56138827bb7823 Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 14:38:19 +0530 Subject: [PATCH 016/289] Address remaining Greptile feedback: mask token, reuse HTTP client, align columns - Mask integration_token in GET /vantage/settings response (renamed field to integration_token_masked) - Reuse single httpx.AsyncClient across all batch uploads in deliver() - Align FocusExportEngine.dry_run_export_usage_data to use post-transform FOCUS columns (BilledCost, SubAccountId, ResourceType) matching the Vantage dry-run endpoint Co-Authored-By: Claude Opus 4.6 --- .../focus/destinations/vantage_destination.py | 58 +++++++++++-------- litellm/integrations/focus/export_engine.py | 7 +-- .../proxy/spend_tracking/vantage_endpoints.py | 4 +- litellm/types/proxy/vantage_endpoints.py | 5 +- 4 files changed, 41 insertions(+), 33 deletions(-) diff --git a/litellm/integrations/focus/destinations/vantage_destination.py b/litellm/integrations/focus/destinations/vantage_destination.py index e8d9532c41..e2a21c773f 100644 --- a/litellm/integrations/focus/destinations/vantage_destination.py +++ b/litellm/integrations/focus/destinations/vantage_destination.py @@ -56,21 +56,25 @@ class FocusVantageDestination(FocusDestination): verbose_logger.debug("Vantage destination: empty content, skipping upload") return - # Check both size and row-count limits before single-shot upload - lines = content.split(b"\n") - data_line_count = sum(1 for line in lines[1:] if line.strip()) - within_limits = ( - len(content) <= VANTAGE_MAX_BYTES_PER_UPLOAD - and data_line_count <= VANTAGE_MAX_ROWS_PER_UPLOAD - ) - if within_limits: - await self._upload_csv(content, filename) - return + # Reuse a single HTTP client for the entire deliver() call + async with httpx.AsyncClient(timeout=60.0) as client: + # Check both size and row-count limits before single-shot upload + lines = content.split(b"\n") + data_line_count = sum(1 for line in lines[1:] if line.strip()) + within_limits = ( + len(content) <= VANTAGE_MAX_BYTES_PER_UPLOAD + and data_line_count <= VANTAGE_MAX_ROWS_PER_UPLOAD + ) + if within_limits: + await self._upload_csv(client, content, filename) + return - # Otherwise split into batches respecting both limits - await self._upload_batched(content, filename) + # Otherwise split into batches respecting both limits + await self._upload_batched(client, content, filename) - async def _upload_csv(self, csv_bytes: bytes, filename: str) -> None: + async def _upload_csv( + self, client: httpx.AsyncClient, csv_bytes: bytes, filename: str + ) -> None: url = ( f"{self.base_url}/v2/integrations/" f"{self.integration_token}/costs.csv" @@ -79,13 +83,12 @@ class FocusVantageDestination(FocusDestination): "Authorization": f"Bearer {self.api_key}", } - async with httpx.AsyncClient(timeout=60.0) as client: - response = await client.post( - url, - headers=headers, - files={"file": (filename, csv_bytes, "text/csv")}, - ) - response.raise_for_status() + response = await client.post( + url, + headers=headers, + files={"file": (filename, csv_bytes, "text/csv")}, + ) + response.raise_for_status() verbose_logger.debug( "Vantage destination: uploaded %d bytes (%s)", @@ -93,7 +96,9 @@ class FocusVantageDestination(FocusDestination): filename, ) - async def _upload_batched(self, csv_bytes: bytes, filename: str) -> None: + async def _upload_batched( + self, client: httpx.AsyncClient, csv_bytes: bytes, filename: str + ) -> None: """Split the CSV into batches and upload each.""" lines = csv_bytes.split(b"\n") header = lines[0] @@ -106,14 +111,17 @@ class FocusVantageDestination(FocusDestination): # If a single batch still exceeds 2 MB, split further by size if len(batch_csv) > VANTAGE_MAX_BYTES_PER_UPLOAD: - await self._upload_size_limited(header, batch_lines, filename, batch_num) + await self._upload_size_limited( + client, header, batch_lines, filename, batch_num + ) else: batch_filename = f"{filename}.part{batch_num}" - await self._upload_csv(batch_csv, batch_filename) + await self._upload_csv(client, batch_csv, batch_filename) batch_num += 1 async def _upload_size_limited( self, + client: httpx.AsyncClient, header: bytes, data_lines: list[bytes], filename: str, @@ -129,7 +137,7 @@ class FocusVantageDestination(FocusDestination): if current_size + line_size > VANTAGE_MAX_BYTES_PER_UPLOAD and current_chunk: batch_csv = header + b"\n" + b"\n".join(current_chunk) + b"\n" batch_filename = f"{filename}.part{batch_offset}_{sub_batch}" - await self._upload_csv(batch_csv, batch_filename) + await self._upload_csv(client, batch_csv, batch_filename) current_chunk = [] current_size = len(header) + 1 sub_batch += 1 @@ -139,4 +147,4 @@ class FocusVantageDestination(FocusDestination): if current_chunk: batch_csv = header + b"\n" + b"\n".join(current_chunk) + b"\n" batch_filename = f"{filename}.part{batch_offset}_{sub_batch}" - await self._upload_csv(batch_csv, batch_filename) + await self._upload_csv(client, batch_csv, batch_filename) diff --git a/litellm/integrations/focus/export_engine.py b/litellm/integrations/focus/export_engine.py index a9361d0e98..0cad1b3acd 100644 --- a/litellm/integrations/focus/export_engine.py +++ b/litellm/integrations/focus/export_engine.py @@ -55,10 +55,9 @@ class FocusExportEngine: summary = { "total_records": len(normalized), - "total_spend": self._sum_column(normalized, "spend"), - "total_tokens": self._sum_column(normalized, "total_tokens"), - "unique_teams": self._count_unique(normalized, "team_id"), - "unique_models": self._count_unique(normalized, "model"), + "total_spend": self._sum_column(normalized, "BilledCost"), + "unique_teams": self._count_unique(normalized, "SubAccountId"), + "unique_models": self._count_unique(normalized, "ResourceType"), } return { diff --git a/litellm/proxy/spend_tracking/vantage_endpoints.py b/litellm/proxy/spend_tracking/vantage_endpoints.py index a553d1061e..d3d6787e5f 100644 --- a/litellm/proxy/spend_tracking/vantage_endpoints.py +++ b/litellm/proxy/spend_tracking/vantage_endpoints.py @@ -155,7 +155,7 @@ async def get_vantage_settings( if not settings: return VantageSettingsView( api_key_masked=None, - integration_token=None, + integration_token_masked=None, base_url=None, status=None, ) @@ -164,7 +164,7 @@ async def get_vantage_settings( return VantageSettingsView( api_key_masked=masked_settings.get("api_key"), - integration_token=settings.get("integration_token"), + integration_token_masked=masked_settings.get("integration_token"), base_url=settings.get("base_url"), status="configured", ) diff --git a/litellm/types/proxy/vantage_endpoints.py b/litellm/types/proxy/vantage_endpoints.py index 394677d1e8..165c21316b 100644 --- a/litellm/types/proxy/vantage_endpoints.py +++ b/litellm/types/proxy/vantage_endpoints.py @@ -62,8 +62,9 @@ class VantageSettingsView(BaseModel): None, description="Masked API key showing only first 4 and last 4 characters", ) - integration_token: Optional[str] = Field( - None, description="Vantage integration token" + integration_token_masked: Optional[str] = Field( + None, + description="Masked integration token showing only first 4 and last 4 characters", ) base_url: Optional[str] = Field(None, description="Vantage API base URL") status: Optional[str] = Field(None, description="Configuration status") From 9cc6df6b8d1a042ce28d80c1a57d3e2c0c3b3fd4 Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 14:51:03 +0530 Subject: [PATCH 017/289] Fix Greptile round 4: preserve backward compat, add guards, fix defaults - Revert FocusExportEngine.dry_run_export_usage_data to use original raw column names (spend, total_tokens, team_id, model) preserving backward compatibility for existing callers - Vantage dry-run endpoint computes its own summary from FOCUS columns independently, avoiding coupling to the engine method - Set VantageExportRequest.limit default to 500 (was None) matching docstring - Add empty-settings guard in /vantage/export returning 404 instead of deferring ValueError to runtime - Fix misleading docstring in _build_tags_expr about Rust-level execution - Clarify Tags schema comment: parquet is self-describing so existing exports are unaffected Co-Authored-By: Claude Opus 4.6 --- litellm/integrations/focus/export_engine.py | 7 ++++--- litellm/integrations/focus/schema.py | 5 ++++- litellm/integrations/focus/transformer.py | 6 ++++-- litellm/proxy/spend_tracking/vantage_endpoints.py | 10 +++++++++- litellm/types/proxy/vantage_endpoints.py | 2 +- 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/litellm/integrations/focus/export_engine.py b/litellm/integrations/focus/export_engine.py index 0cad1b3acd..1f51e1bac9 100644 --- a/litellm/integrations/focus/export_engine.py +++ b/litellm/integrations/focus/export_engine.py @@ -55,9 +55,10 @@ class FocusExportEngine: summary = { "total_records": len(normalized), - "total_spend": self._sum_column(normalized, "BilledCost"), - "unique_teams": self._count_unique(normalized, "SubAccountId"), - "unique_models": self._count_unique(normalized, "ResourceType"), + "total_spend": self._sum_column(data, "spend"), + "total_tokens": self._sum_column(data, "total_tokens"), + "unique_teams": self._count_unique(data, "team_id"), + "unique_models": self._count_unique(data, "model"), } return { diff --git a/litellm/integrations/focus/schema.py b/litellm/integrations/focus/schema.py index 127e8ee03a..c06ca9982a 100644 --- a/litellm/integrations/focus/schema.py +++ b/litellm/integrations/focus/schema.py @@ -45,7 +45,10 @@ FOCUS_NORMALIZED_SCHEMA = pl.Schema( ("SubAccountType", pl.String), # Changed from pl.Object to pl.String to hold JSON metadata # (team_id, user_id, etc.) needed by Vantage Token Allocation. - # Previously Tags was always None so no existing data is lost. + # This schema is only used for creating empty DataFrames (e.g. + # when transform() receives no rows). Parquet files are + # self-describing and embed their own schema, so existing S3 + # exports are unaffected. Previously Tags was always None. ("Tags", pl.String), ] ) diff --git a/litellm/integrations/focus/transformer.py b/litellm/integrations/focus/transformer.py index adac158651..b7d28e3dbb 100644 --- a/litellm/integrations/focus/transformer.py +++ b/litellm/integrations/focus/transformer.py @@ -25,8 +25,10 @@ _TAG_KEYS = ( def _build_tags_expr(available_keys: list[str]) -> pl.Expr: """Build a Polars expression that produces a JSON Tags string per row. - Uses ``pl.struct`` + ``map_elements`` so the heavy iteration stays inside - Polars rather than materialising every row to a Python dict first. + Uses ``pl.struct`` + ``map_elements`` to avoid materialising the entire + DataFrame to a list of Python dicts. The JSON serialisation callback + still runs in Python (GIL-bound), but struct-packing and loop dispatch + are handled by Polars' Rust engine. """ def _struct_to_json(row: dict) -> str: diff --git a/litellm/proxy/spend_tracking/vantage_endpoints.py b/litellm/proxy/spend_tracking/vantage_endpoints.py index d3d6787e5f..d354ed2962 100644 --- a/litellm/proxy/spend_tracking/vantage_endpoints.py +++ b/litellm/proxy/spend_tracking/vantage_endpoints.py @@ -388,7 +388,8 @@ async def vantage_dry_run_export( usage_sample = data.head(min(50, len(data))).to_dicts() if not data.is_empty() else [] normalized_sample = normalized.head(min(50, len(normalized))).to_dicts() if not normalized.is_empty() else [] - # Use the same column names as FocusExportEngine.dry_run_export_usage_data + # Compute summary from the FOCUS-normalized DataFrame. + # These use post-transform column names specific to this endpoint. summary = { "total_records": len(normalized), "total_spend": FocusExportEngine._sum_column(normalized, "BilledCost"), @@ -459,6 +460,13 @@ async def vantage_export( logger = _get_registered_vantage_logger() if logger is None: settings = await _get_vantage_settings() + if not settings: + raise HTTPException( + status_code=404, + detail={ + "error": "Vantage settings not found. Please initialize settings first using /vantage/init" + }, + ) logger = VantageLogger( api_key=settings.get("api_key"), integration_token=settings.get("integration_token"), diff --git a/litellm/types/proxy/vantage_endpoints.py b/litellm/types/proxy/vantage_endpoints.py index 165c21316b..ce2bad84e3 100644 --- a/litellm/types/proxy/vantage_endpoints.py +++ b/litellm/types/proxy/vantage_endpoints.py @@ -32,7 +32,7 @@ class VantageExportRequest(BaseModel): """Request model for Vantage export operations""" limit: Optional[int] = Field( - None, description="Optional limit on number of records to export" + 500, description="Limit on number of records to export (default: 500)" ) start_time_utc: Optional[datetime] = Field( None, description="Start time for data export in UTC" From 622d5dabba0dcc676247069f2891f3ef1dc9fb0a Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 14:59:52 +0530 Subject: [PATCH 018/289] Fix HTTPException swallowed as 500 in /vantage/export endpoint Add missing `except HTTPException: raise` guard so intentional 404 responses (e.g. when settings are not configured) are not caught by the generic Exception handler and re-raised as 500 errors. Co-Authored-By: Claude Opus 4.6 --- litellm/proxy/spend_tracking/vantage_endpoints.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/litellm/proxy/spend_tracking/vantage_endpoints.py b/litellm/proxy/spend_tracking/vantage_endpoints.py index d354ed2962..e497e42e69 100644 --- a/litellm/proxy/spend_tracking/vantage_endpoints.py +++ b/litellm/proxy/spend_tracking/vantage_endpoints.py @@ -487,6 +487,8 @@ async def vantage_export( summary=None, ) + except HTTPException: + raise except Exception as e: verbose_proxy_logger.error(f"Error performing Vantage export: {str(e)}") raise HTTPException( From 230c85313b9a424652041f51263bf53b0c78664b Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 15:10:53 +0530 Subject: [PATCH 019/289] Fix dry-run HTTPException guard and VantageLogger instance detection - Add missing except HTTPException: raise in vantage_dry_run_export (consistent with all other endpoints in the file) - Fix is_vantage_setup_in_config() to detect both the string "vantage" and VantageLogger instances in litellm.callbacks, preventing duplicate logger registration on startup Co-Authored-By: Claude Opus 4.6 --- litellm/proxy/spend_tracking/vantage_endpoints.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/litellm/proxy/spend_tracking/vantage_endpoints.py b/litellm/proxy/spend_tracking/vantage_endpoints.py index e497e42e69..f478ba5160 100644 --- a/litellm/proxy/spend_tracking/vantage_endpoints.py +++ b/litellm/proxy/spend_tracking/vantage_endpoints.py @@ -276,10 +276,13 @@ async def is_vantage_setup_in_db() -> bool: def is_vantage_setup_in_config() -> bool: - """Check if Vantage is setup in config.yaml or environment variables.""" - import litellm + """Check if Vantage is setup in config.yaml, environment variables, or programmatically.""" + from litellm.integrations.vantage.vantage_logger import VantageLogger - return "vantage" in litellm.callbacks + for cb in litellm.callbacks: + if cb == "vantage" or isinstance(cb, VantageLogger): + return True + return False async def is_vantage_setup() -> bool: @@ -412,6 +415,8 @@ async def vantage_dry_run_export( summary=summary, ) + except HTTPException: + raise except Exception as e: verbose_proxy_logger.error( f"Error performing Vantage dry run export: {str(e)}" From 9e623ceaff0cb30a261e5241cdd356a37932fe58 Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 15:16:49 +0530 Subject: [PATCH 020/289] Remove redundant empty-frame guard in FocusCsvSerializer Polars write_csv already handles empty DataFrames correctly (outputs header-only CSV), so the conditional branch was a no-op. Co-Authored-By: Claude Opus 4.6 --- litellm/integrations/focus/serializers/csv.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/litellm/integrations/focus/serializers/csv.py b/litellm/integrations/focus/serializers/csv.py index 30e7f3283d..320c99517d 100644 --- a/litellm/integrations/focus/serializers/csv.py +++ b/litellm/integrations/focus/serializers/csv.py @@ -16,7 +16,6 @@ class FocusCsvSerializer(FocusSerializer): def serialize(self, frame: pl.DataFrame) -> bytes: """Encode the provided frame as a CSV payload.""" - target = frame if not frame.is_empty() else pl.DataFrame(schema=frame.schema) buffer = io.BytesIO() - target.write_csv(buffer) + frame.write_csv(buffer) return buffer.getvalue() From 25c865876188959fd141435391ac0c0636a3e50d Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 15:34:24 +0530 Subject: [PATCH 021/289] Fix oversized-row handling, batch error resilience, and callback registration Vantage destination: - Skip individual CSV rows exceeding 2MB limit with a warning instead of uploading an oversized batch that Vantage would reject - Wrap each batch upload in try/except so remaining batches continue on failure; re-raise the first error after all batches are attempted Callback registration: - Use litellm.logging_callback_manager.add_litellm_callback() instead of raw litellm.callbacks.append() for DB-bootstrapped VantageLogger, ensuring proper dedup and manager visibility - Add "vantage" init handler in litellm_logging.py (both creation and lookup branches) so config.yaml string callbacks are properly resolved Co-Authored-By: Claude Opus 4.6 --- .../focus/destinations/vantage_destination.py | 49 +++++++++++++++---- litellm/litellm_core_utils/litellm_logging.py | 15 ++++++ litellm/proxy/proxy_server.py | 4 +- 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/litellm/integrations/focus/destinations/vantage_destination.py b/litellm/integrations/focus/destinations/vantage_destination.py index e2a21c773f..59c4e0cdb9 100644 --- a/litellm/integrations/focus/destinations/vantage_destination.py +++ b/litellm/integrations/focus/destinations/vantage_destination.py @@ -99,26 +99,41 @@ class FocusVantageDestination(FocusDestination): async def _upload_batched( self, client: httpx.AsyncClient, csv_bytes: bytes, filename: str ) -> None: - """Split the CSV into batches and upload each.""" + """Split the CSV into batches and upload each. + + Continues uploading remaining batches even if one fails, then raises + the first error encountered so callers know the export was partial. + """ lines = csv_bytes.split(b"\n") header = lines[0] data_lines = [line for line in lines[1:] if line.strip()] + first_error: Optional[Exception] = None batch_num = 0 for start in range(0, len(data_lines), VANTAGE_MAX_ROWS_PER_UPLOAD): batch_lines = data_lines[start : start + VANTAGE_MAX_ROWS_PER_UPLOAD] batch_csv = header + b"\n" + b"\n".join(batch_lines) + b"\n" - # If a single batch still exceeds 2 MB, split further by size - if len(batch_csv) > VANTAGE_MAX_BYTES_PER_UPLOAD: - await self._upload_size_limited( - client, header, batch_lines, filename, batch_num + try: + # If a single batch still exceeds 2 MB, split further by size + if len(batch_csv) > VANTAGE_MAX_BYTES_PER_UPLOAD: + await self._upload_size_limited( + client, header, batch_lines, filename, batch_num + ) + else: + batch_filename = f"{filename}.part{batch_num}" + await self._upload_csv(client, batch_csv, batch_filename) + except Exception as e: + verbose_logger.error( + "Vantage destination: batch %d failed: %s", batch_num, e ) - else: - batch_filename = f"{filename}.part{batch_num}" - await self._upload_csv(client, batch_csv, batch_filename) + if first_error is None: + first_error = e batch_num += 1 + if first_error is not None: + raise first_error + async def _upload_size_limited( self, client: httpx.AsyncClient, @@ -127,19 +142,33 @@ class FocusVantageDestination(FocusDestination): filename: str, batch_offset: int, ) -> None: - """Upload lines in chunks that stay under the 2 MB size limit.""" + """Upload lines in chunks that stay under the 2 MB size limit. + + Individual rows that exceed the limit on their own are skipped with + a warning — they cannot be split further. + """ current_chunk: list[bytes] = [] current_size = len(header) + 1 # header + newline sub_batch = 0 + header_size = len(header) + 1 for line in data_lines: line_size = len(line) + 1 # line + newline + + # Skip individual rows that exceed the limit on their own + if header_size + line_size > VANTAGE_MAX_BYTES_PER_UPLOAD: + verbose_logger.warning( + "Vantage destination: skipping oversized row (%d bytes)", + line_size, + ) + continue + if current_size + line_size > VANTAGE_MAX_BYTES_PER_UPLOAD and current_chunk: batch_csv = header + b"\n" + b"\n".join(current_chunk) + b"\n" batch_filename = f"{filename}.part{batch_offset}_{sub_batch}" await self._upload_csv(client, batch_csv, batch_filename) current_chunk = [] - current_size = len(header) + 1 + current_size = header_size sub_batch += 1 current_chunk.append(line) current_size += line_size diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index 6f587abcdf..7157f4cb63 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -3873,6 +3873,15 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 focus_logger = FocusLogger() _in_memory_loggers.append(focus_logger) return focus_logger # type: ignore + elif logging_integration == "vantage": + from litellm.integrations.vantage.vantage_logger import VantageLogger + + for callback in _in_memory_loggers: + if isinstance(callback, VantageLogger): + return callback # type: ignore + vantage_logger = VantageLogger() + _in_memory_loggers.append(vantage_logger) + return vantage_logger # type: ignore elif logging_integration == "deepeval": for callback in _in_memory_loggers: if isinstance(callback, DeepEvalLogger): @@ -4243,6 +4252,12 @@ def get_custom_logger_compatible_class( # noqa: PLR0915 for callback in _in_memory_loggers: if isinstance(callback, FocusLogger): return callback + elif logging_integration == "vantage": + from litellm.integrations.vantage.vantage_logger import VantageLogger + + for callback in _in_memory_loggers: + if isinstance(callback, VantageLogger): + return callback elif logging_integration == "deepeval": for callback in _in_memory_loggers: if isinstance(callback, DeepEvalLogger): diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 9bd4cd7f14..c71df3a2ce 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -6152,7 +6152,9 @@ class ProxyStartupEvent: integration_token=db_settings.get("integration_token"), base_url=db_settings.get("base_url"), ) - litellm.callbacks.append(vantage_logger) # type: ignore[arg-type] + litellm.logging_callback_manager.add_litellm_callback( + vantage_logger + ) except Exception as e: verbose_proxy_logger.warning( "Failed to register VantageLogger from DB settings: %s", e From d35abfb55f926ae784b864356531923d649434ef Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 16:06:59 +0530 Subject: [PATCH 022/289] Fix data truncation, sub-batch resilience, and env var safety - Split VantageExportRequest (limit=None) and VantageDryRunRequest (limit=500) so actual exports don't silently truncate large datasets - Add try/except around each sub-batch upload in _upload_size_limited, consistent with _upload_batched's continue-on-failure guarantee - Guard VANTAGE_EXPORT_INTERVAL_SECONDS against non-numeric values with try/except instead of bare int() cast Co-Authored-By: Claude Opus 4.6 --- .../focus/destinations/vantage_destination.py | 28 +++++++++++++++++-- .../integrations/vantage/vantage_logger.py | 10 ++++++- .../proxy/spend_tracking/vantage_endpoints.py | 5 ++-- litellm/types/proxy/vantage_endpoints.py | 12 ++++++-- 4 files changed, 47 insertions(+), 8 deletions(-) diff --git a/litellm/integrations/focus/destinations/vantage_destination.py b/litellm/integrations/focus/destinations/vantage_destination.py index 59c4e0cdb9..0e06c8f441 100644 --- a/litellm/integrations/focus/destinations/vantage_destination.py +++ b/litellm/integrations/focus/destinations/vantage_destination.py @@ -145,12 +145,15 @@ class FocusVantageDestination(FocusDestination): """Upload lines in chunks that stay under the 2 MB size limit. Individual rows that exceed the limit on their own are skipped with - a warning — they cannot be split further. + a warning — they cannot be split further. Sub-batch failures are + recorded and the first error is re-raised after all sub-batches have + been attempted, consistent with ``_upload_batched``. """ current_chunk: list[bytes] = [] current_size = len(header) + 1 # header + newline sub_batch = 0 header_size = len(header) + 1 + first_error: Optional[Exception] = None for line in data_lines: line_size = len(line) + 1 # line + newline @@ -166,7 +169,15 @@ class FocusVantageDestination(FocusDestination): if current_size + line_size > VANTAGE_MAX_BYTES_PER_UPLOAD and current_chunk: batch_csv = header + b"\n" + b"\n".join(current_chunk) + b"\n" batch_filename = f"{filename}.part{batch_offset}_{sub_batch}" - await self._upload_csv(client, batch_csv, batch_filename) + try: + await self._upload_csv(client, batch_csv, batch_filename) + except Exception as e: + verbose_logger.error( + "Vantage destination: sub-batch %s failed: %s", + batch_filename, e, + ) + if first_error is None: + first_error = e current_chunk = [] current_size = header_size sub_batch += 1 @@ -176,4 +187,15 @@ class FocusVantageDestination(FocusDestination): if current_chunk: batch_csv = header + b"\n" + b"\n".join(current_chunk) + b"\n" batch_filename = f"{filename}.part{batch_offset}_{sub_batch}" - await self._upload_csv(client, batch_csv, batch_filename) + try: + await self._upload_csv(client, batch_csv, batch_filename) + except Exception as e: + verbose_logger.error( + "Vantage destination: sub-batch %s failed: %s", + batch_filename, e, + ) + if first_error is None: + first_error = e + + if first_error is not None: + raise first_error diff --git a/litellm/integrations/vantage/vantage_logger.py b/litellm/integrations/vantage/vantage_logger.py index 01529d537f..df51bb7286 100644 --- a/litellm/integrations/vantage/vantage_logger.py +++ b/litellm/integrations/vantage/vantage_logger.py @@ -53,7 +53,15 @@ class VantageLogger(FocusLogger): ).lower() raw_interval = interval_seconds or os.getenv("VANTAGE_EXPORT_INTERVAL_SECONDS") - resolved_interval = int(raw_interval) if raw_interval is not None else None + resolved_interval: Optional[int] = None + if raw_interval is not None: + try: + resolved_interval = int(raw_interval) + except (ValueError, TypeError): + verbose_logger.warning( + "Invalid VANTAGE_EXPORT_INTERVAL_SECONDS value: %s, ignoring", + raw_interval, + ) destination_config: Dict[str, Any] = {} if resolved_api_key: diff --git a/litellm/proxy/spend_tracking/vantage_endpoints.py b/litellm/proxy/spend_tracking/vantage_endpoints.py index f478ba5160..cd78cf7ebd 100644 --- a/litellm/proxy/spend_tracking/vantage_endpoints.py +++ b/litellm/proxy/spend_tracking/vantage_endpoints.py @@ -12,6 +12,7 @@ from litellm.proxy.common_utils.encrypt_decrypt_utils import ( encrypt_value_helper, ) from litellm.types.proxy.vantage_endpoints import ( + VantageDryRunRequest, VantageExportRequest, VantageExportResponse, VantageInitRequest, @@ -356,7 +357,7 @@ async def init_vantage_settings( response_model=VantageExportResponse, ) async def vantage_dry_run_export( - request: VantageExportRequest, + request: VantageDryRunRequest, user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth), ): """ @@ -365,7 +366,7 @@ async def vantage_dry_run_export( Returns the data that would be exported without actually sending it to Vantage. Parameters: - - limit: Optional limit on number of records to process (default: 500) + - limit: Limit on number of records to preview (default: 500) Only admin users can perform Vantage exports. """ diff --git a/litellm/types/proxy/vantage_endpoints.py b/litellm/types/proxy/vantage_endpoints.py index ce2bad84e3..12d9099f81 100644 --- a/litellm/types/proxy/vantage_endpoints.py +++ b/litellm/types/proxy/vantage_endpoints.py @@ -29,10 +29,10 @@ class VantageInitResponse(BaseModel): class VantageExportRequest(BaseModel): - """Request model for Vantage export operations""" + """Request model for Vantage export operations (actual export, no default limit)""" limit: Optional[int] = Field( - 500, description="Limit on number of records to export (default: 500)" + None, description="Optional limit on number of records to export (default: no limit)" ) start_time_utc: Optional[datetime] = Field( None, description="Start time for data export in UTC" @@ -42,6 +42,14 @@ class VantageExportRequest(BaseModel): ) +class VantageDryRunRequest(BaseModel): + """Request model for Vantage dry-run operations (capped for preview)""" + + limit: Optional[int] = Field( + 500, description="Limit on number of records to preview (default: 500)" + ) + + class VantageExportResponse(BaseModel): """Response model for Vantage export operations""" From 9200b2807899a267e3ce5e64dbaa70fca244478c Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 16:31:30 +0530 Subject: [PATCH 023/289] Fix dry-run summary alignment, token logging, and upload error handling - Align dry-run summary to use pre-transform columns (spend, total_tokens, team_id, model) matching FocusExportEngine internals - Reduce token exposure in debug logs to first 4 chars - Wrap raise_for_status in try/except to log httpx errors before re-raising Co-Authored-By: Claude Opus 4.6 --- .../focus/destinations/vantage_destination.py | 10 +++++++++- litellm/integrations/vantage/vantage_logger.py | 2 +- litellm/proxy/spend_tracking/vantage_endpoints.py | 11 ++++++----- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/litellm/integrations/focus/destinations/vantage_destination.py b/litellm/integrations/focus/destinations/vantage_destination.py index 0e06c8f441..8275c0690b 100644 --- a/litellm/integrations/focus/destinations/vantage_destination.py +++ b/litellm/integrations/focus/destinations/vantage_destination.py @@ -88,7 +88,15 @@ class FocusVantageDestination(FocusDestination): headers=headers, files={"file": (filename, csv_bytes, "text/csv")}, ) - response.raise_for_status() + try: + response.raise_for_status() + except httpx.HTTPStatusError as e: + verbose_logger.error( + "Vantage destination: upload failed for %s — %s", + filename, + e, + ) + raise verbose_logger.debug( "Vantage destination: uploaded %d bytes (%s)", diff --git a/litellm/integrations/vantage/vantage_logger.py b/litellm/integrations/vantage/vantage_logger.py index df51bb7286..5dbcce8c33 100644 --- a/litellm/integrations/vantage/vantage_logger.py +++ b/litellm/integrations/vantage/vantage_logger.py @@ -83,7 +83,7 @@ class VantageLogger(FocusLogger): verbose_logger.debug( "VantageLogger initialized (integration_token=%s)", - resolved_token[:8] + "..." if resolved_token else "None", + resolved_token[:4] + "***" if resolved_token and len(resolved_token) > 4 else "***", ) @staticmethod diff --git a/litellm/proxy/spend_tracking/vantage_endpoints.py b/litellm/proxy/spend_tracking/vantage_endpoints.py index cd78cf7ebd..4a11bb0e9d 100644 --- a/litellm/proxy/spend_tracking/vantage_endpoints.py +++ b/litellm/proxy/spend_tracking/vantage_endpoints.py @@ -392,13 +392,14 @@ async def vantage_dry_run_export( usage_sample = data.head(min(50, len(data))).to_dicts() if not data.is_empty() else [] normalized_sample = normalized.head(min(50, len(normalized))).to_dicts() if not normalized.is_empty() else [] - # Compute summary from the FOCUS-normalized DataFrame. - # These use post-transform column names specific to this endpoint. + # Use the same pre-transform column names as + # FocusExportEngine.dry_run_export_usage_data for consistency. summary = { "total_records": len(normalized), - "total_spend": FocusExportEngine._sum_column(normalized, "BilledCost"), - "unique_teams": FocusExportEngine._count_unique(normalized, "SubAccountId"), - "unique_models": FocusExportEngine._count_unique(normalized, "ResourceType"), + "total_spend": FocusExportEngine._sum_column(data, "spend"), + "total_tokens": FocusExportEngine._sum_column(data, "total_tokens"), + "unique_teams": FocusExportEngine._count_unique(data, "team_id"), + "unique_models": FocusExportEngine._count_unique(data, "model"), } dry_run_result = { From 3cc2ccec4ae2bd001cb9b30ce00f3c0de52204e3 Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 16:42:35 +0530 Subject: [PATCH 024/289] Fix double-scheduling bug and Decimal CSV serialization - Guard FocusLogger.init_focus_export_background_job with exact type check (type(cb) is FocusLogger) to exclude VantageLogger subclass, preventing duplicate hourly exports when VantageLogger is registered programmatically before startup - Cast pl.Decimal columns to Float64 in FocusCsvSerializer so CSV output uses standard floating-point notation instead of fixed-point strings that Vantage's parser may reject Co-Authored-By: Claude Opus 4.6 --- litellm/integrations/focus/focus_logger.py | 14 +++++++++----- litellm/integrations/focus/serializers/csv.py | 12 ++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/litellm/integrations/focus/focus_logger.py b/litellm/integrations/focus/focus_logger.py index ade1cf861b..a1b75fbfff 100644 --- a/litellm/integrations/focus/focus_logger.py +++ b/litellm/integrations/focus/focus_logger.py @@ -137,11 +137,15 @@ class FocusLogger(CustomLogger): ) -> None: """Register the export cron/interval job with the provided scheduler.""" - focus_loggers: List[ - CustomLogger - ] = litellm.logging_callback_manager.get_custom_loggers_for_type( - callback_type=FocusLogger - ) + # Use exact type match to exclude subclasses like VantageLogger, + # which have their own dedicated scheduling method. + focus_loggers: List[CustomLogger] = [ + cb + for cb in litellm.logging_callback_manager.get_custom_loggers_for_type( + callback_type=FocusLogger + ) + if type(cb) is FocusLogger + ] if not focus_loggers: verbose_logger.debug( "No Focus export logger registered; skipping scheduler" diff --git a/litellm/integrations/focus/serializers/csv.py b/litellm/integrations/focus/serializers/csv.py index 320c99517d..8e33c557be 100644 --- a/litellm/integrations/focus/serializers/csv.py +++ b/litellm/integrations/focus/serializers/csv.py @@ -16,6 +16,18 @@ class FocusCsvSerializer(FocusSerializer): def serialize(self, frame: pl.DataFrame) -> bytes: """Encode the provided frame as a CSV payload.""" + # Cast Decimal columns to Float64 so CSV output uses standard + # floating-point notation (e.g. "1.5") instead of fixed-point + # strings (e.g. "1.500000") that some parsers may reject. + decimal_cols = [ + col + for col, dtype in zip(frame.columns, frame.dtypes) + if isinstance(dtype, pl.Decimal) + ] + if decimal_cols: + frame = frame.with_columns( + [pl.col(c).cast(pl.Float64) for c in decimal_cols] + ) buffer = io.BytesIO() frame.write_csv(buffer) return buffer.getvalue() From 4a9d03f1b11917a82a540c6166cd4d5b4767d185 Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 17:01:16 +0530 Subject: [PATCH 025/289] Fix FocusLogger dedup to use exact type match in litellm_logging.py Use `type(cb) is FocusLogger` instead of `isinstance(cb, FocusLogger)` in both _init_custom_logger_compatible_class and get_custom_logger_compatible_class so that a VantageLogger already in _in_memory_loggers is not incorrectly returned for a "focus" lookup. This ensures users with both "vantage" and "focus" in success_callbacks get separate loggers for each export destination. Co-Authored-By: Claude Opus 4.6 --- litellm/litellm_core_utils/litellm_logging.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index 7157f4cb63..81f85e3d5b 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -3868,7 +3868,7 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 from litellm.integrations.focus.focus_logger import FocusLogger for callback in _in_memory_loggers: - if isinstance(callback, FocusLogger): + if type(callback) is FocusLogger: # exact match; exclude subclasses like VantageLogger return callback # type: ignore focus_logger = FocusLogger() _in_memory_loggers.append(focus_logger) @@ -4250,7 +4250,7 @@ def get_custom_logger_compatible_class( # noqa: PLR0915 from litellm.integrations.focus.focus_logger import FocusLogger for callback in _in_memory_loggers: - if isinstance(callback, FocusLogger): + if type(callback) is FocusLogger: # exact match; exclude subclasses like VantageLogger return callback elif logging_integration == "vantage": from litellm.integrations.vantage.vantage_logger import VantageLogger From 212cd0e4aadae0522392f9550a0ca4c968061eca Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 17:28:19 +0530 Subject: [PATCH 026/289] Fix pod lock collision, empty credential validation, and interval parsing - Override initialize_focus_export_job in VantageLogger to use VANTAGE_USAGE_DATA_JOB_NAME as the Redis pod lock key, preventing silent export skips when both Focus and Vantage loggers are configured - Add field_validator to VantageInitRequest rejecting empty-string api_key and integration_token at init time instead of at export time - Guard FocusLogger FOCUS_INTERVAL_SECONDS with try/except matching the pattern already used in VantageLogger Co-Authored-By: Claude Opus 4.6 --- litellm/integrations/focus/focus_logger.py | 10 +++++- .../integrations/vantage/vantage_logger.py | 31 +++++++++++++++++++ litellm/types/proxy/vantage_endpoints.py | 9 +++++- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/litellm/integrations/focus/focus_logger.py b/litellm/integrations/focus/focus_logger.py index a1b75fbfff..f461f8c9fa 100644 --- a/litellm/integrations/focus/focus_logger.py +++ b/litellm/integrations/focus/focus_logger.py @@ -53,7 +53,15 @@ class FocusLogger(CustomLogger): if interval_seconds is not None else os.getenv("FOCUS_INTERVAL_SECONDS") ) - self.interval_seconds = int(raw_interval) if raw_interval is not None else None + self.interval_seconds: Optional[int] = None + if raw_interval is not None: + try: + self.interval_seconds = int(raw_interval) + except (ValueError, TypeError): + verbose_logger.warning( + "Invalid FOCUS_INTERVAL_SECONDS value: %s, ignoring", + raw_interval, + ) env_prefix = os.getenv("FOCUS_PREFIX") self.prefix: str = ( prefix if prefix is not None else (env_prefix if env_prefix else "focus_exports") diff --git a/litellm/integrations/vantage/vantage_logger.py b/litellm/integrations/vantage/vantage_logger.py index 5dbcce8c33..6689d93274 100644 --- a/litellm/integrations/vantage/vantage_logger.py +++ b/litellm/integrations/vantage/vantage_logger.py @@ -86,6 +86,37 @@ class VantageLogger(FocusLogger): resolved_token[:4] + "***" if resolved_token and len(resolved_token) > 4 else "***", ) + async def initialize_focus_export_job(self) -> None: + """Override to use the Vantage-specific pod lock key. + + Without this, VantageLogger and FocusLogger would compete for the + same ``FOCUS_USAGE_DATA_JOB_NAME`` lock, causing one to silently + skip its export cycle when both are configured simultaneously. + """ + from litellm.proxy.proxy_server import proxy_logging_obj + + pod_lock_manager = None + if proxy_logging_obj is not None: + writer = getattr(proxy_logging_obj, "db_spend_update_writer", None) + if writer is not None: + pod_lock_manager = getattr(writer, "pod_lock_manager", None) + + if pod_lock_manager and pod_lock_manager.redis_cache: + acquired = await pod_lock_manager.acquire_lock( + cronjob_id=VANTAGE_USAGE_DATA_JOB_NAME + ) + if not acquired: + verbose_logger.debug("Vantage export: unable to acquire pod lock") + return + try: + await self._run_scheduled_export() + finally: + await pod_lock_manager.release_lock( + cronjob_id=VANTAGE_USAGE_DATA_JOB_NAME + ) + else: + await self._run_scheduled_export() + @staticmethod async def init_vantage_background_job( scheduler: AsyncIOScheduler, diff --git a/litellm/types/proxy/vantage_endpoints.py b/litellm/types/proxy/vantage_endpoints.py index 12d9099f81..86b5a26dbc 100644 --- a/litellm/types/proxy/vantage_endpoints.py +++ b/litellm/types/proxy/vantage_endpoints.py @@ -5,7 +5,7 @@ Vantage endpoint types for LiteLLM Proxy from datetime import datetime from typing import Any, Dict, Optional -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, field_validator class VantageInitRequest(BaseModel): @@ -20,6 +20,13 @@ class VantageInitRequest(BaseModel): description="Vantage API base URL (default: https://api.vantage.sh)", ) + @field_validator("api_key", "integration_token") + @classmethod + def must_be_non_empty(cls, v: str) -> str: + if not v.strip(): + raise ValueError("must be a non-empty string") + return v + class VantageInitResponse(BaseModel): """Response model for Vantage initialization""" From 358c2fd033231c31ebc2416943c240999e80aaab Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 17:41:23 +0530 Subject: [PATCH 027/289] Add empty-string credential validator to VantageSettingsUpdate Matches the existing validator on VantageInitRequest so that empty or whitespace-only api_key/integration_token values are rejected at update time rather than silently persisted and failing at the next export. Co-Authored-By: Claude Opus 4.6 --- litellm/types/proxy/vantage_endpoints.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/litellm/types/proxy/vantage_endpoints.py b/litellm/types/proxy/vantage_endpoints.py index 86b5a26dbc..cf4f0a6685 100644 --- a/litellm/types/proxy/vantage_endpoints.py +++ b/litellm/types/proxy/vantage_endpoints.py @@ -95,3 +95,10 @@ class VantageSettingsUpdate(BaseModel): None, description="New Vantage integration token" ) base_url: Optional[str] = Field(None, description="New Vantage API base URL") + + @field_validator("api_key", "integration_token") + @classmethod + def must_be_non_empty(cls, v: Optional[str]) -> Optional[str]: + if v is not None and not v.strip(): + raise ValueError("must be a non-empty string") + return v From ce052d07be9093b85042db1c33c6bbac9c4488d2 Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 18:12:27 +0530 Subject: [PATCH 028/289] Fix test helper hour=23 bug and add row-count batching test - Use timedelta(hours=1) instead of replace(hour=hour+1) in _window() to avoid ValueError when hour=23 - Add test_should_batch_by_row_count covering the >10K rows batching path (previously only the 2 MB size-limit path was tested) Co-Authored-By: Claude Opus 4.6 --- .../focus/test_vantage_destination.py | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/tests/test_litellm/integrations/focus/test_vantage_destination.py b/tests/test_litellm/integrations/focus/test_vantage_destination.py index 181d3d1381..c3fa9bda63 100644 --- a/tests/test_litellm/integrations/focus/test_vantage_destination.py +++ b/tests/test_litellm/integrations/focus/test_vantage_destination.py @@ -2,7 +2,7 @@ from __future__ import annotations -from datetime import datetime, timezone +from datetime import datetime, timedelta, timezone from typing import Any, Dict, List from unittest.mock import AsyncMock, patch @@ -12,12 +12,13 @@ from litellm.integrations.focus.destinations.base import FocusTimeWindow from litellm.integrations.focus.destinations.vantage_destination import ( FocusVantageDestination, VANTAGE_MAX_BYTES_PER_UPLOAD, + VANTAGE_MAX_ROWS_PER_UPLOAD, ) def _window(freq: str = "hourly", hour: int = 5) -> FocusTimeWindow: start = datetime(2024, 1, 2, hour, tzinfo=timezone.utc) - end = start.replace(hour=hour + 1) + end = start + timedelta(hours=1) return FocusTimeWindow(start_time=start, end_time=end, frequency=freq) @@ -136,3 +137,51 @@ async def test_should_batch_large_content(): # Each upload should be within limits for chunk in upload_calls: assert len(chunk) <= VANTAGE_MAX_BYTES_PER_UPLOAD + + +@pytest.mark.asyncio +async def test_should_batch_by_row_count(): + """Verify batching triggers when row count exceeds 10K even if under 2 MB.""" + dest = FocusVantageDestination(prefix="exports", config=_config()) + + header = b"col1" + # Short rows so total size stays well under 2 MB + row = b"x" + num_rows = VANTAGE_MAX_ROWS_PER_UPLOAD + 500 + content = header + b"\n" + b"\n".join([row] * num_rows) + b"\n" + + # Confirm content is under 2 MB but over 10K rows + assert len(content) < VANTAGE_MAX_BYTES_PER_UPLOAD + assert num_rows > VANTAGE_MAX_ROWS_PER_UPLOAD + + upload_calls: List[bytes] = [] + + mock_response = AsyncMock() + mock_response.raise_for_status = lambda: None + + mock_client = AsyncMock() + mock_client.__aenter__ = AsyncMock(return_value=mock_client) + mock_client.__aexit__ = AsyncMock(return_value=False) + + async def capture_post(url, **kwargs): + files = kwargs.get("files", {}) + if "file" in files: + upload_calls.append(files["file"][1]) + return mock_response + + mock_client.post = capture_post + + with patch("litellm.integrations.focus.destinations.vantage_destination.httpx.AsyncClient", return_value=mock_client): + await dest.deliver( + content=content, + time_window=_window(), + filename="usage.csv", + ) + + # Should have made at least 2 uploads due to row count + assert len(upload_calls) >= 2 + # Each batch should have at most 10K data rows (header + data rows + trailing newline) + for chunk in upload_calls: + lines = chunk.split(b"\n") + data_lines = [line for line in lines[1:] if line.strip()] + assert len(data_lines) <= VANTAGE_MAX_ROWS_PER_UPLOAD From 24d4e5bc60bf54156f7d72ed3b31932e2efddcb7 Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 19:28:27 +0530 Subject: [PATCH 029/289] Deregister VantageLogger on delete and add Decimal cast test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DELETE /vantage/delete now removes the in-memory VantageLogger from litellm.callbacks via remove_callbacks_by_type, preventing the scheduler from continuing to fire exports with stale credentials - Add test_should_cast_decimal_columns_to_float covering the Decimal→Float64 cast in FocusCsvSerializer Co-Authored-By: Claude Opus 4.6 --- litellm/proxy/spend_tracking/vantage_endpoints.py | 7 +++++++ .../integrations/focus/test_csv_serializer.py | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/litellm/proxy/spend_tracking/vantage_endpoints.py b/litellm/proxy/spend_tracking/vantage_endpoints.py index 4a11bb0e9d..19859bfb83 100644 --- a/litellm/proxy/spend_tracking/vantage_endpoints.py +++ b/litellm/proxy/spend_tracking/vantage_endpoints.py @@ -547,6 +547,13 @@ async def delete_vantage_settings( where={"param_name": VANTAGE_SETTINGS_PARAM_NAME} ) + # Deregister in-memory VantageLogger so the scheduler stops firing + from litellm.integrations.vantage.vantage_logger import VantageLogger + + litellm.logging_callback_manager.remove_callbacks_by_type( + litellm.callbacks, VantageLogger + ) + verbose_proxy_logger.info("Vantage settings deleted successfully") return VantageInitResponse( diff --git a/tests/test_litellm/integrations/focus/test_csv_serializer.py b/tests/test_litellm/integrations/focus/test_csv_serializer.py index f527a9dceb..f3256808e4 100644 --- a/tests/test_litellm/integrations/focus/test_csv_serializer.py +++ b/tests/test_litellm/integrations/focus/test_csv_serializer.py @@ -30,5 +30,18 @@ def test_should_return_header_only_for_empty_frame(): assert len(lines) == 1 # header only +def test_should_cast_decimal_columns_to_float(): + frame = pl.DataFrame( + {"BilledCost": [1, 2], "ServiceName": ["openai", "anthropic"]} + ).cast({"BilledCost": pl.Decimal(18, 6)}) + serializer = FocusCsvSerializer() + result = serializer.serialize(frame) + + lines = result.decode("utf-8").strip().split("\n") + # Should use floating-point notation (e.g. "1.0") not fixed-point ("1.000000") + assert "1.000000" not in lines[1] + assert lines[1].startswith("1.0,") + + def test_extension_should_be_csv(): assert FocusCsvSerializer.extension == "csv" From e878941da5e037dc615e0a63557176a09dc8e31e Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Wed, 11 Mar 2026 19:42:29 +0530 Subject: [PATCH 030/289] Fix Decimal serialization crash in dry-run endpoint Cast Polars Decimal columns to Float64 before calling .to_dicts() in vantage_dry_run_export so the response contains JSON-serializable float values instead of decimal.Decimal objects that FastAPI cannot encode. Also cast summary totals to float for the same reason. Co-Authored-By: Claude Opus 4.6 --- .../proxy/spend_tracking/vantage_endpoints.py | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/litellm/proxy/spend_tracking/vantage_endpoints.py b/litellm/proxy/spend_tracking/vantage_endpoints.py index 19859bfb83..14c0ebcb54 100644 --- a/litellm/proxy/spend_tracking/vantage_endpoints.py +++ b/litellm/proxy/spend_tracking/vantage_endpoints.py @@ -386,18 +386,35 @@ async def vantage_dry_run_export( database = FocusLiteLLMDatabase() transformer = FocusTransformer() + import polars as pl + data = await database.get_usage_data(limit=request.limit) normalized = transformer.transform(data) - usage_sample = data.head(min(50, len(data))).to_dicts() if not data.is_empty() else [] - normalized_sample = normalized.head(min(50, len(normalized))).to_dicts() if not normalized.is_empty() else [] + def _to_json_safe_dicts(frame: pl.DataFrame) -> list: + """Cast Decimal columns to Float64 so .to_dicts() produces + JSON-serializable float values instead of decimal.Decimal.""" + decimal_cols = [ + col for col, dtype in zip(frame.columns, frame.dtypes) + if isinstance(dtype, pl.Decimal) + ] + if decimal_cols: + frame = frame.with_columns( + [pl.col(c).cast(pl.Float64) for c in decimal_cols] + ) + return frame.to_dicts() + + usage_sample = _to_json_safe_dicts(data.head(min(50, len(data)))) if not data.is_empty() else [] + normalized_sample = _to_json_safe_dicts(normalized.head(min(50, len(normalized)))) if not normalized.is_empty() else [] # Use the same pre-transform column names as # FocusExportEngine.dry_run_export_usage_data for consistency. + total_spend = FocusExportEngine._sum_column(data, "spend") + total_tokens = FocusExportEngine._sum_column(data, "total_tokens") summary = { "total_records": len(normalized), - "total_spend": FocusExportEngine._sum_column(data, "spend"), - "total_tokens": FocusExportEngine._sum_column(data, "total_tokens"), + "total_spend": float(total_spend) if total_spend is not None else 0, + "total_tokens": float(total_tokens) if total_tokens is not None else 0, "unique_teams": FocusExportEngine._count_unique(data, "team_id"), "unique_models": FocusExportEngine._count_unique(data, "model"), } From a4f94b241b6f106dbba73ce5244891b426335e63 Mon Sep 17 00:00:00 2001 From: michelligabriele Date: Fri, 13 Mar 2026 04:32:36 +0100 Subject: [PATCH 031/289] fix(proxy): prevent duplicate callback logs for pass-through endpoint failures Pass-through endpoint failures fired both async_failure_handler and async_post_call_failure_hook, causing duplicate logs in callback integrations. Add pass-through guards to the failure path, matching the existing success path behavior. --- litellm/litellm_core_utils/litellm_logging.py | 5 +- .../pass_through_endpoints.py | 8 ++ litellm/proxy/utils.py | 19 ++- tests/proxy_unit_tests/test_proxy_utils.py | 131 ++++++++++++++++++ .../test_litellm_logging.py | 65 +++++++++ 5 files changed, 223 insertions(+), 5 deletions(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index e22d057bb6..24fcbde1a0 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -2920,7 +2920,10 @@ class Logging(LiteLLMLoggingBaseClass): callback_func=callback, ) if ( - isinstance(callback, CustomLogger) and is_sync_request + isinstance(callback, CustomLogger) + and is_sync_request + and self.call_type + != CallTypes.pass_through.value # pass-through endpoints call async_log_failure_event ): # custom logger class callback.log_failure_event( start_time=start_time, diff --git a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py b/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py index 9e287c2bec..871d9848ab 100644 --- a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py +++ b/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py @@ -961,6 +961,10 @@ async def pass_through_request( # noqa: PLR0915 if kwargs: for key, value in kwargs.items(): request_payload[key] = value + # Ensure the original logging_obj is in request_payload so + # _handle_logging_proxy_only_error reuses it (preserving call_type) + if logging_obj is not None: + request_payload["litellm_logging_obj"] = logging_obj if ( "model" not in request_payload @@ -1703,6 +1707,8 @@ async def websocket_passthrough_request( # noqa: PLR0915 if kwargs: for key, value in kwargs.items(): request_payload[key] = value + if logging_obj is not None: + request_payload["litellm_logging_obj"] = logging_obj # Log the connection failure using the same pattern as HTTP await proxy_logging_obj.post_call_failure_hook( @@ -1729,6 +1735,8 @@ async def websocket_passthrough_request( # noqa: PLR0915 if kwargs: for key, value in kwargs.items(): request_payload[key] = value + if logging_obj is not None: + request_payload["litellm_logging_obj"] = logging_obj # Log the unexpected error using the same pattern as HTTP await proxy_logging_obj.post_call_failure_hook( diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index b9a1bfb906..695f75b86e 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -1849,7 +1849,7 @@ class ProxyLogging: for k, v in request_data.items(): if k in litellm_param_keys: _litellm_params[k] = v - elif k != "model" and k != "user": + elif k not in ("model", "user", "litellm_logging_obj"): _optional_params[k] = v litellm_logging_obj.update_environment_variables( @@ -1865,20 +1865,31 @@ class ProxyLogging: ): input = request_data["messages"] litellm_logging_obj.model_call_details["messages"] = input - litellm_logging_obj.call_type = CallTypes.acompletion.value + if litellm_logging_obj.call_type != CallTypes.pass_through.value: + litellm_logging_obj.call_type = CallTypes.acompletion.value elif "prompt" in request_data and isinstance(request_data["prompt"], str): input = request_data["prompt"] litellm_logging_obj.model_call_details["prompt"] = input - litellm_logging_obj.call_type = CallTypes.atext_completion.value + if litellm_logging_obj.call_type != CallTypes.pass_through.value: + litellm_logging_obj.call_type = CallTypes.atext_completion.value elif "input" in request_data and isinstance(request_data["input"], list): input = request_data["input"] litellm_logging_obj.model_call_details["input"] = input - litellm_logging_obj.call_type = CallTypes.aembedding.value + if litellm_logging_obj.call_type != CallTypes.pass_through.value: + litellm_logging_obj.call_type = CallTypes.aembedding.value litellm_logging_obj.pre_call( input=input, api_key="", ) + # For pass-through endpoints, skip async_failure_handler and + # failure_handler here. The callback loop in post_call_failure_hook + # will call async_post_call_failure_hook on each CustomLogger, + # which handles logging. Firing both paths would produce duplicate + # entries in Datadog, Arize, and other callback integrations. + if litellm_logging_obj.call_type == CallTypes.pass_through.value: + return + # log the custom exception await litellm_logging_obj.async_failure_handler( exception=original_exception, diff --git a/tests/proxy_unit_tests/test_proxy_utils.py b/tests/proxy_unit_tests/test_proxy_utils.py index b2ed4f9103..2f82e1d194 100644 --- a/tests/proxy_unit_tests/test_proxy_utils.py +++ b/tests/proxy_unit_tests/test_proxy_utils.py @@ -2385,3 +2385,134 @@ async def test_during_call_hook_parallel_execution_with_error(): assert "Guardrail violation detected!" in str(exc_info.value) finally: litellm.callbacks = original_callbacks + + +@pytest.mark.asyncio +async def test_handle_logging_proxy_only_error_preserves_pass_through_call_type(): + """Ensure _handle_logging_proxy_only_error does not overwrite call_type + when the logging object is already marked as pass_through_endpoint. + """ + from litellm.caching.caching import DualCache + from litellm.litellm_core_utils.litellm_logging import Logging + from litellm.proxy.utils import ProxyLogging + from litellm.types.utils import CallTypes + + logging_obj = Logging( + model="unknown", + messages=[{"role": "user", "content": "test"}], + stream=False, + call_type="pass_through_endpoint", + start_time=datetime.now(), + litellm_call_id="test-call-id", + function_id="test-function-id", + ) + + request_data = { + "litellm_logging_obj": logging_obj, + "messages": [{"role": "user", "content": "test"}], + "model": "claude-3-5-sonnet", + } + + cache = DualCache() + proxy_logging = ProxyLogging(user_api_key_cache=cache) + + with patch.object(logging_obj, "async_failure_handler", new_callable=AsyncMock): + with patch.object(logging_obj, "failure_handler"): + await proxy_logging._handle_logging_proxy_only_error( + request_data=request_data, + user_api_key_dict=UserAPIKeyAuth( + api_key="test_key", token="test_token" + ), + original_exception=Exception("test error"), + ) + + assert logging_obj.call_type == CallTypes.pass_through.value + + +@pytest.mark.asyncio +async def test_litellm_logging_obj_excluded_from_optional_params(): + """Ensure litellm_logging_obj is excluded from _optional_params to prevent + circular references in model_call_details. + """ + from litellm.caching.caching import DualCache + from litellm.litellm_core_utils.litellm_logging import Logging + from litellm.proxy.utils import ProxyLogging + + logging_obj = Logging( + model="unknown", + messages=[{"role": "user", "content": "test"}], + stream=False, + call_type="pass_through_endpoint", + start_time=datetime.now(), + litellm_call_id="test-call-id", + function_id="test-function-id", + ) + + request_data = { + "litellm_logging_obj": logging_obj, + "messages": [{"role": "user", "content": "test"}], + "model": "claude-3-5-sonnet", + } + + cache = DualCache() + proxy_logging = ProxyLogging(user_api_key_cache=cache) + + with patch.object(logging_obj, "async_failure_handler", new_callable=AsyncMock): + with patch.object(logging_obj, "failure_handler"): + await proxy_logging._handle_logging_proxy_only_error( + request_data=request_data, + user_api_key_dict=UserAPIKeyAuth( + api_key="test_key", token="test_token" + ), + original_exception=Exception("test error"), + ) + + assert "litellm_logging_obj" not in logging_obj.model_call_details + + +@pytest.mark.asyncio +async def test_handle_logging_proxy_only_error_skips_handlers_for_pass_through(): + """Ensure _handle_logging_proxy_only_error skips async_failure_handler and + failure_handler for pass-through endpoint errors, so only + async_post_call_failure_hook fires (avoiding duplicate logs). + + Regression test for duplicate Datadog/Arize logs on pass-through failures. + """ + from litellm.caching.caching import DualCache + from litellm.litellm_core_utils.litellm_logging import Logging + from litellm.proxy.utils import ProxyLogging + from litellm.types.utils import CallTypes + + logging_obj = Logging( + model="unknown", + messages=[{"role": "user", "content": "test"}], + stream=False, + call_type="pass_through_endpoint", + start_time=datetime.now(), + litellm_call_id="test-call-id", + function_id="test-function-id", + ) + + cache = DualCache() + proxy_logging = ProxyLogging(user_api_key_cache=cache) + + request_data = { + "litellm_logging_obj": logging_obj, + "messages": [{"role": "user", "content": "test"}], + "model": "claude-3-5-sonnet", + } + + with patch.object(logging_obj, "async_failure_handler", new_callable=AsyncMock) as mock_async: + with patch.object(logging_obj, "failure_handler") as mock_sync: + await proxy_logging._handle_logging_proxy_only_error( + request_data=request_data, + user_api_key_dict=UserAPIKeyAuth( + api_key="test_key", token="test_token" + ), + original_exception=Exception("test error"), + ) + + # Neither handler should fire for pass-through requests + mock_async.assert_not_called() + mock_sync.assert_not_called() + assert logging_obj.call_type == CallTypes.pass_through.value diff --git a/tests/test_litellm/litellm_core_utils/test_litellm_logging.py b/tests/test_litellm/litellm_core_utils/test_litellm_logging.py index f4aeb27b31..482ee049fa 100644 --- a/tests/test_litellm/litellm_core_utils/test_litellm_logging.py +++ b/tests/test_litellm/litellm_core_utils/test_litellm_logging.py @@ -1833,3 +1833,68 @@ def test_function_setup_empty_metadata_falls_back_to_litellm_metadata(): assert metadata is not None assert metadata.get("user_api_key_hash") == "sk-hashed-empty-test" assert metadata.get("user_api_key_team_id") == "team-empty-test" + + +def test_failure_handler_skips_sync_callbacks_for_pass_through_requests(logging_obj): + """Ensure sync failure callbacks are skipped for pass-through endpoint requests. + + Regression test for duplicate Datadog/Arize logs on pass-through endpoint failures. + The async_failure_handler fires async_log_failure_event; the sync failure_handler + must NOT also fire log_failure_event for pass-through requests. + """ + from litellm.integrations.custom_logger import CustomLogger + from litellm.types.utils import CallTypes + + class DummyLogger(CustomLogger): + pass + + logging_obj.call_type = CallTypes.pass_through.value + logging_obj.stream = False + logging_obj.model_call_details["litellm_params"] = {} + logging_obj.litellm_params = {} + + dummy_logger = DummyLogger() + dummy_logger.log_failure_event = MagicMock() + + with patch.object( + logging_obj, + "get_combined_callback_list", + return_value=[dummy_logger], + ): + logging_obj.failure_handler( + exception=Exception("test error"), + traceback_exception="", + ) + + dummy_logger.log_failure_event.assert_not_called() + + +@pytest.mark.parametrize("call_type", ["completion", "acompletion"]) +def test_failure_handler_runs_sync_callbacks_for_non_pass_through_requests( + logging_obj, call_type +): + """Ensure sync failure callbacks still fire for normal (non-pass-through) requests.""" + from litellm.integrations.custom_logger import CustomLogger + + class DummyLogger(CustomLogger): + pass + + logging_obj.call_type = call_type + logging_obj.stream = False + logging_obj.model_call_details["litellm_params"] = {} + logging_obj.litellm_params = {} + + dummy_logger = DummyLogger() + dummy_logger.log_failure_event = MagicMock() + + with patch.object( + logging_obj, + "get_combined_callback_list", + return_value=[dummy_logger], + ): + logging_obj.failure_handler( + exception=Exception("test error"), + traceback_exception="", + ) + + dummy_logger.log_failure_event.assert_called_once() From 583bdb279b36a6ad1dc1113b2ea63cc0f4c05380 Mon Sep 17 00:00:00 2001 From: michelligabriele Date: Fri, 13 Mar 2026 04:53:50 +0100 Subject: [PATCH 032/289] address greptile review: move early return before pre_call, trim comments --- litellm/litellm_core_utils/litellm_logging.py | 2 +- .../pass_through_endpoints.py | 2 -- litellm/proxy/utils.py | 13 +++++-------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index 24fcbde1a0..d091a263df 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -2923,7 +2923,7 @@ class Logging(LiteLLMLoggingBaseClass): isinstance(callback, CustomLogger) and is_sync_request and self.call_type - != CallTypes.pass_through.value # pass-through endpoints call async_log_failure_event + != CallTypes.pass_through.value ): # custom logger class callback.log_failure_event( start_time=start_time, diff --git a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py b/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py index 871d9848ab..0aa9968520 100644 --- a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py +++ b/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py @@ -961,8 +961,6 @@ async def pass_through_request( # noqa: PLR0915 if kwargs: for key, value in kwargs.items(): request_payload[key] = value - # Ensure the original logging_obj is in request_payload so - # _handle_logging_proxy_only_error reuses it (preserving call_type) if logging_obj is not None: request_payload["litellm_logging_obj"] = logging_obj diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index 695f75b86e..b0d709abbb 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -1877,19 +1877,16 @@ class ProxyLogging: litellm_logging_obj.model_call_details["input"] = input if litellm_logging_obj.call_type != CallTypes.pass_through.value: litellm_logging_obj.call_type = CallTypes.aembedding.value + # Pass-through endpoints are logged via the callback loop's + # async_post_call_failure_hook — skip pre_call and failure handlers. + if litellm_logging_obj.call_type == CallTypes.pass_through.value: + return + litellm_logging_obj.pre_call( input=input, api_key="", ) - # For pass-through endpoints, skip async_failure_handler and - # failure_handler here. The callback loop in post_call_failure_hook - # will call async_post_call_failure_hook on each CustomLogger, - # which handles logging. Firing both paths would produce duplicate - # entries in Datadog, Arize, and other callback integrations. - if litellm_logging_obj.call_type == CallTypes.pass_through.value: - return - # log the custom exception await litellm_logging_obj.async_failure_handler( exception=original_exception, From bfcba21564fd993fcc769fe22bdce7674b1ee102 Mon Sep 17 00:00:00 2001 From: michelligabriele Date: Fri, 13 Mar 2026 05:01:50 +0100 Subject: [PATCH 033/289] pop litellm_logging_obj from request_data before callback loop --- litellm/proxy/utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index b0d709abbb..e2df0acd21 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -1729,6 +1729,9 @@ class ProxyLogging: original_exception=original_exception, ) + # Remove before callbacks iterate — not serialisable + request_data.pop("litellm_logging_obj", None) + # Track the first HTTPException returned or raised by any callback transformed_exception: Optional[HTTPException] = None From 45ba9e1f7ef08e747b3e16c124ed76b9f709c1f0 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 13 Mar 2026 11:34:18 +0530 Subject: [PATCH 034/289] fix(anthropic): preserve native tool format when guardrails convert tools for Anthropic Messages API - Keep Anthropic-native tools (tool_search_tool_regex, web_search, bash, etc.) in original format when translating to OpenAI format for guardrails - Convert guardrail-returned tools back from OpenAI to Anthropic format (type=custom for user tools) - Add TOOL_SEARCH_TOOL to ANTHROPIC_HOSTED_TOOLS enum; use prefix matching for native tool detection - Set type=custom explicitly when mapping OpenAI function tools to AnthropicMessagesTool - Add test for Anthropic native tools with guardrails Made-with: Cursor --- .../chat/guardrail_translation/handler.py | 10 ++- litellm/llms/anthropic/chat/transformation.py | 6 +- .../adapters/transformation.py | 9 +++ litellm/types/llms/anthropic.py | 1 + .../test_anthropic_guardrail_handler.py | 63 +++++++++++++++++++ 5 files changed, 87 insertions(+), 2 deletions(-) diff --git a/litellm/llms/anthropic/chat/guardrail_translation/handler.py b/litellm/llms/anthropic/chat/guardrail_translation/handler.py index 0bc0777e37..5372757cbb 100644 --- a/litellm/llms/anthropic/chat/guardrail_translation/handler.py +++ b/litellm/llms/anthropic/chat/guardrail_translation/handler.py @@ -127,7 +127,15 @@ class AnthropicMessagesHandler(BaseTranslation): guardrailed_texts = guardrailed_inputs.get("texts", []) guardrailed_tools = guardrailed_inputs.get("tools") if guardrailed_tools is not None: - data["tools"] = guardrailed_tools + # Convert tools back from OpenAI format to Anthropic format + anthropic_config = AnthropicConfig() + anthropic_tools: List[AllAnthropicToolsValues] = [] + for tool in guardrailed_tools: + converted_tool, mcp_server = anthropic_config._map_tool_helper(tool) + if converted_tool is not None: + anthropic_tools.append(converted_tool) + # Note: MCP servers are handled separately in the main transformation + data["tools"] = anthropic_tools # Step 3: Map guardrail responses back to original message structure await self._apply_guardrail_responses_to_input( diff --git a/litellm/llms/anthropic/chat/transformation.py b/litellm/llms/anthropic/chat/transformation.py index 1b912bfc2a..47cdd8287e 100644 --- a/litellm/llms/anthropic/chat/transformation.py +++ b/litellm/llms/anthropic/chat/transformation.py @@ -55,7 +55,10 @@ from litellm.types.utils import ( CompletionTokensDetailsWrapper, ) from litellm.types.utils import Message as LitellmMessage -from litellm.types.utils import PromptTokensDetailsWrapper, ServerToolUse +from litellm.types.utils import ( + PromptTokensDetailsWrapper, + ServerToolUse, +) from litellm.utils import ( ModelResponse, Usage, @@ -420,6 +423,7 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig): _tool = AnthropicMessagesTool( name=tool["function"]["name"], input_schema=input_anthropic_schema, + type="custom", ) _description = tool["function"].get("description") diff --git a/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py index 43a6fa8045..c1a6bd6750 100644 --- a/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py +++ b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py @@ -68,6 +68,7 @@ from litellm.litellm_core_utils.prompt_templates.common_utils import ( parse_tool_call_arguments, ) from litellm.types.llms.anthropic import ( + ANTHROPIC_HOSTED_TOOLS, AllAnthropicToolsValues, AnthopicMessagesAssistantMessageParam, AnthropicFinishReason, @@ -771,7 +772,15 @@ class LiteLLMAnthropicMessagesAdapter: new_tools: List[ChatCompletionToolParam] = [] tool_name_mapping: Dict[str, str] = {} mapped_tool_params = ["name", "input_schema", "description", "cache_control"] + for tool in tools: + # Check if this is an Anthropic-native tool that should be kept as-is + tool_type = tool.get("type", "") + if any(tool_type.startswith(t.value) for t in ANTHROPIC_HOSTED_TOOLS): + # Keep Anthropic-native tools in their original format + new_tools.append(tool) # type: ignore[arg-type] + continue + original_name = tool["name"] truncated_name = truncate_tool_name(original_name) diff --git a/litellm/types/llms/anthropic.py b/litellm/types/llms/anthropic.py index 478fcbdbd1..37044c2b4f 100644 --- a/litellm/types/llms/anthropic.py +++ b/litellm/types/llms/anthropic.py @@ -639,6 +639,7 @@ class ANTHROPIC_HOSTED_TOOLS(str, Enum): CODE_EXECUTION = "code_execution" WEB_FETCH = "web_fetch" MEMORY = "memory" + TOOL_SEARCH_TOOL = "tool_search_tool" class ANTHROPIC_BETA_HEADER_VALUES(str, Enum): diff --git a/tests/test_litellm/llms/anthropic/chat/guardrail_translation/test_anthropic_guardrail_handler.py b/tests/test_litellm/llms/anthropic/chat/guardrail_translation/test_anthropic_guardrail_handler.py index 82517b7af9..9f70c7371d 100644 --- a/tests/test_litellm/llms/anthropic/chat/guardrail_translation/test_anthropic_guardrail_handler.py +++ b/tests/test_litellm/llms/anthropic/chat/guardrail_translation/test_anthropic_guardrail_handler.py @@ -231,6 +231,69 @@ class TestAnthropicMessagesHandlerInputProcessing: assert result == responses_so_far + @pytest.mark.asyncio + async def test_process_input_messages_with_anthropic_native_tools(self): + """Test that Anthropic native tools (tool_search_tool_regex) are preserved correctly + + This test verifies the fix for the bug where Anthropic native tools like + tool_search_tool_regex_20251119 were being converted to OpenAI format and then + not properly converted back, causing API errors. + + The guardrail converts tools to OpenAI format for processing, then they need to be + converted back to Anthropic format. Native Anthropic tools should be preserved as-is, + while regular tools should be converted to type="custom". + """ + handler = AnthropicMessagesHandler() + guardrail = MockPassThroughGuardrail(guardrail_name="test") + + data = { + "model": "claude-opus-4-6", + "messages": [{"role": "user", "content": "What is the weather in San Francisco?"}], + "tools": [ + { + "type": "tool_search_tool_regex_20251119", + "name": "tool_search_tool_regex" + }, + { + "name": "get_weather", + "description": "Get the weather at a specific location", + "input_schema": { + "type": "object", + "properties": { + "location": {"type": "string"}, + "unit": { + "type": "string", + "enum": ["celsius", "fahrenheit"] + } + }, + "required": ["location"] + }, + "defer_loading": True + } + ] + } + + result = await handler.process_input_messages( + data=data, + guardrail_to_apply=guardrail, + litellm_logging_obj=MagicMock() + ) + + # Verify tools are in correct Anthropic format + tools = result["tools"] + assert len(tools) == 2 + + # First tool should be preserved as Anthropic native tool + assert tools[0]["type"] == "tool_search_tool_regex_20251119" + assert tools[0]["name"] == "tool_search_tool_regex" + + # Second tool should be converted to Anthropic custom tool format + assert tools[1]["type"] == "custom" + assert tools[1]["name"] == "get_weather" + assert tools[1]["description"] == "Get the weather at a specific location" + assert "input_schema" in tools[1] + + if __name__ == "__main__": # Run the tests pytest.main([__file__, "-v"]) From a01248658e498274ae62d8f3edb191e28c74c2f6 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 13 Mar 2026 13:06:18 +0530 Subject: [PATCH 035/289] fix(streaming): preserve upstream custom fields on final chunk Ensure final finish_reason chunks retain non-OpenAI attributes from original provider chunks, including the holding_chunk flush path where delta is non-empty. Add regression tests for both final-chunk branches. Made-with: Cursor --- .../litellm_core_utils/streaming_handler.py | 13 +++- .../test_streaming_handler.py | 73 +++++++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/litellm/litellm_core_utils/streaming_handler.py b/litellm/litellm_core_utils/streaming_handler.py index db2369d03d..6e991e6911 100644 --- a/litellm/litellm_core_utils/streaming_handler.py +++ b/litellm/litellm_core_utils/streaming_handler.py @@ -31,7 +31,7 @@ from litellm.litellm_core_utils.model_response_utils import ( ) from litellm.litellm_core_utils.redact_messages import LiteLLMLoggingObject from litellm.litellm_core_utils.thread_pool_executor import executor -from litellm.types.llms.openai import ChatCompletionChunk +from litellm.types.llms.openai import OpenAIChatCompletionChunk from litellm.types.router import GenericLiteLLMParams from litellm.types.utils import ( Delta, @@ -745,7 +745,7 @@ class CustomStreamWrapper: def copy_model_response_level_provider_specific_fields( self, - original_chunk: Union[ModelResponseStream, ChatCompletionChunk], + original_chunk: Union[ModelResponseStream, OpenAIChatCompletionChunk], model_response: ModelResponseStream, ) -> ModelResponseStream: """ @@ -1012,6 +1012,15 @@ class CustomStreamWrapper: # if delta is None _is_delta_empty = self.is_delta_empty(delta=model_response.choices[0].delta) + # Preserve custom attributes from original chunk (applies to both + # empty and non-empty delta final chunks). + _original_chunk = response_obj.get("original_chunk", None) + if _original_chunk is not None: + preserve_upstream_non_openai_attributes( + model_response=model_response, + original_chunk=_original_chunk, + ) + if _is_delta_empty: model_response.choices[0].delta = Delta( content=None diff --git a/tests/test_litellm/litellm_core_utils/test_streaming_handler.py b/tests/test_litellm/litellm_core_utils/test_streaming_handler.py index 6a64e7020b..5d7b291e7b 100644 --- a/tests/test_litellm/litellm_core_utils/test_streaming_handler.py +++ b/tests/test_litellm/litellm_core_utils/test_streaming_handler.py @@ -615,6 +615,79 @@ def test_streaming_handler_with_stop_chunk( assert returned_chunk is None +def test_finish_reason_chunk_preserves_non_openai_attributes( + initialized_custom_stream_wrapper: CustomStreamWrapper, +): + """ + Regression test for #23444: + Preserve upstream non-OpenAI attributes on final finish_reason chunk. + """ + initialized_custom_stream_wrapper.received_finish_reason = "stop" + + original_chunk = ModelResponseStream( + id="chatcmpl-test", + created=1742093326, + model=None, + object="chat.completion.chunk", + choices=[ + StreamingChoices( + finish_reason="stop", + index=0, + delta=Delta(content=""), + logprobs=None, + ) + ], + ) + setattr(original_chunk, "custom_field", {"key": "value"}) + + returned_chunk = initialized_custom_stream_wrapper.return_processed_chunk_logic( + completion_obj={"content": ""}, + response_obj={"original_chunk": original_chunk}, + model_response=ModelResponseStream(), + ) + + assert returned_chunk is not None + assert getattr(returned_chunk, "custom_field", None) == {"key": "value"} + + +def test_finish_reason_with_holding_chunk_preserves_non_openai_attributes( + initialized_custom_stream_wrapper: CustomStreamWrapper, +): + """ + Regression test for #23444 holding-chunk path: + preserve custom attributes when _is_delta_empty is False after flushing + holding_chunk. + """ + initialized_custom_stream_wrapper.received_finish_reason = "stop" + initialized_custom_stream_wrapper.holding_chunk = "filtered text" + + original_chunk = ModelResponseStream( + id="chatcmpl-test-2", + created=1742093327, + model=None, + object="chat.completion.chunk", + choices=[ + StreamingChoices( + finish_reason="stop", + index=0, + delta=Delta(content=""), + logprobs=None, + ) + ], + ) + setattr(original_chunk, "custom_field", {"key": "value"}) + + returned_chunk = initialized_custom_stream_wrapper.return_processed_chunk_logic( + completion_obj={"content": ""}, + response_obj={"original_chunk": original_chunk}, + model_response=ModelResponseStream(), + ) + + assert returned_chunk is not None + assert returned_chunk.choices[0].delta.content == "filtered text" + assert getattr(returned_chunk, "custom_field", None) == {"key": "value"} + + def test_set_response_id_propagation_empty_to_valid( initialized_custom_stream_wrapper: CustomStreamWrapper, ): From a5bec4911fdd1e44bcae1c661a17424eb7d15aac Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 13 Mar 2026 13:29:39 +0530 Subject: [PATCH 036/289] Fix _supports_reasoning_effort_level for responses bridge --- litellm/main.py | 15 ++++++++------- tests/llm_translation/test_openai.py | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/litellm/main.py b/litellm/main.py index f2ce894ba3..395a8b0838 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -1356,6 +1356,13 @@ def completion( # type: ignore # noqa: PLR0915 api_key=api_key, ) + ## RESPONSES API BRIDGE LOGIC ## - check early and normalize model name + responses_api_model_info, model = responses_api_bridge_check( + model=model, + custom_llm_provider=custom_llm_provider, + web_search_options=web_search_options, + ) + if not _should_allow_input_examples( custom_llm_provider=custom_llm_provider, model=model ): @@ -1591,14 +1598,8 @@ def completion( # type: ignore # noqa: PLR0915 timeout=timeout, ) - ## RESPONSES API BRIDGE LOGIC ## - check if model has 'mode: responses' in litellm.model_cost map - model_info, model = responses_api_bridge_check( - model=model, - custom_llm_provider=custom_llm_provider, - web_search_options=web_search_options, - ) - if model_info.get("mode") == "responses": + if responses_api_model_info.get("mode") == "responses": from litellm.completion_extras import responses_api_bridge return responses_api_bridge.completion( diff --git a/tests/llm_translation/test_openai.py b/tests/llm_translation/test_openai.py index 9e6e5bb369..acbb9c5136 100644 --- a/tests/llm_translation/test_openai.py +++ b/tests/llm_translation/test_openai.py @@ -1454,3 +1454,29 @@ def test_gpt_5_web_search(): for chunk in response: print("chunk: ", chunk) + + +def test_responses_gpt54_with_xhigh_reasoning(): + """ + Ensure chat->responses bridge sends the correct request payload for + openai/responses/gpt-5.4 with reasoning_effort="xhigh". + """ + with patch("litellm.responses") as mock_responses: + # Stop execution right after request generation to avoid external API calls. + mock_responses.side_effect = RuntimeError("stop_after_request_build") + + with pytest.raises(Exception): + litellm.completion( + model="openai/responses/gpt-5.4", + messages=[{"role": "user", "content": "What is 2+2?"}], + reasoning_effort="xhigh", + max_tokens=100, + ) + + mock_responses.assert_called_once() + request_body = mock_responses.call_args.kwargs + + # The responses prefix should be stripped before routing. + assert request_body["model"] == "gpt-5.4" + # chat-completions reasoning_effort must map to Responses API reasoning. + assert request_body["reasoning"] == {"effort": "xhigh"} From 118d8114f8d606faa40f7802765f53ffce37762c Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Fri, 13 Mar 2026 15:37:13 +0530 Subject: [PATCH 037/289] Include time window in export filename to prevent Vantage overwrites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vantage deduplicates by filename — uploading the same filename overwrites previous data. Changed _build_filename to include the time window (e.g. usage_20240102T050000Z_20240102T060000Z.csv) so each hourly/daily export has a unique filename. Co-Authored-By: Claude Opus 4.6 --- litellm/integrations/focus/export_engine.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/litellm/integrations/focus/export_engine.py b/litellm/integrations/focus/export_engine.py index 1f51e1bac9..8b77fad9e1 100644 --- a/litellm/integrations/focus/export_engine.py +++ b/litellm/integrations/focus/export_engine.py @@ -101,13 +101,17 @@ class FocusExportEngine: await self._destination.deliver( content=payload, time_window=window, - filename=self._build_filename(), + filename=self._build_filename(window), ) - def _build_filename(self) -> str: + def _build_filename(self, window: FocusTimeWindow) -> str: if not self._serializer.extension: raise ValueError("Serializer must declare a file extension") - return f"usage.{self._serializer.extension}" + # Include time window in filename so Vantage (which deduplicates + # by filename) doesn't overwrite previous uploads. + start_str = window.start_time.strftime("%Y%m%dT%H%M%SZ") + end_str = window.end_time.strftime("%Y%m%dT%H%M%SZ") + return f"usage_{start_str}_{end_str}.{self._serializer.extension}" @staticmethod def _sum_column(frame: pl.DataFrame, column: str) -> float: From 511cd2ba2b31615872dbb2568433e5006a7c4a44 Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Fri, 13 Mar 2026 16:51:44 +0530 Subject: [PATCH 038/289] fix: silent metrics race condition --- litellm/router.py | 31 +++++++++++++++---- .../test_router_silent_experiment.py | 8 ++++- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/litellm/router.py b/litellm/router.py index 585cec682d..99bb10717e 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -1492,13 +1492,32 @@ class Router: def _get_silent_experiment_kwargs(self, **kwargs) -> dict: """ Prepare kwargs for a silent experiment by ensuring isolation from the primary call. - """ - # Copy kwargs to ensure isolation (use safe_deep_copy to handle non-serializable objects like OTEL spans) - from litellm.litellm_core_utils.core_helpers import safe_deep_copy - silent_kwargs = safe_deep_copy(kwargs) - if "metadata" not in silent_kwargs: - silent_kwargs["metadata"] = {} + IMPORTANT: We avoid calling safe_deep_copy(kwargs) because it temporarily + mutates the original dict (pops litellm_parent_otel_span, replaces with + "placeholder", then restores). Since this runs in a background thread while + the primary request's async callbacks may still be reading the same dict, + that mutation causes a race condition that breaks otel/prometheus callbacks + for the primary request. + """ + import copy + + # Shallow copy top-level kwargs — does NOT mutate the original + silent_kwargs = dict(kwargs) + + # Deep-copy metadata so we don't share state with the primary request. + # Remove the OTEL span BEFORE deep-copying (it's not picklable and is + # thread-bound anyway). + original_metadata = kwargs.get("metadata") or {} + metadata_copy = { + k: v + for k, v in original_metadata.items() + if k != "litellm_parent_otel_span" + } + try: + silent_kwargs["metadata"] = copy.deepcopy(metadata_copy) + except Exception: + silent_kwargs["metadata"] = dict(metadata_copy) silent_kwargs["metadata"]["is_silent_experiment"] = True diff --git a/tests/test_litellm/test_router_silent_experiment.py b/tests/test_litellm/test_router_silent_experiment.py index 67d262f83d..8bced04ab8 100644 --- a/tests/test_litellm/test_router_silent_experiment.py +++ b/tests/test_litellm/test_router_silent_experiment.py @@ -20,8 +20,9 @@ def test_get_silent_experiment_kwargs(): }, ] router = Router(model_list=model_list) + mock_span = MagicMock() kwargs = { - "metadata": {"foo": "bar"}, + "metadata": {"foo": "bar", "litellm_parent_otel_span": mock_span}, "litellm_call_id": "call-123", "stream": True, "proxy_server_request": {"body": {"model": "test"}}, @@ -34,6 +35,11 @@ def test_get_silent_experiment_kwargs(): assert result["stream"] is False # proxy_server_request must be preserved for spend log metadata assert "proxy_server_request" in result + # parent OTEL span must be removed — it's thread-bound and invalid in the + # background thread's new event loop + assert "litellm_parent_otel_span" not in result["metadata"] + # CRITICAL: original kwargs must NOT be mutated (race condition with primary callbacks) + assert kwargs["metadata"]["litellm_parent_otel_span"] is mock_span def test_silent_experiment_completion_direct(): From 8f769ef524a5bf95f3517961e85b6a3867c385ae Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 13 Mar 2026 17:54:33 +0530 Subject: [PATCH 039/289] docs(blog): add WebRTC blog post link Made-with: Cursor --- litellm/blog_posts.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/litellm/blog_posts.json b/litellm/blog_posts.json index 15340514bc..fa768b3ec5 100644 --- a/litellm/blog_posts.json +++ b/litellm/blog_posts.json @@ -1,10 +1,10 @@ { "posts": [ { - "title": "Incident Report: SERVER_ROOT_PATH regression broke UI routing", - "description": "How a single line removal caused UI 404s for all deployments using SERVER_ROOT_PATH, and the tests we added to prevent it from happening again.", - "date": "2026-02-21", - "url": "https://docs.litellm.ai/blog/server-root-path-incident" + "title": "Realtime WebRTC HTTP Endpoints", + "description": "Use the LiteLLM proxy to route OpenAI-style WebRTC realtime via HTTP: client_secrets and SDP exchange.", + "date": "2026-03-12", + "url": "https://docs.litellm.ai/blog/realtime_webrtc_http_endpoints" } ] } From 7e662afe01a094887b63c5ca0fe097a22073b953 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 13 Mar 2026 18:25:29 +0530 Subject: [PATCH 040/289] feat(azure): Azure Model Router cost breakdown in UI + additional_costs from hidden_params - Backend: Use request model from hidden_params for Azure Model Router additional_costs when response has actual model - Backend: Add additional_costs to total cost calculation - UI: Show all non-null/non-zero additional_costs in CostBreakdownViewer - UI: Render cost breakdown when only additional_costs exist - Tests: Backend test for hidden_params flow; frontend tests for additional_costs Made-with: Cursor --- litellm/cost_calculator.py | 31 +++- .../azure_ai/test_azure_ai_cost_calculator.py | 46 ++++++ .../view_logs/CostBreakdownViewer.test.tsx | 154 ++++++++++++++++++ .../view_logs/CostBreakdownViewer.tsx | 16 +- 4 files changed, 233 insertions(+), 14 deletions(-) create mode 100644 ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.test.tsx diff --git a/litellm/cost_calculator.py b/litellm/cost_calculator.py index c1daa109c7..a3ef7b264e 100644 --- a/litellm/cost_calculator.py +++ b/litellm/cost_calculator.py @@ -1182,7 +1182,7 @@ def completion_cost( # noqa: PLR0915 and _usage["prompt_tokens_details"] != {} and _usage["prompt_tokens_details"] ): - prompt_tokens_details = _usage.get("prompt_tokens_details", {}) + prompt_tokens_details = _usage.get("prompt_tokens_details") or {} cache_read_input_tokens = prompt_tokens_details.get( "cached_tokens", 0 ) @@ -1484,8 +1484,8 @@ def completion_cost( # noqa: PLR0915 completion_tokens_cost_usd_dollar, ) = cost_per_token( model=model, - prompt_tokens=prompt_tokens, - completion_tokens=completion_tokens, + prompt_tokens=prompt_tokens or 0, + completion_tokens=completion_tokens or 0, custom_llm_provider=custom_llm_provider, response_time_ms=total_time, region_name=region_name, @@ -1505,13 +1505,27 @@ def completion_cost( # noqa: PLR0915 ) # Get additional costs from provider (e.g., routing fees, infrastructure costs) - # Only azure_ai implements additional costs if custom_llm_provider == "azure_ai": + model_for_additional_costs = request_model_for_cost + if completion_response is not None: + hidden_params = getattr(completion_response, "_hidden_params", None) or {} + hidden_model = hidden_params.get("model") or hidden_params.get( + "litellm_model_name" + ) + if hidden_model and ( + "model_router" in (hidden_model or "").lower() + or "model-router" in (hidden_model or "").lower() + ): + model_for_additional_costs = hidden_model + elif model_for_additional_costs is None: + model_for_additional_costs = hidden_model + if model_for_additional_costs is None: + model_for_additional_costs = model additional_costs = _get_additional_costs( - model=model, + model=model_for_additional_costs, custom_llm_provider=custom_llm_provider, - prompt_tokens=prompt_tokens, - completion_tokens=completion_tokens, + prompt_tokens=prompt_tokens or 0, + completion_tokens=completion_tokens or 0, ) else: additional_costs = None @@ -1529,8 +1543,9 @@ def completion_cost( # noqa: PLR0915 ) ) _final_cost += cost_for_built_in_tools + if additional_costs: + _final_cost += sum(additional_costs.values()) - # Apply discount from module-level config if configured original_cost = _final_cost if litellm.cost_discount_config: ( diff --git a/tests/test_litellm/llms/azure_ai/test_azure_ai_cost_calculator.py b/tests/test_litellm/llms/azure_ai/test_azure_ai_cost_calculator.py index ec1d4e4b3c..2b00c25049 100644 --- a/tests/test_litellm/llms/azure_ai/test_azure_ai_cost_calculator.py +++ b/tests/test_litellm/llms/azure_ai/test_azure_ai_cost_calculator.py @@ -382,3 +382,49 @@ class TestAzureModelRouterCostBreakdown: print(f"Additional costs in breakdown: {additional_costs}") print(f"Azure Model Router Flat Cost: ${actual_flat_cost:.6f}") + + def test_additional_costs_when_response_has_actual_model_via_hidden_params(self): + """additional_costs populated when response has actual model but request was via model router (hidden_params).""" + from datetime import datetime + + from litellm.cost_calculator import completion_cost + from litellm.litellm_core_utils.litellm_logging import Logging + from litellm.types.utils import Choices, Message, ModelResponse, Usage + + logging_obj = Logging( + model="gpt-4.1-nano-2025-04-14", + messages=[{"role": "user", "content": "Hello"}], + stream=False, + call_type="completion", + start_time=datetime.now(), + litellm_call_id="test-123", + function_id="test-function", + ) + response = ModelResponse( + id="test-123", + choices=[Choices(finish_reason="stop", index=0, message=Message(role="assistant", content="Hello"))], + created=1234567890, + model="gpt-4.1-nano-2025-04-14", + object="chat.completion", + usage=Usage(prompt_tokens=5000, completion_tokens=2000, total_tokens=7000), + ) + response._hidden_params = { + "custom_llm_provider": "azure_ai", + "litellm_model_name": "azure_ai/model-router", + } + cost = completion_cost( + completion_response=response, + model="gpt-4.1-nano-2025-04-14", + custom_llm_provider="azure_ai", + litellm_logging_obj=logging_obj, + ) + expected_flat_cost = ( + 5000 * AZURE_MODEL_ROUTER_FLAT_COST_PER_M_INPUT_TOKENS / 1_000_000 + ) + assert cost >= expected_flat_cost + assert logging_obj.cost_breakdown is not None + assert "additional_costs" in logging_obj.cost_breakdown + assert "Azure Model Router Flat Cost" in logging_obj.cost_breakdown["additional_costs"] + assert logging_obj.cost_breakdown["additional_costs"]["Azure Model Router Flat Cost"] == pytest.approx( + expected_flat_cost, rel=1e-9 + ) diff --git a/ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.test.tsx b/ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.test.tsx new file mode 100644 index 0000000000..983e78aa98 --- /dev/null +++ b/ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.test.tsx @@ -0,0 +1,154 @@ +import React from "react"; +import { describe, it, expect } from "vitest"; +import userEvent from "@testing-library/user-event"; +import { renderWithProviders, screen } from "../../../tests/test-utils"; +import { CostBreakdownViewer } from "./CostBreakdownViewer"; + +async function expandCostBreakdown() { + const user = userEvent.setup(); + await user.click(screen.getByText("Cost Breakdown")); +} + +describe("CostBreakdownViewer", () => { + it("renders cost breakdown with input and output costs", async () => { + renderWithProviders( + + ); + + expect(screen.getByText("Cost Breakdown")).toBeInTheDocument(); + await expandCostBreakdown(); + expect(screen.getByText("Input Cost:")).toBeInTheDocument(); + expect(screen.getByText("Output Cost:")).toBeInTheDocument(); + expect(screen.getByText("Final Calculated Cost:")).toBeInTheDocument(); + }); + + it("shows non-null, non-zero additional_costs", async () => { + renderWithProviders( + + ); + + await expandCostBreakdown(); + expect(screen.getByText("Azure Model Router Flat Cost:")).toBeInTheDocument(); + expect(screen.getByText("Routing Fee:")).toBeInTheDocument(); + }); + + it("filters out null and zero additional_costs", async () => { + renderWithProviders( + + ); + + await expandCostBreakdown(); + expect(screen.getByText("Azure Model Router Flat Cost:")).toBeInTheDocument(); + expect(screen.queryByText("Zero Cost:")).not.toBeInTheDocument(); + expect(screen.queryByText("Null Cost:")).not.toBeInTheDocument(); + }); + + it("renders when only additional_costs exist (no input/output costs)", async () => { + const { container } = renderWithProviders( + + ); + + expect(screen.getByText("Cost Breakdown")).toBeInTheDocument(); + await expandCostBreakdown(); + expect(screen.getByText("Model Router Flat Cost:")).toBeInTheDocument(); + expect(container).not.toBeEmptyDOMElement(); + }); + + it("returns null when no meaningful data", () => { + const { container } = renderWithProviders( + + ); + + expect(container).toBeEmptyDOMElement(); + }); + + it("returns null when additional_costs are all null/zero", () => { + const { container } = renderWithProviders( + + ); + + expect(container).toBeEmptyDOMElement(); + }); + + it("expands to show additional_costs on click", async () => { + renderWithProviders( + + ); + + expect(screen.queryByText("Azure Model Router Flat Cost:")).not.toBeInTheDocument(); + await expandCostBreakdown(); + expect(screen.getByText("Azure Model Router Flat Cost:")).toBeInTheDocument(); + }); +}); diff --git a/ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.tsx b/ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.tsx index 087863e947..61699cb2ef 100644 --- a/ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.tsx @@ -45,9 +45,15 @@ export const CostBreakdownViewer: React.FC = ({ const hasTokenCounts = promptTokens !== undefined || completionTokens !== undefined; const hasCostBreakdown = costBreakdown?.input_cost !== undefined || costBreakdown?.output_cost !== undefined; + const hasAdditionalCosts = + costBreakdown?.additional_costs && + Object.entries(costBreakdown.additional_costs).some( + ([, value]) => value != null && value !== 0 + ); const hasMeaningfulData = hasCostBreakdown || hasTokenCounts || + hasAdditionalCosts || (costBreakdown && ((costBreakdown.discount_percent !== undefined && costBreakdown.discount_percent !== 0) || (costBreakdown.discount_amount !== undefined && costBreakdown.discount_amount !== 0) || @@ -127,17 +133,15 @@ export const CostBreakdownViewer: React.FC = ({ {formatCost(costBreakdown.tool_usage_cost)} )} - {/* Additional Costs (free-form) */} - {costBreakdown?.additional_costs && Object.keys(costBreakdown.additional_costs).length > 0 && ( - <> - {Object.entries(costBreakdown.additional_costs).map(([key, value]) => ( + {costBreakdown?.additional_costs && + Object.entries(costBreakdown.additional_costs) + .filter(([, value]) => value != null && value !== 0) + .map(([key, value]) => (
{key}: {formatCost(value)}
))} - - )} {/* Subtotal / Original Cost - hide when cached since it would be $0 */} From ac8d6d4fa8015abf870d99eb7b31c5e73b45b195 Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Fri, 13 Mar 2026 19:44:22 +0530 Subject: [PATCH 041/289] fix: ensure metadata isolation in silent experiment to prevent metric collision --- litellm/router.py | 43 +++++++++---------- .../test_router_silent_experiment.py | 10 +++-- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/litellm/router.py b/litellm/router.py index 99bb10717e..c7cff4ba41 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -1493,31 +1493,30 @@ class Router: """ Prepare kwargs for a silent experiment by ensuring isolation from the primary call. - IMPORTANT: We avoid calling safe_deep_copy(kwargs) because it temporarily - mutates the original dict (pops litellm_parent_otel_span, replaces with - "placeholder", then restores). Since this runs in a background thread while - the primary request's async callbacks may still be reading the same dict, - that mutation causes a race condition that breaks otel/prometheus callbacks - for the primary request. + Guarantee metadata isolation: safe_deep_copy falls back to the original + reference when deepcopy fails (e.g. metadata contains UserAPIKeyAuth with + parent_otel_span — an OTel Span that is not deepcopy-able). Force a shallow + copy of the metadata dict so mutations (model_group, is_silent_experiment) + never corrupt the main call's metadata. """ - import copy + from litellm.litellm_core_utils.core_helpers import safe_deep_copy - # Shallow copy top-level kwargs — does NOT mutate the original - silent_kwargs = dict(kwargs) + silent_kwargs = safe_deep_copy(kwargs) - # Deep-copy metadata so we don't share state with the primary request. - # Remove the OTEL span BEFORE deep-copying (it's not picklable and is - # thread-bound anyway). - original_metadata = kwargs.get("metadata") or {} - metadata_copy = { - k: v - for k, v in original_metadata.items() - if k != "litellm_parent_otel_span" - } - try: - silent_kwargs["metadata"] = copy.deepcopy(metadata_copy) - except Exception: - silent_kwargs["metadata"] = dict(metadata_copy) + # safe_deep_copy may fall back to the original metadata reference when + # deepcopy fails (UserAPIKeyAuth.parent_otel_span is not deepcopy-able). + # Detect this via identity check and force a shallow copy so that setting + # model_group / is_silent_experiment on the silent dict doesn't corrupt + # the primary call's metadata. + original_metadata = kwargs.get("metadata") + if ( + original_metadata is not None + and silent_kwargs.get("metadata") is original_metadata + ): + silent_kwargs["metadata"] = dict(original_metadata) + + if "metadata" not in silent_kwargs: + silent_kwargs["metadata"] = {} silent_kwargs["metadata"]["is_silent_experiment"] = True diff --git a/tests/test_litellm/test_router_silent_experiment.py b/tests/test_litellm/test_router_silent_experiment.py index 8bced04ab8..4d6a775c44 100644 --- a/tests/test_litellm/test_router_silent_experiment.py +++ b/tests/test_litellm/test_router_silent_experiment.py @@ -35,10 +35,12 @@ def test_get_silent_experiment_kwargs(): assert result["stream"] is False # proxy_server_request must be preserved for spend log metadata assert "proxy_server_request" in result - # parent OTEL span must be removed — it's thread-bound and invalid in the - # background thread's new event loop - assert "litellm_parent_otel_span" not in result["metadata"] - # CRITICAL: original kwargs must NOT be mutated (race condition with primary callbacks) + # CRITICAL: metadata must be a DIFFERENT dict object than the original, + # so that setting model_group / is_silent_experiment on the silent dict + # doesn't corrupt the primary call's metadata. + assert result["metadata"] is not kwargs["metadata"] + # Original metadata must NOT be mutated + assert "is_silent_experiment" not in kwargs["metadata"] assert kwargs["metadata"]["litellm_parent_otel_span"] is mock_span From c6da45795b26f432b74dc6be8b34bcdf68490972 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Fri, 13 Mar 2026 17:12:30 -0700 Subject: [PATCH 042/289] temp commit --- .../OrganizationDropdown.tsx | 52 +++++++++++++++++++ .../organisms/create_key_button.tsx | 43 ++++++++++++++- .../components/templates/key_edit_view.tsx | 46 +++++++++++++++- 3 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 ui/litellm-dashboard/src/components/common_components/OrganizationDropdown.tsx diff --git a/ui/litellm-dashboard/src/components/common_components/OrganizationDropdown.tsx b/ui/litellm-dashboard/src/components/common_components/OrganizationDropdown.tsx new file mode 100644 index 0000000000..ac93041f3d --- /dev/null +++ b/ui/litellm-dashboard/src/components/common_components/OrganizationDropdown.tsx @@ -0,0 +1,52 @@ +import React from "react"; +import { Select } from "antd"; +import { Organization } from "../networking"; + +interface OrganizationDropdownProps { + organizations?: Organization[] | null; + value?: string; + onChange?: (value: string) => void; + disabled?: boolean; + loading?: boolean; +} + +const OrganizationDropdown: React.FC = ({ + organizations, + value, + onChange, + disabled, + loading, +}) => { + return ( + + ); +}; + +export default OrganizationDropdown; diff --git a/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx b/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx index 0926b11fe0..71e882db3f 100644 --- a/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx +++ b/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx @@ -1,5 +1,6 @@ "use client"; import { keyKeys } from "@/app/(dashboard)/hooks/keys/useKeys"; +import { useOrganizations } from "@/app/(dashboard)/hooks/organizations/useOrganizations"; import { useProjects } from "@/app/(dashboard)/hooks/projects/useProjects"; import { useUISettings } from "@/app/(dashboard)/hooks/uiSettings/useUISettings"; import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; @@ -23,6 +24,7 @@ import PremiumLoggingSettings from "../common_components/PremiumLoggingSettings" import RateLimitTypeFormItem from "../common_components/RateLimitTypeFormItem"; import RouterSettingsAccordion, { RouterSettingsAccordionValue } from "../common_components/RouterSettingsAccordion"; import TeamDropdown from "../common_components/team_dropdown"; +import OrganizationDropdown from "../common_components/OrganizationDropdown"; import ProjectDropdown from "../common_components/ProjectDropdown"; import { CreateUserButton } from "../CreateUserButton"; import { getModelDisplayName } from "../key_team_helpers/fetch_available_models_team_key"; @@ -160,6 +162,7 @@ export const fetchUserModels = async ( const CreateKey: React.FC = ({ team, teams, data, addKey, autoOpenCreate, prefillData }) => { const { accessToken, userId: userID, userRole, premiumUser } = useAuthorized(); const canEditGuardrails = premiumUser || (userRole != null && rolesWithWriteAccess.includes(userRole)); + const { data: organizations, isLoading: isOrganizationsLoading } = useOrganizations(); const { data: projects, isLoading: isProjectsLoading } = useProjects(); const { data: uiSettingsData } = useUISettings(); const enableProjectsUI = Boolean(uiSettingsData?.values?.enable_projects_ui); @@ -179,6 +182,7 @@ const CreateKey: React.FC = ({ team, teams, data, addKey, autoOp const [promptsList, setPromptsList] = useState([]); const [loggingSettings, setLoggingSettings] = useState([]); const [selectedCreateKeyTeam, setSelectedCreateKeyTeam] = useState(team); + const [selectedOrganizationId, setSelectedOrganizationId] = useState(null); const [selectedProjectId, setSelectedProjectId] = useState(null); const [isCreateUserModalVisible, setIsCreateUserModalVisible] = useState(false); const [newlyCreatedUserId, setNewlyCreatedUserId] = useState(null); @@ -207,6 +211,7 @@ const CreateKey: React.FC = ({ team, teams, data, addKey, autoOp setRouterSettings(null); setRouterSettingsKey((prev) => prev + 1); setSelectedAgentId(null); + setSelectedOrganizationId(null); setSelectedProjectId(null); }; @@ -224,6 +229,7 @@ const CreateKey: React.FC = ({ team, teams, data, addKey, autoOp setRouterSettings(null); setRouterSettingsKey((prev) => prev + 1); setSelectedAgentId(null); + setSelectedOrganizationId(null); setSelectedProjectId(null); }; @@ -752,6 +758,32 @@ const CreateKey: React.FC = ({ team, teams, data, addKey, autoOp )} + + Organization{" "} + + + + + } + name="organization_id" + className="mt-4" + > + { + setSelectedOrganizationId(orgId || null); + // Clear team and project when org changes + setSelectedCreateKeyTeam(null); + setSelectedProjectId(null); + form.setFieldValue("team_id", undefined); + form.setFieldValue("project_id", undefined); + }} + /> + @@ -773,7 +805,7 @@ const CreateKey: React.FC = ({ team, teams, data, addKey, autoOp help={keyOwner === "service_account" ? "required" : ""} > t.organization_id === selectedOrganizationId) : teams} disabled={selectedProjectId !== null} loading={!teams} onChange={(teamId) => { @@ -781,6 +813,14 @@ const CreateKey: React.FC = ({ team, teams, data, addKey, autoOp setSelectedCreateKeyTeam(selectedTeam); setSelectedProjectId(null); form.setFieldValue("project_id", undefined); + // Auto-populate org from team for non-admin users + if (selectedTeam?.organization_id) { + setSelectedOrganizationId(selectedTeam.organization_id); + form.setFieldValue("organization_id", selectedTeam.organization_id); + } else if (!teamId) { + setSelectedOrganizationId(null); + form.setFieldValue("organization_id", undefined); + } }} /> @@ -1531,6 +1571,7 @@ const CreateKey: React.FC = ({ team, teams, data, addKey, autoOp excludedFields={[ "key_alias", "team_id", + "organization_id", "models", "duration", "metadata", diff --git a/ui/litellm-dashboard/src/components/templates/key_edit_view.tsx b/ui/litellm-dashboard/src/components/templates/key_edit_view.tsx index b6c00577c9..cf431d1024 100644 --- a/ui/litellm-dashboard/src/components/templates/key_edit_view.tsx +++ b/ui/litellm-dashboard/src/components/templates/key_edit_view.tsx @@ -1,4 +1,5 @@ import GuardrailSelector from "@/components/guardrails/GuardrailSelector"; +import { useOrganizations } from "@/app/(dashboard)/hooks/organizations/useOrganizations"; import { useProjects } from "@/app/(dashboard)/hooks/projects/useProjects"; import { useUISettings } from "@/app/(dashboard)/hooks/uiSettings/useUISettings"; import PolicySelector from "@/components/policies/PolicySelector"; @@ -13,6 +14,7 @@ import { mapInternalToDisplayNames } from "../callback_info_helpers"; import KeyLifecycleSettings from "../common_components/KeyLifecycleSettings"; import PassThroughRoutesSelector from "../common_components/PassThroughRoutesSelector"; import RateLimitTypeFormItem from "../common_components/RateLimitTypeFormItem"; +import OrganizationDropdown from "../common_components/OrganizationDropdown"; import { extractLoggingSettings, formatMetadataForDisplay, stripTagsFromMetadata } from "../key_info_utils"; import { KeyResponse } from "../key_team_helpers/key_list"; import MCPServerSelector from "../mcp_server_management/MCPServerSelector"; @@ -96,10 +98,12 @@ export function KeyEditView({ ? mapInternalToDisplayNames(keyData.metadata.litellm_disabled_callbacks) : [], ); + const [selectedOrganizationId, setSelectedOrganizationId] = useState(keyData.organization_id || null); const [autoRotationEnabled, setAutoRotationEnabled] = useState(keyData.auto_rotate || false); const [rotationInterval, setRotationInterval] = useState(keyData.rotation_interval || ""); const [neverExpire, setNeverExpire] = useState(!keyData.expires); const [isKeySaving, setIsKeySaving] = useState(false); + const { data: organizations, isLoading: isOrganizationsLoading } = useOrganizations(); const { data: projects } = useProjects(); const { data: uiSettingsData } = useUISettings(); const enableProjectsUI = Boolean(uiSettingsData?.values?.enable_projects_ui); @@ -610,6 +614,28 @@ export function KeyEditView({ /> + + Organization{" "} + + + + + } + name="organization_id" + > + { + setSelectedOrganizationId(orgId || null); + form.setFieldValue("team_id", undefined); + }} + /> + + { + const selectedTeam = teams?.find((t) => t.team_id === teamId) || null; + if (selectedTeam?.organization_id) { + setSelectedOrganizationId(selectedTeam.organization_id); + form.setFieldValue("organization_id", selectedTeam.organization_id); + } else if (!teamId) { + setSelectedOrganizationId(null); + form.setFieldValue("organization_id", undefined); + } + }} filterOption={(input, option) => { - const team = teams?.find((t) => t.team_id === option?.value); + const filteredTeams = selectedOrganizationId + ? teams?.filter((t) => t.organization_id === selectedOrganizationId) + : teams; + const team = filteredTeams?.find((t) => t.team_id === option?.value); if (!team) return false; return team.team_alias?.toLowerCase().includes(input.toLowerCase()) ?? false; }} > - {teams?.map((team) => ( + {(selectedOrganizationId + ? teams?.filter((t) => t.organization_id === selectedOrganizationId) + : teams + )?.map((team) => ( {`${team.team_alias} (${team.team_id})`} From c637c93a6ab4b02209523b3f4e6a2e49e8e0a2cb Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Fri, 13 Mar 2026 18:08:02 -0700 Subject: [PATCH 043/289] [Fix] Skip all-team-models sentinel in team change validation When moving a key to a different team, `validate_key_team_change` was treating "all-team-models" as a literal model name and checking if the target team could access it. This always failed because "all-team-models" is a UI/backend sentinel meaning "use whatever the team allows." Also reorder checks so the membership check runs after data validation (models, rate limits) but before permission checks, keeping the admin early-return after all validation. Co-Authored-By: Claude Opus 4.6 --- .../key_management_endpoints.py | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index db1a089ff7..715a395e67 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -2301,23 +2301,16 @@ async def validate_key_team_change( # Check if the team has access to the key's models if len(key.models) > 0: for model in key.models: + # Skip special sentinel values — "all-team-models" means + # "use whatever the team allows", so it's always valid. + if model == SpecialModelNames.all_team_models.value: + continue await can_team_access_model( model=model, team_object=team, llm_router=llm_router, ) - # Check if the key's user_id is a member of the team - member_object = _get_user_in_team( - team_table=cast(LiteLLM_TeamTableCachedObj, team), user_id=key.user_id - ) - if key.user_id is not None: - if not member_object: - raise HTTPException( - status_code=403, - detail=f"User={key.user_id} is not a member of the team={team.team_id}. Check team members via `/team/info`.", - ) - # Check if the key's tpm/rpm limit is less than the team's tpm/rpm limit if key.tpm_limit is not None: if team.tpm_limit and key.tpm_limit > team.tpm_limit: @@ -2331,6 +2324,17 @@ async def validate_key_team_change( detail=f"Key={key.token} has a rpm_limit={key.rpm_limit} which is greater than the team's rpm_limit={team.rpm_limit}.", ) + # Check if the key's user_id is a member of the team + member_object = _get_user_in_team( + team_table=cast(LiteLLM_TeamTableCachedObj, team), user_id=key.user_id + ) + if key.user_id is not None: + if not member_object: + raise HTTPException( + status_code=403, + detail=f"User={key.user_id} is not a member of the team={team.team_id}. Check team members via `/team/info`.", + ) + # Check if the person initiating the change is a Proxy Admin or Team Admin if change_initiated_by.user_role == LitellmUserRoles.PROXY_ADMIN.value: return From bce37e28c3c03b7113ea6b3246052c0d7de3c5d5 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Fri, 13 Mar 2026 18:15:42 -0700 Subject: [PATCH 044/289] [Test] Add tests for organization dropdown in key create/edit - OrganizationDropdown: renders options, calls onChange on selection, applies disabled state, handles empty list - CreateKey: org dropdown renders, disabled for non-admin users, enabled for admins, form state updates on org selection - KeyEditView: org dropdown renders, disabled for non-admin, enabled for admin, initializes from keyData.organization_id Co-Authored-By: Claude Opus 4.6 --- .../OrganizationDropdown.test.tsx | 69 ++++++++++ .../organisms/create_key_button.test.tsx | 119 +++++++++++++++++- .../templates/key_edit_view.test.tsx | 97 ++++++++++++++ 3 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 ui/litellm-dashboard/src/components/common_components/OrganizationDropdown.test.tsx diff --git a/ui/litellm-dashboard/src/components/common_components/OrganizationDropdown.test.tsx b/ui/litellm-dashboard/src/components/common_components/OrganizationDropdown.test.tsx new file mode 100644 index 0000000000..1f6a61f39f --- /dev/null +++ b/ui/litellm-dashboard/src/components/common_components/OrganizationDropdown.test.tsx @@ -0,0 +1,69 @@ +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { describe, expect, it, vi } from "vitest"; +import OrganizationDropdown from "./OrganizationDropdown"; + +const MOCK_ORGS = [ + { + organization_id: "org-1", + organization_alias: "Engineering", + budget_id: "", + metadata: {}, + models: [], + spend: 0, + model_spend: {}, + created_at: "", + created_by: "", + updated_at: "", + }, + { + organization_id: "org-2", + organization_alias: "Sales", + budget_id: "", + metadata: {}, + models: [], + spend: 0, + model_spend: {}, + created_at: "", + created_by: "", + updated_at: "", + }, +]; + +describe("OrganizationDropdown", () => { + it("should render", () => { + render(); + expect(screen.getByRole("combobox")).toBeInTheDocument(); + }); + + it("should display organization options when opened", async () => { + const user = userEvent.setup(); + render(); + + await user.click(screen.getByRole("combobox")); + + expect(await screen.findByText("Engineering")).toBeInTheDocument(); + expect(screen.getByText("Sales")).toBeInTheDocument(); + }); + + it("should call onChange with the org id when an organization is selected", async () => { + const onChange = vi.fn(); + const user = userEvent.setup(); + render(); + + await user.click(screen.getByRole("combobox")); + await user.click(await screen.findByText("Engineering")); + + expect(onChange).toHaveBeenCalledWith("org-1", expect.anything()); + }); + + it("should add ant-select-disabled class when disabled prop is true", () => { + const { container } = render(); + expect(container.querySelector(".ant-select-disabled")).toBeTruthy(); + }); + + it("should render with empty organizations list", () => { + render(); + expect(screen.getByRole("combobox")).toBeInTheDocument(); + }); +}); diff --git a/ui/litellm-dashboard/src/components/organisms/create_key_button.test.tsx b/ui/litellm-dashboard/src/components/organisms/create_key_button.test.tsx index 3ed4c80aea..eef7292dac 100644 --- a/ui/litellm-dashboard/src/components/organisms/create_key_button.test.tsx +++ b/ui/litellm-dashboard/src/components/organisms/create_key_button.test.tsx @@ -213,7 +213,22 @@ vi.mock("../common_components/PassThroughRoutesSelector", () => ({ default: () = vi.mock("../common_components/PremiumLoggingSettings", () => ({ default: () => null })); vi.mock("../common_components/RateLimitTypeFormItem", () => ({ default: () => null })); vi.mock("../common_components/RouterSettingsAccordion", () => ({ default: () => null })); -vi.mock("../common_components/team_dropdown", () => ({ default: () => null })); +vi.mock("../common_components/team_dropdown", () => ({ + default: ({ teams, onChange, disabled }: { teams?: any[]; onChange?: (v: string) => void; disabled?: boolean }) => ( + + ), +})); vi.mock("../CreateUserButton", () => ({ CreateUserButton: () => null })); vi.mock("../mcp_server_management/MCPServerSelector", () => ({ default: () => null })); vi.mock("../mcp_server_management/MCPToolPermissions", () => ({ default: () => null })); @@ -227,6 +242,31 @@ vi.mock("@/app/(dashboard)/hooks/projects/useProjects", () => ({ useProjects: vi.fn().mockReturnValue({ data: [], isLoading: false }), })); +vi.mock("@/app/(dashboard)/hooks/organizations/useOrganizations", () => ({ + useOrganizations: vi.fn().mockReturnValue({ + data: [ + { organization_id: "org-1", organization_alias: "Engineering" }, + { organization_id: "org-2", organization_alias: "Sales" }, + ], + isLoading: false, + }), +})); + +vi.mock("../common_components/OrganizationDropdown", () => ({ + default: ({ value, onChange, disabled }: { value?: string; onChange?: (v: string) => void; disabled?: boolean }) => ( + + ), +})); + vi.mock("../common_components/ProjectDropdown", () => ({ default: ({ value, onChange }: { value?: string; onChange?: (v: string) => void }) => ( { expect(setFieldsValueMock).toHaveBeenCalledWith({ key_type: "management" }); }); }); + + describe("organization dropdown", () => { + it("should render the organization dropdown when modal is open", async () => { + renderWithProviders(); + + act(() => { + fireEvent.click(screen.getByRole("button", { name: /create new key/i })); + }); + + await waitFor(() => { + expect(screen.getByTestId("org-dropdown")).toBeInTheDocument(); + }); + }); + + it("should disable the organization dropdown for non-admin users", async () => { + authorizedState = { ...defaultAuthorizedState, userRole: "Internal User" }; + + renderWithProviders(); + + act(() => { + fireEvent.click(screen.getByRole("button", { name: /create new key/i })); + }); + + await waitFor(() => { + expect(screen.getByTestId("org-dropdown")).toBeDisabled(); + }); + }); + + it("should enable the organization dropdown for admin users", async () => { + authorizedState = { ...defaultAuthorizedState, userRole: "Admin" }; + + renderWithProviders(); + + act(() => { + fireEvent.click(screen.getByRole("button", { name: /create new key/i })); + }); + + await waitFor(() => { + expect(screen.getByTestId("org-dropdown")).not.toBeDisabled(); + }); + }); + + it("should render team dropdown alongside organization dropdown", async () => { + const teamsWithOrg = [ + { team_id: "team-1", team_alias: "Team Alpha", organization_id: "org-1", models: [] }, + ]; + + renderWithProviders(); + + act(() => { + fireEvent.click(screen.getByRole("button", { name: /create new key/i })); + }); + + await waitFor(() => { + expect(screen.getByTestId("org-dropdown")).toBeInTheDocument(); + expect(screen.getByTestId("team-dropdown")).toBeInTheDocument(); + }); + }); + + it("should set organization_id in form state when org is selected", async () => { + renderWithProviders(); + + act(() => { + fireEvent.click(screen.getByRole("button", { name: /create new key/i })); + }); + + await waitFor(() => { + expect(screen.getByTestId("org-dropdown")).toBeInTheDocument(); + }); + + act(() => { + fireEvent.change(screen.getByTestId("org-dropdown"), { target: { value: "org-1" } }); + }); + + expect(formStateRef.current["organization_id"]).toBe("org-1"); + }); + }); }); diff --git a/ui/litellm-dashboard/src/components/templates/key_edit_view.test.tsx b/ui/litellm-dashboard/src/components/templates/key_edit_view.test.tsx index b00a8d1e3f..2e4d0d97e4 100644 --- a/ui/litellm-dashboard/src/components/templates/key_edit_view.test.tsx +++ b/ui/litellm-dashboard/src/components/templates/key_edit_view.test.tsx @@ -53,6 +53,16 @@ vi.mock("../organisms/create_key_button", () => ({ fetchTeamModels: vi.fn().mockResolvedValue(["team-model-1", "team-model-2"]), })); +vi.mock("@/app/(dashboard)/hooks/organizations/useOrganizations", () => ({ + useOrganizations: vi.fn().mockReturnValue({ + data: [ + { organization_id: "org-1", organization_alias: "Engineering" }, + { organization_id: "org-2", organization_alias: "Sales" }, + ], + isLoading: false, + }), +})); + vi.mock("@/app/(dashboard)/hooks/accessGroups/useAccessGroups", () => ({ useAccessGroups: vi.fn().mockReturnValue({ data: [ @@ -576,4 +586,91 @@ describe("KeyEditView", () => { resolveSubmit(); } }); + + describe("organization dropdown", () => { + it("should render the organization dropdown", async () => { + renderWithProviders( + {}} + onSubmit={async () => {}} + accessToken="" + userID="" + userRole="Admin" + premiumUser={false} + />, + ); + + await waitFor(() => { + expect(screen.getByText("Organization")).toBeInTheDocument(); + }); + }); + + it("should disable the organization dropdown for non-admin users", async () => { + const { container } = renderWithProviders( + {}} + onSubmit={async () => {}} + accessToken="" + userID="" + userRole="Internal User" + premiumUser={false} + />, + ); + + await waitFor(() => { + expect(screen.getByText("Organization")).toBeInTheDocument(); + }); + + const orgFormItem = screen.getByText("Organization").closest(".ant-form-item"); + const disabledSelect = orgFormItem?.querySelector(".ant-select-disabled"); + expect(disabledSelect).toBeTruthy(); + }); + + it("should not disable the organization dropdown for admin users", async () => { + const { container } = renderWithProviders( + {}} + onSubmit={async () => {}} + accessToken="" + userID="" + userRole="Admin" + premiumUser={false} + />, + ); + + await waitFor(() => { + expect(screen.getByText("Organization")).toBeInTheDocument(); + }); + + const orgFormItem = screen.getByText("Organization").closest(".ant-form-item"); + const disabledSelect = orgFormItem?.querySelector(".ant-select-disabled"); + expect(disabledSelect).toBeFalsy(); + }); + + it("should initialize organization from keyData", async () => { + const keyWithOrg = { + ...MOCK_KEY_DATA, + organization_id: "org-1", + }; + + renderWithProviders( + {}} + onSubmit={async () => {}} + accessToken="" + userID="" + userRole="Admin" + premiumUser={false} + />, + ); + + await waitFor(() => { + expect(screen.getByText("Engineering")).toBeInTheDocument(); + }); + }); + }); }); From f6a8087375aaa0eb75569aa1179afaa5ccd29ed4 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Fri, 13 Mar 2026 18:17:18 -0700 Subject: [PATCH 045/289] [Test] Add test for all-team-models sentinel skip in team change validation Verifies that validate_key_team_change does not call can_team_access_model for the "all-team-models" sentinel, allowing keys with that value to be moved between teams without model validation failures. Co-Authored-By: Claude Opus 4.6 --- .../test_key_management_endpoints.py | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py index e496cf373e..cfc16808af 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py @@ -1502,6 +1502,57 @@ async def test_validate_key_team_change_with_member_permissions(): ) +@pytest.mark.asyncio +async def test_validate_key_team_change_skips_all_team_models_sentinel(): + """ + Test that validate_key_team_change skips the 'all-team-models' sentinel + value when checking if the target team can access the key's models. + + Keys with models=["all-team-models"] mean "use whatever models the team + allows", so moving them to any team should not fail model validation. + """ + from unittest.mock import AsyncMock, MagicMock, patch + + mock_key = MagicMock() + mock_key.user_id = "test-user-123" + mock_key.models = ["all-team-models"] + mock_key.tpm_limit = None + mock_key.rpm_limit = None + + mock_team = MagicMock() + mock_team.team_id = "test-team-456" + mock_team.models = ["gpt-4", "claude-3"] + mock_team.members_with_roles = [] + mock_team.tpm_limit = None + mock_team.rpm_limit = None + + mock_change_initiator = MagicMock() + mock_change_initiator.user_id = "test-user-123" + mock_change_initiator.user_role = LitellmUserRoles.PROXY_ADMIN.value + + mock_router = MagicMock() + + with patch( + "litellm.proxy.management_endpoints.key_management_endpoints.can_team_access_model", + new_callable=AsyncMock, + ) as mock_can_access: + with patch( + "litellm.proxy.management_endpoints.key_management_endpoints._get_user_in_team" + ) as mock_get_user: + mock_get_user.return_value = MagicMock() + + await validate_key_team_change( + key=mock_key, + team=mock_team, + change_initiated_by=mock_change_initiator, + llm_router=mock_router, + ) + + # can_team_access_model should NOT have been called since + # "all-team-models" is a sentinel that should be skipped + mock_can_access.assert_not_called() + + def test_key_rotation_fields_helper(): """ Test the key data update logic for rotation fields. From feee689e878f58b2a10e00346a8c3d53440c3e64 Mon Sep 17 00:00:00 2001 From: joereyna Date: Thu, 12 Mar 2026 12:34:17 -0700 Subject: [PATCH 046/289] fix: set oauth2_flow when building MCPServer in _execute_with_mcp_client --- litellm/proxy/_experimental/mcp_server/rest_endpoints.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py index 307caa2fbc..298fe36342 100644 --- a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py +++ b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py @@ -906,9 +906,11 @@ if MCP_AVAILABLE: client_id, client_secret, scopes = _extract_credentials(request) _oauth2_flow: Optional[Literal["client_credentials", "authorization_code"]] = ( - "client_credentials" - if client_id and client_secret and request.token_url - else None + request.oauth2_flow or ( + "client_credentials" + if client_id and client_secret and request.token_url + else None + ) ) server_model = MCPServer( From 377b79afae88aee52574c41334f8cd1a8b2d9be3 Mon Sep 17 00:00:00 2001 From: joereyna Date: Thu, 12 Mar 2026 18:21:19 -0700 Subject: [PATCH 047/289] fix: add oauth2_flow to NewMCPServerRequest and guard auto-detect with token_url --- litellm/proxy/_types.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index b7ac4212cb..f4c3a03fb6 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -1123,6 +1123,7 @@ class NewMCPServerRequest(LiteLLMPydanticObjectBase): authorization_url: Optional[str] = None token_url: Optional[str] = None registration_url: Optional[str] = None + oauth2_flow: Optional[str] = None allow_all_keys: bool = False available_on_public_internet: bool = True is_byok: bool = False From cd7b25842b10c5e38a0db820fe9e1a5e07cc7aba Mon Sep 17 00:00:00 2001 From: joereyna Date: Fri, 13 Mar 2026 19:46:02 -0700 Subject: [PATCH 048/289] fix: narrow oauth2_flow type to Literal in NewMCPServerRequest --- litellm/proxy/_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index f4c3a03fb6..dfc7c3f353 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -1123,7 +1123,7 @@ class NewMCPServerRequest(LiteLLMPydanticObjectBase): authorization_url: Optional[str] = None token_url: Optional[str] = None registration_url: Optional[str] = None - oauth2_flow: Optional[str] = None + oauth2_flow: Optional[Literal["client_credentials", "authorization_code"]] = None allow_all_keys: bool = False available_on_public_internet: bool = True is_byok: bool = False From 9379f24ef114d5adf88172aa0a6853b095b3fc2a Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Sat, 14 Mar 2026 09:58:35 +0530 Subject: [PATCH 049/289] fix: req changes by greptile on test coverage --- .../test_litellm/test_router_silent_experiment.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/test_litellm/test_router_silent_experiment.py b/tests/test_litellm/test_router_silent_experiment.py index 4d6a775c44..b3a6f59a8e 100644 --- a/tests/test_litellm/test_router_silent_experiment.py +++ b/tests/test_litellm/test_router_silent_experiment.py @@ -8,10 +8,20 @@ import litellm from litellm.router import Router +class _NonCopyableSpan: + """Mimics an OTel Span which raises on deepcopy, forcing safe_deep_copy + to fall back to the original reference.""" + + def __deepcopy__(self, memo): + raise TypeError("OTel spans cannot be deepcopied") + + def test_get_silent_experiment_kwargs(): """ Test _get_silent_experiment_kwargs returns isolated kwargs with silent experiment metadata. - Direct call for router code coverage. + + Uses a non-copyable span object so that safe_deep_copy falls back to the + original metadata reference — exercising the identity-check fix path. """ model_list = [ { @@ -20,7 +30,7 @@ def test_get_silent_experiment_kwargs(): }, ] router = Router(model_list=model_list) - mock_span = MagicMock() + mock_span = _NonCopyableSpan() kwargs = { "metadata": {"foo": "bar", "litellm_parent_otel_span": mock_span}, "litellm_call_id": "call-123", From 550ef1eeeabe3548ffb8847899cfcfe11c7d269a Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Sat, 14 Mar 2026 10:01:40 +0530 Subject: [PATCH 050/289] fix: test coverage --- .../test_router_silent_experiment.py | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/tests/test_litellm/test_router_silent_experiment.py b/tests/test_litellm/test_router_silent_experiment.py index b3a6f59a8e..6be95ca91a 100644 --- a/tests/test_litellm/test_router_silent_experiment.py +++ b/tests/test_litellm/test_router_silent_experiment.py @@ -16,12 +16,28 @@ class _NonCopyableSpan: raise TypeError("OTel spans cannot be deepcopied") +class _FakeUserAPIKeyAuth: + """Mimics UserAPIKeyAuth which contains a parent_otel_span that is not + deepcopy-able. This is what actually causes safe_deep_copy to fail for + the metadata dict in production — safe_deep_copy handles the top-level + litellm_parent_otel_span specially (pops it before copying), but does + NOT handle user_api_key_auth.parent_otel_span inside it.""" + + def __init__(self, key_alias, parent_otel_span): + self.key_alias = key_alias + self.parent_otel_span = parent_otel_span + + def __deepcopy__(self, memo): + raise TypeError("Contains OTel span that cannot be deepcopied") + + def test_get_silent_experiment_kwargs(): """ Test _get_silent_experiment_kwargs returns isolated kwargs with silent experiment metadata. - Uses a non-copyable span object so that safe_deep_copy falls back to the - original metadata reference — exercising the identity-check fix path. + Uses a non-copyable user_api_key_auth (mimicking the real proxy scenario) + so that safe_deep_copy falls back to the original metadata reference — + exercising the identity-check fix path. """ model_list = [ { @@ -31,8 +47,16 @@ def test_get_silent_experiment_kwargs(): ] router = Router(model_list=model_list) mock_span = _NonCopyableSpan() + mock_auth = _FakeUserAPIKeyAuth( + key_alias="HaneefKeyNonTeamProd", + parent_otel_span=mock_span, + ) kwargs = { - "metadata": {"foo": "bar", "litellm_parent_otel_span": mock_span}, + "metadata": { + "foo": "bar", + "litellm_parent_otel_span": mock_span, + "user_api_key_auth": mock_auth, + }, "litellm_call_id": "call-123", "stream": True, "proxy_server_request": {"body": {"model": "test"}}, @@ -52,6 +76,7 @@ def test_get_silent_experiment_kwargs(): # Original metadata must NOT be mutated assert "is_silent_experiment" not in kwargs["metadata"] assert kwargs["metadata"]["litellm_parent_otel_span"] is mock_span + assert kwargs["metadata"]["user_api_key_auth"] is mock_auth def test_silent_experiment_completion_direct(): From 4fb71e4a21192eae092dc25213d6323572dd8fe5 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Fri, 13 Mar 2026 21:38:20 -0700 Subject: [PATCH 051/289] [Fix] Fix tag/list 500 error from invalid Prisma group_by kwargs Use `min`/`max` instead of `_min`/`_max` for Prisma group_by input parameters. The underscore-prefixed names are output keys, not input kwargs. Co-Authored-By: Claude Opus 4.6 --- .../management_endpoints/tag_management_endpoints.py | 11 ++++------- .../test_tag_management_endpoints.py | 6 +++--- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/litellm/proxy/management_endpoints/tag_management_endpoints.py b/litellm/proxy/management_endpoints/tag_management_endpoints.py index 8e3061c203..0e60820aab 100644 --- a/litellm/proxy/management_endpoints/tag_management_endpoints.py +++ b/litellm/proxy/management_endpoints/tag_management_endpoints.py @@ -456,11 +456,8 @@ async def list_tags( dynamic_tag_rows = await prisma_client.db.litellm_dailytagspend.group_by( by=["tag"], where={"tag": {"not": None}}, - # The old find_many(distinct=...) returned arbitrary timestamps from - # whichever row Prisma happened to pick. MIN/MAX give more meaningful - # values: earliest appearance and most recent activity. - _min={"created_at": True}, - _max={"updated_at": True}, + min={"created_at": True}, + max={"updated_at": True}, ) dynamic_tag_config = [ @@ -468,8 +465,8 @@ async def list_tags( "name": row["tag"], "description": "This is just a spend tag that was passed dynamically in a request. It does not control any LLM models.", "models": None, - "created_at": row["_min"]["created_at"].isoformat(), - "updated_at": row["_max"]["updated_at"].isoformat(), + "created_at": row["_min"]["created_at"], + "updated_at": row["_max"]["updated_at"], } for row in dynamic_tag_rows if row["tag"] not in stored_tag_names diff --git a/tests/test_litellm/proxy/management_endpoints/test_tag_management_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_tag_management_endpoints.py index f330b40282..4b443f211f 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_tag_management_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_tag_management_endpoints.py @@ -282,9 +282,9 @@ async def test_list_tags_with_dynamic_tags(): # Setup dynamic tags via group_by — includes one that overlaps with stored mock_db.litellm_dailytagspend.group_by = AsyncMock(return_value=[ - {"tag": "dynamic-tag-1", "_min": {"created_at": datetime(2025, 2, 1)}, "_max": {"updated_at": datetime(2025, 3, 1)}}, - {"tag": "dynamic-tag-2", "_min": {"created_at": datetime(2025, 2, 2)}, "_max": {"updated_at": datetime(2025, 3, 2)}}, - {"tag": "stored-tag", "_min": {"created_at": datetime(2025, 1, 1)}, "_max": {"updated_at": datetime(2025, 1, 1)}}, # duplicate, should be excluded + {"tag": "dynamic-tag-1", "_min": {"created_at": "2025-02-01T00:00:00Z"}, "_max": {"updated_at": "2025-03-01T00:00:00Z"}}, + {"tag": "dynamic-tag-2", "_min": {"created_at": "2025-02-02T00:00:00Z"}, "_max": {"updated_at": "2025-03-02T00:00:00Z"}}, + {"tag": "stored-tag", "_min": {"created_at": "2025-01-01T00:00:00Z"}, "_max": {"updated_at": "2025-01-01T00:00:00Z"}}, # duplicate, should be excluded ]) headers = {"Authorization": "Bearer sk-1234"} From a0a951b34fd023ad4a8d8136f501055175a86997 Mon Sep 17 00:00:00 2001 From: RoomWithOutRoof <166608075+Jah-yee@users.noreply.github.com> Date: Sat, 14 Mar 2026 12:54:43 +0800 Subject: [PATCH 052/289] fix: forward extra_headers to HuggingFace embedding calls (#23525) Fixes #23502 The huggingface_embed.embedding() call was not receiving the headers parameter, causing extra_headers (e.g., X-HF-Bill-To) to be silently dropped. Other providers (openrouter, vercel_ai_gateway, bedrock) already pass headers correctly. This fix adds headers=headers to match the behavior of other providers. Co-authored-by: Jah-yee --- litellm/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litellm/main.py b/litellm/main.py index 722b4a7aae..5a1b7f0fe1 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -5122,6 +5122,7 @@ def embedding( # noqa: PLR0915 client=client, aembedding=aembedding, litellm_params=litellm_params_dict, + headers=headers, ) elif custom_llm_provider == "bedrock": if isinstance(input, str): From 7bb2d78394d395b74363115aa6f33b4f11ed3888 Mon Sep 17 00:00:00 2001 From: "Ethan T." Date: Sat, 14 Mar 2026 12:58:58 +0800 Subject: [PATCH 053/289] fix: add getPopupContainer to Select components in fallback modal to fix z-index issue (#23516) The model dropdown menus in the Add Fallbacks modal were rendering behind the modal overlay because Ant Design portals Select dropdowns to document.body by default. By setting getPopupContainer to attach the dropdown to its parent element, the dropdown inherits the modal's stacking context and renders above the modal. Fixes #17895 --- .../Settings/RouterSettings/Fallbacks/FallbackGroupConfig.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/FallbackGroupConfig.tsx b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/FallbackGroupConfig.tsx index 24ce80f0a0..86d70048b6 100644 --- a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/FallbackGroupConfig.tsx +++ b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/FallbackGroupConfig.tsx @@ -78,6 +78,7 @@ export function FallbackGroupConfig({ value={group.primaryModel} onChange={handlePrimaryChange} showSearch + getPopupContainer={(trigger) => trigger.parentElement || document.body} filterOption={(input, option) => (option?.label ?? "").toLowerCase().includes(input.toLowerCase()) } @@ -125,6 +126,7 @@ export function FallbackGroupConfig({ value={group.fallbackModels} onChange={handleFallbackSelect} disabled={!group.primaryModel} + getPopupContainer={(trigger) => trigger.parentElement || document.body} options={availableFallbackOptions.map((m) => ({ label: m, value: m, From c7ba7948bc79606f96382f4f334a528ba12ad28a Mon Sep 17 00:00:00 2001 From: Awais Qureshi Date: Sat, 14 Mar 2026 10:41:25 +0500 Subject: [PATCH 054/289] =?UTF-8?q?PR=20#22867=20added=20=5Fremove=5Fscope?= =?UTF-8?q?=5Ffrom=5Fcache=5Fcontrol=20for=20Bedrock=20and=20Azur=E2=80=A6?= =?UTF-8?q?=20(#23183)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * PR #22867 added _remove_scope_from_cache_control for Bedrock and Azure AI but omitted Vertex AI. This applies the same pattern to VertexAIPartnerModelsAnthropicMessagesConfig." * PR #22867 added _remove_scope_from_cache_control for Bedrock and Azure AI but omitted Vertex AI. This applies the same pattern to VertexAIPartnerModelsAnthropicMessagesConfig." * PR #22867 added _remove_scope_from_cache_control to AzureAnthropicMessagesConfig but missed VertexAIPartnerModelsAnthropicMessagesConfi Rather than duplicating the method again, moved it up to the base AnthropicMessagesConfig so all providers inherit it, and removed the now-redundant copy from the Azure AI subclass. * PR #22867 added _remove_scope_from_cache_control to AzureAnthropicMessagesConfig but missed VertexAIPartnerModelsAnthropicMessagesConfi Rather than duplicating the method again, moved it up to the base AnthropicMessagesConfig so all providers inherit it, and removed the now-redundant copy from the Azure AI subclass. --------- Co-authored-by: Krish Dholakia --- .../messages/transformation.py | 32 +++++++++++++ .../transformation.py | 2 + ...artner_models_anthropic_messages_config.py | 45 +++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/litellm/llms/anthropic/experimental_pass_through/messages/transformation.py b/litellm/llms/anthropic/experimental_pass_through/messages/transformation.py index 4d0a2cd829..e9ceea4822 100644 --- a/litellm/llms/anthropic/experimental_pass_through/messages/transformation.py +++ b/litellm/llms/anthropic/experimental_pass_through/messages/transformation.py @@ -50,6 +50,38 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig): # "metadata", ] + def _remove_scope_from_cache_control( + self, anthropic_messages_request: Dict + ) -> None: + """ + Remove `scope` field from cache_control blocks. + + Some providers (Vertex AI, Azure AI Foundry) do not support the `scope` + field in cache_control (e.g. "global" for cross-request caching). + Processes both `system` and `messages` content blocks. + """ + + def _sanitize(cache_control: Any) -> None: + if isinstance(cache_control, dict): + cache_control.pop("scope", None) + + def _process_content_list(content: list) -> None: + for item in content: + if isinstance(item, dict) and "cache_control" in item: + _sanitize(item["cache_control"]) + + if "system" in anthropic_messages_request: + system = anthropic_messages_request["system"] + if isinstance(system, list): + _process_content_list(system) + + if "messages" in anthropic_messages_request: + for message in anthropic_messages_request["messages"]: + if isinstance(message, dict) and "content" in message: + content = message["content"] + if isinstance(content, list): + _process_content_list(content) + @staticmethod def _filter_billing_headers_from_system(system_param): """ diff --git a/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py b/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py index d3b0217d04..5c3bbf61ee 100644 --- a/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py +++ b/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py @@ -150,6 +150,8 @@ class VertexAIPartnerModelsAnthropicMessagesConfig(AnthropicMessagesConfig, Vert headers=headers, ) + self._remove_scope_from_cache_control(anthropic_messages_request) + anthropic_messages_request["anthropic_version"] = "vertex-2023-10-16" anthropic_messages_request.pop( diff --git a/tests/test_litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/test_vertex_ai_partner_models_anthropic_messages_config.py b/tests/test_litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/test_vertex_ai_partner_models_anthropic_messages_config.py index b5f076262d..391daa24f4 100644 --- a/tests/test_litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/test_vertex_ai_partner_models_anthropic_messages_config.py +++ b/tests/test_litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/test_vertex_ai_partner_models_anthropic_messages_config.py @@ -5,6 +5,7 @@ import pytest from litellm.llms.vertex_ai.vertex_ai_partner_models.anthropic.experimental_pass_through.transformation import ( VertexAIPartnerModelsAnthropicMessagesConfig, ) +from litellm.types.router import GenericLiteLLMParams def test_validate_environment_uses_vertex_ai_location(): @@ -248,3 +249,47 @@ def test_validate_environment_with_authorization_header_calculates_api_base(): # Verify Authorization header is still present assert "Authorization" in updated_headers, \ "Authorization header should be preserved" + + +def test_transform_anthropic_messages_request_removes_scope_from_cache_control(): + """Ensure scope field is removed from cache_control for Vertex AI (not supported).""" + config = VertexAIPartnerModelsAnthropicMessagesConfig() + + messages = [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Hello", + "cache_control": {"type": "ephemeral", "scope": "global"}, + } + ], + } + ] + anthropic_messages_optional_request_params = { + "max_tokens": 1024, + "system": [ + { + "type": "text", + "text": "You are an AI assistant.", + "cache_control": {"type": "ephemeral", "scope": "global"}, + } + ], + } + + result = config.transform_anthropic_messages_request( + model="claude-sonnet-4-6", + messages=messages, + anthropic_messages_optional_request_params=anthropic_messages_optional_request_params, + litellm_params=GenericLiteLLMParams(), + headers={}, + ) + + # scope removed from system + assert "scope" not in result["system"][0]["cache_control"] + assert result["system"][0]["cache_control"]["type"] == "ephemeral" + + # scope removed from message content + assert "scope" not in result["messages"][0]["content"][0]["cache_control"] + assert result["messages"][0]["content"][0]["cache_control"]["type"] == "ephemeral" From a94b961c18995eb51bf07bbfb6386eb7eac91e33 Mon Sep 17 00:00:00 2001 From: Pradyumna Yadav Date: Sat, 14 Mar 2026 11:18:45 +0530 Subject: [PATCH 055/289] fix: auto-fill reasoning_content for moonshot kimi reasoning models in multi-turn tool calling (#23580) --- litellm/llms/moonshot/chat/transformation.py | 70 +++++++-- ...odel_prices_and_context_window_backup.json | 3 + model_prices_and_context_window.json | 3 + .../test_moonshot_chat_transformation.py | 148 +++++++++++++++++- 4 files changed, 207 insertions(+), 17 deletions(-) diff --git a/litellm/llms/moonshot/chat/transformation.py b/litellm/llms/moonshot/chat/transformation.py index 3ed08f51c8..40096be05c 100644 --- a/litellm/llms/moonshot/chat/transformation.py +++ b/litellm/llms/moonshot/chat/transformation.py @@ -2,13 +2,15 @@ Translates from OpenAI's `/v1/chat/completions` to Moonshot AI's `/v1/chat/completions` """ -from typing import Any, Coroutine, List, Literal, Optional, Tuple, Union, overload +from typing import Any, Coroutine, List, Literal, Optional, Tuple, Union, cast, overload +import litellm from litellm.litellm_core_utils.prompt_templates.common_utils import ( handle_messages_with_content_list_to_str_conversion, ) from litellm.secret_managers.main import get_secret_str from litellm.types.llms.openai import AllMessageValues +from litellm.utils import supports_reasoning from ...openai.chat.gpt_transformation import OpenAIGPTConfig @@ -17,8 +19,7 @@ class MoonshotChatConfig(OpenAIGPTConfig): @overload def _transform_messages( self, messages: List[AllMessageValues], model: str, is_async: Literal[True] - ) -> Coroutine[Any, Any, List[AllMessageValues]]: - ... + ) -> Coroutine[Any, Any, List[AllMessageValues]]: ... @overload def _transform_messages( @@ -26,8 +27,7 @@ class MoonshotChatConfig(OpenAIGPTConfig): messages: List[AllMessageValues], model: str, is_async: Literal[False] = False, - ) -> List[AllMessageValues]: - ... + ) -> List[AllMessageValues]: ... def _transform_messages( self, messages: List[AllMessageValues], model: str, is_async: bool = False @@ -53,22 +53,14 @@ class MoonshotChatConfig(OpenAIGPTConfig): messages = handle_messages_with_content_list_to_str_conversion(messages) if is_async: - return super()._transform_messages( - messages=messages, model=model, is_async=True - ) + return super()._transform_messages(messages=messages, model=model, is_async=True) else: - return super()._transform_messages( - messages=messages, model=model, is_async=False - ) + return super()._transform_messages(messages=messages, model=model, is_async=False) def _get_openai_compatible_provider_info( self, api_base: Optional[str], api_key: Optional[str] ) -> Tuple[Optional[str], Optional[str]]: - api_base = ( - api_base - or get_secret_str("MOONSHOT_API_BASE") - or "https://api.moonshot.ai/v1" - ) # type: ignore + api_base = api_base or get_secret_str("MOONSHOT_API_BASE") or "https://api.moonshot.ai/v1" # type: ignore dynamic_api_key = api_key or get_secret_str("MOONSHOT_API_KEY") return api_base, dynamic_api_key @@ -149,6 +141,48 @@ class MoonshotChatConfig(OpenAIGPTConfig): optional_params["temperature"] = 0.3 return optional_params + def fill_reasoning_content(self, messages: List[AllMessageValues]) -> List[AllMessageValues]: + """ + Moonshot reasoning models require `reasoning_content` on every assistant + message that contains tool_calls (multi-turn tool-calling flows). + + For each such message that is missing the field: + 1. Promote provider_specific_fields["reasoning_content"] if present and non-empty + (this is where LiteLLM stores it from a previous response) + 2. Otherwise inject a single space — the minimum value the API accepts + Messages that already carry the field, or are not assistant/tool-call messages, + are appended as-is (no copy made). + """ + result: List[AllMessageValues] = [] + for msg in messages: + if ( + msg.get("role") == "assistant" + and msg.get("tool_calls") + and "reasoning_content" not in msg + ): + patched = dict(cast(dict, msg)) + provider_fields = patched.get("provider_specific_fields") or {} + stored = provider_fields.get("reasoning_content") + if stored: + patched["reasoning_content"] = stored + # Remove the promoted key from provider_specific_fields to + # avoid sending the value twice in the serialised request body + cleaned_provider_fields = dict(provider_fields) + cleaned_provider_fields.pop("reasoning_content", None) + patched["provider_specific_fields"] = cleaned_provider_fields + else: + litellm.verbose_logger.warning( + "Moonshot reasoning model: assistant tool-call message is missing " + "`reasoning_content`. Injecting a placeholder to satisfy API validation. " + "For best results, preserve `reasoning_content` from the original " + "assistant response when building multi-turn conversation history." + ) + patched["reasoning_content"] = " " + result.append(cast(AllMessageValues, patched)) + else: + result.append(msg) + return result + def transform_request( self, model: str, @@ -169,6 +203,10 @@ class MoonshotChatConfig(OpenAIGPTConfig): optional_params=optional_params, ) + # Moonshot reasoning models: fill in reasoning_content before the API call + if supports_reasoning(model=model, custom_llm_provider="moonshot"): + messages = self.fill_reasoning_content(messages) + # Call parent transform_request which handles _transform_messages return super().transform_request( model=model, diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 9b1d81fee4..6786fc3359 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -22083,6 +22083,7 @@ "output_cost_per_token": 3e-06, "source": "https://platform.moonshot.ai/docs/guide/kimi-k2-5-quickstart", "supports_function_calling": true, + "supports_reasoning": true, "supports_tool_choice": true, "supports_video_input": true, "supports_vision": true @@ -22166,6 +22167,7 @@ "output_cost_per_token": 2.5e-06, "source": "https://platform.moonshot.ai/docs/pricing/chat#generation-model-kimi-k2", "supports_function_calling": true, + "supports_reasoning": true, "supports_tool_choice": true, "supports_web_search": true }, @@ -22180,6 +22182,7 @@ "output_cost_per_token": 8e-06, "source": "https://platform.moonshot.ai/docs/pricing/chat#generation-model-kimi-k2", "supports_function_calling": true, + "supports_reasoning": true, "supports_tool_choice": true, "supports_web_search": true }, diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 9b1d81fee4..6786fc3359 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -22083,6 +22083,7 @@ "output_cost_per_token": 3e-06, "source": "https://platform.moonshot.ai/docs/guide/kimi-k2-5-quickstart", "supports_function_calling": true, + "supports_reasoning": true, "supports_tool_choice": true, "supports_video_input": true, "supports_vision": true @@ -22166,6 +22167,7 @@ "output_cost_per_token": 2.5e-06, "source": "https://platform.moonshot.ai/docs/pricing/chat#generation-model-kimi-k2", "supports_function_calling": true, + "supports_reasoning": true, "supports_tool_choice": true, "supports_web_search": true }, @@ -22180,6 +22182,7 @@ "output_cost_per_token": 8e-06, "source": "https://platform.moonshot.ai/docs/pricing/chat#generation-model-kimi-k2", "supports_function_calling": true, + "supports_reasoning": true, "supports_tool_choice": true, "supports_web_search": true }, diff --git a/tests/test_litellm/llms/moonshot/test_moonshot_chat_transformation.py b/tests/test_litellm/llms/moonshot/test_moonshot_chat_transformation.py index 345186e8a6..c557fb395f 100644 --- a/tests/test_litellm/llms/moonshot/test_moonshot_chat_transformation.py +++ b/tests/test_litellm/llms/moonshot/test_moonshot_chat_transformation.py @@ -7,6 +7,7 @@ Moonshot AI is an OpenAI-compatible provider with minor customizations. import os import sys +from unittest.mock import patch sys.path.insert( 0, os.path.abspath("../../../../..") @@ -404,4 +405,149 @@ class TestMoonshotConfig: # Content should be flattened to a plain string assert isinstance(result["messages"][0]["content"], str) - assert result["messages"][0]["content"] == "Hello, how are you?" \ No newline at end of file + assert result["messages"][0]["content"] == "Hello, how are you?" + + # ------------------------------------------------------------------ # + # Tests for fill_reasoning_content # + # ------------------------------------------------------------------ # + + def test_reasoning_content_space_injected_when_absent(self): + """Assistant tool-call message with no reasoning_content gets a space injected.""" + config = MoonshotChatConfig() + + messages = [ + {"role": "user", "content": "What's the weather?"}, + { + "role": "assistant", + "content": None, + "tool_calls": [ + {"id": "call_1", "type": "function", "function": {"name": "get_weather", "arguments": "{}"}} + ], + }, + {"role": "tool", "tool_call_id": "call_1", "content": "Sunny, 22°C"}, + ] + + result = config.fill_reasoning_content(messages) + + assert result[1].get("reasoning_content") == " " + # Non-assistant messages are untouched + assert "reasoning_content" not in result[0] + assert "reasoning_content" not in result[2] + + def test_empty_tool_calls_list_not_injected(self): + """Assistant message with tool_calls: [] should not get reasoning_content injected.""" + config = MoonshotChatConfig() + + original_msg = { + "role": "assistant", + "content": "Here is the answer.", + "tool_calls": [], + } + messages = [original_msg] + + result = config.fill_reasoning_content(messages) + + assert "reasoning_content" not in result[0] + assert result[0] is original_msg + + def test_existing_reasoning_content_not_overwritten(self): + """Message that already has reasoning_content is passed through unchanged.""" + config = MoonshotChatConfig() + + original_msg = { + "role": "assistant", + "content": None, + "tool_calls": [ + {"id": "call_1", "type": "function", "function": {"name": "fn", "arguments": "{}"}} + ], + "reasoning_content": "", + } + messages = [original_msg] + + result = config.fill_reasoning_content(messages) + + assert result[0].get("reasoning_content") == "" + # Same object — no copy was made + assert result[0] is original_msg + + def test_provider_specific_fields_reasoning_content_promoted(self): + """reasoning_content stored in provider_specific_fields is promoted to top level.""" + config = MoonshotChatConfig() + + messages = [ + { + "role": "assistant", + "content": None, + "tool_calls": [ + {"id": "call_1", "type": "function", "function": {"name": "fn", "arguments": "{}"}} + ], + "provider_specific_fields": {"reasoning_content": "stored thinking"}, + } + ] + + result = config.fill_reasoning_content(messages) + + assert result[0].get("reasoning_content") == "stored thinking" + # The promoted key must be removed from provider_specific_fields to + # avoid sending the value twice in the serialised request body + assert "reasoning_content" not in (result[0].get("provider_specific_fields") or {}) + + def test_reasoning_model_fill_called_from_transform_request(self): + """transform_request injects reasoning_content end-to-end for reasoning models.""" + config = MoonshotChatConfig() + + messages = [ + {"role": "user", "content": "Call a tool"}, + { + "role": "assistant", + "content": None, + "tool_calls": [ + {"id": "call_1", "type": "function", "function": {"name": "fn", "arguments": "{}"}} + ], + }, + ] + + with patch( + "litellm.llms.moonshot.chat.transformation.supports_reasoning", + return_value=True, + ): + result = config.transform_request( + model="kimi-k2-thinking", + messages=messages, + optional_params={}, + litellm_params={}, + headers={}, + ) + + assert result["messages"][1].get("reasoning_content") == " " + + def test_non_reasoning_model_messages_untouched(self): + """For non-reasoning models, transform_request leaves messages unchanged.""" + config = MoonshotChatConfig() + + messages = [ + {"role": "user", "content": "Hello"}, + { + "role": "assistant", + "content": None, + "tool_calls": [ + {"id": "call_1", "type": "function", "function": {"name": "fn", "arguments": "{}"}} + ], + }, + ] + + with patch( + "litellm.llms.moonshot.chat.transformation.supports_reasoning", + return_value=False, + ): + result = config.transform_request( + model="moonshot-v1-8k", + messages=messages, + optional_params={}, + litellm_params={}, + headers={}, + ) + + # reasoning_content must not have been injected + for msg in result["messages"]: + assert "reasoning_content" not in msg \ No newline at end of file From 1b0c4bdbb7875d965fe51268835722b2a15d4e7a Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Fri, 13 Mar 2026 21:47:03 -0700 Subject: [PATCH 056/289] Add unit tests for 5 previously untested UI components Tests for HelpLink, ScoreChart, AgentCard, ToolPoliciesView, and CostBreakdownViewer (33 tests total). Co-Authored-By: Claude Opus 4.6 --- .../GuardrailsMonitor/ScoreChart.test.tsx | 54 ++++++++ .../src/components/HelpLink.test.tsx | 117 ++++++++++++++++++ .../src/components/ToolPoliciesView.test.tsx | 53 ++++++++ .../src/components/agents/agent_card.test.tsx | 99 +++++++++++++++ .../view_logs/CostBreakdownViewer.test.tsx | 117 ++++++++++++++++++ 5 files changed, 440 insertions(+) create mode 100644 ui/litellm-dashboard/src/components/GuardrailsMonitor/ScoreChart.test.tsx create mode 100644 ui/litellm-dashboard/src/components/HelpLink.test.tsx create mode 100644 ui/litellm-dashboard/src/components/ToolPoliciesView.test.tsx create mode 100644 ui/litellm-dashboard/src/components/agents/agent_card.test.tsx create mode 100644 ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.test.tsx diff --git a/ui/litellm-dashboard/src/components/GuardrailsMonitor/ScoreChart.test.tsx b/ui/litellm-dashboard/src/components/GuardrailsMonitor/ScoreChart.test.tsx new file mode 100644 index 0000000000..848807ce5a --- /dev/null +++ b/ui/litellm-dashboard/src/components/GuardrailsMonitor/ScoreChart.test.tsx @@ -0,0 +1,54 @@ +import React from "react"; +import { describe, it, expect, vi } from "vitest"; +import { screen } from "@testing-library/react"; +import { renderWithProviders } from "../../../tests/test-utils"; +import { ScoreChart } from "./ScoreChart"; + +vi.mock("@tremor/react", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + BarChart: ({ data, categories }: { data: any[]; categories: string[] }) => ( +
+ {data.map((d, i) => ( + + {d.date}: {categories.map((c) => `${c}=${d[c]}`).join(", ")} + + ))} +
+ ), + }; +}); + +describe("ScoreChart", () => { + it("should render the title", () => { + renderWithProviders(); + + expect(screen.getByText("Request Outcomes Over Time")).toBeInTheDocument(); + }); + + it("should show empty state when no data is provided", () => { + renderWithProviders(); + + expect(screen.getByText("No chart data for this period")).toBeInTheDocument(); + }); + + it("should show empty state when data is an empty array", () => { + renderWithProviders(); + + expect(screen.getByText("No chart data for this period")).toBeInTheDocument(); + }); + + it("should render the chart when data is provided", () => { + const data = [ + { date: "2026-03-01", passed: 10, blocked: 2 }, + { date: "2026-03-02", passed: 15, blocked: 1 }, + ]; + + renderWithProviders(); + + expect(screen.queryByText("No chart data for this period")).not.toBeInTheDocument(); + expect(screen.getByText(/2026-03-01/)).toBeInTheDocument(); + expect(screen.getByText(/2026-03-02/)).toBeInTheDocument(); + }); +}); diff --git a/ui/litellm-dashboard/src/components/HelpLink.test.tsx b/ui/litellm-dashboard/src/components/HelpLink.test.tsx new file mode 100644 index 0000000000..72033bd93a --- /dev/null +++ b/ui/litellm-dashboard/src/components/HelpLink.test.tsx @@ -0,0 +1,117 @@ +import React from "react"; +import { describe, it, expect, vi } from "vitest"; +import { screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { renderWithProviders } from "../../tests/test-utils"; +import { HelpLink, HelpIcon, DocsMenu } from "./HelpLink"; + +describe("HelpLink", () => { + it("should render with default children and open in new tab", () => { + renderWithProviders(); + + const link = screen.getByRole("link", { name: /learn more/i }); + expect(link).toHaveAttribute("href", "https://docs.example.com"); + expect(link).toHaveAttribute("target", "_blank"); + expect(link).toHaveAttribute("rel", "noopener noreferrer"); + }); + + it("should render custom children text", () => { + renderWithProviders( + Custom docs link + ); + + expect(screen.getByText("Custom docs link")).toBeInTheDocument(); + }); + + it("should include a screen-reader-only label for accessibility", () => { + renderWithProviders(); + + expect(screen.getByText("(opens in a new tab)")).toBeInTheDocument(); + }); +}); + +describe("HelpIcon", () => { + it("should render a help button with accessible label", () => { + renderWithProviders(); + + expect(screen.getByRole("button", { name: /help information/i })).toBeInTheDocument(); + }); + + it("should show tooltip content on hover", async () => { + const user = userEvent.setup(); + renderWithProviders(); + + await user.hover(screen.getByRole("button", { name: /help information/i })); + + expect(screen.getByText("Tooltip help text")).toBeInTheDocument(); + }); + + it("should show learn more link when learnMoreHref is provided", async () => { + const user = userEvent.setup(); + renderWithProviders( + + ); + + await user.hover(screen.getByRole("button", { name: /help information/i })); + + const link = screen.getByRole("link", { name: /read docs/i }); + expect(link).toHaveAttribute("href", "https://docs.example.com"); + }); + + it("should not show learn more link when learnMoreHref is not provided", async () => { + const user = userEvent.setup(); + renderWithProviders(); + + await user.hover(screen.getByRole("button", { name: /help information/i })); + + expect(screen.queryByRole("link")).not.toBeInTheDocument(); + }); +}); + +describe("DocsMenu", () => { + const items = [ + { label: "Custom pricing", href: "https://docs.example.com/pricing" }, + { label: "Cost tracking", href: "https://docs.example.com/cost" }, + ]; + + it("should render the menu button with default text", () => { + renderWithProviders(); + + expect(screen.getByRole("button", { name: /docs/i })).toBeInTheDocument(); + }); + + it("should show menu items when button is clicked", async () => { + const user = userEvent.setup(); + renderWithProviders(); + + await user.click(screen.getByRole("button", { name: /docs/i })); + + expect(screen.getByText("Custom pricing")).toBeInTheDocument(); + expect(screen.getByText("Cost tracking")).toBeInTheDocument(); + }); + + it("should close the menu when an item is clicked", async () => { + const user = userEvent.setup(); + renderWithProviders(); + + await user.click(screen.getByRole("button", { name: /docs/i })); + await user.click(screen.getByText("Custom pricing")); + + expect(screen.queryByText("Cost tracking")).not.toBeInTheDocument(); + }); + + it("should set aria-expanded correctly based on menu state", async () => { + const user = userEvent.setup(); + renderWithProviders(); + + const button = screen.getByRole("button", { name: /docs/i }); + expect(button).toHaveAttribute("aria-expanded", "false"); + + await user.click(button); + expect(button).toHaveAttribute("aria-expanded", "true"); + }); +}); diff --git a/ui/litellm-dashboard/src/components/ToolPoliciesView.test.tsx b/ui/litellm-dashboard/src/components/ToolPoliciesView.test.tsx new file mode 100644 index 0000000000..8b2b1d0e4b --- /dev/null +++ b/ui/litellm-dashboard/src/components/ToolPoliciesView.test.tsx @@ -0,0 +1,53 @@ +import React from "react"; +import { describe, it, expect, vi } from "vitest"; +import { screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { renderWithProviders } from "../../tests/test-utils"; +import ToolPoliciesView from "./ToolPoliciesView"; + +vi.mock("@/components/ToolDetail", () => ({ + ToolDetail: ({ toolName, onBack }: { toolName: string; onBack: () => void }) => ( +
+ Detail: {toolName} + +
+ ), +})); + +vi.mock("@/components/ToolPolicies", () => ({ + ToolPolicies: ({ onSelectTool }: { onSelectTool: (name: string) => void }) => ( +
+ Tool Policies Overview + +
+ ), +})); + +describe("ToolPoliciesView", () => { + it("should render the overview by default", () => { + renderWithProviders(); + + expect(screen.getByText("Tool Policies Overview")).toBeInTheDocument(); + }); + + it("should navigate to tool detail when a tool is selected", async () => { + const user = userEvent.setup(); + renderWithProviders(); + + await user.click(screen.getByRole("button", { name: /select tool/i })); + + expect(screen.getByText("Detail: my-tool")).toBeInTheDocument(); + expect(screen.queryByText("Tool Policies Overview")).not.toBeInTheDocument(); + }); + + it("should navigate back to overview when back is clicked", async () => { + const user = userEvent.setup(); + renderWithProviders(); + + await user.click(screen.getByRole("button", { name: /select tool/i })); + await user.click(screen.getByRole("button", { name: /back/i })); + + expect(screen.getByText("Tool Policies Overview")).toBeInTheDocument(); + expect(screen.queryByText("Detail: my-tool")).not.toBeInTheDocument(); + }); +}); diff --git a/ui/litellm-dashboard/src/components/agents/agent_card.test.tsx b/ui/litellm-dashboard/src/components/agents/agent_card.test.tsx new file mode 100644 index 0000000000..0f928866a0 --- /dev/null +++ b/ui/litellm-dashboard/src/components/agents/agent_card.test.tsx @@ -0,0 +1,99 @@ +import React from "react"; +import { describe, it, expect, vi } from "vitest"; +import { screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { renderWithProviders } from "../../../tests/test-utils"; +import AgentCard from "./agent_card"; +import type { Agent } from "./types"; + +const baseAgent: Agent = { + agent_id: "agent-123", + agent_name: "Test Agent", + litellm_params: { model: "gpt-4" }, + agent_card_params: { + description: "A test agent for unit testing", + url: "https://agent.example.com", + }, +}; + +const defaultProps = { + agent: baseAgent, + onAgentClick: vi.fn(), + accessToken: "token-123", + isAdmin: false, + onAgentUpdated: vi.fn(), +}; + +describe("AgentCard", () => { + it("should render the agent name and description", () => { + renderWithProviders(); + + expect(screen.getByText("Test Agent")).toBeInTheDocument(); + expect(screen.getByText("A test agent for unit testing")).toBeInTheDocument(); + }); + + it("should show 'No description' when agent has no description", () => { + const agent = { ...baseAgent, agent_card_params: {} }; + renderWithProviders(); + + expect(screen.getByText("No description")).toBeInTheDocument(); + }); + + it("should show the agent URL when provided", () => { + renderWithProviders(); + + expect(screen.getByText("https://agent.example.com")).toBeInTheDocument(); + }); + + it("should show 'Needs Setup' badge when agent has no key", () => { + renderWithProviders(); + + expect(screen.getByText("Needs Setup")).toBeInTheDocument(); + expect(screen.getByText("No key assigned")).toBeInTheDocument(); + }); + + it("should show 'Active' badge and key info when agent has a key", () => { + const keyInfo = { has_key: true, key_alias: "my-key" }; + renderWithProviders(); + + expect(screen.getByText("Active")).toBeInTheDocument(); + expect(screen.getByText("my-key")).toBeInTheDocument(); + }); + + it("should call onAgentClick when card is clicked", async () => { + const user = userEvent.setup(); + const onAgentClick = vi.fn(); + renderWithProviders(); + + await user.click(screen.getByText("Test Agent")); + + expect(onAgentClick).toHaveBeenCalledWith("agent-123"); + }); + + it("should show delete button only for admins", () => { + const onDeleteClick = vi.fn(); + const { unmount } = renderWithProviders( + + ); + expect(screen.queryByRole("button", { name: /delete/i })).not.toBeInTheDocument(); + + unmount(); + + renderWithProviders( + + ); + expect(screen.getByRole("button", { name: /delete/i })).toBeInTheDocument(); + }); + + it("should call onDeleteClick with agent id and name when delete is clicked", async () => { + const user = userEvent.setup(); + const onDeleteClick = vi.fn(); + renderWithProviders( + + ); + + await user.click(screen.getByRole("button", { name: /delete/i })); + + expect(onDeleteClick).toHaveBeenCalledWith("agent-123", "Test Agent"); + }); +}); diff --git a/ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.test.tsx b/ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.test.tsx new file mode 100644 index 0000000000..4a5cff3757 --- /dev/null +++ b/ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.test.tsx @@ -0,0 +1,117 @@ +import React from "react"; +import { describe, it, expect } from "vitest"; +import { screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { renderWithProviders } from "../../../tests/test-utils"; +import { CostBreakdownViewer, CostBreakdown } from "./CostBreakdownViewer"; + +describe("CostBreakdownViewer", () => { + it("should render nothing when there is no meaningful data", () => { + const { container } = renderWithProviders( + + ); + + expect(container.firstChild).toBeNull(); + }); + + it("should render nothing when costBreakdown is undefined", () => { + const { container } = renderWithProviders( + + ); + + expect(container.firstChild).toBeNull(); + }); + + it("should render the collapse header with heading and total", () => { + const breakdown: CostBreakdown = { + input_cost: 0.001, + output_cost: 0.002, + total_cost: 0.003, + }; + + renderWithProviders( + + ); + + expect(screen.getByRole("heading", { name: "Cost Breakdown" })).toBeInTheDocument(); + }); + + it("should show input and output costs when the panel is expanded", async () => { + const user = userEvent.setup(); + const breakdown: CostBreakdown = { + input_cost: 0.001, + output_cost: 0.002, + }; + + renderWithProviders( + + ); + + await user.click(screen.getByRole("heading", { name: "Cost Breakdown" })); + + expect(screen.getByText("Input Cost:")).toBeVisible(); + expect(screen.getByText("Output Cost:")).toBeVisible(); + expect(screen.getByText(/500 prompt tokens/)).toBeVisible(); + expect(screen.getByText(/200 completion tokens/)).toBeVisible(); + }); + + it("should show '(Cached)' in the header when cacheHit is true", () => { + const breakdown: CostBreakdown = { + input_cost: 0.001, + output_cost: 0.002, + total_cost: 0.003, + }; + + renderWithProviders( + + ); + + expect(screen.getByText(/\(Cached\)/)).toBeInTheDocument(); + }); + + it("should show discount label with percentage when panel is expanded", async () => { + const user = userEvent.setup(); + const breakdown: CostBreakdown = { + input_cost: 0.01, + output_cost: 0.02, + discount_percent: 0.1, + discount_amount: 0.003, + }; + + renderWithProviders( + + ); + + await user.click(screen.getByRole("heading", { name: "Cost Breakdown" })); + + expect(screen.getByText(/Discount \(10\.00%\)/)).toBeVisible(); + }); + + it("should show margin label with percentage when panel is expanded", async () => { + const user = userEvent.setup(); + const breakdown: CostBreakdown = { + input_cost: 0.01, + output_cost: 0.02, + margin_percent: 0.15, + margin_total_amount: 0.005, + }; + + renderWithProviders( + + ); + + await user.click(screen.getByRole("heading", { name: "Cost Breakdown" })); + + expect(screen.getByText(/Margin \(15\.00%\)/)).toBeVisible(); + expect(screen.getByText("Final Calculated Cost:")).toBeVisible(); + }); +}); From 81474c17fec6578044861ca2c5ff351bc73dbe1e Mon Sep 17 00:00:00 2001 From: xianzongxie-stripe <87151258+xianzongxie-stripe@users.noreply.github.com> Date: Fri, 13 Mar 2026 23:02:09 -0700 Subject: [PATCH 057/289] Handle response.failed, response.incomplete, and response.cancelled (#23492) * Handle response.failed, response.incomplete, and response.cancelled terminal events in background streaming Previously the background streaming task only handled response.completed and hardcoded the final status to "completed". This missed three other terminal event types from the OpenAI streaming spec, causing failed/incomplete/cancelled responses to be incorrectly marked as completed. Co-Authored-By: Claude Opus 4.6 Committed-By-Agent: claude * Remove unused terminal_response_data variable Co-Authored-By: Claude Opus 4.6 Committed-By-Agent: claude * Address code review: derive fallback status from event type, rewrite tests as integration tests 1. Replace hardcoded "completed" fallback in response_data.get("status") with _event_to_status lookup so that response.incomplete and response.cancelled events get the correct fallback if the response body ever omits the status field. 2. Replace duplicated-logic unit tests with integration tests that exercise background_streaming_task directly using mocked streaming responses and assert on the final update_state call arguments. Co-Authored-By: Claude Opus 4.6 Committed-By-Agent: claude * Remove dead mock_processor and unused mock_response parameter from test helper Co-Authored-By: Claude Opus 4.6 Committed-By-Agent: claude * Remove FastAPI and UserAPIKeyAuth imports from test file These types were only used as Mock(spec=...) arguments. Drop the spec constraints and remove the top-level imports to avoid pulling FastAPI into test files outside litellm/proxy/. Co-Authored-By: Claude Opus 4.6 Committed-By-Agent: claude * Log warning when streaming response has no body_iterator If base_process_llm_request returns a non-streaming response (no body_iterator), log a warning since this likely indicates a misconfiguration or provider error rather than a successful completion. Co-Authored-By: Claude Opus 4.6 Committed-By-Agent: claude --------- Co-authored-by: Claude Opus 4.6 --- .../response_polling/background_streaming.py | 44 ++- .../test_response_polling_handler.py | 261 ++++++++++++++++++ 2 files changed, 299 insertions(+), 6 deletions(-) diff --git a/litellm/proxy/response_polling/background_streaming.py b/litellm/proxy/response_polling/background_streaming.py index f1b2493976..682ad4943b 100644 --- a/litellm/proxy/response_polling/background_streaming.py +++ b/litellm/proxy/response_polling/background_streaming.py @@ -113,6 +113,16 @@ async def background_streaming_task( # noqa: PLR0915 last_update_time = asyncio.get_event_loop().time() UPDATE_INTERVAL = 0.150 # 150ms batching interval + # Track the terminal event from the stream (may not be "completed") + terminal_status = None # Will be set by response.completed/failed/incomplete/cancelled + terminal_error = None + _event_to_status = { + "response.completed": "completed", + "response.failed": "failed", + "response.incomplete": "incomplete", + "response.cancelled": "cancelled", + } + async def flush_state_if_needed(force: bool = False) -> None: """Flush accumulated state to Redis if interval elapsed or forced""" nonlocal state_dirty, last_update_time @@ -131,6 +141,12 @@ async def background_streaming_task( # noqa: PLR0915 last_update_time = current_time # Handle StreamingResponse + if not hasattr(response, "body_iterator"): + verbose_proxy_logger.warning( + f"background_streaming_task: response for {polling_id} has no " + "body_iterator; this may indicate a misconfiguration or provider error" + ) + if hasattr(response, "body_iterator"): async for chunk in response.body_iterator: # Parse chunk @@ -224,10 +240,23 @@ async def background_streaming_task( # noqa: PLR0915 status="in_progress", ) - elif event_type == "response.completed": - # Response completed - extract all ResponsesAPIResponse fields - # https://platform.openai.com/docs/api-reference/responses-streaming/response-completed + elif event_type in ( + "response.completed", + "response.failed", + "response.incomplete", + "response.cancelled", + ): + # Terminal event - extract all ResponsesAPIResponse fields + # https://platform.openai.com/docs/api-reference/responses-streaming response_data = event.get("response", {}) + terminal_status = response_data.get( + "status", + _event_to_status.get(event_type, "completed"), + ) + + # Extract error for failed responses + if event_type == "response.failed": + terminal_error = response_data.get("error") # Core response fields usage_data = response_data.get("usage") @@ -278,11 +307,14 @@ async def background_streaming_task( # noqa: PLR0915 # Final flush to ensure all accumulated state is saved await flush_state_if_needed(force=True) - # Mark as completed with all ResponsesAPIResponse fields + # Use the terminal status from the stream, default to "completed" + final_status = terminal_status or "completed" + await polling_handler.update_state( polling_id=polling_id, - status="completed", + status=final_status, usage=usage_data, + error=terminal_error, reasoning=reasoning_data, tool_choice=tool_choice_data, tools=tools_data, @@ -301,7 +333,7 @@ async def background_streaming_task( # noqa: PLR0915 ) verbose_proxy_logger.info( - f"Completed background streaming for {polling_id}, output_items={len(output_items)}" + f"Finished background streaming for {polling_id}, status={final_status}, output_items={len(output_items)}" ) except Exception as e: diff --git a/tests/proxy_unit_tests/test_response_polling_handler.py b/tests/proxy_unit_tests/test_response_polling_handler.py index 83e7e26728..6235dde847 100644 --- a/tests/proxy_unit_tests/test_response_polling_handler.py +++ b/tests/proxy_unit_tests/test_response_polling_handler.py @@ -1318,6 +1318,267 @@ class TestStreamingEventParsing: assert output_items["item_123"]["content"][0]["type"] == "text" +def _make_sse_stream(events: list) -> Mock: + """Create a mock StreamingResponse with body_iterator from a list of event dicts.""" + + async def _body_iterator(): + for event in events: + yield f"data: {json.dumps(event)}" + yield "data: [DONE]" + + mock_response = Mock() + mock_response.body_iterator = _body_iterator() + return mock_response + + +def _make_background_streaming_kwargs( + polling_id: str, + polling_handler: ResponsePollingHandler, +) -> dict: + """Build kwargs for background_streaming_task with all required mocks.""" + return dict( + polling_id=polling_id, + data={"model": "gpt-4o", "stream": False, "background": True}, + polling_handler=polling_handler, + request=Mock(), + fastapi_response=Mock(), + user_api_key_dict=Mock(), + general_settings={}, + llm_router=None, + proxy_config=Mock(), + proxy_logging_obj=Mock(), + select_data_generator=Mock(), + user_model=None, + user_temperature=None, + user_request_timeout=None, + user_max_tokens=None, + user_api_base=None, + version=None, + ) + + +@pytest.mark.xdist_group("heavy_imports") +class TestBackgroundStreamingTerminalEvents: + """ + Integration tests that exercise background_streaming_task with mocked + streaming responses, verifying the final update_state call for each + terminal event type. + """ + + @pytest.mark.asyncio + async def test_response_failed_sets_failed_status_and_error(self): + """Test that a response.failed stream event results in failed status with error""" + from litellm.proxy.response_polling.background_streaming import ( + background_streaming_task, + ) + + error_payload = { + "type": "server_error", + "message": "The model encountered an error", + "code": "model_error", + } + events = [ + {"type": "response.in_progress"}, + { + "type": "response.failed", + "response": { + "id": "resp_123", + "status": "failed", + "error": error_payload, + "model": "gpt-4o", + "output": [], + }, + }, + ] + mock_response = _make_sse_stream(events) + handler = AsyncMock(spec=ResponsePollingHandler) + kwargs = _make_background_streaming_kwargs("poll_1", handler) + + with patch( + "litellm.proxy.response_polling.background_streaming.ProxyBaseLLMRequestProcessing" + ) as MockProcessor: + MockProcessor.return_value.base_process_llm_request = AsyncMock( + return_value=mock_response + ) + await background_streaming_task(**kwargs) + + # Find the final update_state call (last one) + final_call = handler.update_state.call_args_list[-1] + assert final_call.kwargs["status"] == "failed" + assert final_call.kwargs["error"] == error_payload + + @pytest.mark.asyncio + async def test_response_incomplete_sets_incomplete_status_and_details(self): + """Test that a response.incomplete stream event results in incomplete status""" + from litellm.proxy.response_polling.background_streaming import ( + background_streaming_task, + ) + + events = [ + {"type": "response.in_progress"}, + { + "type": "response.incomplete", + "response": { + "id": "resp_123", + "status": "incomplete", + "incomplete_details": {"reason": "max_output_tokens"}, + "usage": {"input_tokens": 10, "output_tokens": 4096}, + "model": "gpt-4o", + "output": [{"id": "item_1", "type": "message"}], + }, + }, + ] + mock_response = _make_sse_stream(events) + handler = AsyncMock(spec=ResponsePollingHandler) + kwargs = _make_background_streaming_kwargs("poll_2", handler) + + with patch( + "litellm.proxy.response_polling.background_streaming.ProxyBaseLLMRequestProcessing" + ) as MockProcessor: + MockProcessor.return_value.base_process_llm_request = AsyncMock( + return_value=mock_response + ) + await background_streaming_task(**kwargs) + + final_call = handler.update_state.call_args_list[-1] + assert final_call.kwargs["status"] == "incomplete" + assert final_call.kwargs["incomplete_details"] == {"reason": "max_output_tokens"} + assert final_call.kwargs["usage"] == {"input_tokens": 10, "output_tokens": 4096} + + @pytest.mark.asyncio + async def test_response_cancelled_sets_cancelled_status(self): + """Test that a response.cancelled stream event results in cancelled status""" + from litellm.proxy.response_polling.background_streaming import ( + background_streaming_task, + ) + + events = [ + {"type": "response.in_progress"}, + { + "type": "response.cancelled", + "response": { + "id": "resp_123", + "status": "cancelled", + "model": "gpt-4o", + "output": [], + }, + }, + ] + mock_response = _make_sse_stream(events) + handler = AsyncMock(spec=ResponsePollingHandler) + kwargs = _make_background_streaming_kwargs("poll_3", handler) + + with patch( + "litellm.proxy.response_polling.background_streaming.ProxyBaseLLMRequestProcessing" + ) as MockProcessor: + MockProcessor.return_value.base_process_llm_request = AsyncMock( + return_value=mock_response + ) + await background_streaming_task(**kwargs) + + final_call = handler.update_state.call_args_list[-1] + assert final_call.kwargs["status"] == "cancelled" + + @pytest.mark.asyncio + async def test_response_completed_sets_completed_status(self): + """Test that a response.completed stream event results in completed status""" + from litellm.proxy.response_polling.background_streaming import ( + background_streaming_task, + ) + + events = [ + {"type": "response.in_progress"}, + { + "type": "response.completed", + "response": { + "id": "resp_123", + "status": "completed", + "usage": {"input_tokens": 10, "output_tokens": 50}, + "model": "gpt-4o", + "output": [{"id": "item_1", "type": "message"}], + }, + }, + ] + mock_response = _make_sse_stream(events) + handler = AsyncMock(spec=ResponsePollingHandler) + kwargs = _make_background_streaming_kwargs("poll_4", handler) + + with patch( + "litellm.proxy.response_polling.background_streaming.ProxyBaseLLMRequestProcessing" + ) as MockProcessor: + MockProcessor.return_value.base_process_llm_request = AsyncMock( + return_value=mock_response + ) + await background_streaming_task(**kwargs) + + final_call = handler.update_state.call_args_list[-1] + assert final_call.kwargs["status"] == "completed" + assert final_call.kwargs["usage"] == {"input_tokens": 10, "output_tokens": 50} + + @pytest.mark.asyncio + async def test_fallback_status_derived_from_event_type_when_status_field_missing(self): + """Test that when the response body lacks a status field, the fallback + is derived from the event type, not hardcoded to 'completed'.""" + from litellm.proxy.response_polling.background_streaming import ( + background_streaming_task, + ) + + # response.incomplete event with NO status field in the response body + events = [ + {"type": "response.in_progress"}, + { + "type": "response.incomplete", + "response": { + "id": "resp_123", + # "status" deliberately omitted + "incomplete_details": {"reason": "max_output_tokens"}, + "model": "gpt-4o", + "output": [], + }, + }, + ] + mock_response = _make_sse_stream(events) + handler = AsyncMock(spec=ResponsePollingHandler) + kwargs = _make_background_streaming_kwargs("poll_5", handler) + + with patch( + "litellm.proxy.response_polling.background_streaming.ProxyBaseLLMRequestProcessing" + ) as MockProcessor: + MockProcessor.return_value.base_process_llm_request = AsyncMock( + return_value=mock_response + ) + await background_streaming_task(**kwargs) + + final_call = handler.update_state.call_args_list[-1] + assert final_call.kwargs["status"] == "incomplete" + + @pytest.mark.asyncio + async def test_no_terminal_event_defaults_to_completed(self): + """Test that when no terminal event is received, status defaults to completed""" + from litellm.proxy.response_polling.background_streaming import ( + background_streaming_task, + ) + + # Stream with only in_progress, no terminal event + events = [ + {"type": "response.in_progress"}, + ] + mock_response = _make_sse_stream(events) + handler = AsyncMock(spec=ResponsePollingHandler) + kwargs = _make_background_streaming_kwargs("poll_6", handler) + + with patch( + "litellm.proxy.response_polling.background_streaming.ProxyBaseLLMRequestProcessing" + ) as MockProcessor: + MockProcessor.return_value.base_process_llm_request = AsyncMock( + return_value=mock_response + ) + await background_streaming_task(**kwargs) + + final_call = handler.update_state.call_args_list[-1] + assert final_call.kwargs["status"] == "completed" + + class TestEdgeCases: """Test edge cases and error scenarios""" From 25ee2fb3f9d8b90f7927b3e8816424f1f3669fbc Mon Sep 17 00:00:00 2001 From: Joe Reyna Date: Fri, 13 Mar 2026 23:08:14 -0700 Subject: [PATCH 058/289] fix(security): bump tar to 7.5.11 and tornado to 6.5.5 (#23602) * fix(security): bump tar to 7.5.11 and tornado to 6.5.5 - tar >=7.5.11: fixes CVE-2026-31802 (HIGH) in node-pkg - tornado >=6.5.5: fixes CVE-2026-31958 (HIGH) and GHSA-78cv-mqj4-43f7 (MEDIUM) in python-pkg Addresses vulnerabilities found in ghcr.io/berriai/litellm:main-v1.82.0-stable Trivy scan. Co-Authored-By: Claude Sonnet 4.6 * fix: document tar override is enforced via Dockerfile, not npm * fix: revert invalid JSON comment in package.json tar override --------- Co-authored-by: Claude Sonnet 4.6 --- requirements.txt | 2 +- ui/litellm-dashboard/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index f7b72b6f0c..bf2bf2c47a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ # LITELLM PROXY DEPENDENCIES # # Security: explicit pins for transitive deps (CVE fixes) urllib3>=2.6.0 # CVE-2025-66471, CVE-2025-66418, CVE-2026-21441 -tornado>=6.5.3 # CVE-2025-67725, CVE-2025-67726, CVE-2025-67724 +tornado>=6.5.5 # CVE-2025-67725, CVE-2025-67726, CVE-2025-67724, CVE-2026-31958, GHSA-78cv-mqj4-43f7 filelock>=3.20.1 # CVE-2025-68146 h11>=0.16.0 # CVE-2025-43859, GHSA-vqfr-h8mv-ghfj — HTTP request smuggling wheel>=0.46.2 # CVE-2026-24049 — path traversal diff --git a/ui/litellm-dashboard/package.json b/ui/litellm-dashboard/package.json index 5cbe1ead88..2a9bb3e5e2 100644 --- a/ui/litellm-dashboard/package.json +++ b/ui/litellm-dashboard/package.json @@ -88,7 +88,7 @@ "mermaid": ">=11.10.0", "js-yaml": ">=4.1.1", "glob": ">=11.1.0", - "tar": ">=7.5.10", + "tar": ">=7.5.11", "minimatch": ">=10.2.4", "@isaacs/brace-expansion": ">=5.0.1", "node-forge": ">=1.3.2", From f0d283cf9f4b59ad732c6b8cfcba252e1c8c9c59 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 14 Mar 2026 00:01:25 -0700 Subject: [PATCH 059/289] [Feature] UI - Default Team Settings: Modernize page and fix defaults application Rewrite Default Team Settings UI from Tremor to antd with hardcoded fields, fix default team params not applying during team creation or persisting across proxy restarts, remove dead code, and add comprehensive tests. Co-Authored-By: Claude Opus 4.6 --- litellm/constants.py | 1 + .../management_endpoints/team_endpoints.py | 37 +- .../team_member_permission_checks.py | 20 +- .../proxy_setting_endpoints.py | 41 +- .../proxy/management_endpoints/ui_sso.py | 6 +- .../scim/test_scim_v2_endpoints.py | 1 - .../test_team_default_params.py | 487 ++++++++++++++ .../test_team_member_permission_checks.py | 190 ++++++ .../test_proxy_setting_endpoints.py | 50 ++ .../src/components/TeamSSOSettings.test.tsx | 607 ++++++------------ .../src/components/TeamSSOSettings.tsx | 443 +++++++------ .../src/components/networking.tsx | 1 - ui/litellm-dashboard/tsconfig.json | 2 +- 13 files changed, 1266 insertions(+), 620 deletions(-) create mode 100644 tests/test_litellm/proxy/management_endpoints/test_team_default_params.py create mode 100644 tests/test_litellm/proxy/management_helpers/test_team_member_permission_checks.py diff --git a/litellm/constants.py b/litellm/constants.py index dbc79b69a6..0cf9700cdd 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -1417,6 +1417,7 @@ SECRET_MANAGER_REFRESH_INTERVAL = int( ) LITELLM_SETTINGS_SAFE_DB_OVERRIDES = [ "default_internal_user_params", + "default_team_params", "public_mcp_servers", "public_agent_groups", "public_model_groups", diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py index 9c8e6f7282..d83ceb1b09 100644 --- a/litellm/proxy/management_endpoints/team_endpoints.py +++ b/litellm/proxy/management_endpoints/team_endpoints.py @@ -252,6 +252,28 @@ class TeamMemberBudgetHandler: data_dict.pop("team_member_tpm_limit", None) +def _get_default_team_param(field: str) -> Any: + """ + Returns a default value for the given field from litellm.default_team_params config. + Returns None if no default is configured. + + For list fields containing enums (e.g. team_member_permissions), converts enum values to strings. + """ + default_params = litellm.default_team_params + if default_params is None: + return None + if isinstance(default_params, dict): + value = default_params.get(field) + else: + value = getattr(default_params, field, None) + if value is None: + return None + # Convert enum values in lists to strings + if isinstance(value, list): + return [v.value if hasattr(v, "value") else v for v in value] + return value + + def _is_available_team(team_id: str, user_api_key_dict: UserAPIKeyAuth) -> bool: if litellm.default_internal_user_params is None: return False @@ -833,16 +855,23 @@ async def new_team( # noqa: PLR0915 prisma_client=prisma_client, ) - # If max_budget is not explicitly provided in the request, - # check for a default value in the proxy configuration. + # Apply defaults from litellm.default_team_params for any fields + # not explicitly provided in the request. + for field in ("max_budget", "budget_duration", "tpm_limit", "rpm_limit", "team_member_permissions"): + if getattr(data, field, None) is None: + default_value = _get_default_team_param(field) + if default_value is not None: + setattr(data, field, default_value) + + # Legacy fallback: apply max_budget from default_team_settings (YAML config) + # if still not set after checking default_team_params. if data.max_budget is None: if ( isinstance(litellm.default_team_settings, list) and len(litellm.default_team_settings) > 0 and isinstance(litellm.default_team_settings[0], dict) ): - default_settings = litellm.default_team_settings[0] - default_budget = default_settings.get("max_budget") + default_budget = litellm.default_team_settings[0].get("max_budget") if default_budget is not None: data.max_budget = default_budget diff --git a/litellm/proxy/management_helpers/team_member_permission_checks.py b/litellm/proxy/management_helpers/team_member_permission_checks.py index 4642028b77..7dd99d4ff1 100644 --- a/litellm/proxy/management_helpers/team_member_permission_checks.py +++ b/litellm/proxy/management_helpers/team_member_permission_checks.py @@ -16,11 +16,13 @@ from litellm.proxy.auth.auth_checks import get_team_object from litellm.proxy.auth.route_checks import RouteChecks from litellm.proxy.utils import PrismaClient -DEFAULT_TEAM_MEMBER_PERMISSIONS = [ +BASELINE_TEAM_MEMBER_PERMISSIONS = [ KeyManagementRoutes.KEY_INFO, KeyManagementRoutes.KEY_HEALTH, ] +DEFAULT_TEAM_MEMBER_PERMISSIONS = BASELINE_TEAM_MEMBER_PERMISSIONS + class TeamMemberPermissionChecks: @staticmethod @@ -29,15 +31,23 @@ class TeamMemberPermissionChecks: team_table: LiteLLM_TeamTableCachedObj, ) -> List[KeyManagementRoutes]: """ - Returns the permissions for a team member + Returns the permissions for a team member. + + - If team has explicit permissions set (including []), use those + plus baseline permissions (/key/info, /key/health). + - If team has no permissions set (None), fall back to + DEFAULT_TEAM_MEMBER_PERMISSIONS. """ - if team_table.team_member_permissions and isinstance( + if team_table.team_member_permissions is not None and isinstance( team_table.team_member_permissions, list ): - return [ + permissions = { KeyManagementRoutes(permission) for permission in team_table.team_member_permissions - ] + } + # Always include baseline permissions + permissions.update(BASELINE_TEAM_MEMBER_PERMISSIONS) + return list(permissions) return DEFAULT_TEAM_MEMBER_PERMISSIONS diff --git a/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py b/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py index 8df215d998..0fa27905ba 100644 --- a/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py +++ b/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py @@ -328,11 +328,34 @@ async def _get_settings_with_schema( } # Add property descriptions + defs = schema.get("$defs", schema.get("definitions", {})) for field_name, field_info in schema["properties"].items(): - result["field_schema"]["properties"][field_name] = { + # For Optional fields, Pydantic v2 uses anyOf with [actual_type, null]. + # Resolve the non-null variant to get the real type and items. + resolved = field_info + if "anyOf" in field_info: + for variant in field_info["anyOf"]: + if variant.get("type") != "null": + resolved = variant + break + + prop_entry: dict = { "description": field_info.get("description", ""), - "type": field_info.get("type", "string"), + "type": resolved.get("type", "string"), } + # Pass through items info (including enum values) for array fields + # so the UI can render a multi-select dropdown + if "items" in resolved: + items = resolved["items"] + # Resolve $ref to enum definitions if needed + if "$ref" in items: + ref_name = items["$ref"].split("/")[-1] + ref_def = defs.get(ref_name, {}) + if "enum" in ref_def: + prop_entry["items"] = {"enum": ref_def["enum"]} + else: + prop_entry["items"] = items + result["field_schema"]["properties"][field_name] = prop_entry # Add nested object descriptions for def_name, def_schema in schema.get("definitions", {}).items(): @@ -427,7 +450,6 @@ async def _update_litellm_setting( DefaultInternalUserParams, DefaultTeamSSOParams, MCPSemanticFilterSettings ], settings_key: str, - in_memory_var: Any, success_message: str, ): """ @@ -436,7 +458,6 @@ async def _update_litellm_setting( Args: settings: The settings object to update settings_key: The key in litellm_settings to update - in_memory_var: The in-memory variable to update success_message: Message to return on success """ from litellm.proxy.proxy_server import proxy_config, store_model_in_db @@ -449,13 +470,16 @@ async def _update_litellm_setting( }, ) - # Update the in-memory settings in_memory_var = settings.model_dump(exclude_none=True) - setattr(litellm, settings_key, in_memory_var) - # Load existing config + # Load existing config first, then set in-memory value after, + # because get_config() may overwrite litellm. with stale DB values + # via LITELLM_SETTINGS_SAFE_DB_OVERRIDES. config = await proxy_config.get_config() + # Update the in-memory settings (after get_config to avoid stale override) + setattr(litellm, settings_key, in_memory_var) + # Update config with new settings if "litellm_settings" not in config: config["litellm_settings"] = {} @@ -495,7 +519,6 @@ async def update_internal_user_settings( return await _update_litellm_setting( settings=settings, settings_key="default_internal_user_params", - in_memory_var=litellm.default_internal_user_params, success_message="Internal user settings updated successfully", ) @@ -513,7 +536,6 @@ async def update_default_team_settings(settings: DefaultTeamSSOParams): return await _update_litellm_setting( settings=settings, settings_key="default_team_params", - in_memory_var=litellm.default_team_params, success_message="Default team settings updated successfully", ) @@ -935,7 +957,6 @@ async def update_mcp_semantic_filter_settings( result = await _update_litellm_setting( settings=settings, settings_key="mcp_semantic_tool_filter", - in_memory_var=None, success_message="MCP Semantic Filter settings updated successfully. Changes will be applied across all pods within 10 seconds.", ) try: diff --git a/litellm/types/proxy/management_endpoints/ui_sso.py b/litellm/types/proxy/management_endpoints/ui_sso.py index 6743c4a5b9..7d8ff0f65c 100644 --- a/litellm/types/proxy/management_endpoints/ui_sso.py +++ b/litellm/types/proxy/management_endpoints/ui_sso.py @@ -3,7 +3,7 @@ from typing import Dict, List, Literal, Optional, Union from pydantic import BaseModel, Field from typing_extensions import TypedDict -from litellm.proxy._types import LitellmUserRoles +from litellm.proxy._types import KeyManagementRoutes, LitellmUserRoles from litellm.types.utils import LiteLLMPydanticObjectBase @@ -205,6 +205,10 @@ class DefaultTeamSSOParams(LiteLLMPydanticObjectBase): default=None, description="Default rpm limit for new automatically created teams", ) + team_member_permissions: Optional[List[KeyManagementRoutes]] = Field( + default=None, + description="Default permissions granted to members of newly created teams (e.g. /key/generate, /key/update, /key/delete). /key/info and /key/health are always included.", + ) class InProductNudgeResponse(BaseModel): diff --git a/tests/test_litellm/proxy/management_endpoints/scim/test_scim_v2_endpoints.py b/tests/test_litellm/proxy/management_endpoints/scim/test_scim_v2_endpoints.py index 1355ca0abb..3c4444a5ef 100644 --- a/tests/test_litellm/proxy/management_endpoints/scim/test_scim_v2_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/scim/test_scim_v2_endpoints.py @@ -202,7 +202,6 @@ async def test_scim_create_user_respects_default_role_set_via_ui(mocker, monkeyp await _update_litellm_setting( settings=settings, settings_key="default_internal_user_params", - in_memory_var=litellm.default_internal_user_params, success_message="ok", ) diff --git a/tests/test_litellm/proxy/management_endpoints/test_team_default_params.py b/tests/test_litellm/proxy/management_endpoints/test_team_default_params.py new file mode 100644 index 0000000000..7fc7cb8aae --- /dev/null +++ b/tests/test_litellm/proxy/management_endpoints/test_team_default_params.py @@ -0,0 +1,487 @@ +""" +Tests for applying default team params during team creation +and loading default_team_params from DB on startup. +""" + +import os +import sys +from unittest.mock import AsyncMock, MagicMock, patch + +import pytest + +sys.path.insert( + 0, os.path.abspath("../../../") +) # Adds the parent directory to the system path + +import litellm +from litellm.proxy._types import ( + NewTeamRequest, + UserAPIKeyAuth, + LitellmUserRoles, +) +from litellm.proxy.management_endpoints.team_endpoints import ( + _get_default_team_param, +) +from litellm.proxy.proxy_server import ProxyConfig + + +# --------------------------------------------------------------------------- +# _update_config_fields: default_team_params loaded from DB on startup +# --------------------------------------------------------------------------- + + +class TestConfigFieldsDefaultTeamParams: + """Tests that _update_config_fields applies default_team_params from DB.""" + + def _make_proxy_config(self) -> ProxyConfig: + return ProxyConfig() + + def test_default_team_params_applied_from_db(self, monkeypatch): + """default_team_params in DB is set on litellm module during config load.""" + monkeypatch.setattr(litellm, "default_team_params", None) + + pc = self._make_proxy_config() + db_settings = { + "default_team_params": { + "max_budget": 500.0, + "budget_duration": "30d", + "tpm_limit": 1000, + "rpm_limit": 200, + "team_member_permissions": ["/key/generate", "/key/delete"], + } + } + + pc._update_config_fields( + current_config={}, + param_name="litellm_settings", + db_param_value=db_settings, + ) + + assert litellm.default_team_params == db_settings["default_team_params"] + + def test_default_team_params_merged_into_config_dict(self): + """DB default_team_params ends up in the returned config dict.""" + pc = self._make_proxy_config() + config = {"litellm_settings": {"cache": False}} + db_settings = { + "default_team_params": { + "max_budget": 100.0, + } + } + + result = pc._update_config_fields( + current_config=config, + param_name="litellm_settings", + db_param_value=db_settings, + ) + + assert result["litellm_settings"]["default_team_params"] == {"max_budget": 100.0} + # Existing keys preserved + assert result["litellm_settings"]["cache"] is False + + def test_default_team_params_not_applied_when_absent(self, monkeypatch): + """When DB litellm_settings has no default_team_params, it stays None.""" + monkeypatch.setattr(litellm, "default_team_params", None) + + pc = self._make_proxy_config() + pc._update_config_fields( + current_config={}, + param_name="litellm_settings", + db_param_value={"cache": True}, + ) + + assert litellm.default_team_params is None + + def test_default_team_params_overrides_yaml_value(self, monkeypatch): + """DB value for default_team_params overrides YAML value via deep merge.""" + monkeypatch.setattr(litellm, "default_team_params", None) + + pc = self._make_proxy_config() + config = { + "litellm_settings": { + "default_team_params": { + "max_budget": 50.0, + "tpm_limit": 100, + } + } + } + db_settings = { + "default_team_params": { + "max_budget": 200.0, + "rpm_limit": 500, + } + } + + result = pc._update_config_fields( + current_config=config, + param_name="litellm_settings", + db_param_value=db_settings, + ) + + merged = result["litellm_settings"]["default_team_params"] + # DB value wins for max_budget + assert merged["max_budget"] == 200.0 + # DB adds rpm_limit + assert merged["rpm_limit"] == 500 + # YAML tpm_limit preserved (not in DB) + assert merged["tpm_limit"] == 100 + + # setattr should have applied the DB value + assert litellm.default_team_params == db_settings["default_team_params"] + + +# --------------------------------------------------------------------------- +# new_team: default params applied to team creation +# +# We test the defaults-application logic by calling new_team with +# prisma_client patched at the proxy_server module level (where the +# endpoint imports it from). +# --------------------------------------------------------------------------- + + +class TestNewTeamDefaultParamsApplied: + """Tests that /team/new applies defaults from litellm.default_team_params.""" + + @pytest.fixture(autouse=True) + def setup_mocks(self, monkeypatch): + """Set up common mocks for team creation tests.""" + mock_prisma = AsyncMock() + mock_prisma.insert_data = AsyncMock( + return_value=MagicMock( + team_id="test-team-id", + team_alias="test-team", + ) + ) + mock_prisma.get_generic_data = AsyncMock(return_value=None) + mock_prisma.db = MagicMock() + mock_prisma.db.litellm_teamtable = MagicMock() + mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=None) + mock_prisma.db.litellm_teamtable.count = AsyncMock(return_value=0) + + monkeypatch.setattr( + "litellm.proxy.proxy_server.prisma_client", mock_prisma + ) + + # Reset default_team_settings to avoid legacy fallback interference + monkeypatch.setattr(litellm, "default_team_settings", None) + + def _make_admin_auth(self) -> UserAPIKeyAuth: + return UserAPIKeyAuth( + user_id="admin-user", + user_role=LitellmUserRoles.PROXY_ADMIN, + ) + + @pytest.mark.asyncio + async def test_all_defaults_applied_when_not_provided(self, monkeypatch): + """When no budget/rate/permission fields are in the request, all defaults apply.""" + from litellm.proxy.management_endpoints.team_endpoints import new_team + + monkeypatch.setattr( + litellm, + "default_team_params", + { + "max_budget": 100.0, + "budget_duration": "30d", + "tpm_limit": 200, + "rpm_limit": 500, + "team_member_permissions": ["/key/generate", "/key/update"], + }, + ) + + data = NewTeamRequest(team_alias="my-team") + auth = self._make_admin_auth() + + try: + await new_team( + data=data, + user_api_key_dict=auth, + http_request=MagicMock(), + ) + except Exception: + pass # May fail on downstream mocks, that's OK + + # Verify defaults were set on the data object + assert data.max_budget == 100.0 + assert data.budget_duration == "30d" + assert data.tpm_limit == 200 + assert data.rpm_limit == 500 + assert data.team_member_permissions == ["/key/generate", "/key/update"] + + @pytest.mark.asyncio + async def test_explicit_values_not_overridden(self, monkeypatch): + """When request provides explicit values, defaults do not override them.""" + from litellm.proxy.management_endpoints.team_endpoints import new_team + + monkeypatch.setattr( + litellm, + "default_team_params", + { + "max_budget": 100.0, + "budget_duration": "30d", + "tpm_limit": 200, + "rpm_limit": 500, + "team_member_permissions": ["/key/generate"], + }, + ) + + data = NewTeamRequest( + team_alias="my-team", + max_budget=50.0, + budget_duration="7d", + tpm_limit=999, + rpm_limit=888, + team_member_permissions=["/key/delete"], + ) + auth = self._make_admin_auth() + + try: + await new_team( + data=data, + user_api_key_dict=auth, + http_request=MagicMock(), + ) + except Exception: + pass + + # Explicit values preserved + assert data.max_budget == 50.0 + assert data.budget_duration == "7d" + assert data.tpm_limit == 999 + assert data.rpm_limit == 888 + assert data.team_member_permissions == ["/key/delete"] + + @pytest.mark.asyncio + async def test_partial_defaults_applied(self, monkeypatch): + """Only missing fields get defaults; provided fields are untouched.""" + from litellm.proxy.management_endpoints.team_endpoints import new_team + + monkeypatch.setattr( + litellm, + "default_team_params", + { + "max_budget": 100.0, + "budget_duration": "30d", + "tpm_limit": 200, + "rpm_limit": 500, + }, + ) + + data = NewTeamRequest( + team_alias="my-team", + max_budget=75.0, # explicit + # budget_duration, tpm_limit, rpm_limit not set → defaults apply + ) + auth = self._make_admin_auth() + + try: + await new_team( + data=data, + user_api_key_dict=auth, + http_request=MagicMock(), + ) + except Exception: + pass + + assert data.max_budget == 75.0 # explicit, not overridden + assert data.budget_duration == "30d" # default applied + assert data.tpm_limit == 200 # default applied + assert data.rpm_limit == 500 # default applied + + @pytest.mark.asyncio + async def test_no_defaults_when_config_is_none(self, monkeypatch): + """When default_team_params is None, no defaults applied.""" + from litellm.proxy.management_endpoints.team_endpoints import new_team + + monkeypatch.setattr(litellm, "default_team_params", None) + + data = NewTeamRequest(team_alias="my-team") + auth = self._make_admin_auth() + + try: + await new_team( + data=data, + user_api_key_dict=auth, + http_request=MagicMock(), + ) + except Exception: + pass + + assert data.max_budget is None + assert data.budget_duration is None + assert data.tpm_limit is None + assert data.rpm_limit is None + assert data.team_member_permissions is None + + @pytest.mark.asyncio + async def test_legacy_default_team_settings_fallback(self, monkeypatch): + """Legacy default_team_settings YAML config applies max_budget as fallback.""" + from litellm.proxy.management_endpoints.team_endpoints import new_team + + monkeypatch.setattr(litellm, "default_team_params", None) + monkeypatch.setattr( + litellm, + "default_team_settings", + [{"team_id": "default", "max_budget": 999.0}], + ) + + data = NewTeamRequest(team_alias="my-team") + auth = self._make_admin_auth() + + try: + await new_team( + data=data, + user_api_key_dict=auth, + http_request=MagicMock(), + ) + except Exception: + pass + + assert data.max_budget == 999.0 + + @pytest.mark.asyncio + async def test_default_team_params_takes_priority_over_legacy(self, monkeypatch): + """default_team_params max_budget takes priority over legacy default_team_settings.""" + from litellm.proxy.management_endpoints.team_endpoints import new_team + + monkeypatch.setattr( + litellm, + "default_team_params", + {"max_budget": 100.0}, + ) + monkeypatch.setattr( + litellm, + "default_team_settings", + [{"team_id": "default", "max_budget": 999.0}], + ) + + data = NewTeamRequest(team_alias="my-team") + auth = self._make_admin_auth() + + try: + await new_team( + data=data, + user_api_key_dict=auth, + http_request=MagicMock(), + ) + except Exception: + pass + + # default_team_params wins (100.0), legacy fallback (999.0) not used + assert data.max_budget == 100.0 + + +# --------------------------------------------------------------------------- +# _update_litellm_setting: setattr ordering +# --------------------------------------------------------------------------- + + +class TestUpdateLitellmSettingOrdering: + """Tests that _update_litellm_setting sets in-memory value AFTER get_config, + so stale DB values from LITELLM_SETTINGS_SAFE_DB_OVERRIDES don't overwrite it.""" + + @pytest.mark.asyncio + async def test_setattr_not_overwritten_by_get_config(self, monkeypatch): + """The new in-memory value survives get_config() which may load stale DB values.""" + from litellm.proxy.ui_crud_endpoints.proxy_setting_endpoints import ( + _update_litellm_setting, + ) + from litellm.types.proxy.management_endpoints.ui_sso import ( + DefaultTeamSSOParams, + ) + + # Simulate stale DB state: get_config returns old default_team_params + stale_value = {"max_budget": 50.0} + monkeypatch.setattr(litellm, "default_team_params", stale_value) + + # get_config will overwrite litellm.default_team_params with stale DB value + async def mock_get_config(): + # Simulate what _update_config_from_db does for safe overrides + litellm.default_team_params = stale_value + return { + "litellm_settings": { + "default_team_params": stale_value, + } + } + + saved_configs = [] + + async def mock_save_config(new_config=None): + saved_configs.append(new_config) + + from litellm.proxy.proxy_server import proxy_config + + monkeypatch.setattr(proxy_config, "get_config", mock_get_config) + monkeypatch.setattr(proxy_config, "save_config", mock_save_config) + monkeypatch.setattr( + "litellm.proxy.proxy_server.store_model_in_db", True + ) + + # New settings to save + new_settings = DefaultTeamSSOParams( + max_budget=200.0, + budget_duration="7d", + rpm_limit=1000, + ) + + result = await _update_litellm_setting( + settings=new_settings, + settings_key="default_team_params", + success_message="Updated", + ) + + # In-memory value should be the NEW value, not the stale one + expected = new_settings.model_dump(exclude_none=True) + assert litellm.default_team_params == expected + + # Saved config should contain the new value + assert len(saved_configs) == 1 + saved_settings = saved_configs[0]["litellm_settings"]["default_team_params"] + assert saved_settings == expected + + # Return value should reflect the new settings + assert result["settings"] == expected + + @pytest.mark.asyncio + async def test_requires_store_model_in_db(self, monkeypatch): + """Raises HTTPException when store_model_in_db is not True.""" + from fastapi import HTTPException + + from litellm.proxy.ui_crud_endpoints.proxy_setting_endpoints import ( + _update_litellm_setting, + ) + from litellm.types.proxy.management_endpoints.ui_sso import ( + DefaultTeamSSOParams, + ) + + monkeypatch.setattr( + "litellm.proxy.proxy_server.store_model_in_db", False + ) + + with pytest.raises(HTTPException) as exc_info: + await _update_litellm_setting( + settings=DefaultTeamSSOParams(max_budget=100.0), + settings_key="default_team_params", + success_message="Updated", + ) + + assert exc_info.value.status_code == 500 + + +# --------------------------------------------------------------------------- +# LITELLM_SETTINGS_SAFE_DB_OVERRIDES contains default_team_params +# --------------------------------------------------------------------------- + + +class TestSafeDbOverrides: + """Verify default_team_params is in the safe overrides list.""" + + def test_default_team_params_in_safe_overrides(self): + from litellm.constants import LITELLM_SETTINGS_SAFE_DB_OVERRIDES + + assert "default_team_params" in LITELLM_SETTINGS_SAFE_DB_OVERRIDES + + def test_default_internal_user_params_in_safe_overrides(self): + """Sanity: default_internal_user_params was already in the list.""" + from litellm.constants import LITELLM_SETTINGS_SAFE_DB_OVERRIDES + + assert "default_internal_user_params" in LITELLM_SETTINGS_SAFE_DB_OVERRIDES diff --git a/tests/test_litellm/proxy/management_helpers/test_team_member_permission_checks.py b/tests/test_litellm/proxy/management_helpers/test_team_member_permission_checks.py new file mode 100644 index 0000000000..6aa08dddd0 --- /dev/null +++ b/tests/test_litellm/proxy/management_helpers/test_team_member_permission_checks.py @@ -0,0 +1,190 @@ +import os +import sys +from unittest.mock import MagicMock + +import pytest + +sys.path.insert( + 0, os.path.abspath("../../..") +) # Adds the parent directory to the system path + +from litellm.proxy._types import KeyManagementRoutes, Member +from litellm.proxy.management_helpers.team_member_permission_checks import ( + BASELINE_TEAM_MEMBER_PERMISSIONS, + TeamMemberPermissionChecks, +) + + +def _make_team_table(team_member_permissions): + """Create a mock team table object with given permissions.""" + team = MagicMock() + team.team_member_permissions = team_member_permissions + return team + + +class TestGetPermissionsForTeamMember: + def test_none_permissions_returns_defaults(self): + """When team_member_permissions is None, return DEFAULT_TEAM_MEMBER_PERMISSIONS.""" + team = _make_team_table(None) + member = MagicMock(spec=Member) + + result = TeamMemberPermissionChecks.get_permissions_for_team_member( + team_member_object=member, team_table=team + ) + + assert set(result) == set(BASELINE_TEAM_MEMBER_PERMISSIONS) + + def test_empty_list_includes_baseline(self): + """When team_member_permissions is [], baseline permissions are still included.""" + team = _make_team_table([]) + member = MagicMock(spec=Member) + + result = TeamMemberPermissionChecks.get_permissions_for_team_member( + team_member_object=member, team_table=team + ) + + assert KeyManagementRoutes.KEY_INFO in result + assert KeyManagementRoutes.KEY_HEALTH in result + + def test_explicit_permissions_include_baseline(self): + """When explicit permissions are set, baseline is always included.""" + team = _make_team_table(["/key/generate", "/key/delete"]) + member = MagicMock(spec=Member) + + result = TeamMemberPermissionChecks.get_permissions_for_team_member( + team_member_object=member, team_table=team + ) + + assert KeyManagementRoutes.KEY_GENERATE in result + assert KeyManagementRoutes.KEY_DELETE in result + assert KeyManagementRoutes.KEY_INFO in result + assert KeyManagementRoutes.KEY_HEALTH in result + + def test_explicit_permissions_with_baseline_no_duplicates(self): + """When explicit permissions already include baseline, no duplicates.""" + team = _make_team_table(["/key/info", "/key/generate"]) + member = MagicMock(spec=Member) + + result = TeamMemberPermissionChecks.get_permissions_for_team_member( + team_member_object=member, team_table=team + ) + + # Using set ensures no duplicates from the implementation + assert KeyManagementRoutes.KEY_INFO in result + assert KeyManagementRoutes.KEY_GENERATE in result + assert KeyManagementRoutes.KEY_HEALTH in result + + +class TestGetDefaultTeamParam: + def test_returns_none_when_no_config(self, monkeypatch): + """Returns None when litellm.default_team_params is None.""" + import litellm + + from litellm.proxy.management_endpoints.team_endpoints import ( + _get_default_team_param, + ) + + monkeypatch.setattr(litellm, "default_team_params", None) + + assert _get_default_team_param("team_member_permissions") is None + assert _get_default_team_param("max_budget") is None + + def test_returns_none_when_field_not_set(self, monkeypatch): + """Returns None when default_team_params exists but the field is not set.""" + import litellm + + from litellm.proxy.management_endpoints.team_endpoints import ( + _get_default_team_param, + ) + + monkeypatch.setattr(litellm, "default_team_params", {"models": ["gpt-4"]}) + + assert _get_default_team_param("team_member_permissions") is None + assert _get_default_team_param("max_budget") is None + + def test_returns_permissions_from_dict_config(self, monkeypatch): + """Returns permissions when default_team_params is a dict.""" + import litellm + + from litellm.proxy.management_endpoints.team_endpoints import ( + _get_default_team_param, + ) + + monkeypatch.setattr( + litellm, + "default_team_params", + {"team_member_permissions": ["/key/generate", "/key/update"]}, + ) + + result = _get_default_team_param("team_member_permissions") + assert result == ["/key/generate", "/key/update"] + + def test_returns_scalar_fields_from_dict_config(self, monkeypatch): + """Returns scalar fields (max_budget, tpm_limit, etc.) from dict config.""" + import litellm + + from litellm.proxy.management_endpoints.team_endpoints import ( + _get_default_team_param, + ) + + monkeypatch.setattr( + litellm, + "default_team_params", + { + "max_budget": 100.0, + "budget_duration": "30d", + "tpm_limit": 200, + "rpm_limit": 500, + }, + ) + + assert _get_default_team_param("max_budget") == 100.0 + assert _get_default_team_param("budget_duration") == "30d" + assert _get_default_team_param("tpm_limit") == 200 + assert _get_default_team_param("rpm_limit") == 500 + + def test_returns_permissions_from_pydantic_config(self, monkeypatch): + """Returns permissions when default_team_params is a DefaultTeamSSOParams object.""" + import litellm + + from litellm.proxy.management_endpoints.team_endpoints import ( + _get_default_team_param, + ) + from litellm.types.proxy.management_endpoints.ui_sso import ( + DefaultTeamSSOParams, + ) + + params = DefaultTeamSSOParams( + team_member_permissions=[ + KeyManagementRoutes.KEY_GENERATE, + KeyManagementRoutes.KEY_DELETE, + ] + ) + monkeypatch.setattr(litellm, "default_team_params", params) + + result = _get_default_team_param("team_member_permissions") + assert result == ["/key/generate", "/key/delete"] + + def test_returns_scalar_fields_from_pydantic_config(self, monkeypatch): + """Returns scalar fields from DefaultTeamSSOParams object.""" + import litellm + + from litellm.proxy.management_endpoints.team_endpoints import ( + _get_default_team_param, + ) + from litellm.types.proxy.management_endpoints.ui_sso import ( + DefaultTeamSSOParams, + ) + + params = DefaultTeamSSOParams( + max_budget=250.0, + budget_duration="7d", + tpm_limit=1000, + rpm_limit=100, + ) + monkeypatch.setattr(litellm, "default_team_params", params) + + assert _get_default_team_param("max_budget") == 250.0 + assert _get_default_team_param("budget_duration") == "7d" + assert _get_default_team_param("tpm_limit") == 1000 + assert _get_default_team_param("rpm_limit") == 100 diff --git a/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py b/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py index f955a6134b..7378b14cdf 100644 --- a/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py +++ b/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py @@ -231,6 +231,56 @@ class TestProxySettingEndpoints: # Verify save_config was called exactly once assert mock_proxy_config["save_call_count"]() == 1 + def test_get_default_team_settings_includes_team_member_permissions_schema( + self, mock_proxy_config, mock_auth + ): + """Test that team_member_permissions field appears in schema with enum items""" + response = client.get("/get/default_team_settings") + + assert response.status_code == 200 + data = response.json() + + # Check that team_member_permissions is in the schema + props = data["field_schema"]["properties"] + assert "team_member_permissions" in props + + perm_schema = props["team_member_permissions"] + assert perm_schema["type"] == "array" + assert "items" in perm_schema + assert "enum" in perm_schema["items"] + # Verify some known enum values are present + enum_values = perm_schema["items"]["enum"] + assert "/key/generate" in enum_values + assert "/key/info" in enum_values + assert "/key/delete" in enum_values + + def test_update_default_team_settings_with_permissions( + self, mock_proxy_config, mock_auth, monkeypatch + ): + """Test updating default team settings with team_member_permissions""" + import litellm + + monkeypatch.setattr("litellm.proxy.proxy_server.store_model_in_db", True) + monkeypatch.setattr(litellm, "default_team_params", {}) + + new_settings = { + "models": ["gpt-4"], + "team_member_permissions": ["/key/generate", "/key/update", "/key/delete"], + } + + response = client.patch("/update/default_team_settings", json=new_settings) + + assert response.status_code == 200 + data = response.json() + assert data["status"] == "success" + + settings = data["settings"] + assert settings["team_member_permissions"] == [ + "/key/generate", + "/key/update", + "/key/delete", + ] + def test_get_sso_settings(self, mock_proxy_config, mock_auth, monkeypatch): """Test getting the SSO settings from the dedicated database table""" from unittest.mock import AsyncMock, MagicMock diff --git a/ui/litellm-dashboard/src/components/TeamSSOSettings.test.tsx b/ui/litellm-dashboard/src/components/TeamSSOSettings.test.tsx index ae93b11879..5006afb61e 100644 --- a/ui/litellm-dashboard/src/components/TeamSSOSettings.test.tsx +++ b/ui/litellm-dashboard/src/components/TeamSSOSettings.test.tsx @@ -18,14 +18,18 @@ vi.mock("./common_components/budget_duration_dropdown", () => { aria-label="Budget duration" > - - + + + ); BudgetDurationDropdown.displayName = "BudgetDurationDropdown"; return { default: BudgetDurationDropdown, - getBudgetDurationLabel: vi.fn((value: string) => `Budget: ${value}`), + getBudgetDurationLabel: vi.fn((value: string) => { + const map: Record = { "24h": "daily", "7d": "weekly", "30d": "monthly" }; + return map[value] || value; + }), }; }); @@ -56,6 +60,7 @@ vi.mock("./ModelSelect/ModelSelect", () => { vi.mock("antd", async (importOriginal) => { const actual = await importOriginal(); const React = await import("react"); + const SelectComponent = ({ value, onChange, @@ -88,37 +93,53 @@ vi.mock("antd", async (importOriginal) => { ); }; SelectComponent.displayName = "Select"; + const SelectOption = ({ value: optionValue, children: optionChildren }: { value: string; children: React.ReactNode }) => React.createElement("option", { value: optionValue }, optionChildren); SelectOption.displayName = "SelectOption"; SelectComponent.Option = SelectOption; - const Spin = ({ size }: { size?: string }) => React.createElement("div", { "data-testid": "spinner", "data-size": size }); + + const Spin = ({ size }: { size?: string }) => + React.createElement("div", { "data-testid": "spinner", "data-size": size }); Spin.displayName = "Spin"; - const Switch = ({ checked, onChange }: { checked: boolean; onChange: (checked: boolean) => void }) => + + const InputNumber = ({ + value, + onChange, + placeholder, + prefix, + }: { + value: number | null; + onChange: (value: number | null) => void; + placeholder?: string; + prefix?: string; + min?: number; + className?: string; + style?: React.CSSProperties; + }) => React.createElement("input", { - type: "checkbox", - role: "switch", - checked: checked, - onChange: (e) => onChange(e.target.checked), - "aria-label": "Toggle switch", + type: "number", + value: value ?? "", + onChange: (e: React.ChangeEvent) => { + const v = e.target.value === "" ? null : Number(e.target.value); + onChange(v); + }, + placeholder, + "data-prefix": prefix, + "aria-label": "number input", }); - Switch.displayName = "Switch"; - const Paragraph = ({ children }: { children: React.ReactNode }) => React.createElement("p", {}, children); - Paragraph.displayName = "Paragraph"; + InputNumber.displayName = "InputNumber"; + return { ...actual, Spin, - Switch, Select: SelectComponent, - Typography: { - Paragraph, - }, + InputNumber, }; }); const mockGetDefaultTeamSettings = vi.mocked(networking.getDefaultTeamSettings); const mockUpdateDefaultTeamSettings = vi.mocked(networking.updateDefaultTeamSettings); -const mockModelAvailableCall = vi.mocked(networking.modelAvailableCall); const mockNotificationsManager = vi.mocked(NotificationsManager); describe("TeamSSOSettings", () => { @@ -128,77 +149,33 @@ describe("TeamSSOSettings", () => { userRole: "admin", }; - const mockSettings = { + const mockSettingsResponse = { values: { - budget_duration: "monthly", max_budget: 1000, - enabled: true, - allowed_models: ["gpt-4", "claude-3"], + budget_duration: "30d", + tpm_limit: 500, + rpm_limit: 100, models: ["gpt-4"], - status: "active", - }, - field_schema: { - description: "Default team settings schema", - properties: { - budget_duration: { - type: "string", - description: "Budget duration setting", - }, - max_budget: { - type: "number", - description: "Maximum budget amount", - }, - enabled: { - type: "boolean", - description: "Enable feature", - }, - allowed_models: { - type: "array", - items: { - enum: ["gpt-4", "claude-3", "gpt-3.5-turbo"], - }, - description: "Allowed models", - }, - models: { - type: "array", - description: "Selected models", - }, - status: { - type: "string", - enum: ["active", "inactive", "pending"], - description: "Status", - }, - }, + team_member_permissions: ["/key/generate", "/key/update"], }, }; beforeEach(() => { vi.clearAllMocks(); - mockModelAvailableCall.mockResolvedValue({ - data: [{ id: "gpt-4" }, { id: "claude-3" }], - }); }); - it("should render", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); - - renderWithProviders(); - - await waitFor(() => { - expect(screen.getByText("Default Team Settings")).toBeInTheDocument(); - }); - }); + // --- Loading & Error States --- it("should show loading spinner while fetching settings", () => { - mockGetDefaultTeamSettings.mockImplementation(() => new Promise(() => { })); + mockGetDefaultTeamSettings.mockImplementation(() => new Promise(() => {})); renderWithProviders(); expect(screen.getByTestId("spinner")).toBeInTheDocument(); }); - it("should display message when no settings are available", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(null as any); + it("should display error message when fetch fails", async () => { + mockGetDefaultTeamSettings.mockRejectedValue(new Error("Fetch failed")); renderWithProviders(); @@ -207,6 +184,7 @@ describe("TeamSSOSettings", () => { screen.getByText("No team settings available or you do not have permission to view them."), ).toBeInTheDocument(); }); + expect(mockNotificationsManager.fromBackend).toHaveBeenCalledWith("Failed to fetch team settings"); }); it("should not fetch settings when access token is null", async () => { @@ -217,432 +195,273 @@ describe("TeamSSOSettings", () => { }); }); - it("should display settings fields with correct values", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); + // --- View Mode --- + + it("should render title and subtitle", async () => { + mockGetDefaultTeamSettings.mockResolvedValue(mockSettingsResponse); + + renderWithProviders(); + + await waitFor(() => { + expect(screen.getByText("Default Team Settings")).toBeInTheDocument(); + expect(screen.getByText("These settings will be applied by default when creating new teams.")).toBeInTheDocument(); + }); + }); + + it("should render section headers", async () => { + mockGetDefaultTeamSettings.mockResolvedValue(mockSettingsResponse); + + renderWithProviders(); + + await waitFor(() => { + expect(screen.getByText("Budget & Rate Limits")).toBeInTheDocument(); + expect(screen.getByText("Access & Permissions")).toBeInTheDocument(); + }); + }); + + it("should display all field labels and descriptions", async () => { + mockGetDefaultTeamSettings.mockResolvedValue(mockSettingsResponse); renderWithProviders(); await waitFor(() => { - expect(screen.getByText("Budget Duration")).toBeInTheDocument(); expect(screen.getByText("Max Budget")).toBeInTheDocument(); + expect(screen.getByText("Budget Duration")).toBeInTheDocument(); + expect(screen.getByText("TPM Limit")).toBeInTheDocument(); + expect(screen.getByText("RPM Limit")).toBeInTheDocument(); + expect(screen.getByText("Models")).toBeInTheDocument(); + expect(screen.getByText("Team Member Permissions")).toBeInTheDocument(); }); - expect(screen.getByText("Budget: monthly")).toBeInTheDocument(); - expect(screen.getByText("1000")).toBeInTheDocument(); - const enabledTexts = screen.getAllByText("Enabled"); - expect(enabledTexts.length).toBeGreaterThan(0); + // Descriptions + expect(screen.getByText("Maximum budget (in USD) for new automatically created teams.")).toBeInTheDocument(); + expect(screen.getByText("How frequently the team's budget resets.")).toBeInTheDocument(); + }); + + it("should display formatted values in view mode", async () => { + mockGetDefaultTeamSettings.mockResolvedValue(mockSettingsResponse); + + renderWithProviders(); + + await waitFor(() => { + // max_budget displayed with $ + expect(screen.getByText("$1,000")).toBeInTheDocument(); + // budget_duration through getBudgetDurationLabel + expect(screen.getByText("monthly")).toBeInTheDocument(); + // tpm_limit formatted + expect(screen.getByText("500")).toBeInTheDocument(); + // rpm_limit formatted + expect(screen.getByText("100")).toBeInTheDocument(); + }); + }); + + it("should display models as tags in view mode", async () => { + mockGetDefaultTeamSettings.mockResolvedValue(mockSettingsResponse); + + renderWithProviders(); + + await waitFor(() => { + expect(screen.getByText("gpt-4")).toBeInTheDocument(); + }); + }); + + it("should display permissions as tags in view mode", async () => { + mockGetDefaultTeamSettings.mockResolvedValue(mockSettingsResponse); + + renderWithProviders(); + + await waitFor(() => { + expect(screen.getByText("/key/generate")).toBeInTheDocument(); + expect(screen.getByText("/key/update")).toBeInTheDocument(); + }); }); it("should display 'Not set' for null values", async () => { - const settingsWithNulls = { - ...mockSettings, + mockGetDefaultTeamSettings.mockResolvedValue({ values: { - ...mockSettings.values, max_budget: null, + budget_duration: null, + tpm_limit: null, + rpm_limit: null, + models: [], + team_member_permissions: [], }, - }; - mockGetDefaultTeamSettings.mockResolvedValue(settingsWithNulls); + }); renderWithProviders(); await waitFor(() => { - expect(screen.getByText("Not set")).toBeInTheDocument(); + const notSetElements = screen.getAllByText("Not set"); + // max_budget, budget_duration, tpm_limit, rpm_limit, models (empty), permissions (empty) + expect(notSetElements.length).toBeGreaterThanOrEqual(4); }); }); - it("should toggle edit mode when edit button is clicked", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); + // --- Edit Mode Toggle --- + + it("should toggle to edit mode when Edit Settings is clicked", async () => { + mockGetDefaultTeamSettings.mockResolvedValue(mockSettingsResponse); renderWithProviders(); await waitFor(() => { - expect(screen.getByRole("button", { name: "Edit Settings" })).toBeInTheDocument(); + expect(screen.getByRole("button", { name: /Edit Settings/i })).toBeInTheDocument(); }); - const editButton = screen.getByRole("button", { name: "Edit Settings" }); - await userEvent.click(editButton); + await userEvent.click(screen.getByRole("button", { name: /Edit Settings/i })); - expect(screen.getByRole("button", { name: "Cancel" })).toBeInTheDocument(); - expect(screen.getByRole("button", { name: "Save Changes" })).toBeInTheDocument(); - expect(screen.queryByRole("button", { name: "Edit Settings" })).not.toBeInTheDocument(); + expect(screen.getByRole("button", { name: /Cancel/i })).toBeInTheDocument(); + expect(screen.getByRole("button", { name: /Save Changes/i })).toBeInTheDocument(); + expect(screen.queryByRole("button", { name: /Edit Settings/i })).not.toBeInTheDocument(); }); it("should cancel edit mode and reset values", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); + mockGetDefaultTeamSettings.mockResolvedValue(mockSettingsResponse); renderWithProviders(); await waitFor(() => { - expect(screen.getByRole("button", { name: "Edit Settings" })).toBeInTheDocument(); + expect(screen.getByRole("button", { name: /Edit Settings/i })).toBeInTheDocument(); }); - const editButton = screen.getByRole("button", { name: "Edit Settings" }); - await userEvent.click(editButton); + await userEvent.click(screen.getByRole("button", { name: /Edit Settings/i })); + await userEvent.click(screen.getByRole("button", { name: /Cancel/i })); - const cancelButton = screen.getByRole("button", { name: "Cancel" }); - await userEvent.click(cancelButton); - - expect(screen.getByRole("button", { name: "Edit Settings" })).toBeInTheDocument(); - expect(screen.queryByRole("button", { name: "Cancel" })).not.toBeInTheDocument(); + expect(screen.getByRole("button", { name: /Edit Settings/i })).toBeInTheDocument(); + expect(screen.queryByRole("button", { name: /Cancel/i })).not.toBeInTheDocument(); }); - it("should save settings when save button is clicked", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); - mockUpdateDefaultTeamSettings.mockResolvedValue({ - settings: mockSettings.values, - }); + // --- Edit Mode Fields --- + + it("should show budget duration dropdown in edit mode", async () => { + mockGetDefaultTeamSettings.mockResolvedValue(mockSettingsResponse); renderWithProviders(); await waitFor(() => { - expect(screen.getByRole("button", { name: "Edit Settings" })).toBeInTheDocument(); + expect(screen.getByRole("button", { name: /Edit Settings/i })).toBeInTheDocument(); }); - const editButton = screen.getByRole("button", { name: "Edit Settings" }); - await userEvent.click(editButton); + await userEvent.click(screen.getByRole("button", { name: /Edit Settings/i })); await waitFor(() => { - expect(screen.getByRole("button", { name: "Save Changes" })).toBeInTheDocument(); - }); - - const saveButton = screen.getByRole("button", { name: "Save Changes" }); - await userEvent.click(saveButton); - - await waitFor(() => { - expect(mockUpdateDefaultTeamSettings).toHaveBeenCalledWith("test-token", mockSettings.values); - }); - - expect(mockNotificationsManager.success).toHaveBeenCalledWith("Default team settings updated successfully"); - }); - - it("should show error notification when save fails", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); - mockUpdateDefaultTeamSettings.mockRejectedValue(new Error("Save failed")); - - renderWithProviders(); - - await waitFor(() => { - expect(screen.getByRole("button", { name: "Edit Settings" })).toBeInTheDocument(); - }); - - const editButton = screen.getByRole("button", { name: "Edit Settings" }); - await userEvent.click(editButton); - - await waitFor(() => { - expect(screen.getByRole("button", { name: "Save Changes" })).toBeInTheDocument(); - }); - - const saveButton = screen.getByRole("button", { name: "Save Changes" }); - await userEvent.click(saveButton); - - await waitFor(() => { - expect(mockNotificationsManager.fromBackend).toHaveBeenCalledWith("Failed to update team settings"); + expect(screen.getByTestId("budget-duration-dropdown")).toBeInTheDocument(); }); }); - it("should render boolean field as switch in edit mode", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); + it("should show ModelSelect in edit mode", async () => { + mockGetDefaultTeamSettings.mockResolvedValue(mockSettingsResponse); renderWithProviders(); await waitFor(() => { - expect(screen.getByRole("button", { name: "Edit Settings" })).toBeInTheDocument(); + expect(screen.getByRole("button", { name: /Edit Settings/i })).toBeInTheDocument(); }); - const editButton = screen.getByRole("button", { name: "Edit Settings" }); - await userEvent.click(editButton); - - await waitFor(() => { - const switchElement = screen.getByRole("switch"); - expect(switchElement).toBeInTheDocument(); - expect(switchElement).toBeChecked(); - }); - }); - - it("should update boolean value when switch is toggled", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); - - renderWithProviders(); - - await waitFor(() => { - expect(screen.getByRole("button", { name: "Edit Settings" })).toBeInTheDocument(); - }); - - const editButton = screen.getByRole("button", { name: "Edit Settings" }); - await userEvent.click(editButton); - - await waitFor(() => { - expect(screen.getByRole("switch")).toBeInTheDocument(); - }); - - const switchElement = screen.getByRole("switch"); - await userEvent.click(switchElement); - - expect(switchElement).not.toBeChecked(); - }); - - it("should render budget duration dropdown in edit mode", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); - - renderWithProviders(); - - await waitFor(() => { - expect(screen.getByRole("button", { name: "Edit Settings" })).toBeInTheDocument(); - }); - - const editButton = screen.getByRole("button", { name: "Edit Settings" }); - await userEvent.click(editButton); - - await waitFor(() => { - expect(screen.getByLabelText("Budget duration")).toBeInTheDocument(); - }); - }); - - it("should update budget duration when dropdown value changes", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); - - renderWithProviders(); - - await waitFor(() => { - expect(screen.getByRole("button", { name: "Edit Settings" })).toBeInTheDocument(); - }); - - const editButton = screen.getByRole("button", { name: "Edit Settings" }); - await userEvent.click(editButton); - - await waitFor(() => { - expect(screen.getByLabelText("Budget duration")).toBeInTheDocument(); - }); - - const dropdown = screen.getByLabelText("Budget duration"); - await userEvent.selectOptions(dropdown, "daily"); - - expect(dropdown).toHaveValue("daily"); - }); - - it("should render text input for string fields in edit mode", async () => { - const settingsWithString = { - ...mockSettings, - field_schema: { - ...mockSettings.field_schema, - properties: { - ...mockSettings.field_schema.properties, - team_name: { - type: "string", - description: "Team name", - }, - }, - }, - values: { - ...mockSettings.values, - team_name: "Test Team", - }, - }; - mockGetDefaultTeamSettings.mockResolvedValue(settingsWithString); - - renderWithProviders(); - - await waitFor(() => { - expect(screen.getByRole("button", { name: "Edit Settings" })).toBeInTheDocument(); - }); - - const editButton = screen.getByRole("button", { name: "Edit Settings" }); - await userEvent.click(editButton); - - await waitFor(() => { - const textInput = screen.getByDisplayValue("Test Team"); - expect(textInput).toBeInTheDocument(); - }); - }); - - it("should render enum select for string enum fields in edit mode", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); - - renderWithProviders(); - - await waitFor(() => { - expect(screen.getByRole("button", { name: "Edit Settings" })).toBeInTheDocument(); - }); - - const editButton = screen.getByRole("button", { name: "Edit Settings" }); - await userEvent.click(editButton); - - await waitFor(() => { - const statusSelect = screen.getAllByRole("listbox")[0]; - expect(statusSelect).toBeInTheDocument(); - }); - }); - - it("should render multi-select for array enum fields in edit mode", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); - - renderWithProviders(); - - await waitFor(() => { - expect(screen.getByRole("button", { name: "Edit Settings" })).toBeInTheDocument(); - }); - - const editButton = screen.getByRole("button", { name: "Edit Settings" }); - await userEvent.click(editButton); - - await waitFor(() => { - const multiSelects = screen.getAllByRole("listbox"); - expect(multiSelects.length).toBeGreaterThan(0); - }); - }); - - it("should render ModelSelect for models field in edit mode", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); - - renderWithProviders(); - - await waitFor(() => { - expect(screen.getByRole("button", { name: "Edit Settings" })).toBeInTheDocument(); - }); - - const editButton = screen.getByRole("button", { name: "Edit Settings" }); - await userEvent.click(editButton); + await userEvent.click(screen.getByRole("button", { name: /Edit Settings/i })); await waitFor(() => { expect(screen.getByTestId("model-select")).toBeInTheDocument(); }); }); - it("should display models as badges in view mode", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); + it("should show number inputs for budget and rate limits in edit mode", async () => { + mockGetDefaultTeamSettings.mockResolvedValue(mockSettingsResponse); renderWithProviders(); await waitFor(() => { - const gpt4Elements = screen.getAllByText("gpt-4"); - expect(gpt4Elements.length).toBeGreaterThan(0); + expect(screen.getByRole("button", { name: /Edit Settings/i })).toBeInTheDocument(); + }); + + await userEvent.click(screen.getByRole("button", { name: /Edit Settings/i })); + + await waitFor(() => { + const numberInputs = screen.getAllByLabelText("number input"); + // max_budget, tpm_limit, rpm_limit + expect(numberInputs.length).toBe(3); }); }); - it("should display 'None' for empty arrays in view mode", async () => { - const settingsWithEmptyArray = { - ...mockSettings, - values: { - ...mockSettings.values, - models: [], - }, - }; - mockGetDefaultTeamSettings.mockResolvedValue(settingsWithEmptyArray); + it("should show permissions multi-select in edit mode", async () => { + mockGetDefaultTeamSettings.mockResolvedValue(mockSettingsResponse); renderWithProviders(); await waitFor(() => { - const noneTexts = screen.getAllByText("None"); - expect(noneTexts.length).toBeGreaterThan(0); + expect(screen.getByRole("button", { name: /Edit Settings/i })).toBeInTheDocument(); + }); + + await userEvent.click(screen.getByRole("button", { name: /Edit Settings/i })); + + await waitFor(() => { + const listboxes = screen.getAllByRole("listbox"); + expect(listboxes.length).toBeGreaterThan(0); }); }); - it("should display schema description when available", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); + // --- Save --- + + it("should save settings and show success notification", async () => { + mockGetDefaultTeamSettings.mockResolvedValue(mockSettingsResponse); + mockUpdateDefaultTeamSettings.mockResolvedValue({ + settings: mockSettingsResponse.values, + }); renderWithProviders(); await waitFor(() => { - expect(screen.getByText("Default team settings schema")).toBeInTheDocument(); + expect(screen.getByRole("button", { name: /Edit Settings/i })).toBeInTheDocument(); + }); + + await userEvent.click(screen.getByRole("button", { name: /Edit Settings/i })); + await userEvent.click(screen.getByRole("button", { name: /Save Changes/i })); + + await waitFor(() => { + expect(mockUpdateDefaultTeamSettings).toHaveBeenCalledWith("test-token", expect.any(Object)); + }); + + expect(mockNotificationsManager.success).toHaveBeenCalledWith("Default team settings updated successfully"); + + // Should exit edit mode after save + await waitFor(() => { + expect(screen.getByRole("button", { name: /Edit Settings/i })).toBeInTheDocument(); }); }); - it("should show error notification when fetching settings fails", async () => { - mockGetDefaultTeamSettings.mockRejectedValue(new Error("Fetch failed")); + it("should show error notification when save fails", async () => { + mockGetDefaultTeamSettings.mockResolvedValue(mockSettingsResponse); + mockUpdateDefaultTeamSettings.mockRejectedValue(new Error("Save failed")); renderWithProviders(); await waitFor(() => { - expect(mockNotificationsManager.fromBackend).toHaveBeenCalledWith("Failed to fetch team settings"); + expect(screen.getByRole("button", { name: /Edit Settings/i })).toBeInTheDocument(); }); - }); - it("should handle model fetch error gracefully", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); - mockModelAvailableCall.mockRejectedValue(new Error("Model fetch failed")); - - renderWithProviders(); + await userEvent.click(screen.getByRole("button", { name: /Edit Settings/i })); + await userEvent.click(screen.getByRole("button", { name: /Save Changes/i })); await waitFor(() => { - expect(screen.getByText("Default Team Settings")).toBeInTheDocument(); + expect(mockNotificationsManager.fromBackend).toHaveBeenCalledWith("Failed to update team settings"); }); }); it("should disable cancel button while saving", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); + mockGetDefaultTeamSettings.mockResolvedValue(mockSettingsResponse); mockUpdateDefaultTeamSettings.mockImplementation( - () => new Promise((resolve) => setTimeout(() => resolve({ settings: mockSettings.values }), 100)), + () => new Promise((resolve) => setTimeout(() => resolve({ settings: mockSettingsResponse.values }), 100)), ); renderWithProviders(); await waitFor(() => { - expect(screen.getByRole("button", { name: "Edit Settings" })).toBeInTheDocument(); + expect(screen.getByRole("button", { name: /Edit Settings/i })).toBeInTheDocument(); }); - const editButton = screen.getByRole("button", { name: "Edit Settings" }); - await userEvent.click(editButton); + await userEvent.click(screen.getByRole("button", { name: /Edit Settings/i })); + await userEvent.click(screen.getByRole("button", { name: /Save Changes/i })); - await waitFor(() => { - expect(screen.getByRole("button", { name: "Save Changes" })).toBeInTheDocument(); - }); - - const saveButton = screen.getByRole("button", { name: "Save Changes" }); - await userEvent.click(saveButton); - - const cancelButton = screen.getByRole("button", { name: "Cancel" }); - expect(cancelButton).toBeDisabled(); - }); - - it("should display field descriptions", async () => { - mockGetDefaultTeamSettings.mockResolvedValue(mockSettings); - - renderWithProviders(); - - await waitFor(() => { - expect(screen.getByText("Budget duration setting")).toBeInTheDocument(); - expect(screen.getByText("Maximum budget amount")).toBeInTheDocument(); - }); - }); - - it("should format field names by replacing underscores and capitalizing", async () => { - const settingsWithUnderscores = { - ...mockSettings, - field_schema: { - ...mockSettings.field_schema, - properties: { - ...mockSettings.field_schema.properties, - max_budget_per_user: { - type: "number", - description: "Max budget per user", - }, - }, - }, - values: { - ...mockSettings.values, - max_budget_per_user: 500, - }, - }; - mockGetDefaultTeamSettings.mockResolvedValue(settingsWithUnderscores); - - renderWithProviders(); - - await waitFor(() => { - expect(screen.getByText("Max Budget Per User")).toBeInTheDocument(); - }); - }); - - it("should display 'No schema information available' when schema is missing", async () => { - const settingsWithoutSchema = { - values: {}, - field_schema: null, - }; - mockGetDefaultTeamSettings.mockResolvedValue(settingsWithoutSchema); - - renderWithProviders(); - - await waitFor(() => { - expect(screen.getByText("No schema information available")).toBeInTheDocument(); - }); + expect(screen.getByRole("button", { name: /Cancel/i })).toBeDisabled(); }); }); diff --git a/ui/litellm-dashboard/src/components/TeamSSOSettings.tsx b/ui/litellm-dashboard/src/components/TeamSSOSettings.tsx index 33bfc783af..a9c07cdbcf 100644 --- a/ui/litellm-dashboard/src/components/TeamSSOSettings.tsx +++ b/ui/litellm-dashboard/src/components/TeamSSOSettings.tsx @@ -1,30 +1,96 @@ import React, { useState, useEffect } from "react"; -import { Card, Title, Text, Divider, Button, TextInput } from "@tremor/react"; -import { Typography, Spin, Switch, Select } from "antd"; -import { getDefaultTeamSettings, updateDefaultTeamSettings, modelAvailableCall } from "./networking"; +import { Card, Button, InputNumber, Typography, Spin, Select, Tag, Row, Col } from "antd"; +import { EditOutlined, SaveOutlined } from "@ant-design/icons"; +import { getDefaultTeamSettings, updateDefaultTeamSettings } from "./networking"; import BudgetDurationDropdown, { getBudgetDurationLabel } from "./common_components/budget_duration_dropdown"; import { getModelDisplayName } from "./key_team_helpers/fetch_available_models_team_key"; import NotificationsManager from "./molecules/notifications_manager"; import { ModelSelect } from "./ModelSelect/ModelSelect"; +const { Title, Text } = Typography; + interface TeamSSOSettingsProps { accessToken: string | null; userID: string; userRole: string; } -const TeamSSOSettings: React.FC = ({ accessToken, userID, userRole }) => { +const PERMISSION_OPTIONS = [ + "/key/generate", + "/key/update", + "/key/delete", + "/key/regenerate", + "/key/service-account/generate", + "/key/{key_id}/regenerate", + "/key/block", + "/key/unblock", + "/key/bulk_update", + "/key/{key_id}/reset_spend", +]; + +interface SettingRowProps { + label: string; + description: string; + isEditing: boolean; + viewContent: React.ReactNode; + editContent: React.ReactNode; +} + +const SettingRow: React.FC = ({ label, description, isEditing, viewContent, editContent }) => ( + + +
{label}
+
{description}
+ + +
{isEditing ? editContent : viewContent}
+ +
+); + +const NotSet = () => Not set; + +const renderTags = (values: string[], displayFn?: (v: string) => string) => { + if (!values || values.length === 0) return ; + return ( +
+ {values.map((v) => ( + + {displayFn ? displayFn(v) : v} + + ))} +
+ ); +}; + +interface SettingsValues { + max_budget: number | null; + budget_duration: string | null; + tpm_limit: number | null; + rpm_limit: number | null; + models: string[]; + team_member_permissions: string[]; +} + +const DEFAULT_VALUES: SettingsValues = { + max_budget: null, + budget_duration: null, + tpm_limit: null, + rpm_limit: null, + models: [], + team_member_permissions: [], +}; + +const TeamSSOSettings: React.FC = ({ accessToken }) => { const [loading, setLoading] = useState(true); - const [settings, setSettings] = useState(null); + const [values, setValues] = useState(DEFAULT_VALUES); const [isEditing, setIsEditing] = useState(false); - const [editedValues, setEditedValues] = useState({}); + const [editedValues, setEditedValues] = useState(DEFAULT_VALUES); const [saving, setSaving] = useState(false); - const [availableModels, setAvailableModels] = useState([]); - const { Paragraph } = Typography; - const { Option } = Select; + const [fetchError, setFetchError] = useState(false); useEffect(() => { - const fetchTeamSSOSettings = async () => { + const fetchSettings = async () => { if (!accessToken) { setLoading(false); return; @@ -32,39 +98,30 @@ const TeamSSOSettings: React.FC = ({ accessToken, userID, try { const data = await getDefaultTeamSettings(accessToken); - setSettings(data); - setEditedValues(data.values || {}); - - // Fetch available models - if (accessToken) { - try { - const modelResponse = await modelAvailableCall(accessToken, userID, userRole); - if (modelResponse && modelResponse.data) { - const modelNames = modelResponse.data.map((model: { id: string }) => model.id); - setAvailableModels(modelNames); - } - } catch (error) { - console.error("Error fetching available models:", error); - } - } + const fetched = { ...DEFAULT_VALUES, ...(data.values || {}) }; + setValues(fetched); + setEditedValues(fetched); } catch (error) { console.error("Error fetching team SSO settings:", error); + setFetchError(true); NotificationsManager.fromBackend("Failed to fetch team settings"); } finally { setLoading(false); } }; - fetchTeamSSOSettings(); + fetchSettings(); }, [accessToken]); - const handleSaveSettings = async () => { + const handleSave = async () => { if (!accessToken) return; setSaving(true); try { const updatedSettings = await updateDefaultTeamSettings(accessToken, editedValues); - setSettings({ ...settings, values: updatedSettings.settings }); + const newValues = { ...DEFAULT_VALUES, ...(updatedSettings.settings || {}) }; + setValues(newValues); + setEditedValues(newValues); setIsEditing(false); NotificationsManager.success("Default team settings updated successfully"); } catch (error) { @@ -75,129 +132,13 @@ const TeamSSOSettings: React.FC = ({ accessToken, userID, } }; - const handleTextInputChange = (key: string, value: any) => { - setEditedValues((prev: Record) => ({ - ...prev, - [key]: value, - })); + const handleCancel = () => { + setIsEditing(false); + setEditedValues(values); }; - const renderEditableField = (key: string, property: any, value: any) => { - const type = property.type; - - if (key === "budget_duration") { - return ( - handleTextInputChange(key, value)} - className="mt-2" - /> - ); - } else if (type === "boolean") { - return ( -
- handleTextInputChange(key, checked)} /> -
- ); - } else if (type === "array" && property.items?.enum) { - return ( - - ); - } else if (key === "models") { - return ( - handleTextInputChange(key, value)} - context="global" - style={{ width: "100%" }} - options={{ - includeSpecialOptions: true, - }} - /> - ); - } else if (type === "string" && property.enum) { - return ( - - ); - } else { - return ( - handleTextInputChange(key, e.target.value)} - placeholder={property.description || ""} - className="mt-2" - /> - ); - } - }; - - const renderValue = (key: string, value: any): JSX.Element => { - if (value === null || value === undefined) return Not set; - - if (key === "budget_duration") { - return {getBudgetDurationLabel(value)}; - } - - if (typeof value === "boolean") { - return {value ? "Enabled" : "Disabled"}; - } - - if (key === "models" && Array.isArray(value)) { - if (value.length === 0) return None; - - return ( -
- {value.map((model, index) => ( - - {getModelDisplayName(model)} - - ))} -
- ); - } - - if (typeof value === "object") { - if (Array.isArray(value)) { - if (value.length === 0) return None; - - return ( -
- {value.map((item, index) => ( - - {typeof item === "object" ? JSON.stringify(item) : String(item)} - - ))} -
- ); - } - - return
{JSON.stringify(value, null, 2)}
; - } - - return {String(value)}; + const update = (key: K, value: SettingsValues[K]) => { + setEditedValues((prev) => ({ ...prev, [key]: value })); }; if (loading) { @@ -208,7 +149,7 @@ const TeamSSOSettings: React.FC = ({ accessToken, userID, ); } - if (!settings) { + if (fetchError) { return ( No team settings available or you do not have permission to view them. @@ -216,70 +157,166 @@ const TeamSSOSettings: React.FC = ({ accessToken, userID, ); } - // Dynamically render settings based on the schema - const renderSettings = () => { - const { values, field_schema } = settings; - - if (!field_schema || !field_schema.properties) { - return No schema information available; - } - - return Object.entries(field_schema.properties).map(([key, property]: [string, any]) => { - const value = values[key]; - const displayName = key.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()); - - return ( -
- {displayName} - - {property.description || "No description available"} - - - {isEditing ? ( -
{renderEditableField(key, property, value)}
- ) : ( -
{renderValue(key, value)}
- )} -
- ); - }); - }; - return ( - -
- Default Team Settings - {!loading && - settings && - (isEditing ? ( -
- -
) : ( - - ))} + + )} +
- These settings will be applied by default when creating new teams. +
+ {/* Budget & Rate Limits */} +
+
Budget & Rate Limits
+
+ ${Number(values.max_budget).toLocaleString()} : + } + editContent={ + update("max_budget", v)} + placeholder="Not set" + prefix="$" + min={0} + /> + } + /> - {settings?.field_schema?.description && ( - {settings.field_schema.description} - )} - + {getBudgetDurationLabel(values.budget_duration)} : + } + editContent={ + update("budget_duration", v)} + style={{ maxWidth: 320 }} + /> + } + /> -
{renderSettings()}
+ {values.tpm_limit.toLocaleString()} : + } + editContent={ + update("tpm_limit", v)} + placeholder="Not set" + min={0} + /> + } + /> + + {values.rpm_limit.toLocaleString()} : + } + editContent={ + update("rpm_limit", v)} + placeholder="Not set" + min={0} + /> + } + /> +
+
+ + {/* Access & Permissions */} +
+
Access & Permissions
+
+ update("models", v)} + context="global" + style={{ width: "100%" }} + options={{ includeSpecialOptions: true }} + /> + } + /> + + update("team_member_permissions", v)} + placeholder="Select permissions" + tagRender={({ label, closable, onClose }) => ( + + {label} + + )} + > + {PERMISSION_OPTIONS.map((option) => ( + + {option} + + ))} + + } + /> +
+
+
); }; diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index 11a8a6f1fe..bb9a0c1e01 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -7206,7 +7206,6 @@ export const updateDefaultTeamSettings = async (accessToken: string, settings: R const data = await response.json(); console.log("Updated default team settings:", data); - NotificationsManager.success("Default team settings updated successfully"); return data; } catch (error) { console.error("Failed to update default team settings:", error); diff --git a/ui/litellm-dashboard/tsconfig.json b/ui/litellm-dashboard/tsconfig.json index 5b0352feb9..d24bdd340f 100644 --- a/ui/litellm-dashboard/tsconfig.json +++ b/ui/litellm-dashboard/tsconfig.json @@ -14,7 +14,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { From 3ae9e070d97a41f5ab01da979c33ed1ffda0052b Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 14 Mar 2026 00:30:03 -0700 Subject: [PATCH 060/289] [Feature] UI - Usage: Auto-paginate daily spend data with progressive rendering Previously, EntityUsage only fetched page 1 of paginated daily spend endpoints, showing incomplete data. UsagePageView fetched all pages but blocked the UI until completion. This adds a reusable usePaginatedDailyActivity hook that fetches pages sequentially with 500ms delays, updates charts progressively, and supports cancellation on unmount or user action. Co-Authored-By: Claude Opus 4.6 --- .../components/EntityUsage/EntityUsage.tsx | 178 +++++++-------- .../UsagePage/components/UsagePageView.tsx | 177 +++++++-------- .../hooks/usePaginatedDailyActivity.ts | 209 ++++++++++++++++++ 3 files changed, 373 insertions(+), 191 deletions(-) create mode 100644 ui/litellm-dashboard/src/components/UsagePage/hooks/usePaginatedDailyActivity.ts diff --git a/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx b/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx index 92d9c25c6b..c1d5314096 100644 --- a/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx +++ b/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx @@ -22,7 +22,8 @@ import { Text, Title, } from "@tremor/react"; -import React, { useEffect, useState } from "react"; +import { LoadingOutlined } from "@ant-design/icons"; +import React, { useMemo, useState } from "react"; import { ActivityMetrics, processActivityData } from "../../../activity_metrics"; import { UsageExportHeader } from "../../../EntityUsageExport"; import type { EntityType } from "../../../EntityUsageExport/types"; @@ -35,6 +36,7 @@ import { userDailyActivityCall, } from "../../../networking"; import { getProviderLogoAndName } from "../../../provider_info_helpers"; +import { usePaginatedDailyActivity } from "../../hooks/usePaginatedDailyActivity"; import { BreakdownMetrics, DailyData, EntityMetricWithMetadata, KeyMetricWithMetadata, TagUsage } from "../../types"; import { valueFormatterSpend } from "../../utils/value_formatters"; import EndpointUsage from "../EndpointUsage/EndpointUsage"; @@ -87,119 +89,64 @@ interface EntityUsageProps { dateValue: DateRangePickerValue; } +const ENTITY_FETCH_FNS: Record Promise> = { + tag: tagDailyActivityCall, + team: teamDailyActivityCall, + organization: organizationDailyActivityCall, + customer: customerDailyActivityCall, + agent: agentDailyActivityCall, + user: userDailyActivityCall, +}; + const EntityUsage: React.FC = ({ accessToken, entityType, entityId, entityList, dateValue }) => { - const [spendData, setSpendData] = useState({ - results: [], - metadata: { - total_spend: 0, - total_api_requests: 0, - total_successful_requests: 0, - total_failed_requests: 0, - total_tokens: 0, - }, - }); const { teams } = useTeams(); - - const [agentSpendData, setAgentSpendData] = useState({ - results: [], - metadata: { - total_spend: 0, - total_api_requests: 0, - total_successful_requests: 0, - total_failed_requests: 0, - total_tokens: 0, - }, - }); - - const modelMetrics = processActivityData(spendData, "models", teams || []); - const keyMetrics = processActivityData(spendData, "api_keys", teams || []); - const agentMetrics = entityType === "team" ? processActivityData(agentSpendData, "entities", teams || []) : {}; const [selectedTags, setSelectedTags] = useState([]); const [topKeysLimit, setTopKeysLimit] = useState(5); const [topModelsLimit, setTopModelsLimit] = useState(5); const [topAgentsLimit, setTopAgentsLimit] = useState(5); - const fetchSpendData = async () => { - if (!accessToken || !dateValue.from || !dateValue.to) return; - // Create new Date objects to avoid mutating the original dates - const startTime = new Date(dateValue.from); - const endTime = new Date(dateValue.to); + const startTime = useMemo(() => dateValue.from ? new Date(dateValue.from) : null, [dateValue.from]); + const endTime = useMemo(() => dateValue.to ? new Date(dateValue.to) : null, [dateValue.to]); - if (entityType === "tag") { - const data = await tagDailyActivityCall( - accessToken, - startTime, - endTime, - 1, - selectedTags.length > 0 ? selectedTags : null, - ); - setSpendData(data); - } else if (entityType === "team") { - const data = await teamDailyActivityCall( - accessToken, - startTime, - endTime, - 1, - selectedTags.length > 0 ? selectedTags : null, - ); - setSpendData(data); - } else if (entityType === "organization") { - const data = await organizationDailyActivityCall( - accessToken, - startTime, - endTime, - 1, - selectedTags.length > 0 ? selectedTags : null, - ); - setSpendData(data); - } else if (entityType === "customer") { - const data = await customerDailyActivityCall( - accessToken, - startTime, - endTime, - 1, - selectedTags.length > 0 ? selectedTags : null, - ); - setSpendData(data); - } else if (entityType === "agent") { - const data = await agentDailyActivityCall( - accessToken, - startTime, - endTime, - 1, - selectedTags.length > 0 ? selectedTags : null, - ); - setSpendData(data); - } else if (entityType === "user") { - const data = await userDailyActivityCall( - accessToken, - startTime, - endTime, - 1, - selectedTags.length > 0 ? selectedTags[0] : null, - ); - setSpendData(data); - } else { - throw new Error("Invalid entity type"); - } - }; + const entityFilterArg = useMemo(() => { + if (entityType === "user") return selectedTags.length > 0 ? selectedTags[0] : null; + return selectedTags.length > 0 ? selectedTags : null; + }, [entityType, selectedTags]); - const fetchAgentSpendData = async () => { - if (!accessToken || !dateValue.from || !dateValue.to || entityType !== "team") return; - const startTime = new Date(dateValue.from); - const endTime = new Date(dateValue.to); - try { - const data = await agentDailyActivityCall(accessToken, startTime, endTime, 1, null); - setAgentSpendData(data); - } catch (e) { - console.error("Failed to fetch agent activity data:", e); - } - }; + const fetchFn = ENTITY_FETCH_FNS[entityType]; + const enabled = !!accessToken && !!startTime && !!endTime; - useEffect(() => { - fetchSpendData(); - fetchAgentSpendData(); - }, [accessToken, dateValue, entityId, selectedTags]); + const { + data: spendDataRaw, + isFetchingMore, + progress, + cancelled, + cancel, + } = usePaginatedDailyActivity({ + fetchFn, + args: [accessToken, startTime, endTime, entityFilterArg], + enabled, + }); + + const spendData = spendDataRaw as unknown as EntitySpendData; + + const { + data: agentSpendDataRaw, + isFetchingMore: agentIsFetchingMore, + progress: agentProgress, + cancelled: agentCancelled, + cancel: agentCancel, + } = usePaginatedDailyActivity({ + fetchFn: agentDailyActivityCall, + args: [accessToken, startTime, endTime, null], + enabled: enabled && entityType === "team", + }); + + const agentSpendData = agentSpendDataRaw as unknown as EntitySpendData; + + const modelMetrics = processActivityData(spendData, "models", teams || []); + const keyMetrics = processActivityData(spendData, "api_keys", teams || []); + const agentMetrics = entityType === "team" ? processActivityData(agentSpendData, "entities", teams || []) : {}; const getTopModels = () => { const modelSpend: { [key: string]: any } = {}; @@ -448,6 +395,29 @@ const EntityUsage: React.FC = ({ accessToken, entityType, enti return (
+ {(isFetchingMore || cancelled || agentIsFetchingMore || agentCancelled) && ( +
+ {isFetchingMore && ( + <> + + Loading spend data... (page {progress.currentPage}/{progress.totalPages}) + + + )} + {cancelled && ( + + Showing partial data ({progress.currentPage}/{progress.totalPages} pages loaded) + + )} + {agentIsFetchingMore && entityType === "team" && ( + <> + + Loading agent data... (page {agentProgress.currentPage}/{agentProgress.totalPages}) + + + )} +
+ )} = ({ teams, organizations }) => { const { accessToken, userRole, userId: userID, premiumUser } = useAuthorized(); - const [userSpendData, setUserSpendData] = useState<{ - results: DailyData[]; - metadata: any; - }>({ results: [], metadata: {} }); + // Aggregated endpoint: try first, fall back to paginated if unavailable + const [aggregatedData, setAggregatedData] = useState<{ results: DailyData[]; metadata: any } | null>(null); + const [aggregatedFailed, setAggregatedFailed] = useState(false); + const [aggregatedLoading, setAggregatedLoading] = useState(false); // Separate loading states for better UX - const [loading, setLoading] = useState(false); const [isDateChanging, setIsDateChanging] = useState(false); // Create initial dates outside of state to prevent recreation @@ -173,6 +173,67 @@ const UsagePage: React.FC = ({ teams, organizations }) => { } }, [isAdmin, userID]); + // For non-admins, always pass their own user_id + const effectiveUserId = isAdmin ? selectedUserId : (userID || null); + + const startTime = useMemo(() => dateValue.from ? new Date(dateValue.from) : null, [dateValue.from]); + const endTime = useMemo(() => dateValue.to ? new Date(dateValue.to) : null, [dateValue.to]); + + // Try aggregated endpoint first, fall back to paginated on failure + const aggregatedFetchIdRef = useRef(0); + useEffect(() => { + if (!accessToken || !startTime || !endTime) return; + const fetchId = ++aggregatedFetchIdRef.current; + setAggregatedLoading(true); + setAggregatedFailed(false); + setAggregatedData(null); + + userDailyActivityAggregatedCall(accessToken, startTime, endTime, effectiveUserId) + .then((data) => { + if (aggregatedFetchIdRef.current !== fetchId) return; + setAggregatedData(data); + setAggregatedLoading(false); + setIsDateChanging(false); + }) + .catch(() => { + if (aggregatedFetchIdRef.current !== fetchId) return; + setAggregatedFailed(true); + setAggregatedLoading(false); + }); + }, [accessToken, startTime, endTime, effectiveUserId]); + + // Paginated fallback — only enabled when aggregated endpoint fails + const paginatedResult = usePaginatedDailyActivity({ + fetchFn: userDailyActivityCall, + args: [accessToken, startTime, endTime, effectiveUserId], + enabled: aggregatedFailed && !!accessToken && !!startTime && !!endTime, + }); + + // Derive userSpendData from whichever source is active + const userSpendData = useMemo(() => { + if (aggregatedData) return aggregatedData; + if (aggregatedFailed) return paginatedResult.data; + return { results: [] as DailyData[], metadata: {} as any }; + }, [aggregatedData, aggregatedFailed, paginatedResult.data]); + + const loading = aggregatedLoading || paginatedResult.loading; + + // Clear isDateChanging when paginated data starts arriving + useEffect(() => { + if (aggregatedFailed && !paginatedResult.loading && paginatedResult.data.results.length > 0) { + setIsDateChanging(false); + } + }, [aggregatedFailed, paginatedResult.loading, paginatedResult.data.results.length]); + + // Super responsive date change handler + const handleDateChange = useCallback((newValue: DateRangePickerValue) => { + // Instant visual feedback + setIsDateChanging(true); + + // Update date immediately for UI responsiveness + setDateValue(newValue); + }, []); + // Derived states from userSpendData const totalSpend = userSpendData.metadata?.total_spend || 0; @@ -362,87 +423,6 @@ const UsagePage: React.FC = ({ teams, organizations }) => { .slice(0, topKeysLimit); }, [userSpendData.results, topKeysLimit]); - const fetchUserSpendData = useCallback(async () => { - if (!accessToken || !dateValue.from || !dateValue.to) return; - - // For non-admins, always pass their own user_id - const effectiveUserId = isAdmin ? selectedUserId : (userID || null); - - setLoading(true); - - // Create new Date objects to avoid mutating the original dates - const startTime = new Date(dateValue.from); - const endTime = new Date(dateValue.to); - - try { - // Prefer aggregated endpoint to avoid many page requests - try { - const aggregated = await userDailyActivityAggregatedCall(accessToken, startTime, endTime, effectiveUserId); - setUserSpendData(aggregated); - return; - } catch (e) { - // Fallback to paginated calls if aggregated endpoint is unavailable - } - - const firstPageData = await userDailyActivityCall(accessToken, startTime, endTime, 1, effectiveUserId); - - if (firstPageData.metadata.total_pages <= 1) { - setUserSpendData(firstPageData); - return; - } - - const allResults = [...firstPageData.results]; - const aggregatedMetadata = { ...firstPageData.metadata }; - - for (let page = 2; page <= firstPageData.metadata.total_pages; page++) { - const pageData = await userDailyActivityCall(accessToken, startTime, endTime, page, effectiveUserId); - allResults.push(...pageData.results); - if (pageData.metadata) { - aggregatedMetadata.total_spend = (aggregatedMetadata.total_spend || 0) + (pageData.metadata.total_spend || 0); - aggregatedMetadata.total_api_requests = (aggregatedMetadata.total_api_requests || 0) + (pageData.metadata.total_api_requests || 0); - aggregatedMetadata.total_successful_requests = (aggregatedMetadata.total_successful_requests || 0) + (pageData.metadata.total_successful_requests || 0); - aggregatedMetadata.total_failed_requests = (aggregatedMetadata.total_failed_requests || 0) + (pageData.metadata.total_failed_requests || 0); - aggregatedMetadata.total_tokens = (aggregatedMetadata.total_tokens || 0) + (pageData.metadata.total_tokens || 0); - aggregatedMetadata.total_prompt_tokens = (aggregatedMetadata.total_prompt_tokens || 0) + (pageData.metadata.total_prompt_tokens || 0); - aggregatedMetadata.total_completion_tokens = (aggregatedMetadata.total_completion_tokens || 0) + (pageData.metadata.total_completion_tokens || 0); - aggregatedMetadata.total_cache_read_input_tokens = (aggregatedMetadata.total_cache_read_input_tokens || 0) + (pageData.metadata.total_cache_read_input_tokens || 0); - aggregatedMetadata.total_cache_creation_input_tokens = (aggregatedMetadata.total_cache_creation_input_tokens || 0) + (pageData.metadata.total_cache_creation_input_tokens || 0); - } - } - - setUserSpendData({ - results: allResults, - metadata: aggregatedMetadata, - }); - } catch (error) { - console.error("Error fetching user spend data:", error); - } finally { - setLoading(false); - setIsDateChanging(false); - } - }, [accessToken, dateValue.from, dateValue.to, selectedUserId, isAdmin, userID]); - - // Super responsive date change handler - const handleDateChange = useCallback((newValue: DateRangePickerValue) => { - // Instant visual feedback - setIsDateChanging(true); - setLoading(true); - - // Update date immediately for UI responsiveness - setDateValue(newValue); - }, []); - - // Debounced effect for data fetching with shorter delay - useEffect(() => { - if (!dateValue.from || !dateValue.to) return; - - const timeoutId = setTimeout(() => { - fetchUserSpendData(); - }, 50); // Very short debounce - - return () => clearTimeout(timeoutId); - }, [fetchUserSpendData]); - const sortedDailyResults = useMemo( () => [...userSpendData.results].sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()), [userSpendData.results], @@ -502,6 +482,29 @@ const UsagePage: React.FC = ({ teams, organizations }) => { />
+ {(paginatedResult.isFetchingMore || paginatedResult.cancelled) && ( +
+ {paginatedResult.isFetchingMore && ( + <> + + + Loading spend data... (page {paginatedResult.progress.currentPage}/{paginatedResult.progress.totalPages}) + + + + )} + {paginatedResult.cancelled && ( + + Showing partial data ({paginatedResult.progress.currentPage}/{paginatedResult.progress.totalPages} pages loaded) + + )} +
+ )} {/* Your Usage Panel */} {usageView === "global" && ( <> diff --git a/ui/litellm-dashboard/src/components/UsagePage/hooks/usePaginatedDailyActivity.ts b/ui/litellm-dashboard/src/components/UsagePage/hooks/usePaginatedDailyActivity.ts new file mode 100644 index 0000000000..19872bf31a --- /dev/null +++ b/ui/litellm-dashboard/src/components/UsagePage/hooks/usePaginatedDailyActivity.ts @@ -0,0 +1,209 @@ +import { useCallback, useEffect, useRef, useState } from "react"; +import { DailyData } from "../types"; + +export interface PaginationProgress { + currentPage: number; + totalPages: number; +} + +/** Delay between sequential page fetches (ms) to avoid overloading the backend. */ +const PAGE_FETCH_DELAY_MS = 500; + +/** The metadata fields returned by the daily activity API that should be summed across pages. */ +const SUMMABLE_METADATA_KEYS = [ + "total_spend", + "total_prompt_tokens", + "total_completion_tokens", + "total_tokens", + "total_api_requests", + "total_successful_requests", + "total_failed_requests", + "total_cache_read_input_tokens", + "total_cache_creation_input_tokens", +] as const; + +interface DailyActivityResponse { + results: DailyData[]; + metadata: Record; +} + +type FetchPageFn = (...args: any[]) => Promise; + +interface UsePaginatedDailyActivityParams { + /** The API call function (e.g., userDailyActivityCall). */ + fetchFn: FetchPageFn; + /** Arguments to pass to fetchFn: [accessToken, startTime, endTime, ...extraArgs]. Page is injected by the hook at index 3. */ + args: any[]; + /** Whether the hook should fetch. Set to false to disable. */ + enabled: boolean; +} + +interface UsePaginatedDailyActivityReturn { + data: DailyActivityResponse; + loading: boolean; + isFetchingMore: boolean; + progress: PaginationProgress; + cancelled: boolean; + cancel: () => void; +} + +const EMPTY_DATA: DailyActivityResponse = { + results: [], + metadata: { + total_spend: 0, + total_prompt_tokens: 0, + total_completion_tokens: 0, + total_tokens: 0, + total_api_requests: 0, + total_successful_requests: 0, + total_failed_requests: 0, + total_cache_read_input_tokens: 0, + total_cache_creation_input_tokens: 0, + total_pages: 1, + has_more: false, + page: 1, + }, +}; + +function sumMetadata( + a: Record, + b: Record, +): Record { + const result = { ...a }; + for (const key of SUMMABLE_METADATA_KEYS) { + result[key] = (a[key] || 0) + (b[key] || 0); + } + return result; +} + +/** + * Hook that auto-paginates daily activity endpoints, updating state after each + * page so charts render progressively. Cancels on unmount, param changes, or + * manual cancel(). + * + * The `args` array should contain every argument the fetchFn expects EXCEPT + * the `page` parameter. The hook injects `page` as the 4th argument (index 3), + * matching the signature of all daily activity calls: + * (accessToken, startTime, endTime, page, ...rest) + */ +export function usePaginatedDailyActivity({ + fetchFn, + args, + enabled, +}: UsePaginatedDailyActivityParams): UsePaginatedDailyActivityReturn { + const [data, setData] = useState(EMPTY_DATA); + const [loading, setLoading] = useState(false); + const [isFetchingMore, setIsFetchingMore] = useState(false); + const [progress, setProgress] = useState({ + currentPage: 0, + totalPages: 0, + }); + const [cancelled, setCancelled] = useState(false); + + const fetchIdRef = useRef(0); + const cancelledRef = useRef(false); + + const cancel = useCallback(() => { + cancelledRef.current = true; + setCancelled(true); + setIsFetchingMore(false); + }, []); + + useEffect(() => { + if (!enabled) { + setData(EMPTY_DATA); + setLoading(false); + setIsFetchingMore(false); + setProgress({ currentPage: 0, totalPages: 0 }); + setCancelled(false); + return; + } + + const currentFetchId = ++fetchIdRef.current; + cancelledRef.current = false; + setCancelled(false); + + const isStale = () => + fetchIdRef.current !== currentFetchId || cancelledRef.current; + + const run = async () => { + setLoading(true); + setIsFetchingMore(false); + setProgress({ currentPage: 1, totalPages: 1 }); + + try { + // Inject page=1 as the 4th argument. + const argsWithPage = [...args.slice(0, 3), 1, ...args.slice(3)]; + const firstPage = await fetchFn(...argsWithPage); + + if (isStale()) return; + + setData(firstPage); + + const totalPages = firstPage.metadata?.total_pages || 1; + + setProgress({ currentPage: 1, totalPages }); + + if (totalPages <= 1) { + setLoading(false); + return; + } + + // More pages — start fetching sequentially. + setLoading(false); + setIsFetchingMore(true); + + let accumulatedResults = [...firstPage.results]; + let accumulatedMetadata = { ...firstPage.metadata }; + + for (let page = 2; page <= totalPages; page++) { + if (isStale()) return; + + // Small delay to avoid overwhelming the backend. + await new Promise((resolve) => + setTimeout(resolve, PAGE_FETCH_DELAY_MS), + ); + + if (isStale()) return; + + const argsForPage = [...args.slice(0, 3), page, ...args.slice(3)]; + const pageData = await fetchFn(...argsForPage); + + if (isStale()) return; + + accumulatedResults = [...accumulatedResults, ...pageData.results]; + accumulatedMetadata = sumMetadata( + accumulatedMetadata, + pageData.metadata, + ); + accumulatedMetadata.total_pages = totalPages; + accumulatedMetadata.has_more = page < totalPages; + accumulatedMetadata.page = page; + + setData({ + results: accumulatedResults, + metadata: accumulatedMetadata, + }); + setProgress({ currentPage: page, totalPages }); + } + + setIsFetchingMore(false); + } catch (error) { + if (!isStale()) { + console.error("Error fetching daily activity:", error); + setLoading(false); + setIsFetchingMore(false); + } + } + }; + + run(); + + return () => { + fetchIdRef.current++; + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [enabled, fetchFn, ...args]); + + return { data, loading, isFetchingMore, progress, cancelled, cancel }; +} From 01ed0e0ebffa233927256d43757975ad5d60488a Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Sat, 14 Mar 2026 16:32:18 +0530 Subject: [PATCH 061/289] fix: ensure metadata isolation for silent model metrics --- litellm/router.py | 5 +++++ tests/test_litellm/test_router_silent_experiment.py | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/litellm/router.py b/litellm/router.py index c7cff4ba41..8636f6684a 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -1518,6 +1518,11 @@ class Router: if "metadata" not in silent_kwargs: silent_kwargs["metadata"] = {} + # OTel spans are not safe to use across event loops. The silent + # experiment runs in a new event loop, so strip the span to prevent + # cross-loop tracing races or span corruption. + silent_kwargs["metadata"].pop("litellm_parent_otel_span", None) + silent_kwargs["metadata"]["is_silent_experiment"] = True # Force stream=False so the response is fully consumed and callbacks fire diff --git a/tests/test_litellm/test_router_silent_experiment.py b/tests/test_litellm/test_router_silent_experiment.py index 6be95ca91a..24f574a4f8 100644 --- a/tests/test_litellm/test_router_silent_experiment.py +++ b/tests/test_litellm/test_router_silent_experiment.py @@ -73,7 +73,11 @@ def test_get_silent_experiment_kwargs(): # so that setting model_group / is_silent_experiment on the silent dict # doesn't corrupt the primary call's metadata. assert result["metadata"] is not kwargs["metadata"] - # Original metadata must NOT be mutated + # OTel span must be stripped from the silent copy — it's not safe to use + # across event loops (silent experiment runs in a new event loop). + assert "litellm_parent_otel_span" not in result["metadata"] + # Original metadata must NOT be mutated — must carry the real span, + # not safe_deep_copy's temporary "placeholder" string. assert "is_silent_experiment" not in kwargs["metadata"] assert kwargs["metadata"]["litellm_parent_otel_span"] is mock_span assert kwargs["metadata"]["user_api_key_auth"] is mock_auth From dc6f68b43187cbc009f92a6d1e3cb686dd74fbd2 Mon Sep 17 00:00:00 2001 From: Harshit Jain <48647625+Harshit28j@users.noreply.github.com> Date: Sat, 14 Mar 2026 16:47:56 +0530 Subject: [PATCH 062/289] Update tests/test_litellm/test_router_silent_experiment.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- tests/test_litellm/test_router_silent_experiment.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_litellm/test_router_silent_experiment.py b/tests/test_litellm/test_router_silent_experiment.py index 24f574a4f8..f5c5729cd4 100644 --- a/tests/test_litellm/test_router_silent_experiment.py +++ b/tests/test_litellm/test_router_silent_experiment.py @@ -81,6 +81,9 @@ def test_get_silent_experiment_kwargs(): assert "is_silent_experiment" not in kwargs["metadata"] assert kwargs["metadata"]["litellm_parent_otel_span"] is mock_span assert kwargs["metadata"]["user_api_key_auth"] is mock_auth + # Shallow copy must preserve user_api_key_auth so the silent experiment + # can attribute billing / spend logs to the correct key/team. + assert result["metadata"]["user_api_key_auth"] is mock_auth def test_silent_experiment_completion_direct(): From 83e6096dae150f925f695364f842fa330144292a Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 14 Mar 2026 09:37:44 -0700 Subject: [PATCH 063/289] [Feature] UI - Internal Users: Add/remove team membership from user info page Co-Authored-By: Claude Opus 4.6 --- .../view_users/user_info_view.test.tsx | 200 +++++++++-- .../components/view_users/user_info_view.tsx | 339 ++++++++++++++---- 2 files changed, 451 insertions(+), 88 deletions(-) diff --git a/ui/litellm-dashboard/src/components/view_users/user_info_view.test.tsx b/ui/litellm-dashboard/src/components/view_users/user_info_view.test.tsx index 201c686de2..481a2c6668 100644 --- a/ui/litellm-dashboard/src/components/view_users/user_info_view.test.tsx +++ b/ui/litellm-dashboard/src/components/view_users/user_info_view.test.tsx @@ -1,32 +1,47 @@ -import { render, screen } from "@testing-library/react"; -import { describe, expect, it, vi } from "vitest"; +import { render, screen, waitFor, within } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { describe, expect, it, vi, beforeEach } from "vitest"; import UserInfoView from "./user_info_view"; -vi.mock("../networking", () => { - const MOCK_USER_DATA = { - user_id: "user-123", - user_email: "test@example.com", - user_alias: "Test Alias", - user_role: "admin", - spend: 0, - max_budget: 100, - models: [], - budget_duration: "30d", - budget_reset_at: null, - metadata: {}, - created_at: "2025-01-01T00:00:00.000Z", - updated_at: "2025-01-02T00:00:00.000Z", - sso_user_id: null, - teams: [], - }; +const mockTeamMemberAddCall = vi.fn(); +const mockTeamMemberDeleteCall = vi.fn(); +const mockTeamListCall = vi.fn(); +const mockUserGetInfoV2 = vi.fn(); +const mockTeamInfoCall = vi.fn(); +const MOCK_USER_DATA = { + user_id: "user-123", + user_email: "test@example.com", + user_alias: "Test Alias", + user_role: "admin", + spend: 0, + max_budget: 100, + models: [], + budget_duration: "30d", + budget_reset_at: null, + metadata: {}, + created_at: "2025-01-01T00:00:00.000Z", + updated_at: "2025-01-02T00:00:00.000Z", + sso_user_id: null, + teams: ["team-1", "team-2"], +}; + +const MOCK_USER_DATA_NO_TEAMS = { + ...MOCK_USER_DATA, + teams: [], +}; + +vi.mock("../networking", () => { return { - userGetInfoV2: vi.fn().mockResolvedValue(MOCK_USER_DATA), + userGetInfoV2: (...args: any[]) => mockUserGetInfoV2(...args), userDeleteCall: vi.fn(), userUpdateUserCall: vi.fn(), modelAvailableCall: vi.fn().mockResolvedValue({ data: [] }), invitationCreateCall: vi.fn(), - teamInfoCall: vi.fn().mockResolvedValue({ team_alias: "Test Team" }), + teamInfoCall: (...args: any[]) => mockTeamInfoCall(...args), + teamListCall: (...args: any[]) => mockTeamListCall(...args), + teamMemberAddCall: (...args: any[]) => mockTeamMemberAddCall(...args), + teamMemberDeleteCall: (...args: any[]) => mockTeamMemberDeleteCall(...args), getProxyBaseUrl: () => "https://litellm.test", }; }); @@ -36,10 +51,30 @@ describe("UserInfoView", () => { userId: "user-123", onClose: vi.fn(), accessToken: "test-token", - userRole: null, + userRole: null as string | null, possibleUIRoles: null, }; + beforeEach(() => { + vi.clearAllMocks(); + mockUserGetInfoV2.mockResolvedValue(MOCK_USER_DATA); + mockTeamInfoCall.mockImplementation((_token: string, teamId: string) => { + const teamMap: Record = { + "team-1": { team_id: "team-1", team_info: { team_alias: "Alpha Team" } }, + "team-2": { team_id: "team-2", team_info: { team_alias: "Beta Team" } }, + "team-3": { team_id: "team-3", team_info: { team_alias: "Gamma Team" } }, + }; + return Promise.resolve(teamMap[teamId] || { team_id: teamId, team_info: { team_alias: null } }); + }); + mockTeamListCall.mockResolvedValue([ + { team_id: "team-1", team_alias: "Alpha Team" }, + { team_id: "team-2", team_alias: "Beta Team" }, + { team_id: "team-3", team_alias: "Gamma Team" }, + ]); + mockTeamMemberAddCall.mockResolvedValue({}); + mockTeamMemberDeleteCall.mockResolvedValue({}); + }); + it("should render the loading state", () => { render(); @@ -60,4 +95,125 @@ describe("UserInfoView", () => { const aliases = await screen.findAllByText("Test Alias"); expect(aliases.length).toBeGreaterThan(0); }); + + it("should render teams in a table with team names", async () => { + render(); + + await waitFor(() => { + expect(screen.getByText("Alpha Team")).toBeInTheDocument(); + expect(screen.getByText("Beta Team")).toBeInTheDocument(); + }); + }); + + it("should show 'No teams' when user has no teams", async () => { + mockUserGetInfoV2.mockResolvedValue(MOCK_USER_DATA_NO_TEAMS); + render(); + + await waitFor(() => { + expect(screen.getByText("No teams")).toBeInTheDocument(); + }); + }); + + it("should show Add Team button for proxy admins", async () => { + render(); + + await waitFor(() => { + expect(screen.getByText("Add Team")).toBeInTheDocument(); + }); + }); + + it("should not show Add Team button for non-proxy-admins", async () => { + render(); + + await waitFor(() => { + expect(screen.getByText("Alpha Team")).toBeInTheDocument(); + }); + expect(screen.queryByText("Add Team")).not.toBeInTheDocument(); + }); + + it("should show delete buttons for proxy admins", async () => { + render(); + + await waitFor(() => { + expect(screen.getByText("Alpha Team")).toBeInTheDocument(); + }); + // Should have the Actions column header + expect(screen.getByText("Actions")).toBeInTheDocument(); + }); + + it("should not show delete buttons for non-proxy-admins", async () => { + render(); + + await waitFor(() => { + expect(screen.getByText("Alpha Team")).toBeInTheDocument(); + }); + expect(screen.queryByText("Actions")).not.toBeInTheDocument(); + }); + + it("should open the add team modal when Add Team is clicked", async () => { + const user = userEvent.setup(); + render(); + + await waitFor(() => { + expect(screen.getByText("Add Team")).toBeInTheDocument(); + }); + + await user.click(screen.getByText("Add Team")); + + await waitFor(() => { + expect(screen.getByText("Add User to Team")).toBeInTheDocument(); + }); + expect(mockTeamListCall).toHaveBeenCalledWith("test-token", null); + }); + + it("should open remove confirmation modal when delete is clicked", async () => { + const user = userEvent.setup(); + render(); + + await waitFor(() => { + expect(screen.getByText("Alpha Team")).toBeInTheDocument(); + }); + + // Find the row with Alpha Team and click its delete button + const alphaRow = screen.getByText("Alpha Team").closest("tr")!; + const deleteButton = within(alphaRow).getByRole("button"); + await user.click(deleteButton); + + await waitFor(() => { + expect(screen.getByText("Remove from Team")).toBeInTheDocument(); + expect(screen.getByText(/Removing this user from the team will also delete any keys/)).toBeInTheDocument(); + }); + }); + + it("should call teamMemberDeleteCall when remove is confirmed", async () => { + const user = userEvent.setup(); + render(); + + await waitFor(() => { + expect(screen.getByText("Alpha Team")).toBeInTheDocument(); + }); + + // Click delete on Alpha Team + const alphaRow = screen.getByText("Alpha Team").closest("tr")!; + const deleteButton = within(alphaRow).getByRole("button"); + await user.click(deleteButton); + + // Confirm deletion + await waitFor(() => { + expect(screen.getByText("Remove from Team")).toBeInTheDocument(); + }); + + // The DeleteResourceModal's OK button has text "Delete" - find it within the modal + const modal = screen.getByText("Remove from Team").closest(".ant-modal") as HTMLElement; + const deleteConfirmButton = within(modal).getByRole("button", { name: /delete/i }); + await user.click(deleteConfirmButton); + + await waitFor(() => { + expect(mockTeamMemberDeleteCall).toHaveBeenCalledWith( + "test-token", + "team-1", + { role: "user", user_id: "user-123" } + ); + }); + }); }); diff --git a/ui/litellm-dashboard/src/components/view_users/user_info_view.tsx b/ui/litellm-dashboard/src/components/view_users/user_info_view.tsx index d0684d81e5..e5ec60642f 100644 --- a/ui/litellm-dashboard/src/components/view_users/user_info_view.tsx +++ b/ui/litellm-dashboard/src/components/view_users/user_info_view.tsx @@ -1,6 +1,9 @@ import React, { useState } from "react"; -import { Card, Text, Button, Grid, Tab, TabList, TabGroup, TabPanel, TabPanels, Title, Badge } from "@tremor/react"; -import { ArrowLeftIcon, TrashIcon, RefreshIcon } from "@heroicons/react/outline"; +import { + Card, Text, Button, Grid, Tab, TabList, TabGroup, TabPanel, TabPanels, Title, + Table, TableHead, TableBody, TableRow, TableHeaderCell, TableCell, +} from "@tremor/react"; +import { ArrowLeftIcon, TrashIcon, RefreshIcon, PlusIcon } from "@heroicons/react/outline"; import { userGetInfoV2, UserInfoV2Response, @@ -10,8 +13,12 @@ import { invitationCreateCall, getProxyBaseUrl, teamInfoCall, + teamListCall, + teamMemberAddCall, + teamMemberDeleteCall, + Member, } from "../networking"; -import { Button as AntdButton } from "antd"; +import { Button as AntdButton, Modal, Select as AntdSelect, Form, Tooltip } from "antd"; import { rolesWithWriteAccess } from "../../utils/roles"; import { UserEditView } from "../user_edit_view"; import OnboardingModal, { InvitationLink } from "../onboarding_link"; @@ -61,6 +68,15 @@ export default function UserInfoView({ const [activeTab, setActiveTab] = useState(initialTab); const [copiedStates, setCopiedStates] = useState>({}); const [isTeamsExpanded, setIsTeamsExpanded] = useState(false); + const [isAddTeamModalOpen, setIsAddTeamModalOpen] = useState(false); + const [isRemoveTeamModalOpen, setIsRemoveTeamModalOpen] = useState(false); + const [teamToRemove, setTeamToRemove] = useState(null); + const [isAddingTeam, setIsAddingTeam] = useState(false); + const [isRemovingTeam, setIsRemovingTeam] = useState(false); + const [allTeams, setAllTeams] = useState>([]); + const [selectedTeamId, setSelectedTeamId] = useState(""); + const [selectedRole, setSelectedRole] = useState("user"); + const [isLoadingTeams, setIsLoadingTeams] = useState(false); React.useEffect(() => { setBaseUrl(getProxyBaseUrl()); @@ -82,7 +98,7 @@ export default function UserInfoView({ const teamData = await teamInfoCall(accessToken, teamId); return { team_id: teamId, - team_alias: teamData?.team_alias || null, + team_alias: teamData?.team_info?.team_alias || null, }; } catch { return { team_id: teamId, team_alias: null }; @@ -111,6 +127,118 @@ export default function UserInfoView({ fetchData(); }, [accessToken, userId, userRole]); + const isProxyAdmin = userRole === "proxy_admin" || userRole === "Admin"; + + const fetchAllTeams = async () => { + if (!accessToken) return; + setIsLoadingTeams(true); + try { + const teams = await teamListCall(accessToken, null); + setAllTeams( + (teams || []).map((t: any) => ({ + team_id: t.team_id, + team_alias: t.team_alias || t.team_id, + })) + ); + } catch (error) { + console.error("Error fetching teams:", error); + } finally { + setIsLoadingTeams(false); + } + }; + + const handleOpenAddTeamModal = () => { + setSelectedTeamId(""); + setSelectedRole("user"); + setIsAddTeamModalOpen(true); + fetchAllTeams(); + }; + + const handleAddTeamSubmit = async () => { + if (!accessToken || !selectedTeamId) return; + setIsAddingTeam(true); + try { + const member: Member = { + role: selectedRole, + user_id: userId, + }; + await teamMemberAddCall(accessToken, selectedTeamId, member); + NotificationsManager.success("User added to team successfully"); + setIsAddTeamModalOpen(false); + // Re-fetch user data to refresh teams + const data = await userGetInfoV2(accessToken, userId); + setUserData(data); + if (data.teams && data.teams.length > 0) { + const teamPromises = data.teams.map(async (teamId: string) => { + try { + const teamData = await teamInfoCall(accessToken, teamId); + return { team_id: teamId, team_alias: teamData?.team_info?.team_alias || null }; + } catch { + return { team_id: teamId, team_alias: null }; + } + }); + setTeamDetails(await Promise.all(teamPromises)); + } else { + setTeamDetails([]); + } + } catch (error: any) { + console.error("Error adding user to team:", error); + NotificationsManager.fromBackend(error?.message || "Failed to add user to team"); + } finally { + setIsAddingTeam(false); + } + }; + + const handleOpenRemoveTeamModal = (team: TeamDisplayInfo) => { + setTeamToRemove(team); + setIsRemoveTeamModalOpen(true); + }; + + const handleRemoveTeamConfirm = async () => { + if (!accessToken || !teamToRemove) return; + setIsRemovingTeam(true); + try { + const member: Member = { + role: "user", + user_id: userId, + }; + await teamMemberDeleteCall(accessToken, teamToRemove.team_id, member); + NotificationsManager.success("User removed from team successfully"); + setIsRemoveTeamModalOpen(false); + setTeamToRemove(null); + // Re-fetch user data to refresh teams + const data = await userGetInfoV2(accessToken, userId); + setUserData(data); + if (data.teams && data.teams.length > 0) { + const teamPromises = data.teams.map(async (teamId: string) => { + try { + const teamData = await teamInfoCall(accessToken, teamId); + return { team_id: teamId, team_alias: teamData?.team_info?.team_alias || null }; + } catch { + return { team_id: teamId, team_alias: null }; + } + }); + setTeamDetails(await Promise.all(teamPromises)); + } else { + setTeamDetails([]); + } + } catch (error: any) { + console.error("Error removing user from team:", error); + NotificationsManager.fromBackend(error?.message || "Failed to remove user from team"); + } finally { + setIsRemovingTeam(false); + } + }; + + const handleRemoveTeamCancel = () => { + setIsRemoveTeamModalOpen(false); + setTeamToRemove(null); + }; + + const availableTeamsForAdd = allTeams.filter( + (t) => !teamDetails.some((td) => td.team_id === t.team_id) + ); + const handleResetPassword = async () => { if (!accessToken) { NotificationsManager.fromBackend("Access token not found"); @@ -312,37 +440,72 @@ export default function UserInfoView({
- Teams +
+ Teams + {isProxyAdmin && ( + + )} +
{teamDetails.length > 0 ? ( -
- {teamDetails.slice(0, isTeamsExpanded ? teamDetails.length : 20).map((team, index) => ( - - {team.team_alias || team.team_id} - - ))} - {!isTeamsExpanded && teamDetails.length > 20 && ( - setIsTeamsExpanded(true)} - > - +{teamDetails.length - 20} more - - )} - {isTeamsExpanded && teamDetails.length > 20 && ( - setIsTeamsExpanded(false)} - > - Show Less - - )} +
+ + + + Team Name + {isProxyAdmin && Actions} + + + + {teamDetails.slice(0, isTeamsExpanded ? teamDetails.length : 20).map((team) => ( + + {team.team_alias || team.team_id} + {isProxyAdmin && ( + +
) : ( No teams )} + {!isTeamsExpanded && teamDetails.length > 20 && ( + + )} + {isTeamsExpanded && teamDetails.length > 20 && ( + + )}
@@ -434,43 +597,6 @@ export default function UserInfoView({
-
- Teams -
- {teamDetails.length > 0 ? ( - <> - {teamDetails.slice(0, isTeamsExpanded ? teamDetails.length : 20).map((team, index) => ( - - {team.team_alias || team.team_id} - - ))} - {!isTeamsExpanded && teamDetails.length > 20 && ( - setIsTeamsExpanded(true)} - > - +{teamDetails.length - 20} more - - )} - {isTeamsExpanded && teamDetails.length > 20 && ( - setIsTeamsExpanded(false)} - > - Show Less - - )} - - ) : ( - No teams - )} -
-
-
Personal Models
@@ -519,6 +645,87 @@ export default function UserInfoView({ invitationLinkData={invitationLinkData} modalType="resetPassword" /> + + {/* Delete Team Member Modal */} + + + {/* Add to Team Modal */} + setIsAddTeamModalOpen(false)} + footer={null} + width={500} + maskClosable={!isAddingTeam} + > +
+ + { + const team = availableTeamsForAdd.find((t) => t.team_id === option?.value); + if (!team) return false; + return team.team_alias.toLowerCase().includes(input.toLowerCase()); + }} + loading={isLoadingTeams} + > + {availableTeamsForAdd.map((team) => ( + + {team.team_alias} + + ))} + + + + + + + + user + - Can view team info, but not manage it + + + + + admin + - Can create team keys, add members, and manage settings + + + + + +
+ + {isAddingTeam ? "Adding..." : "Add to Team"} + +
+
+
); } From b87d1f8dad80ea73b796df2f2f9fbc5b6b9eaf8d Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sat, 14 Mar 2026 09:40:00 -0700 Subject: [PATCH 064/289] [Feat] - Ishaan main merge branch (#23596) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(bedrock): respect s3_region_name for batch file uploads (#23569) * fix(bedrock): respect s3_region_name for batch file uploads (GovCloud fix) * fix: s3_region_name always wins over aws_region_name for S3 signing (Greptile feedback) * fix: _filter_headers_for_aws_signature - Bedrock KB (#23571) * fix: _filter_headers_for_aws_signature * fix: filter None header values in all post-signing re-merge paths Addresses Greptile feedback: None-valued headers were being filtered during SigV4 signing but re-merged back into the final headers dict afterward, which would cause downstream HTTP client failures. Made-with: Cursor * feat(router): tag_regex routing — route by User-Agent regex without per-developer tag config (#23594) * feat(router): add tag_regex support for header-based routing Adds a new `tag_regex` field to litellm_params that lets operators route requests based on regex patterns matched against request headers — primarily User-Agent — without requiring per-developer tag configuration. Use case: route all Claude Code traffic (User-Agent: claude-code/x.y.z) to a dedicated deployment by setting: tag_regex: - "^User-Agent: claude-code\\/" in the deployment's litellm_params. Works alongside existing `tags` routing; exact tag match takes precedence over regex match. Unmatched requests fall through to deployments tagged `default`. The matched deployment, pattern, and user_agent are recorded in `metadata["tag_routing"]` so they flow through to SpendLogs automatically. * fix(tag_regex): address backwards-compat, metadata overwrite, and warning noise Three issues from code review: 1. Backwards-compat: `has_tag_filter` was widened to activate on any non-empty User-Agent, which would raise ValueError for existing deployments using plain tags without a `default` fallback. Fix: only activate header-based regex filtering when at least one candidate deployment has `tag_regex` configured. 2. Metadata overwrite: `metadata["tag_routing"]` was overwritten for every matching deployment in the loop, leaving inaccurate provenance when multiple deployments match. Fix: write only for the first match. 3. Warning noise: an invalid regex pattern logged one warning per header string rather than once per pattern. Fix: compile first (catching re.error once), then iterate over header strings. Also adds two new tests covering these cases, and adds docs page for tag_regex routing with a Claude Code walk-through. * refactor(tag_regex): remove unnecessary _healthy_list copy * docs: merge tag_regex section into tag_routing.md, remove standalone page - Add ## Regex-based tag routing (tag_regex) section to existing tag_routing.md instead of a separate page - Remove tag_regex_routing.md standalone doc (odd UX to have a separate page for a sub-feature) - Remove proxy/tag_regex_routing from sidebars.js - Add match_any=False debug warning in tag_based_routing.py when regex routing fires under strict mode (regex always uses OR semantics) * fix(tag_regex): address greptile review - security docs, strict-mode enforcement, validation order - Strengthen security note in tag_routing.md: explicitly state User-Agent is client-supplied and can be set to any value; frame tag_regex as a traffic classification hint, not an access-control mechanism - Move tag_regex startup validation before _add_deployment() so an invalid pattern never leaves partial router state - Enforce match_any=False strict-tag policy: when a deployment has both tags and tag_regex and the strict tag check fails, skip the regex fallback rather than silently bypassing the operator's intent - Extract per-deployment match logic into _match_deployment() helper to keep get_deployments_for_tag() readable - Add two new tests: strict-mode blocks regex fallback, regex-only deployment still matches under match_any=False * fix(ci): apply Black formatting to 14 files and stabilize flaky caplog tests - Run Black formatter on 14 files that were failing the lint check - Replace caplog-based assertions in TestAliasConflicts with unittest.mock.patch on verbose_logger.warning for xdist compatibility - The caplog fixture can produce empty text in pytest-xdist workers in certain CI environments, causing flaky test failures Co-authored-by: Ishaan Jaff --------- Co-authored-by: Cursor Agent Co-authored-by: Ishaan Jaff --- docs/my-website/docs/proxy/tag_routing.md | 100 +++++ .../transformation.py | 5 +- .../prompt_templates/factory.py | 4 +- .../llms/anthropic/files/transformation.py | 4 +- litellm/llms/base_llm/base_model_iterator.py | 8 +- litellm/llms/bedrock/base_aws_llm.py | 8 +- litellm/llms/bedrock/files/transformation.py | 16 +- .../image_edit/transformation.py | 4 +- .../perplexity/responses/transformation.py | 4 +- .../mcp_server/rest_endpoints.py | 24 +- litellm/proxy/auth/user_api_key_auth.py | 6 +- .../guardrails/guardrail_hooks/presidio.py | 8 +- .../key_management_endpoints.py | 8 +- litellm/proxy/management_endpoints/ui_sso.py | 24 +- litellm/proxy/utils.py | 2 +- .../transformation.py | 4 +- litellm/router.py | 17 +- litellm/router_strategy/tag_based_routing.py | 143 ++++++- litellm/types/router.py | 7 + .../test_bedrock_files_transformation.py | 158 ++++++++ .../llms/bedrock/test_base_aws_llm.py | 82 +++- .../test_router_tag_regex_routing.py | 375 ++++++++++++++++++ tests/test_litellm/test_model_cost_aliases.py | 21 +- 23 files changed, 959 insertions(+), 73 deletions(-) create mode 100644 tests/test_litellm/router_strategy/test_router_tag_regex_routing.py diff --git a/docs/my-website/docs/proxy/tag_routing.md b/docs/my-website/docs/proxy/tag_routing.md index 399c43d2c0..a1ae52e5e4 100644 --- a/docs/my-website/docs/proxy/tag_routing.md +++ b/docs/my-website/docs/proxy/tag_routing.md @@ -209,6 +209,106 @@ Expect to see the following response header when this works x-litellm-model-id: default-model ``` +## Regex-based tag routing (`tag_regex`) + +Use `tag_regex` to route requests based on regex patterns matched against request headers, without requiring clients to pass a tag explicitly. This is useful when clients already send a recognisable header, such as `User-Agent`. + +**Use case: route all Claude Code traffic to dedicated AWS accounts** + +Claude Code always sends `User-Agent: claude-code/`. With `tag_regex` you can route that traffic to a dedicated deployment automatically — no per-developer configuration needed. + +### 1. Config + +```yaml +model_list: + # Claude Code traffic → dedicated deployment, matched by User-Agent + - model_name: claude-sonnet + litellm_params: + model: bedrock/converse/anthropic-claude-sonnet-4-6 + aws_region_name: us-east-1 + aws_role_name: arn:aws:iam::111122223333:role/LiteLLMClaudeCode + tag_regex: + - "^User-Agent: claude-code\\/" # matches claude-code/1.x, 2.x, etc. + model_info: + id: claude-code-deployment + + # All other traffic falls back to the default deployment + - model_name: claude-sonnet + litellm_params: + model: bedrock/converse/anthropic-claude-sonnet-4-6 + aws_region_name: us-east-1 + aws_role_name: arn:aws:iam::444455556666:role/LiteLLMDefault + tags: + - default + model_info: + id: regular-deployment + +router_settings: + enable_tag_filtering: true + tag_filtering_match_any: true + +general_settings: + master_key: sk-1234 +``` + +### 2. Verify routing + +Claude Code sets `User-Agent: claude-code/` automatically — no client config needed: + +```shell +# Claude Code request (User-Agent set automatically by Claude Code) +curl http://localhost:4000/v1/chat/completions \ + -H "Authorization: Bearer sk-1234" \ + -H "User-Agent: claude-code/1.2.3" \ + -d '{"model": "claude-sonnet", "messages": [{"role": "user", "content": "hi"}]}' +# → x-litellm-model-id: claude-code-deployment + +# Any other client (no matching User-Agent) → default deployment +curl http://localhost:4000/v1/chat/completions \ + -H "Authorization: Bearer sk-1234" \ + -d '{"model": "claude-sonnet", "messages": [{"role": "user", "content": "hi"}]}' +# → x-litellm-model-id: regular-deployment +``` + +### How matching works + +| Priority | Condition | Result | +|----------|-----------|--------| +| 1 | Request has `tags` AND deployment has `tags` | Exact tag match (respects `match_any` setting) | +| 2 | Deployment has `tag_regex` AND request has a `User-Agent` | Regex match (always OR logic — any pattern match suffices) | +| 3 | Deployment has `tags: [default]` | Default fallback | +| 4 | No default set | All healthy deployments returned | + +`tag_regex` always uses OR semantics — `tag_filtering_match_any=False` applies only to exact tag matching, not to regex patterns. + +### Observability + +When a regex matches, `tag_routing` is written into request metadata and flows to SpendLogs: + +```json +{ + "tag_routing": { + "matched_via": "tag_regex", + "matched_value": "^User-Agent: claude-code\\/", + "user_agent": "claude-code/1.2.3", + "request_tags": [] + } +} +``` + +### Security note + +:::caution + +**`User-Agent` is a client-supplied header and can be set to any value.** Any API consumer can send `User-Agent: claude-code/1.0` regardless of whether they are actually using Claude Code. + +Do not rely on `tag_regex` routing to enforce access controls or spend limits — use [team/key-based routing](./users) for that. `tag_regex` is a **traffic classification hint** (useful for billing visibility, capacity planning, and routing convenience), not a security boundary. + +::: + + +--- + ## ✨ Team based tag routing (Enterprise) LiteLLM Proxy supports team-based tag routing, allowing you to associate specific tags with teams and route requests accordingly. Example **Team A can access gpt-4 deployment A, Team B can access gpt-4 deployment B** (LLM Access Control For Teams) diff --git a/litellm/completion_extras/litellm_responses_transformation/transformation.py b/litellm/completion_extras/litellm_responses_transformation/transformation.py index 4b31bcfc28..53ffd3647b 100644 --- a/litellm/completion_extras/litellm_responses_transformation/transformation.py +++ b/litellm/completion_extras/litellm_responses_transformation/transformation.py @@ -398,6 +398,7 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): ResponseOutputMessage, ResponseReasoningItem, ) + try: from openai.types.responses.response_output_item import ( ResponseApplyPatchToolCall, @@ -460,7 +461,9 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): accumulated_tool_calls.append(tool_call_dict) tool_call_index += 1 - elif ResponseApplyPatchToolCall is not None and isinstance(item, ResponseApplyPatchToolCall): + elif ResponseApplyPatchToolCall is not None and isinstance( + item, ResponseApplyPatchToolCall + ): from litellm.responses.litellm_completion_transformation.transformation import ( LiteLLMCompletionResponsesConfig, ) diff --git a/litellm/litellm_core_utils/prompt_templates/factory.py b/litellm/litellm_core_utils/prompt_templates/factory.py index ea1f81f9b3..47272b38ad 100644 --- a/litellm/litellm_core_utils/prompt_templates/factory.py +++ b/litellm/litellm_core_utils/prompt_templates/factory.py @@ -2680,7 +2680,9 @@ def anthropic_messages_pt( # noqa: PLR0915 _content_is_list = "content" in assistant_content_block and isinstance( assistant_content_block["content"], list ) - _content_list = assistant_content_block.get("content") if _content_is_list else None + _content_list = ( + assistant_content_block.get("content") if _content_is_list else None + ) _list_has_thinking = False if _content_is_list and _content_list is not None: for _item in _content_list: diff --git a/litellm/llms/anthropic/files/transformation.py b/litellm/llms/anthropic/files/transformation.py index 0691742bb0..98a548a136 100644 --- a/litellm/llms/anthropic/files/transformation.py +++ b/litellm/llms/anthropic/files/transformation.py @@ -79,7 +79,9 @@ class AnthropicFilesConfig(BaseFilesConfig): return AnthropicError( status_code=status_code, message=error_message, - headers=cast(httpx.Headers, headers) if isinstance(headers, dict) else headers, + headers=cast(httpx.Headers, headers) + if isinstance(headers, dict) + else headers, ) def validate_environment( diff --git a/litellm/llms/base_llm/base_model_iterator.py b/litellm/llms/base_llm/base_model_iterator.py index 18551d9714..cf1fd6f786 100644 --- a/litellm/llms/base_llm/base_model_iterator.py +++ b/litellm/llms/base_llm/base_model_iterator.py @@ -144,9 +144,7 @@ class BaseModelResponseIterator: # Skip empty lines (common in SSE streams between events). # Only apply to str chunks — non-string objects (e.g. Pydantic # BaseModel events from the Responses API) must pass through. - if isinstance(str_line, str) and ( - not str_line or not str_line.strip() - ): + if isinstance(str_line, str) and (not str_line or not str_line.strip()): continue # chunk is a str at this point @@ -184,9 +182,7 @@ class BaseModelResponseIterator: # Skip empty lines (common in SSE streams between events). # Only apply to str chunks — non-string objects (e.g. Pydantic # BaseModel events from the Responses API) must pass through. - if isinstance(str_line, str) and ( - not str_line or not str_line.strip() - ): + if isinstance(str_line, str) and (not str_line or not str_line.strip()): continue # chunk is a str at this point diff --git a/litellm/llms/bedrock/base_aws_llm.py b/litellm/llms/bedrock/base_aws_llm.py index 697fccd268..b159d62367 100644 --- a/litellm/llms/bedrock/base_aws_llm.py +++ b/litellm/llms/bedrock/base_aws_llm.py @@ -1268,7 +1268,8 @@ class BaseAWSLLM: # Add back all original headers (including forwarded ones) after signature calculation for header_name, header_value in headers.items(): - request.headers[header_name] = header_value + if header_value is not None: + request.headers[header_name] = header_value if ( extra_headers is not None and "Authorization" in extra_headers @@ -1298,6 +1299,8 @@ class BaseAWSLLM: } for header_name, header_value in headers.items(): + if header_value is None: + continue header_lower = header_name.lower() if ( header_lower in aws_headers @@ -1393,7 +1396,8 @@ class BaseAWSLLM: # Add back original headers after signing. Only headers in SignedHeaders # are integrity-protected; forwarded headers (x-forwarded-*) must remain unsigned. for header_name, header_value in headers.items(): - request_headers_dict[header_name] = header_value + if header_value is not None: + request_headers_dict[header_name] = header_value if ( headers is not None and "Authorization" in headers ): # prevent sigv4 from overwriting the auth header diff --git a/litellm/llms/bedrock/files/transformation.py b/litellm/llms/bedrock/files/transformation.py index 096371749b..3007b54808 100644 --- a/litellm/llms/bedrock/files/transformation.py +++ b/litellm/llms/bedrock/files/transformation.py @@ -173,7 +173,12 @@ class BedrockFilesConfig(BaseAWSLLM, BaseFilesConfig): "S3 bucket_name is required. Set 's3_bucket_name' in litellm_params or AWS_S3_BUCKET_NAME env var" ) - aws_region_name = self._get_aws_region_name(optional_params, model) + s3_region_name = litellm_params.get("s3_region_name") or optional_params.get( + "s3_region_name" + ) + aws_region_name = s3_region_name or self._get_aws_region_name( + optional_params, model + ) file_data = data.get("file") purpose = data.get("purpose") @@ -398,6 +403,15 @@ class BedrockFilesConfig(BaseAWSLLM, BaseFilesConfig): data=create_file_data, ) + # s3_region_name always wins for S3 operations (same priority as in + # get_complete_file_url above). Overwrite aws_region_name unconditionally + # so the SigV4 region matches the URL region, avoiding SignatureDoesNotMatch. + s3_region_name = litellm_params.get("s3_region_name") or optional_params.get( + "s3_region_name" + ) + if s3_region_name: + optional_params = {**optional_params, "aws_region_name": s3_region_name} + # Sign the request and return a pre-signed request object signed_headers, signed_body = self._sign_s3_request( content=file_content, diff --git a/litellm/llms/black_forest_labs/image_edit/transformation.py b/litellm/llms/black_forest_labs/image_edit/transformation.py index 63413787c0..c6d8e8298e 100644 --- a/litellm/llms/black_forest_labs/image_edit/transformation.py +++ b/litellm/llms/black_forest_labs/image_edit/transformation.py @@ -201,7 +201,9 @@ class BlackForestLabsImageEditConfig(BaseImageEditConfig): return image elif isinstance(image, list): # If it's a list, take the first image - return self._read_image_bytes(image[0], depth=depth + 1, max_depth=max_depth) + return self._read_image_bytes( + image[0], depth=depth + 1, max_depth=max_depth + ) elif isinstance(image, str): if image.startswith(("http://", "https://")): # Download image from URL diff --git a/litellm/llms/perplexity/responses/transformation.py b/litellm/llms/perplexity/responses/transformation.py index c7ec131356..e09dc01f1c 100644 --- a/litellm/llms/perplexity/responses/transformation.py +++ b/litellm/llms/perplexity/responses/transformation.py @@ -71,7 +71,9 @@ class PerplexityResponsesConfig(OpenAIResponsesAPIConfig): result: List[Any] = [] for item in input: if isinstance(item, dict) and "type" not in item: - new_item = dict(item) # convert to plain dict to avoid TypedDict checking + new_item = dict( + item + ) # convert to plain dict to avoid TypedDict checking new_item["type"] = "message" result.append(new_item) else: diff --git a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py index 307caa2fbc..1bec0d23c9 100644 --- a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py +++ b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py @@ -378,9 +378,7 @@ if MCP_AVAILABLE: # Resolve a server name to its UUID if needed _name_resolved = None if server_id not in allowed_server_ids: - _name_resolved = global_mcp_server_manager.get_mcp_server_by_name( - server_id - ) + _name_resolved = global_mcp_server_manager.get_mcp_server_by_name(server_id) if _name_resolved is not None and _name_resolved.server_id in set( allowed_server_ids ): @@ -442,9 +440,7 @@ if MCP_AVAILABLE: extra_headers=user_oauth_extra_headers, ) except Exception as e: - verbose_logger.exception( - f"Error getting tools from {server.name}: {e}" - ) + verbose_logger.exception(f"Error getting tools from {server.name}: {e}") return { "tools": [], "error": "server_error", @@ -473,7 +469,9 @@ if MCP_AVAILABLE: _name_resolved = None if server_id not in allowed_server_ids: _name_resolved = global_mcp_server_manager.get_mcp_server_by_name(server_id) - if _name_resolved is not None and _name_resolved.server_id in set(allowed_server_ids): + if _name_resolved is not None and _name_resolved.server_id in set( + allowed_server_ids + ): server_id = _name_resolved.server_id if server_id not in allowed_server_ids: @@ -518,7 +516,9 @@ if MCP_AVAILABLE: server_auth_header = _get_server_auth_header( server, mcp_server_auth_headers, mcp_auth_header ) - user_oauth_extra_headers = await _get_user_oauth_extra_headers(server, user_api_key_dict) + user_oauth_extra_headers = await _get_user_oauth_extra_headers( + server, user_api_key_dict + ) try: list_tools_result = await _get_tools_for_single_server( @@ -529,9 +529,7 @@ if MCP_AVAILABLE: extra_headers=user_oauth_extra_headers, ) except Exception as e: - verbose_logger.exception( - f"Error getting tools from {server.name}: {e}" - ) + verbose_logger.exception(f"Error getting tools from {server.name}: {e}") return { "tools": [], "error": "server_error", @@ -905,7 +903,9 @@ if MCP_AVAILABLE: try: client_id, client_secret, scopes = _extract_credentials(request) - _oauth2_flow: Optional[Literal["client_credentials", "authorization_code"]] = ( + _oauth2_flow: Optional[ + Literal["client_credentials", "authorization_code"] + ] = ( "client_credentials" if client_id and client_secret and request.token_url else None diff --git a/litellm/proxy/auth/user_api_key_auth.py b/litellm/proxy/auth/user_api_key_auth.py index c4adecdab4..376048e7a1 100644 --- a/litellm/proxy/auth/user_api_key_auth.py +++ b/litellm/proxy/auth/user_api_key_auth.py @@ -64,7 +64,11 @@ from litellm.proxy.common_utils.http_parsing_utils import ( populate_request_with_path_params, ) from litellm.proxy.common_utils.realtime_utils import _realtime_request_body -from litellm.proxy.utils import PrismaClient, ProxyLogging, normalize_route_for_root_path +from litellm.proxy.utils import ( + PrismaClient, + ProxyLogging, + normalize_route_for_root_path, +) from litellm.secret_managers.main import get_secret_bool from litellm.types.services import ServiceTypes diff --git a/litellm/proxy/guardrails/guardrail_hooks/presidio.py b/litellm/proxy/guardrails/guardrail_hooks/presidio.py index 48ffab39bd..0f4ebbd488 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/presidio.py +++ b/litellm/proxy/guardrails/guardrail_hooks/presidio.py @@ -106,9 +106,13 @@ class _OPTIONAL_PresidioPIIMasking(CustomGuardrail): if (self.output_parse_pii or self.apply_to_output) and not logging_only: current_hook = self.event_hook if isinstance(current_hook, str) and current_hook != "post_call": - self.event_hook = cast(List[GuardrailEventHooks], [current_hook, "post_call"]) + self.event_hook = cast( + List[GuardrailEventHooks], [current_hook, "post_call"] + ) elif isinstance(current_hook, list) and "post_call" not in current_hook: - self.event_hook = cast(List[GuardrailEventHooks], current_hook + ["post_call"]) + self.event_hook = cast( + List[GuardrailEventHooks], current_hook + ["post_call"] + ) self.pii_entities_config: Dict[Union[PiiEntityType, str], PiiAction] = ( pii_entities_config or {} ) diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index db1a089ff7..3049a9f43c 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -1838,9 +1838,7 @@ async def _validate_update_key_data( # Check team limits if key has a team_id (from request or existing key) team_obj: Optional[LiteLLM_TeamTableCachedObj] = None - _team_id_to_check = data.team_id or getattr( - existing_key_row, "team_id", None - ) + _team_id_to_check = data.team_id or getattr(existing_key_row, "team_id", None) if _team_id_to_check is not None: team_obj = await get_team_object( team_id=_team_id_to_check, @@ -1910,9 +1908,7 @@ async def _validate_update_key_data( if team_obj is None: raise HTTPException( status_code=500, - detail={ - "error": "Team object not found for team change validation" - }, + detail={"error": "Team object not found for team change validation"}, ) await validate_key_team_change( key=existing_key_row, diff --git a/litellm/proxy/management_endpoints/ui_sso.py b/litellm/proxy/management_endpoints/ui_sso.py index d55aa85a9b..daf1d6f131 100644 --- a/litellm/proxy/management_endpoints/ui_sso.py +++ b/litellm/proxy/management_endpoints/ui_sso.py @@ -846,12 +846,16 @@ async def get_generic_sso_response( verbose_proxy_logger.debug("calling generic_sso.verify_and_process") additional_generic_sso_headers_dict = _parse_generic_sso_headers() - code_verifier: Optional[str] = None # assigned inside try; initialized for type tracking + code_verifier: Optional[ + str + ] = None # assigned inside try; initialized for type tracking try: - token_exchange_params = await SSOAuthenticationHandler.prepare_token_exchange_parameters( - request=request, - generic_include_client_id=generic_include_client_id, + token_exchange_params = ( + await SSOAuthenticationHandler.prepare_token_exchange_parameters( + request=request, + generic_include_client_id=generic_include_client_id, + ) ) # Extract code_verifier (and the cache key for deferred deletion) before calling fastapi-sso @@ -915,7 +919,9 @@ async def get_generic_sso_response( # Assign directly rather than relying on nonlocal mutation so that Pyright # can track that received_response is non-None from this point on. received_response = { - k: v for k, v in combined_response.items() if k not in _OAUTH_TOKEN_FIELDS + k: v + for k, v in combined_response.items() + if k not in _OAUTH_TOKEN_FIELDS } # In the PKCE path verify_and_process is skipped, so generic_sso.access_token # is never set. Read the token directly from the exchange response instead so @@ -2598,7 +2604,9 @@ class SSOAuthenticationHandler: state, ) else: - verbose_proxy_logger.debug("PKCE code_verifier retrieved from cache") + verbose_proxy_logger.debug( + "PKCE code_verifier retrieved from cache" + ) elif isinstance(cached_data, str): # Handle legacy format (plain string) for backward compatibility code_verifier = cached_data @@ -2647,7 +2655,9 @@ class SSOAuthenticationHandler: In strict mode (PKCE_STRICT_CACHE_MISS=true) raises ProxyException. Otherwise logs a warning and returns (token exchange proceeds without verifier). """ - active_cache = redis_usage_cache if redis_usage_cache is not None else user_api_key_cache + active_cache = ( + redis_usage_cache if redis_usage_cache is not None else user_api_key_cache + ) strict_cache_miss = ( os.getenv("PKCE_STRICT_CACHE_MISS", "false").lower() == "true" ) diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index b9a1bfb906..01a0f55aac 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -5233,7 +5233,7 @@ def normalize_route_for_root_path(route: str) -> Optional[str]: root_path = get_server_root_path() if root_path and root_path != "/": if route.startswith(root_path + "/"): - return route[len(root_path):] + return route[len(root_path) :] return None return route diff --git a/litellm/responses/litellm_completion_transformation/transformation.py b/litellm/responses/litellm_completion_transformation/transformation.py index e9333c7dfa..71fa88fb75 100644 --- a/litellm/responses/litellm_completion_transformation/transformation.py +++ b/litellm/responses/litellm_completion_transformation/transformation.py @@ -415,7 +415,9 @@ class LiteLLMCompletionResponsesConfig: if isinstance(new_msg, dict) else getattr(new_msg, "tool_calls", None) ) - new_tcs: list = _raw_tcs if isinstance(_raw_tcs, list) else [] + new_tcs: list = ( + _raw_tcs if isinstance(_raw_tcs, list) else [] + ) for tc in new_tcs: LiteLLMCompletionResponsesConfig._add_tool_call_to_assistant( last_msg, tc diff --git a/litellm/router.py b/litellm/router.py index a63d5d91d1..295e937bfb 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -14,6 +14,7 @@ import hashlib import inspect import json import logging +import re import threading import time import traceback @@ -1551,7 +1552,9 @@ class Router: # Drain any fire-and-forget tasks (e.g. alerting hooks) # scheduled via asyncio.create_task during acompletion. pending = asyncio.all_tasks() - pending.discard(asyncio.current_task()) + current = asyncio.current_task() + if current is not None: + pending.discard(current) if pending: await asyncio.gather(*pending, return_exceptions=True) @@ -6542,6 +6545,18 @@ class Router: ) return None + # Validate tag_regex patterns BEFORE adding the deployment so we never + # have partially-initialised router state if a pattern is invalid. + _tag_regex = deployment.litellm_params.get("tag_regex") or [] + for pattern in _tag_regex: + try: + re.compile(pattern) + except re.error as exc: + raise ValueError( + f"Invalid regex in tag_regex for model '{deployment.model_name}': " + f"{pattern!r} — {exc}" + ) from exc + deployment = self._add_deployment(deployment=deployment) model = deployment.to_json(exclude_none=True) diff --git a/litellm/router_strategy/tag_based_routing.py b/litellm/router_strategy/tag_based_routing.py index e7156bf128..1309846c10 100644 --- a/litellm/router_strategy/tag_based_routing.py +++ b/litellm/router_strategy/tag_based_routing.py @@ -6,6 +6,7 @@ Use this to route requests between Teams - If no default_deployments are set, return all deployments """ +import re from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Union from litellm._logging import verbose_logger @@ -19,6 +20,29 @@ else: LitellmRouter = Any +def _is_valid_deployment_tag_regex( + tag_regexes: List[str], + header_strings: List[str], +) -> Optional[str]: + """ + Test compiled regex patterns against "Header-Name: value" strings. + + Returns the first matching pattern string, or None if nothing matches. + Compiles each pattern once (re's LRU cache) and logs invalid patterns once + per pattern, not once per header string. + """ + for pattern in tag_regexes: + try: + compiled = re.compile(pattern) + except re.error: + verbose_logger.warning("tag_regex: invalid pattern %r — skipping", pattern) + continue + for header_str in header_strings: + if compiled.search(header_str): + return pattern + return None + + def is_valid_deployment_tag( deployment_tags: List[str], request_tags: List[str], match_any: bool = True ) -> bool: @@ -47,6 +71,54 @@ def is_valid_deployment_tag( return False +def _match_deployment( + deployment: Any, + request_tags: Optional[List[str]], + header_strings: List[str], + match_any: bool, +) -> Optional[Dict[str, str]]: + """ + Determine whether *deployment* matches the current request. + + Returns {"matched_via": ..., "matched_value": ...} if the deployment + should be included, or None if it should be excluded. + + Priority: + 1. Exact tag match (respects match_any semantics). + 2. Regex match — skipped when match_any=False and the tag check already + ran and failed, so the regex cannot override strict-tag policy. + """ + litellm_params = deployment.get("litellm_params", {}) + deployment_tags: Optional[List[str]] = litellm_params.get("tags") + deployment_tag_regex: Optional[List[str]] = litellm_params.get("tag_regex") + + # 1. Exact tag match (existing behaviour). + if deployment_tags and request_tags: + if is_valid_deployment_tag(deployment_tags, request_tags, match_any): + matched_value = next( + (t for t in deployment_tags if t in set(request_tags)), + deployment_tags[0], + ) + return {"matched_via": "tags", "matched_value": matched_value} + + # 2. Regex match against request headers. + # When match_any=False and the deployment has both plain tags and tag_regex, + # the strict tag check has already failed (step 1 returned None). Allow + # the regex to fire only when the deployment has NO plain tags, so we never + # use regex as a backdoor around the operator's strict-tag policy. + strict_tag_check_failed = ( + not match_any and bool(deployment_tags) and bool(request_tags) + ) + if deployment_tag_regex and header_strings and not strict_tag_check_failed: + regex_match = _is_valid_deployment_tag_regex( + deployment_tag_regex, header_strings + ) + if regex_match is not None: + return {"matched_via": "tag_regex", "matched_value": regex_match} + + return None + + async def get_deployments_for_tag( llm_router_instance: LitellmRouter, model: str, # used to raise the correct error @@ -83,30 +155,63 @@ async def get_deployments_for_tag( request_tags = metadata.get("tags") match_any = llm_router_instance.tag_filtering_match_any - new_healthy_deployments = [] - default_deployments = [] - if request_tags: - verbose_logger.debug( - "get_deployments_for_tag routing: router_keys: %s", request_tags - ) - # example this can be router_keys=["free", "custom"] - for deployment in healthy_deployments: - deployment_litellm_params = deployment.get("litellm_params") - deployment_tags = deployment_litellm_params.get("tags") + # Build header strings for regex matching from what the proxy already stores. + # Currently we match against User-Agent; format matches "^User-Agent: claude-code/..." + user_agent = metadata.get("user_agent", "") + header_strings: List[str] = [f"User-Agent: {user_agent}"] if user_agent else [] - verbose_logger.debug( - "deployment: %s, deployment_router_keys: %s", - deployment, - deployment_tags, + new_healthy_deployments: List[Any] = [] + default_deployments: List[Any] = [] + + # Only activate header-based regex filtering when at least one deployment in + # the candidate set has tag_regex configured. This preserves existing + # behaviour for operators who use plain tags: a request that carries a + # User-Agent (all proxy requests do) but targets deployments with no + # tag_regex will continue to use the original tag-only code path. + has_regex_deployments = any( + d.get("litellm_params", {}).get("tag_regex") for d in healthy_deployments + ) + has_tag_filter = bool(request_tags) or ( + bool(header_strings) and has_regex_deployments + ) + if has_tag_filter: + verbose_logger.debug( + "get_deployments_for_tag routing: request_tags=%s user_agent=%s", + request_tags, + user_agent, + ) + for deployment in healthy_deployments: + deployment_tags = deployment.get("litellm_params", {}).get("tags") + + match_result = _match_deployment( + deployment=deployment, + request_tags=request_tags, + header_strings=header_strings, + match_any=match_any, ) - if deployment_tags is None: - continue - - if is_valid_deployment_tag(deployment_tags, request_tags, match_any): + if match_result is not None: + verbose_logger.debug( + "tag routing match: deployment=%s matched_via=%s matched_value=%s", + deployment.get("model_name"), + match_result["matched_via"], + match_result["matched_value"], + ) + # Record provenance in metadata so it flows to SpendLogs. + # Written only for the first match — load balancer selects one + # deployment from new_healthy_deployments, so overwriting on + # subsequent matches would produce misleading observability data. + if "tag_routing" not in metadata: + metadata["tag_routing"] = { + "matched_deployment": deployment.get("model_name"), + "matched_via": match_result["matched_via"], + "matched_value": match_result["matched_value"], + "request_tags": request_tags or [], + "user_agent": user_agent, + } new_healthy_deployments.append(deployment) - if "default" in deployment_tags: + if deployment_tags and "default" in deployment_tags: default_deployments.append(deployment) if len(new_healthy_deployments) == 0 and len(default_deployments) == 0: diff --git a/litellm/types/router.py b/litellm/types/router.py index f0c1ea5e32..e8ff2115ff 100644 --- a/litellm/types/router.py +++ b/litellm/types/router.py @@ -198,6 +198,11 @@ class GenericLiteLLMParams(CredentialLiteLLMParams, CustomPricingLiteLLMParams): model_info: Optional[Dict] = None mock_response: Optional[Union[str, ModelResponse, Exception, Any]] = None + # tag-based routing + tags: Optional[List[str]] = None + # regex patterns matched against request headers for tag routing + tag_regex: Optional[List[str]] = None + # auto-router params auto_router_config_path: Optional[str] = None auto_router_config: Optional[str] = None @@ -334,6 +339,8 @@ class LiteLLMParamsTypedDict(TypedDict, total=False): # routing params # use this for tag-based routing tags: Optional[List[str]] + # regex patterns matched against request headers (e.g. "^User-Agent:\\s*claude-code\\/") + tag_regex: Optional[List[str]] # deployment budgets max_budget: Optional[float] diff --git a/tests/test_litellm/llms/bedrock/files/test_bedrock_files_transformation.py b/tests/test_litellm/llms/bedrock/files/test_bedrock_files_transformation.py index 88cac84e43..40a17c1211 100644 --- a/tests/test_litellm/llms/bedrock/files/test_bedrock_files_transformation.py +++ b/tests/test_litellm/llms/bedrock/files/test_bedrock_files_transformation.py @@ -272,6 +272,164 @@ class TestBedrockFilesTransformation: assert "messages" in model_input assert "max_tokens" in model_input + def test_get_complete_file_url_respects_s3_region_name(self): + """ + s3_region_name in litellm_params must be used when building the S3 URL. + Previously the code fell back to us-west-2 even when s3_region_name was set, + breaking GovCloud (us-gov-west-1) deployments. + """ + from litellm.llms.bedrock.files.transformation import BedrockFilesConfig + + config = BedrockFilesConfig() + + jsonl_content = json.dumps( + { + "custom_id": "req-1", + "method": "POST", + "url": "/v1/chat/completions", + "body": { + "model": "bedrock/amazon.nova-pro-v1:0", + "messages": [{"role": "user", "content": "Hello"}], + "max_tokens": 10, + }, + } + ).encode() + + create_file_data = { + "file": ("batch.jsonl", jsonl_content, "application/jsonl"), + "purpose": "batch", + } + + litellm_params = { + "s3_bucket_name": "litellm-batch-352026", + "s3_region_name": "us-gov-west-1", + } + + url = config.get_complete_file_url( + api_base=None, + api_key=None, + model="amazon.nova-pro-v1:0", + optional_params={}, + litellm_params=litellm_params, + data=create_file_data, + ) + + assert "us-gov-west-1" in url, ( + f"Expected us-gov-west-1 in URL but got: {url}" + ) + assert "us-west-2" not in url, ( + f"us-west-2 must not appear when s3_region_name is set, got: {url}" + ) + assert "litellm-batch-352026" in url + + def test_transform_create_file_request_injects_s3_region_for_signing(self): + """ + When s3_region_name is provided, transform_create_file_request must pass + that region to _sign_s3_request so SigV4 signatures use the correct region. + """ + from unittest.mock import patch + + from litellm.llms.bedrock.files.transformation import BedrockFilesConfig + + config = BedrockFilesConfig() + + jsonl_content = json.dumps( + { + "custom_id": "req-1", + "method": "POST", + "url": "/v1/chat/completions", + "body": { + "model": "bedrock/amazon.nova-pro-v1:0", + "messages": [{"role": "user", "content": "Hello"}], + "max_tokens": 10, + }, + } + ).encode() + + create_file_data = { + "file": ("batch.jsonl", jsonl_content, "application/jsonl"), + "purpose": "batch", + } + + litellm_params = { + "s3_bucket_name": "litellm-batch-352026", + "s3_region_name": "us-gov-west-1", + } + + captured_optional_params: dict = {} + + def fake_sign(content, api_base, optional_params): + captured_optional_params.update(optional_params) + return {"Authorization": "fake"}, content + + with patch.object(config, "_sign_s3_request", side_effect=fake_sign): + config.transform_create_file_request( + model="amazon.nova-pro-v1:0", + create_file_data=create_file_data, + optional_params={}, + litellm_params=litellm_params, + ) + + assert captured_optional_params.get("aws_region_name") == "us-gov-west-1", ( + "s3_region_name must be forwarded as aws_region_name for SigV4 signing" + ) + + def test_s3_region_name_wins_over_aws_region_name_for_signing(self): + """ + When both s3_region_name and aws_region_name are set to different values, + s3_region_name must win for signing (same as for the URL). Otherwise the + SigV4 signature would be computed against a different region than the URL, + causing SignatureDoesNotMatch from AWS. + """ + from unittest.mock import patch + + from litellm.llms.bedrock.files.transformation import BedrockFilesConfig + + config = BedrockFilesConfig() + + jsonl_content = json.dumps( + { + "custom_id": "req-1", + "method": "POST", + "url": "/v1/chat/completions", + "body": { + "model": "bedrock/amazon.nova-pro-v1:0", + "messages": [{"role": "user", "content": "Hello"}], + "max_tokens": 10, + }, + } + ).encode() + + create_file_data = { + "file": ("batch.jsonl", jsonl_content, "application/jsonl"), + "purpose": "batch", + } + + litellm_params = { + "s3_bucket_name": "litellm-batch-352026", + "s3_region_name": "us-gov-west-1", + } + # aws_region_name set to something different — s3_region_name must still win + optional_params = {"aws_region_name": "us-east-1"} + + captured_optional_params: dict = {} + + def fake_sign(content, api_base, optional_params): + captured_optional_params.update(optional_params) + return {"Authorization": "fake"}, content + + with patch.object(config, "_sign_s3_request", side_effect=fake_sign): + config.transform_create_file_request( + model="amazon.nova-pro-v1:0", + create_file_data=create_file_data, + optional_params=optional_params, + litellm_params=litellm_params, + ) + + assert captured_optional_params.get("aws_region_name") == "us-gov-west-1", ( + "s3_region_name must override aws_region_name for SigV4 signing" + ) + def test_openai_passthrough_still_works(self): """ Regression test: ensure OpenAI-compatible models (e.g. gpt-oss) diff --git a/tests/test_litellm/llms/bedrock/test_base_aws_llm.py b/tests/test_litellm/llms/bedrock/test_base_aws_llm.py index 18fc7c6173..29ed345d2d 100644 --- a/tests/test_litellm/llms/bedrock/test_base_aws_llm.py +++ b/tests/test_litellm/llms/bedrock/test_base_aws_llm.py @@ -14,15 +14,16 @@ from datetime import datetime, timedelta, timezone from typing import Any, Dict from unittest.mock import MagicMock, patch +from botocore.awsrequest import AWSPreparedRequest, AWSRequest from botocore.credentials import Credentials -from botocore.awsrequest import AWSRequest, AWSPreparedRequest + import litellm +from litellm.caching.caching import DualCache from litellm.llms.bedrock.base_aws_llm import ( AwsAuthError, BaseAWSLLM, Boto3CredentialsInfo, ) -from litellm.caching.caching import DualCache # Global variable for the base_aws_llm.py file path @@ -1519,6 +1520,83 @@ def test_is_already_running_as_role_invalid_target_arn(): assert base_aws_llm._is_already_running_as_role("not-a-valid-arn") is False +def test_filter_headers_skips_none_values(): + """ + Test that _filter_headers_for_aws_signature skips headers with None values. + + Reproduces the issue where botocore's SigV4Auth crashes with + 'NoneType' object has no attribute 'split' when a header value is None. + """ + llm = BaseAWSLLM() + + headers = { + "Content-Type": "application/json", + "x-amz-security-token": None, + "x-amzn-bedrock-kb-session-id": None, + "host": None, + "x-amz-date": "20240101T000000Z", + "x-custom-header": None, + } + + filtered = llm._filter_headers_for_aws_signature(headers) + + assert filtered["Content-Type"] == "application/json" + assert filtered["x-amz-date"] == "20240101T000000Z" + assert "x-amz-security-token" not in filtered + assert "x-amzn-bedrock-kb-session-id" not in filtered + assert "host" not in filtered + # Non-AWS headers are excluded regardless + assert "x-custom-header" not in filtered + + +def test_sign_request_with_none_header_values(): + """ + End-to-end test that _sign_request does not crash when headers contain + None values for x-amz-* keys. + + This reproduces the Bedrock KB GovCloud issue where SigV4 signing failed + with 'NoneType' object has no attribute 'split'. + + Also verifies that None-valued headers are NOT re-merged into the + returned headers dict (which would cause downstream HTTP client failures). + """ + llm = BaseAWSLLM() + + mock_credentials = Credentials("test_key", "test_secret") + + headers_with_nones = { + "Content-Type": "application/json", + "x-amzn-trace-id": None, + "x-forwarded-for": None, + } + + with patch.object( + llm, "get_credentials", return_value=mock_credentials + ), patch.object( + llm, "_get_aws_region_name", return_value="us-gov-west-1" + ): + result_headers, result_body = llm._sign_request( + service_name="bedrock", + headers=headers_with_nones, + optional_params={ + "aws_access_key_id": "test_key", + "aws_secret_access_key": "test_secret", + "aws_region_name": "us-gov-west-1", + }, + request_data={"retrievalQuery": {"text": "test query"}}, + api_base="https://bedrock-agent-runtime.us-gov-west-1.amazonaws.com/knowledgebases/KB123/retrieve", + ) + + assert "Authorization" in result_headers + assert result_body is not None + + # None-valued headers must NOT appear in the returned headers + for header_name, header_value in result_headers.items(): + assert header_value is not None, ( + f"Header '{header_name}' has None value in returned headers" + ) + + def test_is_already_running_as_role_ssl_verify_passed(): """ Test that ssl_verify parameter is correctly passed to the STS client. diff --git a/tests/test_litellm/router_strategy/test_router_tag_regex_routing.py b/tests/test_litellm/router_strategy/test_router_tag_regex_routing.py new file mode 100644 index 0000000000..6c7cfa61b5 --- /dev/null +++ b/tests/test_litellm/router_strategy/test_router_tag_regex_routing.py @@ -0,0 +1,375 @@ +""" +Unit tests for tag_regex routing. + +Tests _is_valid_deployment_tag_regex() and get_deployments_for_tag() with tag_regex +patterns, verifying that regex-based header matching works correctly alongside +existing tag-based routing. +""" + +import os +import sys + +import pytest + +sys.path.insert(0, os.path.abspath("../..")) + +from unittest.mock import MagicMock + +from litellm.router_strategy import tag_based_routing +from litellm.router_strategy.tag_based_routing import get_deployments_for_tag + +_is_valid_deployment_tag_regex = tag_based_routing._is_valid_deployment_tag_regex + + +# --------------------------------------------------------------------------- +# _is_valid_deployment_tag_regex unit tests +# --------------------------------------------------------------------------- + + +def test_regex_matches_claude_code_user_agent(): + """^User-Agent: claude-code/ matches a claude-code UA string.""" + result = _is_valid_deployment_tag_regex( + tag_regexes=[r"^User-Agent: claude-code\/"], + header_strings=["User-Agent: claude-code/1.2.3"], + ) + assert result == r"^User-Agent: claude-code\/" + + +def test_regex_no_match_for_other_ua(): + """Pattern does not match a non-claude-code User-Agent.""" + result = _is_valid_deployment_tag_regex( + tag_regexes=[r"^User-Agent: claude-code\/"], + header_strings=["User-Agent: Mozilla/5.0 (browser)"], + ) + assert result is None + + +def test_regex_returns_first_matching_pattern(): + """When multiple patterns are provided, returns the first match.""" + result = _is_valid_deployment_tag_regex( + tag_regexes=[r"^User-Agent: cursor\/", r"^User-Agent: claude-code\/"], + header_strings=["User-Agent: claude-code/2.0.0"], + ) + assert result == r"^User-Agent: claude-code\/" + + +def test_regex_empty_inputs_return_none(): + """Empty lists return None without errors.""" + assert _is_valid_deployment_tag_regex([], ["User-Agent: claude-code/1.0"]) is None + assert _is_valid_deployment_tag_regex([r"^User-Agent: claude-code\/"], []) is None + + +def test_invalid_regex_skipped_does_not_raise(): + """An invalid regex pattern is skipped (warning logged) — no exception raised.""" + result = _is_valid_deployment_tag_regex( + tag_regexes=["[invalid(regex"], + header_strings=["User-Agent: claude-code/1.0"], + ) + assert result is None + + +def test_regex_matches_version_range(): + """Semver-aware pattern matches multiple versions.""" + pattern = r"^User-Agent: claude-code\/\d" + for ua in ["claude-code/1.0", "claude-code/2.0.0-beta.1", "claude-code/99.0"]: + result = _is_valid_deployment_tag_regex( + tag_regexes=[pattern], + header_strings=[f"User-Agent: {ua}"], + ) + assert result == pattern, f"Expected match for UA: {ua}" + + +# --------------------------------------------------------------------------- +# get_deployments_for_tag integration tests +# --------------------------------------------------------------------------- + +CLAUDE_CODE_DEPLOYMENT = { + "model_name": "claude-sonnet", + "litellm_params": { + "model": "openai/claude-code-deployment", + "api_key": "fake", + "mock_response": "cc", + "tag_regex": [r"^User-Agent: claude-code\/"], + }, + "model_info": {"id": "claude-code-deployment"}, +} + +REGULAR_DEPLOYMENT = { + "model_name": "claude-sonnet", + "litellm_params": { + "model": "openai/regular-deployment", + "api_key": "fake", + "mock_response": "regular", + "tags": ["default"], + }, + "model_info": {"id": "regular-deployment"}, +} + +ALL_DEPLOYMENTS = [CLAUDE_CODE_DEPLOYMENT, REGULAR_DEPLOYMENT] + + +def _make_router_mock(enable_tag_filtering=True, match_any=True): + mock = MagicMock() + mock.enable_tag_filtering = enable_tag_filtering + mock.tag_filtering_match_any = match_any + return mock + + +@pytest.mark.asyncio +async def test_claude_code_ua_routes_to_cc_deployment(): + """claude-code/x.y.z UA → claude-code-deployment via tag_regex.""" + router = _make_router_mock() + result = await get_deployments_for_tag( + llm_router_instance=router, + model="claude-sonnet", + healthy_deployments=ALL_DEPLOYMENTS, + request_kwargs={"metadata": {"user_agent": "claude-code/1.2.3"}}, + ) + assert len(result) == 1 + assert result[0]["model_info"]["id"] == "claude-code-deployment" + + +@pytest.mark.asyncio +async def test_regular_ua_routes_to_default_deployment(): + """Mozilla UA → regular-deployment via default tag fallback.""" + router = _make_router_mock() + result = await get_deployments_for_tag( + llm_router_instance=router, + model="claude-sonnet", + healthy_deployments=ALL_DEPLOYMENTS, + request_kwargs={"metadata": {"user_agent": "Mozilla/5.0 (browser)"}}, + ) + assert len(result) == 1 + assert result[0]["model_info"]["id"] == "regular-deployment" + + +@pytest.mark.asyncio +async def test_no_ua_routes_to_default_deployment(): + """No User-Agent → default deployment.""" + router = _make_router_mock() + result = await get_deployments_for_tag( + llm_router_instance=router, + model="claude-sonnet", + healthy_deployments=ALL_DEPLOYMENTS, + request_kwargs={"metadata": {}}, + ) + assert len(result) == 1 + assert result[0]["model_info"]["id"] == "regular-deployment" + + +@pytest.mark.asyncio +async def test_tag_routing_metadata_written_for_regex_match(): + """tag_routing metadata block is populated when regex matches.""" + router = _make_router_mock() + metadata: dict = {"user_agent": "claude-code/2.0.0-beta.1"} + await get_deployments_for_tag( + llm_router_instance=router, + model="claude-sonnet", + healthy_deployments=ALL_DEPLOYMENTS, + request_kwargs={"metadata": metadata}, + ) + assert "tag_routing" in metadata + tr = metadata["tag_routing"] + assert tr["matched_via"] == "tag_regex" + assert tr["matched_value"] == r"^User-Agent: claude-code\/" + assert tr["user_agent"] == "claude-code/2.0.0-beta.1" + + +@pytest.mark.asyncio +async def test_tag_filtering_disabled_returns_all_deployments(): + """When enable_tag_filtering is False, all deployments returned regardless of UA.""" + router = _make_router_mock(enable_tag_filtering=False) + result = await get_deployments_for_tag( + llm_router_instance=router, + model="claude-sonnet", + healthy_deployments=ALL_DEPLOYMENTS, + request_kwargs={"metadata": {"user_agent": "claude-code/1.0"}}, + ) + assert result == ALL_DEPLOYMENTS + + +@pytest.mark.asyncio +async def test_explicit_tag_match_takes_precedence_over_regex(): + """A deployment with both tags and tag_regex: exact tag match fires first.""" + deployment_with_both = { + "model_name": "claude-sonnet", + "litellm_params": { + "model": "openai/both-deployment", + "api_key": "fake", + "tags": ["premium"], + "tag_regex": [r"^User-Agent: claude-code\/"], + }, + "model_info": {"id": "both-deployment"}, + } + router = _make_router_mock() + metadata: dict = { + "tags": ["premium"], + "user_agent": "claude-code/1.0", + } + result = await get_deployments_for_tag( + llm_router_instance=router, + model="claude-sonnet", + healthy_deployments=[deployment_with_both], + request_kwargs={"metadata": metadata}, + ) + assert len(result) == 1 + tr = metadata.get("tag_routing", {}) + assert tr.get("matched_via") == "tags" + + +@pytest.mark.asyncio +async def test_user_agent_present_no_tag_regex_deployments_does_not_raise(): + """ + Backwards-compat: a request that carries a User-Agent but targets plain-tag + deployments (no tag_regex) must NOT raise ValueError — it should fall + through to the default/all-deployments path just like before. + """ + plain_tag_only_deployments = [ + { + "model_name": "gpt-4", + "litellm_params": { + "model": "openai/premium-deployment", + "api_key": "fake", + "tags": ["premium"], + }, + "model_info": {"id": "premium-deployment"}, + }, + { + "model_name": "gpt-4", + "litellm_params": { + "model": "openai/free-deployment", + "api_key": "fake", + "tags": ["free"], + }, + "model_info": {"id": "free-deployment"}, + }, + ] + router = _make_router_mock() + # The request has a User-Agent (as all proxy requests do) but NO tags and + # neither deployment has tag_regex — must not raise, must return all. + result = await get_deployments_for_tag( + llm_router_instance=router, + model="gpt-4", + healthy_deployments=plain_tag_only_deployments, + request_kwargs={"metadata": {"user_agent": "Mozilla/5.0 (any-client)"}}, + ) + # Falls through to "return healthy_deployments" path unchanged + assert result == plain_tag_only_deployments + + +@pytest.mark.asyncio +async def test_tag_routing_metadata_not_overwritten_for_multiple_matches(): + """ + When multiple deployments match, tag_routing records only the first match + so the provenance reflects what the load balancer likely selected. + """ + deployment_a = { + "model_name": "claude-sonnet", + "litellm_params": { + "model": "openai/cc-deployment-a", + "api_key": "fake", + "tag_regex": [r"^User-Agent: claude-code\/"], + }, + "model_info": {"id": "cc-deployment-a"}, + } + deployment_b = { + "model_name": "claude-sonnet", + "litellm_params": { + "model": "openai/cc-deployment-b", + "api_key": "fake", + "tag_regex": [r"^User-Agent: claude-code\/"], + }, + "model_info": {"id": "cc-deployment-b"}, + } + router = _make_router_mock() + metadata: dict = {"user_agent": "claude-code/1.0"} + result = await get_deployments_for_tag( + llm_router_instance=router, + model="claude-sonnet", + healthy_deployments=[deployment_a, deployment_b], + request_kwargs={"metadata": metadata}, + ) + assert len(result) == 2 + # tag_routing recorded once and reflects the first match + tr = metadata.get("tag_routing", {}) + assert tr.get("matched_deployment") == "claude-sonnet" + assert tr.get("matched_via") == "tag_regex" + + +@pytest.mark.asyncio +async def test_match_any_false_strict_tag_check_blocks_regex_fallback(): + """ + When match_any=False and a deployment has both tags and tag_regex: + if the strict tag check fails (request has a tag NOT present on the + deployment, so req_set is NOT a subset of dep_set), the regex fallback + must NOT fire — that would violate the operator's strict-filtering intent. + + Semantics of match_any=False: req_set.issubset(dep_set), i.e. every + request tag must appear on the deployment. A request with tags ["vip"] + against a deployment with tags ["premium"] fails because "vip" ∉ dep_set. + """ + deployment_strict = { + "model_name": "claude-sonnet", + "litellm_params": { + "model": "openai/strict-deployment", + "api_key": "fake", + "tags": ["premium"], + "tag_regex": [r"^User-Agent: claude-code\/"], + }, + "model_info": {"id": "strict-deployment"}, + } + default_deployment = { + "model_name": "claude-sonnet", + "litellm_params": { + "model": "openai/default-deployment", + "api_key": "fake", + "tags": ["default"], + }, + "model_info": {"id": "default-deployment"}, + } + # match_any=False: req_set must be a subset of dep_set. + # Request has "vip" which is NOT in ["premium"], so tag check fails. + # Even though UA matches tag_regex, the deployment must NOT be selected. + router = _make_router_mock(enable_tag_filtering=True, match_any=False) + metadata: dict = { + "tags": ["vip"], # "vip" not in deployment tags → strict check fails + "user_agent": "claude-code/1.0", + } + result = await get_deployments_for_tag( + llm_router_instance=router, + model="claude-sonnet", + healthy_deployments=[deployment_strict, default_deployment], + request_kwargs={"metadata": metadata}, + ) + ids = [d["model_info"]["id"] for d in result] + assert "strict-deployment" not in ids, ( + "strict-deployment should not be selected: strict tag check failed " + "and regex must not override the strict policy" + ) + + +@pytest.mark.asyncio +async def test_match_any_false_regex_only_deployment_still_matches(): + """ + When match_any=False and a deployment has ONLY tag_regex (no plain tags), + there is no strict tag policy to violate, so the regex check must still fire. + """ + regex_only_deployment = { + "model_name": "claude-sonnet", + "litellm_params": { + "model": "openai/regex-only-deployment", + "api_key": "fake", + "tag_regex": [r"^User-Agent: claude-code\/"], + # no "tags" key at all + }, + "model_info": {"id": "regex-only-deployment"}, + } + router = _make_router_mock(enable_tag_filtering=True, match_any=False) + result = await get_deployments_for_tag( + llm_router_instance=router, + model="claude-sonnet", + healthy_deployments=[regex_only_deployment], + request_kwargs={"metadata": {"user_agent": "claude-code/1.0"}}, + ) + assert len(result) == 1 + assert result[0]["model_info"]["id"] == "regex-only-deployment" diff --git a/tests/test_litellm/test_model_cost_aliases.py b/tests/test_litellm/test_model_cost_aliases.py index 6e30cbfe15..f9f92a85cb 100644 --- a/tests/test_litellm/test_model_cost_aliases.py +++ b/tests/test_litellm/test_model_cost_aliases.py @@ -5,8 +5,9 @@ The ``_expand_model_aliases`` function processes ``aliases`` lists from model entries, creating shared dict references for alias entries at load time. """ -import logging +from unittest.mock import patch +from litellm import verbose_logger from litellm.litellm_core_utils.get_model_cost_map import _expand_model_aliases @@ -118,7 +119,7 @@ class TestExpandModelAliases: class TestAliasConflicts: """Tests for alias conflict detection and handling.""" - def test_alias_conflicts_with_canonical_entry(self, caplog): + def test_alias_conflicts_with_canonical_entry(self): """Alias that matches an existing canonical entry is skipped with a warning.""" model_cost = { "model-latest": { @@ -133,14 +134,17 @@ class TestAliasConflicts: "mode": "chat", }, } - with caplog.at_level(logging.WARNING, logger="LiteLLM"): + with patch.object(verbose_logger, "warning") as mock_warn: result = _expand_model_aliases(model_cost) # The canonical "model-dated" entry is preserved, not overwritten assert "model-dated" in result - assert "alias conflict" in caplog.text.lower() + # Verify a warning about the alias conflict was logged + mock_warn.assert_called() + warning_messages = " ".join(str(c) for c in mock_warn.call_args_list) + assert "alias conflict" in warning_messages.lower() - def test_duplicate_alias_across_entries(self, caplog): + def test_duplicate_alias_across_entries(self): """Same alias claimed by two different entries: second one is skipped.""" model_cost = { "model-a": { @@ -156,13 +160,16 @@ class TestAliasConflicts: "mode": "chat", }, } - with caplog.at_level(logging.WARNING, logger="LiteLLM"): + with patch.object(verbose_logger, "warning") as mock_warn: result = _expand_model_aliases(model_cost) # "shared-alias" should point to model-a (first one wins) assert "shared-alias" in result assert result["shared-alias"]["input_cost_per_token"] == 1e-06 - assert "alias conflict" in caplog.text.lower() + # Verify a warning about the alias conflict was logged + mock_warn.assert_called() + warning_messages = " ".join(str(c) for c in mock_warn.call_args_list) + assert "alias conflict" in warning_messages.lower() def test_canonical_entry_not_overwritten_by_alias(self): """An alias must never overwrite an existing canonical entry's data.""" From 0cd4a681579d21e6497824f91b0c9b789299846b Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 14 Mar 2026 09:47:56 -0700 Subject: [PATCH 065/289] [Fix] Add missing networking mocks to CreateKeyPage test The test's partial vi.mock of @/components/networking was missing the daily activity call exports now imported by EntityUsage via ENTITY_FETCH_FNS. Co-Authored-By: Claude Opus 4.6 --- .../tests/CreateKeyPage.expiredToken.test.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ui/litellm-dashboard/tests/CreateKeyPage.expiredToken.test.tsx b/ui/litellm-dashboard/tests/CreateKeyPage.expiredToken.test.tsx index 8b05def9ba..1d725572a3 100644 --- a/ui/litellm-dashboard/tests/CreateKeyPage.expiredToken.test.tsx +++ b/ui/litellm-dashboard/tests/CreateKeyPage.expiredToken.test.tsx @@ -77,6 +77,14 @@ vi.mock("@/components/networking", () => { // Called when decoding a valid token setGlobalLitellmHeaderName: vi.fn(), Organization: {}, + // Daily activity calls used by UsagePage components in the render tree + tagDailyActivityCall: vi.fn().mockResolvedValue({ results: [], metadata: {} }), + teamDailyActivityCall: vi.fn().mockResolvedValue({ results: [], metadata: {} }), + organizationDailyActivityCall: vi.fn().mockResolvedValue({ results: [], metadata: {} }), + customerDailyActivityCall: vi.fn().mockResolvedValue({ results: [], metadata: {} }), + agentDailyActivityCall: vi.fn().mockResolvedValue({ results: [], metadata: {} }), + userDailyActivityCall: vi.fn().mockResolvedValue({ results: [], metadata: {} }), + userDailyActivityAggregatedCall: vi.fn().mockResolvedValue({ results: [], metadata: {} }), }; }); From d72a34dbe2e167d78e7f7baf79438ceff5f4aa17 Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Sat, 14 Mar 2026 22:19:56 +0530 Subject: [PATCH 066/289] add docs and export fixes --- docs/my-website/docs/observability/vantage.md | 148 ++++++++++++++++++ .../focus/destinations/vantage_destination.py | 102 ++++++++++-- litellm/integrations/focus/export_engine.py | 27 ++++ litellm/integrations/focus/focus_logger.py | 27 +++- 4 files changed, 288 insertions(+), 16 deletions(-) create mode 100644 docs/my-website/docs/observability/vantage.md diff --git a/docs/my-website/docs/observability/vantage.md b/docs/my-website/docs/observability/vantage.md new file mode 100644 index 0000000000..31b43a76c3 --- /dev/null +++ b/docs/my-website/docs/observability/vantage.md @@ -0,0 +1,148 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Vantage Integration + +LiteLLM can export proxy spend data to [Vantage](https://vantage.sh) as [FOCUS 1.2](https://focus.finops.org/) formatted cost reports. This lets you visualize LLM spend alongside your cloud infrastructure costs in the Vantage dashboard. + +## Overview + +| Property | Details | +|----------|---------| +| Destination | Export LiteLLM usage data to Vantage Custom Provider | +| Data format | FOCUS CSV (automatically transformed from LiteLLM spend data) | +| Supported operations | Manual export, automatic scheduled export (hourly/daily/interval) | +| Authentication | Vantage API key + Custom Provider token | + +## Prerequisites + +You need two credentials from the [Vantage console](https://console.vantage.sh): + +1. **API Key** — Go to **Settings → API Access Tokens** → Create a token with **Write** scope. The token looks like `vntg_tkn_...`. +2. **Custom Provider Token** — Go to **Settings → Integrations** → Create a **Custom Provider** integration → Copy the Provider ID (looks like `accss_crdntl_...`). + +## Setup via API + +The recommended setup uses the proxy admin endpoints. No config file changes needed. + +### 1. Initialize credentials + +```bash +curl -X POST http://localhost:4000/vantage/init \ + -H "Authorization: Bearer $LITELLM_ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "api_key": "vntg_tkn_YOUR_VANTAGE_API_KEY", + "integration_token": "accss_crdntl_YOUR_PROVIDER_TOKEN" + }' +``` + +Credentials are encrypted and stored in the proxy database. + +### 2. Preview data (dry run) + +```bash +curl -X POST http://localhost:4000/vantage/dry-run \ + -H "Authorization: Bearer $LITELLM_ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"limit": 10}' +``` + +This returns FOCUS-transformed data without sending anything to Vantage. Use it to verify the pipeline works and inspect the data mapping. + +### 3. Export to Vantage + +```bash +curl -X POST http://localhost:4000/vantage/export \ + -H "Authorization: Bearer $LITELLM_ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{}' +``` + +Optional parameters: +- `limit` — Max number of records to export +- `start_time_utc` / `end_time_utc` — Filter by time range (must be provided together) + +### 4. Verify in Vantage + +Go to **Settings → Integrations → your Custom Provider → Import Costs** tab to see uploaded CSVs. Once the status changes from "Importing and Processing" to "Stable", costs appear in **Cost Reporting → All Resources**. + +## Setup via Environment Variables + +For automatic scheduled exports, configure via environment variables and proxy config: + +### Environment variables + +| Variable | Required | Description | +|----------|----------|-------------| +| `VANTAGE_API_KEY` | Yes | Vantage API access token | +| `VANTAGE_INTEGRATION_TOKEN` | Yes | Custom Provider token from Vantage dashboard | +| `VANTAGE_BASE_URL` | No | API URL override (default: `https://api.vantage.sh`) | +| `VANTAGE_EXPORT_FREQUENCY` | No | `hourly` (default), `daily`, or `interval` | +| `VANTAGE_EXPORT_INTERVAL_SECONDS` | No | Seconds between exports when frequency is `interval` | + +### Proxy config + +```yaml +model_list: + - model_name: gpt-4o + litellm_params: + model: openai/gpt-4o + api_key: sk-your-key + +litellm_settings: + callbacks: ["vantage"] +``` + +```bash +export VANTAGE_API_KEY="vntg_tkn_..." +export VANTAGE_INTEGRATION_TOKEN="accss_crdntl_..." +litellm --config /path/to/config.yaml +``` + +The proxy registers a background job that exports data on the configured schedule. + +## API Endpoints + +All endpoints require admin authentication. + +| Method | Endpoint | Description | +|--------|----------|-------------| +| `POST` | `/vantage/init` | Store Vantage credentials (encrypted) | +| `GET` | `/vantage/settings` | View current config (credentials masked) | +| `PUT` | `/vantage/settings` | Update credentials or base URL | +| `POST` | `/vantage/dry-run` | Preview FOCUS data without uploading | +| `POST` | `/vantage/export` | Upload cost data to Vantage | +| `DELETE` | `/vantage/delete` | Remove credentials and stop scheduled exports | + +## FOCUS Field Mapping + +LiteLLM spend data is transformed into the FOCUS 1.2 schema: + +| LiteLLM Field | FOCUS Column | Description | +|---------------|-------------|-------------| +| `spend` | BilledCost, EffectiveCost | Cost of the usage | +| `model` | ChargeDescription, ResourceId | Model identifier | +| `model_group` | ServiceName | Model group / deployment | +| `custom_llm_provider` | ProviderName, PublisherName | Provider (openai, anthropic, etc.) | +| `api_key` | BillingAccountId | Hashed API key | +| `api_key_alias` | BillingAccountName | Human-readable key alias | +| `team_id` | SubAccountId | Team identifier | +| `team_alias` | SubAccountName | Team name | + +Additional metadata (user_id, model_group, etc.) is included in the `Tags` column as JSON. + +## Upload Limits + +Vantage enforces per-upload limits. LiteLLM handles these automatically: + +- **10,000 rows** per upload — large exports are split into batches +- **2 MB** per upload — oversized batches are further split by size +- **Unsupported columns** are stripped before upload + +## Related Links + +- [Vantage](https://vantage.sh) +- [Vantage Custom Providers](https://docs.vantage.sh/connecting_custom_providers) +- [FOCUS Specification](https://focus.finops.org/) +- [Focus Export (S3/Parquet)](./focus.md) diff --git a/litellm/integrations/focus/destinations/vantage_destination.py b/litellm/integrations/focus/destinations/vantage_destination.py index 8275c0690b..9e6028900f 100644 --- a/litellm/integrations/focus/destinations/vantage_destination.py +++ b/litellm/integrations/focus/destinations/vantage_destination.py @@ -2,6 +2,8 @@ from __future__ import annotations +import csv +import io from typing import Any, Optional import httpx @@ -14,6 +16,77 @@ from .base import FocusDestination, FocusTimeWindow VANTAGE_MAX_ROWS_PER_UPLOAD = 10_000 VANTAGE_MAX_BYTES_PER_UPLOAD = 2 * 1024 * 1024 # 2 MB +# Columns that Vantage actually supports for custom provider CSV uploads. +# See: https://docs.vantage.sh/connecting_custom_providers +# Columns not in this set are silently dropped before upload so Vantage +# does not reject the file. +VANTAGE_SUPPORTED_COLUMNS = { + # Required + "ChargeCategory", + "ChargePeriodStart", + "BilledCost", + "ServiceName", + # Optional + "BillingCurrency", + "BillingAccountId", + "BillingAccountName", + "ChargePeriodEnd", + "ChargeDescription", + "ChargeFrequency", + "ConsumedQuantity", + "ConsumedUnit", + "ContractedCost", + "EffectiveCost", + "ListCost", + "RegionId", + "RegionName", + "ResourceId", + "ResourceName", + "ResourceType", + "ServiceCategory", + "ServiceSubcategory", + "SubAccountId", + "SubAccountName", + "Tags", +} + + +def _strip_unsupported_columns(csv_bytes: bytes) -> bytes: + """Remove CSV columns not in VANTAGE_SUPPORTED_COLUMNS. + + Parses the header row, identifies column indices to keep, and + rebuilds the CSV with only those columns. + """ + lines = csv_bytes.split(b"\n") + if not lines: + return csv_bytes + + header_cols = lines[0].decode("utf-8").split(",") + keep_indices = [ + i + for i, col in enumerate(header_cols) + if col.strip('"') in VANTAGE_SUPPORTED_COLUMNS + ] + + # If all columns are supported, return as-is + if len(keep_indices) == len(header_cols): + return csv_bytes + + dropped = [col for i, col in enumerate(header_cols) if i not in keep_indices] + verbose_logger.debug( + "Vantage destination: dropping unsupported columns: %s", dropped + ) + + output = io.StringIO() + writer = csv.writer(output) + reader = csv.reader(io.StringIO(csv_bytes.decode("utf-8"))) + for row in reader: + if not row: + continue + writer.writerow([row[i] for i in keep_indices]) + + return output.getvalue().encode("utf-8") + class FocusVantageDestination(FocusDestination): """Upload FOCUS CSV exports to the Vantage cost-import API.""" @@ -39,9 +112,7 @@ class FocusVantageDestination(FocusDestination): ) self.api_key = api_key self.integration_token = integration_token - self.base_url = config.get( - "base_url", "https://api.vantage.sh" - ) + self.base_url = config.get("base_url", "https://api.vantage.sh") self.prefix = prefix async def deliver( @@ -56,6 +127,10 @@ class FocusVantageDestination(FocusDestination): verbose_logger.debug("Vantage destination: empty content, skipping upload") return + # Strip columns that Vantage does not support to avoid silent + # rejection (e.g. InvoiceIssuerName, ProviderName, PublisherName). + content = _strip_unsupported_columns(content) + # Reuse a single HTTP client for the entire deliver() call async with httpx.AsyncClient(timeout=60.0) as client: # Check both size and row-count limits before single-shot upload @@ -75,10 +150,7 @@ class FocusVantageDestination(FocusDestination): async def _upload_csv( self, client: httpx.AsyncClient, csv_bytes: bytes, filename: str ) -> None: - url = ( - f"{self.base_url}/v2/integrations/" - f"{self.integration_token}/costs.csv" - ) + url = f"{self.base_url}/v2/integrations/" f"{self.integration_token}/costs.csv" headers = { "Authorization": f"Bearer {self.api_key}", } @@ -86,15 +158,16 @@ class FocusVantageDestination(FocusDestination): response = await client.post( url, headers=headers, - files={"file": (filename, csv_bytes, "text/csv")}, + files={"csv": (filename, csv_bytes, "text/csv")}, ) try: response.raise_for_status() except httpx.HTTPStatusError as e: verbose_logger.error( - "Vantage destination: upload failed for %s — %s", + "Vantage destination: upload failed for %s — %s — response body: %s", filename, e, + response.text, ) raise @@ -174,7 +247,10 @@ class FocusVantageDestination(FocusDestination): ) continue - if current_size + line_size > VANTAGE_MAX_BYTES_PER_UPLOAD and current_chunk: + if ( + current_size + line_size > VANTAGE_MAX_BYTES_PER_UPLOAD + and current_chunk + ): batch_csv = header + b"\n" + b"\n".join(current_chunk) + b"\n" batch_filename = f"{filename}.part{batch_offset}_{sub_batch}" try: @@ -182,7 +258,8 @@ class FocusVantageDestination(FocusDestination): except Exception as e: verbose_logger.error( "Vantage destination: sub-batch %s failed: %s", - batch_filename, e, + batch_filename, + e, ) if first_error is None: first_error = e @@ -200,7 +277,8 @@ class FocusVantageDestination(FocusDestination): except Exception as e: verbose_logger.error( "Vantage destination: sub-batch %s failed: %s", - batch_filename, e, + batch_filename, + e, ) if first_error is None: first_error = e diff --git a/litellm/integrations/focus/export_engine.py b/litellm/integrations/focus/export_engine.py index 8b77fad9e1..37da18a0eb 100644 --- a/litellm/integrations/focus/export_engine.py +++ b/litellm/integrations/focus/export_engine.py @@ -67,6 +67,33 @@ class FocusExportEngine: "summary": summary, } + async def export_all( + self, + *, + limit: Optional[int], + ) -> None: + """Export all available data without time-window filtering.""" + data = await self._database.get_usage_data(limit=limit) + if data.is_empty(): + verbose_logger.debug("Focus export: no usage data available") + return + + normalized = self._transformer.transform(data) + if normalized.is_empty(): + verbose_logger.debug("Focus export: normalized data empty") + return + + # Build a window spanning the full data range for the filename + from datetime import datetime, timezone + + now = datetime.now(timezone.utc) + window = FocusTimeWindow( + start_time=now.replace(hour=0, minute=0, second=0, microsecond=0), + end_time=now, + frequency="all", + ) + await self._serialize_and_upload(normalized, window) + async def export_window( self, *, diff --git a/litellm/integrations/focus/focus_logger.py b/litellm/integrations/focus/focus_logger.py index f461f8c9fa..083b0e1463 100644 --- a/litellm/integrations/focus/focus_logger.py +++ b/litellm/integrations/focus/focus_logger.py @@ -64,7 +64,9 @@ class FocusLogger(CustomLogger): ) env_prefix = os.getenv("FOCUS_PREFIX") self.prefix: str = ( - prefix if prefix is not None else (env_prefix if env_prefix else "focus_exports") + prefix + if prefix is not None + else (env_prefix if env_prefix else "focus_exports") ) self._destination_config = destination_config @@ -90,7 +92,13 @@ class FocusLogger(CustomLogger): start_time_utc: Optional[datetime] = None, end_time_utc: Optional[datetime] = None, ) -> None: - """Public hook to trigger export immediately.""" + """Public hook to trigger export immediately. + + When called without time bounds (manual /vantage/export with no + start/end), exports **all** available data instead of the last + scheduled window. The hourly/daily window only applies to + automatic scheduler runs. + """ if bool(start_time_utc) ^ bool(end_time_utc): raise ValueError( "start_time_utc and end_time_utc must be provided together" @@ -102,9 +110,10 @@ class FocusLogger(CustomLogger): end_time=end_time_utc, frequency=self.frequency, ) + await self._export_window(window=window, limit=limit) else: - window = self._compute_time_window(datetime.now(timezone.utc)) - await self._export_window(window=window, limit=limit) + # No time bounds → export all available data + await self._export_all(limit=limit) async def dry_run_export_usage_data( self, limit: Optional[int] = DEFAULT_DRY_RUN_LIMIT @@ -190,6 +199,15 @@ class FocusLogger(CustomLogger): window = self._compute_time_window(datetime.now(timezone.utc)) await self._export_window(window=window, limit=None) + async def _export_all( + self, + *, + limit: Optional[int], + ) -> None: + """Export all available data without a time window filter.""" + engine = self._ensure_engine() + await engine.export_all(limit=limit) + async def _export_window( self, *, @@ -220,4 +238,5 @@ class FocusLogger(CustomLogger): frequency=self.frequency, ) + __all__ = ["FocusLogger"] From db37f3109943696a2cc9be05e1c81c8d93f0fcc6 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 14 Mar 2026 09:55:57 -0700 Subject: [PATCH 067/289] [Fix] Address review feedback on paginated daily activity hook 1. Replace ...args spread in useEffect deps with JSON.stringify(args) key to prevent infinite re-renders when callers pass unstable array references. 2. Add missing agentCancelled partial-data message in EntityUsage so the outer condition no longer renders an empty div. 3. Store setTimeout ID in a ref and clearTimeout on cleanup/cancel to avoid orphaned timers under rapid re-renders. Co-Authored-By: Claude Opus 4.6 --- .../components/EntityUsage/EntityUsage.tsx | 5 +++ .../hooks/usePaginatedDailyActivity.ts | 38 ++++++++++++++++--- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx b/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx index c1d5314096..e075e8b34e 100644 --- a/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx +++ b/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx @@ -416,6 +416,11 @@ const EntityUsage: React.FC = ({ accessToken, entityType, enti )} + {agentCancelled && entityType === "team" && ( + + Showing partial agent data ({agentProgress.currentPage}/{agentProgress.totalPages} pages loaded) + + )}
)} | null>(null); + + // Keep args in a ref so the effect can always read the latest values + // without needing them in the dependency array. + const argsRef = useRef(args); + argsRef.current = args; + + // Stable serialised key so the effect only re-runs when the arg *values* change. + const argsKey = JSON.stringify(args); const cancel = useCallback(() => { cancelledRef.current = true; setCancelled(true); setIsFetchingMore(false); + if (delayTimerRef.current !== null) { + clearTimeout(delayTimerRef.current); + delayTimerRef.current = null; + } }, []); useEffect(() => { @@ -126,14 +139,24 @@ export function usePaginatedDailyActivity({ const isStale = () => fetchIdRef.current !== currentFetchId || cancelledRef.current; + /** Cancellable delay that clears itself on cleanup. */ + const delay = (ms: number) => + new Promise((resolve) => { + delayTimerRef.current = setTimeout(() => { + delayTimerRef.current = null; + resolve(); + }, ms); + }); + const run = async () => { + const currentArgs = argsRef.current; setLoading(true); setIsFetchingMore(false); setProgress({ currentPage: 1, totalPages: 1 }); try { // Inject page=1 as the 4th argument. - const argsWithPage = [...args.slice(0, 3), 1, ...args.slice(3)]; + const argsWithPage = [...currentArgs.slice(0, 3), 1, ...currentArgs.slice(3)]; const firstPage = await fetchFn(...argsWithPage); if (isStale()) return; @@ -160,13 +183,11 @@ export function usePaginatedDailyActivity({ if (isStale()) return; // Small delay to avoid overwhelming the backend. - await new Promise((resolve) => - setTimeout(resolve, PAGE_FETCH_DELAY_MS), - ); + await delay(PAGE_FETCH_DELAY_MS); if (isStale()) return; - const argsForPage = [...args.slice(0, 3), page, ...args.slice(3)]; + const argsForPage = [...currentArgs.slice(0, 3), page, ...currentArgs.slice(3)]; const pageData = await fetchFn(...argsForPage); if (isStale()) return; @@ -201,9 +222,14 @@ export function usePaginatedDailyActivity({ return () => { fetchIdRef.current++; + if (delayTimerRef.current !== null) { + clearTimeout(delayTimerRef.current); + delayTimerRef.current = null; + } }; + // argsKey is a stable JSON string so the effect only re-fires when arg values change. // eslint-disable-next-line react-hooks/exhaustive-deps - }, [enabled, fetchFn, ...args]); + }, [enabled, fetchFn, argsKey]); return { data, loading, isFetchingMore, progress, cancelled, cancel }; } From b793eee245ae12de16b6562b9d2799532e5c9853 Mon Sep 17 00:00:00 2001 From: milan-berri Date: Sat, 14 Mar 2026 19:48:36 +0200 Subject: [PATCH 068/289] fix: tiktoken cache nonroot offline (#23498) * fix: restore offline tiktoken cache for non-root envs Made-with: Cursor * chore: mkdir for custom tiktoken cache dir Made-with: Cursor * test: patch tiktoken.get_encoding in custom-dir test to avoid network Made-with: Cursor * test: clear CUSTOM_TIKTOKEN_CACHE_DIR in helper for test isolation Made-with: Cursor * test: restore default_encoding module state after custom-dir test Made-with: Cursor --- .../litellm_core_utils/default_encoding.py | 22 +++--- tests/test_default_encoding_non_root.py | 78 ++++++++++--------- 2 files changed, 56 insertions(+), 44 deletions(-) diff --git a/litellm/litellm_core_utils/default_encoding.py b/litellm/litellm_core_utils/default_encoding.py index 1771efba41..24533feecc 100644 --- a/litellm/litellm_core_utils/default_encoding.py +++ b/litellm/litellm_core_utils/default_encoding.py @@ -15,16 +15,19 @@ except (ImportError, AttributeError): __name__, "litellm_core_utils/tokenizers" ) -# Check if the directory is writable. If not, use /tmp as a fallback. -# This is especially important for non-root Docker environments where the package directory is read-only. -is_non_root = os.getenv("LITELLM_NON_ROOT", "").lower() == "true" -if not os.access(filename, os.W_OK) and is_non_root: - filename = "/tmp/tiktoken_cache" - os.makedirs(filename, exist_ok=True) +# Always default TIKTOKEN_CACHE_DIR to the bundled tokenizers directory +# unless the user explicitly overrides it via CUSTOM_TIKTOKEN_CACHE_DIR. +# This keeps tiktoken fully offline-capable by default (see #1071). +custom_cache_dir = os.getenv("CUSTOM_TIKTOKEN_CACHE_DIR") +if custom_cache_dir: + # If the user opts into a custom cache dir, ensure it exists. + os.makedirs(custom_cache_dir, exist_ok=True) + cache_dir = custom_cache_dir +else: + cache_dir = filename + +os.environ["TIKTOKEN_CACHE_DIR"] = cache_dir # use local copy of tiktoken b/c of - https://github.com/BerriAI/litellm/issues/1071 -os.environ["TIKTOKEN_CACHE_DIR"] = os.getenv( - "CUSTOM_TIKTOKEN_CACHE_DIR", filename -) # use local copy of tiktoken b/c of - https://github.com/BerriAI/litellm/issues/1071 import tiktoken import time import random @@ -45,3 +48,4 @@ for attempt in range(_max_retries): # Exponential backoff with jitter to reduce collision probability delay = _retry_delay * (2**attempt) + random.uniform(0, 0.1) time.sleep(delay) + diff --git a/tests/test_default_encoding_non_root.py b/tests/test_default_encoding_non_root.py index 1f22b7c69e..9f65d0fc09 100644 --- a/tests/test_default_encoding_non_root.py +++ b/tests/test_default_encoding_non_root.py @@ -1,49 +1,57 @@ +import importlib import os -from unittest.mock import patch +from unittest.mock import MagicMock, patch + +import litellm.litellm_core_utils.default_encoding as default_encoding -def test_tiktoken_cache_fallback(monkeypatch): +def _reload_default_encoding(monkeypatch, **env_overrides): """ - Test that TIKTOKEN_CACHE_DIR falls back to /tmp/tiktoken_cache - if the default directory is not writable and LITELLM_NON_ROOT is true. + Helper to reload default_encoding with a clean TIKTOKEN_CACHE_DIR and + specific environment overrides. """ - # Simulate non-root environment - monkeypatch.setenv("LITELLM_NON_ROOT", "true") + monkeypatch.delenv("TIKTOKEN_CACHE_DIR", raising=False) monkeypatch.delenv("CUSTOM_TIKTOKEN_CACHE_DIR", raising=False) - - # Mock os.access to return False (not writable) - # and mock os.makedirs to avoid actually creating /tmp/tiktoken_cache on local machine - with patch("os.access", return_value=False), patch("os.makedirs"): - # We need to reload or re-run the logic in default_encoding.py - # But since it's already executed, we'll just test the logic directly - # mirroring what we wrote in the file. - - filename = ( - "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/tokenizers" - ) - is_non_root = os.getenv("LITELLM_NON_ROOT", "").lower() == "true" - - if not os.access(filename, os.W_OK) and is_non_root: - filename = "/tmp/tiktoken_cache" - # mock_makedirs(filename, exist_ok=True) - - assert filename == "/tmp/tiktoken_cache" + for key, value in env_overrides.items(): + monkeypatch.setenv(key, value) + importlib.reload(default_encoding) -def test_tiktoken_cache_no_fallback_if_writable(monkeypatch): +def test_default_encoding_uses_bundled_tokenizers_by_default(monkeypatch): """ - Test that TIKTOKEN_CACHE_DIR does NOT fall back if writable + TIKTOKEN_CACHE_DIR should point at the bundled tokenizers directory + when no CUSTOM_TIKTOKEN_CACHE_DIR is set, even in non-root environments. """ - monkeypatch.setenv("LITELLM_NON_ROOT", "true") + _reload_default_encoding(monkeypatch, LITELLM_NON_ROOT="true") - filename = "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/tokenizers" + assert "TIKTOKEN_CACHE_DIR" in os.environ + cache_dir = os.environ["TIKTOKEN_CACHE_DIR"] + assert "tokenizers" in cache_dir - with patch("os.access", return_value=True): - is_non_root = os.getenv("LITELLM_NON_ROOT", "").lower() == "true" - if not os.access(filename, os.W_OK) and is_non_root: - filename = "/tmp/tiktoken_cache" - assert ( - filename - == "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/tokenizers" +def test_custom_tiktoken_cache_dir_override(monkeypatch, tmp_path): + """ + CUSTOM_TIKTOKEN_CACHE_DIR must override the default bundled directory + and the directory should be created if it does not exist. + Reload with an empty custom dir would otherwise trigger tiktoken to + download the vocab; we patch get_encoding so the test is offline-safe + and does not depend on tiktoken's in-memory cache state. + """ + custom_dir = tmp_path / "tiktoken_cache" + with patch( + "litellm.litellm_core_utils.default_encoding.tiktoken.get_encoding", + return_value=MagicMock(), + ): + _reload_default_encoding( + monkeypatch, CUSTOM_TIKTOKEN_CACHE_DIR=str(custom_dir) ) + + cache_dir = os.environ.get("TIKTOKEN_CACHE_DIR") + assert cache_dir == str(custom_dir) + assert os.path.isdir(cache_dir) + + # Restore module to a clean state so default_encoding.encoding is a real + # tiktoken Encoding, not the MagicMock, for any test that runs after this. + monkeypatch.delenv("TIKTOKEN_CACHE_DIR", raising=False) + monkeypatch.delenv("CUSTOM_TIKTOKEN_CACHE_DIR", raising=False) + importlib.reload(default_encoding) From d29287c1c30f65e2937704e239f4e910e51bca42 Mon Sep 17 00:00:00 2001 From: milan-berri Date: Sat, 14 Mar 2026 19:50:33 +0200 Subject: [PATCH 069/289] fix: normalize content_filtered finish_reason (#23564) Map provider finish_reason "content_filtered" to the OpenAI-compatible "content_filter" and extend core_helpers tests to cover this case. Made-with: Cursor --- litellm/litellm_core_utils/core_helpers.py | 2 ++ .../litellm_core_utils/test_core_helpers.py | 27 +++++++++---------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/litellm/litellm_core_utils/core_helpers.py b/litellm/litellm_core_utils/core_helpers.py index ee111f3592..256b16ff31 100644 --- a/litellm/litellm_core_utils/core_helpers.py +++ b/litellm/litellm_core_utils/core_helpers.py @@ -96,6 +96,8 @@ _FINISH_REASON_MAP: dict[str, OpenAIChatCompletionFinishReason] = { "tool_calls": "tool_calls", "function_call": "function_call", "content_filter": "content_filter", + # Anthropic Sonnet 4 + "content_filtered": "content_filter", } diff --git a/tests/test_litellm/litellm_core_utils/test_core_helpers.py b/tests/test_litellm/litellm_core_utils/test_core_helpers.py index 0ef76e0942..72c3b2b077 100644 --- a/tests/test_litellm/litellm_core_utils/test_core_helpers.py +++ b/tests/test_litellm/litellm_core_utils/test_core_helpers.py @@ -59,20 +59,19 @@ VALID_OPENAI_FINISH_REASONS = {"stop", "length", "tool_calls", "function_call", class TestMapFinishReasonAnthropic: - def test_stop_sequence(self): - assert map_finish_reason("stop_sequence") == "stop" - - def test_end_turn(self): - assert map_finish_reason("end_turn") == "stop" - - def test_max_tokens(self): - assert map_finish_reason("max_tokens") == "length" - - def test_tool_use(self): - assert map_finish_reason("tool_use") == "tool_calls" - - def test_compaction(self): - assert map_finish_reason("compaction") == "length" + @pytest.mark.parametrize( + "provider_reason,expected", + [ + ("stop_sequence", "stop"), + ("end_turn", "stop"), + ("max_tokens", "length"), + ("tool_use", "tool_calls"), + ("compaction", "length"), + ("content_filtered", "content_filter"), + ], + ) + def test_anthropic_finish_reasons(self, provider_reason: str, expected: str) -> None: + assert map_finish_reason(provider_reason) == expected class TestMapFinishReasonGemini: From f72931a46332d6d53f63605ca584b70e328a9b67 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 14 Mar 2026 11:09:10 -0700 Subject: [PATCH 070/289] [Feature] UI - Usage: Prominent fetch banner, batched pagination renders Replace subtle loading text with antd Alert banners that clearly communicate pagination status, and batch state flushes to reduce chart re-renders. - Replace inline loading text with warning Alert banners showing progress, "open a new tab" link with ExportOutlined icon, and primary Stop button - Batch setData calls every 5 pages instead of per-page to cut re-renders ~80% - Reduce fetch delay from 500ms to 300ms for faster data loading - Add "Charts will update periodically" messaging to set expectations - Fix pre-existing TS error: Button icon prop was using render function instead of ReactNode Co-Authored-By: Claude Opus 4.6 --- .../components/EntityUsage/EntityUsage.tsx | 99 ++- .../components/UsagePageView.test.tsx | 1 + .../UsagePage/components/UsagePageView.tsx | 785 +++++++++--------- .../hooks/usePaginatedDailyActivity.ts | 21 +- 4 files changed, 467 insertions(+), 439 deletions(-) diff --git a/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx b/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx index e075e8b34e..cb1a08d3ff 100644 --- a/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx +++ b/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx @@ -22,7 +22,8 @@ import { Text, Title, } from "@tremor/react"; -import { LoadingOutlined } from "@ant-design/icons"; +import { ExportOutlined } from "@ant-design/icons"; +import { Alert, Button } from "antd"; import React, { useMemo, useState } from "react"; import { ActivityMetrics, processActivityData } from "../../../activity_metrics"; import { UsageExportHeader } from "../../../EntityUsageExport"; @@ -105,8 +106,8 @@ const EntityUsage: React.FC = ({ accessToken, entityType, enti const [topModelsLimit, setTopModelsLimit] = useState(5); const [topAgentsLimit, setTopAgentsLimit] = useState(5); - const startTime = useMemo(() => dateValue.from ? new Date(dateValue.from) : null, [dateValue.from]); - const endTime = useMemo(() => dateValue.to ? new Date(dateValue.to) : null, [dateValue.to]); + const startTime = useMemo(() => (dateValue.from ? new Date(dateValue.from) : null), [dateValue.from]); + const endTime = useMemo(() => (dateValue.to ? new Date(dateValue.to) : null), [dateValue.to]); const entityFilterArg = useMemo(() => { if (entityType === "user") return selectedTags.length > 0 ? selectedTags[0] : null; @@ -395,33 +396,75 @@ const EntityUsage: React.FC = ({ accessToken, entityType, enti return (
- {(isFetchingMore || cancelled || agentIsFetchingMore || agentCancelled) && ( -
- {isFetchingMore && ( - <> - - Loading spend data... (page {progress.currentPage}/{progress.totalPages}) - - - )} - {cancelled && ( - + {isFetchingMore && ( + + + Currently fetching spend data: fetched {progress.currentPage} / {progress.totalPages} pages. Charts will + update periodically as data loads. Moving off of this page will stop and reset this. To continue using + the UI in the meantime,{" "} + + open a new tab + + . + + +
+ } + /> + )} + {cancelled && ( + Showing partial data ({progress.currentPage}/{progress.totalPages} pages loaded) - )} - {agentIsFetchingMore && entityType === "team" && ( - <> - - Loading agent data... (page {agentProgress.currentPage}/{agentProgress.totalPages}) - - - )} - {agentCancelled && entityType === "team" && ( - + } + /> + )} + {agentIsFetchingMore && entityType === "team" && ( + + + Currently fetching agent data: fetched {agentProgress.currentPage} / {agentProgress.totalPages} pages. + Charts will update periodically as data loads. Moving off of this page will stop and reset this. To + continue using the UI in the meantime,{" "} + + open a new tab + + . + + +
+ } + /> + )} + {agentCancelled && entityType === "team" && ( + Showing partial agent data ({agentProgress.currentPage}/{agentProgress.totalPages} pages loaded) - )} - + } + /> )} = ({ accessToken, entityType, enti - ) : <>} + ) : ( + <> + )} diff --git a/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.test.tsx b/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.test.tsx index b9fe1687e6..bbcddd572c 100644 --- a/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.test.tsx +++ b/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.test.tsx @@ -251,6 +251,7 @@ vi.mock("@ant-design/icons", async () => { UserOutlined: Icon, DownOutlined: Icon, RightOutlined: Icon, + ExportOutlined: Icon, LoadingOutlined, }; }); diff --git a/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.tsx b/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.tsx index 3ebe820505..8b111c63c9 100644 --- a/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.tsx +++ b/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.tsx @@ -6,7 +6,8 @@ * Works at 1m+ spend logs, by querying an aggregate table instead. */ -import { DownOutlined, InfoCircleOutlined, LoadingOutlined, RightOutlined } from "@ant-design/icons"; +import { DownOutlined, ExportOutlined, InfoCircleOutlined, LoadingOutlined, RightOutlined } from "@ant-design/icons"; +import { useDebouncedState } from "@tanstack/react-pacer/debouncer"; import { BarChart, Card, @@ -19,10 +20,9 @@ import { TabPanel, TabPanels, Text, - Title + Title, } from "@tremor/react"; -import { Alert, Segmented, Select, Tooltip, Typography } from "antd"; -import { useDebouncedState } from "@tanstack/react-pacer/debouncer"; +import { Alert, Button, Segmented, Select, Tooltip, Typography } from "antd"; import React, { useCallback, useEffect, useMemo, useRef, useState, type UIEvent } from "react"; import { useAgents } from "@/app/(dashboard)/hooks/agents/useAgents"; @@ -31,7 +31,6 @@ import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; import { useCurrentUser } from "@/app/(dashboard)/hooks/users/useCurrentUser"; import { useInfiniteUsers } from "@/app/(dashboard)/hooks/users/useUsers"; import { formatNumberWithCommas } from "@/utils/dataUtils"; -import { Button } from "@tremor/react"; import { all_admin_roles } from "../../../utils/roles"; import { ActivityMetrics, processActivityData } from "../../activity_metrics"; import CloudZeroExportModal from "../../cloudzero_export_modal"; @@ -50,8 +49,8 @@ import EndpointUsage from "./EndpointUsage/EndpointUsage"; import EntityUsage, { EntityList } from "./EntityUsage/EntityUsage"; import SpendByProvider from "./EntityUsage/SpendByProvider"; import TopKeyView from "./EntityUsage/TopKeyView"; -import { UsageOption, UsageViewSelect } from "./UsageViewSelect/UsageViewSelect"; import UsageAIChatPanel from "./UsageAIChatPanel"; +import { UsageOption, UsageViewSelect } from "./UsageViewSelect/UsageViewSelect"; interface UsagePageProps { teams: Team[]; @@ -128,8 +127,7 @@ const UsagePage: React.FC = ({ teams, organizations }) => { const handleUserPopupScroll = (e: UIEvent) => { const target = e.currentTarget; - const scrollRatio = - (target.scrollTop + target.clientHeight) / target.scrollHeight; + const scrollRatio = (target.scrollTop + target.clientHeight) / target.scrollHeight; if (scrollRatio >= 0.8 && hasNextUsersPage && !isFetchingNextUsersPage) { fetchNextUsersPage(); } @@ -137,9 +135,7 @@ const UsagePage: React.FC = ({ teams, organizations }) => { // For admins: null means global view (all users), a string means filter by that user // For non-admins: always set to their own user ID - const [selectedUserId, setSelectedUserId] = useState( - isAdmin ? null : (userID || null) - ); + const [selectedUserId, setSelectedUserId] = useState(isAdmin ? null : userID || null); const [modelViewType, setModelViewType] = useState<"groups" | "individual">("groups"); const [isCloudZeroModalOpen, setIsCloudZeroModalOpen] = useState(false); const [isGlobalExportModalOpen, setIsGlobalExportModalOpen] = useState(false); @@ -174,10 +170,10 @@ const UsagePage: React.FC = ({ teams, organizations }) => { }, [isAdmin, userID]); // For non-admins, always pass their own user_id - const effectiveUserId = isAdmin ? selectedUserId : (userID || null); + const effectiveUserId = isAdmin ? selectedUserId : userID || null; - const startTime = useMemo(() => dateValue.from ? new Date(dateValue.from) : null, [dateValue.from]); - const endTime = useMemo(() => dateValue.to ? new Date(dateValue.to) : null, [dateValue.to]); + const startTime = useMemo(() => (dateValue.from ? new Date(dateValue.from) : null), [dateValue.from]); + const endTime = useMemo(() => (dateValue.to ? new Date(dateValue.to) : null), [dateValue.to]); // Try aggregated endpoint first, fall back to paginated on failure const aggregatedFetchIdRef = useRef(0); @@ -361,7 +357,8 @@ const UsagePage: React.FC = ({ teams, organizations }) => { providerSpendMap[provider].metrics.successful_requests += metrics.metrics.successful_requests || 0; providerSpendMap[provider].metrics.failed_requests += metrics.metrics.failed_requests || 0; providerSpendMap[provider].metrics.cache_read_input_tokens += metrics.metrics.cache_read_input_tokens || 0; - providerSpendMap[provider].metrics.cache_creation_input_tokens += metrics.metrics.cache_creation_input_tokens || 0; + providerSpendMap[provider].metrics.cache_creation_input_tokens += + metrics.metrics.cache_creation_input_tokens || 0; }); }); @@ -429,430 +426,408 @@ const UsagePage: React.FC = ({ teams, organizations }) => { ); const modelMetrics = useMemo(() => processActivityData(userSpendData, "models", teams), [userSpendData, teams]); const keyMetrics = useMemo(() => processActivityData(userSpendData, "api_keys", teams), [userSpendData, teams]); - const mcpServerMetrics = useMemo(() => processActivityData(userSpendData, "mcp_servers", teams), [userSpendData, teams]); + const mcpServerMetrics = useMemo( + () => processActivityData(userSpendData, "mcp_servers", teams), + [userSpendData, teams], + ); return (
- {/* Export Data Button - Positioned in top right corner */} - {/* {all_admin_roles.includes(userRole || "") && ( -
- -
- )} */} - {/* Global Date Picker and Tabs - Single Row */}
- setUsageView(value)} - isAdmin={isAdmin} - /> + setUsageView(value)} isAdmin={isAdmin} />
- {(paginatedResult.isFetchingMore || paginatedResult.cancelled) && ( -
- {paginatedResult.isFetchingMore && ( - <> - + {paginatedResult.isFetchingMore && ( + - Loading spend data... (page {paginatedResult.progress.currentPage}/{paginatedResult.progress.totalPages}) + Currently fetching spend data: fetched {paginatedResult.progress.currentPage} /{" "} + {paginatedResult.progress.totalPages} pages. Charts will update periodically as data loads. Moving + off of this page will stop and reset this. To continue using the UI in the meantime,{" "} + + open a new tab + + . - - - )} - {paginatedResult.cancelled && ( - - Showing partial data ({paginatedResult.progress.currentPage}/{paginatedResult.progress.totalPages} pages loaded) + +
+ } + /> + )} + {paginatedResult.cancelled && ( + + Showing partial data ({paginatedResult.progress.currentPage}/{paginatedResult.progress.totalPages}{" "} + pages loaded) - )} -
+ } + /> )} {/* Your Usage Panel */} {usageView === "global" && ( <> - {isAdmin && ( -
- Filter by user - setSelectedUserId(value ?? null)} + filterOption={false} + onSearch={handleUserSearchChange} + searchValue={userSearchInput} + onPopupScroll={handleUserPopupScroll} + loading={isLoadingUsers} + notFoundContent={isLoadingUsers ? : "No users found"} + options={userOptions} + popupRender={(menu) => ( + <> + {menu} + {isFetchingNextUsersPage && ( +
+ +
+ )} + )} - > - Ask AI - - + />
-
- - {/* Cost Panel */} - - - {/* Total Spend Card */} - -
- - Project Spend{" "} - {dateValue.from && dateValue.to && ( - <> - {dateValue.from.toLocaleDateString("en-US", { - month: "short", - day: "numeric", - year: dateValue.from.getFullYear() !== dateValue.to.getFullYear() ? "numeric" : undefined, - })} - {" - "} - {dateValue.to.toLocaleDateString("en-US", { - month: "short", - day: "numeric", - year: "numeric", - })} - - )} - -
+ )} + +
+ + Cost + Model Activity + Key Activity + MCP Server Activity + Endpoint Activity + +
+ + +
+
+ + {/* Cost Panel */} + + + {/* Total Spend Card */} + +
+ + Project Spend{" "} + {dateValue.from && dateValue.to && ( + <> + {dateValue.from.toLocaleDateString("en-US", { + month: "short", + day: "numeric", + year: + dateValue.from.getFullYear() !== dateValue.to.getFullYear() ? "numeric" : undefined, + })} + {" - "} + {dateValue.to.toLocaleDateString("en-US", { + month: "short", + day: "numeric", + year: "numeric", + })} + + )} + +
- - + + - - - Usage Metrics - - - Total Requests - - {userSpendData.metadata?.total_api_requests?.toLocaleString() || 0} - - - - Successful Requests - - {userSpendData.metadata?.total_successful_requests?.toLocaleString() || 0} - - - -
- Failed Requests - - - -
- - {userSpendData.metadata?.total_failed_requests?.toLocaleString() || 0} - -
- - Average Cost per Request - - $ - {formatNumberWithCommas( - (totalSpend || 0) / (userSpendData.metadata?.total_api_requests || 1), - 4, - )} - - - setShowTokenBreakdown(!showTokenBreakdown)} - > -
- Total Tokens - {showTokenBreakdown ? ( - - ) : ( - - )} -
- - {userSpendData.metadata?.total_tokens?.toLocaleString() || 0} - -
-
- {showTokenBreakdown && ( - + + + Usage Metrics + - Input Tokens - - {userSpendData.metadata?.total_prompt_tokens?.toLocaleString() || 0} + Total Requests + + {userSpendData.metadata?.total_api_requests?.toLocaleString() || 0} - Output Tokens - - {userSpendData.metadata?.total_completion_tokens?.toLocaleString() || 0} - - - - Cache Read Tokens + Successful Requests - {userSpendData.metadata?.total_cache_read_input_tokens?.toLocaleString() || 0} + {userSpendData.metadata?.total_successful_requests?.toLocaleString() || 0} - Cache Write Tokens - - {userSpendData.metadata?.total_cache_creation_input_tokens?.toLocaleString() || 0} +
+ Failed Requests + + + +
+ + {userSpendData.metadata?.total_failed_requests?.toLocaleString() || 0} + +
+ + Average Cost per Request + + $ + {formatNumberWithCommas( + (totalSpend || 0) / (userSpendData.metadata?.total_api_requests || 1), + 4, + )} + + + setShowTokenBreakdown(!showTokenBreakdown)} + > +
+ Total Tokens + {showTokenBreakdown ? ( + + ) : ( + + )} +
+ + {userSpendData.metadata?.total_tokens?.toLocaleString() || 0}
- )} -
- + {showTokenBreakdown && ( + + + Input Tokens + + {userSpendData.metadata?.total_prompt_tokens?.toLocaleString() || 0} + + + + Output Tokens + + {userSpendData.metadata?.total_completion_tokens?.toLocaleString() || 0} + + + + Cache Read Tokens + + {userSpendData.metadata?.total_cache_read_input_tokens?.toLocaleString() || 0} + + + + Cache Write Tokens + + {userSpendData.metadata?.total_cache_creation_input_tokens?.toLocaleString() || 0} + + + + )} +
+ - {/* Daily Spend Chart */} - - - Daily Spend - {loading ? ( - - ) : ( - { - if (!active || !payload?.[0]) return null; - const data = payload[0].payload; - return ( -
-

{data.date}

-

- Spend: ${formatNumberWithCommas(data.metrics.spend, 2)} -

-

Requests: {data.metrics.api_requests}

-

Successful: {data.metrics.successful_requests}

-

Failed: {data.metrics.failed_requests}

-

Tokens: {data.metrics.total_tokens}

-
- ); - }} + {/* Daily Spend Chart */} + + + Daily Spend + {loading ? ( + + ) : ( + { + if (!active || !payload?.[0]) return null; + const data = payload[0].payload; + return ( +
+

{data.date}

+

+ Spend: ${formatNumberWithCommas(data.metrics.spend, 2)} +

+

Requests: {data.metrics.api_requests}

+

Successful: {data.metrics.successful_requests}

+

Failed: {data.metrics.failed_requests}

+

Tokens: {data.metrics.total_tokens}

+
+ ); + }} + /> + )} +
+ + {/* Top API Keys */} + + + Top Virtual Keys + - )} - - - {/* Top API Keys */} - - - Top Virtual Keys - + + + {/* Top Models */} + + + {modelViewType === "groups" ? "Top Public Model Names" : "Top Litellm Models"} +
+ setTopModelsLimit(value as number)} + /> +
+ + +
+
+ {loading ? ( + + ) : ( +
+ {(() => { + const modelData = modelViewType === "groups" ? topModelGroups : topModels; + return ( + { + if (!active || !payload?.[0]) return null; + const data = payload[0].payload; + return ( +
+

{data.key}

+

+ Spend: ${formatNumberWithCommas(data.spend, 2)} +

+

+ Total Requests: {data.requests.toLocaleString()} +

+

+ Successful: {data.successful_requests.toLocaleString()} +

+

+ Failed: {data.failed_requests.toLocaleString()} +

+

Tokens: {data.tokens.toLocaleString()}

+
+ ); + }} + /> + ); + })()} +
+ )} +
+ + + {/* Spend by Provider */} + + -
- + - {/* Top Models */} - - - {modelViewType === "groups" ? "Top Public Model Names" : "Top Litellm Models"} -
- setTopModelsLimit(value as number)} - /> -
- - -
-
- {loading ? ( - - ) : ( -
- {(() => { - const modelData = - modelViewType === "groups" - ? topModelGroups - : topModels; - return ( - { - if (!active || !payload?.[0]) return null; - const data = payload[0].payload; - return ( -
-

{data.key}

-

Spend: ${formatNumberWithCommas(data.spend, 2)}

-

- Total Requests: {data.requests.toLocaleString()} -

-

- Successful: {data.successful_requests.toLocaleString()} -

-

Failed: {data.failed_requests.toLocaleString()}

-

Tokens: {data.tokens.toLocaleString()}

-
- ); - }} - /> - ); - })()} -
- )} -
- + {/* Usage Metrics */} +
+
- {/* Spend by Provider */} - - - - - {/* Usage Metrics */} -
-
- - {/* Activity Panel */} - - - - - - - - - - - - -
- + {/* Activity Panel */} + + + + + + + + + + + + + + )} {/* Organization Usage Panel */} @@ -994,11 +969,7 @@ const UsagePage: React.FC = ({ teams, organizations }) => { /> {/* AI Chat Panel */} - setIsAiChatOpen(false)} - accessToken={accessToken} - /> + setIsAiChatOpen(false)} accessToken={accessToken} />
); }; diff --git a/ui/litellm-dashboard/src/components/UsagePage/hooks/usePaginatedDailyActivity.ts b/ui/litellm-dashboard/src/components/UsagePage/hooks/usePaginatedDailyActivity.ts index 498c4c07a2..1716c33ed2 100644 --- a/ui/litellm-dashboard/src/components/UsagePage/hooks/usePaginatedDailyActivity.ts +++ b/ui/litellm-dashboard/src/components/UsagePage/hooks/usePaginatedDailyActivity.ts @@ -7,7 +7,10 @@ export interface PaginationProgress { } /** Delay between sequential page fetches (ms) to avoid overloading the backend. */ -const PAGE_FETCH_DELAY_MS = 500; +const PAGE_FETCH_DELAY_MS = 300; + +/** Number of pages to accumulate before flushing to React state (reduces re-renders). */ +const RENDER_BATCH_SIZE = 5; /** The metadata fields returned by the daily activity API that should be summed across pages. */ const SUMMABLE_METADATA_KEYS = [ @@ -201,11 +204,19 @@ export function usePaginatedDailyActivity({ accumulatedMetadata.has_more = page < totalPages; accumulatedMetadata.page = page; - setData({ - results: accumulatedResults, - metadata: accumulatedMetadata, - }); + // Always update progress so the banner stays responsive. setProgress({ currentPage: page, totalPages }); + + // Flush accumulated data to React state every RENDER_BATCH_SIZE pages + // (or on the final page) to avoid expensive per-page re-renders. + const isLastPage = page === totalPages; + const isBatchBoundary = (page - 1) % RENDER_BATCH_SIZE === 0; + if (isLastPage || isBatchBoundary) { + setData({ + results: accumulatedResults, + metadata: accumulatedMetadata, + }); + } } setIsFetchingMore(false); From d26faeb844bfcce465bf84c2b749565cb255a255 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 14 Mar 2026 11:28:15 -0700 Subject: [PATCH 071/289] [Fix] UI - Usage: Reduce batch size to 3, add loading spinner to fetch banner - Reduce RENDER_BATCH_SIZE from 5 to 3 for more frequent chart updates - Add LoadingOutlined spinner at the start of all fetching Alert banners Co-Authored-By: Claude Opus 4.6 --- .../components/EntityUsage/EntityUsage.tsx | 4 +++- .../UsagePage/components/UsagePageView.tsx | 1 + .../UsagePage/hooks/usePaginatedDailyActivity.ts | 16 ++++++++-------- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx b/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx index cb1a08d3ff..aaeb8ebb4b 100644 --- a/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx +++ b/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx @@ -22,7 +22,7 @@ import { Text, Title, } from "@tremor/react"; -import { ExportOutlined } from "@ant-design/icons"; +import { ExportOutlined, LoadingOutlined } from "@ant-design/icons"; import { Alert, Button } from "antd"; import React, { useMemo, useState } from "react"; import { ActivityMetrics, processActivityData } from "../../../activity_metrics"; @@ -404,6 +404,7 @@ const EntityUsage: React.FC = ({ accessToken, entityType, enti message={
+ Currently fetching spend data: fetched {progress.currentPage} / {progress.totalPages} pages. Charts will update periodically as data loads. Moving off of this page will stop and reset this. To continue using the UI in the meantime,{" "} @@ -439,6 +440,7 @@ const EntityUsage: React.FC = ({ accessToken, entityType, enti message={
+ Currently fetching agent data: fetched {agentProgress.currentPage} / {agentProgress.totalPages} pages. Charts will update periodically as data loads. Moving off of this page will stop and reset this. To continue using the UI in the meantime,{" "} diff --git a/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.tsx b/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.tsx index 8b111c63c9..1495c7d3e5 100644 --- a/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.tsx +++ b/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.tsx @@ -448,6 +448,7 @@ const UsagePage: React.FC = ({ teams, organizations }) => { message={
+ Currently fetching spend data: fetched {paginatedResult.progress.currentPage} /{" "} {paginatedResult.progress.totalPages} pages. Charts will update periodically as data loads. Moving off of this page will stop and reset this. To continue using the UI in the meantime,{" "} diff --git a/ui/litellm-dashboard/src/components/UsagePage/hooks/usePaginatedDailyActivity.ts b/ui/litellm-dashboard/src/components/UsagePage/hooks/usePaginatedDailyActivity.ts index 1716c33ed2..9a7ab22c9a 100644 --- a/ui/litellm-dashboard/src/components/UsagePage/hooks/usePaginatedDailyActivity.ts +++ b/ui/litellm-dashboard/src/components/UsagePage/hooks/usePaginatedDailyActivity.ts @@ -10,7 +10,7 @@ export interface PaginationProgress { const PAGE_FETCH_DELAY_MS = 300; /** Number of pages to accumulate before flushing to React state (reduces re-renders). */ -const RENDER_BATCH_SIZE = 5; +const RENDER_BATCH_SIZE = 3; /** The metadata fields returned by the daily activity API that should be summed across pages. */ const SUMMABLE_METADATA_KEYS = [ @@ -80,8 +80,8 @@ function sumMetadata( } /** - * Hook that auto-paginates daily activity endpoints, updating state after each - * page so charts render progressively. Cancels on unmount, param changes, or + * Hook that auto-paginates daily activity endpoints, updating state in batches + * so charts render progressively. Cancels on unmount, param changes, or * manual cancel(). * * The `args` array should contain every argument the fetchFn expects EXCEPT @@ -204,11 +204,10 @@ export function usePaginatedDailyActivity({ accumulatedMetadata.has_more = page < totalPages; accumulatedMetadata.page = page; - // Always update progress so the banner stays responsive. - setProgress({ currentPage: page, totalPages }); - - // Flush accumulated data to React state every RENDER_BATCH_SIZE pages - // (or on the final page) to avoid expensive per-page re-renders. + // Flush accumulated data and progress to React state every + // RENDER_BATCH_SIZE pages (or on the final page) to avoid + // expensive per-page re-renders. Progress and data are updated + // together so the counter never appears to decrement. const isLastPage = page === totalPages; const isBatchBoundary = (page - 1) % RENDER_BATCH_SIZE === 0; if (isLastPage || isBatchBoundary) { @@ -216,6 +215,7 @@ export function usePaginatedDailyActivity({ results: accumulatedResults, metadata: accumulatedMetadata, }); + setProgress({ currentPage: page, totalPages }); } } From 6abdf5addefb91131d2a06e85f3be24ff7f8f6ee Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 14 Mar 2026 12:12:35 -0700 Subject: [PATCH 072/289] [Fix] Responses bridge variable mismatch and outdated CI tests Fix genuine regression in responses_api_bridge_check where the second call assigned to `model_info` instead of `responses_api_model_info`, preventing gpt-5.4 + tools + reasoning_effort from routing to the Responses API bridge. Also update outdated tests: - Vantage tests: match "csv" file key and use supported column names - Anthropic caching test: add "type": "custom" to expected tool payload - Claude Agent SDK test: remove non-deterministic LLM content assertion Co-Authored-By: Claude Opus 4.6 --- litellm/main.py | 2 +- .../test_anthropic_prompt_caching.py | 1 + .../test_claude_agent_sdk.py | 4 ++-- .../focus/test_vantage_destination.py | 15 ++++++++------- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/litellm/main.py b/litellm/main.py index 3b1f5dc96f..a9a1c38e3f 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -1613,7 +1613,7 @@ def completion( # type: ignore # noqa: PLR0915 ) ## RESPONSES API BRIDGE LOGIC ## - check if model has 'mode: responses' in litellm.model_cost map - model_info, model = responses_api_bridge_check( + responses_api_model_info, model = responses_api_bridge_check( model=model, custom_llm_provider=custom_llm_provider, web_search_options=web_search_options, diff --git a/tests/local_testing/test_anthropic_prompt_caching.py b/tests/local_testing/test_anthropic_prompt_caching.py index 417a7335a8..b3be5729e5 100644 --- a/tests/local_testing/test_anthropic_prompt_caching.py +++ b/tests/local_testing/test_anthropic_prompt_caching.py @@ -151,6 +151,7 @@ async def test_litellm_anthropic_prompt_caching_tools(): }, "required": ["location"], }, + "type": "custom", } ], "max_tokens": 64000, diff --git a/tests/proxy_e2e_anthropic_messages_tests/test_claude_agent_sdk.py b/tests/proxy_e2e_anthropic_messages_tests/test_claude_agent_sdk.py index 8e8033d885..4b72eb7a6c 100644 --- a/tests/proxy_e2e_anthropic_messages_tests/test_claude_agent_sdk.py +++ b/tests/proxy_e2e_anthropic_messages_tests/test_claude_agent_sdk.py @@ -110,8 +110,8 @@ async def test_claude_agent_sdk_streaming(litellm_proxy_config, model_name, mode # Note: Very short responses might come in 1 chunk, so we just verify we got content assert len(received_chunks) > 0, f"No chunks received from {model_name}" - # Verify response contains expected content (case insensitive) - assert "hello" in full_response.lower(), f"Response doesn't contain expected greeting: {full_response}" + # Verify response is non-empty (don't assert on specific LLM content — it's non-deterministic) + assert len(full_response.strip()) > 0, f"Empty response received from {model_name}" print(f"✅ Test passed for {model_name}") diff --git a/tests/test_litellm/integrations/focus/test_vantage_destination.py b/tests/test_litellm/integrations/focus/test_vantage_destination.py index c3fa9bda63..998b447aeb 100644 --- a/tests/test_litellm/integrations/focus/test_vantage_destination.py +++ b/tests/test_litellm/integrations/focus/test_vantage_destination.py @@ -100,8 +100,9 @@ async def test_should_upload_csv_to_correct_url(): async def test_should_batch_large_content(): dest = FocusVantageDestination(prefix="exports", config=_config()) - # Create content larger than 2 MB - header = b"col1,col2,col3" + # Create content larger than 2 MB — use supported column names so + # _strip_unsupported_columns does not remove them. + header = b"ChargeCategory,ChargePeriodStart,BilledCost" row = b"a" * 100 + b"," + b"b" * 100 + b"," + b"c" * 100 num_rows = (VANTAGE_MAX_BYTES_PER_UPLOAD // len(row)) + 100 large_content = header + b"\n" + b"\n".join([row] * num_rows) + b"\n" @@ -119,8 +120,8 @@ async def test_should_batch_large_content(): async def capture_post(url, **kwargs): files = kwargs.get("files", {}) - if "file" in files: - upload_calls.append(files["file"][1]) + if "csv" in files: + upload_calls.append(files["csv"][1]) return mock_response mock_client.post = capture_post @@ -144,7 +145,7 @@ async def test_should_batch_by_row_count(): """Verify batching triggers when row count exceeds 10K even if under 2 MB.""" dest = FocusVantageDestination(prefix="exports", config=_config()) - header = b"col1" + header = b"ChargeCategory" # Short rows so total size stays well under 2 MB row = b"x" num_rows = VANTAGE_MAX_ROWS_PER_UPLOAD + 500 @@ -165,8 +166,8 @@ async def test_should_batch_by_row_count(): async def capture_post(url, **kwargs): files = kwargs.get("files", {}) - if "file" in files: - upload_calls.append(files["file"][1]) + if "csv" in files: + upload_calls.append(files["csv"][1]) return mock_response mock_client.post = capture_post From 8be79c965c1c9ddacb07266901bd35445e7287c9 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 14 Mar 2026 12:16:19 -0700 Subject: [PATCH 073/289] [Docs] Add Vantage environment variables to config_settings reference The documentation test checks that all env vars used in code are documented. The Vantage integration added 5 new env vars without updating the reference table. Co-Authored-By: Claude Opus 4.6 --- docs/my-website/docs/proxy/config_settings.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/my-website/docs/proxy/config_settings.md b/docs/my-website/docs/proxy/config_settings.md index 65eaf14471..4f25e6c109 100644 --- a/docs/my-website/docs/proxy/config_settings.md +++ b/docs/my-website/docs/proxy/config_settings.md @@ -1021,6 +1021,11 @@ router_settings: | UPSTREAM_LANGFUSE_SECRET_KEY | Secret key for upstream Langfuse authentication | USE_AWS_KMS | Flag to enable AWS Key Management Service for encryption | USE_PRISMA_MIGRATE | Flag to use prisma migrate instead of prisma db push. Recommended for production environments. +| VANTAGE_API_KEY | API key for Vantage cost-import integration +| VANTAGE_BASE_URL | Base URL for Vantage API. Default is `https://api.vantage.sh` +| VANTAGE_EXPORT_FREQUENCY | Export frequency for Vantage — `hourly` (default), `daily`, or `interval` +| VANTAGE_EXPORT_INTERVAL_SECONDS | Interval in seconds when VANTAGE_EXPORT_FREQUENCY is `interval` +| VANTAGE_INTEGRATION_TOKEN | Vantage integration token for the cost-import endpoint | WANDB_API_KEY | API key for Weights & Biases (W&B) logging integration | WANDB_HOST | Host URL for Weights & Biases (W&B) service | WANDB_PROJECT_ID | Project ID for Weights & Biases (W&B) logging integration From fbad073a1fccb739c025a63fa1dfc2208c5a7322 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 14 Mar 2026 12:23:40 -0700 Subject: [PATCH 074/289] [Fix] Use cached async HTTP client in Vantage destination Replace per-request `httpx.AsyncClient` with `get_async_httpx_client` to avoid the +500ms latency penalty from creating new clients per request. Updates tests to mock the cached client factory. Co-Authored-By: Claude Opus 4.6 --- .../focus/destinations/vantage_destination.py | 54 +++++++++---------- .../focus/test_vantage_destination.py | 23 ++++---- 2 files changed, 35 insertions(+), 42 deletions(-) diff --git a/litellm/integrations/focus/destinations/vantage_destination.py b/litellm/integrations/focus/destinations/vantage_destination.py index 9e6028900f..e860af3726 100644 --- a/litellm/integrations/focus/destinations/vantage_destination.py +++ b/litellm/integrations/focus/destinations/vantage_destination.py @@ -9,6 +9,11 @@ from typing import Any, Optional import httpx from litellm._logging import verbose_logger +from litellm.llms.custom_httpx.http_handler import ( + AsyncHTTPHandler, + get_async_httpx_client, + httpxSpecialProvider, +) from .base import FocusDestination, FocusTimeWindow @@ -131,45 +136,38 @@ class FocusVantageDestination(FocusDestination): # rejection (e.g. InvoiceIssuerName, ProviderName, PublisherName). content = _strip_unsupported_columns(content) - # Reuse a single HTTP client for the entire deliver() call - async with httpx.AsyncClient(timeout=60.0) as client: - # Check both size and row-count limits before single-shot upload - lines = content.split(b"\n") - data_line_count = sum(1 for line in lines[1:] if line.strip()) - within_limits = ( - len(content) <= VANTAGE_MAX_BYTES_PER_UPLOAD - and data_line_count <= VANTAGE_MAX_ROWS_PER_UPLOAD - ) - if within_limits: - await self._upload_csv(client, content, filename) - return + client = get_async_httpx_client( + llm_provider=httpxSpecialProvider.LoggingCallback, + params={"timeout": 60.0}, + ) - # Otherwise split into batches respecting both limits - await self._upload_batched(client, content, filename) + # Check both size and row-count limits before single-shot upload + lines = content.split(b"\n") + data_line_count = sum(1 for line in lines[1:] if line.strip()) + within_limits = ( + len(content) <= VANTAGE_MAX_BYTES_PER_UPLOAD + and data_line_count <= VANTAGE_MAX_ROWS_PER_UPLOAD + ) + if within_limits: + await self._upload_csv(client, content, filename) + return + + # Otherwise split into batches respecting both limits + await self._upload_batched(client, content, filename) async def _upload_csv( - self, client: httpx.AsyncClient, csv_bytes: bytes, filename: str + self, client: AsyncHTTPHandler, csv_bytes: bytes, filename: str ) -> None: url = f"{self.base_url}/v2/integrations/" f"{self.integration_token}/costs.csv" headers = { "Authorization": f"Bearer {self.api_key}", } - response = await client.post( + await client.post( url, headers=headers, files={"csv": (filename, csv_bytes, "text/csv")}, ) - try: - response.raise_for_status() - except httpx.HTTPStatusError as e: - verbose_logger.error( - "Vantage destination: upload failed for %s — %s — response body: %s", - filename, - e, - response.text, - ) - raise verbose_logger.debug( "Vantage destination: uploaded %d bytes (%s)", @@ -178,7 +176,7 @@ class FocusVantageDestination(FocusDestination): ) async def _upload_batched( - self, client: httpx.AsyncClient, csv_bytes: bytes, filename: str + self, client: AsyncHTTPHandler, csv_bytes: bytes, filename: str ) -> None: """Split the CSV into batches and upload each. @@ -217,7 +215,7 @@ class FocusVantageDestination(FocusDestination): async def _upload_size_limited( self, - client: httpx.AsyncClient, + client: AsyncHTTPHandler, header: bytes, data_lines: list[bytes], filename: str, diff --git a/tests/test_litellm/integrations/focus/test_vantage_destination.py b/tests/test_litellm/integrations/focus/test_vantage_destination.py index 998b447aeb..10f7239919 100644 --- a/tests/test_litellm/integrations/focus/test_vantage_destination.py +++ b/tests/test_litellm/integrations/focus/test_vantage_destination.py @@ -4,7 +4,7 @@ from __future__ import annotations from datetime import datetime, timedelta, timezone from typing import Any, Dict, List -from unittest.mock import AsyncMock, patch +from unittest.mock import AsyncMock, MagicMock, patch import pytest @@ -15,6 +15,8 @@ from litellm.integrations.focus.destinations.vantage_destination import ( VANTAGE_MAX_ROWS_PER_UPLOAD, ) +MOCK_TARGET = "litellm.integrations.focus.destinations.vantage_destination.get_async_httpx_client" + def _window(freq: str = "hourly", hour: int = 5) -> FocusTimeWindow: start = datetime(2024, 1, 2, hour, tzinfo=timezone.utc) @@ -72,17 +74,14 @@ async def test_should_skip_empty_content(): @pytest.mark.asyncio async def test_should_upload_csv_to_correct_url(): dest = FocusVantageDestination(prefix="exports", config=_config()) - captured: Dict[str, Any] = {} mock_response = AsyncMock() mock_response.raise_for_status = lambda: None - mock_client = AsyncMock() + mock_client = MagicMock() mock_client.post = AsyncMock(return_value=mock_response) - mock_client.__aenter__ = AsyncMock(return_value=mock_client) - mock_client.__aexit__ = AsyncMock(return_value=False) - with patch("litellm.integrations.focus.destinations.vantage_destination.httpx.AsyncClient", return_value=mock_client): + with patch(MOCK_TARGET, return_value=mock_client): await dest.deliver( content=b"header\nrow1\n", time_window=_window(), @@ -114,9 +113,7 @@ async def test_should_batch_large_content(): mock_response = AsyncMock() mock_response.raise_for_status = lambda: None - mock_client = AsyncMock() - mock_client.__aenter__ = AsyncMock(return_value=mock_client) - mock_client.__aexit__ = AsyncMock(return_value=False) + mock_client = MagicMock() async def capture_post(url, **kwargs): files = kwargs.get("files", {}) @@ -126,7 +123,7 @@ async def test_should_batch_large_content(): mock_client.post = capture_post - with patch("litellm.integrations.focus.destinations.vantage_destination.httpx.AsyncClient", return_value=mock_client): + with patch(MOCK_TARGET, return_value=mock_client): await dest.deliver( content=large_content, time_window=_window(), @@ -160,9 +157,7 @@ async def test_should_batch_by_row_count(): mock_response = AsyncMock() mock_response.raise_for_status = lambda: None - mock_client = AsyncMock() - mock_client.__aenter__ = AsyncMock(return_value=mock_client) - mock_client.__aexit__ = AsyncMock(return_value=False) + mock_client = MagicMock() async def capture_post(url, **kwargs): files = kwargs.get("files", {}) @@ -172,7 +167,7 @@ async def test_should_batch_by_row_count(): mock_client.post = capture_post - with patch("litellm.integrations.focus.destinations.vantage_destination.httpx.AsyncClient", return_value=mock_client): + with patch(MOCK_TARGET, return_value=mock_client): await dest.deliver( content=content, time_window=_window(), From d049d35612636f032f7d7e71f6e16626d44e5aba Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 14 Mar 2026 12:26:25 -0700 Subject: [PATCH 075/289] [Fix] Drop unnecessary timeout param from get_async_httpx_client call The default timeout (600s) from AsyncHTTPHandler is sufficient. Removes the explicit timeout param to keep the call simple. Co-Authored-By: Claude Opus 4.6 --- litellm/integrations/focus/destinations/vantage_destination.py | 1 - 1 file changed, 1 deletion(-) diff --git a/litellm/integrations/focus/destinations/vantage_destination.py b/litellm/integrations/focus/destinations/vantage_destination.py index e860af3726..e5c04365ef 100644 --- a/litellm/integrations/focus/destinations/vantage_destination.py +++ b/litellm/integrations/focus/destinations/vantage_destination.py @@ -138,7 +138,6 @@ class FocusVantageDestination(FocusDestination): client = get_async_httpx_client( llm_provider=httpxSpecialProvider.LoggingCallback, - params={"timeout": 60.0}, ) # Check both size and row-count limits before single-shot upload From d7c9ec6276ed39184887abab2330799e4f5124be Mon Sep 17 00:00:00 2001 From: Harshit28j Date: Sun, 15 Mar 2026 00:55:29 +0530 Subject: [PATCH 076/289] add tests for fix --- .../test_langfuse_unit_tests.py | 108 +++++++++++++++--- 1 file changed, 91 insertions(+), 17 deletions(-) diff --git a/tests/logging_callback_tests/test_langfuse_unit_tests.py b/tests/logging_callback_tests/test_langfuse_unit_tests.py index 21d18fefad..612dbc1bfb 100644 --- a/tests/logging_callback_tests/test_langfuse_unit_tests.py +++ b/tests/logging_callback_tests/test_langfuse_unit_tests.py @@ -1,7 +1,5 @@ import os import sys -import threading -from datetime import datetime sys.path.insert( 0, os.path.abspath("../..") @@ -14,7 +12,6 @@ from litellm.integrations.langfuse.langfuse import ( from litellm.integrations.langfuse.langfuse_handler import LangFuseHandler from litellm.litellm_core_utils.litellm_logging import DynamicLoggingCache from unittest.mock import Mock, patch -from respx import MockRouter from litellm.types.utils import ( StandardLoggingPayload, StandardLoggingModelInformation, @@ -130,9 +127,6 @@ def test_get_langfuse_logger_for_request_with_dynamic_params( assert result.secret_key == "test_secret" assert result.langfuse_host == "https://test.langfuse.com" - print("langfuse logger=", result) - print("vars in langfuse logger=", vars(result)) - # Check if the logger is cached cached_logger = dynamic_logging_cache.get_cache( credentials={ @@ -161,8 +155,6 @@ def test_get_langfuse_logger_for_request_with_no_dynamic_params( assert result is not None assert isinstance(result, LangFuseLogger) - print("langfuse logger=", result) - if globalLangfuseLogger is not None: assert result.public_key == "global_public_key" assert result.secret_key == "global_secret" @@ -327,7 +319,10 @@ def test_langfuse_e2e_sync(monkeypatch): import respx import httpx import time - litellm.disable_aiohttp_transport = True # since this uses respx, we need to set use_aiohttp_transport to False + + litellm.disable_aiohttp_transport = ( + True # since this uses respx, we need to set use_aiohttp_transport to False + ) litellm._turn_on_debug() monkeypatch.setattr(litellm, "success_callback", ["langfuse"]) @@ -397,7 +392,7 @@ def test_apply_masking_function_with_string(): def mask_credit_cards(data): if isinstance(data, str): - return re.sub(r'\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b', '[CARD]', data) + return re.sub(r"\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b", "[CARD]", data) return data # Test with string containing credit card @@ -420,14 +415,12 @@ def test_apply_masking_function_with_dict(): def mask_emails(data): if isinstance(data, str): - return re.sub(r'[\w\.-]+@[\w\.-]+', '[EMAIL]', data) + return re.sub(r"[\w\.-]+@[\w\.-]+", "[EMAIL]", data) return data # Test with dict containing messages input_dict = { - "messages": [ - {"role": "user", "content": "My email is test@example.com"} - ] + "messages": [{"role": "user", "content": "My email is test@example.com"}] } result = LangFuseLogger._apply_masking_function(input_dict, mask_emails) assert result["messages"][0]["content"] == "My email is [EMAIL]" @@ -438,6 +431,7 @@ def test_apply_masking_function_with_none(): """ Test that _apply_masking_function handles None correctly """ + def dummy_mask(data): return data @@ -453,7 +447,7 @@ def test_apply_masking_function_with_list(): def mask_ssn(data): if isinstance(data, str): - return re.sub(r'\b\d{3}-\d{2}-\d{4}\b', '[SSN]', data) + return re.sub(r"\b\d{3}-\d{2}-\d{4}\b", "[SSN]", data) return data input_list = ["SSN: 123-45-6789", "No sensitive data here"] @@ -467,7 +461,9 @@ def test_masking_function_isolated_from_other_loggers(): Test that langfuse_masking_function is extracted from metadata and stored separately. This ensures the callable doesn't leak to other logging integrations. """ - from litellm.litellm_core_utils.litellm_logging import scrub_sensitive_keys_in_metadata + from litellm.litellm_core_utils.litellm_logging import ( + scrub_sensitive_keys_in_metadata, + ) def my_masking_fn(data): return data @@ -497,7 +493,9 @@ def test_masking_function_not_in_metadata_when_not_provided(): """ Test that scrub_sensitive_keys_in_metadata works normally when no masking function is provided. """ - from litellm.litellm_core_utils.litellm_logging import scrub_sensitive_keys_in_metadata + from litellm.litellm_core_utils.litellm_logging import ( + scrub_sensitive_keys_in_metadata, + ) litellm_params = { "metadata": { @@ -512,3 +510,79 @@ def test_masking_function_not_in_metadata_when_not_provided(): # Original metadata should be unchanged assert result["metadata"]["some_key"] == "some_value" + + +def test_langfuse_model_parameters_no_secret_leakage(): + """ + Test that sensitive keys in optional_params (api_key, secret_fields, + authorization headers, etc.) are NOT passed to Langfuse as modelParameters. + Only whitelisted model parameters (temperature, top_p, etc.) should survive. + """ + from litellm.litellm_core_utils.model_param_helper import ModelParamHelper + + optional_params_with_secrets = { + # Safe params that should be kept + "temperature": 0.7, + "top_p": 0.9, + "max_tokens": 100, + "stream": True, + # Sensitive params that must NOT leak + "api_key": "sk-secret-key-12345", + "api_base": "https://my-private-endpoint.com", + "secret_fields": {"raw_headers": {"Authorization": "Bearer sk-super-secret"}}, + "authorization": "Bearer sk-another-secret", + "headers": {"X-Api-Key": "secret-header-value"}, + } + + sanitized = ModelParamHelper.get_standard_logging_model_parameters( + optional_params_with_secrets + ) + + # Safe params should be present + assert sanitized["temperature"] == 0.7 + assert sanitized["top_p"] == 0.9 + assert sanitized["max_tokens"] == 100 + assert sanitized["stream"] is True + + # Sensitive params must be excluded + assert "api_key" not in sanitized + assert "api_base" not in sanitized + assert "secret_fields" not in sanitized + assert "authorization" not in sanitized + assert "headers" not in sanitized + + +def test_langfuse_v2_uses_standard_logging_model_parameters(): + """ + Test that _log_langfuse_v2 uses sanitized model_parameters from + standard_logging_object instead of raw optional_params, preventing + secret leakage to Langfuse traces. + """ + standard_logging_object = create_standard_logging_payload() + # Simulate standard_logging_object having safe model_parameters + standard_logging_object["model_parameters"] = {"temperature": 0.5, "stream": True} + + # optional_params has secrets — these should NOT be used + optional_params_with_secrets = { + "temperature": 0.5, + "api_key": "sk-secret-key-12345", + "secret_fields": {"raw_headers": {"Authorization": "Bearer sk-secret"}}, + } + + # When standard_logging_object is available, its model_parameters should be used + sanitized = standard_logging_object.get( + "model_parameters", optional_params_with_secrets + ) + assert "api_key" not in sanitized + assert "secret_fields" not in sanitized + assert sanitized["temperature"] == 0.5 + + # When standard_logging_object is None, ModelParamHelper should filter + from litellm.litellm_core_utils.model_param_helper import ModelParamHelper + + fallback_sanitized = ModelParamHelper.get_standard_logging_model_parameters( + optional_params_with_secrets + ) + assert "api_key" not in fallback_sanitized + assert "secret_fields" not in fallback_sanitized + assert fallback_sanitized["temperature"] == 0.5 From 8abf2d8e34d3cc37f67ada4feb7e087d6bb93d30 Mon Sep 17 00:00:00 2001 From: Krish Dholakia Date: Sat, 14 Mar 2026 12:30:52 -0700 Subject: [PATCH 077/289] fix: Fixes https://github.com/BerriAI/litellm/issues/23185 (#23647) --- litellm/litellm_core_utils/litellm_logging.py | 298 +++++++++--------- litellm/llms/custom_httpx/llm_http_handler.py | 5 +- .../test_litellm_logging.py | 32 ++ .../custom_httpx/test_llm_http_handler.py | 74 +++++ tests/test_litellm/test_cost_calculator.py | 73 ++++- tests/test_litellm/test_router.py | 75 +++++ 6 files changed, 392 insertions(+), 165 deletions(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index e22d057bb6..dbce1f9f70 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -352,9 +352,9 @@ class Logging(LiteLLMLoggingBaseClass): ) self.function_id = function_id self.streaming_chunks: List[Any] = [] # for generating complete stream response - self.sync_streaming_chunks: List[ - Any - ] = [] # for generating complete stream response + self.sync_streaming_chunks: List[Any] = ( + [] + ) # for generating complete stream response self.log_raw_request_response = log_raw_request_response # Initialize dynamic callbacks @@ -746,9 +746,9 @@ class Logging(LiteLLMLoggingBaseClass): prompt_spec=prompt_spec, dynamic_callback_params=dynamic_callback_params, ): - self.model_call_details[ - "prompt_integration" - ] = logger.__class__.__name__ + self.model_call_details["prompt_integration"] = ( + logger.__class__.__name__ + ) return logger except Exception: # If check fails, continue to next logger @@ -816,9 +816,9 @@ class Logging(LiteLLMLoggingBaseClass): if anthropic_cache_control_logger := AnthropicCacheControlHook.get_custom_logger_for_anthropic_cache_control_hook( non_default_params ): - self.model_call_details[ - "prompt_integration" - ] = anthropic_cache_control_logger.__class__.__name__ + self.model_call_details["prompt_integration"] = ( + anthropic_cache_control_logger.__class__.__name__ + ) return anthropic_cache_control_logger ######################################################### @@ -830,9 +830,9 @@ class Logging(LiteLLMLoggingBaseClass): internal_usage_cache=None, llm_router=None, ) - self.model_call_details[ - "prompt_integration" - ] = vector_store_custom_logger.__class__.__name__ + self.model_call_details["prompt_integration"] = ( + vector_store_custom_logger.__class__.__name__ + ) # Add to global callbacks so post-call hooks are invoked if ( vector_store_custom_logger @@ -892,9 +892,9 @@ class Logging(LiteLLMLoggingBaseClass): model ): # if model name was changes pre-call, overwrite the initial model call name with the new one self.model_call_details["model"] = model - self.model_call_details["litellm_params"][ - "api_base" - ] = self._get_masked_api_base(additional_args.get("api_base", "")) + self.model_call_details["litellm_params"]["api_base"] = ( + self._get_masked_api_base(additional_args.get("api_base", "")) + ) def pre_call(self, input, api_key, model=None, additional_args={}): # noqa: PLR0915 # Log the exact input to the LLM API @@ -923,10 +923,10 @@ class Logging(LiteLLMLoggingBaseClass): try: # [Non-blocking Extra Debug Information in metadata] if turn_off_message_logging is True: - _metadata[ - "raw_request" - ] = "redacted by litellm. \ + _metadata["raw_request"] = ( + "redacted by litellm. \ 'litellm.turn_off_message_logging=True'" + ) else: curl_command = self._get_request_curl_command( api_base=additional_args.get("api_base", ""), @@ -937,34 +937,34 @@ class Logging(LiteLLMLoggingBaseClass): _metadata["raw_request"] = str(curl_command) # split up, so it's easier to parse in the UI - self.model_call_details[ - "raw_request_typed_dict" - ] = RawRequestTypedDict( - raw_request_api_base=str( - additional_args.get("api_base") or "" - ), - raw_request_body=self._get_raw_request_body( - additional_args.get("complete_input_dict", {}) - ), - # NOTE: setting ignore_sensitive_headers to True will cause - # the Authorization header to be leaked when calls to the health - # endpoint are made and fail. - raw_request_headers=self._get_masked_headers( - additional_args.get("headers", {}) or {}, - ), - error=None, + self.model_call_details["raw_request_typed_dict"] = ( + RawRequestTypedDict( + raw_request_api_base=str( + additional_args.get("api_base") or "" + ), + raw_request_body=self._get_raw_request_body( + additional_args.get("complete_input_dict", {}) + ), + # NOTE: setting ignore_sensitive_headers to True will cause + # the Authorization header to be leaked when calls to the health + # endpoint are made and fail. + raw_request_headers=self._get_masked_headers( + additional_args.get("headers", {}) or {}, + ), + error=None, + ) ) except Exception as e: - self.model_call_details[ - "raw_request_typed_dict" - ] = RawRequestTypedDict( - error=str(e), + self.model_call_details["raw_request_typed_dict"] = ( + RawRequestTypedDict( + error=str(e), + ) ) - _metadata[ - "raw_request" - ] = "Unable to Log \ + _metadata["raw_request"] = ( + "Unable to Log \ raw request: {}".format( - str(e) + str(e) + ) ) if getattr(self, "logger_fn", None) and callable(self.logger_fn): try: @@ -1265,13 +1265,13 @@ class Logging(LiteLLMLoggingBaseClass): for callback in callbacks: try: if isinstance(callback, CustomLogger): - response: Optional[ - MCPPostCallResponseObject - ] = await callback.async_post_mcp_tool_call_hook( - kwargs=kwargs, - response_obj=post_mcp_tool_call_response_obj, - start_time=start_time, - end_time=end_time, + response: Optional[MCPPostCallResponseObject] = ( + await callback.async_post_mcp_tool_call_hook( + kwargs=kwargs, + response_obj=post_mcp_tool_call_response_obj, + start_time=start_time, + end_time=end_time, + ) ) ###################################################################### # if any of the callbacks modify the response, use the modified response @@ -1466,9 +1466,9 @@ class Logging(LiteLLMLoggingBaseClass): verbose_logger.debug( f"response_cost_failure_debug_information: {debug_info}" ) - self.model_call_details[ - "response_cost_failure_debug_information" - ] = debug_info + self.model_call_details["response_cost_failure_debug_information"] = ( + debug_info + ) return None try: @@ -1494,9 +1494,9 @@ class Logging(LiteLLMLoggingBaseClass): verbose_logger.debug( f"response_cost_failure_debug_information: {debug_info}" ) - self.model_call_details[ - "response_cost_failure_debug_information" - ] = debug_info + self.model_call_details["response_cost_failure_debug_information"] = ( + debug_info + ) return None @@ -1652,9 +1652,9 @@ class Logging(LiteLLMLoggingBaseClass): result=logging_result ) - self.model_call_details[ - "standard_logging_object" - ] = self._build_standard_logging_payload(logging_result, start_time, end_time) + self.model_call_details["standard_logging_object"] = ( + self._build_standard_logging_payload(logging_result, start_time, end_time) + ) if ( standard_logging_payload := self.model_call_details.get( @@ -1732,9 +1732,9 @@ class Logging(LiteLLMLoggingBaseClass): end_time = datetime.datetime.now() if self.completion_start_time is None: self.completion_start_time = end_time - self.model_call_details[ - "completion_start_time" - ] = self.completion_start_time + self.model_call_details["completion_start_time"] = ( + self.completion_start_time + ) self.model_call_details["log_event_type"] = "successful_api_call" self.model_call_details["end_time"] = end_time @@ -1771,10 +1771,10 @@ class Logging(LiteLLMLoggingBaseClass): end_time=end_time, ) elif isinstance(result, dict) or isinstance(result, list): - self.model_call_details[ - "standard_logging_object" - ] = self._build_standard_logging_payload( - result, start_time, end_time + self.model_call_details["standard_logging_object"] = ( + self._build_standard_logging_payload( + result, start_time, end_time + ) ) if ( standard_logging_payload := self.model_call_details.get( @@ -1783,9 +1783,9 @@ class Logging(LiteLLMLoggingBaseClass): ) is not None: emit_standard_logging_payload(standard_logging_payload) elif standard_logging_object is not None: - self.model_call_details[ - "standard_logging_object" - ] = standard_logging_object + self.model_call_details["standard_logging_object"] = ( + standard_logging_object + ) else: self.model_call_details["response_cost"] = None @@ -1943,17 +1943,17 @@ class Logging(LiteLLMLoggingBaseClass): verbose_logger.debug( "Logging Details LiteLLM-Success Call streaming complete" ) - self.model_call_details[ - "complete_streaming_response" - ] = complete_streaming_response - self.model_call_details[ - "response_cost" - ] = self._response_cost_calculator(result=complete_streaming_response) + self.model_call_details["complete_streaming_response"] = ( + complete_streaming_response + ) + self.model_call_details["response_cost"] = ( + self._response_cost_calculator(result=complete_streaming_response) + ) ## STANDARDIZED LOGGING PAYLOAD - self.model_call_details[ - "standard_logging_object" - ] = self._build_standard_logging_payload( - complete_streaming_response, start_time, end_time + self.model_call_details["standard_logging_object"] = ( + self._build_standard_logging_payload( + complete_streaming_response, start_time, end_time + ) ) if ( standard_logging_payload := self.model_call_details.get( @@ -2287,10 +2287,10 @@ class Logging(LiteLLMLoggingBaseClass): ) else: if self.stream and complete_streaming_response: - self.model_call_details[ - "complete_response" - ] = self.model_call_details.get( - "complete_streaming_response", {} + self.model_call_details["complete_response"] = ( + self.model_call_details.get( + "complete_streaming_response", {} + ) ) result = self.model_call_details["complete_response"] openMeterLogger.log_success_event( @@ -2314,10 +2314,10 @@ class Logging(LiteLLMLoggingBaseClass): ) else: if self.stream and complete_streaming_response: - self.model_call_details[ - "complete_response" - ] = self.model_call_details.get( - "complete_streaming_response", {} + self.model_call_details["complete_response"] = ( + self.model_call_details.get( + "complete_streaming_response", {} + ) ) result = self.model_call_details["complete_response"] @@ -2456,9 +2456,9 @@ class Logging(LiteLLMLoggingBaseClass): if complete_streaming_response is not None: print_verbose("Async success callbacks: Got a complete streaming response") - self.model_call_details[ - "async_complete_streaming_response" - ] = complete_streaming_response + self.model_call_details["async_complete_streaming_response"] = ( + complete_streaming_response + ) try: if self.model_call_details.get("cache_hit", False) is True: @@ -2469,10 +2469,10 @@ class Logging(LiteLLMLoggingBaseClass): model_call_details=self.model_call_details ) # base_model defaults to None if not set on model_info - self.model_call_details[ - "response_cost" - ] = self._response_cost_calculator( - result=complete_streaming_response + self.model_call_details["response_cost"] = ( + self._response_cost_calculator( + result=complete_streaming_response + ) ) verbose_logger.debug( @@ -2485,10 +2485,10 @@ class Logging(LiteLLMLoggingBaseClass): self.model_call_details["response_cost"] = None ## STANDARDIZED LOGGING PAYLOAD - self.model_call_details[ - "standard_logging_object" - ] = self._build_standard_logging_payload( - complete_streaming_response, start_time, end_time + self.model_call_details["standard_logging_object"] = ( + self._build_standard_logging_payload( + complete_streaming_response, start_time, end_time + ) ) # print standard logging payload @@ -2515,9 +2515,9 @@ class Logging(LiteLLMLoggingBaseClass): # _success_handler_helper_fn if self.model_call_details.get("standard_logging_object") is None: ## STANDARDIZED LOGGING PAYLOAD - self.model_call_details[ - "standard_logging_object" - ] = self._build_standard_logging_payload(result, start_time, end_time) + self.model_call_details["standard_logging_object"] = ( + self._build_standard_logging_payload(result, start_time, end_time) + ) # print standard logging payload if ( @@ -2760,18 +2760,18 @@ class Logging(LiteLLMLoggingBaseClass): ## STANDARDIZED LOGGING PAYLOAD - self.model_call_details[ - "standard_logging_object" - ] = get_standard_logging_object_payload( - kwargs=self.model_call_details, - init_response_obj={}, - start_time=start_time, - end_time=end_time, - logging_obj=self, - status="failure", - error_str=str(exception), - original_exception=exception, - standard_built_in_tools_params=self.standard_built_in_tools_params, + self.model_call_details["standard_logging_object"] = ( + get_standard_logging_object_payload( + kwargs=self.model_call_details, + init_response_obj={}, + start_time=start_time, + end_time=end_time, + logging_obj=self, + status="failure", + error_str=str(exception), + original_exception=exception, + standard_built_in_tools_params=self.standard_built_in_tools_params, + ) ) return start_time, end_time @@ -3735,9 +3735,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 service_name=arize_config.project_name, ) - os.environ[ - "OTEL_EXPORTER_OTLP_TRACES_HEADERS" - ] = f"space_id={arize_config.space_key or arize_config.space_id},api_key={arize_config.api_key}" + os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = ( + f"space_id={arize_config.space_key or arize_config.space_id},api_key={arize_config.api_key}" + ) for callback in _in_memory_loggers: if ( isinstance(callback, ArizeLogger) @@ -3763,13 +3763,13 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 existing_attrs = os.environ.get("OTEL_RESOURCE_ATTRIBUTES", "") # Add openinference.project.name attribute if existing_attrs: - os.environ[ - "OTEL_RESOURCE_ATTRIBUTES" - ] = f"{existing_attrs},openinference.project.name={arize_phoenix_config.project_name}" + os.environ["OTEL_RESOURCE_ATTRIBUTES"] = ( + f"{existing_attrs},openinference.project.name={arize_phoenix_config.project_name}" + ) else: - os.environ[ - "OTEL_RESOURCE_ATTRIBUTES" - ] = f"openinference.project.name={arize_phoenix_config.project_name}" + os.environ["OTEL_RESOURCE_ATTRIBUTES"] = ( + f"openinference.project.name={arize_phoenix_config.project_name}" + ) # Set Phoenix project name from environment variable phoenix_project_name = os.environ.get("PHOENIX_PROJECT_NAME", None) @@ -3777,19 +3777,19 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 existing_attrs = os.environ.get("OTEL_RESOURCE_ATTRIBUTES", "") # Add openinference.project.name attribute if existing_attrs: - os.environ[ - "OTEL_RESOURCE_ATTRIBUTES" - ] = f"{existing_attrs},openinference.project.name={phoenix_project_name}" + os.environ["OTEL_RESOURCE_ATTRIBUTES"] = ( + f"{existing_attrs},openinference.project.name={phoenix_project_name}" + ) else: - os.environ[ - "OTEL_RESOURCE_ATTRIBUTES" - ] = f"openinference.project.name={phoenix_project_name}" + os.environ["OTEL_RESOURCE_ATTRIBUTES"] = ( + f"openinference.project.name={phoenix_project_name}" + ) # auth can be disabled on local deployments of arize phoenix if arize_phoenix_config.otlp_auth_headers is not None: - os.environ[ - "OTEL_EXPORTER_OTLP_TRACES_HEADERS" - ] = arize_phoenix_config.otlp_auth_headers + os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = ( + arize_phoenix_config.otlp_auth_headers + ) for callback in _in_memory_loggers: if ( @@ -3965,9 +3965,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 exporter="otlp_http", endpoint="https://langtrace.ai/api/trace", ) - os.environ[ - "OTEL_EXPORTER_OTLP_TRACES_HEADERS" - ] = f"api_key={os.getenv('LANGTRACE_API_KEY')}" + os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = ( + f"api_key={os.getenv('LANGTRACE_API_KEY')}" + ) for callback in _in_memory_loggers: if ( isinstance(callback, OpenTelemetry) @@ -4446,15 +4446,17 @@ def use_custom_pricing_for_model(litellm_params: Optional[dict]) -> bool: if litellm_params.get(key) is not None: return True - # Check model_info - metadata: dict = litellm_params.get("metadata", {}) or {} - model_info: dict = metadata.get("model_info", {}) or {} + # Check model_info from metadata or litellm_metadata (generic_api_call routes + # like /responses and /messages store model_info under litellm_metadata) + for metadata_key in ("metadata", "litellm_metadata"): + metadata: dict = litellm_params.get(metadata_key, {}) or {} + model_info: dict = metadata.get("model_info", {}) or {} - if model_info: - matching_keys = _CUSTOM_PRICING_KEYS & model_info.keys() - for key in matching_keys: - if model_info.get(key) is not None: - return True + if model_info: + matching_keys = _CUSTOM_PRICING_KEYS & model_info.keys() + for key in matching_keys: + if model_info.get(key) is not None: + return True return False @@ -4881,10 +4883,10 @@ class StandardLoggingPayloadSetup: for key in StandardLoggingHiddenParams.__annotations__.keys(): if key in hidden_params: if key == "additional_headers": - clean_hidden_params[ - "additional_headers" - ] = StandardLoggingPayloadSetup.get_additional_headers( - hidden_params[key] + clean_hidden_params["additional_headers"] = ( + StandardLoggingPayloadSetup.get_additional_headers( + hidden_params[key] + ) ) else: clean_hidden_params[key] = hidden_params[key] # type: ignore @@ -5523,9 +5525,9 @@ def scrub_sensitive_keys_in_metadata(litellm_params: Optional[dict]): ): for k, v in metadata["user_api_key_metadata"].items(): if k == "logging": # prevent logging user logging keys - cleaned_user_api_key_metadata[ - k - ] = "scrubbed_by_litellm_for_sensitive_keys" + cleaned_user_api_key_metadata[k] = ( + "scrubbed_by_litellm_for_sensitive_keys" + ) else: cleaned_user_api_key_metadata[k] = v diff --git a/litellm/llms/custom_httpx/llm_http_handler.py b/litellm/llms/custom_httpx/llm_http_handler.py index a8d649064a..4394343c8e 100644 --- a/litellm/llms/custom_httpx/llm_http_handler.py +++ b/litellm/llms/custom_httpx/llm_http_handler.py @@ -22,9 +22,7 @@ import litellm.litellm_core_utils import litellm.types import litellm.types.utils from litellm._logging import verbose_logger -from litellm.anthropic_beta_headers_manager import ( - update_headers_with_filtered_beta, -) +from litellm.anthropic_beta_headers_manager import update_headers_with_filtered_beta from litellm.constants import REALTIME_WEBSOCKET_MAX_MESSAGE_SIZE_BYTES from litellm.litellm_core_utils.realtime_streaming import RealTimeStreaming from litellm.llms.base_llm.anthropic_messages.transformation import ( @@ -1889,6 +1887,7 @@ class BaseLLMHTTPHandler: optional_params=dict(anthropic_messages_optional_request_params), litellm_params={ "metadata": kwargs.get("metadata", {}), + "litellm_metadata": kwargs.get("litellm_metadata", {}), "preset_cache_key": None, "stream_response": {}, **anthropic_messages_optional_request_params, diff --git a/tests/test_litellm/litellm_core_utils/test_litellm_logging.py b/tests/test_litellm/litellm_core_utils/test_litellm_logging.py index f4aeb27b31..34162bba3f 100644 --- a/tests/test_litellm/litellm_core_utils/test_litellm_logging.py +++ b/tests/test_litellm/litellm_core_utils/test_litellm_logging.py @@ -148,6 +148,38 @@ def test_use_custom_pricing_for_model(): assert use_custom_pricing_for_model(litellm_params) == True +def test_use_custom_pricing_for_model_via_litellm_metadata(): + """Pricing in litellm_metadata.model_info must be detected. + + Generic API call routes (/messages, /responses) store model_info + under litellm_metadata, not metadata. Regression test for #23185. + """ + from litellm.litellm_core_utils.litellm_logging import use_custom_pricing_for_model + + litellm_params = { + "litellm_metadata": { + "model_info": { + "id": "claude-sonnet-4-custom", + "input_cost_per_token": 0.0003, + "output_cost_per_token": 0.0015, + }, + }, + } + assert use_custom_pricing_for_model(litellm_params) is True + + +def test_use_custom_pricing_not_detected_litellm_metadata_no_pricing(): + """Should return False when litellm_metadata.model_info has no pricing keys.""" + from litellm.litellm_core_utils.litellm_logging import use_custom_pricing_for_model + + litellm_params = { + "litellm_metadata": { + "model_info": {"id": "some-id", "db_model": False}, + }, + } + assert use_custom_pricing_for_model(litellm_params) is False + + def test_logging_prevent_double_logging(logging_obj): """ When using a bridge, log only once from the underlying bridge call. 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 17b4243da1..c418650aa8 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 @@ -154,6 +154,80 @@ async def test_async_anthropic_messages_handler_extra_headers(): assert captured_headers["X-Auth-Token"] == "token123" +@pytest.mark.asyncio +async def test_async_anthropic_messages_handler_passes_litellm_metadata(): + """Ensure litellm_metadata from kwargs is included in litellm_params + passed to update_environment_variables. + + Routes like /messages store model_info under kwargs['litellm_metadata']. + The handler must forward this into litellm_params so that + use_custom_pricing_for_model can detect custom pricing. Regression test for #23185. + """ + handler = BaseLLMHTTPHandler() + + 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-sonnet-4-20250514", "messages": []} + ) + + 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-sonnet-4-20250514", + "stop_reason": "end_turn", + } + mock_client.post = AsyncMock(return_value=mock_response) + + mock_logging_obj = Mock() + mock_logging_obj.update_environment_variables = Mock() + mock_logging_obj.model_call_details = {} + mock_logging_obj.stream = False + + custom_model_info = { + "id": "claude-sonnet-4-custom-pricing", + "input_cost_per_token": 0.0003, + "output_cost_per_token": 0.0015, + } + kwargs = { + "litellm_metadata": { + "model_info": custom_model_info, + "deployment": "anthropic/claude-sonnet-4-20250514", + }, + } + + try: + await handler.async_anthropic_messages_handler( + model="claude-sonnet-4-20250514", + 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 + + mock_logging_obj.update_environment_variables.assert_called_once() + call_kwargs = mock_logging_obj.update_environment_variables.call_args + litellm_params_arg = call_kwargs.kwargs.get( + "litellm_params", call_kwargs[1].get("litellm_params", {}) + ) if call_kwargs.kwargs else call_kwargs[1].get("litellm_params", {}) + + assert "litellm_metadata" in litellm_params_arg + assert litellm_params_arg["litellm_metadata"]["model_info"] == custom_model_info + + @pytest.mark.asyncio async def test_async_anthropic_messages_handler_header_priority(): """ diff --git a/tests/test_litellm/test_cost_calculator.py b/tests/test_litellm/test_cost_calculator.py index 1204b11934..463f6952d2 100644 --- a/tests/test_litellm/test_cost_calculator.py +++ b/tests/test_litellm/test_cost_calculator.py @@ -332,6 +332,62 @@ def test_custom_pricing_with_router_model_id(): assert model_info["cache_read_input_token_cost"] == 0.0000006 +def test_custom_pricing_cost_calc_uses_router_model_id_from_litellm_metadata(): + """When custom pricing is in litellm_metadata.model_info, + use_custom_pricing_for_model should return True and + _select_model_name_for_cost_calc should use router_model_id. + + This tests the full chain that was broken for /messages and /responses + endpoints. Regression test for #23185. + """ + from litellm.cost_calculator import _select_model_name_for_cost_calc + from litellm.litellm_core_utils.litellm_logging import use_custom_pricing_for_model + + custom_model_id = "claude-sonnet-4-custom-pricing-test" + custom_pricing_info = { + "input_cost_per_token": 0.0003, + "output_cost_per_token": 0.0015, + "max_tokens": 8192, + "litellm_provider": "anthropic", + } + litellm.register_model(model_cost={custom_model_id: custom_pricing_info}) + + litellm_params = { + "litellm_metadata": { + "model_info": { + "id": custom_model_id, + "input_cost_per_token": 0.0003, + "output_cost_per_token": 0.0015, + }, + }, + } + + custom_pricing = use_custom_pricing_for_model(litellm_params) + assert custom_pricing is True + + # _select_model_name_for_cost_calc appends provider prefix to the + # selected router_model_id, so the result is "anthropic/" + selected_model = _select_model_name_for_cost_calc( + model="anthropic/claude-sonnet-4-20250514", + completion_response=None, + custom_pricing=custom_pricing, + custom_llm_provider="anthropic", + router_model_id=custom_model_id, + ) + assert selected_model is not None + assert custom_model_id in selected_model + + # Without custom_pricing, the router_model_id is NOT selected + selected_model_no_custom = _select_model_name_for_cost_calc( + model="anthropic/claude-sonnet-4-20250514", + completion_response=None, + custom_pricing=False, + custom_llm_provider="anthropic", + router_model_id=custom_model_id, + ) + assert custom_model_id not in (selected_model_no_custom or "") + + def test_azure_realtime_cost_calculator(): os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True" litellm.model_cost = litellm.get_model_cost_map(url="") @@ -365,11 +421,7 @@ def test_azure_audio_output_cost_calculation(): Audio tokens should be charged at output_cost_per_audio_token rate, not at the text token rate (output_cost_per_token). """ - from litellm.types.utils import ( - Choices, - CompletionTokensDetailsWrapper, - Message, - ) + from litellm.types.utils import Choices, CompletionTokensDetailsWrapper, Message os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True" litellm.model_cost = litellm.get_model_cost_map(url="") @@ -471,11 +523,7 @@ def test_default_image_cost_calculator(monkeypatch): def test_cost_calculator_with_cache_creation(): from litellm import completion_cost - from litellm.types.utils import ( - Choices, - Message, - Usage, - ) + from litellm.types.utils import Choices, Message, Usage litellm_model_response = ModelResponse( id="chatcmpl-cc5638bc-fdfe-48e4-8884-57c8f4fb7c63", @@ -896,10 +944,7 @@ def test_azure_ai_cache_cost_calculation(): applied correctly. """ from litellm.litellm_core_utils.llm_cost_calc.utils import generic_cost_per_token - from litellm.types.utils import ( - PromptTokensDetailsWrapper, - Usage, - ) + from litellm.types.utils import PromptTokensDetailsWrapper, Usage os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True" litellm.model_cost = litellm.get_model_cost_map(url="") diff --git a/tests/test_litellm/test_router.py b/tests/test_litellm/test_router.py index 8c37214e19..83387ad8b3 100644 --- a/tests/test_litellm/test_router.py +++ b/tests/test_litellm/test_router.py @@ -2735,6 +2735,81 @@ def test_credential_name_not_injected_when_absent(): assert kwargs["metadata"]["tags"] == ["A.101"] +def test_update_kwargs_with_deployment_model_info_in_litellm_metadata(): + """For generic_api_call, model_info with pricing must go to litellm_metadata. + + Routes like /messages and /responses use generic_api_call which stores + model_info under litellm_metadata. Regression test for #23185. + """ + router = litellm.Router( + model_list=[ + { + "model_name": "claude-sonnet-4", + "litellm_params": { + "model": "anthropic/claude-sonnet-4-20250514", + "api_key": "fake-key", + }, + "model_info": { + "id": "custom-pricing-id", + "input_cost_per_token": 0.0003, + "output_cost_per_token": 0.0015, + }, + }, + ], + ) + + kwargs: dict = {} + deployment = router.get_deployment_by_model_group_name( + model_group_name="claude-sonnet-4" + ) + router._update_kwargs_with_deployment( + deployment=deployment, kwargs=kwargs, function_name="generic_api_call" + ) + + assert "litellm_metadata" in kwargs + model_info = kwargs["litellm_metadata"]["model_info"] + assert model_info["id"] == "custom-pricing-id" + assert model_info["input_cost_per_token"] == 0.0003 + assert model_info["output_cost_per_token"] == 0.0015 + + +def test_update_kwargs_with_deployment_model_info_in_metadata(): + """For acompletion (function_name=None), model_info goes to metadata. + + /chat/completions uses acompletion which stores model_info under metadata. + """ + router = litellm.Router( + model_list=[ + { + "model_name": "claude-sonnet-4", + "litellm_params": { + "model": "anthropic/claude-sonnet-4-20250514", + "api_key": "fake-key", + }, + "model_info": { + "id": "custom-pricing-id", + "input_cost_per_token": 0.0003, + "output_cost_per_token": 0.0015, + }, + }, + ], + ) + + kwargs: dict = {} + deployment = router.get_deployment_by_model_group_name( + model_group_name="claude-sonnet-4" + ) + router._update_kwargs_with_deployment( + deployment=deployment, kwargs=kwargs, function_name=None + ) + + assert "metadata" in kwargs + model_info = kwargs["metadata"]["model_info"] + assert model_info["id"] == "custom-pricing-id" + assert model_info["input_cost_per_token"] == 0.0003 + assert model_info["output_cost_per_token"] == 0.0015 + + def test_combine_fallback_usage(): """Test that _combine_fallback_usage merges partial and fallback usage.""" from litellm.router import Router From 03231f3b266c8b67799c6fa6785aefd36a767bbe Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 14 Mar 2026 12:43:03 -0700 Subject: [PATCH 078/289] [Fix] CI failures: mypy type error, ruff lint, and flaky router test - Fix mypy arg-type error in background_streaming.py by adding proper type annotation and cast for terminal_status - Fix ruff F401 false positive for httpx import in vantage_destination.py caused by from __future__ import annotations - Fix flaky test_arouter_responses_api_bridge by providing a properly structured mock response to prevent exception mapping errors Co-Authored-By: Claude Opus 4.6 --- .../focus/destinations/vantage_destination.py | 2 +- .../proxy/response_polling/background_streaming.py | 14 +++++++++----- tests/test_litellm/test_router.py | 8 +++++++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/litellm/integrations/focus/destinations/vantage_destination.py b/litellm/integrations/focus/destinations/vantage_destination.py index 9e6028900f..4b9d270d2f 100644 --- a/litellm/integrations/focus/destinations/vantage_destination.py +++ b/litellm/integrations/focus/destinations/vantage_destination.py @@ -6,7 +6,7 @@ import csv import io from typing import Any, Optional -import httpx +import httpx # noqa: F401 - used at runtime (AsyncClient, HTTPStatusError) from litellm._logging import verbose_logger diff --git a/litellm/proxy/response_polling/background_streaming.py b/litellm/proxy/response_polling/background_streaming.py index 682ad4943b..5ec0aac8e2 100644 --- a/litellm/proxy/response_polling/background_streaming.py +++ b/litellm/proxy/response_polling/background_streaming.py @@ -9,7 +9,7 @@ https://platform.openai.com/docs/api-reference/responses-streaming """ import asyncio import json -from typing import Any +from typing import Any, Optional, cast from fastapi import Request, Response @@ -17,6 +17,7 @@ from litellm._logging import verbose_proxy_logger from litellm.proxy.auth.user_api_key_auth import UserAPIKeyAuth from litellm.proxy.common_request_processing import ProxyBaseLLMRequestProcessing from litellm.proxy.response_polling.polling_handler import ResponsePollingHandler +from litellm.types.llms.openai import ResponsesAPIStatus async def background_streaming_task( # noqa: PLR0915 @@ -114,7 +115,7 @@ async def background_streaming_task( # noqa: PLR0915 UPDATE_INTERVAL = 0.150 # 150ms batching interval # Track the terminal event from the stream (may not be "completed") - terminal_status = None # Will be set by response.completed/failed/incomplete/cancelled + terminal_status: Optional[ResponsesAPIStatus] = None # Will be set by response.completed/failed/incomplete/cancelled terminal_error = None _event_to_status = { "response.completed": "completed", @@ -249,9 +250,12 @@ async def background_streaming_task( # noqa: PLR0915 # Terminal event - extract all ResponsesAPIResponse fields # https://platform.openai.com/docs/api-reference/responses-streaming response_data = event.get("response", {}) - terminal_status = response_data.get( - "status", - _event_to_status.get(event_type, "completed"), + terminal_status = cast( + ResponsesAPIStatus, + response_data.get( + "status", + _event_to_status.get(event_type, "completed"), + ), ) # Extract error for failed responses diff --git a/tests/test_litellm/test_router.py b/tests/test_litellm/test_router.py index 8c37214e19..b563a2e3c5 100644 --- a/tests/test_litellm/test_router.py +++ b/tests/test_litellm/test_router.py @@ -643,7 +643,13 @@ def test_arouter_responses_api_bridge(): ## CONFIRM MODEL NAME IS STRIPPED client = HTTPHandler() - with patch.object(client, "post", return_value=MagicMock()) as mock_post: + mock_response = MagicMock() + mock_response.status_code = 200 + mock_response.headers = {"content-type": "application/json"} + mock_response.json.return_value = {"id": "resp_test", "object": "response", "status": "completed", "output": []} + mock_response.text = '{"id": "resp_test", "object": "response", "status": "completed", "output": []}' + + with patch.object(client, "post", return_value=mock_response) as mock_post: try: result = router.completion( model="[IP-approved] o3-pro", From 47c38403ffa1f67cd7f491635537f71e08c60bc7 Mon Sep 17 00:00:00 2001 From: Krish Dholakia Date: Sat, 14 Mar 2026 13:21:10 -0700 Subject: [PATCH 079/289] Litellm dev 03 14 2026 p1 (#23653) * fix: Fixes https://github.com/BerriAI/litellm/issues/23185 * fix(responses/main.py): ensure litellm metadata custom cost works --- litellm/responses/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litellm/responses/main.py b/litellm/responses/main.py index 6f7e38dc8b..b83cfb6e3c 100644 --- a/litellm/responses/main.py +++ b/litellm/responses/main.py @@ -751,6 +751,7 @@ def responses( "aresponses": _is_async, "litellm_call_id": litellm_call_id, "metadata": metadata_for_callbacks, + "litellm_metadata": kwargs.get("litellm_metadata", {}), }, custom_llm_provider=custom_llm_provider, ) From af0c2f67923437e3b280664911bf5dd5d813f657 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sat, 14 Mar 2026 13:24:16 -0700 Subject: [PATCH 080/289] docs: add Claude Code skills page for litellm-skills (#23642) * docs: add Claude Code skills page for litellm-skills * docs: move skills page to new 'Manage with AI Agents' section * docs: simplify install to one-liner, rename to LiteLLM Skills --- .../docs/tutorials/claude_code_skills.md | 99 +++++++++++++++++++ docs/my-website/sidebars.js | 13 +++ 2 files changed, 112 insertions(+) create mode 100644 docs/my-website/docs/tutorials/claude_code_skills.md diff --git a/docs/my-website/docs/tutorials/claude_code_skills.md b/docs/my-website/docs/tutorials/claude_code_skills.md new file mode 100644 index 0000000000..0c6344f956 --- /dev/null +++ b/docs/my-website/docs/tutorials/claude_code_skills.md @@ -0,0 +1,99 @@ +# LiteLLM Skills + +[litellm-skills](https://github.com/BerriAI/litellm-skills) is a collection of [Agent Skills](https://agentskills.io) for managing a live LiteLLM proxy. Install them once and any agent that supports the Agent Skills standard (Claude Code, OpenCode, OpenClaw, etc.) can create users, teams, keys, models, MCP servers, agents, and query usage — all by running `curl` commands against your proxy. + +## Install + +```bash +curl -fsSL https://raw.githubusercontent.com/BerriAI/litellm-skills/main/install.sh | sh +``` + +## Requirements + +- `curl` installed +- A running LiteLLM proxy (local or remote) +- A proxy admin key — not a virtual key scoped to `llm_api_routes` + +## Available Skills + +### Users + +| Skill | What it does | +|-------|-------------| +| `/add-user` | Create a user — email, role, budget, model access | +| `/update-user` | Update budget, role, or models for an existing user | +| `/delete-user` | Delete one or more users | + +### Teams + +| Skill | What it does | +|-------|-------------| +| `/add-team` | Create a team with budget and model limits | +| `/update-team` | Update budget, models, or rate limits | +| `/delete-team` | Delete one or more teams | + +### API Keys + +| Skill | What it does | +|-------|-------------| +| `/add-key` | Generate a key scoped to a user, team, budget, and expiry | +| `/update-key` | Update budget, models, or expiry | +| `/delete-key` | Delete by key value or alias | + +### Organizations + +| Skill | What it does | +|-------|-------------| +| `/add-org` | Create an org with budget and model access | +| `/delete-org` | Delete one or more orgs | + +### Models + +| Skill | What it does | +|-------|-------------| +| `/add-model` | Add any provider (OpenAI, Azure, Anthropic, Bedrock, Ollama…) and test it | +| `/update-model` | Rotate credentials or swap the underlying deployment | +| `/delete-model` | Remove a model | + +### MCP Servers + +| Skill | What it does | +|-------|-------------| +| `/add-mcp` | Register an MCP server (SSE, HTTP, or stdio) | +| `/update-mcp` | Update URL, credentials, or allowed tools | +| `/delete-mcp` | Remove an MCP server | + +### Agents + +| Skill | What it does | +|-------|-------------| +| `/add-agent` | Create an agent backed by a model and optional MCP servers | +| `/update-agent` | Swap the model or update description and limits | +| `/delete-agent` | Remove an agent | + +### Usage + +| Skill | What it does | +|-------|-------------| +| `/view-usage` | Daily spend and token activity — by user, team, org, or model | + +## How it works + +When you invoke a skill, the agent asks for your `LITELLM_BASE_URL` and admin key, collects the fields needed for that operation, runs the `curl`, and shows the result. For example: + +``` +/add-model +``` +→ Agent asks: provider, public name, credentials. Adds the model, runs a test completion, reports pass/fail. + +``` +/view-usage +``` +→ Agent asks: date range (defaults to current month), optional team/model filter. Prints a table of daily requests, tokens, and spend. + +## Related + +- [litellm-skills on GitHub](https://github.com/BerriAI/litellm-skills) +- [Virtual Keys](../proxy/virtual_keys.md) — managing API keys on the proxy +- [Team-based routing](../proxy/team_based_routing.md) — setting up teams +- [Model Management](../proxy/model_management.md) — adding models via config or API diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index d1eb331f55..1362745a91 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -195,6 +195,19 @@ const sidebars = { "projects/openai-agents" ] }, + { + type: "category", + label: "Manage with AI Agents", + link: { + type: "generated-index", + title: "Manage with AI Agents", + description: "Use AI agents to manage your LiteLLM deployment — create users, teams, keys, models, and more via natural language.", + slug: "/manage_with_ai_agents" + }, + items: [ + "tutorials/claude_code_skills", + ] + }, ], // But you can create a sidebar manually From 374c3458d51ed6fb5c82400a55d6c38d997e101e Mon Sep 17 00:00:00 2001 From: ryanh-ai <3118399+ryanh-ai@users.noreply.github.com> Date: Sat, 14 Mar 2026 15:10:01 -0700 Subject: [PATCH 081/289] feat: add sagemaker_nova provider for Amazon Nova models on SageMaker (#21542) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add sagemaker_nova provider for Nova models on SageMaker Add support for custom/fine-tuned Amazon Nova models (Nova Micro, Nova Lite, Nova 2 Lite) deployed on SageMaker Inference real-time endpoints. Nova uses OpenAI-compatible request/response format with additional Nova-specific parameters (top_k, reasoning_effort, allowed_token_ids, truncate_prompt_tokens) and requires stream:true in the request body. Nova endpoints also reject 'model' in the request body. Changes: - New provider: sagemaker_nova/ - SagemakerNovaConfig inherits from SagemakerChatConfig - Override transform_request to strip 'model' from request body - Override supports_stream_param_in_request_body (True for Nova) - Extend get_supported_openai_params with Nova-specific params - Refactored SagemakerChatConfig to use custom_llm_provider param instead of hardcoded strings (backwards-compatible) - Consolidated main.py routing for sagemaker_chat and sagemaker_nova - 22 unit tests + 9 integration tests (skip-gated) - Documentation with SDK, streaming, multimodal, and proxy examples - All tests verified against live SageMaker Nova endpoint * fix: move integration tests to tests/local_testing/ per test directory policy * fix: remove unused module-level SagemakerNovaConfig instance The sagemaker_nova_config singleton was never imported or used — the ProviderConfigManager creates its own instance via the lambda registered in utils.py. Removing this leftover boilerplate. --------- Co-authored-by: Krish Dholakia --- .../docs/providers/aws_sagemaker.md | 95 +++++ litellm/__init__.py | 9 +- litellm/_lazy_imports_registry.py | 5 + litellm/constants.py | 1 + litellm/llms/sagemaker/chat/transformation.py | 10 +- litellm/llms/sagemaker/nova/__init__.py | 1 + litellm/llms/sagemaker/nova/transformation.py | 70 ++++ litellm/main.py | 6 +- litellm/types/utils.py | 1 + litellm/utils.py | 1 + .../test_sagemaker_nova_integration.py | 276 ++++++++++++ .../test_sagemaker_nova_transformation.py | 393 ++++++++++++++++++ 12 files changed, 857 insertions(+), 11 deletions(-) create mode 100644 litellm/llms/sagemaker/nova/__init__.py create mode 100644 litellm/llms/sagemaker/nova/transformation.py create mode 100644 tests/local_testing/test_sagemaker_nova_integration.py create mode 100644 tests/test_litellm/llms/sagemaker/test_sagemaker_nova_transformation.py diff --git a/docs/my-website/docs/providers/aws_sagemaker.md b/docs/my-website/docs/providers/aws_sagemaker.md index bab475e730..a2440c73d7 100644 --- a/docs/my-website/docs/providers/aws_sagemaker.md +++ b/docs/my-website/docs/providers/aws_sagemaker.md @@ -526,3 +526,98 @@ print(f"response: {response}") ``` + +## Nova Models on SageMaker + +LiteLLM supports Amazon Nova models (Nova Micro, Nova Lite, Nova 2 Lite) deployed on SageMaker Inference real-time endpoints. These custom/fine-tuned Nova models use an OpenAI-compatible API format. + +**Reference:** [AWS Blog - Amazon SageMaker Inference for Custom Amazon Nova Models](https://aws.amazon.com/blogs/aws/announcing-amazon-sagemaker-inference-for-custom-amazon-nova-models/) + +### Usage + +Use the `sagemaker_nova/` prefix with your SageMaker endpoint name: + +```python +import litellm +import os + +os.environ["AWS_ACCESS_KEY_ID"] = "" +os.environ["AWS_SECRET_ACCESS_KEY"] = "" +os.environ["AWS_REGION_NAME"] = "us-east-1" + +# Basic chat completion +response = litellm.completion( + model="sagemaker_nova/my-nova-endpoint", + messages=[{"role": "user", "content": "Hello, how are you?"}], + temperature=0.7, + max_tokens=512, +) +print(response.choices[0].message.content) +``` + +### Streaming + +```python +response = litellm.completion( + model="sagemaker_nova/my-nova-endpoint", + messages=[{"role": "user", "content": "Write a short poem"}], + stream=True, + stream_options={"include_usage": True}, +) +for chunk in response: + if chunk.choices[0].delta.content: + print(chunk.choices[0].delta.content, end="") +``` + +### Multimodal (Images) + +Nova models on SageMaker support image inputs using base64 data URIs: + +```python +response = litellm.completion( + model="sagemaker_nova/my-nova-endpoint", + messages=[ + { + "role": "user", + "content": [ + {"type": "text", "text": "What's in this image?"}, + {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,..."}} + ] + } + ], +) +``` + +### Proxy Config + +```yaml +model_list: + - model_name: nova-micro + litellm_params: + model: sagemaker_nova/my-nova-micro-endpoint + aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID + aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY + aws_region_name: us-east-1 +``` + +### Supported Parameters + +All standard OpenAI parameters are supported, plus these Nova-specific parameters: + +| Parameter | Type | Description | +|-----------|------|-------------| +| `top_k` | integer | Limits token selection to top K most likely tokens | +| `reasoning_effort` | `"low"` \| `"high"` | Reasoning effort level (Nova 2 Lite custom models only) | +| `allowed_token_ids` | array[int] | Restrict output to specified token IDs | +| `truncate_prompt_tokens` | integer | Truncate prompt to N tokens if it exceeds limit | + +```python +response = litellm.completion( + model="sagemaker_nova/my-nova-endpoint", + messages=[{"role": "user", "content": "Think step by step: what is 2+2?"}], + top_k=40, + reasoning_effort="low", + logprobs=True, + top_logprobs=2, +) +``` diff --git a/litellm/__init__.py b/litellm/__init__.py index dcd4ce2909..b75630c19d 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -1464,12 +1464,9 @@ if TYPE_CHECKING: from .llms.petals.completion.transformation import PetalsConfig as PetalsConfig from .llms.ollama.chat.transformation import OllamaChatConfig as OllamaChatConfig from .llms.ollama.completion.transformation import OllamaConfig as OllamaConfig - from .llms.sagemaker.completion.transformation import ( - SagemakerConfig as SagemakerConfig, - ) - from .llms.sagemaker.chat.transformation import ( - SagemakerChatConfig as SagemakerChatConfig, - ) + from .llms.sagemaker.completion.transformation import SagemakerConfig as SagemakerConfig + from .llms.sagemaker.chat.transformation import SagemakerChatConfig as SagemakerChatConfig + from .llms.sagemaker.nova.transformation import SagemakerNovaConfig as SagemakerNovaConfig from .llms.cohere.chat.transformation import CohereChatConfig as CohereChatConfig from .llms.anthropic.experimental_pass_through.messages.transformation import ( AnthropicMessagesConfig as AnthropicMessagesConfig, diff --git a/litellm/_lazy_imports_registry.py b/litellm/_lazy_imports_registry.py index f7f56d2b88..9164a3c8ae 100644 --- a/litellm/_lazy_imports_registry.py +++ b/litellm/_lazy_imports_registry.py @@ -167,6 +167,7 @@ LLM_CONFIG_NAMES = ( "OllamaConfig", "SagemakerConfig", "SagemakerChatConfig", + "SagemakerNovaConfig", "CohereChatConfig", "AnthropicMessagesConfig", "AmazonAnthropicClaudeMessagesConfig", @@ -701,6 +702,10 @@ _LLM_CONFIGS_IMPORT_MAP = { ".llms.sagemaker.chat.transformation", "SagemakerChatConfig", ), + "SagemakerNovaConfig": ( + ".llms.sagemaker.nova.transformation", + "SagemakerNovaConfig", + ), "CohereChatConfig": (".llms.cohere.chat.transformation", "CohereChatConfig"), "AnthropicMessagesConfig": ( ".llms.anthropic.experimental_pass_through.messages.transformation", diff --git a/litellm/constants.py b/litellm/constants.py index 0cf9700cdd..89c59ee932 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -505,6 +505,7 @@ LITELLM_CHAT_PROVIDERS = [ "azure_ai", "sagemaker", "sagemaker_chat", + "sagemaker_nova", "bedrock", "vllm", "nlp_cloud", diff --git a/litellm/llms/sagemaker/chat/transformation.py b/litellm/llms/sagemaker/chat/transformation.py index 2b458fbc43..60e85c9f93 100644 --- a/litellm/llms/sagemaker/chat/transformation.py +++ b/litellm/llms/sagemaker/chat/transformation.py @@ -160,7 +160,7 @@ class SagemakerChatConfig(OpenAIGPTConfig, BaseAWSLLM): streaming_response = CustomStreamWrapper( completion_stream=completion_stream, model=model, - custom_llm_provider="sagemaker_chat", + custom_llm_provider=custom_llm_provider, logging_obj=logging_obj, ) return streaming_response @@ -180,8 +180,12 @@ class SagemakerChatConfig(OpenAIGPTConfig, BaseAWSLLM): signed_json_body: Optional[bytes] = None, ) -> CustomStreamWrapper: if client is None or isinstance(client, HTTPHandler): + try: + llm_provider = LlmProviders(custom_llm_provider) + except ValueError: + llm_provider = LlmProviders.SAGEMAKER_CHAT client = get_async_httpx_client( - llm_provider=LlmProviders.SAGEMAKER_CHAT, params={} + llm_provider=llm_provider, params={} ) try: @@ -210,7 +214,7 @@ class SagemakerChatConfig(OpenAIGPTConfig, BaseAWSLLM): streaming_response = CustomStreamWrapper( completion_stream=completion_stream, model=model, - custom_llm_provider="sagemaker_chat", + custom_llm_provider=custom_llm_provider, logging_obj=logging_obj, ) return streaming_response diff --git a/litellm/llms/sagemaker/nova/__init__.py b/litellm/llms/sagemaker/nova/__init__.py new file mode 100644 index 0000000000..fdebd0b0e4 --- /dev/null +++ b/litellm/llms/sagemaker/nova/__init__.py @@ -0,0 +1 @@ +from .transformation import SagemakerNovaConfig # noqa: F401 diff --git a/litellm/llms/sagemaker/nova/transformation.py b/litellm/llms/sagemaker/nova/transformation.py new file mode 100644 index 0000000000..41c20847b5 --- /dev/null +++ b/litellm/llms/sagemaker/nova/transformation.py @@ -0,0 +1,70 @@ +""" +Translate from OpenAI's `/v1/chat/completions` to SageMaker Nova Inference endpoints. + +Nova models on SageMaker use OpenAI-compatible request/response format with +additional Nova-specific parameters (top_k, reasoning_effort, etc.). + +Docs: https://docs.aws.amazon.com/nova/latest/nova2-userguide/nova-sagemaker-inference-api-reference.html +""" + +from typing import List + +from litellm.types.llms.openai import AllMessageValues + +from ..chat.transformation import SagemakerChatConfig + + +class SagemakerNovaConfig(SagemakerChatConfig): + """ + Config for Amazon Nova models deployed on SageMaker Inference endpoints. + + Nova uses OpenAI-compatible format (same as sagemaker_chat / HF Messages API) + but with additional Nova-specific parameters and requires `stream: true` in + the request body for streaming. + + Usage: + model="sagemaker_nova/" + """ + + @property + def supports_stream_param_in_request_body(self) -> bool: + """Nova expects `stream: true` in the request body for streaming.""" + return True + + def get_supported_openai_params(self, model: str) -> List: + """Extend parent params with Nova-specific parameters.""" + params = super().get_supported_openai_params(model) + nova_params = [ + "top_k", + "reasoning_effort", + "allowed_token_ids", + "truncate_prompt_tokens", + ] + for p in nova_params: + if p not in params: + params.append(p) + return params + + def transform_request( + self, + model: str, + messages: List[AllMessageValues], + optional_params: dict, + litellm_params: dict, + headers: dict, + ) -> dict: + """ + Nova SageMaker endpoints do not accept 'model' in the request body. + Only supported fields: messages, max_tokens, max_completion_tokens, + temperature, top_p, top_k, stream, stream_options, logprobs, + top_logprobs, reasoning_effort, allowed_token_ids, truncate_prompt_tokens. + """ + request_body = super().transform_request( + model=model, + messages=messages, + optional_params=optional_params, + litellm_params=litellm_params, + headers=headers, + ) + request_body.pop("model", None) + return request_body diff --git a/litellm/main.py b/litellm/main.py index 5a1b7f0fe1..986ca4527f 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -3712,8 +3712,10 @@ def completion( # type: ignore # noqa: PLR0915 ): return _model_response response = _model_response - elif custom_llm_provider == "sagemaker_chat": + elif custom_llm_provider in ("sagemaker_chat", "sagemaker_nova"): # boto3 reads keys from .env + # sagemaker_chat: HF Messages API endpoints + # sagemaker_nova: Nova models on SageMaker (OpenAI-compatible) model_response = base_llm_http_handler.completion( model=model, stream=stream, @@ -3723,7 +3725,7 @@ def completion( # type: ignore # noqa: PLR0915 model_response=model_response, optional_params=optional_params, litellm_params=litellm_params, - custom_llm_provider="sagemaker_chat", + custom_llm_provider=custom_llm_provider, timeout=timeout, headers=headers, encoding=_get_encoding(), diff --git a/litellm/types/utils.py b/litellm/types/utils.py index f9a4f1429b..892c9578b9 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -3131,6 +3131,7 @@ class LlmProviders(str, Enum): AZURE_AI = "azure_ai" SAGEMAKER = "sagemaker" SAGEMAKER_CHAT = "sagemaker_chat" + SAGEMAKER_NOVA = "sagemaker_nova" BEDROCK = "bedrock" VLLM = "vllm" NLP_CLOUD = "nlp_cloud" diff --git a/litellm/utils.py b/litellm/utils.py index b4ed37f9a7..81d749ab82 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -7945,6 +7945,7 @@ class ProviderConfigManager: LlmProviders.VERTEX_AI_BETA: (lambda: litellm.VertexGeminiConfig(), False), LlmProviders.CLOUDFLARE: (lambda: litellm.CloudflareChatConfig(), False), LlmProviders.SAGEMAKER_CHAT: (lambda: litellm.SagemakerChatConfig(), False), + LlmProviders.SAGEMAKER_NOVA: (lambda: litellm.SagemakerNovaConfig(), False), LlmProviders.SAGEMAKER: (lambda: litellm.SagemakerConfig(), False), LlmProviders.FIREWORKS_AI: (lambda: litellm.FireworksAIConfig(), False), LlmProviders.FRIENDLIAI: (lambda: litellm.FriendliaiChatConfig(), False), diff --git a/tests/local_testing/test_sagemaker_nova_integration.py b/tests/local_testing/test_sagemaker_nova_integration.py new file mode 100644 index 0000000000..6f55bea38b --- /dev/null +++ b/tests/local_testing/test_sagemaker_nova_integration.py @@ -0,0 +1,276 @@ +""" +Integration tests for SageMaker Nova provider. + +These tests require a live SageMaker Nova endpoint and AWS credentials. +They are skipped by default — run manually with: + + pytest tests/test_litellm/llms/sagemaker/test_sagemaker_nova_integration.py -v --no-header -rN + +Prerequisites: + export AWS_PROFILE= # or set AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY + export AWS_REGION_NAME=us-east-1 + export SAGEMAKER_NOVA_ENDPOINT= +""" + +import base64 +import io +import json +import os +import struct +import zlib + +import pytest + +import litellm + +ENDPOINT = os.environ.get("SAGEMAKER_NOVA_ENDPOINT", "") +MODEL = f"sagemaker_nova/{ENDPOINT}" + +skip_if_no_endpoint = pytest.mark.skipif( + not ENDPOINT, + reason="SAGEMAKER_NOVA_ENDPOINT not set — skipping live integration tests", +) + + +def _make_test_png() -> str: + """Create a minimal 4x4 PNG (red border, blue center) and return base64.""" + + def chunk(ctype, data): + c = ctype + data + return ( + struct.pack(">I", len(data)) + + c + + struct.pack(">I", zlib.crc32(c) & 0xFFFFFFFF) + ) + + width, height = 4, 4 + pixels = [] + for y in range(height): + for x in range(width): + if 1 <= x <= 2 and 1 <= y <= 2: + pixels.append((0, 0, 255)) + else: + pixels.append((255, 0, 0)) + + raw = b"" + for y in range(height): + raw += b"\x00" + for x in range(width): + raw += bytes(pixels[y * width + x]) + + png = ( + b"\x89PNG\r\n\x1a\n" + + chunk( + b"IHDR", struct.pack(">IIBBBBB", width, height, 8, 2, 0, 0, 0) + ) + + chunk(b"IDAT", zlib.compress(raw)) + + chunk(b"IEND", b"") + ) + return base64.b64encode(png).decode() + + +@skip_if_no_endpoint +class TestSagemakerNovaIntegration: + """Live integration tests for sagemaker_nova provider.""" + + def test_should_complete_basic_single_turn(self): + """Basic single-turn chat completion.""" + response = litellm.completion( + model=MODEL, + messages=[{"role": "user", "content": "What is 2+2? Reply in one word."}], + max_tokens=32, + temperature=0.1, + ) + assert response.choices[0].message.content is not None + assert len(response.choices[0].message.content.strip()) > 0 + assert response.choices[0].finish_reason == "stop" + assert response.usage.prompt_tokens > 0 + assert response.usage.completion_tokens > 0 + assert response.usage.total_tokens == ( + response.usage.prompt_tokens + response.usage.completion_tokens + ) + + def test_should_complete_multi_turn_conversation(self): + """Multi-turn conversation maintains context.""" + messages = [ + {"role": "user", "content": "My name is Alice."}, + ] + response1 = litellm.completion( + model=MODEL, + messages=messages, + max_tokens=64, + temperature=0.1, + ) + assistant_msg = response1.choices[0].message.content + assert assistant_msg is not None + + # Second turn — model should remember the name + messages.append({"role": "assistant", "content": assistant_msg}) + messages.append({"role": "user", "content": "What is my name?"}) + + response2 = litellm.completion( + model=MODEL, + messages=messages, + max_tokens=64, + temperature=0.1, + ) + answer = response2.choices[0].message.content.lower() + assert "alice" in answer, f"Expected 'alice' in response, got: {answer}" + + def test_should_stream_response(self): + """Streaming returns chunks with content and final usage.""" + response = litellm.completion( + model=MODEL, + messages=[{"role": "user", "content": "Count from 1 to 5."}], + max_tokens=64, + stream=True, + stream_options={"include_usage": True}, + ) + + chunks = [] + full_content = "" + for chunk in response: + chunks.append(chunk) + delta = chunk.choices[0].delta.content or "" + full_content += delta + + assert len(chunks) > 1, "Expected multiple streaming chunks" + assert len(full_content.strip()) > 0, "Expected non-empty streamed content" + + # Last chunk should have finish_reason + final_chunks_with_finish = [ + c for c in chunks if c.choices and c.choices[0].finish_reason is not None + ] + assert len(final_chunks_with_finish) > 0, "Expected at least one chunk with finish_reason" + + def test_should_return_logprobs(self): + """Logprobs are returned when requested.""" + response = litellm.completion( + model=MODEL, + messages=[{"role": "user", "content": "Say hello."}], + max_tokens=16, + temperature=0.1, + logprobs=True, + top_logprobs=3, + ) + lp = response.choices[0].logprobs + assert lp is not None, "Expected logprobs in response" + + content = lp.content if hasattr(lp, "content") else lp.get("content") + assert content is not None and len(content) > 0, "Expected logprobs content" + + first_token = content[0] + assert "token" in first_token or hasattr(first_token, "token") + assert "logprob" in first_token or hasattr(first_token, "logprob") + + top = first_token.get("top_logprobs") if isinstance(first_token, dict) else first_token.top_logprobs + assert top is not None and len(top) == 3, "Expected 3 top_logprobs" + + def test_should_handle_multimodal_image_input(self): + """Multimodal with base64 image in content array.""" + b64_image = _make_test_png() + response = litellm.completion( + model=MODEL, + messages=[ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "What colors do you see in this image? List them.", + }, + { + "type": "image_url", + "image_url": { + "url": f"data:image/png;base64,{b64_image}" + }, + }, + ], + } + ], + max_tokens=128, + ) + content = response.choices[0].message.content.lower() + assert response.choices[0].message.content is not None + assert len(content) > 0 + # The image has red and blue — model should mention at least one + assert "red" in content or "blue" in content, ( + f"Expected 'red' or 'blue' in multimodal response, got: {content}" + ) + + def test_should_pass_nova_specific_params(self): + """Nova-specific parameters (top_k) are accepted.""" + response = litellm.completion( + model=MODEL, + messages=[{"role": "user", "content": "Say hello."}], + max_tokens=32, + top_k=40, + temperature=0.7, + ) + assert response.choices[0].message.content is not None + assert response.usage.total_tokens > 0 + + def test_should_respect_system_message(self): + """System message should influence the response.""" + response = litellm.completion( + model=MODEL, + messages=[ + { + "role": "system", + "content": "You are a pirate. Always respond in pirate speak.", + }, + {"role": "user", "content": "How are you today?"}, + ], + max_tokens=128, + temperature=0.7, + ) + content = response.choices[0].message.content.lower() + assert response.choices[0].message.content is not None + # Pirate-themed words likely in response + pirate_words = ["arr", "ahoy", "matey", "ye", "sail", "sea", "cap"] + assert any( + w in content for w in pirate_words + ), f"Expected pirate speak, got: {content}" + + +NOVA2_ENDPOINT = os.environ.get("SAGEMAKER_NOVA2_LITE_ENDPOINT", "") +NOVA2_MODEL = f"sagemaker_nova/{NOVA2_ENDPOINT}" + +skip_if_no_nova2_endpoint = pytest.mark.skipif( + not NOVA2_ENDPOINT, + reason="SAGEMAKER_NOVA2_LITE_ENDPOINT not set — requires Nova 2 Lite endpoint", +) + + +@skip_if_no_nova2_endpoint +class TestSagemakerNova2LiteIntegration: + """ + Integration tests requiring a Nova 2 Lite endpoint (reasoning_effort support). + + Run with: + export SAGEMAKER_NOVA2_LITE_ENDPOINT= + pytest tests/test_litellm/llms/sagemaker/test_sagemaker_nova_integration.py::TestSagemakerNova2LiteIntegration -v + """ + + def test_should_accept_reasoning_effort_low(self): + """reasoning_effort='low' should be accepted by Nova 2 Lite.""" + response = litellm.completion( + model=NOVA2_MODEL, + messages=[{"role": "user", "content": "What is 2+2?"}], + max_tokens=32, + reasoning_effort="low", + ) + assert response.choices[0].message.content is not None + assert response.usage.total_tokens > 0 + + def test_should_accept_reasoning_effort_high(self): + """reasoning_effort='high' should be accepted by Nova 2 Lite.""" + response = litellm.completion( + model=NOVA2_MODEL, + messages=[{"role": "user", "content": "Explain why the sky is blue."}], + max_tokens=256, + reasoning_effort="high", + ) + assert response.choices[0].message.content is not None + assert len(response.choices[0].message.content) > 0 + assert response.usage.completion_tokens > 0 diff --git a/tests/test_litellm/llms/sagemaker/test_sagemaker_nova_transformation.py b/tests/test_litellm/llms/sagemaker/test_sagemaker_nova_transformation.py new file mode 100644 index 0000000000..8c468a1ff6 --- /dev/null +++ b/tests/test_litellm/llms/sagemaker/test_sagemaker_nova_transformation.py @@ -0,0 +1,393 @@ +""" +Unit tests for SageMaker Nova transformation config. +""" + +import json +import pytest + +from litellm.llms.sagemaker.nova.transformation import SagemakerNovaConfig +from litellm.types.utils import ModelResponse +from litellm.utils import convert_to_model_response_object + + +class TestSagemakerNovaConfig: + def setup_method(self): + self.config = SagemakerNovaConfig() + + def test_should_support_stream_param_in_request_body(self): + """Nova requires stream: true in the request body.""" + assert self.config.supports_stream_param_in_request_body is True + + def test_should_include_nova_specific_params(self): + """Nova-specific params should be in the supported params list.""" + params = self.config.get_supported_openai_params(model="my-nova-endpoint") + assert "top_k" in params + assert "reasoning_effort" in params + assert "allowed_token_ids" in params + assert "truncate_prompt_tokens" in params + + def test_should_include_standard_openai_params(self): + """Standard OpenAI params from parent should still be present.""" + params = self.config.get_supported_openai_params(model="my-nova-endpoint") + assert "temperature" in params + assert "max_tokens" in params + assert "top_p" in params + assert "stream" in params + assert "logprobs" in params + assert "top_logprobs" in params + assert "stream_options" in params + + def test_should_map_nova_params_to_request(self): + """Nova-specific params should pass through to optional_params.""" + optional_params = self.config.map_openai_params( + non_default_params={ + "top_k": 40, + "reasoning_effort": "low", + "temperature": 0.7, + }, + optional_params={}, + model="my-nova-endpoint", + drop_params=False, + ) + assert optional_params["top_k"] == 40 + assert optional_params["reasoning_effort"] == "low" + assert optional_params["temperature"] == 0.7 + + def test_should_generate_correct_url_non_streaming(self): + """Non-streaming URL should use /invocations.""" + url = self.config.get_complete_url( + api_base=None, + api_key=None, + model="my-nova-endpoint", + optional_params={"aws_region_name": "us-east-1"}, + litellm_params={}, + stream=False, + ) + assert url == "https://runtime.sagemaker.us-east-1.amazonaws.com/endpoints/my-nova-endpoint/invocations" + + def test_should_generate_correct_url_streaming(self): + """Streaming URL should use /invocations-response-stream.""" + url = self.config.get_complete_url( + api_base=None, + api_key=None, + model="my-nova-endpoint", + optional_params={"aws_region_name": "us-east-1"}, + litellm_params={}, + stream=True, + ) + assert url == "https://runtime.sagemaker.us-east-1.amazonaws.com/endpoints/my-nova-endpoint/invocations-response-stream" + + def test_should_have_custom_stream_wrapper(self): + """Nova should use custom stream wrapper (AWS EventStream).""" + assert self.config.has_custom_stream_wrapper is True + + +class TestSagemakerNovaResponseParsing: + """Test that Nova's OpenAI-compatible responses are correctly parsed.""" + + def test_should_parse_non_streaming_response(self): + """Nova non-streaming response should be parsed into ModelResponse.""" + nova_response = { + "id": "chatcmpl-123e4567-e89b-12d3-a456-426614174000", + "object": "chat.completion", + "created": 1677652288, + "model": "nova-micro-custom", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "Hello! How can I help?", + "refusal": None, + }, + "finish_reason": "stop", + } + ], + "usage": { + "prompt_tokens": 9, + "completion_tokens": 12, + "total_tokens": 21, + }, + } + result = convert_to_model_response_object( + response_object=nova_response, + model_response_object=ModelResponse(), + ) + assert result.id == "chatcmpl-123e4567-e89b-12d3-a456-426614174000" + assert result.choices[0].message.content == "Hello! How can I help?" + assert result.choices[0].finish_reason == "stop" + assert result.usage.prompt_tokens == 9 + assert result.usage.completion_tokens == 12 + assert result.usage.total_tokens == 21 + + def test_should_parse_response_with_reasoning_content(self): + """Nova reasoning_content should be extracted correctly.""" + nova_response = { + "id": "chatcmpl-reasoning-test", + "object": "chat.completion", + "created": 1677652288, + "model": "nova-2-lite-custom", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The answer is 4.", + "reasoning_content": "Let me think: 2+2=4", + }, + "finish_reason": "stop", + } + ], + "usage": { + "prompt_tokens": 15, + "completion_tokens": 20, + "total_tokens": 35, + }, + } + result = convert_to_model_response_object( + response_object=nova_response, + model_response_object=ModelResponse(), + ) + assert result.choices[0].message.content == "The answer is 4." + assert result.choices[0].message.reasoning_content == "Let me think: 2+2=4" + + def test_should_parse_response_with_logprobs(self): + """Nova logprobs should be preserved in response.""" + nova_response = { + "id": "chatcmpl-logprobs-test", + "object": "chat.completion", + "created": 1677652288, + "model": "nova-micro-custom", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "Hello", + }, + "logprobs": { + "content": [ + { + "token": "Hello", + "logprob": -0.5, + "top_logprobs": [ + {"token": "Hello", "logprob": -0.5}, + {"token": "Hi", "logprob": -1.2}, + ], + } + ] + }, + "finish_reason": "stop", + } + ], + "usage": { + "prompt_tokens": 5, + "completion_tokens": 1, + "total_tokens": 6, + }, + } + result = convert_to_model_response_object( + response_object=nova_response, + model_response_object=ModelResponse(), + ) + assert result.choices[0].logprobs is not None + assert result.choices[0].logprobs["content"][0]["token"] == "Hello" + + def test_should_parse_response_with_cached_tokens(self): + """Nova prompt_tokens_details with cached_tokens should be parsed.""" + nova_response = { + "id": "chatcmpl-cached-test", + "object": "chat.completion", + "created": 1677652288, + "model": "nova-micro-custom", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "Hi", + }, + "finish_reason": "stop", + } + ], + "usage": { + "prompt_tokens": 20, + "completion_tokens": 1, + "total_tokens": 21, + "prompt_tokens_details": {"cached_tokens": 10}, + }, + } + result = convert_to_model_response_object( + response_object=nova_response, + model_response_object=ModelResponse(), + ) + assert result.usage.prompt_tokens_details.cached_tokens == 10 + + +class TestSagemakerChatBackwardsCompatibility: + """Verify that changes to SagemakerChatConfig don't break existing sagemaker_chat callers.""" + + def setup_method(self): + from litellm.llms.sagemaker.chat.transformation import SagemakerChatConfig + self.config = SagemakerChatConfig() + + def test_should_not_support_stream_param_in_request_body(self): + """sagemaker_chat should NOT send stream in request body (unchanged behavior).""" + assert self.config.supports_stream_param_in_request_body is False + + def test_should_generate_correct_urls(self): + """sagemaker_chat URLs should be unchanged.""" + url = self.config.get_complete_url( + api_base=None, + api_key=None, + model="my-hf-endpoint", + optional_params={"aws_region_name": "us-west-2"}, + litellm_params={}, + stream=False, + ) + assert url == "https://runtime.sagemaker.us-west-2.amazonaws.com/endpoints/my-hf-endpoint/invocations" + + stream_url = self.config.get_complete_url( + api_base=None, + api_key=None, + model="my-hf-endpoint", + optional_params={"aws_region_name": "us-west-2"}, + litellm_params={}, + stream=True, + ) + assert stream_url == "https://runtime.sagemaker.us-west-2.amazonaws.com/endpoints/my-hf-endpoint/invocations-response-stream" + + def test_should_still_have_custom_stream_wrapper(self): + """sagemaker_chat should still use custom stream wrapper.""" + assert self.config.has_custom_stream_wrapper is True + + def test_should_not_include_nova_specific_params(self): + """sagemaker_chat should NOT have Nova-specific params.""" + params = self.config.get_supported_openai_params(model="my-hf-endpoint") + assert "top_k" not in params + assert "reasoning_effort" not in params + assert "allowed_token_ids" not in params + assert "truncate_prompt_tokens" not in params + + def test_should_preserve_standard_openai_params(self): + """sagemaker_chat should still support standard OpenAI params.""" + params = self.config.get_supported_openai_params(model="my-hf-endpoint") + assert "temperature" in params + assert "max_tokens" in params + assert "top_p" in params + assert "stream" in params + + def test_sync_stream_wrapper_uses_correct_provider_string(self): + """ + Verify that when get_sync_custom_stream_wrapper is called with + custom_llm_provider="sagemaker_chat", the CustomStreamWrapper + receives "sagemaker_chat" (not something else). + """ + from unittest.mock import patch, MagicMock + + mock_client = MagicMock() + mock_response = MagicMock() + mock_response.status_code = 200 + mock_response.iter_bytes.return_value = iter([]) + mock_client.post.return_value = mock_response + + with patch("litellm.llms.sagemaker.chat.transformation.CustomStreamWrapper") as mock_csw: + mock_csw.return_value = MagicMock() + self.config.get_sync_custom_stream_wrapper( + model="my-hf-endpoint", + custom_llm_provider="sagemaker_chat", + logging_obj=MagicMock(), + api_base="https://example.com", + headers={}, + data={}, + messages=[], + client=mock_client, + ) + mock_csw.assert_called_once() + call_kwargs = mock_csw.call_args[1] + assert call_kwargs["custom_llm_provider"] == "sagemaker_chat" + + def test_async_stream_wrapper_uses_correct_provider_string(self): + """ + Verify that when get_async_custom_stream_wrapper is called with + custom_llm_provider="sagemaker_chat", the CustomStreamWrapper + receives "sagemaker_chat". + """ + import asyncio + from unittest.mock import patch, MagicMock, AsyncMock + + mock_client = AsyncMock() + mock_response = MagicMock() + mock_response.status_code = 200 + + async def empty_aiter(): + return + yield # make it an async generator + + mock_response.aiter_bytes.return_value = empty_aiter() + mock_client.post.return_value = mock_response + + with patch("litellm.llms.sagemaker.chat.transformation.CustomStreamWrapper") as mock_csw: + mock_csw.return_value = MagicMock() + asyncio.run( + self.config.get_async_custom_stream_wrapper( + model="my-hf-endpoint", + custom_llm_provider="sagemaker_chat", + logging_obj=MagicMock(), + api_base="https://example.com", + headers={}, + data={}, + messages=[], + client=mock_client, + ) + ) + mock_csw.assert_called_once() + call_kwargs = mock_csw.call_args[1] + assert call_kwargs["custom_llm_provider"] == "sagemaker_chat" + + def test_async_stream_wrapper_llm_provider_enum_resolves(self): + """ + Verify LlmProviders(custom_llm_provider) resolves correctly for + "sagemaker_chat" and doesn't fall through to the ValueError fallback. + """ + from litellm.types.utils import LlmProviders + provider = LlmProviders("sagemaker_chat") + assert provider == LlmProviders.SAGEMAKER_CHAT + + +class TestSagemakerNovaTransformRequest: + """Test Nova-specific request transformation.""" + + def setup_method(self): + self.config = SagemakerNovaConfig() + + def test_should_not_include_model_in_request_body(self): + """Nova SageMaker endpoints reject 'model' in the request body.""" + request = self.config.transform_request( + model="my-nova-endpoint", + messages=[{"role": "user", "content": "Hello"}], + optional_params={"temperature": 0.7}, + litellm_params={}, + headers={}, + ) + assert "model" not in request + assert "messages" in request + assert request["temperature"] == 0.7 + + def test_should_include_all_nova_params_in_request(self): + """Nova-specific params should appear in the request body.""" + request = self.config.transform_request( + model="my-nova-endpoint", + messages=[{"role": "user", "content": "Hello"}], + optional_params={ + "top_k": 40, + "max_tokens": 512, + "reasoning_effort": "low", + }, + litellm_params={}, + headers={}, + ) + assert "model" not in request + assert request["top_k"] == 40 + assert request["max_tokens"] == 512 + assert request["reasoning_effort"] == "low" From 2bd527e62ea2f3d1ba097fdf801988063adc2186 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 14 Mar 2026 15:19:14 -0700 Subject: [PATCH 082/289] [Fix] Prevent second responses_api_bridge_check from overwriting first The second `responses_api_bridge_check` call unconditionally overwrote `responses_api_model_info` set by the first call. For models using the `responses/` prefix (e.g. `azure/responses/`), the first check correctly detected `mode: "responses"` and stripped the prefix, but the second check then overwrote it with an empty dict since the model no longer started with `responses/`. Skip the second check when the first already detected responses mode. Co-Authored-By: Claude Opus 4.6 --- litellm/main.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/litellm/main.py b/litellm/main.py index a9a1c38e3f..60d411c98a 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -1613,13 +1613,18 @@ def completion( # type: ignore # noqa: PLR0915 ) ## RESPONSES API BRIDGE LOGIC ## - check if model has 'mode: responses' in litellm.model_cost map - responses_api_model_info, model = responses_api_bridge_check( - model=model, - custom_llm_provider=custom_llm_provider, - web_search_options=web_search_options, - tools=tools, - reasoning_effort=reasoning_effort, - ) + # Only run the second bridge check if the first one didn't already + # detect responses mode (e.g. via the "responses/" prefix). The second + # check handles cases like gpt-5.4+ with tools+reasoning_effort that + # the first (early) check doesn't cover. + if responses_api_model_info.get("mode") != "responses": + responses_api_model_info, model = responses_api_bridge_check( + model=model, + custom_llm_provider=custom_llm_provider, + web_search_options=web_search_options, + tools=tools, + reasoning_effort=reasoning_effort, + ) if responses_api_model_info.get("mode") == "responses": from litellm.completion_extras import responses_api_bridge From e0b3fcb34cf6e2153e2af88ff745736a109394af Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Sat, 14 Mar 2026 15:19:40 -0700 Subject: [PATCH 083/289] refactor: update pr template to invite users to slack oss --- .github/pull_request_template.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index bd434bea39..d830c16dfa 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -11,6 +11,10 @@ - [ ] My PR's scope is as isolated as possible, it only solves 1 specific problem - [ ] I have requested a Greptile review by commenting `@greptileai` and received a **Confidence Score of at least 4/5** before requesting a maintainer review +## Delays in PR merge? + +If you're seeing a delay in your PR being merged, ping the LiteLLM Team on [Slack (#pr-review)](https://join.slack.com/t/litellmossslack/shared_invite/zt-3o7nkuyfr-p_kbNJj8taRfXGgQI1~YyA). + ## CI (LiteLLM team) > **CI status guideline:** From 6970e1000c6fc874e9351e06eba79e3a6054e642 Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Sat, 14 Mar 2026 15:28:37 -0700 Subject: [PATCH 084/289] fix: align DefaultInternalUserParams Pydantic default with runtime fallback The Pydantic default for user_role was INTERNAL_USER, but all runtime provisioning paths (SSO, SCIM, JWT) fall back to INTERNAL_USER_VIEW_ONLY when no settings are saved. This caused the UI to show "Internal User" on fresh instances while new users actually got "Internal Viewer". --- litellm/proxy/_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index b7ac4212cb..8bc77d300c 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -4262,7 +4262,7 @@ class DefaultInternalUserParams(LiteLLMPydanticObjectBase): LitellmUserRoles.PROXY_ADMIN_VIEW_ONLY, ] ] = Field( - default=LitellmUserRoles.INTERNAL_USER, + default=LitellmUserRoles.INTERNAL_USER_VIEW_ONLY, description="Default role assigned to new users created", ) max_budget: Optional[float] = Field( From c60f1dd590c23fe5b79699f9f3c4176a541c6b19 Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Sat, 14 Mar 2026 15:36:26 -0700 Subject: [PATCH 085/289] test: add regression test for fresh-instance default role sync Asserts that GET /get/internal_user_settings returns INTERNAL_USER_VIEW_ONLY on a fresh DB with no saved settings, matching the runtime fallback in SSO/SCIM/JWT provisioning. --- .../test_proxy_setting_endpoints.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py b/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py index 7378b14cdf..15ec901ab5 100644 --- a/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py +++ b/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py @@ -111,6 +111,43 @@ class TestProxySettingEndpoints: assert "user_role" in data["field_schema"]["properties"] assert "description" in data["field_schema"]["properties"]["user_role"] + def test_get_internal_user_settings_fresh_db_defaults_to_viewer( + self, mock_auth, monkeypatch + ): + """ + On a fresh DB with no saved settings, the GET endpoint should return + INTERNAL_USER_VIEW_ONLY as the default role — matching the runtime + fallback in SSO/SCIM/JWT provisioning paths. + """ + # Simulate fresh DB: no default_internal_user_params in config + empty_config = { + "litellm_settings": {}, + "general_settings": {}, + "environment_variables": {}, + } + + from litellm.proxy.proxy_server import proxy_config + + monkeypatch.setattr( + proxy_config, "get_config", lambda: empty_config # sync, wrapped by endpoint + ) + + import asyncio + + async def mock_get_config(): + return empty_config + + monkeypatch.setattr(proxy_config, "get_config", mock_get_config) + + response = client.get("/get/internal_user_settings") + assert response.status_code == 200 + + values = response.json()["values"] + assert values["user_role"] == LitellmUserRoles.INTERNAL_USER_VIEW_ONLY, ( + f"Fresh DB should default to INTERNAL_USER_VIEW_ONLY, got {values['user_role']}. " + "The Pydantic default must match the runtime fallback." + ) + def test_update_internal_user_settings( self, mock_proxy_config, mock_auth, monkeypatch ): From c95783e6411cd3fc4ef23ae45a0e2c4c41dd2c7d Mon Sep 17 00:00:00 2001 From: ryan-crabbe <128659760+ryan-crabbe@users.noreply.github.com> Date: Sat, 14 Mar 2026 15:42:17 -0700 Subject: [PATCH 086/289] Update tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- .../proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py b/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py index 15ec901ab5..bd9968ae93 100644 --- a/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py +++ b/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py @@ -128,12 +128,6 @@ class TestProxySettingEndpoints: from litellm.proxy.proxy_server import proxy_config - monkeypatch.setattr( - proxy_config, "get_config", lambda: empty_config # sync, wrapped by endpoint - ) - - import asyncio - async def mock_get_config(): return empty_config From 47ddd0d0bfc04c74c0d4d7ae3884aba4d97c6d6d Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Sat, 14 Mar 2026 15:51:00 -0700 Subject: [PATCH 087/289] fix: redact secrets from proxy log output Add SecretRedactionFilter to scrub API keys, tokens, and credentials from all log records (messages, args, tracebacks, extra fields). - Enable redaction by default; opt out with LITELLM_DISABLE_REDACT_SECRETS=true - Redact patterns: sk-*, Bearer tokens, x-api-key values, base64 creds - Handle JSON formatter exception hooks and percent-style format args - Snapshot dict iteration to avoid RuntimeError during concurrent logging --- litellm/_logging.py | 92 ++++++++- tests/test_litellm/test_secret_redaction.py | 215 ++++++++++++++++++++ 2 files changed, 304 insertions(+), 3 deletions(-) create mode 100644 tests/test_litellm/test_secret_redaction.py diff --git a/litellm/_logging.py b/litellm/_logging.py index fd833f7056..5de9fbb355 100644 --- a/litellm/_logging.py +++ b/litellm/_logging.py @@ -1,10 +1,11 @@ import ast import logging import os +import re import sys from datetime import datetime from logging import Formatter -from typing import Any, Dict, Optional +from typing import Any, Dict, List, Optional from litellm.litellm_core_utils.safe_json_dumps import safe_dumps from litellm.litellm_core_utils.safe_json_loads import safe_json_loads @@ -15,12 +16,94 @@ if set_verbose is True: logging.warning( "`litellm.set_verbose` is deprecated. Please set `os.environ['LITELLM_LOG'] = 'DEBUG'` for debug logs." ) + +_ENABLE_SECRET_REDACTION = os.getenv("LITELLM_DISABLE_REDACT_SECRETS", "").lower() != "true" + +_REDACTED = "REDACTED" + + +def _build_secret_patterns() -> re.Pattern: + patterns: List[str] = [ + # AWS access key IDs + r"(?:AKIA|ASIA)[0-9A-Z]{16}", + # AWS secrets / session tokens / access key IDs (key=value) + r"(?:aws_secret_access_key|aws_session_token|aws_access_key_id)" + r"\s*[:=]\s*[A-Za-z0-9/+=]{20,}", + # Bearer tokens (OAuth, JWT, etc.) + r"Bearer\s+[A-Za-z0-9\-._~+/]{10,}=*", + # Basic auth headers + r"Basic\s+[A-Za-z0-9+/]{10,}={0,2}", + # OpenAI / Anthropic sk- prefixed keys + r"sk-[A-Za-z0-9\-_]{20,}", + # Generic api_key / api-key / apikey (handles 'key': 'value' dict repr) + r"(?:api[_-]?key)['\"]?\s*[:=]\s*['\"]?[^\s,'\"})\]{}>]{8,}", + # x-api-key / api-key header values (handles 'key': 'value' dict repr) + r"(?:x-api-key|api-key)['\"]?\s*[:=]\s*['\"]?[^\s,'\"})\]{}>]+", + # Anthropic internal header keys + r"x-ak-[A-Za-z0-9\-_]{20,}", + # Google API keys + r"AIza[0-9A-Za-z\-_]{35}", + # Password / secret params (handles key=value and 'key': 'value') + r"\w*(?:password|passwd|client_secret|secret_key|_secret)" + r"['\"]?\s*[:=]\s*['\"]?[^\s,'\"})\]{}>]+", + # Database connection string credentials (scheme://user:pass@host) + r"(?<=://)[^\s'\"]*:[^\s'\"@]+(?=@)", + # Databricks personal access tokens + r"dapi[0-9a-f]{32}", + ] + return re.compile("|".join(patterns), re.IGNORECASE) + + +_SECRET_RE = _build_secret_patterns() + + +def _redact_string(value: str) -> str: + return _SECRET_RE.sub(_REDACTED, value) + + +class SecretRedactionFilter(logging.Filter): + """Scrubs known secret/credential patterns from log records.""" + + _formatter = logging.Formatter() + + def filter(self, record: logging.LogRecord) -> bool: + if not _ENABLE_SECRET_REDACTION: + return True + + try: + record.msg = _redact_string(record.getMessage()) + record.args = None + except Exception: + if isinstance(record.msg, str): + record.msg = _redact_string(record.msg) + + # Redact exception tracebacks + if record.exc_info and record.exc_info[1] is not None: + try: + record.exc_text = _redact_string( + self._formatter.formatException(record.exc_info) + ) + except Exception: + pass + + # Redact extra fields passed via logger.debug("msg", extra={...}) + for key, value in list(record.__dict__.items()): + if key not in _STANDARD_RECORD_ATTRS and isinstance(value, str): + setattr(record, key, _redact_string(value)) + + return True + + +_secret_filter = SecretRedactionFilter() + + json_logs = bool(os.getenv("JSON_LOGS", False)) # Create a handler for the logger (you may need to adapt this based on your needs) log_level = os.getenv("LITELLM_LOG", "DEBUG") numeric_level: str = getattr(logging, log_level.upper()) handler = logging.StreamHandler() handler.setLevel(numeric_level) +handler.addFilter(_secret_filter) def _try_parse_json_message(message: str) -> Optional[Dict[str, Any]]: @@ -116,7 +199,7 @@ class JsonFormatter(Formatter): json_record[key] = value if record.exc_info: - json_record["stacktrace"] = self.formatException(record.exc_info) + json_record["stacktrace"] = record.exc_text or self.formatException(record.exc_info) return safe_dumps(json_record) @@ -126,6 +209,7 @@ def _setup_json_exception_handlers(formatter): # Create a handler with JSON formatting for exceptions error_handler = logging.StreamHandler() error_handler.setFormatter(formatter) + error_handler.addFilter(_secret_filter) # Setup excepthook for uncaught exceptions def json_excepthook(exc_type, exc_value, exc_traceback): @@ -149,6 +233,7 @@ def _setup_json_exception_handlers(formatter): def async_json_exception_handler(loop, context): exception = context.get("exception") if exception: + exc_type = type(exception) record = logging.LogRecord( name="LiteLLM", level=logging.ERROR, @@ -156,7 +241,7 @@ def _setup_json_exception_handlers(formatter): lineno=0, msg=str(exception), args=(), - exc_info=None, + exc_info=(exc_type, exception, exception.__traceback__), ) error_handler.handle(record) else: @@ -240,6 +325,7 @@ def _initialize_loggers_with_handler(handler: logging.Handler): - Adds a handler to each logger - Prevents bubbling to parent/root (critical to prevent duplicate JSON logs) """ + handler.addFilter(_secret_filter) for lg in _get_loggers_to_initialize(): lg.handlers.clear() # remove any existing handlers lg.addHandler(handler) # add JSON formatter handler diff --git a/tests/test_litellm/test_secret_redaction.py b/tests/test_litellm/test_secret_redaction.py new file mode 100644 index 0000000000..821529c111 --- /dev/null +++ b/tests/test_litellm/test_secret_redaction.py @@ -0,0 +1,215 @@ +import logging +import sys +from io import StringIO +from unittest.mock import patch + +import pytest + +from litellm._logging import ( + JsonFormatter, + _redact_string, + _secret_filter, + _setup_json_exception_handlers, + verbose_logger, + verbose_proxy_logger, + verbose_router_logger, +) + +SECRET = "sk-proj-abc123def456ghi789jklmnopqrst" + + +@pytest.fixture(autouse=True) +def _enable_redaction(): + """Ensure secret redaction is on (the default) for all tests in this module.""" + with patch("litellm._logging._ENABLE_SECRET_REDACTION", True): + yield + + +def _capture_logger_output(fn): + """Run fn with all litellm loggers wired to a StringIO buffer, return output.""" + buf = StringIO() + h = logging.StreamHandler(buf) + h.addFilter(_secret_filter) + loggers = [verbose_logger, verbose_proxy_logger, verbose_router_logger] + saved = [(lg, lg.handlers[:], lg.level) for lg in loggers] + for lg in loggers: + lg.handlers.clear() + lg.addHandler(h) + lg.setLevel(logging.DEBUG) + try: + fn() + return buf.getvalue() + finally: + for lg, handlers, level in saved: + lg.handlers.clear() + for old_h in handlers: + lg.addHandler(old_h) + lg.setLevel(level) + + +def test_redact_string_catches_secret_patterns(): + """Core regex patterns redact known secret formats.""" + cases = [ + "Bearer eyJhbGciOiJSUzI1NiJ9.payload.sig", + "api_key=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6", + "password=supersecretpassword123", + "postgresql://admin:s3cretpass@db.example.com:5432/mydb", + SECRET, + ] + for secret in cases: + result = _redact_string("msg: " + secret) + assert secret not in result, f"{secret!r} was not redacted" + assert "REDACTED" in result + + normal = "Loaded model gpt-4 with 3 replicas on us-east-1" + assert _redact_string(normal) == normal + + +def test_filter_redacts_secrets_in_logger_output(): + def log_messages(): + verbose_logger.debug("Key: " + SECRET) + verbose_logger.debug("Normal message with no secrets") + + output = _capture_logger_output(log_messages) + assert SECRET not in output + assert "REDACTED" in output + assert "Normal message with no secrets" in output + + +def test_filter_redacts_percent_style_args(): + """Secrets passed as %-style args should be redacted.""" + + def log_messages(): + verbose_logger.debug("key=%s region=%s", SECRET, "us-east-1") + + output = _capture_logger_output(log_messages) + assert SECRET not in output + assert "us-east-1" in output + + +def test_filter_redacts_non_string_args(): + """Secrets inside dicts/lists passed as %-style args should be redacted.""" + + def log_messages(): + verbose_logger.debug("Config: %s", {"nested": {"key": SECRET}}) + verbose_logger.debug("Keys: %s", [SECRET]) + + output = _capture_logger_output(log_messages) + assert SECRET not in output + assert "REDACTED" in output + + +def test_filter_redacts_exception_tracebacks(): + """Secrets embedded in exception messages must be redacted in tracebacks.""" + + def log_messages(): + try: + raise ValueError(f"Auth failed with key {SECRET}") + except ValueError: + verbose_logger.exception("Something went wrong") + + output = _capture_logger_output(log_messages) + assert SECRET not in output + assert "REDACTED" in output + assert "Something went wrong" in output + + +def test_filter_redacts_extra_fields(): + """Secrets passed via extra={...} must be redacted on the record.""" + record = logging.LogRecord( + name="test", + level=logging.DEBUG, + pathname="", + lineno=0, + msg="request completed", + args=(), + exc_info=None, + ) + record.api_key = SECRET + record.region = "us-east-1" + + _secret_filter.filter(record) + + assert SECRET not in record.api_key + assert "REDACTED" in record.api_key + assert record.region == "us-east-1" + + +def test_disable_redaction_passes_secrets_through(): + """When LITELLM_DISABLE_REDACT_SECRETS=true, secrets pass through.""" + with patch("litellm._logging._ENABLE_SECRET_REDACTION", False): + record = logging.LogRecord( + name="test", + level=logging.DEBUG, + pathname="", + lineno=0, + msg="key=" + SECRET, + args=(), + exc_info=None, + ) + _secret_filter.filter(record) + assert "sk-proj-" in record.msg + + +def test_x_api_key_regex_does_not_consume_json_delimiters(): + """x-api-key pattern must stop before closing quotes/braces so JSON stays valid.""" + # Simulates a JSON log line containing an x-api-key header value + json_line = '{"headers": {"x-api-key": "secret123"}, "status": 200}' + result = _redact_string(json_line) + # The secret value should be redacted + assert "secret123" not in result + assert "REDACTED" in result + # Closing delimiter must survive so the line is still valid-ish JSON + assert '"status": 200' in result + assert "}" in result + + +def test_json_excepthook_redacts_secrets(): + """Unhandled exceptions in JSON mode must have secrets redacted.""" + buf = StringIO() + h = logging.StreamHandler(buf) + h.setFormatter(JsonFormatter()) + h.addFilter(_secret_filter) + + # Capture what the excepthook would emit + record = logging.LogRecord( + name="LiteLLM", + level=logging.ERROR, + pathname="", + lineno=0, + msg=f"Connection failed with key {SECRET}", + args=(), + exc_info=None, + ) + # Simulate the filter + formatter pipeline + _secret_filter.filter(record) + output = h.formatter.format(record) + assert SECRET not in output + assert "REDACTED" in output + + +def test_json_excepthook_redacts_traceback_secrets(): + """Unhandled exception tracebacks in JSON mode must have secrets redacted.""" + buf = StringIO() + h = logging.StreamHandler(buf) + h.setFormatter(JsonFormatter()) + h.addFilter(_secret_filter) + + try: + raise RuntimeError(f"Failed to auth with {SECRET}") + except RuntimeError: + exc_info = sys.exc_info() + + record = logging.LogRecord( + name="LiteLLM", + level=logging.ERROR, + pathname="", + lineno=0, + msg=str(exc_info[1]), + args=(), + exc_info=exc_info, + ) + _secret_filter.filter(record) + output = h.formatter.format(record) + assert SECRET not in output + assert "REDACTED" in output From e45c82aea070fe40f725fbeb40eb83493b80f310 Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Sat, 14 Mar 2026 15:59:52 -0700 Subject: [PATCH 088/289] docs: add LITELLM_DISABLE_REDACT_SECRETS to environment variable reference --- docs/my-website/docs/proxy/config_settings.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/my-website/docs/proxy/config_settings.md b/docs/my-website/docs/proxy/config_settings.md index 4f25e6c109..a0e404e3a1 100644 --- a/docs/my-website/docs/proxy/config_settings.md +++ b/docs/my-website/docs/proxy/config_settings.md @@ -778,6 +778,7 @@ router_settings: | LITELLM_GLOBAL_MAX_PARALLEL_REQUEST_RETRIES | Maximum retries for parallel requests in LiteLLM | LITELLM_GLOBAL_MAX_PARALLEL_REQUEST_RETRY_TIMEOUT | Timeout for retries of parallel requests in LiteLLM | LITELLM_DISABLE_LAZY_LOADING | When set to "1", "true", "yes", or "on", disables lazy loading of attributes (currently only affects encoding/tiktoken). This ensures encoding is initialized before VCR starts recording HTTP requests, fixing VCR cassette creation issues. See [issue #18659](https://github.com/BerriAI/litellm/issues/18659) +| LITELLM_DISABLE_REDACT_SECRETS | When set to "true", disables automatic redaction of secrets (API keys, tokens, credentials) from proxy log output. Secret redaction is enabled by default. | LITELLM_MIGRATION_DIR | Custom migrations directory for prisma migrations, used for baselining db in read-only file systems. | LITELLM_HOSTED_UI | URL of the hosted UI for LiteLLM | LITELLM_UI_API_DOC_BASE_URL | Optional override for the API Reference base URL (used in sample code/docs) when the admin UI runs on a different host than the proxy. Defaults to `PROXY_BASE_URL` when unset. From 1d753c3fa62b58aa19e805975e9ef40aa146890d Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 14 Mar 2026 16:38:34 -0700 Subject: [PATCH 089/289] [Fix] Allow team admins to query /user/filter/ui when scope_user_search_to_org is enabled When scope_user_search_to_org flag is ON, team admins (non-org-admins) were getting 403 because the code only checked for ORG_ADMIN role in org memberships. Now checks all org memberships (any role) and falls back to the API key's team_id to resolve the org. Co-Authored-By: Claude Opus 4.6 --- .../internal_user_endpoints.py | 17 ++- .../test_internal_user_endpoints.py | 131 ++++++++++++++++++ 2 files changed, 141 insertions(+), 7 deletions(-) diff --git a/litellm/proxy/management_endpoints/internal_user_endpoints.py b/litellm/proxy/management_endpoints/internal_user_endpoints.py index 356080e0ac..8a71b8d4b5 100644 --- a/litellm/proxy/management_endpoints/internal_user_endpoints.py +++ b/litellm/proxy/management_endpoints/internal_user_endpoints.py @@ -2137,21 +2137,24 @@ async def _resolve_org_filter_for_user_search( except ValueError: caller_user = None - org_admin_org_ids: List[str] = [] + # Collect org IDs from ALL org memberships (any role, not just ORG_ADMIN). + # This allows team admins who are org members to search users in their org. + member_org_ids: List[str] = [] if caller_user is not None: - org_admin_org_ids = [ + member_org_ids = [ m.organization_id for m in (caller_user.organization_memberships or []) - if m.user_role == LitellmUserRoles.ORG_ADMIN.value ] - if org_admin_org_ids: - return org_admin_org_ids + if member_org_ids: + return member_org_ids - if team_id is not None: + # Fall back to resolving via team_id (query param or from the caller's API key) + resolved_team_id = team_id or user_api_key_dict.team_id + if resolved_team_id is not None: return await _resolve_team_org_filter( user_api_key_dict, - team_id, + resolved_team_id, prisma_client, user_api_key_cache, proxy_logging_obj, diff --git a/tests/test_litellm/proxy/management_endpoints/test_internal_user_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_internal_user_endpoints.py index 3ef87c62cd..e358cbe3be 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_internal_user_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_internal_user_endpoints.py @@ -431,6 +431,137 @@ async def test_ui_view_users_flag_on_non_admin_no_team_id_403(mocker): assert "scope_user_search_to_org is enabled" in str(exc_info.value.detail) +@pytest.mark.asyncio +async def test_ui_view_users_flag_on_team_admin_org_member_no_team_id(mocker): + """ + Flag ON, team admin who is an org member (not org admin), no team_id param: + should succeed and filter by the user's org membership. + """ + mock_prisma_client = mocker.MagicMock() + org_id = "org-member-org" + + async def mock_find_many(*args, **kwargs): + where = kwargs.get("where") or {} + assert "organization_memberships" in where + assert where["organization_memberships"] == { + "some": {"organization_id": {"in": [org_id]}} + } + return [] + + mock_prisma_client.db.litellm_usertable.find_many = mock_find_many + + mocker.patch( + "litellm.proxy.ui_crud_endpoints.proxy_setting_endpoints.get_ui_settings_cached", + return_value={"scope_user_search_to_org": True}, + ) + + mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma_client) + mocker.patch("litellm.proxy.proxy_server.user_api_key_cache", mocker.MagicMock()) + mocker.patch("litellm.proxy.proxy_server.proxy_logging_obj", mocker.MagicMock()) + + # Caller is org member (internal_user role, not org admin) + membership = mocker.MagicMock() + membership.organization_id = org_id + membership.user_role = "internal_user" + + caller_user = mocker.MagicMock() + caller_user.organization_memberships = [membership] + + async def mock_get_user_object(*args, **kwargs): + return caller_user + + mocker.patch( + "litellm.proxy.management_endpoints.internal_user_endpoints.get_user_object", + side_effect=mock_get_user_object, + ) + + response = await ui_view_users( + user_api_key_dict=UserAPIKeyAuth(user_id="team-admin-in-org", user_role=None), + user_id=None, + user_email="u", + team_id=None, + page=1, + page_size=50, + ) + + assert response == [] + + +@pytest.mark.asyncio +async def test_ui_view_users_flag_on_team_admin_not_in_org_resolves_via_key_team( + mocker, +): + """ + Flag ON, team admin NOT in any org, no team_id query param but + user_api_key_dict.team_id is set: resolves org via the key's team. + """ + from litellm.proxy._types import LiteLLM_TeamTableCachedObj + + mock_prisma_client = mocker.MagicMock() + org_id = "org-from-team" + tid = "key-team-id" + + async def mock_find_many(*args, **kwargs): + where = kwargs.get("where") or {} + assert "organization_memberships" in where + assert where["organization_memberships"] == { + "some": {"organization_id": {"in": [org_id]}} + } + return [] + + mock_prisma_client.db.litellm_usertable.find_many = mock_find_many + + mocker.patch( + "litellm.proxy.ui_crud_endpoints.proxy_setting_endpoints.get_ui_settings_cached", + return_value={"scope_user_search_to_org": True}, + ) + + team_obj = LiteLLM_TeamTableCachedObj( + team_id=tid, + team_alias="key-team", + organization_id=org_id, + members_with_roles=[{"user_id": "team-admin-no-org", "role": "admin"}], + ) + + async def mock_get_team_object(*args, **kwargs): + return team_obj + + mocker.patch( + "litellm.proxy.management_endpoints.internal_user_endpoints.get_team_object", + side_effect=mock_get_team_object, + ) + + mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma_client) + mocker.patch("litellm.proxy.proxy_server.user_api_key_cache", mocker.MagicMock()) + mocker.patch("litellm.proxy.proxy_server.proxy_logging_obj", mocker.MagicMock()) + + # Caller has no org memberships + caller_user = mocker.MagicMock() + caller_user.organization_memberships = [] + + async def mock_get_user_object(*args, **kwargs): + return caller_user + + mocker.patch( + "litellm.proxy.management_endpoints.internal_user_endpoints.get_user_object", + side_effect=mock_get_user_object, + ) + + # No team_id query param, but team_id on the API key + response = await ui_view_users( + user_api_key_dict=UserAPIKeyAuth( + user_id="team-admin-no-org", user_role=None, team_id=tid + ), + user_id=None, + user_email="u", + team_id=None, + page=1, + page_size=50, + ) + + assert response == [] + + def test_user_daily_activity_types(): """ Assert all fiels in SpendMetrics are reported in DailySpendMetadata as "total_" From d28e42d7ceeaa01d3a4f59c592c5b97abd54066f Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 14 Mar 2026 16:50:13 -0700 Subject: [PATCH 090/289] chore: update Next.js build artifacts (2026-03-14 23:50 UTC, node v22.16.0) --- litellm/proxy/_experimental/out/404.html | 2 +- .../proxy/_experimental/out/__next.__PAGE__.txt | 10 +++++----- litellm/proxy/_experimental/out/__next._full.txt | 16 ++++++++-------- litellm/proxy/_experimental/out/__next._head.txt | 2 +- .../proxy/_experimental/out/__next._index.txt | 2 +- litellm/proxy/_experimental/out/__next._tree.txt | 2 +- .../_buildManifest.js | 0 .../_clientMiddlewareManifest.json | 0 .../_ssgManifest.js | 0 .../out/_next/static/chunks/07fd9d7c5c879cb6.js | 1 - .../out/_next/static/chunks/0bffe854234d50c4.js | 8 -------- .../{69365f493e1655a4.js => 0dda11815be4f78b.js} | 4 ++-- .../out/_next/static/chunks/123bb7375879d789.js | 3 +++ .../{92260915afd3dac5.js => 179425128d293da9.js} | 2 +- .../out/_next/static/chunks/23bf955e8672ce98.js | 1 + .../{0b06d056425a991f.js => 2bacff998dbae5da.js} | 4 ++-- .../out/_next/static/chunks/2f9ed92e7b7cd792.js | 1 - .../out/_next/static/chunks/31ad6450b9c696ec.js | 1 - .../{81b595b330469e25.js => 38976546132cd527.js} | 4 ++-- .../{9b0c03a2b0969129.js => 3b3c0b070b14da06.js} | 4 ++-- .../{b08200c758c5c505.js => 3da2633a10defd79.js} | 2 +- .../{e99f98e7f34532c9.js => 40f766ecc87dbf9a.js} | 2 +- .../out/_next/static/chunks/4348e537165edb3b.js | 1 + .../{3413b6a1ede03f29.js => 5595eb6378e90997.js} | 2 +- .../{f2ee2fa5fe008110.js => 62a03e24dd5227b9.js} | 2 +- .../{0adb91ab5f3140d5.js => 67ddb5107368a659.js} | 2 +- .../{f728bd69dddaff23.js => 68066e020262ced9.js} | 2 +- .../{16d77647b44247de.js => 715057b8e12f1cd9.js} | 2 +- .../{531dc633eecbb64f.js => 7174130ddef406dd.js} | 8 ++++---- .../out/_next/static/chunks/8cc98e6cf29063c4.js | 1 + .../{5ec157703332dbc8.js => 90c332d66ef5954b.js} | 2 +- .../out/_next/static/chunks/94b1900e63940a2b.js | 8 ++++++++ .../out/_next/static/chunks/9668e5e89a8b80cb.js | 1 - .../{fa6fc6b79591df63.js => a89452659b6e1d90.js} | 2 +- .../out/_next/static/chunks/aae16a3ce4812424.js | 1 - .../out/_next/static/chunks/d223c00dadf4b924.js | 1 + .../out/_next/static/chunks/d2dd9cccff5163b7.js | 3 --- .../out/_next/static/chunks/e42252ef58f496fe.js | 1 - .../out/_next/static/chunks/e775bbab37491d9c.js | 1 + .../{503ca4764960a7c8.js => ed079ecd9e95349e.js} | 4 ++-- .../out/_next/static/chunks/f683569e573c506e.js | 1 + litellm/proxy/_experimental/out/_not-found.html | 2 +- litellm/proxy/_experimental/out/_not-found.txt | 2 +- .../out/_not-found/__next._full.txt | 2 +- .../out/_not-found/__next._head.txt | 2 +- .../out/_not-found/__next._index.txt | 2 +- .../_not-found/__next._not-found.__PAGE__.txt | 2 +- .../out/_not-found/__next._not-found.txt | 2 +- .../out/_not-found/__next._tree.txt | 2 +- .../proxy/_experimental/out/api-reference.html | 2 +- .../proxy/_experimental/out/api-reference.txt | 6 +++--- ...t.!KGRhc2hib2FyZCk.api-reference.__PAGE__.txt | 4 ++-- .../__next.!KGRhc2hib2FyZCk.api-reference.txt | 2 +- .../api-reference/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../out/api-reference/__next._full.txt | 6 +++--- .../out/api-reference/__next._head.txt | 2 +- .../out/api-reference/__next._index.txt | 2 +- .../out/api-reference/__next._tree.txt | 2 +- litellm/proxy/_experimental/out/chat.html | 2 +- litellm/proxy/_experimental/out/chat.txt | 4 ++-- .../_experimental/out/chat/__next._full.txt | 4 ++-- .../_experimental/out/chat/__next._head.txt | 2 +- .../_experimental/out/chat/__next._index.txt | 2 +- .../_experimental/out/chat/__next._tree.txt | 2 +- .../out/chat/__next.chat.__PAGE__.txt | 4 ++-- .../proxy/_experimental/out/chat/__next.chat.txt | 2 +- .../out/experimental/api-playground.html | 2 +- .../out/experimental/api-playground.txt | 6 +++--- ...yZCk.experimental.api-playground.__PAGE__.txt | 4 ++-- ...Rhc2hib2FyZCk.experimental.api-playground.txt | 2 +- .../__next.!KGRhc2hib2FyZCk.experimental.txt | 2 +- .../api-playground/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../experimental/api-playground/__next._full.txt | 6 +++--- .../experimental/api-playground/__next._head.txt | 2 +- .../api-playground/__next._index.txt | 2 +- .../experimental/api-playground/__next._tree.txt | 2 +- .../_experimental/out/experimental/budgets.html | 2 +- .../_experimental/out/experimental/budgets.txt | 6 +++--- ...c2hib2FyZCk.experimental.budgets.__PAGE__.txt | 4 ++-- ...ext.!KGRhc2hib2FyZCk.experimental.budgets.txt | 2 +- .../__next.!KGRhc2hib2FyZCk.experimental.txt | 2 +- .../budgets/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../out/experimental/budgets/__next._full.txt | 6 +++--- .../out/experimental/budgets/__next._head.txt | 2 +- .../out/experimental/budgets/__next._index.txt | 2 +- .../out/experimental/budgets/__next._tree.txt | 2 +- .../_experimental/out/experimental/caching.html | 2 +- .../_experimental/out/experimental/caching.txt | 6 +++--- ...c2hib2FyZCk.experimental.caching.__PAGE__.txt | 4 ++-- ...ext.!KGRhc2hib2FyZCk.experimental.caching.txt | 2 +- .../__next.!KGRhc2hib2FyZCk.experimental.txt | 2 +- .../caching/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../out/experimental/caching/__next._full.txt | 6 +++--- .../out/experimental/caching/__next._head.txt | 2 +- .../out/experimental/caching/__next._index.txt | 2 +- .../out/experimental/caching/__next._tree.txt | 2 +- .../out/experimental/claude-code-plugins.html | 2 +- .../out/experimental/claude-code-plugins.txt | 6 +++--- ...experimental.claude-code-plugins.__PAGE__.txt | 4 ++-- ...ib2FyZCk.experimental.claude-code-plugins.txt | 2 +- .../__next.!KGRhc2hib2FyZCk.experimental.txt | 2 +- .../__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../claude-code-plugins/__next._full.txt | 6 +++--- .../claude-code-plugins/__next._head.txt | 2 +- .../claude-code-plugins/__next._index.txt | 2 +- .../claude-code-plugins/__next._tree.txt | 2 +- .../out/experimental/old-usage.html | 2 +- .../_experimental/out/experimental/old-usage.txt | 8 ++++---- ...hib2FyZCk.experimental.old-usage.__PAGE__.txt | 4 ++-- ...t.!KGRhc2hib2FyZCk.experimental.old-usage.txt | 2 +- .../__next.!KGRhc2hib2FyZCk.experimental.txt | 2 +- .../old-usage/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../out/experimental/old-usage/__next._full.txt | 8 ++++---- .../out/experimental/old-usage/__next._head.txt | 2 +- .../out/experimental/old-usage/__next._index.txt | 2 +- .../out/experimental/old-usage/__next._tree.txt | 2 +- .../_experimental/out/experimental/prompts.html | 2 +- .../_experimental/out/experimental/prompts.txt | 6 +++--- ...c2hib2FyZCk.experimental.prompts.__PAGE__.txt | 4 ++-- ...ext.!KGRhc2hib2FyZCk.experimental.prompts.txt | 2 +- .../__next.!KGRhc2hib2FyZCk.experimental.txt | 2 +- .../prompts/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../out/experimental/prompts/__next._full.txt | 6 +++--- .../out/experimental/prompts/__next._head.txt | 2 +- .../out/experimental/prompts/__next._index.txt | 2 +- .../out/experimental/prompts/__next._tree.txt | 2 +- .../out/experimental/tag-management.html | 2 +- .../out/experimental/tag-management.txt | 8 ++++---- ...yZCk.experimental.tag-management.__PAGE__.txt | 4 ++-- ...Rhc2hib2FyZCk.experimental.tag-management.txt | 2 +- .../__next.!KGRhc2hib2FyZCk.experimental.txt | 2 +- .../tag-management/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../experimental/tag-management/__next._full.txt | 8 ++++---- .../experimental/tag-management/__next._head.txt | 2 +- .../tag-management/__next._index.txt | 2 +- .../experimental/tag-management/__next._tree.txt | 2 +- litellm/proxy/_experimental/out/guardrails.html | 2 +- litellm/proxy/_experimental/out/guardrails.txt | 6 +++--- ...next.!KGRhc2hib2FyZCk.guardrails.__PAGE__.txt | 4 ++-- .../__next.!KGRhc2hib2FyZCk.guardrails.txt | 2 +- .../out/guardrails/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../out/guardrails/__next._full.txt | 6 +++--- .../out/guardrails/__next._head.txt | 2 +- .../out/guardrails/__next._index.txt | 2 +- .../out/guardrails/__next._tree.txt | 2 +- litellm/proxy/_experimental/out/index.html | 2 +- litellm/proxy/_experimental/out/index.txt | 16 ++++++++-------- litellm/proxy/_experimental/out/login.html | 2 +- litellm/proxy/_experimental/out/login.txt | 4 ++-- .../_experimental/out/login/__next._full.txt | 4 ++-- .../_experimental/out/login/__next._head.txt | 2 +- .../_experimental/out/login/__next._index.txt | 2 +- .../_experimental/out/login/__next._tree.txt | 2 +- .../out/login/__next.login.__PAGE__.txt | 4 ++-- .../_experimental/out/login/__next.login.txt | 2 +- litellm/proxy/_experimental/out/logs.html | 2 +- litellm/proxy/_experimental/out/logs.txt | 8 ++++---- .../__next.!KGRhc2hib2FyZCk.logs.__PAGE__.txt | 4 ++-- .../out/logs/__next.!KGRhc2hib2FyZCk.logs.txt | 2 +- .../out/logs/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../_experimental/out/logs/__next._full.txt | 8 ++++---- .../_experimental/out/logs/__next._head.txt | 2 +- .../_experimental/out/logs/__next._index.txt | 2 +- .../_experimental/out/logs/__next._tree.txt | 2 +- .../_experimental/out/mcp/oauth/callback.html | 2 +- .../_experimental/out/mcp/oauth/callback.txt | 2 +- .../out/mcp/oauth/callback/__next._full.txt | 2 +- .../out/mcp/oauth/callback/__next._head.txt | 2 +- .../out/mcp/oauth/callback/__next._index.txt | 2 +- .../out/mcp/oauth/callback/__next._tree.txt | 2 +- .../__next.mcp.oauth.callback.__PAGE__.txt | 2 +- .../oauth/callback/__next.mcp.oauth.callback.txt | 2 +- .../out/mcp/oauth/callback/__next.mcp.oauth.txt | 2 +- .../out/mcp/oauth/callback/__next.mcp.txt | 2 +- litellm/proxy/_experimental/out/model-hub.html | 2 +- litellm/proxy/_experimental/out/model-hub.txt | 6 +++--- ..._next.!KGRhc2hib2FyZCk.model-hub.__PAGE__.txt | 4 ++-- .../__next.!KGRhc2hib2FyZCk.model-hub.txt | 2 +- .../out/model-hub/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../_experimental/out/model-hub/__next._full.txt | 6 +++--- .../_experimental/out/model-hub/__next._head.txt | 2 +- .../out/model-hub/__next._index.txt | 2 +- .../_experimental/out/model-hub/__next._tree.txt | 2 +- litellm/proxy/_experimental/out/model_hub.html | 2 +- litellm/proxy/_experimental/out/model_hub.txt | 4 ++-- .../_experimental/out/model_hub/__next._full.txt | 4 ++-- .../_experimental/out/model_hub/__next._head.txt | 2 +- .../out/model_hub/__next._index.txt | 2 +- .../_experimental/out/model_hub/__next._tree.txt | 2 +- .../out/model_hub/__next.model_hub.__PAGE__.txt | 4 ++-- .../out/model_hub/__next.model_hub.txt | 2 +- .../proxy/_experimental/out/model_hub_table.html | 2 +- .../proxy/_experimental/out/model_hub_table.txt | 4 ++-- .../out/model_hub_table/__next._full.txt | 4 ++-- .../out/model_hub_table/__next._head.txt | 2 +- .../out/model_hub_table/__next._index.txt | 2 +- .../out/model_hub_table/__next._tree.txt | 2 +- .../__next.model_hub_table.__PAGE__.txt | 4 ++-- .../model_hub_table/__next.model_hub_table.txt | 2 +- .../_experimental/out/models-and-endpoints.html | 2 +- .../_experimental/out/models-and-endpoints.txt | 8 ++++---- ...c2hib2FyZCk.models-and-endpoints.__PAGE__.txt | 4 ++-- ...ext.!KGRhc2hib2FyZCk.models-and-endpoints.txt | 2 +- .../__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../out/models-and-endpoints/__next._full.txt | 8 ++++---- .../out/models-and-endpoints/__next._head.txt | 2 +- .../out/models-and-endpoints/__next._index.txt | 2 +- .../out/models-and-endpoints/__next._tree.txt | 2 +- litellm/proxy/_experimental/out/onboarding.html | 2 +- litellm/proxy/_experimental/out/onboarding.txt | 4 ++-- .../out/onboarding/__next._full.txt | 4 ++-- .../out/onboarding/__next._head.txt | 2 +- .../out/onboarding/__next._index.txt | 2 +- .../out/onboarding/__next._tree.txt | 2 +- .../onboarding/__next.onboarding.__PAGE__.txt | 4 ++-- .../out/onboarding/__next.onboarding.txt | 2 +- .../proxy/_experimental/out/organizations.html | 2 +- .../proxy/_experimental/out/organizations.txt | 8 ++++---- ...t.!KGRhc2hib2FyZCk.organizations.__PAGE__.txt | 4 ++-- .../__next.!KGRhc2hib2FyZCk.organizations.txt | 2 +- .../organizations/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../out/organizations/__next._full.txt | 8 ++++---- .../out/organizations/__next._head.txt | 2 +- .../out/organizations/__next._index.txt | 2 +- .../out/organizations/__next._tree.txt | 2 +- litellm/proxy/_experimental/out/playground.html | 2 +- litellm/proxy/_experimental/out/playground.txt | 6 +++--- ...next.!KGRhc2hib2FyZCk.playground.__PAGE__.txt | 4 ++-- .../__next.!KGRhc2hib2FyZCk.playground.txt | 2 +- .../out/playground/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../out/playground/__next._full.txt | 6 +++--- .../out/playground/__next._head.txt | 2 +- .../out/playground/__next._index.txt | 2 +- .../out/playground/__next._tree.txt | 2 +- litellm/proxy/_experimental/out/policies.html | 2 +- litellm/proxy/_experimental/out/policies.txt | 6 +++--- ...__next.!KGRhc2hib2FyZCk.policies.__PAGE__.txt | 4 ++-- .../__next.!KGRhc2hib2FyZCk.policies.txt | 2 +- .../out/policies/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../_experimental/out/policies/__next._full.txt | 6 +++--- .../_experimental/out/policies/__next._head.txt | 2 +- .../_experimental/out/policies/__next._index.txt | 2 +- .../_experimental/out/policies/__next._tree.txt | 2 +- .../out/settings/admin-settings.html | 2 +- .../out/settings/admin-settings.txt | 6 +++--- ...ib2FyZCk.settings.admin-settings.__PAGE__.txt | 4 ++-- ....!KGRhc2hib2FyZCk.settings.admin-settings.txt | 2 +- .../__next.!KGRhc2hib2FyZCk.settings.txt | 2 +- .../admin-settings/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../out/settings/admin-settings/__next._full.txt | 6 +++--- .../out/settings/admin-settings/__next._head.txt | 2 +- .../settings/admin-settings/__next._index.txt | 2 +- .../out/settings/admin-settings/__next._tree.txt | 2 +- .../out/settings/logging-and-alerts.html | 2 +- .../out/settings/logging-and-alerts.txt | 6 +++--- ...yZCk.settings.logging-and-alerts.__PAGE__.txt | 4 ++-- ...Rhc2hib2FyZCk.settings.logging-and-alerts.txt | 2 +- .../__next.!KGRhc2hib2FyZCk.settings.txt | 2 +- .../__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../settings/logging-and-alerts/__next._full.txt | 6 +++--- .../settings/logging-and-alerts/__next._head.txt | 2 +- .../logging-and-alerts/__next._index.txt | 2 +- .../settings/logging-and-alerts/__next._tree.txt | 2 +- .../out/settings/router-settings.html | 2 +- .../out/settings/router-settings.txt | 8 ++++---- ...b2FyZCk.settings.router-settings.__PAGE__.txt | 4 ++-- ...!KGRhc2hib2FyZCk.settings.router-settings.txt | 2 +- .../__next.!KGRhc2hib2FyZCk.settings.txt | 2 +- .../router-settings/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../settings/router-settings/__next._full.txt | 8 ++++---- .../settings/router-settings/__next._head.txt | 2 +- .../settings/router-settings/__next._index.txt | 2 +- .../settings/router-settings/__next._tree.txt | 2 +- .../_experimental/out/settings/ui-theme.html | 2 +- .../_experimental/out/settings/ui-theme.txt | 6 +++--- .../__next.!KGRhc2hib2FyZCk.settings.txt | 2 +- ...GRhc2hib2FyZCk.settings.ui-theme.__PAGE__.txt | 4 ++-- ...__next.!KGRhc2hib2FyZCk.settings.ui-theme.txt | 2 +- .../ui-theme/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../out/settings/ui-theme/__next._full.txt | 6 +++--- .../out/settings/ui-theme/__next._head.txt | 2 +- .../out/settings/ui-theme/__next._index.txt | 2 +- .../out/settings/ui-theme/__next._tree.txt | 2 +- litellm/proxy/_experimental/out/teams.html | 2 +- litellm/proxy/_experimental/out/teams.txt | 8 ++++---- .../__next.!KGRhc2hib2FyZCk.teams.__PAGE__.txt | 4 ++-- .../out/teams/__next.!KGRhc2hib2FyZCk.teams.txt | 2 +- .../out/teams/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../_experimental/out/teams/__next._full.txt | 8 ++++---- .../_experimental/out/teams/__next._head.txt | 2 +- .../_experimental/out/teams/__next._index.txt | 2 +- .../_experimental/out/teams/__next._tree.txt | 2 +- litellm/proxy/_experimental/out/test-key.html | 2 +- litellm/proxy/_experimental/out/test-key.txt | 6 +++--- ...__next.!KGRhc2hib2FyZCk.test-key.__PAGE__.txt | 4 ++-- .../__next.!KGRhc2hib2FyZCk.test-key.txt | 2 +- .../out/test-key/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../_experimental/out/test-key/__next._full.txt | 6 +++--- .../_experimental/out/test-key/__next._head.txt | 2 +- .../_experimental/out/test-key/__next._index.txt | 2 +- .../_experimental/out/test-key/__next._tree.txt | 2 +- .../_experimental/out/tools/mcp-servers.html | 2 +- .../_experimental/out/tools/mcp-servers.txt | 6 +++--- ...GRhc2hib2FyZCk.tools.mcp-servers.__PAGE__.txt | 4 ++-- ...__next.!KGRhc2hib2FyZCk.tools.mcp-servers.txt | 2 +- .../__next.!KGRhc2hib2FyZCk.tools.txt | 2 +- .../mcp-servers/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../out/tools/mcp-servers/__next._full.txt | 6 +++--- .../out/tools/mcp-servers/__next._head.txt | 2 +- .../out/tools/mcp-servers/__next._index.txt | 2 +- .../out/tools/mcp-servers/__next._tree.txt | 2 +- .../_experimental/out/tools/vector-stores.html | 2 +- .../_experimental/out/tools/vector-stores.txt | 6 +++--- .../__next.!KGRhc2hib2FyZCk.tools.txt | 2 +- ...hc2hib2FyZCk.tools.vector-stores.__PAGE__.txt | 4 ++-- ...next.!KGRhc2hib2FyZCk.tools.vector-stores.txt | 2 +- .../vector-stores/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../out/tools/vector-stores/__next._full.txt | 6 +++--- .../out/tools/vector-stores/__next._head.txt | 2 +- .../out/tools/vector-stores/__next._index.txt | 2 +- .../out/tools/vector-stores/__next._tree.txt | 2 +- litellm/proxy/_experimental/out/usage.html | 2 +- litellm/proxy/_experimental/out/usage.txt | 8 ++++---- .../out/usage/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../__next.!KGRhc2hib2FyZCk.usage.__PAGE__.txt | 4 ++-- .../out/usage/__next.!KGRhc2hib2FyZCk.usage.txt | 2 +- .../_experimental/out/usage/__next._full.txt | 8 ++++---- .../_experimental/out/usage/__next._head.txt | 2 +- .../_experimental/out/usage/__next._index.txt | 2 +- .../_experimental/out/usage/__next._tree.txt | 2 +- litellm/proxy/_experimental/out/users.html | 2 +- litellm/proxy/_experimental/out/users.txt | 8 ++++---- .../out/users/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- .../__next.!KGRhc2hib2FyZCk.users.__PAGE__.txt | 4 ++-- .../out/users/__next.!KGRhc2hib2FyZCk.users.txt | 2 +- .../_experimental/out/users/__next._full.txt | 8 ++++---- .../_experimental/out/users/__next._head.txt | 2 +- .../_experimental/out/users/__next._index.txt | 2 +- .../_experimental/out/users/__next._tree.txt | 2 +- .../proxy/_experimental/out/virtual-keys.html | 2 +- litellm/proxy/_experimental/out/virtual-keys.txt | 8 ++++---- .../out/virtual-keys/__next.!KGRhc2hib2FyZCk.txt | 4 ++-- ...xt.!KGRhc2hib2FyZCk.virtual-keys.__PAGE__.txt | 4 ++-- .../__next.!KGRhc2hib2FyZCk.virtual-keys.txt | 2 +- .../out/virtual-keys/__next._full.txt | 8 ++++---- .../out/virtual-keys/__next._head.txt | 2 +- .../out/virtual-keys/__next._index.txt | 2 +- .../out/virtual-keys/__next._tree.txt | 2 +- 348 files changed, 563 insertions(+), 563 deletions(-) rename litellm/proxy/_experimental/out/_next/static/{Kalni9LnFJDBB7xvqCPNe => aKKihXXKRJWLQThZgi8Rq}/_buildManifest.js (100%) rename litellm/proxy/_experimental/out/_next/static/{Kalni9LnFJDBB7xvqCPNe => aKKihXXKRJWLQThZgi8Rq}/_clientMiddlewareManifest.json (100%) rename litellm/proxy/_experimental/out/_next/static/{Kalni9LnFJDBB7xvqCPNe => aKKihXXKRJWLQThZgi8Rq}/_ssgManifest.js (100%) delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/07fd9d7c5c879cb6.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/0bffe854234d50c4.js rename litellm/proxy/_experimental/out/_next/static/chunks/{69365f493e1655a4.js => 0dda11815be4f78b.js} (79%) create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/123bb7375879d789.js rename litellm/proxy/_experimental/out/_next/static/chunks/{92260915afd3dac5.js => 179425128d293da9.js} (93%) create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/23bf955e8672ce98.js rename litellm/proxy/_experimental/out/_next/static/chunks/{0b06d056425a991f.js => 2bacff998dbae5da.js} (56%) delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/2f9ed92e7b7cd792.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/31ad6450b9c696ec.js rename litellm/proxy/_experimental/out/_next/static/chunks/{81b595b330469e25.js => 38976546132cd527.js} (79%) rename litellm/proxy/_experimental/out/_next/static/chunks/{9b0c03a2b0969129.js => 3b3c0b070b14da06.js} (70%) rename litellm/proxy/_experimental/out/_next/static/chunks/{b08200c758c5c505.js => 3da2633a10defd79.js} (97%) rename litellm/proxy/_experimental/out/_next/static/chunks/{e99f98e7f34532c9.js => 40f766ecc87dbf9a.js} (63%) create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/4348e537165edb3b.js rename litellm/proxy/_experimental/out/_next/static/chunks/{3413b6a1ede03f29.js => 5595eb6378e90997.js} (87%) rename litellm/proxy/_experimental/out/_next/static/chunks/{f2ee2fa5fe008110.js => 62a03e24dd5227b9.js} (93%) rename litellm/proxy/_experimental/out/_next/static/chunks/{0adb91ab5f3140d5.js => 67ddb5107368a659.js} (95%) rename litellm/proxy/_experimental/out/_next/static/chunks/{f728bd69dddaff23.js => 68066e020262ced9.js} (92%) rename litellm/proxy/_experimental/out/_next/static/chunks/{16d77647b44247de.js => 715057b8e12f1cd9.js} (93%) rename litellm/proxy/_experimental/out/_next/static/chunks/{531dc633eecbb64f.js => 7174130ddef406dd.js} (58%) create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/8cc98e6cf29063c4.js rename litellm/proxy/_experimental/out/_next/static/chunks/{5ec157703332dbc8.js => 90c332d66ef5954b.js} (51%) create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/94b1900e63940a2b.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/9668e5e89a8b80cb.js rename litellm/proxy/_experimental/out/_next/static/chunks/{fa6fc6b79591df63.js => a89452659b6e1d90.js} (75%) delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/aae16a3ce4812424.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/d223c00dadf4b924.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/d2dd9cccff5163b7.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/e42252ef58f496fe.js create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/e775bbab37491d9c.js rename litellm/proxy/_experimental/out/_next/static/chunks/{503ca4764960a7c8.js => ed079ecd9e95349e.js} (56%) create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/f683569e573c506e.js diff --git a/litellm/proxy/_experimental/out/404.html b/litellm/proxy/_experimental/out/404.html index 9ae6eece58..29dbbfcdd6 100644 --- a/litellm/proxy/_experimental/out/404.html +++ b/litellm/proxy/_experimental/out/404.html @@ -1 +1 @@ -404: This page could not be found.LiteLLM Dashboard

404

This page could not be found.

\ No newline at end of file +404: This page could not be found.LiteLLM Dashboard

404

This page could not be found.

\ No newline at end of file diff --git a/litellm/proxy/_experimental/out/__next.__PAGE__.txt b/litellm/proxy/_experimental/out/__next.__PAGE__.txt index 9953e63348..f453aaf9be 100644 --- a/litellm/proxy/_experimental/out/__next.__PAGE__.txt +++ b/litellm/proxy/_experimental/out/__next.__PAGE__.txt @@ -1,23 +1,23 @@ 1:"$Sreact.fragment" 2:I[347257,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"ClientPageRoot"] -3:I[952683,["/litellm-asset-prefix/_next/static/chunks/a7f104aa2cc7f3f0.js","/litellm-asset-prefix/_next/static/chunks/e8ed72789c2b42ff.js","/litellm-asset-prefix/_next/static/chunks/e627c7aa5ead52b3.js","/litellm-asset-prefix/_next/static/chunks/142704439974f6b3.js","/litellm-asset-prefix/_next/static/chunks/30539b80ac15aad2.js","/litellm-asset-prefix/_next/static/chunks/7d82a1cebfdb679c.js","/litellm-asset-prefix/_next/static/chunks/2d471965761a22ff.js","/litellm-asset-prefix/_next/static/chunks/1fe0596a309ad6cf.js","/litellm-asset-prefix/_next/static/chunks/7b788dd93ad868b3.js","/litellm-asset-prefix/_next/static/chunks/c847ecdf8c790b0b.js","/litellm-asset-prefix/_next/static/chunks/403c4d96324c23a6.js","/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","/litellm-asset-prefix/_next/static/chunks/d64d74932cb225a3.js","/litellm-asset-prefix/_next/static/chunks/8c13023d89b01566.js","/litellm-asset-prefix/_next/static/chunks/3b30ab8eaa03bc21.js","/litellm-asset-prefix/_next/static/chunks/74ce31aa0fb2adc9.js","/litellm-asset-prefix/_next/static/chunks/cdf98a03da656604.js","/litellm-asset-prefix/_next/static/chunks/cac89fc12fb6ef7e.js","/litellm-asset-prefix/_next/static/chunks/d0d828f9a0668699.js","/litellm-asset-prefix/_next/static/chunks/1a04d31843c96649.js","/litellm-asset-prefix/_next/static/chunks/ed90bf177ad61e18.js","/litellm-asset-prefix/_next/static/chunks/2971c4658f1bcd7d.js","/litellm-asset-prefix/_next/static/chunks/6c4c97f1ea6e7d77.js","/litellm-asset-prefix/_next/static/chunks/9d6e5aad99b19216.js","/litellm-asset-prefix/_next/static/chunks/134f728fa7099e3e.js","/litellm-asset-prefix/_next/static/chunks/acbeac1b0fde1fdf.js","/litellm-asset-prefix/_next/static/chunks/fa6fc6b79591df63.js","/litellm-asset-prefix/_next/static/chunks/7e417dd24c8becd0.js","/litellm-asset-prefix/_next/static/chunks/348b31083769a7c4.js","/litellm-asset-prefix/_next/static/chunks/a85adee4198d5478.js","/litellm-asset-prefix/_next/static/chunks/c8eee6971ca36303.js","/litellm-asset-prefix/_next/static/chunks/0adb91ab5f3140d5.js","/litellm-asset-prefix/_next/static/chunks/b6cdb9a433f054f3.js","/litellm-asset-prefix/_next/static/chunks/22970a12064ba16b.js","/litellm-asset-prefix/_next/static/chunks/aae16a3ce4812424.js","/litellm-asset-prefix/_next/static/chunks/4980372eaa37b78b.js","/litellm-asset-prefix/_next/static/chunks/d069df5baead6d90.js","/litellm-asset-prefix/_next/static/chunks/69365f493e1655a4.js","/litellm-asset-prefix/_next/static/chunks/0a65da2cd24e2ab6.js","/litellm-asset-prefix/_next/static/chunks/fc4d54eb6afe7984.js","/litellm-asset-prefix/_next/static/chunks/e99f98e7f34532c9.js","/litellm-asset-prefix/_next/static/chunks/496b84010c33cf69.js","/litellm-asset-prefix/_next/static/chunks/06ebe9b0e9cdf241.js","/litellm-asset-prefix/_next/static/chunks/df6546cd8a44d3b3.js","/litellm-asset-prefix/_next/static/chunks/d3ac82723ec9e30d.js","/litellm-asset-prefix/_next/static/chunks/99cf9cf99df5ccfc.js","/litellm-asset-prefix/_next/static/chunks/07fd9d7c5c879cb6.js","/litellm-asset-prefix/_next/static/chunks/8dda507c226082ca.js","/litellm-asset-prefix/_next/static/chunks/54e29148cb2f2582.js","/litellm-asset-prefix/_next/static/chunks/3675074b1d85e268.js","/litellm-asset-prefix/_next/static/chunks/fcdf7322b0aa3e2e.js","/litellm-asset-prefix/_next/static/chunks/bd94e2fe34d8a187.js"],"default"] +3:I[952683,["/litellm-asset-prefix/_next/static/chunks/a7f104aa2cc7f3f0.js","/litellm-asset-prefix/_next/static/chunks/e8ed72789c2b42ff.js","/litellm-asset-prefix/_next/static/chunks/e627c7aa5ead52b3.js","/litellm-asset-prefix/_next/static/chunks/142704439974f6b3.js","/litellm-asset-prefix/_next/static/chunks/30539b80ac15aad2.js","/litellm-asset-prefix/_next/static/chunks/7d82a1cebfdb679c.js","/litellm-asset-prefix/_next/static/chunks/2d471965761a22ff.js","/litellm-asset-prefix/_next/static/chunks/1fe0596a309ad6cf.js","/litellm-asset-prefix/_next/static/chunks/7b788dd93ad868b3.js","/litellm-asset-prefix/_next/static/chunks/c847ecdf8c790b0b.js","/litellm-asset-prefix/_next/static/chunks/403c4d96324c23a6.js","/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","/litellm-asset-prefix/_next/static/chunks/d64d74932cb225a3.js","/litellm-asset-prefix/_next/static/chunks/8c13023d89b01566.js","/litellm-asset-prefix/_next/static/chunks/3b30ab8eaa03bc21.js","/litellm-asset-prefix/_next/static/chunks/74ce31aa0fb2adc9.js","/litellm-asset-prefix/_next/static/chunks/cdf98a03da656604.js","/litellm-asset-prefix/_next/static/chunks/cac89fc12fb6ef7e.js","/litellm-asset-prefix/_next/static/chunks/d0d828f9a0668699.js","/litellm-asset-prefix/_next/static/chunks/1a04d31843c96649.js","/litellm-asset-prefix/_next/static/chunks/ed90bf177ad61e18.js","/litellm-asset-prefix/_next/static/chunks/2971c4658f1bcd7d.js","/litellm-asset-prefix/_next/static/chunks/6c4c97f1ea6e7d77.js","/litellm-asset-prefix/_next/static/chunks/9d6e5aad99b19216.js","/litellm-asset-prefix/_next/static/chunks/134f728fa7099e3e.js","/litellm-asset-prefix/_next/static/chunks/acbeac1b0fde1fdf.js","/litellm-asset-prefix/_next/static/chunks/a89452659b6e1d90.js","/litellm-asset-prefix/_next/static/chunks/7e417dd24c8becd0.js","/litellm-asset-prefix/_next/static/chunks/348b31083769a7c4.js","/litellm-asset-prefix/_next/static/chunks/a85adee4198d5478.js","/litellm-asset-prefix/_next/static/chunks/c8eee6971ca36303.js","/litellm-asset-prefix/_next/static/chunks/67ddb5107368a659.js","/litellm-asset-prefix/_next/static/chunks/b6cdb9a433f054f3.js","/litellm-asset-prefix/_next/static/chunks/22970a12064ba16b.js","/litellm-asset-prefix/_next/static/chunks/4348e537165edb3b.js","/litellm-asset-prefix/_next/static/chunks/4980372eaa37b78b.js","/litellm-asset-prefix/_next/static/chunks/d069df5baead6d90.js","/litellm-asset-prefix/_next/static/chunks/0dda11815be4f78b.js","/litellm-asset-prefix/_next/static/chunks/0a65da2cd24e2ab6.js","/litellm-asset-prefix/_next/static/chunks/fc4d54eb6afe7984.js","/litellm-asset-prefix/_next/static/chunks/40f766ecc87dbf9a.js","/litellm-asset-prefix/_next/static/chunks/496b84010c33cf69.js","/litellm-asset-prefix/_next/static/chunks/06ebe9b0e9cdf241.js","/litellm-asset-prefix/_next/static/chunks/df6546cd8a44d3b3.js","/litellm-asset-prefix/_next/static/chunks/d3ac82723ec9e30d.js","/litellm-asset-prefix/_next/static/chunks/99cf9cf99df5ccfc.js","/litellm-asset-prefix/_next/static/chunks/23bf955e8672ce98.js","/litellm-asset-prefix/_next/static/chunks/8dda507c226082ca.js","/litellm-asset-prefix/_next/static/chunks/54e29148cb2f2582.js","/litellm-asset-prefix/_next/static/chunks/3675074b1d85e268.js","/litellm-asset-prefix/_next/static/chunks/fcdf7322b0aa3e2e.js","/litellm-asset-prefix/_next/static/chunks/bd94e2fe34d8a187.js"],"default"] 17:I[897367,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"OutletBoundary"] 18:"$Sreact.suspense" :HL["/litellm-asset-prefix/_next/static/chunks/3f3fa56b5786d58c.css","style"] -0:{"buildId":"Kalni9LnFJDBB7xvqCPNe","rsc":["$","$1","c",{"children":[["$","$L2",null,{"Component":"$3","serverProvidedParams":{"searchParams":{},"params":{},"promises":["$@4","$@5"]}}],[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/3f3fa56b5786d58c.css","precedence":"next"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/e627c7aa5ead52b3.js","async":true}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/142704439974f6b3.js","async":true}],["$","script","script-2",{"src":"/litellm-asset-prefix/_next/static/chunks/30539b80ac15aad2.js","async":true}],["$","script","script-3",{"src":"/litellm-asset-prefix/_next/static/chunks/7d82a1cebfdb679c.js","async":true}],["$","script","script-4",{"src":"/litellm-asset-prefix/_next/static/chunks/2d471965761a22ff.js","async":true}],["$","script","script-5",{"src":"/litellm-asset-prefix/_next/static/chunks/1fe0596a309ad6cf.js","async":true}],["$","script","script-6",{"src":"/litellm-asset-prefix/_next/static/chunks/7b788dd93ad868b3.js","async":true}],["$","script","script-7",{"src":"/litellm-asset-prefix/_next/static/chunks/c847ecdf8c790b0b.js","async":true}],["$","script","script-8",{"src":"/litellm-asset-prefix/_next/static/chunks/403c4d96324c23a6.js","async":true}],["$","script","script-9",{"src":"/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","async":true}],["$","script","script-10",{"src":"/litellm-asset-prefix/_next/static/chunks/d64d74932cb225a3.js","async":true}],["$","script","script-11",{"src":"/litellm-asset-prefix/_next/static/chunks/8c13023d89b01566.js","async":true}],["$","script","script-12",{"src":"/litellm-asset-prefix/_next/static/chunks/3b30ab8eaa03bc21.js","async":true}],["$","script","script-13",{"src":"/litellm-asset-prefix/_next/static/chunks/74ce31aa0fb2adc9.js","async":true}],["$","script","script-14",{"src":"/litellm-asset-prefix/_next/static/chunks/cdf98a03da656604.js","async":true}],["$","script","script-15",{"src":"/litellm-asset-prefix/_next/static/chunks/cac89fc12fb6ef7e.js","async":true}],["$","script","script-16",{"src":"/litellm-asset-prefix/_next/static/chunks/d0d828f9a0668699.js","async":true}],["$","script","script-17",{"src":"/litellm-asset-prefix/_next/static/chunks/1a04d31843c96649.js","async":true}],["$","script","script-18",{"src":"/litellm-asset-prefix/_next/static/chunks/ed90bf177ad61e18.js","async":true}],["$","script","script-19",{"src":"/litellm-asset-prefix/_next/static/chunks/2971c4658f1bcd7d.js","async":true}],["$","script","script-20",{"src":"/litellm-asset-prefix/_next/static/chunks/6c4c97f1ea6e7d77.js","async":true}],["$","script","script-21",{"src":"/litellm-asset-prefix/_next/static/chunks/9d6e5aad99b19216.js","async":true}],["$","script","script-22",{"src":"/litellm-asset-prefix/_next/static/chunks/134f728fa7099e3e.js","async":true}],["$","script","script-23",{"src":"/litellm-asset-prefix/_next/static/chunks/acbeac1b0fde1fdf.js","async":true}],["$","script","script-24",{"src":"/litellm-asset-prefix/_next/static/chunks/fa6fc6b79591df63.js","async":true}],["$","script","script-25",{"src":"/litellm-asset-prefix/_next/static/chunks/7e417dd24c8becd0.js","async":true}],["$","script","script-26",{"src":"/litellm-asset-prefix/_next/static/chunks/348b31083769a7c4.js","async":true}],["$","script","script-27",{"src":"/litellm-asset-prefix/_next/static/chunks/a85adee4198d5478.js","async":true}],["$","script","script-28",{"src":"/litellm-asset-prefix/_next/static/chunks/c8eee6971ca36303.js","async":true}],["$","script","script-29",{"src":"/litellm-asset-prefix/_next/static/chunks/0adb91ab5f3140d5.js","async":true}],["$","script","script-30",{"src":"/litellm-asset-prefix/_next/static/chunks/b6cdb9a433f054f3.js","async":true}],["$","script","script-31",{"src":"/litellm-asset-prefix/_next/static/chunks/22970a12064ba16b.js","async":true}],["$","script","script-32",{"src":"/litellm-asset-prefix/_next/static/chunks/aae16a3ce4812424.js","async":true}],["$","script","script-33",{"src":"/litellm-asset-prefix/_next/static/chunks/4980372eaa37b78b.js","async":true}],"$L6","$L7","$L8","$L9","$La","$Lb","$Lc","$Ld","$Le","$Lf","$L10","$L11","$L12","$L13","$L14","$L15"],"$L16"]}],"loading":null,"isPartial":false} +0:{"buildId":"aKKihXXKRJWLQThZgi8Rq","rsc":["$","$1","c",{"children":[["$","$L2",null,{"Component":"$3","serverProvidedParams":{"searchParams":{},"params":{},"promises":["$@4","$@5"]}}],[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/3f3fa56b5786d58c.css","precedence":"next"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/e627c7aa5ead52b3.js","async":true}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/142704439974f6b3.js","async":true}],["$","script","script-2",{"src":"/litellm-asset-prefix/_next/static/chunks/30539b80ac15aad2.js","async":true}],["$","script","script-3",{"src":"/litellm-asset-prefix/_next/static/chunks/7d82a1cebfdb679c.js","async":true}],["$","script","script-4",{"src":"/litellm-asset-prefix/_next/static/chunks/2d471965761a22ff.js","async":true}],["$","script","script-5",{"src":"/litellm-asset-prefix/_next/static/chunks/1fe0596a309ad6cf.js","async":true}],["$","script","script-6",{"src":"/litellm-asset-prefix/_next/static/chunks/7b788dd93ad868b3.js","async":true}],["$","script","script-7",{"src":"/litellm-asset-prefix/_next/static/chunks/c847ecdf8c790b0b.js","async":true}],["$","script","script-8",{"src":"/litellm-asset-prefix/_next/static/chunks/403c4d96324c23a6.js","async":true}],["$","script","script-9",{"src":"/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","async":true}],["$","script","script-10",{"src":"/litellm-asset-prefix/_next/static/chunks/d64d74932cb225a3.js","async":true}],["$","script","script-11",{"src":"/litellm-asset-prefix/_next/static/chunks/8c13023d89b01566.js","async":true}],["$","script","script-12",{"src":"/litellm-asset-prefix/_next/static/chunks/3b30ab8eaa03bc21.js","async":true}],["$","script","script-13",{"src":"/litellm-asset-prefix/_next/static/chunks/74ce31aa0fb2adc9.js","async":true}],["$","script","script-14",{"src":"/litellm-asset-prefix/_next/static/chunks/cdf98a03da656604.js","async":true}],["$","script","script-15",{"src":"/litellm-asset-prefix/_next/static/chunks/cac89fc12fb6ef7e.js","async":true}],["$","script","script-16",{"src":"/litellm-asset-prefix/_next/static/chunks/d0d828f9a0668699.js","async":true}],["$","script","script-17",{"src":"/litellm-asset-prefix/_next/static/chunks/1a04d31843c96649.js","async":true}],["$","script","script-18",{"src":"/litellm-asset-prefix/_next/static/chunks/ed90bf177ad61e18.js","async":true}],["$","script","script-19",{"src":"/litellm-asset-prefix/_next/static/chunks/2971c4658f1bcd7d.js","async":true}],["$","script","script-20",{"src":"/litellm-asset-prefix/_next/static/chunks/6c4c97f1ea6e7d77.js","async":true}],["$","script","script-21",{"src":"/litellm-asset-prefix/_next/static/chunks/9d6e5aad99b19216.js","async":true}],["$","script","script-22",{"src":"/litellm-asset-prefix/_next/static/chunks/134f728fa7099e3e.js","async":true}],["$","script","script-23",{"src":"/litellm-asset-prefix/_next/static/chunks/acbeac1b0fde1fdf.js","async":true}],["$","script","script-24",{"src":"/litellm-asset-prefix/_next/static/chunks/a89452659b6e1d90.js","async":true}],["$","script","script-25",{"src":"/litellm-asset-prefix/_next/static/chunks/7e417dd24c8becd0.js","async":true}],["$","script","script-26",{"src":"/litellm-asset-prefix/_next/static/chunks/348b31083769a7c4.js","async":true}],["$","script","script-27",{"src":"/litellm-asset-prefix/_next/static/chunks/a85adee4198d5478.js","async":true}],["$","script","script-28",{"src":"/litellm-asset-prefix/_next/static/chunks/c8eee6971ca36303.js","async":true}],["$","script","script-29",{"src":"/litellm-asset-prefix/_next/static/chunks/67ddb5107368a659.js","async":true}],["$","script","script-30",{"src":"/litellm-asset-prefix/_next/static/chunks/b6cdb9a433f054f3.js","async":true}],["$","script","script-31",{"src":"/litellm-asset-prefix/_next/static/chunks/22970a12064ba16b.js","async":true}],["$","script","script-32",{"src":"/litellm-asset-prefix/_next/static/chunks/4348e537165edb3b.js","async":true}],["$","script","script-33",{"src":"/litellm-asset-prefix/_next/static/chunks/4980372eaa37b78b.js","async":true}],"$L6","$L7","$L8","$L9","$La","$Lb","$Lc","$Ld","$Le","$Lf","$L10","$L11","$L12","$L13","$L14","$L15"],"$L16"]}],"loading":null,"isPartial":false} 4:{} 5:"$0:rsc:props:children:0:props:serverProvidedParams:params" 6:["$","script","script-34",{"src":"/litellm-asset-prefix/_next/static/chunks/d069df5baead6d90.js","async":true}] -7:["$","script","script-35",{"src":"/litellm-asset-prefix/_next/static/chunks/69365f493e1655a4.js","async":true}] +7:["$","script","script-35",{"src":"/litellm-asset-prefix/_next/static/chunks/0dda11815be4f78b.js","async":true}] 8:["$","script","script-36",{"src":"/litellm-asset-prefix/_next/static/chunks/0a65da2cd24e2ab6.js","async":true}] 9:["$","script","script-37",{"src":"/litellm-asset-prefix/_next/static/chunks/fc4d54eb6afe7984.js","async":true}] -a:["$","script","script-38",{"src":"/litellm-asset-prefix/_next/static/chunks/e99f98e7f34532c9.js","async":true}] +a:["$","script","script-38",{"src":"/litellm-asset-prefix/_next/static/chunks/40f766ecc87dbf9a.js","async":true}] b:["$","script","script-39",{"src":"/litellm-asset-prefix/_next/static/chunks/496b84010c33cf69.js","async":true}] c:["$","script","script-40",{"src":"/litellm-asset-prefix/_next/static/chunks/06ebe9b0e9cdf241.js","async":true}] d:["$","script","script-41",{"src":"/litellm-asset-prefix/_next/static/chunks/df6546cd8a44d3b3.js","async":true}] e:["$","script","script-42",{"src":"/litellm-asset-prefix/_next/static/chunks/d3ac82723ec9e30d.js","async":true}] f:["$","script","script-43",{"src":"/litellm-asset-prefix/_next/static/chunks/99cf9cf99df5ccfc.js","async":true}] -10:["$","script","script-44",{"src":"/litellm-asset-prefix/_next/static/chunks/07fd9d7c5c879cb6.js","async":true}] +10:["$","script","script-44",{"src":"/litellm-asset-prefix/_next/static/chunks/23bf955e8672ce98.js","async":true}] 11:["$","script","script-45",{"src":"/litellm-asset-prefix/_next/static/chunks/8dda507c226082ca.js","async":true}] 12:["$","script","script-46",{"src":"/litellm-asset-prefix/_next/static/chunks/54e29148cb2f2582.js","async":true}] 13:["$","script","script-47",{"src":"/litellm-asset-prefix/_next/static/chunks/3675074b1d85e268.js","async":true}] diff --git a/litellm/proxy/_experimental/out/__next._full.txt b/litellm/proxy/_experimental/out/__next._full.txt index 62ed8a5f0b..49820f4617 100644 --- a/litellm/proxy/_experimental/out/__next._full.txt +++ b/litellm/proxy/_experimental/out/__next._full.txt @@ -4,13 +4,13 @@ 4:I[339756,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"default"] 5:I[837457,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"default"] 6:I[347257,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"ClientPageRoot"] -7:I[952683,["/litellm-asset-prefix/_next/static/chunks/a7f104aa2cc7f3f0.js","/litellm-asset-prefix/_next/static/chunks/e8ed72789c2b42ff.js","/litellm-asset-prefix/_next/static/chunks/e627c7aa5ead52b3.js","/litellm-asset-prefix/_next/static/chunks/142704439974f6b3.js","/litellm-asset-prefix/_next/static/chunks/30539b80ac15aad2.js","/litellm-asset-prefix/_next/static/chunks/7d82a1cebfdb679c.js","/litellm-asset-prefix/_next/static/chunks/2d471965761a22ff.js","/litellm-asset-prefix/_next/static/chunks/1fe0596a309ad6cf.js","/litellm-asset-prefix/_next/static/chunks/7b788dd93ad868b3.js","/litellm-asset-prefix/_next/static/chunks/c847ecdf8c790b0b.js","/litellm-asset-prefix/_next/static/chunks/403c4d96324c23a6.js","/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","/litellm-asset-prefix/_next/static/chunks/d64d74932cb225a3.js","/litellm-asset-prefix/_next/static/chunks/8c13023d89b01566.js","/litellm-asset-prefix/_next/static/chunks/3b30ab8eaa03bc21.js","/litellm-asset-prefix/_next/static/chunks/74ce31aa0fb2adc9.js","/litellm-asset-prefix/_next/static/chunks/cdf98a03da656604.js","/litellm-asset-prefix/_next/static/chunks/cac89fc12fb6ef7e.js","/litellm-asset-prefix/_next/static/chunks/d0d828f9a0668699.js","/litellm-asset-prefix/_next/static/chunks/1a04d31843c96649.js","/litellm-asset-prefix/_next/static/chunks/ed90bf177ad61e18.js","/litellm-asset-prefix/_next/static/chunks/2971c4658f1bcd7d.js","/litellm-asset-prefix/_next/static/chunks/6c4c97f1ea6e7d77.js","/litellm-asset-prefix/_next/static/chunks/9d6e5aad99b19216.js","/litellm-asset-prefix/_next/static/chunks/134f728fa7099e3e.js","/litellm-asset-prefix/_next/static/chunks/acbeac1b0fde1fdf.js","/litellm-asset-prefix/_next/static/chunks/fa6fc6b79591df63.js","/litellm-asset-prefix/_next/static/chunks/7e417dd24c8becd0.js","/litellm-asset-prefix/_next/static/chunks/348b31083769a7c4.js","/litellm-asset-prefix/_next/static/chunks/a85adee4198d5478.js","/litellm-asset-prefix/_next/static/chunks/c8eee6971ca36303.js","/litellm-asset-prefix/_next/static/chunks/0adb91ab5f3140d5.js","/litellm-asset-prefix/_next/static/chunks/b6cdb9a433f054f3.js","/litellm-asset-prefix/_next/static/chunks/22970a12064ba16b.js","/litellm-asset-prefix/_next/static/chunks/aae16a3ce4812424.js","/litellm-asset-prefix/_next/static/chunks/4980372eaa37b78b.js","/litellm-asset-prefix/_next/static/chunks/d069df5baead6d90.js","/litellm-asset-prefix/_next/static/chunks/69365f493e1655a4.js","/litellm-asset-prefix/_next/static/chunks/0a65da2cd24e2ab6.js","/litellm-asset-prefix/_next/static/chunks/fc4d54eb6afe7984.js","/litellm-asset-prefix/_next/static/chunks/e99f98e7f34532c9.js","/litellm-asset-prefix/_next/static/chunks/496b84010c33cf69.js","/litellm-asset-prefix/_next/static/chunks/06ebe9b0e9cdf241.js","/litellm-asset-prefix/_next/static/chunks/df6546cd8a44d3b3.js","/litellm-asset-prefix/_next/static/chunks/d3ac82723ec9e30d.js","/litellm-asset-prefix/_next/static/chunks/99cf9cf99df5ccfc.js","/litellm-asset-prefix/_next/static/chunks/07fd9d7c5c879cb6.js","/litellm-asset-prefix/_next/static/chunks/8dda507c226082ca.js","/litellm-asset-prefix/_next/static/chunks/54e29148cb2f2582.js","/litellm-asset-prefix/_next/static/chunks/3675074b1d85e268.js","/litellm-asset-prefix/_next/static/chunks/fcdf7322b0aa3e2e.js","/litellm-asset-prefix/_next/static/chunks/bd94e2fe34d8a187.js"],"default"] +7:I[952683,["/litellm-asset-prefix/_next/static/chunks/a7f104aa2cc7f3f0.js","/litellm-asset-prefix/_next/static/chunks/e8ed72789c2b42ff.js","/litellm-asset-prefix/_next/static/chunks/e627c7aa5ead52b3.js","/litellm-asset-prefix/_next/static/chunks/142704439974f6b3.js","/litellm-asset-prefix/_next/static/chunks/30539b80ac15aad2.js","/litellm-asset-prefix/_next/static/chunks/7d82a1cebfdb679c.js","/litellm-asset-prefix/_next/static/chunks/2d471965761a22ff.js","/litellm-asset-prefix/_next/static/chunks/1fe0596a309ad6cf.js","/litellm-asset-prefix/_next/static/chunks/7b788dd93ad868b3.js","/litellm-asset-prefix/_next/static/chunks/c847ecdf8c790b0b.js","/litellm-asset-prefix/_next/static/chunks/403c4d96324c23a6.js","/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","/litellm-asset-prefix/_next/static/chunks/d64d74932cb225a3.js","/litellm-asset-prefix/_next/static/chunks/8c13023d89b01566.js","/litellm-asset-prefix/_next/static/chunks/3b30ab8eaa03bc21.js","/litellm-asset-prefix/_next/static/chunks/74ce31aa0fb2adc9.js","/litellm-asset-prefix/_next/static/chunks/cdf98a03da656604.js","/litellm-asset-prefix/_next/static/chunks/cac89fc12fb6ef7e.js","/litellm-asset-prefix/_next/static/chunks/d0d828f9a0668699.js","/litellm-asset-prefix/_next/static/chunks/1a04d31843c96649.js","/litellm-asset-prefix/_next/static/chunks/ed90bf177ad61e18.js","/litellm-asset-prefix/_next/static/chunks/2971c4658f1bcd7d.js","/litellm-asset-prefix/_next/static/chunks/6c4c97f1ea6e7d77.js","/litellm-asset-prefix/_next/static/chunks/9d6e5aad99b19216.js","/litellm-asset-prefix/_next/static/chunks/134f728fa7099e3e.js","/litellm-asset-prefix/_next/static/chunks/acbeac1b0fde1fdf.js","/litellm-asset-prefix/_next/static/chunks/a89452659b6e1d90.js","/litellm-asset-prefix/_next/static/chunks/7e417dd24c8becd0.js","/litellm-asset-prefix/_next/static/chunks/348b31083769a7c4.js","/litellm-asset-prefix/_next/static/chunks/a85adee4198d5478.js","/litellm-asset-prefix/_next/static/chunks/c8eee6971ca36303.js","/litellm-asset-prefix/_next/static/chunks/67ddb5107368a659.js","/litellm-asset-prefix/_next/static/chunks/b6cdb9a433f054f3.js","/litellm-asset-prefix/_next/static/chunks/22970a12064ba16b.js","/litellm-asset-prefix/_next/static/chunks/4348e537165edb3b.js","/litellm-asset-prefix/_next/static/chunks/4980372eaa37b78b.js","/litellm-asset-prefix/_next/static/chunks/d069df5baead6d90.js","/litellm-asset-prefix/_next/static/chunks/0dda11815be4f78b.js","/litellm-asset-prefix/_next/static/chunks/0a65da2cd24e2ab6.js","/litellm-asset-prefix/_next/static/chunks/fc4d54eb6afe7984.js","/litellm-asset-prefix/_next/static/chunks/40f766ecc87dbf9a.js","/litellm-asset-prefix/_next/static/chunks/496b84010c33cf69.js","/litellm-asset-prefix/_next/static/chunks/06ebe9b0e9cdf241.js","/litellm-asset-prefix/_next/static/chunks/df6546cd8a44d3b3.js","/litellm-asset-prefix/_next/static/chunks/d3ac82723ec9e30d.js","/litellm-asset-prefix/_next/static/chunks/99cf9cf99df5ccfc.js","/litellm-asset-prefix/_next/static/chunks/23bf955e8672ce98.js","/litellm-asset-prefix/_next/static/chunks/8dda507c226082ca.js","/litellm-asset-prefix/_next/static/chunks/54e29148cb2f2582.js","/litellm-asset-prefix/_next/static/chunks/3675074b1d85e268.js","/litellm-asset-prefix/_next/static/chunks/fcdf7322b0aa3e2e.js","/litellm-asset-prefix/_next/static/chunks/bd94e2fe34d8a187.js"],"default"] 2e:I[168027,[],"default"] :HL["/litellm-asset-prefix/_next/static/chunks/4e20891f2fd03463.css","style"] :HL["/litellm-asset-prefix/_next/static/chunks/8dc3b559a2e76f88.css","style"] :HL["/litellm-asset-prefix/_next/static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2","font",{"crossOrigin":"","type":"font/woff2"}] :HL["/litellm-asset-prefix/_next/static/chunks/3f3fa56b5786d58c.css","style"] -0:{"P":null,"b":"Kalni9LnFJDBB7xvqCPNe","c":["",""],"q":"","i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/4e20891f2fd03463.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/8dc3b559a2e76f88.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/a7f104aa2cc7f3f0.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/e8ed72789c2b42ff.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"inter_5972bc34-module__OU16Qa__className","children":["$","$L2",null,{"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]}]}]]}],{"children":[["$","$1","c",{"children":[["$","$L6",null,{"Component":"$7","serverProvidedParams":{"searchParams":{},"params":{},"promises":["$@8","$@9"]}}],[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/3f3fa56b5786d58c.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/e627c7aa5ead52b3.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/142704439974f6b3.js","async":true,"nonce":"$undefined"}],["$","script","script-2",{"src":"/litellm-asset-prefix/_next/static/chunks/30539b80ac15aad2.js","async":true,"nonce":"$undefined"}],["$","script","script-3",{"src":"/litellm-asset-prefix/_next/static/chunks/7d82a1cebfdb679c.js","async":true,"nonce":"$undefined"}],["$","script","script-4",{"src":"/litellm-asset-prefix/_next/static/chunks/2d471965761a22ff.js","async":true,"nonce":"$undefined"}],["$","script","script-5",{"src":"/litellm-asset-prefix/_next/static/chunks/1fe0596a309ad6cf.js","async":true,"nonce":"$undefined"}],["$","script","script-6",{"src":"/litellm-asset-prefix/_next/static/chunks/7b788dd93ad868b3.js","async":true,"nonce":"$undefined"}],["$","script","script-7",{"src":"/litellm-asset-prefix/_next/static/chunks/c847ecdf8c790b0b.js","async":true,"nonce":"$undefined"}],["$","script","script-8",{"src":"/litellm-asset-prefix/_next/static/chunks/403c4d96324c23a6.js","async":true,"nonce":"$undefined"}],["$","script","script-9",{"src":"/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","async":true,"nonce":"$undefined"}],["$","script","script-10",{"src":"/litellm-asset-prefix/_next/static/chunks/d64d74932cb225a3.js","async":true,"nonce":"$undefined"}],["$","script","script-11",{"src":"/litellm-asset-prefix/_next/static/chunks/8c13023d89b01566.js","async":true,"nonce":"$undefined"}],["$","script","script-12",{"src":"/litellm-asset-prefix/_next/static/chunks/3b30ab8eaa03bc21.js","async":true,"nonce":"$undefined"}],["$","script","script-13",{"src":"/litellm-asset-prefix/_next/static/chunks/74ce31aa0fb2adc9.js","async":true,"nonce":"$undefined"}],["$","script","script-14",{"src":"/litellm-asset-prefix/_next/static/chunks/cdf98a03da656604.js","async":true,"nonce":"$undefined"}],["$","script","script-15",{"src":"/litellm-asset-prefix/_next/static/chunks/cac89fc12fb6ef7e.js","async":true,"nonce":"$undefined"}],"$La","$Lb","$Lc","$Ld","$Le","$Lf","$L10","$L11","$L12","$L13","$L14","$L15","$L16","$L17","$L18","$L19","$L1a","$L1b","$L1c","$L1d","$L1e","$L1f","$L20","$L21","$L22","$L23","$L24","$L25","$L26","$L27","$L28","$L29","$L2a","$L2b"],"$L2c"]}],{},null,false,false]},null,false,false],"$L2d",false]],"m":"$undefined","G":["$2e",[]],"S":true} +0:{"P":null,"b":"aKKihXXKRJWLQThZgi8Rq","c":["",""],"q":"","i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/4e20891f2fd03463.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/8dc3b559a2e76f88.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/a7f104aa2cc7f3f0.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/e8ed72789c2b42ff.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"inter_5972bc34-module__OU16Qa__className","children":["$","$L2",null,{"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]}]}]]}],{"children":[["$","$1","c",{"children":[["$","$L6",null,{"Component":"$7","serverProvidedParams":{"searchParams":{},"params":{},"promises":["$@8","$@9"]}}],[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/3f3fa56b5786d58c.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/e627c7aa5ead52b3.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/142704439974f6b3.js","async":true,"nonce":"$undefined"}],["$","script","script-2",{"src":"/litellm-asset-prefix/_next/static/chunks/30539b80ac15aad2.js","async":true,"nonce":"$undefined"}],["$","script","script-3",{"src":"/litellm-asset-prefix/_next/static/chunks/7d82a1cebfdb679c.js","async":true,"nonce":"$undefined"}],["$","script","script-4",{"src":"/litellm-asset-prefix/_next/static/chunks/2d471965761a22ff.js","async":true,"nonce":"$undefined"}],["$","script","script-5",{"src":"/litellm-asset-prefix/_next/static/chunks/1fe0596a309ad6cf.js","async":true,"nonce":"$undefined"}],["$","script","script-6",{"src":"/litellm-asset-prefix/_next/static/chunks/7b788dd93ad868b3.js","async":true,"nonce":"$undefined"}],["$","script","script-7",{"src":"/litellm-asset-prefix/_next/static/chunks/c847ecdf8c790b0b.js","async":true,"nonce":"$undefined"}],["$","script","script-8",{"src":"/litellm-asset-prefix/_next/static/chunks/403c4d96324c23a6.js","async":true,"nonce":"$undefined"}],["$","script","script-9",{"src":"/litellm-asset-prefix/_next/static/chunks/88c74f8b4b20d25a.js","async":true,"nonce":"$undefined"}],["$","script","script-10",{"src":"/litellm-asset-prefix/_next/static/chunks/d64d74932cb225a3.js","async":true,"nonce":"$undefined"}],["$","script","script-11",{"src":"/litellm-asset-prefix/_next/static/chunks/8c13023d89b01566.js","async":true,"nonce":"$undefined"}],["$","script","script-12",{"src":"/litellm-asset-prefix/_next/static/chunks/3b30ab8eaa03bc21.js","async":true,"nonce":"$undefined"}],["$","script","script-13",{"src":"/litellm-asset-prefix/_next/static/chunks/74ce31aa0fb2adc9.js","async":true,"nonce":"$undefined"}],["$","script","script-14",{"src":"/litellm-asset-prefix/_next/static/chunks/cdf98a03da656604.js","async":true,"nonce":"$undefined"}],["$","script","script-15",{"src":"/litellm-asset-prefix/_next/static/chunks/cac89fc12fb6ef7e.js","async":true,"nonce":"$undefined"}],"$La","$Lb","$Lc","$Ld","$Le","$Lf","$L10","$L11","$L12","$L13","$L14","$L15","$L16","$L17","$L18","$L19","$L1a","$L1b","$L1c","$L1d","$L1e","$L1f","$L20","$L21","$L22","$L23","$L24","$L25","$L26","$L27","$L28","$L29","$L2a","$L2b"],"$L2c"]}],{},null,false,false]},null,false,false],"$L2d",false]],"m":"$undefined","G":["$2e",[]],"S":true} 2f:I[897367,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"OutletBoundary"] 30:"$Sreact.suspense" 32:I[897367,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"ViewportBoundary"] @@ -23,27 +23,27 @@ e:["$","script","script-20",{"src":"/litellm-asset-prefix/_next/static/chunks/6c f:["$","script","script-21",{"src":"/litellm-asset-prefix/_next/static/chunks/9d6e5aad99b19216.js","async":true,"nonce":"$undefined"}] 10:["$","script","script-22",{"src":"/litellm-asset-prefix/_next/static/chunks/134f728fa7099e3e.js","async":true,"nonce":"$undefined"}] 11:["$","script","script-23",{"src":"/litellm-asset-prefix/_next/static/chunks/acbeac1b0fde1fdf.js","async":true,"nonce":"$undefined"}] -12:["$","script","script-24",{"src":"/litellm-asset-prefix/_next/static/chunks/fa6fc6b79591df63.js","async":true,"nonce":"$undefined"}] +12:["$","script","script-24",{"src":"/litellm-asset-prefix/_next/static/chunks/a89452659b6e1d90.js","async":true,"nonce":"$undefined"}] 13:["$","script","script-25",{"src":"/litellm-asset-prefix/_next/static/chunks/7e417dd24c8becd0.js","async":true,"nonce":"$undefined"}] 14:["$","script","script-26",{"src":"/litellm-asset-prefix/_next/static/chunks/348b31083769a7c4.js","async":true,"nonce":"$undefined"}] 15:["$","script","script-27",{"src":"/litellm-asset-prefix/_next/static/chunks/a85adee4198d5478.js","async":true,"nonce":"$undefined"}] 16:["$","script","script-28",{"src":"/litellm-asset-prefix/_next/static/chunks/c8eee6971ca36303.js","async":true,"nonce":"$undefined"}] -17:["$","script","script-29",{"src":"/litellm-asset-prefix/_next/static/chunks/0adb91ab5f3140d5.js","async":true,"nonce":"$undefined"}] +17:["$","script","script-29",{"src":"/litellm-asset-prefix/_next/static/chunks/67ddb5107368a659.js","async":true,"nonce":"$undefined"}] 18:["$","script","script-30",{"src":"/litellm-asset-prefix/_next/static/chunks/b6cdb9a433f054f3.js","async":true,"nonce":"$undefined"}] 19:["$","script","script-31",{"src":"/litellm-asset-prefix/_next/static/chunks/22970a12064ba16b.js","async":true,"nonce":"$undefined"}] -1a:["$","script","script-32",{"src":"/litellm-asset-prefix/_next/static/chunks/aae16a3ce4812424.js","async":true,"nonce":"$undefined"}] +1a:["$","script","script-32",{"src":"/litellm-asset-prefix/_next/static/chunks/4348e537165edb3b.js","async":true,"nonce":"$undefined"}] 1b:["$","script","script-33",{"src":"/litellm-asset-prefix/_next/static/chunks/4980372eaa37b78b.js","async":true,"nonce":"$undefined"}] 1c:["$","script","script-34",{"src":"/litellm-asset-prefix/_next/static/chunks/d069df5baead6d90.js","async":true,"nonce":"$undefined"}] -1d:["$","script","script-35",{"src":"/litellm-asset-prefix/_next/static/chunks/69365f493e1655a4.js","async":true,"nonce":"$undefined"}] +1d:["$","script","script-35",{"src":"/litellm-asset-prefix/_next/static/chunks/0dda11815be4f78b.js","async":true,"nonce":"$undefined"}] 1e:["$","script","script-36",{"src":"/litellm-asset-prefix/_next/static/chunks/0a65da2cd24e2ab6.js","async":true,"nonce":"$undefined"}] 1f:["$","script","script-37",{"src":"/litellm-asset-prefix/_next/static/chunks/fc4d54eb6afe7984.js","async":true,"nonce":"$undefined"}] -20:["$","script","script-38",{"src":"/litellm-asset-prefix/_next/static/chunks/e99f98e7f34532c9.js","async":true,"nonce":"$undefined"}] +20:["$","script","script-38",{"src":"/litellm-asset-prefix/_next/static/chunks/40f766ecc87dbf9a.js","async":true,"nonce":"$undefined"}] 21:["$","script","script-39",{"src":"/litellm-asset-prefix/_next/static/chunks/496b84010c33cf69.js","async":true,"nonce":"$undefined"}] 22:["$","script","script-40",{"src":"/litellm-asset-prefix/_next/static/chunks/06ebe9b0e9cdf241.js","async":true,"nonce":"$undefined"}] 23:["$","script","script-41",{"src":"/litellm-asset-prefix/_next/static/chunks/df6546cd8a44d3b3.js","async":true,"nonce":"$undefined"}] 24:["$","script","script-42",{"src":"/litellm-asset-prefix/_next/static/chunks/d3ac82723ec9e30d.js","async":true,"nonce":"$undefined"}] 25:["$","script","script-43",{"src":"/litellm-asset-prefix/_next/static/chunks/99cf9cf99df5ccfc.js","async":true,"nonce":"$undefined"}] -26:["$","script","script-44",{"src":"/litellm-asset-prefix/_next/static/chunks/07fd9d7c5c879cb6.js","async":true,"nonce":"$undefined"}] +26:["$","script","script-44",{"src":"/litellm-asset-prefix/_next/static/chunks/23bf955e8672ce98.js","async":true,"nonce":"$undefined"}] 27:["$","script","script-45",{"src":"/litellm-asset-prefix/_next/static/chunks/8dda507c226082ca.js","async":true,"nonce":"$undefined"}] 28:["$","script","script-46",{"src":"/litellm-asset-prefix/_next/static/chunks/54e29148cb2f2582.js","async":true,"nonce":"$undefined"}] 29:["$","script","script-47",{"src":"/litellm-asset-prefix/_next/static/chunks/3675074b1d85e268.js","async":true,"nonce":"$undefined"}] diff --git a/litellm/proxy/_experimental/out/__next._head.txt b/litellm/proxy/_experimental/out/__next._head.txt index 594e8f5749..8005053bb8 100644 --- a/litellm/proxy/_experimental/out/__next._head.txt +++ b/litellm/proxy/_experimental/out/__next._head.txt @@ -3,4 +3,4 @@ 3:I[897367,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"MetadataBoundary"] 4:"$Sreact.suspense" 5:I[27201,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"IconMark"] -0:{"buildId":"Kalni9LnFJDBB7xvqCPNe","rsc":["$","$1","h",{"children":[null,["$","$L2",null,{"children":[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]}],["$","div",null,{"hidden":true,"children":["$","$L3",null,{"children":["$","$4",null,{"name":"Next.Metadata","children":[["$","title","0",{"children":"LiteLLM Dashboard"}],["$","meta","1",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","2",{"rel":"icon","href":"/favicon.ico?favicon.1d32c690.ico","sizes":"48x48","type":"image/x-icon"}],["$","link","3",{"rel":"icon","href":"./favicon.ico"}],["$","$L5","4",{}]]}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],"loading":null,"isPartial":false} +0:{"buildId":"aKKihXXKRJWLQThZgi8Rq","rsc":["$","$1","h",{"children":[null,["$","$L2",null,{"children":[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]}],["$","div",null,{"hidden":true,"children":["$","$L3",null,{"children":["$","$4",null,{"name":"Next.Metadata","children":[["$","title","0",{"children":"LiteLLM Dashboard"}],["$","meta","1",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","2",{"rel":"icon","href":"/favicon.ico?favicon.1d32c690.ico","sizes":"48x48","type":"image/x-icon"}],["$","link","3",{"rel":"icon","href":"./favicon.ico"}],["$","$L5","4",{}]]}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],"loading":null,"isPartial":false} diff --git a/litellm/proxy/_experimental/out/__next._index.txt b/litellm/proxy/_experimental/out/__next._index.txt index 5b96902d9c..2670187ea3 100644 --- a/litellm/proxy/_experimental/out/__next._index.txt +++ b/litellm/proxy/_experimental/out/__next._index.txt @@ -5,4 +5,4 @@ 5:I[837457,["/litellm-asset-prefix/_next/static/chunks/d96012bcfc98706a.js","/litellm-asset-prefix/_next/static/chunks/dbca964212122d58.js"],"default"] :HL["/litellm-asset-prefix/_next/static/chunks/4e20891f2fd03463.css","style"] :HL["/litellm-asset-prefix/_next/static/chunks/8dc3b559a2e76f88.css","style"] -0:{"buildId":"Kalni9LnFJDBB7xvqCPNe","rsc":["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/4e20891f2fd03463.css","precedence":"next"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/8dc3b559a2e76f88.css","precedence":"next"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/a7f104aa2cc7f3f0.js","async":true}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/e8ed72789c2b42ff.js","async":true}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"inter_5972bc34-module__OU16Qa__className","children":["$","$L2",null,{"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","template":["$","$L5",null,{}],"notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]]}]}]}]}]}]]}],"loading":null,"isPartial":false} +0:{"buildId":"aKKihXXKRJWLQThZgi8Rq","rsc":["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/4e20891f2fd03463.css","precedence":"next"}],["$","link","1",{"rel":"stylesheet","href":"/litellm-asset-prefix/_next/static/chunks/8dc3b559a2e76f88.css","precedence":"next"}],["$","script","script-0",{"src":"/litellm-asset-prefix/_next/static/chunks/a7f104aa2cc7f3f0.js","async":true}],["$","script","script-1",{"src":"/litellm-asset-prefix/_next/static/chunks/e8ed72789c2b42ff.js","async":true}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"inter_5972bc34-module__OU16Qa__className","children":["$","$L2",null,{"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","template":["$","$L5",null,{}],"notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]]}]}]}]}]}]]}],"loading":null,"isPartial":false} diff --git a/litellm/proxy/_experimental/out/__next._tree.txt b/litellm/proxy/_experimental/out/__next._tree.txt index 90402dd4bf..e783edb76a 100644 --- a/litellm/proxy/_experimental/out/__next._tree.txt +++ b/litellm/proxy/_experimental/out/__next._tree.txt @@ -2,4 +2,4 @@ :HL["/litellm-asset-prefix/_next/static/chunks/8dc3b559a2e76f88.css","style"] :HL["/litellm-asset-prefix/_next/static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2","font",{"crossOrigin":"","type":"font/woff2"}] :HL["/litellm-asset-prefix/_next/static/chunks/3f3fa56b5786d58c.css","style"] -0:{"buildId":"Kalni9LnFJDBB7xvqCPNe","tree":{"name":"","paramType":null,"paramKey":"","hasRuntimePrefetch":false,"slots":{"children":{"name":"__PAGE__","paramType":null,"paramKey":"__PAGE__","hasRuntimePrefetch":false,"slots":null,"isRootLayout":false}},"isRootLayout":true},"staleTime":300} +0:{"buildId":"aKKihXXKRJWLQThZgi8Rq","tree":{"name":"","paramType":null,"paramKey":"","hasRuntimePrefetch":false,"slots":{"children":{"name":"__PAGE__","paramType":null,"paramKey":"__PAGE__","hasRuntimePrefetch":false,"slots":null,"isRootLayout":false}},"isRootLayout":true},"staleTime":300} diff --git a/litellm/proxy/_experimental/out/_next/static/Kalni9LnFJDBB7xvqCPNe/_buildManifest.js b/litellm/proxy/_experimental/out/_next/static/aKKihXXKRJWLQThZgi8Rq/_buildManifest.js similarity index 100% rename from litellm/proxy/_experimental/out/_next/static/Kalni9LnFJDBB7xvqCPNe/_buildManifest.js rename to litellm/proxy/_experimental/out/_next/static/aKKihXXKRJWLQThZgi8Rq/_buildManifest.js diff --git a/litellm/proxy/_experimental/out/_next/static/Kalni9LnFJDBB7xvqCPNe/_clientMiddlewareManifest.json b/litellm/proxy/_experimental/out/_next/static/aKKihXXKRJWLQThZgi8Rq/_clientMiddlewareManifest.json similarity index 100% rename from litellm/proxy/_experimental/out/_next/static/Kalni9LnFJDBB7xvqCPNe/_clientMiddlewareManifest.json rename to litellm/proxy/_experimental/out/_next/static/aKKihXXKRJWLQThZgi8Rq/_clientMiddlewareManifest.json diff --git a/litellm/proxy/_experimental/out/_next/static/Kalni9LnFJDBB7xvqCPNe/_ssgManifest.js b/litellm/proxy/_experimental/out/_next/static/aKKihXXKRJWLQThZgi8Rq/_ssgManifest.js similarity index 100% rename from litellm/proxy/_experimental/out/_next/static/Kalni9LnFJDBB7xvqCPNe/_ssgManifest.js rename to litellm/proxy/_experimental/out/_next/static/aKKihXXKRJWLQThZgi8Rq/_ssgManifest.js diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/07fd9d7c5c879cb6.js b/litellm/proxy/_experimental/out/_next/static/chunks/07fd9d7c5c879cb6.js deleted file mode 100644 index 77423d0078..0000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/07fd9d7c5c879cb6.js +++ /dev/null @@ -1 +0,0 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,757440,e=>{"use strict";var t=e.i(290571),s=e.i(271645);let r=e=>{var r=(0,t.__rest)(e,[]);return s.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},r),s.default.createElement("path",{d:"M11.9999 13.1714L16.9497 8.22168L18.3639 9.63589L11.9999 15.9999L5.63599 9.63589L7.0502 8.22168L11.9999 13.1714Z"}))};e.s(["default",()=>r])},446428,854056,e=>{"use strict";let t;var s=e.i(290571),r=e.i(271645);let l=e=>{var t=(0,s.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},t),r.default.createElement("path",{d:"M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 10.5858L9.17157 7.75736L7.75736 9.17157L10.5858 12L7.75736 14.8284L9.17157 16.2426L12 13.4142L14.8284 16.2426L16.2426 14.8284L13.4142 12L16.2426 9.17157L14.8284 7.75736L12 10.5858Z"}))};e.s(["default",()=>l],446428);var a=e.i(746725),n=e.i(914189),i=e.i(553521),o=e.i(835696),d=e.i(941444),c=e.i(178677),u=e.i(294316),m=e.i(83733),h=e.i(233137),x=e.i(732607),g=e.i(397701),f=e.i(700020);function p(e){var t;return!!(e.enter||e.enterFrom||e.enterTo||e.leave||e.leaveFrom||e.leaveTo)||(null!=(t=e.as)?t:N)!==r.Fragment||1===r.default.Children.count(e.children)}let b=(0,r.createContext)(null);b.displayName="TransitionContext";var j=((t=j||{}).Visible="visible",t.Hidden="hidden",t);let y=(0,r.createContext)(null);function v(e){return"children"in e?v(e.children):e.current.filter(({el:e})=>null!==e.current).filter(({state:e})=>"visible"===e).length>0}function _(e,t){let s=(0,d.useLatestValue)(e),l=(0,r.useRef)([]),o=(0,i.useIsMounted)(),c=(0,a.useDisposables)(),u=(0,n.useEvent)((e,t=f.RenderStrategy.Hidden)=>{let r=l.current.findIndex(({el:t})=>t===e);-1!==r&&((0,g.match)(t,{[f.RenderStrategy.Unmount](){l.current.splice(r,1)},[f.RenderStrategy.Hidden](){l.current[r].state="hidden"}}),c.microTask(()=>{var e;!v(l)&&o.current&&(null==(e=s.current)||e.call(s))}))}),m=(0,n.useEvent)(e=>{let t=l.current.find(({el:t})=>t===e);return t?"visible"!==t.state&&(t.state="visible"):l.current.push({el:e,state:"visible"}),()=>u(e,f.RenderStrategy.Unmount)}),h=(0,r.useRef)([]),x=(0,r.useRef)(Promise.resolve()),p=(0,r.useRef)({enter:[],leave:[]}),b=(0,n.useEvent)((e,s,r)=>{h.current.splice(0),t&&(t.chains.current[s]=t.chains.current[s].filter(([t])=>t!==e)),null==t||t.chains.current[s].push([e,new Promise(e=>{h.current.push(e)})]),null==t||t.chains.current[s].push([e,new Promise(e=>{Promise.all(p.current[s].map(([e,t])=>t)).then(()=>e())})]),"enter"===s?x.current=x.current.then(()=>null==t?void 0:t.wait.current).then(()=>r(s)):r(s)}),j=(0,n.useEvent)((e,t,s)=>{Promise.all(p.current[t].splice(0).map(([e,t])=>t)).then(()=>{var e;null==(e=h.current.shift())||e()}).then(()=>s(t))});return(0,r.useMemo)(()=>({children:l,register:m,unregister:u,onStart:b,onStop:j,wait:x,chains:p}),[m,u,l,b,j,p,x])}y.displayName="NestingContext";let N=r.Fragment,S=f.RenderFeatures.RenderStrategy,w=(0,f.forwardRefWithAs)(function(e,t){let{show:s,appear:l=!1,unmount:a=!0,...i}=e,d=(0,r.useRef)(null),m=p(e),x=(0,u.useSyncRefs)(...m?[d,t]:null===t?[]:[t]);(0,c.useServerHandoffComplete)();let g=(0,h.useOpenClosed)();if(void 0===s&&null!==g&&(s=(g&h.State.Open)===h.State.Open),void 0===s)throw Error("A is used but it is missing a `show={true | false}` prop.");let[j,N]=(0,r.useState)(s?"visible":"hidden"),w=_(()=>{s||N("hidden")}),[T,k]=(0,r.useState)(!0),I=(0,r.useRef)([s]);(0,o.useIsoMorphicEffect)(()=>{!1!==T&&I.current[I.current.length-1]!==s&&(I.current.push(s),k(!1))},[I,s]);let E=(0,r.useMemo)(()=>({show:s,appear:l,initial:T}),[s,l,T]);(0,o.useIsoMorphicEffect)(()=>{s?N("visible"):v(w)||null===d.current||N("hidden")},[s,w]);let U={unmount:a},R=(0,n.useEvent)(()=>{var t;T&&k(!1),null==(t=e.beforeEnter)||t.call(e)}),B=(0,n.useEvent)(()=>{var t;T&&k(!1),null==(t=e.beforeLeave)||t.call(e)}),F=(0,f.useRender)();return r.default.createElement(y.Provider,{value:w},r.default.createElement(b.Provider,{value:E},F({ourProps:{...U,as:r.Fragment,children:r.default.createElement(C,{ref:x,...U,...i,beforeEnter:R,beforeLeave:B})},theirProps:{},defaultTag:r.Fragment,features:S,visible:"visible"===j,name:"Transition"})))}),C=(0,f.forwardRefWithAs)(function(e,t){var s,l;let{transition:a=!0,beforeEnter:i,afterEnter:d,beforeLeave:j,afterLeave:w,enter:C,enterFrom:T,enterTo:k,entered:I,leave:E,leaveFrom:U,leaveTo:R,...B}=e,[F,M]=(0,r.useState)(null),L=(0,r.useRef)(null),D=p(e),A=(0,u.useSyncRefs)(...D?[L,t,M]:null===t?[]:[t]),O=null==(s=B.unmount)||s?f.RenderStrategy.Unmount:f.RenderStrategy.Hidden,{show:P,appear:z,initial:V}=function(){let e=(0,r.useContext)(b);if(null===e)throw Error("A is used but it is missing a parent or .");return e}(),[$,K]=(0,r.useState)(P?"visible":"hidden"),q=function(){let e=(0,r.useContext)(y);if(null===e)throw Error("A is used but it is missing a parent or .");return e}(),{register:H,unregister:W}=q;(0,o.useIsoMorphicEffect)(()=>H(L),[H,L]),(0,o.useIsoMorphicEffect)(()=>{if(O===f.RenderStrategy.Hidden&&L.current)return P&&"visible"!==$?void K("visible"):(0,g.match)($,{hidden:()=>W(L),visible:()=>H(L)})},[$,L,H,W,P,O]);let G=(0,c.useServerHandoffComplete)();(0,o.useIsoMorphicEffect)(()=>{if(D&&G&&"visible"===$&&null===L.current)throw Error("Did you forget to passthrough the `ref` to the actual DOM node?")},[L,$,G,D]);let J=V&&!z,Q=z&&P&&V,Z=(0,r.useRef)(!1),Y=_(()=>{Z.current||(K("hidden"),W(L))},q),X=(0,n.useEvent)(e=>{Z.current=!0,Y.onStart(L,e?"enter":"leave",e=>{"enter"===e?null==i||i():"leave"===e&&(null==j||j())})}),ee=(0,n.useEvent)(e=>{let t=e?"enter":"leave";Z.current=!1,Y.onStop(L,t,e=>{"enter"===e?null==d||d():"leave"===e&&(null==w||w())}),"leave"!==t||v(Y)||(K("hidden"),W(L))});(0,r.useEffect)(()=>{D&&a||(X(P),ee(P))},[P,D,a]);let et=!(!a||!D||!G||J),[,es]=(0,m.useTransition)(et,F,P,{start:X,end:ee}),er=(0,f.compact)({ref:A,className:(null==(l=(0,x.classNames)(B.className,Q&&C,Q&&T,es.enter&&C,es.enter&&es.closed&&T,es.enter&&!es.closed&&k,es.leave&&E,es.leave&&!es.closed&&U,es.leave&&es.closed&&R,!es.transition&&P&&I))?void 0:l.trim())||void 0,...(0,m.transitionDataAttributes)(es)}),el=0;"visible"===$&&(el|=h.State.Open),"hidden"===$&&(el|=h.State.Closed),es.enter&&(el|=h.State.Opening),es.leave&&(el|=h.State.Closing);let ea=(0,f.useRender)();return r.default.createElement(y.Provider,{value:Y},r.default.createElement(h.OpenClosedProvider,{value:el},ea({ourProps:er,theirProps:B,defaultTag:N,features:S,visible:"visible"===$,name:"Transition.Child"})))}),T=(0,f.forwardRefWithAs)(function(e,t){let s=null!==(0,r.useContext)(b),l=null!==(0,h.useOpenClosed)();return r.default.createElement(r.default.Fragment,null,!s&&l?r.default.createElement(w,{ref:t,...e}):r.default.createElement(C,{ref:t,...e}))}),k=Object.assign(w,{Child:T,Root:w});e.s(["Transition",()=>k],854056)},206929,e=>{"use strict";var t=e.i(290571),s=e.i(757440),r=e.i(271645),l=e.i(446428),a=e.i(444755),n=e.i(673706),i=e.i(103471),o=e.i(495470),d=e.i(854056),c=e.i(888288);let u=(0,n.makeClassName)("Select"),m=r.default.forwardRef((e,n)=>{let{defaultValue:m="",value:h,onValueChange:x,placeholder:g="Select...",disabled:f=!1,icon:p,enableClear:b=!1,required:j,children:y,name:v,error:_=!1,errorMessage:N,className:S,id:w}=e,C=(0,t.__rest)(e,["defaultValue","value","onValueChange","placeholder","disabled","icon","enableClear","required","children","name","error","errorMessage","className","id"]),T=(0,r.useRef)(null),k=r.Children.toArray(y),[I,E]=(0,c.default)(m,h),U=(0,r.useMemo)(()=>{let e=r.default.Children.toArray(y).filter(r.isValidElement);return(0,i.constructValueToNameMapping)(e)},[y]);return r.default.createElement("div",{className:(0,a.tremorTwMerge)("w-full min-w-[10rem] text-tremor-default",S)},r.default.createElement("div",{className:"relative"},r.default.createElement("select",{title:"select-hidden",required:j,className:(0,a.tremorTwMerge)("h-full w-full absolute left-0 top-0 -z-10 opacity-0"),value:I,onChange:e=>{e.preventDefault()},name:v,disabled:f,id:w,onFocus:()=>{let e=T.current;e&&e.focus()}},r.default.createElement("option",{className:"hidden",value:"",disabled:!0,hidden:!0},g),k.map(e=>{let t=e.props.value,s=e.props.children;return r.default.createElement("option",{className:"hidden",key:t,value:t},s)})),r.default.createElement(o.Listbox,Object.assign({as:"div",ref:n,defaultValue:I,value:I,onChange:e=>{null==x||x(e),E(e)},disabled:f,id:w},C),({value:e})=>{var t;return r.default.createElement(r.default.Fragment,null,r.default.createElement(o.ListboxButton,{ref:T,className:(0,a.tremorTwMerge)("w-full outline-none text-left whitespace-nowrap truncate rounded-tremor-default focus:ring-2 transition duration-100 border pr-8 py-2","border-tremor-border shadow-tremor-input focus:border-tremor-brand-subtle focus:ring-tremor-brand-muted","dark:border-dark-tremor-border dark:shadow-dark-tremor-input dark:focus:border-dark-tremor-brand-subtle dark:focus:ring-dark-tremor-brand-muted",p?"pl-10":"pl-3",(0,i.getSelectButtonColors)((0,i.hasValue)(e),f,_))},p&&r.default.createElement("span",{className:(0,a.tremorTwMerge)("absolute inset-y-0 left-0 flex items-center ml-px pl-2.5")},r.default.createElement(p,{className:(0,a.tremorTwMerge)(u("Icon"),"flex-none h-5 w-5","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")})),r.default.createElement("span",{className:"w-[90%] block truncate"},e&&null!=(t=U.get(e))?t:g),r.default.createElement("span",{className:(0,a.tremorTwMerge)("absolute inset-y-0 right-0 flex items-center mr-3")},r.default.createElement(s.default,{className:(0,a.tremorTwMerge)(u("arrowDownIcon"),"flex-none h-5 w-5","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")}))),b&&I?r.default.createElement("button",{type:"button",className:(0,a.tremorTwMerge)("absolute inset-y-0 right-0 flex items-center mr-8"),onClick:e=>{e.preventDefault(),E(""),null==x||x("")}},r.default.createElement(l.default,{className:(0,a.tremorTwMerge)(u("clearIcon"),"flex-none h-4 w-4","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")})):null,r.default.createElement(d.Transition,{enter:"transition ease duration-100 transform",enterFrom:"opacity-0 -translate-y-4",enterTo:"opacity-100 translate-y-0",leave:"transition ease duration-100 transform",leaveFrom:"opacity-100 translate-y-0",leaveTo:"opacity-0 -translate-y-4"},r.default.createElement(o.ListboxOptions,{anchor:"bottom start",className:(0,a.tremorTwMerge)("z-10 w-[var(--button-width)] divide-y overflow-y-auto outline-none rounded-tremor-default max-h-[228px] border [--anchor-gap:4px]","bg-tremor-background border-tremor-border divide-tremor-border shadow-tremor-dropdown","dark:bg-dark-tremor-background dark:border-dark-tremor-border dark:divide-dark-tremor-border dark:shadow-dark-tremor-dropdown")},y)))})),_&&N?r.default.createElement("p",{className:(0,a.tremorTwMerge)("errorMessage","text-sm text-rose-500 mt-1")},N):null)});m.displayName="Select",e.s(["Select",()=>m],206929)},502275,e=>{"use strict";var t=e.i(271645);let s=t.forwardRef(function(e,s){return t.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:s},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["InformationCircleIcon",0,s],502275)},78085,e=>{"use strict";var t=e.i(290571),s=e.i(103471),r=e.i(888288),l=e.i(271645),a=e.i(444755),n=e.i(673706);let i=(0,n.makeClassName)("Textarea"),o=l.default.forwardRef((e,o)=>{let{value:d,defaultValue:c="",placeholder:u="Type...",error:m=!1,errorMessage:h,disabled:x=!1,className:g,onChange:f,onValueChange:p,autoHeight:b=!1}=e,j=(0,t.__rest)(e,["value","defaultValue","placeholder","error","errorMessage","disabled","className","onChange","onValueChange","autoHeight"]),[y,v]=(0,r.default)(c,d),_=(0,l.useRef)(null),N=(0,s.hasValue)(y);return(0,l.useEffect)(()=>{let e=_.current;if(b&&e){e.style.height="60px";let t=e.scrollHeight;e.style.height=t+"px"}},[b,_,y]),l.default.createElement(l.default.Fragment,null,l.default.createElement("textarea",Object.assign({ref:(0,n.mergeRefs)([_,o]),value:y,placeholder:u,disabled:x,className:(0,a.tremorTwMerge)(i("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,s.getSelectButtonColors)(N,x,m),x?"placeholder:text-tremor-content-subtle dark:placeholder:text-dark-tremor-content-subtle":"placeholder:text-tremor-content dark:placeholder:text-dark-tremor-content",g),"data-testid":"text-area",onChange:e=>{null==f||f(e),v(e.target.value),null==p||p(e.target.value)}},j)),m&&h?l.default.createElement("p",{className:(0,a.tremorTwMerge)(i("errorMessage"),"text-sm text-red-500 mt-1")},h):null)});o.displayName="Textarea",e.s(["Textarea",()=>o],78085)},910119,e=>{"use strict";var t=e.i(843476),s=e.i(197647),r=e.i(653824),l=e.i(881073),a=e.i(404206),n=e.i(723731),i=e.i(271645),o=e.i(464571),d=e.i(212931),c=e.i(898586),u=e.i(312361),m=e.i(998573),h=e.i(291542),x=e.i(199133),g=e.i(28651),f=e.i(175712),p=e.i(770914),b=e.i(536916),j=e.i(764205),y=e.i(827252),v=e.i(994388),_=e.i(35983),N=e.i(779241),S=e.i(78085),w=e.i(808613),C=e.i(592968),T=e.i(708347),k=e.i(860585),I=e.i(355619),E=e.i(435451);function U({userData:e,onCancel:s,onSubmit:r,teams:l,accessToken:a,userID:n,userRole:o,userModels:d,possibleUIRoles:c,isBulkEdit:u=!1}){let[m]=w.Form.useForm(),[h,g]=(0,i.useState)(!1);return i.default.useEffect(()=>{let t=e.user_info?.max_budget,s=null==t;g(s),m.setFieldsValue({user_id:e.user_id,user_email:e.user_info?.user_email,user_alias:e.user_info?.user_alias,user_role:e.user_info?.user_role,models:e.user_info?.models||[],max_budget:s?"":t,budget_duration:e.user_info?.budget_duration,metadata:e.user_info?.metadata?JSON.stringify(e.user_info.metadata,null,2):void 0})},[e,m]),(0,t.jsxs)(w.Form,{form:m,onFinish:e=>{if(e.metadata&&"string"==typeof e.metadata)try{e.metadata=JSON.parse(e.metadata)}catch(e){console.error("Error parsing metadata JSON:",e);return}(h||""===e.max_budget||void 0===e.max_budget)&&(e.max_budget=null),r(e)},layout:"vertical",children:[!u&&(0,t.jsx)(w.Form.Item,{label:"User ID",name:"user_id",children:(0,t.jsx)(N.TextInput,{disabled:!0})}),!u&&(0,t.jsx)(w.Form.Item,{label:"Email",name:"user_email",children:(0,t.jsx)(N.TextInput,{})}),(0,t.jsx)(w.Form.Item,{label:"User Alias",name:"user_alias",children:(0,t.jsx)(N.TextInput,{})}),(0,t.jsx)(w.Form.Item,{label:(0,t.jsxs)("span",{children:["Global Proxy Role"," ",(0,t.jsx)(C.Tooltip,{title:"This is the role that the user will globally on the proxy. This role is independent of any team/org specific roles.",children:(0,t.jsx)(y.InfoCircleOutlined,{})})]}),name:"user_role",children:(0,t.jsx)(x.Select,{children:c&&Object.entries(c).map(([e,{ui_label:s,description:r}])=>(0,t.jsx)(_.SelectItem,{value:e,title:s,children:(0,t.jsxs)("div",{className:"flex",children:[s," ",(0,t.jsx)("p",{className:"ml-2",style:{color:"gray",fontSize:"12px"},children:r})]})},e))})}),(0,t.jsx)(w.Form.Item,{label:(0,t.jsxs)("span",{children:["Personal Models"," ",(0,t.jsx)(C.Tooltip,{title:"Select which models this user can access outside of team-scope. Choose 'All Proxy Models' to grant access to all models available on the proxy.",children:(0,t.jsx)(y.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"models",children:(0,t.jsxs)(x.Select,{mode:"multiple",placeholder:"Select models",style:{width:"100%"},disabled:!T.all_admin_roles.includes(o||""),children:[(0,t.jsx)(x.Select.Option,{value:"all-proxy-models",children:"All Proxy Models"},"all-proxy-models"),(0,t.jsx)(x.Select.Option,{value:"no-default-models",children:"No Default Models"},"no-default-models"),d.map(e=>(0,t.jsx)(x.Select.Option,{value:e,children:(0,I.getModelDisplayName)(e)},e))]})}),(0,t.jsx)(w.Form.Item,{label:(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"12px"},children:[(0,t.jsx)("span",{children:"Max Budget (USD)"}),(0,t.jsx)(b.Checkbox,{checked:h,onChange:e=>{let t=e.target.checked;g(t),t&&m.setFieldsValue({max_budget:""})},children:"Unlimited Budget"})]}),name:"max_budget",rules:[{validator:(e,t)=>h||""!==t&&null!=t?Promise.resolve():Promise.reject(Error("Please enter a budget or select Unlimited Budget"))}],children:(0,t.jsx)(E.default,{step:.01,precision:2,style:{width:"100%"},disabled:h})}),(0,t.jsx)(w.Form.Item,{label:"Reset Budget",name:"budget_duration",children:(0,t.jsx)(k.default,{})}),(0,t.jsx)(w.Form.Item,{label:"Metadata",name:"metadata",children:(0,t.jsx)(S.Textarea,{rows:4,placeholder:"Enter metadata as JSON"})}),(0,t.jsxs)("div",{className:"flex justify-end space-x-2",children:[(0,t.jsx)(v.Button,{variant:"secondary",type:"button",onClick:s,children:"Cancel"}),(0,t.jsx)(v.Button,{type:"submit",children:"Save Changes"})]})]})}var R=e.i(727749);let{Text:B,Title:F}=c.Typography,M=({open:e,onCancel:s,selectedUsers:r,possibleUIRoles:l,accessToken:a,onSuccess:n,teams:o,userRole:c,userModels:y,allowAllUsers:v=!1})=>{let[_,N]=(0,i.useState)(!1),[S,w]=(0,i.useState)([]),[C,T]=(0,i.useState)(null),[k,I]=(0,i.useState)(!1),[E,M]=(0,i.useState)(!1),L=()=>{w([]),T(null),I(!1),M(!1),s()},D=i.default.useMemo(()=>({user_id:"bulk_edit",user_info:{user_email:"",user_role:"",teams:[],models:[],max_budget:null,spend:0,metadata:{},created_at:null,updated_at:null},keys:[],teams:o||[]}),[o,e]),A=async e=>{if(console.log("formValues",e),!a)return void R.default.fromBackend("Access token not found");N(!0);try{let t=r.map(e=>e.user_id),l={};e.user_role&&""!==e.user_role&&(l.user_role=e.user_role),null!==e.max_budget&&void 0!==e.max_budget&&(l.max_budget=e.max_budget),e.models&&e.models.length>0&&(l.models=e.models),e.budget_duration&&""!==e.budget_duration&&(l.budget_duration=e.budget_duration),e.metadata&&Object.keys(e.metadata).length>0&&(l.metadata=e.metadata);let i=Object.keys(l).length>0,o=k&&S.length>0;if(!i&&!o)return void R.default.fromBackend("Please modify at least one field or select teams to add users to");let d=[];if(i)if(E){let e=await (0,j.userBulkUpdateUserCall)(a,l,void 0,!0);d.push(`Updated all users (${e.total_requested} total)`)}else await (0,j.userBulkUpdateUserCall)(a,l,t),d.push(`Updated ${t.length} user(s)`);if(o){let e=[];for(let t of S)try{let s=null;s=E?null:r.map(e=>({user_id:e.user_id,role:"user",user_email:e.user_email||null}));let l=await (0,j.teamBulkMemberAddCall)(a,t,s||null,C||void 0,E);console.log("result",l),e.push({teamId:t,success:!0,successfulAdditions:l.successful_additions,failedAdditions:l.failed_additions})}catch(s){console.error(`Failed to add users to team ${t}:`,s),e.push({teamId:t,success:!1,error:s})}let t=e.filter(e=>e.success),s=e.filter(e=>!e.success);if(t.length>0){let e=t.reduce((e,t)=>e+t.successfulAdditions,0);d.push(`Added users to ${t.length} team(s) (${e} total additions)`)}s.length>0&&m.message.warning(`Failed to add users to ${s.length} team(s)`)}d.length>0&&R.default.success(d.join(". ")),w([]),T(null),I(!1),M(!1),n(),s()}catch(e){console.error("Bulk operation failed:",e),R.default.fromBackend("Failed to perform bulk operations")}finally{N(!1)}};return(0,t.jsxs)(d.Modal,{open:e,onCancel:L,footer:null,title:E?"Bulk Edit All Users":`Bulk Edit ${r.length} User(s)`,width:800,children:[v&&(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(b.Checkbox,{checked:E,onChange:e=>M(e.target.checked),children:(0,t.jsx)(B,{strong:!0,children:"Update ALL users in the system"})}),E&&(0,t.jsx)("div",{style:{marginTop:8},children:(0,t.jsx)(B,{type:"warning",style:{fontSize:"12px"},children:"⚠️ This will apply changes to ALL users in the system, not just the selected ones."})})]}),!E&&(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsxs)(F,{level:5,children:["Selected Users (",r.length,"):"]}),(0,t.jsx)(h.Table,{size:"small",bordered:!0,dataSource:r,pagination:!1,scroll:{y:200},rowKey:"user_id",columns:[{title:"User ID",dataIndex:"user_id",key:"user_id",width:"30%",render:e=>(0,t.jsx)(B,{strong:!0,style:{fontSize:"12px"},children:e.length>20?`${e.slice(0,20)}...`:e})},{title:"Email",dataIndex:"user_email",key:"user_email",width:"25%",render:e=>(0,t.jsx)(B,{type:"secondary",style:{fontSize:"12px"},children:e||"No email"})},{title:"Current Role",dataIndex:"user_role",key:"user_role",width:"25%",render:e=>(0,t.jsx)(B,{style:{fontSize:"12px"},children:l?.[e]?.ui_label||e})},{title:"Budget",dataIndex:"max_budget",key:"max_budget",width:"20%",render:e=>(0,t.jsx)(B,{style:{fontSize:"12px"},children:null!==e?`$${e}`:"Unlimited"})}]})]}),(0,t.jsx)(u.Divider,{}),(0,t.jsx)("div",{className:"mb-4",children:(0,t.jsxs)(B,{children:[(0,t.jsx)("strong",{children:"Instructions:"})," Fill in the fields below with the values you want to apply to all selected users. You can bulk edit: role, budget, models, and metadata. You can also add users to teams."]})}),(0,t.jsx)(f.Card,{title:"Team Management",size:"small",className:"mb-4",style:{backgroundColor:"#fafafa"},children:(0,t.jsxs)(p.Space,{direction:"vertical",style:{width:"100%"},children:[(0,t.jsx)(b.Checkbox,{checked:k,onChange:e=>I(e.target.checked),children:"Add selected users to teams"}),k&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(B,{strong:!0,children:"Select Teams:"}),(0,t.jsx)(x.Select,{mode:"multiple",placeholder:"Select teams to add users to",value:S,onChange:w,style:{width:"100%",marginTop:8},options:o?.map(e=>({label:e.team_alias||e.team_id,value:e.team_id}))||[]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(B,{strong:!0,children:"Team Budget (Optional):"}),(0,t.jsx)(g.InputNumber,{placeholder:"Max budget per user in team",value:C,onChange:e=>T(e),style:{width:"100%",marginTop:8},min:0,step:.01,precision:2}),(0,t.jsx)(B,{type:"secondary",style:{fontSize:"12px"},children:"Leave empty for unlimited budget within team limits"})]}),(0,t.jsx)(B,{type:"secondary",style:{fontSize:"12px"},children:'Users will be added with "user" role by default. All users will be added to each selected team.'})]})]})}),(0,t.jsx)(U,{userData:D,onCancel:L,onSubmit:A,teams:o,accessToken:a,userID:"bulk_edit",userRole:c,userModels:y,possibleUIRoles:l,isBulkEdit:!0}),_&&(0,t.jsx)("div",{style:{textAlign:"center",marginTop:"10px"},children:(0,t.jsxs)(B,{children:["Updating ",E?"all users":r.length," user(s)..."]})})]})};var L=e.i(371455);let D=({visible:e,possibleUIRoles:s,onCancel:r,user:l,onSubmit:a})=>{let[n,c]=(0,i.useState)(l),[u]=w.Form.useForm();(0,i.useEffect)(()=>{u.resetFields()},[l]);let m=async()=>{u.resetFields(),r()},h=async e=>{a(e),u.resetFields(),r()};return l?(0,t.jsx)(d.Modal,{open:e,onCancel:m,footer:null,title:"Edit User "+l.user_id,width:1e3,children:(0,t.jsx)(w.Form,{form:u,onFinish:h,initialValues:l,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(w.Form.Item,{className:"mt-8",label:"User Email",tooltip:"Email of the User",name:"user_email",children:(0,t.jsx)(N.TextInput,{})}),(0,t.jsx)(w.Form.Item,{label:"user_id",name:"user_id",hidden:!0,children:(0,t.jsx)(N.TextInput,{})}),(0,t.jsx)(w.Form.Item,{label:"User Role",name:"user_role",children:(0,t.jsx)(x.Select,{children:s&&Object.entries(s).map(([e,{ui_label:s,description:r}])=>(0,t.jsx)(_.SelectItem,{value:e,title:s,children:(0,t.jsxs)("div",{className:"flex",children:[s," ",(0,t.jsx)("p",{className:"ml-2",style:{color:"gray",fontSize:"12px"},children:r})]})},e))})}),(0,t.jsx)(w.Form.Item,{label:"Spend (USD)",name:"spend",tooltip:"(float) - Spend of all LLM calls completed by this user",help:"Across all keys (including keys with team_id).",children:(0,t.jsx)(g.InputNumber,{min:0,step:.01})}),(0,t.jsx)(w.Form.Item,{label:"User Budget (USD)",name:"max_budget",tooltip:"(float) - Maximum budget of this user",help:"Maximum budget of this user.",children:(0,t.jsx)(E.default,{min:0,step:.01})}),(0,t.jsx)(w.Form.Item,{label:"Reset Budget",name:"budget_duration",children:(0,t.jsx)(k.default,{})}),(0,t.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,t.jsx)(o.Button,{htmlType:"submit",children:"Save"})}),(0,t.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,t.jsx)(o.Button,{htmlType:"submit",children:"Save"})})]})})}):null};var A=e.i(172372),O=e.i(500330),P=e.i(152473),z=e.i(266027),V=e.i(912598),$=e.i(127952),K=e.i(304967),q=e.i(629569),H=e.i(599724),W=e.i(114600),G=e.i(482725),J=e.i(790848),Q=e.i(646563),Z=e.i(955135);let Y=({accessToken:e,possibleUIRoles:s,userID:r,userRole:l})=>{let[a,n]=(0,i.useState)(!0),[o,d]=(0,i.useState)(null),[u,m]=(0,i.useState)(!1),[h,f]=(0,i.useState)({}),[p,b]=(0,i.useState)(!1),[y,_]=(0,i.useState)([]),{Paragraph:S}=c.Typography,{Option:w}=x.Select;(0,i.useEffect)(()=>{(async()=>{if(!e)return n(!1);try{let t=await (0,j.getInternalUserSettings)(e);if(d(t),f(t.values||{}),e)try{let t=await (0,j.modelAvailableCall)(e,r,l);if(t&&t.data){let e=t.data.map(e=>e.id);_(e)}}catch(e){console.error("Error fetching available models:",e)}}catch(e){console.error("Error fetching SSO settings:",e),R.default.fromBackend("Failed to fetch SSO settings")}finally{n(!1)}})()},[e]);let C=async()=>{if(e){b(!0);try{let t=Object.entries(h).reduce((e,[t,s])=>(e[t]=""===s?null:s,e),{}),s=await (0,j.updateInternalUserSettings)(e,t);d({...o,values:s.settings}),m(!1)}catch(e){console.error("Error updating SSO settings:",e),R.default.fromBackend("Failed to update settings: "+e)}finally{b(!1)}}},T=(e,t)=>{f(s=>({...s,[e]:t}))},E=e=>e&&Array.isArray(e)?e.map(e=>"string"==typeof e?{team_id:e,user_role:"user"}:"object"==typeof e&&e.team_id?{team_id:e.team_id,max_budget_in_team:e.max_budget_in_team,user_role:e.user_role||"user"}:{team_id:"",user_role:"user"}):[];return a?(0,t.jsx)("div",{className:"flex justify-center items-center h-64",children:(0,t.jsx)(G.Spin,{size:"large"})}):o?(0,t.jsxs)(K.Card,{children:[(0,t.jsxs)("div",{className:"flex justify-between items-center mb-4",children:[(0,t.jsx)(q.Title,{children:"Default User Settings"}),!a&&o&&(u?(0,t.jsxs)("div",{className:"flex gap-2",children:[(0,t.jsx)(v.Button,{variant:"secondary",onClick:()=>{m(!1),f(o.values||{})},disabled:p,children:"Cancel"}),(0,t.jsx)(v.Button,{onClick:C,loading:p,children:"Save Changes"})]}):(0,t.jsx)(v.Button,{onClick:()=>m(!0),children:"Edit Settings"}))]}),o?.field_schema?.description&&(0,t.jsx)(S,{className:"mb-4",children:o.field_schema.description}),(0,t.jsx)(W.Divider,{}),(0,t.jsx)("div",{className:"mt-4 space-y-4",children:(()=>{let{values:e,field_schema:r}=o;return r&&r.properties?Object.entries(r.properties).map(([r,l])=>{let a=e[r],n=r.replace(/_/g," ").replace(/\b\w/g,e=>e.toUpperCase());return(0,t.jsxs)("div",{className:"mb-6 pb-6 border-b border-gray-200 last:border-0",children:[(0,t.jsx)(H.Text,{className:"font-medium text-lg",children:n}),(0,t.jsx)(S,{className:"text-sm text-gray-500 mt-1",children:l.description||"No description available"}),u?(0,t.jsx)("div",{className:"mt-2",children:((e,r,l)=>{let a=r.type;if("teams"===e){let s,r;return(0,t.jsx)("div",{className:"mt-2",children:(s=E(h[e]||[]),r=(e,t,r)=>{let l=[...s];l[e]={...l[e],[t]:r},T("teams",l)},(0,t.jsxs)("div",{className:"space-y-3",children:[s.map((e,l)=>(0,t.jsxs)("div",{className:"border rounded-lg p-4 bg-gray-50",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-3",children:[(0,t.jsxs)(H.Text,{className:"font-medium",children:["Team ",l+1]}),(0,t.jsx)(v.Button,{size:"sm",variant:"secondary",icon:Z.DeleteOutlined,onClick:()=>{T("teams",s.filter((e,t)=>t!==l))},className:"text-red-500 hover:text-red-700",children:"Remove"})]}),(0,t.jsxs)("div",{className:"grid grid-cols-1 md:grid-cols-3 gap-3",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"text-sm font-medium mb-1",children:"Team ID"}),(0,t.jsx)(N.TextInput,{value:e.team_id,onChange:e=>r(l,"team_id",e.target.value),placeholder:"Enter team ID"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"text-sm font-medium mb-1",children:"Max Budget in Team"}),(0,t.jsx)(g.InputNumber,{style:{width:"100%"},value:e.max_budget_in_team,onChange:e=>r(l,"max_budget_in_team",e),placeholder:"Optional",min:0,step:.01,precision:2})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"text-sm font-medium mb-1",children:"User Role"}),(0,t.jsxs)(x.Select,{style:{width:"100%"},value:e.user_role,onChange:e=>r(l,"user_role",e),children:[(0,t.jsx)(w,{value:"user",children:"User"}),(0,t.jsx)(w,{value:"admin",children:"Admin"})]})]})]})]},l)),(0,t.jsx)(v.Button,{variant:"secondary",icon:Q.PlusOutlined,onClick:()=>{T("teams",[...s,{team_id:"",user_role:"user"}])},className:"w-full",children:"Add Team"})]}))})}if("user_role"===e&&s)return(0,t.jsx)(x.Select,{style:{width:"100%"},value:h[e]||"",onChange:t=>T(e,t),className:"mt-2",children:Object.entries(s).filter(([e])=>e.includes("internal_user")).map(([e,{ui_label:s,description:r}])=>(0,t.jsx)(w,{value:e,children:(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)("span",{children:s}),(0,t.jsx)("span",{className:"ml-2 text-xs text-gray-500",children:r})]})},e))});if("budget_duration"===e)return(0,t.jsx)(k.default,{value:h[e]||null,onChange:t=>T(e,t),className:"mt-2"});if("boolean"===a)return(0,t.jsx)("div",{className:"mt-2",children:(0,t.jsx)(J.Switch,{checked:!!h[e],onChange:t=>T(e,t)})});if("array"===a&&r.items?.enum)return(0,t.jsx)(x.Select,{mode:"multiple",style:{width:"100%"},value:h[e]||[],onChange:t=>T(e,t),className:"mt-2",children:r.items.enum.map(e=>(0,t.jsx)(w,{value:e,children:e},e))});else if("models"===e)return(0,t.jsxs)(x.Select,{mode:"multiple",style:{width:"100%"},value:h[e]||[],onChange:t=>T(e,t),className:"mt-2",children:[(0,t.jsx)(w,{value:"no-default-models",children:"No Default Models"},"no-default-models"),(0,t.jsx)(w,{value:"all-proxy-models",children:"All Proxy Models"},"all-proxy-models"),y.map(e=>(0,t.jsx)(w,{value:e,children:(0,I.getModelDisplayName)(e)},e))]});else if("string"===a&&r.enum)return(0,t.jsx)(x.Select,{style:{width:"100%"},value:h[e]||"",onChange:t=>T(e,t),className:"mt-2",children:r.enum.map(e=>(0,t.jsx)(w,{value:e,children:e},e))});else return(0,t.jsx)(N.TextInput,{value:void 0!==h[e]?String(h[e]):"",onChange:t=>T(e,t.target.value),placeholder:r.description||"",className:"mt-2"})})(r,l,0)}):(0,t.jsx)("div",{className:"mt-1 p-2 bg-gray-50 rounded",children:((e,r)=>{if(null==r)return(0,t.jsx)("span",{className:"text-gray-400",children:"Not set"});if("teams"===e&&Array.isArray(r)){if(0===r.length)return(0,t.jsx)("span",{className:"text-gray-400",children:"No teams assigned"});let e=E(r);return(0,t.jsx)("div",{className:"space-y-2 mt-1",children:e.map((e,s)=>(0,t.jsx)("div",{className:"border rounded-lg p-3 bg-white",children:(0,t.jsxs)("div",{className:"grid grid-cols-1 md:grid-cols-3 gap-2 text-sm",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"font-medium text-gray-600",children:"Team ID:"}),(0,t.jsx)("p",{className:"text-gray-900",children:e.team_id||"Not specified"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"font-medium text-gray-600",children:"Max Budget:"}),(0,t.jsx)("p",{className:"text-gray-900",children:void 0!==e.max_budget_in_team?`$${(0,O.formatNumberWithCommas)(e.max_budget_in_team,4)}`:"No limit"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"font-medium text-gray-600",children:"Role:"}),(0,t.jsx)("p",{className:"text-gray-900 capitalize",children:e.user_role})]})]})},s))})}if("user_role"===e&&s&&s[r]){let{ui_label:e,description:l}=s[r];return(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"font-medium",children:e}),l&&(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:l})]})}if("budget_duration"===e)return(0,t.jsx)("span",{children:(0,k.getBudgetDurationLabel)(r)});if("boolean"==typeof r)return(0,t.jsx)("span",{children:r?"Enabled":"Disabled"});if("models"===e&&Array.isArray(r))return 0===r.length?(0,t.jsx)("span",{className:"text-gray-400",children:"None"}):(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:r.map((e,s)=>(0,t.jsx)("span",{className:"px-2 py-1 bg-blue-100 rounded text-xs",children:(0,I.getModelDisplayName)(e)},s))});if("object"==typeof r)return Array.isArray(r)?0===r.length?(0,t.jsx)("span",{className:"text-gray-400",children:"None"}):(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:r.map((e,s)=>(0,t.jsx)("span",{className:"px-2 py-1 bg-blue-100 rounded text-xs",children:"object"==typeof e?JSON.stringify(e):String(e)},s))}):(0,t.jsx)("pre",{className:"bg-gray-100 p-2 rounded text-xs overflow-auto mt-1",children:JSON.stringify(r,null,2)});return(0,t.jsx)("span",{children:String(r)})})(r,a)})]},r)}):(0,t.jsx)(H.Text,{children:"No schema information available"})})()})]}):(0,t.jsx)(K.Card,{children:(0,t.jsx)(H.Text,{children:"No settings available or you do not have permission to view them."})})};var X=e.i(389083),ee=e.i(350967),et=e.i(752978),es=e.i(591935),er=e.i(68155),el=e.i(502275),ea=e.i(278587);let en=(e,s,r,l,a,n)=>{let i=[{header:"User ID",accessorKey:"user_id",enableSorting:!0,cell:({row:e})=>(0,t.jsx)(C.Tooltip,{title:e.original.user_id,children:(0,t.jsx)("span",{className:"text-xs",children:e.original.user_id?`${e.original.user_id.slice(0,7)}...`:"-"})})},{header:"Email",accessorKey:"user_email",enableSorting:!0,cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs",children:e.original.user_email||"-"})},{header:"Global Proxy Role",accessorKey:"user_role",enableSorting:!0,cell:({row:s})=>(0,t.jsx)("span",{className:"text-xs",children:e?.[s.original.user_role]?.ui_label||"-"})},{header:"User Alias",accessorKey:"user_alias",enableSorting:!1,cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs",children:e.original.user_alias||"-"})},{header:"Spend (USD)",accessorKey:"spend",enableSorting:!0,cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs",children:e.original.spend?(0,O.formatNumberWithCommas)(e.original.spend,4):"-"})},{header:"Budget (USD)",accessorKey:"max_budget",enableSorting:!1,cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs",children:null!==e.original.max_budget?e.original.max_budget:"Unlimited"})},{header:()=>(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{children:"SSO ID"}),(0,t.jsx)(C.Tooltip,{title:"SSO ID is the ID of the user in the SSO provider. If the user is not using SSO, this will be null.",children:(0,t.jsx)(el.InformationCircleIcon,{className:"w-4 h-4"})})]}),accessorKey:"sso_user_id",enableSorting:!1,cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs",children:null!==e.original.sso_user_id?e.original.sso_user_id:"-"})},{header:"Virtual Keys",accessorKey:"key_count",enableSorting:!1,cell:({row:e})=>(0,t.jsx)(ee.Grid,{numItems:2,children:e.original.key_count>0?(0,t.jsxs)(X.Badge,{size:"xs",color:"indigo",children:[e.original.key_count," ",1===e.original.key_count?"Key":"Keys"]}):(0,t.jsx)(X.Badge,{size:"xs",color:"gray",children:"No Keys"})})},{header:"Created At",accessorKey:"created_at",enableSorting:!0,cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs",children:e.original.created_at?new Date(e.original.created_at).toLocaleDateString():"-"})},{header:"Updated At",accessorKey:"updated_at",enableSorting:!1,cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs",children:e.original.updated_at?new Date(e.original.updated_at).toLocaleDateString():"-"})},{id:"actions",header:"Actions",enableSorting:!1,cell:({row:e})=>(0,t.jsxs)("div",{className:"flex gap-2",children:[(0,t.jsx)(C.Tooltip,{title:"Edit user details",children:(0,t.jsx)(et.Icon,{icon:es.PencilAltIcon,size:"sm",onClick:()=>a(e.original.user_id,!0),className:"cursor-pointer hover:text-blue-600"})}),(0,t.jsx)(C.Tooltip,{title:"Delete user",children:(0,t.jsx)(et.Icon,{icon:er.TrashIcon,size:"sm",onClick:()=>r(e.original),className:"cursor-pointer hover:text-red-600"})}),(0,t.jsx)(C.Tooltip,{title:"Reset Password",children:(0,t.jsx)(et.Icon,{icon:ea.RefreshIcon,size:"sm",onClick:()=>l(e.original.user_id),className:"cursor-pointer hover:text-green-600"})})]})}];if(n){let{onSelectUser:e,onSelectAll:s,isUserSelected:r,isAllSelected:l,isIndeterminate:a}=n;return[{id:"select",enableSorting:!1,header:()=>(0,t.jsx)(b.Checkbox,{indeterminate:a,checked:l,onChange:e=>s(e.target.checked),onClick:e=>e.stopPropagation()}),cell:({row:s})=>(0,t.jsx)(b.Checkbox,{checked:r(s.original),onChange:t=>e(s.original,t.target.checked),onClick:e=>e.stopPropagation()})},...i]}return i};var ei=e.i(152990),eo=e.i(682830),ed=e.i(269200),ec=e.i(427612),eu=e.i(64848),em=e.i(942232),eh=e.i(496020),ex=e.i(977572),eg=e.i(206929),ef=e.i(94629),ep=e.i(360820),eb=e.i(871943),ej=e.i(981339),ey=e.i(530212),ev=e.i(118366),e_=e.i(678784);function eN({userId:e,onClose:d,accessToken:c,userRole:u,onDelete:m,possibleUIRoles:h,initialTab:x=0,startInEditMode:g=!1}){let[f,p]=(0,i.useState)(null),[b,y]=(0,i.useState)(!1),[_,N]=(0,i.useState)(!1),[S,w]=(0,i.useState)(!0),[C,I]=(0,i.useState)(g),[E,B]=(0,i.useState)([]),[F,M]=(0,i.useState)(!1),[L,D]=(0,i.useState)(null),[P,z]=(0,i.useState)(null),[V,W]=(0,i.useState)(x),[G,J]=(0,i.useState)({}),[Q,Z]=(0,i.useState)(!1);i.default.useEffect(()=>{z((0,j.getProxyBaseUrl)())},[]),i.default.useEffect(()=>{console.log(`userId: ${e}, userRole: ${u}, accessToken: ${c}`),(async()=>{try{if(!c)return;let t=await (0,j.userInfoCall)(c,e,u||"",!1,null,null,!0);p(t);let s=(await (0,j.modelAvailableCall)(c,e,u||"")).data.map(e=>e.id);B(s)}catch(e){console.error("Error fetching user data:",e),R.default.fromBackend("Failed to fetch user data")}finally{w(!1)}})()},[c,e,u]);let Y=async()=>{if(!c)return void R.default.fromBackend("Access token not found");try{R.default.success("Generating password reset link...");let t=await (0,j.invitationCreateCall)(c,e);D(t),M(!0)}catch(e){R.default.fromBackend("Failed to generate password reset link")}},et=async()=>{try{if(!c)return;N(!0),await (0,j.userDeleteCall)(c,[e]),R.default.success("User deleted successfully"),m&&m(),d()}catch(e){console.error("Error deleting user:",e),R.default.fromBackend("Failed to delete user")}finally{y(!1),N(!1)}},es=async e=>{try{if(!c||!f)return;await (0,j.userUpdateUserCall)(c,e,null),p({...f,user_info:{...f.user_info,user_email:e.user_email,user_alias:e.user_alias,models:e.models,max_budget:e.max_budget,budget_duration:e.budget_duration,metadata:e.metadata}}),R.default.success("User updated successfully"),I(!1)}catch(e){console.error("Error updating user:",e),R.default.fromBackend("Failed to update user")}};if(S)return(0,t.jsxs)("div",{className:"p-4",children:[(0,t.jsx)(v.Button,{icon:ey.ArrowLeftIcon,variant:"light",onClick:d,className:"mb-4",children:"Back to Users"}),(0,t.jsx)(H.Text,{children:"Loading user data..."})]});if(!f)return(0,t.jsxs)("div",{className:"p-4",children:[(0,t.jsx)(v.Button,{icon:ey.ArrowLeftIcon,variant:"light",onClick:d,className:"mb-4",children:"Back to Users"}),(0,t.jsx)(H.Text,{children:"User not found"})]});let el=async(e,t)=>{await (0,O.copyToClipboard)(e)&&(J(e=>({...e,[t]:!0})),setTimeout(()=>{J(e=>({...e,[t]:!1}))},2e3))};return(0,t.jsxs)("div",{className:"p-4",children:[(0,t.jsxs)("div",{className:"flex justify-between items-center mb-6",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(v.Button,{icon:ey.ArrowLeftIcon,variant:"light",onClick:d,className:"mb-4",children:"Back to Users"}),(0,t.jsx)(q.Title,{children:f.user_info?.user_email||"User"}),(0,t.jsxs)("div",{className:"flex items-center cursor-pointer",children:[(0,t.jsx)(H.Text,{className:"text-gray-500 font-mono",children:f.user_id}),(0,t.jsx)(o.Button,{type:"text",size:"small",icon:G["user-id"]?(0,t.jsx)(e_.CheckIcon,{size:12}):(0,t.jsx)(ev.CopyIcon,{size:12}),onClick:()=>el(f.user_id,"user-id"),className:`left-2 z-10 transition-all duration-200 ${G["user-id"]?"text-green-600 bg-green-50 border-green-200":"text-gray-500 hover:text-gray-700 hover:bg-gray-100"}`})]})]}),u&&T.rolesWithWriteAccess.includes(u)&&(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,t.jsx)(v.Button,{icon:ea.RefreshIcon,variant:"secondary",onClick:Y,className:"flex items-center",children:"Reset Password"}),(0,t.jsx)(v.Button,{icon:er.TrashIcon,variant:"secondary",onClick:()=>y(!0),className:"flex items-center text-red-500 border-red-500 hover:text-red-600 hover:border-red-600",children:"Delete User"})]})]}),(0,t.jsx)($.default,{isOpen:b,title:"Delete User?",message:"Are you sure you want to delete this user? This action cannot be undone.",resourceInformationTitle:"User Information",resourceInformation:[{label:"Email",value:f.user_info?.user_email},{label:"User ID",value:f.user_id,code:!0},{label:"Global Proxy Role",value:f.user_info?.user_role&&h?.[f.user_info.user_role]?.ui_label||f.user_info?.user_role||"-"},{label:"Total Spend (USD)",value:f.user_info?.spend!==null&&f.user_info?.spend!==void 0?f.user_info.spend.toFixed(2):void 0}],onCancel:()=>{y(!1)},onOk:et,confirmLoading:_}),(0,t.jsxs)(r.TabGroup,{defaultIndex:V,onIndexChange:W,children:[(0,t.jsxs)(l.TabList,{className:"mb-4",children:[(0,t.jsx)(s.Tab,{children:"Overview"}),(0,t.jsx)(s.Tab,{children:"Details"})]}),(0,t.jsxs)(n.TabPanels,{children:[(0,t.jsx)(a.TabPanel,{children:(0,t.jsxs)(ee.Grid,{numItems:1,numItemsSm:2,numItemsLg:3,className:"gap-6",children:[(0,t.jsxs)(K.Card,{children:[(0,t.jsx)(H.Text,{children:"Spend"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(q.Title,{children:["$",(0,O.formatNumberWithCommas)(f.user_info?.spend||0,4)]}),(0,t.jsxs)(H.Text,{children:["of"," ",f.user_info?.max_budget!==null?`$${(0,O.formatNumberWithCommas)(f.user_info.max_budget,4)}`:"Unlimited"]})]})]}),(0,t.jsxs)(K.Card,{children:[(0,t.jsx)(H.Text,{children:"Teams"}),(0,t.jsx)("div",{className:"mt-2",children:f.teams?.length&&f.teams?.length>0?(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[f.teams?.slice(0,Q?f.teams.length:20).map((e,s)=>(0,t.jsx)(X.Badge,{color:"blue",title:e.team_alias,children:e.team_alias},s)),!Q&&f.teams?.length>20&&(0,t.jsxs)(X.Badge,{color:"gray",className:"cursor-pointer hover:bg-gray-200 transition-colors",onClick:()=>Z(!0),children:["+",f.teams.length-20," more"]}),Q&&f.teams?.length>20&&(0,t.jsx)(X.Badge,{color:"gray",className:"cursor-pointer hover:bg-gray-200 transition-colors",onClick:()=>Z(!1),children:"Show Less"})]}):(0,t.jsx)(H.Text,{children:"No teams"})})]}),(0,t.jsxs)(K.Card,{children:[(0,t.jsx)(H.Text,{children:"Virtual Keys"}),(0,t.jsx)("div",{className:"mt-2",children:(0,t.jsxs)(H.Text,{children:[f.keys?.length||0," ",f.keys?.length===1?"Key":"Keys"]})})]}),(0,t.jsxs)(K.Card,{children:[(0,t.jsx)(H.Text,{children:"Personal Models"}),(0,t.jsx)("div",{className:"mt-2",children:f.user_info?.models?.length&&f.user_info?.models?.length>0?f.user_info?.models?.map((e,s)=>(0,t.jsx)(H.Text,{children:e},s)):(0,t.jsx)(H.Text,{children:"All proxy models"})})]})]})}),(0,t.jsx)(a.TabPanel,{children:(0,t.jsxs)(K.Card,{children:[(0,t.jsxs)("div",{className:"flex justify-between items-center mb-4",children:[(0,t.jsx)(q.Title,{children:"User Settings"}),!C&&u&&T.rolesWithWriteAccess.includes(u)&&(0,t.jsx)(v.Button,{onClick:()=>I(!0),children:"Edit Settings"})]}),C&&f?(0,t.jsx)(U,{userData:f,onCancel:()=>I(!1),onSubmit:es,teams:f.teams,accessToken:c,userID:e,userRole:u,userModels:E,possibleUIRoles:h}):(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"User ID"}),(0,t.jsxs)("div",{className:"flex items-center cursor-pointer",children:[(0,t.jsx)(H.Text,{className:"font-mono",children:f.user_id}),(0,t.jsx)(o.Button,{type:"text",size:"small",icon:G["user-id"]?(0,t.jsx)(e_.CheckIcon,{size:12}):(0,t.jsx)(ev.CopyIcon,{size:12}),onClick:()=>el(f.user_id,"user-id"),className:`left-2 z-10 transition-all duration-200 ${G["user-id"]?"text-green-600 bg-green-50 border-green-200":"text-gray-500 hover:text-gray-700 hover:bg-gray-100"}`})]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Email"}),(0,t.jsx)(H.Text,{children:f.user_info?.user_email||"Not Set"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"User Alias"}),(0,t.jsx)(H.Text,{children:f.user_info?.user_alias||"Not Set"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Global Proxy Role"}),(0,t.jsx)(H.Text,{children:f.user_info?.user_role||"Not Set"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Created"}),(0,t.jsx)(H.Text,{children:f.user_info?.created_at?new Date(f.user_info.created_at).toLocaleString():"Unknown"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Last Updated"}),(0,t.jsx)(H.Text,{children:f.user_info?.updated_at?new Date(f.user_info.updated_at).toLocaleString():"Unknown"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Teams"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:f.teams?.length&&f.teams?.length>0?(0,t.jsxs)(t.Fragment,{children:[f.teams?.slice(0,Q?f.teams.length:20).map((e,s)=>(0,t.jsx)("span",{className:"px-2 py-1 bg-blue-100 rounded text-xs",title:e.team_alias||e.team_id,children:e.team_alias||e.team_id},s)),!Q&&f.teams?.length>20&&(0,t.jsxs)("span",{className:"px-2 py-1 bg-gray-100 rounded text-xs cursor-pointer hover:bg-gray-200 transition-colors",onClick:()=>Z(!0),children:["+",f.teams.length-20," more"]}),Q&&f.teams?.length>20&&(0,t.jsx)("span",{className:"px-2 py-1 bg-gray-100 rounded text-xs cursor-pointer hover:bg-gray-200 transition-colors",onClick:()=>Z(!1),children:"Show Less"})]}):(0,t.jsx)(H.Text,{children:"No teams"})})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Personal Models"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:f.user_info?.models?.length&&f.user_info?.models?.length>0?f.user_info?.models?.map((e,s)=>(0,t.jsx)("span",{className:"px-2 py-1 bg-blue-100 rounded text-xs",children:e},s)):(0,t.jsx)(H.Text,{children:"All proxy models"})})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Virtual Keys"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:f.keys?.length&&f.keys?.length>0?f.keys.map((e,s)=>(0,t.jsx)("span",{className:"px-2 py-1 bg-green-100 rounded text-xs",children:e.key_alias||e.token},s)):(0,t.jsx)(H.Text,{children:"No Virtual Keys"})})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Max Budget"}),(0,t.jsx)(H.Text,{children:f.user_info?.max_budget!==null&&f.user_info?.max_budget!==void 0?`$${(0,O.formatNumberWithCommas)(f.user_info.max_budget,4)}`:"Unlimited"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Budget Reset"}),(0,t.jsx)(H.Text,{children:(0,k.getBudgetDurationLabel)(f.user_info?.budget_duration??null)})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Metadata"}),(0,t.jsx)("pre",{className:"bg-gray-100 p-2 rounded text-xs overflow-auto mt-1",children:JSON.stringify(f.user_info?.metadata||{},null,2)})]})]})]})})]})]}),(0,t.jsx)(A.default,{isInvitationLinkModalVisible:F,setIsInvitationLinkModalVisible:M,baseUrl:P||"",invitationLinkData:L,modalType:"resetPassword"})]})}var eS=e.i(655913),ew=e.i(38419),eC=e.i(78334),eT=e.i(555436),ek=e.i(284614);let eI=(0,e.i(475254).default)("circle-user-round",[["path",{d:"M18 20a6 6 0 0 0-12 0",key:"1qehca"}],["circle",{cx:"12",cy:"10",r:"4",key:"1h16sb"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]]);function eE({data:e=[],columns:s,isLoading:r=!1,onSortChange:l,currentSort:a,accessToken:n,userRole:o,possibleUIRoles:d,handleEdit:c,handleDelete:u,handleResetPassword:m,selectedUsers:h=[],onSelectionChange:x,enableSelection:g=!1,filters:f,updateFilters:p,initialFilters:b,teams:j,userListResponse:y,currentPage:v,handlePageChange:N}){let[S,w]=i.default.useState([{id:a?.sortBy||"created_at",desc:a?.sortOrder==="desc"}]),[C,T]=i.default.useState(null),[k,I]=i.default.useState(!1),[E,U]=i.default.useState(!1),R=(e,t=!1)=>{T(e),I(t)},B=(e,t)=>{x&&(t?x([...h,e]):x(h.filter(t=>t.user_id!==e.user_id)))},F=t=>{x&&(t?x(e):x([]))},M=e=>h.some(t=>t.user_id===e.user_id),L=e.length>0&&h.length===e.length,D=h.length>0&&h.lengthd?en(d,c,u,m,R,g?{selectedUsers:h,onSelectUser:B,onSelectAll:F,isUserSelected:M,isAllSelected:L,isIndeterminate:D}:void 0):s,[d,c,u,m,R,s,g,h,L,D]),O=(0,ei.useReactTable)({data:e,columns:A,state:{sorting:S},onSortingChange:e=>{let t="function"==typeof e?e(S):e;if(w(t),t&&Array.isArray(t)&&t.length>0&&t[0]){let e=t[0];if(e.id){let t=e.id,s=e.desc?"desc":"asc";l?.(t,s)}}else l?.("created_at","desc")},getCoreRowModel:(0,eo.getCoreRowModel)(),manualSorting:!0,enableSorting:!0});return(i.default.useEffect(()=>{a&&w([{id:a.sortBy,desc:"desc"===a.sortOrder}])},[a]),C)?(0,t.jsx)(eN,{userId:C,onClose:()=>{T(null),I(!1)},accessToken:n,userRole:o,possibleUIRoles:d,initialTab:+!!k,startInEditMode:k}):(0,t.jsxs)("div",{className:"bg-white rounded-lg shadow",children:[(0,t.jsx)("div",{className:"border-b px-6 py-4",children:(0,t.jsxs)("div",{className:"flex flex-col space-y-4",children:[(0,t.jsxs)("div",{className:"flex flex-wrap items-center gap-3",children:[(0,t.jsx)(eS.FilterInput,{placeholder:"Search by email...",value:f.email,onChange:e=>p({email:e}),icon:eT.Search}),(0,t.jsx)(ew.FiltersButton,{onClick:()=>U(!E),active:E,hasActiveFilters:!!(f.user_id||f.user_role||f.team)}),(0,t.jsx)(eC.ResetFiltersButton,{onClick:()=>{p(b)}})]}),E&&(0,t.jsxs)("div",{className:"flex flex-wrap items-center gap-3 mt-3",children:[(0,t.jsx)(eS.FilterInput,{placeholder:"Filter by User ID",value:f.user_id,onChange:e=>p({user_id:e}),icon:ek.User}),(0,t.jsx)(eS.FilterInput,{placeholder:"Filter by SSO ID",value:f.sso_user_id,onChange:e=>p({sso_user_id:e}),icon:eI}),(0,t.jsx)("div",{className:"w-64",children:(0,t.jsx)(eg.Select,{value:f.user_role,onValueChange:e=>p({user_role:e}),placeholder:"Select Role",children:d&&Object.entries(d).map(([e,s])=>(0,t.jsx)(_.SelectItem,{value:e,children:s.ui_label},e))})}),(0,t.jsx)("div",{className:"w-64",children:(0,t.jsx)(eg.Select,{value:f.team,onValueChange:e=>p({team:e}),placeholder:"Select Team",children:j?.map(e=>(0,t.jsx)(_.SelectItem,{value:e.team_id,children:e.team_alias||e.team_id},e.team_id))})})]}),(0,t.jsxs)("div",{className:"flex justify-between items-center",children:[r?(0,t.jsx)(ej.Skeleton.Input,{active:!0,style:{width:192,height:20}}):(0,t.jsxs)("span",{className:"text-sm text-gray-700",children:["Showing"," ",y&&y.users&&y.users.length>0?(y.page-1)*y.page_size+1:0," ","-"," ",y&&y.users?Math.min(y.page*y.page_size,y.total):0," ","of ",y?y.total:0," results"]}),(0,t.jsx)("div",{className:"flex space-x-2",children:r?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(ej.Skeleton.Button,{active:!0,size:"small",style:{width:80,height:30}}),(0,t.jsx)(ej.Skeleton.Button,{active:!0,size:"small",style:{width:60,height:30}})]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("button",{onClick:()=>N(v-1),disabled:1===v,className:`px-3 py-1 text-sm border rounded-md ${1===v?"bg-gray-100 text-gray-400 cursor-not-allowed":"hover:bg-gray-50"}`,children:"Previous"}),(0,t.jsx)("button",{onClick:()=>N(v+1),disabled:!y||v>=y.total_pages,className:`px-3 py-1 text-sm border rounded-md ${!y||v>=y.total_pages?"bg-gray-100 text-gray-400 cursor-not-allowed":"hover:bg-gray-50"}`,children:"Next"})]})})]})]})}),(0,t.jsx)("div",{className:"overflow-auto",children:(0,t.jsx)("div",{className:"rounded-lg custom-border relative",children:(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)(ed.Table,{className:"[&_td]:py-0.5 [&_th]:py-1",children:[(0,t.jsx)(ec.TableHead,{children:O.getHeaderGroups().map(e=>(0,t.jsx)(eh.TableRow,{children:e.headers.map(e=>(0,t.jsx)(eu.TableHeaderCell,{className:`py-1 h-8 ${"actions"===e.id?"sticky right-0 bg-white shadow-[-4px_0_8px_-6px_rgba(0,0,0,0.1)]":""} ${e.column.getCanSort()?"cursor-pointer hover:bg-gray-50":""}`,onClick:e.column.getToggleSortingHandler(),children:(0,t.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,t.jsx)("div",{className:"flex items-center",children:e.isPlaceholder?null:(0,ei.flexRender)(e.column.columnDef.header,e.getContext())}),"actions"!==e.id&&e.column.getCanSort()&&(0,t.jsx)("div",{className:"w-4",children:e.column.getIsSorted()?({asc:(0,t.jsx)(ep.ChevronUpIcon,{className:"h-4 w-4 text-blue-500"}),desc:(0,t.jsx)(eb.ChevronDownIcon,{className:"h-4 w-4 text-blue-500"})})[e.column.getIsSorted()]:(0,t.jsx)(ef.SwitchVerticalIcon,{className:"h-4 w-4 text-gray-400"})})]})},e.id))},e.id))}),(0,t.jsx)(em.TableBody,{children:r?(0,t.jsx)(eh.TableRow,{children:(0,t.jsx)(ex.TableCell,{colSpan:A.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"🚅 Loading users..."})})})}):e.length>0?O.getRowModel().rows.map(e=>(0,t.jsx)(eh.TableRow,{className:"h-8",children:e.getVisibleCells().map(e=>(0,t.jsx)(ex.TableCell,{className:`py-0.5 max-h-8 overflow-hidden text-ellipsis whitespace-nowrap ${"actions"===e.column.id?"sticky right-0 bg-white shadow-[-4px_0_8px_-6px_rgba(0,0,0,0.1)]":""}`,onClick:()=>{"user_id"===e.column.id&&R(e.getValue(),!1)},style:{cursor:"user_id"===e.column.id?"pointer":"default",color:"user_id"===e.column.id?"#3b82f6":"inherit"},children:(0,ei.flexRender)(e.column.columnDef.cell,e.getContext())},e.id))},e.id)):(0,t.jsx)(eh.TableRow,{children:(0,t.jsx)(ex.TableCell,{colSpan:A.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"No users found"})})})})})]})})})})]})}let{Text:eU,Title:eR}=c.Typography,eB={email:"",user_id:"",user_role:"",sso_user_id:"",team:"",model:"",min_spend:null,max_spend:null,sort_by:"created_at",sort_order:"desc"};e.s(["default",0,({accessToken:e,token:d,userRole:c,userID:u,teams:m,orgAdminOrgIds:h})=>{let x=!!c&&(0,T.isProxyAdminRole)(c),g=(0,V.useQueryClient)(),[f,p]=(0,i.useState)(1),[b,y]=(0,i.useState)(!1),[v,_]=(0,i.useState)(null),[N,S]=(0,i.useState)(!1),[w,C]=(0,i.useState)(!1),[k,I]=(0,i.useState)(null),[E,U]=(0,i.useState)("users"),[B,F]=(0,i.useState)(eB),[K,q,H]=(0,P.useDebouncedState)(B,{wait:300}),[W,G]=(0,i.useState)(!1),[J,Q]=(0,i.useState)(null),[Z,X]=(0,i.useState)(null),[ee,et]=(0,i.useState)([]),[es,er]=(0,i.useState)(!1),[el,ea]=(0,i.useState)(!1),[ei,eo]=(0,i.useState)([]),ed=e=>{I(e),S(!0)};(0,i.useEffect)(()=>()=>{H.cancel()},[H]),(0,i.useEffect)(()=>{X((0,j.getProxyBaseUrl)())},[]),(0,i.useEffect)(()=>{(async()=>{try{if(!u||!c||!e)return;let t=(await (0,j.modelAvailableCall)(e,u,c)).data.map(e=>e.id);console.log("available_model_names:",t),eo(t)}catch(e){console.error("Error fetching user models:",e)}})()},[e,u,c]);let ec=e=>{F(t=>{let s={...t,...e};return q(s),s})},eu=(e,t)=>{ec({sort_by:e,sort_order:t})},em=async t=>{if(!e)return void R.default.fromBackend("Access token not found");try{R.default.success("Generating password reset link...");let s=await (0,j.invitationCreateCall)(e,t);Q(s),G(!0)}catch(e){R.default.fromBackend("Failed to generate password reset link")}},eh=async()=>{if(k&&e)try{C(!0),await (0,j.userDeleteCall)(e,[k.user_id]),g.setQueriesData({queryKey:["userList"]},e=>{if(void 0===e)return e;let t=e.users.filter(e=>e.user_id!==k.user_id);return{...e,users:t}}),R.default.success("User deleted successfully")}catch(e){console.error("Error deleting user:",e),R.default.fromBackend("Failed to delete user")}finally{S(!1),I(null),C(!1)}},ex=async()=>{_(null),y(!1)},eg=async t=>{if(console.log("inside handleEditSubmit:",t),e&&d&&c&&u){try{let s=await (0,j.userUpdateUserCall)(e,t,null);g.setQueriesData({queryKey:["userList"]},e=>{if(void 0===e)return e;let t=e.users.map(e=>e.user_id===s.data.user_id?(0,O.updateExistingKeys)(e,s.data):e);return{...e,users:t}}),R.default.success(`User ${t.user_id} updated successfully`)}catch(e){console.error("There was an error updating the user",e)}_(null),y(!1)}},ef=async e=>{p(e)},ep=e=>{et(e)},eb=(0,z.useQuery)({queryKey:["userList",{debouncedFilter:K,currentPage:f,orgAdminOrgIds:h}],queryFn:async()=>{if(!e)throw Error("Access token required");return await (0,j.userListCall)(e,K.user_id?[K.user_id]:null,f,25,K.email||null,K.user_role||null,K.team||null,K.sso_user_id||null,K.sort_by,K.sort_order,h?h.map(e=>e.organization_id):null)},enabled:!!(e&&d&&c&&u),placeholderData:e=>e}),ey=eb.data,ev=(0,z.useQuery)({queryKey:["userRoles"],initialData:()=>({}),queryFn:async()=>{if(!e)throw Error("Access token required");return await (0,j.getPossibleUserRoles)(e)},enabled:!!(e&&d&&c&&u)}).data,e_=en(ev,e=>{_(e),y(!0)},ed,em,()=>{});return(0,t.jsxs)("div",{className:"w-full p-8 overflow-hidden",children:[(0,t.jsx)("div",{className:"flex items-center justify-between mb-4",children:(0,t.jsx)("div",{className:"flex space-x-3",children:eb.isLoading?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(ej.Skeleton.Button,{active:!0,size:"default",shape:"default",style:{width:110,height:36}}),(0,t.jsx)(ej.Skeleton.Button,{active:!0,size:"default",shape:"default",style:{width:145,height:36}}),(0,t.jsx)(ej.Skeleton.Button,{active:!0,size:"default",shape:"default",style:{width:110,height:36}})]}):u&&e?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(L.CreateUserButton,{userID:u,accessToken:e,teams:m,possibleUIRoles:ev}),x&&(0,t.jsx)(o.Button,{onClick:()=>{ea(!el),et([])},type:el?"primary":"default",className:"flex items-center",children:el?"Cancel Selection":"Select Users"}),x&&el&&(0,t.jsxs)(o.Button,{type:"primary",onClick:()=>{0===ee.length?R.default.fromBackend("Please select users to edit"):er(!0)},disabled:0===ee.length,className:"flex items-center",children:["Bulk Edit (",ee.length," selected)"]})]}):null})}),x?(0,t.jsxs)(r.TabGroup,{defaultIndex:0,onIndexChange:e=>U(0===e?"users":"settings"),children:[(0,t.jsxs)(l.TabList,{className:"mb-4",children:[(0,t.jsx)(s.Tab,{children:"Users"}),(0,t.jsx)(s.Tab,{children:"Default User Settings"})]}),(0,t.jsxs)(n.TabPanels,{children:[(0,t.jsx)(a.TabPanel,{children:(0,t.jsx)(eE,{data:eb.data?.users||[],columns:e_,isLoading:eb.isLoading,accessToken:e,userRole:c,onSortChange:eu,currentSort:{sortBy:B.sort_by,sortOrder:B.sort_order},possibleUIRoles:ev,handleEdit:e=>{_(e),y(!0)},handleDelete:ed,handleResetPassword:em,enableSelection:el,selectedUsers:ee,onSelectionChange:ep,filters:B,updateFilters:ec,initialFilters:eB,teams:m,userListResponse:ey,currentPage:f,handlePageChange:ef})}),(0,t.jsx)(a.TabPanel,{children:u&&c&&e?(0,t.jsx)(Y,{accessToken:e,possibleUIRoles:ev,userID:u,userRole:c}):(0,t.jsx)("div",{className:"flex justify-center items-center h-64",children:(0,t.jsx)(ej.Skeleton,{active:!0,paragraph:{rows:4}})})})]})]}):(0,t.jsx)(eE,{data:eb.data?.users||[],columns:e_,isLoading:eb.isLoading,accessToken:e,userRole:c,onSortChange:eu,currentSort:{sortBy:B.sort_by,sortOrder:B.sort_order},possibleUIRoles:ev,handleEdit:e=>{_(e),y(!0)},handleDelete:ed,handleResetPassword:em,enableSelection:!1,selectedUsers:[],onSelectionChange:ep,filters:B,updateFilters:ec,initialFilters:eB,teams:m,userListResponse:ey,currentPage:f,handlePageChange:ef}),(0,t.jsx)(D,{visible:b,possibleUIRoles:ev,onCancel:ex,user:v,onSubmit:eg}),(0,t.jsx)($.default,{isOpen:N,title:"Delete User?",message:"Are you sure you want to delete this user? This action cannot be undone.",resourceInformationTitle:"User Information",resourceInformation:[{label:"Email",value:k?.user_email},{label:"User ID",value:k?.user_id,code:!0},{label:"Global Proxy Role",value:k&&ev?.[k.user_role]?.ui_label||k?.user_role||"-"},{label:"Total Spend (USD)",value:k?.spend?.toFixed(2)}],onCancel:()=>{S(!1),I(null)},onOk:eh,confirmLoading:w}),(0,t.jsx)(A.default,{isInvitationLinkModalVisible:W,setIsInvitationLinkModalVisible:G,baseUrl:Z||"",invitationLinkData:J,modalType:"resetPassword"}),(0,t.jsx)(M,{open:es,onCancel:()=>er(!1),selectedUsers:ee,possibleUIRoles:ev,accessToken:e,onSuccess:()=>{g.invalidateQueries({queryKey:["userList"]}),et([]),ea(!1)},teams:m,userRole:c,userModels:ei,allowAllUsers:!!c&&(0,T.isAdminRole)(c)})]})}],910119)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/0bffe854234d50c4.js b/litellm/proxy/_experimental/out/_next/static/chunks/0bffe854234d50c4.js deleted file mode 100644 index a2b8809a94..0000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/0bffe854234d50c4.js +++ /dev/null @@ -1,8 +0,0 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,434626,e=>{"use strict";var t=e.i(271645);let l=t.forwardRef(function(e,l){return t.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:l},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"}))});e.s(["ExternalLinkIcon",0,l],434626)},902555,e=>{"use strict";var t=e.i(843476),l=e.i(591935),a=e.i(122577),r=e.i(278587),n=e.i(68155),i=e.i(360820),o=e.i(871943),s=e.i(434626),c=e.i(592968),d=e.i(115504),u=e.i(752978);function m({icon:e,onClick:l,className:a,disabled:r,dataTestId:n}){return r?(0,t.jsx)(u.Icon,{icon:e,size:"sm",className:"opacity-50 cursor-not-allowed","data-testid":n}):(0,t.jsx)(u.Icon,{icon:e,size:"sm",onClick:l,className:(0,d.cx)("cursor-pointer",a),"data-testid":n})}let g={Edit:{icon:l.PencilAltIcon,className:"hover:text-blue-600"},Delete:{icon:n.TrashIcon,className:"hover:text-red-600"},Test:{icon:a.PlayIcon,className:"hover:text-blue-600"},Regenerate:{icon:r.RefreshIcon,className:"hover:text-green-600"},Up:{icon:i.ChevronUpIcon,className:"hover:text-blue-600"},Down:{icon:o.ChevronDownIcon,className:"hover:text-blue-600"},Open:{icon:s.ExternalLinkIcon,className:"hover:text-green-600"}};function b({onClick:e,tooltipText:l,disabled:a=!1,disabledTooltipText:r,dataTestId:n,variant:i}){let{icon:o,className:s}=g[i];return(0,t.jsx)(c.Tooltip,{title:a?r:l,children:(0,t.jsx)("span",{children:(0,t.jsx)(m,{icon:o,onClick:e,className:s,disabled:a,dataTestId:n})})})}e.s(["default",()=>b],902555)},122577,e=>{"use strict";var t=e.i(271645);let l=t.forwardRef(function(e,l){return t.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:l},e),t.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"}),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M21 12a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlayIcon",0,l],122577)},591935,e=>{"use strict";var t=e.i(271645);let l=t.forwardRef(function(e,l){return t.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:l},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"}))});e.s(["PencilAltIcon",0,l],591935)},360820,e=>{"use strict";var t=e.i(271645);let l=t.forwardRef(function(e,l){return t.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:l},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 15l7-7 7 7"}))});e.s(["ChevronUpIcon",0,l],360820)},871943,e=>{"use strict";var t=e.i(271645);let l=t.forwardRef(function(e,l){return t.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:l},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"}))});e.s(["ChevronDownIcon",0,l],871943)},185793,e=>{"use strict";e.i(247167);var t=e.i(271645),l=e.i(343794),a=e.i(242064),r=e.i(529681);let n=e=>{let{prefixCls:a,className:r,style:n,size:i,shape:o}=e,s=(0,l.default)({[`${a}-lg`]:"large"===i,[`${a}-sm`]:"small"===i}),c=(0,l.default)({[`${a}-circle`]:"circle"===o,[`${a}-square`]:"square"===o,[`${a}-round`]:"round"===o}),d=t.useMemo(()=>"number"==typeof i?{width:i,height:i,lineHeight:`${i}px`}:{},[i]);return t.createElement("span",{className:(0,l.default)(a,s,c,r),style:Object.assign(Object.assign({},d),n)})};e.i(296059);var i=e.i(694758),o=e.i(915654),s=e.i(246422),c=e.i(838378);let d=new i.Keyframes("ant-skeleton-loading",{"0%":{backgroundPosition:"100% 50%"},"100%":{backgroundPosition:"0 50%"}}),u=e=>({height:e,lineHeight:(0,o.unit)(e)}),m=e=>Object.assign({width:e},u(e)),g=(e,t)=>Object.assign({width:t(e).mul(5).equal(),minWidth:t(e).mul(5).equal()},u(e)),b=e=>Object.assign({width:e},u(e)),p=(e,t,l)=>{let{skeletonButtonCls:a}=e;return{[`${l}${a}-circle`]:{width:t,minWidth:t,borderRadius:"50%"},[`${l}${a}-round`]:{borderRadius:t}}},f=(e,t)=>Object.assign({width:t(e).mul(2).equal(),minWidth:t(e).mul(2).equal()},u(e)),h=(0,s.genStyleHooks)("Skeleton",e=>{let{componentCls:t,calc:l}=e;return(e=>{let{componentCls:t,skeletonAvatarCls:l,skeletonTitleCls:a,skeletonParagraphCls:r,skeletonButtonCls:n,skeletonInputCls:i,skeletonImageCls:o,controlHeight:s,controlHeightLG:c,controlHeightSM:u,gradientFromColor:h,padding:v,marginSM:x,borderRadius:j,titleHeight:$,blockRadius:y,paragraphLiHeight:w,controlHeightXS:C,paragraphMarginTop:O}=e;return{[t]:{display:"table",width:"100%",[`${t}-header`]:{display:"table-cell",paddingInlineEnd:v,verticalAlign:"top",[l]:Object.assign({display:"inline-block",verticalAlign:"top",background:h},m(s)),[`${l}-circle`]:{borderRadius:"50%"},[`${l}-lg`]:Object.assign({},m(c)),[`${l}-sm`]:Object.assign({},m(u))},[`${t}-content`]:{display:"table-cell",width:"100%",verticalAlign:"top",[a]:{width:"100%",height:$,background:h,borderRadius:y,[`+ ${r}`]:{marginBlockStart:u}},[r]:{padding:0,"> li":{width:"100%",height:w,listStyle:"none",background:h,borderRadius:y,"+ li":{marginBlockStart:C}}},[`${r}> li:last-child:not(:first-child):not(:nth-child(2))`]:{width:"61%"}},[`&-round ${t}-content`]:{[`${a}, ${r} > li`]:{borderRadius:j}}},[`${t}-with-avatar ${t}-content`]:{[a]:{marginBlockStart:x,[`+ ${r}`]:{marginBlockStart:O}}},[`${t}${t}-element`]:Object.assign(Object.assign(Object.assign(Object.assign({display:"inline-block",width:"auto"},(e=>{let{borderRadiusSM:t,skeletonButtonCls:l,controlHeight:a,controlHeightLG:r,controlHeightSM:n,gradientFromColor:i,calc:o}=e;return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({[l]:Object.assign({display:"inline-block",verticalAlign:"top",background:i,borderRadius:t,width:o(a).mul(2).equal(),minWidth:o(a).mul(2).equal()},f(a,o))},p(e,a,l)),{[`${l}-lg`]:Object.assign({},f(r,o))}),p(e,r,`${l}-lg`)),{[`${l}-sm`]:Object.assign({},f(n,o))}),p(e,n,`${l}-sm`))})(e)),(e=>{let{skeletonAvatarCls:t,gradientFromColor:l,controlHeight:a,controlHeightLG:r,controlHeightSM:n}=e;return{[t]:Object.assign({display:"inline-block",verticalAlign:"top",background:l},m(a)),[`${t}${t}-circle`]:{borderRadius:"50%"},[`${t}${t}-lg`]:Object.assign({},m(r)),[`${t}${t}-sm`]:Object.assign({},m(n))}})(e)),(e=>{let{controlHeight:t,borderRadiusSM:l,skeletonInputCls:a,controlHeightLG:r,controlHeightSM:n,gradientFromColor:i,calc:o}=e;return{[a]:Object.assign({display:"inline-block",verticalAlign:"top",background:i,borderRadius:l},g(t,o)),[`${a}-lg`]:Object.assign({},g(r,o)),[`${a}-sm`]:Object.assign({},g(n,o))}})(e)),(e=>{let{skeletonImageCls:t,imageSizeBase:l,gradientFromColor:a,borderRadiusSM:r,calc:n}=e;return{[t]:Object.assign(Object.assign({display:"inline-flex",alignItems:"center",justifyContent:"center",verticalAlign:"middle",background:a,borderRadius:r},b(n(l).mul(2).equal())),{[`${t}-path`]:{fill:"#bfbfbf"},[`${t}-svg`]:Object.assign(Object.assign({},b(l)),{maxWidth:n(l).mul(4).equal(),maxHeight:n(l).mul(4).equal()}),[`${t}-svg${t}-svg-circle`]:{borderRadius:"50%"}}),[`${t}${t}-circle`]:{borderRadius:"50%"}}})(e)),[`${t}${t}-block`]:{width:"100%",[n]:{width:"100%"},[i]:{width:"100%"}},[`${t}${t}-active`]:{[` - ${a}, - ${r} > li, - ${l}, - ${n}, - ${i}, - ${o} - `]:Object.assign({},{background:e.skeletonLoadingBackground,backgroundSize:"400% 100%",animationName:d,animationDuration:e.skeletonLoadingMotionDuration,animationTimingFunction:"ease",animationIterationCount:"infinite"})}}})((0,c.mergeToken)(e,{skeletonAvatarCls:`${t}-avatar`,skeletonTitleCls:`${t}-title`,skeletonParagraphCls:`${t}-paragraph`,skeletonButtonCls:`${t}-button`,skeletonInputCls:`${t}-input`,skeletonImageCls:`${t}-image`,imageSizeBase:l(e.controlHeight).mul(1.5).equal(),borderRadius:100,skeletonLoadingBackground:`linear-gradient(90deg, ${e.gradientFromColor} 25%, ${e.gradientToColor} 37%, ${e.gradientFromColor} 63%)`,skeletonLoadingMotionDuration:"1.4s"}))},e=>{let{colorFillContent:t,colorFill:l}=e;return{color:t,colorGradientEnd:l,gradientFromColor:t,gradientToColor:l,titleHeight:e.controlHeight/2,blockRadius:e.borderRadiusSM,paragraphMarginTop:e.marginLG+e.marginXXS,paragraphLiHeight:e.controlHeight/2}},{deprecatedTokens:[["color","gradientFromColor"],["colorGradientEnd","gradientToColor"]]}),v=e=>{let{prefixCls:a,className:r,style:n,rows:i=0}=e,o=Array.from({length:i}).map((l,a)=>t.createElement("li",{key:a,style:{width:((e,t)=>{let{width:l,rows:a=2}=t;return Array.isArray(l)?l[e]:a-1===e?l:void 0})(a,e)}}));return t.createElement("ul",{className:(0,l.default)(a,r),style:n},o)},x=({prefixCls:e,className:a,width:r,style:n})=>t.createElement("h3",{className:(0,l.default)(e,a),style:Object.assign({width:r},n)});function j(e){return e&&"object"==typeof e?e:{}}let $=e=>{let{prefixCls:r,loading:i,className:o,rootClassName:s,style:c,children:d,avatar:u=!1,title:m=!0,paragraph:g=!0,active:b,round:p}=e,{getPrefixCls:f,direction:$,className:y,style:w}=(0,a.useComponentConfig)("skeleton"),C=f("skeleton",r),[O,k,N]=h(C);if(i||!("loading"in e)){let e,a,r=!!u,i=!!m,d=!!g;if(r){let l=Object.assign(Object.assign({prefixCls:`${C}-avatar`},i&&!d?{size:"large",shape:"square"}:{size:"large",shape:"circle"}),j(u));e=t.createElement("div",{className:`${C}-header`},t.createElement(n,Object.assign({},l)))}if(i||d){let e,l;if(i){let l=Object.assign(Object.assign({prefixCls:`${C}-title`},!r&&d?{width:"38%"}:r&&d?{width:"50%"}:{}),j(m));e=t.createElement(x,Object.assign({},l))}if(d){let e,a=Object.assign(Object.assign({prefixCls:`${C}-paragraph`},(e={},r&&i||(e.width="61%"),!r&&i?e.rows=3:e.rows=2,e)),j(g));l=t.createElement(v,Object.assign({},a))}a=t.createElement("div",{className:`${C}-content`},e,l)}let f=(0,l.default)(C,{[`${C}-with-avatar`]:r,[`${C}-active`]:b,[`${C}-rtl`]:"rtl"===$,[`${C}-round`]:p},y,o,s,k,N);return O(t.createElement("div",{className:f,style:Object.assign(Object.assign({},w),c)},e,a))}return null!=d?d:null};$.Button=e=>{let{prefixCls:i,className:o,rootClassName:s,active:c,block:d=!1,size:u="default"}=e,{getPrefixCls:m}=t.useContext(a.ConfigContext),g=m("skeleton",i),[b,p,f]=h(g),v=(0,r.default)(e,["prefixCls"]),x=(0,l.default)(g,`${g}-element`,{[`${g}-active`]:c,[`${g}-block`]:d},o,s,p,f);return b(t.createElement("div",{className:x},t.createElement(n,Object.assign({prefixCls:`${g}-button`,size:u},v))))},$.Avatar=e=>{let{prefixCls:i,className:o,rootClassName:s,active:c,shape:d="circle",size:u="default"}=e,{getPrefixCls:m}=t.useContext(a.ConfigContext),g=m("skeleton",i),[b,p,f]=h(g),v=(0,r.default)(e,["prefixCls","className"]),x=(0,l.default)(g,`${g}-element`,{[`${g}-active`]:c},o,s,p,f);return b(t.createElement("div",{className:x},t.createElement(n,Object.assign({prefixCls:`${g}-avatar`,shape:d,size:u},v))))},$.Input=e=>{let{prefixCls:i,className:o,rootClassName:s,active:c,block:d,size:u="default"}=e,{getPrefixCls:m}=t.useContext(a.ConfigContext),g=m("skeleton",i),[b,p,f]=h(g),v=(0,r.default)(e,["prefixCls"]),x=(0,l.default)(g,`${g}-element`,{[`${g}-active`]:c,[`${g}-block`]:d},o,s,p,f);return b(t.createElement("div",{className:x},t.createElement(n,Object.assign({prefixCls:`${g}-input`,size:u},v))))},$.Image=e=>{let{prefixCls:r,className:n,rootClassName:i,style:o,active:s}=e,{getPrefixCls:c}=t.useContext(a.ConfigContext),d=c("skeleton",r),[u,m,g]=h(d),b=(0,l.default)(d,`${d}-element`,{[`${d}-active`]:s},n,i,m,g);return u(t.createElement("div",{className:b},t.createElement("div",{className:(0,l.default)(`${d}-image`,n),style:o},t.createElement("svg",{viewBox:"0 0 1098 1024",xmlns:"http://www.w3.org/2000/svg",className:`${d}-image-svg`},t.createElement("title",null,"Image placeholder"),t.createElement("path",{d:"M365.714286 329.142857q0 45.714286-32.036571 77.677714t-77.677714 32.036571-77.677714-32.036571-32.036571-77.677714 32.036571-77.677714 77.677714-32.036571 77.677714 32.036571 32.036571 77.677714zM950.857143 548.571429l0 256-804.571429 0 0-109.714286 182.857143-182.857143 91.428571 91.428571 292.571429-292.571429zM1005.714286 146.285714l-914.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 694.857143q0 7.460571 5.412571 12.873143t12.873143 5.412571l914.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143l0-694.857143q0-7.460571-5.412571-12.873143t-12.873143-5.412571zM1097.142857 164.571429l0 694.857143q0 37.741714-26.843429 64.585143t-64.585143 26.843429l-914.285714 0q-37.741714 0-64.585143-26.843429t-26.843429-64.585143l0-694.857143q0-37.741714 26.843429-64.585143t64.585143-26.843429l914.285714 0q37.741714 0 64.585143 26.843429t26.843429 64.585143z",className:`${d}-image-path`})))))},$.Node=e=>{let{prefixCls:r,className:n,rootClassName:i,style:o,active:s,children:c}=e,{getPrefixCls:d}=t.useContext(a.ConfigContext),u=d("skeleton",r),[m,g,b]=h(u),p=(0,l.default)(u,`${u}-element`,{[`${u}-active`]:s},g,n,i,b);return m(t.createElement("div",{className:p},t.createElement("div",{className:(0,l.default)(`${u}-image`,n),style:o},c)))},e.s(["default",0,$],185793)},959013,e=>{"use strict";e.i(247167);var t=e.i(931067),l=e.i(271645);let a={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"}},{tag:"path",attrs:{d:"M192 474h672q8 0 8 8v60q0 8-8 8H160q-8 0-8-8v-60q0-8 8-8z"}}]},name:"plus",theme:"outlined"};var r=e.i(9583),n=l.forwardRef(function(e,n){return l.createElement(r.default,(0,t.default)({},e,{ref:n,icon:a}))});e.s(["default",0,n],959013)},269200,e=>{"use strict";var t=e.i(290571),l=e.i(271645),a=e.i(444755);let r=(0,e.i(673706).makeClassName)("Table"),n=l.default.forwardRef((e,n)=>{let{children:i,className:o}=e,s=(0,t.__rest)(e,["children","className"]);return l.default.createElement("div",{className:(0,a.tremorTwMerge)(r("root"),"overflow-auto",o)},l.default.createElement("table",Object.assign({ref:n,className:(0,a.tremorTwMerge)(r("table"),"w-full text-tremor-default","text-tremor-content","dark:text-dark-tremor-content")},s),i))});n.displayName="Table",e.s(["Table",()=>n],269200)},427612,e=>{"use strict";var t=e.i(290571),l=e.i(271645),a=e.i(444755);let r=(0,e.i(673706).makeClassName)("TableHead"),n=l.default.forwardRef((e,n)=>{let{children:i,className:o}=e,s=(0,t.__rest)(e,["children","className"]);return l.default.createElement(l.default.Fragment,null,l.default.createElement("thead",Object.assign({ref:n,className:(0,a.tremorTwMerge)(r("root"),"text-left","text-tremor-content","dark:text-dark-tremor-content",o)},s),i))});n.displayName="TableHead",e.s(["TableHead",()=>n],427612)},64848,e=>{"use strict";var t=e.i(290571),l=e.i(271645),a=e.i(444755);let r=(0,e.i(673706).makeClassName)("TableHeaderCell"),n=l.default.forwardRef((e,n)=>{let{children:i,className:o}=e,s=(0,t.__rest)(e,["children","className"]);return l.default.createElement(l.default.Fragment,null,l.default.createElement("th",Object.assign({ref:n,className:(0,a.tremorTwMerge)(r("root"),"whitespace-nowrap text-left font-semibold top-0 px-4 py-3.5","text-tremor-content-strong","dark:text-dark-tremor-content-strong",o)},s),i))});n.displayName="TableHeaderCell",e.s(["TableHeaderCell",()=>n],64848)},942232,e=>{"use strict";var t=e.i(290571),l=e.i(271645),a=e.i(444755);let r=(0,e.i(673706).makeClassName)("TableBody"),n=l.default.forwardRef((e,n)=>{let{children:i,className:o}=e,s=(0,t.__rest)(e,["children","className"]);return l.default.createElement(l.default.Fragment,null,l.default.createElement("tbody",Object.assign({ref:n,className:(0,a.tremorTwMerge)(r("root"),"align-top divide-y","divide-tremor-border","dark:divide-dark-tremor-border",o)},s),i))});n.displayName="TableBody",e.s(["TableBody",()=>n],942232)},496020,e=>{"use strict";var t=e.i(290571),l=e.i(271645),a=e.i(444755);let r=(0,e.i(673706).makeClassName)("TableRow"),n=l.default.forwardRef((e,n)=>{let{children:i,className:o}=e,s=(0,t.__rest)(e,["children","className"]);return l.default.createElement(l.default.Fragment,null,l.default.createElement("tr",Object.assign({ref:n,className:(0,a.tremorTwMerge)(r("row"),o)},s),i))});n.displayName="TableRow",e.s(["TableRow",()=>n],496020)},977572,e=>{"use strict";var t=e.i(290571),l=e.i(271645),a=e.i(444755);let r=(0,e.i(673706).makeClassName)("TableCell"),n=l.default.forwardRef((e,n)=>{let{children:i,className:o}=e,s=(0,t.__rest)(e,["children","className"]);return l.default.createElement(l.default.Fragment,null,l.default.createElement("td",Object.assign({ref:n,className:(0,a.tremorTwMerge)(r("root"),"align-middle whitespace-nowrap text-left p-4",o)},s),i))});n.displayName="TableCell",e.s(["TableCell",()=>n],977572)},68155,e=>{"use strict";var t=e.i(271645);let l=t.forwardRef(function(e,l){return t.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:l},e),t.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"}))});e.s(["TrashIcon",0,l],68155)},278587,e=>{"use strict";var t=e.i(271645);let l=t.forwardRef(function(e,l){return t.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:l},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"}))});e.s(["RefreshIcon",0,l],278587)},207670,e=>{"use strict";function t(){for(var e,t,l=0,a="",r=arguments.length;lt,"default",0,t])},906579,e=>{"use strict";e.i(247167);var t=e.i(271645),l=e.i(343794),a=e.i(361275),r=e.i(702779),n=e.i(763731),i=e.i(242064);e.i(296059);var o=e.i(915654),s=e.i(694758),c=e.i(183293),d=e.i(403541),u=e.i(246422),m=e.i(838378);let g=new s.Keyframes("antStatusProcessing",{"0%":{transform:"scale(0.8)",opacity:.5},"100%":{transform:"scale(2.4)",opacity:0}}),b=new s.Keyframes("antZoomBadgeIn",{"0%":{transform:"scale(0) translate(50%, -50%)",opacity:0},"100%":{transform:"scale(1) translate(50%, -50%)"}}),p=new s.Keyframes("antZoomBadgeOut",{"0%":{transform:"scale(1) translate(50%, -50%)"},"100%":{transform:"scale(0) translate(50%, -50%)",opacity:0}}),f=new s.Keyframes("antNoWrapperZoomBadgeIn",{"0%":{transform:"scale(0)",opacity:0},"100%":{transform:"scale(1)"}}),h=new s.Keyframes("antNoWrapperZoomBadgeOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0)",opacity:0}}),v=new s.Keyframes("antBadgeLoadingCircle",{"0%":{transformOrigin:"50%"},"100%":{transform:"translate(50%, -50%) rotate(360deg)",transformOrigin:"50%"}}),x=e=>{let{fontHeight:t,lineWidth:l,marginXS:a,colorBorderBg:r}=e,n=e.colorTextLightSolid,i=e.colorError,o=e.colorErrorHover;return(0,m.mergeToken)(e,{badgeFontHeight:t,badgeShadowSize:l,badgeTextColor:n,badgeColor:i,badgeColorHover:o,badgeShadowColor:r,badgeProcessingDuration:"1.2s",badgeRibbonOffset:a,badgeRibbonCornerTransform:"scaleY(0.75)",badgeRibbonCornerFilter:"brightness(75%)"})},j=e=>{let{fontSize:t,lineHeight:l,fontSizeSM:a,lineWidth:r}=e;return{indicatorZIndex:"auto",indicatorHeight:Math.round(t*l)-2*r,indicatorHeightSM:t,dotSize:a/2,textFontSize:a,textFontSizeSM:a,textFontWeight:"normal",statusSize:a/2}},$=(0,u.genStyleHooks)("Badge",e=>(e=>{let{componentCls:t,iconCls:l,antCls:a,badgeShadowSize:r,textFontSize:n,textFontSizeSM:i,statusSize:s,dotSize:u,textFontWeight:m,indicatorHeight:x,indicatorHeightSM:j,marginXS:$,calc:y}=e,w=`${a}-scroll-number`,C=(0,d.genPresetColor)(e,(e,{darkColor:l})=>({[`&${t} ${t}-color-${e}`]:{background:l,[`&:not(${t}-count)`]:{color:l},"a:hover &":{background:l}}}));return{[t]:Object.assign(Object.assign(Object.assign(Object.assign({},(0,c.resetComponent)(e)),{position:"relative",display:"inline-block",width:"fit-content",lineHeight:1,[`${t}-count`]:{display:"inline-flex",justifyContent:"center",zIndex:e.indicatorZIndex,minWidth:x,height:x,color:e.badgeTextColor,fontWeight:m,fontSize:n,lineHeight:(0,o.unit)(x),whiteSpace:"nowrap",textAlign:"center",background:e.badgeColor,borderRadius:y(x).div(2).equal(),boxShadow:`0 0 0 ${(0,o.unit)(r)} ${e.badgeShadowColor}`,transition:`background ${e.motionDurationMid}`,a:{color:e.badgeTextColor},"a:hover":{color:e.badgeTextColor},"a:hover &":{background:e.badgeColorHover}},[`${t}-count-sm`]:{minWidth:j,height:j,fontSize:i,lineHeight:(0,o.unit)(j),borderRadius:y(j).div(2).equal()},[`${t}-multiple-words`]:{padding:`0 ${(0,o.unit)(e.paddingXS)}`,bdi:{unicodeBidi:"plaintext"}},[`${t}-dot`]:{zIndex:e.indicatorZIndex,width:u,minWidth:u,height:u,background:e.badgeColor,borderRadius:"100%",boxShadow:`0 0 0 ${(0,o.unit)(r)} ${e.badgeShadowColor}`},[`${t}-count, ${t}-dot, ${w}-custom-component`]:{position:"absolute",top:0,insetInlineEnd:0,transform:"translate(50%, -50%)",transformOrigin:"100% 0%",[`&${l}-spin`]:{animationName:v,animationDuration:"1s",animationIterationCount:"infinite",animationTimingFunction:"linear"}},[`&${t}-status`]:{lineHeight:"inherit",verticalAlign:"baseline",[`${t}-status-dot`]:{position:"relative",top:-1,display:"inline-block",width:s,height:s,verticalAlign:"middle",borderRadius:"50%"},[`${t}-status-success`]:{backgroundColor:e.colorSuccess},[`${t}-status-processing`]:{overflow:"visible",color:e.colorInfo,backgroundColor:e.colorInfo,borderColor:"currentcolor","&::after":{position:"absolute",top:0,insetInlineStart:0,width:"100%",height:"100%",borderWidth:r,borderStyle:"solid",borderColor:"inherit",borderRadius:"50%",animationName:g,animationDuration:e.badgeProcessingDuration,animationIterationCount:"infinite",animationTimingFunction:"ease-in-out",content:'""'}},[`${t}-status-default`]:{backgroundColor:e.colorTextPlaceholder},[`${t}-status-error`]:{backgroundColor:e.colorError},[`${t}-status-warning`]:{backgroundColor:e.colorWarning},[`${t}-status-text`]:{marginInlineStart:$,color:e.colorText,fontSize:e.fontSize}}}),C),{[`${t}-zoom-appear, ${t}-zoom-enter`]:{animationName:b,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack,animationFillMode:"both"},[`${t}-zoom-leave`]:{animationName:p,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack,animationFillMode:"both"},[`&${t}-not-a-wrapper`]:{[`${t}-zoom-appear, ${t}-zoom-enter`]:{animationName:f,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack},[`${t}-zoom-leave`]:{animationName:h,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack},[`&:not(${t}-status)`]:{verticalAlign:"middle"},[`${w}-custom-component, ${t}-count`]:{transform:"none"},[`${w}-custom-component, ${w}`]:{position:"relative",top:"auto",display:"block",transformOrigin:"50% 50%"}},[w]:{overflow:"hidden",transition:`all ${e.motionDurationMid} ${e.motionEaseOutBack}`,[`${w}-only`]:{position:"relative",display:"inline-block",height:x,transition:`all ${e.motionDurationSlow} ${e.motionEaseOutBack}`,WebkitTransformStyle:"preserve-3d",WebkitBackfaceVisibility:"hidden",[`> p${w}-only-unit`]:{height:x,margin:0,WebkitTransformStyle:"preserve-3d",WebkitBackfaceVisibility:"hidden"}},[`${w}-symbol`]:{verticalAlign:"top"}},"&-rtl":{direction:"rtl",[`${t}-count, ${t}-dot, ${w}-custom-component`]:{transform:"translate(-50%, -50%)"}}})}})(x(e)),j),y=(0,u.genStyleHooks)(["Badge","Ribbon"],e=>(e=>{let{antCls:t,badgeFontHeight:l,marginXS:a,badgeRibbonOffset:r,calc:n}=e,i=`${t}-ribbon`,s=`${t}-ribbon-wrapper`,u=(0,d.genPresetColor)(e,(e,{darkColor:t})=>({[`&${i}-color-${e}`]:{background:t,color:t}}));return{[s]:{position:"relative"},[i]:Object.assign(Object.assign(Object.assign(Object.assign({},(0,c.resetComponent)(e)),{position:"absolute",top:a,padding:`0 ${(0,o.unit)(e.paddingXS)}`,color:e.colorPrimary,lineHeight:(0,o.unit)(l),whiteSpace:"nowrap",backgroundColor:e.colorPrimary,borderRadius:e.borderRadiusSM,[`${i}-text`]:{color:e.badgeTextColor},[`${i}-corner`]:{position:"absolute",top:"100%",width:r,height:r,color:"currentcolor",border:`${(0,o.unit)(n(r).div(2).equal())} solid`,transform:e.badgeRibbonCornerTransform,transformOrigin:"top",filter:e.badgeRibbonCornerFilter}}),u),{[`&${i}-placement-end`]:{insetInlineEnd:n(r).mul(-1).equal(),borderEndEndRadius:0,[`${i}-corner`]:{insetInlineEnd:0,borderInlineEndColor:"transparent",borderBlockEndColor:"transparent"}},[`&${i}-placement-start`]:{insetInlineStart:n(r).mul(-1).equal(),borderEndStartRadius:0,[`${i}-corner`]:{insetInlineStart:0,borderBlockEndColor:"transparent",borderInlineStartColor:"transparent"}},"&-rtl":{direction:"rtl"}})}})(x(e)),j),w=e=>{let a,{prefixCls:r,value:n,current:i,offset:o=0}=e;return o&&(a={position:"absolute",top:`${o}00%`,left:0}),t.createElement("span",{style:a,className:(0,l.default)(`${r}-only-unit`,{current:i})},n)},C=e=>{let l,a,{prefixCls:r,count:n,value:i}=e,o=Number(i),s=Math.abs(n),[c,d]=t.useState(o),[u,m]=t.useState(s),g=()=>{d(o),m(s)};if(t.useEffect(()=>{let e=setTimeout(g,1e3);return()=>clearTimeout(e)},[o]),c===o||Number.isNaN(o)||Number.isNaN(c))l=[t.createElement(w,Object.assign({},e,{key:o,current:!0}))],a={transition:"none"};else{l=[];let r=o+10,n=[];for(let e=o;e<=r;e+=1)n.push(e);let i=ue%10===c);l=(i<0?n.slice(0,d+1):n.slice(d)).map((l,a)=>t.createElement(w,Object.assign({},e,{key:l,value:l%10,offset:i<0?a-d:a,current:a===d}))),a={transform:`translateY(${-function(e,t,l){let a=e,r=0;for(;(a+10)%10!==t;)a+=l,r+=l;return r}(c,o,i)}00%)`}}return t.createElement("span",{className:`${r}-only`,style:a,onTransitionEnd:g},l)};var O=function(e,t){var l={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(l[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,a=Object.getOwnPropertySymbols(e);rt.indexOf(a[r])&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(l[a[r]]=e[a[r]]);return l};let k=t.forwardRef((e,a)=>{let{prefixCls:r,count:o,className:s,motionClassName:c,style:d,title:u,show:m,component:g="sup",children:b}=e,p=O(e,["prefixCls","count","className","motionClassName","style","title","show","component","children"]),{getPrefixCls:f}=t.useContext(i.ConfigContext),h=f("scroll-number",r),v=Object.assign(Object.assign({},p),{"data-show":m,style:d,className:(0,l.default)(h,s,c),title:u}),x=o;if(o&&Number(o)%1==0){let e=String(o).split("");x=t.createElement("bdi",null,e.map((l,a)=>t.createElement(C,{prefixCls:h,count:Number(o),value:l,key:e.length-a})))}return((null==d?void 0:d.borderColor)&&(v.style=Object.assign(Object.assign({},d),{boxShadow:`0 0 0 1px ${d.borderColor} inset`})),b)?(0,n.cloneElement)(b,e=>({className:(0,l.default)(`${h}-custom-component`,null==e?void 0:e.className,c)})):t.createElement(g,Object.assign({},v,{ref:a}),x)});var N=function(e,t){var l={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(l[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,a=Object.getOwnPropertySymbols(e);rt.indexOf(a[r])&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(l[a[r]]=e[a[r]]);return l};let E=t.forwardRef((e,o)=>{var s,c,d,u,m;let{prefixCls:g,scrollNumberPrefixCls:b,children:p,status:f,text:h,color:v,count:x=null,overflowCount:j=99,dot:y=!1,size:w="default",title:C,offset:O,style:E,className:S,rootClassName:T,classNames:I,styles:R,showZero:M=!1}=e,_=N(e,["prefixCls","scrollNumberPrefixCls","children","status","text","color","count","overflowCount","dot","size","title","offset","style","className","rootClassName","classNames","styles","showZero"]),{getPrefixCls:F,direction:A,badge:B}=t.useContext(i.ConfigContext),z=F("badge",g),[q,P,L]=$(z),H=x>j?`${j}+`:x,D="0"===H||0===H||"0"===h||0===h,W=null===x||D&&!M,U=(null!=f||null!=v)&&W,K=null!=f||!D,V=y&&!D,Z=V?"":H,X=(0,t.useMemo)(()=>((null==Z||""===Z)&&(null==h||""===h)||D&&!M)&&!V,[Z,D,M,V,h]),G=(0,t.useRef)(x);X||(G.current=x);let J=G.current,Q=(0,t.useRef)(Z);X||(Q.current=Z);let Y=Q.current,ee=(0,t.useRef)(V);X||(ee.current=V);let et=(0,t.useMemo)(()=>{if(!O)return Object.assign(Object.assign({},null==B?void 0:B.style),E);let e={marginTop:O[1]};return"rtl"===A?e.left=Number.parseInt(O[0],10):e.right=-Number.parseInt(O[0],10),Object.assign(Object.assign(Object.assign({},e),null==B?void 0:B.style),E)},[A,O,E,null==B?void 0:B.style]),el=null!=C?C:"string"==typeof J||"number"==typeof J?J:void 0,ea=!X&&(0===h?M:!!h&&!0!==h),er=ea?t.createElement("span",{className:`${z}-status-text`},h):null,en=J&&"object"==typeof J?(0,n.cloneElement)(J,e=>({style:Object.assign(Object.assign({},et),e.style)})):void 0,ei=(0,r.isPresetColor)(v,!1),eo=(0,l.default)(null==I?void 0:I.indicator,null==(s=null==B?void 0:B.classNames)?void 0:s.indicator,{[`${z}-status-dot`]:U,[`${z}-status-${f}`]:!!f,[`${z}-color-${v}`]:ei}),es={};v&&!ei&&(es.color=v,es.background=v);let ec=(0,l.default)(z,{[`${z}-status`]:U,[`${z}-not-a-wrapper`]:!p,[`${z}-rtl`]:"rtl"===A},S,T,null==B?void 0:B.className,null==(c=null==B?void 0:B.classNames)?void 0:c.root,null==I?void 0:I.root,P,L);if(!p&&U&&(h||K||!W)){let e=et.color;return q(t.createElement("span",Object.assign({},_,{className:ec,style:Object.assign(Object.assign(Object.assign({},null==R?void 0:R.root),null==(d=null==B?void 0:B.styles)?void 0:d.root),et)}),t.createElement("span",{className:eo,style:Object.assign(Object.assign(Object.assign({},null==R?void 0:R.indicator),null==(u=null==B?void 0:B.styles)?void 0:u.indicator),es)}),ea&&t.createElement("span",{style:{color:e},className:`${z}-status-text`},h)))}return q(t.createElement("span",Object.assign({ref:o},_,{className:ec,style:Object.assign(Object.assign({},null==(m=null==B?void 0:B.styles)?void 0:m.root),null==R?void 0:R.root)}),p,t.createElement(a.default,{visible:!X,motionName:`${z}-zoom`,motionAppear:!1,motionDeadline:1e3},({className:e})=>{var a,r;let n=F("scroll-number",b),i=ee.current,o=(0,l.default)(null==I?void 0:I.indicator,null==(a=null==B?void 0:B.classNames)?void 0:a.indicator,{[`${z}-dot`]:i,[`${z}-count`]:!i,[`${z}-count-sm`]:"small"===w,[`${z}-multiple-words`]:!i&&Y&&Y.toString().length>1,[`${z}-status-${f}`]:!!f,[`${z}-color-${v}`]:ei}),s=Object.assign(Object.assign(Object.assign({},null==R?void 0:R.indicator),null==(r=null==B?void 0:B.styles)?void 0:r.indicator),et);return v&&!ei&&((s=s||{}).background=v),t.createElement(k,{prefixCls:n,show:!X,motionClassName:e,className:o,count:Y,title:el,style:s,key:"scrollNumber"},en)}),er))});E.Ribbon=e=>{let{className:a,prefixCls:n,style:o,color:s,children:c,text:d,placement:u="end",rootClassName:m}=e,{getPrefixCls:g,direction:b}=t.useContext(i.ConfigContext),p=g("ribbon",n),f=`${p}-wrapper`,[h,v,x]=y(p,f),j=(0,r.isPresetColor)(s,!1),$=(0,l.default)(p,`${p}-placement-${u}`,{[`${p}-rtl`]:"rtl"===b,[`${p}-color-${s}`]:j},a),w={},C={};return s&&!j&&(w.background=s,C.color=s),h(t.createElement("div",{className:(0,l.default)(f,m,v,x)},c,t.createElement("div",{className:(0,l.default)($,v),style:Object.assign(Object.assign({},w),o)},t.createElement("span",{className:`${p}-text`},d),t.createElement("div",{className:`${p}-corner`,style:C}))))},e.s(["Badge",0,E],906579)},738014,e=>{"use strict";var t=e.i(135214),l=e.i(764205),a=e.i(266027);let r=(0,e.i(243652).createQueryKeys)("users");e.s(["useCurrentUser",0,()=>{let{accessToken:e,userId:n,userRole:i}=(0,t.default)();return(0,a.useQuery)({queryKey:r.detail(n),queryFn:async()=>{let t=await (0,l.userInfoCall)(e,n,i,!1,null,null);return console.log(`userInfo: ${JSON.stringify(t)}`),t.user_info},enabled:!!(e&&n&&i)})}])},907308,e=>{"use strict";var t=e.i(843476),l=e.i(271645),a=e.i(212931),r=e.i(808613),n=e.i(464571),i=e.i(199133),o=e.i(592968),s=e.i(213205),c=e.i(374009),d=e.i(764205);e.s(["default",0,({isVisible:e,onCancel:u,onSubmit:m,accessToken:g,title:b="Add Team Member",roles:p=[{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:f="user",teamId:h})=>{let[v]=r.Form.useForm(),[x,j]=(0,l.useState)([]),[$,y]=(0,l.useState)(!1),[w,C]=(0,l.useState)("user_email"),[O,k]=(0,l.useState)(!1),N=async(e,t)=>{if(!e)return void j([]);y(!0);try{let l=new URLSearchParams;if(l.append(t,e),h&&l.append("team_id",h),null==g)return;let a=(await (0,d.userFilterUICall)(g,l)).map(e=>({label:"user_email"===t?`${e.user_email}`:`${e.user_id}`,value:"user_email"===t?e.user_email:e.user_id,user:e}));j(a)}catch(e){console.error("Error fetching users:",e)}finally{y(!1)}},E=(0,l.useCallback)((0,c.default)((e,t)=>N(e,t),300),[]),S=(e,t)=>{C(t),E(e,t)},T=(e,t)=>{let l=t.user;v.setFieldsValue({user_email:l.user_email,user_id:l.user_id,role:v.getFieldValue("role")})},I=async e=>{k(!0);try{await m(e)}finally{k(!1)}};return(0,t.jsx)(a.Modal,{title:b,open:e,onCancel:()=>{v.resetFields(),j([]),u()},footer:null,width:800,maskClosable:!O,children:(0,t.jsxs)(r.Form,{form:v,onFinish:I,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",initialValues:{role:f},children:[(0,t.jsx)(r.Form.Item,{label:"Email",name:"user_email",className:"mb-4",children:(0,t.jsx)(i.Select,{showSearch:!0,className:"w-full",placeholder:"Search by email",filterOption:!1,onSearch:e=>S(e,"user_email"),onSelect:(e,t)=>T(e,t),options:"user_email"===w?x:[],loading:$,allowClear:!0})}),(0,t.jsx)("div",{className:"text-center mb-4",children:"OR"}),(0,t.jsx)(r.Form.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,t.jsx)(i.Select,{showSearch:!0,className:"w-full",placeholder:"Search by user ID",filterOption:!1,onSearch:e=>S(e,"user_id"),onSelect:(e,t)=>T(e,t),options:"user_id"===w?x:[],loading:$,allowClear:!0})}),(0,t.jsx)(r.Form.Item,{label:"Member Role",name:"role",className:"mb-4",children:(0,t.jsx)(i.Select,{defaultValue:f,children:p.map(e=>(0,t.jsx)(i.Select.Option,{value:e.value,children:(0,t.jsxs)(o.Tooltip,{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)(n.Button,{type:"primary",htmlType:"submit",icon:(0,t.jsx)(s.UserAddOutlined,{}),loading:O,children:O?"Adding...":"Add Member"})})]})})}])},162386,e=>{"use strict";var t=e.i(843476),l=e.i(625901),a=e.i(109799),r=e.i(785242),n=e.i(738014),i=e.i(199133),o=e.i(981339),s=e.i(592968);let c={label:"All Proxy Models",value:"all-proxy-models"},d={label:"No Default Models",value:"no-default-models"},u=[c,d],m={user:({allProxyModels:e,userModels:t,options:l})=>t&&l?.includeUserModels?t:[],team:({allProxyModels:e,selectedOrganization:t,userModels:l})=>t?t.models.includes(c.value)||0===t.models.length?e:e.filter(e=>t.models.includes(e)):e??[],organization:({allProxyModels:e})=>e,global:({allProxyModels:e})=>e};e.s(["ModelSelect",0,e=>{let{teamID:g,organizationID:b,options:p,context:f,dataTestId:h,value:v=[],onChange:x,style:j}=e,{includeUserModels:$,showAllTeamModelsOption:y,showAllProxyModelsOverride:w,includeSpecialOptions:C}=p||{},{data:O,isLoading:k}=(0,l.useAllProxyModels)(),{data:N,isLoading:E}=(0,r.useTeam)(g),{data:S,isLoading:T}=(0,a.useOrganization)(b),{data:I,isLoading:R}=(0,n.useCurrentUser)(),M=e=>u.some(t=>t.value===e),_=v.some(M),F=S?.models.includes(c.value)||S?.models.length===0;if(k||E||T||R)return(0,t.jsx)(o.Skeleton.Input,{active:!0,block:!0});let{wildcard:A,regular:B}=(e=>{let t=[],l=[];for(let a of e)a.endsWith("/*")?t.push(a):l.push(a);return{wildcard:t,regular:l}})(((e,t,l)=>{let a=Array.from(new Map(e.map(e=>[e.id,e])).values()).map(e=>e.id);if(t.options?.showAllProxyModelsOverride)return a;let r=m[t.context];return r?r({allProxyModels:a,...l,options:t.options}):[]})(O?.data??[],e,{selectedTeam:N,selectedOrganization:S,userModels:I?.models}));return(0,t.jsx)(i.Select,{"data-testid":h,value:v,onChange:e=>{let t=e.filter(M);x(t.length>0?[t[t.length-1]]:e)},style:j,options:[C?{label:(0,t.jsx)("span",{children:"Special Options"}),title:"Special Options",options:[...w||F&&C||"global"===f?[{label:(0,t.jsx)("span",{children:"All Proxy Models"}),value:c.value,disabled:v.length>0&&v.some(e=>M(e)&&e!==c.value),key:c.value}]:[],{label:(0,t.jsx)("span",{children:"No Default Models"}),value:d.value,disabled:v.length>0&&v.some(e=>M(e)&&e!==d.value),key:d.value}]}:[],...A.length>0?[{label:(0,t.jsx)("span",{children:"Wildcard Options"}),title:"Wildcard Options",options:A.map(e=>{let l=e.replace("/*",""),a=l.charAt(0).toUpperCase()+l.slice(1);return{label:(0,t.jsx)("span",{children:`All ${a} models`}),value:e,disabled:_}})}]:[],{label:(0,t.jsx)("span",{children:"Models"}),title:"Models",options:B.map(e=>({label:(0,t.jsx)("span",{children:e}),value:e,disabled:_}))}],mode:"multiple",placeholder:"Select Models",allowClear:!0,maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(s.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})})})}],162386)},276173,e=>{"use strict";var t=e.i(843476),l=e.i(599724),a=e.i(779241),r=e.i(464571),n=e.i(808613),i=e.i(212931),o=e.i(199133),s=e.i(271645),c=e.i(435451);e.s(["default",0,({visible:e,onCancel:d,onSubmit:u,initialData:m,mode:g,config:b})=>{let p,[f]=n.Form.useForm(),[h,v]=(0,s.useState)(!1);console.log("Initial Data:",m),(0,s.useEffect)(()=>{if(e)if("edit"===g&&m){let e={...m,role:m.role||b.defaultRole,max_budget_in_team:m.max_budget_in_team||null,tpm_limit:m.tpm_limit||null,rpm_limit:m.rpm_limit||null};console.log("Setting form values:",e),f.setFieldsValue(e)}else f.resetFields(),f.setFieldsValue({role:b.defaultRole||b.roleOptions[0]?.value})},[e,m,g,f,b.defaultRole,b.roleOptions]);let x=async e=>{try{v(!0);let t=Object.entries(e).reduce((e,[t,l])=>{if("string"==typeof l){let a=l.trim();return""===a&&("max_budget_in_team"===t||"tpm_limit"===t||"rpm_limit"===t)?{...e,[t]:null}:{...e,[t]:a}}return{...e,[t]:l}},{});console.log("Submitting form data:",t),await Promise.resolve(u(t)),f.resetFields()}catch(e){console.error("Form submission error:",e)}finally{v(!1)}};return(0,t.jsx)(i.Modal,{title:b.title||("add"===g?"Add Member":"Edit Member"),open:e,width:1e3,footer:null,onCancel:d,children:(0,t.jsxs)(n.Form,{form:f,onFinish:x,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[b.showEmail&&(0,t.jsx)(n.Form.Item,{label:"Email",name:"user_email",className:"mb-4",rules:[{type:"email",message:"Please enter a valid email!"}],children:(0,t.jsx)(a.TextInput,{placeholder:"user@example.com"})}),b.showEmail&&b.showUserId&&(0,t.jsx)("div",{className:"text-center mb-4",children:(0,t.jsx)(l.Text,{children:"OR"})}),b.showUserId&&(0,t.jsx)(n.Form.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,t.jsx)(a.TextInput,{placeholder:"user_123"})}),(0,t.jsx)(n.Form.Item,{label:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{children:"Role"}),"edit"===g&&m&&(0,t.jsxs)("span",{className:"text-gray-500 text-sm",children:["(Current: ",(p=m.role,b.roleOptions.find(e=>e.value===p)?.label||p),")"]})]}),name:"role",className:"mb-4",rules:[{required:!0,message:"Please select a role!"}],children:(0,t.jsx)(o.Select,{children:"edit"===g&&m?[...b.roleOptions.filter(e=>e.value===m.role),...b.roleOptions.filter(e=>e.value!==m.role)].map(e=>(0,t.jsx)(o.Select.Option,{value:e.value,children:e.label},e.value)):b.roleOptions.map(e=>(0,t.jsx)(o.Select.Option,{value:e.value,children:e.label},e.value))})}),b.additionalFields?.map(e=>(0,t.jsx)(n.Form.Item,{label:e.label,name:e.name,className:"mb-4",rules:e.rules,children:(e=>{switch(e.type){case"input":return(0,t.jsx)(a.TextInput,{placeholder:e.placeholder});case"numerical":return(0,t.jsx)(c.default,{step:e.step||1,min:e.min||0,style:{width:"100%"},placeholder:e.placeholder||"Enter a numerical value"});case"select":return(0,t.jsx)(o.Select,{children:e.options?.map(e=>(0,t.jsx)(o.Select.Option,{value:e.value,children:e.label},e.value))});default:return null}})(e)},e.name)),(0,t.jsxs)("div",{className:"text-right mt-6",children:[(0,t.jsx)(r.Button,{onClick:d,className:"mr-2",disabled:h,children:"Cancel"}),(0,t.jsx)(r.Button,{type:"default",htmlType:"submit",loading:h,children:"add"===g?h?"Adding...":"Add Member":h?"Saving...":"Save Changes"})]})]})})}])},294612,e=>{"use strict";var t=e.i(843476),l=e.i(100486),a=e.i(827252),r=e.i(213205),n=e.i(771674),i=e.i(464571),o=e.i(770914),s=e.i(291542),c=e.i(262218),d=e.i(592968),u=e.i(898586),m=e.i(902555);let{Text:g}=u.Typography;function b({members:e,canEdit:u,onEdit:b,onDelete:p,onAddMember:f,roleColumnTitle:h="Role",roleTooltip:v,extraColumns:x=[],showDeleteForMember:j,emptyText:$}){let y=[{title:"User Email",dataIndex:"user_email",key:"user_email",render:e=>(0,t.jsx)(g,{children:e||"-"})},{title:"User ID",dataIndex:"user_id",key:"user_id",render:e=>"default_user_id"===e?(0,t.jsx)(c.Tag,{color:"blue",children:"Default Proxy Admin"}):(0,t.jsx)(g,{children:e||"-"})},{title:v?(0,t.jsxs)(o.Space,{direction:"horizontal",children:[h,(0,t.jsx)(d.Tooltip,{title:v,children:(0,t.jsx)(a.InfoCircleOutlined,{})})]}):h,dataIndex:"role",key:"role",render:e=>(0,t.jsxs)(o.Space,{children:[e?.toLowerCase()==="admin"||e?.toLowerCase()==="org_admin"?(0,t.jsx)(l.CrownOutlined,{}):(0,t.jsx)(n.UserOutlined,{}),(0,t.jsx)(g,{style:{textTransform:"capitalize"},children:e||"-"})]})},...x,{title:"Actions",key:"actions",fixed:"right",width:120,render:(e,l)=>u?(0,t.jsxs)(o.Space,{children:[(0,t.jsx)(m.default,{variant:"Edit",tooltipText:"Edit member",dataTestId:"edit-member",onClick:()=>b(l)}),(!j||j(l))&&(0,t.jsx)(m.default,{variant:"Delete",tooltipText:"Delete member",dataTestId:"delete-member",onClick:()=>p(l)})]}):null}];return(0,t.jsxs)(o.Space,{direction:"vertical",style:{width:"100%"},children:[(0,t.jsxs)("span",{className:"inline-flex text-sm text-gray-700",children:[e.length," Member",1!==e.length?"s":""]}),(0,t.jsx)(s.Table,{columns:y,dataSource:e,rowKey:e=>e.user_id??e.user_email??JSON.stringify(e),pagination:!1,size:"small",scroll:{x:"max-content"},locale:$?{emptyText:$}:void 0}),f&&u&&(0,t.jsx)(i.Button,{icon:(0,t.jsx)(r.UserAddOutlined,{}),type:"primary",onClick:f,children:"Add Member"})]})}e.s(["default",()=>b])}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/69365f493e1655a4.js b/litellm/proxy/_experimental/out/_next/static/chunks/0dda11815be4f78b.js similarity index 79% rename from litellm/proxy/_experimental/out/_next/static/chunks/69365f493e1655a4.js rename to litellm/proxy/_experimental/out/_next/static/chunks/0dda11815be4f78b.js index 6b38909128..f8b096910b 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/69365f493e1655a4.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/0dda11815be4f78b.js @@ -100,6 +100,6 @@ `]:{animationName:i.slideDownIn},[`${u}${d}bottomLeft`]:{animationName:i.slideUpOut},[` ${u}${d}topLeft, ${u}${d}topRight - `]:{animationName:i.slideDownOut},"&-hidden":{display:"none"},[o]:Object.assign(Object.assign({},l(e)),{cursor:"pointer",transition:`background ${e.motionDurationSlow} ease`,borderRadius:e.borderRadiusSM,"&-group":{color:e.colorTextDescription,fontSize:e.fontSizeSM,cursor:"default"},"&-option":{display:"flex","&-content":Object.assign({flex:"auto"},t.textEllipsis),"&-state":{flex:"none",display:"flex",alignItems:"center"},[`&-active:not(${o}-option-disabled)`]:{backgroundColor:e.optionActiveBg},[`&-selected:not(${o}-option-disabled)`]:{color:e.optionSelectedColor,fontWeight:e.optionSelectedFontWeight,backgroundColor:e.optionSelectedBg,[`${o}-option-state`]:{color:e.colorPrimary}},"&-disabled":{[`&${o}-option-selected`]:{backgroundColor:e.colorBgContainerDisabled},color:e.colorTextDisabled,cursor:"not-allowed"},"&-grouped":{paddingInlineStart:e.calc(e.controlPaddingHorizontal).mul(2).equal()}},"&-empty":Object.assign(Object.assign({},l(e)),{color:e.colorTextDisabled})}),[`${f}:has(+ ${f})`]:{borderEndStartRadius:0,borderEndEndRadius:0,[`& + ${f}`]:{borderStartStartRadius:0,borderStartEndRadius:0}},"&-rtl":{direction:"rtl"}})},(0,i.initSlideMotion)(e,"slide-up"),(0,i.initSlideMotion)(e,"slide-down"),(0,a.initMoveMotion)(e,"move-up"),(0,a.initMoveMotion)(e,"move-down")]})(e),{[`${n}-rtl`]:{direction:"rtl"}},(0,r.genCompactItemStyle)(e,{borderElCls:`${n}-selector`,focusElCls:`${n}-focused`})]})(v),{[v.componentCls]:Object.assign(Object.assign(Object.assign(Object.assign({},{"&-outlined":Object.assign(Object.assign(Object.assign(Object.assign({},d(v,{borderColor:v.colorBorder,hoverBorderHover:v.hoverBorderColor,activeBorderColor:v.activeBorderColor,activeOutlineColor:v.activeOutlineColor,color:v.colorText})),f(v,{status:"error",borderColor:v.colorError,hoverBorderHover:v.colorErrorHover,activeBorderColor:v.colorError,activeOutlineColor:v.colorErrorOutline,color:v.colorError})),f(v,{status:"warning",borderColor:v.colorWarning,hoverBorderHover:v.colorWarningHover,activeBorderColor:v.colorWarning,activeOutlineColor:v.colorWarningOutline,color:v.colorWarning})),{[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{background:v.colorBgContainerDisabled,color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.multipleItemBg,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.multipleItemBorderColor}`}})}),{"&-filled":Object.assign(Object.assign(Object.assign(Object.assign({},p(v,{bg:v.colorFillTertiary,hoverBg:v.colorFillSecondary,activeBorderColor:v.activeBorderColor,color:v.colorText})),m(v,{status:"error",bg:v.colorErrorBg,hoverBg:v.colorErrorBgHover,activeBorderColor:v.colorError,color:v.colorError})),m(v,{status:"warning",bg:v.colorWarningBg,hoverBg:v.colorWarningBgHover,activeBorderColor:v.colorWarning,color:v.colorWarning})),{[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{borderColor:v.colorBorder,background:v.colorBgContainerDisabled,color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.colorBgContainer,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.colorSplit}`}})}),{"&-borderless":{[`${v.componentCls}-selector`]:{background:"transparent",border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} transparent`},[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.multipleItemBg,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.multipleItemBorderColor}`},[`&${v.componentCls}-status-error`]:{[`${v.componentCls}-prefix, ${v.componentCls}-selection-item`]:{color:v.colorError}},[`&${v.componentCls}-status-warning`]:{[`${v.componentCls}-prefix, ${v.componentCls}-selection-item`]:{color:v.colorWarning}}}}),{"&-underlined":Object.assign(Object.assign(Object.assign(Object.assign({},h(v,{borderColor:v.colorBorder,hoverBorderHover:v.hoverBorderColor,activeBorderColor:v.activeBorderColor,activeOutlineColor:v.activeOutlineColor,color:v.colorText})),g(v,{status:"error",borderColor:v.colorError,hoverBorderHover:v.colorErrorHover,activeBorderColor:v.colorError,activeOutlineColor:v.colorErrorOutline,color:v.colorError})),g(v,{status:"warning",borderColor:v.colorWarning,hoverBorderHover:v.colorWarningHover,activeBorderColor:v.colorWarning,activeOutlineColor:v.colorWarningOutline,color:v.colorWarning})),{[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.multipleItemBg,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.multipleItemBorderColor}`}})})}]},e=>{let{fontSize:t,lineHeight:r,lineWidth:n,controlHeight:o,controlHeightSM:a,controlHeightLG:i,paddingXXS:l,controlPaddingHorizontal:s,zIndexPopupBase:c,colorText:u,fontWeightStrong:d,controlItemBgActive:f,controlItemBgHover:p,colorBgContainer:m,colorFillSecondary:h,colorBgContainerDisabled:g,colorTextDisabled:v,colorPrimaryHover:y,colorPrimary:b,controlOutline:w}=e,$=2*l,C=2*n,E=Math.min(o-$,o-C),S=Math.min(a-$,a-C),x=Math.min(i-$,i-C);return{INTERNAL_FIXED_ITEM_MARGIN:Math.floor(l/2),zIndexPopup:c+50,optionSelectedColor:u,optionSelectedFontWeight:d,optionSelectedBg:f,optionActiveBg:p,optionPadding:`${(o-t*r)/2}px ${s}px`,optionFontSize:t,optionLineHeight:r,optionHeight:o,selectorBg:m,clearBg:m,singleItemHeightLG:i,multipleItemBg:h,multipleItemBorderColor:"transparent",multipleItemHeight:E,multipleItemHeightSM:S,multipleItemHeightLG:x,multipleSelectorBgDisabled:g,multipleItemColorDisabled:v,multipleItemBorderColorDisabled:"transparent",showArrowPaddingInlineEnd:Math.ceil(1.25*e.fontSize),hoverBorderColor:y,activeBorderColor:b,activeOutlineColor:w,selectAffixPadding:l}},{unitless:{optionLineHeight:!0,optionSelectedFontWeight:!0}});e.s(["default",0,v],950302)},121229,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let n={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"}}]},name:"check",theme:"outlined"};var o=e.i(9583),a=r.forwardRef(function(e,a){return r.createElement(o.default,(0,t.default)({},e,{ref:a,icon:n}))});e.s(["default",0,a],121229)},729151,e=>{"use strict";var t=e.i(271645),r=e.i(121229),n=e.i(726289),o=e.i(864517),a=e.i(247153),i=e.i(739295),l=e.i(38953);function s({suffixIcon:e,clearIcon:s,menuItemSelectedIcon:c,removeIcon:u,loading:d,multiple:f,hasFeedback:p,prefixCls:m,showSuffixIcon:h,feedbackIcon:g,showArrow:v,componentName:y}){let b=null!=s?s:t.createElement(n.default,null),w=r=>null!==e||p||v?t.createElement(t.Fragment,null,!1!==h&&r,p&&g):null,$=null;if(void 0!==e)$=w(e);else if(d)$=w(t.createElement(i.default,{spin:!0}));else{let e=`${m}-suffix`;$=({open:r,showSearch:n})=>r&&n?w(t.createElement(l.default,{className:e})):w(t.createElement(a.default,{className:e}))}let C=null;C=void 0!==c?c:f?t.createElement(r.default,null):null;return{clearIcon:b,suffixIcon:$,itemIcon:C,removeIcon:void 0!==u?u:t.createElement(o.default,null)}}e.s(["default",()=>s])},327494,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),n=e.i(123829),o=e.i(955492),a=e.i(869301),i=e.i(529681),l=e.i(122767),s=e.i(613541),c=e.i(805484),u=e.i(52956),d=e.i(242064),f=e.i(721132),p=e.i(937328),m=e.i(321883),h=e.i(517455),g=e.i(62139),v=e.i(792812),y=e.i(249616),b=e.i(104458),w=e.i(85566),$=e.i(950302),C=e.i(729151),E=e.i(617206),S=function(e,t){var r={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&0>t.indexOf(n)&&(r[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var o=0,n=Object.getOwnPropertySymbols(e);ot.indexOf(n[o])&&Object.prototype.propertyIsEnumerable.call(e,n[o])&&(r[n[o]]=e[n[o]]);return r};let x="SECRET_COMBOBOX_MODE_DO_NOT_USE",j=t.forwardRef((e,o)=>{var a,c,j,O,k,T,F,_;let I,{prefixCls:P,bordered:N,className:R,rootClassName:M,getPopupContainer:B,popupClassName:A,dropdownClassName:z,listHeight:L=256,placement:H,listItemHeight:D,size:V,disabled:W,notFoundContent:G,status:U,builtinPlacements:q,dropdownMatchSelectWidth:J,popupMatchSelectWidth:K,direction:X,style:Y,allowClear:Z,variant:Q,dropdownStyle:ee,transitionName:et,tagRender:er,maxCount:en,prefix:eo,dropdownRender:ea,popupRender:ei,onDropdownVisibleChange:el,onOpenChange:es,styles:ec,classNames:eu}=e,ed=S(e,["prefixCls","bordered","className","rootClassName","getPopupContainer","popupClassName","dropdownClassName","listHeight","placement","listItemHeight","size","disabled","notFoundContent","status","builtinPlacements","dropdownMatchSelectWidth","popupMatchSelectWidth","direction","style","allowClear","variant","dropdownStyle","transitionName","tagRender","maxCount","prefix","dropdownRender","popupRender","onDropdownVisibleChange","onOpenChange","styles","classNames"]),{getPopupContainer:ef,getPrefixCls:ep,renderEmpty:em,direction:eh,virtual:eg,popupMatchSelectWidth:ev,popupOverflow:ey}=t.useContext(d.ConfigContext),{showSearch:eb,style:ew,styles:e$,className:eC,classNames:eE}=(0,d.useComponentConfig)("select"),[,eS]=(0,b.useToken)(),ex=null!=D?D:null==eS?void 0:eS.controlHeight,ej=ep("select",P),eO=ep(),ek=null!=X?X:eh,{compactSize:eT,compactItemClassnames:eF}=(0,y.useCompactItemContext)(ej,ek),[e_,eI]=(0,v.default)("select",Q,N),eP=(0,m.default)(ej),[eN,eR,eM]=(0,$.default)(ej,eP),eB=t.useMemo(()=>{let{mode:t}=e;if("combobox"!==t)return t===x?"combobox":t},[e.mode]),eA="multiple"===eB||"tags"===eB,ez=(T=e.suffixIcon,void 0!==(F=e.showArrow)?F:null!==T),eL=null!=(a=null!=K?K:J)?a:ev,eH=(null==(c=null==ec?void 0:ec.popup)?void 0:c.root)||(null==(j=e$.popup)?void 0:j.root)||ee,eD=(_=ei||ea,t.default.useMemo(()=>{if(_)return(...e)=>t.default.createElement(E.default,{space:!0},_.apply(void 0,e))},[_])),{status:eV,hasFeedback:eW,isFormItemInput:eG,feedbackIcon:eU}=t.useContext(g.FormItemInputContext),eq=(0,u.getMergedStatus)(eV,U);I=void 0!==G?G:"combobox"===eB?null:(null==em?void 0:em("Select"))||t.createElement(f.default,{componentName:"Select"});let{suffixIcon:eJ,itemIcon:eK,removeIcon:eX,clearIcon:eY}=(0,C.default)(Object.assign(Object.assign({},ed),{multiple:eA,hasFeedback:eW,feedbackIcon:eU,showSuffixIcon:ez,prefixCls:ej,componentName:"Select"})),eZ=(0,i.default)(ed,["suffixIcon","itemIcon"]),eQ=(0,r.default)((null==(O=null==eu?void 0:eu.popup)?void 0:O.root)||(null==(k=null==eE?void 0:eE.popup)?void 0:k.root)||A||z,{[`${ej}-dropdown-${ek}`]:"rtl"===ek},M,eE.root,null==eu?void 0:eu.root,eM,eP,eR),e0=(0,h.default)(e=>{var t;return null!=(t=null!=V?V:eT)?t:e}),e1=t.useContext(p.default),e2=(0,r.default)({[`${ej}-lg`]:"large"===e0,[`${ej}-sm`]:"small"===e0,[`${ej}-rtl`]:"rtl"===ek,[`${ej}-${e_}`]:eI,[`${ej}-in-form-item`]:eG},(0,u.getStatusClassNames)(ej,eq,eW),eF,eC,R,eE.root,null==eu?void 0:eu.root,M,eM,eP,eR),e4=t.useMemo(()=>void 0!==H?H:"rtl"===ek?"bottomRight":"bottomLeft",[H,ek]),[e6]=(0,l.useZIndex)("SelectLike",null==eH?void 0:eH.zIndex);return eN(t.createElement(n.default,Object.assign({ref:o,virtual:eg,showSearch:eb},eZ,{style:Object.assign(Object.assign(Object.assign(Object.assign({},e$.root),null==ec?void 0:ec.root),ew),Y),dropdownMatchSelectWidth:eL,transitionName:(0,s.getTransitionName)(eO,"slide-up",et),builtinPlacements:(0,w.default)(q,ey),listHeight:L,listItemHeight:ex,mode:eB,prefixCls:ej,placement:e4,direction:ek,prefix:eo,suffixIcon:eJ,menuItemSelectedIcon:eK,removeIcon:eX,allowClear:!0===Z?{clearIcon:eY}:Z,notFoundContent:I,className:e2,getPopupContainer:B||ef,dropdownClassName:eQ,disabled:null!=W?W:e1,dropdownStyle:Object.assign(Object.assign({},eH),{zIndex:e6}),maxCount:eA?en:void 0,tagRender:eA?er:void 0,dropdownRender:eD,onDropdownVisibleChange:es||el})))}),O=(0,c.default)(j,"dropdownAlign");j.SECRET_COMBOBOX_MODE_DO_NOT_USE=x,j.Option=a.Option,j.OptGroup=o.OptGroup,j._InternalPanelDoNotUseOrYouWillBeFired=O,e.s(["default",0,j],327494)},199133,e=>{"use strict";var t=e.i(327494);e.s(["Select",()=>t.default])},689074,21243,98801,e=>{"use strict";var t=e.i(290571),r=e.i(271645);let n=e=>{var n=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},n),r.default.createElement("path",{d:"M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM11 15V17H13V15H11ZM11 7V13H13V7H11Z"}))};e.s(["default",()=>n],689074);let o=e=>{var n=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},n),r.default.createElement("path",{d:"M1.18164 12C2.12215 6.87976 6.60812 3 12.0003 3C17.3924 3 21.8784 6.87976 22.8189 12C21.8784 17.1202 17.3924 21 12.0003 21C6.60812 21 2.12215 17.1202 1.18164 12ZM12.0003 17C14.7617 17 17.0003 14.7614 17.0003 12C17.0003 9.23858 14.7617 7 12.0003 7C9.23884 7 7.00026 9.23858 7.00026 12C7.00026 14.7614 9.23884 17 12.0003 17ZM12.0003 15C10.3434 15 9.00026 13.6569 9.00026 12C9.00026 10.3431 10.3434 9 12.0003 9C13.6571 9 15.0003 10.3431 15.0003 12C15.0003 13.6569 13.6571 15 12.0003 15Z"}))};e.s(["default",()=>o],21243);let a=e=>{var n=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},n),r.default.createElement("path",{d:"M4.52047 5.93457L1.39366 2.80777L2.80788 1.39355L22.6069 21.1925L21.1927 22.6068L17.8827 19.2968C16.1814 20.3755 14.1638 21.0002 12.0003 21.0002C6.60812 21.0002 2.12215 17.1204 1.18164 12.0002C1.61832 9.62282 2.81932 7.5129 4.52047 5.93457ZM14.7577 16.1718L13.2937 14.7078C12.902 14.8952 12.4634 15.0002 12.0003 15.0002C10.3434 15.0002 9.00026 13.657 9.00026 12.0002C9.00026 11.537 9.10522 11.0984 9.29263 10.7067L7.82866 9.24277C7.30514 10.0332 7.00026 10.9811 7.00026 12.0002C7.00026 14.7616 9.23884 17.0002 12.0003 17.0002C13.0193 17.0002 13.9672 16.6953 14.7577 16.1718ZM7.97446 3.76015C9.22127 3.26959 10.5793 3.00016 12.0003 3.00016C17.3924 3.00016 21.8784 6.87992 22.8189 12.0002C22.5067 13.6998 21.8038 15.2628 20.8068 16.5925L16.947 12.7327C16.9821 12.4936 17.0003 12.249 17.0003 12.0002C17.0003 9.23873 14.7617 7.00016 12.0003 7.00016C11.7514 7.00016 11.5068 7.01833 11.2677 7.05343L7.97446 3.76015Z"}))};e.s(["default",()=>a],98801)},103471,e=>{"use strict";var t=e.i(444755),r=e.i(271645);let n=e=>["string","number"].includes(typeof e)?e:e instanceof Array?e.map(n).join(""):"object"==typeof e&&e?n(e.props.children):void 0;function o(e){let t=new Map;return r.default.Children.map(e,e=>{var r;t.set(e.props.value,null!=(r=n(e))?r:e.props.value)}),t}function a(e,t){return r.default.Children.map(t,t=>{var r;if((null!=(r=n(t))?r:t.props.value).toLowerCase().includes(e.toLowerCase()))return t})}let i=(e,r,n=!1)=>(0,t.tremorTwMerge)(r?"bg-tremor-background-subtle dark:bg-dark-tremor-background-subtle":"bg-tremor-background dark:bg-dark-tremor-background",!r&&"hover:bg-tremor-background-muted dark:hover:bg-dark-tremor-background-muted",e?"text-tremor-content-emphasis dark:text-dark-tremor-content-emphasis":"text-tremor-content dark:text-dark-tremor-content",r&&"text-tremor-content-subtle dark:text-dark-tremor-content-subtle",n&&"text-red-500 placeholder:text-red-500 dark:text-red-500 dark:placeholder:text-red-500",n?"border-red-500 dark:border-red-500":"border-tremor-border dark:border-dark-tremor-border");function l(e){return null!=e&&""!==e}e.s(["constructValueToNameMapping",()=>o,"getFilteredOptions",()=>a,"getNodeText",()=>n,"getSelectButtonColors",()=>i,"hasValue",()=>l])},779241,677955,e=>{"use strict";var t=e.i(290571),r=e.i(271645),n=e.i(673706),o=e.i(689074),a=e.i(21243),i=e.i(98801),l=e.i(103471),s=e.i(444755);let c=r.default.forwardRef((e,c)=>{let{value:u,defaultValue:d,type:f,placeholder:p="Type...",icon:m,error:h=!1,errorMessage:g,disabled:v=!1,stepper:y,makeInputClassName:b,className:w,onChange:$,onValueChange:C,autoFocus:E,pattern:S}=e,x=(0,t.__rest)(e,["value","defaultValue","type","placeholder","icon","error","errorMessage","disabled","stepper","makeInputClassName","className","onChange","onValueChange","autoFocus","pattern"]),[j,O]=(0,r.useState)(E||!1),[k,T]=(0,r.useState)(!1),F=(0,r.useCallback)(()=>T(!k),[k,T]),_=(0,r.useRef)(null),I=(0,l.hasValue)(u||d);return r.default.useEffect(()=>{let e=()=>O(!0),t=()=>O(!1),r=_.current;return r&&(r.addEventListener("focus",e),r.addEventListener("blur",t),E&&r.focus()),()=>{r&&(r.removeEventListener("focus",e),r.removeEventListener("blur",t))}},[E]),r.default.createElement(r.default.Fragment,null,r.default.createElement("div",{className:(0,s.tremorTwMerge)(b("root"),"relative w-full flex items-center min-w-[10rem] outline-none rounded-tremor-default transition duration-100 border","shadow-tremor-input","dark:shadow-dark-tremor-input",(0,l.getSelectButtonColors)(I,v,h),j&&(0,s.tremorTwMerge)("ring-2","border-tremor-brand-subtle ring-tremor-brand-muted","dark:border-dark-tremor-brand-subtle dark:ring-dark-tremor-brand-muted"),w)},m?r.default.createElement(m,{className:(0,s.tremorTwMerge)(b("icon"),"shrink-0 h-5 w-5 mx-2.5 absolute left-0 flex items-center","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")}):null,r.default.createElement("input",Object.assign({ref:(0,n.mergeRefs)([_,c]),defaultValue:d,value:u,type:k?"text":f,className:(0,s.tremorTwMerge)(b("input"),"w-full bg-transparent focus:outline-none focus:ring-0 border-none text-tremor-default rounded-tremor-default transition duration-100 py-2","text-tremor-content-emphasis","dark:text-dark-tremor-content-emphasis","[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none","password"===f?h?"pr-16":"pr-12":h?"pr-8":"pr-3",m?"pl-10":"pl-3",v?"placeholder:text-tremor-content-subtle dark:placeholder:text-dark-tremor-content-subtle":"placeholder:text-tremor-content dark:placeholder:text-dark-tremor-content"),placeholder:p,disabled:v,"data-testid":"base-input",onChange:e=>{null==$||$(e),null==C||C(e.target.value)},pattern:S},x)),"password"!==f||v?null:r.default.createElement("button",{className:(0,s.tremorTwMerge)(b("toggleButton"),"absolute inset-y-0 right-0 flex items-center px-2.5 rounded-lg"),type:"button",onClick:()=>F(),"aria-label":k?"Hide password":"Show Password"},k?r.default.createElement(i.default,{className:(0,s.tremorTwMerge)("flex-none h-5 w-5 transition","text-tremor-content-subtle hover:text-tremor-content","dark:text-dark-tremor-content-subtle hover:dark:text-dark-tremor-content"),"aria-hidden":!0}):r.default.createElement(a.default,{className:(0,s.tremorTwMerge)("flex-none h-5 w-5 transition","text-tremor-content-subtle hover:text-tremor-content","dark:text-dark-tremor-content-subtle hover:dark:text-dark-tremor-content"),"aria-hidden":!0})),h?r.default.createElement(o.default,{className:(0,s.tremorTwMerge)(b("errorIcon"),"text-red-500 shrink-0 h-5 w-5 absolute right-0 flex items-center","password"===f?"mr-10":"number"===f?y?"mr-20":"mr-3":"mx-2.5")}):null,null!=y?y:null),h&&g?r.default.createElement("p",{className:(0,s.tremorTwMerge)(b("errorMessage"),"text-sm text-red-500 mt-1")},g):null)});c.displayName="BaseInput",e.s(["default",()=>c],677955);let u=(0,n.makeClassName)("TextInput"),d=r.default.forwardRef((e,n)=>{let{type:o="text"}=e,a=(0,t.__rest)(e,["type"]);return r.default.createElement(c,Object.assign({ref:n,type:o,makeInputClassName:u},a))});d.displayName="TextInput",e.s(["TextInput",()=>d],779241)},827252,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let n={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:"M464 336a48 48 0 1096 0 48 48 0 10-96 0zm72 112h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V456c0-4.4-3.6-8-8-8z"}}]},name:"info-circle",theme:"outlined"};var o=e.i(9583),a=r.forwardRef(function(e,a){return r.createElement(o.default,(0,t.default)({},e,{ref:a,icon:n}))});e.s(["InfoCircleOutlined",0,a],827252)},592968,e=>{"use strict";var t=e.i(491816);e.s(["Tooltip",()=>t.default])},122550,e=>{"use strict";function t(e,t){return e.length>t?e.substring(0,t)+"...":e}e.s(["formItemValidateJSON",0,(e,t)=>{if(!t)return Promise.resolve();try{return JSON.parse(t),Promise.resolve()}catch(e){return Promise.reject("Please enter valid JSON")}},"formatLabel",0,e=>e?e.replace(/_/g," ").replace(/\b\w/g,e=>e.toUpperCase()):e,"truncateString",()=>t])},764205,82946,e=>{"use strict";e.s(["addAllowedIP",()=>eP,"adminGlobalActivity",()=>eq,"adminGlobalActivityPerModel",()=>eK,"adminGlobalCacheActivity",()=>eJ,"adminSpendLogsCall",()=>eV,"adminTopEndUsersCall",()=>eG,"adminTopKeysCall",()=>eW,"adminTopModelsCall",()=>eX,"adminspendByProvider",()=>eU,"agentDailyActivityCall",()=>ew,"agentHubPublicModelsCall",()=>eT,"alertingSettingsCall",()=>J,"allEndUsersCall",()=>eL,"allTagNamesCall",()=>ez,"applyGuardrail",()=>nr,"approveGuardrailSubmission",()=>tB,"approveMCPServer",()=>rS,"availableTeamListCall",()=>el,"budgetCreateCall",()=>G,"budgetDeleteCall",()=>W,"budgetUpdateCall",()=>U,"buildMcpOAuthAuthorizeUrl",()=>nh,"cacheTemporaryMcpServer",()=>np,"cachingHealthCheckCall",()=>tk,"callMCPTool",()=>rP,"cancelModelCostMapReload",()=>z,"checkEuAiActCompliance",()=>nM,"checkGdprCompliance",()=>nB,"claimOnboardingToken",()=>eC,"convertPromptFileToJson",()=>rl,"createAgentCall",()=>rs,"createGuardrailCall",()=>rc,"createMCPServer",()=>rb,"createPassThroughEndpoint",()=>tC,"createPolicyAttachmentCall",()=>t3,"createPolicyCall",()=>tY,"createPolicyVersion",()=>t0,"createPromptCall",()=>ro,"createSearchTool",()=>rO,"credentialCreateCall",()=>e3,"credentialDeleteCall",()=>e9,"credentialGetCall",()=>e5,"credentialListCall",()=>e7,"credentialUpdateCall",()=>e8,"customerDailyActivityCall",()=>eb,"deleteAgentCall",()=>rQ,"deleteAllowedIP",()=>eN,"deleteCallback",()=>nd,"deleteClaudeCodePlugin",()=>nR,"deleteConfigFieldSetting",()=>tS,"deleteGuardrailCall",()=>r2,"deleteMCPOAuthUserCredential",()=>nG,"deleteMCPServer",()=>r$,"deletePassThroughEndpointsCall",()=>tx,"deletePolicyAttachmentCall",()=>t7,"deletePolicyCall",()=>t2,"deletePromptCall",()=>ri,"deleteSearchTool",()=>rT,"deleteToolPolicyOverride",()=>nV,"deriveErrorMessage",()=>nx,"disableClaudeCodePlugin",()=>nN,"enableClaudeCodePlugin",()=>nP,"enrichPolicyTemplate",()=>tU,"enrichPolicyTemplateStream",()=>tK,"estimateAttachmentImpactCall",()=>re,"exchangeMcpOAuthToken",()=>ng,"fetchAvailableSearchProviders",()=>rF,"fetchDiscoverableMCPServers",()=>rm,"fetchMCPAccessGroups",()=>rv,"fetchMCPClientIp",()=>ry,"fetchMCPServerHealth",()=>rg,"fetchMCPServers",()=>rh,"fetchMCPSubmissions",()=>rE,"fetchOpenAPIRegistry",()=>rp,"fetchSearchTools",()=>rj,"fetchToolDetail",()=>nH,"fetchToolPolicyOptions",()=>nA,"fetchToolsList",()=>nz,"formatDate",()=>v,"getAgentCreateMetadata",()=>k,"getAgentInfo",()=>r9,"getAgentsList",()=>r5,"getAllowedIPs",()=>eI,"getBudgetList",()=>tp,"getCacheSettingsCall",()=>tv,"getCallbackConfigsCall",()=>y,"getCallbacksCall",()=>tm,"getCategoryYaml",()=>r3,"getClaudeCodeMarketplace",()=>nT,"getClaudeCodePluginDetails",()=>n_,"getClaudeCodePluginsList",()=>nF,"getConfigFieldSetting",()=>t$,"getDefaultTeamSettings",()=>rz,"getEmailEventSettings",()=>rX,"getGeneralSettingsCall",()=>th,"getGlobalLitellmHeaderName",()=>_,"getGuardrailInfo",()=>r8,"getGuardrailProviderSpecificParams",()=>r6,"getGuardrailUISettings",()=>r4,"getGuardrailsList",()=>tR,"getGuardrailsUsageDetail",()=>tL,"getGuardrailsUsageLogs",()=>tH,"getGuardrailsUsageOverview",()=>tz,"getInProductNudgesCall",()=>b,"getInternalUserSettings",()=>rd,"getLicenseInfo",()=>nc,"getMCPOAuthUserCredentialStatus",()=>nU,"getMCPSemanticFilterSettings",()=>tI,"getMajorAirlines",()=>r7,"getModelCostMapReloadStatus",()=>H,"getModelCostMapSource",()=>L,"getOnboardingCredentials",()=>e$,"getOpenAPISchema",()=>R,"getPassThroughEndpointsCall",()=>tw,"getPoliciesList",()=>tD,"getPolicyAttachmentsList",()=>t6,"getPolicyInfo",()=>t4,"getPolicyInfoWithGuardrails",()=>tW,"getPolicyTemplates",()=>tG,"getPossibleUserRoles",()=>e4,"getPromptInfo",()=>rr,"getPromptVersions",()=>rn,"getPromptsList",()=>rt,"getProviderCreateMetadata",()=>O,"getProxyBaseUrl",()=>C,"getProxyUISettings",()=>tF,"getPublicModelHubInfo",()=>N,"getRemainingUsers",()=>ns,"getResolvedGuardrails",()=>t9,"getRouterSettingsCall",()=>tg,"getSSOSettings",()=>na,"getTeamPermissionsCall",()=>rH,"getToolUsageLogs",()=>nL,"getUISettings",()=>t_,"getUiConfig",()=>P,"getUiSettings",()=>nO,"handleError",()=>j,"individualModelHealthCheckCall",()=>tO,"invitationCreateCall",()=>q,"keyAliasesCall",()=>e1,"keyCreateCall",()=>X,"keyCreateForAgentCall",()=>Y,"keyCreateServiceAccountCall",()=>K,"keyDeleteCall",()=>Q,"keyInfoCall",()=>eY,"keyInfoV1Call",()=>eQ,"keyListCall",()=>e0,"keyUpdateCall",()=>te,"latestHealthChecksCall",()=>tT,"listGuardrailSubmissions",()=>tM,"listMCPTools",()=>rI,"listMCPUserCredentials",()=>nq,"listPolicyVersions",()=>tQ,"loginCall",()=>nj,"makeAgentsPublicCall",()=>r0,"makeMCPPublicCall",()=>r1,"makeModelGroupPublic",()=>I,"mcpHubPublicServersCall",()=>eF,"modelAvailableCall",()=>eM,"modelCostMap",()=>M,"modelCreateCall",()=>D,"modelDeleteCall",()=>V,"modelHubCall",()=>e_,"modelHubPublicModelsCall",()=>ek,"modelInfoCall",()=>ej,"modelInfoV1Call",()=>eO,"modelPatchUpdateCall",()=>tr,"organizationCreateCall",()=>eu,"organizationDailyActivityCall",()=>ey,"organizationDeleteCall",()=>ef,"organizationInfoCall",()=>ec,"organizationListCall",()=>es,"organizationMemberAddCall",()=>tl,"organizationMemberDeleteCall",()=>ts,"organizationMemberUpdateCall",()=>tc,"organizationUpdateCall",()=>ed,"patchAgentCall",()=>ne,"perUserAnalyticsCall",()=>nS,"proxyBaseUrl",()=>$,"ragIngestCall",()=>rK,"regenerateKeyCall",()=>eE,"registerClaudeCodePlugin",()=>nI,"registerMCPServer",()=>rC,"registerMcpOAuthClient",()=>nm,"rejectGuardrailSubmission",()=>tA,"rejectMCPServer",()=>rx,"reloadModelCostMap",()=>B,"resetEmailEventSettings",()=>rZ,"resolvePoliciesCall",()=>t8,"scheduleModelCostMapReload",()=>A,"searchToolQueryCall",()=>ny,"serverRootPath",()=>w,"serviceHealthCheck",()=>tf,"sessionSpendLogsCall",()=>rV,"setCallbacksCall",()=>tj,"setGlobalLitellmHeaderName",()=>F,"storeMCPOAuthUserCredential",()=>nW,"suggestPolicyTemplates",()=>tq,"tagCreateCall",()=>rN,"tagDailyActivityCall",()=>eg,"tagDauCall",()=>nb,"tagDeleteCall",()=>rA,"tagDistinctCall",()=>nC,"tagInfoCall",()=>rM,"tagListCall",()=>rB,"tagMauCall",()=>n$,"tagUpdateCall",()=>rR,"tagWauCall",()=>nw,"tagsSpendLogsCall",()=>eA,"teamBulkMemberAddCall",()=>to,"teamCreateCall",()=>e6,"teamDailyActivityCall",()=>ev,"teamDeleteCall",()=>et,"teamInfoCall",()=>eo,"teamListCall",()=>ei,"teamMemberAddCall",()=>tn,"teamMemberDeleteCall",()=>ti,"teamMemberUpdateCall",()=>ta,"teamPermissionsUpdateCall",()=>rD,"teamSpendLogsCall",()=>eB,"teamUpdateCall",()=>tt,"testCacheConnectionCall",()=>ty,"testConnectionRequest",()=>eZ,"testCustomCodeGuardrail",()=>nn,"testMCPSemanticFilter",()=>tN,"testMCPToolsListRequest",()=>nf,"testPipelineCall",()=>t5,"testPoliciesAndGuardrails",()=>tV,"testPolicyTemplate",()=>tJ,"testSearchToolConnection",()=>r_,"transformRequestCall",()=>ep,"uiAuditLogsCall",()=>nl,"uiSpendLogDetailsCall",()=>ru,"uiSpendLogsCall",()=>eD,"updateCacheSettingsCall",()=>tb,"updateConfigFieldSetting",()=>tE,"updateDefaultTeamSettings",()=>rL,"updateEmailEventSettings",()=>rY,"updateGuardrailCall",()=>nt,"updateInternalUserSettings",()=>rf,"updateMCPSemanticFilterSettings",()=>tP,"updateMCPServer",()=>rw,"updatePassThroughEndpoint",()=>nu,"updatePolicyCall",()=>tZ,"updatePolicyVersionStatus",()=>t1,"updatePromptCall",()=>ra,"updateSSOSettings",()=>ni,"updateSearchTool",()=>rk,"updateToolPolicy",()=>nD,"updateUiSettings",()=>nk,"updateUsefulLinksCall",()=>eR,"usageAiChatStream",()=>tX,"userAgentSummaryCall",()=>nE,"userBulkUpdateUserCall",()=>td,"userCreateCall",()=>Z,"userDailyActivityAggregatedCall",()=>e2,"userDailyActivityCall",()=>eh,"userDeleteCall",()=>ee,"userFilterUICall",()=>eH,"userInfoCall",()=>en,"userListCall",()=>er,"userUpdateUserCall",()=>tu,"v2TeamListCall",()=>ea,"validateBlockedWordsFile",()=>no,"vectorStoreCreateCall",()=>rW,"vectorStoreDeleteCall",()=>rU,"vectorStoreInfoCall",()=>rq,"vectorStoreListCall",()=>rG,"vectorStoreSearchCall",()=>nv,"vectorStoreUpdateCall",()=>rJ],764205),e.i(247167);var t=e.i(998573),r=e.i(268004);e.s(["default",()=>h,"jsonFields",()=>p],82946);var n=e.i(843476),o=e.i(271645),a=e.i(808613),i=e.i(311451),l=e.i(28651),s=e.i(199133),c=e.i(779241),u=e.i(827252),d=e.i(592968),f=e.i(122550);let p=["metadata","config","enforced_params","aliases"],m=(e,t)=>p.includes(e)||"json"===t.format,h=({schemaComponent:e,excludedFields:t=[],form:r,overrideLabels:p={},overrideTooltips:h={},customValidation:g={},defaultValues:v={}})=>{let[y,b]=(0,o.useState)(null),[w,$]=(0,o.useState)(null);return((0,o.useEffect)(()=>{(async()=>{try{let n=(await R()).components.schemas[e];if(!n)throw Error(`Schema component "${e}" not found`);b(n);let o={};Object.keys(n.properties).filter(e=>!t.includes(e)&&void 0!==v[e]).forEach(e=>{o[e]=v[e]}),r.setFieldsValue(o)}catch(e){console.error("Schema fetch error:",e),$(e instanceof Error?e.message:"Failed to fetch schema")}})()},[e,r,t]),w)?(0,n.jsxs)("div",{className:"text-red-500",children:["Error: ",w]}):y?.properties?(0,n.jsx)("div",{children:Object.entries(y.properties).filter(([e])=>!t.includes(e)).map(([e,t])=>{let r,o,b,w,$,C,E,S;return o=(e=>{if(e.type)return e.type;if(e.anyOf){let t=e.anyOf.map(e=>e.type);if(t.includes("number")||t.includes("integer"))return"number";t.includes("string")}return"string"})(t),b=y?.required?.includes(e),w=p[e]||t.title||(0,f.formatLabel)(e),$=h[e]||t.description,C=[],b&&C.push({required:!0,message:`${w} is required`}),g[e]&&C.push({validator:g[e]}),m(e,t)&&C.push({validator:async(e,t)=>{if(t&&!(e=>{if(!e)return!0;try{return JSON.parse(e),!0}catch{return!1}})(t))throw Error("Please enter valid JSON")}}),E=$?(0,n.jsxs)("span",{children:[w," ",(0,n.jsx)(d.Tooltip,{title:$,children:(0,n.jsx)(u.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}):w,r=m(e,t)?(0,n.jsx)(i.Input.TextArea,{rows:4,placeholder:"Enter as JSON",className:"font-mono"}):t.enum?(0,n.jsx)(s.Select,{children:t.enum.map(e=>(0,n.jsx)(s.Select.Option,{value:e,children:e},e))}):"number"===o||"integer"===o?(0,n.jsx)(l.InputNumber,{style:{width:"100%"},precision:"integer"===o?0:void 0}):"duration"===e?(0,n.jsx)(c.TextInput,{placeholder:"eg: 30s, 30h, 30d"}):(0,n.jsx)(c.TextInput,{placeholder:$||""}),(0,n.jsx)(a.Form.Item,{label:E,name:e,className:"mt-8",rules:C,initialValue:v[e],help:(0,n.jsx)("div",{className:"text-xs text-gray-500",children:(S=({max_budget:"Enter maximum budget in USD (e.g., 100.50)",budget_duration:"Select a time period for budget reset",tpm_limit:"Enter maximum tokens per minute (whole number)",rpm_limit:"Enter maximum requests per minute (whole number)",duration:"Enter duration (e.g., 30s, 24h, 7d)",metadata:'Enter JSON object with key-value pairs\nExample: {"team": "research", "project": "nlp"}',config:'Enter configuration as JSON object\nExample: {"setting": "value"}',permissions:"Enter comma-separated permission strings",enforced_params:'Enter parameters as JSON object\nExample: {"param": "value"}',blocked:"Enter true/false or specific block conditions",aliases:'Enter aliases as JSON object\nExample: {"alias1": "value1", "alias2": "value2"}',models:"Select one or more model names",key_alias:"Enter a unique identifier for this key",tags:"Enter comma-separated tag strings"})[e]||({string:"Text input",number:"Numeric input",integer:"Whole number input",boolean:"True/False value"})[o]||"Text input",m(e,t)?`${S} + `]:{animationName:i.slideDownOut},"&-hidden":{display:"none"},[o]:Object.assign(Object.assign({},l(e)),{cursor:"pointer",transition:`background ${e.motionDurationSlow} ease`,borderRadius:e.borderRadiusSM,"&-group":{color:e.colorTextDescription,fontSize:e.fontSizeSM,cursor:"default"},"&-option":{display:"flex","&-content":Object.assign({flex:"auto"},t.textEllipsis),"&-state":{flex:"none",display:"flex",alignItems:"center"},[`&-active:not(${o}-option-disabled)`]:{backgroundColor:e.optionActiveBg},[`&-selected:not(${o}-option-disabled)`]:{color:e.optionSelectedColor,fontWeight:e.optionSelectedFontWeight,backgroundColor:e.optionSelectedBg,[`${o}-option-state`]:{color:e.colorPrimary}},"&-disabled":{[`&${o}-option-selected`]:{backgroundColor:e.colorBgContainerDisabled},color:e.colorTextDisabled,cursor:"not-allowed"},"&-grouped":{paddingInlineStart:e.calc(e.controlPaddingHorizontal).mul(2).equal()}},"&-empty":Object.assign(Object.assign({},l(e)),{color:e.colorTextDisabled})}),[`${f}:has(+ ${f})`]:{borderEndStartRadius:0,borderEndEndRadius:0,[`& + ${f}`]:{borderStartStartRadius:0,borderStartEndRadius:0}},"&-rtl":{direction:"rtl"}})},(0,i.initSlideMotion)(e,"slide-up"),(0,i.initSlideMotion)(e,"slide-down"),(0,a.initMoveMotion)(e,"move-up"),(0,a.initMoveMotion)(e,"move-down")]})(e),{[`${n}-rtl`]:{direction:"rtl"}},(0,r.genCompactItemStyle)(e,{borderElCls:`${n}-selector`,focusElCls:`${n}-focused`})]})(v),{[v.componentCls]:Object.assign(Object.assign(Object.assign(Object.assign({},{"&-outlined":Object.assign(Object.assign(Object.assign(Object.assign({},d(v,{borderColor:v.colorBorder,hoverBorderHover:v.hoverBorderColor,activeBorderColor:v.activeBorderColor,activeOutlineColor:v.activeOutlineColor,color:v.colorText})),f(v,{status:"error",borderColor:v.colorError,hoverBorderHover:v.colorErrorHover,activeBorderColor:v.colorError,activeOutlineColor:v.colorErrorOutline,color:v.colorError})),f(v,{status:"warning",borderColor:v.colorWarning,hoverBorderHover:v.colorWarningHover,activeBorderColor:v.colorWarning,activeOutlineColor:v.colorWarningOutline,color:v.colorWarning})),{[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{background:v.colorBgContainerDisabled,color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.multipleItemBg,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.multipleItemBorderColor}`}})}),{"&-filled":Object.assign(Object.assign(Object.assign(Object.assign({},p(v,{bg:v.colorFillTertiary,hoverBg:v.colorFillSecondary,activeBorderColor:v.activeBorderColor,color:v.colorText})),m(v,{status:"error",bg:v.colorErrorBg,hoverBg:v.colorErrorBgHover,activeBorderColor:v.colorError,color:v.colorError})),m(v,{status:"warning",bg:v.colorWarningBg,hoverBg:v.colorWarningBgHover,activeBorderColor:v.colorWarning,color:v.colorWarning})),{[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{borderColor:v.colorBorder,background:v.colorBgContainerDisabled,color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.colorBgContainer,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.colorSplit}`}})}),{"&-borderless":{[`${v.componentCls}-selector`]:{background:"transparent",border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} transparent`},[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.multipleItemBg,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.multipleItemBorderColor}`},[`&${v.componentCls}-status-error`]:{[`${v.componentCls}-prefix, ${v.componentCls}-selection-item`]:{color:v.colorError}},[`&${v.componentCls}-status-warning`]:{[`${v.componentCls}-prefix, ${v.componentCls}-selection-item`]:{color:v.colorWarning}}}}),{"&-underlined":Object.assign(Object.assign(Object.assign(Object.assign({},h(v,{borderColor:v.colorBorder,hoverBorderHover:v.hoverBorderColor,activeBorderColor:v.activeBorderColor,activeOutlineColor:v.activeOutlineColor,color:v.colorText})),g(v,{status:"error",borderColor:v.colorError,hoverBorderHover:v.colorErrorHover,activeBorderColor:v.colorError,activeOutlineColor:v.colorErrorOutline,color:v.colorError})),g(v,{status:"warning",borderColor:v.colorWarning,hoverBorderHover:v.colorWarningHover,activeBorderColor:v.colorWarning,activeOutlineColor:v.colorWarningOutline,color:v.colorWarning})),{[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.multipleItemBg,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.multipleItemBorderColor}`}})})}]},e=>{let{fontSize:t,lineHeight:r,lineWidth:n,controlHeight:o,controlHeightSM:a,controlHeightLG:i,paddingXXS:l,controlPaddingHorizontal:s,zIndexPopupBase:c,colorText:u,fontWeightStrong:d,controlItemBgActive:f,controlItemBgHover:p,colorBgContainer:m,colorFillSecondary:h,colorBgContainerDisabled:g,colorTextDisabled:v,colorPrimaryHover:y,colorPrimary:b,controlOutline:w}=e,$=2*l,C=2*n,E=Math.min(o-$,o-C),S=Math.min(a-$,a-C),x=Math.min(i-$,i-C);return{INTERNAL_FIXED_ITEM_MARGIN:Math.floor(l/2),zIndexPopup:c+50,optionSelectedColor:u,optionSelectedFontWeight:d,optionSelectedBg:f,optionActiveBg:p,optionPadding:`${(o-t*r)/2}px ${s}px`,optionFontSize:t,optionLineHeight:r,optionHeight:o,selectorBg:m,clearBg:m,singleItemHeightLG:i,multipleItemBg:h,multipleItemBorderColor:"transparent",multipleItemHeight:E,multipleItemHeightSM:S,multipleItemHeightLG:x,multipleSelectorBgDisabled:g,multipleItemColorDisabled:v,multipleItemBorderColorDisabled:"transparent",showArrowPaddingInlineEnd:Math.ceil(1.25*e.fontSize),hoverBorderColor:y,activeBorderColor:b,activeOutlineColor:w,selectAffixPadding:l}},{unitless:{optionLineHeight:!0,optionSelectedFontWeight:!0}});e.s(["default",0,v],950302)},121229,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let n={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"}}]},name:"check",theme:"outlined"};var o=e.i(9583),a=r.forwardRef(function(e,a){return r.createElement(o.default,(0,t.default)({},e,{ref:a,icon:n}))});e.s(["default",0,a],121229)},729151,e=>{"use strict";var t=e.i(271645),r=e.i(121229),n=e.i(726289),o=e.i(864517),a=e.i(247153),i=e.i(739295),l=e.i(38953);function s({suffixIcon:e,clearIcon:s,menuItemSelectedIcon:c,removeIcon:u,loading:d,multiple:f,hasFeedback:p,prefixCls:m,showSuffixIcon:h,feedbackIcon:g,showArrow:v,componentName:y}){let b=null!=s?s:t.createElement(n.default,null),w=r=>null!==e||p||v?t.createElement(t.Fragment,null,!1!==h&&r,p&&g):null,$=null;if(void 0!==e)$=w(e);else if(d)$=w(t.createElement(i.default,{spin:!0}));else{let e=`${m}-suffix`;$=({open:r,showSearch:n})=>r&&n?w(t.createElement(l.default,{className:e})):w(t.createElement(a.default,{className:e}))}let C=null;C=void 0!==c?c:f?t.createElement(r.default,null):null;return{clearIcon:b,suffixIcon:$,itemIcon:C,removeIcon:void 0!==u?u:t.createElement(o.default,null)}}e.s(["default",()=>s])},327494,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),n=e.i(123829),o=e.i(955492),a=e.i(869301),i=e.i(529681),l=e.i(122767),s=e.i(613541),c=e.i(805484),u=e.i(52956),d=e.i(242064),f=e.i(721132),p=e.i(937328),m=e.i(321883),h=e.i(517455),g=e.i(62139),v=e.i(792812),y=e.i(249616),b=e.i(104458),w=e.i(85566),$=e.i(950302),C=e.i(729151),E=e.i(617206),S=function(e,t){var r={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&0>t.indexOf(n)&&(r[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var o=0,n=Object.getOwnPropertySymbols(e);ot.indexOf(n[o])&&Object.prototype.propertyIsEnumerable.call(e,n[o])&&(r[n[o]]=e[n[o]]);return r};let x="SECRET_COMBOBOX_MODE_DO_NOT_USE",j=t.forwardRef((e,o)=>{var a,c,j,O,k,T,F,_;let I,{prefixCls:P,bordered:N,className:R,rootClassName:M,getPopupContainer:B,popupClassName:A,dropdownClassName:z,listHeight:L=256,placement:H,listItemHeight:D,size:V,disabled:W,notFoundContent:G,status:U,builtinPlacements:q,dropdownMatchSelectWidth:J,popupMatchSelectWidth:K,direction:X,style:Y,allowClear:Z,variant:Q,dropdownStyle:ee,transitionName:et,tagRender:er,maxCount:en,prefix:eo,dropdownRender:ea,popupRender:ei,onDropdownVisibleChange:el,onOpenChange:es,styles:ec,classNames:eu}=e,ed=S(e,["prefixCls","bordered","className","rootClassName","getPopupContainer","popupClassName","dropdownClassName","listHeight","placement","listItemHeight","size","disabled","notFoundContent","status","builtinPlacements","dropdownMatchSelectWidth","popupMatchSelectWidth","direction","style","allowClear","variant","dropdownStyle","transitionName","tagRender","maxCount","prefix","dropdownRender","popupRender","onDropdownVisibleChange","onOpenChange","styles","classNames"]),{getPopupContainer:ef,getPrefixCls:ep,renderEmpty:em,direction:eh,virtual:eg,popupMatchSelectWidth:ev,popupOverflow:ey}=t.useContext(d.ConfigContext),{showSearch:eb,style:ew,styles:e$,className:eC,classNames:eE}=(0,d.useComponentConfig)("select"),[,eS]=(0,b.useToken)(),ex=null!=D?D:null==eS?void 0:eS.controlHeight,ej=ep("select",P),eO=ep(),ek=null!=X?X:eh,{compactSize:eT,compactItemClassnames:eF}=(0,y.useCompactItemContext)(ej,ek),[e_,eI]=(0,v.default)("select",Q,N),eP=(0,m.default)(ej),[eN,eR,eM]=(0,$.default)(ej,eP),eB=t.useMemo(()=>{let{mode:t}=e;if("combobox"!==t)return t===x?"combobox":t},[e.mode]),eA="multiple"===eB||"tags"===eB,ez=(T=e.suffixIcon,void 0!==(F=e.showArrow)?F:null!==T),eL=null!=(a=null!=K?K:J)?a:ev,eH=(null==(c=null==ec?void 0:ec.popup)?void 0:c.root)||(null==(j=e$.popup)?void 0:j.root)||ee,eD=(_=ei||ea,t.default.useMemo(()=>{if(_)return(...e)=>t.default.createElement(E.default,{space:!0},_.apply(void 0,e))},[_])),{status:eV,hasFeedback:eW,isFormItemInput:eG,feedbackIcon:eU}=t.useContext(g.FormItemInputContext),eq=(0,u.getMergedStatus)(eV,U);I=void 0!==G?G:"combobox"===eB?null:(null==em?void 0:em("Select"))||t.createElement(f.default,{componentName:"Select"});let{suffixIcon:eJ,itemIcon:eK,removeIcon:eX,clearIcon:eY}=(0,C.default)(Object.assign(Object.assign({},ed),{multiple:eA,hasFeedback:eW,feedbackIcon:eU,showSuffixIcon:ez,prefixCls:ej,componentName:"Select"})),eZ=(0,i.default)(ed,["suffixIcon","itemIcon"]),eQ=(0,r.default)((null==(O=null==eu?void 0:eu.popup)?void 0:O.root)||(null==(k=null==eE?void 0:eE.popup)?void 0:k.root)||A||z,{[`${ej}-dropdown-${ek}`]:"rtl"===ek},M,eE.root,null==eu?void 0:eu.root,eM,eP,eR),e0=(0,h.default)(e=>{var t;return null!=(t=null!=V?V:eT)?t:e}),e1=t.useContext(p.default),e2=(0,r.default)({[`${ej}-lg`]:"large"===e0,[`${ej}-sm`]:"small"===e0,[`${ej}-rtl`]:"rtl"===ek,[`${ej}-${e_}`]:eI,[`${ej}-in-form-item`]:eG},(0,u.getStatusClassNames)(ej,eq,eW),eF,eC,R,eE.root,null==eu?void 0:eu.root,M,eM,eP,eR),e4=t.useMemo(()=>void 0!==H?H:"rtl"===ek?"bottomRight":"bottomLeft",[H,ek]),[e6]=(0,l.useZIndex)("SelectLike",null==eH?void 0:eH.zIndex);return eN(t.createElement(n.default,Object.assign({ref:o,virtual:eg,showSearch:eb},eZ,{style:Object.assign(Object.assign(Object.assign(Object.assign({},e$.root),null==ec?void 0:ec.root),ew),Y),dropdownMatchSelectWidth:eL,transitionName:(0,s.getTransitionName)(eO,"slide-up",et),builtinPlacements:(0,w.default)(q,ey),listHeight:L,listItemHeight:ex,mode:eB,prefixCls:ej,placement:e4,direction:ek,prefix:eo,suffixIcon:eJ,menuItemSelectedIcon:eK,removeIcon:eX,allowClear:!0===Z?{clearIcon:eY}:Z,notFoundContent:I,className:e2,getPopupContainer:B||ef,dropdownClassName:eQ,disabled:null!=W?W:e1,dropdownStyle:Object.assign(Object.assign({},eH),{zIndex:e6}),maxCount:eA?en:void 0,tagRender:eA?er:void 0,dropdownRender:eD,onDropdownVisibleChange:es||el})))}),O=(0,c.default)(j,"dropdownAlign");j.SECRET_COMBOBOX_MODE_DO_NOT_USE=x,j.Option=a.Option,j.OptGroup=o.OptGroup,j._InternalPanelDoNotUseOrYouWillBeFired=O,e.s(["default",0,j],327494)},199133,e=>{"use strict";var t=e.i(327494);e.s(["Select",()=>t.default])},689074,21243,98801,e=>{"use strict";var t=e.i(290571),r=e.i(271645);let n=e=>{var n=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},n),r.default.createElement("path",{d:"M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM11 15V17H13V15H11ZM11 7V13H13V7H11Z"}))};e.s(["default",()=>n],689074);let o=e=>{var n=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},n),r.default.createElement("path",{d:"M1.18164 12C2.12215 6.87976 6.60812 3 12.0003 3C17.3924 3 21.8784 6.87976 22.8189 12C21.8784 17.1202 17.3924 21 12.0003 21C6.60812 21 2.12215 17.1202 1.18164 12ZM12.0003 17C14.7617 17 17.0003 14.7614 17.0003 12C17.0003 9.23858 14.7617 7 12.0003 7C9.23884 7 7.00026 9.23858 7.00026 12C7.00026 14.7614 9.23884 17 12.0003 17ZM12.0003 15C10.3434 15 9.00026 13.6569 9.00026 12C9.00026 10.3431 10.3434 9 12.0003 9C13.6571 9 15.0003 10.3431 15.0003 12C15.0003 13.6569 13.6571 15 12.0003 15Z"}))};e.s(["default",()=>o],21243);let a=e=>{var n=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},n),r.default.createElement("path",{d:"M4.52047 5.93457L1.39366 2.80777L2.80788 1.39355L22.6069 21.1925L21.1927 22.6068L17.8827 19.2968C16.1814 20.3755 14.1638 21.0002 12.0003 21.0002C6.60812 21.0002 2.12215 17.1204 1.18164 12.0002C1.61832 9.62282 2.81932 7.5129 4.52047 5.93457ZM14.7577 16.1718L13.2937 14.7078C12.902 14.8952 12.4634 15.0002 12.0003 15.0002C10.3434 15.0002 9.00026 13.657 9.00026 12.0002C9.00026 11.537 9.10522 11.0984 9.29263 10.7067L7.82866 9.24277C7.30514 10.0332 7.00026 10.9811 7.00026 12.0002C7.00026 14.7616 9.23884 17.0002 12.0003 17.0002C13.0193 17.0002 13.9672 16.6953 14.7577 16.1718ZM7.97446 3.76015C9.22127 3.26959 10.5793 3.00016 12.0003 3.00016C17.3924 3.00016 21.8784 6.87992 22.8189 12.0002C22.5067 13.6998 21.8038 15.2628 20.8068 16.5925L16.947 12.7327C16.9821 12.4936 17.0003 12.249 17.0003 12.0002C17.0003 9.23873 14.7617 7.00016 12.0003 7.00016C11.7514 7.00016 11.5068 7.01833 11.2677 7.05343L7.97446 3.76015Z"}))};e.s(["default",()=>a],98801)},103471,e=>{"use strict";var t=e.i(444755),r=e.i(271645);let n=e=>["string","number"].includes(typeof e)?e:e instanceof Array?e.map(n).join(""):"object"==typeof e&&e?n(e.props.children):void 0;function o(e){let t=new Map;return r.default.Children.map(e,e=>{var r;t.set(e.props.value,null!=(r=n(e))?r:e.props.value)}),t}function a(e,t){return r.default.Children.map(t,t=>{var r;if((null!=(r=n(t))?r:t.props.value).toLowerCase().includes(e.toLowerCase()))return t})}let i=(e,r,n=!1)=>(0,t.tremorTwMerge)(r?"bg-tremor-background-subtle dark:bg-dark-tremor-background-subtle":"bg-tremor-background dark:bg-dark-tremor-background",!r&&"hover:bg-tremor-background-muted dark:hover:bg-dark-tremor-background-muted",e?"text-tremor-content-emphasis dark:text-dark-tremor-content-emphasis":"text-tremor-content dark:text-dark-tremor-content",r&&"text-tremor-content-subtle dark:text-dark-tremor-content-subtle",n&&"text-red-500 placeholder:text-red-500 dark:text-red-500 dark:placeholder:text-red-500",n?"border-red-500 dark:border-red-500":"border-tremor-border dark:border-dark-tremor-border");function l(e){return null!=e&&""!==e}e.s(["constructValueToNameMapping",()=>o,"getFilteredOptions",()=>a,"getNodeText",()=>n,"getSelectButtonColors",()=>i,"hasValue",()=>l])},779241,677955,e=>{"use strict";var t=e.i(290571),r=e.i(271645),n=e.i(673706),o=e.i(689074),a=e.i(21243),i=e.i(98801),l=e.i(103471),s=e.i(444755);let c=r.default.forwardRef((e,c)=>{let{value:u,defaultValue:d,type:f,placeholder:p="Type...",icon:m,error:h=!1,errorMessage:g,disabled:v=!1,stepper:y,makeInputClassName:b,className:w,onChange:$,onValueChange:C,autoFocus:E,pattern:S}=e,x=(0,t.__rest)(e,["value","defaultValue","type","placeholder","icon","error","errorMessage","disabled","stepper","makeInputClassName","className","onChange","onValueChange","autoFocus","pattern"]),[j,O]=(0,r.useState)(E||!1),[k,T]=(0,r.useState)(!1),F=(0,r.useCallback)(()=>T(!k),[k,T]),_=(0,r.useRef)(null),I=(0,l.hasValue)(u||d);return r.default.useEffect(()=>{let e=()=>O(!0),t=()=>O(!1),r=_.current;return r&&(r.addEventListener("focus",e),r.addEventListener("blur",t),E&&r.focus()),()=>{r&&(r.removeEventListener("focus",e),r.removeEventListener("blur",t))}},[E]),r.default.createElement(r.default.Fragment,null,r.default.createElement("div",{className:(0,s.tremorTwMerge)(b("root"),"relative w-full flex items-center min-w-[10rem] outline-none rounded-tremor-default transition duration-100 border","shadow-tremor-input","dark:shadow-dark-tremor-input",(0,l.getSelectButtonColors)(I,v,h),j&&(0,s.tremorTwMerge)("ring-2","border-tremor-brand-subtle ring-tremor-brand-muted","dark:border-dark-tremor-brand-subtle dark:ring-dark-tremor-brand-muted"),w)},m?r.default.createElement(m,{className:(0,s.tremorTwMerge)(b("icon"),"shrink-0 h-5 w-5 mx-2.5 absolute left-0 flex items-center","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")}):null,r.default.createElement("input",Object.assign({ref:(0,n.mergeRefs)([_,c]),defaultValue:d,value:u,type:k?"text":f,className:(0,s.tremorTwMerge)(b("input"),"w-full bg-transparent focus:outline-none focus:ring-0 border-none text-tremor-default rounded-tremor-default transition duration-100 py-2","text-tremor-content-emphasis","dark:text-dark-tremor-content-emphasis","[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none","password"===f?h?"pr-16":"pr-12":h?"pr-8":"pr-3",m?"pl-10":"pl-3",v?"placeholder:text-tremor-content-subtle dark:placeholder:text-dark-tremor-content-subtle":"placeholder:text-tremor-content dark:placeholder:text-dark-tremor-content"),placeholder:p,disabled:v,"data-testid":"base-input",onChange:e=>{null==$||$(e),null==C||C(e.target.value)},pattern:S},x)),"password"!==f||v?null:r.default.createElement("button",{className:(0,s.tremorTwMerge)(b("toggleButton"),"absolute inset-y-0 right-0 flex items-center px-2.5 rounded-lg"),type:"button",onClick:()=>F(),"aria-label":k?"Hide password":"Show Password"},k?r.default.createElement(i.default,{className:(0,s.tremorTwMerge)("flex-none h-5 w-5 transition","text-tremor-content-subtle hover:text-tremor-content","dark:text-dark-tremor-content-subtle hover:dark:text-dark-tremor-content"),"aria-hidden":!0}):r.default.createElement(a.default,{className:(0,s.tremorTwMerge)("flex-none h-5 w-5 transition","text-tremor-content-subtle hover:text-tremor-content","dark:text-dark-tremor-content-subtle hover:dark:text-dark-tremor-content"),"aria-hidden":!0})),h?r.default.createElement(o.default,{className:(0,s.tremorTwMerge)(b("errorIcon"),"text-red-500 shrink-0 h-5 w-5 absolute right-0 flex items-center","password"===f?"mr-10":"number"===f?y?"mr-20":"mr-3":"mx-2.5")}):null,null!=y?y:null),h&&g?r.default.createElement("p",{className:(0,s.tremorTwMerge)(b("errorMessage"),"text-sm text-red-500 mt-1")},g):null)});c.displayName="BaseInput",e.s(["default",()=>c],677955);let u=(0,n.makeClassName)("TextInput"),d=r.default.forwardRef((e,n)=>{let{type:o="text"}=e,a=(0,t.__rest)(e,["type"]);return r.default.createElement(c,Object.assign({ref:n,type:o,makeInputClassName:u},a))});d.displayName="TextInput",e.s(["TextInput",()=>d],779241)},827252,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let n={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:"M464 336a48 48 0 1096 0 48 48 0 10-96 0zm72 112h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V456c0-4.4-3.6-8-8-8z"}}]},name:"info-circle",theme:"outlined"};var o=e.i(9583),a=r.forwardRef(function(e,a){return r.createElement(o.default,(0,t.default)({},e,{ref:a,icon:n}))});e.s(["InfoCircleOutlined",0,a],827252)},592968,e=>{"use strict";var t=e.i(491816);e.s(["Tooltip",()=>t.default])},122550,e=>{"use strict";function t(e,t){return e.length>t?e.substring(0,t)+"...":e}e.s(["formItemValidateJSON",0,(e,t)=>{if(!t)return Promise.resolve();try{return JSON.parse(t),Promise.resolve()}catch(e){return Promise.reject("Please enter valid JSON")}},"formatLabel",0,e=>e?e.replace(/_/g," ").replace(/\b\w/g,e=>e.toUpperCase()):e,"truncateString",()=>t])},764205,82946,e=>{"use strict";e.s(["addAllowedIP",()=>eN,"adminGlobalActivity",()=>eJ,"adminGlobalActivityPerModel",()=>eX,"adminGlobalCacheActivity",()=>eK,"adminSpendLogsCall",()=>eW,"adminTopEndUsersCall",()=>eU,"adminTopKeysCall",()=>eG,"adminTopModelsCall",()=>eY,"adminspendByProvider",()=>eq,"agentDailyActivityCall",()=>e$,"agentHubPublicModelsCall",()=>eF,"alertingSettingsCall",()=>J,"allEndUsersCall",()=>eH,"allTagNamesCall",()=>eL,"applyGuardrail",()=>nn,"approveGuardrailSubmission",()=>tA,"approveMCPServer",()=>rx,"availableTeamListCall",()=>es,"budgetCreateCall",()=>G,"budgetDeleteCall",()=>W,"budgetUpdateCall",()=>U,"buildMcpOAuthAuthorizeUrl",()=>ng,"cacheTemporaryMcpServer",()=>nm,"cachingHealthCheckCall",()=>tT,"callMCPTool",()=>rN,"cancelModelCostMapReload",()=>z,"checkEuAiActCompliance",()=>nB,"checkGdprCompliance",()=>nA,"claimOnboardingToken",()=>eE,"convertPromptFileToJson",()=>rs,"createAgentCall",()=>rc,"createGuardrailCall",()=>ru,"createMCPServer",()=>rw,"createPassThroughEndpoint",()=>tE,"createPolicyAttachmentCall",()=>t7,"createPolicyCall",()=>tZ,"createPolicyVersion",()=>t1,"createPromptCall",()=>ra,"createSearchTool",()=>rk,"credentialCreateCall",()=>e7,"credentialDeleteCall",()=>e8,"credentialGetCall",()=>e9,"credentialListCall",()=>e5,"credentialUpdateCall",()=>te,"customerDailyActivityCall",()=>ew,"deleteAgentCall",()=>r0,"deleteAllowedIP",()=>eR,"deleteCallback",()=>nf,"deleteClaudeCodePlugin",()=>nM,"deleteConfigFieldSetting",()=>tx,"deleteGuardrailCall",()=>r4,"deleteMCPOAuthUserCredential",()=>nU,"deleteMCPServer",()=>rC,"deletePassThroughEndpointsCall",()=>tj,"deletePolicyAttachmentCall",()=>t5,"deletePolicyCall",()=>t4,"deletePromptCall",()=>rl,"deleteSearchTool",()=>rF,"deleteToolPolicyOverride",()=>nW,"deriveErrorMessage",()=>nj,"disableClaudeCodePlugin",()=>nR,"enableClaudeCodePlugin",()=>nN,"enrichPolicyTemplate",()=>tq,"enrichPolicyTemplateStream",()=>tX,"estimateAttachmentImpactCall",()=>rt,"exchangeMcpOAuthToken",()=>nv,"fetchAvailableSearchProviders",()=>r_,"fetchDiscoverableMCPServers",()=>rh,"fetchMCPAccessGroups",()=>ry,"fetchMCPClientIp",()=>rb,"fetchMCPServerHealth",()=>rv,"fetchMCPServers",()=>rg,"fetchMCPSubmissions",()=>rS,"fetchOpenAPIRegistry",()=>rm,"fetchSearchTools",()=>rO,"fetchToolDetail",()=>nD,"fetchToolPolicyOptions",()=>nz,"fetchToolsList",()=>nL,"formatDate",()=>v,"getAgentCreateMetadata",()=>k,"getAgentInfo",()=>r8,"getAgentsList",()=>r9,"getAllowedIPs",()=>eP,"getBudgetList",()=>tm,"getCacheSettingsCall",()=>ty,"getCallbackConfigsCall",()=>y,"getCallbacksCall",()=>th,"getCategoryYaml",()=>r7,"getClaudeCodeMarketplace",()=>nF,"getClaudeCodePluginDetails",()=>nI,"getClaudeCodePluginsList",()=>n_,"getConfigFieldSetting",()=>tC,"getDefaultTeamSettings",()=>rL,"getEmailEventSettings",()=>rY,"getGeneralSettingsCall",()=>tg,"getGlobalLitellmHeaderName",()=>_,"getGuardrailInfo",()=>ne,"getGuardrailProviderSpecificParams",()=>r3,"getGuardrailUISettings",()=>r6,"getGuardrailsList",()=>tM,"getGuardrailsUsageDetail",()=>tH,"getGuardrailsUsageLogs",()=>tD,"getGuardrailsUsageOverview",()=>tL,"getInProductNudgesCall",()=>b,"getInternalUserSettings",()=>rf,"getLicenseInfo",()=>nu,"getMCPOAuthUserCredentialStatus",()=>nq,"getMCPSemanticFilterSettings",()=>tP,"getMajorAirlines",()=>r5,"getModelCostMapReloadStatus",()=>H,"getModelCostMapSource",()=>L,"getOnboardingCredentials",()=>eC,"getOpenAPISchema",()=>R,"getPassThroughEndpointsCall",()=>t$,"getPoliciesList",()=>tV,"getPolicyAttachmentsList",()=>t3,"getPolicyInfo",()=>t6,"getPolicyInfoWithGuardrails",()=>tG,"getPolicyTemplates",()=>tU,"getPossibleUserRoles",()=>e6,"getPromptInfo",()=>rn,"getPromptVersions",()=>ro,"getPromptsList",()=>rr,"getProviderCreateMetadata",()=>O,"getProxyBaseUrl",()=>C,"getProxyUISettings",()=>t_,"getPublicModelHubInfo",()=>N,"getRemainingUsers",()=>nc,"getResolvedGuardrails",()=>t8,"getRouterSettingsCall",()=>tv,"getSSOSettings",()=>ni,"getTeamPermissionsCall",()=>rD,"getToolUsageLogs",()=>nH,"getUISettings",()=>tI,"getUiConfig",()=>P,"getUiSettings",()=>nk,"handleError",()=>j,"individualModelHealthCheckCall",()=>tk,"invitationCreateCall",()=>q,"keyAliasesCall",()=>e2,"keyCreateCall",()=>X,"keyCreateForAgentCall",()=>Y,"keyCreateServiceAccountCall",()=>K,"keyDeleteCall",()=>Q,"keyInfoCall",()=>eZ,"keyInfoV1Call",()=>e0,"keyListCall",()=>e1,"keyUpdateCall",()=>tt,"latestHealthChecksCall",()=>tF,"listGuardrailSubmissions",()=>tB,"listMCPTools",()=>rP,"listMCPUserCredentials",()=>nJ,"listPolicyVersions",()=>t0,"loginCall",()=>nO,"makeAgentsPublicCall",()=>r1,"makeMCPPublicCall",()=>r2,"makeModelGroupPublic",()=>I,"mcpHubPublicServersCall",()=>e_,"modelAvailableCall",()=>eB,"modelCostMap",()=>M,"modelCreateCall",()=>D,"modelDeleteCall",()=>V,"modelHubCall",()=>eI,"modelHubPublicModelsCall",()=>eT,"modelInfoCall",()=>eO,"modelInfoV1Call",()=>ek,"modelPatchUpdateCall",()=>tn,"organizationCreateCall",()=>ed,"organizationDailyActivityCall",()=>eb,"organizationDeleteCall",()=>ep,"organizationInfoCall",()=>eu,"organizationListCall",()=>ec,"organizationMemberAddCall",()=>ts,"organizationMemberDeleteCall",()=>tc,"organizationMemberUpdateCall",()=>tu,"organizationUpdateCall",()=>ef,"patchAgentCall",()=>nt,"perUserAnalyticsCall",()=>nx,"proxyBaseUrl",()=>$,"ragIngestCall",()=>rX,"regenerateKeyCall",()=>eS,"registerClaudeCodePlugin",()=>nP,"registerMCPServer",()=>rE,"registerMcpOAuthClient",()=>nh,"rejectGuardrailSubmission",()=>tz,"rejectMCPServer",()=>rj,"reloadModelCostMap",()=>B,"resetEmailEventSettings",()=>rQ,"resolvePoliciesCall",()=>re,"scheduleModelCostMapReload",()=>A,"searchToolQueryCall",()=>nb,"serverRootPath",()=>w,"serviceHealthCheck",()=>tp,"sessionSpendLogsCall",()=>rW,"setCallbacksCall",()=>tO,"setGlobalLitellmHeaderName",()=>F,"storeMCPOAuthUserCredential",()=>nG,"suggestPolicyTemplates",()=>tJ,"tagCreateCall",()=>rR,"tagDailyActivityCall",()=>ev,"tagDauCall",()=>nw,"tagDeleteCall",()=>rz,"tagDistinctCall",()=>nE,"tagInfoCall",()=>rB,"tagListCall",()=>rA,"tagMauCall",()=>nC,"tagUpdateCall",()=>rM,"tagWauCall",()=>n$,"tagsSpendLogsCall",()=>ez,"teamBulkMemberAddCall",()=>ta,"teamCreateCall",()=>e3,"teamDailyActivityCall",()=>ey,"teamDeleteCall",()=>et,"teamInfoCall",()=>ea,"teamListCall",()=>el,"teamMemberAddCall",()=>to,"teamMemberDeleteCall",()=>tl,"teamMemberUpdateCall",()=>ti,"teamPermissionsUpdateCall",()=>rV,"teamSpendLogsCall",()=>eA,"teamUpdateCall",()=>tr,"testCacheConnectionCall",()=>tb,"testConnectionRequest",()=>eQ,"testCustomCodeGuardrail",()=>no,"testMCPSemanticFilter",()=>tR,"testMCPToolsListRequest",()=>np,"testPipelineCall",()=>t9,"testPoliciesAndGuardrails",()=>tW,"testPolicyTemplate",()=>tK,"testSearchToolConnection",()=>rI,"transformRequestCall",()=>em,"uiAuditLogsCall",()=>ns,"uiSpendLogDetailsCall",()=>rd,"uiSpendLogsCall",()=>eV,"updateCacheSettingsCall",()=>tw,"updateConfigFieldSetting",()=>tS,"updateDefaultTeamSettings",()=>rH,"updateEmailEventSettings",()=>rZ,"updateGuardrailCall",()=>nr,"updateInternalUserSettings",()=>rp,"updateMCPSemanticFilterSettings",()=>tN,"updateMCPServer",()=>r$,"updatePassThroughEndpoint",()=>nd,"updatePolicyCall",()=>tQ,"updatePolicyVersionStatus",()=>t2,"updatePromptCall",()=>ri,"updateSSOSettings",()=>nl,"updateSearchTool",()=>rT,"updateToolPolicy",()=>nV,"updateUiSettings",()=>nT,"updateUsefulLinksCall",()=>eM,"usageAiChatStream",()=>tY,"userAgentSummaryCall",()=>nS,"userBulkUpdateUserCall",()=>tf,"userCreateCall",()=>Z,"userDailyActivityAggregatedCall",()=>e4,"userDailyActivityCall",()=>eg,"userDeleteCall",()=>ee,"userFilterUICall",()=>eD,"userGetInfoV2",()=>en,"userInfoCall",()=>eo,"userListCall",()=>er,"userUpdateUserCall",()=>td,"v2TeamListCall",()=>ei,"validateBlockedWordsFile",()=>na,"vectorStoreCreateCall",()=>rG,"vectorStoreDeleteCall",()=>rq,"vectorStoreInfoCall",()=>rJ,"vectorStoreListCall",()=>rU,"vectorStoreSearchCall",()=>ny,"vectorStoreUpdateCall",()=>rK],764205),e.i(247167);var t=e.i(998573),r=e.i(268004);e.s(["default",()=>h,"jsonFields",()=>p],82946);var n=e.i(843476),o=e.i(271645),a=e.i(808613),i=e.i(311451),l=e.i(28651),s=e.i(199133),c=e.i(779241),u=e.i(827252),d=e.i(592968),f=e.i(122550);let p=["metadata","config","enforced_params","aliases"],m=(e,t)=>p.includes(e)||"json"===t.format,h=({schemaComponent:e,excludedFields:t=[],form:r,overrideLabels:p={},overrideTooltips:h={},customValidation:g={},defaultValues:v={}})=>{let[y,b]=(0,o.useState)(null),[w,$]=(0,o.useState)(null);return((0,o.useEffect)(()=>{(async()=>{try{let n=(await R()).components.schemas[e];if(!n)throw Error(`Schema component "${e}" not found`);b(n);let o={};Object.keys(n.properties).filter(e=>!t.includes(e)&&void 0!==v[e]).forEach(e=>{o[e]=v[e]}),r.setFieldsValue(o)}catch(e){console.error("Schema fetch error:",e),$(e instanceof Error?e.message:"Failed to fetch schema")}})()},[e,r,t]),w)?(0,n.jsxs)("div",{className:"text-red-500",children:["Error: ",w]}):y?.properties?(0,n.jsx)("div",{children:Object.entries(y.properties).filter(([e])=>!t.includes(e)).map(([e,t])=>{let r,o,b,w,$,C,E,S;return o=(e=>{if(e.type)return e.type;if(e.anyOf){let t=e.anyOf.map(e=>e.type);if(t.includes("number")||t.includes("integer"))return"number";t.includes("string")}return"string"})(t),b=y?.required?.includes(e),w=p[e]||t.title||(0,f.formatLabel)(e),$=h[e]||t.description,C=[],b&&C.push({required:!0,message:`${w} is required`}),g[e]&&C.push({validator:g[e]}),m(e,t)&&C.push({validator:async(e,t)=>{if(t&&!(e=>{if(!e)return!0;try{return JSON.parse(e),!0}catch{return!1}})(t))throw Error("Please enter valid JSON")}}),E=$?(0,n.jsxs)("span",{children:[w," ",(0,n.jsx)(d.Tooltip,{title:$,children:(0,n.jsx)(u.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}):w,r=m(e,t)?(0,n.jsx)(i.Input.TextArea,{rows:4,placeholder:"Enter as JSON",className:"font-mono"}):t.enum?(0,n.jsx)(s.Select,{children:t.enum.map(e=>(0,n.jsx)(s.Select.Option,{value:e,children:e},e))}):"number"===o||"integer"===o?(0,n.jsx)(l.InputNumber,{style:{width:"100%"},precision:"integer"===o?0:void 0}):"duration"===e?(0,n.jsx)(c.TextInput,{placeholder:"eg: 30s, 30h, 30d"}):(0,n.jsx)(c.TextInput,{placeholder:$||""}),(0,n.jsx)(a.Form.Item,{label:E,name:e,className:"mt-8",rules:C,initialValue:v[e],help:(0,n.jsx)("div",{className:"text-xs text-gray-500",children:(S=({max_budget:"Enter maximum budget in USD (e.g., 100.50)",budget_duration:"Select a time period for budget reset",tpm_limit:"Enter maximum tokens per minute (whole number)",rpm_limit:"Enter maximum requests per minute (whole number)",duration:"Enter duration (e.g., 30s, 24h, 7d)",metadata:'Enter JSON object with key-value pairs\nExample: {"team": "research", "project": "nlp"}',config:'Enter configuration as JSON object\nExample: {"setting": "value"}',permissions:"Enter comma-separated permission strings",enforced_params:'Enter parameters as JSON object\nExample: {"param": "value"}',blocked:"Enter true/false or specific block conditions",aliases:'Enter aliases as JSON object\nExample: {"alias1": "value1", "alias2": "value2"}',models:"Select one or more model names",key_alias:"Enter a unique identifier for this key",tags:"Enter comma-separated tag strings"})[e]||({string:"Text input",number:"Numeric input",integer:"Whole number input",boolean:"True/False value"})[o]||"Text input",m(e,t)?`${S} Must be valid JSON format`:t.enum?`Select from available options -Allowed values: ${t.enum.join(", ")}`:S)}),children:r},e)})}):null};var g=e.i(727749);let v=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${n}`},y=async e=>{try{let t=$?`${$}/callbacks/configs`:"/callbacks/configs",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},b=async e=>{try{let t=$?`${$}/in_product_nudges`:"/in_product_nudges",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get in-product nudges:",e),e}},w="/",$=null;console.log=function(){};let C=()=>{if($)return $;let e=window.location;return e?.origin??""},E="POST",S="DELETE",x=0,j=async e=>{let t=Date.now();if(t-x>6e4){if(("string"==typeof e?e:JSON.stringify(e)).includes("Authentication Error - Expired Key")){g.default.info("UI Session Expired. Logging out."),x=t,(0,r.clearTokenCookies)();let e=window.location;e&&(window.location.href=e.pathname)}x=t}else console.log("Error suppressed to prevent spam:",e)},O=async()=>{let e=$?`${$}/public/providers/fields`:"/public/providers/fields",t=await fetch(e,{method:"GET"});if(!t.ok){let e=await t.text();throw console.error("Failed to fetch provider create metadata:",t.status,e),Error("Failed to load provider configuration")}return await t.json()},k=async()=>{let e=$?`${$}/public/agents/fields`:"/public/agents/fields",t=await fetch(e,{method:"GET"});if(!t.ok){let e=await t.text();throw console.error("Failed to fetch agent create metadata:",t.status,e),Error("Failed to load agent configuration")}return await t.json()},T="Authorization";function F(e="Authorization"){console.log(`setGlobalLitellmHeaderName: ${e}`),T=e}function _(){return T}let I=async(e,t)=>{let r=$?`${$}/model_group/make_public`:"/model_group/make_public";return(await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({model_groups:t})})).json()},P=async()=>{console.log("Getting UI config");let e=await fetch("/litellm/.well-known/litellm-ui-config"),t=await e.json();return console.log("jsonData in getUiConfig:",t),((e,t=null)=>{let r=window.location,n=r?.origin??null,o=t||n;if(console.log("proxyBaseUrl:",$),console.log("serverRootPath:",e),!o)return console.log("Updated proxyBaseUrl:",$=$??null);e.length>0&&!o.endsWith(e)&&"/"!=e&&(o+=e),console.log("Updated proxyBaseUrl:",$=o)})(t.server_root_path,t.proxy_base_url),t},N=async()=>{let e=$?`${$}/public/model_hub/info`:"/public/model_hub/info",t=await fetch(e);return await t.json()},R=async()=>{let e=$?`${$}/openapi.json`:"/openapi.json",t=await fetch(e);return await t.json()},M=async()=>{try{let e=$?`${$}/public/litellm_model_cost_map`:"/public/litellm_model_cost_map",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}}),r=await t.json();return console.log(`received litellm model cost data: ${r}`),r}catch(e){throw console.error("Failed to get model cost map:",e),e}},B=async e=>{try{let t=$?`${$}/reload/model_cost_map`:"/reload/model_cost_map",r=await fetch(t,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}}),n=await r.json();return console.log(`Model cost map reload response: ${n}`),n}catch(e){throw console.error("Failed to reload model cost map:",e),e}},A=async(e,t)=>{try{let r=$?`${$}/schedule/model_cost_map_reload?hours=${t}`:`/schedule/model_cost_map_reload?hours=${t}`,n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}}),o=await n.json();return console.log(`Schedule model cost map reload response: ${o}`),o}catch(e){throw console.error("Failed to schedule model cost map reload:",e),e}},z=async e=>{try{let t=$?`${$}/schedule/model_cost_map_reload`:"/schedule/model_cost_map_reload",r=await fetch(t,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}}),n=await r.json();return console.log(`Cancel model cost map reload response: ${n}`),n}catch(e){throw console.error("Failed to cancel model cost map reload:",e),e}},L=async e=>{try{let t=$?`${$}/model/cost_map/source`:"/model/cost_map/source",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw Error(`HTTP ${r.status}: ${e}`)}let n=await r.json();return console.log("Model cost map source info:",n),n}catch(e){throw console.error("Failed to get model cost map source info:",e),e}},H=async e=>{try{let t=$?`${$}/schedule/model_cost_map_reload/status`:"/schedule/model_cost_map_reload/status";console.log("Fetching status from URL:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){console.error(`Status request failed with status: ${r.status}`);let e=await r.text();throw console.error("Error response:",e),Error(`HTTP ${r.status}: ${e}`)}let n=await r.json();return console.log("Model cost map reload status:",n),n}catch(e){throw console.error("Failed to get model cost map reload status:",e),e}},D=async(e,r)=>{try{let n=$?`${$}/model/new`:"/model/new",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),t.message.destroy(),g.default.success(`Model ${r.model_name} created successfully`),a}catch(e){throw console.error("Failed to create key:",e),e}},V=async(e,t)=>{console.log(`model_id in model delete call: ${t}`);try{let r=$?`${$}/model/delete`:"/model/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({id:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},W=async(e,t)=>{if(console.log(`budget_id in budget delete call: ${t}`),null!=e)try{let r=$?`${$}/budget/delete`:"/budget/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({id:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},G=async(e,t)=>{try{console.log("Form Values in budgetCreateCall:",t),console.log("Form Values after check:",t);let r=$?`${$}/budget/new`:"/budget/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},U=async(e,t)=>{try{console.log("Form Values in budgetUpdateCall:",t),console.log("Form Values after check:",t);let r=$?`${$}/budget/update`:"/budget/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},q=async(e,t)=>{try{let r=$?`${$}/invitation/new`:"/invitation/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_id:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},J=async e=>{try{let t=$?`${$}/alerting/settings`:"/alerting/settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},K=async(e,t)=>{try{for(let e of(console.log("Form Values in keyCreateServiceAccountCall:",t),t.description&&(t.metadata||(t.metadata={}),t.metadata.description=t.description,delete t.description,t.metadata=JSON.stringify(t.metadata)),p))if(t[e]){console.log(`formValues.${e}:`,t[e]);try{t[e]=JSON.parse(t[e])}catch(t){throw Error(`Failed to parse ${e}: `+t)}}console.log("Form Values after check:",t);let r=$?`${$}/key/service-account/generate`:"/key/service-account/generate",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},X=async(e,t,r)=>{try{for(let e of(console.log("Form Values in keyCreateCall:",r),r.description&&(r.metadata||(r.metadata={}),r.metadata.description=r.description,delete r.description,r.metadata=JSON.stringify(r.metadata)),p))if(r[e]){console.log(`formValues.${e}:`,r[e]);try{r[e]=JSON.parse(r[e])}catch(t){throw Error(`Failed to parse ${e}: `+t)}}console.log("Form Values after check:",r);let n=$?`${$}/key/generate`:"/key/generate",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...r})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},Y=async(e,t,r,n,o,a)=>{let i=$?`${$}/key/generate`:"/key/generate",l={agent_id:t,key_alias:r,models:n.length>0?n:[]};a&&(l.team_id=a),o&&Object.keys(o).length>0&&(l.metadata=o);let s=await fetch(i,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(l)});if(!s.ok)throw j(await s.text()),Error("Failed to create key for agent");return s.json()},Z=async(e,t,r)=>{try{if(console.log("Form Values in keyCreateCall:",r),r.description&&(r.metadata||(r.metadata={}),r.metadata.description=r.description,delete r.description,r.metadata=JSON.stringify(r.metadata)),r.auto_create_key=!1,r.metadata){console.log("formValues.metadata:",r.metadata);try{r.metadata=JSON.parse(r.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}console.log("Form Values after check:",r);let n=$?`${$}/user/new`:"/user/new",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...r})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},Q=async(e,t)=>{try{let r=$?`${$}/key/delete`:"/key/delete";console.log("in keyDeleteCall:",t);let n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({keys:[t]})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to create key:",e),e}},ee=async(e,t)=>{try{let r=$?`${$}/user/delete`:"/user/delete";console.log("in userDeleteCall:",t);let n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_ids:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to delete user(s):",e),e}},et=async(e,t)=>{try{let r=$?`${$}/team/delete`:"/team/delete";console.log("in teamDeleteCall:",t);let n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({team_ids:[t]})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to delete key:",e),e}},er=async(e,t=null,r=null,n=null,o=null,a=null,i=null,l=null,s=null,c=null,u=null)=>{try{let d=$?`${$}/user/list`:"/user/list";console.log("in userListCall");let f=new URLSearchParams;if(t&&t.length>0){let e=t.join(",");f.append("user_ids",e)}r&&f.append("page",r.toString()),n&&f.append("page_size",n.toString()),o&&f.append("user_email",o),a&&f.append("role",a),i&&f.append("team",i),l&&f.append("sso_user_ids",l),s&&f.append("sort_by",s),c&&f.append("sort_order",c),u&&u.length>0&&f.append("organization_ids",u.join(","));let p=f.toString();p&&(d+=`?${p}`);let m=await fetch(d,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!m.ok){let e=await m.json(),t=nx(e);throw j(t),Error(t)}let h=await m.json();return console.log("/user/list API Response:",h),h}catch(e){throw console.error("Failed to create key:",e),e}},en=async(e,t,r,n=!1,o,a,i=!1)=>{console.log(`userInfoCall: ${t}, ${r}, ${n}, ${o}, ${a}, ${i}`);try{let l;if(n){l=$?`${$}/user/list`:"/user/list";let e=new URLSearchParams;null!=o&&e.append("page",o.toString()),null!=a&&e.append("page_size",a.toString()),l+=`?${e.toString()}`}else l=$?`${$}/user/info`:"/user/info",("Admin"!==r&&"Admin Viewer"!==r||i)&&t&&(l+=`?user_id=${t}`);console.log("Requesting user data from:",l);let s=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nx(e);throw j(t),Error(t)}let c=await s.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to fetch user data:",e),e}},eo=async(e,t)=>{try{let r=$?`${$}/team/info`:"/team/info";t&&(r=`${r}?team_id=${t}`),console.log("in teamInfoCall");let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ea=async(e,t,r=null,n=null,o=null,a=1,i=10,l=null,s=null)=>{try{let a=$?`${$}/v2/team/list`:"/v2/team/list";console.log("in teamInfoCall");let i=new URLSearchParams;r&&i.append("user_id",r.toString()),t&&i.append("organization_id",t.toString()),n&&i.append("team_id",n.toString()),o&&i.append("team_alias",o.toString());let l=i.toString();l&&(a+=`?${l}`);let s=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nx(e);throw j(t),Error(t)}let c=await s.json();return console.log("/v2/team/list API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},ei=async(e,t,r=null,n=null,o=null)=>{try{let a=$?`${$}/team/list`:"/team/list";console.log("in teamInfoCall");let i=new URLSearchParams;r&&i.append("user_id",r.toString()),t&&i.append("organization_id",t.toString()),n&&i.append("team_id",n.toString()),o&&i.append("team_alias",o.toString());let l=i.toString();l&&(a+=`?${l}`);let s=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nx(e);throw j(t),Error(t)}let c=await s.json();return console.log("/team/list API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},el=async e=>{try{let t=$?`${$}/team/available`:"/team/available";console.log("in availableTeamListCall");let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("/team/available_teams API Response:",n),n}catch(e){throw e}},es=async(e,t=null,r=null)=>{try{let n=$?`${$}/organization/list`:"/organization/list",o=new URLSearchParams;t&&o.append("org_id",t.toString()),r&&o.append("org_alias",r.toString());let a=o.toString();a&&(n+=`?${a}`);let i=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nx(e);throw j(t),Error(t)}return await i.json()}catch(e){throw console.error("Failed to create key:",e),e}},ec=async(e,t)=>{try{let r=$?`${$}/organization/info`:"/organization/info";t&&(r=`${r}?organization_id=${t}`),console.log("in teamInfoCall");let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},eu=async(e,t)=>{try{if(console.log("Form Values in organizationCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw console.error("Failed to parse metadata:",e),Error("Failed to parse metadata: "+e)}}let r=$?`${$}/organization/new`:"/organization/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ed=async(e,t)=>{try{console.log("Form Values in organizationUpdateCall:",t);let r=$?`${$}/organization/update`:"/organization/update",n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Update Team Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ef=async(e,t)=>{try{let r=$?`${$}/organization/delete`:"/organization/delete",n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_ids:[t]})});if(!n.ok){let e=await n.text();throw j(e),Error(`Error deleting organization: ${e}`)}return await n.json()}catch(e){throw console.error("Failed to delete organization:",e),e}},ep=async(e,t)=>{try{let r=$?`${$}/utils/transform_request`:"/utils/transform_request",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create key:",e),e}},em=async({accessToken:e,endpoint:t,startTime:r,endTime:n,page:o=1,extraQueryParams:a})=>{try{let i,l,s,c,u=(i=t.startsWith("/")?t:`/${t}`,l=$?`${$}${i}`:i,(s=new URLSearchParams).append("start_date",v(r)),s.append("end_date",v(n)),s.append("page_size","1000"),s.append("page",o.toString()),s.append("timezone",new Date().getTimezoneOffset().toString()),a&&Object.entries(a).forEach(([e,t])=>{((e,t,r)=>{if(null!=r){if(Array.isArray(r)){r.length>0&&e.append(t,r.join(","));return}e.append(t,`${r}`)}})(s,e,t)}),(c=s.toString())?`${l}?${c}`:l),d=await fetch(u,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!d.ok){let e=await d.json(),t=nx(e);throw j(t),Error(t)}return await d.json()}catch(e){throw console.error(`Failed to fetch daily activity (${t}):`,e),e}},eh=async(e,t,r,n=1,o=null)=>em({accessToken:e,endpoint:"/user/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{user_id:o}}),eg=async(e,t,r,n=1,o=null)=>em({accessToken:e,endpoint:"/tag/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{tags:o}}),ev=async(e,t,r,n=1,o=null)=>em({accessToken:e,endpoint:"/team/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{team_ids:o,exclude_team_ids:"litellm-dashboard"}}),ey=async(e,t,r,n=1,o=null)=>em({accessToken:e,endpoint:"/organization/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{organization_ids:o}}),eb=async(e,t,r,n=1,o=null)=>em({accessToken:e,endpoint:"/customer/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{end_user_ids:o}}),ew=async(e,t,r,n=1,o=null)=>em({accessToken:e,endpoint:"/agent/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{agent_ids:o}}),e$=async e=>{try{let t=$?`${$}/onboarding/get_token`:"/onboarding/get_token";t+=`?invite_link=${e}`;let r=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to create key:",e),e}},eC=async(e,t,r,n)=>{let o=$?`${$}/onboarding/claim_token`:"/onboarding/claim_token";try{let a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({invitation_link:t,user_id:r,password:n})});if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to delete key:",e),e}},eE=async(e,t,r)=>{try{let n=$?`${$}/key/${t}/regenerate`:`/key/${t}/regenerate`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("Regenerate key Response:",a),a}catch(e){throw console.error("Failed to regenerate key:",e),e}},eS=!1,ex=null,ej=async(e,t,r,n=1,o=50,a,i,l,s,c)=>{try{console.log("modelInfoCall:",e,t,r,n,o,a,i,l,s,c);let u=$?`${$}/v2/model/info`:"/v2/model/info",d=new URLSearchParams;d.append("include_team_models","true"),d.append("page",n.toString()),d.append("size",o.toString()),a&&a.trim()&&d.append("search",a.trim()),i&&i.trim()&&d.append("modelId",i.trim()),l&&l.trim()&&d.append("teamId",l.trim()),s&&s.trim()&&d.append("sortBy",s.trim()),c&&c.trim()&&d.append("sortOrder",c.trim()),d.toString()&&(u+=`?${d.toString()}`);let f=await fetch(u,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!f.ok){let e=await f.text();throw e+=`error shown=${eS}`,eS||(e.includes("No model list passed")&&(e="No Models Exist. Click Add Model to get started."),g.default.info(e),eS=!0,ex&&clearTimeout(ex),ex=setTimeout(()=>{eS=!1},1e4)),Error("Network response was not ok")}let p=await f.json();return console.log("modelInfoCall:",p),p}catch(e){throw console.error("Failed to create key:",e),e}},eO=async(e,t)=>{try{let r=$?`${$}/v1/model/info`:"/v1/model/info";r+=`?litellm_model_id=${t}`;let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("modelInfoV1Call:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ek=async()=>{let e=$?`${$}/public/model_hub`:"/public/model_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`modelHubPublicModelsCall failed with status ${t.status}`),[])},eT=async()=>{let e=$?`${$}/public/agent_hub`:"/public/agent_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`agentHubPublicModelsCall failed with status ${t.status}`),[])},eF=async()=>{let e=$?`${$}/public/mcp_hub`:"/public/mcp_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`mcpHubPublicServersCall failed with status ${t.status}`),[])},e_=async e=>{try{let t=$?`${$}/model_group/info`:"/model_group/info",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("modelHubCall:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},eI=async e=>{try{let t=$?`${$}/get/allowed_ips`:"/get/allowed_ips",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("getAllowedIPs:",n),n.data}catch(e){throw console.error("Failed to get allowed IPs:",e),e}},eP=async(e,t)=>{try{let r=$?`${$}/add/allowed_ip`:"/add/allowed_ip",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({ip:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("addAllowedIP:",o),o}catch(e){throw console.error("Failed to add allowed IP:",e),e}},eN=async(e,t)=>{try{let r=$?`${$}/delete/allowed_ip`:"/delete/allowed_ip",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({ip:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("deleteAllowedIP:",o),o}catch(e){throw console.error("Failed to delete allowed IP:",e),e}},eR=async(e,t)=>{try{let r=$?`${$}/model_hub/update_useful_links`:"/model_hub/update_useful_links",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({useful_links:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create key:",e),e}},eM=async(e,t,r,n=!1,o=null,a=!1,i=!1,l)=>{console.log("in /models calls, globalLitellmHeaderName",T);try{let t=$?`${$}/models`:"/models",r=new URLSearchParams;r.append("include_model_access_groups","True"),!0===n&&r.append("return_wildcard_routes","True"),!0===i&&r.append("only_model_access_groups","True"),o&&r.append("team_id",o.toString()),l&&r.append("scope",l),r.toString()&&(t+=`?${r.toString()}`);let a=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}return await a.json()}catch(e){throw console.error("Failed to create key:",e),e}},eB=async e=>{try{let t=$?`${$}/global/spend/teams`:"/global/spend/teams";console.log("in teamSpendLogsCall:",t);let r=await fetch(`${t}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eA=async(e,t,r,n)=>{try{let o=$?`${$}/global/spend/tags`:"/global/spend/tags";t&&r&&(o=`${o}?start_date=${t}&end_date=${r}`),n&&(o+=`&tags=${n.join(",")}`),console.log("in tagsSpendLogsCall:",o);let a=await fetch(`${o}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to create key:",e),e}},ez=async e=>{try{let t=$?`${$}/global/spend/all_tag_names`:"/global/spend/all_tag_names";console.log("in global/spend/all_tag_names call",t);let r=await fetch(`${t}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eL=async e=>{try{let t=$?`${$}/customer/list`:"/customer/list";console.log("in customer/list",t);let r=await fetch(`${t}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to fetch end users:",e),e}},eH=async(e,t)=>{try{let r=$?`${$}/user/filter/ui`:"/user/filter/ui",n=new URLSearchParams;t.get("user_email")&&n.append("user_email",t.get("user_email")),t.get("user_id")&&n.append("user_id",t.get("user_id")),t.get("team_id")&&n.append("team_id",t.get("team_id"));let o=n.toString(),a=o?`${r}?${o}`:r,i=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nx(e);throw j(t),Error(t)}return await i.json()}catch(e){throw console.error("Failed to create key:",e),e}},eD=async({accessToken:e,start_date:t,end_date:r,page:n=1,page_size:o=50,params:a={}})=>{try{let i=$?`${$}/spend/logs/ui`:"/spend/logs/ui",l=new URLSearchParams;for(let[e,i]of(l.append("start_date",t),l.append("end_date",r),l.append("page",n.toString()),l.append("page_size",o.toString()),Object.entries(a)))null!=i&&("min_spend"===e||"max_spend"===e?l.append(e,i.toString()):"string"==typeof i&&""!==i&&l.append(e,String(i)));let s=l.toString();s&&(i+=`?${s}`);let c=await fetch(i,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!c.ok){let e=await c.json(),t=nx(e);throw j(t),Error(t)}let u=await c.json();return console.log("Spend Logs Response:",u),u}catch(e){throw console.error("Failed to fetch spend logs:",e),e}},eV=async e=>{try{let t=$?`${$}/global/spend/logs`:"/global/spend/logs",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eW=async e=>{try{let t=$?`${$}/global/spend/keys?limit=5`:"/global/spend/keys?limit=5",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eG=async(e,t,r,n)=>{try{let o=$?`${$}/global/spend/end_users`:"/global/spend/end_users",a="";a=t?JSON.stringify({api_key:t,startTime:r,endTime:n}):JSON.stringify({startTime:r,endTime:n});let i={method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:a},l=await fetch(o,i);if(!l.ok){let e=await l.json(),t=nx(e);throw j(t),Error(t)}let s=await l.json();return console.log(s),s}catch(e){throw console.error("Failed to create key:",e),e}},eU=async(e,t,r,n)=>{try{let o=$?`${$}/global/spend/provider`:"/global/spend/provider";r&&n&&(o+=`?start_date=${r}&end_date=${n}`),t&&(o+=`&api_key=${t}`);let a={method:"GET",headers:{[T]:`Bearer ${e}`}},i=await fetch(o,a);if(!i.ok){let e=await i.json(),t=nx(e);throw j(t),Error(t)}let l=await i.json();return console.log(l),l}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eq=async(e,t,r)=>{try{let n=$?`${$}/global/activity`:"/global/activity";t&&r&&(n+=`?start_date=${t}&end_date=${r}`);let o={method:"GET",headers:{[T]:`Bearer ${e}`}},a=await fetch(n,o);if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eJ=async(e,t,r)=>{try{let n=$?`${$}/global/activity/cache_hits`:"/global/activity/cache_hits";t&&r&&(n+=`?start_date=${t}&end_date=${r}`);let o={method:"GET",headers:{[T]:`Bearer ${e}`}},a=await fetch(n,o);if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eK=async(e,t,r)=>{try{let n=$?`${$}/global/activity/model`:"/global/activity/model";t&&r&&(n+=`?start_date=${t}&end_date=${r}`);let o={method:"GET",headers:{[T]:`Bearer ${e}`}},a=await fetch(n,o);if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eX=async e=>{try{let t=$?`${$}/global/spend/models?limit=5`:"/global/spend/models?limit=5",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eY=async(e,t)=>{try{let r=$?`${$}/v2/key/info`:"/v2/key/info",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({keys:t})});if(!n.ok){let e=await n.text();if(e.includes("Invalid proxy server token passed"))throw Error("Invalid proxy server token passed");throw j(e),Error("Network response was not ok")}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to create key:",e),e}},eZ=async(e,t,r,n)=>{try{console.log("Sending model connection test request:",JSON.stringify(t));let o=$?`${$}/health/test_connection`:"/health/test_connection",a=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({litellm_params:t,model_info:r,mode:n})}),i=a.headers.get("content-type");if(!i||!i.includes("application/json")){let e=await a.text();throw console.error("Received non-JSON response:",e),Error(`Received non-JSON response (${a.status}: ${a.statusText}). Check network tab for details.`)}let l=await a.json();if((!a.ok||"error"===l.status)&&"error"!==l.status)return{status:"error",message:l.error?.message||`Connection test failed: ${a.status} ${a.statusText}`};return l}catch(e){throw console.error("Model connection test error:",e),e}},eQ=async(e,t)=>{try{console.log("entering keyInfoV1Call");let r=$?`${$}/key/info`:"/key/info";r=`${r}?key=${t}`;let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(console.log("response",n),!n.ok){let e=await n.text();j(e),g.default.fromBackend("Failed to fetch key info - "+e)}let o=await n.json();return console.log("data",o),o}catch(e){throw console.error("Failed to fetch key info:",e),e}},e0=async(e,t,r,n,o,a,i,l,s=null,c=null,u=null,d=null)=>{try{let f=$?`${$}/key/list`:"/key/list";console.log("in keyListCall");let p=new URLSearchParams;r&&p.append("team_id",r.toString()),t&&p.append("organization_id",t.toString()),n&&p.append("key_alias",n),a&&p.append("key_hash",a),o&&p.append("user_id",o.toString()),i&&p.append("page",i.toString()),l&&p.append("size",l.toString()),s&&p.append("sort_by",s),c&&p.append("sort_order",c),u&&p.append("expand",u),d&&p.append("status",d),p.append("return_full_object","true"),p.append("include_team_keys","true"),p.append("include_created_by_keys","true");let m=p.toString();m&&(f+=`?${m}`);let h=await fetch(f,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!h.ok){let e=await h.json(),t=nx(e);throw j(t),Error(t)}let g=await h.json();return console.log("/team/list API Response:",g),g}catch(e){throw console.error("Failed to create key:",e),e}},e1=async(e,t=1,r=50,n)=>{try{let o=new URLSearchParams(Object.entries({page:String(t),size:String(r),...n?{search:n}:{}})),a=$?`${$}/key/aliases`:"/key/aliases";a=`${a}?${o}`;let i=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nx(e);throw j(t),Error(t)}let l=await i.json();return console.log("/key/aliases API Response:",l),l}catch(e){throw console.error("Failed to fetch key aliases:",e),e}},e2=async(e,t,r,n=null)=>{try{let o=$?`${$}/user/daily/activity/aggregated`:"/user/daily/activity/aggregated",a=new URLSearchParams,i=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${n}`};a.append("start_date",i(t)),a.append("end_date",i(r)),a.append("timezone",new Date().getTimezoneOffset().toString()),n&&a.append("user_id",n);let l=a.toString();l&&(o+=`?${l}`);let s=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nx(e);throw j(t),Error(t)}return await s.json()}catch(e){throw console.error("Failed to fetch aggregated user daily activity:",e),e}},e4=async e=>{try{let t=$?`${$}/user/available_roles`:"/user/available_roles",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("response from user/available_role",n),n}catch(e){throw e}},e6=async(e,t)=>{try{if(console.log("Form Values in teamCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let r=$?`${$}/team/new`:"/team/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},e3=async(e,t)=>{try{if(console.log("Form Values in credentialCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let r=$?`${$}/credentials`:"/credentials",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},e7=async e=>{try{let t=$?`${$}/credentials`:"/credentials";console.log("in credentialListCall");let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("/credentials API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},e5=async(e,t,r)=>{try{let n=$?`${$}/credentials`:"/credentials";t?n+=`/by_name/${t}`:r&&(n+=`/by_model/${r}`),console.log("in credentialListCall");let o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("/credentials API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},e9=async(e,t)=>{try{let r=$?`${$}/credentials/${t}`:`/credentials/${t}`;console.log("in credentialDeleteCall:",t);let n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to delete key:",e),e}},e8=async(e,t,r)=>{try{if(console.log("Form Values in credentialUpdateCall:",r),r.metadata){console.log("formValues.metadata:",r.metadata);try{r.metadata=JSON.parse(r.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let n=$?`${$}/credentials/${t}`:`/credentials/${t}`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},te=async(e,t)=>{try{if(console.log("Form Values in keyUpdateCall:",t),t.model_tpm_limit){console.log("formValues.model_tpm_limit:",t.model_tpm_limit);try{t.model_tpm_limit=JSON.parse(t.model_tpm_limit)}catch(e){throw Error("Failed to parse model_tpm_limit: "+e)}}if(t.model_rpm_limit){console.log("formValues.model_rpm_limit:",t.model_rpm_limit);try{t.model_rpm_limit=JSON.parse(t.model_rpm_limit)}catch(e){throw Error("Failed to parse model_rpm_limit: "+e)}}let r=$?`${$}/key/update`:"/key/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let o=await n.json();return console.log("Update key Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},tt=async(e,t)=>{try{console.log("Form Values in teamUpateCall:",t);let r=$?`${$}/team/update`:"/team/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),console.error("Error response from the server:",e),g.default.fromBackend("Failed to update team settings: "+e),Error(e)}let o=await n.json();return console.log("Update Team Response:",o),o}catch(e){throw console.error("Failed to update team:",e),e}},tr=async(e,t,r)=>{try{console.log("Form Values in modelUpateCall:",t);let n=$?`${$}/model/${r}/update`:`/model/${r}/update`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error update from the server:",e),Error("Network response was not ok")}let a=await o.json();return console.log("Update model Response:",a),a}catch(e){throw console.error("Failed to update model:",e),e}},tn=async(e,t,r)=>{try{console.log("Form Values in teamMemberAddCall:",r);let n=$?`${$}/team/member_add`:"/team/member_add",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({team_id:t,member:r})});if(!o.ok){let e=await o.text(),t={};try{t=JSON.parse(e)}catch(t){console.warn("Failed to parse error body as JSON:",e)}let r=t?.detail?.error||"Failed to add team member",n=Error(r);throw n.raw=t,n}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},to=async(e,t,r,n,o)=>{try{console.log("Bulk add team members:",{teamId:t,members:r,maxBudgetInTeam:n});let a=$?`${$}/team/bulk_member_add`:"/team/bulk_member_add",i={team_id:t};o?i.all_users=!0:i.members=r,null!=n&&(i.max_budget_in_team=n);let l=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!l.ok){let e=await l.text(),t={};try{t=JSON.parse(e)}catch(t){console.warn("Failed to parse error body as JSON:",e)}let r=t?.detail?.error||"Failed to bulk add team members",n=Error(r);throw n.raw=t,n}let s=await l.json();return console.log("Bulk team member add API Response:",s),s}catch(e){throw console.error("Failed to bulk add team members:",e),e}},ta=async(e,t,r)=>{try{console.log("Form Values in teamMemberUpdateCall:",r),console.log("Budget value:",r.max_budget_in_team),console.log("TPM limit:",r.tpm_limit),console.log("RPM limit:",r.rpm_limit);let n=$?`${$}/team/member_update`:"/team/member_update",o={team_id:t,role:r.role,user_id:r.user_id};void 0!==r.user_email&&(o.user_email=r.user_email),void 0!==r.max_budget_in_team&&null!==r.max_budget_in_team&&(o.max_budget_in_team=r.max_budget_in_team),void 0!==r.tpm_limit&&null!==r.tpm_limit&&(o.tpm_limit=r.tpm_limit),void 0!==r.rpm_limit&&null!==r.rpm_limit&&(o.rpm_limit=r.rpm_limit),console.log("Final request body:",o);let a=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(o)});if(!a.ok){let e=await a.text(),t={};try{t=JSON.parse(e)}catch(t){console.warn("Failed to parse error body as JSON:",e)}let r=t?.detail?.error||"Failed to add team member",n=Error(r);throw n.raw=t,n}let i=await a.json();return console.log("API Response:",i),i}catch(e){throw console.error("Failed to update team member:",e),e}},ti=async(e,t,r)=>{try{console.log("Form Values in teamMemberAddCall:",r);let n=$?`${$}/team/member_delete`:"/team/member_delete",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({team_id:t,...void 0!==r.user_email&&{user_email:r.user_email},...void 0!==r.user_id&&{user_id:r.user_id}})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},tl=async(e,t,r)=>{try{console.log("Form Values in teamMemberAddCall:",r);let n=$?`${$}/organization/member_add`:"/organization/member_add",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,member:r})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create organization member:",e),e}},ts=async(e,t,r)=>{try{console.log("Form Values in organizationMemberDeleteCall:",r);let n=$?`${$}/organization/member_delete`:"/organization/member_delete",o=await fetch(n,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,user_id:r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to delete organization member:",e),e}},tc=async(e,t,r)=>{try{console.log("Form Values in organizationMemberUpdateCall:",r);let n=$?`${$}/organization/member_update`:"/organization/member_update",o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,...r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to update organization member:",e),e}},tu=async(e,t,r)=>{try{console.log("Form Values in userUpdateUserCall:",t);let n=$?`${$}/user/update`:"/user/update",o={...t};null!==r&&(o.user_role=r),o=JSON.stringify(o);let a=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:o});if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}let i=await a.json();return console.log("API Response:",i),i}catch(e){throw console.error("Failed to create key:",e),e}},td=async(e,t,r,n=!1)=>{try{let o;console.log("Form Values in userUpdateUserCall:",t);let a=$?`${$}/user/bulk_update`:"/user/bulk_update";if(n)o=JSON.stringify({all_users:!0,user_updates:t});else if(r&&r.length>0){let e=[];for(let n of r)e.push({user_id:n,...t});o=JSON.stringify({users:e})}else throw Error("Must provide either userIds or set allUsers=true");let i=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:o});if(!i.ok){let e=await i.json(),t=nx(e);throw j(t),Error(t)}let l=await i.json();return console.log("API Response:",l),l}catch(e){throw console.error("Failed to create key:",e),e}},tf=async(e,t)=>{try{let r=$?`${$}/health/services?service=${t}`:`/health/services?service=${t}`;console.log("Checking Slack Budget Alerts service health");let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error(e)}return await n.json()}catch(e){throw console.error("Failed to perform health check:",e),e}},tp=async e=>{try{let t=$?`${$}/budget/list`:"/budget/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tm=async(e,t,r)=>{try{let t=$?`${$}/get/config/callbacks`:"/get/config/callbacks",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},th=async e=>{try{let t=$?`${$}/config/list?config_type=general_settings`:"/config/list?config_type=general_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tg=async e=>{try{let t=$?`${$}/router/settings`:"/router/settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get router settings:",e),e}},tv=async e=>{try{let t=$?`${$}/cache/settings`:"/cache/settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get cache settings:",e),e}},ty=async(e,t)=>{try{let r=$?`${$}/cache/settings/test`:"/cache/settings/test",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({cache_settings:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to test cache connection:",e),e}},tb=async(e,t)=>{try{let r=$?`${$}/cache/settings`:"/cache/settings",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({cache_settings:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to update cache settings:",e),e}},tw=async(e,t)=>{try{let r=$?`${$}/config/pass_through_endpoint`:"/config/pass_through_endpoint";t&&(r+=`/team/${t}`);let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},t$=async(e,t)=>{try{let r=$?`${$}/config/field/info?field_name=${t}`:`/config/field/info?field_name=${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},tC=async(e,t)=>{try{let r=$?`${$}/config/pass_through_endpoint`:"/config/pass_through_endpoint",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},tE=async(e,t,r)=>{try{let n=$?`${$}/config/field/update`:"/config/field/update",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({field_name:t,field_value:r,config_type:"general_settings"})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return g.default.success("Successfully updated value!"),a}catch(e){throw console.error("Failed to set callbacks:",e),e}},tS=async(e,t)=>{try{let r=$?`${$}/config/field/delete`:"/config/field/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({field_name:t,config_type:"general_settings"})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return g.default.success("Field reset on proxy"),o}catch(e){throw console.error("Failed to get callbacks:",e),e}},tx=async(e,t)=>{try{let r=$?`${$}/config/pass_through_endpoint?endpoint_id=${t}`:`/config/pass_through_endpoint?endpoint_id=${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tj=async(e,t)=>{try{let r=$?`${$}/config/update`:"/config/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},tO=async(e,t)=>{try{let r=$?`${$}/health?model_id=${encodeURIComponent(t)}`:`/health?model_id=${encodeURIComponent(t)}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error(`Failed to call /health for model id ${t}:`,e),e}},tk=async e=>{try{let t=$?`${$}/cache/ping`:"/cache/ping",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error(e)}return await r.json()}catch(e){throw console.error("Failed to call /cache/ping:",e),e}},tT=async e=>{try{let t=$?`${$}/health/latest`:"/health/latest",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error(e)}return await r.json()}catch(e){throw console.error("Failed to call /health/latest:",e),e}},tF=async e=>{try{console.log("Getting proxy UI settings"),console.log("proxyBaseUrl in getProxyUISettings:",$);let t=$?`${$}/sso/get/ui_settings`:"/sso/get/ui_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},t_=async e=>{try{let t=$?`${$}/get/ui_settings`:"/get/ui_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);return console.error("Failed to get UI settings:",t),null}return await r.json()}catch(e){return console.error("Failed to get UI settings:",e),null}},tI=async e=>{try{let t=$?`${$}/get/mcp_semantic_filter_settings`:"/get/mcp_semantic_filter_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get MCP semantic filter settings:",e),e}},tP=async(e,t)=>{try{let r=$?`${$}/update/mcp_semantic_filter_settings`:"/update/mcp_semantic_filter_settings",n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to update MCP semantic filter settings:",e),e}},tN=async(e,t,r)=>{try{let n=$?`${$}/v1/responses`:"/v1/responses",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({model:t,input:[{role:"user",content:r,type:"message"}],tools:[{type:"mcp",server_url:"litellm_proxy",require_approval:"never"}],tool_choice:"required"})}),a=o.headers.get("x-litellm-semantic-filter"),i=o.headers.get("x-litellm-semantic-filter-tools");if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return{data:await o.json(),headers:{filter:a,tools:i}}}catch(e){throw console.error("Failed to test MCP semantic filter:",e),e}},tR=async e=>{try{let t=$?`${$}/v2/guardrails/list`:"/v2/guardrails/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok)throw Error(`v2 guardrails/list returned ${r.status}`);return await r.json()}catch(t){console.log("v2/guardrails/list failed, falling back to v1:",t);try{let t=$?`${$}/guardrails/list`:"/guardrails/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get guardrails list:",e),e}}},tM=async(e,t)=>{let r=$?`${$}/guardrails/submissions`:"/guardrails/submissions",n=new URLSearchParams;t?.status&&n.set("status",t.status),t?.team_id&&n.set("team_id",t.team_id),t?.team_guardrail!==void 0&&n.set("team_guardrail",String(t.team_guardrail)),t?.search&&n.set("search",t.search);let o=n.toString()?`${r}?${n.toString()}`:r,a=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=nx(await a.json().catch(()=>({})));throw j(e),Error(e)}return a.json()},tB=async(e,t)=>{let r=$?`${$}/guardrails/submissions/${encodeURIComponent(t)}/approve`:`/guardrails/submissions/${encodeURIComponent(t)}/approve`,n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=nx(await n.json().catch(()=>({})));throw j(e),Error(e)}return n.json()},tA=async(e,t)=>{let r=$?`${$}/guardrails/submissions/${encodeURIComponent(t)}/reject`:`/guardrails/submissions/${encodeURIComponent(t)}/reject`,n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=nx(await n.json().catch(()=>({})));throw j(e),Error(e)}return n.json()},tz=async(e,t,r)=>{try{let n=$?`${$}/guardrails/usage/overview`:"/guardrails/usage/overview",o=new URLSearchParams;t&&o.append("start_date",t),r&&o.append("end_date",r),o.toString()&&(n+=`?${o.toString()}`);let a=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json();throw Error(nx(e))}return a.json()}catch(e){throw console.error("Failed to get guardrails usage overview:",e),e}},tL=async(e,t,r,n)=>{try{let o=$?`${$}/guardrails/usage/detail/${encodeURIComponent(t)}`:`/guardrails/usage/detail/${encodeURIComponent(t)}`,a=new URLSearchParams;r&&a.append("start_date",r),n&&a.append("end_date",n),a.toString()&&(o+=`?${a.toString()}`);let i=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json();throw Error(nx(e))}return i.json()}catch(e){throw console.error("Failed to get guardrails usage detail:",e),e}},tH=async(e,t)=>{try{let r=$?`${$}/guardrails/usage/logs`:"/guardrails/usage/logs",n=new URLSearchParams;t.guardrailId&&n.append("guardrail_id",t.guardrailId),t.policyId&&n.append("policy_id",t.policyId),null!=t.page&&n.append("page",String(t.page)),null!=t.pageSize&&n.append("page_size",String(t.pageSize)),t.action&&n.append("action",t.action),t.startDate&&n.append("start_date",t.startDate),t.endDate&&n.append("end_date",t.endDate),n.toString()&&(r+=`?${n.toString()}`);let o=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json();throw Error(nx(e))}return o.json()}catch(e){throw console.error("Failed to get guardrails usage logs:",e),e}},tD=async e=>{try{let t=$?`${$}/policies/list`:"/policies/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get policies list:",e),e}},tV=async(e,t,r)=>{try{let n=$?`${$}/utils/test_policies_and_guardrails`:"/utils/test_policies_and_guardrails",o=await fetch(n,{method:"POST",signal:r,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({policy_names:t.policy_names??null,guardrail_names:t.guardrail_names??null,inputs:t.inputs??null,inputs_list:t.inputs_list??null,request_data:t.request_data??{},input_type:t.input_type??"request",agent_id:t.agent_id??null})});if(!o.ok){let e=await o.text(),t="Failed to test policies and guardrails";try{let r=JSON.parse(e);r.detail?t="string"==typeof r.detail?r.detail:JSON.stringify(r.detail):r.message&&(t=r.message)}catch{t=e||t}throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to test policies and guardrails:",e),e}},tW=async(e,t)=>{try{let r=$?`${$}/policy/info/${t}`:`/policy/info/${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error(`Failed to get policy info for ${t}:`,e),e}},tG=async e=>{try{let t=$?`${$}/policy/templates`:"/policy/templates",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get policy templates:",e),e}},tU=async(e,t,r,n,o)=>{try{let a=$?`${$}/policy/templates/enrich`:"/policy/templates/enrich",i={template_id:t,parameters:r};n&&(i.model=n),o&&(i.competitors=o);let l=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!l.ok){let e=await l.json(),t=nx(e);throw j(t),Error(t)}return await l.json()}catch(e){throw console.error("Failed to enrich policy template:",e),e}},tq=async(e,t,r,n)=>{try{let o=$?`${$}/policy/templates/suggest`:"/policy/templates/suggest",a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({attack_examples:t.filter(e=>e.trim()),description:r,model:n})});if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}return a.json()}catch(e){throw console.error("Failed to suggest policy templates:",e),e}},tJ=async(e,t,r)=>{try{let n=$?`${$}/policy/templates/test`:"/policy/templates/test",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({guardrail_definitions:t,text:r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return o.json()}catch(e){throw console.error("Failed to test policy template:",e),e}},tK=async(e,t,r,n,o,a,i,l,s)=>{let c=$?`${$}/policy/templates/enrich/stream`:"/policy/templates/enrich/stream",u={template_id:t,parameters:r,model:n};l?.instruction&&(u.instruction=l.instruction),l?.existingCompetitors&&(u.competitors=l.existingCompetitors);let d=await fetch(c,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(u)});if(!d.ok){let e=nx(await d.json());throw j(e),Error(e)}let f=d.body?.getReader();if(!f)throw Error("No response body");let p=new TextDecoder,m="";for(;;){let{done:e,value:t}=await f.read();if(e)break;let r=(m+=p.decode(t,{stream:!0})).split("\n");for(let e of(m=r.pop()||"",r))if(e.startsWith("data: "))try{let t=JSON.parse(e.slice(6));"competitor"===t.type?o(t.name):"status"===t.type?s?.(t.message):"done"===t.type?a(t):"error"===t.type&&i?.(t.message)}catch{}}},tX=async(e,t,r,n,o,a,i,l,s)=>{let c=$?`${$}/usage/ai/chat`:"/usage/ai/chat",u=await fetch(c,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({messages:t,model:r}),signal:s});if(!u.ok){let e=nx(await u.json());throw j(e),Error(e)}let d=u.body?.getReader();if(!d)throw Error("No response body");let f=new TextDecoder,p="";for(;;){let{done:e,value:t}=await d.read();if(e)break;let r=(p+=f.decode(t,{stream:!0})).split("\n");for(let e of(p=r.pop()||"",r))if(e.startsWith("data: "))try{let t=JSON.parse(e.slice(6));"chunk"===t.type?n(t.content):"status"===t.type?i?.(t.message):"tool_call"===t.type?l?.(t):"done"===t.type?o():"error"===t.type&&a?.(t.message)}catch{}}},tY=async(e,t)=>{try{let r=$?`${$}/policies`:"/policies",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create policy:",e),e}},tZ=async(e,t,r)=>{try{let n=$?`${$}/policies/${t}`:`/policies/${t}`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update policy:",e),e}},tQ=async(e,t)=>{try{let r=encodeURIComponent(t),n=$?`${$}/policies/name/${r}/versions`:`/policies/name/${r}/versions`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to list policy versions:",e),e}},t0=async(e,t,r)=>{try{let n=encodeURIComponent(t),o=$?`${$}/policies/name/${n}/versions`:`/policies/name/${n}/versions`,a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({source_policy_id:r??void 0})});if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}return await a.json()}catch(e){throw console.error("Failed to create policy version:",e),e}},t1=async(e,t,r)=>{try{let n=$?`${$}/policies/${t}/status`:`/policies/${t}/status`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({version_status:r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update policy version status:",e),e}},t2=async(e,t)=>{try{let r=$?`${$}/policies/${t}`:`/policies/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete policy:",e),e}},t4=async(e,t)=>{try{let r=$?`${$}/policies/${t}`:`/policies/${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get policy info:",e),e}},t6=async e=>{try{let t=$?`${$}/policies/attachments/list`:"/policies/attachments/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get policy attachments list:",e),e}},t3=async(e,t)=>{try{let r=$?`${$}/policies/attachments`:"/policies/attachments",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create policy attachment:",e),e}},t7=async(e,t)=>{try{let r=$?`${$}/policies/attachments/${t}`:`/policies/attachments/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete policy attachment:",e),e}},t5=async(e,t,r)=>{try{let n=$?`${$}/policies/test-pipeline`:"/policies/test-pipeline",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({pipeline:t,test_messages:r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to test pipeline:",e),e}},t9=async(e,t)=>{try{let r=$?`${$}/policies/${t}/resolved-guardrails`:`/policies/${t}/resolved-guardrails`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get resolved guardrails:",e),e}},t8=async(e,t)=>{try{let r=$?`${$}/policies/resolve`:"/policies/resolve",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to resolve policies:",e),e}},re=async(e,t)=>{try{let r=$?`${$}/policies/attachments/estimate-impact`:"/policies/attachments/estimate-impact",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to estimate attachment impact:",e),e}},rt=async e=>{try{let t=$?`${$}/prompts/list`:"/prompts/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get prompts list:",e),e}},rr=async(e,t)=>{try{let r=$?`${$}/prompts/${t}/info`:`/prompts/${t}/info`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get prompt info:",e),e}},rn=async(e,t)=>{try{let r=$?`${$}/prompts/${t}/versions`:`/prompts/${t}/versions`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw 404!==n.status&&j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get prompt versions:",e),e}},ro=async(e,t)=>{try{let r=$?`${$}/prompts`:"/prompts",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create prompt:",e),e}},ra=async(e,t,r)=>{try{let n=$?`${$}/prompts/${t}`:`/prompts/${t}`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update prompt:",e),e}},ri=async(e,t)=>{try{let r=$?`${$}/prompts/${t}`:`/prompts/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete prompt:",e),e}},rl=async(e,t)=>{try{let r=new FormData;r.append("file",t);let n=$?`${$}/utils/dotprompt_json_converter`:"/utils/dotprompt_json_converter",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`},body:r});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to convert prompt file:",e),e}},rs=async(e,t)=>{try{let r=$?`${$}/v1/agents`:"/v1/agents",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Create agent response:",o),o}catch(e){throw console.error("Failed to create agent:",e),e}},rc=async(e,t)=>{try{let r=$?`${$}/guardrails`:"/guardrails",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({guardrail:t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Create guardrail response:",o),o}catch(e){throw console.error("Failed to create guardrail:",e),e}},ru=async(e,t,r)=>{try{let n=$?`${$}/spend/logs/ui/${t}?start_date=${encodeURIComponent(r)}`:`/spend/logs/ui/${t}?start_date=${encodeURIComponent(r)}`;console.log("Fetching log details from:",n);let o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("Fetched log details:",a),a}catch(e){throw console.error("Failed to fetch log details:",e),e}},rd=async e=>{try{let t=$?`${$}/get/internal_user_settings`:"/get/internal_user_settings";console.log("Fetching SSO settings from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched SSO settings:",n),n}catch(e){throw console.error("Failed to fetch SSO settings:",e),e}},rf=async(e,t)=>{try{let r=$?`${$}/update/internal_user_settings`:"/update/internal_user_settings";console.log("Updating internal user settings:",t);let n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Updated internal user settings:",o),g.default.success("Internal user settings updated successfully"),o}catch(e){throw console.error("Failed to update internal user settings:",e),e}},rp=async e=>{try{let t=$?`${$}/v1/mcp/openapi-registry`:"/v1/mcp/openapi-registry",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json();throw Error(nx(e))}return await r.json()}catch(e){throw console.error("Failed to fetch OpenAPI registry:",e),e}},rm=async e=>{try{let t=$?`${$}/v1/mcp/discover`:"/v1/mcp/discover",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to fetch discoverable MCP servers:",e),e}},rh=async(e,t)=>{try{let r=$?`${$}/v1/mcp/server`:"/v1/mcp/server";if(t){let e=new URLSearchParams;e.append("team_id",t),r=`${r}?${e.toString()}`}console.log("Fetching MCP servers from:",r);let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Fetched MCP servers:",o),o}catch(e){throw console.error("Failed to fetch MCP servers:",e),e}},rg=async(e,t)=>{try{let r=$?`${$}/v1/mcp/server/health`:"/v1/mcp/server/health";if(t&&t.length>0){let e=new URLSearchParams;t.forEach(t=>e.append("server_ids",t)),r=`${r}?${e.toString()}`}console.log("Fetching MCP server health from:",r);let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Fetched MCP server health:",o),o}catch(e){throw console.error("Failed to fetch MCP server health:",e),e}},rv=async e=>{try{let t=$?`${$}/v1/mcp/access_groups`:"/v1/mcp/access_groups";console.log("Fetching MCP access groups from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched MCP access groups:",n),n.access_groups||[]}catch(e){throw console.error("Failed to fetch MCP access groups:",e),e}},ry=async e=>{try{let t=$?`${$}/v1/mcp/network/client-ip`:"/v1/mcp/network/client-ip",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok)return null;return(await r.json()).ip||null}catch{return null}},rb=async(e,t)=>{try{console.log("Form Values in createMCPServer:",t);let r=$?`${$}/v1/mcp/server`:"/v1/mcp/server",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},rw=async(e,t)=>{try{let r=$?`${$}/v1/mcp/server`:"/v1/mcp/server",n=await fetch(r,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to update MCP server:",e),e}},r$=async(e,t)=>{try{let r=($?`${$}`:"")+`/v1/mcp/server/${t}`;console.log("in deleteMCPServer:",t);let n=await fetch(r,{method:S,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}}catch(e){throw console.error("Failed to delete key:",e),e}},rC=async(e,t)=>{try{let r=($?`${$}`:"")+"/v1/mcp/server/register",n=await fetch(r,{method:E,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return n.json()}catch(e){throw console.error("Failed to register MCP server:",e),e}},rE=async e=>{try{let t=($?`${$}`:"")+"/v1/mcp/server/submissions",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json().catch(()=>({})),t=nx(e);throw j(t),Error(t)}return r.json()}catch(e){throw console.error("Failed to fetch MCP submissions:",e),e}},rS=async(e,t)=>{try{let r=($?`${$}`:"")+`/v1/mcp/server/${encodeURIComponent(t)}/approve`,n=await fetch(r,{method:"PUT",headers:{[T]:`Bearer ${e}`}});if(!n.ok){let e=await n.json().catch(()=>({})),t=nx(e);throw j(t),Error(t)}return n.json()}catch(e){throw console.error("Failed to approve MCP server:",e),e}},rx=async(e,t,r)=>{try{let n=($?`${$}`:"")+`/v1/mcp/server/${encodeURIComponent(t)}/reject`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({review_notes:r??null})});if(!o.ok){let e=await o.json().catch(()=>({})),t=nx(e);throw j(t),Error(t)}return o.json()}catch(e){throw console.error("Failed to reject MCP server:",e),e}},rj=async e=>{try{let t=$?`${$}/search_tools/list`:"/search_tools/list";console.log("Fetching search tools from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched search tools:",n),n}catch(e){throw console.error("Failed to fetch search tools:",e),e}},rO=async(e,t)=>{try{console.log("Creating search tool with values:",t);let r=$?`${$}/search_tools`:"/search_tools",n=await fetch(r,{method:E,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({search_tool:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Created search tool:",o),o}catch(e){throw console.error("Failed to create search tool:",e),e}},rk=async(e,t,r)=>{try{console.log("Updating search tool with ID:",t,"values:",r);let n=$?`${$}/search_tools/${t}`:`/search_tools/${t}`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({search_tool:r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("Updated search tool:",a),a}catch(e){throw console.error("Failed to update search tool:",e),e}},rT=async(e,t)=>{try{let r=($?`${$}`:"")+`/search_tools/${t}`;console.log("Deleting search tool:",t);let n=await fetch(r,{method:S,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Deleted search tool:",o),o}catch(e){throw console.error("Failed to delete search tool:",e),e}},rF=async e=>{try{let t=$?`${$}/search_tools/ui/available_providers`:"/search_tools/ui/available_providers";console.log("Fetching available search providers from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched available search providers:",n),n}catch(e){throw console.error("Failed to fetch available search providers:",e),e}},r_=async(e,t)=>{try{let r=$?`${$}/search_tools/test_connection`:"/search_tools/test_connection";console.log("Testing search tool connection:",r);let n=await fetch(r,{method:E,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({litellm_params:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Test connection response:",o),o}catch(e){throw console.error("Failed to test search tool connection:",e),e}},rI=async(e,t,r)=>{try{let n=$?`${$}/mcp-rest/tools/list?server_id=${t}`:`/mcp-rest/tools/list?server_id=${t}`;console.log("Fetching MCP tools from:",n);let o={[T]:`Bearer ${e}`,"Content-Type":"application/json",...r},a=await fetch(n,{method:"GET",headers:o}),i=await a.json();if(console.log("Fetched MCP tools response:",i),!a.ok){if(i.error&&i.message)throw Error(i.message);throw Error("Failed to fetch MCP tools")}return i}catch(e){return console.error("Failed to fetch MCP tools:",e),{tools:[],error:"network_error",message:e instanceof Error?e.message:"Failed to fetch MCP tools",stack_trace:null}}},rP=async(e,t,r,n,o)=>{try{let a=$?`${$}/mcp-rest/tools/call`:"/mcp-rest/tools/call";console.log("Calling MCP tool:",r,"with arguments:",n,"for server:",t);let i={[T]:`Bearer ${e}`,"Content-Type":"application/json",...o?.customHeaders||{}},l={server_id:t,name:r,arguments:n};o?.guardrails&&o.guardrails.length>0&&(l.litellm_metadata={guardrails:o.guardrails});let s=await fetch(a,{method:"POST",headers:i,body:JSON.stringify(l)});if(!s.ok){let e="Network response was not ok",t=null,r=await s.text();try{let n=JSON.parse(r);n.detail?"string"==typeof n.detail?e=n.detail:"object"==typeof n.detail&&(e=n.detail.message||n.detail.error||"An error occurred",t=n.detail):e=n.message||n.error||e}catch(t){console.error("Failed to parse JSON error response:",t),r&&(e=r)}let n=Error(e);throw n.status=s.status,n.statusText=s.statusText,n.details=t,j(e),n}let c=await s.json();return console.log("MCP tool call response:",c),c}catch(e){throw console.error("Failed to call MCP tool:",e),console.error("Error type:",typeof e),e instanceof Error&&(console.error("Error message:",e.message),console.error("Error stack:",e.stack)),e}},rN=async(e,t)=>{try{let r=$?`${$}/tag/new`:"/tag/new",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();await j(e);return}return await n.json()}catch(e){throw console.error("Error creating tag:",e),e}},rR=async(e,t)=>{try{let r=$?`${$}/tag/update`:"/tag/update",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();await j(e);return}return await n.json()}catch(e){throw console.error("Error updating tag:",e),e}},rM=async(e,t)=>{try{let r=$?`${$}/tag/info`:"/tag/info",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({names:t})});if(!n.ok){let e=await n.text();return await j(e),{}}return await n.json()}catch(e){throw console.error("Error getting tag info:",e),e}},rB=async e=>{try{let t=$?`${$}/tag/list`:"/tag/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok){let e=await r.text();return await j(e),{}}return await r.json()}catch(e){throw console.error("Error listing tags:",e),e}},rA=async(e,t)=>{try{let r=$?`${$}/tag/delete`:"/tag/delete",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({name:t})});if(!n.ok){let e=await n.text();await j(e);return}return await n.json()}catch(e){throw console.error("Error deleting tag:",e),e}},rz=async e=>{try{let t=$?`${$}/get/default_team_settings`:"/get/default_team_settings";console.log("Fetching default team settings from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched default team settings:",n),n}catch(e){throw console.error("Failed to fetch default team settings:",e),e}},rL=async(e,t)=>{try{let r=$?`${$}/update/default_team_settings`:"/update/default_team_settings";console.log("Updating default team settings:",t);let n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Updated default team settings:",o),g.default.success("Default team settings updated successfully"),o}catch(e){throw console.error("Failed to update default team settings:",e),e}},rH=async(e,t)=>{try{let r=$?`${$}/team/permissions_list?team_id=${t}`:`/team/permissions_list?team_id=${t}`,n=await fetch(r,{method:"GET",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Team permissions response:",o),o}catch(e){throw console.error("Failed to get team permissions:",e),e}},rD=async(e,t,r)=>{try{let n=$?`${$}/team/permissions_update`:"/team/permissions_update",o=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({team_id:t,team_member_permissions:r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("Team permissions response:",a),a}catch(e){throw console.error("Failed to update team permissions:",e),e}},rV=async(e,t)=>{try{let r=$?`${$}/spend/logs/session/ui?session_id=${encodeURIComponent(t)}`:`/spend/logs/session/ui?session_id=${encodeURIComponent(t)}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to fetch session logs:",e),e}},rW=async(e,t)=>{try{let r=$?`${$}/vector_store/new`:"/vector_store/new",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to create vector store")}return await n.json()}catch(e){throw console.error("Error creating vector store:",e),e}},rG=async(e,t=1,r=100)=>{try{let t=$?`${$}/vector_store/list`:"/vector_store/list",r=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`}});if(!r.ok){let e=await r.json();throw Error(e.detail||"Failed to list vector stores")}return await r.json()}catch(e){throw console.error("Error listing vector stores:",e),e}},rU=async(e,t)=>{try{let r=$?`${$}/vector_store/delete`:"/vector_store/delete",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({vector_store_id:t})});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to delete vector store")}return await n.json()}catch(e){throw console.error("Error deleting vector store:",e),e}},rq=async(e,t)=>{try{let r=$?`${$}/vector_store/info`:"/vector_store/info",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({vector_store_id:t})});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to get vector store info")}return await n.json()}catch(e){throw console.error("Error getting vector store info:",e),e}},rJ=async(e,t)=>{try{let r=$?`${$}/vector_store/update`:"/vector_store/update",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to update vector store")}return await n.json()}catch(e){throw console.error("Error updating vector store:",e),e}},rK=async(e,t,r,n,o,a,i)=>{try{let l=$?`${$}/rag/ingest`:"/rag/ingest",s=new FormData;s.append("file",t);let c={ingest_options:{vector_store:{custom_llm_provider:r,...n&&{vector_store_id:n},...i&&i}}};(o||a)&&(c.ingest_options.litellm_vector_store_params={},o&&(c.ingest_options.litellm_vector_store_params.vector_store_name=o),a&&(c.ingest_options.litellm_vector_store_params.vector_store_description=a)),s.append("request",JSON.stringify(c));let u=await fetch(l,{method:"POST",headers:{[T]:`Bearer ${e}`},body:s});if(!u.ok){let e=await u.json();throw Error(e.error?.message||e.detail||"Failed to ingest document")}return await u.json()}catch(e){throw console.error("Error ingesting document:",e),e}},rX=async e=>{try{let t=$?`${$}/email/event_settings`:"/email/event_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to get email event settings")}let n=await r.json();return console.log("Email event settings response:",n),n}catch(e){throw console.error("Failed to get email event settings:",e),e}},rY=async(e,t)=>{try{let r=$?`${$}/email/event_settings`:"/email/event_settings",n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to update email event settings")}let o=await n.json();return console.log("Update email event settings response:",o),o}catch(e){throw console.error("Failed to update email event settings:",e),e}},rZ=async e=>{try{let t=$?`${$}/email/event_settings/reset`:"/email/event_settings/reset",r=await fetch(t,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to reset email event settings")}let n=await r.json();return console.log("Reset email event settings response:",n),n}catch(e){throw console.error("Failed to reset email event settings:",e),e}},rQ=async(e,t)=>{try{let r=$?`${$}/v1/agents/${t}`:`/v1/agents/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Delete agent response:",o),o}catch(e){throw console.error("Failed to delete agent:",e),e}},r0=async(e,t)=>{try{let r=$?`${$}/v1/agents/make_public`:"/v1/agents/make_public",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({agent_ids:t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Make agents public response:",o),o}catch(e){throw console.error("Failed to make agents public:",e),e}},r1=async(e,t)=>{try{let r=$?`${$}/v1/mcp/make_public`:"/v1/mcp/make_public",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({mcp_server_ids:t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Make agents public response:",o),o}catch(e){throw console.error("Failed to make agents public:",e),e}},r2=async(e,t)=>{try{let r=$?`${$}/guardrails/${t}`:`/guardrails/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Delete guardrail response:",o),o}catch(e){throw console.error("Failed to delete guardrail:",e),e}},r4=async e=>{try{let t=$?`${$}/guardrails/ui/add_guardrail_settings`:"/guardrails/ui/add_guardrail_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to get guardrail UI settings")}let n=await r.json();return console.log("Guardrail UI settings response:",n),n}catch(e){throw console.error("Failed to get guardrail UI settings:",e),e}},r6=async e=>{try{let t=$?`${$}/guardrails/ui/provider_specific_params`:"/guardrails/ui/provider_specific_params",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to get guardrail provider specific parameters")}let n=await r.json();return console.log("Guardrail provider specific params response:",n),n}catch(e){throw console.error("Failed to get guardrail provider specific parameters:",e),e}},r3=async(e,t)=>{try{let r=encodeURIComponent(t),n=$?`${$}/guardrails/ui/category_yaml/${r}`:`/guardrails/ui/category_yaml/${r}`;console.log(`Fetching category YAML from: ${n}`);let o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw console.error(`Failed to get category YAML. Status: ${o.status}, Error:`,e),j(e),Error(`Failed to get category YAML: ${o.status} ${e}`)}let a=await o.json();return console.log("Category YAML response:",a),a}catch(e){throw console.error("Failed to get category YAML:",e),e}},r7=async e=>{try{let t=$?`${$}/guardrails/ui/major_airlines`:"/guardrails/ui/major_airlines",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw console.error(`Failed to get major airlines. Status: ${r.status}, Error:`,e),j(e),Error(`Failed to get major airlines: ${r.status} ${e}`)}return await r.json()}catch(e){throw console.error("Failed to get major airlines:",e),e}},r5=async(e,t=!1)=>{try{let r=t?"?health_check=true":"",n=$?`${$}/v1/agents${r}`:`/v1/agents${r}`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw j(e),Error("Failed to get agents list")}let a=await o.json();return console.log("Agents list response:",a),{agents:a}}catch(e){throw console.error("Failed to get agents list:",e),e}},r9=async(e,t)=>{try{let r=$?`${$}/v1/agents/${t}`:`/v1/agents/${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to get agent info")}let o=await n.json();return console.log("Agent info response:",o),o}catch(e){throw console.error("Failed to get agent info:",e),e}},r8=async(e,t)=>{try{let r=$?`${$}/guardrails/${t}/info`:`/guardrails/${t}/info`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to get guardrail info")}let o=await n.json();return console.log("Guardrail info response:",o),o}catch(e){throw console.error("Failed to get guardrail info:",e),e}},ne=async(e,t,r)=>{try{let n=$?`${$}/v1/agents/${t}`:`/v1/agents/${t}`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.text();throw j(e),Error("Failed to patch agent")}let a=await o.json();return console.log("Patch agent response:",a),a}catch(e){throw console.error("Failed to update guardrail:",e),e}},nt=async(e,t,r)=>{try{let n=$?`${$}/guardrails/${t}`:`/guardrails/${t}`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.text();throw j(e),Error("Failed to update guardrail")}let a=await o.json();return console.log("Update guardrail response:",a),a}catch(e){throw console.error("Failed to update guardrail:",e),e}},nr=async(e,t,r,n,o)=>{try{let a=$?`${$}/guardrails/apply_guardrail`:"/guardrails/apply_guardrail",i={guardrail_name:t,text:r};n&&(i.language=n),o&&o.length>0&&(i.entities=o);let l=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!l.ok){let e=await l.text(),t="Failed to apply guardrail";try{let r=JSON.parse(e);r.error?.message?t=r.error.message:r.detail?t=r.detail:r.message&&(t=r.message)}catch(r){t=e||t}throw j(e),Error(t)}let s=await l.json();return console.log("Apply guardrail response:",s),s}catch(e){throw console.error("Failed to apply guardrail:",e),e}},nn=async(e,t)=>{try{let r=$?`${$}/guardrails/test_custom_code`:"/guardrails/test_custom_code",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.text(),t="Failed to test custom code guardrail";try{let r=JSON.parse(e);r.error?.message?t=r.error.message:r.detail?t=r.detail:r.message&&(t=r.message)}catch(r){t=e||t}throw j(e),Error(t)}let o=await n.json();return console.log("Test custom code guardrail response:",o),o}catch(e){throw console.error("Failed to test custom code guardrail:",e),e}},no=async(e,t)=>{try{let r=$?`${$}/guardrails/validate_blocked_words_file`:"/guardrails/validate_blocked_words_file",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({file_content:t})});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to validate blocked words file")}let o=await n.json();return console.log("Validate blocked words file response:",o),o}catch(e){throw console.error("Failed to validate blocked words file:",e),e}},na=async e=>{try{let t=$?`${$}/get/sso_settings`:"/get/sso_settings";console.log("Fetching SSO configuration from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched SSO configuration:",n),n}catch(e){throw console.error("Failed to fetch SSO configuration:",e),e}},ni=async(e,t)=>{try{let r=$?`${$}/update/sso_settings`:"/update/sso_settings";console.log("Updating SSO configuration:",t);let n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t="object"==typeof e?.detail?e.detail?.error||e.detail?.message:e?.detail,r="string"==typeof t&&t.length>0?t:nx(e);j(r);let o=Error(r);throw e?.detail!==void 0&&(o.detail=e.detail),o.rawError=e,o}let o=await n.json();return console.log("Updated SSO configuration:",o),o}catch(e){throw console.error("Failed to update SSO configuration:",e),e}},nl=async({accessToken:e,page:t=1,page_size:r=50,params:n={}})=>{try{let o=$?`${$}/audit`:"/audit",a=new URLSearchParams;for(let[e,o]of(a.append("page",t.toString()),a.append("page_size",r.toString()),Object.entries(n)))null!=o&&""!==o&&a.append(e,String(o));o+=`?${a.toString()}`;let i=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nx(e);throw j(t),Error(t)}return await i.json()}catch(e){throw console.error("Failed to fetch audit logs:",e),e}},ns=async e=>{try{let t=$?`${$}/user/available_users`:"/user/available_users",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok){if(404===r.status)return null;let e=await r.text();throw j(e),Error("Network response was not ok")}return await r.json()}catch(e){throw console.error("Failed to fetch remaining users:",e),e}},nc=async e=>{try{let t=$?`${$}/health/license`:"/health/license",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok){if(404===r.status)return null;let e=await r.text();throw j(e),Error("Network response was not ok")}return await r.json()}catch(e){throw console.error("Failed to fetch license info:",e),e}},nu=async(e,t,r)=>{try{let n=$?`${$}/config/pass_through_endpoint/${encodeURIComponent(t)}`:`/config/pass_through_endpoint/${encodeURIComponent(t)}`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return g.default.success("Pass through endpoint updated successfully"),a}catch(e){throw console.error("Failed to update pass through endpoint:",e),e}},nd=async(e,t)=>{try{let r=$?`${$}/config/callback/delete`:"/config/callback/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({callback_name:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete specific callback:",e),e}},nf=async(e,t,r)=>{try{console.log("Testing MCP tools list with config:",JSON.stringify(t));let n=$?`${$}/mcp-rest/test/tools/list`:"/mcp-rest/test/tools/list",o={"Content-Type":"application/json"};e&&(o["x-litellm-api-key"]=e),r?o.Authorization=`Bearer ${r}`:e&&(o[T]=`Bearer ${e}`);let a=await fetch(n,{method:"POST",headers:o,body:JSON.stringify(t)}),i=a.headers.get("content-type");if(!i||!i.includes("application/json")){let e=await a.text();throw console.error("Received non-JSON response:",e),Error(`Received non-JSON response (${a.status}: ${a.statusText}). Check network tab for details.`)}let l=await a.json();if((!a.ok||l.error)&&!l.error)return{tools:[],error:"request_failed",message:l.message||`MCP tools list failed: ${a.status} ${a.statusText}`};return l}catch(e){throw console.error("MCP tools list test error:",e),e}},np=async(e,t)=>{let r=$?`${$}/v1/mcp/server/oauth/session`:"/v1/mcp/server/oauth/session",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)}),o=await n.json();if(!n.ok)throw Error(nx(o)||o?.error||"Failed to cache MCP server");return o},nm=async(e,t,r)=>{let n=C(),o=encodeURIComponent(t.trim()),a=`${n}/v1/mcp/server/oauth/${o}/register`,i=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json",Accept:"application/json, text/event-stream"},body:JSON.stringify(r)}),l=await i.json();if(!i.ok)throw Error(nx(l)||l?.detail||"Failed to register OAuth client");return l},nh=({serverId:e,clientId:t,redirectUri:r,state:n,codeChallenge:o,scope:a})=>{let i=C(),l=encodeURIComponent(e.trim()),s=`${i}/v1/mcp/server/oauth/${l}/authorize`,c=new URLSearchParams({redirect_uri:r,state:n,response_type:"code",code_challenge:o,code_challenge_method:"S256"});return t&&t.trim().length>0&&c.set("client_id",t),a&&a.trim().length>0&&c.set("scope",a),`${s}?${c.toString()}`},ng=async({serverId:e,code:t,clientId:r,clientSecret:n,codeVerifier:o,redirectUri:a})=>{let i=C(),l=encodeURIComponent(e.trim()),s=`${i}/v1/mcp/server/oauth/${l}/token`,c=new URLSearchParams;c.set("grant_type","authorization_code"),c.set("code",t),r&&r.trim().length>0&&c.set("client_id",r),n&&n.trim().length>0&&c.set("client_secret",n),c.set("code_verifier",o),c.set("redirect_uri",a);let u=await fetch(s,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:c.toString()}),d=await u.json();if(!u.ok)throw Error(nx(d)||d?.detail||"OAuth token exchange failed");return d},nv=async(e,t,r)=>{try{let n=`${C()}/v1/vector_stores/${t}/search`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({query:r})});if(!o.ok){let e=await o.text();return await j(e),null}return await o.json()}catch(e){throw console.error("Error testing vector store search:",e),e}},ny=async(e,t,r,n)=>{try{let o=`${C()}/v1/search/${t}`,a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({query:r,max_results:n||5})});if(!a.ok){let e=await a.text();return await j(e),null}return await a.json()}catch(e){throw console.error("Error querying search tool:",e),e}},nb=async(e,t,r,n)=>{try{let o,a,i,l=$?`${$}/tag/dau`:"/tag/dau",s=new URLSearchParams;s.append("end_date",(o=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0"),`${o}-${a}-${i}`)),n&&n.length>0?n.forEach(e=>{s.append("tag_filters",e)}):r&&s.append("tag_filter",r);let c=s.toString();c&&(l+=`?${c}`);let u=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!u.ok){let e=await u.json(),t=nx(e);throw j(t),Error(t)}return await u.json()}catch(e){throw console.error("Failed to fetch DAU:",e),e}},nw=async(e,t,r,n)=>{try{let o,a,i,l=$?`${$}/tag/wau`:"/tag/wau",s=new URLSearchParams;s.append("end_date",(o=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0"),`${o}-${a}-${i}`)),n&&n.length>0?n.forEach(e=>{s.append("tag_filters",e)}):r&&s.append("tag_filter",r);let c=s.toString();c&&(l+=`?${c}`);let u=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!u.ok){let e=await u.json(),t=nx(e);throw j(t),Error(t)}return await u.json()}catch(e){throw console.error("Failed to fetch WAU:",e),e}},n$=async(e,t,r,n)=>{try{let o,a,i,l=$?`${$}/tag/mau`:"/tag/mau",s=new URLSearchParams;s.append("end_date",(o=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0"),`${o}-${a}-${i}`)),n&&n.length>0?n.forEach(e=>{s.append("tag_filters",e)}):r&&s.append("tag_filter",r);let c=s.toString();c&&(l+=`?${c}`);let u=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!u.ok){let e=await u.json(),t=nx(e);throw j(t),Error(t)}return await u.json()}catch(e){throw console.error("Failed to fetch MAU:",e),e}},nC=async e=>{try{let t=$?`${$}/tag/distinct`:"/tag/distinct",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to fetch distinct tags:",e),e}},nE=async(e,t,r,n)=>{try{let o=$?`${$}/tag/summary`:"/tag/summary",a=new URLSearchParams,i=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${n}`};a.append("start_date",i(t)),a.append("end_date",i(r)),n&&n.length>0&&n.forEach(e=>{a.append("tag_filters",e)});let l=a.toString();l&&(o+=`?${l}`);let s=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nx(e);throw j(t),Error(t)}return await s.json()}catch(e){throw console.error("Failed to fetch user agent summary:",e),e}},nS=async(e,t=1,r=50,n)=>{try{let o=$?`${$}/tag/user-agent/per-user-analytics`:"/tag/user-agent/per-user-analytics",a=new URLSearchParams;a.append("page",t.toString()),a.append("page_size",r.toString()),n&&n.length>0&&n.forEach(e=>{a.append("tag_filters",e)});let i=a.toString();i&&(o+=`?${i}`);let l=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!l.ok){let e=await l.json(),t=nx(e);throw j(t),Error(t)}return await l.json()}catch(e){throw console.error("Failed to fetch per-user analytics:",e),e}},nx=e=>{let t=e?.detail,r=Array.isArray(t)?t.map(e=>e?.msg||JSON.stringify(e)).join("; "):"string"==typeof t?t:void 0;return e?.error&&(e.error.message||("string"==typeof e.error?e.error:void 0))||e?.message||r||JSON.stringify(e)},nj=async(e,t)=>{let r=C(),n=r?`${r}/v2/login`:"/v2/login",o=JSON.stringify({username:e,password:t}),a=await fetch(n,{method:"POST",body:o,credentials:"include",headers:{"Content-Type":"application/json"}});if(!a.ok)throw Error(nx(await a.json()));return await a.json()},nO=async()=>{let e=C(),t=e?`${e}/get/ui_settings`:"/get/ui_settings",r=await fetch(t,{method:"GET"});if(!r.ok)throw Error(nx(await r.json()));return await r.json()},nk=async(e,t)=>{let r=C(),n=r?`${r}/update/ui_settings`:"/update/ui_settings",o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok)throw Error(nx(await o.json()));return await o.json()},nT=async()=>{try{let e=C(),t=e?`${e}/claude-code/marketplace.json`:"/claude-code/marketplace.json",r=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"}});if(!r.ok){let e=await r.text(),t=nx(JSON.parse(e));throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to fetch Claude Code marketplace:",e),e}},nF=async(e,t=!1)=>{try{let r=C(),n=r?`${r}/claude-code/plugins?enabled_only=${t}`:`/claude-code/plugins?enabled_only=${t}`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nx(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to fetch Claude Code plugins list:",e),e}},n_=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}`:`/claude-code/plugins/${t}`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nx(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to fetch plugin "${t}":`,e),e}},nI=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins`:"/claude-code/plugins",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.text(),t=nx(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to register Claude Code plugin:",e),e}},nP=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}/enable`:`/claude-code/plugins/${t}/enable`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nx(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to enable plugin "${t}":`,e),e}},nN=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}/disable`:`/claude-code/plugins/${t}/disable`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nx(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to disable plugin "${t}":`,e),e}},nR=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}`:`/claude-code/plugins/${t}`,o=await fetch(n,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nx(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to delete plugin "${t}":`,e),e}},nM=async(e,t)=>{let r=$?`${$}/compliance/eu-ai-act`:"/compliance/eu-ai-act",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok)throw Error(await n.text());return n.json()},nB=async(e,t)=>{let r=$?`${$}/compliance/gdpr`:"/compliance/gdpr",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok)throw Error(await n.text());return n.json()},nA=async e=>{let t=$?`${$}/v1/tool/policy/options`:"/v1/tool/policy/options",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok)throw Error(await r.text());return r.json()},nz=async e=>{let t=$?`${$}/v1/tool/list`:"/v1/tool/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok)throw Error(await r.text());return(await r.json()).tools??[]},nL=async(e,t,r)=>{let n=encodeURIComponent(t),o=$?`${$}/v1/tool/${n}/logs`:`/v1/tool/${n}/logs`,a=new URLSearchParams;null!=r.page&&a.append("page",String(r.page)),null!=r.pageSize&&a.append("page_size",String(r.pageSize)),r.startDate&&a.append("start_date",r.startDate),r.endDate&&a.append("end_date",r.endDate);let i=a.toString()?`${o}?${a.toString()}`:o,l=await fetch(i,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!l.ok)throw Error(nx(await l.json().catch(()=>({}))));return l.json()},nH=async(e,t)=>{let r=encodeURIComponent(t),n=$?`${$}/v1/tool/${r}/detail`:`/v1/tool/${r}/detail`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok)throw Error(await o.text());return o.json()},nD=async(e,t,r,n)=>{let o=$?`${$}/v1/tool/policy`:"/v1/tool/policy",a={tool_name:t};null!=r.input_policy&&(a.input_policy=r.input_policy),null!=r.output_policy&&(a.output_policy=r.output_policy),n?.team_id!=null&&(a.team_id=n.team_id||void 0),n?.key_hash!=null&&(a.key_hash=n.key_hash||void 0),n?.key_alias!=null&&(a.key_alias=n.key_alias||void 0);let i=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(a)});if(!i.ok)throw Error(await i.text());return i.json()},nV=async(e,t,r)=>{let n=encodeURIComponent(t),o=new URLSearchParams;null!=r.team_id&&""!==r.team_id&&o.set("team_id",r.team_id),null!=r.key_hash&&""!==r.key_hash&&o.set("key_hash",r.key_hash);let a=o.toString(),i=$?`${$}/v1/tool/${n}/overrides${a?`?${a}`:""}`:`/v1/tool/${n}/overrides${a?`?${a}`:""}`,l=await fetch(i,{method:"DELETE",headers:{[T]:`Bearer ${e}`}});if(!l.ok)throw Error(await l.text());return l.json()},nW=async(e,t,r)=>{let n=$?`${$}/v1/mcp/server/${t}/oauth-user-credential`:`/v1/mcp/server/${t}/oauth-user-credential`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json().catch(()=>({})),t=e?.detail;throw Error((Array.isArray(t)?t.map(e=>e&&"object"==typeof e?e.msg??JSON.stringify(e):String(e)).join("; "):"string"==typeof t?t:t&&"string"==typeof t.error?t.error:void 0)||"Failed to store OAuth credential")}return o.json()},nG=async(e,t)=>{let r=$?`${$}/v1/mcp/server/${t}/oauth-user-credential`:`/v1/mcp/server/${t}/oauth-user-credential`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`}});if(!n.ok){let e=await n.json().catch(()=>({})),t=e?.detail;throw Error((Array.isArray(t)?t.map(e=>e&&"object"==typeof e?e.msg??JSON.stringify(e):String(e)).join("; "):"string"==typeof t?t:t&&"string"==typeof t.error?t.error:void 0)||"Failed to revoke OAuth credential")}return n.json()},nU=async(e,t)=>{let r=$?`${$}/v1/mcp/server/${t}/oauth-user-credential/status`:`/v1/mcp/server/${t}/oauth-user-credential/status`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`}});return n.ok?n.json():{server_id:t,has_credential:!1,is_expired:!1}},nq=async e=>{let t=$?`${$}/v1/mcp/user-credentials`:"/v1/mcp/user-credentials",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});return r.ok?r.json():[]}}]); \ No newline at end of file +Allowed values: ${t.enum.join(", ")}`:S)}),children:r},e)})}):null};var g=e.i(727749);let v=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${n}`},y=async e=>{try{let t=$?`${$}/callbacks/configs`:"/callbacks/configs",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},b=async e=>{try{let t=$?`${$}/in_product_nudges`:"/in_product_nudges",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get in-product nudges:",e),e}},w="/",$=null;console.log=function(){};let C=()=>{if($)return $;let e=window.location;return e?.origin??""},E="POST",S="DELETE",x=0,j=async e=>{let t=Date.now();if(t-x>6e4){if(("string"==typeof e?e:JSON.stringify(e)).includes("Authentication Error - Expired Key")){g.default.info("UI Session Expired. Logging out."),x=t,(0,r.clearTokenCookies)();let e=window.location;e&&(window.location.href=e.pathname)}x=t}else console.log("Error suppressed to prevent spam:",e)},O=async()=>{let e=$?`${$}/public/providers/fields`:"/public/providers/fields",t=await fetch(e,{method:"GET"});if(!t.ok){let e=await t.text();throw console.error("Failed to fetch provider create metadata:",t.status,e),Error("Failed to load provider configuration")}return await t.json()},k=async()=>{let e=$?`${$}/public/agents/fields`:"/public/agents/fields",t=await fetch(e,{method:"GET"});if(!t.ok){let e=await t.text();throw console.error("Failed to fetch agent create metadata:",t.status,e),Error("Failed to load agent configuration")}return await t.json()},T="Authorization";function F(e="Authorization"){console.log(`setGlobalLitellmHeaderName: ${e}`),T=e}function _(){return T}let I=async(e,t)=>{let r=$?`${$}/model_group/make_public`:"/model_group/make_public";return(await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({model_groups:t})})).json()},P=async()=>{console.log("Getting UI config");let e=await fetch("/litellm/.well-known/litellm-ui-config"),t=await e.json();return console.log("jsonData in getUiConfig:",t),((e,t=null)=>{let r=window.location,n=r?.origin??null,o=t||n;if(console.log("proxyBaseUrl:",$),console.log("serverRootPath:",e),!o)return console.log("Updated proxyBaseUrl:",$=$??null);e.length>0&&!o.endsWith(e)&&"/"!=e&&(o+=e),console.log("Updated proxyBaseUrl:",$=o)})(t.server_root_path,t.proxy_base_url),t},N=async()=>{let e=$?`${$}/public/model_hub/info`:"/public/model_hub/info",t=await fetch(e);return await t.json()},R=async()=>{let e=$?`${$}/openapi.json`:"/openapi.json",t=await fetch(e);return await t.json()},M=async()=>{try{let e=$?`${$}/public/litellm_model_cost_map`:"/public/litellm_model_cost_map",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}}),r=await t.json();return console.log(`received litellm model cost data: ${r}`),r}catch(e){throw console.error("Failed to get model cost map:",e),e}},B=async e=>{try{let t=$?`${$}/reload/model_cost_map`:"/reload/model_cost_map",r=await fetch(t,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}}),n=await r.json();return console.log(`Model cost map reload response: ${n}`),n}catch(e){throw console.error("Failed to reload model cost map:",e),e}},A=async(e,t)=>{try{let r=$?`${$}/schedule/model_cost_map_reload?hours=${t}`:`/schedule/model_cost_map_reload?hours=${t}`,n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}}),o=await n.json();return console.log(`Schedule model cost map reload response: ${o}`),o}catch(e){throw console.error("Failed to schedule model cost map reload:",e),e}},z=async e=>{try{let t=$?`${$}/schedule/model_cost_map_reload`:"/schedule/model_cost_map_reload",r=await fetch(t,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}}),n=await r.json();return console.log(`Cancel model cost map reload response: ${n}`),n}catch(e){throw console.error("Failed to cancel model cost map reload:",e),e}},L=async e=>{try{let t=$?`${$}/model/cost_map/source`:"/model/cost_map/source",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw Error(`HTTP ${r.status}: ${e}`)}let n=await r.json();return console.log("Model cost map source info:",n),n}catch(e){throw console.error("Failed to get model cost map source info:",e),e}},H=async e=>{try{let t=$?`${$}/schedule/model_cost_map_reload/status`:"/schedule/model_cost_map_reload/status";console.log("Fetching status from URL:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){console.error(`Status request failed with status: ${r.status}`);let e=await r.text();throw console.error("Error response:",e),Error(`HTTP ${r.status}: ${e}`)}let n=await r.json();return console.log("Model cost map reload status:",n),n}catch(e){throw console.error("Failed to get model cost map reload status:",e),e}},D=async(e,r)=>{try{let n=$?`${$}/model/new`:"/model/new",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),t.message.destroy(),g.default.success(`Model ${r.model_name} created successfully`),a}catch(e){throw console.error("Failed to create key:",e),e}},V=async(e,t)=>{console.log(`model_id in model delete call: ${t}`);try{let r=$?`${$}/model/delete`:"/model/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({id:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},W=async(e,t)=>{if(console.log(`budget_id in budget delete call: ${t}`),null!=e)try{let r=$?`${$}/budget/delete`:"/budget/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({id:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},G=async(e,t)=>{try{console.log("Form Values in budgetCreateCall:",t),console.log("Form Values after check:",t);let r=$?`${$}/budget/new`:"/budget/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},U=async(e,t)=>{try{console.log("Form Values in budgetUpdateCall:",t),console.log("Form Values after check:",t);let r=$?`${$}/budget/update`:"/budget/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},q=async(e,t)=>{try{let r=$?`${$}/invitation/new`:"/invitation/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_id:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},J=async e=>{try{let t=$?`${$}/alerting/settings`:"/alerting/settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},K=async(e,t)=>{try{for(let e of(console.log("Form Values in keyCreateServiceAccountCall:",t),t.description&&(t.metadata||(t.metadata={}),t.metadata.description=t.description,delete t.description,t.metadata=JSON.stringify(t.metadata)),p))if(t[e]){console.log(`formValues.${e}:`,t[e]);try{t[e]=JSON.parse(t[e])}catch(t){throw Error(`Failed to parse ${e}: `+t)}}console.log("Form Values after check:",t);let r=$?`${$}/key/service-account/generate`:"/key/service-account/generate",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},X=async(e,t,r)=>{try{for(let e of(console.log("Form Values in keyCreateCall:",r),r.description&&(r.metadata||(r.metadata={}),r.metadata.description=r.description,delete r.description,r.metadata=JSON.stringify(r.metadata)),p))if(r[e]){console.log(`formValues.${e}:`,r[e]);try{r[e]=JSON.parse(r[e])}catch(t){throw Error(`Failed to parse ${e}: `+t)}}console.log("Form Values after check:",r);let n=$?`${$}/key/generate`:"/key/generate",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...r})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},Y=async(e,t,r,n,o,a)=>{let i=$?`${$}/key/generate`:"/key/generate",l={agent_id:t,key_alias:r,models:n.length>0?n:[]};a&&(l.team_id=a),o&&Object.keys(o).length>0&&(l.metadata=o);let s=await fetch(i,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(l)});if(!s.ok)throw j(await s.text()),Error("Failed to create key for agent");return s.json()},Z=async(e,t,r)=>{try{if(console.log("Form Values in keyCreateCall:",r),r.description&&(r.metadata||(r.metadata={}),r.metadata.description=r.description,delete r.description,r.metadata=JSON.stringify(r.metadata)),r.auto_create_key=!1,r.metadata){console.log("formValues.metadata:",r.metadata);try{r.metadata=JSON.parse(r.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}console.log("Form Values after check:",r);let n=$?`${$}/user/new`:"/user/new",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...r})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},Q=async(e,t)=>{try{let r=$?`${$}/key/delete`:"/key/delete";console.log("in keyDeleteCall:",t);let n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({keys:[t]})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to create key:",e),e}},ee=async(e,t)=>{try{let r=$?`${$}/user/delete`:"/user/delete";console.log("in userDeleteCall:",t);let n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_ids:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to delete user(s):",e),e}},et=async(e,t)=>{try{let r=$?`${$}/team/delete`:"/team/delete";console.log("in teamDeleteCall:",t);let n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({team_ids:[t]})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to delete key:",e),e}},er=async(e,t=null,r=null,n=null,o=null,a=null,i=null,l=null,s=null,c=null,u=null)=>{try{let d=$?`${$}/user/list`:"/user/list";console.log("in userListCall");let f=new URLSearchParams;if(t&&t.length>0){let e=t.join(",");f.append("user_ids",e)}r&&f.append("page",r.toString()),n&&f.append("page_size",n.toString()),o&&f.append("user_email",o),a&&f.append("role",a),i&&f.append("team",i),l&&f.append("sso_user_ids",l),s&&f.append("sort_by",s),c&&f.append("sort_order",c),u&&u.length>0&&f.append("organization_ids",u.join(","));let p=f.toString();p&&(d+=`?${p}`);let m=await fetch(d,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!m.ok){let e=await m.json(),t=nj(e);throw j(t),Error(t)}let h=await m.json();return console.log("/user/list API Response:",h),h}catch(e){throw console.error("Failed to create key:",e),e}},en=async(e,t)=>{try{let r=$?`${$}/v2/user/info`:"/v2/user/info";t&&(r+=`?user_id=${encodeURIComponent(t)}`);let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to fetch user info v2:",e),e}},eo=async(e,t,r,n=!1,o,a,i=!1)=>{console.log(`userInfoCall: ${t}, ${r}, ${n}, ${o}, ${a}, ${i}`);try{let l;if(n){l=$?`${$}/user/list`:"/user/list";let e=new URLSearchParams;null!=o&&e.append("page",o.toString()),null!=a&&e.append("page_size",a.toString()),l+=`?${e.toString()}`}else l=$?`${$}/user/info`:"/user/info",("Admin"!==r&&"Admin Viewer"!==r||i)&&t&&(l+=`?user_id=${t}`);console.log("Requesting user data from:",l);let s=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nj(e);throw j(t),Error(t)}let c=await s.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to fetch user data:",e),e}},ea=async(e,t)=>{try{let r=$?`${$}/team/info`:"/team/info";t&&(r=`${r}?team_id=${t}`),console.log("in teamInfoCall");let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ei=async(e,t,r=null,n=null,o=null,a=1,i=10,l=null,s=null)=>{try{let a=$?`${$}/v2/team/list`:"/v2/team/list";console.log("in teamInfoCall");let i=new URLSearchParams;r&&i.append("user_id",r.toString()),t&&i.append("organization_id",t.toString()),n&&i.append("team_id",n.toString()),o&&i.append("team_alias",o.toString());let l=i.toString();l&&(a+=`?${l}`);let s=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nj(e);throw j(t),Error(t)}let c=await s.json();return console.log("/v2/team/list API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},el=async(e,t,r=null,n=null,o=null)=>{try{let a=$?`${$}/team/list`:"/team/list";console.log("in teamInfoCall");let i=new URLSearchParams;r&&i.append("user_id",r.toString()),t&&i.append("organization_id",t.toString()),n&&i.append("team_id",n.toString()),o&&i.append("team_alias",o.toString());let l=i.toString();l&&(a+=`?${l}`);let s=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nj(e);throw j(t),Error(t)}let c=await s.json();return console.log("/team/list API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},es=async e=>{try{let t=$?`${$}/team/available`:"/team/available";console.log("in availableTeamListCall");let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("/team/available_teams API Response:",n),n}catch(e){throw e}},ec=async(e,t=null,r=null)=>{try{let n=$?`${$}/organization/list`:"/organization/list",o=new URLSearchParams;t&&o.append("org_id",t.toString()),r&&o.append("org_alias",r.toString());let a=o.toString();a&&(n+=`?${a}`);let i=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nj(e);throw j(t),Error(t)}return await i.json()}catch(e){throw console.error("Failed to create key:",e),e}},eu=async(e,t)=>{try{let r=$?`${$}/organization/info`:"/organization/info";t&&(r=`${r}?organization_id=${t}`),console.log("in teamInfoCall");let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ed=async(e,t)=>{try{if(console.log("Form Values in organizationCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw console.error("Failed to parse metadata:",e),Error("Failed to parse metadata: "+e)}}let r=$?`${$}/organization/new`:"/organization/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ef=async(e,t)=>{try{console.log("Form Values in organizationUpdateCall:",t);let r=$?`${$}/organization/update`:"/organization/update",n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Update Team Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ep=async(e,t)=>{try{let r=$?`${$}/organization/delete`:"/organization/delete",n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_ids:[t]})});if(!n.ok){let e=await n.text();throw j(e),Error(`Error deleting organization: ${e}`)}return await n.json()}catch(e){throw console.error("Failed to delete organization:",e),e}},em=async(e,t)=>{try{let r=$?`${$}/utils/transform_request`:"/utils/transform_request",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create key:",e),e}},eh=async({accessToken:e,endpoint:t,startTime:r,endTime:n,page:o=1,extraQueryParams:a})=>{try{let i,l,s,c,u=(i=t.startsWith("/")?t:`/${t}`,l=$?`${$}${i}`:i,(s=new URLSearchParams).append("start_date",v(r)),s.append("end_date",v(n)),s.append("page_size","1000"),s.append("page",o.toString()),s.append("timezone",new Date().getTimezoneOffset().toString()),a&&Object.entries(a).forEach(([e,t])=>{((e,t,r)=>{if(null!=r){if(Array.isArray(r)){r.length>0&&e.append(t,r.join(","));return}e.append(t,`${r}`)}})(s,e,t)}),(c=s.toString())?`${l}?${c}`:l),d=await fetch(u,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!d.ok){let e=await d.json(),t=nj(e);throw j(t),Error(t)}return await d.json()}catch(e){throw console.error(`Failed to fetch daily activity (${t}):`,e),e}},eg=async(e,t,r,n=1,o=null)=>eh({accessToken:e,endpoint:"/user/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{user_id:o}}),ev=async(e,t,r,n=1,o=null)=>eh({accessToken:e,endpoint:"/tag/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{tags:o}}),ey=async(e,t,r,n=1,o=null)=>eh({accessToken:e,endpoint:"/team/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{team_ids:o,exclude_team_ids:"litellm-dashboard"}}),eb=async(e,t,r,n=1,o=null)=>eh({accessToken:e,endpoint:"/organization/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{organization_ids:o}}),ew=async(e,t,r,n=1,o=null)=>eh({accessToken:e,endpoint:"/customer/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{end_user_ids:o}}),e$=async(e,t,r,n=1,o=null)=>eh({accessToken:e,endpoint:"/agent/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{agent_ids:o}}),eC=async e=>{try{let t=$?`${$}/onboarding/get_token`:"/onboarding/get_token";t+=`?invite_link=${e}`;let r=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to create key:",e),e}},eE=async(e,t,r,n)=>{let o=$?`${$}/onboarding/claim_token`:"/onboarding/claim_token";try{let a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({invitation_link:t,user_id:r,password:n})});if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to delete key:",e),e}},eS=async(e,t,r)=>{try{let n=$?`${$}/key/${t}/regenerate`:`/key/${t}/regenerate`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("Regenerate key Response:",a),a}catch(e){throw console.error("Failed to regenerate key:",e),e}},ex=!1,ej=null,eO=async(e,t,r,n=1,o=50,a,i,l,s,c)=>{try{console.log("modelInfoCall:",e,t,r,n,o,a,i,l,s,c);let u=$?`${$}/v2/model/info`:"/v2/model/info",d=new URLSearchParams;d.append("include_team_models","true"),d.append("page",n.toString()),d.append("size",o.toString()),a&&a.trim()&&d.append("search",a.trim()),i&&i.trim()&&d.append("modelId",i.trim()),l&&l.trim()&&d.append("teamId",l.trim()),s&&s.trim()&&d.append("sortBy",s.trim()),c&&c.trim()&&d.append("sortOrder",c.trim()),d.toString()&&(u+=`?${d.toString()}`);let f=await fetch(u,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!f.ok){let e=await f.text();throw e+=`error shown=${ex}`,ex||(e.includes("No model list passed")&&(e="No Models Exist. Click Add Model to get started."),g.default.info(e),ex=!0,ej&&clearTimeout(ej),ej=setTimeout(()=>{ex=!1},1e4)),Error("Network response was not ok")}let p=await f.json();return console.log("modelInfoCall:",p),p}catch(e){throw console.error("Failed to create key:",e),e}},ek=async(e,t)=>{try{let r=$?`${$}/v1/model/info`:"/v1/model/info";r+=`?litellm_model_id=${t}`;let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("modelInfoV1Call:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},eT=async()=>{let e=$?`${$}/public/model_hub`:"/public/model_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`modelHubPublicModelsCall failed with status ${t.status}`),[])},eF=async()=>{let e=$?`${$}/public/agent_hub`:"/public/agent_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`agentHubPublicModelsCall failed with status ${t.status}`),[])},e_=async()=>{let e=$?`${$}/public/mcp_hub`:"/public/mcp_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`mcpHubPublicServersCall failed with status ${t.status}`),[])},eI=async e=>{try{let t=$?`${$}/model_group/info`:"/model_group/info",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("modelHubCall:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},eP=async e=>{try{let t=$?`${$}/get/allowed_ips`:"/get/allowed_ips",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("getAllowedIPs:",n),n.data}catch(e){throw console.error("Failed to get allowed IPs:",e),e}},eN=async(e,t)=>{try{let r=$?`${$}/add/allowed_ip`:"/add/allowed_ip",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({ip:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("addAllowedIP:",o),o}catch(e){throw console.error("Failed to add allowed IP:",e),e}},eR=async(e,t)=>{try{let r=$?`${$}/delete/allowed_ip`:"/delete/allowed_ip",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({ip:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("deleteAllowedIP:",o),o}catch(e){throw console.error("Failed to delete allowed IP:",e),e}},eM=async(e,t)=>{try{let r=$?`${$}/model_hub/update_useful_links`:"/model_hub/update_useful_links",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({useful_links:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create key:",e),e}},eB=async(e,t,r,n=!1,o=null,a=!1,i=!1,l)=>{console.log("in /models calls, globalLitellmHeaderName",T);try{let t=$?`${$}/models`:"/models",r=new URLSearchParams;r.append("include_model_access_groups","True"),!0===n&&r.append("return_wildcard_routes","True"),!0===i&&r.append("only_model_access_groups","True"),o&&r.append("team_id",o.toString()),l&&r.append("scope",l),r.toString()&&(t+=`?${r.toString()}`);let a=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}return await a.json()}catch(e){throw console.error("Failed to create key:",e),e}},eA=async e=>{try{let t=$?`${$}/global/spend/teams`:"/global/spend/teams";console.log("in teamSpendLogsCall:",t);let r=await fetch(`${t}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},ez=async(e,t,r,n)=>{try{let o=$?`${$}/global/spend/tags`:"/global/spend/tags";t&&r&&(o=`${o}?start_date=${t}&end_date=${r}`),n&&(o+=`&tags=${n.join(",")}`),console.log("in tagsSpendLogsCall:",o);let a=await fetch(`${o}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to create key:",e),e}},eL=async e=>{try{let t=$?`${$}/global/spend/all_tag_names`:"/global/spend/all_tag_names";console.log("in global/spend/all_tag_names call",t);let r=await fetch(`${t}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eH=async e=>{try{let t=$?`${$}/customer/list`:"/customer/list";console.log("in customer/list",t);let r=await fetch(`${t}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to fetch end users:",e),e}},eD=async(e,t)=>{try{let r=$?`${$}/user/filter/ui`:"/user/filter/ui",n=new URLSearchParams;t.get("user_email")&&n.append("user_email",t.get("user_email")),t.get("user_id")&&n.append("user_id",t.get("user_id")),t.get("team_id")&&n.append("team_id",t.get("team_id"));let o=n.toString(),a=o?`${r}?${o}`:r,i=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nj(e);throw j(t),Error(t)}return await i.json()}catch(e){throw console.error("Failed to create key:",e),e}},eV=async({accessToken:e,start_date:t,end_date:r,page:n=1,page_size:o=50,params:a={}})=>{try{let i=$?`${$}/spend/logs/ui`:"/spend/logs/ui",l=new URLSearchParams;for(let[e,i]of(l.append("start_date",t),l.append("end_date",r),l.append("page",n.toString()),l.append("page_size",o.toString()),Object.entries(a)))null!=i&&("min_spend"===e||"max_spend"===e?l.append(e,i.toString()):"string"==typeof i&&""!==i&&l.append(e,String(i)));let s=l.toString();s&&(i+=`?${s}`);let c=await fetch(i,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!c.ok){let e=await c.json(),t=nj(e);throw j(t),Error(t)}let u=await c.json();return console.log("Spend Logs Response:",u),u}catch(e){throw console.error("Failed to fetch spend logs:",e),e}},eW=async e=>{try{let t=$?`${$}/global/spend/logs`:"/global/spend/logs",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eG=async e=>{try{let t=$?`${$}/global/spend/keys?limit=5`:"/global/spend/keys?limit=5",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eU=async(e,t,r,n)=>{try{let o=$?`${$}/global/spend/end_users`:"/global/spend/end_users",a="";a=t?JSON.stringify({api_key:t,startTime:r,endTime:n}):JSON.stringify({startTime:r,endTime:n});let i={method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:a},l=await fetch(o,i);if(!l.ok){let e=await l.json(),t=nj(e);throw j(t),Error(t)}let s=await l.json();return console.log(s),s}catch(e){throw console.error("Failed to create key:",e),e}},eq=async(e,t,r,n)=>{try{let o=$?`${$}/global/spend/provider`:"/global/spend/provider";r&&n&&(o+=`?start_date=${r}&end_date=${n}`),t&&(o+=`&api_key=${t}`);let a={method:"GET",headers:{[T]:`Bearer ${e}`}},i=await fetch(o,a);if(!i.ok){let e=await i.json(),t=nj(e);throw j(t),Error(t)}let l=await i.json();return console.log(l),l}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eJ=async(e,t,r)=>{try{let n=$?`${$}/global/activity`:"/global/activity";t&&r&&(n+=`?start_date=${t}&end_date=${r}`);let o={method:"GET",headers:{[T]:`Bearer ${e}`}},a=await fetch(n,o);if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eK=async(e,t,r)=>{try{let n=$?`${$}/global/activity/cache_hits`:"/global/activity/cache_hits";t&&r&&(n+=`?start_date=${t}&end_date=${r}`);let o={method:"GET",headers:{[T]:`Bearer ${e}`}},a=await fetch(n,o);if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eX=async(e,t,r)=>{try{let n=$?`${$}/global/activity/model`:"/global/activity/model";t&&r&&(n+=`?start_date=${t}&end_date=${r}`);let o={method:"GET",headers:{[T]:`Bearer ${e}`}},a=await fetch(n,o);if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eY=async e=>{try{let t=$?`${$}/global/spend/models?limit=5`:"/global/spend/models?limit=5",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eZ=async(e,t)=>{try{let r=$?`${$}/v2/key/info`:"/v2/key/info",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({keys:t})});if(!n.ok){let e=await n.text();if(e.includes("Invalid proxy server token passed"))throw Error("Invalid proxy server token passed");throw j(e),Error("Network response was not ok")}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to create key:",e),e}},eQ=async(e,t,r,n)=>{try{console.log("Sending model connection test request:",JSON.stringify(t));let o=$?`${$}/health/test_connection`:"/health/test_connection",a=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({litellm_params:t,model_info:r,mode:n})}),i=a.headers.get("content-type");if(!i||!i.includes("application/json")){let e=await a.text();throw console.error("Received non-JSON response:",e),Error(`Received non-JSON response (${a.status}: ${a.statusText}). Check network tab for details.`)}let l=await a.json();if((!a.ok||"error"===l.status)&&"error"!==l.status)return{status:"error",message:l.error?.message||`Connection test failed: ${a.status} ${a.statusText}`};return l}catch(e){throw console.error("Model connection test error:",e),e}},e0=async(e,t)=>{try{console.log("entering keyInfoV1Call");let r=$?`${$}/key/info`:"/key/info";r=`${r}?key=${t}`;let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(console.log("response",n),!n.ok){let e=await n.text();j(e),g.default.fromBackend("Failed to fetch key info - "+e)}let o=await n.json();return console.log("data",o),o}catch(e){throw console.error("Failed to fetch key info:",e),e}},e1=async(e,t,r,n,o,a,i,l,s=null,c=null,u=null,d=null)=>{try{let f=$?`${$}/key/list`:"/key/list";console.log("in keyListCall");let p=new URLSearchParams;r&&p.append("team_id",r.toString()),t&&p.append("organization_id",t.toString()),n&&p.append("key_alias",n),a&&p.append("key_hash",a),o&&p.append("user_id",o.toString()),i&&p.append("page",i.toString()),l&&p.append("size",l.toString()),s&&p.append("sort_by",s),c&&p.append("sort_order",c),u&&p.append("expand",u),d&&p.append("status",d),p.append("return_full_object","true"),p.append("include_team_keys","true"),p.append("include_created_by_keys","true");let m=p.toString();m&&(f+=`?${m}`);let h=await fetch(f,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!h.ok){let e=await h.json(),t=nj(e);throw j(t),Error(t)}let g=await h.json();return console.log("/team/list API Response:",g),g}catch(e){throw console.error("Failed to create key:",e),e}},e2=async(e,t=1,r=50,n)=>{try{let o=new URLSearchParams(Object.entries({page:String(t),size:String(r),...n?{search:n}:{}})),a=$?`${$}/key/aliases`:"/key/aliases";a=`${a}?${o}`;let i=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nj(e);throw j(t),Error(t)}let l=await i.json();return console.log("/key/aliases API Response:",l),l}catch(e){throw console.error("Failed to fetch key aliases:",e),e}},e4=async(e,t,r,n=null)=>{try{let o=$?`${$}/user/daily/activity/aggregated`:"/user/daily/activity/aggregated",a=new URLSearchParams,i=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${n}`};a.append("start_date",i(t)),a.append("end_date",i(r)),a.append("timezone",new Date().getTimezoneOffset().toString()),n&&a.append("user_id",n);let l=a.toString();l&&(o+=`?${l}`);let s=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nj(e);throw j(t),Error(t)}return await s.json()}catch(e){throw console.error("Failed to fetch aggregated user daily activity:",e),e}},e6=async e=>{try{let t=$?`${$}/user/available_roles`:"/user/available_roles",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("response from user/available_role",n),n}catch(e){throw e}},e3=async(e,t)=>{try{if(console.log("Form Values in teamCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let r=$?`${$}/team/new`:"/team/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},e7=async(e,t)=>{try{if(console.log("Form Values in credentialCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let r=$?`${$}/credentials`:"/credentials",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},e5=async e=>{try{let t=$?`${$}/credentials`:"/credentials";console.log("in credentialListCall");let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("/credentials API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},e9=async(e,t,r)=>{try{let n=$?`${$}/credentials`:"/credentials";t?n+=`/by_name/${t}`:r&&(n+=`/by_model/${r}`),console.log("in credentialListCall");let o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("/credentials API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},e8=async(e,t)=>{try{let r=$?`${$}/credentials/${t}`:`/credentials/${t}`;console.log("in credentialDeleteCall:",t);let n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to delete key:",e),e}},te=async(e,t,r)=>{try{if(console.log("Form Values in credentialUpdateCall:",r),r.metadata){console.log("formValues.metadata:",r.metadata);try{r.metadata=JSON.parse(r.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let n=$?`${$}/credentials/${t}`:`/credentials/${t}`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},tt=async(e,t)=>{try{if(console.log("Form Values in keyUpdateCall:",t),t.model_tpm_limit){console.log("formValues.model_tpm_limit:",t.model_tpm_limit);try{t.model_tpm_limit=JSON.parse(t.model_tpm_limit)}catch(e){throw Error("Failed to parse model_tpm_limit: "+e)}}if(t.model_rpm_limit){console.log("formValues.model_rpm_limit:",t.model_rpm_limit);try{t.model_rpm_limit=JSON.parse(t.model_rpm_limit)}catch(e){throw Error("Failed to parse model_rpm_limit: "+e)}}let r=$?`${$}/key/update`:"/key/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let o=await n.json();return console.log("Update key Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},tr=async(e,t)=>{try{console.log("Form Values in teamUpateCall:",t);let r=$?`${$}/team/update`:"/team/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),console.error("Error response from the server:",e),g.default.fromBackend("Failed to update team settings: "+e),Error(e)}let o=await n.json();return console.log("Update Team Response:",o),o}catch(e){throw console.error("Failed to update team:",e),e}},tn=async(e,t,r)=>{try{console.log("Form Values in modelUpateCall:",t);let n=$?`${$}/model/${r}/update`:`/model/${r}/update`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error update from the server:",e),Error("Network response was not ok")}let a=await o.json();return console.log("Update model Response:",a),a}catch(e){throw console.error("Failed to update model:",e),e}},to=async(e,t,r)=>{try{console.log("Form Values in teamMemberAddCall:",r);let n=$?`${$}/team/member_add`:"/team/member_add",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({team_id:t,member:r})});if(!o.ok){let e=await o.text(),t={};try{t=JSON.parse(e)}catch(t){console.warn("Failed to parse error body as JSON:",e)}let r=t?.detail?.error||"Failed to add team member",n=Error(r);throw n.raw=t,n}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},ta=async(e,t,r,n,o)=>{try{console.log("Bulk add team members:",{teamId:t,members:r,maxBudgetInTeam:n});let a=$?`${$}/team/bulk_member_add`:"/team/bulk_member_add",i={team_id:t};o?i.all_users=!0:i.members=r,null!=n&&(i.max_budget_in_team=n);let l=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!l.ok){let e=await l.text(),t={};try{t=JSON.parse(e)}catch(t){console.warn("Failed to parse error body as JSON:",e)}let r=t?.detail?.error||"Failed to bulk add team members",n=Error(r);throw n.raw=t,n}let s=await l.json();return console.log("Bulk team member add API Response:",s),s}catch(e){throw console.error("Failed to bulk add team members:",e),e}},ti=async(e,t,r)=>{try{console.log("Form Values in teamMemberUpdateCall:",r),console.log("Budget value:",r.max_budget_in_team),console.log("TPM limit:",r.tpm_limit),console.log("RPM limit:",r.rpm_limit);let n=$?`${$}/team/member_update`:"/team/member_update",o={team_id:t,role:r.role,user_id:r.user_id};void 0!==r.user_email&&(o.user_email=r.user_email),void 0!==r.max_budget_in_team&&null!==r.max_budget_in_team&&(o.max_budget_in_team=r.max_budget_in_team),void 0!==r.tpm_limit&&null!==r.tpm_limit&&(o.tpm_limit=r.tpm_limit),void 0!==r.rpm_limit&&null!==r.rpm_limit&&(o.rpm_limit=r.rpm_limit),console.log("Final request body:",o);let a=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(o)});if(!a.ok){let e=await a.text(),t={};try{t=JSON.parse(e)}catch(t){console.warn("Failed to parse error body as JSON:",e)}let r=t?.detail?.error||"Failed to add team member",n=Error(r);throw n.raw=t,n}let i=await a.json();return console.log("API Response:",i),i}catch(e){throw console.error("Failed to update team member:",e),e}},tl=async(e,t,r)=>{try{console.log("Form Values in teamMemberAddCall:",r);let n=$?`${$}/team/member_delete`:"/team/member_delete",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({team_id:t,...void 0!==r.user_email&&{user_email:r.user_email},...void 0!==r.user_id&&{user_id:r.user_id}})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},ts=async(e,t,r)=>{try{console.log("Form Values in teamMemberAddCall:",r);let n=$?`${$}/organization/member_add`:"/organization/member_add",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,member:r})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create organization member:",e),e}},tc=async(e,t,r)=>{try{console.log("Form Values in organizationMemberDeleteCall:",r);let n=$?`${$}/organization/member_delete`:"/organization/member_delete",o=await fetch(n,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,user_id:r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to delete organization member:",e),e}},tu=async(e,t,r)=>{try{console.log("Form Values in organizationMemberUpdateCall:",r);let n=$?`${$}/organization/member_update`:"/organization/member_update",o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,...r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to update organization member:",e),e}},td=async(e,t,r)=>{try{console.log("Form Values in userUpdateUserCall:",t);let n=$?`${$}/user/update`:"/user/update",o={...t};null!==r&&(o.user_role=r),o=JSON.stringify(o);let a=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:o});if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}let i=await a.json();return console.log("API Response:",i),i}catch(e){throw console.error("Failed to create key:",e),e}},tf=async(e,t,r,n=!1)=>{try{let o;console.log("Form Values in userUpdateUserCall:",t);let a=$?`${$}/user/bulk_update`:"/user/bulk_update";if(n)o=JSON.stringify({all_users:!0,user_updates:t});else if(r&&r.length>0){let e=[];for(let n of r)e.push({user_id:n,...t});o=JSON.stringify({users:e})}else throw Error("Must provide either userIds or set allUsers=true");let i=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:o});if(!i.ok){let e=await i.json(),t=nj(e);throw j(t),Error(t)}let l=await i.json();return console.log("API Response:",l),l}catch(e){throw console.error("Failed to create key:",e),e}},tp=async(e,t)=>{try{let r=$?`${$}/health/services?service=${t}`:`/health/services?service=${t}`;console.log("Checking Slack Budget Alerts service health");let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error(e)}return await n.json()}catch(e){throw console.error("Failed to perform health check:",e),e}},tm=async e=>{try{let t=$?`${$}/budget/list`:"/budget/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},th=async(e,t,r)=>{try{let t=$?`${$}/get/config/callbacks`:"/get/config/callbacks",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tg=async e=>{try{let t=$?`${$}/config/list?config_type=general_settings`:"/config/list?config_type=general_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tv=async e=>{try{let t=$?`${$}/router/settings`:"/router/settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get router settings:",e),e}},ty=async e=>{try{let t=$?`${$}/cache/settings`:"/cache/settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get cache settings:",e),e}},tb=async(e,t)=>{try{let r=$?`${$}/cache/settings/test`:"/cache/settings/test",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({cache_settings:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to test cache connection:",e),e}},tw=async(e,t)=>{try{let r=$?`${$}/cache/settings`:"/cache/settings",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({cache_settings:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to update cache settings:",e),e}},t$=async(e,t)=>{try{let r=$?`${$}/config/pass_through_endpoint`:"/config/pass_through_endpoint";t&&(r+=`/team/${t}`);let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tC=async(e,t)=>{try{let r=$?`${$}/config/field/info?field_name=${t}`:`/config/field/info?field_name=${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},tE=async(e,t)=>{try{let r=$?`${$}/config/pass_through_endpoint`:"/config/pass_through_endpoint",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},tS=async(e,t,r)=>{try{let n=$?`${$}/config/field/update`:"/config/field/update",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({field_name:t,field_value:r,config_type:"general_settings"})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return g.default.success("Successfully updated value!"),a}catch(e){throw console.error("Failed to set callbacks:",e),e}},tx=async(e,t)=>{try{let r=$?`${$}/config/field/delete`:"/config/field/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({field_name:t,config_type:"general_settings"})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return g.default.success("Field reset on proxy"),o}catch(e){throw console.error("Failed to get callbacks:",e),e}},tj=async(e,t)=>{try{let r=$?`${$}/config/pass_through_endpoint?endpoint_id=${t}`:`/config/pass_through_endpoint?endpoint_id=${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tO=async(e,t)=>{try{let r=$?`${$}/config/update`:"/config/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},tk=async(e,t)=>{try{let r=$?`${$}/health?model_id=${encodeURIComponent(t)}`:`/health?model_id=${encodeURIComponent(t)}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error(`Failed to call /health for model id ${t}:`,e),e}},tT=async e=>{try{let t=$?`${$}/cache/ping`:"/cache/ping",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error(e)}return await r.json()}catch(e){throw console.error("Failed to call /cache/ping:",e),e}},tF=async e=>{try{let t=$?`${$}/health/latest`:"/health/latest",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error(e)}return await r.json()}catch(e){throw console.error("Failed to call /health/latest:",e),e}},t_=async e=>{try{console.log("Getting proxy UI settings"),console.log("proxyBaseUrl in getProxyUISettings:",$);let t=$?`${$}/sso/get/ui_settings`:"/sso/get/ui_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tI=async e=>{try{let t=$?`${$}/get/ui_settings`:"/get/ui_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);return console.error("Failed to get UI settings:",t),null}return await r.json()}catch(e){return console.error("Failed to get UI settings:",e),null}},tP=async e=>{try{let t=$?`${$}/get/mcp_semantic_filter_settings`:"/get/mcp_semantic_filter_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get MCP semantic filter settings:",e),e}},tN=async(e,t)=>{try{let r=$?`${$}/update/mcp_semantic_filter_settings`:"/update/mcp_semantic_filter_settings",n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to update MCP semantic filter settings:",e),e}},tR=async(e,t,r)=>{try{let n=$?`${$}/v1/responses`:"/v1/responses",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({model:t,input:[{role:"user",content:r,type:"message"}],tools:[{type:"mcp",server_url:"litellm_proxy",require_approval:"never"}],tool_choice:"required"})}),a=o.headers.get("x-litellm-semantic-filter"),i=o.headers.get("x-litellm-semantic-filter-tools");if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return{data:await o.json(),headers:{filter:a,tools:i}}}catch(e){throw console.error("Failed to test MCP semantic filter:",e),e}},tM=async e=>{try{let t=$?`${$}/v2/guardrails/list`:"/v2/guardrails/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok)throw Error(`v2 guardrails/list returned ${r.status}`);return await r.json()}catch(t){console.log("v2/guardrails/list failed, falling back to v1:",t);try{let t=$?`${$}/guardrails/list`:"/guardrails/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get guardrails list:",e),e}}},tB=async(e,t)=>{let r=$?`${$}/guardrails/submissions`:"/guardrails/submissions",n=new URLSearchParams;t?.status&&n.set("status",t.status),t?.team_id&&n.set("team_id",t.team_id),t?.team_guardrail!==void 0&&n.set("team_guardrail",String(t.team_guardrail)),t?.search&&n.set("search",t.search);let o=n.toString()?`${r}?${n.toString()}`:r,a=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=nj(await a.json().catch(()=>({})));throw j(e),Error(e)}return a.json()},tA=async(e,t)=>{let r=$?`${$}/guardrails/submissions/${encodeURIComponent(t)}/approve`:`/guardrails/submissions/${encodeURIComponent(t)}/approve`,n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=nj(await n.json().catch(()=>({})));throw j(e),Error(e)}return n.json()},tz=async(e,t)=>{let r=$?`${$}/guardrails/submissions/${encodeURIComponent(t)}/reject`:`/guardrails/submissions/${encodeURIComponent(t)}/reject`,n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=nj(await n.json().catch(()=>({})));throw j(e),Error(e)}return n.json()},tL=async(e,t,r)=>{try{let n=$?`${$}/guardrails/usage/overview`:"/guardrails/usage/overview",o=new URLSearchParams;t&&o.append("start_date",t),r&&o.append("end_date",r),o.toString()&&(n+=`?${o.toString()}`);let a=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json();throw Error(nj(e))}return a.json()}catch(e){throw console.error("Failed to get guardrails usage overview:",e),e}},tH=async(e,t,r,n)=>{try{let o=$?`${$}/guardrails/usage/detail/${encodeURIComponent(t)}`:`/guardrails/usage/detail/${encodeURIComponent(t)}`,a=new URLSearchParams;r&&a.append("start_date",r),n&&a.append("end_date",n),a.toString()&&(o+=`?${a.toString()}`);let i=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json();throw Error(nj(e))}return i.json()}catch(e){throw console.error("Failed to get guardrails usage detail:",e),e}},tD=async(e,t)=>{try{let r=$?`${$}/guardrails/usage/logs`:"/guardrails/usage/logs",n=new URLSearchParams;t.guardrailId&&n.append("guardrail_id",t.guardrailId),t.policyId&&n.append("policy_id",t.policyId),null!=t.page&&n.append("page",String(t.page)),null!=t.pageSize&&n.append("page_size",String(t.pageSize)),t.action&&n.append("action",t.action),t.startDate&&n.append("start_date",t.startDate),t.endDate&&n.append("end_date",t.endDate),n.toString()&&(r+=`?${n.toString()}`);let o=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json();throw Error(nj(e))}return o.json()}catch(e){throw console.error("Failed to get guardrails usage logs:",e),e}},tV=async e=>{try{let t=$?`${$}/policies/list`:"/policies/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get policies list:",e),e}},tW=async(e,t,r)=>{try{let n=$?`${$}/utils/test_policies_and_guardrails`:"/utils/test_policies_and_guardrails",o=await fetch(n,{method:"POST",signal:r,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({policy_names:t.policy_names??null,guardrail_names:t.guardrail_names??null,inputs:t.inputs??null,inputs_list:t.inputs_list??null,request_data:t.request_data??{},input_type:t.input_type??"request",agent_id:t.agent_id??null})});if(!o.ok){let e=await o.text(),t="Failed to test policies and guardrails";try{let r=JSON.parse(e);r.detail?t="string"==typeof r.detail?r.detail:JSON.stringify(r.detail):r.message&&(t=r.message)}catch{t=e||t}throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to test policies and guardrails:",e),e}},tG=async(e,t)=>{try{let r=$?`${$}/policy/info/${t}`:`/policy/info/${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error(`Failed to get policy info for ${t}:`,e),e}},tU=async e=>{try{let t=$?`${$}/policy/templates`:"/policy/templates",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get policy templates:",e),e}},tq=async(e,t,r,n,o)=>{try{let a=$?`${$}/policy/templates/enrich`:"/policy/templates/enrich",i={template_id:t,parameters:r};n&&(i.model=n),o&&(i.competitors=o);let l=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!l.ok){let e=await l.json(),t=nj(e);throw j(t),Error(t)}return await l.json()}catch(e){throw console.error("Failed to enrich policy template:",e),e}},tJ=async(e,t,r,n)=>{try{let o=$?`${$}/policy/templates/suggest`:"/policy/templates/suggest",a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({attack_examples:t.filter(e=>e.trim()),description:r,model:n})});if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}return a.json()}catch(e){throw console.error("Failed to suggest policy templates:",e),e}},tK=async(e,t,r)=>{try{let n=$?`${$}/policy/templates/test`:"/policy/templates/test",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({guardrail_definitions:t,text:r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return o.json()}catch(e){throw console.error("Failed to test policy template:",e),e}},tX=async(e,t,r,n,o,a,i,l,s)=>{let c=$?`${$}/policy/templates/enrich/stream`:"/policy/templates/enrich/stream",u={template_id:t,parameters:r,model:n};l?.instruction&&(u.instruction=l.instruction),l?.existingCompetitors&&(u.competitors=l.existingCompetitors);let d=await fetch(c,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(u)});if(!d.ok){let e=nj(await d.json());throw j(e),Error(e)}let f=d.body?.getReader();if(!f)throw Error("No response body");let p=new TextDecoder,m="";for(;;){let{done:e,value:t}=await f.read();if(e)break;let r=(m+=p.decode(t,{stream:!0})).split("\n");for(let e of(m=r.pop()||"",r))if(e.startsWith("data: "))try{let t=JSON.parse(e.slice(6));"competitor"===t.type?o(t.name):"status"===t.type?s?.(t.message):"done"===t.type?a(t):"error"===t.type&&i?.(t.message)}catch{}}},tY=async(e,t,r,n,o,a,i,l,s)=>{let c=$?`${$}/usage/ai/chat`:"/usage/ai/chat",u=await fetch(c,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({messages:t,model:r}),signal:s});if(!u.ok){let e=nj(await u.json());throw j(e),Error(e)}let d=u.body?.getReader();if(!d)throw Error("No response body");let f=new TextDecoder,p="";for(;;){let{done:e,value:t}=await d.read();if(e)break;let r=(p+=f.decode(t,{stream:!0})).split("\n");for(let e of(p=r.pop()||"",r))if(e.startsWith("data: "))try{let t=JSON.parse(e.slice(6));"chunk"===t.type?n(t.content):"status"===t.type?i?.(t.message):"tool_call"===t.type?l?.(t):"done"===t.type?o():"error"===t.type&&a?.(t.message)}catch{}}},tZ=async(e,t)=>{try{let r=$?`${$}/policies`:"/policies",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create policy:",e),e}},tQ=async(e,t,r)=>{try{let n=$?`${$}/policies/${t}`:`/policies/${t}`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update policy:",e),e}},t0=async(e,t)=>{try{let r=encodeURIComponent(t),n=$?`${$}/policies/name/${r}/versions`:`/policies/name/${r}/versions`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to list policy versions:",e),e}},t1=async(e,t,r)=>{try{let n=encodeURIComponent(t),o=$?`${$}/policies/name/${n}/versions`:`/policies/name/${n}/versions`,a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({source_policy_id:r??void 0})});if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}return await a.json()}catch(e){throw console.error("Failed to create policy version:",e),e}},t2=async(e,t,r)=>{try{let n=$?`${$}/policies/${t}/status`:`/policies/${t}/status`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({version_status:r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update policy version status:",e),e}},t4=async(e,t)=>{try{let r=$?`${$}/policies/${t}`:`/policies/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete policy:",e),e}},t6=async(e,t)=>{try{let r=$?`${$}/policies/${t}`:`/policies/${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get policy info:",e),e}},t3=async e=>{try{let t=$?`${$}/policies/attachments/list`:"/policies/attachments/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get policy attachments list:",e),e}},t7=async(e,t)=>{try{let r=$?`${$}/policies/attachments`:"/policies/attachments",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create policy attachment:",e),e}},t5=async(e,t)=>{try{let r=$?`${$}/policies/attachments/${t}`:`/policies/attachments/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete policy attachment:",e),e}},t9=async(e,t,r)=>{try{let n=$?`${$}/policies/test-pipeline`:"/policies/test-pipeline",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({pipeline:t,test_messages:r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to test pipeline:",e),e}},t8=async(e,t)=>{try{let r=$?`${$}/policies/${t}/resolved-guardrails`:`/policies/${t}/resolved-guardrails`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get resolved guardrails:",e),e}},re=async(e,t)=>{try{let r=$?`${$}/policies/resolve`:"/policies/resolve",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to resolve policies:",e),e}},rt=async(e,t)=>{try{let r=$?`${$}/policies/attachments/estimate-impact`:"/policies/attachments/estimate-impact",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to estimate attachment impact:",e),e}},rr=async e=>{try{let t=$?`${$}/prompts/list`:"/prompts/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get prompts list:",e),e}},rn=async(e,t)=>{try{let r=$?`${$}/prompts/${t}/info`:`/prompts/${t}/info`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get prompt info:",e),e}},ro=async(e,t)=>{try{let r=$?`${$}/prompts/${t}/versions`:`/prompts/${t}/versions`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw 404!==n.status&&j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get prompt versions:",e),e}},ra=async(e,t)=>{try{let r=$?`${$}/prompts`:"/prompts",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create prompt:",e),e}},ri=async(e,t,r)=>{try{let n=$?`${$}/prompts/${t}`:`/prompts/${t}`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update prompt:",e),e}},rl=async(e,t)=>{try{let r=$?`${$}/prompts/${t}`:`/prompts/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete prompt:",e),e}},rs=async(e,t)=>{try{let r=new FormData;r.append("file",t);let n=$?`${$}/utils/dotprompt_json_converter`:"/utils/dotprompt_json_converter",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`},body:r});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to convert prompt file:",e),e}},rc=async(e,t)=>{try{let r=$?`${$}/v1/agents`:"/v1/agents",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Create agent response:",o),o}catch(e){throw console.error("Failed to create agent:",e),e}},ru=async(e,t)=>{try{let r=$?`${$}/guardrails`:"/guardrails",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({guardrail:t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Create guardrail response:",o),o}catch(e){throw console.error("Failed to create guardrail:",e),e}},rd=async(e,t,r)=>{try{let n=$?`${$}/spend/logs/ui/${t}?start_date=${encodeURIComponent(r)}`:`/spend/logs/ui/${t}?start_date=${encodeURIComponent(r)}`;console.log("Fetching log details from:",n);let o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("Fetched log details:",a),a}catch(e){throw console.error("Failed to fetch log details:",e),e}},rf=async e=>{try{let t=$?`${$}/get/internal_user_settings`:"/get/internal_user_settings";console.log("Fetching SSO settings from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched SSO settings:",n),n}catch(e){throw console.error("Failed to fetch SSO settings:",e),e}},rp=async(e,t)=>{try{let r=$?`${$}/update/internal_user_settings`:"/update/internal_user_settings";console.log("Updating internal user settings:",t);let n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Updated internal user settings:",o),g.default.success("Internal user settings updated successfully"),o}catch(e){throw console.error("Failed to update internal user settings:",e),e}},rm=async e=>{try{let t=$?`${$}/v1/mcp/openapi-registry`:"/v1/mcp/openapi-registry",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json();throw Error(nj(e))}return await r.json()}catch(e){throw console.error("Failed to fetch OpenAPI registry:",e),e}},rh=async e=>{try{let t=$?`${$}/v1/mcp/discover`:"/v1/mcp/discover",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to fetch discoverable MCP servers:",e),e}},rg=async(e,t)=>{try{let r=$?`${$}/v1/mcp/server`:"/v1/mcp/server";if(t){let e=new URLSearchParams;e.append("team_id",t),r=`${r}?${e.toString()}`}console.log("Fetching MCP servers from:",r);let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Fetched MCP servers:",o),o}catch(e){throw console.error("Failed to fetch MCP servers:",e),e}},rv=async(e,t)=>{try{let r=$?`${$}/v1/mcp/server/health`:"/v1/mcp/server/health";if(t&&t.length>0){let e=new URLSearchParams;t.forEach(t=>e.append("server_ids",t)),r=`${r}?${e.toString()}`}console.log("Fetching MCP server health from:",r);let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Fetched MCP server health:",o),o}catch(e){throw console.error("Failed to fetch MCP server health:",e),e}},ry=async e=>{try{let t=$?`${$}/v1/mcp/access_groups`:"/v1/mcp/access_groups";console.log("Fetching MCP access groups from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched MCP access groups:",n),n.access_groups||[]}catch(e){throw console.error("Failed to fetch MCP access groups:",e),e}},rb=async e=>{try{let t=$?`${$}/v1/mcp/network/client-ip`:"/v1/mcp/network/client-ip",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok)return null;return(await r.json()).ip||null}catch{return null}},rw=async(e,t)=>{try{console.log("Form Values in createMCPServer:",t);let r=$?`${$}/v1/mcp/server`:"/v1/mcp/server",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},r$=async(e,t)=>{try{let r=$?`${$}/v1/mcp/server`:"/v1/mcp/server",n=await fetch(r,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to update MCP server:",e),e}},rC=async(e,t)=>{try{let r=($?`${$}`:"")+`/v1/mcp/server/${t}`;console.log("in deleteMCPServer:",t);let n=await fetch(r,{method:S,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}}catch(e){throw console.error("Failed to delete key:",e),e}},rE=async(e,t)=>{try{let r=($?`${$}`:"")+"/v1/mcp/server/register",n=await fetch(r,{method:E,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return n.json()}catch(e){throw console.error("Failed to register MCP server:",e),e}},rS=async e=>{try{let t=($?`${$}`:"")+"/v1/mcp/server/submissions",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json().catch(()=>({})),t=nj(e);throw j(t),Error(t)}return r.json()}catch(e){throw console.error("Failed to fetch MCP submissions:",e),e}},rx=async(e,t)=>{try{let r=($?`${$}`:"")+`/v1/mcp/server/${encodeURIComponent(t)}/approve`,n=await fetch(r,{method:"PUT",headers:{[T]:`Bearer ${e}`}});if(!n.ok){let e=await n.json().catch(()=>({})),t=nj(e);throw j(t),Error(t)}return n.json()}catch(e){throw console.error("Failed to approve MCP server:",e),e}},rj=async(e,t,r)=>{try{let n=($?`${$}`:"")+`/v1/mcp/server/${encodeURIComponent(t)}/reject`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({review_notes:r??null})});if(!o.ok){let e=await o.json().catch(()=>({})),t=nj(e);throw j(t),Error(t)}return o.json()}catch(e){throw console.error("Failed to reject MCP server:",e),e}},rO=async e=>{try{let t=$?`${$}/search_tools/list`:"/search_tools/list";console.log("Fetching search tools from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched search tools:",n),n}catch(e){throw console.error("Failed to fetch search tools:",e),e}},rk=async(e,t)=>{try{console.log("Creating search tool with values:",t);let r=$?`${$}/search_tools`:"/search_tools",n=await fetch(r,{method:E,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({search_tool:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Created search tool:",o),o}catch(e){throw console.error("Failed to create search tool:",e),e}},rT=async(e,t,r)=>{try{console.log("Updating search tool with ID:",t,"values:",r);let n=$?`${$}/search_tools/${t}`:`/search_tools/${t}`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({search_tool:r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("Updated search tool:",a),a}catch(e){throw console.error("Failed to update search tool:",e),e}},rF=async(e,t)=>{try{let r=($?`${$}`:"")+`/search_tools/${t}`;console.log("Deleting search tool:",t);let n=await fetch(r,{method:S,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Deleted search tool:",o),o}catch(e){throw console.error("Failed to delete search tool:",e),e}},r_=async e=>{try{let t=$?`${$}/search_tools/ui/available_providers`:"/search_tools/ui/available_providers";console.log("Fetching available search providers from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched available search providers:",n),n}catch(e){throw console.error("Failed to fetch available search providers:",e),e}},rI=async(e,t)=>{try{let r=$?`${$}/search_tools/test_connection`:"/search_tools/test_connection";console.log("Testing search tool connection:",r);let n=await fetch(r,{method:E,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({litellm_params:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Test connection response:",o),o}catch(e){throw console.error("Failed to test search tool connection:",e),e}},rP=async(e,t,r)=>{try{let n=$?`${$}/mcp-rest/tools/list?server_id=${t}`:`/mcp-rest/tools/list?server_id=${t}`;console.log("Fetching MCP tools from:",n);let o={[T]:`Bearer ${e}`,"Content-Type":"application/json",...r},a=await fetch(n,{method:"GET",headers:o}),i=await a.json();if(console.log("Fetched MCP tools response:",i),!a.ok){if(i.error&&i.message)throw Error(i.message);throw Error("Failed to fetch MCP tools")}return i}catch(e){return console.error("Failed to fetch MCP tools:",e),{tools:[],error:"network_error",message:e instanceof Error?e.message:"Failed to fetch MCP tools",stack_trace:null}}},rN=async(e,t,r,n,o)=>{try{let a=$?`${$}/mcp-rest/tools/call`:"/mcp-rest/tools/call";console.log("Calling MCP tool:",r,"with arguments:",n,"for server:",t);let i={[T]:`Bearer ${e}`,"Content-Type":"application/json",...o?.customHeaders||{}},l={server_id:t,name:r,arguments:n};o?.guardrails&&o.guardrails.length>0&&(l.litellm_metadata={guardrails:o.guardrails});let s=await fetch(a,{method:"POST",headers:i,body:JSON.stringify(l)});if(!s.ok){let e="Network response was not ok",t=null,r=await s.text();try{let n=JSON.parse(r);n.detail?"string"==typeof n.detail?e=n.detail:"object"==typeof n.detail&&(e=n.detail.message||n.detail.error||"An error occurred",t=n.detail):e=n.message||n.error||e}catch(t){console.error("Failed to parse JSON error response:",t),r&&(e=r)}let n=Error(e);throw n.status=s.status,n.statusText=s.statusText,n.details=t,j(e),n}let c=await s.json();return console.log("MCP tool call response:",c),c}catch(e){throw console.error("Failed to call MCP tool:",e),console.error("Error type:",typeof e),e instanceof Error&&(console.error("Error message:",e.message),console.error("Error stack:",e.stack)),e}},rR=async(e,t)=>{try{let r=$?`${$}/tag/new`:"/tag/new",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();await j(e);return}return await n.json()}catch(e){throw console.error("Error creating tag:",e),e}},rM=async(e,t)=>{try{let r=$?`${$}/tag/update`:"/tag/update",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();await j(e);return}return await n.json()}catch(e){throw console.error("Error updating tag:",e),e}},rB=async(e,t)=>{try{let r=$?`${$}/tag/info`:"/tag/info",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({names:t})});if(!n.ok){let e=await n.text();return await j(e),{}}return await n.json()}catch(e){throw console.error("Error getting tag info:",e),e}},rA=async e=>{try{let t=$?`${$}/tag/list`:"/tag/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok){let e=await r.text();return await j(e),{}}return await r.json()}catch(e){throw console.error("Error listing tags:",e),e}},rz=async(e,t)=>{try{let r=$?`${$}/tag/delete`:"/tag/delete",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({name:t})});if(!n.ok){let e=await n.text();await j(e);return}return await n.json()}catch(e){throw console.error("Error deleting tag:",e),e}},rL=async e=>{try{let t=$?`${$}/get/default_team_settings`:"/get/default_team_settings";console.log("Fetching default team settings from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched default team settings:",n),n}catch(e){throw console.error("Failed to fetch default team settings:",e),e}},rH=async(e,t)=>{try{let r=$?`${$}/update/default_team_settings`:"/update/default_team_settings";console.log("Updating default team settings:",t);let n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Updated default team settings:",o),g.default.success("Default team settings updated successfully"),o}catch(e){throw console.error("Failed to update default team settings:",e),e}},rD=async(e,t)=>{try{let r=$?`${$}/team/permissions_list?team_id=${t}`:`/team/permissions_list?team_id=${t}`,n=await fetch(r,{method:"GET",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Team permissions response:",o),o}catch(e){throw console.error("Failed to get team permissions:",e),e}},rV=async(e,t,r)=>{try{let n=$?`${$}/team/permissions_update`:"/team/permissions_update",o=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({team_id:t,team_member_permissions:r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("Team permissions response:",a),a}catch(e){throw console.error("Failed to update team permissions:",e),e}},rW=async(e,t)=>{try{let r=$?`${$}/spend/logs/session/ui?session_id=${encodeURIComponent(t)}`:`/spend/logs/session/ui?session_id=${encodeURIComponent(t)}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to fetch session logs:",e),e}},rG=async(e,t)=>{try{let r=$?`${$}/vector_store/new`:"/vector_store/new",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to create vector store")}return await n.json()}catch(e){throw console.error("Error creating vector store:",e),e}},rU=async(e,t=1,r=100)=>{try{let t=$?`${$}/vector_store/list`:"/vector_store/list",r=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`}});if(!r.ok){let e=await r.json();throw Error(e.detail||"Failed to list vector stores")}return await r.json()}catch(e){throw console.error("Error listing vector stores:",e),e}},rq=async(e,t)=>{try{let r=$?`${$}/vector_store/delete`:"/vector_store/delete",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({vector_store_id:t})});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to delete vector store")}return await n.json()}catch(e){throw console.error("Error deleting vector store:",e),e}},rJ=async(e,t)=>{try{let r=$?`${$}/vector_store/info`:"/vector_store/info",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({vector_store_id:t})});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to get vector store info")}return await n.json()}catch(e){throw console.error("Error getting vector store info:",e),e}},rK=async(e,t)=>{try{let r=$?`${$}/vector_store/update`:"/vector_store/update",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to update vector store")}return await n.json()}catch(e){throw console.error("Error updating vector store:",e),e}},rX=async(e,t,r,n,o,a,i)=>{try{let l=$?`${$}/rag/ingest`:"/rag/ingest",s=new FormData;s.append("file",t);let c={ingest_options:{vector_store:{custom_llm_provider:r,...n&&{vector_store_id:n},...i&&i}}};(o||a)&&(c.ingest_options.litellm_vector_store_params={},o&&(c.ingest_options.litellm_vector_store_params.vector_store_name=o),a&&(c.ingest_options.litellm_vector_store_params.vector_store_description=a)),s.append("request",JSON.stringify(c));let u=await fetch(l,{method:"POST",headers:{[T]:`Bearer ${e}`},body:s});if(!u.ok){let e=await u.json();throw Error(e.error?.message||e.detail||"Failed to ingest document")}return await u.json()}catch(e){throw console.error("Error ingesting document:",e),e}},rY=async e=>{try{let t=$?`${$}/email/event_settings`:"/email/event_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to get email event settings")}let n=await r.json();return console.log("Email event settings response:",n),n}catch(e){throw console.error("Failed to get email event settings:",e),e}},rZ=async(e,t)=>{try{let r=$?`${$}/email/event_settings`:"/email/event_settings",n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to update email event settings")}let o=await n.json();return console.log("Update email event settings response:",o),o}catch(e){throw console.error("Failed to update email event settings:",e),e}},rQ=async e=>{try{let t=$?`${$}/email/event_settings/reset`:"/email/event_settings/reset",r=await fetch(t,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to reset email event settings")}let n=await r.json();return console.log("Reset email event settings response:",n),n}catch(e){throw console.error("Failed to reset email event settings:",e),e}},r0=async(e,t)=>{try{let r=$?`${$}/v1/agents/${t}`:`/v1/agents/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Delete agent response:",o),o}catch(e){throw console.error("Failed to delete agent:",e),e}},r1=async(e,t)=>{try{let r=$?`${$}/v1/agents/make_public`:"/v1/agents/make_public",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({agent_ids:t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Make agents public response:",o),o}catch(e){throw console.error("Failed to make agents public:",e),e}},r2=async(e,t)=>{try{let r=$?`${$}/v1/mcp/make_public`:"/v1/mcp/make_public",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({mcp_server_ids:t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Make agents public response:",o),o}catch(e){throw console.error("Failed to make agents public:",e),e}},r4=async(e,t)=>{try{let r=$?`${$}/guardrails/${t}`:`/guardrails/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Delete guardrail response:",o),o}catch(e){throw console.error("Failed to delete guardrail:",e),e}},r6=async e=>{try{let t=$?`${$}/guardrails/ui/add_guardrail_settings`:"/guardrails/ui/add_guardrail_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to get guardrail UI settings")}let n=await r.json();return console.log("Guardrail UI settings response:",n),n}catch(e){throw console.error("Failed to get guardrail UI settings:",e),e}},r3=async e=>{try{let t=$?`${$}/guardrails/ui/provider_specific_params`:"/guardrails/ui/provider_specific_params",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to get guardrail provider specific parameters")}let n=await r.json();return console.log("Guardrail provider specific params response:",n),n}catch(e){throw console.error("Failed to get guardrail provider specific parameters:",e),e}},r7=async(e,t)=>{try{let r=encodeURIComponent(t),n=$?`${$}/guardrails/ui/category_yaml/${r}`:`/guardrails/ui/category_yaml/${r}`;console.log(`Fetching category YAML from: ${n}`);let o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw console.error(`Failed to get category YAML. Status: ${o.status}, Error:`,e),j(e),Error(`Failed to get category YAML: ${o.status} ${e}`)}let a=await o.json();return console.log("Category YAML response:",a),a}catch(e){throw console.error("Failed to get category YAML:",e),e}},r5=async e=>{try{let t=$?`${$}/guardrails/ui/major_airlines`:"/guardrails/ui/major_airlines",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw console.error(`Failed to get major airlines. Status: ${r.status}, Error:`,e),j(e),Error(`Failed to get major airlines: ${r.status} ${e}`)}return await r.json()}catch(e){throw console.error("Failed to get major airlines:",e),e}},r9=async(e,t=!1)=>{try{let r=t?"?health_check=true":"",n=$?`${$}/v1/agents${r}`:`/v1/agents${r}`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw j(e),Error("Failed to get agents list")}let a=await o.json();return console.log("Agents list response:",a),{agents:a}}catch(e){throw console.error("Failed to get agents list:",e),e}},r8=async(e,t)=>{try{let r=$?`${$}/v1/agents/${t}`:`/v1/agents/${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to get agent info")}let o=await n.json();return console.log("Agent info response:",o),o}catch(e){throw console.error("Failed to get agent info:",e),e}},ne=async(e,t)=>{try{let r=$?`${$}/guardrails/${t}/info`:`/guardrails/${t}/info`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to get guardrail info")}let o=await n.json();return console.log("Guardrail info response:",o),o}catch(e){throw console.error("Failed to get guardrail info:",e),e}},nt=async(e,t,r)=>{try{let n=$?`${$}/v1/agents/${t}`:`/v1/agents/${t}`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.text();throw j(e),Error("Failed to patch agent")}let a=await o.json();return console.log("Patch agent response:",a),a}catch(e){throw console.error("Failed to update guardrail:",e),e}},nr=async(e,t,r)=>{try{let n=$?`${$}/guardrails/${t}`:`/guardrails/${t}`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.text();throw j(e),Error("Failed to update guardrail")}let a=await o.json();return console.log("Update guardrail response:",a),a}catch(e){throw console.error("Failed to update guardrail:",e),e}},nn=async(e,t,r,n,o)=>{try{let a=$?`${$}/guardrails/apply_guardrail`:"/guardrails/apply_guardrail",i={guardrail_name:t,text:r};n&&(i.language=n),o&&o.length>0&&(i.entities=o);let l=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!l.ok){let e=await l.text(),t="Failed to apply guardrail";try{let r=JSON.parse(e);r.error?.message?t=r.error.message:r.detail?t=r.detail:r.message&&(t=r.message)}catch(r){t=e||t}throw j(e),Error(t)}let s=await l.json();return console.log("Apply guardrail response:",s),s}catch(e){throw console.error("Failed to apply guardrail:",e),e}},no=async(e,t)=>{try{let r=$?`${$}/guardrails/test_custom_code`:"/guardrails/test_custom_code",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.text(),t="Failed to test custom code guardrail";try{let r=JSON.parse(e);r.error?.message?t=r.error.message:r.detail?t=r.detail:r.message&&(t=r.message)}catch(r){t=e||t}throw j(e),Error(t)}let o=await n.json();return console.log("Test custom code guardrail response:",o),o}catch(e){throw console.error("Failed to test custom code guardrail:",e),e}},na=async(e,t)=>{try{let r=$?`${$}/guardrails/validate_blocked_words_file`:"/guardrails/validate_blocked_words_file",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({file_content:t})});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to validate blocked words file")}let o=await n.json();return console.log("Validate blocked words file response:",o),o}catch(e){throw console.error("Failed to validate blocked words file:",e),e}},ni=async e=>{try{let t=$?`${$}/get/sso_settings`:"/get/sso_settings";console.log("Fetching SSO configuration from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched SSO configuration:",n),n}catch(e){throw console.error("Failed to fetch SSO configuration:",e),e}},nl=async(e,t)=>{try{let r=$?`${$}/update/sso_settings`:"/update/sso_settings";console.log("Updating SSO configuration:",t);let n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t="object"==typeof e?.detail?e.detail?.error||e.detail?.message:e?.detail,r="string"==typeof t&&t.length>0?t:nj(e);j(r);let o=Error(r);throw e?.detail!==void 0&&(o.detail=e.detail),o.rawError=e,o}let o=await n.json();return console.log("Updated SSO configuration:",o),o}catch(e){throw console.error("Failed to update SSO configuration:",e),e}},ns=async({accessToken:e,page:t=1,page_size:r=50,params:n={}})=>{try{let o=$?`${$}/audit`:"/audit",a=new URLSearchParams;for(let[e,o]of(a.append("page",t.toString()),a.append("page_size",r.toString()),Object.entries(n)))null!=o&&""!==o&&a.append(e,String(o));o+=`?${a.toString()}`;let i=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nj(e);throw j(t),Error(t)}return await i.json()}catch(e){throw console.error("Failed to fetch audit logs:",e),e}},nc=async e=>{try{let t=$?`${$}/user/available_users`:"/user/available_users",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok){if(404===r.status)return null;let e=await r.text();throw j(e),Error("Network response was not ok")}return await r.json()}catch(e){throw console.error("Failed to fetch remaining users:",e),e}},nu=async e=>{try{let t=$?`${$}/health/license`:"/health/license",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok){if(404===r.status)return null;let e=await r.text();throw j(e),Error("Network response was not ok")}return await r.json()}catch(e){throw console.error("Failed to fetch license info:",e),e}},nd=async(e,t,r)=>{try{let n=$?`${$}/config/pass_through_endpoint/${encodeURIComponent(t)}`:`/config/pass_through_endpoint/${encodeURIComponent(t)}`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return g.default.success("Pass through endpoint updated successfully"),a}catch(e){throw console.error("Failed to update pass through endpoint:",e),e}},nf=async(e,t)=>{try{let r=$?`${$}/config/callback/delete`:"/config/callback/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({callback_name:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete specific callback:",e),e}},np=async(e,t,r)=>{try{console.log("Testing MCP tools list with config:",JSON.stringify(t));let n=$?`${$}/mcp-rest/test/tools/list`:"/mcp-rest/test/tools/list",o={"Content-Type":"application/json"};e&&(o["x-litellm-api-key"]=e),r?o.Authorization=`Bearer ${r}`:e&&(o[T]=`Bearer ${e}`);let a=await fetch(n,{method:"POST",headers:o,body:JSON.stringify(t)}),i=a.headers.get("content-type");if(!i||!i.includes("application/json")){let e=await a.text();throw console.error("Received non-JSON response:",e),Error(`Received non-JSON response (${a.status}: ${a.statusText}). Check network tab for details.`)}let l=await a.json();if((!a.ok||l.error)&&!l.error)return{tools:[],error:"request_failed",message:l.message||`MCP tools list failed: ${a.status} ${a.statusText}`};return l}catch(e){throw console.error("MCP tools list test error:",e),e}},nm=async(e,t)=>{let r=$?`${$}/v1/mcp/server/oauth/session`:"/v1/mcp/server/oauth/session",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)}),o=await n.json();if(!n.ok)throw Error(nj(o)||o?.error||"Failed to cache MCP server");return o},nh=async(e,t,r)=>{let n=C(),o=encodeURIComponent(t.trim()),a=`${n}/v1/mcp/server/oauth/${o}/register`,i=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json",Accept:"application/json, text/event-stream"},body:JSON.stringify(r)}),l=await i.json();if(!i.ok)throw Error(nj(l)||l?.detail||"Failed to register OAuth client");return l},ng=({serverId:e,clientId:t,redirectUri:r,state:n,codeChallenge:o,scope:a})=>{let i=C(),l=encodeURIComponent(e.trim()),s=`${i}/v1/mcp/server/oauth/${l}/authorize`,c=new URLSearchParams({redirect_uri:r,state:n,response_type:"code",code_challenge:o,code_challenge_method:"S256"});return t&&t.trim().length>0&&c.set("client_id",t),a&&a.trim().length>0&&c.set("scope",a),`${s}?${c.toString()}`},nv=async({serverId:e,code:t,clientId:r,clientSecret:n,codeVerifier:o,redirectUri:a})=>{let i=C(),l=encodeURIComponent(e.trim()),s=`${i}/v1/mcp/server/oauth/${l}/token`,c=new URLSearchParams;c.set("grant_type","authorization_code"),c.set("code",t),r&&r.trim().length>0&&c.set("client_id",r),n&&n.trim().length>0&&c.set("client_secret",n),c.set("code_verifier",o),c.set("redirect_uri",a);let u=await fetch(s,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:c.toString()}),d=await u.json();if(!u.ok)throw Error(nj(d)||d?.detail||"OAuth token exchange failed");return d},ny=async(e,t,r)=>{try{let n=`${C()}/v1/vector_stores/${t}/search`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({query:r})});if(!o.ok){let e=await o.text();return await j(e),null}return await o.json()}catch(e){throw console.error("Error testing vector store search:",e),e}},nb=async(e,t,r,n)=>{try{let o=`${C()}/v1/search/${t}`,a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({query:r,max_results:n||5})});if(!a.ok){let e=await a.text();return await j(e),null}return await a.json()}catch(e){throw console.error("Error querying search tool:",e),e}},nw=async(e,t,r,n)=>{try{let o,a,i,l=$?`${$}/tag/dau`:"/tag/dau",s=new URLSearchParams;s.append("end_date",(o=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0"),`${o}-${a}-${i}`)),n&&n.length>0?n.forEach(e=>{s.append("tag_filters",e)}):r&&s.append("tag_filter",r);let c=s.toString();c&&(l+=`?${c}`);let u=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!u.ok){let e=await u.json(),t=nj(e);throw j(t),Error(t)}return await u.json()}catch(e){throw console.error("Failed to fetch DAU:",e),e}},n$=async(e,t,r,n)=>{try{let o,a,i,l=$?`${$}/tag/wau`:"/tag/wau",s=new URLSearchParams;s.append("end_date",(o=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0"),`${o}-${a}-${i}`)),n&&n.length>0?n.forEach(e=>{s.append("tag_filters",e)}):r&&s.append("tag_filter",r);let c=s.toString();c&&(l+=`?${c}`);let u=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!u.ok){let e=await u.json(),t=nj(e);throw j(t),Error(t)}return await u.json()}catch(e){throw console.error("Failed to fetch WAU:",e),e}},nC=async(e,t,r,n)=>{try{let o,a,i,l=$?`${$}/tag/mau`:"/tag/mau",s=new URLSearchParams;s.append("end_date",(o=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0"),`${o}-${a}-${i}`)),n&&n.length>0?n.forEach(e=>{s.append("tag_filters",e)}):r&&s.append("tag_filter",r);let c=s.toString();c&&(l+=`?${c}`);let u=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!u.ok){let e=await u.json(),t=nj(e);throw j(t),Error(t)}return await u.json()}catch(e){throw console.error("Failed to fetch MAU:",e),e}},nE=async e=>{try{let t=$?`${$}/tag/distinct`:"/tag/distinct",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to fetch distinct tags:",e),e}},nS=async(e,t,r,n)=>{try{let o=$?`${$}/tag/summary`:"/tag/summary",a=new URLSearchParams,i=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${n}`};a.append("start_date",i(t)),a.append("end_date",i(r)),n&&n.length>0&&n.forEach(e=>{a.append("tag_filters",e)});let l=a.toString();l&&(o+=`?${l}`);let s=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nj(e);throw j(t),Error(t)}return await s.json()}catch(e){throw console.error("Failed to fetch user agent summary:",e),e}},nx=async(e,t=1,r=50,n)=>{try{let o=$?`${$}/tag/user-agent/per-user-analytics`:"/tag/user-agent/per-user-analytics",a=new URLSearchParams;a.append("page",t.toString()),a.append("page_size",r.toString()),n&&n.length>0&&n.forEach(e=>{a.append("tag_filters",e)});let i=a.toString();i&&(o+=`?${i}`);let l=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!l.ok){let e=await l.json(),t=nj(e);throw j(t),Error(t)}return await l.json()}catch(e){throw console.error("Failed to fetch per-user analytics:",e),e}},nj=e=>{let t=e?.detail,r=Array.isArray(t)?t.map(e=>e?.msg||JSON.stringify(e)).join("; "):"string"==typeof t?t:void 0;return e?.error&&(e.error.message||("string"==typeof e.error?e.error:void 0))||e?.message||r||JSON.stringify(e)},nO=async(e,t)=>{let r=C(),n=r?`${r}/v2/login`:"/v2/login",o=JSON.stringify({username:e,password:t}),a=await fetch(n,{method:"POST",body:o,credentials:"include",headers:{"Content-Type":"application/json"}});if(!a.ok)throw Error(nj(await a.json()));return await a.json()},nk=async()=>{let e=C(),t=e?`${e}/get/ui_settings`:"/get/ui_settings",r=await fetch(t,{method:"GET"});if(!r.ok)throw Error(nj(await r.json()));return await r.json()},nT=async(e,t)=>{let r=C(),n=r?`${r}/update/ui_settings`:"/update/ui_settings",o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok)throw Error(nj(await o.json()));return await o.json()},nF=async()=>{try{let e=C(),t=e?`${e}/claude-code/marketplace.json`:"/claude-code/marketplace.json",r=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"}});if(!r.ok){let e=await r.text(),t=nj(JSON.parse(e));throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to fetch Claude Code marketplace:",e),e}},n_=async(e,t=!1)=>{try{let r=C(),n=r?`${r}/claude-code/plugins?enabled_only=${t}`:`/claude-code/plugins?enabled_only=${t}`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nj(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to fetch Claude Code plugins list:",e),e}},nI=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}`:`/claude-code/plugins/${t}`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nj(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to fetch plugin "${t}":`,e),e}},nP=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins`:"/claude-code/plugins",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.text(),t=nj(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to register Claude Code plugin:",e),e}},nN=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}/enable`:`/claude-code/plugins/${t}/enable`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nj(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to enable plugin "${t}":`,e),e}},nR=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}/disable`:`/claude-code/plugins/${t}/disable`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nj(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to disable plugin "${t}":`,e),e}},nM=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}`:`/claude-code/plugins/${t}`,o=await fetch(n,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nj(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to delete plugin "${t}":`,e),e}},nB=async(e,t)=>{let r=$?`${$}/compliance/eu-ai-act`:"/compliance/eu-ai-act",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok)throw Error(await n.text());return n.json()},nA=async(e,t)=>{let r=$?`${$}/compliance/gdpr`:"/compliance/gdpr",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok)throw Error(await n.text());return n.json()},nz=async e=>{let t=$?`${$}/v1/tool/policy/options`:"/v1/tool/policy/options",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok)throw Error(await r.text());return r.json()},nL=async e=>{let t=$?`${$}/v1/tool/list`:"/v1/tool/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok)throw Error(await r.text());return(await r.json()).tools??[]},nH=async(e,t,r)=>{let n=encodeURIComponent(t),o=$?`${$}/v1/tool/${n}/logs`:`/v1/tool/${n}/logs`,a=new URLSearchParams;null!=r.page&&a.append("page",String(r.page)),null!=r.pageSize&&a.append("page_size",String(r.pageSize)),r.startDate&&a.append("start_date",r.startDate),r.endDate&&a.append("end_date",r.endDate);let i=a.toString()?`${o}?${a.toString()}`:o,l=await fetch(i,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!l.ok)throw Error(nj(await l.json().catch(()=>({}))));return l.json()},nD=async(e,t)=>{let r=encodeURIComponent(t),n=$?`${$}/v1/tool/${r}/detail`:`/v1/tool/${r}/detail`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok)throw Error(await o.text());return o.json()},nV=async(e,t,r,n)=>{let o=$?`${$}/v1/tool/policy`:"/v1/tool/policy",a={tool_name:t};null!=r.input_policy&&(a.input_policy=r.input_policy),null!=r.output_policy&&(a.output_policy=r.output_policy),n?.team_id!=null&&(a.team_id=n.team_id||void 0),n?.key_hash!=null&&(a.key_hash=n.key_hash||void 0),n?.key_alias!=null&&(a.key_alias=n.key_alias||void 0);let i=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(a)});if(!i.ok)throw Error(await i.text());return i.json()},nW=async(e,t,r)=>{let n=encodeURIComponent(t),o=new URLSearchParams;null!=r.team_id&&""!==r.team_id&&o.set("team_id",r.team_id),null!=r.key_hash&&""!==r.key_hash&&o.set("key_hash",r.key_hash);let a=o.toString(),i=$?`${$}/v1/tool/${n}/overrides${a?`?${a}`:""}`:`/v1/tool/${n}/overrides${a?`?${a}`:""}`,l=await fetch(i,{method:"DELETE",headers:{[T]:`Bearer ${e}`}});if(!l.ok)throw Error(await l.text());return l.json()},nG=async(e,t,r)=>{let n=$?`${$}/v1/mcp/server/${t}/oauth-user-credential`:`/v1/mcp/server/${t}/oauth-user-credential`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json().catch(()=>({})),t=e?.detail;throw Error((Array.isArray(t)?t.map(e=>e&&"object"==typeof e?e.msg??JSON.stringify(e):String(e)).join("; "):"string"==typeof t?t:t&&"string"==typeof t.error?t.error:void 0)||"Failed to store OAuth credential")}return o.json()},nU=async(e,t)=>{let r=$?`${$}/v1/mcp/server/${t}/oauth-user-credential`:`/v1/mcp/server/${t}/oauth-user-credential`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`}});if(!n.ok){let e=await n.json().catch(()=>({})),t=e?.detail;throw Error((Array.isArray(t)?t.map(e=>e&&"object"==typeof e?e.msg??JSON.stringify(e):String(e)).join("; "):"string"==typeof t?t:t&&"string"==typeof t.error?t.error:void 0)||"Failed to revoke OAuth credential")}return n.json()},nq=async(e,t)=>{let r=$?`${$}/v1/mcp/server/${t}/oauth-user-credential/status`:`/v1/mcp/server/${t}/oauth-user-credential/status`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`}});return n.ok?n.json():{server_id:t,has_credential:!1,is_expired:!1}},nJ=async e=>{let t=$?`${$}/v1/mcp/user-credentials`:"/v1/mcp/user-credentials",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});return r.ok?r.json():[]}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/123bb7375879d789.js b/litellm/proxy/_experimental/out/_next/static/chunks/123bb7375879d789.js new file mode 100644 index 0000000000..b23ef2ae7e --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/123bb7375879d789.js @@ -0,0 +1,3 @@ +(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,517442,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(592968);let l=e=>e>=.8?"text-green-600":"text-yellow-600",r=({entities:e})=>{let[a,r]=(0,s.useState)(!0),[i,n]=(0,s.useState)({});return e&&0!==e.length?(0,t.jsxs)("div",{className:"mt-4",children:[(0,t.jsxs)("div",{className:"flex items-center mb-2 cursor-pointer",onClick:()=>r(!a),children:[(0,t.jsx)("svg",{className:`w-5 h-5 mr-2 transition-transform ${a?"transform rotate-90":""}`,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"})}),(0,t.jsxs)("h4",{className:"font-medium",children:["Detected Entities (",e.length,")"]})]}),a&&(0,t.jsx)("div",{className:"space-y-2",children:e.map((e,s)=>{let a=i[s]||!1;return(0,t.jsxs)("div",{className:"border rounded-lg overflow-hidden",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between p-3 bg-gray-50 cursor-pointer hover:bg-gray-100",onClick:()=>{n(e=>({...e,[s]:!e[s]}))},children:[(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)("svg",{className:`w-5 h-5 mr-2 transition-transform ${a?"transform rotate-90":""}`,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"})}),(0,t.jsx)("span",{className:"font-medium mr-2",children:e.entity_type}),(0,t.jsxs)("span",{className:`font-mono ${l(e.score)}`,children:["Score: ",e.score.toFixed(2)]})]}),(0,t.jsxs)("span",{className:"text-xs text-gray-500",children:["Position: ",e.start,"-",e.end]})]}),a&&(0,t.jsx)("div",{className:"p-3 border-t bg-white",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4 mb-2",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Entity Type:"}),(0,t.jsx)("span",{children:e.entity_type})]}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Position:"}),(0,t.jsxs)("span",{children:["Characters ",e.start,"-",e.end]})]}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Confidence:"}),(0,t.jsx)("span",{className:l(e.score),children:e.score.toFixed(2)})]})]}),(0,t.jsxs)("div",{className:"space-y-2",children:[e.recognition_metadata&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Recognizer:"}),(0,t.jsx)("span",{children:e.recognition_metadata.recognizer_name})]}),(0,t.jsxs)("div",{className:"flex overflow-hidden",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Identifier:"}),(0,t.jsx)("span",{className:"truncate text-xs font-mono",children:e.recognition_metadata.recognizer_identifier})]})]}),e.analysis_explanation&&(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Explanation:"}),(0,t.jsx)("span",{children:e.analysis_explanation})]})]})]})})]},s)})})]}):null},i=(e,s="slate")=>(0,t.jsx)("span",{className:`px-2 py-1 rounded-md text-xs font-medium inline-block ${{green:"bg-green-100 text-green-800",red:"bg-red-100 text-red-800",blue:"bg-blue-50 text-blue-700",slate:"bg-slate-100 text-slate-800",amber:"bg-amber-100 text-amber-800"}[s]}`,children:e}),n=e=>e?i("detected","red"):i("not detected","slate"),o=({title:e,count:a,defaultOpen:l=!0,right:r,children:i})=>{let[n,o]=(0,s.useState)(l);return(0,t.jsxs)("div",{className:"border rounded-lg overflow-hidden",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between p-3 bg-gray-50 cursor-pointer hover:bg-gray-100",onClick:()=>o(e=>!e),children:[(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)("svg",{className:`w-5 h-5 mr-2 transition-transform ${n?"transform rotate-90":""}`,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"})}),(0,t.jsxs)("h5",{className:"font-medium",children:[e," ","number"==typeof a&&(0,t.jsxs)("span",{className:"text-gray-500 font-normal",children:["(",a,")"]})]})]}),(0,t.jsx)("div",{children:r})]}),n&&(0,t.jsx)("div",{className:"p-3 border-t bg-white",children:i})]})},d=({label:e,children:s,mono:a})=>(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:e}),(0,t.jsx)("span",{className:a?"font-mono text-sm break-all":"",children:s})]}),c=()=>(0,t.jsx)("div",{className:"my-3 border-t"}),m=({response:e})=>{if(!e)return null;let s=e.outputs??e.output??[],a="GUARDRAIL_INTERVENED"===e.action?"red":"green",l=(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[e.guardrailCoverage?.textCharacters&&i(`text guarded ${e.guardrailCoverage.textCharacters.guarded??0}/${e.guardrailCoverage.textCharacters.total??0}`,"blue"),e.guardrailCoverage?.images&&i(`images guarded ${e.guardrailCoverage.images.guarded??0}/${e.guardrailCoverage.images.total??0}`,"blue")]}),r=e.usage&&(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:Object.entries(e.usage).map(([e,s])=>"number"==typeof s?(0,t.jsxs)("span",{className:"px-2 py-1 bg-slate-100 text-slate-800 rounded-md text-xs font-medium",children:[e,": ",s]},e):null)});return(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"border rounded-lg p-4",children:[(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)(d,{label:"Action:",children:i(e.action??"N/A",a)}),e.actionReason&&(0,t.jsx)(d,{label:"Action Reason:",children:e.actionReason}),e.blockedResponse&&(0,t.jsx)(d,{label:"Blocked Response:",children:(0,t.jsx)("span",{className:"italic",children:e.blockedResponse})})]}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)(d,{label:"Coverage:",children:l}),(0,t.jsx)(d,{label:"Usage:",children:r})]})]}),s.length>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(c,{}),(0,t.jsx)("h4",{className:"font-medium mb-2",children:"Outputs"}),(0,t.jsx)("div",{className:"space-y-2",children:s.map((e,s)=>(0,t.jsx)("div",{className:"p-3 bg-gray-50 rounded-md",children:(0,t.jsx)("div",{className:"text-sm whitespace-pre-wrap",children:e.text??(0,t.jsx)("em",{children:"(non-text output)"})})},s))})]})]}),e.assessments?.length?(0,t.jsx)("div",{className:"space-y-3",children:e.assessments.map((e,s)=>{let a=(0,t.jsxs)("div",{className:"flex flex-wrap gap-1",children:[e.wordPolicy&&i("word","slate"),e.contentPolicy&&i("content","slate"),e.topicPolicy&&i("topic","slate"),e.sensitiveInformationPolicy&&i("sensitive-info","slate"),e.contextualGroundingPolicy&&i("contextual-grounding","slate"),e.automatedReasoningPolicy&&i("automated-reasoning","slate")]});return(0,t.jsxs)(o,{title:`Assessment #${s+1}`,defaultOpen:!0,right:(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[e.invocationMetrics?.guardrailProcessingLatency!=null&&i(`${e.invocationMetrics.guardrailProcessingLatency} ms`,"amber"),a]}),children:[e.wordPolicy&&(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h6",{className:"font-medium mb-2",children:"Word Policy"}),(e.wordPolicy.customWords?.length??0)>0&&(0,t.jsx)(o,{title:"Custom Words",defaultOpen:!0,children:(0,t.jsx)("div",{className:"space-y-2",children:e.wordPolicy.customWords.map((e,s)=>(0,t.jsxs)("div",{className:"flex justify-between items-center p-2 bg-gray-50 rounded",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[i(e.action??"N/A",e.detected?"red":"slate"),(0,t.jsx)("span",{className:"font-mono text-sm break-all",children:e.match})]}),n(e.detected)]},s))})}),(e.wordPolicy.managedWordLists?.length??0)>0&&(0,t.jsx)(o,{title:"Managed Word Lists",defaultOpen:!1,children:(0,t.jsx)("div",{className:"space-y-2",children:e.wordPolicy.managedWordLists.map((e,s)=>(0,t.jsxs)("div",{className:"flex justify-between items-center p-2 bg-gray-50 rounded",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[i(e.action??"N/A",e.detected?"red":"slate"),(0,t.jsx)("span",{className:"font-mono text-sm break-all",children:e.match}),e.type&&i(e.type,"slate")]}),n(e.detected)]},s))})})]}),e.contentPolicy?.filters?.length?(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h6",{className:"font-medium mb-2",children:"Content Policy"}),(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)("table",{className:"min-w-full text-sm",children:[(0,t.jsx)("thead",{children:(0,t.jsxs)("tr",{className:"text-left text-gray-600",children:[(0,t.jsx)("th",{className:"py-1 pr-4",children:"Type"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Action"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Detected"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Strength"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Confidence"})]})}),(0,t.jsx)("tbody",{children:e.contentPolicy.filters.map((e,s)=>(0,t.jsxs)("tr",{className:"border-t",children:[(0,t.jsx)("td",{className:"py-1 pr-4",children:e.type??"—"}),(0,t.jsx)("td",{className:"py-1 pr-4",children:i(e.action??"—",e.detected?"red":"slate")}),(0,t.jsx)("td",{className:"py-1 pr-4",children:n(e.detected)}),(0,t.jsx)("td",{className:"py-1 pr-4",children:e.filterStrength??"—"}),(0,t.jsx)("td",{className:"py-1 pr-4",children:e.confidence??"—"})]},s))})]})})]}):null,e.contextualGroundingPolicy?.filters?.length?(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h6",{className:"font-medium mb-2",children:"Contextual Grounding"}),(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)("table",{className:"min-w-full text-sm",children:[(0,t.jsx)("thead",{children:(0,t.jsxs)("tr",{className:"text-left text-gray-600",children:[(0,t.jsx)("th",{className:"py-1 pr-4",children:"Type"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Action"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Detected"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Score"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Threshold"})]})}),(0,t.jsx)("tbody",{children:e.contextualGroundingPolicy.filters.map((e,s)=>(0,t.jsxs)("tr",{className:"border-t",children:[(0,t.jsx)("td",{className:"py-1 pr-4",children:e.type??"—"}),(0,t.jsx)("td",{className:"py-1 pr-4",children:i(e.action??"—",e.detected?"red":"slate")}),(0,t.jsx)("td",{className:"py-1 pr-4",children:n(e.detected)}),(0,t.jsx)("td",{className:"py-1 pr-4",children:e.score??"—"}),(0,t.jsx)("td",{className:"py-1 pr-4",children:e.threshold??"—"})]},s))})]})})]}):null,e.sensitiveInformationPolicy&&(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h6",{className:"font-medium mb-2",children:"Sensitive Information"}),(e.sensitiveInformationPolicy.piiEntities?.length??0)>0&&(0,t.jsx)(o,{title:"PII Entities",defaultOpen:!0,children:(0,t.jsx)("div",{className:"space-y-2",children:e.sensitiveInformationPolicy.piiEntities.map((e,s)=>(0,t.jsxs)("div",{className:"flex justify-between items-center p-2 bg-gray-50 rounded",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[i(e.action??"N/A",e.detected?"red":"slate"),e.type&&i(e.type,"slate"),(0,t.jsx)("span",{className:"font-mono text-xs break-all",children:e.match})]}),n(e.detected)]},s))})}),(e.sensitiveInformationPolicy.regexes?.length??0)>0&&(0,t.jsx)(o,{title:"Custom Regexes",defaultOpen:!1,children:(0,t.jsx)("div",{className:"space-y-2",children:e.sensitiveInformationPolicy.regexes.map((e,s)=>(0,t.jsxs)("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between p-2 bg-gray-50 rounded gap-1",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[i(e.action??"N/A",e.detected?"red":"slate"),(0,t.jsx)("span",{className:"font-medium",children:e.name??"regex"}),(0,t.jsx)("span",{className:"font-mono text-xs break-all",children:e.regex})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[n(e.detected),e.match&&(0,t.jsx)("span",{className:"font-mono text-xs break-all",children:e.match})]})]},s))})})]}),e.topicPolicy?.topics?.length?(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h6",{className:"font-medium mb-2",children:"Topic Policy"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:e.topicPolicy.topics.map((e,s)=>(0,t.jsx)("div",{className:"px-3 py-1.5 bg-gray-50 rounded-md text-xs",children:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[i(e.action??"N/A",e.detected?"red":"slate"),(0,t.jsx)("span",{className:"font-medium",children:e.name??"topic"}),e.type&&i(e.type,"slate"),n(e.detected)]})},s))})]}):null,e.invocationMetrics&&(0,t.jsx)(o,{title:"Invocation Metrics",defaultOpen:!1,children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)(d,{label:"Latency (ms)",children:e.invocationMetrics.guardrailProcessingLatency??"—"}),(0,t.jsx)(d,{label:"Coverage:",children:(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[e.invocationMetrics.guardrailCoverage?.textCharacters&&i(`text ${e.invocationMetrics.guardrailCoverage.textCharacters.guarded??0}/${e.invocationMetrics.guardrailCoverage.textCharacters.total??0}`,"blue"),e.invocationMetrics.guardrailCoverage?.images&&i(`images ${e.invocationMetrics.guardrailCoverage.images.guarded??0}/${e.invocationMetrics.guardrailCoverage.images.total??0}`,"blue")]})})]}),(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsx)(d,{label:"Usage:",children:(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:e.invocationMetrics.usage&&Object.entries(e.invocationMetrics.usage).map(([e,s])=>"number"==typeof s?(0,t.jsxs)("span",{className:"px-2 py-1 bg-slate-100 text-slate-800 rounded-md text-xs font-medium",children:[e,": ",s]},e):null)})})})]})}),e.automatedReasoningPolicy?.findings?.length?(0,t.jsx)(o,{title:"Automated Reasoning Findings",defaultOpen:!1,children:(0,t.jsx)("div",{className:"space-y-2",children:e.automatedReasoningPolicy.findings.map((e,s)=>(0,t.jsx)("pre",{className:"bg-gray-50 rounded p-2 text-xs overflow-x-auto",children:JSON.stringify(e,null,2)},s))})}):null]},s)})}):null,(0,t.jsx)(o,{title:"Raw Bedrock Guardrail Response",defaultOpen:!1,children:(0,t.jsx)("pre",{className:"bg-gray-50 rounded p-3 text-xs overflow-x-auto",children:JSON.stringify(e,null,2)})})]})},x=(e,s="slate")=>(0,t.jsx)("span",{className:`px-2 py-1 rounded-md text-xs font-medium inline-block ${{green:"bg-green-100 text-green-800",red:"bg-red-100 text-red-800",blue:"bg-blue-50 text-blue-700",slate:"bg-slate-100 text-slate-800",amber:"bg-amber-100 text-amber-800"}[s]}`,children:e}),u=({title:e,count:a,defaultOpen:l=!0,children:r})=>{let[i,n]=(0,s.useState)(l);return(0,t.jsxs)("div",{className:"border rounded-lg overflow-hidden",children:[(0,t.jsx)("div",{className:"flex items-center justify-between p-3 bg-gray-50 cursor-pointer hover:bg-gray-100",onClick:()=>n(e=>!e),children:(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)("svg",{className:`w-5 h-5 mr-2 transition-transform ${i?"transform rotate-90":""}`,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"})}),(0,t.jsxs)("h5",{className:"font-medium",children:[e," ","number"==typeof a&&(0,t.jsxs)("span",{className:"text-gray-500 font-normal",children:["(",a,")"]})]})]})}),i&&(0,t.jsx)("div",{className:"p-3 border-t bg-white",children:r})]})},p=({label:e,children:s,mono:a})=>(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:e}),(0,t.jsx)("span",{className:a?"font-mono text-sm break-all":"",children:s})]}),h=({response:e})=>{if(!e||"string"==typeof e)return"string"==typeof e&&e?(0,t.jsx)("div",{className:"bg-white rounded-lg border border-red-200 p-4",children:(0,t.jsxs)("div",{className:"text-red-800",children:[(0,t.jsx)("h5",{className:"font-medium mb-2",children:"Error"}),(0,t.jsx)("p",{className:"text-sm",children:e})]})}):null;let s=Array.isArray(e)?e:[];if(0===s.length)return(0,t.jsx)("div",{className:"bg-white rounded-lg border border-gray-200 p-4",children:(0,t.jsx)("div",{className:"text-gray-600 text-sm",children:"No detections found"})});let a=s.filter(e=>"pattern"===e.type),l=s.filter(e=>"blocked_word"===e.type),r=s.filter(e=>"category_keyword"===e.type),i=s.filter(e=>"BLOCK"===e.action).length,n=s.filter(e=>"MASK"===e.action).length,o=s.length;return(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsx)("div",{className:"bg-white rounded-lg border border-gray-200 p-4",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)(p,{label:"Total Detections:",children:(0,t.jsx)("span",{className:"font-semibold",children:o})}),(0,t.jsx)(p,{label:"Actions:",children:(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[i>0&&x(`${i} blocked`,"red"),n>0&&x(`${n} masked`,"blue"),0===i&&0===n&&x("passed","green")]})})]}),(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsx)(p,{label:"By Type:",children:(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[a.length>0&&x(`${a.length} patterns`,"slate"),l.length>0&&x(`${l.length} keywords`,"slate"),r.length>0&&x(`${r.length} categories`,"slate")]})})})]})}),a.length>0&&(0,t.jsx)(u,{title:"Patterns Matched",count:a.length,defaultOpen:!0,children:(0,t.jsx)("div",{className:"space-y-2",children:a.map((e,s)=>(0,t.jsx)("div",{className:"p-3 bg-gray-50 rounded-md",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsx)("div",{className:"space-y-1",children:(0,t.jsx)(p,{label:"Pattern:",children:e.pattern_name||"unknown"})}),(0,t.jsx)("div",{className:"space-y-1",children:(0,t.jsx)(p,{label:"Action:",children:x(e.action,"BLOCK"===e.action?"red":"blue")})})]})},s))})}),l.length>0&&(0,t.jsx)(u,{title:"Blocked Words Detected",count:l.length,defaultOpen:!0,children:(0,t.jsx)("div",{className:"space-y-2",children:l.map((e,s)=>(0,t.jsx)("div",{className:"p-3 bg-gray-50 rounded-md",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-1",children:[(0,t.jsx)(p,{label:"Keyword:",mono:!0,children:e.keyword||"unknown"}),e.description&&(0,t.jsx)(p,{label:"Description:",children:e.description})]}),(0,t.jsx)("div",{className:"space-y-1",children:(0,t.jsx)(p,{label:"Action:",children:x(e.action,"BLOCK"===e.action?"red":"blue")})})]})},s))})}),r.length>0&&(0,t.jsx)(u,{title:"Category Keywords Detected",count:r.length,defaultOpen:!0,children:(0,t.jsx)("div",{className:"space-y-2",children:r.map((e,s)=>(0,t.jsx)("div",{className:"p-3 bg-gray-50 rounded-md",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-1",children:[(0,t.jsx)(p,{label:"Category:",children:e.category||"unknown"}),(0,t.jsx)(p,{label:"Keyword:",mono:!0,children:e.keyword||"unknown"}),e.severity&&(0,t.jsx)(p,{label:"Severity:",children:x(e.severity,"high"===e.severity?"red":"medium"===e.severity?"amber":"slate")})]}),(0,t.jsx)("div",{className:"space-y-1",children:(0,t.jsx)(p,{label:"Action:",children:x(e.action,"BLOCK"===e.action?"red":"blue")})})]})},s))})}),(0,t.jsx)(u,{title:"Raw Detection Data",defaultOpen:!1,children:(0,t.jsx)("pre",{className:"bg-gray-50 rounded p-3 text-xs overflow-x-auto",children:JSON.stringify(s,null,2)})})]})};var g=e.i(764205);let f=()=>(0,t.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:[(0,t.jsx)("circle",{cx:"8",cy:"8",r:"7",stroke:"#16A34A",strokeWidth:"1.5",fill:"#F0FDF4"}),(0,t.jsx)("path",{d:"M5 8l2 2 4-4",stroke:"#16A34A",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})]}),y=()=>(0,t.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:[(0,t.jsx)("circle",{cx:"8",cy:"8",r:"7",stroke:"#DC2626",strokeWidth:"1.5",fill:"#FEF2F2"}),(0,t.jsx)("path",{d:"M6 6l4 4M10 6l-4 4",stroke:"#DC2626",strokeWidth:"1.5",strokeLinecap:"round"})]}),j=()=>(0,t.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",className:"animate-spin",children:[(0,t.jsx)("circle",{cx:"8",cy:"8",r:"6",stroke:"#D1D5DB",strokeWidth:"2"}),(0,t.jsx)("path",{d:"M8 2a6 6 0 0 1 6 6",stroke:"#6366F1",strokeWidth:"2",strokeLinecap:"round"})]}),b=({title:e,data:l,loading:r,error:i})=>{let[n,o]=(0,s.useState)(!1);return(0,t.jsxs)("div",{className:"border border-gray-200 rounded-lg bg-white",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-4 py-3 cursor-pointer hover:bg-gray-50 transition-colors",onClick:()=>o(!n),children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[r?(0,t.jsx)(j,{}):i?(0,t.jsx)(a.Tooltip,{title:i,children:(0,t.jsx)("span",{className:"text-gray-400 text-sm",children:"--"})}):l?.compliant?(0,t.jsx)(f,{}):(0,t.jsx)(y,{}),(0,t.jsx)("span",{className:"font-medium text-sm text-gray-900",children:e})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[!r&&!i&&l&&(0,t.jsx)("span",{className:`px-2 py-0.5 rounded text-[11px] font-semibold uppercase ${l.compliant?"bg-green-100 text-green-700 border border-green-200":"bg-red-100 text-red-700 border border-red-200"}`,children:l.compliant?"COMPLIANT":"NON-COMPLIANT"}),i&&(0,t.jsx)("span",{className:"px-2 py-0.5 rounded text-[11px] font-medium bg-gray-100 text-gray-500 border border-gray-200",children:"UNAVAILABLE"}),(0,t.jsx)("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"none",className:`transition-transform ${n?"rotate-180":""}`,children:(0,t.jsx)("path",{d:"M6 8l4 4 4-4",stroke:"#6B7280",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]})]}),n&&(0,t.jsxs)("div",{className:"border-t border-gray-100 px-4 py-3",children:[r&&(0,t.jsx)("p",{className:"text-sm text-gray-500",children:"Checking compliance..."}),i&&(0,t.jsx)("p",{className:"text-sm text-red-600",children:i}),l&&(0,t.jsx)("div",{className:"space-y-2",children:l.checks.map((e,s)=>(0,t.jsxs)("div",{className:"flex items-start gap-2",children:[(0,t.jsx)("div",{className:"flex-shrink-0 mt-0.5",children:e.passed?(0,t.jsx)(f,{}):(0,t.jsx)(y,{})}),(0,t.jsxs)("div",{className:"min-w-0",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900",children:e.check_name}),(0,t.jsx)("span",{className:"text-[10px] font-mono text-gray-400",children:e.article})]}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5",children:e.detail})]})]},s))})]})]})},v=({accessToken:e,logEntry:a})=>{let[l,r]=(0,s.useState)(null),[i,n]=(0,s.useState)(null),[o,d]=(0,s.useState)(!1),[c,m]=(0,s.useState)(!1),[x,u]=(0,s.useState)(null),[p,h]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(!e||!a.request_id)return;let t={request_id:a.request_id,user_id:a.user,model:a.model,timestamp:a.startTime,guardrail_information:a.metadata?.guardrail_information};d(!0),u(null),(0,g.checkEuAiActCompliance)(e,t).then(r).catch(e=>u(e.message||"Failed to check EU AI Act compliance")).finally(()=>d(!1)),m(!0),h(null),(0,g.checkGdprCompliance)(e,t).then(n).catch(e=>h(e.message||"Failed to check GDPR compliance")).finally(()=>m(!1))},[e,a]),(0,t.jsxs)("div",{children:[(0,t.jsx)("h4",{className:"text-xs font-semibold text-gray-500 uppercase tracking-wider mb-4",children:"Regulatory Compliance"}),(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsx)(b,{title:"EU AI Act",data:l,loading:o,error:x}),(0,t.jsx)(b,{title:"GDPR",data:i,loading:c,error:p})]})]})},_=new Set(["presidio","bedrock","litellm_content_filter"]),N=e=>Object.values(e.masked_entity_count||{}).reduce((e,t)=>e+("number"==typeof t?t:0),0),w=e=>"success"===(e.guardrail_status??"").toLowerCase(),S=e=>e.policy_template||e.guardrail_name,k=()=>(0,t.jsxs)("svg",{width:"40",height:"40",viewBox:"0 0 40 40",fill:"none",children:[(0,t.jsx)("circle",{cx:"20",cy:"20",r:"20",fill:"#EEF2FF"}),(0,t.jsx)("path",{d:"M20 10l8 4v6c0 5.25-3.4 10.15-8 11.5C15.4 30.15 12 25.25 12 20v-6l8-4z",stroke:"#6366F1",strokeWidth:"1.5",fill:"none"}),(0,t.jsx)("path",{d:"M16 20l3 3 5-6",stroke:"#6366F1",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",fill:"none"})]}),C=({className:e})=>(0,t.jsxs)("svg",{width:"22",height:"22",viewBox:"0 0 22 22",fill:"none",className:e,children:[(0,t.jsx)("circle",{cx:"11",cy:"11",r:"10",stroke:"#16A34A",strokeWidth:"1.5",fill:"#F0FDF4"}),(0,t.jsx)("path",{d:"M7 11l3 3 5-6",stroke:"#16A34A",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})]}),T=({className:e})=>(0,t.jsxs)("svg",{width:"22",height:"22",viewBox:"0 0 22 22",fill:"none",className:e,children:[(0,t.jsx)("circle",{cx:"11",cy:"11",r:"10",stroke:"#DC2626",strokeWidth:"1.5",fill:"#FEF2F2"}),(0,t.jsx)("path",{d:"M8 8l6 6M14 8l-6 6",stroke:"#DC2626",strokeWidth:"1.5",strokeLinecap:"round"})]}),L=()=>(0,t.jsxs)("svg",{width:"22",height:"22",viewBox:"0 0 22 22",fill:"none",children:[(0,t.jsx)("circle",{cx:"11",cy:"11",r:"10",stroke:"#3B82F6",strokeWidth:"1.5",fill:"#EFF6FF"}),(0,t.jsx)("path",{d:"M9 7.5l6 3.5-6 3.5V7.5z",fill:"#3B82F6"})]}),M=()=>(0,t.jsx)("svg",{width:"22",height:"22",viewBox:"0 0 22 22",fill:"none",children:(0,t.jsx)("circle",{cx:"11",cy:"11",r:"5",fill:"#9CA3AF"})}),E=({expanded:e})=>(0,t.jsx)("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"none",className:`transition-transform ${e?"rotate-180":""}`,children:(0,t.jsx)("path",{d:"M6 8l4 4 4-4",stroke:"#6B7280",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})}),A=()=>(0,t.jsx)("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:(0,t.jsx)("path",{d:"M8 2v8m0 0l-3-3m3 3l3-3M3 12h10",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})}),D=({matchDetails:e})=>e&&0!==e.length?(0,t.jsxs)("div",{className:"mt-3",children:[(0,t.jsxs)("h5",{className:"text-sm font-medium mb-2 text-gray-700",children:["Match Details (",e.length,")"]}),(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)("table",{className:"w-full text-sm",children:[(0,t.jsx)("thead",{children:(0,t.jsxs)("tr",{className:"border-b text-left text-gray-500",children:[(0,t.jsx)("th",{className:"pb-2 pr-4 font-medium",children:"Type"}),(0,t.jsx)("th",{className:"pb-2 pr-4 font-medium",children:"Method"}),(0,t.jsx)("th",{className:"pb-2 pr-4 font-medium",children:"Action"}),(0,t.jsx)("th",{className:"pb-2 font-medium",children:"Detail"})]})}),(0,t.jsx)("tbody",{children:e.map((e,s)=>(0,t.jsxs)("tr",{className:"border-b border-gray-100",children:[(0,t.jsx)("td",{className:"py-2 pr-4",children:e.type}),(0,t.jsx)("td",{className:"py-2 pr-4",children:(0,t.jsx)("span",{className:"px-2 py-0.5 bg-slate-100 text-slate-700 rounded text-xs",children:e.detection_method??"-"})}),(0,t.jsx)("td",{className:"py-2 pr-4",children:(0,t.jsx)("span",{className:`px-2 py-0.5 rounded text-xs font-medium ${"BLOCK"===e.action_taken?"bg-red-100 text-red-800":"bg-blue-50 text-blue-700"}`,children:e.action_taken??"-"})}),(0,t.jsxs)("td",{className:"py-2 font-mono text-xs text-gray-600 break-all",children:[e.category?`[${e.category}] `:"",e.snippet??"-"]})]},s))})]})})]}):null,I=({response:e})=>{let[a,l]=(0,s.useState)(!1);return(0,t.jsx)("div",{className:"mt-3",children:(0,t.jsxs)("div",{className:"border rounded-lg overflow-hidden",children:[(0,t.jsx)("div",{className:"flex items-center justify-between p-3 bg-gray-50 cursor-pointer hover:bg-gray-100",onClick:()=>l(!a),children:(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)(E,{expanded:a}),(0,t.jsx)("h5",{className:"font-medium text-sm ml-1",children:"Raw Guardrail Response"})]})}),a&&(0,t.jsx)("div",{className:"p-3 border-t bg-white",children:(0,t.jsx)("pre",{className:"bg-gray-50 rounded p-3 text-xs overflow-x-auto",children:JSON.stringify(e,null,2)})})]})})},O=({entries:e})=>{let a=(0,s.useMemo)(()=>[...e].sort((e,t)=>(e.start_time??0)-(t.start_time??0)),[e]),l=(0,s.useMemo)(()=>{if(0===a.length)return[];let e=a[0].start_time,t=[];t.push({type:"request",label:"Request received",offsetMs:0});let s=a.filter(e=>"pre_call"===e.guardrail_mode),l=a.filter(e=>"post_call"===e.guardrail_mode||"logging_only"===e.guardrail_mode),r=a.filter(e=>"during_call"===e.guardrail_mode);for(let a of s){let s=Math.round((a.end_time-e)*1e3);t.push({type:"guardrail",label:`Pre-call guardrail: ${S(a)}`,offsetMs:s,status:w(a)?"PASSED":"FAILED",isSuccess:w(a)})}let i=s.length>0?Math.max(...s.map(e=>e.end_time)):e,n=Math.round((((l.length>0?Math.min(...l.map(e=>e.start_time)):void 0)??i+1)-e)*1e3);for(let s of(t.push({type:"llm",label:"LLM call",offsetMs:n}),r)){let a=Math.round((s.end_time-e)*1e3);t.push({type:"guardrail",label:`During-call guardrail: ${S(s)}`,offsetMs:a,status:w(s)?"PASSED":"FAILED",isSuccess:w(s)})}for(let s of l){let a=Math.round((s.end_time-e)*1e3);t.push({type:"guardrail",label:`Post-call guardrail: ${S(s)}`,offsetMs:a,status:w(s)?"PASSED":"FAILED",isSuccess:w(s)})}let o=Math.round((Math.max(...a.map(e=>e.end_time))-e)*1e3)+1;return t.push({type:"response",label:"Response returned",offsetMs:o}),t},[a]);return(0,t.jsxs)("div",{children:[(0,t.jsx)("h4",{className:"text-xs font-semibold text-gray-500 uppercase tracking-wider mb-4",children:"Request Lifecycle"}),(0,t.jsx)("div",{className:"relative",children:l.map((e,s)=>(0,t.jsxs)("div",{className:"flex items-start gap-3 relative",children:[(0,t.jsxs)("div",{className:"flex flex-col items-center",children:[(0,t.jsx)("div",{className:"flex-shrink-0",children:"request"===e.type||"response"===e.type?(0,t.jsx)(M,{}):"llm"===e.type?(0,t.jsx)(L,{}):e.isSuccess?(0,t.jsx)(C,{}):(0,t.jsx)(T,{})}),s{var l;let i,[n,o]=(0,s.useState)(!1),d=w(e),c=N(e),x=S(e),u=(i=Math.round(1e3*e.duration),`${i}ms`),p=null==(l=e.guardrail_mode)||""===l?"—":("string"==typeof l?l:String(l)).replace(/_/g,"-").toUpperCase(),g=(e=>{if(!w(e))return null;if(null!=e.risk_score)return e.risk_score;let t=N(e),s=e.patterns_checked??0,a=e.confidence_score??0;if(0===s&&0===a)return 0;let l=7*(s>0?t/s:0)+3*a;return t>0&&l<2&&(l=2),Math.min(10,Math.round(10*l)/10)})(e),f=e.guardrail_provider??"presidio",y=e.guardrail_response,j=Array.isArray(y)?y:[],b="bedrock"!==f||null===y||"object"!=typeof y||Array.isArray(y)?void 0:y,v=null!=e.patterns_checked?`${c}/${e.patterns_checked} matched`:c>0?`${c} matched`:null;return(0,t.jsxs)("div",{className:"border border-gray-200 rounded-lg bg-white",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3 px-4 py-3 cursor-pointer hover:bg-gray-50 transition-colors",onClick:()=>o(!n),children:[(0,t.jsx)("div",{className:"flex-shrink-0",children:d?(0,t.jsx)(C,{}):(0,t.jsx)(T,{})}),(0,t.jsxs)("div",{className:"flex items-center gap-2 flex-wrap flex-1 min-w-0",children:[(0,t.jsx)("span",{className:"font-semibold text-gray-900 text-sm truncate",children:x}),(0,t.jsx)("span",{className:"px-2 py-0.5 border border-blue-200 bg-blue-50 text-blue-700 rounded text-[11px] font-semibold uppercase flex-shrink-0",children:p}),(0,t.jsx)("span",{className:`px-2 py-0.5 rounded text-[11px] font-semibold uppercase flex-shrink-0 ${d?"bg-green-100 text-green-700 border border-green-200":"bg-red-100 text-red-700 border border-red-200"}`,children:d?"PASSED":"FAILED"}),v&&(0,t.jsx)("span",{className:`px-2 py-0.5 rounded text-[11px] font-medium flex-shrink-0 ${0===c?"bg-green-50 text-green-700 border border-green-200":"bg-amber-50 text-amber-700 border border-amber-200"}`,children:v}),null!=e.confidence_score&&(0,t.jsxs)("span",{className:"px-2 py-0.5 bg-gray-100 text-gray-600 border border-gray-200 rounded text-[11px] font-medium flex-shrink-0",children:[(100*e.confidence_score).toFixed(0),"% conf"]}),null!=g&&d&&(0,t.jsx)(a.Tooltip,{title:`Risk score: ${g}/10`,children:(0,t.jsxs)("span",{className:`px-2 py-0.5 border rounded text-[11px] font-semibold flex-shrink-0 ${g<=3?"text-green-600 bg-green-50 border-green-200":g<=6?"text-amber-600 bg-amber-50 border-amber-200":"text-red-600 bg-red-50 border-red-200"}`,children:["Risk ",g,"/10"]})})]}),(0,t.jsxs)("div",{className:"flex items-center gap-3 flex-shrink-0",children:[(0,t.jsx)("span",{className:"text-sm text-gray-500 font-mono",children:u}),e.detection_method&&(0,t.jsx)("span",{className:"px-2 py-0.5 bg-gray-100 text-gray-600 border border-gray-200 rounded text-[11px] font-medium",children:e.detection_method.split(",")[0].trim()}),(0,t.jsx)(E,{expanded:n})]})]}),n&&(0,t.jsxs)("div",{className:"border-t border-gray-100 px-4 py-3",children:[e.classification&&(0,t.jsxs)("div",{className:"mb-3 bg-gray-50 rounded-lg p-3 space-y-1",children:[(0,t.jsx)("h5",{className:"text-sm font-medium text-gray-700 mb-2",children:"Classification"}),e.classification.category&&(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"font-medium w-1/3 text-gray-500",children:"Category:"}),(0,t.jsx)("span",{children:e.classification.category})]}),e.classification.article_reference&&(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"font-medium w-1/3 text-gray-500",children:"Reference:"}),(0,t.jsx)("span",{className:"font-mono",children:e.classification.article_reference})]}),null!=e.classification.confidence&&(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"font-medium w-1/3 text-gray-500",children:"Confidence:"}),(0,t.jsxs)("span",{children:[(100*e.classification.confidence).toFixed(0),"%"]})]}),e.classification.reason&&(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"font-medium w-1/3 text-gray-500",children:"Reason:"}),(0,t.jsx)("span",{children:e.classification.reason})]})]}),e.match_details&&e.match_details.length>0&&(0,t.jsx)(D,{matchDetails:e.match_details}),c>0&&(0,t.jsxs)("div",{className:"mt-3",children:[(0,t.jsx)("h5",{className:"text-sm font-medium text-gray-700 mb-2",children:"Masked Entities"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:Object.entries(e.masked_entity_count||{}).map(([e,s])=>(0,t.jsxs)("span",{className:"px-2 py-1 bg-blue-50 text-blue-700 rounded text-xs font-medium",children:[e,": ",s]},e))})]}),"presidio"===f&&j.length>0&&(0,t.jsx)("div",{className:"mt-3",children:(0,t.jsx)(r,{entities:j})}),"bedrock"===f&&b&&(0,t.jsx)("div",{className:"mt-3",children:(0,t.jsx)(m,{response:b})}),"litellm_content_filter"===f&&y&&(0,t.jsx)("div",{className:"mt-3",children:(0,t.jsx)(h,{response:y})}),f&&!_.has(f)&&y&&(0,t.jsx)(I,{response:y})]})]})};e.s(["default",0,({data:e,accessToken:a,logEntry:l})=>{let r=(0,s.useMemo)(()=>Array.isArray(e)?e.filter(e=>!!e):e?[e]:[],[e]),i=r.filter(w).length,n=i===r.length,o=(0,s.useMemo)(()=>Math.round(1e3*r.reduce((e,t)=>e+(t.duration??0),0)),[r]);return((0,s.useMemo)(()=>Array.from(new Set(r.map(e=>e.policy_template).filter(Boolean))),[r]),0===r.length)?null:(0,t.jsxs)("div",{className:"bg-white rounded-xl border border-gray-200 shadow-sm w-full max-w-full overflow-hidden mb-6",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-6 py-4 border-b border-gray-100",children:[(0,t.jsxs)("div",{className:"flex items-center gap-4",children:[(0,t.jsx)(k,{}),(0,t.jsxs)("div",{children:[(0,t.jsx)("h3",{className:"text-lg font-semibold text-gray-900",children:"Guardrails & Policy Compliance"}),(0,t.jsxs)("div",{className:"flex items-center gap-2 mt-0.5",children:[(0,t.jsxs)("span",{className:"text-sm text-gray-500",children:[r.length," guardrail",1!==r.length?"s":""," evaluated"]}),(0,t.jsx)("span",{className:"text-gray-300",children:"|"}),(0,t.jsxs)("span",{className:`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-semibold ${n?"bg-green-50 text-green-700 border border-green-200":"bg-red-50 text-red-700 border border-red-200"}`,children:[n?(0,t.jsx)("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",children:(0,t.jsx)("path",{d:"M3 6l2.5 2.5L9 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})}):null,i," Passed"]})]})]})]}),(0,t.jsxs)("div",{className:"flex items-center gap-6",children:[(0,t.jsx)("div",{className:"text-right",children:(0,t.jsxs)("div",{className:"text-sm font-medium text-gray-900",children:["Total: ",o,"ms overhead"]})}),(0,t.jsxs)("button",{onClick:()=>{let e=new Blob([JSON.stringify(r,null,2)],{type:"application/json"}),t=URL.createObjectURL(e),s=document.createElement("a");s.href=t,s.download=`guardrail-compliance-log-${new Date().toISOString().slice(0,10)}.json`,s.click(),URL.revokeObjectURL(t)},className:"inline-flex items-center gap-2 px-4 py-2 border border-gray-300 rounded-lg text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 transition-colors",children:[(0,t.jsx)(A,{}),"Export Compliance Log"]})]})]}),a&&l&&(0,t.jsx)("div",{className:"px-6 py-4 border-b border-gray-100",children:(0,t.jsx)(v,{accessToken:a,logEntry:l})}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("div",{className:"w-[340px] flex-shrink-0 border-r border-gray-100 px-6 py-5",children:(0,t.jsx)(O,{entries:r})}),(0,t.jsxs)("div",{className:"flex-1 px-6 py-5 min-w-0",children:[(0,t.jsx)("h4",{className:"text-xs font-semibold text-gray-500 uppercase tracking-wider mb-4",children:"Evaluation Details"}),(0,t.jsx)("div",{className:"space-y-3",children:r.map((e,s)=>(0,t.jsx)(z,{entry:e},`${e.guardrail_name??"guardrail"}-${s}`))})]})]})]})}],517442)},93648,245767,291950,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(207082),l=e.i(500330),r=e.i(871943),i=e.i(360820),n=e.i(94629),o=e.i(152990),d=e.i(682830),c=e.i(269200),m=e.i(942232),x=e.i(977572),u=e.i(427612),p=e.i(64848),h=e.i(496020),g=e.i(592968);function f({keys:e,totalCount:a,isLoading:f,isFetching:y,pageIndex:j,pageSize:b,onPageChange:v}){let[_,N]=(0,s.useState)([{id:"deleted_at",desc:!0}]),[w,S]=(0,s.useState)({pageIndex:j,pageSize:b});s.default.useEffect(()=>{S({pageIndex:j,pageSize:b})},[j,b]);let k=[{id:"token",accessorKey:"token",header:"Key ID",size:150,maxSize:250,cell:e=>{let s=e.getValue();return(0,t.jsx)(g.Tooltip,{title:s,children:(0,t.jsx)("span",{className:"font-mono text-blue-500 text-xs truncate block max-w-[250px]",children:s||"-"})})}},{id:"key_alias",accessorKey:"key_alias",header:"Key Alias",size:150,maxSize:200,cell:e=>{let s=e.getValue();return(0,t.jsx)(g.Tooltip,{title:s,children:(0,t.jsx)("span",{className:"font-mono text-xs truncate block max-w-[200px]",children:s??"-"})})}},{id:"team_alias",accessorKey:"team_alias",header:"Team Alias",size:120,maxSize:180,cell:e=>{let s=e.getValue();return(0,t.jsx)("span",{className:"truncate block max-w-[180px]",children:s||"-"})}},{id:"spend",accessorKey:"spend",header:"Spend (USD)",size:100,maxSize:140,cell:e=>(0,t.jsx)("span",{className:"block max-w-[140px]",children:(0,l.formatNumberWithCommas)(e.getValue(),4)})},{id:"max_budget",accessorKey:"max_budget",header:"Budget (USD)",size:110,maxSize:150,cell:e=>{let s=e.getValue();return(0,t.jsx)("span",{className:"block max-w-[150px]",children:null===s?"Unlimited":`$${(0,l.formatNumberWithCommas)(s)}`})}},{id:"user_email",accessorKey:"user_email",header:"User Email",size:160,maxSize:250,cell:e=>{let s=e.getValue();return(0,t.jsx)(g.Tooltip,{title:s,children:(0,t.jsx)("span",{className:"font-mono text-xs truncate block max-w-[250px]",children:s??"-"})})}},{id:"user_id",accessorKey:"user_id",header:"User ID",size:120,maxSize:200,cell:e=>{let s=e.getValue();return(0,t.jsx)(g.Tooltip,{title:s||void 0,children:(0,t.jsx)("span",{className:"truncate block max-w-[200px]",children:s||"-"})})}},{id:"created_at",accessorKey:"created_at",header:"Created At",size:120,maxSize:140,cell:e=>{let s=e.getValue();return(0,t.jsx)("span",{className:"block max-w-[140px]",children:s?new Date(s).toLocaleDateString():"-"})}},{id:"created_by",accessorKey:"created_by",header:"Created By",size:120,maxSize:180,cell:e=>{let s=e.row.original.created_by;return(0,t.jsx)(g.Tooltip,{title:s||void 0,children:(0,t.jsx)("span",{className:"truncate block max-w-[180px]",children:s||"-"})})}},{id:"deleted_at",accessorKey:"deleted_at",header:"Deleted At",size:120,maxSize:140,cell:e=>{let s=e.row.original.deleted_at;return(0,t.jsx)("span",{className:"block max-w-[140px]",children:s?new Date(s).toLocaleDateString():"-"})}},{id:"deleted_by",accessorKey:"deleted_by",header:"Deleted By",size:120,maxSize:180,cell:e=>{let s=e.row.original.deleted_by;return(0,t.jsx)(g.Tooltip,{title:s||void 0,children:(0,t.jsx)("span",{className:"truncate block max-w-[180px]",children:s||"-"})})}}],C=(0,o.useReactTable)({data:e,columns:k,columnResizeMode:"onChange",columnResizeDirection:"ltr",state:{sorting:_,pagination:w},onSortingChange:N,onPaginationChange:e=>{let t="function"==typeof e?e(w):e;S(t),v(t.pageIndex)},getCoreRowModel:(0,d.getCoreRowModel)(),getSortedRowModel:(0,d.getSortedRowModel)(),getPaginationRowModel:(0,d.getPaginationRowModel)(),enableSorting:!0,manualSorting:!1,manualPagination:!0,pageCount:Math.ceil(a/b)}),{pageIndex:T}=C.getState().pagination,L=T*b+1,M=Math.min((T+1)*b,a),E=`${L} - ${M}`;return(0,t.jsx)("div",{className:"w-full h-full overflow-hidden",children:(0,t.jsxs)("div",{className:"border-b py-4 flex-1 overflow-hidden",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between w-full mb-4",children:[f||y?(0,t.jsx)("span",{className:"inline-flex text-sm text-gray-700",children:"Loading..."}):(0,t.jsxs)("span",{className:"inline-flex text-sm text-gray-700",children:["Showing ",E," of ",a," results"]}),(0,t.jsxs)("div",{className:"inline-flex items-center gap-2",children:[f||y?(0,t.jsx)("span",{className:"text-sm text-gray-700",children:"Loading..."}):(0,t.jsxs)("span",{className:"text-sm text-gray-700",children:["Page ",T+1," of ",C.getPageCount()]}),(0,t.jsx)("button",{onClick:()=>C.previousPage(),disabled:f||y||!C.getCanPreviousPage(),className:"px-3 py-1 text-sm border rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed",children:"Previous"}),(0,t.jsx)("button",{onClick:()=>C.nextPage(),disabled:f||y||!C.getCanNextPage(),className:"px-3 py-1 text-sm border rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed",children:"Next"})]})]}),(0,t.jsx)("div",{className:"h-[75vh] overflow-auto",children:(0,t.jsx)("div",{className:"rounded-lg custom-border relative",children:(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)(c.Table,{className:"[&_td]:py-0.5 [&_th]:py-1",style:{width:C.getCenterTotalSize()},children:[(0,t.jsx)(u.TableHead,{children:C.getHeaderGroups().map(e=>(0,t.jsx)(h.TableRow,{children:e.headers.map(e=>(0,t.jsx)(p.TableHeaderCell,{"data-header-id":e.id,className:"py-1 h-8 relative hover:bg-gray-50",style:{width:e.getSize(),maxWidth:e.column.columnDef.maxSize,position:"relative"},onMouseEnter:()=>{let t=document.querySelector(`[data-header-id="${e.id}"] .resizer`);t&&(t.style.opacity="0.5")},onMouseLeave:()=>{let t=document.querySelector(`[data-header-id="${e.id}"] .resizer`);t&&!e.column.getIsResizing()&&(t.style.opacity="0")},onClick:e.column.getToggleSortingHandler(),children:(0,t.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,t.jsx)("div",{className:"flex items-center",children:e.isPlaceholder?null:(0,o.flexRender)(e.column.columnDef.header,e.getContext())}),(0,t.jsx)("div",{className:"w-4",children:e.column.getIsSorted()?({asc:(0,t.jsx)(i.ChevronUpIcon,{className:"h-4 w-4 text-blue-500"}),desc:(0,t.jsx)(r.ChevronDownIcon,{className:"h-4 w-4 text-blue-500"})})[e.column.getIsSorted()]:(0,t.jsx)(n.SwitchVerticalIcon,{className:"h-4 w-4 text-gray-400"})}),(0,t.jsx)("div",{onDoubleClick:()=>e.column.resetSize(),onMouseDown:e.getResizeHandler(),onTouchStart:e.getResizeHandler(),className:`resizer ${C.options.columnResizeDirection} ${e.column.getIsResizing()?"isResizing":""}`,style:{position:"absolute",right:0,top:0,height:"100%",width:"5px",background:e.column.getIsResizing()?"#3b82f6":"transparent",cursor:"col-resize",userSelect:"none",touchAction:"none",opacity:+!!e.column.getIsResizing()}})]})},e.id))},e.id))}),(0,t.jsx)(m.TableBody,{children:f||y?(0,t.jsx)(h.TableRow,{children:(0,t.jsx)(x.TableCell,{colSpan:k.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"🚅 Loading keys..."})})})}):e.length>0?C.getRowModel().rows.map(e=>(0,t.jsx)(h.TableRow,{className:"h-8",children:e.getVisibleCells().map(e=>(0,t.jsx)(x.TableCell,{style:{width:e.column.getSize(),maxWidth:e.column.columnDef.maxSize,whiteSpace:"pre-wrap",overflow:"hidden"},className:"py-0.5 max-h-8 overflow-hidden text-ellipsis whitespace-nowrap",children:(0,o.flexRender)(e.column.columnDef.cell,e.getContext())},e.id))},e.id)):(0,t.jsx)(h.TableRow,{children:(0,t.jsx)(x.TableCell,{colSpan:k.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"No deleted keys found"})})})})})]})})})})]})})}function y(){let[e,l]=(0,s.useState)(0),[r]=(0,s.useState)(50),{data:i,isPending:n,isFetching:o}=(0,a.useDeletedKeys)(e+1,r);return(0,t.jsx)(f,{keys:i?.keys||[],totalCount:i?.total_count||0,isLoading:n,isFetching:o,pageIndex:e,pageSize:r,onPageChange:l})}e.s(["default",()=>y],93648);var j=e.i(785242),b=e.i(389083),v=e.i(599724),_=e.i(355619);function N({teams:e,isLoading:a,isFetching:f}){let[y,j]=(0,s.useState)([{id:"deleted_at",desc:!0}]),N=[{id:"team_alias",accessorKey:"team_alias",header:"Team Name",size:150,maxSize:200,cell:e=>{let s=e.getValue();return(0,t.jsx)(g.Tooltip,{title:s||void 0,children:(0,t.jsx)("span",{className:"truncate block max-w-[200px]",children:s||"-"})})}},{id:"team_id",accessorKey:"team_id",header:"Team ID",size:150,maxSize:250,cell:e=>{let s=e.getValue();return(0,t.jsx)(g.Tooltip,{title:s,children:(0,t.jsx)("span",{className:"font-mono text-blue-500 text-xs truncate block max-w-[250px]",children:s||"-"})})}},{id:"created_at",accessorKey:"created_at",header:"Created",size:120,maxSize:140,cell:e=>{let s=e.getValue();return(0,t.jsx)("span",{className:"block max-w-[140px]",children:s?new Date(s).toLocaleDateString():"-"})}},{id:"spend",accessorKey:"spend",header:"Spend (USD)",size:100,maxSize:140,cell:e=>{let s=e.row.original.spend;return(0,t.jsx)("span",{className:"block max-w-[140px]",children:void 0!==s?(0,l.formatNumberWithCommas)(s,4):"-"})}},{id:"max_budget",accessorKey:"max_budget",header:"Budget (USD)",size:110,maxSize:150,cell:e=>{let s=e.getValue();return(0,t.jsx)("span",{className:"block max-w-[150px]",children:null==s?"No limit":`$${(0,l.formatNumberWithCommas)(s)}`})}},{id:"models",accessorKey:"models",header:"Models",size:200,maxSize:300,cell:e=>{let s=e.getValue();return Array.isArray(s)&&0!==s.length?(0,t.jsxs)("div",{className:"flex flex-wrap gap-1 max-w-[300px]",children:[s.slice(0,3).map((e,s)=>"all-proxy-models"===e?(0,t.jsx)(b.Badge,{size:"xs",color:"red",children:(0,t.jsx)(v.Text,{children:"All Proxy Models"})},s):(0,t.jsx)(b.Badge,{size:"xs",color:"blue",children:(0,t.jsx)(v.Text,{children:e.length>30?`${(0,_.getModelDisplayName)(e).slice(0,30)}...`:(0,_.getModelDisplayName)(e)})},s)),s.length>3&&(0,t.jsx)(b.Badge,{size:"xs",color:"gray",children:(0,t.jsxs)(v.Text,{children:["+",s.length-3," ",s.length-3==1?"more model":"more models"]})})]}):(0,t.jsx)(b.Badge,{size:"xs",color:"red",children:(0,t.jsx)(v.Text,{children:"All Proxy Models"})})}},{id:"organization_id",accessorKey:"organization_id",header:"Organization",size:150,maxSize:200,cell:e=>{let s=e.getValue();return(0,t.jsx)(g.Tooltip,{title:s||void 0,children:(0,t.jsx)("span",{className:"truncate block max-w-[200px]",children:s||"-"})})}},{id:"deleted_at",accessorKey:"deleted_at",header:"Deleted At",size:120,maxSize:140,cell:e=>{let s=e.row.original.deleted_at;return(0,t.jsx)("span",{className:"block max-w-[140px]",children:s?new Date(s).toLocaleDateString():"-"})}},{id:"deleted_by",accessorKey:"deleted_by",header:"Deleted By",size:120,maxSize:180,cell:e=>{let s=e.row.original.deleted_by;return(0,t.jsx)(g.Tooltip,{title:s||void 0,children:(0,t.jsx)("span",{className:"truncate block max-w-[180px]",children:s||"-"})})}}],w=(0,o.useReactTable)({data:e,columns:N,columnResizeMode:"onChange",columnResizeDirection:"ltr",state:{sorting:y},onSortingChange:j,getCoreRowModel:(0,d.getCoreRowModel)(),getSortedRowModel:(0,d.getSortedRowModel)(),enableSorting:!0,manualSorting:!1});return(0,t.jsx)("div",{className:"w-full h-full overflow-hidden",children:(0,t.jsxs)("div",{className:"border-b py-4 flex-1 overflow-hidden",children:[(0,t.jsx)("div",{className:"flex items-center justify-between w-full mb-4",children:a||f?(0,t.jsx)("span",{className:"inline-flex text-sm text-gray-700",children:"Loading..."}):(0,t.jsxs)("span",{className:"inline-flex text-sm text-gray-700",children:["Showing ",e.length," ",1===e.length?"team":"teams"]})}),(0,t.jsx)("div",{className:"h-[75vh] overflow-auto",children:(0,t.jsx)("div",{className:"rounded-lg custom-border relative",children:(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)(c.Table,{className:"[&_td]:py-0.5 [&_th]:py-1",style:{width:w.getCenterTotalSize()},children:[(0,t.jsx)(u.TableHead,{children:w.getHeaderGroups().map(e=>(0,t.jsx)(h.TableRow,{children:e.headers.map(e=>(0,t.jsx)(p.TableHeaderCell,{"data-header-id":e.id,className:"py-1 h-8 relative hover:bg-gray-50",style:{width:e.getSize(),maxWidth:e.column.columnDef.maxSize,position:"relative"},onMouseEnter:()=>{let t=document.querySelector(`[data-header-id="${e.id}"] .resizer`);t&&(t.style.opacity="0.5")},onMouseLeave:()=>{let t=document.querySelector(`[data-header-id="${e.id}"] .resizer`);t&&!e.column.getIsResizing()&&(t.style.opacity="0")},onClick:e.column.getToggleSortingHandler(),children:(0,t.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,t.jsx)("div",{className:"flex items-center",children:e.isPlaceholder?null:(0,o.flexRender)(e.column.columnDef.header,e.getContext())}),(0,t.jsx)("div",{className:"w-4",children:e.column.getIsSorted()?({asc:(0,t.jsx)(i.ChevronUpIcon,{className:"h-4 w-4 text-blue-500"}),desc:(0,t.jsx)(r.ChevronDownIcon,{className:"h-4 w-4 text-blue-500"})})[e.column.getIsSorted()]:(0,t.jsx)(n.SwitchVerticalIcon,{className:"h-4 w-4 text-gray-400"})}),(0,t.jsx)("div",{onDoubleClick:()=>e.column.resetSize(),onMouseDown:e.getResizeHandler(),onTouchStart:e.getResizeHandler(),className:`resizer ${w.options.columnResizeDirection} ${e.column.getIsResizing()?"isResizing":""}`,style:{position:"absolute",right:0,top:0,height:"100%",width:"5px",background:e.column.getIsResizing()?"#3b82f6":"transparent",cursor:"col-resize",userSelect:"none",touchAction:"none",opacity:+!!e.column.getIsResizing()}})]})},e.id))},e.id))}),(0,t.jsx)(m.TableBody,{children:a||f?(0,t.jsx)(h.TableRow,{children:(0,t.jsx)(x.TableCell,{colSpan:N.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"🚅 Loading teams..."})})})}):e.length>0?w.getRowModel().rows.map(e=>(0,t.jsx)(h.TableRow,{className:"h-8",children:e.getVisibleCells().map(e=>(0,t.jsx)(x.TableCell,{style:{width:e.column.getSize(),maxWidth:e.column.columnDef.maxSize,whiteSpace:"pre-wrap",overflow:"hidden"},className:"py-0.5 max-h-8 overflow-hidden text-ellipsis whitespace-nowrap",children:(0,o.flexRender)(e.column.columnDef.cell,e.getContext())},e.id))},e.id)):(0,t.jsx)(h.TableRow,{children:(0,t.jsx)(x.TableCell,{colSpan:N.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"No deleted teams found"})})})})})]})})})})]})})}function w(){let{data:e,isPending:s,isFetching:a}=(0,j.useDeletedTeams)(1,100);return(0,t.jsx)(N,{teams:e||[],isLoading:s,isFetching:a})}e.s(["default",()=>w],245767);var S=e.i(625901),k=e.i(56456),C=e.i(152473),T=e.i(199133),L=e.i(770914);let{Text:M}=e.i(898586).Typography;e.s(["PaginatedModelSelect",0,({value:e,onChange:a,placeholder:l="Select a model",style:r,pageSize:i=50,allowClear:n=!0,disabled:o=!1})=>{let[d,c]=(0,s.useState)(""),[m,x]=(0,C.useDebouncedState)("",{wait:300}),{data:u,fetchNextPage:p,hasNextPage:h,isFetchingNextPage:g,isLoading:f}=(0,S.useInfiniteModelInfo)(i,m||void 0),y=(0,s.useMemo)(()=>{if(!u?.pages)return[];let e=new Set,t=[];for(let s of u.pages)for(let a of s.data){let s=a.model_info?.id??"",l=a.model_name??"";!s||e.has(s)||(e.add(s),t.push({label:l?`${l} (${s})`:s,value:s,modelName:l,modelId:s}))}return t},[u]);return(0,t.jsx)(T.Select,{value:e||void 0,onChange:e=>{let t="string"==typeof e?e:Array.isArray(e)?e[0]??"":"";a?.(t)},placeholder:l,style:{width:"100%",...r},allowClear:n,disabled:o,showSearch:!0,filterOption:!1,onSearch:e=>{c(e),x(e)},searchValue:d,onPopupScroll:e=>{let t=e.currentTarget;(t.scrollTop+t.clientHeight)/t.scrollHeight>=.8&&h&&!g&&p()},loading:f,notFoundContent:f?(0,t.jsx)(k.LoadingOutlined,{spin:!0}):"No models found",options:y,optionRender:e=>{let{modelName:s,modelId:a}=e.data;return(0,t.jsx)(t.Fragment,{children:s?(0,t.jsxs)(L.Space,{direction:"vertical",children:[(0,t.jsxs)(L.Space,{direction:"horizontal",children:[(0,t.jsx)(M,{strong:!0,children:"Model name:"}),(0,t.jsx)(M,{ellipsis:!0,children:s})]}),(0,t.jsxs)(M,{ellipsis:!0,type:"secondary",children:["Model ID: ",a]})]}):(0,t.jsxs)(M,{ellipsis:!0,type:"secondary",children:["Model ID: ",a]})})},popupRender:e=>(0,t.jsxs)(t.Fragment,{children:[e,g&&(0,t.jsx)("div",{style:{textAlign:"center",padding:8},children:(0,t.jsx)(k.LoadingOutlined,{spin:!0})})]})})}],291950)},95684,e=>{"use strict";var t=e.i(165370);e.s(["Pagination",()=>t.default])},942161,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(266027),l=e.i(619273),r=e.i(291542),i=e.i(262218),n=e.i(311451),o=e.i(199133),d=e.i(464571),c=e.i(95684),m=e.i(482725),x=e.i(91979),u=e.i(56456),p=e.i(166540),h=e.i(764205),g=e.i(608856),f=e.i(898586),y=e.i(149192),j=e.i(166406),b=e.i(492030),v=e.i(304911);let{Text:_}=f.Typography,N={LiteLLM_VerificationToken:"Keys",LiteLLM_TeamTable:"Teams",LiteLLM_UserTable:"Users",LiteLLM_OrganizationTable:"Organizations",LiteLLM_ProxyModelTable:"Models"},w={created:"green",updated:"blue",deleted:"red",rotated:"orange"};function S({label:e,value:a}){let[l,r]=(0,s.useState)(!1),i=(0,s.useCallback)(async()=>{try{let e=JSON.stringify(a,null,2);if(navigator.clipboard&&window.isSecureContext)await navigator.clipboard.writeText(e);else{let t=document.createElement("textarea");t.value=e,t.style.position="fixed",t.style.opacity="0",document.body.appendChild(t),t.focus(),t.select(),document.execCommand("copy"),document.body.removeChild(t)}r(!0),setTimeout(()=>r(!1),2e3)}catch(e){console.error("Copy failed:",e)}},[a]);return(0,t.jsxs)("div",{className:"bg-white rounded border overflow-hidden",children:[(0,t.jsxs)("div",{className:"flex justify-between items-center px-3 py-2 border-b bg-gray-50",children:[(0,t.jsx)("span",{className:"text-xs font-semibold text-gray-600",children:e}),(0,t.jsx)("button",{onClick:i,className:"p-1 hover:bg-gray-200 rounded text-gray-500 hover:text-gray-700 transition-colors",title:"Copy JSON",children:l?(0,t.jsx)(b.CheckOutlined,{className:"text-green-600"}):(0,t.jsx)(j.CopyOutlined,{})})]}),(0,t.jsx)("pre",{className:"p-3 bg-white text-xs font-mono overflow-auto max-h-96 whitespace-pre-wrap break-all m-0",children:JSON.stringify(a,null,2)})]})}function k({label:e,value:s}){return(0,t.jsxs)("div",{className:"flex items-start gap-2 py-1.5",children:[(0,t.jsx)("span",{className:"text-xs text-gray-500 w-36 shrink-0",children:e}),(0,t.jsx)("span",{className:"text-xs text-gray-900 break-all",children:s})]})}function C({log:e}){let{action:s,table_name:a,before_value:l,updated_values:r}=e,i="LiteLLM_VerificationToken"===a,n="updated"===s||"rotated"===s,o=l,d=r;if(n&&l&&r){let e={},t={};new Set([...Object.keys(l),...Object.keys(r)]).forEach(s=>{JSON.stringify(l[s])!==JSON.stringify(r[s])&&(s in l&&(e[s]=l[s]),s in r&&(t[s]=r[s]))}),Object.keys(l).forEach(s=>{s in r||s in e||(e[s]=l[s],t[s]=void 0)}),Object.keys(r).forEach(s=>{s in l||s in t||(t[s]=r[s],e[s]=void 0)}),o=Object.keys(e).length>0?e:{note:"No differing fields detected"},d=Object.keys(t).length>0?t:{note:"No differing fields detected"}}let c=(e,s)=>{if(!s||0===Object.keys(s).length)return(0,t.jsxs)("div",{className:"bg-white rounded border overflow-hidden",children:[(0,t.jsx)("div",{className:"flex items-center px-3 py-2 border-b bg-gray-50",children:(0,t.jsx)("span",{className:"text-xs font-semibold text-gray-600",children:e})}),(0,t.jsx)("p",{className:"px-3 py-3 text-xs text-gray-400 italic m-0",children:"N/A"})]});if(i&&n){let a=["token","spend","max_budget"];if(Object.keys(s).every(e=>a.includes(e))&&!("note"in s))return(0,t.jsxs)("div",{className:"bg-white rounded border overflow-hidden",children:[(0,t.jsx)("div",{className:"flex items-center px-3 py-2 border-b bg-gray-50",children:(0,t.jsx)("span",{className:"text-xs font-semibold text-gray-600",children:e})}),(0,t.jsxs)("div",{className:"px-3 py-3 space-y-1 text-xs",children:[void 0!==s.token&&(0,t.jsxs)("p",{children:[(0,t.jsx)("span",{className:"text-gray-500",children:"Token:"})," ",s.token??"N/A"]}),void 0!==s.spend&&(0,t.jsxs)("p",{children:[(0,t.jsx)("span",{className:"text-gray-500",children:"Spend:"})," $",Number(s.spend).toFixed(6)]}),void 0!==s.max_budget&&(0,t.jsxs)("p",{children:[(0,t.jsx)("span",{className:"text-gray-500",children:"Max Budget:"})," $",Number(s.max_budget).toFixed(6)]})]})]})}return(0,t.jsx)(S,{label:e,value:s})};return(0,t.jsxs)("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4 mt-4",children:[c("Before",o),c("After",d)]})}function T({open:e,onClose:s,log:a}){if(!a)return null;let l=N[a.table_name]??a.table_name,r=w[a.action]??"default";return(0,t.jsxs)(g.Drawer,{placement:"right",width:"60%",open:e,onClose:s,closable:!1,mask:!0,maskClosable:!0,styles:{body:{padding:0,display:"flex",flexDirection:"column"},header:{display:"none"}},children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-6 py-4 border-b bg-white shrink-0",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)(i.Tag,{color:r,className:"capitalize m-0",children:a.action}),(0,t.jsx)("span",{className:"text-sm text-gray-500",children:p.default.utc(a.updated_at).local().format("MMM D, YYYY HH:mm:ss")})]}),(0,t.jsx)("button",{onClick:s,className:"w-8 h-8 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500","aria-label":"Close",children:(0,t.jsx)(y.CloseOutlined,{})})]}),(0,t.jsxs)("div",{className:"px-6 py-5",children:[(0,t.jsxs)("div",{className:"bg-gray-50 border rounded-lg p-4 mb-5",children:[(0,t.jsx)("p",{className:"text-xs font-semibold text-gray-700 mb-2 uppercase tracking-wide",children:"Details"}),(0,t.jsx)(k,{label:"Table",value:l}),(0,t.jsx)(k,{label:"Object ID",value:(0,t.jsx)(_,{copyable:!0,className:"font-mono text-xs",children:a.object_id})}),(0,t.jsx)(k,{label:"Changed By",value:(0,t.jsx)(v.default,{userId:a.changed_by})}),(0,t.jsx)(k,{label:"API Key (Hash)",value:a.changed_by_api_key?(0,t.jsx)(_,{copyable:!0,className:"font-mono text-xs break-all",children:a.changed_by_api_key}):"—"})]}),(0,t.jsx)(C,{log:a})]})]})}let{Search:L}=n.Input,M={LiteLLM_VerificationToken:"Keys",LiteLLM_TeamTable:"Teams",LiteLLM_UserTable:"Users",LiteLLM_OrganizationTable:"Organizations",LiteLLM_ProxyModelTable:"Models"},E={created:"green",updated:"blue",deleted:"red",rotated:"orange"};function A({userID:e,userRole:n,token:g,accessToken:f,isActive:y,premiumUser:j}){let[b,_]=(0,s.useState)(1),[N,w]=(0,s.useState)(""),[S,k]=(0,s.useState)(""),[C,A]=(0,s.useState)(""),[D,I]=(0,s.useState)(""),[O,z]=(0,s.useState)(void 0),[R,P]=(0,s.useState)(void 0),[B,F]=(0,s.useState)(null),[q,H]=(0,s.useState)(!1),$=(0,a.useQuery)({queryKey:["audit_logs",b,50,N,S,C,D,O,R],queryFn:async()=>f&&g&&n&&e?(0,h.uiAuditLogsCall)({accessToken:f,page:b,page_size:50,params:{object_id:N||void 0,changed_by:S||void 0,object_key_hash:C||void 0,object_team_id:D||void 0,action:O||void 0,table_name:R||void 0,sort_by:"updated_at",sort_order:"desc"}}):{audit_logs:[],total:0,page:1,page_size:50,total_pages:0},enabled:!!f&&!!g&&!!n&&!!e&&y,placeholderData:l.keepPreviousData}),Y=[{title:"Timestamp",dataIndex:"updated_at",key:"updated_at",width:200,render:e=>(0,t.jsx)("span",{className:"font-mono text-xs whitespace-nowrap",children:p.default.utc(e).local().format("MMM D, YYYY HH:mm:ss")})},{title:"Action",dataIndex:"action",key:"action",width:100,render:e=>(0,t.jsx)(i.Tag,{color:E[e]??"default",className:"capitalize",children:e})},{title:"Table",dataIndex:"table_name",key:"table_name",width:130,render:e=>M[e]??e},{title:"Object ID",dataIndex:"object_id",key:"object_id",render:e=>(0,t.jsx)("span",{className:"font-mono text-xs",children:e})},{title:"Changed By",dataIndex:"changed_by",key:"changed_by",width:200,render:e=>(0,t.jsx)(v.default,{userId:e})},{title:"API Key (Hash)",dataIndex:"changed_by_api_key",key:"changed_by_api_key",width:140,render:e=>e?(0,t.jsxs)("span",{className:"font-mono text-xs",children:[e.slice(0,12),"…"]}):"—"}];if(!j)return(0,t.jsxs)("div",{style:{textAlign:"center",marginTop:"20px"},children:[(0,t.jsx)("h1",{style:{display:"block",marginBottom:"10px"},children:"✨ Enterprise Feature."}),(0,t.jsx)("p",{style:{display:"block",marginBottom:"10px"},children:"This is a LiteLLM Enterprise feature, and requires a valid key to use."}),(0,t.jsx)("p",{style:{display:"block",marginBottom:"20px",fontStyle:"italic"},children:"Here's a preview of what Audit Logs offer:"}),(0,t.jsx)("img",{src:"../ui/assets/audit-logs-preview.png",alt:"Audit Logs Preview",style:{maxWidth:"100%",maxHeight:"700px",borderRadius:"8px",boxShadow:"0 4px 8px rgba(0,0,0,0.1)",margin:"0 auto"},onError:e=>{e.target.style.display="none"}})]});let K=$.data?.audit_logs??[],V=$.data?.total??0;return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"bg-white rounded-lg shadow",children:[(0,t.jsxs)("div",{className:"border-b px-6 py-4",children:[(0,t.jsx)("div",{className:"flex items-center justify-between mb-4",children:(0,t.jsx)("h1",{className:"text-xl font-semibold",children:"Audit Logs"})}),(0,t.jsxs)("div",{className:"flex flex-wrap items-center gap-3",children:[(0,t.jsx)(L,{placeholder:"Object ID",allowClear:!0,style:{width:200},onSearch:e=>{w(e),_(1)},onChange:e=>{e.target.value||(w(""),_(1))}}),(0,t.jsx)(L,{placeholder:"Changed By",allowClear:!0,style:{width:180},onSearch:e=>{k(e),_(1)},onChange:e=>{e.target.value||(k(""),_(1))}}),(0,t.jsx)(L,{placeholder:"Team ID",allowClear:!0,style:{width:180},onSearch:e=>{I(e),_(1)},onChange:e=>{e.target.value||(I(""),_(1))}}),(0,t.jsx)(L,{placeholder:"Key Hash",allowClear:!0,style:{width:180},onSearch:e=>{A(e),_(1)},onChange:e=>{e.target.value||(A(""),_(1))}}),(0,t.jsx)(o.Select,{placeholder:"All Actions",allowClear:!0,style:{width:140},options:[{label:"Created",value:"created"},{label:"Updated",value:"updated"},{label:"Deleted",value:"deleted"},{label:"Rotated",value:"rotated"}],onChange:e=>{z(e),_(1)}}),(0,t.jsx)(o.Select,{placeholder:"All Tables",allowClear:!0,style:{width:150},options:[{label:"Keys",value:"LiteLLM_VerificationToken"},{label:"Teams",value:"LiteLLM_TeamTable"},{label:"Users",value:"LiteLLM_UserTable"},{label:"Organizations",value:"LiteLLM_OrganizationTable"},{label:"Models",value:"LiteLLM_ProxyModelTable"}],onChange:e=>{P(e),_(1)}}),(0,t.jsxs)("div",{className:"ml-auto flex items-center gap-2",children:[(0,t.jsx)(d.Button,{icon:(0,t.jsx)(x.ReloadOutlined,{spin:$.isFetching}),onClick:()=>$.refetch(),disabled:$.isFetching}),(0,t.jsx)(c.Pagination,{current:b,pageSize:50,total:V,showTotal:e=>`${e} total`,showSizeChanger:!1,size:"small",onChange:e=>_(e)})]})]})]}),(0,t.jsx)(r.Table,{columns:Y,dataSource:K,rowKey:"id",loading:{spinning:$.isLoading,indicator:(0,t.jsx)(m.Spin,{indicator:(0,t.jsx)(u.LoadingOutlined,{spin:!0}),size:"small"})},size:"small",pagination:!1,onRow:e=>({onClick:()=>{F(e),H(!0)},style:{cursor:"pointer"}})})]}),(0,t.jsx)(T,{open:q,onClose:()=>H(!1),log:B})]})}e.s(["default",()=>A],942161)},307582,e=>{"use strict";var t=e.i(843476);e.s(["TimeCell",0,({utcTime:e})=>(0,t.jsx)("span",{style:{fontFamily:"monospace",width:"180px",display:"inline-block"},children:(e=>{try{return new Date(e).toLocaleString("en-US",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!0}).replace(",","")}catch(e){return"Error converting time"}})(e)})])},97859,e=>{"use strict";e.s(["AGENT_CALL_TYPES",0,["asend_message"],"ERROR_CODE_OPTIONS",0,[{label:"400 - Bad Request",value:"400"},{label:"401 - Invalid Authentication",value:"401"},{label:"403 - Permission Denied",value:"403"},{label:"404 - Not Found",value:"404"},{label:"408 - Request Timeout",value:"408"},{label:"422 - Unprocessable Entity",value:"422"},{label:"429 - Rate Limited",value:"429"},{label:"500 - Internal Server Error",value:"500"},{label:"502 - Bad Gateway",value:"502"},{label:"503 - Service Unavailable",value:"503"},{label:"529 - Overloaded",value:"529"}],"MCP_CALL_TYPES",0,["call_mcp_tool","list_mcp_tools"],"QUICK_SELECT_OPTIONS",0,[{label:"Last 15 Minutes",value:15,unit:"minutes"},{label:"Last Hour",value:1,unit:"hours"},{label:"Last 4 Hours",value:4,unit:"hours"},{label:"Last 24 Hours",value:24,unit:"hours"},{label:"Last 7 Days",value:7,unit:"days"}]])},245099,e=>{"use strict";var t=e.i(843476),s=e.i(500330),a=(e.i(389083),e.i(994388)),l=e.i(592968);e.i(271645);var r=e.i(916925),i=e.i(446891),n=e.i(307582),o=e.i(97859);let d=({size:e=12})=>(0,t.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"flex-shrink-0 text-gray-400",children:(0,t.jsx)("path",{d:"M12 3l1.912 5.813a2 2 0 0 0 1.275 1.275L21 12l-5.813 1.912a2 2 0 0 0-1.275 1.275L12 21l-1.912-5.813a2 2 0 0 0-1.275-1.275L3 12l5.813-1.912a2 2 0 0 0 1.275-1.275L12 3z"})}),c=({size:e=10})=>(0,t.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"flex-shrink-0",children:(0,t.jsx)("path",{d:"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"})}),m=({size:e=12})=>(0,t.jsxs)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"flex-shrink-0",children:[(0,t.jsx)("path",{d:"M12 8V4H8"}),(0,t.jsx)("rect",{width:"16",height:"12",x:"4",y:"8",rx:"2"}),(0,t.jsx)("path",{d:"M2 14h2"}),(0,t.jsx)("path",{d:"M20 14h2"}),(0,t.jsx)("path",{d:"M15 13v2"}),(0,t.jsx)("path",{d:"M9 13v2"})]}),x=({count:e})=>(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-blue-50 text-blue-700 border border-blue-200 rounded-full text-[11px] font-medium whitespace-nowrap",children:[(0,t.jsx)(d,{}),null!=e?e:"LLM"]}),u=({count:e})=>(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-amber-50 text-amber-700 border border-amber-200 rounded-full text-[11px] font-medium whitespace-nowrap",children:[(0,t.jsx)(c,{}),null!=e?e:"MCP"]}),p=({count:e})=>(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-violet-50 text-violet-700 border border-violet-200 rounded-full text-[11px] font-medium whitespace-nowrap",children:[(0,t.jsx)(m,{}),null!=e?e:"Agent"]}),h=({label:e,field:s,sortBy:a,sortOrder:l,onSortChange:r})=>(0,t.jsxs)("div",{className:"flex items-center gap-1",children:[(0,t.jsx)("span",{children:e}),(0,t.jsx)(i.TableHeaderSortDropdown,{sortState:a===s&&l,onSortChange:e=>{!1===e?r("startTime","desc"):r(s,e)}})]}),g=e=>[{header:e?()=>(0,t.jsx)(h,{label:"Time",field:"startTime",sortBy:e.sortBy,sortOrder:e.sortOrder,onSortChange:e.onSortChange}):"Time",accessorKey:"startTime",cell:e=>(0,t.jsx)(n.TimeCell,{utcTime:e.getValue()})},{header:"Type",id:"type",cell:e=>{let s=e.row.original,a=s.session_total_count||1,r=o.MCP_CALL_TYPES.includes(s.call_type),i=o.AGENT_CALL_TYPES.includes(s.call_type),n=s.session_llm_count??(r||i?0:a),h=s.session_agent_count??(i?a:0),g=s.session_mcp_count??(r?a:0);if(r)return(0,t.jsx)(u,{});if(i&&a<=1)return(0,t.jsx)(p,{});if(a<=1)return(0,t.jsx)(x,{});let f=(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-blue-50 text-blue-700 border border-blue-200 rounded-full text-[11px] font-medium whitespace-nowrap",children:[(0,t.jsx)(d,{}),(0,t.jsx)("span",{children:a}),h>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("span",{className:"text-blue-300",children:"·"}),(0,t.jsx)(m,{size:10})]}),g>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("span",{className:"text-blue-300",children:"·"}),(0,t.jsx)(c,{})]})]}),y=[n>0&&`${n} LLM`,h>0&&`${h} Agent`,g>0&&`${g} MCP`].filter(Boolean);return(0,t.jsx)(l.Tooltip,{title:y.join(" • "),children:f})}},{header:"Status",accessorKey:"metadata.status",cell:e=>{let s="failure"!==(e.getValue()||"Success").toLowerCase();return(0,t.jsx)("span",{className:`px-2 py-1 rounded-md text-xs font-medium inline-block text-center w-16 ${s?"bg-green-100 text-green-800":"bg-red-100 text-red-800"}`,children:s?"Success":"Failure"})}},{header:"Session ID",accessorKey:"session_id",cell:e=>{let s=String(e.getValue()||""),r=e.row.original.onSessionClick;return(0,t.jsx)(l.Tooltip,{title:String(e.getValue()||""),children:(0,t.jsx)(a.Button,{size:"xs",variant:"light",className:"font-mono text-blue-500 bg-blue-50 hover:bg-blue-100 text-xs font-normal text-xs max-w-[15ch] truncate block",onClick:()=>r?.(s),children:String(e.getValue()||"")})})}},{header:"Request ID",accessorKey:"request_id",cell:e=>(0,t.jsx)(l.Tooltip,{title:String(e.getValue()||""),children:(0,t.jsx)("span",{className:"font-mono text-xs max-w-[15ch] truncate block",children:String(e.getValue()||"")})})},{header:e?()=>(0,t.jsx)(h,{label:"Cost",field:"spend",sortBy:e.sortBy,sortOrder:e.sortOrder,onSortChange:e.onSortChange}):"Cost",accessorKey:"spend",cell:e=>{let a=e.row.original,r=a.mcp_tool_call_count||0,i=a.mcp_tool_call_spend||0;return(0,t.jsxs)("div",{className:"flex flex-col",children:[(0,t.jsx)(l.Tooltip,{title:`$${String(e.getValue()||0)}`,children:(0,t.jsx)("span",{children:(0,s.getSpendString)(e.getValue()||0)})}),r>0&&i>0&&(0,t.jsxs)("span",{className:"text-[10px] text-amber-600",children:["incl. ",(0,s.getSpendString)(i)," from ",r," MCP"]})]})}},{header:e?()=>(0,t.jsx)(h,{label:"Duration (s)",field:"request_duration_ms",sortBy:e.sortBy,sortOrder:e.sortOrder,onSortChange:e.onSortChange}):"Duration (s)",accessorKey:"request_duration_ms",cell:e=>{let s=e.getValue();if(null==s)return(0,t.jsx)("span",{children:"-"});let a=(s/1e3).toFixed(2);return(0,t.jsx)(l.Tooltip,{title:`${s}ms`,children:(0,t.jsx)("span",{className:"max-w-[15ch] truncate block",children:a})})}},{header:"TTFT (s)",accessorKey:"completionStartTime",cell:e=>{let s=e.row.original,a=e.getValue();if(!a||a===s.endTime)return(0,t.jsx)("span",{children:"-"});let r=new Date(a).getTime()-new Date(s.startTime).getTime();if(r<=0)return(0,t.jsx)("span",{children:"-"});let i=(r/1e3).toFixed(2);return(0,t.jsx)(l.Tooltip,{title:`${r}ms`,children:(0,t.jsx)("span",{className:"max-w-[15ch] truncate block",children:i})})}},{header:"Team Name",accessorKey:"metadata.user_api_key_team_alias",cell:e=>(0,t.jsx)(l.Tooltip,{title:String(e.getValue()||"-"),children:(0,t.jsx)("span",{className:"max-w-[15ch] truncate block",children:String(e.getValue()||"-")})})},{header:"Key Hash",accessorKey:"metadata.user_api_key",cell:e=>{let s=String(e.getValue()||"-"),a=e.row.original.onKeyHashClick;return(0,t.jsx)(l.Tooltip,{title:s,children:(0,t.jsx)("span",{className:"font-mono max-w-[15ch] truncate block cursor-pointer hover:text-blue-600",onClick:()=>a?.(s),children:s})})}},{header:"Key Name",accessorKey:"metadata.user_api_key_alias",cell:e=>(0,t.jsx)(l.Tooltip,{title:String(e.getValue()||"-"),children:(0,t.jsx)("span",{className:"max-w-[15ch] truncate block",children:String(e.getValue()||"-")})})},{header:"Model",accessorKey:"model",cell:e=>{let s=e.row.original,a=s.custom_llm_provider,i=String(e.getValue()||"");return(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[a&&(0,t.jsx)("img",{src:s.metadata?.mcp_tool_call_metadata?.mcp_server_logo_url?s.metadata.mcp_tool_call_metadata.mcp_server_logo_url:a?(0,r.getProviderLogoAndName)(a).logo:"",alt:"",className:"w-4 h-4",onError:e=>{e.target.style.display="none"}}),(0,t.jsx)(l.Tooltip,{title:i,children:(0,t.jsx)("span",{className:"max-w-[15ch] truncate block",children:i})})]})}},{header:e?()=>(0,t.jsx)(h,{label:"Tokens",field:"total_tokens",sortBy:e.sortBy,sortOrder:e.sortOrder,onSortChange:e.onSortChange}):"Tokens",accessorKey:"total_tokens",cell:e=>{let s=e.row.original;return(0,t.jsxs)("span",{className:"text-sm",children:[String(s.total_tokens||"0"),(0,t.jsxs)("span",{className:"text-gray-400 text-xs ml-1",children:["(",String(s.prompt_tokens||"0"),"+",String(s.completion_tokens||"0"),")"]})]})}},{header:"Internal User",accessorKey:"user",cell:e=>(0,t.jsx)(l.Tooltip,{title:String(e.getValue()||"-"),children:(0,t.jsx)("span",{className:"max-w-[15ch] truncate block",children:String(e.getValue()||"-")})})},{header:"End User",accessorKey:"end_user",cell:e=>(0,t.jsx)(l.Tooltip,{title:String(e.getValue()||"-"),children:(0,t.jsx)("span",{className:"max-w-[15ch] truncate block",children:String(e.getValue()||"-")})})},{header:"Tags",accessorKey:"request_tags",cell:e=>{let s=e.getValue();if(!s||0===Object.keys(s).length)return"-";let a=Object.entries(s),r=a[0],i=a.slice(1);return(0,t.jsx)("div",{className:"flex flex-wrap gap-1",children:(0,t.jsx)(l.Tooltip,{title:(0,t.jsx)("div",{className:"flex flex-col gap-1",children:a.map(([e,s])=>(0,t.jsxs)("span",{children:[e,": ",String(s)]},e))}),children:(0,t.jsxs)("span",{className:"px-2 py-1 bg-gray-100 rounded-full text-xs",children:[r[0],": ",String(r[1]),i.length>0&&` +${i.length}`]})})})}}];g(),e.s(["createColumns",0,g],245099)},70969,e=>{"use strict";var t=e.i(843476);e.s(["ConfigInfoMessage",0,({show:e,onOpenSettings:s})=>e?(0,t.jsxs)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-4 flex items-start",children:[(0,t.jsx)("div",{className:"text-blue-500 mr-3 flex-shrink-0 mt-0.5",children:(0,t.jsxs)("svg",{xmlns:"http://www.w3.org/2000/svg",width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,t.jsx)("circle",{cx:"12",cy:"12",r:"10"}),(0,t.jsx)("line",{x1:"12",y1:"16",x2:"12",y2:"12"}),(0,t.jsx)("line",{x1:"12",y1:"8",x2:"12.01",y2:"8"})]})}),(0,t.jsxs)("div",{children:[(0,t.jsx)("h4",{className:"text-sm font-medium text-blue-800",children:"Request/Response Data Not Available"}),(0,t.jsxs)("p",{className:"text-sm text-blue-700 mt-1",children:["To view request and response details, enable prompt storage in your LiteLLM configuration by adding the following to your ",(0,t.jsx)("code",{className:"bg-blue-100 px-1 py-0.5 rounded",children:"proxy_config.yaml"})," file",s&&(0,t.jsxs)(t.Fragment,{children:[" or"," ",(0,t.jsx)("button",{onClick:s,className:"text-blue-600 hover:text-blue-800 underline font-medium",children:"open the settings"})," ","to configure this directly."]})]}),(0,t.jsx)("pre",{className:"mt-2 bg-white p-3 rounded border border-blue-200 text-xs font-mono overflow-auto",children:`general_settings: + store_model_in_db: true + store_prompts_in_spend_logs: true`}),(0,t.jsx)("p",{className:"text-xs text-blue-700 mt-2",children:"Note: This will only affect new requests after the configuration change."})]})]}):null])},70635,e=>{"use strict";var t=e.i(843476),s=e.i(362024),a=e.i(500330);let l=e=>null==e?"-":`$${(0,a.formatNumberWithCommas)(e,8)}`,r=e=>null==e?"-":`${(100*e).toFixed(2)}%`;e.s(["CostBreakdownViewer",0,({costBreakdown:e,totalSpend:a,promptTokens:i,completionTokens:n,cacheHit:o})=>{let d=o?.toLowerCase()==="true",c=void 0!==i||void 0!==n,m=e?.input_cost!==void 0||e?.output_cost!==void 0,x=e?.additional_costs&&Object.entries(e.additional_costs).some(([,e])=>null!=e&&0!==e);if(!(m||c||x||e&&(void 0!==e.discount_percent&&0!==e.discount_percent||void 0!==e.discount_amount&&0!==e.discount_amount||void 0!==e.margin_percent&&0!==e.margin_percent||void 0!==e.margin_fixed_amount&&0!==e.margin_fixed_amount||void 0!==e.margin_total_amount&&0!==e.margin_total_amount)))return null;let u=e&&(void 0!==e.discount_percent&&0!==e.discount_percent||void 0!==e.discount_amount&&0!==e.discount_amount),p=e&&(void 0!==e.margin_percent&&0!==e.margin_percent||void 0!==e.margin_fixed_amount&&0!==e.margin_fixed_amount||void 0!==e.margin_total_amount&&0!==e.margin_total_amount),h=d?0:e?.input_cost,g=d?0:e?.output_cost,f=d?0:e?.original_cost,y=d?0:e?.total_cost??a;return(0,t.jsx)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6",children:(0,t.jsx)(s.Collapse,{expandIconPosition:"start",items:[{key:"1",label:(0,t.jsxs)("div",{className:"flex items-center justify-between w-full",children:[(0,t.jsx)("h3",{className:"text-lg font-medium text-gray-900",children:"Cost Breakdown"}),(0,t.jsxs)("div",{className:"flex items-center space-x-2 mr-4",children:[(0,t.jsx)("span",{className:"text-sm text-gray-500",children:"Total:"}),(0,t.jsxs)("span",{className:"text-sm font-semibold text-gray-900",children:[l(a),d&&" (Cached)"]})]})]}),children:(0,t.jsxs)("div",{className:"p-6 space-y-4",children:[(0,t.jsxs)("div",{className:"space-y-2 max-w-2xl",children:[(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"text-gray-600 font-medium w-1/3",children:"Input Cost:"}),(0,t.jsxs)("span",{className:"text-gray-900",children:[l(h),void 0!==i&&(0,t.jsxs)("span",{className:"text-gray-500 font-normal ml-1",children:["(",i.toLocaleString()," prompt tokens)"]})]})]}),(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"text-gray-600 font-medium w-1/3",children:"Output Cost:"}),(0,t.jsxs)("span",{className:"text-gray-900",children:[l(g),void 0!==n&&(0,t.jsxs)("span",{className:"text-gray-500 font-normal ml-1",children:["(",n.toLocaleString()," completion tokens)"]})]})]}),e?.tool_usage_cost!==void 0&&e.tool_usage_cost>0&&(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"text-gray-600 font-medium w-1/3",children:"Tool Usage Cost:"}),(0,t.jsx)("span",{className:"text-gray-900",children:l(e.tool_usage_cost)})]}),e?.additional_costs&&Object.entries(e.additional_costs).filter(([,e])=>null!=e&&0!==e).map(([e,s])=>(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsxs)("span",{className:"text-gray-600 font-medium w-1/3",children:[e,":"]}),(0,t.jsx)("span",{className:"text-gray-900",children:l(s)})]},e))]}),!d&&(0,t.jsx)("div",{className:"pt-2 border-t border-gray-100 max-w-2xl",children:(0,t.jsxs)("div",{className:"flex text-sm font-semibold",children:[(0,t.jsx)("span",{className:"text-gray-900 w-1/3",children:"Original LLM Cost:"}),(0,t.jsx)("span",{className:"text-gray-900",children:l(f)})]})}),(u||p)&&(0,t.jsxs)("div",{className:"pt-2 space-y-2 max-w-2xl",children:[u&&(0,t.jsxs)("div",{className:"space-y-2",children:[void 0!==e.discount_percent&&0!==e.discount_percent&&(0,t.jsxs)("div",{className:"flex text-sm text-gray-600",children:[(0,t.jsxs)("span",{className:"font-medium w-1/3",children:["Discount (",r(e.discount_percent),"):"]}),(0,t.jsxs)("span",{className:"text-gray-900",children:["-",l(e.discount_amount)]})]}),void 0!==e.discount_amount&&void 0===e.discount_percent&&(0,t.jsxs)("div",{className:"flex text-sm text-gray-600",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Discount Amount:"}),(0,t.jsxs)("span",{className:"text-gray-900",children:["-",l(e.discount_amount)]})]})]}),p&&(0,t.jsxs)("div",{className:"space-y-2",children:[void 0!==e.margin_percent&&0!==e.margin_percent&&(0,t.jsxs)("div",{className:"flex text-sm text-gray-600",children:[(0,t.jsxs)("span",{className:"font-medium w-1/3",children:["Margin (",r(e.margin_percent),"):"]}),(0,t.jsxs)("span",{className:"text-gray-900",children:["+",l((e.margin_total_amount||0)-(e.margin_fixed_amount||0))]})]}),void 0!==e.margin_fixed_amount&&0!==e.margin_fixed_amount&&(0,t.jsxs)("div",{className:"flex text-sm text-gray-600",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Margin:"}),(0,t.jsxs)("span",{className:"text-gray-900",children:["+",l(e.margin_fixed_amount)]})]})]})]}),(0,t.jsx)("div",{className:"mt-4 pt-4 border-t border-gray-200 max-w-2xl",children:(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)("span",{className:"font-bold text-sm text-gray-900 w-1/3",children:"Final Calculated Cost:"}),(0,t.jsxs)("span",{className:"text-sm font-bold text-gray-900",children:[l(y),d&&" (Cached)"]})]})})]})}]})})}])},339086,504809,e=>{"use strict";e.i(843476);var t=e.i(271645);e.s([],339086);var s=e.i(166540),a=e.i(764205),l=e.i(266027),r=e.i(633627),i=e.i(374009),n=e.i(700514);let o="Team ID",d="Key Hash",c="Request ID",m="Model",x="User ID",u="End User",p="Status",h="Key Alias",g="Error Code",f="Error Message";function y({logs:e,accessToken:y,startTime:j,endTime:b,pageSize:v=n.defaultPageSize,isCustomDate:_,setCurrentPage:N,userID:w,userRole:S,sortBy:k="startTime",sortOrder:C="desc",currentPage:T=1}){let L=(0,t.useMemo)(()=>({[o]:"",[d]:"",[c]:"",[m]:"",[x]:"",[u]:"",[p]:"",[h]:"",[g]:"",[f]:""}),[]),[M,E]=(0,t.useState)(L),[A,D]=(0,t.useState)({data:[],total:0,page:1,page_size:50,total_pages:0}),I=(0,t.useRef)(0),O=(0,t.useCallback)(async(e,t=1)=>{if(!y)return;console.log("Filters being sent to API:",e);let l=Date.now();I.current=l;let r=(0,s.default)(j).utc().format("YYYY-MM-DD HH:mm:ss"),i=_?(0,s.default)(b).utc().format("YYYY-MM-DD HH:mm:ss"):(0,s.default)().utc().format("YYYY-MM-DD HH:mm:ss");try{let s=await (0,a.uiSpendLogsCall)({accessToken:y,start_date:r,end_date:i,page:t,page_size:v,params:{api_key:e[d]||void 0,team_id:e[o]||void 0,request_id:e[c]||void 0,user_id:e[x]||void 0,end_user:e[u]||void 0,status_filter:e[p]||void 0,model_id:e[m]||void 0,key_alias:e[h]||void 0,error_code:e[g]||void 0,error_message:e[f]||void 0,sort_by:k,sort_order:C}});l===I.current&&s.data&&D(s)}catch(e){console.error("Error searching users:",e)}},[y,j,b,_,v,k,C]),z=(0,t.useMemo)(()=>(0,i.default)((e,t)=>O(e,t),300),[O]);(0,t.useEffect)(()=>()=>z.cancel(),[z]);let R=(0,t.useMemo)(()=>!!(M[h]||M[d]||M[c]||M[x]||M[u]||M[g]||M[f]||M[m]),[M]);(0,t.useEffect)(()=>{R&&y&&(z.cancel(),O(M,T))},[k,C,T,j,b,_]);let P=(0,t.useMemo)(()=>{if(!e||!e.data)return{data:[],total:0,page:1,page_size:50,total_pages:0};if(R)return e;let t=[...e.data];return M[o]&&(t=t.filter(e=>e.team_id===M[o])),M[p]&&(t=t.filter(e=>"success"===M[p]?!e.status||"success"===e.status:e.status===M[p])),M[m]&&(t=t.filter(e=>e.model_id===M[m])),M[d]&&(t=t.filter(e=>e.api_key===M[d])),M[u]&&(t=t.filter(e=>e.end_user===M[u])),M[g]&&(t=t.filter(e=>{let t=(e.metadata||{}).error_information;return t&&t.error_code===M[g]})),{data:t,total:e.total,page:e.page,page_size:e.page_size,total_pages:e.total_pages}},[e,M,R]),B=(0,t.useMemo)(()=>R?A&&A.data&&A.data.length>0?A:e||{data:[],total:0,page:1,page_size:50,total_pages:0}:P,[R,A,P,e]),{data:F}=(0,l.useQuery)({queryKey:["allTeamsForLogFilters",y],queryFn:async()=>y&&await (0,r.fetchAllTeams)(y)||[],enabled:!!y});return{filters:M,filteredLogs:B,hasBackendFilters:R,allTeams:F,handleFilterChange:e=>{E(t=>{let s={...t,...e};for(let e of Object.keys(L))e in s||(s[e]=L[e]);return JSON.stringify(s)!==JSON.stringify(t)&&(N(1),z(s,1)),s})},handleFilterReset:()=>{E(L),D({data:[],total:0,page:1,page_size:50,total_pages:0}),z(L,1)}}}e.s(["useLogFilterLogic",()=>y],504809)},894660,283086,195116,e=>{"use strict";var t=e.i(801312);e.s(["LeftOutlined",()=>t.default],894660);var s=e.i(475254);let a=(0,s.default)("sparkles",[["path",{d:"M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z",key:"4pj2yx"}],["path",{d:"M20 3v4",key:"1olli1"}],["path",{d:"M22 5h-4",key:"1gvqau"}],["path",{d:"M4 17v2",key:"vumght"}],["path",{d:"M5 18H3",key:"zchphs"}]]);e.s(["Sparkles",()=>a],283086);let l=(0,s.default)("wrench",[["path",{d:"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z",key:"cbrjhi"}]]);e.s(["Wrench",()=>l],195116)},257486,624001,207066,337767,237062,e=>{"use strict";var t=e.i(97859);function s(e,s){let a=(s||"").trim();if(t.MCP_CALL_TYPES.includes(e))return a.replace(/^mcp:\s*/i,"").split("/").pop()||a||"mcp_tool";let l=(a.split("/").pop()||a).replace(/-20\d{6}.*$/i,"").replace(/:.*$/,""),r=l.match(/claude-[a-z0-9-]+/i);return r?r[0]:l||"llm_call"}e.s(["getEventDisplayName",()=>s],257486);var a=e.i(843476),l=e.i(464571),r=e.i(770914),i=e.i(262218),n=e.i(592968),o=e.i(898586),d=e.i(149192),c=e.i(536591);e.s(["UpOutlined",()=>c.default],624001);var c=c,m=e.i(755151),x=e.i(166540),u=e.i(916925);let p="16px 24px",h="Escape",g="monospace",f="#f0f0f0",y="#fff";e.s(["API_BASE_MAX_WIDTH",0,200,"COLOR_BACKGROUND",0,y,"COLOR_BG_LIGHT",0,"#fafafa","COLOR_BORDER",0,f,"DEFAULT_MAX_WIDTH",0,180,"DRAWER_CONTENT_PADDING",0,"24px","DRAWER_HEADER_PADDING",0,p,"DRAWER_WIDTH",0,"60%","FONT_FAMILY_MONO",0,g,"FONT_SIZE_HEADER",0,16,"FONT_SIZE_MEDIUM",0,13,"FONT_SIZE_SMALL",0,12,"JSON_MAX_HEIGHT",0,400,"KEY_ESCAPE",0,h,"KEY_J_LOWER",0,"j","KEY_J_UPPER",0,"J","KEY_K_LOWER",0,"k","KEY_K_UPPER",0,"K","METADATA_MAX_HEIGHT",0,300,"SPACING_LARGE",0,12,"SPACING_MEDIUM",0,8,"SPACING_SMALL",0,4,"SPACING_XLARGE",0,16,"TAB_REQUEST",0,"request","TAB_RESPONSE",0,"response"],207066);let{Text:j}=o.Typography;function b({log:e,onClose:t,onPrevious:s,onNext:l,statusLabel:r,statusColor:i,environment:n}){let o=e.custom_llm_provider||"",d=o?(0,u.getProviderLogoAndName)(o):null;return(0,a.jsxs)("div",{style:{padding:p,borderBottom:`1px solid ${f}`,backgroundColor:y,position:"sticky",top:0,zIndex:10},children:[(0,a.jsx)(v,{model:e.model,providerLogo:d?.logo,providerName:d?.displayName}),(0,a.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:8},children:[(0,a.jsx)(_,{requestId:e.request_id}),(0,a.jsx)(N,{onPrevious:s,onNext:l,onClose:t})]}),(0,a.jsx)(w,{log:e,statusLabel:r,statusColor:i,environment:n})]})}function v({model:e,providerLogo:t,providerName:s}){return(0,a.jsxs)(r.Space,{size:8,style:{marginBottom:8},children:[t&&(0,a.jsx)("img",{src:t,alt:s||"Provider",style:{width:24,height:24},onError:e=>{e.target.style.display="none"}}),(0,a.jsxs)(r.Space,{size:8,direction:"horizontal",children:[(0,a.jsx)(j,{strong:!0,style:{fontSize:14},children:e}),s&&(0,a.jsx)(j,{type:"secondary",style:{fontSize:12},children:s})]})]})}function _({requestId:e}){return(0,a.jsx)("div",{style:{flex:1,minWidth:0},children:(0,a.jsx)(n.Tooltip,{title:e,children:(0,a.jsx)(j,{strong:!0,copyable:{text:e,tooltips:["Copy Request ID","Copied!"]},style:{fontSize:16,fontFamily:g,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",display:"block"},children:e})})})}function N({onPrevious:e,onNext:t,onClose:s}){let i={border:"1px solid #d9d9d9",borderRadius:4,padding:"0 4px",fontSize:12,fontFamily:"monospace",marginLeft:4,background:"#fafafa"};return(0,a.jsxs)(r.Space,{size:4,split:(0,a.jsx)("div",{style:{width:1,height:20,background:f}}),children:[(0,a.jsxs)(l.Button,{type:"text",size:"small",onClick:e,children:[(0,a.jsx)(c.default,{}),(0,a.jsx)("span",{style:i,children:"K"})]}),(0,a.jsxs)(l.Button,{type:"text",size:"small",onClick:t,children:[(0,a.jsx)(m.DownOutlined,{}),(0,a.jsx)("span",{style:i,children:"J"})]}),(0,a.jsx)(n.Tooltip,{title:"ESC to close",children:(0,a.jsx)(l.Button,{type:"text",icon:(0,a.jsx)(d.CloseOutlined,{}),onClick:s})})]})}function w({log:e,statusLabel:t,statusColor:s,environment:l}){return(0,a.jsxs)(r.Space,{size:12,children:[(0,a.jsx)(i.Tag,{color:s,children:t}),(0,a.jsxs)(i.Tag,{children:["Env: ",l]}),(0,a.jsxs)(r.Space,{size:8,children:[(0,a.jsx)(j,{type:"secondary",style:{fontSize:13},children:(0,x.default)(e.startTime).format("MMM D, YYYY h:mm:ss A")}),(0,a.jsxs)(j,{type:"secondary",style:{fontSize:13},children:["(",(0,x.default)(e.startTime).fromNow(),")"]})]})]})}e.s(["DrawerHeader",()=>b],337767);var S=e.i(271645);function k({isOpen:e,currentLog:t,allLogs:s,onClose:a,onSelectLog:l}){(0,S.useEffect)(()=>{let t=t=>{var s;if(!((s=t.target)instanceof HTMLInputElement||s instanceof HTMLTextAreaElement)&&e)switch(t.key){case h:a();break;case"j":case"J":i();break;case"k":case"K":r()}};return window.addEventListener("keydown",t),()=>window.removeEventListener("keydown",t)},[e,t,s]);let r=()=>{if(!t||!s.length||!l)return;let e=s.findIndex(e=>e.request_id===t.request_id);e{if(!t||!s.length||!l)return;let e=s.findIndex(e=>e.request_id===t.request_id);e>0&&l(s[e-1])};return{selectNextLog:r,selectPreviousLog:i}}e.s(["useKeyboardNavigation",()=>k],237062)},3565,331052,867612,502626,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(464571),l=e.i(608856),r=e.i(492030),i=e.i(166406),n=e.i(894660),o=e.i(240647),d=e.i(531245),c=e.i(283086),m=e.i(195116),x=e.i(97859),u=e.i(257486),p=e.i(337767),h=e.i(237062),g=e.i(898586),f=e.i(869216),y=e.i(175712),j=e.i(262218),b=e.i(653496),v=e.i(560445),_=e.i(362024),N=e.i(91739),w=e.i(770914),S=e.i(482725),k=e.i(166540),C=e.i(500330),T=e.i(517442),L=e.i(70635),M=e.i(70969),E=e.i(916925);function A({data:e}){let[a,l]=(0,s.useState)({});if(!e||0===e.length)return null;let r=e=>new Date(1e3*e).toLocaleString();return(0,t.jsx)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6",children:(0,t.jsx)(_.Collapse,{defaultActiveKey:["1"],expandIconPosition:"start",items:[{key:"1",label:(0,t.jsx)("h3",{className:"text-lg font-medium text-gray-900",children:"Vector Store Requests"}),children:(0,t.jsx)("div",{className:"p-4",children:e.map((e,s)=>{var i,n;return(0,t.jsxs)("div",{className:"mb-6 last:mb-0",children:[(0,t.jsx)("div",{className:"bg-white rounded-lg border p-4 mb-4",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Query:"}),(0,t.jsx)("span",{className:"font-mono",children:e.query})]}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Vector Store ID:"}),(0,t.jsx)("span",{className:"font-mono",children:e.vector_store_id})]}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Provider:"}),(0,t.jsx)("span",{className:"flex items-center",children:(()=>{let{logo:s,displayName:a}=(0,E.getProviderLogoAndName)(e.custom_llm_provider);return(0,t.jsxs)(t.Fragment,{children:[s&&(0,t.jsx)("img",{src:s,alt:`${a} logo`,className:"h-5 w-5 mr-2"}),a]})})()})]})]}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Start Time:"}),(0,t.jsx)("span",{children:r(e.start_time)})]}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"End Time:"}),(0,t.jsx)("span",{children:r(e.end_time)})]}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Duration:"}),(0,t.jsx)("span",{children:(i=e.start_time,n=e.end_time,`${((n-i)*1e3).toFixed(2)}ms`)})]})]})]})}),(0,t.jsx)("h4",{className:"font-medium mb-2",children:"Search Results"}),(0,t.jsx)("div",{className:"space-y-2",children:e.vector_store_search_response.data.map((e,r)=>{let i=a[`${s}-${r}`]||!1;return(0,t.jsxs)("div",{className:"border rounded-lg overflow-hidden",children:[(0,t.jsxs)("div",{className:"flex items-center p-3 bg-gray-50 cursor-pointer",onClick:()=>{let e;return e=`${s}-${r}`,void l(t=>({...t,[e]:!t[e]}))},children:[(0,t.jsx)("svg",{className:`w-5 h-5 mr-2 transition-transform ${i?"transform rotate-90":""}`,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"})}),(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsxs)("span",{className:"font-medium mr-2",children:["Result ",r+1]}),(0,t.jsxs)("span",{className:"text-gray-500 text-sm",children:["Score: ",(0,t.jsx)("span",{className:"font-mono",children:e.score.toFixed(4)})]})]})]}),i&&(0,t.jsx)("div",{className:"p-3 border-t bg-white",children:e.content.map((e,s)=>(0,t.jsxs)("div",{className:"mb-2 last:mb-0",children:[(0,t.jsx)("div",{className:"text-xs text-gray-500 mb-1",children:e.type}),(0,t.jsx)("pre",{className:"text-xs font-mono whitespace-pre-wrap break-all bg-gray-50 p-2 rounded",children:e.text})]},s))})]},r)})})]},s)})})}]})})}e.s(["VectorStoreViewer",()=>A],331052);var D=e.i(592968),I=e.i(207066);let{Text:O}=g.Typography;function z({value:e,maxWidth:s=I.DEFAULT_MAX_WIDTH}){return e?(0,t.jsx)(D.Tooltip,{title:e,children:(0,t.jsx)(O,{copyable:{text:e,tooltips:["Copy","Copied!"]},style:{maxWidth:s,display:"inline-block",verticalAlign:"bottom",fontFamily:I.FONT_FAMILY_MONO,fontSize:I.FONT_SIZE_SMALL},ellipsis:!0,children:e})}):(0,t.jsx)(O,{type:"secondary",children:"-"})}let{Text:R}=g.Typography;function P({prompt:e=0,completion:s=0,total:a=0}){return(0,t.jsxs)(R,{children:[a.toLocaleString()," (",e.toLocaleString()," prompt tokens + ",s.toLocaleString()," completion tokens)"]})}let B=e=>!!e&&e instanceof Date,F=e=>"object"==typeof e&&null!==e,q=e=>!!e&&e instanceof Object&&"function"==typeof e;function H(e,t){return void 0===t&&(t=!1),!e||t?`"${e}"`:e}function $(e){let{field:t,value:a,data:l,lastElement:r,openBracket:i,closeBracket:n,level:o,style:d,shouldExpandNode:c,clickToExpandNode:m,outerRef:x,beforeExpandChange:u}=e,p=(0,s.useRef)(!1),[h,g]=(0,s.useState)(()=>c(o,a,t)),f=(0,s.useRef)(null);(0,s.useEffect)(()=>{p.current?g(c(o,a,t)):p.current=!0},[c]);let y=(0,s.useId)();if(0===l.length)return function(e){let{field:t,openBracket:a,closeBracket:l,lastElement:r,style:i}=e;return(0,s.createElement)("div",{className:i.basicChildStyle,role:"treeitem","aria-selected":void 0},(t||""===t)&&(0,s.createElement)("span",{className:i.label},H(t,i.quotesForFieldNames),":"),(0,s.createElement)("span",{className:i.punctuation},a),(0,s.createElement)("span",{className:i.punctuation},l),!r&&(0,s.createElement)("span",{className:i.punctuation},","))}({field:t,openBracket:i,closeBracket:n,lastElement:r,style:d});let j=h?d.collapseIcon:d.expandIcon,b=h?d.ariaLables.collapseJson:d.ariaLables.expandJson,v=o+1,_=l.length-1,N=e=>{h!==e&&(!u||u({level:o,value:a,field:t,newExpandValue:e}))&&g(e)},w=e=>{if("ArrowRight"===e.key||"ArrowLeft"===e.key)e.preventDefault(),N("ArrowRight"===e.key);else if("ArrowUp"===e.key||"ArrowDown"===e.key){e.preventDefault();let t="ArrowUp"===e.key?-1:1;if(!x.current)return;let s=x.current.querySelectorAll("[role=button]"),a=-1;for(let e=0;e{var e;N(!h);let t=f.current;if(!t)return;let s=null==(e=x.current)?void 0:e.querySelector('[role=button][tabindex="0"]');s&&(s.tabIndex=-1),t.tabIndex=0,t.focus()};return(0,s.createElement)("div",{className:d.basicChildStyle,role:"treeitem","aria-expanded":h,"aria-selected":void 0},(0,s.createElement)("span",{className:j,onClick:S,onKeyDown:w,role:"button","aria-label":b,"aria-expanded":h,"aria-controls":h?y:void 0,ref:f,tabIndex:0===o?0:-1}),(t||""===t)&&(m?(0,s.createElement)("span",{className:d.clickableLabel,onClick:S,onKeyDown:w},H(t,d.quotesForFieldNames),":"):(0,s.createElement)("span",{className:d.label},H(t,d.quotesForFieldNames),":")),(0,s.createElement)("span",{className:d.punctuation},i),h?(0,s.createElement)("ul",{id:y,role:"group",className:d.childFieldsContainer},l.map((e,t)=>(0,s.createElement)(W,{key:e[0]||t,field:e[0],value:e[1],style:d,lastElement:t===_,level:v,shouldExpandNode:c,clickToExpandNode:m,beforeExpandChange:u,outerRef:x}))):(0,s.createElement)("span",{className:d.collapsedContent,onClick:S,onKeyDown:w}),(0,s.createElement)("span",{className:d.punctuation},n),!r&&(0,s.createElement)("span",{className:d.punctuation},","))}function Y(e){let{field:t,value:s,style:a,lastElement:l,shouldExpandNode:r,clickToExpandNode:i,level:n,outerRef:o,beforeExpandChange:d}=e;return $({field:t,value:s,lastElement:l||!1,level:n,openBracket:"{",closeBracket:"}",style:a,shouldExpandNode:r,clickToExpandNode:i,data:Object.keys(s).map(e=>[e,s[e]]),outerRef:o,beforeExpandChange:d})}function K(e){let{field:t,value:s,style:a,lastElement:l,level:r,shouldExpandNode:i,clickToExpandNode:n,outerRef:o,beforeExpandChange:d}=e;return $({field:t,value:s,lastElement:l||!1,level:r,openBracket:"[",closeBracket:"]",style:a,shouldExpandNode:i,clickToExpandNode:n,data:s.map(e=>[void 0,e]),outerRef:o,beforeExpandChange:d})}function V(e){let t,{field:a,value:l,style:r,lastElement:i}=e,n=r.otherValue;if(null===l)t="null",n=r.nullValue;else if(void 0===l)t="undefined",n=r.undefinedValue;else if("string"==typeof l||l instanceof String){var o;o=!r.noQuotesForStringValues,t=r.stringifyStringValues?JSON.stringify(l):o?`"${l}"`:l,n=r.stringValue}else if("boolean"==typeof l||l instanceof Boolean)t=l?"true":"false",n=r.booleanValue;else if("number"==typeof l||l instanceof Number)t=l.toString(),n=r.numberValue;else"bigint"==typeof l||l instanceof BigInt?(t=`${l.toString()}n`,n=r.numberValue):t=B(l)?l.toISOString():q(l)?"function() { }":l.toString();return(0,s.createElement)("div",{className:r.basicChildStyle,role:"treeitem","aria-selected":void 0},(a||""===a)&&(0,s.createElement)("span",{className:r.label},H(a,r.quotesForFieldNames),":"),(0,s.createElement)("span",{className:n},t),!i&&(0,s.createElement)("span",{className:r.punctuation},","))}function W(e){let t=e.value;return Array.isArray(t)?(0,s.createElement)(K,Object.assign({},e)):!F(t)||B(t)||q(t)?(0,s.createElement)(V,Object.assign({},e)):(0,s.createElement)(Y,Object.assign({},e))}let U={container:"_2IvMF _GzYRV",basicChildStyle:"_2bkNM",childFieldsContainer:"_1BXBN",label:"_1MGIk",clickableLabel:"_2YKJg _1MGIk _1MFti",nullValue:"_2T6PJ",undefinedValue:"_1Gho6",stringValue:"_vGjyY",booleanValue:"_3zQKs",numberValue:"_1bQdo",otherValue:"_1xvuR",punctuation:"_3uHL6 _3eOF8",collapseIcon:"_oLqym _f10Tu _1MFti _1LId0",expandIcon:"_2AXVT _f10Tu _1MFti _1UmXx",collapsedContent:"_2KJWg _1pNG9 _1MFti",noQuotesForStringValues:!1,quotesForFieldNames:!1,ariaLables:{collapseJson:"collapse JSON",expandJson:"expand JSON"},stringifyStringValues:!1},G=()=>!0,J=e=>{let{data:t,style:a=U,shouldExpandNode:l=G,clickToExpandNode:r=!1,beforeExpandChange:i,compactTopLevel:n,...o}=e,d=(0,s.useRef)(null);return(0,s.createElement)("div",Object.assign({"aria-label":"JSON view"},o,{className:a.container,ref:d,role:"tree"}),n&&F(t)?Object.entries(t).map(e=>{let[t,n]=e;return(0,s.createElement)(W,{key:t,field:t,value:n,style:{...U,...a},lastElement:!0,level:1,shouldExpandNode:l,clickToExpandNode:r,beforeExpandChange:i,outerRef:d})}):(0,s.createElement)(W,{value:t,style:{...U,...a},lastElement:!0,level:0,shouldExpandNode:l,clickToExpandNode:r,outerRef:d,beforeExpandChange:i}))};e.s(["JsonView",()=>J,"defaultStyles",()=>U],867612);let{Text:Q}=g.Typography;function X({data:e}){return e?(0,t.jsx)("div",{style:{maxHeight:I.JSON_MAX_HEIGHT,overflow:"auto",background:I.COLOR_BG_LIGHT,padding:I.SPACING_LARGE,borderRadius:4},children:(0,t.jsx)("div",{className:"[&_[role='tree']]:bg-white [&_[role='tree']]:text-slate-900",children:(0,t.jsx)(J,{data:e,style:U,clickToExpandNode:!0})})}):(0,t.jsx)(Q,{type:"secondary",children:"No data"})}function Z(e){if("string"==typeof e)try{return JSON.parse(e)}catch{}return e}function ee(e){return Array.isArray(e)?e:e?[e]:[]}function et(e){if("string"==typeof e)try{return JSON.parse(e)}catch{}return e}var es=e.i(366308),ea=e.i(755151),el=e.i(291542);let{Text:er}=g.Typography;function ei({tool:e}){let s=Object.entries(e.parameters?.properties||{}).map(([t,s])=>({key:t,name:t,type:s.type||"any",description:s.description||"-",required:e.parameters?.required?.includes(t)||!1})),a=[{title:"Parameter",dataIndex:"name",key:"name",render:(e,s)=>(0,t.jsxs)(er,{code:!0,children:[e,s.required&&(0,t.jsx)(er,{type:"danger",children:"*"})]})},{title:"Type",dataIndex:"type",key:"type",render:e=>(0,t.jsx)(er,{code:!0,style:{color:"#1890ff"},children:e})},{title:"Description",dataIndex:"description",key:"description",render:e=>(0,t.jsx)(er,{type:"secondary",children:e})}];return(0,t.jsxs)("div",{children:[e.description&&(0,t.jsx)("div",{style:{marginBottom:16},children:(0,t.jsx)(er,{style:{lineHeight:1.6,whiteSpace:"pre-wrap"},children:e.description})}),s.length>0&&(0,t.jsxs)("div",{children:[(0,t.jsx)(er,{type:"secondary",style:{fontSize:12,display:"block",marginBottom:8},children:"Parameters"}),(0,t.jsx)(el.Table,{dataSource:s,columns:a,pagination:!1,size:"small",bordered:!0})]}),e.called&&e.callData&&(0,t.jsxs)("div",{style:{marginTop:16},children:[(0,t.jsx)(er,{type:"secondary",style:{fontSize:12,display:"block",marginBottom:8},children:"Called With"}),(0,t.jsx)("div",{style:{background:"#f6ffed",border:"1px solid #b7eb8f",borderRadius:4,padding:12},children:(0,t.jsx)("pre",{style:{margin:0,fontSize:12,whiteSpace:"pre-wrap",wordBreak:"break-word"},children:JSON.stringify(e.callData.arguments,null,2)})})]})]})}function en({tool:e}){let s={type:"function",function:{name:e.name,description:e.description,parameters:e.parameters}};return(0,t.jsx)("pre",{style:{margin:0,whiteSpace:"pre-wrap",wordBreak:"break-word",fontSize:12,background:"#fafafa",padding:12,borderRadius:4,maxHeight:300,overflow:"auto"},children:JSON.stringify(s,null,2)})}let{Text:eo}=g.Typography;function ed({tool:e}){let[a,l]=(0,s.useState)("formatted");return(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",marginBottom:12},children:[(0,t.jsx)(eo,{type:"secondary",style:{fontSize:12},children:"Description"}),(0,t.jsxs)(N.Radio.Group,{size:"small",value:a,onChange:e=>l(e.target.value),children:[(0,t.jsx)(N.Radio.Button,{value:"formatted",children:"Formatted"}),(0,t.jsx)(N.Radio.Button,{value:"json",children:"JSON"})]})]}),"formatted"===a?(0,t.jsx)(ei,{tool:e}):(0,t.jsx)(en,{tool:e})]})}let{Text:ec}=g.Typography;function em({tool:e}){let[a,l]=(0,s.useState)(!1);return(0,t.jsxs)("div",{style:{border:"1px solid #f0f0f0",borderRadius:8,overflow:"hidden"},children:[(0,t.jsxs)("div",{onClick:()=>l(!a),style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"12px 16px",cursor:"pointer",background:a?"#fafafa":"#fff",transition:"background 0.2s"},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:10},children:[(0,t.jsx)(es.ToolOutlined,{style:{color:"#8c8c8c",fontSize:14}}),(0,t.jsxs)(ec,{style:{fontSize:14},children:[e.index,". ",e.name]})]}),(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8},children:[(0,t.jsx)(j.Tag,{color:e.called?"blue":"default",children:e.called?"called":"not called"}),a?(0,t.jsx)(ea.DownOutlined,{style:{fontSize:12,color:"#8c8c8c"}}):(0,t.jsx)(o.RightOutlined,{style:{fontSize:12,color:"#8c8c8c"}})]})]}),a&&(0,t.jsx)("div",{style:{padding:"16px",borderTop:"1px solid #f0f0f0",background:"#fff"},children:(0,t.jsx)(ed,{tool:e})})]})}let{Text:ex}=g.Typography;function eu({log:e}){let s=function(e){let t,s=!(t=et(e.proxy_server_request||e.messages))||Array.isArray(t)?[]:"object"==typeof t&&t.tools&&Array.isArray(t.tools)?t.tools:[];if(0===s.length)return[];let a=function(e){let t=et(e.response);if(!t||"object"!=typeof t)return[];let s=t.choices;if(Array.isArray(s)&&s.length>0){let e=s[0].message;if(e&&Array.isArray(e.tool_calls))return e.tool_calls}if(Array.isArray(t.content)){let e=t.content.filter(e=>"tool_use"===e.type);if(e.length>0)return e.map(e=>({id:e.id,type:"function",function:{name:e.name,arguments:JSON.stringify(e.input||{})}}))}if(Array.isArray(t.tool_calls))return t.tool_calls;if(Array.isArray(t.results)){let e=[];for(let s of t.results)if("response.done"===s.type&&s.response?.output)for(let t of s.response.output)"function_call"===t.type&&e.push({id:t.call_id||"",type:"function",function:{name:t.name||"",arguments:t.arguments||"{}"}});if(e.length>0)return e}return[]}(e),l=new Set(a.map(e=>e.function?.name).filter(Boolean)),r=new Map;return a.forEach(e=>{let t=e.function?.name;t&&r.set(t,{id:e.id,name:t,arguments:function(e){try{return JSON.parse(e)}catch{return{}}}(e.function?.arguments||"{}")})}),s.map((e,t)=>{let s=e.function?.name||e.name||`Tool ${t+1}`;return{index:t+1,name:s,description:e.function?.description||e.description||"",parameters:e.function?.parameters||e.input_schema||{},called:l.has(s),callData:r.get(s)}})}(e);if(0===s.length)return null;let a=s.length,l=s.filter(e=>e.called).length,r=s.slice(0,2).map(e=>e.name).join(", "),i=s.length>2;return(0,t.jsx)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6",children:(0,t.jsx)(_.Collapse,{expandIconPosition:"start",items:[{key:"1",label:(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:12,flexWrap:"wrap"},children:[(0,t.jsx)("h3",{className:"text-lg font-medium text-gray-900",children:"Tools"}),(0,t.jsxs)(ex,{type:"secondary",style:{fontSize:14},children:[a," provided, ",l," called"]}),(0,t.jsxs)(ex,{type:"secondary",style:{fontSize:14},children:["• ",r,i&&"..."]})]}),children:(0,t.jsx)("div",{style:{display:"flex",flexDirection:"column",gap:8},children:s.map(e=>(0,t.jsx)(em,{tool:e},e.name))})}]})})}let ep=e=>{if(!e)return{};if("string"==typeof e)try{return JSON.parse(e)}catch{return{raw:e}}return e};var eh=e.i(998573),eg=e.i(264843),ef=e.i(624001);let{Text:ey}=g.Typography;function ej({type:e,tokens:s,cost:l,onCopy:r,isCollapsed:n,onToggleCollapse:o,turnCount:d}){return(0,t.jsxs)("div",{onClick:o,style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"10px 16px",borderBottom:n?"none":"1px solid #f0f0f0",background:"#fafafa",cursor:o?"pointer":"default",transition:"background 0.15s ease"},onMouseEnter:e=>{o&&(e.currentTarget.style.background="#f5f5f5")},onMouseLeave:e=>{e.currentTarget.style.background="#fafafa"},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:16},children:[o&&(0,t.jsx)("div",{style:{display:"flex",alignItems:"center"},children:n?(0,t.jsx)(ea.DownOutlined,{style:{fontSize:10,color:"#8c8c8c"}}):(0,t.jsx)(ef.UpOutlined,{style:{fontSize:10,color:"#8c8c8c"}})}),(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8},children:["input"===e?(0,t.jsx)(eg.MessageOutlined,{style:{color:"#8c8c8c",fontSize:14}}):(0,t.jsx)("span",{style:{fontSize:14,filter:"grayscale(1)",opacity:.6},children:"✨"}),(0,t.jsx)(ey,{style:{fontWeight:500,fontSize:14},children:"input"===e?"Input":"Output"})]}),void 0!==s&&(0,t.jsxs)(ey,{type:"secondary",style:{fontSize:12},children:["Tokens: ",s.toLocaleString()]}),void 0!==l&&(0,t.jsxs)(ey,{type:"secondary",style:{fontSize:12},children:["Cost: $",l.toFixed(6)]}),void 0!==d&&d>0&&(0,t.jsxs)(ey,{type:"secondary",style:{fontSize:12},children:["Turns: ",d]})]}),(0,t.jsx)(D.Tooltip,{title:"Copy",children:(0,t.jsx)(a.Button,{type:"text",size:"small",icon:(0,t.jsx)(i.CopyOutlined,{}),onClick:e=>{e.stopPropagation(),r()}})})]})}let{Text:eb}=g.Typography;function ev({label:e,content:a,defaultExpanded:l=!1}){let[r,i]=(0,s.useState)(l),[n,d]=(0,s.useState)(!1),c=a?.length||0;return a&&0!==c?(0,t.jsxs)("div",{style:{marginBottom:8},children:[(0,t.jsxs)("div",{onClick:()=>i(!r),onMouseEnter:()=>d(!0),onMouseLeave:()=>d(!1),style:{display:"flex",alignItems:"center",gap:6,cursor:"pointer",padding:"4px 0",borderRadius:4,background:n?"#f5f5f5":"transparent",transition:"background 0.15s ease",marginBottom:4*!!r},children:[r?(0,t.jsx)(ea.DownOutlined,{style:{fontSize:10,color:"#8c8c8c"}}):(0,t.jsx)(o.RightOutlined,{style:{fontSize:10,color:"#8c8c8c"}}),(0,t.jsx)(eb,{type:"secondary",style:{fontSize:10,letterSpacing:"0.5px",textTransform:"uppercase"},children:e}),(0,t.jsxs)(eb,{type:"secondary",style:{fontSize:10},children:["(",c.toLocaleString()," chars)"]})]}),(0,t.jsx)("div",{style:{maxHeight:r?"2000px":"0px",overflow:"hidden",transition:"max-height 0.2s ease-out, opacity 0.2s ease-out",opacity:+!!r},children:(0,t.jsx)("div",{style:{paddingLeft:16,fontSize:13,lineHeight:1.7,color:"#262626",borderLeft:"1px solid #f0f0f0",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:a})})]}):null}let{Text:e_}=g.Typography;function eN({tool:e,compact:s=!1}){return(0,t.jsxs)("div",{style:{background:"#f8f9fa",border:"1px solid #e9ecef",borderRadius:6,padding:s?"6px 10px":"10px 14px",marginTop:8,fontFamily:"monospace",fontSize:12,position:"relative"},children:[(0,t.jsx)("div",{style:{position:"absolute",top:-8,left:12,background:"#fff",padding:"0 6px",fontSize:10,color:"#8c8c8c",border:"1px solid #e9ecef",borderRadius:3},children:"function"}),(0,t.jsx)(e_,{strong:!0,style:{fontSize:13,display:"block",marginBottom:6},children:e.name}),Object.keys(e.arguments).length>0&&(0,t.jsx)("div",{children:Object.entries(e.arguments).map(([e,s])=>(0,t.jsxs)("div",{style:{marginBottom:2},children:[(0,t.jsxs)(e_,{type:"secondary",style:{fontSize:12},children:[e,":"," "]}),(0,t.jsx)(e_,{style:{fontSize:12},children:JSON.stringify(s)})]},e))})]})}let{Text:ew}=g.Typography;function eS({label:e,content:s,toolCalls:a,isCompact:l=!1}){let r=s&&"null"!==s&&s.length>0?s:null,i=a&&a.length>0;return r||i?(0,t.jsxs)("div",{style:{marginBottom:8*!!l},children:[(0,t.jsx)(ew,{type:"secondary",style:{fontSize:10,letterSpacing:"0.5px",textTransform:"uppercase",display:"block",marginBottom:3},children:e}),r&&(0,t.jsx)("div",{style:{fontSize:13,lineHeight:1.7,color:"#262626",whiteSpace:"pre-wrap",wordBreak:"break-word",marginBottom:6*!!i},children:r}),i&&(0,t.jsx)("div",{children:a.map((e,s)=>(0,t.jsx)(eN,{tool:e,compact:l},e.id||s))})]}):null}let{Text:ek}=g.Typography;function eC({messages:e}){let[a,l]=(0,s.useState)(!1),[r,i]=(0,s.useState)(!1);return 0===e.length?null:(0,t.jsxs)("div",{style:{marginBottom:8},children:[(0,t.jsxs)("div",{onClick:()=>l(!a),onMouseEnter:()=>i(!0),onMouseLeave:()=>i(!1),style:{display:"flex",alignItems:"center",gap:6,cursor:"pointer",padding:"4px 0",borderRadius:4,background:r?"#f5f5f5":"transparent",transition:"background 0.15s ease",marginBottom:4*!!a},children:[a?(0,t.jsx)(ea.DownOutlined,{style:{fontSize:10,color:"#8c8c8c"}}):(0,t.jsx)(o.RightOutlined,{style:{fontSize:10,color:"#8c8c8c"}}),(0,t.jsxs)(ek,{type:"secondary",style:{fontSize:10,letterSpacing:"0.5px",textTransform:"uppercase"},children:["HISTORY (",e.length," message",1!==e.length?"s":"",")"]})]}),(0,t.jsx)("div",{style:{maxHeight:a?"2000px":"0px",overflow:"hidden",transition:"max-height 0.2s ease-out, opacity 0.2s ease-out",opacity:+!!a},children:(0,t.jsx)("div",{style:{paddingLeft:16,borderLeft:"1px solid #f0f0f0"},children:e.map((e,s)=>(0,t.jsx)(eS,{label:e.role.toUpperCase(),content:e.content,toolCalls:e.toolCalls,isCompact:!0},s))})})]})}function eT({messages:e,promptTokens:a,inputCost:l}){let[r,i]=(0,s.useState)(!1);if(0===e.length)return null;let n=e.find(e=>"system"===e.role),o=e.filter(e=>"system"!==e.role),d=o.length>0?o[o.length-1]:null,c=o.slice(0,-1);return(0,t.jsxs)("div",{style:{border:"1px solid #f0f0f0",borderRadius:6,marginBottom:8,overflow:"hidden"},children:[(0,t.jsx)(ej,{type:"input",tokens:a,cost:l,onCopy:()=>{let e=d?.content||"";navigator.clipboard.writeText(e),eh.message.success("Input copied")},isCollapsed:r,onToggleCollapse:()=>i(!r)}),(0,t.jsx)("div",{style:{maxHeight:r?"0px":"10000px",overflow:"hidden",transition:"max-height 0.3s ease-out, opacity 0.3s ease-out",opacity:+!r},children:(0,t.jsxs)("div",{style:{padding:"12px 16px"},children:[n&&(0,t.jsx)(ev,{label:"SYSTEM",content:n.content,defaultExpanded:!!(n.content&&n.content.length<200)}),c.length>0&&(0,t.jsx)(eC,{messages:c}),d&&(0,t.jsx)(eS,{label:d.role.toUpperCase(),content:d.content,toolCalls:d.toolCalls})]})})]})}let{Text:eL}=g.Typography;function eM({message:e,completionTokens:a,outputCost:l}){let[r,i]=(0,s.useState)(!1),n=()=>{if(!e)return;let t=e.content||"";navigator.clipboard.writeText(t),eh.message.success("Output copied")};return e?(0,t.jsxs)("div",{style:{border:"1px solid #f0f0f0",borderRadius:6,overflow:"hidden"},children:[(0,t.jsx)(ej,{type:"output",tokens:a,cost:l,onCopy:n,isCollapsed:r,onToggleCollapse:()=>i(!r)}),(0,t.jsx)("div",{style:{maxHeight:r?"0px":"10000px",overflow:"hidden",transition:"max-height 0.3s ease-out, opacity 0.3s ease-out",opacity:+!r},children:(0,t.jsx)("div",{style:{padding:"12px 16px"},children:(0,t.jsx)(eS,{label:"ASSISTANT",content:e.content,toolCalls:e.toolCalls})})})]}):(0,t.jsxs)("div",{style:{border:"1px solid #f0f0f0",borderRadius:6,overflow:"hidden"},children:[(0,t.jsx)(ej,{type:"output",tokens:a,cost:l,onCopy:n,isCollapsed:r,onToggleCollapse:()=>i(!r)}),(0,t.jsx)("div",{style:{maxHeight:r?"0px":"10000px",overflow:"hidden",transition:"max-height 0.3s ease-out, opacity 0.3s ease-out",opacity:+!r},children:(0,t.jsx)("div",{style:{padding:"12px 16px"},children:(0,t.jsx)(eL,{type:"secondary",style:{fontSize:13,fontStyle:"italic"},children:"No response data available"})})})]})}var eE=e.i(782273),eA=e.i(313603),eD=e.i(793916);let{Text:eI}=g.Typography;function eO({response:e,metrics:s}){let a=e?.results||[],l=e?.usage,r=a.find(e=>"session.created"===e.type||"session.updated"===e.type),i=a.filter(e=>"response.done"===e.type);return(0,t.jsxs)("div",{children:[r?.session&&(0,t.jsx)(ez,{session:r.session,turnCount:i.length}),i.length>0&&(0,t.jsx)(eR,{responses:i.map(e=>e.response).filter(Boolean),totalUsage:l,metrics:s}),!r&&0===i.length&&(0,t.jsx)("div",{style:{border:"1px solid #f0f0f0",borderRadius:6,padding:"16px",color:"#8c8c8c",fontStyle:"italic",fontSize:13},children:"No recognized realtime events found"})]})}function ez({session:e,turnCount:a}){let[l,r]=(0,s.useState)(!0);return(0,t.jsxs)("div",{style:{border:"1px solid #f0f0f0",borderRadius:6,marginBottom:8,overflow:"hidden"},children:[(0,t.jsx)("div",{onClick:()=>r(!l),style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"10px 16px",borderBottom:l?"none":"1px solid #f0f0f0",background:"#fafafa",cursor:"pointer",transition:"background 0.15s ease"},onMouseEnter:e=>{e.currentTarget.style.background="#f5f5f5"},onMouseLeave:e=>{e.currentTarget.style.background="#fafafa"},children:(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:16},children:[(0,t.jsx)("div",{style:{display:"flex",alignItems:"center"},children:l?(0,t.jsx)(ea.DownOutlined,{style:{fontSize:10,color:"#8c8c8c"}}):(0,t.jsx)(ef.UpOutlined,{style:{fontSize:10,color:"#8c8c8c"}})}),(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8},children:[(0,t.jsx)(eA.SettingOutlined,{style:{color:"#8c8c8c",fontSize:14}}),(0,t.jsx)(eI,{style:{fontWeight:500,fontSize:14},children:"Session"})]}),(0,t.jsx)(eI,{type:"secondary",style:{fontSize:12},children:e.model}),a>0&&(0,t.jsxs)(j.Tag,{color:"purple",style:{margin:0,fontWeight:500},children:[a," ",1===a?"turn":"turns"]}),e.voice&&(0,t.jsxs)(j.Tag,{color:"blue",style:{margin:0},children:[(0,t.jsx)(eE.SoundOutlined,{})," ",e.voice]}),e.modalities&&(0,t.jsx)("div",{style:{display:"flex",gap:4},children:e.modalities.map(e=>(0,t.jsxs)(j.Tag,{style:{margin:0},children:["audio"===e?(0,t.jsx)(eD.AudioOutlined,{}):(0,t.jsx)(eg.MessageOutlined,{})," ",e]},e))})]})}),(0,t.jsx)("div",{style:{maxHeight:l?"0px":"10000px",overflow:"hidden",transition:"max-height 0.3s ease-out, opacity 0.3s ease-out",opacity:+!l},children:(0,t.jsxs)("div",{style:{padding:"12px 16px"},children:[(0,t.jsxs)("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"8px 24px",fontSize:13},children:[(0,t.jsx)(eq,{label:"Model",value:e.model}),(0,t.jsx)(eq,{label:"Voice",value:e.voice}),(0,t.jsx)(eq,{label:"Temperature",value:e.temperature}),(0,t.jsx)(eq,{label:"Max Output Tokens",value:e.max_response_output_tokens}),(0,t.jsx)(eq,{label:"Input Audio Format",value:e.input_audio_format}),(0,t.jsx)(eq,{label:"Output Audio Format",value:e.output_audio_format}),e.turn_detection&&(0,t.jsx)(eq,{label:"Turn Detection",value:e.turn_detection.type}),e.tools&&e.tools.length>0&&(0,t.jsx)(eq,{label:"Tools",value:`${e.tools.length} tool(s)`})]}),e.instructions&&(0,t.jsxs)("div",{style:{marginTop:12},children:[(0,t.jsx)(eI,{type:"secondary",style:{fontSize:10,letterSpacing:"0.5px",textTransform:"uppercase",display:"block",marginBottom:4},children:"Instructions"}),(0,t.jsx)("div",{style:{fontSize:12,lineHeight:1.6,color:"#595959",background:"#fafafa",padding:"8px 12px",borderRadius:4,border:"1px solid #f0f0f0",whiteSpace:"pre-wrap",wordBreak:"break-word",maxHeight:120,overflowY:"auto"},children:e.instructions})]})]})})]})}function eR({responses:e,totalUsage:a,metrics:l}){let[r,i]=(0,s.useState)(!1),n=a?.total_tokens,o=e.length;return(0,t.jsxs)("div",{style:{border:"1px solid #f0f0f0",borderRadius:6,overflow:"hidden"},children:[(0,t.jsx)(ej,{type:"output",tokens:l?.completion_tokens??n,cost:l?.output_cost,onCopy:()=>{let t=e.flatMap(e=>(e.output||[]).flatMap(e=>(e.content||[]).map(t=>`${e.role}: ${t.transcript||t.text||""}`))).join("\n");navigator.clipboard.writeText(t)},isCollapsed:r,onToggleCollapse:()=>i(!r),turnCount:o}),(0,t.jsx)("div",{style:{maxHeight:r?"0px":"10000px",overflow:"hidden",transition:"max-height 0.3s ease-out, opacity 0.3s ease-out",opacity:+!r},children:(0,t.jsx)("div",{style:{padding:"12px 16px"},children:e.map((e,s)=>(0,t.jsx)(eP,{response:e,index:s},e.id||s))})})]})}function eP({response:e,index:s}){let a=e.output||[],l=e.usage;return(0,t.jsxs)("div",{style:{marginBottom:12,paddingBottom:12,borderBottom:"1px solid #f5f5f5"},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8,marginBottom:8},children:[(0,t.jsx)(j.Tag,{color:"completed"===e.status?"green":"orange",style:{margin:0},children:e.status||"unknown"}),l&&(0,t.jsxs)(eI,{type:"secondary",style:{fontSize:11},children:[l.input_tokens??0," in / ",l.output_tokens??0," out tokens"]}),e.conversation_id&&(0,t.jsx)(D.Tooltip,{title:e.conversation_id,children:(0,t.jsxs)(eI,{type:"secondary",style:{fontSize:11,cursor:"help"},children:["conv: ",e.conversation_id.slice(0,12),"..."]})})]}),a.map((e,s)=>(0,t.jsx)(eB,{output:e},e.id||s)),l?.input_token_details&&(0,t.jsx)(eF,{label:"Input",details:l.input_token_details}),l?.output_token_details&&(0,t.jsx)(eF,{label:"Output",details:l.output_token_details})]})}function eB({output:e}){let s=e.content||[];return s.some(e=>e.transcript||e.text)?(0,t.jsxs)("div",{style:{marginBottom:8},children:[(0,t.jsx)(eI,{type:"secondary",style:{fontSize:10,letterSpacing:"0.5px",textTransform:"uppercase",display:"block",marginBottom:3},children:e.role?.toUpperCase()||"ASSISTANT"}),s.map((e,s)=>{let a=e.transcript||e.text;return a?(0,t.jsxs)("div",{style:{display:"flex",alignItems:"flex-start",gap:8,marginBottom:4},children:["audio"===e.type&&(0,t.jsx)(eD.AudioOutlined,{style:{color:"#8c8c8c",fontSize:12,marginTop:3,flexShrink:0}}),"text"===e.type&&(0,t.jsx)(eg.MessageOutlined,{style:{color:"#8c8c8c",fontSize:12,marginTop:3,flexShrink:0}}),(0,t.jsx)("div",{style:{fontSize:13,lineHeight:1.7,color:"#262626",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:a})]},s):null})]}):null}function eF({label:e,details:s}){let a=Object.entries(s).filter(([,e])=>"number"==typeof e||"object"==typeof e&&null!==e);return 0===a.length?null:(0,t.jsxs)("div",{style:{marginTop:4},children:[(0,t.jsxs)(eI,{type:"secondary",style:{fontSize:10,letterSpacing:"0.5px",textTransform:"uppercase"},children:[e," Token Breakdown"]}),(0,t.jsx)("div",{style:{display:"flex",flexWrap:"wrap",gap:8,marginTop:4},children:a.map(([e,s])=>"number"==typeof s?(0,t.jsxs)(j.Tag,{style:{margin:0},children:[e.replace(/_/g," ").replace(/\b\w/g,e=>e.toUpperCase()),": ",s.toLocaleString()]},e):null)})]})}function eq({label:e,value:s}){return null==s?null:(0,t.jsxs)("div",{children:[(0,t.jsx)(eI,{type:"secondary",style:{fontSize:11},children:e}),(0,t.jsx)("div",{style:{fontSize:13,color:"#262626"},children:String(s)})]})}function eH({request:e,response:s,metrics:a}){let l,r,i;if(s&&s.results&&Array.isArray(s.results)&&0!==s.results.length&&s.results.some(e=>"session.created"===e.type||"session.updated"===e.type||"response.done"===e.type))return(0,t.jsx)(eO,{response:s,metrics:a});let{requestMessages:n,responseMessage:o}=(l=[],e?.messages&&Array.isArray(e.messages)&&e.messages.forEach(e=>{let t;l.push({role:e.role||"user",content:"string"==typeof(t=e.content)?t:Array.isArray(t)?t.map(e=>"string"==typeof e?e:"text"===e.type?e.text:"image_url"===e.type?"[Image]":JSON.stringify(e)).join("\n"):JSON.stringify(t),toolCallId:e.tool_call_id})}),r=null,(i=s?.choices?.[0]?.message)&&(r={role:i.role||"assistant",content:i.content||"",toolCalls:(e=>{if(e&&Array.isArray(e))return e.map(e=>({id:e.id||"",name:e.function?.name||"unknown",arguments:ep(e.function?.arguments)}))})(i.tool_calls)}),{requestMessages:l,responseMessage:r});return(0,t.jsxs)("div",{children:[(0,t.jsx)(eT,{messages:n,promptTokens:a?.prompt_tokens,inputCost:a?.input_cost}),(0,t.jsx)(eM,{message:o,completionTokens:a?.completion_tokens,outputCost:a?.output_cost})]})}let{Text:e$}=g.Typography;function eY({logEntry:e,onOpenSettings:s,isLoadingDetails:a=!1,accessToken:l}){var r,i;let n=e.metadata||{},o="failure"===n.status,d=o?n.error_information:null,c=!!(r=e.messages)&&(Array.isArray(r)?r.length>0:"object"==typeof r&&Object.keys(r).length>0),m=!!(i=e.response)&&Object.keys(Z(i)).length>0,x=!c&&!m&&!o&&!a,u=n?.guardrail_information,p=ee(u),h=p.length>0,g=p.reduce((e,t)=>{let s=t?.masked_entity_count;return s?e+Object.values(s).reduce((e,t)=>"number"==typeof t?e+t:e,0):e},0),j=0===p.length?"-":1===p.length?p[0]?.guardrail_name??"-":`${p.length} guardrails`,b=n.vector_store_request_metadata&&Array.isArray(n.vector_store_request_metadata)&&n.vector_store_request_metadata.length>0;return(0,t.jsxs)("div",{style:{padding:`${I.DRAWER_CONTENT_PADDING} ${I.DRAWER_CONTENT_PADDING} 0`},children:[o&&d&&(0,t.jsx)(v.Alert,{type:"error",showIcon:!0,message:"Request Failed",description:(0,t.jsx)(eK,{errorInfo:d}),className:"mb-6"}),e.request_tags&&Object.keys(e.request_tags).length>0&&(0,t.jsx)(eV,{tags:e.request_tags}),(0,t.jsx)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6",children:(0,t.jsx)(y.Card,{title:"Request Details",size:"small",bordered:!1,style:{marginBottom:0},children:(0,t.jsxs)(f.Descriptions,{column:2,size:"small",children:[(0,t.jsx)(f.Descriptions.Item,{label:"Model",children:e.model}),(0,t.jsx)(f.Descriptions.Item,{label:"Provider",children:e.custom_llm_provider||"-"}),(0,t.jsx)(f.Descriptions.Item,{label:"Call Type",children:e.call_type}),(0,t.jsx)(f.Descriptions.Item,{label:"Model ID",children:(0,t.jsx)(z,{value:e.model_id})}),(0,t.jsx)(f.Descriptions.Item,{label:"API Base",children:(0,t.jsx)(z,{value:e.api_base,maxWidth:I.API_BASE_MAX_WIDTH})}),e.requester_ip_address&&(0,t.jsx)(f.Descriptions.Item,{label:"IP Address",children:e.requester_ip_address}),h&&(0,t.jsx)(f.Descriptions.Item,{label:"Guardrail",children:(0,t.jsx)(eW,{label:j,maskedCount:g})})]})})}),(0,t.jsx)(eU,{logEntry:e,metadata:n}),(0,t.jsx)(L.CostBreakdownViewer,{costBreakdown:n?.cost_breakdown,totalSpend:e.spend??0,promptTokens:e.prompt_tokens,completionTokens:e.completion_tokens,cacheHit:e.cache_hit}),(0,t.jsx)(eu,{log:e}),x&&(0,t.jsx)("div",{className:"mb-6",children:(0,t.jsx)(M.ConfigInfoMessage,{show:x,onOpenSettings:s})}),a?(0,t.jsxs)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6 p-8 text-center",children:[(0,t.jsx)(S.Spin,{size:"default"}),(0,t.jsx)("div",{style:{marginTop:8,color:"#999"},children:"Loading request & response data..."})]}):(0,t.jsx)(eG,{hasResponse:m,hasError:o,getRawRequest:()=>Z(e.proxy_server_request||e.messages),getFormattedResponse:()=>o&&d?{error:{message:d.error_message||"An error occurred",type:d.error_class||"error",code:d.error_code||"unknown",param:null}}:Z(e.response),logEntry:e}),h&&(0,t.jsx)("div",{id:"guardrail-section",children:(0,t.jsx)(T.default,{data:u,accessToken:l??null,logEntry:{request_id:e.request_id,user:e.user,model:e.model,startTime:e.startTime,metadata:e.metadata}})}),b&&(0,t.jsx)(A,{data:n.vector_store_request_metadata}),e.metadata&&Object.keys(e.metadata).length>0&&(0,t.jsx)(eQ,{metadata:e.metadata}),(0,t.jsx)("div",{style:{height:I.DRAWER_CONTENT_PADDING}})]})}function eK({errorInfo:e}){return(0,t.jsxs)("div",{children:[e.error_code&&(0,t.jsxs)("div",{children:[(0,t.jsx)(e$,{strong:!0,children:"Error Code:"})," ",e.error_code]}),e.error_message&&(0,t.jsxs)("div",{children:[(0,t.jsx)(e$,{strong:!0,children:"Message:"})," ",e.error_message]})]})}function eV({tags:e}){return(0,t.jsxs)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden p-4 mb-6",children:[(0,t.jsx)(e$,{strong:!0,style:{display:"block",marginBottom:8,fontSize:16},children:"Tags"}),(0,t.jsx)(w.Space,{size:I.SPACING_MEDIUM,wrap:!0,children:Object.entries(e).map(([e,s])=>(0,t.jsxs)(j.Tag,{children:[e,": ",String(s)]},e))})]})}function eW({label:e,maskedCount:s}){return(0,t.jsxs)(w.Space,{size:I.SPACING_MEDIUM,children:[(0,t.jsx)("a",{onClick:()=>{let e=document.getElementById("guardrail-section");e&&e.scrollIntoView({behavior:"smooth"})},style:{cursor:"pointer"},children:e}),s>0&&(0,t.jsxs)(j.Tag,{color:"blue",children:[s," masked"]})]})}function eU({logEntry:e,metadata:s}){let a=e.completionStartTime,l=a&&a!==e.endTime?new Date(a).getTime()-new Date(e.startTime).getTime():null,r=e.cache_hit||s?.additional_usage_values?.cache_read_input_tokens&&s.additional_usage_values.cache_read_input_tokens>0,i=String(e.cache_hit??"None"),n="true"===i.toLowerCase()?"green":"false"===i.toLowerCase()?"red":"default";return(0,t.jsx)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6",children:(0,t.jsx)(y.Card,{title:"Metrics",size:"small",style:{marginBottom:0},children:(0,t.jsxs)(f.Descriptions,{column:2,size:"small",children:[(0,t.jsx)(f.Descriptions.Item,{label:"Tokens",children:(0,t.jsx)(P,{prompt:e.prompt_tokens,completion:e.completion_tokens,total:e.total_tokens})}),(0,t.jsxs)(f.Descriptions.Item,{label:"Cost",children:["$",(0,C.formatNumberWithCommas)(e.spend||0,8)]}),(0,t.jsxs)(f.Descriptions.Item,{label:"Duration",children:[null!=e.request_duration_ms?(e.request_duration_ms/1e3).toFixed(3):"-"," s"]}),null!=l&&l>0&&(0,t.jsxs)(f.Descriptions.Item,{label:"Time to First Token",children:[(l/1e3).toFixed(3)," s"]}),r&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(f.Descriptions.Item,{label:"Cache Hit",children:(0,t.jsx)(j.Tag,{color:n,children:i})}),s?.additional_usage_values?.cache_read_input_tokens>0&&(0,t.jsx)(f.Descriptions.Item,{label:"Cache Read Tokens",children:(0,C.formatNumberWithCommas)(s.additional_usage_values.cache_read_input_tokens)}),s?.additional_usage_values?.cache_creation_input_tokens>0&&(0,t.jsx)(f.Descriptions.Item,{label:"Cache Creation Tokens",children:(0,C.formatNumberWithCommas)(s.additional_usage_values.cache_creation_input_tokens)})]}),s?.litellm_overhead_time_ms!==void 0&&null!==s.litellm_overhead_time_ms&&(0,t.jsxs)(f.Descriptions.Item,{label:"LiteLLM Overhead",children:[s.litellm_overhead_time_ms.toFixed(2)," ms"]}),(0,t.jsx)(f.Descriptions.Item,{label:"Retries",children:s?.attempted_retries!==void 0&&s?.attempted_retries!==null?s.attempted_retries>0?(0,t.jsxs)(t.Fragment,{children:[s.attempted_retries,void 0!==s.max_retries&&null!==s.max_retries?` / ${s.max_retries}`:""]}):(0,t.jsx)(j.Tag,{color:"green",children:"None"}):"-"}),(0,t.jsx)(f.Descriptions.Item,{label:"Start Time",children:(0,k.default)(e.startTime).format("YYYY-MM-DDTHH:mm:ss.SSS[Z]")}),(0,t.jsx)(f.Descriptions.Item,{label:"End Time",children:(0,k.default)(e.endTime).format("YYYY-MM-DDTHH:mm:ss.SSS[Z]")})]})})})}function eG({hasResponse:e,hasError:a,getRawRequest:l,getFormattedResponse:r,logEntry:i}){let[n,o]=(0,s.useState)(I.TAB_REQUEST),[d,c]=(0,s.useState)("pretty"),m=i.spend??0,x=i.prompt_tokens||0,u=i.completion_tokens||0,p=x+u,h=i.metadata?.cost_breakdown,g=h?.input_cost!==void 0&&h?.output_cost!==void 0,f=g?h.input_cost??0:p>0?m*x/p:0,y=g?h.output_cost??0:p>0?m*u/p:0;return(0,t.jsx)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6",children:(0,t.jsx)(_.Collapse,{defaultActiveKey:["1"],expandIconPosition:"start",items:[{key:"1",label:(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%"},onClick:e=>{e.target.closest(".ant-radio-group")&&e.stopPropagation()},children:[(0,t.jsx)("h3",{className:"text-lg font-medium text-gray-900",style:{margin:0},children:"Request & Response"}),(0,t.jsxs)(N.Radio.Group,{size:"small",value:d,onChange:e=>c(e.target.value),children:[(0,t.jsx)(N.Radio.Button,{value:"pretty",children:"Pretty"}),(0,t.jsx)(N.Radio.Button,{value:"json",children:"JSON"})]})]}),children:(0,t.jsx)("div",{children:"pretty"===d?(0,t.jsx)(eH,{request:l(),response:r(),metrics:{prompt_tokens:x,completion_tokens:u,input_cost:f,output_cost:y}}):(0,t.jsx)(b.Tabs,{activeKey:n,onChange:e=>o(e),tabBarExtraContent:(0,t.jsx)(e$,{copyable:{text:JSON.stringify(n===I.TAB_REQUEST?l():r(),null,2),tooltips:["Copy JSON","Copied!"]},disabled:n===I.TAB_RESPONSE&&!e&&!a}),items:[{key:I.TAB_REQUEST,label:"Request",children:(0,t.jsx)("div",{style:{paddingTop:I.SPACING_XLARGE,paddingBottom:I.SPACING_XLARGE},children:(0,t.jsx)(X,{data:l(),mode:"formatted"})})},{key:I.TAB_RESPONSE,label:"Response",children:(0,t.jsx)("div",{style:{paddingTop:I.SPACING_XLARGE,paddingBottom:I.SPACING_XLARGE},children:e||a?(0,t.jsx)(X,{data:r(),mode:"formatted"}):(0,t.jsx)("div",{style:{textAlign:"center",padding:20,color:"#999",fontStyle:"italic"},children:"Response data not available"})})}]})})}]})})}function eJ({guardrailEntries:e}){let s=e.every(e=>{let t=e?.guardrail_status||e?.status;return"pass"===t||"passed"===t||"success"===t});return(0,t.jsx)("div",{style:{textAlign:"left",marginBottom:12},children:(0,t.jsxs)("div",{onClick:()=>{let e=document.getElementById("guardrail-section");e&&e.scrollIntoView({behavior:"smooth"})},style:{display:"inline-flex",alignItems:"center",gap:6,padding:"4px 12px",borderRadius:16,cursor:"pointer",fontSize:13,fontWeight:500,backgroundColor:s?"#f0fdf4":"#fef2f2",color:s?"#15803d":"#b91c1c",border:`1px solid ${s?"#bbf7d0":"#fecaca"}`},children:[s?"✓":"✗"," ",e.length," guardrail",1!==e.length?"s":""," evaluated",(0,t.jsx)("span",{style:{fontSize:11,opacity:.7},children:"↓"})]})})}function eQ({metadata:e}){return(0,t.jsx)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6",children:(0,t.jsx)(_.Collapse,{defaultActiveKey:["1"],expandIconPosition:"start",items:[{key:"1",label:(0,t.jsx)("h3",{className:"text-lg font-medium text-gray-900",children:"Metadata"}),children:(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{style:{display:"flex",justifyContent:"flex-end",marginBottom:8},children:(0,t.jsx)(e$,{copyable:{text:JSON.stringify(e,null,2),tooltips:["Copy Metadata","Copied!"]}})}),(0,t.jsx)("pre",{style:{maxHeight:I.METADATA_MAX_HEIGHT,overflowY:"auto",fontSize:I.FONT_SIZE_SMALL,fontFamily:I.FONT_FAMILY_MONO,whiteSpace:"pre-wrap",wordBreak:"break-all",margin:0},children:JSON.stringify(e,null,2)})]})}]})})}var eX=e.i(764205),eZ=e.i(266027),e0=e.i(135214);function e1({row:e,isSelected:s,onClick:a}){let l=x.MCP_CALL_TYPES.includes(e.call_type),r=x.AGENT_CALL_TYPES.includes(e.call_type),i=null!=e.request_duration_ms?(e.request_duration_ms/1e3).toFixed(3):e.startTime&&e.endTime?((Date.parse(e.endTime)-Date.parse(e.startTime))/1e3).toFixed(3):"-";return(0,t.jsxs)("button",{type:"button",className:`w-full text-left pl-8 pr-2 py-1 transition-colors ${s?"bg-blue-50":"hover:bg-slate-100"}`,onClick:a,children:[(0,t.jsxs)("div",{className:"flex items-center gap-1",children:[l?(0,t.jsx)(m.Wrench,{size:12,className:"text-slate-500 flex-shrink-0"}):r?(0,t.jsx)(d.Bot,{size:12,className:"text-slate-500 flex-shrink-0"}):(0,t.jsx)(c.Sparkles,{size:12,className:"text-slate-500 flex-shrink-0"}),(0,t.jsx)("span",{className:"text-xs font-medium text-slate-900 truncate",children:(0,u.getEventDisplayName)(e.call_type,e.model)})]}),(0,t.jsxs)("div",{className:"text-[10px] text-slate-500 mt-0 flex items-center gap-1.5 font-mono",children:[(0,t.jsxs)("span",{children:[i,"s"]}),e.spend?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("span",{children:"·"}),(0,t.jsx)("span",{children:(0,C.getSpendString)(e.spend)})]}):null,e.total_tokens?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("span",{children:"·"}),(0,t.jsxs)("span",{children:[e.total_tokens," tok"]})]}):null]})]})}function e2({open:e,onClose:d,logEntry:c,sessionId:m,accessToken:u,onOpenSettings:g,allLogs:f=[],onSelectLog:y,startTime:j}){let b=!!m,[v,_]=(0,s.useState)(null),[N,w]=(0,s.useState)(!1),[S,k]=(0,s.useState)(!1),{data:T=[]}=(0,eZ.useQuery)({queryKey:["sessionLogs",m],queryFn:async()=>{if(!m||!u)return[];let e=await (0,eX.sessionSpendLogsCall)(u,m);return(e.data||e||[]).map(e=>({...e,request_duration_ms:e.request_duration_ms??Date.parse(e.endTime)-Date.parse(e.startTime)})).sort((e,t)=>{let s=+!!x.MCP_CALL_TYPES.includes(e.call_type),a=+!!x.MCP_CALL_TYPES.includes(t.call_type);return s!==a?s-a:new Date(e.startTime).getTime()-new Date(t.startTime).getTime()})},enabled:!!(e&&b&&m&&u)}),L=(0,s.useMemo)(()=>b?T.length?v?T.find(e=>e.request_id===v)||T[0]:c?.request_id&&T.find(e=>e.request_id===c.request_id)||T[0]:null:c,[b,c,v,T]);(0,s.useEffect)(()=>{b&&T.length&&(v&&T.some(e=>e.request_id===v)||_(c?.request_id&&T.some(e=>e.request_id===c.request_id)?c.request_id:T[0].request_id))},[b,c,v,T]),(0,s.useEffect)(()=>{e?w(!1):(b&&_(null),k(!1))},[e,b]);let{selectNextLog:M,selectPreviousLog:E}=(0,h.useKeyboardNavigation)({isOpen:e,currentLog:L,allLogs:b?T:f,onClose:d,onSelectLog:e=>{b&&_(e.request_id),y?.(e)}}),A=((e,t,s)=>{let{accessToken:a}=(0,e0.default)();return(0,eZ.useQuery)({queryKey:["logDetails",e,t,a],queryFn:async()=>a&&e&&t?await (0,eX.uiSpendLogDetailsCall)(a,e,t):null,enabled:s&&!!a&&!!e&&!!t,staleTime:6e5,gcTime:6e5})})(L?.request_id,j,e&&!!L?.request_id),D=A.data,O=A.isLoading,z=(0,s.useMemo)(()=>L?{...L,messages:D?.messages||L.messages,response:D?.response||L.response,proxy_server_request:D?.proxy_server_request||L.proxy_server_request}:null,[L,D]),R=L?.metadata||{},P="failure"===R.status?"Failure":"Success",B="failure"===R.status?"error":"success",F=R?.user_api_key_team_alias||"default",q=T.reduce((e,t)=>e+(t.spend||0),0),H=T.length>0?new Date(Math.min(...T.map(e=>new Date(e.startTime).getTime()))):null,$=T.length>0?new Date(Math.max(...T.map(e=>new Date(e.endTime).getTime()))):null,Y=H&&$?(($.getTime()-H.getTime())/1e3).toFixed(2):"0.00",K=T.filter(e=>!x.MCP_CALL_TYPES.includes(e.call_type)&&!x.AGENT_CALL_TYPES.includes(e.call_type)).length,V=T.filter(e=>x.AGENT_CALL_TYPES.includes(e.call_type)).length,W=T.filter(e=>x.MCP_CALL_TYPES.includes(e.call_type)).length,U=b?T:L?[L]:[],G=b?m||"":L?.request_id||"",J=G.length>14?`${G.slice(0,11)}...`:G,Q=async()=>{if(G)try{await navigator.clipboard.writeText(G),k(!0),setTimeout(()=>k(!1),1200)}catch{}};return L&&z?(0,t.jsx)(l.Drawer,{title:null,placement:"right",onClose:d,open:e,width:I.DRAWER_WIDTH,closable:!1,mask:!0,maskClosable:!0,styles:{body:{padding:0,overflow:"hidden"},header:{display:"none"}},children:(0,t.jsxs)("div",{style:{height:"100%"},className:"flex relative",children:[N?(0,t.jsx)(a.Button,{type:"text",size:"small",icon:(0,t.jsx)(o.RightOutlined,{}),onClick:()=>w(!1),className:"absolute top-2 left-2 z-20 !bg-white !border !border-slate-200 !rounded-md","aria-label":"Expand trace sidebar"}):(0,t.jsx)(a.Button,{type:"text",size:"small",icon:(0,t.jsx)(n.LeftOutlined,{}),onClick:()=>w(!0),className:"absolute top-2 left-2 z-20 !bg-white !border !border-slate-200 !rounded-md","aria-label":"Collapse trace sidebar"}),!N&&(0,t.jsxs)("div",{className:"border-r border-slate-200 bg-slate-50 flex flex-col",style:{width:224},children:[(0,t.jsxs)("div",{className:"pl-12 pr-3 py-2 border-b border-slate-200 bg-white",children:[(0,t.jsx)("div",{className:"flex items-start justify-between gap-2",children:(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{className:"text-[10px] uppercase tracking-wide text-slate-500",children:b?"Session":"Trace"}),(0,t.jsxs)("div",{className:"font-mono text-[12px] text-slate-900 leading-tight flex items-center gap-1",children:[(0,t.jsx)("span",{className:"truncate",children:J}),(0,t.jsx)("button",{type:"button",onClick:Q,className:"text-slate-400 hover:text-slate-600","aria-label":"Copy trace id",children:S?(0,t.jsx)(r.CheckOutlined,{className:"text-[11px]"}):(0,t.jsx)(i.CopyOutlined,{className:"text-[11px]"})})]})]})}),(0,t.jsxs)("div",{className:"mt-1 text-[11px] text-slate-500 font-mono",children:[U.length," req",[b?K:U.filter(e=>!x.MCP_CALL_TYPES.includes(e.call_type)&&!x.AGENT_CALL_TYPES.includes(e.call_type)).length,b?V:U.filter(e=>x.AGENT_CALL_TYPES.includes(e.call_type)).length,b?W:U.filter(e=>x.MCP_CALL_TYPES.includes(e.call_type)).length].map((e,s)=>{let a=[" LLM"," Agent"," MCP"][s];return e>0?(0,t.jsxs)("span",{children:[(0,t.jsx)("span",{className:"mx-1.5",children:"·"}),e,a]},a):null}),(0,t.jsx)("span",{className:"mx-1.5",children:"·"}),b?(0,C.getSpendString)(q):(0,C.getSpendString)(L.spend||0),b&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("span",{className:"mx-1.5",children:"·"}),Y,"s"]})]})]}),(0,t.jsxs)("div",{className:"flex-1 overflow-y-auto",children:[ee(R?.guardrail_information).length>0&&(0,t.jsx)("div",{className:"px-3 pt-2",children:(0,t.jsx)(eJ,{guardrailEntries:ee(R?.guardrail_information)})}),b?(0,t.jsx)("div",{className:"py-1",children:(0,t.jsxs)("div",{className:"relative pl-2",children:[(0,t.jsx)("div",{className:"absolute left-4 top-1 bottom-1 border-l border-slate-300"}),U.map((e,s)=>{let a=s===U.length-1;return(0,t.jsxs)("div",{className:"relative",children:[(0,t.jsx)("div",{className:"absolute left-4 top-3 w-3 border-t border-slate-300"}),a&&(0,t.jsx)("div",{className:"absolute left-4 top-3 bottom-0 w-px bg-slate-50"}),(0,t.jsx)(e1,{row:e,isSelected:e.request_id===L.request_id,onClick:()=>{_(e.request_id),y?.(e)}})]},e.request_id)})]})}):(0,t.jsx)("div",{className:"py-1",children:U.map(e=>(0,t.jsx)(e1,{row:e,isSelected:e.request_id===L.request_id,onClick:()=>y?.(e)},e.request_id))})]})]}),(0,t.jsxs)("div",{className:"flex-1 flex flex-col overflow-hidden",children:[(0,t.jsx)(p.DrawerHeader,{log:L,onClose:d,onPrevious:E,onNext:M,statusLabel:P,statusColor:B,environment:F}),(0,t.jsx)("div",{className:"flex-1 overflow-y-auto",children:(0,t.jsx)(eY,{logEntry:z,onOpenSettings:g,isLoadingDetails:O,accessToken:u??null})})]})]})}):null}e.s(["LogDetailsDrawer",()=>e2],502626),e.s([],3565)},936190,e=>{"use strict";var t=e.i(843476),s=e.i(619273),a=e.i(266027),l=e.i(912598),r=e.i(166540),i=e.i(271645);e.i(517442),e.i(500330),e.i(122550);var n=e.i(313603),o=e.i(772345),d=e.i(793130),c=e.i(197647),m=e.i(653824),x=e.i(881073),u=e.i(404206),p=e.i(723731),h=e.i(464571),g=e.i(708347),f=e.i(93648),y=e.i(245767),j=e.i(50882),b=e.i(291950),v=e.i(969550),_=e.i(764205),N=e.i(20147),w=e.i(942161),S=e.i(245099);e.i(70969);var k=e.i(97859);e.i(70635),e.i(339086);var C=e.i(504809);e.i(3565);var T=e.i(502626),L=e.i(727749);e.i(867612);var M=e.i(153472),E=e.i(954616),A=e.i(135214);let D=async(e,t)=>{let s=(0,_.getProxyBaseUrl)(),a=s?`${s}/config/update`:"/config/update",l=await fetch(a,{method:"POST",headers:{[(0,_.getGlobalLitellmHeaderName)()]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({general_settings:{store_prompts_in_spend_logs:t.store_prompts_in_spend_logs,...t.maximum_spend_logs_retention_period&&{maximum_spend_logs_retention_period:t.maximum_spend_logs_retention_period}}})});if(!l.ok){let e=await l.json().catch(()=>({}));throw Error(e?.error?.message||e?.message||e?.detail||"Failed to update spend logs settings")}return await l.json()};var I=e.i(190702),O=e.i(637235),z=e.i(808613),R=e.i(311451),P=e.i(212931),B=e.i(981339),F=e.i(770914),q=e.i(790848),H=e.i(898586);let $=({isVisible:e,onCancel:s,onSuccess:a})=>{let[l]=z.Form.useForm(),{mutateAsync:r,isPending:n}=(()=>{let{accessToken:e}=(0,A.default)();return(0,E.useMutation)({mutationFn:async t=>{if(!e)throw Error("Access token is required");return await D(e,t)}})})(),{mutateAsync:o,isPending:d}=(0,M.useDeleteProxyConfigField)(),{data:c,isLoading:m,refetch:x}=(0,M.useProxyConfig)(M.ConfigType.GENERAL_SETTINGS),u=z.Form.useWatch("store_prompts_in_spend_logs",l);(0,i.useEffect)(()=>{e&&x()},[e,x]);let p=(0,i.useMemo)(()=>{if(!c)return{store_prompts_in_spend_logs:!1,maximum_spend_logs_retention_period:void 0};let e=c.find(e=>"store_prompts_in_spend_logs"===e.field_name),t=c.find(e=>"maximum_spend_logs_retention_period"===e.field_name);return{store_prompts_in_spend_logs:e?.field_value??!1,maximum_spend_logs_retention_period:t?.field_value??void 0}},[c]),g=async e=>{try{let t=e.maximum_spend_logs_retention_period;if(!t||"string"==typeof t&&""===t.trim())try{await o({config_type:M.ConfigType.GENERAL_SETTINGS,field_name:M.GeneralSettingsFieldName.MAXIMUM_SPEND_LOGS_RETENTION_PERIOD})}catch(e){console.warn("Failed to delete retention period field (may not exist):",e)}let s={store_prompts_in_spend_logs:e.store_prompts_in_spend_logs,...t&&"string"==typeof t&&""!==t.trim()&&{maximum_spend_logs_retention_period:t}};await r(s,{onSuccess:()=>{L.default.success("Spend logs settings updated successfully"),x(),a?.()},onError:e=>{L.default.fromBackend("Failed to save spend logs settings: "+(0,I.parseErrorMessage)(e))}})}catch(e){L.default.fromBackend("Failed to save spend logs settings: "+(0,I.parseErrorMessage)(e))}},f=()=>{l.resetFields(),s()};return(0,t.jsx)(P.Modal,{title:(0,t.jsx)(H.Typography.Title,{level:5,children:"Spend Logs Settings"}),open:e,footer:(0,t.jsxs)(F.Space,{children:[(0,t.jsx)(h.Button,{onClick:f,disabled:n||d||m,children:"Cancel"}),(0,t.jsx)(h.Button,{type:"primary",loading:n||d,disabled:m,onClick:()=>l.submit(),children:n||d?"Saving...":"Save Settings"})]}),onCancel:f,children:(0,t.jsxs)(z.Form,{form:l,layout:"horizontal",onFinish:g,initialValues:p,children:[(0,t.jsx)(z.Form.Item,{label:"Store Prompts in Spend Logs",name:"store_prompts_in_spend_logs",tooltip:c?.find(e=>"store_prompts_in_spend_logs"===e.field_name)?.field_description||"When enabled, prompts will be stored in spend logs for tracking and analysis purposes.",valuePropName:"checked",children:(0,t.jsx)("div",{children:m?(0,t.jsx)(B.Skeleton.Input,{active:!0,block:!0}):(0,t.jsx)(q.Switch,{checked:u??!1,onChange:e=>l.setFieldValue("store_prompts_in_spend_logs",e)})})}),(0,t.jsx)(z.Form.Item,{label:"Maximum Spend Logs Retention Period (Optional)",name:"maximum_spend_logs_retention_period",tooltip:c?.find(e=>"maximum_spend_logs_retention_period"===e.field_name)?.field_description||"Set the maximum retention period for spend logs (e.g., '7d' for 7 days, '30d' for 30 days). Leave empty for no limit.",children:m?(0,t.jsx)(B.Skeleton.Input,{active:!0,block:!0}):(0,t.jsx)(R.Input,{placeholder:"e.g., 7d, 30d",prefix:(0,t.jsx)(O.ClockCircleOutlined,{})})})]},c?JSON.stringify(p):"loading")})};var Y=e.i(149121);function K({accessToken:e,token:L,userRole:M,userID:E,allTeams:A,premiumUser:D}){let[I,O]=(0,i.useState)(""),[z,R]=(0,i.useState)(!1),[P,B]=(0,i.useState)(!1),[F,q]=(0,i.useState)(1),[H]=(0,i.useState)(50),K=(0,i.useRef)(null),V=(0,i.useRef)(null),W=(0,i.useRef)(null),[U,G]=(0,i.useState)((0,r.default)().subtract(24,"hours").format("YYYY-MM-DDTHH:mm")),[J,Q]=(0,i.useState)((0,r.default)().format("YYYY-MM-DDTHH:mm")),[X,Z]=(0,i.useState)(!1),[ee,et]=(0,i.useState)(!1),[es,ea]=(0,i.useState)(""),[el,er]=(0,i.useState)(""),[ei,en]=(0,i.useState)(""),[eo,ed]=(0,i.useState)(""),[ec,em]=(0,i.useState)(""),[ex,eu]=(0,i.useState)(null),[ep,eh]=(0,i.useState)(null),[eg,ef]=(0,i.useState)(""),[ey,ej]=(0,i.useState)(""),[eb,ev]=(0,i.useState)(M&&g.internalUserRoles.includes(M)),[e_,eN]=(0,i.useState)("request logs"),[ew,eS]=(0,i.useState)(null),[ek,eC]=(0,i.useState)(!1),[eT,eL]=(0,i.useState)(null),[eM,eE]=(0,i.useState)(!1),[eA,eD]=(0,i.useState)("startTime"),[eI,eO]=(0,i.useState)("desc"),[ez,eR]=(0,i.useState)(!0);(0,l.useQueryClient)();let[eP,eB]=(0,i.useState)(()=>{let e=sessionStorage.getItem("isLiveTail");return null===e||JSON.parse(e)});(0,i.useEffect)(()=>{sessionStorage.setItem("isLiveTail",JSON.stringify(eP))},[eP]);let[eF,eq]=(0,i.useState)({value:24,unit:"hours"});(0,i.useEffect)(()=>{(async()=>{ep&&e&&eu({...(await (0,_.keyInfoV1Call)(e,ep)).info,token:ep,api_key:ep})})()},[ep,e]),(0,i.useEffect)(()=>{function e(e){K.current&&!K.current.contains(e.target)&&B(!1),V.current&&!V.current.contains(e.target)&&R(!1),W.current&&!W.current.contains(e.target)&&et(!1)}return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[]),(0,i.useEffect)(()=>{M&&g.internalUserRoles.includes(M)&&ev(!0)},[M]);let eH=(0,a.useQuery)({queryKey:["logs","table",F,H,U,J,ei,eo,eb?E:null,eg,ec,eA,eI],queryFn:async()=>{if(!e||!L||!M||!E)return{data:[],total:0,page:1,page_size:H,total_pages:0};let t=(0,r.default)(U).utc().format("YYYY-MM-DD HH:mm:ss"),s=X?(0,r.default)(J).utc().format("YYYY-MM-DD HH:mm:ss"):(0,r.default)().utc().format("YYYY-MM-DD HH:mm:ss");return await (0,_.uiSpendLogsCall)({accessToken:e,start_date:t,end_date:s,page:F,page_size:H,params:{api_key:eo||void 0,team_id:ei||void 0,user_id:eb?E??void 0:void 0,end_user:ey||void 0,status_filter:eg||void 0,model_id:ec||void 0,sort_by:eA,sort_order:eI}})},enabled:!!e&&!!L&&!!M&&!!E&&"request logs"===e_&&ez,refetchInterval:!!eP&&1===F&&15e3,placeholderData:s.keepPreviousData,refetchIntervalInBackground:!0}),e$=(0,i.useDeferredValue)(eH.isFetching),eY=eH.isFetching||e$,eK=eH.data||{data:[],total:0,page:1,page_size:H||10,total_pages:1},{filters:eV,filteredLogs:eW,hasBackendFilters:eU,allTeams:eG,handleFilterChange:eJ,handleFilterReset:eQ}=(0,C.useLogFilterLogic)({logs:eK,accessToken:e,startTime:U,endTime:J,pageSize:H,isCustomDate:X,setCurrentPage:q,userID:E,userRole:M,sortBy:eA,sortOrder:eI,currentPage:F}),eX=(0,i.useCallback)(()=>{eQ(),G((0,r.default)().subtract(24,"hours").format("YYYY-MM-DDTHH:mm")),Q((0,r.default)().format("YYYY-MM-DDTHH:mm")),Z(!1),eq({value:24,unit:"hours"}),q(1)},[eQ]);if((0,i.useEffect)(()=>{eR(!eU)},[eU]),(0,i.useEffect)(()=>{e&&(eV["Team ID"]?en(eV["Team ID"]):en(""),ef(eV.Status||""),em(eV.Model||""),ej(eV["End User"]||""),ed(eV["Key Hash"]||""))},[eV,e]),!e||!L||!M||!E)return null;let eZ=eW.data.filter(e=>!I||e.request_id.includes(I)||e.model.includes(I)||e.user&&e.user.includes(I)),e0=eZ.reduce((e,t)=>(t.session_id&&(e[t.session_id]||(e[t.session_id]={llm:0,agent:0,mcp:0}),k.MCP_CALL_TYPES.includes(t.call_type)?e[t.session_id].mcp+=1:k.AGENT_CALL_TYPES.includes(t.call_type)?e[t.session_id].agent+=1:e[t.session_id].llm+=1),e),{}),e1=new Map;for(let e of eZ){if(!e.session_id||1>=(e.session_total_count||1))continue;let t=k.MCP_CALL_TYPES.includes(e.call_type),s=e1.get(e.session_id);s&&(!s.isMcp||t)||e1.set(e.session_id,{requestId:e.request_id,isMcp:t})}let e2=eZ.map(e=>{let t=e.session_id?e0[e.session_id]:void 0;return{...e,request_duration_ms:e.request_duration_ms,session_llm_count:t?.llm??void 0,session_mcp_count:t?.mcp??void 0,session_agent_count:t?.agent??void 0,onKeyHashClick:e=>eh(e),onSessionClick:t=>{t&&(eL(t),eS(e),eC(!0))}}}).filter(e=>!e.session_id||1>=(e.session_total_count||1)||e1.get(e.session_id)?.requestId===e.request_id)||[],e5=[{name:"Team ID",label:"Team ID",isSearchable:!0,searchFn:async e=>A&&0!==A.length?A.filter(t=>t.team_id.toLowerCase().includes(e.toLowerCase())||t.team_alias&&t.team_alias.toLowerCase().includes(e.toLowerCase())).map(e=>({label:`${e.team_alias||e.team_id} (${e.team_id})`,value:e.team_id})):[]},{name:"Status",label:"Status",isSearchable:!1,options:[{label:"Success",value:"success"},{label:"Failure",value:"failure"}]},{name:"Model",label:"Model",customComponent:b.PaginatedModelSelect},{name:"Key Alias",label:"Key Alias",customComponent:j.PaginatedKeyAliasSelect},{name:"End User",label:"End User",isSearchable:!0,searchFn:async t=>{if(!e)return[];let s=await (0,_.allEndUsersCall)(e);return(s?.map(e=>e.user_id)||[]).filter(e=>e.toLowerCase().includes(t.toLowerCase())).map(e=>({label:e,value:e}))}},{name:"Error Code",label:"Error Code",isSearchable:!0,searchFn:async e=>{if(!e)return k.ERROR_CODE_OPTIONS;let t=e.toLowerCase(),s=k.ERROR_CODE_OPTIONS.filter(e=>e.label.toLowerCase().includes(t));return!k.ERROR_CODE_OPTIONS.some(t=>t.value===e.trim())&&e.trim()&&s.push({label:`Use custom code: ${e.trim()}`,value:e.trim()}),s}},{name:"Key Hash",label:"Key Hash",isSearchable:!1},{name:"Error Message",label:"Error Message",isSearchable:!1}],e4=k.QUICK_SELECT_OPTIONS.find(e=>e.value===eF.value&&e.unit===eF.unit),e6=X?((e,t,s)=>{if(e)return`${(0,r.default)(t).format("MMM D, h:mm A")} - ${(0,r.default)(s).format("MMM D, h:mm A")}`;let a=(0,r.default)(),l=(0,r.default)(t),i=a.diff(l,"minutes");if(i>=0&&i<2)return"Last 1 Minute";if(i>=2&&i<16)return"Last 15 Minutes";if(i>=16&&i<61)return"Last Hour";let n=a.diff(l,"hours");return n>=1&&n<5?"Last 4 Hours":n>=5&&n<25?"Last 24 Hours":n>=25&&n<169?"Last 7 Days":`${l.format("MMM D")} - ${a.format("MMM D")}`})(X,U,J):e4?.label;return(0,t.jsxs)("div",{className:"w-full max-w-screen p-6 overflow-x-hidden box-border",children:[(0,t.jsxs)(m.TabGroup,{defaultIndex:0,onIndexChange:e=>eN(0===e?"request logs":"audit logs"),children:[(0,t.jsxs)(x.TabList,{children:[(0,t.jsx)(c.Tab,{children:"Request Logs"}),(0,t.jsx)(c.Tab,{children:"Audit Logs"}),(0,t.jsx)(c.Tab,{children:"Deleted Keys"}),(0,t.jsx)(c.Tab,{children:"Deleted Teams"})]}),(0,t.jsxs)(p.TabPanels,{children:[(0,t.jsxs)(u.TabPanel,{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-4",children:[(0,t.jsx)("h1",{className:"text-xl font-semibold",children:"Request Logs"}),(0,t.jsx)(h.Button,{icon:(0,t.jsx)(n.SettingOutlined,{}),onClick:()=>eE(!0),title:"Spend Logs Settings"})]}),ex&&ep&&ex.api_key===ep?(0,t.jsx)(N.default,{keyId:ep,keyData:ex,teams:A,onClose:()=>eh(null),backButtonText:"Back to Logs"}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(v.default,{options:e5,onApplyFilters:eJ,onResetFilters:eX}),(0,t.jsx)($,{isVisible:eM,onCancel:()=>eE(!1),onSuccess:()=>eE(!1)}),(0,t.jsxs)("div",{className:"bg-white rounded-lg shadow w-full max-w-full box-border",children:[(0,t.jsx)("div",{className:"border-b px-6 py-4 w-full max-w-full box-border",children:(0,t.jsxs)("div",{className:"flex flex-col md:flex-row items-start md:items-center justify-between space-y-4 md:space-y-0 w-full max-w-full box-border",children:[(0,t.jsxs)("div",{className:"flex flex-wrap items-center gap-3 w-full max-w-full box-border",children:[(0,t.jsxs)("div",{className:"relative w-64 min-w-0 flex-shrink-0",children:[(0,t.jsx)("input",{type:"text",placeholder:"Search by Request ID",className:"w-full px-3 py-2 pl-8 border rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500",value:I,onChange:e=>O(e.target.value)}),(0,t.jsx)("svg",{className:"absolute left-2.5 top-2.5 h-4 w-4 text-gray-500",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"})})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2 min-w-0 flex-shrink",children:[(0,t.jsxs)("div",{className:"relative z-50",ref:W,children:[(0,t.jsxs)("button",{onClick:()=>et(!ee),className:"px-3 py-2 text-sm border rounded-md hover:bg-gray-50 flex items-center gap-2",children:[(0,t.jsx)("svg",{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"})}),e6]}),ee&&(0,t.jsx)("div",{className:"absolute right-0 mt-2 w-64 bg-white rounded-lg shadow-lg border p-2 z-50",children:(0,t.jsxs)("div",{className:"space-y-1",children:[k.QUICK_SELECT_OPTIONS.map(e=>(0,t.jsx)("button",{className:`w-full px-3 py-2 text-left text-sm hover:bg-gray-50 rounded-md ${e6===e.label?"bg-blue-50 text-blue-600":""}`,onClick:()=>{q(1),Q((0,r.default)().format("YYYY-MM-DDTHH:mm")),G((0,r.default)().subtract(e.value,e.unit).format("YYYY-MM-DDTHH:mm")),eq({value:e.value,unit:e.unit}),Z(!1),et(!1)},children:e.label},e.label)),(0,t.jsx)("div",{className:"border-t my-2"}),(0,t.jsx)("button",{className:`w-full px-3 py-2 text-left text-sm hover:bg-gray-50 rounded-md ${X?"bg-blue-50 text-blue-600":""}`,onClick:()=>Z(!X),children:"Custom Range"})]})})]}),(0,t.jsx)(()=>(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900",children:"Live Tail"}),(0,t.jsx)(d.Switch,{color:"green",checked:eP,defaultChecked:!0,onChange:eB})]}),{}),(0,t.jsx)(h.Button,{type:"default",icon:(0,t.jsx)(o.SyncOutlined,{spin:eY}),onClick:()=>{eH.refetch()},disabled:eY,title:"Fetch data",children:eY?"Fetching":"Fetch"})]}),X&&(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("div",{children:(0,t.jsx)("input",{type:"datetime-local",value:U,onChange:e=>{G(e.target.value),q(1)},className:"px-3 py-2 border rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"})}),(0,t.jsx)("span",{className:"text-gray-500",children:"to"}),(0,t.jsx)("div",{children:(0,t.jsx)("input",{type:"datetime-local",value:J,onChange:e=>{Q(e.target.value),q(1)},className:"px-3 py-2 border rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"})})]})]}),(0,t.jsxs)("div",{className:"flex items-center space-x-4",children:[(0,t.jsxs)("span",{className:"text-sm text-gray-700 whitespace-nowrap",children:["Showing ",eH.isLoading?"...":eW?(F-1)*H+1:0," -"," ",eH.isLoading?"...":eW?Math.min(F*H,eW.total):0," ","of ",eH.isLoading?"...":eW?eW.total:0," results"]}),(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,t.jsxs)("span",{className:"text-sm text-gray-700 min-w-[90px]",children:["Page ",eH.isLoading?"...":F," of"," ",eH.isLoading?"...":eW?eW.total_pages:1]}),(0,t.jsx)("button",{onClick:()=>q(e=>Math.max(1,e-1)),disabled:eH.isLoading||1===F,className:"px-3 py-1 text-sm border rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed",children:"Previous"}),(0,t.jsx)("button",{onClick:()=>q(e=>Math.min(eW.total_pages||1,e+1)),disabled:eH.isLoading||F===(eW.total_pages||1),className:"px-3 py-1 text-sm border rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed",children:"Next"})]})]})]})}),eP&&1===F&&ez&&(0,t.jsxs)("div",{className:"mb-4 px-4 py-2 bg-green-50 border border-greem-200 rounded-md flex items-center justify-between",children:[(0,t.jsx)("div",{className:"flex items-center gap-2",children:(0,t.jsx)("span",{className:"text-sm text-green-700",children:"Auto-refreshing every 15 seconds"})}),(0,t.jsx)("button",{onClick:()=>eB(!1),className:"text-sm text-green-600 hover:text-green-800",children:"Stop"})]}),(0,t.jsx)(Y.DataTable,{columns:(0,S.createColumns)({sortBy:eA,sortOrder:eI,onSortChange:(e,t)=>{eD(e),eO(t),q(1)}}),data:e2,onRowClick:e=>{if(e.session_id&&(e.session_total_count||1)>1){eL(e.session_id),eS(e),eC(!0);return}eL(null),eS(e),eC(!0)},isLoading:eH.isLoading})]})]})]}),(0,t.jsx)(u.TabPanel,{children:(0,t.jsx)(w.default,{userID:E,userRole:M,token:L,accessToken:e,isActive:"audit logs"===e_,premiumUser:D})}),(0,t.jsx)(u.TabPanel,{children:(0,t.jsx)(f.default,{})}),(0,t.jsx)(u.TabPanel,{children:(0,t.jsx)(y.default,{})})]})]}),(0,t.jsx)(T.LogDetailsDrawer,{open:ek,onClose:()=>{eC(!1),eL(null)},logEntry:ew,sessionId:eT,accessToken:e,onOpenSettings:()=>eE(!0),allLogs:e2,onSelectLog:e=>{eS(e)},startTime:(0,r.default)(U).utc().format("YYYY-MM-DD HH:mm:ss")})]})}e.i(331052),e.s(["default",()=>K],936190)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/92260915afd3dac5.js b/litellm/proxy/_experimental/out/_next/static/chunks/179425128d293da9.js similarity index 93% rename from litellm/proxy/_experimental/out/_next/static/chunks/92260915afd3dac5.js rename to litellm/proxy/_experimental/out/_next/static/chunks/179425128d293da9.js index a4ac20198b..2d9ba69123 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/92260915afd3dac5.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/179425128d293da9.js @@ -4,4 +4,4 @@ `]:{[`&:hover ${t}-inner`]:{borderColor:e.colorPrimary}},[`${l}:not(${l}-disabled)`]:{[`&:hover ${t}-checked:not(${t}-disabled) ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"},[`&:hover ${t}-checked:not(${t}-disabled):after`]:{borderColor:e.colorPrimaryHover}}},{[`${t}-checked`]:{[`${t}-inner`]:{backgroundColor:e.colorPrimary,borderColor:e.colorPrimary,"&:after":{opacity:1,transform:"rotate(45deg) scale(1) translate(-50%,-50%)",transition:`all ${e.motionDurationMid} ${e.motionEaseOutBack} ${e.motionDurationFast}`}}},[` ${l}-checked:not(${l}-disabled), ${t}-checked:not(${t}-disabled) - `]:{[`&:hover ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"}}},{[t]:{"&-indeterminate":{"&":{[`${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${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 ${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${e.colorPrimary}`}}}}},{[`${l}-disabled`]:{cursor:"not-allowed"},[`${t}-disabled`]:{[`&, ${t}-input`]:{cursor:"not-allowed",pointerEvents:"none"},[`${t}-inner`]:{background:e.colorBgContainerDisabled,borderColor:e.colorBorder,"&:after":{borderColor:e.colorTextDisabled}},"&:after":{display:"none"},"& + span":{color:e.colorTextDisabled},[`&${t}-indeterminate ${t}-inner::after`]:{background:e.colorTextDisabled}}}]})((0,o.mergeToken)(t,{checkboxCls:`.${e}`,checkboxSize:t.controlInteractiveSize}))}let s=(0,l.genStyleHooks)("Checkbox",(e,{prefixCls:t})=>[n(t,e)]);e.s(["default",0,s,"getStyle",()=>n],236836)},374276,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(91874),l=e.i(611935),o=e.i(121872),n=e.i(26905),s=e.i(242064),i=e.i(937328),c=e.i(321883),d=e.i(62139),u=e.i(421512),m=e.i(236836),g=e.i(681216),p=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let f=t.forwardRef((e,f)=>{var h;let{prefixCls:x,className:b,rootClassName:y,children:v,indeterminate:w=!1,style:k,onMouseEnter:C,onMouseLeave:j,skipGroup:N=!1,disabled:S}=e,$=p(e,["prefixCls","className","rootClassName","children","indeterminate","style","onMouseEnter","onMouseLeave","skipGroup","disabled"]),{getPrefixCls:M,direction:E,checkbox:O}=t.useContext(s.ConfigContext),T=t.useContext(u.default),{isFormItemInput:P}=t.useContext(d.FormItemInputContext),_=t.useContext(i.default),z=null!=(h=(null==T?void 0:T.disabled)||S)?h:_,R=t.useRef($.value),I=t.useRef(null),L=(0,l.composeRef)(f,I);t.useEffect(()=>{null==T||T.registerValue($.value)},[]),t.useEffect(()=>{if(!N)return $.value!==R.current&&(null==T||T.cancelValue(R.current),null==T||T.registerValue($.value),R.current=$.value),()=>null==T?void 0:T.cancelValue($.value)},[$.value]),t.useEffect(()=>{var e;(null==(e=I.current)?void 0:e.input)&&(I.current.input.indeterminate=w)},[w]);let D=M("checkbox",x),B=(0,c.default)(D),[F,A,q]=(0,m.default)(D,B),H=Object.assign({},$);T&&!N&&(H.onChange=(...e)=>{$.onChange&&$.onChange.apply($,e),T.toggleOption&&T.toggleOption({label:v,value:$.value})},H.name=T.name,H.checked=T.value.includes($.value));let G=(0,r.default)(`${D}-wrapper`,{[`${D}-rtl`]:"rtl"===E,[`${D}-wrapper-checked`]:H.checked,[`${D}-wrapper-disabled`]:z,[`${D}-wrapper-in-form-item`]:P},null==O?void 0:O.className,b,y,q,B,A),X=(0,r.default)({[`${D}-indeterminate`]:w},n.TARGET_CLS,A),[V,K]=(0,g.default)(H.onClick);return F(t.createElement(o.default,{component:"Checkbox",disabled:z},t.createElement("label",{className:G,style:Object.assign(Object.assign({},null==O?void 0:O.style),k),onMouseEnter:C,onMouseLeave:j,onClick:V},t.createElement(a.default,Object.assign({},H,{onClick:K,prefixCls:D,className:X,disabled:z,ref:L})),null!=v&&t.createElement("span",{className:`${D}-label`},v))))});var h=e.i(8211),x=e.i(529681),b=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let y=t.forwardRef((e,a)=>{let{defaultValue:l,children:o,options:n=[],prefixCls:i,className:d,rootClassName:g,style:p,onChange:y}=e,v=b(e,["defaultValue","children","options","prefixCls","className","rootClassName","style","onChange"]),{getPrefixCls:w,direction:k}=t.useContext(s.ConfigContext),[C,j]=t.useState(v.value||l||[]),[N,S]=t.useState([]);t.useEffect(()=>{"value"in v&&j(v.value||[])},[v.value]);let $=t.useMemo(()=>n.map(e=>"string"==typeof e||"number"==typeof e?{label:e,value:e}:e),[n]),M=e=>{S(t=>t.filter(t=>t!==e))},E=e=>{S(t=>[].concat((0,h.default)(t),[e]))},O=e=>{let t=C.indexOf(e.value),r=(0,h.default)(C);-1===t?r.push(e.value):r.splice(t,1),"value"in v||j(r),null==y||y(r.filter(e=>N.includes(e)).sort((e,t)=>$.findIndex(t=>t.value===e)-$.findIndex(e=>e.value===t)))},T=w("checkbox",i),P=`${T}-group`,_=(0,c.default)(T),[z,R,I]=(0,m.default)(T,_),L=(0,x.default)(v,["value","disabled"]),D=n.length?$.map(e=>t.createElement(f,{prefixCls:T,key:e.value.toString(),disabled:"disabled"in e?e.disabled:v.disabled,value:e.value,checked:C.includes(e.value),onChange:e.onChange,className:(0,r.default)(`${P}-item`,e.className),style:e.style,title:e.title,id:e.id,required:e.required},e.label)):o,B=t.useMemo(()=>({toggleOption:O,value:C,disabled:v.disabled,name:v.name,registerValue:E,cancelValue:M}),[O,C,v.disabled,v.name,E,M]),F=(0,r.default)(P,{[`${P}-rtl`]:"rtl"===k},d,g,I,_,R);return z(t.createElement("div",Object.assign({className:F,style:p},L,{ref:a}),t.createElement(u.default.Provider,{value:B},D)))});f.Group=y,f.__ANT_CHECKBOX=!0,e.s(["default",0,f],374276)},536916,e=>{"use strict";var t=e.i(374276);e.s(["Checkbox",()=>t.default])},292639,e=>{"use strict";var t=e.i(764205),r=e.i(266027);let a=(0,e.i(243652).createQueryKeys)("uiSettings");e.s(["useUISettings",0,()=>(0,r.useQuery)({queryKey:a.list({}),queryFn:async()=>await (0,t.getUiSettings)(),staleTime:36e5,gcTime:36e5})])},250980,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlusCircleIcon",0,r],250980)},502547,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 5l7 7-7 7"}))});e.s(["ChevronRightIcon",0,r],502547)},988297,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"}))});e.s(["PlusIcon",0,r],988297)},797672,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"}))});e.s(["PencilIcon",0,r],797672)},992619,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(779241),l=e.i(599724),o=e.i(199133),n=e.i(983561),s=e.i(689020);e.s(["default",0,({accessToken:e,value:i,placeholder:c="Select a Model",onChange:d,disabled:u=!1,style:m,className:g,showLabel:p=!0,labelText:f="Select Model"})=>{let[h,x]=(0,r.useState)(i),[b,y]=(0,r.useState)(!1),[v,w]=(0,r.useState)([]),k=(0,r.useRef)(null);return(0,r.useEffect)(()=>{x(i)},[i]),(0,r.useEffect)(()=>{e&&(async()=>{try{let t=await (0,s.fetchAvailableModels)(e);console.log("Fetched models for selector:",t),t.length>0&&w(t)}catch(e){console.error("Error fetching model info:",e)}})()},[e]),(0,t.jsxs)("div",{children:[p&&(0,t.jsxs)(l.Text,{className:"font-medium block mb-2 text-gray-700 flex items-center",children:[(0,t.jsx)(n.RobotOutlined,{className:"mr-2"})," ",f]}),(0,t.jsx)(o.Select,{value:h,placeholder:c,onChange:e=>{"custom"===e?(y(!0),x(void 0)):(y(!1),x(e),d&&d(e))},options:[...Array.from(new Set(v.map(e=>e.model_group))).map((e,t)=>({value:e,label:e,key:t})),{value:"custom",label:"Enter custom model",key:"custom"}],style:{width:"100%",...m},showSearch:!0,className:`rounded-md ${g||""}`,disabled:u}),b&&(0,t.jsx)(a.TextInput,{className:"mt-2",placeholder:"Enter custom model name",onValueChange:e=>{k.current&&clearTimeout(k.current),k.current=setTimeout(()=>{x(e),d&&d(e)},500)},disabled:u})]})}])},91739,e=>{"use strict";var t=e.i(544195);e.s(["Radio",()=>t.default])},409797,e=>{"use strict";var t=e.i(631171);e.s(["ChevronDownIcon",()=>t.default])},500727,696609,531516,e=>{"use strict";var t=e.i(266027),r=e.i(243652),a=e.i(764205),l=e.i(135214);let o=(0,r.createQueryKeys)("mcpServers");e.s(["useMCPServers",0,e=>{let{accessToken:r}=(0,l.default)();return(0,t.useQuery)({queryKey:o.list(e?{filters:{teamId:e}}:void 0),queryFn:async()=>await (0,a.fetchMCPServers)(r,e),enabled:!!r})}],500727);var n=e.i(843476),s=e.i(271645),i=e.i(536916),c=e.i(599724),d=e.i(409797),u=e.i(246349),u=u;let m=/\b(delete|remove|destroy|purge|drop|erase|unlink)\b/i,g=/\b(create|add|insert|new|post|submit|register|make|generate|write|upload)\b/i,p=/\b(update|edit|modify|change|patch|put|set|rename|move|transform)\b/i,f=/\b(get|read|list|fetch|search|find|query|retrieve|show|view|check|describe|info)\b/i;function h(e,t=""){let r=e.toLowerCase();if(f.test(r))return"read";if(m.test(r))return"delete";if(p.test(r))return"update";if(g.test(r))return"create";if(t){let e=t.toLowerCase();if(f.test(e))return"read";if(m.test(e))return"delete";if(p.test(e))return"update";if(g.test(e))return"create"}return"unknown"}function x(e){let t={read:[],create:[],update:[],delete:[],unknown:[]};for(let r of e)t[h(r.name,r.description)].push(r);return t}let b={read:{label:"Read",description:"Safe operations — fetch, list, search. No side effects.",risk:"low"},create:{label:"Create",description:"Add new resources — insert, upload, register.",risk:"medium"},update:{label:"Update",description:"Modify existing resources — edit, patch, rename.",risk:"medium"},delete:{label:"Delete",description:"Destructive operations — remove, purge, destroy.",risk:"high"},unknown:{label:"Other",description:"Operations that could not be automatically classified.",risk:"unknown"}};e.s(["CRUD_GROUP_META",0,b,"classifyToolOp",()=>h,"groupToolsByCrud",()=>x],696609);let y=["read","create","update","delete","unknown"],v={low:"bg-green-100 text-green-800",medium:"bg-yellow-100 text-yellow-800",high:"bg-red-100 text-red-800 font-semibold",unknown:"bg-gray-100 text-gray-700"},w={read:"border-green-200",create:"border-blue-200",update:"border-yellow-200",delete:"border-red-300",unknown:"border-gray-200"},k={read:"bg-green-50",create:"bg-blue-50",update:"bg-yellow-50",delete:"bg-red-50",unknown:"bg-gray-50"};e.s(["default",0,({tools:e,value:t,onChange:r,readOnly:a=!1,searchFilter:l=""})=>{let[o,m]=(0,s.useState)({read:!1,create:!1,update:!1,delete:!1,unknown:!0}),g=(0,s.useMemo)(()=>x(e),[e]),p=(0,s.useMemo)(()=>new Set(void 0===t?e.map(e=>e.name):t),[t,e]),f=e=>{if(a)return;let t=new Set(p);t.has(e)?t.delete(e):t.add(e),r(Array.from(t))};return 0===e.length?null:(0,n.jsx)("div",{className:"space-y-3",children:y.map(e=>{let t,s=g[e];if(0===s.length)return null;if(l){let e=l.toLowerCase();if(!s.some(t=>t.name.toLowerCase().includes(e)||(t.description??"").toLowerCase().includes(e)))return null}let h=b[e],x=(t=g[e]).length>0&&t.every(e=>p.has(e.name)),y=(e=>{let t=g[e];if(0===t.length)return!1;let r=t.filter(e=>p.has(e.name)).length;return r>0&&r{m(t=>({...t,[e]:!t[e]}))},children:[C?(0,n.jsx)(u.default,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}):(0,n.jsx)(d.ChevronDownIcon,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}),(0,n.jsx)("span",{className:"font-semibold text-gray-900 text-sm",children:h.label}),(0,n.jsx)("span",{className:`text-xs px-2 py-0.5 rounded-full ${v[h.risk]}`,children:"high"===h.risk?"High Risk":"medium"===h.risk?"Medium Risk":"low"===h.risk?"Safe":"Unclassified"}),(0,n.jsxs)("span",{className:"text-xs text-gray-500 ml-1",children:[s.filter(e=>p.has(e.name)).length,"/",s.length," allowed"]})]}),!a&&(0,n.jsxs)("div",{className:"flex items-center gap-2 ml-4",children:[(0,n.jsx)(c.Text,{className:"text-xs text-gray-500",children:x?"All on":y?"Partial":"All off"}),(0,n.jsx)(i.Checkbox,{checked:x,indeterminate:y,onChange:t=>((e,t)=>{if(a)return;let l=new Set(p);for(let r of g[e])t?l.add(r.name):l.delete(r.name);r(Array.from(l))})(e,t.target.checked),onClick:e=>e.stopPropagation()})]})]}),!C&&(0,n.jsx)("div",{className:"px-4 pt-2 pb-1 text-xs text-gray-500 bg-white border-b border-gray-100",children:h.description}),!C&&(0,n.jsx)("div",{className:"bg-white divide-y divide-gray-50",children:s.filter(e=>!l||e.name.toLowerCase().includes(l.toLowerCase())||(e.description??"").toLowerCase().includes(l.toLowerCase())).map(e=>{let t,r=(t=e.name,p.has(t));return(0,n.jsxs)("div",{className:`flex items-start gap-3 px-4 py-2.5 transition-colors hover:bg-gray-50 ${!a?"cursor-pointer":""} ${r?"":"opacity-60"}`,onClick:()=>f(e.name),children:[(0,n.jsx)(i.Checkbox,{checked:r,onChange:()=>f(e.name),disabled:a,onClick:e=>e.stopPropagation()}),(0,n.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,n.jsx)(c.Text,{className:"font-medium text-gray-900 text-sm",children:e.name}),e.description&&(0,n.jsx)(c.Text,{className:"text-xs text-gray-500 mt-0.5 leading-snug",children:e.description})]}),(0,n.jsx)("span",{className:`text-xs px-1.5 py-0.5 rounded flex-shrink-0 ${r?"bg-green-100 text-green-700":"bg-gray-100 text-gray-500"}`,children:r?"on":"off"})]},e.name)})})]},e)})})}],531516)},361653,e=>{"use strict";let t=(0,e.i(475254).default)("circle-alert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);e.s(["default",()=>t])},841947,e=>{"use strict";let t=(0,e.i(475254).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["default",()=>t])},603908,e=>{"use strict";let t=(0,e.i(475254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);e.s(["default",()=>t])},793130,e=>{"use strict";var t=e.i(290571),r=e.i(429427),a=e.i(371330),l=e.i(271645),o=e.i(394487),n=e.i(503269),s=e.i(214520),i=e.i(746725),c=e.i(914189),d=e.i(144279),u=e.i(294316),m=e.i(601893),g=e.i(140721),p=e.i(942803),f=e.i(233538),h=e.i(694421),x=e.i(700020),b=e.i(35889),y=e.i(998348),v=e.i(722678);let w=(0,l.createContext)(null);w.displayName="GroupContext";let k=l.Fragment,C=Object.assign((0,x.forwardRefWithAs)(function(e,t){var k;let C=(0,l.useId)(),j=(0,p.useProvidedId)(),N=(0,m.useDisabled)(),{id:S=j||`headlessui-switch-${C}`,disabled:$=N||!1,checked:M,defaultChecked:E,onChange:O,name:T,value:P,form:_,autoFocus:z=!1,...R}=e,I=(0,l.useContext)(w),[L,D]=(0,l.useState)(null),B=(0,l.useRef)(null),F=(0,u.useSyncRefs)(B,t,null===I?null:I.setSwitch,D),A=(0,s.useDefaultValue)(E),[q,H]=(0,n.useControllable)(M,O,null!=A&&A),G=(0,i.useDisposables)(),[X,V]=(0,l.useState)(!1),K=(0,c.useEvent)(()=>{V(!0),null==H||H(!q),G.nextFrame(()=>{V(!1)})}),W=(0,c.useEvent)(e=>{if((0,f.isDisabledReactIssue7711)(e.currentTarget))return e.preventDefault();e.preventDefault(),K()}),U=(0,c.useEvent)(e=>{e.key===y.Keys.Space?(e.preventDefault(),K()):e.key===y.Keys.Enter&&(0,h.attemptSubmit)(e.currentTarget)}),Y=(0,c.useEvent)(e=>e.preventDefault()),Q=(0,v.useLabelledBy)(),J=(0,b.useDescribedBy)(),{isFocusVisible:Z,focusProps:ee}=(0,r.useFocusRing)({autoFocus:z}),{isHovered:et,hoverProps:er}=(0,a.useHover)({isDisabled:$}),{pressed:ea,pressProps:el}=(0,o.useActivePress)({disabled:$}),eo=(0,l.useMemo)(()=>({checked:q,disabled:$,hover:et,focus:Z,active:ea,autofocus:z,changing:X}),[q,et,Z,ea,$,X,z]),en=(0,x.mergeProps)({id:S,ref:F,role:"switch",type:(0,d.useResolveButtonType)(e,L),tabIndex:-1===e.tabIndex?0:null!=(k=e.tabIndex)?k:0,"aria-checked":q,"aria-labelledby":Q,"aria-describedby":J,disabled:$||void 0,autoFocus:z,onClick:W,onKeyUp:U,onKeyPress:Y},ee,er,el),es=(0,l.useCallback)(()=>{if(void 0!==A)return null==H?void 0:H(A)},[H,A]),ei=(0,x.useRender)();return l.default.createElement(l.default.Fragment,null,null!=T&&l.default.createElement(g.FormFields,{disabled:$,data:{[T]:P||"on"},overrides:{type:"checkbox",checked:q},form:_,onReset:es}),ei({ourProps:en,theirProps:R,slot:eo,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var t;let[r,a]=(0,l.useState)(null),[o,n]=(0,v.useLabels)(),[s,i]=(0,b.useDescriptions)(),c=(0,l.useMemo)(()=>({switch:r,setSwitch:a}),[r,a]),d=(0,x.useRender)();return l.default.createElement(i,{name:"Switch.Description",value:s},l.default.createElement(n,{name:"Switch.Label",value:o,props:{htmlFor:null==(t=c.switch)?void 0:t.id,onClick(e){r&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),r.click(),r.focus({preventScroll:!0}))}}},l.default.createElement(w.Provider,{value:c},d({ourProps:{},theirProps:e,slot:{},defaultTag:k,name:"Switch.Group"}))))},Label:v.Label,Description:b.Description});var j=e.i(888288),N=e.i(95779),S=e.i(444755),$=e.i(673706),M=e.i(829087);let E=(0,$.makeClassName)("Switch"),O=l.default.forwardRef((e,r)=>{let{checked:a,defaultChecked:o=!1,onChange:n,color:s,name:i,error:c,errorMessage:d,disabled:u,required:m,tooltip:g,id:p}=e,f=(0,t.__rest)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),h={bgColor:s?(0,$.getColorClassNames)(s,N.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:s?(0,$.getColorClassNames)(s,N.colorPalette.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[x,b]=(0,j.default)(o,a),[y,v]=(0,l.useState)(!1),{tooltipProps:w,getReferenceProps:k}=(0,M.useTooltip)(300);return l.default.createElement("div",{className:"flex flex-row items-center justify-start"},l.default.createElement(M.default,Object.assign({text:g},w)),l.default.createElement("div",Object.assign({ref:(0,$.mergeRefs)([r,w.refs.setReference]),className:(0,S.tremorTwMerge)(E("root"),"flex flex-row relative h-5")},f,k),l.default.createElement("input",{type:"checkbox",className:(0,S.tremorTwMerge)(E("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:i,required:m,checked:x,onChange:e=>{e.preventDefault()}}),l.default.createElement(C,{checked:x,onChange:e=>{b(e),null==n||n(e)},disabled:u,className:(0,S.tremorTwMerge)(E("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:()=>v(!0),onBlur:()=>v(!1),id:p},l.default.createElement("span",{className:(0,S.tremorTwMerge)(E("sr-only"),"sr-only")},"Switch ",x?"on":"off"),l.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("background"),x?h.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.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("round"),x?(0,S.tremorTwMerge)(h.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",y?(0,S.tremorTwMerge)("ring-2",h.ringColor):"")}))),c&&d?l.default.createElement("p",{className:(0,S.tremorTwMerge)(E("errorMessage"),"text-sm text-red-500 mt-1 ")},d):null)});O.displayName="Switch",e.s(["Switch",()=>O],793130)},158392,419470,e=>{"use strict";var t=e.i(843476),r=e.i(779241);let a={ttl:3600,lowest_latency_buffer:0},l=({routingStrategyArgs:e})=>{let l={ttl:"Sliding window to look back over when calculating the average latency of a deployment. Default - 1 hour (in seconds).",lowest_latency_buffer:"Shuffle between deployments within this % of the lowest latency. Default - 0 (i.e. always pick lowest latency)."};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Latency-Based Configuration"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Fine-tune latency-based routing behavior"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e||a).map(([e,a])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:e.replace(/_/g," ")}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l[e]||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:"object"==typeof a?JSON.stringify(a,null,2):a?.toString(),className:"font-mono text-sm w-full"})]})},e))})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"})]})},o=({routerSettings:e,routerFieldsMetadata:a})=>(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Reliability & Retries"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure retry logic and failure handling"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e).filter(([e,t])=>"fallbacks"!=e&&"context_window_fallbacks"!=e&&"routing_strategy_args"!=e&&"routing_strategy"!=e&&"enable_tag_filtering"!=e).map(([e,l])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:a[e]?.ui_field_name||e}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:a[e]?.field_description||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:null==l||"null"===l?"":"object"==typeof l?JSON.stringify(l,null,2):l?.toString()||"",placeholder:"—",className:"font-mono text-sm w-full"})]})},e))})]});var n=e.i(199133);let s=({selectedStrategy:e,availableStrategies:r,routingStrategyDescriptions:a,routerFieldsMetadata:l,onStrategyChange:o})=>(0,t.jsxs)("div",{className:"space-y-2 max-w-3xl",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:l.routing_strategy?.ui_field_name||"Routing Strategy"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l.routing_strategy?.field_description||""})]}),(0,t.jsx)("div",{className:"routing-strategy-select max-w-3xl",children:(0,t.jsx)(n.Select,{value:e,onChange:o,style:{width:"100%"},size:"large",children:r.map(e=>(0,t.jsx)(n.Select.Option,{value:e,label:e,children:(0,t.jsxs)("div",{className:"flex flex-col gap-0.5 py-1",children:[(0,t.jsx)("span",{className:"font-mono text-sm font-medium",children:e}),a[e]&&(0,t.jsx)("span",{className:"text-xs text-gray-500 font-normal",children:a[e]})]})},e))})})]});var i=e.i(793130);let c=({enabled:e,routerFieldsMetadata:r,onToggle:a})=>(0,t.jsx)("div",{className:"space-y-3 max-w-3xl",children:(0,t.jsxs)("div",{className:"flex items-start justify-between",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:r.enable_tag_filtering?.ui_field_name||"Enable Tag Filtering"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500 mt-0.5",children:[r.enable_tag_filtering?.field_description||"",r.enable_tag_filtering?.link&&(0,t.jsxs)(t.Fragment,{children:[" ",(0,t.jsx)("a",{href:r.enable_tag_filtering.link,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline",children:"Learn more"})]})]})]}),(0,t.jsx)(i.Switch,{checked:e,onChange:a,className:"ml-4"})]})});e.s(["default",0,({value:e,onChange:r,routerFieldsMetadata:a,availableRoutingStrategies:n,routingStrategyDescriptions:i})=>(0,t.jsxs)("div",{className:"w-full space-y-8 py-2",children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Routing Settings"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure how requests are routed to deployments"})]}),n.length>0&&(0,t.jsx)(s,{selectedStrategy:e.selectedStrategy||e.routerSettings.routing_strategy||null,availableStrategies:n,routingStrategyDescriptions:i,routerFieldsMetadata:a,onStrategyChange:t=>{r({...e,selectedStrategy:t})}}),(0,t.jsx)(c,{enabled:e.enableTagFiltering,routerFieldsMetadata:a,onToggle:t=>{r({...e,enableTagFiltering:t})}})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),"latency-based-routing"===e.selectedStrategy&&(0,t.jsx)(l,{routingStrategyArgs:e.routerSettings.routing_strategy_args}),(0,t.jsx)(o,{routerSettings:e.routerSettings,routerFieldsMetadata:a})]})],158392);var d=e.i(994388),u=e.i(998573),m=e.i(653496),g=e.i(107233),p=e.i(271645),f=e.i(592968),h=e.i(361653),h=h;let x=(0,e.i(475254).default)("arrow-down",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var b=e.i(37727);function y({group:e,onChange:r,availableModels:a,maxFallbacks:l}){let o=a.filter(t=>t!==e.primaryModel),s=e.fallbackModels.length{let a=[...e.fallbackModels];a.includes(t)&&(a=a.filter(e=>e!==t)),r({...e,primaryModel:t,fallbackModels:a})},showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase()),options:a.map(e=>({label:e,value:e}))}),!e.primaryModel&&(0,t.jsxs)("div",{className:"mt-2 flex items-center gap-2 text-amber-600 text-xs bg-amber-50 p-2 rounded",children:[(0,t.jsx)(h.default,{className:"w-4 h-4"}),(0,t.jsx)("span",{children:"Select a model to begin configuring fallbacks"})]})]}),(0,t.jsx)("div",{className:"flex items-center justify-center -my-4 z-10",children:(0,t.jsxs)("div",{className:"bg-indigo-50 text-indigo-500 px-4 py-1 rounded-full text-xs font-bold border border-indigo-100 flex items-center gap-2 shadow-sm",children:[(0,t.jsx)(x,{className:"w-4 h-4"}),"IF FAILS, TRY..."]})}),(0,t.jsxs)("div",{className:`transition-opacity duration-300 ${!e.primaryModel?"opacity-50 pointer-events-none":"opacity-100"}`,children:[(0,t.jsxs)("label",{className:"block text-sm font-semibold text-gray-700 mb-2",children:["Fallback Chain ",(0,t.jsx)("span",{className:"text-red-500",children:"*"}),(0,t.jsxs)("span",{className:"text-xs text-gray-500 font-normal ml-2",children:["(Max ",l," fallbacks at a time)"]})]}),(0,t.jsxs)("div",{className:"bg-gray-50 rounded-xl p-4 border border-gray-200",children:[(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(n.Select,{mode:"multiple",className:"w-full",size:"large",placeholder:s?"Select fallback models to add...":`Maximum ${l} fallbacks reached`,value:e.fallbackModels,onChange:t=>{let a=t.slice(0,l);r({...e,fallbackModels:a})},disabled:!e.primaryModel,options:o.map(e=>({label:e,value:e})),optionRender:(r,a)=>{let l=e.fallbackModels.includes(r.value),o=l?e.fallbackModels.indexOf(r.value)+1:null;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[l&&null!==o&&(0,t.jsx)("span",{className:"flex items-center justify-center w-5 h-5 rounded bg-indigo-100 text-indigo-600 text-xs font-bold",children:o}),(0,t.jsx)("span",{children:r.label})]})},maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(f.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})}),showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase())}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1 ml-1",children:s?`Search and select multiple models. Selected models will appear below in order. (${e.fallbackModels.length}/${l} used)`:`Maximum ${l} fallbacks reached. Remove some to add more.`})]}),(0,t.jsx)("div",{className:"space-y-2 min-h-[100px]",children:0===e.fallbackModels.length?(0,t.jsxs)("div",{className:"h-32 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)("span",{className:"text-sm",children:"No fallback models selected"}),(0,t.jsx)("span",{className:"text-xs mt-1",children:"Add models from the dropdown above"})]}):e.fallbackModels.map((a,l)=>(0,t.jsxs)("div",{className:"group flex items-center justify-between p-3 bg-white rounded-lg border border-gray-200 hover:border-indigo-300 hover:shadow-sm transition-all",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex items-center justify-center w-6 h-6 rounded bg-gray-100 text-gray-400 group-hover:text-indigo-500 group-hover:bg-indigo-50",children:(0,t.jsx)("span",{className:"text-xs font-bold",children:l+1})}),(0,t.jsx)("div",{children:(0,t.jsx)("span",{className:"font-medium text-gray-800",children:a})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>{let t;return t=e.fallbackModels.filter((e,t)=>t!==l),void r({...e,fallbackModels:t})},className:"opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500 p-1",children:(0,t.jsx)(b.X,{className:"w-4 h-4"})})]},`${a}-${l}`))})]})]})]})}function v({groups:e,onGroupsChange:r,availableModels:a,maxFallbacks:l=10,maxGroups:o=5}){let[n,s]=(0,p.useState)(e.length>0?e[0].id:"1");(0,p.useEffect)(()=>{e.length>0?e.some(e=>e.id===n)||s(e[0].id):s("1")},[e]);let i=()=>{if(e.length>=o)return;let t=Date.now().toString();r([...e,{id:t,primaryModel:null,fallbackModels:[]}]),s(t)},c=t=>{r(e.map(e=>e.id===t.id?t:e))},f=e.map((r,o)=>{let n=r.primaryModel?r.primaryModel:`Group ${o+1}`;return{key:r.id,label:n,closable:e.length>1,children:(0,t.jsx)(y,{group:r,onChange:c,availableModels:a,maxFallbacks:l})}});return 0===e.length?(0,t.jsxs)("div",{className:"text-center py-12 bg-gray-50 rounded-lg border border-dashed border-gray-300",children:[(0,t.jsx)("p",{className:"text-gray-500 mb-4",children:"No fallback groups configured"}),(0,t.jsx)(d.Button,{variant:"primary",onClick:i,icon:()=>(0,t.jsx)(g.Plus,{className:"w-4 h-4"}),children:"Create First Group"})]}):(0,t.jsx)(m.Tabs,{type:"editable-card",activeKey:n,onChange:s,onEdit:(t,a)=>{"add"===a?i():"remove"===a&&e.length>1&&(t=>{if(1===e.length)return u.message.warning("At least one group is required");let a=e.filter(e=>e.id!==t);r(a),n===t&&a.length>0&&s(a[a.length-1].id)})(t)},items:f,className:"fallback-tabs",tabBarStyle:{marginBottom:0},hideAdd:e.length>=o})}e.s(["FallbackSelectionForm",()=>v],419470)}]); \ No newline at end of file + `]:{[`&:hover ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"}}},{[t]:{"&-indeterminate":{"&":{[`${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${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 ${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${e.colorPrimary}`}}}}},{[`${l}-disabled`]:{cursor:"not-allowed"},[`${t}-disabled`]:{[`&, ${t}-input`]:{cursor:"not-allowed",pointerEvents:"none"},[`${t}-inner`]:{background:e.colorBgContainerDisabled,borderColor:e.colorBorder,"&:after":{borderColor:e.colorTextDisabled}},"&:after":{display:"none"},"& + span":{color:e.colorTextDisabled},[`&${t}-indeterminate ${t}-inner::after`]:{background:e.colorTextDisabled}}}]})((0,o.mergeToken)(t,{checkboxCls:`.${e}`,checkboxSize:t.controlInteractiveSize}))}let s=(0,l.genStyleHooks)("Checkbox",(e,{prefixCls:t})=>[n(t,e)]);e.s(["default",0,s,"getStyle",()=>n],236836)},374276,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(91874),l=e.i(611935),o=e.i(121872),n=e.i(26905),s=e.i(242064),i=e.i(937328),c=e.i(321883),d=e.i(62139),u=e.i(421512),m=e.i(236836),g=e.i(681216),p=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let f=t.forwardRef((e,f)=>{var h;let{prefixCls:x,className:b,rootClassName:y,children:v,indeterminate:w=!1,style:k,onMouseEnter:C,onMouseLeave:j,skipGroup:N=!1,disabled:S}=e,$=p(e,["prefixCls","className","rootClassName","children","indeterminate","style","onMouseEnter","onMouseLeave","skipGroup","disabled"]),{getPrefixCls:M,direction:E,checkbox:O}=t.useContext(s.ConfigContext),T=t.useContext(u.default),{isFormItemInput:P}=t.useContext(d.FormItemInputContext),_=t.useContext(i.default),z=null!=(h=(null==T?void 0:T.disabled)||S)?h:_,R=t.useRef($.value),I=t.useRef(null),L=(0,l.composeRef)(f,I);t.useEffect(()=>{null==T||T.registerValue($.value)},[]),t.useEffect(()=>{if(!N)return $.value!==R.current&&(null==T||T.cancelValue(R.current),null==T||T.registerValue($.value),R.current=$.value),()=>null==T?void 0:T.cancelValue($.value)},[$.value]),t.useEffect(()=>{var e;(null==(e=I.current)?void 0:e.input)&&(I.current.input.indeterminate=w)},[w]);let D=M("checkbox",x),B=(0,c.default)(D),[F,A,q]=(0,m.default)(D,B),H=Object.assign({},$);T&&!N&&(H.onChange=(...e)=>{$.onChange&&$.onChange.apply($,e),T.toggleOption&&T.toggleOption({label:v,value:$.value})},H.name=T.name,H.checked=T.value.includes($.value));let G=(0,r.default)(`${D}-wrapper`,{[`${D}-rtl`]:"rtl"===E,[`${D}-wrapper-checked`]:H.checked,[`${D}-wrapper-disabled`]:z,[`${D}-wrapper-in-form-item`]:P},null==O?void 0:O.className,b,y,q,B,A),X=(0,r.default)({[`${D}-indeterminate`]:w},n.TARGET_CLS,A),[V,K]=(0,g.default)(H.onClick);return F(t.createElement(o.default,{component:"Checkbox",disabled:z},t.createElement("label",{className:G,style:Object.assign(Object.assign({},null==O?void 0:O.style),k),onMouseEnter:C,onMouseLeave:j,onClick:V},t.createElement(a.default,Object.assign({},H,{onClick:K,prefixCls:D,className:X,disabled:z,ref:L})),null!=v&&t.createElement("span",{className:`${D}-label`},v))))});var h=e.i(8211),x=e.i(529681),b=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let y=t.forwardRef((e,a)=>{let{defaultValue:l,children:o,options:n=[],prefixCls:i,className:d,rootClassName:g,style:p,onChange:y}=e,v=b(e,["defaultValue","children","options","prefixCls","className","rootClassName","style","onChange"]),{getPrefixCls:w,direction:k}=t.useContext(s.ConfigContext),[C,j]=t.useState(v.value||l||[]),[N,S]=t.useState([]);t.useEffect(()=>{"value"in v&&j(v.value||[])},[v.value]);let $=t.useMemo(()=>n.map(e=>"string"==typeof e||"number"==typeof e?{label:e,value:e}:e),[n]),M=e=>{S(t=>t.filter(t=>t!==e))},E=e=>{S(t=>[].concat((0,h.default)(t),[e]))},O=e=>{let t=C.indexOf(e.value),r=(0,h.default)(C);-1===t?r.push(e.value):r.splice(t,1),"value"in v||j(r),null==y||y(r.filter(e=>N.includes(e)).sort((e,t)=>$.findIndex(t=>t.value===e)-$.findIndex(e=>e.value===t)))},T=w("checkbox",i),P=`${T}-group`,_=(0,c.default)(T),[z,R,I]=(0,m.default)(T,_),L=(0,x.default)(v,["value","disabled"]),D=n.length?$.map(e=>t.createElement(f,{prefixCls:T,key:e.value.toString(),disabled:"disabled"in e?e.disabled:v.disabled,value:e.value,checked:C.includes(e.value),onChange:e.onChange,className:(0,r.default)(`${P}-item`,e.className),style:e.style,title:e.title,id:e.id,required:e.required},e.label)):o,B=t.useMemo(()=>({toggleOption:O,value:C,disabled:v.disabled,name:v.name,registerValue:E,cancelValue:M}),[O,C,v.disabled,v.name,E,M]),F=(0,r.default)(P,{[`${P}-rtl`]:"rtl"===k},d,g,I,_,R);return z(t.createElement("div",Object.assign({className:F,style:p},L,{ref:a}),t.createElement(u.default.Provider,{value:B},D)))});f.Group=y,f.__ANT_CHECKBOX=!0,e.s(["default",0,f],374276)},536916,e=>{"use strict";var t=e.i(374276);e.s(["Checkbox",()=>t.default])},292639,e=>{"use strict";var t=e.i(764205),r=e.i(266027);let a=(0,e.i(243652).createQueryKeys)("uiSettings");e.s(["useUISettings",0,()=>(0,r.useQuery)({queryKey:a.list({}),queryFn:async()=>await (0,t.getUiSettings)(),staleTime:36e5,gcTime:36e5})])},250980,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlusCircleIcon",0,r],250980)},502547,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 5l7 7-7 7"}))});e.s(["ChevronRightIcon",0,r],502547)},988297,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"}))});e.s(["PlusIcon",0,r],988297)},797672,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"}))});e.s(["PencilIcon",0,r],797672)},992619,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(779241),l=e.i(599724),o=e.i(199133),n=e.i(983561),s=e.i(689020);e.s(["default",0,({accessToken:e,value:i,placeholder:c="Select a Model",onChange:d,disabled:u=!1,style:m,className:g,showLabel:p=!0,labelText:f="Select Model"})=>{let[h,x]=(0,r.useState)(i),[b,y]=(0,r.useState)(!1),[v,w]=(0,r.useState)([]),k=(0,r.useRef)(null);return(0,r.useEffect)(()=>{x(i)},[i]),(0,r.useEffect)(()=>{e&&(async()=>{try{let t=await (0,s.fetchAvailableModels)(e);console.log("Fetched models for selector:",t),t.length>0&&w(t)}catch(e){console.error("Error fetching model info:",e)}})()},[e]),(0,t.jsxs)("div",{children:[p&&(0,t.jsxs)(l.Text,{className:"font-medium block mb-2 text-gray-700 flex items-center",children:[(0,t.jsx)(n.RobotOutlined,{className:"mr-2"})," ",f]}),(0,t.jsx)(o.Select,{value:h,placeholder:c,onChange:e=>{"custom"===e?(y(!0),x(void 0)):(y(!1),x(e),d&&d(e))},options:[...Array.from(new Set(v.map(e=>e.model_group))).map((e,t)=>({value:e,label:e,key:t})),{value:"custom",label:"Enter custom model",key:"custom"}],style:{width:"100%",...m},showSearch:!0,className:`rounded-md ${g||""}`,disabled:u}),b&&(0,t.jsx)(a.TextInput,{className:"mt-2",placeholder:"Enter custom model name",onValueChange:e=>{k.current&&clearTimeout(k.current),k.current=setTimeout(()=>{x(e),d&&d(e)},500)},disabled:u})]})}])},91739,e=>{"use strict";var t=e.i(544195);e.s(["Radio",()=>t.default])},409797,e=>{"use strict";var t=e.i(631171);e.s(["ChevronDownIcon",()=>t.default])},500727,696609,531516,e=>{"use strict";var t=e.i(266027),r=e.i(243652),a=e.i(764205),l=e.i(135214);let o=(0,r.createQueryKeys)("mcpServers");e.s(["useMCPServers",0,e=>{let{accessToken:r}=(0,l.default)();return(0,t.useQuery)({queryKey:o.list(e?{filters:{teamId:e}}:void 0),queryFn:async()=>await (0,a.fetchMCPServers)(r,e),enabled:!!r})}],500727);var n=e.i(843476),s=e.i(271645),i=e.i(536916),c=e.i(599724),d=e.i(409797),u=e.i(246349),u=u;let m=/\b(delete|remove|destroy|purge|drop|erase|unlink)\b/i,g=/\b(create|add|insert|new|post|submit|register|make|generate|write|upload)\b/i,p=/\b(update|edit|modify|change|patch|put|set|rename|move|transform)\b/i,f=/\b(get|read|list|fetch|search|find|query|retrieve|show|view|check|describe|info)\b/i;function h(e,t=""){let r=e.toLowerCase();if(f.test(r))return"read";if(m.test(r))return"delete";if(p.test(r))return"update";if(g.test(r))return"create";if(t){let e=t.toLowerCase();if(f.test(e))return"read";if(m.test(e))return"delete";if(p.test(e))return"update";if(g.test(e))return"create"}return"unknown"}function x(e){let t={read:[],create:[],update:[],delete:[],unknown:[]};for(let r of e)t[h(r.name,r.description)].push(r);return t}let b={read:{label:"Read",description:"Safe operations — fetch, list, search. No side effects.",risk:"low"},create:{label:"Create",description:"Add new resources — insert, upload, register.",risk:"medium"},update:{label:"Update",description:"Modify existing resources — edit, patch, rename.",risk:"medium"},delete:{label:"Delete",description:"Destructive operations — remove, purge, destroy.",risk:"high"},unknown:{label:"Other",description:"Operations that could not be automatically classified.",risk:"unknown"}};e.s(["CRUD_GROUP_META",0,b,"classifyToolOp",()=>h,"groupToolsByCrud",()=>x],696609);let y=["read","create","update","delete","unknown"],v={low:"bg-green-100 text-green-800",medium:"bg-yellow-100 text-yellow-800",high:"bg-red-100 text-red-800 font-semibold",unknown:"bg-gray-100 text-gray-700"},w={read:"border-green-200",create:"border-blue-200",update:"border-yellow-200",delete:"border-red-300",unknown:"border-gray-200"},k={read:"bg-green-50",create:"bg-blue-50",update:"bg-yellow-50",delete:"bg-red-50",unknown:"bg-gray-50"};e.s(["default",0,({tools:e,value:t,onChange:r,readOnly:a=!1,searchFilter:l=""})=>{let[o,m]=(0,s.useState)({read:!1,create:!1,update:!1,delete:!1,unknown:!0}),g=(0,s.useMemo)(()=>x(e),[e]),p=(0,s.useMemo)(()=>new Set(void 0===t?e.map(e=>e.name):t),[t,e]),f=e=>{if(a)return;let t=new Set(p);t.has(e)?t.delete(e):t.add(e),r(Array.from(t))};return 0===e.length?null:(0,n.jsx)("div",{className:"space-y-3",children:y.map(e=>{let t,s=g[e];if(0===s.length)return null;if(l){let e=l.toLowerCase();if(!s.some(t=>t.name.toLowerCase().includes(e)||(t.description??"").toLowerCase().includes(e)))return null}let h=b[e],x=(t=g[e]).length>0&&t.every(e=>p.has(e.name)),y=(e=>{let t=g[e];if(0===t.length)return!1;let r=t.filter(e=>p.has(e.name)).length;return r>0&&r{m(t=>({...t,[e]:!t[e]}))},children:[C?(0,n.jsx)(u.default,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}):(0,n.jsx)(d.ChevronDownIcon,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}),(0,n.jsx)("span",{className:"font-semibold text-gray-900 text-sm",children:h.label}),(0,n.jsx)("span",{className:`text-xs px-2 py-0.5 rounded-full ${v[h.risk]}`,children:"high"===h.risk?"High Risk":"medium"===h.risk?"Medium Risk":"low"===h.risk?"Safe":"Unclassified"}),(0,n.jsxs)("span",{className:"text-xs text-gray-500 ml-1",children:[s.filter(e=>p.has(e.name)).length,"/",s.length," allowed"]})]}),!a&&(0,n.jsxs)("div",{className:"flex items-center gap-2 ml-4",children:[(0,n.jsx)(c.Text,{className:"text-xs text-gray-500",children:x?"All on":y?"Partial":"All off"}),(0,n.jsx)(i.Checkbox,{checked:x,indeterminate:y,onChange:t=>((e,t)=>{if(a)return;let l=new Set(p);for(let r of g[e])t?l.add(r.name):l.delete(r.name);r(Array.from(l))})(e,t.target.checked),onClick:e=>e.stopPropagation()})]})]}),!C&&(0,n.jsx)("div",{className:"px-4 pt-2 pb-1 text-xs text-gray-500 bg-white border-b border-gray-100",children:h.description}),!C&&(0,n.jsx)("div",{className:"bg-white divide-y divide-gray-50",children:s.filter(e=>!l||e.name.toLowerCase().includes(l.toLowerCase())||(e.description??"").toLowerCase().includes(l.toLowerCase())).map(e=>{let t,r=(t=e.name,p.has(t));return(0,n.jsxs)("div",{className:`flex items-start gap-3 px-4 py-2.5 transition-colors hover:bg-gray-50 ${!a?"cursor-pointer":""} ${r?"":"opacity-60"}`,onClick:()=>f(e.name),children:[(0,n.jsx)(i.Checkbox,{checked:r,onChange:()=>f(e.name),disabled:a,onClick:e=>e.stopPropagation()}),(0,n.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,n.jsx)(c.Text,{className:"font-medium text-gray-900 text-sm",children:e.name}),e.description&&(0,n.jsx)(c.Text,{className:"text-xs text-gray-500 mt-0.5 leading-snug",children:e.description})]}),(0,n.jsx)("span",{className:`text-xs px-1.5 py-0.5 rounded flex-shrink-0 ${r?"bg-green-100 text-green-700":"bg-gray-100 text-gray-500"}`,children:r?"on":"off"})]},e.name)})})]},e)})})}],531516)},361653,e=>{"use strict";let t=(0,e.i(475254).default)("circle-alert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);e.s(["default",()=>t])},841947,e=>{"use strict";let t=(0,e.i(475254).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["default",()=>t])},603908,e=>{"use strict";let t=(0,e.i(475254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);e.s(["default",()=>t])},793130,e=>{"use strict";var t=e.i(290571),r=e.i(429427),a=e.i(371330),l=e.i(271645),o=e.i(394487),n=e.i(503269),s=e.i(214520),i=e.i(746725),c=e.i(914189),d=e.i(144279),u=e.i(294316),m=e.i(601893),g=e.i(140721),p=e.i(942803),f=e.i(233538),h=e.i(694421),x=e.i(700020),b=e.i(35889),y=e.i(998348),v=e.i(722678);let w=(0,l.createContext)(null);w.displayName="GroupContext";let k=l.Fragment,C=Object.assign((0,x.forwardRefWithAs)(function(e,t){var k;let C=(0,l.useId)(),j=(0,p.useProvidedId)(),N=(0,m.useDisabled)(),{id:S=j||`headlessui-switch-${C}`,disabled:$=N||!1,checked:M,defaultChecked:E,onChange:O,name:T,value:P,form:_,autoFocus:z=!1,...R}=e,I=(0,l.useContext)(w),[L,D]=(0,l.useState)(null),B=(0,l.useRef)(null),F=(0,u.useSyncRefs)(B,t,null===I?null:I.setSwitch,D),A=(0,s.useDefaultValue)(E),[q,H]=(0,n.useControllable)(M,O,null!=A&&A),G=(0,i.useDisposables)(),[X,V]=(0,l.useState)(!1),K=(0,c.useEvent)(()=>{V(!0),null==H||H(!q),G.nextFrame(()=>{V(!1)})}),W=(0,c.useEvent)(e=>{if((0,f.isDisabledReactIssue7711)(e.currentTarget))return e.preventDefault();e.preventDefault(),K()}),U=(0,c.useEvent)(e=>{e.key===y.Keys.Space?(e.preventDefault(),K()):e.key===y.Keys.Enter&&(0,h.attemptSubmit)(e.currentTarget)}),Y=(0,c.useEvent)(e=>e.preventDefault()),Q=(0,v.useLabelledBy)(),J=(0,b.useDescribedBy)(),{isFocusVisible:Z,focusProps:ee}=(0,r.useFocusRing)({autoFocus:z}),{isHovered:et,hoverProps:er}=(0,a.useHover)({isDisabled:$}),{pressed:ea,pressProps:el}=(0,o.useActivePress)({disabled:$}),eo=(0,l.useMemo)(()=>({checked:q,disabled:$,hover:et,focus:Z,active:ea,autofocus:z,changing:X}),[q,et,Z,ea,$,X,z]),en=(0,x.mergeProps)({id:S,ref:F,role:"switch",type:(0,d.useResolveButtonType)(e,L),tabIndex:-1===e.tabIndex?0:null!=(k=e.tabIndex)?k:0,"aria-checked":q,"aria-labelledby":Q,"aria-describedby":J,disabled:$||void 0,autoFocus:z,onClick:W,onKeyUp:U,onKeyPress:Y},ee,er,el),es=(0,l.useCallback)(()=>{if(void 0!==A)return null==H?void 0:H(A)},[H,A]),ei=(0,x.useRender)();return l.default.createElement(l.default.Fragment,null,null!=T&&l.default.createElement(g.FormFields,{disabled:$,data:{[T]:P||"on"},overrides:{type:"checkbox",checked:q},form:_,onReset:es}),ei({ourProps:en,theirProps:R,slot:eo,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var t;let[r,a]=(0,l.useState)(null),[o,n]=(0,v.useLabels)(),[s,i]=(0,b.useDescriptions)(),c=(0,l.useMemo)(()=>({switch:r,setSwitch:a}),[r,a]),d=(0,x.useRender)();return l.default.createElement(i,{name:"Switch.Description",value:s},l.default.createElement(n,{name:"Switch.Label",value:o,props:{htmlFor:null==(t=c.switch)?void 0:t.id,onClick(e){r&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),r.click(),r.focus({preventScroll:!0}))}}},l.default.createElement(w.Provider,{value:c},d({ourProps:{},theirProps:e,slot:{},defaultTag:k,name:"Switch.Group"}))))},Label:v.Label,Description:b.Description});var j=e.i(888288),N=e.i(95779),S=e.i(444755),$=e.i(673706),M=e.i(829087);let E=(0,$.makeClassName)("Switch"),O=l.default.forwardRef((e,r)=>{let{checked:a,defaultChecked:o=!1,onChange:n,color:s,name:i,error:c,errorMessage:d,disabled:u,required:m,tooltip:g,id:p}=e,f=(0,t.__rest)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),h={bgColor:s?(0,$.getColorClassNames)(s,N.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:s?(0,$.getColorClassNames)(s,N.colorPalette.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[x,b]=(0,j.default)(o,a),[y,v]=(0,l.useState)(!1),{tooltipProps:w,getReferenceProps:k}=(0,M.useTooltip)(300);return l.default.createElement("div",{className:"flex flex-row items-center justify-start"},l.default.createElement(M.default,Object.assign({text:g},w)),l.default.createElement("div",Object.assign({ref:(0,$.mergeRefs)([r,w.refs.setReference]),className:(0,S.tremorTwMerge)(E("root"),"flex flex-row relative h-5")},f,k),l.default.createElement("input",{type:"checkbox",className:(0,S.tremorTwMerge)(E("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:i,required:m,checked:x,onChange:e=>{e.preventDefault()}}),l.default.createElement(C,{checked:x,onChange:e=>{b(e),null==n||n(e)},disabled:u,className:(0,S.tremorTwMerge)(E("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:()=>v(!0),onBlur:()=>v(!1),id:p},l.default.createElement("span",{className:(0,S.tremorTwMerge)(E("sr-only"),"sr-only")},"Switch ",x?"on":"off"),l.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("background"),x?h.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.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("round"),x?(0,S.tremorTwMerge)(h.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",y?(0,S.tremorTwMerge)("ring-2",h.ringColor):"")}))),c&&d?l.default.createElement("p",{className:(0,S.tremorTwMerge)(E("errorMessage"),"text-sm text-red-500 mt-1 ")},d):null)});O.displayName="Switch",e.s(["Switch",()=>O],793130)},158392,419470,e=>{"use strict";var t=e.i(843476),r=e.i(779241);let a={ttl:3600,lowest_latency_buffer:0},l=({routingStrategyArgs:e})=>{let l={ttl:"Sliding window to look back over when calculating the average latency of a deployment. Default - 1 hour (in seconds).",lowest_latency_buffer:"Shuffle between deployments within this % of the lowest latency. Default - 0 (i.e. always pick lowest latency)."};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Latency-Based Configuration"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Fine-tune latency-based routing behavior"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e||a).map(([e,a])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:e.replace(/_/g," ")}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l[e]||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:"object"==typeof a?JSON.stringify(a,null,2):a?.toString(),className:"font-mono text-sm w-full"})]})},e))})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"})]})},o=({routerSettings:e,routerFieldsMetadata:a})=>(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Reliability & Retries"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure retry logic and failure handling"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e).filter(([e,t])=>"fallbacks"!=e&&"context_window_fallbacks"!=e&&"routing_strategy_args"!=e&&"routing_strategy"!=e&&"enable_tag_filtering"!=e).map(([e,l])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:a[e]?.ui_field_name||e}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:a[e]?.field_description||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:null==l||"null"===l?"":"object"==typeof l?JSON.stringify(l,null,2):l?.toString()||"",placeholder:"—",className:"font-mono text-sm w-full"})]})},e))})]});var n=e.i(199133);let s=({selectedStrategy:e,availableStrategies:r,routingStrategyDescriptions:a,routerFieldsMetadata:l,onStrategyChange:o})=>(0,t.jsxs)("div",{className:"space-y-2 max-w-3xl",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:l.routing_strategy?.ui_field_name||"Routing Strategy"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l.routing_strategy?.field_description||""})]}),(0,t.jsx)("div",{className:"routing-strategy-select max-w-3xl",children:(0,t.jsx)(n.Select,{value:e,onChange:o,style:{width:"100%"},size:"large",children:r.map(e=>(0,t.jsx)(n.Select.Option,{value:e,label:e,children:(0,t.jsxs)("div",{className:"flex flex-col gap-0.5 py-1",children:[(0,t.jsx)("span",{className:"font-mono text-sm font-medium",children:e}),a[e]&&(0,t.jsx)("span",{className:"text-xs text-gray-500 font-normal",children:a[e]})]})},e))})})]});var i=e.i(793130);let c=({enabled:e,routerFieldsMetadata:r,onToggle:a})=>(0,t.jsx)("div",{className:"space-y-3 max-w-3xl",children:(0,t.jsxs)("div",{className:"flex items-start justify-between",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:r.enable_tag_filtering?.ui_field_name||"Enable Tag Filtering"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500 mt-0.5",children:[r.enable_tag_filtering?.field_description||"",r.enable_tag_filtering?.link&&(0,t.jsxs)(t.Fragment,{children:[" ",(0,t.jsx)("a",{href:r.enable_tag_filtering.link,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline",children:"Learn more"})]})]})]}),(0,t.jsx)(i.Switch,{checked:e,onChange:a,className:"ml-4"})]})});e.s(["default",0,({value:e,onChange:r,routerFieldsMetadata:a,availableRoutingStrategies:n,routingStrategyDescriptions:i})=>(0,t.jsxs)("div",{className:"w-full space-y-8 py-2",children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Routing Settings"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure how requests are routed to deployments"})]}),n.length>0&&(0,t.jsx)(s,{selectedStrategy:e.selectedStrategy||e.routerSettings.routing_strategy||null,availableStrategies:n,routingStrategyDescriptions:i,routerFieldsMetadata:a,onStrategyChange:t=>{r({...e,selectedStrategy:t})}}),(0,t.jsx)(c,{enabled:e.enableTagFiltering,routerFieldsMetadata:a,onToggle:t=>{r({...e,enableTagFiltering:t})}})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),"latency-based-routing"===e.selectedStrategy&&(0,t.jsx)(l,{routingStrategyArgs:e.routerSettings.routing_strategy_args}),(0,t.jsx)(o,{routerSettings:e.routerSettings,routerFieldsMetadata:a})]})],158392);var d=e.i(994388),u=e.i(998573),m=e.i(653496),g=e.i(107233),p=e.i(271645),f=e.i(592968),h=e.i(361653),h=h;let x=(0,e.i(475254).default)("arrow-down",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var b=e.i(37727);function y({group:e,onChange:r,availableModels:a,maxFallbacks:l}){let o=a.filter(t=>t!==e.primaryModel),s=e.fallbackModels.length{let a=[...e.fallbackModels];a.includes(t)&&(a=a.filter(e=>e!==t)),r({...e,primaryModel:t,fallbackModels:a})},showSearch:!0,getPopupContainer:e=>e.parentElement||document.body,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase()),options:a.map(e=>({label:e,value:e}))}),!e.primaryModel&&(0,t.jsxs)("div",{className:"mt-2 flex items-center gap-2 text-amber-600 text-xs bg-amber-50 p-2 rounded",children:[(0,t.jsx)(h.default,{className:"w-4 h-4"}),(0,t.jsx)("span",{children:"Select a model to begin configuring fallbacks"})]})]}),(0,t.jsx)("div",{className:"flex items-center justify-center -my-4 z-10",children:(0,t.jsxs)("div",{className:"bg-indigo-50 text-indigo-500 px-4 py-1 rounded-full text-xs font-bold border border-indigo-100 flex items-center gap-2 shadow-sm",children:[(0,t.jsx)(x,{className:"w-4 h-4"}),"IF FAILS, TRY..."]})}),(0,t.jsxs)("div",{className:`transition-opacity duration-300 ${!e.primaryModel?"opacity-50 pointer-events-none":"opacity-100"}`,children:[(0,t.jsxs)("label",{className:"block text-sm font-semibold text-gray-700 mb-2",children:["Fallback Chain ",(0,t.jsx)("span",{className:"text-red-500",children:"*"}),(0,t.jsxs)("span",{className:"text-xs text-gray-500 font-normal ml-2",children:["(Max ",l," fallbacks at a time)"]})]}),(0,t.jsxs)("div",{className:"bg-gray-50 rounded-xl p-4 border border-gray-200",children:[(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(n.Select,{mode:"multiple",className:"w-full",size:"large",placeholder:s?"Select fallback models to add...":`Maximum ${l} fallbacks reached`,value:e.fallbackModels,onChange:t=>{let a=t.slice(0,l);r({...e,fallbackModels:a})},disabled:!e.primaryModel,getPopupContainer:e=>e.parentElement||document.body,options:o.map(e=>({label:e,value:e})),optionRender:(r,a)=>{let l=e.fallbackModels.includes(r.value),o=l?e.fallbackModels.indexOf(r.value)+1:null;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[l&&null!==o&&(0,t.jsx)("span",{className:"flex items-center justify-center w-5 h-5 rounded bg-indigo-100 text-indigo-600 text-xs font-bold",children:o}),(0,t.jsx)("span",{children:r.label})]})},maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(f.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})}),showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase())}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1 ml-1",children:s?`Search and select multiple models. Selected models will appear below in order. (${e.fallbackModels.length}/${l} used)`:`Maximum ${l} fallbacks reached. Remove some to add more.`})]}),(0,t.jsx)("div",{className:"space-y-2 min-h-[100px]",children:0===e.fallbackModels.length?(0,t.jsxs)("div",{className:"h-32 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)("span",{className:"text-sm",children:"No fallback models selected"}),(0,t.jsx)("span",{className:"text-xs mt-1",children:"Add models from the dropdown above"})]}):e.fallbackModels.map((a,l)=>(0,t.jsxs)("div",{className:"group flex items-center justify-between p-3 bg-white rounded-lg border border-gray-200 hover:border-indigo-300 hover:shadow-sm transition-all",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex items-center justify-center w-6 h-6 rounded bg-gray-100 text-gray-400 group-hover:text-indigo-500 group-hover:bg-indigo-50",children:(0,t.jsx)("span",{className:"text-xs font-bold",children:l+1})}),(0,t.jsx)("div",{children:(0,t.jsx)("span",{className:"font-medium text-gray-800",children:a})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>{let t;return t=e.fallbackModels.filter((e,t)=>t!==l),void r({...e,fallbackModels:t})},className:"opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500 p-1",children:(0,t.jsx)(b.X,{className:"w-4 h-4"})})]},`${a}-${l}`))})]})]})]})}function v({groups:e,onGroupsChange:r,availableModels:a,maxFallbacks:l=10,maxGroups:o=5}){let[n,s]=(0,p.useState)(e.length>0?e[0].id:"1");(0,p.useEffect)(()=>{e.length>0?e.some(e=>e.id===n)||s(e[0].id):s("1")},[e]);let i=()=>{if(e.length>=o)return;let t=Date.now().toString();r([...e,{id:t,primaryModel:null,fallbackModels:[]}]),s(t)},c=t=>{r(e.map(e=>e.id===t.id?t:e))},f=e.map((r,o)=>{let n=r.primaryModel?r.primaryModel:`Group ${o+1}`;return{key:r.id,label:n,closable:e.length>1,children:(0,t.jsx)(y,{group:r,onChange:c,availableModels:a,maxFallbacks:l})}});return 0===e.length?(0,t.jsxs)("div",{className:"text-center py-12 bg-gray-50 rounded-lg border border-dashed border-gray-300",children:[(0,t.jsx)("p",{className:"text-gray-500 mb-4",children:"No fallback groups configured"}),(0,t.jsx)(d.Button,{variant:"primary",onClick:i,icon:()=>(0,t.jsx)(g.Plus,{className:"w-4 h-4"}),children:"Create First Group"})]}):(0,t.jsx)(m.Tabs,{type:"editable-card",activeKey:n,onChange:s,onEdit:(t,a)=>{"add"===a?i():"remove"===a&&e.length>1&&(t=>{if(1===e.length)return u.message.warning("At least one group is required");let a=e.filter(e=>e.id!==t);r(a),n===t&&a.length>0&&s(a[a.length-1].id)})(t)},items:f,className:"fallback-tabs",tabBarStyle:{marginBottom:0},hideAdd:e.length>=o})}e.s(["FallbackSelectionForm",()=>v],419470)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/23bf955e8672ce98.js b/litellm/proxy/_experimental/out/_next/static/chunks/23bf955e8672ce98.js new file mode 100644 index 0000000000..f483b01ffa --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/23bf955e8672ce98.js @@ -0,0 +1 @@ +(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,757440,e=>{"use strict";var t=e.i(290571),s=e.i(271645);let l=e=>{var l=(0,t.__rest)(e,[]);return s.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},l),s.default.createElement("path",{d:"M11.9999 13.1714L16.9497 8.22168L18.3639 9.63589L11.9999 15.9999L5.63599 9.63589L7.0502 8.22168L11.9999 13.1714Z"}))};e.s(["default",()=>l])},446428,854056,e=>{"use strict";let t;var s=e.i(290571),l=e.i(271645);let r=e=>{var t=(0,s.__rest)(e,[]);return l.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},t),l.default.createElement("path",{d:"M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 10.5858L9.17157 7.75736L7.75736 9.17157L10.5858 12L7.75736 14.8284L9.17157 16.2426L12 13.4142L14.8284 16.2426L16.2426 14.8284L13.4142 12L16.2426 9.17157L14.8284 7.75736L12 10.5858Z"}))};e.s(["default",()=>r],446428);var a=e.i(746725),n=e.i(914189),i=e.i(553521),d=e.i(835696),o=e.i(941444),c=e.i(178677),u=e.i(294316),m=e.i(83733),h=e.i(233137),x=e.i(732607),g=e.i(397701),f=e.i(700020);function p(e){var t;return!!(e.enter||e.enterFrom||e.enterTo||e.leave||e.leaveFrom||e.leaveTo)||(null!=(t=e.as)?t:S)!==l.Fragment||1===l.default.Children.count(e.children)}let b=(0,l.createContext)(null);b.displayName="TransitionContext";var j=((t=j||{}).Visible="visible",t.Hidden="hidden",t);let v=(0,l.createContext)(null);function y(e){return"children"in e?y(e.children):e.current.filter(({el:e})=>null!==e.current).filter(({state:e})=>"visible"===e).length>0}function _(e,t){let s=(0,o.useLatestValue)(e),r=(0,l.useRef)([]),d=(0,i.useIsMounted)(),c=(0,a.useDisposables)(),u=(0,n.useEvent)((e,t=f.RenderStrategy.Hidden)=>{let l=r.current.findIndex(({el:t})=>t===e);-1!==l&&((0,g.match)(t,{[f.RenderStrategy.Unmount](){r.current.splice(l,1)},[f.RenderStrategy.Hidden](){r.current[l].state="hidden"}}),c.microTask(()=>{var e;!y(r)&&d.current&&(null==(e=s.current)||e.call(s))}))}),m=(0,n.useEvent)(e=>{let t=r.current.find(({el:t})=>t===e);return t?"visible"!==t.state&&(t.state="visible"):r.current.push({el:e,state:"visible"}),()=>u(e,f.RenderStrategy.Unmount)}),h=(0,l.useRef)([]),x=(0,l.useRef)(Promise.resolve()),p=(0,l.useRef)({enter:[],leave:[]}),b=(0,n.useEvent)((e,s,l)=>{h.current.splice(0),t&&(t.chains.current[s]=t.chains.current[s].filter(([t])=>t!==e)),null==t||t.chains.current[s].push([e,new Promise(e=>{h.current.push(e)})]),null==t||t.chains.current[s].push([e,new Promise(e=>{Promise.all(p.current[s].map(([e,t])=>t)).then(()=>e())})]),"enter"===s?x.current=x.current.then(()=>null==t?void 0:t.wait.current).then(()=>l(s)):l(s)}),j=(0,n.useEvent)((e,t,s)=>{Promise.all(p.current[t].splice(0).map(([e,t])=>t)).then(()=>{var e;null==(e=h.current.shift())||e()}).then(()=>s(t))});return(0,l.useMemo)(()=>({children:r,register:m,unregister:u,onStart:b,onStop:j,wait:x,chains:p}),[m,u,r,b,j,p,x])}v.displayName="NestingContext";let S=l.Fragment,N=f.RenderFeatures.RenderStrategy,w=(0,f.forwardRefWithAs)(function(e,t){let{show:s,appear:r=!1,unmount:a=!0,...i}=e,o=(0,l.useRef)(null),m=p(e),x=(0,u.useSyncRefs)(...m?[o,t]:null===t?[]:[t]);(0,c.useServerHandoffComplete)();let g=(0,h.useOpenClosed)();if(void 0===s&&null!==g&&(s=(g&h.State.Open)===h.State.Open),void 0===s)throw Error("A is used but it is missing a `show={true | false}` prop.");let[j,S]=(0,l.useState)(s?"visible":"hidden"),w=_(()=>{s||S("hidden")}),[T,k]=(0,l.useState)(!0),I=(0,l.useRef)([s]);(0,d.useIsoMorphicEffect)(()=>{!1!==T&&I.current[I.current.length-1]!==s&&(I.current.push(s),k(!1))},[I,s]);let E=(0,l.useMemo)(()=>({show:s,appear:r,initial:T}),[s,r,T]);(0,d.useIsoMorphicEffect)(()=>{s?S("visible"):y(w)||null===o.current||S("hidden")},[s,w]);let U={unmount:a},R=(0,n.useEvent)(()=>{var t;T&&k(!1),null==(t=e.beforeEnter)||t.call(e)}),B=(0,n.useEvent)(()=>{var t;T&&k(!1),null==(t=e.beforeLeave)||t.call(e)}),F=(0,f.useRender)();return l.default.createElement(v.Provider,{value:w},l.default.createElement(b.Provider,{value:E},F({ourProps:{...U,as:l.Fragment,children:l.default.createElement(C,{ref:x,...U,...i,beforeEnter:R,beforeLeave:B})},theirProps:{},defaultTag:l.Fragment,features:N,visible:"visible"===j,name:"Transition"})))}),C=(0,f.forwardRefWithAs)(function(e,t){var s,r;let{transition:a=!0,beforeEnter:i,afterEnter:o,beforeLeave:j,afterLeave:w,enter:C,enterFrom:T,enterTo:k,entered:I,leave:E,leaveFrom:U,leaveTo:R,...B}=e,[F,M]=(0,l.useState)(null),L=(0,l.useRef)(null),D=p(e),A=(0,u.useSyncRefs)(...D?[L,t,M]:null===t?[]:[t]),O=null==(s=B.unmount)||s?f.RenderStrategy.Unmount:f.RenderStrategy.Hidden,{show:P,appear:z,initial:V}=function(){let e=(0,l.useContext)(b);if(null===e)throw Error("A is used but it is missing a parent or .");return e}(),[$,K]=(0,l.useState)(P?"visible":"hidden"),q=function(){let e=(0,l.useContext)(v);if(null===e)throw Error("A is used but it is missing a parent or .");return e}(),{register:H,unregister:G}=q;(0,d.useIsoMorphicEffect)(()=>H(L),[H,L]),(0,d.useIsoMorphicEffect)(()=>{if(O===f.RenderStrategy.Hidden&&L.current)return P&&"visible"!==$?void K("visible"):(0,g.match)($,{hidden:()=>G(L),visible:()=>H(L)})},[$,L,H,G,P,O]);let W=(0,c.useServerHandoffComplete)();(0,d.useIsoMorphicEffect)(()=>{if(D&&W&&"visible"===$&&null===L.current)throw Error("Did you forget to passthrough the `ref` to the actual DOM node?")},[L,$,W,D]);let J=V&&!z,Q=z&&P&&V,Z=(0,l.useRef)(!1),Y=_(()=>{Z.current||(K("hidden"),G(L))},q),X=(0,n.useEvent)(e=>{Z.current=!0,Y.onStart(L,e?"enter":"leave",e=>{"enter"===e?null==i||i():"leave"===e&&(null==j||j())})}),ee=(0,n.useEvent)(e=>{let t=e?"enter":"leave";Z.current=!1,Y.onStop(L,t,e=>{"enter"===e?null==o||o():"leave"===e&&(null==w||w())}),"leave"!==t||y(Y)||(K("hidden"),G(L))});(0,l.useEffect)(()=>{D&&a||(X(P),ee(P))},[P,D,a]);let et=!(!a||!D||!W||J),[,es]=(0,m.useTransition)(et,F,P,{start:X,end:ee}),el=(0,f.compact)({ref:A,className:(null==(r=(0,x.classNames)(B.className,Q&&C,Q&&T,es.enter&&C,es.enter&&es.closed&&T,es.enter&&!es.closed&&k,es.leave&&E,es.leave&&!es.closed&&U,es.leave&&es.closed&&R,!es.transition&&P&&I))?void 0:r.trim())||void 0,...(0,m.transitionDataAttributes)(es)}),er=0;"visible"===$&&(er|=h.State.Open),"hidden"===$&&(er|=h.State.Closed),es.enter&&(er|=h.State.Opening),es.leave&&(er|=h.State.Closing);let ea=(0,f.useRender)();return l.default.createElement(v.Provider,{value:Y},l.default.createElement(h.OpenClosedProvider,{value:er},ea({ourProps:el,theirProps:B,defaultTag:S,features:N,visible:"visible"===$,name:"Transition.Child"})))}),T=(0,f.forwardRefWithAs)(function(e,t){let s=null!==(0,l.useContext)(b),r=null!==(0,h.useOpenClosed)();return l.default.createElement(l.default.Fragment,null,!s&&r?l.default.createElement(w,{ref:t,...e}):l.default.createElement(C,{ref:t,...e}))}),k=Object.assign(w,{Child:T,Root:w});e.s(["Transition",()=>k],854056)},206929,e=>{"use strict";var t=e.i(290571),s=e.i(757440),l=e.i(271645),r=e.i(446428),a=e.i(444755),n=e.i(673706),i=e.i(103471),d=e.i(495470),o=e.i(854056),c=e.i(888288);let u=(0,n.makeClassName)("Select"),m=l.default.forwardRef((e,n)=>{let{defaultValue:m="",value:h,onValueChange:x,placeholder:g="Select...",disabled:f=!1,icon:p,enableClear:b=!1,required:j,children:v,name:y,error:_=!1,errorMessage:S,className:N,id:w}=e,C=(0,t.__rest)(e,["defaultValue","value","onValueChange","placeholder","disabled","icon","enableClear","required","children","name","error","errorMessage","className","id"]),T=(0,l.useRef)(null),k=l.Children.toArray(v),[I,E]=(0,c.default)(m,h),U=(0,l.useMemo)(()=>{let e=l.default.Children.toArray(v).filter(l.isValidElement);return(0,i.constructValueToNameMapping)(e)},[v]);return l.default.createElement("div",{className:(0,a.tremorTwMerge)("w-full min-w-[10rem] text-tremor-default",N)},l.default.createElement("div",{className:"relative"},l.default.createElement("select",{title:"select-hidden",required:j,className:(0,a.tremorTwMerge)("h-full w-full absolute left-0 top-0 -z-10 opacity-0"),value:I,onChange:e=>{e.preventDefault()},name:y,disabled:f,id:w,onFocus:()=>{let e=T.current;e&&e.focus()}},l.default.createElement("option",{className:"hidden",value:"",disabled:!0,hidden:!0},g),k.map(e=>{let t=e.props.value,s=e.props.children;return l.default.createElement("option",{className:"hidden",key:t,value:t},s)})),l.default.createElement(d.Listbox,Object.assign({as:"div",ref:n,defaultValue:I,value:I,onChange:e=>{null==x||x(e),E(e)},disabled:f,id:w},C),({value:e})=>{var t;return l.default.createElement(l.default.Fragment,null,l.default.createElement(d.ListboxButton,{ref:T,className:(0,a.tremorTwMerge)("w-full outline-none text-left whitespace-nowrap truncate rounded-tremor-default focus:ring-2 transition duration-100 border pr-8 py-2","border-tremor-border shadow-tremor-input focus:border-tremor-brand-subtle focus:ring-tremor-brand-muted","dark:border-dark-tremor-border dark:shadow-dark-tremor-input dark:focus:border-dark-tremor-brand-subtle dark:focus:ring-dark-tremor-brand-muted",p?"pl-10":"pl-3",(0,i.getSelectButtonColors)((0,i.hasValue)(e),f,_))},p&&l.default.createElement("span",{className:(0,a.tremorTwMerge)("absolute inset-y-0 left-0 flex items-center ml-px pl-2.5")},l.default.createElement(p,{className:(0,a.tremorTwMerge)(u("Icon"),"flex-none h-5 w-5","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")})),l.default.createElement("span",{className:"w-[90%] block truncate"},e&&null!=(t=U.get(e))?t:g),l.default.createElement("span",{className:(0,a.tremorTwMerge)("absolute inset-y-0 right-0 flex items-center mr-3")},l.default.createElement(s.default,{className:(0,a.tremorTwMerge)(u("arrowDownIcon"),"flex-none h-5 w-5","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")}))),b&&I?l.default.createElement("button",{type:"button",className:(0,a.tremorTwMerge)("absolute inset-y-0 right-0 flex items-center mr-8"),onClick:e=>{e.preventDefault(),E(""),null==x||x("")}},l.default.createElement(r.default,{className:(0,a.tremorTwMerge)(u("clearIcon"),"flex-none h-4 w-4","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")})):null,l.default.createElement(o.Transition,{enter:"transition ease duration-100 transform",enterFrom:"opacity-0 -translate-y-4",enterTo:"opacity-100 translate-y-0",leave:"transition ease duration-100 transform",leaveFrom:"opacity-100 translate-y-0",leaveTo:"opacity-0 -translate-y-4"},l.default.createElement(d.ListboxOptions,{anchor:"bottom start",className:(0,a.tremorTwMerge)("z-10 w-[var(--button-width)] divide-y overflow-y-auto outline-none rounded-tremor-default max-h-[228px] border [--anchor-gap:4px]","bg-tremor-background border-tremor-border divide-tremor-border shadow-tremor-dropdown","dark:bg-dark-tremor-background dark:border-dark-tremor-border dark:divide-dark-tremor-border dark:shadow-dark-tremor-dropdown")},v)))})),_&&S?l.default.createElement("p",{className:(0,a.tremorTwMerge)("errorMessage","text-sm text-rose-500 mt-1")},S):null)});m.displayName="Select",e.s(["Select",()=>m],206929)},502275,e=>{"use strict";var t=e.i(271645);let s=t.forwardRef(function(e,s){return t.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:s},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["InformationCircleIcon",0,s],502275)},78085,e=>{"use strict";var t=e.i(290571),s=e.i(103471),l=e.i(888288),r=e.i(271645),a=e.i(444755),n=e.i(673706);let i=(0,n.makeClassName)("Textarea"),d=r.default.forwardRef((e,d)=>{let{value:o,defaultValue:c="",placeholder:u="Type...",error:m=!1,errorMessage:h,disabled:x=!1,className:g,onChange:f,onValueChange:p,autoHeight:b=!1}=e,j=(0,t.__rest)(e,["value","defaultValue","placeholder","error","errorMessage","disabled","className","onChange","onValueChange","autoHeight"]),[v,y]=(0,l.default)(c,o),_=(0,r.useRef)(null),S=(0,s.hasValue)(v);return(0,r.useEffect)(()=>{let e=_.current;if(b&&e){e.style.height="60px";let t=e.scrollHeight;e.style.height=t+"px"}},[b,_,v]),r.default.createElement(r.default.Fragment,null,r.default.createElement("textarea",Object.assign({ref:(0,n.mergeRefs)([_,d]),value:v,placeholder:u,disabled:x,className:(0,a.tremorTwMerge)(i("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,s.getSelectButtonColors)(S,x,m),x?"placeholder:text-tremor-content-subtle dark:placeholder:text-dark-tremor-content-subtle":"placeholder:text-tremor-content dark:placeholder:text-dark-tremor-content",g),"data-testid":"text-area",onChange:e=>{null==f||f(e),y(e.target.value),null==p||p(e.target.value)}},j)),m&&h?r.default.createElement("p",{className:(0,a.tremorTwMerge)(i("errorMessage"),"text-sm text-red-500 mt-1")},h):null)});d.displayName="Textarea",e.s(["Textarea",()=>d],78085)},910119,e=>{"use strict";var t=e.i(843476),s=e.i(197647),l=e.i(653824),r=e.i(881073),a=e.i(404206),n=e.i(723731),i=e.i(271645),d=e.i(464571),o=e.i(212931),c=e.i(898586),u=e.i(312361),m=e.i(998573),h=e.i(291542),x=e.i(199133),g=e.i(28651),f=e.i(175712),p=e.i(770914),b=e.i(536916),j=e.i(764205),v=e.i(827252),y=e.i(994388),_=e.i(35983),S=e.i(779241),N=e.i(78085),w=e.i(808613),C=e.i(592968),T=e.i(708347),k=e.i(860585),I=e.i(355619),E=e.i(435451);function U({userData:e,onCancel:s,onSubmit:l,teams:r,accessToken:a,userID:n,userRole:d,userModels:o,possibleUIRoles:c,isBulkEdit:u=!1}){let[m]=w.Form.useForm(),[h,g]=(0,i.useState)(!1);return i.default.useEffect(()=>{let t=e.user_info?.max_budget,s=null==t;g(s),m.setFieldsValue({user_id:e.user_id,user_email:e.user_info?.user_email,user_alias:e.user_info?.user_alias,user_role:e.user_info?.user_role,models:e.user_info?.models||[],max_budget:s?"":t,budget_duration:e.user_info?.budget_duration,metadata:e.user_info?.metadata?JSON.stringify(e.user_info.metadata,null,2):void 0})},[e,m]),(0,t.jsxs)(w.Form,{form:m,onFinish:e=>{if(e.metadata&&"string"==typeof e.metadata)try{e.metadata=JSON.parse(e.metadata)}catch(e){console.error("Error parsing metadata JSON:",e);return}(h||""===e.max_budget||void 0===e.max_budget)&&(e.max_budget=null),l(e)},layout:"vertical",children:[!u&&(0,t.jsx)(w.Form.Item,{label:"User ID",name:"user_id",children:(0,t.jsx)(S.TextInput,{disabled:!0})}),!u&&(0,t.jsx)(w.Form.Item,{label:"Email",name:"user_email",children:(0,t.jsx)(S.TextInput,{})}),(0,t.jsx)(w.Form.Item,{label:"User Alias",name:"user_alias",children:(0,t.jsx)(S.TextInput,{})}),(0,t.jsx)(w.Form.Item,{label:(0,t.jsxs)("span",{children:["Global Proxy Role"," ",(0,t.jsx)(C.Tooltip,{title:"This is the role that the user will globally on the proxy. This role is independent of any team/org specific roles.",children:(0,t.jsx)(v.InfoCircleOutlined,{})})]}),name:"user_role",children:(0,t.jsx)(x.Select,{children:c&&Object.entries(c).map(([e,{ui_label:s,description:l}])=>(0,t.jsx)(_.SelectItem,{value:e,title:s,children:(0,t.jsxs)("div",{className:"flex",children:[s," ",(0,t.jsx)("p",{className:"ml-2",style:{color:"gray",fontSize:"12px"},children:l})]})},e))})}),(0,t.jsx)(w.Form.Item,{label:(0,t.jsxs)("span",{children:["Personal Models"," ",(0,t.jsx)(C.Tooltip,{title:"Select which models this user can access outside of team-scope. Choose 'All Proxy Models' to grant access to all models available on the proxy.",children:(0,t.jsx)(v.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"models",children:(0,t.jsxs)(x.Select,{mode:"multiple",placeholder:"Select models",style:{width:"100%"},disabled:!T.all_admin_roles.includes(d||""),children:[(0,t.jsx)(x.Select.Option,{value:"all-proxy-models",children:"All Proxy Models"},"all-proxy-models"),(0,t.jsx)(x.Select.Option,{value:"no-default-models",children:"No Default Models"},"no-default-models"),o.map(e=>(0,t.jsx)(x.Select.Option,{value:e,children:(0,I.getModelDisplayName)(e)},e))]})}),(0,t.jsx)(w.Form.Item,{label:(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"12px"},children:[(0,t.jsx)("span",{children:"Max Budget (USD)"}),(0,t.jsx)(b.Checkbox,{checked:h,onChange:e=>{let t=e.target.checked;g(t),t&&m.setFieldsValue({max_budget:""})},children:"Unlimited Budget"})]}),name:"max_budget",rules:[{validator:(e,t)=>h||""!==t&&null!=t?Promise.resolve():Promise.reject(Error("Please enter a budget or select Unlimited Budget"))}],children:(0,t.jsx)(E.default,{step:.01,precision:2,style:{width:"100%"},disabled:h})}),(0,t.jsx)(w.Form.Item,{label:"Reset Budget",name:"budget_duration",children:(0,t.jsx)(k.default,{})}),(0,t.jsx)(w.Form.Item,{label:"Metadata",name:"metadata",children:(0,t.jsx)(N.Textarea,{rows:4,placeholder:"Enter metadata as JSON"})}),(0,t.jsxs)("div",{className:"flex justify-end space-x-2",children:[(0,t.jsx)(y.Button,{variant:"secondary",type:"button",onClick:s,children:"Cancel"}),(0,t.jsx)(y.Button,{type:"submit",children:"Save Changes"})]})]})}var R=e.i(727749);let{Text:B,Title:F}=c.Typography,M=({open:e,onCancel:s,selectedUsers:l,possibleUIRoles:r,accessToken:a,onSuccess:n,teams:d,userRole:c,userModels:v,allowAllUsers:y=!1})=>{let[_,S]=(0,i.useState)(!1),[N,w]=(0,i.useState)([]),[C,T]=(0,i.useState)(null),[k,I]=(0,i.useState)(!1),[E,M]=(0,i.useState)(!1),L=()=>{w([]),T(null),I(!1),M(!1),s()},D=i.default.useMemo(()=>({user_id:"bulk_edit",user_info:{user_email:"",user_role:"",teams:[],models:[],max_budget:null,spend:0,metadata:{},created_at:null,updated_at:null},keys:[],teams:d||[]}),[d,e]),A=async e=>{if(console.log("formValues",e),!a)return void R.default.fromBackend("Access token not found");S(!0);try{let t=l.map(e=>e.user_id),r={};e.user_role&&""!==e.user_role&&(r.user_role=e.user_role),null!==e.max_budget&&void 0!==e.max_budget&&(r.max_budget=e.max_budget),e.models&&e.models.length>0&&(r.models=e.models),e.budget_duration&&""!==e.budget_duration&&(r.budget_duration=e.budget_duration),e.metadata&&Object.keys(e.metadata).length>0&&(r.metadata=e.metadata);let i=Object.keys(r).length>0,d=k&&N.length>0;if(!i&&!d)return void R.default.fromBackend("Please modify at least one field or select teams to add users to");let o=[];if(i)if(E){let e=await (0,j.userBulkUpdateUserCall)(a,r,void 0,!0);o.push(`Updated all users (${e.total_requested} total)`)}else await (0,j.userBulkUpdateUserCall)(a,r,t),o.push(`Updated ${t.length} user(s)`);if(d){let e=[];for(let t of N)try{let s=null;s=E?null:l.map(e=>({user_id:e.user_id,role:"user",user_email:e.user_email||null}));let r=await (0,j.teamBulkMemberAddCall)(a,t,s||null,C||void 0,E);console.log("result",r),e.push({teamId:t,success:!0,successfulAdditions:r.successful_additions,failedAdditions:r.failed_additions})}catch(s){console.error(`Failed to add users to team ${t}:`,s),e.push({teamId:t,success:!1,error:s})}let t=e.filter(e=>e.success),s=e.filter(e=>!e.success);if(t.length>0){let e=t.reduce((e,t)=>e+t.successfulAdditions,0);o.push(`Added users to ${t.length} team(s) (${e} total additions)`)}s.length>0&&m.message.warning(`Failed to add users to ${s.length} team(s)`)}o.length>0&&R.default.success(o.join(". ")),w([]),T(null),I(!1),M(!1),n(),s()}catch(e){console.error("Bulk operation failed:",e),R.default.fromBackend("Failed to perform bulk operations")}finally{S(!1)}};return(0,t.jsxs)(o.Modal,{open:e,onCancel:L,footer:null,title:E?"Bulk Edit All Users":`Bulk Edit ${l.length} User(s)`,width:800,children:[y&&(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(b.Checkbox,{checked:E,onChange:e=>M(e.target.checked),children:(0,t.jsx)(B,{strong:!0,children:"Update ALL users in the system"})}),E&&(0,t.jsx)("div",{style:{marginTop:8},children:(0,t.jsx)(B,{type:"warning",style:{fontSize:"12px"},children:"⚠️ This will apply changes to ALL users in the system, not just the selected ones."})})]}),!E&&(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsxs)(F,{level:5,children:["Selected Users (",l.length,"):"]}),(0,t.jsx)(h.Table,{size:"small",bordered:!0,dataSource:l,pagination:!1,scroll:{y:200},rowKey:"user_id",columns:[{title:"User ID",dataIndex:"user_id",key:"user_id",width:"30%",render:e=>(0,t.jsx)(B,{strong:!0,style:{fontSize:"12px"},children:e.length>20?`${e.slice(0,20)}...`:e})},{title:"Email",dataIndex:"user_email",key:"user_email",width:"25%",render:e=>(0,t.jsx)(B,{type:"secondary",style:{fontSize:"12px"},children:e||"No email"})},{title:"Current Role",dataIndex:"user_role",key:"user_role",width:"25%",render:e=>(0,t.jsx)(B,{style:{fontSize:"12px"},children:r?.[e]?.ui_label||e})},{title:"Budget",dataIndex:"max_budget",key:"max_budget",width:"20%",render:e=>(0,t.jsx)(B,{style:{fontSize:"12px"},children:null!==e?`$${e}`:"Unlimited"})}]})]}),(0,t.jsx)(u.Divider,{}),(0,t.jsx)("div",{className:"mb-4",children:(0,t.jsxs)(B,{children:[(0,t.jsx)("strong",{children:"Instructions:"})," Fill in the fields below with the values you want to apply to all selected users. You can bulk edit: role, budget, models, and metadata. You can also add users to teams."]})}),(0,t.jsx)(f.Card,{title:"Team Management",size:"small",className:"mb-4",style:{backgroundColor:"#fafafa"},children:(0,t.jsxs)(p.Space,{direction:"vertical",style:{width:"100%"},children:[(0,t.jsx)(b.Checkbox,{checked:k,onChange:e=>I(e.target.checked),children:"Add selected users to teams"}),k&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(B,{strong:!0,children:"Select Teams:"}),(0,t.jsx)(x.Select,{mode:"multiple",placeholder:"Select teams to add users to",value:N,onChange:w,style:{width:"100%",marginTop:8},options:d?.map(e=>({label:e.team_alias||e.team_id,value:e.team_id}))||[]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(B,{strong:!0,children:"Team Budget (Optional):"}),(0,t.jsx)(g.InputNumber,{placeholder:"Max budget per user in team",value:C,onChange:e=>T(e),style:{width:"100%",marginTop:8},min:0,step:.01,precision:2}),(0,t.jsx)(B,{type:"secondary",style:{fontSize:"12px"},children:"Leave empty for unlimited budget within team limits"})]}),(0,t.jsx)(B,{type:"secondary",style:{fontSize:"12px"},children:'Users will be added with "user" role by default. All users will be added to each selected team.'})]})]})}),(0,t.jsx)(U,{userData:D,onCancel:L,onSubmit:A,teams:d,accessToken:a,userID:"bulk_edit",userRole:c,userModels:v,possibleUIRoles:r,isBulkEdit:!0}),_&&(0,t.jsx)("div",{style:{textAlign:"center",marginTop:"10px"},children:(0,t.jsxs)(B,{children:["Updating ",E?"all users":l.length," user(s)..."]})})]})};var L=e.i(371455);let D=({visible:e,possibleUIRoles:s,onCancel:l,user:r,onSubmit:a})=>{let[n,c]=(0,i.useState)(r),[u]=w.Form.useForm();(0,i.useEffect)(()=>{u.resetFields()},[r]);let m=async()=>{u.resetFields(),l()},h=async e=>{a(e),u.resetFields(),l()};return r?(0,t.jsx)(o.Modal,{open:e,onCancel:m,footer:null,title:"Edit User "+r.user_id,width:1e3,children:(0,t.jsx)(w.Form,{form:u,onFinish:h,initialValues:r,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(w.Form.Item,{className:"mt-8",label:"User Email",tooltip:"Email of the User",name:"user_email",children:(0,t.jsx)(S.TextInput,{})}),(0,t.jsx)(w.Form.Item,{label:"user_id",name:"user_id",hidden:!0,children:(0,t.jsx)(S.TextInput,{})}),(0,t.jsx)(w.Form.Item,{label:"User Role",name:"user_role",children:(0,t.jsx)(x.Select,{children:s&&Object.entries(s).map(([e,{ui_label:s,description:l}])=>(0,t.jsx)(_.SelectItem,{value:e,title:s,children:(0,t.jsxs)("div",{className:"flex",children:[s," ",(0,t.jsx)("p",{className:"ml-2",style:{color:"gray",fontSize:"12px"},children:l})]})},e))})}),(0,t.jsx)(w.Form.Item,{label:"Spend (USD)",name:"spend",tooltip:"(float) - Spend of all LLM calls completed by this user",help:"Across all keys (including keys with team_id).",children:(0,t.jsx)(g.InputNumber,{min:0,step:.01})}),(0,t.jsx)(w.Form.Item,{label:"User Budget (USD)",name:"max_budget",tooltip:"(float) - Maximum budget of this user",help:"Maximum budget of this user.",children:(0,t.jsx)(E.default,{min:0,step:.01})}),(0,t.jsx)(w.Form.Item,{label:"Reset Budget",name:"budget_duration",children:(0,t.jsx)(k.default,{})}),(0,t.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,t.jsx)(d.Button,{htmlType:"submit",children:"Save"})}),(0,t.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,t.jsx)(d.Button,{htmlType:"submit",children:"Save"})})]})})}):null};var A=e.i(172372),O=e.i(500330),P=e.i(152473),z=e.i(266027),V=e.i(912598),$=e.i(127952),K=e.i(304967),q=e.i(629569),H=e.i(599724),G=e.i(114600),W=e.i(482725),J=e.i(790848),Q=e.i(646563),Z=e.i(955135);let Y=({accessToken:e,possibleUIRoles:s,userID:l,userRole:r})=>{let[a,n]=(0,i.useState)(!0),[d,o]=(0,i.useState)(null),[u,m]=(0,i.useState)(!1),[h,f]=(0,i.useState)({}),[p,b]=(0,i.useState)(!1),[v,_]=(0,i.useState)([]),{Paragraph:N}=c.Typography,{Option:w}=x.Select;(0,i.useEffect)(()=>{(async()=>{if(!e)return n(!1);try{let t=await (0,j.getInternalUserSettings)(e);if(o(t),f(t.values||{}),e)try{let t=await (0,j.modelAvailableCall)(e,l,r);if(t&&t.data){let e=t.data.map(e=>e.id);_(e)}}catch(e){console.error("Error fetching available models:",e)}}catch(e){console.error("Error fetching SSO settings:",e),R.default.fromBackend("Failed to fetch SSO settings")}finally{n(!1)}})()},[e]);let C=async()=>{if(e){b(!0);try{let t=Object.entries(h).reduce((e,[t,s])=>(e[t]=""===s?null:s,e),{}),s=await (0,j.updateInternalUserSettings)(e,t);o({...d,values:s.settings}),m(!1)}catch(e){console.error("Error updating SSO settings:",e),R.default.fromBackend("Failed to update settings: "+e)}finally{b(!1)}}},T=(e,t)=>{f(s=>({...s,[e]:t}))},E=e=>e&&Array.isArray(e)?e.map(e=>"string"==typeof e?{team_id:e,user_role:"user"}:"object"==typeof e&&e.team_id?{team_id:e.team_id,max_budget_in_team:e.max_budget_in_team,user_role:e.user_role||"user"}:{team_id:"",user_role:"user"}):[];return a?(0,t.jsx)("div",{className:"flex justify-center items-center h-64",children:(0,t.jsx)(W.Spin,{size:"large"})}):d?(0,t.jsxs)(K.Card,{children:[(0,t.jsxs)("div",{className:"flex justify-between items-center mb-4",children:[(0,t.jsx)(q.Title,{children:"Default User Settings"}),!a&&d&&(u?(0,t.jsxs)("div",{className:"flex gap-2",children:[(0,t.jsx)(y.Button,{variant:"secondary",onClick:()=>{m(!1),f(d.values||{})},disabled:p,children:"Cancel"}),(0,t.jsx)(y.Button,{onClick:C,loading:p,children:"Save Changes"})]}):(0,t.jsx)(y.Button,{onClick:()=>m(!0),children:"Edit Settings"}))]}),d?.field_schema?.description&&(0,t.jsx)(N,{className:"mb-4",children:d.field_schema.description}),(0,t.jsx)(G.Divider,{}),(0,t.jsx)("div",{className:"mt-4 space-y-4",children:(()=>{let{values:e,field_schema:l}=d;return l&&l.properties?Object.entries(l.properties).map(([l,r])=>{let a=e[l],n=l.replace(/_/g," ").replace(/\b\w/g,e=>e.toUpperCase());return(0,t.jsxs)("div",{className:"mb-6 pb-6 border-b border-gray-200 last:border-0",children:[(0,t.jsx)(H.Text,{className:"font-medium text-lg",children:n}),(0,t.jsx)(N,{className:"text-sm text-gray-500 mt-1",children:r.description||"No description available"}),u?(0,t.jsx)("div",{className:"mt-2",children:((e,l,r)=>{let a=l.type;if("teams"===e){let s,l;return(0,t.jsx)("div",{className:"mt-2",children:(s=E(h[e]||[]),l=(e,t,l)=>{let r=[...s];r[e]={...r[e],[t]:l},T("teams",r)},(0,t.jsxs)("div",{className:"space-y-3",children:[s.map((e,r)=>(0,t.jsxs)("div",{className:"border rounded-lg p-4 bg-gray-50",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-3",children:[(0,t.jsxs)(H.Text,{className:"font-medium",children:["Team ",r+1]}),(0,t.jsx)(y.Button,{size:"sm",variant:"secondary",icon:Z.DeleteOutlined,onClick:()=>{T("teams",s.filter((e,t)=>t!==r))},className:"text-red-500 hover:text-red-700",children:"Remove"})]}),(0,t.jsxs)("div",{className:"grid grid-cols-1 md:grid-cols-3 gap-3",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"text-sm font-medium mb-1",children:"Team ID"}),(0,t.jsx)(S.TextInput,{value:e.team_id,onChange:e=>l(r,"team_id",e.target.value),placeholder:"Enter team ID"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"text-sm font-medium mb-1",children:"Max Budget in Team"}),(0,t.jsx)(g.InputNumber,{style:{width:"100%"},value:e.max_budget_in_team,onChange:e=>l(r,"max_budget_in_team",e),placeholder:"Optional",min:0,step:.01,precision:2})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"text-sm font-medium mb-1",children:"User Role"}),(0,t.jsxs)(x.Select,{style:{width:"100%"},value:e.user_role,onChange:e=>l(r,"user_role",e),children:[(0,t.jsx)(w,{value:"user",children:"User"}),(0,t.jsx)(w,{value:"admin",children:"Admin"})]})]})]})]},r)),(0,t.jsx)(y.Button,{variant:"secondary",icon:Q.PlusOutlined,onClick:()=>{T("teams",[...s,{team_id:"",user_role:"user"}])},className:"w-full",children:"Add Team"})]}))})}if("user_role"===e&&s)return(0,t.jsx)(x.Select,{style:{width:"100%"},value:h[e]||"",onChange:t=>T(e,t),className:"mt-2",children:Object.entries(s).filter(([e])=>e.includes("internal_user")).map(([e,{ui_label:s,description:l}])=>(0,t.jsx)(w,{value:e,children:(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)("span",{children:s}),(0,t.jsx)("span",{className:"ml-2 text-xs text-gray-500",children:l})]})},e))});if("budget_duration"===e)return(0,t.jsx)(k.default,{value:h[e]||null,onChange:t=>T(e,t),className:"mt-2"});if("boolean"===a)return(0,t.jsx)("div",{className:"mt-2",children:(0,t.jsx)(J.Switch,{checked:!!h[e],onChange:t=>T(e,t)})});if("array"===a&&l.items?.enum)return(0,t.jsx)(x.Select,{mode:"multiple",style:{width:"100%"},value:h[e]||[],onChange:t=>T(e,t),className:"mt-2",children:l.items.enum.map(e=>(0,t.jsx)(w,{value:e,children:e},e))});else if("models"===e)return(0,t.jsxs)(x.Select,{mode:"multiple",style:{width:"100%"},value:h[e]||[],onChange:t=>T(e,t),className:"mt-2",children:[(0,t.jsx)(w,{value:"no-default-models",children:"No Default Models"},"no-default-models"),(0,t.jsx)(w,{value:"all-proxy-models",children:"All Proxy Models"},"all-proxy-models"),v.map(e=>(0,t.jsx)(w,{value:e,children:(0,I.getModelDisplayName)(e)},e))]});else if("string"===a&&l.enum)return(0,t.jsx)(x.Select,{style:{width:"100%"},value:h[e]||"",onChange:t=>T(e,t),className:"mt-2",children:l.enum.map(e=>(0,t.jsx)(w,{value:e,children:e},e))});else return(0,t.jsx)(S.TextInput,{value:void 0!==h[e]?String(h[e]):"",onChange:t=>T(e,t.target.value),placeholder:l.description||"",className:"mt-2"})})(l,r,0)}):(0,t.jsx)("div",{className:"mt-1 p-2 bg-gray-50 rounded",children:((e,l)=>{if(null==l)return(0,t.jsx)("span",{className:"text-gray-400",children:"Not set"});if("teams"===e&&Array.isArray(l)){if(0===l.length)return(0,t.jsx)("span",{className:"text-gray-400",children:"No teams assigned"});let e=E(l);return(0,t.jsx)("div",{className:"space-y-2 mt-1",children:e.map((e,s)=>(0,t.jsx)("div",{className:"border rounded-lg p-3 bg-white",children:(0,t.jsxs)("div",{className:"grid grid-cols-1 md:grid-cols-3 gap-2 text-sm",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"font-medium text-gray-600",children:"Team ID:"}),(0,t.jsx)("p",{className:"text-gray-900",children:e.team_id||"Not specified"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"font-medium text-gray-600",children:"Max Budget:"}),(0,t.jsx)("p",{className:"text-gray-900",children:void 0!==e.max_budget_in_team?`$${(0,O.formatNumberWithCommas)(e.max_budget_in_team,4)}`:"No limit"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"font-medium text-gray-600",children:"Role:"}),(0,t.jsx)("p",{className:"text-gray-900 capitalize",children:e.user_role})]})]})},s))})}if("user_role"===e&&s&&s[l]){let{ui_label:e,description:r}=s[l];return(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"font-medium",children:e}),r&&(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:r})]})}if("budget_duration"===e)return(0,t.jsx)("span",{children:(0,k.getBudgetDurationLabel)(l)});if("boolean"==typeof l)return(0,t.jsx)("span",{children:l?"Enabled":"Disabled"});if("models"===e&&Array.isArray(l))return 0===l.length?(0,t.jsx)("span",{className:"text-gray-400",children:"None"}):(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:l.map((e,s)=>(0,t.jsx)("span",{className:"px-2 py-1 bg-blue-100 rounded text-xs",children:(0,I.getModelDisplayName)(e)},s))});if("object"==typeof l)return Array.isArray(l)?0===l.length?(0,t.jsx)("span",{className:"text-gray-400",children:"None"}):(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:l.map((e,s)=>(0,t.jsx)("span",{className:"px-2 py-1 bg-blue-100 rounded text-xs",children:"object"==typeof e?JSON.stringify(e):String(e)},s))}):(0,t.jsx)("pre",{className:"bg-gray-100 p-2 rounded text-xs overflow-auto mt-1",children:JSON.stringify(l,null,2)});return(0,t.jsx)("span",{children:String(l)})})(l,a)})]},l)}):(0,t.jsx)(H.Text,{children:"No schema information available"})})()})]}):(0,t.jsx)(K.Card,{children:(0,t.jsx)(H.Text,{children:"No settings available or you do not have permission to view them."})})};var X=e.i(389083),ee=e.i(350967),et=e.i(752978),es=e.i(591935),el=e.i(68155),er=e.i(502275),ea=e.i(278587);let en=(e,s,l,r,a,n)=>{let i=[{header:"User ID",accessorKey:"user_id",enableSorting:!0,cell:({row:e})=>(0,t.jsx)(C.Tooltip,{title:e.original.user_id,children:(0,t.jsx)("span",{className:"text-xs",children:e.original.user_id?`${e.original.user_id.slice(0,7)}...`:"-"})})},{header:"Email",accessorKey:"user_email",enableSorting:!0,cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs",children:e.original.user_email||"-"})},{header:"Global Proxy Role",accessorKey:"user_role",enableSorting:!0,cell:({row:s})=>(0,t.jsx)("span",{className:"text-xs",children:e?.[s.original.user_role]?.ui_label||"-"})},{header:"User Alias",accessorKey:"user_alias",enableSorting:!1,cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs",children:e.original.user_alias||"-"})},{header:"Spend (USD)",accessorKey:"spend",enableSorting:!0,cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs",children:e.original.spend?(0,O.formatNumberWithCommas)(e.original.spend,4):"-"})},{header:"Budget (USD)",accessorKey:"max_budget",enableSorting:!1,cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs",children:null!==e.original.max_budget?e.original.max_budget:"Unlimited"})},{header:()=>(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{children:"SSO ID"}),(0,t.jsx)(C.Tooltip,{title:"SSO ID is the ID of the user in the SSO provider. If the user is not using SSO, this will be null.",children:(0,t.jsx)(er.InformationCircleIcon,{className:"w-4 h-4"})})]}),accessorKey:"sso_user_id",enableSorting:!1,cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs",children:null!==e.original.sso_user_id?e.original.sso_user_id:"-"})},{header:"Virtual Keys",accessorKey:"key_count",enableSorting:!1,cell:({row:e})=>(0,t.jsx)(ee.Grid,{numItems:2,children:e.original.key_count>0?(0,t.jsxs)(X.Badge,{size:"xs",color:"indigo",children:[e.original.key_count," ",1===e.original.key_count?"Key":"Keys"]}):(0,t.jsx)(X.Badge,{size:"xs",color:"gray",children:"No Keys"})})},{header:"Created At",accessorKey:"created_at",enableSorting:!0,cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs",children:e.original.created_at?new Date(e.original.created_at).toLocaleDateString():"-"})},{header:"Updated At",accessorKey:"updated_at",enableSorting:!1,cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs",children:e.original.updated_at?new Date(e.original.updated_at).toLocaleDateString():"-"})},{id:"actions",header:"Actions",enableSorting:!1,cell:({row:e})=>(0,t.jsxs)("div",{className:"flex gap-2",children:[(0,t.jsx)(C.Tooltip,{title:"Edit user details",children:(0,t.jsx)(et.Icon,{icon:es.PencilAltIcon,size:"sm",onClick:()=>a(e.original.user_id,!0),className:"cursor-pointer hover:text-blue-600"})}),(0,t.jsx)(C.Tooltip,{title:"Delete user",children:(0,t.jsx)(et.Icon,{icon:el.TrashIcon,size:"sm",onClick:()=>l(e.original),className:"cursor-pointer hover:text-red-600"})}),(0,t.jsx)(C.Tooltip,{title:"Reset Password",children:(0,t.jsx)(et.Icon,{icon:ea.RefreshIcon,size:"sm",onClick:()=>r(e.original.user_id),className:"cursor-pointer hover:text-green-600"})})]})}];if(n){let{onSelectUser:e,onSelectAll:s,isUserSelected:l,isAllSelected:r,isIndeterminate:a}=n;return[{id:"select",enableSorting:!1,header:()=>(0,t.jsx)(b.Checkbox,{indeterminate:a,checked:r,onChange:e=>s(e.target.checked),onClick:e=>e.stopPropagation()}),cell:({row:s})=>(0,t.jsx)(b.Checkbox,{checked:l(s.original),onChange:t=>e(s.original,t.target.checked),onClick:e=>e.stopPropagation()})},...i]}return i};var ei=e.i(152990),ed=e.i(682830),eo=e.i(269200),ec=e.i(427612),eu=e.i(64848),em=e.i(942232),eh=e.i(496020),ex=e.i(977572),eg=e.i(206929),ef=e.i(94629),ep=e.i(360820),eb=e.i(871943),ej=e.i(981339),ev=e.i(530212),ey=e.i(118366),e_=e.i(678784);function eS({userId:e,onClose:o,accessToken:c,userRole:u,onDelete:m,possibleUIRoles:h,initialTab:x=0,startInEditMode:g=!1}){let[f,p]=(0,i.useState)(null),[b,v]=(0,i.useState)([]),[_,S]=(0,i.useState)(!1),[N,w]=(0,i.useState)(!1),[C,I]=(0,i.useState)(!0),[E,B]=(0,i.useState)(g),[F,M]=(0,i.useState)([]),[L,D]=(0,i.useState)(!1),[P,z]=(0,i.useState)(null),[V,G]=(0,i.useState)(null),[W,J]=(0,i.useState)(x),[Q,Z]=(0,i.useState)({}),[Y,et]=(0,i.useState)(!1);i.default.useEffect(()=>{G((0,j.getProxyBaseUrl)())},[]),i.default.useEffect(()=>{console.log(`userId: ${e}, userRole: ${u}, accessToken: ${c}`),(async()=>{try{if(!c)return;let t=await (0,j.userGetInfoV2)(c,e);if(p(t),t.teams&&t.teams.length>0)try{let e=t.teams.map(async e=>{try{let t=await (0,j.teamInfoCall)(c,e);return{team_id:e,team_alias:t?.team_alias||null}}catch{return{team_id:e,team_alias:null}}}),s=await Promise.all(e);v(s)}catch{v(t.teams.map(e=>({team_id:e,team_alias:null})))}let s=(await (0,j.modelAvailableCall)(c,e,u||"")).data.map(e=>e.id);M(s)}catch(e){console.error("Error fetching user data:",e),R.default.fromBackend("Failed to fetch user data")}finally{I(!1)}})()},[c,e,u]);let es=async()=>{if(!c)return void R.default.fromBackend("Access token not found");try{R.default.success("Generating password reset link...");let t=await (0,j.invitationCreateCall)(c,e);z(t),D(!0)}catch(e){R.default.fromBackend("Failed to generate password reset link")}},er=async()=>{try{if(!c)return;w(!0),await (0,j.userDeleteCall)(c,[e]),R.default.success("User deleted successfully"),m&&m(),o()}catch(e){console.error("Error deleting user:",e),R.default.fromBackend("Failed to delete user")}finally{S(!1),w(!1)}},en=async e=>{try{if(!c||!f)return;await (0,j.userUpdateUserCall)(c,e,null),p({...f,user_email:e.user_email??f.user_email,user_alias:e.user_alias??f.user_alias,models:e.models??f.models,max_budget:e.max_budget??f.max_budget,budget_duration:e.budget_duration??f.budget_duration,metadata:e.metadata??f.metadata}),R.default.success("User updated successfully"),B(!1)}catch(e){console.error("Error updating user:",e),R.default.fromBackend("Failed to update user")}};if(C)return(0,t.jsxs)("div",{className:"p-4",children:[(0,t.jsx)(y.Button,{icon:ev.ArrowLeftIcon,variant:"light",onClick:o,className:"mb-4",children:"Back to Users"}),(0,t.jsx)(H.Text,{children:"Loading user data..."})]});if(!f)return(0,t.jsxs)("div",{className:"p-4",children:[(0,t.jsx)(y.Button,{icon:ev.ArrowLeftIcon,variant:"light",onClick:o,className:"mb-4",children:"Back to Users"}),(0,t.jsx)(H.Text,{children:"User not found"})]});let ei=async(e,t)=>{await (0,O.copyToClipboard)(e)&&(Z(e=>({...e,[t]:!0})),setTimeout(()=>{Z(e=>({...e,[t]:!1}))},2e3))},ed={user_id:f.user_id,user_info:{user_email:f.user_email,user_alias:f.user_alias,user_role:f.user_role,models:f.models,max_budget:f.max_budget,budget_duration:f.budget_duration,metadata:f.metadata}};return(0,t.jsxs)("div",{className:"p-4",children:[(0,t.jsxs)("div",{className:"flex justify-between items-center mb-6",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(y.Button,{icon:ev.ArrowLeftIcon,variant:"light",onClick:o,className:"mb-4",children:"Back to Users"}),(0,t.jsx)(q.Title,{children:f.user_email||"User"}),(0,t.jsxs)("div",{className:"flex items-center cursor-pointer",children:[(0,t.jsx)(H.Text,{className:"text-gray-500 font-mono",children:f.user_id}),(0,t.jsx)(d.Button,{type:"text",size:"small",icon:Q["user-id"]?(0,t.jsx)(e_.CheckIcon,{size:12}):(0,t.jsx)(ey.CopyIcon,{size:12}),onClick:()=>ei(f.user_id,"user-id"),className:`left-2 z-10 transition-all duration-200 ${Q["user-id"]?"text-green-600 bg-green-50 border-green-200":"text-gray-500 hover:text-gray-700 hover:bg-gray-100"}`})]})]}),u&&T.rolesWithWriteAccess.includes(u)&&(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,t.jsx)(y.Button,{icon:ea.RefreshIcon,variant:"secondary",onClick:es,className:"flex items-center",children:"Reset Password"}),(0,t.jsx)(y.Button,{icon:el.TrashIcon,variant:"secondary",onClick:()=>S(!0),className:"flex items-center text-red-500 border-red-500 hover:text-red-600 hover:border-red-600",children:"Delete User"})]})]}),(0,t.jsx)($.default,{isOpen:_,title:"Delete User?",message:"Are you sure you want to delete this user? This action cannot be undone.",resourceInformationTitle:"User Information",resourceInformation:[{label:"Email",value:f.user_email},{label:"User ID",value:f.user_id,code:!0},{label:"Global Proxy Role",value:f.user_role&&h?.[f.user_role]?.ui_label||f.user_role||"-"},{label:"Total Spend (USD)",value:null!==f.spend&&void 0!==f.spend?f.spend.toFixed(2):void 0}],onCancel:()=>{S(!1)},onOk:er,confirmLoading:N}),(0,t.jsxs)(l.TabGroup,{defaultIndex:W,onIndexChange:J,children:[(0,t.jsxs)(r.TabList,{className:"mb-4",children:[(0,t.jsx)(s.Tab,{children:"Overview"}),(0,t.jsx)(s.Tab,{children:"Details"})]}),(0,t.jsxs)(n.TabPanels,{children:[(0,t.jsx)(a.TabPanel,{children:(0,t.jsxs)(ee.Grid,{numItems:1,numItemsSm:2,numItemsLg:3,className:"gap-6",children:[(0,t.jsxs)(K.Card,{children:[(0,t.jsx)(H.Text,{children:"Spend"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(q.Title,{children:["$",(0,O.formatNumberWithCommas)(f.spend||0,4)]}),(0,t.jsxs)(H.Text,{children:["of"," ",null!==f.max_budget?`$${(0,O.formatNumberWithCommas)(f.max_budget,4)}`:"Unlimited"]})]})]}),(0,t.jsxs)(K.Card,{children:[(0,t.jsx)(H.Text,{children:"Teams"}),(0,t.jsx)("div",{className:"mt-2",children:b.length>0?(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[b.slice(0,Y?b.length:20).map((e,s)=>(0,t.jsx)(X.Badge,{color:"blue",title:e.team_alias||e.team_id,children:e.team_alias||e.team_id},s)),!Y&&b.length>20&&(0,t.jsxs)(X.Badge,{color:"gray",className:"cursor-pointer hover:bg-gray-200 transition-colors",onClick:()=>et(!0),children:["+",b.length-20," more"]}),Y&&b.length>20&&(0,t.jsx)(X.Badge,{color:"gray",className:"cursor-pointer hover:bg-gray-200 transition-colors",onClick:()=>et(!1),children:"Show Less"})]}):(0,t.jsx)(H.Text,{children:"No teams"})})]}),(0,t.jsxs)(K.Card,{children:[(0,t.jsx)(H.Text,{children:"Personal Models"}),(0,t.jsx)("div",{className:"mt-2",children:f.models?.length&&f.models?.length>0?f.models?.map((e,s)=>(0,t.jsx)(H.Text,{children:e},s)):(0,t.jsx)(H.Text,{children:"All proxy models"})})]})]})}),(0,t.jsx)(a.TabPanel,{children:(0,t.jsxs)(K.Card,{children:[(0,t.jsxs)("div",{className:"flex justify-between items-center mb-4",children:[(0,t.jsx)(q.Title,{children:"User Settings"}),!E&&u&&T.rolesWithWriteAccess.includes(u)&&(0,t.jsx)(y.Button,{onClick:()=>B(!0),children:"Edit Settings"})]}),E&&f?(0,t.jsx)(U,{userData:ed,onCancel:()=>B(!1),onSubmit:en,teams:b,accessToken:c,userID:e,userRole:u,userModels:F,possibleUIRoles:h}):(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"User ID"}),(0,t.jsxs)("div",{className:"flex items-center cursor-pointer",children:[(0,t.jsx)(H.Text,{className:"font-mono",children:f.user_id}),(0,t.jsx)(d.Button,{type:"text",size:"small",icon:Q["user-id"]?(0,t.jsx)(e_.CheckIcon,{size:12}):(0,t.jsx)(ey.CopyIcon,{size:12}),onClick:()=>ei(f.user_id,"user-id"),className:`left-2 z-10 transition-all duration-200 ${Q["user-id"]?"text-green-600 bg-green-50 border-green-200":"text-gray-500 hover:text-gray-700 hover:bg-gray-100"}`})]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Email"}),(0,t.jsx)(H.Text,{children:f.user_email||"Not Set"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"User Alias"}),(0,t.jsx)(H.Text,{children:f.user_alias||"Not Set"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Global Proxy Role"}),(0,t.jsx)(H.Text,{children:f.user_role||"Not Set"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Created"}),(0,t.jsx)(H.Text,{children:f.created_at?new Date(f.created_at).toLocaleString():"Unknown"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Last Updated"}),(0,t.jsx)(H.Text,{children:f.updated_at?new Date(f.updated_at).toLocaleString():"Unknown"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Teams"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:b.length>0?(0,t.jsxs)(t.Fragment,{children:[b.slice(0,Y?b.length:20).map((e,s)=>(0,t.jsx)("span",{className:"px-2 py-1 bg-blue-100 rounded text-xs",title:e.team_alias||e.team_id,children:e.team_alias||e.team_id},s)),!Y&&b.length>20&&(0,t.jsxs)("span",{className:"px-2 py-1 bg-gray-100 rounded text-xs cursor-pointer hover:bg-gray-200 transition-colors",onClick:()=>et(!0),children:["+",b.length-20," more"]}),Y&&b.length>20&&(0,t.jsx)("span",{className:"px-2 py-1 bg-gray-100 rounded text-xs cursor-pointer hover:bg-gray-200 transition-colors",onClick:()=>et(!1),children:"Show Less"})]}):(0,t.jsx)(H.Text,{children:"No teams"})})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Personal Models"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:f.models?.length&&f.models?.length>0?f.models?.map((e,s)=>(0,t.jsx)("span",{className:"px-2 py-1 bg-blue-100 rounded text-xs",children:e},s)):(0,t.jsx)(H.Text,{children:"All proxy models"})})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Max Budget"}),(0,t.jsx)(H.Text,{children:null!==f.max_budget&&void 0!==f.max_budget?`$${(0,O.formatNumberWithCommas)(f.max_budget,4)}`:"Unlimited"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Budget Reset"}),(0,t.jsx)(H.Text,{children:(0,k.getBudgetDurationLabel)(f.budget_duration??null)})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(H.Text,{className:"font-medium",children:"Metadata"}),(0,t.jsx)("pre",{className:"bg-gray-100 p-2 rounded text-xs overflow-auto mt-1",children:JSON.stringify(f.metadata||{},null,2)})]})]})]})})]})]}),(0,t.jsx)(A.default,{isInvitationLinkModalVisible:L,setIsInvitationLinkModalVisible:D,baseUrl:V||"",invitationLinkData:P,modalType:"resetPassword"})]})}var eN=e.i(655913),ew=e.i(38419),eC=e.i(78334),eT=e.i(555436),ek=e.i(284614);let eI=(0,e.i(475254).default)("circle-user-round",[["path",{d:"M18 20a6 6 0 0 0-12 0",key:"1qehca"}],["circle",{cx:"12",cy:"10",r:"4",key:"1h16sb"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]]);function eE({data:e=[],columns:s,isLoading:l=!1,onSortChange:r,currentSort:a,accessToken:n,userRole:d,possibleUIRoles:o,handleEdit:c,handleDelete:u,handleResetPassword:m,selectedUsers:h=[],onSelectionChange:x,enableSelection:g=!1,filters:f,updateFilters:p,initialFilters:b,teams:j,userListResponse:v,currentPage:y,handlePageChange:S}){let[N,w]=i.default.useState([{id:a?.sortBy||"created_at",desc:a?.sortOrder==="desc"}]),[C,T]=i.default.useState(null),[k,I]=i.default.useState(!1),[E,U]=i.default.useState(!1),R=(e,t=!1)=>{T(e),I(t)},B=(e,t)=>{x&&(t?x([...h,e]):x(h.filter(t=>t.user_id!==e.user_id)))},F=t=>{x&&(t?x(e):x([]))},M=e=>h.some(t=>t.user_id===e.user_id),L=e.length>0&&h.length===e.length,D=h.length>0&&h.lengtho?en(o,c,u,m,R,g?{selectedUsers:h,onSelectUser:B,onSelectAll:F,isUserSelected:M,isAllSelected:L,isIndeterminate:D}:void 0):s,[o,c,u,m,R,s,g,h,L,D]),O=(0,ei.useReactTable)({data:e,columns:A,state:{sorting:N},onSortingChange:e=>{let t="function"==typeof e?e(N):e;if(w(t),t&&Array.isArray(t)&&t.length>0&&t[0]){let e=t[0];if(e.id){let t=e.id,s=e.desc?"desc":"asc";r?.(t,s)}}else r?.("created_at","desc")},getCoreRowModel:(0,ed.getCoreRowModel)(),manualSorting:!0,enableSorting:!0});return(i.default.useEffect(()=>{a&&w([{id:a.sortBy,desc:"desc"===a.sortOrder}])},[a]),C)?(0,t.jsx)(eS,{userId:C,onClose:()=>{T(null),I(!1)},accessToken:n,userRole:d,possibleUIRoles:o,initialTab:+!!k,startInEditMode:k}):(0,t.jsxs)("div",{className:"bg-white rounded-lg shadow",children:[(0,t.jsx)("div",{className:"border-b px-6 py-4",children:(0,t.jsxs)("div",{className:"flex flex-col space-y-4",children:[(0,t.jsxs)("div",{className:"flex flex-wrap items-center gap-3",children:[(0,t.jsx)(eN.FilterInput,{placeholder:"Search by email...",value:f.email,onChange:e=>p({email:e}),icon:eT.Search}),(0,t.jsx)(ew.FiltersButton,{onClick:()=>U(!E),active:E,hasActiveFilters:!!(f.user_id||f.user_role||f.team)}),(0,t.jsx)(eC.ResetFiltersButton,{onClick:()=>{p(b)}})]}),E&&(0,t.jsxs)("div",{className:"flex flex-wrap items-center gap-3 mt-3",children:[(0,t.jsx)(eN.FilterInput,{placeholder:"Filter by User ID",value:f.user_id,onChange:e=>p({user_id:e}),icon:ek.User}),(0,t.jsx)(eN.FilterInput,{placeholder:"Filter by SSO ID",value:f.sso_user_id,onChange:e=>p({sso_user_id:e}),icon:eI}),(0,t.jsx)("div",{className:"w-64",children:(0,t.jsx)(eg.Select,{value:f.user_role,onValueChange:e=>p({user_role:e}),placeholder:"Select Role",children:o&&Object.entries(o).map(([e,s])=>(0,t.jsx)(_.SelectItem,{value:e,children:s.ui_label},e))})}),(0,t.jsx)("div",{className:"w-64",children:(0,t.jsx)(eg.Select,{value:f.team,onValueChange:e=>p({team:e}),placeholder:"Select Team",children:j?.map(e=>(0,t.jsx)(_.SelectItem,{value:e.team_id,children:e.team_alias||e.team_id},e.team_id))})})]}),(0,t.jsxs)("div",{className:"flex justify-between items-center",children:[l?(0,t.jsx)(ej.Skeleton.Input,{active:!0,style:{width:192,height:20}}):(0,t.jsxs)("span",{className:"text-sm text-gray-700",children:["Showing"," ",v&&v.users&&v.users.length>0?(v.page-1)*v.page_size+1:0," ","-"," ",v&&v.users?Math.min(v.page*v.page_size,v.total):0," ","of ",v?v.total:0," results"]}),(0,t.jsx)("div",{className:"flex space-x-2",children:l?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(ej.Skeleton.Button,{active:!0,size:"small",style:{width:80,height:30}}),(0,t.jsx)(ej.Skeleton.Button,{active:!0,size:"small",style:{width:60,height:30}})]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("button",{onClick:()=>S(y-1),disabled:1===y,className:`px-3 py-1 text-sm border rounded-md ${1===y?"bg-gray-100 text-gray-400 cursor-not-allowed":"hover:bg-gray-50"}`,children:"Previous"}),(0,t.jsx)("button",{onClick:()=>S(y+1),disabled:!v||y>=v.total_pages,className:`px-3 py-1 text-sm border rounded-md ${!v||y>=v.total_pages?"bg-gray-100 text-gray-400 cursor-not-allowed":"hover:bg-gray-50"}`,children:"Next"})]})})]})]})}),(0,t.jsx)("div",{className:"overflow-auto",children:(0,t.jsx)("div",{className:"rounded-lg custom-border relative",children:(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)(eo.Table,{className:"[&_td]:py-0.5 [&_th]:py-1",children:[(0,t.jsx)(ec.TableHead,{children:O.getHeaderGroups().map(e=>(0,t.jsx)(eh.TableRow,{children:e.headers.map(e=>(0,t.jsx)(eu.TableHeaderCell,{className:`py-1 h-8 ${"actions"===e.id?"sticky right-0 bg-white shadow-[-4px_0_8px_-6px_rgba(0,0,0,0.1)]":""} ${e.column.getCanSort()?"cursor-pointer hover:bg-gray-50":""}`,onClick:e.column.getToggleSortingHandler(),children:(0,t.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,t.jsx)("div",{className:"flex items-center",children:e.isPlaceholder?null:(0,ei.flexRender)(e.column.columnDef.header,e.getContext())}),"actions"!==e.id&&e.column.getCanSort()&&(0,t.jsx)("div",{className:"w-4",children:e.column.getIsSorted()?({asc:(0,t.jsx)(ep.ChevronUpIcon,{className:"h-4 w-4 text-blue-500"}),desc:(0,t.jsx)(eb.ChevronDownIcon,{className:"h-4 w-4 text-blue-500"})})[e.column.getIsSorted()]:(0,t.jsx)(ef.SwitchVerticalIcon,{className:"h-4 w-4 text-gray-400"})})]})},e.id))},e.id))}),(0,t.jsx)(em.TableBody,{children:l?(0,t.jsx)(eh.TableRow,{children:(0,t.jsx)(ex.TableCell,{colSpan:A.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"🚅 Loading users..."})})})}):e.length>0?O.getRowModel().rows.map(e=>(0,t.jsx)(eh.TableRow,{className:"h-8",children:e.getVisibleCells().map(e=>(0,t.jsx)(ex.TableCell,{className:`py-0.5 max-h-8 overflow-hidden text-ellipsis whitespace-nowrap ${"actions"===e.column.id?"sticky right-0 bg-white shadow-[-4px_0_8px_-6px_rgba(0,0,0,0.1)]":""}`,onClick:()=>{"user_id"===e.column.id&&R(e.getValue(),!1)},style:{cursor:"user_id"===e.column.id?"pointer":"default",color:"user_id"===e.column.id?"#3b82f6":"inherit"},children:(0,ei.flexRender)(e.column.columnDef.cell,e.getContext())},e.id))},e.id)):(0,t.jsx)(eh.TableRow,{children:(0,t.jsx)(ex.TableCell,{colSpan:A.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"No users found"})})})})})]})})})})]})}let{Text:eU,Title:eR}=c.Typography,eB={email:"",user_id:"",user_role:"",sso_user_id:"",team:"",model:"",min_spend:null,max_spend:null,sort_by:"created_at",sort_order:"desc"};e.s(["default",0,({accessToken:e,token:o,userRole:c,userID:u,teams:m,orgAdminOrgIds:h})=>{let x=!!c&&(0,T.isProxyAdminRole)(c),g=(0,V.useQueryClient)(),[f,p]=(0,i.useState)(1),[b,v]=(0,i.useState)(!1),[y,_]=(0,i.useState)(null),[S,N]=(0,i.useState)(!1),[w,C]=(0,i.useState)(!1),[k,I]=(0,i.useState)(null),[E,U]=(0,i.useState)("users"),[B,F]=(0,i.useState)(eB),[K,q,H]=(0,P.useDebouncedState)(B,{wait:300}),[G,W]=(0,i.useState)(!1),[J,Q]=(0,i.useState)(null),[Z,X]=(0,i.useState)(null),[ee,et]=(0,i.useState)([]),[es,el]=(0,i.useState)(!1),[er,ea]=(0,i.useState)(!1),[ei,ed]=(0,i.useState)([]),eo=e=>{I(e),N(!0)};(0,i.useEffect)(()=>()=>{H.cancel()},[H]),(0,i.useEffect)(()=>{X((0,j.getProxyBaseUrl)())},[]),(0,i.useEffect)(()=>{(async()=>{try{if(!u||!c||!e)return;let t=(await (0,j.modelAvailableCall)(e,u,c)).data.map(e=>e.id);console.log("available_model_names:",t),ed(t)}catch(e){console.error("Error fetching user models:",e)}})()},[e,u,c]);let ec=e=>{F(t=>{let s={...t,...e};return q(s),s})},eu=(e,t)=>{ec({sort_by:e,sort_order:t})},em=async t=>{if(!e)return void R.default.fromBackend("Access token not found");try{R.default.success("Generating password reset link...");let s=await (0,j.invitationCreateCall)(e,t);Q(s),W(!0)}catch(e){R.default.fromBackend("Failed to generate password reset link")}},eh=async()=>{if(k&&e)try{C(!0),await (0,j.userDeleteCall)(e,[k.user_id]),g.setQueriesData({queryKey:["userList"]},e=>{if(void 0===e)return e;let t=e.users.filter(e=>e.user_id!==k.user_id);return{...e,users:t}}),R.default.success("User deleted successfully")}catch(e){console.error("Error deleting user:",e),R.default.fromBackend("Failed to delete user")}finally{N(!1),I(null),C(!1)}},ex=async()=>{_(null),v(!1)},eg=async t=>{if(console.log("inside handleEditSubmit:",t),e&&o&&c&&u){try{let s=await (0,j.userUpdateUserCall)(e,t,null);g.setQueriesData({queryKey:["userList"]},e=>{if(void 0===e)return e;let t=e.users.map(e=>e.user_id===s.data.user_id?(0,O.updateExistingKeys)(e,s.data):e);return{...e,users:t}}),R.default.success(`User ${t.user_id} updated successfully`)}catch(e){console.error("There was an error updating the user",e)}_(null),v(!1)}},ef=async e=>{p(e)},ep=e=>{et(e)},eb=(0,z.useQuery)({queryKey:["userList",{debouncedFilter:K,currentPage:f,orgAdminOrgIds:h}],queryFn:async()=>{if(!e)throw Error("Access token required");return await (0,j.userListCall)(e,K.user_id?[K.user_id]:null,f,25,K.email||null,K.user_role||null,K.team||null,K.sso_user_id||null,K.sort_by,K.sort_order,h?h.map(e=>e.organization_id):null)},enabled:!!(e&&o&&c&&u),placeholderData:e=>e}),ev=eb.data,ey=(0,z.useQuery)({queryKey:["userRoles"],initialData:()=>({}),queryFn:async()=>{if(!e)throw Error("Access token required");return await (0,j.getPossibleUserRoles)(e)},enabled:!!(e&&o&&c&&u)}).data,e_=en(ey,e=>{_(e),v(!0)},eo,em,()=>{});return(0,t.jsxs)("div",{className:"w-full p-8 overflow-hidden",children:[(0,t.jsx)("div",{className:"flex items-center justify-between mb-4",children:(0,t.jsx)("div",{className:"flex space-x-3",children:eb.isLoading?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(ej.Skeleton.Button,{active:!0,size:"default",shape:"default",style:{width:110,height:36}}),(0,t.jsx)(ej.Skeleton.Button,{active:!0,size:"default",shape:"default",style:{width:145,height:36}}),(0,t.jsx)(ej.Skeleton.Button,{active:!0,size:"default",shape:"default",style:{width:110,height:36}})]}):u&&e?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(L.CreateUserButton,{userID:u,accessToken:e,teams:m,possibleUIRoles:ey}),x&&(0,t.jsx)(d.Button,{onClick:()=>{ea(!er),et([])},type:er?"primary":"default",className:"flex items-center",children:er?"Cancel Selection":"Select Users"}),x&&er&&(0,t.jsxs)(d.Button,{type:"primary",onClick:()=>{0===ee.length?R.default.fromBackend("Please select users to edit"):el(!0)},disabled:0===ee.length,className:"flex items-center",children:["Bulk Edit (",ee.length," selected)"]})]}):null})}),x?(0,t.jsxs)(l.TabGroup,{defaultIndex:0,onIndexChange:e=>U(0===e?"users":"settings"),children:[(0,t.jsxs)(r.TabList,{className:"mb-4",children:[(0,t.jsx)(s.Tab,{children:"Users"}),(0,t.jsx)(s.Tab,{children:"Default User Settings"})]}),(0,t.jsxs)(n.TabPanels,{children:[(0,t.jsx)(a.TabPanel,{children:(0,t.jsx)(eE,{data:eb.data?.users||[],columns:e_,isLoading:eb.isLoading,accessToken:e,userRole:c,onSortChange:eu,currentSort:{sortBy:B.sort_by,sortOrder:B.sort_order},possibleUIRoles:ey,handleEdit:e=>{_(e),v(!0)},handleDelete:eo,handleResetPassword:em,enableSelection:er,selectedUsers:ee,onSelectionChange:ep,filters:B,updateFilters:ec,initialFilters:eB,teams:m,userListResponse:ev,currentPage:f,handlePageChange:ef})}),(0,t.jsx)(a.TabPanel,{children:u&&c&&e?(0,t.jsx)(Y,{accessToken:e,possibleUIRoles:ey,userID:u,userRole:c}):(0,t.jsx)("div",{className:"flex justify-center items-center h-64",children:(0,t.jsx)(ej.Skeleton,{active:!0,paragraph:{rows:4}})})})]})]}):(0,t.jsx)(eE,{data:eb.data?.users||[],columns:e_,isLoading:eb.isLoading,accessToken:e,userRole:c,onSortChange:eu,currentSort:{sortBy:B.sort_by,sortOrder:B.sort_order},possibleUIRoles:ey,handleEdit:e=>{_(e),v(!0)},handleDelete:eo,handleResetPassword:em,enableSelection:!1,selectedUsers:[],onSelectionChange:ep,filters:B,updateFilters:ec,initialFilters:eB,teams:m,userListResponse:ev,currentPage:f,handlePageChange:ef}),(0,t.jsx)(D,{visible:b,possibleUIRoles:ey,onCancel:ex,user:y,onSubmit:eg}),(0,t.jsx)($.default,{isOpen:S,title:"Delete User?",message:"Are you sure you want to delete this user? This action cannot be undone.",resourceInformationTitle:"User Information",resourceInformation:[{label:"Email",value:k?.user_email},{label:"User ID",value:k?.user_id,code:!0},{label:"Global Proxy Role",value:k&&ey?.[k.user_role]?.ui_label||k?.user_role||"-"},{label:"Total Spend (USD)",value:k?.spend?.toFixed(2)}],onCancel:()=>{N(!1),I(null)},onOk:eh,confirmLoading:w}),(0,t.jsx)(A.default,{isInvitationLinkModalVisible:G,setIsInvitationLinkModalVisible:W,baseUrl:Z||"",invitationLinkData:J,modalType:"resetPassword"}),(0,t.jsx)(M,{open:es,onCancel:()=>el(!1),selectedUsers:ee,possibleUIRoles:ey,accessToken:e,onSuccess:()=>{g.invalidateQueries({queryKey:["userList"]}),et([]),ea(!1)},teams:m,userRole:c,userModels:ei,allowAllUsers:!!c&&(0,T.isAdminRole)(c)})]})}],910119)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/0b06d056425a991f.js b/litellm/proxy/_experimental/out/_next/static/chunks/2bacff998dbae5da.js similarity index 56% rename from litellm/proxy/_experimental/out/_next/static/chunks/0b06d056425a991f.js rename to litellm/proxy/_experimental/out/_next/static/chunks/2bacff998dbae5da.js index c05203719b..3f1702793c 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/0b06d056425a991f.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/2bacff998dbae5da.js @@ -1,7 +1,7 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,270345,e=>{"use strict";var t=e.i(764205);let r=async(e,r,a,l)=>"Admin"!=a&&"Admin Viewer"!=a?await (0,t.teamListCall)(e,l?.organization_id||null,r):await (0,t.teamListCall)(e,l?.organization_id||null);e.s(["fetchTeams",0,r])},519756,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let a={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"};var l=e.i(9583),n=r.forwardRef(function(e,n){return r.createElement(l.default,(0,t.default)({},e,{ref:n,icon:a}))});e.s(["UploadOutlined",0,n],519756)},981339,e=>{"use strict";var t=e.i(185793);e.s(["Skeleton",()=>t.default])},500330,e=>{"use strict";var t=e.i(727749);function r(e,t){let r=structuredClone(e);for(let[e,a]of Object.entries(t))e in r&&(r[e]=a);return r}let a=(e,t=0,r=!1,a=!0)=>{if(null==e||!Number.isFinite(e)||0===e&&!a)return"-";let l={minimumFractionDigits:t,maximumFractionDigits:t};if(!r)return e.toLocaleString("en-US",l);let n=e<0?"-":"",s=Math.abs(e),o=s,i="";return s>=1e6?(o=s/1e6,i="M"):s>=1e3&&(o=s/1e3,i="K"),`${n}${o.toLocaleString("en-US",l)}${i}`},l=async(e,r="Copied to clipboard")=>{if(!e)return!1;if(!navigator||!navigator.clipboard||!navigator.clipboard.writeText)return n(e,r);try{return await navigator.clipboard.writeText(e),t.default.success(r),!0}catch(t){return console.error("Clipboard API failed: ",t),n(e,r)}},n=(e,r)=>{try{let a=document.createElement("textarea");a.value=e,a.style.position="fixed",a.style.left="-999999px",a.style.top="-999999px",a.setAttribute("readonly",""),document.body.appendChild(a),a.focus(),a.select();let l=document.execCommand("copy");if(document.body.removeChild(a),l)return t.default.success(r),!0;throw Error("execCommand failed")}catch(e){return t.default.fromBackend("Failed to copy to clipboard"),console.error("Failed to copy: ",e),!1}};e.s(["copyToClipboard",0,l,"formatNumberWithCommas",0,a,"getSpendString",0,(e,t=6)=>{if(null==e||!Number.isFinite(e)||0===e)return"-";let r=a(e,t,!1,!1);if(0===Number(r.replace(/,/g,""))){let e=(1/10**t).toFixed(t);return`< $${e}`}return`$${r}`},"updateExistingKeys",()=>r])},743151,(e,t,r)=>{"use strict";function a(e){return(a="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)}Object.defineProperty(r,"__esModule",{value:!0}),r.CopyToClipboard=void 0;var l=o(e.r(271645)),n=o(e.r(844343)),s=["text","onCopy","options","children"];function o(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,a)}return r}function c(e){for(var t=1;t=0||(l[r]=e[r]);return l}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(a=0;a=0)&&Object.prototype.propertyIsEnumerable.call(e,r)&&(l[r]=e[r])}return l}(e,s),a=l.default.Children.only(t);return l.default.cloneElement(a,c(c({},r),{},{onClick:this.onClick}))}}],function(e,t){for(var r=0;r{"use strict";var a=e.r(743151).CopyToClipboard;a.CopyToClipboard=a,t.exports=a},109799,e=>{"use strict";var t=e.i(135214),r=e.i(764205),a=e.i(266027),l=e.i(912598);let n=(0,e.i(243652).createQueryKeys)("organizations");e.s(["useOrganization",0,e=>{let s=(0,l.useQueryClient)(),{accessToken:o}=(0,t.default)();return(0,a.useQuery)({queryKey:n.detail(e),enabled:!!(o&&e),queryFn:async()=>{if(!o||!e)throw Error("Missing auth or teamId");return(0,r.organizationInfoCall)(o,e)},initialData:()=>{if(!e)return;let t=s.getQueryData(n.list({}));return t?.find(t=>t.organization_id===e)}})},"useOrganizations",0,()=>{let{accessToken:e,userId:l,userRole:s}=(0,t.default)();return(0,a.useQuery)({queryKey:n.list({}),queryFn:async()=>await (0,r.organizationListCall)(e),enabled:!!(e&&l&&s)})}])},309426,e=>{"use strict";var t=e.i(290571),r=e.i(444755),a=e.i(673706),l=e.i(271645),n=e.i(46757);let s=(0,a.makeClassName)("Col"),o=l.default.forwardRef((e,a)=>{let o,i,c,d,{numColSpan:u=1,numColSpanSm:m,numColSpanMd:g,numColSpanLg:f,children:p,className:h}=e,x=(0,t.__rest)(e,["numColSpan","numColSpanSm","numColSpanMd","numColSpanLg","children","className"]),b=(e,t)=>e&&Object.keys(t).includes(String(e))?t[e]:"";return l.default.createElement("div",Object.assign({ref:a,className:(0,r.tremorTwMerge)(s("root"),(o=b(u,n.colSpan),i=b(m,n.colSpanSm),c=b(g,n.colSpanMd),d=b(f,n.colSpanLg),(0,r.tremorTwMerge)(o,i,c,d)),h)},x),p)});o.displayName="Col",e.s(["Col",()=>o],309426)},988297,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"}))});e.s(["PlusIcon",0,r],988297)},797672,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"}))});e.s(["PencilIcon",0,r],797672)},992619,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(779241),l=e.i(599724),n=e.i(199133),s=e.i(983561),o=e.i(689020);e.s(["default",0,({accessToken:e,value:i,placeholder:c="Select a Model",onChange:d,disabled:u=!1,style:m,className:g,showLabel:f=!0,labelText:p="Select Model"})=>{let[h,x]=(0,r.useState)(i),[b,y]=(0,r.useState)(!1),[v,w]=(0,r.useState)([]),k=(0,r.useRef)(null);return(0,r.useEffect)(()=>{x(i)},[i]),(0,r.useEffect)(()=>{e&&(async()=>{try{let t=await (0,o.fetchAvailableModels)(e);console.log("Fetched models for selector:",t),t.length>0&&w(t)}catch(e){console.error("Error fetching model info:",e)}})()},[e]),(0,t.jsxs)("div",{children:[f&&(0,t.jsxs)(l.Text,{className:"font-medium block mb-2 text-gray-700 flex items-center",children:[(0,t.jsx)(s.RobotOutlined,{className:"mr-2"})," ",p]}),(0,t.jsx)(n.Select,{value:h,placeholder:c,onChange:e=>{"custom"===e?(y(!0),x(void 0)):(y(!1),x(e),d&&d(e))},options:[...Array.from(new Set(v.map(e=>e.model_group))).map((e,t)=>({value:e,label:e,key:t})),{value:"custom",label:"Enter custom model",key:"custom"}],style:{width:"100%",...m},showSearch:!0,className:`rounded-md ${g||""}`,disabled:u}),b&&(0,t.jsx)(a.TextInput,{className:"mt-2",placeholder:"Enter custom model name",onValueChange:e=>{k.current&&clearTimeout(k.current),k.current=setTimeout(()=>{x(e),d&&d(e)},500)},disabled:u})]})}])},409797,e=>{"use strict";var t=e.i(631171);e.s(["ChevronDownIcon",()=>t.default])},91739,e=>{"use strict";var t=e.i(544195);e.s(["Radio",()=>t.default])},500727,696609,531516,e=>{"use strict";var t=e.i(266027),r=e.i(243652),a=e.i(764205),l=e.i(135214);let n=(0,r.createQueryKeys)("mcpServers");e.s(["useMCPServers",0,e=>{let{accessToken:r}=(0,l.default)();return(0,t.useQuery)({queryKey:n.list(e?{filters:{teamId:e}}:void 0),queryFn:async()=>await (0,a.fetchMCPServers)(r,e),enabled:!!r})}],500727);var s=e.i(843476),o=e.i(271645),i=e.i(536916),c=e.i(599724),d=e.i(409797),u=e.i(246349),u=u;let m=/\b(delete|remove|destroy|purge|drop|erase|unlink)\b/i,g=/\b(create|add|insert|new|post|submit|register|make|generate|write|upload)\b/i,f=/\b(update|edit|modify|change|patch|put|set|rename|move|transform)\b/i,p=/\b(get|read|list|fetch|search|find|query|retrieve|show|view|check|describe|info)\b/i;function h(e,t=""){let r=e.toLowerCase();if(p.test(r))return"read";if(m.test(r))return"delete";if(f.test(r))return"update";if(g.test(r))return"create";if(t){let e=t.toLowerCase();if(p.test(e))return"read";if(m.test(e))return"delete";if(f.test(e))return"update";if(g.test(e))return"create"}return"unknown"}function x(e){let t={read:[],create:[],update:[],delete:[],unknown:[]};for(let r of e)t[h(r.name,r.description)].push(r);return t}let b={read:{label:"Read",description:"Safe operations — fetch, list, search. No side effects.",risk:"low"},create:{label:"Create",description:"Add new resources — insert, upload, register.",risk:"medium"},update:{label:"Update",description:"Modify existing resources — edit, patch, rename.",risk:"medium"},delete:{label:"Delete",description:"Destructive operations — remove, purge, destroy.",risk:"high"},unknown:{label:"Other",description:"Operations that could not be automatically classified.",risk:"unknown"}};e.s(["CRUD_GROUP_META",0,b,"classifyToolOp",()=>h,"groupToolsByCrud",()=>x],696609);let y=["read","create","update","delete","unknown"],v={low:"bg-green-100 text-green-800",medium:"bg-yellow-100 text-yellow-800",high:"bg-red-100 text-red-800 font-semibold",unknown:"bg-gray-100 text-gray-700"},w={read:"border-green-200",create:"border-blue-200",update:"border-yellow-200",delete:"border-red-300",unknown:"border-gray-200"},k={read:"bg-green-50",create:"bg-blue-50",update:"bg-yellow-50",delete:"bg-red-50",unknown:"bg-gray-50"};e.s(["default",0,({tools:e,value:t,onChange:r,readOnly:a=!1,searchFilter:l=""})=>{let[n,m]=(0,o.useState)({read:!1,create:!1,update:!1,delete:!1,unknown:!0}),g=(0,o.useMemo)(()=>x(e),[e]),f=(0,o.useMemo)(()=>new Set(void 0===t?e.map(e=>e.name):t),[t,e]),p=e=>{if(a)return;let t=new Set(f);t.has(e)?t.delete(e):t.add(e),r(Array.from(t))};return 0===e.length?null:(0,s.jsx)("div",{className:"space-y-3",children:y.map(e=>{let t,o=g[e];if(0===o.length)return null;if(l){let e=l.toLowerCase();if(!o.some(t=>t.name.toLowerCase().includes(e)||(t.description??"").toLowerCase().includes(e)))return null}let h=b[e],x=(t=g[e]).length>0&&t.every(e=>f.has(e.name)),y=(e=>{let t=g[e];if(0===t.length)return!1;let r=t.filter(e=>f.has(e.name)).length;return r>0&&r{m(t=>({...t,[e]:!t[e]}))},children:[C?(0,s.jsx)(u.default,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}):(0,s.jsx)(d.ChevronDownIcon,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}),(0,s.jsx)("span",{className:"font-semibold text-gray-900 text-sm",children:h.label}),(0,s.jsx)("span",{className:`text-xs px-2 py-0.5 rounded-full ${v[h.risk]}`,children:"high"===h.risk?"High Risk":"medium"===h.risk?"Medium Risk":"low"===h.risk?"Safe":"Unclassified"}),(0,s.jsxs)("span",{className:"text-xs text-gray-500 ml-1",children:[o.filter(e=>f.has(e.name)).length,"/",o.length," allowed"]})]}),!a&&(0,s.jsxs)("div",{className:"flex items-center gap-2 ml-4",children:[(0,s.jsx)(c.Text,{className:"text-xs text-gray-500",children:x?"All on":y?"Partial":"All off"}),(0,s.jsx)(i.Checkbox,{checked:x,indeterminate:y,onChange:t=>((e,t)=>{if(a)return;let l=new Set(f);for(let r of g[e])t?l.add(r.name):l.delete(r.name);r(Array.from(l))})(e,t.target.checked),onClick:e=>e.stopPropagation()})]})]}),!C&&(0,s.jsx)("div",{className:"px-4 pt-2 pb-1 text-xs text-gray-500 bg-white border-b border-gray-100",children:h.description}),!C&&(0,s.jsx)("div",{className:"bg-white divide-y divide-gray-50",children:o.filter(e=>!l||e.name.toLowerCase().includes(l.toLowerCase())||(e.description??"").toLowerCase().includes(l.toLowerCase())).map(e=>{let t,r=(t=e.name,f.has(t));return(0,s.jsxs)("div",{className:`flex items-start gap-3 px-4 py-2.5 transition-colors hover:bg-gray-50 ${!a?"cursor-pointer":""} ${r?"":"opacity-60"}`,onClick:()=>p(e.name),children:[(0,s.jsx)(i.Checkbox,{checked:r,onChange:()=>p(e.name),disabled:a,onClick:e=>e.stopPropagation()}),(0,s.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,s.jsx)(c.Text,{className:"font-medium text-gray-900 text-sm",children:e.name}),e.description&&(0,s.jsx)(c.Text,{className:"text-xs text-gray-500 mt-0.5 leading-snug",children:e.description})]}),(0,s.jsx)("span",{className:`text-xs px-1.5 py-0.5 rounded flex-shrink-0 ${r?"bg-green-100 text-green-700":"bg-gray-100 text-gray-500"}`,children:r?"on":"off"})]},e.name)})})]},e)})})}],531516)},361653,e=>{"use strict";let t=(0,e.i(475254).default)("circle-alert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);e.s(["default",()=>t])},603908,e=>{"use strict";let t=(0,e.i(475254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);e.s(["default",()=>t])},841947,e=>{"use strict";let t=(0,e.i(475254).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["default",()=>t])},793130,e=>{"use strict";var t=e.i(290571),r=e.i(429427),a=e.i(371330),l=e.i(271645),n=e.i(394487),s=e.i(503269),o=e.i(214520),i=e.i(746725),c=e.i(914189),d=e.i(144279),u=e.i(294316),m=e.i(601893),g=e.i(140721),f=e.i(942803),p=e.i(233538),h=e.i(694421),x=e.i(700020),b=e.i(35889),y=e.i(998348),v=e.i(722678);let w=(0,l.createContext)(null);w.displayName="GroupContext";let k=l.Fragment,C=Object.assign((0,x.forwardRefWithAs)(function(e,t){var k;let C=(0,l.useId)(),j=(0,f.useProvidedId)(),N=(0,m.useDisabled)(),{id:S=j||`headlessui-switch-${C}`,disabled:M=N||!1,checked:T,defaultChecked:O,onChange:E,name:P,value:$,form:_,autoFocus:R=!1,...L}=e,z=(0,l.useContext)(w),[B,D]=(0,l.useState)(null),F=(0,l.useRef)(null),I=(0,u.useSyncRefs)(F,t,null===z?null:z.setSwitch,D),A=(0,o.useDefaultValue)(O),[H,q]=(0,s.useControllable)(T,E,null!=A&&A),V=(0,i.useDisposables)(),[G,K]=(0,l.useState)(!1),X=(0,c.useEvent)(()=>{K(!0),null==q||q(!H),V.nextFrame(()=>{K(!1)})}),W=(0,c.useEvent)(e=>{if((0,p.isDisabledReactIssue7711)(e.currentTarget))return e.preventDefault();e.preventDefault(),X()}),U=(0,c.useEvent)(e=>{e.key===y.Keys.Space?(e.preventDefault(),X()):e.key===y.Keys.Enter&&(0,h.attemptSubmit)(e.currentTarget)}),Y=(0,c.useEvent)(e=>e.preventDefault()),Q=(0,v.useLabelledBy)(),J=(0,b.useDescribedBy)(),{isFocusVisible:Z,focusProps:ee}=(0,r.useFocusRing)({autoFocus:R}),{isHovered:et,hoverProps:er}=(0,a.useHover)({isDisabled:M}),{pressed:ea,pressProps:el}=(0,n.useActivePress)({disabled:M}),en=(0,l.useMemo)(()=>({checked:H,disabled:M,hover:et,focus:Z,active:ea,autofocus:R,changing:G}),[H,et,Z,ea,M,G,R]),es=(0,x.mergeProps)({id:S,ref:I,role:"switch",type:(0,d.useResolveButtonType)(e,B),tabIndex:-1===e.tabIndex?0:null!=(k=e.tabIndex)?k:0,"aria-checked":H,"aria-labelledby":Q,"aria-describedby":J,disabled:M||void 0,autoFocus:R,onClick:W,onKeyUp:U,onKeyPress:Y},ee,er,el),eo=(0,l.useCallback)(()=>{if(void 0!==A)return null==q?void 0:q(A)},[q,A]),ei=(0,x.useRender)();return l.default.createElement(l.default.Fragment,null,null!=P&&l.default.createElement(g.FormFields,{disabled:M,data:{[P]:$||"on"},overrides:{type:"checkbox",checked:H},form:_,onReset:eo}),ei({ourProps:es,theirProps:L,slot:en,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var t;let[r,a]=(0,l.useState)(null),[n,s]=(0,v.useLabels)(),[o,i]=(0,b.useDescriptions)(),c=(0,l.useMemo)(()=>({switch:r,setSwitch:a}),[r,a]),d=(0,x.useRender)();return l.default.createElement(i,{name:"Switch.Description",value:o},l.default.createElement(s,{name:"Switch.Label",value:n,props:{htmlFor:null==(t=c.switch)?void 0:t.id,onClick(e){r&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),r.click(),r.focus({preventScroll:!0}))}}},l.default.createElement(w.Provider,{value:c},d({ourProps:{},theirProps:e,slot:{},defaultTag:k,name:"Switch.Group"}))))},Label:v.Label,Description:b.Description});var j=e.i(888288),N=e.i(95779),S=e.i(444755),M=e.i(673706),T=e.i(829087);let O=(0,M.makeClassName)("Switch"),E=l.default.forwardRef((e,r)=>{let{checked:a,defaultChecked:n=!1,onChange:s,color:o,name:i,error:c,errorMessage:d,disabled:u,required:m,tooltip:g,id:f}=e,p=(0,t.__rest)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),h={bgColor:o?(0,M.getColorClassNames)(o,N.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:o?(0,M.getColorClassNames)(o,N.colorPalette.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[x,b]=(0,j.default)(n,a),[y,v]=(0,l.useState)(!1),{tooltipProps:w,getReferenceProps:k}=(0,T.useTooltip)(300);return l.default.createElement("div",{className:"flex flex-row items-center justify-start"},l.default.createElement(T.default,Object.assign({text:g},w)),l.default.createElement("div",Object.assign({ref:(0,M.mergeRefs)([r,w.refs.setReference]),className:(0,S.tremorTwMerge)(O("root"),"flex flex-row relative h-5")},p,k),l.default.createElement("input",{type:"checkbox",className:(0,S.tremorTwMerge)(O("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:i,required:m,checked:x,onChange:e=>{e.preventDefault()}}),l.default.createElement(C,{checked:x,onChange:e=>{b(e),null==s||s(e)},disabled:u,className:(0,S.tremorTwMerge)(O("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:()=>v(!0),onBlur:()=>v(!1),id:f},l.default.createElement("span",{className:(0,S.tremorTwMerge)(O("sr-only"),"sr-only")},"Switch ",x?"on":"off"),l.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(O("background"),x?h.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.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(O("round"),x?(0,S.tremorTwMerge)(h.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",y?(0,S.tremorTwMerge)("ring-2",h.ringColor):"")}))),c&&d?l.default.createElement("p",{className:(0,S.tremorTwMerge)(O("errorMessage"),"text-sm text-red-500 mt-1 ")},d):null)});E.displayName="Switch",e.s(["Switch",()=>E],793130)},158392,419470,e=>{"use strict";var t=e.i(843476),r=e.i(779241);let a={ttl:3600,lowest_latency_buffer:0},l=({routingStrategyArgs:e})=>{let l={ttl:"Sliding window to look back over when calculating the average latency of a deployment. Default - 1 hour (in seconds).",lowest_latency_buffer:"Shuffle between deployments within this % of the lowest latency. Default - 0 (i.e. always pick lowest latency)."};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Latency-Based Configuration"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Fine-tune latency-based routing behavior"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e||a).map(([e,a])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:e.replace(/_/g," ")}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l[e]||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:"object"==typeof a?JSON.stringify(a,null,2):a?.toString(),className:"font-mono text-sm w-full"})]})},e))})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"})]})},n=({routerSettings:e,routerFieldsMetadata:a})=>(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Reliability & Retries"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure retry logic and failure handling"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e).filter(([e,t])=>"fallbacks"!=e&&"context_window_fallbacks"!=e&&"routing_strategy_args"!=e&&"routing_strategy"!=e&&"enable_tag_filtering"!=e).map(([e,l])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:a[e]?.ui_field_name||e}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:a[e]?.field_description||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:null==l||"null"===l?"":"object"==typeof l?JSON.stringify(l,null,2):l?.toString()||"",placeholder:"—",className:"font-mono text-sm w-full"})]})},e))})]});var s=e.i(199133);let o=({selectedStrategy:e,availableStrategies:r,routingStrategyDescriptions:a,routerFieldsMetadata:l,onStrategyChange:n})=>(0,t.jsxs)("div",{className:"space-y-2 max-w-3xl",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:l.routing_strategy?.ui_field_name||"Routing Strategy"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l.routing_strategy?.field_description||""})]}),(0,t.jsx)("div",{className:"routing-strategy-select max-w-3xl",children:(0,t.jsx)(s.Select,{value:e,onChange:n,style:{width:"100%"},size:"large",children:r.map(e=>(0,t.jsx)(s.Select.Option,{value:e,label:e,children:(0,t.jsxs)("div",{className:"flex flex-col gap-0.5 py-1",children:[(0,t.jsx)("span",{className:"font-mono text-sm font-medium",children:e}),a[e]&&(0,t.jsx)("span",{className:"text-xs text-gray-500 font-normal",children:a[e]})]})},e))})})]});var i=e.i(793130);let c=({enabled:e,routerFieldsMetadata:r,onToggle:a})=>(0,t.jsx)("div",{className:"space-y-3 max-w-3xl",children:(0,t.jsxs)("div",{className:"flex items-start justify-between",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:r.enable_tag_filtering?.ui_field_name||"Enable Tag Filtering"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500 mt-0.5",children:[r.enable_tag_filtering?.field_description||"",r.enable_tag_filtering?.link&&(0,t.jsxs)(t.Fragment,{children:[" ",(0,t.jsx)("a",{href:r.enable_tag_filtering.link,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline",children:"Learn more"})]})]})]}),(0,t.jsx)(i.Switch,{checked:e,onChange:a,className:"ml-4"})]})});e.s(["default",0,({value:e,onChange:r,routerFieldsMetadata:a,availableRoutingStrategies:s,routingStrategyDescriptions:i})=>(0,t.jsxs)("div",{className:"w-full space-y-8 py-2",children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Routing Settings"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure how requests are routed to deployments"})]}),s.length>0&&(0,t.jsx)(o,{selectedStrategy:e.selectedStrategy||e.routerSettings.routing_strategy||null,availableStrategies:s,routingStrategyDescriptions:i,routerFieldsMetadata:a,onStrategyChange:t=>{r({...e,selectedStrategy:t})}}),(0,t.jsx)(c,{enabled:e.enableTagFiltering,routerFieldsMetadata:a,onToggle:t=>{r({...e,enableTagFiltering:t})}})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),"latency-based-routing"===e.selectedStrategy&&(0,t.jsx)(l,{routingStrategyArgs:e.routerSettings.routing_strategy_args}),(0,t.jsx)(n,{routerSettings:e.routerSettings,routerFieldsMetadata:a})]})],158392);var d=e.i(994388),u=e.i(998573),m=e.i(653496),g=e.i(107233),f=e.i(271645),p=e.i(592968),h=e.i(361653),h=h;let x=(0,e.i(475254).default)("arrow-down",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var b=e.i(37727);function y({group:e,onChange:r,availableModels:a,maxFallbacks:l}){let n=a.filter(t=>t!==e.primaryModel),o=e.fallbackModels.length{let a=[...e.fallbackModels];a.includes(t)&&(a=a.filter(e=>e!==t)),r({...e,primaryModel:t,fallbackModels:a})},showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase()),options:a.map(e=>({label:e,value:e}))}),!e.primaryModel&&(0,t.jsxs)("div",{className:"mt-2 flex items-center gap-2 text-amber-600 text-xs bg-amber-50 p-2 rounded",children:[(0,t.jsx)(h.default,{className:"w-4 h-4"}),(0,t.jsx)("span",{children:"Select a model to begin configuring fallbacks"})]})]}),(0,t.jsx)("div",{className:"flex items-center justify-center -my-4 z-10",children:(0,t.jsxs)("div",{className:"bg-indigo-50 text-indigo-500 px-4 py-1 rounded-full text-xs font-bold border border-indigo-100 flex items-center gap-2 shadow-sm",children:[(0,t.jsx)(x,{className:"w-4 h-4"}),"IF FAILS, TRY..."]})}),(0,t.jsxs)("div",{className:`transition-opacity duration-300 ${!e.primaryModel?"opacity-50 pointer-events-none":"opacity-100"}`,children:[(0,t.jsxs)("label",{className:"block text-sm font-semibold text-gray-700 mb-2",children:["Fallback Chain ",(0,t.jsx)("span",{className:"text-red-500",children:"*"}),(0,t.jsxs)("span",{className:"text-xs text-gray-500 font-normal ml-2",children:["(Max ",l," fallbacks at a time)"]})]}),(0,t.jsxs)("div",{className:"bg-gray-50 rounded-xl p-4 border border-gray-200",children:[(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(s.Select,{mode:"multiple",className:"w-full",size:"large",placeholder:o?"Select fallback models to add...":`Maximum ${l} fallbacks reached`,value:e.fallbackModels,onChange:t=>{let a=t.slice(0,l);r({...e,fallbackModels:a})},disabled:!e.primaryModel,options:n.map(e=>({label:e,value:e})),optionRender:(r,a)=>{let l=e.fallbackModels.includes(r.value),n=l?e.fallbackModels.indexOf(r.value)+1:null;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[l&&null!==n&&(0,t.jsx)("span",{className:"flex items-center justify-center w-5 h-5 rounded bg-indigo-100 text-indigo-600 text-xs font-bold",children:n}),(0,t.jsx)("span",{children:r.label})]})},maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(p.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})}),showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase())}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1 ml-1",children:o?`Search and select multiple models. Selected models will appear below in order. (${e.fallbackModels.length}/${l} used)`:`Maximum ${l} fallbacks reached. Remove some to add more.`})]}),(0,t.jsx)("div",{className:"space-y-2 min-h-[100px]",children:0===e.fallbackModels.length?(0,t.jsxs)("div",{className:"h-32 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)("span",{className:"text-sm",children:"No fallback models selected"}),(0,t.jsx)("span",{className:"text-xs mt-1",children:"Add models from the dropdown above"})]}):e.fallbackModels.map((a,l)=>(0,t.jsxs)("div",{className:"group flex items-center justify-between p-3 bg-white rounded-lg border border-gray-200 hover:border-indigo-300 hover:shadow-sm transition-all",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex items-center justify-center w-6 h-6 rounded bg-gray-100 text-gray-400 group-hover:text-indigo-500 group-hover:bg-indigo-50",children:(0,t.jsx)("span",{className:"text-xs font-bold",children:l+1})}),(0,t.jsx)("div",{children:(0,t.jsx)("span",{className:"font-medium text-gray-800",children:a})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>{let t;return t=e.fallbackModels.filter((e,t)=>t!==l),void r({...e,fallbackModels:t})},className:"opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500 p-1",children:(0,t.jsx)(b.X,{className:"w-4 h-4"})})]},`${a}-${l}`))})]})]})]})}function v({groups:e,onGroupsChange:r,availableModels:a,maxFallbacks:l=10,maxGroups:n=5}){let[s,o]=(0,f.useState)(e.length>0?e[0].id:"1");(0,f.useEffect)(()=>{e.length>0?e.some(e=>e.id===s)||o(e[0].id):o("1")},[e]);let i=()=>{if(e.length>=n)return;let t=Date.now().toString();r([...e,{id:t,primaryModel:null,fallbackModels:[]}]),o(t)},c=t=>{r(e.map(e=>e.id===t.id?t:e))},p=e.map((r,n)=>{let s=r.primaryModel?r.primaryModel:`Group ${n+1}`;return{key:r.id,label:s,closable:e.length>1,children:(0,t.jsx)(y,{group:r,onChange:c,availableModels:a,maxFallbacks:l})}});return 0===e.length?(0,t.jsxs)("div",{className:"text-center py-12 bg-gray-50 rounded-lg border border-dashed border-gray-300",children:[(0,t.jsx)("p",{className:"text-gray-500 mb-4",children:"No fallback groups configured"}),(0,t.jsx)(d.Button,{variant:"primary",onClick:i,icon:()=>(0,t.jsx)(g.Plus,{className:"w-4 h-4"}),children:"Create First Group"})]}):(0,t.jsx)(m.Tabs,{type:"editable-card",activeKey:s,onChange:o,onEdit:(t,a)=>{"add"===a?i():"remove"===a&&e.length>1&&(t=>{if(1===e.length)return u.message.warning("At least one group is required");let a=e.filter(e=>e.id!==t);r(a),s===t&&a.length>0&&o(a[a.length-1].id)})(t)},items:p,className:"fallback-tabs",tabBarStyle:{marginBottom:0},hideAdd:e.length>=n})}e.s(["FallbackSelectionForm",()=>v],419470)},653496,e=>{"use strict";var t=e.i(721369);e.s(["Tabs",()=>t.default])},599724,936325,e=>{"use strict";var t=e.i(95779),r=e.i(444755),a=e.i(673706),l=e.i(271645);let n=l.default.forwardRef((e,n)=>{let{color:s,className:o,children:i}=e;return l.default.createElement("p",{ref:n,className:(0,r.tremorTwMerge)("text-tremor-default",s?(0,a.getColorClassNames)(s,t.colorPalette.text).textColor:(0,r.tremorTwMerge)("text-tremor-content","dark:text-dark-tremor-content"),o)},i)});n.displayName="Text",e.s(["default",()=>n],936325),e.s(["Text",()=>n],599724)},304967,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(480731),l=e.i(95779),n=e.i(444755),s=e.i(673706);let o=(0,s.makeClassName)("Card"),i=r.default.forwardRef((e,i)=>{let{decoration:c="",decorationColor:d,children:u,className:m}=e,g=(0,t.__rest)(e,["decoration","decorationColor","children","className"]);return r.default.createElement("div",Object.assign({ref:i,className:(0,n.tremorTwMerge)(o("root"),"relative w-full text-left ring-1 rounded-tremor-default p-6","bg-tremor-background ring-tremor-ring shadow-tremor-card","dark:bg-dark-tremor-background dark:ring-dark-tremor-ring dark:shadow-dark-tremor-card",d?(0,s.getColorClassNames)(d,l.colorPalette.border).borderColor:"border-tremor-brand dark:border-dark-tremor-brand",(e=>{if(!e)return"";switch(e){case a.HorizontalPositions.Left:return"border-l-4";case a.VerticalPositions.Top:return"border-t-4";case a.HorizontalPositions.Right:return"border-r-4";case a.VerticalPositions.Bottom:return"border-b-4";default:return""}})(c),m)},g),u)});i.displayName="Card",e.s(["Card",()=>i],304967)},994388,e=>{"use strict";var t=e.i(290571),r=e.i(829087),a=e.i(271645);let l=["preEnter","entering","entered","preExit","exiting","exited","unmounted"],n=e=>({_s:e,status:l[e],isEnter:e<3,isMounted:6!==e,isResolved:2===e||e>4}),s=e=>e?6:5,o=(e,t,r,a,l)=>{clearTimeout(a.current);let s=n(e);t(s),r.current=s,l&&l({current:s})};var i=e.i(480731),c=e.i(444755),d=e.i(673706);let u=e=>{var r=(0,t.__rest)(e,[]);return a.default.createElement("svg",Object.assign({},r,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"}),a.default.createElement("path",{fill:"none",d:"M0 0h24v24H0z"}),a.default.createElement("path",{d:"M18.364 5.636L16.95 7.05A7 7 0 1 0 19 12h2a9 9 0 1 1-2.636-6.364z"}))};var m=e.i(95779);let g={xs:{height:"h-4",width:"w-4"},sm:{height:"h-5",width:"w-5"},md:{height:"h-5",width:"w-5"},lg:{height:"h-6",width:"w-6"},xl:{height:"h-6",width:"w-6"}},f=(e,t)=>{switch(e){case"primary":return{textColor:t?(0,d.getColorClassNames)("white").textColor:"text-tremor-brand-inverted dark:text-dark-tremor-brand-inverted",hoverTextColor:t?(0,d.getColorClassNames)("white").textColor:"text-tremor-brand-inverted dark:text-dark-tremor-brand-inverted",bgColor:t?(0,d.getColorClassNames)(t,m.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",hoverBgColor:t?(0,d.getColorClassNames)(t,m.colorPalette.darkBackground).hoverBgColor:"hover:bg-tremor-brand-emphasis dark:hover:bg-dark-tremor-brand-emphasis",borderColor:t?(0,d.getColorClassNames)(t,m.colorPalette.border).borderColor:"border-tremor-brand dark:border-dark-tremor-brand",hoverBorderColor:t?(0,d.getColorClassNames)(t,m.colorPalette.darkBorder).hoverBorderColor:"hover:border-tremor-brand-emphasis dark:hover:border-dark-tremor-brand-emphasis"};case"secondary":return{textColor:t?(0,d.getColorClassNames)(t,m.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",hoverTextColor:t?(0,d.getColorClassNames)(t,m.colorPalette.text).textColor:"hover:text-tremor-brand-emphasis dark:hover:text-dark-tremor-brand-emphasis",bgColor:(0,d.getColorClassNames)("transparent").bgColor,hoverBgColor:t?(0,c.tremorTwMerge)((0,d.getColorClassNames)(t,m.colorPalette.background).hoverBgColor,"hover:bg-opacity-20 dark:hover:bg-opacity-20"):"hover:bg-tremor-brand-faint dark:hover:bg-dark-tremor-brand-faint",borderColor:t?(0,d.getColorClassNames)(t,m.colorPalette.border).borderColor:"border-tremor-brand dark:border-dark-tremor-brand"};case"light":return{textColor:t?(0,d.getColorClassNames)(t,m.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",hoverTextColor:t?(0,d.getColorClassNames)(t,m.colorPalette.darkText).hoverTextColor:"hover:text-tremor-brand-emphasis dark:hover:text-dark-tremor-brand-emphasis",bgColor:(0,d.getColorClassNames)("transparent").bgColor,borderColor:"",hoverBorderColor:""}}},p=(0,d.makeClassName)("Button"),h=({loading:e,iconSize:t,iconPosition:r,Icon:l,needMargin:n,transitionStatus:s})=>{let o=n?r===i.HorizontalPositions.Left?(0,c.tremorTwMerge)("-ml-1","mr-1.5"):(0,c.tremorTwMerge)("-mr-1","ml-1.5"):"",d=(0,c.tremorTwMerge)("w-0 h-0"),m={default:d,entering:d,entered:t,exiting:t,exited:d};return e?a.default.createElement(u,{className:(0,c.tremorTwMerge)(p("icon"),"animate-spin shrink-0",o,m.default,m[s]),style:{transition:"width 150ms"}}):a.default.createElement(l,{className:(0,c.tremorTwMerge)(p("icon"),"shrink-0",t,o)})},x=a.default.forwardRef((e,l)=>{let{icon:u,iconPosition:m=i.HorizontalPositions.Left,size:x=i.Sizes.SM,color:b,variant:y="primary",disabled:v,loading:w=!1,loadingText:k,children:C,tooltip:j,className:N}=e,S=(0,t.__rest)(e,["icon","iconPosition","size","color","variant","disabled","loading","loadingText","children","tooltip","className"]),M=w||v,T=void 0!==u||w,O=w&&k,E=!(!C&&!O),P=(0,c.tremorTwMerge)(g[x].height,g[x].width),$="light"!==y?(0,c.tremorTwMerge)("rounded-tremor-default border","shadow-tremor-input","dark:shadow-dark-tremor-input"):"",_=f(y,b),R=("light"!==y?{xs:{paddingX:"px-2.5",paddingY:"py-1.5",fontSize:"text-xs"},sm:{paddingX:"px-4",paddingY:"py-2",fontSize:"text-sm"},md:{paddingX:"px-4",paddingY:"py-2",fontSize:"text-md"},lg:{paddingX:"px-4",paddingY:"py-2.5",fontSize:"text-lg"},xl:{paddingX:"px-4",paddingY:"py-3",fontSize:"text-xl"}}:{xs:{paddingX:"",paddingY:"",fontSize:"text-xs"},sm:{paddingX:"",paddingY:"",fontSize:"text-sm"},md:{paddingX:"",paddingY:"",fontSize:"text-md"},lg:{paddingX:"",paddingY:"",fontSize:"text-lg"},xl:{paddingX:"",paddingY:"",fontSize:"text-xl"}})[x],{tooltipProps:L,getReferenceProps:z}=(0,r.useTooltip)(300),[B,D]=(({enter:e=!0,exit:t=!0,preEnter:r,preExit:l,timeout:i,initialEntered:c,mountOnEnter:d,unmountOnExit:u,onStateChange:m}={})=>{let[g,f]=(0,a.useState)(()=>n(c?2:s(d))),p=(0,a.useRef)(g),h=(0,a.useRef)(0),[x,b]="object"==typeof i?[i.enter,i.exit]:[i,i],y=(0,a.useCallback)(()=>{let e=((e,t)=>{switch(e){case 1:case 0:return 2;case 4:case 3:return s(t)}})(p.current._s,u);e&&o(e,f,p,h,m)},[m,u]);return[g,(0,a.useCallback)(a=>{let n=e=>{switch(o(e,f,p,h,m),e){case 1:x>=0&&(h.current=((...e)=>setTimeout(...e))(y,x));break;case 4:b>=0&&(h.current=((...e)=>setTimeout(...e))(y,b));break;case 0:case 3:h.current=((...e)=>setTimeout(...e))(()=>{isNaN(document.body.offsetTop)||n(e+1)},0)}},i=p.current.isEnter;"boolean"!=typeof a&&(a=!i),a?i||n(e?+!r:2):i&&n(t?l?3:4:s(u))},[y,m,e,t,r,l,x,b,u]),y]})({timeout:50});return(0,a.useEffect)(()=>{D(w)},[w]),a.default.createElement("button",Object.assign({ref:(0,d.mergeRefs)([l,L.refs.setReference]),className:(0,c.tremorTwMerge)(p("root"),"shrink-0 inline-flex justify-center items-center group font-medium outline-none",$,R.paddingX,R.paddingY,R.fontSize,_.textColor,_.bgColor,_.borderColor,_.hoverBorderColor,M?"opacity-50 cursor-not-allowed":(0,c.tremorTwMerge)(f(y,b).hoverTextColor,f(y,b).hoverBgColor,f(y,b).hoverBorderColor),N),disabled:M},z,S),a.default.createElement(r.default,Object.assign({text:j},L)),T&&m!==i.HorizontalPositions.Right?a.default.createElement(h,{loading:w,iconSize:P,iconPosition:m,Icon:u,transitionStatus:B.status,needMargin:E}):null,O||C?a.default.createElement("span",{className:(0,c.tremorTwMerge)(p("text"),"text-tremor-default whitespace-nowrap")},O?k:C):null,T&&m===i.HorizontalPositions.Right?a.default.createElement(h,{loading:w,iconSize:P,iconPosition:m,Icon:u,transitionStatus:B.status,needMargin:E}):null)});x.displayName="Button",e.s(["Button",()=>x],994388)},629569,e=>{"use strict";var t=e.i(290571),r=e.i(95779),a=e.i(444755),l=e.i(673706),n=e.i(271645);let s=n.default.forwardRef((e,s)=>{let{color:o,children:i,className:c}=e,d=(0,t.__rest)(e,["color","children","className"]);return n.default.createElement("p",Object.assign({ref:s,className:(0,a.tremorTwMerge)("font-medium text-tremor-title",o?(0,l.getColorClassNames)(o,r.colorPalette.darkText).textColor:"text-tremor-content-strong dark:text-dark-tremor-content-strong",c)},d),i)});s.displayName="Title",e.s(["Title",()=>s],629569)},91874,e=>{"use strict";var t=e.i(931067),r=e.i(209428),a=e.i(211577),l=e.i(392221),n=e.i(703923),s=e.i(343794),o=e.i(914949),i=e.i(271645),c=["prefixCls","className","style","checked","disabled","defaultChecked","type","title","onChange"],d=(0,i.forwardRef)(function(e,d){var u=e.prefixCls,m=void 0===u?"rc-checkbox":u,g=e.className,f=e.style,p=e.checked,h=e.disabled,x=e.defaultChecked,b=e.type,y=void 0===b?"checkbox":b,v=e.title,w=e.onChange,k=(0,n.default)(e,c),C=(0,i.useRef)(null),j=(0,i.useRef)(null),N=(0,o.default)(void 0!==x&&x,{value:p}),S=(0,l.default)(N,2),M=S[0],T=S[1];(0,i.useImperativeHandle)(d,function(){return{focus:function(e){var t;null==(t=C.current)||t.focus(e)},blur:function(){var e;null==(e=C.current)||e.blur()},input:C.current,nativeElement:j.current}});var O=(0,s.default)(m,g,(0,a.default)((0,a.default)({},"".concat(m,"-checked"),M),"".concat(m,"-disabled"),h));return i.createElement("span",{className:O,title:v,style:f,ref:j},i.createElement("input",(0,t.default)({},k,{className:"".concat(m,"-input"),ref:C,onChange:function(t){h||("checked"in e||T(t.target.checked),null==w||w({target:(0,r.default)((0,r.default)({},e),{},{type:y,checked:t.target.checked}),stopPropagation:function(){t.stopPropagation()},preventDefault:function(){t.preventDefault()},nativeEvent:t.nativeEvent}))},disabled:h,checked:!!M,type:y})),i.createElement("span",{className:"".concat(m,"-inner")}))});e.s(["default",0,d])},421512,236836,e=>{"use strict";let t=e.i(271645).default.createContext(null);e.s(["default",0,t],421512),e.i(296059);var r=e.i(915654),a=e.i(183293),l=e.i(246422),n=e.i(838378);function s(e,t){return(e=>{let{checkboxCls:t}=e,l=`${t}-wrapper`;return[{[`${t}-group`]:Object.assign(Object.assign({},(0,a.resetComponent)(e)),{display:"inline-flex",flexWrap:"wrap",columnGap:e.marginXS,[`> ${e.antCls}-row`]:{flex:1}}),[l]:Object.assign(Object.assign({},(0,a.resetComponent)(e)),{display:"inline-flex",alignItems:"baseline",cursor:"pointer","&:after":{display:"inline-block",width:0,overflow:"hidden",content:"'\\a0'"},[`& + ${l}`]:{marginInlineStart:0},[`&${l}-in-form-item`]:{'input[type="checkbox"]':{width:14,height:14}}}),[t]:Object.assign(Object.assign({},(0,a.resetComponent)(e)),{position:"relative",whiteSpace:"nowrap",lineHeight:1,cursor:"pointer",borderRadius:e.borderRadiusSM,alignSelf:"center",[`${t}-input`]:{position:"absolute",inset:0,zIndex:1,cursor:"pointer",opacity:0,margin:0,[`&:focus-visible + ${t}-inner`]:(0,a.genFocusOutline)(e)},[`${t}-inner`]:{boxSizing:"border-box",display:"block",width:e.checkboxSize,height:e.checkboxSize,direction:"ltr",backgroundColor:e.colorBgContainer,border:`${(0,r.unit)(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderRadius:e.borderRadiusSM,borderCollapse:"separate",transition:`all ${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:`${(0,r.unit)(e.lineWidthBold)} solid ${e.colorWhite}`,borderTop:0,borderInlineStart:0,transform:"rotate(45deg) scale(0) translate(-50%,-50%)",opacity:0,content:'""',transition:`all ${e.motionDurationFast} ${e.motionEaseInBack}, opacity ${e.motionDurationFast}`}},"& + span":{paddingInlineStart:e.paddingXS,paddingInlineEnd:e.paddingXS}})},{[` +(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,270345,e=>{"use strict";var t=e.i(764205);let r=async(e,r,a,l)=>"Admin"!=a&&"Admin Viewer"!=a?await (0,t.teamListCall)(e,l?.organization_id||null,r):await (0,t.teamListCall)(e,l?.organization_id||null);e.s(["fetchTeams",0,r])},519756,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let a={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"};var l=e.i(9583),n=r.forwardRef(function(e,n){return r.createElement(l.default,(0,t.default)({},e,{ref:n,icon:a}))});e.s(["UploadOutlined",0,n],519756)},981339,e=>{"use strict";var t=e.i(185793);e.s(["Skeleton",()=>t.default])},500330,e=>{"use strict";var t=e.i(727749);function r(e,t){let r=structuredClone(e);for(let[e,a]of Object.entries(t))e in r&&(r[e]=a);return r}let a=(e,t=0,r=!1,a=!0)=>{if(null==e||!Number.isFinite(e)||0===e&&!a)return"-";let l={minimumFractionDigits:t,maximumFractionDigits:t};if(!r)return e.toLocaleString("en-US",l);let n=e<0?"-":"",o=Math.abs(e),s=o,i="";return o>=1e6?(s=o/1e6,i="M"):o>=1e3&&(s=o/1e3,i="K"),`${n}${s.toLocaleString("en-US",l)}${i}`},l=async(e,r="Copied to clipboard")=>{if(!e)return!1;if(!navigator||!navigator.clipboard||!navigator.clipboard.writeText)return n(e,r);try{return await navigator.clipboard.writeText(e),t.default.success(r),!0}catch(t){return console.error("Clipboard API failed: ",t),n(e,r)}},n=(e,r)=>{try{let a=document.createElement("textarea");a.value=e,a.style.position="fixed",a.style.left="-999999px",a.style.top="-999999px",a.setAttribute("readonly",""),document.body.appendChild(a),a.focus(),a.select();let l=document.execCommand("copy");if(document.body.removeChild(a),l)return t.default.success(r),!0;throw Error("execCommand failed")}catch(e){return t.default.fromBackend("Failed to copy to clipboard"),console.error("Failed to copy: ",e),!1}};e.s(["copyToClipboard",0,l,"formatNumberWithCommas",0,a,"getSpendString",0,(e,t=6)=>{if(null==e||!Number.isFinite(e)||0===e)return"-";let r=a(e,t,!1,!1);if(0===Number(r.replace(/,/g,""))){let e=(1/10**t).toFixed(t);return`< $${e}`}return`$${r}`},"updateExistingKeys",()=>r])},743151,(e,t,r)=>{"use strict";function a(e){return(a="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)}Object.defineProperty(r,"__esModule",{value:!0}),r.CopyToClipboard=void 0;var l=s(e.r(271645)),n=s(e.r(844343)),o=["text","onCopy","options","children"];function s(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,a)}return r}function c(e){for(var t=1;t=0||(l[r]=e[r]);return l}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(a=0;a=0)&&Object.prototype.propertyIsEnumerable.call(e,r)&&(l[r]=e[r])}return l}(e,o),a=l.default.Children.only(t);return l.default.cloneElement(a,c(c({},r),{},{onClick:this.onClick}))}}],function(e,t){for(var r=0;r{"use strict";var a=e.r(743151).CopyToClipboard;a.CopyToClipboard=a,t.exports=a},109799,e=>{"use strict";var t=e.i(135214),r=e.i(764205),a=e.i(266027),l=e.i(912598);let n=(0,e.i(243652).createQueryKeys)("organizations");e.s(["useOrganization",0,e=>{let o=(0,l.useQueryClient)(),{accessToken:s}=(0,t.default)();return(0,a.useQuery)({queryKey:n.detail(e),enabled:!!(s&&e),queryFn:async()=>{if(!s||!e)throw Error("Missing auth or teamId");return(0,r.organizationInfoCall)(s,e)},initialData:()=>{if(!e)return;let t=o.getQueryData(n.list({}));return t?.find(t=>t.organization_id===e)}})},"useOrganizations",0,()=>{let{accessToken:e,userId:l,userRole:o}=(0,t.default)();return(0,a.useQuery)({queryKey:n.list({}),queryFn:async()=>await (0,r.organizationListCall)(e),enabled:!!(e&&l&&o)})}])},309426,e=>{"use strict";var t=e.i(290571),r=e.i(444755),a=e.i(673706),l=e.i(271645),n=e.i(46757);let o=(0,a.makeClassName)("Col"),s=l.default.forwardRef((e,a)=>{let s,i,c,d,{numColSpan:u=1,numColSpanSm:m,numColSpanMd:g,numColSpanLg:p,children:f,className:h}=e,x=(0,t.__rest)(e,["numColSpan","numColSpanSm","numColSpanMd","numColSpanLg","children","className"]),b=(e,t)=>e&&Object.keys(t).includes(String(e))?t[e]:"";return l.default.createElement("div",Object.assign({ref:a,className:(0,r.tremorTwMerge)(o("root"),(s=b(u,n.colSpan),i=b(m,n.colSpanSm),c=b(g,n.colSpanMd),d=b(p,n.colSpanLg),(0,r.tremorTwMerge)(s,i,c,d)),h)},x),f)});s.displayName="Col",e.s(["Col",()=>s],309426)},988297,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"}))});e.s(["PlusIcon",0,r],988297)},797672,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"}))});e.s(["PencilIcon",0,r],797672)},992619,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(779241),l=e.i(599724),n=e.i(199133),o=e.i(983561),s=e.i(689020);e.s(["default",0,({accessToken:e,value:i,placeholder:c="Select a Model",onChange:d,disabled:u=!1,style:m,className:g,showLabel:p=!0,labelText:f="Select Model"})=>{let[h,x]=(0,r.useState)(i),[b,y]=(0,r.useState)(!1),[v,w]=(0,r.useState)([]),k=(0,r.useRef)(null);return(0,r.useEffect)(()=>{x(i)},[i]),(0,r.useEffect)(()=>{e&&(async()=>{try{let t=await (0,s.fetchAvailableModels)(e);console.log("Fetched models for selector:",t),t.length>0&&w(t)}catch(e){console.error("Error fetching model info:",e)}})()},[e]),(0,t.jsxs)("div",{children:[p&&(0,t.jsxs)(l.Text,{className:"font-medium block mb-2 text-gray-700 flex items-center",children:[(0,t.jsx)(o.RobotOutlined,{className:"mr-2"})," ",f]}),(0,t.jsx)(n.Select,{value:h,placeholder:c,onChange:e=>{"custom"===e?(y(!0),x(void 0)):(y(!1),x(e),d&&d(e))},options:[...Array.from(new Set(v.map(e=>e.model_group))).map((e,t)=>({value:e,label:e,key:t})),{value:"custom",label:"Enter custom model",key:"custom"}],style:{width:"100%",...m},showSearch:!0,className:`rounded-md ${g||""}`,disabled:u}),b&&(0,t.jsx)(a.TextInput,{className:"mt-2",placeholder:"Enter custom model name",onValueChange:e=>{k.current&&clearTimeout(k.current),k.current=setTimeout(()=>{x(e),d&&d(e)},500)},disabled:u})]})}])},409797,e=>{"use strict";var t=e.i(631171);e.s(["ChevronDownIcon",()=>t.default])},91739,e=>{"use strict";var t=e.i(544195);e.s(["Radio",()=>t.default])},500727,696609,531516,e=>{"use strict";var t=e.i(266027),r=e.i(243652),a=e.i(764205),l=e.i(135214);let n=(0,r.createQueryKeys)("mcpServers");e.s(["useMCPServers",0,e=>{let{accessToken:r}=(0,l.default)();return(0,t.useQuery)({queryKey:n.list(e?{filters:{teamId:e}}:void 0),queryFn:async()=>await (0,a.fetchMCPServers)(r,e),enabled:!!r})}],500727);var o=e.i(843476),s=e.i(271645),i=e.i(536916),c=e.i(599724),d=e.i(409797),u=e.i(246349),u=u;let m=/\b(delete|remove|destroy|purge|drop|erase|unlink)\b/i,g=/\b(create|add|insert|new|post|submit|register|make|generate|write|upload)\b/i,p=/\b(update|edit|modify|change|patch|put|set|rename|move|transform)\b/i,f=/\b(get|read|list|fetch|search|find|query|retrieve|show|view|check|describe|info)\b/i;function h(e,t=""){let r=e.toLowerCase();if(f.test(r))return"read";if(m.test(r))return"delete";if(p.test(r))return"update";if(g.test(r))return"create";if(t){let e=t.toLowerCase();if(f.test(e))return"read";if(m.test(e))return"delete";if(p.test(e))return"update";if(g.test(e))return"create"}return"unknown"}function x(e){let t={read:[],create:[],update:[],delete:[],unknown:[]};for(let r of e)t[h(r.name,r.description)].push(r);return t}let b={read:{label:"Read",description:"Safe operations — fetch, list, search. No side effects.",risk:"low"},create:{label:"Create",description:"Add new resources — insert, upload, register.",risk:"medium"},update:{label:"Update",description:"Modify existing resources — edit, patch, rename.",risk:"medium"},delete:{label:"Delete",description:"Destructive operations — remove, purge, destroy.",risk:"high"},unknown:{label:"Other",description:"Operations that could not be automatically classified.",risk:"unknown"}};e.s(["CRUD_GROUP_META",0,b,"classifyToolOp",()=>h,"groupToolsByCrud",()=>x],696609);let y=["read","create","update","delete","unknown"],v={low:"bg-green-100 text-green-800",medium:"bg-yellow-100 text-yellow-800",high:"bg-red-100 text-red-800 font-semibold",unknown:"bg-gray-100 text-gray-700"},w={read:"border-green-200",create:"border-blue-200",update:"border-yellow-200",delete:"border-red-300",unknown:"border-gray-200"},k={read:"bg-green-50",create:"bg-blue-50",update:"bg-yellow-50",delete:"bg-red-50",unknown:"bg-gray-50"};e.s(["default",0,({tools:e,value:t,onChange:r,readOnly:a=!1,searchFilter:l=""})=>{let[n,m]=(0,s.useState)({read:!1,create:!1,update:!1,delete:!1,unknown:!0}),g=(0,s.useMemo)(()=>x(e),[e]),p=(0,s.useMemo)(()=>new Set(void 0===t?e.map(e=>e.name):t),[t,e]),f=e=>{if(a)return;let t=new Set(p);t.has(e)?t.delete(e):t.add(e),r(Array.from(t))};return 0===e.length?null:(0,o.jsx)("div",{className:"space-y-3",children:y.map(e=>{let t,s=g[e];if(0===s.length)return null;if(l){let e=l.toLowerCase();if(!s.some(t=>t.name.toLowerCase().includes(e)||(t.description??"").toLowerCase().includes(e)))return null}let h=b[e],x=(t=g[e]).length>0&&t.every(e=>p.has(e.name)),y=(e=>{let t=g[e];if(0===t.length)return!1;let r=t.filter(e=>p.has(e.name)).length;return r>0&&r{m(t=>({...t,[e]:!t[e]}))},children:[C?(0,o.jsx)(u.default,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}):(0,o.jsx)(d.ChevronDownIcon,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}),(0,o.jsx)("span",{className:"font-semibold text-gray-900 text-sm",children:h.label}),(0,o.jsx)("span",{className:`text-xs px-2 py-0.5 rounded-full ${v[h.risk]}`,children:"high"===h.risk?"High Risk":"medium"===h.risk?"Medium Risk":"low"===h.risk?"Safe":"Unclassified"}),(0,o.jsxs)("span",{className:"text-xs text-gray-500 ml-1",children:[s.filter(e=>p.has(e.name)).length,"/",s.length," allowed"]})]}),!a&&(0,o.jsxs)("div",{className:"flex items-center gap-2 ml-4",children:[(0,o.jsx)(c.Text,{className:"text-xs text-gray-500",children:x?"All on":y?"Partial":"All off"}),(0,o.jsx)(i.Checkbox,{checked:x,indeterminate:y,onChange:t=>((e,t)=>{if(a)return;let l=new Set(p);for(let r of g[e])t?l.add(r.name):l.delete(r.name);r(Array.from(l))})(e,t.target.checked),onClick:e=>e.stopPropagation()})]})]}),!C&&(0,o.jsx)("div",{className:"px-4 pt-2 pb-1 text-xs text-gray-500 bg-white border-b border-gray-100",children:h.description}),!C&&(0,o.jsx)("div",{className:"bg-white divide-y divide-gray-50",children:s.filter(e=>!l||e.name.toLowerCase().includes(l.toLowerCase())||(e.description??"").toLowerCase().includes(l.toLowerCase())).map(e=>{let t,r=(t=e.name,p.has(t));return(0,o.jsxs)("div",{className:`flex items-start gap-3 px-4 py-2.5 transition-colors hover:bg-gray-50 ${!a?"cursor-pointer":""} ${r?"":"opacity-60"}`,onClick:()=>f(e.name),children:[(0,o.jsx)(i.Checkbox,{checked:r,onChange:()=>f(e.name),disabled:a,onClick:e=>e.stopPropagation()}),(0,o.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,o.jsx)(c.Text,{className:"font-medium text-gray-900 text-sm",children:e.name}),e.description&&(0,o.jsx)(c.Text,{className:"text-xs text-gray-500 mt-0.5 leading-snug",children:e.description})]}),(0,o.jsx)("span",{className:`text-xs px-1.5 py-0.5 rounded flex-shrink-0 ${r?"bg-green-100 text-green-700":"bg-gray-100 text-gray-500"}`,children:r?"on":"off"})]},e.name)})})]},e)})})}],531516)},361653,e=>{"use strict";let t=(0,e.i(475254).default)("circle-alert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);e.s(["default",()=>t])},603908,e=>{"use strict";let t=(0,e.i(475254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);e.s(["default",()=>t])},841947,e=>{"use strict";let t=(0,e.i(475254).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["default",()=>t])},793130,e=>{"use strict";var t=e.i(290571),r=e.i(429427),a=e.i(371330),l=e.i(271645),n=e.i(394487),o=e.i(503269),s=e.i(214520),i=e.i(746725),c=e.i(914189),d=e.i(144279),u=e.i(294316),m=e.i(601893),g=e.i(140721),p=e.i(942803),f=e.i(233538),h=e.i(694421),x=e.i(700020),b=e.i(35889),y=e.i(998348),v=e.i(722678);let w=(0,l.createContext)(null);w.displayName="GroupContext";let k=l.Fragment,C=Object.assign((0,x.forwardRefWithAs)(function(e,t){var k;let C=(0,l.useId)(),j=(0,p.useProvidedId)(),N=(0,m.useDisabled)(),{id:S=j||`headlessui-switch-${C}`,disabled:M=N||!1,checked:T,defaultChecked:E,onChange:O,name:P,value:$,form:_,autoFocus:R=!1,...L}=e,z=(0,l.useContext)(w),[B,D]=(0,l.useState)(null),F=(0,l.useRef)(null),I=(0,u.useSyncRefs)(F,t,null===z?null:z.setSwitch,D),A=(0,s.useDefaultValue)(E),[H,q]=(0,o.useControllable)(T,O,null!=A&&A),V=(0,i.useDisposables)(),[G,K]=(0,l.useState)(!1),X=(0,c.useEvent)(()=>{K(!0),null==q||q(!H),V.nextFrame(()=>{K(!1)})}),W=(0,c.useEvent)(e=>{if((0,f.isDisabledReactIssue7711)(e.currentTarget))return e.preventDefault();e.preventDefault(),X()}),U=(0,c.useEvent)(e=>{e.key===y.Keys.Space?(e.preventDefault(),X()):e.key===y.Keys.Enter&&(0,h.attemptSubmit)(e.currentTarget)}),Y=(0,c.useEvent)(e=>e.preventDefault()),Q=(0,v.useLabelledBy)(),J=(0,b.useDescribedBy)(),{isFocusVisible:Z,focusProps:ee}=(0,r.useFocusRing)({autoFocus:R}),{isHovered:et,hoverProps:er}=(0,a.useHover)({isDisabled:M}),{pressed:ea,pressProps:el}=(0,n.useActivePress)({disabled:M}),en=(0,l.useMemo)(()=>({checked:H,disabled:M,hover:et,focus:Z,active:ea,autofocus:R,changing:G}),[H,et,Z,ea,M,G,R]),eo=(0,x.mergeProps)({id:S,ref:I,role:"switch",type:(0,d.useResolveButtonType)(e,B),tabIndex:-1===e.tabIndex?0:null!=(k=e.tabIndex)?k:0,"aria-checked":H,"aria-labelledby":Q,"aria-describedby":J,disabled:M||void 0,autoFocus:R,onClick:W,onKeyUp:U,onKeyPress:Y},ee,er,el),es=(0,l.useCallback)(()=>{if(void 0!==A)return null==q?void 0:q(A)},[q,A]),ei=(0,x.useRender)();return l.default.createElement(l.default.Fragment,null,null!=P&&l.default.createElement(g.FormFields,{disabled:M,data:{[P]:$||"on"},overrides:{type:"checkbox",checked:H},form:_,onReset:es}),ei({ourProps:eo,theirProps:L,slot:en,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var t;let[r,a]=(0,l.useState)(null),[n,o]=(0,v.useLabels)(),[s,i]=(0,b.useDescriptions)(),c=(0,l.useMemo)(()=>({switch:r,setSwitch:a}),[r,a]),d=(0,x.useRender)();return l.default.createElement(i,{name:"Switch.Description",value:s},l.default.createElement(o,{name:"Switch.Label",value:n,props:{htmlFor:null==(t=c.switch)?void 0:t.id,onClick(e){r&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),r.click(),r.focus({preventScroll:!0}))}}},l.default.createElement(w.Provider,{value:c},d({ourProps:{},theirProps:e,slot:{},defaultTag:k,name:"Switch.Group"}))))},Label:v.Label,Description:b.Description});var j=e.i(888288),N=e.i(95779),S=e.i(444755),M=e.i(673706),T=e.i(829087);let E=(0,M.makeClassName)("Switch"),O=l.default.forwardRef((e,r)=>{let{checked:a,defaultChecked:n=!1,onChange:o,color:s,name:i,error:c,errorMessage:d,disabled:u,required:m,tooltip:g,id:p}=e,f=(0,t.__rest)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),h={bgColor:s?(0,M.getColorClassNames)(s,N.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:s?(0,M.getColorClassNames)(s,N.colorPalette.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[x,b]=(0,j.default)(n,a),[y,v]=(0,l.useState)(!1),{tooltipProps:w,getReferenceProps:k}=(0,T.useTooltip)(300);return l.default.createElement("div",{className:"flex flex-row items-center justify-start"},l.default.createElement(T.default,Object.assign({text:g},w)),l.default.createElement("div",Object.assign({ref:(0,M.mergeRefs)([r,w.refs.setReference]),className:(0,S.tremorTwMerge)(E("root"),"flex flex-row relative h-5")},f,k),l.default.createElement("input",{type:"checkbox",className:(0,S.tremorTwMerge)(E("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:i,required:m,checked:x,onChange:e=>{e.preventDefault()}}),l.default.createElement(C,{checked:x,onChange:e=>{b(e),null==o||o(e)},disabled:u,className:(0,S.tremorTwMerge)(E("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:()=>v(!0),onBlur:()=>v(!1),id:p},l.default.createElement("span",{className:(0,S.tremorTwMerge)(E("sr-only"),"sr-only")},"Switch ",x?"on":"off"),l.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("background"),x?h.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.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("round"),x?(0,S.tremorTwMerge)(h.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",y?(0,S.tremorTwMerge)("ring-2",h.ringColor):"")}))),c&&d?l.default.createElement("p",{className:(0,S.tremorTwMerge)(E("errorMessage"),"text-sm text-red-500 mt-1 ")},d):null)});O.displayName="Switch",e.s(["Switch",()=>O],793130)},158392,419470,e=>{"use strict";var t=e.i(843476),r=e.i(779241);let a={ttl:3600,lowest_latency_buffer:0},l=({routingStrategyArgs:e})=>{let l={ttl:"Sliding window to look back over when calculating the average latency of a deployment. Default - 1 hour (in seconds).",lowest_latency_buffer:"Shuffle between deployments within this % of the lowest latency. Default - 0 (i.e. always pick lowest latency)."};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Latency-Based Configuration"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Fine-tune latency-based routing behavior"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e||a).map(([e,a])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:e.replace(/_/g," ")}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l[e]||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:"object"==typeof a?JSON.stringify(a,null,2):a?.toString(),className:"font-mono text-sm w-full"})]})},e))})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"})]})},n=({routerSettings:e,routerFieldsMetadata:a})=>(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Reliability & Retries"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure retry logic and failure handling"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e).filter(([e,t])=>"fallbacks"!=e&&"context_window_fallbacks"!=e&&"routing_strategy_args"!=e&&"routing_strategy"!=e&&"enable_tag_filtering"!=e).map(([e,l])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:a[e]?.ui_field_name||e}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:a[e]?.field_description||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:null==l||"null"===l?"":"object"==typeof l?JSON.stringify(l,null,2):l?.toString()||"",placeholder:"—",className:"font-mono text-sm w-full"})]})},e))})]});var o=e.i(199133);let s=({selectedStrategy:e,availableStrategies:r,routingStrategyDescriptions:a,routerFieldsMetadata:l,onStrategyChange:n})=>(0,t.jsxs)("div",{className:"space-y-2 max-w-3xl",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:l.routing_strategy?.ui_field_name||"Routing Strategy"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l.routing_strategy?.field_description||""})]}),(0,t.jsx)("div",{className:"routing-strategy-select max-w-3xl",children:(0,t.jsx)(o.Select,{value:e,onChange:n,style:{width:"100%"},size:"large",children:r.map(e=>(0,t.jsx)(o.Select.Option,{value:e,label:e,children:(0,t.jsxs)("div",{className:"flex flex-col gap-0.5 py-1",children:[(0,t.jsx)("span",{className:"font-mono text-sm font-medium",children:e}),a[e]&&(0,t.jsx)("span",{className:"text-xs text-gray-500 font-normal",children:a[e]})]})},e))})})]});var i=e.i(793130);let c=({enabled:e,routerFieldsMetadata:r,onToggle:a})=>(0,t.jsx)("div",{className:"space-y-3 max-w-3xl",children:(0,t.jsxs)("div",{className:"flex items-start justify-between",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:r.enable_tag_filtering?.ui_field_name||"Enable Tag Filtering"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500 mt-0.5",children:[r.enable_tag_filtering?.field_description||"",r.enable_tag_filtering?.link&&(0,t.jsxs)(t.Fragment,{children:[" ",(0,t.jsx)("a",{href:r.enable_tag_filtering.link,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline",children:"Learn more"})]})]})]}),(0,t.jsx)(i.Switch,{checked:e,onChange:a,className:"ml-4"})]})});e.s(["default",0,({value:e,onChange:r,routerFieldsMetadata:a,availableRoutingStrategies:o,routingStrategyDescriptions:i})=>(0,t.jsxs)("div",{className:"w-full space-y-8 py-2",children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Routing Settings"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure how requests are routed to deployments"})]}),o.length>0&&(0,t.jsx)(s,{selectedStrategy:e.selectedStrategy||e.routerSettings.routing_strategy||null,availableStrategies:o,routingStrategyDescriptions:i,routerFieldsMetadata:a,onStrategyChange:t=>{r({...e,selectedStrategy:t})}}),(0,t.jsx)(c,{enabled:e.enableTagFiltering,routerFieldsMetadata:a,onToggle:t=>{r({...e,enableTagFiltering:t})}})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),"latency-based-routing"===e.selectedStrategy&&(0,t.jsx)(l,{routingStrategyArgs:e.routerSettings.routing_strategy_args}),(0,t.jsx)(n,{routerSettings:e.routerSettings,routerFieldsMetadata:a})]})],158392);var d=e.i(994388),u=e.i(998573),m=e.i(653496),g=e.i(107233),p=e.i(271645),f=e.i(592968),h=e.i(361653),h=h;let x=(0,e.i(475254).default)("arrow-down",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var b=e.i(37727);function y({group:e,onChange:r,availableModels:a,maxFallbacks:l}){let n=a.filter(t=>t!==e.primaryModel),s=e.fallbackModels.length{let a=[...e.fallbackModels];a.includes(t)&&(a=a.filter(e=>e!==t)),r({...e,primaryModel:t,fallbackModels:a})},showSearch:!0,getPopupContainer:e=>e.parentElement||document.body,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase()),options:a.map(e=>({label:e,value:e}))}),!e.primaryModel&&(0,t.jsxs)("div",{className:"mt-2 flex items-center gap-2 text-amber-600 text-xs bg-amber-50 p-2 rounded",children:[(0,t.jsx)(h.default,{className:"w-4 h-4"}),(0,t.jsx)("span",{children:"Select a model to begin configuring fallbacks"})]})]}),(0,t.jsx)("div",{className:"flex items-center justify-center -my-4 z-10",children:(0,t.jsxs)("div",{className:"bg-indigo-50 text-indigo-500 px-4 py-1 rounded-full text-xs font-bold border border-indigo-100 flex items-center gap-2 shadow-sm",children:[(0,t.jsx)(x,{className:"w-4 h-4"}),"IF FAILS, TRY..."]})}),(0,t.jsxs)("div",{className:`transition-opacity duration-300 ${!e.primaryModel?"opacity-50 pointer-events-none":"opacity-100"}`,children:[(0,t.jsxs)("label",{className:"block text-sm font-semibold text-gray-700 mb-2",children:["Fallback Chain ",(0,t.jsx)("span",{className:"text-red-500",children:"*"}),(0,t.jsxs)("span",{className:"text-xs text-gray-500 font-normal ml-2",children:["(Max ",l," fallbacks at a time)"]})]}),(0,t.jsxs)("div",{className:"bg-gray-50 rounded-xl p-4 border border-gray-200",children:[(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(o.Select,{mode:"multiple",className:"w-full",size:"large",placeholder:s?"Select fallback models to add...":`Maximum ${l} fallbacks reached`,value:e.fallbackModels,onChange:t=>{let a=t.slice(0,l);r({...e,fallbackModels:a})},disabled:!e.primaryModel,getPopupContainer:e=>e.parentElement||document.body,options:n.map(e=>({label:e,value:e})),optionRender:(r,a)=>{let l=e.fallbackModels.includes(r.value),n=l?e.fallbackModels.indexOf(r.value)+1:null;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[l&&null!==n&&(0,t.jsx)("span",{className:"flex items-center justify-center w-5 h-5 rounded bg-indigo-100 text-indigo-600 text-xs font-bold",children:n}),(0,t.jsx)("span",{children:r.label})]})},maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(f.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})}),showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase())}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1 ml-1",children:s?`Search and select multiple models. Selected models will appear below in order. (${e.fallbackModels.length}/${l} used)`:`Maximum ${l} fallbacks reached. Remove some to add more.`})]}),(0,t.jsx)("div",{className:"space-y-2 min-h-[100px]",children:0===e.fallbackModels.length?(0,t.jsxs)("div",{className:"h-32 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)("span",{className:"text-sm",children:"No fallback models selected"}),(0,t.jsx)("span",{className:"text-xs mt-1",children:"Add models from the dropdown above"})]}):e.fallbackModels.map((a,l)=>(0,t.jsxs)("div",{className:"group flex items-center justify-between p-3 bg-white rounded-lg border border-gray-200 hover:border-indigo-300 hover:shadow-sm transition-all",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex items-center justify-center w-6 h-6 rounded bg-gray-100 text-gray-400 group-hover:text-indigo-500 group-hover:bg-indigo-50",children:(0,t.jsx)("span",{className:"text-xs font-bold",children:l+1})}),(0,t.jsx)("div",{children:(0,t.jsx)("span",{className:"font-medium text-gray-800",children:a})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>{let t;return t=e.fallbackModels.filter((e,t)=>t!==l),void r({...e,fallbackModels:t})},className:"opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500 p-1",children:(0,t.jsx)(b.X,{className:"w-4 h-4"})})]},`${a}-${l}`))})]})]})]})}function v({groups:e,onGroupsChange:r,availableModels:a,maxFallbacks:l=10,maxGroups:n=5}){let[o,s]=(0,p.useState)(e.length>0?e[0].id:"1");(0,p.useEffect)(()=>{e.length>0?e.some(e=>e.id===o)||s(e[0].id):s("1")},[e]);let i=()=>{if(e.length>=n)return;let t=Date.now().toString();r([...e,{id:t,primaryModel:null,fallbackModels:[]}]),s(t)},c=t=>{r(e.map(e=>e.id===t.id?t:e))},f=e.map((r,n)=>{let o=r.primaryModel?r.primaryModel:`Group ${n+1}`;return{key:r.id,label:o,closable:e.length>1,children:(0,t.jsx)(y,{group:r,onChange:c,availableModels:a,maxFallbacks:l})}});return 0===e.length?(0,t.jsxs)("div",{className:"text-center py-12 bg-gray-50 rounded-lg border border-dashed border-gray-300",children:[(0,t.jsx)("p",{className:"text-gray-500 mb-4",children:"No fallback groups configured"}),(0,t.jsx)(d.Button,{variant:"primary",onClick:i,icon:()=>(0,t.jsx)(g.Plus,{className:"w-4 h-4"}),children:"Create First Group"})]}):(0,t.jsx)(m.Tabs,{type:"editable-card",activeKey:o,onChange:s,onEdit:(t,a)=>{"add"===a?i():"remove"===a&&e.length>1&&(t=>{if(1===e.length)return u.message.warning("At least one group is required");let a=e.filter(e=>e.id!==t);r(a),o===t&&a.length>0&&s(a[a.length-1].id)})(t)},items:f,className:"fallback-tabs",tabBarStyle:{marginBottom:0},hideAdd:e.length>=n})}e.s(["FallbackSelectionForm",()=>v],419470)},653496,e=>{"use strict";var t=e.i(721369);e.s(["Tabs",()=>t.default])},599724,936325,e=>{"use strict";var t=e.i(95779),r=e.i(444755),a=e.i(673706),l=e.i(271645);let n=l.default.forwardRef((e,n)=>{let{color:o,className:s,children:i}=e;return l.default.createElement("p",{ref:n,className:(0,r.tremorTwMerge)("text-tremor-default",o?(0,a.getColorClassNames)(o,t.colorPalette.text).textColor:(0,r.tremorTwMerge)("text-tremor-content","dark:text-dark-tremor-content"),s)},i)});n.displayName="Text",e.s(["default",()=>n],936325),e.s(["Text",()=>n],599724)},994388,e=>{"use strict";var t=e.i(290571),r=e.i(829087),a=e.i(271645);let l=["preEnter","entering","entered","preExit","exiting","exited","unmounted"],n=e=>({_s:e,status:l[e],isEnter:e<3,isMounted:6!==e,isResolved:2===e||e>4}),o=e=>e?6:5,s=(e,t,r,a,l)=>{clearTimeout(a.current);let o=n(e);t(o),r.current=o,l&&l({current:o})};var i=e.i(480731),c=e.i(444755),d=e.i(673706);let u=e=>{var r=(0,t.__rest)(e,[]);return a.default.createElement("svg",Object.assign({},r,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"}),a.default.createElement("path",{fill:"none",d:"M0 0h24v24H0z"}),a.default.createElement("path",{d:"M18.364 5.636L16.95 7.05A7 7 0 1 0 19 12h2a9 9 0 1 1-2.636-6.364z"}))};var m=e.i(95779);let g={xs:{height:"h-4",width:"w-4"},sm:{height:"h-5",width:"w-5"},md:{height:"h-5",width:"w-5"},lg:{height:"h-6",width:"w-6"},xl:{height:"h-6",width:"w-6"}},p=(e,t)=>{switch(e){case"primary":return{textColor:t?(0,d.getColorClassNames)("white").textColor:"text-tremor-brand-inverted dark:text-dark-tremor-brand-inverted",hoverTextColor:t?(0,d.getColorClassNames)("white").textColor:"text-tremor-brand-inverted dark:text-dark-tremor-brand-inverted",bgColor:t?(0,d.getColorClassNames)(t,m.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",hoverBgColor:t?(0,d.getColorClassNames)(t,m.colorPalette.darkBackground).hoverBgColor:"hover:bg-tremor-brand-emphasis dark:hover:bg-dark-tremor-brand-emphasis",borderColor:t?(0,d.getColorClassNames)(t,m.colorPalette.border).borderColor:"border-tremor-brand dark:border-dark-tremor-brand",hoverBorderColor:t?(0,d.getColorClassNames)(t,m.colorPalette.darkBorder).hoverBorderColor:"hover:border-tremor-brand-emphasis dark:hover:border-dark-tremor-brand-emphasis"};case"secondary":return{textColor:t?(0,d.getColorClassNames)(t,m.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",hoverTextColor:t?(0,d.getColorClassNames)(t,m.colorPalette.text).textColor:"hover:text-tremor-brand-emphasis dark:hover:text-dark-tremor-brand-emphasis",bgColor:(0,d.getColorClassNames)("transparent").bgColor,hoverBgColor:t?(0,c.tremorTwMerge)((0,d.getColorClassNames)(t,m.colorPalette.background).hoverBgColor,"hover:bg-opacity-20 dark:hover:bg-opacity-20"):"hover:bg-tremor-brand-faint dark:hover:bg-dark-tremor-brand-faint",borderColor:t?(0,d.getColorClassNames)(t,m.colorPalette.border).borderColor:"border-tremor-brand dark:border-dark-tremor-brand"};case"light":return{textColor:t?(0,d.getColorClassNames)(t,m.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",hoverTextColor:t?(0,d.getColorClassNames)(t,m.colorPalette.darkText).hoverTextColor:"hover:text-tremor-brand-emphasis dark:hover:text-dark-tremor-brand-emphasis",bgColor:(0,d.getColorClassNames)("transparent").bgColor,borderColor:"",hoverBorderColor:""}}},f=(0,d.makeClassName)("Button"),h=({loading:e,iconSize:t,iconPosition:r,Icon:l,needMargin:n,transitionStatus:o})=>{let s=n?r===i.HorizontalPositions.Left?(0,c.tremorTwMerge)("-ml-1","mr-1.5"):(0,c.tremorTwMerge)("-mr-1","ml-1.5"):"",d=(0,c.tremorTwMerge)("w-0 h-0"),m={default:d,entering:d,entered:t,exiting:t,exited:d};return e?a.default.createElement(u,{className:(0,c.tremorTwMerge)(f("icon"),"animate-spin shrink-0",s,m.default,m[o]),style:{transition:"width 150ms"}}):a.default.createElement(l,{className:(0,c.tremorTwMerge)(f("icon"),"shrink-0",t,s)})},x=a.default.forwardRef((e,l)=>{let{icon:u,iconPosition:m=i.HorizontalPositions.Left,size:x=i.Sizes.SM,color:b,variant:y="primary",disabled:v,loading:w=!1,loadingText:k,children:C,tooltip:j,className:N}=e,S=(0,t.__rest)(e,["icon","iconPosition","size","color","variant","disabled","loading","loadingText","children","tooltip","className"]),M=w||v,T=void 0!==u||w,E=w&&k,O=!(!C&&!E),P=(0,c.tremorTwMerge)(g[x].height,g[x].width),$="light"!==y?(0,c.tremorTwMerge)("rounded-tremor-default border","shadow-tremor-input","dark:shadow-dark-tremor-input"):"",_=p(y,b),R=("light"!==y?{xs:{paddingX:"px-2.5",paddingY:"py-1.5",fontSize:"text-xs"},sm:{paddingX:"px-4",paddingY:"py-2",fontSize:"text-sm"},md:{paddingX:"px-4",paddingY:"py-2",fontSize:"text-md"},lg:{paddingX:"px-4",paddingY:"py-2.5",fontSize:"text-lg"},xl:{paddingX:"px-4",paddingY:"py-3",fontSize:"text-xl"}}:{xs:{paddingX:"",paddingY:"",fontSize:"text-xs"},sm:{paddingX:"",paddingY:"",fontSize:"text-sm"},md:{paddingX:"",paddingY:"",fontSize:"text-md"},lg:{paddingX:"",paddingY:"",fontSize:"text-lg"},xl:{paddingX:"",paddingY:"",fontSize:"text-xl"}})[x],{tooltipProps:L,getReferenceProps:z}=(0,r.useTooltip)(300),[B,D]=(({enter:e=!0,exit:t=!0,preEnter:r,preExit:l,timeout:i,initialEntered:c,mountOnEnter:d,unmountOnExit:u,onStateChange:m}={})=>{let[g,p]=(0,a.useState)(()=>n(c?2:o(d))),f=(0,a.useRef)(g),h=(0,a.useRef)(0),[x,b]="object"==typeof i?[i.enter,i.exit]:[i,i],y=(0,a.useCallback)(()=>{let e=((e,t)=>{switch(e){case 1:case 0:return 2;case 4:case 3:return o(t)}})(f.current._s,u);e&&s(e,p,f,h,m)},[m,u]);return[g,(0,a.useCallback)(a=>{let n=e=>{switch(s(e,p,f,h,m),e){case 1:x>=0&&(h.current=((...e)=>setTimeout(...e))(y,x));break;case 4:b>=0&&(h.current=((...e)=>setTimeout(...e))(y,b));break;case 0:case 3:h.current=((...e)=>setTimeout(...e))(()=>{isNaN(document.body.offsetTop)||n(e+1)},0)}},i=f.current.isEnter;"boolean"!=typeof a&&(a=!i),a?i||n(e?+!r:2):i&&n(t?l?3:4:o(u))},[y,m,e,t,r,l,x,b,u]),y]})({timeout:50});return(0,a.useEffect)(()=>{D(w)},[w]),a.default.createElement("button",Object.assign({ref:(0,d.mergeRefs)([l,L.refs.setReference]),className:(0,c.tremorTwMerge)(f("root"),"shrink-0 inline-flex justify-center items-center group font-medium outline-none",$,R.paddingX,R.paddingY,R.fontSize,_.textColor,_.bgColor,_.borderColor,_.hoverBorderColor,M?"opacity-50 cursor-not-allowed":(0,c.tremorTwMerge)(p(y,b).hoverTextColor,p(y,b).hoverBgColor,p(y,b).hoverBorderColor),N),disabled:M},z,S),a.default.createElement(r.default,Object.assign({text:j},L)),T&&m!==i.HorizontalPositions.Right?a.default.createElement(h,{loading:w,iconSize:P,iconPosition:m,Icon:u,transitionStatus:B.status,needMargin:O}):null,E||C?a.default.createElement("span",{className:(0,c.tremorTwMerge)(f("text"),"text-tremor-default whitespace-nowrap")},E?k:C):null,T&&m===i.HorizontalPositions.Right?a.default.createElement(h,{loading:w,iconSize:P,iconPosition:m,Icon:u,transitionStatus:B.status,needMargin:O}):null)});x.displayName="Button",e.s(["Button",()=>x],994388)},304967,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(480731),l=e.i(95779),n=e.i(444755),o=e.i(673706);let s=(0,o.makeClassName)("Card"),i=r.default.forwardRef((e,i)=>{let{decoration:c="",decorationColor:d,children:u,className:m}=e,g=(0,t.__rest)(e,["decoration","decorationColor","children","className"]);return r.default.createElement("div",Object.assign({ref:i,className:(0,n.tremorTwMerge)(s("root"),"relative w-full text-left ring-1 rounded-tremor-default p-6","bg-tremor-background ring-tremor-ring shadow-tremor-card","dark:bg-dark-tremor-background dark:ring-dark-tremor-ring dark:shadow-dark-tremor-card",d?(0,o.getColorClassNames)(d,l.colorPalette.border).borderColor:"border-tremor-brand dark:border-dark-tremor-brand",(e=>{if(!e)return"";switch(e){case a.HorizontalPositions.Left:return"border-l-4";case a.VerticalPositions.Top:return"border-t-4";case a.HorizontalPositions.Right:return"border-r-4";case a.VerticalPositions.Bottom:return"border-b-4";default:return""}})(c),m)},g),u)});i.displayName="Card",e.s(["Card",()=>i],304967)},629569,e=>{"use strict";var t=e.i(290571),r=e.i(95779),a=e.i(444755),l=e.i(673706),n=e.i(271645);let o=n.default.forwardRef((e,o)=>{let{color:s,children:i,className:c}=e,d=(0,t.__rest)(e,["color","children","className"]);return n.default.createElement("p",Object.assign({ref:o,className:(0,a.tremorTwMerge)("font-medium text-tremor-title",s?(0,l.getColorClassNames)(s,r.colorPalette.darkText).textColor:"text-tremor-content-strong dark:text-dark-tremor-content-strong",c)},d),i)});o.displayName="Title",e.s(["Title",()=>o],629569)},91874,e=>{"use strict";var t=e.i(931067),r=e.i(209428),a=e.i(211577),l=e.i(392221),n=e.i(703923),o=e.i(343794),s=e.i(914949),i=e.i(271645),c=["prefixCls","className","style","checked","disabled","defaultChecked","type","title","onChange"],d=(0,i.forwardRef)(function(e,d){var u=e.prefixCls,m=void 0===u?"rc-checkbox":u,g=e.className,p=e.style,f=e.checked,h=e.disabled,x=e.defaultChecked,b=e.type,y=void 0===b?"checkbox":b,v=e.title,w=e.onChange,k=(0,n.default)(e,c),C=(0,i.useRef)(null),j=(0,i.useRef)(null),N=(0,s.default)(void 0!==x&&x,{value:f}),S=(0,l.default)(N,2),M=S[0],T=S[1];(0,i.useImperativeHandle)(d,function(){return{focus:function(e){var t;null==(t=C.current)||t.focus(e)},blur:function(){var e;null==(e=C.current)||e.blur()},input:C.current,nativeElement:j.current}});var E=(0,o.default)(m,g,(0,a.default)((0,a.default)({},"".concat(m,"-checked"),M),"".concat(m,"-disabled"),h));return i.createElement("span",{className:E,title:v,style:p,ref:j},i.createElement("input",(0,t.default)({},k,{className:"".concat(m,"-input"),ref:C,onChange:function(t){h||("checked"in e||T(t.target.checked),null==w||w({target:(0,r.default)((0,r.default)({},e),{},{type:y,checked:t.target.checked}),stopPropagation:function(){t.stopPropagation()},preventDefault:function(){t.preventDefault()},nativeEvent:t.nativeEvent}))},disabled:h,checked:!!M,type:y})),i.createElement("span",{className:"".concat(m,"-inner")}))});e.s(["default",0,d])},421512,236836,e=>{"use strict";let t=e.i(271645).default.createContext(null);e.s(["default",0,t],421512),e.i(296059);var r=e.i(915654),a=e.i(183293),l=e.i(246422),n=e.i(838378);function o(e,t){return(e=>{let{checkboxCls:t}=e,l=`${t}-wrapper`;return[{[`${t}-group`]:Object.assign(Object.assign({},(0,a.resetComponent)(e)),{display:"inline-flex",flexWrap:"wrap",columnGap:e.marginXS,[`> ${e.antCls}-row`]:{flex:1}}),[l]:Object.assign(Object.assign({},(0,a.resetComponent)(e)),{display:"inline-flex",alignItems:"baseline",cursor:"pointer","&:after":{display:"inline-block",width:0,overflow:"hidden",content:"'\\a0'"},[`& + ${l}`]:{marginInlineStart:0},[`&${l}-in-form-item`]:{'input[type="checkbox"]':{width:14,height:14}}}),[t]:Object.assign(Object.assign({},(0,a.resetComponent)(e)),{position:"relative",whiteSpace:"nowrap",lineHeight:1,cursor:"pointer",borderRadius:e.borderRadiusSM,alignSelf:"center",[`${t}-input`]:{position:"absolute",inset:0,zIndex:1,cursor:"pointer",opacity:0,margin:0,[`&:focus-visible + ${t}-inner`]:(0,a.genFocusOutline)(e)},[`${t}-inner`]:{boxSizing:"border-box",display:"block",width:e.checkboxSize,height:e.checkboxSize,direction:"ltr",backgroundColor:e.colorBgContainer,border:`${(0,r.unit)(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderRadius:e.borderRadiusSM,borderCollapse:"separate",transition:`all ${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:`${(0,r.unit)(e.lineWidthBold)} solid ${e.colorWhite}`,borderTop:0,borderInlineStart:0,transform:"rotate(45deg) scale(0) translate(-50%,-50%)",opacity:0,content:'""',transition:`all ${e.motionDurationFast} ${e.motionEaseInBack}, opacity ${e.motionDurationFast}`}},"& + span":{paddingInlineStart:e.paddingXS,paddingInlineEnd:e.paddingXS}})},{[` ${l}:not(${l}-disabled), ${t}:not(${t}-disabled) `]:{[`&:hover ${t}-inner`]:{borderColor:e.colorPrimary}},[`${l}:not(${l}-disabled)`]:{[`&:hover ${t}-checked:not(${t}-disabled) ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"},[`&:hover ${t}-checked:not(${t}-disabled):after`]:{borderColor:e.colorPrimaryHover}}},{[`${t}-checked`]:{[`${t}-inner`]:{backgroundColor:e.colorPrimary,borderColor:e.colorPrimary,"&:after":{opacity:1,transform:"rotate(45deg) scale(1) translate(-50%,-50%)",transition:`all ${e.motionDurationMid} ${e.motionEaseOutBack} ${e.motionDurationFast}`}}},[` ${l}-checked:not(${l}-disabled), ${t}-checked:not(${t}-disabled) - `]:{[`&:hover ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"}}},{[t]:{"&-indeterminate":{"&":{[`${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${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 ${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${e.colorPrimary}`}}}}},{[`${l}-disabled`]:{cursor:"not-allowed"},[`${t}-disabled`]:{[`&, ${t}-input`]:{cursor:"not-allowed",pointerEvents:"none"},[`${t}-inner`]:{background:e.colorBgContainerDisabled,borderColor:e.colorBorder,"&:after":{borderColor:e.colorTextDisabled}},"&:after":{display:"none"},"& + span":{color:e.colorTextDisabled},[`&${t}-indeterminate ${t}-inner::after`]:{background:e.colorTextDisabled}}}]})((0,n.mergeToken)(t,{checkboxCls:`.${e}`,checkboxSize:t.controlInteractiveSize}))}let o=(0,l.genStyleHooks)("Checkbox",(e,{prefixCls:t})=>[s(t,e)]);e.s(["default",0,o,"getStyle",()=>s],236836)},681216,e=>{"use strict";var t=e.i(271645),r=e.i(963188);function a(e){let a=t.default.useRef(null),l=()=>{r.default.cancel(a.current),a.current=null};return[()=>{l(),a.current=(0,r.default)(()=>{a.current=null})},t=>{a.current&&(t.stopPropagation(),l()),null==e||e(t)}]}e.s(["default",()=>a])},374276,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(91874),l=e.i(611935),n=e.i(121872),s=e.i(26905),o=e.i(242064),i=e.i(937328),c=e.i(321883),d=e.i(62139),u=e.i(421512),m=e.i(236836),g=e.i(681216),f=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let p=t.forwardRef((e,p)=>{var h;let{prefixCls:x,className:b,rootClassName:y,children:v,indeterminate:w=!1,style:k,onMouseEnter:C,onMouseLeave:j,skipGroup:N=!1,disabled:S}=e,M=f(e,["prefixCls","className","rootClassName","children","indeterminate","style","onMouseEnter","onMouseLeave","skipGroup","disabled"]),{getPrefixCls:T,direction:O,checkbox:E}=t.useContext(o.ConfigContext),P=t.useContext(u.default),{isFormItemInput:$}=t.useContext(d.FormItemInputContext),_=t.useContext(i.default),R=null!=(h=(null==P?void 0:P.disabled)||S)?h:_,L=t.useRef(M.value),z=t.useRef(null),B=(0,l.composeRef)(p,z);t.useEffect(()=>{null==P||P.registerValue(M.value)},[]),t.useEffect(()=>{if(!N)return M.value!==L.current&&(null==P||P.cancelValue(L.current),null==P||P.registerValue(M.value),L.current=M.value),()=>null==P?void 0:P.cancelValue(M.value)},[M.value]),t.useEffect(()=>{var e;(null==(e=z.current)?void 0:e.input)&&(z.current.input.indeterminate=w)},[w]);let D=T("checkbox",x),F=(0,c.default)(D),[I,A,H]=(0,m.default)(D,F),q=Object.assign({},M);P&&!N&&(q.onChange=(...e)=>{M.onChange&&M.onChange.apply(M,e),P.toggleOption&&P.toggleOption({label:v,value:M.value})},q.name=P.name,q.checked=P.value.includes(M.value));let V=(0,r.default)(`${D}-wrapper`,{[`${D}-rtl`]:"rtl"===O,[`${D}-wrapper-checked`]:q.checked,[`${D}-wrapper-disabled`]:R,[`${D}-wrapper-in-form-item`]:$},null==E?void 0:E.className,b,y,H,F,A),G=(0,r.default)({[`${D}-indeterminate`]:w},s.TARGET_CLS,A),[K,X]=(0,g.default)(q.onClick);return I(t.createElement(n.default,{component:"Checkbox",disabled:R},t.createElement("label",{className:V,style:Object.assign(Object.assign({},null==E?void 0:E.style),k),onMouseEnter:C,onMouseLeave:j,onClick:K},t.createElement(a.default,Object.assign({},q,{onClick:X,prefixCls:D,className:G,disabled:R,ref:B})),null!=v&&t.createElement("span",{className:`${D}-label`},v))))});var h=e.i(8211),x=e.i(529681),b=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let y=t.forwardRef((e,a)=>{let{defaultValue:l,children:n,options:s=[],prefixCls:i,className:d,rootClassName:g,style:f,onChange:y}=e,v=b(e,["defaultValue","children","options","prefixCls","className","rootClassName","style","onChange"]),{getPrefixCls:w,direction:k}=t.useContext(o.ConfigContext),[C,j]=t.useState(v.value||l||[]),[N,S]=t.useState([]);t.useEffect(()=>{"value"in v&&j(v.value||[])},[v.value]);let M=t.useMemo(()=>s.map(e=>"string"==typeof e||"number"==typeof e?{label:e,value:e}:e),[s]),T=e=>{S(t=>t.filter(t=>t!==e))},O=e=>{S(t=>[].concat((0,h.default)(t),[e]))},E=e=>{let t=C.indexOf(e.value),r=(0,h.default)(C);-1===t?r.push(e.value):r.splice(t,1),"value"in v||j(r),null==y||y(r.filter(e=>N.includes(e)).sort((e,t)=>M.findIndex(t=>t.value===e)-M.findIndex(e=>e.value===t)))},P=w("checkbox",i),$=`${P}-group`,_=(0,c.default)(P),[R,L,z]=(0,m.default)(P,_),B=(0,x.default)(v,["value","disabled"]),D=s.length?M.map(e=>t.createElement(p,{prefixCls:P,key:e.value.toString(),disabled:"disabled"in e?e.disabled:v.disabled,value:e.value,checked:C.includes(e.value),onChange:e.onChange,className:(0,r.default)(`${$}-item`,e.className),style:e.style,title:e.title,id:e.id,required:e.required},e.label)):n,F=t.useMemo(()=>({toggleOption:E,value:C,disabled:v.disabled,name:v.name,registerValue:O,cancelValue:T}),[E,C,v.disabled,v.name,O,T]),I=(0,r.default)($,{[`${$}-rtl`]:"rtl"===k},d,g,z,_,L);return R(t.createElement("div",Object.assign({className:I,style:f},B,{ref:a}),t.createElement(u.default.Provider,{value:F},D)))});p.Group=y,p.__ANT_CHECKBOX=!0,e.s(["default",0,p],374276)},536916,e=>{"use strict";var t=e.i(374276);e.s(["Checkbox",()=>t.default])},292639,e=>{"use strict";var t=e.i(764205),r=e.i(266027);let a=(0,e.i(243652).createQueryKeys)("uiSettings");e.s(["useUISettings",0,()=>(0,r.useQuery)({queryKey:a.list({}),queryFn:async()=>await (0,t.getUiSettings)(),staleTime:36e5,gcTime:36e5})])},250980,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlusCircleIcon",0,r],250980)},502547,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 5l7 7-7 7"}))});e.s(["ChevronRightIcon",0,r],502547)},384767,e=>{"use strict";var t=e.i(843476),r=e.i(599724),a=e.i(271645),l=e.i(389083);let n=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:"M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"}))});var s=e.i(764205);let o=function({vectorStores:e,accessToken:o}){let[i,c]=(0,a.useState)([]);return(0,a.useEffect)(()=>{(async()=>{if(o&&0!==e.length)try{let e=await (0,s.vectorStoreListCall)(o);e.data&&c(e.data.map(e=>({vector_store_id:e.vector_store_id,vector_store_name:e.vector_store_name})))}catch(e){console.error("Error fetching vector stores:",e)}})()},[o,e.length]),(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(n,{className:"h-4 w-4 text-blue-600"}),(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"Vector Stores"}),(0,t.jsx)(l.Badge,{color:"blue",size:"xs",children:e.length})]}),e.length>0?(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:e.map((e,r)=>{let a;return(0,t.jsx)("div",{className:"inline-flex items-center px-3 py-1.5 rounded-lg bg-blue-50 border border-blue-200 text-blue-800 text-sm font-medium",children:(a=i.find(t=>t.vector_store_id===e))?`${a.vector_store_name||a.vector_store_id} (${a.vector_store_id})`:e},r)})}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(n,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(r.Text,{className:"text-gray-500 text-sm",children:"No vector stores configured"})]})]})},i=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:"M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"}))});var c=e.i(871943),d=e.i(502547),u=e.i(592968);let m=function({mcpServers:n,mcpAccessGroups:o=[],mcpToolPermissions:m={},accessToken:g}){let[f,p]=(0,a.useState)([]),[h,x]=(0,a.useState)([]),[b,y]=(0,a.useState)(new Set);(0,a.useEffect)(()=>{(async()=>{if(g&&n.length>0)try{let e=await (0,s.fetchMCPServers)(g);e&&Array.isArray(e)?p(e):e.data&&Array.isArray(e.data)&&p(e.data)}catch(e){console.error("Error fetching MCP servers:",e)}})()},[g,n.length]),(0,a.useEffect)(()=>{(async()=>{if(g&&o.length>0)try{let t=await e.A(601236).then(e=>e.fetchMCPAccessGroups(g));x(Array.isArray(t)?t:t.data||[])}catch(e){console.error("Error fetching MCP access groups:",e)}})()},[g,o.length]);let v=[...n.map(e=>({type:"server",value:e})),...o.map(e=>({type:"accessGroup",value:e}))],w=v.length;return(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(i,{className:"h-4 w-4 text-blue-600"}),(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"MCP Servers"}),(0,t.jsx)(l.Badge,{color:"blue",size:"xs",children:w})]}),w>0?(0,t.jsx)("div",{className:"max-h-[400px] overflow-y-auto space-y-2 pr-1",children:v.map((e,r)=>{let a="server"===e.type?m[e.value]:void 0,l=a&&a.length>0,n=b.has(e.value);return(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{onClick:()=>{var t;return l&&(t=e.value,void y(e=>{let r=new Set(e);return r.has(t)?r.delete(t):r.add(t),r}))},className:`flex items-center gap-3 py-2 px-3 rounded-lg border border-gray-200 transition-all ${l?"cursor-pointer hover:bg-gray-50 hover:border-gray-300":"bg-white"}`,children:[(0,t.jsx)("div",{className:"flex items-center gap-2 flex-1 min-w-0",children:"server"===e.type?(0,t.jsx)(u.Tooltip,{title:`Full ID: ${e.value}`,placement:"top",children:(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-blue-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:(e=>{let t=f.find(t=>t.server_id===e);if(t){let r=e.length>7?`${e.slice(0,3)}...${e.slice(-4)}`:e;return`${t.alias} (${r})`}return e})(e.value)})]})}):(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-green-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:e.value}),(0,t.jsx)("span",{className:"ml-1 px-1.5 py-0.5 text-[9px] font-semibold text-green-600 bg-green-50 border border-green-200 rounded uppercase tracking-wide flex-shrink-0",children:"Group"})]})}),l&&(0,t.jsxs)("div",{className:"flex items-center gap-1 flex-shrink-0 whitespace-nowrap",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-600",children:a.length}),(0,t.jsx)("span",{className:"text-xs text-gray-500",children:1===a.length?"tool":"tools"}),n?(0,t.jsx)(c.ChevronDownIcon,{className:"h-3.5 w-3.5 text-gray-400 ml-0.5"}):(0,t.jsx)(d.ChevronRightIcon,{className:"h-3.5 w-3.5 text-gray-400 ml-0.5"})]})]}),l&&n&&(0,t.jsx)("div",{className:"ml-4 pl-4 border-l-2 border-blue-200 pb-1",children:(0,t.jsx)("div",{className:"flex flex-wrap gap-1.5",children:a.map((e,r)=>(0,t.jsx)("span",{className:"inline-flex items-center px-2.5 py-1 rounded-lg bg-blue-50 border border-blue-200 text-blue-800 text-xs font-medium",children:e},r))})})]},r)})}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(i,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(r.Text,{className:"text-gray-500 text-sm",children:"No MCP servers or access groups configured"})]})]})},g=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:"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"}))}),f=function({agents:e,agentAccessGroups:n=[],accessToken:o}){let[i,c]=(0,a.useState)([]);(0,a.useEffect)(()=>{(async()=>{if(o&&e.length>0)try{let e=await (0,s.getAgentsList)(o);e&&e.agents&&Array.isArray(e.agents)&&c(e.agents)}catch(e){console.error("Error fetching agents:",e)}})()},[o,e.length]);let d=[...e.map(e=>({type:"agent",value:e})),...n.map(e=>({type:"accessGroup",value:e}))],m=d.length;return(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(g,{className:"h-4 w-4 text-purple-600"}),(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"Agents"}),(0,t.jsx)(l.Badge,{color:"purple",size:"xs",children:m})]}),m>0?(0,t.jsx)("div",{className:"max-h-[400px] overflow-y-auto space-y-2 pr-1",children:d.map((e,r)=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsx)("div",{className:"flex items-center gap-3 py-2 px-3 rounded-lg border border-gray-200 bg-white",children:(0,t.jsx)("div",{className:"flex items-center gap-2 flex-1 min-w-0",children:"agent"===e.type?(0,t.jsx)(u.Tooltip,{title:`Full ID: ${e.value}`,placement:"top",children:(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-purple-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:(e=>{let t=i.find(t=>t.agent_id===e);if(t){let r=e.length>7?`${e.slice(0,3)}...${e.slice(-4)}`:e;return`${t.agent_name} (${r})`}return e})(e.value)})]})}):(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-green-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:e.value}),(0,t.jsx)("span",{className:"ml-1 px-1.5 py-0.5 text-[9px] font-semibold text-green-600 bg-green-50 border border-green-200 rounded uppercase tracking-wide flex-shrink-0",children:"Group"})]})})})},r))}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(g,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(r.Text,{className:"text-gray-500 text-sm",children:"No agents or access groups configured"})]})]})};e.s(["default",0,function({objectPermission:e,variant:a="card",className:l="",accessToken:n}){let s=e?.vector_stores||[],i=e?.mcp_servers||[],c=e?.mcp_access_groups||[],d=e?.mcp_tool_permissions||{},u=e?.agents||[],g=e?.agent_access_groups||[],p=(0,t.jsxs)("div",{className:"card"===a?"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6":"space-y-4",children:[(0,t.jsx)(o,{vectorStores:s,accessToken:n}),(0,t.jsx)(m,{mcpServers:i,mcpAccessGroups:c,mcpToolPermissions:d,accessToken:n}),(0,t.jsx)(f,{agents:u,agentAccessGroups:g,accessToken:n})]});return"card"===a?(0,t.jsxs)("div",{className:`bg-white border border-gray-200 rounded-lg p-6 ${l}`,children:[(0,t.jsx)("div",{className:"flex items-center gap-2 mb-6",children:(0,t.jsxs)("div",{children:[(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"Object Permissions"}),(0,t.jsx)(r.Text,{className:"text-xs text-gray-500",children:"Access control for Vector Stores and MCP Servers"})]})}),p]}):(0,t.jsxs)("div",{className:`${l}`,children:[(0,t.jsx)(r.Text,{className:"font-medium text-gray-900 mb-3",children:"Object Permissions"}),p]})}],384767)}]); \ No newline at end of file + `]:{[`&:hover ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"}}},{[t]:{"&-indeterminate":{"&":{[`${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${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 ${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${e.colorPrimary}`}}}}},{[`${l}-disabled`]:{cursor:"not-allowed"},[`${t}-disabled`]:{[`&, ${t}-input`]:{cursor:"not-allowed",pointerEvents:"none"},[`${t}-inner`]:{background:e.colorBgContainerDisabled,borderColor:e.colorBorder,"&:after":{borderColor:e.colorTextDisabled}},"&:after":{display:"none"},"& + span":{color:e.colorTextDisabled},[`&${t}-indeterminate ${t}-inner::after`]:{background:e.colorTextDisabled}}}]})((0,n.mergeToken)(t,{checkboxCls:`.${e}`,checkboxSize:t.controlInteractiveSize}))}let s=(0,l.genStyleHooks)("Checkbox",(e,{prefixCls:t})=>[o(t,e)]);e.s(["default",0,s,"getStyle",()=>o],236836)},681216,e=>{"use strict";var t=e.i(271645),r=e.i(963188);function a(e){let a=t.default.useRef(null),l=()=>{r.default.cancel(a.current),a.current=null};return[()=>{l(),a.current=(0,r.default)(()=>{a.current=null})},t=>{a.current&&(t.stopPropagation(),l()),null==e||e(t)}]}e.s(["default",()=>a])},374276,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(91874),l=e.i(611935),n=e.i(121872),o=e.i(26905),s=e.i(242064),i=e.i(937328),c=e.i(321883),d=e.i(62139),u=e.i(421512),m=e.i(236836),g=e.i(681216),p=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let f=t.forwardRef((e,f)=>{var h;let{prefixCls:x,className:b,rootClassName:y,children:v,indeterminate:w=!1,style:k,onMouseEnter:C,onMouseLeave:j,skipGroup:N=!1,disabled:S}=e,M=p(e,["prefixCls","className","rootClassName","children","indeterminate","style","onMouseEnter","onMouseLeave","skipGroup","disabled"]),{getPrefixCls:T,direction:E,checkbox:O}=t.useContext(s.ConfigContext),P=t.useContext(u.default),{isFormItemInput:$}=t.useContext(d.FormItemInputContext),_=t.useContext(i.default),R=null!=(h=(null==P?void 0:P.disabled)||S)?h:_,L=t.useRef(M.value),z=t.useRef(null),B=(0,l.composeRef)(f,z);t.useEffect(()=>{null==P||P.registerValue(M.value)},[]),t.useEffect(()=>{if(!N)return M.value!==L.current&&(null==P||P.cancelValue(L.current),null==P||P.registerValue(M.value),L.current=M.value),()=>null==P?void 0:P.cancelValue(M.value)},[M.value]),t.useEffect(()=>{var e;(null==(e=z.current)?void 0:e.input)&&(z.current.input.indeterminate=w)},[w]);let D=T("checkbox",x),F=(0,c.default)(D),[I,A,H]=(0,m.default)(D,F),q=Object.assign({},M);P&&!N&&(q.onChange=(...e)=>{M.onChange&&M.onChange.apply(M,e),P.toggleOption&&P.toggleOption({label:v,value:M.value})},q.name=P.name,q.checked=P.value.includes(M.value));let V=(0,r.default)(`${D}-wrapper`,{[`${D}-rtl`]:"rtl"===E,[`${D}-wrapper-checked`]:q.checked,[`${D}-wrapper-disabled`]:R,[`${D}-wrapper-in-form-item`]:$},null==O?void 0:O.className,b,y,H,F,A),G=(0,r.default)({[`${D}-indeterminate`]:w},o.TARGET_CLS,A),[K,X]=(0,g.default)(q.onClick);return I(t.createElement(n.default,{component:"Checkbox",disabled:R},t.createElement("label",{className:V,style:Object.assign(Object.assign({},null==O?void 0:O.style),k),onMouseEnter:C,onMouseLeave:j,onClick:K},t.createElement(a.default,Object.assign({},q,{onClick:X,prefixCls:D,className:G,disabled:R,ref:B})),null!=v&&t.createElement("span",{className:`${D}-label`},v))))});var h=e.i(8211),x=e.i(529681),b=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let y=t.forwardRef((e,a)=>{let{defaultValue:l,children:n,options:o=[],prefixCls:i,className:d,rootClassName:g,style:p,onChange:y}=e,v=b(e,["defaultValue","children","options","prefixCls","className","rootClassName","style","onChange"]),{getPrefixCls:w,direction:k}=t.useContext(s.ConfigContext),[C,j]=t.useState(v.value||l||[]),[N,S]=t.useState([]);t.useEffect(()=>{"value"in v&&j(v.value||[])},[v.value]);let M=t.useMemo(()=>o.map(e=>"string"==typeof e||"number"==typeof e?{label:e,value:e}:e),[o]),T=e=>{S(t=>t.filter(t=>t!==e))},E=e=>{S(t=>[].concat((0,h.default)(t),[e]))},O=e=>{let t=C.indexOf(e.value),r=(0,h.default)(C);-1===t?r.push(e.value):r.splice(t,1),"value"in v||j(r),null==y||y(r.filter(e=>N.includes(e)).sort((e,t)=>M.findIndex(t=>t.value===e)-M.findIndex(e=>e.value===t)))},P=w("checkbox",i),$=`${P}-group`,_=(0,c.default)(P),[R,L,z]=(0,m.default)(P,_),B=(0,x.default)(v,["value","disabled"]),D=o.length?M.map(e=>t.createElement(f,{prefixCls:P,key:e.value.toString(),disabled:"disabled"in e?e.disabled:v.disabled,value:e.value,checked:C.includes(e.value),onChange:e.onChange,className:(0,r.default)(`${$}-item`,e.className),style:e.style,title:e.title,id:e.id,required:e.required},e.label)):n,F=t.useMemo(()=>({toggleOption:O,value:C,disabled:v.disabled,name:v.name,registerValue:E,cancelValue:T}),[O,C,v.disabled,v.name,E,T]),I=(0,r.default)($,{[`${$}-rtl`]:"rtl"===k},d,g,z,_,L);return R(t.createElement("div",Object.assign({className:I,style:p},B,{ref:a}),t.createElement(u.default.Provider,{value:F},D)))});f.Group=y,f.__ANT_CHECKBOX=!0,e.s(["default",0,f],374276)},536916,e=>{"use strict";var t=e.i(374276);e.s(["Checkbox",()=>t.default])},292639,e=>{"use strict";var t=e.i(764205),r=e.i(266027);let a=(0,e.i(243652).createQueryKeys)("uiSettings");e.s(["useUISettings",0,()=>(0,r.useQuery)({queryKey:a.list({}),queryFn:async()=>await (0,t.getUiSettings)(),staleTime:36e5,gcTime:36e5})])},250980,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlusCircleIcon",0,r],250980)},502547,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 5l7 7-7 7"}))});e.s(["ChevronRightIcon",0,r],502547)},384767,e=>{"use strict";var t=e.i(843476),r=e.i(599724),a=e.i(271645),l=e.i(389083);let n=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:"M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"}))});var o=e.i(764205);let s=function({vectorStores:e,accessToken:s}){let[i,c]=(0,a.useState)([]);return(0,a.useEffect)(()=>{(async()=>{if(s&&0!==e.length)try{let e=await (0,o.vectorStoreListCall)(s);e.data&&c(e.data.map(e=>({vector_store_id:e.vector_store_id,vector_store_name:e.vector_store_name})))}catch(e){console.error("Error fetching vector stores:",e)}})()},[s,e.length]),(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(n,{className:"h-4 w-4 text-blue-600"}),(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"Vector Stores"}),(0,t.jsx)(l.Badge,{color:"blue",size:"xs",children:e.length})]}),e.length>0?(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:e.map((e,r)=>{let a;return(0,t.jsx)("div",{className:"inline-flex items-center px-3 py-1.5 rounded-lg bg-blue-50 border border-blue-200 text-blue-800 text-sm font-medium",children:(a=i.find(t=>t.vector_store_id===e))?`${a.vector_store_name||a.vector_store_id} (${a.vector_store_id})`:e},r)})}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(n,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(r.Text,{className:"text-gray-500 text-sm",children:"No vector stores configured"})]})]})},i=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:"M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"}))});var c=e.i(871943),d=e.i(502547),u=e.i(592968);let m=function({mcpServers:n,mcpAccessGroups:s=[],mcpToolPermissions:m={},accessToken:g}){let[p,f]=(0,a.useState)([]),[h,x]=(0,a.useState)([]),[b,y]=(0,a.useState)(new Set);(0,a.useEffect)(()=>{(async()=>{if(g&&n.length>0)try{let e=await (0,o.fetchMCPServers)(g);e&&Array.isArray(e)?f(e):e.data&&Array.isArray(e.data)&&f(e.data)}catch(e){console.error("Error fetching MCP servers:",e)}})()},[g,n.length]),(0,a.useEffect)(()=>{(async()=>{if(g&&s.length>0)try{let t=await e.A(601236).then(e=>e.fetchMCPAccessGroups(g));x(Array.isArray(t)?t:t.data||[])}catch(e){console.error("Error fetching MCP access groups:",e)}})()},[g,s.length]);let v=[...n.map(e=>({type:"server",value:e})),...s.map(e=>({type:"accessGroup",value:e}))],w=v.length;return(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(i,{className:"h-4 w-4 text-blue-600"}),(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"MCP Servers"}),(0,t.jsx)(l.Badge,{color:"blue",size:"xs",children:w})]}),w>0?(0,t.jsx)("div",{className:"max-h-[400px] overflow-y-auto space-y-2 pr-1",children:v.map((e,r)=>{let a="server"===e.type?m[e.value]:void 0,l=a&&a.length>0,n=b.has(e.value);return(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{onClick:()=>{var t;return l&&(t=e.value,void y(e=>{let r=new Set(e);return r.has(t)?r.delete(t):r.add(t),r}))},className:`flex items-center gap-3 py-2 px-3 rounded-lg border border-gray-200 transition-all ${l?"cursor-pointer hover:bg-gray-50 hover:border-gray-300":"bg-white"}`,children:[(0,t.jsx)("div",{className:"flex items-center gap-2 flex-1 min-w-0",children:"server"===e.type?(0,t.jsx)(u.Tooltip,{title:`Full ID: ${e.value}`,placement:"top",children:(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-blue-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:(e=>{let t=p.find(t=>t.server_id===e);if(t){let r=e.length>7?`${e.slice(0,3)}...${e.slice(-4)}`:e;return`${t.alias} (${r})`}return e})(e.value)})]})}):(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-green-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:e.value}),(0,t.jsx)("span",{className:"ml-1 px-1.5 py-0.5 text-[9px] font-semibold text-green-600 bg-green-50 border border-green-200 rounded uppercase tracking-wide flex-shrink-0",children:"Group"})]})}),l&&(0,t.jsxs)("div",{className:"flex items-center gap-1 flex-shrink-0 whitespace-nowrap",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-600",children:a.length}),(0,t.jsx)("span",{className:"text-xs text-gray-500",children:1===a.length?"tool":"tools"}),n?(0,t.jsx)(c.ChevronDownIcon,{className:"h-3.5 w-3.5 text-gray-400 ml-0.5"}):(0,t.jsx)(d.ChevronRightIcon,{className:"h-3.5 w-3.5 text-gray-400 ml-0.5"})]})]}),l&&n&&(0,t.jsx)("div",{className:"ml-4 pl-4 border-l-2 border-blue-200 pb-1",children:(0,t.jsx)("div",{className:"flex flex-wrap gap-1.5",children:a.map((e,r)=>(0,t.jsx)("span",{className:"inline-flex items-center px-2.5 py-1 rounded-lg bg-blue-50 border border-blue-200 text-blue-800 text-xs font-medium",children:e},r))})})]},r)})}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(i,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(r.Text,{className:"text-gray-500 text-sm",children:"No MCP servers or access groups configured"})]})]})},g=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:"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"}))}),p=function({agents:e,agentAccessGroups:n=[],accessToken:s}){let[i,c]=(0,a.useState)([]);(0,a.useEffect)(()=>{(async()=>{if(s&&e.length>0)try{let e=await (0,o.getAgentsList)(s);e&&e.agents&&Array.isArray(e.agents)&&c(e.agents)}catch(e){console.error("Error fetching agents:",e)}})()},[s,e.length]);let d=[...e.map(e=>({type:"agent",value:e})),...n.map(e=>({type:"accessGroup",value:e}))],m=d.length;return(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(g,{className:"h-4 w-4 text-purple-600"}),(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"Agents"}),(0,t.jsx)(l.Badge,{color:"purple",size:"xs",children:m})]}),m>0?(0,t.jsx)("div",{className:"max-h-[400px] overflow-y-auto space-y-2 pr-1",children:d.map((e,r)=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsx)("div",{className:"flex items-center gap-3 py-2 px-3 rounded-lg border border-gray-200 bg-white",children:(0,t.jsx)("div",{className:"flex items-center gap-2 flex-1 min-w-0",children:"agent"===e.type?(0,t.jsx)(u.Tooltip,{title:`Full ID: ${e.value}`,placement:"top",children:(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-purple-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:(e=>{let t=i.find(t=>t.agent_id===e);if(t){let r=e.length>7?`${e.slice(0,3)}...${e.slice(-4)}`:e;return`${t.agent_name} (${r})`}return e})(e.value)})]})}):(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-green-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:e.value}),(0,t.jsx)("span",{className:"ml-1 px-1.5 py-0.5 text-[9px] font-semibold text-green-600 bg-green-50 border border-green-200 rounded uppercase tracking-wide flex-shrink-0",children:"Group"})]})})})},r))}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(g,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(r.Text,{className:"text-gray-500 text-sm",children:"No agents or access groups configured"})]})]})};e.s(["default",0,function({objectPermission:e,variant:a="card",className:l="",accessToken:n}){let o=e?.vector_stores||[],i=e?.mcp_servers||[],c=e?.mcp_access_groups||[],d=e?.mcp_tool_permissions||{},u=e?.agents||[],g=e?.agent_access_groups||[],f=(0,t.jsxs)("div",{className:"card"===a?"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6":"space-y-4",children:[(0,t.jsx)(s,{vectorStores:o,accessToken:n}),(0,t.jsx)(m,{mcpServers:i,mcpAccessGroups:c,mcpToolPermissions:d,accessToken:n}),(0,t.jsx)(p,{agents:u,agentAccessGroups:g,accessToken:n})]});return"card"===a?(0,t.jsxs)("div",{className:`bg-white border border-gray-200 rounded-lg p-6 ${l}`,children:[(0,t.jsx)("div",{className:"flex items-center gap-2 mb-6",children:(0,t.jsxs)("div",{children:[(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"Object Permissions"}),(0,t.jsx)(r.Text,{className:"text-xs text-gray-500",children:"Access control for Vector Stores and MCP Servers"})]})}),f]}):(0,t.jsxs)("div",{className:`${l}`,children:[(0,t.jsx)(r.Text,{className:"font-medium text-gray-900 mb-3",children:"Object Permissions"}),f]})}],384767)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/2f9ed92e7b7cd792.js b/litellm/proxy/_experimental/out/_next/static/chunks/2f9ed92e7b7cd792.js deleted file mode 100644 index 47b035afd1..0000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/2f9ed92e7b7cd792.js +++ /dev/null @@ -1 +0,0 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,916925,e=>{"use strict";var t,r=((t={}).A2A_Agent="A2A Agent",t.AI21="Ai21",t.AI21_CHAT="Ai21 Chat",t.AIML="AI/ML API",t.AIOHTTP_OPENAI="Aiohttp Openai",t.Anthropic="Anthropic",t.ANTHROPIC_TEXT="Anthropic Text",t.AssemblyAI="AssemblyAI",t.AUTO_ROUTER="Auto Router",t.Bedrock="Amazon Bedrock",t.BedrockMantle="Amazon Bedrock Mantle",t.SageMaker="AWS SageMaker",t.Azure="Azure",t.Azure_AI_Studio="Azure AI Foundry (Studio)",t.AZURE_TEXT="Azure Text",t.BASETEN="Baseten",t.BYTEZ="Bytez",t.Cerebras="Cerebras",t.CLARIFAI="Clarifai",t.CLOUDFLARE="Cloudflare",t.CODESTRAL="Codestral",t.Cohere="Cohere",t.COHERE_CHAT="Cohere Chat",t.COMETAPI="Cometapi",t.COMPACTIFAI="Compactifai",t.Cursor="Cursor",t.Dashscope="Dashscope",t.Databricks="Databricks (Qwen API)",t.DATAROBOT="Datarobot",t.DeepInfra="DeepInfra",t.Deepgram="Deepgram",t.Deepseek="Deepseek",t.DOCKER_MODEL_RUNNER="Docker Model Runner",t.DOTPROMPT="Dotprompt",t.ElevenLabs="ElevenLabs",t.EMPOWER="Empower",t.FalAI="Fal AI",t.FEATHERLESS_AI="Featherless Ai",t.FireworksAI="Fireworks AI",t.FRIENDLIAI="Friendliai",t.GALADRIEL="Galadriel",t.GITHUB_COPILOT="Github Copilot",t.Google_AI_Studio="Google AI Studio",t.GradientAI="GradientAI",t.Groq="Groq",t.HEROKU="Heroku",t.Hosted_Vllm="vllm",t.HUGGINGFACE="Huggingface",t.HYPERBOLIC="Hyperbolic",t.Infinity="Infinity",t.JinaAI="Jina AI",t.LAMBDA_AI="Lambda Ai",t.LEMONADE="Lemonade",t.LLAMAFILE="Llamafile",t.LM_STUDIO="Lm Studio",t.LLAMA="Meta Llama",t.MARITALK="Maritalk",t.MiniMax="MiniMax",t.MistralAI="Mistral AI",t.MOONSHOT="Moonshot",t.MORPH="Morph",t.NEBIUS="Nebius",t.NLP_CLOUD="Nlp Cloud",t.NOVITA="Novita",t.NSCALE="Nscale",t.NVIDIA_NIM="Nvidia Nim",t.Ollama="Ollama",t.OLLAMA_CHAT="Ollama Chat",t.OOBABOOGA="Oobabooga",t.OpenAI="OpenAI",t.OPENAI_LIKE="Openai Like",t.OpenAI_Compatible="OpenAI-Compatible Endpoints (Together AI, etc.)",t.OpenAI_Text="OpenAI Text Completion",t.OpenAI_Text_Compatible="OpenAI-Compatible Text Completion Models (Together AI, etc.)",t.Openrouter="Openrouter",t.Oracle="Oracle Cloud Infrastructure (OCI)",t.OVHCLOUD="Ovhcloud",t.Perplexity="Perplexity",t.PETALS="Petals",t.PG_VECTOR="Pg Vector",t.PREDIBASE="Predibase",t.RECRAFT="Recraft",t.REPLICATE="Replicate",t.RunwayML="RunwayML",t.SAGEMAKER_LEGACY="Sagemaker",t.Sambanova="Sambanova",t.SAP="SAP Generative AI Hub",t.Snowflake="Snowflake",t.TEXT_COMPLETION_CODESTRAL="Text-Completion-Codestral",t.TogetherAI="TogetherAI",t.TOPAZ="Topaz",t.Triton="Triton",t.V0="V0",t.VERCEL_AI_GATEWAY="Vercel Ai Gateway",t.Vertex_AI="Vertex AI (Anthropic, Gemini, etc.)",t.VERTEX_AI_BETA="Vertex Ai Beta",t.VLLM="Vllm",t.VolcEngine="VolcEngine",t.Voyage="Voyage AI",t.WANDB="Wandb",t.WATSONX="Watsonx",t.WATSONX_TEXT="Watsonx Text",t.xAI="xAI",t.XINFERENCE="Xinference",t);let a={A2A_Agent:"a2a_agent",AI21:"ai21",AI21_CHAT:"ai21_chat",AIML:"aiml",AIOHTTP_OPENAI:"aiohttp_openai",Anthropic:"anthropic",ANTHROPIC_TEXT:"anthropic_text",AssemblyAI:"assemblyai",AUTO_ROUTER:"auto_router",Azure:"azure",Azure_AI_Studio:"azure_ai",AZURE_TEXT:"azure_text",BASETEN:"baseten",Bedrock:"bedrock",BedrockMantle:"bedrock_mantle",BYTEZ:"bytez",Cerebras:"cerebras",CLARIFAI:"clarifai",CLOUDFLARE:"cloudflare",CODESTRAL:"codestral",Cohere:"cohere",COHERE_CHAT:"cohere_chat",COMETAPI:"cometapi",COMPACTIFAI:"compactifai",Cursor:"cursor",Dashscope:"dashscope",Databricks:"databricks",DATAROBOT:"datarobot",DeepInfra:"deepinfra",Deepgram:"deepgram",Deepseek:"deepseek",DOCKER_MODEL_RUNNER:"docker_model_runner",DOTPROMPT:"dotprompt",ElevenLabs:"elevenlabs",EMPOWER:"empower",FalAI:"fal_ai",FEATHERLESS_AI:"featherless_ai",FireworksAI:"fireworks_ai",FRIENDLIAI:"friendliai",GALADRIEL:"galadriel",GITHUB_COPILOT:"github_copilot",Google_AI_Studio:"gemini",GradientAI:"gradient_ai",Groq:"groq",HEROKU:"heroku",Hosted_Vllm:"hosted_vllm",HUGGINGFACE:"huggingface",HYPERBOLIC:"hyperbolic",Infinity:"infinity",JinaAI:"jina_ai",LAMBDA_AI:"lambda_ai",LEMONADE:"lemonade",LLAMAFILE:"llamafile",LLAMA:"meta_llama",LM_STUDIO:"lm_studio",MARITALK:"maritalk",MiniMax:"minimax",MistralAI:"mistral",MOONSHOT:"moonshot",MORPH:"morph",NEBIUS:"nebius",NLP_CLOUD:"nlp_cloud",NOVITA:"novita",NSCALE:"nscale",NVIDIA_NIM:"nvidia_nim",Ollama:"ollama",OLLAMA_CHAT:"ollama_chat",OOBABOOGA:"oobabooga",OpenAI:"openai",OPENAI_LIKE:"openai_like",OpenAI_Compatible:"openai",OpenAI_Text:"text-completion-openai",OpenAI_Text_Compatible:"text-completion-openai",Openrouter:"openrouter",Oracle:"oci",OVHCLOUD:"ovhcloud",Perplexity:"perplexity",PETALS:"petals",PG_VECTOR:"pg_vector",PREDIBASE:"predibase",RECRAFT:"recraft",REPLICATE:"replicate",RunwayML:"runwayml",SAGEMAKER_LEGACY:"sagemaker",SageMaker:"sagemaker_chat",Sambanova:"sambanova",SAP:"sap",Snowflake:"snowflake",TEXT_COMPLETION_CODESTRAL:"text-completion-codestral",TogetherAI:"together_ai",TOPAZ:"topaz",Triton:"triton",V0:"v0",VERCEL_AI_GATEWAY:"vercel_ai_gateway",Vertex_AI:"vertex_ai",VERTEX_AI_BETA:"vertex_ai_beta",VLLM:"vllm",VolcEngine:"volcengine",Voyage:"voyage",WANDB:"wandb",WATSONX:"watsonx",WATSONX_TEXT:"watsonx_text",xAI:"xai",XINFERENCE:"xinference"},i="../ui/assets/logos/",o={"A2A Agent":`${i}a2a_agent.png`,Ai21:`${i}ai21.svg`,"Ai21 Chat":`${i}ai21.svg`,"AI/ML API":`${i}aiml_api.svg`,"Aiohttp Openai":`${i}openai_small.svg`,Anthropic:`${i}anthropic.svg`,"Anthropic Text":`${i}anthropic.svg`,AssemblyAI:`${i}assemblyai_small.png`,Azure:`${i}microsoft_azure.svg`,"Azure AI Foundry (Studio)":`${i}microsoft_azure.svg`,"Azure Text":`${i}microsoft_azure.svg`,Baseten:`${i}baseten.svg`,"Amazon Bedrock":`${i}bedrock.svg`,"Amazon Bedrock Mantle":`${i}bedrock.svg`,"AWS SageMaker":`${i}bedrock.svg`,Cerebras:`${i}cerebras.svg`,Cloudflare:`${i}cloudflare.svg`,Codestral:`${i}mistral.svg`,Cohere:`${i}cohere.svg`,"Cohere Chat":`${i}cohere.svg`,Cometapi:`${i}cometapi.svg`,Cursor:`${i}cursor.svg`,"Databricks (Qwen API)":`${i}databricks.svg`,Dashscope:`${i}dashscope.svg`,Deepseek:`${i}deepseek.svg`,Deepgram:`${i}deepgram.png`,DeepInfra:`${i}deepinfra.png`,ElevenLabs:`${i}elevenlabs.png`,"Fal AI":`${i}fal_ai.jpg`,"Featherless Ai":`${i}featherless.svg`,"Fireworks AI":`${i}fireworks.svg`,Friendliai:`${i}friendli.svg`,"Github Copilot":`${i}github_copilot.svg`,"Google AI Studio":`${i}google.svg`,GradientAI:`${i}gradientai.svg`,Groq:`${i}groq.svg`,vllm:`${i}vllm.png`,Huggingface:`${i}huggingface.svg`,Hyperbolic:`${i}hyperbolic.svg`,Infinity:`${i}infinity.png`,"Jina AI":`${i}jina.png`,"Lambda Ai":`${i}lambda.svg`,"Lm Studio":`${i}lmstudio.svg`,"Meta Llama":`${i}meta_llama.svg`,MiniMax:`${i}minimax.svg`,"Mistral AI":`${i}mistral.svg`,Moonshot:`${i}moonshot.svg`,Morph:`${i}morph.svg`,Nebius:`${i}nebius.svg`,Novita:`${i}novita.svg`,"Nvidia Nim":`${i}nvidia_nim.svg`,Ollama:`${i}ollama.svg`,"Ollama Chat":`${i}ollama.svg`,Oobabooga:`${i}openai_small.svg`,OpenAI:`${i}openai_small.svg`,"Openai Like":`${i}openai_small.svg`,"OpenAI Text Completion":`${i}openai_small.svg`,"OpenAI-Compatible Text Completion Models (Together AI, etc.)":`${i}openai_small.svg`,"OpenAI-Compatible Endpoints (Together AI, etc.)":`${i}openai_small.svg`,Openrouter:`${i}openrouter.svg`,"Oracle Cloud Infrastructure (OCI)":`${i}oracle.svg`,Perplexity:`${i}perplexity-ai.svg`,Recraft:`${i}recraft.svg`,Replicate:`${i}replicate.svg`,RunwayML:`${i}runwayml.png`,Sagemaker:`${i}bedrock.svg`,Sambanova:`${i}sambanova.svg`,"SAP Generative AI Hub":`${i}sap.png`,Snowflake:`${i}snowflake.svg`,"Text-Completion-Codestral":`${i}mistral.svg`,TogetherAI:`${i}togetherai.svg`,Topaz:`${i}topaz.svg`,Triton:`${i}nvidia_triton.png`,V0:`${i}v0.svg`,"Vercel Ai Gateway":`${i}vercel.svg`,"Vertex AI (Anthropic, Gemini, etc.)":`${i}google.svg`,"Vertex Ai Beta":`${i}google.svg`,Vllm:`${i}vllm.png`,VolcEngine:`${i}volcengine.png`,"Voyage AI":`${i}voyage.webp`,Watsonx:`${i}watsonx.svg`,"Watsonx Text":`${i}watsonx.svg`,xAI:`${i}xai.svg`,Xinference:`${i}xinference.svg`};e.s(["Providers",()=>r,"getPlaceholder",0,e=>{if("AI/ML API"===e)return"aiml/flux-pro/v1.1";if("Vertex AI (Anthropic, Gemini, etc.)"===e)return"gemini-pro";if("Anthropic"==e)return"claude-3-opus";if("Amazon Bedrock"==e)return"claude-3-opus";if("AWS SageMaker"==e)return"sagemaker/jumpstart-dft-meta-textgeneration-llama-2-7b";else if("Google AI Studio"==e)return"gemini-pro";else if("Azure AI Foundry (Studio)"==e)return"azure_ai/command-r-plus";else if("Azure"==e)return"my-deployment";else if("Oracle Cloud Infrastructure (OCI)"==e)return"oci/xai.grok-4";else if("Snowflake"==e)return"snowflake/mistral-7b";else if("Voyage AI"==e)return"voyage/";else if("Jina AI"==e)return"jina_ai/";else if("VolcEngine"==e)return"volcengine/";else if("DeepInfra"==e)return"deepinfra/";else if("Fal AI"==e)return"fal_ai/fal-ai/flux-pro/v1.1-ultra";else if("RunwayML"==e)return"runwayml/gen4_turbo";else if("Watsonx"===e)return"watsonx/ibm/granite-3-3-8b-instruct";else if("Cursor"===e)return"cursor/claude-4-sonnet";else return"gpt-3.5-turbo"},"getProviderLogoAndName",0,e=>{if(!e)return{logo:"",displayName:"-"};if("gemini"===e.toLowerCase()){let e="Google AI Studio";return{logo:o[e],displayName:e}}let t=Object.keys(a).find(t=>a[t].toLowerCase()===e.toLowerCase());if(!t)return{logo:"",displayName:e};let i=r[t];return{logo:o[i],displayName:i}},"getProviderModels",0,(e,t)=>{console.log(`Provider key: ${e}`);let r=a[e];console.log(`Provider mapped to: ${r}`);let i=[];return e&&"object"==typeof t&&(Object.entries(t).forEach(([e,t])=>{if(null!==t&&"object"==typeof t&&"litellm_provider"in t){let a=t.litellm_provider;(a===r||"string"==typeof a&&a.includes(r))&&i.push(e)}}),"Cohere"==e&&(console.log("Adding cohere chat models"),Object.entries(t).forEach(([e,t])=>{null!==t&&"object"==typeof t&&"litellm_provider"in t&&"cohere_chat"===t.litellm_provider&&i.push(e)})),"AWS SageMaker"==e&&(console.log("Adding sagemaker chat models"),Object.entries(t).forEach(([e,t])=>{null!==t&&"object"==typeof t&&"litellm_provider"in t&&"sagemaker_chat"===t.litellm_provider&&i.push(e)}))),i},"providerLogoMap",0,o,"provider_map",0,a])},362024,e=>{"use strict";var t=e.i(988122);e.s(["Collapse",()=>t.default])},240647,e=>{"use strict";var t=e.i(286612);e.s(["RightOutlined",()=>t.default])},152473,e=>{"use strict";var t=e.i(271645);let r={enabled:!0,leading:!1,trailing:!0,wait:0,onExecute:()=>{}};class a{constructor(e,t){this.fn=e,this._canLeadingExecute=!0,this._isPending=!1,this._executionCount=0,this._options={...r,...t}}setOptions(e){return this._options={...this._options,...e},this._options.enabled||(this._isPending=!1),this._options}getOptions(){return this._options}maybeExecute(...e){this._options.leading&&this._canLeadingExecute&&(this.executeFunction(...e),this._canLeadingExecute=!1),(this._options.leading||this._options.trailing)&&(this._isPending=!0),this._timeoutId&&clearTimeout(this._timeoutId),this._timeoutId=setTimeout(()=>{this._canLeadingExecute=!0,this._isPending=!1,this._options.trailing&&this.executeFunction(...e)},this._options.wait)}executeFunction(...e){this._options.enabled&&(this.fn(...e),this._executionCount++,this._options.onExecute(this))}cancel(){this._timeoutId&&(clearTimeout(this._timeoutId),this._canLeadingExecute=!0,this._isPending=!1)}getExecutionCount(){return this._executionCount}getIsPending(){return this._options.enabled&&this._isPending}}function i(e,r){let[i,o]=(0,t.useState)(e),n=function(e,r){let[i]=(0,t.useState)(()=>{var t;return Object.getOwnPropertyNames(Object.getPrototypeOf(t=new a(e,r))).filter(e=>"function"==typeof t[e]).reduce((e,r)=>{let a=t[r];return"function"==typeof a&&(e[r]=a.bind(t)),e},{})});return i.setOptions(r),i}(o,r);return[i,n.maybeExecute,n]}e.s(["useDebouncedState",()=>i],152473)},738014,e=>{"use strict";var t=e.i(135214),r=e.i(764205),a=e.i(266027);let i=(0,e.i(243652).createQueryKeys)("users");e.s(["useCurrentUser",0,()=>{let{accessToken:e,userId:o,userRole:n}=(0,t.default)();return(0,a.useQuery)({queryKey:i.detail(o),queryFn:async()=>{let t=await (0,r.userInfoCall)(e,o,n,!1,null,null);return console.log(`userInfo: ${JSON.stringify(t)}`),t.user_info},enabled:!!(e&&o&&n)})}])},906579,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(361275),i=e.i(702779),o=e.i(763731),n=e.i(242064);e.i(296059);var s=e.i(915654),l=e.i(694758),c=e.i(183293),u=e.i(403541),d=e.i(246422),m=e.i(838378);let g=new l.Keyframes("antStatusProcessing",{"0%":{transform:"scale(0.8)",opacity:.5},"100%":{transform:"scale(2.4)",opacity:0}}),p=new l.Keyframes("antZoomBadgeIn",{"0%":{transform:"scale(0) translate(50%, -50%)",opacity:0},"100%":{transform:"scale(1) translate(50%, -50%)"}}),f=new l.Keyframes("antZoomBadgeOut",{"0%":{transform:"scale(1) translate(50%, -50%)"},"100%":{transform:"scale(0) translate(50%, -50%)",opacity:0}}),h=new l.Keyframes("antNoWrapperZoomBadgeIn",{"0%":{transform:"scale(0)",opacity:0},"100%":{transform:"scale(1)"}}),b=new l.Keyframes("antNoWrapperZoomBadgeOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0)",opacity:0}}),v=new l.Keyframes("antBadgeLoadingCircle",{"0%":{transformOrigin:"50%"},"100%":{transform:"translate(50%, -50%) rotate(360deg)",transformOrigin:"50%"}}),A=e=>{let{fontHeight:t,lineWidth:r,marginXS:a,colorBorderBg:i}=e,o=e.colorTextLightSolid,n=e.colorError,s=e.colorErrorHover;return(0,m.mergeToken)(e,{badgeFontHeight:t,badgeShadowSize:r,badgeTextColor:o,badgeColor:n,badgeColorHover:s,badgeShadowColor:i,badgeProcessingDuration:"1.2s",badgeRibbonOffset:a,badgeRibbonCornerTransform:"scaleY(0.75)",badgeRibbonCornerFilter:"brightness(75%)"})},y=e=>{let{fontSize:t,lineHeight:r,fontSizeSM:a,lineWidth:i}=e;return{indicatorZIndex:"auto",indicatorHeight:Math.round(t*r)-2*i,indicatorHeightSM:t,dotSize:a/2,textFontSize:a,textFontSizeSM:a,textFontWeight:"normal",statusSize:a/2}},O=(0,d.genStyleHooks)("Badge",e=>(e=>{let{componentCls:t,iconCls:r,antCls:a,badgeShadowSize:i,textFontSize:o,textFontSizeSM:n,statusSize:l,dotSize:d,textFontWeight:m,indicatorHeight:A,indicatorHeightSM:y,marginXS:O,calc:x}=e,C=`${a}-scroll-number`,I=(0,u.genPresetColor)(e,(e,{darkColor:r})=>({[`&${t} ${t}-color-${e}`]:{background:r,[`&:not(${t}-count)`]:{color:r},"a:hover &":{background:r}}}));return{[t]:Object.assign(Object.assign(Object.assign(Object.assign({},(0,c.resetComponent)(e)),{position:"relative",display:"inline-block",width:"fit-content",lineHeight:1,[`${t}-count`]:{display:"inline-flex",justifyContent:"center",zIndex:e.indicatorZIndex,minWidth:A,height:A,color:e.badgeTextColor,fontWeight:m,fontSize:o,lineHeight:(0,s.unit)(A),whiteSpace:"nowrap",textAlign:"center",background:e.badgeColor,borderRadius:x(A).div(2).equal(),boxShadow:`0 0 0 ${(0,s.unit)(i)} ${e.badgeShadowColor}`,transition:`background ${e.motionDurationMid}`,a:{color:e.badgeTextColor},"a:hover":{color:e.badgeTextColor},"a:hover &":{background:e.badgeColorHover}},[`${t}-count-sm`]:{minWidth:y,height:y,fontSize:n,lineHeight:(0,s.unit)(y),borderRadius:x(y).div(2).equal()},[`${t}-multiple-words`]:{padding:`0 ${(0,s.unit)(e.paddingXS)}`,bdi:{unicodeBidi:"plaintext"}},[`${t}-dot`]:{zIndex:e.indicatorZIndex,width:d,minWidth:d,height:d,background:e.badgeColor,borderRadius:"100%",boxShadow:`0 0 0 ${(0,s.unit)(i)} ${e.badgeShadowColor}`},[`${t}-count, ${t}-dot, ${C}-custom-component`]:{position:"absolute",top:0,insetInlineEnd:0,transform:"translate(50%, -50%)",transformOrigin:"100% 0%",[`&${r}-spin`]:{animationName:v,animationDuration:"1s",animationIterationCount:"infinite",animationTimingFunction:"linear"}},[`&${t}-status`]:{lineHeight:"inherit",verticalAlign:"baseline",[`${t}-status-dot`]:{position:"relative",top:-1,display:"inline-block",width:l,height:l,verticalAlign:"middle",borderRadius:"50%"},[`${t}-status-success`]:{backgroundColor:e.colorSuccess},[`${t}-status-processing`]:{overflow:"visible",color:e.colorInfo,backgroundColor:e.colorInfo,borderColor:"currentcolor","&::after":{position:"absolute",top:0,insetInlineStart:0,width:"100%",height:"100%",borderWidth:i,borderStyle:"solid",borderColor:"inherit",borderRadius:"50%",animationName:g,animationDuration:e.badgeProcessingDuration,animationIterationCount:"infinite",animationTimingFunction:"ease-in-out",content:'""'}},[`${t}-status-default`]:{backgroundColor:e.colorTextPlaceholder},[`${t}-status-error`]:{backgroundColor:e.colorError},[`${t}-status-warning`]:{backgroundColor:e.colorWarning},[`${t}-status-text`]:{marginInlineStart:O,color:e.colorText,fontSize:e.fontSize}}}),I),{[`${t}-zoom-appear, ${t}-zoom-enter`]:{animationName:p,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack,animationFillMode:"both"},[`${t}-zoom-leave`]:{animationName:f,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack,animationFillMode:"both"},[`&${t}-not-a-wrapper`]:{[`${t}-zoom-appear, ${t}-zoom-enter`]:{animationName:h,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack},[`${t}-zoom-leave`]:{animationName:b,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack},[`&:not(${t}-status)`]:{verticalAlign:"middle"},[`${C}-custom-component, ${t}-count`]:{transform:"none"},[`${C}-custom-component, ${C}`]:{position:"relative",top:"auto",display:"block",transformOrigin:"50% 50%"}},[C]:{overflow:"hidden",transition:`all ${e.motionDurationMid} ${e.motionEaseOutBack}`,[`${C}-only`]:{position:"relative",display:"inline-block",height:A,transition:`all ${e.motionDurationSlow} ${e.motionEaseOutBack}`,WebkitTransformStyle:"preserve-3d",WebkitBackfaceVisibility:"hidden",[`> p${C}-only-unit`]:{height:A,margin:0,WebkitTransformStyle:"preserve-3d",WebkitBackfaceVisibility:"hidden"}},[`${C}-symbol`]:{verticalAlign:"top"}},"&-rtl":{direction:"rtl",[`${t}-count, ${t}-dot, ${C}-custom-component`]:{transform:"translate(-50%, -50%)"}}})}})(A(e)),y),x=(0,d.genStyleHooks)(["Badge","Ribbon"],e=>(e=>{let{antCls:t,badgeFontHeight:r,marginXS:a,badgeRibbonOffset:i,calc:o}=e,n=`${t}-ribbon`,l=`${t}-ribbon-wrapper`,d=(0,u.genPresetColor)(e,(e,{darkColor:t})=>({[`&${n}-color-${e}`]:{background:t,color:t}}));return{[l]:{position:"relative"},[n]:Object.assign(Object.assign(Object.assign(Object.assign({},(0,c.resetComponent)(e)),{position:"absolute",top:a,padding:`0 ${(0,s.unit)(e.paddingXS)}`,color:e.colorPrimary,lineHeight:(0,s.unit)(r),whiteSpace:"nowrap",backgroundColor:e.colorPrimary,borderRadius:e.borderRadiusSM,[`${n}-text`]:{color:e.badgeTextColor},[`${n}-corner`]:{position:"absolute",top:"100%",width:i,height:i,color:"currentcolor",border:`${(0,s.unit)(o(i).div(2).equal())} solid`,transform:e.badgeRibbonCornerTransform,transformOrigin:"top",filter:e.badgeRibbonCornerFilter}}),d),{[`&${n}-placement-end`]:{insetInlineEnd:o(i).mul(-1).equal(),borderEndEndRadius:0,[`${n}-corner`]:{insetInlineEnd:0,borderInlineEndColor:"transparent",borderBlockEndColor:"transparent"}},[`&${n}-placement-start`]:{insetInlineStart:o(i).mul(-1).equal(),borderEndStartRadius:0,[`${n}-corner`]:{insetInlineStart:0,borderBlockEndColor:"transparent",borderInlineStartColor:"transparent"}},"&-rtl":{direction:"rtl"}})}})(A(e)),y),C=e=>{let a,{prefixCls:i,value:o,current:n,offset:s=0}=e;return s&&(a={position:"absolute",top:`${s}00%`,left:0}),t.createElement("span",{style:a,className:(0,r.default)(`${i}-only-unit`,{current:n})},o)},I=e=>{let r,a,{prefixCls:i,count:o,value:n}=e,s=Number(n),l=Math.abs(o),[c,u]=t.useState(s),[d,m]=t.useState(l),g=()=>{u(s),m(l)};if(t.useEffect(()=>{let e=setTimeout(g,1e3);return()=>clearTimeout(e)},[s]),c===s||Number.isNaN(s)||Number.isNaN(c))r=[t.createElement(C,Object.assign({},e,{key:s,current:!0}))],a={transition:"none"};else{r=[];let i=s+10,o=[];for(let e=s;e<=i;e+=1)o.push(e);let n=de%10===c);r=(n<0?o.slice(0,u+1):o.slice(u)).map((r,a)=>t.createElement(C,Object.assign({},e,{key:r,value:r%10,offset:n<0?a-u:a,current:a===u}))),a={transform:`translateY(${-function(e,t,r){let a=e,i=0;for(;(a+10)%10!==t;)a+=r,i+=r;return i}(c,s,n)}00%)`}}return t.createElement("span",{className:`${i}-only`,style:a,onTransitionEnd:g},r)};var E=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,a=Object.getOwnPropertySymbols(e);it.indexOf(a[i])&&Object.prototype.propertyIsEnumerable.call(e,a[i])&&(r[a[i]]=e[a[i]]);return r};let $=t.forwardRef((e,a)=>{let{prefixCls:i,count:s,className:l,motionClassName:c,style:u,title:d,show:m,component:g="sup",children:p}=e,f=E(e,["prefixCls","count","className","motionClassName","style","title","show","component","children"]),{getPrefixCls:h}=t.useContext(n.ConfigContext),b=h("scroll-number",i),v=Object.assign(Object.assign({},f),{"data-show":m,style:u,className:(0,r.default)(b,l,c),title:d}),A=s;if(s&&Number(s)%1==0){let e=String(s).split("");A=t.createElement("bdi",null,e.map((r,a)=>t.createElement(I,{prefixCls:b,count:Number(s),value:r,key:e.length-a})))}return((null==u?void 0:u.borderColor)&&(v.style=Object.assign(Object.assign({},u),{boxShadow:`0 0 0 1px ${u.borderColor} inset`})),p)?(0,o.cloneElement)(p,e=>({className:(0,r.default)(`${b}-custom-component`,null==e?void 0:e.className,c)})):t.createElement(g,Object.assign({},v,{ref:a}),A)});var _=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,a=Object.getOwnPropertySymbols(e);it.indexOf(a[i])&&Object.prototype.propertyIsEnumerable.call(e,a[i])&&(r[a[i]]=e[a[i]]);return r};let T=t.forwardRef((e,s)=>{var l,c,u,d,m;let{prefixCls:g,scrollNumberPrefixCls:p,children:f,status:h,text:b,color:v,count:A=null,overflowCount:y=99,dot:x=!1,size:C="default",title:I,offset:E,style:T,className:w,rootClassName:S,classNames:N,styles:M,showZero:R=!1}=e,P=_(e,["prefixCls","scrollNumberPrefixCls","children","status","text","color","count","overflowCount","dot","size","title","offset","style","className","rootClassName","classNames","styles","showZero"]),{getPrefixCls:k,direction:j,badge:L}=t.useContext(n.ConfigContext),D=k("badge",g),[B,F,z]=O(D),H=A>y?`${y}+`:A,G="0"===H||0===H||"0"===b||0===b,V=null===A||G&&!R,W=(null!=h||null!=v)&&V,K=null!=h||!G,U=x&&!G,q=U?"":H,X=(0,t.useMemo)(()=>((null==q||""===q)&&(null==b||""===b)||G&&!R)&&!U,[q,G,R,U,b]),Q=(0,t.useRef)(A);X||(Q.current=A);let Z=Q.current,Y=(0,t.useRef)(q);X||(Y.current=q);let J=Y.current,ee=(0,t.useRef)(U);X||(ee.current=U);let et=(0,t.useMemo)(()=>{if(!E)return Object.assign(Object.assign({},null==L?void 0:L.style),T);let e={marginTop:E[1]};return"rtl"===j?e.left=Number.parseInt(E[0],10):e.right=-Number.parseInt(E[0],10),Object.assign(Object.assign(Object.assign({},e),null==L?void 0:L.style),T)},[j,E,T,null==L?void 0:L.style]),er=null!=I?I:"string"==typeof Z||"number"==typeof Z?Z:void 0,ea=!X&&(0===b?R:!!b&&!0!==b),ei=ea?t.createElement("span",{className:`${D}-status-text`},b):null,eo=Z&&"object"==typeof Z?(0,o.cloneElement)(Z,e=>({style:Object.assign(Object.assign({},et),e.style)})):void 0,en=(0,i.isPresetColor)(v,!1),es=(0,r.default)(null==N?void 0:N.indicator,null==(l=null==L?void 0:L.classNames)?void 0:l.indicator,{[`${D}-status-dot`]:W,[`${D}-status-${h}`]:!!h,[`${D}-color-${v}`]:en}),el={};v&&!en&&(el.color=v,el.background=v);let ec=(0,r.default)(D,{[`${D}-status`]:W,[`${D}-not-a-wrapper`]:!f,[`${D}-rtl`]:"rtl"===j},w,S,null==L?void 0:L.className,null==(c=null==L?void 0:L.classNames)?void 0:c.root,null==N?void 0:N.root,F,z);if(!f&&W&&(b||K||!V)){let e=et.color;return B(t.createElement("span",Object.assign({},P,{className:ec,style:Object.assign(Object.assign(Object.assign({},null==M?void 0:M.root),null==(u=null==L?void 0:L.styles)?void 0:u.root),et)}),t.createElement("span",{className:es,style:Object.assign(Object.assign(Object.assign({},null==M?void 0:M.indicator),null==(d=null==L?void 0:L.styles)?void 0:d.indicator),el)}),ea&&t.createElement("span",{style:{color:e},className:`${D}-status-text`},b)))}return B(t.createElement("span",Object.assign({ref:s},P,{className:ec,style:Object.assign(Object.assign({},null==(m=null==L?void 0:L.styles)?void 0:m.root),null==M?void 0:M.root)}),f,t.createElement(a.default,{visible:!X,motionName:`${D}-zoom`,motionAppear:!1,motionDeadline:1e3},({className:e})=>{var a,i;let o=k("scroll-number",p),n=ee.current,s=(0,r.default)(null==N?void 0:N.indicator,null==(a=null==L?void 0:L.classNames)?void 0:a.indicator,{[`${D}-dot`]:n,[`${D}-count`]:!n,[`${D}-count-sm`]:"small"===C,[`${D}-multiple-words`]:!n&&J&&J.toString().length>1,[`${D}-status-${h}`]:!!h,[`${D}-color-${v}`]:en}),l=Object.assign(Object.assign(Object.assign({},null==M?void 0:M.indicator),null==(i=null==L?void 0:L.styles)?void 0:i.indicator),et);return v&&!en&&((l=l||{}).background=v),t.createElement($,{prefixCls:o,show:!X,motionClassName:e,className:s,count:J,title:er,style:l,key:"scrollNumber"},eo)}),ei))});T.Ribbon=e=>{let{className:a,prefixCls:o,style:s,color:l,children:c,text:u,placement:d="end",rootClassName:m}=e,{getPrefixCls:g,direction:p}=t.useContext(n.ConfigContext),f=g("ribbon",o),h=`${f}-wrapper`,[b,v,A]=x(f,h),y=(0,i.isPresetColor)(l,!1),O=(0,r.default)(f,`${f}-placement-${d}`,{[`${f}-rtl`]:"rtl"===p,[`${f}-color-${l}`]:y},a),C={},I={};return l&&!y&&(C.background=l,I.color=l),b(t.createElement("div",{className:(0,r.default)(h,m,v,A)},c,t.createElement("div",{className:(0,r.default)(O,v),style:Object.assign(Object.assign({},C),s)},t.createElement("span",{className:`${f}-text`},u),t.createElement("div",{className:`${f}-corner`,style:I}))))},e.s(["Badge",0,T],906579)},621482,e=>{"use strict";var t=e.i(869230),r=e.i(992571),a=class extends t.QueryObserver{constructor(e,t){super(e,t)}bindMethods(){super.bindMethods(),this.fetchNextPage=this.fetchNextPage.bind(this),this.fetchPreviousPage=this.fetchPreviousPage.bind(this)}setOptions(e){super.setOptions({...e,behavior:(0,r.infiniteQueryBehavior)()})}getOptimisticResult(e){return e.behavior=(0,r.infiniteQueryBehavior)(),super.getOptimisticResult(e)}fetchNextPage(e){return this.fetch({...e,meta:{fetchMore:{direction:"forward"}}})}fetchPreviousPage(e){return this.fetch({...e,meta:{fetchMore:{direction:"backward"}}})}createResult(e,t){let{state:a}=e,i=super.createResult(e,t),{isFetching:o,isRefetching:n,isError:s,isRefetchError:l}=i,c=a.fetchMeta?.fetchMore?.direction,u=s&&"forward"===c,d=o&&"forward"===c,m=s&&"backward"===c,g=o&&"backward"===c;return{...i,fetchNextPage:this.fetchNextPage,fetchPreviousPage:this.fetchPreviousPage,hasNextPage:(0,r.hasNextPage)(t,a.data),hasPreviousPage:(0,r.hasPreviousPage)(t,a.data),isFetchNextPageError:u,isFetchingNextPage:d,isFetchPreviousPageError:m,isFetchingPreviousPage:g,isRefetchError:l&&!u&&!m,isRefetching:n&&!d&&!g}}},i=e.i(469637);function o(e,t){return(0,i.useBaseQuery)(e,a,t)}e.s(["useInfiniteQuery",()=>o],621482)},785242,e=>{"use strict";var t=e.i(619273),r=e.i(266027),a=e.i(912598),i=e.i(135214),o=e.i(270345),n=e.i(243652),s=e.i(764205);let l=(0,n.createQueryKeys)("teams"),c=async(e,t,r,a={})=>{try{let i=(0,s.getProxyBaseUrl)(),o=new URLSearchParams(Object.entries({team_id:a.teamID,organization_id:a.organizationID,team_alias:a.team_alias,user_id:a.userID,page:t,page_size:r,sort_by:a.sortBy,sort_order:a.sortOrder,status:"deleted"}).filter(([,e])=>null!=e).map(([e,t])=>[e,String(t)])),n=`${i?`${i}/v2/team/list`:"/v2/team/list"}?${o}`,l=await fetch(n,{method:"GET",headers:{[(0,s.getGlobalLitellmHeaderName)()]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!l.ok){let e=await l.json(),t=(0,s.deriveErrorMessage)(e);throw(0,s.handleError)(t),Error(t)}let c=await l.json();if(console.log("/team/list?status=deleted API Response:",c),c&&"object"==typeof c&&"teams"in c)return c.teams;return c}catch(e){throw console.error("Failed to list deleted teams:",e),e}},u=(0,n.createQueryKeys)("deletedTeams");e.s(["useDeletedTeams",0,(e,a,o={})=>{let{accessToken:n}=(0,i.default)();return(0,r.useQuery)({queryKey:u.list({page:e,limit:a,...o}),queryFn:async()=>await c(n,e,a,o),enabled:!!n,staleTime:3e4,placeholderData:t.keepPreviousData})},"useTeam",0,e=>{let{accessToken:t}=(0,i.default)(),o=(0,a.useQueryClient)();return(0,r.useQuery)({queryKey:l.detail(e),enabled:!!(t&&e),queryFn:async()=>{if(!t||!e)throw Error("Missing auth or teamId");return(0,s.teamInfoCall)(t,e)},initialData:()=>{if(!e)return;let t=o.getQueryData(l.list({}));return t?.find(t=>t.team_id===e)}})},"useTeams",0,()=>{let{accessToken:e,userId:t,userRole:a}=(0,i.default)();return(0,r.useQuery)({queryKey:l.list({}),queryFn:async()=>await (0,o.fetchTeams)(e,t,a,null),enabled:!!e})}])},980187,e=>{"use strict";e.s(["createTeamAliasMap",0,e=>e?e.reduce((e,t)=>(e[t.team_id]=t.team_alias,e),{}):{},"resolveTeamAliasFromTeamID",0,(e,t)=>{let r=t.find(t=>t.team_id===e);return r?r.team_alias:null}])},571303,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(115504);function i({className:e="",...i}){var o,n;let s=(0,r.useId)();return o=()=>{let e=document.getAnimations().filter(e=>e instanceof CSSAnimation&&"spin"===e.animationName),t=e.find(e=>e.effect.target?.getAttribute("data-spinner-id")===s),r=e.find(e=>e.effect instanceof KeyframeEffect&&e.effect.target?.getAttribute("data-spinner-id")!==s);t&&r&&(t.currentTime=r.currentTime)},n=[s],(0,r.useLayoutEffect)(o,n),(0,t.jsxs)("svg",{"data-spinner-id":s,className:(0,a.cx)("pointer-events-none size-12 animate-spin text-current",e),fill:"none",viewBox:"0 0 24 24",...i,children:[(0,t.jsx)("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),(0,t.jsx)("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]})}e.s(["UiLoadingSpinner",()=>i],571303)},366283,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(95779),i=e.i(444755),o=e.i(673706);let n=(0,o.makeClassName)("Callout"),s=r.default.forwardRef((e,s)=>{let{title:l,icon:c,color:u,className:d,children:m}=e,g=(0,t.__rest)(e,["title","icon","color","className","children"]);return r.default.createElement("div",Object.assign({ref:s,className:(0,i.tremorTwMerge)(n("root"),"flex flex-col overflow-hidden rounded-tremor-default text-tremor-default border-l-4 py-3 pr-3 pl-4",u?(0,i.tremorTwMerge)((0,o.getColorClassNames)(u,a.colorPalette.background).bgColor,(0,o.getColorClassNames)(u,a.colorPalette.darkBorder).borderColor,(0,o.getColorClassNames)(u,a.colorPalette.darkText).textColor,"dark:bg-opacity-10 bg-opacity-10"):(0,i.tremorTwMerge)("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"),d)},g),r.default.createElement("div",{className:(0,i.tremorTwMerge)(n("header"),"flex items-start")},c?r.default.createElement(c,{className:(0,i.tremorTwMerge)(n("icon"),"flex-none h-5 w-5 mr-1.5")}):null,r.default.createElement("h4",{className:(0,i.tremorTwMerge)(n("title"),"font-semibold")},l)),r.default.createElement("p",{className:(0,i.tremorTwMerge)(n("body"),"overflow-y-auto",m?"mt-2":"")},m))});s.displayName="Callout",e.s(["Callout",()=>s],366283)},418371,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(916925);e.s(["ProviderLogo",0,({provider:e,className:i="w-4 h-4"})=>{let[o,n]=(0,r.useState)(!1),{logo:s}=(0,a.getProviderLogoAndName)(e);return o||!s?(0,t.jsx)("div",{className:`${i} rounded-full bg-gray-200 flex items-center justify-center text-xs`,children:e?.charAt(0)||"-"}):(0,t.jsx)("img",{src:s,alt:`${e} logo`,className:i,onError:()=>n(!0)})}])},37091,e=>{"use strict";var t=e.i(290571),r=e.i(95779),a=e.i(444755),i=e.i(673706),o=e.i(271645);let n=o.default.forwardRef((e,n)=>{let{color:s,children:l,className:c}=e,u=(0,t.__rest)(e,["color","children","className"]);return o.default.createElement("p",Object.assign({ref:n,className:(0,a.tremorTwMerge)(s?(0,i.getColorClassNames)(s,r.colorPalette.lightText).textColor:"text-tremor-content-emphasis dark:text-dark-tremor-content-emphasis",c)},u),l)});n.displayName="Subtitle",e.s(["Subtitle",()=>n],37091)},214541,e=>{"use strict";var t=e.i(271645),r=e.i(135214),a=e.i(270345);e.s(["default",0,()=>{let[e,i]=(0,t.useState)([]),{accessToken:o,userId:n,userRole:s}=(0,r.default)();return(0,t.useEffect)(()=>{(async()=>{i(await (0,a.fetchTeams)(o,n,s,null))})()},[o,n,s]),{teams:e,setTeams:i}}])},439189,435684,96226,497245,e=>{"use strict";function t(e){let t=Object.prototype.toString.call(e);return e instanceof Date||"object"==typeof e&&"[object Date]"===t?new e.constructor(+e):new Date("number"==typeof e||"[object Number]"===t||"string"==typeof e||"[object String]"===t?e:NaN)}function r(e,t){return e instanceof Date?new e.constructor(t):new Date(t)}function a(e,a){let i=t(e);return isNaN(a)?r(e,NaN):(a&&i.setDate(i.getDate()+a),i)}function i(e,a){let i=t(e);if(isNaN(a))return r(e,NaN);if(!a)return i;let o=i.getDate(),n=r(e,i.getTime());return(n.setMonth(i.getMonth()+a+1,0),o>=n.getDate())?n:(i.setFullYear(n.getFullYear(),n.getMonth(),o),i)}e.s(["toDate",()=>t],435684),e.s(["constructFrom",()=>r],96226),e.s(["addDays",()=>a],439189),e.s(["addMonths",()=>i],497245)},891547,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(199133),i=e.i(764205);e.s(["default",0,({onChange:e,value:o,className:n,accessToken:s,disabled:l})=>{let[c,u]=(0,r.useState)([]),[d,m]=(0,r.useState)(!1);return(0,r.useEffect)(()=>{(async()=>{if(s){m(!0);try{let e=await (0,i.getGuardrailsList)(s);console.log("Guardrails response:",e),e.guardrails&&(console.log("Guardrails data:",e.guardrails),u(e.guardrails))}catch(e){console.error("Error fetching guardrails:",e)}finally{m(!1)}}})()},[s]),(0,t.jsx)("div",{children:(0,t.jsx)(a.Select,{mode:"multiple",disabled:l,placeholder:l?"Setting guardrails is a premium feature.":"Select guardrails",onChange:t=>{console.log("Selected guardrails:",t),e(t)},value:o,loading:d,className:n,allowClear:!0,options:c.map(e=>(console.log("Mapping guardrail:",e),{label:`${e.guardrail_name}`,value:e.guardrail_name})),optionFilterProp:"label",showSearch:!0,style:{width:"100%"}})})}])},921511,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(199133),i=e.i(764205);function o(e){return e.filter(e=>(e.version_status??"draft")!=="draft").map(e=>{var t;let r=e.version_number??1,a=e.version_status??"draft";return{label:`${e.policy_name} — v${r} (${a})${e.description?` — ${e.description}`:""}`,value:"production"===a?e.policy_name:e.policy_id?(t=e.policy_id,`policy_${t}`):e.policy_name}})}e.s(["default",0,({onChange:e,value:n,className:s,accessToken:l,disabled:c,onPoliciesLoaded:u})=>{let[d,m]=(0,r.useState)([]),[g,p]=(0,r.useState)(!1);return(0,r.useEffect)(()=>{(async()=>{if(l){p(!0);try{let e=await (0,i.getPoliciesList)(l);e.policies&&(m(e.policies),u?.(e.policies))}catch(e){console.error("Error fetching policies:",e)}finally{p(!1)}}})()},[l,u]),(0,t.jsx)("div",{children:(0,t.jsx)(a.Select,{mode:"multiple",disabled:c,placeholder:c?"Setting policies is a premium feature.":"Select policies (production or published versions)",onChange:t=>{e(t)},value:n,loading:g,className:s,allowClear:!0,options:o(d),optionFilterProp:"label",showSearch:!0,style:{width:"100%"}})})},"getPolicyOptionEntries",()=>o])},637235,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let a={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"};var i=e.i(9583),o=r.forwardRef(function(e,o){return r.createElement(i.default,(0,t.default)({},e,{ref:o,icon:a}))});e.s(["ClockCircleOutlined",0,o],637235)},646563,e=>{"use strict";var t=e.i(959013);e.s(["PlusOutlined",()=>t.default])},447566,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let a={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M872 474H286.9l350.2-304c5.6-4.9 2.2-14-5.2-14h-88.5c-3.9 0-7.6 1.4-10.5 3.9L155 487.8a31.96 31.96 0 000 48.3L535.1 866c1.5 1.3 3.3 2 5.2 2h91.5c7.4 0 10.8-9.2 5.2-14L286.9 550H872c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"}}]},name:"arrow-left",theme:"outlined"};var i=e.i(9583),o=r.forwardRef(function(e,o){return r.createElement(i.default,(0,t.default)({},e,{ref:o,icon:a}))});e.s(["ArrowLeftOutlined",0,o],447566)},954616,e=>{"use strict";var t=e.i(271645),r=e.i(114272),a=e.i(540143),i=e.i(915823),o=e.i(619273),n=class extends i.Subscribable{#e;#t=void 0;#r;#a;constructor(e,t){super(),this.#e=e,this.setOptions(t),this.bindMethods(),this.#i()}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(e){let t=this.options;this.options=this.#e.defaultMutationOptions(e),(0,o.shallowEqualObjects)(this.options,t)||this.#e.getMutationCache().notify({type:"observerOptionsUpdated",mutation:this.#r,observer:this}),t?.mutationKey&&this.options.mutationKey&&(0,o.hashKey)(t.mutationKey)!==(0,o.hashKey)(this.options.mutationKey)?this.reset():this.#r?.state.status==="pending"&&this.#r.setOptions(this.options)}onUnsubscribe(){this.hasListeners()||this.#r?.removeObserver(this)}onMutationUpdate(e){this.#i(),this.#o(e)}getCurrentResult(){return this.#t}reset(){this.#r?.removeObserver(this),this.#r=void 0,this.#i(),this.#o()}mutate(e,t){return this.#a=t,this.#r?.removeObserver(this),this.#r=this.#e.getMutationCache().build(this.#e,this.options),this.#r.addObserver(this),this.#r.execute(e)}#i(){let e=this.#r?.state??(0,r.getDefaultState)();this.#t={...e,isPending:"pending"===e.status,isSuccess:"success"===e.status,isError:"error"===e.status,isIdle:"idle"===e.status,mutate:this.mutate,reset:this.reset}}#o(e){a.notifyManager.batch(()=>{if(this.#a&&this.hasListeners()){let t=this.#t.variables,r=this.#t.context,a={client:this.#e,meta:this.options.meta,mutationKey:this.options.mutationKey};if(e?.type==="success"){try{this.#a.onSuccess?.(e.data,t,r,a)}catch(e){Promise.reject(e)}try{this.#a.onSettled?.(e.data,null,t,r,a)}catch(e){Promise.reject(e)}}else if(e?.type==="error"){try{this.#a.onError?.(e.error,t,r,a)}catch(e){Promise.reject(e)}try{this.#a.onSettled?.(void 0,e.error,t,r,a)}catch(e){Promise.reject(e)}}}this.listeners.forEach(e=>{e(this.#t)})})}},s=e.i(912598);function l(e,r){let i=(0,s.useQueryClient)(r),[l]=t.useState(()=>new n(i,e));t.useEffect(()=>{l.setOptions(e)},[l,e]);let c=t.useSyncExternalStore(t.useCallback(e=>l.subscribe(a.notifyManager.batchCalls(e)),[l]),()=>l.getCurrentResult(),()=>l.getCurrentResult()),u=t.useCallback((e,t)=>{l.mutate(e,t).catch(o.noop)},[l]);if(c.error&&(0,o.shouldThrowError)(l.options.throwOnError,[c.error]))throw c.error;return{...c,mutate:u,mutateAsync:c.mutate}}e.s(["useMutation",()=>l],954616)},525720,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(529681),i=e.i(908286),o=e.i(242064),n=e.i(246422),s=e.i(838378);let l=["wrap","nowrap","wrap-reverse"],c=["flex-start","flex-end","start","end","center","space-between","space-around","space-evenly","stretch","normal","left","right"],u=["center","start","end","flex-start","flex-end","self-start","self-end","baseline","normal","stretch"],d=function(e,t){let a,i,o;return(0,r.default)(Object.assign(Object.assign(Object.assign({},(a=!0===t.wrap?"wrap":t.wrap,{[`${e}-wrap-${a}`]:a&&l.includes(a)})),(i={},u.forEach(r=>{i[`${e}-align-${r}`]=t.align===r}),i[`${e}-align-stretch`]=!t.align&&!!t.vertical,i)),(o={},c.forEach(r=>{o[`${e}-justify-${r}`]=t.justify===r}),o)))},m=(0,n.genStyleHooks)("Flex",e=>{let{paddingXS:t,padding:r,paddingLG:a}=e,i=(0,s.mergeToken)(e,{flexGapSM:t,flexGap:r,flexGapLG:a});return[(e=>{let{componentCls:t}=e;return{[t]:{display:"flex",margin:0,padding:0,"&-vertical":{flexDirection:"column"},"&-rtl":{direction:"rtl"},"&:empty":{display:"none"}}}})(i),(e=>{let{componentCls:t}=e;return{[t]:{"&-gap-small":{gap:e.flexGapSM},"&-gap-middle":{gap:e.flexGap},"&-gap-large":{gap:e.flexGapLG}}}})(i),(e=>{let{componentCls:t}=e,r={};return l.forEach(e=>{r[`${t}-wrap-${e}`]={flexWrap:e}}),r})(i),(e=>{let{componentCls:t}=e,r={};return u.forEach(e=>{r[`${t}-align-${e}`]={alignItems:e}}),r})(i),(e=>{let{componentCls:t}=e,r={};return c.forEach(e=>{r[`${t}-justify-${e}`]={justifyContent:e}}),r})(i)]},()=>({}),{resetStyle:!1});var g=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,a=Object.getOwnPropertySymbols(e);it.indexOf(a[i])&&Object.prototype.propertyIsEnumerable.call(e,a[i])&&(r[a[i]]=e[a[i]]);return r};let p=t.default.forwardRef((e,n)=>{let{prefixCls:s,rootClassName:l,className:c,style:u,flex:p,gap:f,vertical:h=!1,component:b="div",children:v}=e,A=g(e,["prefixCls","rootClassName","className","style","flex","gap","vertical","component","children"]),{flex:y,direction:O,getPrefixCls:x}=t.default.useContext(o.ConfigContext),C=x("flex",s),[I,E,$]=m(C),_=null!=h?h:null==y?void 0:y.vertical,T=(0,r.default)(c,l,null==y?void 0:y.className,C,E,$,d(C,e),{[`${C}-rtl`]:"rtl"===O,[`${C}-gap-${f}`]:(0,i.isPresetSize)(f),[`${C}-vertical`]:_}),w=Object.assign(Object.assign({},null==y?void 0:y.style),u);return p&&(w.flex=p),f&&!(0,i.isPresetSize)(f)&&(w.gap=f),I(t.default.createElement(b,Object.assign({ref:n,className:T,style:w},(0,a.default)(A,["justify","wrap","align"])),v))});e.s(["Flex",0,p],525720)},149121,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(152990),i=e.i(682830),o=e.i(269200),n=e.i(427612),s=e.i(64848),l=e.i(942232),c=e.i(496020),u=e.i(977572);function d({data:e=[],columns:d,onRowClick:m,renderSubComponent:g,renderChildRows:p,getRowCanExpand:f,isLoading:h=!1,loadingMessage:b="🚅 Loading logs...",noDataMessage:v="No logs found",enableSorting:A=!1}){let y=!!(g||p)&&!!f,[O,x]=(0,r.useState)([]),C=(0,a.useReactTable)({data:e,columns:d,...A&&{state:{sorting:O},onSortingChange:x,enableSortingRemoval:!1},...y&&{getRowCanExpand:f},getRowId:(e,t)=>e?.request_id??String(t),getCoreRowModel:(0,i.getCoreRowModel)(),...A&&{getSortedRowModel:(0,i.getSortedRowModel)()},...y&&{getExpandedRowModel:(0,i.getExpandedRowModel)()}});return(0,t.jsx)("div",{className:"rounded-lg custom-border overflow-x-auto w-full max-w-full box-border",children:(0,t.jsxs)(o.Table,{className:"[&_td]:py-0.5 [&_th]:py-1 table-fixed w-full box-border",style:{minWidth:"400px"},children:[(0,t.jsx)(n.TableHead,{children:C.getHeaderGroups().map(e=>(0,t.jsx)(c.TableRow,{children:e.headers.map(e=>{let r=A&&e.column.getCanSort(),i=e.column.getIsSorted();return(0,t.jsx)(s.TableHeaderCell,{className:`py-1 h-8 ${r?"cursor-pointer select-none hover:bg-gray-50":""}`,onClick:r?e.column.getToggleSortingHandler():void 0,children:e.isPlaceholder?null:(0,t.jsxs)("div",{className:"flex items-center gap-1",children:[(0,a.flexRender)(e.column.columnDef.header,e.getContext()),r&&(0,t.jsx)("span",{className:"text-gray-400",children:"asc"===i?"↑":"desc"===i?"↓":"⇅"})]})},e.id)})},e.id))}),(0,t.jsx)(l.TableBody,{children:h?(0,t.jsx)(c.TableRow,{children:(0,t.jsx)(u.TableCell,{colSpan:d.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:b})})})}):C.getRowModel().rows.length>0?C.getRowModel().rows.map(e=>(0,t.jsxs)(r.Fragment,{children:[(0,t.jsx)(c.TableRow,{className:`h-8 ${m?"cursor-pointer hover:bg-gray-50":""}`,onClick:()=>m?.(e.original),children:e.getVisibleCells().map(e=>(0,t.jsx)(u.TableCell,{className:"py-0.5 max-h-8 overflow-hidden text-ellipsis whitespace-nowrap",children:(0,a.flexRender)(e.column.columnDef.cell,e.getContext())},e.id))}),y&&e.getIsExpanded()&&p&&p({row:e}),y&&e.getIsExpanded()&&g&&!p&&(0,t.jsx)(c.TableRow,{children:(0,t.jsx)(u.TableCell,{colSpan:e.getVisibleCells().length,className:"p-0",children:(0,t.jsx)("div",{className:"w-full max-w-full overflow-hidden box-border",children:g({row:e})})})})]},e.id)):(0,t.jsx)(c.TableRow,{children:(0,t.jsx)(u.TableCell,{colSpan:d.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:v})})})})})]})})}e.s(["DataTable",()=>d])},986888,e=>{"use strict";var t=e.i(843476),r=e.i(797305),a=e.i(135214),i=e.i(214541);e.s(["default",0,()=>{let{accessToken:e,userRole:o,userId:n,premiumUser:s}=(0,a.default)(),{teams:l}=(0,i.default)();return(0,t.jsx)(r.default,{teams:l??[],organizations:[]})}])},601236,e=>{e.v(e=>Promise.resolve().then(()=>e(764205)))}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/31ad6450b9c696ec.js b/litellm/proxy/_experimental/out/_next/static/chunks/31ad6450b9c696ec.js deleted file mode 100644 index de88919e32..0000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/31ad6450b9c696ec.js +++ /dev/null @@ -1 +0,0 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,367240,555436,e=>{"use strict";let t=(0,e.i(475254).default)("rotate-ccw",[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}]]);e.s(["RotateCcw",()=>t],367240);var l=e.i(54943);e.s(["Search",()=>l.default],555436)},846753,e=>{"use strict";let t=(0,e.i(475254).default)("user",[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]]);e.s(["default",()=>t])},655913,38419,78334,e=>{"use strict";var t=e.i(843476),l=e.i(115504),a=e.i(311451),i=e.i(374009),r=e.i(271645);e.s(["FilterInput",0,({placeholder:e,value:s,onChange:n,icon:o,className:d})=>{let[c,m]=(0,r.useState)(s);(0,r.useEffect)(()=>{m(s)},[s]);let u=(0,r.useMemo)(()=>(0,i.default)(e=>n(e),300),[n]);(0,r.useEffect)(()=>()=>{u.cancel()},[u]);let g=(0,r.useCallback)(e=>{let t=e.target.value;m(t),u(t)},[u]);return(0,t.jsx)(a.Input,{placeholder:e,value:c,onChange:g,prefix:o?(0,t.jsx)(o,{size:16,className:"text-gray-500"}):void 0,className:(0,l.cx)("w-64",d)})}],655913);var s=e.i(906579),n=e.i(464571);let o=(0,e.i(475254).default)("funnel",[["path",{d:"M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z",key:"sc7q7i"}]]);e.s(["FiltersButton",0,({onClick:e,active:l,hasActiveFilters:a,label:i="Filters"})=>(0,t.jsx)(s.Badge,{color:"blue",dot:a,children:(0,t.jsx)(n.Button,{type:"default",onClick:e,icon:(0,t.jsx)(o,{size:16}),className:l?"bg-gray-100":"",children:i})})],38419);var d=e.i(367240);e.s(["ResetFiltersButton",0,({onClick:e,label:l="Reset Filters"})=>(0,t.jsx)(n.Button,{type:"default",onClick:e,icon:(0,t.jsx)(d.RotateCcw,{size:16}),children:l})],78334)},284614,e=>{"use strict";var t=e.i(846753);e.s(["User",()=>t.default])},906579,e=>{"use strict";e.i(247167);var t=e.i(271645),l=e.i(343794),a=e.i(361275),i=e.i(702779),r=e.i(763731),s=e.i(242064);e.i(296059);var n=e.i(915654),o=e.i(694758),d=e.i(183293),c=e.i(403541),m=e.i(246422),u=e.i(838378);let g=new o.Keyframes("antStatusProcessing",{"0%":{transform:"scale(0.8)",opacity:.5},"100%":{transform:"scale(2.4)",opacity:0}}),x=new o.Keyframes("antZoomBadgeIn",{"0%":{transform:"scale(0) translate(50%, -50%)",opacity:0},"100%":{transform:"scale(1) translate(50%, -50%)"}}),h=new o.Keyframes("antZoomBadgeOut",{"0%":{transform:"scale(1) translate(50%, -50%)"},"100%":{transform:"scale(0) translate(50%, -50%)",opacity:0}}),b=new o.Keyframes("antNoWrapperZoomBadgeIn",{"0%":{transform:"scale(0)",opacity:0},"100%":{transform:"scale(1)"}}),p=new o.Keyframes("antNoWrapperZoomBadgeOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0)",opacity:0}}),_=new o.Keyframes("antBadgeLoadingCircle",{"0%":{transformOrigin:"50%"},"100%":{transform:"translate(50%, -50%) rotate(360deg)",transformOrigin:"50%"}}),f=e=>{let{fontHeight:t,lineWidth:l,marginXS:a,colorBorderBg:i}=e,r=e.colorTextLightSolid,s=e.colorError,n=e.colorErrorHover;return(0,u.mergeToken)(e,{badgeFontHeight:t,badgeShadowSize:l,badgeTextColor:r,badgeColor:s,badgeColorHover:n,badgeShadowColor:i,badgeProcessingDuration:"1.2s",badgeRibbonOffset:a,badgeRibbonCornerTransform:"scaleY(0.75)",badgeRibbonCornerFilter:"brightness(75%)"})},j=e=>{let{fontSize:t,lineHeight:l,fontSizeSM:a,lineWidth:i}=e;return{indicatorZIndex:"auto",indicatorHeight:Math.round(t*l)-2*i,indicatorHeightSM:t,dotSize:a/2,textFontSize:a,textFontSizeSM:a,textFontWeight:"normal",statusSize:a/2}},v=(0,m.genStyleHooks)("Badge",e=>(e=>{let{componentCls:t,iconCls:l,antCls:a,badgeShadowSize:i,textFontSize:r,textFontSizeSM:s,statusSize:o,dotSize:m,textFontWeight:u,indicatorHeight:f,indicatorHeightSM:j,marginXS:v,calc:y}=e,C=`${a}-scroll-number`,w=(0,c.genPresetColor)(e,(e,{darkColor:l})=>({[`&${t} ${t}-color-${e}`]:{background:l,[`&:not(${t}-count)`]:{color:l},"a:hover &":{background:l}}}));return{[t]:Object.assign(Object.assign(Object.assign(Object.assign({},(0,d.resetComponent)(e)),{position:"relative",display:"inline-block",width:"fit-content",lineHeight:1,[`${t}-count`]:{display:"inline-flex",justifyContent:"center",zIndex:e.indicatorZIndex,minWidth:f,height:f,color:e.badgeTextColor,fontWeight:u,fontSize:r,lineHeight:(0,n.unit)(f),whiteSpace:"nowrap",textAlign:"center",background:e.badgeColor,borderRadius:y(f).div(2).equal(),boxShadow:`0 0 0 ${(0,n.unit)(i)} ${e.badgeShadowColor}`,transition:`background ${e.motionDurationMid}`,a:{color:e.badgeTextColor},"a:hover":{color:e.badgeTextColor},"a:hover &":{background:e.badgeColorHover}},[`${t}-count-sm`]:{minWidth:j,height:j,fontSize:s,lineHeight:(0,n.unit)(j),borderRadius:y(j).div(2).equal()},[`${t}-multiple-words`]:{padding:`0 ${(0,n.unit)(e.paddingXS)}`,bdi:{unicodeBidi:"plaintext"}},[`${t}-dot`]:{zIndex:e.indicatorZIndex,width:m,minWidth:m,height:m,background:e.badgeColor,borderRadius:"100%",boxShadow:`0 0 0 ${(0,n.unit)(i)} ${e.badgeShadowColor}`},[`${t}-count, ${t}-dot, ${C}-custom-component`]:{position:"absolute",top:0,insetInlineEnd:0,transform:"translate(50%, -50%)",transformOrigin:"100% 0%",[`&${l}-spin`]:{animationName:_,animationDuration:"1s",animationIterationCount:"infinite",animationTimingFunction:"linear"}},[`&${t}-status`]:{lineHeight:"inherit",verticalAlign:"baseline",[`${t}-status-dot`]:{position:"relative",top:-1,display:"inline-block",width:o,height:o,verticalAlign:"middle",borderRadius:"50%"},[`${t}-status-success`]:{backgroundColor:e.colorSuccess},[`${t}-status-processing`]:{overflow:"visible",color:e.colorInfo,backgroundColor:e.colorInfo,borderColor:"currentcolor","&::after":{position:"absolute",top:0,insetInlineStart:0,width:"100%",height:"100%",borderWidth:i,borderStyle:"solid",borderColor:"inherit",borderRadius:"50%",animationName:g,animationDuration:e.badgeProcessingDuration,animationIterationCount:"infinite",animationTimingFunction:"ease-in-out",content:'""'}},[`${t}-status-default`]:{backgroundColor:e.colorTextPlaceholder},[`${t}-status-error`]:{backgroundColor:e.colorError},[`${t}-status-warning`]:{backgroundColor:e.colorWarning},[`${t}-status-text`]:{marginInlineStart:v,color:e.colorText,fontSize:e.fontSize}}}),w),{[`${t}-zoom-appear, ${t}-zoom-enter`]:{animationName:x,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack,animationFillMode:"both"},[`${t}-zoom-leave`]:{animationName:h,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack,animationFillMode:"both"},[`&${t}-not-a-wrapper`]:{[`${t}-zoom-appear, ${t}-zoom-enter`]:{animationName:b,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack},[`${t}-zoom-leave`]:{animationName:p,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack},[`&:not(${t}-status)`]:{verticalAlign:"middle"},[`${C}-custom-component, ${t}-count`]:{transform:"none"},[`${C}-custom-component, ${C}`]:{position:"relative",top:"auto",display:"block",transformOrigin:"50% 50%"}},[C]:{overflow:"hidden",transition:`all ${e.motionDurationMid} ${e.motionEaseOutBack}`,[`${C}-only`]:{position:"relative",display:"inline-block",height:f,transition:`all ${e.motionDurationSlow} ${e.motionEaseOutBack}`,WebkitTransformStyle:"preserve-3d",WebkitBackfaceVisibility:"hidden",[`> p${C}-only-unit`]:{height:f,margin:0,WebkitTransformStyle:"preserve-3d",WebkitBackfaceVisibility:"hidden"}},[`${C}-symbol`]:{verticalAlign:"top"}},"&-rtl":{direction:"rtl",[`${t}-count, ${t}-dot, ${C}-custom-component`]:{transform:"translate(-50%, -50%)"}}})}})(f(e)),j),y=(0,m.genStyleHooks)(["Badge","Ribbon"],e=>(e=>{let{antCls:t,badgeFontHeight:l,marginXS:a,badgeRibbonOffset:i,calc:r}=e,s=`${t}-ribbon`,o=`${t}-ribbon-wrapper`,m=(0,c.genPresetColor)(e,(e,{darkColor:t})=>({[`&${s}-color-${e}`]:{background:t,color:t}}));return{[o]:{position:"relative"},[s]:Object.assign(Object.assign(Object.assign(Object.assign({},(0,d.resetComponent)(e)),{position:"absolute",top:a,padding:`0 ${(0,n.unit)(e.paddingXS)}`,color:e.colorPrimary,lineHeight:(0,n.unit)(l),whiteSpace:"nowrap",backgroundColor:e.colorPrimary,borderRadius:e.borderRadiusSM,[`${s}-text`]:{color:e.badgeTextColor},[`${s}-corner`]:{position:"absolute",top:"100%",width:i,height:i,color:"currentcolor",border:`${(0,n.unit)(r(i).div(2).equal())} solid`,transform:e.badgeRibbonCornerTransform,transformOrigin:"top",filter:e.badgeRibbonCornerFilter}}),m),{[`&${s}-placement-end`]:{insetInlineEnd:r(i).mul(-1).equal(),borderEndEndRadius:0,[`${s}-corner`]:{insetInlineEnd:0,borderInlineEndColor:"transparent",borderBlockEndColor:"transparent"}},[`&${s}-placement-start`]:{insetInlineStart:r(i).mul(-1).equal(),borderEndStartRadius:0,[`${s}-corner`]:{insetInlineStart:0,borderBlockEndColor:"transparent",borderInlineStartColor:"transparent"}},"&-rtl":{direction:"rtl"}})}})(f(e)),j),C=e=>{let a,{prefixCls:i,value:r,current:s,offset:n=0}=e;return n&&(a={position:"absolute",top:`${n}00%`,left:0}),t.createElement("span",{style:a,className:(0,l.default)(`${i}-only-unit`,{current:s})},r)},w=e=>{let l,a,{prefixCls:i,count:r,value:s}=e,n=Number(s),o=Math.abs(r),[d,c]=t.useState(n),[m,u]=t.useState(o),g=()=>{c(n),u(o)};if(t.useEffect(()=>{let e=setTimeout(g,1e3);return()=>clearTimeout(e)},[n]),d===n||Number.isNaN(n)||Number.isNaN(d))l=[t.createElement(C,Object.assign({},e,{key:n,current:!0}))],a={transition:"none"};else{l=[];let i=n+10,r=[];for(let e=n;e<=i;e+=1)r.push(e);let s=me%10===d);l=(s<0?r.slice(0,c+1):r.slice(c)).map((l,a)=>t.createElement(C,Object.assign({},e,{key:l,value:l%10,offset:s<0?a-c:a,current:a===c}))),a={transform:`translateY(${-function(e,t,l){let a=e,i=0;for(;(a+10)%10!==t;)a+=l,i+=l;return i}(d,n,s)}00%)`}}return t.createElement("span",{className:`${i}-only`,style:a,onTransitionEnd:g},l)};var N=function(e,t){var l={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(l[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,a=Object.getOwnPropertySymbols(e);it.indexOf(a[i])&&Object.prototype.propertyIsEnumerable.call(e,a[i])&&(l[a[i]]=e[a[i]]);return l};let T=t.forwardRef((e,a)=>{let{prefixCls:i,count:n,className:o,motionClassName:d,style:c,title:m,show:u,component:g="sup",children:x}=e,h=N(e,["prefixCls","count","className","motionClassName","style","title","show","component","children"]),{getPrefixCls:b}=t.useContext(s.ConfigContext),p=b("scroll-number",i),_=Object.assign(Object.assign({},h),{"data-show":u,style:c,className:(0,l.default)(p,o,d),title:m}),f=n;if(n&&Number(n)%1==0){let e=String(n).split("");f=t.createElement("bdi",null,e.map((l,a)=>t.createElement(w,{prefixCls:p,count:Number(n),value:l,key:e.length-a})))}return((null==c?void 0:c.borderColor)&&(_.style=Object.assign(Object.assign({},c),{boxShadow:`0 0 0 1px ${c.borderColor} inset`})),x)?(0,r.cloneElement)(x,e=>({className:(0,l.default)(`${p}-custom-component`,null==e?void 0:e.className,d)})):t.createElement(g,Object.assign({},_,{ref:a}),f)});var z=function(e,t){var l={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(l[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,a=Object.getOwnPropertySymbols(e);it.indexOf(a[i])&&Object.prototype.propertyIsEnumerable.call(e,a[i])&&(l[a[i]]=e[a[i]]);return l};let S=t.forwardRef((e,n)=>{var o,d,c,m,u;let{prefixCls:g,scrollNumberPrefixCls:x,children:h,status:b,text:p,color:_,count:f=null,overflowCount:j=99,dot:y=!1,size:C="default",title:w,offset:N,style:S,className:O,rootClassName:$,classNames:k,styles:I,showZero:F=!1}=e,M=z(e,["prefixCls","scrollNumberPrefixCls","children","status","text","color","count","overflowCount","dot","size","title","offset","style","className","rootClassName","classNames","styles","showZero"]),{getPrefixCls:E,direction:B,badge:R}=t.useContext(s.ConfigContext),D=E("badge",g),[P,A,L]=v(D),H=f>j?`${j}+`:f,U="0"===H||0===H||"0"===p||0===p,V=null===f||U&&!F,W=(null!=b||null!=_)&&V,q=null!=b||!U,G=y&&!U,K=G?"":H,Z=(0,t.useMemo)(()=>((null==K||""===K)&&(null==p||""===p)||U&&!F)&&!G,[K,U,F,G,p]),J=(0,t.useRef)(f);Z||(J.current=f);let Y=J.current,Q=(0,t.useRef)(K);Z||(Q.current=K);let X=Q.current,ee=(0,t.useRef)(G);Z||(ee.current=G);let et=(0,t.useMemo)(()=>{if(!N)return Object.assign(Object.assign({},null==R?void 0:R.style),S);let e={marginTop:N[1]};return"rtl"===B?e.left=Number.parseInt(N[0],10):e.right=-Number.parseInt(N[0],10),Object.assign(Object.assign(Object.assign({},e),null==R?void 0:R.style),S)},[B,N,S,null==R?void 0:R.style]),el=null!=w?w:"string"==typeof Y||"number"==typeof Y?Y:void 0,ea=!Z&&(0===p?F:!!p&&!0!==p),ei=ea?t.createElement("span",{className:`${D}-status-text`},p):null,er=Y&&"object"==typeof Y?(0,r.cloneElement)(Y,e=>({style:Object.assign(Object.assign({},et),e.style)})):void 0,es=(0,i.isPresetColor)(_,!1),en=(0,l.default)(null==k?void 0:k.indicator,null==(o=null==R?void 0:R.classNames)?void 0:o.indicator,{[`${D}-status-dot`]:W,[`${D}-status-${b}`]:!!b,[`${D}-color-${_}`]:es}),eo={};_&&!es&&(eo.color=_,eo.background=_);let ed=(0,l.default)(D,{[`${D}-status`]:W,[`${D}-not-a-wrapper`]:!h,[`${D}-rtl`]:"rtl"===B},O,$,null==R?void 0:R.className,null==(d=null==R?void 0:R.classNames)?void 0:d.root,null==k?void 0:k.root,A,L);if(!h&&W&&(p||q||!V)){let e=et.color;return P(t.createElement("span",Object.assign({},M,{className:ed,style:Object.assign(Object.assign(Object.assign({},null==I?void 0:I.root),null==(c=null==R?void 0:R.styles)?void 0:c.root),et)}),t.createElement("span",{className:en,style:Object.assign(Object.assign(Object.assign({},null==I?void 0:I.indicator),null==(m=null==R?void 0:R.styles)?void 0:m.indicator),eo)}),ea&&t.createElement("span",{style:{color:e},className:`${D}-status-text`},p)))}return P(t.createElement("span",Object.assign({ref:n},M,{className:ed,style:Object.assign(Object.assign({},null==(u=null==R?void 0:R.styles)?void 0:u.root),null==I?void 0:I.root)}),h,t.createElement(a.default,{visible:!Z,motionName:`${D}-zoom`,motionAppear:!1,motionDeadline:1e3},({className:e})=>{var a,i;let r=E("scroll-number",x),s=ee.current,n=(0,l.default)(null==k?void 0:k.indicator,null==(a=null==R?void 0:R.classNames)?void 0:a.indicator,{[`${D}-dot`]:s,[`${D}-count`]:!s,[`${D}-count-sm`]:"small"===C,[`${D}-multiple-words`]:!s&&X&&X.toString().length>1,[`${D}-status-${b}`]:!!b,[`${D}-color-${_}`]:es}),o=Object.assign(Object.assign(Object.assign({},null==I?void 0:I.indicator),null==(i=null==R?void 0:R.styles)?void 0:i.indicator),et);return _&&!es&&((o=o||{}).background=_),t.createElement(T,{prefixCls:r,show:!Z,motionClassName:e,className:n,count:X,title:el,style:o,key:"scrollNumber"},er)}),ei))});S.Ribbon=e=>{let{className:a,prefixCls:r,style:n,color:o,children:d,text:c,placement:m="end",rootClassName:u}=e,{getPrefixCls:g,direction:x}=t.useContext(s.ConfigContext),h=g("ribbon",r),b=`${h}-wrapper`,[p,_,f]=y(h,b),j=(0,i.isPresetColor)(o,!1),v=(0,l.default)(h,`${h}-placement-${m}`,{[`${h}-rtl`]:"rtl"===x,[`${h}-color-${o}`]:j},a),C={},w={};return o&&!j&&(C.background=o,w.color=o),p(t.createElement("div",{className:(0,l.default)(b,u,_,f)},d,t.createElement("div",{className:(0,l.default)(v,_),style:Object.assign(Object.assign({},C),n)},t.createElement("span",{className:`${h}-text`},c),t.createElement("div",{className:`${h}-corner`,style:w}))))},e.s(["Badge",0,S],906579)},738014,e=>{"use strict";var t=e.i(135214),l=e.i(764205),a=e.i(266027);let i=(0,e.i(243652).createQueryKeys)("users");e.s(["useCurrentUser",0,()=>{let{accessToken:e,userId:r,userRole:s}=(0,t.default)();return(0,a.useQuery)({queryKey:i.detail(r),queryFn:async()=>{let t=await (0,l.userInfoCall)(e,r,s,!1,null,null);return console.log(`userInfo: ${JSON.stringify(t)}`),t.user_info},enabled:!!(e&&r&&s)})}])},980187,e=>{"use strict";e.s(["createTeamAliasMap",0,e=>e?e.reduce((e,t)=>(e[t.team_id]=t.team_alias,e),{}):{},"resolveTeamAliasFromTeamID",0,(e,t)=>{let l=t.find(t=>t.team_id===e);return l?l.team_alias:null}])},846835,e=>{"use strict";var t=e.i(843476),l=e.i(655913),a=e.i(38419),i=e.i(78334),r=e.i(555436),s=e.i(284614);let n=({filters:e,showFilters:n,onToggleFilters:o,onChange:d,onReset:c})=>{let m=!!(e.org_id||e.org_alias);return(0,t.jsxs)("div",{className:"flex flex-col space-y-4",children:[(0,t.jsxs)("div",{className:"flex flex-wrap items-center gap-3",children:[(0,t.jsx)(l.FilterInput,{placeholder:"Search by Organization Name",value:e.org_alias,onChange:e=>d("org_alias",e),icon:r.Search,className:"w-64"}),(0,t.jsx)(a.FiltersButton,{onClick:()=>o(!n),active:n,hasActiveFilters:m}),(0,t.jsx)(i.ResetFiltersButton,{onClick:c})]}),n&&(0,t.jsx)("div",{className:"flex flex-wrap items-center gap-3 mt-3",children:(0,t.jsx)(l.FilterInput,{placeholder:"Search by Organization ID",value:e.org_id,onChange:e=>d("org_id",e),icon:s.User,className:"w-64"})})]})};var o=e.i(827252),d=e.i(871943),c=e.i(502547),m=e.i(278587),u=e.i(389083),g=e.i(994388),x=e.i(304967),h=e.i(309426),b=e.i(350967),p=e.i(752978),_=e.i(197647),f=e.i(653824),j=e.i(269200),v=e.i(942232),y=e.i(977572),C=e.i(427612),w=e.i(64848),N=e.i(496020),T=e.i(881073),z=e.i(404206),S=e.i(723731),O=e.i(599724),$=e.i(779241),k=e.i(808613),I=e.i(311451),F=e.i(212931),M=e.i(199133),E=e.i(592968),B=e.i(271645),R=e.i(500330),D=e.i(127952),P=e.i(902555),A=e.i(355619),L=e.i(75921),H=e.i(162386),U=e.i(727749),V=e.i(764205),W=e.i(785242),q=e.i(980187),G=e.i(530212),K=e.i(629569),Z=e.i(464571),J=e.i(653496),Y=e.i(898586),Q=e.i(678784),X=e.i(118366),ee=e.i(294612),et=e.i(907308),el=e.i(384767),ea=e.i(435451),ei=e.i(276173),er=e.i(916940);let es=({organizationId:e,onClose:l,accessToken:a,is_org_admin:i,is_proxy_admin:r,userModels:s,editOrg:n})=>{let[o,d]=(0,B.useState)(null),[c,m]=(0,B.useState)(!0),[h]=k.Form.useForm(),[p,_]=(0,B.useState)(!1),[f,j]=(0,B.useState)(!1),[v,y]=(0,B.useState)(!1),[C,w]=(0,B.useState)(null),[N,T]=(0,B.useState)({}),[z,S]=(0,B.useState)(!1),F=i||r,{data:E}=(0,W.useTeams)(),D=(0,B.useMemo)(()=>(0,q.createTeamAliasMap)(E),[E]),P=async()=>{try{if(m(!0),!a)return;let t=await (0,V.organizationInfoCall)(a,e);d(t)}catch(e){U.default.fromBackend("Failed to load organization information"),console.error("Error fetching organization info:",e)}finally{m(!1)}};(0,B.useEffect)(()=>{P()},[e,a]);let A=async t=>{try{if(null==a)return;let l={user_email:t.user_email,user_id:t.user_id,role:t.role};await (0,V.organizationMemberAddCall)(a,e,l),U.default.success("Organization member added successfully"),j(!1),h.resetFields(),P()}catch(e){U.default.fromBackend("Failed to add organization member"),console.error("Error adding organization member:",e)}},es=async t=>{try{if(!a)return;let l={user_email:t.user_email,user_id:t.user_id,role:t.role};await (0,V.organizationMemberUpdateCall)(a,e,l),U.default.success("Organization member updated successfully"),y(!1),h.resetFields(),P()}catch(e){U.default.fromBackend("Failed to update organization member"),console.error("Error updating organization member:",e)}},en=async t=>{try{if(!a)return;await (0,V.organizationMemberDeleteCall)(a,e,t.user_id),U.default.success("Organization member deleted successfully"),y(!1),h.resetFields(),P()}catch(e){U.default.fromBackend("Failed to delete organization member"),console.error("Error deleting organization member:",e)}},eo=async t=>{try{if(!a)return;S(!0);let l={organization_id:e,organization_alias:t.organization_alias,models:t.models,litellm_budget_table:{tpm_limit:t.tpm_limit,rpm_limit:t.rpm_limit,max_budget:t.max_budget,budget_duration:t.budget_duration},metadata:t.metadata?JSON.parse(t.metadata):null};if((void 0!==t.vector_stores||void 0!==t.mcp_servers_and_groups)&&(l.object_permission={...o?.object_permission,vector_stores:t.vector_stores||[]},void 0!==t.mcp_servers_and_groups)){let{servers:e,accessGroups:a}=t.mcp_servers_and_groups||{servers:[],accessGroups:[]};e&&e.length>0&&(l.object_permission.mcp_servers=e),a&&a.length>0&&(l.object_permission.mcp_access_groups=a)}await (0,V.organizationUpdateCall)(a,l),U.default.success("Organization settings updated successfully"),_(!1),P()}catch(e){U.default.fromBackend("Failed to update organization settings"),console.error("Error updating organization:",e)}finally{S(!1)}};if(c)return(0,t.jsx)("div",{className:"p-4",children:"Loading..."});if(!o)return(0,t.jsx)("div",{className:"p-4",children:"Organization not found"});let ed=async(e,t)=>{await (0,R.copyToClipboard)(e)&&(T(e=>({...e,[t]:!0})),setTimeout(()=>{T(e=>({...e,[t]:!1}))},2e3))},ec=[{title:"Spend (USD)",key:"spend",render:(e,l)=>{let a=null!=l.user_id?(o.members||[]).find(e=>e.user_id===l.user_id):void 0;return(0,t.jsxs)(Y.Typography.Text,{children:["$",(0,R.formatNumberWithCommas)(a?.spend??0,4)]})}},{title:"Created At",key:"created_at",render:(e,l)=>{let a=null!=l.user_id?(o.members||[]).find(e=>e.user_id===l.user_id):void 0;return(0,t.jsx)(Y.Typography.Text,{children:a?.created_at?new Date(a.created_at).toLocaleString():"-"})}}];return(0,t.jsxs)("div",{className:"w-full h-screen p-4 bg-white",children:[(0,t.jsx)("div",{className:"flex justify-between items-center mb-6",children:(0,t.jsxs)("div",{children:[(0,t.jsx)(g.Button,{icon:G.ArrowLeftIcon,onClick:l,variant:"light",className:"mb-4",children:"Back to Organizations"}),(0,t.jsx)(K.Title,{children:o.organization_alias}),(0,t.jsxs)("div",{className:"flex items-center cursor-pointer",children:[(0,t.jsx)(O.Text,{className:"text-gray-500 font-mono",children:o.organization_id}),(0,t.jsx)(Z.Button,{type:"text",size:"small",icon:N["org-id"]?(0,t.jsx)(Q.CheckIcon,{size:12}):(0,t.jsx)(X.CopyIcon,{size:12}),onClick:()=>ed(o.organization_id,"org-id"),className:`left-2 z-10 transition-all duration-200 ${N["org-id"]?"text-green-600 bg-green-50 border-green-200":"text-gray-500 hover:text-gray-700 hover:bg-gray-100"}`})]})]})}),(0,t.jsx)(J.Tabs,{defaultActiveKey:n?"settings":"overview",className:"mb-4",items:[{key:"overview",label:"Overview",children:(0,t.jsxs)(b.Grid,{numItems:1,numItemsSm:2,numItemsLg:3,className:"gap-6",children:[(0,t.jsxs)(x.Card,{children:[(0,t.jsx)(O.Text,{children:"Organization Details"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(O.Text,{children:["Created: ",new Date(o.created_at).toLocaleDateString()]}),(0,t.jsxs)(O.Text,{children:["Updated: ",new Date(o.updated_at).toLocaleDateString()]}),(0,t.jsxs)(O.Text,{children:["Created By: ",o.created_by]})]})]}),(0,t.jsxs)(x.Card,{children:[(0,t.jsx)(O.Text,{children:"Budget Status"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(K.Title,{children:["$",(0,R.formatNumberWithCommas)(o.spend,4)]}),(0,t.jsxs)(O.Text,{children:["of"," ",null===o.litellm_budget_table.max_budget?"Unlimited":`$${(0,R.formatNumberWithCommas)(o.litellm_budget_table.max_budget,4)}`]}),o.litellm_budget_table.budget_duration&&(0,t.jsxs)(O.Text,{className:"text-gray-500",children:["Reset: ",o.litellm_budget_table.budget_duration]})]})]}),(0,t.jsxs)(x.Card,{children:[(0,t.jsx)(O.Text,{children:"Rate Limits"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(O.Text,{children:["TPM: ",o.litellm_budget_table.tpm_limit||"Unlimited"]}),(0,t.jsxs)(O.Text,{children:["RPM: ",o.litellm_budget_table.rpm_limit||"Unlimited"]}),o.litellm_budget_table.max_parallel_requests&&(0,t.jsxs)(O.Text,{children:["Max Parallel Requests: ",o.litellm_budget_table.max_parallel_requests]})]})]}),(0,t.jsxs)(x.Card,{children:[(0,t.jsx)(O.Text,{children:"Models"}),(0,t.jsx)("div",{className:"mt-2 flex flex-wrap gap-2",children:0===o.models.length?(0,t.jsx)(u.Badge,{color:"red",children:"All proxy models"}):o.models.map((e,l)=>(0,t.jsx)(u.Badge,{color:"red",children:e},l))})]}),(0,t.jsxs)(x.Card,{children:[(0,t.jsx)(O.Text,{children:"Teams"}),(0,t.jsx)("div",{className:"mt-2 flex flex-wrap gap-2",children:o.teams?.map((e,l)=>(0,t.jsx)(u.Badge,{color:"red",children:D[e.team_id]||e.team_id},l))})]}),(0,t.jsx)(el.default,{objectPermission:o.object_permission,variant:"card",accessToken:a})]})},{key:"members",label:"Members",children:(0,t.jsx)("div",{className:"space-y-4",children:(0,t.jsx)(ee.default,{members:(o.members||[]).map(e=>({role:e.user_role||"",user_id:e.user_id,user_email:e.user_email})),canEdit:F,onEdit:e=>{w(e),y(!0)},onDelete:e=>en(e),onAddMember:()=>j(!0),roleColumnTitle:"Organization Role",extraColumns:ec,emptyText:"No members found"})})},{key:"settings",label:"Settings",children:(0,t.jsxs)(x.Card,{className:"overflow-y-auto max-h-[65vh]",children:[(0,t.jsxs)("div",{className:"flex justify-between items-center mb-4",children:[(0,t.jsx)(K.Title,{children:"Organization Settings"}),F&&!p&&(0,t.jsx)(g.Button,{onClick:()=>_(!0),children:"Edit Settings"})]}),p?(0,t.jsxs)(k.Form,{form:h,onFinish:eo,initialValues:{organization_alias:o.organization_alias,models:o.models,tpm_limit:o.litellm_budget_table.tpm_limit,rpm_limit:o.litellm_budget_table.rpm_limit,max_budget:o.litellm_budget_table.max_budget,budget_duration:o.litellm_budget_table.budget_duration,metadata:o.metadata?JSON.stringify(o.metadata,null,2):"",vector_stores:o.object_permission?.vector_stores||[],mcp_servers_and_groups:{servers:o.object_permission?.mcp_servers||[],accessGroups:o.object_permission?.mcp_access_groups||[]}},layout:"vertical",children:[(0,t.jsx)(k.Form.Item,{label:"Organization Name",name:"organization_alias",rules:[{required:!0,message:"Please input an organization name"}],children:(0,t.jsx)($.TextInput,{})}),(0,t.jsx)(k.Form.Item,{label:"Models",name:"models",children:(0,t.jsx)(H.ModelSelect,{value:h.getFieldValue("models"),onChange:e=>h.setFieldValue("models",e),context:"organization",options:{includeSpecialOptions:!0,showAllProxyModelsOverride:!0}})}),(0,t.jsx)(k.Form.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,t.jsx)(ea.default,{step:.01,precision:2,style:{width:"100%"}})}),(0,t.jsx)(k.Form.Item,{label:"Reset Budget",name:"budget_duration",children:(0,t.jsxs)(M.Select,{placeholder:"n/a",children:[(0,t.jsx)(M.Select.Option,{value:"24h",children:"daily"}),(0,t.jsx)(M.Select.Option,{value:"7d",children:"weekly"}),(0,t.jsx)(M.Select.Option,{value:"30d",children:"monthly"})]})}),(0,t.jsx)(k.Form.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,t.jsx)(ea.default,{step:1,style:{width:"100%"}})}),(0,t.jsx)(k.Form.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,t.jsx)(ea.default,{step:1,style:{width:"100%"}})}),(0,t.jsx)(k.Form.Item,{label:"Vector Stores",name:"vector_stores",children:(0,t.jsx)(er.default,{onChange:e=>h.setFieldValue("vector_stores",e),value:h.getFieldValue("vector_stores"),accessToken:a||"",placeholder:"Select vector stores"})}),(0,t.jsx)(k.Form.Item,{label:"MCP Servers & Access Groups",name:"mcp_servers_and_groups",children:(0,t.jsx)(L.default,{onChange:e=>h.setFieldValue("mcp_servers_and_groups",e),value:h.getFieldValue("mcp_servers_and_groups"),accessToken:a||"",placeholder:"Select MCP servers and access groups"})}),(0,t.jsx)(k.Form.Item,{label:"Metadata",name:"metadata",children:(0,t.jsx)(I.Input.TextArea,{rows:4})}),(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)(g.Button,{variant:"secondary",onClick:()=>_(!1),disabled:z,children:"Cancel"}),(0,t.jsx)(g.Button,{type:"submit",loading:z,children:"Save Changes"})]})})]}):(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(O.Text,{className:"font-medium",children:"Organization Name"}),(0,t.jsx)("div",{children:o.organization_alias})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(O.Text,{className:"font-medium",children:"Organization ID"}),(0,t.jsx)("div",{className:"font-mono",children:o.organization_id})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(O.Text,{className:"font-medium",children:"Created At"}),(0,t.jsx)("div",{children:new Date(o.created_at).toLocaleString()})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(O.Text,{className:"font-medium",children:"Models"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:o.models.map((e,l)=>(0,t.jsx)(u.Badge,{color:"red",children:e},l))})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(O.Text,{className:"font-medium",children:"Rate Limits"}),(0,t.jsxs)("div",{children:["TPM: ",o.litellm_budget_table.tpm_limit||"Unlimited"]}),(0,t.jsxs)("div",{children:["RPM: ",o.litellm_budget_table.rpm_limit||"Unlimited"]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(O.Text,{className:"font-medium",children:"Budget"}),(0,t.jsxs)("div",{children:["Max:"," ",null!==o.litellm_budget_table.max_budget?`$${(0,R.formatNumberWithCommas)(o.litellm_budget_table.max_budget,4)}`:"No Limit"]}),(0,t.jsxs)("div",{children:["Reset: ",o.litellm_budget_table.budget_duration||"Never"]})]}),(0,t.jsx)(el.default,{objectPermission:o.object_permission,variant:"inline",className:"pt-4 border-t border-gray-200",accessToken:a})]})]})}]}),(0,t.jsx)(et.default,{isVisible:f,onCancel:()=>j(!1),onSubmit:A,accessToken:a,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,t.jsx)(ei.default,{visible:v,onCancel:()=>y(!1),onSubmit:es,initialData:C,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"}]}})]})},en=async(e,t,l=null,a=null)=>{t(await (0,V.organizationListCall)(e,l,a))};e.s(["default",0,({organizations:e,userRole:l,userModels:a,accessToken:i,lastRefreshed:r,handleRefreshClick:s,currentOrg:W,guardrailsList:q=[],setOrganizations:G,premiumUser:K})=>{let[Z,J]=(0,B.useState)(null),[Y,Q]=(0,B.useState)(!1),[X,ee]=(0,B.useState)(!1),[et,el]=(0,B.useState)(null),[ei,eo]=(0,B.useState)(!1),[ed,ec]=(0,B.useState)(!1),[em]=k.Form.useForm(),[eu,eg]=(0,B.useState)({}),[ex,eh]=(0,B.useState)(!1),[eb,ep]=(0,B.useState)({org_id:"",org_alias:"",sort_by:"created_at",sort_order:"desc"}),e_=async()=>{if(et&&i)try{eo(!0),await (0,V.organizationDeleteCall)(i,et),U.default.success("Organization deleted successfully"),ee(!1),el(null),await en(i,G,eb.org_id||null,eb.org_alias||null)}catch(e){console.error("Error deleting organization:",e)}finally{eo(!1)}},ef=async e=>{try{if(!i)return;console.log(`values in organizations new create call: ${JSON.stringify(e)}`),(e.allowed_vector_store_ids&&e.allowed_vector_store_ids.length>0||e.allowed_mcp_servers_and_groups&&(e.allowed_mcp_servers_and_groups.servers?.length>0||e.allowed_mcp_servers_and_groups.accessGroups?.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&&(e.allowed_mcp_servers_and_groups.servers?.length>0&&(e.object_permission.mcp_servers=e.allowed_mcp_servers_and_groups.servers),e.allowed_mcp_servers_and_groups.accessGroups?.length>0&&(e.object_permission.mcp_access_groups=e.allowed_mcp_servers_and_groups.accessGroups),delete e.allowed_mcp_servers_and_groups)),await (0,V.organizationCreateCall)(i,e),U.default.success("Organization created successfully"),ec(!1),em.resetFields(),en(i,G,eb.org_id||null,eb.org_alias||null)}catch(e){console.error("Error creating organization:",e)}};return K?(0,t.jsxs)("div",{className:"w-full mx-4 h-[75vh]",children:[(0,t.jsx)(b.Grid,{numItems:1,className:"gap-2 p-8 w-full mt-2",children:(0,t.jsxs)(h.Col,{numColSpan:1,className:"flex flex-col gap-2",children:[("Admin"===l||"Org Admin"===l)&&(0,t.jsx)(g.Button,{className:"w-fit",onClick:()=>ec(!0),children:"+ Create New Organization"}),Z?(0,t.jsx)(es,{organizationId:Z,onClose:()=>{J(null),Q(!1)},accessToken:i,is_org_admin:!0,is_proxy_admin:"Admin"===l,userModels:a,editOrg:Y}):(0,t.jsxs)(f.TabGroup,{className:"gap-2 h-[75vh] w-full",children:[(0,t.jsxs)(T.TabList,{className:"flex justify-between mt-2 w-full items-center",children:[(0,t.jsx)("div",{className:"flex",children:(0,t.jsx)(_.Tab,{children:"Your Organizations"})}),(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[r&&(0,t.jsxs)(O.Text,{children:["Last Refreshed: ",r]}),(0,t.jsx)(p.Icon,{icon:m.RefreshIcon,variant:"shadow",size:"xs",className:"self-center",onClick:s})]})]}),(0,t.jsx)(S.TabPanels,{children:(0,t.jsxs)(z.TabPanel,{children:[(0,t.jsx)(O.Text,{children:"Click on “Organization ID” to view organization details."}),(0,t.jsx)(b.Grid,{numItems:1,className:"gap-2 pt-2 pb-2 h-[75vh] w-full mt-2",children:(0,t.jsx)(h.Col,{numColSpan:1,children:(0,t.jsxs)(x.Card,{className:"w-full mx-auto flex-auto overflow-hidden overflow-y-auto max-h-[50vh]",children:[(0,t.jsx)("div",{className:"border-b px-6 py-4",children:(0,t.jsx)("div",{className:"flex flex-col space-y-4",children:(0,t.jsx)(n,{filters:eb,showFilters:ex,onToggleFilters:eh,onChange:(e,t)=>{let l={...eb,[e]:t};ep(l),i&&(0,V.organizationListCall)(i,l.org_id||null,l.org_alias||null).then(e=>{e&&G(e)}).catch(e=>{console.error("Error fetching organizations:",e)})},onReset:()=>{ep({org_id:"",org_alias:"",sort_by:"created_at",sort_order:"desc"}),i&&(0,V.organizationListCall)(i,null,null).then(e=>{e&&G(e)}).catch(e=>{console.error("Error fetching organizations:",e)})}})})}),(0,t.jsxs)(j.Table,{children:[(0,t.jsx)(C.TableHead,{children:(0,t.jsxs)(N.TableRow,{children:[(0,t.jsx)(w.TableHeaderCell,{children:"Organization ID"}),(0,t.jsx)(w.TableHeaderCell,{children:"Organization Name"}),(0,t.jsx)(w.TableHeaderCell,{children:"Created"}),(0,t.jsx)(w.TableHeaderCell,{children:"Spend (USD)"}),(0,t.jsx)(w.TableHeaderCell,{children:"Budget (USD)"}),(0,t.jsx)(w.TableHeaderCell,{children:"Models"}),(0,t.jsx)(w.TableHeaderCell,{children:"TPM / RPM Limits"}),(0,t.jsx)(w.TableHeaderCell,{children:"Info"}),(0,t.jsx)(w.TableHeaderCell,{children:"Actions"})]})}),(0,t.jsx)(v.TableBody,{children:e&&e.length>0?e.sort((e,t)=>new Date(t.created_at).getTime()-new Date(e.created_at).getTime()).map(e=>(0,t.jsxs)(N.TableRow,{children:[(0,t.jsx)(y.TableCell,{children:(0,t.jsx)("div",{className:"overflow-hidden",children:(0,t.jsx)(E.Tooltip,{title:e.organization_id,children:(0,t.jsxs)(g.Button,{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:()=>J(e.organization_id),children:[e.organization_id?.slice(0,7),"..."]})})})}),(0,t.jsx)(y.TableCell,{children:e.organization_alias}),(0,t.jsx)(y.TableCell,{children:e.created_at?new Date(e.created_at).toLocaleDateString():"N/A"}),(0,t.jsx)(y.TableCell,{children:(0,R.formatNumberWithCommas)(e.spend,4)}),(0,t.jsx)(y.TableCell,{children:e.litellm_budget_table?.max_budget!==null&&e.litellm_budget_table?.max_budget!==void 0?e.litellm_budget_table?.max_budget:"No limit"}),(0,t.jsx)(y.TableCell,{style:{maxWidth:"8-x",whiteSpace:"pre-wrap",overflow:"hidden"},className:e.models.length>3?"px-0":"",children:(0,t.jsx)("div",{className:"flex flex-col",children:Array.isArray(e.models)?(0,t.jsx)("div",{className:"flex flex-col",children:0===e.models.length?(0,t.jsx)(u.Badge,{size:"xs",className:"mb-1",color:"red",children:(0,t.jsx)(O.Text,{children:"All Proxy Models"})}):(0,t.jsx)(t.Fragment,{children:(0,t.jsxs)("div",{className:"flex items-start",children:[e.models.length>3&&(0,t.jsx)("div",{children:(0,t.jsx)(p.Icon,{icon:eu[e.organization_id||""]?d.ChevronDownIcon:c.ChevronRightIcon,className:"cursor-pointer",size:"xs",onClick:()=>{eg(t=>({...t,[e.organization_id||""]:!t[e.organization_id||""]}))}})}),(0,t.jsxs)("div",{className:"flex flex-wrap gap-1",children:[e.models.slice(0,3).map((e,l)=>"all-proxy-models"===e?(0,t.jsx)(u.Badge,{size:"xs",color:"red",children:(0,t.jsx)(O.Text,{children:"All Proxy Models"})},l):(0,t.jsx)(u.Badge,{size:"xs",color:"blue",children:(0,t.jsx)(O.Text,{children:e.length>30?`${(0,A.getModelDisplayName)(e).slice(0,30)}...`:(0,A.getModelDisplayName)(e)})},l)),e.models.length>3&&!eu[e.organization_id||""]&&(0,t.jsx)(u.Badge,{size:"xs",color:"gray",className:"cursor-pointer",children:(0,t.jsxs)(O.Text,{children:["+",e.models.length-3," ",e.models.length-3==1?"more model":"more models"]})}),eu[e.organization_id||""]&&(0,t.jsx)("div",{className:"flex flex-wrap gap-1",children:e.models.slice(3).map((e,l)=>"all-proxy-models"===e?(0,t.jsx)(u.Badge,{size:"xs",color:"red",children:(0,t.jsx)(O.Text,{children:"All Proxy Models"})},l+3):(0,t.jsx)(u.Badge,{size:"xs",color:"blue",children:(0,t.jsx)(O.Text,{children:e.length>30?`${(0,A.getModelDisplayName)(e).slice(0,30)}...`:(0,A.getModelDisplayName)(e)})},l+3))})]})]})})}):null})}),(0,t.jsx)(y.TableCell,{children:(0,t.jsxs)(O.Text,{children:["TPM:"," ",e.litellm_budget_table?.tpm_limit?e.litellm_budget_table?.tpm_limit:"Unlimited",(0,t.jsx)("br",{}),"RPM:"," ",e.litellm_budget_table?.rpm_limit?e.litellm_budget_table?.rpm_limit:"Unlimited"]})}),(0,t.jsx)(y.TableCell,{children:(0,t.jsxs)(O.Text,{children:[e.members?.length||0," Members"]})}),(0,t.jsx)(y.TableCell,{children:"Admin"===l&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(P.default,{variant:"Edit",tooltipText:"Edit organization",onClick:()=>{J(e.organization_id),Q(!0)}}),(0,t.jsx)(P.default,{variant:"Delete",tooltipText:"Delete organization",onClick:()=>{var t;(t=e.organization_id)&&(el(t),ee(!0))}})]})})]},e.organization_id)):null})]})]})})})]})})]})]})}),(0,t.jsx)(F.Modal,{title:"Create Organization",visible:ed,width:800,footer:null,onCancel:()=>{ec(!1),em.resetFields()},children:(0,t.jsxs)(k.Form,{form:em,onFinish:ef,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[(0,t.jsx)(k.Form.Item,{label:"Organization Name",name:"organization_alias",rules:[{required:!0,message:"Please input an organization name"}],children:(0,t.jsx)($.TextInput,{placeholder:""})}),(0,t.jsx)(k.Form.Item,{label:"Models",name:"models",children:(0,t.jsx)(H.ModelSelect,{options:{showAllProxyModelsOverride:!0,includeSpecialOptions:!0},value:em.getFieldValue("models"),onChange:e=>em.setFieldValue("models",e),context:"organization"})}),(0,t.jsx)(k.Form.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,t.jsx)(ea.default,{step:.01,precision:2,width:200})}),(0,t.jsx)(k.Form.Item,{label:"Reset Budget",name:"budget_duration",children:(0,t.jsxs)(M.Select,{defaultValue:null,placeholder:"n/a",children:[(0,t.jsx)(M.Select.Option,{value:"24h",children:"daily"}),(0,t.jsx)(M.Select.Option,{value:"7d",children:"weekly"}),(0,t.jsx)(M.Select.Option,{value:"30d",children:"monthly"})]})}),(0,t.jsx)(k.Form.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,t.jsx)(ea.default,{step:1,width:400})}),(0,t.jsx)(k.Form.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,t.jsx)(ea.default,{step:1,width:400})}),(0,t.jsx)(k.Form.Item,{label:(0,t.jsxs)("span",{children:["Allowed Vector Stores"," ",(0,t.jsx)(E.Tooltip,{title:"Select which vector stores this organization can access by default. Leave empty for access to all vector stores",children:(0,t.jsx)(o.InfoCircleOutlined,{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,t.jsx)(er.default,{onChange:e=>em.setFieldValue("allowed_vector_store_ids",e),value:em.getFieldValue("allowed_vector_store_ids"),accessToken:i||"",placeholder:"Select vector stores (optional)"})}),(0,t.jsx)(k.Form.Item,{label:(0,t.jsxs)("span",{children:["Allowed MCP Servers"," ",(0,t.jsx)(E.Tooltip,{title:"Select which MCP servers and access groups this organization can access by default.",children:(0,t.jsx)(o.InfoCircleOutlined,{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,t.jsx)(L.default,{onChange:e=>em.setFieldValue("allowed_mcp_servers_and_groups",e),value:em.getFieldValue("allowed_mcp_servers_and_groups"),accessToken:i||"",placeholder:"Select MCP servers and access groups (optional)"})}),(0,t.jsx)(k.Form.Item,{label:"Metadata",name:"metadata",children:(0,t.jsx)(I.Input.TextArea,{rows:4})}),(0,t.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,t.jsx)(g.Button,{type:"submit",children:"Create Organization"})})]})}),(0,t.jsx)(D.default,{isOpen:X,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:et,code:!0}],onCancel:()=>{ee(!1),el(null)},onOk:e_,confirmLoading:ei})]}):(0,t.jsx)("div",{children:(0,t.jsxs)(O.Text,{children:["This is a LiteLLM Enterprise feature, and requires a valid key to use. Get a trial key"," ",(0,t.jsx)("a",{href:"https://www.litellm.ai/#pricing",target:"_blank",rel:"noopener noreferrer",children:"here"}),"."]})})},"fetchOrganizations",0,en],846835)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/81b595b330469e25.js b/litellm/proxy/_experimental/out/_next/static/chunks/38976546132cd527.js similarity index 79% rename from litellm/proxy/_experimental/out/_next/static/chunks/81b595b330469e25.js rename to litellm/proxy/_experimental/out/_next/static/chunks/38976546132cd527.js index da9bd38829..63208ba2db 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/81b595b330469e25.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/38976546132cd527.js @@ -100,6 +100,6 @@ `]:{animationName:i.slideDownIn},[`${u}${d}bottomLeft`]:{animationName:i.slideUpOut},[` ${u}${d}topLeft, ${u}${d}topRight - `]:{animationName:i.slideDownOut},"&-hidden":{display:"none"},[o]:Object.assign(Object.assign({},l(e)),{cursor:"pointer",transition:`background ${e.motionDurationSlow} ease`,borderRadius:e.borderRadiusSM,"&-group":{color:e.colorTextDescription,fontSize:e.fontSizeSM,cursor:"default"},"&-option":{display:"flex","&-content":Object.assign({flex:"auto"},t.textEllipsis),"&-state":{flex:"none",display:"flex",alignItems:"center"},[`&-active:not(${o}-option-disabled)`]:{backgroundColor:e.optionActiveBg},[`&-selected:not(${o}-option-disabled)`]:{color:e.optionSelectedColor,fontWeight:e.optionSelectedFontWeight,backgroundColor:e.optionSelectedBg,[`${o}-option-state`]:{color:e.colorPrimary}},"&-disabled":{[`&${o}-option-selected`]:{backgroundColor:e.colorBgContainerDisabled},color:e.colorTextDisabled,cursor:"not-allowed"},"&-grouped":{paddingInlineStart:e.calc(e.controlPaddingHorizontal).mul(2).equal()}},"&-empty":Object.assign(Object.assign({},l(e)),{color:e.colorTextDisabled})}),[`${f}:has(+ ${f})`]:{borderEndStartRadius:0,borderEndEndRadius:0,[`& + ${f}`]:{borderStartStartRadius:0,borderStartEndRadius:0}},"&-rtl":{direction:"rtl"}})},(0,i.initSlideMotion)(e,"slide-up"),(0,i.initSlideMotion)(e,"slide-down"),(0,a.initMoveMotion)(e,"move-up"),(0,a.initMoveMotion)(e,"move-down")]})(e),{[`${n}-rtl`]:{direction:"rtl"}},(0,r.genCompactItemStyle)(e,{borderElCls:`${n}-selector`,focusElCls:`${n}-focused`})]})(v),{[v.componentCls]:Object.assign(Object.assign(Object.assign(Object.assign({},{"&-outlined":Object.assign(Object.assign(Object.assign(Object.assign({},d(v,{borderColor:v.colorBorder,hoverBorderHover:v.hoverBorderColor,activeBorderColor:v.activeBorderColor,activeOutlineColor:v.activeOutlineColor,color:v.colorText})),f(v,{status:"error",borderColor:v.colorError,hoverBorderHover:v.colorErrorHover,activeBorderColor:v.colorError,activeOutlineColor:v.colorErrorOutline,color:v.colorError})),f(v,{status:"warning",borderColor:v.colorWarning,hoverBorderHover:v.colorWarningHover,activeBorderColor:v.colorWarning,activeOutlineColor:v.colorWarningOutline,color:v.colorWarning})),{[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{background:v.colorBgContainerDisabled,color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.multipleItemBg,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.multipleItemBorderColor}`}})}),{"&-filled":Object.assign(Object.assign(Object.assign(Object.assign({},p(v,{bg:v.colorFillTertiary,hoverBg:v.colorFillSecondary,activeBorderColor:v.activeBorderColor,color:v.colorText})),m(v,{status:"error",bg:v.colorErrorBg,hoverBg:v.colorErrorBgHover,activeBorderColor:v.colorError,color:v.colorError})),m(v,{status:"warning",bg:v.colorWarningBg,hoverBg:v.colorWarningBgHover,activeBorderColor:v.colorWarning,color:v.colorWarning})),{[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{borderColor:v.colorBorder,background:v.colorBgContainerDisabled,color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.colorBgContainer,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.colorSplit}`}})}),{"&-borderless":{[`${v.componentCls}-selector`]:{background:"transparent",border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} transparent`},[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.multipleItemBg,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.multipleItemBorderColor}`},[`&${v.componentCls}-status-error`]:{[`${v.componentCls}-prefix, ${v.componentCls}-selection-item`]:{color:v.colorError}},[`&${v.componentCls}-status-warning`]:{[`${v.componentCls}-prefix, ${v.componentCls}-selection-item`]:{color:v.colorWarning}}}}),{"&-underlined":Object.assign(Object.assign(Object.assign(Object.assign({},h(v,{borderColor:v.colorBorder,hoverBorderHover:v.hoverBorderColor,activeBorderColor:v.activeBorderColor,activeOutlineColor:v.activeOutlineColor,color:v.colorText})),g(v,{status:"error",borderColor:v.colorError,hoverBorderHover:v.colorErrorHover,activeBorderColor:v.colorError,activeOutlineColor:v.colorErrorOutline,color:v.colorError})),g(v,{status:"warning",borderColor:v.colorWarning,hoverBorderHover:v.colorWarningHover,activeBorderColor:v.colorWarning,activeOutlineColor:v.colorWarningOutline,color:v.colorWarning})),{[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.multipleItemBg,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.multipleItemBorderColor}`}})})}]},e=>{let{fontSize:t,lineHeight:r,lineWidth:n,controlHeight:o,controlHeightSM:a,controlHeightLG:i,paddingXXS:l,controlPaddingHorizontal:s,zIndexPopupBase:c,colorText:u,fontWeightStrong:d,controlItemBgActive:f,controlItemBgHover:p,colorBgContainer:m,colorFillSecondary:h,colorBgContainerDisabled:g,colorTextDisabled:v,colorPrimaryHover:y,colorPrimary:b,controlOutline:w}=e,$=2*l,C=2*n,E=Math.min(o-$,o-C),S=Math.min(a-$,a-C),x=Math.min(i-$,i-C);return{INTERNAL_FIXED_ITEM_MARGIN:Math.floor(l/2),zIndexPopup:c+50,optionSelectedColor:u,optionSelectedFontWeight:d,optionSelectedBg:f,optionActiveBg:p,optionPadding:`${(o-t*r)/2}px ${s}px`,optionFontSize:t,optionLineHeight:r,optionHeight:o,selectorBg:m,clearBg:m,singleItemHeightLG:i,multipleItemBg:h,multipleItemBorderColor:"transparent",multipleItemHeight:E,multipleItemHeightSM:S,multipleItemHeightLG:x,multipleSelectorBgDisabled:g,multipleItemColorDisabled:v,multipleItemBorderColorDisabled:"transparent",showArrowPaddingInlineEnd:Math.ceil(1.25*e.fontSize),hoverBorderColor:y,activeBorderColor:b,activeOutlineColor:w,selectAffixPadding:l}},{unitless:{optionLineHeight:!0,optionSelectedFontWeight:!0}});e.s(["default",0,v],950302)},729151,e=>{"use strict";var t=e.i(271645),r=e.i(121229),n=e.i(726289),o=e.i(864517),a=e.i(247153),i=e.i(739295),l=e.i(38953);function s({suffixIcon:e,clearIcon:s,menuItemSelectedIcon:c,removeIcon:u,loading:d,multiple:f,hasFeedback:p,prefixCls:m,showSuffixIcon:h,feedbackIcon:g,showArrow:v,componentName:y}){let b=null!=s?s:t.createElement(n.default,null),w=r=>null!==e||p||v?t.createElement(t.Fragment,null,!1!==h&&r,p&&g):null,$=null;if(void 0!==e)$=w(e);else if(d)$=w(t.createElement(i.default,{spin:!0}));else{let e=`${m}-suffix`;$=({open:r,showSearch:n})=>r&&n?w(t.createElement(l.default,{className:e})):w(t.createElement(a.default,{className:e}))}let C=null;C=void 0!==c?c:f?t.createElement(r.default,null):null;return{clearIcon:b,suffixIcon:$,itemIcon:C,removeIcon:void 0!==u?u:t.createElement(o.default,null)}}e.s(["default",()=>s])},327494,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),n=e.i(123829),o=e.i(955492),a=e.i(869301),i=e.i(529681),l=e.i(122767),s=e.i(613541),c=e.i(805484),u=e.i(52956),d=e.i(242064),f=e.i(721132),p=e.i(937328),m=e.i(321883),h=e.i(517455),g=e.i(62139),v=e.i(792812),y=e.i(249616),b=e.i(104458),w=e.i(85566),$=e.i(950302),C=e.i(729151),E=e.i(617206),S=function(e,t){var r={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&0>t.indexOf(n)&&(r[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var o=0,n=Object.getOwnPropertySymbols(e);ot.indexOf(n[o])&&Object.prototype.propertyIsEnumerable.call(e,n[o])&&(r[n[o]]=e[n[o]]);return r};let x="SECRET_COMBOBOX_MODE_DO_NOT_USE",j=t.forwardRef((e,o)=>{var a,c,j,O,k,T,F,_;let I,{prefixCls:P,bordered:N,className:R,rootClassName:M,getPopupContainer:B,popupClassName:A,dropdownClassName:z,listHeight:L=256,placement:H,listItemHeight:D,size:V,disabled:W,notFoundContent:G,status:U,builtinPlacements:q,dropdownMatchSelectWidth:J,popupMatchSelectWidth:K,direction:X,style:Y,allowClear:Z,variant:Q,dropdownStyle:ee,transitionName:et,tagRender:er,maxCount:en,prefix:eo,dropdownRender:ea,popupRender:ei,onDropdownVisibleChange:el,onOpenChange:es,styles:ec,classNames:eu}=e,ed=S(e,["prefixCls","bordered","className","rootClassName","getPopupContainer","popupClassName","dropdownClassName","listHeight","placement","listItemHeight","size","disabled","notFoundContent","status","builtinPlacements","dropdownMatchSelectWidth","popupMatchSelectWidth","direction","style","allowClear","variant","dropdownStyle","transitionName","tagRender","maxCount","prefix","dropdownRender","popupRender","onDropdownVisibleChange","onOpenChange","styles","classNames"]),{getPopupContainer:ef,getPrefixCls:ep,renderEmpty:em,direction:eh,virtual:eg,popupMatchSelectWidth:ev,popupOverflow:ey}=t.useContext(d.ConfigContext),{showSearch:eb,style:ew,styles:e$,className:eC,classNames:eE}=(0,d.useComponentConfig)("select"),[,eS]=(0,b.useToken)(),ex=null!=D?D:null==eS?void 0:eS.controlHeight,ej=ep("select",P),eO=ep(),ek=null!=X?X:eh,{compactSize:eT,compactItemClassnames:eF}=(0,y.useCompactItemContext)(ej,ek),[e_,eI]=(0,v.default)("select",Q,N),eP=(0,m.default)(ej),[eN,eR,eM]=(0,$.default)(ej,eP),eB=t.useMemo(()=>{let{mode:t}=e;if("combobox"!==t)return t===x?"combobox":t},[e.mode]),eA="multiple"===eB||"tags"===eB,ez=(T=e.suffixIcon,void 0!==(F=e.showArrow)?F:null!==T),eL=null!=(a=null!=K?K:J)?a:ev,eH=(null==(c=null==ec?void 0:ec.popup)?void 0:c.root)||(null==(j=e$.popup)?void 0:j.root)||ee,eD=(_=ei||ea,t.default.useMemo(()=>{if(_)return(...e)=>t.default.createElement(E.default,{space:!0},_.apply(void 0,e))},[_])),{status:eV,hasFeedback:eW,isFormItemInput:eG,feedbackIcon:eU}=t.useContext(g.FormItemInputContext),eq=(0,u.getMergedStatus)(eV,U);I=void 0!==G?G:"combobox"===eB?null:(null==em?void 0:em("Select"))||t.createElement(f.default,{componentName:"Select"});let{suffixIcon:eJ,itemIcon:eK,removeIcon:eX,clearIcon:eY}=(0,C.default)(Object.assign(Object.assign({},ed),{multiple:eA,hasFeedback:eW,feedbackIcon:eU,showSuffixIcon:ez,prefixCls:ej,componentName:"Select"})),eZ=(0,i.default)(ed,["suffixIcon","itemIcon"]),eQ=(0,r.default)((null==(O=null==eu?void 0:eu.popup)?void 0:O.root)||(null==(k=null==eE?void 0:eE.popup)?void 0:k.root)||A||z,{[`${ej}-dropdown-${ek}`]:"rtl"===ek},M,eE.root,null==eu?void 0:eu.root,eM,eP,eR),e0=(0,h.default)(e=>{var t;return null!=(t=null!=V?V:eT)?t:e}),e1=t.useContext(p.default),e2=(0,r.default)({[`${ej}-lg`]:"large"===e0,[`${ej}-sm`]:"small"===e0,[`${ej}-rtl`]:"rtl"===ek,[`${ej}-${e_}`]:eI,[`${ej}-in-form-item`]:eG},(0,u.getStatusClassNames)(ej,eq,eW),eF,eC,R,eE.root,null==eu?void 0:eu.root,M,eM,eP,eR),e4=t.useMemo(()=>void 0!==H?H:"rtl"===ek?"bottomRight":"bottomLeft",[H,ek]),[e6]=(0,l.useZIndex)("SelectLike",null==eH?void 0:eH.zIndex);return eN(t.createElement(n.default,Object.assign({ref:o,virtual:eg,showSearch:eb},eZ,{style:Object.assign(Object.assign(Object.assign(Object.assign({},e$.root),null==ec?void 0:ec.root),ew),Y),dropdownMatchSelectWidth:eL,transitionName:(0,s.getTransitionName)(eO,"slide-up",et),builtinPlacements:(0,w.default)(q,ey),listHeight:L,listItemHeight:ex,mode:eB,prefixCls:ej,placement:e4,direction:ek,prefix:eo,suffixIcon:eJ,menuItemSelectedIcon:eK,removeIcon:eX,allowClear:!0===Z?{clearIcon:eY}:Z,notFoundContent:I,className:e2,getPopupContainer:B||ef,dropdownClassName:eQ,disabled:null!=W?W:e1,dropdownStyle:Object.assign(Object.assign({},eH),{zIndex:e6}),maxCount:eA?en:void 0,tagRender:eA?er:void 0,dropdownRender:eD,onDropdownVisibleChange:es||el})))}),O=(0,c.default)(j,"dropdownAlign");j.SECRET_COMBOBOX_MODE_DO_NOT_USE=x,j.Option=a.Option,j.OptGroup=o.OptGroup,j._InternalPanelDoNotUseOrYouWillBeFired=O,e.s(["default",0,j],327494)},199133,e=>{"use strict";var t=e.i(327494);e.s(["Select",()=>t.default])},689074,21243,98801,e=>{"use strict";var t=e.i(290571),r=e.i(271645);let n=e=>{var n=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},n),r.default.createElement("path",{d:"M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM11 15V17H13V15H11ZM11 7V13H13V7H11Z"}))};e.s(["default",()=>n],689074);let o=e=>{var n=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},n),r.default.createElement("path",{d:"M1.18164 12C2.12215 6.87976 6.60812 3 12.0003 3C17.3924 3 21.8784 6.87976 22.8189 12C21.8784 17.1202 17.3924 21 12.0003 21C6.60812 21 2.12215 17.1202 1.18164 12ZM12.0003 17C14.7617 17 17.0003 14.7614 17.0003 12C17.0003 9.23858 14.7617 7 12.0003 7C9.23884 7 7.00026 9.23858 7.00026 12C7.00026 14.7614 9.23884 17 12.0003 17ZM12.0003 15C10.3434 15 9.00026 13.6569 9.00026 12C9.00026 10.3431 10.3434 9 12.0003 9C13.6571 9 15.0003 10.3431 15.0003 12C15.0003 13.6569 13.6571 15 12.0003 15Z"}))};e.s(["default",()=>o],21243);let a=e=>{var n=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},n),r.default.createElement("path",{d:"M4.52047 5.93457L1.39366 2.80777L2.80788 1.39355L22.6069 21.1925L21.1927 22.6068L17.8827 19.2968C16.1814 20.3755 14.1638 21.0002 12.0003 21.0002C6.60812 21.0002 2.12215 17.1204 1.18164 12.0002C1.61832 9.62282 2.81932 7.5129 4.52047 5.93457ZM14.7577 16.1718L13.2937 14.7078C12.902 14.8952 12.4634 15.0002 12.0003 15.0002C10.3434 15.0002 9.00026 13.657 9.00026 12.0002C9.00026 11.537 9.10522 11.0984 9.29263 10.7067L7.82866 9.24277C7.30514 10.0332 7.00026 10.9811 7.00026 12.0002C7.00026 14.7616 9.23884 17.0002 12.0003 17.0002C13.0193 17.0002 13.9672 16.6953 14.7577 16.1718ZM7.97446 3.76015C9.22127 3.26959 10.5793 3.00016 12.0003 3.00016C17.3924 3.00016 21.8784 6.87992 22.8189 12.0002C22.5067 13.6998 21.8038 15.2628 20.8068 16.5925L16.947 12.7327C16.9821 12.4936 17.0003 12.249 17.0003 12.0002C17.0003 9.23873 14.7617 7.00016 12.0003 7.00016C11.7514 7.00016 11.5068 7.01833 11.2677 7.05343L7.97446 3.76015Z"}))};e.s(["default",()=>a],98801)},103471,e=>{"use strict";var t=e.i(444755),r=e.i(271645);let n=e=>["string","number"].includes(typeof e)?e:e instanceof Array?e.map(n).join(""):"object"==typeof e&&e?n(e.props.children):void 0;function o(e){let t=new Map;return r.default.Children.map(e,e=>{var r;t.set(e.props.value,null!=(r=n(e))?r:e.props.value)}),t}function a(e,t){return r.default.Children.map(t,t=>{var r;if((null!=(r=n(t))?r:t.props.value).toLowerCase().includes(e.toLowerCase()))return t})}let i=(e,r,n=!1)=>(0,t.tremorTwMerge)(r?"bg-tremor-background-subtle dark:bg-dark-tremor-background-subtle":"bg-tremor-background dark:bg-dark-tremor-background",!r&&"hover:bg-tremor-background-muted dark:hover:bg-dark-tremor-background-muted",e?"text-tremor-content-emphasis dark:text-dark-tremor-content-emphasis":"text-tremor-content dark:text-dark-tremor-content",r&&"text-tremor-content-subtle dark:text-dark-tremor-content-subtle",n&&"text-red-500 placeholder:text-red-500 dark:text-red-500 dark:placeholder:text-red-500",n?"border-red-500 dark:border-red-500":"border-tremor-border dark:border-dark-tremor-border");function l(e){return null!=e&&""!==e}e.s(["constructValueToNameMapping",()=>o,"getFilteredOptions",()=>a,"getNodeText",()=>n,"getSelectButtonColors",()=>i,"hasValue",()=>l])},779241,677955,e=>{"use strict";var t=e.i(290571),r=e.i(271645),n=e.i(673706),o=e.i(689074),a=e.i(21243),i=e.i(98801),l=e.i(103471),s=e.i(444755);let c=r.default.forwardRef((e,c)=>{let{value:u,defaultValue:d,type:f,placeholder:p="Type...",icon:m,error:h=!1,errorMessage:g,disabled:v=!1,stepper:y,makeInputClassName:b,className:w,onChange:$,onValueChange:C,autoFocus:E,pattern:S}=e,x=(0,t.__rest)(e,["value","defaultValue","type","placeholder","icon","error","errorMessage","disabled","stepper","makeInputClassName","className","onChange","onValueChange","autoFocus","pattern"]),[j,O]=(0,r.useState)(E||!1),[k,T]=(0,r.useState)(!1),F=(0,r.useCallback)(()=>T(!k),[k,T]),_=(0,r.useRef)(null),I=(0,l.hasValue)(u||d);return r.default.useEffect(()=>{let e=()=>O(!0),t=()=>O(!1),r=_.current;return r&&(r.addEventListener("focus",e),r.addEventListener("blur",t),E&&r.focus()),()=>{r&&(r.removeEventListener("focus",e),r.removeEventListener("blur",t))}},[E]),r.default.createElement(r.default.Fragment,null,r.default.createElement("div",{className:(0,s.tremorTwMerge)(b("root"),"relative w-full flex items-center min-w-[10rem] outline-none rounded-tremor-default transition duration-100 border","shadow-tremor-input","dark:shadow-dark-tremor-input",(0,l.getSelectButtonColors)(I,v,h),j&&(0,s.tremorTwMerge)("ring-2","border-tremor-brand-subtle ring-tremor-brand-muted","dark:border-dark-tremor-brand-subtle dark:ring-dark-tremor-brand-muted"),w)},m?r.default.createElement(m,{className:(0,s.tremorTwMerge)(b("icon"),"shrink-0 h-5 w-5 mx-2.5 absolute left-0 flex items-center","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")}):null,r.default.createElement("input",Object.assign({ref:(0,n.mergeRefs)([_,c]),defaultValue:d,value:u,type:k?"text":f,className:(0,s.tremorTwMerge)(b("input"),"w-full bg-transparent focus:outline-none focus:ring-0 border-none text-tremor-default rounded-tremor-default transition duration-100 py-2","text-tremor-content-emphasis","dark:text-dark-tremor-content-emphasis","[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none","password"===f?h?"pr-16":"pr-12":h?"pr-8":"pr-3",m?"pl-10":"pl-3",v?"placeholder:text-tremor-content-subtle dark:placeholder:text-dark-tremor-content-subtle":"placeholder:text-tremor-content dark:placeholder:text-dark-tremor-content"),placeholder:p,disabled:v,"data-testid":"base-input",onChange:e=>{null==$||$(e),null==C||C(e.target.value)},pattern:S},x)),"password"!==f||v?null:r.default.createElement("button",{className:(0,s.tremorTwMerge)(b("toggleButton"),"absolute inset-y-0 right-0 flex items-center px-2.5 rounded-lg"),type:"button",onClick:()=>F(),"aria-label":k?"Hide password":"Show Password"},k?r.default.createElement(i.default,{className:(0,s.tremorTwMerge)("flex-none h-5 w-5 transition","text-tremor-content-subtle hover:text-tremor-content","dark:text-dark-tremor-content-subtle hover:dark:text-dark-tremor-content"),"aria-hidden":!0}):r.default.createElement(a.default,{className:(0,s.tremorTwMerge)("flex-none h-5 w-5 transition","text-tremor-content-subtle hover:text-tremor-content","dark:text-dark-tremor-content-subtle hover:dark:text-dark-tremor-content"),"aria-hidden":!0})),h?r.default.createElement(o.default,{className:(0,s.tremorTwMerge)(b("errorIcon"),"text-red-500 shrink-0 h-5 w-5 absolute right-0 flex items-center","password"===f?"mr-10":"number"===f?y?"mr-20":"mr-3":"mx-2.5")}):null,null!=y?y:null),h&&g?r.default.createElement("p",{className:(0,s.tremorTwMerge)(b("errorMessage"),"text-sm text-red-500 mt-1")},g):null)});c.displayName="BaseInput",e.s(["default",()=>c],677955);let u=(0,n.makeClassName)("TextInput"),d=r.default.forwardRef((e,n)=>{let{type:o="text"}=e,a=(0,t.__rest)(e,["type"]);return r.default.createElement(c,Object.assign({ref:n,type:o,makeInputClassName:u},a))});d.displayName="TextInput",e.s(["TextInput",()=>d],779241)},122550,e=>{"use strict";function t(e,t){return e.length>t?e.substring(0,t)+"...":e}e.s(["formItemValidateJSON",0,(e,t)=>{if(!t)return Promise.resolve();try{return JSON.parse(t),Promise.resolve()}catch(e){return Promise.reject("Please enter valid JSON")}},"formatLabel",0,e=>e?e.replace(/_/g," ").replace(/\b\w/g,e=>e.toUpperCase()):e,"truncateString",()=>t])},764205,82946,e=>{"use strict";e.s(["addAllowedIP",()=>eP,"adminGlobalActivity",()=>eq,"adminGlobalActivityPerModel",()=>eK,"adminGlobalCacheActivity",()=>eJ,"adminSpendLogsCall",()=>eV,"adminTopEndUsersCall",()=>eG,"adminTopKeysCall",()=>eW,"adminTopModelsCall",()=>eX,"adminspendByProvider",()=>eU,"agentDailyActivityCall",()=>ew,"agentHubPublicModelsCall",()=>eT,"alertingSettingsCall",()=>J,"allEndUsersCall",()=>eL,"allTagNamesCall",()=>ez,"applyGuardrail",()=>nr,"approveGuardrailSubmission",()=>tB,"approveMCPServer",()=>rS,"availableTeamListCall",()=>el,"budgetCreateCall",()=>G,"budgetDeleteCall",()=>W,"budgetUpdateCall",()=>U,"buildMcpOAuthAuthorizeUrl",()=>nh,"cacheTemporaryMcpServer",()=>np,"cachingHealthCheckCall",()=>tk,"callMCPTool",()=>rP,"cancelModelCostMapReload",()=>z,"checkEuAiActCompliance",()=>nM,"checkGdprCompliance",()=>nB,"claimOnboardingToken",()=>eC,"convertPromptFileToJson",()=>rl,"createAgentCall",()=>rs,"createGuardrailCall",()=>rc,"createMCPServer",()=>rb,"createPassThroughEndpoint",()=>tC,"createPolicyAttachmentCall",()=>t3,"createPolicyCall",()=>tY,"createPolicyVersion",()=>t0,"createPromptCall",()=>ro,"createSearchTool",()=>rO,"credentialCreateCall",()=>e3,"credentialDeleteCall",()=>e9,"credentialGetCall",()=>e5,"credentialListCall",()=>e7,"credentialUpdateCall",()=>e8,"customerDailyActivityCall",()=>eb,"deleteAgentCall",()=>rQ,"deleteAllowedIP",()=>eN,"deleteCallback",()=>nd,"deleteClaudeCodePlugin",()=>nR,"deleteConfigFieldSetting",()=>tS,"deleteGuardrailCall",()=>r2,"deleteMCPOAuthUserCredential",()=>nG,"deleteMCPServer",()=>r$,"deletePassThroughEndpointsCall",()=>tx,"deletePolicyAttachmentCall",()=>t7,"deletePolicyCall",()=>t2,"deletePromptCall",()=>ri,"deleteSearchTool",()=>rT,"deleteToolPolicyOverride",()=>nV,"deriveErrorMessage",()=>nx,"disableClaudeCodePlugin",()=>nN,"enableClaudeCodePlugin",()=>nP,"enrichPolicyTemplate",()=>tU,"enrichPolicyTemplateStream",()=>tK,"estimateAttachmentImpactCall",()=>re,"exchangeMcpOAuthToken",()=>ng,"fetchAvailableSearchProviders",()=>rF,"fetchDiscoverableMCPServers",()=>rm,"fetchMCPAccessGroups",()=>rv,"fetchMCPClientIp",()=>ry,"fetchMCPServerHealth",()=>rg,"fetchMCPServers",()=>rh,"fetchMCPSubmissions",()=>rE,"fetchOpenAPIRegistry",()=>rp,"fetchSearchTools",()=>rj,"fetchToolDetail",()=>nH,"fetchToolPolicyOptions",()=>nA,"fetchToolsList",()=>nz,"formatDate",()=>v,"getAgentCreateMetadata",()=>k,"getAgentInfo",()=>r9,"getAgentsList",()=>r5,"getAllowedIPs",()=>eI,"getBudgetList",()=>tp,"getCacheSettingsCall",()=>tv,"getCallbackConfigsCall",()=>y,"getCallbacksCall",()=>tm,"getCategoryYaml",()=>r3,"getClaudeCodeMarketplace",()=>nT,"getClaudeCodePluginDetails",()=>n_,"getClaudeCodePluginsList",()=>nF,"getConfigFieldSetting",()=>t$,"getDefaultTeamSettings",()=>rz,"getEmailEventSettings",()=>rX,"getGeneralSettingsCall",()=>th,"getGlobalLitellmHeaderName",()=>_,"getGuardrailInfo",()=>r8,"getGuardrailProviderSpecificParams",()=>r6,"getGuardrailUISettings",()=>r4,"getGuardrailsList",()=>tR,"getGuardrailsUsageDetail",()=>tL,"getGuardrailsUsageLogs",()=>tH,"getGuardrailsUsageOverview",()=>tz,"getInProductNudgesCall",()=>b,"getInternalUserSettings",()=>rd,"getLicenseInfo",()=>nc,"getMCPOAuthUserCredentialStatus",()=>nU,"getMCPSemanticFilterSettings",()=>tI,"getMajorAirlines",()=>r7,"getModelCostMapReloadStatus",()=>H,"getModelCostMapSource",()=>L,"getOnboardingCredentials",()=>e$,"getOpenAPISchema",()=>R,"getPassThroughEndpointsCall",()=>tw,"getPoliciesList",()=>tD,"getPolicyAttachmentsList",()=>t6,"getPolicyInfo",()=>t4,"getPolicyInfoWithGuardrails",()=>tW,"getPolicyTemplates",()=>tG,"getPossibleUserRoles",()=>e4,"getPromptInfo",()=>rr,"getPromptVersions",()=>rn,"getPromptsList",()=>rt,"getProviderCreateMetadata",()=>O,"getProxyBaseUrl",()=>C,"getProxyUISettings",()=>tF,"getPublicModelHubInfo",()=>N,"getRemainingUsers",()=>ns,"getResolvedGuardrails",()=>t9,"getRouterSettingsCall",()=>tg,"getSSOSettings",()=>na,"getTeamPermissionsCall",()=>rH,"getToolUsageLogs",()=>nL,"getUISettings",()=>t_,"getUiConfig",()=>P,"getUiSettings",()=>nO,"handleError",()=>j,"individualModelHealthCheckCall",()=>tO,"invitationCreateCall",()=>q,"keyAliasesCall",()=>e1,"keyCreateCall",()=>X,"keyCreateForAgentCall",()=>Y,"keyCreateServiceAccountCall",()=>K,"keyDeleteCall",()=>Q,"keyInfoCall",()=>eY,"keyInfoV1Call",()=>eQ,"keyListCall",()=>e0,"keyUpdateCall",()=>te,"latestHealthChecksCall",()=>tT,"listGuardrailSubmissions",()=>tM,"listMCPTools",()=>rI,"listMCPUserCredentials",()=>nq,"listPolicyVersions",()=>tQ,"loginCall",()=>nj,"makeAgentsPublicCall",()=>r0,"makeMCPPublicCall",()=>r1,"makeModelGroupPublic",()=>I,"mcpHubPublicServersCall",()=>eF,"modelAvailableCall",()=>eM,"modelCostMap",()=>M,"modelCreateCall",()=>D,"modelDeleteCall",()=>V,"modelHubCall",()=>e_,"modelHubPublicModelsCall",()=>ek,"modelInfoCall",()=>ej,"modelInfoV1Call",()=>eO,"modelPatchUpdateCall",()=>tr,"organizationCreateCall",()=>eu,"organizationDailyActivityCall",()=>ey,"organizationDeleteCall",()=>ef,"organizationInfoCall",()=>ec,"organizationListCall",()=>es,"organizationMemberAddCall",()=>tl,"organizationMemberDeleteCall",()=>ts,"organizationMemberUpdateCall",()=>tc,"organizationUpdateCall",()=>ed,"patchAgentCall",()=>ne,"perUserAnalyticsCall",()=>nS,"proxyBaseUrl",()=>$,"ragIngestCall",()=>rK,"regenerateKeyCall",()=>eE,"registerClaudeCodePlugin",()=>nI,"registerMCPServer",()=>rC,"registerMcpOAuthClient",()=>nm,"rejectGuardrailSubmission",()=>tA,"rejectMCPServer",()=>rx,"reloadModelCostMap",()=>B,"resetEmailEventSettings",()=>rZ,"resolvePoliciesCall",()=>t8,"scheduleModelCostMapReload",()=>A,"searchToolQueryCall",()=>ny,"serverRootPath",()=>w,"serviceHealthCheck",()=>tf,"sessionSpendLogsCall",()=>rV,"setCallbacksCall",()=>tj,"setGlobalLitellmHeaderName",()=>F,"storeMCPOAuthUserCredential",()=>nW,"suggestPolicyTemplates",()=>tq,"tagCreateCall",()=>rN,"tagDailyActivityCall",()=>eg,"tagDauCall",()=>nb,"tagDeleteCall",()=>rA,"tagDistinctCall",()=>nC,"tagInfoCall",()=>rM,"tagListCall",()=>rB,"tagMauCall",()=>n$,"tagUpdateCall",()=>rR,"tagWauCall",()=>nw,"tagsSpendLogsCall",()=>eA,"teamBulkMemberAddCall",()=>to,"teamCreateCall",()=>e6,"teamDailyActivityCall",()=>ev,"teamDeleteCall",()=>et,"teamInfoCall",()=>eo,"teamListCall",()=>ei,"teamMemberAddCall",()=>tn,"teamMemberDeleteCall",()=>ti,"teamMemberUpdateCall",()=>ta,"teamPermissionsUpdateCall",()=>rD,"teamSpendLogsCall",()=>eB,"teamUpdateCall",()=>tt,"testCacheConnectionCall",()=>ty,"testConnectionRequest",()=>eZ,"testCustomCodeGuardrail",()=>nn,"testMCPSemanticFilter",()=>tN,"testMCPToolsListRequest",()=>nf,"testPipelineCall",()=>t5,"testPoliciesAndGuardrails",()=>tV,"testPolicyTemplate",()=>tJ,"testSearchToolConnection",()=>r_,"transformRequestCall",()=>ep,"uiAuditLogsCall",()=>nl,"uiSpendLogDetailsCall",()=>ru,"uiSpendLogsCall",()=>eD,"updateCacheSettingsCall",()=>tb,"updateConfigFieldSetting",()=>tE,"updateDefaultTeamSettings",()=>rL,"updateEmailEventSettings",()=>rY,"updateGuardrailCall",()=>nt,"updateInternalUserSettings",()=>rf,"updateMCPSemanticFilterSettings",()=>tP,"updateMCPServer",()=>rw,"updatePassThroughEndpoint",()=>nu,"updatePolicyCall",()=>tZ,"updatePolicyVersionStatus",()=>t1,"updatePromptCall",()=>ra,"updateSSOSettings",()=>ni,"updateSearchTool",()=>rk,"updateToolPolicy",()=>nD,"updateUiSettings",()=>nk,"updateUsefulLinksCall",()=>eR,"usageAiChatStream",()=>tX,"userAgentSummaryCall",()=>nE,"userBulkUpdateUserCall",()=>td,"userCreateCall",()=>Z,"userDailyActivityAggregatedCall",()=>e2,"userDailyActivityCall",()=>eh,"userDeleteCall",()=>ee,"userFilterUICall",()=>eH,"userInfoCall",()=>en,"userListCall",()=>er,"userUpdateUserCall",()=>tu,"v2TeamListCall",()=>ea,"validateBlockedWordsFile",()=>no,"vectorStoreCreateCall",()=>rW,"vectorStoreDeleteCall",()=>rU,"vectorStoreInfoCall",()=>rq,"vectorStoreListCall",()=>rG,"vectorStoreSearchCall",()=>nv,"vectorStoreUpdateCall",()=>rJ],764205),e.i(247167);var t=e.i(998573),r=e.i(268004);e.s(["default",()=>h,"jsonFields",()=>p],82946);var n=e.i(843476),o=e.i(271645),a=e.i(808613),i=e.i(311451),l=e.i(28651),s=e.i(199133),c=e.i(779241),u=e.i(827252),d=e.i(592968),f=e.i(122550);let p=["metadata","config","enforced_params","aliases"],m=(e,t)=>p.includes(e)||"json"===t.format,h=({schemaComponent:e,excludedFields:t=[],form:r,overrideLabels:p={},overrideTooltips:h={},customValidation:g={},defaultValues:v={}})=>{let[y,b]=(0,o.useState)(null),[w,$]=(0,o.useState)(null);return((0,o.useEffect)(()=>{(async()=>{try{let n=(await R()).components.schemas[e];if(!n)throw Error(`Schema component "${e}" not found`);b(n);let o={};Object.keys(n.properties).filter(e=>!t.includes(e)&&void 0!==v[e]).forEach(e=>{o[e]=v[e]}),r.setFieldsValue(o)}catch(e){console.error("Schema fetch error:",e),$(e instanceof Error?e.message:"Failed to fetch schema")}})()},[e,r,t]),w)?(0,n.jsxs)("div",{className:"text-red-500",children:["Error: ",w]}):y?.properties?(0,n.jsx)("div",{children:Object.entries(y.properties).filter(([e])=>!t.includes(e)).map(([e,t])=>{let r,o,b,w,$,C,E,S;return o=(e=>{if(e.type)return e.type;if(e.anyOf){let t=e.anyOf.map(e=>e.type);if(t.includes("number")||t.includes("integer"))return"number";t.includes("string")}return"string"})(t),b=y?.required?.includes(e),w=p[e]||t.title||(0,f.formatLabel)(e),$=h[e]||t.description,C=[],b&&C.push({required:!0,message:`${w} is required`}),g[e]&&C.push({validator:g[e]}),m(e,t)&&C.push({validator:async(e,t)=>{if(t&&!(e=>{if(!e)return!0;try{return JSON.parse(e),!0}catch{return!1}})(t))throw Error("Please enter valid JSON")}}),E=$?(0,n.jsxs)("span",{children:[w," ",(0,n.jsx)(d.Tooltip,{title:$,children:(0,n.jsx)(u.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}):w,r=m(e,t)?(0,n.jsx)(i.Input.TextArea,{rows:4,placeholder:"Enter as JSON",className:"font-mono"}):t.enum?(0,n.jsx)(s.Select,{children:t.enum.map(e=>(0,n.jsx)(s.Select.Option,{value:e,children:e},e))}):"number"===o||"integer"===o?(0,n.jsx)(l.InputNumber,{style:{width:"100%"},precision:"integer"===o?0:void 0}):"duration"===e?(0,n.jsx)(c.TextInput,{placeholder:"eg: 30s, 30h, 30d"}):(0,n.jsx)(c.TextInput,{placeholder:$||""}),(0,n.jsx)(a.Form.Item,{label:E,name:e,className:"mt-8",rules:C,initialValue:v[e],help:(0,n.jsx)("div",{className:"text-xs text-gray-500",children:(S=({max_budget:"Enter maximum budget in USD (e.g., 100.50)",budget_duration:"Select a time period for budget reset",tpm_limit:"Enter maximum tokens per minute (whole number)",rpm_limit:"Enter maximum requests per minute (whole number)",duration:"Enter duration (e.g., 30s, 24h, 7d)",metadata:'Enter JSON object with key-value pairs\nExample: {"team": "research", "project": "nlp"}',config:'Enter configuration as JSON object\nExample: {"setting": "value"}',permissions:"Enter comma-separated permission strings",enforced_params:'Enter parameters as JSON object\nExample: {"param": "value"}',blocked:"Enter true/false or specific block conditions",aliases:'Enter aliases as JSON object\nExample: {"alias1": "value1", "alias2": "value2"}',models:"Select one or more model names",key_alias:"Enter a unique identifier for this key",tags:"Enter comma-separated tag strings"})[e]||({string:"Text input",number:"Numeric input",integer:"Whole number input",boolean:"True/False value"})[o]||"Text input",m(e,t)?`${S} + `]:{animationName:i.slideDownOut},"&-hidden":{display:"none"},[o]:Object.assign(Object.assign({},l(e)),{cursor:"pointer",transition:`background ${e.motionDurationSlow} ease`,borderRadius:e.borderRadiusSM,"&-group":{color:e.colorTextDescription,fontSize:e.fontSizeSM,cursor:"default"},"&-option":{display:"flex","&-content":Object.assign({flex:"auto"},t.textEllipsis),"&-state":{flex:"none",display:"flex",alignItems:"center"},[`&-active:not(${o}-option-disabled)`]:{backgroundColor:e.optionActiveBg},[`&-selected:not(${o}-option-disabled)`]:{color:e.optionSelectedColor,fontWeight:e.optionSelectedFontWeight,backgroundColor:e.optionSelectedBg,[`${o}-option-state`]:{color:e.colorPrimary}},"&-disabled":{[`&${o}-option-selected`]:{backgroundColor:e.colorBgContainerDisabled},color:e.colorTextDisabled,cursor:"not-allowed"},"&-grouped":{paddingInlineStart:e.calc(e.controlPaddingHorizontal).mul(2).equal()}},"&-empty":Object.assign(Object.assign({},l(e)),{color:e.colorTextDisabled})}),[`${f}:has(+ ${f})`]:{borderEndStartRadius:0,borderEndEndRadius:0,[`& + ${f}`]:{borderStartStartRadius:0,borderStartEndRadius:0}},"&-rtl":{direction:"rtl"}})},(0,i.initSlideMotion)(e,"slide-up"),(0,i.initSlideMotion)(e,"slide-down"),(0,a.initMoveMotion)(e,"move-up"),(0,a.initMoveMotion)(e,"move-down")]})(e),{[`${n}-rtl`]:{direction:"rtl"}},(0,r.genCompactItemStyle)(e,{borderElCls:`${n}-selector`,focusElCls:`${n}-focused`})]})(v),{[v.componentCls]:Object.assign(Object.assign(Object.assign(Object.assign({},{"&-outlined":Object.assign(Object.assign(Object.assign(Object.assign({},d(v,{borderColor:v.colorBorder,hoverBorderHover:v.hoverBorderColor,activeBorderColor:v.activeBorderColor,activeOutlineColor:v.activeOutlineColor,color:v.colorText})),f(v,{status:"error",borderColor:v.colorError,hoverBorderHover:v.colorErrorHover,activeBorderColor:v.colorError,activeOutlineColor:v.colorErrorOutline,color:v.colorError})),f(v,{status:"warning",borderColor:v.colorWarning,hoverBorderHover:v.colorWarningHover,activeBorderColor:v.colorWarning,activeOutlineColor:v.colorWarningOutline,color:v.colorWarning})),{[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{background:v.colorBgContainerDisabled,color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.multipleItemBg,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.multipleItemBorderColor}`}})}),{"&-filled":Object.assign(Object.assign(Object.assign(Object.assign({},p(v,{bg:v.colorFillTertiary,hoverBg:v.colorFillSecondary,activeBorderColor:v.activeBorderColor,color:v.colorText})),m(v,{status:"error",bg:v.colorErrorBg,hoverBg:v.colorErrorBgHover,activeBorderColor:v.colorError,color:v.colorError})),m(v,{status:"warning",bg:v.colorWarningBg,hoverBg:v.colorWarningBgHover,activeBorderColor:v.colorWarning,color:v.colorWarning})),{[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{borderColor:v.colorBorder,background:v.colorBgContainerDisabled,color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.colorBgContainer,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.colorSplit}`}})}),{"&-borderless":{[`${v.componentCls}-selector`]:{background:"transparent",border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} transparent`},[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.multipleItemBg,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.multipleItemBorderColor}`},[`&${v.componentCls}-status-error`]:{[`${v.componentCls}-prefix, ${v.componentCls}-selection-item`]:{color:v.colorError}},[`&${v.componentCls}-status-warning`]:{[`${v.componentCls}-prefix, ${v.componentCls}-selection-item`]:{color:v.colorWarning}}}}),{"&-underlined":Object.assign(Object.assign(Object.assign(Object.assign({},h(v,{borderColor:v.colorBorder,hoverBorderHover:v.hoverBorderColor,activeBorderColor:v.activeBorderColor,activeOutlineColor:v.activeOutlineColor,color:v.colorText})),g(v,{status:"error",borderColor:v.colorError,hoverBorderHover:v.colorErrorHover,activeBorderColor:v.colorError,activeOutlineColor:v.colorErrorOutline,color:v.colorError})),g(v,{status:"warning",borderColor:v.colorWarning,hoverBorderHover:v.colorWarningHover,activeBorderColor:v.colorWarning,activeOutlineColor:v.colorWarningOutline,color:v.colorWarning})),{[`&${v.componentCls}-disabled`]:{[`&:not(${v.componentCls}-customize-input) ${v.componentCls}-selector`]:{color:v.colorTextDisabled}},[`&${v.componentCls}-multiple ${v.componentCls}-selection-item`]:{background:v.multipleItemBg,border:`${(0,s.unit)(v.lineWidth)} ${v.lineType} ${v.multipleItemBorderColor}`}})})}]},e=>{let{fontSize:t,lineHeight:r,lineWidth:n,controlHeight:o,controlHeightSM:a,controlHeightLG:i,paddingXXS:l,controlPaddingHorizontal:s,zIndexPopupBase:c,colorText:u,fontWeightStrong:d,controlItemBgActive:f,controlItemBgHover:p,colorBgContainer:m,colorFillSecondary:h,colorBgContainerDisabled:g,colorTextDisabled:v,colorPrimaryHover:y,colorPrimary:b,controlOutline:w}=e,$=2*l,C=2*n,E=Math.min(o-$,o-C),S=Math.min(a-$,a-C),x=Math.min(i-$,i-C);return{INTERNAL_FIXED_ITEM_MARGIN:Math.floor(l/2),zIndexPopup:c+50,optionSelectedColor:u,optionSelectedFontWeight:d,optionSelectedBg:f,optionActiveBg:p,optionPadding:`${(o-t*r)/2}px ${s}px`,optionFontSize:t,optionLineHeight:r,optionHeight:o,selectorBg:m,clearBg:m,singleItemHeightLG:i,multipleItemBg:h,multipleItemBorderColor:"transparent",multipleItemHeight:E,multipleItemHeightSM:S,multipleItemHeightLG:x,multipleSelectorBgDisabled:g,multipleItemColorDisabled:v,multipleItemBorderColorDisabled:"transparent",showArrowPaddingInlineEnd:Math.ceil(1.25*e.fontSize),hoverBorderColor:y,activeBorderColor:b,activeOutlineColor:w,selectAffixPadding:l}},{unitless:{optionLineHeight:!0,optionSelectedFontWeight:!0}});e.s(["default",0,v],950302)},729151,e=>{"use strict";var t=e.i(271645),r=e.i(121229),n=e.i(726289),o=e.i(864517),a=e.i(247153),i=e.i(739295),l=e.i(38953);function s({suffixIcon:e,clearIcon:s,menuItemSelectedIcon:c,removeIcon:u,loading:d,multiple:f,hasFeedback:p,prefixCls:m,showSuffixIcon:h,feedbackIcon:g,showArrow:v,componentName:y}){let b=null!=s?s:t.createElement(n.default,null),w=r=>null!==e||p||v?t.createElement(t.Fragment,null,!1!==h&&r,p&&g):null,$=null;if(void 0!==e)$=w(e);else if(d)$=w(t.createElement(i.default,{spin:!0}));else{let e=`${m}-suffix`;$=({open:r,showSearch:n})=>r&&n?w(t.createElement(l.default,{className:e})):w(t.createElement(a.default,{className:e}))}let C=null;C=void 0!==c?c:f?t.createElement(r.default,null):null;return{clearIcon:b,suffixIcon:$,itemIcon:C,removeIcon:void 0!==u?u:t.createElement(o.default,null)}}e.s(["default",()=>s])},327494,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),n=e.i(123829),o=e.i(955492),a=e.i(869301),i=e.i(529681),l=e.i(122767),s=e.i(613541),c=e.i(805484),u=e.i(52956),d=e.i(242064),f=e.i(721132),p=e.i(937328),m=e.i(321883),h=e.i(517455),g=e.i(62139),v=e.i(792812),y=e.i(249616),b=e.i(104458),w=e.i(85566),$=e.i(950302),C=e.i(729151),E=e.i(617206),S=function(e,t){var r={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&0>t.indexOf(n)&&(r[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var o=0,n=Object.getOwnPropertySymbols(e);ot.indexOf(n[o])&&Object.prototype.propertyIsEnumerable.call(e,n[o])&&(r[n[o]]=e[n[o]]);return r};let x="SECRET_COMBOBOX_MODE_DO_NOT_USE",j=t.forwardRef((e,o)=>{var a,c,j,O,k,T,F,_;let I,{prefixCls:P,bordered:N,className:R,rootClassName:M,getPopupContainer:B,popupClassName:A,dropdownClassName:z,listHeight:L=256,placement:H,listItemHeight:D,size:V,disabled:W,notFoundContent:G,status:U,builtinPlacements:q,dropdownMatchSelectWidth:J,popupMatchSelectWidth:K,direction:X,style:Y,allowClear:Z,variant:Q,dropdownStyle:ee,transitionName:et,tagRender:er,maxCount:en,prefix:eo,dropdownRender:ea,popupRender:ei,onDropdownVisibleChange:el,onOpenChange:es,styles:ec,classNames:eu}=e,ed=S(e,["prefixCls","bordered","className","rootClassName","getPopupContainer","popupClassName","dropdownClassName","listHeight","placement","listItemHeight","size","disabled","notFoundContent","status","builtinPlacements","dropdownMatchSelectWidth","popupMatchSelectWidth","direction","style","allowClear","variant","dropdownStyle","transitionName","tagRender","maxCount","prefix","dropdownRender","popupRender","onDropdownVisibleChange","onOpenChange","styles","classNames"]),{getPopupContainer:ef,getPrefixCls:ep,renderEmpty:em,direction:eh,virtual:eg,popupMatchSelectWidth:ev,popupOverflow:ey}=t.useContext(d.ConfigContext),{showSearch:eb,style:ew,styles:e$,className:eC,classNames:eE}=(0,d.useComponentConfig)("select"),[,eS]=(0,b.useToken)(),ex=null!=D?D:null==eS?void 0:eS.controlHeight,ej=ep("select",P),eO=ep(),ek=null!=X?X:eh,{compactSize:eT,compactItemClassnames:eF}=(0,y.useCompactItemContext)(ej,ek),[e_,eI]=(0,v.default)("select",Q,N),eP=(0,m.default)(ej),[eN,eR,eM]=(0,$.default)(ej,eP),eB=t.useMemo(()=>{let{mode:t}=e;if("combobox"!==t)return t===x?"combobox":t},[e.mode]),eA="multiple"===eB||"tags"===eB,ez=(T=e.suffixIcon,void 0!==(F=e.showArrow)?F:null!==T),eL=null!=(a=null!=K?K:J)?a:ev,eH=(null==(c=null==ec?void 0:ec.popup)?void 0:c.root)||(null==(j=e$.popup)?void 0:j.root)||ee,eD=(_=ei||ea,t.default.useMemo(()=>{if(_)return(...e)=>t.default.createElement(E.default,{space:!0},_.apply(void 0,e))},[_])),{status:eV,hasFeedback:eW,isFormItemInput:eG,feedbackIcon:eU}=t.useContext(g.FormItemInputContext),eq=(0,u.getMergedStatus)(eV,U);I=void 0!==G?G:"combobox"===eB?null:(null==em?void 0:em("Select"))||t.createElement(f.default,{componentName:"Select"});let{suffixIcon:eJ,itemIcon:eK,removeIcon:eX,clearIcon:eY}=(0,C.default)(Object.assign(Object.assign({},ed),{multiple:eA,hasFeedback:eW,feedbackIcon:eU,showSuffixIcon:ez,prefixCls:ej,componentName:"Select"})),eZ=(0,i.default)(ed,["suffixIcon","itemIcon"]),eQ=(0,r.default)((null==(O=null==eu?void 0:eu.popup)?void 0:O.root)||(null==(k=null==eE?void 0:eE.popup)?void 0:k.root)||A||z,{[`${ej}-dropdown-${ek}`]:"rtl"===ek},M,eE.root,null==eu?void 0:eu.root,eM,eP,eR),e0=(0,h.default)(e=>{var t;return null!=(t=null!=V?V:eT)?t:e}),e1=t.useContext(p.default),e2=(0,r.default)({[`${ej}-lg`]:"large"===e0,[`${ej}-sm`]:"small"===e0,[`${ej}-rtl`]:"rtl"===ek,[`${ej}-${e_}`]:eI,[`${ej}-in-form-item`]:eG},(0,u.getStatusClassNames)(ej,eq,eW),eF,eC,R,eE.root,null==eu?void 0:eu.root,M,eM,eP,eR),e4=t.useMemo(()=>void 0!==H?H:"rtl"===ek?"bottomRight":"bottomLeft",[H,ek]),[e6]=(0,l.useZIndex)("SelectLike",null==eH?void 0:eH.zIndex);return eN(t.createElement(n.default,Object.assign({ref:o,virtual:eg,showSearch:eb},eZ,{style:Object.assign(Object.assign(Object.assign(Object.assign({},e$.root),null==ec?void 0:ec.root),ew),Y),dropdownMatchSelectWidth:eL,transitionName:(0,s.getTransitionName)(eO,"slide-up",et),builtinPlacements:(0,w.default)(q,ey),listHeight:L,listItemHeight:ex,mode:eB,prefixCls:ej,placement:e4,direction:ek,prefix:eo,suffixIcon:eJ,menuItemSelectedIcon:eK,removeIcon:eX,allowClear:!0===Z?{clearIcon:eY}:Z,notFoundContent:I,className:e2,getPopupContainer:B||ef,dropdownClassName:eQ,disabled:null!=W?W:e1,dropdownStyle:Object.assign(Object.assign({},eH),{zIndex:e6}),maxCount:eA?en:void 0,tagRender:eA?er:void 0,dropdownRender:eD,onDropdownVisibleChange:es||el})))}),O=(0,c.default)(j,"dropdownAlign");j.SECRET_COMBOBOX_MODE_DO_NOT_USE=x,j.Option=a.Option,j.OptGroup=o.OptGroup,j._InternalPanelDoNotUseOrYouWillBeFired=O,e.s(["default",0,j],327494)},199133,e=>{"use strict";var t=e.i(327494);e.s(["Select",()=>t.default])},689074,21243,98801,e=>{"use strict";var t=e.i(290571),r=e.i(271645);let n=e=>{var n=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},n),r.default.createElement("path",{d:"M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM11 15V17H13V15H11ZM11 7V13H13V7H11Z"}))};e.s(["default",()=>n],689074);let o=e=>{var n=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},n),r.default.createElement("path",{d:"M1.18164 12C2.12215 6.87976 6.60812 3 12.0003 3C17.3924 3 21.8784 6.87976 22.8189 12C21.8784 17.1202 17.3924 21 12.0003 21C6.60812 21 2.12215 17.1202 1.18164 12ZM12.0003 17C14.7617 17 17.0003 14.7614 17.0003 12C17.0003 9.23858 14.7617 7 12.0003 7C9.23884 7 7.00026 9.23858 7.00026 12C7.00026 14.7614 9.23884 17 12.0003 17ZM12.0003 15C10.3434 15 9.00026 13.6569 9.00026 12C9.00026 10.3431 10.3434 9 12.0003 9C13.6571 9 15.0003 10.3431 15.0003 12C15.0003 13.6569 13.6571 15 12.0003 15Z"}))};e.s(["default",()=>o],21243);let a=e=>{var n=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},n),r.default.createElement("path",{d:"M4.52047 5.93457L1.39366 2.80777L2.80788 1.39355L22.6069 21.1925L21.1927 22.6068L17.8827 19.2968C16.1814 20.3755 14.1638 21.0002 12.0003 21.0002C6.60812 21.0002 2.12215 17.1204 1.18164 12.0002C1.61832 9.62282 2.81932 7.5129 4.52047 5.93457ZM14.7577 16.1718L13.2937 14.7078C12.902 14.8952 12.4634 15.0002 12.0003 15.0002C10.3434 15.0002 9.00026 13.657 9.00026 12.0002C9.00026 11.537 9.10522 11.0984 9.29263 10.7067L7.82866 9.24277C7.30514 10.0332 7.00026 10.9811 7.00026 12.0002C7.00026 14.7616 9.23884 17.0002 12.0003 17.0002C13.0193 17.0002 13.9672 16.6953 14.7577 16.1718ZM7.97446 3.76015C9.22127 3.26959 10.5793 3.00016 12.0003 3.00016C17.3924 3.00016 21.8784 6.87992 22.8189 12.0002C22.5067 13.6998 21.8038 15.2628 20.8068 16.5925L16.947 12.7327C16.9821 12.4936 17.0003 12.249 17.0003 12.0002C17.0003 9.23873 14.7617 7.00016 12.0003 7.00016C11.7514 7.00016 11.5068 7.01833 11.2677 7.05343L7.97446 3.76015Z"}))};e.s(["default",()=>a],98801)},103471,e=>{"use strict";var t=e.i(444755),r=e.i(271645);let n=e=>["string","number"].includes(typeof e)?e:e instanceof Array?e.map(n).join(""):"object"==typeof e&&e?n(e.props.children):void 0;function o(e){let t=new Map;return r.default.Children.map(e,e=>{var r;t.set(e.props.value,null!=(r=n(e))?r:e.props.value)}),t}function a(e,t){return r.default.Children.map(t,t=>{var r;if((null!=(r=n(t))?r:t.props.value).toLowerCase().includes(e.toLowerCase()))return t})}let i=(e,r,n=!1)=>(0,t.tremorTwMerge)(r?"bg-tremor-background-subtle dark:bg-dark-tremor-background-subtle":"bg-tremor-background dark:bg-dark-tremor-background",!r&&"hover:bg-tremor-background-muted dark:hover:bg-dark-tremor-background-muted",e?"text-tremor-content-emphasis dark:text-dark-tremor-content-emphasis":"text-tremor-content dark:text-dark-tremor-content",r&&"text-tremor-content-subtle dark:text-dark-tremor-content-subtle",n&&"text-red-500 placeholder:text-red-500 dark:text-red-500 dark:placeholder:text-red-500",n?"border-red-500 dark:border-red-500":"border-tremor-border dark:border-dark-tremor-border");function l(e){return null!=e&&""!==e}e.s(["constructValueToNameMapping",()=>o,"getFilteredOptions",()=>a,"getNodeText",()=>n,"getSelectButtonColors",()=>i,"hasValue",()=>l])},779241,677955,e=>{"use strict";var t=e.i(290571),r=e.i(271645),n=e.i(673706),o=e.i(689074),a=e.i(21243),i=e.i(98801),l=e.i(103471),s=e.i(444755);let c=r.default.forwardRef((e,c)=>{let{value:u,defaultValue:d,type:f,placeholder:p="Type...",icon:m,error:h=!1,errorMessage:g,disabled:v=!1,stepper:y,makeInputClassName:b,className:w,onChange:$,onValueChange:C,autoFocus:E,pattern:S}=e,x=(0,t.__rest)(e,["value","defaultValue","type","placeholder","icon","error","errorMessage","disabled","stepper","makeInputClassName","className","onChange","onValueChange","autoFocus","pattern"]),[j,O]=(0,r.useState)(E||!1),[k,T]=(0,r.useState)(!1),F=(0,r.useCallback)(()=>T(!k),[k,T]),_=(0,r.useRef)(null),I=(0,l.hasValue)(u||d);return r.default.useEffect(()=>{let e=()=>O(!0),t=()=>O(!1),r=_.current;return r&&(r.addEventListener("focus",e),r.addEventListener("blur",t),E&&r.focus()),()=>{r&&(r.removeEventListener("focus",e),r.removeEventListener("blur",t))}},[E]),r.default.createElement(r.default.Fragment,null,r.default.createElement("div",{className:(0,s.tremorTwMerge)(b("root"),"relative w-full flex items-center min-w-[10rem] outline-none rounded-tremor-default transition duration-100 border","shadow-tremor-input","dark:shadow-dark-tremor-input",(0,l.getSelectButtonColors)(I,v,h),j&&(0,s.tremorTwMerge)("ring-2","border-tremor-brand-subtle ring-tremor-brand-muted","dark:border-dark-tremor-brand-subtle dark:ring-dark-tremor-brand-muted"),w)},m?r.default.createElement(m,{className:(0,s.tremorTwMerge)(b("icon"),"shrink-0 h-5 w-5 mx-2.5 absolute left-0 flex items-center","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle")}):null,r.default.createElement("input",Object.assign({ref:(0,n.mergeRefs)([_,c]),defaultValue:d,value:u,type:k?"text":f,className:(0,s.tremorTwMerge)(b("input"),"w-full bg-transparent focus:outline-none focus:ring-0 border-none text-tremor-default rounded-tremor-default transition duration-100 py-2","text-tremor-content-emphasis","dark:text-dark-tremor-content-emphasis","[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none","password"===f?h?"pr-16":"pr-12":h?"pr-8":"pr-3",m?"pl-10":"pl-3",v?"placeholder:text-tremor-content-subtle dark:placeholder:text-dark-tremor-content-subtle":"placeholder:text-tremor-content dark:placeholder:text-dark-tremor-content"),placeholder:p,disabled:v,"data-testid":"base-input",onChange:e=>{null==$||$(e),null==C||C(e.target.value)},pattern:S},x)),"password"!==f||v?null:r.default.createElement("button",{className:(0,s.tremorTwMerge)(b("toggleButton"),"absolute inset-y-0 right-0 flex items-center px-2.5 rounded-lg"),type:"button",onClick:()=>F(),"aria-label":k?"Hide password":"Show Password"},k?r.default.createElement(i.default,{className:(0,s.tremorTwMerge)("flex-none h-5 w-5 transition","text-tremor-content-subtle hover:text-tremor-content","dark:text-dark-tremor-content-subtle hover:dark:text-dark-tremor-content"),"aria-hidden":!0}):r.default.createElement(a.default,{className:(0,s.tremorTwMerge)("flex-none h-5 w-5 transition","text-tremor-content-subtle hover:text-tremor-content","dark:text-dark-tremor-content-subtle hover:dark:text-dark-tremor-content"),"aria-hidden":!0})),h?r.default.createElement(o.default,{className:(0,s.tremorTwMerge)(b("errorIcon"),"text-red-500 shrink-0 h-5 w-5 absolute right-0 flex items-center","password"===f?"mr-10":"number"===f?y?"mr-20":"mr-3":"mx-2.5")}):null,null!=y?y:null),h&&g?r.default.createElement("p",{className:(0,s.tremorTwMerge)(b("errorMessage"),"text-sm text-red-500 mt-1")},g):null)});c.displayName="BaseInput",e.s(["default",()=>c],677955);let u=(0,n.makeClassName)("TextInput"),d=r.default.forwardRef((e,n)=>{let{type:o="text"}=e,a=(0,t.__rest)(e,["type"]);return r.default.createElement(c,Object.assign({ref:n,type:o,makeInputClassName:u},a))});d.displayName="TextInput",e.s(["TextInput",()=>d],779241)},122550,e=>{"use strict";function t(e,t){return e.length>t?e.substring(0,t)+"...":e}e.s(["formItemValidateJSON",0,(e,t)=>{if(!t)return Promise.resolve();try{return JSON.parse(t),Promise.resolve()}catch(e){return Promise.reject("Please enter valid JSON")}},"formatLabel",0,e=>e?e.replace(/_/g," ").replace(/\b\w/g,e=>e.toUpperCase()):e,"truncateString",()=>t])},764205,82946,e=>{"use strict";e.s(["addAllowedIP",()=>eN,"adminGlobalActivity",()=>eJ,"adminGlobalActivityPerModel",()=>eX,"adminGlobalCacheActivity",()=>eK,"adminSpendLogsCall",()=>eW,"adminTopEndUsersCall",()=>eU,"adminTopKeysCall",()=>eG,"adminTopModelsCall",()=>eY,"adminspendByProvider",()=>eq,"agentDailyActivityCall",()=>e$,"agentHubPublicModelsCall",()=>eF,"alertingSettingsCall",()=>J,"allEndUsersCall",()=>eH,"allTagNamesCall",()=>eL,"applyGuardrail",()=>nn,"approveGuardrailSubmission",()=>tA,"approveMCPServer",()=>rx,"availableTeamListCall",()=>es,"budgetCreateCall",()=>G,"budgetDeleteCall",()=>W,"budgetUpdateCall",()=>U,"buildMcpOAuthAuthorizeUrl",()=>ng,"cacheTemporaryMcpServer",()=>nm,"cachingHealthCheckCall",()=>tT,"callMCPTool",()=>rN,"cancelModelCostMapReload",()=>z,"checkEuAiActCompliance",()=>nB,"checkGdprCompliance",()=>nA,"claimOnboardingToken",()=>eE,"convertPromptFileToJson",()=>rs,"createAgentCall",()=>rc,"createGuardrailCall",()=>ru,"createMCPServer",()=>rw,"createPassThroughEndpoint",()=>tE,"createPolicyAttachmentCall",()=>t7,"createPolicyCall",()=>tZ,"createPolicyVersion",()=>t1,"createPromptCall",()=>ra,"createSearchTool",()=>rk,"credentialCreateCall",()=>e7,"credentialDeleteCall",()=>e8,"credentialGetCall",()=>e9,"credentialListCall",()=>e5,"credentialUpdateCall",()=>te,"customerDailyActivityCall",()=>ew,"deleteAgentCall",()=>r0,"deleteAllowedIP",()=>eR,"deleteCallback",()=>nf,"deleteClaudeCodePlugin",()=>nM,"deleteConfigFieldSetting",()=>tx,"deleteGuardrailCall",()=>r4,"deleteMCPOAuthUserCredential",()=>nU,"deleteMCPServer",()=>rC,"deletePassThroughEndpointsCall",()=>tj,"deletePolicyAttachmentCall",()=>t5,"deletePolicyCall",()=>t4,"deletePromptCall",()=>rl,"deleteSearchTool",()=>rF,"deleteToolPolicyOverride",()=>nW,"deriveErrorMessage",()=>nj,"disableClaudeCodePlugin",()=>nR,"enableClaudeCodePlugin",()=>nN,"enrichPolicyTemplate",()=>tq,"enrichPolicyTemplateStream",()=>tX,"estimateAttachmentImpactCall",()=>rt,"exchangeMcpOAuthToken",()=>nv,"fetchAvailableSearchProviders",()=>r_,"fetchDiscoverableMCPServers",()=>rh,"fetchMCPAccessGroups",()=>ry,"fetchMCPClientIp",()=>rb,"fetchMCPServerHealth",()=>rv,"fetchMCPServers",()=>rg,"fetchMCPSubmissions",()=>rS,"fetchOpenAPIRegistry",()=>rm,"fetchSearchTools",()=>rO,"fetchToolDetail",()=>nD,"fetchToolPolicyOptions",()=>nz,"fetchToolsList",()=>nL,"formatDate",()=>v,"getAgentCreateMetadata",()=>k,"getAgentInfo",()=>r8,"getAgentsList",()=>r9,"getAllowedIPs",()=>eP,"getBudgetList",()=>tm,"getCacheSettingsCall",()=>ty,"getCallbackConfigsCall",()=>y,"getCallbacksCall",()=>th,"getCategoryYaml",()=>r7,"getClaudeCodeMarketplace",()=>nF,"getClaudeCodePluginDetails",()=>nI,"getClaudeCodePluginsList",()=>n_,"getConfigFieldSetting",()=>tC,"getDefaultTeamSettings",()=>rL,"getEmailEventSettings",()=>rY,"getGeneralSettingsCall",()=>tg,"getGlobalLitellmHeaderName",()=>_,"getGuardrailInfo",()=>ne,"getGuardrailProviderSpecificParams",()=>r3,"getGuardrailUISettings",()=>r6,"getGuardrailsList",()=>tM,"getGuardrailsUsageDetail",()=>tH,"getGuardrailsUsageLogs",()=>tD,"getGuardrailsUsageOverview",()=>tL,"getInProductNudgesCall",()=>b,"getInternalUserSettings",()=>rf,"getLicenseInfo",()=>nu,"getMCPOAuthUserCredentialStatus",()=>nq,"getMCPSemanticFilterSettings",()=>tP,"getMajorAirlines",()=>r5,"getModelCostMapReloadStatus",()=>H,"getModelCostMapSource",()=>L,"getOnboardingCredentials",()=>eC,"getOpenAPISchema",()=>R,"getPassThroughEndpointsCall",()=>t$,"getPoliciesList",()=>tV,"getPolicyAttachmentsList",()=>t3,"getPolicyInfo",()=>t6,"getPolicyInfoWithGuardrails",()=>tG,"getPolicyTemplates",()=>tU,"getPossibleUserRoles",()=>e6,"getPromptInfo",()=>rn,"getPromptVersions",()=>ro,"getPromptsList",()=>rr,"getProviderCreateMetadata",()=>O,"getProxyBaseUrl",()=>C,"getProxyUISettings",()=>t_,"getPublicModelHubInfo",()=>N,"getRemainingUsers",()=>nc,"getResolvedGuardrails",()=>t8,"getRouterSettingsCall",()=>tv,"getSSOSettings",()=>ni,"getTeamPermissionsCall",()=>rD,"getToolUsageLogs",()=>nH,"getUISettings",()=>tI,"getUiConfig",()=>P,"getUiSettings",()=>nk,"handleError",()=>j,"individualModelHealthCheckCall",()=>tk,"invitationCreateCall",()=>q,"keyAliasesCall",()=>e2,"keyCreateCall",()=>X,"keyCreateForAgentCall",()=>Y,"keyCreateServiceAccountCall",()=>K,"keyDeleteCall",()=>Q,"keyInfoCall",()=>eZ,"keyInfoV1Call",()=>e0,"keyListCall",()=>e1,"keyUpdateCall",()=>tt,"latestHealthChecksCall",()=>tF,"listGuardrailSubmissions",()=>tB,"listMCPTools",()=>rP,"listMCPUserCredentials",()=>nJ,"listPolicyVersions",()=>t0,"loginCall",()=>nO,"makeAgentsPublicCall",()=>r1,"makeMCPPublicCall",()=>r2,"makeModelGroupPublic",()=>I,"mcpHubPublicServersCall",()=>e_,"modelAvailableCall",()=>eB,"modelCostMap",()=>M,"modelCreateCall",()=>D,"modelDeleteCall",()=>V,"modelHubCall",()=>eI,"modelHubPublicModelsCall",()=>eT,"modelInfoCall",()=>eO,"modelInfoV1Call",()=>ek,"modelPatchUpdateCall",()=>tn,"organizationCreateCall",()=>ed,"organizationDailyActivityCall",()=>eb,"organizationDeleteCall",()=>ep,"organizationInfoCall",()=>eu,"organizationListCall",()=>ec,"organizationMemberAddCall",()=>ts,"organizationMemberDeleteCall",()=>tc,"organizationMemberUpdateCall",()=>tu,"organizationUpdateCall",()=>ef,"patchAgentCall",()=>nt,"perUserAnalyticsCall",()=>nx,"proxyBaseUrl",()=>$,"ragIngestCall",()=>rX,"regenerateKeyCall",()=>eS,"registerClaudeCodePlugin",()=>nP,"registerMCPServer",()=>rE,"registerMcpOAuthClient",()=>nh,"rejectGuardrailSubmission",()=>tz,"rejectMCPServer",()=>rj,"reloadModelCostMap",()=>B,"resetEmailEventSettings",()=>rQ,"resolvePoliciesCall",()=>re,"scheduleModelCostMapReload",()=>A,"searchToolQueryCall",()=>nb,"serverRootPath",()=>w,"serviceHealthCheck",()=>tp,"sessionSpendLogsCall",()=>rW,"setCallbacksCall",()=>tO,"setGlobalLitellmHeaderName",()=>F,"storeMCPOAuthUserCredential",()=>nG,"suggestPolicyTemplates",()=>tJ,"tagCreateCall",()=>rR,"tagDailyActivityCall",()=>ev,"tagDauCall",()=>nw,"tagDeleteCall",()=>rz,"tagDistinctCall",()=>nE,"tagInfoCall",()=>rB,"tagListCall",()=>rA,"tagMauCall",()=>nC,"tagUpdateCall",()=>rM,"tagWauCall",()=>n$,"tagsSpendLogsCall",()=>ez,"teamBulkMemberAddCall",()=>ta,"teamCreateCall",()=>e3,"teamDailyActivityCall",()=>ey,"teamDeleteCall",()=>et,"teamInfoCall",()=>ea,"teamListCall",()=>el,"teamMemberAddCall",()=>to,"teamMemberDeleteCall",()=>tl,"teamMemberUpdateCall",()=>ti,"teamPermissionsUpdateCall",()=>rV,"teamSpendLogsCall",()=>eA,"teamUpdateCall",()=>tr,"testCacheConnectionCall",()=>tb,"testConnectionRequest",()=>eQ,"testCustomCodeGuardrail",()=>no,"testMCPSemanticFilter",()=>tR,"testMCPToolsListRequest",()=>np,"testPipelineCall",()=>t9,"testPoliciesAndGuardrails",()=>tW,"testPolicyTemplate",()=>tK,"testSearchToolConnection",()=>rI,"transformRequestCall",()=>em,"uiAuditLogsCall",()=>ns,"uiSpendLogDetailsCall",()=>rd,"uiSpendLogsCall",()=>eV,"updateCacheSettingsCall",()=>tw,"updateConfigFieldSetting",()=>tS,"updateDefaultTeamSettings",()=>rH,"updateEmailEventSettings",()=>rZ,"updateGuardrailCall",()=>nr,"updateInternalUserSettings",()=>rp,"updateMCPSemanticFilterSettings",()=>tN,"updateMCPServer",()=>r$,"updatePassThroughEndpoint",()=>nd,"updatePolicyCall",()=>tQ,"updatePolicyVersionStatus",()=>t2,"updatePromptCall",()=>ri,"updateSSOSettings",()=>nl,"updateSearchTool",()=>rT,"updateToolPolicy",()=>nV,"updateUiSettings",()=>nT,"updateUsefulLinksCall",()=>eM,"usageAiChatStream",()=>tY,"userAgentSummaryCall",()=>nS,"userBulkUpdateUserCall",()=>tf,"userCreateCall",()=>Z,"userDailyActivityAggregatedCall",()=>e4,"userDailyActivityCall",()=>eg,"userDeleteCall",()=>ee,"userFilterUICall",()=>eD,"userGetInfoV2",()=>en,"userInfoCall",()=>eo,"userListCall",()=>er,"userUpdateUserCall",()=>td,"v2TeamListCall",()=>ei,"validateBlockedWordsFile",()=>na,"vectorStoreCreateCall",()=>rG,"vectorStoreDeleteCall",()=>rq,"vectorStoreInfoCall",()=>rJ,"vectorStoreListCall",()=>rU,"vectorStoreSearchCall",()=>ny,"vectorStoreUpdateCall",()=>rK],764205),e.i(247167);var t=e.i(998573),r=e.i(268004);e.s(["default",()=>h,"jsonFields",()=>p],82946);var n=e.i(843476),o=e.i(271645),a=e.i(808613),i=e.i(311451),l=e.i(28651),s=e.i(199133),c=e.i(779241),u=e.i(827252),d=e.i(592968),f=e.i(122550);let p=["metadata","config","enforced_params","aliases"],m=(e,t)=>p.includes(e)||"json"===t.format,h=({schemaComponent:e,excludedFields:t=[],form:r,overrideLabels:p={},overrideTooltips:h={},customValidation:g={},defaultValues:v={}})=>{let[y,b]=(0,o.useState)(null),[w,$]=(0,o.useState)(null);return((0,o.useEffect)(()=>{(async()=>{try{let n=(await R()).components.schemas[e];if(!n)throw Error(`Schema component "${e}" not found`);b(n);let o={};Object.keys(n.properties).filter(e=>!t.includes(e)&&void 0!==v[e]).forEach(e=>{o[e]=v[e]}),r.setFieldsValue(o)}catch(e){console.error("Schema fetch error:",e),$(e instanceof Error?e.message:"Failed to fetch schema")}})()},[e,r,t]),w)?(0,n.jsxs)("div",{className:"text-red-500",children:["Error: ",w]}):y?.properties?(0,n.jsx)("div",{children:Object.entries(y.properties).filter(([e])=>!t.includes(e)).map(([e,t])=>{let r,o,b,w,$,C,E,S;return o=(e=>{if(e.type)return e.type;if(e.anyOf){let t=e.anyOf.map(e=>e.type);if(t.includes("number")||t.includes("integer"))return"number";t.includes("string")}return"string"})(t),b=y?.required?.includes(e),w=p[e]||t.title||(0,f.formatLabel)(e),$=h[e]||t.description,C=[],b&&C.push({required:!0,message:`${w} is required`}),g[e]&&C.push({validator:g[e]}),m(e,t)&&C.push({validator:async(e,t)=>{if(t&&!(e=>{if(!e)return!0;try{return JSON.parse(e),!0}catch{return!1}})(t))throw Error("Please enter valid JSON")}}),E=$?(0,n.jsxs)("span",{children:[w," ",(0,n.jsx)(d.Tooltip,{title:$,children:(0,n.jsx)(u.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}):w,r=m(e,t)?(0,n.jsx)(i.Input.TextArea,{rows:4,placeholder:"Enter as JSON",className:"font-mono"}):t.enum?(0,n.jsx)(s.Select,{children:t.enum.map(e=>(0,n.jsx)(s.Select.Option,{value:e,children:e},e))}):"number"===o||"integer"===o?(0,n.jsx)(l.InputNumber,{style:{width:"100%"},precision:"integer"===o?0:void 0}):"duration"===e?(0,n.jsx)(c.TextInput,{placeholder:"eg: 30s, 30h, 30d"}):(0,n.jsx)(c.TextInput,{placeholder:$||""}),(0,n.jsx)(a.Form.Item,{label:E,name:e,className:"mt-8",rules:C,initialValue:v[e],help:(0,n.jsx)("div",{className:"text-xs text-gray-500",children:(S=({max_budget:"Enter maximum budget in USD (e.g., 100.50)",budget_duration:"Select a time period for budget reset",tpm_limit:"Enter maximum tokens per minute (whole number)",rpm_limit:"Enter maximum requests per minute (whole number)",duration:"Enter duration (e.g., 30s, 24h, 7d)",metadata:'Enter JSON object with key-value pairs\nExample: {"team": "research", "project": "nlp"}',config:'Enter configuration as JSON object\nExample: {"setting": "value"}',permissions:"Enter comma-separated permission strings",enforced_params:'Enter parameters as JSON object\nExample: {"param": "value"}',blocked:"Enter true/false or specific block conditions",aliases:'Enter aliases as JSON object\nExample: {"alias1": "value1", "alias2": "value2"}',models:"Select one or more model names",key_alias:"Enter a unique identifier for this key",tags:"Enter comma-separated tag strings"})[e]||({string:"Text input",number:"Numeric input",integer:"Whole number input",boolean:"True/False value"})[o]||"Text input",m(e,t)?`${S} Must be valid JSON format`:t.enum?`Select from available options -Allowed values: ${t.enum.join(", ")}`:S)}),children:r},e)})}):null};var g=e.i(727749);let v=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${n}`},y=async e=>{try{let t=$?`${$}/callbacks/configs`:"/callbacks/configs",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},b=async e=>{try{let t=$?`${$}/in_product_nudges`:"/in_product_nudges",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get in-product nudges:",e),e}},w="/",$=null;console.log=function(){};let C=()=>{if($)return $;let e=window.location;return e?.origin??""},E="POST",S="DELETE",x=0,j=async e=>{let t=Date.now();if(t-x>6e4){if(("string"==typeof e?e:JSON.stringify(e)).includes("Authentication Error - Expired Key")){g.default.info("UI Session Expired. Logging out."),x=t,(0,r.clearTokenCookies)();let e=window.location;e&&(window.location.href=e.pathname)}x=t}else console.log("Error suppressed to prevent spam:",e)},O=async()=>{let e=$?`${$}/public/providers/fields`:"/public/providers/fields",t=await fetch(e,{method:"GET"});if(!t.ok){let e=await t.text();throw console.error("Failed to fetch provider create metadata:",t.status,e),Error("Failed to load provider configuration")}return await t.json()},k=async()=>{let e=$?`${$}/public/agents/fields`:"/public/agents/fields",t=await fetch(e,{method:"GET"});if(!t.ok){let e=await t.text();throw console.error("Failed to fetch agent create metadata:",t.status,e),Error("Failed to load agent configuration")}return await t.json()},T="Authorization";function F(e="Authorization"){console.log(`setGlobalLitellmHeaderName: ${e}`),T=e}function _(){return T}let I=async(e,t)=>{let r=$?`${$}/model_group/make_public`:"/model_group/make_public";return(await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({model_groups:t})})).json()},P=async()=>{console.log("Getting UI config");let e=await fetch("/litellm/.well-known/litellm-ui-config"),t=await e.json();return console.log("jsonData in getUiConfig:",t),((e,t=null)=>{let r=window.location,n=r?.origin??null,o=t||n;if(console.log("proxyBaseUrl:",$),console.log("serverRootPath:",e),!o)return console.log("Updated proxyBaseUrl:",$=$??null);e.length>0&&!o.endsWith(e)&&"/"!=e&&(o+=e),console.log("Updated proxyBaseUrl:",$=o)})(t.server_root_path,t.proxy_base_url),t},N=async()=>{let e=$?`${$}/public/model_hub/info`:"/public/model_hub/info",t=await fetch(e);return await t.json()},R=async()=>{let e=$?`${$}/openapi.json`:"/openapi.json",t=await fetch(e);return await t.json()},M=async()=>{try{let e=$?`${$}/public/litellm_model_cost_map`:"/public/litellm_model_cost_map",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}}),r=await t.json();return console.log(`received litellm model cost data: ${r}`),r}catch(e){throw console.error("Failed to get model cost map:",e),e}},B=async e=>{try{let t=$?`${$}/reload/model_cost_map`:"/reload/model_cost_map",r=await fetch(t,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}}),n=await r.json();return console.log(`Model cost map reload response: ${n}`),n}catch(e){throw console.error("Failed to reload model cost map:",e),e}},A=async(e,t)=>{try{let r=$?`${$}/schedule/model_cost_map_reload?hours=${t}`:`/schedule/model_cost_map_reload?hours=${t}`,n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}}),o=await n.json();return console.log(`Schedule model cost map reload response: ${o}`),o}catch(e){throw console.error("Failed to schedule model cost map reload:",e),e}},z=async e=>{try{let t=$?`${$}/schedule/model_cost_map_reload`:"/schedule/model_cost_map_reload",r=await fetch(t,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}}),n=await r.json();return console.log(`Cancel model cost map reload response: ${n}`),n}catch(e){throw console.error("Failed to cancel model cost map reload:",e),e}},L=async e=>{try{let t=$?`${$}/model/cost_map/source`:"/model/cost_map/source",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw Error(`HTTP ${r.status}: ${e}`)}let n=await r.json();return console.log("Model cost map source info:",n),n}catch(e){throw console.error("Failed to get model cost map source info:",e),e}},H=async e=>{try{let t=$?`${$}/schedule/model_cost_map_reload/status`:"/schedule/model_cost_map_reload/status";console.log("Fetching status from URL:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){console.error(`Status request failed with status: ${r.status}`);let e=await r.text();throw console.error("Error response:",e),Error(`HTTP ${r.status}: ${e}`)}let n=await r.json();return console.log("Model cost map reload status:",n),n}catch(e){throw console.error("Failed to get model cost map reload status:",e),e}},D=async(e,r)=>{try{let n=$?`${$}/model/new`:"/model/new",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),t.message.destroy(),g.default.success(`Model ${r.model_name} created successfully`),a}catch(e){throw console.error("Failed to create key:",e),e}},V=async(e,t)=>{console.log(`model_id in model delete call: ${t}`);try{let r=$?`${$}/model/delete`:"/model/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({id:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},W=async(e,t)=>{if(console.log(`budget_id in budget delete call: ${t}`),null!=e)try{let r=$?`${$}/budget/delete`:"/budget/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({id:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},G=async(e,t)=>{try{console.log("Form Values in budgetCreateCall:",t),console.log("Form Values after check:",t);let r=$?`${$}/budget/new`:"/budget/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},U=async(e,t)=>{try{console.log("Form Values in budgetUpdateCall:",t),console.log("Form Values after check:",t);let r=$?`${$}/budget/update`:"/budget/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},q=async(e,t)=>{try{let r=$?`${$}/invitation/new`:"/invitation/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_id:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},J=async e=>{try{let t=$?`${$}/alerting/settings`:"/alerting/settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},K=async(e,t)=>{try{for(let e of(console.log("Form Values in keyCreateServiceAccountCall:",t),t.description&&(t.metadata||(t.metadata={}),t.metadata.description=t.description,delete t.description,t.metadata=JSON.stringify(t.metadata)),p))if(t[e]){console.log(`formValues.${e}:`,t[e]);try{t[e]=JSON.parse(t[e])}catch(t){throw Error(`Failed to parse ${e}: `+t)}}console.log("Form Values after check:",t);let r=$?`${$}/key/service-account/generate`:"/key/service-account/generate",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},X=async(e,t,r)=>{try{for(let e of(console.log("Form Values in keyCreateCall:",r),r.description&&(r.metadata||(r.metadata={}),r.metadata.description=r.description,delete r.description,r.metadata=JSON.stringify(r.metadata)),p))if(r[e]){console.log(`formValues.${e}:`,r[e]);try{r[e]=JSON.parse(r[e])}catch(t){throw Error(`Failed to parse ${e}: `+t)}}console.log("Form Values after check:",r);let n=$?`${$}/key/generate`:"/key/generate",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...r})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},Y=async(e,t,r,n,o,a)=>{let i=$?`${$}/key/generate`:"/key/generate",l={agent_id:t,key_alias:r,models:n.length>0?n:[]};a&&(l.team_id=a),o&&Object.keys(o).length>0&&(l.metadata=o);let s=await fetch(i,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(l)});if(!s.ok)throw j(await s.text()),Error("Failed to create key for agent");return s.json()},Z=async(e,t,r)=>{try{if(console.log("Form Values in keyCreateCall:",r),r.description&&(r.metadata||(r.metadata={}),r.metadata.description=r.description,delete r.description,r.metadata=JSON.stringify(r.metadata)),r.auto_create_key=!1,r.metadata){console.log("formValues.metadata:",r.metadata);try{r.metadata=JSON.parse(r.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}console.log("Form Values after check:",r);let n=$?`${$}/user/new`:"/user/new",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...r})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},Q=async(e,t)=>{try{let r=$?`${$}/key/delete`:"/key/delete";console.log("in keyDeleteCall:",t);let n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({keys:[t]})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to create key:",e),e}},ee=async(e,t)=>{try{let r=$?`${$}/user/delete`:"/user/delete";console.log("in userDeleteCall:",t);let n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_ids:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to delete user(s):",e),e}},et=async(e,t)=>{try{let r=$?`${$}/team/delete`:"/team/delete";console.log("in teamDeleteCall:",t);let n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({team_ids:[t]})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to delete key:",e),e}},er=async(e,t=null,r=null,n=null,o=null,a=null,i=null,l=null,s=null,c=null,u=null)=>{try{let d=$?`${$}/user/list`:"/user/list";console.log("in userListCall");let f=new URLSearchParams;if(t&&t.length>0){let e=t.join(",");f.append("user_ids",e)}r&&f.append("page",r.toString()),n&&f.append("page_size",n.toString()),o&&f.append("user_email",o),a&&f.append("role",a),i&&f.append("team",i),l&&f.append("sso_user_ids",l),s&&f.append("sort_by",s),c&&f.append("sort_order",c),u&&u.length>0&&f.append("organization_ids",u.join(","));let p=f.toString();p&&(d+=`?${p}`);let m=await fetch(d,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!m.ok){let e=await m.json(),t=nx(e);throw j(t),Error(t)}let h=await m.json();return console.log("/user/list API Response:",h),h}catch(e){throw console.error("Failed to create key:",e),e}},en=async(e,t,r,n=!1,o,a,i=!1)=>{console.log(`userInfoCall: ${t}, ${r}, ${n}, ${o}, ${a}, ${i}`);try{let l;if(n){l=$?`${$}/user/list`:"/user/list";let e=new URLSearchParams;null!=o&&e.append("page",o.toString()),null!=a&&e.append("page_size",a.toString()),l+=`?${e.toString()}`}else l=$?`${$}/user/info`:"/user/info",("Admin"!==r&&"Admin Viewer"!==r||i)&&t&&(l+=`?user_id=${t}`);console.log("Requesting user data from:",l);let s=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nx(e);throw j(t),Error(t)}let c=await s.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to fetch user data:",e),e}},eo=async(e,t)=>{try{let r=$?`${$}/team/info`:"/team/info";t&&(r=`${r}?team_id=${t}`),console.log("in teamInfoCall");let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ea=async(e,t,r=null,n=null,o=null,a=1,i=10,l=null,s=null)=>{try{let a=$?`${$}/v2/team/list`:"/v2/team/list";console.log("in teamInfoCall");let i=new URLSearchParams;r&&i.append("user_id",r.toString()),t&&i.append("organization_id",t.toString()),n&&i.append("team_id",n.toString()),o&&i.append("team_alias",o.toString());let l=i.toString();l&&(a+=`?${l}`);let s=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nx(e);throw j(t),Error(t)}let c=await s.json();return console.log("/v2/team/list API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},ei=async(e,t,r=null,n=null,o=null)=>{try{let a=$?`${$}/team/list`:"/team/list";console.log("in teamInfoCall");let i=new URLSearchParams;r&&i.append("user_id",r.toString()),t&&i.append("organization_id",t.toString()),n&&i.append("team_id",n.toString()),o&&i.append("team_alias",o.toString());let l=i.toString();l&&(a+=`?${l}`);let s=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nx(e);throw j(t),Error(t)}let c=await s.json();return console.log("/team/list API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},el=async e=>{try{let t=$?`${$}/team/available`:"/team/available";console.log("in availableTeamListCall");let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("/team/available_teams API Response:",n),n}catch(e){throw e}},es=async(e,t=null,r=null)=>{try{let n=$?`${$}/organization/list`:"/organization/list",o=new URLSearchParams;t&&o.append("org_id",t.toString()),r&&o.append("org_alias",r.toString());let a=o.toString();a&&(n+=`?${a}`);let i=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nx(e);throw j(t),Error(t)}return await i.json()}catch(e){throw console.error("Failed to create key:",e),e}},ec=async(e,t)=>{try{let r=$?`${$}/organization/info`:"/organization/info";t&&(r=`${r}?organization_id=${t}`),console.log("in teamInfoCall");let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},eu=async(e,t)=>{try{if(console.log("Form Values in organizationCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw console.error("Failed to parse metadata:",e),Error("Failed to parse metadata: "+e)}}let r=$?`${$}/organization/new`:"/organization/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ed=async(e,t)=>{try{console.log("Form Values in organizationUpdateCall:",t);let r=$?`${$}/organization/update`:"/organization/update",n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Update Team Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ef=async(e,t)=>{try{let r=$?`${$}/organization/delete`:"/organization/delete",n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_ids:[t]})});if(!n.ok){let e=await n.text();throw j(e),Error(`Error deleting organization: ${e}`)}return await n.json()}catch(e){throw console.error("Failed to delete organization:",e),e}},ep=async(e,t)=>{try{let r=$?`${$}/utils/transform_request`:"/utils/transform_request",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create key:",e),e}},em=async({accessToken:e,endpoint:t,startTime:r,endTime:n,page:o=1,extraQueryParams:a})=>{try{let i,l,s,c,u=(i=t.startsWith("/")?t:`/${t}`,l=$?`${$}${i}`:i,(s=new URLSearchParams).append("start_date",v(r)),s.append("end_date",v(n)),s.append("page_size","1000"),s.append("page",o.toString()),s.append("timezone",new Date().getTimezoneOffset().toString()),a&&Object.entries(a).forEach(([e,t])=>{((e,t,r)=>{if(null!=r){if(Array.isArray(r)){r.length>0&&e.append(t,r.join(","));return}e.append(t,`${r}`)}})(s,e,t)}),(c=s.toString())?`${l}?${c}`:l),d=await fetch(u,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!d.ok){let e=await d.json(),t=nx(e);throw j(t),Error(t)}return await d.json()}catch(e){throw console.error(`Failed to fetch daily activity (${t}):`,e),e}},eh=async(e,t,r,n=1,o=null)=>em({accessToken:e,endpoint:"/user/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{user_id:o}}),eg=async(e,t,r,n=1,o=null)=>em({accessToken:e,endpoint:"/tag/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{tags:o}}),ev=async(e,t,r,n=1,o=null)=>em({accessToken:e,endpoint:"/team/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{team_ids:o,exclude_team_ids:"litellm-dashboard"}}),ey=async(e,t,r,n=1,o=null)=>em({accessToken:e,endpoint:"/organization/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{organization_ids:o}}),eb=async(e,t,r,n=1,o=null)=>em({accessToken:e,endpoint:"/customer/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{end_user_ids:o}}),ew=async(e,t,r,n=1,o=null)=>em({accessToken:e,endpoint:"/agent/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{agent_ids:o}}),e$=async e=>{try{let t=$?`${$}/onboarding/get_token`:"/onboarding/get_token";t+=`?invite_link=${e}`;let r=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to create key:",e),e}},eC=async(e,t,r,n)=>{let o=$?`${$}/onboarding/claim_token`:"/onboarding/claim_token";try{let a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({invitation_link:t,user_id:r,password:n})});if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to delete key:",e),e}},eE=async(e,t,r)=>{try{let n=$?`${$}/key/${t}/regenerate`:`/key/${t}/regenerate`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("Regenerate key Response:",a),a}catch(e){throw console.error("Failed to regenerate key:",e),e}},eS=!1,ex=null,ej=async(e,t,r,n=1,o=50,a,i,l,s,c)=>{try{console.log("modelInfoCall:",e,t,r,n,o,a,i,l,s,c);let u=$?`${$}/v2/model/info`:"/v2/model/info",d=new URLSearchParams;d.append("include_team_models","true"),d.append("page",n.toString()),d.append("size",o.toString()),a&&a.trim()&&d.append("search",a.trim()),i&&i.trim()&&d.append("modelId",i.trim()),l&&l.trim()&&d.append("teamId",l.trim()),s&&s.trim()&&d.append("sortBy",s.trim()),c&&c.trim()&&d.append("sortOrder",c.trim()),d.toString()&&(u+=`?${d.toString()}`);let f=await fetch(u,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!f.ok){let e=await f.text();throw e+=`error shown=${eS}`,eS||(e.includes("No model list passed")&&(e="No Models Exist. Click Add Model to get started."),g.default.info(e),eS=!0,ex&&clearTimeout(ex),ex=setTimeout(()=>{eS=!1},1e4)),Error("Network response was not ok")}let p=await f.json();return console.log("modelInfoCall:",p),p}catch(e){throw console.error("Failed to create key:",e),e}},eO=async(e,t)=>{try{let r=$?`${$}/v1/model/info`:"/v1/model/info";r+=`?litellm_model_id=${t}`;let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("modelInfoV1Call:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ek=async()=>{let e=$?`${$}/public/model_hub`:"/public/model_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`modelHubPublicModelsCall failed with status ${t.status}`),[])},eT=async()=>{let e=$?`${$}/public/agent_hub`:"/public/agent_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`agentHubPublicModelsCall failed with status ${t.status}`),[])},eF=async()=>{let e=$?`${$}/public/mcp_hub`:"/public/mcp_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`mcpHubPublicServersCall failed with status ${t.status}`),[])},e_=async e=>{try{let t=$?`${$}/model_group/info`:"/model_group/info",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("modelHubCall:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},eI=async e=>{try{let t=$?`${$}/get/allowed_ips`:"/get/allowed_ips",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("getAllowedIPs:",n),n.data}catch(e){throw console.error("Failed to get allowed IPs:",e),e}},eP=async(e,t)=>{try{let r=$?`${$}/add/allowed_ip`:"/add/allowed_ip",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({ip:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("addAllowedIP:",o),o}catch(e){throw console.error("Failed to add allowed IP:",e),e}},eN=async(e,t)=>{try{let r=$?`${$}/delete/allowed_ip`:"/delete/allowed_ip",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({ip:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("deleteAllowedIP:",o),o}catch(e){throw console.error("Failed to delete allowed IP:",e),e}},eR=async(e,t)=>{try{let r=$?`${$}/model_hub/update_useful_links`:"/model_hub/update_useful_links",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({useful_links:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create key:",e),e}},eM=async(e,t,r,n=!1,o=null,a=!1,i=!1,l)=>{console.log("in /models calls, globalLitellmHeaderName",T);try{let t=$?`${$}/models`:"/models",r=new URLSearchParams;r.append("include_model_access_groups","True"),!0===n&&r.append("return_wildcard_routes","True"),!0===i&&r.append("only_model_access_groups","True"),o&&r.append("team_id",o.toString()),l&&r.append("scope",l),r.toString()&&(t+=`?${r.toString()}`);let a=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}return await a.json()}catch(e){throw console.error("Failed to create key:",e),e}},eB=async e=>{try{let t=$?`${$}/global/spend/teams`:"/global/spend/teams";console.log("in teamSpendLogsCall:",t);let r=await fetch(`${t}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eA=async(e,t,r,n)=>{try{let o=$?`${$}/global/spend/tags`:"/global/spend/tags";t&&r&&(o=`${o}?start_date=${t}&end_date=${r}`),n&&(o+=`&tags=${n.join(",")}`),console.log("in tagsSpendLogsCall:",o);let a=await fetch(`${o}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to create key:",e),e}},ez=async e=>{try{let t=$?`${$}/global/spend/all_tag_names`:"/global/spend/all_tag_names";console.log("in global/spend/all_tag_names call",t);let r=await fetch(`${t}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eL=async e=>{try{let t=$?`${$}/customer/list`:"/customer/list";console.log("in customer/list",t);let r=await fetch(`${t}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to fetch end users:",e),e}},eH=async(e,t)=>{try{let r=$?`${$}/user/filter/ui`:"/user/filter/ui",n=new URLSearchParams;t.get("user_email")&&n.append("user_email",t.get("user_email")),t.get("user_id")&&n.append("user_id",t.get("user_id")),t.get("team_id")&&n.append("team_id",t.get("team_id"));let o=n.toString(),a=o?`${r}?${o}`:r,i=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nx(e);throw j(t),Error(t)}return await i.json()}catch(e){throw console.error("Failed to create key:",e),e}},eD=async({accessToken:e,start_date:t,end_date:r,page:n=1,page_size:o=50,params:a={}})=>{try{let i=$?`${$}/spend/logs/ui`:"/spend/logs/ui",l=new URLSearchParams;for(let[e,i]of(l.append("start_date",t),l.append("end_date",r),l.append("page",n.toString()),l.append("page_size",o.toString()),Object.entries(a)))null!=i&&("min_spend"===e||"max_spend"===e?l.append(e,i.toString()):"string"==typeof i&&""!==i&&l.append(e,String(i)));let s=l.toString();s&&(i+=`?${s}`);let c=await fetch(i,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!c.ok){let e=await c.json(),t=nx(e);throw j(t),Error(t)}let u=await c.json();return console.log("Spend Logs Response:",u),u}catch(e){throw console.error("Failed to fetch spend logs:",e),e}},eV=async e=>{try{let t=$?`${$}/global/spend/logs`:"/global/spend/logs",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eW=async e=>{try{let t=$?`${$}/global/spend/keys?limit=5`:"/global/spend/keys?limit=5",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eG=async(e,t,r,n)=>{try{let o=$?`${$}/global/spend/end_users`:"/global/spend/end_users",a="";a=t?JSON.stringify({api_key:t,startTime:r,endTime:n}):JSON.stringify({startTime:r,endTime:n});let i={method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:a},l=await fetch(o,i);if(!l.ok){let e=await l.json(),t=nx(e);throw j(t),Error(t)}let s=await l.json();return console.log(s),s}catch(e){throw console.error("Failed to create key:",e),e}},eU=async(e,t,r,n)=>{try{let o=$?`${$}/global/spend/provider`:"/global/spend/provider";r&&n&&(o+=`?start_date=${r}&end_date=${n}`),t&&(o+=`&api_key=${t}`);let a={method:"GET",headers:{[T]:`Bearer ${e}`}},i=await fetch(o,a);if(!i.ok){let e=await i.json(),t=nx(e);throw j(t),Error(t)}let l=await i.json();return console.log(l),l}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eq=async(e,t,r)=>{try{let n=$?`${$}/global/activity`:"/global/activity";t&&r&&(n+=`?start_date=${t}&end_date=${r}`);let o={method:"GET",headers:{[T]:`Bearer ${e}`}},a=await fetch(n,o);if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eJ=async(e,t,r)=>{try{let n=$?`${$}/global/activity/cache_hits`:"/global/activity/cache_hits";t&&r&&(n+=`?start_date=${t}&end_date=${r}`);let o={method:"GET",headers:{[T]:`Bearer ${e}`}},a=await fetch(n,o);if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eK=async(e,t,r)=>{try{let n=$?`${$}/global/activity/model`:"/global/activity/model";t&&r&&(n+=`?start_date=${t}&end_date=${r}`);let o={method:"GET",headers:{[T]:`Bearer ${e}`}},a=await fetch(n,o);if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eX=async e=>{try{let t=$?`${$}/global/spend/models?limit=5`:"/global/spend/models?limit=5",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eY=async(e,t)=>{try{let r=$?`${$}/v2/key/info`:"/v2/key/info",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({keys:t})});if(!n.ok){let e=await n.text();if(e.includes("Invalid proxy server token passed"))throw Error("Invalid proxy server token passed");throw j(e),Error("Network response was not ok")}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to create key:",e),e}},eZ=async(e,t,r,n)=>{try{console.log("Sending model connection test request:",JSON.stringify(t));let o=$?`${$}/health/test_connection`:"/health/test_connection",a=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({litellm_params:t,model_info:r,mode:n})}),i=a.headers.get("content-type");if(!i||!i.includes("application/json")){let e=await a.text();throw console.error("Received non-JSON response:",e),Error(`Received non-JSON response (${a.status}: ${a.statusText}). Check network tab for details.`)}let l=await a.json();if((!a.ok||"error"===l.status)&&"error"!==l.status)return{status:"error",message:l.error?.message||`Connection test failed: ${a.status} ${a.statusText}`};return l}catch(e){throw console.error("Model connection test error:",e),e}},eQ=async(e,t)=>{try{console.log("entering keyInfoV1Call");let r=$?`${$}/key/info`:"/key/info";r=`${r}?key=${t}`;let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(console.log("response",n),!n.ok){let e=await n.text();j(e),g.default.fromBackend("Failed to fetch key info - "+e)}let o=await n.json();return console.log("data",o),o}catch(e){throw console.error("Failed to fetch key info:",e),e}},e0=async(e,t,r,n,o,a,i,l,s=null,c=null,u=null,d=null)=>{try{let f=$?`${$}/key/list`:"/key/list";console.log("in keyListCall");let p=new URLSearchParams;r&&p.append("team_id",r.toString()),t&&p.append("organization_id",t.toString()),n&&p.append("key_alias",n),a&&p.append("key_hash",a),o&&p.append("user_id",o.toString()),i&&p.append("page",i.toString()),l&&p.append("size",l.toString()),s&&p.append("sort_by",s),c&&p.append("sort_order",c),u&&p.append("expand",u),d&&p.append("status",d),p.append("return_full_object","true"),p.append("include_team_keys","true"),p.append("include_created_by_keys","true");let m=p.toString();m&&(f+=`?${m}`);let h=await fetch(f,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!h.ok){let e=await h.json(),t=nx(e);throw j(t),Error(t)}let g=await h.json();return console.log("/team/list API Response:",g),g}catch(e){throw console.error("Failed to create key:",e),e}},e1=async(e,t=1,r=50,n)=>{try{let o=new URLSearchParams(Object.entries({page:String(t),size:String(r),...n?{search:n}:{}})),a=$?`${$}/key/aliases`:"/key/aliases";a=`${a}?${o}`;let i=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nx(e);throw j(t),Error(t)}let l=await i.json();return console.log("/key/aliases API Response:",l),l}catch(e){throw console.error("Failed to fetch key aliases:",e),e}},e2=async(e,t,r,n=null)=>{try{let o=$?`${$}/user/daily/activity/aggregated`:"/user/daily/activity/aggregated",a=new URLSearchParams,i=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${n}`};a.append("start_date",i(t)),a.append("end_date",i(r)),a.append("timezone",new Date().getTimezoneOffset().toString()),n&&a.append("user_id",n);let l=a.toString();l&&(o+=`?${l}`);let s=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nx(e);throw j(t),Error(t)}return await s.json()}catch(e){throw console.error("Failed to fetch aggregated user daily activity:",e),e}},e4=async e=>{try{let t=$?`${$}/user/available_roles`:"/user/available_roles",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("response from user/available_role",n),n}catch(e){throw e}},e6=async(e,t)=>{try{if(console.log("Form Values in teamCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let r=$?`${$}/team/new`:"/team/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},e3=async(e,t)=>{try{if(console.log("Form Values in credentialCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let r=$?`${$}/credentials`:"/credentials",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},e7=async e=>{try{let t=$?`${$}/credentials`:"/credentials";console.log("in credentialListCall");let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("/credentials API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},e5=async(e,t,r)=>{try{let n=$?`${$}/credentials`:"/credentials";t?n+=`/by_name/${t}`:r&&(n+=`/by_model/${r}`),console.log("in credentialListCall");let o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("/credentials API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},e9=async(e,t)=>{try{let r=$?`${$}/credentials/${t}`:`/credentials/${t}`;console.log("in credentialDeleteCall:",t);let n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to delete key:",e),e}},e8=async(e,t,r)=>{try{if(console.log("Form Values in credentialUpdateCall:",r),r.metadata){console.log("formValues.metadata:",r.metadata);try{r.metadata=JSON.parse(r.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let n=$?`${$}/credentials/${t}`:`/credentials/${t}`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},te=async(e,t)=>{try{if(console.log("Form Values in keyUpdateCall:",t),t.model_tpm_limit){console.log("formValues.model_tpm_limit:",t.model_tpm_limit);try{t.model_tpm_limit=JSON.parse(t.model_tpm_limit)}catch(e){throw Error("Failed to parse model_tpm_limit: "+e)}}if(t.model_rpm_limit){console.log("formValues.model_rpm_limit:",t.model_rpm_limit);try{t.model_rpm_limit=JSON.parse(t.model_rpm_limit)}catch(e){throw Error("Failed to parse model_rpm_limit: "+e)}}let r=$?`${$}/key/update`:"/key/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let o=await n.json();return console.log("Update key Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},tt=async(e,t)=>{try{console.log("Form Values in teamUpateCall:",t);let r=$?`${$}/team/update`:"/team/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),console.error("Error response from the server:",e),g.default.fromBackend("Failed to update team settings: "+e),Error(e)}let o=await n.json();return console.log("Update Team Response:",o),o}catch(e){throw console.error("Failed to update team:",e),e}},tr=async(e,t,r)=>{try{console.log("Form Values in modelUpateCall:",t);let n=$?`${$}/model/${r}/update`:`/model/${r}/update`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error update from the server:",e),Error("Network response was not ok")}let a=await o.json();return console.log("Update model Response:",a),a}catch(e){throw console.error("Failed to update model:",e),e}},tn=async(e,t,r)=>{try{console.log("Form Values in teamMemberAddCall:",r);let n=$?`${$}/team/member_add`:"/team/member_add",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({team_id:t,member:r})});if(!o.ok){let e=await o.text(),t={};try{t=JSON.parse(e)}catch(t){console.warn("Failed to parse error body as JSON:",e)}let r=t?.detail?.error||"Failed to add team member",n=Error(r);throw n.raw=t,n}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},to=async(e,t,r,n,o)=>{try{console.log("Bulk add team members:",{teamId:t,members:r,maxBudgetInTeam:n});let a=$?`${$}/team/bulk_member_add`:"/team/bulk_member_add",i={team_id:t};o?i.all_users=!0:i.members=r,null!=n&&(i.max_budget_in_team=n);let l=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!l.ok){let e=await l.text(),t={};try{t=JSON.parse(e)}catch(t){console.warn("Failed to parse error body as JSON:",e)}let r=t?.detail?.error||"Failed to bulk add team members",n=Error(r);throw n.raw=t,n}let s=await l.json();return console.log("Bulk team member add API Response:",s),s}catch(e){throw console.error("Failed to bulk add team members:",e),e}},ta=async(e,t,r)=>{try{console.log("Form Values in teamMemberUpdateCall:",r),console.log("Budget value:",r.max_budget_in_team),console.log("TPM limit:",r.tpm_limit),console.log("RPM limit:",r.rpm_limit);let n=$?`${$}/team/member_update`:"/team/member_update",o={team_id:t,role:r.role,user_id:r.user_id};void 0!==r.user_email&&(o.user_email=r.user_email),void 0!==r.max_budget_in_team&&null!==r.max_budget_in_team&&(o.max_budget_in_team=r.max_budget_in_team),void 0!==r.tpm_limit&&null!==r.tpm_limit&&(o.tpm_limit=r.tpm_limit),void 0!==r.rpm_limit&&null!==r.rpm_limit&&(o.rpm_limit=r.rpm_limit),console.log("Final request body:",o);let a=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(o)});if(!a.ok){let e=await a.text(),t={};try{t=JSON.parse(e)}catch(t){console.warn("Failed to parse error body as JSON:",e)}let r=t?.detail?.error||"Failed to add team member",n=Error(r);throw n.raw=t,n}let i=await a.json();return console.log("API Response:",i),i}catch(e){throw console.error("Failed to update team member:",e),e}},ti=async(e,t,r)=>{try{console.log("Form Values in teamMemberAddCall:",r);let n=$?`${$}/team/member_delete`:"/team/member_delete",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({team_id:t,...void 0!==r.user_email&&{user_email:r.user_email},...void 0!==r.user_id&&{user_id:r.user_id}})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},tl=async(e,t,r)=>{try{console.log("Form Values in teamMemberAddCall:",r);let n=$?`${$}/organization/member_add`:"/organization/member_add",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,member:r})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create organization member:",e),e}},ts=async(e,t,r)=>{try{console.log("Form Values in organizationMemberDeleteCall:",r);let n=$?`${$}/organization/member_delete`:"/organization/member_delete",o=await fetch(n,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,user_id:r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to delete organization member:",e),e}},tc=async(e,t,r)=>{try{console.log("Form Values in organizationMemberUpdateCall:",r);let n=$?`${$}/organization/member_update`:"/organization/member_update",o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,...r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to update organization member:",e),e}},tu=async(e,t,r)=>{try{console.log("Form Values in userUpdateUserCall:",t);let n=$?`${$}/user/update`:"/user/update",o={...t};null!==r&&(o.user_role=r),o=JSON.stringify(o);let a=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:o});if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}let i=await a.json();return console.log("API Response:",i),i}catch(e){throw console.error("Failed to create key:",e),e}},td=async(e,t,r,n=!1)=>{try{let o;console.log("Form Values in userUpdateUserCall:",t);let a=$?`${$}/user/bulk_update`:"/user/bulk_update";if(n)o=JSON.stringify({all_users:!0,user_updates:t});else if(r&&r.length>0){let e=[];for(let n of r)e.push({user_id:n,...t});o=JSON.stringify({users:e})}else throw Error("Must provide either userIds or set allUsers=true");let i=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:o});if(!i.ok){let e=await i.json(),t=nx(e);throw j(t),Error(t)}let l=await i.json();return console.log("API Response:",l),l}catch(e){throw console.error("Failed to create key:",e),e}},tf=async(e,t)=>{try{let r=$?`${$}/health/services?service=${t}`:`/health/services?service=${t}`;console.log("Checking Slack Budget Alerts service health");let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error(e)}return await n.json()}catch(e){throw console.error("Failed to perform health check:",e),e}},tp=async e=>{try{let t=$?`${$}/budget/list`:"/budget/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tm=async(e,t,r)=>{try{let t=$?`${$}/get/config/callbacks`:"/get/config/callbacks",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},th=async e=>{try{let t=$?`${$}/config/list?config_type=general_settings`:"/config/list?config_type=general_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tg=async e=>{try{let t=$?`${$}/router/settings`:"/router/settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get router settings:",e),e}},tv=async e=>{try{let t=$?`${$}/cache/settings`:"/cache/settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get cache settings:",e),e}},ty=async(e,t)=>{try{let r=$?`${$}/cache/settings/test`:"/cache/settings/test",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({cache_settings:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to test cache connection:",e),e}},tb=async(e,t)=>{try{let r=$?`${$}/cache/settings`:"/cache/settings",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({cache_settings:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to update cache settings:",e),e}},tw=async(e,t)=>{try{let r=$?`${$}/config/pass_through_endpoint`:"/config/pass_through_endpoint";t&&(r+=`/team/${t}`);let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},t$=async(e,t)=>{try{let r=$?`${$}/config/field/info?field_name=${t}`:`/config/field/info?field_name=${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},tC=async(e,t)=>{try{let r=$?`${$}/config/pass_through_endpoint`:"/config/pass_through_endpoint",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},tE=async(e,t,r)=>{try{let n=$?`${$}/config/field/update`:"/config/field/update",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({field_name:t,field_value:r,config_type:"general_settings"})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return g.default.success("Successfully updated value!"),a}catch(e){throw console.error("Failed to set callbacks:",e),e}},tS=async(e,t)=>{try{let r=$?`${$}/config/field/delete`:"/config/field/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({field_name:t,config_type:"general_settings"})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return g.default.success("Field reset on proxy"),o}catch(e){throw console.error("Failed to get callbacks:",e),e}},tx=async(e,t)=>{try{let r=$?`${$}/config/pass_through_endpoint?endpoint_id=${t}`:`/config/pass_through_endpoint?endpoint_id=${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tj=async(e,t)=>{try{let r=$?`${$}/config/update`:"/config/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},tO=async(e,t)=>{try{let r=$?`${$}/health?model_id=${encodeURIComponent(t)}`:`/health?model_id=${encodeURIComponent(t)}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error(`Failed to call /health for model id ${t}:`,e),e}},tk=async e=>{try{let t=$?`${$}/cache/ping`:"/cache/ping",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error(e)}return await r.json()}catch(e){throw console.error("Failed to call /cache/ping:",e),e}},tT=async e=>{try{let t=$?`${$}/health/latest`:"/health/latest",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error(e)}return await r.json()}catch(e){throw console.error("Failed to call /health/latest:",e),e}},tF=async e=>{try{console.log("Getting proxy UI settings"),console.log("proxyBaseUrl in getProxyUISettings:",$);let t=$?`${$}/sso/get/ui_settings`:"/sso/get/ui_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},t_=async e=>{try{let t=$?`${$}/get/ui_settings`:"/get/ui_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);return console.error("Failed to get UI settings:",t),null}return await r.json()}catch(e){return console.error("Failed to get UI settings:",e),null}},tI=async e=>{try{let t=$?`${$}/get/mcp_semantic_filter_settings`:"/get/mcp_semantic_filter_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get MCP semantic filter settings:",e),e}},tP=async(e,t)=>{try{let r=$?`${$}/update/mcp_semantic_filter_settings`:"/update/mcp_semantic_filter_settings",n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to update MCP semantic filter settings:",e),e}},tN=async(e,t,r)=>{try{let n=$?`${$}/v1/responses`:"/v1/responses",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({model:t,input:[{role:"user",content:r,type:"message"}],tools:[{type:"mcp",server_url:"litellm_proxy",require_approval:"never"}],tool_choice:"required"})}),a=o.headers.get("x-litellm-semantic-filter"),i=o.headers.get("x-litellm-semantic-filter-tools");if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return{data:await o.json(),headers:{filter:a,tools:i}}}catch(e){throw console.error("Failed to test MCP semantic filter:",e),e}},tR=async e=>{try{let t=$?`${$}/v2/guardrails/list`:"/v2/guardrails/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok)throw Error(`v2 guardrails/list returned ${r.status}`);return await r.json()}catch(t){console.log("v2/guardrails/list failed, falling back to v1:",t);try{let t=$?`${$}/guardrails/list`:"/guardrails/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get guardrails list:",e),e}}},tM=async(e,t)=>{let r=$?`${$}/guardrails/submissions`:"/guardrails/submissions",n=new URLSearchParams;t?.status&&n.set("status",t.status),t?.team_id&&n.set("team_id",t.team_id),t?.team_guardrail!==void 0&&n.set("team_guardrail",String(t.team_guardrail)),t?.search&&n.set("search",t.search);let o=n.toString()?`${r}?${n.toString()}`:r,a=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=nx(await a.json().catch(()=>({})));throw j(e),Error(e)}return a.json()},tB=async(e,t)=>{let r=$?`${$}/guardrails/submissions/${encodeURIComponent(t)}/approve`:`/guardrails/submissions/${encodeURIComponent(t)}/approve`,n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=nx(await n.json().catch(()=>({})));throw j(e),Error(e)}return n.json()},tA=async(e,t)=>{let r=$?`${$}/guardrails/submissions/${encodeURIComponent(t)}/reject`:`/guardrails/submissions/${encodeURIComponent(t)}/reject`,n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=nx(await n.json().catch(()=>({})));throw j(e),Error(e)}return n.json()},tz=async(e,t,r)=>{try{let n=$?`${$}/guardrails/usage/overview`:"/guardrails/usage/overview",o=new URLSearchParams;t&&o.append("start_date",t),r&&o.append("end_date",r),o.toString()&&(n+=`?${o.toString()}`);let a=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json();throw Error(nx(e))}return a.json()}catch(e){throw console.error("Failed to get guardrails usage overview:",e),e}},tL=async(e,t,r,n)=>{try{let o=$?`${$}/guardrails/usage/detail/${encodeURIComponent(t)}`:`/guardrails/usage/detail/${encodeURIComponent(t)}`,a=new URLSearchParams;r&&a.append("start_date",r),n&&a.append("end_date",n),a.toString()&&(o+=`?${a.toString()}`);let i=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json();throw Error(nx(e))}return i.json()}catch(e){throw console.error("Failed to get guardrails usage detail:",e),e}},tH=async(e,t)=>{try{let r=$?`${$}/guardrails/usage/logs`:"/guardrails/usage/logs",n=new URLSearchParams;t.guardrailId&&n.append("guardrail_id",t.guardrailId),t.policyId&&n.append("policy_id",t.policyId),null!=t.page&&n.append("page",String(t.page)),null!=t.pageSize&&n.append("page_size",String(t.pageSize)),t.action&&n.append("action",t.action),t.startDate&&n.append("start_date",t.startDate),t.endDate&&n.append("end_date",t.endDate),n.toString()&&(r+=`?${n.toString()}`);let o=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json();throw Error(nx(e))}return o.json()}catch(e){throw console.error("Failed to get guardrails usage logs:",e),e}},tD=async e=>{try{let t=$?`${$}/policies/list`:"/policies/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get policies list:",e),e}},tV=async(e,t,r)=>{try{let n=$?`${$}/utils/test_policies_and_guardrails`:"/utils/test_policies_and_guardrails",o=await fetch(n,{method:"POST",signal:r,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({policy_names:t.policy_names??null,guardrail_names:t.guardrail_names??null,inputs:t.inputs??null,inputs_list:t.inputs_list??null,request_data:t.request_data??{},input_type:t.input_type??"request",agent_id:t.agent_id??null})});if(!o.ok){let e=await o.text(),t="Failed to test policies and guardrails";try{let r=JSON.parse(e);r.detail?t="string"==typeof r.detail?r.detail:JSON.stringify(r.detail):r.message&&(t=r.message)}catch{t=e||t}throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to test policies and guardrails:",e),e}},tW=async(e,t)=>{try{let r=$?`${$}/policy/info/${t}`:`/policy/info/${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error(`Failed to get policy info for ${t}:`,e),e}},tG=async e=>{try{let t=$?`${$}/policy/templates`:"/policy/templates",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get policy templates:",e),e}},tU=async(e,t,r,n,o)=>{try{let a=$?`${$}/policy/templates/enrich`:"/policy/templates/enrich",i={template_id:t,parameters:r};n&&(i.model=n),o&&(i.competitors=o);let l=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!l.ok){let e=await l.json(),t=nx(e);throw j(t),Error(t)}return await l.json()}catch(e){throw console.error("Failed to enrich policy template:",e),e}},tq=async(e,t,r,n)=>{try{let o=$?`${$}/policy/templates/suggest`:"/policy/templates/suggest",a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({attack_examples:t.filter(e=>e.trim()),description:r,model:n})});if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}return a.json()}catch(e){throw console.error("Failed to suggest policy templates:",e),e}},tJ=async(e,t,r)=>{try{let n=$?`${$}/policy/templates/test`:"/policy/templates/test",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({guardrail_definitions:t,text:r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return o.json()}catch(e){throw console.error("Failed to test policy template:",e),e}},tK=async(e,t,r,n,o,a,i,l,s)=>{let c=$?`${$}/policy/templates/enrich/stream`:"/policy/templates/enrich/stream",u={template_id:t,parameters:r,model:n};l?.instruction&&(u.instruction=l.instruction),l?.existingCompetitors&&(u.competitors=l.existingCompetitors);let d=await fetch(c,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(u)});if(!d.ok){let e=nx(await d.json());throw j(e),Error(e)}let f=d.body?.getReader();if(!f)throw Error("No response body");let p=new TextDecoder,m="";for(;;){let{done:e,value:t}=await f.read();if(e)break;let r=(m+=p.decode(t,{stream:!0})).split("\n");for(let e of(m=r.pop()||"",r))if(e.startsWith("data: "))try{let t=JSON.parse(e.slice(6));"competitor"===t.type?o(t.name):"status"===t.type?s?.(t.message):"done"===t.type?a(t):"error"===t.type&&i?.(t.message)}catch{}}},tX=async(e,t,r,n,o,a,i,l,s)=>{let c=$?`${$}/usage/ai/chat`:"/usage/ai/chat",u=await fetch(c,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({messages:t,model:r}),signal:s});if(!u.ok){let e=nx(await u.json());throw j(e),Error(e)}let d=u.body?.getReader();if(!d)throw Error("No response body");let f=new TextDecoder,p="";for(;;){let{done:e,value:t}=await d.read();if(e)break;let r=(p+=f.decode(t,{stream:!0})).split("\n");for(let e of(p=r.pop()||"",r))if(e.startsWith("data: "))try{let t=JSON.parse(e.slice(6));"chunk"===t.type?n(t.content):"status"===t.type?i?.(t.message):"tool_call"===t.type?l?.(t):"done"===t.type?o():"error"===t.type&&a?.(t.message)}catch{}}},tY=async(e,t)=>{try{let r=$?`${$}/policies`:"/policies",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create policy:",e),e}},tZ=async(e,t,r)=>{try{let n=$?`${$}/policies/${t}`:`/policies/${t}`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update policy:",e),e}},tQ=async(e,t)=>{try{let r=encodeURIComponent(t),n=$?`${$}/policies/name/${r}/versions`:`/policies/name/${r}/versions`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to list policy versions:",e),e}},t0=async(e,t,r)=>{try{let n=encodeURIComponent(t),o=$?`${$}/policies/name/${n}/versions`:`/policies/name/${n}/versions`,a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({source_policy_id:r??void 0})});if(!a.ok){let e=await a.json(),t=nx(e);throw j(t),Error(t)}return await a.json()}catch(e){throw console.error("Failed to create policy version:",e),e}},t1=async(e,t,r)=>{try{let n=$?`${$}/policies/${t}/status`:`/policies/${t}/status`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({version_status:r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update policy version status:",e),e}},t2=async(e,t)=>{try{let r=$?`${$}/policies/${t}`:`/policies/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete policy:",e),e}},t4=async(e,t)=>{try{let r=$?`${$}/policies/${t}`:`/policies/${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get policy info:",e),e}},t6=async e=>{try{let t=$?`${$}/policies/attachments/list`:"/policies/attachments/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get policy attachments list:",e),e}},t3=async(e,t)=>{try{let r=$?`${$}/policies/attachments`:"/policies/attachments",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create policy attachment:",e),e}},t7=async(e,t)=>{try{let r=$?`${$}/policies/attachments/${t}`:`/policies/attachments/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete policy attachment:",e),e}},t5=async(e,t,r)=>{try{let n=$?`${$}/policies/test-pipeline`:"/policies/test-pipeline",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({pipeline:t,test_messages:r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to test pipeline:",e),e}},t9=async(e,t)=>{try{let r=$?`${$}/policies/${t}/resolved-guardrails`:`/policies/${t}/resolved-guardrails`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get resolved guardrails:",e),e}},t8=async(e,t)=>{try{let r=$?`${$}/policies/resolve`:"/policies/resolve",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to resolve policies:",e),e}},re=async(e,t)=>{try{let r=$?`${$}/policies/attachments/estimate-impact`:"/policies/attachments/estimate-impact",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to estimate attachment impact:",e),e}},rt=async e=>{try{let t=$?`${$}/prompts/list`:"/prompts/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get prompts list:",e),e}},rr=async(e,t)=>{try{let r=$?`${$}/prompts/${t}/info`:`/prompts/${t}/info`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get prompt info:",e),e}},rn=async(e,t)=>{try{let r=$?`${$}/prompts/${t}/versions`:`/prompts/${t}/versions`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw 404!==n.status&&j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get prompt versions:",e),e}},ro=async(e,t)=>{try{let r=$?`${$}/prompts`:"/prompts",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create prompt:",e),e}},ra=async(e,t,r)=>{try{let n=$?`${$}/prompts/${t}`:`/prompts/${t}`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update prompt:",e),e}},ri=async(e,t)=>{try{let r=$?`${$}/prompts/${t}`:`/prompts/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete prompt:",e),e}},rl=async(e,t)=>{try{let r=new FormData;r.append("file",t);let n=$?`${$}/utils/dotprompt_json_converter`:"/utils/dotprompt_json_converter",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`},body:r});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to convert prompt file:",e),e}},rs=async(e,t)=>{try{let r=$?`${$}/v1/agents`:"/v1/agents",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Create agent response:",o),o}catch(e){throw console.error("Failed to create agent:",e),e}},rc=async(e,t)=>{try{let r=$?`${$}/guardrails`:"/guardrails",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({guardrail:t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Create guardrail response:",o),o}catch(e){throw console.error("Failed to create guardrail:",e),e}},ru=async(e,t,r)=>{try{let n=$?`${$}/spend/logs/ui/${t}?start_date=${encodeURIComponent(r)}`:`/spend/logs/ui/${t}?start_date=${encodeURIComponent(r)}`;console.log("Fetching log details from:",n);let o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("Fetched log details:",a),a}catch(e){throw console.error("Failed to fetch log details:",e),e}},rd=async e=>{try{let t=$?`${$}/get/internal_user_settings`:"/get/internal_user_settings";console.log("Fetching SSO settings from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched SSO settings:",n),n}catch(e){throw console.error("Failed to fetch SSO settings:",e),e}},rf=async(e,t)=>{try{let r=$?`${$}/update/internal_user_settings`:"/update/internal_user_settings";console.log("Updating internal user settings:",t);let n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Updated internal user settings:",o),g.default.success("Internal user settings updated successfully"),o}catch(e){throw console.error("Failed to update internal user settings:",e),e}},rp=async e=>{try{let t=$?`${$}/v1/mcp/openapi-registry`:"/v1/mcp/openapi-registry",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json();throw Error(nx(e))}return await r.json()}catch(e){throw console.error("Failed to fetch OpenAPI registry:",e),e}},rm=async e=>{try{let t=$?`${$}/v1/mcp/discover`:"/v1/mcp/discover",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to fetch discoverable MCP servers:",e),e}},rh=async(e,t)=>{try{let r=$?`${$}/v1/mcp/server`:"/v1/mcp/server";if(t){let e=new URLSearchParams;e.append("team_id",t),r=`${r}?${e.toString()}`}console.log("Fetching MCP servers from:",r);let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Fetched MCP servers:",o),o}catch(e){throw console.error("Failed to fetch MCP servers:",e),e}},rg=async(e,t)=>{try{let r=$?`${$}/v1/mcp/server/health`:"/v1/mcp/server/health";if(t&&t.length>0){let e=new URLSearchParams;t.forEach(t=>e.append("server_ids",t)),r=`${r}?${e.toString()}`}console.log("Fetching MCP server health from:",r);let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Fetched MCP server health:",o),o}catch(e){throw console.error("Failed to fetch MCP server health:",e),e}},rv=async e=>{try{let t=$?`${$}/v1/mcp/access_groups`:"/v1/mcp/access_groups";console.log("Fetching MCP access groups from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched MCP access groups:",n),n.access_groups||[]}catch(e){throw console.error("Failed to fetch MCP access groups:",e),e}},ry=async e=>{try{let t=$?`${$}/v1/mcp/network/client-ip`:"/v1/mcp/network/client-ip",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok)return null;return(await r.json()).ip||null}catch{return null}},rb=async(e,t)=>{try{console.log("Form Values in createMCPServer:",t);let r=$?`${$}/v1/mcp/server`:"/v1/mcp/server",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},rw=async(e,t)=>{try{let r=$?`${$}/v1/mcp/server`:"/v1/mcp/server",n=await fetch(r,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to update MCP server:",e),e}},r$=async(e,t)=>{try{let r=($?`${$}`:"")+`/v1/mcp/server/${t}`;console.log("in deleteMCPServer:",t);let n=await fetch(r,{method:S,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}}catch(e){throw console.error("Failed to delete key:",e),e}},rC=async(e,t)=>{try{let r=($?`${$}`:"")+"/v1/mcp/server/register",n=await fetch(r,{method:E,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return n.json()}catch(e){throw console.error("Failed to register MCP server:",e),e}},rE=async e=>{try{let t=($?`${$}`:"")+"/v1/mcp/server/submissions",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json().catch(()=>({})),t=nx(e);throw j(t),Error(t)}return r.json()}catch(e){throw console.error("Failed to fetch MCP submissions:",e),e}},rS=async(e,t)=>{try{let r=($?`${$}`:"")+`/v1/mcp/server/${encodeURIComponent(t)}/approve`,n=await fetch(r,{method:"PUT",headers:{[T]:`Bearer ${e}`}});if(!n.ok){let e=await n.json().catch(()=>({})),t=nx(e);throw j(t),Error(t)}return n.json()}catch(e){throw console.error("Failed to approve MCP server:",e),e}},rx=async(e,t,r)=>{try{let n=($?`${$}`:"")+`/v1/mcp/server/${encodeURIComponent(t)}/reject`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({review_notes:r??null})});if(!o.ok){let e=await o.json().catch(()=>({})),t=nx(e);throw j(t),Error(t)}return o.json()}catch(e){throw console.error("Failed to reject MCP server:",e),e}},rj=async e=>{try{let t=$?`${$}/search_tools/list`:"/search_tools/list";console.log("Fetching search tools from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched search tools:",n),n}catch(e){throw console.error("Failed to fetch search tools:",e),e}},rO=async(e,t)=>{try{console.log("Creating search tool with values:",t);let r=$?`${$}/search_tools`:"/search_tools",n=await fetch(r,{method:E,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({search_tool:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Created search tool:",o),o}catch(e){throw console.error("Failed to create search tool:",e),e}},rk=async(e,t,r)=>{try{console.log("Updating search tool with ID:",t,"values:",r);let n=$?`${$}/search_tools/${t}`:`/search_tools/${t}`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({search_tool:r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("Updated search tool:",a),a}catch(e){throw console.error("Failed to update search tool:",e),e}},rT=async(e,t)=>{try{let r=($?`${$}`:"")+`/search_tools/${t}`;console.log("Deleting search tool:",t);let n=await fetch(r,{method:S,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Deleted search tool:",o),o}catch(e){throw console.error("Failed to delete search tool:",e),e}},rF=async e=>{try{let t=$?`${$}/search_tools/ui/available_providers`:"/search_tools/ui/available_providers";console.log("Fetching available search providers from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched available search providers:",n),n}catch(e){throw console.error("Failed to fetch available search providers:",e),e}},r_=async(e,t)=>{try{let r=$?`${$}/search_tools/test_connection`:"/search_tools/test_connection";console.log("Testing search tool connection:",r);let n=await fetch(r,{method:E,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({litellm_params:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Test connection response:",o),o}catch(e){throw console.error("Failed to test search tool connection:",e),e}},rI=async(e,t,r)=>{try{let n=$?`${$}/mcp-rest/tools/list?server_id=${t}`:`/mcp-rest/tools/list?server_id=${t}`;console.log("Fetching MCP tools from:",n);let o={[T]:`Bearer ${e}`,"Content-Type":"application/json",...r},a=await fetch(n,{method:"GET",headers:o}),i=await a.json();if(console.log("Fetched MCP tools response:",i),!a.ok){if(i.error&&i.message)throw Error(i.message);throw Error("Failed to fetch MCP tools")}return i}catch(e){return console.error("Failed to fetch MCP tools:",e),{tools:[],error:"network_error",message:e instanceof Error?e.message:"Failed to fetch MCP tools",stack_trace:null}}},rP=async(e,t,r,n,o)=>{try{let a=$?`${$}/mcp-rest/tools/call`:"/mcp-rest/tools/call";console.log("Calling MCP tool:",r,"with arguments:",n,"for server:",t);let i={[T]:`Bearer ${e}`,"Content-Type":"application/json",...o?.customHeaders||{}},l={server_id:t,name:r,arguments:n};o?.guardrails&&o.guardrails.length>0&&(l.litellm_metadata={guardrails:o.guardrails});let s=await fetch(a,{method:"POST",headers:i,body:JSON.stringify(l)});if(!s.ok){let e="Network response was not ok",t=null,r=await s.text();try{let n=JSON.parse(r);n.detail?"string"==typeof n.detail?e=n.detail:"object"==typeof n.detail&&(e=n.detail.message||n.detail.error||"An error occurred",t=n.detail):e=n.message||n.error||e}catch(t){console.error("Failed to parse JSON error response:",t),r&&(e=r)}let n=Error(e);throw n.status=s.status,n.statusText=s.statusText,n.details=t,j(e),n}let c=await s.json();return console.log("MCP tool call response:",c),c}catch(e){throw console.error("Failed to call MCP tool:",e),console.error("Error type:",typeof e),e instanceof Error&&(console.error("Error message:",e.message),console.error("Error stack:",e.stack)),e}},rN=async(e,t)=>{try{let r=$?`${$}/tag/new`:"/tag/new",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();await j(e);return}return await n.json()}catch(e){throw console.error("Error creating tag:",e),e}},rR=async(e,t)=>{try{let r=$?`${$}/tag/update`:"/tag/update",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();await j(e);return}return await n.json()}catch(e){throw console.error("Error updating tag:",e),e}},rM=async(e,t)=>{try{let r=$?`${$}/tag/info`:"/tag/info",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({names:t})});if(!n.ok){let e=await n.text();return await j(e),{}}return await n.json()}catch(e){throw console.error("Error getting tag info:",e),e}},rB=async e=>{try{let t=$?`${$}/tag/list`:"/tag/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok){let e=await r.text();return await j(e),{}}return await r.json()}catch(e){throw console.error("Error listing tags:",e),e}},rA=async(e,t)=>{try{let r=$?`${$}/tag/delete`:"/tag/delete",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({name:t})});if(!n.ok){let e=await n.text();await j(e);return}return await n.json()}catch(e){throw console.error("Error deleting tag:",e),e}},rz=async e=>{try{let t=$?`${$}/get/default_team_settings`:"/get/default_team_settings";console.log("Fetching default team settings from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched default team settings:",n),n}catch(e){throw console.error("Failed to fetch default team settings:",e),e}},rL=async(e,t)=>{try{let r=$?`${$}/update/default_team_settings`:"/update/default_team_settings";console.log("Updating default team settings:",t);let n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Updated default team settings:",o),g.default.success("Default team settings updated successfully"),o}catch(e){throw console.error("Failed to update default team settings:",e),e}},rH=async(e,t)=>{try{let r=$?`${$}/team/permissions_list?team_id=${t}`:`/team/permissions_list?team_id=${t}`,n=await fetch(r,{method:"GET",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}let o=await n.json();return console.log("Team permissions response:",o),o}catch(e){throw console.error("Failed to get team permissions:",e),e}},rD=async(e,t,r)=>{try{let n=$?`${$}/team/permissions_update`:"/team/permissions_update",o=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({team_id:t,team_member_permissions:r})});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return console.log("Team permissions response:",a),a}catch(e){throw console.error("Failed to update team permissions:",e),e}},rV=async(e,t)=>{try{let r=$?`${$}/spend/logs/session/ui?session_id=${encodeURIComponent(t)}`:`/spend/logs/session/ui?session_id=${encodeURIComponent(t)}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to fetch session logs:",e),e}},rW=async(e,t)=>{try{let r=$?`${$}/vector_store/new`:"/vector_store/new",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to create vector store")}return await n.json()}catch(e){throw console.error("Error creating vector store:",e),e}},rG=async(e,t=1,r=100)=>{try{let t=$?`${$}/vector_store/list`:"/vector_store/list",r=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`}});if(!r.ok){let e=await r.json();throw Error(e.detail||"Failed to list vector stores")}return await r.json()}catch(e){throw console.error("Error listing vector stores:",e),e}},rU=async(e,t)=>{try{let r=$?`${$}/vector_store/delete`:"/vector_store/delete",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({vector_store_id:t})});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to delete vector store")}return await n.json()}catch(e){throw console.error("Error deleting vector store:",e),e}},rq=async(e,t)=>{try{let r=$?`${$}/vector_store/info`:"/vector_store/info",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({vector_store_id:t})});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to get vector store info")}return await n.json()}catch(e){throw console.error("Error getting vector store info:",e),e}},rJ=async(e,t)=>{try{let r=$?`${$}/vector_store/update`:"/vector_store/update",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to update vector store")}return await n.json()}catch(e){throw console.error("Error updating vector store:",e),e}},rK=async(e,t,r,n,o,a,i)=>{try{let l=$?`${$}/rag/ingest`:"/rag/ingest",s=new FormData;s.append("file",t);let c={ingest_options:{vector_store:{custom_llm_provider:r,...n&&{vector_store_id:n},...i&&i}}};(o||a)&&(c.ingest_options.litellm_vector_store_params={},o&&(c.ingest_options.litellm_vector_store_params.vector_store_name=o),a&&(c.ingest_options.litellm_vector_store_params.vector_store_description=a)),s.append("request",JSON.stringify(c));let u=await fetch(l,{method:"POST",headers:{[T]:`Bearer ${e}`},body:s});if(!u.ok){let e=await u.json();throw Error(e.error?.message||e.detail||"Failed to ingest document")}return await u.json()}catch(e){throw console.error("Error ingesting document:",e),e}},rX=async e=>{try{let t=$?`${$}/email/event_settings`:"/email/event_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to get email event settings")}let n=await r.json();return console.log("Email event settings response:",n),n}catch(e){throw console.error("Failed to get email event settings:",e),e}},rY=async(e,t)=>{try{let r=$?`${$}/email/event_settings`:"/email/event_settings",n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to update email event settings")}let o=await n.json();return console.log("Update email event settings response:",o),o}catch(e){throw console.error("Failed to update email event settings:",e),e}},rZ=async e=>{try{let t=$?`${$}/email/event_settings/reset`:"/email/event_settings/reset",r=await fetch(t,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to reset email event settings")}let n=await r.json();return console.log("Reset email event settings response:",n),n}catch(e){throw console.error("Failed to reset email event settings:",e),e}},rQ=async(e,t)=>{try{let r=$?`${$}/v1/agents/${t}`:`/v1/agents/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Delete agent response:",o),o}catch(e){throw console.error("Failed to delete agent:",e),e}},r0=async(e,t)=>{try{let r=$?`${$}/v1/agents/make_public`:"/v1/agents/make_public",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({agent_ids:t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Make agents public response:",o),o}catch(e){throw console.error("Failed to make agents public:",e),e}},r1=async(e,t)=>{try{let r=$?`${$}/v1/mcp/make_public`:"/v1/mcp/make_public",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({mcp_server_ids:t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Make agents public response:",o),o}catch(e){throw console.error("Failed to make agents public:",e),e}},r2=async(e,t)=>{try{let r=$?`${$}/guardrails/${t}`:`/guardrails/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Delete guardrail response:",o),o}catch(e){throw console.error("Failed to delete guardrail:",e),e}},r4=async e=>{try{let t=$?`${$}/guardrails/ui/add_guardrail_settings`:"/guardrails/ui/add_guardrail_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to get guardrail UI settings")}let n=await r.json();return console.log("Guardrail UI settings response:",n),n}catch(e){throw console.error("Failed to get guardrail UI settings:",e),e}},r6=async e=>{try{let t=$?`${$}/guardrails/ui/provider_specific_params`:"/guardrails/ui/provider_specific_params",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to get guardrail provider specific parameters")}let n=await r.json();return console.log("Guardrail provider specific params response:",n),n}catch(e){throw console.error("Failed to get guardrail provider specific parameters:",e),e}},r3=async(e,t)=>{try{let r=encodeURIComponent(t),n=$?`${$}/guardrails/ui/category_yaml/${r}`:`/guardrails/ui/category_yaml/${r}`;console.log(`Fetching category YAML from: ${n}`);let o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw console.error(`Failed to get category YAML. Status: ${o.status}, Error:`,e),j(e),Error(`Failed to get category YAML: ${o.status} ${e}`)}let a=await o.json();return console.log("Category YAML response:",a),a}catch(e){throw console.error("Failed to get category YAML:",e),e}},r7=async e=>{try{let t=$?`${$}/guardrails/ui/major_airlines`:"/guardrails/ui/major_airlines",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw console.error(`Failed to get major airlines. Status: ${r.status}, Error:`,e),j(e),Error(`Failed to get major airlines: ${r.status} ${e}`)}return await r.json()}catch(e){throw console.error("Failed to get major airlines:",e),e}},r5=async(e,t=!1)=>{try{let r=t?"?health_check=true":"",n=$?`${$}/v1/agents${r}`:`/v1/agents${r}`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw j(e),Error("Failed to get agents list")}let a=await o.json();return console.log("Agents list response:",a),{agents:a}}catch(e){throw console.error("Failed to get agents list:",e),e}},r9=async(e,t)=>{try{let r=$?`${$}/v1/agents/${t}`:`/v1/agents/${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to get agent info")}let o=await n.json();return console.log("Agent info response:",o),o}catch(e){throw console.error("Failed to get agent info:",e),e}},r8=async(e,t)=>{try{let r=$?`${$}/guardrails/${t}/info`:`/guardrails/${t}/info`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to get guardrail info")}let o=await n.json();return console.log("Guardrail info response:",o),o}catch(e){throw console.error("Failed to get guardrail info:",e),e}},ne=async(e,t,r)=>{try{let n=$?`${$}/v1/agents/${t}`:`/v1/agents/${t}`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.text();throw j(e),Error("Failed to patch agent")}let a=await o.json();return console.log("Patch agent response:",a),a}catch(e){throw console.error("Failed to update guardrail:",e),e}},nt=async(e,t,r)=>{try{let n=$?`${$}/guardrails/${t}`:`/guardrails/${t}`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.text();throw j(e),Error("Failed to update guardrail")}let a=await o.json();return console.log("Update guardrail response:",a),a}catch(e){throw console.error("Failed to update guardrail:",e),e}},nr=async(e,t,r,n,o)=>{try{let a=$?`${$}/guardrails/apply_guardrail`:"/guardrails/apply_guardrail",i={guardrail_name:t,text:r};n&&(i.language=n),o&&o.length>0&&(i.entities=o);let l=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!l.ok){let e=await l.text(),t="Failed to apply guardrail";try{let r=JSON.parse(e);r.error?.message?t=r.error.message:r.detail?t=r.detail:r.message&&(t=r.message)}catch(r){t=e||t}throw j(e),Error(t)}let s=await l.json();return console.log("Apply guardrail response:",s),s}catch(e){throw console.error("Failed to apply guardrail:",e),e}},nn=async(e,t)=>{try{let r=$?`${$}/guardrails/test_custom_code`:"/guardrails/test_custom_code",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.text(),t="Failed to test custom code guardrail";try{let r=JSON.parse(e);r.error?.message?t=r.error.message:r.detail?t=r.detail:r.message&&(t=r.message)}catch(r){t=e||t}throw j(e),Error(t)}let o=await n.json();return console.log("Test custom code guardrail response:",o),o}catch(e){throw console.error("Failed to test custom code guardrail:",e),e}},no=async(e,t)=>{try{let r=$?`${$}/guardrails/validate_blocked_words_file`:"/guardrails/validate_blocked_words_file",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({file_content:t})});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to validate blocked words file")}let o=await n.json();return console.log("Validate blocked words file response:",o),o}catch(e){throw console.error("Failed to validate blocked words file:",e),e}},na=async e=>{try{let t=$?`${$}/get/sso_settings`:"/get/sso_settings";console.log("Fetching SSO configuration from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched SSO configuration:",n),n}catch(e){throw console.error("Failed to fetch SSO configuration:",e),e}},ni=async(e,t)=>{try{let r=$?`${$}/update/sso_settings`:"/update/sso_settings";console.log("Updating SSO configuration:",t);let n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t="object"==typeof e?.detail?e.detail?.error||e.detail?.message:e?.detail,r="string"==typeof t&&t.length>0?t:nx(e);j(r);let o=Error(r);throw e?.detail!==void 0&&(o.detail=e.detail),o.rawError=e,o}let o=await n.json();return console.log("Updated SSO configuration:",o),o}catch(e){throw console.error("Failed to update SSO configuration:",e),e}},nl=async({accessToken:e,page:t=1,page_size:r=50,params:n={}})=>{try{let o=$?`${$}/audit`:"/audit",a=new URLSearchParams;for(let[e,o]of(a.append("page",t.toString()),a.append("page_size",r.toString()),Object.entries(n)))null!=o&&""!==o&&a.append(e,String(o));o+=`?${a.toString()}`;let i=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nx(e);throw j(t),Error(t)}return await i.json()}catch(e){throw console.error("Failed to fetch audit logs:",e),e}},ns=async e=>{try{let t=$?`${$}/user/available_users`:"/user/available_users",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok){if(404===r.status)return null;let e=await r.text();throw j(e),Error("Network response was not ok")}return await r.json()}catch(e){throw console.error("Failed to fetch remaining users:",e),e}},nc=async e=>{try{let t=$?`${$}/health/license`:"/health/license",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok){if(404===r.status)return null;let e=await r.text();throw j(e),Error("Network response was not ok")}return await r.json()}catch(e){throw console.error("Failed to fetch license info:",e),e}},nu=async(e,t,r)=>{try{let n=$?`${$}/config/pass_through_endpoint/${encodeURIComponent(t)}`:`/config/pass_through_endpoint/${encodeURIComponent(t)}`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nx(e);throw j(t),Error(t)}let a=await o.json();return g.default.success("Pass through endpoint updated successfully"),a}catch(e){throw console.error("Failed to update pass through endpoint:",e),e}},nd=async(e,t)=>{try{let r=$?`${$}/config/callback/delete`:"/config/callback/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({callback_name:t})});if(!n.ok){let e=await n.json(),t=nx(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete specific callback:",e),e}},nf=async(e,t,r)=>{try{console.log("Testing MCP tools list with config:",JSON.stringify(t));let n=$?`${$}/mcp-rest/test/tools/list`:"/mcp-rest/test/tools/list",o={"Content-Type":"application/json"};e&&(o["x-litellm-api-key"]=e),r?o.Authorization=`Bearer ${r}`:e&&(o[T]=`Bearer ${e}`);let a=await fetch(n,{method:"POST",headers:o,body:JSON.stringify(t)}),i=a.headers.get("content-type");if(!i||!i.includes("application/json")){let e=await a.text();throw console.error("Received non-JSON response:",e),Error(`Received non-JSON response (${a.status}: ${a.statusText}). Check network tab for details.`)}let l=await a.json();if((!a.ok||l.error)&&!l.error)return{tools:[],error:"request_failed",message:l.message||`MCP tools list failed: ${a.status} ${a.statusText}`};return l}catch(e){throw console.error("MCP tools list test error:",e),e}},np=async(e,t)=>{let r=$?`${$}/v1/mcp/server/oauth/session`:"/v1/mcp/server/oauth/session",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)}),o=await n.json();if(!n.ok)throw Error(nx(o)||o?.error||"Failed to cache MCP server");return o},nm=async(e,t,r)=>{let n=C(),o=encodeURIComponent(t.trim()),a=`${n}/v1/mcp/server/oauth/${o}/register`,i=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json",Accept:"application/json, text/event-stream"},body:JSON.stringify(r)}),l=await i.json();if(!i.ok)throw Error(nx(l)||l?.detail||"Failed to register OAuth client");return l},nh=({serverId:e,clientId:t,redirectUri:r,state:n,codeChallenge:o,scope:a})=>{let i=C(),l=encodeURIComponent(e.trim()),s=`${i}/v1/mcp/server/oauth/${l}/authorize`,c=new URLSearchParams({redirect_uri:r,state:n,response_type:"code",code_challenge:o,code_challenge_method:"S256"});return t&&t.trim().length>0&&c.set("client_id",t),a&&a.trim().length>0&&c.set("scope",a),`${s}?${c.toString()}`},ng=async({serverId:e,code:t,clientId:r,clientSecret:n,codeVerifier:o,redirectUri:a})=>{let i=C(),l=encodeURIComponent(e.trim()),s=`${i}/v1/mcp/server/oauth/${l}/token`,c=new URLSearchParams;c.set("grant_type","authorization_code"),c.set("code",t),r&&r.trim().length>0&&c.set("client_id",r),n&&n.trim().length>0&&c.set("client_secret",n),c.set("code_verifier",o),c.set("redirect_uri",a);let u=await fetch(s,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:c.toString()}),d=await u.json();if(!u.ok)throw Error(nx(d)||d?.detail||"OAuth token exchange failed");return d},nv=async(e,t,r)=>{try{let n=`${C()}/v1/vector_stores/${t}/search`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({query:r})});if(!o.ok){let e=await o.text();return await j(e),null}return await o.json()}catch(e){throw console.error("Error testing vector store search:",e),e}},ny=async(e,t,r,n)=>{try{let o=`${C()}/v1/search/${t}`,a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({query:r,max_results:n||5})});if(!a.ok){let e=await a.text();return await j(e),null}return await a.json()}catch(e){throw console.error("Error querying search tool:",e),e}},nb=async(e,t,r,n)=>{try{let o,a,i,l=$?`${$}/tag/dau`:"/tag/dau",s=new URLSearchParams;s.append("end_date",(o=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0"),`${o}-${a}-${i}`)),n&&n.length>0?n.forEach(e=>{s.append("tag_filters",e)}):r&&s.append("tag_filter",r);let c=s.toString();c&&(l+=`?${c}`);let u=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!u.ok){let e=await u.json(),t=nx(e);throw j(t),Error(t)}return await u.json()}catch(e){throw console.error("Failed to fetch DAU:",e),e}},nw=async(e,t,r,n)=>{try{let o,a,i,l=$?`${$}/tag/wau`:"/tag/wau",s=new URLSearchParams;s.append("end_date",(o=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0"),`${o}-${a}-${i}`)),n&&n.length>0?n.forEach(e=>{s.append("tag_filters",e)}):r&&s.append("tag_filter",r);let c=s.toString();c&&(l+=`?${c}`);let u=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!u.ok){let e=await u.json(),t=nx(e);throw j(t),Error(t)}return await u.json()}catch(e){throw console.error("Failed to fetch WAU:",e),e}},n$=async(e,t,r,n)=>{try{let o,a,i,l=$?`${$}/tag/mau`:"/tag/mau",s=new URLSearchParams;s.append("end_date",(o=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0"),`${o}-${a}-${i}`)),n&&n.length>0?n.forEach(e=>{s.append("tag_filters",e)}):r&&s.append("tag_filter",r);let c=s.toString();c&&(l+=`?${c}`);let u=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!u.ok){let e=await u.json(),t=nx(e);throw j(t),Error(t)}return await u.json()}catch(e){throw console.error("Failed to fetch MAU:",e),e}},nC=async e=>{try{let t=$?`${$}/tag/distinct`:"/tag/distinct",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nx(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to fetch distinct tags:",e),e}},nE=async(e,t,r,n)=>{try{let o=$?`${$}/tag/summary`:"/tag/summary",a=new URLSearchParams,i=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${n}`};a.append("start_date",i(t)),a.append("end_date",i(r)),n&&n.length>0&&n.forEach(e=>{a.append("tag_filters",e)});let l=a.toString();l&&(o+=`?${l}`);let s=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nx(e);throw j(t),Error(t)}return await s.json()}catch(e){throw console.error("Failed to fetch user agent summary:",e),e}},nS=async(e,t=1,r=50,n)=>{try{let o=$?`${$}/tag/user-agent/per-user-analytics`:"/tag/user-agent/per-user-analytics",a=new URLSearchParams;a.append("page",t.toString()),a.append("page_size",r.toString()),n&&n.length>0&&n.forEach(e=>{a.append("tag_filters",e)});let i=a.toString();i&&(o+=`?${i}`);let l=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!l.ok){let e=await l.json(),t=nx(e);throw j(t),Error(t)}return await l.json()}catch(e){throw console.error("Failed to fetch per-user analytics:",e),e}},nx=e=>{let t=e?.detail,r=Array.isArray(t)?t.map(e=>e?.msg||JSON.stringify(e)).join("; "):"string"==typeof t?t:void 0;return e?.error&&(e.error.message||("string"==typeof e.error?e.error:void 0))||e?.message||r||JSON.stringify(e)},nj=async(e,t)=>{let r=C(),n=r?`${r}/v2/login`:"/v2/login",o=JSON.stringify({username:e,password:t}),a=await fetch(n,{method:"POST",body:o,credentials:"include",headers:{"Content-Type":"application/json"}});if(!a.ok)throw Error(nx(await a.json()));return await a.json()},nO=async()=>{let e=C(),t=e?`${e}/get/ui_settings`:"/get/ui_settings",r=await fetch(t,{method:"GET"});if(!r.ok)throw Error(nx(await r.json()));return await r.json()},nk=async(e,t)=>{let r=C(),n=r?`${r}/update/ui_settings`:"/update/ui_settings",o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok)throw Error(nx(await o.json()));return await o.json()},nT=async()=>{try{let e=C(),t=e?`${e}/claude-code/marketplace.json`:"/claude-code/marketplace.json",r=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"}});if(!r.ok){let e=await r.text(),t=nx(JSON.parse(e));throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to fetch Claude Code marketplace:",e),e}},nF=async(e,t=!1)=>{try{let r=C(),n=r?`${r}/claude-code/plugins?enabled_only=${t}`:`/claude-code/plugins?enabled_only=${t}`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nx(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to fetch Claude Code plugins list:",e),e}},n_=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}`:`/claude-code/plugins/${t}`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nx(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to fetch plugin "${t}":`,e),e}},nI=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins`:"/claude-code/plugins",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.text(),t=nx(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to register Claude Code plugin:",e),e}},nP=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}/enable`:`/claude-code/plugins/${t}/enable`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nx(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to enable plugin "${t}":`,e),e}},nN=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}/disable`:`/claude-code/plugins/${t}/disable`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nx(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to disable plugin "${t}":`,e),e}},nR=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}`:`/claude-code/plugins/${t}`,o=await fetch(n,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nx(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to delete plugin "${t}":`,e),e}},nM=async(e,t)=>{let r=$?`${$}/compliance/eu-ai-act`:"/compliance/eu-ai-act",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok)throw Error(await n.text());return n.json()},nB=async(e,t)=>{let r=$?`${$}/compliance/gdpr`:"/compliance/gdpr",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok)throw Error(await n.text());return n.json()},nA=async e=>{let t=$?`${$}/v1/tool/policy/options`:"/v1/tool/policy/options",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok)throw Error(await r.text());return r.json()},nz=async e=>{let t=$?`${$}/v1/tool/list`:"/v1/tool/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok)throw Error(await r.text());return(await r.json()).tools??[]},nL=async(e,t,r)=>{let n=encodeURIComponent(t),o=$?`${$}/v1/tool/${n}/logs`:`/v1/tool/${n}/logs`,a=new URLSearchParams;null!=r.page&&a.append("page",String(r.page)),null!=r.pageSize&&a.append("page_size",String(r.pageSize)),r.startDate&&a.append("start_date",r.startDate),r.endDate&&a.append("end_date",r.endDate);let i=a.toString()?`${o}?${a.toString()}`:o,l=await fetch(i,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!l.ok)throw Error(nx(await l.json().catch(()=>({}))));return l.json()},nH=async(e,t)=>{let r=encodeURIComponent(t),n=$?`${$}/v1/tool/${r}/detail`:`/v1/tool/${r}/detail`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok)throw Error(await o.text());return o.json()},nD=async(e,t,r,n)=>{let o=$?`${$}/v1/tool/policy`:"/v1/tool/policy",a={tool_name:t};null!=r.input_policy&&(a.input_policy=r.input_policy),null!=r.output_policy&&(a.output_policy=r.output_policy),n?.team_id!=null&&(a.team_id=n.team_id||void 0),n?.key_hash!=null&&(a.key_hash=n.key_hash||void 0),n?.key_alias!=null&&(a.key_alias=n.key_alias||void 0);let i=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(a)});if(!i.ok)throw Error(await i.text());return i.json()},nV=async(e,t,r)=>{let n=encodeURIComponent(t),o=new URLSearchParams;null!=r.team_id&&""!==r.team_id&&o.set("team_id",r.team_id),null!=r.key_hash&&""!==r.key_hash&&o.set("key_hash",r.key_hash);let a=o.toString(),i=$?`${$}/v1/tool/${n}/overrides${a?`?${a}`:""}`:`/v1/tool/${n}/overrides${a?`?${a}`:""}`,l=await fetch(i,{method:"DELETE",headers:{[T]:`Bearer ${e}`}});if(!l.ok)throw Error(await l.text());return l.json()},nW=async(e,t,r)=>{let n=$?`${$}/v1/mcp/server/${t}/oauth-user-credential`:`/v1/mcp/server/${t}/oauth-user-credential`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json().catch(()=>({})),t=e?.detail;throw Error((Array.isArray(t)?t.map(e=>e&&"object"==typeof e?e.msg??JSON.stringify(e):String(e)).join("; "):"string"==typeof t?t:t&&"string"==typeof t.error?t.error:void 0)||"Failed to store OAuth credential")}return o.json()},nG=async(e,t)=>{let r=$?`${$}/v1/mcp/server/${t}/oauth-user-credential`:`/v1/mcp/server/${t}/oauth-user-credential`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`}});if(!n.ok){let e=await n.json().catch(()=>({})),t=e?.detail;throw Error((Array.isArray(t)?t.map(e=>e&&"object"==typeof e?e.msg??JSON.stringify(e):String(e)).join("; "):"string"==typeof t?t:t&&"string"==typeof t.error?t.error:void 0)||"Failed to revoke OAuth credential")}return n.json()},nU=async(e,t)=>{let r=$?`${$}/v1/mcp/server/${t}/oauth-user-credential/status`:`/v1/mcp/server/${t}/oauth-user-credential/status`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`}});return n.ok?n.json():{server_id:t,has_credential:!1,is_expired:!1}},nq=async e=>{let t=$?`${$}/v1/mcp/user-credentials`:"/v1/mcp/user-credentials",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});return r.ok?r.json():[]}}]); \ No newline at end of file +Allowed values: ${t.enum.join(", ")}`:S)}),children:r},e)})}):null};var g=e.i(727749);let v=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${n}`},y=async e=>{try{let t=$?`${$}/callbacks/configs`:"/callbacks/configs",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},b=async e=>{try{let t=$?`${$}/in_product_nudges`:"/in_product_nudges",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get in-product nudges:",e),e}},w="/",$=null;console.log=function(){};let C=()=>{if($)return $;let e=window.location;return e?.origin??""},E="POST",S="DELETE",x=0,j=async e=>{let t=Date.now();if(t-x>6e4){if(("string"==typeof e?e:JSON.stringify(e)).includes("Authentication Error - Expired Key")){g.default.info("UI Session Expired. Logging out."),x=t,(0,r.clearTokenCookies)();let e=window.location;e&&(window.location.href=e.pathname)}x=t}else console.log("Error suppressed to prevent spam:",e)},O=async()=>{let e=$?`${$}/public/providers/fields`:"/public/providers/fields",t=await fetch(e,{method:"GET"});if(!t.ok){let e=await t.text();throw console.error("Failed to fetch provider create metadata:",t.status,e),Error("Failed to load provider configuration")}return await t.json()},k=async()=>{let e=$?`${$}/public/agents/fields`:"/public/agents/fields",t=await fetch(e,{method:"GET"});if(!t.ok){let e=await t.text();throw console.error("Failed to fetch agent create metadata:",t.status,e),Error("Failed to load agent configuration")}return await t.json()},T="Authorization";function F(e="Authorization"){console.log(`setGlobalLitellmHeaderName: ${e}`),T=e}function _(){return T}let I=async(e,t)=>{let r=$?`${$}/model_group/make_public`:"/model_group/make_public";return(await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({model_groups:t})})).json()},P=async()=>{console.log("Getting UI config");let e=await fetch("/litellm/.well-known/litellm-ui-config"),t=await e.json();return console.log("jsonData in getUiConfig:",t),((e,t=null)=>{let r=window.location,n=r?.origin??null,o=t||n;if(console.log("proxyBaseUrl:",$),console.log("serverRootPath:",e),!o)return console.log("Updated proxyBaseUrl:",$=$??null);e.length>0&&!o.endsWith(e)&&"/"!=e&&(o+=e),console.log("Updated proxyBaseUrl:",$=o)})(t.server_root_path,t.proxy_base_url),t},N=async()=>{let e=$?`${$}/public/model_hub/info`:"/public/model_hub/info",t=await fetch(e);return await t.json()},R=async()=>{let e=$?`${$}/openapi.json`:"/openapi.json",t=await fetch(e);return await t.json()},M=async()=>{try{let e=$?`${$}/public/litellm_model_cost_map`:"/public/litellm_model_cost_map",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}}),r=await t.json();return console.log(`received litellm model cost data: ${r}`),r}catch(e){throw console.error("Failed to get model cost map:",e),e}},B=async e=>{try{let t=$?`${$}/reload/model_cost_map`:"/reload/model_cost_map",r=await fetch(t,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}}),n=await r.json();return console.log(`Model cost map reload response: ${n}`),n}catch(e){throw console.error("Failed to reload model cost map:",e),e}},A=async(e,t)=>{try{let r=$?`${$}/schedule/model_cost_map_reload?hours=${t}`:`/schedule/model_cost_map_reload?hours=${t}`,n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}}),o=await n.json();return console.log(`Schedule model cost map reload response: ${o}`),o}catch(e){throw console.error("Failed to schedule model cost map reload:",e),e}},z=async e=>{try{let t=$?`${$}/schedule/model_cost_map_reload`:"/schedule/model_cost_map_reload",r=await fetch(t,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}}),n=await r.json();return console.log(`Cancel model cost map reload response: ${n}`),n}catch(e){throw console.error("Failed to cancel model cost map reload:",e),e}},L=async e=>{try{let t=$?`${$}/model/cost_map/source`:"/model/cost_map/source",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw Error(`HTTP ${r.status}: ${e}`)}let n=await r.json();return console.log("Model cost map source info:",n),n}catch(e){throw console.error("Failed to get model cost map source info:",e),e}},H=async e=>{try{let t=$?`${$}/schedule/model_cost_map_reload/status`:"/schedule/model_cost_map_reload/status";console.log("Fetching status from URL:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){console.error(`Status request failed with status: ${r.status}`);let e=await r.text();throw console.error("Error response:",e),Error(`HTTP ${r.status}: ${e}`)}let n=await r.json();return console.log("Model cost map reload status:",n),n}catch(e){throw console.error("Failed to get model cost map reload status:",e),e}},D=async(e,r)=>{try{let n=$?`${$}/model/new`:"/model/new",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),t.message.destroy(),g.default.success(`Model ${r.model_name} created successfully`),a}catch(e){throw console.error("Failed to create key:",e),e}},V=async(e,t)=>{console.log(`model_id in model delete call: ${t}`);try{let r=$?`${$}/model/delete`:"/model/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({id:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},W=async(e,t)=>{if(console.log(`budget_id in budget delete call: ${t}`),null!=e)try{let r=$?`${$}/budget/delete`:"/budget/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({id:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},G=async(e,t)=>{try{console.log("Form Values in budgetCreateCall:",t),console.log("Form Values after check:",t);let r=$?`${$}/budget/new`:"/budget/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},U=async(e,t)=>{try{console.log("Form Values in budgetUpdateCall:",t),console.log("Form Values after check:",t);let r=$?`${$}/budget/update`:"/budget/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},q=async(e,t)=>{try{let r=$?`${$}/invitation/new`:"/invitation/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_id:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},J=async e=>{try{let t=$?`${$}/alerting/settings`:"/alerting/settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},K=async(e,t)=>{try{for(let e of(console.log("Form Values in keyCreateServiceAccountCall:",t),t.description&&(t.metadata||(t.metadata={}),t.metadata.description=t.description,delete t.description,t.metadata=JSON.stringify(t.metadata)),p))if(t[e]){console.log(`formValues.${e}:`,t[e]);try{t[e]=JSON.parse(t[e])}catch(t){throw Error(`Failed to parse ${e}: `+t)}}console.log("Form Values after check:",t);let r=$?`${$}/key/service-account/generate`:"/key/service-account/generate",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},X=async(e,t,r)=>{try{for(let e of(console.log("Form Values in keyCreateCall:",r),r.description&&(r.metadata||(r.metadata={}),r.metadata.description=r.description,delete r.description,r.metadata=JSON.stringify(r.metadata)),p))if(r[e]){console.log(`formValues.${e}:`,r[e]);try{r[e]=JSON.parse(r[e])}catch(t){throw Error(`Failed to parse ${e}: `+t)}}console.log("Form Values after check:",r);let n=$?`${$}/key/generate`:"/key/generate",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...r})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},Y=async(e,t,r,n,o,a)=>{let i=$?`${$}/key/generate`:"/key/generate",l={agent_id:t,key_alias:r,models:n.length>0?n:[]};a&&(l.team_id=a),o&&Object.keys(o).length>0&&(l.metadata=o);let s=await fetch(i,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(l)});if(!s.ok)throw j(await s.text()),Error("Failed to create key for agent");return s.json()},Z=async(e,t,r)=>{try{if(console.log("Form Values in keyCreateCall:",r),r.description&&(r.metadata||(r.metadata={}),r.metadata.description=r.description,delete r.description,r.metadata=JSON.stringify(r.metadata)),r.auto_create_key=!1,r.metadata){console.log("formValues.metadata:",r.metadata);try{r.metadata=JSON.parse(r.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}console.log("Form Values after check:",r);let n=$?`${$}/user/new`:"/user/new",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...r})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},Q=async(e,t)=>{try{let r=$?`${$}/key/delete`:"/key/delete";console.log("in keyDeleteCall:",t);let n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({keys:[t]})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to create key:",e),e}},ee=async(e,t)=>{try{let r=$?`${$}/user/delete`:"/user/delete";console.log("in userDeleteCall:",t);let n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({user_ids:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to delete user(s):",e),e}},et=async(e,t)=>{try{let r=$?`${$}/team/delete`:"/team/delete";console.log("in teamDeleteCall:",t);let n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({team_ids:[t]})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to delete key:",e),e}},er=async(e,t=null,r=null,n=null,o=null,a=null,i=null,l=null,s=null,c=null,u=null)=>{try{let d=$?`${$}/user/list`:"/user/list";console.log("in userListCall");let f=new URLSearchParams;if(t&&t.length>0){let e=t.join(",");f.append("user_ids",e)}r&&f.append("page",r.toString()),n&&f.append("page_size",n.toString()),o&&f.append("user_email",o),a&&f.append("role",a),i&&f.append("team",i),l&&f.append("sso_user_ids",l),s&&f.append("sort_by",s),c&&f.append("sort_order",c),u&&u.length>0&&f.append("organization_ids",u.join(","));let p=f.toString();p&&(d+=`?${p}`);let m=await fetch(d,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!m.ok){let e=await m.json(),t=nj(e);throw j(t),Error(t)}let h=await m.json();return console.log("/user/list API Response:",h),h}catch(e){throw console.error("Failed to create key:",e),e}},en=async(e,t)=>{try{let r=$?`${$}/v2/user/info`:"/v2/user/info";t&&(r+=`?user_id=${encodeURIComponent(t)}`);let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to fetch user info v2:",e),e}},eo=async(e,t,r,n=!1,o,a,i=!1)=>{console.log(`userInfoCall: ${t}, ${r}, ${n}, ${o}, ${a}, ${i}`);try{let l;if(n){l=$?`${$}/user/list`:"/user/list";let e=new URLSearchParams;null!=o&&e.append("page",o.toString()),null!=a&&e.append("page_size",a.toString()),l+=`?${e.toString()}`}else l=$?`${$}/user/info`:"/user/info",("Admin"!==r&&"Admin Viewer"!==r||i)&&t&&(l+=`?user_id=${t}`);console.log("Requesting user data from:",l);let s=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nj(e);throw j(t),Error(t)}let c=await s.json();return console.log("API Response:",c),c}catch(e){throw console.error("Failed to fetch user data:",e),e}},ea=async(e,t)=>{try{let r=$?`${$}/team/info`:"/team/info";t&&(r=`${r}?team_id=${t}`),console.log("in teamInfoCall");let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ei=async(e,t,r=null,n=null,o=null,a=1,i=10,l=null,s=null)=>{try{let a=$?`${$}/v2/team/list`:"/v2/team/list";console.log("in teamInfoCall");let i=new URLSearchParams;r&&i.append("user_id",r.toString()),t&&i.append("organization_id",t.toString()),n&&i.append("team_id",n.toString()),o&&i.append("team_alias",o.toString());let l=i.toString();l&&(a+=`?${l}`);let s=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nj(e);throw j(t),Error(t)}let c=await s.json();return console.log("/v2/team/list API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},el=async(e,t,r=null,n=null,o=null)=>{try{let a=$?`${$}/team/list`:"/team/list";console.log("in teamInfoCall");let i=new URLSearchParams;r&&i.append("user_id",r.toString()),t&&i.append("organization_id",t.toString()),n&&i.append("team_id",n.toString()),o&&i.append("team_alias",o.toString());let l=i.toString();l&&(a+=`?${l}`);let s=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nj(e);throw j(t),Error(t)}let c=await s.json();return console.log("/team/list API Response:",c),c}catch(e){throw console.error("Failed to create key:",e),e}},es=async e=>{try{let t=$?`${$}/team/available`:"/team/available";console.log("in availableTeamListCall");let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("/team/available_teams API Response:",n),n}catch(e){throw e}},ec=async(e,t=null,r=null)=>{try{let n=$?`${$}/organization/list`:"/organization/list",o=new URLSearchParams;t&&o.append("org_id",t.toString()),r&&o.append("org_alias",r.toString());let a=o.toString();a&&(n+=`?${a}`);let i=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nj(e);throw j(t),Error(t)}return await i.json()}catch(e){throw console.error("Failed to create key:",e),e}},eu=async(e,t)=>{try{let r=$?`${$}/organization/info`:"/organization/info";t&&(r=`${r}?organization_id=${t}`),console.log("in teamInfoCall");let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ed=async(e,t)=>{try{if(console.log("Form Values in organizationCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw console.error("Failed to parse metadata:",e),Error("Failed to parse metadata: "+e)}}let r=$?`${$}/organization/new`:"/organization/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ef=async(e,t)=>{try{console.log("Form Values in organizationUpdateCall:",t);let r=$?`${$}/organization/update`:"/organization/update",n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Update Team Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},ep=async(e,t)=>{try{let r=$?`${$}/organization/delete`:"/organization/delete",n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_ids:[t]})});if(!n.ok){let e=await n.text();throw j(e),Error(`Error deleting organization: ${e}`)}return await n.json()}catch(e){throw console.error("Failed to delete organization:",e),e}},em=async(e,t)=>{try{let r=$?`${$}/utils/transform_request`:"/utils/transform_request",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create key:",e),e}},eh=async({accessToken:e,endpoint:t,startTime:r,endTime:n,page:o=1,extraQueryParams:a})=>{try{let i,l,s,c,u=(i=t.startsWith("/")?t:`/${t}`,l=$?`${$}${i}`:i,(s=new URLSearchParams).append("start_date",v(r)),s.append("end_date",v(n)),s.append("page_size","1000"),s.append("page",o.toString()),s.append("timezone",new Date().getTimezoneOffset().toString()),a&&Object.entries(a).forEach(([e,t])=>{((e,t,r)=>{if(null!=r){if(Array.isArray(r)){r.length>0&&e.append(t,r.join(","));return}e.append(t,`${r}`)}})(s,e,t)}),(c=s.toString())?`${l}?${c}`:l),d=await fetch(u,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!d.ok){let e=await d.json(),t=nj(e);throw j(t),Error(t)}return await d.json()}catch(e){throw console.error(`Failed to fetch daily activity (${t}):`,e),e}},eg=async(e,t,r,n=1,o=null)=>eh({accessToken:e,endpoint:"/user/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{user_id:o}}),ev=async(e,t,r,n=1,o=null)=>eh({accessToken:e,endpoint:"/tag/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{tags:o}}),ey=async(e,t,r,n=1,o=null)=>eh({accessToken:e,endpoint:"/team/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{team_ids:o,exclude_team_ids:"litellm-dashboard"}}),eb=async(e,t,r,n=1,o=null)=>eh({accessToken:e,endpoint:"/organization/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{organization_ids:o}}),ew=async(e,t,r,n=1,o=null)=>eh({accessToken:e,endpoint:"/customer/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{end_user_ids:o}}),e$=async(e,t,r,n=1,o=null)=>eh({accessToken:e,endpoint:"/agent/daily/activity",startTime:t,endTime:r,page:n,extraQueryParams:{agent_ids:o}}),eC=async e=>{try{let t=$?`${$}/onboarding/get_token`:"/onboarding/get_token";t+=`?invite_link=${e}`;let r=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to create key:",e),e}},eE=async(e,t,r,n)=>{let o=$?`${$}/onboarding/claim_token`:"/onboarding/claim_token";try{let a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({invitation_link:t,user_id:r,password:n})});if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to delete key:",e),e}},eS=async(e,t,r)=>{try{let n=$?`${$}/key/${t}/regenerate`:`/key/${t}/regenerate`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("Regenerate key Response:",a),a}catch(e){throw console.error("Failed to regenerate key:",e),e}},ex=!1,ej=null,eO=async(e,t,r,n=1,o=50,a,i,l,s,c)=>{try{console.log("modelInfoCall:",e,t,r,n,o,a,i,l,s,c);let u=$?`${$}/v2/model/info`:"/v2/model/info",d=new URLSearchParams;d.append("include_team_models","true"),d.append("page",n.toString()),d.append("size",o.toString()),a&&a.trim()&&d.append("search",a.trim()),i&&i.trim()&&d.append("modelId",i.trim()),l&&l.trim()&&d.append("teamId",l.trim()),s&&s.trim()&&d.append("sortBy",s.trim()),c&&c.trim()&&d.append("sortOrder",c.trim()),d.toString()&&(u+=`?${d.toString()}`);let f=await fetch(u,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!f.ok){let e=await f.text();throw e+=`error shown=${ex}`,ex||(e.includes("No model list passed")&&(e="No Models Exist. Click Add Model to get started."),g.default.info(e),ex=!0,ej&&clearTimeout(ej),ej=setTimeout(()=>{ex=!1},1e4)),Error("Network response was not ok")}let p=await f.json();return console.log("modelInfoCall:",p),p}catch(e){throw console.error("Failed to create key:",e),e}},ek=async(e,t)=>{try{let r=$?`${$}/v1/model/info`:"/v1/model/info";r+=`?litellm_model_id=${t}`;let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("modelInfoV1Call:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},eT=async()=>{let e=$?`${$}/public/model_hub`:"/public/model_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`modelHubPublicModelsCall failed with status ${t.status}`),[])},eF=async()=>{let e=$?`${$}/public/agent_hub`:"/public/agent_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`agentHubPublicModelsCall failed with status ${t.status}`),[])},e_=async()=>{let e=$?`${$}/public/mcp_hub`:"/public/mcp_hub",t=await fetch(e,{method:"GET",headers:{"Content-Type":"application/json"}});return t.ok?t.json():(console.error(`mcpHubPublicServersCall failed with status ${t.status}`),[])},eI=async e=>{try{let t=$?`${$}/model_group/info`:"/model_group/info",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("modelHubCall:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},eP=async e=>{try{let t=$?`${$}/get/allowed_ips`:"/get/allowed_ips",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("getAllowedIPs:",n),n.data}catch(e){throw console.error("Failed to get allowed IPs:",e),e}},eN=async(e,t)=>{try{let r=$?`${$}/add/allowed_ip`:"/add/allowed_ip",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({ip:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("addAllowedIP:",o),o}catch(e){throw console.error("Failed to add allowed IP:",e),e}},eR=async(e,t)=>{try{let r=$?`${$}/delete/allowed_ip`:"/delete/allowed_ip",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({ip:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("deleteAllowedIP:",o),o}catch(e){throw console.error("Failed to delete allowed IP:",e),e}},eM=async(e,t)=>{try{let r=$?`${$}/model_hub/update_useful_links`:"/model_hub/update_useful_links",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({useful_links:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create key:",e),e}},eB=async(e,t,r,n=!1,o=null,a=!1,i=!1,l)=>{console.log("in /models calls, globalLitellmHeaderName",T);try{let t=$?`${$}/models`:"/models",r=new URLSearchParams;r.append("include_model_access_groups","True"),!0===n&&r.append("return_wildcard_routes","True"),!0===i&&r.append("only_model_access_groups","True"),o&&r.append("team_id",o.toString()),l&&r.append("scope",l),r.toString()&&(t+=`?${r.toString()}`);let a=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}return await a.json()}catch(e){throw console.error("Failed to create key:",e),e}},eA=async e=>{try{let t=$?`${$}/global/spend/teams`:"/global/spend/teams";console.log("in teamSpendLogsCall:",t);let r=await fetch(`${t}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},ez=async(e,t,r,n)=>{try{let o=$?`${$}/global/spend/tags`:"/global/spend/tags";t&&r&&(o=`${o}?start_date=${t}&end_date=${r}`),n&&(o+=`&tags=${n.join(",")}`),console.log("in tagsSpendLogsCall:",o);let a=await fetch(`${o}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to create key:",e),e}},eL=async e=>{try{let t=$?`${$}/global/spend/all_tag_names`:"/global/spend/all_tag_names";console.log("in global/spend/all_tag_names call",t);let r=await fetch(`${t}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eH=async e=>{try{let t=$?`${$}/customer/list`:"/customer/list";console.log("in customer/list",t);let r=await fetch(`${t}`,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to fetch end users:",e),e}},eD=async(e,t)=>{try{let r=$?`${$}/user/filter/ui`:"/user/filter/ui",n=new URLSearchParams;t.get("user_email")&&n.append("user_email",t.get("user_email")),t.get("user_id")&&n.append("user_id",t.get("user_id")),t.get("team_id")&&n.append("team_id",t.get("team_id"));let o=n.toString(),a=o?`${r}?${o}`:r,i=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nj(e);throw j(t),Error(t)}return await i.json()}catch(e){throw console.error("Failed to create key:",e),e}},eV=async({accessToken:e,start_date:t,end_date:r,page:n=1,page_size:o=50,params:a={}})=>{try{let i=$?`${$}/spend/logs/ui`:"/spend/logs/ui",l=new URLSearchParams;for(let[e,i]of(l.append("start_date",t),l.append("end_date",r),l.append("page",n.toString()),l.append("page_size",o.toString()),Object.entries(a)))null!=i&&("min_spend"===e||"max_spend"===e?l.append(e,i.toString()):"string"==typeof i&&""!==i&&l.append(e,String(i)));let s=l.toString();s&&(i+=`?${s}`);let c=await fetch(i,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!c.ok){let e=await c.json(),t=nj(e);throw j(t),Error(t)}let u=await c.json();return console.log("Spend Logs Response:",u),u}catch(e){throw console.error("Failed to fetch spend logs:",e),e}},eW=async e=>{try{let t=$?`${$}/global/spend/logs`:"/global/spend/logs",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eG=async e=>{try{let t=$?`${$}/global/spend/keys?limit=5`:"/global/spend/keys?limit=5",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eU=async(e,t,r,n)=>{try{let o=$?`${$}/global/spend/end_users`:"/global/spend/end_users",a="";a=t?JSON.stringify({api_key:t,startTime:r,endTime:n}):JSON.stringify({startTime:r,endTime:n});let i={method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:a},l=await fetch(o,i);if(!l.ok){let e=await l.json(),t=nj(e);throw j(t),Error(t)}let s=await l.json();return console.log(s),s}catch(e){throw console.error("Failed to create key:",e),e}},eq=async(e,t,r,n)=>{try{let o=$?`${$}/global/spend/provider`:"/global/spend/provider";r&&n&&(o+=`?start_date=${r}&end_date=${n}`),t&&(o+=`&api_key=${t}`);let a={method:"GET",headers:{[T]:`Bearer ${e}`}},i=await fetch(o,a);if(!i.ok){let e=await i.json(),t=nj(e);throw j(t),Error(t)}let l=await i.json();return console.log(l),l}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eJ=async(e,t,r)=>{try{let n=$?`${$}/global/activity`:"/global/activity";t&&r&&(n+=`?start_date=${t}&end_date=${r}`);let o={method:"GET",headers:{[T]:`Bearer ${e}`}},a=await fetch(n,o);if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eK=async(e,t,r)=>{try{let n=$?`${$}/global/activity/cache_hits`:"/global/activity/cache_hits";t&&r&&(n+=`?start_date=${t}&end_date=${r}`);let o={method:"GET",headers:{[T]:`Bearer ${e}`}},a=await fetch(n,o);if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eX=async(e,t,r)=>{try{let n=$?`${$}/global/activity/model`:"/global/activity/model";t&&r&&(n+=`?start_date=${t}&end_date=${r}`);let o={method:"GET",headers:{[T]:`Bearer ${e}`}},a=await fetch(n,o);if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}let i=await a.json();return console.log(i),i}catch(e){throw console.error("Failed to fetch spend data:",e),e}},eY=async e=>{try{let t=$?`${$}/global/spend/models?limit=5`:"/global/spend/models?limit=5",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},eZ=async(e,t)=>{try{let r=$?`${$}/v2/key/info`:"/v2/key/info",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({keys:t})});if(!n.ok){let e=await n.text();if(e.includes("Invalid proxy server token passed"))throw Error("Invalid proxy server token passed");throw j(e),Error("Network response was not ok")}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to create key:",e),e}},eQ=async(e,t,r,n)=>{try{console.log("Sending model connection test request:",JSON.stringify(t));let o=$?`${$}/health/test_connection`:"/health/test_connection",a=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({litellm_params:t,model_info:r,mode:n})}),i=a.headers.get("content-type");if(!i||!i.includes("application/json")){let e=await a.text();throw console.error("Received non-JSON response:",e),Error(`Received non-JSON response (${a.status}: ${a.statusText}). Check network tab for details.`)}let l=await a.json();if((!a.ok||"error"===l.status)&&"error"!==l.status)return{status:"error",message:l.error?.message||`Connection test failed: ${a.status} ${a.statusText}`};return l}catch(e){throw console.error("Model connection test error:",e),e}},e0=async(e,t)=>{try{console.log("entering keyInfoV1Call");let r=$?`${$}/key/info`:"/key/info";r=`${r}?key=${t}`;let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(console.log("response",n),!n.ok){let e=await n.text();j(e),g.default.fromBackend("Failed to fetch key info - "+e)}let o=await n.json();return console.log("data",o),o}catch(e){throw console.error("Failed to fetch key info:",e),e}},e1=async(e,t,r,n,o,a,i,l,s=null,c=null,u=null,d=null)=>{try{let f=$?`${$}/key/list`:"/key/list";console.log("in keyListCall");let p=new URLSearchParams;r&&p.append("team_id",r.toString()),t&&p.append("organization_id",t.toString()),n&&p.append("key_alias",n),a&&p.append("key_hash",a),o&&p.append("user_id",o.toString()),i&&p.append("page",i.toString()),l&&p.append("size",l.toString()),s&&p.append("sort_by",s),c&&p.append("sort_order",c),u&&p.append("expand",u),d&&p.append("status",d),p.append("return_full_object","true"),p.append("include_team_keys","true"),p.append("include_created_by_keys","true");let m=p.toString();m&&(f+=`?${m}`);let h=await fetch(f,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!h.ok){let e=await h.json(),t=nj(e);throw j(t),Error(t)}let g=await h.json();return console.log("/team/list API Response:",g),g}catch(e){throw console.error("Failed to create key:",e),e}},e2=async(e,t=1,r=50,n)=>{try{let o=new URLSearchParams(Object.entries({page:String(t),size:String(r),...n?{search:n}:{}})),a=$?`${$}/key/aliases`:"/key/aliases";a=`${a}?${o}`;let i=await fetch(a,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nj(e);throw j(t),Error(t)}let l=await i.json();return console.log("/key/aliases API Response:",l),l}catch(e){throw console.error("Failed to fetch key aliases:",e),e}},e4=async(e,t,r,n=null)=>{try{let o=$?`${$}/user/daily/activity/aggregated`:"/user/daily/activity/aggregated",a=new URLSearchParams,i=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${n}`};a.append("start_date",i(t)),a.append("end_date",i(r)),a.append("timezone",new Date().getTimezoneOffset().toString()),n&&a.append("user_id",n);let l=a.toString();l&&(o+=`?${l}`);let s=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nj(e);throw j(t),Error(t)}return await s.json()}catch(e){throw console.error("Failed to fetch aggregated user daily activity:",e),e}},e6=async e=>{try{let t=$?`${$}/user/available_roles`:"/user/available_roles",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("response from user/available_role",n),n}catch(e){throw e}},e3=async(e,t)=>{try{if(console.log("Form Values in teamCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let r=$?`${$}/team/new`:"/team/new",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},e7=async(e,t)=>{try{if(console.log("Form Values in credentialCreateCall:",t),t.metadata){console.log("formValues.metadata:",t.metadata);try{t.metadata=JSON.parse(t.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let r=$?`${$}/credentials`:"/credentials",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},e5=async e=>{try{let t=$?`${$}/credentials`:"/credentials";console.log("in credentialListCall");let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("/credentials API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},e9=async(e,t,r)=>{try{let n=$?`${$}/credentials`:"/credentials";t?n+=`/by_name/${t}`:r&&(n+=`/by_model/${r}`),console.log("in credentialListCall");let o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("/credentials API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},e8=async(e,t)=>{try{let r=$?`${$}/credentials/${t}`:`/credentials/${t}`;console.log("in credentialDeleteCall:",t);let n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log(o),o}catch(e){throw console.error("Failed to delete key:",e),e}},te=async(e,t,r)=>{try{if(console.log("Form Values in credentialUpdateCall:",r),r.metadata){console.log("formValues.metadata:",r.metadata);try{r.metadata=JSON.parse(r.metadata)}catch(e){throw Error("Failed to parse metadata: "+e)}}let n=$?`${$}/credentials/${t}`:`/credentials/${t}`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},tt=async(e,t)=>{try{if(console.log("Form Values in keyUpdateCall:",t),t.model_tpm_limit){console.log("formValues.model_tpm_limit:",t.model_tpm_limit);try{t.model_tpm_limit=JSON.parse(t.model_tpm_limit)}catch(e){throw Error("Failed to parse model_tpm_limit: "+e)}}if(t.model_rpm_limit){console.log("formValues.model_rpm_limit:",t.model_rpm_limit);try{t.model_rpm_limit=JSON.parse(t.model_rpm_limit)}catch(e){throw Error("Failed to parse model_rpm_limit: "+e)}}let r=$?`${$}/key/update`:"/key/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let o=await n.json();return console.log("Update key Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},tr=async(e,t)=>{try{console.log("Form Values in teamUpateCall:",t);let r=$?`${$}/team/update`:"/team/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),console.error("Error response from the server:",e),g.default.fromBackend("Failed to update team settings: "+e),Error(e)}let o=await n.json();return console.log("Update Team Response:",o),o}catch(e){throw console.error("Failed to update team:",e),e}},tn=async(e,t,r)=>{try{console.log("Form Values in modelUpateCall:",t);let n=$?`${$}/model/${r}/update`:`/model/${r}/update`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error update from the server:",e),Error("Network response was not ok")}let a=await o.json();return console.log("Update model Response:",a),a}catch(e){throw console.error("Failed to update model:",e),e}},to=async(e,t,r)=>{try{console.log("Form Values in teamMemberAddCall:",r);let n=$?`${$}/team/member_add`:"/team/member_add",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({team_id:t,member:r})});if(!o.ok){let e=await o.text(),t={};try{t=JSON.parse(e)}catch(t){console.warn("Failed to parse error body as JSON:",e)}let r=t?.detail?.error||"Failed to add team member",n=Error(r);throw n.raw=t,n}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},ta=async(e,t,r,n,o)=>{try{console.log("Bulk add team members:",{teamId:t,members:r,maxBudgetInTeam:n});let a=$?`${$}/team/bulk_member_add`:"/team/bulk_member_add",i={team_id:t};o?i.all_users=!0:i.members=r,null!=n&&(i.max_budget_in_team=n);let l=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!l.ok){let e=await l.text(),t={};try{t=JSON.parse(e)}catch(t){console.warn("Failed to parse error body as JSON:",e)}let r=t?.detail?.error||"Failed to bulk add team members",n=Error(r);throw n.raw=t,n}let s=await l.json();return console.log("Bulk team member add API Response:",s),s}catch(e){throw console.error("Failed to bulk add team members:",e),e}},ti=async(e,t,r)=>{try{console.log("Form Values in teamMemberUpdateCall:",r),console.log("Budget value:",r.max_budget_in_team),console.log("TPM limit:",r.tpm_limit),console.log("RPM limit:",r.rpm_limit);let n=$?`${$}/team/member_update`:"/team/member_update",o={team_id:t,role:r.role,user_id:r.user_id};void 0!==r.user_email&&(o.user_email=r.user_email),void 0!==r.max_budget_in_team&&null!==r.max_budget_in_team&&(o.max_budget_in_team=r.max_budget_in_team),void 0!==r.tpm_limit&&null!==r.tpm_limit&&(o.tpm_limit=r.tpm_limit),void 0!==r.rpm_limit&&null!==r.rpm_limit&&(o.rpm_limit=r.rpm_limit),console.log("Final request body:",o);let a=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(o)});if(!a.ok){let e=await a.text(),t={};try{t=JSON.parse(e)}catch(t){console.warn("Failed to parse error body as JSON:",e)}let r=t?.detail?.error||"Failed to add team member",n=Error(r);throw n.raw=t,n}let i=await a.json();return console.log("API Response:",i),i}catch(e){throw console.error("Failed to update team member:",e),e}},tl=async(e,t,r)=>{try{console.log("Form Values in teamMemberAddCall:",r);let n=$?`${$}/team/member_delete`:"/team/member_delete",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({team_id:t,...void 0!==r.user_email&&{user_email:r.user_email},...void 0!==r.user_id&&{user_id:r.user_id}})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create key:",e),e}},ts=async(e,t,r)=>{try{console.log("Form Values in teamMemberAddCall:",r);let n=$?`${$}/organization/member_add`:"/organization/member_add",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,member:r})});if(!o.ok){let e=await o.text();throw j(e),console.error("Error response from the server:",e),Error(e)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to create organization member:",e),e}},tc=async(e,t,r)=>{try{console.log("Form Values in organizationMemberDeleteCall:",r);let n=$?`${$}/organization/member_delete`:"/organization/member_delete",o=await fetch(n,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,user_id:r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to delete organization member:",e),e}},tu=async(e,t,r)=>{try{console.log("Form Values in organizationMemberUpdateCall:",r);let n=$?`${$}/organization/member_update`:"/organization/member_update",o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({organization_id:t,...r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("API Response:",a),a}catch(e){throw console.error("Failed to update organization member:",e),e}},td=async(e,t,r)=>{try{console.log("Form Values in userUpdateUserCall:",t);let n=$?`${$}/user/update`:"/user/update",o={...t};null!==r&&(o.user_role=r),o=JSON.stringify(o);let a=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:o});if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}let i=await a.json();return console.log("API Response:",i),i}catch(e){throw console.error("Failed to create key:",e),e}},tf=async(e,t,r,n=!1)=>{try{let o;console.log("Form Values in userUpdateUserCall:",t);let a=$?`${$}/user/bulk_update`:"/user/bulk_update";if(n)o=JSON.stringify({all_users:!0,user_updates:t});else if(r&&r.length>0){let e=[];for(let n of r)e.push({user_id:n,...t});o=JSON.stringify({users:e})}else throw Error("Must provide either userIds or set allUsers=true");let i=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:o});if(!i.ok){let e=await i.json(),t=nj(e);throw j(t),Error(t)}let l=await i.json();return console.log("API Response:",l),l}catch(e){throw console.error("Failed to create key:",e),e}},tp=async(e,t)=>{try{let r=$?`${$}/health/services?service=${t}`:`/health/services?service=${t}`;console.log("Checking Slack Budget Alerts service health");let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error(e)}return await n.json()}catch(e){throw console.error("Failed to perform health check:",e),e}},tm=async e=>{try{let t=$?`${$}/budget/list`:"/budget/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},th=async(e,t,r)=>{try{let t=$?`${$}/get/config/callbacks`:"/get/config/callbacks",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tg=async e=>{try{let t=$?`${$}/config/list?config_type=general_settings`:"/config/list?config_type=general_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tv=async e=>{try{let t=$?`${$}/router/settings`:"/router/settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get router settings:",e),e}},ty=async e=>{try{let t=$?`${$}/cache/settings`:"/cache/settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get cache settings:",e),e}},tb=async(e,t)=>{try{let r=$?`${$}/cache/settings/test`:"/cache/settings/test",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({cache_settings:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to test cache connection:",e),e}},tw=async(e,t)=>{try{let r=$?`${$}/cache/settings`:"/cache/settings",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({cache_settings:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to update cache settings:",e),e}},t$=async(e,t)=>{try{let r=$?`${$}/config/pass_through_endpoint`:"/config/pass_through_endpoint";t&&(r+=`/team/${t}`);let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tC=async(e,t)=>{try{let r=$?`${$}/config/field/info?field_name=${t}`:`/config/field/info?field_name=${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},tE=async(e,t)=>{try{let r=$?`${$}/config/pass_through_endpoint`:"/config/pass_through_endpoint",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},tS=async(e,t,r)=>{try{let n=$?`${$}/config/field/update`:"/config/field/update",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({field_name:t,field_value:r,config_type:"general_settings"})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return g.default.success("Successfully updated value!"),a}catch(e){throw console.error("Failed to set callbacks:",e),e}},tx=async(e,t)=>{try{let r=$?`${$}/config/field/delete`:"/config/field/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({field_name:t,config_type:"general_settings"})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return g.default.success("Field reset on proxy"),o}catch(e){throw console.error("Failed to get callbacks:",e),e}},tj=async(e,t)=>{try{let r=$?`${$}/config/pass_through_endpoint?endpoint_id=${t}`:`/config/pass_through_endpoint?endpoint_id=${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tO=async(e,t)=>{try{let r=$?`${$}/config/update`:"/config/update",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to set callbacks:",e),e}},tk=async(e,t)=>{try{let r=$?`${$}/health?model_id=${encodeURIComponent(t)}`:`/health?model_id=${encodeURIComponent(t)}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error(`Failed to call /health for model id ${t}:`,e),e}},tT=async e=>{try{let t=$?`${$}/cache/ping`:"/cache/ping",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error(e)}return await r.json()}catch(e){throw console.error("Failed to call /cache/ping:",e),e}},tF=async e=>{try{let t=$?`${$}/health/latest`:"/health/latest",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error(e)}return await r.json()}catch(e){throw console.error("Failed to call /health/latest:",e),e}},t_=async e=>{try{console.log("Getting proxy UI settings"),console.log("proxyBaseUrl in getProxyUISettings:",$);let t=$?`${$}/sso/get/ui_settings`:"/sso/get/ui_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get callbacks:",e),e}},tI=async e=>{try{let t=$?`${$}/get/ui_settings`:"/get/ui_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);return console.error("Failed to get UI settings:",t),null}return await r.json()}catch(e){return console.error("Failed to get UI settings:",e),null}},tP=async e=>{try{let t=$?`${$}/get/mcp_semantic_filter_settings`:"/get/mcp_semantic_filter_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get MCP semantic filter settings:",e),e}},tN=async(e,t)=>{try{let r=$?`${$}/update/mcp_semantic_filter_settings`:"/update/mcp_semantic_filter_settings",n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to update MCP semantic filter settings:",e),e}},tR=async(e,t,r)=>{try{let n=$?`${$}/v1/responses`:"/v1/responses",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({model:t,input:[{role:"user",content:r,type:"message"}],tools:[{type:"mcp",server_url:"litellm_proxy",require_approval:"never"}],tool_choice:"required"})}),a=o.headers.get("x-litellm-semantic-filter"),i=o.headers.get("x-litellm-semantic-filter-tools");if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return{data:await o.json(),headers:{filter:a,tools:i}}}catch(e){throw console.error("Failed to test MCP semantic filter:",e),e}},tM=async e=>{try{let t=$?`${$}/v2/guardrails/list`:"/v2/guardrails/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok)throw Error(`v2 guardrails/list returned ${r.status}`);return await r.json()}catch(t){console.log("v2/guardrails/list failed, falling back to v1:",t);try{let t=$?`${$}/guardrails/list`:"/guardrails/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get guardrails list:",e),e}}},tB=async(e,t)=>{let r=$?`${$}/guardrails/submissions`:"/guardrails/submissions",n=new URLSearchParams;t?.status&&n.set("status",t.status),t?.team_id&&n.set("team_id",t.team_id),t?.team_guardrail!==void 0&&n.set("team_guardrail",String(t.team_guardrail)),t?.search&&n.set("search",t.search);let o=n.toString()?`${r}?${n.toString()}`:r,a=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=nj(await a.json().catch(()=>({})));throw j(e),Error(e)}return a.json()},tA=async(e,t)=>{let r=$?`${$}/guardrails/submissions/${encodeURIComponent(t)}/approve`:`/guardrails/submissions/${encodeURIComponent(t)}/approve`,n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=nj(await n.json().catch(()=>({})));throw j(e),Error(e)}return n.json()},tz=async(e,t)=>{let r=$?`${$}/guardrails/submissions/${encodeURIComponent(t)}/reject`:`/guardrails/submissions/${encodeURIComponent(t)}/reject`,n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=nj(await n.json().catch(()=>({})));throw j(e),Error(e)}return n.json()},tL=async(e,t,r)=>{try{let n=$?`${$}/guardrails/usage/overview`:"/guardrails/usage/overview",o=new URLSearchParams;t&&o.append("start_date",t),r&&o.append("end_date",r),o.toString()&&(n+=`?${o.toString()}`);let a=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json();throw Error(nj(e))}return a.json()}catch(e){throw console.error("Failed to get guardrails usage overview:",e),e}},tH=async(e,t,r,n)=>{try{let o=$?`${$}/guardrails/usage/detail/${encodeURIComponent(t)}`:`/guardrails/usage/detail/${encodeURIComponent(t)}`,a=new URLSearchParams;r&&a.append("start_date",r),n&&a.append("end_date",n),a.toString()&&(o+=`?${a.toString()}`);let i=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json();throw Error(nj(e))}return i.json()}catch(e){throw console.error("Failed to get guardrails usage detail:",e),e}},tD=async(e,t)=>{try{let r=$?`${$}/guardrails/usage/logs`:"/guardrails/usage/logs",n=new URLSearchParams;t.guardrailId&&n.append("guardrail_id",t.guardrailId),t.policyId&&n.append("policy_id",t.policyId),null!=t.page&&n.append("page",String(t.page)),null!=t.pageSize&&n.append("page_size",String(t.pageSize)),t.action&&n.append("action",t.action),t.startDate&&n.append("start_date",t.startDate),t.endDate&&n.append("end_date",t.endDate),n.toString()&&(r+=`?${n.toString()}`);let o=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json();throw Error(nj(e))}return o.json()}catch(e){throw console.error("Failed to get guardrails usage logs:",e),e}},tV=async e=>{try{let t=$?`${$}/policies/list`:"/policies/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get policies list:",e),e}},tW=async(e,t,r)=>{try{let n=$?`${$}/utils/test_policies_and_guardrails`:"/utils/test_policies_and_guardrails",o=await fetch(n,{method:"POST",signal:r,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({policy_names:t.policy_names??null,guardrail_names:t.guardrail_names??null,inputs:t.inputs??null,inputs_list:t.inputs_list??null,request_data:t.request_data??{},input_type:t.input_type??"request",agent_id:t.agent_id??null})});if(!o.ok){let e=await o.text(),t="Failed to test policies and guardrails";try{let r=JSON.parse(e);r.detail?t="string"==typeof r.detail?r.detail:JSON.stringify(r.detail):r.message&&(t=r.message)}catch{t=e||t}throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to test policies and guardrails:",e),e}},tG=async(e,t)=>{try{let r=$?`${$}/policy/info/${t}`:`/policy/info/${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error(`Failed to get policy info for ${t}:`,e),e}},tU=async e=>{try{let t=$?`${$}/policy/templates`:"/policy/templates",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get policy templates:",e),e}},tq=async(e,t,r,n,o)=>{try{let a=$?`${$}/policy/templates/enrich`:"/policy/templates/enrich",i={template_id:t,parameters:r};n&&(i.model=n),o&&(i.competitors=o);let l=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!l.ok){let e=await l.json(),t=nj(e);throw j(t),Error(t)}return await l.json()}catch(e){throw console.error("Failed to enrich policy template:",e),e}},tJ=async(e,t,r,n)=>{try{let o=$?`${$}/policy/templates/suggest`:"/policy/templates/suggest",a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({attack_examples:t.filter(e=>e.trim()),description:r,model:n})});if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}return a.json()}catch(e){throw console.error("Failed to suggest policy templates:",e),e}},tK=async(e,t,r)=>{try{let n=$?`${$}/policy/templates/test`:"/policy/templates/test",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({guardrail_definitions:t,text:r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return o.json()}catch(e){throw console.error("Failed to test policy template:",e),e}},tX=async(e,t,r,n,o,a,i,l,s)=>{let c=$?`${$}/policy/templates/enrich/stream`:"/policy/templates/enrich/stream",u={template_id:t,parameters:r,model:n};l?.instruction&&(u.instruction=l.instruction),l?.existingCompetitors&&(u.competitors=l.existingCompetitors);let d=await fetch(c,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(u)});if(!d.ok){let e=nj(await d.json());throw j(e),Error(e)}let f=d.body?.getReader();if(!f)throw Error("No response body");let p=new TextDecoder,m="";for(;;){let{done:e,value:t}=await f.read();if(e)break;let r=(m+=p.decode(t,{stream:!0})).split("\n");for(let e of(m=r.pop()||"",r))if(e.startsWith("data: "))try{let t=JSON.parse(e.slice(6));"competitor"===t.type?o(t.name):"status"===t.type?s?.(t.message):"done"===t.type?a(t):"error"===t.type&&i?.(t.message)}catch{}}},tY=async(e,t,r,n,o,a,i,l,s)=>{let c=$?`${$}/usage/ai/chat`:"/usage/ai/chat",u=await fetch(c,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({messages:t,model:r}),signal:s});if(!u.ok){let e=nj(await u.json());throw j(e),Error(e)}let d=u.body?.getReader();if(!d)throw Error("No response body");let f=new TextDecoder,p="";for(;;){let{done:e,value:t}=await d.read();if(e)break;let r=(p+=f.decode(t,{stream:!0})).split("\n");for(let e of(p=r.pop()||"",r))if(e.startsWith("data: "))try{let t=JSON.parse(e.slice(6));"chunk"===t.type?n(t.content):"status"===t.type?i?.(t.message):"tool_call"===t.type?l?.(t):"done"===t.type?o():"error"===t.type&&a?.(t.message)}catch{}}},tZ=async(e,t)=>{try{let r=$?`${$}/policies`:"/policies",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create policy:",e),e}},tQ=async(e,t,r)=>{try{let n=$?`${$}/policies/${t}`:`/policies/${t}`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update policy:",e),e}},t0=async(e,t)=>{try{let r=encodeURIComponent(t),n=$?`${$}/policies/name/${r}/versions`:`/policies/name/${r}/versions`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to list policy versions:",e),e}},t1=async(e,t,r)=>{try{let n=encodeURIComponent(t),o=$?`${$}/policies/name/${n}/versions`:`/policies/name/${n}/versions`,a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({source_policy_id:r??void 0})});if(!a.ok){let e=await a.json(),t=nj(e);throw j(t),Error(t)}return await a.json()}catch(e){throw console.error("Failed to create policy version:",e),e}},t2=async(e,t,r)=>{try{let n=$?`${$}/policies/${t}/status`:`/policies/${t}/status`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({version_status:r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update policy version status:",e),e}},t4=async(e,t)=>{try{let r=$?`${$}/policies/${t}`:`/policies/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete policy:",e),e}},t6=async(e,t)=>{try{let r=$?`${$}/policies/${t}`:`/policies/${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get policy info:",e),e}},t3=async e=>{try{let t=$?`${$}/policies/attachments/list`:"/policies/attachments/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get policy attachments list:",e),e}},t7=async(e,t)=>{try{let r=$?`${$}/policies/attachments`:"/policies/attachments",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create policy attachment:",e),e}},t5=async(e,t)=>{try{let r=$?`${$}/policies/attachments/${t}`:`/policies/attachments/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete policy attachment:",e),e}},t9=async(e,t,r)=>{try{let n=$?`${$}/policies/test-pipeline`:"/policies/test-pipeline",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({pipeline:t,test_messages:r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to test pipeline:",e),e}},t8=async(e,t)=>{try{let r=$?`${$}/policies/${t}/resolved-guardrails`:`/policies/${t}/resolved-guardrails`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get resolved guardrails:",e),e}},re=async(e,t)=>{try{let r=$?`${$}/policies/resolve`:"/policies/resolve",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to resolve policies:",e),e}},rt=async(e,t)=>{try{let r=$?`${$}/policies/attachments/estimate-impact`:"/policies/attachments/estimate-impact",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to estimate attachment impact:",e),e}},rr=async e=>{try{let t=$?`${$}/prompts/list`:"/prompts/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to get prompts list:",e),e}},rn=async(e,t)=>{try{let r=$?`${$}/prompts/${t}/info`:`/prompts/${t}/info`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get prompt info:",e),e}},ro=async(e,t)=>{try{let r=$?`${$}/prompts/${t}/versions`:`/prompts/${t}/versions`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw 404!==n.status&&j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to get prompt versions:",e),e}},ra=async(e,t)=>{try{let r=$?`${$}/prompts`:"/prompts",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to create prompt:",e),e}},ri=async(e,t,r)=>{try{let n=$?`${$}/prompts/${t}`:`/prompts/${t}`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to update prompt:",e),e}},rl=async(e,t)=>{try{let r=$?`${$}/prompts/${t}`:`/prompts/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete prompt:",e),e}},rs=async(e,t)=>{try{let r=new FormData;r.append("file",t);let n=$?`${$}/utils/dotprompt_json_converter`:"/utils/dotprompt_json_converter",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`},body:r});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to convert prompt file:",e),e}},rc=async(e,t)=>{try{let r=$?`${$}/v1/agents`:"/v1/agents",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Create agent response:",o),o}catch(e){throw console.error("Failed to create agent:",e),e}},ru=async(e,t)=>{try{let r=$?`${$}/guardrails`:"/guardrails",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({guardrail:t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Create guardrail response:",o),o}catch(e){throw console.error("Failed to create guardrail:",e),e}},rd=async(e,t,r)=>{try{let n=$?`${$}/spend/logs/ui/${t}?start_date=${encodeURIComponent(r)}`:`/spend/logs/ui/${t}?start_date=${encodeURIComponent(r)}`;console.log("Fetching log details from:",n);let o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("Fetched log details:",a),a}catch(e){throw console.error("Failed to fetch log details:",e),e}},rf=async e=>{try{let t=$?`${$}/get/internal_user_settings`:"/get/internal_user_settings";console.log("Fetching SSO settings from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched SSO settings:",n),n}catch(e){throw console.error("Failed to fetch SSO settings:",e),e}},rp=async(e,t)=>{try{let r=$?`${$}/update/internal_user_settings`:"/update/internal_user_settings";console.log("Updating internal user settings:",t);let n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Updated internal user settings:",o),g.default.success("Internal user settings updated successfully"),o}catch(e){throw console.error("Failed to update internal user settings:",e),e}},rm=async e=>{try{let t=$?`${$}/v1/mcp/openapi-registry`:"/v1/mcp/openapi-registry",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json();throw Error(nj(e))}return await r.json()}catch(e){throw console.error("Failed to fetch OpenAPI registry:",e),e}},rh=async e=>{try{let t=$?`${$}/v1/mcp/discover`:"/v1/mcp/discover",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to fetch discoverable MCP servers:",e),e}},rg=async(e,t)=>{try{let r=$?`${$}/v1/mcp/server`:"/v1/mcp/server";if(t){let e=new URLSearchParams;e.append("team_id",t),r=`${r}?${e.toString()}`}console.log("Fetching MCP servers from:",r);let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Fetched MCP servers:",o),o}catch(e){throw console.error("Failed to fetch MCP servers:",e),e}},rv=async(e,t)=>{try{let r=$?`${$}/v1/mcp/server/health`:"/v1/mcp/server/health";if(t&&t.length>0){let e=new URLSearchParams;t.forEach(t=>e.append("server_ids",t)),r=`${r}?${e.toString()}`}console.log("Fetching MCP server health from:",r);let n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Fetched MCP server health:",o),o}catch(e){throw console.error("Failed to fetch MCP server health:",e),e}},ry=async e=>{try{let t=$?`${$}/v1/mcp/access_groups`:"/v1/mcp/access_groups";console.log("Fetching MCP access groups from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched MCP access groups:",n),n.access_groups||[]}catch(e){throw console.error("Failed to fetch MCP access groups:",e),e}},rb=async e=>{try{let t=$?`${$}/v1/mcp/network/client-ip`:"/v1/mcp/network/client-ip",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok)return null;return(await r.json()).ip||null}catch{return null}},rw=async(e,t)=>{try{console.log("Form Values in createMCPServer:",t);let r=$?`${$}/v1/mcp/server`:"/v1/mcp/server",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("API Response:",o),o}catch(e){throw console.error("Failed to create key:",e),e}},r$=async(e,t)=>{try{let r=$?`${$}/v1/mcp/server`:"/v1/mcp/server",n=await fetch(r,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to update MCP server:",e),e}},rC=async(e,t)=>{try{let r=($?`${$}`:"")+`/v1/mcp/server/${t}`;console.log("in deleteMCPServer:",t);let n=await fetch(r,{method:S,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}}catch(e){throw console.error("Failed to delete key:",e),e}},rE=async(e,t)=>{try{let r=($?`${$}`:"")+"/v1/mcp/server/register",n=await fetch(r,{method:E,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return n.json()}catch(e){throw console.error("Failed to register MCP server:",e),e}},rS=async e=>{try{let t=($?`${$}`:"")+"/v1/mcp/server/submissions",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json().catch(()=>({})),t=nj(e);throw j(t),Error(t)}return r.json()}catch(e){throw console.error("Failed to fetch MCP submissions:",e),e}},rx=async(e,t)=>{try{let r=($?`${$}`:"")+`/v1/mcp/server/${encodeURIComponent(t)}/approve`,n=await fetch(r,{method:"PUT",headers:{[T]:`Bearer ${e}`}});if(!n.ok){let e=await n.json().catch(()=>({})),t=nj(e);throw j(t),Error(t)}return n.json()}catch(e){throw console.error("Failed to approve MCP server:",e),e}},rj=async(e,t,r)=>{try{let n=($?`${$}`:"")+`/v1/mcp/server/${encodeURIComponent(t)}/reject`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({review_notes:r??null})});if(!o.ok){let e=await o.json().catch(()=>({})),t=nj(e);throw j(t),Error(t)}return o.json()}catch(e){throw console.error("Failed to reject MCP server:",e),e}},rO=async e=>{try{let t=$?`${$}/search_tools/list`:"/search_tools/list";console.log("Fetching search tools from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched search tools:",n),n}catch(e){throw console.error("Failed to fetch search tools:",e),e}},rk=async(e,t)=>{try{console.log("Creating search tool with values:",t);let r=$?`${$}/search_tools`:"/search_tools",n=await fetch(r,{method:E,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({search_tool:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Created search tool:",o),o}catch(e){throw console.error("Failed to create search tool:",e),e}},rT=async(e,t,r)=>{try{console.log("Updating search tool with ID:",t,"values:",r);let n=$?`${$}/search_tools/${t}`:`/search_tools/${t}`,o=await fetch(n,{method:"PUT",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({search_tool:r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("Updated search tool:",a),a}catch(e){throw console.error("Failed to update search tool:",e),e}},rF=async(e,t)=>{try{let r=($?`${$}`:"")+`/search_tools/${t}`;console.log("Deleting search tool:",t);let n=await fetch(r,{method:S,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Deleted search tool:",o),o}catch(e){throw console.error("Failed to delete search tool:",e),e}},r_=async e=>{try{let t=$?`${$}/search_tools/ui/available_providers`:"/search_tools/ui/available_providers";console.log("Fetching available search providers from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched available search providers:",n),n}catch(e){throw console.error("Failed to fetch available search providers:",e),e}},rI=async(e,t)=>{try{let r=$?`${$}/search_tools/test_connection`:"/search_tools/test_connection";console.log("Testing search tool connection:",r);let n=await fetch(r,{method:E,headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({litellm_params:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Test connection response:",o),o}catch(e){throw console.error("Failed to test search tool connection:",e),e}},rP=async(e,t,r)=>{try{let n=$?`${$}/mcp-rest/tools/list?server_id=${t}`:`/mcp-rest/tools/list?server_id=${t}`;console.log("Fetching MCP tools from:",n);let o={[T]:`Bearer ${e}`,"Content-Type":"application/json",...r},a=await fetch(n,{method:"GET",headers:o}),i=await a.json();if(console.log("Fetched MCP tools response:",i),!a.ok){if(i.error&&i.message)throw Error(i.message);throw Error("Failed to fetch MCP tools")}return i}catch(e){return console.error("Failed to fetch MCP tools:",e),{tools:[],error:"network_error",message:e instanceof Error?e.message:"Failed to fetch MCP tools",stack_trace:null}}},rN=async(e,t,r,n,o)=>{try{let a=$?`${$}/mcp-rest/tools/call`:"/mcp-rest/tools/call";console.log("Calling MCP tool:",r,"with arguments:",n,"for server:",t);let i={[T]:`Bearer ${e}`,"Content-Type":"application/json",...o?.customHeaders||{}},l={server_id:t,name:r,arguments:n};o?.guardrails&&o.guardrails.length>0&&(l.litellm_metadata={guardrails:o.guardrails});let s=await fetch(a,{method:"POST",headers:i,body:JSON.stringify(l)});if(!s.ok){let e="Network response was not ok",t=null,r=await s.text();try{let n=JSON.parse(r);n.detail?"string"==typeof n.detail?e=n.detail:"object"==typeof n.detail&&(e=n.detail.message||n.detail.error||"An error occurred",t=n.detail):e=n.message||n.error||e}catch(t){console.error("Failed to parse JSON error response:",t),r&&(e=r)}let n=Error(e);throw n.status=s.status,n.statusText=s.statusText,n.details=t,j(e),n}let c=await s.json();return console.log("MCP tool call response:",c),c}catch(e){throw console.error("Failed to call MCP tool:",e),console.error("Error type:",typeof e),e instanceof Error&&(console.error("Error message:",e.message),console.error("Error stack:",e.stack)),e}},rR=async(e,t)=>{try{let r=$?`${$}/tag/new`:"/tag/new",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();await j(e);return}return await n.json()}catch(e){throw console.error("Error creating tag:",e),e}},rM=async(e,t)=>{try{let r=$?`${$}/tag/update`:"/tag/update",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();await j(e);return}return await n.json()}catch(e){throw console.error("Error updating tag:",e),e}},rB=async(e,t)=>{try{let r=$?`${$}/tag/info`:"/tag/info",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({names:t})});if(!n.ok){let e=await n.text();return await j(e),{}}return await n.json()}catch(e){throw console.error("Error getting tag info:",e),e}},rA=async e=>{try{let t=$?`${$}/tag/list`:"/tag/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok){let e=await r.text();return await j(e),{}}return await r.json()}catch(e){throw console.error("Error listing tags:",e),e}},rz=async(e,t)=>{try{let r=$?`${$}/tag/delete`:"/tag/delete",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({name:t})});if(!n.ok){let e=await n.text();await j(e);return}return await n.json()}catch(e){throw console.error("Error deleting tag:",e),e}},rL=async e=>{try{let t=$?`${$}/get/default_team_settings`:"/get/default_team_settings";console.log("Fetching default team settings from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched default team settings:",n),n}catch(e){throw console.error("Failed to fetch default team settings:",e),e}},rH=async(e,t)=>{try{let r=$?`${$}/update/default_team_settings`:"/update/default_team_settings";console.log("Updating default team settings:",t);let n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Updated default team settings:",o),g.default.success("Default team settings updated successfully"),o}catch(e){throw console.error("Failed to update default team settings:",e),e}},rD=async(e,t)=>{try{let r=$?`${$}/team/permissions_list?team_id=${t}`:`/team/permissions_list?team_id=${t}`,n=await fetch(r,{method:"GET",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}let o=await n.json();return console.log("Team permissions response:",o),o}catch(e){throw console.error("Failed to get team permissions:",e),e}},rV=async(e,t,r)=>{try{let n=$?`${$}/team/permissions_update`:"/team/permissions_update",o=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({team_id:t,team_member_permissions:r})});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return console.log("Team permissions response:",a),a}catch(e){throw console.error("Failed to update team permissions:",e),e}},rW=async(e,t)=>{try{let r=$?`${$}/spend/logs/session/ui?session_id=${encodeURIComponent(t)}`:`/spend/logs/session/ui?session_id=${encodeURIComponent(t)}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to fetch session logs:",e),e}},rG=async(e,t)=>{try{let r=$?`${$}/vector_store/new`:"/vector_store/new",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to create vector store")}return await n.json()}catch(e){throw console.error("Error creating vector store:",e),e}},rU=async(e,t=1,r=100)=>{try{let t=$?`${$}/vector_store/list`:"/vector_store/list",r=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`}});if(!r.ok){let e=await r.json();throw Error(e.detail||"Failed to list vector stores")}return await r.json()}catch(e){throw console.error("Error listing vector stores:",e),e}},rq=async(e,t)=>{try{let r=$?`${$}/vector_store/delete`:"/vector_store/delete",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({vector_store_id:t})});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to delete vector store")}return await n.json()}catch(e){throw console.error("Error deleting vector store:",e),e}},rJ=async(e,t)=>{try{let r=$?`${$}/vector_store/info`:"/vector_store/info",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify({vector_store_id:t})});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to get vector store info")}return await n.json()}catch(e){throw console.error("Error getting vector store info:",e),e}},rK=async(e,t)=>{try{let r=$?`${$}/vector_store/update`:"/vector_store/update",n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",[T]:`Bearer ${e}`},body:JSON.stringify(t)});if(!n.ok){let e=await n.json();throw Error(e.detail||"Failed to update vector store")}return await n.json()}catch(e){throw console.error("Error updating vector store:",e),e}},rX=async(e,t,r,n,o,a,i)=>{try{let l=$?`${$}/rag/ingest`:"/rag/ingest",s=new FormData;s.append("file",t);let c={ingest_options:{vector_store:{custom_llm_provider:r,...n&&{vector_store_id:n},...i&&i}}};(o||a)&&(c.ingest_options.litellm_vector_store_params={},o&&(c.ingest_options.litellm_vector_store_params.vector_store_name=o),a&&(c.ingest_options.litellm_vector_store_params.vector_store_description=a)),s.append("request",JSON.stringify(c));let u=await fetch(l,{method:"POST",headers:{[T]:`Bearer ${e}`},body:s});if(!u.ok){let e=await u.json();throw Error(e.error?.message||e.detail||"Failed to ingest document")}return await u.json()}catch(e){throw console.error("Error ingesting document:",e),e}},rY=async e=>{try{let t=$?`${$}/email/event_settings`:"/email/event_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to get email event settings")}let n=await r.json();return console.log("Email event settings response:",n),n}catch(e){throw console.error("Failed to get email event settings:",e),e}},rZ=async(e,t)=>{try{let r=$?`${$}/email/event_settings`:"/email/event_settings",n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to update email event settings")}let o=await n.json();return console.log("Update email event settings response:",o),o}catch(e){throw console.error("Failed to update email event settings:",e),e}},rQ=async e=>{try{let t=$?`${$}/email/event_settings/reset`:"/email/event_settings/reset",r=await fetch(t,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to reset email event settings")}let n=await r.json();return console.log("Reset email event settings response:",n),n}catch(e){throw console.error("Failed to reset email event settings:",e),e}},r0=async(e,t)=>{try{let r=$?`${$}/v1/agents/${t}`:`/v1/agents/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Delete agent response:",o),o}catch(e){throw console.error("Failed to delete agent:",e),e}},r1=async(e,t)=>{try{let r=$?`${$}/v1/agents/make_public`:"/v1/agents/make_public",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({agent_ids:t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Make agents public response:",o),o}catch(e){throw console.error("Failed to make agents public:",e),e}},r2=async(e,t)=>{try{let r=$?`${$}/v1/mcp/make_public`:"/v1/mcp/make_public",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({mcp_server_ids:t})});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Make agents public response:",o),o}catch(e){throw console.error("Failed to make agents public:",e),e}},r4=async(e,t)=>{try{let r=$?`${$}/guardrails/${t}`:`/guardrails/${t}`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error(e)}let o=await n.json();return console.log("Delete guardrail response:",o),o}catch(e){throw console.error("Failed to delete guardrail:",e),e}},r6=async e=>{try{let t=$?`${$}/guardrails/ui/add_guardrail_settings`:"/guardrails/ui/add_guardrail_settings",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to get guardrail UI settings")}let n=await r.json();return console.log("Guardrail UI settings response:",n),n}catch(e){throw console.error("Failed to get guardrail UI settings:",e),e}},r3=async e=>{try{let t=$?`${$}/guardrails/ui/provider_specific_params`:"/guardrails/ui/provider_specific_params",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw j(e),Error("Failed to get guardrail provider specific parameters")}let n=await r.json();return console.log("Guardrail provider specific params response:",n),n}catch(e){throw console.error("Failed to get guardrail provider specific parameters:",e),e}},r7=async(e,t)=>{try{let r=encodeURIComponent(t),n=$?`${$}/guardrails/ui/category_yaml/${r}`:`/guardrails/ui/category_yaml/${r}`;console.log(`Fetching category YAML from: ${n}`);let o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw console.error(`Failed to get category YAML. Status: ${o.status}, Error:`,e),j(e),Error(`Failed to get category YAML: ${o.status} ${e}`)}let a=await o.json();return console.log("Category YAML response:",a),a}catch(e){throw console.error("Failed to get category YAML:",e),e}},r5=async e=>{try{let t=$?`${$}/guardrails/ui/major_airlines`:"/guardrails/ui/major_airlines",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw console.error(`Failed to get major airlines. Status: ${r.status}, Error:`,e),j(e),Error(`Failed to get major airlines: ${r.status} ${e}`)}return await r.json()}catch(e){throw console.error("Failed to get major airlines:",e),e}},r9=async(e,t=!1)=>{try{let r=t?"?health_check=true":"",n=$?`${$}/v1/agents${r}`:`/v1/agents${r}`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text();throw j(e),Error("Failed to get agents list")}let a=await o.json();return console.log("Agents list response:",a),{agents:a}}catch(e){throw console.error("Failed to get agents list:",e),e}},r8=async(e,t)=>{try{let r=$?`${$}/v1/agents/${t}`:`/v1/agents/${t}`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to get agent info")}let o=await n.json();return console.log("Agent info response:",o),o}catch(e){throw console.error("Failed to get agent info:",e),e}},ne=async(e,t)=>{try{let r=$?`${$}/guardrails/${t}/info`:`/guardrails/${t}/info`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to get guardrail info")}let o=await n.json();return console.log("Guardrail info response:",o),o}catch(e){throw console.error("Failed to get guardrail info:",e),e}},nt=async(e,t,r)=>{try{let n=$?`${$}/v1/agents/${t}`:`/v1/agents/${t}`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.text();throw j(e),Error("Failed to patch agent")}let a=await o.json();return console.log("Patch agent response:",a),a}catch(e){throw console.error("Failed to update guardrail:",e),e}},nr=async(e,t,r)=>{try{let n=$?`${$}/guardrails/${t}`:`/guardrails/${t}`,o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.text();throw j(e),Error("Failed to update guardrail")}let a=await o.json();return console.log("Update guardrail response:",a),a}catch(e){throw console.error("Failed to update guardrail:",e),e}},nn=async(e,t,r,n,o)=>{try{let a=$?`${$}/guardrails/apply_guardrail`:"/guardrails/apply_guardrail",i={guardrail_name:t,text:r};n&&(i.language=n),o&&o.length>0&&(i.entities=o);let l=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i)});if(!l.ok){let e=await l.text(),t="Failed to apply guardrail";try{let r=JSON.parse(e);r.error?.message?t=r.error.message:r.detail?t=r.detail:r.message&&(t=r.message)}catch(r){t=e||t}throw j(e),Error(t)}let s=await l.json();return console.log("Apply guardrail response:",s),s}catch(e){throw console.error("Failed to apply guardrail:",e),e}},no=async(e,t)=>{try{let r=$?`${$}/guardrails/test_custom_code`:"/guardrails/test_custom_code",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.text(),t="Failed to test custom code guardrail";try{let r=JSON.parse(e);r.error?.message?t=r.error.message:r.detail?t=r.detail:r.message&&(t=r.message)}catch(r){t=e||t}throw j(e),Error(t)}let o=await n.json();return console.log("Test custom code guardrail response:",o),o}catch(e){throw console.error("Failed to test custom code guardrail:",e),e}},na=async(e,t)=>{try{let r=$?`${$}/guardrails/validate_blocked_words_file`:"/guardrails/validate_blocked_words_file",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({file_content:t})});if(!n.ok){let e=await n.text();throw j(e),Error("Failed to validate blocked words file")}let o=await n.json();return console.log("Validate blocked words file response:",o),o}catch(e){throw console.error("Failed to validate blocked words file:",e),e}},ni=async e=>{try{let t=$?`${$}/get/sso_settings`:"/get/sso_settings";console.log("Fetching SSO configuration from:",t);let r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}let n=await r.json();return console.log("Fetched SSO configuration:",n),n}catch(e){throw console.error("Failed to fetch SSO configuration:",e),e}},nl=async(e,t)=>{try{let r=$?`${$}/update/sso_settings`:"/update/sso_settings";console.log("Updating SSO configuration:",t);let n=await fetch(r,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let e=await n.json(),t="object"==typeof e?.detail?e.detail?.error||e.detail?.message:e?.detail,r="string"==typeof t&&t.length>0?t:nj(e);j(r);let o=Error(r);throw e?.detail!==void 0&&(o.detail=e.detail),o.rawError=e,o}let o=await n.json();return console.log("Updated SSO configuration:",o),o}catch(e){throw console.error("Failed to update SSO configuration:",e),e}},ns=async({accessToken:e,page:t=1,page_size:r=50,params:n={}})=>{try{let o=$?`${$}/audit`:"/audit",a=new URLSearchParams;for(let[e,o]of(a.append("page",t.toString()),a.append("page_size",r.toString()),Object.entries(n)))null!=o&&""!==o&&a.append(e,String(o));o+=`?${a.toString()}`;let i=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!i.ok){let e=await i.json(),t=nj(e);throw j(t),Error(t)}return await i.json()}catch(e){throw console.error("Failed to fetch audit logs:",e),e}},nc=async e=>{try{let t=$?`${$}/user/available_users`:"/user/available_users",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok){if(404===r.status)return null;let e=await r.text();throw j(e),Error("Network response was not ok")}return await r.json()}catch(e){throw console.error("Failed to fetch remaining users:",e),e}},nu=async e=>{try{let t=$?`${$}/health/license`:"/health/license",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});if(!r.ok){if(404===r.status)return null;let e=await r.text();throw j(e),Error("Network response was not ok")}return await r.json()}catch(e){throw console.error("Failed to fetch license info:",e),e}},nd=async(e,t,r)=>{try{let n=$?`${$}/config/pass_through_endpoint/${encodeURIComponent(t)}`:`/config/pass_through_endpoint/${encodeURIComponent(t)}`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json(),t=nj(e);throw j(t),Error(t)}let a=await o.json();return g.default.success("Pass through endpoint updated successfully"),a}catch(e){throw console.error("Failed to update pass through endpoint:",e),e}},nf=async(e,t)=>{try{let r=$?`${$}/config/callback/delete`:"/config/callback/delete",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({callback_name:t})});if(!n.ok){let e=await n.json(),t=nj(e);throw j(t),Error(t)}return await n.json()}catch(e){throw console.error("Failed to delete specific callback:",e),e}},np=async(e,t,r)=>{try{console.log("Testing MCP tools list with config:",JSON.stringify(t));let n=$?`${$}/mcp-rest/test/tools/list`:"/mcp-rest/test/tools/list",o={"Content-Type":"application/json"};e&&(o["x-litellm-api-key"]=e),r?o.Authorization=`Bearer ${r}`:e&&(o[T]=`Bearer ${e}`);let a=await fetch(n,{method:"POST",headers:o,body:JSON.stringify(t)}),i=a.headers.get("content-type");if(!i||!i.includes("application/json")){let e=await a.text();throw console.error("Received non-JSON response:",e),Error(`Received non-JSON response (${a.status}: ${a.statusText}). Check network tab for details.`)}let l=await a.json();if((!a.ok||l.error)&&!l.error)return{tools:[],error:"request_failed",message:l.message||`MCP tools list failed: ${a.status} ${a.statusText}`};return l}catch(e){throw console.error("MCP tools list test error:",e),e}},nm=async(e,t)=>{let r=$?`${$}/v1/mcp/server/oauth/session`:"/v1/mcp/server/oauth/session",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)}),o=await n.json();if(!n.ok)throw Error(nj(o)||o?.error||"Failed to cache MCP server");return o},nh=async(e,t,r)=>{let n=C(),o=encodeURIComponent(t.trim()),a=`${n}/v1/mcp/server/oauth/${o}/register`,i=await fetch(a,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json",Accept:"application/json, text/event-stream"},body:JSON.stringify(r)}),l=await i.json();if(!i.ok)throw Error(nj(l)||l?.detail||"Failed to register OAuth client");return l},ng=({serverId:e,clientId:t,redirectUri:r,state:n,codeChallenge:o,scope:a})=>{let i=C(),l=encodeURIComponent(e.trim()),s=`${i}/v1/mcp/server/oauth/${l}/authorize`,c=new URLSearchParams({redirect_uri:r,state:n,response_type:"code",code_challenge:o,code_challenge_method:"S256"});return t&&t.trim().length>0&&c.set("client_id",t),a&&a.trim().length>0&&c.set("scope",a),`${s}?${c.toString()}`},nv=async({serverId:e,code:t,clientId:r,clientSecret:n,codeVerifier:o,redirectUri:a})=>{let i=C(),l=encodeURIComponent(e.trim()),s=`${i}/v1/mcp/server/oauth/${l}/token`,c=new URLSearchParams;c.set("grant_type","authorization_code"),c.set("code",t),r&&r.trim().length>0&&c.set("client_id",r),n&&n.trim().length>0&&c.set("client_secret",n),c.set("code_verifier",o),c.set("redirect_uri",a);let u=await fetch(s,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:c.toString()}),d=await u.json();if(!u.ok)throw Error(nj(d)||d?.detail||"OAuth token exchange failed");return d},ny=async(e,t,r)=>{try{let n=`${C()}/v1/vector_stores/${t}/search`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({query:r})});if(!o.ok){let e=await o.text();return await j(e),null}return await o.json()}catch(e){throw console.error("Error testing vector store search:",e),e}},nb=async(e,t,r,n)=>{try{let o=`${C()}/v1/search/${t}`,a=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({query:r,max_results:n||5})});if(!a.ok){let e=await a.text();return await j(e),null}return await a.json()}catch(e){throw console.error("Error querying search tool:",e),e}},nw=async(e,t,r,n)=>{try{let o,a,i,l=$?`${$}/tag/dau`:"/tag/dau",s=new URLSearchParams;s.append("end_date",(o=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0"),`${o}-${a}-${i}`)),n&&n.length>0?n.forEach(e=>{s.append("tag_filters",e)}):r&&s.append("tag_filter",r);let c=s.toString();c&&(l+=`?${c}`);let u=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!u.ok){let e=await u.json(),t=nj(e);throw j(t),Error(t)}return await u.json()}catch(e){throw console.error("Failed to fetch DAU:",e),e}},n$=async(e,t,r,n)=>{try{let o,a,i,l=$?`${$}/tag/wau`:"/tag/wau",s=new URLSearchParams;s.append("end_date",(o=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0"),`${o}-${a}-${i}`)),n&&n.length>0?n.forEach(e=>{s.append("tag_filters",e)}):r&&s.append("tag_filter",r);let c=s.toString();c&&(l+=`?${c}`);let u=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!u.ok){let e=await u.json(),t=nj(e);throw j(t),Error(t)}return await u.json()}catch(e){throw console.error("Failed to fetch WAU:",e),e}},nC=async(e,t,r,n)=>{try{let o,a,i,l=$?`${$}/tag/mau`:"/tag/mau",s=new URLSearchParams;s.append("end_date",(o=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0"),`${o}-${a}-${i}`)),n&&n.length>0?n.forEach(e=>{s.append("tag_filters",e)}):r&&s.append("tag_filter",r);let c=s.toString();c&&(l+=`?${c}`);let u=await fetch(l,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!u.ok){let e=await u.json(),t=nj(e);throw j(t),Error(t)}return await u.json()}catch(e){throw console.error("Failed to fetch MAU:",e),e}},nE=async e=>{try{let t=$?`${$}/tag/distinct`:"/tag/distinct",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=nj(e);throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to fetch distinct tags:",e),e}},nS=async(e,t,r,n)=>{try{let o=$?`${$}/tag/summary`:"/tag/summary",a=new URLSearchParams,i=e=>{let t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0");return`${t}-${r}-${n}`};a.append("start_date",i(t)),a.append("end_date",i(r)),n&&n.length>0&&n.forEach(e=>{a.append("tag_filters",e)});let l=a.toString();l&&(o+=`?${l}`);let s=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!s.ok){let e=await s.json(),t=nj(e);throw j(t),Error(t)}return await s.json()}catch(e){throw console.error("Failed to fetch user agent summary:",e),e}},nx=async(e,t=1,r=50,n)=>{try{let o=$?`${$}/tag/user-agent/per-user-analytics`:"/tag/user-agent/per-user-analytics",a=new URLSearchParams;a.append("page",t.toString()),a.append("page_size",r.toString()),n&&n.length>0&&n.forEach(e=>{a.append("tag_filters",e)});let i=a.toString();i&&(o+=`?${i}`);let l=await fetch(o,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!l.ok){let e=await l.json(),t=nj(e);throw j(t),Error(t)}return await l.json()}catch(e){throw console.error("Failed to fetch per-user analytics:",e),e}},nj=e=>{let t=e?.detail,r=Array.isArray(t)?t.map(e=>e?.msg||JSON.stringify(e)).join("; "):"string"==typeof t?t:void 0;return e?.error&&(e.error.message||("string"==typeof e.error?e.error:void 0))||e?.message||r||JSON.stringify(e)},nO=async(e,t)=>{let r=C(),n=r?`${r}/v2/login`:"/v2/login",o=JSON.stringify({username:e,password:t}),a=await fetch(n,{method:"POST",body:o,credentials:"include",headers:{"Content-Type":"application/json"}});if(!a.ok)throw Error(nj(await a.json()));return await a.json()},nk=async()=>{let e=C(),t=e?`${e}/get/ui_settings`:"/get/ui_settings",r=await fetch(t,{method:"GET"});if(!r.ok)throw Error(nj(await r.json()));return await r.json()},nT=async(e,t)=>{let r=C(),n=r?`${r}/update/ui_settings`:"/update/ui_settings",o=await fetch(n,{method:"PATCH",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok)throw Error(nj(await o.json()));return await o.json()},nF=async()=>{try{let e=C(),t=e?`${e}/claude-code/marketplace.json`:"/claude-code/marketplace.json",r=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"}});if(!r.ok){let e=await r.text(),t=nj(JSON.parse(e));throw j(t),Error(t)}return await r.json()}catch(e){throw console.error("Failed to fetch Claude Code marketplace:",e),e}},n_=async(e,t=!1)=>{try{let r=C(),n=r?`${r}/claude-code/plugins?enabled_only=${t}`:`/claude-code/plugins?enabled_only=${t}`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nj(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to fetch Claude Code plugins list:",e),e}},nI=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}`:`/claude-code/plugins/${t}`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nj(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to fetch plugin "${t}":`,e),e}},nP=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins`:"/claude-code/plugins",o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){let e=await o.text(),t=nj(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error("Failed to register Claude Code plugin:",e),e}},nN=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}/enable`:`/claude-code/plugins/${t}/enable`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nj(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to enable plugin "${t}":`,e),e}},nR=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}/disable`:`/claude-code/plugins/${t}/disable`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nj(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to disable plugin "${t}":`,e),e}},nM=async(e,t)=>{try{let r=C(),n=r?`${r}/claude-code/plugins/${t}`:`/claude-code/plugins/${t}`,o=await fetch(n,{method:"DELETE",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.text(),t=nj(JSON.parse(e));throw j(t),Error(t)}return await o.json()}catch(e){throw console.error(`Failed to delete plugin "${t}":`,e),e}},nB=async(e,t)=>{let r=$?`${$}/compliance/eu-ai-act`:"/compliance/eu-ai-act",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok)throw Error(await n.text());return n.json()},nA=async(e,t)=>{let r=$?`${$}/compliance/gdpr`:"/compliance/gdpr",n=await fetch(r,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok)throw Error(await n.text());return n.json()},nz=async e=>{let t=$?`${$}/v1/tool/policy/options`:"/v1/tool/policy/options",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok)throw Error(await r.text());return r.json()},nL=async e=>{let t=$?`${$}/v1/tool/list`:"/v1/tool/list",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok)throw Error(await r.text());return(await r.json()).tools??[]},nH=async(e,t,r)=>{let n=encodeURIComponent(t),o=$?`${$}/v1/tool/${n}/logs`:`/v1/tool/${n}/logs`,a=new URLSearchParams;null!=r.page&&a.append("page",String(r.page)),null!=r.pageSize&&a.append("page_size",String(r.pageSize)),r.startDate&&a.append("start_date",r.startDate),r.endDate&&a.append("end_date",r.endDate);let i=a.toString()?`${o}?${a.toString()}`:o,l=await fetch(i,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!l.ok)throw Error(nj(await l.json().catch(()=>({}))));return l.json()},nD=async(e,t)=>{let r=encodeURIComponent(t),n=$?`${$}/v1/tool/${r}/detail`:`/v1/tool/${r}/detail`,o=await fetch(n,{method:"GET",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok)throw Error(await o.text());return o.json()},nV=async(e,t,r,n)=>{let o=$?`${$}/v1/tool/policy`:"/v1/tool/policy",a={tool_name:t};null!=r.input_policy&&(a.input_policy=r.input_policy),null!=r.output_policy&&(a.output_policy=r.output_policy),n?.team_id!=null&&(a.team_id=n.team_id||void 0),n?.key_hash!=null&&(a.key_hash=n.key_hash||void 0),n?.key_alias!=null&&(a.key_alias=n.key_alias||void 0);let i=await fetch(o,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(a)});if(!i.ok)throw Error(await i.text());return i.json()},nW=async(e,t,r)=>{let n=encodeURIComponent(t),o=new URLSearchParams;null!=r.team_id&&""!==r.team_id&&o.set("team_id",r.team_id),null!=r.key_hash&&""!==r.key_hash&&o.set("key_hash",r.key_hash);let a=o.toString(),i=$?`${$}/v1/tool/${n}/overrides${a?`?${a}`:""}`:`/v1/tool/${n}/overrides${a?`?${a}`:""}`,l=await fetch(i,{method:"DELETE",headers:{[T]:`Bearer ${e}`}});if(!l.ok)throw Error(await l.text());return l.json()},nG=async(e,t,r)=>{let n=$?`${$}/v1/mcp/server/${t}/oauth-user-credential`:`/v1/mcp/server/${t}/oauth-user-credential`,o=await fetch(n,{method:"POST",headers:{[T]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok){let e=await o.json().catch(()=>({})),t=e?.detail;throw Error((Array.isArray(t)?t.map(e=>e&&"object"==typeof e?e.msg??JSON.stringify(e):String(e)).join("; "):"string"==typeof t?t:t&&"string"==typeof t.error?t.error:void 0)||"Failed to store OAuth credential")}return o.json()},nU=async(e,t)=>{let r=$?`${$}/v1/mcp/server/${t}/oauth-user-credential`:`/v1/mcp/server/${t}/oauth-user-credential`,n=await fetch(r,{method:"DELETE",headers:{[T]:`Bearer ${e}`}});if(!n.ok){let e=await n.json().catch(()=>({})),t=e?.detail;throw Error((Array.isArray(t)?t.map(e=>e&&"object"==typeof e?e.msg??JSON.stringify(e):String(e)).join("; "):"string"==typeof t?t:t&&"string"==typeof t.error?t.error:void 0)||"Failed to revoke OAuth credential")}return n.json()},nq=async(e,t)=>{let r=$?`${$}/v1/mcp/server/${t}/oauth-user-credential/status`:`/v1/mcp/server/${t}/oauth-user-credential/status`,n=await fetch(r,{method:"GET",headers:{[T]:`Bearer ${e}`}});return n.ok?n.json():{server_id:t,has_credential:!1,is_expired:!1}},nJ=async e=>{let t=$?`${$}/v1/mcp/user-credentials`:"/v1/mcp/user-credentials",r=await fetch(t,{method:"GET",headers:{[T]:`Bearer ${e}`}});return r.ok?r.json():[]}}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/9b0c03a2b0969129.js b/litellm/proxy/_experimental/out/_next/static/chunks/3b3c0b070b14da06.js similarity index 70% rename from litellm/proxy/_experimental/out/_next/static/chunks/9b0c03a2b0969129.js rename to litellm/proxy/_experimental/out/_next/static/chunks/3b3c0b070b14da06.js index f9bef80c55..786780e51d 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/9b0c03a2b0969129.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/3b3c0b070b14da06.js @@ -1,8 +1,8 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,916925,e=>{"use strict";var t,r=((t={}).A2A_Agent="A2A Agent",t.AI21="Ai21",t.AI21_CHAT="Ai21 Chat",t.AIML="AI/ML API",t.AIOHTTP_OPENAI="Aiohttp Openai",t.Anthropic="Anthropic",t.ANTHROPIC_TEXT="Anthropic Text",t.AssemblyAI="AssemblyAI",t.AUTO_ROUTER="Auto Router",t.Bedrock="Amazon Bedrock",t.BedrockMantle="Amazon Bedrock Mantle",t.SageMaker="AWS SageMaker",t.Azure="Azure",t.Azure_AI_Studio="Azure AI Foundry (Studio)",t.AZURE_TEXT="Azure Text",t.BASETEN="Baseten",t.BYTEZ="Bytez",t.Cerebras="Cerebras",t.CLARIFAI="Clarifai",t.CLOUDFLARE="Cloudflare",t.CODESTRAL="Codestral",t.Cohere="Cohere",t.COHERE_CHAT="Cohere Chat",t.COMETAPI="Cometapi",t.COMPACTIFAI="Compactifai",t.Cursor="Cursor",t.Dashscope="Dashscope",t.Databricks="Databricks (Qwen API)",t.DATAROBOT="Datarobot",t.DeepInfra="DeepInfra",t.Deepgram="Deepgram",t.Deepseek="Deepseek",t.DOCKER_MODEL_RUNNER="Docker Model Runner",t.DOTPROMPT="Dotprompt",t.ElevenLabs="ElevenLabs",t.EMPOWER="Empower",t.FalAI="Fal AI",t.FEATHERLESS_AI="Featherless Ai",t.FireworksAI="Fireworks AI",t.FRIENDLIAI="Friendliai",t.GALADRIEL="Galadriel",t.GITHUB_COPILOT="Github Copilot",t.Google_AI_Studio="Google AI Studio",t.GradientAI="GradientAI",t.Groq="Groq",t.HEROKU="Heroku",t.Hosted_Vllm="vllm",t.HUGGINGFACE="Huggingface",t.HYPERBOLIC="Hyperbolic",t.Infinity="Infinity",t.JinaAI="Jina AI",t.LAMBDA_AI="Lambda Ai",t.LEMONADE="Lemonade",t.LLAMAFILE="Llamafile",t.LM_STUDIO="Lm Studio",t.LLAMA="Meta Llama",t.MARITALK="Maritalk",t.MiniMax="MiniMax",t.MistralAI="Mistral AI",t.MOONSHOT="Moonshot",t.MORPH="Morph",t.NEBIUS="Nebius",t.NLP_CLOUD="Nlp Cloud",t.NOVITA="Novita",t.NSCALE="Nscale",t.NVIDIA_NIM="Nvidia Nim",t.Ollama="Ollama",t.OLLAMA_CHAT="Ollama Chat",t.OOBABOOGA="Oobabooga",t.OpenAI="OpenAI",t.OPENAI_LIKE="Openai Like",t.OpenAI_Compatible="OpenAI-Compatible Endpoints (Together AI, etc.)",t.OpenAI_Text="OpenAI Text Completion",t.OpenAI_Text_Compatible="OpenAI-Compatible Text Completion Models (Together AI, etc.)",t.Openrouter="Openrouter",t.Oracle="Oracle Cloud Infrastructure (OCI)",t.OVHCLOUD="Ovhcloud",t.Perplexity="Perplexity",t.PETALS="Petals",t.PG_VECTOR="Pg Vector",t.PREDIBASE="Predibase",t.RECRAFT="Recraft",t.REPLICATE="Replicate",t.RunwayML="RunwayML",t.SAGEMAKER_LEGACY="Sagemaker",t.Sambanova="Sambanova",t.SAP="SAP Generative AI Hub",t.Snowflake="Snowflake",t.TEXT_COMPLETION_CODESTRAL="Text-Completion-Codestral",t.TogetherAI="TogetherAI",t.TOPAZ="Topaz",t.Triton="Triton",t.V0="V0",t.VERCEL_AI_GATEWAY="Vercel Ai Gateway",t.Vertex_AI="Vertex AI (Anthropic, Gemini, etc.)",t.VERTEX_AI_BETA="Vertex Ai Beta",t.VLLM="Vllm",t.VolcEngine="VolcEngine",t.Voyage="Voyage AI",t.WANDB="Wandb",t.WATSONX="Watsonx",t.WATSONX_TEXT="Watsonx Text",t.xAI="xAI",t.XINFERENCE="Xinference",t);let a={A2A_Agent:"a2a_agent",AI21:"ai21",AI21_CHAT:"ai21_chat",AIML:"aiml",AIOHTTP_OPENAI:"aiohttp_openai",Anthropic:"anthropic",ANTHROPIC_TEXT:"anthropic_text",AssemblyAI:"assemblyai",AUTO_ROUTER:"auto_router",Azure:"azure",Azure_AI_Studio:"azure_ai",AZURE_TEXT:"azure_text",BASETEN:"baseten",Bedrock:"bedrock",BedrockMantle:"bedrock_mantle",BYTEZ:"bytez",Cerebras:"cerebras",CLARIFAI:"clarifai",CLOUDFLARE:"cloudflare",CODESTRAL:"codestral",Cohere:"cohere",COHERE_CHAT:"cohere_chat",COMETAPI:"cometapi",COMPACTIFAI:"compactifai",Cursor:"cursor",Dashscope:"dashscope",Databricks:"databricks",DATAROBOT:"datarobot",DeepInfra:"deepinfra",Deepgram:"deepgram",Deepseek:"deepseek",DOCKER_MODEL_RUNNER:"docker_model_runner",DOTPROMPT:"dotprompt",ElevenLabs:"elevenlabs",EMPOWER:"empower",FalAI:"fal_ai",FEATHERLESS_AI:"featherless_ai",FireworksAI:"fireworks_ai",FRIENDLIAI:"friendliai",GALADRIEL:"galadriel",GITHUB_COPILOT:"github_copilot",Google_AI_Studio:"gemini",GradientAI:"gradient_ai",Groq:"groq",HEROKU:"heroku",Hosted_Vllm:"hosted_vllm",HUGGINGFACE:"huggingface",HYPERBOLIC:"hyperbolic",Infinity:"infinity",JinaAI:"jina_ai",LAMBDA_AI:"lambda_ai",LEMONADE:"lemonade",LLAMAFILE:"llamafile",LLAMA:"meta_llama",LM_STUDIO:"lm_studio",MARITALK:"maritalk",MiniMax:"minimax",MistralAI:"mistral",MOONSHOT:"moonshot",MORPH:"morph",NEBIUS:"nebius",NLP_CLOUD:"nlp_cloud",NOVITA:"novita",NSCALE:"nscale",NVIDIA_NIM:"nvidia_nim",Ollama:"ollama",OLLAMA_CHAT:"ollama_chat",OOBABOOGA:"oobabooga",OpenAI:"openai",OPENAI_LIKE:"openai_like",OpenAI_Compatible:"openai",OpenAI_Text:"text-completion-openai",OpenAI_Text_Compatible:"text-completion-openai",Openrouter:"openrouter",Oracle:"oci",OVHCLOUD:"ovhcloud",Perplexity:"perplexity",PETALS:"petals",PG_VECTOR:"pg_vector",PREDIBASE:"predibase",RECRAFT:"recraft",REPLICATE:"replicate",RunwayML:"runwayml",SAGEMAKER_LEGACY:"sagemaker",SageMaker:"sagemaker_chat",Sambanova:"sambanova",SAP:"sap",Snowflake:"snowflake",TEXT_COMPLETION_CODESTRAL:"text-completion-codestral",TogetherAI:"together_ai",TOPAZ:"topaz",Triton:"triton",V0:"v0",VERCEL_AI_GATEWAY:"vercel_ai_gateway",Vertex_AI:"vertex_ai",VERTEX_AI_BETA:"vertex_ai_beta",VLLM:"vllm",VolcEngine:"volcengine",Voyage:"voyage",WANDB:"wandb",WATSONX:"watsonx",WATSONX_TEXT:"watsonx_text",xAI:"xai",XINFERENCE:"xinference"},l="../ui/assets/logos/",o={"A2A Agent":`${l}a2a_agent.png`,Ai21:`${l}ai21.svg`,"Ai21 Chat":`${l}ai21.svg`,"AI/ML API":`${l}aiml_api.svg`,"Aiohttp Openai":`${l}openai_small.svg`,Anthropic:`${l}anthropic.svg`,"Anthropic Text":`${l}anthropic.svg`,AssemblyAI:`${l}assemblyai_small.png`,Azure:`${l}microsoft_azure.svg`,"Azure AI Foundry (Studio)":`${l}microsoft_azure.svg`,"Azure Text":`${l}microsoft_azure.svg`,Baseten:`${l}baseten.svg`,"Amazon Bedrock":`${l}bedrock.svg`,"Amazon Bedrock Mantle":`${l}bedrock.svg`,"AWS SageMaker":`${l}bedrock.svg`,Cerebras:`${l}cerebras.svg`,Cloudflare:`${l}cloudflare.svg`,Codestral:`${l}mistral.svg`,Cohere:`${l}cohere.svg`,"Cohere Chat":`${l}cohere.svg`,Cometapi:`${l}cometapi.svg`,Cursor:`${l}cursor.svg`,"Databricks (Qwen API)":`${l}databricks.svg`,Dashscope:`${l}dashscope.svg`,Deepseek:`${l}deepseek.svg`,Deepgram:`${l}deepgram.png`,DeepInfra:`${l}deepinfra.png`,ElevenLabs:`${l}elevenlabs.png`,"Fal AI":`${l}fal_ai.jpg`,"Featherless Ai":`${l}featherless.svg`,"Fireworks AI":`${l}fireworks.svg`,Friendliai:`${l}friendli.svg`,"Github Copilot":`${l}github_copilot.svg`,"Google AI Studio":`${l}google.svg`,GradientAI:`${l}gradientai.svg`,Groq:`${l}groq.svg`,vllm:`${l}vllm.png`,Huggingface:`${l}huggingface.svg`,Hyperbolic:`${l}hyperbolic.svg`,Infinity:`${l}infinity.png`,"Jina AI":`${l}jina.png`,"Lambda Ai":`${l}lambda.svg`,"Lm Studio":`${l}lmstudio.svg`,"Meta Llama":`${l}meta_llama.svg`,MiniMax:`${l}minimax.svg`,"Mistral AI":`${l}mistral.svg`,Moonshot:`${l}moonshot.svg`,Morph:`${l}morph.svg`,Nebius:`${l}nebius.svg`,Novita:`${l}novita.svg`,"Nvidia Nim":`${l}nvidia_nim.svg`,Ollama:`${l}ollama.svg`,"Ollama Chat":`${l}ollama.svg`,Oobabooga:`${l}openai_small.svg`,OpenAI:`${l}openai_small.svg`,"Openai Like":`${l}openai_small.svg`,"OpenAI Text Completion":`${l}openai_small.svg`,"OpenAI-Compatible Text Completion Models (Together AI, etc.)":`${l}openai_small.svg`,"OpenAI-Compatible Endpoints (Together AI, etc.)":`${l}openai_small.svg`,Openrouter:`${l}openrouter.svg`,"Oracle Cloud Infrastructure (OCI)":`${l}oracle.svg`,Perplexity:`${l}perplexity-ai.svg`,Recraft:`${l}recraft.svg`,Replicate:`${l}replicate.svg`,RunwayML:`${l}runwayml.png`,Sagemaker:`${l}bedrock.svg`,Sambanova:`${l}sambanova.svg`,"SAP Generative AI Hub":`${l}sap.png`,Snowflake:`${l}snowflake.svg`,"Text-Completion-Codestral":`${l}mistral.svg`,TogetherAI:`${l}togetherai.svg`,Topaz:`${l}topaz.svg`,Triton:`${l}nvidia_triton.png`,V0:`${l}v0.svg`,"Vercel Ai Gateway":`${l}vercel.svg`,"Vertex AI (Anthropic, Gemini, etc.)":`${l}google.svg`,"Vertex Ai Beta":`${l}google.svg`,Vllm:`${l}vllm.png`,VolcEngine:`${l}volcengine.png`,"Voyage AI":`${l}voyage.webp`,Watsonx:`${l}watsonx.svg`,"Watsonx Text":`${l}watsonx.svg`,xAI:`${l}xai.svg`,Xinference:`${l}xinference.svg`};e.s(["Providers",()=>r,"getPlaceholder",0,e=>{if("AI/ML API"===e)return"aiml/flux-pro/v1.1";if("Vertex AI (Anthropic, Gemini, etc.)"===e)return"gemini-pro";if("Anthropic"==e)return"claude-3-opus";if("Amazon Bedrock"==e)return"claude-3-opus";if("AWS SageMaker"==e)return"sagemaker/jumpstart-dft-meta-textgeneration-llama-2-7b";else if("Google AI Studio"==e)return"gemini-pro";else if("Azure AI Foundry (Studio)"==e)return"azure_ai/command-r-plus";else if("Azure"==e)return"my-deployment";else if("Oracle Cloud Infrastructure (OCI)"==e)return"oci/xai.grok-4";else if("Snowflake"==e)return"snowflake/mistral-7b";else if("Voyage AI"==e)return"voyage/";else if("Jina AI"==e)return"jina_ai/";else if("VolcEngine"==e)return"volcengine/";else if("DeepInfra"==e)return"deepinfra/";else if("Fal AI"==e)return"fal_ai/fal-ai/flux-pro/v1.1-ultra";else if("RunwayML"==e)return"runwayml/gen4_turbo";else if("Watsonx"===e)return"watsonx/ibm/granite-3-3-8b-instruct";else if("Cursor"===e)return"cursor/claude-4-sonnet";else return"gpt-3.5-turbo"},"getProviderLogoAndName",0,e=>{if(!e)return{logo:"",displayName:"-"};if("gemini"===e.toLowerCase()){let e="Google AI Studio";return{logo:o[e],displayName:e}}let t=Object.keys(a).find(t=>a[t].toLowerCase()===e.toLowerCase());if(!t)return{logo:"",displayName:e};let l=r[t];return{logo:o[l],displayName:l}},"getProviderModels",0,(e,t)=>{console.log(`Provider key: ${e}`);let r=a[e];console.log(`Provider mapped to: ${r}`);let l=[];return e&&"object"==typeof t&&(Object.entries(t).forEach(([e,t])=>{if(null!==t&&"object"==typeof t&&"litellm_provider"in t){let a=t.litellm_provider;(a===r||"string"==typeof a&&a.includes(r))&&l.push(e)}}),"Cohere"==e&&(console.log("Adding cohere chat models"),Object.entries(t).forEach(([e,t])=>{null!==t&&"object"==typeof t&&"litellm_provider"in t&&"cohere_chat"===t.litellm_provider&&l.push(e)})),"AWS SageMaker"==e&&(console.log("Adding sagemaker chat models"),Object.entries(t).forEach(([e,t])=>{null!==t&&"object"==typeof t&&"litellm_provider"in t&&"sagemaker_chat"===t.litellm_provider&&l.push(e)}))),l},"providerLogoMap",0,o,"provider_map",0,a])},793130,e=>{"use strict";var t=e.i(290571),r=e.i(429427),a=e.i(371330),l=e.i(271645),o=e.i(394487),s=e.i(503269),i=e.i(214520),n=e.i(746725),d=e.i(914189),c=e.i(144279),u=e.i(294316),m=e.i(601893),g=e.i(140721),p=e.i(942803),f=e.i(233538),b=e.i(694421),h=e.i(700020),x=e.i(35889),v=e.i(998348),C=e.i(722678);let y=(0,l.createContext)(null);y.displayName="GroupContext";let k=l.Fragment,w=Object.assign((0,h.forwardRefWithAs)(function(e,t){var k;let w=(0,l.useId)(),A=(0,p.useProvidedId)(),N=(0,m.useDisabled)(),{id:j=A||`headlessui-switch-${w}`,disabled:_=N||!1,checked:T,defaultChecked:E,onChange:I,name:O,value:M,form:S,autoFocus:$=!1,...R}=e,L=(0,l.useContext)(y),[P,B]=(0,l.useState)(null),F=(0,l.useRef)(null),D=(0,u.useSyncRefs)(F,t,null===L?null:L.setSwitch,B),z=(0,i.useDefaultValue)(E),[H,G]=(0,s.useControllable)(T,I,null!=z&&z),V=(0,n.useDisposables)(),[q,X]=(0,l.useState)(!1),U=(0,d.useEvent)(()=>{X(!0),null==G||G(!H),V.nextFrame(()=>{X(!1)})}),W=(0,d.useEvent)(e=>{if((0,f.isDisabledReactIssue7711)(e.currentTarget))return e.preventDefault();e.preventDefault(),U()}),Y=(0,d.useEvent)(e=>{e.key===v.Keys.Space?(e.preventDefault(),U()):e.key===v.Keys.Enter&&(0,b.attemptSubmit)(e.currentTarget)}),K=(0,d.useEvent)(e=>e.preventDefault()),J=(0,C.useLabelledBy)(),Z=(0,x.useDescribedBy)(),{isFocusVisible:Q,focusProps:ee}=(0,r.useFocusRing)({autoFocus:$}),{isHovered:et,hoverProps:er}=(0,a.useHover)({isDisabled:_}),{pressed:ea,pressProps:el}=(0,o.useActivePress)({disabled:_}),eo=(0,l.useMemo)(()=>({checked:H,disabled:_,hover:et,focus:Q,active:ea,autofocus:$,changing:q}),[H,et,Q,ea,_,q,$]),es=(0,h.mergeProps)({id:j,ref:D,role:"switch",type:(0,c.useResolveButtonType)(e,P),tabIndex:-1===e.tabIndex?0:null!=(k=e.tabIndex)?k:0,"aria-checked":H,"aria-labelledby":J,"aria-describedby":Z,disabled:_||void 0,autoFocus:$,onClick:W,onKeyUp:Y,onKeyPress:K},ee,er,el),ei=(0,l.useCallback)(()=>{if(void 0!==z)return null==G?void 0:G(z)},[G,z]),en=(0,h.useRender)();return l.default.createElement(l.default.Fragment,null,null!=O&&l.default.createElement(g.FormFields,{disabled:_,data:{[O]:M||"on"},overrides:{type:"checkbox",checked:H},form:S,onReset:ei}),en({ourProps:es,theirProps:R,slot:eo,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var t;let[r,a]=(0,l.useState)(null),[o,s]=(0,C.useLabels)(),[i,n]=(0,x.useDescriptions)(),d=(0,l.useMemo)(()=>({switch:r,setSwitch:a}),[r,a]),c=(0,h.useRender)();return l.default.createElement(n,{name:"Switch.Description",value:i},l.default.createElement(s,{name:"Switch.Label",value:o,props:{htmlFor:null==(t=d.switch)?void 0:t.id,onClick(e){r&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),r.click(),r.focus({preventScroll:!0}))}}},l.default.createElement(y.Provider,{value:d},c({ourProps:{},theirProps:e,slot:{},defaultTag:k,name:"Switch.Group"}))))},Label:C.Label,Description:x.Description});var A=e.i(888288),N=e.i(95779),j=e.i(444755),_=e.i(673706),T=e.i(829087);let E=(0,_.makeClassName)("Switch"),I=l.default.forwardRef((e,r)=>{let{checked:a,defaultChecked:o=!1,onChange:s,color:i,name:n,error:d,errorMessage:c,disabled:u,required:m,tooltip:g,id:p}=e,f=(0,t.__rest)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),b={bgColor:i?(0,_.getColorClassNames)(i,N.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:i?(0,_.getColorClassNames)(i,N.colorPalette.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[h,x]=(0,A.default)(o,a),[v,C]=(0,l.useState)(!1),{tooltipProps:y,getReferenceProps:k}=(0,T.useTooltip)(300);return l.default.createElement("div",{className:"flex flex-row items-center justify-start"},l.default.createElement(T.default,Object.assign({text:g},y)),l.default.createElement("div",Object.assign({ref:(0,_.mergeRefs)([r,y.refs.setReference]),className:(0,j.tremorTwMerge)(E("root"),"flex flex-row relative h-5")},f,k),l.default.createElement("input",{type:"checkbox",className:(0,j.tremorTwMerge)(E("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:n,required:m,checked:h,onChange:e=>{e.preventDefault()}}),l.default.createElement(w,{checked:h,onChange:e=>{x(e),null==s||s(e)},disabled:u,className:(0,j.tremorTwMerge)(E("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:()=>C(!0),onBlur:()=>C(!1),id:p},l.default.createElement("span",{className:(0,j.tremorTwMerge)(E("sr-only"),"sr-only")},"Switch ",h?"on":"off"),l.default.createElement("span",{"aria-hidden":"true",className:(0,j.tremorTwMerge)(E("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.default.createElement("span",{"aria-hidden":"true",className:(0,j.tremorTwMerge)(E("round"),h?(0,j.tremorTwMerge)(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,j.tremorTwMerge)("ring-2",b.ringColor):"")}))),d&&c?l.default.createElement("p",{className:(0,j.tremorTwMerge)(E("errorMessage"),"text-sm text-red-500 mt-1 ")},c):null)});I.displayName="Switch",e.s(["Switch",()=>I],793130)},653496,e=>{"use strict";var t=e.i(721369);e.s(["Tabs",()=>t.default])},689020,e=>{"use strict";var t=e.i(764205);let r=async e=>{try{let r=await (0,t.modelHubCall)(e);if(console.log("model_info:",r),r?.data.length>0){let e=r.data.map(e=>({model_group:e.model_group,mode:e?.mode}));return e.sort((e,t)=>e.model_group.localeCompare(t.model_group)),e}return[]}catch(e){throw console.error("Error fetching model info:",e),e}};e.s(["fetchAvailableModels",0,r])},107233,37727,e=>{"use strict";var t=e.i(603908);e.s(["Plus",()=>t.default],107233);var r=e.i(841947);e.s(["X",()=>r.default],37727)},361653,e=>{"use strict";let t=(0,e.i(475254).default)("circle-alert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);e.s(["default",()=>t])},603908,e=>{"use strict";let t=(0,e.i(475254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);e.s(["default",()=>t])},841947,e=>{"use strict";let t=(0,e.i(475254).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["default",()=>t])},158392,419470,e=>{"use strict";var t=e.i(843476),r=e.i(779241);let a={ttl:3600,lowest_latency_buffer:0},l=({routingStrategyArgs:e})=>{let l={ttl:"Sliding window to look back over when calculating the average latency of a deployment. Default - 1 hour (in seconds).",lowest_latency_buffer:"Shuffle between deployments within this % of the lowest latency. Default - 0 (i.e. always pick lowest latency)."};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Latency-Based Configuration"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Fine-tune latency-based routing behavior"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e||a).map(([e,a])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:e.replace(/_/g," ")}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l[e]||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:"object"==typeof a?JSON.stringify(a,null,2):a?.toString(),className:"font-mono text-sm w-full"})]})},e))})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"})]})},o=({routerSettings:e,routerFieldsMetadata:a})=>(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Reliability & Retries"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure retry logic and failure handling"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e).filter(([e,t])=>"fallbacks"!=e&&"context_window_fallbacks"!=e&&"routing_strategy_args"!=e&&"routing_strategy"!=e&&"enable_tag_filtering"!=e).map(([e,l])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:a[e]?.ui_field_name||e}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:a[e]?.field_description||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:null==l||"null"===l?"":"object"==typeof l?JSON.stringify(l,null,2):l?.toString()||"",placeholder:"—",className:"font-mono text-sm w-full"})]})},e))})]});var s=e.i(199133);let i=({selectedStrategy:e,availableStrategies:r,routingStrategyDescriptions:a,routerFieldsMetadata:l,onStrategyChange:o})=>(0,t.jsxs)("div",{className:"space-y-2 max-w-3xl",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:l.routing_strategy?.ui_field_name||"Routing Strategy"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l.routing_strategy?.field_description||""})]}),(0,t.jsx)("div",{className:"routing-strategy-select max-w-3xl",children:(0,t.jsx)(s.Select,{value:e,onChange:o,style:{width:"100%"},size:"large",children:r.map(e=>(0,t.jsx)(s.Select.Option,{value:e,label:e,children:(0,t.jsxs)("div",{className:"flex flex-col gap-0.5 py-1",children:[(0,t.jsx)("span",{className:"font-mono text-sm font-medium",children:e}),a[e]&&(0,t.jsx)("span",{className:"text-xs text-gray-500 font-normal",children:a[e]})]})},e))})})]});var n=e.i(793130);let d=({enabled:e,routerFieldsMetadata:r,onToggle:a})=>(0,t.jsx)("div",{className:"space-y-3 max-w-3xl",children:(0,t.jsxs)("div",{className:"flex items-start justify-between",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:r.enable_tag_filtering?.ui_field_name||"Enable Tag Filtering"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500 mt-0.5",children:[r.enable_tag_filtering?.field_description||"",r.enable_tag_filtering?.link&&(0,t.jsxs)(t.Fragment,{children:[" ",(0,t.jsx)("a",{href:r.enable_tag_filtering.link,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline",children:"Learn more"})]})]})]}),(0,t.jsx)(n.Switch,{checked:e,onChange:a,className:"ml-4"})]})});e.s(["default",0,({value:e,onChange:r,routerFieldsMetadata:a,availableRoutingStrategies:s,routingStrategyDescriptions:n})=>(0,t.jsxs)("div",{className:"w-full space-y-8 py-2",children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Routing Settings"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure how requests are routed to deployments"})]}),s.length>0&&(0,t.jsx)(i,{selectedStrategy:e.selectedStrategy||e.routerSettings.routing_strategy||null,availableStrategies:s,routingStrategyDescriptions:n,routerFieldsMetadata:a,onStrategyChange:t=>{r({...e,selectedStrategy:t})}}),(0,t.jsx)(d,{enabled:e.enableTagFiltering,routerFieldsMetadata:a,onToggle:t=>{r({...e,enableTagFiltering:t})}})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),"latency-based-routing"===e.selectedStrategy&&(0,t.jsx)(l,{routingStrategyArgs:e.routerSettings.routing_strategy_args}),(0,t.jsx)(o,{routerSettings:e.routerSettings,routerFieldsMetadata:a})]})],158392);var c=e.i(994388),u=e.i(998573),m=e.i(653496),g=e.i(107233),p=e.i(271645),f=e.i(592968),b=e.i(361653),b=b;let h=(0,e.i(475254).default)("arrow-down",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var x=e.i(37727);function v({group:e,onChange:r,availableModels:a,maxFallbacks:l}){let o=a.filter(t=>t!==e.primaryModel),i=e.fallbackModels.length{let a=[...e.fallbackModels];a.includes(t)&&(a=a.filter(e=>e!==t)),r({...e,primaryModel:t,fallbackModels:a})},showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase()),options:a.map(e=>({label:e,value:e}))}),!e.primaryModel&&(0,t.jsxs)("div",{className:"mt-2 flex items-center gap-2 text-amber-600 text-xs bg-amber-50 p-2 rounded",children:[(0,t.jsx)(b.default,{className:"w-4 h-4"}),(0,t.jsx)("span",{children:"Select a model to begin configuring fallbacks"})]})]}),(0,t.jsx)("div",{className:"flex items-center justify-center -my-4 z-10",children:(0,t.jsxs)("div",{className:"bg-indigo-50 text-indigo-500 px-4 py-1 rounded-full text-xs font-bold border border-indigo-100 flex items-center gap-2 shadow-sm",children:[(0,t.jsx)(h,{className:"w-4 h-4"}),"IF FAILS, TRY..."]})}),(0,t.jsxs)("div",{className:`transition-opacity duration-300 ${!e.primaryModel?"opacity-50 pointer-events-none":"opacity-100"}`,children:[(0,t.jsxs)("label",{className:"block text-sm font-semibold text-gray-700 mb-2",children:["Fallback Chain ",(0,t.jsx)("span",{className:"text-red-500",children:"*"}),(0,t.jsxs)("span",{className:"text-xs text-gray-500 font-normal ml-2",children:["(Max ",l," fallbacks at a time)"]})]}),(0,t.jsxs)("div",{className:"bg-gray-50 rounded-xl p-4 border border-gray-200",children:[(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(s.Select,{mode:"multiple",className:"w-full",size:"large",placeholder:i?"Select fallback models to add...":`Maximum ${l} fallbacks reached`,value:e.fallbackModels,onChange:t=>{let a=t.slice(0,l);r({...e,fallbackModels:a})},disabled:!e.primaryModel,options:o.map(e=>({label:e,value:e})),optionRender:(r,a)=>{let l=e.fallbackModels.includes(r.value),o=l?e.fallbackModels.indexOf(r.value)+1:null;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[l&&null!==o&&(0,t.jsx)("span",{className:"flex items-center justify-center w-5 h-5 rounded bg-indigo-100 text-indigo-600 text-xs font-bold",children:o}),(0,t.jsx)("span",{children:r.label})]})},maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(f.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})}),showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase())}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1 ml-1",children:i?`Search and select multiple models. Selected models will appear below in order. (${e.fallbackModels.length}/${l} used)`:`Maximum ${l} fallbacks reached. Remove some to add more.`})]}),(0,t.jsx)("div",{className:"space-y-2 min-h-[100px]",children:0===e.fallbackModels.length?(0,t.jsxs)("div",{className:"h-32 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)("span",{className:"text-sm",children:"No fallback models selected"}),(0,t.jsx)("span",{className:"text-xs mt-1",children:"Add models from the dropdown above"})]}):e.fallbackModels.map((a,l)=>(0,t.jsxs)("div",{className:"group flex items-center justify-between p-3 bg-white rounded-lg border border-gray-200 hover:border-indigo-300 hover:shadow-sm transition-all",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex items-center justify-center w-6 h-6 rounded bg-gray-100 text-gray-400 group-hover:text-indigo-500 group-hover:bg-indigo-50",children:(0,t.jsx)("span",{className:"text-xs font-bold",children:l+1})}),(0,t.jsx)("div",{children:(0,t.jsx)("span",{className:"font-medium text-gray-800",children:a})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>{let t;return t=e.fallbackModels.filter((e,t)=>t!==l),void r({...e,fallbackModels:t})},className:"opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500 p-1",children:(0,t.jsx)(x.X,{className:"w-4 h-4"})})]},`${a}-${l}`))})]})]})]})}function C({groups:e,onGroupsChange:r,availableModels:a,maxFallbacks:l=10,maxGroups:o=5}){let[s,i]=(0,p.useState)(e.length>0?e[0].id:"1");(0,p.useEffect)(()=>{e.length>0?e.some(e=>e.id===s)||i(e[0].id):i("1")},[e]);let n=()=>{if(e.length>=o)return;let t=Date.now().toString();r([...e,{id:t,primaryModel:null,fallbackModels:[]}]),i(t)},d=t=>{r(e.map(e=>e.id===t.id?t:e))},f=e.map((r,o)=>{let s=r.primaryModel?r.primaryModel:`Group ${o+1}`;return{key:r.id,label:s,closable:e.length>1,children:(0,t.jsx)(v,{group:r,onChange:d,availableModels:a,maxFallbacks:l})}});return 0===e.length?(0,t.jsxs)("div",{className:"text-center py-12 bg-gray-50 rounded-lg border border-dashed border-gray-300",children:[(0,t.jsx)("p",{className:"text-gray-500 mb-4",children:"No fallback groups configured"}),(0,t.jsx)(c.Button,{variant:"primary",onClick:n,icon:()=>(0,t.jsx)(g.Plus,{className:"w-4 h-4"}),children:"Create First Group"})]}):(0,t.jsx)(m.Tabs,{type:"editable-card",activeKey:s,onChange:i,onEdit:(t,a)=>{"add"===a?n():"remove"===a&&e.length>1&&(t=>{if(1===e.length)return u.message.warning("At least one group is required");let a=e.filter(e=>e.id!==t);r(a),s===t&&a.length>0&&i(a[a.length-1].id)})(t)},items:f,className:"fallback-tabs",tabBarStyle:{marginBottom:0},hideAdd:e.length>=o})}e.s(["FallbackSelectionForm",()=>C],419470)},68155,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.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"}))});e.s(["TrashIcon",0,r],68155)},599724,936325,e=>{"use strict";var t=e.i(95779),r=e.i(444755),a=e.i(673706),l=e.i(271645);let o=l.default.forwardRef((e,o)=>{let{color:s,className:i,children:n}=e;return l.default.createElement("p",{ref:o,className:(0,r.tremorTwMerge)("text-tremor-default",s?(0,a.getColorClassNames)(s,t.colorPalette.text).textColor:(0,r.tremorTwMerge)("text-tremor-content","dark:text-dark-tremor-content"),i)},n)});o.displayName="Text",e.s(["default",()=>o],936325),e.s(["Text",()=>o],599724)},304967,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(480731),l=e.i(95779),o=e.i(444755),s=e.i(673706);let i=(0,s.makeClassName)("Card"),n=r.default.forwardRef((e,n)=>{let{decoration:d="",decorationColor:c,children:u,className:m}=e,g=(0,t.__rest)(e,["decoration","decorationColor","children","className"]);return r.default.createElement("div",Object.assign({ref:n,className:(0,o.tremorTwMerge)(i("root"),"relative w-full text-left ring-1 rounded-tremor-default p-6","bg-tremor-background ring-tremor-ring shadow-tremor-card","dark:bg-dark-tremor-background dark:ring-dark-tremor-ring dark:shadow-dark-tremor-card",c?(0,s.getColorClassNames)(c,l.colorPalette.border).borderColor:"border-tremor-brand dark:border-dark-tremor-brand",(e=>{if(!e)return"";switch(e){case a.HorizontalPositions.Left:return"border-l-4";case a.VerticalPositions.Top:return"border-t-4";case a.HorizontalPositions.Right:return"border-r-4";case a.VerticalPositions.Bottom:return"border-b-4";default:return""}})(d),m)},g),u)});n.displayName="Card",e.s(["Card",()=>n],304967)},994388,e=>{"use strict";var t=e.i(290571),r=e.i(829087),a=e.i(271645);let l=["preEnter","entering","entered","preExit","exiting","exited","unmounted"],o=e=>({_s:e,status:l[e],isEnter:e<3,isMounted:6!==e,isResolved:2===e||e>4}),s=e=>e?6:5,i=(e,t,r,a,l)=>{clearTimeout(a.current);let s=o(e);t(s),r.current=s,l&&l({current:s})};var n=e.i(480731),d=e.i(444755),c=e.i(673706);let u=e=>{var r=(0,t.__rest)(e,[]);return a.default.createElement("svg",Object.assign({},r,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"}),a.default.createElement("path",{fill:"none",d:"M0 0h24v24H0z"}),a.default.createElement("path",{d:"M18.364 5.636L16.95 7.05A7 7 0 1 0 19 12h2a9 9 0 1 1-2.636-6.364z"}))};var m=e.i(95779);let g={xs:{height:"h-4",width:"w-4"},sm:{height:"h-5",width:"w-5"},md:{height:"h-5",width:"w-5"},lg:{height:"h-6",width:"w-6"},xl:{height:"h-6",width:"w-6"}},p=(e,t)=>{switch(e){case"primary":return{textColor:t?(0,c.getColorClassNames)("white").textColor:"text-tremor-brand-inverted dark:text-dark-tremor-brand-inverted",hoverTextColor:t?(0,c.getColorClassNames)("white").textColor:"text-tremor-brand-inverted dark:text-dark-tremor-brand-inverted",bgColor:t?(0,c.getColorClassNames)(t,m.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",hoverBgColor:t?(0,c.getColorClassNames)(t,m.colorPalette.darkBackground).hoverBgColor:"hover:bg-tremor-brand-emphasis dark:hover:bg-dark-tremor-brand-emphasis",borderColor:t?(0,c.getColorClassNames)(t,m.colorPalette.border).borderColor:"border-tremor-brand dark:border-dark-tremor-brand",hoverBorderColor:t?(0,c.getColorClassNames)(t,m.colorPalette.darkBorder).hoverBorderColor:"hover:border-tremor-brand-emphasis dark:hover:border-dark-tremor-brand-emphasis"};case"secondary":return{textColor:t?(0,c.getColorClassNames)(t,m.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",hoverTextColor:t?(0,c.getColorClassNames)(t,m.colorPalette.text).textColor:"hover:text-tremor-brand-emphasis dark:hover:text-dark-tremor-brand-emphasis",bgColor:(0,c.getColorClassNames)("transparent").bgColor,hoverBgColor:t?(0,d.tremorTwMerge)((0,c.getColorClassNames)(t,m.colorPalette.background).hoverBgColor,"hover:bg-opacity-20 dark:hover:bg-opacity-20"):"hover:bg-tremor-brand-faint dark:hover:bg-dark-tremor-brand-faint",borderColor:t?(0,c.getColorClassNames)(t,m.colorPalette.border).borderColor:"border-tremor-brand dark:border-dark-tremor-brand"};case"light":return{textColor:t?(0,c.getColorClassNames)(t,m.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",hoverTextColor:t?(0,c.getColorClassNames)(t,m.colorPalette.darkText).hoverTextColor:"hover:text-tremor-brand-emphasis dark:hover:text-dark-tremor-brand-emphasis",bgColor:(0,c.getColorClassNames)("transparent").bgColor,borderColor:"",hoverBorderColor:""}}},f=(0,c.makeClassName)("Button"),b=({loading:e,iconSize:t,iconPosition:r,Icon:l,needMargin:o,transitionStatus:s})=>{let i=o?r===n.HorizontalPositions.Left?(0,d.tremorTwMerge)("-ml-1","mr-1.5"):(0,d.tremorTwMerge)("-mr-1","ml-1.5"):"",c=(0,d.tremorTwMerge)("w-0 h-0"),m={default:c,entering:c,entered:t,exiting:t,exited:c};return e?a.default.createElement(u,{className:(0,d.tremorTwMerge)(f("icon"),"animate-spin shrink-0",i,m.default,m[s]),style:{transition:"width 150ms"}}):a.default.createElement(l,{className:(0,d.tremorTwMerge)(f("icon"),"shrink-0",t,i)})},h=a.default.forwardRef((e,l)=>{let{icon:u,iconPosition:m=n.HorizontalPositions.Left,size:h=n.Sizes.SM,color:x,variant:v="primary",disabled:C,loading:y=!1,loadingText:k,children:w,tooltip:A,className:N}=e,j=(0,t.__rest)(e,["icon","iconPosition","size","color","variant","disabled","loading","loadingText","children","tooltip","className"]),_=y||C,T=void 0!==u||y,E=y&&k,I=!(!w&&!E),O=(0,d.tremorTwMerge)(g[h].height,g[h].width),M="light"!==v?(0,d.tremorTwMerge)("rounded-tremor-default border","shadow-tremor-input","dark:shadow-dark-tremor-input"):"",S=p(v,x),$=("light"!==v?{xs:{paddingX:"px-2.5",paddingY:"py-1.5",fontSize:"text-xs"},sm:{paddingX:"px-4",paddingY:"py-2",fontSize:"text-sm"},md:{paddingX:"px-4",paddingY:"py-2",fontSize:"text-md"},lg:{paddingX:"px-4",paddingY:"py-2.5",fontSize:"text-lg"},xl:{paddingX:"px-4",paddingY:"py-3",fontSize:"text-xl"}}:{xs:{paddingX:"",paddingY:"",fontSize:"text-xs"},sm:{paddingX:"",paddingY:"",fontSize:"text-sm"},md:{paddingX:"",paddingY:"",fontSize:"text-md"},lg:{paddingX:"",paddingY:"",fontSize:"text-lg"},xl:{paddingX:"",paddingY:"",fontSize:"text-xl"}})[h],{tooltipProps:R,getReferenceProps:L}=(0,r.useTooltip)(300),[P,B]=(({enter:e=!0,exit:t=!0,preEnter:r,preExit:l,timeout:n,initialEntered:d,mountOnEnter:c,unmountOnExit:u,onStateChange:m}={})=>{let[g,p]=(0,a.useState)(()=>o(d?2:s(c))),f=(0,a.useRef)(g),b=(0,a.useRef)(0),[h,x]="object"==typeof n?[n.enter,n.exit]:[n,n],v=(0,a.useCallback)(()=>{let e=((e,t)=>{switch(e){case 1:case 0:return 2;case 4:case 3:return s(t)}})(f.current._s,u);e&&i(e,p,f,b,m)},[m,u]);return[g,(0,a.useCallback)(a=>{let o=e=>{switch(i(e,p,f,b,m),e){case 1:h>=0&&(b.current=((...e)=>setTimeout(...e))(v,h));break;case 4:x>=0&&(b.current=((...e)=>setTimeout(...e))(v,x));break;case 0:case 3:b.current=((...e)=>setTimeout(...e))(()=>{isNaN(document.body.offsetTop)||o(e+1)},0)}},n=f.current.isEnter;"boolean"!=typeof a&&(a=!n),a?n||o(e?+!r:2):n&&o(t?l?3:4:s(u))},[v,m,e,t,r,l,h,x,u]),v]})({timeout:50});return(0,a.useEffect)(()=>{B(y)},[y]),a.default.createElement("button",Object.assign({ref:(0,c.mergeRefs)([l,R.refs.setReference]),className:(0,d.tremorTwMerge)(f("root"),"shrink-0 inline-flex justify-center items-center group font-medium outline-none",M,$.paddingX,$.paddingY,$.fontSize,S.textColor,S.bgColor,S.borderColor,S.hoverBorderColor,_?"opacity-50 cursor-not-allowed":(0,d.tremorTwMerge)(p(v,x).hoverTextColor,p(v,x).hoverBgColor,p(v,x).hoverBorderColor),N),disabled:_},L,j),a.default.createElement(r.default,Object.assign({text:A},R)),T&&m!==n.HorizontalPositions.Right?a.default.createElement(b,{loading:y,iconSize:O,iconPosition:m,Icon:u,transitionStatus:P.status,needMargin:I}):null,E||w?a.default.createElement("span",{className:(0,d.tremorTwMerge)(f("text"),"text-tremor-default whitespace-nowrap")},E?k:w):null,T&&m===n.HorizontalPositions.Right?a.default.createElement(b,{loading:y,iconSize:O,iconPosition:m,Icon:u,transitionStatus:P.status,needMargin:I}):null)});h.displayName="Button",e.s(["Button",()=>h],994388)},185793,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(242064),l=e.i(529681);let o=e=>{let{prefixCls:a,className:l,style:o,size:s,shape:i}=e,n=(0,r.default)({[`${a}-lg`]:"large"===s,[`${a}-sm`]:"small"===s}),d=(0,r.default)({[`${a}-circle`]:"circle"===i,[`${a}-square`]:"square"===i,[`${a}-round`]:"round"===i}),c=t.useMemo(()=>"number"==typeof s?{width:s,height:s,lineHeight:`${s}px`}:{},[s]);return t.createElement("span",{className:(0,r.default)(a,n,d,l),style:Object.assign(Object.assign({},c),o)})};e.i(296059);var s=e.i(694758),i=e.i(915654),n=e.i(246422),d=e.i(838378);let c=new s.Keyframes("ant-skeleton-loading",{"0%":{backgroundPosition:"100% 50%"},"100%":{backgroundPosition:"0 50%"}}),u=e=>({height:e,lineHeight:(0,i.unit)(e)}),m=e=>Object.assign({width:e},u(e)),g=(e,t)=>Object.assign({width:t(e).mul(5).equal(),minWidth:t(e).mul(5).equal()},u(e)),p=e=>Object.assign({width:e},u(e)),f=(e,t,r)=>{let{skeletonButtonCls:a}=e;return{[`${r}${a}-circle`]:{width:t,minWidth:t,borderRadius:"50%"},[`${r}${a}-round`]:{borderRadius:t}}},b=(e,t)=>Object.assign({width:t(e).mul(2).equal(),minWidth:t(e).mul(2).equal()},u(e)),h=(0,n.genStyleHooks)("Skeleton",e=>{let{componentCls:t,calc:r}=e;return(e=>{let{componentCls:t,skeletonAvatarCls:r,skeletonTitleCls:a,skeletonParagraphCls:l,skeletonButtonCls:o,skeletonInputCls:s,skeletonImageCls:i,controlHeight:n,controlHeightLG:d,controlHeightSM:u,gradientFromColor:h,padding:x,marginSM:v,borderRadius:C,titleHeight:y,blockRadius:k,paragraphLiHeight:w,controlHeightXS:A,paragraphMarginTop:N}=e;return{[t]:{display:"table",width:"100%",[`${t}-header`]:{display:"table-cell",paddingInlineEnd:x,verticalAlign:"top",[r]:Object.assign({display:"inline-block",verticalAlign:"top",background:h},m(n)),[`${r}-circle`]:{borderRadius:"50%"},[`${r}-lg`]:Object.assign({},m(d)),[`${r}-sm`]:Object.assign({},m(u))},[`${t}-content`]:{display:"table-cell",width:"100%",verticalAlign:"top",[a]:{width:"100%",height:y,background:h,borderRadius:k,[`+ ${l}`]:{marginBlockStart:u}},[l]:{padding:0,"> li":{width:"100%",height:w,listStyle:"none",background:h,borderRadius:k,"+ li":{marginBlockStart:A}}},[`${l}> li:last-child:not(:first-child):not(:nth-child(2))`]:{width:"61%"}},[`&-round ${t}-content`]:{[`${a}, ${l} > li`]:{borderRadius:C}}},[`${t}-with-avatar ${t}-content`]:{[a]:{marginBlockStart:v,[`+ ${l}`]:{marginBlockStart:N}}},[`${t}${t}-element`]:Object.assign(Object.assign(Object.assign(Object.assign({display:"inline-block",width:"auto"},(e=>{let{borderRadiusSM:t,skeletonButtonCls:r,controlHeight:a,controlHeightLG:l,controlHeightSM:o,gradientFromColor:s,calc:i}=e;return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({[r]:Object.assign({display:"inline-block",verticalAlign:"top",background:s,borderRadius:t,width:i(a).mul(2).equal(),minWidth:i(a).mul(2).equal()},b(a,i))},f(e,a,r)),{[`${r}-lg`]:Object.assign({},b(l,i))}),f(e,l,`${r}-lg`)),{[`${r}-sm`]:Object.assign({},b(o,i))}),f(e,o,`${r}-sm`))})(e)),(e=>{let{skeletonAvatarCls:t,gradientFromColor:r,controlHeight:a,controlHeightLG:l,controlHeightSM:o}=e;return{[t]:Object.assign({display:"inline-block",verticalAlign:"top",background:r},m(a)),[`${t}${t}-circle`]:{borderRadius:"50%"},[`${t}${t}-lg`]:Object.assign({},m(l)),[`${t}${t}-sm`]:Object.assign({},m(o))}})(e)),(e=>{let{controlHeight:t,borderRadiusSM:r,skeletonInputCls:a,controlHeightLG:l,controlHeightSM:o,gradientFromColor:s,calc:i}=e;return{[a]:Object.assign({display:"inline-block",verticalAlign:"top",background:s,borderRadius:r},g(t,i)),[`${a}-lg`]:Object.assign({},g(l,i)),[`${a}-sm`]:Object.assign({},g(o,i))}})(e)),(e=>{let{skeletonImageCls:t,imageSizeBase:r,gradientFromColor:a,borderRadiusSM:l,calc:o}=e;return{[t]:Object.assign(Object.assign({display:"inline-flex",alignItems:"center",justifyContent:"center",verticalAlign:"middle",background:a,borderRadius:l},p(o(r).mul(2).equal())),{[`${t}-path`]:{fill:"#bfbfbf"},[`${t}-svg`]:Object.assign(Object.assign({},p(r)),{maxWidth:o(r).mul(4).equal(),maxHeight:o(r).mul(4).equal()}),[`${t}-svg${t}-svg-circle`]:{borderRadius:"50%"}}),[`${t}${t}-circle`]:{borderRadius:"50%"}}})(e)),[`${t}${t}-block`]:{width:"100%",[o]:{width:"100%"},[s]:{width:"100%"}},[`${t}${t}-active`]:{[` +(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,916925,e=>{"use strict";var t,r=((t={}).A2A_Agent="A2A Agent",t.AI21="Ai21",t.AI21_CHAT="Ai21 Chat",t.AIML="AI/ML API",t.AIOHTTP_OPENAI="Aiohttp Openai",t.Anthropic="Anthropic",t.ANTHROPIC_TEXT="Anthropic Text",t.AssemblyAI="AssemblyAI",t.AUTO_ROUTER="Auto Router",t.Bedrock="Amazon Bedrock",t.BedrockMantle="Amazon Bedrock Mantle",t.SageMaker="AWS SageMaker",t.Azure="Azure",t.Azure_AI_Studio="Azure AI Foundry (Studio)",t.AZURE_TEXT="Azure Text",t.BASETEN="Baseten",t.BYTEZ="Bytez",t.Cerebras="Cerebras",t.CLARIFAI="Clarifai",t.CLOUDFLARE="Cloudflare",t.CODESTRAL="Codestral",t.Cohere="Cohere",t.COHERE_CHAT="Cohere Chat",t.COMETAPI="Cometapi",t.COMPACTIFAI="Compactifai",t.Cursor="Cursor",t.Dashscope="Dashscope",t.Databricks="Databricks (Qwen API)",t.DATAROBOT="Datarobot",t.DeepInfra="DeepInfra",t.Deepgram="Deepgram",t.Deepseek="Deepseek",t.DOCKER_MODEL_RUNNER="Docker Model Runner",t.DOTPROMPT="Dotprompt",t.ElevenLabs="ElevenLabs",t.EMPOWER="Empower",t.FalAI="Fal AI",t.FEATHERLESS_AI="Featherless Ai",t.FireworksAI="Fireworks AI",t.FRIENDLIAI="Friendliai",t.GALADRIEL="Galadriel",t.GITHUB_COPILOT="Github Copilot",t.Google_AI_Studio="Google AI Studio",t.GradientAI="GradientAI",t.Groq="Groq",t.HEROKU="Heroku",t.Hosted_Vllm="vllm",t.HUGGINGFACE="Huggingface",t.HYPERBOLIC="Hyperbolic",t.Infinity="Infinity",t.JinaAI="Jina AI",t.LAMBDA_AI="Lambda Ai",t.LEMONADE="Lemonade",t.LLAMAFILE="Llamafile",t.LM_STUDIO="Lm Studio",t.LLAMA="Meta Llama",t.MARITALK="Maritalk",t.MiniMax="MiniMax",t.MistralAI="Mistral AI",t.MOONSHOT="Moonshot",t.MORPH="Morph",t.NEBIUS="Nebius",t.NLP_CLOUD="Nlp Cloud",t.NOVITA="Novita",t.NSCALE="Nscale",t.NVIDIA_NIM="Nvidia Nim",t.Ollama="Ollama",t.OLLAMA_CHAT="Ollama Chat",t.OOBABOOGA="Oobabooga",t.OpenAI="OpenAI",t.OPENAI_LIKE="Openai Like",t.OpenAI_Compatible="OpenAI-Compatible Endpoints (Together AI, etc.)",t.OpenAI_Text="OpenAI Text Completion",t.OpenAI_Text_Compatible="OpenAI-Compatible Text Completion Models (Together AI, etc.)",t.Openrouter="Openrouter",t.Oracle="Oracle Cloud Infrastructure (OCI)",t.OVHCLOUD="Ovhcloud",t.Perplexity="Perplexity",t.PETALS="Petals",t.PG_VECTOR="Pg Vector",t.PREDIBASE="Predibase",t.RECRAFT="Recraft",t.REPLICATE="Replicate",t.RunwayML="RunwayML",t.SAGEMAKER_LEGACY="Sagemaker",t.Sambanova="Sambanova",t.SAP="SAP Generative AI Hub",t.Snowflake="Snowflake",t.TEXT_COMPLETION_CODESTRAL="Text-Completion-Codestral",t.TogetherAI="TogetherAI",t.TOPAZ="Topaz",t.Triton="Triton",t.V0="V0",t.VERCEL_AI_GATEWAY="Vercel Ai Gateway",t.Vertex_AI="Vertex AI (Anthropic, Gemini, etc.)",t.VERTEX_AI_BETA="Vertex Ai Beta",t.VLLM="Vllm",t.VolcEngine="VolcEngine",t.Voyage="Voyage AI",t.WANDB="Wandb",t.WATSONX="Watsonx",t.WATSONX_TEXT="Watsonx Text",t.xAI="xAI",t.XINFERENCE="Xinference",t);let a={A2A_Agent:"a2a_agent",AI21:"ai21",AI21_CHAT:"ai21_chat",AIML:"aiml",AIOHTTP_OPENAI:"aiohttp_openai",Anthropic:"anthropic",ANTHROPIC_TEXT:"anthropic_text",AssemblyAI:"assemblyai",AUTO_ROUTER:"auto_router",Azure:"azure",Azure_AI_Studio:"azure_ai",AZURE_TEXT:"azure_text",BASETEN:"baseten",Bedrock:"bedrock",BedrockMantle:"bedrock_mantle",BYTEZ:"bytez",Cerebras:"cerebras",CLARIFAI:"clarifai",CLOUDFLARE:"cloudflare",CODESTRAL:"codestral",Cohere:"cohere",COHERE_CHAT:"cohere_chat",COMETAPI:"cometapi",COMPACTIFAI:"compactifai",Cursor:"cursor",Dashscope:"dashscope",Databricks:"databricks",DATAROBOT:"datarobot",DeepInfra:"deepinfra",Deepgram:"deepgram",Deepseek:"deepseek",DOCKER_MODEL_RUNNER:"docker_model_runner",DOTPROMPT:"dotprompt",ElevenLabs:"elevenlabs",EMPOWER:"empower",FalAI:"fal_ai",FEATHERLESS_AI:"featherless_ai",FireworksAI:"fireworks_ai",FRIENDLIAI:"friendliai",GALADRIEL:"galadriel",GITHUB_COPILOT:"github_copilot",Google_AI_Studio:"gemini",GradientAI:"gradient_ai",Groq:"groq",HEROKU:"heroku",Hosted_Vllm:"hosted_vllm",HUGGINGFACE:"huggingface",HYPERBOLIC:"hyperbolic",Infinity:"infinity",JinaAI:"jina_ai",LAMBDA_AI:"lambda_ai",LEMONADE:"lemonade",LLAMAFILE:"llamafile",LLAMA:"meta_llama",LM_STUDIO:"lm_studio",MARITALK:"maritalk",MiniMax:"minimax",MistralAI:"mistral",MOONSHOT:"moonshot",MORPH:"morph",NEBIUS:"nebius",NLP_CLOUD:"nlp_cloud",NOVITA:"novita",NSCALE:"nscale",NVIDIA_NIM:"nvidia_nim",Ollama:"ollama",OLLAMA_CHAT:"ollama_chat",OOBABOOGA:"oobabooga",OpenAI:"openai",OPENAI_LIKE:"openai_like",OpenAI_Compatible:"openai",OpenAI_Text:"text-completion-openai",OpenAI_Text_Compatible:"text-completion-openai",Openrouter:"openrouter",Oracle:"oci",OVHCLOUD:"ovhcloud",Perplexity:"perplexity",PETALS:"petals",PG_VECTOR:"pg_vector",PREDIBASE:"predibase",RECRAFT:"recraft",REPLICATE:"replicate",RunwayML:"runwayml",SAGEMAKER_LEGACY:"sagemaker",SageMaker:"sagemaker_chat",Sambanova:"sambanova",SAP:"sap",Snowflake:"snowflake",TEXT_COMPLETION_CODESTRAL:"text-completion-codestral",TogetherAI:"together_ai",TOPAZ:"topaz",Triton:"triton",V0:"v0",VERCEL_AI_GATEWAY:"vercel_ai_gateway",Vertex_AI:"vertex_ai",VERTEX_AI_BETA:"vertex_ai_beta",VLLM:"vllm",VolcEngine:"volcengine",Voyage:"voyage",WANDB:"wandb",WATSONX:"watsonx",WATSONX_TEXT:"watsonx_text",xAI:"xai",XINFERENCE:"xinference"},l="../ui/assets/logos/",o={"A2A Agent":`${l}a2a_agent.png`,Ai21:`${l}ai21.svg`,"Ai21 Chat":`${l}ai21.svg`,"AI/ML API":`${l}aiml_api.svg`,"Aiohttp Openai":`${l}openai_small.svg`,Anthropic:`${l}anthropic.svg`,"Anthropic Text":`${l}anthropic.svg`,AssemblyAI:`${l}assemblyai_small.png`,Azure:`${l}microsoft_azure.svg`,"Azure AI Foundry (Studio)":`${l}microsoft_azure.svg`,"Azure Text":`${l}microsoft_azure.svg`,Baseten:`${l}baseten.svg`,"Amazon Bedrock":`${l}bedrock.svg`,"Amazon Bedrock Mantle":`${l}bedrock.svg`,"AWS SageMaker":`${l}bedrock.svg`,Cerebras:`${l}cerebras.svg`,Cloudflare:`${l}cloudflare.svg`,Codestral:`${l}mistral.svg`,Cohere:`${l}cohere.svg`,"Cohere Chat":`${l}cohere.svg`,Cometapi:`${l}cometapi.svg`,Cursor:`${l}cursor.svg`,"Databricks (Qwen API)":`${l}databricks.svg`,Dashscope:`${l}dashscope.svg`,Deepseek:`${l}deepseek.svg`,Deepgram:`${l}deepgram.png`,DeepInfra:`${l}deepinfra.png`,ElevenLabs:`${l}elevenlabs.png`,"Fal AI":`${l}fal_ai.jpg`,"Featherless Ai":`${l}featherless.svg`,"Fireworks AI":`${l}fireworks.svg`,Friendliai:`${l}friendli.svg`,"Github Copilot":`${l}github_copilot.svg`,"Google AI Studio":`${l}google.svg`,GradientAI:`${l}gradientai.svg`,Groq:`${l}groq.svg`,vllm:`${l}vllm.png`,Huggingface:`${l}huggingface.svg`,Hyperbolic:`${l}hyperbolic.svg`,Infinity:`${l}infinity.png`,"Jina AI":`${l}jina.png`,"Lambda Ai":`${l}lambda.svg`,"Lm Studio":`${l}lmstudio.svg`,"Meta Llama":`${l}meta_llama.svg`,MiniMax:`${l}minimax.svg`,"Mistral AI":`${l}mistral.svg`,Moonshot:`${l}moonshot.svg`,Morph:`${l}morph.svg`,Nebius:`${l}nebius.svg`,Novita:`${l}novita.svg`,"Nvidia Nim":`${l}nvidia_nim.svg`,Ollama:`${l}ollama.svg`,"Ollama Chat":`${l}ollama.svg`,Oobabooga:`${l}openai_small.svg`,OpenAI:`${l}openai_small.svg`,"Openai Like":`${l}openai_small.svg`,"OpenAI Text Completion":`${l}openai_small.svg`,"OpenAI-Compatible Text Completion Models (Together AI, etc.)":`${l}openai_small.svg`,"OpenAI-Compatible Endpoints (Together AI, etc.)":`${l}openai_small.svg`,Openrouter:`${l}openrouter.svg`,"Oracle Cloud Infrastructure (OCI)":`${l}oracle.svg`,Perplexity:`${l}perplexity-ai.svg`,Recraft:`${l}recraft.svg`,Replicate:`${l}replicate.svg`,RunwayML:`${l}runwayml.png`,Sagemaker:`${l}bedrock.svg`,Sambanova:`${l}sambanova.svg`,"SAP Generative AI Hub":`${l}sap.png`,Snowflake:`${l}snowflake.svg`,"Text-Completion-Codestral":`${l}mistral.svg`,TogetherAI:`${l}togetherai.svg`,Topaz:`${l}topaz.svg`,Triton:`${l}nvidia_triton.png`,V0:`${l}v0.svg`,"Vercel Ai Gateway":`${l}vercel.svg`,"Vertex AI (Anthropic, Gemini, etc.)":`${l}google.svg`,"Vertex Ai Beta":`${l}google.svg`,Vllm:`${l}vllm.png`,VolcEngine:`${l}volcengine.png`,"Voyage AI":`${l}voyage.webp`,Watsonx:`${l}watsonx.svg`,"Watsonx Text":`${l}watsonx.svg`,xAI:`${l}xai.svg`,Xinference:`${l}xinference.svg`};e.s(["Providers",()=>r,"getPlaceholder",0,e=>{if("AI/ML API"===e)return"aiml/flux-pro/v1.1";if("Vertex AI (Anthropic, Gemini, etc.)"===e)return"gemini-pro";if("Anthropic"==e)return"claude-3-opus";if("Amazon Bedrock"==e)return"claude-3-opus";if("AWS SageMaker"==e)return"sagemaker/jumpstart-dft-meta-textgeneration-llama-2-7b";else if("Google AI Studio"==e)return"gemini-pro";else if("Azure AI Foundry (Studio)"==e)return"azure_ai/command-r-plus";else if("Azure"==e)return"my-deployment";else if("Oracle Cloud Infrastructure (OCI)"==e)return"oci/xai.grok-4";else if("Snowflake"==e)return"snowflake/mistral-7b";else if("Voyage AI"==e)return"voyage/";else if("Jina AI"==e)return"jina_ai/";else if("VolcEngine"==e)return"volcengine/";else if("DeepInfra"==e)return"deepinfra/";else if("Fal AI"==e)return"fal_ai/fal-ai/flux-pro/v1.1-ultra";else if("RunwayML"==e)return"runwayml/gen4_turbo";else if("Watsonx"===e)return"watsonx/ibm/granite-3-3-8b-instruct";else if("Cursor"===e)return"cursor/claude-4-sonnet";else return"gpt-3.5-turbo"},"getProviderLogoAndName",0,e=>{if(!e)return{logo:"",displayName:"-"};if("gemini"===e.toLowerCase()){let e="Google AI Studio";return{logo:o[e],displayName:e}}let t=Object.keys(a).find(t=>a[t].toLowerCase()===e.toLowerCase());if(!t)return{logo:"",displayName:e};let l=r[t];return{logo:o[l],displayName:l}},"getProviderModels",0,(e,t)=>{console.log(`Provider key: ${e}`);let r=a[e];console.log(`Provider mapped to: ${r}`);let l=[];return e&&"object"==typeof t&&(Object.entries(t).forEach(([e,t])=>{if(null!==t&&"object"==typeof t&&"litellm_provider"in t){let a=t.litellm_provider;(a===r||"string"==typeof a&&a.includes(r))&&l.push(e)}}),"Cohere"==e&&(console.log("Adding cohere chat models"),Object.entries(t).forEach(([e,t])=>{null!==t&&"object"==typeof t&&"litellm_provider"in t&&"cohere_chat"===t.litellm_provider&&l.push(e)})),"AWS SageMaker"==e&&(console.log("Adding sagemaker chat models"),Object.entries(t).forEach(([e,t])=>{null!==t&&"object"==typeof t&&"litellm_provider"in t&&"sagemaker_chat"===t.litellm_provider&&l.push(e)}))),l},"providerLogoMap",0,o,"provider_map",0,a])},793130,e=>{"use strict";var t=e.i(290571),r=e.i(429427),a=e.i(371330),l=e.i(271645),o=e.i(394487),s=e.i(503269),i=e.i(214520),n=e.i(746725),d=e.i(914189),c=e.i(144279),u=e.i(294316),m=e.i(601893),g=e.i(140721),p=e.i(942803),b=e.i(233538),f=e.i(694421),h=e.i(700020),x=e.i(35889),v=e.i(998348),C=e.i(722678);let y=(0,l.createContext)(null);y.displayName="GroupContext";let k=l.Fragment,w=Object.assign((0,h.forwardRefWithAs)(function(e,t){var k;let w=(0,l.useId)(),A=(0,p.useProvidedId)(),N=(0,m.useDisabled)(),{id:j=A||`headlessui-switch-${w}`,disabled:_=N||!1,checked:T,defaultChecked:E,onChange:I,name:O,value:M,form:S,autoFocus:$=!1,...R}=e,L=(0,l.useContext)(y),[P,B]=(0,l.useState)(null),F=(0,l.useRef)(null),D=(0,u.useSyncRefs)(F,t,null===L?null:L.setSwitch,B),z=(0,i.useDefaultValue)(E),[H,G]=(0,s.useControllable)(T,I,null!=z&&z),V=(0,n.useDisposables)(),[q,X]=(0,l.useState)(!1),U=(0,d.useEvent)(()=>{X(!0),null==G||G(!H),V.nextFrame(()=>{X(!1)})}),W=(0,d.useEvent)(e=>{if((0,b.isDisabledReactIssue7711)(e.currentTarget))return e.preventDefault();e.preventDefault(),U()}),Y=(0,d.useEvent)(e=>{e.key===v.Keys.Space?(e.preventDefault(),U()):e.key===v.Keys.Enter&&(0,f.attemptSubmit)(e.currentTarget)}),K=(0,d.useEvent)(e=>e.preventDefault()),J=(0,C.useLabelledBy)(),Z=(0,x.useDescribedBy)(),{isFocusVisible:Q,focusProps:ee}=(0,r.useFocusRing)({autoFocus:$}),{isHovered:et,hoverProps:er}=(0,a.useHover)({isDisabled:_}),{pressed:ea,pressProps:el}=(0,o.useActivePress)({disabled:_}),eo=(0,l.useMemo)(()=>({checked:H,disabled:_,hover:et,focus:Q,active:ea,autofocus:$,changing:q}),[H,et,Q,ea,_,q,$]),es=(0,h.mergeProps)({id:j,ref:D,role:"switch",type:(0,c.useResolveButtonType)(e,P),tabIndex:-1===e.tabIndex?0:null!=(k=e.tabIndex)?k:0,"aria-checked":H,"aria-labelledby":J,"aria-describedby":Z,disabled:_||void 0,autoFocus:$,onClick:W,onKeyUp:Y,onKeyPress:K},ee,er,el),ei=(0,l.useCallback)(()=>{if(void 0!==z)return null==G?void 0:G(z)},[G,z]),en=(0,h.useRender)();return l.default.createElement(l.default.Fragment,null,null!=O&&l.default.createElement(g.FormFields,{disabled:_,data:{[O]:M||"on"},overrides:{type:"checkbox",checked:H},form:S,onReset:ei}),en({ourProps:es,theirProps:R,slot:eo,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var t;let[r,a]=(0,l.useState)(null),[o,s]=(0,C.useLabels)(),[i,n]=(0,x.useDescriptions)(),d=(0,l.useMemo)(()=>({switch:r,setSwitch:a}),[r,a]),c=(0,h.useRender)();return l.default.createElement(n,{name:"Switch.Description",value:i},l.default.createElement(s,{name:"Switch.Label",value:o,props:{htmlFor:null==(t=d.switch)?void 0:t.id,onClick(e){r&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),r.click(),r.focus({preventScroll:!0}))}}},l.default.createElement(y.Provider,{value:d},c({ourProps:{},theirProps:e,slot:{},defaultTag:k,name:"Switch.Group"}))))},Label:C.Label,Description:x.Description});var A=e.i(888288),N=e.i(95779),j=e.i(444755),_=e.i(673706),T=e.i(829087);let E=(0,_.makeClassName)("Switch"),I=l.default.forwardRef((e,r)=>{let{checked:a,defaultChecked:o=!1,onChange:s,color:i,name:n,error:d,errorMessage:c,disabled:u,required:m,tooltip:g,id:p}=e,b=(0,t.__rest)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),f={bgColor:i?(0,_.getColorClassNames)(i,N.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:i?(0,_.getColorClassNames)(i,N.colorPalette.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[h,x]=(0,A.default)(o,a),[v,C]=(0,l.useState)(!1),{tooltipProps:y,getReferenceProps:k}=(0,T.useTooltip)(300);return l.default.createElement("div",{className:"flex flex-row items-center justify-start"},l.default.createElement(T.default,Object.assign({text:g},y)),l.default.createElement("div",Object.assign({ref:(0,_.mergeRefs)([r,y.refs.setReference]),className:(0,j.tremorTwMerge)(E("root"),"flex flex-row relative h-5")},b,k),l.default.createElement("input",{type:"checkbox",className:(0,j.tremorTwMerge)(E("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:n,required:m,checked:h,onChange:e=>{e.preventDefault()}}),l.default.createElement(w,{checked:h,onChange:e=>{x(e),null==s||s(e)},disabled:u,className:(0,j.tremorTwMerge)(E("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:()=>C(!0),onBlur:()=>C(!1),id:p},l.default.createElement("span",{className:(0,j.tremorTwMerge)(E("sr-only"),"sr-only")},"Switch ",h?"on":"off"),l.default.createElement("span",{"aria-hidden":"true",className:(0,j.tremorTwMerge)(E("background"),h?f.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.default.createElement("span",{"aria-hidden":"true",className:(0,j.tremorTwMerge)(E("round"),h?(0,j.tremorTwMerge)(f.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,j.tremorTwMerge)("ring-2",f.ringColor):"")}))),d&&c?l.default.createElement("p",{className:(0,j.tremorTwMerge)(E("errorMessage"),"text-sm text-red-500 mt-1 ")},c):null)});I.displayName="Switch",e.s(["Switch",()=>I],793130)},653496,e=>{"use strict";var t=e.i(721369);e.s(["Tabs",()=>t.default])},689020,e=>{"use strict";var t=e.i(764205);let r=async e=>{try{let r=await (0,t.modelHubCall)(e);if(console.log("model_info:",r),r?.data.length>0){let e=r.data.map(e=>({model_group:e.model_group,mode:e?.mode}));return e.sort((e,t)=>e.model_group.localeCompare(t.model_group)),e}return[]}catch(e){throw console.error("Error fetching model info:",e),e}};e.s(["fetchAvailableModels",0,r])},107233,37727,e=>{"use strict";var t=e.i(603908);e.s(["Plus",()=>t.default],107233);var r=e.i(841947);e.s(["X",()=>r.default],37727)},361653,e=>{"use strict";let t=(0,e.i(475254).default)("circle-alert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);e.s(["default",()=>t])},603908,e=>{"use strict";let t=(0,e.i(475254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);e.s(["default",()=>t])},841947,e=>{"use strict";let t=(0,e.i(475254).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["default",()=>t])},158392,419470,e=>{"use strict";var t=e.i(843476),r=e.i(779241);let a={ttl:3600,lowest_latency_buffer:0},l=({routingStrategyArgs:e})=>{let l={ttl:"Sliding window to look back over when calculating the average latency of a deployment. Default - 1 hour (in seconds).",lowest_latency_buffer:"Shuffle between deployments within this % of the lowest latency. Default - 0 (i.e. always pick lowest latency)."};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Latency-Based Configuration"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Fine-tune latency-based routing behavior"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e||a).map(([e,a])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:e.replace(/_/g," ")}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l[e]||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:"object"==typeof a?JSON.stringify(a,null,2):a?.toString(),className:"font-mono text-sm w-full"})]})},e))})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"})]})},o=({routerSettings:e,routerFieldsMetadata:a})=>(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Reliability & Retries"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure retry logic and failure handling"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e).filter(([e,t])=>"fallbacks"!=e&&"context_window_fallbacks"!=e&&"routing_strategy_args"!=e&&"routing_strategy"!=e&&"enable_tag_filtering"!=e).map(([e,l])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:a[e]?.ui_field_name||e}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:a[e]?.field_description||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:null==l||"null"===l?"":"object"==typeof l?JSON.stringify(l,null,2):l?.toString()||"",placeholder:"—",className:"font-mono text-sm w-full"})]})},e))})]});var s=e.i(199133);let i=({selectedStrategy:e,availableStrategies:r,routingStrategyDescriptions:a,routerFieldsMetadata:l,onStrategyChange:o})=>(0,t.jsxs)("div",{className:"space-y-2 max-w-3xl",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:l.routing_strategy?.ui_field_name||"Routing Strategy"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l.routing_strategy?.field_description||""})]}),(0,t.jsx)("div",{className:"routing-strategy-select max-w-3xl",children:(0,t.jsx)(s.Select,{value:e,onChange:o,style:{width:"100%"},size:"large",children:r.map(e=>(0,t.jsx)(s.Select.Option,{value:e,label:e,children:(0,t.jsxs)("div",{className:"flex flex-col gap-0.5 py-1",children:[(0,t.jsx)("span",{className:"font-mono text-sm font-medium",children:e}),a[e]&&(0,t.jsx)("span",{className:"text-xs text-gray-500 font-normal",children:a[e]})]})},e))})})]});var n=e.i(793130);let d=({enabled:e,routerFieldsMetadata:r,onToggle:a})=>(0,t.jsx)("div",{className:"space-y-3 max-w-3xl",children:(0,t.jsxs)("div",{className:"flex items-start justify-between",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:r.enable_tag_filtering?.ui_field_name||"Enable Tag Filtering"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500 mt-0.5",children:[r.enable_tag_filtering?.field_description||"",r.enable_tag_filtering?.link&&(0,t.jsxs)(t.Fragment,{children:[" ",(0,t.jsx)("a",{href:r.enable_tag_filtering.link,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline",children:"Learn more"})]})]})]}),(0,t.jsx)(n.Switch,{checked:e,onChange:a,className:"ml-4"})]})});e.s(["default",0,({value:e,onChange:r,routerFieldsMetadata:a,availableRoutingStrategies:s,routingStrategyDescriptions:n})=>(0,t.jsxs)("div",{className:"w-full space-y-8 py-2",children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Routing Settings"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure how requests are routed to deployments"})]}),s.length>0&&(0,t.jsx)(i,{selectedStrategy:e.selectedStrategy||e.routerSettings.routing_strategy||null,availableStrategies:s,routingStrategyDescriptions:n,routerFieldsMetadata:a,onStrategyChange:t=>{r({...e,selectedStrategy:t})}}),(0,t.jsx)(d,{enabled:e.enableTagFiltering,routerFieldsMetadata:a,onToggle:t=>{r({...e,enableTagFiltering:t})}})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),"latency-based-routing"===e.selectedStrategy&&(0,t.jsx)(l,{routingStrategyArgs:e.routerSettings.routing_strategy_args}),(0,t.jsx)(o,{routerSettings:e.routerSettings,routerFieldsMetadata:a})]})],158392);var c=e.i(994388),u=e.i(998573),m=e.i(653496),g=e.i(107233),p=e.i(271645),b=e.i(592968),f=e.i(361653),f=f;let h=(0,e.i(475254).default)("arrow-down",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var x=e.i(37727);function v({group:e,onChange:r,availableModels:a,maxFallbacks:l}){let o=a.filter(t=>t!==e.primaryModel),i=e.fallbackModels.length{let a=[...e.fallbackModels];a.includes(t)&&(a=a.filter(e=>e!==t)),r({...e,primaryModel:t,fallbackModels:a})},showSearch:!0,getPopupContainer:e=>e.parentElement||document.body,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase()),options:a.map(e=>({label:e,value:e}))}),!e.primaryModel&&(0,t.jsxs)("div",{className:"mt-2 flex items-center gap-2 text-amber-600 text-xs bg-amber-50 p-2 rounded",children:[(0,t.jsx)(f.default,{className:"w-4 h-4"}),(0,t.jsx)("span",{children:"Select a model to begin configuring fallbacks"})]})]}),(0,t.jsx)("div",{className:"flex items-center justify-center -my-4 z-10",children:(0,t.jsxs)("div",{className:"bg-indigo-50 text-indigo-500 px-4 py-1 rounded-full text-xs font-bold border border-indigo-100 flex items-center gap-2 shadow-sm",children:[(0,t.jsx)(h,{className:"w-4 h-4"}),"IF FAILS, TRY..."]})}),(0,t.jsxs)("div",{className:`transition-opacity duration-300 ${!e.primaryModel?"opacity-50 pointer-events-none":"opacity-100"}`,children:[(0,t.jsxs)("label",{className:"block text-sm font-semibold text-gray-700 mb-2",children:["Fallback Chain ",(0,t.jsx)("span",{className:"text-red-500",children:"*"}),(0,t.jsxs)("span",{className:"text-xs text-gray-500 font-normal ml-2",children:["(Max ",l," fallbacks at a time)"]})]}),(0,t.jsxs)("div",{className:"bg-gray-50 rounded-xl p-4 border border-gray-200",children:[(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(s.Select,{mode:"multiple",className:"w-full",size:"large",placeholder:i?"Select fallback models to add...":`Maximum ${l} fallbacks reached`,value:e.fallbackModels,onChange:t=>{let a=t.slice(0,l);r({...e,fallbackModels:a})},disabled:!e.primaryModel,getPopupContainer:e=>e.parentElement||document.body,options:o.map(e=>({label:e,value:e})),optionRender:(r,a)=>{let l=e.fallbackModels.includes(r.value),o=l?e.fallbackModels.indexOf(r.value)+1:null;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[l&&null!==o&&(0,t.jsx)("span",{className:"flex items-center justify-center w-5 h-5 rounded bg-indigo-100 text-indigo-600 text-xs font-bold",children:o}),(0,t.jsx)("span",{children:r.label})]})},maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(b.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})}),showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase())}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1 ml-1",children:i?`Search and select multiple models. Selected models will appear below in order. (${e.fallbackModels.length}/${l} used)`:`Maximum ${l} fallbacks reached. Remove some to add more.`})]}),(0,t.jsx)("div",{className:"space-y-2 min-h-[100px]",children:0===e.fallbackModels.length?(0,t.jsxs)("div",{className:"h-32 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)("span",{className:"text-sm",children:"No fallback models selected"}),(0,t.jsx)("span",{className:"text-xs mt-1",children:"Add models from the dropdown above"})]}):e.fallbackModels.map((a,l)=>(0,t.jsxs)("div",{className:"group flex items-center justify-between p-3 bg-white rounded-lg border border-gray-200 hover:border-indigo-300 hover:shadow-sm transition-all",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex items-center justify-center w-6 h-6 rounded bg-gray-100 text-gray-400 group-hover:text-indigo-500 group-hover:bg-indigo-50",children:(0,t.jsx)("span",{className:"text-xs font-bold",children:l+1})}),(0,t.jsx)("div",{children:(0,t.jsx)("span",{className:"font-medium text-gray-800",children:a})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>{let t;return t=e.fallbackModels.filter((e,t)=>t!==l),void r({...e,fallbackModels:t})},className:"opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500 p-1",children:(0,t.jsx)(x.X,{className:"w-4 h-4"})})]},`${a}-${l}`))})]})]})]})}function C({groups:e,onGroupsChange:r,availableModels:a,maxFallbacks:l=10,maxGroups:o=5}){let[s,i]=(0,p.useState)(e.length>0?e[0].id:"1");(0,p.useEffect)(()=>{e.length>0?e.some(e=>e.id===s)||i(e[0].id):i("1")},[e]);let n=()=>{if(e.length>=o)return;let t=Date.now().toString();r([...e,{id:t,primaryModel:null,fallbackModels:[]}]),i(t)},d=t=>{r(e.map(e=>e.id===t.id?t:e))},b=e.map((r,o)=>{let s=r.primaryModel?r.primaryModel:`Group ${o+1}`;return{key:r.id,label:s,closable:e.length>1,children:(0,t.jsx)(v,{group:r,onChange:d,availableModels:a,maxFallbacks:l})}});return 0===e.length?(0,t.jsxs)("div",{className:"text-center py-12 bg-gray-50 rounded-lg border border-dashed border-gray-300",children:[(0,t.jsx)("p",{className:"text-gray-500 mb-4",children:"No fallback groups configured"}),(0,t.jsx)(c.Button,{variant:"primary",onClick:n,icon:()=>(0,t.jsx)(g.Plus,{className:"w-4 h-4"}),children:"Create First Group"})]}):(0,t.jsx)(m.Tabs,{type:"editable-card",activeKey:s,onChange:i,onEdit:(t,a)=>{"add"===a?n():"remove"===a&&e.length>1&&(t=>{if(1===e.length)return u.message.warning("At least one group is required");let a=e.filter(e=>e.id!==t);r(a),s===t&&a.length>0&&i(a[a.length-1].id)})(t)},items:b,className:"fallback-tabs",tabBarStyle:{marginBottom:0},hideAdd:e.length>=o})}e.s(["FallbackSelectionForm",()=>C],419470)},68155,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.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"}))});e.s(["TrashIcon",0,r],68155)},599724,936325,e=>{"use strict";var t=e.i(95779),r=e.i(444755),a=e.i(673706),l=e.i(271645);let o=l.default.forwardRef((e,o)=>{let{color:s,className:i,children:n}=e;return l.default.createElement("p",{ref:o,className:(0,r.tremorTwMerge)("text-tremor-default",s?(0,a.getColorClassNames)(s,t.colorPalette.text).textColor:(0,r.tremorTwMerge)("text-tremor-content","dark:text-dark-tremor-content"),i)},n)});o.displayName="Text",e.s(["default",()=>o],936325),e.s(["Text",()=>o],599724)},304967,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(480731),l=e.i(95779),o=e.i(444755),s=e.i(673706);let i=(0,s.makeClassName)("Card"),n=r.default.forwardRef((e,n)=>{let{decoration:d="",decorationColor:c,children:u,className:m}=e,g=(0,t.__rest)(e,["decoration","decorationColor","children","className"]);return r.default.createElement("div",Object.assign({ref:n,className:(0,o.tremorTwMerge)(i("root"),"relative w-full text-left ring-1 rounded-tremor-default p-6","bg-tremor-background ring-tremor-ring shadow-tremor-card","dark:bg-dark-tremor-background dark:ring-dark-tremor-ring dark:shadow-dark-tremor-card",c?(0,s.getColorClassNames)(c,l.colorPalette.border).borderColor:"border-tremor-brand dark:border-dark-tremor-brand",(e=>{if(!e)return"";switch(e){case a.HorizontalPositions.Left:return"border-l-4";case a.VerticalPositions.Top:return"border-t-4";case a.HorizontalPositions.Right:return"border-r-4";case a.VerticalPositions.Bottom:return"border-b-4";default:return""}})(d),m)},g),u)});n.displayName="Card",e.s(["Card",()=>n],304967)},994388,e=>{"use strict";var t=e.i(290571),r=e.i(829087),a=e.i(271645);let l=["preEnter","entering","entered","preExit","exiting","exited","unmounted"],o=e=>({_s:e,status:l[e],isEnter:e<3,isMounted:6!==e,isResolved:2===e||e>4}),s=e=>e?6:5,i=(e,t,r,a,l)=>{clearTimeout(a.current);let s=o(e);t(s),r.current=s,l&&l({current:s})};var n=e.i(480731),d=e.i(444755),c=e.i(673706);let u=e=>{var r=(0,t.__rest)(e,[]);return a.default.createElement("svg",Object.assign({},r,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"}),a.default.createElement("path",{fill:"none",d:"M0 0h24v24H0z"}),a.default.createElement("path",{d:"M18.364 5.636L16.95 7.05A7 7 0 1 0 19 12h2a9 9 0 1 1-2.636-6.364z"}))};var m=e.i(95779);let g={xs:{height:"h-4",width:"w-4"},sm:{height:"h-5",width:"w-5"},md:{height:"h-5",width:"w-5"},lg:{height:"h-6",width:"w-6"},xl:{height:"h-6",width:"w-6"}},p=(e,t)=>{switch(e){case"primary":return{textColor:t?(0,c.getColorClassNames)("white").textColor:"text-tremor-brand-inverted dark:text-dark-tremor-brand-inverted",hoverTextColor:t?(0,c.getColorClassNames)("white").textColor:"text-tremor-brand-inverted dark:text-dark-tremor-brand-inverted",bgColor:t?(0,c.getColorClassNames)(t,m.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",hoverBgColor:t?(0,c.getColorClassNames)(t,m.colorPalette.darkBackground).hoverBgColor:"hover:bg-tremor-brand-emphasis dark:hover:bg-dark-tremor-brand-emphasis",borderColor:t?(0,c.getColorClassNames)(t,m.colorPalette.border).borderColor:"border-tremor-brand dark:border-dark-tremor-brand",hoverBorderColor:t?(0,c.getColorClassNames)(t,m.colorPalette.darkBorder).hoverBorderColor:"hover:border-tremor-brand-emphasis dark:hover:border-dark-tremor-brand-emphasis"};case"secondary":return{textColor:t?(0,c.getColorClassNames)(t,m.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",hoverTextColor:t?(0,c.getColorClassNames)(t,m.colorPalette.text).textColor:"hover:text-tremor-brand-emphasis dark:hover:text-dark-tremor-brand-emphasis",bgColor:(0,c.getColorClassNames)("transparent").bgColor,hoverBgColor:t?(0,d.tremorTwMerge)((0,c.getColorClassNames)(t,m.colorPalette.background).hoverBgColor,"hover:bg-opacity-20 dark:hover:bg-opacity-20"):"hover:bg-tremor-brand-faint dark:hover:bg-dark-tremor-brand-faint",borderColor:t?(0,c.getColorClassNames)(t,m.colorPalette.border).borderColor:"border-tremor-brand dark:border-dark-tremor-brand"};case"light":return{textColor:t?(0,c.getColorClassNames)(t,m.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",hoverTextColor:t?(0,c.getColorClassNames)(t,m.colorPalette.darkText).hoverTextColor:"hover:text-tremor-brand-emphasis dark:hover:text-dark-tremor-brand-emphasis",bgColor:(0,c.getColorClassNames)("transparent").bgColor,borderColor:"",hoverBorderColor:""}}},b=(0,c.makeClassName)("Button"),f=({loading:e,iconSize:t,iconPosition:r,Icon:l,needMargin:o,transitionStatus:s})=>{let i=o?r===n.HorizontalPositions.Left?(0,d.tremorTwMerge)("-ml-1","mr-1.5"):(0,d.tremorTwMerge)("-mr-1","ml-1.5"):"",c=(0,d.tremorTwMerge)("w-0 h-0"),m={default:c,entering:c,entered:t,exiting:t,exited:c};return e?a.default.createElement(u,{className:(0,d.tremorTwMerge)(b("icon"),"animate-spin shrink-0",i,m.default,m[s]),style:{transition:"width 150ms"}}):a.default.createElement(l,{className:(0,d.tremorTwMerge)(b("icon"),"shrink-0",t,i)})},h=a.default.forwardRef((e,l)=>{let{icon:u,iconPosition:m=n.HorizontalPositions.Left,size:h=n.Sizes.SM,color:x,variant:v="primary",disabled:C,loading:y=!1,loadingText:k,children:w,tooltip:A,className:N}=e,j=(0,t.__rest)(e,["icon","iconPosition","size","color","variant","disabled","loading","loadingText","children","tooltip","className"]),_=y||C,T=void 0!==u||y,E=y&&k,I=!(!w&&!E),O=(0,d.tremorTwMerge)(g[h].height,g[h].width),M="light"!==v?(0,d.tremorTwMerge)("rounded-tremor-default border","shadow-tremor-input","dark:shadow-dark-tremor-input"):"",S=p(v,x),$=("light"!==v?{xs:{paddingX:"px-2.5",paddingY:"py-1.5",fontSize:"text-xs"},sm:{paddingX:"px-4",paddingY:"py-2",fontSize:"text-sm"},md:{paddingX:"px-4",paddingY:"py-2",fontSize:"text-md"},lg:{paddingX:"px-4",paddingY:"py-2.5",fontSize:"text-lg"},xl:{paddingX:"px-4",paddingY:"py-3",fontSize:"text-xl"}}:{xs:{paddingX:"",paddingY:"",fontSize:"text-xs"},sm:{paddingX:"",paddingY:"",fontSize:"text-sm"},md:{paddingX:"",paddingY:"",fontSize:"text-md"},lg:{paddingX:"",paddingY:"",fontSize:"text-lg"},xl:{paddingX:"",paddingY:"",fontSize:"text-xl"}})[h],{tooltipProps:R,getReferenceProps:L}=(0,r.useTooltip)(300),[P,B]=(({enter:e=!0,exit:t=!0,preEnter:r,preExit:l,timeout:n,initialEntered:d,mountOnEnter:c,unmountOnExit:u,onStateChange:m}={})=>{let[g,p]=(0,a.useState)(()=>o(d?2:s(c))),b=(0,a.useRef)(g),f=(0,a.useRef)(0),[h,x]="object"==typeof n?[n.enter,n.exit]:[n,n],v=(0,a.useCallback)(()=>{let e=((e,t)=>{switch(e){case 1:case 0:return 2;case 4:case 3:return s(t)}})(b.current._s,u);e&&i(e,p,b,f,m)},[m,u]);return[g,(0,a.useCallback)(a=>{let o=e=>{switch(i(e,p,b,f,m),e){case 1:h>=0&&(f.current=((...e)=>setTimeout(...e))(v,h));break;case 4:x>=0&&(f.current=((...e)=>setTimeout(...e))(v,x));break;case 0:case 3:f.current=((...e)=>setTimeout(...e))(()=>{isNaN(document.body.offsetTop)||o(e+1)},0)}},n=b.current.isEnter;"boolean"!=typeof a&&(a=!n),a?n||o(e?+!r:2):n&&o(t?l?3:4:s(u))},[v,m,e,t,r,l,h,x,u]),v]})({timeout:50});return(0,a.useEffect)(()=>{B(y)},[y]),a.default.createElement("button",Object.assign({ref:(0,c.mergeRefs)([l,R.refs.setReference]),className:(0,d.tremorTwMerge)(b("root"),"shrink-0 inline-flex justify-center items-center group font-medium outline-none",M,$.paddingX,$.paddingY,$.fontSize,S.textColor,S.bgColor,S.borderColor,S.hoverBorderColor,_?"opacity-50 cursor-not-allowed":(0,d.tremorTwMerge)(p(v,x).hoverTextColor,p(v,x).hoverBgColor,p(v,x).hoverBorderColor),N),disabled:_},L,j),a.default.createElement(r.default,Object.assign({text:A},R)),T&&m!==n.HorizontalPositions.Right?a.default.createElement(f,{loading:y,iconSize:O,iconPosition:m,Icon:u,transitionStatus:P.status,needMargin:I}):null,E||w?a.default.createElement("span",{className:(0,d.tremorTwMerge)(b("text"),"text-tremor-default whitespace-nowrap")},E?k:w):null,T&&m===n.HorizontalPositions.Right?a.default.createElement(f,{loading:y,iconSize:O,iconPosition:m,Icon:u,transitionStatus:P.status,needMargin:I}):null)});h.displayName="Button",e.s(["Button",()=>h],994388)},185793,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(242064),l=e.i(529681);let o=e=>{let{prefixCls:a,className:l,style:o,size:s,shape:i}=e,n=(0,r.default)({[`${a}-lg`]:"large"===s,[`${a}-sm`]:"small"===s}),d=(0,r.default)({[`${a}-circle`]:"circle"===i,[`${a}-square`]:"square"===i,[`${a}-round`]:"round"===i}),c=t.useMemo(()=>"number"==typeof s?{width:s,height:s,lineHeight:`${s}px`}:{},[s]);return t.createElement("span",{className:(0,r.default)(a,n,d,l),style:Object.assign(Object.assign({},c),o)})};e.i(296059);var s=e.i(694758),i=e.i(915654),n=e.i(246422),d=e.i(838378);let c=new s.Keyframes("ant-skeleton-loading",{"0%":{backgroundPosition:"100% 50%"},"100%":{backgroundPosition:"0 50%"}}),u=e=>({height:e,lineHeight:(0,i.unit)(e)}),m=e=>Object.assign({width:e},u(e)),g=(e,t)=>Object.assign({width:t(e).mul(5).equal(),minWidth:t(e).mul(5).equal()},u(e)),p=e=>Object.assign({width:e},u(e)),b=(e,t,r)=>{let{skeletonButtonCls:a}=e;return{[`${r}${a}-circle`]:{width:t,minWidth:t,borderRadius:"50%"},[`${r}${a}-round`]:{borderRadius:t}}},f=(e,t)=>Object.assign({width:t(e).mul(2).equal(),minWidth:t(e).mul(2).equal()},u(e)),h=(0,n.genStyleHooks)("Skeleton",e=>{let{componentCls:t,calc:r}=e;return(e=>{let{componentCls:t,skeletonAvatarCls:r,skeletonTitleCls:a,skeletonParagraphCls:l,skeletonButtonCls:o,skeletonInputCls:s,skeletonImageCls:i,controlHeight:n,controlHeightLG:d,controlHeightSM:u,gradientFromColor:h,padding:x,marginSM:v,borderRadius:C,titleHeight:y,blockRadius:k,paragraphLiHeight:w,controlHeightXS:A,paragraphMarginTop:N}=e;return{[t]:{display:"table",width:"100%",[`${t}-header`]:{display:"table-cell",paddingInlineEnd:x,verticalAlign:"top",[r]:Object.assign({display:"inline-block",verticalAlign:"top",background:h},m(n)),[`${r}-circle`]:{borderRadius:"50%"},[`${r}-lg`]:Object.assign({},m(d)),[`${r}-sm`]:Object.assign({},m(u))},[`${t}-content`]:{display:"table-cell",width:"100%",verticalAlign:"top",[a]:{width:"100%",height:y,background:h,borderRadius:k,[`+ ${l}`]:{marginBlockStart:u}},[l]:{padding:0,"> li":{width:"100%",height:w,listStyle:"none",background:h,borderRadius:k,"+ li":{marginBlockStart:A}}},[`${l}> li:last-child:not(:first-child):not(:nth-child(2))`]:{width:"61%"}},[`&-round ${t}-content`]:{[`${a}, ${l} > li`]:{borderRadius:C}}},[`${t}-with-avatar ${t}-content`]:{[a]:{marginBlockStart:v,[`+ ${l}`]:{marginBlockStart:N}}},[`${t}${t}-element`]:Object.assign(Object.assign(Object.assign(Object.assign({display:"inline-block",width:"auto"},(e=>{let{borderRadiusSM:t,skeletonButtonCls:r,controlHeight:a,controlHeightLG:l,controlHeightSM:o,gradientFromColor:s,calc:i}=e;return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({[r]:Object.assign({display:"inline-block",verticalAlign:"top",background:s,borderRadius:t,width:i(a).mul(2).equal(),minWidth:i(a).mul(2).equal()},f(a,i))},b(e,a,r)),{[`${r}-lg`]:Object.assign({},f(l,i))}),b(e,l,`${r}-lg`)),{[`${r}-sm`]:Object.assign({},f(o,i))}),b(e,o,`${r}-sm`))})(e)),(e=>{let{skeletonAvatarCls:t,gradientFromColor:r,controlHeight:a,controlHeightLG:l,controlHeightSM:o}=e;return{[t]:Object.assign({display:"inline-block",verticalAlign:"top",background:r},m(a)),[`${t}${t}-circle`]:{borderRadius:"50%"},[`${t}${t}-lg`]:Object.assign({},m(l)),[`${t}${t}-sm`]:Object.assign({},m(o))}})(e)),(e=>{let{controlHeight:t,borderRadiusSM:r,skeletonInputCls:a,controlHeightLG:l,controlHeightSM:o,gradientFromColor:s,calc:i}=e;return{[a]:Object.assign({display:"inline-block",verticalAlign:"top",background:s,borderRadius:r},g(t,i)),[`${a}-lg`]:Object.assign({},g(l,i)),[`${a}-sm`]:Object.assign({},g(o,i))}})(e)),(e=>{let{skeletonImageCls:t,imageSizeBase:r,gradientFromColor:a,borderRadiusSM:l,calc:o}=e;return{[t]:Object.assign(Object.assign({display:"inline-flex",alignItems:"center",justifyContent:"center",verticalAlign:"middle",background:a,borderRadius:l},p(o(r).mul(2).equal())),{[`${t}-path`]:{fill:"#bfbfbf"},[`${t}-svg`]:Object.assign(Object.assign({},p(r)),{maxWidth:o(r).mul(4).equal(),maxHeight:o(r).mul(4).equal()}),[`${t}-svg${t}-svg-circle`]:{borderRadius:"50%"}}),[`${t}${t}-circle`]:{borderRadius:"50%"}}})(e)),[`${t}${t}-block`]:{width:"100%",[o]:{width:"100%"},[s]:{width:"100%"}},[`${t}${t}-active`]:{[` ${a}, ${l} > li, ${r}, ${o}, ${s}, ${i} - `]:Object.assign({},{background:e.skeletonLoadingBackground,backgroundSize:"400% 100%",animationName:c,animationDuration:e.skeletonLoadingMotionDuration,animationTimingFunction:"ease",animationIterationCount:"infinite"})}}})((0,d.mergeToken)(e,{skeletonAvatarCls:`${t}-avatar`,skeletonTitleCls:`${t}-title`,skeletonParagraphCls:`${t}-paragraph`,skeletonButtonCls:`${t}-button`,skeletonInputCls:`${t}-input`,skeletonImageCls:`${t}-image`,imageSizeBase:r(e.controlHeight).mul(1.5).equal(),borderRadius:100,skeletonLoadingBackground:`linear-gradient(90deg, ${e.gradientFromColor} 25%, ${e.gradientToColor} 37%, ${e.gradientFromColor} 63%)`,skeletonLoadingMotionDuration:"1.4s"}))},e=>{let{colorFillContent:t,colorFill:r}=e;return{color:t,colorGradientEnd:r,gradientFromColor:t,gradientToColor:r,titleHeight:e.controlHeight/2,blockRadius:e.borderRadiusSM,paragraphMarginTop:e.marginLG+e.marginXXS,paragraphLiHeight:e.controlHeight/2}},{deprecatedTokens:[["color","gradientFromColor"],["colorGradientEnd","gradientToColor"]]}),x=e=>{let{prefixCls:a,className:l,style:o,rows:s=0}=e,i=Array.from({length:s}).map((r,a)=>t.createElement("li",{key:a,style:{width:((e,t)=>{let{width:r,rows:a=2}=t;return Array.isArray(r)?r[e]:a-1===e?r:void 0})(a,e)}}));return t.createElement("ul",{className:(0,r.default)(a,l),style:o},i)},v=({prefixCls:e,className:a,width:l,style:o})=>t.createElement("h3",{className:(0,r.default)(e,a),style:Object.assign({width:l},o)});function C(e){return e&&"object"==typeof e?e:{}}let y=e=>{let{prefixCls:l,loading:s,className:i,rootClassName:n,style:d,children:c,avatar:u=!1,title:m=!0,paragraph:g=!0,active:p,round:f}=e,{getPrefixCls:b,direction:y,className:k,style:w}=(0,a.useComponentConfig)("skeleton"),A=b("skeleton",l),[N,j,_]=h(A);if(s||!("loading"in e)){let e,a,l=!!u,s=!!m,c=!!g;if(l){let r=Object.assign(Object.assign({prefixCls:`${A}-avatar`},s&&!c?{size:"large",shape:"square"}:{size:"large",shape:"circle"}),C(u));e=t.createElement("div",{className:`${A}-header`},t.createElement(o,Object.assign({},r)))}if(s||c){let e,r;if(s){let r=Object.assign(Object.assign({prefixCls:`${A}-title`},!l&&c?{width:"38%"}:l&&c?{width:"50%"}:{}),C(m));e=t.createElement(v,Object.assign({},r))}if(c){let e,a=Object.assign(Object.assign({prefixCls:`${A}-paragraph`},(e={},l&&s||(e.width="61%"),!l&&s?e.rows=3:e.rows=2,e)),C(g));r=t.createElement(x,Object.assign({},a))}a=t.createElement("div",{className:`${A}-content`},e,r)}let b=(0,r.default)(A,{[`${A}-with-avatar`]:l,[`${A}-active`]:p,[`${A}-rtl`]:"rtl"===y,[`${A}-round`]:f},k,i,n,j,_);return N(t.createElement("div",{className:b,style:Object.assign(Object.assign({},w),d)},e,a))}return null!=c?c:null};y.Button=e=>{let{prefixCls:s,className:i,rootClassName:n,active:d,block:c=!1,size:u="default"}=e,{getPrefixCls:m}=t.useContext(a.ConfigContext),g=m("skeleton",s),[p,f,b]=h(g),x=(0,l.default)(e,["prefixCls"]),v=(0,r.default)(g,`${g}-element`,{[`${g}-active`]:d,[`${g}-block`]:c},i,n,f,b);return p(t.createElement("div",{className:v},t.createElement(o,Object.assign({prefixCls:`${g}-button`,size:u},x))))},y.Avatar=e=>{let{prefixCls:s,className:i,rootClassName:n,active:d,shape:c="circle",size:u="default"}=e,{getPrefixCls:m}=t.useContext(a.ConfigContext),g=m("skeleton",s),[p,f,b]=h(g),x=(0,l.default)(e,["prefixCls","className"]),v=(0,r.default)(g,`${g}-element`,{[`${g}-active`]:d},i,n,f,b);return p(t.createElement("div",{className:v},t.createElement(o,Object.assign({prefixCls:`${g}-avatar`,shape:c,size:u},x))))},y.Input=e=>{let{prefixCls:s,className:i,rootClassName:n,active:d,block:c,size:u="default"}=e,{getPrefixCls:m}=t.useContext(a.ConfigContext),g=m("skeleton",s),[p,f,b]=h(g),x=(0,l.default)(e,["prefixCls"]),v=(0,r.default)(g,`${g}-element`,{[`${g}-active`]:d,[`${g}-block`]:c},i,n,f,b);return p(t.createElement("div",{className:v},t.createElement(o,Object.assign({prefixCls:`${g}-input`,size:u},x))))},y.Image=e=>{let{prefixCls:l,className:o,rootClassName:s,style:i,active:n}=e,{getPrefixCls:d}=t.useContext(a.ConfigContext),c=d("skeleton",l),[u,m,g]=h(c),p=(0,r.default)(c,`${c}-element`,{[`${c}-active`]:n},o,s,m,g);return u(t.createElement("div",{className:p},t.createElement("div",{className:(0,r.default)(`${c}-image`,o),style:i},t.createElement("svg",{viewBox:"0 0 1098 1024",xmlns:"http://www.w3.org/2000/svg",className:`${c}-image-svg`},t.createElement("title",null,"Image placeholder"),t.createElement("path",{d:"M365.714286 329.142857q0 45.714286-32.036571 77.677714t-77.677714 32.036571-77.677714-32.036571-32.036571-77.677714 32.036571-77.677714 77.677714-32.036571 77.677714 32.036571 32.036571 77.677714zM950.857143 548.571429l0 256-804.571429 0 0-109.714286 182.857143-182.857143 91.428571 91.428571 292.571429-292.571429zM1005.714286 146.285714l-914.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 694.857143q0 7.460571 5.412571 12.873143t12.873143 5.412571l914.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143l0-694.857143q0-7.460571-5.412571-12.873143t-12.873143-5.412571zM1097.142857 164.571429l0 694.857143q0 37.741714-26.843429 64.585143t-64.585143 26.843429l-914.285714 0q-37.741714 0-64.585143-26.843429t-26.843429-64.585143l0-694.857143q0-37.741714 26.843429-64.585143t64.585143-26.843429l914.285714 0q37.741714 0 64.585143 26.843429t26.843429 64.585143z",className:`${c}-image-path`})))))},y.Node=e=>{let{prefixCls:l,className:o,rootClassName:s,style:i,active:n,children:d}=e,{getPrefixCls:c}=t.useContext(a.ConfigContext),u=c("skeleton",l),[m,g,p]=h(u),f=(0,r.default)(u,`${u}-element`,{[`${u}-active`]:n},g,o,s,p);return m(t.createElement("div",{className:f},t.createElement("div",{className:(0,r.default)(`${u}-image`,o),style:i},d)))},e.s(["default",0,y],185793)},959013,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let a={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"}},{tag:"path",attrs:{d:"M192 474h672q8 0 8 8v60q0 8-8 8H160q-8 0-8-8v-60q0-8 8-8z"}}]},name:"plus",theme:"outlined"};var l=e.i(9583),o=r.forwardRef(function(e,o){return r.createElement(l.default,(0,t.default)({},e,{ref:o,icon:a}))});e.s(["default",0,o],959013)},269200,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(444755);let l=(0,e.i(673706).makeClassName)("Table"),o=r.default.forwardRef((e,o)=>{let{children:s,className:i}=e,n=(0,t.__rest)(e,["children","className"]);return r.default.createElement("div",{className:(0,a.tremorTwMerge)(l("root"),"overflow-auto",i)},r.default.createElement("table",Object.assign({ref:o,className:(0,a.tremorTwMerge)(l("table"),"w-full text-tremor-default","text-tremor-content","dark:text-dark-tremor-content")},n),s))});o.displayName="Table",e.s(["Table",()=>o],269200)},427612,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableHead"),o=r.default.forwardRef((e,o)=>{let{children:s,className:i}=e,n=(0,t.__rest)(e,["children","className"]);return r.default.createElement(r.default.Fragment,null,r.default.createElement("thead",Object.assign({ref:o,className:(0,a.tremorTwMerge)(l("root"),"text-left","text-tremor-content","dark:text-dark-tremor-content",i)},n),s))});o.displayName="TableHead",e.s(["TableHead",()=>o],427612)},496020,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableRow"),o=r.default.forwardRef((e,o)=>{let{children:s,className:i}=e,n=(0,t.__rest)(e,["children","className"]);return r.default.createElement(r.default.Fragment,null,r.default.createElement("tr",Object.assign({ref:o,className:(0,a.tremorTwMerge)(l("row"),i)},n),s))});o.displayName="TableRow",e.s(["TableRow",()=>o],496020)},64848,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableHeaderCell"),o=r.default.forwardRef((e,o)=>{let{children:s,className:i}=e,n=(0,t.__rest)(e,["children","className"]);return r.default.createElement(r.default.Fragment,null,r.default.createElement("th",Object.assign({ref:o,className:(0,a.tremorTwMerge)(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)},n),s))});o.displayName="TableHeaderCell",e.s(["TableHeaderCell",()=>o],64848)},977572,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableCell"),o=r.default.forwardRef((e,o)=>{let{children:s,className:i}=e,n=(0,t.__rest)(e,["children","className"]);return r.default.createElement(r.default.Fragment,null,r.default.createElement("td",Object.assign({ref:o,className:(0,a.tremorTwMerge)(l("root"),"align-middle whitespace-nowrap text-left p-4",i)},n),s))});o.displayName="TableCell",e.s(["TableCell",()=>o],977572)},942232,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableBody"),o=r.default.forwardRef((e,o)=>{let{children:s,className:i}=e,n=(0,t.__rest)(e,["children","className"]);return r.default.createElement(r.default.Fragment,null,r.default.createElement("tbody",Object.assign({ref:o,className:(0,a.tremorTwMerge)(l("root"),"align-top divide-y","divide-tremor-border","dark:divide-dark-tremor-border",i)},n),s))});o.displayName="TableBody",e.s(["TableBody",()=>o],942232)},728889,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(829087),l=e.i(480731),o=e.i(444755),s=e.i(673706),i=e.i(95779);let n={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"}},d={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"}},c={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:""}},u=(0,s.makeClassName)("Icon"),m=r.default.forwardRef((e,m)=>{let{icon:g,variant:p="simple",tooltip:f,size:b=l.Sizes.SM,color:h,className:x}=e,v=(0,t.__rest)(e,["icon","variant","tooltip","size","color","className"]),C=((e,t)=>{switch(e){case"simple":return{textColor:t?(0,s.getColorClassNames)(t,i.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:"",borderColor:"",ringColor:""};case"light":return{textColor:t?(0,s.getColorClassNames)(t,i.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:t?(0,o.tremorTwMerge)((0,s.getColorClassNames)(t,i.colorPalette.background).bgColor,"bg-opacity-20"):"bg-tremor-brand-muted dark:bg-dark-tremor-brand-muted",borderColor:"",ringColor:""};case"shadow":return{textColor:t?(0,s.getColorClassNames)(t,i.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:t?(0,o.tremorTwMerge)((0,s.getColorClassNames)(t,i.colorPalette.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:t?(0,s.getColorClassNames)(t,i.colorPalette.text).textColor:"text-tremor-brand-inverted dark:text-dark-tremor-brand-inverted",bgColor:t?(0,o.tremorTwMerge)((0,s.getColorClassNames)(t,i.colorPalette.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:t?(0,s.getColorClassNames)(t,i.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:t?(0,o.tremorTwMerge)((0,s.getColorClassNames)(t,i.colorPalette.background).bgColor,"bg-opacity-20"):"bg-tremor-background dark:bg-dark-tremor-background",borderColor:t?(0,s.getColorClassNames)(t,i.colorPalette.ring).borderColor:"border-tremor-brand-subtle dark:border-dark-tremor-brand-subtle",ringColor:t?(0,o.tremorTwMerge)((0,s.getColorClassNames)(t,i.colorPalette.ring).ringColor,"ring-opacity-40"):"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"}}})(p,h),{tooltipProps:y,getReferenceProps:k}=(0,a.useTooltip)();return r.default.createElement("span",Object.assign({ref:(0,s.mergeRefs)([m,y.refs.setReference]),className:(0,o.tremorTwMerge)(u("root"),"inline-flex shrink-0 items-center justify-center",C.bgColor,C.textColor,C.borderColor,C.ringColor,c[p].rounded,c[p].border,c[p].shadow,c[p].ring,n[b].paddingX,n[b].paddingY,x)},k,v),r.default.createElement(a.default,Object.assign({text:f},y)),r.default.createElement(g,{className:(0,o.tremorTwMerge)(u("icon"),"shrink-0",d[b].height,d[b].width)}))});m.displayName="Icon",e.s(["default",()=>m],728889)},752978,e=>{"use strict";var t=e.i(728889);e.s(["Icon",()=>t.default])},122577,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.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"}),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M21 12a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlayIcon",0,r],122577)},418371,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(916925);e.s(["ProviderLogo",0,({provider:e,className:l="w-4 h-4"})=>{let[o,s]=(0,r.useState)(!1),{logo:i}=(0,a.getProviderLogoAndName)(e);return o||!i?(0,t.jsx)("div",{className:`${l} rounded-full bg-gray-200 flex items-center justify-center text-xs`,children:e?.charAt(0)||"-"}):(0,t.jsx)("img",{src:i,alt:`${e} logo`,className:l,onError:()=>s(!0)})}])},368670,e=>{"use strict";var t=e.i(764205),r=e.i(266027);let a=(0,e.i(243652).createQueryKeys)("modelCostMap");e.s(["useModelCostMap",0,()=>(0,r.useQuery)({queryKey:a.list({}),queryFn:async()=>await (0,t.modelCostMap)(),staleTime:6e4,gcTime:6e4})])},226898,972520,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(304967),l=e.i(269200),o=e.i(427612),s=e.i(496020),i=e.i(389083),n=e.i(64848),d=e.i(977572),c=e.i(942232),u=e.i(599724),m=e.i(994388),g=e.i(752978),p=e.i(793130),f=e.i(404206),b=e.i(723731),h=e.i(653824),x=e.i(881073),v=e.i(197647),C=e.i(764205),y=e.i(28651),k=e.i(68155),w=e.i(220508),A=e.i(727749),N=e.i(158392);let j=({accessToken:e,userRole:a,userID:l,modelData:o})=>{let[s,i]=(0,r.useState)({routerSettings:{},selectedStrategy:null,enableTagFiltering:!1}),[n,d]=(0,r.useState)([]),[c,u]=(0,r.useState)({}),[g,p]=(0,r.useState)({});return((0,r.useEffect)(()=>{e&&a&&l&&((0,C.getCallbacksCall)(e,l,a).then(e=>{console.log("callbacks",e);let t=e.router_settings;"model_group_retry_policy"in t&&delete t.model_group_retry_policy;let r=t.routing_strategy||null;i(e=>({...e,routerSettings:t,selectedStrategy:r}))}),(0,C.getRouterSettingsCall)(e).then(e=>{if(console.log("router settings from API",e),e.fields){let t={};e.fields.forEach(e=>{t[e.field_name]={ui_field_name:e.ui_field_name,field_description:e.field_description,options:e.options,link:e.link}}),u(t);let r=e.fields.find(e=>"routing_strategy"===e.field_name);r?.options&&d(r.options),e.routing_strategy_descriptions&&p(e.routing_strategy_descriptions);let a=e.fields.find(e=>"enable_tag_filtering"===e.field_name);a?.field_value!==null&&a?.field_value!==void 0&&i(e=>({...e,enableTagFiltering:a.field_value}))}}))},[e,a,l]),e)?(0,t.jsxs)("div",{className:"w-full",children:[(0,t.jsx)(N.default,{value:s,onChange:i,routerFieldsMetadata:c,availableRoutingStrategies:n,routingStrategyDescriptions:g}),(0,t.jsxs)("div",{className:"border-t border-gray-200 pt-6 flex justify-end gap-3",children:[(0,t.jsx)(m.Button,{variant:"secondary",size:"sm",onClick:()=>window.location.reload(),className:"text-sm",children:"Reset"}),(0,t.jsx)(m.Button,{size:"sm",onClick:()=>{if(!e)return;let t=s.routerSettings;console.log("router_settings",t);let r=new Set(["allowed_fails","cooldown_time","num_retries","timeout","retry_after"]),a=new Set(["model_group_alias","retry_policy"]),l=Object.fromEntries(Object.entries({...t,enable_tag_filtering:s.enableTagFiltering}).map(([e,t])=>{if("routing_strategy_args"!==e&&"routing_strategy"!==e&&"enable_tag_filtering"!==e){let l=document.querySelector(`input[name="${e}"]`),o=((e,t,l)=>{if(void 0===t)return l;let o=t.trim();if("null"===o.toLowerCase())return null;if(r.has(e)){let e=Number(o);return Number.isNaN(e)?l:e}if(a.has(e)){if(""===o)return null;try{return JSON.parse(o)}catch{return l}}return"true"===o.toLowerCase()||"false"!==o.toLowerCase()&&o})(e,l?.value,t);return[e,o]}if("routing_strategy"===e)return[e,s.selectedStrategy];if("enable_tag_filtering"===e)return[e,s.enableTagFiltering];if("routing_strategy_args"===e&&"latency-based-routing"===s.selectedStrategy){let e={},t=document.querySelector('input[name="lowest_latency_buffer"]'),r=document.querySelector('input[name="ttl"]');return t?.value&&(e.lowest_latency_buffer=Number(t.value)),r?.value&&(e.ttl=Number(r.value)),console.log(`setRoutingStrategyArgs: ${e}`),["routing_strategy_args",e]}return null}).filter(e=>null!=e));console.log("updatedVariables",l);try{(0,C.setCallbacksCall)(e,{router_settings:l})}catch(e){A.default.fromBackend("Failed to update router settings: "+e)}A.default.success("router settings updated successfully")},className:"text-sm font-medium",children:"Save Changes"})]})]}):null};e.i(247167);var _=e.i(368670);let T=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:"M14 5l7 7m0 0l-7 7m7-7H3"}))});var E=e.i(122577),I=e.i(592968),O=e.i(898586),M=e.i(356449),S=e.i(127952),$=e.i(418371),R=e.i(464571),L=e.i(998573),P=e.i(689020),B=e.i(212931);let F=(0,e.i(475254).default)("arrow-right",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"m12 5 7 7-7 7",key:"xquz4c"}]]);function D({open:e,onCancel:r,children:a}){return(0,t.jsx)(B.Modal,{title:(0,t.jsx)("div",{className:"pb-4 border-b border-gray-100",children:(0,t.jsxs)("div",{className:"flex items-center gap-2 text-gray-800",children:[(0,t.jsx)("div",{className:"p-2 bg-indigo-50 rounded-lg",children:(0,t.jsx)(F,{className:"w-5 h-5 text-indigo-600"})}),(0,t.jsxs)("div",{children:[(0,t.jsx)("h2",{className:"text-lg font-bold m-0",children:"Configure Model Fallbacks"}),(0,t.jsx)("p",{className:"text-sm text-gray-500 font-normal m-0",children:"Manage multiple fallback chains for different models (up to 5 groups at a time)"})]})]})}),open:e,width:900,footer:null,onCancel:r,maskClosable:!1,className:"top-8",styles:{body:{padding:"24px"},header:{padding:"24px 24px 0 24px",border:"none"}},children:(0,t.jsx)("div",{className:"mt-6",children:a})})}e.s(["ArrowRight",()=>F],972520);var z=e.i(419470);function H({models:e,accessToken:a,value:l=[],onChange:o}){let[s,i]=(0,r.useState)(!1),[n,d]=(0,r.useState)([]),[c,u]=(0,r.useState)(0),[g,p]=(0,r.useState)(!1),[f,b]=(0,r.useState)([{id:"1",primaryModel:null,fallbackModels:[]}]);(0,r.useEffect)(()=>{s&&(b([{id:"1",primaryModel:null,fallbackModels:[]}]),u(e=>e+1))},[s]),(0,r.useEffect)(()=>{let e=async()=>{try{let e=await (0,P.fetchAvailableModels)(a);console.log("Fetched models for fallbacks:",e),d(e)}catch(e){console.error("Error fetching model info for fallbacks:",e)}};s&&e()},[a,s]);let h=Array.from(new Set(n.map(e=>e.model_group))).sort(),x=()=>{i(!1),b([{id:"1",primaryModel:null,fallbackModels:[]}])},v=async()=>{let e=f.filter(e=>!e.primaryModel||0===e.fallbackModels.length);if(e.length>0)return void L.message.error(`Please complete configuration for all groups. ${e.length} group(s) incomplete.`);let t=[...l||[],...f.map(e=>({[e.primaryModel]:e.fallbackModels}))];if(o){p(!0);try{await o(t),A.default.success(`${f.length} fallback configuration(s) added successfully!`),x()}catch(e){console.error("Error saving fallbacks:",e)}finally{p(!1)}}else A.default.fromBackend("onChange callback not provided")};return(0,t.jsxs)("div",{children:[(0,t.jsx)(m.Button,{className:"mx-auto",onClick:()=>i(!0),icon:()=>(0,t.jsx)("span",{className:"mr-1",children:"+"}),children:"Add Fallbacks"}),(0,t.jsxs)(D,{open:s,onCancel:x,children:[(0,t.jsx)(z.FallbackSelectionForm,{groups:f,onGroupsChange:b,availableModels:h,maxFallbacks:10,maxGroups:5},c),f.length>0&&(0,t.jsxs)("div",{className:"flex items-center justify-end space-x-3 pt-6 mt-6 border-t border-gray-100",children:[(0,t.jsx)(R.Button,{type:"default",onClick:x,disabled:g,children:"Cancel"}),(0,t.jsx)(R.Button,{type:"default",onClick:v,disabled:0===f.length||g,loading:g,children:g?"Saving Configuration...":"Save All Configurations"})]})]})]})}let G="inline-flex items-center gap-2 px-2.5 py-1 rounded-md border border-gray-200 bg-gray-50 text-sm font-medium text-gray-800 shrink-0";async function V(e,r){console.log=function(){};let a=window.location.origin,l=new M.default.OpenAI({apiKey:r,baseURL:a,dangerouslyAllowBrowser:!0});try{A.default.info("Testing fallback model response...");let r=await l.chat.completions.create({model:e,messages:[{role:"user",content:"Hi, this is a test message"}],mock_testing_fallbacks:!0});A.default.success((0,t.jsxs)("span",{children:["Test model=",(0,t.jsx)("strong",{children:e}),", received model=",(0,t.jsx)("strong",{children:r.model}),". See"," ",(0,t.jsx)("a",{href:"#",onClick:()=>window.open("https://docs.litellm.ai/docs/proxy/reliability","_blank"),style:{textDecoration:"underline",color:"blue"},children:"curl"})]}))}catch(e){A.default.fromBackend(`Error occurred while generating model response. Please try again. Error: ${e}`)}}let q=({accessToken:e,userRole:a,userID:i,modelData:u})=>{let[m,p]=(0,r.useState)({}),[f,b]=(0,r.useState)(!1),[h,x]=(0,r.useState)(null),[v,y]=(0,r.useState)(!1),{data:w}=(0,_.useModelCostMap)(),N=e=>null!=w&&"object"==typeof w&&e in w?w[e].litellm_provider??"":"";(0,r.useEffect)(()=>{e&&a&&i&&(0,C.getCallbacksCall)(e,i,a).then(e=>{console.log("callbacks",e);let t=e.router_settings;"model_group_retry_policy"in t&&delete t.model_group_retry_policy,p(t)})},[e,a,i]);let j=e=>{x(e),y(!0)},M=async()=>{if(!h||!e)return;let t=Object.keys(h)[0];if(!t)return;b(!0);let r=m.fallbacks.map(e=>{let r={...e};return t in r&&Array.isArray(r[t])&&delete r[t],r}).filter(e=>Object.keys(e).length>0),a={...m,fallbacks:r};try{await (0,C.setCallbacksCall)(e,{router_settings:a}),p(a),A.default.success("Router settings updated successfully")}catch(e){A.default.fromBackend("Failed to update router settings: "+e)}finally{b(!1),y(!1),x(null)}};if(!e)return null;let R=async t=>{if(!e)return;let r={...m,fallbacks:t};try{await (0,C.setCallbacksCall)(e,{router_settings:r}),p(r)}catch(t){throw A.default.fromBackend("Failed to update router settings: "+t),e&&a&&i&&(0,C.getCallbacksCall)(e,i,a).then(e=>{let t=e.router_settings;"model_group_retry_policy"in t&&delete t.model_group_retry_policy,p(t)}),t}},L=Array.isArray(m.fallbacks)&&m.fallbacks.length>0;return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(H,{models:u?.data?u.data.map(e=>e.model_name):[],accessToken:e||"",value:m.fallbacks||[],onChange:R}),L?(0,t.jsxs)(l.Table,{children:[(0,t.jsx)(o.TableHead,{children:(0,t.jsxs)(s.TableRow,{children:[(0,t.jsx)(n.TableHeaderCell,{children:"Model Name"}),(0,t.jsx)(n.TableHeaderCell,{children:"Fallbacks"}),(0,t.jsx)(n.TableHeaderCell,{children:"Actions"})]})}),(0,t.jsx)(c.TableBody,{children:m.fallbacks.map((a,l)=>Object.entries(a).map(([o,i])=>{let n;return(0,t.jsxs)(s.TableRow,{children:[(0,t.jsx)(d.TableCell,{className:"align-top",children:(n=N?.(o)??o,(0,t.jsxs)("span",{className:G,children:[(0,t.jsx)($.ProviderLogo,{provider:n,className:"w-4 h-4 shrink-0"}),(0,t.jsx)("span",{children:o})]}))}),(0,t.jsx)(d.TableCell,{className:"align-top",children:function(e,a,l){let o=Array.isArray(a)?a:[];if(0===o.length)return null;let s=({modelName:e})=>{let r=l?.(e)??e;return(0,t.jsxs)("span",{className:G,children:[(0,t.jsx)($.ProviderLogo,{provider:r,className:"w-4 h-4 shrink-0"}),(0,t.jsx)("span",{children:e})]})};return(0,t.jsxs)("span",{className:"grid grid-cols-[auto_1fr] items-start gap-x-2 w-full min-w-0",children:[(0,t.jsx)("span",{className:"inline-flex items-center justify-center w-8 h-8 shrink-0 self-start text-blue-600","aria-hidden":!0,children:(0,t.jsx)(T,{className:"w-5 h-5 stroke-[2.5]"})}),(0,t.jsx)("span",{className:"flex flex-wrap items-start gap-1 min-w-0",children:o.map((e,a)=>(0,t.jsxs)(r.default.Fragment,{children:[a>0&&(0,t.jsx)(g.Icon,{icon:T,size:"xs",className:"shrink-0 text-gray-400"}),(0,t.jsx)(s,{modelName:e})]},e))})]})}(0,Array.isArray(i)?i:[],N)}),(0,t.jsxs)(d.TableCell,{className:"align-top",children:[(0,t.jsx)(I.Tooltip,{title:"Test fallback",children:(0,t.jsx)(g.Icon,{icon:E.PlayIcon,size:"sm",onClick:()=>V(Object.keys(a)[0],e||""),className:"cursor-pointer hover:text-blue-600"})}),(0,t.jsx)(I.Tooltip,{title:"Delete fallback",children:(0,t.jsx)("span",{"data-testid":"delete-fallback-button",role:"button",tabIndex:0,onClick:()=>j(a),onKeyDown:e=>"Enter"===e.key&&j(a),className:"cursor-pointer inline-flex",children:(0,t.jsx)(g.Icon,{icon:k.TrashIcon,size:"sm",className:"hover:text-red-600"})})})]})]},l.toString()+o)}))})]}):(0,t.jsx)("div",{className:"rounded-lg border border-gray-200 bg-gray-50 px-4 py-6 text-center",children:(0,t.jsx)(O.Typography.Text,{type:"secondary",children:"No fallbacks configured. Add fallbacks to automatically try another model when the primary fails."})}),(0,t.jsx)(S.default,{isOpen:v,title:"Delete Fallback?",message:"Are you sure you want to delete this fallback? This action cannot be undone.",resourceInformationTitle:"Fallback Information",resourceInformation:[{label:"Model Name",value:h?Object.keys(h)[0]:"",code:!0}],onCancel:()=>{y(!1),x(null)},onOk:M,confirmLoading:f})]})};e.s(["default",0,({accessToken:e,userRole:A,userID:N,modelData:_})=>{let[T,E]=(0,r.useState)([]);(0,r.useEffect)(()=>{e&&(0,C.getGeneralSettingsCall)(e).then(e=>{E(e)})},[e]);let I=(e,t)=>{E(T.map(r=>r.field_name===e?{...r,field_value:t}:r))};return e?(0,t.jsx)("div",{className:"w-full",children:(0,t.jsxs)(h.TabGroup,{className:"h-[75vh] w-full",children:[(0,t.jsxs)(x.TabList,{variant:"line",defaultValue:"1",className:"px-8 pt-4",children:[(0,t.jsx)(v.Tab,{value:"1",children:"Loadbalancing"}),(0,t.jsx)(v.Tab,{value:"2",children:"Fallbacks"}),(0,t.jsx)(v.Tab,{value:"3",children:"General"})]}),(0,t.jsxs)(b.TabPanels,{className:"px-8 py-6",children:[(0,t.jsx)(f.TabPanel,{children:(0,t.jsx)(j,{accessToken:e,userRole:A,userID:N,modelData:_})}),(0,t.jsx)(f.TabPanel,{children:(0,t.jsx)(q,{accessToken:e,userRole:A,userID:N,modelData:_})}),(0,t.jsx)(f.TabPanel,{children:(0,t.jsx)(a.Card,{children:(0,t.jsxs)(l.Table,{children:[(0,t.jsx)(o.TableHead,{children:(0,t.jsxs)(s.TableRow,{children:[(0,t.jsx)(n.TableHeaderCell,{children:"Setting"}),(0,t.jsx)(n.TableHeaderCell,{children:"Value"}),(0,t.jsx)(n.TableHeaderCell,{children:"Status"}),(0,t.jsx)(n.TableHeaderCell,{children:"Action"})]})}),(0,t.jsx)(c.TableBody,{children:T.filter(e=>"TypedDictionary"!==e.field_type).map((r,a)=>(0,t.jsxs)(s.TableRow,{children:[(0,t.jsxs)(d.TableCell,{children:[(0,t.jsx)(u.Text,{children:r.field_name}),(0,t.jsx)("p",{style:{fontSize:"0.65rem",color:"#808080",fontStyle:"italic"},className:"mt-1",children:r.field_description})]}),(0,t.jsx)(d.TableCell,{children:"Integer"==r.field_type?(0,t.jsx)(y.InputNumber,{step:1,value:r.field_value,onChange:e=>I(r.field_name,e)}):"Boolean"==r.field_type?(0,t.jsx)(p.Switch,{checked:!0===r.field_value||"true"===r.field_value,onChange:e=>I(r.field_name,e)}):null}),(0,t.jsx)(d.TableCell,{children:!0==r.stored_in_db?(0,t.jsx)(i.Badge,{icon:w.CheckCircleIcon,className:"text-white",children:"In DB"}):!1==r.stored_in_db?(0,t.jsx)(i.Badge,{className:"text-gray bg-white outline",children:"In Config"}):(0,t.jsx)(i.Badge,{className:"text-gray bg-white outline",children:"Not Set"})}),(0,t.jsxs)(d.TableCell,{children:[(0,t.jsx)(m.Button,{onClick:()=>((t,r)=>{if(!e)return;let a=T[r].field_value;if(null!=a&&void 0!=a)try{(0,C.updateConfigFieldSetting)(e,t,a);let r=T.map(e=>e.field_name===t?{...e,stored_in_db:!0}:e);E(r)}catch(e){}})(r.field_name,a),children:"Update"}),(0,t.jsx)(g.Icon,{icon:k.TrashIcon,color:"red",onClick:()=>((t,r)=>{if(e)try{(0,C.deleteConfigFieldSetting)(e,t);let r=T.map(e=>e.field_name===t?{...e,stored_in_db:null,field_value:null}:e);E(r)}catch(e){}})(r.field_name,0),children:"Reset"})]})]},a))})]})})})]})]})}):null}],226898)},511715,e=>{"use strict";var t=e.i(843476),r=e.i(226898),a=e.i(135214);e.s(["default",0,()=>{let{accessToken:e,userRole:l,userId:o}=(0,a.default)();return(0,t.jsx)(r.default,{accessToken:e,userRole:l,userID:o,modelData:{}})}])}]); \ No newline at end of file + `]:Object.assign({},{background:e.skeletonLoadingBackground,backgroundSize:"400% 100%",animationName:c,animationDuration:e.skeletonLoadingMotionDuration,animationTimingFunction:"ease",animationIterationCount:"infinite"})}}})((0,d.mergeToken)(e,{skeletonAvatarCls:`${t}-avatar`,skeletonTitleCls:`${t}-title`,skeletonParagraphCls:`${t}-paragraph`,skeletonButtonCls:`${t}-button`,skeletonInputCls:`${t}-input`,skeletonImageCls:`${t}-image`,imageSizeBase:r(e.controlHeight).mul(1.5).equal(),borderRadius:100,skeletonLoadingBackground:`linear-gradient(90deg, ${e.gradientFromColor} 25%, ${e.gradientToColor} 37%, ${e.gradientFromColor} 63%)`,skeletonLoadingMotionDuration:"1.4s"}))},e=>{let{colorFillContent:t,colorFill:r}=e;return{color:t,colorGradientEnd:r,gradientFromColor:t,gradientToColor:r,titleHeight:e.controlHeight/2,blockRadius:e.borderRadiusSM,paragraphMarginTop:e.marginLG+e.marginXXS,paragraphLiHeight:e.controlHeight/2}},{deprecatedTokens:[["color","gradientFromColor"],["colorGradientEnd","gradientToColor"]]}),x=e=>{let{prefixCls:a,className:l,style:o,rows:s=0}=e,i=Array.from({length:s}).map((r,a)=>t.createElement("li",{key:a,style:{width:((e,t)=>{let{width:r,rows:a=2}=t;return Array.isArray(r)?r[e]:a-1===e?r:void 0})(a,e)}}));return t.createElement("ul",{className:(0,r.default)(a,l),style:o},i)},v=({prefixCls:e,className:a,width:l,style:o})=>t.createElement("h3",{className:(0,r.default)(e,a),style:Object.assign({width:l},o)});function C(e){return e&&"object"==typeof e?e:{}}let y=e=>{let{prefixCls:l,loading:s,className:i,rootClassName:n,style:d,children:c,avatar:u=!1,title:m=!0,paragraph:g=!0,active:p,round:b}=e,{getPrefixCls:f,direction:y,className:k,style:w}=(0,a.useComponentConfig)("skeleton"),A=f("skeleton",l),[N,j,_]=h(A);if(s||!("loading"in e)){let e,a,l=!!u,s=!!m,c=!!g;if(l){let r=Object.assign(Object.assign({prefixCls:`${A}-avatar`},s&&!c?{size:"large",shape:"square"}:{size:"large",shape:"circle"}),C(u));e=t.createElement("div",{className:`${A}-header`},t.createElement(o,Object.assign({},r)))}if(s||c){let e,r;if(s){let r=Object.assign(Object.assign({prefixCls:`${A}-title`},!l&&c?{width:"38%"}:l&&c?{width:"50%"}:{}),C(m));e=t.createElement(v,Object.assign({},r))}if(c){let e,a=Object.assign(Object.assign({prefixCls:`${A}-paragraph`},(e={},l&&s||(e.width="61%"),!l&&s?e.rows=3:e.rows=2,e)),C(g));r=t.createElement(x,Object.assign({},a))}a=t.createElement("div",{className:`${A}-content`},e,r)}let f=(0,r.default)(A,{[`${A}-with-avatar`]:l,[`${A}-active`]:p,[`${A}-rtl`]:"rtl"===y,[`${A}-round`]:b},k,i,n,j,_);return N(t.createElement("div",{className:f,style:Object.assign(Object.assign({},w),d)},e,a))}return null!=c?c:null};y.Button=e=>{let{prefixCls:s,className:i,rootClassName:n,active:d,block:c=!1,size:u="default"}=e,{getPrefixCls:m}=t.useContext(a.ConfigContext),g=m("skeleton",s),[p,b,f]=h(g),x=(0,l.default)(e,["prefixCls"]),v=(0,r.default)(g,`${g}-element`,{[`${g}-active`]:d,[`${g}-block`]:c},i,n,b,f);return p(t.createElement("div",{className:v},t.createElement(o,Object.assign({prefixCls:`${g}-button`,size:u},x))))},y.Avatar=e=>{let{prefixCls:s,className:i,rootClassName:n,active:d,shape:c="circle",size:u="default"}=e,{getPrefixCls:m}=t.useContext(a.ConfigContext),g=m("skeleton",s),[p,b,f]=h(g),x=(0,l.default)(e,["prefixCls","className"]),v=(0,r.default)(g,`${g}-element`,{[`${g}-active`]:d},i,n,b,f);return p(t.createElement("div",{className:v},t.createElement(o,Object.assign({prefixCls:`${g}-avatar`,shape:c,size:u},x))))},y.Input=e=>{let{prefixCls:s,className:i,rootClassName:n,active:d,block:c,size:u="default"}=e,{getPrefixCls:m}=t.useContext(a.ConfigContext),g=m("skeleton",s),[p,b,f]=h(g),x=(0,l.default)(e,["prefixCls"]),v=(0,r.default)(g,`${g}-element`,{[`${g}-active`]:d,[`${g}-block`]:c},i,n,b,f);return p(t.createElement("div",{className:v},t.createElement(o,Object.assign({prefixCls:`${g}-input`,size:u},x))))},y.Image=e=>{let{prefixCls:l,className:o,rootClassName:s,style:i,active:n}=e,{getPrefixCls:d}=t.useContext(a.ConfigContext),c=d("skeleton",l),[u,m,g]=h(c),p=(0,r.default)(c,`${c}-element`,{[`${c}-active`]:n},o,s,m,g);return u(t.createElement("div",{className:p},t.createElement("div",{className:(0,r.default)(`${c}-image`,o),style:i},t.createElement("svg",{viewBox:"0 0 1098 1024",xmlns:"http://www.w3.org/2000/svg",className:`${c}-image-svg`},t.createElement("title",null,"Image placeholder"),t.createElement("path",{d:"M365.714286 329.142857q0 45.714286-32.036571 77.677714t-77.677714 32.036571-77.677714-32.036571-32.036571-77.677714 32.036571-77.677714 77.677714-32.036571 77.677714 32.036571 32.036571 77.677714zM950.857143 548.571429l0 256-804.571429 0 0-109.714286 182.857143-182.857143 91.428571 91.428571 292.571429-292.571429zM1005.714286 146.285714l-914.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 694.857143q0 7.460571 5.412571 12.873143t12.873143 5.412571l914.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143l0-694.857143q0-7.460571-5.412571-12.873143t-12.873143-5.412571zM1097.142857 164.571429l0 694.857143q0 37.741714-26.843429 64.585143t-64.585143 26.843429l-914.285714 0q-37.741714 0-64.585143-26.843429t-26.843429-64.585143l0-694.857143q0-37.741714 26.843429-64.585143t64.585143-26.843429l914.285714 0q37.741714 0 64.585143 26.843429t26.843429 64.585143z",className:`${c}-image-path`})))))},y.Node=e=>{let{prefixCls:l,className:o,rootClassName:s,style:i,active:n,children:d}=e,{getPrefixCls:c}=t.useContext(a.ConfigContext),u=c("skeleton",l),[m,g,p]=h(u),b=(0,r.default)(u,`${u}-element`,{[`${u}-active`]:n},g,o,s,p);return m(t.createElement("div",{className:b},t.createElement("div",{className:(0,r.default)(`${u}-image`,o),style:i},d)))},e.s(["default",0,y],185793)},959013,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let a={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"}},{tag:"path",attrs:{d:"M192 474h672q8 0 8 8v60q0 8-8 8H160q-8 0-8-8v-60q0-8 8-8z"}}]},name:"plus",theme:"outlined"};var l=e.i(9583),o=r.forwardRef(function(e,o){return r.createElement(l.default,(0,t.default)({},e,{ref:o,icon:a}))});e.s(["default",0,o],959013)},269200,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(444755);let l=(0,e.i(673706).makeClassName)("Table"),o=r.default.forwardRef((e,o)=>{let{children:s,className:i}=e,n=(0,t.__rest)(e,["children","className"]);return r.default.createElement("div",{className:(0,a.tremorTwMerge)(l("root"),"overflow-auto",i)},r.default.createElement("table",Object.assign({ref:o,className:(0,a.tremorTwMerge)(l("table"),"w-full text-tremor-default","text-tremor-content","dark:text-dark-tremor-content")},n),s))});o.displayName="Table",e.s(["Table",()=>o],269200)},427612,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableHead"),o=r.default.forwardRef((e,o)=>{let{children:s,className:i}=e,n=(0,t.__rest)(e,["children","className"]);return r.default.createElement(r.default.Fragment,null,r.default.createElement("thead",Object.assign({ref:o,className:(0,a.tremorTwMerge)(l("root"),"text-left","text-tremor-content","dark:text-dark-tremor-content",i)},n),s))});o.displayName="TableHead",e.s(["TableHead",()=>o],427612)},496020,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableRow"),o=r.default.forwardRef((e,o)=>{let{children:s,className:i}=e,n=(0,t.__rest)(e,["children","className"]);return r.default.createElement(r.default.Fragment,null,r.default.createElement("tr",Object.assign({ref:o,className:(0,a.tremorTwMerge)(l("row"),i)},n),s))});o.displayName="TableRow",e.s(["TableRow",()=>o],496020)},64848,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableHeaderCell"),o=r.default.forwardRef((e,o)=>{let{children:s,className:i}=e,n=(0,t.__rest)(e,["children","className"]);return r.default.createElement(r.default.Fragment,null,r.default.createElement("th",Object.assign({ref:o,className:(0,a.tremorTwMerge)(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)},n),s))});o.displayName="TableHeaderCell",e.s(["TableHeaderCell",()=>o],64848)},977572,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableCell"),o=r.default.forwardRef((e,o)=>{let{children:s,className:i}=e,n=(0,t.__rest)(e,["children","className"]);return r.default.createElement(r.default.Fragment,null,r.default.createElement("td",Object.assign({ref:o,className:(0,a.tremorTwMerge)(l("root"),"align-middle whitespace-nowrap text-left p-4",i)},n),s))});o.displayName="TableCell",e.s(["TableCell",()=>o],977572)},942232,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableBody"),o=r.default.forwardRef((e,o)=>{let{children:s,className:i}=e,n=(0,t.__rest)(e,["children","className"]);return r.default.createElement(r.default.Fragment,null,r.default.createElement("tbody",Object.assign({ref:o,className:(0,a.tremorTwMerge)(l("root"),"align-top divide-y","divide-tremor-border","dark:divide-dark-tremor-border",i)},n),s))});o.displayName="TableBody",e.s(["TableBody",()=>o],942232)},728889,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(829087),l=e.i(480731),o=e.i(444755),s=e.i(673706),i=e.i(95779);let n={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"}},d={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"}},c={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:""}},u=(0,s.makeClassName)("Icon"),m=r.default.forwardRef((e,m)=>{let{icon:g,variant:p="simple",tooltip:b,size:f=l.Sizes.SM,color:h,className:x}=e,v=(0,t.__rest)(e,["icon","variant","tooltip","size","color","className"]),C=((e,t)=>{switch(e){case"simple":return{textColor:t?(0,s.getColorClassNames)(t,i.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:"",borderColor:"",ringColor:""};case"light":return{textColor:t?(0,s.getColorClassNames)(t,i.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:t?(0,o.tremorTwMerge)((0,s.getColorClassNames)(t,i.colorPalette.background).bgColor,"bg-opacity-20"):"bg-tremor-brand-muted dark:bg-dark-tremor-brand-muted",borderColor:"",ringColor:""};case"shadow":return{textColor:t?(0,s.getColorClassNames)(t,i.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:t?(0,o.tremorTwMerge)((0,s.getColorClassNames)(t,i.colorPalette.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:t?(0,s.getColorClassNames)(t,i.colorPalette.text).textColor:"text-tremor-brand-inverted dark:text-dark-tremor-brand-inverted",bgColor:t?(0,o.tremorTwMerge)((0,s.getColorClassNames)(t,i.colorPalette.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:t?(0,s.getColorClassNames)(t,i.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:t?(0,o.tremorTwMerge)((0,s.getColorClassNames)(t,i.colorPalette.background).bgColor,"bg-opacity-20"):"bg-tremor-background dark:bg-dark-tremor-background",borderColor:t?(0,s.getColorClassNames)(t,i.colorPalette.ring).borderColor:"border-tremor-brand-subtle dark:border-dark-tremor-brand-subtle",ringColor:t?(0,o.tremorTwMerge)((0,s.getColorClassNames)(t,i.colorPalette.ring).ringColor,"ring-opacity-40"):"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"}}})(p,h),{tooltipProps:y,getReferenceProps:k}=(0,a.useTooltip)();return r.default.createElement("span",Object.assign({ref:(0,s.mergeRefs)([m,y.refs.setReference]),className:(0,o.tremorTwMerge)(u("root"),"inline-flex shrink-0 items-center justify-center",C.bgColor,C.textColor,C.borderColor,C.ringColor,c[p].rounded,c[p].border,c[p].shadow,c[p].ring,n[f].paddingX,n[f].paddingY,x)},k,v),r.default.createElement(a.default,Object.assign({text:b},y)),r.default.createElement(g,{className:(0,o.tremorTwMerge)(u("icon"),"shrink-0",d[f].height,d[f].width)}))});m.displayName="Icon",e.s(["default",()=>m],728889)},752978,e=>{"use strict";var t=e.i(728889);e.s(["Icon",()=>t.default])},122577,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.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"}),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M21 12a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlayIcon",0,r],122577)},418371,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(916925);e.s(["ProviderLogo",0,({provider:e,className:l="w-4 h-4"})=>{let[o,s]=(0,r.useState)(!1),{logo:i}=(0,a.getProviderLogoAndName)(e);return o||!i?(0,t.jsx)("div",{className:`${l} rounded-full bg-gray-200 flex items-center justify-center text-xs`,children:e?.charAt(0)||"-"}):(0,t.jsx)("img",{src:i,alt:`${e} logo`,className:l,onError:()=>s(!0)})}])},368670,e=>{"use strict";var t=e.i(764205),r=e.i(266027);let a=(0,e.i(243652).createQueryKeys)("modelCostMap");e.s(["useModelCostMap",0,()=>(0,r.useQuery)({queryKey:a.list({}),queryFn:async()=>await (0,t.modelCostMap)(),staleTime:6e4,gcTime:6e4})])},226898,972520,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(304967),l=e.i(269200),o=e.i(427612),s=e.i(496020),i=e.i(389083),n=e.i(64848),d=e.i(977572),c=e.i(942232),u=e.i(599724),m=e.i(994388),g=e.i(752978),p=e.i(793130),b=e.i(404206),f=e.i(723731),h=e.i(653824),x=e.i(881073),v=e.i(197647),C=e.i(764205),y=e.i(28651),k=e.i(68155),w=e.i(220508),A=e.i(727749),N=e.i(158392);let j=({accessToken:e,userRole:a,userID:l,modelData:o})=>{let[s,i]=(0,r.useState)({routerSettings:{},selectedStrategy:null,enableTagFiltering:!1}),[n,d]=(0,r.useState)([]),[c,u]=(0,r.useState)({}),[g,p]=(0,r.useState)({});return((0,r.useEffect)(()=>{e&&a&&l&&((0,C.getCallbacksCall)(e,l,a).then(e=>{console.log("callbacks",e);let t=e.router_settings;"model_group_retry_policy"in t&&delete t.model_group_retry_policy;let r=t.routing_strategy||null;i(e=>({...e,routerSettings:t,selectedStrategy:r}))}),(0,C.getRouterSettingsCall)(e).then(e=>{if(console.log("router settings from API",e),e.fields){let t={};e.fields.forEach(e=>{t[e.field_name]={ui_field_name:e.ui_field_name,field_description:e.field_description,options:e.options,link:e.link}}),u(t);let r=e.fields.find(e=>"routing_strategy"===e.field_name);r?.options&&d(r.options),e.routing_strategy_descriptions&&p(e.routing_strategy_descriptions);let a=e.fields.find(e=>"enable_tag_filtering"===e.field_name);a?.field_value!==null&&a?.field_value!==void 0&&i(e=>({...e,enableTagFiltering:a.field_value}))}}))},[e,a,l]),e)?(0,t.jsxs)("div",{className:"w-full",children:[(0,t.jsx)(N.default,{value:s,onChange:i,routerFieldsMetadata:c,availableRoutingStrategies:n,routingStrategyDescriptions:g}),(0,t.jsxs)("div",{className:"border-t border-gray-200 pt-6 flex justify-end gap-3",children:[(0,t.jsx)(m.Button,{variant:"secondary",size:"sm",onClick:()=>window.location.reload(),className:"text-sm",children:"Reset"}),(0,t.jsx)(m.Button,{size:"sm",onClick:()=>{if(!e)return;let t=s.routerSettings;console.log("router_settings",t);let r=new Set(["allowed_fails","cooldown_time","num_retries","timeout","retry_after"]),a=new Set(["model_group_alias","retry_policy"]),l=Object.fromEntries(Object.entries({...t,enable_tag_filtering:s.enableTagFiltering}).map(([e,t])=>{if("routing_strategy_args"!==e&&"routing_strategy"!==e&&"enable_tag_filtering"!==e){let l=document.querySelector(`input[name="${e}"]`),o=((e,t,l)=>{if(void 0===t)return l;let o=t.trim();if("null"===o.toLowerCase())return null;if(r.has(e)){let e=Number(o);return Number.isNaN(e)?l:e}if(a.has(e)){if(""===o)return null;try{return JSON.parse(o)}catch{return l}}return"true"===o.toLowerCase()||"false"!==o.toLowerCase()&&o})(e,l?.value,t);return[e,o]}if("routing_strategy"===e)return[e,s.selectedStrategy];if("enable_tag_filtering"===e)return[e,s.enableTagFiltering];if("routing_strategy_args"===e&&"latency-based-routing"===s.selectedStrategy){let e={},t=document.querySelector('input[name="lowest_latency_buffer"]'),r=document.querySelector('input[name="ttl"]');return t?.value&&(e.lowest_latency_buffer=Number(t.value)),r?.value&&(e.ttl=Number(r.value)),console.log(`setRoutingStrategyArgs: ${e}`),["routing_strategy_args",e]}return null}).filter(e=>null!=e));console.log("updatedVariables",l);try{(0,C.setCallbacksCall)(e,{router_settings:l})}catch(e){A.default.fromBackend("Failed to update router settings: "+e)}A.default.success("router settings updated successfully")},className:"text-sm font-medium",children:"Save Changes"})]})]}):null};e.i(247167);var _=e.i(368670);let T=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:"M14 5l7 7m0 0l-7 7m7-7H3"}))});var E=e.i(122577),I=e.i(592968),O=e.i(898586),M=e.i(356449),S=e.i(127952),$=e.i(418371),R=e.i(464571),L=e.i(998573),P=e.i(689020),B=e.i(212931);let F=(0,e.i(475254).default)("arrow-right",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"m12 5 7 7-7 7",key:"xquz4c"}]]);function D({open:e,onCancel:r,children:a}){return(0,t.jsx)(B.Modal,{title:(0,t.jsx)("div",{className:"pb-4 border-b border-gray-100",children:(0,t.jsxs)("div",{className:"flex items-center gap-2 text-gray-800",children:[(0,t.jsx)("div",{className:"p-2 bg-indigo-50 rounded-lg",children:(0,t.jsx)(F,{className:"w-5 h-5 text-indigo-600"})}),(0,t.jsxs)("div",{children:[(0,t.jsx)("h2",{className:"text-lg font-bold m-0",children:"Configure Model Fallbacks"}),(0,t.jsx)("p",{className:"text-sm text-gray-500 font-normal m-0",children:"Manage multiple fallback chains for different models (up to 5 groups at a time)"})]})]})}),open:e,width:900,footer:null,onCancel:r,maskClosable:!1,className:"top-8",styles:{body:{padding:"24px"},header:{padding:"24px 24px 0 24px",border:"none"}},children:(0,t.jsx)("div",{className:"mt-6",children:a})})}e.s(["ArrowRight",()=>F],972520);var z=e.i(419470);function H({models:e,accessToken:a,value:l=[],onChange:o}){let[s,i]=(0,r.useState)(!1),[n,d]=(0,r.useState)([]),[c,u]=(0,r.useState)(0),[g,p]=(0,r.useState)(!1),[b,f]=(0,r.useState)([{id:"1",primaryModel:null,fallbackModels:[]}]);(0,r.useEffect)(()=>{s&&(f([{id:"1",primaryModel:null,fallbackModels:[]}]),u(e=>e+1))},[s]),(0,r.useEffect)(()=>{let e=async()=>{try{let e=await (0,P.fetchAvailableModels)(a);console.log("Fetched models for fallbacks:",e),d(e)}catch(e){console.error("Error fetching model info for fallbacks:",e)}};s&&e()},[a,s]);let h=Array.from(new Set(n.map(e=>e.model_group))).sort(),x=()=>{i(!1),f([{id:"1",primaryModel:null,fallbackModels:[]}])},v=async()=>{let e=b.filter(e=>!e.primaryModel||0===e.fallbackModels.length);if(e.length>0)return void L.message.error(`Please complete configuration for all groups. ${e.length} group(s) incomplete.`);let t=[...l||[],...b.map(e=>({[e.primaryModel]:e.fallbackModels}))];if(o){p(!0);try{await o(t),A.default.success(`${b.length} fallback configuration(s) added successfully!`),x()}catch(e){console.error("Error saving fallbacks:",e)}finally{p(!1)}}else A.default.fromBackend("onChange callback not provided")};return(0,t.jsxs)("div",{children:[(0,t.jsx)(m.Button,{className:"mx-auto",onClick:()=>i(!0),icon:()=>(0,t.jsx)("span",{className:"mr-1",children:"+"}),children:"Add Fallbacks"}),(0,t.jsxs)(D,{open:s,onCancel:x,children:[(0,t.jsx)(z.FallbackSelectionForm,{groups:b,onGroupsChange:f,availableModels:h,maxFallbacks:10,maxGroups:5},c),b.length>0&&(0,t.jsxs)("div",{className:"flex items-center justify-end space-x-3 pt-6 mt-6 border-t border-gray-100",children:[(0,t.jsx)(R.Button,{type:"default",onClick:x,disabled:g,children:"Cancel"}),(0,t.jsx)(R.Button,{type:"default",onClick:v,disabled:0===b.length||g,loading:g,children:g?"Saving Configuration...":"Save All Configurations"})]})]})]})}let G="inline-flex items-center gap-2 px-2.5 py-1 rounded-md border border-gray-200 bg-gray-50 text-sm font-medium text-gray-800 shrink-0";async function V(e,r){console.log=function(){};let a=window.location.origin,l=new M.default.OpenAI({apiKey:r,baseURL:a,dangerouslyAllowBrowser:!0});try{A.default.info("Testing fallback model response...");let r=await l.chat.completions.create({model:e,messages:[{role:"user",content:"Hi, this is a test message"}],mock_testing_fallbacks:!0});A.default.success((0,t.jsxs)("span",{children:["Test model=",(0,t.jsx)("strong",{children:e}),", received model=",(0,t.jsx)("strong",{children:r.model}),". See"," ",(0,t.jsx)("a",{href:"#",onClick:()=>window.open("https://docs.litellm.ai/docs/proxy/reliability","_blank"),style:{textDecoration:"underline",color:"blue"},children:"curl"})]}))}catch(e){A.default.fromBackend(`Error occurred while generating model response. Please try again. Error: ${e}`)}}let q=({accessToken:e,userRole:a,userID:i,modelData:u})=>{let[m,p]=(0,r.useState)({}),[b,f]=(0,r.useState)(!1),[h,x]=(0,r.useState)(null),[v,y]=(0,r.useState)(!1),{data:w}=(0,_.useModelCostMap)(),N=e=>null!=w&&"object"==typeof w&&e in w?w[e].litellm_provider??"":"";(0,r.useEffect)(()=>{e&&a&&i&&(0,C.getCallbacksCall)(e,i,a).then(e=>{console.log("callbacks",e);let t=e.router_settings;"model_group_retry_policy"in t&&delete t.model_group_retry_policy,p(t)})},[e,a,i]);let j=e=>{x(e),y(!0)},M=async()=>{if(!h||!e)return;let t=Object.keys(h)[0];if(!t)return;f(!0);let r=m.fallbacks.map(e=>{let r={...e};return t in r&&Array.isArray(r[t])&&delete r[t],r}).filter(e=>Object.keys(e).length>0),a={...m,fallbacks:r};try{await (0,C.setCallbacksCall)(e,{router_settings:a}),p(a),A.default.success("Router settings updated successfully")}catch(e){A.default.fromBackend("Failed to update router settings: "+e)}finally{f(!1),y(!1),x(null)}};if(!e)return null;let R=async t=>{if(!e)return;let r={...m,fallbacks:t};try{await (0,C.setCallbacksCall)(e,{router_settings:r}),p(r)}catch(t){throw A.default.fromBackend("Failed to update router settings: "+t),e&&a&&i&&(0,C.getCallbacksCall)(e,i,a).then(e=>{let t=e.router_settings;"model_group_retry_policy"in t&&delete t.model_group_retry_policy,p(t)}),t}},L=Array.isArray(m.fallbacks)&&m.fallbacks.length>0;return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(H,{models:u?.data?u.data.map(e=>e.model_name):[],accessToken:e||"",value:m.fallbacks||[],onChange:R}),L?(0,t.jsxs)(l.Table,{children:[(0,t.jsx)(o.TableHead,{children:(0,t.jsxs)(s.TableRow,{children:[(0,t.jsx)(n.TableHeaderCell,{children:"Model Name"}),(0,t.jsx)(n.TableHeaderCell,{children:"Fallbacks"}),(0,t.jsx)(n.TableHeaderCell,{children:"Actions"})]})}),(0,t.jsx)(c.TableBody,{children:m.fallbacks.map((a,l)=>Object.entries(a).map(([o,i])=>{let n;return(0,t.jsxs)(s.TableRow,{children:[(0,t.jsx)(d.TableCell,{className:"align-top",children:(n=N?.(o)??o,(0,t.jsxs)("span",{className:G,children:[(0,t.jsx)($.ProviderLogo,{provider:n,className:"w-4 h-4 shrink-0"}),(0,t.jsx)("span",{children:o})]}))}),(0,t.jsx)(d.TableCell,{className:"align-top",children:function(e,a,l){let o=Array.isArray(a)?a:[];if(0===o.length)return null;let s=({modelName:e})=>{let r=l?.(e)??e;return(0,t.jsxs)("span",{className:G,children:[(0,t.jsx)($.ProviderLogo,{provider:r,className:"w-4 h-4 shrink-0"}),(0,t.jsx)("span",{children:e})]})};return(0,t.jsxs)("span",{className:"grid grid-cols-[auto_1fr] items-start gap-x-2 w-full min-w-0",children:[(0,t.jsx)("span",{className:"inline-flex items-center justify-center w-8 h-8 shrink-0 self-start text-blue-600","aria-hidden":!0,children:(0,t.jsx)(T,{className:"w-5 h-5 stroke-[2.5]"})}),(0,t.jsx)("span",{className:"flex flex-wrap items-start gap-1 min-w-0",children:o.map((e,a)=>(0,t.jsxs)(r.default.Fragment,{children:[a>0&&(0,t.jsx)(g.Icon,{icon:T,size:"xs",className:"shrink-0 text-gray-400"}),(0,t.jsx)(s,{modelName:e})]},e))})]})}(0,Array.isArray(i)?i:[],N)}),(0,t.jsxs)(d.TableCell,{className:"align-top",children:[(0,t.jsx)(I.Tooltip,{title:"Test fallback",children:(0,t.jsx)(g.Icon,{icon:E.PlayIcon,size:"sm",onClick:()=>V(Object.keys(a)[0],e||""),className:"cursor-pointer hover:text-blue-600"})}),(0,t.jsx)(I.Tooltip,{title:"Delete fallback",children:(0,t.jsx)("span",{"data-testid":"delete-fallback-button",role:"button",tabIndex:0,onClick:()=>j(a),onKeyDown:e=>"Enter"===e.key&&j(a),className:"cursor-pointer inline-flex",children:(0,t.jsx)(g.Icon,{icon:k.TrashIcon,size:"sm",className:"hover:text-red-600"})})})]})]},l.toString()+o)}))})]}):(0,t.jsx)("div",{className:"rounded-lg border border-gray-200 bg-gray-50 px-4 py-6 text-center",children:(0,t.jsx)(O.Typography.Text,{type:"secondary",children:"No fallbacks configured. Add fallbacks to automatically try another model when the primary fails."})}),(0,t.jsx)(S.default,{isOpen:v,title:"Delete Fallback?",message:"Are you sure you want to delete this fallback? This action cannot be undone.",resourceInformationTitle:"Fallback Information",resourceInformation:[{label:"Model Name",value:h?Object.keys(h)[0]:"",code:!0}],onCancel:()=>{y(!1),x(null)},onOk:M,confirmLoading:b})]})};e.s(["default",0,({accessToken:e,userRole:A,userID:N,modelData:_})=>{let[T,E]=(0,r.useState)([]);(0,r.useEffect)(()=>{e&&(0,C.getGeneralSettingsCall)(e).then(e=>{E(e)})},[e]);let I=(e,t)=>{E(T.map(r=>r.field_name===e?{...r,field_value:t}:r))};return e?(0,t.jsx)("div",{className:"w-full",children:(0,t.jsxs)(h.TabGroup,{className:"h-[75vh] w-full",children:[(0,t.jsxs)(x.TabList,{variant:"line",defaultValue:"1",className:"px-8 pt-4",children:[(0,t.jsx)(v.Tab,{value:"1",children:"Loadbalancing"}),(0,t.jsx)(v.Tab,{value:"2",children:"Fallbacks"}),(0,t.jsx)(v.Tab,{value:"3",children:"General"})]}),(0,t.jsxs)(f.TabPanels,{className:"px-8 py-6",children:[(0,t.jsx)(b.TabPanel,{children:(0,t.jsx)(j,{accessToken:e,userRole:A,userID:N,modelData:_})}),(0,t.jsx)(b.TabPanel,{children:(0,t.jsx)(q,{accessToken:e,userRole:A,userID:N,modelData:_})}),(0,t.jsx)(b.TabPanel,{children:(0,t.jsx)(a.Card,{children:(0,t.jsxs)(l.Table,{children:[(0,t.jsx)(o.TableHead,{children:(0,t.jsxs)(s.TableRow,{children:[(0,t.jsx)(n.TableHeaderCell,{children:"Setting"}),(0,t.jsx)(n.TableHeaderCell,{children:"Value"}),(0,t.jsx)(n.TableHeaderCell,{children:"Status"}),(0,t.jsx)(n.TableHeaderCell,{children:"Action"})]})}),(0,t.jsx)(c.TableBody,{children:T.filter(e=>"TypedDictionary"!==e.field_type).map((r,a)=>(0,t.jsxs)(s.TableRow,{children:[(0,t.jsxs)(d.TableCell,{children:[(0,t.jsx)(u.Text,{children:r.field_name}),(0,t.jsx)("p",{style:{fontSize:"0.65rem",color:"#808080",fontStyle:"italic"},className:"mt-1",children:r.field_description})]}),(0,t.jsx)(d.TableCell,{children:"Integer"==r.field_type?(0,t.jsx)(y.InputNumber,{step:1,value:r.field_value,onChange:e=>I(r.field_name,e)}):"Boolean"==r.field_type?(0,t.jsx)(p.Switch,{checked:!0===r.field_value||"true"===r.field_value,onChange:e=>I(r.field_name,e)}):null}),(0,t.jsx)(d.TableCell,{children:!0==r.stored_in_db?(0,t.jsx)(i.Badge,{icon:w.CheckCircleIcon,className:"text-white",children:"In DB"}):!1==r.stored_in_db?(0,t.jsx)(i.Badge,{className:"text-gray bg-white outline",children:"In Config"}):(0,t.jsx)(i.Badge,{className:"text-gray bg-white outline",children:"Not Set"})}),(0,t.jsxs)(d.TableCell,{children:[(0,t.jsx)(m.Button,{onClick:()=>((t,r)=>{if(!e)return;let a=T[r].field_value;if(null!=a&&void 0!=a)try{(0,C.updateConfigFieldSetting)(e,t,a);let r=T.map(e=>e.field_name===t?{...e,stored_in_db:!0}:e);E(r)}catch(e){}})(r.field_name,a),children:"Update"}),(0,t.jsx)(g.Icon,{icon:k.TrashIcon,color:"red",onClick:()=>((t,r)=>{if(e)try{(0,C.deleteConfigFieldSetting)(e,t);let r=T.map(e=>e.field_name===t?{...e,stored_in_db:null,field_value:null}:e);E(r)}catch(e){}})(r.field_name,0),children:"Reset"})]})]},a))})]})})})]})]})}):null}],226898)},511715,e=>{"use strict";var t=e.i(843476),r=e.i(226898),a=e.i(135214);e.s(["default",0,()=>{let{accessToken:e,userRole:l,userId:o}=(0,a.default)();return(0,t.jsx)(r.default,{accessToken:e,userRole:l,userID:o,modelData:{}})}])}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/b08200c758c5c505.js b/litellm/proxy/_experimental/out/_next/static/chunks/3da2633a10defd79.js similarity index 97% rename from litellm/proxy/_experimental/out/_next/static/chunks/b08200c758c5c505.js rename to litellm/proxy/_experimental/out/_next/static/chunks/3da2633a10defd79.js index 58a9150e6b..5e26accaf3 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/b08200c758c5c505.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/3da2633a10defd79.js @@ -1 +1 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,304911,e=>{"use strict";var t=e.i(843476),a=e.i(262218);let{Text:s}=e.i(898586).Typography;function l({userId:e}){return"default_user_id"===e?(0,t.jsx)(a.Tag,{color:"blue",children:"Default Proxy Admin"}):(0,t.jsx)(s,{children:e})}e.s(["default",()=>l])},11751,e=>{"use strict";function t(e){return""===e?null:e}e.s(["mapEmptyStringToNull",()=>t])},772345,e=>{"use strict";e.i(247167);var t=e.i(931067),a=e.i(271645);let s={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M168 504.2c1-43.7 10-86.1 26.9-126 17.3-41 42.1-77.7 73.7-109.4S337 212.3 378 195c42.4-17.9 87.4-27 133.9-27s91.5 9.1 133.8 27A341.5 341.5 0 01755 268.8c9.9 9.9 19.2 20.4 27.8 31.4l-60.2 47a8 8 0 003 14.1l175.7 43c5 1.2 9.9-2.6 9.9-7.7l.8-180.9c0-6.7-7.7-10.5-12.9-6.3l-56.4 44.1C765.8 155.1 646.2 92 511.8 92 282.7 92 96.3 275.6 92 503.8a8 8 0 008 8.2h60c4.4 0 7.9-3.5 8-7.8zm756 7.8h-60c-4.4 0-7.9 3.5-8 7.8-1 43.7-10 86.1-26.9 126-17.3 41-42.1 77.8-73.7 109.4A342.45 342.45 0 01512.1 856a342.24 342.24 0 01-243.2-100.8c-9.9-9.9-19.2-20.4-27.8-31.4l60.2-47a8 8 0 00-3-14.1l-175.7-43c-5-1.2-9.9 2.6-9.9 7.7l-.7 181c0 6.7 7.7 10.5 12.9 6.3l56.4-44.1C258.2 868.9 377.8 932 512.2 932c229.2 0 415.5-183.7 419.8-411.8a8 8 0 00-8-8.2z"}}]},name:"sync",theme:"outlined"};var l=e.i(9583),r=a.forwardRef(function(e,r){return a.createElement(l.default,(0,t.default)({},e,{ref:r,icon:s}))});e.s(["SyncOutlined",0,r],772345)},72713,e=>{"use strict";e.i(247167);var t=e.i(931067),a=e.i(271645);let s={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"};var l=e.i(9583),r=a.forwardRef(function(e,r){return a.createElement(l.default,(0,t.default)({},e,{ref:r,icon:s}))});e.s(["CalendarOutlined",0,r],72713)},962944,e=>{"use strict";e.i(247167);var t=e.i(931067),a=e.i(271645);let s={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M848 359.3H627.7L825.8 109c4.1-5.3.4-13-6.3-13H436c-2.8 0-5.5 1.5-6.9 4L170 547.5c-3.1 5.3.7 12 6.9 12h174.4l-89.4 357.6c-1.9 7.8 7.5 13.3 13.3 7.7L853.5 373c5.2-4.9 1.7-13.7-5.5-13.7zM378.2 732.5l60.3-241H281.1l189.6-327.4h224.6L487 427.4h211L378.2 732.5z"}}]},name:"thunderbolt",theme:"outlined"};var l=e.i(9583),r=a.forwardRef(function(e,r){return a.createElement(l.default,(0,t.default)({},e,{ref:r,icon:s}))});e.s(["ThunderboltOutlined",0,r],962944)},534172,3750,e=>{"use strict";e.i(247167);var t=e.i(931067),a=e.i(271645);let s={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M866.9 169.9L527.1 54.1C523 52.7 517.5 52 512 52s-11 .7-15.1 2.1L157.1 169.9c-8.3 2.8-15.1 12.4-15.1 21.2v482.4c0 8.8 5.7 20.4 12.6 25.9L499.3 968c3.5 2.7 8 4.1 12.6 4.1s9.2-1.4 12.6-4.1l344.7-268.6c6.9-5.4 12.6-17 12.6-25.9V191.1c.2-8.8-6.6-18.3-14.9-21.2zM810 654.3L512 886.5 214 654.3V226.7l298-101.6 298 101.6v427.6zm-405.8-201c-3-4.1-7.8-6.6-13-6.6H336c-6.5 0-10.3 7.4-6.5 12.7l126.4 174a16.1 16.1 0 0026 0l212.6-292.7c3.8-5.3 0-12.7-6.5-12.7h-55.2c-5.1 0-10 2.5-13 6.6L468.9 542.4l-64.7-89.1z"}}]},name:"safety-certificate",theme:"outlined"};var l=e.i(9583),r=a.forwardRef(function(e,r){return a.createElement(l.default,(0,t.default)({},e,{ref:r,icon:s}))});e.s(["SafetyCertificateOutlined",0,r],534172);let i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M668.6 320c0-4.4-3.6-8-8-8h-54.5c-3 0-5.8 1.7-7.1 4.4l-84.7 168.8H511l-84.7-168.8a8 8 0 00-7.1-4.4h-55.7c-1.3 0-2.6.3-3.8 1-3.9 2.1-5.3 7-3.2 10.8l103.9 191.6h-57c-4.4 0-8 3.6-8 8v27.1c0 4.4 3.6 8 8 8h76v39h-76c-4.4 0-8 3.6-8 8v27.1c0 4.4 3.6 8 8 8h76V704c0 4.4 3.6 8 8 8h49.9c4.4 0 8-3.6 8-8v-63.5h76.3c4.4 0 8-3.6 8-8v-27.1c0-4.4-3.6-8-8-8h-76.3v-39h76.3c4.4 0 8-3.6 8-8v-27.1c0-4.4-3.6-8-8-8H564l103.7-191.6c.5-1.1.9-2.4.9-3.7zM157.9 504.2a352.7 352.7 0 01103.5-242.4c32.5-32.5 70.3-58.1 112.4-75.9 43.6-18.4 89.9-27.8 137.6-27.8 47.8 0 94.1 9.3 137.6 27.8 42.1 17.8 79.9 43.4 112.4 75.9 10 10 19.3 20.5 27.9 31.4l-50 39.1a8 8 0 003 14.1l156.8 38.3c5 1.2 9.9-2.6 9.9-7.7l.8-161.5c0-6.7-7.7-10.5-12.9-6.3l-47.8 37.4C770.7 146.3 648.6 82 511.5 82 277 82 86.3 270.1 82 503.8a8 8 0 008 8.2h60c4.3 0 7.8-3.5 7.9-7.8zM934 512h-60c-4.3 0-7.9 3.5-8 7.8a352.7 352.7 0 01-103.5 242.4 352.57 352.57 0 01-112.4 75.9c-43.6 18.4-89.9 27.8-137.6 27.8s-94.1-9.3-137.6-27.8a352.57 352.57 0 01-112.4-75.9c-10-10-19.3-20.5-27.9-31.4l49.9-39.1a8 8 0 00-3-14.1l-156.8-38.3c-5-1.2-9.9 2.6-9.9 7.7l-.8 161.7c0 6.7 7.7 10.5 12.9 6.3l47.8-37.4C253.3 877.7 375.4 942 512.5 942 747 942 937.7 753.9 942 520.2a8 8 0 00-8-8.2z"}}]},name:"transaction",theme:"outlined"};var n=a.forwardRef(function(e,s){return a.createElement(l.default,(0,t.default)({},e,{ref:s,icon:i}))});e.s(["TransactionOutlined",0,n],3750)},784647,505022,721929,e=>{"use strict";var t=e.i(843476),a=e.i(464571),s=e.i(898586),l=e.i(592968),r=e.i(770914),i=e.i(312361),n=e.i(525720),o=e.i(447566),d=e.i(772345),c=e.i(955135),m=e.i(646563),u=e.i(771674),x=e.i(948401),p=e.i(72713),g=e.i(637235),h=e.i(962944),j=e.i(534172),_=e.i(3750),y=e.i(304911);let{Text:b}=s.Typography;function f({label:e,value:a,icon:s,truncate:l=!1,copyable:i=!1,defaultUserIdCheck:n=!1}){let o=!a,d=n&&"default_user_id"===a,c=d?(0,t.jsx)(y.default,{userId:a}):(0,t.jsx)(b,{strong:!0,copyable:!!(i&&!o&&!d)&&{tooltips:[`Copy ${e}`,"Copied!"]},ellipsis:l,style:l?{maxWidth:160,display:"block"}:void 0,children:o?"-":a});return(0,t.jsxs)("div",{children:[(0,t.jsxs)(r.Space,{size:4,children:[(0,t.jsx)(b,{type:"secondary",children:s}),(0,t.jsx)(b,{type:"secondary",style:{fontSize:12,textTransform:"uppercase",letterSpacing:"0.05em"},children:e})]}),(0,t.jsx)("div",{children:c})]})}let{Title:v,Text:N}=s.Typography;function k({data:e,onBack:s,onCreateNew:y,onRegenerate:b,onDelete:k,onResetSpend:T,canModifyKey:w=!0,backButtonText:S="Back to Keys",regenerateDisabled:I=!1,regenerateTooltip:C}){return(0,t.jsxs)("div",{children:[y&&(0,t.jsx)("div",{style:{marginBottom:16},children:(0,t.jsx)(a.Button,{type:"primary",icon:(0,t.jsx)(m.PlusOutlined,{}),onClick:y,children:"Create New Key"})}),(0,t.jsx)("div",{style:{marginBottom:16},children:(0,t.jsx)(a.Button,{type:"text",icon:(0,t.jsx)(o.ArrowLeftOutlined,{}),onClick:s,children:S})}),(0,t.jsxs)(n.Flex,{justify:"space-between",align:"start",style:{marginBottom:20},children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(v,{level:3,copyable:{tooltips:["Copy Key Alias","Copied!"]},style:{margin:0},children:e.keyName}),(0,t.jsxs)(N,{type:"secondary",copyable:{text:e.keyId,tooltips:["Copy Key ID","Copied!"]},children:["Key ID: ",e.keyId]})]}),w&&(0,t.jsxs)(r.Space,{children:[(0,t.jsx)(l.Tooltip,{title:C||"",children:(0,t.jsx)("span",{children:(0,t.jsx)(a.Button,{icon:(0,t.jsx)(d.SyncOutlined,{}),onClick:b,disabled:I,children:"Regenerate Key"})})}),T&&(0,t.jsx)(a.Button,{danger:!0,icon:(0,t.jsx)(_.TransactionOutlined,{}),onClick:T,children:"Reset Spend"}),(0,t.jsx)(a.Button,{danger:!0,icon:(0,t.jsx)(c.DeleteOutlined,{}),onClick:k,children:"Delete Key"})]})]}),(0,t.jsxs)(n.Flex,{align:"stretch",gap:40,style:{marginBottom:40},children:[(0,t.jsxs)(r.Space,{direction:"vertical",size:16,children:[(0,t.jsx)(f,{label:"User Email",value:e.userEmail,icon:(0,t.jsx)(x.MailOutlined,{})}),(0,t.jsx)(f,{label:"User ID",value:e.userId,icon:(0,t.jsx)(u.UserOutlined,{}),truncate:!0,copyable:!0,defaultUserIdCheck:!0})]}),(0,t.jsx)(i.Divider,{type:"vertical",style:{height:"auto"}}),(0,t.jsxs)(r.Space,{direction:"vertical",size:16,children:[(0,t.jsx)(f,{label:"Created At",value:e.createdAt,icon:(0,t.jsx)(p.CalendarOutlined,{})}),(0,t.jsx)(f,{label:"Created By",value:e.createdBy,icon:(0,t.jsx)(j.SafetyCertificateOutlined,{}),truncate:!0,copyable:!0,defaultUserIdCheck:!0})]}),(0,t.jsx)(i.Divider,{type:"vertical",style:{height:"auto"}}),(0,t.jsxs)(r.Space,{direction:"vertical",size:16,children:[(0,t.jsx)(f,{label:"Last Updated",value:e.lastUpdated,icon:(0,t.jsx)(g.ClockCircleOutlined,{})}),(0,t.jsx)(f,{label:"Last Active",value:e.lastActive,icon:(0,t.jsx)(h.ThunderboltOutlined,{})})]})]})]})}e.s(["KeyInfoHeader",()=>k],784647);var T=e.i(599724),w=e.i(389083),S=e.i(278587),I=e.i(271645);let C=I.forwardRef(function(e,t){return I.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),I.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["default",0,({autoRotate:e=!1,rotationInterval:a,lastRotationAt:s,keyRotationAt:l,nextRotationAt:r,variant:i="card",className:n=""})=>{let o=e=>{let t=new Date(e),a=t.toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"}),s=t.toLocaleTimeString("en-US",{hour:"numeric",minute:"2-digit",hour12:!0});return`${a} at ${s}`},d=(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsx)("div",{className:"space-y-3",children:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(S.RefreshIcon,{className:"h-4 w-4 text-blue-600"}),(0,t.jsx)(T.Text,{className:"font-semibold text-gray-900",children:"Auto-Rotation"}),(0,t.jsx)(w.Badge,{color:e?"green":"gray",size:"xs",children:e?"Enabled":"Disabled"}),e&&a&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(T.Text,{className:"text-gray-400",children:"•"}),(0,t.jsxs)(T.Text,{className:"text-sm text-gray-600",children:["Every ",a]})]})]})}),(e||s||l||r)&&(0,t.jsxs)("div",{className:"space-y-3",children:[s&&(0,t.jsxs)("div",{className:"flex items-center gap-2 p-3 bg-gray-50 border border-gray-200 rounded-md",children:[(0,t.jsx)(C,{className:"w-4 h-4 text-gray-500"}),(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)(T.Text,{className:"font-medium text-gray-700",children:"Last Rotation"}),(0,t.jsx)(T.Text,{className:"text-sm text-gray-600",children:o(s)})]})]}),(l||r)&&(0,t.jsxs)("div",{className:"flex items-center gap-2 p-3 bg-gray-50 border border-gray-200 rounded-md",children:[(0,t.jsx)(C,{className:"w-4 h-4 text-gray-500"}),(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)(T.Text,{className:"font-medium text-gray-700",children:"Next Scheduled Rotation"}),(0,t.jsx)(T.Text,{className:"text-sm text-gray-600",children:o(r||l||"")})]})]}),e&&!s&&!l&&!r&&(0,t.jsxs)("div",{className:"flex items-center gap-2 p-3 bg-gray-50 border border-gray-100 rounded-md",children:[(0,t.jsx)(C,{className:"w-4 h-4 text-gray-500"}),(0,t.jsx)(T.Text,{className:"text-gray-600",children:"No rotation history available"})]})]}),!e&&!s&&!l&&!r&&(0,t.jsxs)("div",{className:"flex items-center gap-2 p-3 bg-gray-50 border border-gray-100 rounded-md",children:[(0,t.jsx)(S.RefreshIcon,{className:"w-4 h-4 text-gray-400"}),(0,t.jsx)(T.Text,{className:"text-gray-600",children:"Auto-rotation is not enabled for this key"})]})]});return"card"===i?(0,t.jsxs)("div",{className:`bg-white border border-gray-200 rounded-lg p-6 ${n}`,children:[(0,t.jsx)("div",{className:"flex items-center gap-2 mb-6",children:(0,t.jsxs)("div",{children:[(0,t.jsx)(T.Text,{className:"font-semibold text-gray-900",children:"Auto-Rotation"}),(0,t.jsx)(T.Text,{className:"text-xs text-gray-500",children:"Automatic key rotation settings and status for this key"})]})}),d]}):(0,t.jsxs)("div",{className:`${n}`,children:[(0,t.jsx)(T.Text,{className:"font-medium text-gray-900 mb-3",children:"Auto-Rotation"}),d]})}],505022);let A=["logging"];e.s(["extractLoggingSettings",0,e=>e&&"object"==typeof e&&Array.isArray(e.logging)?e.logging:[],"formatMetadataForDisplay",0,(e,t=2)=>JSON.stringify(e&&"object"==typeof e?Object.fromEntries(Object.entries(e).filter(([e])=>!A.includes(e))):{},null,t),"stripTagsFromMetadata",0,e=>{if(!e||"object"!=typeof e)return e;let{tags:t,...a}=e;return a}],721929)},643449,e=>{"use strict";var t=e.i(843476),a=e.i(599724),s=e.i(389083),l=e.i(810757),r=e.i(477386),i=e.i(557662);e.s(["default",0,function({loggingConfigs:e=[],disabledCallbacks:n=[],variant:o="card",className:d=""}){let c=(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(l.CogIcon,{className:"h-4 w-4 text-blue-600"}),(0,t.jsx)(a.Text,{className:"font-semibold text-gray-900",children:"Logging Integrations"}),(0,t.jsx)(s.Badge,{color:"blue",size:"xs",children:e.length})]}),e.length>0?(0,t.jsx)("div",{className:"space-y-3",children:e.map((e,r)=>{var n;let o=(n=e.callback_name,Object.entries(i.callback_map).find(([e,t])=>t===n)?.[0]||n),d=i.callbackInfo[o]?.logo;return(0,t.jsxs)("div",{className:"flex items-center justify-between p-3 rounded-lg bg-blue-50 border border-blue-200",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[d?(0,t.jsx)("img",{src:d,alt:o,className:"w-5 h-5 object-contain"}):(0,t.jsx)(l.CogIcon,{className:"h-5 w-5 text-gray-400"}),(0,t.jsxs)("div",{children:[(0,t.jsx)(a.Text,{className:"font-medium text-blue-800",children:o}),(0,t.jsxs)(a.Text,{className:"text-xs text-blue-600",children:[Object.keys(e.callback_vars).length," parameters configured"]})]})]}),(0,t.jsx)(s.Badge,{color:(e=>{switch(e){case"success":return"green";case"failure":return"red";case"success_and_failure":return"blue";default:return"gray"}})(e.callback_type),size:"sm",children:(e=>{switch(e){case"success":return"Success Only";case"failure":return"Failure Only";case"success_and_failure":return"Success & Failure";default:return e}})(e.callback_type)})]},r)})}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(l.CogIcon,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(a.Text,{className:"text-gray-500 text-sm",children:"No logging integrations configured"})]})]}),(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(r.BanIcon,{className:"h-4 w-4 text-red-600"}),(0,t.jsx)(a.Text,{className:"font-semibold text-gray-900",children:"Disabled Callbacks"}),(0,t.jsx)(s.Badge,{color:"red",size:"xs",children:n.length})]}),n.length>0?(0,t.jsx)("div",{className:"space-y-3",children:n.map((e,l)=>{let n=i.reverse_callback_map[e]||e,o=i.callbackInfo[n]?.logo;return(0,t.jsxs)("div",{className:"flex items-center justify-between p-3 rounded-lg bg-red-50 border border-red-200",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[o?(0,t.jsx)("img",{src:o,alt:n,className:"w-5 h-5 object-contain"}):(0,t.jsx)(r.BanIcon,{className:"h-5 w-5 text-gray-400"}),(0,t.jsxs)("div",{children:[(0,t.jsx)(a.Text,{className:"font-medium text-red-800",children:n}),(0,t.jsx)(a.Text,{className:"text-xs text-red-600",children:"Disabled for this key"})]})]}),(0,t.jsx)(s.Badge,{color:"red",size:"sm",children:"Disabled"})]},l)})}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(r.BanIcon,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(a.Text,{className:"text-gray-500 text-sm",children:"No callbacks disabled"})]})]})]});return"card"===o?(0,t.jsxs)("div",{className:`bg-white border border-gray-200 rounded-lg p-6 ${d}`,children:[(0,t.jsx)("div",{className:"flex items-center gap-2 mb-6",children:(0,t.jsxs)("div",{children:[(0,t.jsx)(a.Text,{className:"font-semibold text-gray-900",children:"Logging Settings"}),(0,t.jsx)(a.Text,{className:"text-xs text-gray-500",children:"Active logging integrations and disabled callbacks for this key"})]})}),c]}):(0,t.jsxs)("div",{className:`${d}`,children:[(0,t.jsx)(a.Text,{className:"font-medium text-gray-900 mb-3",children:"Logging Settings"}),c]})}])},65932,690284,e=>{"use strict";var t=e.i(954616),a=e.i(912598),s=e.i(764205),l=e.i(135214),r=e.i(207082);let i=async(e,t)=>{let a=(0,s.getProxyBaseUrl)(),l=`${a?`${a}/key/${t}/reset_spend`:`/key/${t}/reset_spend`}`,r=await fetch(l,{method:"POST",headers:{[(0,s.getGlobalLitellmHeaderName)()]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({reset_to:0})});if(!r.ok){let e=await r.json(),t=(0,s.deriveErrorMessage)(e);throw(0,s.handleError)(t),Error(t)}return r.json()};e.s(["useResetKeySpend",0,()=>{let{accessToken:e}=(0,l.default)(),s=(0,a.useQueryClient)();return(0,t.useMutation)({mutationFn:async t=>{if(!e)throw Error("Access token is required");return i(e,t)},onSuccess:()=>{s.invalidateQueries({queryKey:r.keyKeys.all})}})}],65932);var n=e.i(843476),o=e.i(994388),d=e.i(309426),c=e.i(350967),m=e.i(599724),u=e.i(779241),x=e.i(629569),p=e.i(808613),g=e.i(28651),h=e.i(212931),j=e.i(439189),_=e.i(497245),y=e.i(96226),b=e.i(435684);function f(e,t){let{years:a=0,months:s=0,weeks:l=0,days:r=0,hours:i=0,minutes:n=0,seconds:o=0}=t,d=(0,b.toDate)(e),c=s||a?(0,_.addMonths)(d,s+12*a):d,m=r||l?(0,j.addDays)(c,r+7*l):c;return(0,y.constructFrom)(e,m.getTime()+1e3*(o+60*(n+60*i)))}var v=e.i(271645),N=e.i(237016),k=e.i(727749);function T({selectedToken:e,visible:t,onClose:a,onKeyUpdate:r}){let{accessToken:i}=(0,l.default)(),[j]=p.Form.useForm(),[_,y]=(0,v.useState)(null),[b,T]=(0,v.useState)(null),[w,S]=(0,v.useState)(null),[I,C]=(0,v.useState)(!1),[A,F]=(0,v.useState)(!1),[L,M]=(0,v.useState)(null);(0,v.useEffect)(()=>{t&&e&&i&&(j.setFieldsValue({key_alias:e.key_alias,max_budget:e.max_budget,tpm_limit:e.tpm_limit,rpm_limit:e.rpm_limit,duration:e.duration||"",grace_period:""}),M(i),F(e.key_name===i))},[t,e,j,i]),(0,v.useEffect)(()=>{t||(y(null),C(!1),F(!1),M(null),j.resetFields())},[t,j]);let R=e=>{if(!e)return null;try{let t,a=new Date;if(e.endsWith("s"))t=f(a,{seconds:parseInt(e)});else if(e.endsWith("h"))t=f(a,{hours:parseInt(e)});else if(e.endsWith("d"))t=f(a,{days:parseInt(e)});else throw Error("Invalid duration format");return t.toLocaleString()}catch(e){return null}};(0,v.useEffect)(()=>{b?.duration?S(R(b.duration)):S(null)},[b?.duration]);let D=async()=>{if(e&&L){C(!0);try{let t=await j.validateFields(),a=await (0,s.regenerateKeyCall)(L,e.token||e.token_id,t);y(a.key),k.default.success("Virtual Key regenerated successfully"),console.log("Full regenerate response:",a);let l={token:a.token||a.key_id||e.token,key_name:a.key,max_budget:t.max_budget,tpm_limit:t.tpm_limit,rpm_limit:t.rpm_limit,expires:t.duration?R(t.duration):e.expires,...a};console.log("Updated key data with new token:",l),r&&r(l),C(!1)}catch(e){console.error("Error regenerating key:",e),k.default.fromBackend(e),C(!1)}}},B=()=>{y(null),C(!1),F(!1),M(null),j.resetFields(),a()};return(0,n.jsx)(h.Modal,{title:"Regenerate Virtual Key",open:t,onCancel:B,footer:_?[(0,n.jsx)(o.Button,{onClick:B,children:"Close"},"close")]:[(0,n.jsx)(o.Button,{onClick:B,className:"mr-2",children:"Cancel"},"cancel"),(0,n.jsx)(o.Button,{onClick:D,disabled:I,children:I?"Regenerating...":"Regenerate"},"regenerate")],children:_?(0,n.jsxs)(c.Grid,{numItems:1,className:"gap-2 w-full",children:[(0,n.jsx)(x.Title,{children:"Regenerated Key"}),(0,n.jsx)(d.Col,{numColSpan:1,children:(0,n.jsxs)("p",{children:["Please replace your old key with the new key generated. For security reasons,"," ",(0,n.jsx)("b",{children:"you will not be able to view it again"})," through your LiteLLM account. If you lose this secret key, you will need to generate a new one."]})}),(0,n.jsxs)(d.Col,{numColSpan:1,children:[(0,n.jsx)(m.Text,{className:"mt-3",children:"Key Alias:"}),(0,n.jsx)("div",{className:"bg-gray-100 p-2 rounded mb-2",children:(0,n.jsx)("pre",{className:"break-words whitespace-normal",children:e?.key_alias||"No alias set"})}),(0,n.jsx)(m.Text,{className:"mt-3",children:"New Virtual Key:"}),(0,n.jsx)("div",{className:"bg-gray-100 p-2 rounded mb-2",children:(0,n.jsx)("pre",{className:"break-words whitespace-normal",children:_})}),(0,n.jsx)(N.CopyToClipboard,{text:_,onCopy:()=>k.default.success("Virtual Key copied to clipboard"),children:(0,n.jsx)(o.Button,{className:"mt-3",children:"Copy Virtual Key"})})]})]}):(0,n.jsxs)(p.Form,{form:j,layout:"vertical",onValuesChange:e=>{"duration"in e&&T(t=>({...t,duration:e.duration}))},children:[(0,n.jsx)(p.Form.Item,{name:"key_alias",label:"Key Alias",children:(0,n.jsx)(u.TextInput,{disabled:!0})}),(0,n.jsx)(p.Form.Item,{name:"max_budget",label:"Max Budget (USD)",children:(0,n.jsx)(g.InputNumber,{step:.01,precision:2,style:{width:"100%"}})}),(0,n.jsx)(p.Form.Item,{name:"tpm_limit",label:"TPM Limit",children:(0,n.jsx)(g.InputNumber,{style:{width:"100%"}})}),(0,n.jsx)(p.Form.Item,{name:"rpm_limit",label:"RPM Limit",children:(0,n.jsx)(g.InputNumber,{style:{width:"100%"}})}),(0,n.jsx)(p.Form.Item,{name:"duration",label:"Expire Key (eg: 30s, 30h, 30d)",className:"mt-8",children:(0,n.jsx)(u.TextInput,{placeholder:""})}),(0,n.jsxs)("div",{className:"mt-2 text-sm text-gray-500",children:["Current expiry: ",e?.expires?new Date(e.expires).toLocaleString():"Never"]}),w&&(0,n.jsxs)("div",{className:"mt-2 text-sm text-green-600",children:["New expiry: ",w]}),(0,n.jsx)(p.Form.Item,{name:"grace_period",label:"Grace Period (eg: 24h, 2d)",tooltip:"Keep the old key valid for this duration after rotation. Both keys work during this period for seamless cutover. Empty = immediate revoke.",className:"mt-8",rules:[{pattern:/^(\d+(s|m|h|d|w|mo))?$/,message:"Must be a duration like 30s, 30m, 24h, 2d, 1w, or 1mo"}],children:(0,n.jsx)(u.TextInput,{placeholder:"e.g. 24h, 2d (empty = immediate revoke)"})}),(0,n.jsx)("div",{className:"mt-2 text-sm text-gray-500",children:"Recommended: 24h to 72h for production keys to allow seamless client migration."})]})})}e.s(["RegenerateKeyModal",()=>T],690284)},183588,e=>{"use strict";var t=e.i(843476),a=e.i(266484);e.s(["default",0,({value:e,onChange:s,disabledCallbacks:l=[],onDisabledCallbacksChange:r})=>(0,t.jsx)(a.default,{value:e,onChange:s,disabledCallbacks:l,onDisabledCallbacksChange:r})])},20147,e=>{"use strict";var t=e.i(843476),a=e.i(135214),s=e.i(510674),l=e.i(292639),r=e.i(214541),i=e.i(500330),n=e.i(11751),o=e.i(530212),d=e.i(389083),c=e.i(994388),m=e.i(304967),u=e.i(350967),x=e.i(197647),p=e.i(653824),g=e.i(881073),h=e.i(404206),j=e.i(723731),_=e.i(599724),y=e.i(629569),b=e.i(808613),f=e.i(212931),v=e.i(262218),N=e.i(784647),k=e.i(271645),T=e.i(708347),w=e.i(557662),S=e.i(505022),I=e.i(127952),C=e.i(721929),A=e.i(643449),F=e.i(727749),L=e.i(764205),M=e.i(65932),R=e.i(384767),D=e.i(690284),B=e.i(190702),E=e.i(891547),P=e.i(921511),O=e.i(827252),K=e.i(779241),U=e.i(311451),V=e.i(199133),$=e.i(790848),z=e.i(592968),G=e.i(552130),W=e.i(9314),H=e.i(392110),q=e.i(844565),J=e.i(939510),Q=e.i(75921),Y=e.i(390605),X=e.i(702597),Z=e.i(435451),ee=e.i(183588),et=e.i(916940);function ea({keyData:e,onCancel:a,onSubmit:r,teams:i,accessToken:n,userID:o,userRole:d,premiumUser:m=!1}){let u=m||null!=d&&T.rolesWithWriteAccess.includes(d),[x]=b.Form.useForm(),[p,g]=(0,k.useState)([]),[h,j]=(0,k.useState)({}),_=i?.find(t=>t.team_id===e.team_id),[y,f]=(0,k.useState)([]),[v,N]=(0,k.useState)(Array.isArray(e.metadata?.litellm_disabled_callbacks)?(0,w.mapInternalToDisplayNames)(e.metadata.litellm_disabled_callbacks):[]),[S,I]=(0,k.useState)(e.auto_rotate||!1),[A,M]=(0,k.useState)(e.rotation_interval||""),[R,D]=(0,k.useState)(!e.expires),[B,ea]=(0,k.useState)(!1),{data:es}=(0,s.useProjects)(),{data:el}=(0,l.useUISettings)(),er=!!el?.values?.enable_projects_ui,ei=!!e.project_id,en=(()=>{if(!e.project_id)return null;let t=es?.find(t=>t.project_id===e.project_id);return t?.project_alias?`${t.project_alias} (${e.project_id})`:e.project_id})();(0,k.useEffect)(()=>{let t=async()=>{if(o&&d&&n)try{if(null===e.team_id){let e=(await (0,L.modelAvailableCall)(n,o,d)).data.map(e=>e.id);f(e)}else if(_?.team_id){let e=await (0,X.fetchTeamModels)(o,d,n,_.team_id);f(Array.from(new Set([..._.models,...e])))}}catch(e){console.error("Error fetching models:",e)}};(async()=>{if(n)try{let e=await (0,L.getPromptsList)(n);g(e.prompts.map(e=>e.prompt_id))}catch(e){console.error("Failed to fetch prompts:",e)}})(),t()},[o,d,n,_,e.team_id]),(0,k.useEffect)(()=>{x.setFieldValue("disabled_callbacks",v)},[x,v]);let eo=e=>e&&({"24h":"daily","7d":"weekly","30d":"monthly"})[e]||null,ed={...e,token:e.token||e.token_id,budget_duration:eo(e.budget_duration),metadata:(0,C.formatMetadataForDisplay)((0,C.stripTagsFromMetadata)(e.metadata)),guardrails:e.metadata?.guardrails,disable_global_guardrails:e.metadata?.disable_global_guardrails||!1,prompts:e.metadata?.prompts,tags:e.metadata?.tags,vector_stores:e.object_permission?.vector_stores||[],mcp_servers_and_groups:{servers:e.object_permission?.mcp_servers||[],accessGroups:e.object_permission?.mcp_access_groups||[]},mcp_tool_permissions:e.object_permission?.mcp_tool_permissions||{},agents_and_groups:{agents:e.object_permission?.agents||[],accessGroups:e.object_permission?.agent_access_groups||[]},logging_settings:(0,C.extractLoggingSettings)(e.metadata),disabled_callbacks:Array.isArray(e.metadata?.litellm_disabled_callbacks)?(0,w.mapInternalToDisplayNames)(e.metadata.litellm_disabled_callbacks):[],access_group_ids:e.access_group_ids||[],auto_rotate:e.auto_rotate||!1,...e.rotation_interval&&{rotation_interval:e.rotation_interval},allowed_routes:Array.isArray(e.allowed_routes)&&e.allowed_routes.length>0?e.allowed_routes.join(", "):""};(0,k.useEffect)(()=>{x.setFieldsValue({...e,token:e.token||e.token_id,budget_duration:eo(e.budget_duration),metadata:(0,C.formatMetadataForDisplay)((0,C.stripTagsFromMetadata)(e.metadata)),guardrails:e.metadata?.guardrails,disable_global_guardrails:e.metadata?.disable_global_guardrails||!1,prompts:e.metadata?.prompts,tags:e.metadata?.tags,vector_stores:e.object_permission?.vector_stores||[],mcp_servers_and_groups:{servers:e.object_permission?.mcp_servers||[],accessGroups:e.object_permission?.mcp_access_groups||[]},mcp_tool_permissions:e.object_permission?.mcp_tool_permissions||{},logging_settings:(0,C.extractLoggingSettings)(e.metadata),disabled_callbacks:Array.isArray(e.metadata?.litellm_disabled_callbacks)?(0,w.mapInternalToDisplayNames)(e.metadata.litellm_disabled_callbacks):[],access_group_ids:e.access_group_ids||[],auto_rotate:e.auto_rotate||!1,...e.rotation_interval&&{rotation_interval:e.rotation_interval},allowed_routes:Array.isArray(e.allowed_routes)&&e.allowed_routes.length>0?e.allowed_routes.join(", "):""})},[e,x]),(0,k.useEffect)(()=>{x.setFieldValue("auto_rotate",S)},[S,x]),(0,k.useEffect)(()=>{A&&x.setFieldValue("rotation_interval",A)},[A,x]),(0,k.useEffect)(()=>{(async()=>{if(n)try{let e=await (0,L.tagListCall)(n);j(e)}catch(e){F.default.fromBackend("Error fetching tags: "+e)}})()},[n]);let ec=async e=>{try{if(ea(!0),"string"==typeof e.allowed_routes){let t=e.allowed_routes.trim();""===t?e.allowed_routes=[]:e.allowed_routes=t.split(",").map(e=>e.trim()).filter(e=>e.length>0)}R&&(e.duration=null),await r(e)}finally{ea(!1)}};return(0,t.jsxs)(b.Form,{form:x,onFinish:ec,initialValues:ed,layout:"vertical",children:[(0,t.jsx)(b.Form.Item,{label:"Key Alias",name:"key_alias",children:(0,t.jsx)(K.TextInput,{})}),(0,t.jsx)(b.Form.Item,{label:"Models",name:"models",children:(0,t.jsx)(b.Form.Item,{noStyle:!0,shouldUpdate:(e,t)=>e.allowed_routes!==t.allowed_routes||e.models!==t.models,children:({getFieldValue:e,setFieldValue:a})=>{let s=e("allowed_routes")||"",l="string"==typeof s&&""!==s.trim()?s.split(",").map(e=>e.trim()).filter(e=>e.length>0):[],r=l.includes("management_routes")||l.includes("info_routes"),i=e("models")||[];return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(V.Select,{mode:"multiple",placeholder:"Select models",style:{width:"100%"},disabled:r,value:r?[]:i,onChange:e=>a("models",e),children:[y.length>0&&(0,t.jsx)(V.Select.Option,{value:"all-team-models",children:"All Team Models"}),y.map(e=>(0,t.jsx)(V.Select.Option,{value:e,children:e},e))]}),r&&(0,t.jsx)("div",{style:{fontSize:"11px",color:"#6b7280",marginTop:"2px"},children:"Models field is disabled for this key type"})]})}})}),(0,t.jsx)(b.Form.Item,{label:"Key Type",children:(0,t.jsx)(b.Form.Item,{noStyle:!0,shouldUpdate:(e,t)=>e.allowed_routes!==t.allowed_routes,children:({getFieldValue:e,setFieldValue:a})=>{var s;let l=e("allowed_routes")||"",r=(s="string"==typeof l&&""!==l.trim()?l.split(",").map(e=>e.trim()).filter(e=>e.length>0):[])&&0!==s.length?s.includes("llm_api_routes")?"llm_api":s.includes("management_routes")?"management":s.includes("info_routes")?"read_only":"default":"default";return(0,t.jsxs)(V.Select,{placeholder:"Select key type",style:{width:"100%"},optionLabelProp:"label",value:r,onChange:e=>{switch(e){case"default":a("allowed_routes","");break;case"llm_api":a("allowed_routes","llm_api_routes");break;case"management":a("allowed_routes","management_routes"),a("models",[])}},children:[(0,t.jsx)(V.Select.Option,{value:"default",label:"Default",children:(0,t.jsxs)("div",{style:{padding:"4px 0"},children:[(0,t.jsx)("div",{style:{fontWeight:500},children:"Default"}),(0,t.jsx)("div",{style:{fontSize:"11px",color:"#6b7280",marginTop:"2px"},children:"Can call AI APIs + Management routes"})]})}),(0,t.jsx)(V.Select.Option,{value:"llm_api",label:"AI APIs",children:(0,t.jsxs)("div",{style:{padding:"4px 0"},children:[(0,t.jsx)("div",{style:{fontWeight:500},children:"AI APIs"}),(0,t.jsx)("div",{style:{fontSize:"11px",color:"#6b7280",marginTop:"2px"},children:"Can call only AI API routes (chat/completions, embeddings, etc.)"})]})}),(0,t.jsx)(V.Select.Option,{value:"management",label:"Management",children:(0,t.jsxs)("div",{style:{padding:"4px 0"},children:[(0,t.jsx)("div",{style:{fontWeight:500},children:"Management"}),(0,t.jsx)("div",{style:{fontSize:"11px",color:"#6b7280",marginTop:"2px"},children:"Can call only management routes (user/team/key management)"})]})})]})}})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Allowed Routes"," ",(0,t.jsx)(z.Tooltip,{title:"List of allowed routes for the key (comma-separated). Can be specific routes (e.g., '/chat/completions') or route patterns (e.g., 'llm_api_routes', 'management_routes', '/keys/*'). Leave empty to allow all routes.",children:(0,t.jsx)(O.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"allowed_routes",children:(0,t.jsx)(U.Input,{placeholder:"Enter allowed routes (comma-separated). Special values: llm_api_routes, management_routes. Examples: llm_api_routes, /chat/completions, /keys/*. Leave empty to allow all routes"})}),(0,t.jsx)(b.Form.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,t.jsx)(Z.default,{step:.01,style:{width:"100%"},placeholder:"Enter a numerical value"})}),(0,t.jsx)(b.Form.Item,{label:"Reset Budget",name:"budget_duration",children:(0,t.jsxs)(V.Select,{placeholder:"n/a",children:[(0,t.jsx)(V.Select.Option,{value:"daily",children:"Daily"}),(0,t.jsx)(V.Select.Option,{value:"weekly",children:"Weekly"}),(0,t.jsx)(V.Select.Option,{value:"monthly",children:"Monthly"})]})}),(0,t.jsx)(b.Form.Item,{label:"TPM Limit",name:"tpm_limit",children:(0,t.jsx)(Z.default,{min:0})}),(0,t.jsx)(J.default,{type:"tpm",name:"tpm_limit_type",showDetailedDescriptions:!1}),(0,t.jsx)(b.Form.Item,{label:"RPM Limit",name:"rpm_limit",children:(0,t.jsx)(Z.default,{min:0})}),(0,t.jsx)(J.default,{type:"rpm",name:"rpm_limit_type",showDetailedDescriptions:!1}),(0,t.jsx)(b.Form.Item,{label:"Max Parallel Requests",name:"max_parallel_requests",children:(0,t.jsx)(Z.default,{min:0})}),(0,t.jsx)(b.Form.Item,{label:"Model TPM Limit",name:"model_tpm_limit",children:(0,t.jsx)(U.Input.TextArea,{rows:4,placeholder:'{"gpt-4": 100, "claude-v1": 200}'})}),(0,t.jsx)(b.Form.Item,{label:"Model RPM Limit",name:"model_rpm_limit",children:(0,t.jsx)(U.Input.TextArea,{rows:4,placeholder:'{"gpt-4": 100, "claude-v1": 200}'})}),(0,t.jsx)(b.Form.Item,{label:"Guardrails",name:"guardrails",children:n&&(0,t.jsx)(E.default,{onChange:e=>{x.setFieldValue("guardrails",e)},accessToken:n,disabled:!u})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Disable Global Guardrails"," ",(0,t.jsx)(z.Tooltip,{title:"When enabled, this key will bypass any guardrails configured to run on every request (global guardrails)",children:(0,t.jsx)(O.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"disable_global_guardrails",valuePropName:"checked",children:(0,t.jsx)($.Switch,{disabled:!u,checkedChildren:"Yes",unCheckedChildren:"No"})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Policies"," ",(0,t.jsx)(z.Tooltip,{title:"Apply policies to this key to control guardrails and other settings",children:(0,t.jsx)(O.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"policies",children:n&&(0,t.jsx)(P.default,{onChange:e=>{x.setFieldValue("policies",e)},accessToken:n,disabled:!m})}),(0,t.jsx)(b.Form.Item,{label:"Tags",name:"tags",children:(0,t.jsx)(V.Select,{mode:"tags",style:{width:"100%"},placeholder:"Select or enter tags",options:Object.values(h).map(e=>({value:e.name,label:e.name,title:e.description||e.name}))})}),(0,t.jsx)(b.Form.Item,{label:"Prompts",name:"prompts",children:(0,t.jsx)(z.Tooltip,{title:m?"":"Setting prompts by key is a premium feature",placement:"top",children:(0,t.jsx)(V.Select,{mode:"tags",style:{width:"100%"},disabled:!m,placeholder:m?Array.isArray(e.metadata?.prompts)&&e.metadata.prompts.length>0?`Current: ${e.metadata.prompts.join(", ")}`:"Select or enter prompts":"Premium feature - Upgrade to set prompts by key",options:p.map(e=>({value:e,label:e}))})})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Access Groups"," ",(0,t.jsx)(z.Tooltip,{title:"Assign access groups to this key. Access groups control which models, MCP servers, and agents this key can use",children:(0,t.jsx)(O.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"access_group_ids",children:(0,t.jsx)(W.default,{placeholder:"Select access groups (optional)"})}),(0,t.jsx)(b.Form.Item,{label:"Allowed Pass Through Routes",name:"allowed_passthrough_routes",children:(0,t.jsx)(z.Tooltip,{title:m?"":"Setting allowed pass through routes by key is a premium feature",placement:"top",children:(0,t.jsx)(q.default,{onChange:e=>x.setFieldValue("allowed_passthrough_routes",e),value:x.getFieldValue("allowed_passthrough_routes"),accessToken:n||"",placeholder:m?Array.isArray(e.metadata?.allowed_passthrough_routes)&&e.metadata.allowed_passthrough_routes.length>0?`Current: ${e.metadata.allowed_passthrough_routes.join(", ")}`:"Select or enter allowed pass through routes":"Premium feature - Upgrade to set allowed pass through routes by key",disabled:!m})})}),(0,t.jsx)(b.Form.Item,{label:"Vector Stores",name:"vector_stores",children:(0,t.jsx)(et.default,{onChange:e=>x.setFieldValue("vector_stores",e),value:x.getFieldValue("vector_stores"),accessToken:n||"",placeholder:"Select vector stores"})}),(0,t.jsx)(b.Form.Item,{label:"MCP Servers / Access Groups",name:"mcp_servers_and_groups",children:(0,t.jsx)(Q.default,{onChange:e=>x.setFieldValue("mcp_servers_and_groups",e),value:x.getFieldValue("mcp_servers_and_groups"),accessToken:n||"",placeholder:"Select MCP servers or access groups (optional)"})}),(0,t.jsx)(b.Form.Item,{name:"mcp_tool_permissions",initialValue:{},hidden:!0,children:(0,t.jsx)(U.Input,{type:"hidden"})}),(0,t.jsx)(b.Form.Item,{noStyle:!0,shouldUpdate:(e,t)=>e.mcp_servers_and_groups!==t.mcp_servers_and_groups||e.mcp_tool_permissions!==t.mcp_tool_permissions,children:()=>(0,t.jsx)("div",{className:"mb-6",children:(0,t.jsx)(Y.default,{accessToken:n||"",selectedServers:x.getFieldValue("mcp_servers_and_groups")?.servers||[],toolPermissions:x.getFieldValue("mcp_tool_permissions")||{},onChange:e=>x.setFieldsValue({mcp_tool_permissions:e})})})}),(0,t.jsx)(b.Form.Item,{label:"Agents / Access Groups",name:"agents_and_groups",children:(0,t.jsx)(G.default,{onChange:e=>x.setFieldValue("agents_and_groups",e),value:x.getFieldValue("agents_and_groups"),accessToken:n||"",placeholder:"Select agents or access groups (optional)"})}),(0,t.jsx)(b.Form.Item,{label:"Team ID",name:"team_id",help:er&&ei?"Team is locked because this key belongs to a project":void 0,children:(0,t.jsx)(V.Select,{placeholder:"Select team",showSearch:!0,disabled:er&&ei,style:{width:"100%"},filterOption:(e,t)=>{let a=i?.find(e=>e.team_id===t?.value);return!!a&&(a.team_alias?.toLowerCase().includes(e.toLowerCase())??!1)},children:i?.map(e=>(0,t.jsx)(V.Select.Option,{value:e.team_id,children:`${e.team_alias} (${e.team_id})`},e.team_id))})}),er&&ei&&(0,t.jsx)(b.Form.Item,{label:"Project",children:(0,t.jsx)(U.Input,{value:en??"",disabled:!0})}),(0,t.jsx)(b.Form.Item,{label:"Logging Settings",name:"logging_settings",children:(0,t.jsx)(ee.default,{value:x.getFieldValue("logging_settings"),onChange:e=>x.setFieldValue("logging_settings",e),disabledCallbacks:v,onDisabledCallbacksChange:e=>{N((0,w.mapInternalToDisplayNames)(e)),x.setFieldValue("disabled_callbacks",e)}})}),(0,t.jsx)(b.Form.Item,{label:"Metadata",name:"metadata",children:(0,t.jsx)(U.Input.TextArea,{rows:10})}),(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(H.default,{form:x,autoRotationEnabled:S,onAutoRotationChange:I,rotationInterval:A,onRotationIntervalChange:M,neverExpire:R,onNeverExpireChange:D}),(0,t.jsx)(b.Form.Item,{name:"duration",hidden:!0,initialValue:"",children:(0,t.jsx)(U.Input,{})})]}),(0,t.jsx)(b.Form.Item,{name:"token",hidden:!0,children:(0,t.jsx)(U.Input,{})}),(0,t.jsx)(b.Form.Item,{name:"disabled_callbacks",hidden:!0,children:(0,t.jsx)(U.Input,{})}),(0,t.jsx)(b.Form.Item,{name:"auto_rotate",hidden:!0,children:(0,t.jsx)(U.Input,{})}),(0,t.jsx)(b.Form.Item,{name:"rotation_interval",hidden:!0,children:(0,t.jsx)(U.Input,{})}),(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)(c.Button,{variant:"secondary",onClick:a,disabled:B,children:"Cancel"}),(0,t.jsx)(c.Button,{type:"submit",loading:B,children:"Save Changes"})]})})]})}function es({onClose:e,keyData:E,teams:P,onKeyDataUpdate:O,onDelete:K,backButtonText:U="Back to Keys"}){let V,{accessToken:$,userId:z,userRole:G,premiumUser:W}=(0,a.default)(),H=W||null!=G&&T.rolesWithWriteAccess.includes(G),{teams:q}=(0,r.default)(),{data:J}=(0,s.useProjects)(),{data:Q}=(0,l.useUISettings)(),Y=!!Q?.values?.enable_projects_ui,[X,Z]=(0,k.useState)(!1),[ee]=b.Form.useForm(),[et,es]=(0,k.useState)(!1),[el,er]=(0,k.useState)(!1),[ei,en]=(0,k.useState)(""),[eo,ed]=(0,k.useState)(!1),[ec,em]=(0,k.useState)(!1),{mutate:eu,isPending:ex}=(0,M.useResetKeySpend)(),[ep,eg]=(0,k.useState)(E),[eh,ej]=(0,k.useState)(null),[e_,ey]=(0,k.useState)(!1),[eb,ef]=(0,k.useState)({}),[ev,eN]=(0,k.useState)(!1);if((0,k.useEffect)(()=>{E&&eg(E)},[E]),(0,k.useEffect)(()=>{(async()=>{let e=ep?.metadata?.policies;if(!$||!e||!Array.isArray(e)||0===e.length)return;eN(!0);let t={};try{await Promise.all(e.map(async e=>{try{let a=await (0,L.getPolicyInfoWithGuardrails)($,e);t[e]=a.resolved_guardrails||[]}catch(a){console.error(`Failed to fetch guardrails for policy ${e}:`,a),t[e]=[]}})),ef(t)}catch(e){console.error("Failed to fetch policy guardrails:",e)}finally{eN(!1)}})()},[$,ep?.metadata?.policies]),(0,k.useEffect)(()=>{if(e_){let e=setTimeout(()=>{ey(!1)},5e3);return()=>clearTimeout(e)}},[e_]),!ep)return(0,t.jsxs)("div",{className:"p-4",children:[(0,t.jsx)(c.Button,{icon:o.ArrowLeftIcon,variant:"light",onClick:e,className:"mb-4",children:U}),(0,t.jsx)(_.Text,{children:"Key not found"})]});let ek=async e=>{try{if(!$)return;let t=e.token;if(e.key=t,H||(delete e.guardrails,delete e.prompts),e.max_budget=(0,n.mapEmptyStringToNull)(e.max_budget),void 0!==e.vector_stores&&(e.object_permission={...ep.object_permission,vector_stores:e.vector_stores||[]},delete e.vector_stores),void 0!==e.mcp_servers_and_groups){let{servers:t,accessGroups:a}=e.mcp_servers_and_groups||{servers:[],accessGroups:[]};e.object_permission={...ep.object_permission,mcp_servers:t||[],mcp_access_groups:a||[]},delete e.mcp_servers_and_groups}if(void 0!==e.mcp_tool_permissions){let t=e.mcp_tool_permissions||{};Object.keys(t).length>0&&(e.object_permission={...e.object_permission,mcp_tool_permissions:t}),delete e.mcp_tool_permissions}if(void 0!==e.agents_and_groups){let{agents:t,accessGroups:a}=e.agents_and_groups||{agents:[],accessGroups:[]};e.object_permission={...e.object_permission,agents:t||[],agent_access_groups:a||[]},delete e.agents_and_groups}if(e.max_budget=(0,n.mapEmptyStringToNull)(e.max_budget),e.tpm_limit=(0,n.mapEmptyStringToNull)(e.tpm_limit),e.rpm_limit=(0,n.mapEmptyStringToNull)(e.rpm_limit),e.max_parallel_requests=(0,n.mapEmptyStringToNull)(e.max_parallel_requests),e.metadata&&"string"==typeof e.metadata)try{let t=JSON.parse(e.metadata);"tags"in t&&delete t.tags,e.metadata={...t,...Array.isArray(e.tags)&&e.tags.length>0?{tags:e.tags}:{},...e.guardrails?.length>0?{guardrails:e.guardrails}:{},...Array.isArray(e.logging_settings)&&e.logging_settings.length>0?{logging:e.logging_settings}:{},...e.disabled_callbacks?.length>0?{litellm_disabled_callbacks:(0,w.mapDisplayToInternalNames)(e.disabled_callbacks)}:{}}}catch(e){console.error("Error parsing metadata JSON:",e),F.default.error("Invalid metadata JSON");return}else{let{tags:t,...a}=e.metadata||{};e.metadata={...a,...Array.isArray(e.tags)&&e.tags.length>0?{tags:e.tags}:{},...e.guardrails?.length>0?{guardrails:e.guardrails}:{},...Array.isArray(e.logging_settings)&&e.logging_settings.length>0?{logging:e.logging_settings}:{},...e.disabled_callbacks?.length>0?{litellm_disabled_callbacks:(0,w.mapDisplayToInternalNames)(e.disabled_callbacks)}:{}}}"tags"in e&&delete e.tags,delete e.logging_settings,e.budget_duration&&(e.budget_duration=({daily:"24h",weekly:"7d",monthly:"30d"})[e.budget_duration]);let a=await (0,L.keyUpdateCall)($,e);eg(e=>e?{...e,...a}:void 0),O&&O(a),F.default.success("Key updated successfully"),Z(!1)}catch(e){F.default.fromBackend((0,B.parseErrorMessage)(e)),console.error("Error updating key:",e)}},eT=async()=>{try{if(er(!0),!$)return;await (0,L.keyDeleteCall)($,ep.token||ep.token_id),F.default.success("Key deleted successfully"),K&&K(),e()}catch(e){console.error("Error deleting the key:",e),F.default.fromBackend(e)}finally{er(!1),es(!1),en("")}},ew=e=>{let t=new Date(e),a=t.toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"}),s=t.toLocaleTimeString("en-US",{hour:"numeric",minute:"2-digit",hour12:!0});return`${a} at ${s}`},eS=(0,T.isProxyAdminRole)(G||"")||q&&(0,T.isUserTeamAdminForSingleTeam)(q?.filter(e=>e.team_id===ep.team_id)[0]?.members_with_roles,z||"")||z===ep.user_id&&"Internal Viewer"!==G,eI=(0,T.isProxyAdminRole)(G||"")||q&&(0,T.isUserTeamAdminForSingleTeam)(q?.filter(e=>e.team_id===ep.team_id)[0]?.members_with_roles,z||"");return(0,t.jsxs)("div",{className:"w-full h-screen p-4",children:[(0,t.jsx)(N.KeyInfoHeader,{data:{keyName:ep.key_alias||"Virtual Key",keyId:ep.token_id||ep.token,userId:ep.user_id||"",userEmail:ep.user_email||"",createdBy:ep.user_email||ep.user_id||"",createdAt:ep.created_at?ew(ep.created_at):"",lastUpdated:ep.updated_at?ew(ep.updated_at):"",lastActive:ep.last_active?ew(ep.last_active):"Never"},onBack:e,onRegenerate:()=>ed(!0),onDelete:()=>es(!0),onResetSpend:eI?()=>em(!0):void 0,canModifyKey:eS,backButtonText:U,regenerateDisabled:!W,regenerateTooltip:W?void 0:"This is a LiteLLM Enterprise feature, and requires a valid key to use."}),(0,t.jsx)(D.RegenerateKeyModal,{selectedToken:ep,visible:eo,onClose:()=>ed(!1),onKeyUpdate:e=>{eg(t=>{if(t)return{...t,...e,created_at:new Date().toLocaleString()}}),ej(new Date),ey(!0),O&&O({...e,created_at:new Date().toLocaleString()})}}),(0,t.jsx)(I.default,{isOpen:et,title:"Delete Key",alertMessage:"This action is irreversible and will immediately revoke access for any applications using this key.",message:"Are you sure you want to delete this Virtual Key?",resourceInformationTitle:"Key Information",resourceInformation:[{label:"Key Alias",value:ep?.key_alias||"-"},{label:"Key ID",value:ep?.token_id||ep?.token||"-",code:!0},{label:"Team ID",value:ep?.team_id||"-",code:!0},{label:"Spend",value:ep?.spend?`$${(0,i.formatNumberWithCommas)(ep.spend,4)}`:"$0.0000"}],onCancel:()=>{es(!1),en("")},onOk:eT,confirmLoading:el,requiredConfirmation:ep?.key_alias}),(0,t.jsxs)(f.Modal,{title:"Reset Key Spend",open:ec,onOk:()=>{eu(ep.token||ep.token_id,{onSuccess:()=>{eg(e=>e?{...e,spend:0}:void 0),O&&O({spend:0}),F.default.success("Key spend reset to $0"),em(!1)},onError:e=>{F.default.fromBackend((0,B.parseErrorMessage)(e)),console.error("Error resetting key spend:",e)}})},onCancel:()=>em(!1),okText:"Reset",okButtonProps:{danger:!0},confirmLoading:ex,children:[(0,t.jsxs)("p",{children:["Reset spend for ",(0,t.jsx)("strong",{children:ep?.key_alias||ep?.token_id||"this key"})," to"," ",(0,t.jsx)("strong",{children:"$0"}),"?"]}),(0,t.jsxs)("p",{style:{color:"#666",fontSize:"0.875rem",marginTop:8},children:["Current spend: ",(0,t.jsxs)("strong",{children:["$",(0,i.formatNumberWithCommas)(ep.spend,4)]}),". Spend history is preserved in logs. This resets the current period spend counter, the same as an automatic budget reset."]})]}),(0,t.jsxs)(p.TabGroup,{children:[(0,t.jsxs)(g.TabList,{className:"mb-4",children:[(0,t.jsx)(x.Tab,{children:"Overview"}),(0,t.jsx)(x.Tab,{children:"Settings"})]}),(0,t.jsxs)(j.TabPanels,{children:[(0,t.jsx)(h.TabPanel,{children:(0,t.jsxs)(u.Grid,{numItems:1,numItemsSm:2,numItemsLg:3,className:"gap-6",children:[(0,t.jsxs)(m.Card,{children:[(0,t.jsx)(_.Text,{children:"Spend"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(y.Title,{children:["$",(0,i.formatNumberWithCommas)(ep.spend,4)]}),(0,t.jsxs)(_.Text,{children:["of"," ",null!==ep.max_budget?`$${(0,i.formatNumberWithCommas)(ep.max_budget)}`:"Unlimited"]})]})]}),(0,t.jsxs)(m.Card,{children:[(0,t.jsx)(_.Text,{children:"Rate Limits"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(_.Text,{children:["TPM: ",null!==ep.tpm_limit?ep.tpm_limit:"Unlimited"]}),(0,t.jsxs)(_.Text,{children:["RPM: ",null!==ep.rpm_limit?ep.rpm_limit:"Unlimited"]})]})]}),(0,t.jsxs)(m.Card,{children:[(0,t.jsx)(_.Text,{children:"Models"}),(0,t.jsx)("div",{className:"mt-2 flex flex-wrap gap-2",children:ep.models&&ep.models.length>0?ep.models.map((e,a)=>(0,t.jsx)(d.Badge,{color:"red",children:e},a)):(0,t.jsx)(_.Text,{children:"No models specified"})})]}),(0,t.jsx)(m.Card,{children:(0,t.jsx)(R.default,{objectPermission:ep.object_permission,variant:"inline",accessToken:$})}),(0,t.jsxs)(m.Card,{children:[(0,t.jsx)(_.Text,{className:"font-medium mb-3",children:"Guardrails"}),Array.isArray(ep.metadata?.guardrails)&&ep.metadata.guardrails.length>0?(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:ep.metadata.guardrails.map((e,a)=>(0,t.jsx)(d.Badge,{color:"blue",children:e},a))}):(0,t.jsx)(_.Text,{className:"text-gray-500",children:"No guardrails configured"}),"boolean"==typeof ep.metadata?.disable_global_guardrails&&!0===ep.metadata.disable_global_guardrails&&(0,t.jsx)("div",{className:"mt-3 pt-3 border-t border-gray-200",children:(0,t.jsx)(d.Badge,{color:"yellow",children:"Global Guardrails Disabled"})})]}),(0,t.jsxs)(m.Card,{children:[(0,t.jsx)(_.Text,{className:"font-medium mb-3",children:"Policies"}),Array.isArray(ep.metadata?.policies)&&ep.metadata.policies.length>0?(0,t.jsx)("div",{className:"space-y-4",children:ep.metadata.policies.map((e,a)=>(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(d.Badge,{color:"purple",children:e}),ev&&(0,t.jsx)(_.Text,{className:"text-xs text-gray-400",children:"Loading guardrails..."})]}),!ev&&eb[e]&&eb[e].length>0&&(0,t.jsxs)("div",{className:"ml-4 pl-3 border-l-2 border-gray-200",children:[(0,t.jsx)(_.Text,{className:"text-xs text-gray-500 mb-1",children:"Resolved Guardrails:"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-1",children:eb[e].map((e,a)=>(0,t.jsx)(d.Badge,{color:"blue",size:"xs",children:e},a))})]})]},a))}):(0,t.jsx)(_.Text,{className:"text-gray-500",children:"No policies configured"})]}),(0,t.jsx)(A.default,{loggingConfigs:(0,C.extractLoggingSettings)(ep.metadata),disabledCallbacks:Array.isArray(ep.metadata?.litellm_disabled_callbacks)?(0,w.mapInternalToDisplayNames)(ep.metadata.litellm_disabled_callbacks):[],variant:"card"}),(0,t.jsx)(S.default,{autoRotate:ep.auto_rotate,rotationInterval:ep.rotation_interval,lastRotationAt:ep.last_rotation_at,keyRotationAt:ep.key_rotation_at,nextRotationAt:ep.next_rotation_at,variant:"card"})]})}),(0,t.jsx)(h.TabPanel,{children:(0,t.jsxs)(m.Card,{className:"overflow-y-auto max-h-[65vh]",children:[(0,t.jsxs)("div",{className:"flex justify-between items-center mb-4",children:[(0,t.jsx)(y.Title,{children:"Key Settings"}),!X&&eS&&(0,t.jsx)(c.Button,{onClick:()=>Z(!0),children:"Edit Settings"})]}),X?(0,t.jsx)(ea,{keyData:ep,onCancel:()=>Z(!1),onSubmit:ek,teams:P,accessToken:$,userID:z,userRole:G,premiumUser:W}):(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Key ID"}),(0,t.jsx)(_.Text,{className:"font-mono",children:ep.token_id||ep.token})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Key Alias"}),(0,t.jsx)(_.Text,{children:ep.key_alias||"Not Set"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Secret Key"}),(0,t.jsx)(_.Text,{className:"font-mono",children:ep.key_name})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Team ID"}),(0,t.jsx)(_.Text,{children:ep.team_id||"Not Set"})]}),Y&&(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Project"}),(0,t.jsx)(_.Text,{children:ep.project_id?(V=J?.find(e=>e.project_id===ep.project_id),V?.project_alias?`${V.project_alias} (${ep.project_id})`:ep.project_id):"Not Set"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Organization"}),(0,t.jsx)(_.Text,{children:(ep.organization_id??ep.org_id)||"Not Set"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Created"}),(0,t.jsx)(_.Text,{children:ew(ep.created_at)})]}),eh&&(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Last Regenerated"}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(_.Text,{children:ew(eh)}),(0,t.jsx)(d.Badge,{color:"green",size:"xs",children:"Recent"})]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Expires"}),(0,t.jsx)(_.Text,{children:ep.expires?ew(ep.expires):"Never"})]}),(0,t.jsx)(S.default,{autoRotate:ep.auto_rotate,rotationInterval:ep.rotation_interval,lastRotationAt:ep.last_rotation_at,keyRotationAt:ep.key_rotation_at,nextRotationAt:ep.next_rotation_at,variant:"inline",className:"pt-4 border-t border-gray-200"}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Spend"}),(0,t.jsxs)(_.Text,{children:["$",(0,i.formatNumberWithCommas)(ep.spend,4)," USD"]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Budget"}),(0,t.jsx)(_.Text,{children:null!==ep.max_budget?`$${(0,i.formatNumberWithCommas)(ep.max_budget,2)}`:"Unlimited"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Tags"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:Array.isArray(ep.metadata?.tags)&&ep.metadata.tags.length>0?ep.metadata.tags.map((e,a)=>(0,t.jsx)("span",{className:"px-2 mr-2 py-1 bg-blue-100 rounded text-xs",children:e},a)):"No tags specified"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Prompts"}),(0,t.jsx)(_.Text,{children:Array.isArray(ep.metadata?.prompts)&&ep.metadata.prompts.length>0?ep.metadata.prompts.map((e,a)=>(0,t.jsx)("span",{className:"px-2 mr-2 py-1 bg-blue-100 rounded text-xs",children:e},a)):"No prompts specified"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Allowed Routes"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:Array.isArray(ep.allowed_routes)&&ep.allowed_routes.length>0?ep.allowed_routes.map((e,a)=>(0,t.jsx)("span",{className:"px-2 py-1 bg-blue-100 rounded text-xs",children:e},a)):(0,t.jsx)(v.Tag,{color:"green",children:"All routes allowed"})})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Allowed Pass Through Routes"}),(0,t.jsx)(_.Text,{children:Array.isArray(ep.metadata?.allowed_passthrough_routes)&&ep.metadata.allowed_passthrough_routes.length>0?ep.metadata.allowed_passthrough_routes.map((e,a)=>(0,t.jsx)("span",{className:"px-2 mr-2 py-1 bg-blue-100 rounded text-xs",children:e},a)):"No pass through routes specified"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Disable Global Guardrails"}),(0,t.jsx)(_.Text,{children:ep.metadata?.disable_global_guardrails===!0?(0,t.jsx)(d.Badge,{color:"yellow",children:"Enabled - Global guardrails bypassed"}):(0,t.jsx)(d.Badge,{color:"green",children:"Disabled - Global guardrails active"})})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Models"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:ep.models&&ep.models.length>0?ep.models.map((e,a)=>(0,t.jsx)("span",{className:"px-2 py-1 bg-blue-100 rounded text-xs",children:e},a)):(0,t.jsx)(_.Text,{children:"No models specified"})})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Rate Limits"}),(0,t.jsxs)(_.Text,{children:["TPM: ",null!==ep.tpm_limit?ep.tpm_limit:"Unlimited"]}),(0,t.jsxs)(_.Text,{children:["RPM: ",null!==ep.rpm_limit?ep.rpm_limit:"Unlimited"]}),(0,t.jsxs)(_.Text,{children:["Max Parallel Requests:"," ",null!==ep.max_parallel_requests?ep.max_parallel_requests:"Unlimited"]}),(0,t.jsxs)(_.Text,{children:["Model TPM Limits:"," ",ep.metadata?.model_tpm_limit?JSON.stringify(ep.metadata.model_tpm_limit):"Unlimited"]}),(0,t.jsxs)(_.Text,{children:["Model RPM Limits:"," ",ep.metadata?.model_rpm_limit?JSON.stringify(ep.metadata.model_rpm_limit):"Unlimited"]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Metadata"}),(0,t.jsx)("pre",{className:"bg-gray-100 p-2 rounded text-xs overflow-auto mt-1",children:(0,C.formatMetadataForDisplay)((0,C.stripTagsFromMetadata)(ep.metadata))})]}),(0,t.jsx)(R.default,{objectPermission:ep.object_permission,variant:"inline",className:"pt-4 border-t border-gray-200",accessToken:$}),(0,t.jsx)(A.default,{loggingConfigs:(0,C.extractLoggingSettings)(ep.metadata),disabledCallbacks:Array.isArray(ep.metadata?.litellm_disabled_callbacks)?(0,w.mapInternalToDisplayNames)(ep.metadata.litellm_disabled_callbacks):[],variant:"inline",className:"pt-4 border-t border-gray-200"})]})]})})]})]})]})}e.s(["default",()=>es],20147)}]); \ No newline at end of file +(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,772345,e=>{"use strict";e.i(247167);var t=e.i(931067),a=e.i(271645);let s={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M168 504.2c1-43.7 10-86.1 26.9-126 17.3-41 42.1-77.7 73.7-109.4S337 212.3 378 195c42.4-17.9 87.4-27 133.9-27s91.5 9.1 133.8 27A341.5 341.5 0 01755 268.8c9.9 9.9 19.2 20.4 27.8 31.4l-60.2 47a8 8 0 003 14.1l175.7 43c5 1.2 9.9-2.6 9.9-7.7l.8-180.9c0-6.7-7.7-10.5-12.9-6.3l-56.4 44.1C765.8 155.1 646.2 92 511.8 92 282.7 92 96.3 275.6 92 503.8a8 8 0 008 8.2h60c4.4 0 7.9-3.5 8-7.8zm756 7.8h-60c-4.4 0-7.9 3.5-8 7.8-1 43.7-10 86.1-26.9 126-17.3 41-42.1 77.8-73.7 109.4A342.45 342.45 0 01512.1 856a342.24 342.24 0 01-243.2-100.8c-9.9-9.9-19.2-20.4-27.8-31.4l60.2-47a8 8 0 00-3-14.1l-175.7-43c-5-1.2-9.9 2.6-9.9 7.7l-.7 181c0 6.7 7.7 10.5 12.9 6.3l56.4-44.1C258.2 868.9 377.8 932 512.2 932c229.2 0 415.5-183.7 419.8-411.8a8 8 0 00-8-8.2z"}}]},name:"sync",theme:"outlined"};var l=e.i(9583),r=a.forwardRef(function(e,r){return a.createElement(l.default,(0,t.default)({},e,{ref:r,icon:s}))});e.s(["SyncOutlined",0,r],772345)},304911,e=>{"use strict";var t=e.i(843476),a=e.i(262218);let{Text:s}=e.i(898586).Typography;function l({userId:e}){return"default_user_id"===e?(0,t.jsx)(a.Tag,{color:"blue",children:"Default Proxy Admin"}):(0,t.jsx)(s,{children:e})}e.s(["default",()=>l])},11751,e=>{"use strict";function t(e){return""===e?null:e}e.s(["mapEmptyStringToNull",()=>t])},72713,e=>{"use strict";e.i(247167);var t=e.i(931067),a=e.i(271645);let s={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"};var l=e.i(9583),r=a.forwardRef(function(e,r){return a.createElement(l.default,(0,t.default)({},e,{ref:r,icon:s}))});e.s(["CalendarOutlined",0,r],72713)},962944,e=>{"use strict";e.i(247167);var t=e.i(931067),a=e.i(271645);let s={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M848 359.3H627.7L825.8 109c4.1-5.3.4-13-6.3-13H436c-2.8 0-5.5 1.5-6.9 4L170 547.5c-3.1 5.3.7 12 6.9 12h174.4l-89.4 357.6c-1.9 7.8 7.5 13.3 13.3 7.7L853.5 373c5.2-4.9 1.7-13.7-5.5-13.7zM378.2 732.5l60.3-241H281.1l189.6-327.4h224.6L487 427.4h211L378.2 732.5z"}}]},name:"thunderbolt",theme:"outlined"};var l=e.i(9583),r=a.forwardRef(function(e,r){return a.createElement(l.default,(0,t.default)({},e,{ref:r,icon:s}))});e.s(["ThunderboltOutlined",0,r],962944)},534172,3750,e=>{"use strict";e.i(247167);var t=e.i(931067),a=e.i(271645);let s={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M866.9 169.9L527.1 54.1C523 52.7 517.5 52 512 52s-11 .7-15.1 2.1L157.1 169.9c-8.3 2.8-15.1 12.4-15.1 21.2v482.4c0 8.8 5.7 20.4 12.6 25.9L499.3 968c3.5 2.7 8 4.1 12.6 4.1s9.2-1.4 12.6-4.1l344.7-268.6c6.9-5.4 12.6-17 12.6-25.9V191.1c.2-8.8-6.6-18.3-14.9-21.2zM810 654.3L512 886.5 214 654.3V226.7l298-101.6 298 101.6v427.6zm-405.8-201c-3-4.1-7.8-6.6-13-6.6H336c-6.5 0-10.3 7.4-6.5 12.7l126.4 174a16.1 16.1 0 0026 0l212.6-292.7c3.8-5.3 0-12.7-6.5-12.7h-55.2c-5.1 0-10 2.5-13 6.6L468.9 542.4l-64.7-89.1z"}}]},name:"safety-certificate",theme:"outlined"};var l=e.i(9583),r=a.forwardRef(function(e,r){return a.createElement(l.default,(0,t.default)({},e,{ref:r,icon:s}))});e.s(["SafetyCertificateOutlined",0,r],534172);let i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M668.6 320c0-4.4-3.6-8-8-8h-54.5c-3 0-5.8 1.7-7.1 4.4l-84.7 168.8H511l-84.7-168.8a8 8 0 00-7.1-4.4h-55.7c-1.3 0-2.6.3-3.8 1-3.9 2.1-5.3 7-3.2 10.8l103.9 191.6h-57c-4.4 0-8 3.6-8 8v27.1c0 4.4 3.6 8 8 8h76v39h-76c-4.4 0-8 3.6-8 8v27.1c0 4.4 3.6 8 8 8h76V704c0 4.4 3.6 8 8 8h49.9c4.4 0 8-3.6 8-8v-63.5h76.3c4.4 0 8-3.6 8-8v-27.1c0-4.4-3.6-8-8-8h-76.3v-39h76.3c4.4 0 8-3.6 8-8v-27.1c0-4.4-3.6-8-8-8H564l103.7-191.6c.5-1.1.9-2.4.9-3.7zM157.9 504.2a352.7 352.7 0 01103.5-242.4c32.5-32.5 70.3-58.1 112.4-75.9 43.6-18.4 89.9-27.8 137.6-27.8 47.8 0 94.1 9.3 137.6 27.8 42.1 17.8 79.9 43.4 112.4 75.9 10 10 19.3 20.5 27.9 31.4l-50 39.1a8 8 0 003 14.1l156.8 38.3c5 1.2 9.9-2.6 9.9-7.7l.8-161.5c0-6.7-7.7-10.5-12.9-6.3l-47.8 37.4C770.7 146.3 648.6 82 511.5 82 277 82 86.3 270.1 82 503.8a8 8 0 008 8.2h60c4.3 0 7.8-3.5 7.9-7.8zM934 512h-60c-4.3 0-7.9 3.5-8 7.8a352.7 352.7 0 01-103.5 242.4 352.57 352.57 0 01-112.4 75.9c-43.6 18.4-89.9 27.8-137.6 27.8s-94.1-9.3-137.6-27.8a352.57 352.57 0 01-112.4-75.9c-10-10-19.3-20.5-27.9-31.4l49.9-39.1a8 8 0 00-3-14.1l-156.8-38.3c-5-1.2-9.9 2.6-9.9 7.7l-.8 161.7c0 6.7 7.7 10.5 12.9 6.3l47.8-37.4C253.3 877.7 375.4 942 512.5 942 747 942 937.7 753.9 942 520.2a8 8 0 00-8-8.2z"}}]},name:"transaction",theme:"outlined"};var n=a.forwardRef(function(e,s){return a.createElement(l.default,(0,t.default)({},e,{ref:s,icon:i}))});e.s(["TransactionOutlined",0,n],3750)},784647,505022,721929,e=>{"use strict";var t=e.i(843476),a=e.i(464571),s=e.i(898586),l=e.i(592968),r=e.i(770914),i=e.i(312361),n=e.i(525720),o=e.i(447566),d=e.i(772345),c=e.i(955135),m=e.i(646563),u=e.i(771674),x=e.i(948401),p=e.i(72713),g=e.i(637235),h=e.i(962944),j=e.i(534172),_=e.i(3750),y=e.i(304911);let{Text:b}=s.Typography;function f({label:e,value:a,icon:s,truncate:l=!1,copyable:i=!1,defaultUserIdCheck:n=!1}){let o=!a,d=n&&"default_user_id"===a,c=d?(0,t.jsx)(y.default,{userId:a}):(0,t.jsx)(b,{strong:!0,copyable:!!(i&&!o&&!d)&&{tooltips:[`Copy ${e}`,"Copied!"]},ellipsis:l,style:l?{maxWidth:160,display:"block"}:void 0,children:o?"-":a});return(0,t.jsxs)("div",{children:[(0,t.jsxs)(r.Space,{size:4,children:[(0,t.jsx)(b,{type:"secondary",children:s}),(0,t.jsx)(b,{type:"secondary",style:{fontSize:12,textTransform:"uppercase",letterSpacing:"0.05em"},children:e})]}),(0,t.jsx)("div",{children:c})]})}let{Title:v,Text:N}=s.Typography;function k({data:e,onBack:s,onCreateNew:y,onRegenerate:b,onDelete:k,onResetSpend:T,canModifyKey:w=!0,backButtonText:S="Back to Keys",regenerateDisabled:I=!1,regenerateTooltip:C}){return(0,t.jsxs)("div",{children:[y&&(0,t.jsx)("div",{style:{marginBottom:16},children:(0,t.jsx)(a.Button,{type:"primary",icon:(0,t.jsx)(m.PlusOutlined,{}),onClick:y,children:"Create New Key"})}),(0,t.jsx)("div",{style:{marginBottom:16},children:(0,t.jsx)(a.Button,{type:"text",icon:(0,t.jsx)(o.ArrowLeftOutlined,{}),onClick:s,children:S})}),(0,t.jsxs)(n.Flex,{justify:"space-between",align:"start",style:{marginBottom:20},children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(v,{level:3,copyable:{tooltips:["Copy Key Alias","Copied!"]},style:{margin:0},children:e.keyName}),(0,t.jsxs)(N,{type:"secondary",copyable:{text:e.keyId,tooltips:["Copy Key ID","Copied!"]},children:["Key ID: ",e.keyId]})]}),w&&(0,t.jsxs)(r.Space,{children:[(0,t.jsx)(l.Tooltip,{title:C||"",children:(0,t.jsx)("span",{children:(0,t.jsx)(a.Button,{icon:(0,t.jsx)(d.SyncOutlined,{}),onClick:b,disabled:I,children:"Regenerate Key"})})}),T&&(0,t.jsx)(a.Button,{danger:!0,icon:(0,t.jsx)(_.TransactionOutlined,{}),onClick:T,children:"Reset Spend"}),(0,t.jsx)(a.Button,{danger:!0,icon:(0,t.jsx)(c.DeleteOutlined,{}),onClick:k,children:"Delete Key"})]})]}),(0,t.jsxs)(n.Flex,{align:"stretch",gap:40,style:{marginBottom:40},children:[(0,t.jsxs)(r.Space,{direction:"vertical",size:16,children:[(0,t.jsx)(f,{label:"User Email",value:e.userEmail,icon:(0,t.jsx)(x.MailOutlined,{})}),(0,t.jsx)(f,{label:"User ID",value:e.userId,icon:(0,t.jsx)(u.UserOutlined,{}),truncate:!0,copyable:!0,defaultUserIdCheck:!0})]}),(0,t.jsx)(i.Divider,{type:"vertical",style:{height:"auto"}}),(0,t.jsxs)(r.Space,{direction:"vertical",size:16,children:[(0,t.jsx)(f,{label:"Created At",value:e.createdAt,icon:(0,t.jsx)(p.CalendarOutlined,{})}),(0,t.jsx)(f,{label:"Created By",value:e.createdBy,icon:(0,t.jsx)(j.SafetyCertificateOutlined,{}),truncate:!0,copyable:!0,defaultUserIdCheck:!0})]}),(0,t.jsx)(i.Divider,{type:"vertical",style:{height:"auto"}}),(0,t.jsxs)(r.Space,{direction:"vertical",size:16,children:[(0,t.jsx)(f,{label:"Last Updated",value:e.lastUpdated,icon:(0,t.jsx)(g.ClockCircleOutlined,{})}),(0,t.jsx)(f,{label:"Last Active",value:e.lastActive,icon:(0,t.jsx)(h.ThunderboltOutlined,{})})]})]})]})}e.s(["KeyInfoHeader",()=>k],784647);var T=e.i(599724),w=e.i(389083),S=e.i(278587),I=e.i(271645);let C=I.forwardRef(function(e,t){return I.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),I.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["default",0,({autoRotate:e=!1,rotationInterval:a,lastRotationAt:s,keyRotationAt:l,nextRotationAt:r,variant:i="card",className:n=""})=>{let o=e=>{let t=new Date(e),a=t.toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"}),s=t.toLocaleTimeString("en-US",{hour:"numeric",minute:"2-digit",hour12:!0});return`${a} at ${s}`},d=(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsx)("div",{className:"space-y-3",children:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(S.RefreshIcon,{className:"h-4 w-4 text-blue-600"}),(0,t.jsx)(T.Text,{className:"font-semibold text-gray-900",children:"Auto-Rotation"}),(0,t.jsx)(w.Badge,{color:e?"green":"gray",size:"xs",children:e?"Enabled":"Disabled"}),e&&a&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(T.Text,{className:"text-gray-400",children:"•"}),(0,t.jsxs)(T.Text,{className:"text-sm text-gray-600",children:["Every ",a]})]})]})}),(e||s||l||r)&&(0,t.jsxs)("div",{className:"space-y-3",children:[s&&(0,t.jsxs)("div",{className:"flex items-center gap-2 p-3 bg-gray-50 border border-gray-200 rounded-md",children:[(0,t.jsx)(C,{className:"w-4 h-4 text-gray-500"}),(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)(T.Text,{className:"font-medium text-gray-700",children:"Last Rotation"}),(0,t.jsx)(T.Text,{className:"text-sm text-gray-600",children:o(s)})]})]}),(l||r)&&(0,t.jsxs)("div",{className:"flex items-center gap-2 p-3 bg-gray-50 border border-gray-200 rounded-md",children:[(0,t.jsx)(C,{className:"w-4 h-4 text-gray-500"}),(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)(T.Text,{className:"font-medium text-gray-700",children:"Next Scheduled Rotation"}),(0,t.jsx)(T.Text,{className:"text-sm text-gray-600",children:o(r||l||"")})]})]}),e&&!s&&!l&&!r&&(0,t.jsxs)("div",{className:"flex items-center gap-2 p-3 bg-gray-50 border border-gray-100 rounded-md",children:[(0,t.jsx)(C,{className:"w-4 h-4 text-gray-500"}),(0,t.jsx)(T.Text,{className:"text-gray-600",children:"No rotation history available"})]})]}),!e&&!s&&!l&&!r&&(0,t.jsxs)("div",{className:"flex items-center gap-2 p-3 bg-gray-50 border border-gray-100 rounded-md",children:[(0,t.jsx)(S.RefreshIcon,{className:"w-4 h-4 text-gray-400"}),(0,t.jsx)(T.Text,{className:"text-gray-600",children:"Auto-rotation is not enabled for this key"})]})]});return"card"===i?(0,t.jsxs)("div",{className:`bg-white border border-gray-200 rounded-lg p-6 ${n}`,children:[(0,t.jsx)("div",{className:"flex items-center gap-2 mb-6",children:(0,t.jsxs)("div",{children:[(0,t.jsx)(T.Text,{className:"font-semibold text-gray-900",children:"Auto-Rotation"}),(0,t.jsx)(T.Text,{className:"text-xs text-gray-500",children:"Automatic key rotation settings and status for this key"})]})}),d]}):(0,t.jsxs)("div",{className:`${n}`,children:[(0,t.jsx)(T.Text,{className:"font-medium text-gray-900 mb-3",children:"Auto-Rotation"}),d]})}],505022);let A=["logging"];e.s(["extractLoggingSettings",0,e=>e&&"object"==typeof e&&Array.isArray(e.logging)?e.logging:[],"formatMetadataForDisplay",0,(e,t=2)=>JSON.stringify(e&&"object"==typeof e?Object.fromEntries(Object.entries(e).filter(([e])=>!A.includes(e))):{},null,t),"stripTagsFromMetadata",0,e=>{if(!e||"object"!=typeof e)return e;let{tags:t,...a}=e;return a}],721929)},643449,e=>{"use strict";var t=e.i(843476),a=e.i(599724),s=e.i(389083),l=e.i(810757),r=e.i(477386),i=e.i(557662);e.s(["default",0,function({loggingConfigs:e=[],disabledCallbacks:n=[],variant:o="card",className:d=""}){let c=(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(l.CogIcon,{className:"h-4 w-4 text-blue-600"}),(0,t.jsx)(a.Text,{className:"font-semibold text-gray-900",children:"Logging Integrations"}),(0,t.jsx)(s.Badge,{color:"blue",size:"xs",children:e.length})]}),e.length>0?(0,t.jsx)("div",{className:"space-y-3",children:e.map((e,r)=>{var n;let o=(n=e.callback_name,Object.entries(i.callback_map).find(([e,t])=>t===n)?.[0]||n),d=i.callbackInfo[o]?.logo;return(0,t.jsxs)("div",{className:"flex items-center justify-between p-3 rounded-lg bg-blue-50 border border-blue-200",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[d?(0,t.jsx)("img",{src:d,alt:o,className:"w-5 h-5 object-contain"}):(0,t.jsx)(l.CogIcon,{className:"h-5 w-5 text-gray-400"}),(0,t.jsxs)("div",{children:[(0,t.jsx)(a.Text,{className:"font-medium text-blue-800",children:o}),(0,t.jsxs)(a.Text,{className:"text-xs text-blue-600",children:[Object.keys(e.callback_vars).length," parameters configured"]})]})]}),(0,t.jsx)(s.Badge,{color:(e=>{switch(e){case"success":return"green";case"failure":return"red";case"success_and_failure":return"blue";default:return"gray"}})(e.callback_type),size:"sm",children:(e=>{switch(e){case"success":return"Success Only";case"failure":return"Failure Only";case"success_and_failure":return"Success & Failure";default:return e}})(e.callback_type)})]},r)})}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(l.CogIcon,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(a.Text,{className:"text-gray-500 text-sm",children:"No logging integrations configured"})]})]}),(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(r.BanIcon,{className:"h-4 w-4 text-red-600"}),(0,t.jsx)(a.Text,{className:"font-semibold text-gray-900",children:"Disabled Callbacks"}),(0,t.jsx)(s.Badge,{color:"red",size:"xs",children:n.length})]}),n.length>0?(0,t.jsx)("div",{className:"space-y-3",children:n.map((e,l)=>{let n=i.reverse_callback_map[e]||e,o=i.callbackInfo[n]?.logo;return(0,t.jsxs)("div",{className:"flex items-center justify-between p-3 rounded-lg bg-red-50 border border-red-200",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[o?(0,t.jsx)("img",{src:o,alt:n,className:"w-5 h-5 object-contain"}):(0,t.jsx)(r.BanIcon,{className:"h-5 w-5 text-gray-400"}),(0,t.jsxs)("div",{children:[(0,t.jsx)(a.Text,{className:"font-medium text-red-800",children:n}),(0,t.jsx)(a.Text,{className:"text-xs text-red-600",children:"Disabled for this key"})]})]}),(0,t.jsx)(s.Badge,{color:"red",size:"sm",children:"Disabled"})]},l)})}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(r.BanIcon,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(a.Text,{className:"text-gray-500 text-sm",children:"No callbacks disabled"})]})]})]});return"card"===o?(0,t.jsxs)("div",{className:`bg-white border border-gray-200 rounded-lg p-6 ${d}`,children:[(0,t.jsx)("div",{className:"flex items-center gap-2 mb-6",children:(0,t.jsxs)("div",{children:[(0,t.jsx)(a.Text,{className:"font-semibold text-gray-900",children:"Logging Settings"}),(0,t.jsx)(a.Text,{className:"text-xs text-gray-500",children:"Active logging integrations and disabled callbacks for this key"})]})}),c]}):(0,t.jsxs)("div",{className:`${d}`,children:[(0,t.jsx)(a.Text,{className:"font-medium text-gray-900 mb-3",children:"Logging Settings"}),c]})}])},65932,690284,e=>{"use strict";var t=e.i(954616),a=e.i(912598),s=e.i(764205),l=e.i(135214),r=e.i(207082);let i=async(e,t)=>{let a=(0,s.getProxyBaseUrl)(),l=`${a?`${a}/key/${t}/reset_spend`:`/key/${t}/reset_spend`}`,r=await fetch(l,{method:"POST",headers:{[(0,s.getGlobalLitellmHeaderName)()]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({reset_to:0})});if(!r.ok){let e=await r.json(),t=(0,s.deriveErrorMessage)(e);throw(0,s.handleError)(t),Error(t)}return r.json()};e.s(["useResetKeySpend",0,()=>{let{accessToken:e}=(0,l.default)(),s=(0,a.useQueryClient)();return(0,t.useMutation)({mutationFn:async t=>{if(!e)throw Error("Access token is required");return i(e,t)},onSuccess:()=>{s.invalidateQueries({queryKey:r.keyKeys.all})}})}],65932);var n=e.i(843476),o=e.i(994388),d=e.i(309426),c=e.i(350967),m=e.i(599724),u=e.i(779241),x=e.i(629569),p=e.i(808613),g=e.i(28651),h=e.i(212931),j=e.i(439189),_=e.i(497245),y=e.i(96226),b=e.i(435684);function f(e,t){let{years:a=0,months:s=0,weeks:l=0,days:r=0,hours:i=0,minutes:n=0,seconds:o=0}=t,d=(0,b.toDate)(e),c=s||a?(0,_.addMonths)(d,s+12*a):d,m=r||l?(0,j.addDays)(c,r+7*l):c;return(0,y.constructFrom)(e,m.getTime()+1e3*(o+60*(n+60*i)))}var v=e.i(271645),N=e.i(237016),k=e.i(727749);function T({selectedToken:e,visible:t,onClose:a,onKeyUpdate:r}){let{accessToken:i}=(0,l.default)(),[j]=p.Form.useForm(),[_,y]=(0,v.useState)(null),[b,T]=(0,v.useState)(null),[w,S]=(0,v.useState)(null),[I,C]=(0,v.useState)(!1),[A,F]=(0,v.useState)(!1),[L,M]=(0,v.useState)(null);(0,v.useEffect)(()=>{t&&e&&i&&(j.setFieldsValue({key_alias:e.key_alias,max_budget:e.max_budget,tpm_limit:e.tpm_limit,rpm_limit:e.rpm_limit,duration:e.duration||"",grace_period:""}),M(i),F(e.key_name===i))},[t,e,j,i]),(0,v.useEffect)(()=>{t||(y(null),C(!1),F(!1),M(null),j.resetFields())},[t,j]);let R=e=>{if(!e)return null;try{let t,a=new Date;if(e.endsWith("s"))t=f(a,{seconds:parseInt(e)});else if(e.endsWith("h"))t=f(a,{hours:parseInt(e)});else if(e.endsWith("d"))t=f(a,{days:parseInt(e)});else throw Error("Invalid duration format");return t.toLocaleString()}catch(e){return null}};(0,v.useEffect)(()=>{b?.duration?S(R(b.duration)):S(null)},[b?.duration]);let D=async()=>{if(e&&L){C(!0);try{let t=await j.validateFields(),a=await (0,s.regenerateKeyCall)(L,e.token||e.token_id,t);y(a.key),k.default.success("Virtual Key regenerated successfully"),console.log("Full regenerate response:",a);let l={token:a.token||a.key_id||e.token,key_name:a.key,max_budget:t.max_budget,tpm_limit:t.tpm_limit,rpm_limit:t.rpm_limit,expires:t.duration?R(t.duration):e.expires,...a};console.log("Updated key data with new token:",l),r&&r(l),C(!1)}catch(e){console.error("Error regenerating key:",e),k.default.fromBackend(e),C(!1)}}},B=()=>{y(null),C(!1),F(!1),M(null),j.resetFields(),a()};return(0,n.jsx)(h.Modal,{title:"Regenerate Virtual Key",open:t,onCancel:B,footer:_?[(0,n.jsx)(o.Button,{onClick:B,children:"Close"},"close")]:[(0,n.jsx)(o.Button,{onClick:B,className:"mr-2",children:"Cancel"},"cancel"),(0,n.jsx)(o.Button,{onClick:D,disabled:I,children:I?"Regenerating...":"Regenerate"},"regenerate")],children:_?(0,n.jsxs)(c.Grid,{numItems:1,className:"gap-2 w-full",children:[(0,n.jsx)(x.Title,{children:"Regenerated Key"}),(0,n.jsx)(d.Col,{numColSpan:1,children:(0,n.jsxs)("p",{children:["Please replace your old key with the new key generated. For security reasons,"," ",(0,n.jsx)("b",{children:"you will not be able to view it again"})," through your LiteLLM account. If you lose this secret key, you will need to generate a new one."]})}),(0,n.jsxs)(d.Col,{numColSpan:1,children:[(0,n.jsx)(m.Text,{className:"mt-3",children:"Key Alias:"}),(0,n.jsx)("div",{className:"bg-gray-100 p-2 rounded mb-2",children:(0,n.jsx)("pre",{className:"break-words whitespace-normal",children:e?.key_alias||"No alias set"})}),(0,n.jsx)(m.Text,{className:"mt-3",children:"New Virtual Key:"}),(0,n.jsx)("div",{className:"bg-gray-100 p-2 rounded mb-2",children:(0,n.jsx)("pre",{className:"break-words whitespace-normal",children:_})}),(0,n.jsx)(N.CopyToClipboard,{text:_,onCopy:()=>k.default.success("Virtual Key copied to clipboard"),children:(0,n.jsx)(o.Button,{className:"mt-3",children:"Copy Virtual Key"})})]})]}):(0,n.jsxs)(p.Form,{form:j,layout:"vertical",onValuesChange:e=>{"duration"in e&&T(t=>({...t,duration:e.duration}))},children:[(0,n.jsx)(p.Form.Item,{name:"key_alias",label:"Key Alias",children:(0,n.jsx)(u.TextInput,{disabled:!0})}),(0,n.jsx)(p.Form.Item,{name:"max_budget",label:"Max Budget (USD)",children:(0,n.jsx)(g.InputNumber,{step:.01,precision:2,style:{width:"100%"}})}),(0,n.jsx)(p.Form.Item,{name:"tpm_limit",label:"TPM Limit",children:(0,n.jsx)(g.InputNumber,{style:{width:"100%"}})}),(0,n.jsx)(p.Form.Item,{name:"rpm_limit",label:"RPM Limit",children:(0,n.jsx)(g.InputNumber,{style:{width:"100%"}})}),(0,n.jsx)(p.Form.Item,{name:"duration",label:"Expire Key (eg: 30s, 30h, 30d)",className:"mt-8",children:(0,n.jsx)(u.TextInput,{placeholder:""})}),(0,n.jsxs)("div",{className:"mt-2 text-sm text-gray-500",children:["Current expiry: ",e?.expires?new Date(e.expires).toLocaleString():"Never"]}),w&&(0,n.jsxs)("div",{className:"mt-2 text-sm text-green-600",children:["New expiry: ",w]}),(0,n.jsx)(p.Form.Item,{name:"grace_period",label:"Grace Period (eg: 24h, 2d)",tooltip:"Keep the old key valid for this duration after rotation. Both keys work during this period for seamless cutover. Empty = immediate revoke.",className:"mt-8",rules:[{pattern:/^(\d+(s|m|h|d|w|mo))?$/,message:"Must be a duration like 30s, 30m, 24h, 2d, 1w, or 1mo"}],children:(0,n.jsx)(u.TextInput,{placeholder:"e.g. 24h, 2d (empty = immediate revoke)"})}),(0,n.jsx)("div",{className:"mt-2 text-sm text-gray-500",children:"Recommended: 24h to 72h for production keys to allow seamless client migration."})]})})}e.s(["RegenerateKeyModal",()=>T],690284)},183588,e=>{"use strict";var t=e.i(843476),a=e.i(266484);e.s(["default",0,({value:e,onChange:s,disabledCallbacks:l=[],onDisabledCallbacksChange:r})=>(0,t.jsx)(a.default,{value:e,onChange:s,disabledCallbacks:l,onDisabledCallbacksChange:r})])},20147,e=>{"use strict";var t=e.i(843476),a=e.i(135214),s=e.i(510674),l=e.i(292639),r=e.i(214541),i=e.i(500330),n=e.i(11751),o=e.i(530212),d=e.i(389083),c=e.i(994388),m=e.i(304967),u=e.i(350967),x=e.i(197647),p=e.i(653824),g=e.i(881073),h=e.i(404206),j=e.i(723731),_=e.i(599724),y=e.i(629569),b=e.i(808613),f=e.i(212931),v=e.i(262218),N=e.i(784647),k=e.i(271645),T=e.i(708347),w=e.i(557662),S=e.i(505022),I=e.i(127952),C=e.i(721929),A=e.i(643449),F=e.i(727749),L=e.i(764205),M=e.i(65932),R=e.i(384767),D=e.i(690284),B=e.i(190702),E=e.i(891547),P=e.i(921511),O=e.i(827252),K=e.i(779241),U=e.i(311451),V=e.i(199133),$=e.i(790848),z=e.i(592968),G=e.i(552130),W=e.i(9314),H=e.i(392110),q=e.i(844565),J=e.i(939510),Q=e.i(75921),Y=e.i(390605),X=e.i(702597),Z=e.i(435451),ee=e.i(183588),et=e.i(916940);function ea({keyData:e,onCancel:a,onSubmit:r,teams:i,accessToken:n,userID:o,userRole:d,premiumUser:m=!1}){let u=m||null!=d&&T.rolesWithWriteAccess.includes(d),[x]=b.Form.useForm(),[p,g]=(0,k.useState)([]),[h,j]=(0,k.useState)({}),_=i?.find(t=>t.team_id===e.team_id),[y,f]=(0,k.useState)([]),[v,N]=(0,k.useState)(Array.isArray(e.metadata?.litellm_disabled_callbacks)?(0,w.mapInternalToDisplayNames)(e.metadata.litellm_disabled_callbacks):[]),[S,I]=(0,k.useState)(e.auto_rotate||!1),[A,M]=(0,k.useState)(e.rotation_interval||""),[R,D]=(0,k.useState)(!e.expires),[B,ea]=(0,k.useState)(!1),{data:es}=(0,s.useProjects)(),{data:el}=(0,l.useUISettings)(),er=!!el?.values?.enable_projects_ui,ei=!!e.project_id,en=(()=>{if(!e.project_id)return null;let t=es?.find(t=>t.project_id===e.project_id);return t?.project_alias?`${t.project_alias} (${e.project_id})`:e.project_id})();(0,k.useEffect)(()=>{let t=async()=>{if(o&&d&&n)try{if(null===e.team_id){let e=(await (0,L.modelAvailableCall)(n,o,d)).data.map(e=>e.id);f(e)}else if(_?.team_id){let e=await (0,X.fetchTeamModels)(o,d,n,_.team_id);f(Array.from(new Set([..._.models,...e])))}}catch(e){console.error("Error fetching models:",e)}};(async()=>{if(n)try{let e=await (0,L.getPromptsList)(n);g(e.prompts.map(e=>e.prompt_id))}catch(e){console.error("Failed to fetch prompts:",e)}})(),t()},[o,d,n,_,e.team_id]),(0,k.useEffect)(()=>{x.setFieldValue("disabled_callbacks",v)},[x,v]);let eo=e=>e&&({"24h":"daily","7d":"weekly","30d":"monthly"})[e]||null,ed={...e,token:e.token||e.token_id,budget_duration:eo(e.budget_duration),metadata:(0,C.formatMetadataForDisplay)((0,C.stripTagsFromMetadata)(e.metadata)),guardrails:e.metadata?.guardrails,disable_global_guardrails:e.metadata?.disable_global_guardrails||!1,prompts:e.metadata?.prompts,tags:e.metadata?.tags,vector_stores:e.object_permission?.vector_stores||[],mcp_servers_and_groups:{servers:e.object_permission?.mcp_servers||[],accessGroups:e.object_permission?.mcp_access_groups||[]},mcp_tool_permissions:e.object_permission?.mcp_tool_permissions||{},agents_and_groups:{agents:e.object_permission?.agents||[],accessGroups:e.object_permission?.agent_access_groups||[]},logging_settings:(0,C.extractLoggingSettings)(e.metadata),disabled_callbacks:Array.isArray(e.metadata?.litellm_disabled_callbacks)?(0,w.mapInternalToDisplayNames)(e.metadata.litellm_disabled_callbacks):[],access_group_ids:e.access_group_ids||[],auto_rotate:e.auto_rotate||!1,...e.rotation_interval&&{rotation_interval:e.rotation_interval},allowed_routes:Array.isArray(e.allowed_routes)&&e.allowed_routes.length>0?e.allowed_routes.join(", "):""};(0,k.useEffect)(()=>{x.setFieldsValue({...e,token:e.token||e.token_id,budget_duration:eo(e.budget_duration),metadata:(0,C.formatMetadataForDisplay)((0,C.stripTagsFromMetadata)(e.metadata)),guardrails:e.metadata?.guardrails,disable_global_guardrails:e.metadata?.disable_global_guardrails||!1,prompts:e.metadata?.prompts,tags:e.metadata?.tags,vector_stores:e.object_permission?.vector_stores||[],mcp_servers_and_groups:{servers:e.object_permission?.mcp_servers||[],accessGroups:e.object_permission?.mcp_access_groups||[]},mcp_tool_permissions:e.object_permission?.mcp_tool_permissions||{},logging_settings:(0,C.extractLoggingSettings)(e.metadata),disabled_callbacks:Array.isArray(e.metadata?.litellm_disabled_callbacks)?(0,w.mapInternalToDisplayNames)(e.metadata.litellm_disabled_callbacks):[],access_group_ids:e.access_group_ids||[],auto_rotate:e.auto_rotate||!1,...e.rotation_interval&&{rotation_interval:e.rotation_interval},allowed_routes:Array.isArray(e.allowed_routes)&&e.allowed_routes.length>0?e.allowed_routes.join(", "):""})},[e,x]),(0,k.useEffect)(()=>{x.setFieldValue("auto_rotate",S)},[S,x]),(0,k.useEffect)(()=>{A&&x.setFieldValue("rotation_interval",A)},[A,x]),(0,k.useEffect)(()=>{(async()=>{if(n)try{let e=await (0,L.tagListCall)(n);j(e)}catch(e){F.default.fromBackend("Error fetching tags: "+e)}})()},[n]);let ec=async e=>{try{if(ea(!0),"string"==typeof e.allowed_routes){let t=e.allowed_routes.trim();""===t?e.allowed_routes=[]:e.allowed_routes=t.split(",").map(e=>e.trim()).filter(e=>e.length>0)}R&&(e.duration=null),await r(e)}finally{ea(!1)}};return(0,t.jsxs)(b.Form,{form:x,onFinish:ec,initialValues:ed,layout:"vertical",children:[(0,t.jsx)(b.Form.Item,{label:"Key Alias",name:"key_alias",children:(0,t.jsx)(K.TextInput,{})}),(0,t.jsx)(b.Form.Item,{label:"Models",name:"models",children:(0,t.jsx)(b.Form.Item,{noStyle:!0,shouldUpdate:(e,t)=>e.allowed_routes!==t.allowed_routes||e.models!==t.models,children:({getFieldValue:e,setFieldValue:a})=>{let s=e("allowed_routes")||"",l="string"==typeof s&&""!==s.trim()?s.split(",").map(e=>e.trim()).filter(e=>e.length>0):[],r=l.includes("management_routes")||l.includes("info_routes"),i=e("models")||[];return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(V.Select,{mode:"multiple",placeholder:"Select models",style:{width:"100%"},disabled:r,value:r?[]:i,onChange:e=>a("models",e),children:[y.length>0&&(0,t.jsx)(V.Select.Option,{value:"all-team-models",children:"All Team Models"}),y.map(e=>(0,t.jsx)(V.Select.Option,{value:e,children:e},e))]}),r&&(0,t.jsx)("div",{style:{fontSize:"11px",color:"#6b7280",marginTop:"2px"},children:"Models field is disabled for this key type"})]})}})}),(0,t.jsx)(b.Form.Item,{label:"Key Type",children:(0,t.jsx)(b.Form.Item,{noStyle:!0,shouldUpdate:(e,t)=>e.allowed_routes!==t.allowed_routes,children:({getFieldValue:e,setFieldValue:a})=>{var s;let l=e("allowed_routes")||"",r=(s="string"==typeof l&&""!==l.trim()?l.split(",").map(e=>e.trim()).filter(e=>e.length>0):[])&&0!==s.length?s.includes("llm_api_routes")?"llm_api":s.includes("management_routes")?"management":s.includes("info_routes")?"read_only":"default":"default";return(0,t.jsxs)(V.Select,{placeholder:"Select key type",style:{width:"100%"},optionLabelProp:"label",value:r,onChange:e=>{switch(e){case"default":a("allowed_routes","");break;case"llm_api":a("allowed_routes","llm_api_routes");break;case"management":a("allowed_routes","management_routes"),a("models",[])}},children:[(0,t.jsx)(V.Select.Option,{value:"default",label:"Default",children:(0,t.jsxs)("div",{style:{padding:"4px 0"},children:[(0,t.jsx)("div",{style:{fontWeight:500},children:"Default"}),(0,t.jsx)("div",{style:{fontSize:"11px",color:"#6b7280",marginTop:"2px"},children:"Can call AI APIs + Management routes"})]})}),(0,t.jsx)(V.Select.Option,{value:"llm_api",label:"AI APIs",children:(0,t.jsxs)("div",{style:{padding:"4px 0"},children:[(0,t.jsx)("div",{style:{fontWeight:500},children:"AI APIs"}),(0,t.jsx)("div",{style:{fontSize:"11px",color:"#6b7280",marginTop:"2px"},children:"Can call only AI API routes (chat/completions, embeddings, etc.)"})]})}),(0,t.jsx)(V.Select.Option,{value:"management",label:"Management",children:(0,t.jsxs)("div",{style:{padding:"4px 0"},children:[(0,t.jsx)("div",{style:{fontWeight:500},children:"Management"}),(0,t.jsx)("div",{style:{fontSize:"11px",color:"#6b7280",marginTop:"2px"},children:"Can call only management routes (user/team/key management)"})]})})]})}})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Allowed Routes"," ",(0,t.jsx)(z.Tooltip,{title:"List of allowed routes for the key (comma-separated). Can be specific routes (e.g., '/chat/completions') or route patterns (e.g., 'llm_api_routes', 'management_routes', '/keys/*'). Leave empty to allow all routes.",children:(0,t.jsx)(O.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"allowed_routes",children:(0,t.jsx)(U.Input,{placeholder:"Enter allowed routes (comma-separated). Special values: llm_api_routes, management_routes. Examples: llm_api_routes, /chat/completions, /keys/*. Leave empty to allow all routes"})}),(0,t.jsx)(b.Form.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,t.jsx)(Z.default,{step:.01,style:{width:"100%"},placeholder:"Enter a numerical value"})}),(0,t.jsx)(b.Form.Item,{label:"Reset Budget",name:"budget_duration",children:(0,t.jsxs)(V.Select,{placeholder:"n/a",children:[(0,t.jsx)(V.Select.Option,{value:"daily",children:"Daily"}),(0,t.jsx)(V.Select.Option,{value:"weekly",children:"Weekly"}),(0,t.jsx)(V.Select.Option,{value:"monthly",children:"Monthly"})]})}),(0,t.jsx)(b.Form.Item,{label:"TPM Limit",name:"tpm_limit",children:(0,t.jsx)(Z.default,{min:0})}),(0,t.jsx)(J.default,{type:"tpm",name:"tpm_limit_type",showDetailedDescriptions:!1}),(0,t.jsx)(b.Form.Item,{label:"RPM Limit",name:"rpm_limit",children:(0,t.jsx)(Z.default,{min:0})}),(0,t.jsx)(J.default,{type:"rpm",name:"rpm_limit_type",showDetailedDescriptions:!1}),(0,t.jsx)(b.Form.Item,{label:"Max Parallel Requests",name:"max_parallel_requests",children:(0,t.jsx)(Z.default,{min:0})}),(0,t.jsx)(b.Form.Item,{label:"Model TPM Limit",name:"model_tpm_limit",children:(0,t.jsx)(U.Input.TextArea,{rows:4,placeholder:'{"gpt-4": 100, "claude-v1": 200}'})}),(0,t.jsx)(b.Form.Item,{label:"Model RPM Limit",name:"model_rpm_limit",children:(0,t.jsx)(U.Input.TextArea,{rows:4,placeholder:'{"gpt-4": 100, "claude-v1": 200}'})}),(0,t.jsx)(b.Form.Item,{label:"Guardrails",name:"guardrails",children:n&&(0,t.jsx)(E.default,{onChange:e=>{x.setFieldValue("guardrails",e)},accessToken:n,disabled:!u})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Disable Global Guardrails"," ",(0,t.jsx)(z.Tooltip,{title:"When enabled, this key will bypass any guardrails configured to run on every request (global guardrails)",children:(0,t.jsx)(O.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"disable_global_guardrails",valuePropName:"checked",children:(0,t.jsx)($.Switch,{disabled:!u,checkedChildren:"Yes",unCheckedChildren:"No"})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Policies"," ",(0,t.jsx)(z.Tooltip,{title:"Apply policies to this key to control guardrails and other settings",children:(0,t.jsx)(O.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"policies",children:n&&(0,t.jsx)(P.default,{onChange:e=>{x.setFieldValue("policies",e)},accessToken:n,disabled:!m})}),(0,t.jsx)(b.Form.Item,{label:"Tags",name:"tags",children:(0,t.jsx)(V.Select,{mode:"tags",style:{width:"100%"},placeholder:"Select or enter tags",options:Object.values(h).map(e=>({value:e.name,label:e.name,title:e.description||e.name}))})}),(0,t.jsx)(b.Form.Item,{label:"Prompts",name:"prompts",children:(0,t.jsx)(z.Tooltip,{title:m?"":"Setting prompts by key is a premium feature",placement:"top",children:(0,t.jsx)(V.Select,{mode:"tags",style:{width:"100%"},disabled:!m,placeholder:m?Array.isArray(e.metadata?.prompts)&&e.metadata.prompts.length>0?`Current: ${e.metadata.prompts.join(", ")}`:"Select or enter prompts":"Premium feature - Upgrade to set prompts by key",options:p.map(e=>({value:e,label:e}))})})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Access Groups"," ",(0,t.jsx)(z.Tooltip,{title:"Assign access groups to this key. Access groups control which models, MCP servers, and agents this key can use",children:(0,t.jsx)(O.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"access_group_ids",children:(0,t.jsx)(W.default,{placeholder:"Select access groups (optional)"})}),(0,t.jsx)(b.Form.Item,{label:"Allowed Pass Through Routes",name:"allowed_passthrough_routes",children:(0,t.jsx)(z.Tooltip,{title:m?"":"Setting allowed pass through routes by key is a premium feature",placement:"top",children:(0,t.jsx)(q.default,{onChange:e=>x.setFieldValue("allowed_passthrough_routes",e),value:x.getFieldValue("allowed_passthrough_routes"),accessToken:n||"",placeholder:m?Array.isArray(e.metadata?.allowed_passthrough_routes)&&e.metadata.allowed_passthrough_routes.length>0?`Current: ${e.metadata.allowed_passthrough_routes.join(", ")}`:"Select or enter allowed pass through routes":"Premium feature - Upgrade to set allowed pass through routes by key",disabled:!m})})}),(0,t.jsx)(b.Form.Item,{label:"Vector Stores",name:"vector_stores",children:(0,t.jsx)(et.default,{onChange:e=>x.setFieldValue("vector_stores",e),value:x.getFieldValue("vector_stores"),accessToken:n||"",placeholder:"Select vector stores"})}),(0,t.jsx)(b.Form.Item,{label:"MCP Servers / Access Groups",name:"mcp_servers_and_groups",children:(0,t.jsx)(Q.default,{onChange:e=>x.setFieldValue("mcp_servers_and_groups",e),value:x.getFieldValue("mcp_servers_and_groups"),accessToken:n||"",placeholder:"Select MCP servers or access groups (optional)"})}),(0,t.jsx)(b.Form.Item,{name:"mcp_tool_permissions",initialValue:{},hidden:!0,children:(0,t.jsx)(U.Input,{type:"hidden"})}),(0,t.jsx)(b.Form.Item,{noStyle:!0,shouldUpdate:(e,t)=>e.mcp_servers_and_groups!==t.mcp_servers_and_groups||e.mcp_tool_permissions!==t.mcp_tool_permissions,children:()=>(0,t.jsx)("div",{className:"mb-6",children:(0,t.jsx)(Y.default,{accessToken:n||"",selectedServers:x.getFieldValue("mcp_servers_and_groups")?.servers||[],toolPermissions:x.getFieldValue("mcp_tool_permissions")||{},onChange:e=>x.setFieldsValue({mcp_tool_permissions:e})})})}),(0,t.jsx)(b.Form.Item,{label:"Agents / Access Groups",name:"agents_and_groups",children:(0,t.jsx)(G.default,{onChange:e=>x.setFieldValue("agents_and_groups",e),value:x.getFieldValue("agents_and_groups"),accessToken:n||"",placeholder:"Select agents or access groups (optional)"})}),(0,t.jsx)(b.Form.Item,{label:"Team ID",name:"team_id",help:er&&ei?"Team is locked because this key belongs to a project":void 0,children:(0,t.jsx)(V.Select,{placeholder:"Select team",showSearch:!0,disabled:er&&ei,style:{width:"100%"},filterOption:(e,t)=>{let a=i?.find(e=>e.team_id===t?.value);return!!a&&(a.team_alias?.toLowerCase().includes(e.toLowerCase())??!1)},children:i?.map(e=>(0,t.jsx)(V.Select.Option,{value:e.team_id,children:`${e.team_alias} (${e.team_id})`},e.team_id))})}),er&&ei&&(0,t.jsx)(b.Form.Item,{label:"Project",children:(0,t.jsx)(U.Input,{value:en??"",disabled:!0})}),(0,t.jsx)(b.Form.Item,{label:"Logging Settings",name:"logging_settings",children:(0,t.jsx)(ee.default,{value:x.getFieldValue("logging_settings"),onChange:e=>x.setFieldValue("logging_settings",e),disabledCallbacks:v,onDisabledCallbacksChange:e=>{N((0,w.mapInternalToDisplayNames)(e)),x.setFieldValue("disabled_callbacks",e)}})}),(0,t.jsx)(b.Form.Item,{label:"Metadata",name:"metadata",children:(0,t.jsx)(U.Input.TextArea,{rows:10})}),(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(H.default,{form:x,autoRotationEnabled:S,onAutoRotationChange:I,rotationInterval:A,onRotationIntervalChange:M,neverExpire:R,onNeverExpireChange:D}),(0,t.jsx)(b.Form.Item,{name:"duration",hidden:!0,initialValue:"",children:(0,t.jsx)(U.Input,{})})]}),(0,t.jsx)(b.Form.Item,{name:"token",hidden:!0,children:(0,t.jsx)(U.Input,{})}),(0,t.jsx)(b.Form.Item,{name:"disabled_callbacks",hidden:!0,children:(0,t.jsx)(U.Input,{})}),(0,t.jsx)(b.Form.Item,{name:"auto_rotate",hidden:!0,children:(0,t.jsx)(U.Input,{})}),(0,t.jsx)(b.Form.Item,{name:"rotation_interval",hidden:!0,children:(0,t.jsx)(U.Input,{})}),(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)(c.Button,{variant:"secondary",onClick:a,disabled:B,children:"Cancel"}),(0,t.jsx)(c.Button,{type:"submit",loading:B,children:"Save Changes"})]})})]})}function es({onClose:e,keyData:E,teams:P,onKeyDataUpdate:O,onDelete:K,backButtonText:U="Back to Keys"}){let V,{accessToken:$,userId:z,userRole:G,premiumUser:W}=(0,a.default)(),H=W||null!=G&&T.rolesWithWriteAccess.includes(G),{teams:q}=(0,r.default)(),{data:J}=(0,s.useProjects)(),{data:Q}=(0,l.useUISettings)(),Y=!!Q?.values?.enable_projects_ui,[X,Z]=(0,k.useState)(!1),[ee]=b.Form.useForm(),[et,es]=(0,k.useState)(!1),[el,er]=(0,k.useState)(!1),[ei,en]=(0,k.useState)(""),[eo,ed]=(0,k.useState)(!1),[ec,em]=(0,k.useState)(!1),{mutate:eu,isPending:ex}=(0,M.useResetKeySpend)(),[ep,eg]=(0,k.useState)(E),[eh,ej]=(0,k.useState)(null),[e_,ey]=(0,k.useState)(!1),[eb,ef]=(0,k.useState)({}),[ev,eN]=(0,k.useState)(!1);if((0,k.useEffect)(()=>{E&&eg(E)},[E]),(0,k.useEffect)(()=>{(async()=>{let e=ep?.metadata?.policies;if(!$||!e||!Array.isArray(e)||0===e.length)return;eN(!0);let t={};try{await Promise.all(e.map(async e=>{try{let a=await (0,L.getPolicyInfoWithGuardrails)($,e);t[e]=a.resolved_guardrails||[]}catch(a){console.error(`Failed to fetch guardrails for policy ${e}:`,a),t[e]=[]}})),ef(t)}catch(e){console.error("Failed to fetch policy guardrails:",e)}finally{eN(!1)}})()},[$,ep?.metadata?.policies]),(0,k.useEffect)(()=>{if(e_){let e=setTimeout(()=>{ey(!1)},5e3);return()=>clearTimeout(e)}},[e_]),!ep)return(0,t.jsxs)("div",{className:"p-4",children:[(0,t.jsx)(c.Button,{icon:o.ArrowLeftIcon,variant:"light",onClick:e,className:"mb-4",children:U}),(0,t.jsx)(_.Text,{children:"Key not found"})]});let ek=async e=>{try{if(!$)return;let t=e.token;if(e.key=t,H||(delete e.guardrails,delete e.prompts),e.max_budget=(0,n.mapEmptyStringToNull)(e.max_budget),void 0!==e.vector_stores&&(e.object_permission={...ep.object_permission,vector_stores:e.vector_stores||[]},delete e.vector_stores),void 0!==e.mcp_servers_and_groups){let{servers:t,accessGroups:a}=e.mcp_servers_and_groups||{servers:[],accessGroups:[]};e.object_permission={...ep.object_permission,mcp_servers:t||[],mcp_access_groups:a||[]},delete e.mcp_servers_and_groups}if(void 0!==e.mcp_tool_permissions){let t=e.mcp_tool_permissions||{};Object.keys(t).length>0&&(e.object_permission={...e.object_permission,mcp_tool_permissions:t}),delete e.mcp_tool_permissions}if(void 0!==e.agents_and_groups){let{agents:t,accessGroups:a}=e.agents_and_groups||{agents:[],accessGroups:[]};e.object_permission={...e.object_permission,agents:t||[],agent_access_groups:a||[]},delete e.agents_and_groups}if(e.max_budget=(0,n.mapEmptyStringToNull)(e.max_budget),e.tpm_limit=(0,n.mapEmptyStringToNull)(e.tpm_limit),e.rpm_limit=(0,n.mapEmptyStringToNull)(e.rpm_limit),e.max_parallel_requests=(0,n.mapEmptyStringToNull)(e.max_parallel_requests),e.metadata&&"string"==typeof e.metadata)try{let t=JSON.parse(e.metadata);"tags"in t&&delete t.tags,e.metadata={...t,...Array.isArray(e.tags)&&e.tags.length>0?{tags:e.tags}:{},...e.guardrails?.length>0?{guardrails:e.guardrails}:{},...Array.isArray(e.logging_settings)&&e.logging_settings.length>0?{logging:e.logging_settings}:{},...e.disabled_callbacks?.length>0?{litellm_disabled_callbacks:(0,w.mapDisplayToInternalNames)(e.disabled_callbacks)}:{}}}catch(e){console.error("Error parsing metadata JSON:",e),F.default.error("Invalid metadata JSON");return}else{let{tags:t,...a}=e.metadata||{};e.metadata={...a,...Array.isArray(e.tags)&&e.tags.length>0?{tags:e.tags}:{},...e.guardrails?.length>0?{guardrails:e.guardrails}:{},...Array.isArray(e.logging_settings)&&e.logging_settings.length>0?{logging:e.logging_settings}:{},...e.disabled_callbacks?.length>0?{litellm_disabled_callbacks:(0,w.mapDisplayToInternalNames)(e.disabled_callbacks)}:{}}}"tags"in e&&delete e.tags,delete e.logging_settings,e.budget_duration&&(e.budget_duration=({daily:"24h",weekly:"7d",monthly:"30d"})[e.budget_duration]);let a=await (0,L.keyUpdateCall)($,e);eg(e=>e?{...e,...a}:void 0),O&&O(a),F.default.success("Key updated successfully"),Z(!1)}catch(e){F.default.fromBackend((0,B.parseErrorMessage)(e)),console.error("Error updating key:",e)}},eT=async()=>{try{if(er(!0),!$)return;await (0,L.keyDeleteCall)($,ep.token||ep.token_id),F.default.success("Key deleted successfully"),K&&K(),e()}catch(e){console.error("Error deleting the key:",e),F.default.fromBackend(e)}finally{er(!1),es(!1),en("")}},ew=e=>{let t=new Date(e),a=t.toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"}),s=t.toLocaleTimeString("en-US",{hour:"numeric",minute:"2-digit",hour12:!0});return`${a} at ${s}`},eS=(0,T.isProxyAdminRole)(G||"")||q&&(0,T.isUserTeamAdminForSingleTeam)(q?.filter(e=>e.team_id===ep.team_id)[0]?.members_with_roles,z||"")||z===ep.user_id&&"Internal Viewer"!==G,eI=(0,T.isProxyAdminRole)(G||"")||q&&(0,T.isUserTeamAdminForSingleTeam)(q?.filter(e=>e.team_id===ep.team_id)[0]?.members_with_roles,z||"");return(0,t.jsxs)("div",{className:"w-full h-screen p-4",children:[(0,t.jsx)(N.KeyInfoHeader,{data:{keyName:ep.key_alias||"Virtual Key",keyId:ep.token_id||ep.token,userId:ep.user_id||"",userEmail:ep.user_email||"",createdBy:ep.user_email||ep.user_id||"",createdAt:ep.created_at?ew(ep.created_at):"",lastUpdated:ep.updated_at?ew(ep.updated_at):"",lastActive:ep.last_active?ew(ep.last_active):"Never"},onBack:e,onRegenerate:()=>ed(!0),onDelete:()=>es(!0),onResetSpend:eI?()=>em(!0):void 0,canModifyKey:eS,backButtonText:U,regenerateDisabled:!W,regenerateTooltip:W?void 0:"This is a LiteLLM Enterprise feature, and requires a valid key to use."}),(0,t.jsx)(D.RegenerateKeyModal,{selectedToken:ep,visible:eo,onClose:()=>ed(!1),onKeyUpdate:e=>{eg(t=>{if(t)return{...t,...e,created_at:new Date().toLocaleString()}}),ej(new Date),ey(!0),O&&O({...e,created_at:new Date().toLocaleString()})}}),(0,t.jsx)(I.default,{isOpen:et,title:"Delete Key",alertMessage:"This action is irreversible and will immediately revoke access for any applications using this key.",message:"Are you sure you want to delete this Virtual Key?",resourceInformationTitle:"Key Information",resourceInformation:[{label:"Key Alias",value:ep?.key_alias||"-"},{label:"Key ID",value:ep?.token_id||ep?.token||"-",code:!0},{label:"Team ID",value:ep?.team_id||"-",code:!0},{label:"Spend",value:ep?.spend?`$${(0,i.formatNumberWithCommas)(ep.spend,4)}`:"$0.0000"}],onCancel:()=>{es(!1),en("")},onOk:eT,confirmLoading:el,requiredConfirmation:ep?.key_alias}),(0,t.jsxs)(f.Modal,{title:"Reset Key Spend",open:ec,onOk:()=>{eu(ep.token||ep.token_id,{onSuccess:()=>{eg(e=>e?{...e,spend:0}:void 0),O&&O({spend:0}),F.default.success("Key spend reset to $0"),em(!1)},onError:e=>{F.default.fromBackend((0,B.parseErrorMessage)(e)),console.error("Error resetting key spend:",e)}})},onCancel:()=>em(!1),okText:"Reset",okButtonProps:{danger:!0},confirmLoading:ex,children:[(0,t.jsxs)("p",{children:["Reset spend for ",(0,t.jsx)("strong",{children:ep?.key_alias||ep?.token_id||"this key"})," to"," ",(0,t.jsx)("strong",{children:"$0"}),"?"]}),(0,t.jsxs)("p",{style:{color:"#666",fontSize:"0.875rem",marginTop:8},children:["Current spend: ",(0,t.jsxs)("strong",{children:["$",(0,i.formatNumberWithCommas)(ep.spend,4)]}),". Spend history is preserved in logs. This resets the current period spend counter, the same as an automatic budget reset."]})]}),(0,t.jsxs)(p.TabGroup,{children:[(0,t.jsxs)(g.TabList,{className:"mb-4",children:[(0,t.jsx)(x.Tab,{children:"Overview"}),(0,t.jsx)(x.Tab,{children:"Settings"})]}),(0,t.jsxs)(j.TabPanels,{children:[(0,t.jsx)(h.TabPanel,{children:(0,t.jsxs)(u.Grid,{numItems:1,numItemsSm:2,numItemsLg:3,className:"gap-6",children:[(0,t.jsxs)(m.Card,{children:[(0,t.jsx)(_.Text,{children:"Spend"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(y.Title,{children:["$",(0,i.formatNumberWithCommas)(ep.spend,4)]}),(0,t.jsxs)(_.Text,{children:["of"," ",null!==ep.max_budget?`$${(0,i.formatNumberWithCommas)(ep.max_budget)}`:"Unlimited"]})]})]}),(0,t.jsxs)(m.Card,{children:[(0,t.jsx)(_.Text,{children:"Rate Limits"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(_.Text,{children:["TPM: ",null!==ep.tpm_limit?ep.tpm_limit:"Unlimited"]}),(0,t.jsxs)(_.Text,{children:["RPM: ",null!==ep.rpm_limit?ep.rpm_limit:"Unlimited"]})]})]}),(0,t.jsxs)(m.Card,{children:[(0,t.jsx)(_.Text,{children:"Models"}),(0,t.jsx)("div",{className:"mt-2 flex flex-wrap gap-2",children:ep.models&&ep.models.length>0?ep.models.map((e,a)=>(0,t.jsx)(d.Badge,{color:"red",children:e},a)):(0,t.jsx)(_.Text,{children:"No models specified"})})]}),(0,t.jsx)(m.Card,{children:(0,t.jsx)(R.default,{objectPermission:ep.object_permission,variant:"inline",accessToken:$})}),(0,t.jsxs)(m.Card,{children:[(0,t.jsx)(_.Text,{className:"font-medium mb-3",children:"Guardrails"}),Array.isArray(ep.metadata?.guardrails)&&ep.metadata.guardrails.length>0?(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:ep.metadata.guardrails.map((e,a)=>(0,t.jsx)(d.Badge,{color:"blue",children:e},a))}):(0,t.jsx)(_.Text,{className:"text-gray-500",children:"No guardrails configured"}),"boolean"==typeof ep.metadata?.disable_global_guardrails&&!0===ep.metadata.disable_global_guardrails&&(0,t.jsx)("div",{className:"mt-3 pt-3 border-t border-gray-200",children:(0,t.jsx)(d.Badge,{color:"yellow",children:"Global Guardrails Disabled"})})]}),(0,t.jsxs)(m.Card,{children:[(0,t.jsx)(_.Text,{className:"font-medium mb-3",children:"Policies"}),Array.isArray(ep.metadata?.policies)&&ep.metadata.policies.length>0?(0,t.jsx)("div",{className:"space-y-4",children:ep.metadata.policies.map((e,a)=>(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(d.Badge,{color:"purple",children:e}),ev&&(0,t.jsx)(_.Text,{className:"text-xs text-gray-400",children:"Loading guardrails..."})]}),!ev&&eb[e]&&eb[e].length>0&&(0,t.jsxs)("div",{className:"ml-4 pl-3 border-l-2 border-gray-200",children:[(0,t.jsx)(_.Text,{className:"text-xs text-gray-500 mb-1",children:"Resolved Guardrails:"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-1",children:eb[e].map((e,a)=>(0,t.jsx)(d.Badge,{color:"blue",size:"xs",children:e},a))})]})]},a))}):(0,t.jsx)(_.Text,{className:"text-gray-500",children:"No policies configured"})]}),(0,t.jsx)(A.default,{loggingConfigs:(0,C.extractLoggingSettings)(ep.metadata),disabledCallbacks:Array.isArray(ep.metadata?.litellm_disabled_callbacks)?(0,w.mapInternalToDisplayNames)(ep.metadata.litellm_disabled_callbacks):[],variant:"card"}),(0,t.jsx)(S.default,{autoRotate:ep.auto_rotate,rotationInterval:ep.rotation_interval,lastRotationAt:ep.last_rotation_at,keyRotationAt:ep.key_rotation_at,nextRotationAt:ep.next_rotation_at,variant:"card"})]})}),(0,t.jsx)(h.TabPanel,{children:(0,t.jsxs)(m.Card,{className:"overflow-y-auto max-h-[65vh]",children:[(0,t.jsxs)("div",{className:"flex justify-between items-center mb-4",children:[(0,t.jsx)(y.Title,{children:"Key Settings"}),!X&&eS&&(0,t.jsx)(c.Button,{onClick:()=>Z(!0),children:"Edit Settings"})]}),X?(0,t.jsx)(ea,{keyData:ep,onCancel:()=>Z(!1),onSubmit:ek,teams:P,accessToken:$,userID:z,userRole:G,premiumUser:W}):(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Key ID"}),(0,t.jsx)(_.Text,{className:"font-mono",children:ep.token_id||ep.token})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Key Alias"}),(0,t.jsx)(_.Text,{children:ep.key_alias||"Not Set"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Secret Key"}),(0,t.jsx)(_.Text,{className:"font-mono",children:ep.key_name})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Team ID"}),(0,t.jsx)(_.Text,{children:ep.team_id||"Not Set"})]}),Y&&(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Project"}),(0,t.jsx)(_.Text,{children:ep.project_id?(V=J?.find(e=>e.project_id===ep.project_id),V?.project_alias?`${V.project_alias} (${ep.project_id})`:ep.project_id):"Not Set"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Organization"}),(0,t.jsx)(_.Text,{children:(ep.organization_id??ep.org_id)||"Not Set"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Created"}),(0,t.jsx)(_.Text,{children:ew(ep.created_at)})]}),eh&&(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Last Regenerated"}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(_.Text,{children:ew(eh)}),(0,t.jsx)(d.Badge,{color:"green",size:"xs",children:"Recent"})]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Expires"}),(0,t.jsx)(_.Text,{children:ep.expires?ew(ep.expires):"Never"})]}),(0,t.jsx)(S.default,{autoRotate:ep.auto_rotate,rotationInterval:ep.rotation_interval,lastRotationAt:ep.last_rotation_at,keyRotationAt:ep.key_rotation_at,nextRotationAt:ep.next_rotation_at,variant:"inline",className:"pt-4 border-t border-gray-200"}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Spend"}),(0,t.jsxs)(_.Text,{children:["$",(0,i.formatNumberWithCommas)(ep.spend,4)," USD"]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Budget"}),(0,t.jsx)(_.Text,{children:null!==ep.max_budget?`$${(0,i.formatNumberWithCommas)(ep.max_budget,2)}`:"Unlimited"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Tags"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:Array.isArray(ep.metadata?.tags)&&ep.metadata.tags.length>0?ep.metadata.tags.map((e,a)=>(0,t.jsx)("span",{className:"px-2 mr-2 py-1 bg-blue-100 rounded text-xs",children:e},a)):"No tags specified"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Prompts"}),(0,t.jsx)(_.Text,{children:Array.isArray(ep.metadata?.prompts)&&ep.metadata.prompts.length>0?ep.metadata.prompts.map((e,a)=>(0,t.jsx)("span",{className:"px-2 mr-2 py-1 bg-blue-100 rounded text-xs",children:e},a)):"No prompts specified"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Allowed Routes"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:Array.isArray(ep.allowed_routes)&&ep.allowed_routes.length>0?ep.allowed_routes.map((e,a)=>(0,t.jsx)("span",{className:"px-2 py-1 bg-blue-100 rounded text-xs",children:e},a)):(0,t.jsx)(v.Tag,{color:"green",children:"All routes allowed"})})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Allowed Pass Through Routes"}),(0,t.jsx)(_.Text,{children:Array.isArray(ep.metadata?.allowed_passthrough_routes)&&ep.metadata.allowed_passthrough_routes.length>0?ep.metadata.allowed_passthrough_routes.map((e,a)=>(0,t.jsx)("span",{className:"px-2 mr-2 py-1 bg-blue-100 rounded text-xs",children:e},a)):"No pass through routes specified"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Disable Global Guardrails"}),(0,t.jsx)(_.Text,{children:ep.metadata?.disable_global_guardrails===!0?(0,t.jsx)(d.Badge,{color:"yellow",children:"Enabled - Global guardrails bypassed"}):(0,t.jsx)(d.Badge,{color:"green",children:"Disabled - Global guardrails active"})})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Models"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:ep.models&&ep.models.length>0?ep.models.map((e,a)=>(0,t.jsx)("span",{className:"px-2 py-1 bg-blue-100 rounded text-xs",children:e},a)):(0,t.jsx)(_.Text,{children:"No models specified"})})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Rate Limits"}),(0,t.jsxs)(_.Text,{children:["TPM: ",null!==ep.tpm_limit?ep.tpm_limit:"Unlimited"]}),(0,t.jsxs)(_.Text,{children:["RPM: ",null!==ep.rpm_limit?ep.rpm_limit:"Unlimited"]}),(0,t.jsxs)(_.Text,{children:["Max Parallel Requests:"," ",null!==ep.max_parallel_requests?ep.max_parallel_requests:"Unlimited"]}),(0,t.jsxs)(_.Text,{children:["Model TPM Limits:"," ",ep.metadata?.model_tpm_limit?JSON.stringify(ep.metadata.model_tpm_limit):"Unlimited"]}),(0,t.jsxs)(_.Text,{children:["Model RPM Limits:"," ",ep.metadata?.model_rpm_limit?JSON.stringify(ep.metadata.model_rpm_limit):"Unlimited"]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(_.Text,{className:"font-medium",children:"Metadata"}),(0,t.jsx)("pre",{className:"bg-gray-100 p-2 rounded text-xs overflow-auto mt-1",children:(0,C.formatMetadataForDisplay)((0,C.stripTagsFromMetadata)(ep.metadata))})]}),(0,t.jsx)(R.default,{objectPermission:ep.object_permission,variant:"inline",className:"pt-4 border-t border-gray-200",accessToken:$}),(0,t.jsx)(A.default,{loggingConfigs:(0,C.extractLoggingSettings)(ep.metadata),disabledCallbacks:Array.isArray(ep.metadata?.litellm_disabled_callbacks)?(0,w.mapInternalToDisplayNames)(ep.metadata.litellm_disabled_callbacks):[],variant:"inline",className:"pt-4 border-t border-gray-200"})]})]})})]})]})]})}e.s(["default",()=>es],20147)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/e99f98e7f34532c9.js b/litellm/proxy/_experimental/out/_next/static/chunks/40f766ecc87dbf9a.js similarity index 63% rename from litellm/proxy/_experimental/out/_next/static/chunks/e99f98e7f34532c9.js rename to litellm/proxy/_experimental/out/_next/static/chunks/40f766ecc87dbf9a.js index bd7488f525..faa3fae736 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/e99f98e7f34532c9.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/40f766ecc87dbf9a.js @@ -1 +1 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,56567,e=>{"use strict";var t=e.i(843476),a=e.i(135214),r=e.i(109799),l=e.i(907308),i=e.i(764205),s=e.i(500330),n=e.i(11751),o=e.i(708347),d=e.i(751904),m=e.i(827252),c=e.i(987432),u=e.i(530212),g=e.i(389083),h=e.i(304967),p=e.i(350967),x=e.i(599724),b=e.i(779241),f=e.i(629569),y=e.i(464571),_=e.i(808613),v=e.i(311451),j=e.i(998573),w=e.i(199133),C=e.i(790848),S=e.i(653496),k=e.i(592968),N=e.i(678784),T=e.i(118366),I=e.i(271645),M=e.i(9314),O=e.i(552130),z=e.i(127952);function E({className:e,value:a,onChange:r}){return(0,t.jsxs)(w.Select,{className:e,value:a,onChange:r,children:[(0,t.jsx)(w.Select.Option,{value:"24h",children:"Daily"}),(0,t.jsx)(w.Select.Option,{value:"7d",children:"Weekly"}),(0,t.jsx)(w.Select.Option,{value:"30d",children:"Monthly"})]})}var P=e.i(844565),D=e.i(355619),$=e.i(643449),F=e.i(75921),L=e.i(390605),A=e.i(162386),R=e.i(727749),B=e.i(384767),U=e.i(435451),V=e.i(916940),K=e.i(183588),q=e.i(276173),W=e.i(91979),H=e.i(269200),G=e.i(942232),Q=e.i(977572),X=e.i(427612),Y=e.i(64848),J=e.i(496020),Z=e.i(536916),ee=e.i(21548);let et={"/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","/team/daily/activity":"Member can view all team usage data (not just their own)"},ea=({teamId:e,accessToken:a,canEditTeam:r})=>{let[l,s]=(0,I.useState)([]),[n,o]=(0,I.useState)([]),[d,m]=(0,I.useState)(!0),[u,g]=(0,I.useState)(!1),[p,b]=(0,I.useState)(!1),_=async()=>{try{if(m(!0),!a)return;let t=await (0,i.getTeamPermissionsCall)(a,e),r=t.all_available_permissions||[];s(r);let l=t.team_member_permissions||[];o(l),b(!1)}catch(e){R.default.fromBackend("Failed to load permissions"),console.error("Error fetching permissions:",e)}finally{m(!1)}};(0,I.useEffect)(()=>{_()},[e,a]);let v=async()=>{try{if(!a)return;g(!0),await (0,i.teamPermissionsUpdateCall)(a,e,n),R.default.success("Permissions updated successfully"),b(!1)}catch(e){R.default.fromBackend("Failed to update permissions"),console.error("Error updating permissions:",e)}finally{g(!1)}};if(d)return(0,t.jsx)("div",{className:"p-6 text-center",children:"Loading permissions..."});let j=l.length>0;return(0,t.jsxs)(h.Card,{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)(f.Title,{className:"mb-2 sm:mb-0",children:"Member Permissions"}),r&&p&&(0,t.jsxs)("div",{className:"flex gap-3",children:[(0,t.jsx)(y.Button,{icon:(0,t.jsx)(W.ReloadOutlined,{}),onClick:()=>{_()},children:"Reset"}),(0,t.jsx)(y.Button,{onClick:v,loading:u,type:"primary",icon:(0,t.jsx)(c.SaveOutlined,{}),children:"Save Changes"})]})]}),(0,t.jsx)(x.Text,{className:"mb-6 text-gray-600",children:"Control what team members can do when they are not team admins."}),j?(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)(H.Table,{className:" min-w-full",children:[(0,t.jsx)(X.TableHead,{children:(0,t.jsxs)(J.TableRow,{children:[(0,t.jsx)(Y.TableHeaderCell,{children:"Method"}),(0,t.jsx)(Y.TableHeaderCell,{children:"Endpoint"}),(0,t.jsx)(Y.TableHeaderCell,{children:"Description"}),(0,t.jsx)(Y.TableHeaderCell,{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)(G.TableBody,{children:l.map(e=>{let a=(e=>{let t=e.includes("/info")||e.includes("/list")||e.includes("/activity")?"GET":"POST",a=et[e];if(!a){for(let[t,r]of Object.entries(et))if(e.includes(t)){a=r;break}}return a||(a=`Access ${e}`),{method:t,endpoint:e,description:a,route:e}})(e);return(0,t.jsxs)(J.TableRow,{className:"hover:bg-gray-50 transition-colors",children:[(0,t.jsx)(Q.TableCell,{children:(0,t.jsx)("span",{className:`px-2 py-1 rounded text-xs font-medium ${"GET"===a.method?"bg-blue-100 text-blue-800":"bg-green-100 text-green-800"}`,children:a.method})}),(0,t.jsx)(Q.TableCell,{children:(0,t.jsx)("span",{className:"font-mono text-sm text-gray-800",children:a.endpoint})}),(0,t.jsx)(Q.TableCell,{className:"text-gray-700",children:a.description}),(0,t.jsx)(Q.TableCell,{className:"sticky right-0 bg-white shadow-[-4px_0_4px_-4px_rgba(0,0,0,0.1)] text-center",children:(0,t.jsx)(Z.Checkbox,{checked:n.includes(e),onChange:t=>{o(t.target.checked?[...n,e]:n.filter(t=>t!==e)),b(!0)},disabled:!r})})]},e)})})]})}):(0,t.jsx)("div",{className:"py-12",children:(0,t.jsx)(ee.Empty,{description:"No permissions available"})})]})},er="overview",el="virtual-keys",ei="members",es="member-permissions",en="settings",eo={[er]:"Overview",[el]:"Virtual Keys",[ei]:"Members",[es]:"Member Permissions",[en]:"Settings"};var ed=e.i(292639),em=e.i(770914),ec=e.i(898586),eu=e.i(294612);function eg({teamData:e,canEditTeam:r,handleMemberDelete:l,setSelectedEditMember:i,setIsEditMemberModalVisible:n,setIsAddMemberModalVisible:d}){let c=e=>{if(null==e)return"0";if("number"==typeof e){let t=Number(e);return t===Math.floor(t)?t.toString():(0,s.formatNumberWithCommas)(t,8).replace(/\.?0+$/,"")}return"0"},{data:u}=(0,ed.useUISettings)(),{userId:g,userRole:h}=(0,a.default)(),p=!!u?.values?.disable_team_admin_delete_team_user,x=(0,o.isUserTeamAdminForSingleTeam)(e.team_info.members_with_roles,g||""),b=(0,o.isProxyAdminRole)(h||""),f=[{title:(0,t.jsxs)(em.Space,{direction:"horizontal",children:["Team Member Spend (USD)",(0,t.jsx)(k.Tooltip,{title:"This is the amount spent by a user in the team.",children:(0,t.jsx)(m.InfoCircleOutlined,{})})]}),key:"spend",render:(a,r)=>(0,t.jsxs)(ec.Typography.Text,{children:["$",(0,s.formatNumberWithCommas)((t=>{if(!t)return 0;let a=e.team_memberships.find(e=>e.user_id===t);return a?.spend||0})(r.user_id),4)]})},{title:"Team Member Budget (USD)",key:"budget",render:(a,r)=>{let l=(t=>{if(!t)return null;let a=e.team_memberships.find(e=>e.user_id===t),r=a?.litellm_budget_table?.max_budget;return null==r?null:c(r)})(r.user_id);return(0,t.jsx)(ec.Typography.Text,{children:l?`$${(0,s.formatNumberWithCommas)(Number(l),4)}`:"No Limit"})}},{title:(0,t.jsxs)(em.Space,{direction:"horizontal",children:["Team Member Rate Limits",(0,t.jsx)(k.Tooltip,{title:"Rate limits for this member's usage within this team.",children:(0,t.jsx)(m.InfoCircleOutlined,{})})]}),key:"rate_limits",render:(a,r)=>(0,t.jsx)(ec.Typography.Text,{children:(t=>{if(!t)return"No Limits";let a=e.team_memberships.find(e=>e.user_id===t),r=a?.litellm_budget_table?.rpm_limit,l=a?.litellm_budget_table?.tpm_limit,i=[r?`${c(r)} RPM`:null,l?`${c(l)} TPM`:null].filter(Boolean);return i.length>0?i.join(" / "):"No Limits"})(r.user_id)})}];return(0,t.jsx)(eu.default,{members:e.team_info.members_with_roles,canEdit:r,onEdit:t=>{let a=e.team_memberships.find(e=>e.user_id===t.user_id);i({...t,max_budget_in_team:a?.litellm_budget_table?.max_budget||null,tpm_limit:a?.litellm_budget_table?.tpm_limit||null,rpm_limit:a?.litellm_budget_table?.rpm_limit||null}),n(!0)},onDelete:l,onAddMember:()=>d(!0),roleColumnTitle:"Team Role",roleTooltip:"This role applies only to this team and is independent from the user's proxy-level role.",extraColumns:f,showDeleteForMember:()=>b||r&&!x||x&&!p})}var eh=e.i(207082),ep=e.i(871943),ex=e.i(502547),eb=e.i(360820),ef=e.i(94629),ey=e.i(152990),e_=e.i(682830),ev=e.i(994388),ej=e.i(752978),ew=e.i(282786),eC=e.i(981339),eS=e.i(969550),ek=e.i(20147),eN=e.i(266027),eT=e.i(633627);function eI({teamId:e,teamAlias:r,organization:l}){let{accessToken:i}=(0,a.default)(),[n,o]=(0,I.useState)(null),[d,c]=(0,I.useState)([{id:"created_at",desc:!0}]),[u,h]=(0,I.useState)({pageIndex:0,pageSize:50}),[p,b]=(0,I.useState)({"Organization ID":"","Key Alias":"","User ID":"","Sort By":"created_at","Sort Order":"desc"}),f=d.length>0?d[0].id:"created_at",y=d.length>0?d[0].desc?"desc":"asc":"desc",_=u.pageIndex,v=u.pageSize,{data:j,isPending:w,isFetching:C,refetch:S}=(0,eh.useKeys)(_+1,v,{teamID:e,organizationID:p["Organization ID"]?.trim()||void 0,selectedKeyAlias:p["Key Alias"]?.trim()||void 0,userID:p["User ID"]?.trim()||void 0,sortBy:f||void 0,sortOrder:y||void 0,expand:"user"}),N=(0,I.useMemo)(()=>{let e=j?.keys||[],t=l?.organization_id;return t?e.map(e=>({...e,organization_id:(e.organization_id??e.org_id)||t})):e},[j?.keys,l?.organization_id]),T=j?.total_pages??0,[M,O]=(0,I.useState)({}),z=(0,I.useMemo)(()=>({team_id:e,team_alias:r||e,models:[],max_budget:null,budget_duration:null,tpm_limit:null,rpm_limit:null,organization_id:l?.organization_id||"",created_at:"",keys:[],members_with_roles:[],spend:0}),[e,r,l]),E=(0,eN.useQuery)({queryKey:["teamFilterOptions",e,i],queryFn:async()=>(0,eT.fetchTeamFilterOptions)(i,e),enabled:!!i&&!!e,staleTime:3e4}).data||{keyAliases:[],organizationIds:[],userIds:[]},P=(0,I.useCallback)(()=>{S?.()},[S]);(0,I.useEffect)(()=>(window.addEventListener("storage",P),()=>window.removeEventListener("storage",P)),[P]);let $=(0,I.useCallback)((e,t=!1)=>{b(t=>({...t,"Organization ID":e["Organization ID"]??t["Organization ID"],"Key Alias":e["Key Alias"]??t["Key Alias"],"User ID":e["User ID"]??t["User ID"],"Sort By":e["Sort By"]??t["Sort By"]??"created_at","Sort Order":e["Sort Order"]??t["Sort Order"]??"desc"})),t||h(e=>({...e,pageIndex:0}))},[]),F=(0,I.useCallback)(()=>{b({"Organization ID":"","Key Alias":"","User ID":"","Sort By":"created_at","Sort Order":"desc"}),h(e=>({...e,pageIndex:0}))},[]),L=(0,I.useMemo)(()=>[{name:"Organization ID",label:"Organization ID",isSearchable:!0,searchFn:async e=>{let{organizationIds:t}=E;if(!t.length)return[];let a=e.toLowerCase();return(a?t.filter(e=>e.toLowerCase().includes(a)):t).map(e=>({label:e,value:e}))}},{name:"Key Alias",label:"Key Alias",isSearchable:!0,searchFn:async e=>{let{keyAliases:t}=E,a=e.toLowerCase();return(a?t.filter(e=>e.toLowerCase().includes(a)):t).map(e=>({label:e,value:e}))}},{name:"User ID",label:"User ID",isSearchable:!0,searchFn:async e=>{let{userIds:t}=E,a=e.toLowerCase();return(a?t.filter(e=>e.id.toLowerCase().includes(a)||e.email.toLowerCase().includes(a)):t).map(e=>({label:e.email?`${e.id} (${e.email})`:e.id,value:e.id}))}}],[E]),A=(0,I.useMemo)(()=>[{id:"token",accessorKey:"token",header:"Key ID",size:100,enableSorting:!0,cell:e=>{let a=e.getValue(),r=e.cell.column.getSize();return(0,t.jsx)(k.Tooltip,{title:a,children:(0,t.jsx)(ev.Button,{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 block",style:{maxWidth:r,overflow:"hidden"},onClick:()=>o(e.row.original),children:a??"-"})})}},{id:"key_alias",accessorKey:"key_alias",header:"Key Alias",size:150,enableSorting:!0,cell:e=>{let a=e.getValue(),r=e.cell.column.getSize();return(0,t.jsx)(k.Tooltip,{title:a,children:(0,t.jsx)("span",{className:"font-mono text-xs truncate block",style:{maxWidth:r,overflow:"hidden"},children:a??"-"})})}},{id:"key_name",accessorKey:"key_name",header:"Secret Key",size:120,enableSorting:!1,cell:e=>(0,t.jsx)("span",{className:"font-mono text-xs",children:e.getValue()})},{id:"organization_id",accessorKey:"organization_id",header:"Organization ID",size:140,enableSorting:!1,cell:e=>e.getValue()?e.renderValue():"-"},{id:"user_email",accessorKey:"user",header:"User Email",size:160,enableSorting:!1,cell:e=>{let a=e.getValue(),r=a?.user_email,l=e.cell.column.getSize();return(0,t.jsx)(k.Tooltip,{title:r,children:(0,t.jsx)("span",{className:"font-mono text-xs truncate block",style:{maxWidth:l,overflow:"hidden"},children:r??"-"})})}},{id:"user_id",accessorKey:"user_id",header:"User ID",size:70,enableSorting:!1,cell:e=>{let a=e.getValue(),r="default_user_id"===a?"Default Proxy Admin":a,l=e.cell.column.getSize();return(0,t.jsx)(k.Tooltip,{title:r,children:(0,t.jsx)("span",{className:"font-mono text-xs truncate block",style:{maxWidth:l,overflow:"hidden"},children:r??"-"})})}},{id:"created_at",accessorKey:"created_at",header:"Created At",size:120,enableSorting:!0,cell:e=>{let t=e.getValue();return t?new Date(t).toLocaleDateString():"-"}},{id:"created_by",accessorKey:"created_by",header:"Created By",size:70,enableSorting:!1,cell:e=>{let a=e.getValue(),r="default_user_id"===a?"Default Proxy Admin":a,l=e.cell.column.getSize();return(0,t.jsx)(k.Tooltip,{title:r,children:(0,t.jsx)("span",{className:"font-mono text-xs truncate block",style:{maxWidth:l,overflow:"hidden"},children:r??"-"})})}},{id:"updated_at",accessorKey:"updated_at",header:"Updated At",size:120,enableSorting:!0,cell:e=>{let t=e.getValue();return t?new Date(t).toLocaleDateString():"Never"}},{id:"last_active",accessorKey:"last_active",header:()=>(0,t.jsxs)("span",{className:"flex items-center gap-1",children:["Last Active",(0,t.jsx)(ew.Popover,{content:"This is a new field and is not backfilled. Only new key usage will update this value.",trigger:"hover",children:(0,t.jsx)(m.InfoCircleOutlined,{className:"text-gray-400 text-xs cursor-help"})})]}),size:130,enableSorting:!1,cell:e=>{let a=e.getValue();if(!a)return"Unknown";let r=new Date(a);return(0,t.jsx)(k.Tooltip,{title:r.toLocaleString(void 0,{dateStyle:"medium",timeStyle:"long"}),children:(0,t.jsx)("span",{children:r.toLocaleDateString()})})}},{id:"expires",accessorKey:"expires",header:"Expires",size:120,enableSorting:!1,cell:e=>{let t=e.getValue();return t?new Date(t).toLocaleDateString():"Never"}},{id:"spend",accessorKey:"spend",header:"Spend (USD)",size:100,enableSorting:!0,cell:e=>(0,s.formatNumberWithCommas)(e.getValue(),4)},{id:"max_budget",accessorKey:"max_budget",header:"Budget (USD)",size:110,enableSorting:!0,cell:e=>{let t=e.getValue();return null===t?"Unlimited":`$${(0,s.formatNumberWithCommas)(t)}`}},{id:"budget_reset_at",accessorKey:"budget_reset_at",header:"Budget Reset",size:130,enableSorting:!1,cell:e=>{let t=e.getValue();return t?new Date(t).toLocaleString():"Never"}},{id:"models",accessorKey:"models",header:"Models",size:200,enableSorting:!1,cell:e=>{let a=e.getValue();return(0,t.jsx)("div",{className:"flex flex-col py-2",children:Array.isArray(a)?(0,t.jsx)("div",{className:"flex flex-col",children:0===a.length?(0,t.jsx)(g.Badge,{size:"xs",className:"mb-1",color:"red",children:(0,t.jsx)(x.Text,{children:"All Proxy Models"})}):(0,t.jsx)(t.Fragment,{children:(0,t.jsxs)("div",{className:"flex items-start",children:[a.length>3&&(0,t.jsx)("div",{children:(0,t.jsx)(ej.Icon,{icon:M[e.row.id]?ep.ChevronDownIcon:ex.ChevronRightIcon,className:"cursor-pointer",size:"xs",onClick:()=>O(t=>({...t,[e.row.id]:!t[e.row.id]}))})}),(0,t.jsxs)("div",{className:"flex flex-wrap gap-1",children:[a.slice(0,3).map((e,a)=>"all-proxy-models"===e?(0,t.jsx)(g.Badge,{size:"xs",color:"red",children:(0,t.jsx)(x.Text,{children:"All Proxy Models"})},a):(0,t.jsx)(g.Badge,{size:"xs",color:"blue",children:(0,t.jsx)(x.Text,{children:e.length>30?`${(0,D.getModelDisplayName)(e).slice(0,30)}...`:(0,D.getModelDisplayName)(e)})},a)),a.length>3&&!M[e.row.id]&&(0,t.jsx)(g.Badge,{size:"xs",color:"gray",className:"cursor-pointer",children:(0,t.jsxs)(x.Text,{children:["+",a.length-3," ",a.length-3==1?"more model":"more models"]})}),M[e.row.id]&&(0,t.jsx)("div",{className:"flex flex-wrap gap-1",children:a.slice(3).map((e,a)=>"all-proxy-models"===e?(0,t.jsx)(g.Badge,{size:"xs",color:"red",children:(0,t.jsx)(x.Text,{children:"All Proxy Models"})},a+3):(0,t.jsx)(g.Badge,{size:"xs",color:"blue",children:(0,t.jsx)(x.Text,{children:e.length>30?`${(0,D.getModelDisplayName)(e).slice(0,30)}...`:(0,D.getModelDisplayName)(e)})},a+3))})]})]})})}):null})}},{id:"rate_limits",header:"Rate Limits",size:140,enableSorting:!1,cell:({row:e})=>{let a=e.original;return(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{children:["TPM: ",null!==a.tpm_limit?a.tpm_limit:"Unlimited"]}),(0,t.jsxs)("div",{children:["RPM: ",null!==a.rpm_limit?a.rpm_limit:"Unlimited"]})]})}}],[M]),R=(0,I.useCallback)(e=>{let t="function"==typeof e?e(d):e;if(c(t),t?.length>0){let e=t[0];$({"Sort By":e.id,"Sort Order":e.desc?"desc":"asc"},!0)}},[d,$]),B=(0,ey.useReactTable)({data:N,columns:A,columnResizeMode:"onChange",columnResizeDirection:"ltr",state:{sorting:d,pagination:u},onSortingChange:R,onPaginationChange:h,getCoreRowModel:(0,e_.getCoreRowModel)(),enableSorting:!0,manualSorting:!0,manualPagination:!0,pageCount:T});return(0,t.jsx)("div",{className:"w-full h-full overflow-hidden",children:n?(0,t.jsx)(ek.default,{keyId:n.token,onClose:()=>o(null),keyData:n,teams:[z],onDelete:S}):(0,t.jsxs)("div",{className:"border-b py-4 flex-1 overflow-hidden",children:[(0,t.jsx)("div",{className:"w-full mb-6",children:(0,t.jsx)(eS.default,{options:L,onApplyFilters:$,initialValues:p,onResetFilters:F})}),(0,t.jsx)("div",{className:"flex items-center justify-end w-full mb-4",children:(0,t.jsxs)("div",{className:"inline-flex items-center gap-2",children:[w||C?(0,t.jsx)(eC.Skeleton.Node,{active:!0,style:{width:74,height:20}}):(0,t.jsxs)("span",{className:"text-sm text-gray-700",children:["Page ",_+1," of ",B.getPageCount()]}),w||C?(0,t.jsx)(eC.Skeleton.Button,{active:!0,size:"small",style:{width:84,height:30}}):(0,t.jsx)("button",{onClick:()=>B.previousPage(),disabled:w||C||!B.getCanPreviousPage(),className:"px-3 py-1 text-sm border rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed",children:"Previous"}),w||C?(0,t.jsx)(eC.Skeleton.Button,{active:!0,size:"small",style:{width:58,height:30}}):(0,t.jsx)("button",{onClick:()=>B.nextPage(),disabled:w||C||!B.getCanNextPage(),className:"px-3 py-1 text-sm border rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed",children:"Next"})]})}),(0,t.jsx)("div",{className:"h-[75vh] overflow-auto",children:(0,t.jsx)("div",{className:"rounded-lg custom-border relative",children:(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)(H.Table,{className:"[&_td]:py-0.5 [&_th]:py-1",style:{width:B.getCenterTotalSize()},children:[(0,t.jsx)(X.TableHead,{children:B.getHeaderGroups().map(e=>(0,t.jsx)(J.TableRow,{children:e.headers.map(e=>(0,t.jsx)(Y.TableHeaderCell,{"data-header-id":e.id,className:`py-1 h-8 relative hover:bg-gray-50 ${"actions"===e.id?"sticky right-0 bg-white shadow-[-4px_0_8px_-6px_rgba(0,0,0,0.1)]":""}`,style:{width:e.getSize(),position:"relative",cursor:e.column.getCanSort()?"pointer":"default"},onMouseEnter:()=>{let t=document.querySelector(`[data-header-id="${e.id}"] .resizer`);t&&(t.style.opacity="0.5")},onMouseLeave:()=>{let t=document.querySelector(`[data-header-id="${e.id}"] .resizer`);t&&!e.column.getIsResizing()&&(t.style.opacity="0")},onClick:e.column.getCanSort()?e.column.getToggleSortingHandler():void 0,children:(0,t.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,t.jsx)("div",{className:"flex items-center",children:e.isPlaceholder?null:(0,ey.flexRender)(e.column.columnDef.header,e.getContext())}),"actions"!==e.id&&e.column.getCanSort()&&(0,t.jsx)("div",{className:"w-4",children:e.column.getIsSorted()?({asc:(0,t.jsx)(eb.ChevronUpIcon,{className:"h-4 w-4 text-blue-500"}),desc:(0,t.jsx)(ep.ChevronDownIcon,{className:"h-4 w-4 text-blue-500"})})[e.column.getIsSorted()]:(0,t.jsx)(ef.SwitchVerticalIcon,{className:"h-4 w-4 text-gray-400"})}),(0,t.jsx)("div",{onDoubleClick:()=>e.column.resetSize(),onMouseDown:e.getResizeHandler(),onTouchStart:e.getResizeHandler(),className:`resizer ${B.options.columnResizeDirection} ${e.column.getIsResizing()?"isResizing":""}`,style:{position:"absolute",right:0,top:0,height:"100%",width:"5px",background:e.column.getIsResizing()?"#3b82f6":"transparent",cursor:"col-resize",userSelect:"none",touchAction:"none",opacity:+!!e.column.getIsResizing()}})]})},e.id))},e.id))}),(0,t.jsx)(G.TableBody,{children:w||C?(0,t.jsx)(J.TableRow,{children:(0,t.jsx)(Q.TableCell,{colSpan:A.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"Loading keys..."})})})}):N.length>0?B.getRowModel().rows.map(e=>(0,t.jsx)(J.TableRow,{className:"h-8",children:e.getVisibleCells().map(e=>(0,t.jsx)(Q.TableCell,{style:{width:e.column.getSize(),maxWidth:"8-x",whiteSpace:"pre-wrap",overflow:"hidden"},className:`py-0.5 max-h-8 overflow-hidden text-ellipsis whitespace-nowrap ${"models"===e.column.id&&Array.isArray(e.getValue())&&e.getValue().length>3?"px-0":""}`,children:(0,ey.flexRender)(e.column.columnDef.cell,e.getContext())},e.id))},e.id)):(0,t.jsx)(J.TableRow,{children:(0,t.jsx)(Q.TableCell,{colSpan:A.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"No keys found"})})})})})]})})})})]})})}e.s(["default",0,({teamId:e,onClose:W,accessToken:H,is_team_admin:G,is_proxy_admin:Q,is_org_admin:X=!1,userModels:Y,editTeam:J,premiumUser:Z=!1,onUpdate:ee})=>{let[et,ed]=(0,I.useState)(null),[em,ec]=(0,I.useState)(!0),[eu,eh]=(0,I.useState)(!1),[ep]=_.Form.useForm(),[ex,eb]=(0,I.useState)(!1),[ef,ey]=(0,I.useState)(null),[e_,ev]=(0,I.useState)(!1),[ej,ew]=(0,I.useState)([]),[eC,eS]=(0,I.useState)(!1),[ek,eN]=(0,I.useState)({}),[eT,eM]=(0,I.useState)([]),[eO,ez]=(0,I.useState)([]),[eE,eP]=(0,I.useState)({}),[eD,e$]=(0,I.useState)(!1),[eF,eL]=(0,I.useState)(null),[eA,eR]=(0,I.useState)(!1),[eB,eU]=(0,I.useState)(!1),[eV,eK]=(0,I.useState)(!1),[eq,eW]=(0,I.useState)(null),{userRole:eH,userId:eG}=(0,a.default)(),{data:eQ=[]}=(0,r.useOrganizations)(),eX=(0,I.useMemo)(()=>{let e=et?.team_info?.organization_id;if(!e||!eG)return!1;let t=eQ.find(t=>t.organization_id===e);return t?.members?.some(e=>e.user_id===eG&&"org_admin"===e.user_role)??!1},[et,eQ,eG]),eY=G||Q||X||eX,eJ=(0,I.useMemo)(()=>{let e;return e=[er,el],eY?[...e,ei,es,en]:e},[eY]),eZ=(0,I.useMemo)(()=>J&&eY?en:er,[J,eY]),e0=async()=>{try{if(ec(!0),!H)return;let t=await (0,i.teamInfoCall)(H,e);ed(t)}catch(e){R.default.fromBackend("Failed to load team information"),console.error("Error fetching team info:",e)}finally{ec(!1)}};(0,I.useEffect)(()=>{e0()},[e,H]),(0,I.useEffect)(()=>{(async()=>{if(!H||!et?.team_info?.organization_id)return eW(null);try{let e=await (0,i.organizationInfoCall)(H,et.team_info.organization_id);eW(e)}catch(e){console.error("Error fetching organization info:",e),eW(null)}})()},[H,et?.team_info?.organization_id]),(0,I.useMemo)(()=>{let e;return e=[],e=eq?eq.models.includes("all-proxy-models")?Y:eq.models.length>0?eq.models:Y:Y,(0,D.unfurlWildcardModelsInList)(e,Y)},[eq,Y]),(0,I.useEffect)(()=>{let e=async()=>{try{if(!H)return;let e=(await (0,i.getPoliciesList)(H)).policies.map(e=>e.policy_name);ez(e)}catch(e){console.error("Failed to fetch policies:",e)}};(async()=>{try{if(!H)return;let e=(await (0,i.getGuardrailsList)(H)).guardrails.map(e=>e.guardrail_name);eM(e)}catch(e){console.error("Failed to fetch guardrails:",e)}})(),e()},[H]),(0,I.useEffect)(()=>{(async()=>{if(!H||!et?.team_info?.policies||0===et.team_info.policies.length)return;e$(!0);let e={};try{await Promise.all(et.team_info.policies.map(async t=>{try{let a=await (0,i.getPolicyInfoWithGuardrails)(H,t);e[t]=a.resolved_guardrails||[]}catch(a){console.error(`Failed to fetch guardrails for policy ${t}:`,a),e[t]=[]}})),eP(e)}catch(e){console.error("Failed to fetch policy guardrails:",e)}finally{e$(!1)}})()},[H,et?.team_info?.policies]);let e1=async t=>{try{if(null==H)return;let a={user_email:t.user_email,user_id:t.user_id,role:t.role};await (0,i.teamMemberAddCall)(H,e,a),R.default.success("Team member added successfully"),eh(!1),ep.resetFields();let r=await (0,i.teamInfoCall)(H,e);ed(r),ee(r)}catch(t){let e="Failed to add team member";t?.raw?.detail?.error?.includes("Assigning team admins is a premium feature")?e="Assigning admins is an enterprise-only feature. Please upgrade your LiteLLM plan to enable this.":t?.message&&(e=t.message),R.default.fromBackend(e),console.error("Error adding team member:",t)}},e2=async t=>{try{if(null==H)return;let a={user_email:t.user_email,user_id:t.user_id,role:t.role,max_budget_in_team:t.max_budget_in_team,tpm_limit:t.tpm_limit,rpm_limit:t.rpm_limit};j.message.destroy(),await (0,i.teamMemberUpdateCall)(H,e,a),R.default.success("Team member updated successfully"),eb(!1);let r=await (0,i.teamInfoCall)(H,e);ed(r),ee(r)}catch(t){let e="Failed to update team member";t?.raw?.detail?.includes("Assigning team admins is a premium feature")?e="Assigning admins is an enterprise-only feature. Please upgrade your LiteLLM plan to enable this.":t?.message&&(e=t.message),eb(!1),j.message.destroy(),R.default.fromBackend(e),console.error("Error updating team member:",t)}},e4=async()=>{if(eF&&H){eU(!0);try{await (0,i.teamMemberDeleteCall)(H,e,eF),R.default.success("Team member removed successfully");let t=await (0,i.teamInfoCall)(H,e);ed(t),ee(t)}catch(e){R.default.fromBackend("Failed to remove team member"),console.error("Error removing team member:",e)}finally{eU(!1),eR(!1),eL(null)}}},e5=async t=>{try{let a;if(!H)return;eK(!0);let r={};try{let{soft_budget_alerting_emails:e,...a}=t.metadata?JSON.parse(t.metadata):{};r=a}catch(e){R.default.fromBackend("Invalid JSON in metadata field");return}if("string"==typeof t.secret_manager_settings&&t.secret_manager_settings.trim().length>0)try{a=JSON.parse(t.secret_manager_settings)}catch(e){R.default.fromBackend("Invalid JSON in secret manager settings");return}let l=e=>null==e||"string"==typeof e&&""===e.trim()||"number"==typeof e&&Number.isNaN(e)?null:e,s={team_id:e,team_alias:t.team_alias,models:t.models,tpm_limit:l(t.tpm_limit),rpm_limit:l(t.rpm_limit),max_budget:t.max_budget,soft_budget:l(t.soft_budget),budget_duration:t.budget_duration,metadata:{...r,...t.guardrails?.length>0?{guardrails:t.guardrails}:{},...t.logging_settings?.length>0?{logging:t.logging_settings}:{},disable_global_guardrails:t.disable_global_guardrails||!1,soft_budget_alerting_emails:"string"==typeof t.soft_budget_alerting_emails?t.soft_budget_alerting_emails.split(",").map(e=>e.trim()).filter(e=>e.length>0):t.soft_budget_alerting_emails||[],...void 0!==a?{secret_manager_settings:a}:{}},...t.policies?.length>0?{policies:t.policies}:{},organization_id:t.organization_id};s.max_budget=(0,n.mapEmptyStringToNull)(s.max_budget),s.team_member_budget_duration=t.team_member_budget_duration,void 0!==t.team_member_budget&&(s.team_member_budget=Number(t.team_member_budget)),void 0!==t.team_member_key_duration&&(s.team_member_key_duration=t.team_member_key_duration),(void 0!==t.team_member_tpm_limit||void 0!==t.team_member_rpm_limit)&&(s.team_member_tpm_limit=l(t.team_member_tpm_limit),s.team_member_rpm_limit=l(t.team_member_rpm_limit));let{servers:o,accessGroups:d}=t.mcp_servers_and_groups||{servers:[],accessGroups:[]},m=new Set(o||[]),c=Object.fromEntries(Object.entries(t.mcp_tool_permissions||{}).filter(([e])=>m.has(e)));s.object_permission={},o&&(s.object_permission.mcp_servers=o),d&&(s.object_permission.mcp_access_groups=d),c&&(s.object_permission.mcp_tool_permissions=c),delete t.mcp_servers_and_groups,delete t.mcp_tool_permissions;let{agents:u,accessGroups:g}=t.agents_and_groups||{agents:[],accessGroups:[]};u&&u.length>0&&(s.object_permission.agents=u),g&&g.length>0&&(s.object_permission.agent_access_groups=g),delete t.agents_and_groups,t.vector_stores&&t.vector_stores.length>0&&(s.object_permission.vector_stores=t.vector_stores),void 0!==t.access_group_ids&&(s.access_group_ids=t.access_group_ids),await (0,i.teamUpdateCall)(H,s),R.default.success("Team settings updated successfully"),ev(!1),e0()}catch(e){console.error("Error updating team:",e)}finally{eK(!1)}};if(em)return(0,t.jsx)("div",{className:"p-4",children:"Loading..."});if(!et?.team_info)return(0,t.jsx)("div",{className:"p-4",children:"Team not found"});let{team_info:e7}=et,e6=async(e,t)=>{await (0,s.copyToClipboard)(e)&&(eN(e=>({...e,[t]:!0})),setTimeout(()=>{eN(e=>({...e,[t]:!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)(y.Button,{type:"text",icon:(0,t.jsx)(u.ArrowLeftIcon,{className:"h-4 w-4"}),onClick:W,className:"mb-4",children:"Back to Teams"}),(0,t.jsx)(f.Title,{children:e7.team_alias}),(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)(x.Text,{className:"text-gray-500 font-mono",children:e7.team_id}),(0,t.jsx)(y.Button,{type:"text",size:"small",icon:ek["team-id"]?(0,t.jsx)(N.CheckIcon,{size:12}):(0,t.jsx)(T.CopyIcon,{size:12}),onClick:()=>e6(e7.team_id,"team-id"),className:`left-2 z-10 transition-all duration-200 ${ek["team-id"]?"text-green-600 bg-green-50 border-green-200":"text-gray-500 hover:text-gray-700 hover:bg-gray-100"}`})]})]})}),(0,t.jsx)(S.Tabs,{defaultActiveKey:eZ,className:"mb-4",items:[{key:er,label:eo[er],children:(0,t.jsxs)(p.Grid,{numItems:1,numItemsSm:2,numItemsLg:3,className:"gap-6",children:[(0,t.jsxs)(h.Card,{children:[(0,t.jsx)(x.Text,{children:"Budget Status"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(f.Title,{children:["$",(0,s.formatNumberWithCommas)(e7.spend,4)]}),(0,t.jsxs)(x.Text,{children:["of ",null===e7.max_budget?"Unlimited":`$${(0,s.formatNumberWithCommas)(e7.max_budget,4)}`]}),e7.budget_duration&&(0,t.jsxs)(x.Text,{className:"text-gray-500",children:["Reset: ",e7.budget_duration]}),(0,t.jsx)("br",{}),e7.team_member_budget_table&&(0,t.jsxs)(x.Text,{className:"text-gray-500",children:["Team Member Budget: $",(0,s.formatNumberWithCommas)(e7.team_member_budget_table.max_budget,4)]})]})]}),(0,t.jsxs)(h.Card,{children:[(0,t.jsx)(x.Text,{children:"Rate Limits"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(x.Text,{children:["TPM: ",e7.tpm_limit||"Unlimited"]}),(0,t.jsxs)(x.Text,{children:["RPM: ",e7.rpm_limit||"Unlimited"]}),e7.max_parallel_requests&&(0,t.jsxs)(x.Text,{children:["Max Parallel Requests: ",e7.max_parallel_requests]})]})]}),(0,t.jsxs)(h.Card,{children:[(0,t.jsx)(x.Text,{children:"Models"}),(0,t.jsx)("div",{className:"mt-2 flex flex-wrap gap-2",children:0===e7.models.length?(0,t.jsx)(g.Badge,{color:"red",children:"All proxy models"}):e7.models.map((e,a)=>(0,t.jsx)(g.Badge,{color:"red",children:e},a))})]}),(0,t.jsxs)(h.Card,{children:[(0,t.jsx)(x.Text,{className:"font-semibold text-gray-900",children:"Virtual Keys"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(x.Text,{children:["User Keys: ",et.keys.filter(e=>e.user_id).length]}),(0,t.jsxs)(x.Text,{children:["Service Account Keys: ",et.keys.filter(e=>!e.user_id).length]}),(0,t.jsxs)(x.Text,{className:"text-gray-500",children:["Total: ",et.keys.length]})]})]}),(0,t.jsx)(B.default,{objectPermission:e7.object_permission,variant:"card",accessToken:H}),(0,t.jsxs)(h.Card,{children:[(0,t.jsx)(x.Text,{className:"font-semibold text-gray-900 mb-3",children:"Guardrails"}),e7.guardrails&&e7.guardrails.length>0?(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:e7.guardrails.map((e,a)=>(0,t.jsx)(g.Badge,{color:"blue",children:e},a))}):(0,t.jsx)(x.Text,{className:"text-gray-500",children:"No guardrails configured"}),e7.metadata?.disable_global_guardrails&&(0,t.jsx)("div",{className:"mt-3 pt-3 border-t border-gray-200",children:(0,t.jsx)(g.Badge,{color:"yellow",children:"Global Guardrails Disabled"})})]}),(0,t.jsxs)(h.Card,{children:[(0,t.jsx)(x.Text,{className:"font-semibold text-gray-900 mb-3",children:"Policies"}),e7.policies&&e7.policies.length>0?(0,t.jsx)("div",{className:"space-y-4",children:e7.policies.map((e,a)=>(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(g.Badge,{color:"purple",children:e}),eD&&(0,t.jsx)(x.Text,{className:"text-xs text-gray-400",children:"Loading guardrails..."})]}),!eD&&eE[e]&&eE[e].length>0&&(0,t.jsxs)("div",{className:"ml-4 pl-3 border-l-2 border-gray-200",children:[(0,t.jsx)(x.Text,{className:"text-xs text-gray-500 mb-1",children:"Resolved Guardrails:"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-1",children:eE[e].map((e,a)=>(0,t.jsx)(g.Badge,{color:"blue",size:"xs",children:e},a))})]})]},a))}):(0,t.jsx)(x.Text,{className:"text-gray-500",children:"No policies configured"})]}),(0,t.jsx)($.default,{loggingConfigs:e7.metadata?.logging||[],disabledCallbacks:[],variant:"card"})]})},{key:el,label:eo[el],children:(0,t.jsx)(eI,{teamId:e,teamAlias:e7.team_alias,organization:eq})},{key:ei,label:eo[ei],children:(0,t.jsx)(eg,{teamData:et,canEditTeam:eY,handleMemberDelete:e=>{eL(e),eR(!0)},setSelectedEditMember:ey,setIsEditMemberModalVisible:eb,setIsAddMemberModalVisible:eh})},{key:es,label:eo[es],children:(0,t.jsx)(ea,{teamId:e,accessToken:H,canEditTeam:eY})},{key:en,label:eo[en],children:(0,t.jsxs)(h.Card,{className:"overflow-y-auto max-h-[65vh]",children:[(0,t.jsxs)("div",{className:"flex justify-between items-center mb-4",children:[(0,t.jsx)(f.Title,{children:"Team Settings"}),eY&&!e_&&(0,t.jsx)(y.Button,{icon:(0,t.jsx)(d.EditOutlined,{className:"h-4 w-4"}),onClick:()=>ev(!0),children:"Edit Settings"})]}),e_?(0,t.jsxs)(_.Form,{form:ep,onFinish:e5,initialValues:{...e7,team_alias:e7.team_alias,models:e7.models,tpm_limit:e7.tpm_limit,rpm_limit:e7.rpm_limit,max_budget:e7.max_budget,soft_budget:e7.soft_budget,budget_duration:e7.budget_duration,team_member_tpm_limit:e7.team_member_budget_table?.tpm_limit,team_member_rpm_limit:e7.team_member_budget_table?.rpm_limit,team_member_budget:e7.team_member_budget_table?.max_budget,team_member_budget_duration:e7.team_member_budget_table?.budget_duration,guardrails:e7.metadata?.guardrails||[],policies:e7.policies||[],disable_global_guardrails:e7.metadata?.disable_global_guardrails||!1,soft_budget_alerting_emails:Array.isArray(e7.metadata?.soft_budget_alerting_emails)?e7.metadata.soft_budget_alerting_emails.join(", "):"",metadata:e7.metadata?JSON.stringify((({logging:e,secret_manager_settings:t,soft_budget_alerting_emails:a,...r})=>r)(e7.metadata),null,2):"",logging_settings:e7.metadata?.logging||[],secret_manager_settings:e7.metadata?.secret_manager_settings?JSON.stringify(e7.metadata.secret_manager_settings,null,2):"",organization_id:e7.organization_id,vector_stores:e7.object_permission?.vector_stores||[],mcp_servers:e7.object_permission?.mcp_servers||[],mcp_access_groups:e7.object_permission?.mcp_access_groups||[],mcp_servers_and_groups:{servers:e7.object_permission?.mcp_servers||[],accessGroups:e7.object_permission?.mcp_access_groups||[]},mcp_tool_permissions:e7.object_permission?.mcp_tool_permissions||{},agents_and_groups:{agents:e7.object_permission?.agents||[],accessGroups:e7.object_permission?.agent_access_groups||[]},access_group_ids:e7.access_group_ids||[]},layout:"vertical",children:[(0,t.jsx)(_.Form.Item,{label:"Team Name",name:"team_alias",rules:[{required:!0,message:"Please input a team name"}],children:(0,t.jsx)(v.Input,{type:""})}),(0,t.jsx)(_.Form.Item,{label:"Models",name:"models",rules:[{required:!0,message:"Please select at least one model"}],children:(0,t.jsx)(A.ModelSelect,{value:ep.getFieldValue("models")||[],onChange:e=>ep.setFieldValue("models",e),teamID:e,organizationID:et?.team_info?.organization_id||void 0,options:{includeSpecialOptions:!0,includeUserModels:!et?.team_info?.organization_id,showAllProxyModelsOverride:(0,o.isProxyAdminRole)(eH)&&!et?.team_info?.organization_id},context:"team",dataTestId:"models-select"})}),(0,t.jsx)(_.Form.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,t.jsx)(U.default,{step:.01,precision:2,style:{width:"100%"}})}),(0,t.jsx)(_.Form.Item,{label:"Soft Budget (USD)",name:"soft_budget",children:(0,t.jsx)(U.default,{step:.01,precision:2,style:{width:"100%"}})}),(0,t.jsx)(_.Form.Item,{label:"Soft Budget Alerting Emails",name:"soft_budget_alerting_emails",tooltip:"Comma-separated email addresses to receive alerts when the soft budget is reached",children:(0,t.jsx)(v.Input,{placeholder:"example1@test.com, example2@test.com"})}),(0,t.jsx)(_.Form.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)(U.default,{step:.01,precision:2,style:{width:"100%"}})}),(0,t.jsx)(_.Form.Item,{label:"Team Member Budget Duration",name:"team_member_budget_duration",children:(0,t.jsx)(E,{onChange:e=>ep.setFieldValue("team_member_budget_duration",e),value:ep.getFieldValue("team_member_budget_duration")})}),(0,t.jsx)(_.Form.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)(b.TextInput,{placeholder:"e.g., 30d"})}),(0,t.jsx)(_.Form.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)(U.default,{step:1,style:{width:"100%"},placeholder:"e.g., 1000"})}),(0,t.jsx)(_.Form.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)(U.default,{step:1,style:{width:"100%"},placeholder:"e.g., 100"})}),(0,t.jsx)(_.Form.Item,{label:"Reset Budget",name:"budget_duration",children:(0,t.jsxs)(w.Select,{placeholder:"n/a",children:[(0,t.jsx)(w.Select.Option,{value:"24h",children:"daily"}),(0,t.jsx)(w.Select.Option,{value:"7d",children:"weekly"}),(0,t.jsx)(w.Select.Option,{value:"30d",children:"monthly"})]})}),(0,t.jsx)(_.Form.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,t.jsx)(U.default,{step:1,style:{width:"100%"}})}),(0,t.jsx)(_.Form.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,t.jsx)(U.default,{step:1,style:{width:"100%"}})}),(0,t.jsx)(_.Form.Item,{label:(0,t.jsxs)("span",{children:["Guardrails"," ",(0,t.jsx)(k.Tooltip,{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.InfoCircleOutlined,{style:{marginLeft:"4px"}})})})]}),name:"guardrails",help:"Select existing guardrails or enter new ones",children:(0,t.jsx)(w.Select,{mode:"tags",placeholder:"Select or enter guardrails",options:eT.map(e=>({value:e,label:e}))})}),(0,t.jsx)(_.Form.Item,{label:(0,t.jsxs)("span",{children:["Disable Global Guardrails",(0,t.jsx)(k.Tooltip,{title:"When enabled, this team will bypass any guardrails configured to run on every request (global guardrails)",children:(0,t.jsx)(m.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"disable_global_guardrails",valuePropName:"checked",help:"Bypass global guardrails for this team",children:(0,t.jsx)(C.Switch,{checkedChildren:"Yes",unCheckedChildren:"No"})}),(0,t.jsx)(_.Form.Item,{label:(0,t.jsxs)("span",{children:["Policies"," ",(0,t.jsx)(k.Tooltip,{title:"Apply policies to this team to control guardrails and other settings",children:(0,t.jsx)("a",{href:"https://docs.litellm.ai/docs/proxy/guardrails/guardrail_policies",target:"_blank",rel:"noopener noreferrer",onClick:e=>e.stopPropagation(),children:(0,t.jsx)(m.InfoCircleOutlined,{style:{marginLeft:"4px"}})})})]}),name:"policies",help:"Select existing policies or enter new ones",children:(0,t.jsx)(w.Select,{mode:"tags",placeholder:"Select or enter policies",options:eO.map(e=>({value:e,label:e}))})}),(0,t.jsx)(_.Form.Item,{label:(0,t.jsxs)("span",{children:["Access Groups"," ",(0,t.jsx)(k.Tooltip,{title:"Assign access groups to this team. Access groups control which models, MCP servers, and agents this team can use",children:(0,t.jsx)(m.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"access_group_ids",children:(0,t.jsx)(M.default,{placeholder:"Select access groups (optional)"})}),(0,t.jsx)(_.Form.Item,{label:"Vector Stores",name:"vector_stores","aria-label":"Vector Stores",children:(0,t.jsx)(V.default,{onChange:e=>ep.setFieldValue("vector_stores",e),value:ep.getFieldValue("vector_stores"),accessToken:H||"",placeholder:"Select vector stores"})}),(0,t.jsx)(_.Form.Item,{label:"Allowed Pass Through Routes",name:"allowed_passthrough_routes",children:(0,t.jsx)(P.default,{onChange:e=>ep.setFieldValue("allowed_passthrough_routes",e),value:ep.getFieldValue("allowed_passthrough_routes"),accessToken:H||"",placeholder:"Select pass through routes"})}),(0,t.jsx)(_.Form.Item,{label:"MCP Servers / Access Groups",name:"mcp_servers_and_groups",children:(0,t.jsx)(F.default,{onChange:e=>ep.setFieldValue("mcp_servers_and_groups",e),value:ep.getFieldValue("mcp_servers_and_groups"),accessToken:H||"",placeholder:"Select MCP servers or access groups (optional)"})}),(0,t.jsx)(_.Form.Item,{name:"mcp_tool_permissions",initialValue:{},hidden:!0,children:(0,t.jsx)(v.Input,{type:"hidden"})}),(0,t.jsx)(_.Form.Item,{noStyle:!0,shouldUpdate:(e,t)=>e.mcp_servers_and_groups!==t.mcp_servers_and_groups||e.mcp_tool_permissions!==t.mcp_tool_permissions,children:()=>(0,t.jsx)("div",{className:"mb-6",children:(0,t.jsx)(L.default,{accessToken:H||"",selectedServers:ep.getFieldValue("mcp_servers_and_groups")?.servers||[],toolPermissions:ep.getFieldValue("mcp_tool_permissions")||{},onChange:e=>ep.setFieldsValue({mcp_tool_permissions:e})})})}),(0,t.jsx)(_.Form.Item,{label:"Agents / Access Groups",name:"agents_and_groups",children:(0,t.jsx)(O.default,{onChange:e=>ep.setFieldValue("agents_and_groups",e),value:ep.getFieldValue("agents_and_groups"),accessToken:H||"",placeholder:"Select agents or access groups (optional)"})}),(0,t.jsx)(_.Form.Item,{label:"Organization ID",name:"organization_id",children:(0,t.jsx)(v.Input,{type:"",disabled:!0})}),(0,t.jsx)(_.Form.Item,{label:"Logging Settings",name:"logging_settings",children:(0,t.jsx)(K.default,{value:ep.getFieldValue("logging_settings"),onChange:e=>ep.setFieldValue("logging_settings",e)})}),(0,t.jsx)(_.Form.Item,{label:"Secret Manager Settings",name:"secret_manager_settings",help:Z?"Enter secret manager configuration as a JSON object.":"Premium feature - Upgrade to manage secret manager settings.",rules:[{validator:async(e,t)=>{if(!t)return Promise.resolve();try{return JSON.parse(t),Promise.resolve()}catch(e){return Promise.reject(Error("Please enter valid JSON"))}}}],children:(0,t.jsx)(v.Input.TextArea,{rows:6,placeholder:'{"namespace": "admin", "mount": "secret", "path_prefix": "litellm"}',disabled:!Z})}),(0,t.jsx)(_.Form.Item,{label:"Metadata",name:"metadata",children:(0,t.jsx)(v.Input.TextArea,{rows:10})}),(0,t.jsx)("div",{className:"sticky z-10 bg-white p-4 pr-0 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)(y.Button,{onClick:()=>ev(!1),disabled:eV,children:"Cancel"}),(0,t.jsx)(y.Button,{icon:(0,t.jsx)(c.SaveOutlined,{className:"h-4 w-4"}),type:"primary",htmlType:"submit",loading:eV,children:"Save Changes"})]})})]}):(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Team Name"}),(0,t.jsx)("div",{children:e7.team_alias})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Team ID"}),(0,t.jsx)("div",{className:"font-mono",children:e7.team_id})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Created At"}),(0,t.jsx)("div",{children:new Date(e7.created_at).toLocaleString()})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Models"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:e7.models.map((e,a)=>(0,t.jsx)(g.Badge,{color:"red",children:e},a))})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Rate Limits"}),(0,t.jsxs)("div",{children:["TPM: ",e7.tpm_limit||"Unlimited"]}),(0,t.jsxs)("div",{children:["RPM: ",e7.rpm_limit||"Unlimited"]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Team Budget"}),(0,t.jsxs)("div",{children:["Max Budget:"," ",null!==e7.max_budget?`$${(0,s.formatNumberWithCommas)(e7.max_budget,4)}`:"No Limit"]}),(0,t.jsxs)("div",{children:["Soft Budget:"," ",null!==e7.soft_budget&&void 0!==e7.soft_budget?`$${(0,s.formatNumberWithCommas)(e7.soft_budget,4)}`:"No Limit"]}),(0,t.jsxs)("div",{children:["Budget Reset: ",e7.budget_duration||"Never"]}),e7.metadata?.soft_budget_alerting_emails&&Array.isArray(e7.metadata.soft_budget_alerting_emails)&&e7.metadata.soft_budget_alerting_emails.length>0&&(0,t.jsxs)("div",{children:["Soft Budget Alerting Emails: ",e7.metadata.soft_budget_alerting_emails.join(", ")]})]}),(0,t.jsxs)("div",{children:[(0,t.jsxs)(x.Text,{className:"font-medium",children:["Team Member Settings"," ",(0,t.jsx)(k.Tooltip,{title:"These are limits on individual team members",children:(0,t.jsx)(m.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),(0,t.jsxs)("div",{children:["Max Budget: ",e7.team_member_budget_table?.max_budget||"No Limit"]}),(0,t.jsxs)("div",{children:["Budget Duration: ",e7.team_member_budget_table?.budget_duration||"No Limit"]}),(0,t.jsxs)("div",{children:["Key Duration: ",e7.metadata?.team_member_key_duration||"No Limit"]}),(0,t.jsxs)("div",{children:["TPM Limit: ",e7.team_member_budget_table?.tpm_limit||"No Limit"]}),(0,t.jsxs)("div",{children:["RPM Limit: ",e7.team_member_budget_table?.rpm_limit||"No Limit"]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Organization ID"}),(0,t.jsx)("div",{children:e7.organization_id})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Status"}),(0,t.jsx)(g.Badge,{color:e7.blocked?"red":"green",children:e7.blocked?"Blocked":"Active"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Disable Global Guardrails"}),(0,t.jsx)("div",{children:e7.metadata?.disable_global_guardrails===!0?(0,t.jsx)(g.Badge,{color:"yellow",children:"Enabled - Global guardrails bypassed"}):(0,t.jsx)(g.Badge,{color:"green",children:"Disabled - Global guardrails active"})})]}),(0,t.jsx)(B.default,{objectPermission:e7.object_permission,variant:"inline",className:"pt-4 border-t border-gray-200",accessToken:H}),(0,t.jsx)($.default,{loggingConfigs:e7.metadata?.logging||[],disabledCallbacks:[],variant:"inline",className:"pt-4 border-t border-gray-200"}),e7.metadata?.secret_manager_settings&&(0,t.jsxs)("div",{className:"pt-4 border-t border-gray-200",children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Secret Manager Settings"}),(0,t.jsx)("pre",{className:"mt-2 bg-gray-50 p-3 rounded text-xs overflow-x-auto",children:JSON.stringify(e7.metadata.secret_manager_settings,null,2)})]})]})]})}].filter(e=>eJ.includes(e.key))}),(0,t.jsx)(q.default,{visible:ex,onCancel:()=>eb(!1),onSubmit:e2,initialData:ef,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)(k.Tooltip,{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.InfoCircleOutlined,{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)(k.Tooltip,{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.InfoCircleOutlined,{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)(k.Tooltip,{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.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),type:"numerical",step:1,min:0,placeholder:"Requests per minute limit for this member in this team"}]}}),(0,t.jsx)(l.default,{isVisible:eu,onCancel:()=>eh(!1),onSubmit:e1,accessToken:H,teamId:e}),(0,t.jsx)(z.default,{isOpen:eA,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:eF?.user_id,code:!0},{label:"Email",value:eF?.user_email},{label:"Role",value:eF?.role}],onCancel:()=>{eR(!1),eL(null)},onOk:e4,confirmLoading:eB})]})}],56567)},829672,836938,310730,e=>{"use strict";e.i(247167);var t=e.i(271645),a=e.i(343794),r=e.i(914949),l=e.i(404948);let i=e=>e?"function"==typeof e?e():e:null;e.s(["getRenderPropValue",0,i],836938);var s=e.i(613541),n=e.i(763731),o=e.i(242064),d=e.i(491816);e.i(793154);var m=e.i(880476),c=e.i(183293),u=e.i(717356),g=e.i(320560),h=e.i(307358),p=e.i(246422),x=e.i(838378),b=e.i(617933);let f=(0,p.genStyleHooks)("Popover",e=>{let{colorBgElevated:t,colorText:a}=e,r=(0,x.mergeToken)(e,{popoverBg:t,popoverColor:a});return[(e=>{let{componentCls:t,popoverColor:a,titleMinWidth:r,fontWeightStrong:l,innerPadding:i,boxShadowSecondary:s,colorTextHeading:n,borderRadiusLG:o,zIndexPopup:d,titleMarginBottom:m,colorBgElevated:u,popoverBg:h,titleBorderBottom:p,innerContentPadding:x,titlePadding:b}=e;return[{[t]:Object.assign(Object.assign({},(0,c.resetComponent)(e)),{position:"absolute",top:0,left:{_skip_check_:!0,value:0},zIndex:d,fontWeight:"normal",whiteSpace:"normal",textAlign:"start",cursor:"auto",userSelect:"text","--valid-offset-x":"var(--arrow-offset-horizontal, var(--arrow-x))",transformOrigin:"var(--valid-offset-x, 50%) var(--arrow-y, 50%)","--antd-arrow-background-color":u,width:"max-content",maxWidth:"100vw","&-rtl":{direction:"rtl"},"&-hidden":{display:"none"},[`${t}-content`]:{position:"relative"},[`${t}-inner`]:{backgroundColor:h,backgroundClip:"padding-box",borderRadius:o,boxShadow:s,padding:i},[`${t}-title`]:{minWidth:r,marginBottom:m,color:n,fontWeight:l,borderBottom:p,padding:b},[`${t}-inner-content`]:{color:a,padding:x}})},(0,g.default)(e,"var(--antd-arrow-background-color)"),{[`${t}-pure`]:{position:"relative",maxWidth:"none",margin:e.sizePopupArrow,display:"inline-block",[`${t}-content`]:{display:"inline-block"}}}]})(r),(e=>{let{componentCls:t}=e;return{[t]:b.PresetColors.map(a=>{let r=e[`${a}6`];return{[`&${t}-${a}`]:{"--antd-arrow-background-color":r,[`${t}-inner`]:{backgroundColor:r},[`${t}-arrow`]:{background:"transparent"}}}})}})(r),(0,u.initZoomMotion)(r,"zoom-big")]},e=>{let{lineWidth:t,controlHeight:a,fontHeight:r,padding:l,wireframe:i,zIndexPopupBase:s,borderRadiusLG:n,marginXS:o,lineType:d,colorSplit:m,paddingSM:c}=e,u=a-r;return Object.assign(Object.assign(Object.assign({titleMinWidth:177,zIndexPopup:s+30},(0,h.getArrowToken)(e)),(0,g.getArrowOffsetToken)({contentRadius:n,limitVerticalRadius:!0})),{innerPadding:12*!i,titleMarginBottom:i?0:o,titlePadding:i?`${u/2}px ${l}px ${u/2-t}px`:0,titleBorderBottom:i?`${t}px ${d} ${m}`:"none",innerContentPadding:i?`${c}px ${l}px`:0})},{resetStyle:!1,deprecatedTokens:[["width","titleMinWidth"],["minWidth","titleMinWidth"]]});var y=function(e,t){var a={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(a[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,r=Object.getOwnPropertySymbols(e);lt.indexOf(r[l])&&Object.prototype.propertyIsEnumerable.call(e,r[l])&&(a[r[l]]=e[r[l]]);return a};let _=({title:e,content:a,prefixCls:r})=>e||a?t.createElement(t.Fragment,null,e&&t.createElement("div",{className:`${r}-title`},e),a&&t.createElement("div",{className:`${r}-inner-content`},a)):null,v=e=>{let{hashId:r,prefixCls:l,className:s,style:n,placement:o="top",title:d,content:c,children:u}=e,g=i(d),h=i(c),p=(0,a.default)(r,l,`${l}-pure`,`${l}-placement-${o}`,s);return t.createElement("div",{className:p,style:n},t.createElement("div",{className:`${l}-arrow`}),t.createElement(m.Popup,Object.assign({},e,{className:r,prefixCls:l}),u||t.createElement(_,{prefixCls:l,title:g,content:h})))},j=e=>{let{prefixCls:r,className:l}=e,i=y(e,["prefixCls","className"]),{getPrefixCls:s}=t.useContext(o.ConfigContext),n=s("popover",r),[d,m,c]=f(n);return d(t.createElement(v,Object.assign({},i,{prefixCls:n,hashId:m,className:(0,a.default)(l,c)})))};e.s(["Overlay",0,_,"default",0,j],310730);var w=function(e,t){var a={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(a[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,r=Object.getOwnPropertySymbols(e);lt.indexOf(r[l])&&Object.prototype.propertyIsEnumerable.call(e,r[l])&&(a[r[l]]=e[r[l]]);return a};let C=t.forwardRef((e,m)=>{var c,u;let{prefixCls:g,title:h,content:p,overlayClassName:x,placement:b="top",trigger:y="hover",children:v,mouseEnterDelay:j=.1,mouseLeaveDelay:C=.1,onOpenChange:S,overlayStyle:k={},styles:N,classNames:T}=e,I=w(e,["prefixCls","title","content","overlayClassName","placement","trigger","children","mouseEnterDelay","mouseLeaveDelay","onOpenChange","overlayStyle","styles","classNames"]),{getPrefixCls:M,className:O,style:z,classNames:E,styles:P}=(0,o.useComponentConfig)("popover"),D=M("popover",g),[$,F,L]=f(D),A=M(),R=(0,a.default)(x,F,L,O,E.root,null==T?void 0:T.root),B=(0,a.default)(E.body,null==T?void 0:T.body),[U,V]=(0,r.default)(!1,{value:null!=(c=e.open)?c:e.visible,defaultValue:null!=(u=e.defaultOpen)?u:e.defaultVisible}),K=(e,t)=>{V(e,!0),null==S||S(e,t)},q=i(h),W=i(p);return $(t.createElement(d.default,Object.assign({placement:b,trigger:y,mouseEnterDelay:j,mouseLeaveDelay:C},I,{prefixCls:D,classNames:{root:R,body:B},styles:{root:Object.assign(Object.assign(Object.assign(Object.assign({},P.root),z),k),null==N?void 0:N.root),body:Object.assign(Object.assign({},P.body),null==N?void 0:N.body)},ref:m,open:U,onOpenChange:e=>{K(e)},overlay:q||W?t.createElement(_,{prefixCls:D,title:q,content:W}):null,transitionName:(0,s.getTransitionName)(A,"zoom-big",I.transitionName),"data-popover-inject":!0}),(0,n.cloneElement)(v,{onKeyDown:e=>{var a,r;(0,t.isValidElement)(v)&&(null==(r=null==v?void 0:(a=v.props).onKeyDown)||r.call(a,e)),e.keyCode===l.default.ESC&&K(!1,e)}})))});C._InternalPanelDoNotUseOrYouWillBeFired=j,e.s(["default",0,C],829672)},282786,e=>{"use strict";var t=e.i(829672);e.s(["Popover",()=>t.default])},751904,e=>{"use strict";var t=e.i(401361);e.s(["EditOutlined",()=>t.default])},434626,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"}))});e.s(["ExternalLinkIcon",0,a],434626)},902555,e=>{"use strict";var t=e.i(843476),a=e.i(591935),r=e.i(122577),l=e.i(278587),i=e.i(68155),s=e.i(360820),n=e.i(871943),o=e.i(434626),d=e.i(592968),m=e.i(115504),c=e.i(752978);function u({icon:e,onClick:a,className:r,disabled:l,dataTestId:i}){return l?(0,t.jsx)(c.Icon,{icon:e,size:"sm",className:"opacity-50 cursor-not-allowed","data-testid":i}):(0,t.jsx)(c.Icon,{icon:e,size:"sm",onClick:a,className:(0,m.cx)("cursor-pointer",r),"data-testid":i})}let g={Edit:{icon:a.PencilAltIcon,className:"hover:text-blue-600"},Delete:{icon:i.TrashIcon,className:"hover:text-red-600"},Test:{icon:r.PlayIcon,className:"hover:text-blue-600"},Regenerate:{icon:l.RefreshIcon,className:"hover:text-green-600"},Up:{icon:s.ChevronUpIcon,className:"hover:text-blue-600"},Down:{icon:n.ChevronDownIcon,className:"hover:text-blue-600"},Open:{icon:o.ExternalLinkIcon,className:"hover:text-green-600"}};function h({onClick:e,tooltipText:a,disabled:r=!1,disabledTooltipText:l,dataTestId:i,variant:s}){let{icon:n,className:o}=g[s];return(0,t.jsx)(d.Tooltip,{title:r?l:a,children:(0,t.jsx)("span",{children:(0,t.jsx)(u,{icon:n,onClick:e,className:o,disabled:r,dataTestId:i})})})}e.s(["default",()=>h],902555)},122577,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.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"}),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M21 12a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlayIcon",0,a],122577)},278587,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"}))});e.s(["RefreshIcon",0,a],278587)},207670,e=>{"use strict";function t(){for(var e,t,a=0,r="",l=arguments.length;at,"default",0,t])},728889,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(829087),l=e.i(480731),i=e.i(444755),s=e.i(673706),n=e.i(95779);let o={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"}},d={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:""}},c=(0,s.makeClassName)("Icon"),u=a.default.forwardRef((e,u)=>{let{icon:g,variant:h="simple",tooltip:p,size:x=l.Sizes.SM,color:b,className:f}=e,y=(0,t.__rest)(e,["icon","variant","tooltip","size","color","className"]),_=((e,t)=>{switch(e){case"simple":return{textColor:t?(0,s.getColorClassNames)(t,n.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:"",borderColor:"",ringColor:""};case"light":return{textColor:t?(0,s.getColorClassNames)(t,n.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:t?(0,i.tremorTwMerge)((0,s.getColorClassNames)(t,n.colorPalette.background).bgColor,"bg-opacity-20"):"bg-tremor-brand-muted dark:bg-dark-tremor-brand-muted",borderColor:"",ringColor:""};case"shadow":return{textColor:t?(0,s.getColorClassNames)(t,n.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:t?(0,i.tremorTwMerge)((0,s.getColorClassNames)(t,n.colorPalette.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:t?(0,s.getColorClassNames)(t,n.colorPalette.text).textColor:"text-tremor-brand-inverted dark:text-dark-tremor-brand-inverted",bgColor:t?(0,i.tremorTwMerge)((0,s.getColorClassNames)(t,n.colorPalette.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:t?(0,s.getColorClassNames)(t,n.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:t?(0,i.tremorTwMerge)((0,s.getColorClassNames)(t,n.colorPalette.background).bgColor,"bg-opacity-20"):"bg-tremor-background dark:bg-dark-tremor-background",borderColor:t?(0,s.getColorClassNames)(t,n.colorPalette.ring).borderColor:"border-tremor-brand-subtle dark:border-dark-tremor-brand-subtle",ringColor:t?(0,i.tremorTwMerge)((0,s.getColorClassNames)(t,n.colorPalette.ring).ringColor,"ring-opacity-40"):"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"}}})(h,b),{tooltipProps:v,getReferenceProps:j}=(0,r.useTooltip)();return a.default.createElement("span",Object.assign({ref:(0,s.mergeRefs)([u,v.refs.setReference]),className:(0,i.tremorTwMerge)(c("root"),"inline-flex shrink-0 items-center justify-center",_.bgColor,_.textColor,_.borderColor,_.ringColor,m[h].rounded,m[h].border,m[h].shadow,m[h].ring,o[x].paddingX,o[x].paddingY,f)},j,y),a.default.createElement(r.default,Object.assign({text:p},v)),a.default.createElement(g,{className:(0,i.tremorTwMerge)(c("icon"),"shrink-0",d[x].height,d[x].width)}))});u.displayName="Icon",e.s(["default",()=>u],728889)},752978,e=>{"use strict";var t=e.i(728889);e.s(["Icon",()=>t.default])},591935,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"}))});e.s(["PencilAltIcon",0,a],591935)},100486,e=>{"use strict";e.i(247167);var t=e.i(931067),a=e.i(271645);let r={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M899.6 276.5L705 396.4 518.4 147.5a8.06 8.06 0 00-12.9 0L319 396.4 124.3 276.5c-5.7-3.5-13.1 1.2-12.2 7.9L188.5 865c1.1 7.9 7.9 14 16 14h615.1c8 0 14.9-6 15.9-14l76.4-580.6c.8-6.7-6.5-11.4-12.3-7.9zm-126 534.1H250.3l-53.8-409.4 139.8 86.1L512 252.9l175.7 234.4 139.8-86.1-53.9 409.4zM512 509c-62.1 0-112.6 50.5-112.6 112.6S449.9 734.2 512 734.2s112.6-50.5 112.6-112.6S574.1 509 512 509zm0 160.9c-26.6 0-48.2-21.6-48.2-48.3 0-26.6 21.6-48.3 48.2-48.3s48.2 21.6 48.2 48.3c0 26.6-21.6 48.3-48.2 48.3z"}}]},name:"crown",theme:"outlined"};var l=e.i(9583),i=a.forwardRef(function(e,i){return a.createElement(l.default,(0,t.default)({},e,{ref:i,icon:r}))});e.s(["CrownOutlined",0,i],100486)},621482,e=>{"use strict";var t=e.i(869230),a=e.i(992571),r=class extends t.QueryObserver{constructor(e,t){super(e,t)}bindMethods(){super.bindMethods(),this.fetchNextPage=this.fetchNextPage.bind(this),this.fetchPreviousPage=this.fetchPreviousPage.bind(this)}setOptions(e){super.setOptions({...e,behavior:(0,a.infiniteQueryBehavior)()})}getOptimisticResult(e){return e.behavior=(0,a.infiniteQueryBehavior)(),super.getOptimisticResult(e)}fetchNextPage(e){return this.fetch({...e,meta:{fetchMore:{direction:"forward"}}})}fetchPreviousPage(e){return this.fetch({...e,meta:{fetchMore:{direction:"backward"}}})}createResult(e,t){let{state:r}=e,l=super.createResult(e,t),{isFetching:i,isRefetching:s,isError:n,isRefetchError:o}=l,d=r.fetchMeta?.fetchMore?.direction,m=n&&"forward"===d,c=i&&"forward"===d,u=n&&"backward"===d,g=i&&"backward"===d;return{...l,fetchNextPage:this.fetchNextPage,fetchPreviousPage:this.fetchPreviousPage,hasNextPage:(0,a.hasNextPage)(t,r.data),hasPreviousPage:(0,a.hasPreviousPage)(t,r.data),isFetchNextPageError:m,isFetchingNextPage:c,isFetchPreviousPageError:u,isFetchingPreviousPage:g,isRefetchError:o&&!m&&!u,isRefetching:s&&!c&&!g}}},l=e.i(469637);function i(e,t){return(0,l.useBaseQuery)(e,r,t)}e.s(["useInfiniteQuery",()=>i],621482)},785242,e=>{"use strict";var t=e.i(619273),a=e.i(266027),r=e.i(912598),l=e.i(135214),i=e.i(270345),s=e.i(243652),n=e.i(764205);let o=(0,s.createQueryKeys)("teams"),d=async(e,t,a,r={})=>{try{let l=(0,n.getProxyBaseUrl)(),i=new URLSearchParams(Object.entries({team_id:r.teamID,organization_id:r.organizationID,team_alias:r.team_alias,user_id:r.userID,page:t,page_size:a,sort_by:r.sortBy,sort_order:r.sortOrder,status:"deleted"}).filter(([,e])=>null!=e).map(([e,t])=>[e,String(t)])),s=`${l?`${l}/v2/team/list`:"/v2/team/list"}?${i}`,o=await fetch(s,{method:"GET",headers:{[(0,n.getGlobalLitellmHeaderName)()]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=(0,n.deriveErrorMessage)(e);throw(0,n.handleError)(t),Error(t)}let d=await o.json();if(console.log("/team/list?status=deleted API Response:",d),d&&"object"==typeof d&&"teams"in d)return d.teams;return d}catch(e){throw console.error("Failed to list deleted teams:",e),e}},m=(0,s.createQueryKeys)("deletedTeams");e.s(["useDeletedTeams",0,(e,r,i={})=>{let{accessToken:s}=(0,l.default)();return(0,a.useQuery)({queryKey:m.list({page:e,limit:r,...i}),queryFn:async()=>await d(s,e,r,i),enabled:!!s,staleTime:3e4,placeholderData:t.keepPreviousData})},"useTeam",0,e=>{let{accessToken:t}=(0,l.default)(),i=(0,r.useQueryClient)();return(0,a.useQuery)({queryKey:o.detail(e),enabled:!!(t&&e),queryFn:async()=>{if(!t||!e)throw Error("Missing auth or teamId");return(0,n.teamInfoCall)(t,e)},initialData:()=>{if(!e)return;let t=i.getQueryData(o.list({}));return t?.find(t=>t.team_id===e)}})},"useTeams",0,()=>{let{accessToken:e,userId:t,userRole:r}=(0,l.default)();return(0,a.useQuery)({queryKey:o.list({}),queryFn:async()=>await (0,i.fetchTeams)(e,t,r,null),enabled:!!e})}])},738014,e=>{"use strict";var t=e.i(135214),a=e.i(764205),r=e.i(266027);let l=(0,e.i(243652).createQueryKeys)("users");e.s(["useCurrentUser",0,()=>{let{accessToken:e,userId:i,userRole:s}=(0,t.default)();return(0,r.useQuery)({queryKey:l.detail(i),queryFn:async()=>{let t=await (0,a.userInfoCall)(e,i,s,!1,null,null);return console.log(`userInfo: ${JSON.stringify(t)}`),t.user_info},enabled:!!(e&&i&&s)})}])},907308,e=>{"use strict";var t=e.i(843476),a=e.i(271645),r=e.i(212931),l=e.i(808613),i=e.i(464571),s=e.i(199133),n=e.i(592968),o=e.i(213205),d=e.i(374009),m=e.i(764205);e.s(["default",0,({isVisible:e,onCancel:c,onSubmit:u,accessToken:g,title:h="Add Team Member",roles:p=[{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:x="user",teamId:b})=>{let[f]=l.Form.useForm(),[y,_]=(0,a.useState)([]),[v,j]=(0,a.useState)(!1),[w,C]=(0,a.useState)("user_email"),[S,k]=(0,a.useState)(!1),N=async(e,t)=>{if(!e)return void _([]);j(!0);try{let a=new URLSearchParams;if(a.append(t,e),b&&a.append("team_id",b),null==g)return;let r=(await (0,m.userFilterUICall)(g,a)).map(e=>({label:"user_email"===t?`${e.user_email}`:`${e.user_id}`,value:"user_email"===t?e.user_email:e.user_id,user:e}));_(r)}catch(e){console.error("Error fetching users:",e)}finally{j(!1)}},T=(0,a.useCallback)((0,d.default)((e,t)=>N(e,t),300),[]),I=(e,t)=>{C(t),T(e,t)},M=(e,t)=>{let a=t.user;f.setFieldsValue({user_email:a.user_email,user_id:a.user_id,role:f.getFieldValue("role")})},O=async e=>{k(!0);try{await u(e)}finally{k(!1)}};return(0,t.jsx)(r.Modal,{title:h,open:e,onCancel:()=>{f.resetFields(),_([]),c()},footer:null,width:800,maskClosable:!S,children:(0,t.jsxs)(l.Form,{form:f,onFinish:O,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",initialValues:{role:x},children:[(0,t.jsx)(l.Form.Item,{label:"Email",name:"user_email",className:"mb-4",children:(0,t.jsx)(s.Select,{showSearch:!0,className:"w-full",placeholder:"Search by email",filterOption:!1,onSearch:e=>I(e,"user_email"),onSelect:(e,t)=>M(e,t),options:"user_email"===w?y:[],loading:v,allowClear:!0})}),(0,t.jsx)("div",{className:"text-center mb-4",children:"OR"}),(0,t.jsx)(l.Form.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,t.jsx)(s.Select,{showSearch:!0,className:"w-full",placeholder:"Search by user ID",filterOption:!1,onSearch:e=>I(e,"user_id"),onSelect:(e,t)=>M(e,t),options:"user_id"===w?y:[],loading:v,allowClear:!0})}),(0,t.jsx)(l.Form.Item,{label:"Member Role",name:"role",className:"mb-4",children:(0,t.jsx)(s.Select,{defaultValue:x,children:p.map(e=>(0,t.jsx)(s.Select.Option,{value:e.value,children:(0,t.jsxs)(n.Tooltip,{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)(i.Button,{type:"primary",htmlType:"submit",icon:(0,t.jsx)(o.UserAddOutlined,{}),loading:S,children:S?"Adding...":"Add Member"})})]})})}])},162386,e=>{"use strict";var t=e.i(843476),a=e.i(625901),r=e.i(109799),l=e.i(785242),i=e.i(738014),s=e.i(199133),n=e.i(981339),o=e.i(592968);let d={label:"All Proxy Models",value:"all-proxy-models"},m={label:"No Default Models",value:"no-default-models"},c=[d,m],u={user:({allProxyModels:e,userModels:t,options:a})=>t&&a?.includeUserModels?t:[],team:({allProxyModels:e,selectedOrganization:t,userModels:a})=>t?t.models.includes(d.value)||0===t.models.length?e:e.filter(e=>t.models.includes(e)):e??[],organization:({allProxyModels:e})=>e,global:({allProxyModels:e})=>e};e.s(["ModelSelect",0,e=>{let{teamID:g,organizationID:h,options:p,context:x,dataTestId:b,value:f=[],onChange:y,style:_}=e,{includeUserModels:v,showAllTeamModelsOption:j,showAllProxyModelsOverride:w,includeSpecialOptions:C}=p||{},{data:S,isLoading:k}=(0,a.useAllProxyModels)(),{data:N,isLoading:T}=(0,l.useTeam)(g),{data:I,isLoading:M}=(0,r.useOrganization)(h),{data:O,isLoading:z}=(0,i.useCurrentUser)(),E=e=>c.some(t=>t.value===e),P=f.some(E),D=I?.models.includes(d.value)||I?.models.length===0;if(k||T||M||z)return(0,t.jsx)(n.Skeleton.Input,{active:!0,block:!0});let{wildcard:$,regular:F}=(e=>{let t=[],a=[];for(let r of e)r.endsWith("/*")?t.push(r):a.push(r);return{wildcard:t,regular:a}})(((e,t,a)=>{let r=Array.from(new Map(e.map(e=>[e.id,e])).values()).map(e=>e.id);if(t.options?.showAllProxyModelsOverride)return r;let l=u[t.context];return l?l({allProxyModels:r,...a,options:t.options}):[]})(S?.data??[],e,{selectedTeam:N,selectedOrganization:I,userModels:O?.models}));return(0,t.jsx)(s.Select,{"data-testid":b,value:f,onChange:e=>{let t=e.filter(E);y(t.length>0?[t[t.length-1]]:e)},style:_,options:[C?{label:(0,t.jsx)("span",{children:"Special Options"}),title:"Special Options",options:[...w||D&&C||"global"===x?[{label:(0,t.jsx)("span",{children:"All Proxy Models"}),value:d.value,disabled:f.length>0&&f.some(e=>E(e)&&e!==d.value),key:d.value}]:[],{label:(0,t.jsx)("span",{children:"No Default Models"}),value:m.value,disabled:f.length>0&&f.some(e=>E(e)&&e!==m.value),key:m.value}]}:[],...$.length>0?[{label:(0,t.jsx)("span",{children:"Wildcard Options"}),title:"Wildcard Options",options:$.map(e=>{let a=e.replace("/*",""),r=a.charAt(0).toUpperCase()+a.slice(1);return{label:(0,t.jsx)("span",{children:`All ${r} models`}),value:e,disabled:P}})}]:[],{label:(0,t.jsx)("span",{children:"Models"}),title:"Models",options:F.map(e=>({label:(0,t.jsx)("span",{children:e}),value:e,disabled:P}))}],mode:"multiple",placeholder:"Select Models",allowClear:!0,maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(o.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})})})}],162386)},276173,e=>{"use strict";var t=e.i(843476),a=e.i(599724),r=e.i(779241),l=e.i(464571),i=e.i(808613),s=e.i(212931),n=e.i(199133),o=e.i(271645),d=e.i(435451);e.s(["default",0,({visible:e,onCancel:m,onSubmit:c,initialData:u,mode:g,config:h})=>{let p,[x]=i.Form.useForm(),[b,f]=(0,o.useState)(!1);console.log("Initial Data:",u),(0,o.useEffect)(()=>{if(e)if("edit"===g&&u){let e={...u,role:u.role||h.defaultRole,max_budget_in_team:u.max_budget_in_team||null,tpm_limit:u.tpm_limit||null,rpm_limit:u.rpm_limit||null};console.log("Setting form values:",e),x.setFieldsValue(e)}else x.resetFields(),x.setFieldsValue({role:h.defaultRole||h.roleOptions[0]?.value})},[e,u,g,x,h.defaultRole,h.roleOptions]);let y=async e=>{try{f(!0);let t=Object.entries(e).reduce((e,[t,a])=>{if("string"==typeof a){let r=a.trim();return""===r&&("max_budget_in_team"===t||"tpm_limit"===t||"rpm_limit"===t)?{...e,[t]:null}:{...e,[t]:r}}return{...e,[t]:a}},{});console.log("Submitting form data:",t),await Promise.resolve(c(t)),x.resetFields()}catch(e){console.error("Form submission error:",e)}finally{f(!1)}};return(0,t.jsx)(s.Modal,{title:h.title||("add"===g?"Add Member":"Edit Member"),open:e,width:1e3,footer:null,onCancel:m,children:(0,t.jsxs)(i.Form,{form:x,onFinish:y,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[h.showEmail&&(0,t.jsx)(i.Form.Item,{label:"Email",name:"user_email",className:"mb-4",rules:[{type:"email",message:"Please enter a valid email!"}],children:(0,t.jsx)(r.TextInput,{placeholder:"user@example.com"})}),h.showEmail&&h.showUserId&&(0,t.jsx)("div",{className:"text-center mb-4",children:(0,t.jsx)(a.Text,{children:"OR"})}),h.showUserId&&(0,t.jsx)(i.Form.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,t.jsx)(r.TextInput,{placeholder:"user_123"})}),(0,t.jsx)(i.Form.Item,{label:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{children:"Role"}),"edit"===g&&u&&(0,t.jsxs)("span",{className:"text-gray-500 text-sm",children:["(Current: ",(p=u.role,h.roleOptions.find(e=>e.value===p)?.label||p),")"]})]}),name:"role",className:"mb-4",rules:[{required:!0,message:"Please select a role!"}],children:(0,t.jsx)(n.Select,{children:"edit"===g&&u?[...h.roleOptions.filter(e=>e.value===u.role),...h.roleOptions.filter(e=>e.value!==u.role)].map(e=>(0,t.jsx)(n.Select.Option,{value:e.value,children:e.label},e.value)):h.roleOptions.map(e=>(0,t.jsx)(n.Select.Option,{value:e.value,children:e.label},e.value))})}),h.additionalFields?.map(e=>(0,t.jsx)(i.Form.Item,{label:e.label,name:e.name,className:"mb-4",rules:e.rules,children:(e=>{switch(e.type){case"input":return(0,t.jsx)(r.TextInput,{placeholder:e.placeholder});case"numerical":return(0,t.jsx)(d.default,{step:e.step||1,min:e.min||0,style:{width:"100%"},placeholder:e.placeholder||"Enter a numerical value"});case"select":return(0,t.jsx)(n.Select,{children:e.options?.map(e=>(0,t.jsx)(n.Select.Option,{value:e.value,children:e.label},e.value))});default:return null}})(e)},e.name)),(0,t.jsxs)("div",{className:"text-right mt-6",children:[(0,t.jsx)(l.Button,{onClick:m,className:"mr-2",disabled:b,children:"Cancel"}),(0,t.jsx)(l.Button,{type:"default",htmlType:"submit",loading:b,children:"add"===g?b?"Adding...":"Add Member":b?"Saving...":"Save Changes"})]})]})})}])},294612,e=>{"use strict";var t=e.i(843476),a=e.i(100486),r=e.i(827252),l=e.i(213205),i=e.i(771674),s=e.i(464571),n=e.i(770914),o=e.i(291542),d=e.i(262218),m=e.i(592968),c=e.i(898586),u=e.i(902555);let{Text:g}=c.Typography;function h({members:e,canEdit:c,onEdit:h,onDelete:p,onAddMember:x,roleColumnTitle:b="Role",roleTooltip:f,extraColumns:y=[],showDeleteForMember:_,emptyText:v}){let j=[{title:"User Email",dataIndex:"user_email",key:"user_email",render:e=>(0,t.jsx)(g,{children:e||"-"})},{title:"User ID",dataIndex:"user_id",key:"user_id",render:e=>"default_user_id"===e?(0,t.jsx)(d.Tag,{color:"blue",children:"Default Proxy Admin"}):(0,t.jsx)(g,{children:e||"-"})},{title:f?(0,t.jsxs)(n.Space,{direction:"horizontal",children:[b,(0,t.jsx)(m.Tooltip,{title:f,children:(0,t.jsx)(r.InfoCircleOutlined,{})})]}):b,dataIndex:"role",key:"role",render:e=>(0,t.jsxs)(n.Space,{children:[e?.toLowerCase()==="admin"||e?.toLowerCase()==="org_admin"?(0,t.jsx)(a.CrownOutlined,{}):(0,t.jsx)(i.UserOutlined,{}),(0,t.jsx)(g,{style:{textTransform:"capitalize"},children:e||"-"})]})},...y,{title:"Actions",key:"actions",fixed:"right",width:120,render:(e,a)=>c?(0,t.jsxs)(n.Space,{children:[(0,t.jsx)(u.default,{variant:"Edit",tooltipText:"Edit member",dataTestId:"edit-member",onClick:()=>h(a)}),(!_||_(a))&&(0,t.jsx)(u.default,{variant:"Delete",tooltipText:"Delete member",dataTestId:"delete-member",onClick:()=>p(a)})]}):null}];return(0,t.jsxs)(n.Space,{direction:"vertical",style:{width:"100%"},children:[(0,t.jsxs)("span",{className:"inline-flex text-sm text-gray-700",children:[e.length," Member",1!==e.length?"s":""]}),(0,t.jsx)(o.Table,{columns:j,dataSource:e,rowKey:e=>e.user_id??e.user_email??JSON.stringify(e),pagination:!1,size:"small",scroll:{x:"max-content"},locale:v?{emptyText:v}:void 0}),x&&c&&(0,t.jsx)(s.Button,{icon:(0,t.jsx)(l.UserAddOutlined,{}),type:"primary",onClick:x,children:"Add Member"})]})}e.s(["default",()=>h])},94629,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4"}))});e.s(["SwitchVerticalIcon",0,a],94629)},244451,e=>{"use strict";let t;e.i(247167);var a=e.i(271645),r=e.i(343794),l=e.i(242064),i=e.i(763731),s=e.i(174428);let n=80*Math.PI,o=e=>{let{dotClassName:t,style:l,hasCircleCls:i}=e;return a.createElement("circle",{className:(0,r.default)(`${t}-circle`,{[`${t}-circle-bg`]:i}),r:40,cx:50,cy:50,strokeWidth:20,style:l})},d=({percent:e,prefixCls:t})=>{let l=`${t}-dot`,i=`${l}-holder`,d=`${i}-hidden`,[m,c]=a.useState(!1);(0,s.default)(()=>{0!==e&&c(!0)},[0!==e]);let u=Math.max(Math.min(e,100),0);if(!m)return null;let g={strokeDashoffset:`${n/4}`,strokeDasharray:`${n*u/100} ${n*(100-u)/100}`};return a.createElement("span",{className:(0,r.default)(i,`${l}-progress`,u<=0&&d)},a.createElement("svg",{viewBox:"0 0 100 100",role:"progressbar","aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":u},a.createElement(o,{dotClassName:l,hasCircleCls:!0}),a.createElement(o,{dotClassName:l,style:g})))};function m(e){let{prefixCls:t,percent:l=0}=e,i=`${t}-dot`,s=`${i}-holder`,n=`${s}-hidden`;return a.createElement(a.Fragment,null,a.createElement("span",{className:(0,r.default)(s,l>0&&n)},a.createElement("span",{className:(0,r.default)(i,`${t}-dot-spin`)},[1,2,3,4].map(e=>a.createElement("i",{className:`${t}-dot-item`,key:e})))),a.createElement(d,{prefixCls:t,percent:l}))}function c(e){var t;let{prefixCls:l,indicator:s,percent:n}=e,o=`${l}-dot`;return s&&a.isValidElement(s)?(0,i.cloneElement)(s,{className:(0,r.default)(null==(t=s.props)?void 0:t.className,o),percent:n}):a.createElement(m,{prefixCls:l,percent:n})}e.i(296059);var u=e.i(694758),g=e.i(183293),h=e.i(246422),p=e.i(838378);let x=new u.Keyframes("antSpinMove",{to:{opacity:1}}),b=new u.Keyframes("antRotate",{to:{transform:"rotate(405deg)"}}),f=(0,h.genStyleHooks)("Spin",e=>(e=>{let{componentCls:t,calc:a}=e;return{[t]:Object.assign(Object.assign({},(0,g.resetComponent)(e)),{position:"absolute",display:"none",color:e.colorPrimary,fontSize:0,textAlign:"center",verticalAlign:"middle",opacity:0,transition:`transform ${e.motionDurationSlow} ${e.motionEaseInOutCirc}`,"&-spinning":{position:"relative",display:"inline-block",opacity:1},[`${t}-text`]:{fontSize:e.fontSize,paddingTop:a(a(e.dotSize).sub(e.fontSize)).div(2).add(2).equal()},"&-fullscreen":{position:"fixed",width:"100vw",height:"100vh",backgroundColor:e.colorBgMask,zIndex:e.zIndexPopupBase,inset:0,display:"flex",alignItems:"center",flexDirection:"column",justifyContent:"center",opacity:0,visibility:"hidden",transition:`all ${e.motionDurationMid}`,"&-show":{opacity:1,visibility:"visible"},[t]:{[`${t}-dot-holder`]:{color:e.colorWhite},[`${t}-text`]:{color:e.colorTextLightSolid}}},"&-nested-loading":{position:"relative",[`> div > ${t}`]:{position:"absolute",top:0,insetInlineStart:0,zIndex:4,display:"block",width:"100%",height:"100%",maxHeight:e.contentHeight,[`${t}-dot`]:{position:"absolute",top:"50%",insetInlineStart:"50%",margin:a(e.dotSize).mul(-1).div(2).equal()},[`${t}-text`]:{position:"absolute",top:"50%",width:"100%",textShadow:`0 1px 2px ${e.colorBgContainer}`},[`&${t}-show-text ${t}-dot`]:{marginTop:a(e.dotSize).div(2).mul(-1).sub(10).equal()},"&-sm":{[`${t}-dot`]:{margin:a(e.dotSizeSM).mul(-1).div(2).equal()},[`${t}-text`]:{paddingTop:a(a(e.dotSizeSM).sub(e.fontSize)).div(2).add(2).equal()},[`&${t}-show-text ${t}-dot`]:{marginTop:a(e.dotSizeSM).div(2).mul(-1).sub(10).equal()}},"&-lg":{[`${t}-dot`]:{margin:a(e.dotSizeLG).mul(-1).div(2).equal()},[`${t}-text`]:{paddingTop:a(a(e.dotSizeLG).sub(e.fontSize)).div(2).add(2).equal()},[`&${t}-show-text ${t}-dot`]:{marginTop:a(e.dotSizeLG).div(2).mul(-1).sub(10).equal()}}},[`${t}-container`]:{position:"relative",transition:`opacity ${e.motionDurationSlow}`,"&::after":{position:"absolute",top:0,insetInlineEnd:0,bottom:0,insetInlineStart:0,zIndex:10,width:"100%",height:"100%",background:e.colorBgContainer,opacity:0,transition:`all ${e.motionDurationSlow}`,content:'""',pointerEvents:"none"}},[`${t}-blur`]:{clear:"both",opacity:.5,userSelect:"none",pointerEvents:"none","&::after":{opacity:.4,pointerEvents:"auto"}}},"&-tip":{color:e.spinDotDefault},[`${t}-dot-holder`]:{width:"1em",height:"1em",fontSize:e.dotSize,display:"inline-block",transition:`transform ${e.motionDurationSlow} ease, opacity ${e.motionDurationSlow} ease`,transformOrigin:"50% 50%",lineHeight:1,color:e.colorPrimary,"&-hidden":{transform:"scale(0.3)",opacity:0}},[`${t}-dot-progress`]:{position:"absolute",inset:0},[`${t}-dot`]:{position:"relative",display:"inline-block",fontSize:e.dotSize,width:"1em",height:"1em","&-item":{position:"absolute",display:"block",width:a(e.dotSize).sub(a(e.marginXXS).div(2)).div(2).equal(),height:a(e.dotSize).sub(a(e.marginXXS).div(2)).div(2).equal(),background:"currentColor",borderRadius:"100%",transform:"scale(0.75)",transformOrigin:"50% 50%",opacity:.3,animationName:x,animationDuration:"1s",animationIterationCount:"infinite",animationTimingFunction:"linear",animationDirection:"alternate","&:nth-child(1)":{top:0,insetInlineStart:0,animationDelay:"0s"},"&:nth-child(2)":{top:0,insetInlineEnd:0,animationDelay:"0.4s"},"&:nth-child(3)":{insetInlineEnd:0,bottom:0,animationDelay:"0.8s"},"&:nth-child(4)":{bottom:0,insetInlineStart:0,animationDelay:"1.2s"}},"&-spin":{transform:"rotate(45deg)",animationName:b,animationDuration:"1.2s",animationIterationCount:"infinite",animationTimingFunction:"linear"},"&-circle":{strokeLinecap:"round",transition:["stroke-dashoffset","stroke-dasharray","stroke","stroke-width","opacity"].map(t=>`${t} ${e.motionDurationSlow} ease`).join(","),fillOpacity:0,stroke:"currentcolor"},"&-circle-bg":{stroke:e.colorFillSecondary}},[`&-sm ${t}-dot`]:{"&, &-holder":{fontSize:e.dotSizeSM}},[`&-sm ${t}-dot-holder`]:{i:{width:a(a(e.dotSizeSM).sub(a(e.marginXXS).div(2))).div(2).equal(),height:a(a(e.dotSizeSM).sub(a(e.marginXXS).div(2))).div(2).equal()}},[`&-lg ${t}-dot`]:{"&, &-holder":{fontSize:e.dotSizeLG}},[`&-lg ${t}-dot-holder`]:{i:{width:a(a(e.dotSizeLG).sub(e.marginXXS)).div(2).equal(),height:a(a(e.dotSizeLG).sub(e.marginXXS)).div(2).equal()}},[`&${t}-show-text ${t}-text`]:{display:"block"}})}})((0,p.mergeToken)(e,{spinDotDefault:e.colorTextDescription})),e=>{let{controlHeightLG:t,controlHeight:a}=e;return{contentHeight:400,dotSize:t/2,dotSizeSM:.35*t,dotSizeLG:a}}),y=[[30,.05],[70,.03],[96,.01]];var _=function(e,t){var a={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(a[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,r=Object.getOwnPropertySymbols(e);lt.indexOf(r[l])&&Object.prototype.propertyIsEnumerable.call(e,r[l])&&(a[r[l]]=e[r[l]]);return a};let v=e=>{var i;let{prefixCls:s,spinning:n=!0,delay:o=0,className:d,rootClassName:m,size:u="default",tip:g,wrapperClassName:h,style:p,children:x,fullscreen:b=!1,indicator:v,percent:j}=e,w=_(e,["prefixCls","spinning","delay","className","rootClassName","size","tip","wrapperClassName","style","children","fullscreen","indicator","percent"]),{getPrefixCls:C,direction:S,className:k,style:N,indicator:T}=(0,l.useComponentConfig)("spin"),I=C("spin",s),[M,O,z]=f(I),[E,P]=a.useState(()=>n&&(!n||!o||!!Number.isNaN(Number(o)))),D=function(e,t){let[r,l]=a.useState(0),i=a.useRef(null),s="auto"===t;return a.useEffect(()=>(s&&e&&(l(0),i.current=setInterval(()=>{l(e=>{let t=100-e;for(let a=0;a{i.current&&(clearInterval(i.current),i.current=null)}),[s,e]),s?r:t}(E,j);a.useEffect(()=>{if(n){let e=function(e,t,a){var r,l=a||{},i=l.noTrailing,s=void 0!==i&&i,n=l.noLeading,o=void 0!==n&&n,d=l.debounceMode,m=void 0===d?void 0:d,c=!1,u=0;function g(){r&&clearTimeout(r)}function h(){for(var a=arguments.length,l=Array(a),i=0;ie?o?(u=Date.now(),s||(r=setTimeout(m?p:h,e))):h():!0!==s&&(r=setTimeout(m?p:h,void 0===m?e-d:e)))}return h.cancel=function(e){var t=(e||{}).upcomingOnly;g(),c=!(void 0!==t&&t)},h}(o,()=>{P(!0)},{debounceMode:false});return e(),()=>{var t;null==(t=null==e?void 0:e.cancel)||t.call(e)}}P(!1)},[o,n]);let $=a.useMemo(()=>void 0!==x&&!b,[x,b]),F=(0,r.default)(I,k,{[`${I}-sm`]:"small"===u,[`${I}-lg`]:"large"===u,[`${I}-spinning`]:E,[`${I}-show-text`]:!!g,[`${I}-rtl`]:"rtl"===S},d,!b&&m,O,z),L=(0,r.default)(`${I}-container`,{[`${I}-blur`]:E}),A=null!=(i=null!=v?v:T)?i:t,R=Object.assign(Object.assign({},N),p),B=a.createElement("div",Object.assign({},w,{style:R,className:F,"aria-live":"polite","aria-busy":E}),a.createElement(c,{prefixCls:I,indicator:A,percent:D}),g&&($||b)?a.createElement("div",{className:`${I}-text`},g):null);return M($?a.createElement("div",Object.assign({},w,{className:(0,r.default)(`${I}-nested-loading`,h,O,z)}),E&&a.createElement("div",{key:"loading"},B),a.createElement("div",{className:L,key:"container"},x)):b?a.createElement("div",{className:(0,r.default)(`${I}-fullscreen`,{[`${I}-fullscreen-show`]:E},m,O,z)},B):B)};v.setDefaultIndicator=e=>{t=e},e.s(["default",0,v],244451)},482725,e=>{"use strict";var t=e.i(244451);e.s(["Spin",()=>t.default])},269200,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(444755);let l=(0,e.i(673706).makeClassName)("Table"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement("div",{className:(0,r.tremorTwMerge)(l("root"),"overflow-auto",n)},a.default.createElement("table",Object.assign({ref:i,className:(0,r.tremorTwMerge)(l("table"),"w-full text-tremor-default","text-tremor-content","dark:text-dark-tremor-content")},o),s))});i.displayName="Table",e.s(["Table",()=>i],269200)},427612,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableHead"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement(a.default.Fragment,null,a.default.createElement("thead",Object.assign({ref:i,className:(0,r.tremorTwMerge)(l("root"),"text-left","text-tremor-content","dark:text-dark-tremor-content",n)},o),s))});i.displayName="TableHead",e.s(["TableHead",()=>i],427612)},64848,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableHeaderCell"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement(a.default.Fragment,null,a.default.createElement("th",Object.assign({ref:i,className:(0,r.tremorTwMerge)(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",n)},o),s))});i.displayName="TableHeaderCell",e.s(["TableHeaderCell",()=>i],64848)},942232,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableBody"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement(a.default.Fragment,null,a.default.createElement("tbody",Object.assign({ref:i,className:(0,r.tremorTwMerge)(l("root"),"align-top divide-y","divide-tremor-border","dark:divide-dark-tremor-border",n)},o),s))});i.displayName="TableBody",e.s(["TableBody",()=>i],942232)},496020,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableRow"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement(a.default.Fragment,null,a.default.createElement("tr",Object.assign({ref:i,className:(0,r.tremorTwMerge)(l("row"),n)},o),s))});i.displayName="TableRow",e.s(["TableRow",()=>i],496020)},977572,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableCell"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement(a.default.Fragment,null,a.default.createElement("td",Object.assign({ref:i,className:(0,r.tremorTwMerge)(l("root"),"align-middle whitespace-nowrap text-left p-4",n)},o),s))});i.displayName="TableCell",e.s(["TableCell",()=>i],977572)},389083,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(829087),l=e.i(480731),i=e.i(95779),s=e.i(444755),n=e.i(673706);let o={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"}},d={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,n.makeClassName)("Badge"),c=a.default.forwardRef((e,c)=>{let{color:u,icon:g,size:h=l.Sizes.SM,tooltip:p,className:x,children:b}=e,f=(0,t.__rest)(e,["color","icon","size","tooltip","className","children"]),y=g||null,{tooltipProps:_,getReferenceProps:v}=(0,r.useTooltip)();return a.default.createElement("span",Object.assign({ref:(0,n.mergeRefs)([c,_.refs.setReference]),className:(0,s.tremorTwMerge)(m("root"),"w-max shrink-0 inline-flex justify-center items-center cursor-default rounded-tremor-small ring-1 ring-inset",u?(0,s.tremorTwMerge)((0,n.getColorClassNames)(u,i.colorPalette.background).bgColor,(0,n.getColorClassNames)(u,i.colorPalette.iconText).textColor,(0,n.getColorClassNames)(u,i.colorPalette.iconRing).ringColor,"bg-opacity-10 ring-opacity-20","dark:bg-opacity-5 dark:ring-opacity-60"):(0,s.tremorTwMerge)("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"),o[h].paddingX,o[h].paddingY,o[h].fontSize,x)},v,f),a.default.createElement(r.default,Object.assign({text:p},_)),y?a.default.createElement(y,{className:(0,s.tremorTwMerge)(m("icon"),"shrink-0 -ml-1 mr-1.5",d[h].height,d[h].width)}):null,a.default.createElement("span",{className:(0,s.tremorTwMerge)(m("text"),"whitespace-nowrap")},b))});c.displayName="Badge",e.s(["Badge",()=>c],389083)},68155,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.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"}))});e.s(["TrashIcon",0,a],68155)},360820,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 15l7-7 7 7"}))});e.s(["ChevronUpIcon",0,a],360820)},871943,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"}))});e.s(["ChevronDownIcon",0,a],871943)},530212,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M10 19l-7-7m0 0l7-7m-7 7h18"}))});e.s(["ArrowLeftIcon",0,a],530212)},969550,e=>{"use strict";var t=e.i(843476),a=e.i(271645);let r=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:"M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"}))});var l=e.i(464571),i=e.i(311451),s=e.i(199133),n=e.i(374009);e.s(["default",0,({options:e,onApplyFilters:o,onResetFilters:d,initialValues:m={},buttonLabel:c="Filters"})=>{let[u,g]=(0,a.useState)(!1),[h,p]=(0,a.useState)(m),[x,b]=(0,a.useState)({}),[f,y]=(0,a.useState)({}),[_,v]=(0,a.useState)({}),[j,w]=(0,a.useState)({}),C=(0,a.useCallback)((0,n.default)(async(e,t)=>{if(t.isSearchable&&t.searchFn){y(e=>({...e,[t.name]:!0}));try{let a=await t.searchFn(e);b(e=>({...e,[t.name]:a}))}catch(e){console.error("Error searching:",e),b(e=>({...e,[t.name]:[]}))}finally{y(e=>({...e,[t.name]:!1}))}}},300),[]),S=(0,a.useCallback)(async e=>{if(e.isSearchable&&e.searchFn&&!j[e.name]){y(t=>({...t,[e.name]:!0})),w(t=>({...t,[e.name]:!0}));try{let t=await e.searchFn("");b(a=>({...a,[e.name]:t}))}catch(t){console.error("Error loading initial options:",t),b(t=>({...t,[e.name]:[]}))}finally{y(t=>({...t,[e.name]:!1}))}}},[j]);(0,a.useEffect)(()=>{u&&e.forEach(e=>{e.isSearchable&&!j[e.name]&&S(e)})},[u,e,S,j]);let k=(e,t)=>{let a={...h,[e]:t};p(a),o(a)};return(0,t.jsxs)("div",{className:"w-full",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2 mb-6",children:[(0,t.jsx)(l.Button,{icon:(0,t.jsx)(r,{className:"h-4 w-4"}),onClick:()=>g(!u),className:"flex items-center gap-2",children:c}),(0,t.jsx)(l.Button,{onClick:()=>{let t={};e.forEach(e=>{t[e.name]=""}),p(t),d()},children:"Reset Filters"})]}),u&&(0,t.jsx)("div",{className:"grid grid-cols-3 gap-x-6 gap-y-4 mb-6",children:["Team ID","Status","Organization ID","Key Alias","User ID","End User","Error Code","Error Message","Key Hash","Model"].map(a=>{let r,l=e.find(e=>e.label===a||e.name===a);return l?(0,t.jsxs)("div",{className:"flex flex-col gap-2",children:[(0,t.jsx)("label",{className:"text-sm text-gray-600",children:l.label||l.name}),l.isSearchable?(0,t.jsx)(s.Select,{showSearch:!0,className:"w-full",placeholder:`Search ${l.label||l.name}...`,value:h[l.name]||void 0,onChange:e=>k(l.name,e),onOpenChange:e=>{e&&l.isSearchable&&!j[l.name]&&S(l)},onSearch:e=>{v(t=>({...t,[l.name]:e})),l.searchFn&&C(e,l)},filterOption:!1,loading:f[l.name],options:x[l.name]||[],allowClear:!0,notFoundContent:f[l.name]?"Loading...":"No results found"}):l.options?(0,t.jsx)(s.Select,{className:"w-full",placeholder:`Select ${l.label||l.name}...`,value:h[l.name]||void 0,onChange:e=>k(l.name,e),allowClear:!0,children:l.options.map(e=>(0,t.jsx)(s.Select.Option,{value:e.value,children:e.label},e.value))}):l.customComponent?(r=l.customComponent,(0,t.jsx)(r,{value:h[l.name]||void 0,onChange:e=>k(l.name,e??""),placeholder:`Select ${l.label||l.name}...`})):(0,t.jsx)(i.Input,{className:"w-full",placeholder:`Enter ${l.label||l.name}...`,value:h[l.name]||"",onChange:e=>k(l.name,e.target.value),allowClear:!0})]},l.name):null})})]})}],969550)},633627,e=>{"use strict";var t=e.i(764205);let a=(e,t,a,r)=>{for(let l of e){let e=l?.key_alias;e&&"string"==typeof e&&t.add(e.trim());let i=l?.organization_id??l?.org_id;i&&"string"==typeof i&&a.add(i.trim());let s=l?.user_id;if(s&&"string"==typeof s){let e=l?.user?.user_email||s;r.set(s,e)}}},r=async(e,r)=>{if(!e||!r)return{keyAliases:[],organizationIds:[],userIds:[]};try{let l=new Set,i=new Set,s=new Map,n=await (0,t.keyListCall)(e,null,r,null,null,null,1,100,null,null,"user",null),o=n?.keys||[],d=n?.total_pages??1;a(o,l,i,s);let m=Math.min(d,10)-1;if(m>0){let n=Array.from({length:m},(a,l)=>(0,t.keyListCall)(e,null,r,null,null,null,l+2,100,null,null,"user",null));for(let e of(await Promise.allSettled(n)))"fulfilled"===e.status&&a(e.value?.keys||[],l,i,s)}return{keyAliases:Array.from(l).sort(),organizationIds:Array.from(i).sort(),userIds:Array.from(s.entries()).map(([e,t])=>({id:e,email:t}))}}catch(e){return console.error("Error fetching team filter options:",e),{keyAliases:[],organizationIds:[],userIds:[]}}},l=async(e,a)=>{if(!e)return[];try{let r=[],l=1,i=!0;for(;i;){let s=await (0,t.teamListCall)(e,a||null,null);r=[...r,...s],l{if(!e)return[];try{let a=[],r=1,l=!0;for(;l;){let i=await (0,t.organizationListCall)(e);a=[...a,...i],r{"use strict";var t=e.i(266027),a=e.i(621482),r=e.i(243652),l=e.i(764205),i=e.i(135214);let s=(0,r.createQueryKeys)("models"),n=(0,r.createQueryKeys)("modelHub"),o=(0,r.createQueryKeys)("allProxyModels");(0,r.createQueryKeys)("selectedTeamModels");let d=(0,r.createQueryKeys)("infiniteModels");e.s(["useAllProxyModels",0,()=>{let{accessToken:e,userId:a,userRole:r}=(0,i.default)();return(0,t.useQuery)({queryKey:o.list({}),queryFn:async()=>await (0,l.modelAvailableCall)(e,a,r,!0,null,!0,!1,"expand"),enabled:!!(e&&a&&r)})},"useInfiniteModelInfo",0,(e=50,t)=>{let{accessToken:r,userId:s,userRole:n}=(0,i.default)();return(0,a.useInfiniteQuery)({queryKey:d.list({filters:{...s&&{userId:s},...n&&{userRole:n},size:e,...t&&{search:t}}}),queryFn:async({pageParam:a})=>await (0,l.modelInfoCall)(r,s,n,a,e,t),initialPageParam:1,getNextPageParam:e=>{if(e.current_page{let{accessToken:e}=(0,i.default)();return(0,t.useQuery)({queryKey:n.list({}),queryFn:async()=>await (0,l.modelHubCall)(e),enabled:!!e})},"useModelsInfo",0,(e=1,a=50,r,n,o,d,m)=>{let{accessToken:c,userId:u,userRole:g}=(0,i.default)();return(0,t.useQuery)({queryKey:s.list({filters:{...u&&{userId:u},...g&&{userRole:g},page:e,size:a,...r&&{search:r},...n&&{modelId:n},...o&&{teamId:o},...d&&{sortBy:d},...m&&{sortOrder:m}}}),queryFn:async()=>await (0,l.modelInfoCall)(c,u,g,e,a,r,n,o,d,m),enabled:!!(c&&u&&g)})}])},91979,e=>{"use strict";e.i(247167);var t=e.i(931067),a=e.i(271645);let r={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M909.1 209.3l-56.4 44.1C775.8 155.1 656.2 92 521.9 92 290 92 102.3 279.5 102 511.5 101.7 743.7 289.8 932 521.9 932c181.3 0 335.8-115 394.6-276.1 1.5-4.2-.7-8.9-4.9-10.3l-56.7-19.5a8 8 0 00-10.1 4.8c-1.8 5-3.8 10-5.9 14.9-17.3 41-42.1 77.8-73.7 109.4A344.77 344.77 0 01655.9 829c-42.3 17.9-87.4 27-133.8 27-46.5 0-91.5-9.1-133.8-27A341.5 341.5 0 01279 755.2a342.16 342.16 0 01-73.7-109.4c-17.9-42.4-27-87.4-27-133.9s9.1-91.5 27-133.9c17.3-41 42.1-77.8 73.7-109.4 31.6-31.6 68.4-56.4 109.3-73.8 42.3-17.9 87.4-27 133.8-27 46.5 0 91.5 9.1 133.8 27a341.5 341.5 0 01109.3 73.8c9.9 9.9 19.2 20.4 27.8 31.4l-60.2 47a8 8 0 003 14.1l175.6 43c5 1.2 9.9-2.6 9.9-7.7l.8-180.9c-.1-6.6-7.8-10.3-13-6.2z"}}]},name:"reload",theme:"outlined"};var l=e.i(9583),i=a.forwardRef(function(e,i){return a.createElement(l.default,(0,t.default)({},e,{ref:i,icon:r}))});e.s(["ReloadOutlined",0,i],91979)}]); \ No newline at end of file +(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,56567,e=>{"use strict";var t=e.i(843476),a=e.i(135214),r=e.i(109799),l=e.i(907308),i=e.i(764205),s=e.i(500330),n=e.i(11751),o=e.i(708347),d=e.i(751904),m=e.i(827252),c=e.i(987432),u=e.i(530212),g=e.i(389083),h=e.i(304967),p=e.i(350967),x=e.i(599724),b=e.i(779241),f=e.i(629569),y=e.i(464571),_=e.i(808613),v=e.i(311451),j=e.i(998573),w=e.i(199133),C=e.i(790848),S=e.i(653496),k=e.i(592968),N=e.i(678784),T=e.i(118366),I=e.i(271645),M=e.i(9314),O=e.i(552130),z=e.i(127952);function E({className:e,value:a,onChange:r}){return(0,t.jsxs)(w.Select,{className:e,value:a,onChange:r,children:[(0,t.jsx)(w.Select.Option,{value:"24h",children:"Daily"}),(0,t.jsx)(w.Select.Option,{value:"7d",children:"Weekly"}),(0,t.jsx)(w.Select.Option,{value:"30d",children:"Monthly"})]})}var P=e.i(844565),D=e.i(355619),$=e.i(643449),F=e.i(75921),L=e.i(390605),A=e.i(162386),R=e.i(727749),B=e.i(384767),U=e.i(435451),V=e.i(916940),K=e.i(183588),q=e.i(276173),W=e.i(91979),G=e.i(269200),H=e.i(942232),Q=e.i(977572),X=e.i(427612),Y=e.i(64848),J=e.i(496020),Z=e.i(536916),ee=e.i(21548);let et={"/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","/team/daily/activity":"Member can view all team usage data (not just their own)"},ea=({teamId:e,accessToken:a,canEditTeam:r})=>{let[l,s]=(0,I.useState)([]),[n,o]=(0,I.useState)([]),[d,m]=(0,I.useState)(!0),[u,g]=(0,I.useState)(!1),[p,b]=(0,I.useState)(!1),_=async()=>{try{if(m(!0),!a)return;let t=await (0,i.getTeamPermissionsCall)(a,e),r=t.all_available_permissions||[];s(r);let l=t.team_member_permissions||[];o(l),b(!1)}catch(e){R.default.fromBackend("Failed to load permissions"),console.error("Error fetching permissions:",e)}finally{m(!1)}};(0,I.useEffect)(()=>{_()},[e,a]);let v=async()=>{try{if(!a)return;g(!0),await (0,i.teamPermissionsUpdateCall)(a,e,n),R.default.success("Permissions updated successfully"),b(!1)}catch(e){R.default.fromBackend("Failed to update permissions"),console.error("Error updating permissions:",e)}finally{g(!1)}};if(d)return(0,t.jsx)("div",{className:"p-6 text-center",children:"Loading permissions..."});let j=l.length>0;return(0,t.jsxs)(h.Card,{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)(f.Title,{className:"mb-2 sm:mb-0",children:"Member Permissions"}),r&&p&&(0,t.jsxs)("div",{className:"flex gap-3",children:[(0,t.jsx)(y.Button,{icon:(0,t.jsx)(W.ReloadOutlined,{}),onClick:()=>{_()},children:"Reset"}),(0,t.jsx)(y.Button,{onClick:v,loading:u,type:"primary",icon:(0,t.jsx)(c.SaveOutlined,{}),children:"Save Changes"})]})]}),(0,t.jsx)(x.Text,{className:"mb-6 text-gray-600",children:"Control what team members can do when they are not team admins."}),j?(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)(G.Table,{className:" min-w-full",children:[(0,t.jsx)(X.TableHead,{children:(0,t.jsxs)(J.TableRow,{children:[(0,t.jsx)(Y.TableHeaderCell,{children:"Method"}),(0,t.jsx)(Y.TableHeaderCell,{children:"Endpoint"}),(0,t.jsx)(Y.TableHeaderCell,{children:"Description"}),(0,t.jsx)(Y.TableHeaderCell,{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)(H.TableBody,{children:l.map(e=>{let a=(e=>{let t=e.includes("/info")||e.includes("/list")||e.includes("/activity")?"GET":"POST",a=et[e];if(!a){for(let[t,r]of Object.entries(et))if(e.includes(t)){a=r;break}}return a||(a=`Access ${e}`),{method:t,endpoint:e,description:a,route:e}})(e);return(0,t.jsxs)(J.TableRow,{className:"hover:bg-gray-50 transition-colors",children:[(0,t.jsx)(Q.TableCell,{children:(0,t.jsx)("span",{className:`px-2 py-1 rounded text-xs font-medium ${"GET"===a.method?"bg-blue-100 text-blue-800":"bg-green-100 text-green-800"}`,children:a.method})}),(0,t.jsx)(Q.TableCell,{children:(0,t.jsx)("span",{className:"font-mono text-sm text-gray-800",children:a.endpoint})}),(0,t.jsx)(Q.TableCell,{className:"text-gray-700",children:a.description}),(0,t.jsx)(Q.TableCell,{className:"sticky right-0 bg-white shadow-[-4px_0_4px_-4px_rgba(0,0,0,0.1)] text-center",children:(0,t.jsx)(Z.Checkbox,{checked:n.includes(e),onChange:t=>{o(t.target.checked?[...n,e]:n.filter(t=>t!==e)),b(!0)},disabled:!r})})]},e)})})]})}):(0,t.jsx)("div",{className:"py-12",children:(0,t.jsx)(ee.Empty,{description:"No permissions available"})})]})},er="overview",el="virtual-keys",ei="members",es="member-permissions",en="settings",eo={[er]:"Overview",[el]:"Virtual Keys",[ei]:"Members",[es]:"Member Permissions",[en]:"Settings"};var ed=e.i(292639),em=e.i(770914),ec=e.i(898586),eu=e.i(294612);function eg({teamData:e,canEditTeam:r,handleMemberDelete:l,setSelectedEditMember:i,setIsEditMemberModalVisible:n,setIsAddMemberModalVisible:d}){let c=e=>{if(null==e)return"0";if("number"==typeof e){let t=Number(e);return t===Math.floor(t)?t.toString():(0,s.formatNumberWithCommas)(t,8).replace(/\.?0+$/,"")}return"0"},{data:u}=(0,ed.useUISettings)(),{userId:g,userRole:h}=(0,a.default)(),p=!!u?.values?.disable_team_admin_delete_team_user,x=(0,o.isUserTeamAdminForSingleTeam)(e.team_info.members_with_roles,g||""),b=(0,o.isProxyAdminRole)(h||""),f=[{title:(0,t.jsxs)(em.Space,{direction:"horizontal",children:["Team Member Spend (USD)",(0,t.jsx)(k.Tooltip,{title:"This is the amount spent by a user in the team.",children:(0,t.jsx)(m.InfoCircleOutlined,{})})]}),key:"spend",render:(a,r)=>(0,t.jsxs)(ec.Typography.Text,{children:["$",(0,s.formatNumberWithCommas)((t=>{if(!t)return 0;let a=e.team_memberships.find(e=>e.user_id===t);return a?.spend||0})(r.user_id),4)]})},{title:"Team Member Budget (USD)",key:"budget",render:(a,r)=>{let l=(t=>{if(!t)return null;let a=e.team_memberships.find(e=>e.user_id===t),r=a?.litellm_budget_table?.max_budget;return null==r?null:c(r)})(r.user_id);return(0,t.jsx)(ec.Typography.Text,{children:l?`$${(0,s.formatNumberWithCommas)(Number(l),4)}`:"No Limit"})}},{title:(0,t.jsxs)(em.Space,{direction:"horizontal",children:["Team Member Rate Limits",(0,t.jsx)(k.Tooltip,{title:"Rate limits for this member's usage within this team.",children:(0,t.jsx)(m.InfoCircleOutlined,{})})]}),key:"rate_limits",render:(a,r)=>(0,t.jsx)(ec.Typography.Text,{children:(t=>{if(!t)return"No Limits";let a=e.team_memberships.find(e=>e.user_id===t),r=a?.litellm_budget_table?.rpm_limit,l=a?.litellm_budget_table?.tpm_limit,i=[r?`${c(r)} RPM`:null,l?`${c(l)} TPM`:null].filter(Boolean);return i.length>0?i.join(" / "):"No Limits"})(r.user_id)})}];return(0,t.jsx)(eu.default,{members:e.team_info.members_with_roles,canEdit:r,onEdit:t=>{let a=e.team_memberships.find(e=>e.user_id===t.user_id);i({...t,max_budget_in_team:a?.litellm_budget_table?.max_budget||null,tpm_limit:a?.litellm_budget_table?.tpm_limit||null,rpm_limit:a?.litellm_budget_table?.rpm_limit||null}),n(!0)},onDelete:l,onAddMember:()=>d(!0),roleColumnTitle:"Team Role",roleTooltip:"This role applies only to this team and is independent from the user's proxy-level role.",extraColumns:f,showDeleteForMember:()=>b||r&&!x||x&&!p})}var eh=e.i(207082),ep=e.i(871943),ex=e.i(502547),eb=e.i(360820),ef=e.i(94629),ey=e.i(152990),e_=e.i(682830),ev=e.i(994388),ej=e.i(752978),ew=e.i(282786),eC=e.i(981339),eS=e.i(969550),ek=e.i(20147),eN=e.i(266027),eT=e.i(633627);function eI({teamId:e,teamAlias:r,organization:l}){let{accessToken:i}=(0,a.default)(),[n,o]=(0,I.useState)(null),[d,c]=(0,I.useState)([{id:"created_at",desc:!0}]),[u,h]=(0,I.useState)({pageIndex:0,pageSize:50}),[p,b]=(0,I.useState)({"Organization ID":"","Key Alias":"","User ID":"","Sort By":"created_at","Sort Order":"desc"}),f=d.length>0?d[0].id:"created_at",y=d.length>0?d[0].desc?"desc":"asc":"desc",_=u.pageIndex,v=u.pageSize,{data:j,isPending:w,isFetching:C,refetch:S}=(0,eh.useKeys)(_+1,v,{teamID:e,organizationID:p["Organization ID"]?.trim()||void 0,selectedKeyAlias:p["Key Alias"]?.trim()||void 0,userID:p["User ID"]?.trim()||void 0,sortBy:f||void 0,sortOrder:y||void 0,expand:"user"}),N=(0,I.useMemo)(()=>{let e=j?.keys||[],t=l?.organization_id;return t?e.map(e=>({...e,organization_id:(e.organization_id??e.org_id)||t})):e},[j?.keys,l?.organization_id]),T=j?.total_pages??0,[M,O]=(0,I.useState)({}),z=(0,I.useMemo)(()=>({team_id:e,team_alias:r||e,models:[],max_budget:null,budget_duration:null,tpm_limit:null,rpm_limit:null,organization_id:l?.organization_id||"",created_at:"",keys:[],members_with_roles:[],spend:0}),[e,r,l]),E=(0,eN.useQuery)({queryKey:["teamFilterOptions",e,i],queryFn:async()=>(0,eT.fetchTeamFilterOptions)(i,e),enabled:!!i&&!!e,staleTime:3e4}).data||{keyAliases:[],organizationIds:[],userIds:[]},P=(0,I.useCallback)(()=>{S?.()},[S]);(0,I.useEffect)(()=>(window.addEventListener("storage",P),()=>window.removeEventListener("storage",P)),[P]);let $=(0,I.useCallback)((e,t=!1)=>{b(t=>({...t,"Organization ID":e["Organization ID"]??t["Organization ID"],"Key Alias":e["Key Alias"]??t["Key Alias"],"User ID":e["User ID"]??t["User ID"],"Sort By":e["Sort By"]??t["Sort By"]??"created_at","Sort Order":e["Sort Order"]??t["Sort Order"]??"desc"})),t||h(e=>({...e,pageIndex:0}))},[]),F=(0,I.useCallback)(()=>{b({"Organization ID":"","Key Alias":"","User ID":"","Sort By":"created_at","Sort Order":"desc"}),h(e=>({...e,pageIndex:0}))},[]),L=(0,I.useMemo)(()=>[{name:"Organization ID",label:"Organization ID",isSearchable:!0,searchFn:async e=>{let{organizationIds:t}=E;if(!t.length)return[];let a=e.toLowerCase();return(a?t.filter(e=>e.toLowerCase().includes(a)):t).map(e=>({label:e,value:e}))}},{name:"Key Alias",label:"Key Alias",isSearchable:!0,searchFn:async e=>{let{keyAliases:t}=E,a=e.toLowerCase();return(a?t.filter(e=>e.toLowerCase().includes(a)):t).map(e=>({label:e,value:e}))}},{name:"User ID",label:"User ID",isSearchable:!0,searchFn:async e=>{let{userIds:t}=E,a=e.toLowerCase();return(a?t.filter(e=>e.id.toLowerCase().includes(a)||e.email.toLowerCase().includes(a)):t).map(e=>({label:e.email?`${e.id} (${e.email})`:e.id,value:e.id}))}}],[E]),A=(0,I.useMemo)(()=>[{id:"token",accessorKey:"token",header:"Key ID",size:100,enableSorting:!0,cell:e=>{let a=e.getValue(),r=e.cell.column.getSize();return(0,t.jsx)(k.Tooltip,{title:a,children:(0,t.jsx)(ev.Button,{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 block",style:{maxWidth:r,overflow:"hidden"},onClick:()=>o(e.row.original),children:a??"-"})})}},{id:"key_alias",accessorKey:"key_alias",header:"Key Alias",size:150,enableSorting:!0,cell:e=>{let a=e.getValue(),r=e.cell.column.getSize();return(0,t.jsx)(k.Tooltip,{title:a,children:(0,t.jsx)("span",{className:"font-mono text-xs truncate block",style:{maxWidth:r,overflow:"hidden"},children:a??"-"})})}},{id:"key_name",accessorKey:"key_name",header:"Secret Key",size:120,enableSorting:!1,cell:e=>(0,t.jsx)("span",{className:"font-mono text-xs",children:e.getValue()})},{id:"organization_id",accessorKey:"organization_id",header:"Organization ID",size:140,enableSorting:!1,cell:e=>e.getValue()?e.renderValue():"-"},{id:"user_email",accessorKey:"user",header:"User Email",size:160,enableSorting:!1,cell:e=>{let a=e.getValue(),r=a?.user_email,l=e.cell.column.getSize();return(0,t.jsx)(k.Tooltip,{title:r,children:(0,t.jsx)("span",{className:"font-mono text-xs truncate block",style:{maxWidth:l,overflow:"hidden"},children:r??"-"})})}},{id:"user_id",accessorKey:"user_id",header:"User ID",size:70,enableSorting:!1,cell:e=>{let a=e.getValue(),r="default_user_id"===a?"Default Proxy Admin":a,l=e.cell.column.getSize();return(0,t.jsx)(k.Tooltip,{title:r,children:(0,t.jsx)("span",{className:"font-mono text-xs truncate block",style:{maxWidth:l,overflow:"hidden"},children:r??"-"})})}},{id:"created_at",accessorKey:"created_at",header:"Created At",size:120,enableSorting:!0,cell:e=>{let t=e.getValue();return t?new Date(t).toLocaleDateString():"-"}},{id:"created_by",accessorKey:"created_by",header:"Created By",size:70,enableSorting:!1,cell:e=>{let a=e.getValue(),r="default_user_id"===a?"Default Proxy Admin":a,l=e.cell.column.getSize();return(0,t.jsx)(k.Tooltip,{title:r,children:(0,t.jsx)("span",{className:"font-mono text-xs truncate block",style:{maxWidth:l,overflow:"hidden"},children:r??"-"})})}},{id:"updated_at",accessorKey:"updated_at",header:"Updated At",size:120,enableSorting:!0,cell:e=>{let t=e.getValue();return t?new Date(t).toLocaleDateString():"Never"}},{id:"last_active",accessorKey:"last_active",header:()=>(0,t.jsxs)("span",{className:"flex items-center gap-1",children:["Last Active",(0,t.jsx)(ew.Popover,{content:"This is a new field and is not backfilled. Only new key usage will update this value.",trigger:"hover",children:(0,t.jsx)(m.InfoCircleOutlined,{className:"text-gray-400 text-xs cursor-help"})})]}),size:130,enableSorting:!1,cell:e=>{let a=e.getValue();if(!a)return"Unknown";let r=new Date(a);return(0,t.jsx)(k.Tooltip,{title:r.toLocaleString(void 0,{dateStyle:"medium",timeStyle:"long"}),children:(0,t.jsx)("span",{children:r.toLocaleDateString()})})}},{id:"expires",accessorKey:"expires",header:"Expires",size:120,enableSorting:!1,cell:e=>{let t=e.getValue();return t?new Date(t).toLocaleDateString():"Never"}},{id:"spend",accessorKey:"spend",header:"Spend (USD)",size:100,enableSorting:!0,cell:e=>(0,s.formatNumberWithCommas)(e.getValue(),4)},{id:"max_budget",accessorKey:"max_budget",header:"Budget (USD)",size:110,enableSorting:!0,cell:e=>{let t=e.getValue();return null===t?"Unlimited":`$${(0,s.formatNumberWithCommas)(t)}`}},{id:"budget_reset_at",accessorKey:"budget_reset_at",header:"Budget Reset",size:130,enableSorting:!1,cell:e=>{let t=e.getValue();return t?new Date(t).toLocaleString():"Never"}},{id:"models",accessorKey:"models",header:"Models",size:200,enableSorting:!1,cell:e=>{let a=e.getValue();return(0,t.jsx)("div",{className:"flex flex-col py-2",children:Array.isArray(a)?(0,t.jsx)("div",{className:"flex flex-col",children:0===a.length?(0,t.jsx)(g.Badge,{size:"xs",className:"mb-1",color:"red",children:(0,t.jsx)(x.Text,{children:"All Proxy Models"})}):(0,t.jsx)(t.Fragment,{children:(0,t.jsxs)("div",{className:"flex items-start",children:[a.length>3&&(0,t.jsx)("div",{children:(0,t.jsx)(ej.Icon,{icon:M[e.row.id]?ep.ChevronDownIcon:ex.ChevronRightIcon,className:"cursor-pointer",size:"xs",onClick:()=>O(t=>({...t,[e.row.id]:!t[e.row.id]}))})}),(0,t.jsxs)("div",{className:"flex flex-wrap gap-1",children:[a.slice(0,3).map((e,a)=>"all-proxy-models"===e?(0,t.jsx)(g.Badge,{size:"xs",color:"red",children:(0,t.jsx)(x.Text,{children:"All Proxy Models"})},a):(0,t.jsx)(g.Badge,{size:"xs",color:"blue",children:(0,t.jsx)(x.Text,{children:e.length>30?`${(0,D.getModelDisplayName)(e).slice(0,30)}...`:(0,D.getModelDisplayName)(e)})},a)),a.length>3&&!M[e.row.id]&&(0,t.jsx)(g.Badge,{size:"xs",color:"gray",className:"cursor-pointer",children:(0,t.jsxs)(x.Text,{children:["+",a.length-3," ",a.length-3==1?"more model":"more models"]})}),M[e.row.id]&&(0,t.jsx)("div",{className:"flex flex-wrap gap-1",children:a.slice(3).map((e,a)=>"all-proxy-models"===e?(0,t.jsx)(g.Badge,{size:"xs",color:"red",children:(0,t.jsx)(x.Text,{children:"All Proxy Models"})},a+3):(0,t.jsx)(g.Badge,{size:"xs",color:"blue",children:(0,t.jsx)(x.Text,{children:e.length>30?`${(0,D.getModelDisplayName)(e).slice(0,30)}...`:(0,D.getModelDisplayName)(e)})},a+3))})]})]})})}):null})}},{id:"rate_limits",header:"Rate Limits",size:140,enableSorting:!1,cell:({row:e})=>{let a=e.original;return(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{children:["TPM: ",null!==a.tpm_limit?a.tpm_limit:"Unlimited"]}),(0,t.jsxs)("div",{children:["RPM: ",null!==a.rpm_limit?a.rpm_limit:"Unlimited"]})]})}}],[M]),R=(0,I.useCallback)(e=>{let t="function"==typeof e?e(d):e;if(c(t),t?.length>0){let e=t[0];$({"Sort By":e.id,"Sort Order":e.desc?"desc":"asc"},!0)}},[d,$]),B=(0,ey.useReactTable)({data:N,columns:A,columnResizeMode:"onChange",columnResizeDirection:"ltr",state:{sorting:d,pagination:u},onSortingChange:R,onPaginationChange:h,getCoreRowModel:(0,e_.getCoreRowModel)(),enableSorting:!0,manualSorting:!0,manualPagination:!0,pageCount:T});return(0,t.jsx)("div",{className:"w-full h-full overflow-hidden",children:n?(0,t.jsx)(ek.default,{keyId:n.token,onClose:()=>o(null),keyData:n,teams:[z],onDelete:S}):(0,t.jsxs)("div",{className:"border-b py-4 flex-1 overflow-hidden",children:[(0,t.jsx)("div",{className:"w-full mb-6",children:(0,t.jsx)(eS.default,{options:L,onApplyFilters:$,initialValues:p,onResetFilters:F})}),(0,t.jsx)("div",{className:"flex items-center justify-end w-full mb-4",children:(0,t.jsxs)("div",{className:"inline-flex items-center gap-2",children:[w||C?(0,t.jsx)(eC.Skeleton.Node,{active:!0,style:{width:74,height:20}}):(0,t.jsxs)("span",{className:"text-sm text-gray-700",children:["Page ",_+1," of ",B.getPageCount()]}),w||C?(0,t.jsx)(eC.Skeleton.Button,{active:!0,size:"small",style:{width:84,height:30}}):(0,t.jsx)("button",{onClick:()=>B.previousPage(),disabled:w||C||!B.getCanPreviousPage(),className:"px-3 py-1 text-sm border rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed",children:"Previous"}),w||C?(0,t.jsx)(eC.Skeleton.Button,{active:!0,size:"small",style:{width:58,height:30}}):(0,t.jsx)("button",{onClick:()=>B.nextPage(),disabled:w||C||!B.getCanNextPage(),className:"px-3 py-1 text-sm border rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed",children:"Next"})]})}),(0,t.jsx)("div",{className:"h-[75vh] overflow-auto",children:(0,t.jsx)("div",{className:"rounded-lg custom-border relative",children:(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)(G.Table,{className:"[&_td]:py-0.5 [&_th]:py-1",style:{width:B.getCenterTotalSize()},children:[(0,t.jsx)(X.TableHead,{children:B.getHeaderGroups().map(e=>(0,t.jsx)(J.TableRow,{children:e.headers.map(e=>(0,t.jsx)(Y.TableHeaderCell,{"data-header-id":e.id,className:`py-1 h-8 relative hover:bg-gray-50 ${"actions"===e.id?"sticky right-0 bg-white shadow-[-4px_0_8px_-6px_rgba(0,0,0,0.1)]":""}`,style:{width:e.getSize(),position:"relative",cursor:e.column.getCanSort()?"pointer":"default"},onMouseEnter:()=>{let t=document.querySelector(`[data-header-id="${e.id}"] .resizer`);t&&(t.style.opacity="0.5")},onMouseLeave:()=>{let t=document.querySelector(`[data-header-id="${e.id}"] .resizer`);t&&!e.column.getIsResizing()&&(t.style.opacity="0")},onClick:e.column.getCanSort()?e.column.getToggleSortingHandler():void 0,children:(0,t.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,t.jsx)("div",{className:"flex items-center",children:e.isPlaceholder?null:(0,ey.flexRender)(e.column.columnDef.header,e.getContext())}),"actions"!==e.id&&e.column.getCanSort()&&(0,t.jsx)("div",{className:"w-4",children:e.column.getIsSorted()?({asc:(0,t.jsx)(eb.ChevronUpIcon,{className:"h-4 w-4 text-blue-500"}),desc:(0,t.jsx)(ep.ChevronDownIcon,{className:"h-4 w-4 text-blue-500"})})[e.column.getIsSorted()]:(0,t.jsx)(ef.SwitchVerticalIcon,{className:"h-4 w-4 text-gray-400"})}),(0,t.jsx)("div",{onDoubleClick:()=>e.column.resetSize(),onMouseDown:e.getResizeHandler(),onTouchStart:e.getResizeHandler(),className:`resizer ${B.options.columnResizeDirection} ${e.column.getIsResizing()?"isResizing":""}`,style:{position:"absolute",right:0,top:0,height:"100%",width:"5px",background:e.column.getIsResizing()?"#3b82f6":"transparent",cursor:"col-resize",userSelect:"none",touchAction:"none",opacity:+!!e.column.getIsResizing()}})]})},e.id))},e.id))}),(0,t.jsx)(H.TableBody,{children:w||C?(0,t.jsx)(J.TableRow,{children:(0,t.jsx)(Q.TableCell,{colSpan:A.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"Loading keys..."})})})}):N.length>0?B.getRowModel().rows.map(e=>(0,t.jsx)(J.TableRow,{className:"h-8",children:e.getVisibleCells().map(e=>(0,t.jsx)(Q.TableCell,{style:{width:e.column.getSize(),maxWidth:"8-x",whiteSpace:"pre-wrap",overflow:"hidden"},className:`py-0.5 max-h-8 overflow-hidden text-ellipsis whitespace-nowrap ${"models"===e.column.id&&Array.isArray(e.getValue())&&e.getValue().length>3?"px-0":""}`,children:(0,ey.flexRender)(e.column.columnDef.cell,e.getContext())},e.id))},e.id)):(0,t.jsx)(J.TableRow,{children:(0,t.jsx)(Q.TableCell,{colSpan:A.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"No keys found"})})})})})]})})})})]})})}e.s(["default",0,({teamId:e,onClose:W,accessToken:G,is_team_admin:H,is_proxy_admin:Q,is_org_admin:X=!1,userModels:Y,editTeam:J,premiumUser:Z=!1,onUpdate:ee})=>{let[et,ed]=(0,I.useState)(null),[em,ec]=(0,I.useState)(!0),[eu,eh]=(0,I.useState)(!1),[ep]=_.Form.useForm(),[ex,eb]=(0,I.useState)(!1),[ef,ey]=(0,I.useState)(null),[e_,ev]=(0,I.useState)(!1),[ej,ew]=(0,I.useState)([]),[eC,eS]=(0,I.useState)(!1),[ek,eN]=(0,I.useState)({}),[eT,eM]=(0,I.useState)([]),[eO,ez]=(0,I.useState)([]),[eE,eP]=(0,I.useState)({}),[eD,e$]=(0,I.useState)(!1),[eF,eL]=(0,I.useState)(null),[eA,eR]=(0,I.useState)(!1),[eB,eU]=(0,I.useState)(!1),[eV,eK]=(0,I.useState)(!1),[eq,eW]=(0,I.useState)(null),{userRole:eG,userId:eH}=(0,a.default)(),{data:eQ=[]}=(0,r.useOrganizations)(),eX=(0,I.useMemo)(()=>{let e=et?.team_info?.organization_id;if(!e||!eH)return!1;let t=eQ.find(t=>t.organization_id===e);return t?.members?.some(e=>e.user_id===eH&&"org_admin"===e.user_role)??!1},[et,eQ,eH]),eY=H||Q||X||eX,eJ=(0,I.useMemo)(()=>{let e;return e=[er,el],eY?[...e,ei,es,en]:e},[eY]),eZ=(0,I.useMemo)(()=>J&&eY?en:er,[J,eY]),e0=async()=>{try{if(ec(!0),!G)return;let t=await (0,i.teamInfoCall)(G,e);ed(t)}catch(e){R.default.fromBackend("Failed to load team information"),console.error("Error fetching team info:",e)}finally{ec(!1)}};(0,I.useEffect)(()=>{e0()},[e,G]),(0,I.useEffect)(()=>{(async()=>{if(!G||!et?.team_info?.organization_id)return eW(null);try{let e=await (0,i.organizationInfoCall)(G,et.team_info.organization_id);eW(e)}catch(e){console.error("Error fetching organization info:",e),eW(null)}})()},[G,et?.team_info?.organization_id]),(0,I.useMemo)(()=>{let e;return e=[],e=eq?eq.models.includes("all-proxy-models")?Y:eq.models.length>0?eq.models:Y:Y,(0,D.unfurlWildcardModelsInList)(e,Y)},[eq,Y]),(0,I.useEffect)(()=>{let e=async()=>{try{if(!G)return;let e=(await (0,i.getPoliciesList)(G)).policies.map(e=>e.policy_name);ez(e)}catch(e){console.error("Failed to fetch policies:",e)}};(async()=>{try{if(!G)return;let e=(await (0,i.getGuardrailsList)(G)).guardrails.map(e=>e.guardrail_name);eM(e)}catch(e){console.error("Failed to fetch guardrails:",e)}})(),e()},[G]),(0,I.useEffect)(()=>{(async()=>{if(!G||!et?.team_info?.policies||0===et.team_info.policies.length)return;e$(!0);let e={};try{await Promise.all(et.team_info.policies.map(async t=>{try{let a=await (0,i.getPolicyInfoWithGuardrails)(G,t);e[t]=a.resolved_guardrails||[]}catch(a){console.error(`Failed to fetch guardrails for policy ${t}:`,a),e[t]=[]}})),eP(e)}catch(e){console.error("Failed to fetch policy guardrails:",e)}finally{e$(!1)}})()},[G,et?.team_info?.policies]);let e1=async t=>{try{if(null==G)return;let a={user_email:t.user_email,user_id:t.user_id,role:t.role};await (0,i.teamMemberAddCall)(G,e,a),R.default.success("Team member added successfully"),eh(!1),ep.resetFields();let r=await (0,i.teamInfoCall)(G,e);ed(r),ee(r)}catch(t){let e="Failed to add team member";t?.raw?.detail?.error?.includes("Assigning team admins is a premium feature")?e="Assigning admins is an enterprise-only feature. Please upgrade your LiteLLM plan to enable this.":t?.message&&(e=t.message),R.default.fromBackend(e),console.error("Error adding team member:",t)}},e2=async t=>{try{if(null==G)return;let a={user_email:t.user_email,user_id:t.user_id,role:t.role,max_budget_in_team:t.max_budget_in_team,tpm_limit:t.tpm_limit,rpm_limit:t.rpm_limit};j.message.destroy(),await (0,i.teamMemberUpdateCall)(G,e,a),R.default.success("Team member updated successfully"),eb(!1);let r=await (0,i.teamInfoCall)(G,e);ed(r),ee(r)}catch(t){let e="Failed to update team member";t?.raw?.detail?.includes("Assigning team admins is a premium feature")?e="Assigning admins is an enterprise-only feature. Please upgrade your LiteLLM plan to enable this.":t?.message&&(e=t.message),eb(!1),j.message.destroy(),R.default.fromBackend(e),console.error("Error updating team member:",t)}},e4=async()=>{if(eF&&G){eU(!0);try{await (0,i.teamMemberDeleteCall)(G,e,eF),R.default.success("Team member removed successfully");let t=await (0,i.teamInfoCall)(G,e);ed(t),ee(t)}catch(e){R.default.fromBackend("Failed to remove team member"),console.error("Error removing team member:",e)}finally{eU(!1),eR(!1),eL(null)}}},e5=async t=>{try{let a;if(!G)return;eK(!0);let r={};try{let{soft_budget_alerting_emails:e,...a}=t.metadata?JSON.parse(t.metadata):{};r=a}catch(e){R.default.fromBackend("Invalid JSON in metadata field");return}if("string"==typeof t.secret_manager_settings&&t.secret_manager_settings.trim().length>0)try{a=JSON.parse(t.secret_manager_settings)}catch(e){R.default.fromBackend("Invalid JSON in secret manager settings");return}let l=e=>null==e||"string"==typeof e&&""===e.trim()||"number"==typeof e&&Number.isNaN(e)?null:e,s={team_id:e,team_alias:t.team_alias,models:t.models,tpm_limit:l(t.tpm_limit),rpm_limit:l(t.rpm_limit),max_budget:t.max_budget,soft_budget:l(t.soft_budget),budget_duration:t.budget_duration,metadata:{...r,...t.guardrails?.length>0?{guardrails:t.guardrails}:{},...t.logging_settings?.length>0?{logging:t.logging_settings}:{},disable_global_guardrails:t.disable_global_guardrails||!1,soft_budget_alerting_emails:"string"==typeof t.soft_budget_alerting_emails?t.soft_budget_alerting_emails.split(",").map(e=>e.trim()).filter(e=>e.length>0):t.soft_budget_alerting_emails||[],...void 0!==a?{secret_manager_settings:a}:{}},...t.policies?.length>0?{policies:t.policies}:{},organization_id:t.organization_id};s.max_budget=(0,n.mapEmptyStringToNull)(s.max_budget),s.team_member_budget_duration=t.team_member_budget_duration,void 0!==t.team_member_budget&&(s.team_member_budget=Number(t.team_member_budget)),void 0!==t.team_member_key_duration&&(s.team_member_key_duration=t.team_member_key_duration),(void 0!==t.team_member_tpm_limit||void 0!==t.team_member_rpm_limit)&&(s.team_member_tpm_limit=l(t.team_member_tpm_limit),s.team_member_rpm_limit=l(t.team_member_rpm_limit));let{servers:o,accessGroups:d}=t.mcp_servers_and_groups||{servers:[],accessGroups:[]},m=new Set(o||[]),c=Object.fromEntries(Object.entries(t.mcp_tool_permissions||{}).filter(([e])=>m.has(e)));s.object_permission={},o&&(s.object_permission.mcp_servers=o),d&&(s.object_permission.mcp_access_groups=d),c&&(s.object_permission.mcp_tool_permissions=c),delete t.mcp_servers_and_groups,delete t.mcp_tool_permissions;let{agents:u,accessGroups:g}=t.agents_and_groups||{agents:[],accessGroups:[]};u&&u.length>0&&(s.object_permission.agents=u),g&&g.length>0&&(s.object_permission.agent_access_groups=g),delete t.agents_and_groups,t.vector_stores&&t.vector_stores.length>0&&(s.object_permission.vector_stores=t.vector_stores),void 0!==t.access_group_ids&&(s.access_group_ids=t.access_group_ids),await (0,i.teamUpdateCall)(G,s),R.default.success("Team settings updated successfully"),ev(!1),e0()}catch(e){console.error("Error updating team:",e)}finally{eK(!1)}};if(em)return(0,t.jsx)("div",{className:"p-4",children:"Loading..."});if(!et?.team_info)return(0,t.jsx)("div",{className:"p-4",children:"Team not found"});let{team_info:e7}=et,e6=async(e,t)=>{await (0,s.copyToClipboard)(e)&&(eN(e=>({...e,[t]:!0})),setTimeout(()=>{eN(e=>({...e,[t]:!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)(y.Button,{type:"text",icon:(0,t.jsx)(u.ArrowLeftIcon,{className:"h-4 w-4"}),onClick:W,className:"mb-4",children:"Back to Teams"}),(0,t.jsx)(f.Title,{children:e7.team_alias}),(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)(x.Text,{className:"text-gray-500 font-mono",children:e7.team_id}),(0,t.jsx)(y.Button,{type:"text",size:"small",icon:ek["team-id"]?(0,t.jsx)(N.CheckIcon,{size:12}):(0,t.jsx)(T.CopyIcon,{size:12}),onClick:()=>e6(e7.team_id,"team-id"),className:`left-2 z-10 transition-all duration-200 ${ek["team-id"]?"text-green-600 bg-green-50 border-green-200":"text-gray-500 hover:text-gray-700 hover:bg-gray-100"}`})]})]})}),(0,t.jsx)(S.Tabs,{defaultActiveKey:eZ,className:"mb-4",items:[{key:er,label:eo[er],children:(0,t.jsxs)(p.Grid,{numItems:1,numItemsSm:2,numItemsLg:3,className:"gap-6",children:[(0,t.jsxs)(h.Card,{children:[(0,t.jsx)(x.Text,{children:"Budget Status"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(f.Title,{children:["$",(0,s.formatNumberWithCommas)(e7.spend,4)]}),(0,t.jsxs)(x.Text,{children:["of ",null===e7.max_budget?"Unlimited":`$${(0,s.formatNumberWithCommas)(e7.max_budget,4)}`]}),e7.budget_duration&&(0,t.jsxs)(x.Text,{className:"text-gray-500",children:["Reset: ",e7.budget_duration]}),(0,t.jsx)("br",{}),e7.team_member_budget_table&&(0,t.jsxs)(x.Text,{className:"text-gray-500",children:["Team Member Budget: $",(0,s.formatNumberWithCommas)(e7.team_member_budget_table.max_budget,4)]})]})]}),(0,t.jsxs)(h.Card,{children:[(0,t.jsx)(x.Text,{children:"Rate Limits"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(x.Text,{children:["TPM: ",e7.tpm_limit||"Unlimited"]}),(0,t.jsxs)(x.Text,{children:["RPM: ",e7.rpm_limit||"Unlimited"]}),e7.max_parallel_requests&&(0,t.jsxs)(x.Text,{children:["Max Parallel Requests: ",e7.max_parallel_requests]})]})]}),(0,t.jsxs)(h.Card,{children:[(0,t.jsx)(x.Text,{children:"Models"}),(0,t.jsx)("div",{className:"mt-2 flex flex-wrap gap-2",children:0===e7.models.length?(0,t.jsx)(g.Badge,{color:"red",children:"All proxy models"}):e7.models.map((e,a)=>(0,t.jsx)(g.Badge,{color:"red",children:e},a))})]}),(0,t.jsxs)(h.Card,{children:[(0,t.jsx)(x.Text,{className:"font-semibold text-gray-900",children:"Virtual Keys"}),(0,t.jsxs)("div",{className:"mt-2",children:[(0,t.jsxs)(x.Text,{children:["User Keys: ",et.keys.filter(e=>e.user_id).length]}),(0,t.jsxs)(x.Text,{children:["Service Account Keys: ",et.keys.filter(e=>!e.user_id).length]}),(0,t.jsxs)(x.Text,{className:"text-gray-500",children:["Total: ",et.keys.length]})]})]}),(0,t.jsx)(B.default,{objectPermission:e7.object_permission,variant:"card",accessToken:G}),(0,t.jsxs)(h.Card,{children:[(0,t.jsx)(x.Text,{className:"font-semibold text-gray-900 mb-3",children:"Guardrails"}),e7.guardrails&&e7.guardrails.length>0?(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:e7.guardrails.map((e,a)=>(0,t.jsx)(g.Badge,{color:"blue",children:e},a))}):(0,t.jsx)(x.Text,{className:"text-gray-500",children:"No guardrails configured"}),e7.metadata?.disable_global_guardrails&&(0,t.jsx)("div",{className:"mt-3 pt-3 border-t border-gray-200",children:(0,t.jsx)(g.Badge,{color:"yellow",children:"Global Guardrails Disabled"})})]}),(0,t.jsxs)(h.Card,{children:[(0,t.jsx)(x.Text,{className:"font-semibold text-gray-900 mb-3",children:"Policies"}),e7.policies&&e7.policies.length>0?(0,t.jsx)("div",{className:"space-y-4",children:e7.policies.map((e,a)=>(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(g.Badge,{color:"purple",children:e}),eD&&(0,t.jsx)(x.Text,{className:"text-xs text-gray-400",children:"Loading guardrails..."})]}),!eD&&eE[e]&&eE[e].length>0&&(0,t.jsxs)("div",{className:"ml-4 pl-3 border-l-2 border-gray-200",children:[(0,t.jsx)(x.Text,{className:"text-xs text-gray-500 mb-1",children:"Resolved Guardrails:"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-1",children:eE[e].map((e,a)=>(0,t.jsx)(g.Badge,{color:"blue",size:"xs",children:e},a))})]})]},a))}):(0,t.jsx)(x.Text,{className:"text-gray-500",children:"No policies configured"})]}),(0,t.jsx)($.default,{loggingConfigs:e7.metadata?.logging||[],disabledCallbacks:[],variant:"card"})]})},{key:el,label:eo[el],children:(0,t.jsx)(eI,{teamId:e,teamAlias:e7.team_alias,organization:eq})},{key:ei,label:eo[ei],children:(0,t.jsx)(eg,{teamData:et,canEditTeam:eY,handleMemberDelete:e=>{eL(e),eR(!0)},setSelectedEditMember:ey,setIsEditMemberModalVisible:eb,setIsAddMemberModalVisible:eh})},{key:es,label:eo[es],children:(0,t.jsx)(ea,{teamId:e,accessToken:G,canEditTeam:eY})},{key:en,label:eo[en],children:(0,t.jsxs)(h.Card,{className:"overflow-y-auto max-h-[65vh]",children:[(0,t.jsxs)("div",{className:"flex justify-between items-center mb-4",children:[(0,t.jsx)(f.Title,{children:"Team Settings"}),eY&&!e_&&(0,t.jsx)(y.Button,{icon:(0,t.jsx)(d.EditOutlined,{className:"h-4 w-4"}),onClick:()=>ev(!0),children:"Edit Settings"})]}),e_?(0,t.jsxs)(_.Form,{form:ep,onFinish:e5,initialValues:{...e7,team_alias:e7.team_alias,models:e7.models,tpm_limit:e7.tpm_limit,rpm_limit:e7.rpm_limit,max_budget:e7.max_budget,soft_budget:e7.soft_budget,budget_duration:e7.budget_duration,team_member_tpm_limit:e7.team_member_budget_table?.tpm_limit,team_member_rpm_limit:e7.team_member_budget_table?.rpm_limit,team_member_budget:e7.team_member_budget_table?.max_budget,team_member_budget_duration:e7.team_member_budget_table?.budget_duration,guardrails:e7.metadata?.guardrails||[],policies:e7.policies||[],disable_global_guardrails:e7.metadata?.disable_global_guardrails||!1,soft_budget_alerting_emails:Array.isArray(e7.metadata?.soft_budget_alerting_emails)?e7.metadata.soft_budget_alerting_emails.join(", "):"",metadata:e7.metadata?JSON.stringify((({logging:e,secret_manager_settings:t,soft_budget_alerting_emails:a,...r})=>r)(e7.metadata),null,2):"",logging_settings:e7.metadata?.logging||[],secret_manager_settings:e7.metadata?.secret_manager_settings?JSON.stringify(e7.metadata.secret_manager_settings,null,2):"",organization_id:e7.organization_id,vector_stores:e7.object_permission?.vector_stores||[],mcp_servers:e7.object_permission?.mcp_servers||[],mcp_access_groups:e7.object_permission?.mcp_access_groups||[],mcp_servers_and_groups:{servers:e7.object_permission?.mcp_servers||[],accessGroups:e7.object_permission?.mcp_access_groups||[]},mcp_tool_permissions:e7.object_permission?.mcp_tool_permissions||{},agents_and_groups:{agents:e7.object_permission?.agents||[],accessGroups:e7.object_permission?.agent_access_groups||[]},access_group_ids:e7.access_group_ids||[]},layout:"vertical",children:[(0,t.jsx)(_.Form.Item,{label:"Team Name",name:"team_alias",rules:[{required:!0,message:"Please input a team name"}],children:(0,t.jsx)(v.Input,{type:""})}),(0,t.jsx)(_.Form.Item,{label:"Models",name:"models",rules:[{required:!0,message:"Please select at least one model"}],children:(0,t.jsx)(A.ModelSelect,{value:ep.getFieldValue("models")||[],onChange:e=>ep.setFieldValue("models",e),teamID:e,organizationID:et?.team_info?.organization_id||void 0,options:{includeSpecialOptions:!0,includeUserModels:!et?.team_info?.organization_id,showAllProxyModelsOverride:(0,o.isProxyAdminRole)(eG)&&!et?.team_info?.organization_id},context:"team",dataTestId:"models-select"})}),(0,t.jsx)(_.Form.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,t.jsx)(U.default,{step:.01,precision:2,style:{width:"100%"}})}),(0,t.jsx)(_.Form.Item,{label:"Soft Budget (USD)",name:"soft_budget",children:(0,t.jsx)(U.default,{step:.01,precision:2,style:{width:"100%"}})}),(0,t.jsx)(_.Form.Item,{label:"Soft Budget Alerting Emails",name:"soft_budget_alerting_emails",tooltip:"Comma-separated email addresses to receive alerts when the soft budget is reached",children:(0,t.jsx)(v.Input,{placeholder:"example1@test.com, example2@test.com"})}),(0,t.jsx)(_.Form.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)(U.default,{step:.01,precision:2,style:{width:"100%"}})}),(0,t.jsx)(_.Form.Item,{label:"Team Member Budget Duration",name:"team_member_budget_duration",children:(0,t.jsx)(E,{onChange:e=>ep.setFieldValue("team_member_budget_duration",e),value:ep.getFieldValue("team_member_budget_duration")})}),(0,t.jsx)(_.Form.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)(b.TextInput,{placeholder:"e.g., 30d"})}),(0,t.jsx)(_.Form.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)(U.default,{step:1,style:{width:"100%"},placeholder:"e.g., 1000"})}),(0,t.jsx)(_.Form.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)(U.default,{step:1,style:{width:"100%"},placeholder:"e.g., 100"})}),(0,t.jsx)(_.Form.Item,{label:"Reset Budget",name:"budget_duration",children:(0,t.jsxs)(w.Select,{placeholder:"n/a",children:[(0,t.jsx)(w.Select.Option,{value:"24h",children:"daily"}),(0,t.jsx)(w.Select.Option,{value:"7d",children:"weekly"}),(0,t.jsx)(w.Select.Option,{value:"30d",children:"monthly"})]})}),(0,t.jsx)(_.Form.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,t.jsx)(U.default,{step:1,style:{width:"100%"}})}),(0,t.jsx)(_.Form.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,t.jsx)(U.default,{step:1,style:{width:"100%"}})}),(0,t.jsx)(_.Form.Item,{label:(0,t.jsxs)("span",{children:["Guardrails"," ",(0,t.jsx)(k.Tooltip,{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.InfoCircleOutlined,{style:{marginLeft:"4px"}})})})]}),name:"guardrails",help:"Select existing guardrails or enter new ones",children:(0,t.jsx)(w.Select,{mode:"tags",placeholder:"Select or enter guardrails",options:eT.map(e=>({value:e,label:e}))})}),(0,t.jsx)(_.Form.Item,{label:(0,t.jsxs)("span",{children:["Disable Global Guardrails",(0,t.jsx)(k.Tooltip,{title:"When enabled, this team will bypass any guardrails configured to run on every request (global guardrails)",children:(0,t.jsx)(m.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"disable_global_guardrails",valuePropName:"checked",help:"Bypass global guardrails for this team",children:(0,t.jsx)(C.Switch,{checkedChildren:"Yes",unCheckedChildren:"No"})}),(0,t.jsx)(_.Form.Item,{label:(0,t.jsxs)("span",{children:["Policies"," ",(0,t.jsx)(k.Tooltip,{title:"Apply policies to this team to control guardrails and other settings",children:(0,t.jsx)("a",{href:"https://docs.litellm.ai/docs/proxy/guardrails/guardrail_policies",target:"_blank",rel:"noopener noreferrer",onClick:e=>e.stopPropagation(),children:(0,t.jsx)(m.InfoCircleOutlined,{style:{marginLeft:"4px"}})})})]}),name:"policies",help:"Select existing policies or enter new ones",children:(0,t.jsx)(w.Select,{mode:"tags",placeholder:"Select or enter policies",options:eO.map(e=>({value:e,label:e}))})}),(0,t.jsx)(_.Form.Item,{label:(0,t.jsxs)("span",{children:["Access Groups"," ",(0,t.jsx)(k.Tooltip,{title:"Assign access groups to this team. Access groups control which models, MCP servers, and agents this team can use",children:(0,t.jsx)(m.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"access_group_ids",children:(0,t.jsx)(M.default,{placeholder:"Select access groups (optional)"})}),(0,t.jsx)(_.Form.Item,{label:"Vector Stores",name:"vector_stores","aria-label":"Vector Stores",children:(0,t.jsx)(V.default,{onChange:e=>ep.setFieldValue("vector_stores",e),value:ep.getFieldValue("vector_stores"),accessToken:G||"",placeholder:"Select vector stores"})}),(0,t.jsx)(_.Form.Item,{label:"Allowed Pass Through Routes",name:"allowed_passthrough_routes",children:(0,t.jsx)(P.default,{onChange:e=>ep.setFieldValue("allowed_passthrough_routes",e),value:ep.getFieldValue("allowed_passthrough_routes"),accessToken:G||"",placeholder:"Select pass through routes"})}),(0,t.jsx)(_.Form.Item,{label:"MCP Servers / Access Groups",name:"mcp_servers_and_groups",children:(0,t.jsx)(F.default,{onChange:e=>ep.setFieldValue("mcp_servers_and_groups",e),value:ep.getFieldValue("mcp_servers_and_groups"),accessToken:G||"",placeholder:"Select MCP servers or access groups (optional)"})}),(0,t.jsx)(_.Form.Item,{name:"mcp_tool_permissions",initialValue:{},hidden:!0,children:(0,t.jsx)(v.Input,{type:"hidden"})}),(0,t.jsx)(_.Form.Item,{noStyle:!0,shouldUpdate:(e,t)=>e.mcp_servers_and_groups!==t.mcp_servers_and_groups||e.mcp_tool_permissions!==t.mcp_tool_permissions,children:()=>(0,t.jsx)("div",{className:"mb-6",children:(0,t.jsx)(L.default,{accessToken:G||"",selectedServers:ep.getFieldValue("mcp_servers_and_groups")?.servers||[],toolPermissions:ep.getFieldValue("mcp_tool_permissions")||{},onChange:e=>ep.setFieldsValue({mcp_tool_permissions:e})})})}),(0,t.jsx)(_.Form.Item,{label:"Agents / Access Groups",name:"agents_and_groups",children:(0,t.jsx)(O.default,{onChange:e=>ep.setFieldValue("agents_and_groups",e),value:ep.getFieldValue("agents_and_groups"),accessToken:G||"",placeholder:"Select agents or access groups (optional)"})}),(0,t.jsx)(_.Form.Item,{label:"Organization ID",name:"organization_id",children:(0,t.jsx)(v.Input,{type:"",disabled:!0})}),(0,t.jsx)(_.Form.Item,{label:"Logging Settings",name:"logging_settings",children:(0,t.jsx)(K.default,{value:ep.getFieldValue("logging_settings"),onChange:e=>ep.setFieldValue("logging_settings",e)})}),(0,t.jsx)(_.Form.Item,{label:"Secret Manager Settings",name:"secret_manager_settings",help:Z?"Enter secret manager configuration as a JSON object.":"Premium feature - Upgrade to manage secret manager settings.",rules:[{validator:async(e,t)=>{if(!t)return Promise.resolve();try{return JSON.parse(t),Promise.resolve()}catch(e){return Promise.reject(Error("Please enter valid JSON"))}}}],children:(0,t.jsx)(v.Input.TextArea,{rows:6,placeholder:'{"namespace": "admin", "mount": "secret", "path_prefix": "litellm"}',disabled:!Z})}),(0,t.jsx)(_.Form.Item,{label:"Metadata",name:"metadata",children:(0,t.jsx)(v.Input.TextArea,{rows:10})}),(0,t.jsx)("div",{className:"sticky z-10 bg-white p-4 pr-0 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)(y.Button,{onClick:()=>ev(!1),disabled:eV,children:"Cancel"}),(0,t.jsx)(y.Button,{icon:(0,t.jsx)(c.SaveOutlined,{className:"h-4 w-4"}),type:"primary",htmlType:"submit",loading:eV,children:"Save Changes"})]})})]}):(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Team Name"}),(0,t.jsx)("div",{children:e7.team_alias})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Team ID"}),(0,t.jsx)("div",{className:"font-mono",children:e7.team_id})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Created At"}),(0,t.jsx)("div",{children:new Date(e7.created_at).toLocaleString()})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Models"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2 mt-1",children:e7.models.map((e,a)=>(0,t.jsx)(g.Badge,{color:"red",children:e},a))})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Rate Limits"}),(0,t.jsxs)("div",{children:["TPM: ",e7.tpm_limit||"Unlimited"]}),(0,t.jsxs)("div",{children:["RPM: ",e7.rpm_limit||"Unlimited"]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Team Budget"}),(0,t.jsxs)("div",{children:["Max Budget:"," ",null!==e7.max_budget?`$${(0,s.formatNumberWithCommas)(e7.max_budget,4)}`:"No Limit"]}),(0,t.jsxs)("div",{children:["Soft Budget:"," ",null!==e7.soft_budget&&void 0!==e7.soft_budget?`$${(0,s.formatNumberWithCommas)(e7.soft_budget,4)}`:"No Limit"]}),(0,t.jsxs)("div",{children:["Budget Reset: ",e7.budget_duration||"Never"]}),e7.metadata?.soft_budget_alerting_emails&&Array.isArray(e7.metadata.soft_budget_alerting_emails)&&e7.metadata.soft_budget_alerting_emails.length>0&&(0,t.jsxs)("div",{children:["Soft Budget Alerting Emails: ",e7.metadata.soft_budget_alerting_emails.join(", ")]})]}),(0,t.jsxs)("div",{children:[(0,t.jsxs)(x.Text,{className:"font-medium",children:["Team Member Settings"," ",(0,t.jsx)(k.Tooltip,{title:"These are limits on individual team members",children:(0,t.jsx)(m.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),(0,t.jsxs)("div",{children:["Max Budget: ",e7.team_member_budget_table?.max_budget||"No Limit"]}),(0,t.jsxs)("div",{children:["Budget Duration: ",e7.team_member_budget_table?.budget_duration||"No Limit"]}),(0,t.jsxs)("div",{children:["Key Duration: ",e7.metadata?.team_member_key_duration||"No Limit"]}),(0,t.jsxs)("div",{children:["TPM Limit: ",e7.team_member_budget_table?.tpm_limit||"No Limit"]}),(0,t.jsxs)("div",{children:["RPM Limit: ",e7.team_member_budget_table?.rpm_limit||"No Limit"]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Organization ID"}),(0,t.jsx)("div",{children:e7.organization_id})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Status"}),(0,t.jsx)(g.Badge,{color:e7.blocked?"red":"green",children:e7.blocked?"Blocked":"Active"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Disable Global Guardrails"}),(0,t.jsx)("div",{children:e7.metadata?.disable_global_guardrails===!0?(0,t.jsx)(g.Badge,{color:"yellow",children:"Enabled - Global guardrails bypassed"}):(0,t.jsx)(g.Badge,{color:"green",children:"Disabled - Global guardrails active"})})]}),(0,t.jsx)(B.default,{objectPermission:e7.object_permission,variant:"inline",className:"pt-4 border-t border-gray-200",accessToken:G}),(0,t.jsx)($.default,{loggingConfigs:e7.metadata?.logging||[],disabledCallbacks:[],variant:"inline",className:"pt-4 border-t border-gray-200"}),e7.metadata?.secret_manager_settings&&(0,t.jsxs)("div",{className:"pt-4 border-t border-gray-200",children:[(0,t.jsx)(x.Text,{className:"font-medium",children:"Secret Manager Settings"}),(0,t.jsx)("pre",{className:"mt-2 bg-gray-50 p-3 rounded text-xs overflow-x-auto",children:JSON.stringify(e7.metadata.secret_manager_settings,null,2)})]})]})]})}].filter(e=>eJ.includes(e.key))}),(0,t.jsx)(q.default,{visible:ex,onCancel:()=>eb(!1),onSubmit:e2,initialData:ef,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)(k.Tooltip,{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.InfoCircleOutlined,{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)(k.Tooltip,{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.InfoCircleOutlined,{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)(k.Tooltip,{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.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),type:"numerical",step:1,min:0,placeholder:"Requests per minute limit for this member in this team"}]}}),(0,t.jsx)(l.default,{isVisible:eu,onCancel:()=>eh(!1),onSubmit:e1,accessToken:G,teamId:e}),(0,t.jsx)(z.default,{isOpen:eA,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:eF?.user_id,code:!0},{label:"Email",value:eF?.user_email},{label:"Role",value:eF?.role}],onCancel:()=>{eR(!1),eL(null)},onOk:e4,confirmLoading:eB})]})}],56567)},829672,836938,310730,e=>{"use strict";e.i(247167);var t=e.i(271645),a=e.i(343794),r=e.i(914949),l=e.i(404948);let i=e=>e?"function"==typeof e?e():e:null;e.s(["getRenderPropValue",0,i],836938);var s=e.i(613541),n=e.i(763731),o=e.i(242064),d=e.i(491816);e.i(793154);var m=e.i(880476),c=e.i(183293),u=e.i(717356),g=e.i(320560),h=e.i(307358),p=e.i(246422),x=e.i(838378),b=e.i(617933);let f=(0,p.genStyleHooks)("Popover",e=>{let{colorBgElevated:t,colorText:a}=e,r=(0,x.mergeToken)(e,{popoverBg:t,popoverColor:a});return[(e=>{let{componentCls:t,popoverColor:a,titleMinWidth:r,fontWeightStrong:l,innerPadding:i,boxShadowSecondary:s,colorTextHeading:n,borderRadiusLG:o,zIndexPopup:d,titleMarginBottom:m,colorBgElevated:u,popoverBg:h,titleBorderBottom:p,innerContentPadding:x,titlePadding:b}=e;return[{[t]:Object.assign(Object.assign({},(0,c.resetComponent)(e)),{position:"absolute",top:0,left:{_skip_check_:!0,value:0},zIndex:d,fontWeight:"normal",whiteSpace:"normal",textAlign:"start",cursor:"auto",userSelect:"text","--valid-offset-x":"var(--arrow-offset-horizontal, var(--arrow-x))",transformOrigin:"var(--valid-offset-x, 50%) var(--arrow-y, 50%)","--antd-arrow-background-color":u,width:"max-content",maxWidth:"100vw","&-rtl":{direction:"rtl"},"&-hidden":{display:"none"},[`${t}-content`]:{position:"relative"},[`${t}-inner`]:{backgroundColor:h,backgroundClip:"padding-box",borderRadius:o,boxShadow:s,padding:i},[`${t}-title`]:{minWidth:r,marginBottom:m,color:n,fontWeight:l,borderBottom:p,padding:b},[`${t}-inner-content`]:{color:a,padding:x}})},(0,g.default)(e,"var(--antd-arrow-background-color)"),{[`${t}-pure`]:{position:"relative",maxWidth:"none",margin:e.sizePopupArrow,display:"inline-block",[`${t}-content`]:{display:"inline-block"}}}]})(r),(e=>{let{componentCls:t}=e;return{[t]:b.PresetColors.map(a=>{let r=e[`${a}6`];return{[`&${t}-${a}`]:{"--antd-arrow-background-color":r,[`${t}-inner`]:{backgroundColor:r},[`${t}-arrow`]:{background:"transparent"}}}})}})(r),(0,u.initZoomMotion)(r,"zoom-big")]},e=>{let{lineWidth:t,controlHeight:a,fontHeight:r,padding:l,wireframe:i,zIndexPopupBase:s,borderRadiusLG:n,marginXS:o,lineType:d,colorSplit:m,paddingSM:c}=e,u=a-r;return Object.assign(Object.assign(Object.assign({titleMinWidth:177,zIndexPopup:s+30},(0,h.getArrowToken)(e)),(0,g.getArrowOffsetToken)({contentRadius:n,limitVerticalRadius:!0})),{innerPadding:12*!i,titleMarginBottom:i?0:o,titlePadding:i?`${u/2}px ${l}px ${u/2-t}px`:0,titleBorderBottom:i?`${t}px ${d} ${m}`:"none",innerContentPadding:i?`${c}px ${l}px`:0})},{resetStyle:!1,deprecatedTokens:[["width","titleMinWidth"],["minWidth","titleMinWidth"]]});var y=function(e,t){var a={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(a[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,r=Object.getOwnPropertySymbols(e);lt.indexOf(r[l])&&Object.prototype.propertyIsEnumerable.call(e,r[l])&&(a[r[l]]=e[r[l]]);return a};let _=({title:e,content:a,prefixCls:r})=>e||a?t.createElement(t.Fragment,null,e&&t.createElement("div",{className:`${r}-title`},e),a&&t.createElement("div",{className:`${r}-inner-content`},a)):null,v=e=>{let{hashId:r,prefixCls:l,className:s,style:n,placement:o="top",title:d,content:c,children:u}=e,g=i(d),h=i(c),p=(0,a.default)(r,l,`${l}-pure`,`${l}-placement-${o}`,s);return t.createElement("div",{className:p,style:n},t.createElement("div",{className:`${l}-arrow`}),t.createElement(m.Popup,Object.assign({},e,{className:r,prefixCls:l}),u||t.createElement(_,{prefixCls:l,title:g,content:h})))},j=e=>{let{prefixCls:r,className:l}=e,i=y(e,["prefixCls","className"]),{getPrefixCls:s}=t.useContext(o.ConfigContext),n=s("popover",r),[d,m,c]=f(n);return d(t.createElement(v,Object.assign({},i,{prefixCls:n,hashId:m,className:(0,a.default)(l,c)})))};e.s(["Overlay",0,_,"default",0,j],310730);var w=function(e,t){var a={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(a[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,r=Object.getOwnPropertySymbols(e);lt.indexOf(r[l])&&Object.prototype.propertyIsEnumerable.call(e,r[l])&&(a[r[l]]=e[r[l]]);return a};let C=t.forwardRef((e,m)=>{var c,u;let{prefixCls:g,title:h,content:p,overlayClassName:x,placement:b="top",trigger:y="hover",children:v,mouseEnterDelay:j=.1,mouseLeaveDelay:C=.1,onOpenChange:S,overlayStyle:k={},styles:N,classNames:T}=e,I=w(e,["prefixCls","title","content","overlayClassName","placement","trigger","children","mouseEnterDelay","mouseLeaveDelay","onOpenChange","overlayStyle","styles","classNames"]),{getPrefixCls:M,className:O,style:z,classNames:E,styles:P}=(0,o.useComponentConfig)("popover"),D=M("popover",g),[$,F,L]=f(D),A=M(),R=(0,a.default)(x,F,L,O,E.root,null==T?void 0:T.root),B=(0,a.default)(E.body,null==T?void 0:T.body),[U,V]=(0,r.default)(!1,{value:null!=(c=e.open)?c:e.visible,defaultValue:null!=(u=e.defaultOpen)?u:e.defaultVisible}),K=(e,t)=>{V(e,!0),null==S||S(e,t)},q=i(h),W=i(p);return $(t.createElement(d.default,Object.assign({placement:b,trigger:y,mouseEnterDelay:j,mouseLeaveDelay:C},I,{prefixCls:D,classNames:{root:R,body:B},styles:{root:Object.assign(Object.assign(Object.assign(Object.assign({},P.root),z),k),null==N?void 0:N.root),body:Object.assign(Object.assign({},P.body),null==N?void 0:N.body)},ref:m,open:U,onOpenChange:e=>{K(e)},overlay:q||W?t.createElement(_,{prefixCls:D,title:q,content:W}):null,transitionName:(0,s.getTransitionName)(A,"zoom-big",I.transitionName),"data-popover-inject":!0}),(0,n.cloneElement)(v,{onKeyDown:e=>{var a,r;(0,t.isValidElement)(v)&&(null==(r=null==v?void 0:(a=v.props).onKeyDown)||r.call(a,e)),e.keyCode===l.default.ESC&&K(!1,e)}})))});C._InternalPanelDoNotUseOrYouWillBeFired=j,e.s(["default",0,C],829672)},282786,e=>{"use strict";var t=e.i(829672);e.s(["Popover",()=>t.default])},751904,e=>{"use strict";var t=e.i(401361);e.s(["EditOutlined",()=>t.default])},434626,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"}))});e.s(["ExternalLinkIcon",0,a],434626)},902555,e=>{"use strict";var t=e.i(843476),a=e.i(591935),r=e.i(122577),l=e.i(278587),i=e.i(68155),s=e.i(360820),n=e.i(871943),o=e.i(434626),d=e.i(592968),m=e.i(115504),c=e.i(752978);function u({icon:e,onClick:a,className:r,disabled:l,dataTestId:i}){return l?(0,t.jsx)(c.Icon,{icon:e,size:"sm",className:"opacity-50 cursor-not-allowed","data-testid":i}):(0,t.jsx)(c.Icon,{icon:e,size:"sm",onClick:a,className:(0,m.cx)("cursor-pointer",r),"data-testid":i})}let g={Edit:{icon:a.PencilAltIcon,className:"hover:text-blue-600"},Delete:{icon:i.TrashIcon,className:"hover:text-red-600"},Test:{icon:r.PlayIcon,className:"hover:text-blue-600"},Regenerate:{icon:l.RefreshIcon,className:"hover:text-green-600"},Up:{icon:s.ChevronUpIcon,className:"hover:text-blue-600"},Down:{icon:n.ChevronDownIcon,className:"hover:text-blue-600"},Open:{icon:o.ExternalLinkIcon,className:"hover:text-green-600"}};function h({onClick:e,tooltipText:a,disabled:r=!1,disabledTooltipText:l,dataTestId:i,variant:s}){let{icon:n,className:o}=g[s];return(0,t.jsx)(d.Tooltip,{title:r?l:a,children:(0,t.jsx)("span",{children:(0,t.jsx)(u,{icon:n,onClick:e,className:o,disabled:r,dataTestId:i})})})}e.s(["default",()=>h],902555)},122577,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.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"}),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M21 12a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlayIcon",0,a],122577)},278587,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"}))});e.s(["RefreshIcon",0,a],278587)},207670,e=>{"use strict";function t(){for(var e,t,a=0,r="",l=arguments.length;at,"default",0,t])},728889,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(829087),l=e.i(480731),i=e.i(444755),s=e.i(673706),n=e.i(95779);let o={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"}},d={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:""}},c=(0,s.makeClassName)("Icon"),u=a.default.forwardRef((e,u)=>{let{icon:g,variant:h="simple",tooltip:p,size:x=l.Sizes.SM,color:b,className:f}=e,y=(0,t.__rest)(e,["icon","variant","tooltip","size","color","className"]),_=((e,t)=>{switch(e){case"simple":return{textColor:t?(0,s.getColorClassNames)(t,n.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:"",borderColor:"",ringColor:""};case"light":return{textColor:t?(0,s.getColorClassNames)(t,n.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:t?(0,i.tremorTwMerge)((0,s.getColorClassNames)(t,n.colorPalette.background).bgColor,"bg-opacity-20"):"bg-tremor-brand-muted dark:bg-dark-tremor-brand-muted",borderColor:"",ringColor:""};case"shadow":return{textColor:t?(0,s.getColorClassNames)(t,n.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:t?(0,i.tremorTwMerge)((0,s.getColorClassNames)(t,n.colorPalette.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:t?(0,s.getColorClassNames)(t,n.colorPalette.text).textColor:"text-tremor-brand-inverted dark:text-dark-tremor-brand-inverted",bgColor:t?(0,i.tremorTwMerge)((0,s.getColorClassNames)(t,n.colorPalette.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:t?(0,s.getColorClassNames)(t,n.colorPalette.text).textColor:"text-tremor-brand dark:text-dark-tremor-brand",bgColor:t?(0,i.tremorTwMerge)((0,s.getColorClassNames)(t,n.colorPalette.background).bgColor,"bg-opacity-20"):"bg-tremor-background dark:bg-dark-tremor-background",borderColor:t?(0,s.getColorClassNames)(t,n.colorPalette.ring).borderColor:"border-tremor-brand-subtle dark:border-dark-tremor-brand-subtle",ringColor:t?(0,i.tremorTwMerge)((0,s.getColorClassNames)(t,n.colorPalette.ring).ringColor,"ring-opacity-40"):"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"}}})(h,b),{tooltipProps:v,getReferenceProps:j}=(0,r.useTooltip)();return a.default.createElement("span",Object.assign({ref:(0,s.mergeRefs)([u,v.refs.setReference]),className:(0,i.tremorTwMerge)(c("root"),"inline-flex shrink-0 items-center justify-center",_.bgColor,_.textColor,_.borderColor,_.ringColor,m[h].rounded,m[h].border,m[h].shadow,m[h].ring,o[x].paddingX,o[x].paddingY,f)},j,y),a.default.createElement(r.default,Object.assign({text:p},v)),a.default.createElement(g,{className:(0,i.tremorTwMerge)(c("icon"),"shrink-0",d[x].height,d[x].width)}))});u.displayName="Icon",e.s(["default",()=>u],728889)},752978,e=>{"use strict";var t=e.i(728889);e.s(["Icon",()=>t.default])},591935,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"}))});e.s(["PencilAltIcon",0,a],591935)},100486,e=>{"use strict";e.i(247167);var t=e.i(931067),a=e.i(271645);let r={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M899.6 276.5L705 396.4 518.4 147.5a8.06 8.06 0 00-12.9 0L319 396.4 124.3 276.5c-5.7-3.5-13.1 1.2-12.2 7.9L188.5 865c1.1 7.9 7.9 14 16 14h615.1c8 0 14.9-6 15.9-14l76.4-580.6c.8-6.7-6.5-11.4-12.3-7.9zm-126 534.1H250.3l-53.8-409.4 139.8 86.1L512 252.9l175.7 234.4 139.8-86.1-53.9 409.4zM512 509c-62.1 0-112.6 50.5-112.6 112.6S449.9 734.2 512 734.2s112.6-50.5 112.6-112.6S574.1 509 512 509zm0 160.9c-26.6 0-48.2-21.6-48.2-48.3 0-26.6 21.6-48.3 48.2-48.3s48.2 21.6 48.2 48.3c0 26.6-21.6 48.3-48.2 48.3z"}}]},name:"crown",theme:"outlined"};var l=e.i(9583),i=a.forwardRef(function(e,i){return a.createElement(l.default,(0,t.default)({},e,{ref:i,icon:r}))});e.s(["CrownOutlined",0,i],100486)},621482,e=>{"use strict";var t=e.i(869230),a=e.i(992571),r=class extends t.QueryObserver{constructor(e,t){super(e,t)}bindMethods(){super.bindMethods(),this.fetchNextPage=this.fetchNextPage.bind(this),this.fetchPreviousPage=this.fetchPreviousPage.bind(this)}setOptions(e){super.setOptions({...e,behavior:(0,a.infiniteQueryBehavior)()})}getOptimisticResult(e){return e.behavior=(0,a.infiniteQueryBehavior)(),super.getOptimisticResult(e)}fetchNextPage(e){return this.fetch({...e,meta:{fetchMore:{direction:"forward"}}})}fetchPreviousPage(e){return this.fetch({...e,meta:{fetchMore:{direction:"backward"}}})}createResult(e,t){let{state:r}=e,l=super.createResult(e,t),{isFetching:i,isRefetching:s,isError:n,isRefetchError:o}=l,d=r.fetchMeta?.fetchMore?.direction,m=n&&"forward"===d,c=i&&"forward"===d,u=n&&"backward"===d,g=i&&"backward"===d;return{...l,fetchNextPage:this.fetchNextPage,fetchPreviousPage:this.fetchPreviousPage,hasNextPage:(0,a.hasNextPage)(t,r.data),hasPreviousPage:(0,a.hasPreviousPage)(t,r.data),isFetchNextPageError:m,isFetchingNextPage:c,isFetchPreviousPageError:u,isFetchingPreviousPage:g,isRefetchError:o&&!m&&!u,isRefetching:s&&!c&&!g}}},l=e.i(469637);function i(e,t){return(0,l.useBaseQuery)(e,r,t)}e.s(["useInfiniteQuery",()=>i],621482)},785242,e=>{"use strict";var t=e.i(619273),a=e.i(266027),r=e.i(912598),l=e.i(135214),i=e.i(270345),s=e.i(243652),n=e.i(764205);let o=(0,s.createQueryKeys)("teams"),d=async(e,t,a,r={})=>{try{let l=(0,n.getProxyBaseUrl)(),i=new URLSearchParams(Object.entries({team_id:r.teamID,organization_id:r.organizationID,team_alias:r.team_alias,user_id:r.userID,page:t,page_size:a,sort_by:r.sortBy,sort_order:r.sortOrder,status:"deleted"}).filter(([,e])=>null!=e).map(([e,t])=>[e,String(t)])),s=`${l?`${l}/v2/team/list`:"/v2/team/list"}?${i}`,o=await fetch(s,{method:"GET",headers:{[(0,n.getGlobalLitellmHeaderName)()]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=(0,n.deriveErrorMessage)(e);throw(0,n.handleError)(t),Error(t)}let d=await o.json();if(console.log("/team/list?status=deleted API Response:",d),d&&"object"==typeof d&&"teams"in d)return d.teams;return d}catch(e){throw console.error("Failed to list deleted teams:",e),e}},m=(0,s.createQueryKeys)("deletedTeams");e.s(["useDeletedTeams",0,(e,r,i={})=>{let{accessToken:s}=(0,l.default)();return(0,a.useQuery)({queryKey:m.list({page:e,limit:r,...i}),queryFn:async()=>await d(s,e,r,i),enabled:!!s,staleTime:3e4,placeholderData:t.keepPreviousData})},"useTeam",0,e=>{let{accessToken:t}=(0,l.default)(),i=(0,r.useQueryClient)();return(0,a.useQuery)({queryKey:o.detail(e),enabled:!!(t&&e),queryFn:async()=>{if(!t||!e)throw Error("Missing auth or teamId");return(0,n.teamInfoCall)(t,e)},initialData:()=>{if(!e)return;let t=i.getQueryData(o.list({}));return t?.find(t=>t.team_id===e)}})},"useTeams",0,()=>{let{accessToken:e,userId:t,userRole:r}=(0,l.default)();return(0,a.useQuery)({queryKey:o.list({}),queryFn:async()=>await (0,i.fetchTeams)(e,t,r,null),enabled:!!e})}])},738014,e=>{"use strict";var t=e.i(135214),a=e.i(764205),r=e.i(266027);let l=(0,e.i(243652).createQueryKeys)("users");e.s(["useCurrentUser",0,()=>{let{accessToken:e,userId:i}=(0,t.default)();return(0,r.useQuery)({queryKey:l.detail(i),queryFn:async()=>await (0,a.userGetInfoV2)(e),enabled:!!(e&&i)})}])},907308,e=>{"use strict";var t=e.i(843476),a=e.i(271645),r=e.i(212931),l=e.i(808613),i=e.i(464571),s=e.i(199133),n=e.i(592968),o=e.i(213205),d=e.i(374009),m=e.i(764205);e.s(["default",0,({isVisible:e,onCancel:c,onSubmit:u,accessToken:g,title:h="Add Team Member",roles:p=[{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:x="user",teamId:b})=>{let[f]=l.Form.useForm(),[y,_]=(0,a.useState)([]),[v,j]=(0,a.useState)(!1),[w,C]=(0,a.useState)("user_email"),[S,k]=(0,a.useState)(!1),N=async(e,t)=>{if(!e)return void _([]);j(!0);try{let a=new URLSearchParams;if(a.append(t,e),b&&a.append("team_id",b),null==g)return;let r=(await (0,m.userFilterUICall)(g,a)).map(e=>({label:"user_email"===t?`${e.user_email}`:`${e.user_id}`,value:"user_email"===t?e.user_email:e.user_id,user:e}));_(r)}catch(e){console.error("Error fetching users:",e)}finally{j(!1)}},T=(0,a.useCallback)((0,d.default)((e,t)=>N(e,t),300),[]),I=(e,t)=>{C(t),T(e,t)},M=(e,t)=>{let a=t.user;f.setFieldsValue({user_email:a.user_email,user_id:a.user_id,role:f.getFieldValue("role")})},O=async e=>{k(!0);try{await u(e)}finally{k(!1)}};return(0,t.jsx)(r.Modal,{title:h,open:e,onCancel:()=>{f.resetFields(),_([]),c()},footer:null,width:800,maskClosable:!S,children:(0,t.jsxs)(l.Form,{form:f,onFinish:O,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",initialValues:{role:x},children:[(0,t.jsx)(l.Form.Item,{label:"Email",name:"user_email",className:"mb-4",children:(0,t.jsx)(s.Select,{showSearch:!0,className:"w-full",placeholder:"Search by email",filterOption:!1,onSearch:e=>I(e,"user_email"),onSelect:(e,t)=>M(e,t),options:"user_email"===w?y:[],loading:v,allowClear:!0})}),(0,t.jsx)("div",{className:"text-center mb-4",children:"OR"}),(0,t.jsx)(l.Form.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,t.jsx)(s.Select,{showSearch:!0,className:"w-full",placeholder:"Search by user ID",filterOption:!1,onSearch:e=>I(e,"user_id"),onSelect:(e,t)=>M(e,t),options:"user_id"===w?y:[],loading:v,allowClear:!0})}),(0,t.jsx)(l.Form.Item,{label:"Member Role",name:"role",className:"mb-4",children:(0,t.jsx)(s.Select,{defaultValue:x,children:p.map(e=>(0,t.jsx)(s.Select.Option,{value:e.value,children:(0,t.jsxs)(n.Tooltip,{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)(i.Button,{type:"primary",htmlType:"submit",icon:(0,t.jsx)(o.UserAddOutlined,{}),loading:S,children:S?"Adding...":"Add Member"})})]})})}])},162386,e=>{"use strict";var t=e.i(843476),a=e.i(625901),r=e.i(109799),l=e.i(785242),i=e.i(738014),s=e.i(199133),n=e.i(981339),o=e.i(592968);let d={label:"All Proxy Models",value:"all-proxy-models"},m={label:"No Default Models",value:"no-default-models"},c=[d,m],u={user:({allProxyModels:e,userModels:t,options:a})=>t&&a?.includeUserModels?t:[],team:({allProxyModels:e,selectedOrganization:t,userModels:a})=>t?t.models.includes(d.value)||0===t.models.length?e:e.filter(e=>t.models.includes(e)):e??[],organization:({allProxyModels:e})=>e,global:({allProxyModels:e})=>e};e.s(["ModelSelect",0,e=>{let{teamID:g,organizationID:h,options:p,context:x,dataTestId:b,value:f=[],onChange:y,style:_}=e,{includeUserModels:v,showAllTeamModelsOption:j,showAllProxyModelsOverride:w,includeSpecialOptions:C}=p||{},{data:S,isLoading:k}=(0,a.useAllProxyModels)(),{data:N,isLoading:T}=(0,l.useTeam)(g),{data:I,isLoading:M}=(0,r.useOrganization)(h),{data:O,isLoading:z}=(0,i.useCurrentUser)(),E=e=>c.some(t=>t.value===e),P=f.some(E),D=I?.models.includes(d.value)||I?.models.length===0;if(k||T||M||z)return(0,t.jsx)(n.Skeleton.Input,{active:!0,block:!0});let{wildcard:$,regular:F}=(e=>{let t=[],a=[];for(let r of e)r.endsWith("/*")?t.push(r):a.push(r);return{wildcard:t,regular:a}})(((e,t,a)=>{let r=Array.from(new Map(e.map(e=>[e.id,e])).values()).map(e=>e.id);if(t.options?.showAllProxyModelsOverride)return r;let l=u[t.context];return l?l({allProxyModels:r,...a,options:t.options}):[]})(S?.data??[],e,{selectedTeam:N,selectedOrganization:I,userModels:O?.models}));return(0,t.jsx)(s.Select,{"data-testid":b,value:f,onChange:e=>{let t=e.filter(E);y(t.length>0?[t[t.length-1]]:e)},style:_,options:[C?{label:(0,t.jsx)("span",{children:"Special Options"}),title:"Special Options",options:[...w||D&&C||"global"===x?[{label:(0,t.jsx)("span",{children:"All Proxy Models"}),value:d.value,disabled:f.length>0&&f.some(e=>E(e)&&e!==d.value),key:d.value}]:[],{label:(0,t.jsx)("span",{children:"No Default Models"}),value:m.value,disabled:f.length>0&&f.some(e=>E(e)&&e!==m.value),key:m.value}]}:[],...$.length>0?[{label:(0,t.jsx)("span",{children:"Wildcard Options"}),title:"Wildcard Options",options:$.map(e=>{let a=e.replace("/*",""),r=a.charAt(0).toUpperCase()+a.slice(1);return{label:(0,t.jsx)("span",{children:`All ${r} models`}),value:e,disabled:P}})}]:[],{label:(0,t.jsx)("span",{children:"Models"}),title:"Models",options:F.map(e=>({label:(0,t.jsx)("span",{children:e}),value:e,disabled:P}))}],mode:"multiple",placeholder:"Select Models",allowClear:!0,maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(o.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})})})}],162386)},276173,e=>{"use strict";var t=e.i(843476),a=e.i(599724),r=e.i(779241),l=e.i(464571),i=e.i(808613),s=e.i(212931),n=e.i(199133),o=e.i(271645),d=e.i(435451);e.s(["default",0,({visible:e,onCancel:m,onSubmit:c,initialData:u,mode:g,config:h})=>{let p,[x]=i.Form.useForm(),[b,f]=(0,o.useState)(!1);console.log("Initial Data:",u),(0,o.useEffect)(()=>{if(e)if("edit"===g&&u){let e={...u,role:u.role||h.defaultRole,max_budget_in_team:u.max_budget_in_team||null,tpm_limit:u.tpm_limit||null,rpm_limit:u.rpm_limit||null};console.log("Setting form values:",e),x.setFieldsValue(e)}else x.resetFields(),x.setFieldsValue({role:h.defaultRole||h.roleOptions[0]?.value})},[e,u,g,x,h.defaultRole,h.roleOptions]);let y=async e=>{try{f(!0);let t=Object.entries(e).reduce((e,[t,a])=>{if("string"==typeof a){let r=a.trim();return""===r&&("max_budget_in_team"===t||"tpm_limit"===t||"rpm_limit"===t)?{...e,[t]:null}:{...e,[t]:r}}return{...e,[t]:a}},{});console.log("Submitting form data:",t),await Promise.resolve(c(t)),x.resetFields()}catch(e){console.error("Form submission error:",e)}finally{f(!1)}};return(0,t.jsx)(s.Modal,{title:h.title||("add"===g?"Add Member":"Edit Member"),open:e,width:1e3,footer:null,onCancel:m,children:(0,t.jsxs)(i.Form,{form:x,onFinish:y,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[h.showEmail&&(0,t.jsx)(i.Form.Item,{label:"Email",name:"user_email",className:"mb-4",rules:[{type:"email",message:"Please enter a valid email!"}],children:(0,t.jsx)(r.TextInput,{placeholder:"user@example.com"})}),h.showEmail&&h.showUserId&&(0,t.jsx)("div",{className:"text-center mb-4",children:(0,t.jsx)(a.Text,{children:"OR"})}),h.showUserId&&(0,t.jsx)(i.Form.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,t.jsx)(r.TextInput,{placeholder:"user_123"})}),(0,t.jsx)(i.Form.Item,{label:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{children:"Role"}),"edit"===g&&u&&(0,t.jsxs)("span",{className:"text-gray-500 text-sm",children:["(Current: ",(p=u.role,h.roleOptions.find(e=>e.value===p)?.label||p),")"]})]}),name:"role",className:"mb-4",rules:[{required:!0,message:"Please select a role!"}],children:(0,t.jsx)(n.Select,{children:"edit"===g&&u?[...h.roleOptions.filter(e=>e.value===u.role),...h.roleOptions.filter(e=>e.value!==u.role)].map(e=>(0,t.jsx)(n.Select.Option,{value:e.value,children:e.label},e.value)):h.roleOptions.map(e=>(0,t.jsx)(n.Select.Option,{value:e.value,children:e.label},e.value))})}),h.additionalFields?.map(e=>(0,t.jsx)(i.Form.Item,{label:e.label,name:e.name,className:"mb-4",rules:e.rules,children:(e=>{switch(e.type){case"input":return(0,t.jsx)(r.TextInput,{placeholder:e.placeholder});case"numerical":return(0,t.jsx)(d.default,{step:e.step||1,min:e.min||0,style:{width:"100%"},placeholder:e.placeholder||"Enter a numerical value"});case"select":return(0,t.jsx)(n.Select,{children:e.options?.map(e=>(0,t.jsx)(n.Select.Option,{value:e.value,children:e.label},e.value))});default:return null}})(e)},e.name)),(0,t.jsxs)("div",{className:"text-right mt-6",children:[(0,t.jsx)(l.Button,{onClick:m,className:"mr-2",disabled:b,children:"Cancel"}),(0,t.jsx)(l.Button,{type:"default",htmlType:"submit",loading:b,children:"add"===g?b?"Adding...":"Add Member":b?"Saving...":"Save Changes"})]})]})})}])},294612,e=>{"use strict";var t=e.i(843476),a=e.i(100486),r=e.i(827252),l=e.i(213205),i=e.i(771674),s=e.i(464571),n=e.i(770914),o=e.i(291542),d=e.i(262218),m=e.i(592968),c=e.i(898586),u=e.i(902555);let{Text:g}=c.Typography;function h({members:e,canEdit:c,onEdit:h,onDelete:p,onAddMember:x,roleColumnTitle:b="Role",roleTooltip:f,extraColumns:y=[],showDeleteForMember:_,emptyText:v}){let j=[{title:"User Email",dataIndex:"user_email",key:"user_email",render:e=>(0,t.jsx)(g,{children:e||"-"})},{title:"User ID",dataIndex:"user_id",key:"user_id",render:e=>"default_user_id"===e?(0,t.jsx)(d.Tag,{color:"blue",children:"Default Proxy Admin"}):(0,t.jsx)(g,{children:e||"-"})},{title:f?(0,t.jsxs)(n.Space,{direction:"horizontal",children:[b,(0,t.jsx)(m.Tooltip,{title:f,children:(0,t.jsx)(r.InfoCircleOutlined,{})})]}):b,dataIndex:"role",key:"role",render:e=>(0,t.jsxs)(n.Space,{children:[e?.toLowerCase()==="admin"||e?.toLowerCase()==="org_admin"?(0,t.jsx)(a.CrownOutlined,{}):(0,t.jsx)(i.UserOutlined,{}),(0,t.jsx)(g,{style:{textTransform:"capitalize"},children:e||"-"})]})},...y,{title:"Actions",key:"actions",fixed:"right",width:120,render:(e,a)=>c?(0,t.jsxs)(n.Space,{children:[(0,t.jsx)(u.default,{variant:"Edit",tooltipText:"Edit member",dataTestId:"edit-member",onClick:()=>h(a)}),(!_||_(a))&&(0,t.jsx)(u.default,{variant:"Delete",tooltipText:"Delete member",dataTestId:"delete-member",onClick:()=>p(a)})]}):null}];return(0,t.jsxs)(n.Space,{direction:"vertical",style:{width:"100%"},children:[(0,t.jsxs)("span",{className:"inline-flex text-sm text-gray-700",children:[e.length," Member",1!==e.length?"s":""]}),(0,t.jsx)(o.Table,{columns:j,dataSource:e,rowKey:e=>e.user_id??e.user_email??JSON.stringify(e),pagination:!1,size:"small",scroll:{x:"max-content"},locale:v?{emptyText:v}:void 0}),x&&c&&(0,t.jsx)(s.Button,{icon:(0,t.jsx)(l.UserAddOutlined,{}),type:"primary",onClick:x,children:"Add Member"})]})}e.s(["default",()=>h])},94629,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4"}))});e.s(["SwitchVerticalIcon",0,a],94629)},244451,e=>{"use strict";let t;e.i(247167);var a=e.i(271645),r=e.i(343794),l=e.i(242064),i=e.i(763731),s=e.i(174428);let n=80*Math.PI,o=e=>{let{dotClassName:t,style:l,hasCircleCls:i}=e;return a.createElement("circle",{className:(0,r.default)(`${t}-circle`,{[`${t}-circle-bg`]:i}),r:40,cx:50,cy:50,strokeWidth:20,style:l})},d=({percent:e,prefixCls:t})=>{let l=`${t}-dot`,i=`${l}-holder`,d=`${i}-hidden`,[m,c]=a.useState(!1);(0,s.default)(()=>{0!==e&&c(!0)},[0!==e]);let u=Math.max(Math.min(e,100),0);if(!m)return null;let g={strokeDashoffset:`${n/4}`,strokeDasharray:`${n*u/100} ${n*(100-u)/100}`};return a.createElement("span",{className:(0,r.default)(i,`${l}-progress`,u<=0&&d)},a.createElement("svg",{viewBox:"0 0 100 100",role:"progressbar","aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":u},a.createElement(o,{dotClassName:l,hasCircleCls:!0}),a.createElement(o,{dotClassName:l,style:g})))};function m(e){let{prefixCls:t,percent:l=0}=e,i=`${t}-dot`,s=`${i}-holder`,n=`${s}-hidden`;return a.createElement(a.Fragment,null,a.createElement("span",{className:(0,r.default)(s,l>0&&n)},a.createElement("span",{className:(0,r.default)(i,`${t}-dot-spin`)},[1,2,3,4].map(e=>a.createElement("i",{className:`${t}-dot-item`,key:e})))),a.createElement(d,{prefixCls:t,percent:l}))}function c(e){var t;let{prefixCls:l,indicator:s,percent:n}=e,o=`${l}-dot`;return s&&a.isValidElement(s)?(0,i.cloneElement)(s,{className:(0,r.default)(null==(t=s.props)?void 0:t.className,o),percent:n}):a.createElement(m,{prefixCls:l,percent:n})}e.i(296059);var u=e.i(694758),g=e.i(183293),h=e.i(246422),p=e.i(838378);let x=new u.Keyframes("antSpinMove",{to:{opacity:1}}),b=new u.Keyframes("antRotate",{to:{transform:"rotate(405deg)"}}),f=(0,h.genStyleHooks)("Spin",e=>(e=>{let{componentCls:t,calc:a}=e;return{[t]:Object.assign(Object.assign({},(0,g.resetComponent)(e)),{position:"absolute",display:"none",color:e.colorPrimary,fontSize:0,textAlign:"center",verticalAlign:"middle",opacity:0,transition:`transform ${e.motionDurationSlow} ${e.motionEaseInOutCirc}`,"&-spinning":{position:"relative",display:"inline-block",opacity:1},[`${t}-text`]:{fontSize:e.fontSize,paddingTop:a(a(e.dotSize).sub(e.fontSize)).div(2).add(2).equal()},"&-fullscreen":{position:"fixed",width:"100vw",height:"100vh",backgroundColor:e.colorBgMask,zIndex:e.zIndexPopupBase,inset:0,display:"flex",alignItems:"center",flexDirection:"column",justifyContent:"center",opacity:0,visibility:"hidden",transition:`all ${e.motionDurationMid}`,"&-show":{opacity:1,visibility:"visible"},[t]:{[`${t}-dot-holder`]:{color:e.colorWhite},[`${t}-text`]:{color:e.colorTextLightSolid}}},"&-nested-loading":{position:"relative",[`> div > ${t}`]:{position:"absolute",top:0,insetInlineStart:0,zIndex:4,display:"block",width:"100%",height:"100%",maxHeight:e.contentHeight,[`${t}-dot`]:{position:"absolute",top:"50%",insetInlineStart:"50%",margin:a(e.dotSize).mul(-1).div(2).equal()},[`${t}-text`]:{position:"absolute",top:"50%",width:"100%",textShadow:`0 1px 2px ${e.colorBgContainer}`},[`&${t}-show-text ${t}-dot`]:{marginTop:a(e.dotSize).div(2).mul(-1).sub(10).equal()},"&-sm":{[`${t}-dot`]:{margin:a(e.dotSizeSM).mul(-1).div(2).equal()},[`${t}-text`]:{paddingTop:a(a(e.dotSizeSM).sub(e.fontSize)).div(2).add(2).equal()},[`&${t}-show-text ${t}-dot`]:{marginTop:a(e.dotSizeSM).div(2).mul(-1).sub(10).equal()}},"&-lg":{[`${t}-dot`]:{margin:a(e.dotSizeLG).mul(-1).div(2).equal()},[`${t}-text`]:{paddingTop:a(a(e.dotSizeLG).sub(e.fontSize)).div(2).add(2).equal()},[`&${t}-show-text ${t}-dot`]:{marginTop:a(e.dotSizeLG).div(2).mul(-1).sub(10).equal()}}},[`${t}-container`]:{position:"relative",transition:`opacity ${e.motionDurationSlow}`,"&::after":{position:"absolute",top:0,insetInlineEnd:0,bottom:0,insetInlineStart:0,zIndex:10,width:"100%",height:"100%",background:e.colorBgContainer,opacity:0,transition:`all ${e.motionDurationSlow}`,content:'""',pointerEvents:"none"}},[`${t}-blur`]:{clear:"both",opacity:.5,userSelect:"none",pointerEvents:"none","&::after":{opacity:.4,pointerEvents:"auto"}}},"&-tip":{color:e.spinDotDefault},[`${t}-dot-holder`]:{width:"1em",height:"1em",fontSize:e.dotSize,display:"inline-block",transition:`transform ${e.motionDurationSlow} ease, opacity ${e.motionDurationSlow} ease`,transformOrigin:"50% 50%",lineHeight:1,color:e.colorPrimary,"&-hidden":{transform:"scale(0.3)",opacity:0}},[`${t}-dot-progress`]:{position:"absolute",inset:0},[`${t}-dot`]:{position:"relative",display:"inline-block",fontSize:e.dotSize,width:"1em",height:"1em","&-item":{position:"absolute",display:"block",width:a(e.dotSize).sub(a(e.marginXXS).div(2)).div(2).equal(),height:a(e.dotSize).sub(a(e.marginXXS).div(2)).div(2).equal(),background:"currentColor",borderRadius:"100%",transform:"scale(0.75)",transformOrigin:"50% 50%",opacity:.3,animationName:x,animationDuration:"1s",animationIterationCount:"infinite",animationTimingFunction:"linear",animationDirection:"alternate","&:nth-child(1)":{top:0,insetInlineStart:0,animationDelay:"0s"},"&:nth-child(2)":{top:0,insetInlineEnd:0,animationDelay:"0.4s"},"&:nth-child(3)":{insetInlineEnd:0,bottom:0,animationDelay:"0.8s"},"&:nth-child(4)":{bottom:0,insetInlineStart:0,animationDelay:"1.2s"}},"&-spin":{transform:"rotate(45deg)",animationName:b,animationDuration:"1.2s",animationIterationCount:"infinite",animationTimingFunction:"linear"},"&-circle":{strokeLinecap:"round",transition:["stroke-dashoffset","stroke-dasharray","stroke","stroke-width","opacity"].map(t=>`${t} ${e.motionDurationSlow} ease`).join(","),fillOpacity:0,stroke:"currentcolor"},"&-circle-bg":{stroke:e.colorFillSecondary}},[`&-sm ${t}-dot`]:{"&, &-holder":{fontSize:e.dotSizeSM}},[`&-sm ${t}-dot-holder`]:{i:{width:a(a(e.dotSizeSM).sub(a(e.marginXXS).div(2))).div(2).equal(),height:a(a(e.dotSizeSM).sub(a(e.marginXXS).div(2))).div(2).equal()}},[`&-lg ${t}-dot`]:{"&, &-holder":{fontSize:e.dotSizeLG}},[`&-lg ${t}-dot-holder`]:{i:{width:a(a(e.dotSizeLG).sub(e.marginXXS)).div(2).equal(),height:a(a(e.dotSizeLG).sub(e.marginXXS)).div(2).equal()}},[`&${t}-show-text ${t}-text`]:{display:"block"}})}})((0,p.mergeToken)(e,{spinDotDefault:e.colorTextDescription})),e=>{let{controlHeightLG:t,controlHeight:a}=e;return{contentHeight:400,dotSize:t/2,dotSizeSM:.35*t,dotSizeLG:a}}),y=[[30,.05],[70,.03],[96,.01]];var _=function(e,t){var a={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&0>t.indexOf(r)&&(a[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,r=Object.getOwnPropertySymbols(e);lt.indexOf(r[l])&&Object.prototype.propertyIsEnumerable.call(e,r[l])&&(a[r[l]]=e[r[l]]);return a};let v=e=>{var i;let{prefixCls:s,spinning:n=!0,delay:o=0,className:d,rootClassName:m,size:u="default",tip:g,wrapperClassName:h,style:p,children:x,fullscreen:b=!1,indicator:v,percent:j}=e,w=_(e,["prefixCls","spinning","delay","className","rootClassName","size","tip","wrapperClassName","style","children","fullscreen","indicator","percent"]),{getPrefixCls:C,direction:S,className:k,style:N,indicator:T}=(0,l.useComponentConfig)("spin"),I=C("spin",s),[M,O,z]=f(I),[E,P]=a.useState(()=>n&&(!n||!o||!!Number.isNaN(Number(o)))),D=function(e,t){let[r,l]=a.useState(0),i=a.useRef(null),s="auto"===t;return a.useEffect(()=>(s&&e&&(l(0),i.current=setInterval(()=>{l(e=>{let t=100-e;for(let a=0;a{i.current&&(clearInterval(i.current),i.current=null)}),[s,e]),s?r:t}(E,j);a.useEffect(()=>{if(n){let e=function(e,t,a){var r,l=a||{},i=l.noTrailing,s=void 0!==i&&i,n=l.noLeading,o=void 0!==n&&n,d=l.debounceMode,m=void 0===d?void 0:d,c=!1,u=0;function g(){r&&clearTimeout(r)}function h(){for(var a=arguments.length,l=Array(a),i=0;ie?o?(u=Date.now(),s||(r=setTimeout(m?p:h,e))):h():!0!==s&&(r=setTimeout(m?p:h,void 0===m?e-d:e)))}return h.cancel=function(e){var t=(e||{}).upcomingOnly;g(),c=!(void 0!==t&&t)},h}(o,()=>{P(!0)},{debounceMode:false});return e(),()=>{var t;null==(t=null==e?void 0:e.cancel)||t.call(e)}}P(!1)},[o,n]);let $=a.useMemo(()=>void 0!==x&&!b,[x,b]),F=(0,r.default)(I,k,{[`${I}-sm`]:"small"===u,[`${I}-lg`]:"large"===u,[`${I}-spinning`]:E,[`${I}-show-text`]:!!g,[`${I}-rtl`]:"rtl"===S},d,!b&&m,O,z),L=(0,r.default)(`${I}-container`,{[`${I}-blur`]:E}),A=null!=(i=null!=v?v:T)?i:t,R=Object.assign(Object.assign({},N),p),B=a.createElement("div",Object.assign({},w,{style:R,className:F,"aria-live":"polite","aria-busy":E}),a.createElement(c,{prefixCls:I,indicator:A,percent:D}),g&&($||b)?a.createElement("div",{className:`${I}-text`},g):null);return M($?a.createElement("div",Object.assign({},w,{className:(0,r.default)(`${I}-nested-loading`,h,O,z)}),E&&a.createElement("div",{key:"loading"},B),a.createElement("div",{className:L,key:"container"},x)):b?a.createElement("div",{className:(0,r.default)(`${I}-fullscreen`,{[`${I}-fullscreen-show`]:E},m,O,z)},B):B)};v.setDefaultIndicator=e=>{t=e},e.s(["default",0,v],244451)},482725,e=>{"use strict";var t=e.i(244451);e.s(["Spin",()=>t.default])},269200,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(444755);let l=(0,e.i(673706).makeClassName)("Table"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement("div",{className:(0,r.tremorTwMerge)(l("root"),"overflow-auto",n)},a.default.createElement("table",Object.assign({ref:i,className:(0,r.tremorTwMerge)(l("table"),"w-full text-tremor-default","text-tremor-content","dark:text-dark-tremor-content")},o),s))});i.displayName="Table",e.s(["Table",()=>i],269200)},427612,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableHead"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement(a.default.Fragment,null,a.default.createElement("thead",Object.assign({ref:i,className:(0,r.tremorTwMerge)(l("root"),"text-left","text-tremor-content","dark:text-dark-tremor-content",n)},o),s))});i.displayName="TableHead",e.s(["TableHead",()=>i],427612)},64848,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableHeaderCell"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement(a.default.Fragment,null,a.default.createElement("th",Object.assign({ref:i,className:(0,r.tremorTwMerge)(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",n)},o),s))});i.displayName="TableHeaderCell",e.s(["TableHeaderCell",()=>i],64848)},942232,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableBody"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement(a.default.Fragment,null,a.default.createElement("tbody",Object.assign({ref:i,className:(0,r.tremorTwMerge)(l("root"),"align-top divide-y","divide-tremor-border","dark:divide-dark-tremor-border",n)},o),s))});i.displayName="TableBody",e.s(["TableBody",()=>i],942232)},496020,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableRow"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement(a.default.Fragment,null,a.default.createElement("tr",Object.assign({ref:i,className:(0,r.tremorTwMerge)(l("row"),n)},o),s))});i.displayName="TableRow",e.s(["TableRow",()=>i],496020)},977572,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(444755);let l=(0,e.i(673706).makeClassName)("TableCell"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement(a.default.Fragment,null,a.default.createElement("td",Object.assign({ref:i,className:(0,r.tremorTwMerge)(l("root"),"align-middle whitespace-nowrap text-left p-4",n)},o),s))});i.displayName="TableCell",e.s(["TableCell",()=>i],977572)},389083,e=>{"use strict";var t=e.i(290571),a=e.i(271645),r=e.i(829087),l=e.i(480731),i=e.i(95779),s=e.i(444755),n=e.i(673706);let o={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"}},d={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,n.makeClassName)("Badge"),c=a.default.forwardRef((e,c)=>{let{color:u,icon:g,size:h=l.Sizes.SM,tooltip:p,className:x,children:b}=e,f=(0,t.__rest)(e,["color","icon","size","tooltip","className","children"]),y=g||null,{tooltipProps:_,getReferenceProps:v}=(0,r.useTooltip)();return a.default.createElement("span",Object.assign({ref:(0,n.mergeRefs)([c,_.refs.setReference]),className:(0,s.tremorTwMerge)(m("root"),"w-max shrink-0 inline-flex justify-center items-center cursor-default rounded-tremor-small ring-1 ring-inset",u?(0,s.tremorTwMerge)((0,n.getColorClassNames)(u,i.colorPalette.background).bgColor,(0,n.getColorClassNames)(u,i.colorPalette.iconText).textColor,(0,n.getColorClassNames)(u,i.colorPalette.iconRing).ringColor,"bg-opacity-10 ring-opacity-20","dark:bg-opacity-5 dark:ring-opacity-60"):(0,s.tremorTwMerge)("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"),o[h].paddingX,o[h].paddingY,o[h].fontSize,x)},v,f),a.default.createElement(r.default,Object.assign({text:p},_)),y?a.default.createElement(y,{className:(0,s.tremorTwMerge)(m("icon"),"shrink-0 -ml-1 mr-1.5",d[h].height,d[h].width)}):null,a.default.createElement("span",{className:(0,s.tremorTwMerge)(m("text"),"whitespace-nowrap")},b))});c.displayName="Badge",e.s(["Badge",()=>c],389083)},68155,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.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"}))});e.s(["TrashIcon",0,a],68155)},360820,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 15l7-7 7 7"}))});e.s(["ChevronUpIcon",0,a],360820)},871943,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"}))});e.s(["ChevronDownIcon",0,a],871943)},530212,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M10 19l-7-7m0 0l7-7m-7 7h18"}))});e.s(["ArrowLeftIcon",0,a],530212)},969550,e=>{"use strict";var t=e.i(843476),a=e.i(271645);let r=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:"M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"}))});var l=e.i(464571),i=e.i(311451),s=e.i(199133),n=e.i(374009);e.s(["default",0,({options:e,onApplyFilters:o,onResetFilters:d,initialValues:m={},buttonLabel:c="Filters"})=>{let[u,g]=(0,a.useState)(!1),[h,p]=(0,a.useState)(m),[x,b]=(0,a.useState)({}),[f,y]=(0,a.useState)({}),[_,v]=(0,a.useState)({}),[j,w]=(0,a.useState)({}),C=(0,a.useCallback)((0,n.default)(async(e,t)=>{if(t.isSearchable&&t.searchFn){y(e=>({...e,[t.name]:!0}));try{let a=await t.searchFn(e);b(e=>({...e,[t.name]:a}))}catch(e){console.error("Error searching:",e),b(e=>({...e,[t.name]:[]}))}finally{y(e=>({...e,[t.name]:!1}))}}},300),[]),S=(0,a.useCallback)(async e=>{if(e.isSearchable&&e.searchFn&&!j[e.name]){y(t=>({...t,[e.name]:!0})),w(t=>({...t,[e.name]:!0}));try{let t=await e.searchFn("");b(a=>({...a,[e.name]:t}))}catch(t){console.error("Error loading initial options:",t),b(t=>({...t,[e.name]:[]}))}finally{y(t=>({...t,[e.name]:!1}))}}},[j]);(0,a.useEffect)(()=>{u&&e.forEach(e=>{e.isSearchable&&!j[e.name]&&S(e)})},[u,e,S,j]);let k=(e,t)=>{let a={...h,[e]:t};p(a),o(a)};return(0,t.jsxs)("div",{className:"w-full",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2 mb-6",children:[(0,t.jsx)(l.Button,{icon:(0,t.jsx)(r,{className:"h-4 w-4"}),onClick:()=>g(!u),className:"flex items-center gap-2",children:c}),(0,t.jsx)(l.Button,{onClick:()=>{let t={};e.forEach(e=>{t[e.name]=""}),p(t),d()},children:"Reset Filters"})]}),u&&(0,t.jsx)("div",{className:"grid grid-cols-3 gap-x-6 gap-y-4 mb-6",children:["Team ID","Status","Organization ID","Key Alias","User ID","End User","Error Code","Error Message","Key Hash","Model"].map(a=>{let r,l=e.find(e=>e.label===a||e.name===a);return l?(0,t.jsxs)("div",{className:"flex flex-col gap-2",children:[(0,t.jsx)("label",{className:"text-sm text-gray-600",children:l.label||l.name}),l.isSearchable?(0,t.jsx)(s.Select,{showSearch:!0,className:"w-full",placeholder:`Search ${l.label||l.name}...`,value:h[l.name]||void 0,onChange:e=>k(l.name,e),onOpenChange:e=>{e&&l.isSearchable&&!j[l.name]&&S(l)},onSearch:e=>{v(t=>({...t,[l.name]:e})),l.searchFn&&C(e,l)},filterOption:!1,loading:f[l.name],options:x[l.name]||[],allowClear:!0,notFoundContent:f[l.name]?"Loading...":"No results found"}):l.options?(0,t.jsx)(s.Select,{className:"w-full",placeholder:`Select ${l.label||l.name}...`,value:h[l.name]||void 0,onChange:e=>k(l.name,e),allowClear:!0,children:l.options.map(e=>(0,t.jsx)(s.Select.Option,{value:e.value,children:e.label},e.value))}):l.customComponent?(r=l.customComponent,(0,t.jsx)(r,{value:h[l.name]||void 0,onChange:e=>k(l.name,e??""),placeholder:`Select ${l.label||l.name}...`})):(0,t.jsx)(i.Input,{className:"w-full",placeholder:`Enter ${l.label||l.name}...`,value:h[l.name]||"",onChange:e=>k(l.name,e.target.value),allowClear:!0})]},l.name):null})})]})}],969550)},633627,e=>{"use strict";var t=e.i(764205);let a=(e,t,a,r)=>{for(let l of e){let e=l?.key_alias;e&&"string"==typeof e&&t.add(e.trim());let i=l?.organization_id??l?.org_id;i&&"string"==typeof i&&a.add(i.trim());let s=l?.user_id;if(s&&"string"==typeof s){let e=l?.user?.user_email||s;r.set(s,e)}}},r=async(e,r)=>{if(!e||!r)return{keyAliases:[],organizationIds:[],userIds:[]};try{let l=new Set,i=new Set,s=new Map,n=await (0,t.keyListCall)(e,null,r,null,null,null,1,100,null,null,"user",null),o=n?.keys||[],d=n?.total_pages??1;a(o,l,i,s);let m=Math.min(d,10)-1;if(m>0){let n=Array.from({length:m},(a,l)=>(0,t.keyListCall)(e,null,r,null,null,null,l+2,100,null,null,"user",null));for(let e of(await Promise.allSettled(n)))"fulfilled"===e.status&&a(e.value?.keys||[],l,i,s)}return{keyAliases:Array.from(l).sort(),organizationIds:Array.from(i).sort(),userIds:Array.from(s.entries()).map(([e,t])=>({id:e,email:t}))}}catch(e){return console.error("Error fetching team filter options:",e),{keyAliases:[],organizationIds:[],userIds:[]}}},l=async(e,a)=>{if(!e)return[];try{let r=[],l=1,i=!0;for(;i;){let s=await (0,t.teamListCall)(e,a||null,null);r=[...r,...s],l{if(!e)return[];try{let a=[],r=1,l=!0;for(;l;){let i=await (0,t.organizationListCall)(e);a=[...a,...i],r{"use strict";var t=e.i(266027),a=e.i(621482),r=e.i(243652),l=e.i(764205),i=e.i(135214);let s=(0,r.createQueryKeys)("models"),n=(0,r.createQueryKeys)("modelHub"),o=(0,r.createQueryKeys)("allProxyModels");(0,r.createQueryKeys)("selectedTeamModels");let d=(0,r.createQueryKeys)("infiniteModels");e.s(["useAllProxyModels",0,()=>{let{accessToken:e,userId:a,userRole:r}=(0,i.default)();return(0,t.useQuery)({queryKey:o.list({}),queryFn:async()=>await (0,l.modelAvailableCall)(e,a,r,!0,null,!0,!1,"expand"),enabled:!!(e&&a&&r)})},"useInfiniteModelInfo",0,(e=50,t)=>{let{accessToken:r,userId:s,userRole:n}=(0,i.default)();return(0,a.useInfiniteQuery)({queryKey:d.list({filters:{...s&&{userId:s},...n&&{userRole:n},size:e,...t&&{search:t}}}),queryFn:async({pageParam:a})=>await (0,l.modelInfoCall)(r,s,n,a,e,t),initialPageParam:1,getNextPageParam:e=>{if(e.current_page{let{accessToken:e}=(0,i.default)();return(0,t.useQuery)({queryKey:n.list({}),queryFn:async()=>await (0,l.modelHubCall)(e),enabled:!!e})},"useModelsInfo",0,(e=1,a=50,r,n,o,d,m)=>{let{accessToken:c,userId:u,userRole:g}=(0,i.default)();return(0,t.useQuery)({queryKey:s.list({filters:{...u&&{userId:u},...g&&{userRole:g},page:e,size:a,...r&&{search:r},...n&&{modelId:n},...o&&{teamId:o},...d&&{sortBy:d},...m&&{sortOrder:m}}}),queryFn:async()=>await (0,l.modelInfoCall)(c,u,g,e,a,r,n,o,d,m),enabled:!!(c&&u&&g)})}])},91979,e=>{"use strict";e.i(247167);var t=e.i(931067),a=e.i(271645);let r={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M909.1 209.3l-56.4 44.1C775.8 155.1 656.2 92 521.9 92 290 92 102.3 279.5 102 511.5 101.7 743.7 289.8 932 521.9 932c181.3 0 335.8-115 394.6-276.1 1.5-4.2-.7-8.9-4.9-10.3l-56.7-19.5a8 8 0 00-10.1 4.8c-1.8 5-3.8 10-5.9 14.9-17.3 41-42.1 77.8-73.7 109.4A344.77 344.77 0 01655.9 829c-42.3 17.9-87.4 27-133.8 27-46.5 0-91.5-9.1-133.8-27A341.5 341.5 0 01279 755.2a342.16 342.16 0 01-73.7-109.4c-17.9-42.4-27-87.4-27-133.9s9.1-91.5 27-133.9c17.3-41 42.1-77.8 73.7-109.4 31.6-31.6 68.4-56.4 109.3-73.8 42.3-17.9 87.4-27 133.8-27 46.5 0 91.5 9.1 133.8 27a341.5 341.5 0 01109.3 73.8c9.9 9.9 19.2 20.4 27.8 31.4l-60.2 47a8 8 0 003 14.1l175.6 43c5 1.2 9.9-2.6 9.9-7.7l.8-180.9c-.1-6.6-7.8-10.3-13-6.2z"}}]},name:"reload",theme:"outlined"};var l=e.i(9583),i=a.forwardRef(function(e,i){return a.createElement(l.default,(0,t.default)({},e,{ref:i,icon:r}))});e.s(["ReloadOutlined",0,i],91979)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/4348e537165edb3b.js b/litellm/proxy/_experimental/out/_next/static/chunks/4348e537165edb3b.js new file mode 100644 index 0000000000..1b8a9c367e --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/4348e537165edb3b.js @@ -0,0 +1 @@ +(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,988297,e=>{"use strict";var t=e.i(271645);let s=t.forwardRef(function(e,s){return t.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:s},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"}))});e.s(["PlusIcon",0,s],988297)},797672,e=>{"use strict";var t=e.i(271645);let s=t.forwardRef(function(e,s){return t.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:s},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"}))});e.s(["PencilIcon",0,s],797672)},981339,e=>{"use strict";var t=e.i(185793);e.s(["Skeleton",()=>t.default])},653496,e=>{"use strict";var t=e.i(721369);e.s(["Tabs",()=>t.default])},983561,e=>{"use strict";e.i(247167);var t=e.i(931067),s=e.i(271645);let a={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M300 328a60 60 0 10120 0 60 60 0 10-120 0zM852 64H172c-17.7 0-32 14.3-32 32v660c0 17.7 14.3 32 32 32h680c17.7 0 32-14.3 32-32V96c0-17.7-14.3-32-32-32zm-32 660H204V128h616v596zM604 328a60 60 0 10120 0 60 60 0 10-120 0zm250.2 556H169.8c-16.5 0-29.8 14.3-29.8 32v36c0 4.4 3.3 8 7.4 8h729.1c4.1 0 7.4-3.6 7.4-8v-36c.1-17.7-13.2-32-29.7-32zM664 508H360c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h304c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"}}]},name:"robot",theme:"outlined"};var r=e.i(9583),l=s.forwardRef(function(e,l){return s.createElement(r.default,(0,t.default)({},e,{ref:l,icon:a}))});e.s(["RobotOutlined",0,l],983561)},992619,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(779241),r=e.i(599724),l=e.i(199133),i=e.i(983561),n=e.i(689020);e.s(["default",0,({accessToken:e,value:o,placeholder:c="Select a Model",onChange:d,disabled:u=!1,style:m,className:h,showLabel:p=!0,labelText:g="Select Model"})=>{let[f,x]=(0,s.useState)(o),[y,b]=(0,s.useState)(!1),[_,v]=(0,s.useState)([]),j=(0,s.useRef)(null);return(0,s.useEffect)(()=>{x(o)},[o]),(0,s.useEffect)(()=>{e&&(async()=>{try{let t=await (0,n.fetchAvailableModels)(e);console.log("Fetched models for selector:",t),t.length>0&&v(t)}catch(e){console.error("Error fetching model info:",e)}})()},[e]),(0,t.jsxs)("div",{children:[p&&(0,t.jsxs)(r.Text,{className:"font-medium block mb-2 text-gray-700 flex items-center",children:[(0,t.jsx)(i.RobotOutlined,{className:"mr-2"})," ",g]}),(0,t.jsx)(l.Select,{value:f,placeholder:c,onChange:e=>{"custom"===e?(b(!0),x(void 0)):(b(!1),x(e),d&&d(e))},options:[...Array.from(new Set(_.map(e=>e.model_group))).map((e,t)=>({value:e,label:e,key:t})),{value:"custom",label:"Enter custom model",key:"custom"}],style:{width:"100%",...m},showSearch:!0,className:`rounded-md ${h||""}`,disabled:u}),y&&(0,t.jsx)(a.TextInput,{className:"mt-2",placeholder:"Enter custom model name",onValueChange:e=>{j.current&&clearTimeout(j.current),j.current=setTimeout(()=>{x(e),d&&d(e)},500)},disabled:u})]})}])},91739,e=>{"use strict";var t=e.i(544195);e.s(["Radio",()=>t.default])},409797,e=>{"use strict";var t=e.i(631171);e.s(["ChevronDownIcon",()=>t.default])},500727,696609,531516,e=>{"use strict";var t=e.i(266027),s=e.i(243652),a=e.i(764205),r=e.i(135214);let l=(0,s.createQueryKeys)("mcpServers");e.s(["useMCPServers",0,e=>{let{accessToken:s}=(0,r.default)();return(0,t.useQuery)({queryKey:l.list(e?{filters:{teamId:e}}:void 0),queryFn:async()=>await (0,a.fetchMCPServers)(s,e),enabled:!!s})}],500727);var i=e.i(843476),n=e.i(271645),o=e.i(536916),c=e.i(599724),d=e.i(409797),u=e.i(246349),u=u;let m=/\b(delete|remove|destroy|purge|drop|erase|unlink)\b/i,h=/\b(create|add|insert|new|post|submit|register|make|generate|write|upload)\b/i,p=/\b(update|edit|modify|change|patch|put|set|rename|move|transform)\b/i,g=/\b(get|read|list|fetch|search|find|query|retrieve|show|view|check|describe|info)\b/i;function f(e,t=""){let s=e.toLowerCase();if(g.test(s))return"read";if(m.test(s))return"delete";if(p.test(s))return"update";if(h.test(s))return"create";if(t){let e=t.toLowerCase();if(g.test(e))return"read";if(m.test(e))return"delete";if(p.test(e))return"update";if(h.test(e))return"create"}return"unknown"}function x(e){let t={read:[],create:[],update:[],delete:[],unknown:[]};for(let s of e)t[f(s.name,s.description)].push(s);return t}let y={read:{label:"Read",description:"Safe operations — fetch, list, search. No side effects.",risk:"low"},create:{label:"Create",description:"Add new resources — insert, upload, register.",risk:"medium"},update:{label:"Update",description:"Modify existing resources — edit, patch, rename.",risk:"medium"},delete:{label:"Delete",description:"Destructive operations — remove, purge, destroy.",risk:"high"},unknown:{label:"Other",description:"Operations that could not be automatically classified.",risk:"unknown"}};e.s(["CRUD_GROUP_META",0,y,"classifyToolOp",()=>f,"groupToolsByCrud",()=>x],696609);let b=["read","create","update","delete","unknown"],_={low:"bg-green-100 text-green-800",medium:"bg-yellow-100 text-yellow-800",high:"bg-red-100 text-red-800 font-semibold",unknown:"bg-gray-100 text-gray-700"},v={read:"border-green-200",create:"border-blue-200",update:"border-yellow-200",delete:"border-red-300",unknown:"border-gray-200"},j={read:"bg-green-50",create:"bg-blue-50",update:"bg-yellow-50",delete:"bg-red-50",unknown:"bg-gray-50"};e.s(["default",0,({tools:e,value:t,onChange:s,readOnly:a=!1,searchFilter:r=""})=>{let[l,m]=(0,n.useState)({read:!1,create:!1,update:!1,delete:!1,unknown:!0}),h=(0,n.useMemo)(()=>x(e),[e]),p=(0,n.useMemo)(()=>new Set(void 0===t?e.map(e=>e.name):t),[t,e]),g=e=>{if(a)return;let t=new Set(p);t.has(e)?t.delete(e):t.add(e),s(Array.from(t))};return 0===e.length?null:(0,i.jsx)("div",{className:"space-y-3",children:b.map(e=>{let t,n=h[e];if(0===n.length)return null;if(r){let e=r.toLowerCase();if(!n.some(t=>t.name.toLowerCase().includes(e)||(t.description??"").toLowerCase().includes(e)))return null}let f=y[e],x=(t=h[e]).length>0&&t.every(e=>p.has(e.name)),b=(e=>{let t=h[e];if(0===t.length)return!1;let s=t.filter(e=>p.has(e.name)).length;return s>0&&s{m(t=>({...t,[e]:!t[e]}))},children:[w?(0,i.jsx)(u.default,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}):(0,i.jsx)(d.ChevronDownIcon,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}),(0,i.jsx)("span",{className:"font-semibold text-gray-900 text-sm",children:f.label}),(0,i.jsx)("span",{className:`text-xs px-2 py-0.5 rounded-full ${_[f.risk]}`,children:"high"===f.risk?"High Risk":"medium"===f.risk?"Medium Risk":"low"===f.risk?"Safe":"Unclassified"}),(0,i.jsxs)("span",{className:"text-xs text-gray-500 ml-1",children:[n.filter(e=>p.has(e.name)).length,"/",n.length," allowed"]})]}),!a&&(0,i.jsxs)("div",{className:"flex items-center gap-2 ml-4",children:[(0,i.jsx)(c.Text,{className:"text-xs text-gray-500",children:x?"All on":b?"Partial":"All off"}),(0,i.jsx)(o.Checkbox,{checked:x,indeterminate:b,onChange:t=>((e,t)=>{if(a)return;let r=new Set(p);for(let s of h[e])t?r.add(s.name):r.delete(s.name);s(Array.from(r))})(e,t.target.checked),onClick:e=>e.stopPropagation()})]})]}),!w&&(0,i.jsx)("div",{className:"px-4 pt-2 pb-1 text-xs text-gray-500 bg-white border-b border-gray-100",children:f.description}),!w&&(0,i.jsx)("div",{className:"bg-white divide-y divide-gray-50",children:n.filter(e=>!r||e.name.toLowerCase().includes(r.toLowerCase())||(e.description??"").toLowerCase().includes(r.toLowerCase())).map(e=>{let t,s=(t=e.name,p.has(t));return(0,i.jsxs)("div",{className:`flex items-start gap-3 px-4 py-2.5 transition-colors hover:bg-gray-50 ${!a?"cursor-pointer":""} ${s?"":"opacity-60"}`,onClick:()=>g(e.name),children:[(0,i.jsx)(o.Checkbox,{checked:s,onChange:()=>g(e.name),disabled:a,onClick:e=>e.stopPropagation()}),(0,i.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,i.jsx)(c.Text,{className:"font-medium text-gray-900 text-sm",children:e.name}),e.description&&(0,i.jsx)(c.Text,{className:"text-xs text-gray-500 mt-0.5 leading-snug",children:e.description})]}),(0,i.jsx)("span",{className:`text-xs px-1.5 py-0.5 rounded flex-shrink-0 ${s?"bg-green-100 text-green-700":"bg-gray-100 text-gray-500"}`,children:s?"on":"off"})]},e.name)})})]},e)})})}],531516)},107233,37727,e=>{"use strict";var t=e.i(603908);e.s(["Plus",()=>t.default],107233);var s=e.i(841947);e.s(["X",()=>s.default],37727)},246349,e=>{"use strict";let t=(0,e.i(475254).default)("chevron-right",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);e.s(["default",()=>t])},689020,e=>{"use strict";var t=e.i(764205);let s=async e=>{try{let s=await (0,t.modelHubCall)(e);if(console.log("model_info:",s),s?.data.length>0){let e=s.data.map(e=>({model_group:e.model_group,mode:e?.mode}));return e.sort((e,t)=>e.model_group.localeCompare(t.model_group)),e}return[]}catch(e){throw console.error("Error fetching model info:",e),e}};e.s(["fetchAvailableModels",0,s])},955135,e=>{"use strict";var t=e.i(597440);e.s(["DeleteOutlined",()=>t.default])},737434,e=>{"use strict";var t=e.i(184163);e.s(["DownloadOutlined",()=>t.default])},916940,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(199133),r=e.i(764205);e.s(["default",0,({onChange:e,value:l,className:i,accessToken:n,placeholder:o="Select vector stores",disabled:c=!1})=>{let[d,u]=(0,s.useState)([]),[m,h]=(0,s.useState)(!1);return(0,s.useEffect)(()=>{(async()=>{if(n){h(!0);try{let e=await (0,r.vectorStoreListCall)(n);e.data&&u(e.data)}catch(e){console.error("Error fetching vector stores:",e)}finally{h(!1)}}})()},[n]),(0,t.jsx)("div",{children:(0,t.jsx)(a.Select,{mode:"multiple",placeholder:o,onChange:e,value:l,loading:m,className:i,allowClear:!0,options:d.map(e=>({label:`${e.vector_store_name||e.vector_store_id} (${e.vector_store_id})`,value:e.vector_store_id,title:e.vector_store_description||e.vector_store_id})),optionFilterProp:"label",showSearch:!0,style:{width:"100%"},disabled:c})})}])},59935,(e,t,s)=>{var a;let r;e.e,a=function e(){var t,s="u">typeof self?self:"u">typeof window?window:void 0!==s?s:{},a=!s.document&&!!s.postMessage,r=s.IS_PAPA_WORKER||!1,l={},i=0,n={};function o(e){this._handle=null,this._finished=!1,this._completed=!1,this._halted=!1,this._input=null,this._baseIndex=0,this._partialLine="",this._rowCount=0,this._start=0,this._nextChunk=null,this.isFirstChunk=!0,this._completeResults={data:[],errors:[],meta:{}},(function(e){var t=b(e);t.chunkSize=parseInt(t.chunkSize),e.step||e.chunk||(t.chunkSize=null),this._handle=new h(t),(this._handle.streamer=this)._config=t}).call(this,e),this.parseChunk=function(e,t){var a=parseInt(this._config.skipFirstNLines)||0;if(this.isFirstChunk&&0=this._config.preview,r)s.postMessage({results:l,workerId:n.WORKER_ID,finished:a});else if(v(this._config.chunk)&&!t){if(this._config.chunk(l,this._handle),this._handle.paused()||this._handle.aborted())return void(this._halted=!0);this._completeResults=l=void 0}return this._config.step||this._config.chunk||(this._completeResults.data=this._completeResults.data.concat(l.data),this._completeResults.errors=this._completeResults.errors.concat(l.errors),this._completeResults.meta=l.meta),this._completed||!a||!v(this._config.complete)||l&&l.meta.aborted||(this._config.complete(this._completeResults,this._input),this._completed=!0),a||l&&l.meta.paused||this._nextChunk(),l}this._halted=!0},this._sendError=function(e){v(this._config.error)?this._config.error(e):r&&this._config.error&&s.postMessage({workerId:n.WORKER_ID,error:e,finished:!1})}}function c(e){var t;(e=e||{}).chunkSize||(e.chunkSize=n.RemoteChunkSize),o.call(this,e),this._nextChunk=a?function(){this._readChunk(),this._chunkLoaded()}:function(){this._readChunk()},this.stream=function(e){this._input=e,this._nextChunk()},this._readChunk=function(){if(this._finished)this._chunkLoaded();else{if(t=new XMLHttpRequest,this._config.withCredentials&&(t.withCredentials=this._config.withCredentials),a||(t.onload=_(this._chunkLoaded,this),t.onerror=_(this._chunkError,this)),t.open(this._config.downloadRequestBody?"POST":"GET",this._input,!a),this._config.downloadRequestHeaders){var e,s,r=this._config.downloadRequestHeaders;for(s in r)t.setRequestHeader(s,r[s])}this._config.chunkSize&&(e=this._start+this._config.chunkSize-1,t.setRequestHeader("Range","bytes="+this._start+"-"+e));try{t.send(this._config.downloadRequestBody)}catch(e){this._chunkError(e.message)}a&&0===t.status&&this._chunkError()}},this._chunkLoaded=function(){let e;4===t.readyState&&(t.status<200||400<=t.status?this._chunkError():(this._start+=this._config.chunkSize||t.responseText.length,this._finished=!this._config.chunkSize||this._start>=(null!==(e=(e=t).getResponseHeader("Content-Range"))?parseInt(e.substring(e.lastIndexOf("/")+1)):-1),this.parseChunk(t.responseText)))},this._chunkError=function(e){e=t.statusText||e,this._sendError(Error(e))}}function d(e){(e=e||{}).chunkSize||(e.chunkSize=n.LocalChunkSize),o.call(this,e);var t,s,a="u">typeof FileReader;this.stream=function(e){this._input=e,s=e.slice||e.webkitSlice||e.mozSlice,a?((t=new FileReader).onload=_(this._chunkLoaded,this),t.onerror=_(this._chunkError,this)):t=new FileReaderSync,this._nextChunk()},this._nextChunk=function(){this._finished||this._config.preview&&!(this._rowCount=this._input.size,this.parseChunk(e.target.result)},this._chunkError=function(){this._sendError(t.error)}}function u(e){var t;o.call(this,e=e||{}),this.stream=function(e){return t=e,this._nextChunk()},this._nextChunk=function(){var e,s;if(!this._finished)return t=(e=this._config.chunkSize)?(s=t.substring(0,e),t.substring(e)):(s=t,""),this._finished=!t,this.parseChunk(s)}}function m(e){o.call(this,e=e||{});var t=[],s=!0,a=!1;this.pause=function(){o.prototype.pause.apply(this,arguments),this._input.pause()},this.resume=function(){o.prototype.resume.apply(this,arguments),this._input.resume()},this.stream=function(e){this._input=e,this._input.on("data",this._streamData),this._input.on("end",this._streamEnd),this._input.on("error",this._streamError)},this._checkIsFinished=function(){a&&1===t.length&&(this._finished=!0)},this._nextChunk=function(){this._checkIsFinished(),t.length?this.parseChunk(t.shift()):s=!0},this._streamData=_(function(e){try{t.push("string"==typeof e?e:e.toString(this._config.encoding)),s&&(s=!1,this._checkIsFinished(),this.parseChunk(t.shift()))}catch(e){this._streamError(e)}},this),this._streamError=_(function(e){this._streamCleanUp(),this._sendError(e)},this),this._streamEnd=_(function(){this._streamCleanUp(),a=!0,this._streamData("")},this),this._streamCleanUp=_(function(){this._input.removeListener("data",this._streamData),this._input.removeListener("end",this._streamEnd),this._input.removeListener("error",this._streamError)},this)}function h(e){var t,s,a,r,l=/^\s*-?(\d+\.?|\.\d+|\d+\.\d+)([eE][-+]?\d+)?\s*$/,i=/^((\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)))$/,o=this,c=0,d=0,u=!1,m=!1,h=[],f={data:[],errors:[],meta:{}};function x(t){return"greedy"===e.skipEmptyLines?""===t.join("").trim():1===t.length&&0===t[0].length}function y(){if(f&&a&&(j("Delimiter","UndetectableDelimiter","Unable to auto-detect delimiting character; defaulted to '"+n.DefaultDelimiter+"'"),a=!1),e.skipEmptyLines&&(f.data=f.data.filter(function(e){return!x(e)})),_()){if(f)if(Array.isArray(f.data[0])){for(var t,s=0;_()&&s(e.dynamicTypingFunction&&void 0===e.dynamicTyping[t]&&(e.dynamicTyping[t]=e.dynamicTypingFunction(t)),!0===(e.dynamicTyping[t]||e.dynamicTyping))?"true"===s||"TRUE"===s||"false"!==s&&"FALSE"!==s&&((e=>{if(l.test(e)&&-0x20000000000000<(e=parseFloat(e))&&e<0x20000000000000)return 1})(s)?parseFloat(s):i.test(s)?new Date(s):""===s?null:s):s)(n=e.header?r>=h.length?"__parsed_extra":h[r]:n,o=e.transform?e.transform(o,n):o);"__parsed_extra"===n?(a[n]=a[n]||[],a[n].push(o)):a[n]=o}return e.header&&(r>h.length?j("FieldMismatch","TooManyFields","Too many fields: expected "+h.length+" fields but parsed "+r,d+s):re.preview?s.abort():(f.data=f.data[0],r(f,o))))}),this.parse=function(r,l,i){var o=e.quoteChar||'"',o=(e.newline||(e.newline=this.guessLineEndings(r,o)),a=!1,e.delimiter?v(e.delimiter)&&(e.delimiter=e.delimiter(r),f.meta.delimiter=e.delimiter):((o=((t,s,a,r,l)=>{var i,o,c,d;l=l||[","," ","|",";",n.RECORD_SEP,n.UNIT_SEP];for(var u=0;u=s.length/2?"\r\n":"\r"}}function p(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function g(e){var t=(e=e||{}).delimiter,s=e.newline,a=e.comments,r=e.step,l=e.preview,i=e.fastMode,o=null,c=!1,d=null==e.quoteChar?'"':e.quoteChar,u=d;if(void 0!==e.escapeChar&&(u=e.escapeChar),("string"!=typeof t||-1=l)return D(!0);break}k.push({type:"Quotes",code:"InvalidQuotes",message:"Trailing quote on quoted field is malformed",row:w.length,index:m}),O++}}else if(a&&0===N.length&&n.substring(m,m+_)===a){if(-1===I)return D();m=I+b,I=n.indexOf(s,m),E=n.indexOf(t,m)}else if(-1!==E&&(E=l)return D(!0)}return R();function M(e){w.push(e),S=m}function F(e){return -1!==e&&(e=n.substring(O+1,e))&&""===e.trim()?e.length:0}function R(e){return f||(void 0===e&&(e=n.substring(m)),N.push(e),m=x,M(N),j&&B()),D()}function P(e){m=e,M(N),N=[],I=n.indexOf(s,m)}function D(a){if(e.header&&!g&&w.length&&!c){var r=w[0],l=Object.create(null),i=new Set(r);let t=!1;for(let s=0;s{if("object"==typeof t){if("string"!=typeof t.delimiter||n.BAD_DELIMITERS.filter(function(e){return -1!==t.delimiter.indexOf(e)}).length||(r=t.delimiter),("boolean"==typeof t.quotes||"function"==typeof t.quotes||Array.isArray(t.quotes))&&(s=t.quotes),"boolean"!=typeof t.skipEmptyLines&&"string"!=typeof t.skipEmptyLines||(c=t.skipEmptyLines),"string"==typeof t.newline&&(l=t.newline),"string"==typeof t.quoteChar&&(i=t.quoteChar),"boolean"==typeof t.header&&(a=t.header),Array.isArray(t.columns)){if(0===t.columns.length)throw Error("Option columns is empty");d=t.columns}void 0!==t.escapeChar&&(o=t.escapeChar+i),t.escapeFormulae instanceof RegExp?u=t.escapeFormulae:"boolean"==typeof t.escapeFormulae&&t.escapeFormulae&&(u=/^[=+\-@\t\r].*$/)}})(),RegExp(p(i),"g"));if("string"==typeof e&&(e=JSON.parse(e)),Array.isArray(e)){if(!e.length||Array.isArray(e[0]))return h(null,e,c);if("object"==typeof e[0])return h(d||Object.keys(e[0]),e,c)}else if("object"==typeof e)return"string"==typeof e.data&&(e.data=JSON.parse(e.data)),Array.isArray(e.data)&&(e.fields||(e.fields=e.meta&&e.meta.fields||d),e.fields||(e.fields=Array.isArray(e.data[0])?e.fields:"object"==typeof e.data[0]?Object.keys(e.data[0]):[]),Array.isArray(e.data[0])||"object"==typeof e.data[0]||(e.data=[e.data])),h(e.fields||[],e.data||[],c);throw Error("Unable to serialize unrecognized input");function h(e,t,s){var i="",n=("string"==typeof e&&(e=JSON.parse(e)),"string"==typeof t&&(t=JSON.parse(t)),Array.isArray(e)&&0{for(var s=0;s{"use strict";let t=(0,e.i(475254).default)("circle-alert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);e.s(["default",()=>t])},603908,e=>{"use strict";let t=(0,e.i(475254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);e.s(["default",()=>t])},841947,e=>{"use strict";let t=(0,e.i(475254).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["default",()=>t])},793130,e=>{"use strict";var t=e.i(290571),s=e.i(429427),a=e.i(371330),r=e.i(271645),l=e.i(394487),i=e.i(503269),n=e.i(214520),o=e.i(746725),c=e.i(914189),d=e.i(144279),u=e.i(294316),m=e.i(601893),h=e.i(140721),p=e.i(942803),g=e.i(233538),f=e.i(694421),x=e.i(700020),y=e.i(35889),b=e.i(998348),_=e.i(722678);let v=(0,r.createContext)(null);v.displayName="GroupContext";let j=r.Fragment,w=Object.assign((0,x.forwardRefWithAs)(function(e,t){var j;let w=(0,r.useId)(),k=(0,p.useProvidedId)(),N=(0,m.useDisabled)(),{id:S=k||`headlessui-switch-${w}`,disabled:C=N||!1,checked:T,defaultChecked:E,onChange:I,name:A,value:O,form:L,autoFocus:M=!1,...F}=e,R=(0,r.useContext)(v),[P,D]=(0,r.useState)(null),B=(0,r.useRef)(null),$=(0,u.useSyncRefs)(B,t,null===R?null:R.setSwitch,D),K=(0,n.useDefaultValue)(E),[U,z]=(0,i.useControllable)(T,I,null!=K&&K),V=(0,o.useDisposables)(),[q,G]=(0,r.useState)(!1),H=(0,c.useEvent)(()=>{G(!0),null==z||z(!U),V.nextFrame(()=>{G(!1)})}),W=(0,c.useEvent)(e=>{if((0,g.isDisabledReactIssue7711)(e.currentTarget))return e.preventDefault();e.preventDefault(),H()}),Q=(0,c.useEvent)(e=>{e.key===b.Keys.Space?(e.preventDefault(),H()):e.key===b.Keys.Enter&&(0,f.attemptSubmit)(e.currentTarget)}),J=(0,c.useEvent)(e=>e.preventDefault()),Y=(0,_.useLabelledBy)(),X=(0,y.useDescribedBy)(),{isFocusVisible:Z,focusProps:ee}=(0,s.useFocusRing)({autoFocus:M}),{isHovered:et,hoverProps:es}=(0,a.useHover)({isDisabled:C}),{pressed:ea,pressProps:er}=(0,l.useActivePress)({disabled:C}),el=(0,r.useMemo)(()=>({checked:U,disabled:C,hover:et,focus:Z,active:ea,autofocus:M,changing:q}),[U,et,Z,ea,C,q,M]),ei=(0,x.mergeProps)({id:S,ref:$,role:"switch",type:(0,d.useResolveButtonType)(e,P),tabIndex:-1===e.tabIndex?0:null!=(j=e.tabIndex)?j:0,"aria-checked":U,"aria-labelledby":Y,"aria-describedby":X,disabled:C||void 0,autoFocus:M,onClick:W,onKeyUp:Q,onKeyPress:J},ee,es,er),en=(0,r.useCallback)(()=>{if(void 0!==K)return null==z?void 0:z(K)},[z,K]),eo=(0,x.useRender)();return r.default.createElement(r.default.Fragment,null,null!=A&&r.default.createElement(h.FormFields,{disabled:C,data:{[A]:O||"on"},overrides:{type:"checkbox",checked:U},form:L,onReset:en}),eo({ourProps:ei,theirProps:F,slot:el,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var t;let[s,a]=(0,r.useState)(null),[l,i]=(0,_.useLabels)(),[n,o]=(0,y.useDescriptions)(),c=(0,r.useMemo)(()=>({switch:s,setSwitch:a}),[s,a]),d=(0,x.useRender)();return r.default.createElement(o,{name:"Switch.Description",value:n},r.default.createElement(i,{name:"Switch.Label",value:l,props:{htmlFor:null==(t=c.switch)?void 0:t.id,onClick(e){s&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),s.click(),s.focus({preventScroll:!0}))}}},r.default.createElement(v.Provider,{value:c},d({ourProps:{},theirProps:e,slot:{},defaultTag:j,name:"Switch.Group"}))))},Label:_.Label,Description:y.Description});var k=e.i(888288),N=e.i(95779),S=e.i(444755),C=e.i(673706),T=e.i(829087);let E=(0,C.makeClassName)("Switch"),I=r.default.forwardRef((e,s)=>{let{checked:a,defaultChecked:l=!1,onChange:i,color:n,name:o,error:c,errorMessage:d,disabled:u,required:m,tooltip:h,id:p}=e,g=(0,t.__rest)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),f={bgColor:n?(0,C.getColorClassNames)(n,N.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:n?(0,C.getColorClassNames)(n,N.colorPalette.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[x,y]=(0,k.default)(l,a),[b,_]=(0,r.useState)(!1),{tooltipProps:v,getReferenceProps:j}=(0,T.useTooltip)(300);return r.default.createElement("div",{className:"flex flex-row items-center justify-start"},r.default.createElement(T.default,Object.assign({text:h},v)),r.default.createElement("div",Object.assign({ref:(0,C.mergeRefs)([s,v.refs.setReference]),className:(0,S.tremorTwMerge)(E("root"),"flex flex-row relative h-5")},g,j),r.default.createElement("input",{type:"checkbox",className:(0,S.tremorTwMerge)(E("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:o,required:m,checked:x,onChange:e=>{e.preventDefault()}}),r.default.createElement(w,{checked:x,onChange:e=>{y(e),null==i||i(e)},disabled:u,className:(0,S.tremorTwMerge)(E("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:()=>_(!0),onBlur:()=>_(!1),id:p},r.default.createElement("span",{className:(0,S.tremorTwMerge)(E("sr-only"),"sr-only")},"Switch ",x?"on":"off"),r.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("background"),x?f.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")}),r.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("round"),x?(0,S.tremorTwMerge)(f.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",b?(0,S.tremorTwMerge)("ring-2",f.ringColor):"")}))),c&&d?r.default.createElement("p",{className:(0,S.tremorTwMerge)(E("errorMessage"),"text-sm text-red-500 mt-1 ")},d):null)});I.displayName="Switch",e.s(["Switch",()=>I],793130)},158392,419470,e=>{"use strict";var t=e.i(843476),s=e.i(779241);let a={ttl:3600,lowest_latency_buffer:0},r=({routingStrategyArgs:e})=>{let r={ttl:"Sliding window to look back over when calculating the average latency of a deployment. Default - 1 hour (in seconds).",lowest_latency_buffer:"Shuffle between deployments within this % of the lowest latency. Default - 0 (i.e. always pick lowest latency)."};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Latency-Based Configuration"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Fine-tune latency-based routing behavior"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e||a).map(([e,a])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:e.replace(/_/g," ")}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:r[e]||""}),(0,t.jsx)(s.TextInput,{name:e,defaultValue:"object"==typeof a?JSON.stringify(a,null,2):a?.toString(),className:"font-mono text-sm w-full"})]})},e))})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"})]})},l=({routerSettings:e,routerFieldsMetadata:a})=>(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Reliability & Retries"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure retry logic and failure handling"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e).filter(([e,t])=>"fallbacks"!=e&&"context_window_fallbacks"!=e&&"routing_strategy_args"!=e&&"routing_strategy"!=e&&"enable_tag_filtering"!=e).map(([e,r])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:a[e]?.ui_field_name||e}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:a[e]?.field_description||""}),(0,t.jsx)(s.TextInput,{name:e,defaultValue:null==r||"null"===r?"":"object"==typeof r?JSON.stringify(r,null,2):r?.toString()||"",placeholder:"—",className:"font-mono text-sm w-full"})]})},e))})]});var i=e.i(199133);let n=({selectedStrategy:e,availableStrategies:s,routingStrategyDescriptions:a,routerFieldsMetadata:r,onStrategyChange:l})=>(0,t.jsxs)("div",{className:"space-y-2 max-w-3xl",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:r.routing_strategy?.ui_field_name||"Routing Strategy"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:r.routing_strategy?.field_description||""})]}),(0,t.jsx)("div",{className:"routing-strategy-select max-w-3xl",children:(0,t.jsx)(i.Select,{value:e,onChange:l,style:{width:"100%"},size:"large",children:s.map(e=>(0,t.jsx)(i.Select.Option,{value:e,label:e,children:(0,t.jsxs)("div",{className:"flex flex-col gap-0.5 py-1",children:[(0,t.jsx)("span",{className:"font-mono text-sm font-medium",children:e}),a[e]&&(0,t.jsx)("span",{className:"text-xs text-gray-500 font-normal",children:a[e]})]})},e))})})]});var o=e.i(793130);let c=({enabled:e,routerFieldsMetadata:s,onToggle:a})=>(0,t.jsx)("div",{className:"space-y-3 max-w-3xl",children:(0,t.jsxs)("div",{className:"flex items-start justify-between",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:s.enable_tag_filtering?.ui_field_name||"Enable Tag Filtering"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500 mt-0.5",children:[s.enable_tag_filtering?.field_description||"",s.enable_tag_filtering?.link&&(0,t.jsxs)(t.Fragment,{children:[" ",(0,t.jsx)("a",{href:s.enable_tag_filtering.link,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline",children:"Learn more"})]})]})]}),(0,t.jsx)(o.Switch,{checked:e,onChange:a,className:"ml-4"})]})});e.s(["default",0,({value:e,onChange:s,routerFieldsMetadata:a,availableRoutingStrategies:i,routingStrategyDescriptions:o})=>(0,t.jsxs)("div",{className:"w-full space-y-8 py-2",children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Routing Settings"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure how requests are routed to deployments"})]}),i.length>0&&(0,t.jsx)(n,{selectedStrategy:e.selectedStrategy||e.routerSettings.routing_strategy||null,availableStrategies:i,routingStrategyDescriptions:o,routerFieldsMetadata:a,onStrategyChange:t=>{s({...e,selectedStrategy:t})}}),(0,t.jsx)(c,{enabled:e.enableTagFiltering,routerFieldsMetadata:a,onToggle:t=>{s({...e,enableTagFiltering:t})}})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),"latency-based-routing"===e.selectedStrategy&&(0,t.jsx)(r,{routingStrategyArgs:e.routerSettings.routing_strategy_args}),(0,t.jsx)(l,{routerSettings:e.routerSettings,routerFieldsMetadata:a})]})],158392);var d=e.i(994388),u=e.i(998573),m=e.i(653496),h=e.i(107233),p=e.i(271645),g=e.i(592968),f=e.i(361653),f=f;let x=(0,e.i(475254).default)("arrow-down",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var y=e.i(37727);function b({group:e,onChange:s,availableModels:a,maxFallbacks:r}){let l=a.filter(t=>t!==e.primaryModel),n=e.fallbackModels.length{let a=[...e.fallbackModels];a.includes(t)&&(a=a.filter(e=>e!==t)),s({...e,primaryModel:t,fallbackModels:a})},showSearch:!0,getPopupContainer:e=>e.parentElement||document.body,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase()),options:a.map(e=>({label:e,value:e}))}),!e.primaryModel&&(0,t.jsxs)("div",{className:"mt-2 flex items-center gap-2 text-amber-600 text-xs bg-amber-50 p-2 rounded",children:[(0,t.jsx)(f.default,{className:"w-4 h-4"}),(0,t.jsx)("span",{children:"Select a model to begin configuring fallbacks"})]})]}),(0,t.jsx)("div",{className:"flex items-center justify-center -my-4 z-10",children:(0,t.jsxs)("div",{className:"bg-indigo-50 text-indigo-500 px-4 py-1 rounded-full text-xs font-bold border border-indigo-100 flex items-center gap-2 shadow-sm",children:[(0,t.jsx)(x,{className:"w-4 h-4"}),"IF FAILS, TRY..."]})}),(0,t.jsxs)("div",{className:`transition-opacity duration-300 ${!e.primaryModel?"opacity-50 pointer-events-none":"opacity-100"}`,children:[(0,t.jsxs)("label",{className:"block text-sm font-semibold text-gray-700 mb-2",children:["Fallback Chain ",(0,t.jsx)("span",{className:"text-red-500",children:"*"}),(0,t.jsxs)("span",{className:"text-xs text-gray-500 font-normal ml-2",children:["(Max ",r," fallbacks at a time)"]})]}),(0,t.jsxs)("div",{className:"bg-gray-50 rounded-xl p-4 border border-gray-200",children:[(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(i.Select,{mode:"multiple",className:"w-full",size:"large",placeholder:n?"Select fallback models to add...":`Maximum ${r} fallbacks reached`,value:e.fallbackModels,onChange:t=>{let a=t.slice(0,r);s({...e,fallbackModels:a})},disabled:!e.primaryModel,getPopupContainer:e=>e.parentElement||document.body,options:l.map(e=>({label:e,value:e})),optionRender:(s,a)=>{let r=e.fallbackModels.includes(s.value),l=r?e.fallbackModels.indexOf(s.value)+1:null;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[r&&null!==l&&(0,t.jsx)("span",{className:"flex items-center justify-center w-5 h-5 rounded bg-indigo-100 text-indigo-600 text-xs font-bold",children:l}),(0,t.jsx)("span",{children:s.label})]})},maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(g.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})}),showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase())}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1 ml-1",children:n?`Search and select multiple models. Selected models will appear below in order. (${e.fallbackModels.length}/${r} used)`:`Maximum ${r} fallbacks reached. Remove some to add more.`})]}),(0,t.jsx)("div",{className:"space-y-2 min-h-[100px]",children:0===e.fallbackModels.length?(0,t.jsxs)("div",{className:"h-32 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)("span",{className:"text-sm",children:"No fallback models selected"}),(0,t.jsx)("span",{className:"text-xs mt-1",children:"Add models from the dropdown above"})]}):e.fallbackModels.map((a,r)=>(0,t.jsxs)("div",{className:"group flex items-center justify-between p-3 bg-white rounded-lg border border-gray-200 hover:border-indigo-300 hover:shadow-sm transition-all",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex items-center justify-center w-6 h-6 rounded bg-gray-100 text-gray-400 group-hover:text-indigo-500 group-hover:bg-indigo-50",children:(0,t.jsx)("span",{className:"text-xs font-bold",children:r+1})}),(0,t.jsx)("div",{children:(0,t.jsx)("span",{className:"font-medium text-gray-800",children:a})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>{let t;return t=e.fallbackModels.filter((e,t)=>t!==r),void s({...e,fallbackModels:t})},className:"opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500 p-1",children:(0,t.jsx)(y.X,{className:"w-4 h-4"})})]},`${a}-${r}`))})]})]})]})}function _({groups:e,onGroupsChange:s,availableModels:a,maxFallbacks:r=10,maxGroups:l=5}){let[i,n]=(0,p.useState)(e.length>0?e[0].id:"1");(0,p.useEffect)(()=>{e.length>0?e.some(e=>e.id===i)||n(e[0].id):n("1")},[e]);let o=()=>{if(e.length>=l)return;let t=Date.now().toString();s([...e,{id:t,primaryModel:null,fallbackModels:[]}]),n(t)},c=t=>{s(e.map(e=>e.id===t.id?t:e))},g=e.map((s,l)=>{let i=s.primaryModel?s.primaryModel:`Group ${l+1}`;return{key:s.id,label:i,closable:e.length>1,children:(0,t.jsx)(b,{group:s,onChange:c,availableModels:a,maxFallbacks:r})}});return 0===e.length?(0,t.jsxs)("div",{className:"text-center py-12 bg-gray-50 rounded-lg border border-dashed border-gray-300",children:[(0,t.jsx)("p",{className:"text-gray-500 mb-4",children:"No fallback groups configured"}),(0,t.jsx)(d.Button,{variant:"primary",onClick:o,icon:()=>(0,t.jsx)(h.Plus,{className:"w-4 h-4"}),children:"Create First Group"})]}):(0,t.jsx)(m.Tabs,{type:"editable-card",activeKey:i,onChange:n,onEdit:(t,a)=>{"add"===a?o():"remove"===a&&e.length>1&&(t=>{if(1===e.length)return u.message.warning("At least one group is required");let a=e.filter(e=>e.id!==t);s(a),i===t&&a.length>0&&n(a[a.length-1].id)})(t)},items:g,className:"fallback-tabs",tabBarStyle:{marginBottom:0},hideAdd:e.length>=l})}e.s(["FallbackSelectionForm",()=>_],419470)},309426,e=>{"use strict";var t=e.i(290571),s=e.i(444755),a=e.i(673706),r=e.i(271645),l=e.i(46757);let i=(0,a.makeClassName)("Col"),n=r.default.forwardRef((e,a)=>{let n,o,c,d,{numColSpan:u=1,numColSpanSm:m,numColSpanMd:h,numColSpanLg:p,children:g,className:f}=e,x=(0,t.__rest)(e,["numColSpan","numColSpanSm","numColSpanMd","numColSpanLg","children","className"]),y=(e,t)=>e&&Object.keys(t).includes(String(e))?t[e]:"";return r.default.createElement("div",Object.assign({ref:a,className:(0,s.tremorTwMerge)(i("root"),(n=y(u,l.colSpan),o=y(m,l.colSpanSm),c=y(h,l.colSpanMd),d=y(p,l.colSpanLg),(0,s.tremorTwMerge)(n,o,c,d)),f)},x),g)});n.displayName="Col",e.s(["Col",()=>n],309426)},677667,674175,886148,543086,e=>{"use strict";let t,s;var a,r=e.i(290571),l=e.i(429427),i=e.i(371330),n=e.i(271645),o=e.i(394487),c=e.i(914189),d=e.i(144279),u=e.i(294316),m=e.i(83733);let h=(0,n.createContext)(()=>{});function p({value:e,children:t}){return n.default.createElement(h.Provider,{value:e},t)}e.s(["CloseProvider",()=>p],674175);var g=e.i(233137),f=e.i(233538),x=e.i(397701),y=e.i(402155),b=e.i(700020);let _=null!=(a=n.default.startTransition)?a:function(e){e()};var v=e.i(998348),j=((t=j||{})[t.Open=0]="Open",t[t.Closed=1]="Closed",t),w=((s=w||{})[s.ToggleDisclosure=0]="ToggleDisclosure",s[s.CloseDisclosure=1]="CloseDisclosure",s[s.SetButtonId=2]="SetButtonId",s[s.SetPanelId=3]="SetPanelId",s[s.SetButtonElement=4]="SetButtonElement",s[s.SetPanelElement=5]="SetPanelElement",s);let k={0:e=>({...e,disclosureState:(0,x.match)(e.disclosureState,{0:1,1:0})}),1:e=>1===e.disclosureState?e:{...e,disclosureState:1},2:(e,t)=>e.buttonId===t.buttonId?e:{...e,buttonId:t.buttonId},3:(e,t)=>e.panelId===t.panelId?e:{...e,panelId:t.panelId},4:(e,t)=>e.buttonElement===t.element?e:{...e,buttonElement:t.element},5:(e,t)=>e.panelElement===t.element?e:{...e,panelElement:t.element}},N=(0,n.createContext)(null);function S(e){let t=(0,n.useContext)(N);if(null===t){let t=Error(`<${e} /> is missing a parent component.`);throw Error.captureStackTrace&&Error.captureStackTrace(t,S),t}return t}N.displayName="DisclosureContext";let C=(0,n.createContext)(null);C.displayName="DisclosureAPIContext";let T=(0,n.createContext)(null);function E(e,t){return(0,x.match)(t.type,k,e,t)}T.displayName="DisclosurePanelContext";let I=n.Fragment,A=b.RenderFeatures.RenderStrategy|b.RenderFeatures.Static,O=Object.assign((0,b.forwardRefWithAs)(function(e,t){let{defaultOpen:s=!1,...a}=e,r=(0,n.useRef)(null),l=(0,u.useSyncRefs)(t,(0,u.optionalRef)(e=>{r.current=e},void 0===e.as||e.as===n.Fragment)),i=(0,n.useReducer)(E,{disclosureState:+!s,buttonElement:null,panelElement:null,buttonId:null,panelId:null}),[{disclosureState:o,buttonId:d},m]=i,h=(0,c.useEvent)(e=>{m({type:1});let t=(0,y.getOwnerDocument)(r);if(!t||!d)return;let s=e?e instanceof HTMLElement?e:e.current instanceof HTMLElement?e.current:t.getElementById(d):t.getElementById(d);null==s||s.focus()}),f=(0,n.useMemo)(()=>({close:h}),[h]),_=(0,n.useMemo)(()=>({open:0===o,close:h}),[o,h]),v=(0,b.useRender)();return n.default.createElement(N.Provider,{value:i},n.default.createElement(C.Provider,{value:f},n.default.createElement(p,{value:h},n.default.createElement(g.OpenClosedProvider,{value:(0,x.match)(o,{0:g.State.Open,1:g.State.Closed})},v({ourProps:{ref:l},theirProps:a,slot:_,defaultTag:I,name:"Disclosure"})))))}),{Button:(0,b.forwardRefWithAs)(function(e,t){let s=(0,n.useId)(),{id:a=`headlessui-disclosure-button-${s}`,disabled:r=!1,autoFocus:m=!1,...h}=e,[p,g]=S("Disclosure.Button"),x=(0,n.useContext)(T),y=null!==x&&x===p.panelId,_=(0,n.useRef)(null),j=(0,u.useSyncRefs)(_,t,(0,c.useEvent)(e=>{if(!y)return g({type:4,element:e})}));(0,n.useEffect)(()=>{if(!y)return g({type:2,buttonId:a}),()=>{g({type:2,buttonId:null})}},[a,g,y]);let w=(0,c.useEvent)(e=>{var t;if(y){if(1===p.disclosureState)return;switch(e.key){case v.Keys.Space:case v.Keys.Enter:e.preventDefault(),e.stopPropagation(),g({type:0}),null==(t=p.buttonElement)||t.focus()}}else switch(e.key){case v.Keys.Space:case v.Keys.Enter:e.preventDefault(),e.stopPropagation(),g({type:0})}}),k=(0,c.useEvent)(e=>{e.key===v.Keys.Space&&e.preventDefault()}),N=(0,c.useEvent)(e=>{var t;(0,f.isDisabledReactIssue7711)(e.currentTarget)||r||(y?(g({type:0}),null==(t=p.buttonElement)||t.focus()):g({type:0}))}),{isFocusVisible:C,focusProps:E}=(0,l.useFocusRing)({autoFocus:m}),{isHovered:I,hoverProps:A}=(0,i.useHover)({isDisabled:r}),{pressed:O,pressProps:L}=(0,o.useActivePress)({disabled:r}),M=(0,n.useMemo)(()=>({open:0===p.disclosureState,hover:I,active:O,disabled:r,focus:C,autofocus:m}),[p,I,O,C,r,m]),F=(0,d.useResolveButtonType)(e,p.buttonElement),R=y?(0,b.mergeProps)({ref:j,type:F,disabled:r||void 0,autoFocus:m,onKeyDown:w,onClick:N},E,A,L):(0,b.mergeProps)({ref:j,id:a,type:F,"aria-expanded":0===p.disclosureState,"aria-controls":p.panelElement?p.panelId:void 0,disabled:r||void 0,autoFocus:m,onKeyDown:w,onKeyUp:k,onClick:N},E,A,L);return(0,b.useRender)()({ourProps:R,theirProps:h,slot:M,defaultTag:"button",name:"Disclosure.Button"})}),Panel:(0,b.forwardRefWithAs)(function(e,t){let s=(0,n.useId)(),{id:a=`headlessui-disclosure-panel-${s}`,transition:r=!1,...l}=e,[i,o]=S("Disclosure.Panel"),{close:d}=function e(t){let s=(0,n.useContext)(C);if(null===s){let s=Error(`<${t} /> is missing a parent component.`);throw Error.captureStackTrace&&Error.captureStackTrace(s,e),s}return s}("Disclosure.Panel"),[h,p]=(0,n.useState)(null),f=(0,u.useSyncRefs)(t,(0,c.useEvent)(e=>{_(()=>o({type:5,element:e}))}),p);(0,n.useEffect)(()=>(o({type:3,panelId:a}),()=>{o({type:3,panelId:null})}),[a,o]);let x=(0,g.useOpenClosed)(),[y,v]=(0,m.useTransition)(r,h,null!==x?(x&g.State.Open)===g.State.Open:0===i.disclosureState),j=(0,n.useMemo)(()=>({open:0===i.disclosureState,close:d}),[i.disclosureState,d]),w={ref:f,id:a,...(0,m.transitionDataAttributes)(v)},k=(0,b.useRender)();return n.default.createElement(g.ResetOpenClosedProvider,null,n.default.createElement(T.Provider,{value:i.panelId},k({ourProps:w,theirProps:l,slot:j,defaultTag:"div",features:A,visible:y,name:"Disclosure.Panel"})))})});e.s(["Disclosure",()=>O],886148);let L=(0,n.createContext)(void 0);var M=e.i(444755);let F=(0,e.i(673706).makeClassName)("Accordion"),R=(0,n.createContext)({isOpen:!1}),P=n.default.forwardRef((e,t)=>{var s;let{defaultOpen:a=!1,children:l,className:i}=e,o=(0,r.__rest)(e,["defaultOpen","children","className"]),c=null!=(s=(0,n.useContext)(L))?s:(0,M.tremorTwMerge)("rounded-tremor-default border");return n.default.createElement(O,Object.assign({as:"div",ref:t,className:(0,M.tremorTwMerge)(F("root"),"overflow-hidden","bg-tremor-background border-tremor-border","dark:bg-dark-tremor-background dark:border-dark-tremor-border",c,i),defaultOpen:a},o),({open:e})=>n.default.createElement(R.Provider,{value:{isOpen:e}},l))});P.displayName="Accordion",e.s(["OpenContext",()=>R,"default",()=>P],543086),e.s(["Accordion",()=>P],677667)},898667,e=>{"use strict";var t=e.i(290571),s=e.i(271645),a=e.i(886148);let r=e=>{var a=(0,t.__rest)(e,[]);return s.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},a),s.default.createElement("path",{d:"M11.9999 10.8284L7.0502 15.7782L5.63599 14.364L11.9999 8L18.3639 14.364L16.9497 15.7782L11.9999 10.8284Z"}))};var l=e.i(543086),i=e.i(444755);let n=(0,e.i(673706).makeClassName)("AccordionHeader"),o=s.default.forwardRef((e,o)=>{let{children:c,className:d}=e,u=(0,t.__rest)(e,["children","className"]),{isOpen:m}=(0,s.useContext)(l.OpenContext);return s.default.createElement(a.Disclosure.Button,Object.assign({ref:o,className:(0,i.tremorTwMerge)(n("root"),"w-full flex items-center justify-between px-4 py-3","text-tremor-content-emphasis","dark:text-dark-tremor-content-emphasis",d)},u),s.default.createElement("div",{className:(0,i.tremorTwMerge)(n("children"),"flex flex-1 text-inherit mr-4")},c),s.default.createElement("div",null,s.default.createElement(r,{className:(0,i.tremorTwMerge)(n("arrowIcon"),"h-5 w-5 -mr-1","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle",m?"transition-all":"transition-all -rotate-180")})))});o.displayName="AccordionHeader",e.s(["AccordionHeader",()=>o],898667)},130643,e=>{"use strict";var t=e.i(290571),s=e.i(271645),a=e.i(886148),r=e.i(444755);let l=(0,e.i(673706).makeClassName)("AccordionBody"),i=s.default.forwardRef((e,i)=>{let{children:n,className:o}=e,c=(0,t.__rest)(e,["children","className"]);return s.default.createElement(a.Disclosure.Panel,Object.assign({ref:i,className:(0,r.tremorTwMerge)(l("root"),"w-full text-tremor-default px-4 pb-3","text-tremor-content","dark:text-dark-tremor-content",o)},c),n)});i.displayName="AccordionBody",e.s(["AccordionBody",()=>i],130643)},950724,(e,t,s)=>{t.exports=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}},100236,(e,t,s)=>{t.exports=e.g&&e.g.Object===Object&&e.g},139088,(e,t,s)=>{var a=e.r(100236),r="object"==typeof self&&self&&self.Object===Object&&self;t.exports=a||r||Function("return this")()},631926,(e,t,s)=>{var a=e.r(139088);t.exports=function(){return a.Date.now()}},748891,(e,t,s)=>{var a=/\s/;t.exports=function(e){for(var t=e.length;t--&&a.test(e.charAt(t)););return t}},830364,(e,t,s)=>{var a=e.r(748891),r=/^\s+/;t.exports=function(e){return e?e.slice(0,a(e)+1).replace(r,""):e}},630353,(e,t,s)=>{t.exports=e.r(139088).Symbol},243436,(e,t,s)=>{var a=e.r(630353),r=Object.prototype,l=r.hasOwnProperty,i=r.toString,n=a?a.toStringTag:void 0;t.exports=function(e){var t=l.call(e,n),s=e[n];try{e[n]=void 0;var a=!0}catch(e){}var r=i.call(e);return a&&(t?e[n]=s:delete e[n]),r}},223243,(e,t,s)=>{var a=Object.prototype.toString;t.exports=function(e){return a.call(e)}},377684,(e,t,s)=>{var a=e.r(630353),r=e.r(243436),l=e.r(223243),i=a?a.toStringTag:void 0;t.exports=function(e){return null==e?void 0===e?"[object Undefined]":"[object Null]":i&&i in Object(e)?r(e):l(e)}},877289,(e,t,s)=>{t.exports=function(e){return null!=e&&"object"==typeof e}},361884,(e,t,s)=>{var a=e.r(377684),r=e.r(877289);t.exports=function(e){return"symbol"==typeof e||r(e)&&"[object Symbol]"==a(e)}},773759,(e,t,s)=>{var a=e.r(830364),r=e.r(950724),l=e.r(361884),i=0/0,n=/^[-+]0x[0-9a-f]+$/i,o=/^0b[01]+$/i,c=/^0o[0-7]+$/i,d=parseInt;t.exports=function(e){if("number"==typeof e)return e;if(l(e))return i;if(r(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=r(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=a(e);var s=o.test(e);return s||c.test(e)?d(e.slice(2),s?2:8):n.test(e)?i:+e}},374009,(e,t,s)=>{var a=e.r(950724),r=e.r(631926),l=e.r(773759),i=Math.max,n=Math.min;t.exports=function(e,t,s){var o,c,d,u,m,h,p=0,g=!1,f=!1,x=!0;if("function"!=typeof e)throw TypeError("Expected a function");function y(t){var s=o,a=c;return o=c=void 0,p=t,u=e.apply(a,s)}function b(e){var s=e-h,a=e-p;return void 0===h||s>=t||s<0||f&&a>=d}function _(){var e,s,a,l=r();if(b(l))return v(l);m=setTimeout(_,(e=l-h,s=l-p,a=t-e,f?n(a,d-s):a))}function v(e){return(m=void 0,x&&o)?y(e):(o=c=void 0,u)}function j(){var e,s=r(),a=b(s);if(o=arguments,c=this,h=s,a){if(void 0===m)return p=e=h,m=setTimeout(_,t),g?y(e):u;if(f)return clearTimeout(m),m=setTimeout(_,t),y(h)}return void 0===m&&(m=setTimeout(_,t)),u}return t=l(t)||0,a(s)&&(g=!!s.leading,d=(f="maxWait"in s)?i(l(s.maxWait)||0,t):d,x="trailing"in s?!!s.trailing:x),j.cancel=function(){void 0!==m&&clearTimeout(m),p=0,o=h=c=m=void 0},j.flush=function(){return void 0===m?u:v(r())},j}},964306,e=>{"use strict";var t=e.i(271645);let s=t.forwardRef(function(e,s){return t.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:s},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["XCircleIcon",0,s],964306)},9314,263147,e=>{"use strict";var t=e.i(843476),s=e.i(199133),a=e.i(981339),r=e.i(645526),l=e.i(599724),i=e.i(266027),n=e.i(243652),o=e.i(764205),c=e.i(708347),d=e.i(135214);let u=(0,n.createQueryKeys)("accessGroups"),m=async e=>{let t=(0,o.getProxyBaseUrl)(),s=`${t}/v1/access_group`,a=await fetch(s,{method:"GET",headers:{[(0,o.getGlobalLitellmHeaderName)()]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!a.ok){let e=await a.json(),t=(0,o.deriveErrorMessage)(e);throw(0,o.handleError)(t),Error(t)}return a.json()},h=()=>{let{accessToken:e,userRole:t}=(0,d.default)();return(0,i.useQuery)({queryKey:u.list({}),queryFn:async()=>m(e),enabled:!!e&&c.all_admin_roles.includes(t||"")})};e.s(["accessGroupKeys",0,u,"useAccessGroups",0,h],263147),e.s(["default",0,({value:e,onChange:i,placeholder:n="Select access groups",disabled:o=!1,style:c,className:d,showLabel:u=!1,labelText:m="Access Group",allowClear:p=!0})=>{let{data:g,isLoading:f,isError:x}=h();if(f)return(0,t.jsxs)("div",{children:[u&&(0,t.jsxs)(l.Text,{className:"font-medium block mb-2 text-gray-700 flex items-center",children:[(0,t.jsx)(r.TeamOutlined,{className:"mr-2"})," ",m]}),(0,t.jsx)(a.Skeleton.Input,{active:!0,block:!0,style:{height:32,...c}})]});let y=(g??[]).map(e=>({label:(0,t.jsxs)("span",{children:[(0,t.jsx)("span",{className:"font-medium",children:e.access_group_name})," ",(0,t.jsxs)("span",{className:"text-gray-400 text-xs",children:["(",e.access_group_id,")"]})]}),value:e.access_group_id,selectedLabel:e.access_group_name,searchText:`${e.access_group_name} ${e.access_group_id}`}));return(0,t.jsxs)("div",{children:[u&&(0,t.jsxs)(l.Text,{className:"font-medium block mb-2 text-gray-700 flex items-center",children:[(0,t.jsx)(r.TeamOutlined,{className:"mr-2"})," ",m]}),(0,t.jsx)(s.Select,{mode:"multiple",value:e,placeholder:n,onChange:i,disabled:o,allowClear:p,showSearch:!0,style:{width:"100%",...c},className:`rounded-md ${d??""}`,notFoundContent:x?(0,t.jsx)("span",{className:"text-red-500",children:"Failed to load access groups"}):"No access groups found",filterOption:(e,t)=>(y.find(e=>e.value===t?.value)?.searchText??"").toLowerCase().includes(e.toLowerCase()),optionLabelProp:"selectedLabel",options:y.map(e=>({label:e.label,value:e.value,selectedLabel:e.selectedLabel}))})]})}],9314)},552130,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(199133),r=e.i(764205);e.s(["default",0,({onChange:e,value:l,className:i,accessToken:n,placeholder:o="Select agents",disabled:c=!1})=>{let[d,u]=(0,s.useState)([]),[m,h]=(0,s.useState)([]),[p,g]=(0,s.useState)(!1);(0,s.useEffect)(()=>{(async()=>{if(n){g(!0);try{let e=await (0,r.getAgentsList)(n),t=e?.agents||[];u(t);let s=new Set;t.forEach(e=>{let t=e.agent_access_groups;t&&Array.isArray(t)&&t.forEach(e=>s.add(e))}),h(Array.from(s))}catch(e){console.error("Error fetching agents:",e)}finally{g(!1)}}})()},[n]);let f=[...m.map(e=>({label:e,value:`group:${e}`,isAccessGroup:!0,searchText:`${e} Access Group`})),...d.map(e=>({label:`${e.agent_name||e.agent_id}`,value:e.agent_id,isAccessGroup:!1,searchText:`${e.agent_name||e.agent_id} ${e.agent_id} Agent`}))],x=[...l?.agents||[],...(l?.accessGroups||[]).map(e=>`group:${e}`)];return(0,t.jsx)("div",{children:(0,t.jsx)(a.Select,{mode:"multiple",placeholder:o,onChange:t=>{e({agents:t.filter(e=>!e.startsWith("group:")),accessGroups:t.filter(e=>e.startsWith("group:")).map(e=>e.replace("group:",""))})},value:x,loading:p,className:i,allowClear:!0,showSearch:!0,style:{width:"100%"},disabled:c,filterOption:(e,t)=>(f.find(e=>e.value===t?.value)?.searchText||"").toLowerCase().includes(e.toLowerCase()),children:f.map(e=>(0,t.jsx)(a.Select.Option,{value:e.value,label:e.label,children:(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"8px"},children:[(0,t.jsx)("span",{style:{display:"inline-block",width:8,height:8,borderRadius:"50%",background:e.isAccessGroup?"#52c41a":"#722ed1",flexShrink:0}}),(0,t.jsx)("span",{style:{flex:1},children:e.label}),(0,t.jsx)("span",{style:{color:e.isAccessGroup?"#52c41a":"#722ed1",fontSize:"12px",fontWeight:500,opacity:.8},children:e.isAccessGroup?"Access Group":"Agent"})]})},e.value))})})}])},844565,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(199133),r=e.i(764205);e.s(["default",0,({onChange:e,value:l,className:i,accessToken:n,placeholder:o="Select pass through routes",disabled:c=!1,teamId:d})=>{let[u,m]=(0,s.useState)([]),[h,p]=(0,s.useState)(!1);return(0,s.useEffect)(()=>{(async()=>{if(n){p(!0);try{let e=await (0,r.getPassThroughEndpointsCall)(n,d);if(e.endpoints){let t=e.endpoints.flatMap(e=>{let t=e.path,s=e.methods;return s&&s.length>0?s.map(e=>({label:`${e} ${t}`,value:t})):[{label:t,value:t}]});m(t)}}catch(e){console.error("Error fetching pass through routes:",e)}finally{p(!1)}}})()},[n,d]),(0,t.jsx)(a.Select,{mode:"tags",placeholder:o,onChange:e,value:l,loading:h,className:i,allowClear:!0,options:u,optionFilterProp:"label",showSearch:!0,style:{width:"100%"},disabled:c})}])},810757,477386,e=>{"use strict";var t=e.i(271645);let s=t.forwardRef(function(e,s){return t.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:s},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"}),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15 12a3 3 0 11-6 0 3 3 0 016 0z"}))});e.s(["CogIcon",0,s],810757);let a=t.forwardRef(function(e,s){return t.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:s},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"}))});e.s(["BanIcon",0,a],477386)},557662,e=>{"use strict";let t="../ui/assets/logos/",s=[{id:"arize",displayName:"Arize",logo:`${t}arize.png`,supports_key_team_logging:!0,dynamic_params:{arize_api_key:"password",arize_space_id:"password"},description:"Arize Logging Integration"},{id:"braintrust",displayName:"Braintrust",logo:`${t}braintrust.png`,supports_key_team_logging:!1,dynamic_params:{braintrust_api_key:"password",braintrust_project_name:"text"},description:"Braintrust Logging Integration"},{id:"custom_callback_api",displayName:"Custom Callback API",logo:`${t}custom.svg`,supports_key_team_logging:!0,dynamic_params:{custom_callback_api_url:"text",custom_callback_api_headers:"text"},description:"Custom Callback API Logging Integration"},{id:"datadog",displayName:"Datadog",logo:`${t}datadog.png`,supports_key_team_logging:!1,dynamic_params:{dd_api_key:"password",dd_site:"text"},description:"Datadog Logging Integration"},{id:"lago",displayName:"Lago",logo:`${t}lago.svg`,supports_key_team_logging:!1,dynamic_params:{lago_api_url:"text",lago_api_key:"password"},description:"Lago Billing Logging Integration"},{id:"langfuse",displayName:"Langfuse",logo:`${t}langfuse.png`,supports_key_team_logging:!0,dynamic_params:{langfuse_public_key:"text",langfuse_secret_key:"password",langfuse_host:"text"},description:"Langfuse v2 Logging Integration"},{id:"langfuse_otel",displayName:"Langfuse OTEL",logo:`${t}langfuse.png`,supports_key_team_logging:!0,dynamic_params:{langfuse_public_key:"text",langfuse_secret_key:"password",langfuse_host:"text"},description:"Langfuse v3 OTEL Logging Integration"},{id:"langsmith",displayName:"LangSmith",logo:`${t}langsmith.png`,supports_key_team_logging:!0,dynamic_params:{langsmith_api_key:"password",langsmith_project:"text",langsmith_base_url:"text",langsmith_sampling_rate:"number"},description:"Langsmith Logging Integration"},{id:"openmeter",displayName:"OpenMeter",logo:`${t}openmeter.png`,supports_key_team_logging:!1,dynamic_params:{openmeter_api_key:"password",openmeter_base_url:"text"},description:"OpenMeter Logging Integration"},{id:"otel",displayName:"Open Telemetry",logo:`${t}otel.png`,supports_key_team_logging:!1,dynamic_params:{otel_endpoint:"text",otel_headers:"text"},description:"OpenTelemetry Logging Integration"},{id:"s3",displayName:"S3",logo:`${t}aws.svg`,supports_key_team_logging:!1,dynamic_params:{s3_bucket_name:"text",aws_access_key_id:"password",aws_secret_access_key:"password",aws_region:"text"},description:"S3 Bucket (AWS) Logging Integration"},{id:"SQS",displayName:"SQS",logo:`${t}aws.svg`,supports_key_team_logging:!1,dynamic_params:{sqs_queue_url:"text",aws_access_key_id:"password",aws_secret_access_key:"password",aws_region:"text"},description:"SQS Queue (AWS) Logging Integration"}],a=s.reduce((e,t)=>(e[t.displayName]=t,e),{}),r=s.reduce((e,t)=>(e[t.displayName]=t.id,e),{}),l=s.reduce((e,t)=>(e[t.id]=t.displayName,e),{});e.s(["callbackInfo",0,a,"callback_map",0,r,"mapDisplayToInternalNames",0,e=>e.map(e=>r[e]||e),"mapInternalToDisplayNames",0,e=>e.map(e=>l[e]||e),"reverse_callback_map",0,l])},75921,e=>{"use strict";var t=e.i(843476),s=e.i(266027),a=e.i(243652),r=e.i(764205),l=e.i(135214);let i=(0,a.createQueryKeys)("mcpAccessGroups");var n=e.i(500727),o=e.i(199133);e.s(["default",0,({onChange:e,value:a,className:c,accessToken:d,placeholder:u="Select MCP servers",disabled:m=!1,teamId:h})=>{let{data:p=[],isLoading:g}=(0,n.useMCPServers)(h),{data:f=[],isLoading:x}=(()=>{let{accessToken:e}=(0,l.default)();return(0,s.useQuery)({queryKey:i.list({}),queryFn:async()=>await (0,r.fetchMCPAccessGroups)(e),enabled:!!e})})(),y=[...f.map(e=>({label:e,value:e,isAccessGroup:!0,searchText:`${e} Access Group`})),...p.map(e=>({label:`${e.server_name||e.server_id} (${e.server_id})`,value:e.server_id,isAccessGroup:!1,searchText:`${e.server_name||e.server_id} ${e.server_id} MCP Server`}))],b=[...a?.servers||[],...a?.accessGroups||[]];return(0,t.jsx)("div",{children:(0,t.jsx)(o.Select,{mode:"multiple",placeholder:u,onChange:t=>{e({servers:t.filter(e=>!f.includes(e)),accessGroups:t.filter(e=>f.includes(e))})},value:b,loading:g||x,className:c,allowClear:!0,showSearch:!0,style:{width:"100%"},disabled:m,filterOption:(e,t)=>(y.find(e=>e.value===t?.value)?.searchText||"").toLowerCase().includes(e.toLowerCase()),children:y.map(e=>(0,t.jsx)(o.Select.Option,{value:e.value,label:e.label,children:(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"8px"},children:[(0,t.jsx)("span",{style:{display:"inline-block",width:8,height:8,borderRadius:"50%",background:e.isAccessGroup?"#52c41a":"#1890ff",flexShrink:0}}),(0,t.jsx)("span",{style:{flex:1},children:e.label}),(0,t.jsx)("span",{style:{color:e.isAccessGroup?"#52c41a":"#1890ff",fontSize:"12px",fontWeight:500,opacity:.8},children:e.isAccessGroup?"Access Group":"MCP Server"})]})},e.value))})})}],75921)},390605,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(764205),r=e.i(599724),l=e.i(482725),i=e.i(91739),n=e.i(500727),o=e.i(531516),c=e.i(696609);e.s(["default",0,({accessToken:e,selectedServers:d,toolPermissions:u,onChange:m,disabled:h=!1})=>{let{data:p=[]}=(0,n.useMCPServers)(),[g,f]=(0,s.useState)({}),[x,y]=(0,s.useState)({}),[b,_]=(0,s.useState)({}),[v,j]=(0,s.useState)({}),w=(0,s.useRef)(u);(0,s.useEffect)(()=>{w.current=u},[u]);let k=(0,s.useMemo)(()=>0===d.length?[]:p.filter(e=>d.includes(e.server_id)),[p,d]),N=async(e,t)=>{y(t=>({...t,[e]:!0})),_(t=>({...t,[e]:""}));try{let s=await (0,a.listMCPTools)(t,e);if(s.error)_(t=>({...t,[e]:s.message||"Failed to fetch tools"})),f(t=>({...t,[e]:[]}));else{let t=s.tools||[];f(s=>({...s,[e]:t}));let a=w.current;if(!a[e]&&t.length>0){let s=t.filter(e=>"delete"!==(0,c.classifyToolOp)(e.name,e.description||"")).map(e=>e.name);m({...a,[e]:s})}}}catch(t){console.error(`Error fetching tools for server ${e}:`,t),_(t=>({...t,[e]:"Failed to fetch tools"})),f(t=>({...t,[e]:[]}))}finally{y(t=>({...t,[e]:!1}))}};(0,s.useEffect)(()=>{k.forEach(t=>{g[t.server_id]||x[t.server_id]||N(t.server_id,e)})},[k,e]);let S=(e,t)=>{m({...u,[e]:t})};return 0===d.length?null:(0,t.jsx)("div",{className:"space-y-4",children:k.map(e=>{let s=e.server_name||e.alias||e.server_id,a=g[e.server_id]||[],n=u[e.server_id]||[],c=x[e.server_id],d=b[e.server_id],p=v[e.server_id]??"crud";return(0,t.jsxs)("div",{className:"border rounded-lg bg-gray-50",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between p-4 border-b bg-white rounded-t-lg",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:s}),e.description&&(0,t.jsx)(r.Text,{className:"text-sm text-gray-500",children:e.description})]}),(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[!h&&a.length>0&&(0,t.jsx)(i.Radio.Group,{value:p,onChange:t=>j(s=>({...s,[e.server_id]:t.target.value})),size:"small",optionType:"button",buttonStyle:"solid",options:[{label:"Risk Groups",value:"crud"},{label:"Flat List",value:"flat"}]}),!h&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("button",{type:"button",className:"text-sm text-blue-600 hover:text-blue-700 font-medium",onClick:()=>{var t;let s;return s=g[t=e.server_id]||[],void m({...u,[t]:s.map(e=>e.name)})},disabled:c,children:"Select All"}),(0,t.jsx)("button",{type:"button",className:"text-sm text-blue-600 hover:text-blue-700 font-medium",onClick:()=>{var t;return t=e.server_id,void m({...u,[t]:[]})},disabled:c,children:"Deselect All"})]})]})]}),(0,t.jsxs)("div",{className:"p-4",children:[c&&(0,t.jsxs)("div",{className:"flex items-center justify-center py-8",children:[(0,t.jsx)(l.Spin,{size:"large"}),(0,t.jsx)(r.Text,{className:"ml-3 text-gray-500",children:"Loading tools..."})]}),d&&!c&&(0,t.jsxs)("div",{className:"p-4 bg-red-50 border border-red-200 rounded-lg text-center",children:[(0,t.jsx)(r.Text,{className:"text-red-600 font-medium",children:"Unable to load tools"}),(0,t.jsx)(r.Text,{className:"text-sm text-red-500 mt-1",children:d})]}),!c&&!d&&a.length>0&&"crud"===p&&(0,t.jsx)(o.default,{tools:a,value:u[e.server_id]?n:void 0,onChange:t=>S(e.server_id,t),readOnly:h}),!c&&!d&&a.length>0&&"flat"===p&&(0,t.jsx)("div",{className:"space-y-2",children:a.map(s=>{let a=n.includes(s.name);return(0,t.jsxs)("div",{className:"flex items-start gap-2",children:[(0,t.jsx)("input",{type:"checkbox",checked:a,onChange:()=>{if(h)return;let t=a?n.filter(e=>e!==s.name):[...n,s.name];S(e.server_id,t)},disabled:h,className:"mt-0.5"}),(0,t.jsx)("div",{className:"flex-1 min-w-0",children:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(r.Text,{className:"font-medium text-gray-900",children:s.name}),(0,t.jsxs)(r.Text,{className:"text-sm text-gray-500",children:["- ",s.description||"No description"]})]})})]},s.name)})}),!c&&!d&&0===a.length&&(0,t.jsx)("div",{className:"text-center py-6",children:(0,t.jsx)(r.Text,{className:"text-gray-500",children:"No tools available"})})]})]},e.server_id)})})}])},266484,e=>{"use strict";var t=e.i(843476),s=e.i(199133),a=e.i(592968),r=e.i(312361),l=e.i(827252),i=e.i(994388),n=e.i(304967),o=e.i(779241),c=e.i(988297),d=e.i(68155),u=e.i(810757),m=e.i(477386),h=e.i(557662),p=e.i(435451);let{Option:g}=s.Select;e.s(["default",0,({value:e=[],onChange:f,disabledCallbacks:x=[],onDisabledCallbacksChange:y})=>{let b=Object.entries(h.callbackInfo).filter(([e,t])=>t.supports_key_team_logging).map(([e,t])=>e),_=Object.keys(h.callbackInfo),v=e=>{f?.(e)},j=(t,s,a)=>{let r=[...e];if("callback_name"===s){let e=h.callback_map[a]||a;r[t]={...r[t],[s]:e,callback_vars:{}}}else r[t]={...r[t],[s]:a};v(r)},w=(t,s,a)=>{let r=[...e];r[t]={...r[t],callback_vars:{...r[t].callback_vars,[s]:a}},v(r)};return(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,t.jsx)(m.BanIcon,{className:"w-5 h-5 text-red-500"}),(0,t.jsx)("span",{className:"text-base font-semibold text-gray-800",children:"Disabled Callbacks"}),(0,t.jsx)(a.Tooltip,{title:"Select callbacks to disable for this key. Disabled callbacks will not receive any logging data.",children:(0,t.jsx)(l.InfoCircleOutlined,{className:"text-gray-400 cursor-help"})})]}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)("label",{className:"text-sm font-medium text-gray-700",children:"Disabled Callbacks"}),(0,t.jsx)(s.Select,{mode:"multiple",placeholder:"Select callbacks to disable",value:x,onChange:e=>{let t=(0,h.mapDisplayToInternalNames)(e);y?.(t)},style:{width:"100%"},optionLabelProp:"label",children:_.map(e=>{let s=h.callbackInfo[e]?.logo,r=h.callbackInfo[e]?.description;return(0,t.jsx)(g,{value:e,label:e,children:(0,t.jsx)(a.Tooltip,{title:r,placement:"right",children:(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[s&&(0,t.jsx)("img",{src:s,alt:e,className:"w-4 h-4 object-contain",onError:t=>{let s=t.target,a=s.parentElement;if(a){let t=document.createElement("div");t.className="w-4 h-4 rounded-full bg-gray-200 flex items-center justify-center text-xs",t.textContent=e.charAt(0),a.replaceChild(t,s)}}}),(0,t.jsx)("span",{children:e})]})})},e)})}),(0,t.jsx)("div",{className:"text-xs text-gray-500",children:"Select callbacks that should be disabled for this key. These callbacks will not receive any logging data."})]})]}),(0,t.jsx)(r.Divider,{}),(0,t.jsxs)("div",{className:"flex justify-between items-center",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,t.jsx)(u.CogIcon,{className:"w-5 h-5 text-blue-500"}),(0,t.jsx)("span",{className:"text-base font-semibold text-gray-800",children:"Logging Integrations"}),(0,t.jsx)(a.Tooltip,{title:"Configure callback logging integrations for this team.",children:(0,t.jsx)(l.InfoCircleOutlined,{className:"text-gray-400 cursor-help"})})]}),(0,t.jsx)(i.Button,{variant:"secondary",onClick:()=>{v([...e,{callback_name:"",callback_type:"success",callback_vars:{}}])},icon:c.PlusIcon,size:"sm",className:"hover:border-blue-400 hover:text-blue-500",type:"button",children:"Add Integration"})]}),(0,t.jsx)("div",{className:"space-y-4",children:e.map((r,c)=>{let u=r.callback_name?Object.entries(h.callback_map).find(([e,t])=>t===r.callback_name)?.[0]:void 0,m=u?h.callbackInfo[u]?.logo:null;return(0,t.jsxs)(n.Card,{className:"border border-gray-200 shadow-sm hover:shadow-md transition-shadow duration-200",decoration:"top",decorationColor:"blue",children:[(0,t.jsxs)("div",{className:"flex justify-between items-start mb-4",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[m&&(0,t.jsx)("img",{src:m,alt:u,className:"w-5 h-5 object-contain"}),(0,t.jsxs)("span",{className:"text-sm font-medium",children:[u||"New Integration"," Configuration"]})]}),(0,t.jsx)(i.Button,{variant:"light",onClick:()=>{v(e.filter((e,t)=>t!==c))},icon:d.TrashIcon,size:"xs",color:"red",className:"hover:bg-red-50",type:"button",children:"Remove"})]}),(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)("label",{className:"text-sm font-medium text-gray-700",children:"Integration Type"}),(0,t.jsx)(s.Select,{value:u,placeholder:"Select integration",onChange:e=>j(c,"callback_name",e),className:"w-full",optionLabelProp:"label",children:b.map(e=>{let s=h.callbackInfo[e]?.logo,r=h.callbackInfo[e]?.description;return(0,t.jsx)(g,{value:e,label:e,children:(0,t.jsx)(a.Tooltip,{title:r,placement:"right",children:(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[s&&(0,t.jsx)("img",{src:s,alt:e,className:"w-4 h-4 object-contain",onError:t=>{let s=t.target,a=s.parentElement;if(a){let t=document.createElement("div");t.className="w-4 h-4 rounded-full bg-gray-200 flex items-center justify-center text-xs",t.textContent=e.charAt(0),a.replaceChild(t,s)}}}),(0,t.jsx)("span",{children:e})]})})},e)})})]}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)("label",{className:"text-sm font-medium text-gray-700",children:"Event Type"}),(0,t.jsxs)(s.Select,{value:r.callback_type,onChange:e=>j(c,"callback_type",e),className:"w-full",children:[(0,t.jsx)(g,{value:"success",children:(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,t.jsx)("div",{className:"w-2 h-2 bg-green-500 rounded-full"}),(0,t.jsx)("span",{children:"Success Only"})]})}),(0,t.jsx)(g,{value:"failure",children:(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,t.jsx)("div",{className:"w-2 h-2 bg-red-500 rounded-full"}),(0,t.jsx)("span",{children:"Failure Only"})]})}),(0,t.jsx)(g,{value:"success_and_failure",children:(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,t.jsx)("div",{className:"w-2 h-2 bg-blue-500 rounded-full"}),(0,t.jsx)("span",{children:"Success & Failure"})]})})]})]})]}),((e,s)=>{if(!e.callback_name)return null;let r=Object.entries(h.callback_map).find(([t,s])=>s===e.callback_name)?.[0];if(!r)return null;let i=h.callbackInfo[r]?.dynamic_params||{};return 0===Object.keys(i).length?null:(0,t.jsxs)("div",{className:"mt-6 pt-4 border-t border-gray-100",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-2 mb-4",children:[(0,t.jsx)("div",{className:"w-3 h-3 bg-blue-100 rounded-full flex items-center justify-center",children:(0,t.jsx)("div",{className:"w-1.5 h-1.5 bg-blue-500 rounded-full"})}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700",children:"Integration Parameters"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-4",children:Object.entries(i).map(([r,i])=>(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("label",{className:"text-sm font-medium text-gray-700 capitalize flex items-center space-x-1",children:[(0,t.jsx)("span",{children:r.replace(/_/g," ")}),(0,t.jsx)(a.Tooltip,{title:`Environment variable reference recommended: os.environ/${r.toUpperCase()}`,children:(0,t.jsx)(l.InfoCircleOutlined,{className:"text-gray-400 cursor-help text-xs"})}),"password"===i&&(0,t.jsx)("span",{className:"inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-yellow-100 text-yellow-800",children:"Sensitive"}),"number"===i&&(0,t.jsx)("span",{className:"inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-yellow-100 text-yellow-800",children:"Number"})]}),"number"===i&&(0,t.jsx)("span",{className:"text-xs text-gray-500",children:"Value must be between 0 and 1"}),"number"===i?(0,t.jsx)(p.default,{step:.01,width:400,placeholder:`os.environ/${r.toUpperCase()}`,value:e.callback_vars[r]||"",onChange:e=>w(s,r,e.target.value)}):(0,t.jsx)(o.TextInput,{type:"password"===i?"password":"text",placeholder:`os.environ/${r.toUpperCase()}`,value:e.callback_vars[r]||"",onChange:e=>w(s,r,e.target.value)})]},r))})]})})(r,c)]})]},c)})}),0===e.length&&(0,t.jsxs)("div",{className:"text-center py-12 text-gray-500 border-2 border-dashed border-gray-200 rounded-lg bg-gray-50/50",children:[(0,t.jsx)(u.CogIcon,{className:"w-12 h-12 text-gray-300 mb-3 mx-auto"}),(0,t.jsx)("div",{className:"text-base font-medium mb-1",children:"No logging integrations configured"}),(0,t.jsx)("div",{className:"text-sm text-gray-400",children:'Click "Add Integration" to configure logging for this team'})]})]})}])},207082,e=>{"use strict";var t=e.i(619273),s=e.i(266027),a=e.i(243652),r=e.i(764205),l=e.i(135214);let i=(0,a.createQueryKeys)("keys"),n=async(e,t,s,a={})=>{try{let l=(0,r.getProxyBaseUrl)(),i=new URLSearchParams(Object.entries({team_id:a.teamID,project_id:a.projectID,organization_id:a.organizationID,key_alias:a.selectedKeyAlias,key_hash:a.keyHash,user_id:a.userID,page:t,size:s,sort_by:a.sortBy,sort_order:a.sortOrder,expand:a.expand,status:a.status,return_full_object:"true",include_team_keys:"true",include_created_by_keys:"true"}).filter(([,e])=>null!=e).map(([e,t])=>[e,String(t)])),n=`${l?`${l}/key/list`:"/key/list"}?${i}`,o=await fetch(n,{method:"GET",headers:{[(0,r.getGlobalLitellmHeaderName)()]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=(0,r.deriveErrorMessage)(e);throw(0,r.handleError)(t),Error(t)}let c=await o.json();return console.log("/key/list API Response:",c),c}catch(e){throw console.error("Failed to list keys:",e),e}},o=(0,a.createQueryKeys)("deletedKeys");e.s(["keyKeys",0,i,"useDeletedKeys",0,(e,a,r={})=>{let{accessToken:i}=(0,l.default)();return(0,s.useQuery)({queryKey:o.list({page:e,limit:a,...r}),queryFn:async()=>await n(i,e,a,{...r,status:"deleted"}),enabled:!!i,staleTime:3e4,placeholderData:t.keepPreviousData})},"useKeys",0,(e,a,r={})=>{let{accessToken:o}=(0,l.default)();return(0,s.useQuery)({queryKey:i.list({page:e,limit:a,...r}),queryFn:async()=>await n(o,e,a,r),enabled:!!o,staleTime:3e4,placeholderData:t.keepPreviousData})}])},510674,e=>{"use strict";var t=e.i(266027),s=e.i(243652),a=e.i(764205),r=e.i(708347),l=e.i(135214);let i=(0,s.createQueryKeys)("projects"),n=async e=>{let t=(0,a.getProxyBaseUrl)(),s=`${t}/project/list`,r=await fetch(s,{method:"GET",headers:{[(0,a.getGlobalLitellmHeaderName)()]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!r.ok){let e=await r.json(),t=(0,a.deriveErrorMessage)(e);throw(0,a.handleError)(t),Error(t)}return r.json()};e.s(["projectKeys",0,i,"useProjects",0,()=>{let{accessToken:e,userRole:s}=(0,l.default)();return(0,t.useQuery)({queryKey:i.list({}),queryFn:async()=>n(e),enabled:!!e&&r.all_admin_roles.includes(s||"")})}])},392110,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(199133),r=e.i(592968),l=e.i(312361),i=e.i(790848),n=e.i(536916),o=e.i(827252),c=e.i(779241);let{Option:d}=a.Select;e.s(["default",0,({form:e,autoRotationEnabled:u,onAutoRotationChange:m,rotationInterval:h,onRotationIntervalChange:p,isCreateMode:g=!1,neverExpire:f=!1,onNeverExpireChange:x})=>{let y=h&&!["7d","30d","90d","180d","365d"].includes(h),[b,_]=(0,s.useState)(y),[v,j]=(0,s.useState)(y?h:""),[w,k]=(0,s.useState)(e?.getFieldValue?.("duration")||"");return(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700",children:"Key Expiry Settings"}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("label",{className:"text-sm font-medium text-gray-700 flex items-center space-x-1",children:[(0,t.jsx)("span",{children:"Expire Key"}),(0,t.jsx)(r.Tooltip,{title:"Set when this key should expire. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days). Leave empty to keep the current expiry unchanged.",children:(0,t.jsx)(o.InfoCircleOutlined,{className:"text-gray-400 cursor-help text-xs"})}),!g&&x&&(0,t.jsx)(n.Checkbox,{checked:f,onChange:t=>{let s=t.target.checked;x(s),s&&(k(""),e&&"function"==typeof e.setFieldValue?e.setFieldValue("duration",""):e&&"function"==typeof e.setFieldsValue&&e.setFieldsValue({duration:""}))},className:"ml-2 text-sm font-normal text-gray-600",children:"Never Expire"})]}),(0,t.jsx)(c.TextInput,{name:"duration",placeholder:g?"e.g., 30d or leave empty to never expire":"e.g., 30d",className:"w-full",value:w,onValueChange:t=>{k(t),e&&"function"==typeof e.setFieldValue?e.setFieldValue("duration",t):e&&"function"==typeof e.setFieldsValue&&e.setFieldsValue({duration:t})},disabled:!g&&f})]})]}),(0,t.jsx)(l.Divider,{}),(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700",children:"Auto-Rotation Settings"}),(0,t.jsxs)("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("label",{className:"text-sm font-medium text-gray-700 flex items-center space-x-1",children:[(0,t.jsx)("span",{children:"Enable Auto-Rotation"}),(0,t.jsx)(r.Tooltip,{title:"Key will automatically regenerate at the specified interval for enhanced security.",children:(0,t.jsx)(o.InfoCircleOutlined,{className:"text-gray-400 cursor-help text-xs"})})]}),(0,t.jsx)(i.Switch,{checked:u,onChange:m,size:"default",className:u?"":"bg-gray-400"})]}),u&&(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("label",{className:"text-sm font-medium text-gray-700 flex items-center space-x-1",children:[(0,t.jsx)("span",{children:"Rotation Interval"}),(0,t.jsx)(r.Tooltip,{title:"How often the key should be automatically rotated. Choose the interval that best fits your security requirements.",children:(0,t.jsx)(o.InfoCircleOutlined,{className:"text-gray-400 cursor-help text-xs"})})]}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)(a.Select,{value:b?"custom":h,onChange:e=>{"custom"===e?_(!0):(_(!1),j(""),p(e))},className:"w-full",placeholder:"Select interval",children:[(0,t.jsx)(d,{value:"7d",children:"7 days"}),(0,t.jsx)(d,{value:"30d",children:"30 days"}),(0,t.jsx)(d,{value:"90d",children:"90 days"}),(0,t.jsx)(d,{value:"180d",children:"180 days"}),(0,t.jsx)(d,{value:"365d",children:"365 days"}),(0,t.jsx)(d,{value:"custom",children:"Custom interval"})]}),b&&(0,t.jsxs)("div",{className:"space-y-1",children:[(0,t.jsx)(c.TextInput,{value:v,onChange:e=>{let t=e.target.value;j(t),p(t)},placeholder:"e.g., 1s, 5m, 2h, 14d"}),(0,t.jsx)("div",{className:"text-xs text-gray-500",children:"Supported formats: seconds (s), minutes (m), hours (h), days (d)"})]})]})]})]}),u&&(0,t.jsx)("div",{className:"bg-blue-50 p-3 rounded-md text-sm text-blue-700",children:"When rotation occurs, you'll receive a notification with the new key. The old key will be deactivated after a brief grace period."})]})]})}])},939510,e=>{"use strict";var t=e.i(843476),s=e.i(808613),a=e.i(199133),r=e.i(592968),l=e.i(827252);let{Option:i}=a.Select;e.s(["default",0,({type:e,name:n,showDetailedDescriptions:o=!0,className:c="",initialValue:d=null,form:u,onChange:m})=>{let h=e.toUpperCase(),p=e.toLowerCase(),g=`Select 'guaranteed_throughput' to prevent overallocating ${h} limit when the key belongs to a Team with specific ${h} limits.`;return(0,t.jsx)(s.Form.Item,{label:(0,t.jsxs)("span",{children:[h," Rate Limit Type"," ",(0,t.jsx)(r.Tooltip,{title:g,children:(0,t.jsx)(l.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:n,initialValue:d,className:c,children:(0,t.jsx)(a.Select,{defaultValue:o?"default":void 0,placeholder:"Select rate limit type",style:{width:"100%"},optionLabelProp:o?"label":void 0,onChange:e=>{u&&u.setFieldValue(n,e),m&&m(e)},children:o?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(i,{value:"best_effort_throughput",label:"Default",children:(0,t.jsxs)("div",{style:{padding:"4px 0"},children:[(0,t.jsx)("div",{style:{fontWeight:500},children:"Default"}),(0,t.jsxs)("div",{style:{fontSize:"11px",color:"#6b7280",marginTop:"2px"},children:["Best effort throughput - no error if we're overallocating ",p," (Team/Key Limits checked at runtime)."]})]})}),(0,t.jsx)(i,{value:"guaranteed_throughput",label:"Guaranteed throughput",children:(0,t.jsxs)("div",{style:{padding:"4px 0"},children:[(0,t.jsx)("div",{style:{fontWeight:500},children:"Guaranteed throughput"}),(0,t.jsxs)("div",{style:{fontSize:"11px",color:"#6b7280",marginTop:"2px"},children:["Guaranteed throughput - raise an error if we're overallocating ",p," (also checks model-specific limits)"]})]})}),(0,t.jsx)(i,{value:"dynamic",label:"Dynamic",children:(0,t.jsxs)("div",{style:{padding:"4px 0"},children:[(0,t.jsx)("div",{style:{fontWeight:500},children:"Dynamic"}),(0,t.jsxs)("div",{style:{fontSize:"11px",color:"#6b7280",marginTop:"2px"},children:["If the key has a set ",h," (e.g. 2 ",h,") and there are no 429 errors, it can dynamically exceed the limit when the model being called is not erroring."]})]})})]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(i,{value:"best_effort_throughput",children:"Best effort throughput"}),(0,t.jsx)(i,{value:"guaranteed_throughput",children:"Guaranteed throughput"}),(0,t.jsx)(i,{value:"dynamic",children:"Dynamic"})]})})})}])},533882,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(250980),r=e.i(797672),l=e.i(68155),i=e.i(304967),n=e.i(629569),o=e.i(599724),c=e.i(269200),d=e.i(427612),u=e.i(64848),m=e.i(942232),h=e.i(496020),p=e.i(977572),g=e.i(992619),f=e.i(727749);e.s(["default",0,({accessToken:e,initialModelAliases:x={},onAliasUpdate:y,showExampleConfig:b=!0})=>{let[_,v]=(0,s.useState)([]),[j,w]=(0,s.useState)({aliasName:"",targetModel:""}),[k,N]=(0,s.useState)(null);(0,s.useEffect)(()=>{v(Object.entries(x).map(([e,t],s)=>({id:`${s}-${e}`,aliasName:e,targetModel:t})))},[x]);let S=()=>{if(!k)return;if(!k.aliasName||!k.targetModel)return void f.default.fromBackend("Please provide both alias name and target model");if(_.some(e=>e.id!==k.id&&e.aliasName===k.aliasName))return void f.default.fromBackend("An alias with this name already exists");let e=_.map(e=>e.id===k.id?k:e);v(e),N(null);let t={};e.forEach(e=>{t[e.aliasName]=e.targetModel}),y&&y(t),f.default.success("Alias updated successfully")},C=()=>{N(null)},T=_.reduce((e,t)=>(e[t.aliasName]=t.targetModel,e),{});return(0,t.jsxs)("div",{className:"mt-4",children:[(0,t.jsxs)("div",{className:"mb-6",children:[(0,t.jsx)(o.Text,{className:"text-sm font-medium text-gray-700 mb-2",children:"Add New Alias"}),(0,t.jsxs)("div",{className:"grid grid-cols-3 gap-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"block text-xs text-gray-500 mb-1",children:"Alias Name"}),(0,t.jsx)("input",{type:"text",value:j.aliasName,onChange:e=>w({...j,aliasName:e.target.value}),placeholder:"e.g., gpt-4o",className:"w-full px-3 py-2 border border-gray-300 rounded-md text-sm"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"block text-xs text-gray-500 mb-1",children:"Target Model"}),(0,t.jsx)(g.default,{accessToken:e,value:j.targetModel,placeholder:"Select target model",onChange:e=>w({...j,targetModel:e}),showLabel:!1})]}),(0,t.jsx)("div",{className:"flex items-end",children:(0,t.jsxs)("button",{onClick:()=>{if(!j.aliasName||!j.targetModel)return void f.default.fromBackend("Please provide both alias name and target model");if(_.some(e=>e.aliasName===j.aliasName))return void f.default.fromBackend("An alias with this name already exists");let e=[..._,{id:`${Date.now()}-${j.aliasName}`,aliasName:j.aliasName,targetModel:j.targetModel}];v(e),w({aliasName:"",targetModel:""});let t={};e.forEach(e=>{t[e.aliasName]=e.targetModel}),y&&y(t),f.default.success("Alias added successfully")},disabled:!j.aliasName||!j.targetModel,className:`flex items-center px-4 py-2 rounded-md text-sm ${!j.aliasName||!j.targetModel?"bg-gray-300 text-gray-500 cursor-not-allowed":"bg-green-600 text-white hover:bg-green-700"}`,children:[(0,t.jsx)(a.PlusCircleIcon,{className:"w-4 h-4 mr-1"}),"Add Alias"]})})]})]}),(0,t.jsx)(o.Text,{className:"text-sm font-medium text-gray-700 mb-2",children:"Manage Existing Aliases"}),(0,t.jsx)("div",{className:"rounded-lg custom-border relative mb-6",children:(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)(c.Table,{className:"[&_td]:py-0.5 [&_th]:py-1",children:[(0,t.jsx)(d.TableHead,{children:(0,t.jsxs)(h.TableRow,{children:[(0,t.jsx)(u.TableHeaderCell,{className:"py-1 h-8",children:"Alias Name"}),(0,t.jsx)(u.TableHeaderCell,{className:"py-1 h-8",children:"Target Model"}),(0,t.jsx)(u.TableHeaderCell,{className:"py-1 h-8",children:"Actions"})]})}),(0,t.jsxs)(m.TableBody,{children:[_.map(s=>(0,t.jsx)(h.TableRow,{className:"h-8",children:k&&k.id===s.id?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(p.TableCell,{className:"py-0.5",children:(0,t.jsx)("input",{type:"text",value:k.aliasName,onChange:e=>N({...k,aliasName:e.target.value}),className:"w-full px-2 py-1 border border-gray-300 rounded-md text-sm"})}),(0,t.jsx)(p.TableCell,{className:"py-0.5",children:(0,t.jsx)(g.default,{accessToken:e,value:k.targetModel,onChange:e=>N({...k,targetModel:e}),showLabel:!1,style:{height:"32px"}})}),(0,t.jsx)(p.TableCell,{className:"py-0.5 whitespace-nowrap",children:(0,t.jsxs)("div",{className:"flex space-x-2",children:[(0,t.jsx)("button",{onClick:S,className:"text-xs bg-blue-50 text-blue-600 px-2 py-1 rounded hover:bg-blue-100",children:"Save"}),(0,t.jsx)("button",{onClick:C,className:"text-xs bg-gray-50 text-gray-600 px-2 py-1 rounded hover:bg-gray-100",children:"Cancel"})]})})]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(p.TableCell,{className:"py-0.5 text-sm text-gray-900",children:s.aliasName}),(0,t.jsx)(p.TableCell,{className:"py-0.5 text-sm text-gray-500",children:s.targetModel}),(0,t.jsx)(p.TableCell,{className:"py-0.5 whitespace-nowrap",children:(0,t.jsxs)("div",{className:"flex space-x-2",children:[(0,t.jsx)("button",{onClick:()=>{N({...s})},className:"text-xs bg-blue-50 text-blue-600 px-2 py-1 rounded hover:bg-blue-100",children:(0,t.jsx)(r.PencilIcon,{className:"w-3 h-3"})}),(0,t.jsx)("button",{onClick:()=>{var e;let t,a;return e=s.id,v(t=_.filter(t=>t.id!==e)),a={},void(t.forEach(e=>{a[e.aliasName]=e.targetModel}),y&&y(a),f.default.success("Alias deleted successfully"))},className:"text-xs bg-red-50 text-red-600 px-2 py-1 rounded hover:bg-red-100",children:(0,t.jsx)(l.TrashIcon,{className:"w-3 h-3"})})]})})]})},s.id)),0===_.length&&(0,t.jsx)(h.TableRow,{children:(0,t.jsx)(p.TableCell,{colSpan:3,className:"py-0.5 text-sm text-gray-500 text-center",children:"No aliases added yet. Add a new alias above."})})]})]})})}),b&&(0,t.jsxs)(i.Card,{children:[(0,t.jsx)(n.Title,{className:"mb-4",children:"Configuration Example"}),(0,t.jsx)(o.Text,{className:"text-gray-600 mb-4",children:"Here's how your current aliases would look in the config:"}),(0,t.jsx)("div",{className:"bg-gray-100 rounded-lg p-4 font-mono text-sm",children:(0,t.jsxs)("div",{className:"text-gray-700",children:["model_aliases:",0===Object.keys(T).length?(0,t.jsxs)("span",{className:"text-gray-500",children:[(0,t.jsx)("br",{}),"  # No aliases configured yet"]}):Object.entries(T).map(([e,s])=>(0,t.jsxs)("span",{children:[(0,t.jsx)("br",{}),'  "',e,'": "',s,'"']},e))]})})]})]})}])},651904,e=>{"use strict";var t=e.i(843476),s=e.i(599724),a=e.i(266484);e.s(["default",0,function({value:e,onChange:r,premiumUser:l=!1,disabledCallbacks:i=[],onDisabledCallbacksChange:n}){return l?(0,t.jsx)(a.default,{value:e,onChange:r,disabledCallbacks:i,onDisabledCallbacksChange:n}):(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"flex flex-wrap gap-2 mb-3",children:[(0,t.jsx)("div",{className:"inline-flex items-center px-3 py-1.5 rounded-lg bg-green-50 border border-green-200 text-green-800 text-sm font-medium opacity-50",children:"✨ langfuse-logging"}),(0,t.jsx)("div",{className:"inline-flex items-center px-3 py-1.5 rounded-lg bg-green-50 border border-green-200 text-green-800 text-sm font-medium opacity-50",children:"✨ datadog-logging"})]}),(0,t.jsx)("div",{className:"p-3 bg-yellow-50 border border-yellow-200 rounded-lg",children:(0,t.jsxs)(s.Text,{className:"text-sm text-yellow-800",children:["Setting Key/Team logging settings is a LiteLLM Enterprise feature. Global Logging Settings are available for all free users. Get a trial key"," ",(0,t.jsx)("a",{href:"https://www.litellm.ai/#pricing",target:"_blank",rel:"noopener noreferrer",className:"underline",children:"here"}),"."]})})]})}])},460285,575260,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(404206),r=e.i(723731),l=e.i(653824),i=e.i(881073),n=e.i(197647),o=e.i(764205),c=e.i(158392),d=e.i(419470),u=e.i(689020);let m=(0,s.forwardRef)(({accessToken:e,value:m,onChange:h,modelData:p},g)=>{let[f,x]=(0,s.useState)({routerSettings:{},selectedStrategy:null,enableTagFiltering:!1}),[y,b]=(0,s.useState)([]),[_,v]=(0,s.useState)([]),[j,w]=(0,s.useState)([]),[k,N]=(0,s.useState)([]),[S,C]=(0,s.useState)({}),[T,E]=(0,s.useState)({}),I=(0,s.useRef)(!1),A=(0,s.useRef)(null);(0,s.useEffect)(()=>{let e=m?.router_settings?JSON.stringify({routing_strategy:m.router_settings.routing_strategy,fallbacks:m.router_settings.fallbacks,enable_tag_filtering:m.router_settings.enable_tag_filtering}):null;if(I.current&&e===A.current){I.current=!1;return}if(I.current&&e!==A.current&&(I.current=!1),e!==A.current)if(A.current=e,m?.router_settings){let e=m.router_settings,{fallbacks:t,...s}=e;x({routerSettings:s,selectedStrategy:e.routing_strategy||null,enableTagFiltering:e.enable_tag_filtering??!1});let a=e.fallbacks||[];b(a),v(a&&0!==a.length?a.map((e,t)=>{let[s,a]=Object.entries(e)[0];return{id:(t+1).toString(),primaryModel:s||null,fallbackModels:a||[]}}):[{id:"1",primaryModel:null,fallbackModels:[]}])}else x({routerSettings:{},selectedStrategy:null,enableTagFiltering:!1}),b([]),v([{id:"1",primaryModel:null,fallbackModels:[]}])},[m]),(0,s.useEffect)(()=>{e&&(0,o.getRouterSettingsCall)(e).then(e=>{if(e.fields){let t={};e.fields.forEach(e=>{t[e.field_name]={ui_field_name:e.ui_field_name,field_description:e.field_description,options:e.options,link:e.link}}),C(t);let s=e.fields.find(e=>"routing_strategy"===e.field_name);s?.options&&N(s.options),e.routing_strategy_descriptions&&E(e.routing_strategy_descriptions)}})},[e]),(0,s.useEffect)(()=>{e&&(async()=>{try{let t=await (0,u.fetchAvailableModels)(e);w(t)}catch(e){console.error("Error fetching model info for fallbacks:",e)}})()},[e]);let O=()=>{let e=new Set(["allowed_fails","cooldown_time","num_retries","timeout","retry_after"]),t=new Set(["model_group_alias","retry_policy"]),s=Object.fromEntries(Object.entries({...f.routerSettings,enable_tag_filtering:f.enableTagFiltering,routing_strategy:f.selectedStrategy,fallbacks:y.length>0?y:null}).map(([s,a])=>{if("routing_strategy_args"!==s&&"routing_strategy"!==s&&"enable_tag_filtering"!==s&&"fallbacks"!==s){let r=document.querySelector(`input[name="${s}"]`);if(r&&void 0!==r.value&&""!==r.value){let l=((s,a,r)=>{if(null==a)return r;let l=String(a).trim();if(""===l||"null"===l.toLowerCase())return null;if(e.has(s)){let e=Number(l);return Number.isNaN(e)?r:e}if(t.has(s)){if(""===l)return null;try{return JSON.parse(l)}catch{return r}}return"true"===l.toLowerCase()||"false"!==l.toLowerCase()&&l})(s,r.value,a);return[s,l]}}else if("routing_strategy"===s)return[s,f.selectedStrategy];else if("enable_tag_filtering"===s)return[s,f.enableTagFiltering];else if("fallbacks"===s)return[s,y.length>0?y:null];else if("routing_strategy_args"===s&&"latency-based-routing"===f.selectedStrategy){let e=document.querySelector('input[name="lowest_latency_buffer"]'),t=document.querySelector('input[name="ttl"]'),s={};return e?.value&&(s.lowest_latency_buffer=Number(e.value)),t?.value&&(s.ttl=Number(t.value)),["routing_strategy_args",Object.keys(s).length>0?s:null]}return[s,a]}).filter(e=>null!=e)),a=(e,t=!1)=>null==e||"object"==typeof e&&!Array.isArray(e)&&0===Object.keys(e).length||t&&("number"!=typeof e||Number.isNaN(e))?null:e;return{routing_strategy:a(s.routing_strategy),allowed_fails:a(s.allowed_fails,!0),cooldown_time:a(s.cooldown_time,!0),num_retries:a(s.num_retries,!0),timeout:a(s.timeout,!0),retry_after:a(s.retry_after,!0),fallbacks:y.length>0?y:null,context_window_fallbacks:a(s.context_window_fallbacks),retry_policy:a(s.retry_policy),model_group_alias:a(s.model_group_alias),enable_tag_filtering:f.enableTagFiltering,routing_strategy_args:a(s.routing_strategy_args)}};(0,s.useEffect)(()=>{if(!h)return;let e=setTimeout(()=>{I.current=!0,h({router_settings:O()})},100);return()=>clearTimeout(e)},[f,y]);let L=Array.from(new Set(j.map(e=>e.model_group))).sort();return((0,s.useImperativeHandle)(g,()=>({getValue:()=>({router_settings:O()})})),e)?(0,t.jsx)("div",{className:"w-full",children:(0,t.jsxs)(l.TabGroup,{className:"w-full",children:[(0,t.jsxs)(i.TabList,{variant:"line",defaultValue:"1",className:"px-8 pt-4",children:[(0,t.jsx)(n.Tab,{value:"1",children:"Loadbalancing"}),(0,t.jsx)(n.Tab,{value:"2",children:"Fallbacks"})]}),(0,t.jsxs)(r.TabPanels,{className:"px-8 py-6",children:[(0,t.jsx)(a.TabPanel,{children:(0,t.jsx)(c.default,{value:f,onChange:x,routerFieldsMetadata:S,availableRoutingStrategies:k,routingStrategyDescriptions:T})}),(0,t.jsx)(a.TabPanel,{children:(0,t.jsx)(d.FallbackSelectionForm,{groups:_,onGroupsChange:e=>{v(e),b(e.filter(e=>e.primaryModel&&e.fallbackModels.length>0).map(e=>({[e.primaryModel]:e.fallbackModels})))},availableModels:L,maxGroups:5})})]})]})}):null});m.displayName="RouterSettingsAccordion",e.s(["default",0,m],460285);var h=e.i(199133),p=e.i(482725),g=e.i(56456);e.s(["default",0,({projects:e,value:s,onChange:a,disabled:r,loading:l,teamId:i})=>{let n=i?e?.filter(e=>e.team_id===i):e;return(0,t.jsx)(h.Select,{showSearch:!0,placeholder:"Search or select a project",value:s,onChange:a,disabled:r,loading:l,allowClear:!0,notFoundContent:l?(0,t.jsx)(p.Spin,{indicator:(0,t.jsx)(g.LoadingOutlined,{spin:!0}),size:"small"}):void 0,filterOption:(e,t)=>{if(!t)return!1;let s=n?.find(e=>e.project_id===t.key);if(!s)return!1;let a=e.toLowerCase().trim(),r=(s.project_alias||"").toLowerCase(),l=(s.project_id||"").toLowerCase();return r.includes(a)||l.includes(a)},optionFilterProp:"children",children:!l&&n?.map(e=>(0,t.jsxs)(h.Select.Option,{value:e.project_id,children:[(0,t.jsx)("span",{className:"font-medium",children:e.project_alias||e.project_id})," ",(0,t.jsxs)("span",{className:"text-gray-500",children:["(",e.project_id,")"]})]},e.project_id))})}],575260)},702597,364769,e=>{"use strict";var t=e.i(843476),s=e.i(207082),a=e.i(510674),r=e.i(292639),l=e.i(135214),i=e.i(500330),n=e.i(827252),o=e.i(912598),c=e.i(677667),d=e.i(130643),u=e.i(898667),m=e.i(994388),h=e.i(309426),p=e.i(350967),g=e.i(599724),f=e.i(779241),x=e.i(629569),y=e.i(464571),b=e.i(808613),_=e.i(311451),v=e.i(212931),j=e.i(91739),w=e.i(199133),k=e.i(790848),N=e.i(262218),S=e.i(592968),C=e.i(374009),T=e.i(271645),E=e.i(708347),I=e.i(552130),A=e.i(557662),O=e.i(9314),L=e.i(860585),M=e.i(82946),F=e.i(392110),R=e.i(533882),P=e.i(844565),D=e.i(651904),B=e.i(939510),$=e.i(460285),K=e.i(663435),U=e.i(575260),z=e.i(371455),V=e.i(355619),q=e.i(75921),G=e.i(390605),H=e.i(727749),W=e.i(764205),Q=e.i(237016),J=e.i(998573);let Y=({apiKey:e})=>{let[s,a]=(0,T.useState)(!1);return(0,t.jsxs)("div",{children:[(0,t.jsxs)("p",{className:"mb-2",children:["Please save this secret key somewhere safe and accessible. For security reasons,"," ",(0,t.jsx)("b",{children:"you will not be able to view it again"})," through your LiteLLM account. If you lose this secret key, you will need to generate a new one."]}),(0,t.jsx)("p",{className:"text-sm text-gray-600 mt-3 mb-1",children:"Virtual Key:"}),(0,t.jsx)("div",{style:{background:"#f8f8f8",padding:"10px",borderRadius:"5px",marginBottom:"10px"},children:(0,t.jsx)("pre",{style:{wordWrap:"break-word",whiteSpace:"normal",margin:0},children:e})}),(0,t.jsx)(Q.CopyToClipboard,{text:e,onCopy:()=>{a(!0),J.message.success("Key copied to clipboard"),setTimeout(()=>a(!1),2e3)},children:(0,t.jsx)(y.Button,{type:"primary",style:{marginTop:12},children:s?"Copied!":"Copy Virtual Key"})})]})};e.s(["default",0,Y],364769);var X=e.i(435451),Z=e.i(916940);let{Option:ee}=w.Select,et=async(e,t,s,a)=>{try{if(null===e||null===t)return[];if(null!==s){let r=(await (0,W.modelAvailableCall)(s,e,t,!0,a,!0)).data.map(e=>e.id);return console.log("available_model_names:",r),r}return[]}catch(e){return console.error("Error fetching user models:",e),[]}},es=async(e,t,s,a)=>{try{if(null===e||null===t)return;if(null!==s){let r=(await (0,W.modelAvailableCall)(s,e,t)).data.map(e=>e.id);console.log("available_model_names:",r),a(r)}}catch(e){console.error("Error fetching user models:",e)}};e.s(["default",0,({team:e,teams:Q,data:J,addKey:ea,autoOpenCreate:er,prefillData:el})=>{let{accessToken:ei,userId:en,userRole:eo,premiumUser:ec}=(0,l.default)(),ed=ec||null!=eo&&E.rolesWithWriteAccess.includes(eo),{data:eu,isLoading:em}=(0,a.useProjects)(),{data:eh}=(0,r.useUISettings)(),ep=!!eh?.values?.enable_projects_ui,eg=(0,o.useQueryClient)(),[ef]=b.Form.useForm(),[ex,ey]=(0,T.useState)(!1),[eb,e_]=(0,T.useState)(null),[ev,ej]=(0,T.useState)(null),[ew,ek]=(0,T.useState)([]),[eN,eS]=(0,T.useState)([]),[eC,eT]=(0,T.useState)("you"),[eE,eI]=(0,T.useState)((e=>{let t=[];if(console.log("data:",JSON.stringify(e)),e)for(let s of e)s.metadata&&s.metadata.tags&&t.push(...s.metadata.tags);let s=Array.from(new Set(t)).map(e=>({value:e,label:e}));return console.log("uniqueTags:",s),s})(J)),[eA,eO]=(0,T.useState)(!1),[eL,eM]=(0,T.useState)(null),[eF,eR]=(0,T.useState)([]),[eP,eD]=(0,T.useState)([]),[eB,e$]=(0,T.useState)([]),[eK,eU]=(0,T.useState)([]),[ez,eV]=(0,T.useState)(e),[eq,eG]=(0,T.useState)(null),[eH,eW]=(0,T.useState)(!1),[eQ,eJ]=(0,T.useState)(null),[eY,eX]=(0,T.useState)({}),[eZ,e0]=(0,T.useState)([]),[e1,e2]=(0,T.useState)(!1),[e4,e3]=(0,T.useState)([]),[e5,e6]=(0,T.useState)([]),[e7,e9]=(0,T.useState)("llm_api"),[e8,te]=(0,T.useState)({}),[tt,ts]=(0,T.useState)(!1),[ta,tr]=(0,T.useState)("30d"),[tl,ti]=(0,T.useState)(null),[tn,to]=(0,T.useState)(0),[tc,td]=(0,T.useState)([]),[tu,tm]=(0,T.useState)(null),th=()=>{ey(!1),ef.resetFields(),eU([]),e6([]),e9("llm_api"),te({}),ts(!1),tr("30d"),ti(null),to(e=>e+1),tm(null),eG(null)},tp=()=>{ey(!1),e_(null),eV(null),ef.resetFields(),eU([]),e6([]),e9("llm_api"),te({}),ts(!1),tr("30d"),ti(null),to(e=>e+1),tm(null),eG(null)};(0,T.useEffect)(()=>{en&&eo&&ei&&es(en,eo,ei,ek)},[ei,en,eo]),(0,T.useEffect)(()=>{ei&&(0,W.getAgentsList)(ei).then(e=>td(e?.agents||[])).catch(()=>td([]))},[ei]),(0,T.useEffect)(()=>{let e=async()=>{try{let e=(await (0,W.getPoliciesList)(ei)).policies.map(e=>e.policy_name);eD(e)}catch(e){console.error("Failed to fetch policies:",e)}},t=async()=>{try{let e=await (0,W.getPromptsList)(ei);e$(e.prompts.map(e=>e.prompt_id))}catch(e){console.error("Failed to fetch prompts:",e)}};(async()=>{try{let e=(await (0,W.getGuardrailsList)(ei)).guardrails.map(e=>e.guardrail_name);eR(e)}catch(e){console.error("Failed to fetch guardrails:",e)}})(),e(),t()},[ei]),(0,T.useEffect)(()=>{(async()=>{try{if(ei){let e=sessionStorage.getItem("possibleUserRoles");if(e)eX(JSON.parse(e));else{let e=await (0,W.getPossibleUserRoles)(ei);sessionStorage.setItem("possibleUserRoles",JSON.stringify(e)),eX(e)}}}catch(e){console.error("Error fetching possible user roles:",e)}})()},[ei]),(0,T.useEffect)(()=>{if(er&&!eA&&Q&&eo&&E.rolesWithWriteAccess.includes(eo)&&(ey(!0),eO(!0),el)){if(el.owned_by&&("another_user"===el.owned_by&&"Admin"!==eo?eT("you"):eT(el.owned_by)),el.team_id){let e=Q?.find(e=>e.team_id===el.team_id)||null;e&&(eV(e),ef.setFieldsValue({team_id:el.team_id}))}el.key_alias&&ef.setFieldsValue({key_alias:el.key_alias}),el.models&&el.models.length>0&&eM(el.models),el.key_type&&(e9(el.key_type),ef.setFieldsValue({key_type:el.key_type}))}},[er,el,Q,eA,ef,eo]);let tg=eN.includes("no-default-models")&&!ez,tf=async e=>{try{let t,a=e?.key_alias??"",r=e?.team_id??null;if((J?.filter(e=>e.team_id===r).map(e=>e.key_alias)??[]).includes(a))throw Error(`Key alias ${a} already exists for team with ID ${r}, please provide another key alias`);if(H.default.info("Making API Call"),ey(!0),"you"===eC)e.user_id=en;else if("agent"===eC){if(!tu)return void H.default.fromBackend("Please select an agent");e.agent_id=tu}let l={};try{l=JSON.parse(e.metadata||"{}")}catch(e){console.error("Error parsing metadata:",e)}if("service_account"===eC&&(l.service_account_id=e.key_alias),eK.length>0&&(l={...l,logging:eK.filter(e=>e.callback_name)}),e5.length>0){let e=(0,A.mapDisplayToInternalNames)(e5);l={...l,litellm_disabled_callbacks:e}}if(tt&&(e.auto_rotate=!0,e.rotation_interval=ta),e.duration&&""!==e.duration.trim()||(e.duration=null),e.metadata=JSON.stringify(l),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&&(e.allowed_mcp_servers_and_groups.servers?.length>0||e.allowed_mcp_servers_and_groups.accessGroups?.length>0)){e.object_permission||(e.object_permission={});let{servers:t,accessGroups:s}=e.allowed_mcp_servers_and_groups;t&&t.length>0&&(e.object_permission.mcp_servers=t),s&&s.length>0&&(e.object_permission.mcp_access_groups=s),delete e.allowed_mcp_servers_and_groups}let i=e.mcp_tool_permissions||{};if(Object.keys(i).length>0&&(e.object_permission||(e.object_permission={}),e.object_permission.mcp_tool_permissions=i),delete e.mcp_tool_permissions,e.allowed_mcp_access_groups&&e.allowed_mcp_access_groups.length>0&&(e.object_permission||(e.object_permission={}),e.object_permission.mcp_access_groups=e.allowed_mcp_access_groups,delete e.allowed_mcp_access_groups),e.allowed_agents_and_groups&&(e.allowed_agents_and_groups.agents?.length>0||e.allowed_agents_and_groups.accessGroups?.length>0)){e.object_permission||(e.object_permission={});let{agents:t,accessGroups:s}=e.allowed_agents_and_groups;t&&t.length>0&&(e.object_permission.agents=t),s&&s.length>0&&(e.object_permission.agent_access_groups=s),delete e.allowed_agents_and_groups}Object.keys(e8).length>0&&(e.aliases=JSON.stringify(e8)),tl?.router_settings&&Object.values(tl.router_settings).some(e=>null!=e&&""!==e)&&(e.router_settings=tl.router_settings),t="service_account"===eC?await (0,W.keyCreateServiceAccountCall)(ei,e):await (0,W.keyCreateCall)(ei,en,e),console.log("key create Response:",t),ea(t),eg.invalidateQueries({queryKey:s.keyKeys.lists()}),e_(t.key),ej(t.soft_budget),H.default.success("Virtual Key Created"),ef.resetFields(),localStorage.removeItem("userData"+en)}catch(t){console.log("error in create key:",t);let e=(e=>{let t;if(!(t=!e||"object"!=typeof e||e instanceof Error?String(e):JSON.stringify(e)).includes("/key/generate")&&!t.includes("KeyManagementRoutes.KEY_GENERATE"))return`Error creating the key: ${e}`;let s=t;try{if(!e||"object"!=typeof e||e instanceof Error){let e=t.match(/\{[\s\S]*\}/);if(e){let t=JSON.parse(e[0]),a=t?.error||t;a?.message&&(s=a.message)}}else{let t=e?.error||e;t?.message&&(s=t.message)}}catch(e){}return t.includes("team_member_permission_error")||s.includes("Team member does not have permissions")?"Team member does not have permission to generate key for this team. Ask your proxy admin to configure the team member permission settings.":`Error creating the key: ${e}`})(t);H.default.fromBackend(e)}};(0,T.useEffect)(()=>{if(eq){let e=eu?.find(e=>e.project_id===eq);eS(e?.models??[]),ef.setFieldValue("models",[]);return}en&&eo&&ei&&et(en,eo,ei,ez?.team_id??null).then(e=>{eS(Array.from(new Set([...ez?.models??[],...e])))}),eL||ef.setFieldValue("models",[]),ef.setFieldValue("allowed_mcp_servers_and_groups",{servers:[],accessGroups:[]})},[ez,eq,ei,en,eo,ef]),(0,T.useEffect)(()=>{if(!eL||0===eL.length||!eN||0===eN.length)return;let e=eL.filter(e=>eN.includes(e));e.length>0&&ef.setFieldsValue({models:e}),eM(null)},[eL,eN,ef]),(0,T.useEffect)(()=>{if(!eq||!Q)return;let e=eu?.find(e=>e.project_id===eq);if(!e?.team_id||ez?.team_id===e.team_id)return;let t=Q.find(t=>t.team_id===e.team_id)||null;t&&(eV(t),ef.setFieldValue("team_id",t.team_id))},[Q,eq,eu]);let tx=async e=>{if(!e)return void e0([]);e2(!0);try{let t=new URLSearchParams;if(t.append("user_email",e),null==ei)return;let s=(await (0,W.userFilterUICall)(ei,t)).map(e=>({label:`${e.user_email} (${e.user_id})`,value:e.user_id,user:e}));e0(s)}catch(e){console.error("Error fetching users:",e),H.default.fromBackend("Failed to search for users")}finally{e2(!1)}},ty=(0,T.useCallback)((0,C.default)(e=>tx(e),300),[ei]);return(0,t.jsxs)("div",{children:[eo&&E.rolesWithWriteAccess.includes(eo)&&(0,t.jsx)(m.Button,{className:"mx-auto",onClick:()=>ey(!0),children:"+ Create New Key"}),(0,t.jsx)(v.Modal,{open:ex,width:1e3,footer:null,onOk:th,onCancel:tp,children:(0,t.jsxs)(b.Form,{form:ef,onFinish:tf,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[(0,t.jsxs)("div",{className:"mb-8",children:[(0,t.jsx)(x.Title,{className:"mb-4",children:"Key Ownership"}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Owned By"," ",(0,t.jsx)(S.Tooltip,{title:"Select who will own this Virtual Key",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),className:"mb-4",children:(0,t.jsxs)(j.Radio.Group,{onChange:e=>eT(e.target.value),value:eC,children:[(0,t.jsx)(j.Radio,{value:"you",children:"You"}),(0,t.jsx)(j.Radio,{value:"service_account",children:"Service Account"}),"Admin"===eo&&(0,t.jsx)(j.Radio,{value:"another_user",children:"Another User"}),(0,t.jsxs)(j.Radio,{value:"agent",children:["Agent ",(0,t.jsx)(N.Tag,{color:"purple",children:"New"})]})]})}),"another_user"===eC&&(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["User ID"," ",(0,t.jsx)(S.Tooltip,{title:"The user who will own this key and be responsible for its usage",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"user_id",className:"mt-4",rules:[{required:"another_user"===eC,message:"Please input the user ID of the user you are assigning the key to"}],children:(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{style:{display:"flex",marginBottom:"8px"},children:[(0,t.jsx)(w.Select,{showSearch:!0,placeholder:"Type email to search for users",filterOption:!1,onSearch:e=>{ty(e)},onSelect:(e,t)=>{let s;return s=t.user,void ef.setFieldsValue({user_id:s.user_id})},options:eZ,loading:e1,allowClear:!0,style:{width:"100%"},notFoundContent:e1?"Searching...":"No users found"}),(0,t.jsx)(y.Button,{onClick:()=>eW(!0),style:{marginLeft:"8px"},children:"Create User"})]}),(0,t.jsx)("div",{className:"text-xs text-gray-500",children:"Search by email to find users"})]})}),"agent"===eC&&(0,t.jsxs)("div",{className:"mt-4 p-4 bg-purple-50 border border-purple-200 rounded-md",children:[(0,t.jsx)("div",{className:"mb-3",children:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700",children:["Select Agent ",(0,t.jsx)("span",{className:"text-red-500",children:"*"})]})}),(0,t.jsx)(w.Select,{showSearch:!0,placeholder:"Select an agent",style:{width:"100%"},value:tu,onChange:e=>tm(e),filterOption:(e,t)=>t?.label?.toLowerCase().includes(e.toLowerCase()),options:tc.map(e=>({label:e.agent_name||e.agent_id,value:e.agent_id}))}),(0,t.jsx)("div",{className:"text-xs text-gray-500 mt-2",children:"This key will be used by the selected agent to make requests to LiteLLM"})]}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Team"," ",(0,t.jsx)(S.Tooltip,{title:"The team this key belongs to, which determines available models and budget limits",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"team_id",initialValue:e?e.team_id:null,className:"mt-4",rules:[{required:"service_account"===eC,message:"Please select a team for the service account"}],help:"service_account"===eC?"required":"",children:(0,t.jsx)(K.default,{teams:Q,disabled:null!==eq,loading:!Q,onChange:e=>{eV(Q?.find(t=>t.team_id===e)||null),eG(null),ef.setFieldValue("project_id",void 0)}})}),ep&&(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Project"," ",(0,t.jsx)(S.Tooltip,{title:"Assign this key to a project. Selecting a project will lock the team to the project's team.",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"project_id",className:"mt-4",children:(0,t.jsx)(U.default,{projects:eu,teamId:ez?.team_id,loading:em||!Q,onChange:e=>{if(!e){eG(null),eV(null),ef.setFieldValue("team_id",void 0);return}eG(e)}})})]}),tg&&(0,t.jsx)("div",{className:"mb-8 p-4 bg-blue-50 border border-blue-200 rounded-md",children:(0,t.jsx)(g.Text,{className:"text-blue-800 text-sm",children:"Please select a team to continue configuring your Virtual Key. If you do not see any teams, please contact your Proxy Admin to either provide you with access to models or to add you to a team."})}),!tg&&(0,t.jsxs)("div",{className:"mb-8",children:[(0,t.jsx)(x.Title,{className:"mb-4",children:"Key Details"}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["you"===eC||"another_user"===eC?"Key Name":"Service Account ID"," ",(0,t.jsx)(S.Tooltip,{title:"you"===eC||"another_user"===eC?"A descriptive name to identify this key":"Unique identifier for this service account",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"key_alias",rules:[{required:!0,message:`Please input a ${"you"===eC?"key name":"service account ID"}`}],help:"required",children:(0,t.jsx)(f.TextInput,{placeholder:""})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Models"," ",(0,t.jsx)(S.Tooltip,{title:"Select which models this key can access. Choose 'All Team Models' to grant access to all models available to the team. Leave empty to allow access to all models.",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"models",rules:[],help:"management"===e7||"read_only"===e7?"Models field is disabled for this key type":"optional - leave empty to allow access to all models",className:"mt-4",children:(0,t.jsxs)(w.Select,{mode:"multiple",placeholder:"Select models",style:{width:"100%"},disabled:"management"===e7||"read_only"===e7,onChange:e=>{e.includes("all-team-models")&&ef.setFieldsValue({models:["all-team-models"]})},children:[!eq&&(0,t.jsx)(ee,{value:"all-team-models",children:"All Team Models"},"all-team-models"),eN.map(e=>(0,t.jsx)(ee,{value:e,children:(0,V.getModelDisplayName)(e)},e))]})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Key Type"," ",(0,t.jsx)(S.Tooltip,{title:"Select the type of key to determine what routes and operations this key can access",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"key_type",initialValue:"llm_api",className:"mt-4",children:(0,t.jsxs)(w.Select,{defaultValue:"llm_api",placeholder:"Select key type",style:{width:"100%"},optionLabelProp:"label",onChange:e=>{e9(e),("management"===e||"read_only"===e)&&ef.setFieldsValue({models:[]})},children:[(0,t.jsx)(ee,{value:"default",label:"Default",children:(0,t.jsxs)("div",{style:{padding:"4px 0"},children:[(0,t.jsx)("div",{style:{fontWeight:500},children:"Default"}),(0,t.jsx)("div",{style:{fontSize:"11px",color:"#6b7280",marginTop:"2px"},children:"Can call AI APIs + Management routes"})]})}),(0,t.jsx)(ee,{value:"llm_api",label:"AI APIs",children:(0,t.jsxs)("div",{style:{padding:"4px 0"},children:[(0,t.jsx)("div",{style:{fontWeight:500},children:"AI APIs"}),(0,t.jsx)("div",{style:{fontSize:"11px",color:"#6b7280",marginTop:"2px"},children:"Can call only AI API routes (chat/completions, embeddings, etc.)"})]})}),(0,t.jsx)(ee,{value:"management",label:"Management",children:(0,t.jsxs)("div",{style:{padding:"4px 0"},children:[(0,t.jsx)("div",{style:{fontWeight:500},children:"Management"}),(0,t.jsx)("div",{style:{fontSize:"11px",color:"#6b7280",marginTop:"2px"},children:"Can call only management routes (user/team/key management)"})]})})]})})]}),!tg&&(0,t.jsx)("div",{className:"mb-8",children:(0,t.jsxs)(c.Accordion,{className:"mt-4 mb-4",children:[(0,t.jsx)(u.AccordionHeader,{children:(0,t.jsx)(x.Title,{className:"m-0",children:"Optional Settings"})}),(0,t.jsxs)(d.AccordionBody,{children:[(0,t.jsx)(b.Form.Item,{className:"mt-4",label:(0,t.jsxs)("span",{children:["Max Budget (USD)"," ",(0,t.jsx)(S.Tooltip,{title:"Maximum amount in USD this key can spend. When reached, the key will be blocked from making further requests",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"max_budget",help:`Budget cannot exceed team max budget: $${e?.max_budget!==null&&e?.max_budget!==void 0?e?.max_budget:"unlimited"}`,rules:[{validator:async(t,s)=>{if(s&&e&&null!==e.max_budget&&s>e.max_budget)throw Error(`Budget cannot exceed team max budget: $${(0,i.formatNumberWithCommas)(e.max_budget,4)}`)}}],children:(0,t.jsx)(X.default,{step:.01,precision:2,width:200})}),(0,t.jsx)(b.Form.Item,{className:"mt-4",label:(0,t.jsxs)("span",{children:["Reset Budget"," ",(0,t.jsx)(S.Tooltip,{title:"How often the budget should reset. For example, setting 'daily' will reset the budget every 24 hours",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"budget_duration",help:`Team Reset Budget: ${e?.budget_duration!==null&&e?.budget_duration!==void 0?e?.budget_duration:"None"}`,children:(0,t.jsx)(L.default,{onChange:e=>ef.setFieldValue("budget_duration",e)})}),(0,t.jsx)(b.Form.Item,{className:"mt-4",label:(0,t.jsxs)("span",{children:["Tokens per minute Limit (TPM)"," ",(0,t.jsx)(S.Tooltip,{title:"Maximum number of tokens this key can process per minute. Helps control usage and costs",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"tpm_limit",help:`TPM cannot exceed team TPM limit: ${e?.tpm_limit!==null&&e?.tpm_limit!==void 0?e?.tpm_limit:"unlimited"}`,rules:[{validator:async(t,s)=>{if(s&&e&&null!==e.tpm_limit&&s>e.tpm_limit)throw Error(`TPM limit cannot exceed team TPM limit: ${e.tpm_limit}`)}}],children:(0,t.jsx)(X.default,{step:1,width:400})}),(0,t.jsx)(B.default,{type:"tpm",name:"tpm_limit_type",className:"mt-4",initialValue:null,form:ef,showDetailedDescriptions:!0}),(0,t.jsx)(b.Form.Item,{className:"mt-4",label:(0,t.jsxs)("span",{children:["Requests per minute Limit (RPM)"," ",(0,t.jsx)(S.Tooltip,{title:"Maximum number of API requests this key can make per minute. Helps prevent abuse and manage load",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"rpm_limit",help:`RPM cannot exceed team RPM limit: ${e?.rpm_limit!==null&&e?.rpm_limit!==void 0?e?.rpm_limit:"unlimited"}`,rules:[{validator:async(t,s)=>{if(s&&e&&null!==e.rpm_limit&&s>e.rpm_limit)throw Error(`RPM limit cannot exceed team RPM limit: ${e.rpm_limit}`)}}],children:(0,t.jsx)(X.default,{step:1,width:400})}),(0,t.jsx)(B.default,{type:"rpm",name:"rpm_limit_type",className:"mt-4",initialValue:null,form:ef,showDetailedDescriptions:!0}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Guardrails"," ",(0,t.jsx)(S.Tooltip,{title:"Apply safety guardrails to this key to filter content or enforce policies",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)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})})]}),name:"guardrails",className:"mt-4",help:ed?"Select existing guardrails or enter new ones":"Premium feature - Upgrade to set guardrails by key",children:(0,t.jsx)(w.Select,{mode:"tags",style:{width:"100%"},disabled:!ed,placeholder:ed?"Select or enter guardrails":"Premium feature - Upgrade to set guardrails by key",options:eF.map(e=>({value:e,label:e}))})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Disable Global Guardrails"," ",(0,t.jsx)(S.Tooltip,{title:"When enabled, this key will bypass any guardrails configured to run on every request (global guardrails)",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)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})})]}),name:"disable_global_guardrails",className:"mt-4",valuePropName:"checked",help:ed?"Bypass global guardrails for this key":"Premium feature - Upgrade to disable global guardrails by key",children:(0,t.jsx)(k.Switch,{disabled:!ed,checkedChildren:"Yes",unCheckedChildren:"No"})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Policies"," ",(0,t.jsx)(S.Tooltip,{title:"Apply policies to this key to control guardrails and other settings",children:(0,t.jsx)("a",{href:"https://docs.litellm.ai/docs/proxy/guardrails/guardrail_policies",target:"_blank",rel:"noopener noreferrer",onClick:e=>e.stopPropagation(),children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})})]}),name:"policies",className:"mt-4",help:ec?"Select existing policies or enter new ones":"Premium feature - Upgrade to set policies by key",children:(0,t.jsx)(w.Select,{mode:"tags",style:{width:"100%"},disabled:!ec,placeholder:ec?"Select or enter policies":"Premium feature - Upgrade to set policies by key",options:eP.map(e=>({value:e,label:e}))})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Prompts"," ",(0,t.jsx)(S.Tooltip,{title:"Allow this key to use specific prompt templates",children:(0,t.jsx)("a",{href:"https://docs.litellm.ai/docs/proxy/prompt_management",target:"_blank",rel:"noopener noreferrer",onClick:e=>e.stopPropagation(),children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})})]}),name:"prompts",className:"mt-4",help:ec?"Select existing prompts or enter new ones":"Premium feature - Upgrade to set prompts by key",children:(0,t.jsx)(w.Select,{mode:"tags",style:{width:"100%"},disabled:!ec,placeholder:ec?"Select or enter prompts":"Premium feature - Upgrade to set prompts by key",options:eB.map(e=>({value:e,label:e}))})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Access Groups"," ",(0,t.jsx)(S.Tooltip,{title:"Assign access groups to this key. Access groups control which models, MCP servers, and agents this key can use",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"access_group_ids",className:"mt-4",help:"Select access groups to assign to this key",children:(0,t.jsx)(O.default,{placeholder:"Select access groups (optional)"})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Allowed Pass Through Routes"," ",(0,t.jsx)(S.Tooltip,{title:"Allow this key to use specific pass through routes",children:(0,t.jsx)("a",{href:"https://docs.litellm.ai/docs/proxy/pass_through",target:"_blank",rel:"noopener noreferrer",onClick:e=>e.stopPropagation(),children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})})]}),name:"allowed_passthrough_routes",className:"mt-4",help:ec?"Select existing pass through routes or enter new ones":"Premium feature - Upgrade to set pass through routes by key",children:(0,t.jsx)(P.default,{onChange:e=>ef.setFieldValue("allowed_passthrough_routes",e),value:ef.getFieldValue("allowed_passthrough_routes"),accessToken:ei,placeholder:ec?"Select or enter pass through routes":"Premium feature - Upgrade to set pass through routes by key",disabled:!ec,teamId:ez?ez.team_id:null})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Allowed Vector Stores"," ",(0,t.jsx)(S.Tooltip,{title:"Select which vector stores this key can access. If none selected, the key will have access to all available vector stores",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"allowed_vector_store_ids",className:"mt-4",help:"Select vector stores this key can access. Leave empty for access to all vector stores",children:(0,t.jsx)(Z.default,{onChange:e=>ef.setFieldValue("allowed_vector_store_ids",e),value:ef.getFieldValue("allowed_vector_store_ids"),accessToken:ei,placeholder:"Select vector stores (optional)"})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Metadata"," ",(0,t.jsx)(S.Tooltip,{title:"JSON object with additional information about this key. Used for tracking or custom logic",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"metadata",className:"mt-4",children:(0,t.jsx)(_.Input.TextArea,{rows:4,placeholder:"Enter metadata as JSON"})}),(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Tags"," ",(0,t.jsx)(S.Tooltip,{title:"Tags for tracking spend and/or doing tag-based routing. Used for analytics and filtering",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"tags",className:"mt-4",help:"Tags for tracking spend and/or doing tag-based routing.",children:(0,t.jsx)(w.Select,{mode:"tags",style:{width:"100%"},placeholder:"Enter tags",tokenSeparators:[","],options:eE})}),(0,t.jsxs)(c.Accordion,{className:"mt-4 mb-4",children:[(0,t.jsx)(u.AccordionHeader,{children:(0,t.jsx)("b",{children:"MCP Settings"})}),(0,t.jsxs)(d.AccordionBody,{children:[(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Allowed MCP Servers"," ",(0,t.jsx)(S.Tooltip,{title:"Select which MCP servers or access groups this key can access",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"allowed_mcp_servers_and_groups",help:"Select MCP servers or access groups this key can access",children:(0,t.jsx)(q.default,{onChange:e=>ef.setFieldValue("allowed_mcp_servers_and_groups",e),value:ef.getFieldValue("allowed_mcp_servers_and_groups"),accessToken:ei,teamId:ez?.team_id??null,placeholder:"Select MCP servers or access groups (optional)"})}),(0,t.jsx)(b.Form.Item,{name:"mcp_tool_permissions",initialValue:{},hidden:!0,children:(0,t.jsx)(_.Input,{type:"hidden"})}),(0,t.jsx)(b.Form.Item,{noStyle:!0,shouldUpdate:(e,t)=>e.allowed_mcp_servers_and_groups!==t.allowed_mcp_servers_and_groups||e.mcp_tool_permissions!==t.mcp_tool_permissions,children:()=>(0,t.jsx)("div",{className:"mt-6",children:(0,t.jsx)(G.default,{accessToken:ei,selectedServers:ef.getFieldValue("allowed_mcp_servers_and_groups")?.servers||[],toolPermissions:ef.getFieldValue("mcp_tool_permissions")||{},onChange:e=>ef.setFieldsValue({mcp_tool_permissions:e})})})})]})]}),(0,t.jsxs)(c.Accordion,{className:"mt-4 mb-4",children:[(0,t.jsx)(u.AccordionHeader,{children:(0,t.jsx)("b",{children:"Agent Settings"})}),(0,t.jsx)(d.AccordionBody,{children:(0,t.jsx)(b.Form.Item,{label:(0,t.jsxs)("span",{children:["Allowed Agents"," ",(0,t.jsx)(S.Tooltip,{title:"Select which agents or access groups this key can access",children:(0,t.jsx)(n.InfoCircleOutlined,{style:{marginLeft:"4px"}})})]}),name:"allowed_agents_and_groups",help:"Select agents or access groups this key can access",children:(0,t.jsx)(I.default,{onChange:e=>ef.setFieldValue("allowed_agents_and_groups",e),value:ef.getFieldValue("allowed_agents_and_groups"),accessToken:ei,placeholder:"Select agents or access groups (optional)"})})})]}),ec?(0,t.jsxs)(c.Accordion,{className:"mt-4 mb-4",children:[(0,t.jsx)(u.AccordionHeader,{children:(0,t.jsx)("b",{children:"Logging Settings"})}),(0,t.jsx)(d.AccordionBody,{children:(0,t.jsx)("div",{className:"mt-4",children:(0,t.jsx)(D.default,{value:eK,onChange:eU,premiumUser:!0,disabledCallbacks:e5,onDisabledCallbacksChange:e6})})})]}):(0,t.jsx)(S.Tooltip,{title:(0,t.jsxs)("span",{children:["Key-level logging settings is an enterprise feature, get in touch -",(0,t.jsx)("a",{href:"https://www.litellm.ai/enterprise",target:"_blank",children:"https://www.litellm.ai/enterprise"})]}),placement:"top",children:(0,t.jsxs)("div",{style:{position:"relative"},children:[(0,t.jsx)("div",{style:{opacity:.5},children:(0,t.jsxs)(c.Accordion,{className:"mt-4 mb-4",children:[(0,t.jsx)(u.AccordionHeader,{children:(0,t.jsx)("b",{children:"Logging Settings"})}),(0,t.jsx)(d.AccordionBody,{children:(0,t.jsx)("div",{className:"mt-4",children:(0,t.jsx)(D.default,{value:eK,onChange:eU,premiumUser:!1,disabledCallbacks:e5,onDisabledCallbacksChange:e6})})})]})}),(0,t.jsx)("div",{style:{position:"absolute",inset:0,cursor:"not-allowed"}})]})}),(0,t.jsxs)(c.Accordion,{className:"mt-4 mb-4",children:[(0,t.jsx)(u.AccordionHeader,{children:(0,t.jsx)("b",{children:"Router Settings"})}),(0,t.jsx)(d.AccordionBody,{children:(0,t.jsx)("div",{className:"mt-4 w-full",children:(0,t.jsx)($.default,{accessToken:ei||"",value:tl||void 0,onChange:ti,modelData:ew.length>0?{data:ew.map(e=>({model_name:e}))}:void 0},tn)})})]},`router-settings-accordion-${tn}`),(0,t.jsxs)(c.Accordion,{className:"mt-4 mb-4",children:[(0,t.jsx)(u.AccordionHeader,{children:(0,t.jsx)("b",{children:"Model Aliases"})}),(0,t.jsx)(d.AccordionBody,{children:(0,t.jsxs)("div",{className:"mt-4",children:[(0,t.jsx)(g.Text,{className:"text-sm text-gray-600 mb-4",children:"Create custom aliases for models that can be used in API calls. This allows you to create shortcuts for specific models."}),(0,t.jsx)(R.default,{accessToken:ei,initialModelAliases:e8,onAliasUpdate:te,showExampleConfig:!1})]})})]}),(0,t.jsxs)(c.Accordion,{className:"mt-4 mb-4",children:[(0,t.jsx)(u.AccordionHeader,{children:(0,t.jsx)("b",{children:"Key Lifecycle"})}),(0,t.jsx)(d.AccordionBody,{children:(0,t.jsx)("div",{className:"mt-4",children:(0,t.jsx)(F.default,{form:ef,autoRotationEnabled:tt,onAutoRotationChange:ts,rotationInterval:ta,onRotationIntervalChange:tr,isCreateMode:!0})})}),(0,t.jsx)(b.Form.Item,{name:"duration",hidden:!0,initialValue:null,children:(0,t.jsx)(_.Input,{})})]}),(0,t.jsxs)(c.Accordion,{className:"mt-4 mb-4",children:[(0,t.jsx)(u.AccordionHeader,{children:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("b",{children:"Advanced Settings"}),(0,t.jsx)(S.Tooltip,{title:(0,t.jsxs)("span",{children:["Learn more about advanced settings in our"," ",(0,t.jsx)("a",{href:W.proxyBaseUrl?`${W.proxyBaseUrl}/#/key%20management/generate_key_fn_key_generate_post`:"/#/key%20management/generate_key_fn_key_generate_post",target:"_blank",rel:"noopener noreferrer",className:"text-blue-400 hover:text-blue-300",children:"documentation"})]}),children:(0,t.jsx)(n.InfoCircleOutlined,{className:"text-gray-400 hover:text-gray-300 cursor-help"})})]})}),(0,t.jsx)(d.AccordionBody,{children:(0,t.jsx)(M.default,{schemaComponent:"GenerateKeyRequest",form:ef,excludedFields:["key_alias","team_id","models","duration","metadata","tags","guardrails","max_budget","budget_duration","tpm_limit","rpm_limit"]})})]})]})]})}),(0,t.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,t.jsx)(y.Button,{htmlType:"submit",disabled:tg,style:{opacity:tg?.5:1},children:"Create Key"})})]})}),eH&&(0,t.jsx)(v.Modal,{title:"Create New User",open:eH,onCancel:()=>eW(!1),footer:null,width:800,children:(0,t.jsx)(z.CreateUserButton,{userID:en,accessToken:ei,teams:Q,possibleUIRoles:eY,onUserCreated:e=>{eJ(e),ef.setFieldsValue({user_id:e}),eW(!1)},isEmbedded:!0})}),eb&&(0,t.jsx)(v.Modal,{open:ex,onOk:th,onCancel:tp,footer:null,children:(0,t.jsxs)(p.Grid,{numItems:1,className:"gap-2 w-full",children:[(0,t.jsx)(x.Title,{children:"Save your Key"}),(0,t.jsx)(h.Col,{numColSpan:1,children:null!=eb?(0,t.jsx)(Y,{apiKey:eb}):(0,t.jsx)(g.Text,{children:"Key being created, this might take 30s"})})]})})]})},"fetchTeamModels",0,et,"fetchUserModels",0,es],702597)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/3413b6a1ede03f29.js b/litellm/proxy/_experimental/out/_next/static/chunks/5595eb6378e90997.js similarity index 87% rename from litellm/proxy/_experimental/out/_next/static/chunks/3413b6a1ede03f29.js rename to litellm/proxy/_experimental/out/_next/static/chunks/5595eb6378e90997.js index 016e8f37d8..ab41ae1d36 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/3413b6a1ede03f29.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/5595eb6378e90997.js @@ -1 +1 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,384767,e=>{"use strict";var t=e.i(843476),r=e.i(599724),a=e.i(271645),s=e.i(389083);let l=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:"M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"}))});var n=e.i(764205);let i=function({vectorStores:e,accessToken:i}){let[o,c]=(0,a.useState)([]);return(0,a.useEffect)(()=>{(async()=>{if(i&&0!==e.length)try{let e=await (0,n.vectorStoreListCall)(i);e.data&&c(e.data.map(e=>({vector_store_id:e.vector_store_id,vector_store_name:e.vector_store_name})))}catch(e){console.error("Error fetching vector stores:",e)}})()},[i,e.length]),(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(l,{className:"h-4 w-4 text-blue-600"}),(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"Vector Stores"}),(0,t.jsx)(s.Badge,{color:"blue",size:"xs",children:e.length})]}),e.length>0?(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:e.map((e,r)=>{let a;return(0,t.jsx)("div",{className:"inline-flex items-center px-3 py-1.5 rounded-lg bg-blue-50 border border-blue-200 text-blue-800 text-sm font-medium",children:(a=o.find(t=>t.vector_store_id===e))?`${a.vector_store_name||a.vector_store_id} (${a.vector_store_id})`:e},r)})}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(l,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(r.Text,{className:"text-gray-500 text-sm",children:"No vector stores configured"})]})]})},o=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:"M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"}))});var c=e.i(871943),d=e.i(502547),u=e.i(592968);let m=function({mcpServers:l,mcpAccessGroups:i=[],mcpToolPermissions:m={},accessToken:p}){let[g,f]=(0,a.useState)([]),[x,h]=(0,a.useState)([]),[b,y]=(0,a.useState)(new Set);(0,a.useEffect)(()=>{(async()=>{if(p&&l.length>0)try{let e=await (0,n.fetchMCPServers)(p);e&&Array.isArray(e)?f(e):e.data&&Array.isArray(e.data)&&f(e.data)}catch(e){console.error("Error fetching MCP servers:",e)}})()},[p,l.length]),(0,a.useEffect)(()=>{(async()=>{if(p&&i.length>0)try{let t=await e.A(601236).then(e=>e.fetchMCPAccessGroups(p));h(Array.isArray(t)?t:t.data||[])}catch(e){console.error("Error fetching MCP access groups:",e)}})()},[p,i.length]);let v=[...l.map(e=>({type:"server",value:e})),...i.map(e=>({type:"accessGroup",value:e}))],j=v.length;return(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(o,{className:"h-4 w-4 text-blue-600"}),(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"MCP Servers"}),(0,t.jsx)(s.Badge,{color:"blue",size:"xs",children:j})]}),j>0?(0,t.jsx)("div",{className:"max-h-[400px] overflow-y-auto space-y-2 pr-1",children:v.map((e,r)=>{let a="server"===e.type?m[e.value]:void 0,s=a&&a.length>0,l=b.has(e.value);return(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{onClick:()=>{var t;return s&&(t=e.value,void y(e=>{let r=new Set(e);return r.has(t)?r.delete(t):r.add(t),r}))},className:`flex items-center gap-3 py-2 px-3 rounded-lg border border-gray-200 transition-all ${s?"cursor-pointer hover:bg-gray-50 hover:border-gray-300":"bg-white"}`,children:[(0,t.jsx)("div",{className:"flex items-center gap-2 flex-1 min-w-0",children:"server"===e.type?(0,t.jsx)(u.Tooltip,{title:`Full ID: ${e.value}`,placement:"top",children:(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-blue-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:(e=>{let t=g.find(t=>t.server_id===e);if(t){let r=e.length>7?`${e.slice(0,3)}...${e.slice(-4)}`:e;return`${t.alias} (${r})`}return e})(e.value)})]})}):(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-green-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:e.value}),(0,t.jsx)("span",{className:"ml-1 px-1.5 py-0.5 text-[9px] font-semibold text-green-600 bg-green-50 border border-green-200 rounded uppercase tracking-wide flex-shrink-0",children:"Group"})]})}),s&&(0,t.jsxs)("div",{className:"flex items-center gap-1 flex-shrink-0 whitespace-nowrap",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-600",children:a.length}),(0,t.jsx)("span",{className:"text-xs text-gray-500",children:1===a.length?"tool":"tools"}),l?(0,t.jsx)(c.ChevronDownIcon,{className:"h-3.5 w-3.5 text-gray-400 ml-0.5"}):(0,t.jsx)(d.ChevronRightIcon,{className:"h-3.5 w-3.5 text-gray-400 ml-0.5"})]})]}),s&&l&&(0,t.jsx)("div",{className:"ml-4 pl-4 border-l-2 border-blue-200 pb-1",children:(0,t.jsx)("div",{className:"flex flex-wrap gap-1.5",children:a.map((e,r)=>(0,t.jsx)("span",{className:"inline-flex items-center px-2.5 py-1 rounded-lg bg-blue-50 border border-blue-200 text-blue-800 text-xs font-medium",children:e},r))})})]},r)})}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(o,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(r.Text,{className:"text-gray-500 text-sm",children:"No MCP servers or access groups configured"})]})]})},p=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:"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"}))}),g=function({agents:e,agentAccessGroups:l=[],accessToken:i}){let[o,c]=(0,a.useState)([]);(0,a.useEffect)(()=>{(async()=>{if(i&&e.length>0)try{let e=await (0,n.getAgentsList)(i);e&&e.agents&&Array.isArray(e.agents)&&c(e.agents)}catch(e){console.error("Error fetching agents:",e)}})()},[i,e.length]);let d=[...e.map(e=>({type:"agent",value:e})),...l.map(e=>({type:"accessGroup",value:e}))],m=d.length;return(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(p,{className:"h-4 w-4 text-purple-600"}),(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"Agents"}),(0,t.jsx)(s.Badge,{color:"purple",size:"xs",children:m})]}),m>0?(0,t.jsx)("div",{className:"max-h-[400px] overflow-y-auto space-y-2 pr-1",children:d.map((e,r)=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsx)("div",{className:"flex items-center gap-3 py-2 px-3 rounded-lg border border-gray-200 bg-white",children:(0,t.jsx)("div",{className:"flex items-center gap-2 flex-1 min-w-0",children:"agent"===e.type?(0,t.jsx)(u.Tooltip,{title:`Full ID: ${e.value}`,placement:"top",children:(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-purple-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:(e=>{let t=o.find(t=>t.agent_id===e);if(t){let r=e.length>7?`${e.slice(0,3)}...${e.slice(-4)}`:e;return`${t.agent_name} (${r})`}return e})(e.value)})]})}):(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-green-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:e.value}),(0,t.jsx)("span",{className:"ml-1 px-1.5 py-0.5 text-[9px] font-semibold text-green-600 bg-green-50 border border-green-200 rounded uppercase tracking-wide flex-shrink-0",children:"Group"})]})})})},r))}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(p,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(r.Text,{className:"text-gray-500 text-sm",children:"No agents or access groups configured"})]})]})};e.s(["default",0,function({objectPermission:e,variant:a="card",className:s="",accessToken:l}){let n=e?.vector_stores||[],o=e?.mcp_servers||[],c=e?.mcp_access_groups||[],d=e?.mcp_tool_permissions||{},u=e?.agents||[],p=e?.agent_access_groups||[],f=(0,t.jsxs)("div",{className:"card"===a?"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6":"space-y-4",children:[(0,t.jsx)(i,{vectorStores:n,accessToken:l}),(0,t.jsx)(m,{mcpServers:o,mcpAccessGroups:c,mcpToolPermissions:d,accessToken:l}),(0,t.jsx)(g,{agents:u,agentAccessGroups:p,accessToken:l})]});return"card"===a?(0,t.jsxs)("div",{className:`bg-white border border-gray-200 rounded-lg p-6 ${s}`,children:[(0,t.jsx)("div",{className:"flex items-center gap-2 mb-6",children:(0,t.jsxs)("div",{children:[(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"Object Permissions"}),(0,t.jsx)(r.Text,{className:"text-xs text-gray-500",children:"Access control for Vector Stores and MCP Servers"})]})}),f]}):(0,t.jsxs)("div",{className:`${s}`,children:[(0,t.jsx)(r.Text,{className:"font-medium text-gray-900 mb-3",children:"Object Permissions"}),f]})}],384767)},270345,e=>{"use strict";var t=e.i(764205);let r=async(e,r,a,s)=>"Admin"!=a&&"Admin Viewer"!=a?await (0,t.teamListCall)(e,s?.organization_id||null,r):await (0,t.teamListCall)(e,s?.organization_id||null);e.s(["fetchTeams",0,r])},519756,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let a={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"};var s=e.i(9583),l=r.forwardRef(function(e,l){return r.createElement(s.default,(0,t.default)({},e,{ref:l,icon:a}))});e.s(["UploadOutlined",0,l],519756)},981339,e=>{"use strict";var t=e.i(185793);e.s(["Skeleton",()=>t.default])},500330,e=>{"use strict";var t=e.i(727749);function r(e,t){let r=structuredClone(e);for(let[e,a]of Object.entries(t))e in r&&(r[e]=a);return r}let a=(e,t=0,r=!1,a=!0)=>{if(null==e||!Number.isFinite(e)||0===e&&!a)return"-";let s={minimumFractionDigits:t,maximumFractionDigits:t};if(!r)return e.toLocaleString("en-US",s);let l=e<0?"-":"",n=Math.abs(e),i=n,o="";return n>=1e6?(i=n/1e6,o="M"):n>=1e3&&(i=n/1e3,o="K"),`${l}${i.toLocaleString("en-US",s)}${o}`},s=async(e,r="Copied to clipboard")=>{if(!e)return!1;if(!navigator||!navigator.clipboard||!navigator.clipboard.writeText)return l(e,r);try{return await navigator.clipboard.writeText(e),t.default.success(r),!0}catch(t){return console.error("Clipboard API failed: ",t),l(e,r)}},l=(e,r)=>{try{let a=document.createElement("textarea");a.value=e,a.style.position="fixed",a.style.left="-999999px",a.style.top="-999999px",a.setAttribute("readonly",""),document.body.appendChild(a),a.focus(),a.select();let s=document.execCommand("copy");if(document.body.removeChild(a),s)return t.default.success(r),!0;throw Error("execCommand failed")}catch(e){return t.default.fromBackend("Failed to copy to clipboard"),console.error("Failed to copy: ",e),!1}};e.s(["copyToClipboard",0,s,"formatNumberWithCommas",0,a,"getSpendString",0,(e,t=6)=>{if(null==e||!Number.isFinite(e)||0===e)return"-";let r=a(e,t,!1,!1);if(0===Number(r.replace(/,/g,""))){let e=(1/10**t).toFixed(t);return`< $${e}`}return`$${r}`},"updateExistingKeys",()=>r])},743151,(e,t,r)=>{"use strict";function a(e){return(a="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)}Object.defineProperty(r,"__esModule",{value:!0}),r.CopyToClipboard=void 0;var s=i(e.r(271645)),l=i(e.r(844343)),n=["text","onCopy","options","children"];function i(e){return e&&e.__esModule?e:{default:e}}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,a)}return r}function c(e){for(var t=1;t=0||(s[r]=e[r]);return s}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0)&&Object.prototype.propertyIsEnumerable.call(e,r)&&(s[r]=e[r])}return s}(e,n),a=s.default.Children.only(t);return s.default.cloneElement(a,c(c({},r),{},{onClick:this.onClick}))}}],function(e,t){for(var r=0;r{"use strict";var a=e.r(743151).CopyToClipboard;a.CopyToClipboard=a,t.exports=a},109799,e=>{"use strict";var t=e.i(135214),r=e.i(764205),a=e.i(266027),s=e.i(912598);let l=(0,e.i(243652).createQueryKeys)("organizations");e.s(["useOrganization",0,e=>{let n=(0,s.useQueryClient)(),{accessToken:i}=(0,t.default)();return(0,a.useQuery)({queryKey:l.detail(e),enabled:!!(i&&e),queryFn:async()=>{if(!i||!e)throw Error("Missing auth or teamId");return(0,r.organizationInfoCall)(i,e)},initialData:()=>{if(!e)return;let t=n.getQueryData(l.list({}));return t?.find(t=>t.organization_id===e)}})},"useOrganizations",0,()=>{let{accessToken:e,userId:s,userRole:n}=(0,t.default)();return(0,a.useQuery)({queryKey:l.list({}),queryFn:async()=>await (0,r.organizationListCall)(e),enabled:!!(e&&s&&n)})}])},309426,e=>{"use strict";var t=e.i(290571),r=e.i(444755),a=e.i(673706),s=e.i(271645),l=e.i(46757);let n=(0,a.makeClassName)("Col"),i=s.default.forwardRef((e,a)=>{let i,o,c,d,{numColSpan:u=1,numColSpanSm:m,numColSpanMd:p,numColSpanLg:g,children:f,className:x}=e,h=(0,t.__rest)(e,["numColSpan","numColSpanSm","numColSpanMd","numColSpanLg","children","className"]),b=(e,t)=>e&&Object.keys(t).includes(String(e))?t[e]:"";return s.default.createElement("div",Object.assign({ref:a,className:(0,r.tremorTwMerge)(n("root"),(i=b(u,l.colSpan),o=b(m,l.colSpanSm),c=b(p,l.colSpanMd),d=b(g,l.colSpanLg),(0,r.tremorTwMerge)(i,o,c,d)),x)},h),f)});i.displayName="Col",e.s(["Col",()=>i],309426)},988297,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"}))});e.s(["PlusIcon",0,r],988297)},797672,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"}))});e.s(["PencilIcon",0,r],797672)},992619,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(779241),s=e.i(599724),l=e.i(199133),n=e.i(983561),i=e.i(689020);e.s(["default",0,({accessToken:e,value:o,placeholder:c="Select a Model",onChange:d,disabled:u=!1,style:m,className:p,showLabel:g=!0,labelText:f="Select Model"})=>{let[x,h]=(0,r.useState)(o),[b,y]=(0,r.useState)(!1),[v,j]=(0,r.useState)([]),w=(0,r.useRef)(null);return(0,r.useEffect)(()=>{h(o)},[o]),(0,r.useEffect)(()=>{e&&(async()=>{try{let t=await (0,i.fetchAvailableModels)(e);console.log("Fetched models for selector:",t),t.length>0&&j(t)}catch(e){console.error("Error fetching model info:",e)}})()},[e]),(0,t.jsxs)("div",{children:[g&&(0,t.jsxs)(s.Text,{className:"font-medium block mb-2 text-gray-700 flex items-center",children:[(0,t.jsx)(n.RobotOutlined,{className:"mr-2"})," ",f]}),(0,t.jsx)(l.Select,{value:x,placeholder:c,onChange:e=>{"custom"===e?(y(!0),h(void 0)):(y(!1),h(e),d&&d(e))},options:[...Array.from(new Set(v.map(e=>e.model_group))).map((e,t)=>({value:e,label:e,key:t})),{value:"custom",label:"Enter custom model",key:"custom"}],style:{width:"100%",...m},showSearch:!0,className:`rounded-md ${p||""}`,disabled:u}),b&&(0,t.jsx)(a.TextInput,{className:"mt-2",placeholder:"Enter custom model name",onValueChange:e=>{w.current&&clearTimeout(w.current),w.current=setTimeout(()=>{h(e),d&&d(e)},500)},disabled:u})]})}])},91739,e=>{"use strict";var t=e.i(544195);e.s(["Radio",()=>t.default])},409797,e=>{"use strict";var t=e.i(631171);e.s(["ChevronDownIcon",()=>t.default])},500727,696609,531516,e=>{"use strict";var t=e.i(266027),r=e.i(243652),a=e.i(764205),s=e.i(135214);let l=(0,r.createQueryKeys)("mcpServers");e.s(["useMCPServers",0,e=>{let{accessToken:r}=(0,s.default)();return(0,t.useQuery)({queryKey:l.list(e?{filters:{teamId:e}}:void 0),queryFn:async()=>await (0,a.fetchMCPServers)(r,e),enabled:!!r})}],500727);var n=e.i(843476),i=e.i(271645),o=e.i(536916),c=e.i(599724),d=e.i(409797),u=e.i(246349),u=u;let m=/\b(delete|remove|destroy|purge|drop|erase|unlink)\b/i,p=/\b(create|add|insert|new|post|submit|register|make|generate|write|upload)\b/i,g=/\b(update|edit|modify|change|patch|put|set|rename|move|transform)\b/i,f=/\b(get|read|list|fetch|search|find|query|retrieve|show|view|check|describe|info)\b/i;function x(e,t=""){let r=e.toLowerCase();if(f.test(r))return"read";if(m.test(r))return"delete";if(g.test(r))return"update";if(p.test(r))return"create";if(t){let e=t.toLowerCase();if(f.test(e))return"read";if(m.test(e))return"delete";if(g.test(e))return"update";if(p.test(e))return"create"}return"unknown"}function h(e){let t={read:[],create:[],update:[],delete:[],unknown:[]};for(let r of e)t[x(r.name,r.description)].push(r);return t}let b={read:{label:"Read",description:"Safe operations — fetch, list, search. No side effects.",risk:"low"},create:{label:"Create",description:"Add new resources — insert, upload, register.",risk:"medium"},update:{label:"Update",description:"Modify existing resources — edit, patch, rename.",risk:"medium"},delete:{label:"Delete",description:"Destructive operations — remove, purge, destroy.",risk:"high"},unknown:{label:"Other",description:"Operations that could not be automatically classified.",risk:"unknown"}};e.s(["CRUD_GROUP_META",0,b,"classifyToolOp",()=>x,"groupToolsByCrud",()=>h],696609);let y=["read","create","update","delete","unknown"],v={low:"bg-green-100 text-green-800",medium:"bg-yellow-100 text-yellow-800",high:"bg-red-100 text-red-800 font-semibold",unknown:"bg-gray-100 text-gray-700"},j={read:"border-green-200",create:"border-blue-200",update:"border-yellow-200",delete:"border-red-300",unknown:"border-gray-200"},w={read:"bg-green-50",create:"bg-blue-50",update:"bg-yellow-50",delete:"bg-red-50",unknown:"bg-gray-50"};e.s(["default",0,({tools:e,value:t,onChange:r,readOnly:a=!1,searchFilter:s=""})=>{let[l,m]=(0,i.useState)({read:!1,create:!1,update:!1,delete:!1,unknown:!0}),p=(0,i.useMemo)(()=>h(e),[e]),g=(0,i.useMemo)(()=>new Set(void 0===t?e.map(e=>e.name):t),[t,e]),f=e=>{if(a)return;let t=new Set(g);t.has(e)?t.delete(e):t.add(e),r(Array.from(t))};return 0===e.length?null:(0,n.jsx)("div",{className:"space-y-3",children:y.map(e=>{let t,i=p[e];if(0===i.length)return null;if(s){let e=s.toLowerCase();if(!i.some(t=>t.name.toLowerCase().includes(e)||(t.description??"").toLowerCase().includes(e)))return null}let x=b[e],h=(t=p[e]).length>0&&t.every(e=>g.has(e.name)),y=(e=>{let t=p[e];if(0===t.length)return!1;let r=t.filter(e=>g.has(e.name)).length;return r>0&&r{m(t=>({...t,[e]:!t[e]}))},children:[N?(0,n.jsx)(u.default,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}):(0,n.jsx)(d.ChevronDownIcon,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}),(0,n.jsx)("span",{className:"font-semibold text-gray-900 text-sm",children:x.label}),(0,n.jsx)("span",{className:`text-xs px-2 py-0.5 rounded-full ${v[x.risk]}`,children:"high"===x.risk?"High Risk":"medium"===x.risk?"Medium Risk":"low"===x.risk?"Safe":"Unclassified"}),(0,n.jsxs)("span",{className:"text-xs text-gray-500 ml-1",children:[i.filter(e=>g.has(e.name)).length,"/",i.length," allowed"]})]}),!a&&(0,n.jsxs)("div",{className:"flex items-center gap-2 ml-4",children:[(0,n.jsx)(c.Text,{className:"text-xs text-gray-500",children:h?"All on":y?"Partial":"All off"}),(0,n.jsx)(o.Checkbox,{checked:h,indeterminate:y,onChange:t=>((e,t)=>{if(a)return;let s=new Set(g);for(let r of p[e])t?s.add(r.name):s.delete(r.name);r(Array.from(s))})(e,t.target.checked),onClick:e=>e.stopPropagation()})]})]}),!N&&(0,n.jsx)("div",{className:"px-4 pt-2 pb-1 text-xs text-gray-500 bg-white border-b border-gray-100",children:x.description}),!N&&(0,n.jsx)("div",{className:"bg-white divide-y divide-gray-50",children:i.filter(e=>!s||e.name.toLowerCase().includes(s.toLowerCase())||(e.description??"").toLowerCase().includes(s.toLowerCase())).map(e=>{let t,r=(t=e.name,g.has(t));return(0,n.jsxs)("div",{className:`flex items-start gap-3 px-4 py-2.5 transition-colors hover:bg-gray-50 ${!a?"cursor-pointer":""} ${r?"":"opacity-60"}`,onClick:()=>f(e.name),children:[(0,n.jsx)(o.Checkbox,{checked:r,onChange:()=>f(e.name),disabled:a,onClick:e=>e.stopPropagation()}),(0,n.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,n.jsx)(c.Text,{className:"font-medium text-gray-900 text-sm",children:e.name}),e.description&&(0,n.jsx)(c.Text,{className:"text-xs text-gray-500 mt-0.5 leading-snug",children:e.description})]}),(0,n.jsx)("span",{className:`text-xs px-1.5 py-0.5 rounded flex-shrink-0 ${r?"bg-green-100 text-green-700":"bg-gray-100 text-gray-500"}`,children:r?"on":"off"})]},e.name)})})]},e)})})}],531516)},361653,e=>{"use strict";let t=(0,e.i(475254).default)("circle-alert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);e.s(["default",()=>t])},603908,e=>{"use strict";let t=(0,e.i(475254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);e.s(["default",()=>t])},841947,e=>{"use strict";let t=(0,e.i(475254).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["default",()=>t])},793130,e=>{"use strict";var t=e.i(290571),r=e.i(429427),a=e.i(371330),s=e.i(271645),l=e.i(394487),n=e.i(503269),i=e.i(214520),o=e.i(746725),c=e.i(914189),d=e.i(144279),u=e.i(294316),m=e.i(601893),p=e.i(140721),g=e.i(942803),f=e.i(233538),x=e.i(694421),h=e.i(700020),b=e.i(35889),y=e.i(998348),v=e.i(722678);let j=(0,s.createContext)(null);j.displayName="GroupContext";let w=s.Fragment,N=Object.assign((0,h.forwardRefWithAs)(function(e,t){var w;let N=(0,s.useId)(),k=(0,g.useProvidedId)(),C=(0,m.useDisabled)(),{id:S=k||`headlessui-switch-${N}`,disabled:M=C||!1,checked:_,defaultChecked:O,onChange:T,name:E,value:P,form:L,autoFocus:R=!1,...F}=e,$=(0,s.useContext)(j),[A,D]=(0,s.useState)(null),B=(0,s.useRef)(null),I=(0,u.useSyncRefs)(B,t,null===$?null:$.setSwitch,D),z=(0,i.useDefaultValue)(O),[q,K]=(0,n.useControllable)(_,T,null!=z&&z),V=(0,o.useDisposables)(),[G,H]=(0,s.useState)(!1),U=(0,c.useEvent)(()=>{H(!0),null==K||K(!q),V.nextFrame(()=>{H(!1)})}),Q=(0,c.useEvent)(e=>{if((0,f.isDisabledReactIssue7711)(e.currentTarget))return e.preventDefault();e.preventDefault(),U()}),W=(0,c.useEvent)(e=>{e.key===y.Keys.Space?(e.preventDefault(),U()):e.key===y.Keys.Enter&&(0,x.attemptSubmit)(e.currentTarget)}),J=(0,c.useEvent)(e=>e.preventDefault()),X=(0,v.useLabelledBy)(),Y=(0,b.useDescribedBy)(),{isFocusVisible:Z,focusProps:ee}=(0,r.useFocusRing)({autoFocus:R}),{isHovered:et,hoverProps:er}=(0,a.useHover)({isDisabled:M}),{pressed:ea,pressProps:es}=(0,l.useActivePress)({disabled:M}),el=(0,s.useMemo)(()=>({checked:q,disabled:M,hover:et,focus:Z,active:ea,autofocus:R,changing:G}),[q,et,Z,ea,M,G,R]),en=(0,h.mergeProps)({id:S,ref:I,role:"switch",type:(0,d.useResolveButtonType)(e,A),tabIndex:-1===e.tabIndex?0:null!=(w=e.tabIndex)?w:0,"aria-checked":q,"aria-labelledby":X,"aria-describedby":Y,disabled:M||void 0,autoFocus:R,onClick:Q,onKeyUp:W,onKeyPress:J},ee,er,es),ei=(0,s.useCallback)(()=>{if(void 0!==z)return null==K?void 0:K(z)},[K,z]),eo=(0,h.useRender)();return s.default.createElement(s.default.Fragment,null,null!=E&&s.default.createElement(p.FormFields,{disabled:M,data:{[E]:P||"on"},overrides:{type:"checkbox",checked:q},form:L,onReset:ei}),eo({ourProps:en,theirProps:F,slot:el,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var t;let[r,a]=(0,s.useState)(null),[l,n]=(0,v.useLabels)(),[i,o]=(0,b.useDescriptions)(),c=(0,s.useMemo)(()=>({switch:r,setSwitch:a}),[r,a]),d=(0,h.useRender)();return s.default.createElement(o,{name:"Switch.Description",value:i},s.default.createElement(n,{name:"Switch.Label",value:l,props:{htmlFor:null==(t=c.switch)?void 0:t.id,onClick(e){r&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),r.click(),r.focus({preventScroll:!0}))}}},s.default.createElement(j.Provider,{value:c},d({ourProps:{},theirProps:e,slot:{},defaultTag:w,name:"Switch.Group"}))))},Label:v.Label,Description:b.Description});var k=e.i(888288),C=e.i(95779),S=e.i(444755),M=e.i(673706),_=e.i(829087);let O=(0,M.makeClassName)("Switch"),T=s.default.forwardRef((e,r)=>{let{checked:a,defaultChecked:l=!1,onChange:n,color:i,name:o,error:c,errorMessage:d,disabled:u,required:m,tooltip:p,id:g}=e,f=(0,t.__rest)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),x={bgColor:i?(0,M.getColorClassNames)(i,C.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:i?(0,M.getColorClassNames)(i,C.colorPalette.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[h,b]=(0,k.default)(l,a),[y,v]=(0,s.useState)(!1),{tooltipProps:j,getReferenceProps:w}=(0,_.useTooltip)(300);return s.default.createElement("div",{className:"flex flex-row items-center justify-start"},s.default.createElement(_.default,Object.assign({text:p},j)),s.default.createElement("div",Object.assign({ref:(0,M.mergeRefs)([r,j.refs.setReference]),className:(0,S.tremorTwMerge)(O("root"),"flex flex-row relative h-5")},f,w),s.default.createElement("input",{type:"checkbox",className:(0,S.tremorTwMerge)(O("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:o,required:m,checked:h,onChange:e=>{e.preventDefault()}}),s.default.createElement(N,{checked:h,onChange:e=>{b(e),null==n||n(e)},disabled:u,className:(0,S.tremorTwMerge)(O("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:()=>v(!0),onBlur:()=>v(!1),id:g},s.default.createElement("span",{className:(0,S.tremorTwMerge)(O("sr-only"),"sr-only")},"Switch ",h?"on":"off"),s.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(O("background"),h?x.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")}),s.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(O("round"),h?(0,S.tremorTwMerge)(x.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",y?(0,S.tremorTwMerge)("ring-2",x.ringColor):"")}))),c&&d?s.default.createElement("p",{className:(0,S.tremorTwMerge)(O("errorMessage"),"text-sm text-red-500 mt-1 ")},d):null)});T.displayName="Switch",e.s(["Switch",()=>T],793130)},158392,419470,e=>{"use strict";var t=e.i(843476),r=e.i(779241);let a={ttl:3600,lowest_latency_buffer:0},s=({routingStrategyArgs:e})=>{let s={ttl:"Sliding window to look back over when calculating the average latency of a deployment. Default - 1 hour (in seconds).",lowest_latency_buffer:"Shuffle between deployments within this % of the lowest latency. Default - 0 (i.e. always pick lowest latency)."};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Latency-Based Configuration"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Fine-tune latency-based routing behavior"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e||a).map(([e,a])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:e.replace(/_/g," ")}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:s[e]||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:"object"==typeof a?JSON.stringify(a,null,2):a?.toString(),className:"font-mono text-sm w-full"})]})},e))})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"})]})},l=({routerSettings:e,routerFieldsMetadata:a})=>(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Reliability & Retries"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure retry logic and failure handling"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e).filter(([e,t])=>"fallbacks"!=e&&"context_window_fallbacks"!=e&&"routing_strategy_args"!=e&&"routing_strategy"!=e&&"enable_tag_filtering"!=e).map(([e,s])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:a[e]?.ui_field_name||e}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:a[e]?.field_description||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:null==s||"null"===s?"":"object"==typeof s?JSON.stringify(s,null,2):s?.toString()||"",placeholder:"—",className:"font-mono text-sm w-full"})]})},e))})]});var n=e.i(199133);let i=({selectedStrategy:e,availableStrategies:r,routingStrategyDescriptions:a,routerFieldsMetadata:s,onStrategyChange:l})=>(0,t.jsxs)("div",{className:"space-y-2 max-w-3xl",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:s.routing_strategy?.ui_field_name||"Routing Strategy"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:s.routing_strategy?.field_description||""})]}),(0,t.jsx)("div",{className:"routing-strategy-select max-w-3xl",children:(0,t.jsx)(n.Select,{value:e,onChange:l,style:{width:"100%"},size:"large",children:r.map(e=>(0,t.jsx)(n.Select.Option,{value:e,label:e,children:(0,t.jsxs)("div",{className:"flex flex-col gap-0.5 py-1",children:[(0,t.jsx)("span",{className:"font-mono text-sm font-medium",children:e}),a[e]&&(0,t.jsx)("span",{className:"text-xs text-gray-500 font-normal",children:a[e]})]})},e))})})]});var o=e.i(793130);let c=({enabled:e,routerFieldsMetadata:r,onToggle:a})=>(0,t.jsx)("div",{className:"space-y-3 max-w-3xl",children:(0,t.jsxs)("div",{className:"flex items-start justify-between",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:r.enable_tag_filtering?.ui_field_name||"Enable Tag Filtering"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500 mt-0.5",children:[r.enable_tag_filtering?.field_description||"",r.enable_tag_filtering?.link&&(0,t.jsxs)(t.Fragment,{children:[" ",(0,t.jsx)("a",{href:r.enable_tag_filtering.link,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline",children:"Learn more"})]})]})]}),(0,t.jsx)(o.Switch,{checked:e,onChange:a,className:"ml-4"})]})});e.s(["default",0,({value:e,onChange:r,routerFieldsMetadata:a,availableRoutingStrategies:n,routingStrategyDescriptions:o})=>(0,t.jsxs)("div",{className:"w-full space-y-8 py-2",children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Routing Settings"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure how requests are routed to deployments"})]}),n.length>0&&(0,t.jsx)(i,{selectedStrategy:e.selectedStrategy||e.routerSettings.routing_strategy||null,availableStrategies:n,routingStrategyDescriptions:o,routerFieldsMetadata:a,onStrategyChange:t=>{r({...e,selectedStrategy:t})}}),(0,t.jsx)(c,{enabled:e.enableTagFiltering,routerFieldsMetadata:a,onToggle:t=>{r({...e,enableTagFiltering:t})}})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),"latency-based-routing"===e.selectedStrategy&&(0,t.jsx)(s,{routingStrategyArgs:e.routerSettings.routing_strategy_args}),(0,t.jsx)(l,{routerSettings:e.routerSettings,routerFieldsMetadata:a})]})],158392);var d=e.i(994388),u=e.i(998573),m=e.i(653496),p=e.i(107233),g=e.i(271645),f=e.i(592968),x=e.i(361653),x=x;let h=(0,e.i(475254).default)("arrow-down",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var b=e.i(37727);function y({group:e,onChange:r,availableModels:a,maxFallbacks:s}){let l=a.filter(t=>t!==e.primaryModel),i=e.fallbackModels.length{let a=[...e.fallbackModels];a.includes(t)&&(a=a.filter(e=>e!==t)),r({...e,primaryModel:t,fallbackModels:a})},showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase()),options:a.map(e=>({label:e,value:e}))}),!e.primaryModel&&(0,t.jsxs)("div",{className:"mt-2 flex items-center gap-2 text-amber-600 text-xs bg-amber-50 p-2 rounded",children:[(0,t.jsx)(x.default,{className:"w-4 h-4"}),(0,t.jsx)("span",{children:"Select a model to begin configuring fallbacks"})]})]}),(0,t.jsx)("div",{className:"flex items-center justify-center -my-4 z-10",children:(0,t.jsxs)("div",{className:"bg-indigo-50 text-indigo-500 px-4 py-1 rounded-full text-xs font-bold border border-indigo-100 flex items-center gap-2 shadow-sm",children:[(0,t.jsx)(h,{className:"w-4 h-4"}),"IF FAILS, TRY..."]})}),(0,t.jsxs)("div",{className:`transition-opacity duration-300 ${!e.primaryModel?"opacity-50 pointer-events-none":"opacity-100"}`,children:[(0,t.jsxs)("label",{className:"block text-sm font-semibold text-gray-700 mb-2",children:["Fallback Chain ",(0,t.jsx)("span",{className:"text-red-500",children:"*"}),(0,t.jsxs)("span",{className:"text-xs text-gray-500 font-normal ml-2",children:["(Max ",s," fallbacks at a time)"]})]}),(0,t.jsxs)("div",{className:"bg-gray-50 rounded-xl p-4 border border-gray-200",children:[(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(n.Select,{mode:"multiple",className:"w-full",size:"large",placeholder:i?"Select fallback models to add...":`Maximum ${s} fallbacks reached`,value:e.fallbackModels,onChange:t=>{let a=t.slice(0,s);r({...e,fallbackModels:a})},disabled:!e.primaryModel,options:l.map(e=>({label:e,value:e})),optionRender:(r,a)=>{let s=e.fallbackModels.includes(r.value),l=s?e.fallbackModels.indexOf(r.value)+1:null;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[s&&null!==l&&(0,t.jsx)("span",{className:"flex items-center justify-center w-5 h-5 rounded bg-indigo-100 text-indigo-600 text-xs font-bold",children:l}),(0,t.jsx)("span",{children:r.label})]})},maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(f.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})}),showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase())}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1 ml-1",children:i?`Search and select multiple models. Selected models will appear below in order. (${e.fallbackModels.length}/${s} used)`:`Maximum ${s} fallbacks reached. Remove some to add more.`})]}),(0,t.jsx)("div",{className:"space-y-2 min-h-[100px]",children:0===e.fallbackModels.length?(0,t.jsxs)("div",{className:"h-32 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)("span",{className:"text-sm",children:"No fallback models selected"}),(0,t.jsx)("span",{className:"text-xs mt-1",children:"Add models from the dropdown above"})]}):e.fallbackModels.map((a,s)=>(0,t.jsxs)("div",{className:"group flex items-center justify-between p-3 bg-white rounded-lg border border-gray-200 hover:border-indigo-300 hover:shadow-sm transition-all",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex items-center justify-center w-6 h-6 rounded bg-gray-100 text-gray-400 group-hover:text-indigo-500 group-hover:bg-indigo-50",children:(0,t.jsx)("span",{className:"text-xs font-bold",children:s+1})}),(0,t.jsx)("div",{children:(0,t.jsx)("span",{className:"font-medium text-gray-800",children:a})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>{let t;return t=e.fallbackModels.filter((e,t)=>t!==s),void r({...e,fallbackModels:t})},className:"opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500 p-1",children:(0,t.jsx)(b.X,{className:"w-4 h-4"})})]},`${a}-${s}`))})]})]})]})}function v({groups:e,onGroupsChange:r,availableModels:a,maxFallbacks:s=10,maxGroups:l=5}){let[n,i]=(0,g.useState)(e.length>0?e[0].id:"1");(0,g.useEffect)(()=>{e.length>0?e.some(e=>e.id===n)||i(e[0].id):i("1")},[e]);let o=()=>{if(e.length>=l)return;let t=Date.now().toString();r([...e,{id:t,primaryModel:null,fallbackModels:[]}]),i(t)},c=t=>{r(e.map(e=>e.id===t.id?t:e))},f=e.map((r,l)=>{let n=r.primaryModel?r.primaryModel:`Group ${l+1}`;return{key:r.id,label:n,closable:e.length>1,children:(0,t.jsx)(y,{group:r,onChange:c,availableModels:a,maxFallbacks:s})}});return 0===e.length?(0,t.jsxs)("div",{className:"text-center py-12 bg-gray-50 rounded-lg border border-dashed border-gray-300",children:[(0,t.jsx)("p",{className:"text-gray-500 mb-4",children:"No fallback groups configured"}),(0,t.jsx)(d.Button,{variant:"primary",onClick:o,icon:()=>(0,t.jsx)(p.Plus,{className:"w-4 h-4"}),children:"Create First Group"})]}):(0,t.jsx)(m.Tabs,{type:"editable-card",activeKey:n,onChange:i,onEdit:(t,a)=>{"add"===a?o():"remove"===a&&e.length>1&&(t=>{if(1===e.length)return u.message.warning("At least one group is required");let a=e.filter(e=>e.id!==t);r(a),n===t&&a.length>0&&i(a[a.length-1].id)})(t)},items:f,className:"fallback-tabs",tabBarStyle:{marginBottom:0},hideAdd:e.length>=l})}e.s(["FallbackSelectionForm",()=>v],419470)}]); \ No newline at end of file +(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,384767,e=>{"use strict";var t=e.i(843476),r=e.i(599724),a=e.i(271645),s=e.i(389083);let l=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:"M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"}))});var n=e.i(764205);let i=function({vectorStores:e,accessToken:i}){let[o,c]=(0,a.useState)([]);return(0,a.useEffect)(()=>{(async()=>{if(i&&0!==e.length)try{let e=await (0,n.vectorStoreListCall)(i);e.data&&c(e.data.map(e=>({vector_store_id:e.vector_store_id,vector_store_name:e.vector_store_name})))}catch(e){console.error("Error fetching vector stores:",e)}})()},[i,e.length]),(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(l,{className:"h-4 w-4 text-blue-600"}),(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"Vector Stores"}),(0,t.jsx)(s.Badge,{color:"blue",size:"xs",children:e.length})]}),e.length>0?(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:e.map((e,r)=>{let a;return(0,t.jsx)("div",{className:"inline-flex items-center px-3 py-1.5 rounded-lg bg-blue-50 border border-blue-200 text-blue-800 text-sm font-medium",children:(a=o.find(t=>t.vector_store_id===e))?`${a.vector_store_name||a.vector_store_id} (${a.vector_store_id})`:e},r)})}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(l,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(r.Text,{className:"text-gray-500 text-sm",children:"No vector stores configured"})]})]})},o=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:"M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"}))});var c=e.i(871943),d=e.i(502547),u=e.i(592968);let m=function({mcpServers:l,mcpAccessGroups:i=[],mcpToolPermissions:m={},accessToken:p}){let[g,f]=(0,a.useState)([]),[x,h]=(0,a.useState)([]),[b,y]=(0,a.useState)(new Set);(0,a.useEffect)(()=>{(async()=>{if(p&&l.length>0)try{let e=await (0,n.fetchMCPServers)(p);e&&Array.isArray(e)?f(e):e.data&&Array.isArray(e.data)&&f(e.data)}catch(e){console.error("Error fetching MCP servers:",e)}})()},[p,l.length]),(0,a.useEffect)(()=>{(async()=>{if(p&&i.length>0)try{let t=await e.A(601236).then(e=>e.fetchMCPAccessGroups(p));h(Array.isArray(t)?t:t.data||[])}catch(e){console.error("Error fetching MCP access groups:",e)}})()},[p,i.length]);let v=[...l.map(e=>({type:"server",value:e})),...i.map(e=>({type:"accessGroup",value:e}))],j=v.length;return(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(o,{className:"h-4 w-4 text-blue-600"}),(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"MCP Servers"}),(0,t.jsx)(s.Badge,{color:"blue",size:"xs",children:j})]}),j>0?(0,t.jsx)("div",{className:"max-h-[400px] overflow-y-auto space-y-2 pr-1",children:v.map((e,r)=>{let a="server"===e.type?m[e.value]:void 0,s=a&&a.length>0,l=b.has(e.value);return(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{onClick:()=>{var t;return s&&(t=e.value,void y(e=>{let r=new Set(e);return r.has(t)?r.delete(t):r.add(t),r}))},className:`flex items-center gap-3 py-2 px-3 rounded-lg border border-gray-200 transition-all ${s?"cursor-pointer hover:bg-gray-50 hover:border-gray-300":"bg-white"}`,children:[(0,t.jsx)("div",{className:"flex items-center gap-2 flex-1 min-w-0",children:"server"===e.type?(0,t.jsx)(u.Tooltip,{title:`Full ID: ${e.value}`,placement:"top",children:(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-blue-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:(e=>{let t=g.find(t=>t.server_id===e);if(t){let r=e.length>7?`${e.slice(0,3)}...${e.slice(-4)}`:e;return`${t.alias} (${r})`}return e})(e.value)})]})}):(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-green-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:e.value}),(0,t.jsx)("span",{className:"ml-1 px-1.5 py-0.5 text-[9px] font-semibold text-green-600 bg-green-50 border border-green-200 rounded uppercase tracking-wide flex-shrink-0",children:"Group"})]})}),s&&(0,t.jsxs)("div",{className:"flex items-center gap-1 flex-shrink-0 whitespace-nowrap",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-600",children:a.length}),(0,t.jsx)("span",{className:"text-xs text-gray-500",children:1===a.length?"tool":"tools"}),l?(0,t.jsx)(c.ChevronDownIcon,{className:"h-3.5 w-3.5 text-gray-400 ml-0.5"}):(0,t.jsx)(d.ChevronRightIcon,{className:"h-3.5 w-3.5 text-gray-400 ml-0.5"})]})]}),s&&l&&(0,t.jsx)("div",{className:"ml-4 pl-4 border-l-2 border-blue-200 pb-1",children:(0,t.jsx)("div",{className:"flex flex-wrap gap-1.5",children:a.map((e,r)=>(0,t.jsx)("span",{className:"inline-flex items-center px-2.5 py-1 rounded-lg bg-blue-50 border border-blue-200 text-blue-800 text-xs font-medium",children:e},r))})})]},r)})}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(o,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(r.Text,{className:"text-gray-500 text-sm",children:"No MCP servers or access groups configured"})]})]})},p=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:"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"}))}),g=function({agents:e,agentAccessGroups:l=[],accessToken:i}){let[o,c]=(0,a.useState)([]);(0,a.useEffect)(()=>{(async()=>{if(i&&e.length>0)try{let e=await (0,n.getAgentsList)(i);e&&e.agents&&Array.isArray(e.agents)&&c(e.agents)}catch(e){console.error("Error fetching agents:",e)}})()},[i,e.length]);let d=[...e.map(e=>({type:"agent",value:e})),...l.map(e=>({type:"accessGroup",value:e}))],m=d.length;return(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(p,{className:"h-4 w-4 text-purple-600"}),(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"Agents"}),(0,t.jsx)(s.Badge,{color:"purple",size:"xs",children:m})]}),m>0?(0,t.jsx)("div",{className:"max-h-[400px] overflow-y-auto space-y-2 pr-1",children:d.map((e,r)=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsx)("div",{className:"flex items-center gap-3 py-2 px-3 rounded-lg border border-gray-200 bg-white",children:(0,t.jsx)("div",{className:"flex items-center gap-2 flex-1 min-w-0",children:"agent"===e.type?(0,t.jsx)(u.Tooltip,{title:`Full ID: ${e.value}`,placement:"top",children:(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-purple-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:(e=>{let t=o.find(t=>t.agent_id===e);if(t){let r=e.length>7?`${e.slice(0,3)}...${e.slice(-4)}`:e;return`${t.agent_name} (${r})`}return e})(e.value)})]})}):(0,t.jsxs)("div",{className:"inline-flex items-center gap-2 min-w-0",children:[(0,t.jsx)("span",{className:"inline-block w-1.5 h-1.5 bg-green-500 rounded-full flex-shrink-0"}),(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900 truncate",children:e.value}),(0,t.jsx)("span",{className:"ml-1 px-1.5 py-0.5 text-[9px] font-semibold text-green-600 bg-green-50 border border-green-200 rounded uppercase tracking-wide flex-shrink-0",children:"Group"})]})})})},r))}):(0,t.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200",children:[(0,t.jsx)(p,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)(r.Text,{className:"text-gray-500 text-sm",children:"No agents or access groups configured"})]})]})};e.s(["default",0,function({objectPermission:e,variant:a="card",className:s="",accessToken:l}){let n=e?.vector_stores||[],o=e?.mcp_servers||[],c=e?.mcp_access_groups||[],d=e?.mcp_tool_permissions||{},u=e?.agents||[],p=e?.agent_access_groups||[],f=(0,t.jsxs)("div",{className:"card"===a?"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6":"space-y-4",children:[(0,t.jsx)(i,{vectorStores:n,accessToken:l}),(0,t.jsx)(m,{mcpServers:o,mcpAccessGroups:c,mcpToolPermissions:d,accessToken:l}),(0,t.jsx)(g,{agents:u,agentAccessGroups:p,accessToken:l})]});return"card"===a?(0,t.jsxs)("div",{className:`bg-white border border-gray-200 rounded-lg p-6 ${s}`,children:[(0,t.jsx)("div",{className:"flex items-center gap-2 mb-6",children:(0,t.jsxs)("div",{children:[(0,t.jsx)(r.Text,{className:"font-semibold text-gray-900",children:"Object Permissions"}),(0,t.jsx)(r.Text,{className:"text-xs text-gray-500",children:"Access control for Vector Stores and MCP Servers"})]})}),f]}):(0,t.jsxs)("div",{className:`${s}`,children:[(0,t.jsx)(r.Text,{className:"font-medium text-gray-900 mb-3",children:"Object Permissions"}),f]})}],384767)},270345,e=>{"use strict";var t=e.i(764205);let r=async(e,r,a,s)=>"Admin"!=a&&"Admin Viewer"!=a?await (0,t.teamListCall)(e,s?.organization_id||null,r):await (0,t.teamListCall)(e,s?.organization_id||null);e.s(["fetchTeams",0,r])},519756,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let a={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"};var s=e.i(9583),l=r.forwardRef(function(e,l){return r.createElement(s.default,(0,t.default)({},e,{ref:l,icon:a}))});e.s(["UploadOutlined",0,l],519756)},981339,e=>{"use strict";var t=e.i(185793);e.s(["Skeleton",()=>t.default])},500330,e=>{"use strict";var t=e.i(727749);function r(e,t){let r=structuredClone(e);for(let[e,a]of Object.entries(t))e in r&&(r[e]=a);return r}let a=(e,t=0,r=!1,a=!0)=>{if(null==e||!Number.isFinite(e)||0===e&&!a)return"-";let s={minimumFractionDigits:t,maximumFractionDigits:t};if(!r)return e.toLocaleString("en-US",s);let l=e<0?"-":"",n=Math.abs(e),i=n,o="";return n>=1e6?(i=n/1e6,o="M"):n>=1e3&&(i=n/1e3,o="K"),`${l}${i.toLocaleString("en-US",s)}${o}`},s=async(e,r="Copied to clipboard")=>{if(!e)return!1;if(!navigator||!navigator.clipboard||!navigator.clipboard.writeText)return l(e,r);try{return await navigator.clipboard.writeText(e),t.default.success(r),!0}catch(t){return console.error("Clipboard API failed: ",t),l(e,r)}},l=(e,r)=>{try{let a=document.createElement("textarea");a.value=e,a.style.position="fixed",a.style.left="-999999px",a.style.top="-999999px",a.setAttribute("readonly",""),document.body.appendChild(a),a.focus(),a.select();let s=document.execCommand("copy");if(document.body.removeChild(a),s)return t.default.success(r),!0;throw Error("execCommand failed")}catch(e){return t.default.fromBackend("Failed to copy to clipboard"),console.error("Failed to copy: ",e),!1}};e.s(["copyToClipboard",0,s,"formatNumberWithCommas",0,a,"getSpendString",0,(e,t=6)=>{if(null==e||!Number.isFinite(e)||0===e)return"-";let r=a(e,t,!1,!1);if(0===Number(r.replace(/,/g,""))){let e=(1/10**t).toFixed(t);return`< $${e}`}return`$${r}`},"updateExistingKeys",()=>r])},743151,(e,t,r)=>{"use strict";function a(e){return(a="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)}Object.defineProperty(r,"__esModule",{value:!0}),r.CopyToClipboard=void 0;var s=i(e.r(271645)),l=i(e.r(844343)),n=["text","onCopy","options","children"];function i(e){return e&&e.__esModule?e:{default:e}}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,a)}return r}function c(e){for(var t=1;t=0||(s[r]=e[r]);return s}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0)&&Object.prototype.propertyIsEnumerable.call(e,r)&&(s[r]=e[r])}return s}(e,n),a=s.default.Children.only(t);return s.default.cloneElement(a,c(c({},r),{},{onClick:this.onClick}))}}],function(e,t){for(var r=0;r{"use strict";var a=e.r(743151).CopyToClipboard;a.CopyToClipboard=a,t.exports=a},109799,e=>{"use strict";var t=e.i(135214),r=e.i(764205),a=e.i(266027),s=e.i(912598);let l=(0,e.i(243652).createQueryKeys)("organizations");e.s(["useOrganization",0,e=>{let n=(0,s.useQueryClient)(),{accessToken:i}=(0,t.default)();return(0,a.useQuery)({queryKey:l.detail(e),enabled:!!(i&&e),queryFn:async()=>{if(!i||!e)throw Error("Missing auth or teamId");return(0,r.organizationInfoCall)(i,e)},initialData:()=>{if(!e)return;let t=n.getQueryData(l.list({}));return t?.find(t=>t.organization_id===e)}})},"useOrganizations",0,()=>{let{accessToken:e,userId:s,userRole:n}=(0,t.default)();return(0,a.useQuery)({queryKey:l.list({}),queryFn:async()=>await (0,r.organizationListCall)(e),enabled:!!(e&&s&&n)})}])},309426,e=>{"use strict";var t=e.i(290571),r=e.i(444755),a=e.i(673706),s=e.i(271645),l=e.i(46757);let n=(0,a.makeClassName)("Col"),i=s.default.forwardRef((e,a)=>{let i,o,c,d,{numColSpan:u=1,numColSpanSm:m,numColSpanMd:p,numColSpanLg:g,children:f,className:x}=e,h=(0,t.__rest)(e,["numColSpan","numColSpanSm","numColSpanMd","numColSpanLg","children","className"]),b=(e,t)=>e&&Object.keys(t).includes(String(e))?t[e]:"";return s.default.createElement("div",Object.assign({ref:a,className:(0,r.tremorTwMerge)(n("root"),(i=b(u,l.colSpan),o=b(m,l.colSpanSm),c=b(p,l.colSpanMd),d=b(g,l.colSpanLg),(0,r.tremorTwMerge)(i,o,c,d)),x)},h),f)});i.displayName="Col",e.s(["Col",()=>i],309426)},988297,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"}))});e.s(["PlusIcon",0,r],988297)},797672,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"}))});e.s(["PencilIcon",0,r],797672)},992619,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(779241),s=e.i(599724),l=e.i(199133),n=e.i(983561),i=e.i(689020);e.s(["default",0,({accessToken:e,value:o,placeholder:c="Select a Model",onChange:d,disabled:u=!1,style:m,className:p,showLabel:g=!0,labelText:f="Select Model"})=>{let[x,h]=(0,r.useState)(o),[b,y]=(0,r.useState)(!1),[v,j]=(0,r.useState)([]),w=(0,r.useRef)(null);return(0,r.useEffect)(()=>{h(o)},[o]),(0,r.useEffect)(()=>{e&&(async()=>{try{let t=await (0,i.fetchAvailableModels)(e);console.log("Fetched models for selector:",t),t.length>0&&j(t)}catch(e){console.error("Error fetching model info:",e)}})()},[e]),(0,t.jsxs)("div",{children:[g&&(0,t.jsxs)(s.Text,{className:"font-medium block mb-2 text-gray-700 flex items-center",children:[(0,t.jsx)(n.RobotOutlined,{className:"mr-2"})," ",f]}),(0,t.jsx)(l.Select,{value:x,placeholder:c,onChange:e=>{"custom"===e?(y(!0),h(void 0)):(y(!1),h(e),d&&d(e))},options:[...Array.from(new Set(v.map(e=>e.model_group))).map((e,t)=>({value:e,label:e,key:t})),{value:"custom",label:"Enter custom model",key:"custom"}],style:{width:"100%",...m},showSearch:!0,className:`rounded-md ${p||""}`,disabled:u}),b&&(0,t.jsx)(a.TextInput,{className:"mt-2",placeholder:"Enter custom model name",onValueChange:e=>{w.current&&clearTimeout(w.current),w.current=setTimeout(()=>{h(e),d&&d(e)},500)},disabled:u})]})}])},91739,e=>{"use strict";var t=e.i(544195);e.s(["Radio",()=>t.default])},409797,e=>{"use strict";var t=e.i(631171);e.s(["ChevronDownIcon",()=>t.default])},500727,696609,531516,e=>{"use strict";var t=e.i(266027),r=e.i(243652),a=e.i(764205),s=e.i(135214);let l=(0,r.createQueryKeys)("mcpServers");e.s(["useMCPServers",0,e=>{let{accessToken:r}=(0,s.default)();return(0,t.useQuery)({queryKey:l.list(e?{filters:{teamId:e}}:void 0),queryFn:async()=>await (0,a.fetchMCPServers)(r,e),enabled:!!r})}],500727);var n=e.i(843476),i=e.i(271645),o=e.i(536916),c=e.i(599724),d=e.i(409797),u=e.i(246349),u=u;let m=/\b(delete|remove|destroy|purge|drop|erase|unlink)\b/i,p=/\b(create|add|insert|new|post|submit|register|make|generate|write|upload)\b/i,g=/\b(update|edit|modify|change|patch|put|set|rename|move|transform)\b/i,f=/\b(get|read|list|fetch|search|find|query|retrieve|show|view|check|describe|info)\b/i;function x(e,t=""){let r=e.toLowerCase();if(f.test(r))return"read";if(m.test(r))return"delete";if(g.test(r))return"update";if(p.test(r))return"create";if(t){let e=t.toLowerCase();if(f.test(e))return"read";if(m.test(e))return"delete";if(g.test(e))return"update";if(p.test(e))return"create"}return"unknown"}function h(e){let t={read:[],create:[],update:[],delete:[],unknown:[]};for(let r of e)t[x(r.name,r.description)].push(r);return t}let b={read:{label:"Read",description:"Safe operations — fetch, list, search. No side effects.",risk:"low"},create:{label:"Create",description:"Add new resources — insert, upload, register.",risk:"medium"},update:{label:"Update",description:"Modify existing resources — edit, patch, rename.",risk:"medium"},delete:{label:"Delete",description:"Destructive operations — remove, purge, destroy.",risk:"high"},unknown:{label:"Other",description:"Operations that could not be automatically classified.",risk:"unknown"}};e.s(["CRUD_GROUP_META",0,b,"classifyToolOp",()=>x,"groupToolsByCrud",()=>h],696609);let y=["read","create","update","delete","unknown"],v={low:"bg-green-100 text-green-800",medium:"bg-yellow-100 text-yellow-800",high:"bg-red-100 text-red-800 font-semibold",unknown:"bg-gray-100 text-gray-700"},j={read:"border-green-200",create:"border-blue-200",update:"border-yellow-200",delete:"border-red-300",unknown:"border-gray-200"},w={read:"bg-green-50",create:"bg-blue-50",update:"bg-yellow-50",delete:"bg-red-50",unknown:"bg-gray-50"};e.s(["default",0,({tools:e,value:t,onChange:r,readOnly:a=!1,searchFilter:s=""})=>{let[l,m]=(0,i.useState)({read:!1,create:!1,update:!1,delete:!1,unknown:!0}),p=(0,i.useMemo)(()=>h(e),[e]),g=(0,i.useMemo)(()=>new Set(void 0===t?e.map(e=>e.name):t),[t,e]),f=e=>{if(a)return;let t=new Set(g);t.has(e)?t.delete(e):t.add(e),r(Array.from(t))};return 0===e.length?null:(0,n.jsx)("div",{className:"space-y-3",children:y.map(e=>{let t,i=p[e];if(0===i.length)return null;if(s){let e=s.toLowerCase();if(!i.some(t=>t.name.toLowerCase().includes(e)||(t.description??"").toLowerCase().includes(e)))return null}let x=b[e],h=(t=p[e]).length>0&&t.every(e=>g.has(e.name)),y=(e=>{let t=p[e];if(0===t.length)return!1;let r=t.filter(e=>g.has(e.name)).length;return r>0&&r{m(t=>({...t,[e]:!t[e]}))},children:[N?(0,n.jsx)(u.default,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}):(0,n.jsx)(d.ChevronDownIcon,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}),(0,n.jsx)("span",{className:"font-semibold text-gray-900 text-sm",children:x.label}),(0,n.jsx)("span",{className:`text-xs px-2 py-0.5 rounded-full ${v[x.risk]}`,children:"high"===x.risk?"High Risk":"medium"===x.risk?"Medium Risk":"low"===x.risk?"Safe":"Unclassified"}),(0,n.jsxs)("span",{className:"text-xs text-gray-500 ml-1",children:[i.filter(e=>g.has(e.name)).length,"/",i.length," allowed"]})]}),!a&&(0,n.jsxs)("div",{className:"flex items-center gap-2 ml-4",children:[(0,n.jsx)(c.Text,{className:"text-xs text-gray-500",children:h?"All on":y?"Partial":"All off"}),(0,n.jsx)(o.Checkbox,{checked:h,indeterminate:y,onChange:t=>((e,t)=>{if(a)return;let s=new Set(g);for(let r of p[e])t?s.add(r.name):s.delete(r.name);r(Array.from(s))})(e,t.target.checked),onClick:e=>e.stopPropagation()})]})]}),!N&&(0,n.jsx)("div",{className:"px-4 pt-2 pb-1 text-xs text-gray-500 bg-white border-b border-gray-100",children:x.description}),!N&&(0,n.jsx)("div",{className:"bg-white divide-y divide-gray-50",children:i.filter(e=>!s||e.name.toLowerCase().includes(s.toLowerCase())||(e.description??"").toLowerCase().includes(s.toLowerCase())).map(e=>{let t,r=(t=e.name,g.has(t));return(0,n.jsxs)("div",{className:`flex items-start gap-3 px-4 py-2.5 transition-colors hover:bg-gray-50 ${!a?"cursor-pointer":""} ${r?"":"opacity-60"}`,onClick:()=>f(e.name),children:[(0,n.jsx)(o.Checkbox,{checked:r,onChange:()=>f(e.name),disabled:a,onClick:e=>e.stopPropagation()}),(0,n.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,n.jsx)(c.Text,{className:"font-medium text-gray-900 text-sm",children:e.name}),e.description&&(0,n.jsx)(c.Text,{className:"text-xs text-gray-500 mt-0.5 leading-snug",children:e.description})]}),(0,n.jsx)("span",{className:`text-xs px-1.5 py-0.5 rounded flex-shrink-0 ${r?"bg-green-100 text-green-700":"bg-gray-100 text-gray-500"}`,children:r?"on":"off"})]},e.name)})})]},e)})})}],531516)},361653,e=>{"use strict";let t=(0,e.i(475254).default)("circle-alert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);e.s(["default",()=>t])},603908,e=>{"use strict";let t=(0,e.i(475254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);e.s(["default",()=>t])},841947,e=>{"use strict";let t=(0,e.i(475254).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["default",()=>t])},793130,e=>{"use strict";var t=e.i(290571),r=e.i(429427),a=e.i(371330),s=e.i(271645),l=e.i(394487),n=e.i(503269),i=e.i(214520),o=e.i(746725),c=e.i(914189),d=e.i(144279),u=e.i(294316),m=e.i(601893),p=e.i(140721),g=e.i(942803),f=e.i(233538),x=e.i(694421),h=e.i(700020),b=e.i(35889),y=e.i(998348),v=e.i(722678);let j=(0,s.createContext)(null);j.displayName="GroupContext";let w=s.Fragment,N=Object.assign((0,h.forwardRefWithAs)(function(e,t){var w;let N=(0,s.useId)(),k=(0,g.useProvidedId)(),C=(0,m.useDisabled)(),{id:S=k||`headlessui-switch-${N}`,disabled:M=C||!1,checked:_,defaultChecked:O,onChange:T,name:E,value:P,form:L,autoFocus:R=!1,...F}=e,$=(0,s.useContext)(j),[A,D]=(0,s.useState)(null),B=(0,s.useRef)(null),I=(0,u.useSyncRefs)(B,t,null===$?null:$.setSwitch,D),z=(0,i.useDefaultValue)(O),[q,K]=(0,n.useControllable)(_,T,null!=z&&z),V=(0,o.useDisposables)(),[G,H]=(0,s.useState)(!1),U=(0,c.useEvent)(()=>{H(!0),null==K||K(!q),V.nextFrame(()=>{H(!1)})}),Q=(0,c.useEvent)(e=>{if((0,f.isDisabledReactIssue7711)(e.currentTarget))return e.preventDefault();e.preventDefault(),U()}),W=(0,c.useEvent)(e=>{e.key===y.Keys.Space?(e.preventDefault(),U()):e.key===y.Keys.Enter&&(0,x.attemptSubmit)(e.currentTarget)}),J=(0,c.useEvent)(e=>e.preventDefault()),X=(0,v.useLabelledBy)(),Y=(0,b.useDescribedBy)(),{isFocusVisible:Z,focusProps:ee}=(0,r.useFocusRing)({autoFocus:R}),{isHovered:et,hoverProps:er}=(0,a.useHover)({isDisabled:M}),{pressed:ea,pressProps:es}=(0,l.useActivePress)({disabled:M}),el=(0,s.useMemo)(()=>({checked:q,disabled:M,hover:et,focus:Z,active:ea,autofocus:R,changing:G}),[q,et,Z,ea,M,G,R]),en=(0,h.mergeProps)({id:S,ref:I,role:"switch",type:(0,d.useResolveButtonType)(e,A),tabIndex:-1===e.tabIndex?0:null!=(w=e.tabIndex)?w:0,"aria-checked":q,"aria-labelledby":X,"aria-describedby":Y,disabled:M||void 0,autoFocus:R,onClick:Q,onKeyUp:W,onKeyPress:J},ee,er,es),ei=(0,s.useCallback)(()=>{if(void 0!==z)return null==K?void 0:K(z)},[K,z]),eo=(0,h.useRender)();return s.default.createElement(s.default.Fragment,null,null!=E&&s.default.createElement(p.FormFields,{disabled:M,data:{[E]:P||"on"},overrides:{type:"checkbox",checked:q},form:L,onReset:ei}),eo({ourProps:en,theirProps:F,slot:el,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var t;let[r,a]=(0,s.useState)(null),[l,n]=(0,v.useLabels)(),[i,o]=(0,b.useDescriptions)(),c=(0,s.useMemo)(()=>({switch:r,setSwitch:a}),[r,a]),d=(0,h.useRender)();return s.default.createElement(o,{name:"Switch.Description",value:i},s.default.createElement(n,{name:"Switch.Label",value:l,props:{htmlFor:null==(t=c.switch)?void 0:t.id,onClick(e){r&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),r.click(),r.focus({preventScroll:!0}))}}},s.default.createElement(j.Provider,{value:c},d({ourProps:{},theirProps:e,slot:{},defaultTag:w,name:"Switch.Group"}))))},Label:v.Label,Description:b.Description});var k=e.i(888288),C=e.i(95779),S=e.i(444755),M=e.i(673706),_=e.i(829087);let O=(0,M.makeClassName)("Switch"),T=s.default.forwardRef((e,r)=>{let{checked:a,defaultChecked:l=!1,onChange:n,color:i,name:o,error:c,errorMessage:d,disabled:u,required:m,tooltip:p,id:g}=e,f=(0,t.__rest)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),x={bgColor:i?(0,M.getColorClassNames)(i,C.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:i?(0,M.getColorClassNames)(i,C.colorPalette.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[h,b]=(0,k.default)(l,a),[y,v]=(0,s.useState)(!1),{tooltipProps:j,getReferenceProps:w}=(0,_.useTooltip)(300);return s.default.createElement("div",{className:"flex flex-row items-center justify-start"},s.default.createElement(_.default,Object.assign({text:p},j)),s.default.createElement("div",Object.assign({ref:(0,M.mergeRefs)([r,j.refs.setReference]),className:(0,S.tremorTwMerge)(O("root"),"flex flex-row relative h-5")},f,w),s.default.createElement("input",{type:"checkbox",className:(0,S.tremorTwMerge)(O("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:o,required:m,checked:h,onChange:e=>{e.preventDefault()}}),s.default.createElement(N,{checked:h,onChange:e=>{b(e),null==n||n(e)},disabled:u,className:(0,S.tremorTwMerge)(O("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:()=>v(!0),onBlur:()=>v(!1),id:g},s.default.createElement("span",{className:(0,S.tremorTwMerge)(O("sr-only"),"sr-only")},"Switch ",h?"on":"off"),s.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(O("background"),h?x.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")}),s.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(O("round"),h?(0,S.tremorTwMerge)(x.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",y?(0,S.tremorTwMerge)("ring-2",x.ringColor):"")}))),c&&d?s.default.createElement("p",{className:(0,S.tremorTwMerge)(O("errorMessage"),"text-sm text-red-500 mt-1 ")},d):null)});T.displayName="Switch",e.s(["Switch",()=>T],793130)},158392,419470,e=>{"use strict";var t=e.i(843476),r=e.i(779241);let a={ttl:3600,lowest_latency_buffer:0},s=({routingStrategyArgs:e})=>{let s={ttl:"Sliding window to look back over when calculating the average latency of a deployment. Default - 1 hour (in seconds).",lowest_latency_buffer:"Shuffle between deployments within this % of the lowest latency. Default - 0 (i.e. always pick lowest latency)."};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Latency-Based Configuration"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Fine-tune latency-based routing behavior"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e||a).map(([e,a])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:e.replace(/_/g," ")}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:s[e]||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:"object"==typeof a?JSON.stringify(a,null,2):a?.toString(),className:"font-mono text-sm w-full"})]})},e))})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"})]})},l=({routerSettings:e,routerFieldsMetadata:a})=>(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Reliability & Retries"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure retry logic and failure handling"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e).filter(([e,t])=>"fallbacks"!=e&&"context_window_fallbacks"!=e&&"routing_strategy_args"!=e&&"routing_strategy"!=e&&"enable_tag_filtering"!=e).map(([e,s])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:a[e]?.ui_field_name||e}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:a[e]?.field_description||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:null==s||"null"===s?"":"object"==typeof s?JSON.stringify(s,null,2):s?.toString()||"",placeholder:"—",className:"font-mono text-sm w-full"})]})},e))})]});var n=e.i(199133);let i=({selectedStrategy:e,availableStrategies:r,routingStrategyDescriptions:a,routerFieldsMetadata:s,onStrategyChange:l})=>(0,t.jsxs)("div",{className:"space-y-2 max-w-3xl",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:s.routing_strategy?.ui_field_name||"Routing Strategy"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:s.routing_strategy?.field_description||""})]}),(0,t.jsx)("div",{className:"routing-strategy-select max-w-3xl",children:(0,t.jsx)(n.Select,{value:e,onChange:l,style:{width:"100%"},size:"large",children:r.map(e=>(0,t.jsx)(n.Select.Option,{value:e,label:e,children:(0,t.jsxs)("div",{className:"flex flex-col gap-0.5 py-1",children:[(0,t.jsx)("span",{className:"font-mono text-sm font-medium",children:e}),a[e]&&(0,t.jsx)("span",{className:"text-xs text-gray-500 font-normal",children:a[e]})]})},e))})})]});var o=e.i(793130);let c=({enabled:e,routerFieldsMetadata:r,onToggle:a})=>(0,t.jsx)("div",{className:"space-y-3 max-w-3xl",children:(0,t.jsxs)("div",{className:"flex items-start justify-between",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:r.enable_tag_filtering?.ui_field_name||"Enable Tag Filtering"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500 mt-0.5",children:[r.enable_tag_filtering?.field_description||"",r.enable_tag_filtering?.link&&(0,t.jsxs)(t.Fragment,{children:[" ",(0,t.jsx)("a",{href:r.enable_tag_filtering.link,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline",children:"Learn more"})]})]})]}),(0,t.jsx)(o.Switch,{checked:e,onChange:a,className:"ml-4"})]})});e.s(["default",0,({value:e,onChange:r,routerFieldsMetadata:a,availableRoutingStrategies:n,routingStrategyDescriptions:o})=>(0,t.jsxs)("div",{className:"w-full space-y-8 py-2",children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Routing Settings"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure how requests are routed to deployments"})]}),n.length>0&&(0,t.jsx)(i,{selectedStrategy:e.selectedStrategy||e.routerSettings.routing_strategy||null,availableStrategies:n,routingStrategyDescriptions:o,routerFieldsMetadata:a,onStrategyChange:t=>{r({...e,selectedStrategy:t})}}),(0,t.jsx)(c,{enabled:e.enableTagFiltering,routerFieldsMetadata:a,onToggle:t=>{r({...e,enableTagFiltering:t})}})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),"latency-based-routing"===e.selectedStrategy&&(0,t.jsx)(s,{routingStrategyArgs:e.routerSettings.routing_strategy_args}),(0,t.jsx)(l,{routerSettings:e.routerSettings,routerFieldsMetadata:a})]})],158392);var d=e.i(994388),u=e.i(998573),m=e.i(653496),p=e.i(107233),g=e.i(271645),f=e.i(592968),x=e.i(361653),x=x;let h=(0,e.i(475254).default)("arrow-down",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var b=e.i(37727);function y({group:e,onChange:r,availableModels:a,maxFallbacks:s}){let l=a.filter(t=>t!==e.primaryModel),i=e.fallbackModels.length{let a=[...e.fallbackModels];a.includes(t)&&(a=a.filter(e=>e!==t)),r({...e,primaryModel:t,fallbackModels:a})},showSearch:!0,getPopupContainer:e=>e.parentElement||document.body,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase()),options:a.map(e=>({label:e,value:e}))}),!e.primaryModel&&(0,t.jsxs)("div",{className:"mt-2 flex items-center gap-2 text-amber-600 text-xs bg-amber-50 p-2 rounded",children:[(0,t.jsx)(x.default,{className:"w-4 h-4"}),(0,t.jsx)("span",{children:"Select a model to begin configuring fallbacks"})]})]}),(0,t.jsx)("div",{className:"flex items-center justify-center -my-4 z-10",children:(0,t.jsxs)("div",{className:"bg-indigo-50 text-indigo-500 px-4 py-1 rounded-full text-xs font-bold border border-indigo-100 flex items-center gap-2 shadow-sm",children:[(0,t.jsx)(h,{className:"w-4 h-4"}),"IF FAILS, TRY..."]})}),(0,t.jsxs)("div",{className:`transition-opacity duration-300 ${!e.primaryModel?"opacity-50 pointer-events-none":"opacity-100"}`,children:[(0,t.jsxs)("label",{className:"block text-sm font-semibold text-gray-700 mb-2",children:["Fallback Chain ",(0,t.jsx)("span",{className:"text-red-500",children:"*"}),(0,t.jsxs)("span",{className:"text-xs text-gray-500 font-normal ml-2",children:["(Max ",s," fallbacks at a time)"]})]}),(0,t.jsxs)("div",{className:"bg-gray-50 rounded-xl p-4 border border-gray-200",children:[(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(n.Select,{mode:"multiple",className:"w-full",size:"large",placeholder:i?"Select fallback models to add...":`Maximum ${s} fallbacks reached`,value:e.fallbackModels,onChange:t=>{let a=t.slice(0,s);r({...e,fallbackModels:a})},disabled:!e.primaryModel,getPopupContainer:e=>e.parentElement||document.body,options:l.map(e=>({label:e,value:e})),optionRender:(r,a)=>{let s=e.fallbackModels.includes(r.value),l=s?e.fallbackModels.indexOf(r.value)+1:null;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[s&&null!==l&&(0,t.jsx)("span",{className:"flex items-center justify-center w-5 h-5 rounded bg-indigo-100 text-indigo-600 text-xs font-bold",children:l}),(0,t.jsx)("span",{children:r.label})]})},maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(f.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})}),showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase())}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1 ml-1",children:i?`Search and select multiple models. Selected models will appear below in order. (${e.fallbackModels.length}/${s} used)`:`Maximum ${s} fallbacks reached. Remove some to add more.`})]}),(0,t.jsx)("div",{className:"space-y-2 min-h-[100px]",children:0===e.fallbackModels.length?(0,t.jsxs)("div",{className:"h-32 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)("span",{className:"text-sm",children:"No fallback models selected"}),(0,t.jsx)("span",{className:"text-xs mt-1",children:"Add models from the dropdown above"})]}):e.fallbackModels.map((a,s)=>(0,t.jsxs)("div",{className:"group flex items-center justify-between p-3 bg-white rounded-lg border border-gray-200 hover:border-indigo-300 hover:shadow-sm transition-all",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex items-center justify-center w-6 h-6 rounded bg-gray-100 text-gray-400 group-hover:text-indigo-500 group-hover:bg-indigo-50",children:(0,t.jsx)("span",{className:"text-xs font-bold",children:s+1})}),(0,t.jsx)("div",{children:(0,t.jsx)("span",{className:"font-medium text-gray-800",children:a})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>{let t;return t=e.fallbackModels.filter((e,t)=>t!==s),void r({...e,fallbackModels:t})},className:"opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500 p-1",children:(0,t.jsx)(b.X,{className:"w-4 h-4"})})]},`${a}-${s}`))})]})]})]})}function v({groups:e,onGroupsChange:r,availableModels:a,maxFallbacks:s=10,maxGroups:l=5}){let[n,i]=(0,g.useState)(e.length>0?e[0].id:"1");(0,g.useEffect)(()=>{e.length>0?e.some(e=>e.id===n)||i(e[0].id):i("1")},[e]);let o=()=>{if(e.length>=l)return;let t=Date.now().toString();r([...e,{id:t,primaryModel:null,fallbackModels:[]}]),i(t)},c=t=>{r(e.map(e=>e.id===t.id?t:e))},f=e.map((r,l)=>{let n=r.primaryModel?r.primaryModel:`Group ${l+1}`;return{key:r.id,label:n,closable:e.length>1,children:(0,t.jsx)(y,{group:r,onChange:c,availableModels:a,maxFallbacks:s})}});return 0===e.length?(0,t.jsxs)("div",{className:"text-center py-12 bg-gray-50 rounded-lg border border-dashed border-gray-300",children:[(0,t.jsx)("p",{className:"text-gray-500 mb-4",children:"No fallback groups configured"}),(0,t.jsx)(d.Button,{variant:"primary",onClick:o,icon:()=>(0,t.jsx)(p.Plus,{className:"w-4 h-4"}),children:"Create First Group"})]}):(0,t.jsx)(m.Tabs,{type:"editable-card",activeKey:n,onChange:i,onEdit:(t,a)=>{"add"===a?o():"remove"===a&&e.length>1&&(t=>{if(1===e.length)return u.message.warning("At least one group is required");let a=e.filter(e=>e.id!==t);r(a),n===t&&a.length>0&&i(a[a.length-1].id)})(t)},items:f,className:"fallback-tabs",tabBarStyle:{marginBottom:0},hideAdd:e.length>=l})}e.s(["FallbackSelectionForm",()=>v],419470)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/f2ee2fa5fe008110.js b/litellm/proxy/_experimental/out/_next/static/chunks/62a03e24dd5227b9.js similarity index 93% rename from litellm/proxy/_experimental/out/_next/static/chunks/f2ee2fa5fe008110.js rename to litellm/proxy/_experimental/out/_next/static/chunks/62a03e24dd5227b9.js index 7bfeae44ad..dc9b74ebc1 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/f2ee2fa5fe008110.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/62a03e24dd5227b9.js @@ -4,4 +4,4 @@ `]:{[`&:hover ${t}-inner`]:{borderColor:e.colorPrimary}},[`${l}:not(${l}-disabled)`]:{[`&:hover ${t}-checked:not(${t}-disabled) ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"},[`&:hover ${t}-checked:not(${t}-disabled):after`]:{borderColor:e.colorPrimaryHover}}},{[`${t}-checked`]:{[`${t}-inner`]:{backgroundColor:e.colorPrimary,borderColor:e.colorPrimary,"&:after":{opacity:1,transform:"rotate(45deg) scale(1) translate(-50%,-50%)",transition:`all ${e.motionDurationMid} ${e.motionEaseOutBack} ${e.motionDurationFast}`}}},[` ${l}-checked:not(${l}-disabled), ${t}-checked:not(${t}-disabled) - `]:{[`&:hover ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"}}},{[t]:{"&-indeterminate":{"&":{[`${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${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 ${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${e.colorPrimary}`}}}}},{[`${l}-disabled`]:{cursor:"not-allowed"},[`${t}-disabled`]:{[`&, ${t}-input`]:{cursor:"not-allowed",pointerEvents:"none"},[`${t}-inner`]:{background:e.colorBgContainerDisabled,borderColor:e.colorBorder,"&:after":{borderColor:e.colorTextDisabled}},"&:after":{display:"none"},"& + span":{color:e.colorTextDisabled},[`&${t}-indeterminate ${t}-inner::after`]:{background:e.colorTextDisabled}}}]})((0,o.mergeToken)(t,{checkboxCls:`.${e}`,checkboxSize:t.controlInteractiveSize}))}let s=(0,l.genStyleHooks)("Checkbox",(e,{prefixCls:t})=>[n(t,e)]);e.s(["default",0,s,"getStyle",()=>n],236836)},374276,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(91874),l=e.i(611935),o=e.i(121872),n=e.i(26905),s=e.i(242064),i=e.i(937328),c=e.i(321883),d=e.i(62139),u=e.i(421512),m=e.i(236836),g=e.i(681216),p=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let f=t.forwardRef((e,f)=>{var h;let{prefixCls:x,className:b,rootClassName:y,children:v,indeterminate:w=!1,style:k,onMouseEnter:C,onMouseLeave:j,skipGroup:N=!1,disabled:S}=e,$=p(e,["prefixCls","className","rootClassName","children","indeterminate","style","onMouseEnter","onMouseLeave","skipGroup","disabled"]),{getPrefixCls:M,direction:E,checkbox:O}=t.useContext(s.ConfigContext),T=t.useContext(u.default),{isFormItemInput:P}=t.useContext(d.FormItemInputContext),_=t.useContext(i.default),z=null!=(h=(null==T?void 0:T.disabled)||S)?h:_,R=t.useRef($.value),I=t.useRef(null),L=(0,l.composeRef)(f,I);t.useEffect(()=>{null==T||T.registerValue($.value)},[]),t.useEffect(()=>{if(!N)return $.value!==R.current&&(null==T||T.cancelValue(R.current),null==T||T.registerValue($.value),R.current=$.value),()=>null==T?void 0:T.cancelValue($.value)},[$.value]),t.useEffect(()=>{var e;(null==(e=I.current)?void 0:e.input)&&(I.current.input.indeterminate=w)},[w]);let D=M("checkbox",x),B=(0,c.default)(D),[F,A,q]=(0,m.default)(D,B),H=Object.assign({},$);T&&!N&&(H.onChange=(...e)=>{$.onChange&&$.onChange.apply($,e),T.toggleOption&&T.toggleOption({label:v,value:$.value})},H.name=T.name,H.checked=T.value.includes($.value));let G=(0,r.default)(`${D}-wrapper`,{[`${D}-rtl`]:"rtl"===E,[`${D}-wrapper-checked`]:H.checked,[`${D}-wrapper-disabled`]:z,[`${D}-wrapper-in-form-item`]:P},null==O?void 0:O.className,b,y,q,B,A),X=(0,r.default)({[`${D}-indeterminate`]:w},n.TARGET_CLS,A),[V,K]=(0,g.default)(H.onClick);return F(t.createElement(o.default,{component:"Checkbox",disabled:z},t.createElement("label",{className:G,style:Object.assign(Object.assign({},null==O?void 0:O.style),k),onMouseEnter:C,onMouseLeave:j,onClick:V},t.createElement(a.default,Object.assign({},H,{onClick:K,prefixCls:D,className:X,disabled:z,ref:L})),null!=v&&t.createElement("span",{className:`${D}-label`},v))))});var h=e.i(8211),x=e.i(529681),b=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let y=t.forwardRef((e,a)=>{let{defaultValue:l,children:o,options:n=[],prefixCls:i,className:d,rootClassName:g,style:p,onChange:y}=e,v=b(e,["defaultValue","children","options","prefixCls","className","rootClassName","style","onChange"]),{getPrefixCls:w,direction:k}=t.useContext(s.ConfigContext),[C,j]=t.useState(v.value||l||[]),[N,S]=t.useState([]);t.useEffect(()=>{"value"in v&&j(v.value||[])},[v.value]);let $=t.useMemo(()=>n.map(e=>"string"==typeof e||"number"==typeof e?{label:e,value:e}:e),[n]),M=e=>{S(t=>t.filter(t=>t!==e))},E=e=>{S(t=>[].concat((0,h.default)(t),[e]))},O=e=>{let t=C.indexOf(e.value),r=(0,h.default)(C);-1===t?r.push(e.value):r.splice(t,1),"value"in v||j(r),null==y||y(r.filter(e=>N.includes(e)).sort((e,t)=>$.findIndex(t=>t.value===e)-$.findIndex(e=>e.value===t)))},T=w("checkbox",i),P=`${T}-group`,_=(0,c.default)(T),[z,R,I]=(0,m.default)(T,_),L=(0,x.default)(v,["value","disabled"]),D=n.length?$.map(e=>t.createElement(f,{prefixCls:T,key:e.value.toString(),disabled:"disabled"in e?e.disabled:v.disabled,value:e.value,checked:C.includes(e.value),onChange:e.onChange,className:(0,r.default)(`${P}-item`,e.className),style:e.style,title:e.title,id:e.id,required:e.required},e.label)):o,B=t.useMemo(()=>({toggleOption:O,value:C,disabled:v.disabled,name:v.name,registerValue:E,cancelValue:M}),[O,C,v.disabled,v.name,E,M]),F=(0,r.default)(P,{[`${P}-rtl`]:"rtl"===k},d,g,I,_,R);return z(t.createElement("div",Object.assign({className:F,style:p},L,{ref:a}),t.createElement(u.default.Provider,{value:B},D)))});f.Group=y,f.__ANT_CHECKBOX=!0,e.s(["default",0,f],374276)},536916,e=>{"use strict";var t=e.i(374276);e.s(["Checkbox",()=>t.default])},292639,e=>{"use strict";var t=e.i(764205),r=e.i(266027);let a=(0,e.i(243652).createQueryKeys)("uiSettings");e.s(["useUISettings",0,()=>(0,r.useQuery)({queryKey:a.list({}),queryFn:async()=>await (0,t.getUiSettings)(),staleTime:36e5,gcTime:36e5})])},250980,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlusCircleIcon",0,r],250980)},502547,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 5l7 7-7 7"}))});e.s(["ChevronRightIcon",0,r],502547)},988297,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"}))});e.s(["PlusIcon",0,r],988297)},797672,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"}))});e.s(["PencilIcon",0,r],797672)},992619,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(779241),l=e.i(599724),o=e.i(199133),n=e.i(983561),s=e.i(689020);e.s(["default",0,({accessToken:e,value:i,placeholder:c="Select a Model",onChange:d,disabled:u=!1,style:m,className:g,showLabel:p=!0,labelText:f="Select Model"})=>{let[h,x]=(0,r.useState)(i),[b,y]=(0,r.useState)(!1),[v,w]=(0,r.useState)([]),k=(0,r.useRef)(null);return(0,r.useEffect)(()=>{x(i)},[i]),(0,r.useEffect)(()=>{e&&(async()=>{try{let t=await (0,s.fetchAvailableModels)(e);console.log("Fetched models for selector:",t),t.length>0&&w(t)}catch(e){console.error("Error fetching model info:",e)}})()},[e]),(0,t.jsxs)("div",{children:[p&&(0,t.jsxs)(l.Text,{className:"font-medium block mb-2 text-gray-700 flex items-center",children:[(0,t.jsx)(n.RobotOutlined,{className:"mr-2"})," ",f]}),(0,t.jsx)(o.Select,{value:h,placeholder:c,onChange:e=>{"custom"===e?(y(!0),x(void 0)):(y(!1),x(e),d&&d(e))},options:[...Array.from(new Set(v.map(e=>e.model_group))).map((e,t)=>({value:e,label:e,key:t})),{value:"custom",label:"Enter custom model",key:"custom"}],style:{width:"100%",...m},showSearch:!0,className:`rounded-md ${g||""}`,disabled:u}),b&&(0,t.jsx)(a.TextInput,{className:"mt-2",placeholder:"Enter custom model name",onValueChange:e=>{k.current&&clearTimeout(k.current),k.current=setTimeout(()=>{x(e),d&&d(e)},500)},disabled:u})]})}])},409797,e=>{"use strict";var t=e.i(631171);e.s(["ChevronDownIcon",()=>t.default])},91739,e=>{"use strict";var t=e.i(544195);e.s(["Radio",()=>t.default])},500727,696609,531516,e=>{"use strict";var t=e.i(266027),r=e.i(243652),a=e.i(764205),l=e.i(135214);let o=(0,r.createQueryKeys)("mcpServers");e.s(["useMCPServers",0,e=>{let{accessToken:r}=(0,l.default)();return(0,t.useQuery)({queryKey:o.list(e?{filters:{teamId:e}}:void 0),queryFn:async()=>await (0,a.fetchMCPServers)(r,e),enabled:!!r})}],500727);var n=e.i(843476),s=e.i(271645),i=e.i(536916),c=e.i(599724),d=e.i(409797),u=e.i(246349),u=u;let m=/\b(delete|remove|destroy|purge|drop|erase|unlink)\b/i,g=/\b(create|add|insert|new|post|submit|register|make|generate|write|upload)\b/i,p=/\b(update|edit|modify|change|patch|put|set|rename|move|transform)\b/i,f=/\b(get|read|list|fetch|search|find|query|retrieve|show|view|check|describe|info)\b/i;function h(e,t=""){let r=e.toLowerCase();if(f.test(r))return"read";if(m.test(r))return"delete";if(p.test(r))return"update";if(g.test(r))return"create";if(t){let e=t.toLowerCase();if(f.test(e))return"read";if(m.test(e))return"delete";if(p.test(e))return"update";if(g.test(e))return"create"}return"unknown"}function x(e){let t={read:[],create:[],update:[],delete:[],unknown:[]};for(let r of e)t[h(r.name,r.description)].push(r);return t}let b={read:{label:"Read",description:"Safe operations — fetch, list, search. No side effects.",risk:"low"},create:{label:"Create",description:"Add new resources — insert, upload, register.",risk:"medium"},update:{label:"Update",description:"Modify existing resources — edit, patch, rename.",risk:"medium"},delete:{label:"Delete",description:"Destructive operations — remove, purge, destroy.",risk:"high"},unknown:{label:"Other",description:"Operations that could not be automatically classified.",risk:"unknown"}};e.s(["CRUD_GROUP_META",0,b,"classifyToolOp",()=>h,"groupToolsByCrud",()=>x],696609);let y=["read","create","update","delete","unknown"],v={low:"bg-green-100 text-green-800",medium:"bg-yellow-100 text-yellow-800",high:"bg-red-100 text-red-800 font-semibold",unknown:"bg-gray-100 text-gray-700"},w={read:"border-green-200",create:"border-blue-200",update:"border-yellow-200",delete:"border-red-300",unknown:"border-gray-200"},k={read:"bg-green-50",create:"bg-blue-50",update:"bg-yellow-50",delete:"bg-red-50",unknown:"bg-gray-50"};e.s(["default",0,({tools:e,value:t,onChange:r,readOnly:a=!1,searchFilter:l=""})=>{let[o,m]=(0,s.useState)({read:!1,create:!1,update:!1,delete:!1,unknown:!0}),g=(0,s.useMemo)(()=>x(e),[e]),p=(0,s.useMemo)(()=>new Set(void 0===t?e.map(e=>e.name):t),[t,e]),f=e=>{if(a)return;let t=new Set(p);t.has(e)?t.delete(e):t.add(e),r(Array.from(t))};return 0===e.length?null:(0,n.jsx)("div",{className:"space-y-3",children:y.map(e=>{let t,s=g[e];if(0===s.length)return null;if(l){let e=l.toLowerCase();if(!s.some(t=>t.name.toLowerCase().includes(e)||(t.description??"").toLowerCase().includes(e)))return null}let h=b[e],x=(t=g[e]).length>0&&t.every(e=>p.has(e.name)),y=(e=>{let t=g[e];if(0===t.length)return!1;let r=t.filter(e=>p.has(e.name)).length;return r>0&&r{m(t=>({...t,[e]:!t[e]}))},children:[C?(0,n.jsx)(u.default,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}):(0,n.jsx)(d.ChevronDownIcon,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}),(0,n.jsx)("span",{className:"font-semibold text-gray-900 text-sm",children:h.label}),(0,n.jsx)("span",{className:`text-xs px-2 py-0.5 rounded-full ${v[h.risk]}`,children:"high"===h.risk?"High Risk":"medium"===h.risk?"Medium Risk":"low"===h.risk?"Safe":"Unclassified"}),(0,n.jsxs)("span",{className:"text-xs text-gray-500 ml-1",children:[s.filter(e=>p.has(e.name)).length,"/",s.length," allowed"]})]}),!a&&(0,n.jsxs)("div",{className:"flex items-center gap-2 ml-4",children:[(0,n.jsx)(c.Text,{className:"text-xs text-gray-500",children:x?"All on":y?"Partial":"All off"}),(0,n.jsx)(i.Checkbox,{checked:x,indeterminate:y,onChange:t=>((e,t)=>{if(a)return;let l=new Set(p);for(let r of g[e])t?l.add(r.name):l.delete(r.name);r(Array.from(l))})(e,t.target.checked),onClick:e=>e.stopPropagation()})]})]}),!C&&(0,n.jsx)("div",{className:"px-4 pt-2 pb-1 text-xs text-gray-500 bg-white border-b border-gray-100",children:h.description}),!C&&(0,n.jsx)("div",{className:"bg-white divide-y divide-gray-50",children:s.filter(e=>!l||e.name.toLowerCase().includes(l.toLowerCase())||(e.description??"").toLowerCase().includes(l.toLowerCase())).map(e=>{let t,r=(t=e.name,p.has(t));return(0,n.jsxs)("div",{className:`flex items-start gap-3 px-4 py-2.5 transition-colors hover:bg-gray-50 ${!a?"cursor-pointer":""} ${r?"":"opacity-60"}`,onClick:()=>f(e.name),children:[(0,n.jsx)(i.Checkbox,{checked:r,onChange:()=>f(e.name),disabled:a,onClick:e=>e.stopPropagation()}),(0,n.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,n.jsx)(c.Text,{className:"font-medium text-gray-900 text-sm",children:e.name}),e.description&&(0,n.jsx)(c.Text,{className:"text-xs text-gray-500 mt-0.5 leading-snug",children:e.description})]}),(0,n.jsx)("span",{className:`text-xs px-1.5 py-0.5 rounded flex-shrink-0 ${r?"bg-green-100 text-green-700":"bg-gray-100 text-gray-500"}`,children:r?"on":"off"})]},e.name)})})]},e)})})}],531516)},361653,e=>{"use strict";let t=(0,e.i(475254).default)("circle-alert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);e.s(["default",()=>t])},603908,e=>{"use strict";let t=(0,e.i(475254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);e.s(["default",()=>t])},841947,e=>{"use strict";let t=(0,e.i(475254).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["default",()=>t])},793130,e=>{"use strict";var t=e.i(290571),r=e.i(429427),a=e.i(371330),l=e.i(271645),o=e.i(394487),n=e.i(503269),s=e.i(214520),i=e.i(746725),c=e.i(914189),d=e.i(144279),u=e.i(294316),m=e.i(601893),g=e.i(140721),p=e.i(942803),f=e.i(233538),h=e.i(694421),x=e.i(700020),b=e.i(35889),y=e.i(998348),v=e.i(722678);let w=(0,l.createContext)(null);w.displayName="GroupContext";let k=l.Fragment,C=Object.assign((0,x.forwardRefWithAs)(function(e,t){var k;let C=(0,l.useId)(),j=(0,p.useProvidedId)(),N=(0,m.useDisabled)(),{id:S=j||`headlessui-switch-${C}`,disabled:$=N||!1,checked:M,defaultChecked:E,onChange:O,name:T,value:P,form:_,autoFocus:z=!1,...R}=e,I=(0,l.useContext)(w),[L,D]=(0,l.useState)(null),B=(0,l.useRef)(null),F=(0,u.useSyncRefs)(B,t,null===I?null:I.setSwitch,D),A=(0,s.useDefaultValue)(E),[q,H]=(0,n.useControllable)(M,O,null!=A&&A),G=(0,i.useDisposables)(),[X,V]=(0,l.useState)(!1),K=(0,c.useEvent)(()=>{V(!0),null==H||H(!q),G.nextFrame(()=>{V(!1)})}),W=(0,c.useEvent)(e=>{if((0,f.isDisabledReactIssue7711)(e.currentTarget))return e.preventDefault();e.preventDefault(),K()}),U=(0,c.useEvent)(e=>{e.key===y.Keys.Space?(e.preventDefault(),K()):e.key===y.Keys.Enter&&(0,h.attemptSubmit)(e.currentTarget)}),Y=(0,c.useEvent)(e=>e.preventDefault()),Q=(0,v.useLabelledBy)(),J=(0,b.useDescribedBy)(),{isFocusVisible:Z,focusProps:ee}=(0,r.useFocusRing)({autoFocus:z}),{isHovered:et,hoverProps:er}=(0,a.useHover)({isDisabled:$}),{pressed:ea,pressProps:el}=(0,o.useActivePress)({disabled:$}),eo=(0,l.useMemo)(()=>({checked:q,disabled:$,hover:et,focus:Z,active:ea,autofocus:z,changing:X}),[q,et,Z,ea,$,X,z]),en=(0,x.mergeProps)({id:S,ref:F,role:"switch",type:(0,d.useResolveButtonType)(e,L),tabIndex:-1===e.tabIndex?0:null!=(k=e.tabIndex)?k:0,"aria-checked":q,"aria-labelledby":Q,"aria-describedby":J,disabled:$||void 0,autoFocus:z,onClick:W,onKeyUp:U,onKeyPress:Y},ee,er,el),es=(0,l.useCallback)(()=>{if(void 0!==A)return null==H?void 0:H(A)},[H,A]),ei=(0,x.useRender)();return l.default.createElement(l.default.Fragment,null,null!=T&&l.default.createElement(g.FormFields,{disabled:$,data:{[T]:P||"on"},overrides:{type:"checkbox",checked:q},form:_,onReset:es}),ei({ourProps:en,theirProps:R,slot:eo,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var t;let[r,a]=(0,l.useState)(null),[o,n]=(0,v.useLabels)(),[s,i]=(0,b.useDescriptions)(),c=(0,l.useMemo)(()=>({switch:r,setSwitch:a}),[r,a]),d=(0,x.useRender)();return l.default.createElement(i,{name:"Switch.Description",value:s},l.default.createElement(n,{name:"Switch.Label",value:o,props:{htmlFor:null==(t=c.switch)?void 0:t.id,onClick(e){r&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),r.click(),r.focus({preventScroll:!0}))}}},l.default.createElement(w.Provider,{value:c},d({ourProps:{},theirProps:e,slot:{},defaultTag:k,name:"Switch.Group"}))))},Label:v.Label,Description:b.Description});var j=e.i(888288),N=e.i(95779),S=e.i(444755),$=e.i(673706),M=e.i(829087);let E=(0,$.makeClassName)("Switch"),O=l.default.forwardRef((e,r)=>{let{checked:a,defaultChecked:o=!1,onChange:n,color:s,name:i,error:c,errorMessage:d,disabled:u,required:m,tooltip:g,id:p}=e,f=(0,t.__rest)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),h={bgColor:s?(0,$.getColorClassNames)(s,N.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:s?(0,$.getColorClassNames)(s,N.colorPalette.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[x,b]=(0,j.default)(o,a),[y,v]=(0,l.useState)(!1),{tooltipProps:w,getReferenceProps:k}=(0,M.useTooltip)(300);return l.default.createElement("div",{className:"flex flex-row items-center justify-start"},l.default.createElement(M.default,Object.assign({text:g},w)),l.default.createElement("div",Object.assign({ref:(0,$.mergeRefs)([r,w.refs.setReference]),className:(0,S.tremorTwMerge)(E("root"),"flex flex-row relative h-5")},f,k),l.default.createElement("input",{type:"checkbox",className:(0,S.tremorTwMerge)(E("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:i,required:m,checked:x,onChange:e=>{e.preventDefault()}}),l.default.createElement(C,{checked:x,onChange:e=>{b(e),null==n||n(e)},disabled:u,className:(0,S.tremorTwMerge)(E("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:()=>v(!0),onBlur:()=>v(!1),id:p},l.default.createElement("span",{className:(0,S.tremorTwMerge)(E("sr-only"),"sr-only")},"Switch ",x?"on":"off"),l.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("background"),x?h.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.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("round"),x?(0,S.tremorTwMerge)(h.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",y?(0,S.tremorTwMerge)("ring-2",h.ringColor):"")}))),c&&d?l.default.createElement("p",{className:(0,S.tremorTwMerge)(E("errorMessage"),"text-sm text-red-500 mt-1 ")},d):null)});O.displayName="Switch",e.s(["Switch",()=>O],793130)},158392,419470,e=>{"use strict";var t=e.i(843476),r=e.i(779241);let a={ttl:3600,lowest_latency_buffer:0},l=({routingStrategyArgs:e})=>{let l={ttl:"Sliding window to look back over when calculating the average latency of a deployment. Default - 1 hour (in seconds).",lowest_latency_buffer:"Shuffle between deployments within this % of the lowest latency. Default - 0 (i.e. always pick lowest latency)."};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Latency-Based Configuration"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Fine-tune latency-based routing behavior"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e||a).map(([e,a])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:e.replace(/_/g," ")}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l[e]||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:"object"==typeof a?JSON.stringify(a,null,2):a?.toString(),className:"font-mono text-sm w-full"})]})},e))})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"})]})},o=({routerSettings:e,routerFieldsMetadata:a})=>(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Reliability & Retries"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure retry logic and failure handling"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e).filter(([e,t])=>"fallbacks"!=e&&"context_window_fallbacks"!=e&&"routing_strategy_args"!=e&&"routing_strategy"!=e&&"enable_tag_filtering"!=e).map(([e,l])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:a[e]?.ui_field_name||e}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:a[e]?.field_description||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:null==l||"null"===l?"":"object"==typeof l?JSON.stringify(l,null,2):l?.toString()||"",placeholder:"—",className:"font-mono text-sm w-full"})]})},e))})]});var n=e.i(199133);let s=({selectedStrategy:e,availableStrategies:r,routingStrategyDescriptions:a,routerFieldsMetadata:l,onStrategyChange:o})=>(0,t.jsxs)("div",{className:"space-y-2 max-w-3xl",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:l.routing_strategy?.ui_field_name||"Routing Strategy"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l.routing_strategy?.field_description||""})]}),(0,t.jsx)("div",{className:"routing-strategy-select max-w-3xl",children:(0,t.jsx)(n.Select,{value:e,onChange:o,style:{width:"100%"},size:"large",children:r.map(e=>(0,t.jsx)(n.Select.Option,{value:e,label:e,children:(0,t.jsxs)("div",{className:"flex flex-col gap-0.5 py-1",children:[(0,t.jsx)("span",{className:"font-mono text-sm font-medium",children:e}),a[e]&&(0,t.jsx)("span",{className:"text-xs text-gray-500 font-normal",children:a[e]})]})},e))})})]});var i=e.i(793130);let c=({enabled:e,routerFieldsMetadata:r,onToggle:a})=>(0,t.jsx)("div",{className:"space-y-3 max-w-3xl",children:(0,t.jsxs)("div",{className:"flex items-start justify-between",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:r.enable_tag_filtering?.ui_field_name||"Enable Tag Filtering"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500 mt-0.5",children:[r.enable_tag_filtering?.field_description||"",r.enable_tag_filtering?.link&&(0,t.jsxs)(t.Fragment,{children:[" ",(0,t.jsx)("a",{href:r.enable_tag_filtering.link,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline",children:"Learn more"})]})]})]}),(0,t.jsx)(i.Switch,{checked:e,onChange:a,className:"ml-4"})]})});e.s(["default",0,({value:e,onChange:r,routerFieldsMetadata:a,availableRoutingStrategies:n,routingStrategyDescriptions:i})=>(0,t.jsxs)("div",{className:"w-full space-y-8 py-2",children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Routing Settings"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure how requests are routed to deployments"})]}),n.length>0&&(0,t.jsx)(s,{selectedStrategy:e.selectedStrategy||e.routerSettings.routing_strategy||null,availableStrategies:n,routingStrategyDescriptions:i,routerFieldsMetadata:a,onStrategyChange:t=>{r({...e,selectedStrategy:t})}}),(0,t.jsx)(c,{enabled:e.enableTagFiltering,routerFieldsMetadata:a,onToggle:t=>{r({...e,enableTagFiltering:t})}})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),"latency-based-routing"===e.selectedStrategy&&(0,t.jsx)(l,{routingStrategyArgs:e.routerSettings.routing_strategy_args}),(0,t.jsx)(o,{routerSettings:e.routerSettings,routerFieldsMetadata:a})]})],158392);var d=e.i(994388),u=e.i(998573),m=e.i(653496),g=e.i(107233),p=e.i(271645),f=e.i(592968),h=e.i(361653),h=h;let x=(0,e.i(475254).default)("arrow-down",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var b=e.i(37727);function y({group:e,onChange:r,availableModels:a,maxFallbacks:l}){let o=a.filter(t=>t!==e.primaryModel),s=e.fallbackModels.length{let a=[...e.fallbackModels];a.includes(t)&&(a=a.filter(e=>e!==t)),r({...e,primaryModel:t,fallbackModels:a})},showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase()),options:a.map(e=>({label:e,value:e}))}),!e.primaryModel&&(0,t.jsxs)("div",{className:"mt-2 flex items-center gap-2 text-amber-600 text-xs bg-amber-50 p-2 rounded",children:[(0,t.jsx)(h.default,{className:"w-4 h-4"}),(0,t.jsx)("span",{children:"Select a model to begin configuring fallbacks"})]})]}),(0,t.jsx)("div",{className:"flex items-center justify-center -my-4 z-10",children:(0,t.jsxs)("div",{className:"bg-indigo-50 text-indigo-500 px-4 py-1 rounded-full text-xs font-bold border border-indigo-100 flex items-center gap-2 shadow-sm",children:[(0,t.jsx)(x,{className:"w-4 h-4"}),"IF FAILS, TRY..."]})}),(0,t.jsxs)("div",{className:`transition-opacity duration-300 ${!e.primaryModel?"opacity-50 pointer-events-none":"opacity-100"}`,children:[(0,t.jsxs)("label",{className:"block text-sm font-semibold text-gray-700 mb-2",children:["Fallback Chain ",(0,t.jsx)("span",{className:"text-red-500",children:"*"}),(0,t.jsxs)("span",{className:"text-xs text-gray-500 font-normal ml-2",children:["(Max ",l," fallbacks at a time)"]})]}),(0,t.jsxs)("div",{className:"bg-gray-50 rounded-xl p-4 border border-gray-200",children:[(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(n.Select,{mode:"multiple",className:"w-full",size:"large",placeholder:s?"Select fallback models to add...":`Maximum ${l} fallbacks reached`,value:e.fallbackModels,onChange:t=>{let a=t.slice(0,l);r({...e,fallbackModels:a})},disabled:!e.primaryModel,options:o.map(e=>({label:e,value:e})),optionRender:(r,a)=>{let l=e.fallbackModels.includes(r.value),o=l?e.fallbackModels.indexOf(r.value)+1:null;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[l&&null!==o&&(0,t.jsx)("span",{className:"flex items-center justify-center w-5 h-5 rounded bg-indigo-100 text-indigo-600 text-xs font-bold",children:o}),(0,t.jsx)("span",{children:r.label})]})},maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(f.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})}),showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase())}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1 ml-1",children:s?`Search and select multiple models. Selected models will appear below in order. (${e.fallbackModels.length}/${l} used)`:`Maximum ${l} fallbacks reached. Remove some to add more.`})]}),(0,t.jsx)("div",{className:"space-y-2 min-h-[100px]",children:0===e.fallbackModels.length?(0,t.jsxs)("div",{className:"h-32 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)("span",{className:"text-sm",children:"No fallback models selected"}),(0,t.jsx)("span",{className:"text-xs mt-1",children:"Add models from the dropdown above"})]}):e.fallbackModels.map((a,l)=>(0,t.jsxs)("div",{className:"group flex items-center justify-between p-3 bg-white rounded-lg border border-gray-200 hover:border-indigo-300 hover:shadow-sm transition-all",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex items-center justify-center w-6 h-6 rounded bg-gray-100 text-gray-400 group-hover:text-indigo-500 group-hover:bg-indigo-50",children:(0,t.jsx)("span",{className:"text-xs font-bold",children:l+1})}),(0,t.jsx)("div",{children:(0,t.jsx)("span",{className:"font-medium text-gray-800",children:a})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>{let t;return t=e.fallbackModels.filter((e,t)=>t!==l),void r({...e,fallbackModels:t})},className:"opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500 p-1",children:(0,t.jsx)(b.X,{className:"w-4 h-4"})})]},`${a}-${l}`))})]})]})]})}function v({groups:e,onGroupsChange:r,availableModels:a,maxFallbacks:l=10,maxGroups:o=5}){let[n,s]=(0,p.useState)(e.length>0?e[0].id:"1");(0,p.useEffect)(()=>{e.length>0?e.some(e=>e.id===n)||s(e[0].id):s("1")},[e]);let i=()=>{if(e.length>=o)return;let t=Date.now().toString();r([...e,{id:t,primaryModel:null,fallbackModels:[]}]),s(t)},c=t=>{r(e.map(e=>e.id===t.id?t:e))},f=e.map((r,o)=>{let n=r.primaryModel?r.primaryModel:`Group ${o+1}`;return{key:r.id,label:n,closable:e.length>1,children:(0,t.jsx)(y,{group:r,onChange:c,availableModels:a,maxFallbacks:l})}});return 0===e.length?(0,t.jsxs)("div",{className:"text-center py-12 bg-gray-50 rounded-lg border border-dashed border-gray-300",children:[(0,t.jsx)("p",{className:"text-gray-500 mb-4",children:"No fallback groups configured"}),(0,t.jsx)(d.Button,{variant:"primary",onClick:i,icon:()=>(0,t.jsx)(g.Plus,{className:"w-4 h-4"}),children:"Create First Group"})]}):(0,t.jsx)(m.Tabs,{type:"editable-card",activeKey:n,onChange:s,onEdit:(t,a)=>{"add"===a?i():"remove"===a&&e.length>1&&(t=>{if(1===e.length)return u.message.warning("At least one group is required");let a=e.filter(e=>e.id!==t);r(a),n===t&&a.length>0&&s(a[a.length-1].id)})(t)},items:f,className:"fallback-tabs",tabBarStyle:{marginBottom:0},hideAdd:e.length>=o})}e.s(["FallbackSelectionForm",()=>v],419470)}]); \ No newline at end of file + `]:{[`&:hover ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"}}},{[t]:{"&-indeterminate":{"&":{[`${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${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 ${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${e.colorPrimary}`}}}}},{[`${l}-disabled`]:{cursor:"not-allowed"},[`${t}-disabled`]:{[`&, ${t}-input`]:{cursor:"not-allowed",pointerEvents:"none"},[`${t}-inner`]:{background:e.colorBgContainerDisabled,borderColor:e.colorBorder,"&:after":{borderColor:e.colorTextDisabled}},"&:after":{display:"none"},"& + span":{color:e.colorTextDisabled},[`&${t}-indeterminate ${t}-inner::after`]:{background:e.colorTextDisabled}}}]})((0,o.mergeToken)(t,{checkboxCls:`.${e}`,checkboxSize:t.controlInteractiveSize}))}let s=(0,l.genStyleHooks)("Checkbox",(e,{prefixCls:t})=>[n(t,e)]);e.s(["default",0,s,"getStyle",()=>n],236836)},374276,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(91874),l=e.i(611935),o=e.i(121872),n=e.i(26905),s=e.i(242064),i=e.i(937328),c=e.i(321883),d=e.i(62139),u=e.i(421512),m=e.i(236836),g=e.i(681216),p=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let f=t.forwardRef((e,f)=>{var h;let{prefixCls:x,className:b,rootClassName:y,children:v,indeterminate:w=!1,style:k,onMouseEnter:C,onMouseLeave:j,skipGroup:N=!1,disabled:S}=e,$=p(e,["prefixCls","className","rootClassName","children","indeterminate","style","onMouseEnter","onMouseLeave","skipGroup","disabled"]),{getPrefixCls:M,direction:E,checkbox:O}=t.useContext(s.ConfigContext),T=t.useContext(u.default),{isFormItemInput:P}=t.useContext(d.FormItemInputContext),_=t.useContext(i.default),z=null!=(h=(null==T?void 0:T.disabled)||S)?h:_,R=t.useRef($.value),I=t.useRef(null),L=(0,l.composeRef)(f,I);t.useEffect(()=>{null==T||T.registerValue($.value)},[]),t.useEffect(()=>{if(!N)return $.value!==R.current&&(null==T||T.cancelValue(R.current),null==T||T.registerValue($.value),R.current=$.value),()=>null==T?void 0:T.cancelValue($.value)},[$.value]),t.useEffect(()=>{var e;(null==(e=I.current)?void 0:e.input)&&(I.current.input.indeterminate=w)},[w]);let D=M("checkbox",x),B=(0,c.default)(D),[F,A,q]=(0,m.default)(D,B),H=Object.assign({},$);T&&!N&&(H.onChange=(...e)=>{$.onChange&&$.onChange.apply($,e),T.toggleOption&&T.toggleOption({label:v,value:$.value})},H.name=T.name,H.checked=T.value.includes($.value));let G=(0,r.default)(`${D}-wrapper`,{[`${D}-rtl`]:"rtl"===E,[`${D}-wrapper-checked`]:H.checked,[`${D}-wrapper-disabled`]:z,[`${D}-wrapper-in-form-item`]:P},null==O?void 0:O.className,b,y,q,B,A),X=(0,r.default)({[`${D}-indeterminate`]:w},n.TARGET_CLS,A),[V,K]=(0,g.default)(H.onClick);return F(t.createElement(o.default,{component:"Checkbox",disabled:z},t.createElement("label",{className:G,style:Object.assign(Object.assign({},null==O?void 0:O.style),k),onMouseEnter:C,onMouseLeave:j,onClick:V},t.createElement(a.default,Object.assign({},H,{onClick:K,prefixCls:D,className:X,disabled:z,ref:L})),null!=v&&t.createElement("span",{className:`${D}-label`},v))))});var h=e.i(8211),x=e.i(529681),b=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let y=t.forwardRef((e,a)=>{let{defaultValue:l,children:o,options:n=[],prefixCls:i,className:d,rootClassName:g,style:p,onChange:y}=e,v=b(e,["defaultValue","children","options","prefixCls","className","rootClassName","style","onChange"]),{getPrefixCls:w,direction:k}=t.useContext(s.ConfigContext),[C,j]=t.useState(v.value||l||[]),[N,S]=t.useState([]);t.useEffect(()=>{"value"in v&&j(v.value||[])},[v.value]);let $=t.useMemo(()=>n.map(e=>"string"==typeof e||"number"==typeof e?{label:e,value:e}:e),[n]),M=e=>{S(t=>t.filter(t=>t!==e))},E=e=>{S(t=>[].concat((0,h.default)(t),[e]))},O=e=>{let t=C.indexOf(e.value),r=(0,h.default)(C);-1===t?r.push(e.value):r.splice(t,1),"value"in v||j(r),null==y||y(r.filter(e=>N.includes(e)).sort((e,t)=>$.findIndex(t=>t.value===e)-$.findIndex(e=>e.value===t)))},T=w("checkbox",i),P=`${T}-group`,_=(0,c.default)(T),[z,R,I]=(0,m.default)(T,_),L=(0,x.default)(v,["value","disabled"]),D=n.length?$.map(e=>t.createElement(f,{prefixCls:T,key:e.value.toString(),disabled:"disabled"in e?e.disabled:v.disabled,value:e.value,checked:C.includes(e.value),onChange:e.onChange,className:(0,r.default)(`${P}-item`,e.className),style:e.style,title:e.title,id:e.id,required:e.required},e.label)):o,B=t.useMemo(()=>({toggleOption:O,value:C,disabled:v.disabled,name:v.name,registerValue:E,cancelValue:M}),[O,C,v.disabled,v.name,E,M]),F=(0,r.default)(P,{[`${P}-rtl`]:"rtl"===k},d,g,I,_,R);return z(t.createElement("div",Object.assign({className:F,style:p},L,{ref:a}),t.createElement(u.default.Provider,{value:B},D)))});f.Group=y,f.__ANT_CHECKBOX=!0,e.s(["default",0,f],374276)},536916,e=>{"use strict";var t=e.i(374276);e.s(["Checkbox",()=>t.default])},292639,e=>{"use strict";var t=e.i(764205),r=e.i(266027);let a=(0,e.i(243652).createQueryKeys)("uiSettings");e.s(["useUISettings",0,()=>(0,r.useQuery)({queryKey:a.list({}),queryFn:async()=>await (0,t.getUiSettings)(),staleTime:36e5,gcTime:36e5})])},250980,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlusCircleIcon",0,r],250980)},502547,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 5l7 7-7 7"}))});e.s(["ChevronRightIcon",0,r],502547)},988297,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"}))});e.s(["PlusIcon",0,r],988297)},797672,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"}))});e.s(["PencilIcon",0,r],797672)},992619,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(779241),l=e.i(599724),o=e.i(199133),n=e.i(983561),s=e.i(689020);e.s(["default",0,({accessToken:e,value:i,placeholder:c="Select a Model",onChange:d,disabled:u=!1,style:m,className:g,showLabel:p=!0,labelText:f="Select Model"})=>{let[h,x]=(0,r.useState)(i),[b,y]=(0,r.useState)(!1),[v,w]=(0,r.useState)([]),k=(0,r.useRef)(null);return(0,r.useEffect)(()=>{x(i)},[i]),(0,r.useEffect)(()=>{e&&(async()=>{try{let t=await (0,s.fetchAvailableModels)(e);console.log("Fetched models for selector:",t),t.length>0&&w(t)}catch(e){console.error("Error fetching model info:",e)}})()},[e]),(0,t.jsxs)("div",{children:[p&&(0,t.jsxs)(l.Text,{className:"font-medium block mb-2 text-gray-700 flex items-center",children:[(0,t.jsx)(n.RobotOutlined,{className:"mr-2"})," ",f]}),(0,t.jsx)(o.Select,{value:h,placeholder:c,onChange:e=>{"custom"===e?(y(!0),x(void 0)):(y(!1),x(e),d&&d(e))},options:[...Array.from(new Set(v.map(e=>e.model_group))).map((e,t)=>({value:e,label:e,key:t})),{value:"custom",label:"Enter custom model",key:"custom"}],style:{width:"100%",...m},showSearch:!0,className:`rounded-md ${g||""}`,disabled:u}),b&&(0,t.jsx)(a.TextInput,{className:"mt-2",placeholder:"Enter custom model name",onValueChange:e=>{k.current&&clearTimeout(k.current),k.current=setTimeout(()=>{x(e),d&&d(e)},500)},disabled:u})]})}])},409797,e=>{"use strict";var t=e.i(631171);e.s(["ChevronDownIcon",()=>t.default])},91739,e=>{"use strict";var t=e.i(544195);e.s(["Radio",()=>t.default])},500727,696609,531516,e=>{"use strict";var t=e.i(266027),r=e.i(243652),a=e.i(764205),l=e.i(135214);let o=(0,r.createQueryKeys)("mcpServers");e.s(["useMCPServers",0,e=>{let{accessToken:r}=(0,l.default)();return(0,t.useQuery)({queryKey:o.list(e?{filters:{teamId:e}}:void 0),queryFn:async()=>await (0,a.fetchMCPServers)(r,e),enabled:!!r})}],500727);var n=e.i(843476),s=e.i(271645),i=e.i(536916),c=e.i(599724),d=e.i(409797),u=e.i(246349),u=u;let m=/\b(delete|remove|destroy|purge|drop|erase|unlink)\b/i,g=/\b(create|add|insert|new|post|submit|register|make|generate|write|upload)\b/i,p=/\b(update|edit|modify|change|patch|put|set|rename|move|transform)\b/i,f=/\b(get|read|list|fetch|search|find|query|retrieve|show|view|check|describe|info)\b/i;function h(e,t=""){let r=e.toLowerCase();if(f.test(r))return"read";if(m.test(r))return"delete";if(p.test(r))return"update";if(g.test(r))return"create";if(t){let e=t.toLowerCase();if(f.test(e))return"read";if(m.test(e))return"delete";if(p.test(e))return"update";if(g.test(e))return"create"}return"unknown"}function x(e){let t={read:[],create:[],update:[],delete:[],unknown:[]};for(let r of e)t[h(r.name,r.description)].push(r);return t}let b={read:{label:"Read",description:"Safe operations — fetch, list, search. No side effects.",risk:"low"},create:{label:"Create",description:"Add new resources — insert, upload, register.",risk:"medium"},update:{label:"Update",description:"Modify existing resources — edit, patch, rename.",risk:"medium"},delete:{label:"Delete",description:"Destructive operations — remove, purge, destroy.",risk:"high"},unknown:{label:"Other",description:"Operations that could not be automatically classified.",risk:"unknown"}};e.s(["CRUD_GROUP_META",0,b,"classifyToolOp",()=>h,"groupToolsByCrud",()=>x],696609);let y=["read","create","update","delete","unknown"],v={low:"bg-green-100 text-green-800",medium:"bg-yellow-100 text-yellow-800",high:"bg-red-100 text-red-800 font-semibold",unknown:"bg-gray-100 text-gray-700"},w={read:"border-green-200",create:"border-blue-200",update:"border-yellow-200",delete:"border-red-300",unknown:"border-gray-200"},k={read:"bg-green-50",create:"bg-blue-50",update:"bg-yellow-50",delete:"bg-red-50",unknown:"bg-gray-50"};e.s(["default",0,({tools:e,value:t,onChange:r,readOnly:a=!1,searchFilter:l=""})=>{let[o,m]=(0,s.useState)({read:!1,create:!1,update:!1,delete:!1,unknown:!0}),g=(0,s.useMemo)(()=>x(e),[e]),p=(0,s.useMemo)(()=>new Set(void 0===t?e.map(e=>e.name):t),[t,e]),f=e=>{if(a)return;let t=new Set(p);t.has(e)?t.delete(e):t.add(e),r(Array.from(t))};return 0===e.length?null:(0,n.jsx)("div",{className:"space-y-3",children:y.map(e=>{let t,s=g[e];if(0===s.length)return null;if(l){let e=l.toLowerCase();if(!s.some(t=>t.name.toLowerCase().includes(e)||(t.description??"").toLowerCase().includes(e)))return null}let h=b[e],x=(t=g[e]).length>0&&t.every(e=>p.has(e.name)),y=(e=>{let t=g[e];if(0===t.length)return!1;let r=t.filter(e=>p.has(e.name)).length;return r>0&&r{m(t=>({...t,[e]:!t[e]}))},children:[C?(0,n.jsx)(u.default,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}):(0,n.jsx)(d.ChevronDownIcon,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}),(0,n.jsx)("span",{className:"font-semibold text-gray-900 text-sm",children:h.label}),(0,n.jsx)("span",{className:`text-xs px-2 py-0.5 rounded-full ${v[h.risk]}`,children:"high"===h.risk?"High Risk":"medium"===h.risk?"Medium Risk":"low"===h.risk?"Safe":"Unclassified"}),(0,n.jsxs)("span",{className:"text-xs text-gray-500 ml-1",children:[s.filter(e=>p.has(e.name)).length,"/",s.length," allowed"]})]}),!a&&(0,n.jsxs)("div",{className:"flex items-center gap-2 ml-4",children:[(0,n.jsx)(c.Text,{className:"text-xs text-gray-500",children:x?"All on":y?"Partial":"All off"}),(0,n.jsx)(i.Checkbox,{checked:x,indeterminate:y,onChange:t=>((e,t)=>{if(a)return;let l=new Set(p);for(let r of g[e])t?l.add(r.name):l.delete(r.name);r(Array.from(l))})(e,t.target.checked),onClick:e=>e.stopPropagation()})]})]}),!C&&(0,n.jsx)("div",{className:"px-4 pt-2 pb-1 text-xs text-gray-500 bg-white border-b border-gray-100",children:h.description}),!C&&(0,n.jsx)("div",{className:"bg-white divide-y divide-gray-50",children:s.filter(e=>!l||e.name.toLowerCase().includes(l.toLowerCase())||(e.description??"").toLowerCase().includes(l.toLowerCase())).map(e=>{let t,r=(t=e.name,p.has(t));return(0,n.jsxs)("div",{className:`flex items-start gap-3 px-4 py-2.5 transition-colors hover:bg-gray-50 ${!a?"cursor-pointer":""} ${r?"":"opacity-60"}`,onClick:()=>f(e.name),children:[(0,n.jsx)(i.Checkbox,{checked:r,onChange:()=>f(e.name),disabled:a,onClick:e=>e.stopPropagation()}),(0,n.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,n.jsx)(c.Text,{className:"font-medium text-gray-900 text-sm",children:e.name}),e.description&&(0,n.jsx)(c.Text,{className:"text-xs text-gray-500 mt-0.5 leading-snug",children:e.description})]}),(0,n.jsx)("span",{className:`text-xs px-1.5 py-0.5 rounded flex-shrink-0 ${r?"bg-green-100 text-green-700":"bg-gray-100 text-gray-500"}`,children:r?"on":"off"})]},e.name)})})]},e)})})}],531516)},361653,e=>{"use strict";let t=(0,e.i(475254).default)("circle-alert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);e.s(["default",()=>t])},603908,e=>{"use strict";let t=(0,e.i(475254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);e.s(["default",()=>t])},841947,e=>{"use strict";let t=(0,e.i(475254).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["default",()=>t])},793130,e=>{"use strict";var t=e.i(290571),r=e.i(429427),a=e.i(371330),l=e.i(271645),o=e.i(394487),n=e.i(503269),s=e.i(214520),i=e.i(746725),c=e.i(914189),d=e.i(144279),u=e.i(294316),m=e.i(601893),g=e.i(140721),p=e.i(942803),f=e.i(233538),h=e.i(694421),x=e.i(700020),b=e.i(35889),y=e.i(998348),v=e.i(722678);let w=(0,l.createContext)(null);w.displayName="GroupContext";let k=l.Fragment,C=Object.assign((0,x.forwardRefWithAs)(function(e,t){var k;let C=(0,l.useId)(),j=(0,p.useProvidedId)(),N=(0,m.useDisabled)(),{id:S=j||`headlessui-switch-${C}`,disabled:$=N||!1,checked:M,defaultChecked:E,onChange:O,name:T,value:P,form:_,autoFocus:z=!1,...R}=e,I=(0,l.useContext)(w),[L,D]=(0,l.useState)(null),B=(0,l.useRef)(null),F=(0,u.useSyncRefs)(B,t,null===I?null:I.setSwitch,D),A=(0,s.useDefaultValue)(E),[q,H]=(0,n.useControllable)(M,O,null!=A&&A),G=(0,i.useDisposables)(),[X,V]=(0,l.useState)(!1),K=(0,c.useEvent)(()=>{V(!0),null==H||H(!q),G.nextFrame(()=>{V(!1)})}),W=(0,c.useEvent)(e=>{if((0,f.isDisabledReactIssue7711)(e.currentTarget))return e.preventDefault();e.preventDefault(),K()}),U=(0,c.useEvent)(e=>{e.key===y.Keys.Space?(e.preventDefault(),K()):e.key===y.Keys.Enter&&(0,h.attemptSubmit)(e.currentTarget)}),Y=(0,c.useEvent)(e=>e.preventDefault()),Q=(0,v.useLabelledBy)(),J=(0,b.useDescribedBy)(),{isFocusVisible:Z,focusProps:ee}=(0,r.useFocusRing)({autoFocus:z}),{isHovered:et,hoverProps:er}=(0,a.useHover)({isDisabled:$}),{pressed:ea,pressProps:el}=(0,o.useActivePress)({disabled:$}),eo=(0,l.useMemo)(()=>({checked:q,disabled:$,hover:et,focus:Z,active:ea,autofocus:z,changing:X}),[q,et,Z,ea,$,X,z]),en=(0,x.mergeProps)({id:S,ref:F,role:"switch",type:(0,d.useResolveButtonType)(e,L),tabIndex:-1===e.tabIndex?0:null!=(k=e.tabIndex)?k:0,"aria-checked":q,"aria-labelledby":Q,"aria-describedby":J,disabled:$||void 0,autoFocus:z,onClick:W,onKeyUp:U,onKeyPress:Y},ee,er,el),es=(0,l.useCallback)(()=>{if(void 0!==A)return null==H?void 0:H(A)},[H,A]),ei=(0,x.useRender)();return l.default.createElement(l.default.Fragment,null,null!=T&&l.default.createElement(g.FormFields,{disabled:$,data:{[T]:P||"on"},overrides:{type:"checkbox",checked:q},form:_,onReset:es}),ei({ourProps:en,theirProps:R,slot:eo,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var t;let[r,a]=(0,l.useState)(null),[o,n]=(0,v.useLabels)(),[s,i]=(0,b.useDescriptions)(),c=(0,l.useMemo)(()=>({switch:r,setSwitch:a}),[r,a]),d=(0,x.useRender)();return l.default.createElement(i,{name:"Switch.Description",value:s},l.default.createElement(n,{name:"Switch.Label",value:o,props:{htmlFor:null==(t=c.switch)?void 0:t.id,onClick(e){r&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),r.click(),r.focus({preventScroll:!0}))}}},l.default.createElement(w.Provider,{value:c},d({ourProps:{},theirProps:e,slot:{},defaultTag:k,name:"Switch.Group"}))))},Label:v.Label,Description:b.Description});var j=e.i(888288),N=e.i(95779),S=e.i(444755),$=e.i(673706),M=e.i(829087);let E=(0,$.makeClassName)("Switch"),O=l.default.forwardRef((e,r)=>{let{checked:a,defaultChecked:o=!1,onChange:n,color:s,name:i,error:c,errorMessage:d,disabled:u,required:m,tooltip:g,id:p}=e,f=(0,t.__rest)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),h={bgColor:s?(0,$.getColorClassNames)(s,N.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:s?(0,$.getColorClassNames)(s,N.colorPalette.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[x,b]=(0,j.default)(o,a),[y,v]=(0,l.useState)(!1),{tooltipProps:w,getReferenceProps:k}=(0,M.useTooltip)(300);return l.default.createElement("div",{className:"flex flex-row items-center justify-start"},l.default.createElement(M.default,Object.assign({text:g},w)),l.default.createElement("div",Object.assign({ref:(0,$.mergeRefs)([r,w.refs.setReference]),className:(0,S.tremorTwMerge)(E("root"),"flex flex-row relative h-5")},f,k),l.default.createElement("input",{type:"checkbox",className:(0,S.tremorTwMerge)(E("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:i,required:m,checked:x,onChange:e=>{e.preventDefault()}}),l.default.createElement(C,{checked:x,onChange:e=>{b(e),null==n||n(e)},disabled:u,className:(0,S.tremorTwMerge)(E("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:()=>v(!0),onBlur:()=>v(!1),id:p},l.default.createElement("span",{className:(0,S.tremorTwMerge)(E("sr-only"),"sr-only")},"Switch ",x?"on":"off"),l.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("background"),x?h.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.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("round"),x?(0,S.tremorTwMerge)(h.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",y?(0,S.tremorTwMerge)("ring-2",h.ringColor):"")}))),c&&d?l.default.createElement("p",{className:(0,S.tremorTwMerge)(E("errorMessage"),"text-sm text-red-500 mt-1 ")},d):null)});O.displayName="Switch",e.s(["Switch",()=>O],793130)},158392,419470,e=>{"use strict";var t=e.i(843476),r=e.i(779241);let a={ttl:3600,lowest_latency_buffer:0},l=({routingStrategyArgs:e})=>{let l={ttl:"Sliding window to look back over when calculating the average latency of a deployment. Default - 1 hour (in seconds).",lowest_latency_buffer:"Shuffle between deployments within this % of the lowest latency. Default - 0 (i.e. always pick lowest latency)."};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Latency-Based Configuration"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Fine-tune latency-based routing behavior"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e||a).map(([e,a])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:e.replace(/_/g," ")}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l[e]||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:"object"==typeof a?JSON.stringify(a,null,2):a?.toString(),className:"font-mono text-sm w-full"})]})},e))})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"})]})},o=({routerSettings:e,routerFieldsMetadata:a})=>(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Reliability & Retries"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure retry logic and failure handling"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e).filter(([e,t])=>"fallbacks"!=e&&"context_window_fallbacks"!=e&&"routing_strategy_args"!=e&&"routing_strategy"!=e&&"enable_tag_filtering"!=e).map(([e,l])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:a[e]?.ui_field_name||e}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:a[e]?.field_description||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:null==l||"null"===l?"":"object"==typeof l?JSON.stringify(l,null,2):l?.toString()||"",placeholder:"—",className:"font-mono text-sm w-full"})]})},e))})]});var n=e.i(199133);let s=({selectedStrategy:e,availableStrategies:r,routingStrategyDescriptions:a,routerFieldsMetadata:l,onStrategyChange:o})=>(0,t.jsxs)("div",{className:"space-y-2 max-w-3xl",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:l.routing_strategy?.ui_field_name||"Routing Strategy"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l.routing_strategy?.field_description||""})]}),(0,t.jsx)("div",{className:"routing-strategy-select max-w-3xl",children:(0,t.jsx)(n.Select,{value:e,onChange:o,style:{width:"100%"},size:"large",children:r.map(e=>(0,t.jsx)(n.Select.Option,{value:e,label:e,children:(0,t.jsxs)("div",{className:"flex flex-col gap-0.5 py-1",children:[(0,t.jsx)("span",{className:"font-mono text-sm font-medium",children:e}),a[e]&&(0,t.jsx)("span",{className:"text-xs text-gray-500 font-normal",children:a[e]})]})},e))})})]});var i=e.i(793130);let c=({enabled:e,routerFieldsMetadata:r,onToggle:a})=>(0,t.jsx)("div",{className:"space-y-3 max-w-3xl",children:(0,t.jsxs)("div",{className:"flex items-start justify-between",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:r.enable_tag_filtering?.ui_field_name||"Enable Tag Filtering"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500 mt-0.5",children:[r.enable_tag_filtering?.field_description||"",r.enable_tag_filtering?.link&&(0,t.jsxs)(t.Fragment,{children:[" ",(0,t.jsx)("a",{href:r.enable_tag_filtering.link,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline",children:"Learn more"})]})]})]}),(0,t.jsx)(i.Switch,{checked:e,onChange:a,className:"ml-4"})]})});e.s(["default",0,({value:e,onChange:r,routerFieldsMetadata:a,availableRoutingStrategies:n,routingStrategyDescriptions:i})=>(0,t.jsxs)("div",{className:"w-full space-y-8 py-2",children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Routing Settings"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure how requests are routed to deployments"})]}),n.length>0&&(0,t.jsx)(s,{selectedStrategy:e.selectedStrategy||e.routerSettings.routing_strategy||null,availableStrategies:n,routingStrategyDescriptions:i,routerFieldsMetadata:a,onStrategyChange:t=>{r({...e,selectedStrategy:t})}}),(0,t.jsx)(c,{enabled:e.enableTagFiltering,routerFieldsMetadata:a,onToggle:t=>{r({...e,enableTagFiltering:t})}})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),"latency-based-routing"===e.selectedStrategy&&(0,t.jsx)(l,{routingStrategyArgs:e.routerSettings.routing_strategy_args}),(0,t.jsx)(o,{routerSettings:e.routerSettings,routerFieldsMetadata:a})]})],158392);var d=e.i(994388),u=e.i(998573),m=e.i(653496),g=e.i(107233),p=e.i(271645),f=e.i(592968),h=e.i(361653),h=h;let x=(0,e.i(475254).default)("arrow-down",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var b=e.i(37727);function y({group:e,onChange:r,availableModels:a,maxFallbacks:l}){let o=a.filter(t=>t!==e.primaryModel),s=e.fallbackModels.length{let a=[...e.fallbackModels];a.includes(t)&&(a=a.filter(e=>e!==t)),r({...e,primaryModel:t,fallbackModels:a})},showSearch:!0,getPopupContainer:e=>e.parentElement||document.body,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase()),options:a.map(e=>({label:e,value:e}))}),!e.primaryModel&&(0,t.jsxs)("div",{className:"mt-2 flex items-center gap-2 text-amber-600 text-xs bg-amber-50 p-2 rounded",children:[(0,t.jsx)(h.default,{className:"w-4 h-4"}),(0,t.jsx)("span",{children:"Select a model to begin configuring fallbacks"})]})]}),(0,t.jsx)("div",{className:"flex items-center justify-center -my-4 z-10",children:(0,t.jsxs)("div",{className:"bg-indigo-50 text-indigo-500 px-4 py-1 rounded-full text-xs font-bold border border-indigo-100 flex items-center gap-2 shadow-sm",children:[(0,t.jsx)(x,{className:"w-4 h-4"}),"IF FAILS, TRY..."]})}),(0,t.jsxs)("div",{className:`transition-opacity duration-300 ${!e.primaryModel?"opacity-50 pointer-events-none":"opacity-100"}`,children:[(0,t.jsxs)("label",{className:"block text-sm font-semibold text-gray-700 mb-2",children:["Fallback Chain ",(0,t.jsx)("span",{className:"text-red-500",children:"*"}),(0,t.jsxs)("span",{className:"text-xs text-gray-500 font-normal ml-2",children:["(Max ",l," fallbacks at a time)"]})]}),(0,t.jsxs)("div",{className:"bg-gray-50 rounded-xl p-4 border border-gray-200",children:[(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(n.Select,{mode:"multiple",className:"w-full",size:"large",placeholder:s?"Select fallback models to add...":`Maximum ${l} fallbacks reached`,value:e.fallbackModels,onChange:t=>{let a=t.slice(0,l);r({...e,fallbackModels:a})},disabled:!e.primaryModel,getPopupContainer:e=>e.parentElement||document.body,options:o.map(e=>({label:e,value:e})),optionRender:(r,a)=>{let l=e.fallbackModels.includes(r.value),o=l?e.fallbackModels.indexOf(r.value)+1:null;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[l&&null!==o&&(0,t.jsx)("span",{className:"flex items-center justify-center w-5 h-5 rounded bg-indigo-100 text-indigo-600 text-xs font-bold",children:o}),(0,t.jsx)("span",{children:r.label})]})},maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(f.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})}),showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase())}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1 ml-1",children:s?`Search and select multiple models. Selected models will appear below in order. (${e.fallbackModels.length}/${l} used)`:`Maximum ${l} fallbacks reached. Remove some to add more.`})]}),(0,t.jsx)("div",{className:"space-y-2 min-h-[100px]",children:0===e.fallbackModels.length?(0,t.jsxs)("div",{className:"h-32 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)("span",{className:"text-sm",children:"No fallback models selected"}),(0,t.jsx)("span",{className:"text-xs mt-1",children:"Add models from the dropdown above"})]}):e.fallbackModels.map((a,l)=>(0,t.jsxs)("div",{className:"group flex items-center justify-between p-3 bg-white rounded-lg border border-gray-200 hover:border-indigo-300 hover:shadow-sm transition-all",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex items-center justify-center w-6 h-6 rounded bg-gray-100 text-gray-400 group-hover:text-indigo-500 group-hover:bg-indigo-50",children:(0,t.jsx)("span",{className:"text-xs font-bold",children:l+1})}),(0,t.jsx)("div",{children:(0,t.jsx)("span",{className:"font-medium text-gray-800",children:a})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>{let t;return t=e.fallbackModels.filter((e,t)=>t!==l),void r({...e,fallbackModels:t})},className:"opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500 p-1",children:(0,t.jsx)(b.X,{className:"w-4 h-4"})})]},`${a}-${l}`))})]})]})]})}function v({groups:e,onGroupsChange:r,availableModels:a,maxFallbacks:l=10,maxGroups:o=5}){let[n,s]=(0,p.useState)(e.length>0?e[0].id:"1");(0,p.useEffect)(()=>{e.length>0?e.some(e=>e.id===n)||s(e[0].id):s("1")},[e]);let i=()=>{if(e.length>=o)return;let t=Date.now().toString();r([...e,{id:t,primaryModel:null,fallbackModels:[]}]),s(t)},c=t=>{r(e.map(e=>e.id===t.id?t:e))},f=e.map((r,o)=>{let n=r.primaryModel?r.primaryModel:`Group ${o+1}`;return{key:r.id,label:n,closable:e.length>1,children:(0,t.jsx)(y,{group:r,onChange:c,availableModels:a,maxFallbacks:l})}});return 0===e.length?(0,t.jsxs)("div",{className:"text-center py-12 bg-gray-50 rounded-lg border border-dashed border-gray-300",children:[(0,t.jsx)("p",{className:"text-gray-500 mb-4",children:"No fallback groups configured"}),(0,t.jsx)(d.Button,{variant:"primary",onClick:i,icon:()=>(0,t.jsx)(g.Plus,{className:"w-4 h-4"}),children:"Create First Group"})]}):(0,t.jsx)(m.Tabs,{type:"editable-card",activeKey:n,onChange:s,onEdit:(t,a)=>{"add"===a?i():"remove"===a&&e.length>1&&(t=>{if(1===e.length)return u.message.warning("At least one group is required");let a=e.filter(e=>e.id!==t);r(a),n===t&&a.length>0&&s(a[a.length-1].id)})(t)},items:f,className:"fallback-tabs",tabBarStyle:{marginBottom:0},hideAdd:e.length>=o})}e.s(["FallbackSelectionForm",()=>v],419470)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/0adb91ab5f3140d5.js b/litellm/proxy/_experimental/out/_next/static/chunks/67ddb5107368a659.js similarity index 95% rename from litellm/proxy/_experimental/out/_next/static/chunks/0adb91ab5f3140d5.js rename to litellm/proxy/_experimental/out/_next/static/chunks/67ddb5107368a659.js index a8ed71a7b2..56a8ade942 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/0adb91ab5f3140d5.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/67ddb5107368a659.js @@ -1,3 +1,3 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,894660,283086,195116,e=>{"use strict";var t=e.i(801312);e.s(["LeftOutlined",()=>t.default],894660);var s=e.i(475254);let a=(0,s.default)("sparkles",[["path",{d:"M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z",key:"4pj2yx"}],["path",{d:"M20 3v4",key:"1olli1"}],["path",{d:"M22 5h-4",key:"1gvqau"}],["path",{d:"M4 17v2",key:"vumght"}],["path",{d:"M5 18H3",key:"zchphs"}]]);e.s(["Sparkles",()=>a],283086);let l=(0,s.default)("wrench",[["path",{d:"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z",key:"cbrjhi"}]]);e.s(["Wrench",()=>l],195116)},97859,e=>{"use strict";e.s(["AGENT_CALL_TYPES",0,["asend_message"],"ERROR_CODE_OPTIONS",0,[{label:"400 - Bad Request",value:"400"},{label:"401 - Invalid Authentication",value:"401"},{label:"403 - Permission Denied",value:"403"},{label:"404 - Not Found",value:"404"},{label:"408 - Request Timeout",value:"408"},{label:"422 - Unprocessable Entity",value:"422"},{label:"429 - Rate Limited",value:"429"},{label:"500 - Internal Server Error",value:"500"},{label:"502 - Bad Gateway",value:"502"},{label:"503 - Service Unavailable",value:"503"},{label:"529 - Overloaded",value:"529"}],"MCP_CALL_TYPES",0,["call_mcp_tool","list_mcp_tools"],"QUICK_SELECT_OPTIONS",0,[{label:"Last 15 Minutes",value:15,unit:"minutes"},{label:"Last Hour",value:1,unit:"hours"},{label:"Last 4 Hours",value:4,unit:"hours"},{label:"Last 24 Hours",value:24,unit:"hours"},{label:"Last 7 Days",value:7,unit:"days"}]])},257486,624001,207066,337767,237062,e=>{"use strict";var t=e.i(97859);function s(e,s){let a=(s||"").trim();if(t.MCP_CALL_TYPES.includes(e))return a.replace(/^mcp:\s*/i,"").split("/").pop()||a||"mcp_tool";let l=(a.split("/").pop()||a).replace(/-20\d{6}.*$/i,"").replace(/:.*$/,""),r=l.match(/claude-[a-z0-9-]+/i);return r?r[0]:l||"llm_call"}e.s(["getEventDisplayName",()=>s],257486);var a=e.i(843476),l=e.i(464571),r=e.i(770914),i=e.i(262218),n=e.i(592968),o=e.i(898586),d=e.i(149192),c=e.i(536591);e.s(["UpOutlined",()=>c.default],624001);var c=c,m=e.i(755151),x=e.i(166540),u=e.i(916925);let p="16px 24px",h="Escape",g="monospace",f="#f0f0f0",y="#fff";e.s(["API_BASE_MAX_WIDTH",0,200,"COLOR_BACKGROUND",0,y,"COLOR_BG_LIGHT",0,"#fafafa","COLOR_BORDER",0,f,"DEFAULT_MAX_WIDTH",0,180,"DRAWER_CONTENT_PADDING",0,"24px","DRAWER_HEADER_PADDING",0,p,"DRAWER_WIDTH",0,"60%","FONT_FAMILY_MONO",0,g,"FONT_SIZE_HEADER",0,16,"FONT_SIZE_MEDIUM",0,13,"FONT_SIZE_SMALL",0,12,"JSON_MAX_HEIGHT",0,400,"KEY_ESCAPE",0,h,"KEY_J_LOWER",0,"j","KEY_J_UPPER",0,"J","KEY_K_LOWER",0,"k","KEY_K_UPPER",0,"K","METADATA_MAX_HEIGHT",0,300,"SPACING_LARGE",0,12,"SPACING_MEDIUM",0,8,"SPACING_SMALL",0,4,"SPACING_XLARGE",0,16,"TAB_REQUEST",0,"request","TAB_RESPONSE",0,"response"],207066);let{Text:j}=o.Typography;function b({log:e,onClose:t,onPrevious:s,onNext:l,statusLabel:r,statusColor:i,environment:n}){let o=e.custom_llm_provider||"",d=o?(0,u.getProviderLogoAndName)(o):null;return(0,a.jsxs)("div",{style:{padding:p,borderBottom:`1px solid ${f}`,backgroundColor:y,position:"sticky",top:0,zIndex:10},children:[(0,a.jsx)(v,{model:e.model,providerLogo:d?.logo,providerName:d?.displayName}),(0,a.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:8},children:[(0,a.jsx)(_,{requestId:e.request_id}),(0,a.jsx)(N,{onPrevious:s,onNext:l,onClose:t})]}),(0,a.jsx)(w,{log:e,statusLabel:r,statusColor:i,environment:n})]})}function v({model:e,providerLogo:t,providerName:s}){return(0,a.jsxs)(r.Space,{size:8,style:{marginBottom:8},children:[t&&(0,a.jsx)("img",{src:t,alt:s||"Provider",style:{width:24,height:24},onError:e=>{e.target.style.display="none"}}),(0,a.jsxs)(r.Space,{size:8,direction:"horizontal",children:[(0,a.jsx)(j,{strong:!0,style:{fontSize:14},children:e}),s&&(0,a.jsx)(j,{type:"secondary",style:{fontSize:12},children:s})]})]})}function _({requestId:e}){return(0,a.jsx)("div",{style:{flex:1,minWidth:0},children:(0,a.jsx)(n.Tooltip,{title:e,children:(0,a.jsx)(j,{strong:!0,copyable:{text:e,tooltips:["Copy Request ID","Copied!"]},style:{fontSize:16,fontFamily:g,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",display:"block"},children:e})})})}function N({onPrevious:e,onNext:t,onClose:s}){let i={border:"1px solid #d9d9d9",borderRadius:4,padding:"0 4px",fontSize:12,fontFamily:"monospace",marginLeft:4,background:"#fafafa"};return(0,a.jsxs)(r.Space,{size:4,split:(0,a.jsx)("div",{style:{width:1,height:20,background:f}}),children:[(0,a.jsxs)(l.Button,{type:"text",size:"small",onClick:e,children:[(0,a.jsx)(c.default,{}),(0,a.jsx)("span",{style:i,children:"K"})]}),(0,a.jsxs)(l.Button,{type:"text",size:"small",onClick:t,children:[(0,a.jsx)(m.DownOutlined,{}),(0,a.jsx)("span",{style:i,children:"J"})]}),(0,a.jsx)(n.Tooltip,{title:"ESC to close",children:(0,a.jsx)(l.Button,{type:"text",icon:(0,a.jsx)(d.CloseOutlined,{}),onClick:s})})]})}function w({log:e,statusLabel:t,statusColor:s,environment:l}){return(0,a.jsxs)(r.Space,{size:12,children:[(0,a.jsx)(i.Tag,{color:s,children:t}),(0,a.jsxs)(i.Tag,{children:["Env: ",l]}),(0,a.jsxs)(r.Space,{size:8,children:[(0,a.jsx)(j,{type:"secondary",style:{fontSize:13},children:(0,x.default)(e.startTime).format("MMM D, YYYY h:mm:ss A")}),(0,a.jsxs)(j,{type:"secondary",style:{fontSize:13},children:["(",(0,x.default)(e.startTime).fromNow(),")"]})]})]})}e.s(["DrawerHeader",()=>b],337767);var S=e.i(271645);function k({isOpen:e,currentLog:t,allLogs:s,onClose:a,onSelectLog:l}){(0,S.useEffect)(()=>{let t=t=>{var s;if(!((s=t.target)instanceof HTMLInputElement||s instanceof HTMLTextAreaElement)&&e)switch(t.key){case h:a();break;case"j":case"J":i();break;case"k":case"K":r()}};return window.addEventListener("keydown",t),()=>window.removeEventListener("keydown",t)},[e,t,s]);let r=()=>{if(!t||!s.length||!l)return;let e=s.findIndex(e=>e.request_id===t.request_id);e{if(!t||!s.length||!l)return;let e=s.findIndex(e=>e.request_id===t.request_id);e>0&&l(s[e-1])};return{selectNextLog:r,selectPreviousLog:i}}e.s(["useKeyboardNavigation",()=>k],237062)},517442,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(592968);let l=e=>e>=.8?"text-green-600":"text-yellow-600",r=({entities:e})=>{let[a,r]=(0,s.useState)(!0),[i,n]=(0,s.useState)({});return e&&0!==e.length?(0,t.jsxs)("div",{className:"mt-4",children:[(0,t.jsxs)("div",{className:"flex items-center mb-2 cursor-pointer",onClick:()=>r(!a),children:[(0,t.jsx)("svg",{className:`w-5 h-5 mr-2 transition-transform ${a?"transform rotate-90":""}`,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"})}),(0,t.jsxs)("h4",{className:"font-medium",children:["Detected Entities (",e.length,")"]})]}),a&&(0,t.jsx)("div",{className:"space-y-2",children:e.map((e,s)=>{let a=i[s]||!1;return(0,t.jsxs)("div",{className:"border rounded-lg overflow-hidden",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between p-3 bg-gray-50 cursor-pointer hover:bg-gray-100",onClick:()=>{n(e=>({...e,[s]:!e[s]}))},children:[(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)("svg",{className:`w-5 h-5 mr-2 transition-transform ${a?"transform rotate-90":""}`,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"})}),(0,t.jsx)("span",{className:"font-medium mr-2",children:e.entity_type}),(0,t.jsxs)("span",{className:`font-mono ${l(e.score)}`,children:["Score: ",e.score.toFixed(2)]})]}),(0,t.jsxs)("span",{className:"text-xs text-gray-500",children:["Position: ",e.start,"-",e.end]})]}),a&&(0,t.jsx)("div",{className:"p-3 border-t bg-white",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4 mb-2",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Entity Type:"}),(0,t.jsx)("span",{children:e.entity_type})]}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Position:"}),(0,t.jsxs)("span",{children:["Characters ",e.start,"-",e.end]})]}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Confidence:"}),(0,t.jsx)("span",{className:l(e.score),children:e.score.toFixed(2)})]})]}),(0,t.jsxs)("div",{className:"space-y-2",children:[e.recognition_metadata&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Recognizer:"}),(0,t.jsx)("span",{children:e.recognition_metadata.recognizer_name})]}),(0,t.jsxs)("div",{className:"flex overflow-hidden",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Identifier:"}),(0,t.jsx)("span",{className:"truncate text-xs font-mono",children:e.recognition_metadata.recognizer_identifier})]})]}),e.analysis_explanation&&(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Explanation:"}),(0,t.jsx)("span",{children:e.analysis_explanation})]})]})]})})]},s)})})]}):null},i=(e,s="slate")=>(0,t.jsx)("span",{className:`px-2 py-1 rounded-md text-xs font-medium inline-block ${{green:"bg-green-100 text-green-800",red:"bg-red-100 text-red-800",blue:"bg-blue-50 text-blue-700",slate:"bg-slate-100 text-slate-800",amber:"bg-amber-100 text-amber-800"}[s]}`,children:e}),n=e=>e?i("detected","red"):i("not detected","slate"),o=({title:e,count:a,defaultOpen:l=!0,right:r,children:i})=>{let[n,o]=(0,s.useState)(l);return(0,t.jsxs)("div",{className:"border rounded-lg overflow-hidden",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between p-3 bg-gray-50 cursor-pointer hover:bg-gray-100",onClick:()=>o(e=>!e),children:[(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)("svg",{className:`w-5 h-5 mr-2 transition-transform ${n?"transform rotate-90":""}`,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"})}),(0,t.jsxs)("h5",{className:"font-medium",children:[e," ","number"==typeof a&&(0,t.jsxs)("span",{className:"text-gray-500 font-normal",children:["(",a,")"]})]})]}),(0,t.jsx)("div",{children:r})]}),n&&(0,t.jsx)("div",{className:"p-3 border-t bg-white",children:i})]})},d=({label:e,children:s,mono:a})=>(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:e}),(0,t.jsx)("span",{className:a?"font-mono text-sm break-all":"",children:s})]}),c=()=>(0,t.jsx)("div",{className:"my-3 border-t"}),m=({response:e})=>{if(!e)return null;let s=e.outputs??e.output??[],a="GUARDRAIL_INTERVENED"===e.action?"red":"green",l=(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[e.guardrailCoverage?.textCharacters&&i(`text guarded ${e.guardrailCoverage.textCharacters.guarded??0}/${e.guardrailCoverage.textCharacters.total??0}`,"blue"),e.guardrailCoverage?.images&&i(`images guarded ${e.guardrailCoverage.images.guarded??0}/${e.guardrailCoverage.images.total??0}`,"blue")]}),r=e.usage&&(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:Object.entries(e.usage).map(([e,s])=>"number"==typeof s?(0,t.jsxs)("span",{className:"px-2 py-1 bg-slate-100 text-slate-800 rounded-md text-xs font-medium",children:[e,": ",s]},e):null)});return(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"border rounded-lg p-4",children:[(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)(d,{label:"Action:",children:i(e.action??"N/A",a)}),e.actionReason&&(0,t.jsx)(d,{label:"Action Reason:",children:e.actionReason}),e.blockedResponse&&(0,t.jsx)(d,{label:"Blocked Response:",children:(0,t.jsx)("span",{className:"italic",children:e.blockedResponse})})]}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)(d,{label:"Coverage:",children:l}),(0,t.jsx)(d,{label:"Usage:",children:r})]})]}),s.length>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(c,{}),(0,t.jsx)("h4",{className:"font-medium mb-2",children:"Outputs"}),(0,t.jsx)("div",{className:"space-y-2",children:s.map((e,s)=>(0,t.jsx)("div",{className:"p-3 bg-gray-50 rounded-md",children:(0,t.jsx)("div",{className:"text-sm whitespace-pre-wrap",children:e.text??(0,t.jsx)("em",{children:"(non-text output)"})})},s))})]})]}),e.assessments?.length?(0,t.jsx)("div",{className:"space-y-3",children:e.assessments.map((e,s)=>{let a=(0,t.jsxs)("div",{className:"flex flex-wrap gap-1",children:[e.wordPolicy&&i("word","slate"),e.contentPolicy&&i("content","slate"),e.topicPolicy&&i("topic","slate"),e.sensitiveInformationPolicy&&i("sensitive-info","slate"),e.contextualGroundingPolicy&&i("contextual-grounding","slate"),e.automatedReasoningPolicy&&i("automated-reasoning","slate")]});return(0,t.jsxs)(o,{title:`Assessment #${s+1}`,defaultOpen:!0,right:(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[e.invocationMetrics?.guardrailProcessingLatency!=null&&i(`${e.invocationMetrics.guardrailProcessingLatency} ms`,"amber"),a]}),children:[e.wordPolicy&&(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h6",{className:"font-medium mb-2",children:"Word Policy"}),(e.wordPolicy.customWords?.length??0)>0&&(0,t.jsx)(o,{title:"Custom Words",defaultOpen:!0,children:(0,t.jsx)("div",{className:"space-y-2",children:e.wordPolicy.customWords.map((e,s)=>(0,t.jsxs)("div",{className:"flex justify-between items-center p-2 bg-gray-50 rounded",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[i(e.action??"N/A",e.detected?"red":"slate"),(0,t.jsx)("span",{className:"font-mono text-sm break-all",children:e.match})]}),n(e.detected)]},s))})}),(e.wordPolicy.managedWordLists?.length??0)>0&&(0,t.jsx)(o,{title:"Managed Word Lists",defaultOpen:!1,children:(0,t.jsx)("div",{className:"space-y-2",children:e.wordPolicy.managedWordLists.map((e,s)=>(0,t.jsxs)("div",{className:"flex justify-between items-center p-2 bg-gray-50 rounded",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[i(e.action??"N/A",e.detected?"red":"slate"),(0,t.jsx)("span",{className:"font-mono text-sm break-all",children:e.match}),e.type&&i(e.type,"slate")]}),n(e.detected)]},s))})})]}),e.contentPolicy?.filters?.length?(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h6",{className:"font-medium mb-2",children:"Content Policy"}),(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)("table",{className:"min-w-full text-sm",children:[(0,t.jsx)("thead",{children:(0,t.jsxs)("tr",{className:"text-left text-gray-600",children:[(0,t.jsx)("th",{className:"py-1 pr-4",children:"Type"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Action"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Detected"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Strength"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Confidence"})]})}),(0,t.jsx)("tbody",{children:e.contentPolicy.filters.map((e,s)=>(0,t.jsxs)("tr",{className:"border-t",children:[(0,t.jsx)("td",{className:"py-1 pr-4",children:e.type??"—"}),(0,t.jsx)("td",{className:"py-1 pr-4",children:i(e.action??"—",e.detected?"red":"slate")}),(0,t.jsx)("td",{className:"py-1 pr-4",children:n(e.detected)}),(0,t.jsx)("td",{className:"py-1 pr-4",children:e.filterStrength??"—"}),(0,t.jsx)("td",{className:"py-1 pr-4",children:e.confidence??"—"})]},s))})]})})]}):null,e.contextualGroundingPolicy?.filters?.length?(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h6",{className:"font-medium mb-2",children:"Contextual Grounding"}),(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)("table",{className:"min-w-full text-sm",children:[(0,t.jsx)("thead",{children:(0,t.jsxs)("tr",{className:"text-left text-gray-600",children:[(0,t.jsx)("th",{className:"py-1 pr-4",children:"Type"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Action"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Detected"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Score"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Threshold"})]})}),(0,t.jsx)("tbody",{children:e.contextualGroundingPolicy.filters.map((e,s)=>(0,t.jsxs)("tr",{className:"border-t",children:[(0,t.jsx)("td",{className:"py-1 pr-4",children:e.type??"—"}),(0,t.jsx)("td",{className:"py-1 pr-4",children:i(e.action??"—",e.detected?"red":"slate")}),(0,t.jsx)("td",{className:"py-1 pr-4",children:n(e.detected)}),(0,t.jsx)("td",{className:"py-1 pr-4",children:e.score??"—"}),(0,t.jsx)("td",{className:"py-1 pr-4",children:e.threshold??"—"})]},s))})]})})]}):null,e.sensitiveInformationPolicy&&(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h6",{className:"font-medium mb-2",children:"Sensitive Information"}),(e.sensitiveInformationPolicy.piiEntities?.length??0)>0&&(0,t.jsx)(o,{title:"PII Entities",defaultOpen:!0,children:(0,t.jsx)("div",{className:"space-y-2",children:e.sensitiveInformationPolicy.piiEntities.map((e,s)=>(0,t.jsxs)("div",{className:"flex justify-between items-center p-2 bg-gray-50 rounded",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[i(e.action??"N/A",e.detected?"red":"slate"),e.type&&i(e.type,"slate"),(0,t.jsx)("span",{className:"font-mono text-xs break-all",children:e.match})]}),n(e.detected)]},s))})}),(e.sensitiveInformationPolicy.regexes?.length??0)>0&&(0,t.jsx)(o,{title:"Custom Regexes",defaultOpen:!1,children:(0,t.jsx)("div",{className:"space-y-2",children:e.sensitiveInformationPolicy.regexes.map((e,s)=>(0,t.jsxs)("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between p-2 bg-gray-50 rounded gap-1",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[i(e.action??"N/A",e.detected?"red":"slate"),(0,t.jsx)("span",{className:"font-medium",children:e.name??"regex"}),(0,t.jsx)("span",{className:"font-mono text-xs break-all",children:e.regex})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[n(e.detected),e.match&&(0,t.jsx)("span",{className:"font-mono text-xs break-all",children:e.match})]})]},s))})})]}),e.topicPolicy?.topics?.length?(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h6",{className:"font-medium mb-2",children:"Topic Policy"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:e.topicPolicy.topics.map((e,s)=>(0,t.jsx)("div",{className:"px-3 py-1.5 bg-gray-50 rounded-md text-xs",children:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[i(e.action??"N/A",e.detected?"red":"slate"),(0,t.jsx)("span",{className:"font-medium",children:e.name??"topic"}),e.type&&i(e.type,"slate"),n(e.detected)]})},s))})]}):null,e.invocationMetrics&&(0,t.jsx)(o,{title:"Invocation Metrics",defaultOpen:!1,children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)(d,{label:"Latency (ms)",children:e.invocationMetrics.guardrailProcessingLatency??"—"}),(0,t.jsx)(d,{label:"Coverage:",children:(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[e.invocationMetrics.guardrailCoverage?.textCharacters&&i(`text ${e.invocationMetrics.guardrailCoverage.textCharacters.guarded??0}/${e.invocationMetrics.guardrailCoverage.textCharacters.total??0}`,"blue"),e.invocationMetrics.guardrailCoverage?.images&&i(`images ${e.invocationMetrics.guardrailCoverage.images.guarded??0}/${e.invocationMetrics.guardrailCoverage.images.total??0}`,"blue")]})})]}),(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsx)(d,{label:"Usage:",children:(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:e.invocationMetrics.usage&&Object.entries(e.invocationMetrics.usage).map(([e,s])=>"number"==typeof s?(0,t.jsxs)("span",{className:"px-2 py-1 bg-slate-100 text-slate-800 rounded-md text-xs font-medium",children:[e,": ",s]},e):null)})})})]})}),e.automatedReasoningPolicy?.findings?.length?(0,t.jsx)(o,{title:"Automated Reasoning Findings",defaultOpen:!1,children:(0,t.jsx)("div",{className:"space-y-2",children:e.automatedReasoningPolicy.findings.map((e,s)=>(0,t.jsx)("pre",{className:"bg-gray-50 rounded p-2 text-xs overflow-x-auto",children:JSON.stringify(e,null,2)},s))})}):null]},s)})}):null,(0,t.jsx)(o,{title:"Raw Bedrock Guardrail Response",defaultOpen:!1,children:(0,t.jsx)("pre",{className:"bg-gray-50 rounded p-3 text-xs overflow-x-auto",children:JSON.stringify(e,null,2)})})]})},x=(e,s="slate")=>(0,t.jsx)("span",{className:`px-2 py-1 rounded-md text-xs font-medium inline-block ${{green:"bg-green-100 text-green-800",red:"bg-red-100 text-red-800",blue:"bg-blue-50 text-blue-700",slate:"bg-slate-100 text-slate-800",amber:"bg-amber-100 text-amber-800"}[s]}`,children:e}),u=({title:e,count:a,defaultOpen:l=!0,children:r})=>{let[i,n]=(0,s.useState)(l);return(0,t.jsxs)("div",{className:"border rounded-lg overflow-hidden",children:[(0,t.jsx)("div",{className:"flex items-center justify-between p-3 bg-gray-50 cursor-pointer hover:bg-gray-100",onClick:()=>n(e=>!e),children:(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)("svg",{className:`w-5 h-5 mr-2 transition-transform ${i?"transform rotate-90":""}`,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"})}),(0,t.jsxs)("h5",{className:"font-medium",children:[e," ","number"==typeof a&&(0,t.jsxs)("span",{className:"text-gray-500 font-normal",children:["(",a,")"]})]})]})}),i&&(0,t.jsx)("div",{className:"p-3 border-t bg-white",children:r})]})},p=({label:e,children:s,mono:a})=>(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:e}),(0,t.jsx)("span",{className:a?"font-mono text-sm break-all":"",children:s})]}),h=({response:e})=>{if(!e||"string"==typeof e)return"string"==typeof e&&e?(0,t.jsx)("div",{className:"bg-white rounded-lg border border-red-200 p-4",children:(0,t.jsxs)("div",{className:"text-red-800",children:[(0,t.jsx)("h5",{className:"font-medium mb-2",children:"Error"}),(0,t.jsx)("p",{className:"text-sm",children:e})]})}):null;let s=Array.isArray(e)?e:[];if(0===s.length)return(0,t.jsx)("div",{className:"bg-white rounded-lg border border-gray-200 p-4",children:(0,t.jsx)("div",{className:"text-gray-600 text-sm",children:"No detections found"})});let a=s.filter(e=>"pattern"===e.type),l=s.filter(e=>"blocked_word"===e.type),r=s.filter(e=>"category_keyword"===e.type),i=s.filter(e=>"BLOCK"===e.action).length,n=s.filter(e=>"MASK"===e.action).length,o=s.length;return(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsx)("div",{className:"bg-white rounded-lg border border-gray-200 p-4",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)(p,{label:"Total Detections:",children:(0,t.jsx)("span",{className:"font-semibold",children:o})}),(0,t.jsx)(p,{label:"Actions:",children:(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[i>0&&x(`${i} blocked`,"red"),n>0&&x(`${n} masked`,"blue"),0===i&&0===n&&x("passed","green")]})})]}),(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsx)(p,{label:"By Type:",children:(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[a.length>0&&x(`${a.length} patterns`,"slate"),l.length>0&&x(`${l.length} keywords`,"slate"),r.length>0&&x(`${r.length} categories`,"slate")]})})})]})}),a.length>0&&(0,t.jsx)(u,{title:"Patterns Matched",count:a.length,defaultOpen:!0,children:(0,t.jsx)("div",{className:"space-y-2",children:a.map((e,s)=>(0,t.jsx)("div",{className:"p-3 bg-gray-50 rounded-md",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsx)("div",{className:"space-y-1",children:(0,t.jsx)(p,{label:"Pattern:",children:e.pattern_name||"unknown"})}),(0,t.jsx)("div",{className:"space-y-1",children:(0,t.jsx)(p,{label:"Action:",children:x(e.action,"BLOCK"===e.action?"red":"blue")})})]})},s))})}),l.length>0&&(0,t.jsx)(u,{title:"Blocked Words Detected",count:l.length,defaultOpen:!0,children:(0,t.jsx)("div",{className:"space-y-2",children:l.map((e,s)=>(0,t.jsx)("div",{className:"p-3 bg-gray-50 rounded-md",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-1",children:[(0,t.jsx)(p,{label:"Keyword:",mono:!0,children:e.keyword||"unknown"}),e.description&&(0,t.jsx)(p,{label:"Description:",children:e.description})]}),(0,t.jsx)("div",{className:"space-y-1",children:(0,t.jsx)(p,{label:"Action:",children:x(e.action,"BLOCK"===e.action?"red":"blue")})})]})},s))})}),r.length>0&&(0,t.jsx)(u,{title:"Category Keywords Detected",count:r.length,defaultOpen:!0,children:(0,t.jsx)("div",{className:"space-y-2",children:r.map((e,s)=>(0,t.jsx)("div",{className:"p-3 bg-gray-50 rounded-md",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-1",children:[(0,t.jsx)(p,{label:"Category:",children:e.category||"unknown"}),(0,t.jsx)(p,{label:"Keyword:",mono:!0,children:e.keyword||"unknown"}),e.severity&&(0,t.jsx)(p,{label:"Severity:",children:x(e.severity,"high"===e.severity?"red":"medium"===e.severity?"amber":"slate")})]}),(0,t.jsx)("div",{className:"space-y-1",children:(0,t.jsx)(p,{label:"Action:",children:x(e.action,"BLOCK"===e.action?"red":"blue")})})]})},s))})}),(0,t.jsx)(u,{title:"Raw Detection Data",defaultOpen:!1,children:(0,t.jsx)("pre",{className:"bg-gray-50 rounded p-3 text-xs overflow-x-auto",children:JSON.stringify(s,null,2)})})]})};var g=e.i(764205);let f=()=>(0,t.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:[(0,t.jsx)("circle",{cx:"8",cy:"8",r:"7",stroke:"#16A34A",strokeWidth:"1.5",fill:"#F0FDF4"}),(0,t.jsx)("path",{d:"M5 8l2 2 4-4",stroke:"#16A34A",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})]}),y=()=>(0,t.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:[(0,t.jsx)("circle",{cx:"8",cy:"8",r:"7",stroke:"#DC2626",strokeWidth:"1.5",fill:"#FEF2F2"}),(0,t.jsx)("path",{d:"M6 6l4 4M10 6l-4 4",stroke:"#DC2626",strokeWidth:"1.5",strokeLinecap:"round"})]}),j=()=>(0,t.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",className:"animate-spin",children:[(0,t.jsx)("circle",{cx:"8",cy:"8",r:"6",stroke:"#D1D5DB",strokeWidth:"2"}),(0,t.jsx)("path",{d:"M8 2a6 6 0 0 1 6 6",stroke:"#6366F1",strokeWidth:"2",strokeLinecap:"round"})]}),b=({title:e,data:l,loading:r,error:i})=>{let[n,o]=(0,s.useState)(!1);return(0,t.jsxs)("div",{className:"border border-gray-200 rounded-lg bg-white",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-4 py-3 cursor-pointer hover:bg-gray-50 transition-colors",onClick:()=>o(!n),children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[r?(0,t.jsx)(j,{}):i?(0,t.jsx)(a.Tooltip,{title:i,children:(0,t.jsx)("span",{className:"text-gray-400 text-sm",children:"--"})}):l?.compliant?(0,t.jsx)(f,{}):(0,t.jsx)(y,{}),(0,t.jsx)("span",{className:"font-medium text-sm text-gray-900",children:e})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[!r&&!i&&l&&(0,t.jsx)("span",{className:`px-2 py-0.5 rounded text-[11px] font-semibold uppercase ${l.compliant?"bg-green-100 text-green-700 border border-green-200":"bg-red-100 text-red-700 border border-red-200"}`,children:l.compliant?"COMPLIANT":"NON-COMPLIANT"}),i&&(0,t.jsx)("span",{className:"px-2 py-0.5 rounded text-[11px] font-medium bg-gray-100 text-gray-500 border border-gray-200",children:"UNAVAILABLE"}),(0,t.jsx)("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"none",className:`transition-transform ${n?"rotate-180":""}`,children:(0,t.jsx)("path",{d:"M6 8l4 4 4-4",stroke:"#6B7280",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]})]}),n&&(0,t.jsxs)("div",{className:"border-t border-gray-100 px-4 py-3",children:[r&&(0,t.jsx)("p",{className:"text-sm text-gray-500",children:"Checking compliance..."}),i&&(0,t.jsx)("p",{className:"text-sm text-red-600",children:i}),l&&(0,t.jsx)("div",{className:"space-y-2",children:l.checks.map((e,s)=>(0,t.jsxs)("div",{className:"flex items-start gap-2",children:[(0,t.jsx)("div",{className:"flex-shrink-0 mt-0.5",children:e.passed?(0,t.jsx)(f,{}):(0,t.jsx)(y,{})}),(0,t.jsxs)("div",{className:"min-w-0",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900",children:e.check_name}),(0,t.jsx)("span",{className:"text-[10px] font-mono text-gray-400",children:e.article})]}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5",children:e.detail})]})]},s))})]})]})},v=({accessToken:e,logEntry:a})=>{let[l,r]=(0,s.useState)(null),[i,n]=(0,s.useState)(null),[o,d]=(0,s.useState)(!1),[c,m]=(0,s.useState)(!1),[x,u]=(0,s.useState)(null),[p,h]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(!e||!a.request_id)return;let t={request_id:a.request_id,user_id:a.user,model:a.model,timestamp:a.startTime,guardrail_information:a.metadata?.guardrail_information};d(!0),u(null),(0,g.checkEuAiActCompliance)(e,t).then(r).catch(e=>u(e.message||"Failed to check EU AI Act compliance")).finally(()=>d(!1)),m(!0),h(null),(0,g.checkGdprCompliance)(e,t).then(n).catch(e=>h(e.message||"Failed to check GDPR compliance")).finally(()=>m(!1))},[e,a]),(0,t.jsxs)("div",{children:[(0,t.jsx)("h4",{className:"text-xs font-semibold text-gray-500 uppercase tracking-wider mb-4",children:"Regulatory Compliance"}),(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsx)(b,{title:"EU AI Act",data:l,loading:o,error:x}),(0,t.jsx)(b,{title:"GDPR",data:i,loading:c,error:p})]})]})},_=new Set(["presidio","bedrock","litellm_content_filter"]),N=e=>Object.values(e.masked_entity_count||{}).reduce((e,t)=>e+("number"==typeof t?t:0),0),w=e=>"success"===(e.guardrail_status??"").toLowerCase(),S=e=>e.policy_template||e.guardrail_name,k=()=>(0,t.jsxs)("svg",{width:"40",height:"40",viewBox:"0 0 40 40",fill:"none",children:[(0,t.jsx)("circle",{cx:"20",cy:"20",r:"20",fill:"#EEF2FF"}),(0,t.jsx)("path",{d:"M20 10l8 4v6c0 5.25-3.4 10.15-8 11.5C15.4 30.15 12 25.25 12 20v-6l8-4z",stroke:"#6366F1",strokeWidth:"1.5",fill:"none"}),(0,t.jsx)("path",{d:"M16 20l3 3 5-6",stroke:"#6366F1",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",fill:"none"})]}),C=({className:e})=>(0,t.jsxs)("svg",{width:"22",height:"22",viewBox:"0 0 22 22",fill:"none",className:e,children:[(0,t.jsx)("circle",{cx:"11",cy:"11",r:"10",stroke:"#16A34A",strokeWidth:"1.5",fill:"#F0FDF4"}),(0,t.jsx)("path",{d:"M7 11l3 3 5-6",stroke:"#16A34A",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})]}),T=({className:e})=>(0,t.jsxs)("svg",{width:"22",height:"22",viewBox:"0 0 22 22",fill:"none",className:e,children:[(0,t.jsx)("circle",{cx:"11",cy:"11",r:"10",stroke:"#DC2626",strokeWidth:"1.5",fill:"#FEF2F2"}),(0,t.jsx)("path",{d:"M8 8l6 6M14 8l-6 6",stroke:"#DC2626",strokeWidth:"1.5",strokeLinecap:"round"})]}),L=()=>(0,t.jsxs)("svg",{width:"22",height:"22",viewBox:"0 0 22 22",fill:"none",children:[(0,t.jsx)("circle",{cx:"11",cy:"11",r:"10",stroke:"#3B82F6",strokeWidth:"1.5",fill:"#EFF6FF"}),(0,t.jsx)("path",{d:"M9 7.5l6 3.5-6 3.5V7.5z",fill:"#3B82F6"})]}),M=()=>(0,t.jsx)("svg",{width:"22",height:"22",viewBox:"0 0 22 22",fill:"none",children:(0,t.jsx)("circle",{cx:"11",cy:"11",r:"5",fill:"#9CA3AF"})}),E=({expanded:e})=>(0,t.jsx)("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"none",className:`transition-transform ${e?"rotate-180":""}`,children:(0,t.jsx)("path",{d:"M6 8l4 4 4-4",stroke:"#6B7280",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})}),A=()=>(0,t.jsx)("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:(0,t.jsx)("path",{d:"M8 2v8m0 0l-3-3m3 3l3-3M3 12h10",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})}),D=({matchDetails:e})=>e&&0!==e.length?(0,t.jsxs)("div",{className:"mt-3",children:[(0,t.jsxs)("h5",{className:"text-sm font-medium mb-2 text-gray-700",children:["Match Details (",e.length,")"]}),(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)("table",{className:"w-full text-sm",children:[(0,t.jsx)("thead",{children:(0,t.jsxs)("tr",{className:"border-b text-left text-gray-500",children:[(0,t.jsx)("th",{className:"pb-2 pr-4 font-medium",children:"Type"}),(0,t.jsx)("th",{className:"pb-2 pr-4 font-medium",children:"Method"}),(0,t.jsx)("th",{className:"pb-2 pr-4 font-medium",children:"Action"}),(0,t.jsx)("th",{className:"pb-2 font-medium",children:"Detail"})]})}),(0,t.jsx)("tbody",{children:e.map((e,s)=>(0,t.jsxs)("tr",{className:"border-b border-gray-100",children:[(0,t.jsx)("td",{className:"py-2 pr-4",children:e.type}),(0,t.jsx)("td",{className:"py-2 pr-4",children:(0,t.jsx)("span",{className:"px-2 py-0.5 bg-slate-100 text-slate-700 rounded text-xs",children:e.detection_method??"-"})}),(0,t.jsx)("td",{className:"py-2 pr-4",children:(0,t.jsx)("span",{className:`px-2 py-0.5 rounded text-xs font-medium ${"BLOCK"===e.action_taken?"bg-red-100 text-red-800":"bg-blue-50 text-blue-700"}`,children:e.action_taken??"-"})}),(0,t.jsxs)("td",{className:"py-2 font-mono text-xs text-gray-600 break-all",children:[e.category?`[${e.category}] `:"",e.snippet??"-"]})]},s))})]})})]}):null,I=({response:e})=>{let[a,l]=(0,s.useState)(!1);return(0,t.jsx)("div",{className:"mt-3",children:(0,t.jsxs)("div",{className:"border rounded-lg overflow-hidden",children:[(0,t.jsx)("div",{className:"flex items-center justify-between p-3 bg-gray-50 cursor-pointer hover:bg-gray-100",onClick:()=>l(!a),children:(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)(E,{expanded:a}),(0,t.jsx)("h5",{className:"font-medium text-sm ml-1",children:"Raw Guardrail Response"})]})}),a&&(0,t.jsx)("div",{className:"p-3 border-t bg-white",children:(0,t.jsx)("pre",{className:"bg-gray-50 rounded p-3 text-xs overflow-x-auto",children:JSON.stringify(e,null,2)})})]})})},O=({entries:e})=>{let a=(0,s.useMemo)(()=>[...e].sort((e,t)=>(e.start_time??0)-(t.start_time??0)),[e]),l=(0,s.useMemo)(()=>{if(0===a.length)return[];let e=a[0].start_time,t=[];t.push({type:"request",label:"Request received",offsetMs:0});let s=a.filter(e=>"pre_call"===e.guardrail_mode),l=a.filter(e=>"post_call"===e.guardrail_mode||"logging_only"===e.guardrail_mode),r=a.filter(e=>"during_call"===e.guardrail_mode);for(let a of s){let s=Math.round((a.end_time-e)*1e3);t.push({type:"guardrail",label:`Pre-call guardrail: ${S(a)}`,offsetMs:s,status:w(a)?"PASSED":"FAILED",isSuccess:w(a)})}let i=s.length>0?Math.max(...s.map(e=>e.end_time)):e,n=Math.round((((l.length>0?Math.min(...l.map(e=>e.start_time)):void 0)??i+1)-e)*1e3);for(let s of(t.push({type:"llm",label:"LLM call",offsetMs:n}),r)){let a=Math.round((s.end_time-e)*1e3);t.push({type:"guardrail",label:`During-call guardrail: ${S(s)}`,offsetMs:a,status:w(s)?"PASSED":"FAILED",isSuccess:w(s)})}for(let s of l){let a=Math.round((s.end_time-e)*1e3);t.push({type:"guardrail",label:`Post-call guardrail: ${S(s)}`,offsetMs:a,status:w(s)?"PASSED":"FAILED",isSuccess:w(s)})}let o=Math.round((Math.max(...a.map(e=>e.end_time))-e)*1e3)+1;return t.push({type:"response",label:"Response returned",offsetMs:o}),t},[a]);return(0,t.jsxs)("div",{children:[(0,t.jsx)("h4",{className:"text-xs font-semibold text-gray-500 uppercase tracking-wider mb-4",children:"Request Lifecycle"}),(0,t.jsx)("div",{className:"relative",children:l.map((e,s)=>(0,t.jsxs)("div",{className:"flex items-start gap-3 relative",children:[(0,t.jsxs)("div",{className:"flex flex-col items-center",children:[(0,t.jsx)("div",{className:"flex-shrink-0",children:"request"===e.type||"response"===e.type?(0,t.jsx)(M,{}):"llm"===e.type?(0,t.jsx)(L,{}):e.isSuccess?(0,t.jsx)(C,{}):(0,t.jsx)(T,{})}),s{var l;let i,[n,o]=(0,s.useState)(!1),d=w(e),c=N(e),x=S(e),u=(i=Math.round(1e3*e.duration),`${i}ms`),p=null==(l=e.guardrail_mode)||""===l?"—":("string"==typeof l?l:String(l)).replace(/_/g,"-").toUpperCase(),g=(e=>{if(!w(e))return null;if(null!=e.risk_score)return e.risk_score;let t=N(e),s=e.patterns_checked??0,a=e.confidence_score??0;if(0===s&&0===a)return 0;let l=7*(s>0?t/s:0)+3*a;return t>0&&l<2&&(l=2),Math.min(10,Math.round(10*l)/10)})(e),f=e.guardrail_provider??"presidio",y=e.guardrail_response,j=Array.isArray(y)?y:[],b="bedrock"!==f||null===y||"object"!=typeof y||Array.isArray(y)?void 0:y,v=null!=e.patterns_checked?`${c}/${e.patterns_checked} matched`:c>0?`${c} matched`:null;return(0,t.jsxs)("div",{className:"border border-gray-200 rounded-lg bg-white",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3 px-4 py-3 cursor-pointer hover:bg-gray-50 transition-colors",onClick:()=>o(!n),children:[(0,t.jsx)("div",{className:"flex-shrink-0",children:d?(0,t.jsx)(C,{}):(0,t.jsx)(T,{})}),(0,t.jsxs)("div",{className:"flex items-center gap-2 flex-wrap flex-1 min-w-0",children:[(0,t.jsx)("span",{className:"font-semibold text-gray-900 text-sm truncate",children:x}),(0,t.jsx)("span",{className:"px-2 py-0.5 border border-blue-200 bg-blue-50 text-blue-700 rounded text-[11px] font-semibold uppercase flex-shrink-0",children:p}),(0,t.jsx)("span",{className:`px-2 py-0.5 rounded text-[11px] font-semibold uppercase flex-shrink-0 ${d?"bg-green-100 text-green-700 border border-green-200":"bg-red-100 text-red-700 border border-red-200"}`,children:d?"PASSED":"FAILED"}),v&&(0,t.jsx)("span",{className:`px-2 py-0.5 rounded text-[11px] font-medium flex-shrink-0 ${0===c?"bg-green-50 text-green-700 border border-green-200":"bg-amber-50 text-amber-700 border border-amber-200"}`,children:v}),null!=e.confidence_score&&(0,t.jsxs)("span",{className:"px-2 py-0.5 bg-gray-100 text-gray-600 border border-gray-200 rounded text-[11px] font-medium flex-shrink-0",children:[(100*e.confidence_score).toFixed(0),"% conf"]}),null!=g&&d&&(0,t.jsx)(a.Tooltip,{title:`Risk score: ${g}/10`,children:(0,t.jsxs)("span",{className:`px-2 py-0.5 border rounded text-[11px] font-semibold flex-shrink-0 ${g<=3?"text-green-600 bg-green-50 border-green-200":g<=6?"text-amber-600 bg-amber-50 border-amber-200":"text-red-600 bg-red-50 border-red-200"}`,children:["Risk ",g,"/10"]})})]}),(0,t.jsxs)("div",{className:"flex items-center gap-3 flex-shrink-0",children:[(0,t.jsx)("span",{className:"text-sm text-gray-500 font-mono",children:u}),e.detection_method&&(0,t.jsx)("span",{className:"px-2 py-0.5 bg-gray-100 text-gray-600 border border-gray-200 rounded text-[11px] font-medium",children:e.detection_method.split(",")[0].trim()}),(0,t.jsx)(E,{expanded:n})]})]}),n&&(0,t.jsxs)("div",{className:"border-t border-gray-100 px-4 py-3",children:[e.classification&&(0,t.jsxs)("div",{className:"mb-3 bg-gray-50 rounded-lg p-3 space-y-1",children:[(0,t.jsx)("h5",{className:"text-sm font-medium text-gray-700 mb-2",children:"Classification"}),e.classification.category&&(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"font-medium w-1/3 text-gray-500",children:"Category:"}),(0,t.jsx)("span",{children:e.classification.category})]}),e.classification.article_reference&&(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"font-medium w-1/3 text-gray-500",children:"Reference:"}),(0,t.jsx)("span",{className:"font-mono",children:e.classification.article_reference})]}),null!=e.classification.confidence&&(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"font-medium w-1/3 text-gray-500",children:"Confidence:"}),(0,t.jsxs)("span",{children:[(100*e.classification.confidence).toFixed(0),"%"]})]}),e.classification.reason&&(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"font-medium w-1/3 text-gray-500",children:"Reason:"}),(0,t.jsx)("span",{children:e.classification.reason})]})]}),e.match_details&&e.match_details.length>0&&(0,t.jsx)(D,{matchDetails:e.match_details}),c>0&&(0,t.jsxs)("div",{className:"mt-3",children:[(0,t.jsx)("h5",{className:"text-sm font-medium text-gray-700 mb-2",children:"Masked Entities"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:Object.entries(e.masked_entity_count||{}).map(([e,s])=>(0,t.jsxs)("span",{className:"px-2 py-1 bg-blue-50 text-blue-700 rounded text-xs font-medium",children:[e,": ",s]},e))})]}),"presidio"===f&&j.length>0&&(0,t.jsx)("div",{className:"mt-3",children:(0,t.jsx)(r,{entities:j})}),"bedrock"===f&&b&&(0,t.jsx)("div",{className:"mt-3",children:(0,t.jsx)(m,{response:b})}),"litellm_content_filter"===f&&y&&(0,t.jsx)("div",{className:"mt-3",children:(0,t.jsx)(h,{response:y})}),f&&!_.has(f)&&y&&(0,t.jsx)(I,{response:y})]})]})};e.s(["default",0,({data:e,accessToken:a,logEntry:l})=>{let r=(0,s.useMemo)(()=>Array.isArray(e)?e.filter(e=>!!e):e?[e]:[],[e]),i=r.filter(w).length,n=i===r.length,o=(0,s.useMemo)(()=>Math.round(1e3*r.reduce((e,t)=>e+(t.duration??0),0)),[r]);return((0,s.useMemo)(()=>Array.from(new Set(r.map(e=>e.policy_template).filter(Boolean))),[r]),0===r.length)?null:(0,t.jsxs)("div",{className:"bg-white rounded-xl border border-gray-200 shadow-sm w-full max-w-full overflow-hidden mb-6",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-6 py-4 border-b border-gray-100",children:[(0,t.jsxs)("div",{className:"flex items-center gap-4",children:[(0,t.jsx)(k,{}),(0,t.jsxs)("div",{children:[(0,t.jsx)("h3",{className:"text-lg font-semibold text-gray-900",children:"Guardrails & Policy Compliance"}),(0,t.jsxs)("div",{className:"flex items-center gap-2 mt-0.5",children:[(0,t.jsxs)("span",{className:"text-sm text-gray-500",children:[r.length," guardrail",1!==r.length?"s":""," evaluated"]}),(0,t.jsx)("span",{className:"text-gray-300",children:"|"}),(0,t.jsxs)("span",{className:`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-semibold ${n?"bg-green-50 text-green-700 border border-green-200":"bg-red-50 text-red-700 border border-red-200"}`,children:[n?(0,t.jsx)("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",children:(0,t.jsx)("path",{d:"M3 6l2.5 2.5L9 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})}):null,i," Passed"]})]})]})]}),(0,t.jsxs)("div",{className:"flex items-center gap-6",children:[(0,t.jsx)("div",{className:"text-right",children:(0,t.jsxs)("div",{className:"text-sm font-medium text-gray-900",children:["Total: ",o,"ms overhead"]})}),(0,t.jsxs)("button",{onClick:()=>{let e=new Blob([JSON.stringify(r,null,2)],{type:"application/json"}),t=URL.createObjectURL(e),s=document.createElement("a");s.href=t,s.download=`guardrail-compliance-log-${new Date().toISOString().slice(0,10)}.json`,s.click(),URL.revokeObjectURL(t)},className:"inline-flex items-center gap-2 px-4 py-2 border border-gray-300 rounded-lg text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 transition-colors",children:[(0,t.jsx)(A,{}),"Export Compliance Log"]})]})]}),a&&l&&(0,t.jsx)("div",{className:"px-6 py-4 border-b border-gray-100",children:(0,t.jsx)(v,{accessToken:a,logEntry:l})}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("div",{className:"w-[340px] flex-shrink-0 border-r border-gray-100 px-6 py-5",children:(0,t.jsx)(O,{entries:r})}),(0,t.jsxs)("div",{className:"flex-1 px-6 py-5 min-w-0",children:[(0,t.jsx)("h4",{className:"text-xs font-semibold text-gray-500 uppercase tracking-wider mb-4",children:"Evaluation Details"}),(0,t.jsx)("div",{className:"space-y-3",children:r.map((e,s)=>(0,t.jsx)(z,{entry:e},`${e.guardrail_name??"guardrail"}-${s}`))})]})]})]})}],517442)},70635,e=>{"use strict";var t=e.i(843476),s=e.i(362024),a=e.i(500330);let l=e=>null==e?"-":`$${(0,a.formatNumberWithCommas)(e,8)}`,r=e=>null==e?"-":`${(100*e).toFixed(2)}%`;e.s(["CostBreakdownViewer",0,({costBreakdown:e,totalSpend:a,promptTokens:i,completionTokens:n,cacheHit:o})=>{let d=o?.toLowerCase()==="true",c=void 0!==i||void 0!==n;if(!(e?.input_cost!==void 0||e?.output_cost!==void 0||c||e&&(void 0!==e.discount_percent&&0!==e.discount_percent||void 0!==e.discount_amount&&0!==e.discount_amount||void 0!==e.margin_percent&&0!==e.margin_percent||void 0!==e.margin_fixed_amount&&0!==e.margin_fixed_amount||void 0!==e.margin_total_amount&&0!==e.margin_total_amount)))return null;let m=e&&(void 0!==e.discount_percent&&0!==e.discount_percent||void 0!==e.discount_amount&&0!==e.discount_amount),x=e&&(void 0!==e.margin_percent&&0!==e.margin_percent||void 0!==e.margin_fixed_amount&&0!==e.margin_fixed_amount||void 0!==e.margin_total_amount&&0!==e.margin_total_amount),u=d?0:e?.input_cost,p=d?0:e?.output_cost,h=d?0:e?.original_cost,g=d?0:e?.total_cost??a;return(0,t.jsx)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6",children:(0,t.jsx)(s.Collapse,{expandIconPosition:"start",items:[{key:"1",label:(0,t.jsxs)("div",{className:"flex items-center justify-between w-full",children:[(0,t.jsx)("h3",{className:"text-lg font-medium text-gray-900",children:"Cost Breakdown"}),(0,t.jsxs)("div",{className:"flex items-center space-x-2 mr-4",children:[(0,t.jsx)("span",{className:"text-sm text-gray-500",children:"Total:"}),(0,t.jsxs)("span",{className:"text-sm font-semibold text-gray-900",children:[l(a),d&&" (Cached)"]})]})]}),children:(0,t.jsxs)("div",{className:"p-6 space-y-4",children:[(0,t.jsxs)("div",{className:"space-y-2 max-w-2xl",children:[(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"text-gray-600 font-medium w-1/3",children:"Input Cost:"}),(0,t.jsxs)("span",{className:"text-gray-900",children:[l(u),void 0!==i&&(0,t.jsxs)("span",{className:"text-gray-500 font-normal ml-1",children:["(",i.toLocaleString()," prompt tokens)"]})]})]}),(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"text-gray-600 font-medium w-1/3",children:"Output Cost:"}),(0,t.jsxs)("span",{className:"text-gray-900",children:[l(p),void 0!==n&&(0,t.jsxs)("span",{className:"text-gray-500 font-normal ml-1",children:["(",n.toLocaleString()," completion tokens)"]})]})]}),e?.tool_usage_cost!==void 0&&e.tool_usage_cost>0&&(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"text-gray-600 font-medium w-1/3",children:"Tool Usage Cost:"}),(0,t.jsx)("span",{className:"text-gray-900",children:l(e.tool_usage_cost)})]}),e?.additional_costs&&Object.keys(e.additional_costs).length>0&&(0,t.jsx)(t.Fragment,{children:Object.entries(e.additional_costs).map(([e,s])=>(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsxs)("span",{className:"text-gray-600 font-medium w-1/3",children:[e,":"]}),(0,t.jsx)("span",{className:"text-gray-900",children:l(s)})]},e))})]}),!d&&(0,t.jsx)("div",{className:"pt-2 border-t border-gray-100 max-w-2xl",children:(0,t.jsxs)("div",{className:"flex text-sm font-semibold",children:[(0,t.jsx)("span",{className:"text-gray-900 w-1/3",children:"Original LLM Cost:"}),(0,t.jsx)("span",{className:"text-gray-900",children:l(h)})]})}),(m||x)&&(0,t.jsxs)("div",{className:"pt-2 space-y-2 max-w-2xl",children:[m&&(0,t.jsxs)("div",{className:"space-y-2",children:[void 0!==e.discount_percent&&0!==e.discount_percent&&(0,t.jsxs)("div",{className:"flex text-sm text-gray-600",children:[(0,t.jsxs)("span",{className:"font-medium w-1/3",children:["Discount (",r(e.discount_percent),"):"]}),(0,t.jsxs)("span",{className:"text-gray-900",children:["-",l(e.discount_amount)]})]}),void 0!==e.discount_amount&&void 0===e.discount_percent&&(0,t.jsxs)("div",{className:"flex text-sm text-gray-600",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Discount Amount:"}),(0,t.jsxs)("span",{className:"text-gray-900",children:["-",l(e.discount_amount)]})]})]}),x&&(0,t.jsxs)("div",{className:"space-y-2",children:[void 0!==e.margin_percent&&0!==e.margin_percent&&(0,t.jsxs)("div",{className:"flex text-sm text-gray-600",children:[(0,t.jsxs)("span",{className:"font-medium w-1/3",children:["Margin (",r(e.margin_percent),"):"]}),(0,t.jsxs)("span",{className:"text-gray-900",children:["+",l((e.margin_total_amount||0)-(e.margin_fixed_amount||0))]})]}),void 0!==e.margin_fixed_amount&&0!==e.margin_fixed_amount&&(0,t.jsxs)("div",{className:"flex text-sm text-gray-600",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Margin:"}),(0,t.jsxs)("span",{className:"text-gray-900",children:["+",l(e.margin_fixed_amount)]})]})]})]}),(0,t.jsx)("div",{className:"mt-4 pt-4 border-t border-gray-200 max-w-2xl",children:(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)("span",{className:"font-bold text-sm text-gray-900 w-1/3",children:"Final Calculated Cost:"}),(0,t.jsxs)("span",{className:"text-sm font-bold text-gray-900",children:[l(g),d&&" (Cached)"]})]})})]})}]})})}])},70969,e=>{"use strict";var t=e.i(843476);e.s(["ConfigInfoMessage",0,({show:e,onOpenSettings:s})=>e?(0,t.jsxs)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-4 flex items-start",children:[(0,t.jsx)("div",{className:"text-blue-500 mr-3 flex-shrink-0 mt-0.5",children:(0,t.jsxs)("svg",{xmlns:"http://www.w3.org/2000/svg",width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,t.jsx)("circle",{cx:"12",cy:"12",r:"10"}),(0,t.jsx)("line",{x1:"12",y1:"16",x2:"12",y2:"12"}),(0,t.jsx)("line",{x1:"12",y1:"8",x2:"12.01",y2:"8"})]})}),(0,t.jsxs)("div",{children:[(0,t.jsx)("h4",{className:"text-sm font-medium text-blue-800",children:"Request/Response Data Not Available"}),(0,t.jsxs)("p",{className:"text-sm text-blue-700 mt-1",children:["To view request and response details, enable prompt storage in your LiteLLM configuration by adding the following to your ",(0,t.jsx)("code",{className:"bg-blue-100 px-1 py-0.5 rounded",children:"proxy_config.yaml"})," file",s&&(0,t.jsxs)(t.Fragment,{children:[" or"," ",(0,t.jsx)("button",{onClick:s,className:"text-blue-600 hover:text-blue-800 underline font-medium",children:"open the settings"})," ","to configure this directly."]})]}),(0,t.jsx)("pre",{className:"mt-2 bg-white p-3 rounded border border-blue-200 text-xs font-mono overflow-auto",children:`general_settings: +(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,894660,283086,195116,e=>{"use strict";var t=e.i(801312);e.s(["LeftOutlined",()=>t.default],894660);var s=e.i(475254);let a=(0,s.default)("sparkles",[["path",{d:"M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z",key:"4pj2yx"}],["path",{d:"M20 3v4",key:"1olli1"}],["path",{d:"M22 5h-4",key:"1gvqau"}],["path",{d:"M4 17v2",key:"vumght"}],["path",{d:"M5 18H3",key:"zchphs"}]]);e.s(["Sparkles",()=>a],283086);let l=(0,s.default)("wrench",[["path",{d:"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z",key:"cbrjhi"}]]);e.s(["Wrench",()=>l],195116)},97859,e=>{"use strict";e.s(["AGENT_CALL_TYPES",0,["asend_message"],"ERROR_CODE_OPTIONS",0,[{label:"400 - Bad Request",value:"400"},{label:"401 - Invalid Authentication",value:"401"},{label:"403 - Permission Denied",value:"403"},{label:"404 - Not Found",value:"404"},{label:"408 - Request Timeout",value:"408"},{label:"422 - Unprocessable Entity",value:"422"},{label:"429 - Rate Limited",value:"429"},{label:"500 - Internal Server Error",value:"500"},{label:"502 - Bad Gateway",value:"502"},{label:"503 - Service Unavailable",value:"503"},{label:"529 - Overloaded",value:"529"}],"MCP_CALL_TYPES",0,["call_mcp_tool","list_mcp_tools"],"QUICK_SELECT_OPTIONS",0,[{label:"Last 15 Minutes",value:15,unit:"minutes"},{label:"Last Hour",value:1,unit:"hours"},{label:"Last 4 Hours",value:4,unit:"hours"},{label:"Last 24 Hours",value:24,unit:"hours"},{label:"Last 7 Days",value:7,unit:"days"}]])},257486,624001,207066,337767,237062,e=>{"use strict";var t=e.i(97859);function s(e,s){let a=(s||"").trim();if(t.MCP_CALL_TYPES.includes(e))return a.replace(/^mcp:\s*/i,"").split("/").pop()||a||"mcp_tool";let l=(a.split("/").pop()||a).replace(/-20\d{6}.*$/i,"").replace(/:.*$/,""),r=l.match(/claude-[a-z0-9-]+/i);return r?r[0]:l||"llm_call"}e.s(["getEventDisplayName",()=>s],257486);var a=e.i(843476),l=e.i(464571),r=e.i(770914),i=e.i(262218),n=e.i(592968),o=e.i(898586),d=e.i(149192),c=e.i(536591);e.s(["UpOutlined",()=>c.default],624001);var c=c,m=e.i(755151),x=e.i(166540),u=e.i(916925);let p="16px 24px",h="Escape",g="monospace",f="#f0f0f0",y="#fff";e.s(["API_BASE_MAX_WIDTH",0,200,"COLOR_BACKGROUND",0,y,"COLOR_BG_LIGHT",0,"#fafafa","COLOR_BORDER",0,f,"DEFAULT_MAX_WIDTH",0,180,"DRAWER_CONTENT_PADDING",0,"24px","DRAWER_HEADER_PADDING",0,p,"DRAWER_WIDTH",0,"60%","FONT_FAMILY_MONO",0,g,"FONT_SIZE_HEADER",0,16,"FONT_SIZE_MEDIUM",0,13,"FONT_SIZE_SMALL",0,12,"JSON_MAX_HEIGHT",0,400,"KEY_ESCAPE",0,h,"KEY_J_LOWER",0,"j","KEY_J_UPPER",0,"J","KEY_K_LOWER",0,"k","KEY_K_UPPER",0,"K","METADATA_MAX_HEIGHT",0,300,"SPACING_LARGE",0,12,"SPACING_MEDIUM",0,8,"SPACING_SMALL",0,4,"SPACING_XLARGE",0,16,"TAB_REQUEST",0,"request","TAB_RESPONSE",0,"response"],207066);let{Text:j}=o.Typography;function b({log:e,onClose:t,onPrevious:s,onNext:l,statusLabel:r,statusColor:i,environment:n}){let o=e.custom_llm_provider||"",d=o?(0,u.getProviderLogoAndName)(o):null;return(0,a.jsxs)("div",{style:{padding:p,borderBottom:`1px solid ${f}`,backgroundColor:y,position:"sticky",top:0,zIndex:10},children:[(0,a.jsx)(v,{model:e.model,providerLogo:d?.logo,providerName:d?.displayName}),(0,a.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:8},children:[(0,a.jsx)(_,{requestId:e.request_id}),(0,a.jsx)(N,{onPrevious:s,onNext:l,onClose:t})]}),(0,a.jsx)(w,{log:e,statusLabel:r,statusColor:i,environment:n})]})}function v({model:e,providerLogo:t,providerName:s}){return(0,a.jsxs)(r.Space,{size:8,style:{marginBottom:8},children:[t&&(0,a.jsx)("img",{src:t,alt:s||"Provider",style:{width:24,height:24},onError:e=>{e.target.style.display="none"}}),(0,a.jsxs)(r.Space,{size:8,direction:"horizontal",children:[(0,a.jsx)(j,{strong:!0,style:{fontSize:14},children:e}),s&&(0,a.jsx)(j,{type:"secondary",style:{fontSize:12},children:s})]})]})}function _({requestId:e}){return(0,a.jsx)("div",{style:{flex:1,minWidth:0},children:(0,a.jsx)(n.Tooltip,{title:e,children:(0,a.jsx)(j,{strong:!0,copyable:{text:e,tooltips:["Copy Request ID","Copied!"]},style:{fontSize:16,fontFamily:g,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",display:"block"},children:e})})})}function N({onPrevious:e,onNext:t,onClose:s}){let i={border:"1px solid #d9d9d9",borderRadius:4,padding:"0 4px",fontSize:12,fontFamily:"monospace",marginLeft:4,background:"#fafafa"};return(0,a.jsxs)(r.Space,{size:4,split:(0,a.jsx)("div",{style:{width:1,height:20,background:f}}),children:[(0,a.jsxs)(l.Button,{type:"text",size:"small",onClick:e,children:[(0,a.jsx)(c.default,{}),(0,a.jsx)("span",{style:i,children:"K"})]}),(0,a.jsxs)(l.Button,{type:"text",size:"small",onClick:t,children:[(0,a.jsx)(m.DownOutlined,{}),(0,a.jsx)("span",{style:i,children:"J"})]}),(0,a.jsx)(n.Tooltip,{title:"ESC to close",children:(0,a.jsx)(l.Button,{type:"text",icon:(0,a.jsx)(d.CloseOutlined,{}),onClick:s})})]})}function w({log:e,statusLabel:t,statusColor:s,environment:l}){return(0,a.jsxs)(r.Space,{size:12,children:[(0,a.jsx)(i.Tag,{color:s,children:t}),(0,a.jsxs)(i.Tag,{children:["Env: ",l]}),(0,a.jsxs)(r.Space,{size:8,children:[(0,a.jsx)(j,{type:"secondary",style:{fontSize:13},children:(0,x.default)(e.startTime).format("MMM D, YYYY h:mm:ss A")}),(0,a.jsxs)(j,{type:"secondary",style:{fontSize:13},children:["(",(0,x.default)(e.startTime).fromNow(),")"]})]})]})}e.s(["DrawerHeader",()=>b],337767);var S=e.i(271645);function k({isOpen:e,currentLog:t,allLogs:s,onClose:a,onSelectLog:l}){(0,S.useEffect)(()=>{let t=t=>{var s;if(!((s=t.target)instanceof HTMLInputElement||s instanceof HTMLTextAreaElement)&&e)switch(t.key){case h:a();break;case"j":case"J":i();break;case"k":case"K":r()}};return window.addEventListener("keydown",t),()=>window.removeEventListener("keydown",t)},[e,t,s]);let r=()=>{if(!t||!s.length||!l)return;let e=s.findIndex(e=>e.request_id===t.request_id);e{if(!t||!s.length||!l)return;let e=s.findIndex(e=>e.request_id===t.request_id);e>0&&l(s[e-1])};return{selectNextLog:r,selectPreviousLog:i}}e.s(["useKeyboardNavigation",()=>k],237062)},517442,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(592968);let l=e=>e>=.8?"text-green-600":"text-yellow-600",r=({entities:e})=>{let[a,r]=(0,s.useState)(!0),[i,n]=(0,s.useState)({});return e&&0!==e.length?(0,t.jsxs)("div",{className:"mt-4",children:[(0,t.jsxs)("div",{className:"flex items-center mb-2 cursor-pointer",onClick:()=>r(!a),children:[(0,t.jsx)("svg",{className:`w-5 h-5 mr-2 transition-transform ${a?"transform rotate-90":""}`,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"})}),(0,t.jsxs)("h4",{className:"font-medium",children:["Detected Entities (",e.length,")"]})]}),a&&(0,t.jsx)("div",{className:"space-y-2",children:e.map((e,s)=>{let a=i[s]||!1;return(0,t.jsxs)("div",{className:"border rounded-lg overflow-hidden",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between p-3 bg-gray-50 cursor-pointer hover:bg-gray-100",onClick:()=>{n(e=>({...e,[s]:!e[s]}))},children:[(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)("svg",{className:`w-5 h-5 mr-2 transition-transform ${a?"transform rotate-90":""}`,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"})}),(0,t.jsx)("span",{className:"font-medium mr-2",children:e.entity_type}),(0,t.jsxs)("span",{className:`font-mono ${l(e.score)}`,children:["Score: ",e.score.toFixed(2)]})]}),(0,t.jsxs)("span",{className:"text-xs text-gray-500",children:["Position: ",e.start,"-",e.end]})]}),a&&(0,t.jsx)("div",{className:"p-3 border-t bg-white",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4 mb-2",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Entity Type:"}),(0,t.jsx)("span",{children:e.entity_type})]}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Position:"}),(0,t.jsxs)("span",{children:["Characters ",e.start,"-",e.end]})]}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Confidence:"}),(0,t.jsx)("span",{className:l(e.score),children:e.score.toFixed(2)})]})]}),(0,t.jsxs)("div",{className:"space-y-2",children:[e.recognition_metadata&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Recognizer:"}),(0,t.jsx)("span",{children:e.recognition_metadata.recognizer_name})]}),(0,t.jsxs)("div",{className:"flex overflow-hidden",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Identifier:"}),(0,t.jsx)("span",{className:"truncate text-xs font-mono",children:e.recognition_metadata.recognizer_identifier})]})]}),e.analysis_explanation&&(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Explanation:"}),(0,t.jsx)("span",{children:e.analysis_explanation})]})]})]})})]},s)})})]}):null},i=(e,s="slate")=>(0,t.jsx)("span",{className:`px-2 py-1 rounded-md text-xs font-medium inline-block ${{green:"bg-green-100 text-green-800",red:"bg-red-100 text-red-800",blue:"bg-blue-50 text-blue-700",slate:"bg-slate-100 text-slate-800",amber:"bg-amber-100 text-amber-800"}[s]}`,children:e}),n=e=>e?i("detected","red"):i("not detected","slate"),o=({title:e,count:a,defaultOpen:l=!0,right:r,children:i})=>{let[n,o]=(0,s.useState)(l);return(0,t.jsxs)("div",{className:"border rounded-lg overflow-hidden",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between p-3 bg-gray-50 cursor-pointer hover:bg-gray-100",onClick:()=>o(e=>!e),children:[(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)("svg",{className:`w-5 h-5 mr-2 transition-transform ${n?"transform rotate-90":""}`,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"})}),(0,t.jsxs)("h5",{className:"font-medium",children:[e," ","number"==typeof a&&(0,t.jsxs)("span",{className:"text-gray-500 font-normal",children:["(",a,")"]})]})]}),(0,t.jsx)("div",{children:r})]}),n&&(0,t.jsx)("div",{className:"p-3 border-t bg-white",children:i})]})},d=({label:e,children:s,mono:a})=>(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:e}),(0,t.jsx)("span",{className:a?"font-mono text-sm break-all":"",children:s})]}),c=()=>(0,t.jsx)("div",{className:"my-3 border-t"}),m=({response:e})=>{if(!e)return null;let s=e.outputs??e.output??[],a="GUARDRAIL_INTERVENED"===e.action?"red":"green",l=(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[e.guardrailCoverage?.textCharacters&&i(`text guarded ${e.guardrailCoverage.textCharacters.guarded??0}/${e.guardrailCoverage.textCharacters.total??0}`,"blue"),e.guardrailCoverage?.images&&i(`images guarded ${e.guardrailCoverage.images.guarded??0}/${e.guardrailCoverage.images.total??0}`,"blue")]}),r=e.usage&&(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:Object.entries(e.usage).map(([e,s])=>"number"==typeof s?(0,t.jsxs)("span",{className:"px-2 py-1 bg-slate-100 text-slate-800 rounded-md text-xs font-medium",children:[e,": ",s]},e):null)});return(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"border rounded-lg p-4",children:[(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)(d,{label:"Action:",children:i(e.action??"N/A",a)}),e.actionReason&&(0,t.jsx)(d,{label:"Action Reason:",children:e.actionReason}),e.blockedResponse&&(0,t.jsx)(d,{label:"Blocked Response:",children:(0,t.jsx)("span",{className:"italic",children:e.blockedResponse})})]}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)(d,{label:"Coverage:",children:l}),(0,t.jsx)(d,{label:"Usage:",children:r})]})]}),s.length>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(c,{}),(0,t.jsx)("h4",{className:"font-medium mb-2",children:"Outputs"}),(0,t.jsx)("div",{className:"space-y-2",children:s.map((e,s)=>(0,t.jsx)("div",{className:"p-3 bg-gray-50 rounded-md",children:(0,t.jsx)("div",{className:"text-sm whitespace-pre-wrap",children:e.text??(0,t.jsx)("em",{children:"(non-text output)"})})},s))})]})]}),e.assessments?.length?(0,t.jsx)("div",{className:"space-y-3",children:e.assessments.map((e,s)=>{let a=(0,t.jsxs)("div",{className:"flex flex-wrap gap-1",children:[e.wordPolicy&&i("word","slate"),e.contentPolicy&&i("content","slate"),e.topicPolicy&&i("topic","slate"),e.sensitiveInformationPolicy&&i("sensitive-info","slate"),e.contextualGroundingPolicy&&i("contextual-grounding","slate"),e.automatedReasoningPolicy&&i("automated-reasoning","slate")]});return(0,t.jsxs)(o,{title:`Assessment #${s+1}`,defaultOpen:!0,right:(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[e.invocationMetrics?.guardrailProcessingLatency!=null&&i(`${e.invocationMetrics.guardrailProcessingLatency} ms`,"amber"),a]}),children:[e.wordPolicy&&(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h6",{className:"font-medium mb-2",children:"Word Policy"}),(e.wordPolicy.customWords?.length??0)>0&&(0,t.jsx)(o,{title:"Custom Words",defaultOpen:!0,children:(0,t.jsx)("div",{className:"space-y-2",children:e.wordPolicy.customWords.map((e,s)=>(0,t.jsxs)("div",{className:"flex justify-between items-center p-2 bg-gray-50 rounded",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[i(e.action??"N/A",e.detected?"red":"slate"),(0,t.jsx)("span",{className:"font-mono text-sm break-all",children:e.match})]}),n(e.detected)]},s))})}),(e.wordPolicy.managedWordLists?.length??0)>0&&(0,t.jsx)(o,{title:"Managed Word Lists",defaultOpen:!1,children:(0,t.jsx)("div",{className:"space-y-2",children:e.wordPolicy.managedWordLists.map((e,s)=>(0,t.jsxs)("div",{className:"flex justify-between items-center p-2 bg-gray-50 rounded",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[i(e.action??"N/A",e.detected?"red":"slate"),(0,t.jsx)("span",{className:"font-mono text-sm break-all",children:e.match}),e.type&&i(e.type,"slate")]}),n(e.detected)]},s))})})]}),e.contentPolicy?.filters?.length?(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h6",{className:"font-medium mb-2",children:"Content Policy"}),(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)("table",{className:"min-w-full text-sm",children:[(0,t.jsx)("thead",{children:(0,t.jsxs)("tr",{className:"text-left text-gray-600",children:[(0,t.jsx)("th",{className:"py-1 pr-4",children:"Type"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Action"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Detected"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Strength"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Confidence"})]})}),(0,t.jsx)("tbody",{children:e.contentPolicy.filters.map((e,s)=>(0,t.jsxs)("tr",{className:"border-t",children:[(0,t.jsx)("td",{className:"py-1 pr-4",children:e.type??"—"}),(0,t.jsx)("td",{className:"py-1 pr-4",children:i(e.action??"—",e.detected?"red":"slate")}),(0,t.jsx)("td",{className:"py-1 pr-4",children:n(e.detected)}),(0,t.jsx)("td",{className:"py-1 pr-4",children:e.filterStrength??"—"}),(0,t.jsx)("td",{className:"py-1 pr-4",children:e.confidence??"—"})]},s))})]})})]}):null,e.contextualGroundingPolicy?.filters?.length?(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h6",{className:"font-medium mb-2",children:"Contextual Grounding"}),(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)("table",{className:"min-w-full text-sm",children:[(0,t.jsx)("thead",{children:(0,t.jsxs)("tr",{className:"text-left text-gray-600",children:[(0,t.jsx)("th",{className:"py-1 pr-4",children:"Type"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Action"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Detected"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Score"}),(0,t.jsx)("th",{className:"py-1 pr-4",children:"Threshold"})]})}),(0,t.jsx)("tbody",{children:e.contextualGroundingPolicy.filters.map((e,s)=>(0,t.jsxs)("tr",{className:"border-t",children:[(0,t.jsx)("td",{className:"py-1 pr-4",children:e.type??"—"}),(0,t.jsx)("td",{className:"py-1 pr-4",children:i(e.action??"—",e.detected?"red":"slate")}),(0,t.jsx)("td",{className:"py-1 pr-4",children:n(e.detected)}),(0,t.jsx)("td",{className:"py-1 pr-4",children:e.score??"—"}),(0,t.jsx)("td",{className:"py-1 pr-4",children:e.threshold??"—"})]},s))})]})})]}):null,e.sensitiveInformationPolicy&&(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h6",{className:"font-medium mb-2",children:"Sensitive Information"}),(e.sensitiveInformationPolicy.piiEntities?.length??0)>0&&(0,t.jsx)(o,{title:"PII Entities",defaultOpen:!0,children:(0,t.jsx)("div",{className:"space-y-2",children:e.sensitiveInformationPolicy.piiEntities.map((e,s)=>(0,t.jsxs)("div",{className:"flex justify-between items-center p-2 bg-gray-50 rounded",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[i(e.action??"N/A",e.detected?"red":"slate"),e.type&&i(e.type,"slate"),(0,t.jsx)("span",{className:"font-mono text-xs break-all",children:e.match})]}),n(e.detected)]},s))})}),(e.sensitiveInformationPolicy.regexes?.length??0)>0&&(0,t.jsx)(o,{title:"Custom Regexes",defaultOpen:!1,children:(0,t.jsx)("div",{className:"space-y-2",children:e.sensitiveInformationPolicy.regexes.map((e,s)=>(0,t.jsxs)("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between p-2 bg-gray-50 rounded gap-1",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[i(e.action??"N/A",e.detected?"red":"slate"),(0,t.jsx)("span",{className:"font-medium",children:e.name??"regex"}),(0,t.jsx)("span",{className:"font-mono text-xs break-all",children:e.regex})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[n(e.detected),e.match&&(0,t.jsx)("span",{className:"font-mono text-xs break-all",children:e.match})]})]},s))})})]}),e.topicPolicy?.topics?.length?(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h6",{className:"font-medium mb-2",children:"Topic Policy"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:e.topicPolicy.topics.map((e,s)=>(0,t.jsx)("div",{className:"px-3 py-1.5 bg-gray-50 rounded-md text-xs",children:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[i(e.action??"N/A",e.detected?"red":"slate"),(0,t.jsx)("span",{className:"font-medium",children:e.name??"topic"}),e.type&&i(e.type,"slate"),n(e.detected)]})},s))})]}):null,e.invocationMetrics&&(0,t.jsx)(o,{title:"Invocation Metrics",defaultOpen:!1,children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)(d,{label:"Latency (ms)",children:e.invocationMetrics.guardrailProcessingLatency??"—"}),(0,t.jsx)(d,{label:"Coverage:",children:(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[e.invocationMetrics.guardrailCoverage?.textCharacters&&i(`text ${e.invocationMetrics.guardrailCoverage.textCharacters.guarded??0}/${e.invocationMetrics.guardrailCoverage.textCharacters.total??0}`,"blue"),e.invocationMetrics.guardrailCoverage?.images&&i(`images ${e.invocationMetrics.guardrailCoverage.images.guarded??0}/${e.invocationMetrics.guardrailCoverage.images.total??0}`,"blue")]})})]}),(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsx)(d,{label:"Usage:",children:(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:e.invocationMetrics.usage&&Object.entries(e.invocationMetrics.usage).map(([e,s])=>"number"==typeof s?(0,t.jsxs)("span",{className:"px-2 py-1 bg-slate-100 text-slate-800 rounded-md text-xs font-medium",children:[e,": ",s]},e):null)})})})]})}),e.automatedReasoningPolicy?.findings?.length?(0,t.jsx)(o,{title:"Automated Reasoning Findings",defaultOpen:!1,children:(0,t.jsx)("div",{className:"space-y-2",children:e.automatedReasoningPolicy.findings.map((e,s)=>(0,t.jsx)("pre",{className:"bg-gray-50 rounded p-2 text-xs overflow-x-auto",children:JSON.stringify(e,null,2)},s))})}):null]},s)})}):null,(0,t.jsx)(o,{title:"Raw Bedrock Guardrail Response",defaultOpen:!1,children:(0,t.jsx)("pre",{className:"bg-gray-50 rounded p-3 text-xs overflow-x-auto",children:JSON.stringify(e,null,2)})})]})},x=(e,s="slate")=>(0,t.jsx)("span",{className:`px-2 py-1 rounded-md text-xs font-medium inline-block ${{green:"bg-green-100 text-green-800",red:"bg-red-100 text-red-800",blue:"bg-blue-50 text-blue-700",slate:"bg-slate-100 text-slate-800",amber:"bg-amber-100 text-amber-800"}[s]}`,children:e}),u=({title:e,count:a,defaultOpen:l=!0,children:r})=>{let[i,n]=(0,s.useState)(l);return(0,t.jsxs)("div",{className:"border rounded-lg overflow-hidden",children:[(0,t.jsx)("div",{className:"flex items-center justify-between p-3 bg-gray-50 cursor-pointer hover:bg-gray-100",onClick:()=>n(e=>!e),children:(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)("svg",{className:`w-5 h-5 mr-2 transition-transform ${i?"transform rotate-90":""}`,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"})}),(0,t.jsxs)("h5",{className:"font-medium",children:[e," ","number"==typeof a&&(0,t.jsxs)("span",{className:"text-gray-500 font-normal",children:["(",a,")"]})]})]})}),i&&(0,t.jsx)("div",{className:"p-3 border-t bg-white",children:r})]})},p=({label:e,children:s,mono:a})=>(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:e}),(0,t.jsx)("span",{className:a?"font-mono text-sm break-all":"",children:s})]}),h=({response:e})=>{if(!e||"string"==typeof e)return"string"==typeof e&&e?(0,t.jsx)("div",{className:"bg-white rounded-lg border border-red-200 p-4",children:(0,t.jsxs)("div",{className:"text-red-800",children:[(0,t.jsx)("h5",{className:"font-medium mb-2",children:"Error"}),(0,t.jsx)("p",{className:"text-sm",children:e})]})}):null;let s=Array.isArray(e)?e:[];if(0===s.length)return(0,t.jsx)("div",{className:"bg-white rounded-lg border border-gray-200 p-4",children:(0,t.jsx)("div",{className:"text-gray-600 text-sm",children:"No detections found"})});let a=s.filter(e=>"pattern"===e.type),l=s.filter(e=>"blocked_word"===e.type),r=s.filter(e=>"category_keyword"===e.type),i=s.filter(e=>"BLOCK"===e.action).length,n=s.filter(e=>"MASK"===e.action).length,o=s.length;return(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsx)("div",{className:"bg-white rounded-lg border border-gray-200 p-4",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)(p,{label:"Total Detections:",children:(0,t.jsx)("span",{className:"font-semibold",children:o})}),(0,t.jsx)(p,{label:"Actions:",children:(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[i>0&&x(`${i} blocked`,"red"),n>0&&x(`${n} masked`,"blue"),0===i&&0===n&&x("passed","green")]})})]}),(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsx)(p,{label:"By Type:",children:(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[a.length>0&&x(`${a.length} patterns`,"slate"),l.length>0&&x(`${l.length} keywords`,"slate"),r.length>0&&x(`${r.length} categories`,"slate")]})})})]})}),a.length>0&&(0,t.jsx)(u,{title:"Patterns Matched",count:a.length,defaultOpen:!0,children:(0,t.jsx)("div",{className:"space-y-2",children:a.map((e,s)=>(0,t.jsx)("div",{className:"p-3 bg-gray-50 rounded-md",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsx)("div",{className:"space-y-1",children:(0,t.jsx)(p,{label:"Pattern:",children:e.pattern_name||"unknown"})}),(0,t.jsx)("div",{className:"space-y-1",children:(0,t.jsx)(p,{label:"Action:",children:x(e.action,"BLOCK"===e.action?"red":"blue")})})]})},s))})}),l.length>0&&(0,t.jsx)(u,{title:"Blocked Words Detected",count:l.length,defaultOpen:!0,children:(0,t.jsx)("div",{className:"space-y-2",children:l.map((e,s)=>(0,t.jsx)("div",{className:"p-3 bg-gray-50 rounded-md",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-1",children:[(0,t.jsx)(p,{label:"Keyword:",mono:!0,children:e.keyword||"unknown"}),e.description&&(0,t.jsx)(p,{label:"Description:",children:e.description})]}),(0,t.jsx)("div",{className:"space-y-1",children:(0,t.jsx)(p,{label:"Action:",children:x(e.action,"BLOCK"===e.action?"red":"blue")})})]})},s))})}),r.length>0&&(0,t.jsx)(u,{title:"Category Keywords Detected",count:r.length,defaultOpen:!0,children:(0,t.jsx)("div",{className:"space-y-2",children:r.map((e,s)=>(0,t.jsx)("div",{className:"p-3 bg-gray-50 rounded-md",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-1",children:[(0,t.jsx)(p,{label:"Category:",children:e.category||"unknown"}),(0,t.jsx)(p,{label:"Keyword:",mono:!0,children:e.keyword||"unknown"}),e.severity&&(0,t.jsx)(p,{label:"Severity:",children:x(e.severity,"high"===e.severity?"red":"medium"===e.severity?"amber":"slate")})]}),(0,t.jsx)("div",{className:"space-y-1",children:(0,t.jsx)(p,{label:"Action:",children:x(e.action,"BLOCK"===e.action?"red":"blue")})})]})},s))})}),(0,t.jsx)(u,{title:"Raw Detection Data",defaultOpen:!1,children:(0,t.jsx)("pre",{className:"bg-gray-50 rounded p-3 text-xs overflow-x-auto",children:JSON.stringify(s,null,2)})})]})};var g=e.i(764205);let f=()=>(0,t.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:[(0,t.jsx)("circle",{cx:"8",cy:"8",r:"7",stroke:"#16A34A",strokeWidth:"1.5",fill:"#F0FDF4"}),(0,t.jsx)("path",{d:"M5 8l2 2 4-4",stroke:"#16A34A",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})]}),y=()=>(0,t.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:[(0,t.jsx)("circle",{cx:"8",cy:"8",r:"7",stroke:"#DC2626",strokeWidth:"1.5",fill:"#FEF2F2"}),(0,t.jsx)("path",{d:"M6 6l4 4M10 6l-4 4",stroke:"#DC2626",strokeWidth:"1.5",strokeLinecap:"round"})]}),j=()=>(0,t.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",className:"animate-spin",children:[(0,t.jsx)("circle",{cx:"8",cy:"8",r:"6",stroke:"#D1D5DB",strokeWidth:"2"}),(0,t.jsx)("path",{d:"M8 2a6 6 0 0 1 6 6",stroke:"#6366F1",strokeWidth:"2",strokeLinecap:"round"})]}),b=({title:e,data:l,loading:r,error:i})=>{let[n,o]=(0,s.useState)(!1);return(0,t.jsxs)("div",{className:"border border-gray-200 rounded-lg bg-white",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-4 py-3 cursor-pointer hover:bg-gray-50 transition-colors",onClick:()=>o(!n),children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[r?(0,t.jsx)(j,{}):i?(0,t.jsx)(a.Tooltip,{title:i,children:(0,t.jsx)("span",{className:"text-gray-400 text-sm",children:"--"})}):l?.compliant?(0,t.jsx)(f,{}):(0,t.jsx)(y,{}),(0,t.jsx)("span",{className:"font-medium text-sm text-gray-900",children:e})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[!r&&!i&&l&&(0,t.jsx)("span",{className:`px-2 py-0.5 rounded text-[11px] font-semibold uppercase ${l.compliant?"bg-green-100 text-green-700 border border-green-200":"bg-red-100 text-red-700 border border-red-200"}`,children:l.compliant?"COMPLIANT":"NON-COMPLIANT"}),i&&(0,t.jsx)("span",{className:"px-2 py-0.5 rounded text-[11px] font-medium bg-gray-100 text-gray-500 border border-gray-200",children:"UNAVAILABLE"}),(0,t.jsx)("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"none",className:`transition-transform ${n?"rotate-180":""}`,children:(0,t.jsx)("path",{d:"M6 8l4 4 4-4",stroke:"#6B7280",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]})]}),n&&(0,t.jsxs)("div",{className:"border-t border-gray-100 px-4 py-3",children:[r&&(0,t.jsx)("p",{className:"text-sm text-gray-500",children:"Checking compliance..."}),i&&(0,t.jsx)("p",{className:"text-sm text-red-600",children:i}),l&&(0,t.jsx)("div",{className:"space-y-2",children:l.checks.map((e,s)=>(0,t.jsxs)("div",{className:"flex items-start gap-2",children:[(0,t.jsx)("div",{className:"flex-shrink-0 mt-0.5",children:e.passed?(0,t.jsx)(f,{}):(0,t.jsx)(y,{})}),(0,t.jsxs)("div",{className:"min-w-0",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900",children:e.check_name}),(0,t.jsx)("span",{className:"text-[10px] font-mono text-gray-400",children:e.article})]}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5",children:e.detail})]})]},s))})]})]})},v=({accessToken:e,logEntry:a})=>{let[l,r]=(0,s.useState)(null),[i,n]=(0,s.useState)(null),[o,d]=(0,s.useState)(!1),[c,m]=(0,s.useState)(!1),[x,u]=(0,s.useState)(null),[p,h]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(!e||!a.request_id)return;let t={request_id:a.request_id,user_id:a.user,model:a.model,timestamp:a.startTime,guardrail_information:a.metadata?.guardrail_information};d(!0),u(null),(0,g.checkEuAiActCompliance)(e,t).then(r).catch(e=>u(e.message||"Failed to check EU AI Act compliance")).finally(()=>d(!1)),m(!0),h(null),(0,g.checkGdprCompliance)(e,t).then(n).catch(e=>h(e.message||"Failed to check GDPR compliance")).finally(()=>m(!1))},[e,a]),(0,t.jsxs)("div",{children:[(0,t.jsx)("h4",{className:"text-xs font-semibold text-gray-500 uppercase tracking-wider mb-4",children:"Regulatory Compliance"}),(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsx)(b,{title:"EU AI Act",data:l,loading:o,error:x}),(0,t.jsx)(b,{title:"GDPR",data:i,loading:c,error:p})]})]})},_=new Set(["presidio","bedrock","litellm_content_filter"]),N=e=>Object.values(e.masked_entity_count||{}).reduce((e,t)=>e+("number"==typeof t?t:0),0),w=e=>"success"===(e.guardrail_status??"").toLowerCase(),S=e=>e.policy_template||e.guardrail_name,k=()=>(0,t.jsxs)("svg",{width:"40",height:"40",viewBox:"0 0 40 40",fill:"none",children:[(0,t.jsx)("circle",{cx:"20",cy:"20",r:"20",fill:"#EEF2FF"}),(0,t.jsx)("path",{d:"M20 10l8 4v6c0 5.25-3.4 10.15-8 11.5C15.4 30.15 12 25.25 12 20v-6l8-4z",stroke:"#6366F1",strokeWidth:"1.5",fill:"none"}),(0,t.jsx)("path",{d:"M16 20l3 3 5-6",stroke:"#6366F1",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",fill:"none"})]}),C=({className:e})=>(0,t.jsxs)("svg",{width:"22",height:"22",viewBox:"0 0 22 22",fill:"none",className:e,children:[(0,t.jsx)("circle",{cx:"11",cy:"11",r:"10",stroke:"#16A34A",strokeWidth:"1.5",fill:"#F0FDF4"}),(0,t.jsx)("path",{d:"M7 11l3 3 5-6",stroke:"#16A34A",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})]}),T=({className:e})=>(0,t.jsxs)("svg",{width:"22",height:"22",viewBox:"0 0 22 22",fill:"none",className:e,children:[(0,t.jsx)("circle",{cx:"11",cy:"11",r:"10",stroke:"#DC2626",strokeWidth:"1.5",fill:"#FEF2F2"}),(0,t.jsx)("path",{d:"M8 8l6 6M14 8l-6 6",stroke:"#DC2626",strokeWidth:"1.5",strokeLinecap:"round"})]}),L=()=>(0,t.jsxs)("svg",{width:"22",height:"22",viewBox:"0 0 22 22",fill:"none",children:[(0,t.jsx)("circle",{cx:"11",cy:"11",r:"10",stroke:"#3B82F6",strokeWidth:"1.5",fill:"#EFF6FF"}),(0,t.jsx)("path",{d:"M9 7.5l6 3.5-6 3.5V7.5z",fill:"#3B82F6"})]}),M=()=>(0,t.jsx)("svg",{width:"22",height:"22",viewBox:"0 0 22 22",fill:"none",children:(0,t.jsx)("circle",{cx:"11",cy:"11",r:"5",fill:"#9CA3AF"})}),E=({expanded:e})=>(0,t.jsx)("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"none",className:`transition-transform ${e?"rotate-180":""}`,children:(0,t.jsx)("path",{d:"M6 8l4 4 4-4",stroke:"#6B7280",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})}),A=()=>(0,t.jsx)("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:(0,t.jsx)("path",{d:"M8 2v8m0 0l-3-3m3 3l3-3M3 12h10",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})}),D=({matchDetails:e})=>e&&0!==e.length?(0,t.jsxs)("div",{className:"mt-3",children:[(0,t.jsxs)("h5",{className:"text-sm font-medium mb-2 text-gray-700",children:["Match Details (",e.length,")"]}),(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)("table",{className:"w-full text-sm",children:[(0,t.jsx)("thead",{children:(0,t.jsxs)("tr",{className:"border-b text-left text-gray-500",children:[(0,t.jsx)("th",{className:"pb-2 pr-4 font-medium",children:"Type"}),(0,t.jsx)("th",{className:"pb-2 pr-4 font-medium",children:"Method"}),(0,t.jsx)("th",{className:"pb-2 pr-4 font-medium",children:"Action"}),(0,t.jsx)("th",{className:"pb-2 font-medium",children:"Detail"})]})}),(0,t.jsx)("tbody",{children:e.map((e,s)=>(0,t.jsxs)("tr",{className:"border-b border-gray-100",children:[(0,t.jsx)("td",{className:"py-2 pr-4",children:e.type}),(0,t.jsx)("td",{className:"py-2 pr-4",children:(0,t.jsx)("span",{className:"px-2 py-0.5 bg-slate-100 text-slate-700 rounded text-xs",children:e.detection_method??"-"})}),(0,t.jsx)("td",{className:"py-2 pr-4",children:(0,t.jsx)("span",{className:`px-2 py-0.5 rounded text-xs font-medium ${"BLOCK"===e.action_taken?"bg-red-100 text-red-800":"bg-blue-50 text-blue-700"}`,children:e.action_taken??"-"})}),(0,t.jsxs)("td",{className:"py-2 font-mono text-xs text-gray-600 break-all",children:[e.category?`[${e.category}] `:"",e.snippet??"-"]})]},s))})]})})]}):null,I=({response:e})=>{let[a,l]=(0,s.useState)(!1);return(0,t.jsx)("div",{className:"mt-3",children:(0,t.jsxs)("div",{className:"border rounded-lg overflow-hidden",children:[(0,t.jsx)("div",{className:"flex items-center justify-between p-3 bg-gray-50 cursor-pointer hover:bg-gray-100",onClick:()=>l(!a),children:(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)(E,{expanded:a}),(0,t.jsx)("h5",{className:"font-medium text-sm ml-1",children:"Raw Guardrail Response"})]})}),a&&(0,t.jsx)("div",{className:"p-3 border-t bg-white",children:(0,t.jsx)("pre",{className:"bg-gray-50 rounded p-3 text-xs overflow-x-auto",children:JSON.stringify(e,null,2)})})]})})},O=({entries:e})=>{let a=(0,s.useMemo)(()=>[...e].sort((e,t)=>(e.start_time??0)-(t.start_time??0)),[e]),l=(0,s.useMemo)(()=>{if(0===a.length)return[];let e=a[0].start_time,t=[];t.push({type:"request",label:"Request received",offsetMs:0});let s=a.filter(e=>"pre_call"===e.guardrail_mode),l=a.filter(e=>"post_call"===e.guardrail_mode||"logging_only"===e.guardrail_mode),r=a.filter(e=>"during_call"===e.guardrail_mode);for(let a of s){let s=Math.round((a.end_time-e)*1e3);t.push({type:"guardrail",label:`Pre-call guardrail: ${S(a)}`,offsetMs:s,status:w(a)?"PASSED":"FAILED",isSuccess:w(a)})}let i=s.length>0?Math.max(...s.map(e=>e.end_time)):e,n=Math.round((((l.length>0?Math.min(...l.map(e=>e.start_time)):void 0)??i+1)-e)*1e3);for(let s of(t.push({type:"llm",label:"LLM call",offsetMs:n}),r)){let a=Math.round((s.end_time-e)*1e3);t.push({type:"guardrail",label:`During-call guardrail: ${S(s)}`,offsetMs:a,status:w(s)?"PASSED":"FAILED",isSuccess:w(s)})}for(let s of l){let a=Math.round((s.end_time-e)*1e3);t.push({type:"guardrail",label:`Post-call guardrail: ${S(s)}`,offsetMs:a,status:w(s)?"PASSED":"FAILED",isSuccess:w(s)})}let o=Math.round((Math.max(...a.map(e=>e.end_time))-e)*1e3)+1;return t.push({type:"response",label:"Response returned",offsetMs:o}),t},[a]);return(0,t.jsxs)("div",{children:[(0,t.jsx)("h4",{className:"text-xs font-semibold text-gray-500 uppercase tracking-wider mb-4",children:"Request Lifecycle"}),(0,t.jsx)("div",{className:"relative",children:l.map((e,s)=>(0,t.jsxs)("div",{className:"flex items-start gap-3 relative",children:[(0,t.jsxs)("div",{className:"flex flex-col items-center",children:[(0,t.jsx)("div",{className:"flex-shrink-0",children:"request"===e.type||"response"===e.type?(0,t.jsx)(M,{}):"llm"===e.type?(0,t.jsx)(L,{}):e.isSuccess?(0,t.jsx)(C,{}):(0,t.jsx)(T,{})}),s{var l;let i,[n,o]=(0,s.useState)(!1),d=w(e),c=N(e),x=S(e),u=(i=Math.round(1e3*e.duration),`${i}ms`),p=null==(l=e.guardrail_mode)||""===l?"—":("string"==typeof l?l:String(l)).replace(/_/g,"-").toUpperCase(),g=(e=>{if(!w(e))return null;if(null!=e.risk_score)return e.risk_score;let t=N(e),s=e.patterns_checked??0,a=e.confidence_score??0;if(0===s&&0===a)return 0;let l=7*(s>0?t/s:0)+3*a;return t>0&&l<2&&(l=2),Math.min(10,Math.round(10*l)/10)})(e),f=e.guardrail_provider??"presidio",y=e.guardrail_response,j=Array.isArray(y)?y:[],b="bedrock"!==f||null===y||"object"!=typeof y||Array.isArray(y)?void 0:y,v=null!=e.patterns_checked?`${c}/${e.patterns_checked} matched`:c>0?`${c} matched`:null;return(0,t.jsxs)("div",{className:"border border-gray-200 rounded-lg bg-white",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3 px-4 py-3 cursor-pointer hover:bg-gray-50 transition-colors",onClick:()=>o(!n),children:[(0,t.jsx)("div",{className:"flex-shrink-0",children:d?(0,t.jsx)(C,{}):(0,t.jsx)(T,{})}),(0,t.jsxs)("div",{className:"flex items-center gap-2 flex-wrap flex-1 min-w-0",children:[(0,t.jsx)("span",{className:"font-semibold text-gray-900 text-sm truncate",children:x}),(0,t.jsx)("span",{className:"px-2 py-0.5 border border-blue-200 bg-blue-50 text-blue-700 rounded text-[11px] font-semibold uppercase flex-shrink-0",children:p}),(0,t.jsx)("span",{className:`px-2 py-0.5 rounded text-[11px] font-semibold uppercase flex-shrink-0 ${d?"bg-green-100 text-green-700 border border-green-200":"bg-red-100 text-red-700 border border-red-200"}`,children:d?"PASSED":"FAILED"}),v&&(0,t.jsx)("span",{className:`px-2 py-0.5 rounded text-[11px] font-medium flex-shrink-0 ${0===c?"bg-green-50 text-green-700 border border-green-200":"bg-amber-50 text-amber-700 border border-amber-200"}`,children:v}),null!=e.confidence_score&&(0,t.jsxs)("span",{className:"px-2 py-0.5 bg-gray-100 text-gray-600 border border-gray-200 rounded text-[11px] font-medium flex-shrink-0",children:[(100*e.confidence_score).toFixed(0),"% conf"]}),null!=g&&d&&(0,t.jsx)(a.Tooltip,{title:`Risk score: ${g}/10`,children:(0,t.jsxs)("span",{className:`px-2 py-0.5 border rounded text-[11px] font-semibold flex-shrink-0 ${g<=3?"text-green-600 bg-green-50 border-green-200":g<=6?"text-amber-600 bg-amber-50 border-amber-200":"text-red-600 bg-red-50 border-red-200"}`,children:["Risk ",g,"/10"]})})]}),(0,t.jsxs)("div",{className:"flex items-center gap-3 flex-shrink-0",children:[(0,t.jsx)("span",{className:"text-sm text-gray-500 font-mono",children:u}),e.detection_method&&(0,t.jsx)("span",{className:"px-2 py-0.5 bg-gray-100 text-gray-600 border border-gray-200 rounded text-[11px] font-medium",children:e.detection_method.split(",")[0].trim()}),(0,t.jsx)(E,{expanded:n})]})]}),n&&(0,t.jsxs)("div",{className:"border-t border-gray-100 px-4 py-3",children:[e.classification&&(0,t.jsxs)("div",{className:"mb-3 bg-gray-50 rounded-lg p-3 space-y-1",children:[(0,t.jsx)("h5",{className:"text-sm font-medium text-gray-700 mb-2",children:"Classification"}),e.classification.category&&(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"font-medium w-1/3 text-gray-500",children:"Category:"}),(0,t.jsx)("span",{children:e.classification.category})]}),e.classification.article_reference&&(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"font-medium w-1/3 text-gray-500",children:"Reference:"}),(0,t.jsx)("span",{className:"font-mono",children:e.classification.article_reference})]}),null!=e.classification.confidence&&(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"font-medium w-1/3 text-gray-500",children:"Confidence:"}),(0,t.jsxs)("span",{children:[(100*e.classification.confidence).toFixed(0),"%"]})]}),e.classification.reason&&(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"font-medium w-1/3 text-gray-500",children:"Reason:"}),(0,t.jsx)("span",{children:e.classification.reason})]})]}),e.match_details&&e.match_details.length>0&&(0,t.jsx)(D,{matchDetails:e.match_details}),c>0&&(0,t.jsxs)("div",{className:"mt-3",children:[(0,t.jsx)("h5",{className:"text-sm font-medium text-gray-700 mb-2",children:"Masked Entities"}),(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:Object.entries(e.masked_entity_count||{}).map(([e,s])=>(0,t.jsxs)("span",{className:"px-2 py-1 bg-blue-50 text-blue-700 rounded text-xs font-medium",children:[e,": ",s]},e))})]}),"presidio"===f&&j.length>0&&(0,t.jsx)("div",{className:"mt-3",children:(0,t.jsx)(r,{entities:j})}),"bedrock"===f&&b&&(0,t.jsx)("div",{className:"mt-3",children:(0,t.jsx)(m,{response:b})}),"litellm_content_filter"===f&&y&&(0,t.jsx)("div",{className:"mt-3",children:(0,t.jsx)(h,{response:y})}),f&&!_.has(f)&&y&&(0,t.jsx)(I,{response:y})]})]})};e.s(["default",0,({data:e,accessToken:a,logEntry:l})=>{let r=(0,s.useMemo)(()=>Array.isArray(e)?e.filter(e=>!!e):e?[e]:[],[e]),i=r.filter(w).length,n=i===r.length,o=(0,s.useMemo)(()=>Math.round(1e3*r.reduce((e,t)=>e+(t.duration??0),0)),[r]);return((0,s.useMemo)(()=>Array.from(new Set(r.map(e=>e.policy_template).filter(Boolean))),[r]),0===r.length)?null:(0,t.jsxs)("div",{className:"bg-white rounded-xl border border-gray-200 shadow-sm w-full max-w-full overflow-hidden mb-6",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-6 py-4 border-b border-gray-100",children:[(0,t.jsxs)("div",{className:"flex items-center gap-4",children:[(0,t.jsx)(k,{}),(0,t.jsxs)("div",{children:[(0,t.jsx)("h3",{className:"text-lg font-semibold text-gray-900",children:"Guardrails & Policy Compliance"}),(0,t.jsxs)("div",{className:"flex items-center gap-2 mt-0.5",children:[(0,t.jsxs)("span",{className:"text-sm text-gray-500",children:[r.length," guardrail",1!==r.length?"s":""," evaluated"]}),(0,t.jsx)("span",{className:"text-gray-300",children:"|"}),(0,t.jsxs)("span",{className:`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-semibold ${n?"bg-green-50 text-green-700 border border-green-200":"bg-red-50 text-red-700 border border-red-200"}`,children:[n?(0,t.jsx)("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",children:(0,t.jsx)("path",{d:"M3 6l2.5 2.5L9 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})}):null,i," Passed"]})]})]})]}),(0,t.jsxs)("div",{className:"flex items-center gap-6",children:[(0,t.jsx)("div",{className:"text-right",children:(0,t.jsxs)("div",{className:"text-sm font-medium text-gray-900",children:["Total: ",o,"ms overhead"]})}),(0,t.jsxs)("button",{onClick:()=>{let e=new Blob([JSON.stringify(r,null,2)],{type:"application/json"}),t=URL.createObjectURL(e),s=document.createElement("a");s.href=t,s.download=`guardrail-compliance-log-${new Date().toISOString().slice(0,10)}.json`,s.click(),URL.revokeObjectURL(t)},className:"inline-flex items-center gap-2 px-4 py-2 border border-gray-300 rounded-lg text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 transition-colors",children:[(0,t.jsx)(A,{}),"Export Compliance Log"]})]})]}),a&&l&&(0,t.jsx)("div",{className:"px-6 py-4 border-b border-gray-100",children:(0,t.jsx)(v,{accessToken:a,logEntry:l})}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("div",{className:"w-[340px] flex-shrink-0 border-r border-gray-100 px-6 py-5",children:(0,t.jsx)(O,{entries:r})}),(0,t.jsxs)("div",{className:"flex-1 px-6 py-5 min-w-0",children:[(0,t.jsx)("h4",{className:"text-xs font-semibold text-gray-500 uppercase tracking-wider mb-4",children:"Evaluation Details"}),(0,t.jsx)("div",{className:"space-y-3",children:r.map((e,s)=>(0,t.jsx)(z,{entry:e},`${e.guardrail_name??"guardrail"}-${s}`))})]})]})]})}],517442)},70635,e=>{"use strict";var t=e.i(843476),s=e.i(362024),a=e.i(500330);let l=e=>null==e?"-":`$${(0,a.formatNumberWithCommas)(e,8)}`,r=e=>null==e?"-":`${(100*e).toFixed(2)}%`;e.s(["CostBreakdownViewer",0,({costBreakdown:e,totalSpend:a,promptTokens:i,completionTokens:n,cacheHit:o})=>{let d=o?.toLowerCase()==="true",c=void 0!==i||void 0!==n,m=e?.input_cost!==void 0||e?.output_cost!==void 0,x=e?.additional_costs&&Object.entries(e.additional_costs).some(([,e])=>null!=e&&0!==e);if(!(m||c||x||e&&(void 0!==e.discount_percent&&0!==e.discount_percent||void 0!==e.discount_amount&&0!==e.discount_amount||void 0!==e.margin_percent&&0!==e.margin_percent||void 0!==e.margin_fixed_amount&&0!==e.margin_fixed_amount||void 0!==e.margin_total_amount&&0!==e.margin_total_amount)))return null;let u=e&&(void 0!==e.discount_percent&&0!==e.discount_percent||void 0!==e.discount_amount&&0!==e.discount_amount),p=e&&(void 0!==e.margin_percent&&0!==e.margin_percent||void 0!==e.margin_fixed_amount&&0!==e.margin_fixed_amount||void 0!==e.margin_total_amount&&0!==e.margin_total_amount),h=d?0:e?.input_cost,g=d?0:e?.output_cost,f=d?0:e?.original_cost,y=d?0:e?.total_cost??a;return(0,t.jsx)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6",children:(0,t.jsx)(s.Collapse,{expandIconPosition:"start",items:[{key:"1",label:(0,t.jsxs)("div",{className:"flex items-center justify-between w-full",children:[(0,t.jsx)("h3",{className:"text-lg font-medium text-gray-900",children:"Cost Breakdown"}),(0,t.jsxs)("div",{className:"flex items-center space-x-2 mr-4",children:[(0,t.jsx)("span",{className:"text-sm text-gray-500",children:"Total:"}),(0,t.jsxs)("span",{className:"text-sm font-semibold text-gray-900",children:[l(a),d&&" (Cached)"]})]})]}),children:(0,t.jsxs)("div",{className:"p-6 space-y-4",children:[(0,t.jsxs)("div",{className:"space-y-2 max-w-2xl",children:[(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"text-gray-600 font-medium w-1/3",children:"Input Cost:"}),(0,t.jsxs)("span",{className:"text-gray-900",children:[l(h),void 0!==i&&(0,t.jsxs)("span",{className:"text-gray-500 font-normal ml-1",children:["(",i.toLocaleString()," prompt tokens)"]})]})]}),(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"text-gray-600 font-medium w-1/3",children:"Output Cost:"}),(0,t.jsxs)("span",{className:"text-gray-900",children:[l(g),void 0!==n&&(0,t.jsxs)("span",{className:"text-gray-500 font-normal ml-1",children:["(",n.toLocaleString()," completion tokens)"]})]})]}),e?.tool_usage_cost!==void 0&&e.tool_usage_cost>0&&(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsx)("span",{className:"text-gray-600 font-medium w-1/3",children:"Tool Usage Cost:"}),(0,t.jsx)("span",{className:"text-gray-900",children:l(e.tool_usage_cost)})]}),e?.additional_costs&&Object.entries(e.additional_costs).filter(([,e])=>null!=e&&0!==e).map(([e,s])=>(0,t.jsxs)("div",{className:"flex text-sm",children:[(0,t.jsxs)("span",{className:"text-gray-600 font-medium w-1/3",children:[e,":"]}),(0,t.jsx)("span",{className:"text-gray-900",children:l(s)})]},e))]}),!d&&(0,t.jsx)("div",{className:"pt-2 border-t border-gray-100 max-w-2xl",children:(0,t.jsxs)("div",{className:"flex text-sm font-semibold",children:[(0,t.jsx)("span",{className:"text-gray-900 w-1/3",children:"Original LLM Cost:"}),(0,t.jsx)("span",{className:"text-gray-900",children:l(f)})]})}),(u||p)&&(0,t.jsxs)("div",{className:"pt-2 space-y-2 max-w-2xl",children:[u&&(0,t.jsxs)("div",{className:"space-y-2",children:[void 0!==e.discount_percent&&0!==e.discount_percent&&(0,t.jsxs)("div",{className:"flex text-sm text-gray-600",children:[(0,t.jsxs)("span",{className:"font-medium w-1/3",children:["Discount (",r(e.discount_percent),"):"]}),(0,t.jsxs)("span",{className:"text-gray-900",children:["-",l(e.discount_amount)]})]}),void 0!==e.discount_amount&&void 0===e.discount_percent&&(0,t.jsxs)("div",{className:"flex text-sm text-gray-600",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Discount Amount:"}),(0,t.jsxs)("span",{className:"text-gray-900",children:["-",l(e.discount_amount)]})]})]}),p&&(0,t.jsxs)("div",{className:"space-y-2",children:[void 0!==e.margin_percent&&0!==e.margin_percent&&(0,t.jsxs)("div",{className:"flex text-sm text-gray-600",children:[(0,t.jsxs)("span",{className:"font-medium w-1/3",children:["Margin (",r(e.margin_percent),"):"]}),(0,t.jsxs)("span",{className:"text-gray-900",children:["+",l((e.margin_total_amount||0)-(e.margin_fixed_amount||0))]})]}),void 0!==e.margin_fixed_amount&&0!==e.margin_fixed_amount&&(0,t.jsxs)("div",{className:"flex text-sm text-gray-600",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Margin:"}),(0,t.jsxs)("span",{className:"text-gray-900",children:["+",l(e.margin_fixed_amount)]})]})]})]}),(0,t.jsx)("div",{className:"mt-4 pt-4 border-t border-gray-200 max-w-2xl",children:(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)("span",{className:"font-bold text-sm text-gray-900 w-1/3",children:"Final Calculated Cost:"}),(0,t.jsxs)("span",{className:"text-sm font-bold text-gray-900",children:[l(y),d&&" (Cached)"]})]})})]})}]})})}])},70969,e=>{"use strict";var t=e.i(843476);e.s(["ConfigInfoMessage",0,({show:e,onOpenSettings:s})=>e?(0,t.jsxs)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-4 flex items-start",children:[(0,t.jsx)("div",{className:"text-blue-500 mr-3 flex-shrink-0 mt-0.5",children:(0,t.jsxs)("svg",{xmlns:"http://www.w3.org/2000/svg",width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,t.jsx)("circle",{cx:"12",cy:"12",r:"10"}),(0,t.jsx)("line",{x1:"12",y1:"16",x2:"12",y2:"12"}),(0,t.jsx)("line",{x1:"12",y1:"8",x2:"12.01",y2:"8"})]})}),(0,t.jsxs)("div",{children:[(0,t.jsx)("h4",{className:"text-sm font-medium text-blue-800",children:"Request/Response Data Not Available"}),(0,t.jsxs)("p",{className:"text-sm text-blue-700 mt-1",children:["To view request and response details, enable prompt storage in your LiteLLM configuration by adding the following to your ",(0,t.jsx)("code",{className:"bg-blue-100 px-1 py-0.5 rounded",children:"proxy_config.yaml"})," file",s&&(0,t.jsxs)(t.Fragment,{children:[" or"," ",(0,t.jsx)("button",{onClick:s,className:"text-blue-600 hover:text-blue-800 underline font-medium",children:"open the settings"})," ","to configure this directly."]})]}),(0,t.jsx)("pre",{className:"mt-2 bg-white p-3 rounded border border-blue-200 text-xs font-mono overflow-auto",children:`general_settings: store_model_in_db: true store_prompts_in_spend_logs: true`}),(0,t.jsx)("p",{className:"text-xs text-blue-700 mt-2",children:"Note: This will only affect new requests after the configuration change."})]})]}):null])},3565,331052,867612,502626,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(464571),l=e.i(608856),r=e.i(492030),i=e.i(166406),n=e.i(894660),o=e.i(240647),d=e.i(531245),c=e.i(283086),m=e.i(195116),x=e.i(97859),u=e.i(257486),p=e.i(337767),h=e.i(237062),g=e.i(898586),f=e.i(869216),y=e.i(175712),j=e.i(262218),b=e.i(653496),v=e.i(560445),_=e.i(362024),N=e.i(91739),w=e.i(770914),S=e.i(482725),k=e.i(166540),C=e.i(500330),T=e.i(517442),L=e.i(70635),M=e.i(70969),E=e.i(916925);function A({data:e}){let[a,l]=(0,s.useState)({});if(!e||0===e.length)return null;let r=e=>new Date(1e3*e).toLocaleString();return(0,t.jsx)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6",children:(0,t.jsx)(_.Collapse,{defaultActiveKey:["1"],expandIconPosition:"start",items:[{key:"1",label:(0,t.jsx)("h3",{className:"text-lg font-medium text-gray-900",children:"Vector Store Requests"}),children:(0,t.jsx)("div",{className:"p-4",children:e.map((e,s)=>{var i,n;return(0,t.jsxs)("div",{className:"mb-6 last:mb-0",children:[(0,t.jsx)("div",{className:"bg-white rounded-lg border p-4 mb-4",children:(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4",children:[(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Query:"}),(0,t.jsx)("span",{className:"font-mono",children:e.query})]}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Vector Store ID:"}),(0,t.jsx)("span",{className:"font-mono",children:e.vector_store_id})]}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Provider:"}),(0,t.jsx)("span",{className:"flex items-center",children:(()=>{let{logo:s,displayName:a}=(0,E.getProviderLogoAndName)(e.custom_llm_provider);return(0,t.jsxs)(t.Fragment,{children:[s&&(0,t.jsx)("img",{src:s,alt:`${a} logo`,className:"h-5 w-5 mr-2"}),a]})})()})]})]}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Start Time:"}),(0,t.jsx)("span",{children:r(e.start_time)})]}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"End Time:"}),(0,t.jsx)("span",{children:r(e.end_time)})]}),(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("span",{className:"font-medium w-1/3",children:"Duration:"}),(0,t.jsx)("span",{children:(i=e.start_time,n=e.end_time,`${((n-i)*1e3).toFixed(2)}ms`)})]})]})]})}),(0,t.jsx)("h4",{className:"font-medium mb-2",children:"Search Results"}),(0,t.jsx)("div",{className:"space-y-2",children:e.vector_store_search_response.data.map((e,r)=>{let i=a[`${s}-${r}`]||!1;return(0,t.jsxs)("div",{className:"border rounded-lg overflow-hidden",children:[(0,t.jsxs)("div",{className:"flex items-center p-3 bg-gray-50 cursor-pointer",onClick:()=>{let e;return e=`${s}-${r}`,void l(t=>({...t,[e]:!t[e]}))},children:[(0,t.jsx)("svg",{className:`w-5 h-5 mr-2 transition-transform ${i?"transform rotate-90":""}`,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"})}),(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsxs)("span",{className:"font-medium mr-2",children:["Result ",r+1]}),(0,t.jsxs)("span",{className:"text-gray-500 text-sm",children:["Score: ",(0,t.jsx)("span",{className:"font-mono",children:e.score.toFixed(4)})]})]})]}),i&&(0,t.jsx)("div",{className:"p-3 border-t bg-white",children:e.content.map((e,s)=>(0,t.jsxs)("div",{className:"mb-2 last:mb-0",children:[(0,t.jsx)("div",{className:"text-xs text-gray-500 mb-1",children:e.type}),(0,t.jsx)("pre",{className:"text-xs font-mono whitespace-pre-wrap break-all bg-gray-50 p-2 rounded",children:e.text})]},s))})]},r)})})]},s)})})}]})})}e.s(["VectorStoreViewer",()=>A],331052);var D=e.i(592968),I=e.i(207066);let{Text:O}=g.Typography;function z({value:e,maxWidth:s=I.DEFAULT_MAX_WIDTH}){return e?(0,t.jsx)(D.Tooltip,{title:e,children:(0,t.jsx)(O,{copyable:{text:e,tooltips:["Copy","Copied!"]},style:{maxWidth:s,display:"inline-block",verticalAlign:"bottom",fontFamily:I.FONT_FAMILY_MONO,fontSize:I.FONT_SIZE_SMALL},ellipsis:!0,children:e})}):(0,t.jsx)(O,{type:"secondary",children:"-"})}let{Text:R}=g.Typography;function P({prompt:e=0,completion:s=0,total:a=0}){return(0,t.jsxs)(R,{children:[a.toLocaleString()," (",e.toLocaleString()," prompt tokens + ",s.toLocaleString()," completion tokens)"]})}let B=e=>!!e&&e instanceof Date,F=e=>"object"==typeof e&&null!==e,q=e=>!!e&&e instanceof Object&&"function"==typeof e;function H(e,t){return void 0===t&&(t=!1),!e||t?`"${e}"`:e}function $(e){let{field:t,value:a,data:l,lastElement:r,openBracket:i,closeBracket:n,level:o,style:d,shouldExpandNode:c,clickToExpandNode:m,outerRef:x,beforeExpandChange:u}=e,p=(0,s.useRef)(!1),[h,g]=(0,s.useState)(()=>c(o,a,t)),f=(0,s.useRef)(null);(0,s.useEffect)(()=>{p.current?g(c(o,a,t)):p.current=!0},[c]);let y=(0,s.useId)();if(0===l.length)return function(e){let{field:t,openBracket:a,closeBracket:l,lastElement:r,style:i}=e;return(0,s.createElement)("div",{className:i.basicChildStyle,role:"treeitem","aria-selected":void 0},(t||""===t)&&(0,s.createElement)("span",{className:i.label},H(t,i.quotesForFieldNames),":"),(0,s.createElement)("span",{className:i.punctuation},a),(0,s.createElement)("span",{className:i.punctuation},l),!r&&(0,s.createElement)("span",{className:i.punctuation},","))}({field:t,openBracket:i,closeBracket:n,lastElement:r,style:d});let j=h?d.collapseIcon:d.expandIcon,b=h?d.ariaLables.collapseJson:d.ariaLables.expandJson,v=o+1,_=l.length-1,N=e=>{h!==e&&(!u||u({level:o,value:a,field:t,newExpandValue:e}))&&g(e)},w=e=>{if("ArrowRight"===e.key||"ArrowLeft"===e.key)e.preventDefault(),N("ArrowRight"===e.key);else if("ArrowUp"===e.key||"ArrowDown"===e.key){e.preventDefault();let t="ArrowUp"===e.key?-1:1;if(!x.current)return;let s=x.current.querySelectorAll("[role=button]"),a=-1;for(let e=0;e{var e;N(!h);let t=f.current;if(!t)return;let s=null==(e=x.current)?void 0:e.querySelector('[role=button][tabindex="0"]');s&&(s.tabIndex=-1),t.tabIndex=0,t.focus()};return(0,s.createElement)("div",{className:d.basicChildStyle,role:"treeitem","aria-expanded":h,"aria-selected":void 0},(0,s.createElement)("span",{className:j,onClick:S,onKeyDown:w,role:"button","aria-label":b,"aria-expanded":h,"aria-controls":h?y:void 0,ref:f,tabIndex:0===o?0:-1}),(t||""===t)&&(m?(0,s.createElement)("span",{className:d.clickableLabel,onClick:S,onKeyDown:w},H(t,d.quotesForFieldNames),":"):(0,s.createElement)("span",{className:d.label},H(t,d.quotesForFieldNames),":")),(0,s.createElement)("span",{className:d.punctuation},i),h?(0,s.createElement)("ul",{id:y,role:"group",className:d.childFieldsContainer},l.map((e,t)=>(0,s.createElement)(W,{key:e[0]||t,field:e[0],value:e[1],style:d,lastElement:t===_,level:v,shouldExpandNode:c,clickToExpandNode:m,beforeExpandChange:u,outerRef:x}))):(0,s.createElement)("span",{className:d.collapsedContent,onClick:S,onKeyDown:w}),(0,s.createElement)("span",{className:d.punctuation},n),!r&&(0,s.createElement)("span",{className:d.punctuation},","))}function Y(e){let{field:t,value:s,style:a,lastElement:l,shouldExpandNode:r,clickToExpandNode:i,level:n,outerRef:o,beforeExpandChange:d}=e;return $({field:t,value:s,lastElement:l||!1,level:n,openBracket:"{",closeBracket:"}",style:a,shouldExpandNode:r,clickToExpandNode:i,data:Object.keys(s).map(e=>[e,s[e]]),outerRef:o,beforeExpandChange:d})}function K(e){let{field:t,value:s,style:a,lastElement:l,level:r,shouldExpandNode:i,clickToExpandNode:n,outerRef:o,beforeExpandChange:d}=e;return $({field:t,value:s,lastElement:l||!1,level:r,openBracket:"[",closeBracket:"]",style:a,shouldExpandNode:i,clickToExpandNode:n,data:s.map(e=>[void 0,e]),outerRef:o,beforeExpandChange:d})}function V(e){let t,{field:a,value:l,style:r,lastElement:i}=e,n=r.otherValue;if(null===l)t="null",n=r.nullValue;else if(void 0===l)t="undefined",n=r.undefinedValue;else if("string"==typeof l||l instanceof String){var o;o=!r.noQuotesForStringValues,t=r.stringifyStringValues?JSON.stringify(l):o?`"${l}"`:l,n=r.stringValue}else if("boolean"==typeof l||l instanceof Boolean)t=l?"true":"false",n=r.booleanValue;else if("number"==typeof l||l instanceof Number)t=l.toString(),n=r.numberValue;else"bigint"==typeof l||l instanceof BigInt?(t=`${l.toString()}n`,n=r.numberValue):t=B(l)?l.toISOString():q(l)?"function() { }":l.toString();return(0,s.createElement)("div",{className:r.basicChildStyle,role:"treeitem","aria-selected":void 0},(a||""===a)&&(0,s.createElement)("span",{className:r.label},H(a,r.quotesForFieldNames),":"),(0,s.createElement)("span",{className:n},t),!i&&(0,s.createElement)("span",{className:r.punctuation},","))}function W(e){let t=e.value;return Array.isArray(t)?(0,s.createElement)(K,Object.assign({},e)):!F(t)||B(t)||q(t)?(0,s.createElement)(V,Object.assign({},e)):(0,s.createElement)(Y,Object.assign({},e))}let U={container:"_2IvMF _GzYRV",basicChildStyle:"_2bkNM",childFieldsContainer:"_1BXBN",label:"_1MGIk",clickableLabel:"_2YKJg _1MGIk _1MFti",nullValue:"_2T6PJ",undefinedValue:"_1Gho6",stringValue:"_vGjyY",booleanValue:"_3zQKs",numberValue:"_1bQdo",otherValue:"_1xvuR",punctuation:"_3uHL6 _3eOF8",collapseIcon:"_oLqym _f10Tu _1MFti _1LId0",expandIcon:"_2AXVT _f10Tu _1MFti _1UmXx",collapsedContent:"_2KJWg _1pNG9 _1MFti",noQuotesForStringValues:!1,quotesForFieldNames:!1,ariaLables:{collapseJson:"collapse JSON",expandJson:"expand JSON"},stringifyStringValues:!1},G=()=>!0,J=e=>{let{data:t,style:a=U,shouldExpandNode:l=G,clickToExpandNode:r=!1,beforeExpandChange:i,compactTopLevel:n,...o}=e,d=(0,s.useRef)(null);return(0,s.createElement)("div",Object.assign({"aria-label":"JSON view"},o,{className:a.container,ref:d,role:"tree"}),n&&F(t)?Object.entries(t).map(e=>{let[t,n]=e;return(0,s.createElement)(W,{key:t,field:t,value:n,style:{...U,...a},lastElement:!0,level:1,shouldExpandNode:l,clickToExpandNode:r,beforeExpandChange:i,outerRef:d})}):(0,s.createElement)(W,{value:t,style:{...U,...a},lastElement:!0,level:0,shouldExpandNode:l,clickToExpandNode:r,outerRef:d,beforeExpandChange:i}))};e.s(["JsonView",()=>J,"defaultStyles",()=>U],867612);let{Text:Q}=g.Typography;function X({data:e}){return e?(0,t.jsx)("div",{style:{maxHeight:I.JSON_MAX_HEIGHT,overflow:"auto",background:I.COLOR_BG_LIGHT,padding:I.SPACING_LARGE,borderRadius:4},children:(0,t.jsx)("div",{className:"[&_[role='tree']]:bg-white [&_[role='tree']]:text-slate-900",children:(0,t.jsx)(J,{data:e,style:U,clickToExpandNode:!0})})}):(0,t.jsx)(Q,{type:"secondary",children:"No data"})}function Z(e){if("string"==typeof e)try{return JSON.parse(e)}catch{}return e}function ee(e){return Array.isArray(e)?e:e?[e]:[]}function et(e){if("string"==typeof e)try{return JSON.parse(e)}catch{}return e}var es=e.i(366308),ea=e.i(755151),el=e.i(291542);let{Text:er}=g.Typography;function ei({tool:e}){let s=Object.entries(e.parameters?.properties||{}).map(([t,s])=>({key:t,name:t,type:s.type||"any",description:s.description||"-",required:e.parameters?.required?.includes(t)||!1})),a=[{title:"Parameter",dataIndex:"name",key:"name",render:(e,s)=>(0,t.jsxs)(er,{code:!0,children:[e,s.required&&(0,t.jsx)(er,{type:"danger",children:"*"})]})},{title:"Type",dataIndex:"type",key:"type",render:e=>(0,t.jsx)(er,{code:!0,style:{color:"#1890ff"},children:e})},{title:"Description",dataIndex:"description",key:"description",render:e=>(0,t.jsx)(er,{type:"secondary",children:e})}];return(0,t.jsxs)("div",{children:[e.description&&(0,t.jsx)("div",{style:{marginBottom:16},children:(0,t.jsx)(er,{style:{lineHeight:1.6,whiteSpace:"pre-wrap"},children:e.description})}),s.length>0&&(0,t.jsxs)("div",{children:[(0,t.jsx)(er,{type:"secondary",style:{fontSize:12,display:"block",marginBottom:8},children:"Parameters"}),(0,t.jsx)(el.Table,{dataSource:s,columns:a,pagination:!1,size:"small",bordered:!0})]}),e.called&&e.callData&&(0,t.jsxs)("div",{style:{marginTop:16},children:[(0,t.jsx)(er,{type:"secondary",style:{fontSize:12,display:"block",marginBottom:8},children:"Called With"}),(0,t.jsx)("div",{style:{background:"#f6ffed",border:"1px solid #b7eb8f",borderRadius:4,padding:12},children:(0,t.jsx)("pre",{style:{margin:0,fontSize:12,whiteSpace:"pre-wrap",wordBreak:"break-word"},children:JSON.stringify(e.callData.arguments,null,2)})})]})]})}function en({tool:e}){let s={type:"function",function:{name:e.name,description:e.description,parameters:e.parameters}};return(0,t.jsx)("pre",{style:{margin:0,whiteSpace:"pre-wrap",wordBreak:"break-word",fontSize:12,background:"#fafafa",padding:12,borderRadius:4,maxHeight:300,overflow:"auto"},children:JSON.stringify(s,null,2)})}let{Text:eo}=g.Typography;function ed({tool:e}){let[a,l]=(0,s.useState)("formatted");return(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",marginBottom:12},children:[(0,t.jsx)(eo,{type:"secondary",style:{fontSize:12},children:"Description"}),(0,t.jsxs)(N.Radio.Group,{size:"small",value:a,onChange:e=>l(e.target.value),children:[(0,t.jsx)(N.Radio.Button,{value:"formatted",children:"Formatted"}),(0,t.jsx)(N.Radio.Button,{value:"json",children:"JSON"})]})]}),"formatted"===a?(0,t.jsx)(ei,{tool:e}):(0,t.jsx)(en,{tool:e})]})}let{Text:ec}=g.Typography;function em({tool:e}){let[a,l]=(0,s.useState)(!1);return(0,t.jsxs)("div",{style:{border:"1px solid #f0f0f0",borderRadius:8,overflow:"hidden"},children:[(0,t.jsxs)("div",{onClick:()=>l(!a),style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"12px 16px",cursor:"pointer",background:a?"#fafafa":"#fff",transition:"background 0.2s"},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:10},children:[(0,t.jsx)(es.ToolOutlined,{style:{color:"#8c8c8c",fontSize:14}}),(0,t.jsxs)(ec,{style:{fontSize:14},children:[e.index,". ",e.name]})]}),(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8},children:[(0,t.jsx)(j.Tag,{color:e.called?"blue":"default",children:e.called?"called":"not called"}),a?(0,t.jsx)(ea.DownOutlined,{style:{fontSize:12,color:"#8c8c8c"}}):(0,t.jsx)(o.RightOutlined,{style:{fontSize:12,color:"#8c8c8c"}})]})]}),a&&(0,t.jsx)("div",{style:{padding:"16px",borderTop:"1px solid #f0f0f0",background:"#fff"},children:(0,t.jsx)(ed,{tool:e})})]})}let{Text:ex}=g.Typography;function eu({log:e}){let s=function(e){let t,s=!(t=et(e.proxy_server_request||e.messages))||Array.isArray(t)?[]:"object"==typeof t&&t.tools&&Array.isArray(t.tools)?t.tools:[];if(0===s.length)return[];let a=function(e){let t=et(e.response);if(!t||"object"!=typeof t)return[];let s=t.choices;if(Array.isArray(s)&&s.length>0){let e=s[0].message;if(e&&Array.isArray(e.tool_calls))return e.tool_calls}if(Array.isArray(t.content)){let e=t.content.filter(e=>"tool_use"===e.type);if(e.length>0)return e.map(e=>({id:e.id,type:"function",function:{name:e.name,arguments:JSON.stringify(e.input||{})}}))}if(Array.isArray(t.tool_calls))return t.tool_calls;if(Array.isArray(t.results)){let e=[];for(let s of t.results)if("response.done"===s.type&&s.response?.output)for(let t of s.response.output)"function_call"===t.type&&e.push({id:t.call_id||"",type:"function",function:{name:t.name||"",arguments:t.arguments||"{}"}});if(e.length>0)return e}return[]}(e),l=new Set(a.map(e=>e.function?.name).filter(Boolean)),r=new Map;return a.forEach(e=>{let t=e.function?.name;t&&r.set(t,{id:e.id,name:t,arguments:function(e){try{return JSON.parse(e)}catch{return{}}}(e.function?.arguments||"{}")})}),s.map((e,t)=>{let s=e.function?.name||e.name||`Tool ${t+1}`;return{index:t+1,name:s,description:e.function?.description||e.description||"",parameters:e.function?.parameters||e.input_schema||{},called:l.has(s),callData:r.get(s)}})}(e);if(0===s.length)return null;let a=s.length,l=s.filter(e=>e.called).length,r=s.slice(0,2).map(e=>e.name).join(", "),i=s.length>2;return(0,t.jsx)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6",children:(0,t.jsx)(_.Collapse,{expandIconPosition:"start",items:[{key:"1",label:(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:12,flexWrap:"wrap"},children:[(0,t.jsx)("h3",{className:"text-lg font-medium text-gray-900",children:"Tools"}),(0,t.jsxs)(ex,{type:"secondary",style:{fontSize:14},children:[a," provided, ",l," called"]}),(0,t.jsxs)(ex,{type:"secondary",style:{fontSize:14},children:["• ",r,i&&"..."]})]}),children:(0,t.jsx)("div",{style:{display:"flex",flexDirection:"column",gap:8},children:s.map(e=>(0,t.jsx)(em,{tool:e},e.name))})}]})})}let ep=e=>{if(!e)return{};if("string"==typeof e)try{return JSON.parse(e)}catch{return{raw:e}}return e};var eh=e.i(998573),eg=e.i(264843),ef=e.i(624001);let{Text:ey}=g.Typography;function ej({type:e,tokens:s,cost:l,onCopy:r,isCollapsed:n,onToggleCollapse:o,turnCount:d}){return(0,t.jsxs)("div",{onClick:o,style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"10px 16px",borderBottom:n?"none":"1px solid #f0f0f0",background:"#fafafa",cursor:o?"pointer":"default",transition:"background 0.15s ease"},onMouseEnter:e=>{o&&(e.currentTarget.style.background="#f5f5f5")},onMouseLeave:e=>{e.currentTarget.style.background="#fafafa"},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:16},children:[o&&(0,t.jsx)("div",{style:{display:"flex",alignItems:"center"},children:n?(0,t.jsx)(ea.DownOutlined,{style:{fontSize:10,color:"#8c8c8c"}}):(0,t.jsx)(ef.UpOutlined,{style:{fontSize:10,color:"#8c8c8c"}})}),(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8},children:["input"===e?(0,t.jsx)(eg.MessageOutlined,{style:{color:"#8c8c8c",fontSize:14}}):(0,t.jsx)("span",{style:{fontSize:14,filter:"grayscale(1)",opacity:.6},children:"✨"}),(0,t.jsx)(ey,{style:{fontWeight:500,fontSize:14},children:"input"===e?"Input":"Output"})]}),void 0!==s&&(0,t.jsxs)(ey,{type:"secondary",style:{fontSize:12},children:["Tokens: ",s.toLocaleString()]}),void 0!==l&&(0,t.jsxs)(ey,{type:"secondary",style:{fontSize:12},children:["Cost: $",l.toFixed(6)]}),void 0!==d&&d>0&&(0,t.jsxs)(ey,{type:"secondary",style:{fontSize:12},children:["Turns: ",d]})]}),(0,t.jsx)(D.Tooltip,{title:"Copy",children:(0,t.jsx)(a.Button,{type:"text",size:"small",icon:(0,t.jsx)(i.CopyOutlined,{}),onClick:e=>{e.stopPropagation(),r()}})})]})}let{Text:eb}=g.Typography;function ev({label:e,content:a,defaultExpanded:l=!1}){let[r,i]=(0,s.useState)(l),[n,d]=(0,s.useState)(!1),c=a?.length||0;return a&&0!==c?(0,t.jsxs)("div",{style:{marginBottom:8},children:[(0,t.jsxs)("div",{onClick:()=>i(!r),onMouseEnter:()=>d(!0),onMouseLeave:()=>d(!1),style:{display:"flex",alignItems:"center",gap:6,cursor:"pointer",padding:"4px 0",borderRadius:4,background:n?"#f5f5f5":"transparent",transition:"background 0.15s ease",marginBottom:4*!!r},children:[r?(0,t.jsx)(ea.DownOutlined,{style:{fontSize:10,color:"#8c8c8c"}}):(0,t.jsx)(o.RightOutlined,{style:{fontSize:10,color:"#8c8c8c"}}),(0,t.jsx)(eb,{type:"secondary",style:{fontSize:10,letterSpacing:"0.5px",textTransform:"uppercase"},children:e}),(0,t.jsxs)(eb,{type:"secondary",style:{fontSize:10},children:["(",c.toLocaleString()," chars)"]})]}),(0,t.jsx)("div",{style:{maxHeight:r?"2000px":"0px",overflow:"hidden",transition:"max-height 0.2s ease-out, opacity 0.2s ease-out",opacity:+!!r},children:(0,t.jsx)("div",{style:{paddingLeft:16,fontSize:13,lineHeight:1.7,color:"#262626",borderLeft:"1px solid #f0f0f0",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:a})})]}):null}let{Text:e_}=g.Typography;function eN({tool:e,compact:s=!1}){return(0,t.jsxs)("div",{style:{background:"#f8f9fa",border:"1px solid #e9ecef",borderRadius:6,padding:s?"6px 10px":"10px 14px",marginTop:8,fontFamily:"monospace",fontSize:12,position:"relative"},children:[(0,t.jsx)("div",{style:{position:"absolute",top:-8,left:12,background:"#fff",padding:"0 6px",fontSize:10,color:"#8c8c8c",border:"1px solid #e9ecef",borderRadius:3},children:"function"}),(0,t.jsx)(e_,{strong:!0,style:{fontSize:13,display:"block",marginBottom:6},children:e.name}),Object.keys(e.arguments).length>0&&(0,t.jsx)("div",{children:Object.entries(e.arguments).map(([e,s])=>(0,t.jsxs)("div",{style:{marginBottom:2},children:[(0,t.jsxs)(e_,{type:"secondary",style:{fontSize:12},children:[e,":"," "]}),(0,t.jsx)(e_,{style:{fontSize:12},children:JSON.stringify(s)})]},e))})]})}let{Text:ew}=g.Typography;function eS({label:e,content:s,toolCalls:a,isCompact:l=!1}){let r=s&&"null"!==s&&s.length>0?s:null,i=a&&a.length>0;return r||i?(0,t.jsxs)("div",{style:{marginBottom:8*!!l},children:[(0,t.jsx)(ew,{type:"secondary",style:{fontSize:10,letterSpacing:"0.5px",textTransform:"uppercase",display:"block",marginBottom:3},children:e}),r&&(0,t.jsx)("div",{style:{fontSize:13,lineHeight:1.7,color:"#262626",whiteSpace:"pre-wrap",wordBreak:"break-word",marginBottom:6*!!i},children:r}),i&&(0,t.jsx)("div",{children:a.map((e,s)=>(0,t.jsx)(eN,{tool:e,compact:l},e.id||s))})]}):null}let{Text:ek}=g.Typography;function eC({messages:e}){let[a,l]=(0,s.useState)(!1),[r,i]=(0,s.useState)(!1);return 0===e.length?null:(0,t.jsxs)("div",{style:{marginBottom:8},children:[(0,t.jsxs)("div",{onClick:()=>l(!a),onMouseEnter:()=>i(!0),onMouseLeave:()=>i(!1),style:{display:"flex",alignItems:"center",gap:6,cursor:"pointer",padding:"4px 0",borderRadius:4,background:r?"#f5f5f5":"transparent",transition:"background 0.15s ease",marginBottom:4*!!a},children:[a?(0,t.jsx)(ea.DownOutlined,{style:{fontSize:10,color:"#8c8c8c"}}):(0,t.jsx)(o.RightOutlined,{style:{fontSize:10,color:"#8c8c8c"}}),(0,t.jsxs)(ek,{type:"secondary",style:{fontSize:10,letterSpacing:"0.5px",textTransform:"uppercase"},children:["HISTORY (",e.length," message",1!==e.length?"s":"",")"]})]}),(0,t.jsx)("div",{style:{maxHeight:a?"2000px":"0px",overflow:"hidden",transition:"max-height 0.2s ease-out, opacity 0.2s ease-out",opacity:+!!a},children:(0,t.jsx)("div",{style:{paddingLeft:16,borderLeft:"1px solid #f0f0f0"},children:e.map((e,s)=>(0,t.jsx)(eS,{label:e.role.toUpperCase(),content:e.content,toolCalls:e.toolCalls,isCompact:!0},s))})})]})}function eT({messages:e,promptTokens:a,inputCost:l}){let[r,i]=(0,s.useState)(!1);if(0===e.length)return null;let n=e.find(e=>"system"===e.role),o=e.filter(e=>"system"!==e.role),d=o.length>0?o[o.length-1]:null,c=o.slice(0,-1);return(0,t.jsxs)("div",{style:{border:"1px solid #f0f0f0",borderRadius:6,marginBottom:8,overflow:"hidden"},children:[(0,t.jsx)(ej,{type:"input",tokens:a,cost:l,onCopy:()=>{let e=d?.content||"";navigator.clipboard.writeText(e),eh.message.success("Input copied")},isCollapsed:r,onToggleCollapse:()=>i(!r)}),(0,t.jsx)("div",{style:{maxHeight:r?"0px":"10000px",overflow:"hidden",transition:"max-height 0.3s ease-out, opacity 0.3s ease-out",opacity:+!r},children:(0,t.jsxs)("div",{style:{padding:"12px 16px"},children:[n&&(0,t.jsx)(ev,{label:"SYSTEM",content:n.content,defaultExpanded:!!(n.content&&n.content.length<200)}),c.length>0&&(0,t.jsx)(eC,{messages:c}),d&&(0,t.jsx)(eS,{label:d.role.toUpperCase(),content:d.content,toolCalls:d.toolCalls})]})})]})}let{Text:eL}=g.Typography;function eM({message:e,completionTokens:a,outputCost:l}){let[r,i]=(0,s.useState)(!1),n=()=>{if(!e)return;let t=e.content||"";navigator.clipboard.writeText(t),eh.message.success("Output copied")};return e?(0,t.jsxs)("div",{style:{border:"1px solid #f0f0f0",borderRadius:6,overflow:"hidden"},children:[(0,t.jsx)(ej,{type:"output",tokens:a,cost:l,onCopy:n,isCollapsed:r,onToggleCollapse:()=>i(!r)}),(0,t.jsx)("div",{style:{maxHeight:r?"0px":"10000px",overflow:"hidden",transition:"max-height 0.3s ease-out, opacity 0.3s ease-out",opacity:+!r},children:(0,t.jsx)("div",{style:{padding:"12px 16px"},children:(0,t.jsx)(eS,{label:"ASSISTANT",content:e.content,toolCalls:e.toolCalls})})})]}):(0,t.jsxs)("div",{style:{border:"1px solid #f0f0f0",borderRadius:6,overflow:"hidden"},children:[(0,t.jsx)(ej,{type:"output",tokens:a,cost:l,onCopy:n,isCollapsed:r,onToggleCollapse:()=>i(!r)}),(0,t.jsx)("div",{style:{maxHeight:r?"0px":"10000px",overflow:"hidden",transition:"max-height 0.3s ease-out, opacity 0.3s ease-out",opacity:+!r},children:(0,t.jsx)("div",{style:{padding:"12px 16px"},children:(0,t.jsx)(eL,{type:"secondary",style:{fontSize:13,fontStyle:"italic"},children:"No response data available"})})})]})}var eE=e.i(782273),eA=e.i(313603),eD=e.i(793916);let{Text:eI}=g.Typography;function eO({response:e,metrics:s}){let a=e?.results||[],l=e?.usage,r=a.find(e=>"session.created"===e.type||"session.updated"===e.type),i=a.filter(e=>"response.done"===e.type);return(0,t.jsxs)("div",{children:[r?.session&&(0,t.jsx)(ez,{session:r.session,turnCount:i.length}),i.length>0&&(0,t.jsx)(eR,{responses:i.map(e=>e.response).filter(Boolean),totalUsage:l,metrics:s}),!r&&0===i.length&&(0,t.jsx)("div",{style:{border:"1px solid #f0f0f0",borderRadius:6,padding:"16px",color:"#8c8c8c",fontStyle:"italic",fontSize:13},children:"No recognized realtime events found"})]})}function ez({session:e,turnCount:a}){let[l,r]=(0,s.useState)(!0);return(0,t.jsxs)("div",{style:{border:"1px solid #f0f0f0",borderRadius:6,marginBottom:8,overflow:"hidden"},children:[(0,t.jsx)("div",{onClick:()=>r(!l),style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"10px 16px",borderBottom:l?"none":"1px solid #f0f0f0",background:"#fafafa",cursor:"pointer",transition:"background 0.15s ease"},onMouseEnter:e=>{e.currentTarget.style.background="#f5f5f5"},onMouseLeave:e=>{e.currentTarget.style.background="#fafafa"},children:(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:16},children:[(0,t.jsx)("div",{style:{display:"flex",alignItems:"center"},children:l?(0,t.jsx)(ea.DownOutlined,{style:{fontSize:10,color:"#8c8c8c"}}):(0,t.jsx)(ef.UpOutlined,{style:{fontSize:10,color:"#8c8c8c"}})}),(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8},children:[(0,t.jsx)(eA.SettingOutlined,{style:{color:"#8c8c8c",fontSize:14}}),(0,t.jsx)(eI,{style:{fontWeight:500,fontSize:14},children:"Session"})]}),(0,t.jsx)(eI,{type:"secondary",style:{fontSize:12},children:e.model}),a>0&&(0,t.jsxs)(j.Tag,{color:"purple",style:{margin:0,fontWeight:500},children:[a," ",1===a?"turn":"turns"]}),e.voice&&(0,t.jsxs)(j.Tag,{color:"blue",style:{margin:0},children:[(0,t.jsx)(eE.SoundOutlined,{})," ",e.voice]}),e.modalities&&(0,t.jsx)("div",{style:{display:"flex",gap:4},children:e.modalities.map(e=>(0,t.jsxs)(j.Tag,{style:{margin:0},children:["audio"===e?(0,t.jsx)(eD.AudioOutlined,{}):(0,t.jsx)(eg.MessageOutlined,{})," ",e]},e))})]})}),(0,t.jsx)("div",{style:{maxHeight:l?"0px":"10000px",overflow:"hidden",transition:"max-height 0.3s ease-out, opacity 0.3s ease-out",opacity:+!l},children:(0,t.jsxs)("div",{style:{padding:"12px 16px"},children:[(0,t.jsxs)("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"8px 24px",fontSize:13},children:[(0,t.jsx)(eq,{label:"Model",value:e.model}),(0,t.jsx)(eq,{label:"Voice",value:e.voice}),(0,t.jsx)(eq,{label:"Temperature",value:e.temperature}),(0,t.jsx)(eq,{label:"Max Output Tokens",value:e.max_response_output_tokens}),(0,t.jsx)(eq,{label:"Input Audio Format",value:e.input_audio_format}),(0,t.jsx)(eq,{label:"Output Audio Format",value:e.output_audio_format}),e.turn_detection&&(0,t.jsx)(eq,{label:"Turn Detection",value:e.turn_detection.type}),e.tools&&e.tools.length>0&&(0,t.jsx)(eq,{label:"Tools",value:`${e.tools.length} tool(s)`})]}),e.instructions&&(0,t.jsxs)("div",{style:{marginTop:12},children:[(0,t.jsx)(eI,{type:"secondary",style:{fontSize:10,letterSpacing:"0.5px",textTransform:"uppercase",display:"block",marginBottom:4},children:"Instructions"}),(0,t.jsx)("div",{style:{fontSize:12,lineHeight:1.6,color:"#595959",background:"#fafafa",padding:"8px 12px",borderRadius:4,border:"1px solid #f0f0f0",whiteSpace:"pre-wrap",wordBreak:"break-word",maxHeight:120,overflowY:"auto"},children:e.instructions})]})]})})]})}function eR({responses:e,totalUsage:a,metrics:l}){let[r,i]=(0,s.useState)(!1),n=a?.total_tokens,o=e.length;return(0,t.jsxs)("div",{style:{border:"1px solid #f0f0f0",borderRadius:6,overflow:"hidden"},children:[(0,t.jsx)(ej,{type:"output",tokens:l?.completion_tokens??n,cost:l?.output_cost,onCopy:()=>{let t=e.flatMap(e=>(e.output||[]).flatMap(e=>(e.content||[]).map(t=>`${e.role}: ${t.transcript||t.text||""}`))).join("\n");navigator.clipboard.writeText(t)},isCollapsed:r,onToggleCollapse:()=>i(!r),turnCount:o}),(0,t.jsx)("div",{style:{maxHeight:r?"0px":"10000px",overflow:"hidden",transition:"max-height 0.3s ease-out, opacity 0.3s ease-out",opacity:+!r},children:(0,t.jsx)("div",{style:{padding:"12px 16px"},children:e.map((e,s)=>(0,t.jsx)(eP,{response:e,index:s},e.id||s))})})]})}function eP({response:e,index:s}){let a=e.output||[],l=e.usage;return(0,t.jsxs)("div",{style:{marginBottom:12,paddingBottom:12,borderBottom:"1px solid #f5f5f5"},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8,marginBottom:8},children:[(0,t.jsx)(j.Tag,{color:"completed"===e.status?"green":"orange",style:{margin:0},children:e.status||"unknown"}),l&&(0,t.jsxs)(eI,{type:"secondary",style:{fontSize:11},children:[l.input_tokens??0," in / ",l.output_tokens??0," out tokens"]}),e.conversation_id&&(0,t.jsx)(D.Tooltip,{title:e.conversation_id,children:(0,t.jsxs)(eI,{type:"secondary",style:{fontSize:11,cursor:"help"},children:["conv: ",e.conversation_id.slice(0,12),"..."]})})]}),a.map((e,s)=>(0,t.jsx)(eB,{output:e},e.id||s)),l?.input_token_details&&(0,t.jsx)(eF,{label:"Input",details:l.input_token_details}),l?.output_token_details&&(0,t.jsx)(eF,{label:"Output",details:l.output_token_details})]})}function eB({output:e}){let s=e.content||[];return s.some(e=>e.transcript||e.text)?(0,t.jsxs)("div",{style:{marginBottom:8},children:[(0,t.jsx)(eI,{type:"secondary",style:{fontSize:10,letterSpacing:"0.5px",textTransform:"uppercase",display:"block",marginBottom:3},children:e.role?.toUpperCase()||"ASSISTANT"}),s.map((e,s)=>{let a=e.transcript||e.text;return a?(0,t.jsxs)("div",{style:{display:"flex",alignItems:"flex-start",gap:8,marginBottom:4},children:["audio"===e.type&&(0,t.jsx)(eD.AudioOutlined,{style:{color:"#8c8c8c",fontSize:12,marginTop:3,flexShrink:0}}),"text"===e.type&&(0,t.jsx)(eg.MessageOutlined,{style:{color:"#8c8c8c",fontSize:12,marginTop:3,flexShrink:0}}),(0,t.jsx)("div",{style:{fontSize:13,lineHeight:1.7,color:"#262626",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:a})]},s):null})]}):null}function eF({label:e,details:s}){let a=Object.entries(s).filter(([,e])=>"number"==typeof e||"object"==typeof e&&null!==e);return 0===a.length?null:(0,t.jsxs)("div",{style:{marginTop:4},children:[(0,t.jsxs)(eI,{type:"secondary",style:{fontSize:10,letterSpacing:"0.5px",textTransform:"uppercase"},children:[e," Token Breakdown"]}),(0,t.jsx)("div",{style:{display:"flex",flexWrap:"wrap",gap:8,marginTop:4},children:a.map(([e,s])=>"number"==typeof s?(0,t.jsxs)(j.Tag,{style:{margin:0},children:[e.replace(/_/g," ").replace(/\b\w/g,e=>e.toUpperCase()),": ",s.toLocaleString()]},e):null)})]})}function eq({label:e,value:s}){return null==s?null:(0,t.jsxs)("div",{children:[(0,t.jsx)(eI,{type:"secondary",style:{fontSize:11},children:e}),(0,t.jsx)("div",{style:{fontSize:13,color:"#262626"},children:String(s)})]})}function eH({request:e,response:s,metrics:a}){let l,r,i;if(s&&s.results&&Array.isArray(s.results)&&0!==s.results.length&&s.results.some(e=>"session.created"===e.type||"session.updated"===e.type||"response.done"===e.type))return(0,t.jsx)(eO,{response:s,metrics:a});let{requestMessages:n,responseMessage:o}=(l=[],e?.messages&&Array.isArray(e.messages)&&e.messages.forEach(e=>{let t;l.push({role:e.role||"user",content:"string"==typeof(t=e.content)?t:Array.isArray(t)?t.map(e=>"string"==typeof e?e:"text"===e.type?e.text:"image_url"===e.type?"[Image]":JSON.stringify(e)).join("\n"):JSON.stringify(t),toolCallId:e.tool_call_id})}),r=null,(i=s?.choices?.[0]?.message)&&(r={role:i.role||"assistant",content:i.content||"",toolCalls:(e=>{if(e&&Array.isArray(e))return e.map(e=>({id:e.id||"",name:e.function?.name||"unknown",arguments:ep(e.function?.arguments)}))})(i.tool_calls)}),{requestMessages:l,responseMessage:r});return(0,t.jsxs)("div",{children:[(0,t.jsx)(eT,{messages:n,promptTokens:a?.prompt_tokens,inputCost:a?.input_cost}),(0,t.jsx)(eM,{message:o,completionTokens:a?.completion_tokens,outputCost:a?.output_cost})]})}let{Text:e$}=g.Typography;function eY({logEntry:e,onOpenSettings:s,isLoadingDetails:a=!1,accessToken:l}){var r,i;let n=e.metadata||{},o="failure"===n.status,d=o?n.error_information:null,c=!!(r=e.messages)&&(Array.isArray(r)?r.length>0:"object"==typeof r&&Object.keys(r).length>0),m=!!(i=e.response)&&Object.keys(Z(i)).length>0,x=!c&&!m&&!o&&!a,u=n?.guardrail_information,p=ee(u),h=p.length>0,g=p.reduce((e,t)=>{let s=t?.masked_entity_count;return s?e+Object.values(s).reduce((e,t)=>"number"==typeof t?e+t:e,0):e},0),j=0===p.length?"-":1===p.length?p[0]?.guardrail_name??"-":`${p.length} guardrails`,b=n.vector_store_request_metadata&&Array.isArray(n.vector_store_request_metadata)&&n.vector_store_request_metadata.length>0;return(0,t.jsxs)("div",{style:{padding:`${I.DRAWER_CONTENT_PADDING} ${I.DRAWER_CONTENT_PADDING} 0`},children:[o&&d&&(0,t.jsx)(v.Alert,{type:"error",showIcon:!0,message:"Request Failed",description:(0,t.jsx)(eK,{errorInfo:d}),className:"mb-6"}),e.request_tags&&Object.keys(e.request_tags).length>0&&(0,t.jsx)(eV,{tags:e.request_tags}),(0,t.jsx)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6",children:(0,t.jsx)(y.Card,{title:"Request Details",size:"small",bordered:!1,style:{marginBottom:0},children:(0,t.jsxs)(f.Descriptions,{column:2,size:"small",children:[(0,t.jsx)(f.Descriptions.Item,{label:"Model",children:e.model}),(0,t.jsx)(f.Descriptions.Item,{label:"Provider",children:e.custom_llm_provider||"-"}),(0,t.jsx)(f.Descriptions.Item,{label:"Call Type",children:e.call_type}),(0,t.jsx)(f.Descriptions.Item,{label:"Model ID",children:(0,t.jsx)(z,{value:e.model_id})}),(0,t.jsx)(f.Descriptions.Item,{label:"API Base",children:(0,t.jsx)(z,{value:e.api_base,maxWidth:I.API_BASE_MAX_WIDTH})}),e.requester_ip_address&&(0,t.jsx)(f.Descriptions.Item,{label:"IP Address",children:e.requester_ip_address}),h&&(0,t.jsx)(f.Descriptions.Item,{label:"Guardrail",children:(0,t.jsx)(eW,{label:j,maskedCount:g})})]})})}),(0,t.jsx)(eU,{logEntry:e,metadata:n}),(0,t.jsx)(L.CostBreakdownViewer,{costBreakdown:n?.cost_breakdown,totalSpend:e.spend??0,promptTokens:e.prompt_tokens,completionTokens:e.completion_tokens,cacheHit:e.cache_hit}),(0,t.jsx)(eu,{log:e}),x&&(0,t.jsx)("div",{className:"mb-6",children:(0,t.jsx)(M.ConfigInfoMessage,{show:x,onOpenSettings:s})}),a?(0,t.jsxs)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6 p-8 text-center",children:[(0,t.jsx)(S.Spin,{size:"default"}),(0,t.jsx)("div",{style:{marginTop:8,color:"#999"},children:"Loading request & response data..."})]}):(0,t.jsx)(eG,{hasResponse:m,hasError:o,getRawRequest:()=>Z(e.proxy_server_request||e.messages),getFormattedResponse:()=>o&&d?{error:{message:d.error_message||"An error occurred",type:d.error_class||"error",code:d.error_code||"unknown",param:null}}:Z(e.response),logEntry:e}),h&&(0,t.jsx)("div",{id:"guardrail-section",children:(0,t.jsx)(T.default,{data:u,accessToken:l??null,logEntry:{request_id:e.request_id,user:e.user,model:e.model,startTime:e.startTime,metadata:e.metadata}})}),b&&(0,t.jsx)(A,{data:n.vector_store_request_metadata}),e.metadata&&Object.keys(e.metadata).length>0&&(0,t.jsx)(eQ,{metadata:e.metadata}),(0,t.jsx)("div",{style:{height:I.DRAWER_CONTENT_PADDING}})]})}function eK({errorInfo:e}){return(0,t.jsxs)("div",{children:[e.error_code&&(0,t.jsxs)("div",{children:[(0,t.jsx)(e$,{strong:!0,children:"Error Code:"})," ",e.error_code]}),e.error_message&&(0,t.jsxs)("div",{children:[(0,t.jsx)(e$,{strong:!0,children:"Message:"})," ",e.error_message]})]})}function eV({tags:e}){return(0,t.jsxs)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden p-4 mb-6",children:[(0,t.jsx)(e$,{strong:!0,style:{display:"block",marginBottom:8,fontSize:16},children:"Tags"}),(0,t.jsx)(w.Space,{size:I.SPACING_MEDIUM,wrap:!0,children:Object.entries(e).map(([e,s])=>(0,t.jsxs)(j.Tag,{children:[e,": ",String(s)]},e))})]})}function eW({label:e,maskedCount:s}){return(0,t.jsxs)(w.Space,{size:I.SPACING_MEDIUM,children:[(0,t.jsx)("a",{onClick:()=>{let e=document.getElementById("guardrail-section");e&&e.scrollIntoView({behavior:"smooth"})},style:{cursor:"pointer"},children:e}),s>0&&(0,t.jsxs)(j.Tag,{color:"blue",children:[s," masked"]})]})}function eU({logEntry:e,metadata:s}){let a=e.completionStartTime,l=a&&a!==e.endTime?new Date(a).getTime()-new Date(e.startTime).getTime():null,r=e.cache_hit||s?.additional_usage_values?.cache_read_input_tokens&&s.additional_usage_values.cache_read_input_tokens>0,i=String(e.cache_hit??"None"),n="true"===i.toLowerCase()?"green":"false"===i.toLowerCase()?"red":"default";return(0,t.jsx)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6",children:(0,t.jsx)(y.Card,{title:"Metrics",size:"small",style:{marginBottom:0},children:(0,t.jsxs)(f.Descriptions,{column:2,size:"small",children:[(0,t.jsx)(f.Descriptions.Item,{label:"Tokens",children:(0,t.jsx)(P,{prompt:e.prompt_tokens,completion:e.completion_tokens,total:e.total_tokens})}),(0,t.jsxs)(f.Descriptions.Item,{label:"Cost",children:["$",(0,C.formatNumberWithCommas)(e.spend||0,8)]}),(0,t.jsxs)(f.Descriptions.Item,{label:"Duration",children:[null!=e.request_duration_ms?(e.request_duration_ms/1e3).toFixed(3):"-"," s"]}),null!=l&&l>0&&(0,t.jsxs)(f.Descriptions.Item,{label:"Time to First Token",children:[(l/1e3).toFixed(3)," s"]}),r&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(f.Descriptions.Item,{label:"Cache Hit",children:(0,t.jsx)(j.Tag,{color:n,children:i})}),s?.additional_usage_values?.cache_read_input_tokens>0&&(0,t.jsx)(f.Descriptions.Item,{label:"Cache Read Tokens",children:(0,C.formatNumberWithCommas)(s.additional_usage_values.cache_read_input_tokens)}),s?.additional_usage_values?.cache_creation_input_tokens>0&&(0,t.jsx)(f.Descriptions.Item,{label:"Cache Creation Tokens",children:(0,C.formatNumberWithCommas)(s.additional_usage_values.cache_creation_input_tokens)})]}),s?.litellm_overhead_time_ms!==void 0&&null!==s.litellm_overhead_time_ms&&(0,t.jsxs)(f.Descriptions.Item,{label:"LiteLLM Overhead",children:[s.litellm_overhead_time_ms.toFixed(2)," ms"]}),(0,t.jsx)(f.Descriptions.Item,{label:"Retries",children:s?.attempted_retries!==void 0&&s?.attempted_retries!==null?s.attempted_retries>0?(0,t.jsxs)(t.Fragment,{children:[s.attempted_retries,void 0!==s.max_retries&&null!==s.max_retries?` / ${s.max_retries}`:""]}):(0,t.jsx)(j.Tag,{color:"green",children:"None"}):"-"}),(0,t.jsx)(f.Descriptions.Item,{label:"Start Time",children:(0,k.default)(e.startTime).format("YYYY-MM-DDTHH:mm:ss.SSS[Z]")}),(0,t.jsx)(f.Descriptions.Item,{label:"End Time",children:(0,k.default)(e.endTime).format("YYYY-MM-DDTHH:mm:ss.SSS[Z]")})]})})})}function eG({hasResponse:e,hasError:a,getRawRequest:l,getFormattedResponse:r,logEntry:i}){let[n,o]=(0,s.useState)(I.TAB_REQUEST),[d,c]=(0,s.useState)("pretty"),m=i.spend??0,x=i.prompt_tokens||0,u=i.completion_tokens||0,p=x+u,h=i.metadata?.cost_breakdown,g=h?.input_cost!==void 0&&h?.output_cost!==void 0,f=g?h.input_cost??0:p>0?m*x/p:0,y=g?h.output_cost??0:p>0?m*u/p:0;return(0,t.jsx)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6",children:(0,t.jsx)(_.Collapse,{defaultActiveKey:["1"],expandIconPosition:"start",items:[{key:"1",label:(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%"},onClick:e=>{e.target.closest(".ant-radio-group")&&e.stopPropagation()},children:[(0,t.jsx)("h3",{className:"text-lg font-medium text-gray-900",style:{margin:0},children:"Request & Response"}),(0,t.jsxs)(N.Radio.Group,{size:"small",value:d,onChange:e=>c(e.target.value),children:[(0,t.jsx)(N.Radio.Button,{value:"pretty",children:"Pretty"}),(0,t.jsx)(N.Radio.Button,{value:"json",children:"JSON"})]})]}),children:(0,t.jsx)("div",{children:"pretty"===d?(0,t.jsx)(eH,{request:l(),response:r(),metrics:{prompt_tokens:x,completion_tokens:u,input_cost:f,output_cost:y}}):(0,t.jsx)(b.Tabs,{activeKey:n,onChange:e=>o(e),tabBarExtraContent:(0,t.jsx)(e$,{copyable:{text:JSON.stringify(n===I.TAB_REQUEST?l():r(),null,2),tooltips:["Copy JSON","Copied!"]},disabled:n===I.TAB_RESPONSE&&!e&&!a}),items:[{key:I.TAB_REQUEST,label:"Request",children:(0,t.jsx)("div",{style:{paddingTop:I.SPACING_XLARGE,paddingBottom:I.SPACING_XLARGE},children:(0,t.jsx)(X,{data:l(),mode:"formatted"})})},{key:I.TAB_RESPONSE,label:"Response",children:(0,t.jsx)("div",{style:{paddingTop:I.SPACING_XLARGE,paddingBottom:I.SPACING_XLARGE},children:e||a?(0,t.jsx)(X,{data:r(),mode:"formatted"}):(0,t.jsx)("div",{style:{textAlign:"center",padding:20,color:"#999",fontStyle:"italic"},children:"Response data not available"})})}]})})}]})})}function eJ({guardrailEntries:e}){let s=e.every(e=>{let t=e?.guardrail_status||e?.status;return"pass"===t||"passed"===t||"success"===t});return(0,t.jsx)("div",{style:{textAlign:"left",marginBottom:12},children:(0,t.jsxs)("div",{onClick:()=>{let e=document.getElementById("guardrail-section");e&&e.scrollIntoView({behavior:"smooth"})},style:{display:"inline-flex",alignItems:"center",gap:6,padding:"4px 12px",borderRadius:16,cursor:"pointer",fontSize:13,fontWeight:500,backgroundColor:s?"#f0fdf4":"#fef2f2",color:s?"#15803d":"#b91c1c",border:`1px solid ${s?"#bbf7d0":"#fecaca"}`},children:[s?"✓":"✗"," ",e.length," guardrail",1!==e.length?"s":""," evaluated",(0,t.jsx)("span",{style:{fontSize:11,opacity:.7},children:"↓"})]})})}function eQ({metadata:e}){return(0,t.jsx)("div",{className:"bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6",children:(0,t.jsx)(_.Collapse,{defaultActiveKey:["1"],expandIconPosition:"start",items:[{key:"1",label:(0,t.jsx)("h3",{className:"text-lg font-medium text-gray-900",children:"Metadata"}),children:(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{style:{display:"flex",justifyContent:"flex-end",marginBottom:8},children:(0,t.jsx)(e$,{copyable:{text:JSON.stringify(e,null,2),tooltips:["Copy Metadata","Copied!"]}})}),(0,t.jsx)("pre",{style:{maxHeight:I.METADATA_MAX_HEIGHT,overflowY:"auto",fontSize:I.FONT_SIZE_SMALL,fontFamily:I.FONT_FAMILY_MONO,whiteSpace:"pre-wrap",wordBreak:"break-all",margin:0},children:JSON.stringify(e,null,2)})]})}]})})}var eX=e.i(764205),eZ=e.i(266027),e0=e.i(135214);function e1({row:e,isSelected:s,onClick:a}){let l=x.MCP_CALL_TYPES.includes(e.call_type),r=x.AGENT_CALL_TYPES.includes(e.call_type),i=null!=e.request_duration_ms?(e.request_duration_ms/1e3).toFixed(3):e.startTime&&e.endTime?((Date.parse(e.endTime)-Date.parse(e.startTime))/1e3).toFixed(3):"-";return(0,t.jsxs)("button",{type:"button",className:`w-full text-left pl-8 pr-2 py-1 transition-colors ${s?"bg-blue-50":"hover:bg-slate-100"}`,onClick:a,children:[(0,t.jsxs)("div",{className:"flex items-center gap-1",children:[l?(0,t.jsx)(m.Wrench,{size:12,className:"text-slate-500 flex-shrink-0"}):r?(0,t.jsx)(d.Bot,{size:12,className:"text-slate-500 flex-shrink-0"}):(0,t.jsx)(c.Sparkles,{size:12,className:"text-slate-500 flex-shrink-0"}),(0,t.jsx)("span",{className:"text-xs font-medium text-slate-900 truncate",children:(0,u.getEventDisplayName)(e.call_type,e.model)})]}),(0,t.jsxs)("div",{className:"text-[10px] text-slate-500 mt-0 flex items-center gap-1.5 font-mono",children:[(0,t.jsxs)("span",{children:[i,"s"]}),e.spend?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("span",{children:"·"}),(0,t.jsx)("span",{children:(0,C.getSpendString)(e.spend)})]}):null,e.total_tokens?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("span",{children:"·"}),(0,t.jsxs)("span",{children:[e.total_tokens," tok"]})]}):null]})]})}function e2({open:e,onClose:d,logEntry:c,sessionId:m,accessToken:u,onOpenSettings:g,allLogs:f=[],onSelectLog:y,startTime:j}){let b=!!m,[v,_]=(0,s.useState)(null),[N,w]=(0,s.useState)(!1),[S,k]=(0,s.useState)(!1),{data:T=[]}=(0,eZ.useQuery)({queryKey:["sessionLogs",m],queryFn:async()=>{if(!m||!u)return[];let e=await (0,eX.sessionSpendLogsCall)(u,m);return(e.data||e||[]).map(e=>({...e,request_duration_ms:e.request_duration_ms??Date.parse(e.endTime)-Date.parse(e.startTime)})).sort((e,t)=>{let s=+!!x.MCP_CALL_TYPES.includes(e.call_type),a=+!!x.MCP_CALL_TYPES.includes(t.call_type);return s!==a?s-a:new Date(e.startTime).getTime()-new Date(t.startTime).getTime()})},enabled:!!(e&&b&&m&&u)}),L=(0,s.useMemo)(()=>b?T.length?v?T.find(e=>e.request_id===v)||T[0]:c?.request_id&&T.find(e=>e.request_id===c.request_id)||T[0]:null:c,[b,c,v,T]);(0,s.useEffect)(()=>{b&&T.length&&(v&&T.some(e=>e.request_id===v)||_(c?.request_id&&T.some(e=>e.request_id===c.request_id)?c.request_id:T[0].request_id))},[b,c,v,T]),(0,s.useEffect)(()=>{e?w(!1):(b&&_(null),k(!1))},[e,b]);let{selectNextLog:M,selectPreviousLog:E}=(0,h.useKeyboardNavigation)({isOpen:e,currentLog:L,allLogs:b?T:f,onClose:d,onSelectLog:e=>{b&&_(e.request_id),y?.(e)}}),A=((e,t,s)=>{let{accessToken:a}=(0,e0.default)();return(0,eZ.useQuery)({queryKey:["logDetails",e,t,a],queryFn:async()=>a&&e&&t?await (0,eX.uiSpendLogDetailsCall)(a,e,t):null,enabled:s&&!!a&&!!e&&!!t,staleTime:6e5,gcTime:6e5})})(L?.request_id,j,e&&!!L?.request_id),D=A.data,O=A.isLoading,z=(0,s.useMemo)(()=>L?{...L,messages:D?.messages||L.messages,response:D?.response||L.response,proxy_server_request:D?.proxy_server_request||L.proxy_server_request}:null,[L,D]),R=L?.metadata||{},P="failure"===R.status?"Failure":"Success",B="failure"===R.status?"error":"success",F=R?.user_api_key_team_alias||"default",q=T.reduce((e,t)=>e+(t.spend||0),0),H=T.length>0?new Date(Math.min(...T.map(e=>new Date(e.startTime).getTime()))):null,$=T.length>0?new Date(Math.max(...T.map(e=>new Date(e.endTime).getTime()))):null,Y=H&&$?(($.getTime()-H.getTime())/1e3).toFixed(2):"0.00",K=T.filter(e=>!x.MCP_CALL_TYPES.includes(e.call_type)&&!x.AGENT_CALL_TYPES.includes(e.call_type)).length,V=T.filter(e=>x.AGENT_CALL_TYPES.includes(e.call_type)).length,W=T.filter(e=>x.MCP_CALL_TYPES.includes(e.call_type)).length,U=b?T:L?[L]:[],G=b?m||"":L?.request_id||"",J=G.length>14?`${G.slice(0,11)}...`:G,Q=async()=>{if(G)try{await navigator.clipboard.writeText(G),k(!0),setTimeout(()=>k(!1),1200)}catch{}};return L&&z?(0,t.jsx)(l.Drawer,{title:null,placement:"right",onClose:d,open:e,width:I.DRAWER_WIDTH,closable:!1,mask:!0,maskClosable:!0,styles:{body:{padding:0,overflow:"hidden"},header:{display:"none"}},children:(0,t.jsxs)("div",{style:{height:"100%"},className:"flex relative",children:[N?(0,t.jsx)(a.Button,{type:"text",size:"small",icon:(0,t.jsx)(o.RightOutlined,{}),onClick:()=>w(!1),className:"absolute top-2 left-2 z-20 !bg-white !border !border-slate-200 !rounded-md","aria-label":"Expand trace sidebar"}):(0,t.jsx)(a.Button,{type:"text",size:"small",icon:(0,t.jsx)(n.LeftOutlined,{}),onClick:()=>w(!0),className:"absolute top-2 left-2 z-20 !bg-white !border !border-slate-200 !rounded-md","aria-label":"Collapse trace sidebar"}),!N&&(0,t.jsxs)("div",{className:"border-r border-slate-200 bg-slate-50 flex flex-col",style:{width:224},children:[(0,t.jsxs)("div",{className:"pl-12 pr-3 py-2 border-b border-slate-200 bg-white",children:[(0,t.jsx)("div",{className:"flex items-start justify-between gap-2",children:(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{className:"text-[10px] uppercase tracking-wide text-slate-500",children:b?"Session":"Trace"}),(0,t.jsxs)("div",{className:"font-mono text-[12px] text-slate-900 leading-tight flex items-center gap-1",children:[(0,t.jsx)("span",{className:"truncate",children:J}),(0,t.jsx)("button",{type:"button",onClick:Q,className:"text-slate-400 hover:text-slate-600","aria-label":"Copy trace id",children:S?(0,t.jsx)(r.CheckOutlined,{className:"text-[11px]"}):(0,t.jsx)(i.CopyOutlined,{className:"text-[11px]"})})]})]})}),(0,t.jsxs)("div",{className:"mt-1 text-[11px] text-slate-500 font-mono",children:[U.length," req",[b?K:U.filter(e=>!x.MCP_CALL_TYPES.includes(e.call_type)&&!x.AGENT_CALL_TYPES.includes(e.call_type)).length,b?V:U.filter(e=>x.AGENT_CALL_TYPES.includes(e.call_type)).length,b?W:U.filter(e=>x.MCP_CALL_TYPES.includes(e.call_type)).length].map((e,s)=>{let a=[" LLM"," Agent"," MCP"][s];return e>0?(0,t.jsxs)("span",{children:[(0,t.jsx)("span",{className:"mx-1.5",children:"·"}),e,a]},a):null}),(0,t.jsx)("span",{className:"mx-1.5",children:"·"}),b?(0,C.getSpendString)(q):(0,C.getSpendString)(L.spend||0),b&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("span",{className:"mx-1.5",children:"·"}),Y,"s"]})]})]}),(0,t.jsxs)("div",{className:"flex-1 overflow-y-auto",children:[ee(R?.guardrail_information).length>0&&(0,t.jsx)("div",{className:"px-3 pt-2",children:(0,t.jsx)(eJ,{guardrailEntries:ee(R?.guardrail_information)})}),b?(0,t.jsx)("div",{className:"py-1",children:(0,t.jsxs)("div",{className:"relative pl-2",children:[(0,t.jsx)("div",{className:"absolute left-4 top-1 bottom-1 border-l border-slate-300"}),U.map((e,s)=>{let a=s===U.length-1;return(0,t.jsxs)("div",{className:"relative",children:[(0,t.jsx)("div",{className:"absolute left-4 top-3 w-3 border-t border-slate-300"}),a&&(0,t.jsx)("div",{className:"absolute left-4 top-3 bottom-0 w-px bg-slate-50"}),(0,t.jsx)(e1,{row:e,isSelected:e.request_id===L.request_id,onClick:()=>{_(e.request_id),y?.(e)}})]},e.request_id)})]})}):(0,t.jsx)("div",{className:"py-1",children:U.map(e=>(0,t.jsx)(e1,{row:e,isSelected:e.request_id===L.request_id,onClick:()=>y?.(e)},e.request_id))})]})]}),(0,t.jsxs)("div",{className:"flex-1 flex flex-col overflow-hidden",children:[(0,t.jsx)(p.DrawerHeader,{log:L,onClose:d,onPrevious:E,onNext:M,statusLabel:P,statusColor:B,environment:F}),(0,t.jsx)("div",{className:"flex-1 overflow-y-auto",children:(0,t.jsx)(eY,{logEntry:z,onOpenSettings:g,isLoadingDetails:O,accessToken:u??null})})]})]})}):null}e.s(["LogDetailsDrawer",()=>e2],502626),e.s([],3565)},95684,e=>{"use strict";var t=e.i(165370);e.s(["Pagination",()=>t.default])},307582,e=>{"use strict";var t=e.i(843476);e.s(["TimeCell",0,({utcTime:e})=>(0,t.jsx)("span",{style:{fontFamily:"monospace",width:"180px",display:"inline-block"},children:(e=>{try{return new Date(e).toLocaleString("en-US",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!0}).replace(",","")}catch(e){return"Error converting time"}})(e)})])},93648,245767,291950,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(207082),l=e.i(500330),r=e.i(871943),i=e.i(360820),n=e.i(94629),o=e.i(152990),d=e.i(682830),c=e.i(269200),m=e.i(942232),x=e.i(977572),u=e.i(427612),p=e.i(64848),h=e.i(496020),g=e.i(592968);function f({keys:e,totalCount:a,isLoading:f,isFetching:y,pageIndex:j,pageSize:b,onPageChange:v}){let[_,N]=(0,s.useState)([{id:"deleted_at",desc:!0}]),[w,S]=(0,s.useState)({pageIndex:j,pageSize:b});s.default.useEffect(()=>{S({pageIndex:j,pageSize:b})},[j,b]);let k=[{id:"token",accessorKey:"token",header:"Key ID",size:150,maxSize:250,cell:e=>{let s=e.getValue();return(0,t.jsx)(g.Tooltip,{title:s,children:(0,t.jsx)("span",{className:"font-mono text-blue-500 text-xs truncate block max-w-[250px]",children:s||"-"})})}},{id:"key_alias",accessorKey:"key_alias",header:"Key Alias",size:150,maxSize:200,cell:e=>{let s=e.getValue();return(0,t.jsx)(g.Tooltip,{title:s,children:(0,t.jsx)("span",{className:"font-mono text-xs truncate block max-w-[200px]",children:s??"-"})})}},{id:"team_alias",accessorKey:"team_alias",header:"Team Alias",size:120,maxSize:180,cell:e=>{let s=e.getValue();return(0,t.jsx)("span",{className:"truncate block max-w-[180px]",children:s||"-"})}},{id:"spend",accessorKey:"spend",header:"Spend (USD)",size:100,maxSize:140,cell:e=>(0,t.jsx)("span",{className:"block max-w-[140px]",children:(0,l.formatNumberWithCommas)(e.getValue(),4)})},{id:"max_budget",accessorKey:"max_budget",header:"Budget (USD)",size:110,maxSize:150,cell:e=>{let s=e.getValue();return(0,t.jsx)("span",{className:"block max-w-[150px]",children:null===s?"Unlimited":`$${(0,l.formatNumberWithCommas)(s)}`})}},{id:"user_email",accessorKey:"user_email",header:"User Email",size:160,maxSize:250,cell:e=>{let s=e.getValue();return(0,t.jsx)(g.Tooltip,{title:s,children:(0,t.jsx)("span",{className:"font-mono text-xs truncate block max-w-[250px]",children:s??"-"})})}},{id:"user_id",accessorKey:"user_id",header:"User ID",size:120,maxSize:200,cell:e=>{let s=e.getValue();return(0,t.jsx)(g.Tooltip,{title:s||void 0,children:(0,t.jsx)("span",{className:"truncate block max-w-[200px]",children:s||"-"})})}},{id:"created_at",accessorKey:"created_at",header:"Created At",size:120,maxSize:140,cell:e=>{let s=e.getValue();return(0,t.jsx)("span",{className:"block max-w-[140px]",children:s?new Date(s).toLocaleDateString():"-"})}},{id:"created_by",accessorKey:"created_by",header:"Created By",size:120,maxSize:180,cell:e=>{let s=e.row.original.created_by;return(0,t.jsx)(g.Tooltip,{title:s||void 0,children:(0,t.jsx)("span",{className:"truncate block max-w-[180px]",children:s||"-"})})}},{id:"deleted_at",accessorKey:"deleted_at",header:"Deleted At",size:120,maxSize:140,cell:e=>{let s=e.row.original.deleted_at;return(0,t.jsx)("span",{className:"block max-w-[140px]",children:s?new Date(s).toLocaleDateString():"-"})}},{id:"deleted_by",accessorKey:"deleted_by",header:"Deleted By",size:120,maxSize:180,cell:e=>{let s=e.row.original.deleted_by;return(0,t.jsx)(g.Tooltip,{title:s||void 0,children:(0,t.jsx)("span",{className:"truncate block max-w-[180px]",children:s||"-"})})}}],C=(0,o.useReactTable)({data:e,columns:k,columnResizeMode:"onChange",columnResizeDirection:"ltr",state:{sorting:_,pagination:w},onSortingChange:N,onPaginationChange:e=>{let t="function"==typeof e?e(w):e;S(t),v(t.pageIndex)},getCoreRowModel:(0,d.getCoreRowModel)(),getSortedRowModel:(0,d.getSortedRowModel)(),getPaginationRowModel:(0,d.getPaginationRowModel)(),enableSorting:!0,manualSorting:!1,manualPagination:!0,pageCount:Math.ceil(a/b)}),{pageIndex:T}=C.getState().pagination,L=T*b+1,M=Math.min((T+1)*b,a),E=`${L} - ${M}`;return(0,t.jsx)("div",{className:"w-full h-full overflow-hidden",children:(0,t.jsxs)("div",{className:"border-b py-4 flex-1 overflow-hidden",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between w-full mb-4",children:[f||y?(0,t.jsx)("span",{className:"inline-flex text-sm text-gray-700",children:"Loading..."}):(0,t.jsxs)("span",{className:"inline-flex text-sm text-gray-700",children:["Showing ",E," of ",a," results"]}),(0,t.jsxs)("div",{className:"inline-flex items-center gap-2",children:[f||y?(0,t.jsx)("span",{className:"text-sm text-gray-700",children:"Loading..."}):(0,t.jsxs)("span",{className:"text-sm text-gray-700",children:["Page ",T+1," of ",C.getPageCount()]}),(0,t.jsx)("button",{onClick:()=>C.previousPage(),disabled:f||y||!C.getCanPreviousPage(),className:"px-3 py-1 text-sm border rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed",children:"Previous"}),(0,t.jsx)("button",{onClick:()=>C.nextPage(),disabled:f||y||!C.getCanNextPage(),className:"px-3 py-1 text-sm border rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed",children:"Next"})]})]}),(0,t.jsx)("div",{className:"h-[75vh] overflow-auto",children:(0,t.jsx)("div",{className:"rounded-lg custom-border relative",children:(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)(c.Table,{className:"[&_td]:py-0.5 [&_th]:py-1",style:{width:C.getCenterTotalSize()},children:[(0,t.jsx)(u.TableHead,{children:C.getHeaderGroups().map(e=>(0,t.jsx)(h.TableRow,{children:e.headers.map(e=>(0,t.jsx)(p.TableHeaderCell,{"data-header-id":e.id,className:"py-1 h-8 relative hover:bg-gray-50",style:{width:e.getSize(),maxWidth:e.column.columnDef.maxSize,position:"relative"},onMouseEnter:()=>{let t=document.querySelector(`[data-header-id="${e.id}"] .resizer`);t&&(t.style.opacity="0.5")},onMouseLeave:()=>{let t=document.querySelector(`[data-header-id="${e.id}"] .resizer`);t&&!e.column.getIsResizing()&&(t.style.opacity="0")},onClick:e.column.getToggleSortingHandler(),children:(0,t.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,t.jsx)("div",{className:"flex items-center",children:e.isPlaceholder?null:(0,o.flexRender)(e.column.columnDef.header,e.getContext())}),(0,t.jsx)("div",{className:"w-4",children:e.column.getIsSorted()?({asc:(0,t.jsx)(i.ChevronUpIcon,{className:"h-4 w-4 text-blue-500"}),desc:(0,t.jsx)(r.ChevronDownIcon,{className:"h-4 w-4 text-blue-500"})})[e.column.getIsSorted()]:(0,t.jsx)(n.SwitchVerticalIcon,{className:"h-4 w-4 text-gray-400"})}),(0,t.jsx)("div",{onDoubleClick:()=>e.column.resetSize(),onMouseDown:e.getResizeHandler(),onTouchStart:e.getResizeHandler(),className:`resizer ${C.options.columnResizeDirection} ${e.column.getIsResizing()?"isResizing":""}`,style:{position:"absolute",right:0,top:0,height:"100%",width:"5px",background:e.column.getIsResizing()?"#3b82f6":"transparent",cursor:"col-resize",userSelect:"none",touchAction:"none",opacity:+!!e.column.getIsResizing()}})]})},e.id))},e.id))}),(0,t.jsx)(m.TableBody,{children:f||y?(0,t.jsx)(h.TableRow,{children:(0,t.jsx)(x.TableCell,{colSpan:k.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"🚅 Loading keys..."})})})}):e.length>0?C.getRowModel().rows.map(e=>(0,t.jsx)(h.TableRow,{className:"h-8",children:e.getVisibleCells().map(e=>(0,t.jsx)(x.TableCell,{style:{width:e.column.getSize(),maxWidth:e.column.columnDef.maxSize,whiteSpace:"pre-wrap",overflow:"hidden"},className:"py-0.5 max-h-8 overflow-hidden text-ellipsis whitespace-nowrap",children:(0,o.flexRender)(e.column.columnDef.cell,e.getContext())},e.id))},e.id)):(0,t.jsx)(h.TableRow,{children:(0,t.jsx)(x.TableCell,{colSpan:k.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"No deleted keys found"})})})})})]})})})})]})})}function y(){let[e,l]=(0,s.useState)(0),[r]=(0,s.useState)(50),{data:i,isPending:n,isFetching:o}=(0,a.useDeletedKeys)(e+1,r);return(0,t.jsx)(f,{keys:i?.keys||[],totalCount:i?.total_count||0,isLoading:n,isFetching:o,pageIndex:e,pageSize:r,onPageChange:l})}e.s(["default",()=>y],93648);var j=e.i(785242),b=e.i(389083),v=e.i(599724),_=e.i(355619);function N({teams:e,isLoading:a,isFetching:f}){let[y,j]=(0,s.useState)([{id:"deleted_at",desc:!0}]),N=[{id:"team_alias",accessorKey:"team_alias",header:"Team Name",size:150,maxSize:200,cell:e=>{let s=e.getValue();return(0,t.jsx)(g.Tooltip,{title:s||void 0,children:(0,t.jsx)("span",{className:"truncate block max-w-[200px]",children:s||"-"})})}},{id:"team_id",accessorKey:"team_id",header:"Team ID",size:150,maxSize:250,cell:e=>{let s=e.getValue();return(0,t.jsx)(g.Tooltip,{title:s,children:(0,t.jsx)("span",{className:"font-mono text-blue-500 text-xs truncate block max-w-[250px]",children:s||"-"})})}},{id:"created_at",accessorKey:"created_at",header:"Created",size:120,maxSize:140,cell:e=>{let s=e.getValue();return(0,t.jsx)("span",{className:"block max-w-[140px]",children:s?new Date(s).toLocaleDateString():"-"})}},{id:"spend",accessorKey:"spend",header:"Spend (USD)",size:100,maxSize:140,cell:e=>{let s=e.row.original.spend;return(0,t.jsx)("span",{className:"block max-w-[140px]",children:void 0!==s?(0,l.formatNumberWithCommas)(s,4):"-"})}},{id:"max_budget",accessorKey:"max_budget",header:"Budget (USD)",size:110,maxSize:150,cell:e=>{let s=e.getValue();return(0,t.jsx)("span",{className:"block max-w-[150px]",children:null==s?"No limit":`$${(0,l.formatNumberWithCommas)(s)}`})}},{id:"models",accessorKey:"models",header:"Models",size:200,maxSize:300,cell:e=>{let s=e.getValue();return Array.isArray(s)&&0!==s.length?(0,t.jsxs)("div",{className:"flex flex-wrap gap-1 max-w-[300px]",children:[s.slice(0,3).map((e,s)=>"all-proxy-models"===e?(0,t.jsx)(b.Badge,{size:"xs",color:"red",children:(0,t.jsx)(v.Text,{children:"All Proxy Models"})},s):(0,t.jsx)(b.Badge,{size:"xs",color:"blue",children:(0,t.jsx)(v.Text,{children:e.length>30?`${(0,_.getModelDisplayName)(e).slice(0,30)}...`:(0,_.getModelDisplayName)(e)})},s)),s.length>3&&(0,t.jsx)(b.Badge,{size:"xs",color:"gray",children:(0,t.jsxs)(v.Text,{children:["+",s.length-3," ",s.length-3==1?"more model":"more models"]})})]}):(0,t.jsx)(b.Badge,{size:"xs",color:"red",children:(0,t.jsx)(v.Text,{children:"All Proxy Models"})})}},{id:"organization_id",accessorKey:"organization_id",header:"Organization",size:150,maxSize:200,cell:e=>{let s=e.getValue();return(0,t.jsx)(g.Tooltip,{title:s||void 0,children:(0,t.jsx)("span",{className:"truncate block max-w-[200px]",children:s||"-"})})}},{id:"deleted_at",accessorKey:"deleted_at",header:"Deleted At",size:120,maxSize:140,cell:e=>{let s=e.row.original.deleted_at;return(0,t.jsx)("span",{className:"block max-w-[140px]",children:s?new Date(s).toLocaleDateString():"-"})}},{id:"deleted_by",accessorKey:"deleted_by",header:"Deleted By",size:120,maxSize:180,cell:e=>{let s=e.row.original.deleted_by;return(0,t.jsx)(g.Tooltip,{title:s||void 0,children:(0,t.jsx)("span",{className:"truncate block max-w-[180px]",children:s||"-"})})}}],w=(0,o.useReactTable)({data:e,columns:N,columnResizeMode:"onChange",columnResizeDirection:"ltr",state:{sorting:y},onSortingChange:j,getCoreRowModel:(0,d.getCoreRowModel)(),getSortedRowModel:(0,d.getSortedRowModel)(),enableSorting:!0,manualSorting:!1});return(0,t.jsx)("div",{className:"w-full h-full overflow-hidden",children:(0,t.jsxs)("div",{className:"border-b py-4 flex-1 overflow-hidden",children:[(0,t.jsx)("div",{className:"flex items-center justify-between w-full mb-4",children:a||f?(0,t.jsx)("span",{className:"inline-flex text-sm text-gray-700",children:"Loading..."}):(0,t.jsxs)("span",{className:"inline-flex text-sm text-gray-700",children:["Showing ",e.length," ",1===e.length?"team":"teams"]})}),(0,t.jsx)("div",{className:"h-[75vh] overflow-auto",children:(0,t.jsx)("div",{className:"rounded-lg custom-border relative",children:(0,t.jsx)("div",{className:"overflow-x-auto",children:(0,t.jsxs)(c.Table,{className:"[&_td]:py-0.5 [&_th]:py-1",style:{width:w.getCenterTotalSize()},children:[(0,t.jsx)(u.TableHead,{children:w.getHeaderGroups().map(e=>(0,t.jsx)(h.TableRow,{children:e.headers.map(e=>(0,t.jsx)(p.TableHeaderCell,{"data-header-id":e.id,className:"py-1 h-8 relative hover:bg-gray-50",style:{width:e.getSize(),maxWidth:e.column.columnDef.maxSize,position:"relative"},onMouseEnter:()=>{let t=document.querySelector(`[data-header-id="${e.id}"] .resizer`);t&&(t.style.opacity="0.5")},onMouseLeave:()=>{let t=document.querySelector(`[data-header-id="${e.id}"] .resizer`);t&&!e.column.getIsResizing()&&(t.style.opacity="0")},onClick:e.column.getToggleSortingHandler(),children:(0,t.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,t.jsx)("div",{className:"flex items-center",children:e.isPlaceholder?null:(0,o.flexRender)(e.column.columnDef.header,e.getContext())}),(0,t.jsx)("div",{className:"w-4",children:e.column.getIsSorted()?({asc:(0,t.jsx)(i.ChevronUpIcon,{className:"h-4 w-4 text-blue-500"}),desc:(0,t.jsx)(r.ChevronDownIcon,{className:"h-4 w-4 text-blue-500"})})[e.column.getIsSorted()]:(0,t.jsx)(n.SwitchVerticalIcon,{className:"h-4 w-4 text-gray-400"})}),(0,t.jsx)("div",{onDoubleClick:()=>e.column.resetSize(),onMouseDown:e.getResizeHandler(),onTouchStart:e.getResizeHandler(),className:`resizer ${w.options.columnResizeDirection} ${e.column.getIsResizing()?"isResizing":""}`,style:{position:"absolute",right:0,top:0,height:"100%",width:"5px",background:e.column.getIsResizing()?"#3b82f6":"transparent",cursor:"col-resize",userSelect:"none",touchAction:"none",opacity:+!!e.column.getIsResizing()}})]})},e.id))},e.id))}),(0,t.jsx)(m.TableBody,{children:a||f?(0,t.jsx)(h.TableRow,{children:(0,t.jsx)(x.TableCell,{colSpan:N.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"🚅 Loading teams..."})})})}):e.length>0?w.getRowModel().rows.map(e=>(0,t.jsx)(h.TableRow,{className:"h-8",children:e.getVisibleCells().map(e=>(0,t.jsx)(x.TableCell,{style:{width:e.column.getSize(),maxWidth:e.column.columnDef.maxSize,whiteSpace:"pre-wrap",overflow:"hidden"},className:"py-0.5 max-h-8 overflow-hidden text-ellipsis whitespace-nowrap",children:(0,o.flexRender)(e.column.columnDef.cell,e.getContext())},e.id))},e.id)):(0,t.jsx)(h.TableRow,{children:(0,t.jsx)(x.TableCell,{colSpan:N.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:"No deleted teams found"})})})})})]})})})})]})})}function w(){let{data:e,isPending:s,isFetching:a}=(0,j.useDeletedTeams)(1,100);return(0,t.jsx)(N,{teams:e||[],isLoading:s,isFetching:a})}e.s(["default",()=>w],245767);var S=e.i(625901),k=e.i(56456),C=e.i(152473),T=e.i(199133),L=e.i(770914);let{Text:M}=e.i(898586).Typography;e.s(["PaginatedModelSelect",0,({value:e,onChange:a,placeholder:l="Select a model",style:r,pageSize:i=50,allowClear:n=!0,disabled:o=!1})=>{let[d,c]=(0,s.useState)(""),[m,x]=(0,C.useDebouncedState)("",{wait:300}),{data:u,fetchNextPage:p,hasNextPage:h,isFetchingNextPage:g,isLoading:f}=(0,S.useInfiniteModelInfo)(i,m||void 0),y=(0,s.useMemo)(()=>{if(!u?.pages)return[];let e=new Set,t=[];for(let s of u.pages)for(let a of s.data){let s=a.model_info?.id??"",l=a.model_name??"";!s||e.has(s)||(e.add(s),t.push({label:l?`${l} (${s})`:s,value:s,modelName:l,modelId:s}))}return t},[u]);return(0,t.jsx)(T.Select,{value:e||void 0,onChange:e=>{let t="string"==typeof e?e:Array.isArray(e)?e[0]??"":"";a?.(t)},placeholder:l,style:{width:"100%",...r},allowClear:n,disabled:o,showSearch:!0,filterOption:!1,onSearch:e=>{c(e),x(e)},searchValue:d,onPopupScroll:e=>{let t=e.currentTarget;(t.scrollTop+t.clientHeight)/t.scrollHeight>=.8&&h&&!g&&p()},loading:f,notFoundContent:f?(0,t.jsx)(k.LoadingOutlined,{spin:!0}):"No models found",options:y,optionRender:e=>{let{modelName:s,modelId:a}=e.data;return(0,t.jsx)(t.Fragment,{children:s?(0,t.jsxs)(L.Space,{direction:"vertical",children:[(0,t.jsxs)(L.Space,{direction:"horizontal",children:[(0,t.jsx)(M,{strong:!0,children:"Model name:"}),(0,t.jsx)(M,{ellipsis:!0,children:s})]}),(0,t.jsxs)(M,{ellipsis:!0,type:"secondary",children:["Model ID: ",a]})]}):(0,t.jsxs)(M,{ellipsis:!0,type:"secondary",children:["Model ID: ",a]})})},popupRender:e=>(0,t.jsxs)(t.Fragment,{children:[e,g&&(0,t.jsx)("div",{style:{textAlign:"center",padding:8},children:(0,t.jsx)(k.LoadingOutlined,{spin:!0})})]})})}],291950)},942161,e=>{"use strict";var t=e.i(843476),s=e.i(271645),a=e.i(266027),l=e.i(619273),r=e.i(291542),i=e.i(262218),n=e.i(311451),o=e.i(199133),d=e.i(464571),c=e.i(95684),m=e.i(482725),x=e.i(91979),u=e.i(56456),p=e.i(166540),h=e.i(764205),g=e.i(608856),f=e.i(898586),y=e.i(149192),j=e.i(166406),b=e.i(492030),v=e.i(304911);let{Text:_}=f.Typography,N={LiteLLM_VerificationToken:"Keys",LiteLLM_TeamTable:"Teams",LiteLLM_UserTable:"Users",LiteLLM_OrganizationTable:"Organizations",LiteLLM_ProxyModelTable:"Models"},w={created:"green",updated:"blue",deleted:"red",rotated:"orange"};function S({label:e,value:a}){let[l,r]=(0,s.useState)(!1),i=(0,s.useCallback)(async()=>{try{let e=JSON.stringify(a,null,2);if(navigator.clipboard&&window.isSecureContext)await navigator.clipboard.writeText(e);else{let t=document.createElement("textarea");t.value=e,t.style.position="fixed",t.style.opacity="0",document.body.appendChild(t),t.focus(),t.select(),document.execCommand("copy"),document.body.removeChild(t)}r(!0),setTimeout(()=>r(!1),2e3)}catch(e){console.error("Copy failed:",e)}},[a]);return(0,t.jsxs)("div",{className:"bg-white rounded border overflow-hidden",children:[(0,t.jsxs)("div",{className:"flex justify-between items-center px-3 py-2 border-b bg-gray-50",children:[(0,t.jsx)("span",{className:"text-xs font-semibold text-gray-600",children:e}),(0,t.jsx)("button",{onClick:i,className:"p-1 hover:bg-gray-200 rounded text-gray-500 hover:text-gray-700 transition-colors",title:"Copy JSON",children:l?(0,t.jsx)(b.CheckOutlined,{className:"text-green-600"}):(0,t.jsx)(j.CopyOutlined,{})})]}),(0,t.jsx)("pre",{className:"p-3 bg-white text-xs font-mono overflow-auto max-h-96 whitespace-pre-wrap break-all m-0",children:JSON.stringify(a,null,2)})]})}function k({label:e,value:s}){return(0,t.jsxs)("div",{className:"flex items-start gap-2 py-1.5",children:[(0,t.jsx)("span",{className:"text-xs text-gray-500 w-36 shrink-0",children:e}),(0,t.jsx)("span",{className:"text-xs text-gray-900 break-all",children:s})]})}function C({log:e}){let{action:s,table_name:a,before_value:l,updated_values:r}=e,i="LiteLLM_VerificationToken"===a,n="updated"===s||"rotated"===s,o=l,d=r;if(n&&l&&r){let e={},t={};new Set([...Object.keys(l),...Object.keys(r)]).forEach(s=>{JSON.stringify(l[s])!==JSON.stringify(r[s])&&(s in l&&(e[s]=l[s]),s in r&&(t[s]=r[s]))}),Object.keys(l).forEach(s=>{s in r||s in e||(e[s]=l[s],t[s]=void 0)}),Object.keys(r).forEach(s=>{s in l||s in t||(t[s]=r[s],e[s]=void 0)}),o=Object.keys(e).length>0?e:{note:"No differing fields detected"},d=Object.keys(t).length>0?t:{note:"No differing fields detected"}}let c=(e,s)=>{if(!s||0===Object.keys(s).length)return(0,t.jsxs)("div",{className:"bg-white rounded border overflow-hidden",children:[(0,t.jsx)("div",{className:"flex items-center px-3 py-2 border-b bg-gray-50",children:(0,t.jsx)("span",{className:"text-xs font-semibold text-gray-600",children:e})}),(0,t.jsx)("p",{className:"px-3 py-3 text-xs text-gray-400 italic m-0",children:"N/A"})]});if(i&&n){let a=["token","spend","max_budget"];if(Object.keys(s).every(e=>a.includes(e))&&!("note"in s))return(0,t.jsxs)("div",{className:"bg-white rounded border overflow-hidden",children:[(0,t.jsx)("div",{className:"flex items-center px-3 py-2 border-b bg-gray-50",children:(0,t.jsx)("span",{className:"text-xs font-semibold text-gray-600",children:e})}),(0,t.jsxs)("div",{className:"px-3 py-3 space-y-1 text-xs",children:[void 0!==s.token&&(0,t.jsxs)("p",{children:[(0,t.jsx)("span",{className:"text-gray-500",children:"Token:"})," ",s.token??"N/A"]}),void 0!==s.spend&&(0,t.jsxs)("p",{children:[(0,t.jsx)("span",{className:"text-gray-500",children:"Spend:"})," $",Number(s.spend).toFixed(6)]}),void 0!==s.max_budget&&(0,t.jsxs)("p",{children:[(0,t.jsx)("span",{className:"text-gray-500",children:"Max Budget:"})," $",Number(s.max_budget).toFixed(6)]})]})]})}return(0,t.jsx)(S,{label:e,value:s})};return(0,t.jsxs)("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4 mt-4",children:[c("Before",o),c("After",d)]})}function T({open:e,onClose:s,log:a}){if(!a)return null;let l=N[a.table_name]??a.table_name,r=w[a.action]??"default";return(0,t.jsxs)(g.Drawer,{placement:"right",width:"60%",open:e,onClose:s,closable:!1,mask:!0,maskClosable:!0,styles:{body:{padding:0,display:"flex",flexDirection:"column"},header:{display:"none"}},children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-6 py-4 border-b bg-white shrink-0",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)(i.Tag,{color:r,className:"capitalize m-0",children:a.action}),(0,t.jsx)("span",{className:"text-sm text-gray-500",children:p.default.utc(a.updated_at).local().format("MMM D, YYYY HH:mm:ss")})]}),(0,t.jsx)("button",{onClick:s,className:"w-8 h-8 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500","aria-label":"Close",children:(0,t.jsx)(y.CloseOutlined,{})})]}),(0,t.jsxs)("div",{className:"px-6 py-5",children:[(0,t.jsxs)("div",{className:"bg-gray-50 border rounded-lg p-4 mb-5",children:[(0,t.jsx)("p",{className:"text-xs font-semibold text-gray-700 mb-2 uppercase tracking-wide",children:"Details"}),(0,t.jsx)(k,{label:"Table",value:l}),(0,t.jsx)(k,{label:"Object ID",value:(0,t.jsx)(_,{copyable:!0,className:"font-mono text-xs",children:a.object_id})}),(0,t.jsx)(k,{label:"Changed By",value:(0,t.jsx)(v.default,{userId:a.changed_by})}),(0,t.jsx)(k,{label:"API Key (Hash)",value:a.changed_by_api_key?(0,t.jsx)(_,{copyable:!0,className:"font-mono text-xs break-all",children:a.changed_by_api_key}):"—"})]}),(0,t.jsx)(C,{log:a})]})]})}let{Search:L}=n.Input,M={LiteLLM_VerificationToken:"Keys",LiteLLM_TeamTable:"Teams",LiteLLM_UserTable:"Users",LiteLLM_OrganizationTable:"Organizations",LiteLLM_ProxyModelTable:"Models"},E={created:"green",updated:"blue",deleted:"red",rotated:"orange"};function A({userID:e,userRole:n,token:g,accessToken:f,isActive:y,premiumUser:j}){let[b,_]=(0,s.useState)(1),[N,w]=(0,s.useState)(""),[S,k]=(0,s.useState)(""),[C,A]=(0,s.useState)(""),[D,I]=(0,s.useState)(""),[O,z]=(0,s.useState)(void 0),[R,P]=(0,s.useState)(void 0),[B,F]=(0,s.useState)(null),[q,H]=(0,s.useState)(!1),$=(0,a.useQuery)({queryKey:["audit_logs",b,50,N,S,C,D,O,R],queryFn:async()=>f&&g&&n&&e?(0,h.uiAuditLogsCall)({accessToken:f,page:b,page_size:50,params:{object_id:N||void 0,changed_by:S||void 0,object_key_hash:C||void 0,object_team_id:D||void 0,action:O||void 0,table_name:R||void 0,sort_by:"updated_at",sort_order:"desc"}}):{audit_logs:[],total:0,page:1,page_size:50,total_pages:0},enabled:!!f&&!!g&&!!n&&!!e&&y,placeholderData:l.keepPreviousData}),Y=[{title:"Timestamp",dataIndex:"updated_at",key:"updated_at",width:200,render:e=>(0,t.jsx)("span",{className:"font-mono text-xs whitespace-nowrap",children:p.default.utc(e).local().format("MMM D, YYYY HH:mm:ss")})},{title:"Action",dataIndex:"action",key:"action",width:100,render:e=>(0,t.jsx)(i.Tag,{color:E[e]??"default",className:"capitalize",children:e})},{title:"Table",dataIndex:"table_name",key:"table_name",width:130,render:e=>M[e]??e},{title:"Object ID",dataIndex:"object_id",key:"object_id",render:e=>(0,t.jsx)("span",{className:"font-mono text-xs",children:e})},{title:"Changed By",dataIndex:"changed_by",key:"changed_by",width:200,render:e=>(0,t.jsx)(v.default,{userId:e})},{title:"API Key (Hash)",dataIndex:"changed_by_api_key",key:"changed_by_api_key",width:140,render:e=>e?(0,t.jsxs)("span",{className:"font-mono text-xs",children:[e.slice(0,12),"…"]}):"—"}];if(!j)return(0,t.jsxs)("div",{style:{textAlign:"center",marginTop:"20px"},children:[(0,t.jsx)("h1",{style:{display:"block",marginBottom:"10px"},children:"✨ Enterprise Feature."}),(0,t.jsx)("p",{style:{display:"block",marginBottom:"10px"},children:"This is a LiteLLM Enterprise feature, and requires a valid key to use."}),(0,t.jsx)("p",{style:{display:"block",marginBottom:"20px",fontStyle:"italic"},children:"Here's a preview of what Audit Logs offer:"}),(0,t.jsx)("img",{src:"../ui/assets/audit-logs-preview.png",alt:"Audit Logs Preview",style:{maxWidth:"100%",maxHeight:"700px",borderRadius:"8px",boxShadow:"0 4px 8px rgba(0,0,0,0.1)",margin:"0 auto"},onError:e=>{e.target.style.display="none"}})]});let K=$.data?.audit_logs??[],V=$.data?.total??0;return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"bg-white rounded-lg shadow",children:[(0,t.jsxs)("div",{className:"border-b px-6 py-4",children:[(0,t.jsx)("div",{className:"flex items-center justify-between mb-4",children:(0,t.jsx)("h1",{className:"text-xl font-semibold",children:"Audit Logs"})}),(0,t.jsxs)("div",{className:"flex flex-wrap items-center gap-3",children:[(0,t.jsx)(L,{placeholder:"Object ID",allowClear:!0,style:{width:200},onSearch:e=>{w(e),_(1)},onChange:e=>{e.target.value||(w(""),_(1))}}),(0,t.jsx)(L,{placeholder:"Changed By",allowClear:!0,style:{width:180},onSearch:e=>{k(e),_(1)},onChange:e=>{e.target.value||(k(""),_(1))}}),(0,t.jsx)(L,{placeholder:"Team ID",allowClear:!0,style:{width:180},onSearch:e=>{I(e),_(1)},onChange:e=>{e.target.value||(I(""),_(1))}}),(0,t.jsx)(L,{placeholder:"Key Hash",allowClear:!0,style:{width:180},onSearch:e=>{A(e),_(1)},onChange:e=>{e.target.value||(A(""),_(1))}}),(0,t.jsx)(o.Select,{placeholder:"All Actions",allowClear:!0,style:{width:140},options:[{label:"Created",value:"created"},{label:"Updated",value:"updated"},{label:"Deleted",value:"deleted"},{label:"Rotated",value:"rotated"}],onChange:e=>{z(e),_(1)}}),(0,t.jsx)(o.Select,{placeholder:"All Tables",allowClear:!0,style:{width:150},options:[{label:"Keys",value:"LiteLLM_VerificationToken"},{label:"Teams",value:"LiteLLM_TeamTable"},{label:"Users",value:"LiteLLM_UserTable"},{label:"Organizations",value:"LiteLLM_OrganizationTable"},{label:"Models",value:"LiteLLM_ProxyModelTable"}],onChange:e=>{P(e),_(1)}}),(0,t.jsxs)("div",{className:"ml-auto flex items-center gap-2",children:[(0,t.jsx)(d.Button,{icon:(0,t.jsx)(x.ReloadOutlined,{spin:$.isFetching}),onClick:()=>$.refetch(),disabled:$.isFetching}),(0,t.jsx)(c.Pagination,{current:b,pageSize:50,total:V,showTotal:e=>`${e} total`,showSizeChanger:!1,size:"small",onChange:e=>_(e)})]})]})]}),(0,t.jsx)(r.Table,{columns:Y,dataSource:K,rowKey:"id",loading:{spinning:$.isLoading,indicator:(0,t.jsx)(m.Spin,{indicator:(0,t.jsx)(u.LoadingOutlined,{spin:!0}),size:"small"})},size:"small",pagination:!1,onRow:e=>({onClick:()=>{F(e),H(!0)},style:{cursor:"pointer"}})})]}),(0,t.jsx)(T,{open:q,onClose:()=>H(!1),log:B})]})}e.s(["default",()=>A],942161)},245099,e=>{"use strict";var t=e.i(843476),s=e.i(500330),a=(e.i(389083),e.i(994388)),l=e.i(592968);e.i(271645);var r=e.i(916925),i=e.i(446891),n=e.i(307582),o=e.i(97859);let d=({size:e=12})=>(0,t.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"flex-shrink-0 text-gray-400",children:(0,t.jsx)("path",{d:"M12 3l1.912 5.813a2 2 0 0 0 1.275 1.275L21 12l-5.813 1.912a2 2 0 0 0-1.275 1.275L12 21l-1.912-5.813a2 2 0 0 0-1.275-1.275L3 12l5.813-1.912a2 2 0 0 0 1.275-1.275L12 3z"})}),c=({size:e=10})=>(0,t.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"flex-shrink-0",children:(0,t.jsx)("path",{d:"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"})}),m=({size:e=12})=>(0,t.jsxs)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"flex-shrink-0",children:[(0,t.jsx)("path",{d:"M12 8V4H8"}),(0,t.jsx)("rect",{width:"16",height:"12",x:"4",y:"8",rx:"2"}),(0,t.jsx)("path",{d:"M2 14h2"}),(0,t.jsx)("path",{d:"M20 14h2"}),(0,t.jsx)("path",{d:"M15 13v2"}),(0,t.jsx)("path",{d:"M9 13v2"})]}),x=({count:e})=>(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-blue-50 text-blue-700 border border-blue-200 rounded-full text-[11px] font-medium whitespace-nowrap",children:[(0,t.jsx)(d,{}),null!=e?e:"LLM"]}),u=({count:e})=>(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-amber-50 text-amber-700 border border-amber-200 rounded-full text-[11px] font-medium whitespace-nowrap",children:[(0,t.jsx)(c,{}),null!=e?e:"MCP"]}),p=({count:e})=>(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-violet-50 text-violet-700 border border-violet-200 rounded-full text-[11px] font-medium whitespace-nowrap",children:[(0,t.jsx)(m,{}),null!=e?e:"Agent"]}),h=({label:e,field:s,sortBy:a,sortOrder:l,onSortChange:r})=>(0,t.jsxs)("div",{className:"flex items-center gap-1",children:[(0,t.jsx)("span",{children:e}),(0,t.jsx)(i.TableHeaderSortDropdown,{sortState:a===s&&l,onSortChange:e=>{!1===e?r("startTime","desc"):r(s,e)}})]}),g=e=>[{header:e?()=>(0,t.jsx)(h,{label:"Time",field:"startTime",sortBy:e.sortBy,sortOrder:e.sortOrder,onSortChange:e.onSortChange}):"Time",accessorKey:"startTime",cell:e=>(0,t.jsx)(n.TimeCell,{utcTime:e.getValue()})},{header:"Type",id:"type",cell:e=>{let s=e.row.original,a=s.session_total_count||1,r=o.MCP_CALL_TYPES.includes(s.call_type),i=o.AGENT_CALL_TYPES.includes(s.call_type),n=s.session_llm_count??(r||i?0:a),h=s.session_agent_count??(i?a:0),g=s.session_mcp_count??(r?a:0);if(r)return(0,t.jsx)(u,{});if(i&&a<=1)return(0,t.jsx)(p,{});if(a<=1)return(0,t.jsx)(x,{});let f=(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-blue-50 text-blue-700 border border-blue-200 rounded-full text-[11px] font-medium whitespace-nowrap",children:[(0,t.jsx)(d,{}),(0,t.jsx)("span",{children:a}),h>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("span",{className:"text-blue-300",children:"·"}),(0,t.jsx)(m,{size:10})]}),g>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("span",{className:"text-blue-300",children:"·"}),(0,t.jsx)(c,{})]})]}),y=[n>0&&`${n} LLM`,h>0&&`${h} Agent`,g>0&&`${g} MCP`].filter(Boolean);return(0,t.jsx)(l.Tooltip,{title:y.join(" • "),children:f})}},{header:"Status",accessorKey:"metadata.status",cell:e=>{let s="failure"!==(e.getValue()||"Success").toLowerCase();return(0,t.jsx)("span",{className:`px-2 py-1 rounded-md text-xs font-medium inline-block text-center w-16 ${s?"bg-green-100 text-green-800":"bg-red-100 text-red-800"}`,children:s?"Success":"Failure"})}},{header:"Session ID",accessorKey:"session_id",cell:e=>{let s=String(e.getValue()||""),r=e.row.original.onSessionClick;return(0,t.jsx)(l.Tooltip,{title:String(e.getValue()||""),children:(0,t.jsx)(a.Button,{size:"xs",variant:"light",className:"font-mono text-blue-500 bg-blue-50 hover:bg-blue-100 text-xs font-normal text-xs max-w-[15ch] truncate block",onClick:()=>r?.(s),children:String(e.getValue()||"")})})}},{header:"Request ID",accessorKey:"request_id",cell:e=>(0,t.jsx)(l.Tooltip,{title:String(e.getValue()||""),children:(0,t.jsx)("span",{className:"font-mono text-xs max-w-[15ch] truncate block",children:String(e.getValue()||"")})})},{header:e?()=>(0,t.jsx)(h,{label:"Cost",field:"spend",sortBy:e.sortBy,sortOrder:e.sortOrder,onSortChange:e.onSortChange}):"Cost",accessorKey:"spend",cell:e=>{let a=e.row.original,r=a.mcp_tool_call_count||0,i=a.mcp_tool_call_spend||0;return(0,t.jsxs)("div",{className:"flex flex-col",children:[(0,t.jsx)(l.Tooltip,{title:`$${String(e.getValue()||0)}`,children:(0,t.jsx)("span",{children:(0,s.getSpendString)(e.getValue()||0)})}),r>0&&i>0&&(0,t.jsxs)("span",{className:"text-[10px] text-amber-600",children:["incl. ",(0,s.getSpendString)(i)," from ",r," MCP"]})]})}},{header:e?()=>(0,t.jsx)(h,{label:"Duration (s)",field:"request_duration_ms",sortBy:e.sortBy,sortOrder:e.sortOrder,onSortChange:e.onSortChange}):"Duration (s)",accessorKey:"request_duration_ms",cell:e=>{let s=e.getValue();if(null==s)return(0,t.jsx)("span",{children:"-"});let a=(s/1e3).toFixed(2);return(0,t.jsx)(l.Tooltip,{title:`${s}ms`,children:(0,t.jsx)("span",{className:"max-w-[15ch] truncate block",children:a})})}},{header:"TTFT (s)",accessorKey:"completionStartTime",cell:e=>{let s=e.row.original,a=e.getValue();if(!a||a===s.endTime)return(0,t.jsx)("span",{children:"-"});let r=new Date(a).getTime()-new Date(s.startTime).getTime();if(r<=0)return(0,t.jsx)("span",{children:"-"});let i=(r/1e3).toFixed(2);return(0,t.jsx)(l.Tooltip,{title:`${r}ms`,children:(0,t.jsx)("span",{className:"max-w-[15ch] truncate block",children:i})})}},{header:"Team Name",accessorKey:"metadata.user_api_key_team_alias",cell:e=>(0,t.jsx)(l.Tooltip,{title:String(e.getValue()||"-"),children:(0,t.jsx)("span",{className:"max-w-[15ch] truncate block",children:String(e.getValue()||"-")})})},{header:"Key Hash",accessorKey:"metadata.user_api_key",cell:e=>{let s=String(e.getValue()||"-"),a=e.row.original.onKeyHashClick;return(0,t.jsx)(l.Tooltip,{title:s,children:(0,t.jsx)("span",{className:"font-mono max-w-[15ch] truncate block cursor-pointer hover:text-blue-600",onClick:()=>a?.(s),children:s})})}},{header:"Key Name",accessorKey:"metadata.user_api_key_alias",cell:e=>(0,t.jsx)(l.Tooltip,{title:String(e.getValue()||"-"),children:(0,t.jsx)("span",{className:"max-w-[15ch] truncate block",children:String(e.getValue()||"-")})})},{header:"Model",accessorKey:"model",cell:e=>{let s=e.row.original,a=s.custom_llm_provider,i=String(e.getValue()||"");return(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[a&&(0,t.jsx)("img",{src:s.metadata?.mcp_tool_call_metadata?.mcp_server_logo_url?s.metadata.mcp_tool_call_metadata.mcp_server_logo_url:a?(0,r.getProviderLogoAndName)(a).logo:"",alt:"",className:"w-4 h-4",onError:e=>{e.target.style.display="none"}}),(0,t.jsx)(l.Tooltip,{title:i,children:(0,t.jsx)("span",{className:"max-w-[15ch] truncate block",children:i})})]})}},{header:e?()=>(0,t.jsx)(h,{label:"Tokens",field:"total_tokens",sortBy:e.sortBy,sortOrder:e.sortOrder,onSortChange:e.onSortChange}):"Tokens",accessorKey:"total_tokens",cell:e=>{let s=e.row.original;return(0,t.jsxs)("span",{className:"text-sm",children:[String(s.total_tokens||"0"),(0,t.jsxs)("span",{className:"text-gray-400 text-xs ml-1",children:["(",String(s.prompt_tokens||"0"),"+",String(s.completion_tokens||"0"),")"]})]})}},{header:"Internal User",accessorKey:"user",cell:e=>(0,t.jsx)(l.Tooltip,{title:String(e.getValue()||"-"),children:(0,t.jsx)("span",{className:"max-w-[15ch] truncate block",children:String(e.getValue()||"-")})})},{header:"End User",accessorKey:"end_user",cell:e=>(0,t.jsx)(l.Tooltip,{title:String(e.getValue()||"-"),children:(0,t.jsx)("span",{className:"max-w-[15ch] truncate block",children:String(e.getValue()||"-")})})},{header:"Tags",accessorKey:"request_tags",cell:e=>{let s=e.getValue();if(!s||0===Object.keys(s).length)return"-";let a=Object.entries(s),r=a[0],i=a.slice(1);return(0,t.jsx)("div",{className:"flex flex-wrap gap-1",children:(0,t.jsx)(l.Tooltip,{title:(0,t.jsx)("div",{className:"flex flex-col gap-1",children:a.map(([e,s])=>(0,t.jsxs)("span",{children:[e,": ",String(s)]},e))}),children:(0,t.jsxs)("span",{className:"px-2 py-1 bg-gray-100 rounded-full text-xs",children:[r[0],": ",String(r[1]),i.length>0&&` +${i.length}`]})})})}}];g(),e.s(["createColumns",0,g],245099)},339086,504809,e=>{"use strict";e.i(843476);var t=e.i(271645);e.s([],339086);var s=e.i(166540),a=e.i(764205),l=e.i(266027),r=e.i(633627),i=e.i(374009),n=e.i(700514);let o="Team ID",d="Key Hash",c="Request ID",m="Model",x="User ID",u="End User",p="Status",h="Key Alias",g="Error Code",f="Error Message";function y({logs:e,accessToken:y,startTime:j,endTime:b,pageSize:v=n.defaultPageSize,isCustomDate:_,setCurrentPage:N,userID:w,userRole:S,sortBy:k="startTime",sortOrder:C="desc",currentPage:T=1}){let L=(0,t.useMemo)(()=>({[o]:"",[d]:"",[c]:"",[m]:"",[x]:"",[u]:"",[p]:"",[h]:"",[g]:"",[f]:""}),[]),[M,E]=(0,t.useState)(L),[A,D]=(0,t.useState)({data:[],total:0,page:1,page_size:50,total_pages:0}),I=(0,t.useRef)(0),O=(0,t.useCallback)(async(e,t=1)=>{if(!y)return;console.log("Filters being sent to API:",e);let l=Date.now();I.current=l;let r=(0,s.default)(j).utc().format("YYYY-MM-DD HH:mm:ss"),i=_?(0,s.default)(b).utc().format("YYYY-MM-DD HH:mm:ss"):(0,s.default)().utc().format("YYYY-MM-DD HH:mm:ss");try{let s=await (0,a.uiSpendLogsCall)({accessToken:y,start_date:r,end_date:i,page:t,page_size:v,params:{api_key:e[d]||void 0,team_id:e[o]||void 0,request_id:e[c]||void 0,user_id:e[x]||void 0,end_user:e[u]||void 0,status_filter:e[p]||void 0,model_id:e[m]||void 0,key_alias:e[h]||void 0,error_code:e[g]||void 0,error_message:e[f]||void 0,sort_by:k,sort_order:C}});l===I.current&&s.data&&D(s)}catch(e){console.error("Error searching users:",e)}},[y,j,b,_,v,k,C]),z=(0,t.useMemo)(()=>(0,i.default)((e,t)=>O(e,t),300),[O]);(0,t.useEffect)(()=>()=>z.cancel(),[z]);let R=(0,t.useMemo)(()=>!!(M[h]||M[d]||M[c]||M[x]||M[u]||M[g]||M[f]||M[m]),[M]);(0,t.useEffect)(()=>{R&&y&&(z.cancel(),O(M,T))},[k,C,T,j,b,_]);let P=(0,t.useMemo)(()=>{if(!e||!e.data)return{data:[],total:0,page:1,page_size:50,total_pages:0};if(R)return e;let t=[...e.data];return M[o]&&(t=t.filter(e=>e.team_id===M[o])),M[p]&&(t=t.filter(e=>"success"===M[p]?!e.status||"success"===e.status:e.status===M[p])),M[m]&&(t=t.filter(e=>e.model_id===M[m])),M[d]&&(t=t.filter(e=>e.api_key===M[d])),M[u]&&(t=t.filter(e=>e.end_user===M[u])),M[g]&&(t=t.filter(e=>{let t=(e.metadata||{}).error_information;return t&&t.error_code===M[g]})),{data:t,total:e.total,page:e.page,page_size:e.page_size,total_pages:e.total_pages}},[e,M,R]),B=(0,t.useMemo)(()=>R?A&&A.data&&A.data.length>0?A:e||{data:[],total:0,page:1,page_size:50,total_pages:0}:P,[R,A,P,e]),{data:F}=(0,l.useQuery)({queryKey:["allTeamsForLogFilters",y],queryFn:async()=>y&&await (0,r.fetchAllTeams)(y)||[],enabled:!!y});return{filters:M,filteredLogs:B,hasBackendFilters:R,allTeams:F,handleFilterChange:e=>{E(t=>{let s={...t,...e};for(let e of Object.keys(L))e in s||(s[e]=L[e]);return JSON.stringify(s)!==JSON.stringify(t)&&(N(1),z(s,1)),s})},handleFilterReset:()=>{E(L),D({data:[],total:0,page:1,page_size:50,total_pages:0}),z(L,1)}}}e.s(["useLogFilterLogic",()=>y],504809)},936190,e=>{"use strict";var t=e.i(843476),s=e.i(619273),a=e.i(266027),l=e.i(912598),r=e.i(166540),i=e.i(271645);e.i(517442),e.i(500330),e.i(122550);var n=e.i(313603),o=e.i(772345),d=e.i(793130),c=e.i(197647),m=e.i(653824),x=e.i(881073),u=e.i(404206),p=e.i(723731),h=e.i(464571),g=e.i(708347),f=e.i(93648),y=e.i(245767),j=e.i(50882),b=e.i(291950),v=e.i(969550),_=e.i(764205),N=e.i(20147),w=e.i(942161),S=e.i(245099);e.i(70969);var k=e.i(97859);e.i(70635),e.i(339086);var C=e.i(504809);e.i(3565);var T=e.i(502626),L=e.i(727749);e.i(867612);var M=e.i(153472),E=e.i(954616),A=e.i(135214);let D=async(e,t)=>{let s=(0,_.getProxyBaseUrl)(),a=s?`${s}/config/update`:"/config/update",l=await fetch(a,{method:"POST",headers:{[(0,_.getGlobalLitellmHeaderName)()]:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({general_settings:{store_prompts_in_spend_logs:t.store_prompts_in_spend_logs,...t.maximum_spend_logs_retention_period&&{maximum_spend_logs_retention_period:t.maximum_spend_logs_retention_period}}})});if(!l.ok){let e=await l.json().catch(()=>({}));throw Error(e?.error?.message||e?.message||e?.detail||"Failed to update spend logs settings")}return await l.json()};var I=e.i(190702),O=e.i(637235),z=e.i(808613),R=e.i(311451),P=e.i(212931),B=e.i(981339),F=e.i(770914),q=e.i(790848),H=e.i(898586);let $=({isVisible:e,onCancel:s,onSuccess:a})=>{let[l]=z.Form.useForm(),{mutateAsync:r,isPending:n}=(()=>{let{accessToken:e}=(0,A.default)();return(0,E.useMutation)({mutationFn:async t=>{if(!e)throw Error("Access token is required");return await D(e,t)}})})(),{mutateAsync:o,isPending:d}=(0,M.useDeleteProxyConfigField)(),{data:c,isLoading:m,refetch:x}=(0,M.useProxyConfig)(M.ConfigType.GENERAL_SETTINGS),u=z.Form.useWatch("store_prompts_in_spend_logs",l);(0,i.useEffect)(()=>{e&&x()},[e,x]);let p=(0,i.useMemo)(()=>{if(!c)return{store_prompts_in_spend_logs:!1,maximum_spend_logs_retention_period:void 0};let e=c.find(e=>"store_prompts_in_spend_logs"===e.field_name),t=c.find(e=>"maximum_spend_logs_retention_period"===e.field_name);return{store_prompts_in_spend_logs:e?.field_value??!1,maximum_spend_logs_retention_period:t?.field_value??void 0}},[c]),g=async e=>{try{let t=e.maximum_spend_logs_retention_period;if(!t||"string"==typeof t&&""===t.trim())try{await o({config_type:M.ConfigType.GENERAL_SETTINGS,field_name:M.GeneralSettingsFieldName.MAXIMUM_SPEND_LOGS_RETENTION_PERIOD})}catch(e){console.warn("Failed to delete retention period field (may not exist):",e)}let s={store_prompts_in_spend_logs:e.store_prompts_in_spend_logs,...t&&"string"==typeof t&&""!==t.trim()&&{maximum_spend_logs_retention_period:t}};await r(s,{onSuccess:()=>{L.default.success("Spend logs settings updated successfully"),x(),a?.()},onError:e=>{L.default.fromBackend("Failed to save spend logs settings: "+(0,I.parseErrorMessage)(e))}})}catch(e){L.default.fromBackend("Failed to save spend logs settings: "+(0,I.parseErrorMessage)(e))}},f=()=>{l.resetFields(),s()};return(0,t.jsx)(P.Modal,{title:(0,t.jsx)(H.Typography.Title,{level:5,children:"Spend Logs Settings"}),open:e,footer:(0,t.jsxs)(F.Space,{children:[(0,t.jsx)(h.Button,{onClick:f,disabled:n||d||m,children:"Cancel"}),(0,t.jsx)(h.Button,{type:"primary",loading:n||d,disabled:m,onClick:()=>l.submit(),children:n||d?"Saving...":"Save Settings"})]}),onCancel:f,children:(0,t.jsxs)(z.Form,{form:l,layout:"horizontal",onFinish:g,initialValues:p,children:[(0,t.jsx)(z.Form.Item,{label:"Store Prompts in Spend Logs",name:"store_prompts_in_spend_logs",tooltip:c?.find(e=>"store_prompts_in_spend_logs"===e.field_name)?.field_description||"When enabled, prompts will be stored in spend logs for tracking and analysis purposes.",valuePropName:"checked",children:(0,t.jsx)("div",{children:m?(0,t.jsx)(B.Skeleton.Input,{active:!0,block:!0}):(0,t.jsx)(q.Switch,{checked:u??!1,onChange:e=>l.setFieldValue("store_prompts_in_spend_logs",e)})})}),(0,t.jsx)(z.Form.Item,{label:"Maximum Spend Logs Retention Period (Optional)",name:"maximum_spend_logs_retention_period",tooltip:c?.find(e=>"maximum_spend_logs_retention_period"===e.field_name)?.field_description||"Set the maximum retention period for spend logs (e.g., '7d' for 7 days, '30d' for 30 days). Leave empty for no limit.",children:m?(0,t.jsx)(B.Skeleton.Input,{active:!0,block:!0}):(0,t.jsx)(R.Input,{placeholder:"e.g., 7d, 30d",prefix:(0,t.jsx)(O.ClockCircleOutlined,{})})})]},c?JSON.stringify(p):"loading")})};var Y=e.i(149121);function K({accessToken:e,token:L,userRole:M,userID:E,allTeams:A,premiumUser:D}){let[I,O]=(0,i.useState)(""),[z,R]=(0,i.useState)(!1),[P,B]=(0,i.useState)(!1),[F,q]=(0,i.useState)(1),[H]=(0,i.useState)(50),K=(0,i.useRef)(null),V=(0,i.useRef)(null),W=(0,i.useRef)(null),[U,G]=(0,i.useState)((0,r.default)().subtract(24,"hours").format("YYYY-MM-DDTHH:mm")),[J,Q]=(0,i.useState)((0,r.default)().format("YYYY-MM-DDTHH:mm")),[X,Z]=(0,i.useState)(!1),[ee,et]=(0,i.useState)(!1),[es,ea]=(0,i.useState)(""),[el,er]=(0,i.useState)(""),[ei,en]=(0,i.useState)(""),[eo,ed]=(0,i.useState)(""),[ec,em]=(0,i.useState)(""),[ex,eu]=(0,i.useState)(null),[ep,eh]=(0,i.useState)(null),[eg,ef]=(0,i.useState)(""),[ey,ej]=(0,i.useState)(""),[eb,ev]=(0,i.useState)(M&&g.internalUserRoles.includes(M)),[e_,eN]=(0,i.useState)("request logs"),[ew,eS]=(0,i.useState)(null),[ek,eC]=(0,i.useState)(!1),[eT,eL]=(0,i.useState)(null),[eM,eE]=(0,i.useState)(!1),[eA,eD]=(0,i.useState)("startTime"),[eI,eO]=(0,i.useState)("desc"),[ez,eR]=(0,i.useState)(!0);(0,l.useQueryClient)();let[eP,eB]=(0,i.useState)(()=>{let e=sessionStorage.getItem("isLiveTail");return null===e||JSON.parse(e)});(0,i.useEffect)(()=>{sessionStorage.setItem("isLiveTail",JSON.stringify(eP))},[eP]);let[eF,eq]=(0,i.useState)({value:24,unit:"hours"});(0,i.useEffect)(()=>{(async()=>{ep&&e&&eu({...(await (0,_.keyInfoV1Call)(e,ep)).info,token:ep,api_key:ep})})()},[ep,e]),(0,i.useEffect)(()=>{function e(e){K.current&&!K.current.contains(e.target)&&B(!1),V.current&&!V.current.contains(e.target)&&R(!1),W.current&&!W.current.contains(e.target)&&et(!1)}return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[]),(0,i.useEffect)(()=>{M&&g.internalUserRoles.includes(M)&&ev(!0)},[M]);let eH=(0,a.useQuery)({queryKey:["logs","table",F,H,U,J,ei,eo,eb?E:null,eg,ec,eA,eI],queryFn:async()=>{if(!e||!L||!M||!E)return{data:[],total:0,page:1,page_size:H,total_pages:0};let t=(0,r.default)(U).utc().format("YYYY-MM-DD HH:mm:ss"),s=X?(0,r.default)(J).utc().format("YYYY-MM-DD HH:mm:ss"):(0,r.default)().utc().format("YYYY-MM-DD HH:mm:ss");return await (0,_.uiSpendLogsCall)({accessToken:e,start_date:t,end_date:s,page:F,page_size:H,params:{api_key:eo||void 0,team_id:ei||void 0,user_id:eb?E??void 0:void 0,end_user:ey||void 0,status_filter:eg||void 0,model_id:ec||void 0,sort_by:eA,sort_order:eI}})},enabled:!!e&&!!L&&!!M&&!!E&&"request logs"===e_&&ez,refetchInterval:!!eP&&1===F&&15e3,placeholderData:s.keepPreviousData,refetchIntervalInBackground:!0}),e$=(0,i.useDeferredValue)(eH.isFetching),eY=eH.isFetching||e$,eK=eH.data||{data:[],total:0,page:1,page_size:H||10,total_pages:1},{filters:eV,filteredLogs:eW,hasBackendFilters:eU,allTeams:eG,handleFilterChange:eJ,handleFilterReset:eQ}=(0,C.useLogFilterLogic)({logs:eK,accessToken:e,startTime:U,endTime:J,pageSize:H,isCustomDate:X,setCurrentPage:q,userID:E,userRole:M,sortBy:eA,sortOrder:eI,currentPage:F}),eX=(0,i.useCallback)(()=>{eQ(),G((0,r.default)().subtract(24,"hours").format("YYYY-MM-DDTHH:mm")),Q((0,r.default)().format("YYYY-MM-DDTHH:mm")),Z(!1),eq({value:24,unit:"hours"}),q(1)},[eQ]);if((0,i.useEffect)(()=>{eR(!eU)},[eU]),(0,i.useEffect)(()=>{e&&(eV["Team ID"]?en(eV["Team ID"]):en(""),ef(eV.Status||""),em(eV.Model||""),ej(eV["End User"]||""),ed(eV["Key Hash"]||""))},[eV,e]),!e||!L||!M||!E)return null;let eZ=eW.data.filter(e=>!I||e.request_id.includes(I)||e.model.includes(I)||e.user&&e.user.includes(I)),e0=eZ.reduce((e,t)=>(t.session_id&&(e[t.session_id]||(e[t.session_id]={llm:0,agent:0,mcp:0}),k.MCP_CALL_TYPES.includes(t.call_type)?e[t.session_id].mcp+=1:k.AGENT_CALL_TYPES.includes(t.call_type)?e[t.session_id].agent+=1:e[t.session_id].llm+=1),e),{}),e1=new Map;for(let e of eZ){if(!e.session_id||1>=(e.session_total_count||1))continue;let t=k.MCP_CALL_TYPES.includes(e.call_type),s=e1.get(e.session_id);s&&(!s.isMcp||t)||e1.set(e.session_id,{requestId:e.request_id,isMcp:t})}let e2=eZ.map(e=>{let t=e.session_id?e0[e.session_id]:void 0;return{...e,request_duration_ms:e.request_duration_ms,session_llm_count:t?.llm??void 0,session_mcp_count:t?.mcp??void 0,session_agent_count:t?.agent??void 0,onKeyHashClick:e=>eh(e),onSessionClick:t=>{t&&(eL(t),eS(e),eC(!0))}}}).filter(e=>!e.session_id||1>=(e.session_total_count||1)||e1.get(e.session_id)?.requestId===e.request_id)||[],e5=[{name:"Team ID",label:"Team ID",isSearchable:!0,searchFn:async e=>A&&0!==A.length?A.filter(t=>t.team_id.toLowerCase().includes(e.toLowerCase())||t.team_alias&&t.team_alias.toLowerCase().includes(e.toLowerCase())).map(e=>({label:`${e.team_alias||e.team_id} (${e.team_id})`,value:e.team_id})):[]},{name:"Status",label:"Status",isSearchable:!1,options:[{label:"Success",value:"success"},{label:"Failure",value:"failure"}]},{name:"Model",label:"Model",customComponent:b.PaginatedModelSelect},{name:"Key Alias",label:"Key Alias",customComponent:j.PaginatedKeyAliasSelect},{name:"End User",label:"End User",isSearchable:!0,searchFn:async t=>{if(!e)return[];let s=await (0,_.allEndUsersCall)(e);return(s?.map(e=>e.user_id)||[]).filter(e=>e.toLowerCase().includes(t.toLowerCase())).map(e=>({label:e,value:e}))}},{name:"Error Code",label:"Error Code",isSearchable:!0,searchFn:async e=>{if(!e)return k.ERROR_CODE_OPTIONS;let t=e.toLowerCase(),s=k.ERROR_CODE_OPTIONS.filter(e=>e.label.toLowerCase().includes(t));return!k.ERROR_CODE_OPTIONS.some(t=>t.value===e.trim())&&e.trim()&&s.push({label:`Use custom code: ${e.trim()}`,value:e.trim()}),s}},{name:"Key Hash",label:"Key Hash",isSearchable:!1},{name:"Error Message",label:"Error Message",isSearchable:!1}],e4=k.QUICK_SELECT_OPTIONS.find(e=>e.value===eF.value&&e.unit===eF.unit),e6=X?((e,t,s)=>{if(e)return`${(0,r.default)(t).format("MMM D, h:mm A")} - ${(0,r.default)(s).format("MMM D, h:mm A")}`;let a=(0,r.default)(),l=(0,r.default)(t),i=a.diff(l,"minutes");if(i>=0&&i<2)return"Last 1 Minute";if(i>=2&&i<16)return"Last 15 Minutes";if(i>=16&&i<61)return"Last Hour";let n=a.diff(l,"hours");return n>=1&&n<5?"Last 4 Hours":n>=5&&n<25?"Last 24 Hours":n>=25&&n<169?"Last 7 Days":`${l.format("MMM D")} - ${a.format("MMM D")}`})(X,U,J):e4?.label;return(0,t.jsxs)("div",{className:"w-full max-w-screen p-6 overflow-x-hidden box-border",children:[(0,t.jsxs)(m.TabGroup,{defaultIndex:0,onIndexChange:e=>eN(0===e?"request logs":"audit logs"),children:[(0,t.jsxs)(x.TabList,{children:[(0,t.jsx)(c.Tab,{children:"Request Logs"}),(0,t.jsx)(c.Tab,{children:"Audit Logs"}),(0,t.jsx)(c.Tab,{children:"Deleted Keys"}),(0,t.jsx)(c.Tab,{children:"Deleted Teams"})]}),(0,t.jsxs)(p.TabPanels,{children:[(0,t.jsxs)(u.TabPanel,{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-4",children:[(0,t.jsx)("h1",{className:"text-xl font-semibold",children:"Request Logs"}),(0,t.jsx)(h.Button,{icon:(0,t.jsx)(n.SettingOutlined,{}),onClick:()=>eE(!0),title:"Spend Logs Settings"})]}),ex&&ep&&ex.api_key===ep?(0,t.jsx)(N.default,{keyId:ep,keyData:ex,teams:A,onClose:()=>eh(null),backButtonText:"Back to Logs"}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(v.default,{options:e5,onApplyFilters:eJ,onResetFilters:eX}),(0,t.jsx)($,{isVisible:eM,onCancel:()=>eE(!1),onSuccess:()=>eE(!1)}),(0,t.jsxs)("div",{className:"bg-white rounded-lg shadow w-full max-w-full box-border",children:[(0,t.jsx)("div",{className:"border-b px-6 py-4 w-full max-w-full box-border",children:(0,t.jsxs)("div",{className:"flex flex-col md:flex-row items-start md:items-center justify-between space-y-4 md:space-y-0 w-full max-w-full box-border",children:[(0,t.jsxs)("div",{className:"flex flex-wrap items-center gap-3 w-full max-w-full box-border",children:[(0,t.jsxs)("div",{className:"relative w-64 min-w-0 flex-shrink-0",children:[(0,t.jsx)("input",{type:"text",placeholder:"Search by Request ID",className:"w-full px-3 py-2 pl-8 border rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500",value:I,onChange:e=>O(e.target.value)}),(0,t.jsx)("svg",{className:"absolute left-2.5 top-2.5 h-4 w-4 text-gray-500",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"})})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2 min-w-0 flex-shrink",children:[(0,t.jsxs)("div",{className:"relative z-50",ref:W,children:[(0,t.jsxs)("button",{onClick:()=>et(!ee),className:"px-3 py-2 text-sm border rounded-md hover:bg-gray-50 flex items-center gap-2",children:[(0,t.jsx)("svg",{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"})}),e6]}),ee&&(0,t.jsx)("div",{className:"absolute right-0 mt-2 w-64 bg-white rounded-lg shadow-lg border p-2 z-50",children:(0,t.jsxs)("div",{className:"space-y-1",children:[k.QUICK_SELECT_OPTIONS.map(e=>(0,t.jsx)("button",{className:`w-full px-3 py-2 text-left text-sm hover:bg-gray-50 rounded-md ${e6===e.label?"bg-blue-50 text-blue-600":""}`,onClick:()=>{q(1),Q((0,r.default)().format("YYYY-MM-DDTHH:mm")),G((0,r.default)().subtract(e.value,e.unit).format("YYYY-MM-DDTHH:mm")),eq({value:e.value,unit:e.unit}),Z(!1),et(!1)},children:e.label},e.label)),(0,t.jsx)("div",{className:"border-t my-2"}),(0,t.jsx)("button",{className:`w-full px-3 py-2 text-left text-sm hover:bg-gray-50 rounded-md ${X?"bg-blue-50 text-blue-600":""}`,onClick:()=>Z(!X),children:"Custom Range"})]})})]}),(0,t.jsx)(()=>(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-900",children:"Live Tail"}),(0,t.jsx)(d.Switch,{color:"green",checked:eP,defaultChecked:!0,onChange:eB})]}),{}),(0,t.jsx)(h.Button,{type:"default",icon:(0,t.jsx)(o.SyncOutlined,{spin:eY}),onClick:()=>{eH.refetch()},disabled:eY,title:"Fetch data",children:eY?"Fetching":"Fetch"})]}),X&&(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("div",{children:(0,t.jsx)("input",{type:"datetime-local",value:U,onChange:e=>{G(e.target.value),q(1)},className:"px-3 py-2 border rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"})}),(0,t.jsx)("span",{className:"text-gray-500",children:"to"}),(0,t.jsx)("div",{children:(0,t.jsx)("input",{type:"datetime-local",value:J,onChange:e=>{Q(e.target.value),q(1)},className:"px-3 py-2 border rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"})})]})]}),(0,t.jsxs)("div",{className:"flex items-center space-x-4",children:[(0,t.jsxs)("span",{className:"text-sm text-gray-700 whitespace-nowrap",children:["Showing ",eH.isLoading?"...":eW?(F-1)*H+1:0," -"," ",eH.isLoading?"...":eW?Math.min(F*H,eW.total):0," ","of ",eH.isLoading?"...":eW?eW.total:0," results"]}),(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,t.jsxs)("span",{className:"text-sm text-gray-700 min-w-[90px]",children:["Page ",eH.isLoading?"...":F," of"," ",eH.isLoading?"...":eW?eW.total_pages:1]}),(0,t.jsx)("button",{onClick:()=>q(e=>Math.max(1,e-1)),disabled:eH.isLoading||1===F,className:"px-3 py-1 text-sm border rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed",children:"Previous"}),(0,t.jsx)("button",{onClick:()=>q(e=>Math.min(eW.total_pages||1,e+1)),disabled:eH.isLoading||F===(eW.total_pages||1),className:"px-3 py-1 text-sm border rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed",children:"Next"})]})]})]})}),eP&&1===F&&ez&&(0,t.jsxs)("div",{className:"mb-4 px-4 py-2 bg-green-50 border border-greem-200 rounded-md flex items-center justify-between",children:[(0,t.jsx)("div",{className:"flex items-center gap-2",children:(0,t.jsx)("span",{className:"text-sm text-green-700",children:"Auto-refreshing every 15 seconds"})}),(0,t.jsx)("button",{onClick:()=>eB(!1),className:"text-sm text-green-600 hover:text-green-800",children:"Stop"})]}),(0,t.jsx)(Y.DataTable,{columns:(0,S.createColumns)({sortBy:eA,sortOrder:eI,onSortChange:(e,t)=>{eD(e),eO(t),q(1)}}),data:e2,onRowClick:e=>{if(e.session_id&&(e.session_total_count||1)>1){eL(e.session_id),eS(e),eC(!0);return}eL(null),eS(e),eC(!0)},isLoading:eH.isLoading})]})]})]}),(0,t.jsx)(u.TabPanel,{children:(0,t.jsx)(w.default,{userID:E,userRole:M,token:L,accessToken:e,isActive:"audit logs"===e_,premiumUser:D})}),(0,t.jsx)(u.TabPanel,{children:(0,t.jsx)(f.default,{})}),(0,t.jsx)(u.TabPanel,{children:(0,t.jsx)(y.default,{})})]})]}),(0,t.jsx)(T.LogDetailsDrawer,{open:ek,onClose:()=>{eC(!1),eL(null)},logEntry:ew,sessionId:eT,accessToken:e,onOpenSettings:()=>eE(!0),allLogs:e2,onSelectLog:e=>{eS(e)},startTime:(0,r.default)(U).utc().format("YYYY-MM-DD HH:mm:ss")})]})}e.i(331052),e.s(["default",()=>K],936190)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/f728bd69dddaff23.js b/litellm/proxy/_experimental/out/_next/static/chunks/68066e020262ced9.js similarity index 92% rename from litellm/proxy/_experimental/out/_next/static/chunks/f728bd69dddaff23.js rename to litellm/proxy/_experimental/out/_next/static/chunks/68066e020262ced9.js index 59166e5e81..34cc7798a1 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/f728bd69dddaff23.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/68066e020262ced9.js @@ -4,4 +4,4 @@ `]:{[`&:hover ${t}-inner`]:{borderColor:e.colorPrimary}},[`${l}:not(${l}-disabled)`]:{[`&:hover ${t}-checked:not(${t}-disabled) ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"},[`&:hover ${t}-checked:not(${t}-disabled):after`]:{borderColor:e.colorPrimaryHover}}},{[`${t}-checked`]:{[`${t}-inner`]:{backgroundColor:e.colorPrimary,borderColor:e.colorPrimary,"&:after":{opacity:1,transform:"rotate(45deg) scale(1) translate(-50%,-50%)",transition:`all ${e.motionDurationMid} ${e.motionEaseOutBack} ${e.motionDurationFast}`}}},[` ${l}-checked:not(${l}-disabled), ${t}-checked:not(${t}-disabled) - `]:{[`&:hover ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"}}},{[t]:{"&-indeterminate":{"&":{[`${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${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 ${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${e.colorPrimary}`}}}}},{[`${l}-disabled`]:{cursor:"not-allowed"},[`${t}-disabled`]:{[`&, ${t}-input`]:{cursor:"not-allowed",pointerEvents:"none"},[`${t}-inner`]:{background:e.colorBgContainerDisabled,borderColor:e.colorBorder,"&:after":{borderColor:e.colorTextDisabled}},"&:after":{display:"none"},"& + span":{color:e.colorTextDisabled},[`&${t}-indeterminate ${t}-inner::after`]:{background:e.colorTextDisabled}}}]})((0,o.mergeToken)(t,{checkboxCls:`.${e}`,checkboxSize:t.controlInteractiveSize}))}let s=(0,l.genStyleHooks)("Checkbox",(e,{prefixCls:t})=>[n(t,e)]);e.s(["default",0,s,"getStyle",()=>n],236836)},681216,e=>{"use strict";var t=e.i(271645),r=e.i(963188);function a(e){let a=t.default.useRef(null),l=()=>{r.default.cancel(a.current),a.current=null};return[()=>{l(),a.current=(0,r.default)(()=>{a.current=null})},t=>{a.current&&(t.stopPropagation(),l()),null==e||e(t)}]}e.s(["default",()=>a])},374276,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(91874),l=e.i(611935),o=e.i(121872),n=e.i(26905),s=e.i(242064),i=e.i(937328),c=e.i(321883),d=e.i(62139),u=e.i(421512),m=e.i(236836),g=e.i(681216),p=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let f=t.forwardRef((e,f)=>{var h;let{prefixCls:x,className:b,rootClassName:y,children:v,indeterminate:w=!1,style:k,onMouseEnter:C,onMouseLeave:j,skipGroup:N=!1,disabled:S}=e,$=p(e,["prefixCls","className","rootClassName","children","indeterminate","style","onMouseEnter","onMouseLeave","skipGroup","disabled"]),{getPrefixCls:M,direction:E,checkbox:O}=t.useContext(s.ConfigContext),T=t.useContext(u.default),{isFormItemInput:P}=t.useContext(d.FormItemInputContext),_=t.useContext(i.default),z=null!=(h=(null==T?void 0:T.disabled)||S)?h:_,R=t.useRef($.value),I=t.useRef(null),L=(0,l.composeRef)(f,I);t.useEffect(()=>{null==T||T.registerValue($.value)},[]),t.useEffect(()=>{if(!N)return $.value!==R.current&&(null==T||T.cancelValue(R.current),null==T||T.registerValue($.value),R.current=$.value),()=>null==T?void 0:T.cancelValue($.value)},[$.value]),t.useEffect(()=>{var e;(null==(e=I.current)?void 0:e.input)&&(I.current.input.indeterminate=w)},[w]);let D=M("checkbox",x),B=(0,c.default)(D),[F,A,q]=(0,m.default)(D,B),H=Object.assign({},$);T&&!N&&(H.onChange=(...e)=>{$.onChange&&$.onChange.apply($,e),T.toggleOption&&T.toggleOption({label:v,value:$.value})},H.name=T.name,H.checked=T.value.includes($.value));let G=(0,r.default)(`${D}-wrapper`,{[`${D}-rtl`]:"rtl"===E,[`${D}-wrapper-checked`]:H.checked,[`${D}-wrapper-disabled`]:z,[`${D}-wrapper-in-form-item`]:P},null==O?void 0:O.className,b,y,q,B,A),X=(0,r.default)({[`${D}-indeterminate`]:w},n.TARGET_CLS,A),[V,K]=(0,g.default)(H.onClick);return F(t.createElement(o.default,{component:"Checkbox",disabled:z},t.createElement("label",{className:G,style:Object.assign(Object.assign({},null==O?void 0:O.style),k),onMouseEnter:C,onMouseLeave:j,onClick:V},t.createElement(a.default,Object.assign({},H,{onClick:K,prefixCls:D,className:X,disabled:z,ref:L})),null!=v&&t.createElement("span",{className:`${D}-label`},v))))});var h=e.i(8211),x=e.i(529681),b=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let y=t.forwardRef((e,a)=>{let{defaultValue:l,children:o,options:n=[],prefixCls:i,className:d,rootClassName:g,style:p,onChange:y}=e,v=b(e,["defaultValue","children","options","prefixCls","className","rootClassName","style","onChange"]),{getPrefixCls:w,direction:k}=t.useContext(s.ConfigContext),[C,j]=t.useState(v.value||l||[]),[N,S]=t.useState([]);t.useEffect(()=>{"value"in v&&j(v.value||[])},[v.value]);let $=t.useMemo(()=>n.map(e=>"string"==typeof e||"number"==typeof e?{label:e,value:e}:e),[n]),M=e=>{S(t=>t.filter(t=>t!==e))},E=e=>{S(t=>[].concat((0,h.default)(t),[e]))},O=e=>{let t=C.indexOf(e.value),r=(0,h.default)(C);-1===t?r.push(e.value):r.splice(t,1),"value"in v||j(r),null==y||y(r.filter(e=>N.includes(e)).sort((e,t)=>$.findIndex(t=>t.value===e)-$.findIndex(e=>e.value===t)))},T=w("checkbox",i),P=`${T}-group`,_=(0,c.default)(T),[z,R,I]=(0,m.default)(T,_),L=(0,x.default)(v,["value","disabled"]),D=n.length?$.map(e=>t.createElement(f,{prefixCls:T,key:e.value.toString(),disabled:"disabled"in e?e.disabled:v.disabled,value:e.value,checked:C.includes(e.value),onChange:e.onChange,className:(0,r.default)(`${P}-item`,e.className),style:e.style,title:e.title,id:e.id,required:e.required},e.label)):o,B=t.useMemo(()=>({toggleOption:O,value:C,disabled:v.disabled,name:v.name,registerValue:E,cancelValue:M}),[O,C,v.disabled,v.name,E,M]),F=(0,r.default)(P,{[`${P}-rtl`]:"rtl"===k},d,g,I,_,R);return z(t.createElement("div",Object.assign({className:F,style:p},L,{ref:a}),t.createElement(u.default.Provider,{value:B},D)))});f.Group=y,f.__ANT_CHECKBOX=!0,e.s(["default",0,f],374276)},536916,e=>{"use strict";var t=e.i(374276);e.s(["Checkbox",()=>t.default])},292639,e=>{"use strict";var t=e.i(764205),r=e.i(266027);let a=(0,e.i(243652).createQueryKeys)("uiSettings");e.s(["useUISettings",0,()=>(0,r.useQuery)({queryKey:a.list({}),queryFn:async()=>await (0,t.getUiSettings)(),staleTime:36e5,gcTime:36e5})])},250980,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlusCircleIcon",0,r],250980)},502547,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 5l7 7-7 7"}))});e.s(["ChevronRightIcon",0,r],502547)},988297,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"}))});e.s(["PlusIcon",0,r],988297)},797672,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"}))});e.s(["PencilIcon",0,r],797672)},992619,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(779241),l=e.i(599724),o=e.i(199133),n=e.i(983561),s=e.i(689020);e.s(["default",0,({accessToken:e,value:i,placeholder:c="Select a Model",onChange:d,disabled:u=!1,style:m,className:g,showLabel:p=!0,labelText:f="Select Model"})=>{let[h,x]=(0,r.useState)(i),[b,y]=(0,r.useState)(!1),[v,w]=(0,r.useState)([]),k=(0,r.useRef)(null);return(0,r.useEffect)(()=>{x(i)},[i]),(0,r.useEffect)(()=>{e&&(async()=>{try{let t=await (0,s.fetchAvailableModels)(e);console.log("Fetched models for selector:",t),t.length>0&&w(t)}catch(e){console.error("Error fetching model info:",e)}})()},[e]),(0,t.jsxs)("div",{children:[p&&(0,t.jsxs)(l.Text,{className:"font-medium block mb-2 text-gray-700 flex items-center",children:[(0,t.jsx)(n.RobotOutlined,{className:"mr-2"})," ",f]}),(0,t.jsx)(o.Select,{value:h,placeholder:c,onChange:e=>{"custom"===e?(y(!0),x(void 0)):(y(!1),x(e),d&&d(e))},options:[...Array.from(new Set(v.map(e=>e.model_group))).map((e,t)=>({value:e,label:e,key:t})),{value:"custom",label:"Enter custom model",key:"custom"}],style:{width:"100%",...m},showSearch:!0,className:`rounded-md ${g||""}`,disabled:u}),b&&(0,t.jsx)(a.TextInput,{className:"mt-2",placeholder:"Enter custom model name",onValueChange:e=>{k.current&&clearTimeout(k.current),k.current=setTimeout(()=>{x(e),d&&d(e)},500)},disabled:u})]})}])},91739,e=>{"use strict";var t=e.i(544195);e.s(["Radio",()=>t.default])},409797,e=>{"use strict";var t=e.i(631171);e.s(["ChevronDownIcon",()=>t.default])},500727,696609,531516,e=>{"use strict";var t=e.i(266027),r=e.i(243652),a=e.i(764205),l=e.i(135214);let o=(0,r.createQueryKeys)("mcpServers");e.s(["useMCPServers",0,e=>{let{accessToken:r}=(0,l.default)();return(0,t.useQuery)({queryKey:o.list(e?{filters:{teamId:e}}:void 0),queryFn:async()=>await (0,a.fetchMCPServers)(r,e),enabled:!!r})}],500727);var n=e.i(843476),s=e.i(271645),i=e.i(536916),c=e.i(599724),d=e.i(409797),u=e.i(246349),u=u;let m=/\b(delete|remove|destroy|purge|drop|erase|unlink)\b/i,g=/\b(create|add|insert|new|post|submit|register|make|generate|write|upload)\b/i,p=/\b(update|edit|modify|change|patch|put|set|rename|move|transform)\b/i,f=/\b(get|read|list|fetch|search|find|query|retrieve|show|view|check|describe|info)\b/i;function h(e,t=""){let r=e.toLowerCase();if(f.test(r))return"read";if(m.test(r))return"delete";if(p.test(r))return"update";if(g.test(r))return"create";if(t){let e=t.toLowerCase();if(f.test(e))return"read";if(m.test(e))return"delete";if(p.test(e))return"update";if(g.test(e))return"create"}return"unknown"}function x(e){let t={read:[],create:[],update:[],delete:[],unknown:[]};for(let r of e)t[h(r.name,r.description)].push(r);return t}let b={read:{label:"Read",description:"Safe operations — fetch, list, search. No side effects.",risk:"low"},create:{label:"Create",description:"Add new resources — insert, upload, register.",risk:"medium"},update:{label:"Update",description:"Modify existing resources — edit, patch, rename.",risk:"medium"},delete:{label:"Delete",description:"Destructive operations — remove, purge, destroy.",risk:"high"},unknown:{label:"Other",description:"Operations that could not be automatically classified.",risk:"unknown"}};e.s(["CRUD_GROUP_META",0,b,"classifyToolOp",()=>h,"groupToolsByCrud",()=>x],696609);let y=["read","create","update","delete","unknown"],v={low:"bg-green-100 text-green-800",medium:"bg-yellow-100 text-yellow-800",high:"bg-red-100 text-red-800 font-semibold",unknown:"bg-gray-100 text-gray-700"},w={read:"border-green-200",create:"border-blue-200",update:"border-yellow-200",delete:"border-red-300",unknown:"border-gray-200"},k={read:"bg-green-50",create:"bg-blue-50",update:"bg-yellow-50",delete:"bg-red-50",unknown:"bg-gray-50"};e.s(["default",0,({tools:e,value:t,onChange:r,readOnly:a=!1,searchFilter:l=""})=>{let[o,m]=(0,s.useState)({read:!1,create:!1,update:!1,delete:!1,unknown:!0}),g=(0,s.useMemo)(()=>x(e),[e]),p=(0,s.useMemo)(()=>new Set(void 0===t?e.map(e=>e.name):t),[t,e]),f=e=>{if(a)return;let t=new Set(p);t.has(e)?t.delete(e):t.add(e),r(Array.from(t))};return 0===e.length?null:(0,n.jsx)("div",{className:"space-y-3",children:y.map(e=>{let t,s=g[e];if(0===s.length)return null;if(l){let e=l.toLowerCase();if(!s.some(t=>t.name.toLowerCase().includes(e)||(t.description??"").toLowerCase().includes(e)))return null}let h=b[e],x=(t=g[e]).length>0&&t.every(e=>p.has(e.name)),y=(e=>{let t=g[e];if(0===t.length)return!1;let r=t.filter(e=>p.has(e.name)).length;return r>0&&r{m(t=>({...t,[e]:!t[e]}))},children:[C?(0,n.jsx)(u.default,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}):(0,n.jsx)(d.ChevronDownIcon,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}),(0,n.jsx)("span",{className:"font-semibold text-gray-900 text-sm",children:h.label}),(0,n.jsx)("span",{className:`text-xs px-2 py-0.5 rounded-full ${v[h.risk]}`,children:"high"===h.risk?"High Risk":"medium"===h.risk?"Medium Risk":"low"===h.risk?"Safe":"Unclassified"}),(0,n.jsxs)("span",{className:"text-xs text-gray-500 ml-1",children:[s.filter(e=>p.has(e.name)).length,"/",s.length," allowed"]})]}),!a&&(0,n.jsxs)("div",{className:"flex items-center gap-2 ml-4",children:[(0,n.jsx)(c.Text,{className:"text-xs text-gray-500",children:x?"All on":y?"Partial":"All off"}),(0,n.jsx)(i.Checkbox,{checked:x,indeterminate:y,onChange:t=>((e,t)=>{if(a)return;let l=new Set(p);for(let r of g[e])t?l.add(r.name):l.delete(r.name);r(Array.from(l))})(e,t.target.checked),onClick:e=>e.stopPropagation()})]})]}),!C&&(0,n.jsx)("div",{className:"px-4 pt-2 pb-1 text-xs text-gray-500 bg-white border-b border-gray-100",children:h.description}),!C&&(0,n.jsx)("div",{className:"bg-white divide-y divide-gray-50",children:s.filter(e=>!l||e.name.toLowerCase().includes(l.toLowerCase())||(e.description??"").toLowerCase().includes(l.toLowerCase())).map(e=>{let t,r=(t=e.name,p.has(t));return(0,n.jsxs)("div",{className:`flex items-start gap-3 px-4 py-2.5 transition-colors hover:bg-gray-50 ${!a?"cursor-pointer":""} ${r?"":"opacity-60"}`,onClick:()=>f(e.name),children:[(0,n.jsx)(i.Checkbox,{checked:r,onChange:()=>f(e.name),disabled:a,onClick:e=>e.stopPropagation()}),(0,n.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,n.jsx)(c.Text,{className:"font-medium text-gray-900 text-sm",children:e.name}),e.description&&(0,n.jsx)(c.Text,{className:"text-xs text-gray-500 mt-0.5 leading-snug",children:e.description})]}),(0,n.jsx)("span",{className:`text-xs px-1.5 py-0.5 rounded flex-shrink-0 ${r?"bg-green-100 text-green-700":"bg-gray-100 text-gray-500"}`,children:r?"on":"off"})]},e.name)})})]},e)})})}],531516)},361653,e=>{"use strict";let t=(0,e.i(475254).default)("circle-alert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);e.s(["default",()=>t])},841947,e=>{"use strict";let t=(0,e.i(475254).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["default",()=>t])},603908,e=>{"use strict";let t=(0,e.i(475254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);e.s(["default",()=>t])},793130,e=>{"use strict";var t=e.i(290571),r=e.i(429427),a=e.i(371330),l=e.i(271645),o=e.i(394487),n=e.i(503269),s=e.i(214520),i=e.i(746725),c=e.i(914189),d=e.i(144279),u=e.i(294316),m=e.i(601893),g=e.i(140721),p=e.i(942803),f=e.i(233538),h=e.i(694421),x=e.i(700020),b=e.i(35889),y=e.i(998348),v=e.i(722678);let w=(0,l.createContext)(null);w.displayName="GroupContext";let k=l.Fragment,C=Object.assign((0,x.forwardRefWithAs)(function(e,t){var k;let C=(0,l.useId)(),j=(0,p.useProvidedId)(),N=(0,m.useDisabled)(),{id:S=j||`headlessui-switch-${C}`,disabled:$=N||!1,checked:M,defaultChecked:E,onChange:O,name:T,value:P,form:_,autoFocus:z=!1,...R}=e,I=(0,l.useContext)(w),[L,D]=(0,l.useState)(null),B=(0,l.useRef)(null),F=(0,u.useSyncRefs)(B,t,null===I?null:I.setSwitch,D),A=(0,s.useDefaultValue)(E),[q,H]=(0,n.useControllable)(M,O,null!=A&&A),G=(0,i.useDisposables)(),[X,V]=(0,l.useState)(!1),K=(0,c.useEvent)(()=>{V(!0),null==H||H(!q),G.nextFrame(()=>{V(!1)})}),W=(0,c.useEvent)(e=>{if((0,f.isDisabledReactIssue7711)(e.currentTarget))return e.preventDefault();e.preventDefault(),K()}),U=(0,c.useEvent)(e=>{e.key===y.Keys.Space?(e.preventDefault(),K()):e.key===y.Keys.Enter&&(0,h.attemptSubmit)(e.currentTarget)}),Y=(0,c.useEvent)(e=>e.preventDefault()),Q=(0,v.useLabelledBy)(),J=(0,b.useDescribedBy)(),{isFocusVisible:Z,focusProps:ee}=(0,r.useFocusRing)({autoFocus:z}),{isHovered:et,hoverProps:er}=(0,a.useHover)({isDisabled:$}),{pressed:ea,pressProps:el}=(0,o.useActivePress)({disabled:$}),eo=(0,l.useMemo)(()=>({checked:q,disabled:$,hover:et,focus:Z,active:ea,autofocus:z,changing:X}),[q,et,Z,ea,$,X,z]),en=(0,x.mergeProps)({id:S,ref:F,role:"switch",type:(0,d.useResolveButtonType)(e,L),tabIndex:-1===e.tabIndex?0:null!=(k=e.tabIndex)?k:0,"aria-checked":q,"aria-labelledby":Q,"aria-describedby":J,disabled:$||void 0,autoFocus:z,onClick:W,onKeyUp:U,onKeyPress:Y},ee,er,el),es=(0,l.useCallback)(()=>{if(void 0!==A)return null==H?void 0:H(A)},[H,A]),ei=(0,x.useRender)();return l.default.createElement(l.default.Fragment,null,null!=T&&l.default.createElement(g.FormFields,{disabled:$,data:{[T]:P||"on"},overrides:{type:"checkbox",checked:q},form:_,onReset:es}),ei({ourProps:en,theirProps:R,slot:eo,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var t;let[r,a]=(0,l.useState)(null),[o,n]=(0,v.useLabels)(),[s,i]=(0,b.useDescriptions)(),c=(0,l.useMemo)(()=>({switch:r,setSwitch:a}),[r,a]),d=(0,x.useRender)();return l.default.createElement(i,{name:"Switch.Description",value:s},l.default.createElement(n,{name:"Switch.Label",value:o,props:{htmlFor:null==(t=c.switch)?void 0:t.id,onClick(e){r&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),r.click(),r.focus({preventScroll:!0}))}}},l.default.createElement(w.Provider,{value:c},d({ourProps:{},theirProps:e,slot:{},defaultTag:k,name:"Switch.Group"}))))},Label:v.Label,Description:b.Description});var j=e.i(888288),N=e.i(95779),S=e.i(444755),$=e.i(673706),M=e.i(829087);let E=(0,$.makeClassName)("Switch"),O=l.default.forwardRef((e,r)=>{let{checked:a,defaultChecked:o=!1,onChange:n,color:s,name:i,error:c,errorMessage:d,disabled:u,required:m,tooltip:g,id:p}=e,f=(0,t.__rest)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),h={bgColor:s?(0,$.getColorClassNames)(s,N.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:s?(0,$.getColorClassNames)(s,N.colorPalette.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[x,b]=(0,j.default)(o,a),[y,v]=(0,l.useState)(!1),{tooltipProps:w,getReferenceProps:k}=(0,M.useTooltip)(300);return l.default.createElement("div",{className:"flex flex-row items-center justify-start"},l.default.createElement(M.default,Object.assign({text:g},w)),l.default.createElement("div",Object.assign({ref:(0,$.mergeRefs)([r,w.refs.setReference]),className:(0,S.tremorTwMerge)(E("root"),"flex flex-row relative h-5")},f,k),l.default.createElement("input",{type:"checkbox",className:(0,S.tremorTwMerge)(E("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:i,required:m,checked:x,onChange:e=>{e.preventDefault()}}),l.default.createElement(C,{checked:x,onChange:e=>{b(e),null==n||n(e)},disabled:u,className:(0,S.tremorTwMerge)(E("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:()=>v(!0),onBlur:()=>v(!1),id:p},l.default.createElement("span",{className:(0,S.tremorTwMerge)(E("sr-only"),"sr-only")},"Switch ",x?"on":"off"),l.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("background"),x?h.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.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("round"),x?(0,S.tremorTwMerge)(h.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",y?(0,S.tremorTwMerge)("ring-2",h.ringColor):"")}))),c&&d?l.default.createElement("p",{className:(0,S.tremorTwMerge)(E("errorMessage"),"text-sm text-red-500 mt-1 ")},d):null)});O.displayName="Switch",e.s(["Switch",()=>O],793130)},158392,419470,e=>{"use strict";var t=e.i(843476),r=e.i(779241);let a={ttl:3600,lowest_latency_buffer:0},l=({routingStrategyArgs:e})=>{let l={ttl:"Sliding window to look back over when calculating the average latency of a deployment. Default - 1 hour (in seconds).",lowest_latency_buffer:"Shuffle between deployments within this % of the lowest latency. Default - 0 (i.e. always pick lowest latency)."};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Latency-Based Configuration"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Fine-tune latency-based routing behavior"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e||a).map(([e,a])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:e.replace(/_/g," ")}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l[e]||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:"object"==typeof a?JSON.stringify(a,null,2):a?.toString(),className:"font-mono text-sm w-full"})]})},e))})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"})]})},o=({routerSettings:e,routerFieldsMetadata:a})=>(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Reliability & Retries"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure retry logic and failure handling"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e).filter(([e,t])=>"fallbacks"!=e&&"context_window_fallbacks"!=e&&"routing_strategy_args"!=e&&"routing_strategy"!=e&&"enable_tag_filtering"!=e).map(([e,l])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:a[e]?.ui_field_name||e}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:a[e]?.field_description||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:null==l||"null"===l?"":"object"==typeof l?JSON.stringify(l,null,2):l?.toString()||"",placeholder:"—",className:"font-mono text-sm w-full"})]})},e))})]});var n=e.i(199133);let s=({selectedStrategy:e,availableStrategies:r,routingStrategyDescriptions:a,routerFieldsMetadata:l,onStrategyChange:o})=>(0,t.jsxs)("div",{className:"space-y-2 max-w-3xl",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:l.routing_strategy?.ui_field_name||"Routing Strategy"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l.routing_strategy?.field_description||""})]}),(0,t.jsx)("div",{className:"routing-strategy-select max-w-3xl",children:(0,t.jsx)(n.Select,{value:e,onChange:o,style:{width:"100%"},size:"large",children:r.map(e=>(0,t.jsx)(n.Select.Option,{value:e,label:e,children:(0,t.jsxs)("div",{className:"flex flex-col gap-0.5 py-1",children:[(0,t.jsx)("span",{className:"font-mono text-sm font-medium",children:e}),a[e]&&(0,t.jsx)("span",{className:"text-xs text-gray-500 font-normal",children:a[e]})]})},e))})})]});var i=e.i(793130);let c=({enabled:e,routerFieldsMetadata:r,onToggle:a})=>(0,t.jsx)("div",{className:"space-y-3 max-w-3xl",children:(0,t.jsxs)("div",{className:"flex items-start justify-between",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:r.enable_tag_filtering?.ui_field_name||"Enable Tag Filtering"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500 mt-0.5",children:[r.enable_tag_filtering?.field_description||"",r.enable_tag_filtering?.link&&(0,t.jsxs)(t.Fragment,{children:[" ",(0,t.jsx)("a",{href:r.enable_tag_filtering.link,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline",children:"Learn more"})]})]})]}),(0,t.jsx)(i.Switch,{checked:e,onChange:a,className:"ml-4"})]})});e.s(["default",0,({value:e,onChange:r,routerFieldsMetadata:a,availableRoutingStrategies:n,routingStrategyDescriptions:i})=>(0,t.jsxs)("div",{className:"w-full space-y-8 py-2",children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Routing Settings"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure how requests are routed to deployments"})]}),n.length>0&&(0,t.jsx)(s,{selectedStrategy:e.selectedStrategy||e.routerSettings.routing_strategy||null,availableStrategies:n,routingStrategyDescriptions:i,routerFieldsMetadata:a,onStrategyChange:t=>{r({...e,selectedStrategy:t})}}),(0,t.jsx)(c,{enabled:e.enableTagFiltering,routerFieldsMetadata:a,onToggle:t=>{r({...e,enableTagFiltering:t})}})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),"latency-based-routing"===e.selectedStrategy&&(0,t.jsx)(l,{routingStrategyArgs:e.routerSettings.routing_strategy_args}),(0,t.jsx)(o,{routerSettings:e.routerSettings,routerFieldsMetadata:a})]})],158392);var d=e.i(994388),u=e.i(998573),m=e.i(653496),g=e.i(107233),p=e.i(271645),f=e.i(592968),h=e.i(361653),h=h;let x=(0,e.i(475254).default)("arrow-down",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var b=e.i(37727);function y({group:e,onChange:r,availableModels:a,maxFallbacks:l}){let o=a.filter(t=>t!==e.primaryModel),s=e.fallbackModels.length{let a=[...e.fallbackModels];a.includes(t)&&(a=a.filter(e=>e!==t)),r({...e,primaryModel:t,fallbackModels:a})},showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase()),options:a.map(e=>({label:e,value:e}))}),!e.primaryModel&&(0,t.jsxs)("div",{className:"mt-2 flex items-center gap-2 text-amber-600 text-xs bg-amber-50 p-2 rounded",children:[(0,t.jsx)(h.default,{className:"w-4 h-4"}),(0,t.jsx)("span",{children:"Select a model to begin configuring fallbacks"})]})]}),(0,t.jsx)("div",{className:"flex items-center justify-center -my-4 z-10",children:(0,t.jsxs)("div",{className:"bg-indigo-50 text-indigo-500 px-4 py-1 rounded-full text-xs font-bold border border-indigo-100 flex items-center gap-2 shadow-sm",children:[(0,t.jsx)(x,{className:"w-4 h-4"}),"IF FAILS, TRY..."]})}),(0,t.jsxs)("div",{className:`transition-opacity duration-300 ${!e.primaryModel?"opacity-50 pointer-events-none":"opacity-100"}`,children:[(0,t.jsxs)("label",{className:"block text-sm font-semibold text-gray-700 mb-2",children:["Fallback Chain ",(0,t.jsx)("span",{className:"text-red-500",children:"*"}),(0,t.jsxs)("span",{className:"text-xs text-gray-500 font-normal ml-2",children:["(Max ",l," fallbacks at a time)"]})]}),(0,t.jsxs)("div",{className:"bg-gray-50 rounded-xl p-4 border border-gray-200",children:[(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(n.Select,{mode:"multiple",className:"w-full",size:"large",placeholder:s?"Select fallback models to add...":`Maximum ${l} fallbacks reached`,value:e.fallbackModels,onChange:t=>{let a=t.slice(0,l);r({...e,fallbackModels:a})},disabled:!e.primaryModel,options:o.map(e=>({label:e,value:e})),optionRender:(r,a)=>{let l=e.fallbackModels.includes(r.value),o=l?e.fallbackModels.indexOf(r.value)+1:null;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[l&&null!==o&&(0,t.jsx)("span",{className:"flex items-center justify-center w-5 h-5 rounded bg-indigo-100 text-indigo-600 text-xs font-bold",children:o}),(0,t.jsx)("span",{children:r.label})]})},maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(f.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})}),showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase())}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1 ml-1",children:s?`Search and select multiple models. Selected models will appear below in order. (${e.fallbackModels.length}/${l} used)`:`Maximum ${l} fallbacks reached. Remove some to add more.`})]}),(0,t.jsx)("div",{className:"space-y-2 min-h-[100px]",children:0===e.fallbackModels.length?(0,t.jsxs)("div",{className:"h-32 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)("span",{className:"text-sm",children:"No fallback models selected"}),(0,t.jsx)("span",{className:"text-xs mt-1",children:"Add models from the dropdown above"})]}):e.fallbackModels.map((a,l)=>(0,t.jsxs)("div",{className:"group flex items-center justify-between p-3 bg-white rounded-lg border border-gray-200 hover:border-indigo-300 hover:shadow-sm transition-all",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex items-center justify-center w-6 h-6 rounded bg-gray-100 text-gray-400 group-hover:text-indigo-500 group-hover:bg-indigo-50",children:(0,t.jsx)("span",{className:"text-xs font-bold",children:l+1})}),(0,t.jsx)("div",{children:(0,t.jsx)("span",{className:"font-medium text-gray-800",children:a})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>{let t;return t=e.fallbackModels.filter((e,t)=>t!==l),void r({...e,fallbackModels:t})},className:"opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500 p-1",children:(0,t.jsx)(b.X,{className:"w-4 h-4"})})]},`${a}-${l}`))})]})]})]})}function v({groups:e,onGroupsChange:r,availableModels:a,maxFallbacks:l=10,maxGroups:o=5}){let[n,s]=(0,p.useState)(e.length>0?e[0].id:"1");(0,p.useEffect)(()=>{e.length>0?e.some(e=>e.id===n)||s(e[0].id):s("1")},[e]);let i=()=>{if(e.length>=o)return;let t=Date.now().toString();r([...e,{id:t,primaryModel:null,fallbackModels:[]}]),s(t)},c=t=>{r(e.map(e=>e.id===t.id?t:e))},f=e.map((r,o)=>{let n=r.primaryModel?r.primaryModel:`Group ${o+1}`;return{key:r.id,label:n,closable:e.length>1,children:(0,t.jsx)(y,{group:r,onChange:c,availableModels:a,maxFallbacks:l})}});return 0===e.length?(0,t.jsxs)("div",{className:"text-center py-12 bg-gray-50 rounded-lg border border-dashed border-gray-300",children:[(0,t.jsx)("p",{className:"text-gray-500 mb-4",children:"No fallback groups configured"}),(0,t.jsx)(d.Button,{variant:"primary",onClick:i,icon:()=>(0,t.jsx)(g.Plus,{className:"w-4 h-4"}),children:"Create First Group"})]}):(0,t.jsx)(m.Tabs,{type:"editable-card",activeKey:n,onChange:s,onEdit:(t,a)=>{"add"===a?i():"remove"===a&&e.length>1&&(t=>{if(1===e.length)return u.message.warning("At least one group is required");let a=e.filter(e=>e.id!==t);r(a),n===t&&a.length>0&&s(a[a.length-1].id)})(t)},items:f,className:"fallback-tabs",tabBarStyle:{marginBottom:0},hideAdd:e.length>=o})}e.s(["FallbackSelectionForm",()=>v],419470)}]); \ No newline at end of file + `]:{[`&:hover ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"}}},{[t]:{"&-indeterminate":{"&":{[`${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${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 ${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${e.colorPrimary}`}}}}},{[`${l}-disabled`]:{cursor:"not-allowed"},[`${t}-disabled`]:{[`&, ${t}-input`]:{cursor:"not-allowed",pointerEvents:"none"},[`${t}-inner`]:{background:e.colorBgContainerDisabled,borderColor:e.colorBorder,"&:after":{borderColor:e.colorTextDisabled}},"&:after":{display:"none"},"& + span":{color:e.colorTextDisabled},[`&${t}-indeterminate ${t}-inner::after`]:{background:e.colorTextDisabled}}}]})((0,o.mergeToken)(t,{checkboxCls:`.${e}`,checkboxSize:t.controlInteractiveSize}))}let s=(0,l.genStyleHooks)("Checkbox",(e,{prefixCls:t})=>[n(t,e)]);e.s(["default",0,s,"getStyle",()=>n],236836)},681216,e=>{"use strict";var t=e.i(271645),r=e.i(963188);function a(e){let a=t.default.useRef(null),l=()=>{r.default.cancel(a.current),a.current=null};return[()=>{l(),a.current=(0,r.default)(()=>{a.current=null})},t=>{a.current&&(t.stopPropagation(),l()),null==e||e(t)}]}e.s(["default",()=>a])},374276,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(91874),l=e.i(611935),o=e.i(121872),n=e.i(26905),s=e.i(242064),i=e.i(937328),c=e.i(321883),d=e.i(62139),u=e.i(421512),m=e.i(236836),g=e.i(681216),p=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let f=t.forwardRef((e,f)=>{var h;let{prefixCls:x,className:b,rootClassName:y,children:v,indeterminate:w=!1,style:k,onMouseEnter:C,onMouseLeave:j,skipGroup:N=!1,disabled:S}=e,$=p(e,["prefixCls","className","rootClassName","children","indeterminate","style","onMouseEnter","onMouseLeave","skipGroup","disabled"]),{getPrefixCls:M,direction:E,checkbox:O}=t.useContext(s.ConfigContext),T=t.useContext(u.default),{isFormItemInput:P}=t.useContext(d.FormItemInputContext),_=t.useContext(i.default),z=null!=(h=(null==T?void 0:T.disabled)||S)?h:_,R=t.useRef($.value),I=t.useRef(null),L=(0,l.composeRef)(f,I);t.useEffect(()=>{null==T||T.registerValue($.value)},[]),t.useEffect(()=>{if(!N)return $.value!==R.current&&(null==T||T.cancelValue(R.current),null==T||T.registerValue($.value),R.current=$.value),()=>null==T?void 0:T.cancelValue($.value)},[$.value]),t.useEffect(()=>{var e;(null==(e=I.current)?void 0:e.input)&&(I.current.input.indeterminate=w)},[w]);let D=M("checkbox",x),B=(0,c.default)(D),[F,A,q]=(0,m.default)(D,B),H=Object.assign({},$);T&&!N&&(H.onChange=(...e)=>{$.onChange&&$.onChange.apply($,e),T.toggleOption&&T.toggleOption({label:v,value:$.value})},H.name=T.name,H.checked=T.value.includes($.value));let G=(0,r.default)(`${D}-wrapper`,{[`${D}-rtl`]:"rtl"===E,[`${D}-wrapper-checked`]:H.checked,[`${D}-wrapper-disabled`]:z,[`${D}-wrapper-in-form-item`]:P},null==O?void 0:O.className,b,y,q,B,A),X=(0,r.default)({[`${D}-indeterminate`]:w},n.TARGET_CLS,A),[V,K]=(0,g.default)(H.onClick);return F(t.createElement(o.default,{component:"Checkbox",disabled:z},t.createElement("label",{className:G,style:Object.assign(Object.assign({},null==O?void 0:O.style),k),onMouseEnter:C,onMouseLeave:j,onClick:V},t.createElement(a.default,Object.assign({},H,{onClick:K,prefixCls:D,className:X,disabled:z,ref:L})),null!=v&&t.createElement("span",{className:`${D}-label`},v))))});var h=e.i(8211),x=e.i(529681),b=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let y=t.forwardRef((e,a)=>{let{defaultValue:l,children:o,options:n=[],prefixCls:i,className:d,rootClassName:g,style:p,onChange:y}=e,v=b(e,["defaultValue","children","options","prefixCls","className","rootClassName","style","onChange"]),{getPrefixCls:w,direction:k}=t.useContext(s.ConfigContext),[C,j]=t.useState(v.value||l||[]),[N,S]=t.useState([]);t.useEffect(()=>{"value"in v&&j(v.value||[])},[v.value]);let $=t.useMemo(()=>n.map(e=>"string"==typeof e||"number"==typeof e?{label:e,value:e}:e),[n]),M=e=>{S(t=>t.filter(t=>t!==e))},E=e=>{S(t=>[].concat((0,h.default)(t),[e]))},O=e=>{let t=C.indexOf(e.value),r=(0,h.default)(C);-1===t?r.push(e.value):r.splice(t,1),"value"in v||j(r),null==y||y(r.filter(e=>N.includes(e)).sort((e,t)=>$.findIndex(t=>t.value===e)-$.findIndex(e=>e.value===t)))},T=w("checkbox",i),P=`${T}-group`,_=(0,c.default)(T),[z,R,I]=(0,m.default)(T,_),L=(0,x.default)(v,["value","disabled"]),D=n.length?$.map(e=>t.createElement(f,{prefixCls:T,key:e.value.toString(),disabled:"disabled"in e?e.disabled:v.disabled,value:e.value,checked:C.includes(e.value),onChange:e.onChange,className:(0,r.default)(`${P}-item`,e.className),style:e.style,title:e.title,id:e.id,required:e.required},e.label)):o,B=t.useMemo(()=>({toggleOption:O,value:C,disabled:v.disabled,name:v.name,registerValue:E,cancelValue:M}),[O,C,v.disabled,v.name,E,M]),F=(0,r.default)(P,{[`${P}-rtl`]:"rtl"===k},d,g,I,_,R);return z(t.createElement("div",Object.assign({className:F,style:p},L,{ref:a}),t.createElement(u.default.Provider,{value:B},D)))});f.Group=y,f.__ANT_CHECKBOX=!0,e.s(["default",0,f],374276)},536916,e=>{"use strict";var t=e.i(374276);e.s(["Checkbox",()=>t.default])},292639,e=>{"use strict";var t=e.i(764205),r=e.i(266027);let a=(0,e.i(243652).createQueryKeys)("uiSettings");e.s(["useUISettings",0,()=>(0,r.useQuery)({queryKey:a.list({}),queryFn:async()=>await (0,t.getUiSettings)(),staleTime:36e5,gcTime:36e5})])},250980,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlusCircleIcon",0,r],250980)},502547,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 5l7 7-7 7"}))});e.s(["ChevronRightIcon",0,r],502547)},988297,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"}))});e.s(["PlusIcon",0,r],988297)},797672,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"}))});e.s(["PencilIcon",0,r],797672)},992619,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(779241),l=e.i(599724),o=e.i(199133),n=e.i(983561),s=e.i(689020);e.s(["default",0,({accessToken:e,value:i,placeholder:c="Select a Model",onChange:d,disabled:u=!1,style:m,className:g,showLabel:p=!0,labelText:f="Select Model"})=>{let[h,x]=(0,r.useState)(i),[b,y]=(0,r.useState)(!1),[v,w]=(0,r.useState)([]),k=(0,r.useRef)(null);return(0,r.useEffect)(()=>{x(i)},[i]),(0,r.useEffect)(()=>{e&&(async()=>{try{let t=await (0,s.fetchAvailableModels)(e);console.log("Fetched models for selector:",t),t.length>0&&w(t)}catch(e){console.error("Error fetching model info:",e)}})()},[e]),(0,t.jsxs)("div",{children:[p&&(0,t.jsxs)(l.Text,{className:"font-medium block mb-2 text-gray-700 flex items-center",children:[(0,t.jsx)(n.RobotOutlined,{className:"mr-2"})," ",f]}),(0,t.jsx)(o.Select,{value:h,placeholder:c,onChange:e=>{"custom"===e?(y(!0),x(void 0)):(y(!1),x(e),d&&d(e))},options:[...Array.from(new Set(v.map(e=>e.model_group))).map((e,t)=>({value:e,label:e,key:t})),{value:"custom",label:"Enter custom model",key:"custom"}],style:{width:"100%",...m},showSearch:!0,className:`rounded-md ${g||""}`,disabled:u}),b&&(0,t.jsx)(a.TextInput,{className:"mt-2",placeholder:"Enter custom model name",onValueChange:e=>{k.current&&clearTimeout(k.current),k.current=setTimeout(()=>{x(e),d&&d(e)},500)},disabled:u})]})}])},91739,e=>{"use strict";var t=e.i(544195);e.s(["Radio",()=>t.default])},409797,e=>{"use strict";var t=e.i(631171);e.s(["ChevronDownIcon",()=>t.default])},500727,696609,531516,e=>{"use strict";var t=e.i(266027),r=e.i(243652),a=e.i(764205),l=e.i(135214);let o=(0,r.createQueryKeys)("mcpServers");e.s(["useMCPServers",0,e=>{let{accessToken:r}=(0,l.default)();return(0,t.useQuery)({queryKey:o.list(e?{filters:{teamId:e}}:void 0),queryFn:async()=>await (0,a.fetchMCPServers)(r,e),enabled:!!r})}],500727);var n=e.i(843476),s=e.i(271645),i=e.i(536916),c=e.i(599724),d=e.i(409797),u=e.i(246349),u=u;let m=/\b(delete|remove|destroy|purge|drop|erase|unlink)\b/i,g=/\b(create|add|insert|new|post|submit|register|make|generate|write|upload)\b/i,p=/\b(update|edit|modify|change|patch|put|set|rename|move|transform)\b/i,f=/\b(get|read|list|fetch|search|find|query|retrieve|show|view|check|describe|info)\b/i;function h(e,t=""){let r=e.toLowerCase();if(f.test(r))return"read";if(m.test(r))return"delete";if(p.test(r))return"update";if(g.test(r))return"create";if(t){let e=t.toLowerCase();if(f.test(e))return"read";if(m.test(e))return"delete";if(p.test(e))return"update";if(g.test(e))return"create"}return"unknown"}function x(e){let t={read:[],create:[],update:[],delete:[],unknown:[]};for(let r of e)t[h(r.name,r.description)].push(r);return t}let b={read:{label:"Read",description:"Safe operations — fetch, list, search. No side effects.",risk:"low"},create:{label:"Create",description:"Add new resources — insert, upload, register.",risk:"medium"},update:{label:"Update",description:"Modify existing resources — edit, patch, rename.",risk:"medium"},delete:{label:"Delete",description:"Destructive operations — remove, purge, destroy.",risk:"high"},unknown:{label:"Other",description:"Operations that could not be automatically classified.",risk:"unknown"}};e.s(["CRUD_GROUP_META",0,b,"classifyToolOp",()=>h,"groupToolsByCrud",()=>x],696609);let y=["read","create","update","delete","unknown"],v={low:"bg-green-100 text-green-800",medium:"bg-yellow-100 text-yellow-800",high:"bg-red-100 text-red-800 font-semibold",unknown:"bg-gray-100 text-gray-700"},w={read:"border-green-200",create:"border-blue-200",update:"border-yellow-200",delete:"border-red-300",unknown:"border-gray-200"},k={read:"bg-green-50",create:"bg-blue-50",update:"bg-yellow-50",delete:"bg-red-50",unknown:"bg-gray-50"};e.s(["default",0,({tools:e,value:t,onChange:r,readOnly:a=!1,searchFilter:l=""})=>{let[o,m]=(0,s.useState)({read:!1,create:!1,update:!1,delete:!1,unknown:!0}),g=(0,s.useMemo)(()=>x(e),[e]),p=(0,s.useMemo)(()=>new Set(void 0===t?e.map(e=>e.name):t),[t,e]),f=e=>{if(a)return;let t=new Set(p);t.has(e)?t.delete(e):t.add(e),r(Array.from(t))};return 0===e.length?null:(0,n.jsx)("div",{className:"space-y-3",children:y.map(e=>{let t,s=g[e];if(0===s.length)return null;if(l){let e=l.toLowerCase();if(!s.some(t=>t.name.toLowerCase().includes(e)||(t.description??"").toLowerCase().includes(e)))return null}let h=b[e],x=(t=g[e]).length>0&&t.every(e=>p.has(e.name)),y=(e=>{let t=g[e];if(0===t.length)return!1;let r=t.filter(e=>p.has(e.name)).length;return r>0&&r{m(t=>({...t,[e]:!t[e]}))},children:[C?(0,n.jsx)(u.default,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}):(0,n.jsx)(d.ChevronDownIcon,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}),(0,n.jsx)("span",{className:"font-semibold text-gray-900 text-sm",children:h.label}),(0,n.jsx)("span",{className:`text-xs px-2 py-0.5 rounded-full ${v[h.risk]}`,children:"high"===h.risk?"High Risk":"medium"===h.risk?"Medium Risk":"low"===h.risk?"Safe":"Unclassified"}),(0,n.jsxs)("span",{className:"text-xs text-gray-500 ml-1",children:[s.filter(e=>p.has(e.name)).length,"/",s.length," allowed"]})]}),!a&&(0,n.jsxs)("div",{className:"flex items-center gap-2 ml-4",children:[(0,n.jsx)(c.Text,{className:"text-xs text-gray-500",children:x?"All on":y?"Partial":"All off"}),(0,n.jsx)(i.Checkbox,{checked:x,indeterminate:y,onChange:t=>((e,t)=>{if(a)return;let l=new Set(p);for(let r of g[e])t?l.add(r.name):l.delete(r.name);r(Array.from(l))})(e,t.target.checked),onClick:e=>e.stopPropagation()})]})]}),!C&&(0,n.jsx)("div",{className:"px-4 pt-2 pb-1 text-xs text-gray-500 bg-white border-b border-gray-100",children:h.description}),!C&&(0,n.jsx)("div",{className:"bg-white divide-y divide-gray-50",children:s.filter(e=>!l||e.name.toLowerCase().includes(l.toLowerCase())||(e.description??"").toLowerCase().includes(l.toLowerCase())).map(e=>{let t,r=(t=e.name,p.has(t));return(0,n.jsxs)("div",{className:`flex items-start gap-3 px-4 py-2.5 transition-colors hover:bg-gray-50 ${!a?"cursor-pointer":""} ${r?"":"opacity-60"}`,onClick:()=>f(e.name),children:[(0,n.jsx)(i.Checkbox,{checked:r,onChange:()=>f(e.name),disabled:a,onClick:e=>e.stopPropagation()}),(0,n.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,n.jsx)(c.Text,{className:"font-medium text-gray-900 text-sm",children:e.name}),e.description&&(0,n.jsx)(c.Text,{className:"text-xs text-gray-500 mt-0.5 leading-snug",children:e.description})]}),(0,n.jsx)("span",{className:`text-xs px-1.5 py-0.5 rounded flex-shrink-0 ${r?"bg-green-100 text-green-700":"bg-gray-100 text-gray-500"}`,children:r?"on":"off"})]},e.name)})})]},e)})})}],531516)},361653,e=>{"use strict";let t=(0,e.i(475254).default)("circle-alert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);e.s(["default",()=>t])},841947,e=>{"use strict";let t=(0,e.i(475254).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["default",()=>t])},603908,e=>{"use strict";let t=(0,e.i(475254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);e.s(["default",()=>t])},793130,e=>{"use strict";var t=e.i(290571),r=e.i(429427),a=e.i(371330),l=e.i(271645),o=e.i(394487),n=e.i(503269),s=e.i(214520),i=e.i(746725),c=e.i(914189),d=e.i(144279),u=e.i(294316),m=e.i(601893),g=e.i(140721),p=e.i(942803),f=e.i(233538),h=e.i(694421),x=e.i(700020),b=e.i(35889),y=e.i(998348),v=e.i(722678);let w=(0,l.createContext)(null);w.displayName="GroupContext";let k=l.Fragment,C=Object.assign((0,x.forwardRefWithAs)(function(e,t){var k;let C=(0,l.useId)(),j=(0,p.useProvidedId)(),N=(0,m.useDisabled)(),{id:S=j||`headlessui-switch-${C}`,disabled:$=N||!1,checked:M,defaultChecked:E,onChange:O,name:T,value:P,form:_,autoFocus:z=!1,...R}=e,I=(0,l.useContext)(w),[L,D]=(0,l.useState)(null),B=(0,l.useRef)(null),F=(0,u.useSyncRefs)(B,t,null===I?null:I.setSwitch,D),A=(0,s.useDefaultValue)(E),[q,H]=(0,n.useControllable)(M,O,null!=A&&A),G=(0,i.useDisposables)(),[X,V]=(0,l.useState)(!1),K=(0,c.useEvent)(()=>{V(!0),null==H||H(!q),G.nextFrame(()=>{V(!1)})}),W=(0,c.useEvent)(e=>{if((0,f.isDisabledReactIssue7711)(e.currentTarget))return e.preventDefault();e.preventDefault(),K()}),U=(0,c.useEvent)(e=>{e.key===y.Keys.Space?(e.preventDefault(),K()):e.key===y.Keys.Enter&&(0,h.attemptSubmit)(e.currentTarget)}),Y=(0,c.useEvent)(e=>e.preventDefault()),Q=(0,v.useLabelledBy)(),J=(0,b.useDescribedBy)(),{isFocusVisible:Z,focusProps:ee}=(0,r.useFocusRing)({autoFocus:z}),{isHovered:et,hoverProps:er}=(0,a.useHover)({isDisabled:$}),{pressed:ea,pressProps:el}=(0,o.useActivePress)({disabled:$}),eo=(0,l.useMemo)(()=>({checked:q,disabled:$,hover:et,focus:Z,active:ea,autofocus:z,changing:X}),[q,et,Z,ea,$,X,z]),en=(0,x.mergeProps)({id:S,ref:F,role:"switch",type:(0,d.useResolveButtonType)(e,L),tabIndex:-1===e.tabIndex?0:null!=(k=e.tabIndex)?k:0,"aria-checked":q,"aria-labelledby":Q,"aria-describedby":J,disabled:$||void 0,autoFocus:z,onClick:W,onKeyUp:U,onKeyPress:Y},ee,er,el),es=(0,l.useCallback)(()=>{if(void 0!==A)return null==H?void 0:H(A)},[H,A]),ei=(0,x.useRender)();return l.default.createElement(l.default.Fragment,null,null!=T&&l.default.createElement(g.FormFields,{disabled:$,data:{[T]:P||"on"},overrides:{type:"checkbox",checked:q},form:_,onReset:es}),ei({ourProps:en,theirProps:R,slot:eo,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var t;let[r,a]=(0,l.useState)(null),[o,n]=(0,v.useLabels)(),[s,i]=(0,b.useDescriptions)(),c=(0,l.useMemo)(()=>({switch:r,setSwitch:a}),[r,a]),d=(0,x.useRender)();return l.default.createElement(i,{name:"Switch.Description",value:s},l.default.createElement(n,{name:"Switch.Label",value:o,props:{htmlFor:null==(t=c.switch)?void 0:t.id,onClick(e){r&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),r.click(),r.focus({preventScroll:!0}))}}},l.default.createElement(w.Provider,{value:c},d({ourProps:{},theirProps:e,slot:{},defaultTag:k,name:"Switch.Group"}))))},Label:v.Label,Description:b.Description});var j=e.i(888288),N=e.i(95779),S=e.i(444755),$=e.i(673706),M=e.i(829087);let E=(0,$.makeClassName)("Switch"),O=l.default.forwardRef((e,r)=>{let{checked:a,defaultChecked:o=!1,onChange:n,color:s,name:i,error:c,errorMessage:d,disabled:u,required:m,tooltip:g,id:p}=e,f=(0,t.__rest)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),h={bgColor:s?(0,$.getColorClassNames)(s,N.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:s?(0,$.getColorClassNames)(s,N.colorPalette.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[x,b]=(0,j.default)(o,a),[y,v]=(0,l.useState)(!1),{tooltipProps:w,getReferenceProps:k}=(0,M.useTooltip)(300);return l.default.createElement("div",{className:"flex flex-row items-center justify-start"},l.default.createElement(M.default,Object.assign({text:g},w)),l.default.createElement("div",Object.assign({ref:(0,$.mergeRefs)([r,w.refs.setReference]),className:(0,S.tremorTwMerge)(E("root"),"flex flex-row relative h-5")},f,k),l.default.createElement("input",{type:"checkbox",className:(0,S.tremorTwMerge)(E("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:i,required:m,checked:x,onChange:e=>{e.preventDefault()}}),l.default.createElement(C,{checked:x,onChange:e=>{b(e),null==n||n(e)},disabled:u,className:(0,S.tremorTwMerge)(E("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:()=>v(!0),onBlur:()=>v(!1),id:p},l.default.createElement("span",{className:(0,S.tremorTwMerge)(E("sr-only"),"sr-only")},"Switch ",x?"on":"off"),l.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("background"),x?h.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.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("round"),x?(0,S.tremorTwMerge)(h.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",y?(0,S.tremorTwMerge)("ring-2",h.ringColor):"")}))),c&&d?l.default.createElement("p",{className:(0,S.tremorTwMerge)(E("errorMessage"),"text-sm text-red-500 mt-1 ")},d):null)});O.displayName="Switch",e.s(["Switch",()=>O],793130)},158392,419470,e=>{"use strict";var t=e.i(843476),r=e.i(779241);let a={ttl:3600,lowest_latency_buffer:0},l=({routingStrategyArgs:e})=>{let l={ttl:"Sliding window to look back over when calculating the average latency of a deployment. Default - 1 hour (in seconds).",lowest_latency_buffer:"Shuffle between deployments within this % of the lowest latency. Default - 0 (i.e. always pick lowest latency)."};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Latency-Based Configuration"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Fine-tune latency-based routing behavior"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e||a).map(([e,a])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:e.replace(/_/g," ")}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l[e]||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:"object"==typeof a?JSON.stringify(a,null,2):a?.toString(),className:"font-mono text-sm w-full"})]})},e))})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"})]})},o=({routerSettings:e,routerFieldsMetadata:a})=>(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Reliability & Retries"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure retry logic and failure handling"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e).filter(([e,t])=>"fallbacks"!=e&&"context_window_fallbacks"!=e&&"routing_strategy_args"!=e&&"routing_strategy"!=e&&"enable_tag_filtering"!=e).map(([e,l])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:a[e]?.ui_field_name||e}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:a[e]?.field_description||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:null==l||"null"===l?"":"object"==typeof l?JSON.stringify(l,null,2):l?.toString()||"",placeholder:"—",className:"font-mono text-sm w-full"})]})},e))})]});var n=e.i(199133);let s=({selectedStrategy:e,availableStrategies:r,routingStrategyDescriptions:a,routerFieldsMetadata:l,onStrategyChange:o})=>(0,t.jsxs)("div",{className:"space-y-2 max-w-3xl",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:l.routing_strategy?.ui_field_name||"Routing Strategy"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l.routing_strategy?.field_description||""})]}),(0,t.jsx)("div",{className:"routing-strategy-select max-w-3xl",children:(0,t.jsx)(n.Select,{value:e,onChange:o,style:{width:"100%"},size:"large",children:r.map(e=>(0,t.jsx)(n.Select.Option,{value:e,label:e,children:(0,t.jsxs)("div",{className:"flex flex-col gap-0.5 py-1",children:[(0,t.jsx)("span",{className:"font-mono text-sm font-medium",children:e}),a[e]&&(0,t.jsx)("span",{className:"text-xs text-gray-500 font-normal",children:a[e]})]})},e))})})]});var i=e.i(793130);let c=({enabled:e,routerFieldsMetadata:r,onToggle:a})=>(0,t.jsx)("div",{className:"space-y-3 max-w-3xl",children:(0,t.jsxs)("div",{className:"flex items-start justify-between",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:r.enable_tag_filtering?.ui_field_name||"Enable Tag Filtering"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500 mt-0.5",children:[r.enable_tag_filtering?.field_description||"",r.enable_tag_filtering?.link&&(0,t.jsxs)(t.Fragment,{children:[" ",(0,t.jsx)("a",{href:r.enable_tag_filtering.link,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline",children:"Learn more"})]})]})]}),(0,t.jsx)(i.Switch,{checked:e,onChange:a,className:"ml-4"})]})});e.s(["default",0,({value:e,onChange:r,routerFieldsMetadata:a,availableRoutingStrategies:n,routingStrategyDescriptions:i})=>(0,t.jsxs)("div",{className:"w-full space-y-8 py-2",children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Routing Settings"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure how requests are routed to deployments"})]}),n.length>0&&(0,t.jsx)(s,{selectedStrategy:e.selectedStrategy||e.routerSettings.routing_strategy||null,availableStrategies:n,routingStrategyDescriptions:i,routerFieldsMetadata:a,onStrategyChange:t=>{r({...e,selectedStrategy:t})}}),(0,t.jsx)(c,{enabled:e.enableTagFiltering,routerFieldsMetadata:a,onToggle:t=>{r({...e,enableTagFiltering:t})}})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),"latency-based-routing"===e.selectedStrategy&&(0,t.jsx)(l,{routingStrategyArgs:e.routerSettings.routing_strategy_args}),(0,t.jsx)(o,{routerSettings:e.routerSettings,routerFieldsMetadata:a})]})],158392);var d=e.i(994388),u=e.i(998573),m=e.i(653496),g=e.i(107233),p=e.i(271645),f=e.i(592968),h=e.i(361653),h=h;let x=(0,e.i(475254).default)("arrow-down",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var b=e.i(37727);function y({group:e,onChange:r,availableModels:a,maxFallbacks:l}){let o=a.filter(t=>t!==e.primaryModel),s=e.fallbackModels.length{let a=[...e.fallbackModels];a.includes(t)&&(a=a.filter(e=>e!==t)),r({...e,primaryModel:t,fallbackModels:a})},showSearch:!0,getPopupContainer:e=>e.parentElement||document.body,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase()),options:a.map(e=>({label:e,value:e}))}),!e.primaryModel&&(0,t.jsxs)("div",{className:"mt-2 flex items-center gap-2 text-amber-600 text-xs bg-amber-50 p-2 rounded",children:[(0,t.jsx)(h.default,{className:"w-4 h-4"}),(0,t.jsx)("span",{children:"Select a model to begin configuring fallbacks"})]})]}),(0,t.jsx)("div",{className:"flex items-center justify-center -my-4 z-10",children:(0,t.jsxs)("div",{className:"bg-indigo-50 text-indigo-500 px-4 py-1 rounded-full text-xs font-bold border border-indigo-100 flex items-center gap-2 shadow-sm",children:[(0,t.jsx)(x,{className:"w-4 h-4"}),"IF FAILS, TRY..."]})}),(0,t.jsxs)("div",{className:`transition-opacity duration-300 ${!e.primaryModel?"opacity-50 pointer-events-none":"opacity-100"}`,children:[(0,t.jsxs)("label",{className:"block text-sm font-semibold text-gray-700 mb-2",children:["Fallback Chain ",(0,t.jsx)("span",{className:"text-red-500",children:"*"}),(0,t.jsxs)("span",{className:"text-xs text-gray-500 font-normal ml-2",children:["(Max ",l," fallbacks at a time)"]})]}),(0,t.jsxs)("div",{className:"bg-gray-50 rounded-xl p-4 border border-gray-200",children:[(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(n.Select,{mode:"multiple",className:"w-full",size:"large",placeholder:s?"Select fallback models to add...":`Maximum ${l} fallbacks reached`,value:e.fallbackModels,onChange:t=>{let a=t.slice(0,l);r({...e,fallbackModels:a})},disabled:!e.primaryModel,getPopupContainer:e=>e.parentElement||document.body,options:o.map(e=>({label:e,value:e})),optionRender:(r,a)=>{let l=e.fallbackModels.includes(r.value),o=l?e.fallbackModels.indexOf(r.value)+1:null;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[l&&null!==o&&(0,t.jsx)("span",{className:"flex items-center justify-center w-5 h-5 rounded bg-indigo-100 text-indigo-600 text-xs font-bold",children:o}),(0,t.jsx)("span",{children:r.label})]})},maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(f.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})}),showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase())}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1 ml-1",children:s?`Search and select multiple models. Selected models will appear below in order. (${e.fallbackModels.length}/${l} used)`:`Maximum ${l} fallbacks reached. Remove some to add more.`})]}),(0,t.jsx)("div",{className:"space-y-2 min-h-[100px]",children:0===e.fallbackModels.length?(0,t.jsxs)("div",{className:"h-32 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)("span",{className:"text-sm",children:"No fallback models selected"}),(0,t.jsx)("span",{className:"text-xs mt-1",children:"Add models from the dropdown above"})]}):e.fallbackModels.map((a,l)=>(0,t.jsxs)("div",{className:"group flex items-center justify-between p-3 bg-white rounded-lg border border-gray-200 hover:border-indigo-300 hover:shadow-sm transition-all",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex items-center justify-center w-6 h-6 rounded bg-gray-100 text-gray-400 group-hover:text-indigo-500 group-hover:bg-indigo-50",children:(0,t.jsx)("span",{className:"text-xs font-bold",children:l+1})}),(0,t.jsx)("div",{children:(0,t.jsx)("span",{className:"font-medium text-gray-800",children:a})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>{let t;return t=e.fallbackModels.filter((e,t)=>t!==l),void r({...e,fallbackModels:t})},className:"opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500 p-1",children:(0,t.jsx)(b.X,{className:"w-4 h-4"})})]},`${a}-${l}`))})]})]})]})}function v({groups:e,onGroupsChange:r,availableModels:a,maxFallbacks:l=10,maxGroups:o=5}){let[n,s]=(0,p.useState)(e.length>0?e[0].id:"1");(0,p.useEffect)(()=>{e.length>0?e.some(e=>e.id===n)||s(e[0].id):s("1")},[e]);let i=()=>{if(e.length>=o)return;let t=Date.now().toString();r([...e,{id:t,primaryModel:null,fallbackModels:[]}]),s(t)},c=t=>{r(e.map(e=>e.id===t.id?t:e))},f=e.map((r,o)=>{let n=r.primaryModel?r.primaryModel:`Group ${o+1}`;return{key:r.id,label:n,closable:e.length>1,children:(0,t.jsx)(y,{group:r,onChange:c,availableModels:a,maxFallbacks:l})}});return 0===e.length?(0,t.jsxs)("div",{className:"text-center py-12 bg-gray-50 rounded-lg border border-dashed border-gray-300",children:[(0,t.jsx)("p",{className:"text-gray-500 mb-4",children:"No fallback groups configured"}),(0,t.jsx)(d.Button,{variant:"primary",onClick:i,icon:()=>(0,t.jsx)(g.Plus,{className:"w-4 h-4"}),children:"Create First Group"})]}):(0,t.jsx)(m.Tabs,{type:"editable-card",activeKey:n,onChange:s,onEdit:(t,a)=>{"add"===a?i():"remove"===a&&e.length>1&&(t=>{if(1===e.length)return u.message.warning("At least one group is required");let a=e.filter(e=>e.id!==t);r(a),n===t&&a.length>0&&s(a[a.length-1].id)})(t)},items:f,className:"fallback-tabs",tabBarStyle:{marginBottom:0},hideAdd:e.length>=o})}e.s(["FallbackSelectionForm",()=>v],419470)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/16d77647b44247de.js b/litellm/proxy/_experimental/out/_next/static/chunks/715057b8e12f1cd9.js similarity index 93% rename from litellm/proxy/_experimental/out/_next/static/chunks/16d77647b44247de.js rename to litellm/proxy/_experimental/out/_next/static/chunks/715057b8e12f1cd9.js index e1a9f60f2b..0e332a63ac 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/16d77647b44247de.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/715057b8e12f1cd9.js @@ -4,4 +4,4 @@ `]:{[`&:hover ${t}-inner`]:{borderColor:e.colorPrimary}},[`${l}:not(${l}-disabled)`]:{[`&:hover ${t}-checked:not(${t}-disabled) ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"},[`&:hover ${t}-checked:not(${t}-disabled):after`]:{borderColor:e.colorPrimaryHover}}},{[`${t}-checked`]:{[`${t}-inner`]:{backgroundColor:e.colorPrimary,borderColor:e.colorPrimary,"&:after":{opacity:1,transform:"rotate(45deg) scale(1) translate(-50%,-50%)",transition:`all ${e.motionDurationMid} ${e.motionEaseOutBack} ${e.motionDurationFast}`}}},[` ${l}-checked:not(${l}-disabled), ${t}-checked:not(${t}-disabled) - `]:{[`&:hover ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"}}},{[t]:{"&-indeterminate":{"&":{[`${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${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 ${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${e.colorPrimary}`}}}}},{[`${l}-disabled`]:{cursor:"not-allowed"},[`${t}-disabled`]:{[`&, ${t}-input`]:{cursor:"not-allowed",pointerEvents:"none"},[`${t}-inner`]:{background:e.colorBgContainerDisabled,borderColor:e.colorBorder,"&:after":{borderColor:e.colorTextDisabled}},"&:after":{display:"none"},"& + span":{color:e.colorTextDisabled},[`&${t}-indeterminate ${t}-inner::after`]:{background:e.colorTextDisabled}}}]})((0,o.mergeToken)(t,{checkboxCls:`.${e}`,checkboxSize:t.controlInteractiveSize}))}let s=(0,l.genStyleHooks)("Checkbox",(e,{prefixCls:t})=>[n(t,e)]);e.s(["default",0,s,"getStyle",()=>n],236836)},374276,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(91874),l=e.i(611935),o=e.i(121872),n=e.i(26905),s=e.i(242064),i=e.i(937328),c=e.i(321883),d=e.i(62139),u=e.i(421512),m=e.i(236836),g=e.i(681216),p=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let f=t.forwardRef((e,f)=>{var h;let{prefixCls:x,className:b,rootClassName:y,children:v,indeterminate:w=!1,style:k,onMouseEnter:C,onMouseLeave:j,skipGroup:N=!1,disabled:S}=e,$=p(e,["prefixCls","className","rootClassName","children","indeterminate","style","onMouseEnter","onMouseLeave","skipGroup","disabled"]),{getPrefixCls:M,direction:E,checkbox:O}=t.useContext(s.ConfigContext),T=t.useContext(u.default),{isFormItemInput:P}=t.useContext(d.FormItemInputContext),_=t.useContext(i.default),z=null!=(h=(null==T?void 0:T.disabled)||S)?h:_,R=t.useRef($.value),I=t.useRef(null),L=(0,l.composeRef)(f,I);t.useEffect(()=>{null==T||T.registerValue($.value)},[]),t.useEffect(()=>{if(!N)return $.value!==R.current&&(null==T||T.cancelValue(R.current),null==T||T.registerValue($.value),R.current=$.value),()=>null==T?void 0:T.cancelValue($.value)},[$.value]),t.useEffect(()=>{var e;(null==(e=I.current)?void 0:e.input)&&(I.current.input.indeterminate=w)},[w]);let D=M("checkbox",x),B=(0,c.default)(D),[F,A,q]=(0,m.default)(D,B),H=Object.assign({},$);T&&!N&&(H.onChange=(...e)=>{$.onChange&&$.onChange.apply($,e),T.toggleOption&&T.toggleOption({label:v,value:$.value})},H.name=T.name,H.checked=T.value.includes($.value));let G=(0,r.default)(`${D}-wrapper`,{[`${D}-rtl`]:"rtl"===E,[`${D}-wrapper-checked`]:H.checked,[`${D}-wrapper-disabled`]:z,[`${D}-wrapper-in-form-item`]:P},null==O?void 0:O.className,b,y,q,B,A),X=(0,r.default)({[`${D}-indeterminate`]:w},n.TARGET_CLS,A),[V,K]=(0,g.default)(H.onClick);return F(t.createElement(o.default,{component:"Checkbox",disabled:z},t.createElement("label",{className:G,style:Object.assign(Object.assign({},null==O?void 0:O.style),k),onMouseEnter:C,onMouseLeave:j,onClick:V},t.createElement(a.default,Object.assign({},H,{onClick:K,prefixCls:D,className:X,disabled:z,ref:L})),null!=v&&t.createElement("span",{className:`${D}-label`},v))))});var h=e.i(8211),x=e.i(529681),b=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let y=t.forwardRef((e,a)=>{let{defaultValue:l,children:o,options:n=[],prefixCls:i,className:d,rootClassName:g,style:p,onChange:y}=e,v=b(e,["defaultValue","children","options","prefixCls","className","rootClassName","style","onChange"]),{getPrefixCls:w,direction:k}=t.useContext(s.ConfigContext),[C,j]=t.useState(v.value||l||[]),[N,S]=t.useState([]);t.useEffect(()=>{"value"in v&&j(v.value||[])},[v.value]);let $=t.useMemo(()=>n.map(e=>"string"==typeof e||"number"==typeof e?{label:e,value:e}:e),[n]),M=e=>{S(t=>t.filter(t=>t!==e))},E=e=>{S(t=>[].concat((0,h.default)(t),[e]))},O=e=>{let t=C.indexOf(e.value),r=(0,h.default)(C);-1===t?r.push(e.value):r.splice(t,1),"value"in v||j(r),null==y||y(r.filter(e=>N.includes(e)).sort((e,t)=>$.findIndex(t=>t.value===e)-$.findIndex(e=>e.value===t)))},T=w("checkbox",i),P=`${T}-group`,_=(0,c.default)(T),[z,R,I]=(0,m.default)(T,_),L=(0,x.default)(v,["value","disabled"]),D=n.length?$.map(e=>t.createElement(f,{prefixCls:T,key:e.value.toString(),disabled:"disabled"in e?e.disabled:v.disabled,value:e.value,checked:C.includes(e.value),onChange:e.onChange,className:(0,r.default)(`${P}-item`,e.className),style:e.style,title:e.title,id:e.id,required:e.required},e.label)):o,B=t.useMemo(()=>({toggleOption:O,value:C,disabled:v.disabled,name:v.name,registerValue:E,cancelValue:M}),[O,C,v.disabled,v.name,E,M]),F=(0,r.default)(P,{[`${P}-rtl`]:"rtl"===k},d,g,I,_,R);return z(t.createElement("div",Object.assign({className:F,style:p},L,{ref:a}),t.createElement(u.default.Provider,{value:B},D)))});f.Group=y,f.__ANT_CHECKBOX=!0,e.s(["default",0,f],374276)},536916,e=>{"use strict";var t=e.i(374276);e.s(["Checkbox",()=>t.default])},292639,e=>{"use strict";var t=e.i(764205),r=e.i(266027);let a=(0,e.i(243652).createQueryKeys)("uiSettings");e.s(["useUISettings",0,()=>(0,r.useQuery)({queryKey:a.list({}),queryFn:async()=>await (0,t.getUiSettings)(),staleTime:36e5,gcTime:36e5})])},250980,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlusCircleIcon",0,r],250980)},502547,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 5l7 7-7 7"}))});e.s(["ChevronRightIcon",0,r],502547)},988297,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"}))});e.s(["PlusIcon",0,r],988297)},797672,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"}))});e.s(["PencilIcon",0,r],797672)},992619,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(779241),l=e.i(599724),o=e.i(199133),n=e.i(983561),s=e.i(689020);e.s(["default",0,({accessToken:e,value:i,placeholder:c="Select a Model",onChange:d,disabled:u=!1,style:m,className:g,showLabel:p=!0,labelText:f="Select Model"})=>{let[h,x]=(0,r.useState)(i),[b,y]=(0,r.useState)(!1),[v,w]=(0,r.useState)([]),k=(0,r.useRef)(null);return(0,r.useEffect)(()=>{x(i)},[i]),(0,r.useEffect)(()=>{e&&(async()=>{try{let t=await (0,s.fetchAvailableModels)(e);console.log("Fetched models for selector:",t),t.length>0&&w(t)}catch(e){console.error("Error fetching model info:",e)}})()},[e]),(0,t.jsxs)("div",{children:[p&&(0,t.jsxs)(l.Text,{className:"font-medium block mb-2 text-gray-700 flex items-center",children:[(0,t.jsx)(n.RobotOutlined,{className:"mr-2"})," ",f]}),(0,t.jsx)(o.Select,{value:h,placeholder:c,onChange:e=>{"custom"===e?(y(!0),x(void 0)):(y(!1),x(e),d&&d(e))},options:[...Array.from(new Set(v.map(e=>e.model_group))).map((e,t)=>({value:e,label:e,key:t})),{value:"custom",label:"Enter custom model",key:"custom"}],style:{width:"100%",...m},showSearch:!0,className:`rounded-md ${g||""}`,disabled:u}),b&&(0,t.jsx)(a.TextInput,{className:"mt-2",placeholder:"Enter custom model name",onValueChange:e=>{k.current&&clearTimeout(k.current),k.current=setTimeout(()=>{x(e),d&&d(e)},500)},disabled:u})]})}])},409797,e=>{"use strict";var t=e.i(631171);e.s(["ChevronDownIcon",()=>t.default])},91739,e=>{"use strict";var t=e.i(544195);e.s(["Radio",()=>t.default])},500727,696609,531516,e=>{"use strict";var t=e.i(266027),r=e.i(243652),a=e.i(764205),l=e.i(135214);let o=(0,r.createQueryKeys)("mcpServers");e.s(["useMCPServers",0,e=>{let{accessToken:r}=(0,l.default)();return(0,t.useQuery)({queryKey:o.list(e?{filters:{teamId:e}}:void 0),queryFn:async()=>await (0,a.fetchMCPServers)(r,e),enabled:!!r})}],500727);var n=e.i(843476),s=e.i(271645),i=e.i(536916),c=e.i(599724),d=e.i(409797),u=e.i(246349),u=u;let m=/\b(delete|remove|destroy|purge|drop|erase|unlink)\b/i,g=/\b(create|add|insert|new|post|submit|register|make|generate|write|upload)\b/i,p=/\b(update|edit|modify|change|patch|put|set|rename|move|transform)\b/i,f=/\b(get|read|list|fetch|search|find|query|retrieve|show|view|check|describe|info)\b/i;function h(e,t=""){let r=e.toLowerCase();if(f.test(r))return"read";if(m.test(r))return"delete";if(p.test(r))return"update";if(g.test(r))return"create";if(t){let e=t.toLowerCase();if(f.test(e))return"read";if(m.test(e))return"delete";if(p.test(e))return"update";if(g.test(e))return"create"}return"unknown"}function x(e){let t={read:[],create:[],update:[],delete:[],unknown:[]};for(let r of e)t[h(r.name,r.description)].push(r);return t}let b={read:{label:"Read",description:"Safe operations — fetch, list, search. No side effects.",risk:"low"},create:{label:"Create",description:"Add new resources — insert, upload, register.",risk:"medium"},update:{label:"Update",description:"Modify existing resources — edit, patch, rename.",risk:"medium"},delete:{label:"Delete",description:"Destructive operations — remove, purge, destroy.",risk:"high"},unknown:{label:"Other",description:"Operations that could not be automatically classified.",risk:"unknown"}};e.s(["CRUD_GROUP_META",0,b,"classifyToolOp",()=>h,"groupToolsByCrud",()=>x],696609);let y=["read","create","update","delete","unknown"],v={low:"bg-green-100 text-green-800",medium:"bg-yellow-100 text-yellow-800",high:"bg-red-100 text-red-800 font-semibold",unknown:"bg-gray-100 text-gray-700"},w={read:"border-green-200",create:"border-blue-200",update:"border-yellow-200",delete:"border-red-300",unknown:"border-gray-200"},k={read:"bg-green-50",create:"bg-blue-50",update:"bg-yellow-50",delete:"bg-red-50",unknown:"bg-gray-50"};e.s(["default",0,({tools:e,value:t,onChange:r,readOnly:a=!1,searchFilter:l=""})=>{let[o,m]=(0,s.useState)({read:!1,create:!1,update:!1,delete:!1,unknown:!0}),g=(0,s.useMemo)(()=>x(e),[e]),p=(0,s.useMemo)(()=>new Set(void 0===t?e.map(e=>e.name):t),[t,e]),f=e=>{if(a)return;let t=new Set(p);t.has(e)?t.delete(e):t.add(e),r(Array.from(t))};return 0===e.length?null:(0,n.jsx)("div",{className:"space-y-3",children:y.map(e=>{let t,s=g[e];if(0===s.length)return null;if(l){let e=l.toLowerCase();if(!s.some(t=>t.name.toLowerCase().includes(e)||(t.description??"").toLowerCase().includes(e)))return null}let h=b[e],x=(t=g[e]).length>0&&t.every(e=>p.has(e.name)),y=(e=>{let t=g[e];if(0===t.length)return!1;let r=t.filter(e=>p.has(e.name)).length;return r>0&&r{m(t=>({...t,[e]:!t[e]}))},children:[C?(0,n.jsx)(u.default,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}):(0,n.jsx)(d.ChevronDownIcon,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}),(0,n.jsx)("span",{className:"font-semibold text-gray-900 text-sm",children:h.label}),(0,n.jsx)("span",{className:`text-xs px-2 py-0.5 rounded-full ${v[h.risk]}`,children:"high"===h.risk?"High Risk":"medium"===h.risk?"Medium Risk":"low"===h.risk?"Safe":"Unclassified"}),(0,n.jsxs)("span",{className:"text-xs text-gray-500 ml-1",children:[s.filter(e=>p.has(e.name)).length,"/",s.length," allowed"]})]}),!a&&(0,n.jsxs)("div",{className:"flex items-center gap-2 ml-4",children:[(0,n.jsx)(c.Text,{className:"text-xs text-gray-500",children:x?"All on":y?"Partial":"All off"}),(0,n.jsx)(i.Checkbox,{checked:x,indeterminate:y,onChange:t=>((e,t)=>{if(a)return;let l=new Set(p);for(let r of g[e])t?l.add(r.name):l.delete(r.name);r(Array.from(l))})(e,t.target.checked),onClick:e=>e.stopPropagation()})]})]}),!C&&(0,n.jsx)("div",{className:"px-4 pt-2 pb-1 text-xs text-gray-500 bg-white border-b border-gray-100",children:h.description}),!C&&(0,n.jsx)("div",{className:"bg-white divide-y divide-gray-50",children:s.filter(e=>!l||e.name.toLowerCase().includes(l.toLowerCase())||(e.description??"").toLowerCase().includes(l.toLowerCase())).map(e=>{let t,r=(t=e.name,p.has(t));return(0,n.jsxs)("div",{className:`flex items-start gap-3 px-4 py-2.5 transition-colors hover:bg-gray-50 ${!a?"cursor-pointer":""} ${r?"":"opacity-60"}`,onClick:()=>f(e.name),children:[(0,n.jsx)(i.Checkbox,{checked:r,onChange:()=>f(e.name),disabled:a,onClick:e=>e.stopPropagation()}),(0,n.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,n.jsx)(c.Text,{className:"font-medium text-gray-900 text-sm",children:e.name}),e.description&&(0,n.jsx)(c.Text,{className:"text-xs text-gray-500 mt-0.5 leading-snug",children:e.description})]}),(0,n.jsx)("span",{className:`text-xs px-1.5 py-0.5 rounded flex-shrink-0 ${r?"bg-green-100 text-green-700":"bg-gray-100 text-gray-500"}`,children:r?"on":"off"})]},e.name)})})]},e)})})}],531516)},361653,e=>{"use strict";let t=(0,e.i(475254).default)("circle-alert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);e.s(["default",()=>t])},603908,e=>{"use strict";let t=(0,e.i(475254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);e.s(["default",()=>t])},841947,e=>{"use strict";let t=(0,e.i(475254).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["default",()=>t])},793130,e=>{"use strict";var t=e.i(290571),r=e.i(429427),a=e.i(371330),l=e.i(271645),o=e.i(394487),n=e.i(503269),s=e.i(214520),i=e.i(746725),c=e.i(914189),d=e.i(144279),u=e.i(294316),m=e.i(601893),g=e.i(140721),p=e.i(942803),f=e.i(233538),h=e.i(694421),x=e.i(700020),b=e.i(35889),y=e.i(998348),v=e.i(722678);let w=(0,l.createContext)(null);w.displayName="GroupContext";let k=l.Fragment,C=Object.assign((0,x.forwardRefWithAs)(function(e,t){var k;let C=(0,l.useId)(),j=(0,p.useProvidedId)(),N=(0,m.useDisabled)(),{id:S=j||`headlessui-switch-${C}`,disabled:$=N||!1,checked:M,defaultChecked:E,onChange:O,name:T,value:P,form:_,autoFocus:z=!1,...R}=e,I=(0,l.useContext)(w),[L,D]=(0,l.useState)(null),B=(0,l.useRef)(null),F=(0,u.useSyncRefs)(B,t,null===I?null:I.setSwitch,D),A=(0,s.useDefaultValue)(E),[q,H]=(0,n.useControllable)(M,O,null!=A&&A),G=(0,i.useDisposables)(),[X,V]=(0,l.useState)(!1),K=(0,c.useEvent)(()=>{V(!0),null==H||H(!q),G.nextFrame(()=>{V(!1)})}),W=(0,c.useEvent)(e=>{if((0,f.isDisabledReactIssue7711)(e.currentTarget))return e.preventDefault();e.preventDefault(),K()}),U=(0,c.useEvent)(e=>{e.key===y.Keys.Space?(e.preventDefault(),K()):e.key===y.Keys.Enter&&(0,h.attemptSubmit)(e.currentTarget)}),Y=(0,c.useEvent)(e=>e.preventDefault()),Q=(0,v.useLabelledBy)(),J=(0,b.useDescribedBy)(),{isFocusVisible:Z,focusProps:ee}=(0,r.useFocusRing)({autoFocus:z}),{isHovered:et,hoverProps:er}=(0,a.useHover)({isDisabled:$}),{pressed:ea,pressProps:el}=(0,o.useActivePress)({disabled:$}),eo=(0,l.useMemo)(()=>({checked:q,disabled:$,hover:et,focus:Z,active:ea,autofocus:z,changing:X}),[q,et,Z,ea,$,X,z]),en=(0,x.mergeProps)({id:S,ref:F,role:"switch",type:(0,d.useResolveButtonType)(e,L),tabIndex:-1===e.tabIndex?0:null!=(k=e.tabIndex)?k:0,"aria-checked":q,"aria-labelledby":Q,"aria-describedby":J,disabled:$||void 0,autoFocus:z,onClick:W,onKeyUp:U,onKeyPress:Y},ee,er,el),es=(0,l.useCallback)(()=>{if(void 0!==A)return null==H?void 0:H(A)},[H,A]),ei=(0,x.useRender)();return l.default.createElement(l.default.Fragment,null,null!=T&&l.default.createElement(g.FormFields,{disabled:$,data:{[T]:P||"on"},overrides:{type:"checkbox",checked:q},form:_,onReset:es}),ei({ourProps:en,theirProps:R,slot:eo,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var t;let[r,a]=(0,l.useState)(null),[o,n]=(0,v.useLabels)(),[s,i]=(0,b.useDescriptions)(),c=(0,l.useMemo)(()=>({switch:r,setSwitch:a}),[r,a]),d=(0,x.useRender)();return l.default.createElement(i,{name:"Switch.Description",value:s},l.default.createElement(n,{name:"Switch.Label",value:o,props:{htmlFor:null==(t=c.switch)?void 0:t.id,onClick(e){r&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),r.click(),r.focus({preventScroll:!0}))}}},l.default.createElement(w.Provider,{value:c},d({ourProps:{},theirProps:e,slot:{},defaultTag:k,name:"Switch.Group"}))))},Label:v.Label,Description:b.Description});var j=e.i(888288),N=e.i(95779),S=e.i(444755),$=e.i(673706),M=e.i(829087);let E=(0,$.makeClassName)("Switch"),O=l.default.forwardRef((e,r)=>{let{checked:a,defaultChecked:o=!1,onChange:n,color:s,name:i,error:c,errorMessage:d,disabled:u,required:m,tooltip:g,id:p}=e,f=(0,t.__rest)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),h={bgColor:s?(0,$.getColorClassNames)(s,N.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:s?(0,$.getColorClassNames)(s,N.colorPalette.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[x,b]=(0,j.default)(o,a),[y,v]=(0,l.useState)(!1),{tooltipProps:w,getReferenceProps:k}=(0,M.useTooltip)(300);return l.default.createElement("div",{className:"flex flex-row items-center justify-start"},l.default.createElement(M.default,Object.assign({text:g},w)),l.default.createElement("div",Object.assign({ref:(0,$.mergeRefs)([r,w.refs.setReference]),className:(0,S.tremorTwMerge)(E("root"),"flex flex-row relative h-5")},f,k),l.default.createElement("input",{type:"checkbox",className:(0,S.tremorTwMerge)(E("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:i,required:m,checked:x,onChange:e=>{e.preventDefault()}}),l.default.createElement(C,{checked:x,onChange:e=>{b(e),null==n||n(e)},disabled:u,className:(0,S.tremorTwMerge)(E("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:()=>v(!0),onBlur:()=>v(!1),id:p},l.default.createElement("span",{className:(0,S.tremorTwMerge)(E("sr-only"),"sr-only")},"Switch ",x?"on":"off"),l.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("background"),x?h.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.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("round"),x?(0,S.tremorTwMerge)(h.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",y?(0,S.tremorTwMerge)("ring-2",h.ringColor):"")}))),c&&d?l.default.createElement("p",{className:(0,S.tremorTwMerge)(E("errorMessage"),"text-sm text-red-500 mt-1 ")},d):null)});O.displayName="Switch",e.s(["Switch",()=>O],793130)},158392,419470,e=>{"use strict";var t=e.i(843476),r=e.i(779241);let a={ttl:3600,lowest_latency_buffer:0},l=({routingStrategyArgs:e})=>{let l={ttl:"Sliding window to look back over when calculating the average latency of a deployment. Default - 1 hour (in seconds).",lowest_latency_buffer:"Shuffle between deployments within this % of the lowest latency. Default - 0 (i.e. always pick lowest latency)."};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Latency-Based Configuration"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Fine-tune latency-based routing behavior"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e||a).map(([e,a])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:e.replace(/_/g," ")}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l[e]||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:"object"==typeof a?JSON.stringify(a,null,2):a?.toString(),className:"font-mono text-sm w-full"})]})},e))})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"})]})},o=({routerSettings:e,routerFieldsMetadata:a})=>(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Reliability & Retries"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure retry logic and failure handling"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e).filter(([e,t])=>"fallbacks"!=e&&"context_window_fallbacks"!=e&&"routing_strategy_args"!=e&&"routing_strategy"!=e&&"enable_tag_filtering"!=e).map(([e,l])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:a[e]?.ui_field_name||e}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:a[e]?.field_description||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:null==l||"null"===l?"":"object"==typeof l?JSON.stringify(l,null,2):l?.toString()||"",placeholder:"—",className:"font-mono text-sm w-full"})]})},e))})]});var n=e.i(199133);let s=({selectedStrategy:e,availableStrategies:r,routingStrategyDescriptions:a,routerFieldsMetadata:l,onStrategyChange:o})=>(0,t.jsxs)("div",{className:"space-y-2 max-w-3xl",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:l.routing_strategy?.ui_field_name||"Routing Strategy"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l.routing_strategy?.field_description||""})]}),(0,t.jsx)("div",{className:"routing-strategy-select max-w-3xl",children:(0,t.jsx)(n.Select,{value:e,onChange:o,style:{width:"100%"},size:"large",children:r.map(e=>(0,t.jsx)(n.Select.Option,{value:e,label:e,children:(0,t.jsxs)("div",{className:"flex flex-col gap-0.5 py-1",children:[(0,t.jsx)("span",{className:"font-mono text-sm font-medium",children:e}),a[e]&&(0,t.jsx)("span",{className:"text-xs text-gray-500 font-normal",children:a[e]})]})},e))})})]});var i=e.i(793130);let c=({enabled:e,routerFieldsMetadata:r,onToggle:a})=>(0,t.jsx)("div",{className:"space-y-3 max-w-3xl",children:(0,t.jsxs)("div",{className:"flex items-start justify-between",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:r.enable_tag_filtering?.ui_field_name||"Enable Tag Filtering"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500 mt-0.5",children:[r.enable_tag_filtering?.field_description||"",r.enable_tag_filtering?.link&&(0,t.jsxs)(t.Fragment,{children:[" ",(0,t.jsx)("a",{href:r.enable_tag_filtering.link,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline",children:"Learn more"})]})]})]}),(0,t.jsx)(i.Switch,{checked:e,onChange:a,className:"ml-4"})]})});e.s(["default",0,({value:e,onChange:r,routerFieldsMetadata:a,availableRoutingStrategies:n,routingStrategyDescriptions:i})=>(0,t.jsxs)("div",{className:"w-full space-y-8 py-2",children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Routing Settings"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure how requests are routed to deployments"})]}),n.length>0&&(0,t.jsx)(s,{selectedStrategy:e.selectedStrategy||e.routerSettings.routing_strategy||null,availableStrategies:n,routingStrategyDescriptions:i,routerFieldsMetadata:a,onStrategyChange:t=>{r({...e,selectedStrategy:t})}}),(0,t.jsx)(c,{enabled:e.enableTagFiltering,routerFieldsMetadata:a,onToggle:t=>{r({...e,enableTagFiltering:t})}})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),"latency-based-routing"===e.selectedStrategy&&(0,t.jsx)(l,{routingStrategyArgs:e.routerSettings.routing_strategy_args}),(0,t.jsx)(o,{routerSettings:e.routerSettings,routerFieldsMetadata:a})]})],158392);var d=e.i(994388),u=e.i(998573),m=e.i(653496),g=e.i(107233),p=e.i(271645),f=e.i(592968),h=e.i(361653),h=h;let x=(0,e.i(475254).default)("arrow-down",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var b=e.i(37727);function y({group:e,onChange:r,availableModels:a,maxFallbacks:l}){let o=a.filter(t=>t!==e.primaryModel),s=e.fallbackModels.length{let a=[...e.fallbackModels];a.includes(t)&&(a=a.filter(e=>e!==t)),r({...e,primaryModel:t,fallbackModels:a})},showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase()),options:a.map(e=>({label:e,value:e}))}),!e.primaryModel&&(0,t.jsxs)("div",{className:"mt-2 flex items-center gap-2 text-amber-600 text-xs bg-amber-50 p-2 rounded",children:[(0,t.jsx)(h.default,{className:"w-4 h-4"}),(0,t.jsx)("span",{children:"Select a model to begin configuring fallbacks"})]})]}),(0,t.jsx)("div",{className:"flex items-center justify-center -my-4 z-10",children:(0,t.jsxs)("div",{className:"bg-indigo-50 text-indigo-500 px-4 py-1 rounded-full text-xs font-bold border border-indigo-100 flex items-center gap-2 shadow-sm",children:[(0,t.jsx)(x,{className:"w-4 h-4"}),"IF FAILS, TRY..."]})}),(0,t.jsxs)("div",{className:`transition-opacity duration-300 ${!e.primaryModel?"opacity-50 pointer-events-none":"opacity-100"}`,children:[(0,t.jsxs)("label",{className:"block text-sm font-semibold text-gray-700 mb-2",children:["Fallback Chain ",(0,t.jsx)("span",{className:"text-red-500",children:"*"}),(0,t.jsxs)("span",{className:"text-xs text-gray-500 font-normal ml-2",children:["(Max ",l," fallbacks at a time)"]})]}),(0,t.jsxs)("div",{className:"bg-gray-50 rounded-xl p-4 border border-gray-200",children:[(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(n.Select,{mode:"multiple",className:"w-full",size:"large",placeholder:s?"Select fallback models to add...":`Maximum ${l} fallbacks reached`,value:e.fallbackModels,onChange:t=>{let a=t.slice(0,l);r({...e,fallbackModels:a})},disabled:!e.primaryModel,options:o.map(e=>({label:e,value:e})),optionRender:(r,a)=>{let l=e.fallbackModels.includes(r.value),o=l?e.fallbackModels.indexOf(r.value)+1:null;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[l&&null!==o&&(0,t.jsx)("span",{className:"flex items-center justify-center w-5 h-5 rounded bg-indigo-100 text-indigo-600 text-xs font-bold",children:o}),(0,t.jsx)("span",{children:r.label})]})},maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(f.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})}),showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase())}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1 ml-1",children:s?`Search and select multiple models. Selected models will appear below in order. (${e.fallbackModels.length}/${l} used)`:`Maximum ${l} fallbacks reached. Remove some to add more.`})]}),(0,t.jsx)("div",{className:"space-y-2 min-h-[100px]",children:0===e.fallbackModels.length?(0,t.jsxs)("div",{className:"h-32 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)("span",{className:"text-sm",children:"No fallback models selected"}),(0,t.jsx)("span",{className:"text-xs mt-1",children:"Add models from the dropdown above"})]}):e.fallbackModels.map((a,l)=>(0,t.jsxs)("div",{className:"group flex items-center justify-between p-3 bg-white rounded-lg border border-gray-200 hover:border-indigo-300 hover:shadow-sm transition-all",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex items-center justify-center w-6 h-6 rounded bg-gray-100 text-gray-400 group-hover:text-indigo-500 group-hover:bg-indigo-50",children:(0,t.jsx)("span",{className:"text-xs font-bold",children:l+1})}),(0,t.jsx)("div",{children:(0,t.jsx)("span",{className:"font-medium text-gray-800",children:a})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>{let t;return t=e.fallbackModels.filter((e,t)=>t!==l),void r({...e,fallbackModels:t})},className:"opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500 p-1",children:(0,t.jsx)(b.X,{className:"w-4 h-4"})})]},`${a}-${l}`))})]})]})]})}function v({groups:e,onGroupsChange:r,availableModels:a,maxFallbacks:l=10,maxGroups:o=5}){let[n,s]=(0,p.useState)(e.length>0?e[0].id:"1");(0,p.useEffect)(()=>{e.length>0?e.some(e=>e.id===n)||s(e[0].id):s("1")},[e]);let i=()=>{if(e.length>=o)return;let t=Date.now().toString();r([...e,{id:t,primaryModel:null,fallbackModels:[]}]),s(t)},c=t=>{r(e.map(e=>e.id===t.id?t:e))},f=e.map((r,o)=>{let n=r.primaryModel?r.primaryModel:`Group ${o+1}`;return{key:r.id,label:n,closable:e.length>1,children:(0,t.jsx)(y,{group:r,onChange:c,availableModels:a,maxFallbacks:l})}});return 0===e.length?(0,t.jsxs)("div",{className:"text-center py-12 bg-gray-50 rounded-lg border border-dashed border-gray-300",children:[(0,t.jsx)("p",{className:"text-gray-500 mb-4",children:"No fallback groups configured"}),(0,t.jsx)(d.Button,{variant:"primary",onClick:i,icon:()=>(0,t.jsx)(g.Plus,{className:"w-4 h-4"}),children:"Create First Group"})]}):(0,t.jsx)(m.Tabs,{type:"editable-card",activeKey:n,onChange:s,onEdit:(t,a)=>{"add"===a?i():"remove"===a&&e.length>1&&(t=>{if(1===e.length)return u.message.warning("At least one group is required");let a=e.filter(e=>e.id!==t);r(a),n===t&&a.length>0&&s(a[a.length-1].id)})(t)},items:f,className:"fallback-tabs",tabBarStyle:{marginBottom:0},hideAdd:e.length>=o})}e.s(["FallbackSelectionForm",()=>v],419470)}]); \ No newline at end of file + `]:{[`&:hover ${t}-inner`]:{backgroundColor:e.colorPrimaryHover,borderColor:"transparent"}}},{[t]:{"&-indeterminate":{"&":{[`${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${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 ${t}-inner`]:{backgroundColor:`${e.colorBgContainer}`,borderColor:`${e.colorPrimary}`}}}}},{[`${l}-disabled`]:{cursor:"not-allowed"},[`${t}-disabled`]:{[`&, ${t}-input`]:{cursor:"not-allowed",pointerEvents:"none"},[`${t}-inner`]:{background:e.colorBgContainerDisabled,borderColor:e.colorBorder,"&:after":{borderColor:e.colorTextDisabled}},"&:after":{display:"none"},"& + span":{color:e.colorTextDisabled},[`&${t}-indeterminate ${t}-inner::after`]:{background:e.colorTextDisabled}}}]})((0,o.mergeToken)(t,{checkboxCls:`.${e}`,checkboxSize:t.controlInteractiveSize}))}let s=(0,l.genStyleHooks)("Checkbox",(e,{prefixCls:t})=>[n(t,e)]);e.s(["default",0,s,"getStyle",()=>n],236836)},374276,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(91874),l=e.i(611935),o=e.i(121872),n=e.i(26905),s=e.i(242064),i=e.i(937328),c=e.i(321883),d=e.i(62139),u=e.i(421512),m=e.i(236836),g=e.i(681216),p=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let f=t.forwardRef((e,f)=>{var h;let{prefixCls:x,className:b,rootClassName:y,children:v,indeterminate:w=!1,style:k,onMouseEnter:C,onMouseLeave:j,skipGroup:N=!1,disabled:S}=e,$=p(e,["prefixCls","className","rootClassName","children","indeterminate","style","onMouseEnter","onMouseLeave","skipGroup","disabled"]),{getPrefixCls:M,direction:E,checkbox:O}=t.useContext(s.ConfigContext),T=t.useContext(u.default),{isFormItemInput:P}=t.useContext(d.FormItemInputContext),_=t.useContext(i.default),z=null!=(h=(null==T?void 0:T.disabled)||S)?h:_,R=t.useRef($.value),I=t.useRef(null),L=(0,l.composeRef)(f,I);t.useEffect(()=>{null==T||T.registerValue($.value)},[]),t.useEffect(()=>{if(!N)return $.value!==R.current&&(null==T||T.cancelValue(R.current),null==T||T.registerValue($.value),R.current=$.value),()=>null==T?void 0:T.cancelValue($.value)},[$.value]),t.useEffect(()=>{var e;(null==(e=I.current)?void 0:e.input)&&(I.current.input.indeterminate=w)},[w]);let D=M("checkbox",x),B=(0,c.default)(D),[F,A,q]=(0,m.default)(D,B),H=Object.assign({},$);T&&!N&&(H.onChange=(...e)=>{$.onChange&&$.onChange.apply($,e),T.toggleOption&&T.toggleOption({label:v,value:$.value})},H.name=T.name,H.checked=T.value.includes($.value));let G=(0,r.default)(`${D}-wrapper`,{[`${D}-rtl`]:"rtl"===E,[`${D}-wrapper-checked`]:H.checked,[`${D}-wrapper-disabled`]:z,[`${D}-wrapper-in-form-item`]:P},null==O?void 0:O.className,b,y,q,B,A),X=(0,r.default)({[`${D}-indeterminate`]:w},n.TARGET_CLS,A),[V,K]=(0,g.default)(H.onClick);return F(t.createElement(o.default,{component:"Checkbox",disabled:z},t.createElement("label",{className:G,style:Object.assign(Object.assign({},null==O?void 0:O.style),k),onMouseEnter:C,onMouseLeave:j,onClick:V},t.createElement(a.default,Object.assign({},H,{onClick:K,prefixCls:D,className:X,disabled:z,ref:L})),null!=v&&t.createElement("span",{className:`${D}-label`},v))))});var h=e.i(8211),x=e.i(529681),b=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var l=0,a=Object.getOwnPropertySymbols(e);lt.indexOf(a[l])&&Object.prototype.propertyIsEnumerable.call(e,a[l])&&(r[a[l]]=e[a[l]]);return r};let y=t.forwardRef((e,a)=>{let{defaultValue:l,children:o,options:n=[],prefixCls:i,className:d,rootClassName:g,style:p,onChange:y}=e,v=b(e,["defaultValue","children","options","prefixCls","className","rootClassName","style","onChange"]),{getPrefixCls:w,direction:k}=t.useContext(s.ConfigContext),[C,j]=t.useState(v.value||l||[]),[N,S]=t.useState([]);t.useEffect(()=>{"value"in v&&j(v.value||[])},[v.value]);let $=t.useMemo(()=>n.map(e=>"string"==typeof e||"number"==typeof e?{label:e,value:e}:e),[n]),M=e=>{S(t=>t.filter(t=>t!==e))},E=e=>{S(t=>[].concat((0,h.default)(t),[e]))},O=e=>{let t=C.indexOf(e.value),r=(0,h.default)(C);-1===t?r.push(e.value):r.splice(t,1),"value"in v||j(r),null==y||y(r.filter(e=>N.includes(e)).sort((e,t)=>$.findIndex(t=>t.value===e)-$.findIndex(e=>e.value===t)))},T=w("checkbox",i),P=`${T}-group`,_=(0,c.default)(T),[z,R,I]=(0,m.default)(T,_),L=(0,x.default)(v,["value","disabled"]),D=n.length?$.map(e=>t.createElement(f,{prefixCls:T,key:e.value.toString(),disabled:"disabled"in e?e.disabled:v.disabled,value:e.value,checked:C.includes(e.value),onChange:e.onChange,className:(0,r.default)(`${P}-item`,e.className),style:e.style,title:e.title,id:e.id,required:e.required},e.label)):o,B=t.useMemo(()=>({toggleOption:O,value:C,disabled:v.disabled,name:v.name,registerValue:E,cancelValue:M}),[O,C,v.disabled,v.name,E,M]),F=(0,r.default)(P,{[`${P}-rtl`]:"rtl"===k},d,g,I,_,R);return z(t.createElement("div",Object.assign({className:F,style:p},L,{ref:a}),t.createElement(u.default.Provider,{value:B},D)))});f.Group=y,f.__ANT_CHECKBOX=!0,e.s(["default",0,f],374276)},536916,e=>{"use strict";var t=e.i(374276);e.s(["Checkbox",()=>t.default])},292639,e=>{"use strict";var t=e.i(764205),r=e.i(266027);let a=(0,e.i(243652).createQueryKeys)("uiSettings");e.s(["useUISettings",0,()=>(0,r.useQuery)({queryKey:a.list({}),queryFn:async()=>await (0,t.getUiSettings)(),staleTime:36e5,gcTime:36e5})])},250980,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlusCircleIcon",0,r],250980)},502547,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 5l7 7-7 7"}))});e.s(["ChevronRightIcon",0,r],502547)},988297,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"}))});e.s(["PlusIcon",0,r],988297)},797672,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"}))});e.s(["PencilIcon",0,r],797672)},992619,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(779241),l=e.i(599724),o=e.i(199133),n=e.i(983561),s=e.i(689020);e.s(["default",0,({accessToken:e,value:i,placeholder:c="Select a Model",onChange:d,disabled:u=!1,style:m,className:g,showLabel:p=!0,labelText:f="Select Model"})=>{let[h,x]=(0,r.useState)(i),[b,y]=(0,r.useState)(!1),[v,w]=(0,r.useState)([]),k=(0,r.useRef)(null);return(0,r.useEffect)(()=>{x(i)},[i]),(0,r.useEffect)(()=>{e&&(async()=>{try{let t=await (0,s.fetchAvailableModels)(e);console.log("Fetched models for selector:",t),t.length>0&&w(t)}catch(e){console.error("Error fetching model info:",e)}})()},[e]),(0,t.jsxs)("div",{children:[p&&(0,t.jsxs)(l.Text,{className:"font-medium block mb-2 text-gray-700 flex items-center",children:[(0,t.jsx)(n.RobotOutlined,{className:"mr-2"})," ",f]}),(0,t.jsx)(o.Select,{value:h,placeholder:c,onChange:e=>{"custom"===e?(y(!0),x(void 0)):(y(!1),x(e),d&&d(e))},options:[...Array.from(new Set(v.map(e=>e.model_group))).map((e,t)=>({value:e,label:e,key:t})),{value:"custom",label:"Enter custom model",key:"custom"}],style:{width:"100%",...m},showSearch:!0,className:`rounded-md ${g||""}`,disabled:u}),b&&(0,t.jsx)(a.TextInput,{className:"mt-2",placeholder:"Enter custom model name",onValueChange:e=>{k.current&&clearTimeout(k.current),k.current=setTimeout(()=>{x(e),d&&d(e)},500)},disabled:u})]})}])},409797,e=>{"use strict";var t=e.i(631171);e.s(["ChevronDownIcon",()=>t.default])},91739,e=>{"use strict";var t=e.i(544195);e.s(["Radio",()=>t.default])},500727,696609,531516,e=>{"use strict";var t=e.i(266027),r=e.i(243652),a=e.i(764205),l=e.i(135214);let o=(0,r.createQueryKeys)("mcpServers");e.s(["useMCPServers",0,e=>{let{accessToken:r}=(0,l.default)();return(0,t.useQuery)({queryKey:o.list(e?{filters:{teamId:e}}:void 0),queryFn:async()=>await (0,a.fetchMCPServers)(r,e),enabled:!!r})}],500727);var n=e.i(843476),s=e.i(271645),i=e.i(536916),c=e.i(599724),d=e.i(409797),u=e.i(246349),u=u;let m=/\b(delete|remove|destroy|purge|drop|erase|unlink)\b/i,g=/\b(create|add|insert|new|post|submit|register|make|generate|write|upload)\b/i,p=/\b(update|edit|modify|change|patch|put|set|rename|move|transform)\b/i,f=/\b(get|read|list|fetch|search|find|query|retrieve|show|view|check|describe|info)\b/i;function h(e,t=""){let r=e.toLowerCase();if(f.test(r))return"read";if(m.test(r))return"delete";if(p.test(r))return"update";if(g.test(r))return"create";if(t){let e=t.toLowerCase();if(f.test(e))return"read";if(m.test(e))return"delete";if(p.test(e))return"update";if(g.test(e))return"create"}return"unknown"}function x(e){let t={read:[],create:[],update:[],delete:[],unknown:[]};for(let r of e)t[h(r.name,r.description)].push(r);return t}let b={read:{label:"Read",description:"Safe operations — fetch, list, search. No side effects.",risk:"low"},create:{label:"Create",description:"Add new resources — insert, upload, register.",risk:"medium"},update:{label:"Update",description:"Modify existing resources — edit, patch, rename.",risk:"medium"},delete:{label:"Delete",description:"Destructive operations — remove, purge, destroy.",risk:"high"},unknown:{label:"Other",description:"Operations that could not be automatically classified.",risk:"unknown"}};e.s(["CRUD_GROUP_META",0,b,"classifyToolOp",()=>h,"groupToolsByCrud",()=>x],696609);let y=["read","create","update","delete","unknown"],v={low:"bg-green-100 text-green-800",medium:"bg-yellow-100 text-yellow-800",high:"bg-red-100 text-red-800 font-semibold",unknown:"bg-gray-100 text-gray-700"},w={read:"border-green-200",create:"border-blue-200",update:"border-yellow-200",delete:"border-red-300",unknown:"border-gray-200"},k={read:"bg-green-50",create:"bg-blue-50",update:"bg-yellow-50",delete:"bg-red-50",unknown:"bg-gray-50"};e.s(["default",0,({tools:e,value:t,onChange:r,readOnly:a=!1,searchFilter:l=""})=>{let[o,m]=(0,s.useState)({read:!1,create:!1,update:!1,delete:!1,unknown:!0}),g=(0,s.useMemo)(()=>x(e),[e]),p=(0,s.useMemo)(()=>new Set(void 0===t?e.map(e=>e.name):t),[t,e]),f=e=>{if(a)return;let t=new Set(p);t.has(e)?t.delete(e):t.add(e),r(Array.from(t))};return 0===e.length?null:(0,n.jsx)("div",{className:"space-y-3",children:y.map(e=>{let t,s=g[e];if(0===s.length)return null;if(l){let e=l.toLowerCase();if(!s.some(t=>t.name.toLowerCase().includes(e)||(t.description??"").toLowerCase().includes(e)))return null}let h=b[e],x=(t=g[e]).length>0&&t.every(e=>p.has(e.name)),y=(e=>{let t=g[e];if(0===t.length)return!1;let r=t.filter(e=>p.has(e.name)).length;return r>0&&r{m(t=>({...t,[e]:!t[e]}))},children:[C?(0,n.jsx)(u.default,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}):(0,n.jsx)(d.ChevronDownIcon,{className:"w-4 h-4 text-gray-500 flex-shrink-0"}),(0,n.jsx)("span",{className:"font-semibold text-gray-900 text-sm",children:h.label}),(0,n.jsx)("span",{className:`text-xs px-2 py-0.5 rounded-full ${v[h.risk]}`,children:"high"===h.risk?"High Risk":"medium"===h.risk?"Medium Risk":"low"===h.risk?"Safe":"Unclassified"}),(0,n.jsxs)("span",{className:"text-xs text-gray-500 ml-1",children:[s.filter(e=>p.has(e.name)).length,"/",s.length," allowed"]})]}),!a&&(0,n.jsxs)("div",{className:"flex items-center gap-2 ml-4",children:[(0,n.jsx)(c.Text,{className:"text-xs text-gray-500",children:x?"All on":y?"Partial":"All off"}),(0,n.jsx)(i.Checkbox,{checked:x,indeterminate:y,onChange:t=>((e,t)=>{if(a)return;let l=new Set(p);for(let r of g[e])t?l.add(r.name):l.delete(r.name);r(Array.from(l))})(e,t.target.checked),onClick:e=>e.stopPropagation()})]})]}),!C&&(0,n.jsx)("div",{className:"px-4 pt-2 pb-1 text-xs text-gray-500 bg-white border-b border-gray-100",children:h.description}),!C&&(0,n.jsx)("div",{className:"bg-white divide-y divide-gray-50",children:s.filter(e=>!l||e.name.toLowerCase().includes(l.toLowerCase())||(e.description??"").toLowerCase().includes(l.toLowerCase())).map(e=>{let t,r=(t=e.name,p.has(t));return(0,n.jsxs)("div",{className:`flex items-start gap-3 px-4 py-2.5 transition-colors hover:bg-gray-50 ${!a?"cursor-pointer":""} ${r?"":"opacity-60"}`,onClick:()=>f(e.name),children:[(0,n.jsx)(i.Checkbox,{checked:r,onChange:()=>f(e.name),disabled:a,onClick:e=>e.stopPropagation()}),(0,n.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,n.jsx)(c.Text,{className:"font-medium text-gray-900 text-sm",children:e.name}),e.description&&(0,n.jsx)(c.Text,{className:"text-xs text-gray-500 mt-0.5 leading-snug",children:e.description})]}),(0,n.jsx)("span",{className:`text-xs px-1.5 py-0.5 rounded flex-shrink-0 ${r?"bg-green-100 text-green-700":"bg-gray-100 text-gray-500"}`,children:r?"on":"off"})]},e.name)})})]},e)})})}],531516)},361653,e=>{"use strict";let t=(0,e.i(475254).default)("circle-alert",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);e.s(["default",()=>t])},603908,e=>{"use strict";let t=(0,e.i(475254).default)("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);e.s(["default",()=>t])},841947,e=>{"use strict";let t=(0,e.i(475254).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["default",()=>t])},793130,e=>{"use strict";var t=e.i(290571),r=e.i(429427),a=e.i(371330),l=e.i(271645),o=e.i(394487),n=e.i(503269),s=e.i(214520),i=e.i(746725),c=e.i(914189),d=e.i(144279),u=e.i(294316),m=e.i(601893),g=e.i(140721),p=e.i(942803),f=e.i(233538),h=e.i(694421),x=e.i(700020),b=e.i(35889),y=e.i(998348),v=e.i(722678);let w=(0,l.createContext)(null);w.displayName="GroupContext";let k=l.Fragment,C=Object.assign((0,x.forwardRefWithAs)(function(e,t){var k;let C=(0,l.useId)(),j=(0,p.useProvidedId)(),N=(0,m.useDisabled)(),{id:S=j||`headlessui-switch-${C}`,disabled:$=N||!1,checked:M,defaultChecked:E,onChange:O,name:T,value:P,form:_,autoFocus:z=!1,...R}=e,I=(0,l.useContext)(w),[L,D]=(0,l.useState)(null),B=(0,l.useRef)(null),F=(0,u.useSyncRefs)(B,t,null===I?null:I.setSwitch,D),A=(0,s.useDefaultValue)(E),[q,H]=(0,n.useControllable)(M,O,null!=A&&A),G=(0,i.useDisposables)(),[X,V]=(0,l.useState)(!1),K=(0,c.useEvent)(()=>{V(!0),null==H||H(!q),G.nextFrame(()=>{V(!1)})}),W=(0,c.useEvent)(e=>{if((0,f.isDisabledReactIssue7711)(e.currentTarget))return e.preventDefault();e.preventDefault(),K()}),U=(0,c.useEvent)(e=>{e.key===y.Keys.Space?(e.preventDefault(),K()):e.key===y.Keys.Enter&&(0,h.attemptSubmit)(e.currentTarget)}),Y=(0,c.useEvent)(e=>e.preventDefault()),Q=(0,v.useLabelledBy)(),J=(0,b.useDescribedBy)(),{isFocusVisible:Z,focusProps:ee}=(0,r.useFocusRing)({autoFocus:z}),{isHovered:et,hoverProps:er}=(0,a.useHover)({isDisabled:$}),{pressed:ea,pressProps:el}=(0,o.useActivePress)({disabled:$}),eo=(0,l.useMemo)(()=>({checked:q,disabled:$,hover:et,focus:Z,active:ea,autofocus:z,changing:X}),[q,et,Z,ea,$,X,z]),en=(0,x.mergeProps)({id:S,ref:F,role:"switch",type:(0,d.useResolveButtonType)(e,L),tabIndex:-1===e.tabIndex?0:null!=(k=e.tabIndex)?k:0,"aria-checked":q,"aria-labelledby":Q,"aria-describedby":J,disabled:$||void 0,autoFocus:z,onClick:W,onKeyUp:U,onKeyPress:Y},ee,er,el),es=(0,l.useCallback)(()=>{if(void 0!==A)return null==H?void 0:H(A)},[H,A]),ei=(0,x.useRender)();return l.default.createElement(l.default.Fragment,null,null!=T&&l.default.createElement(g.FormFields,{disabled:$,data:{[T]:P||"on"},overrides:{type:"checkbox",checked:q},form:_,onReset:es}),ei({ourProps:en,theirProps:R,slot:eo,defaultTag:"button",name:"Switch"}))}),{Group:function(e){var t;let[r,a]=(0,l.useState)(null),[o,n]=(0,v.useLabels)(),[s,i]=(0,b.useDescriptions)(),c=(0,l.useMemo)(()=>({switch:r,setSwitch:a}),[r,a]),d=(0,x.useRender)();return l.default.createElement(i,{name:"Switch.Description",value:s},l.default.createElement(n,{name:"Switch.Label",value:o,props:{htmlFor:null==(t=c.switch)?void 0:t.id,onClick(e){r&&(e.currentTarget instanceof HTMLLabelElement&&e.preventDefault(),r.click(),r.focus({preventScroll:!0}))}}},l.default.createElement(w.Provider,{value:c},d({ourProps:{},theirProps:e,slot:{},defaultTag:k,name:"Switch.Group"}))))},Label:v.Label,Description:b.Description});var j=e.i(888288),N=e.i(95779),S=e.i(444755),$=e.i(673706),M=e.i(829087);let E=(0,$.makeClassName)("Switch"),O=l.default.forwardRef((e,r)=>{let{checked:a,defaultChecked:o=!1,onChange:n,color:s,name:i,error:c,errorMessage:d,disabled:u,required:m,tooltip:g,id:p}=e,f=(0,t.__rest)(e,["checked","defaultChecked","onChange","color","name","error","errorMessage","disabled","required","tooltip","id"]),h={bgColor:s?(0,$.getColorClassNames)(s,N.colorPalette.background).bgColor:"bg-tremor-brand dark:bg-dark-tremor-brand",ringColor:s?(0,$.getColorClassNames)(s,N.colorPalette.ring).ringColor:"ring-tremor-brand-muted dark:ring-dark-tremor-brand-muted"},[x,b]=(0,j.default)(o,a),[y,v]=(0,l.useState)(!1),{tooltipProps:w,getReferenceProps:k}=(0,M.useTooltip)(300);return l.default.createElement("div",{className:"flex flex-row items-center justify-start"},l.default.createElement(M.default,Object.assign({text:g},w)),l.default.createElement("div",Object.assign({ref:(0,$.mergeRefs)([r,w.refs.setReference]),className:(0,S.tremorTwMerge)(E("root"),"flex flex-row relative h-5")},f,k),l.default.createElement("input",{type:"checkbox",className:(0,S.tremorTwMerge)(E("input"),"absolute w-5 h-5 cursor-pointer left-0 top-0 opacity-0"),name:i,required:m,checked:x,onChange:e=>{e.preventDefault()}}),l.default.createElement(C,{checked:x,onChange:e=>{b(e),null==n||n(e)},disabled:u,className:(0,S.tremorTwMerge)(E("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:()=>v(!0),onBlur:()=>v(!1),id:p},l.default.createElement("span",{className:(0,S.tremorTwMerge)(E("sr-only"),"sr-only")},"Switch ",x?"on":"off"),l.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("background"),x?h.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.default.createElement("span",{"aria-hidden":"true",className:(0,S.tremorTwMerge)(E("round"),x?(0,S.tremorTwMerge)(h.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",y?(0,S.tremorTwMerge)("ring-2",h.ringColor):"")}))),c&&d?l.default.createElement("p",{className:(0,S.tremorTwMerge)(E("errorMessage"),"text-sm text-red-500 mt-1 ")},d):null)});O.displayName="Switch",e.s(["Switch",()=>O],793130)},158392,419470,e=>{"use strict";var t=e.i(843476),r=e.i(779241);let a={ttl:3600,lowest_latency_buffer:0},l=({routingStrategyArgs:e})=>{let l={ttl:"Sliding window to look back over when calculating the average latency of a deployment. Default - 1 hour (in seconds).",lowest_latency_buffer:"Shuffle between deployments within this % of the lowest latency. Default - 0 (i.e. always pick lowest latency)."};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Latency-Based Configuration"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Fine-tune latency-based routing behavior"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e||a).map(([e,a])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:e.replace(/_/g," ")}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l[e]||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:"object"==typeof a?JSON.stringify(a,null,2):a?.toString(),className:"font-mono text-sm w-full"})]})},e))})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"})]})},o=({routerSettings:e,routerFieldsMetadata:a})=>(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Reliability & Retries"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure retry logic and failure handling"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3",children:Object.entries(e).filter(([e,t])=>"fallbacks"!=e&&"context_window_fallbacks"!=e&&"routing_strategy_args"!=e&&"routing_strategy"!=e&&"enable_tag_filtering"!=e).map(([e,l])=>(0,t.jsx)("div",{className:"space-y-2",children:(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:a[e]?.ui_field_name||e}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:a[e]?.field_description||""}),(0,t.jsx)(r.TextInput,{name:e,defaultValue:null==l||"null"===l?"":"object"==typeof l?JSON.stringify(l,null,2):l?.toString()||"",placeholder:"—",className:"font-mono text-sm w-full"})]})},e))})]});var n=e.i(199133);let s=({selectedStrategy:e,availableStrategies:r,routingStrategyDescriptions:a,routerFieldsMetadata:l,onStrategyChange:o})=>(0,t.jsxs)("div",{className:"space-y-2 max-w-3xl",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:l.routing_strategy?.ui_field_name||"Routing Strategy"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 mb-2",children:l.routing_strategy?.field_description||""})]}),(0,t.jsx)("div",{className:"routing-strategy-select max-w-3xl",children:(0,t.jsx)(n.Select,{value:e,onChange:o,style:{width:"100%"},size:"large",children:r.map(e=>(0,t.jsx)(n.Select.Option,{value:e,label:e,children:(0,t.jsxs)("div",{className:"flex flex-col gap-0.5 py-1",children:[(0,t.jsx)("span",{className:"font-mono text-sm font-medium",children:e}),a[e]&&(0,t.jsx)("span",{className:"text-xs text-gray-500 font-normal",children:a[e]})]})},e))})})]});var i=e.i(793130);let c=({enabled:e,routerFieldsMetadata:r,onToggle:a})=>(0,t.jsx)("div",{className:"space-y-3 max-w-3xl",children:(0,t.jsxs)("div",{className:"flex items-start justify-between",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)("label",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:r.enable_tag_filtering?.ui_field_name||"Enable Tag Filtering"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500 mt-0.5",children:[r.enable_tag_filtering?.field_description||"",r.enable_tag_filtering?.link&&(0,t.jsxs)(t.Fragment,{children:[" ",(0,t.jsx)("a",{href:r.enable_tag_filtering.link,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline",children:"Learn more"})]})]})]}),(0,t.jsx)(i.Switch,{checked:e,onChange:a,className:"ml-4"})]})});e.s(["default",0,({value:e,onChange:r,routerFieldsMetadata:a,availableRoutingStrategies:n,routingStrategyDescriptions:i})=>(0,t.jsxs)("div",{className:"w-full space-y-8 py-2",children:[(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"max-w-3xl",children:[(0,t.jsx)("h3",{className:"text-sm font-medium text-gray-900",children:"Routing Settings"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1",children:"Configure how requests are routed to deployments"})]}),n.length>0&&(0,t.jsx)(s,{selectedStrategy:e.selectedStrategy||e.routerSettings.routing_strategy||null,availableStrategies:n,routingStrategyDescriptions:i,routerFieldsMetadata:a,onStrategyChange:t=>{r({...e,selectedStrategy:t})}}),(0,t.jsx)(c,{enabled:e.enableTagFiltering,routerFieldsMetadata:a,onToggle:t=>{r({...e,enableTagFiltering:t})}})]}),(0,t.jsx)("div",{className:"border-t border-gray-200"}),"latency-based-routing"===e.selectedStrategy&&(0,t.jsx)(l,{routingStrategyArgs:e.routerSettings.routing_strategy_args}),(0,t.jsx)(o,{routerSettings:e.routerSettings,routerFieldsMetadata:a})]})],158392);var d=e.i(994388),u=e.i(998573),m=e.i(653496),g=e.i(107233),p=e.i(271645),f=e.i(592968),h=e.i(361653),h=h;let x=(0,e.i(475254).default)("arrow-down",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var b=e.i(37727);function y({group:e,onChange:r,availableModels:a,maxFallbacks:l}){let o=a.filter(t=>t!==e.primaryModel),s=e.fallbackModels.length{let a=[...e.fallbackModels];a.includes(t)&&(a=a.filter(e=>e!==t)),r({...e,primaryModel:t,fallbackModels:a})},showSearch:!0,getPopupContainer:e=>e.parentElement||document.body,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase()),options:a.map(e=>({label:e,value:e}))}),!e.primaryModel&&(0,t.jsxs)("div",{className:"mt-2 flex items-center gap-2 text-amber-600 text-xs bg-amber-50 p-2 rounded",children:[(0,t.jsx)(h.default,{className:"w-4 h-4"}),(0,t.jsx)("span",{children:"Select a model to begin configuring fallbacks"})]})]}),(0,t.jsx)("div",{className:"flex items-center justify-center -my-4 z-10",children:(0,t.jsxs)("div",{className:"bg-indigo-50 text-indigo-500 px-4 py-1 rounded-full text-xs font-bold border border-indigo-100 flex items-center gap-2 shadow-sm",children:[(0,t.jsx)(x,{className:"w-4 h-4"}),"IF FAILS, TRY..."]})}),(0,t.jsxs)("div",{className:`transition-opacity duration-300 ${!e.primaryModel?"opacity-50 pointer-events-none":"opacity-100"}`,children:[(0,t.jsxs)("label",{className:"block text-sm font-semibold text-gray-700 mb-2",children:["Fallback Chain ",(0,t.jsx)("span",{className:"text-red-500",children:"*"}),(0,t.jsxs)("span",{className:"text-xs text-gray-500 font-normal ml-2",children:["(Max ",l," fallbacks at a time)"]})]}),(0,t.jsxs)("div",{className:"bg-gray-50 rounded-xl p-4 border border-gray-200",children:[(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)(n.Select,{mode:"multiple",className:"w-full",size:"large",placeholder:s?"Select fallback models to add...":`Maximum ${l} fallbacks reached`,value:e.fallbackModels,onChange:t=>{let a=t.slice(0,l);r({...e,fallbackModels:a})},disabled:!e.primaryModel,getPopupContainer:e=>e.parentElement||document.body,options:o.map(e=>({label:e,value:e})),optionRender:(r,a)=>{let l=e.fallbackModels.includes(r.value),o=l?e.fallbackModels.indexOf(r.value)+1:null;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[l&&null!==o&&(0,t.jsx)("span",{className:"flex items-center justify-center w-5 h-5 rounded bg-indigo-100 text-indigo-600 text-xs font-bold",children:o}),(0,t.jsx)("span",{children:r.label})]})},maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(f.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})}),showSearch:!0,filterOption:(e,t)=>(t?.label??"").toLowerCase().includes(e.toLowerCase())}),(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-1 ml-1",children:s?`Search and select multiple models. Selected models will appear below in order. (${e.fallbackModels.length}/${l} used)`:`Maximum ${l} fallbacks reached. Remove some to add more.`})]}),(0,t.jsx)("div",{className:"space-y-2 min-h-[100px]",children:0===e.fallbackModels.length?(0,t.jsxs)("div",{className:"h-32 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)("span",{className:"text-sm",children:"No fallback models selected"}),(0,t.jsx)("span",{className:"text-xs mt-1",children:"Add models from the dropdown above"})]}):e.fallbackModels.map((a,l)=>(0,t.jsxs)("div",{className:"group flex items-center justify-between p-3 bg-white rounded-lg border border-gray-200 hover:border-indigo-300 hover:shadow-sm transition-all",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"flex items-center justify-center w-6 h-6 rounded bg-gray-100 text-gray-400 group-hover:text-indigo-500 group-hover:bg-indigo-50",children:(0,t.jsx)("span",{className:"text-xs font-bold",children:l+1})}),(0,t.jsx)("div",{children:(0,t.jsx)("span",{className:"font-medium text-gray-800",children:a})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>{let t;return t=e.fallbackModels.filter((e,t)=>t!==l),void r({...e,fallbackModels:t})},className:"opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500 p-1",children:(0,t.jsx)(b.X,{className:"w-4 h-4"})})]},`${a}-${l}`))})]})]})]})}function v({groups:e,onGroupsChange:r,availableModels:a,maxFallbacks:l=10,maxGroups:o=5}){let[n,s]=(0,p.useState)(e.length>0?e[0].id:"1");(0,p.useEffect)(()=>{e.length>0?e.some(e=>e.id===n)||s(e[0].id):s("1")},[e]);let i=()=>{if(e.length>=o)return;let t=Date.now().toString();r([...e,{id:t,primaryModel:null,fallbackModels:[]}]),s(t)},c=t=>{r(e.map(e=>e.id===t.id?t:e))},f=e.map((r,o)=>{let n=r.primaryModel?r.primaryModel:`Group ${o+1}`;return{key:r.id,label:n,closable:e.length>1,children:(0,t.jsx)(y,{group:r,onChange:c,availableModels:a,maxFallbacks:l})}});return 0===e.length?(0,t.jsxs)("div",{className:"text-center py-12 bg-gray-50 rounded-lg border border-dashed border-gray-300",children:[(0,t.jsx)("p",{className:"text-gray-500 mb-4",children:"No fallback groups configured"}),(0,t.jsx)(d.Button,{variant:"primary",onClick:i,icon:()=>(0,t.jsx)(g.Plus,{className:"w-4 h-4"}),children:"Create First Group"})]}):(0,t.jsx)(m.Tabs,{type:"editable-card",activeKey:n,onChange:s,onEdit:(t,a)=>{"add"===a?i():"remove"===a&&e.length>1&&(t=>{if(1===e.length)return u.message.warning("At least one group is required");let a=e.filter(e=>e.id!==t);r(a),n===t&&a.length>0&&s(a[a.length-1].id)})(t)},items:f,className:"fallback-tabs",tabBarStyle:{marginBottom:0},hideAdd:e.length>=o})}e.s(["FallbackSelectionForm",()=>v],419470)}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/531dc633eecbb64f.js b/litellm/proxy/_experimental/out/_next/static/chunks/7174130ddef406dd.js similarity index 58% rename from litellm/proxy/_experimental/out/_next/static/chunks/531dc633eecbb64f.js rename to litellm/proxy/_experimental/out/_next/static/chunks/7174130ddef406dd.js index 8ed318457c..21cdd1b50a 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/531dc633eecbb64f.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/7174130ddef406dd.js @@ -1,8 +1,8 @@ -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,162386,e=>{"use strict";var t=e.i(843476),l=e.i(625901),a=e.i(109799),r=e.i(785242),i=e.i(738014),s=e.i(199133),n=e.i(981339),o=e.i(592968);let d={label:"All Proxy Models",value:"all-proxy-models"},c={label:"No Default Models",value:"no-default-models"},u=[d,c],m={user:({allProxyModels:e,userModels:t,options:l})=>t&&l?.includeUserModels?t:[],team:({allProxyModels:e,selectedOrganization:t,userModels:l})=>t?t.models.includes(d.value)||0===t.models.length?e:e.filter(e=>t.models.includes(e)):e??[],organization:({allProxyModels:e})=>e,global:({allProxyModels:e})=>e};e.s(["ModelSelect",0,e=>{let{teamID:h,organizationID:g,options:f,context:p,dataTestId:b,value:v=[],onChange:x,style:y}=e,{includeUserModels:j,showAllTeamModelsOption:w,showAllProxyModelsOverride:k,includeSpecialOptions:C}=f||{},{data:O,isLoading:$}=(0,l.useAllProxyModels)(),{data:N,isLoading:E}=(0,r.useTeam)(h),{data:T,isLoading:_}=(0,a.useOrganization)(g),{data:M,isLoading:I}=(0,i.useCurrentUser)(),S=e=>u.some(t=>t.value===e),R=v.some(S),P=T?.models.includes(d.value)||T?.models.length===0;if($||E||_||I)return(0,t.jsx)(n.Skeleton.Input,{active:!0,block:!0});let{wildcard:q,regular:A}=(e=>{let t=[],l=[];for(let a of e)a.endsWith("/*")?t.push(a):l.push(a);return{wildcard:t,regular:l}})(((e,t,l)=>{let a=Array.from(new Map(e.map(e=>[e.id,e])).values()).map(e=>e.id);if(t.options?.showAllProxyModelsOverride)return a;let r=m[t.context];return r?r({allProxyModels:a,...l,options:t.options}):[]})(O?.data??[],e,{selectedTeam:N,selectedOrganization:T,userModels:M?.models}));return(0,t.jsx)(s.Select,{"data-testid":b,value:v,onChange:e=>{let t=e.filter(S);x(t.length>0?[t[t.length-1]]:e)},style:y,options:[C?{label:(0,t.jsx)("span",{children:"Special Options"}),title:"Special Options",options:[...k||P&&C||"global"===p?[{label:(0,t.jsx)("span",{children:"All Proxy Models"}),value:d.value,disabled:v.length>0&&v.some(e=>S(e)&&e!==d.value),key:d.value}]:[],{label:(0,t.jsx)("span",{children:"No Default Models"}),value:c.value,disabled:v.length>0&&v.some(e=>S(e)&&e!==c.value),key:c.value}]}:[],...q.length>0?[{label:(0,t.jsx)("span",{children:"Wildcard Options"}),title:"Wildcard Options",options:q.map(e=>{let l=e.replace("/*",""),a=l.charAt(0).toUpperCase()+l.slice(1);return{label:(0,t.jsx)("span",{children:`All ${a} models`}),value:e,disabled:R}})}]:[],{label:(0,t.jsx)("span",{children:"Models"}),title:"Models",options:A.map(e=>({label:(0,t.jsx)("span",{children:e}),value:e,disabled:R}))}],mode:"multiple",placeholder:"Select Models",allowClear:!0,maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(o.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})})})}],162386)},294612,e=>{"use strict";var t=e.i(843476),l=e.i(100486),a=e.i(827252),r=e.i(213205),i=e.i(771674),s=e.i(464571),n=e.i(770914),o=e.i(291542),d=e.i(262218),c=e.i(592968),u=e.i(898586),m=e.i(902555);let{Text:h}=u.Typography;function g({members:e,canEdit:u,onEdit:g,onDelete:f,onAddMember:p,roleColumnTitle:b="Role",roleTooltip:v,extraColumns:x=[],showDeleteForMember:y,emptyText:j}){let w=[{title:"User Email",dataIndex:"user_email",key:"user_email",render:e=>(0,t.jsx)(h,{children:e||"-"})},{title:"User ID",dataIndex:"user_id",key:"user_id",render:e=>"default_user_id"===e?(0,t.jsx)(d.Tag,{color:"blue",children:"Default Proxy Admin"}):(0,t.jsx)(h,{children:e||"-"})},{title:v?(0,t.jsxs)(n.Space,{direction:"horizontal",children:[b,(0,t.jsx)(c.Tooltip,{title:v,children:(0,t.jsx)(a.InfoCircleOutlined,{})})]}):b,dataIndex:"role",key:"role",render:e=>(0,t.jsxs)(n.Space,{children:[e?.toLowerCase()==="admin"||e?.toLowerCase()==="org_admin"?(0,t.jsx)(l.CrownOutlined,{}):(0,t.jsx)(i.UserOutlined,{}),(0,t.jsx)(h,{style:{textTransform:"capitalize"},children:e||"-"})]})},...x,{title:"Actions",key:"actions",fixed:"right",width:120,render:(e,l)=>u?(0,t.jsxs)(n.Space,{children:[(0,t.jsx)(m.default,{variant:"Edit",tooltipText:"Edit member",dataTestId:"edit-member",onClick:()=>g(l)}),(!y||y(l))&&(0,t.jsx)(m.default,{variant:"Delete",tooltipText:"Delete member",dataTestId:"delete-member",onClick:()=>f(l)})]}):null}];return(0,t.jsxs)(n.Space,{direction:"vertical",style:{width:"100%"},children:[(0,t.jsxs)("span",{className:"inline-flex text-sm text-gray-700",children:[e.length," Member",1!==e.length?"s":""]}),(0,t.jsx)(o.Table,{columns:w,dataSource:e,rowKey:e=>e.user_id??e.user_email??JSON.stringify(e),pagination:!1,size:"small",scroll:{x:"max-content"},locale:j?{emptyText:j}:void 0}),p&&u&&(0,t.jsx)(s.Button,{icon:(0,t.jsx)(r.UserAddOutlined,{}),type:"primary",onClick:p,children:"Add Member"})]})}e.s(["default",()=>g])},907308,e=>{"use strict";var t=e.i(843476),l=e.i(271645),a=e.i(212931),r=e.i(808613),i=e.i(464571),s=e.i(199133),n=e.i(592968),o=e.i(213205),d=e.i(374009),c=e.i(764205);e.s(["default",0,({isVisible:e,onCancel:u,onSubmit:m,accessToken:h,title:g="Add Team Member",roles:f=[{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",teamId:b})=>{let[v]=r.Form.useForm(),[x,y]=(0,l.useState)([]),[j,w]=(0,l.useState)(!1),[k,C]=(0,l.useState)("user_email"),[O,$]=(0,l.useState)(!1),N=async(e,t)=>{if(!e)return void y([]);w(!0);try{let l=new URLSearchParams;if(l.append(t,e),b&&l.append("team_id",b),null==h)return;let a=(await (0,c.userFilterUICall)(h,l)).map(e=>({label:"user_email"===t?`${e.user_email}`:`${e.user_id}`,value:"user_email"===t?e.user_email:e.user_id,user:e}));y(a)}catch(e){console.error("Error fetching users:",e)}finally{w(!1)}},E=(0,l.useCallback)((0,d.default)((e,t)=>N(e,t),300),[]),T=(e,t)=>{C(t),E(e,t)},_=(e,t)=>{let l=t.user;v.setFieldsValue({user_email:l.user_email,user_id:l.user_id,role:v.getFieldValue("role")})},M=async e=>{$(!0);try{await m(e)}finally{$(!1)}};return(0,t.jsx)(a.Modal,{title:g,open:e,onCancel:()=>{v.resetFields(),y([]),u()},footer:null,width:800,maskClosable:!O,children:(0,t.jsxs)(r.Form,{form:v,onFinish:M,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",initialValues:{role:p},children:[(0,t.jsx)(r.Form.Item,{label:"Email",name:"user_email",className:"mb-4",children:(0,t.jsx)(s.Select,{showSearch:!0,className:"w-full",placeholder:"Search by email",filterOption:!1,onSearch:e=>T(e,"user_email"),onSelect:(e,t)=>_(e,t),options:"user_email"===k?x:[],loading:j,allowClear:!0})}),(0,t.jsx)("div",{className:"text-center mb-4",children:"OR"}),(0,t.jsx)(r.Form.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,t.jsx)(s.Select,{showSearch:!0,className:"w-full",placeholder:"Search by user ID",filterOption:!1,onSearch:e=>T(e,"user_id"),onSelect:(e,t)=>_(e,t),options:"user_id"===k?x:[],loading:j,allowClear:!0})}),(0,t.jsx)(r.Form.Item,{label:"Member Role",name:"role",className:"mb-4",children:(0,t.jsx)(s.Select,{defaultValue:p,children:f.map(e=>(0,t.jsx)(s.Select.Option,{value:e.value,children:(0,t.jsxs)(n.Tooltip,{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)(i.Button,{type:"primary",htmlType:"submit",icon:(0,t.jsx)(o.UserAddOutlined,{}),loading:O,children:O?"Adding...":"Add Member"})})]})})}])},276173,e=>{"use strict";var t=e.i(843476),l=e.i(599724),a=e.i(779241),r=e.i(464571),i=e.i(808613),s=e.i(212931),n=e.i(199133),o=e.i(271645),d=e.i(435451);e.s(["default",0,({visible:e,onCancel:c,onSubmit:u,initialData:m,mode:h,config:g})=>{let f,[p]=i.Form.useForm(),[b,v]=(0,o.useState)(!1);console.log("Initial Data:",m),(0,o.useEffect)(()=>{if(e)if("edit"===h&&m){let e={...m,role:m.role||g.defaultRole,max_budget_in_team:m.max_budget_in_team||null,tpm_limit:m.tpm_limit||null,rpm_limit:m.rpm_limit||null};console.log("Setting form values:",e),p.setFieldsValue(e)}else p.resetFields(),p.setFieldsValue({role:g.defaultRole||g.roleOptions[0]?.value})},[e,m,h,p,g.defaultRole,g.roleOptions]);let x=async e=>{try{v(!0);let t=Object.entries(e).reduce((e,[t,l])=>{if("string"==typeof l){let a=l.trim();return""===a&&("max_budget_in_team"===t||"tpm_limit"===t||"rpm_limit"===t)?{...e,[t]:null}:{...e,[t]:a}}return{...e,[t]:l}},{});console.log("Submitting form data:",t),await Promise.resolve(u(t)),p.resetFields()}catch(e){console.error("Form submission error:",e)}finally{v(!1)}};return(0,t.jsx)(s.Modal,{title:g.title||("add"===h?"Add Member":"Edit Member"),open:e,width:1e3,footer:null,onCancel:c,children:(0,t.jsxs)(i.Form,{form:p,onFinish:x,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[g.showEmail&&(0,t.jsx)(i.Form.Item,{label:"Email",name:"user_email",className:"mb-4",rules:[{type:"email",message:"Please enter a valid email!"}],children:(0,t.jsx)(a.TextInput,{placeholder:"user@example.com"})}),g.showEmail&&g.showUserId&&(0,t.jsx)("div",{className:"text-center mb-4",children:(0,t.jsx)(l.Text,{children:"OR"})}),g.showUserId&&(0,t.jsx)(i.Form.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,t.jsx)(a.TextInput,{placeholder:"user_123"})}),(0,t.jsx)(i.Form.Item,{label:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{children:"Role"}),"edit"===h&&m&&(0,t.jsxs)("span",{className:"text-gray-500 text-sm",children:["(Current: ",(f=m.role,g.roleOptions.find(e=>e.value===f)?.label||f),")"]})]}),name:"role",className:"mb-4",rules:[{required:!0,message:"Please select a role!"}],children:(0,t.jsx)(n.Select,{children:"edit"===h&&m?[...g.roleOptions.filter(e=>e.value===m.role),...g.roleOptions.filter(e=>e.value!==m.role)].map(e=>(0,t.jsx)(n.Select.Option,{value:e.value,children:e.label},e.value)):g.roleOptions.map(e=>(0,t.jsx)(n.Select.Option,{value:e.value,children:e.label},e.value))})}),g.additionalFields?.map(e=>(0,t.jsx)(i.Form.Item,{label:e.label,name:e.name,className:"mb-4",rules:e.rules,children:(e=>{switch(e.type){case"input":return(0,t.jsx)(a.TextInput,{placeholder:e.placeholder});case"numerical":return(0,t.jsx)(d.default,{step:e.step||1,min:e.min||0,style:{width:"100%"},placeholder:e.placeholder||"Enter a numerical value"});case"select":return(0,t.jsx)(n.Select,{children:e.options?.map(e=>(0,t.jsx)(n.Select.Option,{value:e.value,children:e.label},e.value))});default:return null}})(e)},e.name)),(0,t.jsxs)("div",{className:"text-right mt-6",children:[(0,t.jsx)(r.Button,{onClick:c,className:"mr-2",disabled:b,children:"Cancel"}),(0,t.jsx)(r.Button,{type:"default",htmlType:"submit",loading:b,children:"add"===h?b?"Adding...":"Add Member":b?"Saving...":"Save Changes"})]})]})})}])},434626,e=>{"use strict";var t=e.i(271645);let l=t.forwardRef(function(e,l){return t.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:l},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"}))});e.s(["ExternalLinkIcon",0,l],434626)},902555,e=>{"use strict";var t=e.i(843476),l=e.i(591935),a=e.i(122577),r=e.i(278587),i=e.i(68155),s=e.i(360820),n=e.i(871943),o=e.i(434626),d=e.i(592968),c=e.i(115504),u=e.i(752978);function m({icon:e,onClick:l,className:a,disabled:r,dataTestId:i}){return r?(0,t.jsx)(u.Icon,{icon:e,size:"sm",className:"opacity-50 cursor-not-allowed","data-testid":i}):(0,t.jsx)(u.Icon,{icon:e,size:"sm",onClick:l,className:(0,c.cx)("cursor-pointer",a),"data-testid":i})}let h={Edit:{icon:l.PencilAltIcon,className:"hover:text-blue-600"},Delete:{icon:i.TrashIcon,className:"hover:text-red-600"},Test:{icon:a.PlayIcon,className:"hover:text-blue-600"},Regenerate:{icon:r.RefreshIcon,className:"hover:text-green-600"},Up:{icon:s.ChevronUpIcon,className:"hover:text-blue-600"},Down:{icon:n.ChevronDownIcon,className:"hover:text-blue-600"},Open:{icon:o.ExternalLinkIcon,className:"hover:text-green-600"}};function g({onClick:e,tooltipText:l,disabled:a=!1,disabledTooltipText:r,dataTestId:i,variant:s}){let{icon:n,className:o}=h[s];return(0,t.jsx)(d.Tooltip,{title:a?r:l,children:(0,t.jsx)("span",{children:(0,t.jsx)(m,{icon:n,onClick:e,className:o,disabled:a,dataTestId:i})})})}e.s(["default",()=>g],902555)},122577,e=>{"use strict";var t=e.i(271645);let l=t.forwardRef(function(e,l){return t.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:l},e),t.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"}),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M21 12a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlayIcon",0,l],122577)},591935,e=>{"use strict";var t=e.i(271645);let l=t.forwardRef(function(e,l){return t.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:l},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"}))});e.s(["PencilAltIcon",0,l],591935)},871943,e=>{"use strict";var t=e.i(271645);let l=t.forwardRef(function(e,l){return t.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:l},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"}))});e.s(["ChevronDownIcon",0,l],871943)},360820,e=>{"use strict";var t=e.i(271645);let l=t.forwardRef(function(e,l){return t.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:l},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 15l7-7 7 7"}))});e.s(["ChevronUpIcon",0,l],360820)},185793,e=>{"use strict";e.i(247167);var t=e.i(271645),l=e.i(343794),a=e.i(242064),r=e.i(529681);let i=e=>{let{prefixCls:a,className:r,style:i,size:s,shape:n}=e,o=(0,l.default)({[`${a}-lg`]:"large"===s,[`${a}-sm`]:"small"===s}),d=(0,l.default)({[`${a}-circle`]:"circle"===n,[`${a}-square`]:"square"===n,[`${a}-round`]:"round"===n}),c=t.useMemo(()=>"number"==typeof s?{width:s,height:s,lineHeight:`${s}px`}:{},[s]);return t.createElement("span",{className:(0,l.default)(a,o,d,r),style:Object.assign(Object.assign({},c),i)})};e.i(296059);var s=e.i(694758),n=e.i(915654),o=e.i(246422),d=e.i(838378);let c=new s.Keyframes("ant-skeleton-loading",{"0%":{backgroundPosition:"100% 50%"},"100%":{backgroundPosition:"0 50%"}}),u=e=>({height:e,lineHeight:(0,n.unit)(e)}),m=e=>Object.assign({width:e},u(e)),h=(e,t)=>Object.assign({width:t(e).mul(5).equal(),minWidth:t(e).mul(5).equal()},u(e)),g=e=>Object.assign({width:e},u(e)),f=(e,t,l)=>{let{skeletonButtonCls:a}=e;return{[`${l}${a}-circle`]:{width:t,minWidth:t,borderRadius:"50%"},[`${l}${a}-round`]:{borderRadius:t}}},p=(e,t)=>Object.assign({width:t(e).mul(2).equal(),minWidth:t(e).mul(2).equal()},u(e)),b=(0,o.genStyleHooks)("Skeleton",e=>{let{componentCls:t,calc:l}=e;return(e=>{let{componentCls:t,skeletonAvatarCls:l,skeletonTitleCls:a,skeletonParagraphCls:r,skeletonButtonCls:i,skeletonInputCls:s,skeletonImageCls:n,controlHeight:o,controlHeightLG:d,controlHeightSM:u,gradientFromColor:b,padding:v,marginSM:x,borderRadius:y,titleHeight:j,blockRadius:w,paragraphLiHeight:k,controlHeightXS:C,paragraphMarginTop:O}=e;return{[t]:{display:"table",width:"100%",[`${t}-header`]:{display:"table-cell",paddingInlineEnd:v,verticalAlign:"top",[l]:Object.assign({display:"inline-block",verticalAlign:"top",background:b},m(o)),[`${l}-circle`]:{borderRadius:"50%"},[`${l}-lg`]:Object.assign({},m(d)),[`${l}-sm`]:Object.assign({},m(u))},[`${t}-content`]:{display:"table-cell",width:"100%",verticalAlign:"top",[a]:{width:"100%",height:j,background:b,borderRadius:w,[`+ ${r}`]:{marginBlockStart:u}},[r]:{padding:0,"> li":{width:"100%",height:k,listStyle:"none",background:b,borderRadius:w,"+ li":{marginBlockStart:C}}},[`${r}> li:last-child:not(:first-child):not(:nth-child(2))`]:{width:"61%"}},[`&-round ${t}-content`]:{[`${a}, ${r} > li`]:{borderRadius:y}}},[`${t}-with-avatar ${t}-content`]:{[a]:{marginBlockStart:x,[`+ ${r}`]:{marginBlockStart:O}}},[`${t}${t}-element`]:Object.assign(Object.assign(Object.assign(Object.assign({display:"inline-block",width:"auto"},(e=>{let{borderRadiusSM:t,skeletonButtonCls:l,controlHeight:a,controlHeightLG:r,controlHeightSM:i,gradientFromColor:s,calc:n}=e;return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({[l]:Object.assign({display:"inline-block",verticalAlign:"top",background:s,borderRadius:t,width:n(a).mul(2).equal(),minWidth:n(a).mul(2).equal()},p(a,n))},f(e,a,l)),{[`${l}-lg`]:Object.assign({},p(r,n))}),f(e,r,`${l}-lg`)),{[`${l}-sm`]:Object.assign({},p(i,n))}),f(e,i,`${l}-sm`))})(e)),(e=>{let{skeletonAvatarCls:t,gradientFromColor:l,controlHeight:a,controlHeightLG:r,controlHeightSM:i}=e;return{[t]:Object.assign({display:"inline-block",verticalAlign:"top",background:l},m(a)),[`${t}${t}-circle`]:{borderRadius:"50%"},[`${t}${t}-lg`]:Object.assign({},m(r)),[`${t}${t}-sm`]:Object.assign({},m(i))}})(e)),(e=>{let{controlHeight:t,borderRadiusSM:l,skeletonInputCls:a,controlHeightLG:r,controlHeightSM:i,gradientFromColor:s,calc:n}=e;return{[a]:Object.assign({display:"inline-block",verticalAlign:"top",background:s,borderRadius:l},h(t,n)),[`${a}-lg`]:Object.assign({},h(r,n)),[`${a}-sm`]:Object.assign({},h(i,n))}})(e)),(e=>{let{skeletonImageCls:t,imageSizeBase:l,gradientFromColor:a,borderRadiusSM:r,calc:i}=e;return{[t]:Object.assign(Object.assign({display:"inline-flex",alignItems:"center",justifyContent:"center",verticalAlign:"middle",background:a,borderRadius:r},g(i(l).mul(2).equal())),{[`${t}-path`]:{fill:"#bfbfbf"},[`${t}-svg`]:Object.assign(Object.assign({},g(l)),{maxWidth:i(l).mul(4).equal(),maxHeight:i(l).mul(4).equal()}),[`${t}-svg${t}-svg-circle`]:{borderRadius:"50%"}}),[`${t}${t}-circle`]:{borderRadius:"50%"}}})(e)),[`${t}${t}-block`]:{width:"100%",[i]:{width:"100%"},[s]:{width:"100%"}},[`${t}${t}-active`]:{[` - ${a}, - ${r} > li, +(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,162386,e=>{"use strict";var t=e.i(843476),a=e.i(625901),l=e.i(109799),r=e.i(785242),i=e.i(738014),s=e.i(199133),n=e.i(981339),o=e.i(592968);let d={label:"All Proxy Models",value:"all-proxy-models"},c={label:"No Default Models",value:"no-default-models"},u=[d,c],m={user:({allProxyModels:e,userModels:t,options:a})=>t&&a?.includeUserModels?t:[],team:({allProxyModels:e,selectedOrganization:t,userModels:a})=>t?t.models.includes(d.value)||0===t.models.length?e:e.filter(e=>t.models.includes(e)):e??[],organization:({allProxyModels:e})=>e,global:({allProxyModels:e})=>e};e.s(["ModelSelect",0,e=>{let{teamID:h,organizationID:g,options:f,context:p,dataTestId:b,value:v=[],onChange:x,style:y}=e,{includeUserModels:j,showAllTeamModelsOption:w,showAllProxyModelsOverride:k,includeSpecialOptions:C}=f||{},{data:O,isLoading:$}=(0,a.useAllProxyModels)(),{data:N,isLoading:E}=(0,r.useTeam)(h),{data:T,isLoading:_}=(0,l.useOrganization)(g),{data:M,isLoading:I}=(0,i.useCurrentUser)(),R=e=>u.some(t=>t.value===e),S=v.some(R),P=T?.models.includes(d.value)||T?.models.length===0;if($||E||_||I)return(0,t.jsx)(n.Skeleton.Input,{active:!0,block:!0});let{wildcard:q,regular:A}=(e=>{let t=[],a=[];for(let l of e)l.endsWith("/*")?t.push(l):a.push(l);return{wildcard:t,regular:a}})(((e,t,a)=>{let l=Array.from(new Map(e.map(e=>[e.id,e])).values()).map(e=>e.id);if(t.options?.showAllProxyModelsOverride)return l;let r=m[t.context];return r?r({allProxyModels:l,...a,options:t.options}):[]})(O?.data??[],e,{selectedTeam:N,selectedOrganization:T,userModels:M?.models}));return(0,t.jsx)(s.Select,{"data-testid":b,value:v,onChange:e=>{let t=e.filter(R);x(t.length>0?[t[t.length-1]]:e)},style:y,options:[C?{label:(0,t.jsx)("span",{children:"Special Options"}),title:"Special Options",options:[...k||P&&C||"global"===p?[{label:(0,t.jsx)("span",{children:"All Proxy Models"}),value:d.value,disabled:v.length>0&&v.some(e=>R(e)&&e!==d.value),key:d.value}]:[],{label:(0,t.jsx)("span",{children:"No Default Models"}),value:c.value,disabled:v.length>0&&v.some(e=>R(e)&&e!==c.value),key:c.value}]}:[],...q.length>0?[{label:(0,t.jsx)("span",{children:"Wildcard Options"}),title:"Wildcard Options",options:q.map(e=>{let a=e.replace("/*",""),l=a.charAt(0).toUpperCase()+a.slice(1);return{label:(0,t.jsx)("span",{children:`All ${l} models`}),value:e,disabled:S}})}]:[],{label:(0,t.jsx)("span",{children:"Models"}),title:"Models",options:A.map(e=>({label:(0,t.jsx)("span",{children:e}),value:e,disabled:S}))}],mode:"multiple",placeholder:"Select Models",allowClear:!0,maxTagCount:"responsive",maxTagPlaceholder:e=>(0,t.jsx)(o.Tooltip,{styles:{root:{pointerEvents:"none"}},title:e.map(({value:e})=>e).join(", "),children:(0,t.jsxs)("span",{children:["+",e.length," more"]})})})}],162386)},294612,e=>{"use strict";var t=e.i(843476),a=e.i(100486),l=e.i(827252),r=e.i(213205),i=e.i(771674),s=e.i(464571),n=e.i(770914),o=e.i(291542),d=e.i(262218),c=e.i(592968),u=e.i(898586),m=e.i(902555);let{Text:h}=u.Typography;function g({members:e,canEdit:u,onEdit:g,onDelete:f,onAddMember:p,roleColumnTitle:b="Role",roleTooltip:v,extraColumns:x=[],showDeleteForMember:y,emptyText:j}){let w=[{title:"User Email",dataIndex:"user_email",key:"user_email",render:e=>(0,t.jsx)(h,{children:e||"-"})},{title:"User ID",dataIndex:"user_id",key:"user_id",render:e=>"default_user_id"===e?(0,t.jsx)(d.Tag,{color:"blue",children:"Default Proxy Admin"}):(0,t.jsx)(h,{children:e||"-"})},{title:v?(0,t.jsxs)(n.Space,{direction:"horizontal",children:[b,(0,t.jsx)(c.Tooltip,{title:v,children:(0,t.jsx)(l.InfoCircleOutlined,{})})]}):b,dataIndex:"role",key:"role",render:e=>(0,t.jsxs)(n.Space,{children:[e?.toLowerCase()==="admin"||e?.toLowerCase()==="org_admin"?(0,t.jsx)(a.CrownOutlined,{}):(0,t.jsx)(i.UserOutlined,{}),(0,t.jsx)(h,{style:{textTransform:"capitalize"},children:e||"-"})]})},...x,{title:"Actions",key:"actions",fixed:"right",width:120,render:(e,a)=>u?(0,t.jsxs)(n.Space,{children:[(0,t.jsx)(m.default,{variant:"Edit",tooltipText:"Edit member",dataTestId:"edit-member",onClick:()=>g(a)}),(!y||y(a))&&(0,t.jsx)(m.default,{variant:"Delete",tooltipText:"Delete member",dataTestId:"delete-member",onClick:()=>f(a)})]}):null}];return(0,t.jsxs)(n.Space,{direction:"vertical",style:{width:"100%"},children:[(0,t.jsxs)("span",{className:"inline-flex text-sm text-gray-700",children:[e.length," Member",1!==e.length?"s":""]}),(0,t.jsx)(o.Table,{columns:w,dataSource:e,rowKey:e=>e.user_id??e.user_email??JSON.stringify(e),pagination:!1,size:"small",scroll:{x:"max-content"},locale:j?{emptyText:j}:void 0}),p&&u&&(0,t.jsx)(s.Button,{icon:(0,t.jsx)(r.UserAddOutlined,{}),type:"primary",onClick:p,children:"Add Member"})]})}e.s(["default",()=>g])},907308,e=>{"use strict";var t=e.i(843476),a=e.i(271645),l=e.i(212931),r=e.i(808613),i=e.i(464571),s=e.i(199133),n=e.i(592968),o=e.i(213205),d=e.i(374009),c=e.i(764205);e.s(["default",0,({isVisible:e,onCancel:u,onSubmit:m,accessToken:h,title:g="Add Team Member",roles:f=[{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",teamId:b})=>{let[v]=r.Form.useForm(),[x,y]=(0,a.useState)([]),[j,w]=(0,a.useState)(!1),[k,C]=(0,a.useState)("user_email"),[O,$]=(0,a.useState)(!1),N=async(e,t)=>{if(!e)return void y([]);w(!0);try{let a=new URLSearchParams;if(a.append(t,e),b&&a.append("team_id",b),null==h)return;let l=(await (0,c.userFilterUICall)(h,a)).map(e=>({label:"user_email"===t?`${e.user_email}`:`${e.user_id}`,value:"user_email"===t?e.user_email:e.user_id,user:e}));y(l)}catch(e){console.error("Error fetching users:",e)}finally{w(!1)}},E=(0,a.useCallback)((0,d.default)((e,t)=>N(e,t),300),[]),T=(e,t)=>{C(t),E(e,t)},_=(e,t)=>{let a=t.user;v.setFieldsValue({user_email:a.user_email,user_id:a.user_id,role:v.getFieldValue("role")})},M=async e=>{$(!0);try{await m(e)}finally{$(!1)}};return(0,t.jsx)(l.Modal,{title:g,open:e,onCancel:()=>{v.resetFields(),y([]),u()},footer:null,width:800,maskClosable:!O,children:(0,t.jsxs)(r.Form,{form:v,onFinish:M,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",initialValues:{role:p},children:[(0,t.jsx)(r.Form.Item,{label:"Email",name:"user_email",className:"mb-4",children:(0,t.jsx)(s.Select,{showSearch:!0,className:"w-full",placeholder:"Search by email",filterOption:!1,onSearch:e=>T(e,"user_email"),onSelect:(e,t)=>_(e,t),options:"user_email"===k?x:[],loading:j,allowClear:!0})}),(0,t.jsx)("div",{className:"text-center mb-4",children:"OR"}),(0,t.jsx)(r.Form.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,t.jsx)(s.Select,{showSearch:!0,className:"w-full",placeholder:"Search by user ID",filterOption:!1,onSearch:e=>T(e,"user_id"),onSelect:(e,t)=>_(e,t),options:"user_id"===k?x:[],loading:j,allowClear:!0})}),(0,t.jsx)(r.Form.Item,{label:"Member Role",name:"role",className:"mb-4",children:(0,t.jsx)(s.Select,{defaultValue:p,children:f.map(e=>(0,t.jsx)(s.Select.Option,{value:e.value,children:(0,t.jsxs)(n.Tooltip,{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)(i.Button,{type:"primary",htmlType:"submit",icon:(0,t.jsx)(o.UserAddOutlined,{}),loading:O,children:O?"Adding...":"Add Member"})})]})})}])},276173,e=>{"use strict";var t=e.i(843476),a=e.i(599724),l=e.i(779241),r=e.i(464571),i=e.i(808613),s=e.i(212931),n=e.i(199133),o=e.i(271645),d=e.i(435451);e.s(["default",0,({visible:e,onCancel:c,onSubmit:u,initialData:m,mode:h,config:g})=>{let f,[p]=i.Form.useForm(),[b,v]=(0,o.useState)(!1);console.log("Initial Data:",m),(0,o.useEffect)(()=>{if(e)if("edit"===h&&m){let e={...m,role:m.role||g.defaultRole,max_budget_in_team:m.max_budget_in_team||null,tpm_limit:m.tpm_limit||null,rpm_limit:m.rpm_limit||null};console.log("Setting form values:",e),p.setFieldsValue(e)}else p.resetFields(),p.setFieldsValue({role:g.defaultRole||g.roleOptions[0]?.value})},[e,m,h,p,g.defaultRole,g.roleOptions]);let x=async e=>{try{v(!0);let t=Object.entries(e).reduce((e,[t,a])=>{if("string"==typeof a){let l=a.trim();return""===l&&("max_budget_in_team"===t||"tpm_limit"===t||"rpm_limit"===t)?{...e,[t]:null}:{...e,[t]:l}}return{...e,[t]:a}},{});console.log("Submitting form data:",t),await Promise.resolve(u(t)),p.resetFields()}catch(e){console.error("Form submission error:",e)}finally{v(!1)}};return(0,t.jsx)(s.Modal,{title:g.title||("add"===h?"Add Member":"Edit Member"),open:e,width:1e3,footer:null,onCancel:c,children:(0,t.jsxs)(i.Form,{form:p,onFinish:x,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[g.showEmail&&(0,t.jsx)(i.Form.Item,{label:"Email",name:"user_email",className:"mb-4",rules:[{type:"email",message:"Please enter a valid email!"}],children:(0,t.jsx)(l.TextInput,{placeholder:"user@example.com"})}),g.showEmail&&g.showUserId&&(0,t.jsx)("div",{className:"text-center mb-4",children:(0,t.jsx)(a.Text,{children:"OR"})}),g.showUserId&&(0,t.jsx)(i.Form.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,t.jsx)(l.TextInput,{placeholder:"user_123"})}),(0,t.jsx)(i.Form.Item,{label:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{children:"Role"}),"edit"===h&&m&&(0,t.jsxs)("span",{className:"text-gray-500 text-sm",children:["(Current: ",(f=m.role,g.roleOptions.find(e=>e.value===f)?.label||f),")"]})]}),name:"role",className:"mb-4",rules:[{required:!0,message:"Please select a role!"}],children:(0,t.jsx)(n.Select,{children:"edit"===h&&m?[...g.roleOptions.filter(e=>e.value===m.role),...g.roleOptions.filter(e=>e.value!==m.role)].map(e=>(0,t.jsx)(n.Select.Option,{value:e.value,children:e.label},e.value)):g.roleOptions.map(e=>(0,t.jsx)(n.Select.Option,{value:e.value,children:e.label},e.value))})}),g.additionalFields?.map(e=>(0,t.jsx)(i.Form.Item,{label:e.label,name:e.name,className:"mb-4",rules:e.rules,children:(e=>{switch(e.type){case"input":return(0,t.jsx)(l.TextInput,{placeholder:e.placeholder});case"numerical":return(0,t.jsx)(d.default,{step:e.step||1,min:e.min||0,style:{width:"100%"},placeholder:e.placeholder||"Enter a numerical value"});case"select":return(0,t.jsx)(n.Select,{children:e.options?.map(e=>(0,t.jsx)(n.Select.Option,{value:e.value,children:e.label},e.value))});default:return null}})(e)},e.name)),(0,t.jsxs)("div",{className:"text-right mt-6",children:[(0,t.jsx)(r.Button,{onClick:c,className:"mr-2",disabled:b,children:"Cancel"}),(0,t.jsx)(r.Button,{type:"default",htmlType:"submit",loading:b,children:"add"===h?b?"Adding...":"Add Member":b?"Saving...":"Save Changes"})]})]})})}])},434626,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"}))});e.s(["ExternalLinkIcon",0,a],434626)},902555,e=>{"use strict";var t=e.i(843476),a=e.i(591935),l=e.i(122577),r=e.i(278587),i=e.i(68155),s=e.i(360820),n=e.i(871943),o=e.i(434626),d=e.i(592968),c=e.i(115504),u=e.i(752978);function m({icon:e,onClick:a,className:l,disabled:r,dataTestId:i}){return r?(0,t.jsx)(u.Icon,{icon:e,size:"sm",className:"opacity-50 cursor-not-allowed","data-testid":i}):(0,t.jsx)(u.Icon,{icon:e,size:"sm",onClick:a,className:(0,c.cx)("cursor-pointer",l),"data-testid":i})}let h={Edit:{icon:a.PencilAltIcon,className:"hover:text-blue-600"},Delete:{icon:i.TrashIcon,className:"hover:text-red-600"},Test:{icon:l.PlayIcon,className:"hover:text-blue-600"},Regenerate:{icon:r.RefreshIcon,className:"hover:text-green-600"},Up:{icon:s.ChevronUpIcon,className:"hover:text-blue-600"},Down:{icon:n.ChevronDownIcon,className:"hover:text-blue-600"},Open:{icon:o.ExternalLinkIcon,className:"hover:text-green-600"}};function g({onClick:e,tooltipText:a,disabled:l=!1,disabledTooltipText:r,dataTestId:i,variant:s}){let{icon:n,className:o}=h[s];return(0,t.jsx)(d.Tooltip,{title:l?r:a,children:(0,t.jsx)("span",{children:(0,t.jsx)(m,{icon:n,onClick:e,className:o,disabled:l,dataTestId:i})})})}e.s(["default",()=>g],902555)},122577,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.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"}),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M21 12a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["PlayIcon",0,a],122577)},591935,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"}))});e.s(["PencilAltIcon",0,a],591935)},871943,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"}))});e.s(["ChevronDownIcon",0,a],871943)},360820,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 15l7-7 7 7"}))});e.s(["ChevronUpIcon",0,a],360820)},185793,e=>{"use strict";e.i(247167);var t=e.i(271645),a=e.i(343794),l=e.i(242064),r=e.i(529681);let i=e=>{let{prefixCls:l,className:r,style:i,size:s,shape:n}=e,o=(0,a.default)({[`${l}-lg`]:"large"===s,[`${l}-sm`]:"small"===s}),d=(0,a.default)({[`${l}-circle`]:"circle"===n,[`${l}-square`]:"square"===n,[`${l}-round`]:"round"===n}),c=t.useMemo(()=>"number"==typeof s?{width:s,height:s,lineHeight:`${s}px`}:{},[s]);return t.createElement("span",{className:(0,a.default)(l,o,d,r),style:Object.assign(Object.assign({},c),i)})};e.i(296059);var s=e.i(694758),n=e.i(915654),o=e.i(246422),d=e.i(838378);let c=new s.Keyframes("ant-skeleton-loading",{"0%":{backgroundPosition:"100% 50%"},"100%":{backgroundPosition:"0 50%"}}),u=e=>({height:e,lineHeight:(0,n.unit)(e)}),m=e=>Object.assign({width:e},u(e)),h=(e,t)=>Object.assign({width:t(e).mul(5).equal(),minWidth:t(e).mul(5).equal()},u(e)),g=e=>Object.assign({width:e},u(e)),f=(e,t,a)=>{let{skeletonButtonCls:l}=e;return{[`${a}${l}-circle`]:{width:t,minWidth:t,borderRadius:"50%"},[`${a}${l}-round`]:{borderRadius:t}}},p=(e,t)=>Object.assign({width:t(e).mul(2).equal(),minWidth:t(e).mul(2).equal()},u(e)),b=(0,o.genStyleHooks)("Skeleton",e=>{let{componentCls:t,calc:a}=e;return(e=>{let{componentCls:t,skeletonAvatarCls:a,skeletonTitleCls:l,skeletonParagraphCls:r,skeletonButtonCls:i,skeletonInputCls:s,skeletonImageCls:n,controlHeight:o,controlHeightLG:d,controlHeightSM:u,gradientFromColor:b,padding:v,marginSM:x,borderRadius:y,titleHeight:j,blockRadius:w,paragraphLiHeight:k,controlHeightXS:C,paragraphMarginTop:O}=e;return{[t]:{display:"table",width:"100%",[`${t}-header`]:{display:"table-cell",paddingInlineEnd:v,verticalAlign:"top",[a]:Object.assign({display:"inline-block",verticalAlign:"top",background:b},m(o)),[`${a}-circle`]:{borderRadius:"50%"},[`${a}-lg`]:Object.assign({},m(d)),[`${a}-sm`]:Object.assign({},m(u))},[`${t}-content`]:{display:"table-cell",width:"100%",verticalAlign:"top",[l]:{width:"100%",height:j,background:b,borderRadius:w,[`+ ${r}`]:{marginBlockStart:u}},[r]:{padding:0,"> li":{width:"100%",height:k,listStyle:"none",background:b,borderRadius:w,"+ li":{marginBlockStart:C}}},[`${r}> li:last-child:not(:first-child):not(:nth-child(2))`]:{width:"61%"}},[`&-round ${t}-content`]:{[`${l}, ${r} > li`]:{borderRadius:y}}},[`${t}-with-avatar ${t}-content`]:{[l]:{marginBlockStart:x,[`+ ${r}`]:{marginBlockStart:O}}},[`${t}${t}-element`]:Object.assign(Object.assign(Object.assign(Object.assign({display:"inline-block",width:"auto"},(e=>{let{borderRadiusSM:t,skeletonButtonCls:a,controlHeight:l,controlHeightLG:r,controlHeightSM:i,gradientFromColor:s,calc:n}=e;return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({[a]:Object.assign({display:"inline-block",verticalAlign:"top",background:s,borderRadius:t,width:n(l).mul(2).equal(),minWidth:n(l).mul(2).equal()},p(l,n))},f(e,l,a)),{[`${a}-lg`]:Object.assign({},p(r,n))}),f(e,r,`${a}-lg`)),{[`${a}-sm`]:Object.assign({},p(i,n))}),f(e,i,`${a}-sm`))})(e)),(e=>{let{skeletonAvatarCls:t,gradientFromColor:a,controlHeight:l,controlHeightLG:r,controlHeightSM:i}=e;return{[t]:Object.assign({display:"inline-block",verticalAlign:"top",background:a},m(l)),[`${t}${t}-circle`]:{borderRadius:"50%"},[`${t}${t}-lg`]:Object.assign({},m(r)),[`${t}${t}-sm`]:Object.assign({},m(i))}})(e)),(e=>{let{controlHeight:t,borderRadiusSM:a,skeletonInputCls:l,controlHeightLG:r,controlHeightSM:i,gradientFromColor:s,calc:n}=e;return{[l]:Object.assign({display:"inline-block",verticalAlign:"top",background:s,borderRadius:a},h(t,n)),[`${l}-lg`]:Object.assign({},h(r,n)),[`${l}-sm`]:Object.assign({},h(i,n))}})(e)),(e=>{let{skeletonImageCls:t,imageSizeBase:a,gradientFromColor:l,borderRadiusSM:r,calc:i}=e;return{[t]:Object.assign(Object.assign({display:"inline-flex",alignItems:"center",justifyContent:"center",verticalAlign:"middle",background:l,borderRadius:r},g(i(a).mul(2).equal())),{[`${t}-path`]:{fill:"#bfbfbf"},[`${t}-svg`]:Object.assign(Object.assign({},g(a)),{maxWidth:i(a).mul(4).equal(),maxHeight:i(a).mul(4).equal()}),[`${t}-svg${t}-svg-circle`]:{borderRadius:"50%"}}),[`${t}${t}-circle`]:{borderRadius:"50%"}}})(e)),[`${t}${t}-block`]:{width:"100%",[i]:{width:"100%"},[s]:{width:"100%"}},[`${t}${t}-active`]:{[` ${l}, + ${r} > li, + ${a}, ${i}, ${s}, ${n} - `]:Object.assign({},{background:e.skeletonLoadingBackground,backgroundSize:"400% 100%",animationName:c,animationDuration:e.skeletonLoadingMotionDuration,animationTimingFunction:"ease",animationIterationCount:"infinite"})}}})((0,d.mergeToken)(e,{skeletonAvatarCls:`${t}-avatar`,skeletonTitleCls:`${t}-title`,skeletonParagraphCls:`${t}-paragraph`,skeletonButtonCls:`${t}-button`,skeletonInputCls:`${t}-input`,skeletonImageCls:`${t}-image`,imageSizeBase:l(e.controlHeight).mul(1.5).equal(),borderRadius:100,skeletonLoadingBackground:`linear-gradient(90deg, ${e.gradientFromColor} 25%, ${e.gradientToColor} 37%, ${e.gradientFromColor} 63%)`,skeletonLoadingMotionDuration:"1.4s"}))},e=>{let{colorFillContent:t,colorFill:l}=e;return{color:t,colorGradientEnd:l,gradientFromColor:t,gradientToColor:l,titleHeight:e.controlHeight/2,blockRadius:e.borderRadiusSM,paragraphMarginTop:e.marginLG+e.marginXXS,paragraphLiHeight:e.controlHeight/2}},{deprecatedTokens:[["color","gradientFromColor"],["colorGradientEnd","gradientToColor"]]}),v=e=>{let{prefixCls:a,className:r,style:i,rows:s=0}=e,n=Array.from({length:s}).map((l,a)=>t.createElement("li",{key:a,style:{width:((e,t)=>{let{width:l,rows:a=2}=t;return Array.isArray(l)?l[e]:a-1===e?l:void 0})(a,e)}}));return t.createElement("ul",{className:(0,l.default)(a,r),style:i},n)},x=({prefixCls:e,className:a,width:r,style:i})=>t.createElement("h3",{className:(0,l.default)(e,a),style:Object.assign({width:r},i)});function y(e){return e&&"object"==typeof e?e:{}}let j=e=>{let{prefixCls:r,loading:s,className:n,rootClassName:o,style:d,children:c,avatar:u=!1,title:m=!0,paragraph:h=!0,active:g,round:f}=e,{getPrefixCls:p,direction:j,className:w,style:k}=(0,a.useComponentConfig)("skeleton"),C=p("skeleton",r),[O,$,N]=b(C);if(s||!("loading"in e)){let e,a,r=!!u,s=!!m,c=!!h;if(r){let l=Object.assign(Object.assign({prefixCls:`${C}-avatar`},s&&!c?{size:"large",shape:"square"}:{size:"large",shape:"circle"}),y(u));e=t.createElement("div",{className:`${C}-header`},t.createElement(i,Object.assign({},l)))}if(s||c){let e,l;if(s){let l=Object.assign(Object.assign({prefixCls:`${C}-title`},!r&&c?{width:"38%"}:r&&c?{width:"50%"}:{}),y(m));e=t.createElement(x,Object.assign({},l))}if(c){let e,a=Object.assign(Object.assign({prefixCls:`${C}-paragraph`},(e={},r&&s||(e.width="61%"),!r&&s?e.rows=3:e.rows=2,e)),y(h));l=t.createElement(v,Object.assign({},a))}a=t.createElement("div",{className:`${C}-content`},e,l)}let p=(0,l.default)(C,{[`${C}-with-avatar`]:r,[`${C}-active`]:g,[`${C}-rtl`]:"rtl"===j,[`${C}-round`]:f},w,n,o,$,N);return O(t.createElement("div",{className:p,style:Object.assign(Object.assign({},k),d)},e,a))}return null!=c?c:null};j.Button=e=>{let{prefixCls:s,className:n,rootClassName:o,active:d,block:c=!1,size:u="default"}=e,{getPrefixCls:m}=t.useContext(a.ConfigContext),h=m("skeleton",s),[g,f,p]=b(h),v=(0,r.default)(e,["prefixCls"]),x=(0,l.default)(h,`${h}-element`,{[`${h}-active`]:d,[`${h}-block`]:c},n,o,f,p);return g(t.createElement("div",{className:x},t.createElement(i,Object.assign({prefixCls:`${h}-button`,size:u},v))))},j.Avatar=e=>{let{prefixCls:s,className:n,rootClassName:o,active:d,shape:c="circle",size:u="default"}=e,{getPrefixCls:m}=t.useContext(a.ConfigContext),h=m("skeleton",s),[g,f,p]=b(h),v=(0,r.default)(e,["prefixCls","className"]),x=(0,l.default)(h,`${h}-element`,{[`${h}-active`]:d},n,o,f,p);return g(t.createElement("div",{className:x},t.createElement(i,Object.assign({prefixCls:`${h}-avatar`,shape:c,size:u},v))))},j.Input=e=>{let{prefixCls:s,className:n,rootClassName:o,active:d,block:c,size:u="default"}=e,{getPrefixCls:m}=t.useContext(a.ConfigContext),h=m("skeleton",s),[g,f,p]=b(h),v=(0,r.default)(e,["prefixCls"]),x=(0,l.default)(h,`${h}-element`,{[`${h}-active`]:d,[`${h}-block`]:c},n,o,f,p);return g(t.createElement("div",{className:x},t.createElement(i,Object.assign({prefixCls:`${h}-input`,size:u},v))))},j.Image=e=>{let{prefixCls:r,className:i,rootClassName:s,style:n,active:o}=e,{getPrefixCls:d}=t.useContext(a.ConfigContext),c=d("skeleton",r),[u,m,h]=b(c),g=(0,l.default)(c,`${c}-element`,{[`${c}-active`]:o},i,s,m,h);return u(t.createElement("div",{className:g},t.createElement("div",{className:(0,l.default)(`${c}-image`,i),style:n},t.createElement("svg",{viewBox:"0 0 1098 1024",xmlns:"http://www.w3.org/2000/svg",className:`${c}-image-svg`},t.createElement("title",null,"Image placeholder"),t.createElement("path",{d:"M365.714286 329.142857q0 45.714286-32.036571 77.677714t-77.677714 32.036571-77.677714-32.036571-32.036571-77.677714 32.036571-77.677714 77.677714-32.036571 77.677714 32.036571 32.036571 77.677714zM950.857143 548.571429l0 256-804.571429 0 0-109.714286 182.857143-182.857143 91.428571 91.428571 292.571429-292.571429zM1005.714286 146.285714l-914.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 694.857143q0 7.460571 5.412571 12.873143t12.873143 5.412571l914.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143l0-694.857143q0-7.460571-5.412571-12.873143t-12.873143-5.412571zM1097.142857 164.571429l0 694.857143q0 37.741714-26.843429 64.585143t-64.585143 26.843429l-914.285714 0q-37.741714 0-64.585143-26.843429t-26.843429-64.585143l0-694.857143q0-37.741714 26.843429-64.585143t64.585143-26.843429l914.285714 0q37.741714 0 64.585143 26.843429t26.843429 64.585143z",className:`${c}-image-path`})))))},j.Node=e=>{let{prefixCls:r,className:i,rootClassName:s,style:n,active:o,children:d}=e,{getPrefixCls:c}=t.useContext(a.ConfigContext),u=c("skeleton",r),[m,h,g]=b(u),f=(0,l.default)(u,`${u}-element`,{[`${u}-active`]:o},h,i,s,g);return m(t.createElement("div",{className:f},t.createElement("div",{className:(0,l.default)(`${u}-image`,i),style:n},d)))},e.s(["default",0,j],185793)},959013,e=>{"use strict";e.i(247167);var t=e.i(931067),l=e.i(271645);let a={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"}},{tag:"path",attrs:{d:"M192 474h672q8 0 8 8v60q0 8-8 8H160q-8 0-8-8v-60q0-8 8-8z"}}]},name:"plus",theme:"outlined"};var r=e.i(9583),i=l.forwardRef(function(e,i){return l.createElement(r.default,(0,t.default)({},e,{ref:i,icon:a}))});e.s(["default",0,i],959013)},269200,e=>{"use strict";var t=e.i(290571),l=e.i(271645),a=e.i(444755);let r=(0,e.i(673706).makeClassName)("Table"),i=l.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return l.default.createElement("div",{className:(0,a.tremorTwMerge)(r("root"),"overflow-auto",n)},l.default.createElement("table",Object.assign({ref:i,className:(0,a.tremorTwMerge)(r("table"),"w-full text-tremor-default","text-tremor-content","dark:text-dark-tremor-content")},o),s))});i.displayName="Table",e.s(["Table",()=>i],269200)},942232,e=>{"use strict";var t=e.i(290571),l=e.i(271645),a=e.i(444755);let r=(0,e.i(673706).makeClassName)("TableBody"),i=l.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return l.default.createElement(l.default.Fragment,null,l.default.createElement("tbody",Object.assign({ref:i,className:(0,a.tremorTwMerge)(r("root"),"align-top divide-y","divide-tremor-border","dark:divide-dark-tremor-border",n)},o),s))});i.displayName="TableBody",e.s(["TableBody",()=>i],942232)},977572,e=>{"use strict";var t=e.i(290571),l=e.i(271645),a=e.i(444755);let r=(0,e.i(673706).makeClassName)("TableCell"),i=l.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return l.default.createElement(l.default.Fragment,null,l.default.createElement("td",Object.assign({ref:i,className:(0,a.tremorTwMerge)(r("root"),"align-middle whitespace-nowrap text-left p-4",n)},o),s))});i.displayName="TableCell",e.s(["TableCell",()=>i],977572)},427612,e=>{"use strict";var t=e.i(290571),l=e.i(271645),a=e.i(444755);let r=(0,e.i(673706).makeClassName)("TableHead"),i=l.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return l.default.createElement(l.default.Fragment,null,l.default.createElement("thead",Object.assign({ref:i,className:(0,a.tremorTwMerge)(r("root"),"text-left","text-tremor-content","dark:text-dark-tremor-content",n)},o),s))});i.displayName="TableHead",e.s(["TableHead",()=>i],427612)},64848,e=>{"use strict";var t=e.i(290571),l=e.i(271645),a=e.i(444755);let r=(0,e.i(673706).makeClassName)("TableHeaderCell"),i=l.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return l.default.createElement(l.default.Fragment,null,l.default.createElement("th",Object.assign({ref:i,className:(0,a.tremorTwMerge)(r("root"),"whitespace-nowrap text-left font-semibold top-0 px-4 py-3.5","text-tremor-content-strong","dark:text-dark-tremor-content-strong",n)},o),s))});i.displayName="TableHeaderCell",e.s(["TableHeaderCell",()=>i],64848)},496020,e=>{"use strict";var t=e.i(290571),l=e.i(271645),a=e.i(444755);let r=(0,e.i(673706).makeClassName)("TableRow"),i=l.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return l.default.createElement(l.default.Fragment,null,l.default.createElement("tr",Object.assign({ref:i,className:(0,a.tremorTwMerge)(r("row"),n)},o),s))});i.displayName="TableRow",e.s(["TableRow",()=>i],496020)},68155,e=>{"use strict";var t=e.i(271645);let l=t.forwardRef(function(e,l){return t.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:l},e),t.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"}))});e.s(["TrashIcon",0,l],68155)},278587,e=>{"use strict";var t=e.i(271645);let l=t.forwardRef(function(e,l){return t.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:l},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"}))});e.s(["RefreshIcon",0,l],278587)},207670,e=>{"use strict";function t(){for(var e,t,l=0,a="",r=arguments.length;lt,"default",0,t])},625901,e=>{"use strict";var t=e.i(266027),l=e.i(621482),a=e.i(243652),r=e.i(764205),i=e.i(135214);let s=(0,a.createQueryKeys)("models"),n=(0,a.createQueryKeys)("modelHub"),o=(0,a.createQueryKeys)("allProxyModels");(0,a.createQueryKeys)("selectedTeamModels");let d=(0,a.createQueryKeys)("infiniteModels");e.s(["useAllProxyModels",0,()=>{let{accessToken:e,userId:l,userRole:a}=(0,i.default)();return(0,t.useQuery)({queryKey:o.list({}),queryFn:async()=>await (0,r.modelAvailableCall)(e,l,a,!0,null,!0,!1,"expand"),enabled:!!(e&&l&&a)})},"useInfiniteModelInfo",0,(e=50,t)=>{let{accessToken:a,userId:s,userRole:n}=(0,i.default)();return(0,l.useInfiniteQuery)({queryKey:d.list({filters:{...s&&{userId:s},...n&&{userRole:n},size:e,...t&&{search:t}}}),queryFn:async({pageParam:l})=>await (0,r.modelInfoCall)(a,s,n,l,e,t),initialPageParam:1,getNextPageParam:e=>{if(e.current_page{let{accessToken:e}=(0,i.default)();return(0,t.useQuery)({queryKey:n.list({}),queryFn:async()=>await (0,r.modelHubCall)(e),enabled:!!e})},"useModelsInfo",0,(e=1,l=50,a,n,o,d,c)=>{let{accessToken:u,userId:m,userRole:h}=(0,i.default)();return(0,t.useQuery)({queryKey:s.list({filters:{...m&&{userId:m},...h&&{userRole:h},page:e,size:l,...a&&{search:a},...n&&{modelId:n},...o&&{teamId:o},...d&&{sortBy:d},...c&&{sortOrder:c}}}),queryFn:async()=>await (0,r.modelInfoCall)(u,m,h,e,l,a,n,o,d,c),enabled:!!(u&&m&&h)})}])},621482,e=>{"use strict";var t=e.i(869230),l=e.i(992571),a=class extends t.QueryObserver{constructor(e,t){super(e,t)}bindMethods(){super.bindMethods(),this.fetchNextPage=this.fetchNextPage.bind(this),this.fetchPreviousPage=this.fetchPreviousPage.bind(this)}setOptions(e){super.setOptions({...e,behavior:(0,l.infiniteQueryBehavior)()})}getOptimisticResult(e){return e.behavior=(0,l.infiniteQueryBehavior)(),super.getOptimisticResult(e)}fetchNextPage(e){return this.fetch({...e,meta:{fetchMore:{direction:"forward"}}})}fetchPreviousPage(e){return this.fetch({...e,meta:{fetchMore:{direction:"backward"}}})}createResult(e,t){let{state:a}=e,r=super.createResult(e,t),{isFetching:i,isRefetching:s,isError:n,isRefetchError:o}=r,d=a.fetchMeta?.fetchMore?.direction,c=n&&"forward"===d,u=i&&"forward"===d,m=n&&"backward"===d,h=i&&"backward"===d;return{...r,fetchNextPage:this.fetchNextPage,fetchPreviousPage:this.fetchPreviousPage,hasNextPage:(0,l.hasNextPage)(t,a.data),hasPreviousPage:(0,l.hasPreviousPage)(t,a.data),isFetchNextPageError:c,isFetchingNextPage:u,isFetchPreviousPageError:m,isFetchingPreviousPage:h,isRefetchError:o&&!c&&!m,isRefetching:s&&!u&&!h}}},r=e.i(469637);function i(e,t){return(0,r.useBaseQuery)(e,a,t)}e.s(["useInfiniteQuery",()=>i],621482)},785242,e=>{"use strict";var t=e.i(619273),l=e.i(266027),a=e.i(912598),r=e.i(135214),i=e.i(270345),s=e.i(243652),n=e.i(764205);let o=(0,s.createQueryKeys)("teams"),d=async(e,t,l,a={})=>{try{let r=(0,n.getProxyBaseUrl)(),i=new URLSearchParams(Object.entries({team_id:a.teamID,organization_id:a.organizationID,team_alias:a.team_alias,user_id:a.userID,page:t,page_size:l,sort_by:a.sortBy,sort_order:a.sortOrder,status:"deleted"}).filter(([,e])=>null!=e).map(([e,t])=>[e,String(t)])),s=`${r?`${r}/v2/team/list`:"/v2/team/list"}?${i}`,o=await fetch(s,{method:"GET",headers:{[(0,n.getGlobalLitellmHeaderName)()]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=(0,n.deriveErrorMessage)(e);throw(0,n.handleError)(t),Error(t)}let d=await o.json();if(console.log("/team/list?status=deleted API Response:",d),d&&"object"==typeof d&&"teams"in d)return d.teams;return d}catch(e){throw console.error("Failed to list deleted teams:",e),e}},c=(0,s.createQueryKeys)("deletedTeams");e.s(["useDeletedTeams",0,(e,a,i={})=>{let{accessToken:s}=(0,r.default)();return(0,l.useQuery)({queryKey:c.list({page:e,limit:a,...i}),queryFn:async()=>await d(s,e,a,i),enabled:!!s,staleTime:3e4,placeholderData:t.keepPreviousData})},"useTeam",0,e=>{let{accessToken:t}=(0,r.default)(),i=(0,a.useQueryClient)();return(0,l.useQuery)({queryKey:o.detail(e),enabled:!!(t&&e),queryFn:async()=>{if(!t||!e)throw Error("Missing auth or teamId");return(0,n.teamInfoCall)(t,e)},initialData:()=>{if(!e)return;let t=i.getQueryData(o.list({}));return t?.find(t=>t.team_id===e)}})},"useTeams",0,()=>{let{accessToken:e,userId:t,userRole:a}=(0,r.default)();return(0,l.useQuery)({queryKey:o.list({}),queryFn:async()=>await (0,i.fetchTeams)(e,t,a,null),enabled:!!e})}])},738014,e=>{"use strict";var t=e.i(135214),l=e.i(764205),a=e.i(266027);let r=(0,e.i(243652).createQueryKeys)("users");e.s(["useCurrentUser",0,()=>{let{accessToken:e,userId:i,userRole:s}=(0,t.default)();return(0,a.useQuery)({queryKey:r.detail(i),queryFn:async()=>{let t=await (0,l.userInfoCall)(e,i,s,!1,null,null);return console.log(`userInfo: ${JSON.stringify(t)}`),t.user_info},enabled:!!(e&&i&&s)})}])}]); \ No newline at end of file + `]:Object.assign({},{background:e.skeletonLoadingBackground,backgroundSize:"400% 100%",animationName:c,animationDuration:e.skeletonLoadingMotionDuration,animationTimingFunction:"ease",animationIterationCount:"infinite"})}}})((0,d.mergeToken)(e,{skeletonAvatarCls:`${t}-avatar`,skeletonTitleCls:`${t}-title`,skeletonParagraphCls:`${t}-paragraph`,skeletonButtonCls:`${t}-button`,skeletonInputCls:`${t}-input`,skeletonImageCls:`${t}-image`,imageSizeBase:a(e.controlHeight).mul(1.5).equal(),borderRadius:100,skeletonLoadingBackground:`linear-gradient(90deg, ${e.gradientFromColor} 25%, ${e.gradientToColor} 37%, ${e.gradientFromColor} 63%)`,skeletonLoadingMotionDuration:"1.4s"}))},e=>{let{colorFillContent:t,colorFill:a}=e;return{color:t,colorGradientEnd:a,gradientFromColor:t,gradientToColor:a,titleHeight:e.controlHeight/2,blockRadius:e.borderRadiusSM,paragraphMarginTop:e.marginLG+e.marginXXS,paragraphLiHeight:e.controlHeight/2}},{deprecatedTokens:[["color","gradientFromColor"],["colorGradientEnd","gradientToColor"]]}),v=e=>{let{prefixCls:l,className:r,style:i,rows:s=0}=e,n=Array.from({length:s}).map((a,l)=>t.createElement("li",{key:l,style:{width:((e,t)=>{let{width:a,rows:l=2}=t;return Array.isArray(a)?a[e]:l-1===e?a:void 0})(l,e)}}));return t.createElement("ul",{className:(0,a.default)(l,r),style:i},n)},x=({prefixCls:e,className:l,width:r,style:i})=>t.createElement("h3",{className:(0,a.default)(e,l),style:Object.assign({width:r},i)});function y(e){return e&&"object"==typeof e?e:{}}let j=e=>{let{prefixCls:r,loading:s,className:n,rootClassName:o,style:d,children:c,avatar:u=!1,title:m=!0,paragraph:h=!0,active:g,round:f}=e,{getPrefixCls:p,direction:j,className:w,style:k}=(0,l.useComponentConfig)("skeleton"),C=p("skeleton",r),[O,$,N]=b(C);if(s||!("loading"in e)){let e,l,r=!!u,s=!!m,c=!!h;if(r){let a=Object.assign(Object.assign({prefixCls:`${C}-avatar`},s&&!c?{size:"large",shape:"square"}:{size:"large",shape:"circle"}),y(u));e=t.createElement("div",{className:`${C}-header`},t.createElement(i,Object.assign({},a)))}if(s||c){let e,a;if(s){let a=Object.assign(Object.assign({prefixCls:`${C}-title`},!r&&c?{width:"38%"}:r&&c?{width:"50%"}:{}),y(m));e=t.createElement(x,Object.assign({},a))}if(c){let e,l=Object.assign(Object.assign({prefixCls:`${C}-paragraph`},(e={},r&&s||(e.width="61%"),!r&&s?e.rows=3:e.rows=2,e)),y(h));a=t.createElement(v,Object.assign({},l))}l=t.createElement("div",{className:`${C}-content`},e,a)}let p=(0,a.default)(C,{[`${C}-with-avatar`]:r,[`${C}-active`]:g,[`${C}-rtl`]:"rtl"===j,[`${C}-round`]:f},w,n,o,$,N);return O(t.createElement("div",{className:p,style:Object.assign(Object.assign({},k),d)},e,l))}return null!=c?c:null};j.Button=e=>{let{prefixCls:s,className:n,rootClassName:o,active:d,block:c=!1,size:u="default"}=e,{getPrefixCls:m}=t.useContext(l.ConfigContext),h=m("skeleton",s),[g,f,p]=b(h),v=(0,r.default)(e,["prefixCls"]),x=(0,a.default)(h,`${h}-element`,{[`${h}-active`]:d,[`${h}-block`]:c},n,o,f,p);return g(t.createElement("div",{className:x},t.createElement(i,Object.assign({prefixCls:`${h}-button`,size:u},v))))},j.Avatar=e=>{let{prefixCls:s,className:n,rootClassName:o,active:d,shape:c="circle",size:u="default"}=e,{getPrefixCls:m}=t.useContext(l.ConfigContext),h=m("skeleton",s),[g,f,p]=b(h),v=(0,r.default)(e,["prefixCls","className"]),x=(0,a.default)(h,`${h}-element`,{[`${h}-active`]:d},n,o,f,p);return g(t.createElement("div",{className:x},t.createElement(i,Object.assign({prefixCls:`${h}-avatar`,shape:c,size:u},v))))},j.Input=e=>{let{prefixCls:s,className:n,rootClassName:o,active:d,block:c,size:u="default"}=e,{getPrefixCls:m}=t.useContext(l.ConfigContext),h=m("skeleton",s),[g,f,p]=b(h),v=(0,r.default)(e,["prefixCls"]),x=(0,a.default)(h,`${h}-element`,{[`${h}-active`]:d,[`${h}-block`]:c},n,o,f,p);return g(t.createElement("div",{className:x},t.createElement(i,Object.assign({prefixCls:`${h}-input`,size:u},v))))},j.Image=e=>{let{prefixCls:r,className:i,rootClassName:s,style:n,active:o}=e,{getPrefixCls:d}=t.useContext(l.ConfigContext),c=d("skeleton",r),[u,m,h]=b(c),g=(0,a.default)(c,`${c}-element`,{[`${c}-active`]:o},i,s,m,h);return u(t.createElement("div",{className:g},t.createElement("div",{className:(0,a.default)(`${c}-image`,i),style:n},t.createElement("svg",{viewBox:"0 0 1098 1024",xmlns:"http://www.w3.org/2000/svg",className:`${c}-image-svg`},t.createElement("title",null,"Image placeholder"),t.createElement("path",{d:"M365.714286 329.142857q0 45.714286-32.036571 77.677714t-77.677714 32.036571-77.677714-32.036571-32.036571-77.677714 32.036571-77.677714 77.677714-32.036571 77.677714 32.036571 32.036571 77.677714zM950.857143 548.571429l0 256-804.571429 0 0-109.714286 182.857143-182.857143 91.428571 91.428571 292.571429-292.571429zM1005.714286 146.285714l-914.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 694.857143q0 7.460571 5.412571 12.873143t12.873143 5.412571l914.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143l0-694.857143q0-7.460571-5.412571-12.873143t-12.873143-5.412571zM1097.142857 164.571429l0 694.857143q0 37.741714-26.843429 64.585143t-64.585143 26.843429l-914.285714 0q-37.741714 0-64.585143-26.843429t-26.843429-64.585143l0-694.857143q0-37.741714 26.843429-64.585143t64.585143-26.843429l914.285714 0q37.741714 0 64.585143 26.843429t26.843429 64.585143z",className:`${c}-image-path`})))))},j.Node=e=>{let{prefixCls:r,className:i,rootClassName:s,style:n,active:o,children:d}=e,{getPrefixCls:c}=t.useContext(l.ConfigContext),u=c("skeleton",r),[m,h,g]=b(u),f=(0,a.default)(u,`${u}-element`,{[`${u}-active`]:o},h,i,s,g);return m(t.createElement("div",{className:f},t.createElement("div",{className:(0,a.default)(`${u}-image`,i),style:n},d)))},e.s(["default",0,j],185793)},959013,e=>{"use strict";e.i(247167);var t=e.i(931067),a=e.i(271645);let l={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"}},{tag:"path",attrs:{d:"M192 474h672q8 0 8 8v60q0 8-8 8H160q-8 0-8-8v-60q0-8 8-8z"}}]},name:"plus",theme:"outlined"};var r=e.i(9583),i=a.forwardRef(function(e,i){return a.createElement(r.default,(0,t.default)({},e,{ref:i,icon:l}))});e.s(["default",0,i],959013)},269200,e=>{"use strict";var t=e.i(290571),a=e.i(271645),l=e.i(444755);let r=(0,e.i(673706).makeClassName)("Table"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement("div",{className:(0,l.tremorTwMerge)(r("root"),"overflow-auto",n)},a.default.createElement("table",Object.assign({ref:i,className:(0,l.tremorTwMerge)(r("table"),"w-full text-tremor-default","text-tremor-content","dark:text-dark-tremor-content")},o),s))});i.displayName="Table",e.s(["Table",()=>i],269200)},942232,e=>{"use strict";var t=e.i(290571),a=e.i(271645),l=e.i(444755);let r=(0,e.i(673706).makeClassName)("TableBody"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement(a.default.Fragment,null,a.default.createElement("tbody",Object.assign({ref:i,className:(0,l.tremorTwMerge)(r("root"),"align-top divide-y","divide-tremor-border","dark:divide-dark-tremor-border",n)},o),s))});i.displayName="TableBody",e.s(["TableBody",()=>i],942232)},977572,e=>{"use strict";var t=e.i(290571),a=e.i(271645),l=e.i(444755);let r=(0,e.i(673706).makeClassName)("TableCell"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement(a.default.Fragment,null,a.default.createElement("td",Object.assign({ref:i,className:(0,l.tremorTwMerge)(r("root"),"align-middle whitespace-nowrap text-left p-4",n)},o),s))});i.displayName="TableCell",e.s(["TableCell",()=>i],977572)},427612,e=>{"use strict";var t=e.i(290571),a=e.i(271645),l=e.i(444755);let r=(0,e.i(673706).makeClassName)("TableHead"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement(a.default.Fragment,null,a.default.createElement("thead",Object.assign({ref:i,className:(0,l.tremorTwMerge)(r("root"),"text-left","text-tremor-content","dark:text-dark-tremor-content",n)},o),s))});i.displayName="TableHead",e.s(["TableHead",()=>i],427612)},64848,e=>{"use strict";var t=e.i(290571),a=e.i(271645),l=e.i(444755);let r=(0,e.i(673706).makeClassName)("TableHeaderCell"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement(a.default.Fragment,null,a.default.createElement("th",Object.assign({ref:i,className:(0,l.tremorTwMerge)(r("root"),"whitespace-nowrap text-left font-semibold top-0 px-4 py-3.5","text-tremor-content-strong","dark:text-dark-tremor-content-strong",n)},o),s))});i.displayName="TableHeaderCell",e.s(["TableHeaderCell",()=>i],64848)},496020,e=>{"use strict";var t=e.i(290571),a=e.i(271645),l=e.i(444755);let r=(0,e.i(673706).makeClassName)("TableRow"),i=a.default.forwardRef((e,i)=>{let{children:s,className:n}=e,o=(0,t.__rest)(e,["children","className"]);return a.default.createElement(a.default.Fragment,null,a.default.createElement("tr",Object.assign({ref:i,className:(0,l.tremorTwMerge)(r("row"),n)},o),s))});i.displayName="TableRow",e.s(["TableRow",()=>i],496020)},68155,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.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"}))});e.s(["TrashIcon",0,a],68155)},278587,e=>{"use strict";var t=e.i(271645);let a=t.forwardRef(function(e,a){return t.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:a},e),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"}))});e.s(["RefreshIcon",0,a],278587)},207670,e=>{"use strict";function t(){for(var e,t,a=0,l="",r=arguments.length;at,"default",0,t])},625901,e=>{"use strict";var t=e.i(266027),a=e.i(621482),l=e.i(243652),r=e.i(764205),i=e.i(135214);let s=(0,l.createQueryKeys)("models"),n=(0,l.createQueryKeys)("modelHub"),o=(0,l.createQueryKeys)("allProxyModels");(0,l.createQueryKeys)("selectedTeamModels");let d=(0,l.createQueryKeys)("infiniteModels");e.s(["useAllProxyModels",0,()=>{let{accessToken:e,userId:a,userRole:l}=(0,i.default)();return(0,t.useQuery)({queryKey:o.list({}),queryFn:async()=>await (0,r.modelAvailableCall)(e,a,l,!0,null,!0,!1,"expand"),enabled:!!(e&&a&&l)})},"useInfiniteModelInfo",0,(e=50,t)=>{let{accessToken:l,userId:s,userRole:n}=(0,i.default)();return(0,a.useInfiniteQuery)({queryKey:d.list({filters:{...s&&{userId:s},...n&&{userRole:n},size:e,...t&&{search:t}}}),queryFn:async({pageParam:a})=>await (0,r.modelInfoCall)(l,s,n,a,e,t),initialPageParam:1,getNextPageParam:e=>{if(e.current_page{let{accessToken:e}=(0,i.default)();return(0,t.useQuery)({queryKey:n.list({}),queryFn:async()=>await (0,r.modelHubCall)(e),enabled:!!e})},"useModelsInfo",0,(e=1,a=50,l,n,o,d,c)=>{let{accessToken:u,userId:m,userRole:h}=(0,i.default)();return(0,t.useQuery)({queryKey:s.list({filters:{...m&&{userId:m},...h&&{userRole:h},page:e,size:a,...l&&{search:l},...n&&{modelId:n},...o&&{teamId:o},...d&&{sortBy:d},...c&&{sortOrder:c}}}),queryFn:async()=>await (0,r.modelInfoCall)(u,m,h,e,a,l,n,o,d,c),enabled:!!(u&&m&&h)})}])},621482,e=>{"use strict";var t=e.i(869230),a=e.i(992571),l=class extends t.QueryObserver{constructor(e,t){super(e,t)}bindMethods(){super.bindMethods(),this.fetchNextPage=this.fetchNextPage.bind(this),this.fetchPreviousPage=this.fetchPreviousPage.bind(this)}setOptions(e){super.setOptions({...e,behavior:(0,a.infiniteQueryBehavior)()})}getOptimisticResult(e){return e.behavior=(0,a.infiniteQueryBehavior)(),super.getOptimisticResult(e)}fetchNextPage(e){return this.fetch({...e,meta:{fetchMore:{direction:"forward"}}})}fetchPreviousPage(e){return this.fetch({...e,meta:{fetchMore:{direction:"backward"}}})}createResult(e,t){let{state:l}=e,r=super.createResult(e,t),{isFetching:i,isRefetching:s,isError:n,isRefetchError:o}=r,d=l.fetchMeta?.fetchMore?.direction,c=n&&"forward"===d,u=i&&"forward"===d,m=n&&"backward"===d,h=i&&"backward"===d;return{...r,fetchNextPage:this.fetchNextPage,fetchPreviousPage:this.fetchPreviousPage,hasNextPage:(0,a.hasNextPage)(t,l.data),hasPreviousPage:(0,a.hasPreviousPage)(t,l.data),isFetchNextPageError:c,isFetchingNextPage:u,isFetchPreviousPageError:m,isFetchingPreviousPage:h,isRefetchError:o&&!c&&!m,isRefetching:s&&!u&&!h}}},r=e.i(469637);function i(e,t){return(0,r.useBaseQuery)(e,l,t)}e.s(["useInfiniteQuery",()=>i],621482)},785242,e=>{"use strict";var t=e.i(619273),a=e.i(266027),l=e.i(912598),r=e.i(135214),i=e.i(270345),s=e.i(243652),n=e.i(764205);let o=(0,s.createQueryKeys)("teams"),d=async(e,t,a,l={})=>{try{let r=(0,n.getProxyBaseUrl)(),i=new URLSearchParams(Object.entries({team_id:l.teamID,organization_id:l.organizationID,team_alias:l.team_alias,user_id:l.userID,page:t,page_size:a,sort_by:l.sortBy,sort_order:l.sortOrder,status:"deleted"}).filter(([,e])=>null!=e).map(([e,t])=>[e,String(t)])),s=`${r?`${r}/v2/team/list`:"/v2/team/list"}?${i}`,o=await fetch(s,{method:"GET",headers:{[(0,n.getGlobalLitellmHeaderName)()]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok){let e=await o.json(),t=(0,n.deriveErrorMessage)(e);throw(0,n.handleError)(t),Error(t)}let d=await o.json();if(console.log("/team/list?status=deleted API Response:",d),d&&"object"==typeof d&&"teams"in d)return d.teams;return d}catch(e){throw console.error("Failed to list deleted teams:",e),e}},c=(0,s.createQueryKeys)("deletedTeams");e.s(["useDeletedTeams",0,(e,l,i={})=>{let{accessToken:s}=(0,r.default)();return(0,a.useQuery)({queryKey:c.list({page:e,limit:l,...i}),queryFn:async()=>await d(s,e,l,i),enabled:!!s,staleTime:3e4,placeholderData:t.keepPreviousData})},"useTeam",0,e=>{let{accessToken:t}=(0,r.default)(),i=(0,l.useQueryClient)();return(0,a.useQuery)({queryKey:o.detail(e),enabled:!!(t&&e),queryFn:async()=>{if(!t||!e)throw Error("Missing auth or teamId");return(0,n.teamInfoCall)(t,e)},initialData:()=>{if(!e)return;let t=i.getQueryData(o.list({}));return t?.find(t=>t.team_id===e)}})},"useTeams",0,()=>{let{accessToken:e,userId:t,userRole:l}=(0,r.default)();return(0,a.useQuery)({queryKey:o.list({}),queryFn:async()=>await (0,i.fetchTeams)(e,t,l,null),enabled:!!e})}])},738014,e=>{"use strict";var t=e.i(135214),a=e.i(764205),l=e.i(266027);let r=(0,e.i(243652).createQueryKeys)("users");e.s(["useCurrentUser",0,()=>{let{accessToken:e,userId:i}=(0,t.default)();return(0,l.useQuery)({queryKey:r.detail(i),queryFn:async()=>await (0,a.userGetInfoV2)(e),enabled:!!(e&&i)})}])}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/8cc98e6cf29063c4.js b/litellm/proxy/_experimental/out/_next/static/chunks/8cc98e6cf29063c4.js new file mode 100644 index 0000000000..def48bb0c9 --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/8cc98e6cf29063c4.js @@ -0,0 +1 @@ +(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,916925,e=>{"use strict";var t,r=((t={}).A2A_Agent="A2A Agent",t.AI21="Ai21",t.AI21_CHAT="Ai21 Chat",t.AIML="AI/ML API",t.AIOHTTP_OPENAI="Aiohttp Openai",t.Anthropic="Anthropic",t.ANTHROPIC_TEXT="Anthropic Text",t.AssemblyAI="AssemblyAI",t.AUTO_ROUTER="Auto Router",t.Bedrock="Amazon Bedrock",t.BedrockMantle="Amazon Bedrock Mantle",t.SageMaker="AWS SageMaker",t.Azure="Azure",t.Azure_AI_Studio="Azure AI Foundry (Studio)",t.AZURE_TEXT="Azure Text",t.BASETEN="Baseten",t.BYTEZ="Bytez",t.Cerebras="Cerebras",t.CLARIFAI="Clarifai",t.CLOUDFLARE="Cloudflare",t.CODESTRAL="Codestral",t.Cohere="Cohere",t.COHERE_CHAT="Cohere Chat",t.COMETAPI="Cometapi",t.COMPACTIFAI="Compactifai",t.Cursor="Cursor",t.Dashscope="Dashscope",t.Databricks="Databricks (Qwen API)",t.DATAROBOT="Datarobot",t.DeepInfra="DeepInfra",t.Deepgram="Deepgram",t.Deepseek="Deepseek",t.DOCKER_MODEL_RUNNER="Docker Model Runner",t.DOTPROMPT="Dotprompt",t.ElevenLabs="ElevenLabs",t.EMPOWER="Empower",t.FalAI="Fal AI",t.FEATHERLESS_AI="Featherless Ai",t.FireworksAI="Fireworks AI",t.FRIENDLIAI="Friendliai",t.GALADRIEL="Galadriel",t.GITHUB_COPILOT="Github Copilot",t.Google_AI_Studio="Google AI Studio",t.GradientAI="GradientAI",t.Groq="Groq",t.HEROKU="Heroku",t.Hosted_Vllm="vllm",t.HUGGINGFACE="Huggingface",t.HYPERBOLIC="Hyperbolic",t.Infinity="Infinity",t.JinaAI="Jina AI",t.LAMBDA_AI="Lambda Ai",t.LEMONADE="Lemonade",t.LLAMAFILE="Llamafile",t.LM_STUDIO="Lm Studio",t.LLAMA="Meta Llama",t.MARITALK="Maritalk",t.MiniMax="MiniMax",t.MistralAI="Mistral AI",t.MOONSHOT="Moonshot",t.MORPH="Morph",t.NEBIUS="Nebius",t.NLP_CLOUD="Nlp Cloud",t.NOVITA="Novita",t.NSCALE="Nscale",t.NVIDIA_NIM="Nvidia Nim",t.Ollama="Ollama",t.OLLAMA_CHAT="Ollama Chat",t.OOBABOOGA="Oobabooga",t.OpenAI="OpenAI",t.OPENAI_LIKE="Openai Like",t.OpenAI_Compatible="OpenAI-Compatible Endpoints (Together AI, etc.)",t.OpenAI_Text="OpenAI Text Completion",t.OpenAI_Text_Compatible="OpenAI-Compatible Text Completion Models (Together AI, etc.)",t.Openrouter="Openrouter",t.Oracle="Oracle Cloud Infrastructure (OCI)",t.OVHCLOUD="Ovhcloud",t.Perplexity="Perplexity",t.PETALS="Petals",t.PG_VECTOR="Pg Vector",t.PREDIBASE="Predibase",t.RECRAFT="Recraft",t.REPLICATE="Replicate",t.RunwayML="RunwayML",t.SAGEMAKER_LEGACY="Sagemaker",t.Sambanova="Sambanova",t.SAP="SAP Generative AI Hub",t.Snowflake="Snowflake",t.TEXT_COMPLETION_CODESTRAL="Text-Completion-Codestral",t.TogetherAI="TogetherAI",t.TOPAZ="Topaz",t.Triton="Triton",t.V0="V0",t.VERCEL_AI_GATEWAY="Vercel Ai Gateway",t.Vertex_AI="Vertex AI (Anthropic, Gemini, etc.)",t.VERTEX_AI_BETA="Vertex Ai Beta",t.VLLM="Vllm",t.VolcEngine="VolcEngine",t.Voyage="Voyage AI",t.WANDB="Wandb",t.WATSONX="Watsonx",t.WATSONX_TEXT="Watsonx Text",t.xAI="xAI",t.XINFERENCE="Xinference",t);let a={A2A_Agent:"a2a_agent",AI21:"ai21",AI21_CHAT:"ai21_chat",AIML:"aiml",AIOHTTP_OPENAI:"aiohttp_openai",Anthropic:"anthropic",ANTHROPIC_TEXT:"anthropic_text",AssemblyAI:"assemblyai",AUTO_ROUTER:"auto_router",Azure:"azure",Azure_AI_Studio:"azure_ai",AZURE_TEXT:"azure_text",BASETEN:"baseten",Bedrock:"bedrock",BedrockMantle:"bedrock_mantle",BYTEZ:"bytez",Cerebras:"cerebras",CLARIFAI:"clarifai",CLOUDFLARE:"cloudflare",CODESTRAL:"codestral",Cohere:"cohere",COHERE_CHAT:"cohere_chat",COMETAPI:"cometapi",COMPACTIFAI:"compactifai",Cursor:"cursor",Dashscope:"dashscope",Databricks:"databricks",DATAROBOT:"datarobot",DeepInfra:"deepinfra",Deepgram:"deepgram",Deepseek:"deepseek",DOCKER_MODEL_RUNNER:"docker_model_runner",DOTPROMPT:"dotprompt",ElevenLabs:"elevenlabs",EMPOWER:"empower",FalAI:"fal_ai",FEATHERLESS_AI:"featherless_ai",FireworksAI:"fireworks_ai",FRIENDLIAI:"friendliai",GALADRIEL:"galadriel",GITHUB_COPILOT:"github_copilot",Google_AI_Studio:"gemini",GradientAI:"gradient_ai",Groq:"groq",HEROKU:"heroku",Hosted_Vllm:"hosted_vllm",HUGGINGFACE:"huggingface",HYPERBOLIC:"hyperbolic",Infinity:"infinity",JinaAI:"jina_ai",LAMBDA_AI:"lambda_ai",LEMONADE:"lemonade",LLAMAFILE:"llamafile",LLAMA:"meta_llama",LM_STUDIO:"lm_studio",MARITALK:"maritalk",MiniMax:"minimax",MistralAI:"mistral",MOONSHOT:"moonshot",MORPH:"morph",NEBIUS:"nebius",NLP_CLOUD:"nlp_cloud",NOVITA:"novita",NSCALE:"nscale",NVIDIA_NIM:"nvidia_nim",Ollama:"ollama",OLLAMA_CHAT:"ollama_chat",OOBABOOGA:"oobabooga",OpenAI:"openai",OPENAI_LIKE:"openai_like",OpenAI_Compatible:"openai",OpenAI_Text:"text-completion-openai",OpenAI_Text_Compatible:"text-completion-openai",Openrouter:"openrouter",Oracle:"oci",OVHCLOUD:"ovhcloud",Perplexity:"perplexity",PETALS:"petals",PG_VECTOR:"pg_vector",PREDIBASE:"predibase",RECRAFT:"recraft",REPLICATE:"replicate",RunwayML:"runwayml",SAGEMAKER_LEGACY:"sagemaker",SageMaker:"sagemaker_chat",Sambanova:"sambanova",SAP:"sap",Snowflake:"snowflake",TEXT_COMPLETION_CODESTRAL:"text-completion-codestral",TogetherAI:"together_ai",TOPAZ:"topaz",Triton:"triton",V0:"v0",VERCEL_AI_GATEWAY:"vercel_ai_gateway",Vertex_AI:"vertex_ai",VERTEX_AI_BETA:"vertex_ai_beta",VLLM:"vllm",VolcEngine:"volcengine",Voyage:"voyage",WANDB:"wandb",WATSONX:"watsonx",WATSONX_TEXT:"watsonx_text",xAI:"xai",XINFERENCE:"xinference"},i="../ui/assets/logos/",o={"A2A Agent":`${i}a2a_agent.png`,Ai21:`${i}ai21.svg`,"Ai21 Chat":`${i}ai21.svg`,"AI/ML API":`${i}aiml_api.svg`,"Aiohttp Openai":`${i}openai_small.svg`,Anthropic:`${i}anthropic.svg`,"Anthropic Text":`${i}anthropic.svg`,AssemblyAI:`${i}assemblyai_small.png`,Azure:`${i}microsoft_azure.svg`,"Azure AI Foundry (Studio)":`${i}microsoft_azure.svg`,"Azure Text":`${i}microsoft_azure.svg`,Baseten:`${i}baseten.svg`,"Amazon Bedrock":`${i}bedrock.svg`,"Amazon Bedrock Mantle":`${i}bedrock.svg`,"AWS SageMaker":`${i}bedrock.svg`,Cerebras:`${i}cerebras.svg`,Cloudflare:`${i}cloudflare.svg`,Codestral:`${i}mistral.svg`,Cohere:`${i}cohere.svg`,"Cohere Chat":`${i}cohere.svg`,Cometapi:`${i}cometapi.svg`,Cursor:`${i}cursor.svg`,"Databricks (Qwen API)":`${i}databricks.svg`,Dashscope:`${i}dashscope.svg`,Deepseek:`${i}deepseek.svg`,Deepgram:`${i}deepgram.png`,DeepInfra:`${i}deepinfra.png`,ElevenLabs:`${i}elevenlabs.png`,"Fal AI":`${i}fal_ai.jpg`,"Featherless Ai":`${i}featherless.svg`,"Fireworks AI":`${i}fireworks.svg`,Friendliai:`${i}friendli.svg`,"Github Copilot":`${i}github_copilot.svg`,"Google AI Studio":`${i}google.svg`,GradientAI:`${i}gradientai.svg`,Groq:`${i}groq.svg`,vllm:`${i}vllm.png`,Huggingface:`${i}huggingface.svg`,Hyperbolic:`${i}hyperbolic.svg`,Infinity:`${i}infinity.png`,"Jina AI":`${i}jina.png`,"Lambda Ai":`${i}lambda.svg`,"Lm Studio":`${i}lmstudio.svg`,"Meta Llama":`${i}meta_llama.svg`,MiniMax:`${i}minimax.svg`,"Mistral AI":`${i}mistral.svg`,Moonshot:`${i}moonshot.svg`,Morph:`${i}morph.svg`,Nebius:`${i}nebius.svg`,Novita:`${i}novita.svg`,"Nvidia Nim":`${i}nvidia_nim.svg`,Ollama:`${i}ollama.svg`,"Ollama Chat":`${i}ollama.svg`,Oobabooga:`${i}openai_small.svg`,OpenAI:`${i}openai_small.svg`,"Openai Like":`${i}openai_small.svg`,"OpenAI Text Completion":`${i}openai_small.svg`,"OpenAI-Compatible Text Completion Models (Together AI, etc.)":`${i}openai_small.svg`,"OpenAI-Compatible Endpoints (Together AI, etc.)":`${i}openai_small.svg`,Openrouter:`${i}openrouter.svg`,"Oracle Cloud Infrastructure (OCI)":`${i}oracle.svg`,Perplexity:`${i}perplexity-ai.svg`,Recraft:`${i}recraft.svg`,Replicate:`${i}replicate.svg`,RunwayML:`${i}runwayml.png`,Sagemaker:`${i}bedrock.svg`,Sambanova:`${i}sambanova.svg`,"SAP Generative AI Hub":`${i}sap.png`,Snowflake:`${i}snowflake.svg`,"Text-Completion-Codestral":`${i}mistral.svg`,TogetherAI:`${i}togetherai.svg`,Topaz:`${i}topaz.svg`,Triton:`${i}nvidia_triton.png`,V0:`${i}v0.svg`,"Vercel Ai Gateway":`${i}vercel.svg`,"Vertex AI (Anthropic, Gemini, etc.)":`${i}google.svg`,"Vertex Ai Beta":`${i}google.svg`,Vllm:`${i}vllm.png`,VolcEngine:`${i}volcengine.png`,"Voyage AI":`${i}voyage.webp`,Watsonx:`${i}watsonx.svg`,"Watsonx Text":`${i}watsonx.svg`,xAI:`${i}xai.svg`,Xinference:`${i}xinference.svg`};e.s(["Providers",()=>r,"getPlaceholder",0,e=>{if("AI/ML API"===e)return"aiml/flux-pro/v1.1";if("Vertex AI (Anthropic, Gemini, etc.)"===e)return"gemini-pro";if("Anthropic"==e)return"claude-3-opus";if("Amazon Bedrock"==e)return"claude-3-opus";if("AWS SageMaker"==e)return"sagemaker/jumpstart-dft-meta-textgeneration-llama-2-7b";else if("Google AI Studio"==e)return"gemini-pro";else if("Azure AI Foundry (Studio)"==e)return"azure_ai/command-r-plus";else if("Azure"==e)return"my-deployment";else if("Oracle Cloud Infrastructure (OCI)"==e)return"oci/xai.grok-4";else if("Snowflake"==e)return"snowflake/mistral-7b";else if("Voyage AI"==e)return"voyage/";else if("Jina AI"==e)return"jina_ai/";else if("VolcEngine"==e)return"volcengine/";else if("DeepInfra"==e)return"deepinfra/";else if("Fal AI"==e)return"fal_ai/fal-ai/flux-pro/v1.1-ultra";else if("RunwayML"==e)return"runwayml/gen4_turbo";else if("Watsonx"===e)return"watsonx/ibm/granite-3-3-8b-instruct";else if("Cursor"===e)return"cursor/claude-4-sonnet";else return"gpt-3.5-turbo"},"getProviderLogoAndName",0,e=>{if(!e)return{logo:"",displayName:"-"};if("gemini"===e.toLowerCase()){let e="Google AI Studio";return{logo:o[e],displayName:e}}let t=Object.keys(a).find(t=>a[t].toLowerCase()===e.toLowerCase());if(!t)return{logo:"",displayName:e};let i=r[t];return{logo:o[i],displayName:i}},"getProviderModels",0,(e,t)=>{console.log(`Provider key: ${e}`);let r=a[e];console.log(`Provider mapped to: ${r}`);let i=[];return e&&"object"==typeof t&&(Object.entries(t).forEach(([e,t])=>{if(null!==t&&"object"==typeof t&&"litellm_provider"in t){let a=t.litellm_provider;(a===r||"string"==typeof a&&a.includes(r))&&i.push(e)}}),"Cohere"==e&&(console.log("Adding cohere chat models"),Object.entries(t).forEach(([e,t])=>{null!==t&&"object"==typeof t&&"litellm_provider"in t&&"cohere_chat"===t.litellm_provider&&i.push(e)})),"AWS SageMaker"==e&&(console.log("Adding sagemaker chat models"),Object.entries(t).forEach(([e,t])=>{null!==t&&"object"==typeof t&&"litellm_provider"in t&&"sagemaker_chat"===t.litellm_provider&&i.push(e)}))),i},"providerLogoMap",0,o,"provider_map",0,a])},362024,e=>{"use strict";var t=e.i(988122);e.s(["Collapse",()=>t.default])},240647,e=>{"use strict";var t=e.i(286612);e.s(["RightOutlined",()=>t.default])},152473,e=>{"use strict";var t=e.i(271645);let r={enabled:!0,leading:!1,trailing:!0,wait:0,onExecute:()=>{}};class a{constructor(e,t){this.fn=e,this._canLeadingExecute=!0,this._isPending=!1,this._executionCount=0,this._options={...r,...t}}setOptions(e){return this._options={...this._options,...e},this._options.enabled||(this._isPending=!1),this._options}getOptions(){return this._options}maybeExecute(...e){this._options.leading&&this._canLeadingExecute&&(this.executeFunction(...e),this._canLeadingExecute=!1),(this._options.leading||this._options.trailing)&&(this._isPending=!0),this._timeoutId&&clearTimeout(this._timeoutId),this._timeoutId=setTimeout(()=>{this._canLeadingExecute=!0,this._isPending=!1,this._options.trailing&&this.executeFunction(...e)},this._options.wait)}executeFunction(...e){this._options.enabled&&(this.fn(...e),this._executionCount++,this._options.onExecute(this))}cancel(){this._timeoutId&&(clearTimeout(this._timeoutId),this._canLeadingExecute=!0,this._isPending=!1)}getExecutionCount(){return this._executionCount}getIsPending(){return this._options.enabled&&this._isPending}}function i(e,r){let[i,o]=(0,t.useState)(e),n=function(e,r){let[i]=(0,t.useState)(()=>{var t;return Object.getOwnPropertyNames(Object.getPrototypeOf(t=new a(e,r))).filter(e=>"function"==typeof t[e]).reduce((e,r)=>{let a=t[r];return"function"==typeof a&&(e[r]=a.bind(t)),e},{})});return i.setOptions(r),i}(o,r);return[i,n.maybeExecute,n]}e.s(["useDebouncedState",()=>i],152473)},738014,e=>{"use strict";var t=e.i(135214),r=e.i(764205),a=e.i(266027);let i=(0,e.i(243652).createQueryKeys)("users");e.s(["useCurrentUser",0,()=>{let{accessToken:e,userId:o}=(0,t.default)();return(0,a.useQuery)({queryKey:i.detail(o),queryFn:async()=>await (0,r.userGetInfoV2)(e),enabled:!!(e&&o)})}])},906579,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(361275),i=e.i(702779),o=e.i(763731),n=e.i(242064);e.i(296059);var s=e.i(915654),l=e.i(694758),c=e.i(183293),u=e.i(403541),d=e.i(246422),m=e.i(838378);let g=new l.Keyframes("antStatusProcessing",{"0%":{transform:"scale(0.8)",opacity:.5},"100%":{transform:"scale(2.4)",opacity:0}}),p=new l.Keyframes("antZoomBadgeIn",{"0%":{transform:"scale(0) translate(50%, -50%)",opacity:0},"100%":{transform:"scale(1) translate(50%, -50%)"}}),f=new l.Keyframes("antZoomBadgeOut",{"0%":{transform:"scale(1) translate(50%, -50%)"},"100%":{transform:"scale(0) translate(50%, -50%)",opacity:0}}),h=new l.Keyframes("antNoWrapperZoomBadgeIn",{"0%":{transform:"scale(0)",opacity:0},"100%":{transform:"scale(1)"}}),b=new l.Keyframes("antNoWrapperZoomBadgeOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0)",opacity:0}}),v=new l.Keyframes("antBadgeLoadingCircle",{"0%":{transformOrigin:"50%"},"100%":{transform:"translate(50%, -50%) rotate(360deg)",transformOrigin:"50%"}}),A=e=>{let{fontHeight:t,lineWidth:r,marginXS:a,colorBorderBg:i}=e,o=e.colorTextLightSolid,n=e.colorError,s=e.colorErrorHover;return(0,m.mergeToken)(e,{badgeFontHeight:t,badgeShadowSize:r,badgeTextColor:o,badgeColor:n,badgeColorHover:s,badgeShadowColor:i,badgeProcessingDuration:"1.2s",badgeRibbonOffset:a,badgeRibbonCornerTransform:"scaleY(0.75)",badgeRibbonCornerFilter:"brightness(75%)"})},y=e=>{let{fontSize:t,lineHeight:r,fontSizeSM:a,lineWidth:i}=e;return{indicatorZIndex:"auto",indicatorHeight:Math.round(t*r)-2*i,indicatorHeightSM:t,dotSize:a/2,textFontSize:a,textFontSizeSM:a,textFontWeight:"normal",statusSize:a/2}},O=(0,d.genStyleHooks)("Badge",e=>(e=>{let{componentCls:t,iconCls:r,antCls:a,badgeShadowSize:i,textFontSize:o,textFontSizeSM:n,statusSize:l,dotSize:d,textFontWeight:m,indicatorHeight:A,indicatorHeightSM:y,marginXS:O,calc:x}=e,C=`${a}-scroll-number`,E=(0,u.genPresetColor)(e,(e,{darkColor:r})=>({[`&${t} ${t}-color-${e}`]:{background:r,[`&:not(${t}-count)`]:{color:r},"a:hover &":{background:r}}}));return{[t]:Object.assign(Object.assign(Object.assign(Object.assign({},(0,c.resetComponent)(e)),{position:"relative",display:"inline-block",width:"fit-content",lineHeight:1,[`${t}-count`]:{display:"inline-flex",justifyContent:"center",zIndex:e.indicatorZIndex,minWidth:A,height:A,color:e.badgeTextColor,fontWeight:m,fontSize:o,lineHeight:(0,s.unit)(A),whiteSpace:"nowrap",textAlign:"center",background:e.badgeColor,borderRadius:x(A).div(2).equal(),boxShadow:`0 0 0 ${(0,s.unit)(i)} ${e.badgeShadowColor}`,transition:`background ${e.motionDurationMid}`,a:{color:e.badgeTextColor},"a:hover":{color:e.badgeTextColor},"a:hover &":{background:e.badgeColorHover}},[`${t}-count-sm`]:{minWidth:y,height:y,fontSize:n,lineHeight:(0,s.unit)(y),borderRadius:x(y).div(2).equal()},[`${t}-multiple-words`]:{padding:`0 ${(0,s.unit)(e.paddingXS)}`,bdi:{unicodeBidi:"plaintext"}},[`${t}-dot`]:{zIndex:e.indicatorZIndex,width:d,minWidth:d,height:d,background:e.badgeColor,borderRadius:"100%",boxShadow:`0 0 0 ${(0,s.unit)(i)} ${e.badgeShadowColor}`},[`${t}-count, ${t}-dot, ${C}-custom-component`]:{position:"absolute",top:0,insetInlineEnd:0,transform:"translate(50%, -50%)",transformOrigin:"100% 0%",[`&${r}-spin`]:{animationName:v,animationDuration:"1s",animationIterationCount:"infinite",animationTimingFunction:"linear"}},[`&${t}-status`]:{lineHeight:"inherit",verticalAlign:"baseline",[`${t}-status-dot`]:{position:"relative",top:-1,display:"inline-block",width:l,height:l,verticalAlign:"middle",borderRadius:"50%"},[`${t}-status-success`]:{backgroundColor:e.colorSuccess},[`${t}-status-processing`]:{overflow:"visible",color:e.colorInfo,backgroundColor:e.colorInfo,borderColor:"currentcolor","&::after":{position:"absolute",top:0,insetInlineStart:0,width:"100%",height:"100%",borderWidth:i,borderStyle:"solid",borderColor:"inherit",borderRadius:"50%",animationName:g,animationDuration:e.badgeProcessingDuration,animationIterationCount:"infinite",animationTimingFunction:"ease-in-out",content:'""'}},[`${t}-status-default`]:{backgroundColor:e.colorTextPlaceholder},[`${t}-status-error`]:{backgroundColor:e.colorError},[`${t}-status-warning`]:{backgroundColor:e.colorWarning},[`${t}-status-text`]:{marginInlineStart:O,color:e.colorText,fontSize:e.fontSize}}}),E),{[`${t}-zoom-appear, ${t}-zoom-enter`]:{animationName:p,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack,animationFillMode:"both"},[`${t}-zoom-leave`]:{animationName:f,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack,animationFillMode:"both"},[`&${t}-not-a-wrapper`]:{[`${t}-zoom-appear, ${t}-zoom-enter`]:{animationName:h,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack},[`${t}-zoom-leave`]:{animationName:b,animationDuration:e.motionDurationSlow,animationTimingFunction:e.motionEaseOutBack},[`&:not(${t}-status)`]:{verticalAlign:"middle"},[`${C}-custom-component, ${t}-count`]:{transform:"none"},[`${C}-custom-component, ${C}`]:{position:"relative",top:"auto",display:"block",transformOrigin:"50% 50%"}},[C]:{overflow:"hidden",transition:`all ${e.motionDurationMid} ${e.motionEaseOutBack}`,[`${C}-only`]:{position:"relative",display:"inline-block",height:A,transition:`all ${e.motionDurationSlow} ${e.motionEaseOutBack}`,WebkitTransformStyle:"preserve-3d",WebkitBackfaceVisibility:"hidden",[`> p${C}-only-unit`]:{height:A,margin:0,WebkitTransformStyle:"preserve-3d",WebkitBackfaceVisibility:"hidden"}},[`${C}-symbol`]:{verticalAlign:"top"}},"&-rtl":{direction:"rtl",[`${t}-count, ${t}-dot, ${C}-custom-component`]:{transform:"translate(-50%, -50%)"}}})}})(A(e)),y),x=(0,d.genStyleHooks)(["Badge","Ribbon"],e=>(e=>{let{antCls:t,badgeFontHeight:r,marginXS:a,badgeRibbonOffset:i,calc:o}=e,n=`${t}-ribbon`,l=`${t}-ribbon-wrapper`,d=(0,u.genPresetColor)(e,(e,{darkColor:t})=>({[`&${n}-color-${e}`]:{background:t,color:t}}));return{[l]:{position:"relative"},[n]:Object.assign(Object.assign(Object.assign(Object.assign({},(0,c.resetComponent)(e)),{position:"absolute",top:a,padding:`0 ${(0,s.unit)(e.paddingXS)}`,color:e.colorPrimary,lineHeight:(0,s.unit)(r),whiteSpace:"nowrap",backgroundColor:e.colorPrimary,borderRadius:e.borderRadiusSM,[`${n}-text`]:{color:e.badgeTextColor},[`${n}-corner`]:{position:"absolute",top:"100%",width:i,height:i,color:"currentcolor",border:`${(0,s.unit)(o(i).div(2).equal())} solid`,transform:e.badgeRibbonCornerTransform,transformOrigin:"top",filter:e.badgeRibbonCornerFilter}}),d),{[`&${n}-placement-end`]:{insetInlineEnd:o(i).mul(-1).equal(),borderEndEndRadius:0,[`${n}-corner`]:{insetInlineEnd:0,borderInlineEndColor:"transparent",borderBlockEndColor:"transparent"}},[`&${n}-placement-start`]:{insetInlineStart:o(i).mul(-1).equal(),borderEndStartRadius:0,[`${n}-corner`]:{insetInlineStart:0,borderBlockEndColor:"transparent",borderInlineStartColor:"transparent"}},"&-rtl":{direction:"rtl"}})}})(A(e)),y),C=e=>{let a,{prefixCls:i,value:o,current:n,offset:s=0}=e;return s&&(a={position:"absolute",top:`${s}00%`,left:0}),t.createElement("span",{style:a,className:(0,r.default)(`${i}-only-unit`,{current:n})},o)},E=e=>{let r,a,{prefixCls:i,count:o,value:n}=e,s=Number(n),l=Math.abs(o),[c,u]=t.useState(s),[d,m]=t.useState(l),g=()=>{u(s),m(l)};if(t.useEffect(()=>{let e=setTimeout(g,1e3);return()=>clearTimeout(e)},[s]),c===s||Number.isNaN(s)||Number.isNaN(c))r=[t.createElement(C,Object.assign({},e,{key:s,current:!0}))],a={transition:"none"};else{r=[];let i=s+10,o=[];for(let e=s;e<=i;e+=1)o.push(e);let n=de%10===c);r=(n<0?o.slice(0,u+1):o.slice(u)).map((r,a)=>t.createElement(C,Object.assign({},e,{key:r,value:r%10,offset:n<0?a-u:a,current:a===u}))),a={transform:`translateY(${-function(e,t,r){let a=e,i=0;for(;(a+10)%10!==t;)a+=r,i+=r;return i}(c,s,n)}00%)`}}return t.createElement("span",{className:`${i}-only`,style:a,onTransitionEnd:g},r)};var I=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,a=Object.getOwnPropertySymbols(e);it.indexOf(a[i])&&Object.prototype.propertyIsEnumerable.call(e,a[i])&&(r[a[i]]=e[a[i]]);return r};let $=t.forwardRef((e,a)=>{let{prefixCls:i,count:s,className:l,motionClassName:c,style:u,title:d,show:m,component:g="sup",children:p}=e,f=I(e,["prefixCls","count","className","motionClassName","style","title","show","component","children"]),{getPrefixCls:h}=t.useContext(n.ConfigContext),b=h("scroll-number",i),v=Object.assign(Object.assign({},f),{"data-show":m,style:u,className:(0,r.default)(b,l,c),title:d}),A=s;if(s&&Number(s)%1==0){let e=String(s).split("");A=t.createElement("bdi",null,e.map((r,a)=>t.createElement(E,{prefixCls:b,count:Number(s),value:r,key:e.length-a})))}return((null==u?void 0:u.borderColor)&&(v.style=Object.assign(Object.assign({},u),{boxShadow:`0 0 0 1px ${u.borderColor} inset`})),p)?(0,o.cloneElement)(p,e=>({className:(0,r.default)(`${b}-custom-component`,null==e?void 0:e.className,c)})):t.createElement(g,Object.assign({},v,{ref:a}),A)});var _=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,a=Object.getOwnPropertySymbols(e);it.indexOf(a[i])&&Object.prototype.propertyIsEnumerable.call(e,a[i])&&(r[a[i]]=e[a[i]]);return r};let T=t.forwardRef((e,s)=>{var l,c,u,d,m;let{prefixCls:g,scrollNumberPrefixCls:p,children:f,status:h,text:b,color:v,count:A=null,overflowCount:y=99,dot:x=!1,size:C="default",title:E,offset:I,style:T,className:w,rootClassName:S,classNames:N,styles:M,showZero:R=!1}=e,P=_(e,["prefixCls","scrollNumberPrefixCls","children","status","text","color","count","overflowCount","dot","size","title","offset","style","className","rootClassName","classNames","styles","showZero"]),{getPrefixCls:k,direction:j,badge:L}=t.useContext(n.ConfigContext),D=k("badge",g),[B,F,z]=O(D),G=A>y?`${y}+`:A,H="0"===G||0===G||"0"===b||0===b,V=null===A||H&&!R,W=(null!=h||null!=v)&&V,K=null!=h||!H,U=x&&!H,q=U?"":G,X=(0,t.useMemo)(()=>((null==q||""===q)&&(null==b||""===b)||H&&!R)&&!U,[q,H,R,U,b]),Q=(0,t.useRef)(A);X||(Q.current=A);let Z=Q.current,Y=(0,t.useRef)(q);X||(Y.current=q);let J=Y.current,ee=(0,t.useRef)(U);X||(ee.current=U);let et=(0,t.useMemo)(()=>{if(!I)return Object.assign(Object.assign({},null==L?void 0:L.style),T);let e={marginTop:I[1]};return"rtl"===j?e.left=Number.parseInt(I[0],10):e.right=-Number.parseInt(I[0],10),Object.assign(Object.assign(Object.assign({},e),null==L?void 0:L.style),T)},[j,I,T,null==L?void 0:L.style]),er=null!=E?E:"string"==typeof Z||"number"==typeof Z?Z:void 0,ea=!X&&(0===b?R:!!b&&!0!==b),ei=ea?t.createElement("span",{className:`${D}-status-text`},b):null,eo=Z&&"object"==typeof Z?(0,o.cloneElement)(Z,e=>({style:Object.assign(Object.assign({},et),e.style)})):void 0,en=(0,i.isPresetColor)(v,!1),es=(0,r.default)(null==N?void 0:N.indicator,null==(l=null==L?void 0:L.classNames)?void 0:l.indicator,{[`${D}-status-dot`]:W,[`${D}-status-${h}`]:!!h,[`${D}-color-${v}`]:en}),el={};v&&!en&&(el.color=v,el.background=v);let ec=(0,r.default)(D,{[`${D}-status`]:W,[`${D}-not-a-wrapper`]:!f,[`${D}-rtl`]:"rtl"===j},w,S,null==L?void 0:L.className,null==(c=null==L?void 0:L.classNames)?void 0:c.root,null==N?void 0:N.root,F,z);if(!f&&W&&(b||K||!V)){let e=et.color;return B(t.createElement("span",Object.assign({},P,{className:ec,style:Object.assign(Object.assign(Object.assign({},null==M?void 0:M.root),null==(u=null==L?void 0:L.styles)?void 0:u.root),et)}),t.createElement("span",{className:es,style:Object.assign(Object.assign(Object.assign({},null==M?void 0:M.indicator),null==(d=null==L?void 0:L.styles)?void 0:d.indicator),el)}),ea&&t.createElement("span",{style:{color:e},className:`${D}-status-text`},b)))}return B(t.createElement("span",Object.assign({ref:s},P,{className:ec,style:Object.assign(Object.assign({},null==(m=null==L?void 0:L.styles)?void 0:m.root),null==M?void 0:M.root)}),f,t.createElement(a.default,{visible:!X,motionName:`${D}-zoom`,motionAppear:!1,motionDeadline:1e3},({className:e})=>{var a,i;let o=k("scroll-number",p),n=ee.current,s=(0,r.default)(null==N?void 0:N.indicator,null==(a=null==L?void 0:L.classNames)?void 0:a.indicator,{[`${D}-dot`]:n,[`${D}-count`]:!n,[`${D}-count-sm`]:"small"===C,[`${D}-multiple-words`]:!n&&J&&J.toString().length>1,[`${D}-status-${h}`]:!!h,[`${D}-color-${v}`]:en}),l=Object.assign(Object.assign(Object.assign({},null==M?void 0:M.indicator),null==(i=null==L?void 0:L.styles)?void 0:i.indicator),et);return v&&!en&&((l=l||{}).background=v),t.createElement($,{prefixCls:o,show:!X,motionClassName:e,className:s,count:J,title:er,style:l,key:"scrollNumber"},eo)}),ei))});T.Ribbon=e=>{let{className:a,prefixCls:o,style:s,color:l,children:c,text:u,placement:d="end",rootClassName:m}=e,{getPrefixCls:g,direction:p}=t.useContext(n.ConfigContext),f=g("ribbon",o),h=`${f}-wrapper`,[b,v,A]=x(f,h),y=(0,i.isPresetColor)(l,!1),O=(0,r.default)(f,`${f}-placement-${d}`,{[`${f}-rtl`]:"rtl"===p,[`${f}-color-${l}`]:y},a),C={},E={};return l&&!y&&(C.background=l,E.color=l),b(t.createElement("div",{className:(0,r.default)(h,m,v,A)},c,t.createElement("div",{className:(0,r.default)(O,v),style:Object.assign(Object.assign({},C),s)},t.createElement("span",{className:`${f}-text`},u),t.createElement("div",{className:`${f}-corner`,style:E}))))},e.s(["Badge",0,T],906579)},621482,e=>{"use strict";var t=e.i(869230),r=e.i(992571),a=class extends t.QueryObserver{constructor(e,t){super(e,t)}bindMethods(){super.bindMethods(),this.fetchNextPage=this.fetchNextPage.bind(this),this.fetchPreviousPage=this.fetchPreviousPage.bind(this)}setOptions(e){super.setOptions({...e,behavior:(0,r.infiniteQueryBehavior)()})}getOptimisticResult(e){return e.behavior=(0,r.infiniteQueryBehavior)(),super.getOptimisticResult(e)}fetchNextPage(e){return this.fetch({...e,meta:{fetchMore:{direction:"forward"}}})}fetchPreviousPage(e){return this.fetch({...e,meta:{fetchMore:{direction:"backward"}}})}createResult(e,t){let{state:a}=e,i=super.createResult(e,t),{isFetching:o,isRefetching:n,isError:s,isRefetchError:l}=i,c=a.fetchMeta?.fetchMore?.direction,u=s&&"forward"===c,d=o&&"forward"===c,m=s&&"backward"===c,g=o&&"backward"===c;return{...i,fetchNextPage:this.fetchNextPage,fetchPreviousPage:this.fetchPreviousPage,hasNextPage:(0,r.hasNextPage)(t,a.data),hasPreviousPage:(0,r.hasPreviousPage)(t,a.data),isFetchNextPageError:u,isFetchingNextPage:d,isFetchPreviousPageError:m,isFetchingPreviousPage:g,isRefetchError:l&&!u&&!m,isRefetching:n&&!d&&!g}}},i=e.i(469637);function o(e,t){return(0,i.useBaseQuery)(e,a,t)}e.s(["useInfiniteQuery",()=>o],621482)},785242,e=>{"use strict";var t=e.i(619273),r=e.i(266027),a=e.i(912598),i=e.i(135214),o=e.i(270345),n=e.i(243652),s=e.i(764205);let l=(0,n.createQueryKeys)("teams"),c=async(e,t,r,a={})=>{try{let i=(0,s.getProxyBaseUrl)(),o=new URLSearchParams(Object.entries({team_id:a.teamID,organization_id:a.organizationID,team_alias:a.team_alias,user_id:a.userID,page:t,page_size:r,sort_by:a.sortBy,sort_order:a.sortOrder,status:"deleted"}).filter(([,e])=>null!=e).map(([e,t])=>[e,String(t)])),n=`${i?`${i}/v2/team/list`:"/v2/team/list"}?${o}`,l=await fetch(n,{method:"GET",headers:{[(0,s.getGlobalLitellmHeaderName)()]:`Bearer ${e}`,"Content-Type":"application/json"}});if(!l.ok){let e=await l.json(),t=(0,s.deriveErrorMessage)(e);throw(0,s.handleError)(t),Error(t)}let c=await l.json();if(console.log("/team/list?status=deleted API Response:",c),c&&"object"==typeof c&&"teams"in c)return c.teams;return c}catch(e){throw console.error("Failed to list deleted teams:",e),e}},u=(0,n.createQueryKeys)("deletedTeams");e.s(["useDeletedTeams",0,(e,a,o={})=>{let{accessToken:n}=(0,i.default)();return(0,r.useQuery)({queryKey:u.list({page:e,limit:a,...o}),queryFn:async()=>await c(n,e,a,o),enabled:!!n,staleTime:3e4,placeholderData:t.keepPreviousData})},"useTeam",0,e=>{let{accessToken:t}=(0,i.default)(),o=(0,a.useQueryClient)();return(0,r.useQuery)({queryKey:l.detail(e),enabled:!!(t&&e),queryFn:async()=>{if(!t||!e)throw Error("Missing auth or teamId");return(0,s.teamInfoCall)(t,e)},initialData:()=>{if(!e)return;let t=o.getQueryData(l.list({}));return t?.find(t=>t.team_id===e)}})},"useTeams",0,()=>{let{accessToken:e,userId:t,userRole:a}=(0,i.default)();return(0,r.useQuery)({queryKey:l.list({}),queryFn:async()=>await (0,o.fetchTeams)(e,t,a,null),enabled:!!e})}])},980187,e=>{"use strict";e.s(["createTeamAliasMap",0,e=>e?e.reduce((e,t)=>(e[t.team_id]=t.team_alias,e),{}):{},"resolveTeamAliasFromTeamID",0,(e,t)=>{let r=t.find(t=>t.team_id===e);return r?r.team_alias:null}])},571303,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(115504);function i({className:e="",...i}){var o,n;let s=(0,r.useId)();return o=()=>{let e=document.getAnimations().filter(e=>e instanceof CSSAnimation&&"spin"===e.animationName),t=e.find(e=>e.effect.target?.getAttribute("data-spinner-id")===s),r=e.find(e=>e.effect instanceof KeyframeEffect&&e.effect.target?.getAttribute("data-spinner-id")!==s);t&&r&&(t.currentTime=r.currentTime)},n=[s],(0,r.useLayoutEffect)(o,n),(0,t.jsxs)("svg",{"data-spinner-id":s,className:(0,a.cx)("pointer-events-none size-12 animate-spin text-current",e),fill:"none",viewBox:"0 0 24 24",...i,children:[(0,t.jsx)("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),(0,t.jsx)("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]})}e.s(["UiLoadingSpinner",()=>i],571303)},366283,e=>{"use strict";var t=e.i(290571),r=e.i(271645),a=e.i(95779),i=e.i(444755),o=e.i(673706);let n=(0,o.makeClassName)("Callout"),s=r.default.forwardRef((e,s)=>{let{title:l,icon:c,color:u,className:d,children:m}=e,g=(0,t.__rest)(e,["title","icon","color","className","children"]);return r.default.createElement("div",Object.assign({ref:s,className:(0,i.tremorTwMerge)(n("root"),"flex flex-col overflow-hidden rounded-tremor-default text-tremor-default border-l-4 py-3 pr-3 pl-4",u?(0,i.tremorTwMerge)((0,o.getColorClassNames)(u,a.colorPalette.background).bgColor,(0,o.getColorClassNames)(u,a.colorPalette.darkBorder).borderColor,(0,o.getColorClassNames)(u,a.colorPalette.darkText).textColor,"dark:bg-opacity-10 bg-opacity-10"):(0,i.tremorTwMerge)("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"),d)},g),r.default.createElement("div",{className:(0,i.tremorTwMerge)(n("header"),"flex items-start")},c?r.default.createElement(c,{className:(0,i.tremorTwMerge)(n("icon"),"flex-none h-5 w-5 mr-1.5")}):null,r.default.createElement("h4",{className:(0,i.tremorTwMerge)(n("title"),"font-semibold")},l)),r.default.createElement("p",{className:(0,i.tremorTwMerge)(n("body"),"overflow-y-auto",m?"mt-2":"")},m))});s.displayName="Callout",e.s(["Callout",()=>s],366283)},418371,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(916925);e.s(["ProviderLogo",0,({provider:e,className:i="w-4 h-4"})=>{let[o,n]=(0,r.useState)(!1),{logo:s}=(0,a.getProviderLogoAndName)(e);return o||!s?(0,t.jsx)("div",{className:`${i} rounded-full bg-gray-200 flex items-center justify-center text-xs`,children:e?.charAt(0)||"-"}):(0,t.jsx)("img",{src:s,alt:`${e} logo`,className:i,onError:()=>n(!0)})}])},37091,e=>{"use strict";var t=e.i(290571),r=e.i(95779),a=e.i(444755),i=e.i(673706),o=e.i(271645);let n=o.default.forwardRef((e,n)=>{let{color:s,children:l,className:c}=e,u=(0,t.__rest)(e,["color","children","className"]);return o.default.createElement("p",Object.assign({ref:n,className:(0,a.tremorTwMerge)(s?(0,i.getColorClassNames)(s,r.colorPalette.lightText).textColor:"text-tremor-content-emphasis dark:text-dark-tremor-content-emphasis",c)},u),l)});n.displayName="Subtitle",e.s(["Subtitle",()=>n],37091)},214541,e=>{"use strict";var t=e.i(271645),r=e.i(135214),a=e.i(270345);e.s(["default",0,()=>{let[e,i]=(0,t.useState)([]),{accessToken:o,userId:n,userRole:s}=(0,r.default)();return(0,t.useEffect)(()=>{(async()=>{i(await (0,a.fetchTeams)(o,n,s,null))})()},[o,n,s]),{teams:e,setTeams:i}}])},439189,435684,96226,497245,e=>{"use strict";function t(e){let t=Object.prototype.toString.call(e);return e instanceof Date||"object"==typeof e&&"[object Date]"===t?new e.constructor(+e):new Date("number"==typeof e||"[object Number]"===t||"string"==typeof e||"[object String]"===t?e:NaN)}function r(e,t){return e instanceof Date?new e.constructor(t):new Date(t)}function a(e,a){let i=t(e);return isNaN(a)?r(e,NaN):(a&&i.setDate(i.getDate()+a),i)}function i(e,a){let i=t(e);if(isNaN(a))return r(e,NaN);if(!a)return i;let o=i.getDate(),n=r(e,i.getTime());return(n.setMonth(i.getMonth()+a+1,0),o>=n.getDate())?n:(i.setFullYear(n.getFullYear(),n.getMonth(),o),i)}e.s(["toDate",()=>t],435684),e.s(["constructFrom",()=>r],96226),e.s(["addDays",()=>a],439189),e.s(["addMonths",()=>i],497245)},891547,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(199133),i=e.i(764205);e.s(["default",0,({onChange:e,value:o,className:n,accessToken:s,disabled:l})=>{let[c,u]=(0,r.useState)([]),[d,m]=(0,r.useState)(!1);return(0,r.useEffect)(()=>{(async()=>{if(s){m(!0);try{let e=await (0,i.getGuardrailsList)(s);console.log("Guardrails response:",e),e.guardrails&&(console.log("Guardrails data:",e.guardrails),u(e.guardrails))}catch(e){console.error("Error fetching guardrails:",e)}finally{m(!1)}}})()},[s]),(0,t.jsx)("div",{children:(0,t.jsx)(a.Select,{mode:"multiple",disabled:l,placeholder:l?"Setting guardrails is a premium feature.":"Select guardrails",onChange:t=>{console.log("Selected guardrails:",t),e(t)},value:o,loading:d,className:n,allowClear:!0,options:c.map(e=>(console.log("Mapping guardrail:",e),{label:`${e.guardrail_name}`,value:e.guardrail_name})),optionFilterProp:"label",showSearch:!0,style:{width:"100%"}})})}])},921511,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(199133),i=e.i(764205);function o(e){return e.filter(e=>(e.version_status??"draft")!=="draft").map(e=>{var t;let r=e.version_number??1,a=e.version_status??"draft";return{label:`${e.policy_name} — v${r} (${a})${e.description?` — ${e.description}`:""}`,value:"production"===a?e.policy_name:e.policy_id?(t=e.policy_id,`policy_${t}`):e.policy_name}})}e.s(["default",0,({onChange:e,value:n,className:s,accessToken:l,disabled:c,onPoliciesLoaded:u})=>{let[d,m]=(0,r.useState)([]),[g,p]=(0,r.useState)(!1);return(0,r.useEffect)(()=>{(async()=>{if(l){p(!0);try{let e=await (0,i.getPoliciesList)(l);e.policies&&(m(e.policies),u?.(e.policies))}catch(e){console.error("Error fetching policies:",e)}finally{p(!1)}}})()},[l,u]),(0,t.jsx)("div",{children:(0,t.jsx)(a.Select,{mode:"multiple",disabled:c,placeholder:c?"Setting policies is a premium feature.":"Select policies (production or published versions)",onChange:t=>{e(t)},value:n,loading:g,className:s,allowClear:!0,options:o(d),optionFilterProp:"label",showSearch:!0,style:{width:"100%"}})})},"getPolicyOptionEntries",()=>o])},637235,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let a={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"};var i=e.i(9583),o=r.forwardRef(function(e,o){return r.createElement(i.default,(0,t.default)({},e,{ref:o,icon:a}))});e.s(["ClockCircleOutlined",0,o],637235)},646563,e=>{"use strict";var t=e.i(959013);e.s(["PlusOutlined",()=>t.default])},447566,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let a={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M872 474H286.9l350.2-304c5.6-4.9 2.2-14-5.2-14h-88.5c-3.9 0-7.6 1.4-10.5 3.9L155 487.8a31.96 31.96 0 000 48.3L535.1 866c1.5 1.3 3.3 2 5.2 2h91.5c7.4 0 10.8-9.2 5.2-14L286.9 550H872c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"}}]},name:"arrow-left",theme:"outlined"};var i=e.i(9583),o=r.forwardRef(function(e,o){return r.createElement(i.default,(0,t.default)({},e,{ref:o,icon:a}))});e.s(["ArrowLeftOutlined",0,o],447566)},954616,e=>{"use strict";var t=e.i(271645),r=e.i(114272),a=e.i(540143),i=e.i(915823),o=e.i(619273),n=class extends i.Subscribable{#e;#t=void 0;#r;#a;constructor(e,t){super(),this.#e=e,this.setOptions(t),this.bindMethods(),this.#i()}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(e){let t=this.options;this.options=this.#e.defaultMutationOptions(e),(0,o.shallowEqualObjects)(this.options,t)||this.#e.getMutationCache().notify({type:"observerOptionsUpdated",mutation:this.#r,observer:this}),t?.mutationKey&&this.options.mutationKey&&(0,o.hashKey)(t.mutationKey)!==(0,o.hashKey)(this.options.mutationKey)?this.reset():this.#r?.state.status==="pending"&&this.#r.setOptions(this.options)}onUnsubscribe(){this.hasListeners()||this.#r?.removeObserver(this)}onMutationUpdate(e){this.#i(),this.#o(e)}getCurrentResult(){return this.#t}reset(){this.#r?.removeObserver(this),this.#r=void 0,this.#i(),this.#o()}mutate(e,t){return this.#a=t,this.#r?.removeObserver(this),this.#r=this.#e.getMutationCache().build(this.#e,this.options),this.#r.addObserver(this),this.#r.execute(e)}#i(){let e=this.#r?.state??(0,r.getDefaultState)();this.#t={...e,isPending:"pending"===e.status,isSuccess:"success"===e.status,isError:"error"===e.status,isIdle:"idle"===e.status,mutate:this.mutate,reset:this.reset}}#o(e){a.notifyManager.batch(()=>{if(this.#a&&this.hasListeners()){let t=this.#t.variables,r=this.#t.context,a={client:this.#e,meta:this.options.meta,mutationKey:this.options.mutationKey};if(e?.type==="success"){try{this.#a.onSuccess?.(e.data,t,r,a)}catch(e){Promise.reject(e)}try{this.#a.onSettled?.(e.data,null,t,r,a)}catch(e){Promise.reject(e)}}else if(e?.type==="error"){try{this.#a.onError?.(e.error,t,r,a)}catch(e){Promise.reject(e)}try{this.#a.onSettled?.(void 0,e.error,t,r,a)}catch(e){Promise.reject(e)}}}this.listeners.forEach(e=>{e(this.#t)})})}},s=e.i(912598);function l(e,r){let i=(0,s.useQueryClient)(r),[l]=t.useState(()=>new n(i,e));t.useEffect(()=>{l.setOptions(e)},[l,e]);let c=t.useSyncExternalStore(t.useCallback(e=>l.subscribe(a.notifyManager.batchCalls(e)),[l]),()=>l.getCurrentResult(),()=>l.getCurrentResult()),u=t.useCallback((e,t)=>{l.mutate(e,t).catch(o.noop)},[l]);if(c.error&&(0,o.shouldThrowError)(l.options.throwOnError,[c.error]))throw c.error;return{...c,mutate:u,mutateAsync:c.mutate}}e.s(["useMutation",()=>l],954616)},525720,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(529681),i=e.i(908286),o=e.i(242064),n=e.i(246422),s=e.i(838378);let l=["wrap","nowrap","wrap-reverse"],c=["flex-start","flex-end","start","end","center","space-between","space-around","space-evenly","stretch","normal","left","right"],u=["center","start","end","flex-start","flex-end","self-start","self-end","baseline","normal","stretch"],d=function(e,t){let a,i,o;return(0,r.default)(Object.assign(Object.assign(Object.assign({},(a=!0===t.wrap?"wrap":t.wrap,{[`${e}-wrap-${a}`]:a&&l.includes(a)})),(i={},u.forEach(r=>{i[`${e}-align-${r}`]=t.align===r}),i[`${e}-align-stretch`]=!t.align&&!!t.vertical,i)),(o={},c.forEach(r=>{o[`${e}-justify-${r}`]=t.justify===r}),o)))},m=(0,n.genStyleHooks)("Flex",e=>{let{paddingXS:t,padding:r,paddingLG:a}=e,i=(0,s.mergeToken)(e,{flexGapSM:t,flexGap:r,flexGapLG:a});return[(e=>{let{componentCls:t}=e;return{[t]:{display:"flex",margin:0,padding:0,"&-vertical":{flexDirection:"column"},"&-rtl":{direction:"rtl"},"&:empty":{display:"none"}}}})(i),(e=>{let{componentCls:t}=e;return{[t]:{"&-gap-small":{gap:e.flexGapSM},"&-gap-middle":{gap:e.flexGap},"&-gap-large":{gap:e.flexGapLG}}}})(i),(e=>{let{componentCls:t}=e,r={};return l.forEach(e=>{r[`${t}-wrap-${e}`]={flexWrap:e}}),r})(i),(e=>{let{componentCls:t}=e,r={};return u.forEach(e=>{r[`${t}-align-${e}`]={alignItems:e}}),r})(i),(e=>{let{componentCls:t}=e,r={};return c.forEach(e=>{r[`${t}-justify-${e}`]={justifyContent:e}}),r})(i)]},()=>({}),{resetStyle:!1});var g=function(e,t){var r={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(r[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,a=Object.getOwnPropertySymbols(e);it.indexOf(a[i])&&Object.prototype.propertyIsEnumerable.call(e,a[i])&&(r[a[i]]=e[a[i]]);return r};let p=t.default.forwardRef((e,n)=>{let{prefixCls:s,rootClassName:l,className:c,style:u,flex:p,gap:f,vertical:h=!1,component:b="div",children:v}=e,A=g(e,["prefixCls","rootClassName","className","style","flex","gap","vertical","component","children"]),{flex:y,direction:O,getPrefixCls:x}=t.default.useContext(o.ConfigContext),C=x("flex",s),[E,I,$]=m(C),_=null!=h?h:null==y?void 0:y.vertical,T=(0,r.default)(c,l,null==y?void 0:y.className,C,I,$,d(C,e),{[`${C}-rtl`]:"rtl"===O,[`${C}-gap-${f}`]:(0,i.isPresetSize)(f),[`${C}-vertical`]:_}),w=Object.assign(Object.assign({},null==y?void 0:y.style),u);return p&&(w.flex=p),f&&!(0,i.isPresetSize)(f)&&(w.gap=f),E(t.default.createElement(b,Object.assign({ref:n,className:T,style:w},(0,a.default)(A,["justify","wrap","align"])),v))});e.s(["Flex",0,p],525720)},149121,e=>{"use strict";var t=e.i(843476),r=e.i(271645),a=e.i(152990),i=e.i(682830),o=e.i(269200),n=e.i(427612),s=e.i(64848),l=e.i(942232),c=e.i(496020),u=e.i(977572);function d({data:e=[],columns:d,onRowClick:m,renderSubComponent:g,renderChildRows:p,getRowCanExpand:f,isLoading:h=!1,loadingMessage:b="🚅 Loading logs...",noDataMessage:v="No logs found",enableSorting:A=!1}){let y=!!(g||p)&&!!f,[O,x]=(0,r.useState)([]),C=(0,a.useReactTable)({data:e,columns:d,...A&&{state:{sorting:O},onSortingChange:x,enableSortingRemoval:!1},...y&&{getRowCanExpand:f},getRowId:(e,t)=>e?.request_id??String(t),getCoreRowModel:(0,i.getCoreRowModel)(),...A&&{getSortedRowModel:(0,i.getSortedRowModel)()},...y&&{getExpandedRowModel:(0,i.getExpandedRowModel)()}});return(0,t.jsx)("div",{className:"rounded-lg custom-border overflow-x-auto w-full max-w-full box-border",children:(0,t.jsxs)(o.Table,{className:"[&_td]:py-0.5 [&_th]:py-1 table-fixed w-full box-border",style:{minWidth:"400px"},children:[(0,t.jsx)(n.TableHead,{children:C.getHeaderGroups().map(e=>(0,t.jsx)(c.TableRow,{children:e.headers.map(e=>{let r=A&&e.column.getCanSort(),i=e.column.getIsSorted();return(0,t.jsx)(s.TableHeaderCell,{className:`py-1 h-8 ${r?"cursor-pointer select-none hover:bg-gray-50":""}`,onClick:r?e.column.getToggleSortingHandler():void 0,children:e.isPlaceholder?null:(0,t.jsxs)("div",{className:"flex items-center gap-1",children:[(0,a.flexRender)(e.column.columnDef.header,e.getContext()),r&&(0,t.jsx)("span",{className:"text-gray-400",children:"asc"===i?"↑":"desc"===i?"↓":"⇅"})]})},e.id)})},e.id))}),(0,t.jsx)(l.TableBody,{children:h?(0,t.jsx)(c.TableRow,{children:(0,t.jsx)(u.TableCell,{colSpan:d.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:b})})})}):C.getRowModel().rows.length>0?C.getRowModel().rows.map(e=>(0,t.jsxs)(r.Fragment,{children:[(0,t.jsx)(c.TableRow,{className:`h-8 ${m?"cursor-pointer hover:bg-gray-50":""}`,onClick:()=>m?.(e.original),children:e.getVisibleCells().map(e=>(0,t.jsx)(u.TableCell,{className:"py-0.5 max-h-8 overflow-hidden text-ellipsis whitespace-nowrap",children:(0,a.flexRender)(e.column.columnDef.cell,e.getContext())},e.id))}),y&&e.getIsExpanded()&&p&&p({row:e}),y&&e.getIsExpanded()&&g&&!p&&(0,t.jsx)(c.TableRow,{children:(0,t.jsx)(u.TableCell,{colSpan:e.getVisibleCells().length,className:"p-0",children:(0,t.jsx)("div",{className:"w-full max-w-full overflow-hidden box-border",children:g({row:e})})})})]},e.id)):(0,t.jsx)(c.TableRow,{children:(0,t.jsx)(u.TableCell,{colSpan:d.length,className:"h-8 text-center",children:(0,t.jsx)("div",{className:"text-center text-gray-500",children:(0,t.jsx)("p",{children:v})})})})})]})})}e.s(["DataTable",()=>d])},986888,e=>{"use strict";var t=e.i(843476),r=e.i(797305),a=e.i(135214),i=e.i(214541);e.s(["default",0,()=>{let{accessToken:e,userRole:o,userId:n,premiumUser:s}=(0,a.default)(),{teams:l}=(0,i.default)();return(0,t.jsx)(r.default,{teams:l??[],organizations:[]})}])},601236,e=>{e.v(e=>Promise.resolve().then(()=>e(764205)))}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/5ec157703332dbc8.js b/litellm/proxy/_experimental/out/_next/static/chunks/90c332d66ef5954b.js similarity index 51% rename from litellm/proxy/_experimental/out/_next/static/chunks/5ec157703332dbc8.js rename to litellm/proxy/_experimental/out/_next/static/chunks/90c332d66ef5954b.js index 345ee2ef9b..bc806426f1 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/5ec157703332dbc8.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/90c332d66ef5954b.js @@ -1,5 +1,5 @@ (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,955135,e=>{"use strict";var t=e.i(597440);e.s(["DeleteOutlined",()=>t.default])},309821,e=>{"use strict";e.i(247167);var t=e.i(271645);e.i(262370);var r=e.i(135551),n=e.i(201072),o=e.i(121229),i=e.i(726289),a=e.i(864517),l=e.i(343794),s=e.i(529681),c=e.i(242064),d=e.i(931067),u=e.i(209428),f=e.i(703923),m={percent:0,prefixCls:"rc-progress",strokeColor:"#2db7f5",strokeLinecap:"round",strokeWidth:1,trailColor:"#D9D9D9",trailWidth:1,gapPosition:"bottom"},p=function(){var e=(0,t.useRef)([]),r=(0,t.useRef)(null);return(0,t.useEffect)(function(){var t=Date.now(),n=!1;e.current.forEach(function(e){if(e){n=!0;var o=e.style;o.transitionDuration=".3s, .3s, .3s, .06s",r.current&&t-r.current<100&&(o.transitionDuration="0s, 0s")}}),n&&(r.current=Date.now())}),e.current},g=e.i(410160),h=e.i(392221),b=e.i(654310),v=0,y=(0,b.default)();let x=function(e){var r=t.useState(),n=(0,h.default)(r,2),o=n[0],i=n[1];return t.useEffect(function(){var e;i("rc_progress_".concat((y?(e=v,v+=1):e="TEST_OR_SSR",e)))},[]),e||o};var k=function(e){var r=e.bg,n=e.children;return t.createElement("div",{style:{width:"100%",height:"100%",background:r}},n)};function C(e,t){return Object.keys(e).map(function(r){var n=parseFloat(r),o="".concat(Math.floor(n*t),"%");return"".concat(e[r]," ").concat(o)})}var w=t.forwardRef(function(e,r){var n=e.prefixCls,o=e.color,i=e.gradientId,a=e.radius,l=e.style,s=e.ptg,c=e.strokeLinecap,d=e.strokeWidth,u=e.size,f=e.gapDegree,m=o&&"object"===(0,g.default)(o),p=u/2,h=t.createElement("circle",{className:"".concat(n,"-circle-path"),r:a,cx:p,cy:p,stroke:m?"#FFF":void 0,strokeLinecap:c,strokeWidth:d,opacity:+(0!==s),style:l,ref:r});if(!m)return h;var b="".concat(i,"-conic"),v=C(o,(360-f)/360),y=C(o,1),x="conic-gradient(from ".concat(f?"".concat(180+f/2,"deg"):"0deg",", ").concat(v.join(", "),")"),w="linear-gradient(to ".concat(f?"bottom":"top",", ").concat(y.join(", "),")");return t.createElement(t.Fragment,null,t.createElement("mask",{id:b},h),t.createElement("foreignObject",{x:0,y:0,width:u,height:u,mask:"url(#".concat(b,")")},t.createElement(k,{bg:w},t.createElement(k,{bg:x}))))}),S=function(e,t,r,n,o,i,a,l,s,c){var d=arguments.length>10&&void 0!==arguments[10]?arguments[10]:0,u=(100-n)/100*t;return"round"===s&&100!==n&&(u+=c/2)>=t&&(u=t-.01),{stroke:"string"==typeof l?l:void 0,strokeDasharray:"".concat(t,"px ").concat(e),strokeDashoffset:u+d,transform:"rotate(".concat(o+r/100*360*((360-i)/360)+(0===i?0:({bottom:0,top:180,left:90,right:-90})[a]),"deg)"),transformOrigin:"".concat(50,"px ").concat(50,"px"),transition:"stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s",fillOpacity:0}},E=["id","prefixCls","steps","strokeWidth","trailWidth","gapDegree","gapPosition","trailColor","strokeLinecap","style","className","strokeColor","percent"];function j(e){var t=null!=e?e:[];return Array.isArray(t)?t:[t]}let _=function(e){var r,n,o,i,a=(0,u.default)((0,u.default)({},m),e),s=a.id,c=a.prefixCls,h=a.steps,b=a.strokeWidth,v=a.trailWidth,y=a.gapDegree,k=void 0===y?0:y,C=a.gapPosition,_=a.trailColor,N=a.strokeLinecap,O=a.style,$=a.className,T=a.strokeColor,M=a.percent,R=(0,f.default)(a,E),P=x(s),I="".concat(P,"-gradient"),D=50-b/2,L=2*Math.PI*D,F=k>0?90+k/2:-90,z=(360-k)/360*L,A="object"===(0,g.default)(h)?h:{count:h,gap:2},B=A.count,H=A.gap,q=j(M),W=j(T),K=W.find(function(e){return e&&"object"===(0,g.default)(e)}),U=K&&"object"===(0,g.default)(K)?"butt":N,X=S(L,z,0,100,F,k,C,_,U,b),G=p();return t.createElement("svg",(0,d.default)({className:(0,l.default)("".concat(c,"-circle"),$),viewBox:"0 0 ".concat(100," ").concat(100),style:O,id:s,role:"presentation"},R),!B&&t.createElement("circle",{className:"".concat(c,"-circle-trail"),r:D,cx:50,cy:50,stroke:_,strokeLinecap:U,strokeWidth:v||b,style:X}),B?(r=Math.round(B*(q[0]/100)),n=100/B,o=0,Array(B).fill(null).map(function(e,i){var a=i<=r-1?W[0]:_,l=a&&"object"===(0,g.default)(a)?"url(#".concat(I,")"):void 0,s=S(L,z,o,n,F,k,C,a,"butt",b,H);return o+=(z-s.strokeDashoffset+H)*100/z,t.createElement("circle",{key:i,className:"".concat(c,"-circle-path"),r:D,cx:50,cy:50,stroke:l,strokeWidth:b,opacity:1,style:s,ref:function(e){G[i]=e}})})):(i=0,q.map(function(e,r){var n=W[r]||W[W.length-1],o=S(L,z,i,e,F,k,C,n,U,b);return i+=e,t.createElement(w,{key:r,color:n,ptg:e,radius:D,prefixCls:c,gradientId:I,style:o,strokeLinecap:U,strokeWidth:b,gapDegree:k,ref:function(e){G[r]=e},size:100})}).reverse()))};var N=e.i(491816);e.i(765846);var O=e.i(896091);function $(e){return!e||e<0?0:e>100?100:e}function T({success:e,successPercent:t}){let r=t;return e&&"progress"in e&&(r=e.progress),e&&"percent"in e&&(r=e.percent),r}let M=(e,t,r)=>{var n,o,i,a;let l=-1,s=-1;if("step"===t){let t=r.steps,n=r.strokeWidth;"string"==typeof e||void 0===e?(l="small"===e?2:14,s=null!=n?n:8):"number"==typeof e?[l,s]=[e,e]:[l=14,s=8]=Array.isArray(e)?e:[e.width,e.height],l*=t}else if("line"===t){let t=null==r?void 0:r.strokeWidth;"string"==typeof e||void 0===e?s=t||("small"===e?6:8):"number"==typeof e?[l,s]=[e,e]:[l=-1,s=8]=Array.isArray(e)?e:[e.width,e.height]}else("circle"===t||"dashboard"===t)&&("string"==typeof e||void 0===e?[l,s]="small"===e?[60,60]:[120,120]:"number"==typeof e?[l,s]=[e,e]:Array.isArray(e)&&(l=null!=(o=null!=(n=e[0])?n:e[1])?o:120,s=null!=(a=null!=(i=e[0])?i:e[1])?a:120));return[l,s]},R=e=>{let{prefixCls:r,trailColor:n=null,strokeLinecap:o="round",gapPosition:i,gapDegree:a,width:s=120,type:c,children:d,success:u,size:f=s,steps:m}=e,[p,g]=M(f,"circle"),{strokeWidth:h}=e;void 0===h&&(h=Math.max(3/p*100,6));let b=t.useMemo(()=>a||0===a?a:"dashboard"===c?75:void 0,[a,c]),v=(({percent:e,success:t,successPercent:r})=>{let n=$(T({success:t,successPercent:r}));return[n,$($(e)-n)]})(e),y="[object Object]"===Object.prototype.toString.call(e.strokeColor),x=(({success:e={},strokeColor:t})=>{let{strokeColor:r}=e;return[r||O.presetPrimaryColors.green,t||null]})({success:u,strokeColor:e.strokeColor}),k=(0,l.default)(`${r}-inner`,{[`${r}-circle-gradient`]:y}),C=t.createElement(_,{steps:m,percent:m?v[1]:v,strokeWidth:h,trailWidth:h,strokeColor:m?x[1]:x,strokeLinecap:o,trailColor:n,prefixCls:r,gapDegree:b,gapPosition:i||"dashboard"===c&&"bottom"||void 0}),w=p<=20,S=t.createElement("div",{className:k,style:{width:p,height:g,fontSize:.15*p+6}},C,!w&&d);return w?t.createElement(N.default,{title:d},S):S};e.i(296059);var P=e.i(694758),I=e.i(915654),D=e.i(183293),L=e.i(246422),F=e.i(838378);let z="--progress-line-stroke-color",A="--progress-percent",B=e=>{let t=e?"100%":"-100%";return new P.Keyframes(`antProgress${e?"RTL":"LTR"}Active`,{"0%":{transform:`translateX(${t}) scaleX(0)`,opacity:.1},"20%":{transform:`translateX(${t}) scaleX(0)`,opacity:.5},to:{transform:"translateX(0) scaleX(1)",opacity:0}})},H=(0,L.genStyleHooks)("Progress",e=>{let t=e.calc(e.marginXXS).div(2).equal(),r=(0,F.mergeToken)(e,{progressStepMarginInlineEnd:t,progressStepMinWidth:t,progressActiveMotionDuration:"2.4s"});return[(e=>{let{componentCls:t,iconCls:r}=e;return{[t]:Object.assign(Object.assign({},(0,D.resetComponent)(e)),{display:"inline-block","&-rtl":{direction:"rtl"},"&-line":{position:"relative",width:"100%",fontSize:e.fontSize},[`${t}-outer`]:{display:"inline-flex",alignItems:"center",width:"100%"},[`${t}-inner`]:{position:"relative",display:"inline-block",width:"100%",flex:1,overflow:"hidden",verticalAlign:"middle",backgroundColor:e.remainingColor,borderRadius:e.lineBorderRadius},[`${t}-inner:not(${t}-circle-gradient)`]:{[`${t}-circle-path`]:{stroke:e.defaultColor}},[`${t}-success-bg, ${t}-bg`]:{position:"relative",background:e.defaultColor,borderRadius:e.lineBorderRadius,transition:`all ${e.motionDurationSlow} ${e.motionEaseInOutCirc}`},[`${t}-layout-bottom`]:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",[`${t}-text`]:{width:"max-content",marginInlineStart:0,marginTop:e.marginXXS}},[`${t}-bg`]:{overflow:"hidden","&::after":{content:'""',background:{_multi_value_:!0,value:["inherit",`var(${z})`]},height:"100%",width:`calc(1 / var(${A}) * 100%)`,display:"block"},[`&${t}-bg-inner`]:{minWidth:"max-content","&::after":{content:"none"},[`${t}-text-inner`]:{color:e.colorWhite,[`&${t}-text-bright`]:{color:"rgba(0, 0, 0, 0.45)"}}}},[`${t}-success-bg`]:{position:"absolute",insetBlockStart:0,insetInlineStart:0,backgroundColor:e.colorSuccess},[`${t}-text`]:{display:"inline-block",marginInlineStart:e.marginXS,color:e.colorText,lineHeight:1,width:"2em",whiteSpace:"nowrap",textAlign:"start",verticalAlign:"middle",wordBreak:"normal",[r]:{fontSize:e.fontSize},[`&${t}-text-outer`]:{width:"max-content"},[`&${t}-text-outer${t}-text-start`]:{width:"max-content",marginInlineStart:0,marginInlineEnd:e.marginXS}},[`${t}-text-inner`]:{display:"flex",justifyContent:"center",alignItems:"center",width:"100%",height:"100%",marginInlineStart:0,padding:`0 ${(0,I.unit)(e.paddingXXS)}`,[`&${t}-text-start`]:{justifyContent:"start"},[`&${t}-text-end`]:{justifyContent:"end"}},[`&${t}-status-active`]:{[`${t}-bg::before`]:{position:"absolute",inset:0,backgroundColor:e.colorBgContainer,borderRadius:e.lineBorderRadius,opacity:0,animationName:B(),animationDuration:e.progressActiveMotionDuration,animationTimingFunction:e.motionEaseOutQuint,animationIterationCount:"infinite",content:'""'}},[`&${t}-rtl${t}-status-active`]:{[`${t}-bg::before`]:{animationName:B(!0)}},[`&${t}-status-exception`]:{[`${t}-bg`]:{backgroundColor:e.colorError},[`${t}-text`]:{color:e.colorError}},[`&${t}-status-exception ${t}-inner:not(${t}-circle-gradient)`]:{[`${t}-circle-path`]:{stroke:e.colorError}},[`&${t}-status-success`]:{[`${t}-bg`]:{backgroundColor:e.colorSuccess},[`${t}-text`]:{color:e.colorSuccess}},[`&${t}-status-success ${t}-inner:not(${t}-circle-gradient)`]:{[`${t}-circle-path`]:{stroke:e.colorSuccess}}})}})(r),(e=>{let{componentCls:t,iconCls:r}=e;return{[t]:{[`${t}-circle-trail`]:{stroke:e.remainingColor},[`&${t}-circle ${t}-inner`]:{position:"relative",lineHeight:1,backgroundColor:"transparent"},[`&${t}-circle ${t}-text`]:{position:"absolute",insetBlockStart:"50%",insetInlineStart:0,width:"100%",margin:0,padding:0,color:e.circleTextColor,fontSize:e.circleTextFontSize,lineHeight:1,whiteSpace:"normal",textAlign:"center",transform:"translateY(-50%)",[r]:{fontSize:e.circleIconFontSize}},[`${t}-circle&-status-exception`]:{[`${t}-text`]:{color:e.colorError}},[`${t}-circle&-status-success`]:{[`${t}-text`]:{color:e.colorSuccess}}},[`${t}-inline-circle`]:{lineHeight:1,[`${t}-inner`]:{verticalAlign:"bottom"}}}})(r),(e=>{let{componentCls:t}=e;return{[t]:{[`${t}-steps`]:{display:"inline-block","&-outer":{display:"flex",flexDirection:"row",alignItems:"center"},"&-item":{flexShrink:0,minWidth:e.progressStepMinWidth,marginInlineEnd:e.progressStepMarginInlineEnd,backgroundColor:e.remainingColor,transition:`all ${e.motionDurationSlow}`,"&-active":{backgroundColor:e.defaultColor}}}}}})(r),(e=>{let{componentCls:t,iconCls:r}=e;return{[t]:{[`${t}-small&-line, ${t}-small&-line ${t}-text ${r}`]:{fontSize:e.fontSizeSM}}}})(r)]},e=>({circleTextColor:e.colorText,defaultColor:e.colorInfo,remainingColor:e.colorFillSecondary,lineBorderRadius:100,circleTextFontSize:"1em",circleIconFontSize:`${e.fontSize/e.fontSizeSM}em`}));var q=function(e,t){var r={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&0>t.indexOf(n)&&(r[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var o=0,n=Object.getOwnPropertySymbols(e);ot.indexOf(n[o])&&Object.prototype.propertyIsEnumerable.call(e,n[o])&&(r[n[o]]=e[n[o]]);return r};let W=e=>{let{prefixCls:r,direction:n,percent:o,size:i,strokeWidth:a,strokeColor:s,strokeLinecap:c="round",children:d,trailColor:u=null,percentPosition:f,success:m}=e,{align:p,type:g}=f,h=s&&"string"!=typeof s?((e,t)=>{let{from:r=O.presetPrimaryColors.blue,to:n=O.presetPrimaryColors.blue,direction:o="rtl"===t?"to left":"to right"}=e,i=q(e,["from","to","direction"]);if(0!==Object.keys(i).length){let e,t=(e=[],Object.keys(i).forEach(t=>{let r=Number.parseFloat(t.replace(/%/g,""));Number.isNaN(r)||e.push({key:r,value:i[t]})}),(e=e.sort((e,t)=>e.key-t.key)).map(({key:e,value:t})=>`${t} ${e}%`).join(", ")),r=`linear-gradient(${o}, ${t})`;return{background:r,[z]:r}}let a=`linear-gradient(${o}, ${r}, ${n})`;return{background:a,[z]:a}})(s,n):{[z]:s,background:s},b="square"===c||"butt"===c?0:void 0,[v,y]=M(null!=i?i:[-1,a||("small"===i?6:8)],"line",{strokeWidth:a}),x=Object.assign(Object.assign({width:`${$(o)}%`,height:y,borderRadius:b},h),{[A]:$(o)/100}),k=T(e),C={width:`${$(k)}%`,height:y,borderRadius:b,backgroundColor:null==m?void 0:m.strokeColor},w=t.createElement("div",{className:`${r}-inner`,style:{backgroundColor:u||void 0,borderRadius:b}},t.createElement("div",{className:(0,l.default)(`${r}-bg`,`${r}-bg-${g}`),style:x},"inner"===g&&d),void 0!==k&&t.createElement("div",{className:`${r}-success-bg`,style:C})),S="outer"===g&&"start"===p,E="outer"===g&&"end"===p;return"outer"===g&&"center"===p?t.createElement("div",{className:`${r}-layout-bottom`},w,d):t.createElement("div",{className:`${r}-outer`,style:{width:v<0?"100%":v}},S&&d,w,E&&d)},K=e=>{let{size:r,steps:n,rounding:o=Math.round,percent:i=0,strokeWidth:a=8,strokeColor:s,trailColor:c=null,prefixCls:d,children:u}=e,f=o(i/100*n),[m,p]=M(null!=r?r:["small"===r?2:14,a],"step",{steps:n,strokeWidth:a}),g=m/n,h=Array.from({length:n});for(let e=0;et.indexOf(n)&&(r[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var o=0,n=Object.getOwnPropertySymbols(e);ot.indexOf(n[o])&&Object.prototype.propertyIsEnumerable.call(e,n[o])&&(r[n[o]]=e[n[o]]);return r};let X=["normal","exception","active","success"],G=t.forwardRef((e,d)=>{let u,{prefixCls:f,className:m,rootClassName:p,steps:g,strokeColor:h,percent:b=0,size:v="default",showInfo:y=!0,type:x="line",status:k,format:C,style:w,percentPosition:S={}}=e,E=U(e,["prefixCls","className","rootClassName","steps","strokeColor","percent","size","showInfo","type","status","format","style","percentPosition"]),{align:j="end",type:_="outer"}=S,N=Array.isArray(h)?h[0]:h,O="string"==typeof h||Array.isArray(h)?h:void 0,P=t.useMemo(()=>{if(N){let e="string"==typeof N?N:Object.values(N)[0];return new r.FastColor(e).isLight()}return!1},[h]),I=t.useMemo(()=>{var t,r;let n=T(e);return Number.parseInt(void 0!==n?null==(t=null!=n?n:0)?void 0:t.toString():null==(r=null!=b?b:0)?void 0:r.toString(),10)},[b,e.success,e.successPercent]),D=t.useMemo(()=>!X.includes(k)&&I>=100?"success":k||"normal",[k,I]),{getPrefixCls:L,direction:F,progress:z}=t.useContext(c.ConfigContext),A=L("progress",f),[B,q,G]=H(A),V="line"===x,Q=V&&!g,Y=t.useMemo(()=>{let r;if(!y)return null;let s=T(e),c=C||(e=>`${e}%`),d=V&&P&&"inner"===_;return"inner"===_||C||"exception"!==D&&"success"!==D?r=c($(b),$(s)):"exception"===D?r=V?t.createElement(i.default,null):t.createElement(a.default,null):"success"===D&&(r=V?t.createElement(n.default,null):t.createElement(o.default,null)),t.createElement("span",{className:(0,l.default)(`${A}-text`,{[`${A}-text-bright`]:d,[`${A}-text-${j}`]:Q,[`${A}-text-${_}`]:Q}),title:"string"==typeof r?r:void 0},r)},[y,b,I,D,x,A,C]);"line"===x?u=g?t.createElement(K,Object.assign({},e,{strokeColor:O,prefixCls:A,steps:"object"==typeof g?g.count:g}),Y):t.createElement(W,Object.assign({},e,{strokeColor:N,prefixCls:A,direction:F,percentPosition:{align:j,type:_}}),Y):("circle"===x||"dashboard"===x)&&(u=t.createElement(R,Object.assign({},e,{strokeColor:N,prefixCls:A,progressStatus:D}),Y));let J=(0,l.default)(A,`${A}-status-${D}`,{[`${A}-${"dashboard"===x&&"circle"||x}`]:"line"!==x,[`${A}-inline-circle`]:"circle"===x&&M(v,"circle")[0]<=20,[`${A}-line`]:Q,[`${A}-line-align-${j}`]:Q,[`${A}-line-position-${_}`]:Q,[`${A}-steps`]:g,[`${A}-show-info`]:y,[`${A}-${v}`]:"string"==typeof v,[`${A}-rtl`]:"rtl"===F},null==z?void 0:z.className,m,p,q,G);return B(t.createElement("div",Object.assign({ref:d,style:Object.assign(Object.assign({},null==z?void 0:z.style),w),className:J,role:"progressbar","aria-valuenow":I,"aria-valuemin":0,"aria-valuemax":100},(0,s.default)(E,["trailColor","strokeWidth","width","gapDegree","gapPosition","strokeLinecap","success","successPercent"])),u))});e.s(["default",0,G],309821)},597440,e=>{"use strict";e.i(247167);var t=e.i(931067),r=e.i(271645);let n={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"}}]},name:"delete",theme:"outlined"};var o=e.i(9583),i=r.forwardRef(function(e,i){return r.createElement(o.default,(0,t.default)({},e,{ref:i,icon:n}))});e.s(["default",0,i],597440)},737434,e=>{"use strict";var t=e.i(184163);e.s(["DownloadOutlined",()=>t.default])},916940,e=>{"use strict";var t=e.i(843476),r=e.i(271645),n=e.i(199133),o=e.i(764205);e.s(["default",0,({onChange:e,value:i,className:a,accessToken:l,placeholder:s="Select vector stores",disabled:c=!1})=>{let[d,u]=(0,r.useState)([]),[f,m]=(0,r.useState)(!1);return(0,r.useEffect)(()=>{(async()=>{if(l){m(!0);try{let e=await (0,o.vectorStoreListCall)(l);e.data&&u(e.data)}catch(e){console.error("Error fetching vector stores:",e)}finally{m(!1)}}})()},[l]),(0,t.jsx)("div",{children:(0,t.jsx)(n.Select,{mode:"multiple",placeholder:s,onChange:e,value:i,loading:f,className:a,allowClear:!0,options:d.map(e=>({label:`${e.vector_store_name||e.vector_store_id} (${e.vector_store_id})`,value:e.vector_store_id,title:e.vector_store_description||e.vector_store_id})),optionFilterProp:"label",showSearch:!0,style:{width:"100%"},disabled:c})})}])},107233,37727,e=>{"use strict";var t=e.i(603908);e.s(["Plus",()=>t.default],107233);var r=e.i(841947);e.s(["X",()=>r.default],37727)},246349,e=>{"use strict";let t=(0,e.i(475254).default)("chevron-right",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);e.s(["default",()=>t])},309426,e=>{"use strict";var t=e.i(290571),r=e.i(444755),n=e.i(673706),o=e.i(271645),i=e.i(46757);let a=(0,n.makeClassName)("Col"),l=o.default.forwardRef((e,n)=>{let l,s,c,d,{numColSpan:u=1,numColSpanSm:f,numColSpanMd:m,numColSpanLg:p,children:g,className:h}=e,b=(0,t.__rest)(e,["numColSpan","numColSpanSm","numColSpanMd","numColSpanLg","children","className"]),v=(e,t)=>e&&Object.keys(t).includes(String(e))?t[e]:"";return o.default.createElement("div",Object.assign({ref:n,className:(0,r.tremorTwMerge)(a("root"),(l=v(u,i.colSpan),s=v(f,i.colSpanSm),c=v(m,i.colSpanMd),d=v(p,i.colSpanLg),(0,r.tremorTwMerge)(l,s,c,d)),h)},b),g)});l.displayName="Col",e.s(["Col",()=>l],309426)},950724,(e,t,r)=>{t.exports=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}},100236,(e,t,r)=>{t.exports=e.g&&e.g.Object===Object&&e.g},139088,(e,t,r)=>{var n=e.r(100236),o="object"==typeof self&&self&&self.Object===Object&&self;t.exports=n||o||Function("return this")()},631926,(e,t,r)=>{var n=e.r(139088);t.exports=function(){return n.Date.now()}},748891,(e,t,r)=>{var n=/\s/;t.exports=function(e){for(var t=e.length;t--&&n.test(e.charAt(t)););return t}},830364,(e,t,r)=>{var n=e.r(748891),o=/^\s+/;t.exports=function(e){return e?e.slice(0,n(e)+1).replace(o,""):e}},630353,(e,t,r)=>{t.exports=e.r(139088).Symbol},243436,(e,t,r)=>{var n=e.r(630353),o=Object.prototype,i=o.hasOwnProperty,a=o.toString,l=n?n.toStringTag:void 0;t.exports=function(e){var t=i.call(e,l),r=e[l];try{e[l]=void 0;var n=!0}catch(e){}var o=a.call(e);return n&&(t?e[l]=r:delete e[l]),o}},223243,(e,t,r)=>{var n=Object.prototype.toString;t.exports=function(e){return n.call(e)}},377684,(e,t,r)=>{var n=e.r(630353),o=e.r(243436),i=e.r(223243),a=n?n.toStringTag:void 0;t.exports=function(e){return null==e?void 0===e?"[object Undefined]":"[object Null]":a&&a in Object(e)?o(e):i(e)}},877289,(e,t,r)=>{t.exports=function(e){return null!=e&&"object"==typeof e}},361884,(e,t,r)=>{var n=e.r(377684),o=e.r(877289);t.exports=function(e){return"symbol"==typeof e||o(e)&&"[object Symbol]"==n(e)}},773759,(e,t,r)=>{var n=e.r(830364),o=e.r(950724),i=e.r(361884),a=0/0,l=/^[-+]0x[0-9a-f]+$/i,s=/^0b[01]+$/i,c=/^0o[0-7]+$/i,d=parseInt;t.exports=function(e){if("number"==typeof e)return e;if(i(e))return a;if(o(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=o(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=n(e);var r=s.test(e);return r||c.test(e)?d(e.slice(2),r?2:8):l.test(e)?a:+e}},374009,(e,t,r)=>{var n=e.r(950724),o=e.r(631926),i=e.r(773759),a=Math.max,l=Math.min;t.exports=function(e,t,r){var s,c,d,u,f,m,p=0,g=!1,h=!1,b=!0;if("function"!=typeof e)throw TypeError("Expected a function");function v(t){var r=s,n=c;return s=c=void 0,p=t,u=e.apply(n,r)}function y(e){var r=e-m,n=e-p;return void 0===m||r>=t||r<0||h&&n>=d}function x(){var e,r,n,i=o();if(y(i))return k(i);f=setTimeout(x,(e=i-m,r=i-p,n=t-e,h?l(n,d-r):n))}function k(e){return(f=void 0,b&&s)?v(e):(s=c=void 0,u)}function C(){var e,r=o(),n=y(r);if(s=arguments,c=this,m=r,n){if(void 0===f)return p=e=m,f=setTimeout(x,t),g?v(e):u;if(h)return clearTimeout(f),f=setTimeout(x,t),v(m)}return void 0===f&&(f=setTimeout(x,t)),u}return t=i(t)||0,n(r)&&(g=!!r.leading,d=(h="maxWait"in r)?a(i(r.maxWait)||0,t):d,b="trailing"in r?!!r.trailing:b),C.cancel=function(){void 0!==f&&clearTimeout(f),p=0,s=m=c=f=void 0},C.flush=function(){return void 0===f?u:k(o())},C}},964306,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["XCircleIcon",0,r],964306)},677667,674175,886148,543086,e=>{"use strict";let t,r;var n,o=e.i(290571),i=e.i(429427),a=e.i(371330),l=e.i(271645),s=e.i(394487),c=e.i(914189),d=e.i(144279),u=e.i(294316),f=e.i(83733);let m=(0,l.createContext)(()=>{});function p({value:e,children:t}){return l.default.createElement(m.Provider,{value:e},t)}e.s(["CloseProvider",()=>p],674175);var g=e.i(233137),h=e.i(233538),b=e.i(397701),v=e.i(402155),y=e.i(700020);let x=null!=(n=l.default.startTransition)?n:function(e){e()};var k=e.i(998348),C=((t=C||{})[t.Open=0]="Open",t[t.Closed=1]="Closed",t),w=((r=w||{})[r.ToggleDisclosure=0]="ToggleDisclosure",r[r.CloseDisclosure=1]="CloseDisclosure",r[r.SetButtonId=2]="SetButtonId",r[r.SetPanelId=3]="SetPanelId",r[r.SetButtonElement=4]="SetButtonElement",r[r.SetPanelElement=5]="SetPanelElement",r);let S={0:e=>({...e,disclosureState:(0,b.match)(e.disclosureState,{0:1,1:0})}),1:e=>1===e.disclosureState?e:{...e,disclosureState:1},2:(e,t)=>e.buttonId===t.buttonId?e:{...e,buttonId:t.buttonId},3:(e,t)=>e.panelId===t.panelId?e:{...e,panelId:t.panelId},4:(e,t)=>e.buttonElement===t.element?e:{...e,buttonElement:t.element},5:(e,t)=>e.panelElement===t.element?e:{...e,panelElement:t.element}},E=(0,l.createContext)(null);function j(e){let t=(0,l.useContext)(E);if(null===t){let t=Error(`<${e} /> is missing a parent component.`);throw Error.captureStackTrace&&Error.captureStackTrace(t,j),t}return t}E.displayName="DisclosureContext";let _=(0,l.createContext)(null);_.displayName="DisclosureAPIContext";let N=(0,l.createContext)(null);function O(e,t){return(0,b.match)(t.type,S,e,t)}N.displayName="DisclosurePanelContext";let $=l.Fragment,T=y.RenderFeatures.RenderStrategy|y.RenderFeatures.Static,M=Object.assign((0,y.forwardRefWithAs)(function(e,t){let{defaultOpen:r=!1,...n}=e,o=(0,l.useRef)(null),i=(0,u.useSyncRefs)(t,(0,u.optionalRef)(e=>{o.current=e},void 0===e.as||e.as===l.Fragment)),a=(0,l.useReducer)(O,{disclosureState:+!r,buttonElement:null,panelElement:null,buttonId:null,panelId:null}),[{disclosureState:s,buttonId:d},f]=a,m=(0,c.useEvent)(e=>{f({type:1});let t=(0,v.getOwnerDocument)(o);if(!t||!d)return;let r=e?e instanceof HTMLElement?e:e.current instanceof HTMLElement?e.current:t.getElementById(d):t.getElementById(d);null==r||r.focus()}),h=(0,l.useMemo)(()=>({close:m}),[m]),x=(0,l.useMemo)(()=>({open:0===s,close:m}),[s,m]),k=(0,y.useRender)();return l.default.createElement(E.Provider,{value:a},l.default.createElement(_.Provider,{value:h},l.default.createElement(p,{value:m},l.default.createElement(g.OpenClosedProvider,{value:(0,b.match)(s,{0:g.State.Open,1:g.State.Closed})},k({ourProps:{ref:i},theirProps:n,slot:x,defaultTag:$,name:"Disclosure"})))))}),{Button:(0,y.forwardRefWithAs)(function(e,t){let r=(0,l.useId)(),{id:n=`headlessui-disclosure-button-${r}`,disabled:o=!1,autoFocus:f=!1,...m}=e,[p,g]=j("Disclosure.Button"),b=(0,l.useContext)(N),v=null!==b&&b===p.panelId,x=(0,l.useRef)(null),C=(0,u.useSyncRefs)(x,t,(0,c.useEvent)(e=>{if(!v)return g({type:4,element:e})}));(0,l.useEffect)(()=>{if(!v)return g({type:2,buttonId:n}),()=>{g({type:2,buttonId:null})}},[n,g,v]);let w=(0,c.useEvent)(e=>{var t;if(v){if(1===p.disclosureState)return;switch(e.key){case k.Keys.Space:case k.Keys.Enter:e.preventDefault(),e.stopPropagation(),g({type:0}),null==(t=p.buttonElement)||t.focus()}}else switch(e.key){case k.Keys.Space:case k.Keys.Enter:e.preventDefault(),e.stopPropagation(),g({type:0})}}),S=(0,c.useEvent)(e=>{e.key===k.Keys.Space&&e.preventDefault()}),E=(0,c.useEvent)(e=>{var t;(0,h.isDisabledReactIssue7711)(e.currentTarget)||o||(v?(g({type:0}),null==(t=p.buttonElement)||t.focus()):g({type:0}))}),{isFocusVisible:_,focusProps:O}=(0,i.useFocusRing)({autoFocus:f}),{isHovered:$,hoverProps:T}=(0,a.useHover)({isDisabled:o}),{pressed:M,pressProps:R}=(0,s.useActivePress)({disabled:o}),P=(0,l.useMemo)(()=>({open:0===p.disclosureState,hover:$,active:M,disabled:o,focus:_,autofocus:f}),[p,$,M,_,o,f]),I=(0,d.useResolveButtonType)(e,p.buttonElement),D=v?(0,y.mergeProps)({ref:C,type:I,disabled:o||void 0,autoFocus:f,onKeyDown:w,onClick:E},O,T,R):(0,y.mergeProps)({ref:C,id:n,type:I,"aria-expanded":0===p.disclosureState,"aria-controls":p.panelElement?p.panelId:void 0,disabled:o||void 0,autoFocus:f,onKeyDown:w,onKeyUp:S,onClick:E},O,T,R);return(0,y.useRender)()({ourProps:D,theirProps:m,slot:P,defaultTag:"button",name:"Disclosure.Button"})}),Panel:(0,y.forwardRefWithAs)(function(e,t){let r=(0,l.useId)(),{id:n=`headlessui-disclosure-panel-${r}`,transition:o=!1,...i}=e,[a,s]=j("Disclosure.Panel"),{close:d}=function e(t){let r=(0,l.useContext)(_);if(null===r){let r=Error(`<${t} /> is missing a parent component.`);throw Error.captureStackTrace&&Error.captureStackTrace(r,e),r}return r}("Disclosure.Panel"),[m,p]=(0,l.useState)(null),h=(0,u.useSyncRefs)(t,(0,c.useEvent)(e=>{x(()=>s({type:5,element:e}))}),p);(0,l.useEffect)(()=>(s({type:3,panelId:n}),()=>{s({type:3,panelId:null})}),[n,s]);let b=(0,g.useOpenClosed)(),[v,k]=(0,f.useTransition)(o,m,null!==b?(b&g.State.Open)===g.State.Open:0===a.disclosureState),C=(0,l.useMemo)(()=>({open:0===a.disclosureState,close:d}),[a.disclosureState,d]),w={ref:h,id:n,...(0,f.transitionDataAttributes)(k)},S=(0,y.useRender)();return l.default.createElement(g.ResetOpenClosedProvider,null,l.default.createElement(N.Provider,{value:a.panelId},S({ourProps:w,theirProps:i,slot:C,defaultTag:"div",features:T,visible:v,name:"Disclosure.Panel"})))})});e.s(["Disclosure",()=>M],886148);let R=(0,l.createContext)(void 0);var P=e.i(444755);let I=(0,e.i(673706).makeClassName)("Accordion"),D=(0,l.createContext)({isOpen:!1}),L=l.default.forwardRef((e,t)=>{var r;let{defaultOpen:n=!1,children:i,className:a}=e,s=(0,o.__rest)(e,["defaultOpen","children","className"]),c=null!=(r=(0,l.useContext)(R))?r:(0,P.tremorTwMerge)("rounded-tremor-default border");return l.default.createElement(M,Object.assign({as:"div",ref:t,className:(0,P.tremorTwMerge)(I("root"),"overflow-hidden","bg-tremor-background border-tremor-border","dark:bg-dark-tremor-background dark:border-dark-tremor-border",c,a),defaultOpen:n},s),({open:e})=>l.default.createElement(D.Provider,{value:{isOpen:e}},i))});L.displayName="Accordion",e.s(["OpenContext",()=>D,"default",()=>L],543086),e.s(["Accordion",()=>L],677667)},898667,e=>{"use strict";var t=e.i(290571),r=e.i(271645),n=e.i(886148);let o=e=>{var n=(0,t.__rest)(e,[]);return r.default.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor"},n),r.default.createElement("path",{d:"M11.9999 10.8284L7.0502 15.7782L5.63599 14.364L11.9999 8L18.3639 14.364L16.9497 15.7782L11.9999 10.8284Z"}))};var i=e.i(543086),a=e.i(444755);let l=(0,e.i(673706).makeClassName)("AccordionHeader"),s=r.default.forwardRef((e,s)=>{let{children:c,className:d}=e,u=(0,t.__rest)(e,["children","className"]),{isOpen:f}=(0,r.useContext)(i.OpenContext);return r.default.createElement(n.Disclosure.Button,Object.assign({ref:s,className:(0,a.tremorTwMerge)(l("root"),"w-full flex items-center justify-between px-4 py-3","text-tremor-content-emphasis","dark:text-dark-tremor-content-emphasis",d)},u),r.default.createElement("div",{className:(0,a.tremorTwMerge)(l("children"),"flex flex-1 text-inherit mr-4")},c),r.default.createElement("div",null,r.default.createElement(o,{className:(0,a.tremorTwMerge)(l("arrowIcon"),"h-5 w-5 -mr-1","text-tremor-content-subtle","dark:text-dark-tremor-content-subtle",f?"transition-all":"transition-all -rotate-180")})))});s.displayName="AccordionHeader",e.s(["AccordionHeader",()=>s],898667)},130643,e=>{"use strict";var t=e.i(290571),r=e.i(271645),n=e.i(886148),o=e.i(444755);let i=(0,e.i(673706).makeClassName)("AccordionBody"),a=r.default.forwardRef((e,a)=>{let{children:l,className:s}=e,c=(0,t.__rest)(e,["children","className"]);return r.default.createElement(n.Disclosure.Panel,Object.assign({ref:a,className:(0,o.tremorTwMerge)(i("root"),"w-full text-tremor-default px-4 pb-3","text-tremor-content","dark:text-dark-tremor-content",s)},c),l)});a.displayName="AccordionBody",e.s(["AccordionBody",()=>a],130643)},83733,233137,e=>{"use strict";let t,r;var n,o,i=e.i(247167),a=e.i(271645),l=e.i(544508),s=e.i(746725),c=e.i(835696);void 0!==i.default&&"u">typeof globalThis&&"u">typeof Element&&(null==(n=null==i.default?void 0:i.default.env)?void 0:n.NODE_ENV)==="test"&&void 0===(null==(o=null==Element?void 0:Element.prototype)?void 0:o.getAnimations)&&(Element.prototype.getAnimations=function(){return console.warn(["Headless UI has polyfilled `Element.prototype.getAnimations` for your tests.","Please install a proper polyfill e.g. `jsdom-testing-mocks`, to silence these warnings.","","Example usage:","```js","import { mockAnimationsApi } from 'jsdom-testing-mocks'","mockAnimationsApi()","```"].join(` -`)),[]});var d=((t=d||{})[t.None=0]="None",t[t.Closed=1]="Closed",t[t.Enter=2]="Enter",t[t.Leave=4]="Leave",t);function u(e){let t={};for(let r in e)!0===e[r]&&(t[`data-${r}`]="");return t}function f(e,t,r,n){let[o,i]=(0,a.useState)(r),{hasFlag:d,addFlag:u,removeFlag:f}=function(e=0){let[t,r]=(0,a.useState)(e),n=(0,a.useCallback)(e=>r(e),[t]),o=(0,a.useCallback)(e=>r(t=>t|e),[t]),i=(0,a.useCallback)(e=>(t&e)===e,[t]);return{flags:t,setFlag:n,addFlag:o,hasFlag:i,removeFlag:(0,a.useCallback)(e=>r(t=>t&~e),[r]),toggleFlag:(0,a.useCallback)(e=>r(t=>t^e),[r])}}(e&&o?3:0),m=(0,a.useRef)(!1),p=(0,a.useRef)(!1),g=(0,s.useDisposables)();return(0,c.useIsoMorphicEffect)(()=>{var o;if(e){if(r&&i(!0),!t){r&&u(3);return}return null==(o=null==n?void 0:n.start)||o.call(n,r),function(e,{prepare:t,run:r,done:n,inFlight:o}){let i=(0,l.disposables)();return function(e,{inFlight:t,prepare:r}){if(null!=t&&t.current)return r();let n=e.style.transition;e.style.transition="none",r(),e.offsetHeight,e.style.transition=n}(e,{prepare:t,inFlight:o}),i.nextFrame(()=>{r(),i.requestAnimationFrame(()=>{i.add(function(e,t){var r,n;let o=(0,l.disposables)();if(!e)return o.dispose;let i=!1;o.add(()=>{i=!0});let a=null!=(n=null==(r=e.getAnimations)?void 0:r.call(e).filter(e=>e instanceof CSSTransition))?n:[];return 0===a.length?t():Promise.allSettled(a.map(e=>e.finished)).then(()=>{i||t()}),o.dispose}(e,n))})}),i.dispose}(t,{inFlight:m,prepare(){p.current?p.current=!1:p.current=m.current,m.current=!0,p.current||(r?(u(3),f(4)):(u(4),f(2)))},run(){p.current?r?(f(3),u(4)):(f(4),u(3)):r?f(1):u(1)},done(){var e;p.current&&"function"==typeof t.getAnimations&&t.getAnimations().length>0||(m.current=!1,f(7),r||i(!1),null==(e=null==n?void 0:n.end)||e.call(n,r))}})}},[e,r,t,g]),e?[o,{closed:d(1),enter:d(2),leave:d(4),transition:d(2)||d(4)}]:[r,{closed:void 0,enter:void 0,leave:void 0,transition:void 0}]}e.s(["transitionDataAttributes",()=>u,"useTransition",()=>f],83733);let m=(0,a.createContext)(null);m.displayName="OpenClosedContext";var p=((r=p||{})[r.Open=1]="Open",r[r.Closed=2]="Closed",r[r.Closing=4]="Closing",r[r.Opening=8]="Opening",r);function g(){return(0,a.useContext)(m)}function h({value:e,children:t}){return a.default.createElement(m.Provider,{value:e},t)}function b({children:e}){return a.default.createElement(m.Provider,{value:null},e)}e.s(["OpenClosedProvider",()=>h,"ResetOpenClosedProvider",()=>b,"State",()=>p,"useOpenClosed",()=>g],233137)},233538,e=>{"use strict";function t(e){let t=e.parentElement,r=null;for(;t&&!(t instanceof HTMLFieldSetElement);)t instanceof HTMLLegendElement&&(r=t),t=t.parentElement;let n=(null==t?void 0:t.getAttribute("disabled"))==="";return!(n&&function(e){if(!e)return!1;let t=e.previousElementSibling;for(;null!==t;){if(t instanceof HTMLLegendElement)return!1;t=t.previousElementSibling}return!0}(r))&&n}e.s(["isDisabledReactIssue7711",()=>t])},888288,220508,e=>{"use strict";var t=e.i(271645);let r=(e,r)=>{let n=void 0!==r,[o,i]=(0,t.useState)(e);return[n?r:o,e=>{n||i(e)}]};e.s(["default",()=>r],888288);let n=t.forwardRef(function(e,r){return t.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),t.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"}))});e.s(["CheckCircleIcon",0,n],220508)},503269,214520,601893,694421,140721,942803,35889,722678,e=>{"use strict";var t=e.i(271645),r=e.i(914189);function n(e,n,o){let[i,a]=(0,t.useState)(o),l=void 0!==e,s=(0,t.useRef)(l),c=(0,t.useRef)(!1),d=(0,t.useRef)(!1);return!l||s.current||c.current?l||!s.current||d.current||(d.current=!0,s.current=l,console.error("A component is changing from controlled to uncontrolled. This may be caused by the value changing from a defined value to undefined, which should not happen.")):(c.current=!0,s.current=l,console.error("A component is changing from uncontrolled to controlled. This may be caused by the value changing from undefined to a defined value, which should not happen.")),[l?e:i,(0,r.useEvent)(e=>(l||a(e),null==n?void 0:n(e)))]}function o(e){let[r]=(0,t.useState)(e);return r}e.s(["useControllable",()=>n],503269),e.s(["useDefaultValue",()=>o],214520);let i=(0,t.createContext)(void 0);function a(){return(0,t.useContext)(i)}e.s(["useDisabled",()=>a],601893);var l=e.i(174080),s=e.i(746725);function c(e={},t=null,r=[]){for(let[n,o]of Object.entries(e))!function e(t,r,n){if(Array.isArray(n))for(let[o,i]of n.entries())e(t,d(r,o.toString()),i);else n instanceof Date?t.push([r,n.toISOString()]):"boolean"==typeof n?t.push([r,n?"1":"0"]):"string"==typeof n?t.push([r,n]):"number"==typeof n?t.push([r,`${n}`]):null==n?t.push([r,""]):c(n,r,t)}(r,d(t,n),o);return r}function d(e,t){return e?e+"["+t+"]":t}function u(e){var t,r;let n=null!=(t=null==e?void 0:e.form)?t:e.closest("form");if(n){for(let t of n.elements)if(t!==e&&("INPUT"===t.tagName&&"submit"===t.type||"BUTTON"===t.tagName&&"submit"===t.type||"INPUT"===t.nodeName&&"image"===t.type))return void t.click();null==(r=n.requestSubmit)||r.call(n)}}e.s(["attemptSubmit",()=>u,"objectToFormEntries",()=>c],694421);var f=e.i(700020),m=e.i(2788);let p=(0,t.createContext)(null);function g({children:e}){let r=(0,t.useContext)(p);if(!r)return t.default.createElement(t.default.Fragment,null,e);let{target:n}=r;return n?(0,l.createPortal)(t.default.createElement(t.default.Fragment,null,e),n):null}function h({data:e,form:r,disabled:n,onReset:o,overrides:i}){let[a,l]=(0,t.useState)(null),d=(0,s.useDisposables)();return(0,t.useEffect)(()=>{if(o&&a)return d.addEventListener(a,"reset",o)},[a,r,o]),t.default.createElement(g,null,t.default.createElement(b,{setForm:l,formId:r}),c(e).map(([e,o])=>t.default.createElement(m.Hidden,{features:m.HiddenFeatures.Hidden,...(0,f.compact)({key:e,as:"input",type:"hidden",hidden:!0,readOnly:!0,form:r,disabled:n,name:e,value:o,...i})})))}function b({setForm:e,formId:r}){return(0,t.useEffect)(()=>{if(r){let t=document.getElementById(r);t&&e(t)}},[e,r]),r?null:t.default.createElement(m.Hidden,{features:m.HiddenFeatures.Hidden,as:"input",type:"hidden",hidden:!0,readOnly:!0,ref:t=>{if(!t)return;let r=t.closest("form");r&&e(r)}})}e.s(["FormFields",()=>h],140721);let v=(0,t.createContext)(void 0);function y(){return(0,t.useContext)(v)}e.s(["useProvidedId",()=>y],942803);var x=e.i(835696),k=e.i(294316);let C=(0,t.createContext)(null);function w(){var e,r;return null!=(r=null==(e=(0,t.useContext)(C))?void 0:e.value)?r:void 0}function S(){let[e,n]=(0,t.useState)([]);return[e.length>0?e.join(" "):void 0,(0,t.useMemo)(()=>function(e){let o=(0,r.useEvent)(e=>(n(t=>[...t,e]),()=>n(t=>{let r=t.slice(),n=r.indexOf(e);return -1!==n&&r.splice(n,1),r}))),i=(0,t.useMemo)(()=>({register:o,slot:e.slot,name:e.name,props:e.props,value:e.value}),[o,e.slot,e.name,e.props,e.value]);return t.default.createElement(C.Provider,{value:i},e.children)},[n])]}C.displayName="DescriptionContext";let E=Object.assign((0,f.forwardRefWithAs)(function(e,r){let n=(0,t.useId)(),o=a(),{id:i=`headlessui-description-${n}`,...l}=e,s=function e(){let r=(0,t.useContext)(C);if(null===r){let t=Error("You used a component, but it is not inside a relevant parent.");throw Error.captureStackTrace&&Error.captureStackTrace(t,e),t}return r}(),c=(0,k.useSyncRefs)(r);(0,x.useIsoMorphicEffect)(()=>s.register(i),[i,s.register]);let d=o||!1,u=(0,t.useMemo)(()=>({...s.slot,disabled:d}),[s.slot,d]),m={ref:c,...s.props,id:i};return(0,f.useRender)()({ourProps:m,theirProps:l,slot:u,defaultTag:"p",name:s.name||"Description"})}),{});e.s(["Description",()=>E,"useDescribedBy",()=>w,"useDescriptions",()=>S],35889);let j=(0,t.createContext)(null);function _(e){var r,n,o;let i=null!=(n=null==(r=(0,t.useContext)(j))?void 0:r.value)?n:void 0;return(null!=(o=null==e?void 0:e.length)?o:0)>0?[i,...e].filter(Boolean).join(" "):i}function N({inherit:e=!1}={}){let n=_(),[o,i]=(0,t.useState)([]),a=e?[n,...o].filter(Boolean):o;return[a.length>0?a.join(" "):void 0,(0,t.useMemo)(()=>function(e){let n=(0,r.useEvent)(e=>(i(t=>[...t,e]),()=>i(t=>{let r=t.slice(),n=r.indexOf(e);return -1!==n&&r.splice(n,1),r}))),o=(0,t.useMemo)(()=>({register:n,slot:e.slot,name:e.name,props:e.props,value:e.value}),[n,e.slot,e.name,e.props,e.value]);return t.default.createElement(j.Provider,{value:o},e.children)},[i])]}j.displayName="LabelContext";let O=Object.assign((0,f.forwardRefWithAs)(function(e,n){var o;let i=(0,t.useId)(),l=function e(){let r=(0,t.useContext)(j);if(null===r){let t=Error("You used a
+ ); +} diff --git a/docs/my-website/src/components/NavigationCards/styles.module.css b/docs/my-website/src/components/NavigationCards/styles.module.css new file mode 100644 index 0000000000..64f5a42374 --- /dev/null +++ b/docs/my-website/src/components/NavigationCards/styles.module.css @@ -0,0 +1,82 @@ +.grid { + display: grid; + grid-template-columns: repeat(var(--nav-columns, 2), 1fr); + gap: 0.75rem; + margin: 1.25rem 0; +} + +@media (max-width: 768px) { + .grid { + grid-template-columns: 1fr; + } +} + +.card { + position: relative; + display: flex; + flex-direction: column; + padding: 1rem 1.1rem; + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 6px; + text-decoration: none !important; + color: inherit !important; + background: var(--ifm-background-surface-color); + transition: border-color 0.15s ease, box-shadow 0.15s ease; +} + +.card:hover { + border-color: var(--ifm-color-primary); + box-shadow: 0 0 0 1px var(--ifm-color-primary); + text-decoration: none !important; +} + +[data-theme='dark'] .card { + background: var(--ifm-background-surface-color); + border-color: #2d3748; +} + +[data-theme='dark'] .card:hover { + border-color: var(--ifm-color-primary); + box-shadow: 0 0 0 1px var(--ifm-color-primary); +} + +.icon { + font-size: 1.4rem; + margin-bottom: 0.5rem; + line-height: 1; +} + +.title { + font-size: 14px; + font-weight: 600; + margin-bottom: 0.35rem; + color: var(--ifm-heading-color); +} + +.description { + font-size: 13px; + line-height: 1.5; + color: var(--ifm-color-emphasis-700); + margin-bottom: 0.5rem; +} + +.list { + margin: 0.35rem 0 0 0; + padding-left: 1.1rem; + list-style: disc; +} + +.list li { + font-size: 12.5px; + color: var(--ifm-color-emphasis-700); + line-height: 1.6; + margin-bottom: 0; +} + +.externalIcon { + position: absolute; + top: 0.75rem; + right: 0.75rem; + font-size: 12px; + color: var(--ifm-color-emphasis-500); +} diff --git a/docs/my-website/src/css/custom.css b/docs/my-website/src/css/custom.css index 9fa4443afc..d0702fcc57 100644 --- a/docs/my-website/src/css/custom.css +++ b/docs/my-website/src/css/custom.css @@ -1,10 +1,16 @@ /** - * Any CSS included here will be global. The classic template - * bundles Infima by default. Infima is a CSS framework designed to - * work well for content-centric websites. + * Global CSS overrides for LiteLLM docs. + * Infima (Docusaurus CSS framework) variables + custom styling. */ -/* You can override the default Infima variables here. */ +/* ========================================= + FONTS + ========================================= */ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); + +/* ========================================= + ROOT — Light Mode Variables + ========================================= */ :root { --ifm-color-primary: #2e8555; --ifm-color-primary-dark: #29784c; @@ -13,11 +19,22 @@ --ifm-color-primary-light: #33925d; --ifm-color-primary-lighter: #359962; --ifm-color-primary-lightest: #3cad6e; - --ifm-code-font-size: 95%; - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); + --ifm-code-font-size: 85%; + --ifm-menu-color: #6b7280; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.08); + --ifm-font-family-base: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + --ifm-heading-font-weight: 600; + --ifm-font-size-base: 15px; + --ifm-line-height-base: 1.65; + --ifm-border-radius: 6px; + /* Wider reading column — reduces excessive whitespace on large monitors */ + --ifm-container-width: 1380px; + --ifm-container-width-xl: 1560px; } -/* For readability concerns, you should choose a lighter palette in dark mode. */ +/* ========================================= + DARK MODE Variables + ========================================= */ [data-theme='dark'] { --ifm-color-primary: #25c2a0; --ifm-color-primary-dark: #21af90; @@ -26,10 +43,710 @@ --ifm-color-primary-light: #29d5b0; --ifm-color-primary-lighter: #32d8b4; --ifm-color-primary-lightest: #4fddbf; - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); + --ifm-background-color: #0d1117; + --ifm-background-surface-color: #161b22; + --docusaurus-highlighted-code-line-bg: rgba(255, 255, 255, 0.07); } -/* Levo logo sizing and theme switching */ +/* ========================================= + TYPOGRAPHY + ========================================= */ +.theme-doc-markdown h1 { + font-size: 2.2rem; + letter-spacing: -0.02em; + line-height: 1.2; +} + +.theme-doc-markdown h2 { + font-size: 1.6rem; + letter-spacing: -0.01em; + line-height: 1.3; +} + +.theme-doc-markdown h3 { + font-size: 1.25rem; + line-height: 1.4; +} + +.theme-doc-markdown p, +.theme-doc-markdown ul, +.theme-doc-markdown ol { + font-size: 0.9rem; +} + +.theme-doc-markdown table { + font-size: 0.875rem; +} + +.theme-doc-markdown td { + font-size: 0.85rem; +} + +/* ========================================= + NAVBAR + ========================================= */ +[data-theme='light'] .navbar { + background-color: #ffffff; + box-shadow: 0 1px 0 0 #e5e7eb; +} + +[data-theme='dark'] .navbar { + background-color: var(--ifm-background-color); + border-bottom: 1px solid #21262d; + box-shadow: none; +} + +.navbar__link { + font-weight: 400 !important; + font-size: 14px !important; + border-bottom: 2px solid transparent !important; + padding-bottom: 2px; +} + +.navbar__link--active { + font-weight: 500 !important; + border-bottom: 2px solid var(--ifm-color-primary) !important; +} + +@media (max-width: 1330px) { + .navbar__link { + font-size: 13px !important; + } +} + +/* Three-column navbar: logo | center nav | right icons */ +@media (min-width: 997px) { + .navbar__inner { + display: flex !important; + align-items: center; + justify-content: space-between; + } + + .navbar__brand-col { + display: flex; + align-items: center; + flex: 0 0 auto; + margin-left: 1rem; + } + + .navbar__brand-col .navbar__brand { + font-size: 1.25rem; + } + + .navbar__brand-col .navbar__logo { + height: 2rem; + width: auto; + } + + .navbar__center-col { + display: flex; + align-items: center; + justify-content: center; + flex: 1; + } + + .navbar__right-col { + display: flex; + align-items: center; + flex: 0 0 auto; + gap: 0.25rem; + margin-right: 2rem; + } +} + +/* ========================================= + ALERTS / ADMONITIONS + ========================================= */ +.alert { + padding: 0.75rem 1rem; + font-size: 14px; + border-radius: var(--ifm-border-radius); + border-left-width: 3px; +} + +/* Light mode */ +.alert--info { + --ifm-alert-background-color: #f0f7ff !important; + --ifm-alert-border-color: #2264ab !important; +} + +.alert--success { + --ifm-alert-background-color: #f0fff8 !important; + --ifm-alert-border-color: #09bda8 !important; +} + +.alert--secondary { + --ifm-alert-background-color: #f8fafc !important; + --ifm-alert-border-color: #64748b !important; +} + +.alert--danger { + --ifm-alert-background-color: #fff0f5 !important; + --ifm-alert-border-color: #e11d48 !important; +} + +.alert--warning { + --ifm-alert-background-color: #fffbeb !important; + --ifm-alert-border-color: #d97706 !important; +} + +/* Dark mode */ +[data-theme='dark'] .alert--info { + --ifm-alert-background-color: #0c1e30 !important; + --ifm-alert-border-color: #3b82f6 !important; + color: #bfdbfe !important; +} + +[data-theme='dark'] .alert--success { + --ifm-alert-background-color: #022c22 !important; + --ifm-alert-border-color: #10b981 !important; +} + +[data-theme='dark'] .alert--secondary { + --ifm-alert-background-color: #0f172a !important; + --ifm-alert-border-color: #475569 !important; +} + +[data-theme='dark'] .alert--danger { + --ifm-alert-background-color: #2d0a14 !important; + --ifm-alert-border-color: #f43f5e !important; +} + +[data-theme='dark'] .alert--warning { + --ifm-alert-background-color: #1c1200 !important; + --ifm-alert-border-color: #f59e0b !important; +} + +/* ========================================= + COLLAPSIBLE / DETAILS + ========================================= */ +details { + color: #1d232e; + background-color: #ffffff; + border: 1px solid #e9eef2 !important; + border-radius: var(--ifm-border-radius) !important; + padding: 0.75rem !important; + margin-bottom: 1rem !important; + margin-top: 1.5rem !important; + box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.05) !important; +} + +details summary { + font-weight: 600 !important; +} + +details [class*='collapsibleContent'] { + border-top: 1px solid #e2e8f0 !important; +} + +details [class*='collapsibleContent'] p, +details [class*='collapsibleContent'] ul { + font-size: 13px !important; + line-height: 1.75; +} + +[data-theme='dark'] details { + background-color: #1c2130 !important; + color: #e5e7eb !important; + border: 1px solid #2d3748 !important; + box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.3) !important; +} + +[data-theme='dark'] details summary { + color: #f3f4f6 !important; +} + +[data-theme='dark'] details [class*='collapsibleContent'] { + border-top: 1px solid #2d3748 !important; +} + +/* ========================================= + TABS + ========================================= */ +.tabs-container > div { + padding: 1rem; + border: 1px solid #e2e8f0; + border-radius: var(--ifm-border-radius); +} + +/* Remove styling from nested tabs containers */ +.tabs-container .tabs-container > div { + padding: 0; + border: none; + border-radius: 0; +} + +[data-theme='dark'] .tabs-container > div { + border-color: #2d3748; +} + +ul.tabs { + border-bottom: 1px solid #e2e8f0 !important; + column-gap: 0.5rem !important; +} + +[data-theme='dark'] ul.tabs { + border-bottom-color: #2d3748 !important; +} + +li.tabs__item { + padding: 0.5rem !important; + font-weight: 500 !important; + font-size: 14px !important; + border-bottom: 2px solid transparent !important; +} + +li.tabs__item--active { + border-bottom: 2px solid var(--ifm-color-primary) !important; +} + +/* ========================================= + CODE BLOCKS + ========================================= */ +.prism-code { + border-radius: var(--ifm-border-radius); + font-size: 12.5px !important; + line-height: 1.6; +} + +[data-theme='dark'] .prism-code { + border: 1px solid #21262d; +} + +[class*='codeLineNumber']::before { + font-size: 12px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +[class*='codeBlockTitle'] { + font-size: 13px !important; + font-weight: 500 !important; + padding: 0.5rem 1rem !important; + border-bottom: 1px solid #334155 !important; +} + +.theme-code-block-highlighted-line { + background-color: rgba(0, 0, 0, 0.1) !important; +} + +[data-theme='dark'] .theme-code-block-highlighted-line { + background-color: rgba(255, 255, 255, 0.06) !important; +} + +.theme-code-block-highlighted-line > span { + background-color: transparent !important; +} + +/* ========================================= + SIDEBAR / MENU + ========================================= */ +.menu { + font-weight: 400; + padding: 0.5rem 0.25rem !important; + background-image: radial-gradient(rgba(0, 0, 0, 0.07) 1px, transparent 1px); + background-size: 24px 24px; +} + +[data-theme='dark'] .menu { + background-image: radial-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px); + background-size: 24px 24px; +} + +.menu__link { + font-size: 14px; + padding: 0.22rem 0.75rem !important; + border-radius: 4px; +} + +.menu__link--active { + font-weight: 600 !important; + background-color: rgba(46, 133, 85, 0.08) !important; +} + +[data-theme='dark'] .menu__link--active { + background-color: rgba(37, 194, 160, 0.1) !important; +} + +/* ─── Sidebar collapse arrows — uniform size & alignment ────── */ + +/* 1. Categories WITHOUT a link prop: + The button itself holds the text + ::after arrow. + Make it flex so the arrow never wraps to a new line. */ +.menu__link--sublist-caret { + display: flex !important; + align-items: center !important; + justify-content: space-between !important; + gap: 0.5rem; + padding-right: 0.625rem !important; +} + +.menu__link--sublist-caret::after { + content: '' !important; + display: block !important; + flex-shrink: 0 !important; + width: 1.25rem !important; + height: 1.25rem !important; + min-width: 1.25rem !important; + background: var(--ifm-menu-link-sublist-icon) center / 1.25rem 1.25rem no-repeat !important; + margin: 0 !important; +} + +/* 2. Categories WITH a link prop: + A separate +
))} -
@@ -462,7 +461,6 @@ const DefaultUserSettings: React.FC = ({ (isEditing ? (
-
) : ( - + ))} From 7b5a6f35c4d147755645f6d38e90befda7df3b8d Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Tue, 17 Mar 2026 03:46:37 +0530 Subject: [PATCH 201/289] Update sidebar and documentation for Guardrail Providers --- docs/my-website/docs/integrations/index.md | 8 +- .../docs/proxy/docker_quick_start.md | 87 +++++++- docs/my-website/sidebars.js | 211 +++++++++--------- 3 files changed, 185 insertions(+), 121 deletions(-) diff --git a/docs/my-website/docs/integrations/index.md b/docs/my-website/docs/integrations/index.md index 2bd02d7ae6..0134fdc4df 100644 --- a/docs/my-website/docs/integrations/index.md +++ b/docs/my-website/docs/integrations/index.md @@ -113,19 +113,13 @@ items={[ --- -## Guardrails +## Guardrail Providers Add safety and content filtering to LLM calls. -Use this docker compose to spin up the proxy with a postgres database running locally. +### Step 1 — Pull the LiteLLM database image + +LiteLLM provides a pre-built image with Postgres bundled in. Pull it before starting. + +```bash +docker pull ghcr.io/berriai/litellm-database:main-latest +``` + +See all available tags on the [GitHub Container Registry](https://github.com/BerriAI/litellm/pkgs/container/litellm-database). + +--- + +### Step 2 — Set up your config.yaml (do this before starting the server) + +Create a `litellm_config.yaml` file. You **must** add your model and database settings here before starting the proxy. + +```yaml +model_list: + - model_name: gpt-4o + litellm_params: + model: azure/my_azure_deployment + api_base: os.environ/AZURE_API_BASE + api_key: os.environ/AZURE_API_KEY + api_version: "2025-01-01-preview" + +general_settings: + master_key: sk-1234 # 🔑 your proxy admin key (must start with sk-) + database_url: "postgresql://:@:/" # 👈 required for virtual keys +``` + +:::tip +`database_url` is required for virtual keys, spend tracking, and the UI. Use [Supabase](https://supabase.com/) or [Neon](https://neon.tech/) for a free managed Postgres instance. +::: + +Get the docker compose file and create your `.env`: ```bash # Get the docker compose file @@ -46,16 +81,55 @@ curl -O https://raw.githubusercontent.com/BerriAI/litellm/main/docker-compose.ym # Add the master key - you can change this after setup echo 'LITELLM_MASTER_KEY="sk-1234"' > .env -# Add the litellm salt key - you cannot change this after adding a model -# It is used to encrypt / decrypt your LLM API Key credentials -# We recommend - https://1password.com/password-generator/ -# password generator to get a random hash for litellm salt key +# Add the litellm salt key — cannot be changed after adding a model +# Used to encrypt/decrypt your LLM API key credentials +# Generate a strong random value: https://1password.com/password-generator/ echo 'LITELLM_SALT_KEY="sk-1234"' >> .env +``` -# Start +--- + +### Step 3 — Start the proxy server and test it + +```bash docker compose up ``` +Once running, test it with a curl request: + +```bash +curl -X POST 'http://0.0.0.0:4000/chat/completions' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer sk-1234' \ + -d '{ + "model": "gpt-4o", + "messages": [{"role": "user", "content": "Hello!"}] + }' +``` + +**Expected response:** + +```json +{ + "id": "chatcmpl-abc123", + "object": "chat.completion", + "choices": [{"message": {"role": "assistant", "content": "Hello! How can I help you?"}, "finish_reason": "stop"}], + "usage": {"prompt_tokens": 10, "completion_tokens": 9, "total_tokens": 19} +} +``` + +--- + +### Optional — Navigate to the LiteLLM UI and generate a virtual key + +Open [http://localhost:4000/ui](http://localhost:4000/ui) in your browser and log in with your master key (`sk-1234`). + +Navigate to **Virtual Keys** and click **+ Create New Key**: + +LiteLLM UI — Create Virtual Key + +Virtual keys let you track spend, set rate limits, and control model access per user or team. + @@ -647,4 +721,3 @@ LiteLLM Proxy uses the [LiteLLM Python SDK](https://docs.litellm.ai/docs/routing [![Chat on WhatsApp](https://img.shields.io/static/v1?label=Chat%20on&message=WhatsApp&color=success&logo=WhatsApp&style=flat-square)](https://wa.link/huol9n) [![Chat on Discord](https://img.shields.io/static/v1?label=Chat%20on&message=Discord&color=blue&logo=Discord&style=flat-square)](https://discord.gg/wuPM9dRgDw) - diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index 8f05bf94f7..8d361a2632 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -44,70 +44,39 @@ const sidebars = { }, { type: "category", - label: "Guardrails", + label: "Guardrail Providers", items: [ - "proxy/guardrails/quick_start", - "proxy/guardrails/team_based_guardrails", - "proxy/guardrails/guardrail_load_balancing", - "proxy/guardrails/test_playground", - "proxy/guardrails/litellm_content_filter", - "proxy/guardrails/realtime_guardrails", - { - type: "category", - label: "Providers", - items: [ - ...[ - "proxy/guardrails/qualifire", - "proxy/guardrails/aim_security", - "proxy/guardrails/onyx_security", - "proxy/guardrails/aporia_api", - "proxy/guardrails/azure_content_guardrail", - "proxy/guardrails/bedrock", - "proxy/guardrails/crowdstrike_aidr", - "proxy/guardrails/enkryptai", - "proxy/guardrails/ibm_guardrails", - "proxy/guardrails/grayswan", - "proxy/guardrails/hiddenlayer", - "proxy/guardrails/lasso_security", - "proxy/guardrails/guardrails_ai", - "proxy/guardrails/lakera_ai", - "proxy/guardrails/model_armor", - "proxy/guardrails/noma_security", - "proxy/guardrails/dynamoai", - "proxy/guardrails/openai_moderation", - "proxy/guardrails/pangea", - "proxy/guardrails/pillar_security", - "proxy/guardrails/pii_masking_v2", - "proxy/guardrails/panw_prisma_airs", - "proxy/guardrails/secret_detection", - "proxy/guardrails/custom_guardrail", - "proxy/guardrails/custom_code_guardrail", - "proxy/guardrails/prompt_injection", - "proxy/guardrails/tool_permission", - "proxy/guardrails/zscaler_ai_guard", - "proxy/guardrails/javelin" - ].sort(), - ], - }, - { - type: "category", - label: "Contributing to Guardrails", - items: [ - "adding_provider/generic_guardrail_api", - "adding_provider/simple_guardrail_tutorial", - "adding_provider/adding_guardrail_support", - ] - }, - ], - }, - { - type: "category", - label: "Policies", - items: [ - "proxy/guardrails/guardrail_policies", - "proxy/guardrails/policy_flow_builder", - "proxy/guardrails/policy_templates", - "proxy/guardrails/policy_tags", + ...[ + "proxy/guardrails/qualifire", + "proxy/guardrails/aim_security", + "proxy/guardrails/onyx_security", + "proxy/guardrails/aporia_api", + "proxy/guardrails/azure_content_guardrail", + "proxy/guardrails/bedrock", + "proxy/guardrails/crowdstrike_aidr", + "proxy/guardrails/enkryptai", + "proxy/guardrails/ibm_guardrails", + "proxy/guardrails/grayswan", + "proxy/guardrails/hiddenlayer", + "proxy/guardrails/lasso_security", + "proxy/guardrails/guardrails_ai", + "proxy/guardrails/lakera_ai", + "proxy/guardrails/model_armor", + "proxy/guardrails/noma_security", + "proxy/guardrails/dynamoai", + "proxy/guardrails/openai_moderation", + "proxy/guardrails/pangea", + "proxy/guardrails/pillar_security", + "proxy/guardrails/pii_masking_v2", + "proxy/guardrails/panw_prisma_airs", + "proxy/guardrails/secret_detection", + "proxy/guardrails/custom_guardrail", + "proxy/guardrails/custom_code_guardrail", + "proxy/guardrails/prompt_injection", + "proxy/guardrails/tool_permission", + "proxy/guardrails/zscaler_ai_guard", + "proxy/guardrails/javelin" + ].sort(), ], }, { @@ -293,11 +262,6 @@ const sidebars = { }, "completion/token_usage", "exception_mapping", - { - type: "category", - label: "LangChain, LlamaIndex, Instructor", - items: ["langchain/langchain", "tutorials/instructor"], - } ], }, { @@ -310,16 +274,41 @@ const sidebars = { slug: "/simple_proxy", }, items: [ - "proxy/docker_quick_start", + { type: "doc", id: "proxy/docker_quick_start", label: "Getting Started Tutorial" }, { - type: "link", - label: "A2A Agent Gateway", - href: "https://docs.litellm.ai/docs/a2a", - }, - { - type: "link", - label: "MCP Gateway", - href: "https://docs.litellm.ai/docs/mcp", + type: "category", + label: "Agent & MCP Gateway", + items: [ + { + type: "category", + label: "A2A Agent Gateway", + items: [ + "a2a", + "a2a_invoking_agents", + "a2a_agent_headers", + "a2a_cost_tracking", + "a2a_agent_permissions", + "a2a_iteration_budgets", + ], + }, + { + type: "category", + label: "MCP Gateway", + items: [ + "mcp", + "mcp_usage", + "mcp_openapi", + "mcp_oauth", + "mcp_aws_sigv4", + "mcp_public_internet", + "mcp_semantic_filter", + "mcp_control", + "mcp_cost", + "mcp_guardrail", + "mcp_troubleshoot", + ], + }, + ], }, { "type": "category", @@ -461,14 +450,40 @@ const sidebars = { }, "proxy/caching", { - type: "link", + type: "category", label: "Guardrails", - href: "https://docs.litellm.ai/docs/proxy/guardrails/quick_start", + items: [ + "proxy/guardrails/quick_start", + "proxy/guardrails/team_based_guardrails", + "proxy/guardrails/guardrail_load_balancing", + "proxy/guardrails/test_playground", + "proxy/guardrails/litellm_content_filter", + "proxy/guardrails/realtime_guardrails", + { + type: "link", + label: "Providers →", + href: "/docs/integrations#guardrail-providers", + }, + { + type: "category", + label: "Contributing to Guardrails", + items: [ + "adding_provider/generic_guardrail_api", + "adding_provider/simple_guardrail_tutorial", + "adding_provider/adding_guardrail_support", + ] + }, + ], }, { - type: "link", + type: "category", label: "Policies", - href: "https://docs.litellm.ai/docs/proxy/guardrails/guardrail_policies", + items: [ + "proxy/guardrails/guardrail_policies", + "proxy/guardrails/policy_flow_builder", + "proxy/guardrails/policy_templates", + "proxy/guardrails/policy_tags", + ], }, { type: "category", @@ -564,16 +579,9 @@ const sidebars = { }, items: [ { - type: "category", + type: "link", label: "/a2a - A2A Agent Gateway", - items: [ - "a2a", - "a2a_invoking_agents", - "a2a_agent_headers", - "a2a_cost_tracking", - "a2a_agent_permissions", - "a2a_iteration_budgets" - ], + href: "/docs/simple_proxy#agent--mcp-gateway", }, "assistants", "audio_transcription", @@ -636,21 +644,9 @@ const sidebars = { "vector_stores/create", "vector_stores/search", { - type: "category", + type: "link", label: "/mcp - Model Context Protocol", - items: [ - "mcp", - "mcp_usage", - "mcp_openapi", - "mcp_oauth", - "mcp_aws_sigv4", - "mcp_public_internet", - "mcp_semantic_filter", - "mcp_control", - "mcp_cost", - "mcp_guardrail", - "mcp_troubleshoot", - ] + href: "/docs/simple_proxy#agent--mcp-gateway", }, { type: "category", @@ -990,10 +986,10 @@ const sidebars = { { type: "category", - label: "Routing, Loadbalancing & Fallbacks", + label: "Routing & Load Balancing", link: { type: "generated-index", - title: "Routing, Loadbalancing & Fallbacks", + title: "Routing & Load Balancing", description: "Learn how to load balance, route, and set fallbacks for your LLM requests", slug: "/routing-load-balancing", }, @@ -1232,7 +1228,8 @@ const learnSidebar = { "tutorials/copilotkit_sdk", "tutorials/google_adk", "tutorials/livekit_xai_realtime", - "tutorials/instructor", + { type: "doc", id: "tutorials/instructor", label: "Instructor with LiteLLM" }, + { type: "doc", id: "langchain/langchain", label: "LangChain with LiteLLM" }, ], }, { From bc8eba34091e164acfd73840f08836a9b10c49e6 Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Tue, 17 Mar 2026 03:51:22 +0530 Subject: [PATCH 202/289] Update sidebar links for A2A Agent Gateway and Model Context Protocol documentation --- docs/my-website/sidebars.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index 8d361a2632..bb77a3cc7c 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -581,7 +581,7 @@ const sidebars = { { type: "link", label: "/a2a - A2A Agent Gateway", - href: "/docs/simple_proxy#agent--mcp-gateway", + href: "/docs/a2a", }, "assistants", "audio_transcription", @@ -646,7 +646,7 @@ const sidebars = { { type: "link", label: "/mcp - Model Context Protocol", - href: "/docs/simple_proxy#agent--mcp-gateway", + href: "/docs/mcp", }, { type: "category", From 92f830ebea028e5157034647dfbb4638f5c6a63e Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Tue, 17 Mar 2026 03:58:39 +0530 Subject: [PATCH 203/289] fix: top navbar issue --- docs/my-website/docusaurus.config.js | 32 +++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/docs/my-website/docusaurus.config.js b/docs/my-website/docusaurus.config.js index 1b46ed107d..ec3ba19188 100644 --- a/docs/my-website/docusaurus.config.js +++ b/docs/my-website/docusaurus.config.js @@ -195,6 +195,20 @@ const config = { }; }, }), + // Ensure gtag exists before the GA script loads. + () => ({ + name: 'gtag-shim', + injectHtmlTags() { + return { + headTags: [ + { + tagName: 'script', + innerHTML: `window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}if(!window.gtag){window.gtag=gtag;}`, + }, + ], + }; + }, + }), ], presets: [ @@ -202,10 +216,13 @@ const config = { 'classic', /** @type {import('@docusaurus/preset-classic').Options} */ ({ - gtag: { - trackingID: 'G-K7K215ZVNC', - anonymizeIP: true, - }, + gtag: + process.env.NODE_ENV === 'production' + ? { + trackingID: 'G-K7K215ZVNC', + anonymizeIP: true, + } + : undefined, docs: { sidebarPath: require.resolve('./sidebars.js'), }, @@ -245,6 +262,12 @@ const config = { position: 'left', label: 'Docs', }, + { + type: 'docSidebar', + sidebarId: 'learnSidebar', + position: 'left', + label: 'Learn', + }, { type: 'docSidebar', sidebarId: 'integrationsSidebar', @@ -256,7 +279,6 @@ const config = { label: 'Enterprise', to: "docs/enterprise" }, - { to: '/release_notes', label: 'Release Notes', position: 'left' }, { to: '/blog', label: 'Blog', position: 'left' }, { href: 'https://github.com/BerriAI/litellm', From 278c9babc6ff75d7f0301b5b7f02afc266557d0b Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Mon, 16 Mar 2026 15:32:20 -0700 Subject: [PATCH 204/289] [Infra] Merging RC Branch with Main (#23786) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(test): add missing mocks for test_streamable_http_mcp_handler_mock The test was missing mocks for extract_mcp_auth_context and set_auth_context, causing the handler to fail silently in the except block instead of reaching session_manager.handle_request. This mirrors the fix already applied to the sibling test_sse_mcp_handler_mock. Co-authored-by: Ishaan Jaff * fix(ci): route OpenAI models through chat completions in pass-through tests The test_anthropic_messages_openai_model_streaming_cost_injection test fails because the OpenAI Responses API returns 400 for requests routed through the Anthropic Messages endpoint. Setting LITELLM_USE_CHAT_COMPLETIONS_URL_FOR_ANTHROPIC_MESSAGES=true routes OpenAI models through the stable chat completions path instead. Cost injection still works since it happens at the proxy level. Co-authored-by: Ishaan Jaff * fix(ci): fix assemblyai custom auth and router wildcard test flakiness 1. custom_auth_basic.py: Add user_role='proxy_admin' so the custom auth user can access management endpoints like /key/generate. The test test_assemblyai_transcribe_with_non_admin_key was hidden behind an earlier -x failure and was never reached before. 2. test_router_utils.py: Add flaky(retries=3) and increase sleep from 1s to 2s for test_router_get_model_group_usage_wildcard_routes. The async callback needs time to write usage to cache, and 1s is insufficient on slower CI hardware. Co-authored-by: Ishaan Jaff * ci: retrigger CI pipeline Co-authored-by: Ishaan Jaff * fix(mypy): use LitellmUserRoles enum instead of raw string in custom_auth_basic Fixes mypy error: Argument 'user_role' has incompatible type 'str'; expected 'LitellmUserRoles | None' Co-authored-by: Ishaan Jaff * fix: don't close HTTP/SDK clients on LLMClientCache eviction (#22926) * fix: don't close HTTP/SDK clients on LLMClientCache eviction Removing the _remove_key override that eagerly called aclose()/close() on evicted clients. Evicted clients may still be held by in-flight streaming requests; closing them causes: RuntimeError: Cannot send a request, as the client has been closed. This is a regression from commit fb72979432. Clients that are no longer referenced will be garbage-collected naturally. Explicit shutdown cleanup happens via close_litellm_async_clients(). Fixes production crashes after the 1-hour cache TTL expires. * test: update LLMClientCache unit tests for no-close-on-eviction behavior Flip the assertions: evicted clients must NOT be closed. Replace test_remove_key_closes_async_client → test_remove_key_does_not_close_async_client and equivalents for sync/eviction paths. Add test_remove_key_removes_plain_values for non-client cache entries. Remove test_background_tasks_cleaned_up_after_completion (no more _background_tasks). Remove test_remove_key_no_event_loop variant that depended on old behavior. * test: add e2e tests for OpenAI SDK client surviving cache eviction Add two new e2e tests using real AsyncOpenAI clients: - test_evicted_openai_sdk_client_stays_usable: verifies size-based eviction doesn't close the client - test_ttl_expired_openai_sdk_client_stays_usable: verifies TTL expiry eviction doesn't close the client Both tests sleep after eviction so any create_task()-based close would have time to run, making the regression detectable. Also expand the module docstring to explain why the sleep is required. * docs(AGENTS.md): add rule — never close HTTP/SDK clients on cache eviction * docs(CLAUDE.md): add HTTP client cache safety guideline * [Fix] Install bsdmainutils for column command in security scans The security_scans.sh script uses `column` to format vulnerability output, but the package wasn't installed in the CI environment. Co-Authored-By: Claude Opus 4.6 * fix: handle string callback values in prometheus multiproc setup When callbacks are configured as a plain string (e.g., `callbacks: "my_callback"`) instead of a list, the proxy crashes on startup with: TypeError: can only concatenate str (not "list") to str Normalize each callback setting to a list before concatenating. Co-Authored-By: Claude Opus 4.6 * bump: version 1.82.2 → 1.82.3 * fix(test): update test_startup_fails_when_db_setup_fails for opt-in enforcement The --enforce_prisma_migration_check flag is now required to trigger sys.exit(1) on DB migration failure, after #23675 flipped the default behavior to warn-and-continue. Co-Authored-By: Claude Opus 4.6 * fix(cost_calculator): use model name for per-request custom pricing when router_model_id has no pricing When custom pricing is passed as per-request kwargs (input_cost_per_token/output_cost_per_token), completion() registers pricing under the model name, but _select_model_name_for_cost_calc was selecting the router deployment hash (which has no pricing data), causing response_cost to be 0.0. Now checks whether the router_model_id entry actually has pricing before preferring it. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Cursor Agent Co-authored-by: Ishaan Jaff Co-authored-by: Ishaan Jaff Co-authored-by: Claude Opus 4.6 --- .circleci/config.yml | 1 + CLAUDE.md | 2 +- ci_cd/security_scans.sh | 2 +- litellm/cost_calculator.py | 9 ++- .../out/{404.html => 404/index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../{budgets.html => budgets/index.html} | 0 .../{caching.html => caching/index.html} | 0 .../index.html} | 0 .../{old-usage.html => old-usage/index.html} | 0 .../{prompts.html => prompts/index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../out/{login.html => login/index.html} | 0 .../out/{logs.html => logs/index.html} | 0 .../{callback.html => callback/index.html} | 0 .../{model-hub.html => model-hub/index.html} | 0 .../{model_hub.html => model_hub/index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../{policies.html => policies/index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../{ui-theme.html => ui-theme/index.html} | 0 .../out/{teams.html => teams/index.html} | 0 .../{test-key.html => test-key/index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../out/{usage.html => usage/index.html} | 0 .../out/{users.html => users/index.html} | 0 .../index.html} | 0 .../example_config_yaml/custom_auth_basic.py | 3 +- litellm/proxy/proxy_cli.py | 7 +++ pyproject.toml | 4 +- tests/local_testing/test_router_utils.py | 3 +- tests/mcp_tests/test_mcp_server.py | 3 + .../proxy/test_prometheus_cleanup.py | 24 ++++++++ tests/test_litellm/proxy/test_proxy_cli.py | 4 +- tests/test_litellm/test_cost_calculator.py | 59 +++++++++++++++++++ 45 files changed, 112 insertions(+), 9 deletions(-) rename litellm/proxy/_experimental/out/{404.html => 404/index.html} (100%) rename litellm/proxy/_experimental/out/{_not-found.html => _not-found/index.html} (100%) rename litellm/proxy/_experimental/out/{api-reference.html => api-reference/index.html} (100%) rename litellm/proxy/_experimental/out/experimental/{api-playground.html => api-playground/index.html} (100%) rename litellm/proxy/_experimental/out/experimental/{budgets.html => budgets/index.html} (100%) rename litellm/proxy/_experimental/out/experimental/{caching.html => caching/index.html} (100%) rename litellm/proxy/_experimental/out/experimental/{claude-code-plugins.html => claude-code-plugins/index.html} (100%) rename litellm/proxy/_experimental/out/experimental/{old-usage.html => old-usage/index.html} (100%) rename litellm/proxy/_experimental/out/experimental/{prompts.html => prompts/index.html} (100%) rename litellm/proxy/_experimental/out/experimental/{tag-management.html => tag-management/index.html} (100%) rename litellm/proxy/_experimental/out/{guardrails.html => guardrails/index.html} (100%) rename litellm/proxy/_experimental/out/{login.html => login/index.html} (100%) rename litellm/proxy/_experimental/out/{logs.html => logs/index.html} (100%) rename litellm/proxy/_experimental/out/mcp/oauth/{callback.html => callback/index.html} (100%) rename litellm/proxy/_experimental/out/{model-hub.html => model-hub/index.html} (100%) rename litellm/proxy/_experimental/out/{model_hub.html => model_hub/index.html} (100%) rename litellm/proxy/_experimental/out/{model_hub_table.html => model_hub_table/index.html} (100%) rename litellm/proxy/_experimental/out/{models-and-endpoints.html => models-and-endpoints/index.html} (100%) rename litellm/proxy/_experimental/out/{onboarding.html => onboarding/index.html} (100%) rename litellm/proxy/_experimental/out/{organizations.html => organizations/index.html} (100%) rename litellm/proxy/_experimental/out/{playground.html => playground/index.html} (100%) rename litellm/proxy/_experimental/out/{policies.html => policies/index.html} (100%) rename litellm/proxy/_experimental/out/settings/{admin-settings.html => admin-settings/index.html} (100%) rename litellm/proxy/_experimental/out/settings/{logging-and-alerts.html => logging-and-alerts/index.html} (100%) rename litellm/proxy/_experimental/out/settings/{router-settings.html => router-settings/index.html} (100%) rename litellm/proxy/_experimental/out/settings/{ui-theme.html => ui-theme/index.html} (100%) rename litellm/proxy/_experimental/out/{teams.html => teams/index.html} (100%) rename litellm/proxy/_experimental/out/{test-key.html => test-key/index.html} (100%) rename litellm/proxy/_experimental/out/tools/{mcp-servers.html => mcp-servers/index.html} (100%) rename litellm/proxy/_experimental/out/tools/{vector-stores.html => vector-stores/index.html} (100%) rename litellm/proxy/_experimental/out/{usage.html => usage/index.html} (100%) rename litellm/proxy/_experimental/out/{users.html => users/index.html} (100%) rename litellm/proxy/_experimental/out/{virtual-keys.html => virtual-keys/index.html} (100%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 38e6d1fc33..12e3cb1f6b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3218,6 +3218,7 @@ jobs: -e DD_API_KEY=$DD_API_KEY \ -e DD_SITE=$DD_SITE \ -e LITELLM_LICENSE=$LITELLM_LICENSE \ + -e LITELLM_USE_CHAT_COMPLETIONS_URL_FOR_ANTHROPIC_MESSAGES=true \ --add-host host.docker.internal:host-gateway \ --name my-app \ -v $(pwd)/litellm/proxy/example_config_yaml/pass_through_config.yaml:/app/config.yaml \ diff --git a/CLAUDE.md b/CLAUDE.md index 5395d6d938..d9061b5e2b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -156,4 +156,4 @@ LiteLLM is a unified interface for 100+ LLM providers with two main components: **Fix options:** 1. **Create a Prisma migration** (permanent) — run `prisma migrate dev --name ` in the worktree. The generated file will be picked up by `prisma migrate deploy` on next startup. 2. **Apply manually for local dev** — `psql -d litellm -c "ALTER TABLE ... ADD COLUMN IF NOT EXISTS ..."` after each proxy start. Fine for dev, not for production. -3. **Update litellm-proxy-extras** — if the package is installed from PyPI, its migration directory must include the new file. Either update the package or run the migration manually until the next release ships it. \ No newline at end of file +3. **Update litellm-proxy-extras** — if the package is installed from PyPI, its migration directory must include the new file. Either update the package or run the migration manually until the next release ships it. diff --git a/ci_cd/security_scans.sh b/ci_cd/security_scans.sh index 62440d13eb..e0f370e003 100755 --- a/ci_cd/security_scans.sh +++ b/ci_cd/security_scans.sh @@ -11,7 +11,7 @@ echo "Starting security scans for LiteLLM..." install_trivy() { echo "Installing Trivy and required tools..." sudo apt-get update - sudo apt-get install -y wget apt-transport-https gnupg lsb-release jq curl + sudo apt-get install -y wget apt-transport-https gnupg lsb-release jq curl bsdmainutils wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add - echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list sudo apt-get update diff --git a/litellm/cost_calculator.py b/litellm/cost_calculator.py index a3ef7b264e..e0e1e35b94 100644 --- a/litellm/cost_calculator.py +++ b/litellm/cost_calculator.py @@ -660,7 +660,14 @@ def _select_model_name_for_cost_calc( if custom_pricing is True: if router_model_id is not None and router_model_id in litellm.model_cost: - return_model = router_model_id + entry = litellm.model_cost[router_model_id] + if ( + entry.get("input_cost_per_token") is not None + or entry.get("input_cost_per_second") is not None + ): + return_model = router_model_id + else: + return_model = model else: return_model = model diff --git a/litellm/proxy/_experimental/out/404.html b/litellm/proxy/_experimental/out/404/index.html similarity index 100% rename from litellm/proxy/_experimental/out/404.html rename to litellm/proxy/_experimental/out/404/index.html diff --git a/litellm/proxy/_experimental/out/_not-found.html b/litellm/proxy/_experimental/out/_not-found/index.html similarity index 100% rename from litellm/proxy/_experimental/out/_not-found.html rename to litellm/proxy/_experimental/out/_not-found/index.html diff --git a/litellm/proxy/_experimental/out/api-reference.html b/litellm/proxy/_experimental/out/api-reference/index.html similarity index 100% rename from litellm/proxy/_experimental/out/api-reference.html rename to litellm/proxy/_experimental/out/api-reference/index.html diff --git a/litellm/proxy/_experimental/out/experimental/api-playground.html b/litellm/proxy/_experimental/out/experimental/api-playground/index.html similarity index 100% rename from litellm/proxy/_experimental/out/experimental/api-playground.html rename to litellm/proxy/_experimental/out/experimental/api-playground/index.html diff --git a/litellm/proxy/_experimental/out/experimental/budgets.html b/litellm/proxy/_experimental/out/experimental/budgets/index.html similarity index 100% rename from litellm/proxy/_experimental/out/experimental/budgets.html rename to litellm/proxy/_experimental/out/experimental/budgets/index.html diff --git a/litellm/proxy/_experimental/out/experimental/caching.html b/litellm/proxy/_experimental/out/experimental/caching/index.html similarity index 100% rename from litellm/proxy/_experimental/out/experimental/caching.html rename to litellm/proxy/_experimental/out/experimental/caching/index.html diff --git a/litellm/proxy/_experimental/out/experimental/claude-code-plugins.html b/litellm/proxy/_experimental/out/experimental/claude-code-plugins/index.html similarity index 100% rename from litellm/proxy/_experimental/out/experimental/claude-code-plugins.html rename to litellm/proxy/_experimental/out/experimental/claude-code-plugins/index.html diff --git a/litellm/proxy/_experimental/out/experimental/old-usage.html b/litellm/proxy/_experimental/out/experimental/old-usage/index.html similarity index 100% rename from litellm/proxy/_experimental/out/experimental/old-usage.html rename to litellm/proxy/_experimental/out/experimental/old-usage/index.html diff --git a/litellm/proxy/_experimental/out/experimental/prompts.html b/litellm/proxy/_experimental/out/experimental/prompts/index.html similarity index 100% rename from litellm/proxy/_experimental/out/experimental/prompts.html rename to litellm/proxy/_experimental/out/experimental/prompts/index.html diff --git a/litellm/proxy/_experimental/out/experimental/tag-management.html b/litellm/proxy/_experimental/out/experimental/tag-management/index.html similarity index 100% rename from litellm/proxy/_experimental/out/experimental/tag-management.html rename to litellm/proxy/_experimental/out/experimental/tag-management/index.html diff --git a/litellm/proxy/_experimental/out/guardrails.html b/litellm/proxy/_experimental/out/guardrails/index.html similarity index 100% rename from litellm/proxy/_experimental/out/guardrails.html rename to litellm/proxy/_experimental/out/guardrails/index.html diff --git a/litellm/proxy/_experimental/out/login.html b/litellm/proxy/_experimental/out/login/index.html similarity index 100% rename from litellm/proxy/_experimental/out/login.html rename to litellm/proxy/_experimental/out/login/index.html diff --git a/litellm/proxy/_experimental/out/logs.html b/litellm/proxy/_experimental/out/logs/index.html similarity index 100% rename from litellm/proxy/_experimental/out/logs.html rename to litellm/proxy/_experimental/out/logs/index.html diff --git a/litellm/proxy/_experimental/out/mcp/oauth/callback.html b/litellm/proxy/_experimental/out/mcp/oauth/callback/index.html similarity index 100% rename from litellm/proxy/_experimental/out/mcp/oauth/callback.html rename to litellm/proxy/_experimental/out/mcp/oauth/callback/index.html diff --git a/litellm/proxy/_experimental/out/model-hub.html b/litellm/proxy/_experimental/out/model-hub/index.html similarity index 100% rename from litellm/proxy/_experimental/out/model-hub.html rename to litellm/proxy/_experimental/out/model-hub/index.html diff --git a/litellm/proxy/_experimental/out/model_hub.html b/litellm/proxy/_experimental/out/model_hub/index.html similarity index 100% rename from litellm/proxy/_experimental/out/model_hub.html rename to litellm/proxy/_experimental/out/model_hub/index.html diff --git a/litellm/proxy/_experimental/out/model_hub_table.html b/litellm/proxy/_experimental/out/model_hub_table/index.html similarity index 100% rename from litellm/proxy/_experimental/out/model_hub_table.html rename to litellm/proxy/_experimental/out/model_hub_table/index.html diff --git a/litellm/proxy/_experimental/out/models-and-endpoints.html b/litellm/proxy/_experimental/out/models-and-endpoints/index.html similarity index 100% rename from litellm/proxy/_experimental/out/models-and-endpoints.html rename to litellm/proxy/_experimental/out/models-and-endpoints/index.html diff --git a/litellm/proxy/_experimental/out/onboarding.html b/litellm/proxy/_experimental/out/onboarding/index.html similarity index 100% rename from litellm/proxy/_experimental/out/onboarding.html rename to litellm/proxy/_experimental/out/onboarding/index.html diff --git a/litellm/proxy/_experimental/out/organizations.html b/litellm/proxy/_experimental/out/organizations/index.html similarity index 100% rename from litellm/proxy/_experimental/out/organizations.html rename to litellm/proxy/_experimental/out/organizations/index.html diff --git a/litellm/proxy/_experimental/out/playground.html b/litellm/proxy/_experimental/out/playground/index.html similarity index 100% rename from litellm/proxy/_experimental/out/playground.html rename to litellm/proxy/_experimental/out/playground/index.html diff --git a/litellm/proxy/_experimental/out/policies.html b/litellm/proxy/_experimental/out/policies/index.html similarity index 100% rename from litellm/proxy/_experimental/out/policies.html rename to litellm/proxy/_experimental/out/policies/index.html diff --git a/litellm/proxy/_experimental/out/settings/admin-settings.html b/litellm/proxy/_experimental/out/settings/admin-settings/index.html similarity index 100% rename from litellm/proxy/_experimental/out/settings/admin-settings.html rename to litellm/proxy/_experimental/out/settings/admin-settings/index.html diff --git a/litellm/proxy/_experimental/out/settings/logging-and-alerts.html b/litellm/proxy/_experimental/out/settings/logging-and-alerts/index.html similarity index 100% rename from litellm/proxy/_experimental/out/settings/logging-and-alerts.html rename to litellm/proxy/_experimental/out/settings/logging-and-alerts/index.html diff --git a/litellm/proxy/_experimental/out/settings/router-settings.html b/litellm/proxy/_experimental/out/settings/router-settings/index.html similarity index 100% rename from litellm/proxy/_experimental/out/settings/router-settings.html rename to litellm/proxy/_experimental/out/settings/router-settings/index.html diff --git a/litellm/proxy/_experimental/out/settings/ui-theme.html b/litellm/proxy/_experimental/out/settings/ui-theme/index.html similarity index 100% rename from litellm/proxy/_experimental/out/settings/ui-theme.html rename to litellm/proxy/_experimental/out/settings/ui-theme/index.html diff --git a/litellm/proxy/_experimental/out/teams.html b/litellm/proxy/_experimental/out/teams/index.html similarity index 100% rename from litellm/proxy/_experimental/out/teams.html rename to litellm/proxy/_experimental/out/teams/index.html diff --git a/litellm/proxy/_experimental/out/test-key.html b/litellm/proxy/_experimental/out/test-key/index.html similarity index 100% rename from litellm/proxy/_experimental/out/test-key.html rename to litellm/proxy/_experimental/out/test-key/index.html diff --git a/litellm/proxy/_experimental/out/tools/mcp-servers.html b/litellm/proxy/_experimental/out/tools/mcp-servers/index.html similarity index 100% rename from litellm/proxy/_experimental/out/tools/mcp-servers.html rename to litellm/proxy/_experimental/out/tools/mcp-servers/index.html diff --git a/litellm/proxy/_experimental/out/tools/vector-stores.html b/litellm/proxy/_experimental/out/tools/vector-stores/index.html similarity index 100% rename from litellm/proxy/_experimental/out/tools/vector-stores.html rename to litellm/proxy/_experimental/out/tools/vector-stores/index.html diff --git a/litellm/proxy/_experimental/out/usage.html b/litellm/proxy/_experimental/out/usage/index.html similarity index 100% rename from litellm/proxy/_experimental/out/usage.html rename to litellm/proxy/_experimental/out/usage/index.html diff --git a/litellm/proxy/_experimental/out/users.html b/litellm/proxy/_experimental/out/users/index.html similarity index 100% rename from litellm/proxy/_experimental/out/users.html rename to litellm/proxy/_experimental/out/users/index.html diff --git a/litellm/proxy/_experimental/out/virtual-keys.html b/litellm/proxy/_experimental/out/virtual-keys/index.html similarity index 100% rename from litellm/proxy/_experimental/out/virtual-keys.html rename to litellm/proxy/_experimental/out/virtual-keys/index.html diff --git a/litellm/proxy/example_config_yaml/custom_auth_basic.py b/litellm/proxy/example_config_yaml/custom_auth_basic.py index 4d633a54fe..0da6105a30 100644 --- a/litellm/proxy/example_config_yaml/custom_auth_basic.py +++ b/litellm/proxy/example_config_yaml/custom_auth_basic.py @@ -1,6 +1,6 @@ from fastapi import Request -from litellm.proxy._types import UserAPIKeyAuth +from litellm.proxy._types import LitellmUserRoles, UserAPIKeyAuth async def user_api_key_auth(request: Request, api_key: str) -> UserAPIKeyAuth: @@ -9,6 +9,7 @@ async def user_api_key_auth(request: Request, api_key: str) -> UserAPIKeyAuth: api_key="best-api-key-ever", user_id="best-user-id-ever", team_id="best-team-id-ever", + user_role=LitellmUserRoles.PROXY_ADMIN, ) except Exception: raise Exception diff --git a/litellm/proxy/proxy_cli.py b/litellm/proxy/proxy_cli.py index 701762c834..e5a34ae8bd 100644 --- a/litellm/proxy/proxy_cli.py +++ b/litellm/proxy/proxy_cli.py @@ -340,9 +340,16 @@ class ProxyInitializationHelpers: return # Check if prometheus is in any callback list + # Each setting can be a list or a single string; normalize to list callbacks = litellm_settings.get("callbacks") or [] success_callbacks = litellm_settings.get("success_callback") or [] failure_callbacks = litellm_settings.get("failure_callback") or [] + if isinstance(callbacks, str): + callbacks = [callbacks] + if isinstance(success_callbacks, str): + success_callbacks = [success_callbacks] + if isinstance(failure_callbacks, str): + failure_callbacks = [failure_callbacks] all_callbacks = callbacks + success_callbacks + failure_callbacks if "prometheus" not in all_callbacks: return diff --git a/pyproject.toml b/pyproject.toml index 8efc636612..07004f3ae1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "litellm" -version = "1.82.2" +version = "1.82.3" description = "Library to easily interface with LLM API providers" authors = ["BerriAI"] license = "MIT" @@ -183,7 +183,7 @@ requires = ["poetry-core", "wheel"] build-backend = "poetry.core.masonry.api" [tool.commitizen] -version = "1.82.2" +version = "1.82.3" version_files = [ "pyproject.toml:^version" ] diff --git a/tests/local_testing/test_router_utils.py b/tests/local_testing/test_router_utils.py index 9d51685751..4f7f53cef0 100644 --- a/tests/local_testing/test_router_utils.py +++ b/tests/local_testing/test_router_utils.py @@ -199,6 +199,7 @@ def test_router_get_model_info_wildcard_routes(): @pytest.mark.asyncio +@pytest.mark.flaky(retries=3, delay=1) async def test_router_get_model_group_usage_wildcard_routes(): os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True" litellm.model_cost = litellm.get_model_cost_map(url="") @@ -219,7 +220,7 @@ async def test_router_get_model_group_usage_wildcard_routes(): ) print(resp) - await asyncio.sleep(1) + await asyncio.sleep(2) tpm, rpm = await router.get_model_group_usage(model_group="gemini/gemini-1.5-flash") diff --git a/tests/mcp_tests/test_mcp_server.py b/tests/mcp_tests/test_mcp_server.py index 2544e06598..a4a28215e1 100644 --- a/tests/mcp_tests/test_mcp_server.py +++ b/tests/mcp_tests/test_mcp_server.py @@ -395,6 +395,7 @@ async def test_mcp_http_transport_tool_not_found(): @pytest.mark.asyncio async def test_streamable_http_mcp_handler_mock(): """Test the streamable HTTP MCP handler functionality""" + from litellm.proxy._types import UserAPIKeyAuth # Mock the session manager and its methods mock_session_manager = AsyncMock() @@ -425,6 +426,8 @@ async def test_streamable_http_mcp_handler_mock(): ), patch( "litellm.proxy._experimental.mcp_server.server.extract_mcp_auth_context", AsyncMock(return_value=mock_auth_context), + ), patch( + "litellm.proxy._experimental.mcp_server.server.set_auth_context", ): from litellm.proxy._experimental.mcp_server.server import ( handle_streamable_http_mcp, diff --git a/tests/test_litellm/proxy/test_prometheus_cleanup.py b/tests/test_litellm/proxy/test_prometheus_cleanup.py index b3d785f113..0a67d5e64e 100644 --- a/tests/test_litellm/proxy/test_prometheus_cleanup.py +++ b/tests/test_litellm/proxy/test_prometheus_cleanup.py @@ -67,6 +67,30 @@ class TestMaybeSetupPrometheusMultiprocDir: assert os.environ["PROMETHEUS_MULTIPROC_DIR"] == custom_dir assert os.path.isdir(custom_dir) + @pytest.mark.parametrize( + "litellm_settings", + [ + {"callbacks": "prometheus"}, + {"success_callback": "prometheus"}, + {"failure_callback": "prometheus"}, + {"callbacks": "custom_callback"}, # string but not prometheus + ], + ) + def test_handles_string_callbacks(self, litellm_settings): + """When callbacks are specified as a string instead of a list, should not crash.""" + with patch.dict(os.environ, {}, clear=False): + os.environ.pop("PROMETHEUS_MULTIPROC_DIR", None) + os.environ.pop("prometheus_multiproc_dir", None) + + # Should not raise TypeError + ProxyInitializationHelpers._maybe_setup_prometheus_multiproc_dir( + num_workers=4, + litellm_settings=litellm_settings, + ) + + # Cleanup + os.environ.pop("PROMETHEUS_MULTIPROC_DIR", None) + @pytest.mark.parametrize( "num_workers, litellm_settings", [ diff --git a/tests/test_litellm/proxy/test_proxy_cli.py b/tests/test_litellm/proxy/test_proxy_cli.py index 642d21a42f..c5d6c45f9a 100644 --- a/tests/test_litellm/proxy/test_proxy_cli.py +++ b/tests/test_litellm/proxy/test_proxy_cli.py @@ -677,7 +677,7 @@ class TestHealthAppFactory: mock_atexit_register, mock_subprocess_run, ): - """Test that proxy exits with code 1 when PrismaManager.setup_database returns False""" + """Test that proxy exits with code 1 when PrismaManager.setup_database returns False and --enforce_prisma_migration_check is set""" from litellm.proxy.proxy_cli import run_server mock_subprocess_run.return_value = MagicMock(returncode=0) @@ -717,7 +717,7 @@ class TestHealthAppFactory: with pytest.raises(SystemExit) as exc_info: run_server.main( - ["--local", "--skip_server_startup"], standalone_mode=False + ["--local", "--skip_server_startup", "--enforce_prisma_migration_check"], standalone_mode=False ) assert exc_info.value.code == 1 mock_setup_database.assert_called_once_with(use_migrate=True) diff --git a/tests/test_litellm/test_cost_calculator.py b/tests/test_litellm/test_cost_calculator.py index 463f6952d2..8f5c3ece0c 100644 --- a/tests/test_litellm/test_cost_calculator.py +++ b/tests/test_litellm/test_cost_calculator.py @@ -388,6 +388,65 @@ def test_custom_pricing_cost_calc_uses_router_model_id_from_litellm_metadata(): assert custom_model_id not in (selected_model_no_custom or "") +def test_per_request_custom_pricing_with_router(): + """When custom pricing is passed as per-request kwargs (not in model_list), + _select_model_name_for_cost_calc should fall back to the model name + (where register_model stored the pricing) instead of the router_model_id + (which has no pricing data). + + Regression test for the bug where response._hidden_params["response_cost"] + returned 0.0 for per-request custom pricing via Router. + """ + from litellm import Router + from litellm.cost_calculator import _select_model_name_for_cost_calc + + router = Router( + model_list=[ + { + "model_name": "openai/gpt-3.5-turbo", + "litellm_params": { + "model": "openai/gpt-3.5-turbo", + "api_key": "test_api_key", + }, + }, + ] + ) + + # Get the deployment's model_id (hash) that the router registered + deployment = router.model_list[0] + router_model_id = deployment["model_info"]["id"] + + # The router registered this hash in model_cost but without custom pricing + assert router_model_id in litellm.model_cost + entry = litellm.model_cost[router_model_id] + # No custom pricing was set in model_list, so these should be None + assert entry.get("input_cost_per_token") is None + + # Now simulate what completion() does: register custom pricing under the model name + litellm.register_model( + { + "openai/gpt-3.5-turbo": { + "input_cost_per_token": 2.0, + "output_cost_per_token": 2.0, + "litellm_provider": "openai", + } + } + ) + + # _select_model_name_for_cost_calc should pick the model name (which has pricing), + # NOT the router_model_id (which has no pricing) + selected = _select_model_name_for_cost_calc( + model="openai/gpt-3.5-turbo", + completion_response=None, + custom_pricing=True, + custom_llm_provider="openai", + router_model_id=router_model_id, + ) + assert selected is not None + assert router_model_id not in selected + assert "gpt-3.5-turbo" in selected + + def test_azure_realtime_cost_calculator(): os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True" litellm.model_cost = litellm.get_model_cost_map(url="") From 55c7ba94e617d3dedf75dbbc7bea283054e467ce Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Mon, 16 Mar 2026 15:34:25 -0700 Subject: [PATCH 205/289] Update litellm/proxy/management_endpoints/key_management_endpoints.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- litellm/proxy/management_endpoints/key_management_endpoints.py | 1 - 1 file changed, 1 deletion(-) diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index 2907f5f089..6572e3406f 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -4763,7 +4763,6 @@ async def _check_key_admin_access( Raises HTTPException(403) if the caller is not authorized. """ - from litellm.proxy.proxy_server import proxy_logging_obj if user_api_key_dict.user_role == LitellmUserRoles.PROXY_ADMIN.value: return From d58b0a9e06be2b5b285a280d1c9f247a8fee472e Mon Sep 17 00:00:00 2001 From: joereyna Date: Mon, 16 Mar 2026 15:36:27 -0700 Subject: [PATCH 206/289] fix: clear oauth2_flow when client_credentials set without token_url --- litellm/proxy/_experimental/mcp_server/rest_endpoints.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py index 5faa0104ac..ef01f027d6 100644 --- a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py +++ b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py @@ -910,6 +910,10 @@ if MCP_AVAILABLE: else None ) ) + # client_credentials requires token_url to fetch a token; without it the + # incoming auth header would be dropped with nothing to replace it. + if _oauth2_flow == "client_credentials" and not request.token_url: + _oauth2_flow = None server_model = MCPServer( server_id=request.server_id or "", From 5befc025d8ebb41b5a7914e732ab862e8e05b0e4 Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Mon, 16 Mar 2026 15:36:28 -0700 Subject: [PATCH 207/289] chore(ui): use antd danger prop instead of tailwind for Remove button --- ui/litellm-dashboard/src/components/DefaultUserSettings.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/litellm-dashboard/src/components/DefaultUserSettings.tsx b/ui/litellm-dashboard/src/components/DefaultUserSettings.tsx index 9c38d628b9..314946c520 100644 --- a/ui/litellm-dashboard/src/components/DefaultUserSettings.tsx +++ b/ui/litellm-dashboard/src/components/DefaultUserSettings.tsx @@ -161,9 +161,9 @@ const DefaultUserSettings: React.FC = ({ Team {index + 1} From 67482db49dd7aecfeec2e797f993718db037f2d8 Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Mon, 16 Mar 2026 15:55:16 -0700 Subject: [PATCH 208/289] feat: fetch blog posts from docs RSS feed instead of static JSON on GitHub --- litellm/__init__.py | 2 +- litellm/litellm_core_utils/get_blog_posts.py | 82 +++++++++++++----- tests/test_litellm/test_get_blog_posts.py | 89 ++++++++++++++------ 3 files changed, 122 insertions(+), 51 deletions(-) diff --git a/litellm/__init__.py b/litellm/__init__.py index 299bb18245..51c6683861 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -358,7 +358,7 @@ model_cost_map_url: str = os.getenv( ) blog_posts_url: str = os.getenv( "LITELLM_BLOG_POSTS_URL", - "https://raw.githubusercontent.com/BerriAI/litellm/main/litellm/blog_posts.json", + "https://docs.litellm.ai/blog/rss.xml", ) anthropic_beta_headers_url: str = os.getenv( "LITELLM_ANTHROPIC_BETA_HEADERS_URL", diff --git a/litellm/litellm_core_utils/get_blog_posts.py b/litellm/litellm_core_utils/get_blog_posts.py index f54deb5929..99e31cb48b 100644 --- a/litellm/litellm_core_utils/get_blog_posts.py +++ b/litellm/litellm_core_utils/get_blog_posts.py @@ -1,8 +1,8 @@ """ -Pulls the latest LiteLLM blog posts from GitHub. +Pulls the latest LiteLLM blog posts from the docs RSS feed. Falls back to the bundled local backup on any failure. -GitHub JSON URL is configured via litellm.blog_posts_url (or LITELLM_BLOG_POSTS_URL env var). +RSS URL is configured via litellm.blog_posts_url (or LITELLM_BLOG_POSTS_URL env var). Disable remote fetching entirely: export LITELLM_LOCAL_BLOG_POSTS=True @@ -11,6 +11,8 @@ Disable remote fetching entirely: import json import os import time +import xml.etree.ElementTree as ET +from email.utils import parsedate_to_datetime from importlib.resources import files from typing import Any, Dict, List, Optional @@ -37,9 +39,8 @@ class GetBlogPosts: """ Fetches, validates, and caches LiteLLM blog posts. - Mirrors the structure of GetModelCostMap: - - Fetches from GitHub with a 5-second timeout - - Validates the response has a non-empty ``posts`` list + - Fetches RSS feed from docs site with a 5-second timeout + - Parses the XML and extracts the latest blog post - Caches the result in-process for BLOG_POSTS_TTL_SECONDS (1 hour) - Falls back to the bundled local backup on any failure """ @@ -56,30 +57,67 @@ class GetBlogPosts: return content.get("posts", []) @staticmethod - def fetch_remote_blog_posts(url: str, timeout: int = 5) -> dict: + def fetch_rss_feed(url: str, timeout: int = 5) -> str: """ - Fetch blog posts JSON from a remote URL. + Fetch RSS XML from a remote URL. - Returns the parsed response. Raises on network/parse errors. + Returns the raw XML text. Raises on network errors. """ response = httpx.get(url, timeout=timeout) response.raise_for_status() - return response.json() + return response.text @staticmethod - def validate_blog_posts(data: Any) -> bool: - """Return True if data is a dict with a non-empty ``posts`` list.""" - if not isinstance(data, dict): - verbose_logger.warning( - "LiteLLM: Blog posts response is not a dict (type=%s). " - "Falling back to local backup.", - type(data).__name__, + def parse_rss_to_posts(xml_text: str, max_posts: int = 1) -> List[Dict[str, str]]: + """ + Parse RSS XML and return a list of blog post dicts. + + Extracts title, description, date (YYYY-MM-DD), and url from each . + """ + root = ET.fromstring(xml_text) + channel = root.find("channel") + if channel is None: + raise ValueError("RSS feed missing element") + + posts: List[Dict[str, str]] = [] + for item in channel.findall("item"): + if len(posts) >= max_posts: + break + + title_el = item.find("title") + link_el = item.find("link") + desc_el = item.find("description") + pub_date_el = item.find("pubDate") + + if title_el is None or link_el is None: + continue + + # Parse RFC 2822 date to YYYY-MM-DD + date_str = "" + if pub_date_el is not None and pub_date_el.text: + try: + dt = parsedate_to_datetime(pub_date_el.text) + date_str = dt.strftime("%Y-%m-%d") + except Exception: + date_str = pub_date_el.text + + posts.append( + { + "title": title_el.text or "", + "description": desc_el.text or "" if desc_el is not None else "", + "date": date_str, + "url": link_el.text or "", + } ) - return False - posts = data.get("posts") + + return posts + + @staticmethod + def validate_blog_posts(posts: List[Dict[str, str]]) -> bool: + """Return True if posts is a non-empty list.""" if not isinstance(posts, list) or len(posts) == 0: verbose_logger.warning( - "LiteLLM: Blog posts response has no valid 'posts' list. " + "LiteLLM: Parsed RSS feed has no valid posts. " "Falling back to local backup.", ) return False @@ -102,7 +140,8 @@ class GetBlogPosts: return cached try: - data = cls.fetch_remote_blog_posts(url) + xml_text = cls.fetch_rss_feed(url) + posts = cls.parse_rss_to_posts(xml_text) except Exception as e: verbose_logger.warning( "LiteLLM: Failed to fetch blog posts from %s: %s. " @@ -112,10 +151,9 @@ class GetBlogPosts: ) return cls.load_local_blog_posts() - if not cls.validate_blog_posts(data): + if not cls.validate_blog_posts(posts): return cls.load_local_blog_posts() - posts = data["posts"] cls._cached_posts = posts cls._last_fetch_time = now return posts diff --git a/tests/test_litellm/test_get_blog_posts.py b/tests/test_litellm/test_get_blog_posts.py index a17d78e0bb..b04fb4ec70 100644 --- a/tests/test_litellm/test_get_blog_posts.py +++ b/tests/test_litellm/test_get_blog_posts.py @@ -1,5 +1,4 @@ """Tests for GetBlogPosts utility class.""" -import json import time from unittest.mock import MagicMock, patch @@ -13,16 +12,26 @@ from litellm.litellm_core_utils.get_blog_posts import ( get_blog_posts, ) -SAMPLE_RESPONSE = { - "posts": [ - { - "title": "Test Post", - "description": "A test post.", - "date": "2026-01-01", - "url": "https://www.litellm.ai/blog/test", - } - ] -} +SAMPLE_RSS = """\ + + + + LiteLLM Blog + + Test Post + https://docs.litellm.ai/blog/test + A test post. + Wed, 01 Jan 2026 10:00:00 GMT + + + Second Post + https://docs.litellm.ai/blog/second + Another post. + Tue, 31 Dec 2025 10:00:00 GMT + + + +""" @pytest.fixture(autouse=True) @@ -45,26 +54,48 @@ def test_load_local_blog_posts_returns_list(): assert "url" in first +def test_parse_rss_to_posts(): + posts = GetBlogPosts.parse_rss_to_posts(SAMPLE_RSS, max_posts=1) + assert len(posts) == 1 + assert posts[0]["title"] == "Test Post" + assert posts[0]["url"] == "https://docs.litellm.ai/blog/test" + assert posts[0]["description"] == "A test post." + assert posts[0]["date"] == "2026-01-01" + + +def test_parse_rss_to_posts_multiple(): + posts = GetBlogPosts.parse_rss_to_posts(SAMPLE_RSS, max_posts=5) + assert len(posts) == 2 + assert posts[1]["title"] == "Second Post" + + +def test_parse_rss_to_posts_invalid_xml(): + with pytest.raises(Exception): + GetBlogPosts.parse_rss_to_posts("not xml") + + +def test_parse_rss_to_posts_missing_channel(): + with pytest.raises(ValueError, match="missing "): + GetBlogPosts.parse_rss_to_posts("") + + def test_validate_blog_posts_valid(): - assert GetBlogPosts.validate_blog_posts(SAMPLE_RESPONSE) is True - - -def test_validate_blog_posts_missing_posts_key(): - assert GetBlogPosts.validate_blog_posts({"other": []}) is False + posts = [{"title": "T", "description": "D", "date": "2026-01-01", "url": "https://x.com"}] + assert GetBlogPosts.validate_blog_posts(posts) is True def test_validate_blog_posts_empty_list(): - assert GetBlogPosts.validate_blog_posts({"posts": []}) is False + assert GetBlogPosts.validate_blog_posts([]) is False -def test_validate_blog_posts_not_dict(): - assert GetBlogPosts.validate_blog_posts("not a dict") is False +def test_validate_blog_posts_not_list(): + assert GetBlogPosts.validate_blog_posts("not a list") is False def test_get_blog_posts_success(): - """Fetches from remote on first call.""" + """Fetches from RSS on first call.""" mock_response = MagicMock() - mock_response.json.return_value = SAMPLE_RESPONSE + mock_response.text = SAMPLE_RSS mock_response.raise_for_status = MagicMock() with patch("litellm.litellm_core_utils.get_blog_posts.httpx.get", return_value=mock_response): @@ -86,10 +117,10 @@ def test_get_blog_posts_network_error_falls_back_to_local(): assert len(posts) > 0 -def test_get_blog_posts_invalid_json_falls_back_to_local(): - """Falls back when remote returns non-dict.""" +def test_get_blog_posts_invalid_xml_falls_back_to_local(): + """Falls back when remote returns invalid XML.""" mock_response = MagicMock() - mock_response.json.return_value = "not a dict" + mock_response.text = "not valid xml" mock_response.raise_for_status = MagicMock() with patch("litellm.litellm_core_utils.get_blog_posts.httpx.get", return_value=mock_response): @@ -101,7 +132,8 @@ def test_get_blog_posts_invalid_json_falls_back_to_local(): def test_get_blog_posts_ttl_cache_not_refetched(): """Within TTL window, does not re-fetch.""" - GetBlogPosts._cached_posts = SAMPLE_RESPONSE["posts"] + cached = [{"title": "Cached", "description": "D", "date": "2026-01-01", "url": "https://x.com"}] + GetBlogPosts._cached_posts = cached GetBlogPosts._last_fetch_time = time.time() # just now call_count = 0 @@ -110,7 +142,7 @@ def test_get_blog_posts_ttl_cache_not_refetched(): nonlocal call_count call_count += 1 m = MagicMock() - m.json.return_value = SAMPLE_RESPONSE + m.text = SAMPLE_RSS m.raise_for_status = MagicMock() return m @@ -123,11 +155,12 @@ def test_get_blog_posts_ttl_cache_not_refetched(): def test_get_blog_posts_ttl_expired_refetches(): """After TTL window, re-fetches from remote.""" - GetBlogPosts._cached_posts = SAMPLE_RESPONSE["posts"] + cached = [{"title": "Cached", "description": "D", "date": "2026-01-01", "url": "https://x.com"}] + GetBlogPosts._cached_posts = cached GetBlogPosts._last_fetch_time = time.time() - 7200 # 2 hours ago mock_response = MagicMock() - mock_response.json.return_value = SAMPLE_RESPONSE + mock_response.text = SAMPLE_RSS mock_response.raise_for_status = MagicMock() with patch( From 12facb27e143d02880592f863bc913ce06b0b35e Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Mon, 16 Mar 2026 16:23:06 -0700 Subject: [PATCH 209/289] fix: remove unused Any import from get_blog_posts --- litellm/litellm_core_utils/get_blog_posts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litellm/litellm_core_utils/get_blog_posts.py b/litellm/litellm_core_utils/get_blog_posts.py index 99e31cb48b..2f9a14f127 100644 --- a/litellm/litellm_core_utils/get_blog_posts.py +++ b/litellm/litellm_core_utils/get_blog_posts.py @@ -14,7 +14,7 @@ import time import xml.etree.ElementTree as ET from email.utils import parsedate_to_datetime from importlib.resources import files -from typing import Any, Dict, List, Optional +from typing import Dict, List, Optional import httpx from pydantic import BaseModel From 57bba3b863f9fcd128b26386348f5050abd862d5 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Mon, 16 Mar 2026 16:28:11 -0700 Subject: [PATCH 210/289] [Fix] UI - Logs: Fix empty filter results showing stale data Remove `.length > 0` check so that when a backend filter returns an empty result set the table correctly shows no data instead of falling back to the previous unfiltered logs. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/components/view_logs/log_filter_logic.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/litellm-dashboard/src/components/view_logs/log_filter_logic.tsx b/ui/litellm-dashboard/src/components/view_logs/log_filter_logic.tsx index 400e86d19e..4e7153b64c 100644 --- a/ui/litellm-dashboard/src/components/view_logs/log_filter_logic.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/log_filter_logic.tsx @@ -228,7 +228,7 @@ export function useLogFilterLogic({ const filteredLogs: PaginatedResponse = useMemo(() => { if (hasBackendFilters) { // Prefer backend result if present; otherwise fall back to latest logs - if (backendFilteredLogs && backendFilteredLogs.data && backendFilteredLogs.data.length > 0) { + if (backendFilteredLogs && backendFilteredLogs.data) { return backendFilteredLogs; } return ( From c951b337e1823010b0a6bbe7848817060f2c91b3 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Mon, 16 Mar 2026 16:32:12 -0700 Subject: [PATCH 211/289] [Fix] Reapply empty filter fix after merge with main Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/components/view_logs/log_filter_logic.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/litellm-dashboard/src/components/view_logs/log_filter_logic.tsx b/ui/litellm-dashboard/src/components/view_logs/log_filter_logic.tsx index 400e86d19e..4e7153b64c 100644 --- a/ui/litellm-dashboard/src/components/view_logs/log_filter_logic.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/log_filter_logic.tsx @@ -228,7 +228,7 @@ export function useLogFilterLogic({ const filteredLogs: PaginatedResponse = useMemo(() => { if (hasBackendFilters) { // Prefer backend result if present; otherwise fall back to latest logs - if (backendFilteredLogs && backendFilteredLogs.data && backendFilteredLogs.data.length > 0) { + if (backendFilteredLogs && backendFilteredLogs.data) { return backendFilteredLogs; } return ( From bc752fb10965de0210ebf695310035ad903608c2 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Mon, 16 Mar 2026 17:27:12 -0700 Subject: [PATCH 212/289] [Fix] Prevent internal users from creating invalid keys via key/generate and key/update Internal users could exploit key/generate and key/update to create unbound keys (no user_id, no budget) or attach keys to non-existent teams. This adds validation for non-admin callers: auto-assign user_id on generate, reject invalid team_ids, and prevent removing user_id on update. Closes LIT-1884 Co-Authored-By: Claude Opus 4.6 --- .../key_management_endpoints.py | 73 ++++- .../test_key_management_endpoints.py | 292 ++++++++++++++++++ 2 files changed, 363 insertions(+), 2 deletions(-) diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index 6572e3406f..726874bc82 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -354,6 +354,10 @@ def key_generation_check( ## check if key is for team or individual is_team_key = _is_team_key(data=data) + _is_admin = ( + user_api_key_dict.user_role is not None + and user_api_key_dict.user_role == LitellmUserRoles.PROXY_ADMIN.value + ) if is_team_key: if team_table is None and litellm.key_generation_settings is not None: raise HTTPException( @@ -361,7 +365,13 @@ def key_generation_check( detail=f"Unable to find team object in database. Team ID: {data.team_id}", ) elif team_table is None: - return True # assume user is assigning team_id without using the team table + if _is_admin: + return True # admins can assign team_id without team table + # Non-admin callers must have a valid team (LIT-1884) + raise HTTPException( + status_code=400, + detail=f"Unable to find team object in database. Team ID: {data.team_id}", + ) return _team_key_generation_check( team_table=team_table, user_api_key_dict=user_api_key_dict, @@ -1214,6 +1224,19 @@ async def generate_key_fn( raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=message ) + # For non-admin internal users: auto-assign caller's user_id if not provided + # This prevents creating unbound keys with no user association (LIT-1884) + _is_proxy_admin = ( + user_api_key_dict.user_role is not None + and user_api_key_dict.user_role == LitellmUserRoles.PROXY_ADMIN.value + ) + if not _is_proxy_admin and data.user_id is None: + data.user_id = user_api_key_dict.user_id + verbose_proxy_logger.warning( + "key/generate: auto-assigning user_id=%s for non-admin caller", + user_api_key_dict.user_id, + ) + team_table: Optional[LiteLLM_TeamTableCachedObj] = None if data.team_id is not None: try: @@ -1228,6 +1251,12 @@ async def generate_key_fn( verbose_proxy_logger.debug( f"Error getting team object in `/key/generate`: {e}" ) + # For non-admin callers, team must exist (LIT-1884) + if not _is_proxy_admin: + raise HTTPException( + status_code=400, + detail=f"Team not found for team_id={data.team_id}. Non-admin users cannot create keys for non-existent teams.", + ) key_generation_check( team_table=team_table, @@ -1810,17 +1839,57 @@ async def _validate_update_key_data( user_api_key_cache: Any, ) -> None: """Validate permissions and constraints for key update.""" + _is_proxy_admin = ( + user_api_key_dict.user_role == LitellmUserRoles.PROXY_ADMIN.value + ) + + # Prevent non-admin from removing user_id (setting to empty string) (LIT-1884) + if ( + data.user_id is not None + and data.user_id == "" + and not _is_proxy_admin + ): + raise HTTPException( + status_code=403, + detail="Non-admin users cannot remove the user_id from a key.", + ) + # sanity check - prevent non-proxy admin user from updating key to belong to a different user if ( data.user_id is not None and data.user_id != existing_key_row.user_id - and user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN.value + and not _is_proxy_admin ): raise HTTPException( status_code=403, detail=f"User={data.user_id} is not allowed to update key={data.key} to belong to user={existing_key_row.user_id}", ) + # Validate team exists when non-admin changes team_id (LIT-1884) + if ( + data.team_id is not None + and not _is_proxy_admin + ): + try: + _team_obj = await get_team_object( + team_id=data.team_id, + prisma_client=prisma_client, + user_api_key_cache=user_api_key_cache, + check_db_only=True, + ) + if _team_obj is None: + raise HTTPException( + status_code=400, + detail=f"Team not found for team_id={data.team_id}. Non-admin users cannot set keys to non-existent teams.", + ) + except HTTPException: + raise + except Exception: + raise HTTPException( + status_code=400, + detail=f"Team not found for team_id={data.team_id}. Non-admin users cannot set keys to non-existent teams.", + ) + common_key_access_checks( user_api_key_dict=user_api_key_dict, data=data, diff --git a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py index 4bb0cd72ed..e1b4a5288f 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py @@ -41,12 +41,15 @@ from litellm.proxy.management_endpoints.key_management_endpoints import ( _transform_verification_tokens_to_deleted_records, _validate_max_budget, _validate_reset_spend_value, + _validate_update_key_data, can_modify_verification_token, check_org_key_model_specific_limits, check_team_key_model_specific_limits, delete_verification_tokens, + generate_key_fn, generate_key_helper_fn, key_aliases, + key_generation_check, list_keys, prepare_key_update_data, reset_key_spend_fn, @@ -7535,3 +7538,292 @@ async def test_update_key_non_budget_fields_allowed_for_internal_user(monkeypatc ) assert result is not None + + +# ============================================================================ +# LIT-1884: Internal users cannot create invalid keys +# ============================================================================ + + +class TestLIT1884KeyGenerateValidation: + """Tests for LIT-1884: internal users should not be able to generate invalid keys.""" + + @pytest.mark.asyncio + async def test_internal_user_generate_key_no_user_id_auto_assigns(self): + """ + When an internal_user calls /key/generate without user_id, + the caller's user_id should be auto-assigned before reaching + _common_key_generation_helper. + """ + mock_prisma_client = AsyncMock() + + data = GenerateKeyRequest(key_alias="test-alias") + assert data.user_id is None + + user_api_key_dict = UserAPIKeyAuth( + user_id="internal-user-123", + user_role=LitellmUserRoles.INTERNAL_USER, + ) + + # Patch _common_key_generation_helper to avoid needing full DB mocks. + # We just want to verify user_id is set before we reach this point. + with patch("litellm.proxy.proxy_server.prisma_client", mock_prisma_client), \ + patch("litellm.proxy.proxy_server.user_api_key_cache", MagicMock()), \ + patch("litellm.proxy.proxy_server.user_custom_key_generate", None), \ + patch( + "litellm.proxy.management_endpoints.key_management_endpoints._common_key_generation_helper", + new_callable=AsyncMock, + return_value=MagicMock(), + ): + await generate_key_fn( + data=data, + user_api_key_dict=user_api_key_dict, + litellm_changed_by=None, + ) + + # The data object should have been mutated to include the caller's user_id + assert data.user_id == "internal-user-123" + + @pytest.mark.asyncio + async def test_internal_user_generate_key_invalid_team_id_rejected(self): + """ + When an internal_user provides a non-existent team_id, + key/generate should raise ProxyException with status 400. + """ + mock_prisma_client = AsyncMock() + + data = GenerateKeyRequest( + key_alias="test-alias", + team_id="nonexistent-team-id", + ) + + user_api_key_dict = UserAPIKeyAuth( + user_id="internal-user-123", + user_role=LitellmUserRoles.INTERNAL_USER, + ) + + with patch("litellm.proxy.proxy_server.prisma_client", mock_prisma_client), \ + patch("litellm.proxy.proxy_server.user_api_key_cache", MagicMock()), \ + patch("litellm.proxy.proxy_server.user_custom_key_generate", None), \ + patch( + "litellm.proxy.management_endpoints.key_management_endpoints.get_team_object", + AsyncMock(side_effect=Exception("Team not found")), + ): + with pytest.raises(ProxyException) as exc_info: + await generate_key_fn( + data=data, + user_api_key_dict=user_api_key_dict, + litellm_changed_by=None, + ) + assert str(exc_info.value.code) == "400" + assert "Team not found" in str(exc_info.value.message) + + @pytest.mark.asyncio + async def test_admin_generate_key_invalid_team_id_allowed(self): + """ + Admin callers should be allowed to create keys with any team_id, + even if the team doesn't exist (team_table=None is OK for admins). + """ + data = GenerateKeyRequest( + key_alias="admin-key", + team_id="nonexistent-team-id", + user_id="admin-user", + ) + + user_api_key_dict = UserAPIKeyAuth( + user_id="admin-user", + user_role=LitellmUserRoles.PROXY_ADMIN, + ) + + mock_prisma_client = AsyncMock() + + with patch("litellm.proxy.proxy_server.prisma_client", mock_prisma_client), \ + patch("litellm.proxy.proxy_server.user_api_key_cache", MagicMock()), \ + patch("litellm.proxy.proxy_server.user_custom_key_generate", None), \ + patch( + "litellm.proxy.management_endpoints.key_management_endpoints.get_team_object", + AsyncMock(side_effect=Exception("Team not found")), + ), \ + patch( + "litellm.proxy.management_endpoints.key_management_endpoints._common_key_generation_helper", + new_callable=AsyncMock, + return_value=MagicMock(), + ): + # Should NOT raise — admin bypasses team validation + result = await generate_key_fn( + data=data, + user_api_key_dict=user_api_key_dict, + litellm_changed_by=None, + ) + assert result is not None + + @pytest.mark.asyncio + async def test_admin_generate_key_no_user_id_not_auto_assigned(self): + """ + Admin callers should NOT have user_id auto-assigned — they may + intentionally create keys without a user_id. + """ + data = GenerateKeyRequest(key_alias="admin-unbound-key") + assert data.user_id is None + + user_api_key_dict = UserAPIKeyAuth( + user_id="admin-user", + user_role=LitellmUserRoles.PROXY_ADMIN, + ) + + mock_prisma_client = AsyncMock() + + with patch("litellm.proxy.proxy_server.prisma_client", mock_prisma_client), \ + patch("litellm.proxy.proxy_server.user_api_key_cache", MagicMock()), \ + patch("litellm.proxy.proxy_server.user_custom_key_generate", None), \ + patch( + "litellm.proxy.management_endpoints.key_management_endpoints._common_key_generation_helper", + new_callable=AsyncMock, + return_value=MagicMock(), + ): + await generate_key_fn( + data=data, + user_api_key_dict=user_api_key_dict, + litellm_changed_by=None, + ) + + # user_id should remain None for admin + assert data.user_id is None + + def test_key_generation_check_non_admin_no_team_table_raises(self): + """ + key_generation_check should raise 400 for non-admin when team_table is None + and key_generation_settings is not set. + """ + data = GenerateKeyRequest(team_id="some-team-id") + user_api_key_dict = UserAPIKeyAuth( + user_id="internal-user", + user_role=LitellmUserRoles.INTERNAL_USER, + ) + + with patch.object(litellm, "key_generation_settings", None): + with pytest.raises(HTTPException) as exc_info: + key_generation_check( + team_table=None, + user_api_key_dict=user_api_key_dict, + data=data, + route="key_generate", + ) + assert exc_info.value.status_code == 400 + assert "Unable to find team object" in str(exc_info.value.detail) + + def test_key_generation_check_admin_no_team_table_allowed(self): + """ + key_generation_check should allow admin to proceed even when team_table is None. + """ + data = GenerateKeyRequest(team_id="some-team-id") + user_api_key_dict = UserAPIKeyAuth( + user_id="admin-user", + user_role=LitellmUserRoles.PROXY_ADMIN, + ) + + with patch.object(litellm, "key_generation_settings", None): + result = key_generation_check( + team_table=None, + user_api_key_dict=user_api_key_dict, + data=data, + route="key_generate", + ) + assert result is True + + +class TestLIT1884KeyUpdateValidation: + """Tests for LIT-1884: internal users should not be able to update keys to remove user_id or set invalid team.""" + + @pytest.mark.asyncio + async def test_internal_user_cannot_remove_user_id(self): + """ + Non-admin users should not be able to set user_id to empty string (remove it). + """ + data = UpdateKeyRequest(key="sk-test-key", user_id="") + existing_key_row = MagicMock() + existing_key_row.user_id = "internal-user-123" + existing_key_row.token = "hashed_token" + existing_key_row.team_id = None + + user_api_key_dict = UserAPIKeyAuth( + user_id="internal-user-123", + user_role=LitellmUserRoles.INTERNAL_USER, + ) + + with pytest.raises(HTTPException) as exc_info: + await _validate_update_key_data( + data=data, + existing_key_row=existing_key_row, + user_api_key_dict=user_api_key_dict, + llm_router=None, + premium_user=False, + prisma_client=AsyncMock(), + user_api_key_cache=MagicMock(), + ) + assert exc_info.value.status_code == 403 + assert "cannot remove the user_id" in str(exc_info.value.detail) + + @pytest.mark.asyncio + async def test_internal_user_cannot_set_invalid_team_id(self): + """ + Non-admin users should not be able to update a key to a non-existent team. + """ + data = UpdateKeyRequest(key="sk-test-key", team_id="nonexistent-team") + existing_key_row = MagicMock() + existing_key_row.user_id = "internal-user-123" + existing_key_row.token = "hashed_token" + existing_key_row.team_id = None + + user_api_key_dict = UserAPIKeyAuth( + user_id="internal-user-123", + user_role=LitellmUserRoles.INTERNAL_USER, + ) + + with patch( + "litellm.proxy.management_endpoints.key_management_endpoints.get_team_object", + AsyncMock(side_effect=Exception("Team not found")), + ): + with pytest.raises(HTTPException) as exc_info: + await _validate_update_key_data( + data=data, + existing_key_row=existing_key_row, + user_api_key_dict=user_api_key_dict, + llm_router=None, + premium_user=False, + prisma_client=AsyncMock(), + user_api_key_cache=MagicMock(), + ) + assert exc_info.value.status_code == 400 + assert "Team not found" in str(exc_info.value.detail) + + @pytest.mark.asyncio + async def test_admin_can_remove_user_id(self): + """ + Admin users should be allowed to set user_id to empty string. + """ + data = UpdateKeyRequest(key="sk-test-key", user_id="") + existing_key_row = MagicMock() + existing_key_row.user_id = "some-user" + existing_key_row.token = "hashed_token" + existing_key_row.team_id = None + existing_key_row.organization_id = None + existing_key_row.project_id = None + + user_api_key_dict = UserAPIKeyAuth( + user_id="admin-user", + user_role=LitellmUserRoles.PROXY_ADMIN, + ) + + mock_prisma_client = AsyncMock() + + # Should NOT raise + await _validate_update_key_data( + data=data, + existing_key_row=existing_key_row, + user_api_key_dict=user_api_key_dict, + llm_router=None, + premium_user=False, + prisma_client=mock_prisma_client, + user_api_key_cache=MagicMock(), + ) From 208740a87c4da78028475b87222f3c9ea1ee05ef Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Mon, 16 Mar 2026 17:40:42 -0700 Subject: [PATCH 213/289] [Fix] Remove duplicate get_team_object call in _validate_update_key_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the non-admin team validation into the existing get_team_object call site to avoid an extra DB round-trip. The existing call already fetches the team for limits checking — we now add the LIT-1884 guard there when team_obj is None for non-admin callers. Co-Authored-By: Claude Opus 4.6 --- .../key_management_endpoints.py | 32 ++++--------------- .../test_key_management_endpoints.py | 12 +++++-- 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index 726874bc82..67dee47ca8 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -1865,31 +1865,6 @@ async def _validate_update_key_data( detail=f"User={data.user_id} is not allowed to update key={data.key} to belong to user={existing_key_row.user_id}", ) - # Validate team exists when non-admin changes team_id (LIT-1884) - if ( - data.team_id is not None - and not _is_proxy_admin - ): - try: - _team_obj = await get_team_object( - team_id=data.team_id, - prisma_client=prisma_client, - user_api_key_cache=user_api_key_cache, - check_db_only=True, - ) - if _team_obj is None: - raise HTTPException( - status_code=400, - detail=f"Team not found for team_id={data.team_id}. Non-admin users cannot set keys to non-existent teams.", - ) - except HTTPException: - raise - except Exception: - raise HTTPException( - status_code=400, - detail=f"Team not found for team_id={data.team_id}. Non-admin users cannot set keys to non-existent teams.", - ) - common_key_access_checks( user_api_key_dict=user_api_key_dict, data=data, @@ -1929,6 +1904,13 @@ async def _validate_update_key_data( check_db_only=True, ) + # Validate team exists when non-admin sets a new team_id (LIT-1884) + if team_obj is None and data.team_id is not None and not _is_proxy_admin: + raise HTTPException( + status_code=400, + detail=f"Team not found for team_id={data.team_id}. Non-admin users cannot set keys to non-existent teams.", + ) + if team_obj is not None: await _check_team_key_limits( team_table=team_obj, diff --git a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py index e1b4a5288f..08e9b5028d 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py @@ -7768,12 +7768,15 @@ class TestLIT1884KeyUpdateValidation: async def test_internal_user_cannot_set_invalid_team_id(self): """ Non-admin users should not be able to update a key to a non-existent team. + get_team_object raises HTTPException(404) when team doesn't exist in DB. """ data = UpdateKeyRequest(key="sk-test-key", team_id="nonexistent-team") existing_key_row = MagicMock() existing_key_row.user_id = "internal-user-123" existing_key_row.token = "hashed_token" existing_key_row.team_id = None + existing_key_row.organization_id = None + existing_key_row.project_id = None user_api_key_dict = UserAPIKeyAuth( user_id="internal-user-123", @@ -7782,7 +7785,10 @@ class TestLIT1884KeyUpdateValidation: with patch( "litellm.proxy.management_endpoints.key_management_endpoints.get_team_object", - AsyncMock(side_effect=Exception("Team not found")), + AsyncMock(side_effect=HTTPException( + status_code=404, + detail="Team doesn't exist in db. Team=nonexistent-team.", + )), ): with pytest.raises(HTTPException) as exc_info: await _validate_update_key_data( @@ -7794,8 +7800,8 @@ class TestLIT1884KeyUpdateValidation: prisma_client=AsyncMock(), user_api_key_cache=MagicMock(), ) - assert exc_info.value.status_code == 400 - assert "Team not found" in str(exc_info.value.detail) + assert exc_info.value.status_code == 404 + assert "Team doesn't exist" in str(exc_info.value.detail) @pytest.mark.asyncio async def test_admin_can_remove_user_id(self): From 4a92db8da16180da10f12ef72625ff9869c8a9bd Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Mon, 16 Mar 2026 18:07:03 -0700 Subject: [PATCH 214/289] [Fix] Skip key_alias re-validation on update/regenerate when alias unchanged When updating or regenerating a key without changing its key_alias, the existing alias was being re-validated against current format rules. This caused keys with legacy aliases (created before stricter validation) to become uneditable. Now validation only runs when the alias actually changes. Co-Authored-By: Claude Opus 4.6 --- .../key_management_endpoints.py | 10 +- .../test_key_management_endpoints.py | 125 ++++++++++++++++++ 2 files changed, 133 insertions(+), 2 deletions(-) diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index 67dee47ca8..87078a5df2 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -2120,7 +2120,10 @@ async def update_key_fn( data=data, existing_key_row=existing_key_row ) - _validate_key_alias_format(key_alias=non_default_values.get("key_alias", None)) + # Only validate key_alias format if it's actually being changed + new_key_alias = non_default_values.get("key_alias", None) + if new_key_alias != existing_key_row.key_alias: + _validate_key_alias_format(key_alias=new_key_alias) await _enforce_unique_key_alias( key_alias=non_default_values.get("key_alias", None), @@ -3579,7 +3582,10 @@ async def _execute_virtual_key_regeneration( non_default_values = await prepare_key_update_data( data=data, existing_key_row=key_in_db ) - _validate_key_alias_format(key_alias=non_default_values.get("key_alias")) + # Only validate key_alias format if it's actually being changed + new_key_alias = non_default_values.get("key_alias") + if new_key_alias != key_in_db.key_alias: + _validate_key_alias_format(key_alias=new_key_alias) verbose_proxy_logger.debug("non_default_values: %s", non_default_values) update_data.update(non_default_values) update_data = prisma_client.jsonify_object(data=update_data) diff --git a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py index 08e9b5028d..ed2607da24 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py @@ -7833,3 +7833,128 @@ class TestLIT1884KeyUpdateValidation: prisma_client=mock_prisma_client, user_api_key_cache=MagicMock(), ) + + +class TestKeyAliasSkipValidationOnUnchanged: + """ + Test that updating/regenerating a key without changing its key_alias + does NOT re-validate the alias. This prevents legacy aliases (created + before stricter validation rules) from blocking edits to other fields. + """ + + @pytest.fixture(autouse=True) + def enable_validation(self): + litellm.enable_key_alias_format_validation = True + yield + litellm.enable_key_alias_format_validation = False + + @pytest.fixture + def mock_prisma(self): + prisma = MagicMock() + prisma.db = MagicMock() + prisma.db.litellm_verificationtoken = MagicMock() + prisma.get_data = AsyncMock(return_value=None) # no duplicate alias + prisma.update_data = AsyncMock(return_value=None) + prisma.jsonify_object = MagicMock(side_effect=lambda data: data) + return prisma + + @pytest.fixture + def existing_key_with_legacy_alias(self): + """A key whose alias contains '@' — valid now, but simulates a legacy alias.""" + return LiteLLM_VerificationToken( + token="hashed_token_123", + key_alias="user@domain.com", + team_id="team-1", + models=[], + max_budget=100.0, + ) + + @pytest.mark.asyncio + async def test_update_key_unchanged_legacy_alias_passes( + self, mock_prisma, existing_key_with_legacy_alias + ): + """ + Updating a key without changing its key_alias should skip format + validation — even if the alias wouldn't pass current rules. + """ + from litellm.proxy.management_endpoints.key_management_endpoints import ( + _validate_key_alias_format, + ) + + # Temporarily make the regex reject '@' to simulate stricter rules + import re + from litellm.proxy.management_endpoints import key_management_endpoints as mod + + original_pattern = mod._KEY_ALIAS_PATTERN + mod._KEY_ALIAS_PATTERN = re.compile( + r"^[a-zA-Z0-9][a-zA-Z0-9_\-/\.]{0,253}[a-zA-Z0-9]$" + ) + try: + # Confirm the alias WOULD fail validation directly + with pytest.raises(ProxyException): + _validate_key_alias_format("user@domain.com") + + # But prepare_key_update_data + the skip logic should allow it + # Simulate what update_key_fn does: alias is in non_default_values + # but matches existing_key_row.key_alias => skip validation + existing_alias = existing_key_with_legacy_alias.key_alias + new_alias = "user@domain.com" # same as existing + assert new_alias == existing_alias # unchanged + + # This is the core logic from update_key_fn: + if new_alias != existing_alias: + _validate_key_alias_format(new_alias) + # No exception raised — test passes + finally: + mod._KEY_ALIAS_PATTERN = original_pattern + + @pytest.mark.asyncio + async def test_update_key_changed_alias_still_validated( + self, mock_prisma, existing_key_with_legacy_alias + ): + """ + When the alias IS being changed, validation should still run. + """ + from litellm.proxy.management_endpoints.key_management_endpoints import ( + _validate_key_alias_format, + ) + + existing_alias = existing_key_with_legacy_alias.key_alias + new_alias = "!invalid!" + + assert new_alias != existing_alias + with pytest.raises(ProxyException): + if new_alias != existing_alias: + _validate_key_alias_format(new_alias) + + @pytest.mark.asyncio + async def test_update_key_changed_to_valid_alias_passes( + self, mock_prisma, existing_key_with_legacy_alias + ): + """ + Changing the alias to a new valid value should pass validation. + """ + from litellm.proxy.management_endpoints.key_management_endpoints import ( + _validate_key_alias_format, + ) + + existing_alias = existing_key_with_legacy_alias.key_alias + new_alias = "new-valid-alias" + + assert new_alias != existing_alias + # Should not raise + if new_alias != existing_alias: + _validate_key_alias_format(new_alias) + + @pytest.mark.asyncio + async def test_update_key_alias_none_skips_validation(self): + """ + When key_alias is not in the update payload (None), validation + should be skipped regardless. + """ + from litellm.proxy.management_endpoints.key_management_endpoints import ( + _validate_key_alias_format, + ) + + # None alias should always pass + _validate_key_alias_format(None) From a771fe55e478bdc06e4b8b47177f7f12cfc7f44b Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Mon, 16 Mar 2026 18:19:02 -0700 Subject: [PATCH 215/289] [Fix] Update log filter test to match empty-result behavior The test expected fallback to all logs when backend filters return empty, but the source was intentionally changed to show empty results instead of stale data. Updated test to match. Co-Authored-By: Claude Opus 4.6 --- .../src/components/view_logs/log_filter_logic.test.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ui/litellm-dashboard/src/components/view_logs/log_filter_logic.test.tsx b/ui/litellm-dashboard/src/components/view_logs/log_filter_logic.test.tsx index 0bb0f2a44d..8ccf0a9e1b 100644 --- a/ui/litellm-dashboard/src/components/view_logs/log_filter_logic.test.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/log_filter_logic.test.tsx @@ -451,7 +451,7 @@ describe("useLogFilterLogic", () => { ); }); - it("should fall back to logs when backend filters are active but API returns empty", async () => { + it("should return empty results when backend filters are active but API returns empty", async () => { vi.mocked(uiSpendLogsCall).mockResolvedValue({ data: [], total: 0, @@ -474,8 +474,7 @@ describe("useLogFilterLogic", () => { { timeout: 500 }, ); - expect(result.current.filteredLogs.data).toHaveLength(1); - expect(result.current.filteredLogs.data[0].request_id).toBe("client-req"); + expect(result.current.filteredLogs.data).toHaveLength(0); }); it("should refetch when sortBy changes and backend filters are active", async () => { From 7b66c970e9706a5b96c1987bc445ff941e51fb66 Mon Sep 17 00:00:00 2001 From: voidborne-d Date: Tue, 17 Mar 2026 03:11:58 +0000 Subject: [PATCH 216/289] fix: auto-recover shared aiohttp session when closed (#23806) When the shared aiohttp session closes (due to network interruption, idle timeout, or Redis failover side effects), the proxy permanently falls back to creating a new HTTPS connection per request, losing the benefit of connection pooling for the entire pod lifetime. Fix: make add_shared_session_to_data() async and recreate the session when it is found closed, restoring connection pooling automatically. Fixes #23806 --- litellm/proxy/route_llm_request.py | 29 ++++-- .../proxy/test_aiohttp_session_recovery.py | 99 +++++++++++++++++++ 2 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 tests/test_litellm/proxy/test_aiohttp_session_recovery.py diff --git a/litellm/proxy/route_llm_request.py b/litellm/proxy/route_llm_request.py index e5fc9fe76a..265a311d39 100644 --- a/litellm/proxy/route_llm_request.py +++ b/litellm/proxy/route_llm_request.py @@ -123,23 +123,40 @@ def get_team_id_from_data(data: dict) -> Optional[str]: return None -def add_shared_session_to_data(data: dict) -> None: +async def add_shared_session_to_data(data: dict) -> None: """ Add shared aiohttp session for connection reuse (prevents cold starts). + If the session was closed (e.g. due to network interruption or idle timeout), + automatically recreates it so connection pooling is restored. Silently continues without session reuse if import fails or session is unavailable. Args: data: Dictionary to add the shared session to """ try: + import litellm.proxy.proxy_server as proxy_server from litellm._logging import verbose_proxy_logger - from litellm.proxy.proxy_server import shared_aiohttp_session - if shared_aiohttp_session is not None and not shared_aiohttp_session.closed: - data["shared_session"] = shared_aiohttp_session + session = proxy_server.shared_aiohttp_session + + if session is not None and not session.closed: + data["shared_session"] = session verbose_proxy_logger.info( - f"SESSION REUSE: Attached shared aiohttp session to request (ID: {id(shared_aiohttp_session)})" + f"SESSION REUSE: Attached shared aiohttp session to request (ID: {id(session)})" ) + elif session is not None and session.closed: + # Session was created at startup but has since closed — recreate it + verbose_proxy_logger.warning( + f"SESSION REUSE: Shared aiohttp session is closed (ID: {id(session)}), recreating..." + ) + new_session = await proxy_server._initialize_shared_aiohttp_session() + if new_session is not None: + proxy_server.shared_aiohttp_session = new_session + data["shared_session"] = new_session + else: + verbose_proxy_logger.info( + "SESSION REUSE: Failed to recreate shared session, continuing without session reuse" + ) else: verbose_proxy_logger.info( "SESSION REUSE: No shared session available for this request" @@ -248,7 +265,7 @@ async def route_request( # noqa: PLR0915 - Complex routing function, refactorin """ Common helper to route the request """ - add_shared_session_to_data(data) + await add_shared_session_to_data(data) team_id = get_team_id_from_data(data) router_model_names = llm_router.model_names if llm_router is not None else [] diff --git a/tests/test_litellm/proxy/test_aiohttp_session_recovery.py b/tests/test_litellm/proxy/test_aiohttp_session_recovery.py new file mode 100644 index 0000000000..e87ca5a163 --- /dev/null +++ b/tests/test_litellm/proxy/test_aiohttp_session_recovery.py @@ -0,0 +1,99 @@ +""" +Tests for shared aiohttp session auto-recovery. + +When the shared session closes (e.g. network interruption, idle timeout), +add_shared_session_to_data should recreate it instead of permanently +falling back to per-request connections. + +Fixes: https://github.com/BerriAI/litellm/issues/23806 +""" + +import asyncio +from unittest.mock import AsyncMock, MagicMock, patch + +import pytest + + +@pytest.mark.asyncio +async def test_add_shared_session_attaches_open_session(): + """When the shared session is open, it should be attached to data.""" + from litellm.proxy.route_llm_request import add_shared_session_to_data + + mock_session = MagicMock() + mock_session.closed = False + + with patch( + "litellm.proxy.proxy_server.shared_aiohttp_session", mock_session + ): + data = {} + await add_shared_session_to_data(data) + assert data["shared_session"] is mock_session + + +@pytest.mark.asyncio +async def test_add_shared_session_recreates_closed_session(): + """When the shared session is closed, it should be recreated.""" + from litellm.proxy import proxy_server as proxy_server_module + from litellm.proxy.route_llm_request import add_shared_session_to_data + + closed_session = MagicMock() + closed_session.closed = True + + new_session = MagicMock() + new_session.closed = False + + with patch.object( + proxy_server_module, + "shared_aiohttp_session", + closed_session, + ): + with patch.object( + proxy_server_module, + "_initialize_shared_aiohttp_session", + new_callable=AsyncMock, + return_value=new_session, + ) as mock_init: + data = {} + await add_shared_session_to_data(data) + + mock_init.assert_called_once() + assert data["shared_session"] is new_session + assert proxy_server_module.shared_aiohttp_session is new_session + + +@pytest.mark.asyncio +async def test_add_shared_session_handles_recreation_failure(): + """When recreation fails, data should not contain shared_session.""" + from litellm.proxy import proxy_server as proxy_server_module + from litellm.proxy.route_llm_request import add_shared_session_to_data + + closed_session = MagicMock() + closed_session.closed = True + + with patch.object( + proxy_server_module, + "shared_aiohttp_session", + closed_session, + ): + with patch.object( + proxy_server_module, + "_initialize_shared_aiohttp_session", + new_callable=AsyncMock, + return_value=None, + ): + data = {} + await add_shared_session_to_data(data) + assert "shared_session" not in data + + +@pytest.mark.asyncio +async def test_add_shared_session_no_session_available(): + """When no session was ever created, data should not contain shared_session.""" + from litellm.proxy.route_llm_request import add_shared_session_to_data + + with patch( + "litellm.proxy.proxy_server.shared_aiohttp_session", None + ): + data = {} + await add_shared_session_to_data(data) + assert "shared_session" not in data From 53d96c8353b2fd18669a54ec0ff2410ff3518ad5 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Mon, 16 Mar 2026 21:35:21 -0700 Subject: [PATCH 217/289] [Feature] Disable custom API key values via UI setting Add disable_custom_api_keys UI setting that prevents users from specifying custom key values during key generation and regeneration. When enabled, all keys must be auto-generated, eliminating the risk of key hash collisions in multi-tenant environments. Co-Authored-By: Claude Opus 4.6 --- .../key_management_endpoints.py | 30 +++- .../proxy_setting_endpoints.py | 1 + .../test_key_management_endpoints.py | 149 +++++++++++++++++- .../organisms/create_key_button.tsx | 2 + 4 files changed, 176 insertions(+), 6 deletions(-) diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index 87078a5df2..e09d7607eb 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -72,6 +72,9 @@ from litellm.proxy.management_helpers.team_member_permission_checks import ( ) from litellm.proxy.management_helpers.utils import management_endpoint_wrapper from litellm.proxy.spend_tracking.spend_tracking_utils import _is_master_key +from litellm.proxy.ui_crud_endpoints.proxy_setting_endpoints import ( + get_ui_settings_cached, +) from litellm.proxy.utils import ( PrismaClient, ProxyLogging, @@ -96,6 +99,24 @@ from litellm.types.utils import ( ) +async def _check_custom_key_allowed(custom_key_value: Optional[str]) -> None: + """Raise 403 if custom API keys are disabled and a custom key was provided.""" + if custom_key_value is None: + return + + ui_settings = await get_ui_settings_cached() + if ui_settings.get("disable_custom_api_keys", False) is True: + verbose_proxy_logger.warning( + "Custom API key rejected: disable_custom_api_keys is enabled" + ) + raise HTTPException( + status_code=403, + detail={ + "error": "Custom API key values are disabled by your administrator. Keys must be auto-generated." + }, + ) + + def _is_team_key(data: Union[GenerateKeyRequest, LiteLLM_VerificationToken]): return data.team_id is not None @@ -671,6 +692,9 @@ async def _common_key_generation_helper( # noqa: PLR0915 prisma_client=prisma_client, ) + # Reject custom key values if disabled by admin + await _check_custom_key_allowed(data.key) + # Validate user-provided key format if data.key is not None and not data.key.startswith("sk-"): _masked = ( @@ -3479,8 +3503,10 @@ async def _rotate_master_key( # noqa: PLR0915 ) -def get_new_token(data: Optional[RegenerateKeyRequest]) -> str: +async def get_new_token(data: Optional[RegenerateKeyRequest]) -> str: if data and data.new_key is not None: + # Reject custom key values if disabled by admin + await _check_custom_key_allowed(data.new_key) new_token = data.new_key if not data.new_key.startswith("sk-"): raise HTTPException( @@ -3572,7 +3598,7 @@ async def _execute_virtual_key_regeneration( """Generate new token, update DB, invalidate cache, and return response.""" from litellm.proxy.proxy_server import hash_token - new_token = get_new_token(data=data) + new_token = await get_new_token(data=data) new_token_hash = hash_token(new_token) new_token_key_name = f"sk-...{new_token[-4:]}" update_data = {"token": new_token_hash, "key_name": new_token_key_name} diff --git a/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py b/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py index 0fa27905ba..d31079f14f 100644 --- a/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py +++ b/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py @@ -149,6 +149,7 @@ ALLOWED_UI_SETTINGS_FIELDS = { "disable_vector_stores_for_internal_users", "allow_vector_stores_for_team_admins", "scope_user_search_to_org", + "disable_custom_api_keys", } # Flags that must be synced from the persisted UISettings into diff --git a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py index ed2607da24..a3bca77ae3 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py @@ -960,22 +960,34 @@ async def test_key_info_returns_object_permission(monkeypatch): ) -def test_get_new_token_with_valid_key(): +@pytest.mark.asyncio +async def test_get_new_token_with_valid_key(monkeypatch): """Test get_new_token function when provided with a valid key that starts with 'sk-'""" + from unittest.mock import AsyncMock + from litellm.proxy._types import RegenerateKeyRequest from litellm.proxy.management_endpoints.key_management_endpoints import ( get_new_token, ) + # Mock get_ui_settings_cached to return setting disabled (custom keys allowed) + monkeypatch.setattr( + "litellm.proxy.management_endpoints.key_management_endpoints.get_ui_settings_cached", + AsyncMock(return_value={}), + ) + # Test with valid new_key data = RegenerateKeyRequest(new_key="sk-test123456789") - result = get_new_token(data) + result = await get_new_token(data) assert result == "sk-test123456789" -def test_get_new_token_with_invalid_key(): +@pytest.mark.asyncio +async def test_get_new_token_with_invalid_key(monkeypatch): """Test get_new_token function when provided with an invalid key that doesn't start with 'sk-'""" + from unittest.mock import AsyncMock + from fastapi import HTTPException from litellm.proxy._types import RegenerateKeyRequest @@ -983,16 +995,145 @@ def test_get_new_token_with_invalid_key(): get_new_token, ) + # Mock get_ui_settings_cached to return setting disabled (custom keys allowed) + monkeypatch.setattr( + "litellm.proxy.management_endpoints.key_management_endpoints.get_ui_settings_cached", + AsyncMock(return_value={}), + ) + # Test with invalid new_key (doesn't start with 'sk-') data = RegenerateKeyRequest(new_key="invalid-key-123") with pytest.raises(HTTPException) as exc_info: - get_new_token(data) + await get_new_token(data) assert exc_info.value.status_code == 400 assert "New key must start with 'sk-'" in str(exc_info.value.detail) +@pytest.mark.asyncio +async def test_check_custom_key_allowed_when_disabled(monkeypatch): + """_check_custom_key_allowed raises 403 when disable_custom_api_keys is true.""" + from unittest.mock import AsyncMock + + from fastapi import HTTPException + + from litellm.proxy.management_endpoints.key_management_endpoints import ( + _check_custom_key_allowed, + ) + + monkeypatch.setattr( + "litellm.proxy.management_endpoints.key_management_endpoints.get_ui_settings_cached", + AsyncMock(return_value={"disable_custom_api_keys": True}), + ) + + with pytest.raises(HTTPException) as exc_info: + await _check_custom_key_allowed("sk-custom-key-123") + + assert exc_info.value.status_code == 403 + assert "disabled" in str(exc_info.value.detail).lower() + + +@pytest.mark.asyncio +async def test_check_custom_key_allowed_when_enabled(monkeypatch): + """_check_custom_key_allowed does nothing when disable_custom_api_keys is false.""" + from unittest.mock import AsyncMock + + from litellm.proxy.management_endpoints.key_management_endpoints import ( + _check_custom_key_allowed, + ) + + monkeypatch.setattr( + "litellm.proxy.management_endpoints.key_management_endpoints.get_ui_settings_cached", + AsyncMock(return_value={"disable_custom_api_keys": False}), + ) + + # Should not raise + await _check_custom_key_allowed("sk-custom-key-123") + + +@pytest.mark.asyncio +async def test_check_custom_key_allowed_when_unset(monkeypatch): + """_check_custom_key_allowed does nothing when setting is not present.""" + from unittest.mock import AsyncMock + + from litellm.proxy.management_endpoints.key_management_endpoints import ( + _check_custom_key_allowed, + ) + + monkeypatch.setattr( + "litellm.proxy.management_endpoints.key_management_endpoints.get_ui_settings_cached", + AsyncMock(return_value={}), + ) + + # Should not raise + await _check_custom_key_allowed("sk-custom-key-123") + + +@pytest.mark.asyncio +async def test_check_custom_key_allowed_none_key_always_passes(monkeypatch): + """_check_custom_key_allowed does nothing when key is None, even if setting is on.""" + from unittest.mock import AsyncMock + + from litellm.proxy.management_endpoints.key_management_endpoints import ( + _check_custom_key_allowed, + ) + + monkeypatch.setattr( + "litellm.proxy.management_endpoints.key_management_endpoints.get_ui_settings_cached", + AsyncMock(return_value={"disable_custom_api_keys": True}), + ) + + # Should not raise — None means auto-generate + await _check_custom_key_allowed(None) + + +@pytest.mark.asyncio +async def test_get_new_token_rejected_when_custom_keys_disabled(monkeypatch): + """get_new_token raises 403 when new_key is set and disable_custom_api_keys is true.""" + from unittest.mock import AsyncMock + + from fastapi import HTTPException + + from litellm.proxy._types import RegenerateKeyRequest + from litellm.proxy.management_endpoints.key_management_endpoints import ( + get_new_token, + ) + + monkeypatch.setattr( + "litellm.proxy.management_endpoints.key_management_endpoints.get_ui_settings_cached", + AsyncMock(return_value={"disable_custom_api_keys": True}), + ) + + data = RegenerateKeyRequest(new_key="sk-custom-regen-key") + + with pytest.raises(HTTPException) as exc_info: + await get_new_token(data) + + assert exc_info.value.status_code == 403 + + +@pytest.mark.asyncio +async def test_get_new_token_auto_generates_when_custom_keys_disabled(monkeypatch): + """get_new_token auto-generates a key when new_key is None, even if setting is on.""" + from unittest.mock import AsyncMock + + from litellm.proxy._types import RegenerateKeyRequest + from litellm.proxy.management_endpoints.key_management_endpoints import ( + get_new_token, + ) + + monkeypatch.setattr( + "litellm.proxy.management_endpoints.key_management_endpoints.get_ui_settings_cached", + AsyncMock(return_value={"disable_custom_api_keys": True}), + ) + + data = RegenerateKeyRequest() # no new_key + result = await get_new_token(data) + + assert result.startswith("sk-") + + @pytest.mark.asyncio async def test_generate_service_account_requires_team_id(): with pytest.raises(HTTPException): diff --git a/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx b/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx index 71e882db3f..d0a7a909d6 100644 --- a/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx +++ b/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx @@ -166,6 +166,7 @@ const CreateKey: React.FC = ({ team, teams, data, addKey, autoOp const { data: projects, isLoading: isProjectsLoading } = useProjects(); const { data: uiSettingsData } = useUISettings(); const enableProjectsUI = Boolean(uiSettingsData?.values?.enable_projects_ui); + const disableCustomApiKeys = Boolean(uiSettingsData?.values?.disable_custom_api_keys); const queryClient = useQueryClient(); const [form] = Form.useForm(); const [isModalVisible, setIsModalVisible] = useState(false); @@ -1581,6 +1582,7 @@ const CreateKey: React.FC = ({ team, teams, data, addKey, autoOp "budget_duration", "tpm_limit", "rpm_limit", + ...(disableCustomApiKeys ? ["key"] : []), ]} /> From 72aa5fc21926865d3aa6b20afad11c51273539ac Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Mon, 16 Mar 2026 22:10:02 -0700 Subject: [PATCH 218/289] [Fix] Add disable_custom_api_keys to UISettings Pydantic model Without this field on the model, GET /get/ui_settings omits the setting from the response and field_schema, preventing the UI from reading it. Co-Authored-By: Claude Opus 4.6 --- litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py b/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py index d31079f14f..9faadd334a 100644 --- a/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py +++ b/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py @@ -129,6 +129,11 @@ class UISettings(BaseModel): description="If enabled, the user search endpoint (/user/filter/ui) restricts results by organization. When off, any authenticated user can search all users.", ) + disable_custom_api_keys: bool = Field( + default=False, + description="If true, users cannot specify custom API key values. All keys must be auto-generated.", + ) + class UISettingsResponse(SettingsResponse): """Response model for UI settings""" From d15c2d546ecf3448b2447b24aea0d7643b6efe3f Mon Sep 17 00:00:00 2001 From: Harshit Jain <48647625+Harshit28j@users.noreply.github.com> Date: Tue, 17 Mar 2026 10:54:29 +0530 Subject: [PATCH 219/289] fix: Register DynamoAI guardrail initializer and enum entry (#23752) * fix: Register DynamoAI guardrail initializer and enum entry Fix the "Unsupported guardrail: dynamoai" error by: 1. Adding DYNAMOAI to SupportedGuardrailIntegrations enum 2. Implementing initialize_guardrail() and registries in dynamoai/__init__.py The DynamoAI guardrail was added in PR #15920 but never properly registered in the initialization system. The __init__.py was missing the guardrail_initializer_registry and guardrail_class_registry dictionaries that the dynamic discovery mechanism looks for at module load time. Fixes #22773 Co-Authored-By: Claude Haiku 4.5 * Update litellm/proxy/guardrails/guardrail_hooks/dynamoai/__init__.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update litellm/proxy/guardrails/guardrail_hooks/dynamoai/__init__.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * test: Add tests for DynamoAI guardrail registration Verifies enum entry, initializer registry, class registry, instance creation, and global registry discovery. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Haiku 4.5 Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- .../guardrail_hooks/dynamoai/__init__.py | 32 +++++++- litellm/types/guardrails.py | 1 + .../guardrail_hooks/test_dynamoai.py | 81 +++++++++++++++++++ 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 tests/test_litellm/proxy/guardrails/guardrail_hooks/test_dynamoai.py diff --git a/litellm/proxy/guardrails/guardrail_hooks/dynamoai/__init__.py b/litellm/proxy/guardrails/guardrail_hooks/dynamoai/__init__.py index 79f1992da4..f9ebf46a27 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/dynamoai/__init__.py +++ b/litellm/proxy/guardrails/guardrail_hooks/dynamoai/__init__.py @@ -1,3 +1,33 @@ +from typing import TYPE_CHECKING + +from litellm.types.guardrails import SupportedGuardrailIntegrations + from .dynamoai import DynamoAIGuardrails -__all__ = ["DynamoAIGuardrails"] +if TYPE_CHECKING: + from litellm.types.guardrails import Guardrail, LitellmParams + + +def initialize_guardrail(litellm_params: "LitellmParams", guardrail: "Guardrail"): + import litellm + + _dynamoai_callback = DynamoAIGuardrails( + api_base=litellm_params.api_base, + api_key=litellm_params.api_key, + guardrail_name=guardrail.get("guardrail_name", ""), + event_hook=litellm_params.mode, + default_on=litellm_params.default_on, + ) + litellm.logging_callback_manager.add_litellm_callback(_dynamoai_callback) + + return _dynamoai_callback + + +guardrail_initializer_registry = { + SupportedGuardrailIntegrations.DYNAMOAI.value: initialize_guardrail, +} + + +guardrail_class_registry = { + SupportedGuardrailIntegrations.DYNAMOAI.value: DynamoAIGuardrails, +} diff --git a/litellm/types/guardrails.py b/litellm/types/guardrails.py index d5abf5c8fb..27fa27e6da 100644 --- a/litellm/types/guardrails.py +++ b/litellm/types/guardrails.py @@ -44,6 +44,7 @@ guardrails: class SupportedGuardrailIntegrations(Enum): APORIA = "aporia" BEDROCK = "bedrock" + DYNAMOAI = "dynamoai" GUARDRAILS_AI = "guardrails_ai" LAKERA = "lakera" LAKERA_V2 = "lakera_v2" diff --git a/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_dynamoai.py b/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_dynamoai.py new file mode 100644 index 0000000000..7bc4e951a5 --- /dev/null +++ b/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_dynamoai.py @@ -0,0 +1,81 @@ +""" +Tests for DynamoAI guardrail registration and initialization. +""" + +import os +from unittest.mock import patch + +import pytest + + +class TestDynamoAIGuardrailRegistration: + """Tests for DynamoAI guardrail registration in the guardrail system.""" + + def test_supported_guardrail_enum_entry(self): + """Test that DYNAMOAI is in SupportedGuardrailIntegrations enum.""" + from litellm.types.guardrails import SupportedGuardrailIntegrations + + assert hasattr(SupportedGuardrailIntegrations, "DYNAMOAI") + assert SupportedGuardrailIntegrations.DYNAMOAI.value == "dynamoai" + + def test_initialize_guardrail_function_exists(self): + """Test that initialize_guardrail function is properly exported.""" + from litellm.proxy.guardrails.guardrail_hooks.dynamoai import ( + guardrail_initializer_registry, + initialize_guardrail, + ) + + assert initialize_guardrail is not None + assert "dynamoai" in guardrail_initializer_registry + + def test_guardrail_class_registry_exists(self): + """Test that guardrail_class_registry is properly exported.""" + from litellm.proxy.guardrails.guardrail_hooks.dynamoai import ( + guardrail_class_registry, + ) + from litellm.proxy.guardrails.guardrail_hooks.dynamoai.dynamoai import ( + DynamoAIGuardrails, + ) + + assert "dynamoai" in guardrail_class_registry + assert guardrail_class_registry["dynamoai"] == DynamoAIGuardrails + + def test_initialize_guardrail_creates_instance(self): + """Test that initialize_guardrail creates a DynamoAIGuardrails instance.""" + from litellm.proxy.guardrails.guardrail_hooks.dynamoai import ( + initialize_guardrail, + ) + from litellm.proxy.guardrails.guardrail_hooks.dynamoai.dynamoai import ( + DynamoAIGuardrails, + ) + from litellm.types.guardrails import LitellmParams + + litellm_params = LitellmParams( + guardrail="dynamoai", + mode="pre_call", + api_key="test-key", + api_base="https://test.dynamo.ai", + ) + + guardrail = { + "guardrail_name": "test-dynamoai-guard", + } + + with patch( + "litellm.logging_callback_manager.add_litellm_callback" + ) as mock_add: + result = initialize_guardrail(litellm_params, guardrail) + + assert isinstance(result, DynamoAIGuardrails) + assert result.api_key == "test-key" + assert result.api_base == "https://test.dynamo.ai" + assert result.guardrail_name == "test-dynamoai-guard" + mock_add.assert_called_once_with(result) + + def test_dynamoai_in_global_registry(self): + """Test that dynamoai is discoverable in the global guardrail registry.""" + from litellm.proxy.guardrails.guardrail_registry import ( + guardrail_initializer_registry, + ) + + assert "dynamoai" in guardrail_initializer_registry From 966124966f83e6e1091ad08d9dfee6e341d3ad85 Mon Sep 17 00:00:00 2001 From: Joe Reyna Date: Mon, 16 Mar 2026 22:25:55 -0700 Subject: [PATCH 220/289] docs: add v1.82.3 release notes and update provider_endpoints_support.json (#23816) --- docs/my-website/release_notes/v1.82.3.md | 374 +++++++++++++++++++++++ provider_endpoints_support.json | 55 ++-- 2 files changed, 406 insertions(+), 23 deletions(-) create mode 100644 docs/my-website/release_notes/v1.82.3.md diff --git a/docs/my-website/release_notes/v1.82.3.md b/docs/my-website/release_notes/v1.82.3.md new file mode 100644 index 0000000000..98351a30a2 --- /dev/null +++ b/docs/my-website/release_notes/v1.82.3.md @@ -0,0 +1,374 @@ +--- +title: "v1.82.3 - Nebius AI, gpt-5.4, Gemini 3.x, FLUX Kontext, and 116 New Models" +slug: "v1-82-3" +date: 2026-03-16T00:00:00 +authors: + - name: Krrish Dholakia + title: CEO, LiteLLM + url: https://www.linkedin.com/in/krish-d/ + image_url: https://pbs.twimg.com/profile_images/1298587542745358340/DZv3Oj-h_400x400.jpg + - name: Ishaan Jaff + title: CTO, LiteLLM + url: https://www.linkedin.com/in/reffajnaahsi/ + image_url: https://pbs.twimg.com/profile_images/1613813310264340481/lz54oEiB_400x400.jpg +hide_table_of_contents: false +--- + +## Deploy this version + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + +``` showLineNumbers title="docker run litellm" +docker run \ +-e STORE_MODEL_IN_DB=True \ +-p 4000:4000 \ +ghcr.io/berriai/litellm:main-1.82.3-stable +``` + + + + +``` showLineNumbers title="pip install litellm" +pip install litellm==1.82.3 +``` + + + + +## Key Highlights + +- **Nebius AI — new provider** — [30 models across DeepSeek, Qwen, Llama, Mistral, NVIDIA, and BAAI available via Nebius AI cloud](../../docs/providers/nebius) - [PR #21542](https://github.com/BerriAI/litellm/pull/21542) +- **OpenAI gpt-5.4 / gpt-5.4-pro — day 0** — Full pricing and routing support for `gpt-5.4` (1M context, $2.50/$15.00) and `gpt-5.4-pro` ($30.00/$180.00) on OpenAI and Azure +- **Gemini 3.x models** — `gemini-3-flash-preview`, `gemini-3.1-pro-preview`, `gemini-3.1-flash-image-preview`, and `gemini-embedding-2-preview` added to cost map for Google AI and Vertex AI +- **FLUX Kontext image editing** — `flux-kontext-pro` and `flux-kontext-max` added to Black Forest Labs, alongside `flux-pro-1.0-fill` and `flux-pro-1.0-expand` for inpainting and outpainting +- **116 new models, 132 deprecated models cleaned up** — Major model map refresh including Mistral Magistral, Dashscope Qwen3 VL, xAI Grok via Azure AI, ZAI GLM-5, Serper Search; removal of OpenAI GPT-3.5/GPT-4 legacy variants, Gemini 1.5, and Vertex AI PaLM2 +- **SageMaker Nova provider** — [New `sagemaker_nova` provider for Amazon Nova models on SageMaker](../../docs/providers/aws_sagemaker) - [PR #21542](https://github.com/BerriAI/litellm/pull/21542) +- **Secret redaction in logs** — API keys, tokens, and credentials automatically scrubbed from all proxy log output. Enabled by default; opt out with `LITELLM_DISABLE_REDACT_SECRETS=true` - [PR #23668](https://github.com/BerriAI/litellm/pull/23668) +- **Streaming stability fix** — Critical fix for `RuntimeError: Cannot send a request, as the client has been closed.` crashes after ~1 hour in production - [PR #22926](https://github.com/BerriAI/litellm/pull/22926) + +--- + +## New Providers and Endpoints + +### New Providers (4 new providers) + +| Provider | Supported LiteLLM Endpoints | Description | +| -------- | --------------------------- | ----------- | +| [Nebius AI](../../docs/providers/nebius) (`nebius/`) | `/chat/completions`, `/embeddings` | EU-based AI cloud with 30+ open models — DeepSeek, Qwen3, Llama 3.1/3.3, NVIDIA Nemotron, BAAI embeddings | +| [ZAI](../../docs/providers/openai_compatible) (`zai/`) | `/chat/completions` | ZhipuAI GLM-5 models via ZAI cloud | +| [Black Forest Labs](../../docs/providers/black_forest_labs) (`black_forest_labs/`) | `/images/generations`, `/images/edits` | FLUX image generation and editing — Kontext Pro/Max, Pro 1.0 Fill/Expand | +| [Serper](../../docs/providers/serper) (`serper/`) | `/search` | Web search via Serper API | +| [SageMaker Nova](../../docs/providers/aws_sagemaker) (`sagemaker_nova/`) | `/chat/completions` | Amazon Nova models via SageMaker endpoint | + +--- + +## New Models / Updated Models + +#### New Model Support (116 new models) + +| Provider | Model | Context Window | Input ($/1M tokens) | Output ($/1M tokens) | Features | +| -------- | ----- | -------------- | ------------------- | -------------------- | -------- | +| OpenAI | `gpt-5.4` | 1.05M | $2.50 | $15.00 | chat, vision, tools, reasoning | +| OpenAI | `gpt-5.4-pro` | 1.05M | $30.00 | $180.00 | responses, vision, tools, reasoning | +| OpenAI | `gpt-5.3-chat-latest` | 128K | $1.75 | $14.00 | chat, vision, tools, reasoning | +| Azure OpenAI | `azure/gpt-5.4` | 1.05M | $2.50 | $15.00 | chat, vision, tools, reasoning | +| Azure OpenAI | `azure/gpt-5.4-pro` | 1.05M | $30.00 | $180.00 | responses, vision, tools, reasoning | +| Azure OpenAI | `azure/gpt-5.3-chat` | 128K | $1.75 | $14.00 | chat, vision, tools, reasoning | +| Google Gemini | `gemini/gemini-3-flash-preview` | 1M | $0.50 | $3.00 | chat, vision, tools, reasoning | +| Google Gemini | `gemini/gemini-3.1-pro-preview` | 1M | $2.00 | $12.00 | chat, vision, tools, reasoning | +| Google Gemini | `gemini/gemini-3.1-flash-image-preview` | 65K | $0.25 | $1.50 | image generation, vision | +| Google Gemini | `gemini/gemini-3.1-flash-lite-preview` | - | - | - | chat | +| Google Gemini | `gemini/gemini-3-pro-image-preview` | - | - | - | image generation | +| Google Gemini | `gemini/gemini-embedding-2-preview` | 8K | $0.20 | - | embeddings | +| Google Vertex AI | `vertex_ai/gemini-3-flash-preview` | - | - | - | chat | +| Google Vertex AI | `vertex_ai/gemini-3.1-pro-preview` | - | - | - | chat | +| Google Vertex AI | `vertex_ai/gemini-3.1-flash-lite-preview` | - | - | - | chat | +| Google Vertex AI | `vertex_ai/gemini-embedding-2-preview` | - | $0.20 | - | embeddings | +| Mistral | `mistral/magistral-medium-1-2-2509` | 40K | $2.00 | $5.00 | chat, tools, reasoning | +| Mistral | `mistral/magistral-small-1-2-2509` | 40K | $0.50 | $1.50 | chat, tools, reasoning | +| Mistral | `mistral/mistral-large-2512` | 262K | $0.50 | $1.50 | chat, vision, tools | +| Mistral | `mistral/mistral-medium-3-1-2508` | - | - | - | chat | +| Mistral | `mistral/mistral-small-3-2-2506` | - | - | - | chat | +| Mistral | `mistral/ministral-3-3b-2512` | - | - | - | chat | +| Mistral | `mistral/ministral-3-8b-2512` | - | - | - | chat | +| Mistral | `mistral/ministral-3-14b-2512` | - | - | - | chat | +| Black Forest Labs | `black_forest_labs/flux-kontext-pro` | - | - | - | image editing | +| Black Forest Labs | `black_forest_labs/flux-kontext-max` | - | - | - | image editing | +| Black Forest Labs | `black_forest_labs/flux-pro-1.0-fill` | - | - | - | image editing (inpaint) | +| Black Forest Labs | `black_forest_labs/flux-pro-1.0-expand` | - | - | - | image editing (outpaint) | +| Black Forest Labs | `black_forest_labs/flux-pro-1.1` | - | - | - | image generation | +| Black Forest Labs | `black_forest_labs/flux-pro-1.1-ultra` | - | - | - | image generation | +| Black Forest Labs | `black_forest_labs/flux-dev` | - | - | - | image generation | +| Black Forest Labs | `black_forest_labs/flux-pro` | - | - | - | image generation | +| Azure AI | `azure_ai/grok-4-1-fast-non-reasoning` | 131K | $0.20 | $0.50 | chat, tools | +| Azure AI | `azure_ai/grok-4-1-fast-reasoning` | 131K | $0.20 | $0.50 | chat, tools, reasoning | +| Azure AI | `azure_ai/mistral-document-ai-2512` | - | - | - | OCR | +| Dashscope | `dashscope/qwen3-next-80b-a3b-instruct` | 262K | $0.15 | $1.20 | chat | +| Dashscope | `dashscope/qwen3-next-80b-a3b-thinking` | 262K | $0.15 | $1.20 | chat, reasoning | +| Dashscope | `dashscope/qwen3-vl-235b-a22b-instruct` | 131K | $0.40 | $1.60 | chat, vision | +| Dashscope | `dashscope/qwen3-vl-235b-a22b-thinking` | 131K | $0.40 | $4.00 | chat, vision, reasoning | +| Dashscope | `dashscope/qwen3-vl-32b-instruct` | 131K | $0.16 | $0.64 | chat, vision | +| Dashscope | `dashscope/qwen3-vl-32b-thinking` | 131K | $0.16 | $2.87 | chat, vision, reasoning | +| Dashscope | `dashscope/qwen3-vl-plus` | 260K | - | - | chat, vision | +| Dashscope | `dashscope/qwen3.5-plus` | 992K | - | - | chat | +| Dashscope | `dashscope/qwen3-max-2026-01-23` | 258K | - | - | chat | +| Nebius AI | `nebius/deepseek-ai/DeepSeek-R1` | 128K | $0.80 | $2.40 | chat, reasoning | +| Nebius AI | `nebius/deepseek-ai/DeepSeek-R1-0528` | 164K | $0.80 | $2.40 | chat, reasoning | +| Nebius AI | `nebius/deepseek-ai/DeepSeek-V3` | 128K | $0.50 | $1.50 | chat | +| Nebius AI | `nebius/deepseek-ai/DeepSeek-V3-0324` | 128K | $0.50 | $1.50 | chat | +| Nebius AI | `nebius/deepseek-ai/DeepSeek-R1-Distill-Llama-70B` | 128K | $0.25 | $0.75 | chat | +| Nebius AI | `nebius/Qwen/Qwen3-235B-A22B` | 262K | $0.20 | $0.60 | chat | +| Nebius AI | `nebius/Qwen/Qwen3-32B` | 32K | $0.10 | $0.30 | chat | +| Nebius AI | `nebius/Qwen/Qwen3-30B-A3B` | 32K | $0.10 | $0.30 | chat | +| Nebius AI | `nebius/Qwen/Qwen3-14B` | 32K | $0.08 | $0.24 | chat | +| Nebius AI | `nebius/Qwen/Qwen3-4B` | 32K | $0.08 | $0.24 | chat | +| Nebius AI | `nebius/Qwen/QwQ-32B` | 32K | $0.15 | $0.45 | chat | +| Nebius AI | `nebius/Qwen/Qwen2.5-72B-Instruct` | 128K | $0.13 | $0.40 | chat | +| Nebius AI | `nebius/Qwen/Qwen2.5-32B-Instruct` | 128K | $0.06 | $0.20 | chat | +| Nebius AI | `nebius/Qwen/Qwen2.5-VL-72B-Instruct` | 131K | $0.13 | $0.40 | chat, vision | +| Nebius AI | `nebius/Qwen/Qwen2-VL-72B-Instruct` | 131K | $0.13 | $0.40 | chat, vision | +| Nebius AI | `nebius/Qwen/Qwen2-VL-7B-Instruct` | 131K | $0.02 | $0.06 | chat, vision | +| Nebius AI | `nebius/meta-llama/Meta-Llama-3.1-405B-Instruct` | 128K | $1.00 | $3.00 | chat | +| Nebius AI | `nebius/meta-llama/Meta-Llama-3.1-70B-Instruct` | 128K | $0.13 | $0.40 | chat | +| Nebius AI | `nebius/meta-llama/Meta-Llama-3.1-8B-Instruct` | 128K | $0.02 | $0.06 | chat | +| Nebius AI | `nebius/meta-llama/Llama-3.3-70B-Instruct` | 128K | $0.13 | $0.40 | chat | +| Nebius AI | `nebius/meta-llama/Llama-Guard-3-8B` | 128K | $0.02 | $0.06 | chat | +| Nebius AI | `nebius/nvidia/Llama-3.1-Nemotron-Ultra-253B-v1` | 128K | $0.60 | $1.80 | chat | +| Nebius AI | `nebius/nvidia/Llama-3.3-Nemotron-Super-49B-v1` | 131K | $0.10 | $0.40 | chat | +| Nebius AI | `nebius/NousResearch/Hermes-3-Llama-3.1-405B` | 128K | $1.00 | $3.00 | chat | +| Nebius AI | `nebius/google/gemma-3-27b-it` | 128K | $0.06 | $0.20 | chat | +| Nebius AI | `nebius/mistralai/Mistral-Nemo-Instruct-2407` | 128K | $0.04 | $0.12 | chat | +| Nebius AI | `nebius/Qwen/Qwen2.5-Coder-7B` | 32K | $0.01 | $0.03 | chat | +| Nebius AI | `nebius/BAAI/bge-en-icl` | 32K | $0.01 | - | embeddings | +| Nebius AI | `nebius/BAAI/bge-multilingual-gemma2` | 8K | $0.01 | - | embeddings | +| Nebius AI | `nebius/intfloat/e5-mistral-7b-instruct` | 32K | $0.01 | - | embeddings | +| AWS Bedrock | `mistral.devstral-2-123b` | 256K | $0.40 | $2.00 | chat, tools | +| AWS Bedrock | `zai.glm-4.7-flash` | 200K | $0.07 | $0.40 | chat, tools, reasoning | +| ZAI | `zai/glm-5` | 200K | $1.00 | $3.20 | chat, tools, reasoning | +| ZAI | `zai/glm-5-code` | 200K | $1.20 | $5.00 | chat, tools, reasoning | +| OpenRouter | `openrouter/anthropic/claude-sonnet-4.6` | - | - | - | chat | +| OpenRouter | `openrouter/google/gemini-3.1-pro-preview` | - | - | - | chat | +| OpenRouter | `openrouter/openai/gpt-5.1-codex-max` | - | - | - | chat | +| OpenRouter | `openrouter/qwen/qwen3-coder-plus` | - | - | - | chat | +| OpenRouter | `openrouter/qwen/qwen3.5-*` (5 models) | - | - | - | chat | +| OpenRouter | `openrouter/z-ai/glm-5` | - | - | - | chat | +| Together AI | `together_ai/Qwen/Qwen3.5-397B-A17B` | - | - | - | chat | +| Perplexity | `perplexity/pplx-embed-v1-0.6b` | 32K | $0.00 | - | embeddings | +| Perplexity | `perplexity/pplx-embed-v1-4b` | 32K | $0.03 | - | embeddings | +| Serper | `serper/search` | - | - | - | search | + +#### Updated Models + +- **[AWS Bedrock](../../docs/providers/bedrock)** + - Add `cache_read_input_token_cost` and `cache_creation_input_token_cost` to Bedrock-hosted Anthropic models (`claude-3-opus`, `claude-3-sonnet`, `claude-3-haiku`, and APAC/EU variants) — prompt caching is now tracked for cost estimation + - Rename `apac.anthropic.claude-sonnet-4-6` → `au.anthropic.claude-sonnet-4-6` to reflect correct regional identifier + +- **[Azure OpenAI](../../docs/providers/azure)** + - Add `supports_none_reasoning_effort` to all `gpt-5.1-chat`, `gpt-5.1-codex`, and `gpt-5.4` variants (global, EU, standard deployments) — allows passing `reasoning_effort: null` to disable reasoning + +- **[Azure OpenAI](../../docs/providers/azure)** — Removed deprecated models + - Remove `azure/gpt-35-turbo-0301` (deprecated 2025-02-13) + - Remove `azure/gpt-35-turbo-0613` (deprecated 2025-02-13) + +#### Features + +- **[OpenAI](../../docs/providers/openai)** + - Day 0 support for `gpt-5.4` and `gpt-5.4-pro` on OpenAI and Azure + +- **[Google Gemini](../../docs/providers/gemini)** + - Add Gemini 3.x model cost map entries — `gemini-3-flash-preview`, `gemini-3.1-pro-preview`, `gemini-3.1-flash-lite-preview`, `gemini-3-pro-image-preview`, `gemini-embedding-2-preview` + - Add Gemini 2.0 Flash and Flash Lite to cost map (re-added with updated pricing) + +- **[Google Vertex AI](../../docs/providers/vertex)** + - Add `gemini-3-flash-preview`, `gemini-3.1-flash-lite-preview`, `gemini-flash-experimental`, and `gemini-embedding-2-preview` to Vertex AI model cost map + +- **[Mistral](../../docs/providers/mistral)** + - Add Magistral reasoning models (`magistral-medium-1-2-2509`, `magistral-small-1-2-2509`) + - Add `mistral-large-2512`, `mistral-medium-3-1-2508`, `mistral-small-3-2-2506`, `ministral-3-*` variants + +- **[Dashscope / Qwen](../../docs/providers/dashscope)** + - Add Qwen3 VL multimodal models (`qwen3-vl-235b`, `qwen3-vl-32b` — instruct and thinking variants) + - Add `qwen3-next-80b-a3b` (instruct + thinking), `qwen3.5-plus`, `qwen3-max-2026-01-23` + +- **[Black Forest Labs](../../docs/providers/black_forest_labs)** + - Add FLUX Kontext image editing models (`flux-kontext-pro`, `flux-kontext-max`) + - Add FLUX Pro 1.0 Fill (inpainting) and Expand (outpainting) + - Add `flux-pro-1.1`, `flux-pro-1.1-ultra`, `flux-dev`, `flux-pro` + +- **[Azure AI](../../docs/providers/azure_ai)** + - Add xAI Grok models via Azure AI Foundry (`grok-4-1-fast-non-reasoning`, `grok-4-1-fast-reasoning`) + - Add Mistral Document AI (`mistral-document-ai-2512`) — OCR mode + +- **[AWS Bedrock](../../docs/providers/bedrock)** + - Add `mistral.devstral-2-123b` (256K context, tools) + - Add `zai.glm-4.7-flash` via Bedrock Converse (200K context, tools, reasoning) + +- **[SageMaker](../../docs/providers/aws_sagemaker)** + - Add `sagemaker_nova` provider for Amazon Nova models on SageMaker - [PR #21542](https://github.com/BerriAI/litellm/pull/21542) + +#### Deprecated / Removed Models + +**OpenAI** — Legacy models removed from cost map: +- `gpt-3.5-turbo-0301`, `gpt-3.5-turbo-0613`, `gpt-3.5-turbo-16k-0613` +- `gpt-4-0314`, `gpt-4-32k`, `gpt-4-32k-0314`, `gpt-4-32k-0613`, `gpt-4-1106-vision-preview`, `gpt-4-vision-preview` +- `gpt-4.5-preview`, `gpt-4.5-preview-2025-02-27` +- `gpt-4o-audio-preview-2024-10-01`, `gpt-4o-realtime-preview-2024-10-01` +- `o1-mini`, `o1-mini-2024-09-12`, `o1-preview`, `o1-preview-2024-09-12` + +**Google Gemini** — Gemini 1.5 and legacy 2.0 variants removed: +- All `gemini-1.5-*` variants (flash, flash-8b, pro, and dated versions) +- `gemini-2.0-flash-exp`, `gemini-2.0-pro-exp-02-05`, `gemini-2.5-flash-preview-04-17`, `gemini-2.5-flash-preview-05-20` + +**Google Vertex AI** — PaLM 2 / legacy models removed: +- All `chat-bison`, `text-bison`, `codechat-bison`, `code-bison`, `code-gecko` variants +- Gemini 1.0 Pro, 1.5 Flash/Pro, 2.0 Flash experimental, and preview variants + +**Perplexity** — Legacy Llama-sonar models removed: +- `llama-3.1-sonar-huge-128k-online`, `llama-3.1-sonar-large/small-128k-chat/online` + +--- + +## LLM API Endpoints + +#### Features + +- **[Responses API](../../docs/response_api)** + - Handle `response.failed`, `response.incomplete`, and `response.cancelled` terminal event types in background streaming — previously only `response.completed` was handled - [PR #23492](https://github.com/BerriAI/litellm/pull/23492) + +#### Bug Fixes + +- **[Anthropic](../../docs/providers/anthropic)** + - Preserve native tool format (web_search, bash, tool_search, etc.) when guardrails convert tools for the Anthropic Messages API - [PR #23526](https://github.com/BerriAI/litellm/pull/23526) + +- **[Moonshot / Kimi](../../docs/providers/openai_compatible)** + - Auto-fill `reasoning_content` for Moonshot Kimi reasoning models - [PR #23580](https://github.com/BerriAI/litellm/pull/23580) + +- **[HuggingFace](../../docs/providers/huggingface)** + - Forward `extra_headers` to HuggingFace embedding API - [PR #23525](https://github.com/BerriAI/litellm/pull/23525) + +- **General** + - Normalize `content_filtered` finish reason across providers - [PR #23564](https://github.com/BerriAI/litellm/pull/23564) + - Fix custom cost tracking on deployments for `/v1/messages` and `/v1/responses` - [PR #23647](https://github.com/BerriAI/litellm/pull/23647) + - Fix per-request custom pricing when `router_model_id` has no pricing data — now falls back to model name + +--- + +## Management Endpoints / UI + +#### Features + +- **Virtual Keys** + - Add Organization dropdown to Create/Edit Key form — `organization_id` is now a first-class field in Key Ownership - [PR #23595](https://github.com/BerriAI/litellm/pull/23595) + - Allow setting `organization_id` on `/key/update` — keys can be assigned or moved to a different organization after creation - [PR #23557](https://github.com/BerriAI/litellm/pull/23557) + +- **Internal Users** + - Add/Remove Team Membership directly from the Internal Users info page — includes searchable dropdown and role selector; no longer requires navigating to each team - [PR #23638](https://github.com/BerriAI/litellm/pull/23638) + +- **Default Team Settings** + - Modernize page to antd (consistent with rest of app) - [PR #23614](https://github.com/BerriAI/litellm/pull/23614) + - Fix: default team params (budget, duration, tpm, rpm, permissions) now correctly applied on `/team/new` - [PR #23614](https://github.com/BerriAI/litellm/pull/23614) + - Fix: settings persist across proxy restarts (`default_team_params` added to `LITELLM_SETTINGS_SAFE_DB_OVERRIDES`) - [PR #23614](https://github.com/BerriAI/litellm/pull/23614) + - Fix: resolved race condition in `_update_litellm_setting` where `get_config()` could overwrite freshly saved values - [PR #23614](https://github.com/BerriAI/litellm/pull/23614) + +- **Usage** + - Auto-paginate daily spend data — all entity views (teams, orgs, customers, tags, agents, users) fetch pages progressively with charts updating after each page - [PR #23622](https://github.com/BerriAI/litellm/pull/23622) + +- **Models / Cost** + - Azure Model Router cost breakdown in UI — show per-sub-model `additional_costs` from `hidden_params` in `CostBreakdownViewer` - [PR #23550](https://github.com/BerriAI/litellm/pull/23550) + +- **User Management** + - New `/user/info/v2` endpoint — scoped, paginated replacement for the existing god endpoint that caused memory and stability issues on large installs - [PR #23437](https://github.com/BerriAI/litellm/pull/23437) + +#### Bugs + +- Fix Tag list endpoint returning 500 due to invalid Prisma `group_by` kwargs - [PR #23606](https://github.com/BerriAI/litellm/pull/23606) +- Fix Team Admin getting 403 on `/user/filter/ui` when `scope_user_search_to_org` is enabled - [PR #23671](https://github.com/BerriAI/litellm/pull/23671) +- Fix Public Model Hub not showing config-defined models after save - [PR #23501](https://github.com/BerriAI/litellm/pull/23501) +- Fix fallback popup model dropdown z-index issue - [PR #23516](https://github.com/BerriAI/litellm/pull/23516) +- Fix double-counting bug in org/team key limit checks on `/key/update` + +--- + +## AI Integrations + +### Logging + +- **[Vantage](https://vantage.sh)** + - Add Vantage integration for FOCUS 1.2 CSV export — export LiteLLM proxy spend data as FinOps Open Cost & Usage Specification reports, with time-windowed filenames to prevent overwrites - [PR #23333](https://github.com/BerriAI/litellm/pull/23333) + +- **General** + - Fix silent metrics race condition causing metric collision across experiments - [PR #23542](https://github.com/BerriAI/litellm/pull/23542) + +### Guardrails + +No major guardrail changes in this release. + +### Prompt Management + +No major prompt management changes in this release. + +### Secret Managers + +No major secret manager changes in this release. + +--- + +## Performance / Loadbalancing / Reliability improvements + +- **Fix streaming crashes after ~1 hour** — `LLMClientCache._remove_key()` no longer calls `close()`/`aclose()` on evicted HTTP/SDK clients. In-flight requests were crashing with `RuntimeError: Cannot send a request, as the client has been closed.` after the 1-hour TTL expired. Cleanup now happens only at shutdown via `close_litellm_async_clients()` - [PR #22926](https://github.com/BerriAI/litellm/pull/22926) +- **Fix OOM / Prisma connection loss** on large installs — unbounded managed-object poll was exhausting Prisma connections after ~60–70 minutes on instances with 336K+ queued response rows - [PR #23472](https://github.com/BerriAI/litellm/pull/23472) +- **Centralize logging kwarg updates** — root cause fix migrating all logging updates to a single function, eliminating kwarg inconsistencies across logging paths - [PR #23659](https://github.com/BerriAI/litellm/pull/23659) +- **Fix tiktoken cache for non-root offline containers** — tiktoken cache now works correctly in offline environments running as non-root users - [PR #23498](https://github.com/BerriAI/litellm/pull/23498) +- **Add CodSpeed continuous performance benchmarks** — automated performance regression tracking on CI - [PR #23676](https://github.com/BerriAI/litellm/pull/23676) + +--- + +## Security + +- **Secret redaction in proxy logs** — Adds a `SecretRedactionFilter` to all LiteLLM loggers that scrubs API keys, tokens, and credentials from log messages, format args, exception tracebacks, and extra fields. Enabled by default; opt out with `LITELLM_DISABLE_REDACT_SECRETS=true` - [PR #23668](https://github.com/BerriAI/litellm/pull/23668), [PR #23667](https://github.com/BerriAI/litellm/pull/23667) +- **Bump PyJWT to `^2.12.0`** — addresses security vulnerability in `^2.10.1` - [PR #23678](https://github.com/BerriAI/litellm/pull/23678) +- **Bump `tar` to 7.5.11 and `tornado` to 6.5.5** — addresses CVEs in transitive dependencies - [PR #23602](https://github.com/BerriAI/litellm/pull/23602) + +--- + +## Database / Proxy Operations + +- **Fix Prisma migrate deploy on pre-existing instances** — resolved multiple bugs in migration recovery logic: missing return in the P3018 idempotent error handler and unhandled exceptions in `_roll_back_migration` that caused silent failures even after successful recovery - [PR #23655](https://github.com/BerriAI/litellm/pull/23655) +- **Make DB migration failure exit opt-in** — proxy no longer exits on `prisma migrate deploy` failure by default; enable with `--enforce_prisma_migration_check` - [PR #23675](https://github.com/BerriAI/litellm/pull/23675) + +--- + +## New Contributors + +* @ryanh-ai made their first contribution in [PR #21542](https://github.com/BerriAI/litellm/pull/21542) +* @ryan-crabbe made their first contribution in [PR #23668](https://github.com/BerriAI/litellm/pull/23668) +* @Jah-yee made their first contribution in [PR #23525](https://github.com/BerriAI/litellm/pull/23525) +* @gambletan made their first contribution in [PR #23516](https://github.com/BerriAI/litellm/pull/23516) +* @awais786 made their first contribution in [PR #23183](https://github.com/BerriAI/litellm/pull/23183) +* @pradyyadav made their first contribution in [PR #23580](https://github.com/BerriAI/litellm/pull/23580) +* @xianzongxie-stripe made their first contribution in [PR #23492](https://github.com/BerriAI/litellm/pull/23492) +* @Harshit28j made their first contribution in [PR #23333](https://github.com/BerriAI/litellm/pull/23333) +* @codspeed-hq[bot] made their first contribution in [PR #23676](https://github.com/BerriAI/litellm/pull/23676) + +--- + +## Diff Summary + +## 03/16/2026 +* New Providers: 5 +* New Models / Updated Models: 116 new, 132 removed +* LLM API Endpoints: 5 +* Management Endpoints / UI: 11 +* AI Integrations: 2 +* Performance / Reliability: 5 +* Security: 3 +* Database / Proxy Operations: 2 + +--- + +## Full Changelog +[v1.82.0-stable...v1.82.3-stable](https://github.com/BerriAI/litellm/compare/v1.82.0-stable...v1.82.3-stable) diff --git a/provider_endpoints_support.json b/provider_endpoints_support.json index 2f3302bb57..473edb5a6b 100644 --- a/provider_endpoints_support.json +++ b/provider_endpoints_support.json @@ -471,9 +471,7 @@ "audio_speech": false, "moderations": false, "batches": false, - "rerank": false, - "a2a": false, - "interactions": false + "rerank": false } }, "chutes": { @@ -1486,12 +1484,12 @@ } }, "nebius": { - "display_name": "Nebius AI Studio (`nebius`)", + "display_name": "Nebius AI (`nebius`)", "url": "https://docs.litellm.ai/docs/providers/nebius", "endpoints": { "chat_completions": true, - "messages": true, - "responses": true, + "messages": false, + "responses": false, "embeddings": true, "image_generations": false, "audio_transcriptions": false, @@ -1499,8 +1497,7 @@ "moderations": false, "batches": false, "rerank": false, - "a2a": true, - "interactions": true + "a2a": false } }, "nlp_cloud": { @@ -2081,9 +2078,20 @@ }, "serper": { "display_name": "Serper (`serper`)", - "url": "https://docs.litellm.ai/docs/search/serper", + "url": "https://docs.litellm.ai/docs/providers/serper", "endpoints": { - "search": true + "chat_completions": false, + "messages": false, + "responses": false, + "embeddings": false, + "image_generations": false, + "audio_transcriptions": false, + "audio_speech": false, + "moderations": false, + "batches": false, + "rerank": false, + "search": true, + "a2a": false } }, "triton": { @@ -2265,12 +2273,12 @@ } }, "zai": { - "display_name": "Z.AI (Zhipu AI) (`zai`)", - "url": "https://docs.litellm.ai/docs/providers/zai", + "display_name": "ZAI (`zai`)", + "url": "https://docs.litellm.ai/docs/providers/openai_compatible", "endpoints": { "chat_completions": true, - "messages": true, - "responses": true, + "messages": false, + "responses": false, "embeddings": false, "image_generations": false, "audio_transcriptions": false, @@ -2278,8 +2286,7 @@ "moderations": false, "batches": false, "rerank": false, - "a2a": true, - "interactions": true + "a2a": false } }, "ragflow": { @@ -2551,23 +2558,25 @@ "audio_speech": false, "moderations": false, "batches": false, - "rerank": false + "rerank": false, + "a2a": false } }, - "charity_engine": { - "display_name": "Charity Engine (`charity_engine`)", - "url": "https://docs.litellm.ai/docs/providers/charity_engine", + "sagemaker_nova": { + "display_name": "AWS SageMaker Nova (`sagemaker_nova`)", + "url": "https://docs.litellm.ai/docs/providers/aws_sagemaker", "endpoints": { "chat_completions": true, - "messages": true, - "responses": true, + "messages": false, + "responses": false, "embeddings": false, "image_generations": false, "audio_transcriptions": false, "audio_speech": false, "moderations": false, "batches": false, - "rerank": false + "rerank": false, + "a2a": false } } }, From c687e631b4581afcf9df057f9ad8e5d9c6ec7aa1 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Mon, 16 Mar 2026 22:26:11 -0700 Subject: [PATCH 221/289] [Feature] Add disable_custom_api_keys toggle to UI Settings page Adds a toggle switch to the admin UI Settings page so administrators can enable/disable custom API key values without making direct API calls. Co-Authored-By: Claude Opus 4.6 --- .../AdminSettings/UISettings/UISettings.tsx | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx index a22c78c943..0d12a4c4bf 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx @@ -24,6 +24,7 @@ export default function UISettings() { const disableVectorStoresProperty = schema?.properties?.disable_vector_stores_for_internal_users; const allowVectorStoresTeamAdminsProperty = schema?.properties?.allow_vector_stores_for_team_admins; const scopeUserSearchProperty = schema?.properties?.scope_user_search_to_org; + const disableCustomApiKeysProperty = schema?.properties?.disable_custom_api_keys; const values = data?.values ?? {}; const isDisabledForInternalUsers = Boolean(values.disable_model_add_for_internal_users); const isDisabledTeamAdminDeleteTeamUser = Boolean(values.disable_team_admin_delete_team_user); @@ -182,6 +183,20 @@ export default function UISettings() { ); }; + const handleToggleDisableCustomApiKeys = (checked: boolean) => { + updateSettings( + { disable_custom_api_keys: checked }, + { + onSuccess: () => { + NotificationManager.success("UI settings updated successfully"); + }, + onError: (error) => { + NotificationManager.fromBackend(error); + }, + }, + ); + }; + return ( {isLoading ? ( @@ -382,6 +397,26 @@ export default function UISettings() { + {/* Disable custom API key values */} + + + + Disable custom API key values + + {disableCustomApiKeysProperty?.description ?? + "If true, users cannot specify custom API key values. All keys must be auto-generated."} + + + + + + {/* Page Visibility for Internal Users */} Date: Mon, 16 Mar 2026 22:26:45 -0700 Subject: [PATCH 222/289] =?UTF-8?q?Revert=20"docs:=20add=20v1.82.3=20relea?= =?UTF-8?q?se=20notes=20and=20update=20provider=5Fendpoints=5Fsupport?= =?UTF-8?q?=E2=80=A6"=20(#23817)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 966124966f83e6e1091ad08d9dfee6e341d3ad85. --- docs/my-website/release_notes/v1.82.3.md | 374 ----------------------- provider_endpoints_support.json | 55 ++-- 2 files changed, 23 insertions(+), 406 deletions(-) delete mode 100644 docs/my-website/release_notes/v1.82.3.md diff --git a/docs/my-website/release_notes/v1.82.3.md b/docs/my-website/release_notes/v1.82.3.md deleted file mode 100644 index 98351a30a2..0000000000 --- a/docs/my-website/release_notes/v1.82.3.md +++ /dev/null @@ -1,374 +0,0 @@ ---- -title: "v1.82.3 - Nebius AI, gpt-5.4, Gemini 3.x, FLUX Kontext, and 116 New Models" -slug: "v1-82-3" -date: 2026-03-16T00:00:00 -authors: - - name: Krrish Dholakia - title: CEO, LiteLLM - url: https://www.linkedin.com/in/krish-d/ - image_url: https://pbs.twimg.com/profile_images/1298587542745358340/DZv3Oj-h_400x400.jpg - - name: Ishaan Jaff - title: CTO, LiteLLM - url: https://www.linkedin.com/in/reffajnaahsi/ - image_url: https://pbs.twimg.com/profile_images/1613813310264340481/lz54oEiB_400x400.jpg -hide_table_of_contents: false ---- - -## Deploy this version - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - - - - -``` showLineNumbers title="docker run litellm" -docker run \ --e STORE_MODEL_IN_DB=True \ --p 4000:4000 \ -ghcr.io/berriai/litellm:main-1.82.3-stable -``` - - - - -``` showLineNumbers title="pip install litellm" -pip install litellm==1.82.3 -``` - - - - -## Key Highlights - -- **Nebius AI — new provider** — [30 models across DeepSeek, Qwen, Llama, Mistral, NVIDIA, and BAAI available via Nebius AI cloud](../../docs/providers/nebius) - [PR #21542](https://github.com/BerriAI/litellm/pull/21542) -- **OpenAI gpt-5.4 / gpt-5.4-pro — day 0** — Full pricing and routing support for `gpt-5.4` (1M context, $2.50/$15.00) and `gpt-5.4-pro` ($30.00/$180.00) on OpenAI and Azure -- **Gemini 3.x models** — `gemini-3-flash-preview`, `gemini-3.1-pro-preview`, `gemini-3.1-flash-image-preview`, and `gemini-embedding-2-preview` added to cost map for Google AI and Vertex AI -- **FLUX Kontext image editing** — `flux-kontext-pro` and `flux-kontext-max` added to Black Forest Labs, alongside `flux-pro-1.0-fill` and `flux-pro-1.0-expand` for inpainting and outpainting -- **116 new models, 132 deprecated models cleaned up** — Major model map refresh including Mistral Magistral, Dashscope Qwen3 VL, xAI Grok via Azure AI, ZAI GLM-5, Serper Search; removal of OpenAI GPT-3.5/GPT-4 legacy variants, Gemini 1.5, and Vertex AI PaLM2 -- **SageMaker Nova provider** — [New `sagemaker_nova` provider for Amazon Nova models on SageMaker](../../docs/providers/aws_sagemaker) - [PR #21542](https://github.com/BerriAI/litellm/pull/21542) -- **Secret redaction in logs** — API keys, tokens, and credentials automatically scrubbed from all proxy log output. Enabled by default; opt out with `LITELLM_DISABLE_REDACT_SECRETS=true` - [PR #23668](https://github.com/BerriAI/litellm/pull/23668) -- **Streaming stability fix** — Critical fix for `RuntimeError: Cannot send a request, as the client has been closed.` crashes after ~1 hour in production - [PR #22926](https://github.com/BerriAI/litellm/pull/22926) - ---- - -## New Providers and Endpoints - -### New Providers (4 new providers) - -| Provider | Supported LiteLLM Endpoints | Description | -| -------- | --------------------------- | ----------- | -| [Nebius AI](../../docs/providers/nebius) (`nebius/`) | `/chat/completions`, `/embeddings` | EU-based AI cloud with 30+ open models — DeepSeek, Qwen3, Llama 3.1/3.3, NVIDIA Nemotron, BAAI embeddings | -| [ZAI](../../docs/providers/openai_compatible) (`zai/`) | `/chat/completions` | ZhipuAI GLM-5 models via ZAI cloud | -| [Black Forest Labs](../../docs/providers/black_forest_labs) (`black_forest_labs/`) | `/images/generations`, `/images/edits` | FLUX image generation and editing — Kontext Pro/Max, Pro 1.0 Fill/Expand | -| [Serper](../../docs/providers/serper) (`serper/`) | `/search` | Web search via Serper API | -| [SageMaker Nova](../../docs/providers/aws_sagemaker) (`sagemaker_nova/`) | `/chat/completions` | Amazon Nova models via SageMaker endpoint | - ---- - -## New Models / Updated Models - -#### New Model Support (116 new models) - -| Provider | Model | Context Window | Input ($/1M tokens) | Output ($/1M tokens) | Features | -| -------- | ----- | -------------- | ------------------- | -------------------- | -------- | -| OpenAI | `gpt-5.4` | 1.05M | $2.50 | $15.00 | chat, vision, tools, reasoning | -| OpenAI | `gpt-5.4-pro` | 1.05M | $30.00 | $180.00 | responses, vision, tools, reasoning | -| OpenAI | `gpt-5.3-chat-latest` | 128K | $1.75 | $14.00 | chat, vision, tools, reasoning | -| Azure OpenAI | `azure/gpt-5.4` | 1.05M | $2.50 | $15.00 | chat, vision, tools, reasoning | -| Azure OpenAI | `azure/gpt-5.4-pro` | 1.05M | $30.00 | $180.00 | responses, vision, tools, reasoning | -| Azure OpenAI | `azure/gpt-5.3-chat` | 128K | $1.75 | $14.00 | chat, vision, tools, reasoning | -| Google Gemini | `gemini/gemini-3-flash-preview` | 1M | $0.50 | $3.00 | chat, vision, tools, reasoning | -| Google Gemini | `gemini/gemini-3.1-pro-preview` | 1M | $2.00 | $12.00 | chat, vision, tools, reasoning | -| Google Gemini | `gemini/gemini-3.1-flash-image-preview` | 65K | $0.25 | $1.50 | image generation, vision | -| Google Gemini | `gemini/gemini-3.1-flash-lite-preview` | - | - | - | chat | -| Google Gemini | `gemini/gemini-3-pro-image-preview` | - | - | - | image generation | -| Google Gemini | `gemini/gemini-embedding-2-preview` | 8K | $0.20 | - | embeddings | -| Google Vertex AI | `vertex_ai/gemini-3-flash-preview` | - | - | - | chat | -| Google Vertex AI | `vertex_ai/gemini-3.1-pro-preview` | - | - | - | chat | -| Google Vertex AI | `vertex_ai/gemini-3.1-flash-lite-preview` | - | - | - | chat | -| Google Vertex AI | `vertex_ai/gemini-embedding-2-preview` | - | $0.20 | - | embeddings | -| Mistral | `mistral/magistral-medium-1-2-2509` | 40K | $2.00 | $5.00 | chat, tools, reasoning | -| Mistral | `mistral/magistral-small-1-2-2509` | 40K | $0.50 | $1.50 | chat, tools, reasoning | -| Mistral | `mistral/mistral-large-2512` | 262K | $0.50 | $1.50 | chat, vision, tools | -| Mistral | `mistral/mistral-medium-3-1-2508` | - | - | - | chat | -| Mistral | `mistral/mistral-small-3-2-2506` | - | - | - | chat | -| Mistral | `mistral/ministral-3-3b-2512` | - | - | - | chat | -| Mistral | `mistral/ministral-3-8b-2512` | - | - | - | chat | -| Mistral | `mistral/ministral-3-14b-2512` | - | - | - | chat | -| Black Forest Labs | `black_forest_labs/flux-kontext-pro` | - | - | - | image editing | -| Black Forest Labs | `black_forest_labs/flux-kontext-max` | - | - | - | image editing | -| Black Forest Labs | `black_forest_labs/flux-pro-1.0-fill` | - | - | - | image editing (inpaint) | -| Black Forest Labs | `black_forest_labs/flux-pro-1.0-expand` | - | - | - | image editing (outpaint) | -| Black Forest Labs | `black_forest_labs/flux-pro-1.1` | - | - | - | image generation | -| Black Forest Labs | `black_forest_labs/flux-pro-1.1-ultra` | - | - | - | image generation | -| Black Forest Labs | `black_forest_labs/flux-dev` | - | - | - | image generation | -| Black Forest Labs | `black_forest_labs/flux-pro` | - | - | - | image generation | -| Azure AI | `azure_ai/grok-4-1-fast-non-reasoning` | 131K | $0.20 | $0.50 | chat, tools | -| Azure AI | `azure_ai/grok-4-1-fast-reasoning` | 131K | $0.20 | $0.50 | chat, tools, reasoning | -| Azure AI | `azure_ai/mistral-document-ai-2512` | - | - | - | OCR | -| Dashscope | `dashscope/qwen3-next-80b-a3b-instruct` | 262K | $0.15 | $1.20 | chat | -| Dashscope | `dashscope/qwen3-next-80b-a3b-thinking` | 262K | $0.15 | $1.20 | chat, reasoning | -| Dashscope | `dashscope/qwen3-vl-235b-a22b-instruct` | 131K | $0.40 | $1.60 | chat, vision | -| Dashscope | `dashscope/qwen3-vl-235b-a22b-thinking` | 131K | $0.40 | $4.00 | chat, vision, reasoning | -| Dashscope | `dashscope/qwen3-vl-32b-instruct` | 131K | $0.16 | $0.64 | chat, vision | -| Dashscope | `dashscope/qwen3-vl-32b-thinking` | 131K | $0.16 | $2.87 | chat, vision, reasoning | -| Dashscope | `dashscope/qwen3-vl-plus` | 260K | - | - | chat, vision | -| Dashscope | `dashscope/qwen3.5-plus` | 992K | - | - | chat | -| Dashscope | `dashscope/qwen3-max-2026-01-23` | 258K | - | - | chat | -| Nebius AI | `nebius/deepseek-ai/DeepSeek-R1` | 128K | $0.80 | $2.40 | chat, reasoning | -| Nebius AI | `nebius/deepseek-ai/DeepSeek-R1-0528` | 164K | $0.80 | $2.40 | chat, reasoning | -| Nebius AI | `nebius/deepseek-ai/DeepSeek-V3` | 128K | $0.50 | $1.50 | chat | -| Nebius AI | `nebius/deepseek-ai/DeepSeek-V3-0324` | 128K | $0.50 | $1.50 | chat | -| Nebius AI | `nebius/deepseek-ai/DeepSeek-R1-Distill-Llama-70B` | 128K | $0.25 | $0.75 | chat | -| Nebius AI | `nebius/Qwen/Qwen3-235B-A22B` | 262K | $0.20 | $0.60 | chat | -| Nebius AI | `nebius/Qwen/Qwen3-32B` | 32K | $0.10 | $0.30 | chat | -| Nebius AI | `nebius/Qwen/Qwen3-30B-A3B` | 32K | $0.10 | $0.30 | chat | -| Nebius AI | `nebius/Qwen/Qwen3-14B` | 32K | $0.08 | $0.24 | chat | -| Nebius AI | `nebius/Qwen/Qwen3-4B` | 32K | $0.08 | $0.24 | chat | -| Nebius AI | `nebius/Qwen/QwQ-32B` | 32K | $0.15 | $0.45 | chat | -| Nebius AI | `nebius/Qwen/Qwen2.5-72B-Instruct` | 128K | $0.13 | $0.40 | chat | -| Nebius AI | `nebius/Qwen/Qwen2.5-32B-Instruct` | 128K | $0.06 | $0.20 | chat | -| Nebius AI | `nebius/Qwen/Qwen2.5-VL-72B-Instruct` | 131K | $0.13 | $0.40 | chat, vision | -| Nebius AI | `nebius/Qwen/Qwen2-VL-72B-Instruct` | 131K | $0.13 | $0.40 | chat, vision | -| Nebius AI | `nebius/Qwen/Qwen2-VL-7B-Instruct` | 131K | $0.02 | $0.06 | chat, vision | -| Nebius AI | `nebius/meta-llama/Meta-Llama-3.1-405B-Instruct` | 128K | $1.00 | $3.00 | chat | -| Nebius AI | `nebius/meta-llama/Meta-Llama-3.1-70B-Instruct` | 128K | $0.13 | $0.40 | chat | -| Nebius AI | `nebius/meta-llama/Meta-Llama-3.1-8B-Instruct` | 128K | $0.02 | $0.06 | chat | -| Nebius AI | `nebius/meta-llama/Llama-3.3-70B-Instruct` | 128K | $0.13 | $0.40 | chat | -| Nebius AI | `nebius/meta-llama/Llama-Guard-3-8B` | 128K | $0.02 | $0.06 | chat | -| Nebius AI | `nebius/nvidia/Llama-3.1-Nemotron-Ultra-253B-v1` | 128K | $0.60 | $1.80 | chat | -| Nebius AI | `nebius/nvidia/Llama-3.3-Nemotron-Super-49B-v1` | 131K | $0.10 | $0.40 | chat | -| Nebius AI | `nebius/NousResearch/Hermes-3-Llama-3.1-405B` | 128K | $1.00 | $3.00 | chat | -| Nebius AI | `nebius/google/gemma-3-27b-it` | 128K | $0.06 | $0.20 | chat | -| Nebius AI | `nebius/mistralai/Mistral-Nemo-Instruct-2407` | 128K | $0.04 | $0.12 | chat | -| Nebius AI | `nebius/Qwen/Qwen2.5-Coder-7B` | 32K | $0.01 | $0.03 | chat | -| Nebius AI | `nebius/BAAI/bge-en-icl` | 32K | $0.01 | - | embeddings | -| Nebius AI | `nebius/BAAI/bge-multilingual-gemma2` | 8K | $0.01 | - | embeddings | -| Nebius AI | `nebius/intfloat/e5-mistral-7b-instruct` | 32K | $0.01 | - | embeddings | -| AWS Bedrock | `mistral.devstral-2-123b` | 256K | $0.40 | $2.00 | chat, tools | -| AWS Bedrock | `zai.glm-4.7-flash` | 200K | $0.07 | $0.40 | chat, tools, reasoning | -| ZAI | `zai/glm-5` | 200K | $1.00 | $3.20 | chat, tools, reasoning | -| ZAI | `zai/glm-5-code` | 200K | $1.20 | $5.00 | chat, tools, reasoning | -| OpenRouter | `openrouter/anthropic/claude-sonnet-4.6` | - | - | - | chat | -| OpenRouter | `openrouter/google/gemini-3.1-pro-preview` | - | - | - | chat | -| OpenRouter | `openrouter/openai/gpt-5.1-codex-max` | - | - | - | chat | -| OpenRouter | `openrouter/qwen/qwen3-coder-plus` | - | - | - | chat | -| OpenRouter | `openrouter/qwen/qwen3.5-*` (5 models) | - | - | - | chat | -| OpenRouter | `openrouter/z-ai/glm-5` | - | - | - | chat | -| Together AI | `together_ai/Qwen/Qwen3.5-397B-A17B` | - | - | - | chat | -| Perplexity | `perplexity/pplx-embed-v1-0.6b` | 32K | $0.00 | - | embeddings | -| Perplexity | `perplexity/pplx-embed-v1-4b` | 32K | $0.03 | - | embeddings | -| Serper | `serper/search` | - | - | - | search | - -#### Updated Models - -- **[AWS Bedrock](../../docs/providers/bedrock)** - - Add `cache_read_input_token_cost` and `cache_creation_input_token_cost` to Bedrock-hosted Anthropic models (`claude-3-opus`, `claude-3-sonnet`, `claude-3-haiku`, and APAC/EU variants) — prompt caching is now tracked for cost estimation - - Rename `apac.anthropic.claude-sonnet-4-6` → `au.anthropic.claude-sonnet-4-6` to reflect correct regional identifier - -- **[Azure OpenAI](../../docs/providers/azure)** - - Add `supports_none_reasoning_effort` to all `gpt-5.1-chat`, `gpt-5.1-codex`, and `gpt-5.4` variants (global, EU, standard deployments) — allows passing `reasoning_effort: null` to disable reasoning - -- **[Azure OpenAI](../../docs/providers/azure)** — Removed deprecated models - - Remove `azure/gpt-35-turbo-0301` (deprecated 2025-02-13) - - Remove `azure/gpt-35-turbo-0613` (deprecated 2025-02-13) - -#### Features - -- **[OpenAI](../../docs/providers/openai)** - - Day 0 support for `gpt-5.4` and `gpt-5.4-pro` on OpenAI and Azure - -- **[Google Gemini](../../docs/providers/gemini)** - - Add Gemini 3.x model cost map entries — `gemini-3-flash-preview`, `gemini-3.1-pro-preview`, `gemini-3.1-flash-lite-preview`, `gemini-3-pro-image-preview`, `gemini-embedding-2-preview` - - Add Gemini 2.0 Flash and Flash Lite to cost map (re-added with updated pricing) - -- **[Google Vertex AI](../../docs/providers/vertex)** - - Add `gemini-3-flash-preview`, `gemini-3.1-flash-lite-preview`, `gemini-flash-experimental`, and `gemini-embedding-2-preview` to Vertex AI model cost map - -- **[Mistral](../../docs/providers/mistral)** - - Add Magistral reasoning models (`magistral-medium-1-2-2509`, `magistral-small-1-2-2509`) - - Add `mistral-large-2512`, `mistral-medium-3-1-2508`, `mistral-small-3-2-2506`, `ministral-3-*` variants - -- **[Dashscope / Qwen](../../docs/providers/dashscope)** - - Add Qwen3 VL multimodal models (`qwen3-vl-235b`, `qwen3-vl-32b` — instruct and thinking variants) - - Add `qwen3-next-80b-a3b` (instruct + thinking), `qwen3.5-plus`, `qwen3-max-2026-01-23` - -- **[Black Forest Labs](../../docs/providers/black_forest_labs)** - - Add FLUX Kontext image editing models (`flux-kontext-pro`, `flux-kontext-max`) - - Add FLUX Pro 1.0 Fill (inpainting) and Expand (outpainting) - - Add `flux-pro-1.1`, `flux-pro-1.1-ultra`, `flux-dev`, `flux-pro` - -- **[Azure AI](../../docs/providers/azure_ai)** - - Add xAI Grok models via Azure AI Foundry (`grok-4-1-fast-non-reasoning`, `grok-4-1-fast-reasoning`) - - Add Mistral Document AI (`mistral-document-ai-2512`) — OCR mode - -- **[AWS Bedrock](../../docs/providers/bedrock)** - - Add `mistral.devstral-2-123b` (256K context, tools) - - Add `zai.glm-4.7-flash` via Bedrock Converse (200K context, tools, reasoning) - -- **[SageMaker](../../docs/providers/aws_sagemaker)** - - Add `sagemaker_nova` provider for Amazon Nova models on SageMaker - [PR #21542](https://github.com/BerriAI/litellm/pull/21542) - -#### Deprecated / Removed Models - -**OpenAI** — Legacy models removed from cost map: -- `gpt-3.5-turbo-0301`, `gpt-3.5-turbo-0613`, `gpt-3.5-turbo-16k-0613` -- `gpt-4-0314`, `gpt-4-32k`, `gpt-4-32k-0314`, `gpt-4-32k-0613`, `gpt-4-1106-vision-preview`, `gpt-4-vision-preview` -- `gpt-4.5-preview`, `gpt-4.5-preview-2025-02-27` -- `gpt-4o-audio-preview-2024-10-01`, `gpt-4o-realtime-preview-2024-10-01` -- `o1-mini`, `o1-mini-2024-09-12`, `o1-preview`, `o1-preview-2024-09-12` - -**Google Gemini** — Gemini 1.5 and legacy 2.0 variants removed: -- All `gemini-1.5-*` variants (flash, flash-8b, pro, and dated versions) -- `gemini-2.0-flash-exp`, `gemini-2.0-pro-exp-02-05`, `gemini-2.5-flash-preview-04-17`, `gemini-2.5-flash-preview-05-20` - -**Google Vertex AI** — PaLM 2 / legacy models removed: -- All `chat-bison`, `text-bison`, `codechat-bison`, `code-bison`, `code-gecko` variants -- Gemini 1.0 Pro, 1.5 Flash/Pro, 2.0 Flash experimental, and preview variants - -**Perplexity** — Legacy Llama-sonar models removed: -- `llama-3.1-sonar-huge-128k-online`, `llama-3.1-sonar-large/small-128k-chat/online` - ---- - -## LLM API Endpoints - -#### Features - -- **[Responses API](../../docs/response_api)** - - Handle `response.failed`, `response.incomplete`, and `response.cancelled` terminal event types in background streaming — previously only `response.completed` was handled - [PR #23492](https://github.com/BerriAI/litellm/pull/23492) - -#### Bug Fixes - -- **[Anthropic](../../docs/providers/anthropic)** - - Preserve native tool format (web_search, bash, tool_search, etc.) when guardrails convert tools for the Anthropic Messages API - [PR #23526](https://github.com/BerriAI/litellm/pull/23526) - -- **[Moonshot / Kimi](../../docs/providers/openai_compatible)** - - Auto-fill `reasoning_content` for Moonshot Kimi reasoning models - [PR #23580](https://github.com/BerriAI/litellm/pull/23580) - -- **[HuggingFace](../../docs/providers/huggingface)** - - Forward `extra_headers` to HuggingFace embedding API - [PR #23525](https://github.com/BerriAI/litellm/pull/23525) - -- **General** - - Normalize `content_filtered` finish reason across providers - [PR #23564](https://github.com/BerriAI/litellm/pull/23564) - - Fix custom cost tracking on deployments for `/v1/messages` and `/v1/responses` - [PR #23647](https://github.com/BerriAI/litellm/pull/23647) - - Fix per-request custom pricing when `router_model_id` has no pricing data — now falls back to model name - ---- - -## Management Endpoints / UI - -#### Features - -- **Virtual Keys** - - Add Organization dropdown to Create/Edit Key form — `organization_id` is now a first-class field in Key Ownership - [PR #23595](https://github.com/BerriAI/litellm/pull/23595) - - Allow setting `organization_id` on `/key/update` — keys can be assigned or moved to a different organization after creation - [PR #23557](https://github.com/BerriAI/litellm/pull/23557) - -- **Internal Users** - - Add/Remove Team Membership directly from the Internal Users info page — includes searchable dropdown and role selector; no longer requires navigating to each team - [PR #23638](https://github.com/BerriAI/litellm/pull/23638) - -- **Default Team Settings** - - Modernize page to antd (consistent with rest of app) - [PR #23614](https://github.com/BerriAI/litellm/pull/23614) - - Fix: default team params (budget, duration, tpm, rpm, permissions) now correctly applied on `/team/new` - [PR #23614](https://github.com/BerriAI/litellm/pull/23614) - - Fix: settings persist across proxy restarts (`default_team_params` added to `LITELLM_SETTINGS_SAFE_DB_OVERRIDES`) - [PR #23614](https://github.com/BerriAI/litellm/pull/23614) - - Fix: resolved race condition in `_update_litellm_setting` where `get_config()` could overwrite freshly saved values - [PR #23614](https://github.com/BerriAI/litellm/pull/23614) - -- **Usage** - - Auto-paginate daily spend data — all entity views (teams, orgs, customers, tags, agents, users) fetch pages progressively with charts updating after each page - [PR #23622](https://github.com/BerriAI/litellm/pull/23622) - -- **Models / Cost** - - Azure Model Router cost breakdown in UI — show per-sub-model `additional_costs` from `hidden_params` in `CostBreakdownViewer` - [PR #23550](https://github.com/BerriAI/litellm/pull/23550) - -- **User Management** - - New `/user/info/v2` endpoint — scoped, paginated replacement for the existing god endpoint that caused memory and stability issues on large installs - [PR #23437](https://github.com/BerriAI/litellm/pull/23437) - -#### Bugs - -- Fix Tag list endpoint returning 500 due to invalid Prisma `group_by` kwargs - [PR #23606](https://github.com/BerriAI/litellm/pull/23606) -- Fix Team Admin getting 403 on `/user/filter/ui` when `scope_user_search_to_org` is enabled - [PR #23671](https://github.com/BerriAI/litellm/pull/23671) -- Fix Public Model Hub not showing config-defined models after save - [PR #23501](https://github.com/BerriAI/litellm/pull/23501) -- Fix fallback popup model dropdown z-index issue - [PR #23516](https://github.com/BerriAI/litellm/pull/23516) -- Fix double-counting bug in org/team key limit checks on `/key/update` - ---- - -## AI Integrations - -### Logging - -- **[Vantage](https://vantage.sh)** - - Add Vantage integration for FOCUS 1.2 CSV export — export LiteLLM proxy spend data as FinOps Open Cost & Usage Specification reports, with time-windowed filenames to prevent overwrites - [PR #23333](https://github.com/BerriAI/litellm/pull/23333) - -- **General** - - Fix silent metrics race condition causing metric collision across experiments - [PR #23542](https://github.com/BerriAI/litellm/pull/23542) - -### Guardrails - -No major guardrail changes in this release. - -### Prompt Management - -No major prompt management changes in this release. - -### Secret Managers - -No major secret manager changes in this release. - ---- - -## Performance / Loadbalancing / Reliability improvements - -- **Fix streaming crashes after ~1 hour** — `LLMClientCache._remove_key()` no longer calls `close()`/`aclose()` on evicted HTTP/SDK clients. In-flight requests were crashing with `RuntimeError: Cannot send a request, as the client has been closed.` after the 1-hour TTL expired. Cleanup now happens only at shutdown via `close_litellm_async_clients()` - [PR #22926](https://github.com/BerriAI/litellm/pull/22926) -- **Fix OOM / Prisma connection loss** on large installs — unbounded managed-object poll was exhausting Prisma connections after ~60–70 minutes on instances with 336K+ queued response rows - [PR #23472](https://github.com/BerriAI/litellm/pull/23472) -- **Centralize logging kwarg updates** — root cause fix migrating all logging updates to a single function, eliminating kwarg inconsistencies across logging paths - [PR #23659](https://github.com/BerriAI/litellm/pull/23659) -- **Fix tiktoken cache for non-root offline containers** — tiktoken cache now works correctly in offline environments running as non-root users - [PR #23498](https://github.com/BerriAI/litellm/pull/23498) -- **Add CodSpeed continuous performance benchmarks** — automated performance regression tracking on CI - [PR #23676](https://github.com/BerriAI/litellm/pull/23676) - ---- - -## Security - -- **Secret redaction in proxy logs** — Adds a `SecretRedactionFilter` to all LiteLLM loggers that scrubs API keys, tokens, and credentials from log messages, format args, exception tracebacks, and extra fields. Enabled by default; opt out with `LITELLM_DISABLE_REDACT_SECRETS=true` - [PR #23668](https://github.com/BerriAI/litellm/pull/23668), [PR #23667](https://github.com/BerriAI/litellm/pull/23667) -- **Bump PyJWT to `^2.12.0`** — addresses security vulnerability in `^2.10.1` - [PR #23678](https://github.com/BerriAI/litellm/pull/23678) -- **Bump `tar` to 7.5.11 and `tornado` to 6.5.5** — addresses CVEs in transitive dependencies - [PR #23602](https://github.com/BerriAI/litellm/pull/23602) - ---- - -## Database / Proxy Operations - -- **Fix Prisma migrate deploy on pre-existing instances** — resolved multiple bugs in migration recovery logic: missing return in the P3018 idempotent error handler and unhandled exceptions in `_roll_back_migration` that caused silent failures even after successful recovery - [PR #23655](https://github.com/BerriAI/litellm/pull/23655) -- **Make DB migration failure exit opt-in** — proxy no longer exits on `prisma migrate deploy` failure by default; enable with `--enforce_prisma_migration_check` - [PR #23675](https://github.com/BerriAI/litellm/pull/23675) - ---- - -## New Contributors - -* @ryanh-ai made their first contribution in [PR #21542](https://github.com/BerriAI/litellm/pull/21542) -* @ryan-crabbe made their first contribution in [PR #23668](https://github.com/BerriAI/litellm/pull/23668) -* @Jah-yee made their first contribution in [PR #23525](https://github.com/BerriAI/litellm/pull/23525) -* @gambletan made their first contribution in [PR #23516](https://github.com/BerriAI/litellm/pull/23516) -* @awais786 made their first contribution in [PR #23183](https://github.com/BerriAI/litellm/pull/23183) -* @pradyyadav made their first contribution in [PR #23580](https://github.com/BerriAI/litellm/pull/23580) -* @xianzongxie-stripe made their first contribution in [PR #23492](https://github.com/BerriAI/litellm/pull/23492) -* @Harshit28j made their first contribution in [PR #23333](https://github.com/BerriAI/litellm/pull/23333) -* @codspeed-hq[bot] made their first contribution in [PR #23676](https://github.com/BerriAI/litellm/pull/23676) - ---- - -## Diff Summary - -## 03/16/2026 -* New Providers: 5 -* New Models / Updated Models: 116 new, 132 removed -* LLM API Endpoints: 5 -* Management Endpoints / UI: 11 -* AI Integrations: 2 -* Performance / Reliability: 5 -* Security: 3 -* Database / Proxy Operations: 2 - ---- - -## Full Changelog -[v1.82.0-stable...v1.82.3-stable](https://github.com/BerriAI/litellm/compare/v1.82.0-stable...v1.82.3-stable) diff --git a/provider_endpoints_support.json b/provider_endpoints_support.json index 473edb5a6b..2f3302bb57 100644 --- a/provider_endpoints_support.json +++ b/provider_endpoints_support.json @@ -471,7 +471,9 @@ "audio_speech": false, "moderations": false, "batches": false, - "rerank": false + "rerank": false, + "a2a": false, + "interactions": false } }, "chutes": { @@ -1484,12 +1486,12 @@ } }, "nebius": { - "display_name": "Nebius AI (`nebius`)", + "display_name": "Nebius AI Studio (`nebius`)", "url": "https://docs.litellm.ai/docs/providers/nebius", "endpoints": { "chat_completions": true, - "messages": false, - "responses": false, + "messages": true, + "responses": true, "embeddings": true, "image_generations": false, "audio_transcriptions": false, @@ -1497,7 +1499,8 @@ "moderations": false, "batches": false, "rerank": false, - "a2a": false + "a2a": true, + "interactions": true } }, "nlp_cloud": { @@ -2078,20 +2081,9 @@ }, "serper": { "display_name": "Serper (`serper`)", - "url": "https://docs.litellm.ai/docs/providers/serper", + "url": "https://docs.litellm.ai/docs/search/serper", "endpoints": { - "chat_completions": false, - "messages": false, - "responses": false, - "embeddings": false, - "image_generations": false, - "audio_transcriptions": false, - "audio_speech": false, - "moderations": false, - "batches": false, - "rerank": false, - "search": true, - "a2a": false + "search": true } }, "triton": { @@ -2273,12 +2265,12 @@ } }, "zai": { - "display_name": "ZAI (`zai`)", - "url": "https://docs.litellm.ai/docs/providers/openai_compatible", + "display_name": "Z.AI (Zhipu AI) (`zai`)", + "url": "https://docs.litellm.ai/docs/providers/zai", "endpoints": { "chat_completions": true, - "messages": false, - "responses": false, + "messages": true, + "responses": true, "embeddings": false, "image_generations": false, "audio_transcriptions": false, @@ -2286,7 +2278,8 @@ "moderations": false, "batches": false, "rerank": false, - "a2a": false + "a2a": true, + "interactions": true } }, "ragflow": { @@ -2558,25 +2551,23 @@ "audio_speech": false, "moderations": false, "batches": false, - "rerank": false, - "a2a": false + "rerank": false } }, - "sagemaker_nova": { - "display_name": "AWS SageMaker Nova (`sagemaker_nova`)", - "url": "https://docs.litellm.ai/docs/providers/aws_sagemaker", + "charity_engine": { + "display_name": "Charity Engine (`charity_engine`)", + "url": "https://docs.litellm.ai/docs/providers/charity_engine", "endpoints": { "chat_completions": true, - "messages": false, - "responses": false, + "messages": true, + "responses": true, "embeddings": false, "image_generations": false, "audio_transcriptions": false, "audio_speech": false, "moderations": false, "batches": false, - "rerank": false, - "a2a": false + "rerank": false } } }, From 0b0fe7e26374b5473bdfe67c76eb952828c26ce4 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Mon, 16 Mar 2026 22:26:53 -0700 Subject: [PATCH 223/289] [Fix] Rename toggle label to "Disable custom Virtual key values" Co-Authored-By: Claude Opus 4.6 --- .../Settings/AdminSettings/UISettings/UISettings.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx index 0d12a4c4bf..f3eb6abdec 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx @@ -397,17 +397,17 @@ export default function UISettings() { - {/* Disable custom API key values */} + {/* Disable custom Virtual key values */} - Disable custom API key values + Disable custom Virtual key values {disableCustomApiKeysProperty?.description ?? "If true, users cannot specify custom API key values. All keys must be auto-generated."} From 471e0f147e3a19da4c55e7b54a92c4023a07f49c Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Mon, 16 Mar 2026 22:35:44 -0700 Subject: [PATCH 224/289] [Fix] Remove "API" from custom key description text Co-Authored-By: Claude Opus 4.6 --- litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py | 2 +- .../components/Settings/AdminSettings/UISettings/UISettings.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py b/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py index 9faadd334a..60bf41709e 100644 --- a/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py +++ b/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py @@ -131,7 +131,7 @@ class UISettings(BaseModel): disable_custom_api_keys: bool = Field( default=False, - description="If true, users cannot specify custom API key values. All keys must be auto-generated.", + description="If true, users cannot specify custom key values. All keys must be auto-generated.", ) diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx index f3eb6abdec..fb7c38449b 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx @@ -410,7 +410,7 @@ export default function UISettings() { Disable custom Virtual key values {disableCustomApiKeysProperty?.description ?? - "If true, users cannot specify custom API key values. All keys must be auto-generated."} + "If true, users cannot specify custom key values. All keys must be auto-generated."} From c098eca509ef5f0393ac4e33bc9e5ae2eeb283f8 Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Mon, 16 Mar 2026 22:31:53 -0700 Subject: [PATCH 225/289] fix(ui): CSV export empty on Global Usage page Aggregated endpoint returns empty breakdown.entities; fall back to grouping breakdown.api_keys by team_id. --- .../EntityUsageExport/utils.test.ts | 134 ++++++++++++++++++ .../src/components/EntityUsageExport/utils.ts | 53 ++++++- 2 files changed, 182 insertions(+), 5 deletions(-) diff --git a/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts b/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts index 67de4b6917..2ca7ad7ef3 100644 --- a/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts +++ b/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts @@ -11,6 +11,7 @@ import { getEntityBreakdown, handleExportCSV, handleExportJSON, + resolveEntities, } from "./utils"; vi.mock("@/utils/dataUtils", () => ({ @@ -1561,4 +1562,137 @@ describe("EntityUsageExport utils", () => { window.Blob = originalBlob; }); }); + + describe("resolveEntities and aggregated endpoint fallback", () => { + // Simulates the response from /user/daily/activity/aggregated which has + // empty entities but populated api_keys at the breakdown level. + // Derived from mockSpendData: flatten all entities' api_key_breakdowns + // into top-level api_keys, clear entities, and add a second key for team-1 + // to test multi-key grouping. + const aggregatedSpendData: EntitySpendData = { + ...mockSpendData, + results: mockSpendData.results.slice(0, 1).map((day) => ({ + ...day, + breakdown: { + entities: {}, + api_keys: { + ...Object.fromEntries( + Object.values(day.breakdown.entities as Record).flatMap((e: any) => + Object.entries(e.api_key_breakdown || {}), + ), + ), + // Extra key on team-1 to test multi-key-per-team aggregation + key1b: { + metrics: { spend: 5, api_requests: 50, successful_requests: 48, failed_requests: 2, total_tokens: 500 }, + metadata: { team_id: "team-1", key_alias: "staging-key" }, + }, + }, + models: { "gpt-4": { metrics: { spend: 35, api_requests: 350, total_tokens: 3500 } } }, + }, + })), + }; + + describe("resolveEntities", () => { + it("should return entities when populated", () => { + const breakdown = { + entities: { e1: { metrics: { spend: 1 } } }, + api_keys: { k1: { metrics: { spend: 2 }, metadata: { team_id: "t1" } } }, + }; + const result = resolveEntities(breakdown); + expect(result).toBe(breakdown.entities); + }); + + it("should aggregate api_keys into entities when entities is empty", () => { + const breakdown = aggregatedSpendData.results[0].breakdown; + const result = resolveEntities(breakdown); + + // Two teams: team-1 (key1+key2) and team-2 (key3) + expect(Object.keys(result)).toHaveLength(2); + expect(result["team-1"]).toBeDefined(); + expect(result["team-2"]).toBeDefined(); + + // team-1 spend = 10.5 (key1) + 5 (key1b) + expect(result["team-1"].metrics.spend).toBe(15.5); + expect(result["team-1"].metrics.api_requests).toBe(150); + expect(result["team-1"].metrics.total_tokens).toBe(1500); + + // team-2 spend = 20.3 (key2) + expect(result["team-2"].metrics.spend).toBe(20.3); + expect(result["team-2"].metrics.api_requests).toBe(200); + }); + + it("should use 'Unassigned' for keys without team_id", () => { + const breakdown = { + entities: {}, + api_keys: { + k1: { + metrics: { spend: 7, api_requests: 10, successful_requests: 10, failed_requests: 0, total_tokens: 100 }, + metadata: {}, + }, + }, + }; + const result = resolveEntities(breakdown); + expect(result["Unassigned"]).toBeDefined(); + expect(result["Unassigned"].metrics.spend).toBe(7); + }); + + it("should handle missing or empty api_keys gracefully", () => { + expect(Object.keys(resolveEntities({ entities: {}, api_keys: {} }))).toHaveLength(0); + expect(Object.keys(resolveEntities({ entities: {} }))).toHaveLength(0); + }); + + it("should preserve api_key_breakdown on aggregated entities", () => { + const breakdown = aggregatedSpendData.results[0].breakdown; + const result = resolveEntities(breakdown); + + // team-1 should have key1 and key1b in api_key_breakdown + expect(Object.keys(result["team-1"].api_key_breakdown)).toEqual(["key1", "key1b"]); + // team-2 should have key2 + expect(Object.keys(result["team-2"].api_key_breakdown)).toEqual(["key2"]); + }); + }); + + describe("getEntityBreakdown with aggregated data", () => { + it("should produce breakdown from api_keys when entities is empty", () => { + const result = getEntityBreakdown(aggregatedSpendData); + expect(result.length).toBeGreaterThan(0); + + // Sorted by spend desc: team-2 (20.3) then team-1 (15.5) + expect(result[0].metrics.spend).toBe(20.3); + expect(result[1].metrics.spend).toBe(15.5); + }); + + }); + + describe("generateDailyData with aggregated data", () => { + it("should produce rows from api_keys when entities is empty", () => { + const result = generateDailyData(aggregatedSpendData, "Team"); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("Date"); + expect(result[0]).toHaveProperty("Team"); + }); + }); + + describe("generateDailyWithKeysData with aggregated data", () => { + it("should produce rows from api_keys when entities is empty", () => { + const result = generateDailyWithKeysData(aggregatedSpendData, "Team"); + expect(result.length).toBeGreaterThan(0); + + // Should have 3 key rows (key1, key1b, key2) + expect(result).toHaveLength(3); + const keyIds = result.map((r) => r["Key ID"]); + expect(keyIds).toContain("key1"); + expect(keyIds).toContain("key1b"); + expect(keyIds).toContain("key2"); + }); + }); + + describe("generateDailyWithModelsData with aggregated data", () => { + it("should produce rows from api_keys when entities is empty", () => { + const result = generateDailyWithModelsData(aggregatedSpendData, "Team"); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("Model"); + }); + }); + }); }); diff --git a/ui/litellm-dashboard/src/components/EntityUsageExport/utils.ts b/ui/litellm-dashboard/src/components/EntityUsageExport/utils.ts index ebef3da8a7..45bf21a6e7 100644 --- a/ui/litellm-dashboard/src/components/EntityUsageExport/utils.ts +++ b/ui/litellm-dashboard/src/components/EntityUsageExport/utils.ts @@ -17,6 +17,49 @@ const extractTeamIdFromApiKeyBreakdown = (apiKeyBreakdown: Record | return null; }; +// Mirrors backend SpendMetrics fields (litellm/types/activity_tracking.py). +// If the backend adds a field, add it here too. +const METRIC_KEYS = [ + "spend", "api_requests", "successful_requests", "failed_requests", + "total_tokens", "prompt_tokens", "completion_tokens", + "cache_read_input_tokens", "cache_creation_input_tokens", +] as const; + +// When breakdown.entities is empty (aggregated endpoint), reconstruct entities +// from breakdown.api_keys by grouping on metadata.team_id. +const aggregateApiKeysIntoEntities = (breakdown: Record): Record => { + const apiKeys = breakdown.api_keys; + if (!apiKeys || Object.keys(apiKeys).length === 0) return {}; + + const grouped: Record = {}; + + for (const [keyId, keyData] of Object.entries(apiKeys)) { + const teamId = keyData?.metadata?.team_id || "Unassigned"; + if (!grouped[teamId]) { + grouped[teamId] = { + metrics: Object.fromEntries(METRIC_KEYS.map((k) => [k, 0])), + api_key_breakdown: {}, + }; + } + const m = grouped[teamId].metrics; + const km = keyData?.metrics || {}; + for (const k of METRIC_KEYS) { + m[k] += km[k] || 0; + } + grouped[teamId].api_key_breakdown[keyId] = keyData; + } + + return grouped; +}; + +// Returns breakdown.entities if populated, otherwise falls back to +// reconstructing entities from breakdown.api_keys. +export const resolveEntities = (breakdown: Record): Record => { + const entities = breakdown.entities; + if (entities && Object.keys(entities).length > 0) return entities; + return aggregateApiKeysIntoEntities(breakdown); +}; + export const getEntityBreakdown = ( spendData: EntitySpendData, teamAliasMap: Record = {}, @@ -24,7 +67,7 @@ export const getEntityBreakdown = ( const entitySpend: { [key: string]: EntityBreakdown } = {}; spendData.results.forEach((day) => { - Object.entries(day.breakdown.entities || {}).forEach(([entity, data]: [string, any]) => { + Object.entries(resolveEntities(day.breakdown)).forEach(([entity, data]: [string, any]) => { // Extract team_id from api_key_breakdown metadata (not data.metadata which is empty) const teamId = extractTeamIdFromApiKeyBreakdown(data.api_key_breakdown) || entity; // Extract key_alias from the first API key that has one @@ -80,7 +123,7 @@ export const generateDailyData = ( const dailyBreakdown: any[] = []; spendData.results.forEach((day) => { - Object.entries(day.breakdown.entities || {}).forEach(([entity, data]: [string, any]) => { + Object.entries(resolveEntities(day.breakdown)).forEach(([entity, data]: [string, any]) => { // Extract team_id from api_key_breakdown metadata (not data.metadata which is empty) const teamId = extractTeamIdFromApiKeyBreakdown(data.api_key_breakdown); const teamAlias = teamId ? teamAliasMap[teamId] || null : null; @@ -129,7 +172,7 @@ export const generateDailyWithKeysData = ( } = {}; spendData.results.forEach((day) => { - Object.entries(day.breakdown.entities || {}).forEach(([entity, data]: [string, any]) => { + Object.entries(resolveEntities(day.breakdown)).forEach(([entity, data]: [string, any]) => { const apiKeyBreakdown = data.api_key_breakdown || {}; // Iterate through each API key in the breakdown @@ -202,7 +245,7 @@ export const generateDailyWithModelsData = ( spendData.results.forEach((day) => { const dailyEntityModels: { [key: string]: { [key: string]: any } } = {}; - Object.entries(day.breakdown.entities || {}).forEach(([entity, entityData]: [string, any]) => { + Object.entries(resolveEntities(day.breakdown)).forEach(([entity, entityData]: [string, any]) => { if (!dailyEntityModels[entity]) { dailyEntityModels[entity] = {}; } @@ -230,7 +273,7 @@ export const generateDailyWithModelsData = ( }); Object.entries(dailyEntityModels).forEach(([entity, models]) => { - const entityData = day.breakdown.entities?.[entity]; + const entityData = resolveEntities(day.breakdown)[entity]; // Extract team_id from api_key_breakdown metadata (not entityData.metadata which is empty) const teamId = extractTeamIdFromApiKeyBreakdown(entityData?.api_key_breakdown); const teamAlias = teamId ? teamAliasMap[teamId] || null : null; From 7348a537e8f85ed1d4a949c3c7dff758ec504287 Mon Sep 17 00:00:00 2001 From: joereyna Date: Mon, 16 Mar 2026 22:41:22 -0700 Subject: [PATCH 226/289] docs: add v1.82.3 release notes and update provider_endpoints_support.json - Fix provider count header: 4 -> 5 new providers - Fix nebius/zai: add bridged endpoint support (messages, responses, a2a, interactions) - Add missing sagemaker_nova to provider_endpoints_support.json --- docs/my-website/release_notes/v1.82.3.md | 374 +++++++++++++++++++++++ provider_endpoints_support.json | 17 +- 2 files changed, 382 insertions(+), 9 deletions(-) create mode 100644 docs/my-website/release_notes/v1.82.3.md diff --git a/docs/my-website/release_notes/v1.82.3.md b/docs/my-website/release_notes/v1.82.3.md new file mode 100644 index 0000000000..73e5bbf1f1 --- /dev/null +++ b/docs/my-website/release_notes/v1.82.3.md @@ -0,0 +1,374 @@ +--- +title: "v1.82.3 - Nebius AI, gpt-5.4, Gemini 3.x, FLUX Kontext, and 116 New Models" +slug: "v1-82-3" +date: 2026-03-16T00:00:00 +authors: + - name: Krrish Dholakia + title: CEO, LiteLLM + url: https://www.linkedin.com/in/krish-d/ + image_url: https://pbs.twimg.com/profile_images/1298587542745358340/DZv3Oj-h_400x400.jpg + - name: Ishaan Jaff + title: CTO, LiteLLM + url: https://www.linkedin.com/in/reffajnaahsi/ + image_url: https://pbs.twimg.com/profile_images/1613813310264340481/lz54oEiB_400x400.jpg +hide_table_of_contents: false +--- + +## Deploy this version + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + +``` showLineNumbers title="docker run litellm" +docker run \ +-e STORE_MODEL_IN_DB=True \ +-p 4000:4000 \ +ghcr.io/berriai/litellm:main-1.82.3-stable +``` + + + + +``` showLineNumbers title="pip install litellm" +pip install litellm==1.82.3 +``` + + + + +## Key Highlights + +- **Nebius AI — new provider** — [30 models across DeepSeek, Qwen, Llama, Mistral, NVIDIA, and BAAI available via Nebius AI cloud](../../docs/providers/nebius) - [PR #21542](https://github.com/BerriAI/litellm/pull/21542) +- **OpenAI gpt-5.4 / gpt-5.4-pro — day 0** — Full pricing and routing support for `gpt-5.4` (1M context, $2.50/$15.00) and `gpt-5.4-pro` ($30.00/$180.00) on OpenAI and Azure +- **Gemini 3.x models** — `gemini-3-flash-preview`, `gemini-3.1-pro-preview`, `gemini-3.1-flash-image-preview`, and `gemini-embedding-2-preview` added to cost map for Google AI and Vertex AI +- **FLUX Kontext image editing** — `flux-kontext-pro` and `flux-kontext-max` added to Black Forest Labs, alongside `flux-pro-1.0-fill` and `flux-pro-1.0-expand` for inpainting and outpainting +- **116 new models, 132 deprecated models cleaned up** — Major model map refresh including Mistral Magistral, Dashscope Qwen3 VL, xAI Grok via Azure AI, ZAI GLM-5, Serper Search; removal of OpenAI GPT-3.5/GPT-4 legacy variants, Gemini 1.5, and Vertex AI PaLM2 +- **SageMaker Nova provider** — [New `sagemaker_nova` provider for Amazon Nova models on SageMaker](../../docs/providers/aws_sagemaker) - [PR #21542](https://github.com/BerriAI/litellm/pull/21542) +- **Secret redaction in logs** — API keys, tokens, and credentials automatically scrubbed from all proxy log output. Enabled by default; opt out with `LITELLM_DISABLE_REDACT_SECRETS=true` - [PR #23668](https://github.com/BerriAI/litellm/pull/23668) +- **Streaming stability fix** — Critical fix for `RuntimeError: Cannot send a request, as the client has been closed.` crashes after ~1 hour in production - [PR #22926](https://github.com/BerriAI/litellm/pull/22926) + +--- + +## New Providers and Endpoints + +### New Providers (5 new providers) + +| Provider | Supported LiteLLM Endpoints | Description | +| -------- | --------------------------- | ----------- | +| [Nebius AI](../../docs/providers/nebius) (`nebius/`) | `/chat/completions`, `/embeddings` | EU-based AI cloud with 30+ open models — DeepSeek, Qwen3, Llama 3.1/3.3, NVIDIA Nemotron, BAAI embeddings | +| [ZAI](../../docs/providers/openai_compatible) (`zai/`) | `/chat/completions` | ZhipuAI GLM-5 models via ZAI cloud | +| [Black Forest Labs](../../docs/providers/black_forest_labs) (`black_forest_labs/`) | `/images/generations`, `/images/edits` | FLUX image generation and editing — Kontext Pro/Max, Pro 1.0 Fill/Expand | +| [Serper](../../docs/providers/serper) (`serper/`) | `/search` | Web search via Serper API | +| [SageMaker Nova](../../docs/providers/aws_sagemaker) (`sagemaker_nova/`) | `/chat/completions` | Amazon Nova models via SageMaker endpoint | + +--- + +## New Models / Updated Models + +#### New Model Support (116 new models) + +| Provider | Model | Context Window | Input ($/1M tokens) | Output ($/1M tokens) | Features | +| -------- | ----- | -------------- | ------------------- | -------------------- | -------- | +| OpenAI | `gpt-5.4` | 1.05M | $2.50 | $15.00 | chat, vision, tools, reasoning | +| OpenAI | `gpt-5.4-pro` | 1.05M | $30.00 | $180.00 | responses, vision, tools, reasoning | +| OpenAI | `gpt-5.3-chat-latest` | 128K | $1.75 | $14.00 | chat, vision, tools, reasoning | +| Azure OpenAI | `azure/gpt-5.4` | 1.05M | $2.50 | $15.00 | chat, vision, tools, reasoning | +| Azure OpenAI | `azure/gpt-5.4-pro` | 1.05M | $30.00 | $180.00 | responses, vision, tools, reasoning | +| Azure OpenAI | `azure/gpt-5.3-chat` | 128K | $1.75 | $14.00 | chat, vision, tools, reasoning | +| Google Gemini | `gemini/gemini-3-flash-preview` | 1M | $0.50 | $3.00 | chat, vision, tools, reasoning | +| Google Gemini | `gemini/gemini-3.1-pro-preview` | 1M | $2.00 | $12.00 | chat, vision, tools, reasoning | +| Google Gemini | `gemini/gemini-3.1-flash-image-preview` | 65K | $0.25 | $1.50 | image generation, vision | +| Google Gemini | `gemini/gemini-3.1-flash-lite-preview` | - | - | - | chat | +| Google Gemini | `gemini/gemini-3-pro-image-preview` | - | - | - | image generation | +| Google Gemini | `gemini/gemini-embedding-2-preview` | 8K | $0.20 | - | embeddings | +| Google Vertex AI | `vertex_ai/gemini-3-flash-preview` | - | - | - | chat | +| Google Vertex AI | `vertex_ai/gemini-3.1-pro-preview` | - | - | - | chat | +| Google Vertex AI | `vertex_ai/gemini-3.1-flash-lite-preview` | - | - | - | chat | +| Google Vertex AI | `vertex_ai/gemini-embedding-2-preview` | - | $0.20 | - | embeddings | +| Mistral | `mistral/magistral-medium-1-2-2509` | 40K | $2.00 | $5.00 | chat, tools, reasoning | +| Mistral | `mistral/magistral-small-1-2-2509` | 40K | $0.50 | $1.50 | chat, tools, reasoning | +| Mistral | `mistral/mistral-large-2512` | 262K | $0.50 | $1.50 | chat, vision, tools | +| Mistral | `mistral/mistral-medium-3-1-2508` | - | - | - | chat | +| Mistral | `mistral/mistral-small-3-2-2506` | - | - | - | chat | +| Mistral | `mistral/ministral-3-3b-2512` | - | - | - | chat | +| Mistral | `mistral/ministral-3-8b-2512` | - | - | - | chat | +| Mistral | `mistral/ministral-3-14b-2512` | - | - | - | chat | +| Black Forest Labs | `black_forest_labs/flux-kontext-pro` | - | - | - | image editing | +| Black Forest Labs | `black_forest_labs/flux-kontext-max` | - | - | - | image editing | +| Black Forest Labs | `black_forest_labs/flux-pro-1.0-fill` | - | - | - | image editing (inpaint) | +| Black Forest Labs | `black_forest_labs/flux-pro-1.0-expand` | - | - | - | image editing (outpaint) | +| Black Forest Labs | `black_forest_labs/flux-pro-1.1` | - | - | - | image generation | +| Black Forest Labs | `black_forest_labs/flux-pro-1.1-ultra` | - | - | - | image generation | +| Black Forest Labs | `black_forest_labs/flux-dev` | - | - | - | image generation | +| Black Forest Labs | `black_forest_labs/flux-pro` | - | - | - | image generation | +| Azure AI | `azure_ai/grok-4-1-fast-non-reasoning` | 131K | $0.20 | $0.50 | chat, tools | +| Azure AI | `azure_ai/grok-4-1-fast-reasoning` | 131K | $0.20 | $0.50 | chat, tools, reasoning | +| Azure AI | `azure_ai/mistral-document-ai-2512` | - | - | - | OCR | +| Dashscope | `dashscope/qwen3-next-80b-a3b-instruct` | 262K | $0.15 | $1.20 | chat | +| Dashscope | `dashscope/qwen3-next-80b-a3b-thinking` | 262K | $0.15 | $1.20 | chat, reasoning | +| Dashscope | `dashscope/qwen3-vl-235b-a22b-instruct` | 131K | $0.40 | $1.60 | chat, vision | +| Dashscope | `dashscope/qwen3-vl-235b-a22b-thinking` | 131K | $0.40 | $4.00 | chat, vision, reasoning | +| Dashscope | `dashscope/qwen3-vl-32b-instruct` | 131K | $0.16 | $0.64 | chat, vision | +| Dashscope | `dashscope/qwen3-vl-32b-thinking` | 131K | $0.16 | $2.87 | chat, vision, reasoning | +| Dashscope | `dashscope/qwen3-vl-plus` | 260K | - | - | chat, vision | +| Dashscope | `dashscope/qwen3.5-plus` | 992K | - | - | chat | +| Dashscope | `dashscope/qwen3-max-2026-01-23` | 258K | - | - | chat | +| Nebius AI | `nebius/deepseek-ai/DeepSeek-R1` | 128K | $0.80 | $2.40 | chat, reasoning | +| Nebius AI | `nebius/deepseek-ai/DeepSeek-R1-0528` | 164K | $0.80 | $2.40 | chat, reasoning | +| Nebius AI | `nebius/deepseek-ai/DeepSeek-V3` | 128K | $0.50 | $1.50 | chat | +| Nebius AI | `nebius/deepseek-ai/DeepSeek-V3-0324` | 128K | $0.50 | $1.50 | chat | +| Nebius AI | `nebius/deepseek-ai/DeepSeek-R1-Distill-Llama-70B` | 128K | $0.25 | $0.75 | chat | +| Nebius AI | `nebius/Qwen/Qwen3-235B-A22B` | 262K | $0.20 | $0.60 | chat | +| Nebius AI | `nebius/Qwen/Qwen3-32B` | 32K | $0.10 | $0.30 | chat | +| Nebius AI | `nebius/Qwen/Qwen3-30B-A3B` | 32K | $0.10 | $0.30 | chat | +| Nebius AI | `nebius/Qwen/Qwen3-14B` | 32K | $0.08 | $0.24 | chat | +| Nebius AI | `nebius/Qwen/Qwen3-4B` | 32K | $0.08 | $0.24 | chat | +| Nebius AI | `nebius/Qwen/QwQ-32B` | 32K | $0.15 | $0.45 | chat | +| Nebius AI | `nebius/Qwen/Qwen2.5-72B-Instruct` | 128K | $0.13 | $0.40 | chat | +| Nebius AI | `nebius/Qwen/Qwen2.5-32B-Instruct` | 128K | $0.06 | $0.20 | chat | +| Nebius AI | `nebius/Qwen/Qwen2.5-VL-72B-Instruct` | 131K | $0.13 | $0.40 | chat, vision | +| Nebius AI | `nebius/Qwen/Qwen2-VL-72B-Instruct` | 131K | $0.13 | $0.40 | chat, vision | +| Nebius AI | `nebius/Qwen/Qwen2-VL-7B-Instruct` | 131K | $0.02 | $0.06 | chat, vision | +| Nebius AI | `nebius/meta-llama/Meta-Llama-3.1-405B-Instruct` | 128K | $1.00 | $3.00 | chat | +| Nebius AI | `nebius/meta-llama/Meta-Llama-3.1-70B-Instruct` | 128K | $0.13 | $0.40 | chat | +| Nebius AI | `nebius/meta-llama/Meta-Llama-3.1-8B-Instruct` | 128K | $0.02 | $0.06 | chat | +| Nebius AI | `nebius/meta-llama/Llama-3.3-70B-Instruct` | 128K | $0.13 | $0.40 | chat | +| Nebius AI | `nebius/meta-llama/Llama-Guard-3-8B` | 128K | $0.02 | $0.06 | chat | +| Nebius AI | `nebius/nvidia/Llama-3.1-Nemotron-Ultra-253B-v1` | 128K | $0.60 | $1.80 | chat | +| Nebius AI | `nebius/nvidia/Llama-3.3-Nemotron-Super-49B-v1` | 131K | $0.10 | $0.40 | chat | +| Nebius AI | `nebius/NousResearch/Hermes-3-Llama-3.1-405B` | 128K | $1.00 | $3.00 | chat | +| Nebius AI | `nebius/google/gemma-3-27b-it` | 128K | $0.06 | $0.20 | chat | +| Nebius AI | `nebius/mistralai/Mistral-Nemo-Instruct-2407` | 128K | $0.04 | $0.12 | chat | +| Nebius AI | `nebius/Qwen/Qwen2.5-Coder-7B` | 32K | $0.01 | $0.03 | chat | +| Nebius AI | `nebius/BAAI/bge-en-icl` | 32K | $0.01 | - | embeddings | +| Nebius AI | `nebius/BAAI/bge-multilingual-gemma2` | 8K | $0.01 | - | embeddings | +| Nebius AI | `nebius/intfloat/e5-mistral-7b-instruct` | 32K | $0.01 | - | embeddings | +| AWS Bedrock | `mistral.devstral-2-123b` | 256K | $0.40 | $2.00 | chat, tools | +| AWS Bedrock | `zai.glm-4.7-flash` | 200K | $0.07 | $0.40 | chat, tools, reasoning | +| ZAI | `zai/glm-5` | 200K | $1.00 | $3.20 | chat, tools, reasoning | +| ZAI | `zai/glm-5-code` | 200K | $1.20 | $5.00 | chat, tools, reasoning | +| OpenRouter | `openrouter/anthropic/claude-sonnet-4.6` | - | - | - | chat | +| OpenRouter | `openrouter/google/gemini-3.1-pro-preview` | - | - | - | chat | +| OpenRouter | `openrouter/openai/gpt-5.1-codex-max` | - | - | - | chat | +| OpenRouter | `openrouter/qwen/qwen3-coder-plus` | - | - | - | chat | +| OpenRouter | `openrouter/qwen/qwen3.5-*` (5 models) | - | - | - | chat | +| OpenRouter | `openrouter/z-ai/glm-5` | - | - | - | chat | +| Together AI | `together_ai/Qwen/Qwen3.5-397B-A17B` | - | - | - | chat | +| Perplexity | `perplexity/pplx-embed-v1-0.6b` | 32K | $0.00 | - | embeddings | +| Perplexity | `perplexity/pplx-embed-v1-4b` | 32K | $0.03 | - | embeddings | +| Serper | `serper/search` | - | - | - | search | + +#### Updated Models + +- **[AWS Bedrock](../../docs/providers/bedrock)** + - Add `cache_read_input_token_cost` and `cache_creation_input_token_cost` to Bedrock-hosted Anthropic models (`claude-3-opus`, `claude-3-sonnet`, `claude-3-haiku`, and APAC/EU variants) — prompt caching is now tracked for cost estimation + - Rename `apac.anthropic.claude-sonnet-4-6` → `au.anthropic.claude-sonnet-4-6` to reflect correct regional identifier + +- **[Azure OpenAI](../../docs/providers/azure)** + - Add `supports_none_reasoning_effort` to all `gpt-5.1-chat`, `gpt-5.1-codex`, and `gpt-5.4` variants (global, EU, standard deployments) — allows passing `reasoning_effort: null` to disable reasoning + +- **[Azure OpenAI](../../docs/providers/azure)** — Removed deprecated models + - Remove `azure/gpt-35-turbo-0301` (deprecated 2025-02-13) + - Remove `azure/gpt-35-turbo-0613` (deprecated 2025-02-13) + +#### Features + +- **[OpenAI](../../docs/providers/openai)** + - Day 0 support for `gpt-5.4` and `gpt-5.4-pro` on OpenAI and Azure + +- **[Google Gemini](../../docs/providers/gemini)** + - Add Gemini 3.x model cost map entries — `gemini-3-flash-preview`, `gemini-3.1-pro-preview`, `gemini-3.1-flash-lite-preview`, `gemini-3-pro-image-preview`, `gemini-embedding-2-preview` + - Add Gemini 2.0 Flash and Flash Lite to cost map (re-added with updated pricing) + +- **[Google Vertex AI](../../docs/providers/vertex)** + - Add `gemini-3-flash-preview`, `gemini-3.1-flash-lite-preview`, `gemini-flash-experimental`, and `gemini-embedding-2-preview` to Vertex AI model cost map + +- **[Mistral](../../docs/providers/mistral)** + - Add Magistral reasoning models (`magistral-medium-1-2-2509`, `magistral-small-1-2-2509`) + - Add `mistral-large-2512`, `mistral-medium-3-1-2508`, `mistral-small-3-2-2506`, `ministral-3-*` variants + +- **[Dashscope / Qwen](../../docs/providers/dashscope)** + - Add Qwen3 VL multimodal models (`qwen3-vl-235b`, `qwen3-vl-32b` — instruct and thinking variants) + - Add `qwen3-next-80b-a3b` (instruct + thinking), `qwen3.5-plus`, `qwen3-max-2026-01-23` + +- **[Black Forest Labs](../../docs/providers/black_forest_labs)** + - Add FLUX Kontext image editing models (`flux-kontext-pro`, `flux-kontext-max`) + - Add FLUX Pro 1.0 Fill (inpainting) and Expand (outpainting) + - Add `flux-pro-1.1`, `flux-pro-1.1-ultra`, `flux-dev`, `flux-pro` + +- **[Azure AI](../../docs/providers/azure_ai)** + - Add xAI Grok models via Azure AI Foundry (`grok-4-1-fast-non-reasoning`, `grok-4-1-fast-reasoning`) + - Add Mistral Document AI (`mistral-document-ai-2512`) — OCR mode + +- **[AWS Bedrock](../../docs/providers/bedrock)** + - Add `mistral.devstral-2-123b` (256K context, tools) + - Add `zai.glm-4.7-flash` via Bedrock Converse (200K context, tools, reasoning) + +- **[SageMaker](../../docs/providers/aws_sagemaker)** + - Add `sagemaker_nova` provider for Amazon Nova models on SageMaker - [PR #21542](https://github.com/BerriAI/litellm/pull/21542) + +#### Deprecated / Removed Models + +**OpenAI** — Legacy models removed from cost map: +- `gpt-3.5-turbo-0301`, `gpt-3.5-turbo-0613`, `gpt-3.5-turbo-16k-0613` +- `gpt-4-0314`, `gpt-4-32k`, `gpt-4-32k-0314`, `gpt-4-32k-0613`, `gpt-4-1106-vision-preview`, `gpt-4-vision-preview` +- `gpt-4.5-preview`, `gpt-4.5-preview-2025-02-27` +- `gpt-4o-audio-preview-2024-10-01`, `gpt-4o-realtime-preview-2024-10-01` +- `o1-mini`, `o1-mini-2024-09-12`, `o1-preview`, `o1-preview-2024-09-12` + +**Google Gemini** — Gemini 1.5 and legacy 2.0 variants removed: +- All `gemini-1.5-*` variants (flash, flash-8b, pro, and dated versions) +- `gemini-2.0-flash-exp`, `gemini-2.0-pro-exp-02-05`, `gemini-2.5-flash-preview-04-17`, `gemini-2.5-flash-preview-05-20` + +**Google Vertex AI** — PaLM 2 / legacy models removed: +- All `chat-bison`, `text-bison`, `codechat-bison`, `code-bison`, `code-gecko` variants +- Gemini 1.0 Pro, 1.5 Flash/Pro, 2.0 Flash experimental, and preview variants + +**Perplexity** — Legacy Llama-sonar models removed: +- `llama-3.1-sonar-huge-128k-online`, `llama-3.1-sonar-large/small-128k-chat/online` + +--- + +## LLM API Endpoints + +#### Features + +- **[Responses API](../../docs/response_api)** + - Handle `response.failed`, `response.incomplete`, and `response.cancelled` terminal event types in background streaming — previously only `response.completed` was handled - [PR #23492](https://github.com/BerriAI/litellm/pull/23492) + +#### Bug Fixes + +- **[Anthropic](../../docs/providers/anthropic)** + - Preserve native tool format (web_search, bash, tool_search, etc.) when guardrails convert tools for the Anthropic Messages API - [PR #23526](https://github.com/BerriAI/litellm/pull/23526) + +- **[Moonshot / Kimi](../../docs/providers/openai_compatible)** + - Auto-fill `reasoning_content` for Moonshot Kimi reasoning models - [PR #23580](https://github.com/BerriAI/litellm/pull/23580) + +- **[HuggingFace](../../docs/providers/huggingface)** + - Forward `extra_headers` to HuggingFace embedding API - [PR #23525](https://github.com/BerriAI/litellm/pull/23525) + +- **General** + - Normalize `content_filtered` finish reason across providers - [PR #23564](https://github.com/BerriAI/litellm/pull/23564) + - Fix custom cost tracking on deployments for `/v1/messages` and `/v1/responses` - [PR #23647](https://github.com/BerriAI/litellm/pull/23647) + - Fix per-request custom pricing when `router_model_id` has no pricing data — now falls back to model name + +--- + +## Management Endpoints / UI + +#### Features + +- **Virtual Keys** + - Add Organization dropdown to Create/Edit Key form — `organization_id` is now a first-class field in Key Ownership - [PR #23595](https://github.com/BerriAI/litellm/pull/23595) + - Allow setting `organization_id` on `/key/update` — keys can be assigned or moved to a different organization after creation - [PR #23557](https://github.com/BerriAI/litellm/pull/23557) + +- **Internal Users** + - Add/Remove Team Membership directly from the Internal Users info page — includes searchable dropdown and role selector; no longer requires navigating to each team - [PR #23638](https://github.com/BerriAI/litellm/pull/23638) + +- **Default Team Settings** + - Modernize page to antd (consistent with rest of app) - [PR #23614](https://github.com/BerriAI/litellm/pull/23614) + - Fix: default team params (budget, duration, tpm, rpm, permissions) now correctly applied on `/team/new` - [PR #23614](https://github.com/BerriAI/litellm/pull/23614) + - Fix: settings persist across proxy restarts (`default_team_params` added to `LITELLM_SETTINGS_SAFE_DB_OVERRIDES`) - [PR #23614](https://github.com/BerriAI/litellm/pull/23614) + - Fix: resolved race condition in `_update_litellm_setting` where `get_config()` could overwrite freshly saved values - [PR #23614](https://github.com/BerriAI/litellm/pull/23614) + +- **Usage** + - Auto-paginate daily spend data — all entity views (teams, orgs, customers, tags, agents, users) fetch pages progressively with charts updating after each page - [PR #23622](https://github.com/BerriAI/litellm/pull/23622) + +- **Models / Cost** + - Azure Model Router cost breakdown in UI — show per-sub-model `additional_costs` from `hidden_params` in `CostBreakdownViewer` - [PR #23550](https://github.com/BerriAI/litellm/pull/23550) + +- **User Management** + - New `/user/info/v2` endpoint — scoped, paginated replacement for the existing god endpoint that caused memory and stability issues on large installs - [PR #23437](https://github.com/BerriAI/litellm/pull/23437) + +#### Bugs + +- Fix Tag list endpoint returning 500 due to invalid Prisma `group_by` kwargs - [PR #23606](https://github.com/BerriAI/litellm/pull/23606) +- Fix Team Admin getting 403 on `/user/filter/ui` when `scope_user_search_to_org` is enabled - [PR #23671](https://github.com/BerriAI/litellm/pull/23671) +- Fix Public Model Hub not showing config-defined models after save - [PR #23501](https://github.com/BerriAI/litellm/pull/23501) +- Fix fallback popup model dropdown z-index issue - [PR #23516](https://github.com/BerriAI/litellm/pull/23516) +- Fix double-counting bug in org/team key limit checks on `/key/update` + +--- + +## AI Integrations + +### Logging + +- **[Vantage](https://vantage.sh)** + - Add Vantage integration for FOCUS 1.2 CSV export — export LiteLLM proxy spend data as FinOps Open Cost & Usage Specification reports, with time-windowed filenames to prevent overwrites - [PR #23333](https://github.com/BerriAI/litellm/pull/23333) + +- **General** + - Fix silent metrics race condition causing metric collision across experiments - [PR #23542](https://github.com/BerriAI/litellm/pull/23542) + +### Guardrails + +No major guardrail changes in this release. + +### Prompt Management + +No major prompt management changes in this release. + +### Secret Managers + +No major secret manager changes in this release. + +--- + +## Performance / Loadbalancing / Reliability improvements + +- **Fix streaming crashes after ~1 hour** — `LLMClientCache._remove_key()` no longer calls `close()`/`aclose()` on evicted HTTP/SDK clients. In-flight requests were crashing with `RuntimeError: Cannot send a request, as the client has been closed.` after the 1-hour TTL expired. Cleanup now happens only at shutdown via `close_litellm_async_clients()` - [PR #22926](https://github.com/BerriAI/litellm/pull/22926) +- **Fix OOM / Prisma connection loss** on large installs — unbounded managed-object poll was exhausting Prisma connections after ~60–70 minutes on instances with 336K+ queued response rows - [PR #23472](https://github.com/BerriAI/litellm/pull/23472) +- **Centralize logging kwarg updates** — root cause fix migrating all logging updates to a single function, eliminating kwarg inconsistencies across logging paths - [PR #23659](https://github.com/BerriAI/litellm/pull/23659) +- **Fix tiktoken cache for non-root offline containers** — tiktoken cache now works correctly in offline environments running as non-root users - [PR #23498](https://github.com/BerriAI/litellm/pull/23498) +- **Add CodSpeed continuous performance benchmarks** — automated performance regression tracking on CI - [PR #23676](https://github.com/BerriAI/litellm/pull/23676) + +--- + +## Security + +- **Secret redaction in proxy logs** — Adds a `SecretRedactionFilter` to all LiteLLM loggers that scrubs API keys, tokens, and credentials from log messages, format args, exception tracebacks, and extra fields. Enabled by default; opt out with `LITELLM_DISABLE_REDACT_SECRETS=true` - [PR #23668](https://github.com/BerriAI/litellm/pull/23668), [PR #23667](https://github.com/BerriAI/litellm/pull/23667) +- **Bump PyJWT to `^2.12.0`** — addresses security vulnerability in `^2.10.1` - [PR #23678](https://github.com/BerriAI/litellm/pull/23678) +- **Bump `tar` to 7.5.11 and `tornado` to 6.5.5** — addresses CVEs in transitive dependencies - [PR #23602](https://github.com/BerriAI/litellm/pull/23602) + +--- + +## Database / Proxy Operations + +- **Fix Prisma migrate deploy on pre-existing instances** — resolved multiple bugs in migration recovery logic: missing return in the P3018 idempotent error handler and unhandled exceptions in `_roll_back_migration` that caused silent failures even after successful recovery - [PR #23655](https://github.com/BerriAI/litellm/pull/23655) +- **Make DB migration failure exit opt-in** — proxy no longer exits on `prisma migrate deploy` failure by default; enable with `--enforce_prisma_migration_check` - [PR #23675](https://github.com/BerriAI/litellm/pull/23675) + +--- + +## New Contributors + +* @ryanh-ai made their first contribution in [PR #21542](https://github.com/BerriAI/litellm/pull/21542) +* @ryan-crabbe made their first contribution in [PR #23668](https://github.com/BerriAI/litellm/pull/23668) +* @Jah-yee made their first contribution in [PR #23525](https://github.com/BerriAI/litellm/pull/23525) +* @gambletan made their first contribution in [PR #23516](https://github.com/BerriAI/litellm/pull/23516) +* @awais786 made their first contribution in [PR #23183](https://github.com/BerriAI/litellm/pull/23183) +* @pradyyadav made their first contribution in [PR #23580](https://github.com/BerriAI/litellm/pull/23580) +* @xianzongxie-stripe made their first contribution in [PR #23492](https://github.com/BerriAI/litellm/pull/23492) +* @Harshit28j made their first contribution in [PR #23333](https://github.com/BerriAI/litellm/pull/23333) +* @codspeed-hq[bot] made their first contribution in [PR #23676](https://github.com/BerriAI/litellm/pull/23676) + +--- + +## Diff Summary + +## 03/16/2026 +* New Providers: 5 +* New Models / Updated Models: 116 new, 132 removed +* LLM API Endpoints: 5 +* Management Endpoints / UI: 11 +* AI Integrations: 2 +* Performance / Reliability: 5 +* Security: 3 +* Database / Proxy Operations: 2 + +--- + +## Full Changelog +[v1.82.0-stable...v1.82.3-stable](https://github.com/BerriAI/litellm/compare/v1.82.0-stable...v1.82.3-stable) diff --git a/provider_endpoints_support.json b/provider_endpoints_support.json index 2f3302bb57..bd677c5bb5 100644 --- a/provider_endpoints_support.json +++ b/provider_endpoints_support.json @@ -471,9 +471,7 @@ "audio_speech": false, "moderations": false, "batches": false, - "rerank": false, - "a2a": false, - "interactions": false + "rerank": false } }, "chutes": { @@ -2554,20 +2552,21 @@ "rerank": false } }, - "charity_engine": { - "display_name": "Charity Engine (`charity_engine`)", - "url": "https://docs.litellm.ai/docs/providers/charity_engine", + "sagemaker_nova": { + "display_name": "AWS SageMaker Nova (`sagemaker_nova`)", + "url": "https://docs.litellm.ai/docs/providers/aws_sagemaker", "endpoints": { "chat_completions": true, - "messages": true, - "responses": true, + "messages": false, + "responses": false, "embeddings": false, "image_generations": false, "audio_transcriptions": false, "audio_speech": false, "moderations": false, "batches": false, - "rerank": false + "rerank": false, + "a2a": false } } }, From 71db624bfb70c93cb1f502171e75ad70fcd8bd25 Mon Sep 17 00:00:00 2001 From: joereyna Date: Mon, 16 Mar 2026 22:51:07 -0700 Subject: [PATCH 227/289] fix: add interactions: false to sagemaker_nova provider entry --- provider_endpoints_support.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/provider_endpoints_support.json b/provider_endpoints_support.json index bd677c5bb5..d2edb0017f 100644 --- a/provider_endpoints_support.json +++ b/provider_endpoints_support.json @@ -2566,7 +2566,8 @@ "moderations": false, "batches": false, "rerank": false, - "a2a": false + "a2a": false, + "interactions": false } } }, From afd6c4c6246836110517bc5d37647359b9baef99 Mon Sep 17 00:00:00 2001 From: joereyna Date: Mon, 16 Mar 2026 22:53:01 -0700 Subject: [PATCH 228/289] fix: correct Nebius AI PR link in release notes (22614 not 21542) --- docs/my-website/release_notes/v1.82.3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/my-website/release_notes/v1.82.3.md b/docs/my-website/release_notes/v1.82.3.md index 73e5bbf1f1..44c5cfd85d 100644 --- a/docs/my-website/release_notes/v1.82.3.md +++ b/docs/my-website/release_notes/v1.82.3.md @@ -41,7 +41,7 @@ pip install litellm==1.82.3 ## Key Highlights -- **Nebius AI — new provider** — [30 models across DeepSeek, Qwen, Llama, Mistral, NVIDIA, and BAAI available via Nebius AI cloud](../../docs/providers/nebius) - [PR #21542](https://github.com/BerriAI/litellm/pull/21542) +- **Nebius AI — new provider** — [30 models across DeepSeek, Qwen, Llama, Mistral, NVIDIA, and BAAI available via Nebius AI cloud](../../docs/providers/nebius) - [PR #22614](https://github.com/BerriAI/litellm/pull/22614) - **OpenAI gpt-5.4 / gpt-5.4-pro — day 0** — Full pricing and routing support for `gpt-5.4` (1M context, $2.50/$15.00) and `gpt-5.4-pro` ($30.00/$180.00) on OpenAI and Azure - **Gemini 3.x models** — `gemini-3-flash-preview`, `gemini-3.1-pro-preview`, `gemini-3.1-flash-image-preview`, and `gemini-embedding-2-preview` added to cost map for Google AI and Vertex AI - **FLUX Kontext image editing** — `flux-kontext-pro` and `flux-kontext-max` added to Black Forest Labs, alongside `flux-pro-1.0-fill` and `flux-pro-1.0-expand` for inpainting and outpainting From 1c90d92bf5acb4d5f90a565b56862272aa454316 Mon Sep 17 00:00:00 2001 From: joereyna Date: Mon, 16 Mar 2026 22:58:53 -0700 Subject: [PATCH 229/289] fix: update ZAI docs link to dedicated provider page --- docs/my-website/release_notes/v1.82.3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/my-website/release_notes/v1.82.3.md b/docs/my-website/release_notes/v1.82.3.md index 44c5cfd85d..15df33fdb8 100644 --- a/docs/my-website/release_notes/v1.82.3.md +++ b/docs/my-website/release_notes/v1.82.3.md @@ -59,7 +59,7 @@ pip install litellm==1.82.3 | Provider | Supported LiteLLM Endpoints | Description | | -------- | --------------------------- | ----------- | | [Nebius AI](../../docs/providers/nebius) (`nebius/`) | `/chat/completions`, `/embeddings` | EU-based AI cloud with 30+ open models — DeepSeek, Qwen3, Llama 3.1/3.3, NVIDIA Nemotron, BAAI embeddings | -| [ZAI](../../docs/providers/openai_compatible) (`zai/`) | `/chat/completions` | ZhipuAI GLM-5 models via ZAI cloud | +| [ZAI](../../docs/providers/zai) (`zai/`) | `/chat/completions` | ZhipuAI GLM-5 models via ZAI cloud | | [Black Forest Labs](../../docs/providers/black_forest_labs) (`black_forest_labs/`) | `/images/generations`, `/images/edits` | FLUX image generation and editing — Kontext Pro/Max, Pro 1.0 Fill/Expand | | [Serper](../../docs/providers/serper) (`serper/`) | `/search` | Web search via Serper API | | [SageMaker Nova](../../docs/providers/aws_sagemaker) (`sagemaker_nova/`) | `/chat/completions` | Amazon Nova models via SageMaker endpoint | From ab4fda2eebbc6e1dbc772e93d4be8c18b58deb8c Mon Sep 17 00:00:00 2001 From: voidborne-d Date: Tue, 17 Mar 2026 08:08:44 +0000 Subject: [PATCH 230/289] fix: add asyncio.Lock to prevent session/connector leak on concurrent recreation When multiple requests detect a closed shared session simultaneously, they would each create a new aiohttp.ClientSession, leaking intermediate sessions and their TCP connectors. Added double-checked locking pattern with asyncio.Lock to ensure only one coroutine recreates the session. Added concurrent recreation test case. --- litellm/proxy/route_llm_request.py | 45 ++++++++++++---- .../proxy/test_aiohttp_session_recovery.py | 51 +++++++++++++++++++ 2 files changed, 85 insertions(+), 11 deletions(-) diff --git a/litellm/proxy/route_llm_request.py b/litellm/proxy/route_llm_request.py index 265a311d39..376bf07f2b 100644 --- a/litellm/proxy/route_llm_request.py +++ b/litellm/proxy/route_llm_request.py @@ -1,3 +1,4 @@ +import asyncio from typing import TYPE_CHECKING, Any, Literal, Optional from fastapi import HTTPException, status @@ -123,11 +124,24 @@ def get_team_id_from_data(data: dict) -> Optional[str]: return None +_shared_session_lock: Optional[asyncio.Lock] = None + + +def _get_shared_session_lock() -> asyncio.Lock: + """Lazily create the shared session lock (must be called within a running event loop).""" + global _shared_session_lock + if _shared_session_lock is None: + _shared_session_lock = asyncio.Lock() + return _shared_session_lock + + async def add_shared_session_to_data(data: dict) -> None: """ Add shared aiohttp session for connection reuse (prevents cold starts). If the session was closed (e.g. due to network interruption or idle timeout), automatically recreates it so connection pooling is restored. + Uses an asyncio.Lock to prevent race conditions where multiple concurrent + requests could each create a new session, leaking intermediate ones. Silently continues without session reuse if import fails or session is unavailable. Args: @@ -146,23 +160,32 @@ async def add_shared_session_to_data(data: dict) -> None: ) elif session is not None and session.closed: # Session was created at startup but has since closed — recreate it - verbose_proxy_logger.warning( - f"SESSION REUSE: Shared aiohttp session is closed (ID: {id(session)}), recreating..." - ) - new_session = await proxy_server._initialize_shared_aiohttp_session() - if new_session is not None: - proxy_server.shared_aiohttp_session = new_session - data["shared_session"] = new_session - else: - verbose_proxy_logger.info( - "SESSION REUSE: Failed to recreate shared session, continuing without session reuse" + # Use lock to prevent concurrent recreation (avoids session/connector leak) + lock = _get_shared_session_lock() + async with lock: + # Double-check under lock — another coroutine may have already recreated it + session = proxy_server.shared_aiohttp_session + if session is not None and not session.closed: + data["shared_session"] = session + return + + verbose_proxy_logger.warning( + f"SESSION REUSE: Shared aiohttp session is closed (ID: {id(session)}), recreating..." ) + new_session = await proxy_server._initialize_shared_aiohttp_session() + if new_session is not None: + proxy_server.shared_aiohttp_session = new_session + data["shared_session"] = new_session + else: + verbose_proxy_logger.info( + "SESSION REUSE: Failed to recreate shared session, continuing without session reuse" + ) else: verbose_proxy_logger.info( "SESSION REUSE: No shared session available for this request" ) except Exception: - # Silently continue without session reuse if import fails or session unavailable + # Silently continue without session reuse if import fails or session is unavailable pass diff --git a/tests/test_litellm/proxy/test_aiohttp_session_recovery.py b/tests/test_litellm/proxy/test_aiohttp_session_recovery.py index e87ca5a163..b71a61d2c2 100644 --- a/tests/test_litellm/proxy/test_aiohttp_session_recovery.py +++ b/tests/test_litellm/proxy/test_aiohttp_session_recovery.py @@ -97,3 +97,54 @@ async def test_add_shared_session_no_session_available(): data = {} await add_shared_session_to_data(data) assert "shared_session" not in data + + +@pytest.mark.asyncio +async def test_add_shared_session_concurrent_recreation_uses_lock(): + """When multiple coroutines detect a closed session concurrently, + only one should recreate it (double-checked locking via asyncio.Lock).""" + import litellm.proxy.route_llm_request as route_module + from litellm.proxy import proxy_server as proxy_server_module + from litellm.proxy.route_llm_request import add_shared_session_to_data + + # Reset the module-level lock so each test is isolated + route_module._shared_session_lock = None + + closed_session = MagicMock() + closed_session.closed = True + + new_session = MagicMock() + new_session.closed = False + + call_count = 0 + + async def mock_init(): + nonlocal call_count + call_count += 1 + # Simulate some async work + await asyncio.sleep(0.01) + proxy_server_module.shared_aiohttp_session = new_session + return new_session + + with patch.object( + proxy_server_module, + "shared_aiohttp_session", + closed_session, + ): + with patch.object( + proxy_server_module, + "_initialize_shared_aiohttp_session", + side_effect=mock_init, + ): + # Launch 5 concurrent calls + results = [{} for _ in range(5)] + await asyncio.gather( + *(add_shared_session_to_data(d) for d in results) + ) + + # Only 1 coroutine should have called _initialize (the rest see the + # re-checked session as open under the lock) + assert call_count == 1, f"Expected 1 init call, got {call_count}" + # All should have the new session + for d in results: + assert d.get("shared_session") is new_session From 9e09bbc1dfbccc551a8898ab3268a1014c7c81d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?d=20=F0=9F=94=B9?= <258577966+voidborne-d@users.noreply.github.com> Date: Tue, 17 Mar 2026 09:54:01 +0000 Subject: [PATCH 231/289] fix: reset _shared_session_lock in all tests for event loop isolation Address Greptile P1 review: tests that exercise the closed-session code path need to reset the module-level lock to avoid RuntimeError on Python < 3.10 when asyncio.Lock is reused across different event loops. --- tests/test_litellm/proxy/test_aiohttp_session_recovery.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test_litellm/proxy/test_aiohttp_session_recovery.py b/tests/test_litellm/proxy/test_aiohttp_session_recovery.py index b71a61d2c2..763744609e 100644 --- a/tests/test_litellm/proxy/test_aiohttp_session_recovery.py +++ b/tests/test_litellm/proxy/test_aiohttp_session_recovery.py @@ -33,9 +33,13 @@ async def test_add_shared_session_attaches_open_session(): @pytest.mark.asyncio async def test_add_shared_session_recreates_closed_session(): """When the shared session is closed, it should be recreated.""" + import litellm.proxy.route_llm_request as route_module from litellm.proxy import proxy_server as proxy_server_module from litellm.proxy.route_llm_request import add_shared_session_to_data + # Reset the module-level lock so each test uses the current event loop + route_module._shared_session_lock = None + closed_session = MagicMock() closed_session.closed = True @@ -64,9 +68,13 @@ async def test_add_shared_session_recreates_closed_session(): @pytest.mark.asyncio async def test_add_shared_session_handles_recreation_failure(): """When recreation fails, data should not contain shared_session.""" + import litellm.proxy.route_llm_request as route_module from litellm.proxy import proxy_server as proxy_server_module from litellm.proxy.route_llm_request import add_shared_session_to_data + # Reset the module-level lock so each test uses the current event loop + route_module._shared_session_lock = None + closed_session = MagicMock() closed_session.closed = True From d2ea8c15e3648760142d91cc771f44ac5fe1bea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mr=2E=20=C3=85nand?= <73425223+Astrodevil@users.noreply.github.com> Date: Tue, 17 Mar 2026 17:41:58 +0530 Subject: [PATCH 232/289] docs: sidebar QA fixes and index updates - Fix duplicate docs: RBAC and MCP Troubleshooting cross-links in secondary positions - Add observability_index for Integrations - Update guides, integrations, learn, tutorials index pages Made-with: Cursor --- docs/my-website/docs/guides/index.md | 70 ++++--- docs/my-website/docs/integrations/index.md | 34 ++-- .../docs/integrations/observability_index.md | 28 +++ docs/my-website/docs/learn/index.md | 152 ++++++-------- docs/my-website/docs/tutorials/index.md | 76 +++---- docs/my-website/sidebars.js | 192 ++++++++++++------ 6 files changed, 310 insertions(+), 242 deletions(-) create mode 100644 docs/my-website/docs/integrations/observability_index.md diff --git a/docs/my-website/docs/guides/index.md b/docs/my-website/docs/guides/index.md index 4818f08b5b..294bdf1412 100644 --- a/docs/my-website/docs/guides/index.md +++ b/docs/my-website/docs/guides/index.md @@ -11,48 +11,56 @@ import NavigationCards from '@site/src/components/NavigationCards'; --- -## Model Configuration +## Core Features --- -## Security & Networking +## Configuration & Cost - ---- - -## AI Capabilities - - +/> \ No newline at end of file diff --git a/docs/my-website/docs/integrations/index.md b/docs/my-website/docs/integrations/index.md index 0134fdc4df..67e087a976 100644 --- a/docs/my-website/docs/integrations/index.md +++ b/docs/my-website/docs/integrations/index.md @@ -20,60 +20,60 @@ items={[ icon: "🪢", title: "Langfuse", description: "LLM observability and analytics.", - to: "../observability/langfuse_integration", + to: "/docs/observability/langfuse_integration", }, { icon: "🐶", title: "Datadog", description: "Metrics, traces, and dashboards.", - to: "../observability/datadog", + to: "/docs/observability/datadog", }, { icon: "📡", title: "OpenTelemetry", description: "Vendor-neutral tracing.", - to: "../observability/opentelemetry_integration", + to: "/docs/observability/opentelemetry_integration", }, { icon: "🔗", title: "LangSmith", description: "LLM debugging and evaluation.", - to: "../observability/langsmith_integration", + to: "/docs/observability/langsmith_integration", }, { icon: "🔥", title: "Arize / Phoenix", description: "ML observability and evaluation.", - to: "../observability/arize_integration", + to: "/docs/observability/arize_integration", }, { icon: "🌀", title: "Helicone", description: "LLM request logging and analytics.", - to: "../observability/helicone_integration", + to: "/docs/observability/helicone_integration", }, { icon: "📊", title: "MLflow", description: "Experiment tracking.", - to: "../observability/mlflow", + to: "/docs/observability/mlflow", }, { icon: "🏋️", title: "Weights & Biases", description: "ML experiment tracking.", - to: "../observability/wandb_integration", + to: "/docs/observability/wandb_integration", }, { icon: "📉", title: "PostHog", description: "Product analytics.", - to: "../observability/posthog_integration", + to: "/docs/observability/posthog_integration", }, ]} /> -[View all observability integrations →](../observability/callbacks.md) +[View all observability integrations →](/docs/observability_integrations) --- @@ -124,42 +124,42 @@ items={[ icon: "🛡️", title: "Lakera AI", description: "Prompt injection detection.", - to: "../proxy/guardrails/lakera_ai", + to: "/docs/proxy/guardrails/lakera_ai", }, { icon: "☁️", title: "Azure Content Safety", description: "Content moderation.", - to: "../proxy/guardrails/azure_content_guardrail", + to: "/docs/proxy/guardrails/azure_content_guardrail", }, { icon: "🛏️", title: "Bedrock Guardrails", description: "AWS Bedrock safety.", - to: "../proxy/guardrails/bedrock", + to: "/docs/proxy/guardrails/bedrock", }, { icon: "🤖", title: "OpenAI Moderation", description: "OpenAI content policy.", - to: "../proxy/guardrails/openai_moderation", + to: "/docs/proxy/guardrails/openai_moderation", }, { icon: "🔐", title: "Secret Detection", description: "Prevent credential leaks.", - to: "../proxy/guardrails/secret_detection", + to: "/docs/proxy/guardrails/secret_detection", }, { icon: "🕵️", title: "PII Masking", description: "Mask sensitive data.", - to: "../proxy/guardrails/pii_masking_v2", + to: "/docs/proxy/guardrails/pii_masking_v2", }, ]} /> -[View all guardrail providers →](../proxy/guardrails/quick_start.md) +[View all guardrail providers →](/docs/guardrail_providers) --- diff --git a/docs/my-website/docs/integrations/observability_index.md b/docs/my-website/docs/integrations/observability_index.md new file mode 100644 index 0000000000..8ab83950cd --- /dev/null +++ b/docs/my-website/docs/integrations/observability_index.md @@ -0,0 +1,28 @@ +--- +title: Observability +sidebar_label: Overview +slug: observability_integrations +--- + +Track, debug, and analyze LLM calls with observability platforms. + +import NavigationCards from '@site/src/components/NavigationCards'; + +## Observability Integrations + + + +[View all observability integrations →](/docs/observability/callbacks) diff --git a/docs/my-website/docs/learn/index.md b/docs/my-website/docs/learn/index.md index 95f4251951..bb8ffe851e 100644 --- a/docs/my-website/docs/learn/index.md +++ b/docs/my-website/docs/learn/index.md @@ -10,12 +10,12 @@ LiteLLM gives you a single OpenAI-compatible interface to 100+ LLM providers. Us --- -## 1. Make Your First Call +## Get Started -Set up your environment and call your first model. +Set up your environment and make your first LLM call. +[View all getting started tutorials →](/docs/tutorials/getting_started) + --- -## 2. Connect Your Tools +## Guides -Point your existing tools and frameworks at LiteLLM. +Focused references for SDK features and proxy configuration. Each guide is self-contained. + +[View all guides →](/docs/guides) + +--- + +## Tutorials + +Step-by-step walkthroughs for integrating LiteLLM with external tools and services. + + +[View all tutorials →](/docs/tutorials) + --- -## 3. Configure LiteLLM +## Production -Learn how specific SDK features and proxy options work. - - - ---- - -## 4. Run in Production - -Add observability, access control, and safety to your deployment. - - +Add observability, access control, and safety to your deployment. See the [Production section](/docs/tutorials#production) in Tutorials for Observability & Safety, Proxy & Gateway, and more. diff --git a/docs/my-website/docs/tutorials/index.md b/docs/my-website/docs/tutorials/index.md index b8bf4f76eb..1d32ae5a94 100644 --- a/docs/my-website/docs/tutorials/index.md +++ b/docs/my-website/docs/tutorials/index.md @@ -18,73 +18,75 @@ columns={2} items={[ { icon: "⚡", - title: "Set Up Your Environment", - description: "Get your API keys for OpenAI, Cohere, and AI21 — no waitlist required — and configure your environment before making your first LLM call.", - to: "/docs/tutorials/installation", - }, - { - icon: "🧪", - title: "Build an LLM Playground", - description: "Create a Streamlit playground to evaluate and compare multiple LLM providers side by side in under 10 minutes.", - to: "/docs/tutorials/first_playground", + title: "Getting Started", + description: "Installation, playground, text completion, and mock completions.", + to: "/docs/tutorials/getting_started", }, ]} /> --- -## Browse All Tutorials +## Integrations + +--- + +## Production + + + +--- + +## Advanced Features + + diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index bb77a3cc7c..b64291ac1d 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -25,6 +25,7 @@ const sidebars = { { type: "category", label: "Observability", + link: { type: "doc", id: "integrations/observability_index" }, items: [ { type: "category", @@ -34,17 +35,23 @@ const sidebars = { type: "autogenerated", dirName: "contribute_integration" } - ] + ], }, { type: "autogenerated", dirName: "observability" - } + }, ], }, { type: "category", label: "Guardrail Providers", + link: { + type: "generated-index", + title: "Guardrail Providers", + description: "Add safety and content filtering to LLM calls", + slug: "/guardrail_providers" + }, items: [ ...[ "proxy/guardrails/qualifire", @@ -161,6 +168,8 @@ const sidebars = { "tutorials/copilotkit_sdk", "tutorials/google_adk", "tutorials/livekit_xai_realtime", + { type: "doc", id: "tutorials/instructor", label: "Instructor with LiteLLM" }, + { type: "doc", id: "langchain/langchain", label: "LangChain with LiteLLM" }, "projects/openai-agents" ] }, @@ -305,7 +314,11 @@ const sidebars = { "mcp_control", "mcp_cost", "mcp_guardrail", - "mcp_troubleshoot", + { + type: "link", + label: "MCP Troubleshooting Guide →", + href: "/docs/mcp_troubleshoot" + }, ], }, ], @@ -367,7 +380,11 @@ const sidebars = { type: "category", label: "Teams & Organizations", items: [ - "proxy/access_control", + { + type: "link", + label: "Role-based Access Controls (RBAC) →", + href: "/docs/proxy/access_control" + }, "proxy/self_serve", "proxy/public_teams", "proxy/ui_project_management", @@ -462,7 +479,7 @@ const sidebars = { { type: "link", label: "Providers →", - href: "/docs/integrations#guardrail-providers", + href: "/docs/guardrail_providers", }, { type: "category", @@ -1134,45 +1151,77 @@ const learnSidebar = { items: [ { type: "category", - label: "Completion & Messaging", + label: "Completion Basics", collapsible: true, collapsed: false, + link: { + type: "generated-index", + title: "Completion Basics", + description: "Streaming, function calling, JSON mode, vision, audio, and more", + slug: "/guides/completion_basics" + }, items: [ "completion/stream", "completion/function_call", "completion/json_mode", "completion/vision", "completion/audio", - "completion/document_understanding", - "completion/image_generation_chat", "completion/batching", "completion/prefix", "completion/predict_outputs", "completion/provider_specific_params", "reasoning_content", - { - type: "category", - label: "Prompt Config", - collapsible: true, - collapsed: true, - items: [ - "completion/prompt_caching", - "completion/prompt_formatting", - ], - }, "completion/drop_params", - "completion/message_trimming", - "completion/message_sanitization", "completion/model_alias", "completion/mock_requests", "completion/reliable_completions", ], }, + { + type: "category", + label: "Documents, Images & Messages", + collapsible: true, + collapsed: true, + link: { + type: "generated-index", + title: "Documents, Images & Messages", + description: "Document understanding, image generation, message trimming, and sanitization", + slug: "/guides/input_output_handling" + }, + items: [ + "completion/document_understanding", + "completion/image_generation_chat", + "completion/message_trimming", + "completion/message_sanitization", + ], + }, + { + type: "category", + label: "Prompt Optimization", + collapsible: true, + collapsed: true, + link: { + type: "generated-index", + title: "Prompt Optimization", + description: "Prompt caching and prompt formatting", + slug: "/guides/prompt_optimization" + }, + items: [ + "completion/prompt_caching", + "completion/prompt_formatting", + ], + }, { type: "category", label: "AI Capabilities", collapsible: true, collapsed: true, + link: { + type: "generated-index", + title: "AI Capabilities", + description: "Web search, code interpreter, knowledge base, and more", + slug: "/guides/ai_capabilities" + }, items: [ "completion/web_search", "completion/web_fetch", @@ -1180,22 +1229,40 @@ const learnSidebar = { "completion/knowledgebase", "guides/code_interpreter", "proxy/veo_video_generation", - { type: "doc", id: "rag_ingest", label: "RAG Ingest" }, - { type: "doc", id: "rag_query", label: "RAG Query" }, ], }, { type: "category", - label: "Models & Customization", + label: "Models & Configuration", collapsible: true, collapsed: true, + link: { + type: "generated-index", + title: "Models & Configuration", + description: "Fine-tuned models, security settings, and adapters", + slug: "/guides/models_configuration" + }, items: [ "guides/finetuned_models", "guides/security_settings", - "budget_manager", "extras/creating_adapters", ], }, + { + type: "category", + label: "Budgets & Cost", + collapsible: true, + collapsed: true, + link: { + type: "generated-index", + title: "Budgets & Cost", + description: "Set spend limits and track costs", + slug: "/guides/budgets_cost" + }, + items: [ + "budget_manager", + ], + }, ], }, @@ -1211,64 +1278,39 @@ const learnSidebar = { type: "category", label: "Getting Started", collapsed: false, + link: { + type: "generated-index", + title: "Getting Started", + description: "Installation, playground, text completion, and mock completions", + slug: "/tutorials/getting_started" + }, items: [ - "tutorials/first_playground", "tutorials/installation", + "tutorials/first_playground", "tutorials/text_completion", "tutorials/mock_completion", ], }, { - type: "category", + type: "link", label: "Agent SDKs & Frameworks", - collapsed: true, - items: [ - "tutorials/openai_agents_sdk", - "tutorials/claude_agent_sdk", - "tutorials/copilotkit_sdk", - "tutorials/google_adk", - "tutorials/livekit_xai_realtime", - { type: "doc", id: "tutorials/instructor", label: "Instructor with LiteLLM" }, - { type: "doc", id: "langchain/langchain", label: "LangChain with LiteLLM" }, - ], + href: "/docs/agent_sdks", }, { - type: "category", + type: "link", label: "AI Coding Tools", - collapsed: true, - items: [ - "tutorials/openweb_ui", - { - type: "category", - label: "Claude Code", - collapsed: true, - items: [ - "tutorials/claude_responses_api", - "tutorials/claude_code_max_subscription", - "tutorials/claude_code_customer_tracking", - "tutorials/claude_code_prompt_cache_routing", - "tutorials/claude_code_websearch", - "tutorials/claude_mcp", - "tutorials/claude_non_anthropic_models", - "tutorials/claude_code_plugin_marketplace", - "tutorials/claude_code_beta_headers", - ], - }, - "tutorials/cursor_integration", - "tutorials/github_copilot_integration", - "tutorials/opencode_integration", - "tutorials/openclaw_integration", - "tutorials/cost_tracking_coding", - "tutorials/litellm_gemini_cli", - "tutorials/litellm_qwen_code_cli", - "tutorials/openai_codex", - "tutorials/google_genai_sdk", - ], + href: "/docs/ai_tools", }, { type: "category", label: "Provider Tutorials", collapsed: true, + link: { + type: "generated-index", + title: "Provider Tutorials", + description: "Set up Azure OpenAI, HuggingFace, TogetherAI, local models, and more", + slug: "/tutorials/provider_tutorials" + }, items: [ "tutorials/azure_openai", "tutorials/TogetherAI_liteLLM", @@ -1285,6 +1327,12 @@ const learnSidebar = { type: "category", label: "Proxy & Gateway", collapsed: true, + link: { + type: "generated-index", + title: "Proxy & Gateway", + description: "Access control, SSO, SCIM, tag management, and prompt caching", + slug: "/tutorials/proxy_gateway" + }, items: [ "tutorials/default_team_self_serve", "tutorials/msft_sso", @@ -1298,6 +1346,12 @@ const learnSidebar = { type: "category", label: "Observability & Safety", collapsed: true, + link: { + type: "generated-index", + title: "Observability & Safety", + description: "Logging, guardrails, PII masking, and evaluation suites", + slug: "/tutorials/observability_safety" + }, items: [ "tutorials/elasticsearch_logging", "tutorials/litellm_proxy_aporia", @@ -1310,6 +1364,12 @@ const learnSidebar = { type: "category", label: "Advanced Features", collapsed: true, + link: { + type: "generated-index", + title: "Advanced Features", + description: "Model fallbacks, provider-specific params, and realtime audio", + slug: "/tutorials/advanced_features" + }, items: [ "tutorials/model_fallbacks", "tutorials/fallbacks", From 32ecd241168c57fcc1de28c75b3cb72524af8ea2 Mon Sep 17 00:00:00 2001 From: d Date: Tue, 17 Mar 2026 13:09:26 +0000 Subject: [PATCH 233/289] fix: address P2 review feedback - exception handling and warning accuracy - Add try/except around _initialize_shared_aiohttp_session call to catch and log exceptions (instead of letting them bubble to outer handler) - Fix warning message when re-checked session is None (was incorrectly logging closed session ID on a None session) - Add debug logging to outer except handler instead of bare pass - Add test for _initialize_shared_aiohttp_session raising exception --- litellm/proxy/route_llm_request.py | 35 +++++++++++++++---- .../proxy/test_aiohttp_session_recovery.py | 30 ++++++++++++++++ 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/litellm/proxy/route_llm_request.py b/litellm/proxy/route_llm_request.py index 376bf07f2b..96e6f705cc 100644 --- a/litellm/proxy/route_llm_request.py +++ b/litellm/proxy/route_llm_request.py @@ -169,10 +169,23 @@ async def add_shared_session_to_data(data: dict) -> None: data["shared_session"] = session return - verbose_proxy_logger.warning( - f"SESSION REUSE: Shared aiohttp session is closed (ID: {id(session)}), recreating..." - ) - new_session = await proxy_server._initialize_shared_aiohttp_session() + # session could be None here (if another coroutine set it to None) + # or closed — either way we need to recreate + if session is not None: + verbose_proxy_logger.warning( + f"SESSION REUSE: Shared aiohttp session is closed (ID: {id(session)}), recreating..." + ) + else: + verbose_proxy_logger.warning( + "SESSION REUSE: Shared aiohttp session is None after re-check, recreating..." + ) + try: + new_session = await proxy_server._initialize_shared_aiohttp_session() + except Exception: + verbose_proxy_logger.exception( + "SESSION REUSE: Exception during shared session recreation" + ) + new_session = None if new_session is not None: proxy_server.shared_aiohttp_session = new_session data["shared_session"] = new_session @@ -185,8 +198,18 @@ async def add_shared_session_to_data(data: dict) -> None: "SESSION REUSE: No shared session available for this request" ) except Exception: - # Silently continue without session reuse if import fails or session is unavailable - pass + # Continue without session reuse — this outer handler covers import failures + # and other unexpected errors to avoid breaking the request path. + # Inner recovery logic has its own specific exception handling. + try: + from litellm._logging import verbose_proxy_logger + + verbose_proxy_logger.debug( + "SESSION REUSE: Unexpected error in session setup, continuing without reuse", + exc_info=True, + ) + except Exception: + pass async def route_request( # noqa: PLR0915 - Complex routing function, refactoring tracked separately diff --git a/tests/test_litellm/proxy/test_aiohttp_session_recovery.py b/tests/test_litellm/proxy/test_aiohttp_session_recovery.py index 763744609e..224a4aa139 100644 --- a/tests/test_litellm/proxy/test_aiohttp_session_recovery.py +++ b/tests/test_litellm/proxy/test_aiohttp_session_recovery.py @@ -94,6 +94,36 @@ async def test_add_shared_session_handles_recreation_failure(): assert "shared_session" not in data +@pytest.mark.asyncio +async def test_add_shared_session_handles_recreation_exception(): + """When _initialize_shared_aiohttp_session raises, data should not contain shared_session.""" + import litellm.proxy.route_llm_request as route_module + from litellm.proxy import proxy_server as proxy_server_module + from litellm.proxy.route_llm_request import add_shared_session_to_data + + # Reset the module-level lock so each test uses the current event loop + route_module._shared_session_lock = None + + closed_session = MagicMock() + closed_session.closed = True + + with patch.object( + proxy_server_module, + "shared_aiohttp_session", + closed_session, + ): + with patch.object( + proxy_server_module, + "_initialize_shared_aiohttp_session", + new_callable=AsyncMock, + side_effect=RuntimeError("connection pool exhausted"), + ): + data = {} + await add_shared_session_to_data(data) + # Should gracefully handle exception — no shared_session attached + assert "shared_session" not in data + + @pytest.mark.asyncio async def test_add_shared_session_no_session_available(): """When no session was ever created, data should not contain shared_session.""" From 467706ea301a367d92e8957a01b1d3a978c418d5 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 17 Mar 2026 08:58:07 -0700 Subject: [PATCH 234/289] Revert "fix: langfuse trace leak key on model params" --- litellm/integrations/langfuse/langfuse.py | 25 +++-------------- litellm/litellm_core_utils/litellm_logging.py | 28 +++++++++---------- 2 files changed, 17 insertions(+), 36 deletions(-) diff --git a/litellm/integrations/langfuse/langfuse.py b/litellm/integrations/langfuse/langfuse.py index 29038786d0..6ac337d99a 100644 --- a/litellm/integrations/langfuse/langfuse.py +++ b/litellm/integrations/langfuse/langfuse.py @@ -25,7 +25,6 @@ from litellm.litellm_core_utils.core_helpers import ( reconstruct_model_name, filter_exceptions_from_params, ) -from litellm.litellm_core_utils.model_param_helper import ModelParamHelper from litellm.litellm_core_utils.redact_messages import redact_user_api_key_info from litellm.integrations.langfuse.langfuse_mock_client import ( create_mock_langfuse_client, @@ -292,6 +291,8 @@ class LangFuseLogger: functions = optional_params.pop("functions", None) tools = optional_params.pop("tools", None) + # Remove secret_fields to prevent leaking sensitive data (e.g., authorization headers) + optional_params.pop("secret_fields", None) if functions is not None: prompt["functions"] = functions if tools is not None: @@ -504,18 +505,13 @@ class LangFuseLogger: kwargs.get("model", ""), custom_llm_provider, metadata ) - # Use whitelisted model parameters to prevent leaking secrets - sanitized_model_params = ModelParamHelper.get_standard_logging_model_parameters( - optional_params - ) - trace.generation( CreateGeneration( name=metadata.get("generation_name", "litellm-completion"), startTime=start_time, endTime=end_time, model=model_name, - modelParameters=sanitized_model_params, + modelParameters=optional_params, prompt=input, completion=output, usage={ @@ -835,26 +831,13 @@ class LangFuseLogger: kwargs.get("model", ""), custom_llm_provider, metadata ) - # Use whitelisted model_parameters from StandardLoggingPayload - # to prevent leaking secrets (api_key, auth headers, etc.) - if standard_logging_object is not None: - sanitized_model_params = standard_logging_object.get( - "model_parameters", optional_params - ) - else: - sanitized_model_params = ( - ModelParamHelper.get_standard_logging_model_parameters( - optional_params - ) - ) - generation_params = { "name": generation_name, "id": clean_metadata.pop("generation_id", generation_id), "start_time": start_time, "end_time": end_time, "model": model_name, - "model_parameters": sanitized_model_params, + "model_parameters": optional_params, "input": input if not mask_input else "redacted-by-litellm", "output": output if not mask_output else "redacted-by-litellm", "usage": usage, diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index 5c7ca00fee..a92f4cb9ec 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -5569,23 +5569,21 @@ def scrub_sensitive_keys_in_metadata(litellm_params: Optional[dict]): litellm_params["_langfuse_masking_function"] = masking_fn litellm_params["metadata"] = metadata - ## remove sensitive logging/callback keys from metadata dicts - ## these contain credentials (langfuse_secret_key, langfuse_public_key, etc.) - _sensitive_keys = {"logging", "callback_settings"} - - for metadata_field in ( - "user_api_key_metadata", - "user_api_key_auth_metadata", - "user_api_key_team_metadata", + ## check user_api_key_metadata for sensitive logging keys + cleaned_user_api_key_metadata = {} + if "user_api_key_metadata" in metadata and isinstance( + metadata["user_api_key_metadata"], dict ): - if metadata_field in metadata and isinstance(metadata[metadata_field], dict): - for sensitive_key in _sensitive_keys: - metadata[metadata_field].pop(sensitive_key, None) + for k, v in metadata["user_api_key_metadata"].items(): + if k == "logging": # prevent logging user logging keys + cleaned_user_api_key_metadata[k] = ( + "scrubbed_by_litellm_for_sensitive_keys" + ) + else: + cleaned_user_api_key_metadata[k] = v - ## remove user_api_key_auth entirely - contains full auth object with nested credentials - metadata.pop("user_api_key_auth", None) - - litellm_params["metadata"] = metadata + metadata["user_api_key_metadata"] = cleaned_user_api_key_metadata + litellm_params["metadata"] = metadata return litellm_params From ef22144854f0248163ff9250060ed49afff23bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?d=20=F0=9F=94=B9?= <258577966+voidborne-d@users.noreply.github.com> Date: Tue, 17 Mar 2026 18:07:15 +0000 Subject: [PATCH 235/289] address P2 feedback: add lock docstring warning, remove redundant mock write - Add WARNING docstring to _get_shared_session_lock() about not resetting the lock to None while coroutines may be in the recovery path - Remove redundant proxy_server_module.shared_aiohttp_session assignment in mock_init (add_shared_session_to_data overwrites it synchronously) --- litellm/proxy/route_llm_request.py | 7 ++++++- tests/test_litellm/proxy/test_aiohttp_session_recovery.py | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/litellm/proxy/route_llm_request.py b/litellm/proxy/route_llm_request.py index 96e6f705cc..79e8f41972 100644 --- a/litellm/proxy/route_llm_request.py +++ b/litellm/proxy/route_llm_request.py @@ -128,7 +128,12 @@ _shared_session_lock: Optional[asyncio.Lock] = None def _get_shared_session_lock() -> asyncio.Lock: - """Lazily create the shared session lock (must be called within a running event loop).""" + """Lazily create the shared session lock (must be called within a running event loop). + + WARNING: Do not reset _shared_session_lock to None while any coroutine may be + executing the session-recovery path; doing so breaks the double-checked locking + guarantee and can cause duplicate session creation. + """ global _shared_session_lock if _shared_session_lock is None: _shared_session_lock = asyncio.Lock() diff --git a/tests/test_litellm/proxy/test_aiohttp_session_recovery.py b/tests/test_litellm/proxy/test_aiohttp_session_recovery.py index 224a4aa139..a2b0952796 100644 --- a/tests/test_litellm/proxy/test_aiohttp_session_recovery.py +++ b/tests/test_litellm/proxy/test_aiohttp_session_recovery.py @@ -161,7 +161,6 @@ async def test_add_shared_session_concurrent_recreation_uses_lock(): call_count += 1 # Simulate some async work await asyncio.sleep(0.01) - proxy_server_module.shared_aiohttp_session = new_session return new_session with patch.object( From 3ff4ac3de3fc2fb013ed2ecbe4b5b82304d43fe1 Mon Sep 17 00:00:00 2001 From: Xianzong Xie Date: Tue, 17 Mar 2026 11:21:26 -0700 Subject: [PATCH 236/289] Capture incomplete terminal error in background streaming Committed-By-Agent: codex Co-authored-by: codex --- litellm/proxy/response_polling/background_streaming.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/litellm/proxy/response_polling/background_streaming.py b/litellm/proxy/response_polling/background_streaming.py index 5ec0aac8e2..17ee101549 100644 --- a/litellm/proxy/response_polling/background_streaming.py +++ b/litellm/proxy/response_polling/background_streaming.py @@ -258,8 +258,8 @@ async def background_streaming_task( # noqa: PLR0915 ), ) - # Extract error for failed responses - if event_type == "response.failed": + # Extract error for failed and incomplete responses + if event_type == "response.failed" or event_type == "response.incomplete": terminal_error = response_data.get("error") # Core response fields @@ -337,7 +337,7 @@ async def background_streaming_task( # noqa: PLR0915 ) verbose_proxy_logger.info( - f"Finished background streaming for {polling_id}, status={final_status}, output_items={len(output_items)}" + f"Finished background streaming for {polling_id}, status={final_status}, error={terminal_error}, output_items={len(output_items)}" ) except Exception as e: From bd5c39c4d1da36f6641ce5ea57df9067b93241ee Mon Sep 17 00:00:00 2001 From: Xianzong Xie Date: Tue, 17 Mar 2026 11:35:50 -0700 Subject: [PATCH 237/289] Log incomplete details in background streaming Committed-By-Agent: codex Co-authored-by: codex --- litellm/proxy/response_polling/background_streaming.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litellm/proxy/response_polling/background_streaming.py b/litellm/proxy/response_polling/background_streaming.py index 17ee101549..b4d51814e5 100644 --- a/litellm/proxy/response_polling/background_streaming.py +++ b/litellm/proxy/response_polling/background_streaming.py @@ -337,7 +337,7 @@ async def background_streaming_task( # noqa: PLR0915 ) verbose_proxy_logger.info( - f"Finished background streaming for {polling_id}, status={final_status}, error={terminal_error}, output_items={len(output_items)}" + f"Finished background streaming for {polling_id}, status={final_status}, error={terminal_error}, incomplete_details={incomplete_details_data}, output_items={len(output_items)}" ) except Exception as e: From cb888364867f7d4226c3162b411cea0299d60d0a Mon Sep 17 00:00:00 2001 From: Xianzong Xie Date: Tue, 17 Mar 2026 11:39:12 -0700 Subject: [PATCH 238/289] Add incomplete response error propagation test Committed-By-Agent: codex Co-authored-by: codex --- tests/proxy_unit_tests/test_response_polling_handler.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/proxy_unit_tests/test_response_polling_handler.py b/tests/proxy_unit_tests/test_response_polling_handler.py index 6235dde847..c5f3d7c6f4 100644 --- a/tests/proxy_unit_tests/test_response_polling_handler.py +++ b/tests/proxy_unit_tests/test_response_polling_handler.py @@ -1414,6 +1414,11 @@ class TestBackgroundStreamingTerminalEvents: background_streaming_task, ) + error_payload = { + "type": "incomplete_response", + "message": "The model stopped before producing a complete response", + "code": "max_output_tokens", + } events = [ {"type": "response.in_progress"}, { @@ -1421,6 +1426,7 @@ class TestBackgroundStreamingTerminalEvents: "response": { "id": "resp_123", "status": "incomplete", + "error": error_payload, "incomplete_details": {"reason": "max_output_tokens"}, "usage": {"input_tokens": 10, "output_tokens": 4096}, "model": "gpt-4o", @@ -1442,6 +1448,7 @@ class TestBackgroundStreamingTerminalEvents: final_call = handler.update_state.call_args_list[-1] assert final_call.kwargs["status"] == "incomplete" + assert final_call.kwargs["error"] == error_payload assert final_call.kwargs["incomplete_details"] == {"reason": "max_output_tokens"} assert final_call.kwargs["usage"] == {"input_tokens": 10, "output_tokens": 4096} From ca8f5cffa0051dfb9f607b4f4f7fe925312c9a18 Mon Sep 17 00:00:00 2001 From: voidborne-d Date: Tue, 17 Mar 2026 18:52:57 +0000 Subject: [PATCH 239/289] style: apply black formatting to fix CI lint check --- litellm/proxy/route_llm_request.py | 4 +++- .../proxy/test_aiohttp_session_recovery.py | 12 +++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/litellm/proxy/route_llm_request.py b/litellm/proxy/route_llm_request.py index 79e8f41972..f1590b16c2 100644 --- a/litellm/proxy/route_llm_request.py +++ b/litellm/proxy/route_llm_request.py @@ -185,7 +185,9 @@ async def add_shared_session_to_data(data: dict) -> None: "SESSION REUSE: Shared aiohttp session is None after re-check, recreating..." ) try: - new_session = await proxy_server._initialize_shared_aiohttp_session() + new_session = ( + await proxy_server._initialize_shared_aiohttp_session() + ) except Exception: verbose_proxy_logger.exception( "SESSION REUSE: Exception during shared session recreation" diff --git a/tests/test_litellm/proxy/test_aiohttp_session_recovery.py b/tests/test_litellm/proxy/test_aiohttp_session_recovery.py index a2b0952796..f089d10425 100644 --- a/tests/test_litellm/proxy/test_aiohttp_session_recovery.py +++ b/tests/test_litellm/proxy/test_aiohttp_session_recovery.py @@ -22,9 +22,7 @@ async def test_add_shared_session_attaches_open_session(): mock_session = MagicMock() mock_session.closed = False - with patch( - "litellm.proxy.proxy_server.shared_aiohttp_session", mock_session - ): + with patch("litellm.proxy.proxy_server.shared_aiohttp_session", mock_session): data = {} await add_shared_session_to_data(data) assert data["shared_session"] is mock_session @@ -129,9 +127,7 @@ async def test_add_shared_session_no_session_available(): """When no session was ever created, data should not contain shared_session.""" from litellm.proxy.route_llm_request import add_shared_session_to_data - with patch( - "litellm.proxy.proxy_server.shared_aiohttp_session", None - ): + with patch("litellm.proxy.proxy_server.shared_aiohttp_session", None): data = {} await add_shared_session_to_data(data) assert "shared_session" not in data @@ -175,9 +171,7 @@ async def test_add_shared_session_concurrent_recreation_uses_lock(): ): # Launch 5 concurrent calls results = [{} for _ in range(5)] - await asyncio.gather( - *(add_shared_session_to_data(d) for d in results) - ) + await asyncio.gather(*(add_shared_session_to_data(d) for d in results)) # Only 1 coroutine should have called _initialize (the rest see the # re-checked session as open under the lock) From a51c670f2f759de63ad51736ad0933508c922ba0 Mon Sep 17 00:00:00 2001 From: joereyna Date: Tue, 17 Mar 2026 12:56:25 -0700 Subject: [PATCH 240/289] revert: remove provider_endpoints_support.json changes, docs only --- provider_endpoints_support.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/provider_endpoints_support.json b/provider_endpoints_support.json index d2edb0017f..2f3302bb57 100644 --- a/provider_endpoints_support.json +++ b/provider_endpoints_support.json @@ -471,7 +471,9 @@ "audio_speech": false, "moderations": false, "batches": false, - "rerank": false + "rerank": false, + "a2a": false, + "interactions": false } }, "chutes": { @@ -2552,22 +2554,20 @@ "rerank": false } }, - "sagemaker_nova": { - "display_name": "AWS SageMaker Nova (`sagemaker_nova`)", - "url": "https://docs.litellm.ai/docs/providers/aws_sagemaker", + "charity_engine": { + "display_name": "Charity Engine (`charity_engine`)", + "url": "https://docs.litellm.ai/docs/providers/charity_engine", "endpoints": { "chat_completions": true, - "messages": false, - "responses": false, + "messages": true, + "responses": true, "embeddings": false, "image_generations": false, "audio_transcriptions": false, "audio_speech": false, "moderations": false, "batches": false, - "rerank": false, - "a2a": false, - "interactions": false + "rerank": false } } }, From 26dce15f073016fca6718f2ae69eb4948ab49ee4 Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Wed, 18 Mar 2026 01:46:00 +0530 Subject: [PATCH 241/289] docs: update sidebar structure and enhance guides --- docs/my-website/docs/guides/index.md | 104 +++++++--- .../docs/learn/gateway_quickstart.md | 159 +++++++++++++++ docs/my-website/docs/learn/index.md | 188 +++++++++++------- docs/my-website/docs/learn/sdk_quickstart.md | 137 +++++++++++++ docs/my-website/docs/tutorials/index.md | 30 ++- docs/my-website/sidebars.js | 158 +++++++++------ 6 files changed, 610 insertions(+), 166 deletions(-) create mode 100644 docs/my-website/docs/learn/gateway_quickstart.md create mode 100644 docs/my-website/docs/learn/sdk_quickstart.md diff --git a/docs/my-website/docs/guides/index.md b/docs/my-website/docs/guides/index.md index 294bdf1412..b39234e4c8 100644 --- a/docs/my-website/docs/guides/index.md +++ b/docs/my-website/docs/guides/index.md @@ -5,62 +5,102 @@ sidebar_label: Overview import NavigationCards from '@site/src/components/NavigationCards'; -**Guides** are focused references for specific LiteLLM SDK features and proxy configuration options. Each guide is self-contained — jump to any topic without reading the others first. +**Guides** are focused references organized by the job you are trying to do with LiteLLM: make requests, use tools, handle media, manage context, or operate the gateway safely. -> Looking for step-by-step integration walkthroughs? See [Tutorials →](/docs/tutorials) +> New to LiteLLM or not sure whether you need the SDK or Gateway path first? Start at [Learn →](/docs/learn) --- -## Core Features +## Start Here --- -## Configuration & Cost +## Build With LiteLLM + +--- + +## Operate & Extend + + \ No newline at end of file +/> diff --git a/docs/my-website/docs/learn/gateway_quickstart.md b/docs/my-website/docs/learn/gateway_quickstart.md new file mode 100644 index 0000000000..f29f6e7d48 --- /dev/null +++ b/docs/my-website/docs/learn/gateway_quickstart.md @@ -0,0 +1,159 @@ +--- +title: Gateway Quickstart +sidebar_label: Gateway Quickstart +description: Start LiteLLM Gateway, add models and keys, then connect applications and SDKs to one shared endpoint. +--- + +import NavigationCards from '@site/src/components/NavigationCards'; + +Use this path if you need one shared OpenAI-compatible endpoint for a team or platform. + +If you need a Docker or database-first setup, use the [Docker + Database tutorial](/docs/proxy/docker_quick_start). Otherwise, use the steps below to get to a working request fast. + +## 1. Install The Gateway + +```bash +pip install 'litellm[proxy]' +``` + +## 2. Set One Provider Key + +```bash +export OPENAI_API_KEY="your-api-key" +``` + +## 3. Create `config.yaml` + +```yaml +model_list: + - model_name: gpt-4o-mini + litellm_params: + model: openai/gpt-4o-mini + api_key: os.environ/OPENAI_API_KEY + +general_settings: + master_key: sk-1234 +``` + +## 4. Start The Gateway + +```bash +litellm --config config.yaml +``` + +You should see the proxy start on `http://0.0.0.0:4000`. + +## 5. Send Your First Request + +```bash +curl -X POST 'http://0.0.0.0:4000/chat/completions' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer sk-1234' \ + -d '{ + "model": "gpt-4o-mini", + "messages": [ + {"role": "user", "content": "Hello from LiteLLM Gateway"} + ] + }' +``` + +## 6. Check The Response + +If the request succeeds, the proxy returns `200 OK` with the same OpenAI-style response shape LiteLLM uses in the SDK. + +The assistant text will be in: + +```json +choices[0].message.content +``` + +It looks like this: + +```json +{ + "id": "chatcmpl-abc123", + "object": "chat.completion", + "created": 1677858242, + "model": "gpt-4o-mini", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "Hello! How can I help?" + }, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 12, + "completion_tokens": 9, + "total_tokens": 21 + } +} +``` + +`id`, `created`, token counts, and message text will vary by request. + +## 7. Add Keys And The UI + +If you need virtual keys, spend tracking, or the admin UI, add a database next. + +- Add `database_url` under `general_settings` +- Use [Virtual keys](/docs/proxy/virtual_keys) for key creation and budgets +- Use [Admin UI](/docs/proxy/ui) to manage models and keys +- Use the [Docker + Database tutorial](/docs/proxy/docker_quick_start) if you want a fuller setup + +## 8. Pick Your Next Step + + + +## When To Use The SDK Path Instead + +If you only need to call models from one application and do not need centralized auth or shared infrastructure, start with the [SDK Quickstart](/docs/learn/sdk_quickstart) instead. diff --git a/docs/my-website/docs/learn/index.md b/docs/my-website/docs/learn/index.md index bb8ffe851e..e36ec906f3 100644 --- a/docs/my-website/docs/learn/index.md +++ b/docs/my-website/docs/learn/index.md @@ -6,106 +6,148 @@ slug: /learn import NavigationCards from '@site/src/components/NavigationCards'; -LiteLLM gives you a single OpenAI-compatible interface to 100+ LLM providers. Use this page to find the right starting point for where you are. +LiteLLM gives you one OpenAI-compatible interface for 100+ LLM providers. Start with the path that matches your setup. --- -## Get Started +## Start Here -Set up your environment and make your first LLM call. +Pick one path first. + + + +--- + +## Common Tasks + +Jump to a specific task. + +--- + +## Explore + +Use these when you want examples or tool-specific walkthroughs. + + - -[View all getting started tutorials →](/docs/tutorials/getting_started) - ---- - -## Guides - -Focused references for SDK features and proxy configuration. Each guide is self-contained. - - - -[View all guides →](/docs/guides) - ---- - -## Tutorials - -Step-by-step walkthroughs for integrating LiteLLM with external tools and services. - - -[View all tutorials →](/docs/tutorials) - --- -## Production +## Docs Map -Add observability, access control, and safety to your deployment. See the [Production section](/docs/tutorials#production) in Tutorials for Observability & Safety, Proxy & Gateway, and more. +Use these when you already know the type of doc you want. + + + +Not sure where to start? Use [SDK Quickstart](/docs/learn/sdk_quickstart) for app code or [Gateway Quickstart](/docs/learn/gateway_quickstart) for shared infrastructure. diff --git a/docs/my-website/docs/learn/sdk_quickstart.md b/docs/my-website/docs/learn/sdk_quickstart.md new file mode 100644 index 0000000000..3726f1f22b --- /dev/null +++ b/docs/my-website/docs/learn/sdk_quickstart.md @@ -0,0 +1,137 @@ +--- +title: SDK Quickstart +sidebar_label: SDK Quickstart +description: Make your first LiteLLM SDK call, then jump to the right docs for the next feature you need. +--- + +import NavigationCards from '@site/src/components/NavigationCards'; + +Use this path if you are integrating LiteLLM directly into application code. + +## 1. Install LiteLLM + +```bash +pip install litellm +``` + +## 2. Set Provider Credentials + +Start with one provider and set its environment variables. + +- OpenAI: `OPENAI_API_KEY` +- Anthropic: `ANTHROPIC_API_KEY` +- Azure OpenAI: `AZURE_API_KEY`, `AZURE_API_BASE`, `AZURE_API_VERSION` +- Bedrock: standard AWS credentials +- Vertex AI: `VERTEXAI_PROJECT`, `VERTEXAI_LOCATION` + +If you have not picked a provider yet, browse [all supported providers](/docs/providers). + +## 3. Make Your First Call + +```python +from litellm import completion +import os + +os.environ["OPENAI_API_KEY"] = "your-api-key" + +response = completion( + model="openai/gpt-4o", + messages=[{"role": "user", "content": "Hello, how are you?"}], +) + +print(response.choices[0].message.content) +``` + +## 4. Check The Response + +The line below: + +```python +print(response.choices[0].message.content) +``` + +prints the assistant text, for example: + +```text +Hello! I'm doing well, thanks for asking. +``` + +The full response is an OpenAI-style `ModelResponse` object. It looks like this: + +```json +{ + "id": "chatcmpl-abc123", + "object": "chat.completion", + "created": 1677858242, + "model": "gpt-4o", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "Hello! I'm doing well, thanks for asking." + }, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 13, + "completion_tokens": 12, + "total_tokens": 25 + } +} +``` + +`id`, `created`, token counts, and message text will vary by request. For the full output reference, see [completion output](/docs/completion/output). + +Need more provider examples? See the main [Getting Started](/docs/#quick-start) page. + +## 5. Pick Your Next Step + + + +## When To Use Gateway Instead + +Use LiteLLM Gateway if you need centralized auth, virtual keys, spend tracking, shared logging, or one OpenAI-compatible endpoint for multiple apps. + +[Go to Gateway Quickstart →](/docs/learn/gateway_quickstart) diff --git a/docs/my-website/docs/tutorials/index.md b/docs/my-website/docs/tutorials/index.md index 1d32ae5a94..9c3fc7a35b 100644 --- a/docs/my-website/docs/tutorials/index.md +++ b/docs/my-website/docs/tutorials/index.md @@ -7,7 +7,35 @@ import NavigationCards from '@site/src/components/NavigationCards'; **Tutorials** are step-by-step walkthroughs for integrating LiteLLM with external tools, frameworks, and services — or building complete end-to-end workflows. -> Need help with a specific LiteLLM SDK feature or proxy config? See [Guides →](/docs/guides) +> Need help choosing the right path before you start? See [Learn →](/docs/learn) + +--- + +## Start Here + + --- diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index b64291ac1d..27d7c6b34f 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -17,11 +17,6 @@ const sidebars = { integrationsSidebar: [ { type: "doc", id: "integrations/index" }, { type: "doc", id: "integrations/community" }, - { - type: "doc", - id: "integrations/websearch_interception", - label: "Web Search Integration" - }, { type: "category", label: "Observability", @@ -1140,6 +1135,16 @@ const learnSidebar = { learnSidebar: [ // ── Landing page ────────────────────────────────────────────────── { type: "doc", id: "learn/index", label: "Learn" }, + { + type: "category", + label: "Start Here", + collapsible: true, + collapsed: false, + items: [ + "learn/sdk_quickstart", + "learn/gateway_quickstart", + ], + }, // ── Guides ──────────────────────────────────────────────────────── { @@ -1151,118 +1156,151 @@ const learnSidebar = { items: [ { type: "category", - label: "Completion Basics", + label: "Core Requests", collapsible: true, collapsed: false, link: { type: "generated-index", - title: "Completion Basics", - description: "Streaming, function calling, JSON mode, vision, audio, and more", - slug: "/guides/completion_basics" + title: "Core Requests", + description: "Streaming, batching, structured outputs, and reasoning behavior", + slug: "/guides/core_request_response_patterns" }, items: [ "completion/stream", - "completion/function_call", - "completion/json_mode", - "completion/vision", - "completion/audio", "completion/batching", - "completion/prefix", - "completion/predict_outputs", - "completion/provider_specific_params", + "completion/json_mode", "reasoning_content", - "completion/drop_params", - "completion/model_alias", - "completion/mock_requests", - "completion/reliable_completions", ], }, { type: "category", - label: "Documents, Images & Messages", + label: "Tool Calling", collapsible: true, collapsed: true, link: { type: "generated-index", - title: "Documents, Images & Messages", - description: "Document understanding, image generation, message trimming, and sanitization", - slug: "/guides/input_output_handling" + title: "Tool Calling", + description: "Function calling, web tools, interception patterns, computer use, code interpreter, and tool-call hygiene", + slug: "/guides/tools_integrations" }, items: [ - "completion/document_understanding", - "completion/image_generation_chat", - "completion/message_trimming", + "completion/function_call", + "completion/web_search", + { + type: "doc", + id: "integrations/websearch_interception", + label: "Web Search Interception", + }, + "completion/web_fetch", + "completion/computer_use", + "guides/code_interpreter", "completion/message_sanitization", ], }, { type: "category", - label: "Prompt Optimization", + label: "Multimodal I/O", collapsible: true, collapsed: true, link: { type: "generated-index", - title: "Prompt Optimization", - description: "Prompt caching and prompt formatting", - slug: "/guides/prompt_optimization" + title: "Multimodal I/O", + description: "Vision, audio, PDFs, image generation, and video generation", + slug: "/guides/multimodal_io" }, items: [ + "completion/vision", + "completion/audio", + "completion/document_understanding", + "completion/image_generation_chat", + "proxy/veo_video_generation", + ], + }, + { + type: "category", + label: "Retrieval & Knowledge", + collapsible: true, + collapsed: true, + link: { + type: "generated-index", + title: "Retrieval & Knowledge", + description: "Vector stores, file search, citations, and knowledge-base routing", + slug: "/guides/retrieval_knowledge" + }, + items: [ + "completion/knowledgebase", + ], + }, + { + type: "category", + label: "Prompts & Context", + collapsible: true, + collapsed: true, + link: { + type: "generated-index", + title: "Prompts & Context", + description: "Prompt caching, trimming, formatting, assistant prefill, and predicted outputs", + slug: "/guides/prompts_context" + }, + items: [ + "completion/prefix", + "completion/predict_outputs", + "completion/message_trimming", "completion/prompt_caching", "completion/prompt_formatting", ], }, { type: "category", - label: "AI Capabilities", + label: "Compatibility & Extensibility", collapsible: true, collapsed: true, link: { type: "generated-index", - title: "AI Capabilities", - description: "Web search, code interpreter, knowledge base, and more", - slug: "/guides/ai_capabilities" - }, - items: [ - "completion/web_search", - "completion/web_fetch", - "completion/computer_use", - "completion/knowledgebase", - "guides/code_interpreter", - "proxy/veo_video_generation", - ], - }, - { - type: "category", - label: "Models & Configuration", - collapsible: true, - collapsed: true, - link: { - type: "generated-index", - title: "Models & Configuration", - description: "Fine-tuned models, security settings, and adapters", - slug: "/guides/models_configuration" + title: "Compatibility & Extensibility", + description: "Provider-specific params, model aliases, fine-tuned models, and adapters", + slug: "/guides/compatibility_extensibility" }, items: [ + "completion/provider_specific_params", + "completion/drop_params", + "completion/model_alias", "guides/finetuned_models", - "guides/security_settings", "extras/creating_adapters", ], }, { type: "category", - label: "Budgets & Cost", + label: "Reliability, Testing & Spend", collapsible: true, collapsed: true, link: { type: "generated-index", - title: "Budgets & Cost", - description: "Set spend limits and track costs", - slug: "/guides/budgets_cost" + title: "Reliability, Testing & Spend", + description: "Retries, fallbacks, mock responses, and budget controls", + slug: "/guides/reliability_testing_spend" }, items: [ + "completion/mock_requests", + "completion/reliable_completions", "budget_manager", ], }, + { + type: "category", + label: "Security & Network", + collapsible: true, + collapsed: true, + link: { + type: "generated-index", + title: "Security & Network", + description: "SSL, custom CA bundles, HTTP proxy settings, and per-service verification", + slug: "/guides/security_network" + }, + items: [ + "guides/security_settings", + ], + }, ], }, From e0e1ac617acedab7c1fb35a6372210a9e933efde Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 17 Mar 2026 12:49:07 -0700 Subject: [PATCH 242/289] [Test] UI: Add unit tests for 10 previously untested components Add Vitest + RTL tests for HelpLink, DebugWarningBanner, ExportFormatSelector, ExportTypeSelector, ExportSummary, MetricCard, PolicySelect, ComplexityRouterConfig, RateLimitTypeFormItem, and AgentCardGrid (67 tests total). Co-Authored-By: Claude Opus 4.6 --- .../components/DebugWarningBanner.test.tsx | 41 +++++++++ .../ExportFormatSelector.test.tsx | 20 +++++ .../EntityUsageExport/ExportSummary.test.tsx | 59 ++++++++++++ .../ExportTypeSelector.test.tsx | 46 ++++++++++ .../GuardrailsMonitor/MetricCard.test.tsx | 49 ++++++++++ .../src/components/HelpLink.test.tsx | 24 +++++ .../ToolPolicies/PolicySelect.test.tsx | 84 +++++++++++++++++ .../add_model/ComplexityRouterConfig.test.tsx | 82 +++++++++++++++++ .../agents/agent_card_grid.test.tsx | 90 +++++++++++++++++++ .../RateLimitTypeFormItem.test.tsx | 61 +++++++++++++ 10 files changed, 556 insertions(+) create mode 100644 ui/litellm-dashboard/src/components/DebugWarningBanner.test.tsx create mode 100644 ui/litellm-dashboard/src/components/EntityUsageExport/ExportFormatSelector.test.tsx create mode 100644 ui/litellm-dashboard/src/components/EntityUsageExport/ExportSummary.test.tsx create mode 100644 ui/litellm-dashboard/src/components/EntityUsageExport/ExportTypeSelector.test.tsx create mode 100644 ui/litellm-dashboard/src/components/GuardrailsMonitor/MetricCard.test.tsx create mode 100644 ui/litellm-dashboard/src/components/ToolPolicies/PolicySelect.test.tsx create mode 100644 ui/litellm-dashboard/src/components/add_model/ComplexityRouterConfig.test.tsx create mode 100644 ui/litellm-dashboard/src/components/agents/agent_card_grid.test.tsx create mode 100644 ui/litellm-dashboard/src/components/common_components/RateLimitTypeFormItem.test.tsx diff --git a/ui/litellm-dashboard/src/components/DebugWarningBanner.test.tsx b/ui/litellm-dashboard/src/components/DebugWarningBanner.test.tsx new file mode 100644 index 0000000000..2412a84da3 --- /dev/null +++ b/ui/litellm-dashboard/src/components/DebugWarningBanner.test.tsx @@ -0,0 +1,41 @@ +import { renderWithProviders, screen } from "../../tests/test-utils"; +import { vi } from "vitest"; +import { DebugWarningBanner } from "./DebugWarningBanner"; + +vi.mock("@/app/(dashboard)/hooks/healthReadiness/useHealthReadiness", () => ({ + useHealthReadiness: vi.fn(), +})); + +import { useHealthReadiness } from "@/app/(dashboard)/hooks/healthReadiness/useHealthReadiness"; + +describe("DebugWarningBanner", () => { + it("should render", () => { + vi.mocked(useHealthReadiness).mockReturnValue({ data: { is_detailed_debug: true } } as any); + renderWithProviders(); + expect(screen.getByRole("alert")).toBeInTheDocument(); + }); + + it("should show warning when detailed debug mode is active", () => { + vi.mocked(useHealthReadiness).mockReturnValue({ data: { is_detailed_debug: true } } as any); + renderWithProviders(); + expect(screen.getByText(/Performance Warning: Detailed Debug Mode Active/i)).toBeInTheDocument(); + }); + + it("should mention LITELLM_LOG=DEBUG in the description", () => { + vi.mocked(useHealthReadiness).mockReturnValue({ data: { is_detailed_debug: true } } as any); + renderWithProviders(); + expect(screen.getByText("LITELLM_LOG=DEBUG")).toBeInTheDocument(); + }); + + it("should render nothing when is_detailed_debug is false", () => { + vi.mocked(useHealthReadiness).mockReturnValue({ data: { is_detailed_debug: false } } as any); + const { container } = renderWithProviders(); + expect(container).toBeEmptyDOMElement(); + }); + + it("should render nothing when health data is undefined", () => { + vi.mocked(useHealthReadiness).mockReturnValue({ data: undefined } as any); + const { container } = renderWithProviders(); + expect(container).toBeEmptyDOMElement(); + }); +}); diff --git a/ui/litellm-dashboard/src/components/EntityUsageExport/ExportFormatSelector.test.tsx b/ui/litellm-dashboard/src/components/EntityUsageExport/ExportFormatSelector.test.tsx new file mode 100644 index 0000000000..8447df4a6b --- /dev/null +++ b/ui/litellm-dashboard/src/components/EntityUsageExport/ExportFormatSelector.test.tsx @@ -0,0 +1,20 @@ +import { renderWithProviders, screen } from "../../../tests/test-utils"; +import { vi } from "vitest"; +import ExportFormatSelector from "./ExportFormatSelector"; + +describe("ExportFormatSelector", () => { + it("should render", () => { + renderWithProviders(); + expect(screen.getByText("Format")).toBeInTheDocument(); + }); + + it("should display the current value", () => { + renderWithProviders(); + expect(screen.getByText("CSV (Excel, Google Sheets)")).toBeInTheDocument(); + }); + + it("should display JSON label when json is selected", () => { + renderWithProviders(); + expect(screen.getByText("JSON (includes metadata)")).toBeInTheDocument(); + }); +}); diff --git a/ui/litellm-dashboard/src/components/EntityUsageExport/ExportSummary.test.tsx b/ui/litellm-dashboard/src/components/EntityUsageExport/ExportSummary.test.tsx new file mode 100644 index 0000000000..8ebeb33b1e --- /dev/null +++ b/ui/litellm-dashboard/src/components/EntityUsageExport/ExportSummary.test.tsx @@ -0,0 +1,59 @@ +import { renderWithProviders, screen } from "../../../tests/test-utils"; +import ExportSummary from "./ExportSummary"; + +describe("ExportSummary", () => { + it("should render", () => { + const dateRange = { + from: new Date("2024-01-01"), + to: new Date("2024-01-31"), + }; + const { container } = renderWithProviders( + + ); + expect(container).not.toBeEmptyDOMElement(); + }); + + it("should display the date range", () => { + const from = new Date(2024, 0, 1); + const to = new Date(2024, 0, 31); + const dateRange = { from, to }; + renderWithProviders( + + ); + expect(screen.getByText(new RegExp(from.toLocaleDateString()))).toBeInTheDocument(); + expect(screen.getByText(new RegExp(to.toLocaleDateString()))).toBeInTheDocument(); + }); + + it("should show filter count when filters are selected", () => { + const dateRange = { + from: new Date("2024-01-01"), + to: new Date("2024-01-31"), + }; + renderWithProviders( + + ); + expect(screen.getByText(/3 filters/)).toBeInTheDocument(); + }); + + it("should show singular 'filter' for one filter", () => { + const dateRange = { + from: new Date("2024-01-01"), + to: new Date("2024-01-31"), + }; + renderWithProviders( + + ); + expect(screen.getByText(/1 filter$/)).toBeInTheDocument(); + }); + + it("should not show filter count when no filters selected", () => { + const dateRange = { + from: new Date("2024-01-01"), + to: new Date("2024-01-31"), + }; + renderWithProviders( + + ); + expect(screen.queryByText(/filter/)).not.toBeInTheDocument(); + }); +}); diff --git a/ui/litellm-dashboard/src/components/EntityUsageExport/ExportTypeSelector.test.tsx b/ui/litellm-dashboard/src/components/EntityUsageExport/ExportTypeSelector.test.tsx new file mode 100644 index 0000000000..36d2e12b71 --- /dev/null +++ b/ui/litellm-dashboard/src/components/EntityUsageExport/ExportTypeSelector.test.tsx @@ -0,0 +1,46 @@ +import { renderWithProviders, screen } from "../../../tests/test-utils"; +import userEvent from "@testing-library/user-event"; +import { vi } from "vitest"; +import ExportTypeSelector from "./ExportTypeSelector"; + +describe("ExportTypeSelector", () => { + it("should render", () => { + renderWithProviders( + + ); + expect(screen.getByText("Export type")).toBeInTheDocument(); + }); + + it("should display entity type in radio labels", () => { + renderWithProviders( + + ); + expect(screen.getByText(/Day-by-day breakdown by team$/)).toBeInTheDocument(); + expect(screen.getByText(/Day-by-day breakdown by team and key/)).toBeInTheDocument(); + expect(screen.getByText(/Day-by-day by team and model/)).toBeInTheDocument(); + }); + + it("should display the correct entity type for different entities", () => { + renderWithProviders( + + ); + expect(screen.getByText(/Day-by-day breakdown by organization$/)).toBeInTheDocument(); + }); + + it("should call onChange when a radio option is selected", async () => { + const user = userEvent.setup(); + const onChange = vi.fn(); + renderWithProviders( + + ); + await user.click(screen.getByRole("radio", { name: /Day-by-day breakdown by team and key/i })); + expect(onChange).toHaveBeenCalledWith("daily_with_keys"); + }); + + it("should have the correct radio checked", () => { + renderWithProviders( + + ); + expect(screen.getByRole("radio", { name: /Day-by-day by team and model/i })).toBeChecked(); + }); +}); diff --git a/ui/litellm-dashboard/src/components/GuardrailsMonitor/MetricCard.test.tsx b/ui/litellm-dashboard/src/components/GuardrailsMonitor/MetricCard.test.tsx new file mode 100644 index 0000000000..d30df1a006 --- /dev/null +++ b/ui/litellm-dashboard/src/components/GuardrailsMonitor/MetricCard.test.tsx @@ -0,0 +1,49 @@ +import { renderWithProviders, screen } from "../../../tests/test-utils"; +import React from "react"; +import { MetricCard } from "./MetricCard"; + +describe("MetricCard", () => { + it("should render", () => { + renderWithProviders(); + expect(screen.getByText("Total Requests")).toBeInTheDocument(); + }); + + it("should display the label and value", () => { + renderWithProviders(); + expect(screen.getByText("Success Rate")).toBeInTheDocument(); + expect(screen.getByText("98.5%")).toBeInTheDocument(); + }); + + it("should display numeric values", () => { + renderWithProviders(); + expect(screen.getByText("42")).toBeInTheDocument(); + }); + + it("should render icon when provided", () => { + renderWithProviders( + icon} + /> + ); + expect(screen.getByTestId("test-icon")).toBeInTheDocument(); + }); + + it("should not render icon container when no icon provided", () => { + renderWithProviders(); + expect(screen.queryByTestId("test-icon")).not.toBeInTheDocument(); + }); + + it("should render subtitle when provided", () => { + renderWithProviders( + + ); + expect(screen.getByText("Last 24 hours")).toBeInTheDocument(); + }); + + it("should not render subtitle when not provided", () => { + renderWithProviders(); + expect(screen.queryByText("Last 24 hours")).not.toBeInTheDocument(); + }); +}); diff --git a/ui/litellm-dashboard/src/components/HelpLink.test.tsx b/ui/litellm-dashboard/src/components/HelpLink.test.tsx index 72033bd93a..76c42b8159 100644 --- a/ui/litellm-dashboard/src/components/HelpLink.test.tsx +++ b/ui/litellm-dashboard/src/components/HelpLink.test.tsx @@ -23,6 +23,11 @@ describe("HelpLink", () => { expect(screen.getByText("Custom docs link")).toBeInTheDocument(); }); + it("should have the correct href", () => { + renderWithProviders(); + expect(screen.getByRole("link")).toHaveAttribute("href", "https://docs.example.com/test"); + }); + it("should include a screen-reader-only label for accessibility", () => { renderWithProviders(); @@ -46,7 +51,21 @@ describe("HelpIcon", () => { expect(screen.getByText("Tooltip help text")).toBeInTheDocument(); }); + it("should hide tooltip content when not hovered", () => { + renderWithProviders(); + expect(screen.queryByText("Hidden tooltip")).not.toBeInTheDocument(); + }); + it("should show learn more link when learnMoreHref is provided", async () => { + const user = userEvent.setup(); + renderWithProviders( + + ); + await user.hover(screen.getByRole("button", { name: /help information/i })); + expect(screen.getByText("Learn more")).toBeInTheDocument(); + }); + + it("should use custom learn more text when provided", async () => { const user = userEvent.setup(); renderWithProviders( { expect(screen.getByRole("button", { name: /docs/i })).toBeInTheDocument(); }); + it("should hide menu items initially", () => { + renderWithProviders(); + expect(screen.queryByText("Custom pricing")).not.toBeInTheDocument(); + }); + it("should show menu items when button is clicked", async () => { const user = userEvent.setup(); renderWithProviders(); diff --git a/ui/litellm-dashboard/src/components/ToolPolicies/PolicySelect.test.tsx b/ui/litellm-dashboard/src/components/ToolPolicies/PolicySelect.test.tsx new file mode 100644 index 0000000000..cde59fe9c6 --- /dev/null +++ b/ui/litellm-dashboard/src/components/ToolPolicies/PolicySelect.test.tsx @@ -0,0 +1,84 @@ +import { renderWithProviders, screen } from "../../../tests/test-utils"; +import { vi } from "vitest"; +import { + PolicySelect, + policyStyle, + INPUT_POLICY_OPTIONS, + OUTPUT_POLICY_OPTIONS, +} from "./PolicySelect"; + +describe("policyStyle", () => { + it("should return the matching option for a known policy", () => { + expect(policyStyle("trusted")).toEqual(INPUT_POLICY_OPTIONS[1]); + }); + + it("should return the matching option for blocked", () => { + expect(policyStyle("blocked")).toEqual(INPUT_POLICY_OPTIONS[2]); + }); + + it("should return the first option as fallback for unknown policy", () => { + expect(policyStyle("unknown")).toEqual(INPUT_POLICY_OPTIONS[0]); + }); +}); + +describe("PolicySelect", () => { + it("should render", () => { + renderWithProviders( + + ); + expect(screen.getByText("untrusted")).toBeInTheDocument(); + }); + + it("should show the current policy value", () => { + renderWithProviders( + + ); + expect(screen.getByText("trusted")).toBeInTheDocument(); + }); + + it("should be disabled when saving is true", () => { + renderWithProviders( + + ); + expect(screen.getByRole("combobox")).toHaveAttribute("aria-expanded", "false"); + expect(screen.getByRole("combobox").closest(".ant-select")).toHaveClass("ant-select-disabled"); + }); + + it("should not be disabled when saving is false", () => { + renderWithProviders( + + ); + expect(screen.getByRole("combobox").closest(".ant-select")).not.toHaveClass("ant-select-disabled"); + }); +}); + +describe("Policy option constants", () => { + it("should have 3 input policy options", () => { + expect(INPUT_POLICY_OPTIONS).toHaveLength(3); + }); + + it("should have 2 output policy options (no blocked)", () => { + expect(OUTPUT_POLICY_OPTIONS).toHaveLength(2); + expect(OUTPUT_POLICY_OPTIONS.map((o) => o.value)).toEqual(["untrusted", "trusted"]); + }); +}); diff --git a/ui/litellm-dashboard/src/components/add_model/ComplexityRouterConfig.test.tsx b/ui/litellm-dashboard/src/components/add_model/ComplexityRouterConfig.test.tsx new file mode 100644 index 0000000000..59d8721b14 --- /dev/null +++ b/ui/litellm-dashboard/src/components/add_model/ComplexityRouterConfig.test.tsx @@ -0,0 +1,82 @@ +import { renderWithProviders, screen } from "../../../tests/test-utils"; +import { vi } from "vitest"; +import ComplexityRouterConfig from "./ComplexityRouterConfig"; + +const mockModelInfo = [ + { model_group: "gpt-4" }, + { model_group: "gpt-3.5-turbo" }, + { model_group: "claude-3-opus" }, +] as any[]; + +const defaultTiers = { + SIMPLE: "gpt-3.5-turbo", + MEDIUM: "gpt-3.5-turbo", + COMPLEX: "gpt-4", + REASONING: "claude-3-opus", +}; + +describe("ComplexityRouterConfig", () => { + it("should render", () => { + renderWithProviders( + + ); + expect(screen.getByText("Complexity Tier Configuration")).toBeInTheDocument(); + }); + + it("should display all four tier labels", () => { + renderWithProviders( + + ); + expect(screen.getByText("Simple Tier")).toBeInTheDocument(); + expect(screen.getByText("Medium Tier")).toBeInTheDocument(); + expect(screen.getByText("Complex Tier")).toBeInTheDocument(); + expect(screen.getByText("Reasoning Tier")).toBeInTheDocument(); + }); + + it("should show example queries for each tier", () => { + renderWithProviders( + + ); + expect(screen.getByText(/Hello!/)).toBeInTheDocument(); + expect(screen.getByText(/Explain how REST APIs work/)).toBeInTheDocument(); + expect(screen.getByText(/Design a microservices architecture/)).toBeInTheDocument(); + expect(screen.getByText(/Think step by step/)).toBeInTheDocument(); + }); + + it("should display the how classification works section", () => { + renderWithProviders( + + ); + expect(screen.getByText("How Classification Works")).toBeInTheDocument(); + }); + + it("should show score thresholds in the classification section", () => { + renderWithProviders( + + ); + expect(screen.getByText(/Score < 0.15/)).toBeInTheDocument(); + expect(screen.getByText(/Score 0.15 - 0.35/)).toBeInTheDocument(); + expect(screen.getByText(/Score 0.35 - 0.60/)).toBeInTheDocument(); + expect(screen.getByText(/Score > 0.60/)).toBeInTheDocument(); + }); +}); diff --git a/ui/litellm-dashboard/src/components/agents/agent_card_grid.test.tsx b/ui/litellm-dashboard/src/components/agents/agent_card_grid.test.tsx new file mode 100644 index 0000000000..c8a21d1b6e --- /dev/null +++ b/ui/litellm-dashboard/src/components/agents/agent_card_grid.test.tsx @@ -0,0 +1,90 @@ +import { renderWithProviders, screen } from "../../../tests/test-utils"; +import { vi } from "vitest"; +import AgentCardGrid from "./agent_card_grid"; +import type { Agent, AgentKeyInfo } from "./types"; + +vi.mock("./agent_card", () => ({ + default: ({ agent, onAgentClick }: any) => ( +
onAgentClick(agent.agent_id)}> + {agent.agent_name} +
+ ), +})); + +const mockAgents: Agent[] = [ + { + agent_id: "agent-1", + agent_name: "Test Agent 1", + litellm_params: { model: "gpt-4" }, + agent_card_params: { description: "First agent" }, + }, + { + agent_id: "agent-2", + agent_name: "Test Agent 2", + litellm_params: { model: "claude-3" }, + agent_card_params: { description: "Second agent" }, + }, +]; + +const mockKeyInfoMap: Record = { + "agent-1": { has_key: true, key_alias: "key-1" }, + "agent-2": { has_key: false }, +}; + +const defaultProps = { + agentsList: mockAgents, + keyInfoMap: mockKeyInfoMap, + isLoading: false, + onDeleteClick: vi.fn(), + accessToken: "test-token", + onAgentUpdated: vi.fn(), + isAdmin: true, + onAgentClick: vi.fn(), +}; + +describe("AgentCardGrid", () => { + it("should render", () => { + renderWithProviders(); + expect(screen.getByText("Test Agent 1")).toBeInTheDocument(); + }); + + it("should render all agent cards", () => { + renderWithProviders(); + expect(screen.getByText("Test Agent 1")).toBeInTheDocument(); + expect(screen.getByText("Test Agent 2")).toBeInTheDocument(); + }); + + it("should show loading skeletons when isLoading is true", () => { + renderWithProviders(); + expect(screen.queryByText("Test Agent 1")).not.toBeInTheDocument(); + }); + + it("should show admin empty state message when no agents and isAdmin", () => { + renderWithProviders( + + ); + expect( + screen.getByText("No agents found. Create one to get started.") + ).toBeInTheDocument(); + }); + + it("should show non-admin empty state message when no agents and not admin", () => { + renderWithProviders( + + ); + expect( + screen.getByText("No agents found. Contact an admin to create agents.") + ).toBeInTheDocument(); + }); + + it("should call onAgentClick when a card is clicked", async () => { + const onAgentClick = vi.fn(); + renderWithProviders( + + ); + const { default: userEvent } = await import("@testing-library/user-event"); + const user = userEvent.setup(); + await user.click(screen.getByTestId("agent-card-agent-1")); + expect(onAgentClick).toHaveBeenCalledWith("agent-1"); + }); +}); diff --git a/ui/litellm-dashboard/src/components/common_components/RateLimitTypeFormItem.test.tsx b/ui/litellm-dashboard/src/components/common_components/RateLimitTypeFormItem.test.tsx new file mode 100644 index 0000000000..49b8028c51 --- /dev/null +++ b/ui/litellm-dashboard/src/components/common_components/RateLimitTypeFormItem.test.tsx @@ -0,0 +1,61 @@ +import { renderWithProviders, screen } from "../../../tests/test-utils"; +import userEvent from "@testing-library/user-event"; +import { vi } from "vitest"; +import { Form } from "antd"; +import React from "react"; +import { RateLimitTypeFormItem } from "./RateLimitTypeFormItem"; + +const Wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => ( +
{children}
+); + +describe("RateLimitTypeFormItem", () => { + it("should render", () => { + renderWithProviders( + + + + ); + expect(screen.getByText(/TPM Rate Limit Type/)).toBeInTheDocument(); + }); + + it("should display TPM label for tpm type", () => { + renderWithProviders( + + + + ); + expect(screen.getByText(/TPM Rate Limit Type/)).toBeInTheDocument(); + }); + + it("should display RPM label for rpm type", () => { + renderWithProviders( + + + + ); + expect(screen.getByText(/RPM Rate Limit Type/)).toBeInTheDocument(); + }); + + it("should show the select placeholder by default", () => { + renderWithProviders( + + + + ); + expect(screen.getByText("Select rate limit type")).toBeInTheDocument(); + }); + + it("should call onChange when provided", async () => { + const user = userEvent.setup(); + const onChange = vi.fn(); + renderWithProviders( + + + + ); + await user.click(screen.getByRole("combobox")); + await user.click(screen.getByText("Guaranteed throughput")); + expect(onChange).toHaveBeenCalledWith("guaranteed_throughput"); + }); +}); From 79e600507682a976aa246842301c2d562bf48c28 Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Wed, 18 Mar 2026 02:52:50 +0530 Subject: [PATCH 243/289] docs: enhance gateway and SDK quickstart documentation --- .../docs/learn/gateway_quickstart.md | 37 ++++++++++----- docs/my-website/docs/learn/sdk_quickstart.md | 47 ++++++++++++++++++- 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/docs/my-website/docs/learn/gateway_quickstart.md b/docs/my-website/docs/learn/gateway_quickstart.md index f29f6e7d48..2823e97e40 100644 --- a/docs/my-website/docs/learn/gateway_quickstart.md +++ b/docs/my-website/docs/learn/gateway_quickstart.md @@ -59,7 +59,7 @@ curl -X POST 'http://0.0.0.0:4000/chat/completions' \ ## 6. Check The Response -If the request succeeds, the proxy returns `200 OK` with the same OpenAI-style response shape LiteLLM uses in the SDK. +If the request succeeds, the proxy returns `200 OK` with an OpenAI-style response. The assistant text will be in: @@ -67,33 +67,48 @@ The assistant text will be in: choices[0].message.content ``` -It looks like this: +If your gateway is routing to OpenAI, a real response can look like this: ```json { "id": "chatcmpl-abc123", - "object": "chat.completion", "created": 1677858242, - "model": "gpt-4o-mini", + "model": "gpt-4o-mini-2024-07-18", + "object": "chat.completion", + "system_fingerprint": "fp_406d6473f8", "choices": [ { + "finish_reason": "stop", "index": 0, "message": { "role": "assistant", - "content": "Hello! How can I help?" - }, - "finish_reason": "stop" + "content": "Hello! How can I assist you today?", + "tool_calls": null, + "function_call": null, + "annotations": [] + } } ], "usage": { - "prompt_tokens": 12, "completion_tokens": 9, - "total_tokens": 21 - } + "prompt_tokens": 13, + "total_tokens": 22, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 0, + "rejected_prediction_tokens": 0 + }, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + } + }, + "service_tier": "default" } ``` -`id`, `created`, token counts, and message text will vary by request. +`id`, `created`, the resolved model version, token counts, and message text will vary by request. Other providers may return a smaller or slightly different set of fields, but `choices[0].message.content` is the main field to read. ## 7. Add Keys And The UI diff --git a/docs/my-website/docs/learn/sdk_quickstart.md b/docs/my-website/docs/learn/sdk_quickstart.md index 3726f1f22b..b4342d54cd 100644 --- a/docs/my-website/docs/learn/sdk_quickstart.md +++ b/docs/my-website/docs/learn/sdk_quickstart.md @@ -56,7 +56,48 @@ prints the assistant text, for example: Hello! I'm doing well, thanks for asking. ``` -The full response is an OpenAI-style `ModelResponse` object. It looks like this: +If you print the full object with: + +```python +print(response) +``` + +you will see a Python `ModelResponse(...)` object. For an OpenAI-backed model, it can look like this: + +```python +ModelResponse( + id='chatcmpl-abc123', + created=1773782130, + model='gpt-4o-2024-08-06', + object='chat.completion', + system_fingerprint='fp_4ff89bf575', + choices=[ + Choices( + finish_reason='stop', + index=0, + message=Message( + content="Hello! I'm just a program, but I'm here to help you. How can I assist you today?", + role='assistant', + tool_calls=None, + function_call=None, + provider_specific_fields={'refusal': None}, + annotations=[] + ), + provider_specific_fields={} + ) + ], + usage=Usage( + completion_tokens=21, + prompt_tokens=13, + total_tokens=34, + completion_tokens_details=CompletionTokensDetailsWrapper(...), + prompt_tokens_details=PromptTokensDetailsWrapper(...) + ), + service_tier='default' +) +``` + +The same response follows an OpenAI-style shape. Conceptually, it looks like this: ```json { @@ -82,7 +123,9 @@ The full response is an OpenAI-style `ModelResponse` object. It looks like this: } ``` -`id`, `created`, token counts, and message text will vary by request. For the full output reference, see [completion output](/docs/completion/output). +`id`, `created`, token counts, and message text will vary by request. + +If you call an OpenAI-backed model, you may also see extra fields such as `system_fingerprint`, `service_tier`, `tool_calls`, `function_call`, `annotations`, `provider_specific_fields`, and detailed token usage. For the full output reference, see [completion output](/docs/completion/output). Need more provider examples? See the main [Getting Started](/docs/#quick-start) page. From d0c5f494a8bf99a078561a939cb0e557559c614f Mon Sep 17 00:00:00 2001 From: Kelvin Tran Date: Tue, 17 Mar 2026 14:30:12 -0700 Subject: [PATCH 244/289] fix: cache_control directive dropped anthropic document/file blocks --- .../prompt_templates/factory.py | 16 +++- ...llm_core_utils_prompt_templates_factory.py | 89 ++++++++++++++++++- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/litellm/litellm_core_utils/prompt_templates/factory.py b/litellm/litellm_core_utils/prompt_templates/factory.py index 53d2ca2f23..2b4dbc4a3a 100644 --- a/litellm/litellm_core_utils/prompt_templates/factory.py +++ b/litellm/litellm_core_utils/prompt_templates/factory.py @@ -2142,13 +2142,25 @@ def anthropic_messages_pt( # noqa: PLR0915 user_content.append(_content_element) elif m.get("type", "") == "document": - user_content.append(cast(AnthropicMessagesDocumentParam, m)) + _document_content_element = cast( + AnthropicMessagesDocumentParam, + add_cache_control_to_content( + anthropic_content_element=cast(AnthropicMessagesDocumentParam, m), + original_content_element=dict(m), + ), + ) + user_content.append(_document_content_element) elif m.get("type", "") == "file": - user_content.append( + _file_content_element = ( anthropic_process_openai_file_message( cast(ChatCompletionFileObject, m) ) ) + _file_content_element = add_cache_control_to_content( + anthropic_content_element=cast(AnthropicMessagesDocumentParam, _file_content_element), + original_content_element=dict(m), + ) + user_content.append(cast(AnthropicMessagesDocumentParam,_file_content_element)) elif isinstance(user_message_types_block["content"], str): _anthropic_content_text_element: AnthropicMessagesTextParam = { "type": "text", diff --git a/tests/test_litellm/litellm_core_utils/prompt_templates/test_litellm_core_utils_prompt_templates_factory.py b/tests/test_litellm/litellm_core_utils/prompt_templates/test_litellm_core_utils_prompt_templates_factory.py index e87233a52a..fb10116298 100644 --- a/tests/test_litellm/litellm_core_utils/prompt_templates/test_litellm_core_utils_prompt_templates_factory.py +++ b/tests/test_litellm/litellm_core_utils/prompt_templates/test_litellm_core_utils_prompt_templates_factory.py @@ -1,4 +1,4 @@ -import json +import base64 from unittest.mock import MagicMock, patch import pytest @@ -8,6 +8,7 @@ from litellm.litellm_core_utils.prompt_templates.factory import ( BAD_MESSAGE_ERROR_STR, BedrockConverseMessagesProcessor, BedrockImageProcessor, + anthropic_messages_pt, ollama_pt, ) @@ -1590,3 +1591,89 @@ def test_bedrock_tools_unpack_defs_no_oom_with_nested_refs(): # Verify $defs have been removed (Bedrock doesn't support them) tool_schema = result[0]["toolSpec"].get("inputSchema", {}).get("json", {}) assert "$defs" not in tool_schema, "$defs should be removed after expansion" + + +def test_anthropic_messages_pt_file_block_preserves_cache_control(): + """ + Test that cache_control on file-type content blocks is preserved + when translating to Anthropic message format. + Regression test for https://github.com/BerriAI/litellm/issues/23873 + """ + + pdf_b64 = base64.b64encode(b"%PDF-1.4 fake pdf content").decode() + messages = [ + { + "role": "user", + "content": [ + { + "type": "file", + "file": { + "filename": "document.pdf", + "file_data": f"data:application/pdf;base64,{pdf_b64}", + }, + "cache_control": {"type": "ephemeral"}, + }, + { + "type": "text", + "text": "Summarize this document.", + "cache_control": {"type": "ephemeral"}, + }, + ], + } + ] + + result = anthropic_messages_pt( + messages=messages, + model="claude-sonnet-4-20250514", + llm_provider="anthropic", + ) + + assert len(result) == 1 + content_blocks = result[0]["content"] + assert len(content_blocks) == 2 + + file_block = content_blocks[0] + assert file_block["type"] == "document" + assert "cache_control" in file_block, ( + "cache_control should be preserved on file/document content blocks" + ) + assert file_block["cache_control"]["type"] == "ephemeral" + + text_block = content_blocks[1] + assert text_block["type"] == "text" + assert "cache_control" in text_block + assert text_block["cache_control"]["type"] == "ephemeral" + + +def test_anthropic_messages_pt_file_block_without_cache_control(): + """ + Test that file blocks without cache_control still work correctly. + """ + import base64 + + pdf_b64 = base64.b64encode(b"%PDF-1.4 fake").decode() + messages = [ + { + "role": "user", + "content": [ + { + "type": "file", + "file": { + "filename": "doc.pdf", + "file_data": f"data:application/pdf;base64,{pdf_b64}", + }, + }, + ], + } + ] + + result = anthropic_messages_pt( + messages=messages, + model="claude-sonnet-4-20250514", + llm_provider="anthropic", + ) + + assert len(result) == 1 + file_block = result[0]["content"][0] + assert file_block["type"] == "document" + assert "cache_control" not in file_block From f9f7d0a21cb045efbc39918e64317678e79261b7 Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Wed, 18 Mar 2026 03:37:29 +0530 Subject: [PATCH 245/289] docs: simplify sidebar labels and remove outdated project links --- docs/my-website/sidebars.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index 27d7c6b34f..7c15b3384d 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -111,7 +111,7 @@ const sidebars = { }, { type: "category", - label: "AI Tools (OpenWebUI, Claude Code, etc.)", + label: "AI Tools", link: { type: "generated-index", title: "AI Tools", @@ -1088,9 +1088,7 @@ const sidebars = { "projects/Quivr", "projects/Langstream", "projects/Otter", - "projects/GPT Migrate", "projects/YiVal", - "projects/LiteLLM Proxy", "projects/llm_cord", "projects/pgai", "projects/GPTLocalhost", From 16fecb06c1efdf2921caaaa8fd19fee11f04eb9b Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Wed, 18 Mar 2026 04:23:00 +0530 Subject: [PATCH 246/289] docs: update Docker quick start guide for LiteLLM proxy --- .../docs/proxy/docker_quick_start.md | 76 ++++++++++--------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/docs/my-website/docs/proxy/docker_quick_start.md b/docs/my-website/docs/proxy/docker_quick_start.md index eb199c075e..4cce4d0e23 100644 --- a/docs/my-website/docs/proxy/docker_quick_start.md +++ b/docs/my-website/docs/proxy/docker_quick_start.md @@ -40,7 +40,7 @@ $ pip install 'litellm[proxy]' ### Step 1 — Pull the LiteLLM database image -LiteLLM provides a pre-built image with Postgres bundled in. Pull it before starting. +LiteLLM provides a dedicated `litellm-database` image for proxy deployments that connect to Postgres. Pull it before starting Docker Compose. ```bash docker pull ghcr.io/berriai/litellm-database:main-latest @@ -50,29 +50,9 @@ See all available tags on the [GitHub Container Registry](https://github.com/Ber --- -### Step 2 — Set up your config.yaml (do this before starting the server) +### Step 2 — Set up a database -Create a `litellm_config.yaml` file. You **must** add your model and database settings here before starting the proxy. - -```yaml -model_list: - - model_name: gpt-4o - litellm_params: - model: azure/my_azure_deployment - api_base: os.environ/AZURE_API_BASE - api_key: os.environ/AZURE_API_KEY - api_version: "2025-01-01-preview" - -general_settings: - master_key: sk-1234 # 🔑 your proxy admin key (must start with sk-) - database_url: "postgresql://:@:/" # 👈 required for virtual keys -``` - -:::tip -`database_url` is required for virtual keys, spend tracking, and the UI. Use [Supabase](https://supabase.com/) or [Neon](https://neon.tech/) for a free managed Postgres instance. -::: - -Get the docker compose file and create your `.env`: +Get the docker compose file and create your `.env` first: ```bash # Get the docker compose file @@ -85,12 +65,40 @@ echo 'LITELLM_MASTER_KEY="sk-1234"' > .env # Used to encrypt/decrypt your LLM API key credentials # Generate a strong random value: https://1password.com/password-generator/ echo 'LITELLM_SALT_KEY="sk-1234"' >> .env + +# Add your model credentials +echo 'AZURE_API_BASE="https://openai-***********/"' >> .env +echo 'AZURE_API_KEY="your-azure-api-key"' >> .env ``` +Then finish your `config.yaml` before starting the proxy server. If you use the default `docker-compose.yml`, the Postgres container is available at `db:5432`. + +```yaml +model_list: + - model_name: gpt-4o + litellm_params: + model: azure/my_azure_deployment + api_base: os.environ/AZURE_API_BASE + api_key: os.environ/AZURE_API_KEY + api_version: "2025-01-01-preview" + +general_settings: + master_key: sk-1234 # 🔑 your proxy admin key (must start with sk-) + database_url: "postgresql://llmproxy:dbpassword9090@db:5432/litellm" +``` + +:::tip +`database_url` is required for virtual keys, spend tracking, and the UI. If you want a managed database instead, replace it with your [Supabase](https://supabase.com/) or [Neon](https://neon.tech/) connection string. +::: + +Save this file as `config.yaml`. + --- ### Step 3 — Start the proxy server and test it +After `config.yaml` and `.env` are complete, start the proxy: + ```bash docker compose up ``` @@ -318,11 +326,11 @@ curl -X POST 'http://0.0.0.0:4000/chat/completions' \ - [Other/Non-Chat Completion Endpoints](../embedding/supported_embedding.md) - [Pass-through for VertexAI, Bedrock, etc.](../pass_through/vertex_ai.md) -## 3. Generate a virtual key +## Optional: Generate a virtual key -Track Spend, and control model access via virtual keys for the proxy +Track spend and control model access via virtual keys for the proxy. -### 3.1 Set up a Database +### Prerequisite — Set up a database **Requirements** - Need a postgres database (e.g. [Supabase](https://supabase.com/), [Neon](https://neon.tech/), etc) @@ -342,7 +350,9 @@ general_settings: database_url: "postgresql://:@:/" # 👈 KEY CHANGE ``` -Save config.yaml as `litellm_config.yaml` (used in 3.2). +Save config.yaml as `litellm_config.yaml` before continuing. + +You must finish this setup before starting the proxy server. --- @@ -368,7 +378,7 @@ See All General Settings [here](http://localhost:3000/docs/proxy/configs#all-set `database_url: "postgresql://..."` - Set `DATABASE_URL=postgresql://:@:/` in your env -### 3.2 Start Proxy +### Start Proxy ```bash docker run \ @@ -376,12 +386,12 @@ docker run \ -e AZURE_API_KEY=d6*********** \ -e AZURE_API_BASE=https://openai-***********/ \ -p 4000:4000 \ - docker.litellm.ai/berriai/litellm:main-latest \ + ghcr.io/berriai/litellm-database:main-latest \ --config /app/config.yaml --detailed_debug ``` -### 3.3 Create Key w/ RPM Limit +### Create Key w/ RPM Limit Create a key with `rpm_limit: 1`. This will only allow 1 request per minute for calls to proxy with this key. @@ -404,9 +414,9 @@ curl -L -X POST 'http://0.0.0.0:4000/key/generate' \ } ``` -### 3.4 Test it! +### Test it! -**Use your virtual key from step 3.3** +**Use the virtual key you just created.** 1st call - Expect to work! @@ -719,5 +729,3 @@ LiteLLM Proxy uses the [LiteLLM Python SDK](https://docs.litellm.ai/docs/routing - Our emails ✉️ ishaan@berri.ai / krrish@berri.ai [![Chat on WhatsApp](https://img.shields.io/static/v1?label=Chat%20on&message=WhatsApp&color=success&logo=WhatsApp&style=flat-square)](https://wa.link/huol9n) [![Chat on Discord](https://img.shields.io/static/v1?label=Chat%20on&message=Discord&color=blue&logo=Discord&style=flat-square)](https://discord.gg/wuPM9dRgDw) - - From 12822f14ab93037e991de7233d578812bc6fd0f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mr=2E=20=C3=85nand?= <73425223+Astrodevil@users.noreply.github.com> Date: Wed, 18 Mar 2026 04:28:06 +0530 Subject: [PATCH 247/289] docs: sidebar updates, letta resources links, Google GenAI SDK, cost tracking order - Fix Letta Resources links: proxy, SDK (#litellm-python-sdk), observability, correct Letta docs URL - Add Google GenAI SDK to Agent SDKs, remove from AI Tools - Move Track Usage for Coding Tools to end of AI Tools section - Remove Letta from Agent SDKs sidebar - Guides, Learn, Tutorials index updates Made-with: Cursor --- docs/my-website/docs/guides/index.md | 28 ------- docs/my-website/docs/integrations/letta.md | 12 +-- docs/my-website/docs/learn/index.md | 8 +- docs/my-website/docs/tutorials/index.md | 66 ++++++---------- docs/my-website/sidebars.js | 92 +++++++++++++--------- 5 files changed, 82 insertions(+), 124 deletions(-) diff --git a/docs/my-website/docs/guides/index.md b/docs/my-website/docs/guides/index.md index b39234e4c8..1641600dab 100644 --- a/docs/my-website/docs/guides/index.md +++ b/docs/my-website/docs/guides/index.md @@ -11,34 +11,6 @@ import NavigationCards from '@site/src/components/NavigationCards'; --- -## Start Here - - - ---- - ## Build With LiteLLM diff --git a/docs/my-website/docs/tutorials/index.md b/docs/my-website/docs/tutorials/index.md index 9c3fc7a35b..7f80cc760e 100644 --- a/docs/my-website/docs/tutorials/index.md +++ b/docs/my-website/docs/tutorials/index.md @@ -11,34 +11,6 @@ import NavigationCards from '@site/src/components/NavigationCards'; --- -## Start Here - - - ---- - ## Getting Started --- -## Advanced Features +## Observability & Evaluation diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index 27d7c6b34f..39d59d73e6 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -138,14 +138,13 @@ const sidebars = { }, "tutorials/opencode_integration", "tutorials/openclaw_integration", - "tutorials/cost_tracking_coding", "tutorials/cursor_integration", "tutorials/github_copilot_integration", "tutorials/litellm_gemini_cli", - "tutorials/google_genai_sdk", "tutorials/litellm_qwen_code_cli", "tutorials/openai_codex", - "tutorials/retool_assist" + "tutorials/retool_assist", + "tutorials/cost_tracking_coding" ] }, { @@ -162,6 +161,7 @@ const sidebars = { "tutorials/claude_agent_sdk", "tutorials/copilotkit_sdk", "tutorials/google_adk", + "tutorials/google_genai_sdk", "tutorials/livekit_xai_realtime", { type: "doc", id: "tutorials/instructor", label: "Instructor with LiteLLM" }, { type: "doc", id: "langchain/langchain", label: "LangChain with LiteLLM" }, @@ -1085,6 +1085,7 @@ const sidebars = { "projects/Codium PR Agent", "projects/Prompt2Model", "projects/SalesGPT", + "projects/Softgen", "projects/Quivr", "projects/Langstream", "projects/Otter", @@ -1341,80 +1342,93 @@ const learnSidebar = { }, { type: "category", - label: "Provider Tutorials", + label: "Python SDK", collapsed: true, link: { type: "generated-index", - title: "Provider Tutorials", - description: "Set up Azure OpenAI, HuggingFace, TogetherAI, local models, and more", + title: "Python SDK", + description: "Tutorials using only the Python SDK — no proxy server required", + slug: "/tutorials/python_sdk" + }, + items: [ + "tutorials/gradio_integration", + "tutorials/provider_specific_params", + "tutorials/model_fallbacks", + "tutorials/fallbacks", + ], + }, + { + type: "category", + label: "Provider Setup", + collapsed: true, + link: { + type: "generated-index", + title: "Provider Setup", + description: "Connect LiteLLM to Azure OpenAI, HuggingFace, TogetherAI, local models, and more", slug: "/tutorials/provider_tutorials" }, items: [ "tutorials/azure_openai", "tutorials/TogetherAI_liteLLM", - "tutorials/huggingface_codellama", "tutorials/huggingface_tutorial", + "tutorials/huggingface_codellama", "tutorials/finetuned_chat_gpt", - "tutorials/gradio_integration", - "tutorials/compare_llms", - "tutorials/litellm_Test_Multiple_Providers", "tutorials/oobabooga", ], }, { type: "category", - label: "Proxy & Gateway", + label: "Proxy: Admin & Access", collapsed: true, link: { type: "generated-index", - title: "Proxy & Gateway", - description: "Access control, SSO, SCIM, tag management, and prompt caching", - slug: "/tutorials/proxy_gateway" + title: "Proxy: Admin & Access", + description: "User and team management, SSO, SCIM, and routing rules", + slug: "/tutorials/proxy_admin_access" }, items: [ "tutorials/default_team_self_serve", "tutorials/msft_sso", "tutorials/scim_litellm", "tutorials/tag_management", - "tutorials/prompt_caching", - "tutorials/anthropic_file_usage", ], }, { type: "category", - label: "Observability & Safety", + label: "Proxy: Features & Safety", collapsed: true, link: { type: "generated-index", - title: "Observability & Safety", - description: "Logging, guardrails, PII masking, and evaluation suites", - slug: "/tutorials/observability_safety" + title: "Proxy: Features & Safety", + description: "Prompt caching, passthrough APIs, realtime, guardrails, and PII masking", + slug: "/tutorials/proxy_features_safety" + }, + items: [ + "tutorials/prompt_caching", + "tutorials/anthropic_file_usage", + "tutorials/gemini_realtime_with_audio", + "tutorials/litellm_proxy_aporia", + "tutorials/presidio_pii_masking", + ], + }, + { + type: "category", + label: "Observability & Evaluation", + collapsed: true, + link: { + type: "generated-index", + title: "Observability & Evaluation", + description: "Logging, monitoring, benchmarking, and evaluation suites", + slug: "/tutorials/observability_evaluation" }, items: [ "tutorials/elasticsearch_logging", - "tutorials/litellm_proxy_aporia", - "tutorials/presidio_pii_masking", + "tutorials/compare_llms", + "tutorials/litellm_Test_Multiple_Providers", "tutorials/eval_suites", "tutorials/lm_evaluation_harness", ], }, - { - type: "category", - label: "Advanced Features", - collapsed: true, - link: { - type: "generated-index", - title: "Advanced Features", - description: "Model fallbacks, provider-specific params, and realtime audio", - slug: "/tutorials/advanced_features" - }, - items: [ - "tutorials/model_fallbacks", - "tutorials/fallbacks", - "tutorials/provider_specific_params", - "tutorials/gemini_realtime_with_audio", - ], - }, ], }, ], From b8ffbba352ba70b92c4057c418cce44a8e7fa1f9 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 17 Mar 2026 17:23:39 -0700 Subject: [PATCH 248/289] [Fix] Add contents:write permission to release job in ghcr_deploy workflow The release job was failing with "Resource not accessible by integration" because other jobs explicitly set permissions, causing GitHub to scope the default token down for all jobs. The release job needs contents:write to create GitHub releases. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/ghcr_deploy.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ghcr_deploy.yml b/.github/workflows/ghcr_deploy.yml index c317309d91..344b0ec48e 100644 --- a/.github/workflows/ghcr_deploy.yml +++ b/.github/workflows/ghcr_deploy.yml @@ -369,7 +369,8 @@ jobs: release: name: "New LiteLLM Release" needs: [docker-hub-deploy, build-and-push-image, build-and-push-image-database] - + permissions: + contents: write runs-on: "ubuntu-latest" steps: From 709581c5f9279dde6c6d941797bdb9696d3cfcd6 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 17 Mar 2026 17:31:45 -0700 Subject: [PATCH 249/289] =?UTF-8?q?bump:=20version=201.82.3=20=E2=86=92=20?= =?UTF-8?q?1.82.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 07004f3ae1..37223a3e25 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "litellm" -version = "1.82.3" +version = "1.82.4" description = "Library to easily interface with LLM API providers" authors = ["BerriAI"] license = "MIT" @@ -183,7 +183,7 @@ requires = ["poetry-core", "wheel"] build-backend = "poetry.core.masonry.api" [tool.commitizen] -version = "1.82.3" +version = "1.82.4" version_files = [ "pyproject.toml:^version" ] From 9fa1809c30c0bc18f70bbe60626966285a172cfa Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 17 Mar 2026 17:37:04 -0700 Subject: [PATCH 250/289] =?UTF-8?q?bump:=20version=200.4.56=20=E2=86=92=20?= =?UTF-8?q?0.4.57?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- litellm-proxy-extras/pyproject.toml | 4 ++-- pyproject.toml | 2 +- requirements.txt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/litellm-proxy-extras/pyproject.toml b/litellm-proxy-extras/pyproject.toml index b65dbe4523..006aad9480 100644 --- a/litellm-proxy-extras/pyproject.toml +++ b/litellm-proxy-extras/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "litellm-proxy-extras" -version = "0.4.56" +version = "0.4.57" description = "Additional files for the LiteLLM Proxy. Reduces the size of the main litellm package." authors = ["BerriAI"] readme = "README.md" @@ -22,7 +22,7 @@ requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" [tool.commitizen] -version = "0.4.56" +version = "0.4.57" version_files = [ "pyproject.toml:version", "../requirements.txt:litellm-proxy-extras==", diff --git a/pyproject.toml b/pyproject.toml index 37223a3e25..0e2fb40d93 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ boto3 = { version = "^1.40.76", optional = true } redisvl = {version = "^0.4.1", optional = true, markers = "python_version >= '3.9' and python_version < '3.14'"} mcp = {version = ">=1.25.0,<2.0.0", optional = true, python = ">=3.10"} a2a-sdk = {version = "^0.3.22", optional = true, python = ">=3.10"} -litellm-proxy-extras = {version = "^0.4.56", optional = true} +litellm-proxy-extras = {version = "^0.4.57", optional = true} rich = {version = "^13.7.1", optional = true} litellm-enterprise = {version = "^0.1.33", optional = true} diskcache = {version = "^5.6.1", optional = true} diff --git a/requirements.txt b/requirements.txt index 2bdafda612..827986487f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -57,7 +57,7 @@ grpcio>=1.75.0; python_version >= "3.14" sentry_sdk==2.21.0 # for sentry error handling detect-secrets==1.5.0 # Enterprise - secret detection / masking in LLM requests tzdata==2025.1 # IANA time zone database -litellm-proxy-extras==0.4.56 # for proxy extras - e.g. prisma migrations +litellm-proxy-extras==0.4.57 # for proxy extras - e.g. prisma migrations llm-sandbox==0.3.31 # for skill execution in sandbox ### LITELLM PACKAGE DEPENDENCIES python-dotenv==1.0.1 # for env From cc37bf59344f5a5ba364d6fbc406f17f30e550a4 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 17 Mar 2026 17:37:25 -0700 Subject: [PATCH 251/289] adding build --- ...litellm_proxy_extras-0.4.57-py3-none-any.whl | Bin 0 -> 76172 bytes .../dist/litellm_proxy_extras-0.4.57.tar.gz | Bin 0 -> 31935 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 litellm-proxy-extras/dist/litellm_proxy_extras-0.4.57-py3-none-any.whl create mode 100644 litellm-proxy-extras/dist/litellm_proxy_extras-0.4.57.tar.gz diff --git a/litellm-proxy-extras/dist/litellm_proxy_extras-0.4.57-py3-none-any.whl b/litellm-proxy-extras/dist/litellm_proxy_extras-0.4.57-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..eeed18e312aecb6afdcdfe13d71fbd7fce68ea44 GIT binary patch literal 76172 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 literal 0 HcmV?d00001 diff --git a/litellm-proxy-extras/dist/litellm_proxy_extras-0.4.57.tar.gz b/litellm-proxy-extras/dist/litellm_proxy_extras-0.4.57.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..293c44e593d5147d8cb69b76abd3406c9e55c107 GIT binary patch literal 31935 zcmXt z9q#}8@L~7_dyd)rI?uI!YYjsf9v%kz2MgF*xtQ77+Ce`$Ie2(N%{*M3Oq_Z6d4+g| zMR{FJoG^A9cbsNaV)!Lsy6PG&C2)S>^e1EuD%IDg=Ut?GvYh(VxxZ&R`_c|%Arl+?Zf3MrrdcfzPH`@w^ z@5?pmK<9GbOPOzQ@YNNi=ncH^Y9t`N%{~D|`RO09V|bLh>3%-DNlQnE`do=B4^Hrd!y1wM-& z9`VZyRbVeHA}+-<4+tj*N~=prcUqiS$LHE9;*XbhMU04TH7m0uY0kHeEnqMhuECEA z3Q0+}`Q2gnjteF$Vz=k@WBXAx)d!NRm$nugJ?D9^NSc3&%{1=KxJR1q8XVqflNLC( zt3$Rlu0`%ilX|r~F?9ExV{b0beU4v|*iY2MNSa!CMUloE@bvI*1o<+hccAzu_-BUa zN&`4e4bL&%+q{L`ww@@=B=0s8uhegnBX)x>N^_Q#FiU4!Ol8`IpOvr;j4lZpyI-xf z5EDw=UnKaL>TSABl==WQk((}@vY_^3@zZ_T0ELBq1rMr4g}Tq)mvnrX&oHBk=&1bV zZJ!iHRJY^|epFCsQpA)&_#CLM@i_*h4$r!qyhu5x_9``V=~%#ge26b%(G{6~*An8w z{=WJ7pKlsgB-rC;@_L*GSXjpKvT^Wx`#fS0caa7D;O6*4ahX^5UGPgslB1Gbp2g-c zG$SEr-TiCzGca1{MfVg@ZCw-cdddoX7m9FLJm{cDbWZK5ConkRSN@S{`g8O7UDM-E zN_bTIAn&US6#y$Pz7`c-J@(qzZ5u{KDNLRml=f;NE*uasp-i>f^Q-#Ok*WqE~h*XlA3_ClVOW-9AcYcCygnTp6BDvHux+ z7Jw(z0*B0>u3&asflJzsx|V^

q$qREtayi-m&CL1b=*Ac@53@t}s-VDBL~sLrfi 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

_)(gW}{?KFs8NxqarOl zgP(1}@-Rd@lGIE1N=Sp>sYQ&;QzV0u9x%hx57NVcd%f^6(3Q^arNu1lZodxCFBQGN z*Bq|oLBhHA)D^0V4TS(cOm9zQNOU)t8b$!ozo--gJgp?GH}V*Cs7wSb?iz|72VT4= z2bb+-u$Oj}Z&wM`QX-iY!sv4ePHu4!1$?;PXscqn4Jy5ofx|tJcZI4A;SfDW$h1W_ zpUbsI?!&Vl(m7%cpvALB;suuyJ*%kY)*{UkP&P~j*R_|hdXXFWh=7rM-H!*)LNn-h zsFp8Z>} zHjIUjZEJ6c_->P+!fu~~P?ds>z-R}rB*2q#(S?5mwXlE%N-)mLk?A~-+kn9|3SNr@tJ}fb2!V-> zIv72?hBbm*<(+t>!Qc(8x@9t-`8vX6+x5LM9@e$uGP6|kP6s2s(J=i}5BS)W1B23B zp{IvKaHQbdo~}6Jo}hqVD|6Y%P|tFCZKlW6d{CpP=AYk5Nu!FgN57zk&l#$2Cip8s zr*k(fH9L6?5|6h%U(G7}9QWdUF;?7Zw>xSaTM^->L1#xe&5J0(*fl#(H{x;zAE>5L z6}*T853whN_Cc-R`2R!?J!VuOaeMbX5hnMY0*}Dn!^2L5Gvcr26!E}5=M?%*fu?YRo+;rAs2o{1Ne56fYIMz48q~8(5Ep$ z&Fd~wW0;IH9YD3&s1?-DWxI`oiW~%}yM%>;&KyYfyN!iDP!XWiuxbYPSA5;>3wsTFa7cZIV6VY&!&dr*x_zkJydm@xV?~)bM)I8}eU1vpk?B_x zzF7AU*S{fUjaHZIe(Ohz2jsvfS!y6>Q=^v^lT#YDnrFXhR_E4S!S0RXQgQSSO7gNV zEcO$}`&D8`Ps~M`1MIrF)7qnl^u7%eiiA?)P2%D*docBy44C6RlFLuH;Cjw|CqVZl zuTGFw@UH2SmI)_O0^w)F2fWlTQa`JH{w?&*De2$W!)`ODw_-f}XS$etcA!KROq{{f zG(braO1I=J-*r?(pN;}gmdDrfIIlLDbzYAKS@Q;Q{M3GK-g430Y!E zI&=)YR)JzgOXs;P{`8j1Vdz*X2dmq#iBdAyxq{QQ1DgUcBUsmrH$6vhhO<(;cHj3k z4wfNs??u2kCRJD9GgDVkCsN$>KnShOAgtgM%@(IrPQj*F@NJe=;HBII5GT>{E{$i_i(FOZXdC=Ge`vrT8EnGI0Qf5$s^*$@bO*nU-tvm z6A1e@%nkjl5&(yZIB--tW|htNv6EJ>1*5dPA?1Fjn)wSU3BC&#o?p0$*FTAi0@CcBy; zivB05&0h!Sa;wIigX{vbGS?WfFpKW1j$`xxe@A0+Fjute=e);0#qr=|N;g;Qp}26- zm!wpQe2Y-OMxRZT!KmUk+r1SsoU&a;7EJgg5$6I(Z;bR({yW=V$Ml=nc3hdHZQXv7 zk&*ChA@K6Mqnq{Lef_ZWj5wLT-*hV3RZX5 zcaNEiT`9AAeK|ETMLBoO$)%0vU^|}jjQ=h(Pd8tzyomPJ&HV7%yc(yaoL-K4)b8u0 z-o!mp3>|%cjDtFz<`I6Kq*MkTy0gqRuu%`BM~{JXH<+tC2K3e5N;MPqbh$+S6#dsr zcdBVZ@Lsd6FJKRjy=c+pyH&M)s2MAZV?aF@5f7?v+zrnc{ysKd4YGJY8r);1Hj|K0 z!w1X$Ox?tSP~U)kl0lSIBL^ArD!&mUQ#f%lvi)leQC!&QnN(xX^%&4?Ujx@}7{&jP#Ju`vyy4=?)Zv=teG9Yg@>H*$! z+yL?q3Ddd+-D5=3wK)xtfKT7+nCr}Zjylu%D!DTduwszFjDqffoh7iB{RjcWZN88& z$FclLXg-cn**tVI$x?5QGU)o>-jP&JEkx^eB+L-WZ~#jz!EdblBCYn%h*gswL$I=g z^$IUZk6}Ibrt8N3ZfW}b=&I$1a_@xH&laJi*ojhPvP*Az2T0lQ`8{>~@+-KLpJu)` z*3{@0^GtT>e@6L6z4~*%UUXv4(v-AGzvV`!?5MQO5K)e76kr3;19Tpms$7x|Y{_<0kcg`LIGFLU7-5 z`4|*~xZ6AGJt^6<4jaE(n6Lm<$fFk=KXB(=tZUnjM~ADgGs>S*y2{yG4U=ZCPhPB7 zcw|};z2E1{gK+;~Wph{Dc^OwheF47*ZcWloE!Z3H08r|^`RJB=ay@1~Lrf|?_i}Oq z_Le}7F&`ZCAHp~R`b<(I(-E+n)U*W}FCSIUl=80$O<3a>@VEiUJlIB-*!%-KJ>clx zir7r*D}od?i|LW;nZ?`N-T@*Xq821TCtAK`At1%NLv+EyIZlPC0Db zw8pq&a=*9#c*;b-=^s$~0!l zR1O+>`Qt&-V8#WB#2a;5zaO*d|2X=MKRT!vVN>vu9AdajR3$|?CLAysMXiKswYCvv z<+?=2wa$$sJYuA$g>7~wV7M?w;qyLMxSS7oh{cj(NfhFPJN0!f)!=OUGarR?RM&(h zdf7wMqQQhVSgSh9Kg%E4Y7_}+5)}+glIDLpOQ0?e$$d?F6lXsj2X$*|)8H{&{!4ikZ?z@fMO({gF9N zu>g==a|C=GOqkwE6WE-Lkdb?&zMb={5iO$rKcCl64f;TD3;OnXf4wYujDBCLfN!M& zR^w~2O31F_(5PN*@GERUVeqt(WNxbaKO}vmXdBFc&SrR>{wauhO;hJ|R%$f;T4}%6 zy5`l9syWsC`N<-=ge33oQlKzm`*_|~3F(eD$s1^Ik$eoN&gi5Lk1|ER6lkmtwDL;)N;hf;W3cxK^K;t6>*csn3N)T?= zeC?<4fNY2r@T{ZFCNuzyTr%_nxB!aJ#BUuW1DhLQ@DJSoX20Qjq5T6d-27+aU(7Oz zO$W*ULe8+2Fxo+Qe6%ZYRGXqtBuUyzx8O}UPyWk_cOy+ z)1A;6-Ie*0@5VN^`g3`jtCLXa@y~p>gkVw%q8~J-RC`qdt^D&BVgnzEKHts0!=v?{ zU+Kr}a=`Ym>)RHd8c^wi%Co2dmD@33nl9U>VL8+fYvvgD;w90j)1pW(Y|WT27U<8l zg(D{bGUr-ep5#fS7=s;gGf$d>4VhSEpI4ig4=;HAp)DAN@82_oXQkv;SU%A1l zFZqa<_ChV06y4axE2)>m`(+k1jj&c-ii3>YCVkWg!~$C4T)aDm=J5iD2K;AQuOr2= z%6<-Oj=K;2lgkRo`-<9qCRXQ|6@cY zHY=bRN59BE#1IE@KIEp*`E{iE(C1K}Vp8Omr5surt3o{K3u-1mlrd2oNAVxCv3&+>`)2uZuPU+`am?X zQ~1DViS{Fkd8G-5=e^{uG!yU^)n`$>Wq)a?p4Xv@bRHzL&7IBSk6^rxkrn11^|W*f z(R(0Urir}kuSgmYbjQ(2Yh@xz4$}X8;xm7eVsiJ3{FN8`dFBstU0Q{Tzr2(SWg^YW zo!;p>AQ}f}H{fIoC=2g^;GcLAwB7=vB4BR<5HuSZfxNr}AliZ&d`35cdP#+RrlGuA zBpLVjS)5<&bG*|V>y@YEbLndRp@Och^1_Yrzgxd*`4YL<3+@B*bC?2}%pHPP^&+SR z;RuPwfd^(dO*bXAbgwmJPWv*~Uea4RiCI4%S#B0N0%)8z58NZl5oq-UyFo(xY1JQm ztr@=zrfwm~U;5h&wtE(RDN)Js_i$KJhcUC_IQh$S@b&($>|HFVcWDLPu+(8NHw%nG7 z=eyGL7N)7VS>l;z?YZd&wFLe9n1@u!5t1n(1a3bQZVG9Sm{SuzhRK$GbS&w?IcaGo z4jA?+m(6>SktF>tqwU08S|k0d8M7yWf`@Z%i)&lv6?4em`j1goNr$syM%M;Py_d=S zqxHP6WGVF2pE+$C;ttvxd6I`$k2M6-a@KT}ALFfAM{kiwf6em58GiZQ%ZzYlh1P;^ ziO>6i=#-XVn6xHxOCK1>fgL)ln}exSNcO9nlDU2QBt}%dNd`IGK^bt}Maxcx6?Si6 zV|nACa0dTy&tmE(rB!AEk4sH}!JdXsD0N!aL^3P$SH_t%Lxdb>%P4Sav~Q2~)D2kD zU_~()2B3!lJ>p>W!u+MaSYuPeiy$1uS%&6#Rc6A0fv6tbt*Fp{S0dgAmu(p=Qufg?b^khJAxx zC#7p+x@X4Mj%4Tx#&QGCJ^@lGsD6@WqpZPA&J!dJemkt5Q8gTOB)32PH6%H zxDu0JKqSDzEp0`?eBCb}EWYbMmAPQV8>6!CWxH|rgcjb2 zH9EZSHB$_>t`{~&fWGiHZ0;3r-BP8`yA{GC-jW;CRQuVZL-@VM08`N@FdE;~RPI`~&wF z`+Xv+vs^985hQ2%EPOq66Zr_Z4A|KKB}W3K-YV2Bv!P+%ZB`E4PHs=|5!lzLMmZR4 zz-HcDA9PmG5HI_*ImFo9(W@w&aBv}AZwZJn8|5|XFM64#b^YBcy`1NmLv^5K#N#{u z3gu-ieqPyK2LY3T&0U=&(dUjDBeS3BO^-)~FC*~xKoR}hlF;(&)2u-k8~m+myRo@-`h2lZS%!2D(H}qM z2`qce&g=lDFOB{{+X1D>2tO4Yc~|eQkcRIuGGV;E469pK^9_&e+rziE#^^!>&GmC7 zH)?M$i)(T9{=rus4p;OfIjvcr97~3#&p~B^? z{ycBzE`#4pzMFnGyL>G3aD{4CQT@}9_ zWgJrwtt4ICi+IU+uMLAd%}#ihr?tsd)~_cLz3(m`y+>$ zh|}ie>}d$$UNInk-2YjuR&%m)WZ7Df)y}m)730^xQ!J?+eL2sw)Lnt?{QB%595byk z|CY&*hFmINUgVJD30YQ=n+~UaeNr3N^;Jxbw|%rR;vQAL{!6>WWJ8Tl%%RA&!emuu z$`>q^3ix^YmMU&M+Un)jYG-MiyVLLeJu|gg-n-51{QfwgP4FVs-44Lcui!lBU%c0F z4PDfNTfLb}eWMXq9iF-7pXwur+8a3SZq8YHIf6l78chSW_JC;mkM1YhfTP)>Rs@wv z*2g-YO)at1{>mz&rPiMObWk@fj0fZE zU|4e%Hhu<~cnn;(e*@31m};s$dQ}{94W;l&0!yk*WAlKkh)TV%AcMz18w*XGEb`*| z!SD$BPgp=)2S|H2Hxy`)R%lH>@BPWt@9PKGi+lOfi1SHI4F`YvzMuKn{xzX!7OFnj z31+H}0R8JdqY!ee4Bg2~KIc25Sk33hx8tn?ws{q4&K6U5c528s}nNYFKpHV8L) z!bhMD?YuLGcj&5TG?+4yHvUkF)3bc03K|F`li8k(HAr1u&?87mUEu294BYx| zcp{H>m&b!apl0@G^0Bsz&yoIX#hEl7#G9E8m>J9O?dcnCWiCv)c+)Y05Eeb#D#ctw zL(zwfPfz<&_+%%NCJBU`Il_-X1#$}rwkk39`5@GPNBX#Pq`>6z%T8LZ2CqOQ1- zK%x{zS;M+qya&5NIdC0-2!8U!;mlyhM|Il-e~qO+Jr3G}R_-~Z?84BW#TnQ#N5ZBJ z?ZC|UYY5Y@sy{;{p+}s8i?D(}^Ilti#kN+{6mmgq*9-xo|6>gu8g|I^T0c#W>9l~4 zcJC<&zW;(-2E+gUN8yp+@K?e*2tnsvc7{mkXv@-|`v9e6vu5+-!F2uoX4Y3EeM``U z#6WNF!*1FE3$oRrY77^FVNbPbP6+#Kf01 z?ZQfifVlKN3P64w(u+ypAEaWe2j1C>hV{!a`rR=J5DAdDq3~!iz(e^&dc9I>$&zZi9;S6%}{BH z_$bUvE~%eLIw{qx!>CK@f;GBb0?zMJDCJ1-m-{o@&se5GQQ5G5o`;p{AKWjlB{nye zHo;y*1o*^@S}6JkXhQVxn%uh{`>nmpke}Age}ZN8<*yqLoligV_9UbCU@l6%-WMH7 z2XBHYpAs8>>{T}Z(Q&`MirXMy&;lHcp>ub-><=!UOn;JaIptS(R0aJ<*ciK09(Se@ z3J)$&prFL(D zFI__f;*@fp;Ic3pN!UrHEQ=8qwcL!lDNu(LULuY?9uhXZL9yk}>)?nGgchdt)LXCE z$wxgr{r-ztp`6{{gpKYb?mmi{48HE~s7`+5N#4$0^h3oG#uW_l_N@_z{Y zo<#Y?x`!gF+ksm< z4+@ge8SL28X*`G#p40jaHs=ilZ~TrCN#HbY6=NyUe{|{?=6=5d!7yX@zx7=*NZImd zoYYqc5>BVvry+X0hwG8<5c8{zRrB>M=S5q>ZwGCTp(5iR{`~G3UZ0rzX>q*-aYd}b zk@<|Oh`RG+C#$XqouNT>!r-!8x%Ww^Y=P#y28uEAf?JD~p$&{ze#Rwy_<3YvbC zXW>#Ga#s-Ni}t8OWU8Xw+0-i(^zQjT0MvArmAF7x4 zp0hzgsldcI0+xnO(RW5bq<)EH<2Vx+&Jl)yD3{tnas^_pojNgsAgIIahnz0<)T3KR zFMx_{k+DKWA|OIw0S^V2y@?D^C?R*~2hM}=R-m;3-rh&IddE5e5%=9;4UPbf*MFk! z%2wRiEdeuQz6n5ngf6cvpsN*%yI`6S9r!IHp)(*o5};`!Y|d-UdrXA=F-fXSttzG0 z;pSoF-hY$(8|XR)ZpxjYBnL z{*sX;Xt)sezdU{iW`P9Z5!JxqD=Ix!FPrgj&%(pd-}Yr-YS}mYQD0pB9e+W$y-Atsj}UH) zw~aGyPl8le;w32G-5b;)su_5h+%jz2;JQvCM4s4KCcf-~5={j~ya@P*O0PL$GMqf_ zZ_(ec)OIipIR4jxQa#|e0g|KV@UwZKop4o7-DA4Mr#_!j&j`n|zjRwfD+j}OeuVAiOjxG=q~kh&!a{UB=%u2u%ji+u7X5_AKWo|?J5pk{f}?+2zt2S3izWJ+$Qbz^(G7m10Z{)I0o?%e z4^ez^t6aYby5t7c%9F3rCua&ZF?ql9PqHpe*gkd0bCQ)!ET|&-}r!RUVrCRc5 z^m_>$mzhf#x-+*AGuT4%HG_J6uz-#U+(Y85Ni7!B^EX_jXq!%aW~l2SGm(;c39I!7 zZu930>4rmLFFZ@v)j$KxNtN(;|LPb!>DyCZXAHc}KTL>D^_v|Te_TtECy*%0{J7-& zwZv@o^OZ0|r)#bB{uf~}+BciKYSvZw{}=z?foo~okMh>;!vhcM#I^`TV-qU3v}XnC z^!uonj{|)>Mw`>3|qTi@f(8-JC6KTz!NY4Ho;3H)XVAbDlpHnGdVXy%v zc~R+${^xgwk?@xQ(zgzTDsLyBL#53sC9agEh-uth1g)YR|i=axz z#?Ihqz(`pP?8Rd{Cpk_7>8=JCzhr}$fE3RqU#h%#%F7Eh3=8tNg6PGH2UiH+Hvc`= zV(_zVj${P6@MJ5fJe)shB;=h52^qo=dJfhp{Qu^m{)P-Hmj%Et-?T|)ttjsGOi)>s$tPSrJB#}hfs73BN) z`a{<7A7T3Ib1Gr>?YqC$ZW#}YF<&p3v#TjbLMOmGN&q=)q#miUGD^^!(Rsug@$}-U zcFKxS*P9~qo@;r9qeXlXy@#~btsV)eNvBkp)~acsS8FW!-KMGz+lHY>eA2;oY6wPo zyK2R#EC+>-(pna!b(W}KWv`t}A{0&4pS3VQv(+&9ijI%bRRgewBNy0m z-_o7`!fu%I4L5j z+rpw7yHN@@zRHXx<(8jyXZTzo3|iEsGIeiC#$qSzjXo3ZKauGW5p@1QYkfV4u8z&2 z%a_x3a>Ml%tu4}S&D=ob+uaE3z@u4h3A(=cu3Mi|0bC5`Y*8>eQ1!ps7{?z)ij1Mh zzXf!;ndoAVG7i4cy?^|@qigQ5cx?@C`uwsUn-K}A4bCxR_#ODX0j6M1Mo6<%5QkEl zI`*O6>*pWzdk+@>7aFSO_=5LMkcD$<6ET|;{xV54@Pjy9vP8lt)e$Dmiu z`$IoGR+__^eND8#${5jmV?R374HW`> z=U@}PG;Yf&sS*g-hBi775*(COeBn`a?!W~2?xIV$2fr@i#h~ITGTjS#w;&Hd`TMx@ zx-3aQoa6j9{QxsJnG4HJ`*YTS4{*}#n1k4AL!WG_dM#z39f|d-=E=Be>w%b)gU`DC z=HM{)`sc||HoERco39lS7|4$Ohb;pI;w+EBk%iC`R`;fw0Bl1(9SF?0`FMSN<4qoo~5FFGp4cU1xX2q@mNgSSa zof+R{ySQS*J5QabFPH(Bc==v&LGu^cd%A^uS&aE_SM!BZi+QtPO-?t1uUCQ0zpDkW zQ~1>}jP@&~zZB0Sfh>#?OhF;V9Y2FC5EpRU`WUzZG<0<6!p~K@{tNaxKk{h5=R

mhAdnTtjv@ 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 literal 0 HcmV?d00001 From 3e2845181c5f33980ffbdb96714f6733439bd93a Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 17 Mar 2026 17:38:09 -0700 Subject: [PATCH 252/289] bumping next version --- ui/litellm-dashboard/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/litellm-dashboard/package.json b/ui/litellm-dashboard/package.json index 2a9bb3e5e2..fce2e09b54 100644 --- a/ui/litellm-dashboard/package.json +++ b/ui/litellm-dashboard/package.json @@ -35,7 +35,7 @@ "jwt-decode": "^4.0.0", "lucide-react": "^0.513.0", "moment": "^2.30.1", - "next": "^16.1.6", + "next": "^16.1.7", "openai": "^4.93.0", "papaparse": "^5.5.2", "react": "^18.3.1", From 62835ff03dbbcd4d02cc49163a99a1e726ff2dd9 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 17 Mar 2026 17:44:01 -0700 Subject: [PATCH 253/289] adding package-lock --- ui/litellm-dashboard/package-lock.json | 164 ++++++++++++++++++------- 1 file changed, 118 insertions(+), 46 deletions(-) diff --git a/ui/litellm-dashboard/package-lock.json b/ui/litellm-dashboard/package-lock.json index c062356ebb..2b62c1c16b 100644 --- a/ui/litellm-dashboard/package-lock.json +++ b/ui/litellm-dashboard/package-lock.json @@ -23,7 +23,7 @@ "jwt-decode": "^4.0.0", "lucide-react": "^0.513.0", "moment": "^2.30.1", - "next": "^16.1.6", + "next": "^16.1.7", "openai": "^4.93.0", "papaparse": "^5.5.2", "react": "^18.3.1", @@ -92,6 +92,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -1773,6 +1774,7 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -1783,6 +1785,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1792,12 +1795,14 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1828,9 +1833,9 @@ } }, "node_modules/@next/env": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", - "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.7.tgz", + "integrity": "sha512-rJJbIdJB/RQr2F1nylZr/PJzamvNNhfr3brdKP6s/GW850jbtR70QlSfFselvIBbcPUOlQwBakexjFzqLzF6pg==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -1844,9 +1849,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz", - "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.7.tgz", + "integrity": "sha512-b2wWIE8sABdyafc4IM8r5Y/dS6kD80JRtOGrUiKTsACFQfWWgUQ2NwoUX1yjFMXVsAwcQeNpnucF2ZrujsBBPg==", "cpu": [ "arm64" ], @@ -1860,9 +1865,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", - "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.7.tgz", + "integrity": "sha512-zcnVaaZulS1WL0Ss38R5Q6D2gz7MtBu8GZLPfK+73D/hp4GFMrC2sudLky1QibfV7h6RJBJs/gOFvYP0X7UVlQ==", "cpu": [ "x64" ], @@ -1876,9 +1881,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", - "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.7.tgz", + "integrity": "sha512-2ant89Lux/Q3VyC8vNVg7uBaFVP9SwoK2jJOOR0L8TQnX8CAYnh4uctAScy2Hwj2dgjVHqHLORQZJ2wH6VxhSQ==", "cpu": [ "arm64" ], @@ -1892,9 +1897,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", - "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.7.tgz", + "integrity": "sha512-uufcze7LYv0FQg9GnNeZ3/whYfo+1Q3HnQpm16o6Uyi0OVzLlk2ZWoY7j07KADZFY8qwDbsmFnMQP3p3+Ftprw==", "cpu": [ "arm64" ], @@ -1908,9 +1913,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", - "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.7.tgz", + "integrity": "sha512-KWVf2gxYvHtvuT+c4MBOGxuse5TD7DsMFYSxVxRBnOzok/xryNeQSjXgxSv9QpIVlaGzEn/pIuI6Koosx8CGWA==", "cpu": [ "x64" ], @@ -1924,9 +1929,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", - "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.7.tgz", + "integrity": "sha512-HguhaGwsGr1YAGs68uRKc4aGWxLET+NevJskOcCAwXbwj0fYX0RgZW2gsOCzr9S11CSQPIkxmoSbuVaBp4Z3dA==", "cpu": [ "x64" ], @@ -1940,9 +1945,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", - "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.7.tgz", + "integrity": "sha512-S0n3KrDJokKTeFyM/vGGGR8+pCmXYrjNTk2ZozOL1C/JFdfUIL9O1ATaJOl5r2POe56iRChbsszrjMAdWSv7kQ==", "cpu": [ "arm64" ], @@ -1956,9 +1961,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", - "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.7.tgz", + "integrity": "sha512-mwgtg8CNZGYm06LeEd+bNnOUfwOyNem/rOiP14Lsz+AnUY92Zq/LXwtebtUiaeVkhbroRCQ0c8GlR4UT1U+0yg==", "cpu": [ "x64" ], @@ -1975,6 +1980,7 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -1988,6 +1994,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -1997,6 +2004,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -2320,7 +2328,7 @@ "version": "1.58.1", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.1.tgz", "integrity": "sha512-6LdVIUERWxQMmUSSQi0I53GgCBYgM2RpGngCPY7hSeju+VrKjq3lvs7HpJoPbDiY5QM5EYRtRX5fvrinnMAz3w==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "playwright": "1.58.1" @@ -3425,12 +3433,14 @@ "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.2.48", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.48.tgz", "integrity": "sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w==", + "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -3472,6 +3482,7 @@ "version": "0.26.0", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.26.0.tgz", "integrity": "sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA==", + "dev": true, "license": "MIT" }, "node_modules/@types/unist": { @@ -4332,12 +4343,14 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, "license": "MIT" }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -4351,6 +4364,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -4363,6 +4377,7 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, "license": "MIT" }, "node_modules/argparse": { @@ -4734,6 +4749,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4759,6 +4775,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -4874,6 +4891,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -4997,6 +5015,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, "license": "MIT", "dependencies": { "anymatch": "~3.1.2", @@ -5021,6 +5040,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -5096,6 +5116,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -5156,6 +5177,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -5569,12 +5591,14 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, "license": "Apache-2.0" }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, "license": "MIT" }, "node_modules/doctrine": { @@ -6488,6 +6512,7 @@ "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -6520,6 +6545,7 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -6557,6 +6583,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -6717,6 +6744,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -6867,6 +6895,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -7364,6 +7393,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -7416,6 +7446,7 @@ "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -7476,6 +7507,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7521,6 +7553,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -7569,6 +7602,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -7845,6 +7879,7 @@ "version": "1.21.7", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, "license": "MIT", "bin": { "jiti": "bin/jiti.js" @@ -8130,6 +8165,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -8142,6 +8178,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, "license": "MIT" }, "node_modules/locate-path": { @@ -8595,6 +8632,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -9167,6 +9205,7 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -9180,6 +9219,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -9294,6 +9334,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0", @@ -9343,14 +9384,14 @@ "license": "MIT" }, "node_modules/next": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", - "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/next/-/next-16.1.7.tgz", + "integrity": "sha512-WM0L7WrSvKwoLegLYr6V+mz+RIofqQgVAfHhMp9a88ms0cFX8iX9ew+snpWlSBwpkURJOUdvCEt3uLl3NNzvWg==", "license": "MIT", "dependencies": { - "@next/env": "16.1.6", + "@next/env": "16.1.7", "@swc/helpers": "0.5.15", - "baseline-browser-mapping": "^2.8.3", + "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" @@ -9362,14 +9403,14 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.1.6", - "@next/swc-darwin-x64": "16.1.6", - "@next/swc-linux-arm64-gnu": "16.1.6", - "@next/swc-linux-arm64-musl": "16.1.6", - "@next/swc-linux-x64-gnu": "16.1.6", - "@next/swc-linux-x64-musl": "16.1.6", - "@next/swc-win32-arm64-msvc": "16.1.6", - "@next/swc-win32-x64-msvc": "16.1.6", + "@next/swc-darwin-arm64": "16.1.7", + "@next/swc-darwin-x64": "16.1.7", + "@next/swc-linux-arm64-gnu": "16.1.7", + "@next/swc-linux-arm64-musl": "16.1.7", + "@next/swc-linux-x64-gnu": "16.1.7", + "@next/swc-linux-x64-musl": "16.1.7", + "@next/swc-win32-arm64-msvc": "16.1.7", + "@next/swc-win32-x64-msvc": "16.1.7", "sharp": "^0.34.4" }, "peerDependencies": { @@ -9505,6 +9546,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -9523,6 +9565,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -9867,6 +9910,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, "license": "MIT" }, "node_modules/path-scurry": { @@ -9913,6 +9957,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -9925,6 +9970,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -9934,6 +9980,7 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -9943,7 +9990,7 @@ "version": "1.58.1", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.1.tgz", "integrity": "sha512-+2uTZHxSCcxjvGc5C891LrS1/NlxglGxzrC4seZiVjcYVQfUa87wBL6rTDqzGjuoWNjnBzRqKmF6zRYGMvQUaQ==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "playwright-core": "1.58.1" @@ -9962,7 +10009,7 @@ "version": "1.58.1", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.1.tgz", "integrity": "sha512-bcWzOaTxcW+VOOGBCQgnaKToLJ65d6AqfLVKEWvexyS3AS6rbXl+xdpYRMGSRBClPvyj44njOWoxjNdL/H9UNg==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" @@ -9985,6 +10032,7 @@ "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, "funding": [ { "type": "opencollective", @@ -10013,6 +10061,7 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", @@ -10030,6 +10079,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "dev": true, "funding": [ { "type": "opencollective", @@ -10055,6 +10105,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, "funding": [ { "type": "opencollective", @@ -10097,6 +10148,7 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -10122,6 +10174,7 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -10135,6 +10188,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, "license": "MIT" }, "node_modules/prelude-ls": { @@ -10248,6 +10302,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, "funding": [ { "type": "github", @@ -11036,6 +11091,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, "license": "MIT", "dependencies": { "pify": "^2.3.0" @@ -11045,6 +11101,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -11057,6 +11114,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -11354,6 +11412,7 @@ "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.16.1", @@ -11394,6 +11453,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -11449,6 +11509,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "funding": [ { "type": "github", @@ -12089,6 +12150,7 @@ "version": "3.35.1", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", @@ -12124,6 +12186,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -12159,6 +12222,7 @@ "version": "3.4.19", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "dev": true, "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", @@ -12196,6 +12260,7 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -12212,6 +12277,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -12239,6 +12305,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0" @@ -12248,6 +12315,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" @@ -12289,6 +12357,7 @@ "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -12355,6 +12424,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -12442,6 +12512,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, "license": "Apache-2.0" }, "node_modules/tsconfig-paths": { @@ -12558,7 +12629,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -12760,6 +12831,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, "license": "MIT" }, "node_modules/uuid": { @@ -13213,7 +13285,7 @@ "version": "8.19.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" From fc315ab4af0b05b1b025db6f2a9d9e798da7c70c Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Tue, 17 Mar 2026 17:45:16 -0700 Subject: [PATCH 254/289] docs(mcp_zero_trust): add MCP zero trust auth guide (#23918) * docs(mcp_zero_trust): add MCP zero trust auth guide with hero image * fix(docs): move hero image to static/img/ for Docusaurus build --- docs/my-website/docs/mcp_zero_trust.md | 294 ++++++++++++++++++ .../static/img/mcp_zero_trust_gateway.png | Bin 0 -> 301348 bytes 2 files changed, 294 insertions(+) create mode 100644 docs/my-website/docs/mcp_zero_trust.md create mode 100644 docs/my-website/static/img/mcp_zero_trust_gateway.png diff --git a/docs/my-website/docs/mcp_zero_trust.md b/docs/my-website/docs/mcp_zero_trust.md new file mode 100644 index 0000000000..8f431523cb --- /dev/null +++ b/docs/my-website/docs/mcp_zero_trust.md @@ -0,0 +1,294 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# MCP Zero Trust Auth (JWT Signer) + +![Zero Trust MCP Gateway](/img/mcp_zero_trust_gateway.png) + +MCP servers have no built-in way to verify that a request actually came through LiteLLM. Without this guardrail, any client that can reach your MCP server directly can call tools — bypassing your access controls entirely. + +`MCPJWTSigner` fixes this. It signs every outbound tool call with a short-lived RS256 JWT. Your MCP server verifies the signature against LiteLLM's public key. Requests that didn't go through LiteLLM have no valid signature and are rejected. + +--- + +## Basic setup + +Add the guardrail to your config and point your MCP server at LiteLLM's JWKS endpoint. Every tool call gets a signed JWT automatically — no changes needed on the client side. + +```yaml title="config.yaml" +mcp_servers: + - server_name: weather + url: http://localhost:8000/mcp + transport: http + +guardrails: + - guardrail_name: mcp-jwt-signer + litellm_params: + guardrail: mcp_jwt_signer + mode: pre_mcp_call + default_on: true + issuer: "https://my-litellm.example.com" # defaults to request base URL + audience: "mcp" # default: "mcp" + ttl_seconds: 300 # default: 300 +``` + +**Bring your own signing key** — recommended for production. Auto-generated keys are lost on restart. + +```bash +export MCP_JWT_SIGNING_KEY="-----BEGIN RSA PRIVATE KEY-----\n..." +# or point to a file +export MCP_JWT_SIGNING_KEY="file:///secrets/mcp-signing-key.pem" +``` + +**Build a verified MCP server with [FastMCP](https://gofastmcp.com):** + +```python title="weather_server.py" +from fastmcp import FastMCP, Context +from fastmcp.server.auth.providers.jwt import JWTVerifier + +auth = JWTVerifier( + jwks_uri="https://my-litellm.example.com/.well-known/jwks.json", + issuer="https://my-litellm.example.com", + audience="mcp", + algorithm="RS256", +) + +mcp = FastMCP("weather-server", auth=auth) + +@mcp.tool() +async def get_weather(city: str, ctx: Context) -> str: + caller = ctx.client_id # JWT `sub` — the verified user identity + return f"Weather in {city}: sunny, 72°F (requested by {caller})" + +if __name__ == "__main__": + mcp.run(transport="http", host="0.0.0.0", port=8000) +``` + +FastMCP fetches the JWKS automatically and re-fetches when the signing key changes. + +LiteLLM publishes OIDC discovery so MCP servers find the key without any manual configuration: + +``` +GET /.well-known/openid-configuration → { "jwks_uri": "https:///.well-known/jwks.json" } +GET /.well-known/jwks.json → { "keys": [{ "kty": "RSA", "alg": "RS256", ... }] } +``` + +> **Read further only if you need to:** thread a corporate IdP identity into the JWT, enforce specific claims on callers, add custom metadata, use AWS Bedrock AgentCore Gateway, or debug JWT rejections. + +--- + +## Thread IdP identity into MCP JWTs + +By default the outbound JWT `sub` is LiteLLM's internal `user_id`. If your users authenticate with Okta, Azure AD, or another IdP, the MCP server sees a LiteLLM-internal ID — not the user's email or employee ID. + +With verify+re-sign, LiteLLM validates the incoming IdP token first, then builds the outbound JWT using the real identity claims from that token. The MCP server gets the user's actual identity without ever having to trust the original IdP directly. + +```yaml title="config.yaml" +guardrails: + - guardrail_name: mcp-jwt-signer + litellm_params: + guardrail: mcp_jwt_signer + mode: pre_mcp_call + default_on: true + issuer: "https://my-litellm.example.com" + + # Validate the incoming Bearer token against the IdP + access_token_discovery_uri: "https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration" + verify_issuer: "https://login.microsoftonline.com/{tenant}/v2.0" + verify_audience: "api://my-app" + + # Which claim to use for `sub` in the outbound JWT — first non-empty value wins + end_user_claim_sources: + - "token:sub" # from the verified incoming JWT + - "token:email" # fallback to email + - "litellm:user_id" # last resort: LiteLLM's internal user_id +``` + +If the incoming token is **opaque** (not a JWT — some IdPs issue these), add an introspection endpoint. LiteLLM will POST the token to it (RFC 7662) and use the returned claims: + +```yaml + token_introspection_endpoint: "https://idp.example.com/oauth2/introspect" +``` + +**Supported `end_user_claim_sources` values:** + +| Source | Resolves to | +|--------|-------------| +| `token:` | Any claim from the verified incoming JWT (e.g. `token:sub`, `token:email`, `token:oid`) | +| `litellm:user_id` | LiteLLM's internal user ID | +| `litellm:email` | User email from LiteLLM auth context | +| `litellm:end_user_id` | End-user ID if set separately | +| `litellm:team_id` | Team ID from LiteLLM auth context | + +--- + +## Block callers missing required attributes + +Some MCP servers expose sensitive operations that should only be reachable by verified employees — not service accounts, not external API keys. You can enforce this at the LiteLLM layer so the MCP server never receives the request at all. + +`required_claims` rejects with `403` if the incoming token is missing any listed claim. `optional_claims` forwards claims that are useful but not mandatory. + +```yaml title="config.yaml" +guardrails: + - guardrail_name: mcp-jwt-signer + litellm_params: + guardrail: mcp_jwt_signer + mode: pre_mcp_call + default_on: true + + access_token_discovery_uri: "https://idp.example.com/.well-known/openid-configuration" + + # Service accounts without `employee_id` are blocked before the tool runs + required_claims: + - "sub" + - "employee_id" + + # Forward these into the outbound JWT when present — skipped silently if absent + optional_claims: + - "groups" + - "department" +``` + +**What the client sees when blocked:** +```json +HTTP 403 +{ "error": "MCPJWTSigner: incoming token is missing required claims: ['employee_id']. Configure the IdP to include these claims." } +``` + +--- + +## Add custom metadata to every JWT + +Your MCP server may need context that LiteLLM doesn't carry natively — which deployment sent the request, a tenant ID, an environment tag. Use claim operations to inject, override, or strip claims from the outbound JWT. + +```yaml title="config.yaml" +guardrails: + - guardrail_name: mcp-jwt-signer + litellm_params: + guardrail: mcp_jwt_signer + mode: pre_mcp_call + default_on: true + + # add: insert only when the key is not already in the JWT + add_claims: + deployment_id: "prod-us-east-1" + tenant_id: "acme-corp" + + # set: always override — even if the claim came from the incoming token + set_claims: + env: "production" + + # remove: strip claims the MCP server shouldn't see + remove_claims: + - "nbf" # some validators reject nbf; remove it if yours does +``` + +Operations run in order — `add_claims` → `set_claims` → `remove_claims`. `set_claims` always wins over `add_claims`; `remove_claims` beats both. + +--- + +## AWS Bedrock AgentCore Gateway + +Bedrock AgentCore Gateway uses two separate JWTs: one to authenticate the transport connection and another to authorize tool calls. They need different `aud` values and TTLs — a single JWT won't work for both. + +LiteLLM can issue both in one hook and inject them into separate headers: + +```yaml title="config.yaml" +guardrails: + - guardrail_name: mcp-jwt-signer + litellm_params: + guardrail: mcp_jwt_signer + mode: pre_mcp_call + default_on: true + issuer: "https://my-litellm.example.com" + audience: "mcp-resource" # for the MCP resource layer + ttl_seconds: 300 + + # Second JWT for the transport channel — same sub/act/scope, different aud + TTL + channel_token_audience: "bedrock-agentcore-gateway" + channel_token_ttl: 60 # transport tokens should be short-lived +``` + +LiteLLM injects two headers on every tool call: +- `Authorization: Bearer ` — audience `mcp-resource`, TTL 300s +- `x-mcp-channel-token: Bearer ` — audience `bedrock-agentcore-gateway`, TTL 60s + +Both tokens are signed with the same LiteLLM key, so your MCP server only needs to trust one JWKS endpoint. + +--- + +## Control which scopes go into the JWT + +By default LiteLLM generates least-privilege scopes per request: +- Tool call → `mcp:tools/call mcp:tools/{name}:call` +- List tools → `mcp:tools/call mcp:tools/list` + +If your MCP server does its own scope enforcement and needs a specific format, set `allowed_scopes` to replace auto-generation entirely: + +```yaml title="config.yaml" +guardrails: + - guardrail_name: mcp-jwt-signer + litellm_params: + guardrail: mcp_jwt_signer + mode: pre_mcp_call + default_on: true + + allowed_scopes: + - "mcp:tools/call" + - "mcp:tools/list" + - "mcp:admin" +``` + +Every JWT carries exactly those scopes regardless of which tool is being called. + +--- + +## Debug JWT rejections + +Your MCP server is returning 401 and you're not sure what's in the JWT. Enable `debug_headers` and LiteLLM adds a `x-litellm-mcp-debug` response header with the key claims that were signed: + +```yaml title="config.yaml" +guardrails: + - guardrail_name: mcp-jwt-signer + litellm_params: + guardrail: mcp_jwt_signer + mode: pre_mcp_call + default_on: true + debug_headers: true +``` + +Response header: +``` +x-litellm-mcp-debug: v=1; kid=a3f1b2c4d5e6f708; sub=alice@corp.com; iss=https://my-litellm.example.com; exp=1712345678; scope=mcp:tools/call mcp:tools/get_weather:call +``` + +Check that `kid` matches what the MCP server fetched from JWKS, `iss`/`aud` match your server's expected values, and `exp` hasn't passed. Disable in production — the header leaks claim metadata. + +--- + +## JWT claims reference + +| Claim | Value | +|-------|-------| +| `iss` | `issuer` config value (or request base URL) | +| `aud` | `audience` config value (default: `"mcp"`) | +| `sub` | Resolved via `end_user_claim_sources` (default: `user_id` → api-key hash → `"litellm-proxy"`) | +| `act.sub` | `team_id` → `org_id` → `"litellm-proxy"` (RFC 8693 delegation) | +| `email` | `user_email` from LiteLLM auth context (when available) | +| `scope` | Auto-generated per tool call, or `allowed_scopes` when set | +| `iat`, `exp`, `nbf` | Standard timing claims (RFC 7519) | + +--- + +## Limitations + +- **OpenAPI-backed MCP servers** (`spec_path` set) do not support JWT injection. LiteLLM logs a warning and skips the header. Use SSE/HTTP transport servers to get full JWT injection. +- The keypair is **in-memory by default** and rotated on each restart unless `MCP_JWT_SIGNING_KEY` is set. FastMCP's `JWTVerifier` handles key rotation transparently via JWKS key ID matching. + +--- + +## Related + +- [MCP Guardrails](./mcp_guardrail) — PII masking and blocking for MCP calls +- [MCP OAuth](./mcp_oauth) — upstream OAuth2 for MCP server access +- [MCP AWS SigV4](./mcp_aws_sigv4) — AWS-signed requests to MCP servers diff --git a/docs/my-website/static/img/mcp_zero_trust_gateway.png b/docs/my-website/static/img/mcp_zero_trust_gateway.png new file mode 100644 index 0000000000000000000000000000000000000000..3955cef0553247c7730aaef9f77dc24219c2a6c0 GIT binary patch literal 301348 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�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 + )} {endpointType === EndpointType.CHAT && chatUploadedImage && ( -
-
-
- {chatUploadedImage.name.toLowerCase().endsWith(".pdf") ? ( -
- -
- ) : ( - Upload preview - )} -
-
-
{chatUploadedImage.name}
-
- {chatUploadedImage.name.toLowerCase().endsWith(".pdf") ? "PDF" : "Image"} -
-
- -
-
+ )} {/* Code Interpreter indicator and sample prompts when enabled */} diff --git a/ui/litellm-dashboard/src/components/playground/chat_ui/FilePreviewCard.test.tsx b/ui/litellm-dashboard/src/components/playground/chat_ui/FilePreviewCard.test.tsx new file mode 100644 index 0000000000..1014df5d16 --- /dev/null +++ b/ui/litellm-dashboard/src/components/playground/chat_ui/FilePreviewCard.test.tsx @@ -0,0 +1,70 @@ +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { describe, expect, it, vi } from "vitest"; +import FilePreviewCard from "./FilePreviewCard"; + +function makeFile(name: string): File { + return new File(["dummy"], name, { type: "application/octet-stream" }); +} + +describe("FilePreviewCard", () => { + it("should render", () => { + render( + + ); + expect(screen.getByText("photo.png")).toBeInTheDocument(); + }); + + it("should display the file name", () => { + render( + + ); + expect(screen.getByText("my-screenshot.jpg")).toBeInTheDocument(); + }); + + it("should show 'Image' label for non-PDF files", () => { + render( + + ); + expect(screen.getByText("Image")).toBeInTheDocument(); + }); + + it("should show 'PDF' label for PDF files", () => { + render( + + ); + expect(screen.getByText("PDF")).toBeInTheDocument(); + }); + + it("should render an image preview when the file is not a PDF", () => { + render( + + ); + expect(screen.getByAltText("Upload preview")).toBeInTheDocument(); + }); + + it("should not render an image preview when the file is a PDF", () => { + render( + + ); + expect(screen.queryByAltText("Upload preview")).not.toBeInTheDocument(); + }); + + it("should call onRemove when the remove button is clicked", async () => { + const onRemove = vi.fn(); + const user = userEvent.setup(); + render( + + ); + await user.click(screen.getByRole("button")); + expect(onRemove).toHaveBeenCalledOnce(); + }); + + it("should treat .PDF (uppercase) as a PDF file", () => { + render( + + ); + expect(screen.getByText("PDF")).toBeInTheDocument(); + expect(screen.queryByAltText("Upload preview")).not.toBeInTheDocument(); + }); +}); diff --git a/ui/litellm-dashboard/src/components/playground/chat_ui/FilePreviewCard.tsx b/ui/litellm-dashboard/src/components/playground/chat_ui/FilePreviewCard.tsx new file mode 100644 index 0000000000..26bdf07eda --- /dev/null +++ b/ui/litellm-dashboard/src/components/playground/chat_ui/FilePreviewCard.tsx @@ -0,0 +1,45 @@ +import { DeleteOutlined, FilePdfOutlined } from "@ant-design/icons"; + +interface FilePreviewCardProps { + file: File; + previewUrl: string | null; + onRemove: () => void; +} + +function FilePreviewCard({ file, previewUrl, onRemove }: FilePreviewCardProps) { + const isPdf = file.name.toLowerCase().endsWith(".pdf"); + + return ( +
+
+
+ {isPdf ? ( +
+ +
+ ) : ( + Upload preview + )} +
+
+
{file.name}
+
+ {isPdf ? "PDF" : "Image"} +
+
+ +
+
+ ); +} + +export default FilePreviewCard; From b200d472f561f08842e89f05202bfb88a191862f Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Wed, 18 Mar 2026 13:38:23 +0530 Subject: [PATCH 269/289] fix: docker proxy guide --- .../docs/proxy/docker_quick_start.md | 71 ++++++++++--------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/docs/my-website/docs/proxy/docker_quick_start.md b/docs/my-website/docs/proxy/docker_quick_start.md index b2a6b1220f..4f61a56d83 100644 --- a/docs/my-website/docs/proxy/docker_quick_start.md +++ b/docs/my-website/docs/proxy/docker_quick_start.md @@ -1,4 +1,3 @@ - import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import Image from '@theme/IdealImage'; @@ -14,13 +13,13 @@ End-to-End tutorial for LiteLLM Proxy to: ## Pre-Requisites -- Install LiteLLM Docker Image **OR** LiteLLM CLI (pip package) +Choose your install method. **Docker Compose** users complete their full setup inside the tab and are done. **Docker** and **pip** users continue with the steps below the tabs. -``` +```bash docker pull docker.litellm.ai/berriai/litellm:main-latest ``` @@ -38,9 +37,11 @@ $ pip install 'litellm[proxy]' +Docker Compose bundles LiteLLM with a Postgres database. Follow the steps below — the proxy will be fully running by the end. + ### Step 1 — Pull the LiteLLM database image -LiteLLM provides a dedicated `litellm-database` image for proxy deployments that connect to Postgres. Pull it before starting Docker Compose. +LiteLLM provides a dedicated `litellm-database` image for proxy deployments that connect to Postgres. ```bash docker pull ghcr.io/berriai/litellm-database:main-latest @@ -50,11 +51,11 @@ See all available tags on the [GitHub Container Registry](https://github.com/Ber --- -### Step 2 — Create required config files +### Step 2 — Set up a database -You need three files in the same directory as `docker-compose.yml` before running `docker compose up`: `.env`, `config.yaml`, and `prometheus.yml`. +Complete all three config files **before** running `docker compose up`. The proxy server will not start correctly if any of these are missing. -### Step 2.1 — Create your `.env` +#### 2.1 — Get `docker-compose.yml` and create `.env` ```bash # Get the docker compose file @@ -73,9 +74,9 @@ echo 'AZURE_API_BASE="https://openai-***********/"' >> .env echo 'AZURE_API_KEY="your-azure-api-key"' >> .env ``` -### Step 2.2 — Create your `config.yaml` +#### 2.2 — Create `config.yaml` -Proxy and model configuration. If you use the default `docker-compose.yml`, the Postgres container is available at `db:5432`. +The default `docker-compose.yml` starts a Postgres container at `db:5432`. Your `config.yaml` must include `database_url` pointing to it: ```yaml model_list: @@ -87,17 +88,17 @@ model_list: api_version: "2025-01-01-preview" general_settings: - master_key: sk-1234 # 🔑 your proxy admin key (must start with sk-) + master_key: sk-1234 # 🔑 your proxy admin key (must start with sk-) database_url: "postgresql://llmproxy:dbpassword9090@db:5432/litellm" ``` :::tip -`database_url` is required for virtual keys, spend tracking, and the UI. If you want a managed database instead, replace it with your [Supabase](https://supabase.com/) or [Neon](https://neon.tech/) connection string. +`database_url` enables virtual keys, spend tracking, and the UI. Replace it with your [Supabase](https://supabase.com/) or [Neon](https://neon.tech/) connection string if you prefer a managed database. ::: -### Step 2.3 — Create your `prometheus.yml` +#### 2.3 — Create `prometheus.yml` -Metrics scrape config. This file **must exist as a file** before `docker compose up`. If it is missing, Docker auto-creates it as an empty directory, which causes the Prometheus container to fail. +This file **must exist as a file** before `docker compose up`. If it is missing, Docker auto-creates it as an empty directory and the Prometheus container fails to start. ```yaml global: @@ -110,19 +111,19 @@ scrape_configs: - targets: ["litellm:4000"] ``` -Also verify that the `config.yaml` volume mount and `--config` command are **not commented out** in your `docker-compose.yml`: +Also verify that the `config.yaml` volume mount and `--config` flag are **not commented out** in `docker-compose.yml`: ```yaml services: litellm: volumes: - - ./config.yaml:/app/config.yaml # ✅ must be uncommented + - ./config.yaml:/app/config.yaml # ✅ must be uncommented command: - - "--config=/app/config.yaml" # ✅ must be uncommented + - "--config=/app/config.yaml" # ✅ must be uncommented ``` :::warning -All three files must be present before running `docker compose up`. Missing files are the most common cause of startup errors. See the [Troubleshooting](#troubleshooting) section if you run into issues. +All three files (`.env`, `config.yaml`, `prometheus.yml`) must be present before running `docker compose up`. See [Troubleshooting](#troubleshooting) if you run into issues. ::: --- @@ -199,15 +200,18 @@ Navigate to **Virtual Keys** and click **+ Create New Key**: Virtual keys let you track spend, set rate limits, and control model access per user or team. + -## 1. Add a model +:::note Docker Compose users +Your setup is complete — the steps below are for **Docker** and **pip** users only. +::: -Control LiteLLM Proxy with a config.yaml file. +--- -Setup your config.yaml with your azure model. +## Step 1 — Add a model -Note: When using the proxy with a database, you can also **just add models via UI** (UI is available on `/ui` route). +Control LiteLLM Proxy with a `config.yaml` file. Create one with your Azure model: ```yaml model_list: @@ -278,19 +282,19 @@ $ litellm --config /app/config.yaml --detailed_debug +Confirm your config was loaded correctly — you should see this in the logs: -Confirm your config.yaml got mounted correctly - -```bash +``` Loaded config YAML (api_key and environment_variables are not shown): { -"model_list": [ -{ -"model_name ... + "model_list": [ + { + "model_name": ... ``` ### 2.2 Make Call +LiteLLM Proxy is 100% OpenAI-compatible. Test your model via `/chat/completions`: ```bash curl -X POST 'http://0.0.0.0:4000/chat/completions' \ @@ -390,9 +394,11 @@ Track spend and control model access via virtual keys for the proxy. ### Prerequisite — Set up a database -**Requirements** -- Need a postgres database (e.g. [Supabase](https://supabase.com/), [Neon](https://neon.tech/), etc) +:::note Docker Compose users +Your Postgres container is already running — skip ahead to [Create Key w/ RPM Limit](#create-key-w-rpm-limit) below. +::: +**Docker / pip users** — you need a Postgres database (e.g. [Supabase](https://supabase.com/), [Neon](https://neon.tech/), or self-hosted). Add `general_settings` to your `config.yaml`: ```yaml model_list: @@ -448,7 +454,6 @@ docker run \ --config /app/config.yaml --detailed_debug ``` - ### Create Key w/ RPM Limit Create a key with `rpm_limit: 1`. This will only allow 1 request per minute for calls to proxy with this key. @@ -696,15 +701,15 @@ If you see: Error: cannot create subdirectories in ".../prometheus.yml": not a directory ``` -Docker created `prometheus.yml` as an **empty directory** instead of a file. This happens when the file is missing at `docker compose up` time — Docker auto-creates missing bind-mount paths as directories. +Docker created `prometheus.yml` as an **empty directory** instead of a file. This happens when the file is missing at `docker compose up` time. -Fix it by deleting the directory and creating the file manually: +Fix it: ```bash rm -rf prometheus.yml ``` -Then create a valid `prometheus.yml` file (see [Step 2](#step-25--create-required-config-files)) and run `docker compose up` again. +Then create the file (see [Step 2.4](#step-24--create-prometheusyml)) and run `docker compose up` again. ### Non-root docker image? From 143cd66fa0ac7d46a33706b801617a5fe2f39c69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mr=2E=20=C3=85nand?= <73425223+Astrodevil@users.noreply.github.com> Date: Wed, 18 Mar 2026 17:19:27 +0530 Subject: [PATCH 270/289] docs: Learn page updates, card links, integrations, sidebar changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove Explore section from Learn page - Common Tasks: Stream Responses → core_request_response_patterns, Use Tools → tools_integrations, Add Routing → routing-load-balancing - Rename Router & Fallbacks card to Routing & Load Balancing on docs index - Fix Agent & MCP Gateway cards, add letta to Agent SDKs sidebar - Gateway quickstart: Make LLM Requests card first, rename from Connect SDKs - Integrations: fix View all links (observability_integrations, guardrail_providers) - SDK quickstart: remove Use Gateway card, keep When To Use Gateway section Made-with: Cursor --- docs/my-website/docs/index.md | 12 ++----- docs/my-website/docs/integrations/index.md | 2 +- .../docs/learn/gateway_quickstart.md | 12 +++---- docs/my-website/docs/learn/index.md | 36 ++----------------- docs/my-website/docs/learn/sdk_quickstart.md | 6 ---- docs/my-website/sidebars.js | 1 + 6 files changed, 14 insertions(+), 55 deletions(-) diff --git a/docs/my-website/docs/index.md b/docs/my-website/docs/index.md index 79b1b121e9..ca63c9e39f 100644 --- a/docs/my-website/docs/index.md +++ b/docs/my-website/docs/index.md @@ -401,22 +401,16 @@ LiteLLM is a unified gateway for **LLMs, agents, and MCP** — you don't need a columns={2} items={[ { -icon: "🤖", -title: "Agent & MCP Gateway", -description: "What you need to know about adopting A2A or multi-MCP with LiteLLM.", -to: "./agent_mcp_gateway", -}, -{ icon: "🔗", title: "A2A Agents", description: "Add and invoke A2A agents via the LiteLLM gateway.", -to: "./a2a", +to: "/docs/a2a", }, { icon: "🛠️", title: "MCP Gateway", description: "Central MCP endpoint with per-key access control.", -to: "./mcp", +to: "/docs/mcp", }, ]} /> @@ -430,7 +424,7 @@ columns={3} items={[ { icon: "🔀", -title: "Router & Fallbacks", +title: "Routing & Load Balancing", description: "Load balance across deployments and set automatic fallbacks.", to: "/docs/routing-load-balancing", }, diff --git a/docs/my-website/docs/integrations/index.md b/docs/my-website/docs/integrations/index.md index 67e087a976..0ad934d5b4 100644 --- a/docs/my-website/docs/integrations/index.md +++ b/docs/my-website/docs/integrations/index.md @@ -73,7 +73,7 @@ items={[ ]} /> -[View all observability integrations →](/docs/observability_integrations) +[View all observability integrations →](/docs/integrations/observability_integrations) --- diff --git a/docs/my-website/docs/learn/gateway_quickstart.md b/docs/my-website/docs/learn/gateway_quickstart.md index 2823e97e40..acec259758 100644 --- a/docs/my-website/docs/learn/gateway_quickstart.md +++ b/docs/my-website/docs/learn/gateway_quickstart.md @@ -124,6 +124,12 @@ If you need virtual keys, spend tracking, or the admin UI, add a database next. - ---- - ## Docs Map Use these when you already know the type of doc you want. diff --git a/docs/my-website/docs/learn/sdk_quickstart.md b/docs/my-website/docs/learn/sdk_quickstart.md index b4342d54cd..bdf7b63eb5 100644 --- a/docs/my-website/docs/learn/sdk_quickstart.md +++ b/docs/my-website/docs/learn/sdk_quickstart.md @@ -164,12 +164,6 @@ title: "Choose A Provider", description: "Find provider-specific auth, model naming, and params.", to: "/docs/providers", }, -{ -icon: "🖥️", -title: "Use Gateway", -description: "Send requests through a shared LiteLLM gateway.", -to: "/docs/learn/gateway_quickstart", -}, ]} /> diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index 95dfcd99e0..6af8f6e463 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -163,6 +163,7 @@ const sidebars = { "tutorials/google_adk", "tutorials/google_genai_sdk", "tutorials/livekit_xai_realtime", + "integrations/letta", { type: "doc", id: "tutorials/instructor", label: "Instructor with LiteLLM" }, { type: "doc", id: "langchain/langchain", label: "LangChain with LiteLLM" }, "projects/openai-agents" From 40c7873166e505dbd87f2d0a9b8fde728a2ebc02 Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Wed, 18 Mar 2026 20:04:41 +0530 Subject: [PATCH 271/289] chore(docs): add mcp_zero_trust sidebar entry Made-with: Cursor --- docs/my-website/sidebars.js | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index 6af8f6e463..4bf7aed009 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -305,6 +305,7 @@ const sidebars = { "mcp_openapi", "mcp_oauth", "mcp_aws_sigv4", + "mcp_zero_trust", "mcp_public_internet", "mcp_semantic_filter", "mcp_control", From 4bedb6439e8c71b113c3295deeae16b57219ec31 Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Wed, 18 Mar 2026 20:13:56 +0530 Subject: [PATCH 272/289] update sidebar --- docs/my-website/sidebars.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index de850f594b..071f80de02 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -313,7 +313,7 @@ const sidebars = { "mcp_guardrail", { type: "link", - label: "MCP Troubleshooting Guide →", + label: "MCP Troubleshooting Guide", href: "/docs/mcp_troubleshoot" }, ], From 643bfdd04276b606eb26885493a68fd076ba8469 Mon Sep 17 00:00:00 2001 From: Arindam Majumder <109217591+Arindam200@users.noreply.github.com> Date: Wed, 18 Mar 2026 20:36:56 +0530 Subject: [PATCH 273/289] Update docs/my-website/docs/proxy/docker_quick_start.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- docs/my-website/docs/proxy/docker_quick_start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/my-website/docs/proxy/docker_quick_start.md b/docs/my-website/docs/proxy/docker_quick_start.md index 4f61a56d83..4975c76c61 100644 --- a/docs/my-website/docs/proxy/docker_quick_start.md +++ b/docs/my-website/docs/proxy/docker_quick_start.md @@ -704,7 +704,7 @@ Error: cannot create subdirectories in ".../prometheus.yml": not a directory Docker created `prometheus.yml` as an **empty directory** instead of a file. This happens when the file is missing at `docker compose up` time. Fix it: - +Then create the file (see [Step 2.3 — Create `prometheus.yml`](#23--create-prometheusyml)) and run `docker compose up` again. ```bash rm -rf prometheus.yml ``` From 9ad52b1bf396b291a49444040fbe85a9393f9f19 Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Wed, 18 Mar 2026 20:42:29 +0530 Subject: [PATCH 274/289] update: authors image url & linkedin url --- docs/my-website/blog/authors.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/my-website/blog/authors.yml b/docs/my-website/blog/authors.yml index 3593600348..1b1ef4d34c 100644 --- a/docs/my-website/blog/authors.yml +++ b/docs/my-website/blog/authors.yml @@ -44,4 +44,5 @@ alexsander: yuneng: name: Yuneng Jiang title: SWE @ LiteLLM (Full Stack) - url: https://www.linkedin.com/in/yunengjiang/ + url: https://www.linkedin.com/in/yuneng-david-jiang-455676139/ + image_url: https://avatars.githubusercontent.com/u/171294688?v=4 From 06901143aae0b9a93e43e7a9dc4457689c740c66 Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Wed, 18 Mar 2026 21:25:08 +0530 Subject: [PATCH 275/289] Update release notes section --- docs/my-website/release_notes/index.md | 41 ++++++++++--------- .../{v1.81.12.md => v1.81.12/index.md} | 4 +- .../{v1.81.14.md => v1.81.14/index.md} | 8 ++-- .../{v1.81.6.md => v1.81.6/index.md} | 0 .../{v1.81.9.md => v1.81.9/index.md} | 4 +- .../{v1.82.0.md => v1.82.0/index.md} | 0 .../{v1.82.3.md => v1.82.3/index.md} | 0 7 files changed, 29 insertions(+), 28 deletions(-) rename docs/my-website/release_notes/{v1.81.12.md => v1.81.12/index.md} (99%) rename docs/my-website/release_notes/{v1.81.14.md => v1.81.14/index.md} (99%) rename docs/my-website/release_notes/{v1.81.6.md => v1.81.6/index.md} (100%) rename docs/my-website/release_notes/{v1.81.9.md => v1.81.9/index.md} (99%) rename docs/my-website/release_notes/{v1.82.0.md => v1.82.0/index.md} (100%) rename docs/my-website/release_notes/{v1.82.3.md => v1.82.3/index.md} (100%) diff --git a/docs/my-website/release_notes/index.md b/docs/my-website/release_notes/index.md index 44d6d39ba0..e2b7edf322 100644 --- a/docs/my-website/release_notes/index.md +++ b/docs/my-website/release_notes/index.md @@ -10,11 +10,11 @@ LiteLLM ships new releases regularly with new provider support, performance impr ## Latest Release -### [v1.82.0 — Realtime Guardrails, Projects Management, and 10+ Performance Optimizations](/release_notes/v1-82-0) +### [v1.82.3 — Nebius AI, gpt-5.4, Gemini 3.x, FLUX Kontext, and 116 New Models](/release_notes/v1.82.3/v1-82-3) -_February 28, 2026_ +_March 16, 2026_ -Real-time guardrail enforcement, a new Projects Management UI, and over 10 backend performance optimizations. +116 new models including Nebius AI, gpt-5.4, Gemini 3.x, and FLUX Kontext. --- @@ -22,23 +22,24 @@ Real-time guardrail enforcement, a new Projects Management UI, and over 10 backe | Version | Date | Highlights | | ----------------------------------- | ------------ | ---------------------------------------------------------- | -| [v1.81.14](/release_notes/v1-81-14) | Feb 21, 2026 | New Gateway Level Guardrails & Compliance Playground | -| [v1.81.12](/release_notes/v1-81-12) | Feb 14, 2026 | Guardrail Policy Templates & Action Builder | -| [v1.81.9](/release_notes/v1-81-9) | Feb 7, 2026 | Control which MCP Servers are exposed on the Internet | -| [v1.81.6](/release_notes/v1-81-6) | Jan 31, 2026 | Logs v2 with Tool Call Tracing | -| [v1.81.3](/release_notes/v1-81-3) | Jan 26, 2026 | Performance — 25% CPU Usage Reduction | -| [v1.81.0](/release_notes/v1-81-0) | Jan 18, 2026 | Claude Code — Web Search Across All Providers | -| [v1.80.15](/release_notes/v1-80-15) | Jan 10, 2026 | Manus API Support | -| [v1.80.8](/release_notes/v1-80-8) | Dec 6, 2025 | Introducing A2A Agent Gateway | -| [v1.80.5](/release_notes/v1-80-5) | Nov 22, 2025 | Gemini 3.0 Support | -| [v1.80.0](/release_notes/v1-80-0) | Nov 15, 2025 | Introducing Agent Hub: Register, Publish, and Share Agents | -| [v1.79.3](/release_notes/v1-79-3) | Nov 8, 2025 | Built-in Guardrails on AI Gateway | -| [v1.79.0](/release_notes/v1-79-0) | Oct 26, 2025 | Search APIs | -| [v1.78.5](/release_notes/v1-78-5) | Oct 18, 2025 | Native OCR Support | -| [v1.78.0](/release_notes/v1-78-0) | Oct 11, 2025 | MCP Gateway: Control Tool Access by Team, Key | -| [v1.77.7](/release_notes/v1-77-7) | Oct 4, 2025 | 2.9x Lower Median Latency | -| [v1.77.5](/release_notes/v1-77-5) | Sep 29, 2025 | MCP OAuth 2.0 Support | -| [v1.77.3](/release_notes/v1-77-3) | Sep 21, 2025 | Priority Based Rate Limiting | +| [v1.82.0](/release_notes/v1.82.0/v1-82-0) | Feb 28, 2026 | Realtime Guardrails, Projects Management, and 10+ Performance Optimizations | +| [v1.81.14](/release_notes/v1.81.14/v1-81-14) | Feb 21, 2026 | New Gateway Level Guardrails & Compliance Playground | +| [v1.81.12](/release_notes/v1.81.12/v1-81-12) | Feb 14, 2026 | Guardrail Policy Templates & Action Builder | +| [v1.81.9](/release_notes/v1.81.9/v1-81-9) | Feb 7, 2026 | Control which MCP Servers are exposed on the Internet | +| [v1.81.6](/release_notes/v1.81.6/v1-81-6) | Jan 31, 2026 | Logs v2 with Tool Call Tracing | +| [v1.81.3](/release_notes/v1.81.3-stable/v1-81-3) | Jan 26, 2026 | Performance — 25% CPU Usage Reduction | +| [v1.81.0](/release_notes/v1.81.0/v1-81-0) | Jan 18, 2026 | Claude Code — Web Search Across All Providers | +| [v1.80.15](/release_notes/v1.80.15/v1-80-15) | Jan 10, 2026 | Manus API Support | +| [v1.80.8](/release_notes/v1.80.8-stable/v1-80-8) | Dec 6, 2025 | Introducing A2A Agent Gateway | +| [v1.80.5](/release_notes/v1.80.5-stable/v1-80-5) | Nov 22, 2025 | Gemini 3.0 Support | +| [v1.80.0](/release_notes/v1.80.0-stable/v1-80-0) | Nov 15, 2025 | Introducing Agent Hub: Register, Publish, and Share Agents | +| [v1.79.3](/release_notes/v1.79.3-stable/v1-79-3) | Nov 8, 2025 | Built-in Guardrails on AI Gateway | +| [v1.79.0](/release_notes/v1.79.0-stable/v1-79-0) | Oct 26, 2025 | Search APIs | +| [v1.78.5](/release_notes/v1.78.5-stable/v1-78-5) | Oct 18, 2025 | Native OCR Support | +| [v1.78.0](/release_notes/v1.78.0-stable/v1-78-0) | Oct 11, 2025 | MCP Gateway: Control Tool Access by Team, Key | +| [v1.77.7](/release_notes/v1.77.7-stable/v1-77-7) | Oct 4, 2025 | 2.9x Lower Median Latency | +| [v1.77.5](/release_notes/v1.77.5-stable/v1-77-5) | Sep 29, 2025 | MCP OAuth 2.0 Support | +| [v1.77.3](/release_notes/v1.77.3-stable/v1-77-3) | Sep 21, 2025 | Priority Based Rate Limiting | --- diff --git a/docs/my-website/release_notes/v1.81.12.md b/docs/my-website/release_notes/v1.81.12/index.md similarity index 99% rename from docs/my-website/release_notes/v1.81.12.md rename to docs/my-website/release_notes/v1.81.12/index.md index 0b7c1e146a..1bbea5b82b 100644 --- a/docs/my-website/release_notes/v1.81.12.md +++ b/docs/my-website/release_notes/v1.81.12/index.md @@ -62,13 +62,13 @@ This release fixes out-of-memory (OOM) risks from unbounded `asyncio.Queue()` us This release adds a visual action builder for guardrail policies with conditional execution support. You can now chain guardrails into multi-step pipelines — if a simple guardrail fails, route to an advanced one instead of immediately blocking. Each step has configurable ON PASS and ON FAIL actions (Next Step, Block, or Allow), and you can test the full pipeline with a sample message before saving. -![Guardrail Action Builder](../img/release_notes/guard_actions.png) +![Guardrail Action Builder](../../img/release_notes/guard_actions.png) ### Access Groups Access Groups simplify defining resource access across your organization. One group can grant access to models, MCP servers, and agents—simply attach it to a key or team. Create groups in the Admin UI, define which resources each group includes, then assign the group when creating keys or teams. Updates to a group apply automatically to all attached keys and teams. - + ## New Providers and Endpoints diff --git a/docs/my-website/release_notes/v1.81.14.md b/docs/my-website/release_notes/v1.81.14/index.md similarity index 99% rename from docs/my-website/release_notes/v1.81.14.md rename to docs/my-website/release_notes/v1.81.14/index.md index c342bc47ee..92c22bc0ea 100644 --- a/docs/my-website/release_notes/v1.81.14.md +++ b/docs/my-website/release_notes/v1.81.14/index.md @@ -56,7 +56,7 @@ pip install litellm==1.81.14 AI Platform Admins can now browse built-in and partner guardrails from the Guardrail Garden. Guardrails are organized by use case — blocking financial advice, filtering insults, detecting competitor mentions, and more — so you can find the right one and deploy it in a few clicks. -![Guardrail Garden](../img/release_notes/guardrail_garden.png) +![Guardrail Garden](../../img/release_notes/guardrail_garden.png) ### 3 New Built-in Guardrails @@ -72,7 +72,7 @@ These guardrails are built for production and on our benchmarks had a 100% Recal Previously, the `store_model_in_db` setting could only be configured in `proxy_config.yaml` under `general_settings`, requiring a proxy restart to take effect. Now you can enable or disable this setting directly from the Admin UI without any restarts. This is especially useful for cloud deployments where you don't have direct access to config files or want to avoid downtime. Enable `store_model_in_db` to move model definitions from your YAML into the database—reducing config complexity, improving scalability, and enabling dynamic model management across multiple proxy instances. -![Store model in DB Setting](../img/ui_store_model_in_db.png) +![Store model in DB Setting](../../img/ui_store_model_in_db.png) #### Eval results @@ -91,14 +91,14 @@ We benchmarked our new built-in guardrails against labeled datasets before shipp The Compliance Playground lets you test any guardrail against our pre-built eval datasets or your own custom datasets, so you can see precision, recall, and false positive rate before rolling it out to production. -![Compliance Playground](../img/release_notes/compliance_playground.png) +![Compliance Playground](../../img/release_notes/compliance_playground.png) --- ## Performance & Reliability — Up to 13% Lower Latency - + This release cuts latency across all percentiles through 20+ micro-optimizations across logging, cost calculation, routing, and connection management. See [benchmarking](../../docs/benchmarks) for more info about how to benchmark yourself. diff --git a/docs/my-website/release_notes/v1.81.6.md b/docs/my-website/release_notes/v1.81.6/index.md similarity index 100% rename from docs/my-website/release_notes/v1.81.6.md rename to docs/my-website/release_notes/v1.81.6/index.md diff --git a/docs/my-website/release_notes/v1.81.9.md b/docs/my-website/release_notes/v1.81.9/index.md similarity index 99% rename from docs/my-website/release_notes/v1.81.9.md rename to docs/my-website/release_notes/v1.81.9/index.md index 80be4179b4..d11b52e892 100644 --- a/docs/my-website/release_notes/v1.81.9.md +++ b/docs/my-website/release_notes/v1.81.9/index.md @@ -81,7 +81,7 @@ This release makes it safe to expose MCP servers on the public internet by addin [Get started](../../docs/mcp_public_internet) @@ -92,7 +92,7 @@ Set a soft budget on any team to receive email alerts when spending crosses the [Get started](../../docs/proxy/ui_team_soft_budget_alerts) diff --git a/docs/my-website/release_notes/v1.82.0.md b/docs/my-website/release_notes/v1.82.0/index.md similarity index 100% rename from docs/my-website/release_notes/v1.82.0.md rename to docs/my-website/release_notes/v1.82.0/index.md diff --git a/docs/my-website/release_notes/v1.82.3.md b/docs/my-website/release_notes/v1.82.3/index.md similarity index 100% rename from docs/my-website/release_notes/v1.82.3.md rename to docs/my-website/release_notes/v1.82.3/index.md From 6d121616273f4016204f1d8a60781d361d355196 Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Wed, 18 Mar 2026 21:45:43 +0530 Subject: [PATCH 276/289] Enhance navigation and sorting functionality in Docusaurus config --- docs/my-website/docusaurus.config.js | 13 +++++++++++-- .../src/components/NavigationCards/index.js | 7 ++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/my-website/docusaurus.config.js b/docs/my-website/docusaurus.config.js index ec3ba19188..9e1fae6a34 100644 --- a/docs/my-website/docusaurus.config.js +++ b/docs/my-website/docusaurus.config.js @@ -156,7 +156,12 @@ const config = { } // Build categories sorted by year descending - const years = Object.keys(byYear).sort((a, b) => b - a); + const years = Object.keys(byYear).sort((a, b) => { + // Object.keys() returns strings; avoid numeric subtraction type errors. + const na = Number.parseInt(a, 10); + const nb = Number.parseInt(b, 10); + return nb - na; + }); return years.map(year => ({ type: 'category', label: String(year), @@ -291,7 +296,11 @@ const config = { position: 'right', className: 'header-discord-link', 'aria-label': 'Discord / Slack community', - } + }, + { + type: 'search', + position: 'right', + }, ], }, footer: { diff --git a/docs/my-website/src/components/NavigationCards/index.js b/docs/my-website/src/components/NavigationCards/index.js index 1d5d3e577a..5efd89ee14 100644 --- a/docs/my-website/src/components/NavigationCards/index.js +++ b/docs/my-website/src/components/NavigationCards/index.js @@ -1,4 +1,5 @@ import React from 'react'; +import Link from '@docusaurus/Link'; import styles from './styles.module.css'; export default function NavigationCards({ items, columns = 2 }) { @@ -11,9 +12,9 @@ export default function NavigationCards({ items, columns = 2 }) { const isExternal = item.to && (item.to.startsWith('http://') || item.to.startsWith('https://')); return ( -
↗ )} - + ); })} From dcc0c709365eca246ea16d7ded577728af2c6d52 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Wed, 18 Mar 2026 11:59:31 -0700 Subject: [PATCH 277/289] [Refactor] Extract _convert_teams_to_response_models to fix PLR0915 list_team_v2 had 51 statements (limit 50). Extract the team-to-response-model conversion loop into a helper function to satisfy ruff PLR0915. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../management_endpoints/team_endpoints.py | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py index e7cd6c1748..bee4b2517e 100644 --- a/litellm/proxy/management_endpoints/team_endpoints.py +++ b/litellm/proxy/management_endpoints/team_endpoints.py @@ -3323,6 +3323,30 @@ async def _build_team_list_where_conditions( return where_conditions +def _convert_teams_to_response_models( + teams: list, + use_deleted_table: bool, +) -> List[Union[TeamListItem, LiteLLM_TeamTable, LiteLLM_DeletedTeamTable]]: + """Convert raw Prisma team rows to response models.""" + team_list: List[Union[TeamListItem, LiteLLM_TeamTable, LiteLLM_DeletedTeamTable]] = [] + for team in teams: + try: + team_dict = team.model_dump() + except Exception: + team_dict = team.dict() + + if use_deleted_table: + team_list.append(LiteLLM_DeletedTeamTable(**team_dict)) + else: + members_with_roles = team_dict.get("members_with_roles") + if not isinstance(members_with_roles, list): + members_with_roles = [] + team_dict["members_with_roles"] = members_with_roles + members_count = len(members_with_roles) + team_list.append(TeamListItem(**team_dict, members_count=members_count)) + return team_list + + @router.get( "/v2/team/list", tags=["team management"], @@ -3521,22 +3545,7 @@ async def list_team_v2( total_pages = -(-total_count // page_size) # Ceiling division # Convert Prisma models to response models with members_count - team_list: List[Union[TeamListItem, LiteLLM_TeamTable, LiteLLM_DeletedTeamTable]] = [] - for team in teams: - try: - team_dict = team.model_dump() - except Exception: - team_dict = team.dict() - - if use_deleted_table: - team_list.append(LiteLLM_DeletedTeamTable(**team_dict)) - else: - members_with_roles = team_dict.get("members_with_roles") - if not isinstance(members_with_roles, list): - members_with_roles = [] - team_dict["members_with_roles"] = members_with_roles - members_count = len(members_with_roles) - team_list.append(TeamListItem(**team_dict, members_count=members_count)) + team_list = _convert_teams_to_response_models(teams, use_deleted_table) return { "teams": team_list, From 4da2730607d5643805cd5737bb1dc7c386d44399 Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Thu, 19 Mar 2026 00:59:56 +0530 Subject: [PATCH 278/289] Refactor TOC component to use Docusaurus Link for navigation --- docs/my-website/src/theme/TOC/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/my-website/src/theme/TOC/index.js b/docs/my-website/src/theme/TOC/index.js index 4b6adc216d..a112c45959 100644 --- a/docs/my-website/src/theme/TOC/index.js +++ b/docs/my-website/src/theme/TOC/index.js @@ -1,6 +1,7 @@ import React from 'react'; import clsx from 'clsx'; import TOCItems from '@theme/TOCItems'; +import Link from '@docusaurus/Link'; import styles from './styles.module.css'; const LINK_CLASS_NAME = 'table-of-contents__link toc-highlight'; @@ -26,9 +27,9 @@ export default function TOC({ className, ...props }) { SSO/SAML, audit logs, spend tracking, multi-team management, and guardrails — built for production. - + Learn more → - + ); From bb628e974a122a8d89ecad2123bb22a4e95173fb Mon Sep 17 00:00:00 2001 From: jyeros Date: Wed, 18 Mar 2026 15:01:14 -0500 Subject: [PATCH 279/289] Add otel ignore_context_propagation as opt in --- litellm/integrations/opentelemetry.py | 21 +++++++------------ .../integrations/test_opentelemetry.py | 2 +- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/litellm/integrations/opentelemetry.py b/litellm/integrations/opentelemetry.py index 7689a6cc7e..559ed05d30 100644 --- a/litellm/integrations/opentelemetry.py +++ b/litellm/integrations/opentelemetry.py @@ -11,7 +11,7 @@ from litellm.integrations._types.open_inference import ( ) from litellm.integrations.custom_logger import CustomLogger from litellm.litellm_core_utils.safe_json_dumps import safe_dumps -from litellm.secret_managers.main import get_secret_bool +from litellm.secret_managers.main import get_secret_bool, str_to_bool from litellm.types.services import ServiceLoggerPayload from litellm.types.utils import ( ChatCompletionMessageToolCall, @@ -68,6 +68,7 @@ class OpenTelemetryConfig: service_name: Optional[str] = None deployment_environment: Optional[str] = None model_id: Optional[str] = None + ignore_context_propagation: Optional[bool] = None def __post_init__(self) -> None: # If endpoint is specified but exporter is still the default "console", @@ -89,6 +90,10 @@ class OpenTelemetryConfig: ) if not self.model_id: self.model_id = os.getenv("OTEL_MODEL_ID", self.service_name) + if self.ignore_context_propagation is None: + self.ignore_context_propagation = str_to_bool( + os.getenv("OTEL_IGNORE_CONTEXT_PROPAGATION") + ) @classmethod def from_env(cls): @@ -710,12 +715,7 @@ class OpenTelemetry(CustomLogger): ) ctx, parent_span = self._get_span_context(kwargs) - # CRITICAL FIX: For langfuse_otel, ALWAYS create primary spans - # Don't use parent spans from other providers as they cause trace corruption - is_langfuse_otel = ( - hasattr(self, "callback_name") and self.callback_name == "langfuse_otel" - ) - if is_langfuse_otel: + if self.config.ignore_context_propagation: parent_span = None # Ignore parent spans from other providers ctx = None @@ -1256,12 +1256,7 @@ class OpenTelemetry(CustomLogger): ) _parent_context, parent_otel_span = self._get_span_context(kwargs) - # CRITICAL FIX: For langfuse_otel, ALWAYS create primary spans - # Don't use parent spans from other providers as they cause trace corruption - is_langfuse_otel = ( - hasattr(self, "callback_name") and self.callback_name == "langfuse_otel" - ) - if is_langfuse_otel: + if self.config.ignore_context_propagation: parent_otel_span = None # Ignore parent spans from other providers _parent_context = None diff --git a/tests/test_litellm/integrations/test_opentelemetry.py b/tests/test_litellm/integrations/test_opentelemetry.py index 7f3b44e142..3d6fc146a0 100644 --- a/tests/test_litellm/integrations/test_opentelemetry.py +++ b/tests/test_litellm/integrations/test_opentelemetry.py @@ -2175,7 +2175,7 @@ class TestOpenTelemetrySemanticConventions138(unittest.TestCase): tracer_provider.add_span_processor(SimpleSpanProcessor(span_exporter)) otel = OpenTelemetry( - callback_name="langfuse_otel", + config=OpenTelemetryConfig(ignore_context_propagation=True), tracer_provider=tracer_provider, ) otel.tracer = tracer_provider.get_tracer("litellm") From 2b6a32e0cd966f0b758eea416e88a6f757b0a966 Mon Sep 17 00:00:00 2001 From: jyeros Date: Wed, 18 Mar 2026 15:02:03 -0500 Subject: [PATCH 280/289] Add tests --- poetry.lock | 88 +++++++---- pyproject.toml | 1 + .../integrations/test_opentelemetry.py | 141 ++++++++++++++---- 3 files changed, 167 insertions(+), 63 deletions(-) diff --git a/poetry.lock b/poetry.lock index 591d0c270e..86d5b1e4c9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand. [[package]] name = "a2a-sdk" @@ -7,11 +7,11 @@ description = "A2A Python SDK" optional = false python-versions = ">=3.10" groups = ["main", "proxy-dev"] -markers = "python_version >= \"3.10\"" files = [ {file = "a2a_sdk-0.3.22-py3-none-any.whl", hash = "sha256:b98701135bb90b0ff85d35f31533b6b7a299bf810658c1c65f3814a6c15ea385"}, {file = "a2a_sdk-0.3.22.tar.gz", hash = "sha256:77a5694bfc4f26679c11b70c7f1062522206d430b34bc1215cfbb1eba67b7e7d"}, ] +markers = {main = "python_version >= \"3.10\" and extra == \"extra-proxy\"", proxy-dev = "python_version >= \"3.10\""} [package.dependencies] google-api-core = ">=1.26.0" @@ -385,6 +385,7 @@ files = [ {file = "azure_core-1.36.0-py3-none-any.whl", hash = "sha256:fee9923a3a753e94a259563429f3644aaf05c486d45b1215d098115102d91d3b"}, {file = "azure_core-1.36.0.tar.gz", hash = "sha256:22e5605e6d0bf1d229726af56d9e92bc37b6e726b141a18be0b4d424131741b7"}, ] +markers = {main = "extra == \"proxy\" or extra == \"extra-proxy\""} [package.dependencies] requests = ">=2.21.0" @@ -405,6 +406,7 @@ files = [ {file = "azure_identity-1.25.1-py3-none-any.whl", hash = "sha256:e9edd720af03dff020223cd269fa3a61e8f345ea75443858273bcb44844ab651"}, {file = "azure_identity-1.25.1.tar.gz", hash = "sha256:87ca8328883de6036443e1c37b40e8dc8fb74898240f61071e09d2e369361456"}, ] +markers = {main = "extra == \"proxy\" or extra == \"extra-proxy\""} [package.dependencies] azure-core = ">=1.31.0" @@ -598,7 +600,7 @@ files = [ {file = "cachetools-6.2.2-py3-none-any.whl", hash = "sha256:6c09c98183bf58560c97b2abfcedcbaf6a896a490f534b031b661d3723b45ace"}, {file = "cachetools-6.2.2.tar.gz", hash = "sha256:8e6d266b25e539df852251cfd6f990b4bc3a141db73b939058d809ebd2590fc6"}, ] -markers = {main = "extra == \"google\" or extra == \"extra-proxy\" or python_version >= \"3.10\"", proxy-dev = "python_version >= \"3.10\""} +markers = {main = "python_version >= \"3.10\" and (extra == \"extra-proxy\" or extra == \"google\" or extra == \"mlflow\") or extra == \"google\" or extra == \"extra-proxy\"", proxy-dev = "python_version >= \"3.10\""} [[package]] name = "certifi" @@ -705,7 +707,7 @@ files = [ {file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"}, {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"}, ] -markers = {main = "platform_python_implementation != \"PyPy\" or extra == \"proxy\"", dev = "platform_python_implementation != \"PyPy\"", proxy-dev = "platform_python_implementation != \"PyPy\""} +markers = {main = "(platform_python_implementation != \"PyPy\" or extra == \"proxy\") and (python_version >= \"3.10\" or extra == \"proxy\" or extra == \"extra-proxy\") and (extra == \"proxy\" or extra == \"extra-proxy\" or extra == \"mlflow\")", dev = "platform_python_implementation != \"PyPy\"", proxy-dev = "platform_python_implementation != \"PyPy\""} [package.dependencies] pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} @@ -1055,6 +1057,7 @@ files = [ {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"}, {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"}, ] +markers = {main = "python_version >= \"3.10\" and (extra == \"proxy\" or extra == \"extra-proxy\" or extra == \"mlflow\") or extra == \"proxy\" or extra == \"extra-proxy\""} [package.dependencies] cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} @@ -1837,11 +1840,11 @@ description = "Google API client core library" optional = false python-versions = ">=3.7" groups = ["main", "proxy-dev"] -markers = "python_version >= \"3.14\"" files = [ {file = "google_api_core-2.25.2-py3-none-any.whl", hash = "sha256:e9a8f62d363dc8424a8497f4c2a47d6bcda6c16514c935629c257ab5d10210e7"}, {file = "google_api_core-2.25.2.tar.gz", hash = "sha256:1c63aa6af0d0d5e37966f157a77f9396d820fba59f9e43e9415bc3dc5baff300"}, ] +markers = {main = "python_version >= \"3.14\" and (extra == \"extra-proxy\" or extra == \"google\")", proxy-dev = "python_version >= \"3.14\""} [package.dependencies] google-auth = ">=2.14.1,<3.0.0" @@ -1869,7 +1872,7 @@ files = [ {file = "google_api_core-2.28.1-py3-none-any.whl", hash = "sha256:4021b0f8ceb77a6fb4de6fde4502cecab45062e66ff4f2895169e0b35bc9466c"}, {file = "google_api_core-2.28.1.tar.gz", hash = "sha256:2b405df02d68e68ce0fbc138559e6036559e685159d148ae5861013dc201baf8"}, ] -markers = {main = "(python_version >= \"3.10\" or extra == \"google\" or extra == \"extra-proxy\") and python_version < \"3.14\"", proxy-dev = "python_version >= \"3.10\" and python_version < \"3.14\""} +markers = {main = "python_version < \"3.14\" and (extra == \"extra-proxy\" or extra == \"google\")", proxy-dev = "python_version >= \"3.10\" and python_version < \"3.14\""} [package.dependencies] google-auth = ">=2.14.1,<3.0.0" @@ -1906,7 +1909,7 @@ files = [ {file = "google_auth-2.43.0-py2.py3-none-any.whl", hash = "sha256:af628ba6fa493f75c7e9dbe9373d148ca9f4399b5ea29976519e0a3848eddd16"}, {file = "google_auth-2.43.0.tar.gz", hash = "sha256:88228eee5fc21b62a1b5fe773ca15e67778cb07dc8363adcb4a8827b52d81483"}, ] -markers = {main = "extra == \"google\" or extra == \"extra-proxy\" or python_version >= \"3.10\"", proxy-dev = "python_version >= \"3.10\""} +markers = {main = "python_version >= \"3.10\" and (extra == \"extra-proxy\" or extra == \"google\" or extra == \"mlflow\") or extra == \"google\" or extra == \"extra-proxy\"", proxy-dev = "python_version >= \"3.10\""} [package.dependencies] cachetools = ">=2.0.0,<7.0" @@ -2078,11 +2081,11 @@ files = [ ] [package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev" +google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0.dev0", extras = ["grpc"]} +google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0.dev0" +grpc-google-iam-v1 = ">=0.12.4,<1.0.0.dev0" +proto-plus = ">=1.22.3,<2.0.0.dev0" +protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" [[package]] name = "google-cloud-resource-manager" @@ -2264,7 +2267,7 @@ files = [ {file = "googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038"}, {file = "googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5"}, ] -markers = {main = "extra == \"google\" or extra == \"extra-proxy\" or python_version >= \"3.10\""} +markers = {main = "python_version >= \"3.10\" and (extra == \"extra-proxy\" or extra == \"google\") or extra == \"google\" or extra == \"extra-proxy\""} [package.dependencies] grpcio = {version = ">=1.44.0,<2.0.0", optional = true, markers = "extra == \"grpc\""} @@ -2673,11 +2676,11 @@ description = "Consume Server-Sent Event (SSE) messages with HTTPX." optional = false python-versions = ">=3.9" groups = ["main", "proxy-dev"] -markers = "python_version >= \"3.10\"" files = [ {file = "httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc"}, {file = "httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d"}, ] +markers = {main = "python_version >= \"3.10\" and (extra == \"proxy\" or extra == \"extra-proxy\")", proxy-dev = "python_version >= \"3.10\""} [[package]] name = "huey" @@ -3042,7 +3045,7 @@ files = [ [package.dependencies] attrs = ">=22.2.0" -jsonschema-specifications = ">=2023.03.6" +jsonschema-specifications = ">=2023.3.6" referencing = ">=0.28.4" rpds-py = ">=0.7.1" @@ -3219,15 +3222,15 @@ files = [ [[package]] name = "litellm-proxy-extras" -version = "0.4.56" +version = "0.4.57" description = "Additional files for the LiteLLM Proxy. Reduces the size of the main litellm package." optional = true python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8" groups = ["main"] markers = "extra == \"proxy\"" files = [ - {file = "litellm_proxy_extras-0.4.56-py3-none-any.whl", hash = "sha256:52dbe3b5358c790e77e12f1ec5ef8e7508b383c2aaf41299750b6fb400908ee7"}, - {file = "litellm_proxy_extras-0.4.56.tar.gz", hash = "sha256:63ad59baa0defccc5c929cfd933ee7e32a6614b0fc5fa0fc45a12d7608e33f08"}, + {file = "litellm_proxy_extras-0.4.57-py3-none-any.whl", hash = "sha256:04538223cd80318a72d70c6e10f701598e58c763368296a6503c674c92fbdb62"}, + {file = "litellm_proxy_extras-0.4.57.tar.gz", hash = "sha256:ef9b95dc42237614216833bd5d46ebf9dea1caa5ea14ea1a66d7f7842b224ec2"}, ] [[package]] @@ -3713,6 +3716,7 @@ files = [ {file = "msal-1.34.0-py3-none-any.whl", hash = "sha256:f669b1644e4950115da7a176441b0e13ec2975c29528d8b9e81316023676d6e1"}, {file = "msal-1.34.0.tar.gz", hash = "sha256:76ba83b716ea5a6d75b0279c0ac353a0e05b820ca1f6682c0eb7f45190c43c2f"}, ] +markers = {main = "extra == \"proxy\" or extra == \"extra-proxy\""} [package.dependencies] cryptography = ">=2.5,<49" @@ -3733,6 +3737,7 @@ files = [ {file = "msal_extensions-1.3.1-py3-none-any.whl", hash = "sha256:96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca"}, {file = "msal_extensions-1.3.1.tar.gz", hash = "sha256:c5b0fd10f65ef62b5f1d62f4251d51cbcaf003fcedae8c91b040a488614be1a4"}, ] +markers = {main = "extra == \"proxy\" or extra == \"extra-proxy\""} [package.dependencies] msal = ">=1.29,<2" @@ -3983,6 +3988,7 @@ files = [ {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, ] +markers = {main = "extra == \"extra-proxy\""} [[package]] name = "numpy" @@ -4105,7 +4111,7 @@ files = [ {file = "opentelemetry_api-1.39.1-py3-none-any.whl", hash = "sha256:2edd8463432a7f8443edce90972169b195e7d6a05500cd29e6d13898187c9950"}, {file = "opentelemetry_api-1.39.1.tar.gz", hash = "sha256:fbde8c80e1b937a2c61f20347e91c0c18a1940cecf012d62e65a7caf08967c9c"}, ] -markers = {main = "python_version >= \"3.10\""} +markers = {main = "python_version >= \"3.10\" and extra == \"mlflow\""} [package.dependencies] importlib-metadata = ">=6.0,<8.8.0" @@ -4220,7 +4226,7 @@ files = [ {file = "opentelemetry_sdk-1.39.1-py3-none-any.whl", hash = "sha256:4d5482c478513ecb0a5d938dcc61394e647066e0cc2676bee9f3af3f3f45f01c"}, {file = "opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6"}, ] -markers = {main = "python_version >= \"3.10\""} +markers = {main = "python_version >= \"3.10\" and extra == \"mlflow\""} [package.dependencies] opentelemetry-api = "1.39.1" @@ -4238,7 +4244,7 @@ files = [ {file = "opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl", hash = "sha256:9fa8c8b0c110da289809292b0591220d3a7b53c1526a23021e977d68597893fb"}, {file = "opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953"}, ] -markers = {main = "python_version >= \"3.10\""} +markers = {main = "python_version >= \"3.10\" and extra == \"mlflow\""} [package.dependencies] opentelemetry-api = "1.39.1" @@ -4455,6 +4461,21 @@ sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-d test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] xml = ["lxml (>=4.9.2)"] +[[package]] +name = "parameterized" +version = "0.9.0" +description = "Parameterized testing with any Python test framework" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "parameterized-0.9.0-py2.py3-none-any.whl", hash = "sha256:4e0758e3d41bea3bbd05ec14fc2c24736723f243b28d702081aef438c9372b1b"}, + {file = "parameterized-0.9.0.tar.gz", hash = "sha256:7fc905272cefa4f364c1a3429cbbe9c0f98b793988efb5bf90aac80f08db09b1"}, +] + +[package.extras] +dev = ["jinja2"] + [[package]] name = "pathspec" version = "0.12.1" @@ -4722,6 +4743,7 @@ files = [ {file = "prisma-0.11.0-py3-none-any.whl", hash = "sha256:22bb869e59a2968b99f3483bb417717273ffbc569fd1e9ceed95e5614cbaf53a"}, {file = "prisma-0.11.0.tar.gz", hash = "sha256:3f2f2fd2361e1ec5ff655f2a04c7860c2f2a5bc4c91f78ca9c5c6349735bf693"}, ] +markers = {main = "extra == \"extra-proxy\""} [package.dependencies] click = ">=7.1.2" @@ -4895,7 +4917,7 @@ files = [ {file = "proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66"}, {file = "proto_plus-1.26.1.tar.gz", hash = "sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012"}, ] -markers = {main = "extra == \"google\" or extra == \"extra-proxy\" or python_version >= \"3.10\"", proxy-dev = "python_version >= \"3.10\""} +markers = {main = "extra == \"google\" or extra == \"extra-proxy\"", proxy-dev = "python_version >= \"3.10\""} [package.dependencies] protobuf = ">=3.19.0,<7.0.0" @@ -4923,7 +4945,7 @@ files = [ {file = "protobuf-5.29.5-py3-none-any.whl", hash = "sha256:6cf42630262c59b2d8de33954443d94b746c952b01434fc58a417fdbd2e84bd5"}, {file = "protobuf-5.29.5.tar.gz", hash = "sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84"}, ] -markers = {main = "extra == \"google\" or extra == \"extra-proxy\" or python_version >= \"3.10\""} +markers = {main = "python_version >= \"3.10\" and (extra == \"extra-proxy\" or extra == \"google\" or extra == \"mlflow\") or extra == \"google\" or extra == \"extra-proxy\""} [[package]] name = "psutil" @@ -5083,7 +5105,7 @@ files = [ {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"}, {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"}, ] -markers = {main = "extra == \"google\" or extra == \"extra-proxy\" or python_version >= \"3.10\"", proxy-dev = "python_version >= \"3.10\""} +markers = {main = "python_version >= \"3.10\" and (extra == \"extra-proxy\" or extra == \"google\" or extra == \"mlflow\") or extra == \"google\" or extra == \"extra-proxy\"", proxy-dev = "python_version >= \"3.10\""} [[package]] name = "pyasn1-modules" @@ -5096,7 +5118,7 @@ files = [ {file = "pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a"}, {file = "pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6"}, ] -markers = {main = "extra == \"google\" or extra == \"extra-proxy\" or python_version >= \"3.10\"", proxy-dev = "python_version >= \"3.10\""} +markers = {main = "python_version >= \"3.10\" and (extra == \"extra-proxy\" or extra == \"google\" or extra == \"mlflow\") or extra == \"google\" or extra == \"extra-proxy\"", proxy-dev = "python_version >= \"3.10\""} [package.dependencies] pyasn1 = ">=0.6.1,<0.7.0" @@ -5124,7 +5146,7 @@ files = [ {file = "pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934"}, {file = "pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2"}, ] -markers = {main = "implementation_name != \"PyPy\" and (platform_python_implementation != \"PyPy\" or extra == \"proxy\")", dev = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\"", proxy-dev = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\""} +markers = {main = "implementation_name != \"PyPy\" and (platform_python_implementation != \"PyPy\" or extra == \"proxy\") and (python_version >= \"3.10\" or extra == \"proxy\" or extra == \"extra-proxy\") and (extra == \"proxy\" or extra == \"extra-proxy\" or extra == \"mlflow\")", dev = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\"", proxy-dev = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\""} [[package]] name = "pydantic" @@ -5347,6 +5369,7 @@ files = [ {file = "pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c"}, {file = "pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b"}, ] +markers = {main = "(python_version <= \"3.13\" or extra == \"proxy\" or extra == \"extra-proxy\") and (extra == \"extra-proxy\" or extra == \"proxy\")"} [package.dependencies] cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""} @@ -6290,7 +6313,7 @@ files = [ {file = "rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762"}, {file = "rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75"}, ] -markers = {main = "extra == \"google\" or extra == \"extra-proxy\" or python_version >= \"3.10\"", proxy-dev = "python_version >= \"3.10\""} +markers = {main = "python_version >= \"3.10\" and (extra == \"extra-proxy\" or extra == \"google\" or extra == \"mlflow\") or extra == \"google\" or extra == \"extra-proxy\"", proxy-dev = "python_version >= \"3.10\""} [package.dependencies] pyasn1 = ">=0.1.3" @@ -6336,10 +6359,10 @@ files = [ ] [package.dependencies] -botocore = ">=1.37.4,<2.0a.0" +botocore = ">=1.37.4,<2.0a0" [package.extras] -crt = ["botocore[crt] (>=1.37.4,<2.0a.0)"] +crt = ["botocore[crt] (>=1.37.4,<2.0a0)"] [[package]] name = "scikit-learn" @@ -6492,9 +6515,9 @@ tornado = ">=6.4.2,<7" urllib3 = ">=1.26,<3" [package.extras] -all = ["boto3 (>=1.34.98,<2)", "botocore (>=1.34.110,<2)", "cohere (>=5.9.4,<6.00)", "dagger-io (>=0.1.1) ; python_version >= \"3.11\"", "fastembed (>=0.3.0,<0.4) ; python_version < \"3.13\"", "google-cloud-aiplatform (>=1.45.0,<2)", "ipykernel (>=6.25.0,<7)", "llama-cpp-python (>=0.2.28,<0.2.86) ; python_version < \"3.13\"", "mistralai (>=0.0.12,<0.1.0)", "mypy (>=1.7.1,<2)", "ollama (>=0.1.7)", "pillow (>=10.2.0,<11.0.0) ; python_version < \"3.13\"", "pinecone[asyncio] (>=7.0.0,<8.0.0)", "psycopg[binary] (>=3.1.0,<4)", "pytest (>=8.2,<9.0)", "pytest-asyncio (>=0.24.0,<0.25)", "pytest-cov (>=4.1.0,<5)", "pytest-mock (>=3.12.0,<4)", "pytest-timeout", "pytest-xdist (>=3.5.0,<4)", "python-dotenv (>=1.0.0,<2)", "qdrant-client (>=1.11.1,<2)", "requests-mock (>=1.12.1,<2)", "ruff (>=0.11.2,<0.12)", "sentence-transformers (>=5.0.0) ; python_version < \"3.13\"", "tokenizers (>=0.19) ; python_version < \"3.13\"", "torch (>=2.6.0) ; python_version < \"3.13\"", "torchvision (>=0.17.0) ; python_version < \"3.13\"", "transformers (>=4.36.2) ; python_version < \"3.13\"", "types-pyyaml (>=6.0.12.12,<7)", "types-requests (>=2.31.0,<3)"] +all = ["boto3 (>=1.34.98,<2)", "botocore (>=1.34.110,<2)", "cohere (>=5.9.4,<6.0)", "dagger-io (>=0.1.1) ; python_version >= \"3.11\"", "fastembed (>=0.3.0,<0.4) ; python_version < \"3.13\"", "google-cloud-aiplatform (>=1.45.0,<2)", "ipykernel (>=6.25.0,<7)", "llama-cpp-python (>=0.2.28,<0.2.86) ; python_version < \"3.13\"", "mistralai (>=0.0.12,<0.1.0)", "mypy (>=1.7.1,<2)", "ollama (>=0.1.7)", "pillow (>=10.2.0,<11.0.0) ; python_version < \"3.13\"", "pinecone[asyncio] (>=7.0.0,<8.0.0)", "psycopg[binary] (>=3.1.0,<4)", "pytest (>=8.2,<9.0)", "pytest-asyncio (>=0.24.0,<0.25)", "pytest-cov (>=4.1.0,<5)", "pytest-mock (>=3.12.0,<4)", "pytest-timeout", "pytest-xdist (>=3.5.0,<4)", "python-dotenv (>=1.0.0,<2)", "qdrant-client (>=1.11.1,<2)", "requests-mock (>=1.12.1,<2)", "ruff (>=0.11.2,<0.12)", "sentence-transformers (>=5.0.0) ; python_version < \"3.13\"", "tokenizers (>=0.19) ; python_version < \"3.13\"", "torch (>=2.6.0) ; python_version < \"3.13\"", "torchvision (>=0.17.0) ; python_version < \"3.13\"", "transformers (>=4.36.2) ; python_version < \"3.13\"", "types-pyyaml (>=6.0.12.12,<7)", "types-requests (>=2.31.0,<3)"] bedrock = ["boto3 (>=1.34.98,<2)", "botocore (>=1.34.110,<2)"] -cohere = ["cohere (>=5.9.4,<6.00)"] +cohere = ["cohere (>=5.9.4,<6.0)"] dev = ["dagger-io (>=0.1.1) ; python_version >= \"3.11\"", "ipykernel (>=6.25.0,<7)", "mypy (>=1.7.1,<2)", "pytest (>=8.2,<9.0)", "pytest-asyncio (>=0.24.0,<0.25)", "pytest-cov (>=4.1.0,<5)", "pytest-mock (>=3.12.0,<4)", "pytest-timeout", "pytest-xdist (>=3.5.0,<4)", "python-dotenv (>=1.0.0,<2)", "requests-mock (>=1.12.1,<2)", "ruff (>=0.11.2,<0.12)", "types-pyyaml (>=6.0.12.12,<7)", "types-requests (>=2.31.0,<3)"] docs = ["pydoc-markdown (>=4.8.2) ; python_version < \"3.12\""] fastembed = ["fastembed (>=0.3.0,<0.4) ; python_version < \"3.13\""] @@ -7222,6 +7245,7 @@ files = [ {file = "tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0"}, {file = "tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1"}, ] +markers = {main = "extra == \"extra-proxy\""} [[package]] name = "tornado" @@ -7994,4 +8018,4 @@ utils = ["numpydoc"] [metadata] lock-version = "2.1" python-versions = ">=3.9,<4.0" -content-hash = "1f3bbf967451633fb6290ba88980bdf4fbf83420024b14e862d1da717d903684" +content-hash = "0002021a7733b370a9855b26198e8e6dc49a62b67f1eface6f2fbe406ff3c3ac" diff --git a/pyproject.toml b/pyproject.toml index 0e2fb40d93..55a825d831 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -167,6 +167,7 @@ langfuse = "^2.45.0" fastapi-offline = "^1.7.3" fakeredis = "^2.27.1" pytest-rerunfailures = "^14.0" +parameterized = "^0.9.0" [tool.poetry.group.proxy-dev.dependencies] prisma = "0.11.0" diff --git a/tests/test_litellm/integrations/test_opentelemetry.py b/tests/test_litellm/integrations/test_opentelemetry.py index 3d6fc146a0..4e2d4d1ac7 100644 --- a/tests/test_litellm/integrations/test_opentelemetry.py +++ b/tests/test_litellm/integrations/test_opentelemetry.py @@ -3,7 +3,8 @@ import os import sys import time import unittest -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone +from parameterized import parameterized from unittest.mock import MagicMock, patch # Adds the grandparent directory to sys.path to allow importing project modules @@ -420,11 +421,12 @@ class TestOpenTelemetry(unittest.TestCase): otel.tracer = MagicMock() # Mock the dynamic header extraction and tracer creation - with patch.object( - otel, "_get_dynamic_otel_headers_from_kwargs" - ) as mock_get_headers, patch.object( - otel, "_get_tracer_with_dynamic_headers" - ) as mock_get_tracer: + with ( + patch.object( + otel, "_get_dynamic_otel_headers_from_kwargs" + ) as mock_get_headers, + patch.object(otel, "_get_tracer_with_dynamic_headers") as mock_get_tracer, + ): # Test case 1: With dynamic headers mock_get_headers.return_value = { "arize-space-id": "test-space", @@ -2165,10 +2167,15 @@ class TestOpenTelemetrySemanticConventions138(unittest.TestCase): mock_span.set_attribute.assert_any_call("gen_ai.operation.name", "chat") - def test_handle_failure_langfuse_otel_nulls_parent_span(self): + @parameterized.expand([("_handle_success",), ("_handle_failure",)]) + def test_handle_success_failure_nulls_parent_span_if_ignore_context_propagation( + self, handle_method: str + ): """ - For langfuse_otel, _handle_failure should ignore parent spans from other providers - and create a root-level error span (symmetric with _handle_success). + If ignore_context_propagation is True, _handle_success should ignore any parent span + and create a root-level error span. This could be useful for langfuse_otel where + _handle_success may ignore parent spans from other providers and create a root-level + error span (symmetric with _handle_failure). """ span_exporter = InMemorySpanExporter() tracer_provider = TracerProvider() @@ -2181,9 +2188,9 @@ class TestOpenTelemetrySemanticConventions138(unittest.TestCase): otel.tracer = tracer_provider.get_tracer("litellm") other_tracer = tracer_provider.get_tracer("other_provider") - other_span = other_tracer.start_span("other_provider_span") + other_span = other_tracer.start_span("parent_span") - start = datetime.utcnow() + start = datetime.now(timezone.utc) end = start + timedelta(seconds=1) kwargs = { @@ -2202,23 +2209,33 @@ class TestOpenTelemetrySemanticConventions138(unittest.TestCase): "exception": Exception("test error"), } - otel._handle_failure(kwargs, None, start, end) + with patch.dict(os.environ, {"USE_OTEL_LITELLM_REQUEST_SPAN": "true"}): + match handle_method: + case "_handle_success": + otel._handle_success(kwargs, None, start, end) + case "_handle_failure": + otel._handle_failure(kwargs, None, start, end) + case _: + self.fail(f"Invalid handle_method: {handle_method}") other_span.end() spans = span_exporter.get_finished_spans() - failure_spans = [s for s in spans if s.name != "other_provider_span"] + child_spans = [s for s in spans if s.name != "parent_span"] + child_span_ids = {s.context.span_id for s in child_spans if s.context} - self.assertTrue(failure_spans, "Expected at least one failure span") - for span in failure_spans: - self.assertIsNone( - span.parent, - f"langfuse_otel failure span should be a root span, but has parent: {span.parent}", - ) + self.assertTrue(child_spans, "Expected at least one child span") + for span in child_spans: + assert ( + span.parent is None or span.parent.span_id in child_span_ids + ), f"if ignore_context_propagation is True, span should not have parent from other providers, but got parent: {span.parent}" - def test_handle_failure_non_langfuse_preserves_parent_span(self): + @parameterized.expand([("_handle_success",), ("_handle_failure",)]) + def test_handle_success_failure_default_preserves_parent_span( + self, handle_method: str + ): """ - For non-langfuse_otel callbacks, _handle_failure should still use parent spans normally. + For default otel callbacks, _handle_success should use parent spans normally. """ span_exporter = InMemorySpanExporter() tracer_provider = TracerProvider() @@ -2229,7 +2246,7 @@ class TestOpenTelemetrySemanticConventions138(unittest.TestCase): parent_span = otel.tracer.start_span("parent_span") - start = datetime.utcnow() + start = datetime.now(timezone.utc) end = start + timedelta(seconds=1) kwargs = { @@ -2249,19 +2266,83 @@ class TestOpenTelemetrySemanticConventions138(unittest.TestCase): } with patch.dict(os.environ, {"USE_OTEL_LITELLM_REQUEST_SPAN": "true"}): - otel._handle_failure(kwargs, None, start, end) + match handle_method: + case "_handle_success": + otel._handle_success(kwargs, None, start, end) + case "_handle_failure": + otel._handle_failure(kwargs, None, start, end) + case _: + self.fail(f"Invalid handle_method: {handle_method}") parent_span.end() spans = span_exporter.get_finished_spans() child_spans = [s for s in spans if s.name != "parent_span"] - self.assertTrue(child_spans, "Expected at least one child failure span") + self.assertTrue(child_spans, "Expected at least one child span") for span in child_spans: - self.assertIsNotNone( - span.parent, - "Non-langfuse_otel failure span should have a parent", - ) + assert ( + span.parent is not None + ), f"By default parent span should be preserved, but got None parent for span: {span.name}" + + @parameterized.expand([("_handle_success",), ("_handle_failure",)]) + def test_handle_success_failure_with_context_propagation_preserves_parent_span( + self, handle_method: str + ): + """ + For otel callbacks with context propagation enabled, _handle__handle_success should + use parent spans normally. + """ + span_exporter = InMemorySpanExporter() + tracer_provider = TracerProvider() + tracer_provider.add_span_processor(SimpleSpanProcessor(span_exporter)) + + otel = OpenTelemetry( + config=OpenTelemetryConfig(ignore_context_propagation=False), + tracer_provider=tracer_provider, + ) + otel.tracer = tracer_provider.get_tracer("litellm") + + parent_span = otel.tracer.start_span("parent_span") + + start = datetime.now(timezone.utc) + end = start + timedelta(seconds=1) + + kwargs = { + "model": "gpt-4", + "messages": [{"role": "user", "content": "Hello"}], + "optional_params": {}, + "litellm_params": { + "custom_llm_provider": "openai", + "metadata": {"litellm_parent_otel_span": parent_span}, + }, + "standard_logging_object": { + "id": "test-id", + "call_type": "completion", + "metadata": {}, + }, + "exception": Exception("test error"), + } + + with patch.dict(os.environ, {"USE_OTEL_LITELLM_REQUEST_SPAN": "true"}): + match handle_method: + case "_handle_success": + otel._handle_success(kwargs, None, start, end) + case "_handle_failure": + otel._handle_failure(kwargs, None, start, end) + case _: + self.fail(f"Invalid handle_method: {handle_method}") + + parent_span.end() + + spans = span_exporter.get_finished_spans() + child_spans = [s for s in spans if s.name != "parent_span"] + + self.assertTrue(child_spans, "Expected at least one child span") + for span in child_spans: + assert ( + span.parent is not None + ), f"If ignore_context_propagation is False, parent span should be preserved, but got None parent for span: {span.name}" def test_handle_failure_hasattr_guard_on_parent_name(self): """ @@ -2431,9 +2512,7 @@ class TestNoParentSpanDuplication(unittest.TestCase): otel._handle_success(kwargs, response_obj, start, end) spans = span_exporter.get_finished_spans() - proxy_spans = [ - s for s in spans if s.name == LITELLM_PROXY_REQUEST_SPAN_NAME - ] + proxy_spans = [s for s in spans if s.name == LITELLM_PROXY_REQUEST_SPAN_NAME] self.assertEqual(len(proxy_spans), 1, "Should have exactly one proxy span") proxy_attrs = proxy_spans[0].attributes or {} From 7fac4d48ac9461de0271855467e0d9fd0a8e5617 Mon Sep 17 00:00:00 2001 From: jyeros Date: Wed, 18 Mar 2026 15:47:50 -0500 Subject: [PATCH 281/289] Update docs --- .../docs/observability/langfuse_otel_integration.md | 6 ++++++ docs/my-website/docs/proxy/config_settings.md | 1 + 2 files changed, 7 insertions(+) diff --git a/docs/my-website/docs/observability/langfuse_otel_integration.md b/docs/my-website/docs/observability/langfuse_otel_integration.md index b4c9a2bd1a..79ad2f6f75 100644 --- a/docs/my-website/docs/observability/langfuse_otel_integration.md +++ b/docs/my-website/docs/observability/langfuse_otel_integration.md @@ -83,6 +83,9 @@ os.environ["LANGFUSE_OTEL_HOST"] = "https://cloud.langfuse.com" # EU region # Or use self-hosted instance # os.environ["LANGFUSE_OTEL_HOST"] = "https://my-langfuse.company.com" +# Optional: Ignore otel context propagation to prevent parent-child relationships with spans from other providers +# os.environ["OTEL_IGNORE_CONTEXT_PROPAGATION"] = "true" + litellm.callbacks = ["langfuse_otel"] ``` @@ -124,6 +127,9 @@ export LANGFUSE_PUBLIC_KEY="pk-lf-..." export LANGFUSE_SECRET_KEY="sk-lf-..." export LANGFUSE_OTEL_HOST="https://us.cloud.langfuse.com" # Default US region # export LANGFUSE_OTEL_HOST="https://otel.my-langfuse.company.com" # custom OTEL endpoint + +# Optional: Ignore otel context propagation to prevent parent-child relationships with spans from other providers +# export OTEL_IGNORE_CONTEXT_PROPAGATION="true" ``` 2. Setup config.yaml diff --git a/docs/my-website/docs/proxy/config_settings.md b/docs/my-website/docs/proxy/config_settings.md index f5b611a85a..46f557d042 100644 --- a/docs/my-website/docs/proxy/config_settings.md +++ b/docs/my-website/docs/proxy/config_settings.md @@ -100,6 +100,7 @@ litellm_settings: callback_settings: otel: message_logging: boolean # OTEL logging callback specific settings + ignore_context_propagation: boolean # if true, spans created by the OTEL callback will not have parent spans from other providers, even if OTEL context propagation is enabled. This can help prevent issues with incorrect parent-child relationships in spans when multiple providers are used. general_settings: completion_model: string From f88e51e1b925f82909d805f0b1a97c8734c50de9 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Wed, 18 Mar 2026 14:07:22 -0700 Subject: [PATCH 282/289] =?UTF-8?q?bump:=20version=200.4.57=20=E2=86=92=20?= =?UTF-8?q?0.4.58?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- litellm-proxy-extras/pyproject.toml | 4 ++-- pyproject.toml | 2 +- requirements.txt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/litellm-proxy-extras/pyproject.toml b/litellm-proxy-extras/pyproject.toml index 006aad9480..8aa9e70e43 100644 --- a/litellm-proxy-extras/pyproject.toml +++ b/litellm-proxy-extras/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "litellm-proxy-extras" -version = "0.4.57" +version = "0.4.58" description = "Additional files for the LiteLLM Proxy. Reduces the size of the main litellm package." authors = ["BerriAI"] readme = "README.md" @@ -22,7 +22,7 @@ requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" [tool.commitizen] -version = "0.4.57" +version = "0.4.58" version_files = [ "pyproject.toml:version", "../requirements.txt:litellm-proxy-extras==", diff --git a/pyproject.toml b/pyproject.toml index 0e2fb40d93..15fa1e3bb2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ boto3 = { version = "^1.40.76", optional = true } redisvl = {version = "^0.4.1", optional = true, markers = "python_version >= '3.9' and python_version < '3.14'"} mcp = {version = ">=1.25.0,<2.0.0", optional = true, python = ">=3.10"} a2a-sdk = {version = "^0.3.22", optional = true, python = ">=3.10"} -litellm-proxy-extras = {version = "^0.4.57", optional = true} +litellm-proxy-extras = {version = "^0.4.58", optional = true} rich = {version = "^13.7.1", optional = true} litellm-enterprise = {version = "^0.1.33", optional = true} diskcache = {version = "^5.6.1", optional = true} diff --git a/requirements.txt b/requirements.txt index 827986487f..d420f4ac60 100644 --- a/requirements.txt +++ b/requirements.txt @@ -57,7 +57,7 @@ grpcio>=1.75.0; python_version >= "3.14" sentry_sdk==2.21.0 # for sentry error handling detect-secrets==1.5.0 # Enterprise - secret detection / masking in LLM requests tzdata==2025.1 # IANA time zone database -litellm-proxy-extras==0.4.57 # for proxy extras - e.g. prisma migrations +litellm-proxy-extras==0.4.58 # for proxy extras - e.g. prisma migrations llm-sandbox==0.3.31 # for skill execution in sandbox ### LITELLM PACKAGE DEPENDENCIES python-dotenv==1.0.1 # for env From 7aa673a1375f9054a9df3c4ceb4675c5ecc72b54 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Wed, 18 Mar 2026 14:07:43 -0700 Subject: [PATCH 283/289] adding build --- ...litellm_proxy_extras-0.4.58-py3-none-any.whl | Bin 0 -> 76589 bytes .../dist/litellm_proxy_extras-0.4.58.tar.gz | Bin 0 -> 32038 bytes .../migration.sql | 9 +++++++++ 3 files changed, 9 insertions(+) create mode 100644 litellm-proxy-extras/dist/litellm_proxy_extras-0.4.58-py3-none-any.whl create mode 100644 litellm-proxy-extras/dist/litellm_proxy_extras-0.4.58.tar.gz create mode 100644 litellm-proxy-extras/litellm_proxy_extras/migrations/20260318140652_add_index_to_team_table/migration.sql diff --git a/litellm-proxy-extras/dist/litellm_proxy_extras-0.4.58-py3-none-any.whl b/litellm-proxy-extras/dist/litellm_proxy_extras-0.4.58-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..756080f85444bd262788ecc555780fd4d4264a11 GIT binary patch literal 76589 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 literal 0 HcmV?d00001 diff --git a/litellm-proxy-extras/dist/litellm_proxy_extras-0.4.58.tar.gz b/litellm-proxy-extras/dist/litellm_proxy_extras-0.4.58.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..8a52b0584056ce8886164d679617f3d60f298c83 GIT binary patch literal 32038 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 Date: Wed, 18 Mar 2026 14:09:46 -0700 Subject: [PATCH 284/289] updating poetry lock --- poetry.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 591d0c270e..2c8a125a6e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3219,15 +3219,15 @@ files = [ [[package]] name = "litellm-proxy-extras" -version = "0.4.56" +version = "0.4.58" description = "Additional files for the LiteLLM Proxy. Reduces the size of the main litellm package." optional = true python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8" groups = ["main"] markers = "extra == \"proxy\"" files = [ - {file = "litellm_proxy_extras-0.4.56-py3-none-any.whl", hash = "sha256:52dbe3b5358c790e77e12f1ec5ef8e7508b383c2aaf41299750b6fb400908ee7"}, - {file = "litellm_proxy_extras-0.4.56.tar.gz", hash = "sha256:63ad59baa0defccc5c929cfd933ee7e32a6614b0fc5fa0fc45a12d7608e33f08"}, + {file = "litellm_proxy_extras-0.4.58-py3-none-any.whl", hash = "sha256:8863e70de833c0e35119a1cbbf583619bdebe52222efd5654586519175ba403b"}, + {file = "litellm_proxy_extras-0.4.58.tar.gz", hash = "sha256:84a67483329eced8be4fc61c4e43f117287aa4e3deeb8ddf8fe8cdc9a8508836"}, ] [[package]] @@ -7994,4 +7994,4 @@ utils = ["numpydoc"] [metadata] lock-version = "2.1" python-versions = ">=3.9,<4.0" -content-hash = "1f3bbf967451633fb6290ba88980bdf4fbf83420024b14e862d1da717d903684" +content-hash = "eda34dfd8b35474beffee18893d6782c7b3d0d3d2c610f66237eb97176f43527" From 02ebd1302e088a531cd1aa6579f1c4d2349b26ca Mon Sep 17 00:00:00 2001 From: jyeros Date: Wed, 18 Mar 2026 16:12:37 -0500 Subject: [PATCH 285/289] Code review --- docs/my-website/docs/proxy/config_settings.md | 1 - .../integrations/test_opentelemetry.py | 60 +++++++++---------- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/docs/my-website/docs/proxy/config_settings.md b/docs/my-website/docs/proxy/config_settings.md index 46f557d042..f5b611a85a 100644 --- a/docs/my-website/docs/proxy/config_settings.md +++ b/docs/my-website/docs/proxy/config_settings.md @@ -100,7 +100,6 @@ litellm_settings: callback_settings: otel: message_logging: boolean # OTEL logging callback specific settings - ignore_context_propagation: boolean # if true, spans created by the OTEL callback will not have parent spans from other providers, even if OTEL context propagation is enabled. This can help prevent issues with incorrect parent-child relationships in spans when multiple providers are used. general_settings: completion_model: string diff --git a/tests/test_litellm/integrations/test_opentelemetry.py b/tests/test_litellm/integrations/test_opentelemetry.py index 4e2d4d1ac7..450f4ab83e 100644 --- a/tests/test_litellm/integrations/test_opentelemetry.py +++ b/tests/test_litellm/integrations/test_opentelemetry.py @@ -421,12 +421,12 @@ class TestOpenTelemetry(unittest.TestCase): otel.tracer = MagicMock() # Mock the dynamic header extraction and tracer creation - with ( - patch.object( - otel, "_get_dynamic_otel_headers_from_kwargs" - ) as mock_get_headers, - patch.object(otel, "_get_tracer_with_dynamic_headers") as mock_get_tracer, - ): + with patch.object( + otel, "_get_dynamic_otel_headers_from_kwargs" + ) as mock_get_headers, patch.object( + otel, "_get_tracer_with_dynamic_headers" + ) as mock_get_tracer: + # Test case 1: With dynamic headers mock_get_headers.return_value = { "arize-space-id": "test-space", @@ -2173,9 +2173,9 @@ class TestOpenTelemetrySemanticConventions138(unittest.TestCase): ): """ If ignore_context_propagation is True, _handle_success should ignore any parent span - and create a root-level error span. This could be useful for langfuse_otel where + and create a root-level span. This could be useful for langfuse_otel where _handle_success may ignore parent spans from other providers and create a root-level - error span (symmetric with _handle_failure). + span (symmetric with _handle_failure). """ span_exporter = InMemorySpanExporter() tracer_provider = TracerProvider() @@ -2210,13 +2210,12 @@ class TestOpenTelemetrySemanticConventions138(unittest.TestCase): } with patch.dict(os.environ, {"USE_OTEL_LITELLM_REQUEST_SPAN": "true"}): - match handle_method: - case "_handle_success": - otel._handle_success(kwargs, None, start, end) - case "_handle_failure": - otel._handle_failure(kwargs, None, start, end) - case _: - self.fail(f"Invalid handle_method: {handle_method}") + if handle_method == "_handle_success": + otel._handle_success(kwargs, None, start, end) + elif handle_method == "_handle_failure": + otel._handle_failure(kwargs, None, start, end) + else: + self.fail(f"Invalid handle_method: {handle_method}") other_span.end() @@ -2236,6 +2235,7 @@ class TestOpenTelemetrySemanticConventions138(unittest.TestCase): ): """ For default otel callbacks, _handle_success should use parent spans normally. + (symmetric with _handle_failure) """ span_exporter = InMemorySpanExporter() tracer_provider = TracerProvider() @@ -2266,13 +2266,12 @@ class TestOpenTelemetrySemanticConventions138(unittest.TestCase): } with patch.dict(os.environ, {"USE_OTEL_LITELLM_REQUEST_SPAN": "true"}): - match handle_method: - case "_handle_success": - otel._handle_success(kwargs, None, start, end) - case "_handle_failure": - otel._handle_failure(kwargs, None, start, end) - case _: - self.fail(f"Invalid handle_method: {handle_method}") + if handle_method == "_handle_success": + otel._handle_success(kwargs, None, start, end) + elif handle_method == "_handle_failure": + otel._handle_failure(kwargs, None, start, end) + else: + self.fail(f"Invalid handle_method: {handle_method}") parent_span.end() @@ -2290,8 +2289,8 @@ class TestOpenTelemetrySemanticConventions138(unittest.TestCase): self, handle_method: str ): """ - For otel callbacks with context propagation enabled, _handle__handle_success should - use parent spans normally. + For otel callbacks with context propagation enabled, _handle_success should + use parent spans normally. (symmetric with _handle_failure) """ span_exporter = InMemorySpanExporter() tracer_provider = TracerProvider() @@ -2325,13 +2324,12 @@ class TestOpenTelemetrySemanticConventions138(unittest.TestCase): } with patch.dict(os.environ, {"USE_OTEL_LITELLM_REQUEST_SPAN": "true"}): - match handle_method: - case "_handle_success": - otel._handle_success(kwargs, None, start, end) - case "_handle_failure": - otel._handle_failure(kwargs, None, start, end) - case _: - self.fail(f"Invalid handle_method: {handle_method}") + if handle_method == "_handle_success": + otel._handle_success(kwargs, None, start, end) + elif handle_method == "_handle_failure": + otel._handle_failure(kwargs, None, start, end) + else: + self.fail(f"Invalid handle_method: {handle_method}") parent_span.end() From 8e61b32b8e76b3318cd74532fa4dcf1af51803c4 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 18 Mar 2026 15:09:01 -0700 Subject: [PATCH 286/289] [Staging] - Ishaan March 17th (#23903) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(xai): add grok-4.20 beta 2 models with pricing (#23900) Add three grok-4.20 beta 2 model variants from xAI: - grok-4.20-multi-agent-beta-0309 (reasoning + multi-agent) - grok-4.20-beta-0309-reasoning (reasoning) - grok-4.20-beta-0309-non-reasoning Pricing (from https://docs.x.ai/docs/models): - Input: $2.00/1M tokens ($0.20/1M cached) - Output: $6.00/1M tokens - Context: 2M tokens All variants support vision, function calling, tool choice, and web search. Closes LIT-2171 * docs: add Quick Install section for litellm --setup wizard (#23905) * docs: add Quick Install section for litellm --setup wizard * docs: clarify setup wizard is for local/beginner use * feat(setup): interactive setup wizard + install.sh (#23644) * feat(setup): add interactive setup wizard + install.sh Adds `litellm --setup` — a Claude Code-style TUI onboarding wizard that guides users through provider selection, API key entry, and proxy config generation, then optionally starts the proxy immediately. - litellm/setup_wizard.py: wizard with ASCII art, numbered provider menu (OpenAI, Anthropic, Azure, Gemini, Bedrock, Ollama), API key prompts, port/master-key config, and litellm_config.yaml generation - litellm/proxy/proxy_cli.py: adds --setup flag that invokes the wizard - scripts/install.sh: curl-installable script (detect OS/Python, pip install litellm[proxy], launch wizard) Usage: curl -fsSL https://raw.githubusercontent.com/BerriAI/litellm/main/scripts/install.sh | sh litellm --setup * fix(install.sh): remove orange color, add LITELLM_BRANCH env var for branch installs * fix(install.sh): install from git branch so --setup is available for QA * fix(install.sh): remove stale LITELLM_BRANCH reference that caused unbound variable error * fix(install.sh): force-reinstall from git to bypass cached PyPI version * fix(install.sh): show pip progress bar during install * fix(install.sh): always launch wizard via $PYTHON_BIN -m litellm, not PATH binary * fix(install.sh): use litellm.proxy.proxy_cli module (no __main__.py exists) * fix(install.sh): suppress RuntimeWarning from module invocation * fix(install.sh): use Python bin-dir litellm binary to avoid CWD sys.path shadowing * fix(install.sh): use sysconfig.get_path('scripts') to find pip-installed litellm binary * fix(install.sh): redirect stdin from /dev/tty on exec so wizard gets terminal, not exhausted pipe * fix(install.sh): warn about git clone duration, drop --no-cache-dir so re-runs are faster * feat(setup_wizard): arrow-key selector, updated model names * fix(setup_wizard): use sysconfig binary to start proxy, not python -m litellm * feat(setup_wizard): credential validation after key entry + clear next-steps after proxy start * style(install.sh): show git clone warning in blue * refactor(setup_wizard): class with static methods, use check_valid_key from litellm.utils * address greptile review: fix yaml escaping, port validation, display name collisions, tests - setup_wizard.py: add _yaml_escape() for safe YAML embedding of API keys - setup_wizard.py: add _styled_input() with readline ANSI ignore markers - setup_wizard.py: change DIVIDER to _divider() fn to avoid import-time color capture - setup_wizard.py: validate port range 1-65535, initialize before loop - setup_wizard.py: qualify azure display names (azure-gpt-4o) to avoid collision with openai - setup_wizard.py: work on env_copy in _build_config to avoid mutating caller's dict - setup_wizard.py: skip model_list entries for providers with no credentials - setup_wizard.py: prompt for azure deployment name - setup_wizard.py: wrap os.execlp in try/except with friendly fallback - setup_wizard.py: wrap config write in try/except OSError - setup_wizard.py: fix _validate_and_report to use two print lines (no \r overwrite) - setup_wizard.py: add .gitignore tip next to key storage notice - setup_wizard.py: fix run_setup_wizard() return type annotation to None - scripts/install.sh: drop pipefail (not supported by dash on Ubuntu when invoked as sh) - scripts/install.sh: use litellm[proxy] from PyPI (not hardcoded dev branch) - scripts/install.sh: guard /dev/tty read with -r check for Docker/CI compat - scripts/install.sh: remove --force-reinstall to avoid downgrading dependencies - tests/test_litellm/test_setup_wizard.py: 13 unit tests for _build_config and _yaml_escape * style: black format setup_wizard.py * fix: address remaining greptile issues - Windows compat, YAML quoting, credential flow - guard termios/tty imports with try/except ImportError for Windows compat - quote master_key as YAML double-quoted scalar (same as env vars) - remove unused port param from _build_config signature - _validate_and_report now returns the final key so re-entered creds are stored - add test for master_key YAML quoting * fix: add --port to suggested command, guard /dev/tty exec in install.sh * fix: quote api_base in YAML, skip azure if no deployment, only redraw on state change * fix: address greptile review comments - _yaml_escape: add control character escaping (\n, \r, \t) - test: fix tautological assertion in test_build_config_azure_no_deployment_skipped - test: add tests for control character escaping in _yaml_escape * feat(ui): remove Chat UI page link and banner from sidebar and playground (#23908) * feat(guardrails): MCPJWTSigner - built-in guardrail for zero trust MCP auth (#23897) * Allow pre_mcp_call guardrail hooks to mutate outbound MCP headers * Enhance MCPServerManager to support hook-modified arguments and extra headers. Update tests to validate argument mutation and header injection behavior, including warnings for OpenAPI-backed servers when headers are present. * Refactor MCPServerManager to raise HTTPException for extra headers in OpenAPI-backed servers. Update tests to reflect this change, ensuring proper exception handling instead of logging warnings. * Allow pre_mcp_call guardrail hooks to mutate outbound MCP headers * Enhance MCPServerManager to support hook-modified arguments and extra headers. Update tests to validate argument mutation and header injection behavior, including warnings for OpenAPI-backed servers when headers are present. * Refactor MCPServerManager to raise HTTPException for extra headers in OpenAPI-backed servers. Update tests to reflect this change, ensuring proper exception handling instead of logging warnings. * feat(guardrails): add MCPJWTSigner built-in guardrail for zero trust MCP auth Signs outbound MCP tool calls with a LiteLLM-issued RS256 JWT so MCP servers can trust a single signing authority instead of every upstream IdP. Enable in config.yaml: guardrails: - guardrail_name: mcp-jwt-signer litellm_params: guardrail: mcp_jwt_signer mode: pre_mcp_call default_on: true JWT carries sub (user_id), act.sub (team_id, RFC 8693), tool-level scope, iss, aud, iat/exp/nbf. RSA-2048 keypair auto-generated at startup unless MCP_JWT_SIGNING_KEY env var is set. Adds /.well-known/jwks.json endpoint and jwks_uri to /.well-known/openid-configuration so MCP servers can verify LiteLLM-issued tokens via OIDC discovery. * Update MCPServerManager to raise HTTPException with status code 400 for extra headers in OpenAPI-backed servers. Adjust tests to verify the correct status code and exception message. * fix: address P1 issues in MCPJWTSigner - OpenAPI servers: warn + skip header injection instead of 500 - JWKS Cache-Control: 5min for auto-generated keys, 1h for persistent - sub claim: fallback to apikey:{token_hash} for anonymous callers - ttl_seconds: validate > 0 at init time * docs: add MCP zero trust auth guide with architecture diagram * docs: add FastMCP JWT verification guide to zero trust doc * fix: address remaining Greptile review issues (round 2) - mcp_server_manager: warn when hook Authorization overwrites existing header - __init__: remove _mcp_jwt_signer_instance from __all__ (private internal) - discoverable_endpoints: copy dict instead of mutating in-place on OIDC augmentation - test docstring: reflect warn-and-continue behavior for OpenAPI servers - test: update scope assertions for least-privilege (no mcp:tools/list on tool-call JWTs) * fix: address Greptile round 3 feedback - initialize_guardrail: validate mode='pre_mcp_call' at init time — misconfigured mode silently bypasses JWT injection, which is a zero-trust bypass - _build_claims: remove duplicate inline 'import re' (module-level import already present) - _types.py: add TODO comment explaining jwt_claims is forward-compat plumbing for a follow-up PR that will forward upstream IdP claims into outbound MCP JWTs * feat(mcp_jwt_signer): add verify+re-sign, claim ops, two-token model, configurable scopes Addresses all missing pieces from the scoping doc review: FR-5 (Verify + re-sign): MCPJWTSigner now accepts access_token_discovery_uri and token_introspection_endpoint. When set, the incoming Bearer token is extracted from raw_headers (threaded through pre_call_tool_check), verified against the IdP's JWKS (JWT) or introspected (opaque), and only re-signed if valid. Falls back to user_api_key_dict.jwt_claims for LiteLLM JWT-auth mode. FR-12 (Configurable end-user identity mapping): end_user_claim_sources ordered list drives sub resolution — sources: token:, litellm:user_id, litellm:email, litellm:end_user_id, litellm:team_id. FR-13 (Claim operations): add_claims (insert-if-absent), set_claims (always override), remove_claims (delete) applied in that order. FR-14 (Two-token model): channel_token_audience + channel_token_ttl issue a second JWT injected as x-mcp-channel-token: Bearer . FR-15 (Incoming claim validation): required_claims raises HTTP 403 when any listed claim is absent; optional_claims passes listed claims from verified token into the outbound JWT. FR-9 (Debug headers): debug_headers: true emits x-litellm-mcp-debug with kid, sub, iss, exp, scope. FR-10 (Configurable scopes): allowed_scopes replaces auto-generation. Also fixed: tool-call JWTs no longer grant mcp:tools/list (overpermission). P1 fixes: - proxy/utils.py: _convert_mcp_hook_response_to_kwargs merges rather than replaces extra_headers, preserving headers from prior guardrails. - mcp_server_manager.py: warns when hook injects Authorization alongside a server-configured authentication_token (previously silent). - mcp_server_manager.py: pre_call_tool_check now accepts raw_headers and extracts incoming_bearer_token so FR-5 verification has the raw token. - proxy/utils.py: remove stray inline import inspect inside loop (pre-existing lint error, now cleaned up). Tests: 43 passing (28 new tests covering all FR flags + P1 fixes). * feat(mcp_jwt_signer): add verify+re-sign, claim ops, two-token model, configurable scopes (core) Remaining files from the FR implementation: mcp_jwt_signer.py — full rewrite with all new params: FR-5: access_token_discovery_uri, token_introspection_endpoint, verify_issuer, verify_audience + _verify_incoming_jwt(), _introspect_opaque_token() FR-12: end_user_claim_sources ordered resolution chain FR-13: add_claims, set_claims, remove_claims FR-14: channel_token_audience, channel_token_ttl → x-mcp-channel-token FR-15: required_claims (raises 403), optional_claims (passthrough) FR-9: debug_headers → x-litellm-mcp-debug FR-10: allowed_scopes; tool-call JWTs no longer over-grant tools/list mcp_server_manager.py: - pre_call_tool_check gains raw_headers param to extract incoming_bearer_token - Silent Authorization override warning fixed: now fires when server has authentication_token AND hook injects Authorization tests/test_mcp_jwt_signer.py: 28 new tests covering all FR flags + P1 fixes (43 total, all passing) * fix(mcp_jwt_signer): address pre-landing review issues - Remove stale TODO comment on UserAPIKeyAuth.jwt_claims — the field is already populated and consumed by MCPJWTSigner in the same PR - Fix _get_oidc_discovery to only cache the OIDC discovery doc when jwks_uri is present; a malformed/empty doc now retries on the next request instead of being permanently cached until proxy restart - Add FR-5 test coverage for _fetch_jwks (cache hit/miss), _get_oidc_discovery (cache/no-cache on bad doc), _verify_incoming_jwt (valid token, expired token), _introspect_opaque_token (active, inactive, no endpoint), and the end-to-end 401 hook path — 53 tests total, all passing * docs(mcp_zero_trust): rewrite as use-case guide covering all new JWT signer features Add scenario-driven sections for each new config area: - Verify+re-sign with Okta/Azure AD (access_token_discovery_uri, end_user_claim_sources, token_introspection_endpoint) - Enforcing caller attributes with required_claims / optional_claims - Adding metadata via add_claims / set_claims / remove_claims - Two-token model for AWS Bedrock AgentCore Gateway (channel_token_audience / channel_token_ttl) - Controlling scopes with allowed_scopes - Debugging JWT rejections with debug_headers Update JWT claims table to reflect configurable sub (end_user_claim_sources) * fix(mcp_jwt_signer): wire all config.yaml params through initialize_guardrail The factory was only passing issuer/audience/ttl_seconds to MCPJWTSigner. All FR-5/9/10/12/13/14/15 params (access_token_discovery_uri, end_user_claim_sources, add/set/remove_claims, channel_token_audience, required/optional_claims, debug_headers, allowed_scopes, etc.) were silently dropped, making every advertised advanced feature non-functional when loaded from config.yaml. Add regression test that asserts every param is wired through correctly. * docs(mcp_zero_trust): add hero image * docs(mcp_zero_trust): apply Linear-style edits - Lead with the problem (unsigned direct calls bypass access controls) - Shorter statement section headers instead of question-form headers - Move diagram/OIDC discovery block after the reader is bought in - Add 'read further only if you need to' callout after basic setup - Two-token section now opens from the user problem not product jargon - Add concrete 403 error response example in required_claims section - Debug section opens from the symptom (MCP server returning 401) - Lowercase claims reference header for consistency * fix(mcp_jwt_signer): fix algorithm confusion attack + add OIDC discovery 24h TTL - Remove alg from unverified JWT header; use signing_jwk.algorithm_name from JWKS key instead. Reading alg from attacker-controlled headers enables alg:none / HS256 confusion attacks. - Add _oidc_discovery_fetched_at timestamp and _OIDC_DISCOVERY_TTL = 86400 (24h). Without a TTL the cached discovery doc never refreshes, so IdP key rotation is invisible. --------- Co-authored-by: Noah Nistler <60981020+noahnistler@users.noreply.github.com> * fix(ci): stabilize CI - formatting, type errors, test polling, security CVEs, router bug, batch resolution Fix 1: Run Black formatter on 35 files Fix 2: Fix MyPy type errors: - setup_wizard.py: add type annotation for 'selected' set variable - user_api_key_auth.py: remove redundant type annotation on jwt_claims reassignment Fix 3: Fix spend accuracy test burst 2 polling to wait for expected total spend instead of just 'any increase' from burst 2 Fix 4: Bump Next.js 16.1.6 -> 16.1.7 to fix CVE-2026-27978, CVE-2026-27979, CVE-2026-27980, CVE-2026-29057 Fix 5: Fix router _pre_call_checks model variable being overwritten inside loop, causing wrong model lookups on subsequent deployments. Use local _deployment_model variable instead. Fix 6: Add missing resolve_output_file_ids_to_unified call in batch retrieve non-terminal-to-terminal path (matching the terminal path behavior) Co-authored-by: Ishaan Jaff * chore: regenerate poetry.lock to sync with pyproject.toml Co-authored-by: Ishaan Jaff * fix: format merged files from main and regenerate poetry.lock Co-authored-by: Ishaan Jaff * fix(mypy): annotate jwt_claims as Optional[dict] to fix type incompatibility Co-authored-by: Ishaan Jaff * fix(ci): update router region test to use gpt-4.1-mini (fix flaky model lookup) Replace deprecated gpt-3.5-turbo-1106 with gpt-4.1-mini + mock_response in test_router_region_pre_call_check, following the same pattern used in commit 717d37cc5b for test_router_context_window_check_pre_call_check_out_group. Co-authored-by: Ishaan Jaff * ci: retry flaky logging_testing (async event loop race condition) Co-authored-by: Ishaan Jaff * fix(ci): aggregate all mock calls in langfuse e2e test to fix race condition The _verify_langfuse_call helper only inspected the last mock call (mock_post.call_args), but the Langfuse SDK may split trace-create and generation-create events across separate HTTP flush cycles. This caused an IndexError when the last call's batch contained only one event type. Fix: iterate over mock_post.call_args_list to collect batch items from ALL calls. Also add a safety assertion after filtering by trace_id and mark all langfuse e2e tests with @pytest.mark.flaky(retries=3) as an extra safety net for any residual timing issues. Co-authored-by: Ishaan Jaff * fix(ci): black formatting + update OpenAPI compliance tests for spec changes - Apply Black 26.x formatting to litellm_logging.py (parenthesized style) - Update test_input_types_match_spec to follow $ref to InteractionsInput schema (Google updated their OpenAPI spec to use $ref instead of inline oneOf) - Update test_content_schema_uses_discriminator to handle discriminator without explicit mapping (Google removed the mapping key from Content discriminator) Co-authored-by: Ishaan Jaff * revert: undo incorrect Black 26.x formatting on litellm_logging.py The file was correctly formatted for Black 23.12.1 (the version pinned in pyproject.toml). The previous commit applied Black 26.x formatting which was incompatible with the CI's Black version. Co-authored-by: Ishaan Jaff * fix(ci): deduplicate and sort langfuse batch events after aggregation The Langfuse SDK may send the same event (e.g., trace-create) in multiple flush cycles, causing duplicates when we aggregate from all mock calls. After filtering by trace_id, deduplicate by keeping only the first event of each type, then sort to ensure trace-create is at index 0 and generation-create at index 1. Co-authored-by: Ishaan Jaff --------- Co-authored-by: Noah Nistler <60981020+noahnistler@users.noreply.github.com> Co-authored-by: Cursor Agent Co-authored-by: Ishaan Jaff --- CLAUDE.md | 5 + .../docs/proxy/docker_quick_start.md | 73 +- .../my-website/img/mcp_zero_trust_gateway.png | Bin 0 -> 301348 bytes docs/my-website/sidebars.js | 1 + litellm/__init__.py | 12 +- litellm/_logging.py | 8 +- litellm/cost_calculator.py | 8 +- .../focus/destinations/factory.py | 7 +- .../langfuse/langfuse_prompt_management.py | 6 +- .../integrations/vantage/vantage_logger.py | 8 +- .../litellm_core_utils/default_encoding.py | 5 +- litellm/litellm_core_utils/litellm_logging.py | 288 ++--- .../prompt_templates/factory.py | 16 +- .../adapters/transformation.py | 2 +- .../llms/base_llm/videos/transformation.py | 16 +- litellm/llms/custom_httpx/llm_http_handler.py | 20 +- litellm/llms/gemini/videos/transformation.py | 31 +- litellm/llms/moonshot/chat/transformation.py | 18 +- .../llms/runwayml/videos/transformation.py | 39 +- litellm/llms/sagemaker/chat/transformation.py | 4 +- .../llms/vertex_ai/batches/transformation.py | 4 +- .../llms/vertex_ai/videos/transformation.py | 39 +- litellm/main.py | 4 +- ...odel_prices_and_context_window_backup.json | 47 + .../mcp_server/discoverable_endpoints.py | 55 +- .../mcp_server/mcp_server_manager.py | 72 +- .../mcp_server/rest_endpoints.py | 12 +- litellm/proxy/_types.py | 3 + litellm/proxy/auth/auth_utils.py | 10 +- litellm/proxy/auth/user_api_key_auth.py | 5 + litellm/proxy/batches_endpoints/endpoints.py | 3 +- .../mcp_jwt_signer/__init__.py | 84 ++ .../mcp_jwt_signer/mcp_jwt_signer.py | 891 +++++++++++++ .../internal_user_endpoints.py | 3 +- .../key_management_endpoints.py | 10 +- .../management_endpoints/team_endpoints.py | 8 +- .../openai_files_endpoints/common_utils.py | 5 +- litellm/proxy/proxy_cli.py | 15 +- .../response_polling/background_streaming.py | 9 +- .../proxy/spend_tracking/vantage_endpoints.py | 31 +- litellm/proxy/utils.py | 23 +- litellm/proxy/video_endpoints/utils.py | 4 +- litellm/responses/main.py | 60 +- litellm/router.py | 23 +- litellm/setup_wizard.py | 668 ++++++++++ litellm/types/guardrails.py | 1 + litellm/types/proxy/vantage_endpoints.py | 3 +- litellm/types/videos/utils.py | 4 +- litellm/videos/main.py | 34 +- model_prices_and_context_window.json | 47 + scripts/install.sh | 143 +++ tests/local_testing/test_router.py | 3 +- .../test_langfuse_e2e_test.py | 66 +- .../test_spend_accuracy_tests.py | 13 +- .../interactions/test_openapi_compliance.py | 24 +- .../llms/xai/test_xai_cost_calculator.py | 52 +- .../mcp_server/test_mcp_hook_extra_headers.py | 707 +++++++++++ .../proxy/guardrails/test_mcp_jwt_signer.py | 1103 +++++++++++++++++ tests/test_litellm/test_setup_wizard.py | 188 +++ .../app/(dashboard)/components/Sidebar2.tsx | 36 - .../src/app/(dashboard)/playground/page.tsx | 66 - 61 files changed, 4695 insertions(+), 450 deletions(-) create mode 100644 docs/my-website/img/mcp_zero_trust_gateway.png create mode 100644 litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/__init__.py create mode 100644 litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/mcp_jwt_signer.py create mode 100644 litellm/setup_wizard.py create mode 100755 scripts/install.sh create mode 100644 tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_hook_extra_headers.py create mode 100644 tests/test_litellm/proxy/guardrails/test_mcp_jwt_signer.py create mode 100644 tests/test_litellm/test_setup_wizard.py diff --git a/CLAUDE.md b/CLAUDE.md index d9061b5e2b..f047812018 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -140,6 +140,11 @@ LiteLLM is a unified interface for 100+ LLM providers with two main components: - **Check index coverage.** For new or modified queries, check `schema.prisma` for a supporting index. Prefer extending an existing index (e.g. `@@index([a])` → `@@index([a, b])`) over adding a new one, unless it's a `@@unique`. Only add indexes for large/frequent queries. - **Keep schema files in sync.** Apply schema changes to all `schema.prisma` copies (`schema.prisma`, `litellm/proxy/`, `litellm-proxy-extras/`, `litellm-js/spend-logs/` for SpendLogs) with a migration under `litellm-proxy-extras/litellm_proxy_extras/migrations/`. +### Setup Wizard (`litellm/setup_wizard.py`) +- The wizard is implemented as a single `SetupWizard` class with `@staticmethod` methods — keep it that way. No module-level functions except `run_setup_wizard()` (the public entrypoint) and pure helpers (color, ANSI). +- Use `litellm.utils.check_valid_key(model, api_key)` for credential validation — never roll a custom completion call. +- Do not hardcode provider env-key names or model lists that already exist in the codebase. Add a `test_model` field to each provider entry to drive `check_valid_key`; set it to `None` for providers that can't be validated with a single API key (Azure, Bedrock, Ollama). + ### Enterprise Features - Enterprise-specific code in `enterprise/` directory - Optional features enabled via environment variables diff --git a/docs/my-website/docs/proxy/docker_quick_start.md b/docs/my-website/docs/proxy/docker_quick_start.md index 4975c76c61..58a5660475 100644 --- a/docs/my-website/docs/proxy/docker_quick_start.md +++ b/docs/my-website/docs/proxy/docker_quick_start.md @@ -5,11 +5,76 @@ import Image from '@theme/IdealImage'; # Getting Started Tutorial End-to-End tutorial for LiteLLM Proxy to: -- Add an Azure OpenAI model -- Make a successful /chat/completion call -- Generate a virtual key -- Set RPM limit on virtual key +- Add an Azure OpenAI model +- Make a successful /chat/completion call +- Generate a virtual key +- Set RPM limit on virtual key +## Quick Install (Recommended for local / beginners) + +New to LiteLLM? This is the easiest way to get started locally. One command installs LiteLLM and walks you through setup interactively — no config files to write by hand. + +### 1. Install + +```bash +curl -fsSL https://raw.githubusercontent.com/BerriAI/litellm/main/scripts/install.sh | sh +``` + +This detects your OS, installs `litellm[proxy]`, and drops you straight into the setup wizard. + +### 2. Follow the wizard + +``` +$ litellm --setup + + Welcome to LiteLLM + + Choose your LLM providers + ○ 1. OpenAI GPT-4o, GPT-4o-mini, o1 + ○ 2. Anthropic Claude Opus, Sonnet, Haiku + ○ 3. Azure OpenAI GPT-4o via Azure + ○ 4. Google Gemini Gemini 2.0 Flash, 1.5 Pro + ○ 5. AWS Bedrock Claude, Llama via AWS + ○ 6. Ollama Local models + + ❯ Provider(s): 1,2 + + ❯ OpenAI API key: sk-... + ❯ Anthropic API key: sk-ant-... + + ❯ Port [4000]: + ❯ Master key [auto-generate]: + + ✔ Config saved → ./litellm_config.yaml + + ❯ Start the proxy now? (Y/n): +``` + +The wizard walks you through: +1. Pick your LLM providers (OpenAI, Anthropic, Azure, Bedrock, Gemini, Ollama) +2. Enter API keys for each provider +3. Set a port and master key (or accept the defaults) +4. Config is saved to `./litellm_config.yaml` and the proxy starts immediately + +### 3. Make a call + +Your proxy is running on `http://0.0.0.0:4000`. Test it: + +```bash +curl -X POST 'http://0.0.0.0:4000/chat/completions' \ +-H 'Content-Type: application/json' \ +-H 'Authorization: Bearer ' \ +-d '{ + "model": "gpt-4o", + "messages": [{"role": "user", "content": "Hello!"}] +}' +``` + +:::tip Already have pip installed? +You can skip the curl install and run `litellm --setup` directly after `pip install 'litellm[proxy]'`. +::: + +--- ## Pre-Requisites diff --git a/docs/my-website/img/mcp_zero_trust_gateway.png b/docs/my-website/img/mcp_zero_trust_gateway.png new file mode 100644 index 0000000000000000000000000000000000000000..3955cef0553247c7730aaef9f77dc24219c2a6c0 GIT binary patch literal 301348 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�BToAGtQ#N|bhJ77T>c%sic7oZ~B_~wty8C2DGbS3nrD_rjPl^SGk zd-E?I(zGOQ!I+Tb#1ohpY(kAgfE@+ZYxb<7j{8}Xo7(mzZR)53 zsYnN*Dv!}}>1wrV1s7FZv2Ks6(XDfR1yH*8H5CcJk~M_LzI0coeE?XC4nk&=MaX?) zGUOK{quH)qm2h-Rsc?-^`mQqq?@J=L)E)|lm&4vnOLNp~icE5kly`PGOZWlD604Ru zX{hW6Ke{q~=yXqdPKbOUCY*8Zbx10P@tn~C`hAzV>pHMUVG2cPrZ3L*BdEBK8Bf)( z=Y8GT-(FWV(Se6l=X6VYvcU?o{(>z?A(Qm8@03&%~>dN@WeUSOof8UoIC_aU+KruGJvPVLEy5faMhKAiHQ z0nl-R8;}Bh4sB;|HN{F9vxK5*17+NV}L8M6P`+S)shaLhMi0 zi2-1J#(`}2t_)jsoDpvM82FJKqdAf0OD#y z-sSpUee>%ymLjq~{rVexBwSXp&S@P;2Yh3T*?O#|SZeT;!LoAgR?%%+R5$noHML`b zDI-%5s8lsn5G%q_aG3;A>f?CAhMe#1P7HuhXuN%ntz+(-vxOS*AoA288jHqWkED1( zE?x3iOHi_e(R1r-53ziROB2E7Eq$M@G`qtq_L4x7VDZT0Cxnb*{LE06*XfG_hc@E~ z*wuQ)yJ@BciSJp1Zc}sH-#>36M94)*#q<#_Ped>pe5UgJ?Tb_~MNxremwRuC=bDYq zGD^Z4YpQC4Qv%snnpgpOc$tewkg1o0>zYXNR*Y&Yrkx^4<`~6@4|~JE1rYpbDm*Gc7Z* zR~}gs5#TwWe1S5EVt!gLk?cpu?#wTDAP{SmvI+n~_Nb)#rJNYzEX-+(S{|UQzxOSTi`V#%_byRr6b&%6z#3>*5 ziP`erGwKomuP;JI$1}_AiJK?$$acGN&8I1$QNb&Soo!ZZ6@N|s(7Z5aDmtt6KKckg zs2LFLKz>OxzJJ!yZD)*|TppIP-Qfhr{Dnt+ zb*=adJFVs)(+3aOkYc8l7fr)?s5UCr^G4}KpM*9Wy1|;d(3gKA?ytYWyvP6(4Hx%Y z$*djl!ofK_sH)FT^6{=P*gM$n-C;n*T_30BeS?#a1~zppcVA7$B+Ucpi?`+D_Lqm{ z`(wurmgB@ZLr}>J_k(?{1>KMALx3^^&EuUewU#W>87T>nG{G99n7n6 zGCxQ=Dwf(`D(g~G<2|#OH@To*bypjgUpB`Nb+2o8vIGX0Lom7uSjputLWC@iTx7Wu zUrt$>(BimdSV(@2 zO<-_eAAePKC^E{nZX)zwqRz~@G&Q+&3RY<-L*WmWip+{tUjz2p#k;NN0=Go@lzKW7 zN&7UTdgJW(7T`Ic(eUxDvVIEvX@rVe(4g%ED3k^E`Vm?2rFbMC-{@~(Btnf~1-Byn z|G*6SMv-t3s)gR|kA+qrlrXk9C#eG{Fvtb56yxFJ`~5o67lH+#KKQa5a9LUZ0?M*l z-wZ-E`?0xHXlx`VxeHEj=yRJuNXf$)2Pm(yvnI+>pCRlS7G zvp8n^M`KVo2C#Yd>%Qv&7q9i7sXIhJ2vRg0@TO(dsb_#6PI3LdyT54Cp~bSb&sU); z#JQe_3YY!;!F@YY6(GPen~7iuIR&x=zx&Zuk>7EC0&Y+IK|J8j_q(COIs^#Kw54nf zKOq7dD8z9;O&x{Yl=bGKP)QyXc$)C}Zm?q$-_UYIBL(rrK&+10Kq%vIU?7=72qObv z(dwRmbq0_=pGrYsBeC*84{%chpxmWb(XYY! zY3)@YyFU)lLj3|skn9B#a3(=L%K#{AO4!mc3yvY`W|?5ayYIL%9~%Ix^1b>Mplb02 zcmv+z03ixRtu>oEKEc0qZ$5U$(q*YoNuMtWXD=ci#f6HgFXm`NWpUq+jQNc?*HfW# zKoH(aehD-$y;^_{WX=2?ujtz?l>Y#iT3-d~=*zy$@r1SkysAY~fHDApW)lyZgFWj& zt+BrH(p97T`?);_4kc)u*$}~ovztOdpywa}Vld5$g^&-xMnL-=2SG!8_dFNkzoFZ_ z(uD|MX_Z>MK+=IiIRLb(PzVD=Asx3A@#cH=`FjwbZ=+pp{vP4!x6j`Ez3cw_+12L% z$JQW#hbtp>glCsBRTdKT^tnm{l}ejp!#CT6OC32rucP_((rvhd>DpMJ(FNNjtg zy;ZLLl&Mem*%yHkyAmn{epOug;h1Mx(g)SXh?;*rZbo|hbx zegiODB&_u9-(g67Bef?7fBp@x>D&LIe}Y1*YnQ)`fHud_3hRo?Ot+ERgkVxnCS}gTH zoBQuKdEQ1DBT!5^bCug_`(1BNhB;i}-|qit&bRCHwSQ+#ejj&fNz;Nbonno}h6`T0 z3y;3&|0fIn-QfD1k!pX22dS)dZf!62-E7?cr91vdJF7qL0M?s6zn>p%Rz*2{v z?SIjZwQ@!x=$1t^<@ND@(b2eR#@){^Un#cnubbhbioGN_`1l0d=qcn4AVf6Oix zcUyOwobt19K}Ysqysik`p}%rnCnj99jO4b4yv_KF*i4rJ-QC3US?|!$(`gJ{#qmF( z_ob7bHiFTncTY{-U>|2$`R4TH|3Vo03m7}tDVZ7Nb+*A;J2>88LauQYWe+gfcO7Z z%KvN5{Fx;F@3R>Ge=-CI*6{_6mW(ejDyP4={dwbF#jJb#g*R??WrMnB3$W6kBs{zr zOlFoJjQznVR4d8l)G`#R4tkI}L&RG4KUsEcd+#cI)A#-?Fm$o-w!xd#2grvo=iUNS z`%v89T;R7M%r5w(aId?bP$S>x(@F_H+~`n?*McWJzEiBF-KmIC0_OC&YP-6WLe;l6 zCVxynAl^=GgRcvaN5duifTdroxGy?`|9ih9xb)bLZG(3>WM`n#u6x^vzf9-*yi!P= zKjg>DOnQyFfoM+LLAD22@D$tmjiTy&xxFVh{&Bm-H|^yej_|}iU0`C*q1jV|#cpmB z``%#-E_>CI%H(kN2*2H5SV&&>N_qcp(9?emrBjrprssI<=Kxuo-=M$$_-g%I{X}{A zlVz`>lz#lx{eGExArWxX_d>rxl>h##fVYtdhsE(M{$@N%<%83=fV%{L=TBZy@Y7w& zDc8Upipk8(B_Nf>A+M_WlrlH1%Y3}-f$+8`!9T1O-v;4^U12uiGpw8I_-?VdufMfv z_8D666{y*s`?H2{f}RMafg1nYH$3q2SU{c zSOnHmzVYHUYKc_`YB)ko5baf{{OIrbqRn!FcMMzev7F`ugkzHa81~znot2Jo2c0*7 zCVh&+?(Y5bx1X=84R5#Fo3N}s3rz2a<@l_W)R&MC){r%Vj7j|S4+Gv#!EB-uT~}Vs z{Tn}3*x~^=L2>^;SVcs`TG4(Ir`L-O|2vo2s%mH*n`RKd zwc-7Jkbu$d!XJ()AK#(V6n94c-z*Q`f8BWhZ#qD!^P@?k_mY7*LhNv)Iu*s^FH+pm z@OT1nFKvCOG3s+f^hy$Bll)FK-~PVp9ztcce))2{_xNN%LBa6nxm1_8D2!*LvZ@ij3r{ALt8R~d*#$WT{yh1B zxA1kgW56*biYVW|^O%^~=F^a^`{#@J&iyRh+dX+rh)NF5b@%XSy9${IGe z#qK4is|1Ap?K<$Kl7F}l-?3}lqw?vaB~{m2fc5vo&RiAT(HL82{SR&f=74J${0CpE zBM?r~z-#->S@Ji}ZbE@5iN*Ndsqn)^!5N!-GBYzgG`ax;@4+^pZ5p89$R7Gms)Kx=FaAvw zhSi_{voPlS*eA4*0dM}xtbZV=|3<6+8%p~#N&HuP`GHOSH+=j5nM>jO^Dy4Aj>MYi zsBYnUBD^wlibh#YHs#K^9Cb9Uvm^&T*y47QG*_bF6gF4{L?!6kXlh#&>O>ekpX97? zl+!%*X)XO`vWp>z*m7w=h<=OOF5|m^`ytXV*&9%GABR!tl#5jalKgB=0;7lSX%#T$p^l{Ac0&Hl)t; zML_*4@xOV~9%LPSmIlV~_fPcs74#I{9rw`%v_gL$o>^vf7pJcXU1nTFqJ`0j^ulXI zhckQkq7xcyO(;&K4@1H<97seo4n0mBFG#K%G&zFddEFd&*5{lY(G{dv(&D-Wx=`KqKJ0B2S_oQ`n7;z@T{6G0k zrHT;%wl1*@bUa(f7Z7hDszwU_J4#@uJ)y*Ivp=6;;h$BP3$+Rh+-(dl$&;E(_bK2` z=JK9R7m$z6G*7m;`2$e0&aDr7ST&>uLMP zsEInfOiccK8fLa85fn-|>oj1d=;iTFJk~0I3YjyHBZ!gbZ?oRg)E(8z$UH97zrVN0 zneGIdCRE+vJ+?`*!|curmAyG;OZKl^uZHt%|gpCt4AN^EeiKkyY?r7trV*~fP_C{5}CRX$K0 z?T{yT#91}n&~Hz5zeNg=J74C7`2vidwf}iS-~Lzd zJ{_-x@Mlb|Khomy{$>vYWn^%zvQmQRJ8{?_-Tg@eb>)(MdZiUyXnSFD#gldX(-4=ct^q?a5_*?4S7M$npslP1wB}Cf5usz+y?r~7qy{g2uF$VJIeKso%`QXt{52E z#2yt0yaTKjwyVB=ROcG=yjU{|C=D2kGBC|+YeOAzABikyRczLo^#zG&ex1|P(`}87 zSHUFj2J`*k0a=`Rtkq#oiEo$h^qn0qeP0FD?m=BPu}_!iM;-Dcm!tGlDM6_ca3Qfm zFY$rnf^pm8Y}4L}zvV@4i7~!-!|SD#`AH2I|C}4=A2%4|6N=XUTt~#alo4i#w5v#o zWx@r)wS zx=5f&1{e)oq9Jh`r~w*5J*Z2%_FJOdveSw`1U)?czMkE4bgT9$wA9Z3L)VuFLcO;A zqm-sB$w<~v)5wCoZ*X54M@gm|s4-Gjg)%%p-6 zcH}|2o+Ybi=}lQm9?m%VqmbyOofa( zm9tR(NB;nRaIvm)ZR%nCJZk4-?`AWvyjPFBir~#yT2mA)-LWj|3v>O) zInNt&yl3U@ynbBMXRMAtGA1}Jmof^ix(N!^aI&zlczqZjw}xGh5PJa!vfDvaL1CdV zLAtoOm{Tax`NO+ukijz8*Y^lGA5;The8ujXUmzC{{<)x_G>+}&KDurN-PK+Tp3r_E z{n@M`PJvs8hliXH@3|jPSzunGi1nL5R5uwvc+lcS+pP9?N0@v>COGLMzdP=wV2wAM91d{`=`|Zyofl)xm7)ngJ;99-FW;o)~xicnO)W(7U6bu zjKM>%LX8gqK#TVfdXW9ey! z^|ElME;K}0sLOFyKYRA*Pmn1w46DfQgNXxyBl2ZfE!D*N2;!A6;FpfTDafLJo_C zLZMY4eKthIg?{o6Fb8^_U^H>?=jJjffa~k^d3o)By3?Ft`+X_!4`jEezYgd>R29B- z7Qy6%k-CSJ53Oj5G_JS>`$yFWDLkd`>3RGj(Z?%BJ;qKrR=Bt#e;`}}j++XJnhwYA zykgmN*bSV1G1Q@evT~;B=^^m`dR0@E@b2kys*J=Z#R&~aTL(Y8imL(5ayHfe(NQq6 z>jqDU}QsX5l|MAJNQ3J$10#uDCM?A_E4%9g$?q8af>N_eb7` zQP4}x@ViJdOa0NOOP8N6v(J>)=q6@87ZI?UM*TMaZ6BHxi zlpZBI$6h(;V|+*ddiu}B38A$+NgrizdU8PSJa3;dHZrn%`}VE%ENahNPv0{nq^Yu^ zVhDJ(A<~l7C{Oe{4uJ4fyWhWma|&gAdG=1*wV;YER{74A1_}#moRyUokibIpNzSsB z&-nD~eqNDrpjMr?w!c6n3CWzdB&t&~bI(7PiD=AnnC$zc)wlx0H|qg@e$|R0Qc_Z! ztl0_~b`&>}%C9Aj3AG=e*xm?b`-jKt`nq!CDSiI))@YN~Q+KV=JLZpaPda{&j>24Z zGg6~9HnVh({b4c^#LCrCGMKQbYTT}*^N7{u^_0t3=XJ`42 zJ4BTvNR@+mZ&mjmsDsjCVy}GI(#pdGA>2wTcdq*Q_;5bHVWn)by|Xg{0+|qdKw+`7 z2Yl)d*#{=baR`bR$ASbSc22n2?bk2O&#%2=i*%$&ZFt`EHv#Y6 z7yGpDl_B()3*V08+g*1FdhS{@?6O*L{NEnCOsoT1K{DrI)8OylZ+$+f#WD|r_uxsPadFwZ>&&rc?(Xj0 zu35eLzXu2TQs#EoXMDlM7X-AK%WM<7ciV_#Pun>Z3OIrZ)xlkERl6Rrm6eqpyRoJ( zA9Vr(YK@GH%s}1vWw@AtKp=LiLrB#-eOjV%fy*jf`>!z7t~h&IT3TuMak;|6!cBtt z7n^5Ixx~*_<`xzW@>`Z5BCaW zpbRJSs$XM{wW|IFq&&r0SuF}{&*+DM)t3u6`qKRcP4skhe@6KjUtB?{b@h#mEV@2j z==)T(DjR%I)6{7Hixs$4rJ)RPqu0=b;IP2r+h=UuP(imHy4i(AL@M7c)=eCiq=Ci< zCu7AzzfvLVCP`D4ygzQa$J#4D_N+L~_7D z(_n9J;(GnoxyFNyuEv9jV^Rol1`bq%)j=z@?U>B^`caBemWGCg!Lc#m*b_P&_xD#o zrM&0{wYC4|Nk0lQvi7No8Bx>|)c>mT(B<&b;ohfMj-lzT<#QWi+Jh zH{bBQkB(E4j+{+KQ>uaOo*Em)Ui> z0Phk`$yWq+hu1Dd!zsvnrep?X`UfhPn6H`IfYL3^Or0*bJz&sy@In{ff(Ne=Hqul3 zrd8g`LsQP!eKT+<+dN(!+;9d-nV z6Jd_sdvg!-a%Edfv|;v+Q1zJa2UlFxFPQKfhm!)2foWMK(AV!ue8!tRWPRTS@?#Js z44iQnSP4>}PVqlsA3&2$gAj-Y(TVwWw&sD${}(^{*QvBm8yI-`?p4P5mg|hX51AY7 za}HdWKhjo}Ii>wJku<$hoa`fTV|LSEtbHl15M==islK|kyqVascASN+`VnmP;*FMW z&Vg5XfuqUSQ?>aF{xVdOGBPsaryK=rl*dWq#1SjMvAJg_9*$|JbexZ2Y>{|yLXwKw zA)iJTNf8I;avadhi$-THmz9-$V9e;nVpE7apx{b7bbk!1O<6FM6fMZ)zHp|9hUgF6 z`xQ)5qgo!RBCN=l(jAW1oEg1+ebZjljslJ|K)dcCu5_Y#tKT%ERC@-MZV-0{82k~j zAVz-5s~DSFvc|8&x~by-s^xWy1F9uSxrQ;c<*#Y)Uw;|@`{Aeb6Emt8AJQ*nUU>fU z<6xy%fk*){z^;?MP@tgVbr#|5f#^1DD*!ub#KyiZQQpAY7@F{_Crj6cRX(3oh9=A0J(Xrj=L^%0h{<(trj*5*Zj$T`a`cmZ*$ zjKjpxR20PE5L@;^r4ICui%%Ip&E(P#%7Ot6F8}jq@k!&XMx;#l6A0$X_Y*~J$LvBw z%9x~`Lc3)HuU`D?^x`#byS~A}KbW)~Fxb1IFp_5|Z$2EQn_`i{FmUGBE*ywjp&tXW zC=oM-M$4Sg^Z)zvXy%afW&G@tk#~9xxZ9FF@4whxV`96VpyNX%!GDidR(W@Cyj=A^ z+VDjpU1T4b$cn}@E#Fm#_)RpV%awEicOluP&L^zoH~nxQ1q|E4Ep#-+b;La*EyOeq z{47PId5-kzxpQ=Ap3A9%h==B$@(L|~(FE4{)K7~Om-VN*L(lf1>&IX9O`lhQm9M2yZk-b;>d)w;B zjhLdLdof*yY)egF7Ge8ZUc!IkMjT+E{oRJG&E@GHH(*YmK6MwVHS~nD9pT4~KnH;F zkdV}Pcr?RxT!SKyB|d(B{A4g<5QiglfkfqvJ#w7__fA_jm?qPMR&K-GTwS*j`-k^8 z=d%;`;p6oI#*R@@Q3o;-`auitot&J?K!u+IpSeB<+!Jwl5HMI?QgR*X4ZEkMmE>CP z^jipd5eglS%MH4D>sG2IXBU_#TsvQ1HMX*HmH16|iYhJb-C3P*2NL3r8l9)>YeV`E zrm^hlabJpq2Lt7~YF9Q*nMKSWultX#)NkIG4caNP0wP-9mC<)kap3Y&Y~05Johz*X zQ=qT8xjEbnDeF1eOvy#qx|FGDtF5jc-Nf8>3E`%mtzS12FT0ci5@d_Z%KEBYangU* ztpnzu$dE$B?`*yrdh^R+KfVdLEz`V6u2|4#V&>lu}I z?@~#&yeYms5iY?fUAp#iz*d#VIwJNwRSBOzf1bS! z&2qs)V;a38tpq;aNy@J=H?%1UBY-B09@CTa>U8a}>l; z9&8((RUO~hD#Mj5Jnunvis9x0RmOJ!srA` zt#A24=?-&hM#gUhN~cu|P_ek4O5#hG{tK&L(p95dFWg|e_Y$sh;O{9`KQHfQY|_|l zY;toCy%@uayr`yrnyrGaVko`~hX}}MQrtVzkbJ!^vmy7)IrBuOJl~guCmB5B0PY}d zNMPiWeCoinAi)6~aQno~2ay?+P*Jh~ztPRc#%4eoj1E-~zny~7QL@&C@!1PmIUH9u zzP>+o4tV@(T2GiN>u&>LdqabvMu}!5ww4O&mZNu&F07H=*f@?~lz2ZtC-HW_Vg;5< zK^tkNK{GyF?T%~!^7Fxw5hwSC?PS#1DZzi$84I*`!59$gkEf)FSR`-POd){qe23f~ z%jwyGq|BW*Huo#I+qm1J<`s^8%bzcYfeK10i!W5bk~=n6r`_22tK@+xfvvK#Qrd6D zQsqc_Ek=$w>ecC!wPOWb=EObhg(5tlaTANSWVisN5bxfO@Q4Ams;M2AsBb>Khxxo; z>NsY23jhen*mSluEq8Ymx#xtP^-4?F|HvmFTify;xWGI{HSD}6eueEu!dNzU!AeJ$ z(^jZpOgXg|Kp5~64|@3|ndJ>Jmz*-@?9cws^jHA#dT&}q?U7(qkAZ50L{pBP(z-8H0V8#qLTE! ze&JJS3JA>It;MTglC*t7?=Ci&185rKUbigGwF=tGNy1ibt{&|f*J8ZT$*YtC+W&y3 zr*tr}JS{%el#@U3Lrb`*q~@!!Q4w~KS@(O1E7PT;8;?>>cjM+7H+_B9$~acXxptgv z(Y`OI9p6D|j}0u09lAan+mBWRvd0j(065 zsGv4lRj;0F8(t}Hc>={3PMY>k71n(6gH(mOhXIeLfD0D@327`V#+II4%eqxv( zr$+C9Ll($#XTHC{Fay=-wKcB~rXKvkh>D()6B6?5j8n)NN@n1lzT=QvTr5J^%eQiN zaw0=<#%5->SCkLHqC)WqxV<9!Hp|>6!2Ssg(Blcv^h~d_kw<}UE#>9F%=+j z3{==fCg0uZ!Nk(il6HDiL?c`J(=)C`Hs{mat*p|BF!_m@h3L!>uG^m9Rl-{~vk(y( z5gsqsdu~SuHTbPsBb_H6nuE!%nw$dZnl)gI&MO0pJY*qk!CII`^XnxUW2e-J5gly7 zx+y~RBp+fU3At6WzAKO-rtj@6f$n)yBD zm_FQe-w6;9Lv||bspJyQ5OpF~A;z~r3jiEQglB@8B(pWYo+bBLiUt6R-N7oa!<_`a z13<~OUfOl!v5t<8f(iGrzaYB`@!(U6^~Nju?PtJ%(d#Es&{E~EyMF@gH+{)lXK-oc zi74?#ObE!$Onwb-1ha^jf{ARjO&o(IW4cvkLi&^Khm}n$Q~v4BahEngILW?0Bh__D zYxpcL*E)9K=)##Eny;5YXv1ti)>|H8*OPi{n1YtNrUQ1+3fr~JEC!C0(37%OM?msqrXd@4^H&&pOsD7{gA7nnOAM^&&XwWF%Ql+`nk!NbUs{gPq*IUTmWW6?K)Qj5hrCMZf<}I0s z$N3Ca)N4~iLd^i?B4WMedbby9gd9yCR#Wk8DVUW#exajE^GPGGD&}tX%=IdylT)4t zOvN-R2JeF$@O5={?euy}zD+FwdeAH1pCjGnTU=oOz(zx%42q53(Kx(a)Ro84hy28l zk%$R0An!`>z#L|q;#p71CbV1SP)_c{`#dD9QQ2P&;Pc|_cPK9;ogY!1I-7-v7Thx1 zHs~$&p&K!7*QM?0k#^#uR(EVr7Hsi}^8KmSeinZ|jDJAUJ9ujMLZ*Wr{^PP#oCSBi zZGB5kap`?5$6%*F$($i9p{3D)6fBKa7^B}ttw-2LtSist@Nw|NyK@rK(9waXB1sML*!g`> z!Y`D$qurccwls&vmc_O6<$fd9<;XNrCM_MUshso!4|b7s%V#bdlGi>7ZlS*a)accF z=BcI@DN4?iO$MGq01PYxSKP~y74q5HyV$g=Cc4#aq*1Kwr9(z1+Bt)Mo?z))xJ8CE zw+UDrCpS$H`RKr4+0#qNkM@}<|ccQW$%$Q7o; zJcF;5kOqFX>tbd?2Z~RpBckmNQjRxZa4Q;v4mHR`>9+Qv#f2uZs*aL-Pi|TGtl-$AEH)(w*5<^%yg5*o@H{1|Z-LT%qcJ#j6FAMC7 zZRzFKLQe}GkV1}E5mqH@;ao>+(F!1opvfH!O!rE#w@SfP0CNMA5V(wR{`0J0m_e>f zQNxx%57vUw^71NA19tIb&^Tm+Kje|YRKn4G0=#71xhq)&tbzyz*Ma>~IX@EK7p|Tj zxG2~~9%qWdg8jrx$tORbxVUI@!id6h;Q%){IyWn;aJ;g5RDwC)O*kIH-RdbX!dxEy z@-TcAhV)U7XYZ`xiVFd_?>I796y`=@FFO5ia;yKDD=GAPV*YNWDpq%;FL~zM@x3c| zT^SqY6wYhy^5x0K4=Hkz*glvHIuh`sE2!UZ2P~deJocYSbiHVNy-F9gF9jPP+sVS9 z=qxKTGw)3BnKP}=wA%8vn@i<&-pjJ{b(oQ_sy&i7HiRQOaq-D{%RiK2IUEDNnWL;X z+$$4Qzja=9@oWh$S$6incO}=Ry59!0zvT5Pxh*EYgn`A?)mS|EBbIJ#c#^mKy6@N( z;6osf!I6vv1Lr3D(cFT9PEHU8QdnGE`C_Qf4~3iorfExLbRI?KGGI=hI^|Nom44zh z-R{Qm0rI#XjAKg%$o)6SJSHe~4jyuixg221FHs8(c6N3Ob6%WIiUI4b7r{#V7kPu# zPu>Ey#z3X50lOzk>gG+H>}tKO;(l)e+{)Rx5HqvBo4V@$AB zDZjv=tL`eBL`z2(hyxc}s>1biy66(}%}@a#oe@m%j>HE#&=KuC0qD|B2XDeI8l(>d z!h}Rbeg!F_b3GD{el_jgR8aK#^HNdxUCH*>(_9rXF%TTur%=SK>^m~3p{b!^tPxzq zd(!6jmv6F)riUB_zy>AKP#*9!447FCJ~kdMyYpjYecoT=P?=FvQ3)rbjac%8bEIvT zRjP%qt5Yw=*0RfZ3)IS4FFH7(v`*HA9NWn~L~RW5i-+H0MUC z#!SP!Ica}?2~>zOU=-y5M|NxB8=v&&7TH$q+>n%<#c!sq!rMLdxtv{Gw&uuRP29^; zi!A~pczdkacvLB`=WuCl?6CnU?aRnSp_UUFWIVzFWb28+J`i3&f_J zobP$->}<`&Fa8z?SGq5h%lVwvlxP$E_O2G#h;D2@)e>GyNc|;Pu+y5=Q8{fMyHDcf zE@~O4&DZmf%I(YY6c)Z-{YK~YshMx>9E%l4rcJFgrOuSB(ybRACDLO)8(m2gyvD=y zvrx%AvK8{O<1R_>MrBpMC!dh9@p>S*sdXZD3Y8t8W5PoZg(AZImkqig^lQP;7qi<( zE>mYSO=Twz0sKR%FD&f(c2*Lp{VH_iUgYEmR(0ea(K>0RVa2)8(D8bto=f_g%?H(P ziZ~_gr%$jbCZ;O_|XWtq%n)JYvFVy|p8+2uxl+Ni)y+2c0n7 zV!M$UTo@h)4EOdvv^_J$!Y%grYZ!H~bw9Tyu0CM%Akg51 zmcMBloy0*94J@h@+=#X6}y{z5zjai8eYRi2HN@fF2T=h@;UrGI2i|^@u2nc7<@VKw#~VCQJBIO zAWYfTXVvz|)DvKQ@CzV#h%pkBDr4Ffs)e$ulfG2;3Y8}77f4Am(3Q6%!&ZZXgGIQ{ zrh%aG3;qdWZ}!n1u0mPH>s#XuK?p?|qTW^mSd%p=R7Q6jMg9TE{LcXEzz_knZr;v= zQh$Z1(-59rT+^WiOaTzlkYwV~66hnV+{R?;maA~rU;yu4&pIH-a$AQS`q1~V#CGdb z&t@rwchWpN3*LYd8;b2h?XQdrgaP;8Az;W%LfC_w!E7}I4KUBbf`WBTg!X{08YVLR z%=T>^p#yr9P7cR!zu=9e#8ShrVy`(Tzxb~|3R(@CAav0y9(++0g<$lWb!hJE!N@JM z`zCNsOo05NE`fp~+EG?k_MVKw;lQJnz$HB7J`7IdKXqr2q z$&6tFeJ6Og;6q7Fd1#_1q>xBM3b2fuwpC0@m2f=H8vOrlD;MgvMV*; z+Ih!pdk+U22SO@G0eo+(D-`K9Kk7A>-NPx9%SYe(<0*Yhc{WLO5zp$ECy}9yhbnlL zaj4@WJU(vS_yP(UN+Kc{tb6|!o1mCwz9i_#$<7XtrxcDw|8|q6>Z$N-D#;2f{dJAZ zmHqd!@T0&kiNTSH>4z83#FFkpMqb$&6}nnK2`85VV(uayauDs{Zub18HOn;*2CyM%e-y)bT7aEBtI3`e2@T)7nQ{#swS(iepWY!V77OEo zs@VYcy+py7&oKu8aLrShIj0@--JOqz+isni`7ol^{tKFs$m+}3a&JHyqMW$EDytmy zvNEo%SsPQ{{j|uJLQIz7@9|YLo@1Q`4`2VqmDMdIZXadp(`i{K@VV?q)(?H0@!L42 zRP39<;rg$8(k!dhJI}h(lk_caJYcdk6K@x~CsdS^KZ~|aTXo(EIMzd6gcauBG^>$~ z_v#kB;Ut}1;Aq%9ag*=?(_rnREa7`wBfXSg8?7~6R~<9>jD@`Fg* z*$Zt9j@Np97OfwTRW z?`OK(UkD5H{;2aoI>2IuJiS*vlsiwI|6EybfQ!jLM|1gu;7>dBg3Q)|9cwwC_6_YV_*g{fv2jlXWUl|)MRMI1y>1OiGKhH(e8hlvUB@1DKV=pAkEG$A>R5j;JXN>fts1jtdc0_)f6u{u9eO{(ih zJz2nxz4FblZDXrnmt>i#%)P{y)~2jK^t^3bo5?1#5mkB!z}}xVapQ$})355o5j*w7 z@u0(DJ!B_yMxu=M(Qnw{TMQBmQ(QqUra2j}$#;^QBsF9~0kki_n+A+)TV7NAq?3?k z{x|oC{~eE5RJv)dUKJN~RWH!KcMh^(d2iyu$ScOwK7))4%OIsA*N|26)k)nwB`^VW>C-~z9Q41f6r(f#Mw2M02T76oo+QV5PrwEFRfya03U z%~CVg*9X0xlq@iPt(Z7kp4jmLs7rR0pr~l|=g&eP6hj&j1dE9cA2P5ul5PoZ3H!9P zG(cOuL|9qrM#ts0fs8XiA;F#jG&wtY?D+UNn41tXT-!6H^PF#zllf8%3X%mYibuqf z0235f=?u0fH6C9}fD7%IG+2o2$Tn@tHXan{B7We6Q^58MNk~6#Iwl?$fo^$Y{ig(G z_n=pu>lYz-LK~eMA5X`|&R)MF^*iCkVrQAY><_>_P;ds^X>tx*BbYLFgMg*AypzRP zwg*yS^IhW8MQ0f4{r@nb%s?Df*aihO`r{UkgK!a1-|jFWYBr>f`XNbpv2KIxBiKE&95> z<4-K?APXavD{4{o6EHnp$<1dPx;pDAp!4$2kff@9B#T(Uf8cMI0FYP{zkjfaA)!(5 zIbj7~kPqG0-lr`&_`|}z!45pskSE|lR0SUf!ib+l5uIQ;>jLVK!k{ky_W7~ct#uP` zQK>m}0)>6_OJ1K{JF$c5SNFLj19g&4xg%c9r(A>dCerU;%)M~f88~KN-L+6O|8QPiaj^@)3l(59CM+bxN{}RD+JLk^O#<@n zHJ^RYQA5DLE*FJQoo&RBhbHv&^z;qlAuvYX52k0oCHAKZ9GfbzM{0_vhfkikR1G#v zQI2I>R~wxSdZh}b1@-FE0fit1V7G795BDETf~jNQvqtpUh$A4I8N*=i$o+vlcv^D1 zCkX3A6$Ao*>Scb#z0Q2EA9mOhD~039(~6D~X)9?Z!VMvs^FgJiE>@4`8?|aOiQlIv)-W6E(hrZvzSiN)5B}!M*X_ zwpNb8!oD(c81ODI+X``JfY)j^k>{{lg>x$hBNb`yPa$Z<+s|wl7zVnnq6ybwgO$$5 zdjm61uJz>{9*s>LT5Yhr%NO~kAc1(eW9kzgi1BX&f~SBs5LvQHd{l&1ZOA=JDWE^a zN?$2@W;w-~^yOD0g0uwa?+PnU4`6gN-c<^MO^3LqWv{VVc>A)FE3~a3gyeo)44VMR z4g6gHP@`=-U5HNCyZQQoggFB27>zM0Hn#&?V1@WG5H%A_?*?>LAMVMxFW)pcrkPPy zu)Wg*U?Wh~w(R7c16RqMQq}>ky=mVJvAF${J)!T9GLuDVQEK{l;|NoZ7j`QuK;V>7%2=<3J#(@^Oj0RHr6n{)dTwYf$r-nRSW?ITNJJ>^3o z802!#oAE)`i{L)Nca6YG*7@HmD@ZaI6#ovkeWz{nY+N>dUnvbVltdn64|Szx$t&71 zSe(^s%u$Q3L0`#zii z_3NGuM#)YrFph9v!`Oi9$$AtH4(Q|cCP;`uxq4zn?LbXUEns=G`Pm5tkQh({z+Z9HD@xaLu%x6<@3?Alrvj2| zgnXm>Dk7%KsOb6vHb*HDV1R$%O)+&U0vdsn;VXqP-R$Q6DDD%tw#K2}OieuiHn$y2r-YNv4C>() z0wt)U<~bL3_aYVqderbipeYHOe!&k@lr@cgTeJ#dd&2uQq%mC zwRhTm7u-0uM78<%|IPXZTyf2+mcrNXU#ai8C4PX3@Z`-pKM_qODG6=m@y(IY3cWi! z^5*Msy1}Zt34|`AvS67e zZ4V3PV*h6fGfGyWE!}Eh;!nm%E(Rv#QS1S5NP(V`buT@-h4&8ziS(*-QTsh}rbjO` z0O%V^;PKxu%S`qJfVaW|oUDa`5nIlR?gChT4|zB;;5!U>Rrq*?3*#W7 zKBTcl3Xog|zFAhdiBqyJ;sZl+OYadil2+DDl_}mRc!BSmfw>lU6T-x;bV5LzGb58e z!t#ag%qPUciQ5yf0T1WwkcTq8P5<4@{O?D;&TwAF3y_58mL$KHyW@%sgz8v%UT&%r z>%qv2>i4d(b{^Q}jqs&Ex4;J=QQN$p;d*= za!eRPU|*BXOo#~u?toUzOz_o7_p$0L>K<%M53XR5#VPRm3^ zi=_ejn}2g?i5<@t`vO{g`y0bYkXlMjzd&>6)S^M=aio{gaXnDn)`VM?$>*7KtvII= zY8EOZWpd{^b5Bu4;w=f#748MtQt{#9{#E%|)m0;84^w*PR>t{a4DRpsf73l317*&pc*!uCLn>BE^*G}0;kR;B zN8DX7_eMba^_qH*+O(Fls(x<0jK(_`i81!>IoH!o-6`-ES!8?HW=Ij4c?%mVcZv0~ zT!06Ali19l%0FBk+S)v>3T0wn*J$3_e2<>s&^5JKwF}z$skpbOdyVuGL(pO?mVA)B zUVM?%jnjj7>{yT6xmyNyP77UYD#@|kR~BJ>q4C3$=M#s0@T(}uAH|*0guM+gJ-O5y zem|THrw=?|9#h_~71=J7(HOYB-*W-_3#k|~4hHG;?ZeD9t2-yb;*dD!4xeF@ww7t+ zgQ^sMfiXd{9xWRVE7KbG6g!{!%2J!}D9ePnc=2LFpibm88Sm416OU@y(rZR)(onuS zUROMd#`rCdygheWlbBAdZzm5I$47^NHhCNM;hrc&5pb?fE4vJrwX(9Yx$-?Y-&7(m z#lW4mAG)8tqN_j@r;&P$-2KiEFA1gE&IZxpI5MpkmSX)l1f&at6+QRk8O-qkrXggW zy?k4WT2ElRR?7qC&1b{kDS7u{2;G8rCU5R|Wp64rP~-X=7VDa@|kbV&uVWT6pq z1_0||-*h|LNAYk$7c}Vz&WH>_DVN!x2~s-7r+a~$$+kBjIw)m4YX7!e|HG13;R9lf z+cPP!;Ng^2KsVK2HQ~tWHlXAR*)|E8BaoxeoY>@pATh71#{-=QoYC~}y>*pMRRcSo zx4m}ZmVro`0b!1A)0S4#EJ1-ZjM+cfTIlb*%r4(mu>1u8^@`nqoth_qi`R%Ie+Wob z^8>*4mZN2bvm?pfWWOYhlSlL1z^@nVbWyJw?V9q`W{7YEkzra}_(%ZAgI z;cq`L^o8b?mX^A5RnNJTs=s&=pSMn{433R26gCEJq2Nb^!sFwr8c(yf>ciQeiexdE z@4=5dZ1W3j{Z&UJiaxTMTuN|~&>0XP7Xj73a<@&BOm zA`IS(Uyw2`!0(c0Ub0LBj83}s4Iq5UIcR6;Qf0$P5gI*`;DxpF3y_`dXTI4-UTAS9 zzkO>rcK0wJh%(4WL!8{AV%k81i+HVg@J(^6c10fsgLztvCH15O=0M0F#F7bk&B$Wh z#{2k>p8;zb;|^M6EQcSM#1zN@s78i{{)&1N*oG%gP8--k6bw0PJ(IoSbL*}@9e>a& z8KFn)?ctFa^sj{AE#6g8R@s)_^NrUmhx$hz?$rT6x&2j68FR=f6-yT8&QPd!2;Kj**37?+c4ZgVc_ z%vrt6Qpit!){M+Bw@8hg)0)p?7NjEePKZP++ff_mKR*P#JFwftNa~6e6kYR~sck%7}PF$6dBN7phB3SuK_i)uA!a zTZ`a>elDDp>u(r*3YE*C^4AagSwTT-m5^K7t+gyUJefA2M-zEQV}9mc%OmAFLH0Wj zA&cR|BYLaYMu|x72phUF`Y{J9t-$BXsk;0eyb)fHv%Pd^89Pl%5U2LG8W_@F6(|;p z#ws%nL^(Ojr?9#+)n7=@HXKQ4F_Q%7&ai2VJjQ!vxUFA|(+Pr*v~+et)+G+`Wqo1h zfMKNuO;ZC)xNVee%f~GY3}#$YbtigL6%!S5r2FN6ZJjHKs|+q0(W`8#`d$8BP>B~_ zrDNoHCX@~3FJrJPpmh51Z2ya+|CH^C-NF74ub2BT9OtIs`Etiz4SkQzx7i94Cdavz z^c5C}fNYUs%ZDoK+_ED99WYs(@6QpEMR8C@KhL+-&9LbO;Y+pm0dA=*`|`d0EvR6$ z@&EvAHA>MH zy02%2qDlah!#{qc9Y8rK;m;V=Lj$$x*W+#lL|!)6a!~7F!ONA{yA8RIc2uJ2_9_n- zkVgfm{!%8#3}ts6r#dplVYIqLzm)*#+U-keoF#aN_}mBlr;W|uQe?{D0EtO5W77$2 zh`^mmBK=mkXRHh#vBvsk=Z|fF>{vbMUfn&Ao!E;fBQZcnRX_HiVA-3VOb-II9Zt(K z$KEV`Tt2<9ZYr?%1Y zwRT<1q@i|&KhKn>(xW%^dXyJ~27JLHd~*&EaUBM3_`tS{>=?tsK}EMY#vdPW!HB4% z-%aii#Pxd9UpQ=tlonpxw3@pGJyKwVlrkJyy;vopATtc}5C2?DpLbk2q zMhEXsj|zQ&-itPIt4$D5w}KPM=c(j0#L4Z=CN&-a;tFO1+P0~^{0YO>P_k}`y{Md} z`cP+s40t+3x7~@WExavFvu1I@!ris&98Laa`?ZnYcDH;|9rZ=Oy1UJkAL3L`(T*Q@`!aN zKj7XrUPn^U#$948u{wkyMbU#H`*|T7K8s!j52386i2ytY8_EMCPVG34R>kBhoR<0% z34YLk%vXTIe;;gXo7IKJyvEMTp8z79nw4P+y<0I-8acUKI-d$yEA(sru{{zLVHNz$ zAqK5{|7oD|zWJ;<MlWy)k}PpT7o+?7aY`l3!^$ z4pvlzx;v+vUn6HD(^KkChC?aq2%h|T8G~n4 zkZP5>PtmvM@s?j{vZ$5;SA;L6J&VdiUcJ^S-@8PnYNrnD^_%#o*uO~$)ZFn#Np=E8 z%H3skY%s75Awbp~sHh$DMLfYTYp`XcZe6^|5FTs_>J=Nd2Q4@$GOO;= zik6Qy*Y;ep*R=riW$_R;)7+b_F2W^~;87gdwDO|u9fR?Oc$CLw{hqK92|e5s_?fPP z0plse6w4xi!7BEUhIlaSfZVPfF(;bM82bBu3y8q<_J|HlD6^>6AR+NRwe!Kmt*tAo zFXTXqWG8`c=Gh8@=Ua5+O2J1kMUj_~T@MvmZ&nm(V$5myAr(zMt3Ha}V+-8s1>PL2 z->z2Z1~zr8y0V8kmfZ#@nLH>z*7IXB_gyfs7H2dRd)y$+#8swo@A=()SeizDRMWQkiW1!8@#$#Xc-4$m>!AG5L#;nW zW!+zWaRCbfAv%<->!zbTt>@3agBo1=leo>^U(&0hI&H7^?U+ejt4Kg*TWz;r^Xr+7 ze&o>>I_$t(NP)~qDWgGT88#Pbs^PfyI@IA-US69yRFX_Dxxr`UxdMKzwLo!mm?5sp zb@R~%`3&9g&Y)WHaG}1F&kzX8b09(dvfdj^0+;t9(jvlkEDe{6LB2R?+@WdjL(>92G1whi|HbAj6<|TV00fWuNE-8mACyZtY4B6nXLum^z*~KAZ^p5|-SrV##zWLo9rtC*ty! zJN2Xg$KIRAL*2LS;290el;i;iHH-Cmh@|@y%}U0Qa|S(a(OhaBu+gv z#EYL8y?Kh#PO@Bmrs4H-w<`=1MRII$ZhnD_-2F5G>PPGh@!Y`!FEx*!IuCJ1!~jnc zKAf!F{&bsaH+Y6Iy@~3LW ztqydM#$`_099j6JR)ExkBAR#I7kB(Bk}Y)B<(EeK3|zVfL9Uek2R8k{Ltdc*gG8Kf zkil<%y6(nm=OgzoDQmJaZT+WUPUy&a{1aNv3p1W)w7lCT9~5~s`?;8I?tc7zW=~;% z4VU$_JqZ({>&5GS%9b_egV3=f;lkW;N#RKYMaK&>_I5_)k1*|HkpIKK=-M3z89Ek9 zYn6O%5!1VCQOWn6E-@9V+`gd5UOF8cr!>qi+jz@U%;fXl8IVN# zc8Uky5wb}pzuBH4FuE*n5#+U^S)y`+)7d3_R;`^y~`BeiZ zqzbc#-Te#qJK^Uti`qk9KXE(#R8kj}*~1;TOSJfH&AuPX1yBXGMipJCESj~8o>0M0BrfSs&Q)*RzU0VjqjSg2YM|sv zEqR(S-3%qH7G0y1+VO4sMVIC{-FgRz8J9O+vcf^#zWMz0cJlaEqow=tbwK)jAvJY( z6*ZybI$S}jf_?9;i1e<|viAG~x{m}3lb{w(O$te$KH+AbU9Hu18E+3AkHPDv0*ZRi|zHRh4 z?V8%MQMws%KZc>LCS*mmvCy00#+6qp4BNj}YQM6$?u3RGckT!QvV>*3*V|Dq`OynS zcTPsQOmtF8a&onB<@Nl1QEHki2BPCm+hvv#1TuXyb7qEr$qfWq$;E{}y#4_1eAFdT z@SmLPdQktEnVFgAc~bI1@2F+kjnYKh?r&1FQsvmc^!%Il=mAi>YXi1cvZMmf9ZI)eH!fWY!Ck}e9$j@Do0!N) z(rC`73eUmd&N((n?5XF=6Gx5|eBCNg@nc@vbCIW*HMTitwJB$54x|IJGBS9Hv)9^E zCaj^i0PBfvaPmU z5*zoDm+k?f5wGm|ZxSTQOXIR#%TJ58wsqy3d-ugt$Ksa_aCZ9o`YnSKTw{jmo$Udl zO$|t62l`@N3EpH%iZ=o-oH-60C^)Pfx-^GfjiP;nwvA}7OWyh>5pg}!-qW6F2D&4N7aN1?txH2KLUP3wCxtcEG9d-twhUw=x;&l{r8=8{^YC zC0&=;PRF({O0b5QtOqv}T<$~Rv%hL_Mnno|dr;=d1Zt0O^Gaoz8%O3eX#11{Rjrb+ zF3)cAx(gC`E^1VJUjvTI`KXN{m%OO$t zms?P7db-2un~#Ttk{&lYbDgmNq^cf#DoRnc!uEtJQTHGtNsuY^^1+IcG5YEgdpc7D z19NK+9=+JGcP}q4RuUhScda$+*5u`iDuDfrSmn`QwWi3VZt&nlDtpwIp`4+t{-T=u z{cSZjGC0e06Ygf8Dah~En!e^BUnOs$0=iLiz0le@!9Z5VC*b9IA8a_??vpe;`>m=r zcTe=e6Qg)<&DpyQKGBx7;uBn!n)?GLkbuU1zC!A$O?NZ4zm-ibx+8k=KX>iz zIm)xaS%1^pNgNV=)|?`3xBi(n88b`hW*^A&YOF@5G{G{XY|$}rn!unj5srrCF5N`FH&dNlZkdx z^3hM0tGapBZelTZ+dhSBa5F8>ToV|m(8VnfxjkUH?f4#*%*N{8zPVg~^>vWrgpGn9eVjg^6ZG}>XO)@vwsv)1*BCDdwp6AVRB##bI|CB zwC;R2>$DALEOS$YgY0aJoUZvhaBz!LeG@sra_=EBQ7>=?IWpcnkTh!uw z^-jm^TM!DL|FkC|7tq9sU%wU{0>GZ@T3b()K(02G;B9qEx5y@joYiBG?K484IAMxG%^u2Ti>p_!^2B#J$i8~{ zap0^LP(A@;B~+est;iZ-{9bMgEcpGgX1w~Pp`_WAy#gT?L2Fqdp^mGGq<^lKb*tsj#h*~ zS|Hx$SoU7~2Bps9rxo^T3l!GB4bavyw8l8(XLMfLCt&z%fF1-vKUFh!e6|$l3R~eh z*mz{qEnYSyIwq#;ttsy@^kyk`PWe`2dGKf)&MhzPOv}_eWIOTr72Lt^in1q9pC_Mg zKOeY~>A81t~3J?UV17st0_npp-6rWx7Uap6XySx(eX8a_XpjQ|;b z2T}@@m$mHB*g81BUSaOZ*sMt|0kxl=^JIhOB*CqH8bDUqAy1arl-R41xc$VaLJfZ+ z_r<0APO&Bsb;KVo48){qGO#x3v^?V4rh7sVze(-PKN#Kh$2AMP^*3Gnzt-Th)x@~i z@@ZgOkaLzE<#;ZBi0Bk)H(@Pn(N*@%{P^=hr);~}T%by=S%u;U^SvLh?R%_fbFNP_ zlmC^qYNpQj*sW8u_^BInestApskxcJH;Q5fgA#CJUr-msCK1hVo&*IUp`Q~cPS}Wk zBdH>>MDUtshr9<$+dDg#H(^As|1WY(+BW~OS?~wUC!g%;u_f*ID$P#nC$8lh1|7K- zslpSOUb6S41+@Q|o*&*9vgf+#h16?%bl5RJ>OpJN6?mOSp&xH;##B24IpsHR`{PN{ zdC~NO?x?y07{5=K{gjN1;^{DgeZOyi0+DLq82E#3>QY`U$mB-~Cwd=K>*&;! zI{!wD;EjKLGuzEuws@<9CbqG}?>jC)cvtVkEg|4qlZWq0*TT zB_7^`1Ky+DarmMmJH~HJ9%*p@=H+Lp;IJ8{GX7r74rp2hj}#ASYimausHYl-+`C5y zq;Ob+qrcZrg%4b{y2@(<#yBtO_aBaF`vatxK@vm*IDE;5K@EeQ z1cLp>jT>R>ZvXSz@SZjSrl3sf77Jz;7Cq1}hOJ@4U?Q&l_6WiDT>@EWk?b(VL;FIM zywUerI{o|g6y)0zcLxR0SGBc8#|xi5+l5-2A@f3SfBqkq5FVOIFZcIvSbZAg;_@`0 zXRxZbr^gz!sa>JFHeNvYeKqtq8$;9c|N5xi@IC%i0n^j70zGT^{-{$u9a^$C!ejjN z5d)e64xgn@9AHO53M?w9HRU2HH~zFCc8s8VI0$F^!;!ymG;|2N6e z-}aB8Gv;?+>3>-(j^7Hwqko6twfL<_!}{MPB>dBf_`eVQza?EiBLDe6|95Eq;dX<~ z`oBZ-pXcTOkCx{5kr5`E1m5)>M3Q#r!Hvk!Vf^%2|G~1(%mjlPTThn7mzQTczki1T zB0oC+H!trza*vj751*p3DcO zm+q_GK)mi~Z~yKLeNivJnOGRT615eE36ep-n*y@_ahIzPf$L`k$M)>v#f$&hD44JV z3A=!Z_A^;f7+NX23LN0~&==hNaM9)G2gX-`5++_Dx+Eh32@ruy4)7e&DUwGQi&O@tg?_BCr<^V?vJ>UXl;AP0AxGuD`7`tl_ zDh+nWJ>vb%M#-H+YUR48M$WOnxyhcCG}7*Z(Bxs%4~dJHC2SOY^5lsZK*)3Q!&m1= zzBKDOXOjcHzc`l_Er`DS(#~xWHkL{ZtPYGx21>tieWtwT_3JT(@#Y-njsb=#ne@NgStN7q2jg@(V)f{04MY{_~631%iH_`{jD5xZ1)pB^&nS zn}-2Q>xi$mU_B@lc~h!ZrsmzXv?5qJG84pguE5ykwhMIZVbY7=GhCJp+KBr6WP&eN z;|;YByW+MP6JY1y;9$_B{5#R1^^fN@{@LVxPZqTOrnNN;lJFb*Q4PW;!FY*b0#O~OK!OMwh_ ztda~3QB~^k-g7`u>VgyStjB7NC_@(C=qE3D_Uzg0Ny;Uz|6Cu;<;(I1@2IM(I&wv} zoe>rF$elrTbjWRDPHi#@Hhlef$qWs7mqBUH;^#`s-0as0T@zuqwV zajn>umOab+J}=m_l!v3K3xI@g?zLEME(PRV^wrgC*W7QmWTAG!Pxhnh{5<0_&>r$U z_n!JrBZBIMsMFML*eGv9L&GUr)?1ocA8>pG?19~FgnE-`?{1k;J@;W8PBO$lIH#cz zrUA0q#p~rX>*ZdxHCo!j^$eVn`)K0BRU%Z%Xw39}F=p%A#rikX>#((XF)KnWh3xH zv-I&+?hua2$O0v#Pz^EfH9LC6_@kO5tk4zcSWX@jxMWtYb3%|UXXZ;Rg+t>m1A)QA z`Z%zM$3O*J^l-x;(i6}Qc~ljjcE|Ooxbx^!u(w?{!u_)>th_!5{O_o=1T92ED-fiP&-z&w-s)}{K2{= zuC`>Omg@3XzclULHX1EvWH}$VBW@@4l=9Iz+J3s~FZI5E<68caj%2P*P}SC48<1oT zahalhVn=M&(K*(Gq$pm18Dq(d&>z%FNnst>5QB87X|>a8&LDRD>eP)M;Q4J6i>l}G zekJr&zKHn%j9_c<2>jH4WEBTg?TZb^XBV zuz+tD5#bYlU1~J!7lGAUfnYsWpHAW!=x{50cUH~RZv8X~UUqE_xLs6{_)HAb&c8eO zd|lqNVSmoHdYxXC_7m5ReVt7j3m9K6QuaRFk#)<#p|$7MQ4Th?_c1)A{paTUWQ-sM z)rMp;TIPhA(#_~>A#D>MHgfnY8CEl^%gu^=f3hXmKjjCnDSsKv+GXW(o{? zki0LA3s9ssj$v6xea6TaDvi#wy(!?Y@_Pj~fsyu(<4Ver-NF=KH&8gkh2h;4K0tF&L0R@yP0d^X zx~xnPZg{Q=Bu?~vB}EPJLpvwoY^n$iAG~ zsr4Fic){{jn9;E=URwYclGtC5lYOSi zUer>Y_f+IEjgD^5K5xp$yNdsxt*)_ITd^`&nU&&)va=s{SJ}an1Hfty`?W9V<2w)u zhe`kxCL3iy3L?w{+i8tPmVqUnFl;N%B%EkhdTEvfBCW`~#oRhtbZuEI<)Eau{>gq9 z5WeT$p56wH)>*)2H+vEz)qm;53?*O!?KVM-Y0`~l&G1Y_+=|+Qr*YA&K=AJ6H3jU$ z6e~;1*$dMhY%j+HSPf_J8`fA#eb$z*^!O7FcCbdBy8d&bRxBj*OS|i`_MJ=JiyOI@ z{9pxtbk2XV_Yt9#r}~iF<8MxZ$c7O}$<9%tu&bu))^RH1cw79H4H&=KHe$9vZUCv7 z#7{J$M#p(_1yLFeQSk)Z=(WLbzvXYNq8a^Ks#t&pwA^icc~b5$!}pl#y+yQ< zO_<`hi;J!TopI{WVRfivX!GFw*2b_Wf7Gke?|ZqhV(L+?bjh|L9C3&}r4-H6L)*P2Xq2snF&x!f9|Hz^T_6_;xyh9~{aQd|Qm=OjO{~CXU7?Ryu2-TrZ|~@E-)Z8JD-;mKyJt_6Nz&=X z)Ig?74}m;mq;oZN>?4s?(0jpa%t?nn6uc0=GL3NV0aUgj#$_uE@e%8o&VZ&fvUWhNJ02P6Lw3oD=CumBk4wC^&fBOIP8bu4Qdbt+vpof$jt4YMyv z;#e}cWRp>xb1l&!8ZlaFHf9iOAdLx{(-fj?86l-Vnr{e3P)qR8ze8HRN%DSyRN+^V z*IwTR?O=i4eh|XIE&|g1jdtjDRZTe7KUANdjw70PnFSLZ<`bs2rZjUE?qGFB{Iwkv z?9eeHmCEFkC|R-%lrEf)*`-S~ZcjI^+jy7g$7>jiU;F9azrxTl z{DHCa>eR!yt5Qa z=x*ZV3Ou>e4d)g`@?w2HZ3fYL-D5YNzl@h(rX2rS+*3)hqr8V5@l%cG$HFDWM(!7F zvKTtF07{z_NkFEVQ>o|9iyym`9t;7a$FVs#YuJwA#_+?Yy(M=@E$Nko^9C49;KSF` zka4B?xW!EK^^jx2$G&dpcI@XJ+J(ukSfnk1e!xkPaG##1m9Mdgo74vjyUz{DoXf=M zJo|6qKKMFQ{jue8q$&}&h}K|(_lqEUlk!fl@U1HkR5RQmeQZ8LOa?pW8*e!|?VR-a zMuQ1yykq#*S}b=mN)O!Y>RXS|nKL<60HW%7RrUj!Q`gRYND zHm3Rrhoq~`Uk8vMi}X^m-TL~AZ1q8a#X3gD+oMv!L<%M*6@Dg^&cpo;J`Gf)Y&X#_ zlqujJYNi*?_fj3nZE&VDLd#cDW$zjDwF(8262TxuHLQGTyY`WxO5O<{1935ElRS?F9=Ql_z`MSB5@C z417bRYlW}|FKCSK_@Ux+yRA~ZAe3Aa0_zyb*LK|nZ{o<=y17XQBwgR3(KjxJQ(iBL1?BN0LZE?n3WG5)jHi4yw<du_>gpC6H+iqS?0?+9JaZf;S~ zt(WOTdq$gtqjDUz?$MQ8{qvdKOgH`Y(A5m#EPh!V2SCnYqQKvLXc~lmfz&reax?GB;7=5zs7qd`P1F2qMUG$GQGpPj9*Qp zdOlRwvj!)7`P|+T%H8a71+UW!-6g(nsBU~w-L@(dGktqkLO9{{?t~XK5=6EFn5do% zVDiSE#5g>z59QSVb2a=DXF*dc-OwU(00eR-MPOjsRHmDiLGG>d(9vKDcgGq{+8lRx zl(3RnXjO3O-nd<=mB>F*iA%-KhS;~~x%6(r7&{!P_%-m5drHK%E^r&ki;vR=L`tsW z>Z%q}1@>Z$Z|j%4+Cty+Ak^o$h+4E@A_h}k$V;r9TrGhiWRa5w5^f^)3Z80Hk0e@6Fqo3l6soYo zij2temdL_+;d5pf2Nw&%8?{)8LLY$$tY`dgf7(j*@M$>XT0|y{K@!lL_WgDA9lR&4 zjWSsyht<1EO4&}r*p~G&{A%vw6LdH3EXwW$UUVU=Dgs|2} z$Qp)*cO6`+&O6;J(C~O2eG|B?{2&G7+yz$}h(OBY1zWhi-baEYMFzp8AAWxr1ce>x zFxmVN@xLW}l%g&T4wHRp^~S`G&NQ^S?VP^nLwy+Q1{Ex9r7~ zC_+}v_vbTIr#9bUjY*9YQ=YoZ zQM%P*$}g@wVT2_k_x7h}dUpL4r65R~7N>6>4UD8xFc)A0rdwc`G?Hu5rcPqlid`Og z<*-lM%^R(a>ojK-_v;E%_7U#4o6$=K8sKWG%mQ#y;QuHoppycfPoOuP9I z-7cD&n_n++xEUj4qC|IB4ARoIY%ao;KfgK#!=~N+ark)8-Jzdz1_qJU!L9@17|cw3 zp+l+vO+`t2_4i7W#dcvA8bV!L`e?oTF@8Z&EqUSu;KN~l*w;I7 zlWF0!Nw>RP`E|LfAUZaye`S1u_n`H#v-}phYQI*w=OP5^)?2C}<%BwtUc+GwuMQ(;h5wl1T&?{0$ewmU22w$yt!ZbXcBQG3eILphV@gCn$ID`2_A8lBLuytrc9E3hTe`r$J5l z93!KRr!^NNTYMP5svMJXv)lyFhnJKx0j6uA%{>=JoQiUb8UZ{5`x&dN(gGm!fWfc| z5X@y@j)^JsQMfcxu5E2?B)>%YR`xbZe7sznSHm|S{Ac%?$GeX;L1!^#gJAo=@HT^U z&?_eZ;Rq1;`AG8fAa}g@Sv9?~H{>{LjCmvHD>!6s_HZMmW5x8{7e>E&P-BHzI3?P5 zn?;4jV=%9cT9TnJ`@2ZLzC_ESEV+sN8m?yYT0J{7hGf!lFm^TFtxC7NmyUUG>0b}K zw*XK%$EBHpxn3t6sh6?56fD}r#}T+rZ{4iGW%R#tZnEGM(Nn2MP7dPa-uY-C`7OMT zkcHKw$N0^wS|~}nHF1u3S`#emVTi3h*d~n)r@JZD+_YJ4e4h8Qh-nMxqoHmP+@tg# zsvK-JO5lFS4e0z-PeW@5d?I>Pcp}N58`DJvKxoMW!l}$W2xq^EE58i}`N2uz0O+6b zBMa=lH1Kfcv*%3B7Vu@M{BTY%m{y%C-0Fv8GD1HpK-u6qB0^UYsB6w?s3 zMb^HVhwc|5 zIW>V?-*_nnI^PV5h+R`C<+bE+9r|Tr;O72mv`accS*B15j)->^z5-TS6|NwT0Guj* z4CV_=acTM#ajdzxij*}+^raGA^s4M1!)Gzn-;Z&RDcnuOu8zjQ+@;nW}sVi9lq)<_nlY%5sP z?)G7&XFK(;`_CWYTw%@npfJypHR_n038;HPSY9Ia&Hb=~gh!ENI+>-lQSfH1|D2XA zNvrSyf|UHKb|vhj__Vpb!pQkfmOo$QR9m2B?J<7;ui|uxntGhn_3001pKdZAx}W@!t^Vm0ueu;Z=XYVA%HKczo_1bV6_Eg+l@!+aa8 zhbc(mle~WF6PC4OJF6aia`zYHHx>+rQ}Xwh;C&Y`kbk}cuTHfr0h>7rt_(>H^cPI| zKs92~LoBuT4t!xYE@+{x(S!WWh!4;VerTP4Q}?GUO$C|tl2s6$x8tPMi&YJ*T*Ca| zoIs%-aJ)<*k2PJe z5I<1i+0CkOVdbwI9$1d-{#=yLSX2|Bsuy86CHU09hpuAn&%wrKy6F;N(a_yO-gq9E zgqL%aH(^Tly)(jAp~kR6qk3RGS`mU@Z~s_e*~Wya{`m5=rKWT|hK*^XkIAdh5fGfr z;lyou7CIIaH30N!l;N1JF3n0LIbA6b2z<8q7dRKZ2d#xE@`gn=*U`5Kd!1gK7jg__ zZ@7z`C=krTWH(GUJL6u}M@lUr-v-Wj3qeP-9ufU8pp+1?E?^9d?3a=E?YT$mq~DoffcUlyP~k~2)Pd&@FoM`CPk z+!F09<16s(W~DTqwT4-7%}k|12jfRRMBItI!=TYhH{Qw}c6Wmy zo5zOJkVTQ=B;(0xyCpV$tzx^_{gpR+=Ei8l_wdshr-#vr6y94F@%z?ua2U>_kL^B}eA0krbCUY3X#bANymGkB{{7__3dN^LNQ|Ru(D3)}o!;#kR|2e~7C&D8R`usE`VCB>l&$il z%hc7_gKnxGaPuLW70f#Y_bsk@8lo2H^G;Jog^uyqDS*W;eI8LDyTA9( zJ)le$6hmjmn|=rH&(T68v1@+hwP9W8AYWGn!UW4*~Kjh4Al*w68u!3pz~4g)9`G6%0`1Hp^09HKfT(E7ya9+ zU*Z4d0eY|FOK{4Y;UYEx655m;CZh*@RcLu8`eeiN9#)ljG-5Y#+$oeBWksg)C~(U=p%pe_$>bFsx7?qx0C!F69UcQMW=H?{BUmV%K{XMR9`nkEkHFmx~vii!)M#fQ=MBP#ytU<1E;SFOF3a^NFul z;K#R%J!9yp!Rj$pr;h)3>Ca$aX$G2Q0_KG+#!($>)$vw>+Tgp|P^flSY3g&oM8pPo zAC#KIMDG3#7(q6eet5MRipI}DQGnG?^~|#DaRt-$qx0(Dj?RCdv`3-Na)=Zj=?k0eN5wuDH-^;j3~pB;?HvGK;wz9F8k(H$65BSi;{o=D)v~qO#^w zCt^gRAVhM1|CMS7XSfi+`!18{@94M&YG_8P5ZRCC-JSg@Y};Mn!Dk|~@pFtw17{a9 zl>9XyHnaZ0fN?Z~zBN;I`56ybkyNl7%tdzw>t6r`oi*F`Z!RSnAT1QjN(|Lw#x6$z za9&b2WPqi&7+R%41rV8gKXMECRCVfG=?~BeuPd3fJ@Qm@0Qc#?y-g4tlNaDbUqB1V zf?5xp)YyH1q?`otOca}xK?xjdL#V3kKe!k3!|Dw1+?F}b0lM`Yc)Qsmm`mE@vShIN z_3KCd|84L51`fHMyQo_aDu147lW@r);wlUUoB|8e93kWVF%Baw?=4^dgGj?*bTT1o zkyJ;AvD%^YtI{{iRnVOnMsSbjZSe!1R%c6sx1OZu$ma=K$+>I$Y6leejD4`#=h3qIPWY& zl>hf*Wnc*~;Yr9O_P-zOCE<;XkpF{6&TK%5j7Q&3boD_H2b@m!KJf;aSEImbPsafU zlf-!pBRJYk2>>(tVA%GK)R>$M91q8zA09hGkmxA%Y+U5d&kw>L3!@uYle~qV7yJ+5 zBtL7d2D#mB;Zhf*A=t`_ZG|aoT5TIpe~gH1U9^yi)k6~4fxRWVf9+z)d$_AF;J)u+ zV}{O$H*Oq$H3iVgh0a;65z3=E;Uut?g8V_%a+e*1TWDJ)hKrX#5|wO_$$-vt^^31} z5@W`0$FYpC8^5>wjj{jH{S|U$hV>Ap`0W)~Sr zij#%AE(~W4?yy5)Gua-*jrBnKRu`^IwhyI}2Rm^IP!(z{ZUb^$gMa1}IuBf1M7)<5 z;2#P0qG-jqb@-MaEX_g;$Otd%*?oVXhz^dqN9}1~jB8=CMWJYQ9IBf1{h6y_HZ<9R zix3obx!3u@Xx0`tW=WLpdi!u4lY>O8WZ%%dR~7d(ClAz~3@W>)xhKUUoKM-}Kch%I zd*2$)9ab_>1RdmxlZ@EL0PJy?THk5jk7A$z%yCfHZ8h%)|84CK2#`#hlQIdENz#Lz zVUot173l-N`pS!$x4a2!-&&{T)A($&Y{9DTQcE{&+h)<%1ciB;XVdfJraX<-xqY+N zB^)i&pSp_XE8|1hMbaY01%7#l;#VqoiT;pD^NW~$&S2HLeVy;=;POPybbdv9&7ZL^ z+=~sTJ$$oq#KcWmBlA09bzPdK55Qd~ZacaK!}iIs50H$9)<5B}?>y%R+_ve9{HtHy z!|Kh!z}&?c7{5@~eQ!>F84x2@W|S10rZk`b3J33aT@CcEX$3wgfGS0uj^V>8*SZ%) zklv%SU)v}Gzp`_;^HXv;^odk5n~y0L0^}on;KpaljoR|=*!G|D#Pg+hA!A8(SvBEa z(T#VH;YZ8PHa5rpmj0p`9ELaXE8RCZzyW4z_)LGYpYfT1byos44Yr+Ph#w3RlCbob z1nR=P`XhC8|2HvHz%A^yO(88N1#RiGKaG^Zab1oC)ExnMcAsN_x-pxJVuN z94kq-wH>m0idUlH8&sYvE+yLKze!JIx^m&=8eBT2!}|R>O5H1p-LXYvR!-l*X4)&a zXYaEIeA07l1|6ii%c9GgY0vxT%BFnpSgg=u)_!4gDsdvP|E@Kp?F(MWUS@koesTjd zQr*FaeP|GZ2P29L&R;Cpy;MU)3LfNYiZlR@x=&7gi(^^&&|3>U<*n{b@9BA33M*2!cS zF)Ps@IzK)&#g!*H?(FRR9HC?-y#A{-y;iLB~b5Wt%bDHNuUr=%>jNj$7~%Qzl;v4_0nG{qnPYo99FO|9T(zufycG ziLIC)954KWVeo7FtS=QubLWGyoFPD0SAlw^M^iu60O}~6vl`yxTBeW>pxpNi?_o}E z0LAsVMUZ=qb{l7g6n2`2_ZiN=U9sJ4q;Jb%0@Ss|k^mwPAowPe8HbokEdN&5%w6 zRO}-mn8<@^avY9bV6&e1QB;%(r-P2JLgvgLh(emtp>n%?r2QXurst+xW;y}_sln;bT>aG7|fFtH@J9o-R5d~_+t6xOdJ5YDvJcYUS1d}qqOZ( z^cidIZPsl3bQ}Ve3z~esps&$6`I*=S)64P$`3!97I6yD^U1Ah+8{57%E}?T)^1*nE z#c2=}LhxWNC; z9+I_XshqV~^=o6jj%WI3Ayb4~3ET(0qjCcfT;vSwp-7#LzPXL@!Xq-rhgKiAPp-pa zG5%7&x(hSaVuVv&h1te5WxH}z9O|KRGj2ZpiwN#@!u|?m!ny2fZ*b6>h@Zw7dXqX} zIyM%`IJ=Ywo{&1cEASaq6ZH;0t{7xB+%djW3$CQ_Aj7*kg7M*D;nz( z=d(QKk=>)ewGVm$ug8em>TL_quef^$jI!|%Wl)wns7D2T1YRgVj8cN5=0Iub7CSS* zzlCZUHJ*&3x^SBLb}u}2cx*!?gLc+3#Th0#n5L-SRoco(@ukMo(kmzU?qn?9g9B&t^Tw@nfbhaKxaB<6Pc2iPyt}0f}z*!M;Kqbno?A5 zL?apH%u^?5%UG@%aYmBG*0PlGm%X>1zmtif?G*4FEPObC;ZM4fpV6K|k#Ow@8ha>gJ zmmnS+pRna!>xy5y?!MS%K0$4On6Alwt<%0^7TvcB|FLiYePg{oVM8It`SX8ipY>$yQxDo55UXFmzNhk$o z4K~yA6 zxqc3!c9GE0nvJUfNw~xcP)#s}opzB%HV;*cr?orp3^j(!VDZ7XyW-m~pz2j*zS)rHK zP+ATm)>S0(L23{-Pg&-JZy29{{YyCxMbs$#Y0>B|g_8oWD3BzBKe^0b0cf3lmcmVm zZCnuIs#|kz)dweX_*(5x;i1=Jv97m(Y#=>6M-CD2~BG#49Jy6i)LnFMFU#U(T`;+rR_lXL9OPyMIcyH)zijStNGxHZy z6>%lTT#Iviu4`NkaL&yM7~owycj>oXW4X2n)l zj9r_Q;9H5n?p6%<3q(MSdgO6^%tzpSHTyH}ZbC_-f_z{Qm|}AK6-gEtR7iUMfRD6C zoCSHPu3~$mHAxZ)Oj}Oq_Kt~@6Lz-K@^rk&Kk;daRi^Tx6x+OlmZ#;*-Yo->LK#{l zcsY!r=)~YWbrnaeKt)>6G|NAwSCE0L==GM2-Mo9fpRVJNZOC&OeEBxOtLIk_7zP26 z2QH4;L^xTXzo|C9u!ROm7XA($$MlU2o1qt8zX8JIh?$_(mRZ9GTcAu|{bVb>#joDd ze3Pz+x~f`f^%$ij9?9*M&rT;5_aBu?Q!w3!L&g*zdP za$H3vVf1paTz^)2lt&6wf95P)v1TQHi4jRxiij@z+*y=VxxM! z=D)a9cyoc|tm4|cXyYKTTVyCN&77~@-tRGyB~c*ge-_GFeEP=nBc_dcz!$~OM~i0p z-jz=)TvNv=yz)&goNQby9Q-POpvlY@7ru2K33f<;Y7Uq+R-dDChavef zI0-Z44TpQuD0w*&IyaE=LrTDPgo(*-nBHsy1@eN4NTeyEnSO zTNt`4ys8OzT8`BmfbM|(qBUC?H(kh3UYrLhyGapy5WhABm3vdjp-tc0_Lk&s)Lgu_9 zIcHVc>~l2O0esTylf;U%ZcIJ^Hjfu5bGfHb`-WQTkt)jd23kL1#S;(^zmw*`G9LzM zZo_y>?xpH2O(3px#jc7nBK#dh2eS1*os#<$Wah^q#?7vS$gdgL8sin~A$?bsx2HJ7 z5)B%}}M+LBPj)h643Ma0}xmc3??`t=cn$0S|IBScEvm z${kR!IhefDIV($vkUb8=*R`t@EbD9Y&FZi;;}&|opMc}52%t?c#!eS zBLhG8TvquFki7B|ntyBOVw(CyX&hwx3s=Dxd@gudrZvgc7%IETNRvppe^@Z)c@X!1bhxWOG?re0ZK zGOPY4!JzI^_PG}Ff$3pSAPf2p$oWAJFhf4Ts37H)Cgb+W5bD^K77pOaO`$`Elx<3@ zqs_>+2MIV4b9ThRDfB%^tY1&PP;HLb2|Dl7>^N~ZFQO#j4FJU_ar;Z)x2k`5f@-uC z<^u#_%`lL7`Lk-{2XqWjkzlxegWxXL@YVelISWgM;k4t8l8Zc?hW?1Y01+A521HxQG6dLbeZ?{w>Nk)u9Q5rak`D&wK)&e z-j~ViSSD0}C+sp()SZ55x*3Vp*&#~o2+T(8?Ir6s>loS*%hkATuv;wT{y zofUZ9wMPpaELeJ3Fm}b`m?UxPcBzUGtCE=^6g1bl6a~;F0(WrLTwFulJQHCH+rFsW zRT`3#B=&|oO*FzB2Y4R?8OBp8a_0m4@BIuXDDFzSBmSUnw?%ksP$RJpB{P?wh~@-X zpXS?h6T*@+f+kSG7#4}AsIjXtx;MUu1Z!?6LZcJ>k~%ZbIc|8etU=2%iMQ=bAw-;dQQwe5`S5!5@%G>S9)adJX%s` zm_>W6F>0$qTbF<%-A(=v&F5dmfN*&d$Lp`O`B>-cWC#!9cDmW;gp<}mISR+qSx+D-yY$OAicp4-DGmmFXW-MyMVJT*?1xb*u3*nioq1@@+2`2IS6H>4SOM7-@9=P6!fd;iMu+!B-W5v0ACLTF zc-|)$9|$`oIk4jaOhj2!+902|?M)r?b)CgG0Wr)0tNWrH!VlDKN?nK~5x@Z!s_|YJ zaw`XVM4Nk5DFm!#YcPfK*Y1RH*XN{*YYxuq*|wQpg&YopU{hOd!AY`eO5A__sge*P-5 z%{XG$M0R<0r;a?ku=GK0c0C4_o+8oL8XHdS`u?>u+}n0NMeL*XHy=2)_TXe*_Alk8 z_SwsuEmFRiVnr6ByuZk##}O`7n}sTOUzL=pEG$C>DR>z>toxXQjyi99vuq$sB2Ag) zntgex=YzOL!-y6HHWZSZnJFM?NxL+1x;v#0>Ow-z=Sw5|Vk1F&&$zOU58g^)5G?JP z*FRyp+=X?HbTa`H zut{67_RLR+n@A!f;Gmm~DO57nsQFmDS02^1J;l&x4ewhS>O18WKauYZId0~_ZUB|m zi;c07evf|XOh0`_1wLJA9%O@aKYR*vHo%w9A8gqk2`aXQ5Diw~DnK%?6G8c= zf+2tnvTQ{04@zssMn`#}f-+r@Aq?@CjBh-oz*7wf2}nKbHe~>umh3^=5AM|mdQ<(C z-~-A`IHy2b1e8dw<&6D7F3xB@ z)#p)f`H}-p7dSlb*R&7E8a}@TKrz>rz3L*B3&{LYsynTh+|4&l5TH1am{K_?ZwWDw8ek zC!@D1?T6g_-RtHdgFj_#s#8CaPfeEZ^CP4GUoA+6+E1sjTWQPF)?iUv0ILdZSbu;u ziaI*Lj(8=55YN0B?#$Ak*e+B$XeTi{wCV|@K^H?$;L~HG_}wO3%-489gMoT0l}8RTFrHS4dH(={V#D@%{T<3q5EjMx1#kVd>eUY@ zC+h@(BK7h|u;^_n1f$~>5J+t=3EpJNyocJVKQ4$B_-I?)r;QhBttwo`iINPBpwfpJ zi?}7@rZUjWwM`%|YoMQ z?CN%q>B9Sq-Ij)tQaNqABEx?K``_RxIC$KMIHhs}L3CUXpI_R_dZF*g z4wD4Jpq@9vS-8l*l)G^#yqQs+Za_p5F5J8P3v#LjgJ+%}{C{-4c_5Vg`#w%7WKBiM z8l{C~t4x-nqz$dIC&`|YeNUD;Wh;@gwvcR!v5jq*`Q5Ln&-tA5 z{hiPAhqu$)%slhFw)?*B>$+}9G}x3&Rfqdsf;%Aavu1rhA-3N`UHW-Hm1#i2itEZad zEic~V5h5e17O?MLnH-pph9b)ofVzn|=p1$txtkNG+~Wv{YY%CPH+$`_^Jy`N!v+U< zs~0=3$eRFhjO!aT_w?#LWlf9T#Udwq0tztW4nW$jL9UgC@ow5R?~D56>ru2FL*FW`scFL1>bqSFdp#G9|ONS0^5i_Oz$VzAS`> zPw!(3d;EP6`4bkNtR`bd(;_{8y4>C^)@f`U`j70!P4B^-!=nyi#tc%38NGA5#DDZA%wBw@yzpfN}btWofhflSF0 zk4J!hEoA5g-)p9zMU<_6*Y#2+uHiA!39}zvl|D)(zkmDRpOqYKKpxrb?s6Q94)Q4^ z3ikUY2N6dnEDma&J-n;|Sx1hFy4=QhqLJ(tElAAG1@>!f@z!y`Y!TW`LC*f8L%C3| zY)dUJYr3NiE7SWQJH^2Sj)Ym?(0cU%FTDt}*hIW96vMKb)1XMZR-0rPs{)5D>DPyeg7DmmC3_UpA<9eqA&(odxLAtL zO{<^DxnGkHL=hILXarbV?i3ms&lGrZ-rvm4c}I7+8e;mtfWr|JE?4ZasI1 z+Bljj8g}YQ!$T38Y-tEixjkvD=a8s2eAmF#Sc;5`+)*w%uxd9mVQFruVh6*CH?a?P zfY(HiO*hi++zg!r)T~Ic>HeOfkz(Cz^AlZeBxV}wI=voPy)49>V18*f$?cS`Fpb&N zX$1fK(}BzY^^U^c`yU^r1j!!oXsCq;^K3mch62BA148Yo-eUzrSJ6U?g&b%PMJ5GxS@h@tX8o-~?e{ z<{u=4O2gCoj1kT3nd#@}3j839ciYk)G3F7pA9l5~;?T>tLikd&6Cnx@fk$B-Ei-_c z+lI=f*H%Olda})Z#`BjJWUcmDi=)B;#O7(J=(6OYr9#r+J$5{N?0DM-lsS_X78)b{ zFLZnMhbsbhic+3fh%x3`0=S4p7mW0(FfOvrP*)VrdQ@7hv+9J42z1diO)s2;@*VT) z7R6y#v2aU);)uOW`oKKjx0=rpOq0o+hr!ndeAR}?E35yA7y=y(F%^hH99!nWsib>Y zdlj$1+o&axF_!S)V_3x_Ys#zF8wcuC?YRmxc$LF1S61`{eAfdqu*Oun?8O>eNM@Dk zO%_Y1+|-VU0EPy{d5I9mF zOfyGPa0z@*;cT|AcnX*%xy1eiKTW?SS01Ck#ha58i?2b( zxcS?$TO$cV#aHB^W@9Jh69?s!D>w65!d?GzFb;bjv!$tcd!i#eP0x9>DF#T5jE?R` zDpY6>1I%{gD6J|!0Z)FpYbZOR>r;BRf^u4JC1O2)@+8vp?;~uS&8$JZqX5F z&s_9?r@@w7cU#~_^x@E8n`U(XC;ROm*R1~ z54p>U(QZ46qylWjXFNt-Quh7D<}{#S!~k=4TCD>uafH(yj65eeCG3vKlv6c$vo#d4 zPN&)J#`u`I+o{i_T>56iQhgb65$T?J2YH+cwJ*nqgH+i(2hg0w?zms@V_lGRh zqh5u>dZ%W`P*K;-Y94jBb{~`52?z!6&>^9H3tg0m-+PzGVhKtC7f>I^w&|@s3p(Xi zP@TVNjWs9*u5}z<%qL6F!Q-#*Sl5NG4Y+FbdLfxq)?4-J^DUBq;s)J=IFUFFTg@QC z9`;H032~mXwPfFAaz%TfSnicXDqD2rJ+%X@_ZPW|9kA)yFPh+}CMrdeg!+CHiRwdk zmb{wtw>1ql=u?q#Ow=D}T{)6G?GxPsbgj6kpD`3q_tdblTvi4e2M7y|OhlmKr15FlWleVSCUc_)~fFYAS5R zy~QKhZokSoAIG_GWMw(nAM34aa6IWTzV4~Q%jE-%?*ZqBkfDlOxz`vVeoG?tf=$u; zAG-}*&ZidkH?%!bBs*&-<+%)gOBx(dWs1KBA1y&(q-jQ;M1VtL+nfU^ZU=#G;LlTU zi~o}Y1wJ_Ne?egbRv5*GwwCgouRsV*x^ds`gGlQ}=OKm#-Ifr9d49;{*^r zgwH8B-y4^K`XDN&uC4}6eJZETMjseiAl z=^uWna<8KN7sQ2dL9A@FPQe?dSOjYBh?iW4-0!!*ypPAY*>@E}YSP-*wS?9zO4Jd* z02R;>VVOzjrl81*tm!p$a{1F?s)4>GnB1RpSpMX=RSj? zax#84Cw+g?(6I=^W}v*-7(?QvF1Wh&_8}dF?)v!_q^jr6D`@siB?Cqw=cAdMA6DQ* z8C)=bi`dN_H%ha`9^e@B4FAMAz_8w-T3dy4C!B&*1?KEV3POa7hDMv#cmgBb`@Q*> zmu3=i4+NlgzDFj}TXCSXa}nuT^?Yw^7LglHc|y5ZCAIew#UOP4g`fXvmQOLe&O<|N zTG!B*tM{yDY3ke|XMF7A&wG>V08i7~LLxIpM3+|Bg`ovi(51lf2)&oolxN=08$=l%|CFnU~3h#2BQP)*TItZZ6GBD(`*V_K3ue01k z1OSO(ZiL`zr_N)Lx?!`bOKlF0zJ%#M2{_Ry-Pj%!vi|+1x)XC?J8}_uA*@!p3Y;+n ztNFqM$tmm1E=)|%H820?V!1hp_{*DhT;|`S>cQkg6gS&3{S#oEBiU?`vqVGy;C*|T zpYr>Msn_pm0C_|V98YaioEvs*gwtUGil(O#sYsOK*PV2GF`@ZSj*eb-bMf~_p-2F+ zqET%4TO}CSX9K{IIs|q|3)x6}e+Ch~w0C;zf0#HhsZqC}va}P9hFzuZ<8K4> zp}y7WHI#_*U?UWZq4kd}6@C-z(R(qkBDLQ$1ETsY)Y8K{?R7QK*Y|w@TLt26M9BM} zYp*koN7;Imh`f%gMwTH+8tAN|FjYp*!-R-tp$`9IM1z7I@Q1<=v|OsK#AG`SHT(Z4U9 zcVK2w`A!L}F+P9;2m%?L$IDij>?Sa88r|pI4F!YW*S<%HM6L!MiQ#Royb}JuMrS=L zY@;f&s3yWrL1T{O@x>!)&zTPq5|(sX0KX7f9&M5TxS^X~Xtoq-0ma&3sH7W>AwoKt z0({_eS;2&%n$lr;{^NTD5|B$*aKsRxS}%j?Mx-%(Tx-zayyQM{%K)XnTV?Et_V8u;HM{`&=$+kcdK-A2-I zIrt)h4%M(+?eBd7w3vYOWB}n_M!Ntyz<TT{Br2M6OUm`fj3*qNaU;$rwO#sw6kzx=(|!7rOv1^rj|aY~L_7#?Q4)?M-tEP=ZT<{Pjvm_Lsu4S+2P$at zz)~){dV~fsD|Fm_g76)^t&meQ3lz+y0%8QTY|xwLTw>NUfeL+MmGZB;L=*Yb8xS)Q zU52^AHV8@rW4yO$ZnN1+J2FnzILDyf4ee?@^tnPZ7WjlMihWyVhU#hbnpWFJQmG!CANXsFN9BI&Kd~KbDUE0 zBWq7R)!}L>>O{peDmXj1TbNFR3%9ELYhlC z8OYbF6$G9k0R%>FJRj6wsK$l%Hh}700=clT4h_tmJtI&ARCzZHEkt+osm~hl)GjRG z!PbD;b)5MqyRZL;1c^o9q7BA$FHDsQFZ~<2<>)+{hE{P} ze&yk!hYB8UJ&*%;eR!empECuGNZ|VMZ%3d1WARmPLdzR*jY0E#@lvk2S-Lv-=P}m^ z%$7lb@CRWs4gN`q5S~U=@X|x;2vHSJgZu!=y7UM$aCmL924@9p5W)>Y_p3orDGnms z+GuDTPA#;ppr}UHqM{595CY%#xxA7?)m%383_%92tC zCOP5*=(`a-Z$oQ}orj4!1Om7Wv`=YJK=1H2_d%J?ht4o@|00cFi1oDvKu^SQ{)Rkc zP`Pg!Vc~V9oiwg9-RaHOXUr4kzV;pj1O+KC(AqDasXGJ*My0OQ-- zAXEH?teD{GaY>yboxzOrN#oVDgOvBq@6R8%m)!gv=B2&q-%19uly!0)m|6ft>0;$4iDg~^8eXZe}C&D`|YL@&B&)uQ7PQyv0aM|x61J4jt)>b`!98%M+D zEdpw{;L%`Ehii=)fz#2G520dPEZwlpX$(%CoR9n3BiOu-k{qvm4|153>qy5fFHs621U!UJVJsw=01oraWzq4zY0O-v|EM6MNT{c6!A8UVk|c zT}iFCJg({5>PTOc&|byw(g|Ugk63fn8Ug=?P&Sj(aPrG^zBq$>ni4oydNx#622$3p zAq6{4AXm<8p$j~V<`2K~if6FM;=aUvM?-(B;PYP(j70@sqlzUwuDLnt?!1z9=Es`dSeZMW79m zXiZ1;s>FFv*F8aOQV_E;xegT({>%O1L@!1U3sex*FqYy05Mgd2YF;h~s6bnnSMGEtj2UBz zh%^7aA;TtY4V^`q;x3Sp?Sh3P2lpudklRih>LFq`yJ2%7E1cO{k^l$JHz+}U0|G|R zet9P~WFLc%grlnC3Sbk(u;I!Vbt0hxI)kSebig>tGYGChG?zKAPPFUBTi}&};^grDYkhaWbUmui62u?e zm+AIOOqXjjFb+e5B}`A=)OoDeo^3UU3U~z9ZTde>V&ZMO5!P`ztU&2QLazF2xxp2Q z>cN(_c9IL=u&f`tIC*s|D?`jTlyAQxASaHTeO= zm&8I8Vrxoj*(Jm7hoMXh)IA>&bN@N^gicG?v$fc*>+w18wU!iR5W+~JT5mLTXI zpUhGc{k%cvW|te0T8rB_5-7GhWGD9%SMz%RS60i21b_wJL8}Waq__*t5SPB8VL{1D ziq=T%hVHT!L(o5}Fcv|>Jnq9|V_En;G>y$}UXpf7*-8Nny#>|S!cLb{JjaR?1eTyw zac8u&6;A|dk9PuE=wawAUV4Be%%Mft$)|$Y=p|=2I*_)WfMr&U_{#8cXA?ZQ8Q6O% zd{oM=Luo(af(zTf1LhG%j+NWUIl?-$OblVhL-{W6tbLk7eNL&*@rrq+4;A{^50={9 z^^(^$8_1tUbWc0Y870m0k;hlLuU#j*MR%?bCcN7+!W`vhp4BSU(+7SGJVnjm+`1wA zGH29zcaOL|vwCES(gIWsNt{EaWUIJAn+~N{egn6%zh5(U&~A^+qM^Vjk%-G4P)Q;# zZFMd?YYx#1Mvl^&En4vy8;4fG{9Q<^Fxllo*5-4_q*7h`kdBZKax~s-^v{G7bW0~C zbY9)20zuL{Exp<&Xvo>C#p8|?8A?eNj zm`0f>OC&Bb){@?q*do9EuoU66!RH6^6_?S`Rn3YP%MhZZ#B$c^4lTHT0jAaUM0eFy z%1!%8p3a<7PeJK^Y|RPoG{LBS4HbolpCm62$P7XO`RyI{Eg!Nucil%4jnIooO;MrK zM8EB*B>h7IAu-~~4G-wXT{iJTd-^zx+_i*|Jt9W#2$!8c>}grrtJZ%oQ;1;|URf>N zO?DVAFI$_31HFVgRw5cHz{DOr;Hkeirp?9fOxSVZy!{&11F;F5tKJ7T1!lb%+_ zU=uyOK|5VtwzfHf>GZ^-_I0lCaQuuNrP#>BXM8peqkB__bd)kb{NRc8P=4He;&bPU zV!cyW&R(;~qh#Dw+l&9@vX%!P_}@v~?`^dAts65W0lpiGIox;mKyH>88x^PMgp)y?+ba`AycAo?k*A#eP{CHI3_;5e+hP5l*%};&%0ia4CZ~My$oBv z!@DB|`D?afdFeu6Qdt=8krq&Zr4{hn-N30__C43=-!X~ocn5e zvc*h9^D(ERv@tz4{*1~H!Lmn(gVgBfg0w?VMp%#LhKLR<NQ1@CRzoV2YYZv5L+?NZ0BNI>`Z z1$%5TctpLPY*Je5fC(77JVcG5Vu=@<0h#G=D!dl^y_?qd*Z%lY&EmIWkn4$O4k_E-uDXBGl;bWx^;~r5s<{8*X6%9 zUpLvXF=jrGK3-6M;5tolplFb~*~{s=zmMF2N)(3RVmy2z;(XiVm722P7YXvcJ8}~N ztZbQ2q<=_oG~pT>$!?{>9x@t*FGzWDDUCNT*9pOZMN0^V`upmAn-9J-#%Z@bf&`O1 zf8Hlesf#X|$V|EJjZ9DSej7XTE>Vv-!c8}%f3p}d(!(^ROSyBsE=n*C{Dca{BuhGC zk|qAiLM@)O%LT3IyohFo#z`O>(bHw;Q}X|ib($oB_Lq2IGI*# zEDo%3(b;B61|MURkAPSJb6);FwZL8eh9o80Y~5!9zjy$P5kuFff7KjO-LaD28;10R zv8d#GM-nz!LMa$B+v=>^C?GKfRD%}WhDm;>=Xngf)kglIEho5AZSP2DJm*HmU>?uS zdd3Z>=CWH&uHj62wfFRd2V1}D?njbZxsLbZx}&nxC&X^#cdK5oFO>cvar~e!#iu9J zI!N|Kh_UHI?EIJw>7uz3)BkEdFiVPcLwgQ=T-IqPUX3=7jOSE3`+R}$73&FhgX9Gq zoyaJOWgyvXEUHBy0G_frFq$}(45H9hqPs&qN_xx!R#^%x+?H$)gLsNqvW)7YrDcz? zGc^jj&sUP^>5L2+=`=<`+KqDo?GvbPSO?G4g~H`;KDn7V`EDalN`%z^rM+jua*F4vm;5MUaJ>v{<$! zj`u@m>h`=TRjqG}9GkR&Ab)#3;5e;Qjt-Qe^lGny1LV4b+1M)&FU^Tf7ZoJAlIpR7 z!;L0fPjvmR>#ks_$@&GVqWv=qbj!7J2`@a%Y;YYKI+!IJALB4akwJNZ-U8>Xn*Qds zE{-2ML2eacR3PK_1V2zTM7e}7FI2cAuuHy$H}qWQJRNG+1@hW+h2#CDjieJ*mt8~z zBBI?bt@zQ!LKJL`>J=Zbn?0m=8|S zM?90ey{;{(!$-@+eN?sMSwW*kS|Q7$87KV+vr!pIAr!k)9J0-%H^QiaR(@sLce>0` zn{<&&*Usqx;d>bzMJ@9cz#hzLAwz-_*!RDdqiE3@mIKkZWjZf;#c{kdsWKRG2i!=w zI&M`q)N}USh4r36^Ed^@z!=`Vn+wy#3lcP^eun2FXn5ylK-+ebdx_@Ewi?%imd_! zB5_cUd4fV8o0Xv%l#+;pXfppcLvvAv@v6QI6=fk_AZ5_Otb5$ZU2X1%l{K(K^8FQG z-7wLufq-=1m3um)PAf}Px8(rz?xbCs&2>V%rx4AfzQ^b~*H&A6FQRl&pH3&PIvc80 zpzf3(B0U@15V-*Q%*%KSAZ1|6OgI&ES*k#jL?*uhxJ9hP_6YlGyHu`#AAvd$<5|QFR#Yrmg}Lcyd)>s-1p~( zQ?9h1|I? za{YD$BYjdcf(Mav^w4W~pZdeo#wUFI;6QVr=^Z+=mAsMw91}(ViX~? z!;RR0Wqg1s%2PB5H*$;JALgmsZ3V!>ufzSCsL}P&5#J`>nN9?1-|(PV#g&{9<-UL$ zzXj`qK{Gy(i=%t59Ll|4mi~!>Y%B5;z!4%I^akp@?QLbr18#yyh&#N-HXx zSaaEQ=V7VbIBX%(vw(A|eVqaxjrBsH2 zqPq+?;PXQ<)^s7oldeaR&EY z=kzBJx5ep^<${^V13?$Rm?cH{+R%Z-2ohRVTuTmjB<0>oq_U%(o!rwtZ=2ZKd^P|e z+x(mlwF`GO7w#JGNRaB=(2iI0Px036+TM`bYU!LYAACs~f`oXC9jipoQd^;YF#sIK z*DY?>3M?Ruq1A4M_$1{{i}or}@30p~S78wISD17Yc?fgD=jEsMEVX$xseb*$GBc- zLsH`^8G$CI+Rkp}?u8E(!Sb*CuvcQS@s7>V%xrYYhyBJYv*TR%H`k!tSX=o+r|#Ao z2Z?&*-EcmAJ9bCF(87-89kdoLWJssh>tgalZ)>EZO~m41r){|m1oO^$YH%*r>@(=7 zC##aT?%a13V*32k@AOEshgns!HD*d`>FM8XdZriXPMVa}oQ8I}&%2Ee)}zgFX{mn7 z3$k2t8FukBLE+ne?9FFoye7|4ae&;DL5b0pbkgX!m3jp+0CLp-H4%C>PaL1-9=SkA zMoR8=^oB5v3q!B-7y!fhd|_YLPy`+?G&b9#jEG52dEGEd%!;*lXt263t)pizSb%tU zSP8U5@h%}A_aYqW2I-0N?<70o>*iMG6vW`3NX9P+$Vg5k<35?oi_N%mNe^qa^XEtwiyaMsZM{az@uJa&8~AT~xtE{(#&tuzH^! zU8O9b6YU;twSn^(a$Bnm;m#nmRcs(B8q`!BHr}dd;*Chl*lvPzfQ=~UU$%GnK->G? z3;Yi3ONX=9*h)9_`2xXl@?o2KUOnf_8h1t^9PlRTgZYmO6r%+9H+|cI&kJBVY97}f zcE>!KbKoiL3SPtwLiV)wU)(~FPkEjuO&>PCq8A(O{?v`>U(?lw2K1sFTRM*I4Z6dI z$NkM(4(ICaJhHP9(P2Wrn`_!*Kz%nsw{+`UP-UT(Z7eKHe-~v@+)#OOdt$E%$I-`i z11ono?bRVKmxJ7w)Tc=}!Eyw1qpZOi|(Bb$?1_ zsNlJ1UJB=eE<1H*T%UX)X>gWrRF~rjX5PkP$$?C^@F?GIyUpzpRp#EyHJ6WaMbwm- zOdgxtmAKfUQQ)U1nkMC+S=ucy5fvB|eCe9_2X)TY;gw~<3(-!VC^jR%ZavQM{_4NI z<>h=yQ?X{plOdaAj`~?+;x%fEV@dI71=fP^`S4R?Y)i!T-kJ$l7@IdT`6leS$EQwzCe&s5OSN9oaF78hd^{ED#*cAI7$8 z*17sS>=2_jB~>fzGN(@AW>4kUxBS8GCet=N0JNh2A`L>PJ` zy-`zmQlXtFxWC!F+HS^aSia+Fe{w-9^qL^s$Gauvju!?d-ia9UsF+DKzOLy*P;j8e z_b=$tr!DA&eDi7HB2=tc_@TB}n}ke)MzKgdQt^c`pih4V@TX>mq_9`+2_IUs=1TL@ z(@WPy5m5rKnA=>0YQLpV=6_=Ew|F@ay^_D(Os!02dpU5>h9*FIG`{dt2zMDKPLcP2 z`M{T#F8tFJY;zhE=E#!>`({kwXp~Vbg7K$?{QHEyAs`5R(+H?Qh6?<^)c0;Ah(R4k z&IV#zbclWc$bzXLM!vI|gUFbPNQ9z4qKOc1ffoqT3lVWmAiqtbq zg7K7mz#<`^_nG7IjzXmLRU~VGa@>r8^a!Y01hr{$8Nm82(-39&wMAoAki8n-0_J52 zk34SK1zB8+q831j9zgnULlsuf?2eXGna^ibfh*gU)J;Bps0gMc5Y2`<#Ck@@of+de zGk~@m@+P_w@n>GWBX;lx5MI!EmqS3hUDLgBS@KTEo67n5JmkV{id5x>WrUf^F>(Qs z+KosRi2A`8OJ2zsjo!U2_mBg7BfXqwl3@pKc|5Dps2D zT)wu$OV8zzPf~pCHJAGMDe>DsA5x?}t_$>>_RTvjdnls6W_|ye*iC1*o{*E4{;PK_ zzr>uMGfSbS#U#-_kcBhq$D)7xYm3ykC9xJ4g-SEY^SjD5U1f(Cpr1&LxCum0^Uen; zlihq+Ib)e}kMzvk-1(Wm3Xb6Kbw`r)7V|A=D)JXK^BOgpm)-Wp?@h3&y0r|J28&*2 zhIkTh4}2D~IGq(XdW6E$8a~&2mrrB3AEX`*jkYZ}+M=b7m$fWo>xG4dmoJZujJ!vZ zvXinFWUu9gTa*DldM{tuGAx(j!E_Dkt`2BSjf=$c5MN>%Rrd%!Xs@gc zUH<@T#Up@!I((TM|0Lr5$dEPjL>-N@NB{d@SLJR&#B!G9dVK{79$#qMB}GlOPwXoI z*FO68(7#@B<;IR3I~*MyYro*}xm)I83jR=3R2&1iJ+G`x?ZMG)1s)W0aj?@9e4z6( z_Sv)1MDtvqvJ37&I8=uAx~Ll@bOJ>Uyn!op-zxyHh)Lv#5*r^sG7}XOvyt%a+cbTj zY=fWG_wV0h;gs79=G;0K6Oi*}y?9Zjqob3Rm)DFhht8tr?rv^IM~>WqcGbpSUd7J0 zp-XLK^NLM%b+tS6hfc;V-35w|bZqKgb#?W#HpY6FWjLwnc33(z_?<)Br^abQ(swAJ zm#g_LVRJo9OrDoRhUCYk&P`J)eQ>+X-6cZy1&vtd+8$CP&gqWy{hK42q0l1Z~$;vGsQCix%ex4V9ti~S#m2@ixll=PGHTA> z!qnfJkZIjNTy!x}_j2w{5wc&7-%G0n!~@|wj~mW^rbm4ZG;V z0n-}iMMpLps_T0|({%Z29|;3Ldq&70lRw!e#!Lue@B2rs(==YYbmwq&RU|O9|8WHt zpKs6_PIG{&!*pR4kJepJmA7p@yIbEF&wFIt!kr9RTLXo$kv>-YjY*xA=CcjbXJ0N2 z9A^I>P!P!e-GZl1n_t_rd}r-pvQqQXo+zzwVymY`AMaO5aeL(?kxS9C%Kk*fN7{!j z7^WVf&!()&E)~w%gVjo1cR-*@u4;dn&(DpQ_=By_^c;U1c~d{JK#pyrY)r!s&4!8# zq7D{s>#)o3lGfGnt1R&KZF_;aP;}yHa`4Kl(4|qV=8(YU_XgMiY*~DSlGEebS^uYd zMZ(tIIQ#DIs7$azaOIlT#~3FX*e@Qi?oQRHnu;kqEt+oWr)-M1u(V8-d&U13e}Po6 z=kUtg-iYD~e{XgB(lmCtHyT>|KF^M9diS!V`Te8EkNZFF2Hj(5Bp3eC7dx-F4k7cl zOA=-5%Gq-c(+Y?D0_;0xyNT-QmMhxD2D5a76+55D^;_?>=~q`5-K-71JqUYy4yV@H z$*`ThM>}5Zi{9F(Vc;htZukrrn=JBneK3Z{Ew-%U>k#vNuOw9$YW#C_Oj2axN53#8 zk6uClS~<-bp0$Z(5_;k+yrY0Wl#*WNml5bH-ktkp)Sg3Jn2;G=@MRB&MDXr6sU@o< zwXB>}Hs?a`b2^QJ>mdXM1sM^~gm-S@NL@SfEK>MZrlpsQfsU;#&I-><0}|pyI3?L< zLRDN)>yWpPPkCPvX3c(EvsU@$tq){6ph0MysGy;vxK!`Eq|Q zuG@!%dz%?wKm)<%Jh82%pK08_hI3myP44R8BxQLILOOD+R1T*UVleSX? z1O8(ixOhGM(P7Yq>4{&ubm`aY?%Upx+qqbUzfvWqrlF)A`&ffParnq3V*o}HUae6 z9g)usjz3G^$*qfjqGhMdAg|%IE1L6idHNMp9DeFh^6wwI`dzApirV&hW$=qM7N6*X z1me0GlVg0vN#dW>LY7{^H_<`DUHrdkRs?;Xm#rCRm%!e7tok}vgMk&9KV|*5MFXpe zhLjbkbWEOOU6prM+fyZr=+fF?!SgX!C?$2IwQ?Ei)bIID@iuU@?DWfNNioCLj%dA{ z<1?(;%MP>hHLsS~ zI0I-)AWK>F`Gp$-~-iuivd|R7l70u?nxt=RcEcB`q&s zU(K!6d-4Ooc;D}C*O|4$fK00dOQRbDm(pkTfz{e%23`bh|FW-ITV%i5kJF*JD=w0jNpcr!C-YR8aBK;g< z6`faFgMn(Is8#c7<&Bv2tCU;pj9b$Io6~$>N91Z~@XeP8Fkk(sRIu^RAKFzI7|!RT z>SMQC-$xYcL$yLo;HBUCIV(@IgFSDO@@30qHqNd8wX4tX#ZrT^@ep~9?P*Pq4F6eS zQD>46DdJtdcA!qm?f4)ytj6zrw3761K$p4KTsd>L|AxwN9RKJ(3}*DTuzlt!F~M&Q zS1hz%E;ewevu)fdec0^Qt@j5+^pk#hV>L##dINvuvfPOeTC1!_Ak^0v{`J>7@ic>b z1Lw4Mex6<1x9*lf|MG~N;`4X(!NEcEw`a?R+xL`dS*{uVwN3e^Va8szXVOIdVZ+N| ztCSxV%Gf$M%zVhtZzXRlw)FeqVM)7?Jlf)Eeq@!vuM8&x(Ts?T^P_w;6)y{Yp|rCN zT01xKM~Q@{dfA&`MTK(*GfNxG0D{&goX_Z26xr~>pih+K?zRqZ5a;WAMsx0QB-tRK z?c;(XL!T!Hq2X3e zprB}veww0 zRrwpHdmAL4kQBrFaPDOt<_q{b^MlYHrD;r;)#2 zr?o`4Qz8uxyj3cn&-eSvs@>;i>Ek+9w^4#A+qi7< z|EN6BC}!=lFJeqZ26WQq$2*45u~RlxUbUqqqj4UJJ-(g5oaqnGWoKvK5dN{X!8kl$ z`y~}hYTj0hP<0{!drQrrx9$)nVFu&ZyIOqmOIHBcUs1x#TQ`@zeQW>a$^!`1DA-!q zc?n@FR0~Faobf#Wm6R_O`yUnHk-RGxeR#r;f?lXPO`Z#{c^neBZZVfZ#d#Z_e(|ZcfgerR3>8p#O_qN?F+y#F|Fy>RB<%wOS*DJO*aJ&;#Z@0*3lqQUVH69`K7z zf)8~YaG0(FV{mS-5r_6dI%76@sR&#Znvn?=O-=jh$8&6Uwmo}%54*j_oSO`eu;Qdi z1*>&tL8_ZPZCwUoHSCr9HTP?&hxUf?zvHjkkF5v(ul&-!af>y|*up~Sq1LpW_8hmk zH6T({)#X!q<5W({{e9uxdoa8i#RY?G0fx4tY^+G_*Y4v94-dcZ z);yK&#?>eG5r}PN+%(zX$zhee#`mxFv{*hJz%8C}u(j1K%LP8nFj>mdY`d!GQA;t@ z-?WSYHPIw?tzpyGR?1%LxXBQCPp_$;$B;YZ@=C7vIsPx=^gi*WqIVYd_V&INq@+nP zRS4=M&->MGG?nV}1shOSi-MpaY(2Fb>T6k%T-Hx5QvCR}POTb0*d%O z{0h@leBMpE&u(Qfi)`64<#P3ERVidW6loQ=>Eb7Lc6Qyzwyi&< zuV1*hgm8W)sg67`QSkHURTG^5ikroTaGecgh_@Lt=iAP9q$*}TH!ZsPv2YN$pLu}J zo{lF%q+V8ATbtnK1*(m?4=^5N9Rgp6rci1f6yp6quU)$~EvtWa(UFAx8kcvY3v&qa zjr_vG4#SG+P2$9chF${BckzQ+vCHSMa)5r!L;cdvnLQ1-bSd`9lP6w`diq$sF{EAK zkI*nZJuQ3S0P*C>lUXGtB>FFB`j_;K?Cku$KFb~v0Jq3-#KM}wHry(-)+T!A( zd0m0H>)wTVC^`Bt9_wq2xV@YYix?W1cQ|`CIu18;2-lAv2hUh58Z?i;Dk>^EH`n1z zEBf+9NB;Tq=YCtOXxdd?dQ|x>TeegZ|0^#9iD~da>sw|kVcZG+hPdYm0uX%by1Npyn9RK3NHFxH*`hV zP$hPKoghbbj?lf-wezWE<_%v=+oY5q;krMx*p+S+ctPbN@M-CW27h53fOu=)5uRV0 z{P+3!XxpBEOqpHOws@Tf2lf?h9 z$27R4q+3x--8Nv@lc*3aq9^s0mE*t*zgHz~?z_4Bydkh8tHjOwzsWNQO$jeofNB?NVU?~j zj{orbs^IHypTAq)Dt8|1N1C{4Y8pA0AA8{7LC>z+=MS<6k2fw~OrPOd&18&cng0u| z{=HV;9c{U+#M=ttqP-1F&cr>(86HEuxl-yHw!dWiuAtwis0HGx`ZS^_oM z6oaok-l{UHpGMqyV-FDuw%l`Hm=wnU5XD-TjEzTmiZ^{o;Sc9elT3YIF8nR?V_DEf zz&Cqm;&<({DtWhZJKkNRrO1MuCy<5p%kq;Z;nw-v+S`91k&HFX<;}~6`!`ml+5Z5SFqnAYv5vqYDFs^I zzv9*vG~9GL{?weZ0qNld?kIVAd1*KnSnXiTlMZvVHClJ*EChH4kV$60e*Kv|0jwd7 zaIHPF7^ld&bhPxkdESeVbdz+IZmB-$!0)8Ilt=b|OcXLUvu%p|8dbAXviPh;irbMuX`N2)2zl8Z5unfg*VTDrX=zD~2OY6j#`sx|@QFCS z#O^&W-U&O!naj*%6Ze(JW-RUw)=nJVJC?W4x!fXO{xR`Z>fFl+QBfuPLn(@~s8E!7 z9vWcf7ZmK!c)q&w`?INa(G}R;+(pKysg138HzaJ_xKTRox!7Op)5N!Kox!y>nDHg7zUkL2 z-uq_$(lEMjmda6u?T596zO^hYUmsp&<|!B6ps?Y;-+PmNZLXevuOGAn@w;qj7#D|> zwpnlAe%lsZqtdq-1RL*x!t@Edt^?fCB3X+x%8Al!Z5)4eXjvK=smD*`9q3q4i~kkv z`;mqJKR<doUK!owF2@=%6{b%R-szC26#{#}KID5Pa8INj~ae4BT(+e)qo zRt(Eao84>Pf9i17*!WqP#jEsm3#FWljIVbUmCxwtg!as% z;qF&9ohODK4$sPxg{Z8YwWwlJtVw;8`4LyBf640f&m0!wS5#8sDU|=u2cLCJQp73^ zN*WL`Y>K@FXf|#DD+u)q=}f_Hs8YL@X|! z7GX-8nVB=Lq?O#u%7qolk3A$yr%h5lc}}RD85~$C@>3x-VY1 z;JKMSkPPs=d0JYUcgFma2}6ropEhPhTUqr$_PW%qM+g3U-R0}1ZUIkaEXtvDLw!e1 zSv*q=uTp9GJ^;|jyF(L2)nE!_9UmXRws+~T2M@|09^GcXI|itF9T0|sCLgXWv5b?S zO=Xo2v*U#XH{emTn*X>CZ)1Wr@c&#k062dRWQ^OF{*Ji=7j;jZn9700KpzBRoyHi# znB!1?>@gGu*VQq*)5H)#@=AQs_y%cd=Rk#K1S85?q)=}0DkrC|$0SM+D8l9JUAvacGIVSq3Y_-h5w(*?Dt*k9_4Ak zbEG@>LV;mu5Vs)2sDj8l3l3CZzMa7(&q2XbV*;J=P&nx*_bEK~@~qfy_S!~hd^u_j z$OD?#5WH^Mv}utB<|$c@OQy1LdKc2^{*2Bt{}pePCO}*bsCQx9J>mQKs|qIE@TLBb zJFXnx249r`6^-XlpT1jO_H~vxh`~Jb+}VZd8y^GQ-3v6ccq=)>zLAGVAw)J_JHfJ{Nc|X8ejGhLe+b?cDEU7>bjSAXp9!#}GjnnZ zAp3zONwu_}%=K}!o8{|F2nt#S6R~^O(Yq4RG5F+uMa7@5Nk>BJ?`1aj_NK%w&3oh| zTW#7Yq%{D(ZWJ#g3k%AT%ex&M99DX$u$9n?rl(y3dR-REvX*}Kc(JgwrQM^a5;d3K zU#=B=q>(kry6QhyOHo%a&2$gsWUFtIt7s>~9avc|%V|vp(?!p3&1`*JSV%k-Vp0p; z<6T`_Xt?D;c^_3}<$*qzk5DongWi5rIv@0|fON>(q`>igQ`0$%2vQUn0p;U0H;st< zZ+95cuGTVm>HhjAYt?`4qG;~)x~DYU19TEVTWceucy_Hfi5IV5|K(<(si=4r=6tuN zhQ@?7On|s`KQF%t69_9XmmJXU6SQ2Ib-!YH2&(~AtO~i?JWaahZLXv?m=zRfz?7E0 z*45388+wK=ZO3lsa!a?Kxp^Jp2zkDS2F+hf$2EL8iZ4DB66fc?>1(NQ3%TR`zgLkc zIKgxP8+ZeSL1Zjh_$-1ovGK8EA<&n!C&_pEgm_vQcl`i529{^)eF9)Zjsu&ar#KBj z6{lxr#xL#Su!0I9jnOAg|40DQor#T2dRV~DAKOmLXoBNb*|H&H)S?~i`Xu=p!MI|^ zRLExa>eWiTuyMb0_Mds)E&lCrM=9X*eBZ%c`yJmQ&&iZRIkeMm5)=fX_2oo?>`zoa zAKh;yo48cOv*iABkpFzIn?4Vu8L3#=?GOGx#=bkA%K!ae+xwKLq!1E{tn8ANRUt$n zd+!n1>nJNll1+A2_TEkrLiRYeWbeHle%GzupZWd$e&6#);bENnzF)7`bzRTv`Fvgk zgoH?3YVuaUKl(zI@c(xHxD_BB#zW}68pcC7Alqzb$I(J3I4a5vk?15zad2|#!V&{b zrx9}MIQR7QgoPqhKxQb05zNDBCN;S{Be-w%sX8sT|p{a5qS5993g4tKsQ6AUoMntWh2LU4T?Z$>J(gLgy4AOE1ha&|! zIc=DiQ3OK!9&diI_3{}Xk{X1xDDgtLfY8DB+3F7hhEpQ-AN9}sC_&YJFiQCUx>_l- zxH)hBaGT#RO;1Dk~~tgDiJcR?lR05vjQy`GA9-t28(RBEMeC80AMB_<|1xZ9l1yG8ZiPcO}VVYb+QIbO?kZSB!uIU=z~vOfPRN-}bC zgDZB>33VFryu>F9?c=R)L6*=a?j9U;d1NnsIeGRGl-Awt?b^^+hZtm*$thDXyt813 zF#+aqX-jfys!;U$Kqw@qnw;FCmz%5{yHVN^>UMtkWeQ4x}e}N;4yry!e1{ahfV|5 zj~763*H#IQKKPjR(rmD_3(nz>4AmmL?9i@va*iY>il2XSTU@CHzL$*3Bm2X1idEtOPyJ{u zi)yiuoA}4*Po;e`_XxNfz;z}8qnb*zX zP(Nmp2u*CPMt{6x>y8mWo$4jm>BP`<$n$_EX9NVkm09`YMsNpmm;U<>e72Ea6K?mz zo+h=AbLi^s?vrb4>cP{u1^c>h7eo~SG|v5Y;j!XPuFK%(mB7r?b@5MDUT)zGnDmLe z`T6-jZZ`pE!|uE=H?a~m%3JnUT0<|rlyFvzq+x2+P0orvu&qoz^~i8Y8KWDsJ1|)e zmb9-gUb=L{i-(hwHgjHzu(jA~{7uEyueX%;aoEA{t*!4vKgZ~zT4CS zT1~3BbWglA#KGw3QJZv@BH^h# z<>S;5LsqQRXbz{C=O^-*OYA}-JpMA6BYXNyi6aNX{3W*rXazO+?pW%{AM>nn)i|l# zEXQn;%G~MX$gilC47`) z>*n}0^|`!o*CrYdi-9RJ|5t1iH$7}TX1|XV^!D~bs2#_}eU!#BU3|`VAtNo*1x~CU z)gKBsb`}IeXHTc5rm7oPtVcj9rBPUz21JoMPZR72Z+PZvenEl5Yw?~1$n_ypYV>E^ z{O5JTM+4yXUfy}(p!54KBxL)vLhCYU)K&9n^FCl_eIZB&c?gCXnF-UfWnD8HKFh1U z-HFBS?!I7{x*`i8zeyVuj*8AHCrGgC&33$YGgl%^p%W(n4TOf@)R_=r3yZ8%8qIVb z_J)Sv!5L%$hd|nVmwzE46ew4Hzy>ql+9~lcq~{w2!+K$5wo$6G&ZByrLo3CE}LqMjEs3DQ!_Iwa&hGK`GX*K58Z4bVNYN3eLlYi zE%2D!W>o!_r^eQa#e?mbgY9pnMh?S!6Fl=k2Csw^s>OA2)3v3J!P%V%Xt*I7|9fP6 zfO}?U2Fd@x5Mw?nnmFag@i)=YHym?^AR5Xfvyi-1>K#jH*K+0GvA z(4`>huiv9>Y*KDmEpn`|-PgY+eYq-pR{DaEXu8Q(t&F8Ay+w4%PZ`0F{tsxI-eJ2* z6*5QSsL^N^&zvpGL5xS;oar84o`W~@r@N@H;EP^9_YkG#}VT zJ+qOA9H)pztftkn^osc^h^iEBsXrwj&_>o_NY~4^A8X9@8*>wo$LsWj^ zW`*-`>aV(X<;;AB^dl?4q|DgF#6`8(mNGNgq&&09#@d=TByD_}7gn*-e`1$K=LV$9qI}Ebs54JYKDU??tZ%K`!`q)Z zU|*V(c$#KvX1*x0z1!%E#E0k*H^K!B|4}<{WWIW?pCh>+!Km&%_mMwTr!sR986PK72`0 zPY|d0W;ur~t*5vPkEwiY^~{7hLvwxF%Nb2)rjRWs`{!Ri+s&`8ZY(%aMX;OQe<4yH z*@r(>!Sn9X_FagJgbHFiLuN9twrWD_kQBY|?KI9ge(4q*GttfV> zn5?xsr}4}$p)j}6`{imSE3WnyHZ}#Jyi`z{?{K1=WwYIrf)PF$1a|YwL=31`vW7M5 zN2!UK+S=QHso_uKcUbi1)(QdNT;o@C8_KJBaCp1V_wJE&ninTxX2Jhk4B!@- zT-!Lpp^yz+LLhSuC=k2F$@*?=Y<$ZG;j>ffVid}{+K+;{!WiC2$ zjtA8$Tl@{ASAaJ$pNl<5FZBx&n#%HR{NZpe8J8A?%i~~T$#nOwlXMo4Ar5ySqtGZa zaBvz2U3=iOh2Xcz56Qc-8wF?)$ne-@Kj7Nr`pqd}UMX9xIe2^M_yyozz8dIat2in6zUq z{M?rpJEtBT?0?phHe7lJ87Be%dP#UoGn`_p$+5DJg;E3*J*BaXA|kU(cT9F{r0|sd z)&}LM2~m;?_Tt6Oj3~RH`1os3*TkIva4z#0qsN14ksh&?ZFUFs5iV4mEMA>yJ`2iF z`m7P0R%^4h&z?OS5*!xtfh3BR$EYHx49bIQ;I?@U+Mnhn7^ung?I8h`~! zhze(5qLoT6ZRdWNG7Awo%fvHuYB+Lf7i^%F?rf3Z|4RVYx7nC`b{D1`o-#s`Xm5x} z77ZN~Htw;}Tl6q#f(@^6G29?JXEFvobc}ONAo`)YW%xzKC&~}Sf+-x=9#R$JScaMh<&T*F>yX^fpKl%vI1jsQlEQnNkS3_GX%Z1m74P10PBaNZy6IXYFS_BB!)HF0 zJu`hb@fCG*jGzUKoox@Ygh_zOp-@mzuElm zSNFZq6QN9uH-_IZeop@s-vB__0EO#Xy@{90%E78d#a^4n!7z8v!T#i!?;bnjfbI8P z!NN^<_5GhyJn0D~Ux5*%4PCL-mIfFwoDblGrY*uelinZ1?AobE-?psEdIlU}6%i44 zJB|I7P#0DDV=fzVp)oNrVJ%>JbOC$!h$h`(*A?i&8;~KXa!5~d_vRY~j*pFPS@6)& z(Qyk1m_tFx(QEhYZF3r18sh0D>3A+yXF?0?pASS!IMm0e|hSnLKI(bM8l=jfc zDZBzPw?az&#zUa^{`euah=EdLuRLpU#M9Gr$gC&(>$QN_PZbn)I02R0C+ng+5QlTp zG4bDuq<_8X*>A*t!=CVMSJ#NWAt8ANy$=L+G4YIUC^l%JBqt}&15l327FM4_Z)fM2 z%&iXjdSn??SIJkd6?qlq=PTLSZ3a2Oqnm*lUV2oQ_7ye(WS0q7Xgn+9dHfbf#V|6E zymJ>Mpmbe}i-?Z5lv5QaR(WgcGlcoC|k*2zWtn5!cef=bCaJQnG zvGHeY>XhBhHhbh*{j>3SS{KrB5l&$mI(QnI%=lkP&YOQf z^opU%DUX)wFo|}oILdu=@DrtZ-Nbdat3XAI#;%1bgMF z$|iEy@zq>>D&OE$+Cdq6j-0gc-NZ?%q@^={i-whR1b19Y(~!SB!E#)a_H-N>>hhzc z7L`1giFRk}j9kc#$Q8X!;_$NNrtS%#UgM7tqnz<4KSKro?G^(QQ$ARDI&5v55??*% zy7+j>%VXFYI3+m87b{#7;q>LgYOz>)-)ncC=;Rn}YdHXPAYYqGNqk-I@nbERu(zfa z_YR(E-|t~q>}_J#)l4tZDZ_I>KKJ2Hv*e_PE~5Mk&{w` zQ>5n705wLk&x0yI0)HGIA#RUDsa+gLQN&eIL@a!v%9NJoMoWCJgF=B#(KrJijrvVd z8ZN)#1h^^2y(Qa}x?GT?KkdKno=*Ictp{r&;(l!3!rFA;{5>U*VXk~=LA+#(V7PB8 zb^MNLVyyZJe>fL*Z>h;VUb4XNZsn3z^X|k|kljFyy%tYUP*;yGp1gz?@=CZdOSR+| zZiioNgcQR2evvSTux6_@S@KW(s1D*!)Tm+ETZk_%|7{UH{2$*N8&}yqBk>bG>d}_9uQk0#rCbN()^8ht_V%B~_`)q? zy5Onraa!?j3` zqVYav1XnZrIo)|w0ZHgV3$;_c6dv*WzD>XcsYuJ>%s6M$Fu(f2_FZ@mXpkQLlAxX3SGUb?yl&K=v?HO7o_ zcz(UF1W>0>^FI)Md97m>B7eF|e&?U8(oO6Wxq0U_!)cF6I1qo@27v~IC;W!Ij?kb7 zsQ~Nj$=W54`7up`HUpyyR{)gDbg7j@vZD4q7N#4IcYjzCcuYDZ`7&CU>S0T^p*|Q_ zy9LuQ8mz1u*_u}ptWT;K8-LSI2t4pgzHhM41jn$OXQIjLk(_`25cIJQ za3*Qe%~{}{xQ>=4{UxI!seY0tODCh<>3-cl!lskls7Ehb;2r|Jp*jA&p{WQ7)#q`L z3E6Hmh0a5HvOSE1aLbXr?C7w}lTq-8m6Udx1XLqGHgYvUO0VBAdm4o@1?Xr94W}q; z3>^IeWk-~5p<<_g1HZfNp_OCRN#4vPBqTeVwY~JB3D9yx28Z__bng*gk8Aaten|>W zg-a_c!#g3~A&i_NYS1%+^2ABN9AFW7^@P?lHai5@)4iJ$QEm31@~%K|eF}cZ&N>{z zRxE!KTeo)WoyxhlHO~A7{mv?PR|DYS=pW}V#gl=Uy$=<1vF_Xf+I{)9e|tJ$3L^@9TOqs*9A(;kdea|<)tF@ zZjmi$OVDI-LFs9^cNfu}yX(YI&}3Ut*iT&`A*U#;@D|iH^ShKDm)RW+Iyt8XPQ)x4 z$FYc{DKbc*_vKeuBbS7l_hT$z(@k6r2%x_@8@Mx<#L^2BjOMYdM>I2s9409QH_x0o zqXbP7LTJq`S%IsLf|{BcmASG{R1a4sO>r~qLQgst|ei$%(p%)DLm+H8S~xm}!; zbe$C(smH;0=u5o#TY`)I^FNF1&@bG-==P=>4{3U?`5MlKWPS{eEtfrjdP%BCfj8<_82 zr*@e!DP7|ClUx-D4!T!Kp_!<;+%!(6x3U$U`B>uV(=INo37%#pF=gD+8z?A%F&V=S z8m>WT*H(b|s%)fOShH5@E9pH>vURJZZ6h^vQEIYy&C?m7-H(aQ$pJyIl^(s`GO(*gLZscrc-5Re1Wpp`^Y<_P19?1Fk@=>x}8><_Oyk;Zf zXn%eT#^X-v6~C;2j&a!oTEua7RqGOq>JmAPOpJgTq(ERs!-mu^!*l!4KcEX?!%f(0 z(w(kzHS~R)lXHE@tl*ao`F!Rs<+@gY^*ex+72F5*v?cuy%Az7ja>^EB_U!hW(0iv? z*L$DF*jzl$gEK<7B1*g?WaHr7J~y2lQy3CL0`phD1sSdNKEfJXyI488d3jCmj6y-e zrzsM%3}6b5cLHQy1b9jEh91r5I8G=}l`n(ik}~v>nS-)FLV`I9=+f#(-l!Hp%WVd+ zH^+o$Z-Nn%$0>~|o(PbP^p7`&W)v27*D(-@T1!6(t3~)7FpqFq3)Mz+!ub35?+>m$ z5n09F$;V)Z4+MZ!cFN{Bsy>WaRRqJp;7fDkMjb5qdGCL-4a@#DrQbAdolpvxsSN2* zA2bC>fra48QA*D#a)j(=pr_aC_}bUU4K=yiELq~%#9b}JpLWmX{Cabf71qp5KtS;P z;MCOfU&G6w!w{&Rc>!<_UPucZ;X5Cb#Cz+lE5xzJYrSSWlSR*&Cy`yPQPgQu-+J{U zypO!cuf0mAi9hB53%e1>C!X;y^27M``Z-qF^C+<}H%_2rXd$p2--&3WJT!}z_Ci_Y5iFNGaN>}%KX2)IaO&Te<% zz8c?-4hhi*QKf(sH3c-gvgALX#&Q~*PimX(5~BFhm+;&d+CTPFqO|P2Yw}-7Kvk+9 z5)`y`M<)(QAkY@VcpJQa#Q^la3c=$VV-piY&wC^MU6b3awQ$2gZe;C}7M>K1n(Q ); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/playground/page.tsx b/ui/litellm-dashboard/src/app/(dashboard)/playground/page.tsx index 693dc6b20e..2b4b4ace49 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/playground/page.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/playground/page.tsx @@ -8,8 +8,6 @@ import ComplianceUI from "@/components/playground/complianceUI/ComplianceUI"; import { TabGroup, TabList, Tab, TabPanels, TabPanel } from "@tremor/react"; import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; import { fetchProxySettings } from "@/utils/proxyUtils"; -import { useUIConfig } from "@/app/(dashboard)/hooks/uiConfig/useUIConfig"; -import { MessageOutlined, CloseOutlined } from "@ant-design/icons"; interface ProxySettings { PROXY_BASE_URL?: string; @@ -19,12 +17,6 @@ interface ProxySettings { export default function PlaygroundPage() { const { accessToken, userRole, userId, disabledPersonalKeyCreation, token } = useAuthorized(); const [proxySettings, setProxySettings] = useState(undefined); - const [chatBannerDismissed, setChatBannerDismissed] = useState(false); - const { data: uiConfig } = useUIConfig(); - const uiRoot = uiConfig?.server_root_path && uiConfig.server_root_path !== "/" - ? uiConfig.server_root_path.replace(/\/+$/, "") - : ""; - const chatHref = `${uiRoot}/ui/chat`; useEffect(() => { const initializeProxySettings = async () => { @@ -44,64 +36,6 @@ export default function PlaygroundPage() { return (
- {!chatBannerDismissed && ( -
- - New - - - Chat UI - {" "}— a ChatGPT-like interface for your users to chat with AI models and MCP tools. Share it with your team. - - - Open Chat UI → - - -
- )} Chat From 0ecced9780a1cb7b0d6c5211ddb8ce8966a428da Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Wed, 18 Mar 2026 19:52:59 -0700 Subject: [PATCH 287/289] fix: fix responses cost calc --- litellm/litellm_core_utils/litellm_logging.py | 14 ++++ litellm/proxy/_new_secret_config.yaml | 63 +++++++-------- .../test_litellm_logging.py | 76 +++++++++++++++++++ 3 files changed, 117 insertions(+), 36 deletions(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index 826396a70d..4e63dd7076 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -1455,6 +1455,20 @@ class Logging(LiteLLMLoggingBaseClass): ): # use model_id if not already set router_model_id = hidden_params["model_id"] + # Fallback: extract router_model_id from litellm_params when not available + # from the result object. ResponsesAPIResponse objects (used by /v1/responses + # streaming) don't carry _hidden_params["model_id"] like ModelResponse does. + if router_model_id is None and hasattr(self, "litellm_params"): + for metadata_key in ("litellm_metadata", "metadata"): + _metadata: dict = ( + self.litellm_params.get(metadata_key, {}) or {} + ) + _model_info: dict = _metadata.get("model_info", {}) or {} + _model_id = _model_info.get("id") + if _model_id is not None: + router_model_id = _model_id + break + ## RESPONSE COST ## custom_pricing = use_custom_pricing_for_model( litellm_params=( diff --git a/litellm/proxy/_new_secret_config.yaml b/litellm/proxy/_new_secret_config.yaml index 508c1c9465..604e7d5f41 100644 --- a/litellm/proxy/_new_secret_config.yaml +++ b/litellm/proxy/_new_secret_config.yaml @@ -1,41 +1,32 @@ model_list: - - model_name: gpt-3.5-turbo - litellm_params: - model: openai/gpt-3.5-turbo - api_key: os.environ/OPENAI_API_KEY - - model_name: gpt-4o - litellm_params: - model: openai/gpt-4o - api_key: os.environ/OPENAI_API_KEY - - model_name: claude-sonnet-4-5-20250929 - litellm_params: - model: anthropic/claude-sonnet-4-5-20250929 - - model_name: gpt-4.1-mini + + # OpenAI model for /v1/chat/completions test — 200x custom pricing + - model_name: "gpt-4.1-mini" litellm_params: model: openai/gpt-4.1-mini - - model_name: gpt-5-mini + api_key: os.environ/OPENAI_API_KEY + model_info: + id: gpt-4.1-mini-custom-pricing + input_cost_per_token: 0.00004 # 100x standard ($0.40/1M = $0.0000004) + output_cost_per_token: 0.00016 # 100x standard ($1.60/1M = $0.0000016) + + # OpenAI model for /v1/responses test — 100x custom pricing + - model_name: "gpt-5" litellm_params: - model: openai/gpt-5-mini - - model_name: custom_litellm_model + model: openai/gpt-5 + api_key: os.environ/OPENAI_API_KEY + model_info: + id: gpt-5-custom-pricing + mode: "chat" + input_cost_per_token: 125 # 100x standard ($1.25/1M = $0.00000125) + output_cost_per_token: 10 # 100x standard ($10.00/1M = $0.00001) + + # Anthropic model for /v1/messages test — 100x custom pricing + - model_name: "claude-sonnet-4-20250514" litellm_params: - model: litellm_agent/claude-sonnet-4-5-20250929 - litellm_system_prompt: "Be a helpful assistant." - - -guardrails: - - guardrail_name: "tool_policy" - litellm_params: - guardrail: tool_policy - mode: [pre_call, post_call] - default_on: true - -mcp_servers: - my_http_server: - url: "http://0.0.0.0:8001/mcp" - transport: "http" - description: "My custom MCP server" - available_on_public_internet: true - -general_settings: - store_model_in_db: true - store_prompts_in_spend_logs: true + model: anthropic/claude-sonnet-4-20250514 + api_key: os.environ/ANTHROPIC_API_KEY + model_info: + id: claude-sonnet-4-custom-pricing + input_cost_per_token: 0.0003 # 100x standard ($0.000003) + output_cost_per_token: 0.0015 # 100x standard ($0.000015) \ No newline at end of file diff --git a/tests/test_litellm/litellm_core_utils/test_litellm_logging.py b/tests/test_litellm/litellm_core_utils/test_litellm_logging.py index 6e9b72e96c..fe4851283f 100644 --- a/tests/test_litellm/litellm_core_utils/test_litellm_logging.py +++ b/tests/test_litellm/litellm_core_utils/test_litellm_logging.py @@ -180,6 +180,82 @@ def test_use_custom_pricing_not_detected_litellm_metadata_no_pricing(): assert use_custom_pricing_for_model(litellm_params) is False +def test_response_cost_calculator_uses_router_model_id_from_litellm_metadata(): + """_response_cost_calculator should extract router_model_id from + litellm_params.litellm_metadata.model_info.id when the result object + does not carry _hidden_params (e.g. ResponsesAPIResponse from /v1/responses + streaming). Regression test for custom pricing on streaming responses.""" + import litellm + from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj + from litellm.types.llms.openai import ResponsesAPIResponse + + custom_model_id = "gpt-5-custom-pricing" + custom_input_cost = 125.0 + custom_output_cost = 10.0 + + litellm.register_model( + model_cost={ + custom_model_id: { + "input_cost_per_token": custom_input_cost, + "output_cost_per_token": custom_output_cost, + "max_tokens": 128000, + "max_input_tokens": 128000, + "max_output_tokens": 16384, + "litellm_provider": "openai", + } + } + ) + + try: + logging_obj = LiteLLMLoggingObj( + model="gpt-5", + messages=[{"role": "user", "content": "Hi"}], + stream=True, + call_type="aresponses", + start_time=time.time(), + litellm_call_id="test-123", + function_id="test-fn", + ) + + logging_obj.update_environment_variables( + model="gpt-5", + user="", + optional_params={}, + litellm_params={ + "api_base": "", + "litellm_metadata": { + "model_info": { + "id": custom_model_id, + "input_cost_per_token": custom_input_cost, + "output_cost_per_token": custom_output_cost, + }, + }, + }, + ) + + response_obj = ResponsesAPIResponse( + id="resp_abc", + created_at=1234567890, + model="gpt-5", + output=[], + usage={ + "input_tokens": 10, + "output_tokens": 5, + "total_tokens": 15, + }, + ) + + cost = logging_obj._response_cost_calculator(result=response_obj) + + assert cost is not None, "Cost should not be None" + expected_cost = (10 * custom_input_cost) + (5 * custom_output_cost) + assert cost == pytest.approx( + expected_cost + ), f"Expected {expected_cost}, got {cost}" + finally: + litellm.model_cost.pop(custom_model_id, None) + + class TestUpdateFromKwargs: """Tests for the update_from_kwargs convenience wrapper.""" From f7803d2d6d337d94faf34bac82d9441b52507c2f Mon Sep 17 00:00:00 2001 From: joereyna Date: Wed, 18 Mar 2026 21:21:07 -0700 Subject: [PATCH 288/289] chore: regenerate poetry.lock to unblock CI (pyproject.toml content hash drift) --- poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index e3b083d778..dc25864442 100644 --- a/poetry.lock +++ b/poetry.lock @@ -8018,4 +8018,4 @@ utils = ["numpydoc"] [metadata] lock-version = "2.1" python-versions = ">=3.9,<4.0" -content-hash = "eda34dfd8b35474beffee18893d6782c7b3d0d3d2c610f66237eb97176f43527" +content-hash = "2cf958f1a04fd5f1ab0e5cfc33bdbf441b518ed6c82d0f2546bf64cd3d2f89be" From df38fbcc973b269d70d6c6c6891d444d70e9f04d Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 19 Mar 2026 04:47:30 +0000 Subject: [PATCH 289/289] docs: add Contributing to Guardrails section to Guardrail Providers sidebar - Add 'Contributing to Guardrails' category with links to: - Generic Guardrail API (integrate without PR) - Adding a New Guardrail Integration tutorial - Adding Guardrail Support to Endpoints - Add 'Team Bring-Your-Own Guardrails' link for team BYOG workflow These docs existed but were only accessible from the 'LiteLLM AI Gateway' sidebar. Now they're also accessible when browsing the 'Guardrail Providers' section. Co-authored-by: Krish Dholakia --- docs/my-website/sidebars.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index 7db72da276..4c0471fb8f 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -48,6 +48,20 @@ const sidebars = { slug: "/guardrail_providers" }, items: [ + { + type: "category", + label: "Contributing to Guardrails", + items: [ + "adding_provider/generic_guardrail_api", + "adding_provider/simple_guardrail_tutorial", + "adding_provider/adding_guardrail_support", + ] + }, + { + type: "doc", + id: "proxy/guardrails/team_based_guardrails", + label: "Team Bring-Your-Own Guardrails", + }, ...[ "proxy/guardrails/qualifire", "proxy/guardrails/aim_security",

k$ez1@E~m^s%tb)ASor$q>&w5 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 !cQ_M?K18la(+*6wh?&YVlu2i)UN!Xx{I_ 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 literal 0 HcmV?d00001 diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index 071f80de02..7db72da276 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -672,6 +672,7 @@ const sidebars = { "mcp_control", "mcp_cost", "mcp_guardrail", + "mcp_zero_trust", "mcp_troubleshoot", ] }, diff --git a/litellm/__init__.py b/litellm/__init__.py index 51c6683861..7f72e0b0e8 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -1465,9 +1465,15 @@ if TYPE_CHECKING: from .llms.petals.completion.transformation import PetalsConfig as PetalsConfig from .llms.ollama.chat.transformation import OllamaChatConfig as OllamaChatConfig from .llms.ollama.completion.transformation import OllamaConfig as OllamaConfig - from .llms.sagemaker.completion.transformation import SagemakerConfig as SagemakerConfig - from .llms.sagemaker.chat.transformation import SagemakerChatConfig as SagemakerChatConfig - from .llms.sagemaker.nova.transformation import SagemakerNovaConfig as SagemakerNovaConfig + from .llms.sagemaker.completion.transformation import ( + SagemakerConfig as SagemakerConfig, + ) + from .llms.sagemaker.chat.transformation import ( + SagemakerChatConfig as SagemakerChatConfig, + ) + from .llms.sagemaker.nova.transformation import ( + SagemakerNovaConfig as SagemakerNovaConfig, + ) from .llms.cohere.chat.transformation import CohereChatConfig as CohereChatConfig from .llms.anthropic.experimental_pass_through.messages.transformation import ( AnthropicMessagesConfig as AnthropicMessagesConfig, diff --git a/litellm/_logging.py b/litellm/_logging.py index 5de9fbb355..18c3bcb7e8 100644 --- a/litellm/_logging.py +++ b/litellm/_logging.py @@ -17,7 +17,9 @@ if set_verbose is True: "`litellm.set_verbose` is deprecated. Please set `os.environ['LITELLM_LOG'] = 'DEBUG'` for debug logs." ) -_ENABLE_SECRET_REDACTION = os.getenv("LITELLM_DISABLE_REDACT_SECRETS", "").lower() != "true" +_ENABLE_SECRET_REDACTION = ( + os.getenv("LITELLM_DISABLE_REDACT_SECRETS", "").lower() != "true" +) _REDACTED = "REDACTED" @@ -199,7 +201,9 @@ class JsonFormatter(Formatter): json_record[key] = value if record.exc_info: - json_record["stacktrace"] = record.exc_text or self.formatException(record.exc_info) + json_record["stacktrace"] = record.exc_text or self.formatException( + record.exc_info + ) return safe_dumps(json_record) diff --git a/litellm/cost_calculator.py b/litellm/cost_calculator.py index e0e1e35b94..ee3c344169 100644 --- a/litellm/cost_calculator.py +++ b/litellm/cost_calculator.py @@ -1189,7 +1189,9 @@ def completion_cost( # noqa: PLR0915 and _usage["prompt_tokens_details"] != {} and _usage["prompt_tokens_details"] ): - prompt_tokens_details = _usage.get("prompt_tokens_details") or {} + prompt_tokens_details = ( + _usage.get("prompt_tokens_details") or {} + ) cache_read_input_tokens = prompt_tokens_details.get( "cached_tokens", 0 ) @@ -1515,7 +1517,9 @@ def completion_cost( # noqa: PLR0915 if custom_llm_provider == "azure_ai": model_for_additional_costs = request_model_for_cost if completion_response is not None: - hidden_params = getattr(completion_response, "_hidden_params", None) or {} + hidden_params = ( + getattr(completion_response, "_hidden_params", None) or {} + ) hidden_model = hidden_params.get("model") or hidden_params.get( "litellm_model_name" ) diff --git a/litellm/integrations/focus/destinations/factory.py b/litellm/integrations/focus/destinations/factory.py index 01ea6ca9cb..706e10624c 100644 --- a/litellm/integrations/focus/destinations/factory.py +++ b/litellm/integrations/focus/destinations/factory.py @@ -59,17 +59,14 @@ class FocusDestinationFactory: return {k: v for k, v in resolved.items() if v is not None} if provider == "vantage": resolved = { - "api_key": overrides.get("api_key") - or os.getenv("VANTAGE_API_KEY"), + "api_key": overrides.get("api_key") or os.getenv("VANTAGE_API_KEY"), "integration_token": overrides.get("integration_token") or os.getenv("VANTAGE_INTEGRATION_TOKEN"), "base_url": overrides.get("base_url") or os.getenv("VANTAGE_BASE_URL", "https://api.vantage.sh"), } if not resolved.get("api_key"): - raise ValueError( - "VANTAGE_API_KEY must be provided for Vantage exports" - ) + raise ValueError("VANTAGE_API_KEY must be provided for Vantage exports") if not resolved.get("integration_token"): raise ValueError( "VANTAGE_INTEGRATION_TOKEN must be provided for Vantage exports" diff --git a/litellm/integrations/langfuse/langfuse_prompt_management.py b/litellm/integrations/langfuse/langfuse_prompt_management.py index 03a93cd988..bea027aa63 100644 --- a/litellm/integrations/langfuse/langfuse_prompt_management.py +++ b/litellm/integrations/langfuse/langfuse_prompt_management.py @@ -340,9 +340,9 @@ class LangfusePromptManagement(LangFuseLogger, PromptManagementBase, CustomLogge ) status_message = str(kwargs.get("exception", "Unknown error")) if standard_logging_object is not None: - status_message = standard_logging_object.get( - "error_str", None - ) or status_message + status_message = ( + standard_logging_object.get("error_str", None) or status_message + ) langfuse_logger_to_use.log_event_on_langfuse( start_time=start_time, end_time=end_time, diff --git a/litellm/integrations/vantage/vantage_logger.py b/litellm/integrations/vantage/vantage_logger.py index 6689d93274..e0942472be 100644 --- a/litellm/integrations/vantage/vantage_logger.py +++ b/litellm/integrations/vantage/vantage_logger.py @@ -83,7 +83,9 @@ class VantageLogger(FocusLogger): verbose_logger.debug( "VantageLogger initialized (integration_token=%s)", - resolved_token[:4] + "***" if resolved_token and len(resolved_token) > 4 else "***", + resolved_token[:4] + "***" + if resolved_token and len(resolved_token) > 4 + else "***", ) async def initialize_focus_export_job(self) -> None: @@ -128,9 +130,7 @@ class VantageLogger(FocusLogger): callback_type=VantageLogger ) if not vantage_loggers: - verbose_logger.debug( - "No Vantage logger registered; skipping scheduler" - ) + verbose_logger.debug("No Vantage logger registered; skipping scheduler") return vantage_logger = cast(VantageLogger, vantage_loggers[0]) diff --git a/litellm/litellm_core_utils/default_encoding.py b/litellm/litellm_core_utils/default_encoding.py index 24533feecc..f704ba568d 100644 --- a/litellm/litellm_core_utils/default_encoding.py +++ b/litellm/litellm_core_utils/default_encoding.py @@ -26,7 +26,9 @@ if custom_cache_dir: else: cache_dir = filename -os.environ["TIKTOKEN_CACHE_DIR"] = cache_dir # use local copy of tiktoken b/c of - https://github.com/BerriAI/litellm/issues/1071 +os.environ[ + "TIKTOKEN_CACHE_DIR" +] = cache_dir # use local copy of tiktoken b/c of - https://github.com/BerriAI/litellm/issues/1071 import tiktoken import time @@ -48,4 +50,3 @@ for attempt in range(_max_retries): # Exponential backoff with jitter to reduce collision probability delay = _retry_delay * (2**attempt) + random.uniform(0, 0.1) time.sleep(delay) - diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index 01565b9947..826396a70d 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -352,9 +352,9 @@ class Logging(LiteLLMLoggingBaseClass): ) self.function_id = function_id self.streaming_chunks: List[Any] = [] # for generating complete stream response - self.sync_streaming_chunks: List[Any] = ( - [] - ) # for generating complete stream response + self.sync_streaming_chunks: List[ + Any + ] = [] # for generating complete stream response self.log_raw_request_response = log_raw_request_response # Initialize dynamic callbacks @@ -782,9 +782,9 @@ class Logging(LiteLLMLoggingBaseClass): prompt_spec=prompt_spec, dynamic_callback_params=dynamic_callback_params, ): - self.model_call_details["prompt_integration"] = ( - logger.__class__.__name__ - ) + self.model_call_details[ + "prompt_integration" + ] = logger.__class__.__name__ return logger except Exception: # If check fails, continue to next logger @@ -852,9 +852,9 @@ class Logging(LiteLLMLoggingBaseClass): if anthropic_cache_control_logger := AnthropicCacheControlHook.get_custom_logger_for_anthropic_cache_control_hook( non_default_params ): - self.model_call_details["prompt_integration"] = ( - anthropic_cache_control_logger.__class__.__name__ - ) + self.model_call_details[ + "prompt_integration" + ] = anthropic_cache_control_logger.__class__.__name__ return anthropic_cache_control_logger ######################################################### @@ -866,9 +866,9 @@ class Logging(LiteLLMLoggingBaseClass): internal_usage_cache=None, llm_router=None, ) - self.model_call_details["prompt_integration"] = ( - vector_store_custom_logger.__class__.__name__ - ) + self.model_call_details[ + "prompt_integration" + ] = vector_store_custom_logger.__class__.__name__ # Add to global callbacks so post-call hooks are invoked if ( vector_store_custom_logger @@ -928,9 +928,9 @@ class Logging(LiteLLMLoggingBaseClass): model ): # if model name was changes pre-call, overwrite the initial model call name with the new one self.model_call_details["model"] = model - self.model_call_details["litellm_params"]["api_base"] = ( - self._get_masked_api_base(additional_args.get("api_base", "")) - ) + self.model_call_details["litellm_params"][ + "api_base" + ] = self._get_masked_api_base(additional_args.get("api_base", "")) def pre_call(self, input, api_key, model=None, additional_args={}): # noqa: PLR0915 # Log the exact input to the LLM API @@ -959,10 +959,10 @@ class Logging(LiteLLMLoggingBaseClass): try: # [Non-blocking Extra Debug Information in metadata] if turn_off_message_logging is True: - _metadata["raw_request"] = ( - "redacted by litellm. \ + _metadata[ + "raw_request" + ] = "redacted by litellm. \ 'litellm.turn_off_message_logging=True'" - ) else: curl_command = self._get_request_curl_command( api_base=additional_args.get("api_base", ""), @@ -973,34 +973,34 @@ class Logging(LiteLLMLoggingBaseClass): _metadata["raw_request"] = str(curl_command) # split up, so it's easier to parse in the UI - self.model_call_details["raw_request_typed_dict"] = ( - RawRequestTypedDict( - raw_request_api_base=str( - additional_args.get("api_base") or "" - ), - raw_request_body=self._get_raw_request_body( - additional_args.get("complete_input_dict", {}) - ), - # NOTE: setting ignore_sensitive_headers to True will cause - # the Authorization header to be leaked when calls to the health - # endpoint are made and fail. - raw_request_headers=self._get_masked_headers( - additional_args.get("headers", {}) or {}, - ), - error=None, - ) + self.model_call_details[ + "raw_request_typed_dict" + ] = RawRequestTypedDict( + raw_request_api_base=str( + additional_args.get("api_base") or "" + ), + raw_request_body=self._get_raw_request_body( + additional_args.get("complete_input_dict", {}) + ), + # NOTE: setting ignore_sensitive_headers to True will cause + # the Authorization header to be leaked when calls to the health + # endpoint are made and fail. + raw_request_headers=self._get_masked_headers( + additional_args.get("headers", {}) or {}, + ), + error=None, ) except Exception as e: - self.model_call_details["raw_request_typed_dict"] = ( - RawRequestTypedDict( - error=str(e), - ) + self.model_call_details[ + "raw_request_typed_dict" + ] = RawRequestTypedDict( + error=str(e), ) - _metadata["raw_request"] = ( - "Unable to Log \ + _metadata[ + "raw_request" + ] = "Unable to Log \ raw request: {}".format( - str(e) - ) + str(e) ) if getattr(self, "logger_fn", None) and callable(self.logger_fn): try: @@ -1301,13 +1301,13 @@ class Logging(LiteLLMLoggingBaseClass): for callback in callbacks: try: if isinstance(callback, CustomLogger): - response: Optional[MCPPostCallResponseObject] = ( - await callback.async_post_mcp_tool_call_hook( - kwargs=kwargs, - response_obj=post_mcp_tool_call_response_obj, - start_time=start_time, - end_time=end_time, - ) + response: Optional[ + MCPPostCallResponseObject + ] = await callback.async_post_mcp_tool_call_hook( + kwargs=kwargs, + response_obj=post_mcp_tool_call_response_obj, + start_time=start_time, + end_time=end_time, ) ###################################################################### # if any of the callbacks modify the response, use the modified response @@ -1502,9 +1502,9 @@ class Logging(LiteLLMLoggingBaseClass): verbose_logger.debug( f"response_cost_failure_debug_information: {debug_info}" ) - self.model_call_details["response_cost_failure_debug_information"] = ( - debug_info - ) + self.model_call_details[ + "response_cost_failure_debug_information" + ] = debug_info return None try: @@ -1530,9 +1530,9 @@ class Logging(LiteLLMLoggingBaseClass): verbose_logger.debug( f"response_cost_failure_debug_information: {debug_info}" ) - self.model_call_details["response_cost_failure_debug_information"] = ( - debug_info - ) + self.model_call_details[ + "response_cost_failure_debug_information" + ] = debug_info return None @@ -1688,9 +1688,9 @@ class Logging(LiteLLMLoggingBaseClass): result=logging_result ) - self.model_call_details["standard_logging_object"] = ( - self._build_standard_logging_payload(logging_result, start_time, end_time) - ) + self.model_call_details[ + "standard_logging_object" + ] = self._build_standard_logging_payload(logging_result, start_time, end_time) if ( standard_logging_payload := self.model_call_details.get( @@ -1768,9 +1768,9 @@ class Logging(LiteLLMLoggingBaseClass): end_time = datetime.datetime.now() if self.completion_start_time is None: self.completion_start_time = end_time - self.model_call_details["completion_start_time"] = ( - self.completion_start_time - ) + self.model_call_details[ + "completion_start_time" + ] = self.completion_start_time self.model_call_details["log_event_type"] = "successful_api_call" self.model_call_details["end_time"] = end_time @@ -1807,10 +1807,10 @@ class Logging(LiteLLMLoggingBaseClass): end_time=end_time, ) elif isinstance(result, dict) or isinstance(result, list): - self.model_call_details["standard_logging_object"] = ( - self._build_standard_logging_payload( - result, start_time, end_time - ) + self.model_call_details[ + "standard_logging_object" + ] = self._build_standard_logging_payload( + result, start_time, end_time ) if ( standard_logging_payload := self.model_call_details.get( @@ -1819,9 +1819,9 @@ class Logging(LiteLLMLoggingBaseClass): ) is not None: emit_standard_logging_payload(standard_logging_payload) elif standard_logging_object is not None: - self.model_call_details["standard_logging_object"] = ( - standard_logging_object - ) + self.model_call_details[ + "standard_logging_object" + ] = standard_logging_object else: self.model_call_details["response_cost"] = None @@ -1979,17 +1979,17 @@ class Logging(LiteLLMLoggingBaseClass): verbose_logger.debug( "Logging Details LiteLLM-Success Call streaming complete" ) - self.model_call_details["complete_streaming_response"] = ( - complete_streaming_response - ) - self.model_call_details["response_cost"] = ( - self._response_cost_calculator(result=complete_streaming_response) - ) + self.model_call_details[ + "complete_streaming_response" + ] = complete_streaming_response + self.model_call_details[ + "response_cost" + ] = self._response_cost_calculator(result=complete_streaming_response) ## STANDARDIZED LOGGING PAYLOAD - self.model_call_details["standard_logging_object"] = ( - self._build_standard_logging_payload( - complete_streaming_response, start_time, end_time - ) + self.model_call_details[ + "standard_logging_object" + ] = self._build_standard_logging_payload( + complete_streaming_response, start_time, end_time ) if ( standard_logging_payload := self.model_call_details.get( @@ -2323,10 +2323,10 @@ class Logging(LiteLLMLoggingBaseClass): ) else: if self.stream and complete_streaming_response: - self.model_call_details["complete_response"] = ( - self.model_call_details.get( - "complete_streaming_response", {} - ) + self.model_call_details[ + "complete_response" + ] = self.model_call_details.get( + "complete_streaming_response", {} ) result = self.model_call_details["complete_response"] openMeterLogger.log_success_event( @@ -2350,10 +2350,10 @@ class Logging(LiteLLMLoggingBaseClass): ) else: if self.stream and complete_streaming_response: - self.model_call_details["complete_response"] = ( - self.model_call_details.get( - "complete_streaming_response", {} - ) + self.model_call_details[ + "complete_response" + ] = self.model_call_details.get( + "complete_streaming_response", {} ) result = self.model_call_details["complete_response"] @@ -2492,9 +2492,9 @@ class Logging(LiteLLMLoggingBaseClass): if complete_streaming_response is not None: print_verbose("Async success callbacks: Got a complete streaming response") - self.model_call_details["async_complete_streaming_response"] = ( - complete_streaming_response - ) + self.model_call_details[ + "async_complete_streaming_response" + ] = complete_streaming_response try: if self.model_call_details.get("cache_hit", False) is True: @@ -2505,10 +2505,10 @@ class Logging(LiteLLMLoggingBaseClass): model_call_details=self.model_call_details ) # base_model defaults to None if not set on model_info - self.model_call_details["response_cost"] = ( - self._response_cost_calculator( - result=complete_streaming_response - ) + self.model_call_details[ + "response_cost" + ] = self._response_cost_calculator( + result=complete_streaming_response ) verbose_logger.debug( @@ -2521,10 +2521,10 @@ class Logging(LiteLLMLoggingBaseClass): self.model_call_details["response_cost"] = None ## STANDARDIZED LOGGING PAYLOAD - self.model_call_details["standard_logging_object"] = ( - self._build_standard_logging_payload( - complete_streaming_response, start_time, end_time - ) + self.model_call_details[ + "standard_logging_object" + ] = self._build_standard_logging_payload( + complete_streaming_response, start_time, end_time ) # print standard logging payload @@ -2551,9 +2551,9 @@ class Logging(LiteLLMLoggingBaseClass): # _success_handler_helper_fn if self.model_call_details.get("standard_logging_object") is None: ## STANDARDIZED LOGGING PAYLOAD - self.model_call_details["standard_logging_object"] = ( - self._build_standard_logging_payload(result, start_time, end_time) - ) + self.model_call_details[ + "standard_logging_object" + ] = self._build_standard_logging_payload(result, start_time, end_time) # print standard logging payload if ( @@ -2796,18 +2796,18 @@ class Logging(LiteLLMLoggingBaseClass): ## STANDARDIZED LOGGING PAYLOAD - self.model_call_details["standard_logging_object"] = ( - get_standard_logging_object_payload( - kwargs=self.model_call_details, - init_response_obj={}, - start_time=start_time, - end_time=end_time, - logging_obj=self, - status="failure", - error_str=str(exception), - original_exception=exception, - standard_built_in_tools_params=self.standard_built_in_tools_params, - ) + self.model_call_details[ + "standard_logging_object" + ] = get_standard_logging_object_payload( + kwargs=self.model_call_details, + init_response_obj={}, + start_time=start_time, + end_time=end_time, + logging_obj=self, + status="failure", + error_str=str(exception), + original_exception=exception, + standard_built_in_tools_params=self.standard_built_in_tools_params, ) return start_time, end_time @@ -3774,9 +3774,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 service_name=arize_config.project_name, ) - os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = ( - f"space_id={arize_config.space_key or arize_config.space_id},api_key={arize_config.api_key}" - ) + os.environ[ + "OTEL_EXPORTER_OTLP_TRACES_HEADERS" + ] = f"space_id={arize_config.space_key or arize_config.space_id},api_key={arize_config.api_key}" for callback in _in_memory_loggers: if ( isinstance(callback, ArizeLogger) @@ -3802,13 +3802,13 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 existing_attrs = os.environ.get("OTEL_RESOURCE_ATTRIBUTES", "") # Add openinference.project.name attribute if existing_attrs: - os.environ["OTEL_RESOURCE_ATTRIBUTES"] = ( - f"{existing_attrs},openinference.project.name={arize_phoenix_config.project_name}" - ) + os.environ[ + "OTEL_RESOURCE_ATTRIBUTES" + ] = f"{existing_attrs},openinference.project.name={arize_phoenix_config.project_name}" else: - os.environ["OTEL_RESOURCE_ATTRIBUTES"] = ( - f"openinference.project.name={arize_phoenix_config.project_name}" - ) + os.environ[ + "OTEL_RESOURCE_ATTRIBUTES" + ] = f"openinference.project.name={arize_phoenix_config.project_name}" # Set Phoenix project name from environment variable phoenix_project_name = os.environ.get("PHOENIX_PROJECT_NAME", None) @@ -3816,19 +3816,19 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 existing_attrs = os.environ.get("OTEL_RESOURCE_ATTRIBUTES", "") # Add openinference.project.name attribute if existing_attrs: - os.environ["OTEL_RESOURCE_ATTRIBUTES"] = ( - f"{existing_attrs},openinference.project.name={phoenix_project_name}" - ) + os.environ[ + "OTEL_RESOURCE_ATTRIBUTES" + ] = f"{existing_attrs},openinference.project.name={phoenix_project_name}" else: - os.environ["OTEL_RESOURCE_ATTRIBUTES"] = ( - f"openinference.project.name={phoenix_project_name}" - ) + os.environ[ + "OTEL_RESOURCE_ATTRIBUTES" + ] = f"openinference.project.name={phoenix_project_name}" # auth can be disabled on local deployments of arize phoenix if arize_phoenix_config.otlp_auth_headers is not None: - os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = ( - arize_phoenix_config.otlp_auth_headers - ) + os.environ[ + "OTEL_EXPORTER_OTLP_TRACES_HEADERS" + ] = arize_phoenix_config.otlp_auth_headers for callback in _in_memory_loggers: if ( @@ -3907,7 +3907,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 from litellm.integrations.focus.focus_logger import FocusLogger for callback in _in_memory_loggers: - if type(callback) is FocusLogger: # exact match; exclude subclasses like VantageLogger + if ( + type(callback) is FocusLogger + ): # exact match; exclude subclasses like VantageLogger return callback # type: ignore focus_logger = FocusLogger() _in_memory_loggers.append(focus_logger) @@ -4013,9 +4015,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 exporter="otlp_http", endpoint="https://langtrace.ai/api/trace", ) - os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = ( - f"api_key={os.getenv('LANGTRACE_API_KEY')}" - ) + os.environ[ + "OTEL_EXPORTER_OTLP_TRACES_HEADERS" + ] = f"api_key={os.getenv('LANGTRACE_API_KEY')}" for callback in _in_memory_loggers: if ( isinstance(callback, OpenTelemetry) @@ -4289,7 +4291,9 @@ def get_custom_logger_compatible_class( # noqa: PLR0915 from litellm.integrations.focus.focus_logger import FocusLogger for callback in _in_memory_loggers: - if type(callback) is FocusLogger: # exact match; exclude subclasses like VantageLogger + if ( + type(callback) is FocusLogger + ): # exact match; exclude subclasses like VantageLogger return callback elif logging_integration == "vantage": from litellm.integrations.vantage.vantage_logger import VantageLogger @@ -4937,10 +4941,10 @@ class StandardLoggingPayloadSetup: for key in StandardLoggingHiddenParams.__annotations__.keys(): if key in hidden_params: if key == "additional_headers": - clean_hidden_params["additional_headers"] = ( - StandardLoggingPayloadSetup.get_additional_headers( - hidden_params[key] - ) + clean_hidden_params[ + "additional_headers" + ] = StandardLoggingPayloadSetup.get_additional_headers( + hidden_params[key] ) else: clean_hidden_params[key] = hidden_params[key] # type: ignore @@ -5579,9 +5583,9 @@ def scrub_sensitive_keys_in_metadata(litellm_params: Optional[dict]): ): for k, v in metadata["user_api_key_metadata"].items(): if k == "logging": # prevent logging user logging keys - cleaned_user_api_key_metadata[k] = ( - "scrubbed_by_litellm_for_sensitive_keys" - ) + cleaned_user_api_key_metadata[ + k + ] = "scrubbed_by_litellm_for_sensitive_keys" else: cleaned_user_api_key_metadata[k] = v diff --git a/litellm/litellm_core_utils/prompt_templates/factory.py b/litellm/litellm_core_utils/prompt_templates/factory.py index 2b838ad1f8..f600461671 100644 --- a/litellm/litellm_core_utils/prompt_templates/factory.py +++ b/litellm/litellm_core_utils/prompt_templates/factory.py @@ -2442,7 +2442,9 @@ def anthropic_messages_pt( # noqa: PLR0915 _document_content_element = cast( AnthropicMessagesDocumentParam, add_cache_control_to_content( - anthropic_content_element=cast(AnthropicMessagesDocumentParam, m), + anthropic_content_element=cast( + AnthropicMessagesDocumentParam, m + ), original_content_element=dict(m), ), ) @@ -2454,10 +2456,18 @@ def anthropic_messages_pt( # noqa: PLR0915 ) ) _file_content_element = add_cache_control_to_content( - anthropic_content_element=cast(AnthropicMessagesDocumentParam, _file_content_element), + anthropic_content_element=cast( + AnthropicMessagesDocumentParam, + _file_content_element, + ), original_content_element=dict(m), ) - user_content.append(cast(AnthropicMessagesDocumentParam,_file_content_element)) + user_content.append( + cast( + AnthropicMessagesDocumentParam, + _file_content_element, + ) + ) elif isinstance(user_message_types_block["content"], str): _anthropic_content_text_element: AnthropicMessagesTextParam = { "type": "text", diff --git a/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py index c1a6bd6750..3fda05172b 100644 --- a/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py +++ b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py @@ -780,7 +780,7 @@ class LiteLLMAnthropicMessagesAdapter: # Keep Anthropic-native tools in their original format new_tools.append(tool) # type: ignore[arg-type] continue - + original_name = tool["name"] truncated_name = truncate_tool_name(original_name) diff --git a/litellm/llms/base_llm/videos/transformation.py b/litellm/llms/base_llm/videos/transformation.py index a2892e2060..87289ad6a0 100644 --- a/litellm/llms/base_llm/videos/transformation.py +++ b/litellm/llms/base_llm/videos/transformation.py @@ -336,9 +336,7 @@ class BaseVideoConfig(ABC): Returns: Tuple[str, Dict]: (url, data) for the POST request """ - raise NotImplementedError( - "video edit is not supported for this provider" - ) + raise NotImplementedError("video edit is not supported for this provider") def transform_video_edit_response( self, @@ -346,9 +344,7 @@ class BaseVideoConfig(ABC): logging_obj: LiteLLMLoggingObj, custom_llm_provider: Optional[str] = None, ) -> VideoObject: - raise NotImplementedError( - "video edit is not supported for this provider" - ) + raise NotImplementedError("video edit is not supported for this provider") def transform_video_extension_request( self, @@ -366,9 +362,7 @@ class BaseVideoConfig(ABC): Returns: Tuple[str, Dict]: (url, data) for the POST request """ - raise NotImplementedError( - "video extension is not supported for this provider" - ) + raise NotImplementedError("video extension is not supported for this provider") def transform_video_extension_response( self, @@ -376,9 +370,7 @@ class BaseVideoConfig(ABC): logging_obj: LiteLLMLoggingObj, custom_llm_provider: Optional[str] = None, ) -> VideoObject: - raise NotImplementedError( - "video extension is not supported for this provider" - ) + raise NotImplementedError("video extension is not supported for this provider") def get_error_class( self, error_message: str, status_code: int, headers: Union[dict, httpx.Headers] diff --git a/litellm/llms/custom_httpx/llm_http_handler.py b/litellm/llms/custom_httpx/llm_http_handler.py index 204fa4d0cc..4c9abaad90 100644 --- a/litellm/llms/custom_httpx/llm_http_handler.py +++ b/litellm/llms/custom_httpx/llm_http_handler.py @@ -6162,7 +6162,10 @@ class BaseLLMHTTPHandler: litellm_params=dict(litellm_params), ) - url, files_list = video_provider_config.transform_video_create_character_request( + ( + url, + files_list, + ) = video_provider_config.transform_video_create_character_request( name=name, video=video, api_base=api_base, @@ -6230,7 +6233,10 @@ class BaseLLMHTTPHandler: litellm_params=dict(litellm_params), ) - url, files_list = video_provider_config.transform_video_create_character_request( + ( + url, + files_list, + ) = video_provider_config.transform_video_create_character_request( name=name, video=video, api_base=api_base, @@ -6324,11 +6330,7 @@ class BaseLLMHTTPHandler: ) try: - response = sync_httpx_client.get( - url=url, - headers=headers, - params=params - ) + response = sync_httpx_client.get(url=url, headers=headers, params=params) response.raise_for_status() return video_provider_config.transform_video_get_character_response( raw_response=response, @@ -6386,9 +6388,7 @@ class BaseLLMHTTPHandler: try: response = await async_httpx_client.get( - url=url, - headers=headers, - params=params + url=url, headers=headers, params=params ) response.raise_for_status() return video_provider_config.transform_video_get_character_response( diff --git a/litellm/llms/gemini/videos/transformation.py b/litellm/llms/gemini/videos/transformation.py index 0798472310..122cc95483 100644 --- a/litellm/llms/gemini/videos/transformation.py +++ b/litellm/llms/gemini/videos/transformation.py @@ -525,28 +525,47 @@ class GeminiVideoConfig(BaseVideoConfig): """Video delete is not supported.""" raise NotImplementedError("Video delete is not supported by Google Veo.") - def transform_video_create_character_request(self, name, video, api_base, litellm_params, headers): + def transform_video_create_character_request( + self, name, video, api_base, litellm_params, headers + ): raise NotImplementedError("video create character is not supported for Gemini") def transform_video_create_character_response(self, raw_response, logging_obj): raise NotImplementedError("video create character is not supported for Gemini") - def transform_video_get_character_request(self, character_id, api_base, litellm_params, headers): + def transform_video_get_character_request( + self, character_id, api_base, litellm_params, headers + ): raise NotImplementedError("video get character is not supported for Gemini") def transform_video_get_character_response(self, raw_response, logging_obj): raise NotImplementedError("video get character is not supported for Gemini") - def transform_video_edit_request(self, prompt, video_id, api_base, litellm_params, headers, extra_body=None): + def transform_video_edit_request( + self, prompt, video_id, api_base, litellm_params, headers, extra_body=None + ): raise NotImplementedError("video edit is not supported for Gemini") - def transform_video_edit_response(self, raw_response, logging_obj, custom_llm_provider=None): + def transform_video_edit_response( + self, raw_response, logging_obj, custom_llm_provider=None + ): raise NotImplementedError("video edit is not supported for Gemini") - def transform_video_extension_request(self, prompt, video_id, seconds, api_base, litellm_params, headers, extra_body=None): + def transform_video_extension_request( + self, + prompt, + video_id, + seconds, + api_base, + litellm_params, + headers, + extra_body=None, + ): raise NotImplementedError("video extension is not supported for Gemini") - def transform_video_extension_response(self, raw_response, logging_obj, custom_llm_provider=None): + def transform_video_extension_response( + self, raw_response, logging_obj, custom_llm_provider=None + ): raise NotImplementedError("video extension is not supported for Gemini") def get_error_class( diff --git a/litellm/llms/moonshot/chat/transformation.py b/litellm/llms/moonshot/chat/transformation.py index 40096be05c..24f852c28b 100644 --- a/litellm/llms/moonshot/chat/transformation.py +++ b/litellm/llms/moonshot/chat/transformation.py @@ -19,7 +19,8 @@ class MoonshotChatConfig(OpenAIGPTConfig): @overload def _transform_messages( self, messages: List[AllMessageValues], model: str, is_async: Literal[True] - ) -> Coroutine[Any, Any, List[AllMessageValues]]: ... + ) -> Coroutine[Any, Any, List[AllMessageValues]]: + ... @overload def _transform_messages( @@ -27,7 +28,8 @@ class MoonshotChatConfig(OpenAIGPTConfig): messages: List[AllMessageValues], model: str, is_async: Literal[False] = False, - ) -> List[AllMessageValues]: ... + ) -> List[AllMessageValues]: + ... def _transform_messages( self, messages: List[AllMessageValues], model: str, is_async: bool = False @@ -53,9 +55,13 @@ class MoonshotChatConfig(OpenAIGPTConfig): messages = handle_messages_with_content_list_to_str_conversion(messages) if is_async: - return super()._transform_messages(messages=messages, model=model, is_async=True) + return super()._transform_messages( + messages=messages, model=model, is_async=True + ) else: - return super()._transform_messages(messages=messages, model=model, is_async=False) + return super()._transform_messages( + messages=messages, model=model, is_async=False + ) def _get_openai_compatible_provider_info( self, api_base: Optional[str], api_key: Optional[str] @@ -141,7 +147,9 @@ class MoonshotChatConfig(OpenAIGPTConfig): optional_params["temperature"] = 0.3 return optional_params - def fill_reasoning_content(self, messages: List[AllMessageValues]) -> List[AllMessageValues]: + def fill_reasoning_content( + self, messages: List[AllMessageValues] + ) -> List[AllMessageValues]: """ Moonshot reasoning models require `reasoning_content` on every assistant message that contains tool_calls (multi-turn tool-calling flows). diff --git a/litellm/llms/runwayml/videos/transformation.py b/litellm/llms/runwayml/videos/transformation.py index 2c29c2e21e..8377dea952 100644 --- a/litellm/llms/runwayml/videos/transformation.py +++ b/litellm/llms/runwayml/videos/transformation.py @@ -592,28 +592,51 @@ class RunwayMLVideoConfig(BaseVideoConfig): return video_obj - def transform_video_create_character_request(self, name, video, api_base, litellm_params, headers): - raise NotImplementedError("video create character is not supported for RunwayML") + def transform_video_create_character_request( + self, name, video, api_base, litellm_params, headers + ): + raise NotImplementedError( + "video create character is not supported for RunwayML" + ) def transform_video_create_character_response(self, raw_response, logging_obj): - raise NotImplementedError("video create character is not supported for RunwayML") + raise NotImplementedError( + "video create character is not supported for RunwayML" + ) - def transform_video_get_character_request(self, character_id, api_base, litellm_params, headers): + def transform_video_get_character_request( + self, character_id, api_base, litellm_params, headers + ): raise NotImplementedError("video get character is not supported for RunwayML") def transform_video_get_character_response(self, raw_response, logging_obj): raise NotImplementedError("video get character is not supported for RunwayML") - def transform_video_edit_request(self, prompt, video_id, api_base, litellm_params, headers, extra_body=None): + def transform_video_edit_request( + self, prompt, video_id, api_base, litellm_params, headers, extra_body=None + ): raise NotImplementedError("video edit is not supported for RunwayML") - def transform_video_edit_response(self, raw_response, logging_obj, custom_llm_provider=None): + def transform_video_edit_response( + self, raw_response, logging_obj, custom_llm_provider=None + ): raise NotImplementedError("video edit is not supported for RunwayML") - def transform_video_extension_request(self, prompt, video_id, seconds, api_base, litellm_params, headers, extra_body=None): + def transform_video_extension_request( + self, + prompt, + video_id, + seconds, + api_base, + litellm_params, + headers, + extra_body=None, + ): raise NotImplementedError("video extension is not supported for RunwayML") - def transform_video_extension_response(self, raw_response, logging_obj, custom_llm_provider=None): + def transform_video_extension_response( + self, raw_response, logging_obj, custom_llm_provider=None + ): raise NotImplementedError("video extension is not supported for RunwayML") def get_error_class( diff --git a/litellm/llms/sagemaker/chat/transformation.py b/litellm/llms/sagemaker/chat/transformation.py index 60e85c9f93..3e42c1e8c1 100644 --- a/litellm/llms/sagemaker/chat/transformation.py +++ b/litellm/llms/sagemaker/chat/transformation.py @@ -184,9 +184,7 @@ class SagemakerChatConfig(OpenAIGPTConfig, BaseAWSLLM): llm_provider = LlmProviders(custom_llm_provider) except ValueError: llm_provider = LlmProviders.SAGEMAKER_CHAT - client = get_async_httpx_client( - llm_provider=llm_provider, params={} - ) + client = get_async_httpx_client(llm_provider=llm_provider, params={}) try: response = await client.post( diff --git a/litellm/llms/vertex_ai/batches/transformation.py b/litellm/llms/vertex_ai/batches/transformation.py index 86bdc2c7b5..c114465490 100644 --- a/litellm/llms/vertex_ai/batches/transformation.py +++ b/litellm/llms/vertex_ai/batches/transformation.py @@ -142,8 +142,8 @@ class VertexAIBatchTransformation: Gets the output file id from the Vertex AI Batch response """ - output_file_id: str = ( - response.get("outputInfo", OutputInfo()).get("gcsOutputDirectory", "") + output_file_id: str = response.get("outputInfo", OutputInfo()).get( + "gcsOutputDirectory", "" ) if output_file_id: output_file_id = output_file_id.rstrip("/") + "/predictions.jsonl" diff --git a/litellm/llms/vertex_ai/videos/transformation.py b/litellm/llms/vertex_ai/videos/transformation.py index 07b3d6faf7..1c24d657c1 100644 --- a/litellm/llms/vertex_ai/videos/transformation.py +++ b/litellm/llms/vertex_ai/videos/transformation.py @@ -624,28 +624,51 @@ class VertexAIVideoConfig(BaseVideoConfig, VertexBase): """Video delete is not supported.""" raise NotImplementedError("Video delete is not supported by Vertex AI Veo.") - def transform_video_create_character_request(self, name, video, api_base, litellm_params, headers): - raise NotImplementedError("video create character is not supported for Vertex AI") + def transform_video_create_character_request( + self, name, video, api_base, litellm_params, headers + ): + raise NotImplementedError( + "video create character is not supported for Vertex AI" + ) def transform_video_create_character_response(self, raw_response, logging_obj): - raise NotImplementedError("video create character is not supported for Vertex AI") + raise NotImplementedError( + "video create character is not supported for Vertex AI" + ) - def transform_video_get_character_request(self, character_id, api_base, litellm_params, headers): + def transform_video_get_character_request( + self, character_id, api_base, litellm_params, headers + ): raise NotImplementedError("video get character is not supported for Vertex AI") def transform_video_get_character_response(self, raw_response, logging_obj): raise NotImplementedError("video get character is not supported for Vertex AI") - def transform_video_edit_request(self, prompt, video_id, api_base, litellm_params, headers, extra_body=None): + def transform_video_edit_request( + self, prompt, video_id, api_base, litellm_params, headers, extra_body=None + ): raise NotImplementedError("video edit is not supported for Vertex AI") - def transform_video_edit_response(self, raw_response, logging_obj, custom_llm_provider=None): + def transform_video_edit_response( + self, raw_response, logging_obj, custom_llm_provider=None + ): raise NotImplementedError("video edit is not supported for Vertex AI") - def transform_video_extension_request(self, prompt, video_id, seconds, api_base, litellm_params, headers, extra_body=None): + def transform_video_extension_request( + self, + prompt, + video_id, + seconds, + api_base, + litellm_params, + headers, + extra_body=None, + ): raise NotImplementedError("video extension is not supported for Vertex AI") - def transform_video_extension_response(self, raw_response, logging_obj, custom_llm_provider=None): + def transform_video_extension_response( + self, raw_response, logging_obj, custom_llm_provider=None + ): raise NotImplementedError("video extension is not supported for Vertex AI") def get_error_class( diff --git a/litellm/main.py b/litellm/main.py index 81319bc432..112fef44e5 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -7533,9 +7533,7 @@ def stream_chunk_builder( # noqa: PLR0915 # the final chunk. all_annotations: list = [] for ac in annotation_chunks: - all_annotations.extend( - ac["choices"][0]["delta"]["annotations"] - ) + all_annotations.extend(ac["choices"][0]["delta"]["annotations"]) response["choices"][0]["message"]["annotations"] = all_annotations audio_chunks = [ diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 6786fc3359..181045809f 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -32354,6 +32354,53 @@ "supports_vision": true, "supports_web_search": true }, + "xai/grok-4.20-multi-agent-beta-0309": { + "cache_read_input_token_cost": 2e-07, + "input_cost_per_token": 2e-06, + "litellm_provider": "xai", + "max_input_tokens": 2000000, + "max_output_tokens": 2000000, + "max_tokens": 2000000, + "mode": "chat", + "output_cost_per_token": 6e-06, + "source": "https://docs.x.ai/docs/models", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true + }, + "xai/grok-4.20-beta-0309-reasoning": { + "cache_read_input_token_cost": 2e-07, + "input_cost_per_token": 2e-06, + "litellm_provider": "xai", + "max_input_tokens": 2000000, + "max_output_tokens": 2000000, + "max_tokens": 2000000, + "mode": "chat", + "output_cost_per_token": 6e-06, + "source": "https://docs.x.ai/docs/models", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true + }, + "xai/grok-4.20-beta-0309-non-reasoning": { + "cache_read_input_token_cost": 2e-07, + "input_cost_per_token": 2e-06, + "litellm_provider": "xai", + "max_input_tokens": 2000000, + "max_output_tokens": 2000000, + "max_tokens": 2000000, + "mode": "chat", + "output_cost_per_token": 6e-06, + "source": "https://docs.x.ai/docs/models", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true + }, "xai/grok-beta": { "input_cost_per_token": 5e-06, "litellm_provider": "xai", diff --git a/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py b/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py index af3a715051..3385e7feef 100644 --- a/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py +++ b/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py @@ -677,7 +677,60 @@ async def oauth_authorization_server_mcp( # Alias for standard OpenID discovery @router.get("/.well-known/openid-configuration") async def openid_configuration(request: Request): - return await oauth_authorization_server_mcp(request) + response = await oauth_authorization_server_mcp(request) + + # If MCPJWTSigner is active, augment the discovery doc with JWKS fields so + # MCP servers and gateways (e.g. AWS Bedrock AgentCore Gateway) can resolve + # the signing keys and verify liteLLM-issued tokens. + try: + from litellm.proxy.guardrails.guardrail_hooks.mcp_jwt_signer.mcp_jwt_signer import ( + get_mcp_jwt_signer, + ) + + signer = get_mcp_jwt_signer() + if signer is not None: + request_base_url = get_request_base_url(request) + if isinstance(response, dict): + response = { + **response, + "jwks_uri": f"{request_base_url}/.well-known/jwks.json", + "id_token_signing_alg_values_supported": ["RS256"], + } + except ImportError: + pass + + return response + + +@router.get("/.well-known/jwks.json") +async def jwks_json(request: Request): + """ + JSON Web Key Set endpoint. + + Returns the RSA public key used by MCPJWTSigner to sign outbound MCP tokens. + MCP servers and gateways use this endpoint to verify liteLLM-issued JWTs. + + Returns an empty key set if MCPJWTSigner is not configured. + """ + try: + from litellm.proxy.guardrails.guardrail_hooks.mcp_jwt_signer.mcp_jwt_signer import ( + get_mcp_jwt_signer, + ) + + signer = get_mcp_jwt_signer() + if signer is not None: + return JSONResponse( + content=signer.get_jwks(), + headers={"Cache-Control": f"public, max-age={signer.jwks_max_age}"}, + ) + except ImportError: + pass + + # No signer active — return empty key set; short cache so activation is picked up quickly. + return JSONResponse( + content={"keys": []}, + headers={"Cache-Control": "public, max-age=60"}, + ) # Additional legacy pattern support diff --git a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py index 43fe54fdfb..1e9d5c5a52 100644 --- a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py +++ b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py @@ -1908,7 +1908,15 @@ class MCPServerManager: user_api_key_auth: Optional[UserAPIKeyAuth], proxy_logging_obj: ProxyLogging, server: MCPServer, - ): + raw_headers: Optional[Dict[str, str]] = None, + ) -> Dict[str, Any]: + """ + Run pre-call checks and guardrail hooks for an MCP tool call. + + Returns a dict that may contain: + - "arguments": hook-modified tool arguments (only if changed) + - "extra_headers": headers injected by pre_mcp_call guardrail hooks + """ ## check if the tool is allowed or banned for the given server if not self.check_allowed_or_banned_tools(name, server): raise HTTPException( @@ -1932,6 +1940,14 @@ class MCPServerManager: server=server, ) + # Extract incoming Bearer token from raw request headers so + # guardrails like MCPJWTSigner can verify + re-sign it (FR-5). + normalized_raw = {k.lower(): v for k, v in (raw_headers or {}).items()} + incoming_bearer_token: Optional[str] = None + auth_hdr = normalized_raw.get("authorization", "") + if auth_hdr.lower().startswith("bearer "): + incoming_bearer_token = auth_hdr[len("bearer ") :] + pre_hook_kwargs = { "name": name, "arguments": arguments, @@ -1957,6 +1973,7 @@ class MCPServerManager: if user_api_key_auth else None ), + "incoming_bearer_token": incoming_bearer_token, } # Create MCP request object for processing @@ -1969,6 +1986,7 @@ class MCPServerManager: mcp_request_obj, pre_hook_kwargs ) + hook_result: Dict[str, Any] = {} try: # Use standard pre_call_hook modified_data = await proxy_logging_obj.pre_call_hook( @@ -1984,7 +2002,9 @@ class MCPServerManager: ) ) if modified_kwargs.get("arguments") != arguments: - arguments = modified_kwargs["arguments"] + hook_result["arguments"] = modified_kwargs["arguments"] + if modified_kwargs.get("extra_headers"): + hook_result["extra_headers"] = modified_kwargs["extra_headers"] except ( BlockedPiiEntityError, @@ -1995,6 +2015,8 @@ class MCPServerManager: verbose_logger.error(f"Guardrail blocked MCP tool call pre call: {str(e)}") raise e + return hook_result + def _create_during_hook_task( self, name: str, @@ -2047,6 +2069,7 @@ class MCPServerManager: raw_headers: Optional[Dict[str, str]], proxy_logging_obj: Optional[ProxyLogging], host_progress_callback: Optional[Callable] = None, + hook_extra_headers: Optional[Dict[str, str]] = None, ) -> CallToolResult: """ Call a regular MCP tool using the MCP client. @@ -2061,6 +2084,9 @@ class MCPServerManager: oauth2_headers: Optional OAuth2 headers raw_headers: Optional raw headers from the request proxy_logging_obj: Optional ProxyLogging object for hook integration + host_progress_callback: Optional callback for progress updates + hook_extra_headers: Optional headers injected by pre_mcp_call guardrail + hooks. Merged last (highest priority) into outbound request headers. Returns: CallToolResult from the MCP server @@ -2116,6 +2142,31 @@ class MCPServerManager: extra_headers = {} extra_headers.update(mcp_server.static_headers) + if hook_extra_headers: + if extra_headers is None: + extra_headers = {} + if "Authorization" in hook_extra_headers: + if "Authorization" in extra_headers: + verbose_logger.warning( + "MCPServerManager: hook_extra_headers 'Authorization' will overwrite " + "the existing Authorization header from static_headers. " + "The hook JWT will take precedence." + ) + elif server_auth_header is not None: + # server_auth_header is passed separately to _create_mcp_client as + # auth_value. Both will reach the upstream server — warn so admins + # know two Authorization credentials are being sent. + verbose_logger.warning( + "MCPServerManager: hook_extra_headers injects 'Authorization' while " + "server '%s' already has a configured authentication_token. " + "Both credentials will be sent; the hook header is in extra_headers " + "and the server token is in auth_value — the upstream server decides " + "which one wins. Consider unsetting authentication_token if you want " + "the hook JWT to be the sole credential.", + mcp_server.server_name or mcp_server.name, + ) + extra_headers.update(hook_extra_headers) + stdio_env = self._build_stdio_env(mcp_server, raw_headers) client = await self._create_mcp_client( @@ -2201,15 +2252,19 @@ class MCPServerManager: # Allow validation and modification of tool calls before execution # Using standard pre_call_hook ######################################################### + hook_result: Dict[str, Any] = {} if proxy_logging_obj: - await self.pre_call_tool_check( + hook_result = await self.pre_call_tool_check( name=name, arguments=arguments, server_name=server_name, user_api_key_auth=user_api_key_auth, proxy_logging_obj=proxy_logging_obj, server=mcp_server, + raw_headers=raw_headers, ) + if "arguments" in hook_result: + arguments = hook_result["arguments"] # Prepare tasks for during hooks tasks = [] @@ -2227,8 +2282,16 @@ class MCPServerManager: # For OpenAPI servers, call the tool handler directly instead of via MCP client if mcp_server.spec_path: verbose_logger.debug( - f"Calling OpenAPI tool {name} directly via HTTP handler" + "Calling OpenAPI tool %s directly via HTTP handler", name ) + if hook_result.get("extra_headers"): + verbose_logger.warning( + "pre_mcp_call hook returned extra_headers for OpenAPI-backed " + "MCP server '%s' — header injection is not supported for " + "OpenAPI servers; headers will be ignored. Use SSE/HTTP " + "transport to enable hook header injection.", + server_name, + ) tasks.append( asyncio.create_task( self._call_openapi_tool_handler(mcp_server, name, arguments) @@ -2247,6 +2310,7 @@ class MCPServerManager: raw_headers=raw_headers, proxy_logging_obj=proxy_logging_obj, host_progress_callback=host_progress_callback, + hook_extra_headers=hook_result.get("extra_headers"), ) # For OpenAPI tools, await outside the client context diff --git a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py index ef01f027d6..c0151d47e0 100644 --- a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py +++ b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py @@ -903,12 +903,12 @@ if MCP_AVAILABLE: try: client_id, client_secret, scopes = _extract_credentials(request) - _oauth2_flow: Optional[Literal["client_credentials", "authorization_code"]] = ( - request.oauth2_flow or ( - "client_credentials" - if client_id and client_secret and request.token_url - else None - ) + _oauth2_flow: Optional[ + Literal["client_credentials", "authorization_code"] + ] = request.oauth2_flow or ( + "client_credentials" + if client_id and client_secret and request.token_url + else None ) # client_credentials requires token_url to fetch a token; without it the # incoming auth header would be dropped with nothing to replace it. diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index ecbd7314cd..9e86680e35 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -2471,6 +2471,9 @@ class UserAPIKeyAuth( Any ] = None # Expanded created_by user when expand=user is used end_user_object_permission: Optional[LiteLLM_ObjectPermissionTable] = None + # Decoded upstream IdP claims (groups, roles, etc.) propagated by JWT auth machinery + # and forwarded into outbound tokens by guardrails such as MCPJWTSigner. + jwt_claims: Optional[Dict] = None model_config = ConfigDict(arbitrary_types_allowed=True) diff --git a/litellm/proxy/auth/auth_utils.py b/litellm/proxy/auth/auth_utils.py index 0d3c627446..a03e1fb94c 100644 --- a/litellm/proxy/auth/auth_utils.py +++ b/litellm/proxy/auth/auth_utils.py @@ -680,7 +680,7 @@ def get_customer_user_header_from_mapping(user_id_mapping) -> Optional[list]: if customer_headers_mappings: return customer_headers_mappings - + return None @@ -754,15 +754,11 @@ def get_end_user_id_from_request_body( user_id_str = str(header_value) if user_id_str.strip(): return user_id_str - + elif isinstance(custom_header_name_to_check, str): for header_name, header_value in request_headers.items(): if header_name.lower() == custom_header_name_to_check.lower(): - user_id_str = ( - str(header_value) - if header_value is not None - else "" - ) + user_id_str = str(header_value) if header_value is not None else "" if user_id_str.strip(): return user_id_str diff --git a/litellm/proxy/auth/user_api_key_auth.py b/litellm/proxy/auth/user_api_key_auth.py index 376048e7a1..044333ac13 100644 --- a/litellm/proxy/auth/user_api_key_auth.py +++ b/litellm/proxy/auth/user_api_key_auth.py @@ -685,6 +685,7 @@ async def _user_api_key_auth_builder( # noqa: PLR0915 do_standard_jwt_auth = True if jwt_handler.litellm_jwtauth.virtual_key_claim_field is not None: # Decode JWT to get claims without running full auth_builder + jwt_claims: Optional[dict] if jwt_handler.litellm_jwtauth.oidc_userinfo_enabled: jwt_claims = await jwt_handler.get_oidc_userinfo(token=api_key) else: @@ -700,6 +701,7 @@ async def _user_api_key_auth_builder( # noqa: PLR0915 ) if valid_token is not None: api_key = valid_token.token or "" + valid_token.jwt_claims = jwt_claims do_standard_jwt_auth = False # Fall through to virtual key checks @@ -729,6 +731,7 @@ async def _user_api_key_auth_builder( # noqa: PLR0915 team_membership: Optional[LiteLLM_TeamMembership] = result.get( "team_membership", None ) + jwt_claims = result.get("jwt_claims", None) global_proxy_spend = await get_global_proxy_spend( litellm_proxy_admin_name=litellm_proxy_admin_name, @@ -757,6 +760,7 @@ async def _user_api_key_auth_builder( # noqa: PLR0915 org_id=org_id, end_user_id=end_user_id, parent_otel_span=parent_otel_span, + jwt_claims=jwt_claims, ) valid_token = UserAPIKeyAuth( @@ -803,6 +807,7 @@ async def _user_api_key_auth_builder( # noqa: PLR0915 team_metadata=( team_object.metadata if team_object is not None else None ), + jwt_claims=jwt_claims, ) # Check if model has zero cost - if so, skip all budget checks diff --git a/litellm/proxy/batches_endpoints/endpoints.py b/litellm/proxy/batches_endpoints/endpoints.py index 740e63b7f1..38e5229eee 100644 --- a/litellm/proxy/batches_endpoints/endpoints.py +++ b/litellm/proxy/batches_endpoints/endpoints.py @@ -537,9 +537,10 @@ async def retrieve_batch( # noqa: PLR0915 ) # Fix: bug_feb14_batch_retrieve_returns_raw_input_file_id - # Resolve raw provider input_file_id to unified ID. + # Resolve raw provider file IDs (input, output, error) to unified IDs. if unified_batch_id: await resolve_input_file_id_to_unified(response, prisma_client) + await resolve_output_file_ids_to_unified(response, prisma_client) ### ALERTING ### asyncio.create_task( diff --git a/litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/__init__.py b/litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/__init__.py new file mode 100644 index 0000000000..abea9014a1 --- /dev/null +++ b/litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/__init__.py @@ -0,0 +1,84 @@ +"""MCP JWT Signer guardrail — built-in LiteLLM guardrail for zero trust MCP auth.""" + +from typing import TYPE_CHECKING + +from litellm.types.guardrails import SupportedGuardrailIntegrations + +from .mcp_jwt_signer import MCPJWTSigner, get_mcp_jwt_signer + +if TYPE_CHECKING: + from litellm.types.guardrails import Guardrail, LitellmParams + + +def initialize_guardrail( + litellm_params: "LitellmParams", guardrail: "Guardrail" +) -> MCPJWTSigner: + import litellm + + guardrail_name = guardrail.get("guardrail_name") + if not guardrail_name: + raise ValueError("MCPJWTSigner guardrail requires a guardrail_name") + + mode = litellm_params.mode + if mode != "pre_mcp_call": + raise ValueError( + f"MCPJWTSigner guardrail '{guardrail_name}' has mode='{mode}' but must use " + "mode='pre_mcp_call'. JWT injection only fires for MCP tool calls." + ) + + optional_params = getattr(litellm_params, "optional_params", None) + + def _get(key): # type: ignore[no-untyped-def] + if optional_params is not None: + v = getattr(optional_params, key, None) + if v is not None: + return v + return getattr(litellm_params, key, None) + + signer = MCPJWTSigner( + guardrail_name=guardrail_name, + event_hook=litellm_params.mode, + default_on=litellm_params.default_on, + # Core signing + issuer=_get("issuer"), + audience=_get("audience"), + ttl_seconds=_get("ttl_seconds"), + # FR-5: verify + re-sign + access_token_discovery_uri=_get("access_token_discovery_uri"), + token_introspection_endpoint=_get("token_introspection_endpoint"), + verify_issuer=_get("verify_issuer"), + verify_audience=_get("verify_audience"), + # FR-12: end-user identity mapping + end_user_claim_sources=_get("end_user_claim_sources"), + # FR-13: claim operations + add_claims=_get("add_claims"), + set_claims=_get("set_claims"), + remove_claims=_get("remove_claims"), + # FR-14: two-token model + channel_token_audience=_get("channel_token_audience"), + channel_token_ttl=_get("channel_token_ttl"), + # FR-15: incoming claim validation + required_claims=_get("required_claims"), + optional_claims=_get("optional_claims"), + # FR-9: debug headers + debug_headers=_get("debug_headers") or False, + # FR-10: configurable scopes + allowed_scopes=_get("allowed_scopes"), + ) + litellm.logging_callback_manager.add_litellm_callback(signer) + return signer + + +guardrail_initializer_registry = { + SupportedGuardrailIntegrations.MCP_JWT_SIGNER.value: initialize_guardrail, +} + +guardrail_class_registry = { + SupportedGuardrailIntegrations.MCP_JWT_SIGNER.value: MCPJWTSigner, +} + +__all__ = [ + "MCPJWTSigner", + "initialize_guardrail", + "get_mcp_jwt_signer", +] diff --git a/litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/mcp_jwt_signer.py b/litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/mcp_jwt_signer.py new file mode 100644 index 0000000000..5502076829 --- /dev/null +++ b/litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/mcp_jwt_signer.py @@ -0,0 +1,891 @@ +""" +MCPJWTSigner — Built-in LiteLLM guardrail for zero trust MCP authentication. + +Signs outbound MCP requests with a LiteLLM-issued RS256 JWT so that MCP servers +can trust a single signing authority (liteLLM) instead of every upstream IdP. + +Usage in config.yaml: + + guardrails: + - guardrail_name: "mcp-jwt-signer" + litellm_params: + guardrail: mcp_jwt_signer + mode: "pre_mcp_call" + default_on: true + + # Core signing config + issuer: "https://my-litellm.example.com" # optional + audience: "mcp" # optional + ttl_seconds: 300 # optional + + # FR-5: Verify + re-sign — validate incoming Bearer token before signing + access_token_discovery_uri: "https://idp.example.com/.well-known/openid-configuration" + token_introspection_endpoint: "https://idp.example.com/introspect" # opaque tokens + verify_issuer: "https://idp.example.com" # expected iss in incoming JWT + verify_audience: "api://my-app" # expected aud in incoming JWT + + # FR-12: End-user identity mapping — ordered resolution chain + # Supported: token:, litellm:user_id, litellm:email, + # litellm:end_user_id, litellm:team_id + end_user_claim_sources: + - "token:sub" + - "token:email" + - "litellm:user_id" + + # FR-13: Claim operations + add_claims: # add if key not already present in the JWT + deployment_id: "prod-001" + set_claims: # always set (overrides computed value) + env: "production" + remove_claims: # remove from final JWT + - "nbf" + + # FR-14: Two-token model — issue a second JWT for the MCP transport channel + channel_token_audience: "bedrock-gateway" + channel_token_ttl: 60 + + # FR-15: Incoming claim validation — enforce required IdP claims + required_claims: + - "sub" + - "email" + optional_claims: # pass through from jwt_claims into outbound JWT + - "groups" + - "roles" + + # FR-9: Debug headers + debug_headers: false # emit x-litellm-mcp-debug header when true + + # FR-10: Configurable scopes — explicit list replaces auto-generation + allowed_scopes: + - "mcp:tools/call" + - "mcp:tools/list" + +MCP servers verify tokens via: + GET /.well-known/openid-configuration → { jwks_uri: ".../.well-known/jwks.json" } + GET /.well-known/jwks.json → RSA public key in JWKS format + +Optionally set MCP_JWT_SIGNING_KEY env var (PEM string or file:///path) to use +your own RSA keypair. If unset, an RSA-2048 keypair is auto-generated at startup. +""" + +import base64 +import hashlib +import os +import re +import time +from typing import Any, Dict, List, Optional, Union + +import jwt +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey + +from litellm._logging import verbose_proxy_logger +from litellm.caching import DualCache +from litellm.integrations.custom_guardrail import ( + CustomGuardrail, + log_guardrail_information, +) +from litellm.proxy._types import UserAPIKeyAuth +from litellm.types.utils import CallTypesLiteral + +# Module-level singleton for the JWKS discovery endpoint to access. +_mcp_jwt_signer_instance: Optional["MCPJWTSigner"] = None + +# Simple in-memory JWKS cache: keyed by JWKS URI → (keys_list, fetched_at). +_jwks_cache: Dict[str, tuple] = {} +_JWKS_CACHE_TTL = 3600 # 1 hour + + +def get_mcp_jwt_signer() -> Optional["MCPJWTSigner"]: + """Return the active MCPJWTSigner singleton, or None if not initialized.""" + return _mcp_jwt_signer_instance + + +def _load_private_key_from_env(env_var: str) -> RSAPrivateKey: + """Load an RSA private key from an env var (PEM string or file:// path).""" + key_material = os.environ.get(env_var, "") + if not key_material: + raise ValueError( + f"MCPJWTSigner: environment variable '{env_var}' is set but empty." + ) + if key_material.startswith("file://"): + path = key_material[len("file://") :] + with open(path, "rb") as f: + key_bytes = f.read() + else: + key_bytes = key_material.encode("utf-8") + return serialization.load_pem_private_key(key_bytes, password=None) # type: ignore[return-value] + + +def _generate_rsa_key_pair() -> RSAPrivateKey: + """Generate a new RSA-2048 private key.""" + return rsa.generate_private_key( + public_exponent=65537, + key_size=2048, + ) + + +def _int_to_base64url(n: int) -> str: + """Encode an integer as a base64url string (no padding).""" + byte_length = (n.bit_length() + 7) // 8 + return ( + base64.urlsafe_b64encode(n.to_bytes(byte_length, byteorder="big")) + .rstrip(b"=") + .decode("ascii") + ) + + +def _compute_kid(public_key: Any) -> str: + """Derive a key ID from the public key's DER encoding (SHA-256, first 16 hex chars).""" + der_bytes = public_key.public_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PublicFormat.SubjectPublicKeyInfo, + ) + return hashlib.sha256(der_bytes).hexdigest()[:16] + + +async def _fetch_jwks(jwks_uri: str) -> List[Dict[str, Any]]: + """ + Fetch and cache a JWKS from the given URI. + + Results are cached for _JWKS_CACHE_TTL seconds to avoid hammering the IdP. + """ + now = time.time() + cached = _jwks_cache.get(jwks_uri) + if cached is not None: + keys, fetched_at = cached + if now - fetched_at < _JWKS_CACHE_TTL: + return keys # type: ignore[return-value] + + from litellm.llms.custom_httpx.http_handler import ( + get_async_httpx_client, + httpxSpecialProvider, + ) + + client = get_async_httpx_client(llm_provider=httpxSpecialProvider.Oauth2Check) + resp = await client.get(jwks_uri, headers={"Accept": "application/json"}) + resp.raise_for_status() + keys = resp.json().get("keys", []) + _jwks_cache[jwks_uri] = (keys, now) + return keys # type: ignore[return-value] + + +async def _fetch_oidc_discovery(discovery_uri: str) -> Dict[str, Any]: + """Fetch an OIDC discovery document and return its parsed JSON.""" + from litellm.llms.custom_httpx.http_handler import ( + get_async_httpx_client, + httpxSpecialProvider, + ) + + client = get_async_httpx_client(llm_provider=httpxSpecialProvider.Oauth2Check) + resp = await client.get(discovery_uri, headers={"Accept": "application/json"}) + resp.raise_for_status() + return resp.json() # type: ignore[return-value] + + +class MCPJWTSigner(CustomGuardrail): + """ + Built-in LiteLLM guardrail that signs outbound MCP requests with a + LiteLLM-issued RS256 JWT, enabling zero trust authentication. + + MCP servers verify tokens using liteLLM's OIDC discovery endpoint and + JWKS endpoint rather than trusting each upstream IdP directly. + + The signed JWT carries: + - iss: LiteLLM issuer identifier + - aud: MCP audience (configurable) + - sub: End-user identity (resolved via end_user_claim_sources, RFC 8693) + - act: Actor/agent identity (team_id or org_id, RFC 8693 delegation) + - scope: Tool-level access scopes (configurable via allowed_scopes) + - iat, exp, nbf: Standard timing claims + + Feature set: + FR-5: Verify + re-sign (access_token_discovery_uri, token_introspection_endpoint) + FR-9: Debug headers (debug_headers) + FR-10: Configurable scopes (allowed_scopes) + FR-12: Configurable end-user identity mapping (end_user_claim_sources) + FR-13: Claim operations (add_claims, set_claims, remove_claims) + FR-14: Two-token model (channel_token_audience, channel_token_ttl) + FR-15: Incoming claim validation (required_claims, optional_claims) + """ + + ALGORITHM = "RS256" + DEFAULT_TTL = 300 + DEFAULT_AUDIENCE = "mcp" + SIGNING_KEY_ENV = "MCP_JWT_SIGNING_KEY" + + def __init__( + self, + # Core signing config + issuer: Optional[str] = None, + audience: Optional[str] = None, + ttl_seconds: Optional[int] = None, + # FR-5: Verify + re-sign + access_token_discovery_uri: Optional[str] = None, + token_introspection_endpoint: Optional[str] = None, + verify_issuer: Optional[str] = None, + verify_audience: Optional[str] = None, + # FR-12: End-user identity mapping + end_user_claim_sources: Optional[List[str]] = None, + # FR-13: Claim operations + add_claims: Optional[Dict[str, Any]] = None, + set_claims: Optional[Dict[str, Any]] = None, + remove_claims: Optional[List[str]] = None, + # FR-14: Two-token model + channel_token_audience: Optional[str] = None, + channel_token_ttl: Optional[int] = None, + # FR-15: Incoming claim validation + required_claims: Optional[List[str]] = None, + optional_claims: Optional[List[str]] = None, + # FR-9: Debug headers + debug_headers: bool = False, + # FR-10: Configurable scopes + allowed_scopes: Optional[List[str]] = None, + **kwargs: Any, + ) -> None: + super().__init__(**kwargs) + + # --- Signing key setup --- + key_material = os.environ.get(self.SIGNING_KEY_ENV) + if key_material: + self._private_key = _load_private_key_from_env(self.SIGNING_KEY_ENV) + self._persistent_key: bool = True + verbose_proxy_logger.info( + "MCPJWTSigner: loaded RSA key from env var %s", self.SIGNING_KEY_ENV + ) + else: + self._private_key = _generate_rsa_key_pair() + self._persistent_key = False + verbose_proxy_logger.info( + "MCPJWTSigner: auto-generated RSA-2048 keypair (set %s to use your own key)", + self.SIGNING_KEY_ENV, + ) + + self._public_key = self._private_key.public_key() + self._kid = _compute_kid(self._public_key) + + # --- Core config --- + self.issuer: str = ( + issuer + or os.environ.get("MCP_JWT_ISSUER") + or os.environ.get("LITELLM_EXTERNAL_URL") + or "litellm" + ) + self.audience: str = ( + audience or os.environ.get("MCP_JWT_AUDIENCE") or self.DEFAULT_AUDIENCE + ) + resolved_ttl = int( + ttl_seconds + if ttl_seconds is not None + else os.environ.get("MCP_JWT_TTL_SECONDS", str(self.DEFAULT_TTL)) + ) + if resolved_ttl <= 0: + raise ValueError( + f"MCPJWTSigner: ttl_seconds must be > 0, got {resolved_ttl}" + ) + self.ttl_seconds: int = resolved_ttl + + # --- FR-5: Verify + re-sign --- + self.access_token_discovery_uri: Optional[str] = access_token_discovery_uri + self.token_introspection_endpoint: Optional[str] = token_introspection_endpoint + self.verify_issuer: Optional[str] = verify_issuer + self.verify_audience: Optional[str] = verify_audience + # Cached OIDC discovery document (fetched lazily, TTL = 24 h) + self._oidc_discovery_doc: Optional[Dict[str, Any]] = None + self._oidc_discovery_fetched_at: float = 0.0 + + # --- FR-12: End-user identity mapping --- + # Default chain: try incoming JWT sub, fall back to litellm user_id + self.end_user_claim_sources: List[str] = end_user_claim_sources or [ + "token:sub", + "litellm:user_id", + ] + + # --- FR-13: Claim operations --- + self.add_claims: Dict[str, Any] = add_claims or {} + self.set_claims: Dict[str, Any] = set_claims or {} + self.remove_claims: List[str] = remove_claims or [] + + # --- FR-14: Two-token model --- + self.channel_token_audience: Optional[str] = channel_token_audience + self.channel_token_ttl: int = ( + channel_token_ttl if channel_token_ttl is not None else self.ttl_seconds + ) + + # --- FR-15: Incoming claim validation --- + self.required_claims: List[str] = required_claims or [] + self.optional_claims: List[str] = optional_claims or [] + + # --- FR-9: Debug headers --- + self.debug_headers: bool = debug_headers + + # --- FR-10: Configurable scopes --- + self.allowed_scopes: Optional[List[str]] = allowed_scopes + + # Register singleton for JWKS/OIDC discovery endpoints. + global _mcp_jwt_signer_instance + if _mcp_jwt_signer_instance is not None: + verbose_proxy_logger.warning( + "MCPJWTSigner: replacing existing singleton — previously issued tokens " + "signed with the old key will fail JWKS verification. " + "Avoid configuring multiple mcp_jwt_signer guardrails." + ) + _mcp_jwt_signer_instance = self + + verbose_proxy_logger.info( + "MCPJWTSigner initialized: issuer=%s audience=%s ttl=%ds kid=%s " + "verify=%s channel_token=%s debug=%s", + self.issuer, + self.audience, + self.ttl_seconds, + self._kid, + bool(self.access_token_discovery_uri), + bool(self.channel_token_audience), + self.debug_headers, + ) + + # ------------------------------------------------------------------ + # Public helpers (used by /.well-known/jwks.json endpoint) + # ------------------------------------------------------------------ + + @property + def jwks_max_age(self) -> int: + """ + Recommended Cache-Control max-age for the JWKS response (seconds). + + 1 hour for persistent keys; 5 minutes for auto-generated keys so MCP + servers re-fetch quickly after a proxy restart. + """ + return 3600 if self._persistent_key else 300 + + def get_jwks(self) -> Dict[str, Any]: + """ + Return the JWKS for the RSA public key. + Used by GET /.well-known/jwks.json so MCP servers can verify tokens. + """ + public_numbers = self._public_key.public_numbers() + return { + "keys": [ + { + "kty": "RSA", + "alg": self.ALGORITHM, + "use": "sig", + "kid": self._kid, + "n": _int_to_base64url(public_numbers.n), + "e": _int_to_base64url(public_numbers.e), + } + ] + } + + # ------------------------------------------------------------------ + # FR-5: Verify + re-sign helpers + # ------------------------------------------------------------------ + + # 24-hour TTL for the OIDC discovery doc — long enough to avoid hammering + # the IdP, short enough to pick up jwks_uri changes after key rotation. + _OIDC_DISCOVERY_TTL = 86400 + + async def _get_oidc_discovery(self) -> Dict[str, Any]: + """Fetch and cache the OIDC discovery document with a 24-hour TTL. + + Only caches when the doc contains a 'jwks_uri' so that a transient or + malformed response doesn't permanently disable JWT verification. + """ + now = time.time() + cache_expired = ( + now - self._oidc_discovery_fetched_at + ) >= self._OIDC_DISCOVERY_TTL + if ( + self._oidc_discovery_doc is None or cache_expired + ) and self.access_token_discovery_uri: + doc = await _fetch_oidc_discovery(self.access_token_discovery_uri) + if "jwks_uri" in doc: + self._oidc_discovery_doc = doc + self._oidc_discovery_fetched_at = now + else: + return doc + return self._oidc_discovery_doc or {} + + async def _verify_incoming_jwt(self, raw_token: str) -> Dict[str, Any]: + """ + Verify an incoming Bearer JWT against the configured IdP's JWKS. + + Returns the verified payload claims dict. + Raises jwt.PyJWTError (or subclass) if verification fails. + """ + discovery = await self._get_oidc_discovery() + jwks_uri = discovery.get("jwks_uri") + if not jwks_uri: + raise ValueError( + "MCPJWTSigner: access_token_discovery_uri discovery document " + f"at {self.access_token_discovery_uri!r} has no 'jwks_uri'." + ) + + jwks_keys = await _fetch_jwks(jwks_uri) + + # Only read `kid` from the unverified header — never `alg`. + # Reading `alg` from an attacker-controlled header enables algorithm + # confusion attacks (e.g. alg:none, HS256 with the public key as secret). + # The algorithm is determined from the JWKS key entry instead. + unverified_header = jwt.get_unverified_header(raw_token) + kid = unverified_header.get("kid") + + # Build a JWKS object and pick the matching key. + # PyJWT's PyJWKSet handles key-type parsing and kid matching correctly. + from jwt import PyJWKSet + + try: + jwks_set = PyJWKSet.from_dict({"keys": jwks_keys}) + except Exception as exc: + raise jwt.exceptions.PyJWKSetError( # type: ignore[attr-defined] + f"Failed to parse JWKS from {jwks_uri!r}: {exc}" + ) from exc + + signing_jwk = None + for jwk_obj in jwks_set.keys: + if not kid or jwk_obj.key_id == kid: + signing_jwk = jwk_obj + break + + if signing_jwk is None: + raise jwt.exceptions.PyJWKSetError( # type: ignore[attr-defined] + f"No JWKS key matching kid={kid!r} at {jwks_uri!r}" + ) + + # Use the algorithm declared by the JWKS key entry, not the token header. + # PyJWT populates algorithm_name from the key's `alg` field; when absent + # it infers from the key type (RSAPublicKey → RS256). + alg = getattr(signing_jwk, "algorithm_name", None) or "RS256" + + decode_options: Dict[str, Any] = {"verify_exp": True} + decode_kwargs: Dict[str, Any] = { + "algorithms": [alg], + "options": decode_options, + } + if self.verify_audience: + decode_kwargs["audience"] = self.verify_audience + else: + decode_options["verify_aud"] = False + + if self.verify_issuer: + decode_kwargs["issuer"] = self.verify_issuer + + payload: Dict[str, Any] = jwt.decode( + raw_token, signing_jwk.key, **decode_kwargs + ) + return payload + + async def _introspect_opaque_token(self, token: str) -> Dict[str, Any]: + """ + Perform RFC 7662 token introspection for opaque (non-JWT) tokens. + + Returns the introspection response dict. Raises on HTTP error or + inactive token. + """ + if not self.token_introspection_endpoint: + raise ValueError( + "MCPJWTSigner: token_introspection_endpoint is required for " + "opaque token verification but is not configured." + ) + + from litellm.llms.custom_httpx.http_handler import ( + get_async_httpx_client, + httpxSpecialProvider, + ) + + client = get_async_httpx_client(llm_provider=httpxSpecialProvider.Oauth2Check) + resp = await client.post( + self.token_introspection_endpoint, + data={"token": token}, + headers={"Accept": "application/json"}, + ) + resp.raise_for_status() + result: Dict[str, Any] = resp.json() + if not result.get("active", False): + raise jwt.exceptions.ExpiredSignatureError( # type: ignore[attr-defined] + "MCPJWTSigner: incoming token is inactive (introspection returned active=false)" + ) + return result + + # ------------------------------------------------------------------ + # FR-15: Incoming claim validation + # ------------------------------------------------------------------ + + def _validate_required_claims( + self, + jwt_claims: Optional[Dict[str, Any]], + ) -> None: + """ + Raise HTTP 403 if any required_claims are absent from the verified + incoming token claims. + """ + if not self.required_claims: + return + + from fastapi import HTTPException + + missing = [c for c in self.required_claims if not (jwt_claims or {}).get(c)] + if missing: + raise HTTPException( + status_code=403, + detail={ + "error": ( + f"MCPJWTSigner: incoming token is missing required claims: " + f"{missing}. Configure the IdP to include these claims." + ) + }, + ) + + # ------------------------------------------------------------------ + # FR-12: End-user identity mapping + # ------------------------------------------------------------------ + + def _resolve_end_user_identity( + self, + user_api_key_dict: UserAPIKeyAuth, + jwt_claims: Optional[Dict[str, Any]], + ) -> str: + """ + Resolve the outbound JWT 'sub' using the ordered end_user_claim_sources list. + + Supported source prefixes: + token: — from verified incoming JWT / introspection claims + litellm:user_id — from UserAPIKeyAuth.user_id + litellm:email — from UserAPIKeyAuth.user_email + litellm:end_user_id — from UserAPIKeyAuth.end_user_id + litellm:team_id — from UserAPIKeyAuth.team_id + + Falls back to a stable hash of the API token for service-account callers. + """ + for source in self.end_user_claim_sources: + value: Optional[str] = None + + if source.startswith("token:"): + claim_name = source[len("token:") :] + raw = (jwt_claims or {}).get(claim_name) + value = str(raw) if raw else None + + elif source == "litellm:user_id": + uid = getattr(user_api_key_dict, "user_id", None) + value = str(uid) if uid else None + + elif source == "litellm:email": + email = getattr(user_api_key_dict, "user_email", None) + value = str(email) if email else None + + elif source == "litellm:end_user_id": + eid = getattr(user_api_key_dict, "end_user_id", None) + value = str(eid) if eid else None + + elif source == "litellm:team_id": + tid = getattr(user_api_key_dict, "team_id", None) + value = str(tid) if tid else None + + else: + verbose_proxy_logger.warning( + "MCPJWTSigner: unknown end_user_claim_source %r — skipping", source + ) + continue + + if value: + return value + + # Final fallback for service accounts with no user identity + token = getattr(user_api_key_dict, "token", None) or getattr( + user_api_key_dict, "api_key", None + ) + if token: + return "apikey:" + hashlib.sha256(str(token).encode()).hexdigest()[:16] + return "litellm-proxy" + + # ------------------------------------------------------------------ + # FR-10: Scope building + # ------------------------------------------------------------------ + + def _build_scope(self, raw_tool_name: str) -> str: + """ + Build the JWT scope string. + + When allowed_scopes is configured: join them verbatim. + Otherwise auto-generate minimal, least-privilege scopes: + - Tool call → mcp:tools/call mcp:tools/:call + - No tool → mcp:tools/call mcp:tools/list + + NOTE: tools/list is intentionally NOT granted on tool-call JWTs to + prevent callers from enumerating tools they didn't ask to use. + """ + if self.allowed_scopes is not None: + return " ".join(self.allowed_scopes) + + tool_name = ( + re.sub(r"[^a-zA-Z0-9_\-]", "_", raw_tool_name) if raw_tool_name else "" + ) + if tool_name: + scopes = ["mcp:tools/call", f"mcp:tools/{tool_name}:call"] + else: + scopes = ["mcp:tools/call", "mcp:tools/list"] + return " ".join(scopes) + + # ------------------------------------------------------------------ + # FR-13: Claim operations + # ------------------------------------------------------------------ + + def _apply_claim_operations(self, claims: Dict[str, Any]) -> Dict[str, Any]: + """Apply add_claims, set_claims, and remove_claims to the claim dict.""" + # add_claims: insert only when key is absent + for k, v in self.add_claims.items(): + if k not in claims: + claims[k] = v + + # set_claims: always override (highest priority) + claims = {**claims, **self.set_claims} + + # remove_claims: delete listed keys + for k in self.remove_claims: + claims.pop(k, None) + + return claims + + # ------------------------------------------------------------------ + # FR-15: optional_claims passthrough + # ------------------------------------------------------------------ + + def _passthrough_optional_claims( + self, + claims: Dict[str, Any], + jwt_claims: Optional[Dict[str, Any]], + ) -> Dict[str, Any]: + """Forward optional_claims from verified incoming token into the outbound JWT.""" + if not self.optional_claims or not jwt_claims: + return claims + for claim in self.optional_claims: + if claim in jwt_claims and claim not in claims: + claims[claim] = jwt_claims[claim] + return claims + + # ------------------------------------------------------------------ + # Core JWT builder + # ------------------------------------------------------------------ + + def _build_claims( + self, + user_api_key_dict: UserAPIKeyAuth, + data: dict, + jwt_claims: Optional[Dict[str, Any]] = None, + ) -> Dict[str, Any]: + """ + Build JWT claims for the outbound MCP access token. + + Args: + user_api_key_dict: LiteLLM auth context for the current request. + data: Pre-call hook data dict (contains mcp_tool_name etc.). + jwt_claims: Verified incoming IdP claims (FR-5), or LiteLLM-decoded + jwt_claims if available. None for pure API-key requests. + """ + now = int(time.time()) + claims: Dict[str, Any] = { + "iss": self.issuer, + "aud": self.audience, + "iat": now, + "exp": now + self.ttl_seconds, + "nbf": now, + } + + # sub — resolved via ordered claim sources (FR-12) + claims["sub"] = self._resolve_end_user_identity(user_api_key_dict, jwt_claims) + + # email passthrough when available from LiteLLM context + user_email = getattr(user_api_key_dict, "user_email", None) + if user_email: + claims["email"] = user_email + + # act — RFC 8693 delegation claim (team/org context) + team_id = getattr(user_api_key_dict, "team_id", None) + org_id = getattr(user_api_key_dict, "org_id", None) + act_sub = team_id or org_id or "litellm-proxy" + claims["act"] = {"sub": act_sub} + + # end_user_id when set separately from user_id + end_user_id = getattr(user_api_key_dict, "end_user_id", None) + if end_user_id: + claims["end_user_id"] = end_user_id + + # scope (FR-10) + raw_tool_name: str = data.get("mcp_tool_name", "") + claims["scope"] = self._build_scope(raw_tool_name) + + # optional_claims passthrough (FR-15) + claims = self._passthrough_optional_claims(claims, jwt_claims) + + # Claim operations — applied last so admin overrides take effect (FR-13) + claims = self._apply_claim_operations(claims) + + return claims + + def _build_channel_token_claims( + self, + base_claims: Dict[str, Any], + ) -> Dict[str, Any]: + """ + Build claims for the channel token (FR-14 two-token model). + + Inherits sub/act/scope from the access token but uses a separate + audience and TTL so the transport layer and resource layer receive + purpose-bound credentials. + """ + now = int(time.time()) + return { + **base_claims, + "aud": self.channel_token_audience, + "iat": now, + "exp": now + self.channel_token_ttl, + "nbf": now, + } + + # ------------------------------------------------------------------ + # FR-9: Debug header + # ------------------------------------------------------------------ + + @staticmethod + def _build_debug_header(claims: Dict[str, Any], kid: str) -> str: + """ + Build the x-litellm-mcp-debug header value. + + Format: v=1; kid=; sub=; iss=; exp=; scope= + Scope is truncated to 80 chars for header safety. + """ + sub = claims.get("sub", "") + iss = claims.get("iss", "") + exp = claims.get("exp", 0) + scope = claims.get("scope", "") + if len(scope) > 80: + scope = scope[:77] + "..." + return f"v=1; kid={kid}; sub={sub}; iss={iss}; exp={exp}; scope={scope}" + + # ------------------------------------------------------------------ + # Guardrail hook + # ------------------------------------------------------------------ + + @log_guardrail_information + async def async_pre_call_hook( + self, + user_api_key_dict: UserAPIKeyAuth, + cache: DualCache, + data: dict, + call_type: CallTypesLiteral, + ) -> Optional[Union[Exception, str, dict]]: + """ + Verifies the incoming token (when configured), validates required claims, + then signs an outbound JWT and injects it as the Authorization header. + + All non-MCP call types pass through unchanged. + """ + if call_type != "call_mcp_tool": + return data + + # ------------------------------------------------------------------ + # FR-5: Verify incoming token before re-signing + # ------------------------------------------------------------------ + jwt_claims: Optional[Dict[str, Any]] = None + raw_token: Optional[str] = data.get("incoming_bearer_token") + + if self.access_token_discovery_uri and raw_token: + # Three-dot pattern → JWT; otherwise opaque. + is_jwt = raw_token.count(".") == 2 + try: + if is_jwt: + jwt_claims = await self._verify_incoming_jwt(raw_token) + elif self.token_introspection_endpoint: + jwt_claims = await self._introspect_opaque_token(raw_token) + else: + verbose_proxy_logger.warning( + "MCPJWTSigner: access_token_discovery_uri is set but the " + "incoming token appears to be opaque and no " + "token_introspection_endpoint is configured. " + "Proceeding without incoming token verification." + ) + except Exception as exc: + verbose_proxy_logger.error( + "MCPJWTSigner: incoming token verification failed: %s", exc + ) + from fastapi import HTTPException + + raise HTTPException( + status_code=401, + detail={ + "error": ( + f"MCPJWTSigner: incoming token verification failed: {exc}" + ) + }, + ) + elif not raw_token and self.access_token_discovery_uri: + verbose_proxy_logger.debug( + "MCPJWTSigner: access_token_discovery_uri configured but no Bearer " + "token found in request (API-key auth request — skipping verification)." + ) + + # Fall back to LiteLLM-decoded JWT claims (available when proxy uses JWT auth). + if jwt_claims is None: + jwt_claims = getattr(user_api_key_dict, "jwt_claims", None) + + # ------------------------------------------------------------------ + # FR-15: Validate required claims + # ------------------------------------------------------------------ + self._validate_required_claims(jwt_claims) + + # ------------------------------------------------------------------ + # Build outbound access token + # ------------------------------------------------------------------ + claims = self._build_claims(user_api_key_dict, data, jwt_claims) + + signed_token = jwt.encode( + claims, + self._private_key, + algorithm=self.ALGORITHM, + headers={"kid": self._kid}, + ) + + # Merge into existing extra_headers — a prior guardrail in the chain may + # have already injected tracing headers or correlation IDs. + existing_headers: Dict[str, str] = data.get("extra_headers") or {} + new_headers: Dict[str, str] = { + **existing_headers, + "Authorization": f"Bearer {signed_token}", + } + + # ------------------------------------------------------------------ + # FR-14: Two-token model — channel token + # ------------------------------------------------------------------ + if self.channel_token_audience: + channel_claims = self._build_channel_token_claims(claims) + channel_token = jwt.encode( + channel_claims, + self._private_key, + algorithm=self.ALGORITHM, + headers={"kid": self._kid}, + ) + new_headers["x-mcp-channel-token"] = f"Bearer {channel_token}" + + # ------------------------------------------------------------------ + # FR-9: Debug header + # ------------------------------------------------------------------ + if self.debug_headers: + new_headers["x-litellm-mcp-debug"] = self._build_debug_header( + claims, self._kid + ) + + data["extra_headers"] = new_headers + + verbose_proxy_logger.debug( + "MCPJWTSigner: signed JWT sub=%s act=%s tool=%s exp=%d " + "verified=%s channel=%s", + claims.get("sub"), + claims.get("act", {}).get("sub"), + data.get("mcp_tool_name"), + claims["exp"], + jwt_claims is not None, + bool(self.channel_token_audience), + ) + + return data diff --git a/litellm/proxy/management_endpoints/internal_user_endpoints.py b/litellm/proxy/management_endpoints/internal_user_endpoints.py index 8a71b8d4b5..ca8c345f46 100644 --- a/litellm/proxy/management_endpoints/internal_user_endpoints.py +++ b/litellm/proxy/management_endpoints/internal_user_endpoints.py @@ -2142,8 +2142,7 @@ async def _resolve_org_filter_for_user_search( member_org_ids: List[str] = [] if caller_user is not None: member_org_ids = [ - m.organization_id - for m in (caller_user.organization_memberships or []) + m.organization_id for m in (caller_user.organization_memberships or []) ] if member_org_ids: diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index e09d7607eb..1016e6b149 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -1863,16 +1863,10 @@ async def _validate_update_key_data( user_api_key_cache: Any, ) -> None: """Validate permissions and constraints for key update.""" - _is_proxy_admin = ( - user_api_key_dict.user_role == LitellmUserRoles.PROXY_ADMIN.value - ) + _is_proxy_admin = user_api_key_dict.user_role == LitellmUserRoles.PROXY_ADMIN.value # Prevent non-admin from removing user_id (setting to empty string) (LIT-1884) - if ( - data.user_id is not None - and data.user_id == "" - and not _is_proxy_admin - ): + if data.user_id is not None and data.user_id == "" and not _is_proxy_admin: raise HTTPException( status_code=403, detail="Non-admin users cannot remove the user_id from a key.", diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py index d83ceb1b09..ceb3d5d277 100644 --- a/litellm/proxy/management_endpoints/team_endpoints.py +++ b/litellm/proxy/management_endpoints/team_endpoints.py @@ -857,7 +857,13 @@ async def new_team( # noqa: PLR0915 # Apply defaults from litellm.default_team_params for any fields # not explicitly provided in the request. - for field in ("max_budget", "budget_duration", "tpm_limit", "rpm_limit", "team_member_permissions"): + for field in ( + "max_budget", + "budget_duration", + "tpm_limit", + "rpm_limit", + "team_member_permissions", + ): if getattr(data, field, None) is None: default_value = _get_default_team_param(field) if default_value is not None: diff --git a/litellm/proxy/openai_files_endpoints/common_utils.py b/litellm/proxy/openai_files_endpoints/common_utils.py index 49f1753533..25ad1b25aa 100644 --- a/litellm/proxy/openai_files_endpoints/common_utils.py +++ b/litellm/proxy/openai_files_endpoints/common_utils.py @@ -857,7 +857,10 @@ async def update_batch_in_database( # If the batch_processed column doesn't exist (old schema), # retry without it so the status update still succeeds. err_str = str(col_err).lower() - if "batch_processed" in err_str and update_data.get("batch_processed") is not None: + if ( + "batch_processed" in err_str + and update_data.get("batch_processed") is not None + ): verbose_proxy_logger.warning( f"batch_processed column not found, retrying update without it: {col_err}" ) diff --git a/litellm/proxy/proxy_cli.py b/litellm/proxy/proxy_cli.py index e5a34ae8bd..97d5de0d53 100644 --- a/litellm/proxy/proxy_cli.py +++ b/litellm/proxy/proxy_cli.py @@ -468,6 +468,12 @@ class ProxyInitializationHelpers: type=str, help="Path to the logging configuration file", ) +@click.option( + "--setup", + is_flag=True, + default=False, + help="Run the interactive setup wizard to configure providers and generate a config file", +) @click.option( "--version", "-v", @@ -598,6 +604,7 @@ def run_server( # noqa: PLR0915 num_requests, use_queue, health, + setup, version, run_gunicorn, run_hypercorn, @@ -611,6 +618,12 @@ def run_server( # noqa: PLR0915 max_requests_before_restart, enforce_prisma_migration_check: bool, ): + if setup: + from litellm.setup_wizard import run_setup_wizard + + run_setup_wizard() + return + args = locals() if local: from proxy_server import ( @@ -904,7 +917,7 @@ def run_server( # noqa: PLR0915 # Auto-create PROMETHEUS_MULTIPROC_DIR for multi-worker setups ProxyInitializationHelpers._maybe_setup_prometheus_multiproc_dir( num_workers=num_workers, - litellm_settings=litellm_settings if config else None, + litellm_settings=litellm_settings if config else None, # type: ignore[possibly-unbound] ) # --- SEPARATE HEALTH APP LOGIC --- diff --git a/litellm/proxy/response_polling/background_streaming.py b/litellm/proxy/response_polling/background_streaming.py index b4d51814e5..7583f30eb2 100644 --- a/litellm/proxy/response_polling/background_streaming.py +++ b/litellm/proxy/response_polling/background_streaming.py @@ -115,7 +115,9 @@ async def background_streaming_task( # noqa: PLR0915 UPDATE_INTERVAL = 0.150 # 150ms batching interval # Track the terminal event from the stream (may not be "completed") - terminal_status: Optional[ResponsesAPIStatus] = None # Will be set by response.completed/failed/incomplete/cancelled + terminal_status: Optional[ + ResponsesAPIStatus + ] = None # Will be set by response.completed/failed/incomplete/cancelled terminal_error = None _event_to_status = { "response.completed": "completed", @@ -259,7 +261,10 @@ async def background_streaming_task( # noqa: PLR0915 ) # Extract error for failed and incomplete responses - if event_type == "response.failed" or event_type == "response.incomplete": + if ( + event_type == "response.failed" + or event_type == "response.incomplete" + ): terminal_error = response_data.get("error") # Core response fields diff --git a/litellm/proxy/spend_tracking/vantage_endpoints.py b/litellm/proxy/spend_tracking/vantage_endpoints.py index 14c0ebcb54..7d8fbf7461 100644 --- a/litellm/proxy/spend_tracking/vantage_endpoints.py +++ b/litellm/proxy/spend_tracking/vantage_endpoints.py @@ -40,9 +40,7 @@ def _get_registered_vantage_logger(): return None -async def _set_vantage_settings( - api_key: str, integration_token: str, base_url: str -): +async def _set_vantage_settings(api_key: str, integration_token: str, base_url: str): """Store Vantage settings in the database with encrypted API key.""" from litellm.proxy.proxy_server import prisma_client @@ -341,9 +339,7 @@ async def init_vantage_settings( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error( - f"Error initializing Vantage settings: {str(e)}" - ) + verbose_proxy_logger.error(f"Error initializing Vantage settings: {str(e)}") raise HTTPException( status_code=500, detail={"error": f"Failed to initialize Vantage settings: {str(e)}"}, @@ -395,7 +391,8 @@ async def vantage_dry_run_export( """Cast Decimal columns to Float64 so .to_dicts() produces JSON-serializable float values instead of decimal.Decimal.""" decimal_cols = [ - col for col, dtype in zip(frame.columns, frame.dtypes) + col + for col, dtype in zip(frame.columns, frame.dtypes) if isinstance(dtype, pl.Decimal) ] if decimal_cols: @@ -404,8 +401,16 @@ async def vantage_dry_run_export( ) return frame.to_dicts() - usage_sample = _to_json_safe_dicts(data.head(min(50, len(data)))) if not data.is_empty() else [] - normalized_sample = _to_json_safe_dicts(normalized.head(min(50, len(normalized)))) if not normalized.is_empty() else [] + usage_sample = ( + _to_json_safe_dicts(data.head(min(50, len(data)))) + if not data.is_empty() + else [] + ) + normalized_sample = ( + _to_json_safe_dicts(normalized.head(min(50, len(normalized)))) + if not normalized.is_empty() + else [] + ) # Use the same pre-transform column names as # FocusExportEngine.dry_run_export_usage_data for consistency. @@ -437,14 +442,10 @@ async def vantage_dry_run_export( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error( - f"Error performing Vantage dry run export: {str(e)}" - ) + verbose_proxy_logger.error(f"Error performing Vantage dry run export: {str(e)}") raise HTTPException( status_code=500, - detail={ - "error": f"Failed to perform Vantage dry run export: {str(e)}" - }, + detail={"error": f"Failed to perform Vantage dry run export: {str(e)}"}, ) diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index 76662be175..df527d08af 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -454,8 +454,6 @@ class ProxyLogging: for hook in PROXY_HOOKS: proxy_hook = get_proxy_hook(hook) - import inspect - expected_args = inspect.getfullargspec(proxy_hook).args passed_in_args: Dict[str, Any] = {} if "internal_usage_cache" in expected_args: @@ -559,6 +557,10 @@ class ProxyLogging: "user_api_key_request_route": kwargs.get("user_api_key_request_route"), "mcp_tool_name": request_obj.tool_name, # Keep original for reference "mcp_arguments": request_obj.arguments, # Keep original for reference + # Raw Bearer token from the original HTTP request — allows guardrails + # (e.g. MCPJWTSigner) to independently verify the caller's identity + # before re-signing an outbound token (FR-5 verify+re-sign). + "incoming_bearer_token": kwargs.get("incoming_bearer_token"), } return synthetic_data @@ -824,17 +826,30 @@ class ProxyLogging: ) -> dict: """ Helper function to convert pre_call_hook response back to kwargs for MCP usage. + + Supports: + - modified_arguments: Override tool call arguments + - extra_headers: Inject custom headers into the outbound MCP request """ if not response_data: return original_kwargs - # Apply any argument modifications from the hook response modified_kwargs = original_kwargs.copy() - # If the response contains modified arguments, apply them if response_data.get("modified_arguments"): modified_kwargs["arguments"] = response_data["modified_arguments"] + if response_data.get("extra_headers"): + # Merge rather than replace — a prior guardrail in the chain may have + # already injected headers (e.g. tracing IDs). Later guardrails win on + # key collisions so that the most-specific guardrail (e.g. JWT signer) + # takes precedence over earlier ones. + existing = modified_kwargs.get("extra_headers") or {} + modified_kwargs["extra_headers"] = { + **existing, + **response_data["extra_headers"], + } + return modified_kwargs async def process_pre_call_hook_response(self, response, data, call_type): diff --git a/litellm/proxy/video_endpoints/utils.py b/litellm/proxy/video_endpoints/utils.py index 36203bdc77..689fe4a371 100644 --- a/litellm/proxy/video_endpoints/utils.py +++ b/litellm/proxy/video_endpoints/utils.py @@ -7,7 +7,9 @@ from litellm.types.videos.utils import encode_character_id_with_provider def extract_model_from_target_model_names(target_model_names: Any) -> Optional[str]: if isinstance(target_model_names, str): - target_model_names = [m.strip() for m in target_model_names.split(",") if m.strip()] + target_model_names = [ + m.strip() for m in target_model_names.split(",") if m.strip() + ] elif not isinstance(target_model_names, list): return None return target_model_names[0] if target_model_names else None diff --git a/litellm/responses/main.py b/litellm/responses/main.py index cd9ce67c26..2a320517a4 100644 --- a/litellm/responses/main.py +++ b/litellm/responses/main.py @@ -692,11 +692,11 @@ def responses( return run_async_function(aresponses_api_with_mcp, **mcp_call_kwargs) # get provider config - responses_api_provider_config: Optional[BaseResponsesAPIConfig] = ( - ProviderConfigManager.get_provider_responses_api_config( - model=model, - provider=custom_llm_provider, - ) + responses_api_provider_config: Optional[ + BaseResponsesAPIConfig + ] = ProviderConfigManager.get_provider_responses_api_config( + model=model, + provider=custom_llm_provider, ) local_vars.update(kwargs) @@ -908,11 +908,11 @@ def delete_responses( raise ValueError("custom_llm_provider is required but passed as None") # get provider config - responses_api_provider_config: Optional[BaseResponsesAPIConfig] = ( - ProviderConfigManager.get_provider_responses_api_config( - model=None, - provider=custom_llm_provider, - ) + responses_api_provider_config: Optional[ + BaseResponsesAPIConfig + ] = ProviderConfigManager.get_provider_responses_api_config( + model=None, + provider=custom_llm_provider, ) if responses_api_provider_config is None: @@ -1089,11 +1089,11 @@ def get_responses( raise ValueError("custom_llm_provider is required but passed as None") # get provider config - responses_api_provider_config: Optional[BaseResponsesAPIConfig] = ( - ProviderConfigManager.get_provider_responses_api_config( - model=None, - provider=custom_llm_provider, - ) + responses_api_provider_config: Optional[ + BaseResponsesAPIConfig + ] = ProviderConfigManager.get_provider_responses_api_config( + model=None, + provider=custom_llm_provider, ) if responses_api_provider_config is None: @@ -1247,11 +1247,11 @@ def list_input_items( if custom_llm_provider is None: raise ValueError("custom_llm_provider is required but passed as None") - responses_api_provider_config: Optional[BaseResponsesAPIConfig] = ( - ProviderConfigManager.get_provider_responses_api_config( - model=None, - provider=custom_llm_provider, - ) + responses_api_provider_config: Optional[ + BaseResponsesAPIConfig + ] = ProviderConfigManager.get_provider_responses_api_config( + model=None, + provider=custom_llm_provider, ) if responses_api_provider_config is None: @@ -1406,11 +1406,11 @@ def cancel_responses( raise ValueError("custom_llm_provider is required but passed as None") # get provider config - responses_api_provider_config: Optional[BaseResponsesAPIConfig] = ( - ProviderConfigManager.get_provider_responses_api_config( - model=None, - provider=custom_llm_provider, - ) + responses_api_provider_config: Optional[ + BaseResponsesAPIConfig + ] = ProviderConfigManager.get_provider_responses_api_config( + model=None, + provider=custom_llm_provider, ) if responses_api_provider_config is None: @@ -1594,11 +1594,11 @@ def compact_responses( raise ValueError("custom_llm_provider is required but passed as None") # get provider config - responses_api_provider_config: Optional[BaseResponsesAPIConfig] = ( - ProviderConfigManager.get_provider_responses_api_config( - model=model, - provider=custom_llm_provider, - ) + responses_api_provider_config: Optional[ + BaseResponsesAPIConfig + ] = ProviderConfigManager.get_provider_responses_api_config( + model=model, + provider=custom_llm_provider, ) if responses_api_provider_config is None: diff --git a/litellm/router.py b/litellm/router.py index f34368172a..46998abb16 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -8611,6 +8611,7 @@ class Router: _model_info = deployment.get("model_info", {}) # see if we have the info for this model + _deployment_model = None # per-deployment model name (avoids overwriting the outer `model` group name) try: base_model = _model_info.get("base_model", None) if base_model is None: @@ -8618,7 +8619,7 @@ class Router: model_info = self.get_router_model_info( deployment=deployment, received_model_name=model ) - model = base_model or _litellm_params.get("model", None) + _deployment_model = base_model or _litellm_params.get("model", None) if ( isinstance(model_info, dict) @@ -8632,7 +8633,9 @@ class Router: _context_window_error = True _potential_error_str += ( "Model={}, Max Input Tokens={}, Got={}".format( - model, model_info["max_input_tokens"], input_tokens + _deployment_model, + model_info["max_input_tokens"], + input_tokens, ) ) continue @@ -8688,13 +8691,21 @@ class Router: ## INVALID PARAMS ## -> catch 'gpt-3.5-turbo-16k' not supporting 'response_format' param if request_kwargs is not None and litellm.drop_params is False: - # get supported params - model, custom_llm_provider, _, _ = litellm.get_llm_provider( - model=model, litellm_params=LiteLLM_Params(**_litellm_params) + # get supported params — use per-deployment model to avoid overwriting the outer model group name + _dep_model_for_params = _deployment_model or model + ( + _dep_model_for_params, + custom_llm_provider, + _, + _, + ) = litellm.get_llm_provider( + model=_dep_model_for_params, + litellm_params=LiteLLM_Params(**_litellm_params), ) supported_openai_params = litellm.get_supported_openai_params( - model=model, custom_llm_provider=custom_llm_provider + model=_dep_model_for_params, + custom_llm_provider=custom_llm_provider, ) if supported_openai_params is None: diff --git a/litellm/setup_wizard.py b/litellm/setup_wizard.py new file mode 100644 index 0000000000..ee5918e127 --- /dev/null +++ b/litellm/setup_wizard.py @@ -0,0 +1,668 @@ +# ruff: noqa: T201 +# flake8: noqa: T201 +""" +LiteLLM Interactive Setup Wizard + +Guides users through selecting LLM providers, entering API keys, +and generating a proxy config file — mirroring the Claude Code onboarding UX. +""" + +import importlib.metadata +import os +import re +import secrets +import sys +import sysconfig +from pathlib import Path +from typing import Dict, List, Optional, Set + +# termios / tty are Unix-only; fall back gracefully on Windows +try: + import termios + import tty + + _HAS_RAW_TERMINAL: bool = True +except ImportError: + termios = None # type: ignore[assignment] + tty = None # type: ignore[assignment] + _HAS_RAW_TERMINAL = False + +from litellm.utils import check_valid_key + +# --------------------------------------------------------------------------- +# Provider definitions +# --------------------------------------------------------------------------- +# Each entry describes one provider card shown in the wizard. +# `env_key` — primary env var name (None = no key needed, e.g. Ollama) +# `test_model` — model passed to check_valid_key for credential validation +# (None = skip validation, e.g. Azure needs a deployment name) +# `models` — default models written into the generated config +# --------------------------------------------------------------------------- + +PROVIDERS: List[Dict] = [ + { + "id": "openai", + "name": "OpenAI", + "description": "GPT-4o, GPT-4o-mini, o3-mini", + "env_key": "OPENAI_API_KEY", + "key_hint": "sk-...", + "test_model": "gpt-4o-mini", + "models": ["gpt-4o", "gpt-4o-mini"], + }, + { + "id": "anthropic", + "name": "Anthropic", + "description": "Claude Opus 4.6, Sonnet 4.6, Haiku 4.5", + "env_key": "ANTHROPIC_API_KEY", + "key_hint": "sk-ant-...", + "test_model": "claude-haiku-4-5-20251001", + "models": ["claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5-20251001"], + }, + { + "id": "gemini", + "name": "Google Gemini", + "description": "Gemini 2.0 Flash, Gemini 2.5 Pro", + "env_key": "GEMINI_API_KEY", + "key_hint": "AIza...", + "test_model": "gemini/gemini-2.0-flash", + "models": ["gemini/gemini-2.0-flash", "gemini/gemini-2.5-pro"], + }, + { + "id": "azure", + "name": "Azure OpenAI", + "description": "GPT-4o via Azure", + "env_key": "AZURE_API_KEY", + "key_hint": "your-azure-key", + "test_model": None, # needs deployment name — skip validation + "models": [], + "needs_api_base": True, + "api_base_hint": "https://.openai.azure.com/", + "api_version": "2024-07-01-preview", + }, + { + "id": "bedrock", + "name": "AWS Bedrock", + "description": "Claude 3.5, Llama 3 via AWS", + "env_key": "AWS_ACCESS_KEY_ID", + "key_hint": "AKIA...", + "test_model": None, # multi-key auth — skip validation + "models": ["bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0"], + "extra_keys": ["AWS_SECRET_ACCESS_KEY", "AWS_REGION_NAME"], + "extra_hints": ["your-secret-key", "us-east-1"], + }, + { + "id": "ollama", + "name": "Ollama", + "description": "Local models (llama3.2, mistral, etc.)", + "env_key": None, + "key_hint": None, + "test_model": None, # local — no remote validation + "models": ["ollama/llama3.2", "ollama/mistral"], + "api_base": "http://localhost:11434", + }, +] + + +# --------------------------------------------------------------------------- +# ANSI colour helpers +# --------------------------------------------------------------------------- + +_ANSI_RE = re.compile(r"\033\[[^m]*m") + +_ORANGE = "\033[38;2;215;119;87m" +_DIM = "\033[2m" +_BOLD = "\033[1m" +_GREEN = "\033[38;2;78;186;101m" +_BLUE = "\033[38;2;177;185;249m" +_GREY = "\033[38;2;153;153;153m" +_RESET = "\033[0m" +_CHECK = "✔" +_CROSS = "✘" + +_CURSOR_HIDE = "\033[?25l" +_CURSOR_SHOW = "\033[?25h" +_MOVE_UP = "\033[{}A" + + +def _supports_color() -> bool: + return sys.stdout.isatty() and os.environ.get("NO_COLOR") is None + + +def _c(code: str, text: str) -> str: + return f"{code}{text}{_RESET}" if _supports_color() else text + + +def orange(t: str) -> str: + return _c(_ORANGE, t) + + +def bold(t: str) -> str: + return _c(_BOLD, t) + + +def green(t: str) -> str: + return _c(_GREEN, t) + + +def blue(t: str) -> str: + return _c(_BLUE, t) + + +def grey(t: str) -> str: + return _c(_GREY, t) + + +def dim(t: str) -> str: + return _c(_DIM, t) + + +def _divider() -> str: + """Return a styled divider line (evaluated at call-time, not import-time).""" + return dim(" " + "╌" * 74) + + +def _styled_input(prompt: str) -> str: + """ + Like input() but wraps ANSI sequences in readline ignore markers + (\\001...\\002) so readline correctly tracks the cursor column. + In non-TTY contexts, strips ANSI entirely so no escape codes appear. + """ + if sys.stdout.isatty(): + rl_prompt = _ANSI_RE.sub(lambda m: f"\001{m.group()}\002", prompt) + else: + rl_prompt = _ANSI_RE.sub("", prompt) + return input(rl_prompt).strip() + + +def _yaml_escape(value: str) -> str: + """Escape a string for safe embedding in a double-quoted YAML scalar.""" + return ( + value.replace("\\", "\\\\") + .replace('"', '\\"') + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\t", "\\t") + ) + + +# --------------------------------------------------------------------------- +# Layout constants +# --------------------------------------------------------------------------- + +LITELLM_ASCII = r""" + ██╗ ██╗████████╗███████╗██╗ ██╗ ███╗ ███╗ + ██║ ██║╚══██╔══╝██╔════╝██║ ██║ ████╗ ████║ + ██║ ██║ ██║ █████╗ ██║ ██║ ██╔████╔██║ + ██║ ██║ ██║ ██╔══╝ ██║ ██║ ██║╚██╔╝██║ + ███████╗██║ ██║ ███████╗███████╗███████╗██║ ╚═╝ ██║ + ╚══════╝╚═╝ ╚═╝ ╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝ +""" + + +# --------------------------------------------------------------------------- +# Setup wizard +# --------------------------------------------------------------------------- + + +class SetupWizard: + """ + Interactive onboarding wizard: provider selection → API keys → config file. + + All methods are static — the class is purely a namespace with clear + single-responsibility sections. Entry point: SetupWizard.run(). + """ + + # ── entry point ───────────────────────────────────────────────────────── + + @staticmethod + def run() -> None: + try: + SetupWizard._wizard() + except (KeyboardInterrupt, EOFError): + print(f"\n\n {grey('Setup cancelled.')}\n") + + # ── wizard steps ──────────────────────────────────────────────────────── + + @staticmethod + def _wizard() -> None: + SetupWizard._print_welcome() + print(f" {bold('Lets get started.')}") + print() + + providers = SetupWizard._select_providers() + env_vars = SetupWizard._collect_keys(providers) + port, master_key = SetupWizard._proxy_settings() + + config_path = Path(os.getcwd()) / "litellm_config.yaml" + try: + config_path.write_text( + SetupWizard._build_config(providers, env_vars, master_key) + ) + except OSError as exc: + print(f"\n {bold(_CROSS + ' Could not write config:')} {exc}") + print(" Try running from a directory you have write access to.\n") + return + + SetupWizard._print_success(config_path, port, master_key) + SetupWizard._offer_start(config_path, port, master_key) + + # ── welcome ───────────────────────────────────────────────────────────── + + @staticmethod + def _print_welcome() -> None: + try: + version = importlib.metadata.version("litellm") + except Exception: + version = "unknown" + print() + print(orange(LITELLM_ASCII.rstrip("\n"))) + print(f" {orange('Welcome')} to {bold('LiteLLM')} {grey('v' + version)}") + print() + print(_divider()) + print() + + # ── provider selector ─────────────────────────────────────────────────── + + @staticmethod + def _select_providers() -> List[Dict]: + """Arrow-key multi-select. Falls back to number input if /dev/tty unavailable.""" + if not _HAS_RAW_TERMINAL: + return SetupWizard._select_fallback() + try: + return SetupWizard._select_interactive() + except OSError: + return SetupWizard._select_fallback() + + @staticmethod + def _read_key() -> str: + """Read one keypress from /dev/tty in raw mode.""" + assert ( + termios is not None and tty is not None + ) # only called when _HAS_RAW_TERMINAL + with open("/dev/tty", "rb") as tty_fh: + fd = tty_fh.fileno() + old = termios.tcgetattr(fd) + try: + tty.setraw(fd) + ch = tty_fh.read(1) + if ch == b"\x1b": + ch2 = tty_fh.read(1) + if ch2 == b"[": + ch3 = tty_fh.read(1) + return "\x1b[" + ch3.decode("utf-8", errors="replace") + return "\x1b" + ch2.decode("utf-8", errors="replace") + return ch.decode("utf-8", errors="replace") + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old) + + @staticmethod + def _render_selector(cursor: int, selected: Set[int], first_render: bool) -> int: + """Draw or redraw the provider list. Returns the number of lines printed.""" + lines = [ + f"\n {bold('Add your first model')}\n", + grey(" ↑↓ to navigate · Space to select · Enter to confirm") + "\n", + "\n", + ] + for i, p in enumerate(PROVIDERS): + arrow = blue("❯") if i == cursor else " " + bullet = green("◉") if i in selected else grey("○") + name_str = bold(p["name"]) if i == cursor else p["name"] + lines.append(f" {arrow} {bullet} {name_str} {grey(p['description'])}\n") + lines.append("\n") + + content = "".join(lines) + if not first_render and _supports_color(): + sys.stdout.write(_MOVE_UP.format(content.count("\n"))) + sys.stdout.write(content) + sys.stdout.flush() + return content.count("\n") + + @staticmethod + def _select_interactive() -> List[Dict]: + cursor = 0 + selected: set[int] = set() + + if _supports_color(): + sys.stdout.write(_CURSOR_HIDE) + sys.stdout.flush() + try: + SetupWizard._render_selector(cursor, selected, first_render=True) + while True: + key = SetupWizard._read_key() + dirty = False + if key == "\x1b[A": + cursor = (cursor - 1) % len(PROVIDERS) + dirty = True + elif key == "\x1b[B": + cursor = (cursor + 1) % len(PROVIDERS) + dirty = True + elif key == " ": + selected.symmetric_difference_update({cursor}) + dirty = True + elif key in ("\r", "\n"): + if not selected: + selected.add(cursor) + break + elif key in ("\x03", "\x04"): + raise KeyboardInterrupt + if dirty: + SetupWizard._render_selector(cursor, selected, first_render=False) + finally: + if _supports_color(): + sys.stdout.write(_CURSOR_SHOW) + sys.stdout.flush() + + return [PROVIDERS[i] for i in sorted(selected)] + + @staticmethod + def _select_fallback() -> List[Dict]: + """Number-based fallback when raw terminal input is unavailable.""" + print() + print(f" {bold('Add your first model')}") + print( + grey( + " Enter numbers separated by commas (e.g. 1,2). Press Enter to confirm." + ) + ) + print() + for i, p in enumerate(PROVIDERS, 1): + print(f" {grey(str(i) + '.')} {bold(p['name'])} {grey(p['description'])}") + print() + + while True: + raw = _styled_input(f" {blue('❯')} Provider(s): ") + if not raw: + print(grey(" Please select at least one provider.")) + continue + try: + nums = [ + int(x.strip()) + for x in raw.replace(" ", ",").split(",") + if x.strip() + ] + valid = sorted({n for n in nums if 1 <= n <= len(PROVIDERS)}) + if not valid: + print(grey(f" Enter numbers between 1 and {len(PROVIDERS)}.")) + continue + return [PROVIDERS[i - 1] for i in valid] + except ValueError: + print(grey(" Enter numbers separated by commas, e.g. 1,3")) + + # ── key collection ─────────────────────────────────────────────────────── + + @staticmethod + def _collect_keys(providers: List[Dict]) -> Dict[str, str]: + env_vars: Dict[str, str] = {} + print() + print(_divider()) + print() + print(f" {bold('Enter your API keys')}") + print(grey(" Keys are stored only in the generated config file.")) + print( + grey( + " Tip: add litellm_config.yaml to .gitignore to avoid committing secrets." + ) + ) + print() + + for p in providers: + if p["env_key"] is None: + print( + f" {green(p['name'])}: {grey('no key needed (uses local Ollama)')}" + ) + continue + + key = SetupWizard._prompt_key(p) + if not key: + continue + + for extra_key, extra_hint in zip( + p.get("extra_keys", []), p.get("extra_hints", []) + ): + val = _styled_input(f" {blue('❯')} {extra_key} {grey(extra_hint)}: ") + if val: + env_vars[extra_key] = val + + if p.get("needs_api_base"): + api_base = _styled_input( + f" {blue('❯')} Azure endpoint URL {grey(p.get('api_base_hint', ''))}: " + ) + if api_base: + env_vars[f"_LITELLM_AZURE_API_BASE_{p['id'].upper()}"] = api_base + deployment = _styled_input( + f" {blue('❯')} Azure deployment name {grey('(e.g. my-gpt4o)')}: " + ) + if deployment: + env_vars[ + f"_LITELLM_AZURE_DEPLOYMENT_{p['id'].upper()}" + ] = deployment + + # Store the key returned by validation — may be a re-entered replacement + env_vars[p["env_key"]] = SetupWizard._validate_and_report(p, key) + + return env_vars + + @staticmethod + def _prompt_key(provider: Dict) -> str: + """Prompt for a provider's API key, with skip option. Returns the key or ''.""" + hint = grey(provider.get("key_hint", "")) + while True: + key = _styled_input( + f" {blue('❯')} {bold(provider['name'])} API key {hint}: " + ) + if key: + return key + print(grey(" Key is required. Leave blank to skip this provider.")) + if _styled_input(grey(" Skip? (y/N): ")).lower() == "y": + return "" + + @staticmethod + def _validate_and_report(provider: Dict, api_key: str) -> str: + """ + Validate credentials using litellm.utils.check_valid_key and print result. + Offers a re-entry loop on failure. Returns the final (possibly re-entered) key. + """ + test_model: Optional[str] = provider.get("test_model") + if not test_model: + return api_key # Azure / Bedrock / Ollama — skip validation + + while True: + print( + f" {grey('Testing connection to ' + provider['name'] + '...')}", + flush=True, + ) + valid = check_valid_key(model=test_model, api_key=api_key) + if valid: + print( + f" {green(_CHECK)} {bold(provider['name'])} connected successfully" + ) + return api_key + + print(f" {_CROSS} {bold(provider['name'])} {grey('— invalid API key')}") + if ( + _styled_input(f" {blue('❯')} Re-enter key? {grey('(y/N)')}: ").lower() + != "y" + ): + return api_key + + hint = grey(provider.get("key_hint", "")) + new_key = _styled_input( + f" {blue('❯')} {bold(provider['name'])} API key {hint}: " + ) + if not new_key: + return api_key + api_key = new_key + + # ── proxy settings ─────────────────────────────────────────────────────── + + @staticmethod + def _proxy_settings() -> "tuple[int, str]": + print() + print(_divider()) + print() + print(f" {bold('Proxy settings')}") + print() + port = 4000 + while True: + port_raw = _styled_input(f" {blue('❯')} Port {grey('[4000]')}: ") + if not port_raw: + break + if port_raw.isdigit() and 1 <= int(port_raw) <= 65535: + port = int(port_raw) + break + print(grey(" Enter a valid port number (1–65535).")) + key_raw = _styled_input(f" {blue('❯')} Master key {grey('[auto-generate]')}: ") + master_key = key_raw if key_raw else f"sk-{secrets.token_urlsafe(32)}" + return port, master_key + + # ── config generation ──────────────────────────────────────────────────── + + @staticmethod + def _build_config( + providers: List[Dict], + env_vars: Dict[str, str], + master_key: str, + ) -> str: + env_copy = dict(env_vars) # work on a copy — do not mutate caller's dict + lines = ["model_list:"] + for p in providers: + # Only emit models for providers that actually have credentials + has_creds = p["env_key"] is None or p["env_key"] in env_copy + if not has_creds: + continue + + if p["id"] == "azure": + deployment = env_copy.pop( + f"_LITELLM_AZURE_DEPLOYMENT_{p['id'].upper()}", "" + ) + if not deployment: + continue # skip Azure entirely if no deployment name was provided + models = [f"azure/{deployment}"] + else: + models = p["models"] + + for model in models: + raw_display = model.split("/")[-1] if "/" in model else model + # Qualify azure display names to avoid collision with OpenAI model names + display = f"azure-{raw_display}" if p["id"] == "azure" else raw_display + lines += [ + f" - model_name: {display}", + " litellm_params:", + f" model: {model}", + ] + if p["env_key"] and p["env_key"] in env_copy: + lines.append(f" api_key: os.environ/{p['env_key']}") + if p.get("api_base"): + lines.append( + f' api_base: "{_yaml_escape(str(p["api_base"]))}"' + ) + elif p.get("needs_api_base"): + azure_base_key = f"_LITELLM_AZURE_API_BASE_{p['id'].upper()}" + if azure_base_key in env_copy: + lines.append( + f' api_base: "{_yaml_escape(env_copy.pop(azure_base_key))}"' + ) + if p.get("api_version"): + lines.append(f" api_version: {p['api_version']}") + + lines += [ + "", + "general_settings:", + f' master_key: "{_yaml_escape(master_key)}"', + "", + ] + + real_vars = {k: v for k, v in env_copy.items() if not k.startswith("_LITELLM_")} + if real_vars: + lines.append("environment_variables:") + for k, v in real_vars.items(): + lines.append(f' {k}: "{_yaml_escape(v)}"') + lines.append("") + + return "\n".join(lines) + + # ── success + launch ───────────────────────────────────────────────────── + + @staticmethod + def _print_success(config_path: Path, port: int, master_key: str) -> None: + print() + print(_divider()) + print() + print(f" {green(_CHECK + ' Config saved')} → {bold(str(config_path))}") + print() + print(f" {bold('To start your proxy:')}") + print() + print(f" {grey('$')} litellm --config {config_path} --port {port}") + print() + print(f" {bold('Then set your client:')}") + print() + print(f" export OPENAI_BASE_URL=http://localhost:{port}") + print(f" export OPENAI_API_KEY={master_key}") + print() + print(_divider()) + print() + + @staticmethod + def _offer_start(config_path: Path, port: int, master_key: str) -> None: + start = _styled_input( + f" {blue('❯')} Start the proxy now? {grey('(Y/n)')}: " + ).lower() + if start not in ("", "y", "yes"): + print() + print( + f" Run {bold(f'litellm --config {config_path}')} whenever you're ready." + ) + print() + print( + grey(f" Quick test once running: curl http://localhost:{port}/health") + ) + print() + return + + print() + print(_divider()) + print() + print(f" {bold('Proxy is starting on')} http://localhost:{port}") + print() + print(grey(" Your proxy is OpenAI-compatible. Point any OpenAI SDK at it:")) + print() + print(f" export OPENAI_BASE_URL=http://localhost:{port}") + print(f" export OPENAI_API_KEY={master_key}") + print() + print(grey(" Quick test (in another terminal):")) + print() + print(f" curl http://localhost:{port}/health") + print() + print(grey(" Dashboard:")) + print() + print(f" http://localhost:{port}/ui {grey('(login with your master key)')}") + print() + print(_divider()) + print() + print(f" {green(_CHECK)} Starting… {grey('(Ctrl+C to stop)')}") + print() + + scripts_dir = sysconfig.get_path("scripts") + litellm_bin = os.path.join(scripts_dir or "", "litellm") + try: + os.execlp( + litellm_bin, + litellm_bin, + "--config", + str(config_path), + "--port", + str(port), + ) # noqa: S606 + except OSError as exc: + print(f"\n {bold(_CROSS + ' Could not start proxy:')} {exc}") + print(f" Run manually: litellm --config {config_path} --port {port}\n") + + +# --------------------------------------------------------------------------- +# Public entrypoint +# --------------------------------------------------------------------------- + + +def run_setup_wizard() -> None: + """Run the interactive setup wizard. Called by `litellm --setup`.""" + SetupWizard.run() diff --git a/litellm/types/guardrails.py b/litellm/types/guardrails.py index 27fa27e6da..f798f05380 100644 --- a/litellm/types/guardrails.py +++ b/litellm/types/guardrails.py @@ -79,6 +79,7 @@ class SupportedGuardrailIntegrations(Enum): SEMANTIC_GUARD = "semantic_guard" MCP_END_USER_PERMISSION = "mcp_end_user_permission" BLOCK_CODE_EXECUTION = "block_code_execution" + MCP_JWT_SIGNER = "mcp_jwt_signer" class Role(Enum): diff --git a/litellm/types/proxy/vantage_endpoints.py b/litellm/types/proxy/vantage_endpoints.py index cf4f0a6685..84199e7834 100644 --- a/litellm/types/proxy/vantage_endpoints.py +++ b/litellm/types/proxy/vantage_endpoints.py @@ -39,7 +39,8 @@ class VantageExportRequest(BaseModel): """Request model for Vantage export operations (actual export, no default limit)""" limit: Optional[int] = Field( - None, description="Optional limit on number of records to export (default: no limit)" + None, + description="Optional limit on number of records to export (default: no limit)", ) start_time_utc: Optional[datetime] = Field( None, description="Start time for data export in UTC" diff --git a/litellm/types/videos/utils.py b/litellm/types/videos/utils.py index 3a100129bc..bf51fdda37 100644 --- a/litellm/types/videos/utils.py +++ b/litellm/types/videos/utils.py @@ -195,7 +195,9 @@ def decode_character_id_with_provider(encoded_character_id: str) -> DecodedChara character_id=decoded_character_id, ) except Exception as e: - verbose_logger.debug(f"Error decoding character_id '{encoded_character_id}': {e}") + verbose_logger.debug( + f"Error decoding character_id '{encoded_character_id}': {e}" + ) return DecodedCharacterId( custom_llm_provider=None, model_id=None, diff --git a/litellm/videos/main.py b/litellm/videos/main.py index d32a873e0b..cd61293cd1 100644 --- a/litellm/videos/main.py +++ b/litellm/videos/main.py @@ -1186,13 +1186,17 @@ def video_create_character( litellm_params = GenericLiteLLMParams(**kwargs) - provider_config: Optional[BaseVideoConfig] = ProviderConfigManager.get_provider_video_config( + provider_config: Optional[ + BaseVideoConfig + ] = ProviderConfigManager.get_provider_video_config( model=None, provider=litellm.LlmProviders(custom_llm_provider), ) if provider_config is None: - raise ValueError(f"video create character is not supported for {custom_llm_provider}") + raise ValueError( + f"video create character is not supported for {custom_llm_provider}" + ) local_vars.update(kwargs) request_params: Dict = {"name": name} @@ -1311,13 +1315,17 @@ def video_get_character( litellm_params = GenericLiteLLMParams(**kwargs) - provider_config: Optional[BaseVideoConfig] = ProviderConfigManager.get_provider_video_config( + provider_config: Optional[ + BaseVideoConfig + ] = ProviderConfigManager.get_provider_video_config( model=None, provider=litellm.LlmProviders(custom_llm_provider), ) if provider_config is None: - raise ValueError(f"video get character is not supported for {custom_llm_provider}") + raise ValueError( + f"video get character is not supported for {custom_llm_provider}" + ) local_vars.update(kwargs) request_params: Dict = {"character_id": character_id} @@ -1439,7 +1447,9 @@ def video_edit( litellm_params = GenericLiteLLMParams(**kwargs) - provider_config: Optional[BaseVideoConfig] = ProviderConfigManager.get_provider_video_config( + provider_config: Optional[ + BaseVideoConfig + ] = ProviderConfigManager.get_provider_video_config( model=None, provider=litellm.LlmProviders(custom_llm_provider), ) @@ -1572,16 +1582,24 @@ def video_extension( litellm_params = GenericLiteLLMParams(**kwargs) - provider_config: Optional[BaseVideoConfig] = ProviderConfigManager.get_provider_video_config( + provider_config: Optional[ + BaseVideoConfig + ] = ProviderConfigManager.get_provider_video_config( model=None, provider=litellm.LlmProviders(custom_llm_provider), ) if provider_config is None: - raise ValueError(f"video extension is not supported for {custom_llm_provider}") + raise ValueError( + f"video extension is not supported for {custom_llm_provider}" + ) local_vars.update(kwargs) - request_params: Dict = {"video_id": video_id, "prompt": prompt, "seconds": seconds} + request_params: Dict = { + "video_id": video_id, + "prompt": prompt, + "seconds": seconds, + } litellm_logging_obj.update_environment_variables( model="", diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 6786fc3359..181045809f 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -32354,6 +32354,53 @@ "supports_vision": true, "supports_web_search": true }, + "xai/grok-4.20-multi-agent-beta-0309": { + "cache_read_input_token_cost": 2e-07, + "input_cost_per_token": 2e-06, + "litellm_provider": "xai", + "max_input_tokens": 2000000, + "max_output_tokens": 2000000, + "max_tokens": 2000000, + "mode": "chat", + "output_cost_per_token": 6e-06, + "source": "https://docs.x.ai/docs/models", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true + }, + "xai/grok-4.20-beta-0309-reasoning": { + "cache_read_input_token_cost": 2e-07, + "input_cost_per_token": 2e-06, + "litellm_provider": "xai", + "max_input_tokens": 2000000, + "max_output_tokens": 2000000, + "max_tokens": 2000000, + "mode": "chat", + "output_cost_per_token": 6e-06, + "source": "https://docs.x.ai/docs/models", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true + }, + "xai/grok-4.20-beta-0309-non-reasoning": { + "cache_read_input_token_cost": 2e-07, + "input_cost_per_token": 2e-06, + "litellm_provider": "xai", + "max_input_tokens": 2000000, + "max_output_tokens": 2000000, + "max_tokens": 2000000, + "mode": "chat", + "output_cost_per_token": 6e-06, + "source": "https://docs.x.ai/docs/models", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true + }, "xai/grok-beta": { "input_cost_per_token": 5e-06, "litellm_provider": "xai", diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 0000000000..b9912287b7 --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env bash +# LiteLLM Installer +# Usage: curl -fsSL https://raw.githubusercontent.com/BerriAI/litellm/main/scripts/install.sh | sh +# +# NOTE: set -e without pipefail for POSIX sh compatibility (dash on Ubuntu/Debian +# ignores the shebang when invoked as `sh` and does not support `pipefail`). +set -eu + +MIN_PYTHON_MAJOR=3 +MIN_PYTHON_MINOR=9 + +# NOTE: before merging, this must stay as "litellm[proxy]" to install from PyPI. +LITELLM_PACKAGE="litellm[proxy]" + +# ── colours ──────────────────────────────────────────────────────────────── +if [ -t 1 ]; then + BOLD='\033[1m' + GREEN='\033[38;2;78;186;101m' + GREY='\033[38;2;153;153;153m' + RESET='\033[0m' +else + BOLD='' GREEN='' GREY='' RESET='' +fi + +info() { printf "${GREY} %s${RESET}\n" "$*"; } +success() { printf "${GREEN} ✔ %s${RESET}\n" "$*"; } +header() { printf "${BOLD} %s${RESET}\n" "$*"; } +die() { printf "\n Error: %s\n\n" "$*" >&2; exit 1; } + +# ── banner ───────────────────────────────────────────────────────────────── +echo "" +cat << 'EOF' + ██╗ ██╗████████╗███████╗██╗ ██╗ ███╗ ███╗ + ██║ ██║╚══██╔══╝██╔════╝██║ ██║ ████╗ ████║ + ██║ ██║ ██║ █████╗ ██║ ██║ ██╔████╔██║ + ██║ ██║ ██║ ██╔══╝ ██║ ██║ ██║╚██╔╝██║ + ███████╗██║ ██║ ███████╗███████╗███████╗██║ ╚═╝ ██║ + ╚══════╝╚═╝ ╚═╝ ╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝ +EOF +printf " ${BOLD}LiteLLM Installer${RESET} ${GREY}— unified gateway for 100+ LLM providers${RESET}\n\n" + +# ── OS detection ─────────────────────────────────────────────────────────── +OS="$(uname -s)" +ARCH="$(uname -m)" + +case "$OS" in + Darwin) PLATFORM="macOS ($ARCH)" ;; + Linux) PLATFORM="Linux ($ARCH)" ;; + *) die "Unsupported OS: $OS. LiteLLM supports macOS and Linux." ;; +esac + +info "Platform: $PLATFORM" + +# ── Python detection ─────────────────────────────────────────────────────── +PYTHON_BIN="" +for candidate in python3 python; do + if command -v "$candidate" >/dev/null 2>&1; then + major="$("$candidate" -c 'import sys; print(sys.version_info.major)' 2>/dev/null || true)" + minor="$("$candidate" -c 'import sys; print(sys.version_info.minor)' 2>/dev/null || true)" + if [ "${major:-0}" -ge "$MIN_PYTHON_MAJOR" ] && [ "${minor:-0}" -ge "$MIN_PYTHON_MINOR" ]; then + PYTHON_BIN="$(command -v "$candidate")" + info "Python: $("$candidate" --version 2>&1)" + break + fi + fi +done + +if [ -z "$PYTHON_BIN" ]; then + die "Python ${MIN_PYTHON_MAJOR}.${MIN_PYTHON_MINOR}+ is required but not found. + Install it from https://python.org/downloads or via your package manager: + macOS: brew install python@3 + Ubuntu: sudo apt install python3 python3-pip" +fi + +# ── pip detection ────────────────────────────────────────────────────────── +if ! "$PYTHON_BIN" -m pip --version >/dev/null 2>&1; then + die "pip is not available. Install it with: + $PYTHON_BIN -m ensurepip --upgrade" +fi + +# ── install ──────────────────────────────────────────────────────────────── +echo "" +header "Installing litellm[proxy]…" +echo "" + +"$PYTHON_BIN" -m pip install --upgrade "${LITELLM_PACKAGE}" \ + || die "pip install failed. Try manually: $PYTHON_BIN -m pip install '${LITELLM_PACKAGE}'" + +# ── find the litellm binary installed by pip for this Python ─────────────── +# sysconfig.get_path('scripts') is where pip puts console scripts — reliable +# even when the Python lives in a libexec/ symlink tree (e.g. Homebrew). +SCRIPTS_DIR="$("$PYTHON_BIN" -c 'import sysconfig; print(sysconfig.get_path("scripts"))')" +LITELLM_BIN="${SCRIPTS_DIR}/litellm" + +if [ ! -x "$LITELLM_BIN" ]; then + # Fall back to user-base bin (pip install --user) + USER_BIN="$("$PYTHON_BIN" -c 'import site; print(site.getuserbase())')/bin" + LITELLM_BIN="${USER_BIN}/litellm" +fi + +if [ ! -x "$LITELLM_BIN" ]; then + die "litellm binary not found after install. Try: $PYTHON_BIN -m pip install --user '${LITELLM_PACKAGE}'" +fi + +# ── success banner ───────────────────────────────────────────────────────── +echo "" +success "LiteLLM installed" + +installed_ver="$("$LITELLM_BIN" --version 2>&1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)" +[ -n "$installed_ver" ] && info "Version: $installed_ver" + +# ── PATH hint ────────────────────────────────────────────────────────────── +if ! command -v litellm >/dev/null 2>&1; then + info "Note: add litellm to your PATH: export PATH=\"\$PATH:${SCRIPTS_DIR}\"" +fi + +# ── launch setup wizard ──────────────────────────────────────────────────── +echo "" +printf " ${BOLD}Run the interactive setup wizard?${RESET} ${GREY}(Y/n)${RESET}: " +# /dev/tty may be unavailable in Docker/CI — default to yes if it can't be read +answer="" +if [ -r /dev/tty ]; then + read -r answer = 2, ( + f"Expected at least 2 batch items (trace-create + generation-create) " + f"after filtering by trace_id={trace_id}, " + f"but got {len(actual_request_body['batch'])}. " + f"Items: {json.dumps(actual_request_body['batch'], indent=2)}" + ) + # Replace dynamic values in actual request body for item in actual_request_body["batch"]: @@ -150,19 +173,36 @@ class TestLangfuseLogging: """Helper method to verify Langfuse API calls""" await asyncio.sleep(3) - # Verify the call + # Verify at least one call was made assert mock_post.call_count >= 1 - url = mock_post.call_args[0][0] - request_body = mock_post.call_args[1].get("content") - # Parse the JSON string into a dict for assertions - actual_request_body = json.loads(request_body) + # Aggregate batch items from ALL calls — the Langfuse SDK may split + # trace-create and generation-create across separate HTTP flushes. + langfuse_url = "https://us.cloud.langfuse.com/api/public/ingestion" + all_batch_items: list = [] + metadata: Optional[dict] = None + for call in mock_post.call_args_list: + url = call[0][0] + if url != langfuse_url: + continue + request_body = call[1].get("content") + if request_body: + body = json.loads(request_body) + all_batch_items.extend(body.get("batch", [])) + if metadata is None: + metadata = body.get("metadata") - print("\nMocked Request Details:") - print(f"URL: {url}") + assert len(all_batch_items) > 0, "No Langfuse ingestion calls found" + assert metadata is not None, "No metadata found in Langfuse calls" + + actual_request_body = { + "batch": all_batch_items, + "metadata": metadata, + } + + print("\nMocked Request Details (aggregated from all calls):") print(f"Request Body: {json.dumps(actual_request_body, indent=4)}") - assert url == "https://us.cloud.langfuse.com/api/public/ingestion" assert_langfuse_request_matches_expected( actual_request_body, expected_file_name, @@ -170,6 +210,7 @@ class TestLangfuseLogging: ) @pytest.mark.asyncio + @pytest.mark.flaky(retries=3, delay=1) async def test_langfuse_logging_completion(self, mock_setup): """Test Langfuse logging for chat completion""" setup = mock_setup @@ -185,6 +226,7 @@ class TestLangfuseLogging: ) @pytest.mark.asyncio + @pytest.mark.flaky(retries=3, delay=1) async def test_langfuse_logging_completion_with_tags(self, mock_setup): """Test Langfuse logging for chat completion with tags""" setup = mock_setup @@ -203,6 +245,7 @@ class TestLangfuseLogging: ) @pytest.mark.asyncio + @pytest.mark.flaky(retries=3, delay=1) async def test_langfuse_logging_completion_with_tags_stream(self, mock_setup): """Test Langfuse logging for chat completion with tags""" setup = mock_setup @@ -223,6 +266,7 @@ class TestLangfuseLogging: ) @pytest.mark.asyncio + @pytest.mark.flaky(retries=3, delay=1) async def test_langfuse_logging_completion_with_langfuse_metadata(self, mock_setup): """Test Langfuse logging for chat completion with metadata for langfuse""" setup = mock_setup @@ -252,6 +296,7 @@ class TestLangfuseLogging: ) @pytest.mark.asyncio + @pytest.mark.flaky(retries=3, delay=1) async def test_langfuse_logging_with_non_serializable_metadata(self, mock_setup): """Test Langfuse logging with metadata that requires preparation (Pydantic models, sets, etc)""" from pydantic import BaseModel @@ -358,6 +403,7 @@ class TestLangfuseLogging: ) @pytest.mark.asyncio + @pytest.mark.flaky(retries=3, delay=1) async def test_langfuse_logging_completion_with_malformed_llm_response( self, mock_setup ): @@ -387,6 +433,7 @@ class TestLangfuseLogging: ) @pytest.mark.asyncio + @pytest.mark.flaky(retries=3, delay=1) async def test_langfuse_logging_completion_with_bedrock_llm_response( self, mock_setup ): @@ -418,6 +465,7 @@ class TestLangfuseLogging: setup["mock_post"], "completion_with_bedrock_call.json", setup["trace_id"] ) @pytest.mark.asyncio + @pytest.mark.flaky(retries=3, delay=1) async def test_langfuse_logging_completion_with_vertex_llm_response( self, mock_setup ): @@ -449,6 +497,7 @@ class TestLangfuseLogging: ) @pytest.mark.asyncio + @pytest.mark.flaky(retries=3, delay=1) async def test_langfuse_logging_vllm_embedding(self, mock_setup): """ Test that the request sent to the vllm embedding endpoint is correct. @@ -500,6 +549,7 @@ class TestLangfuseLogging: ) @pytest.mark.asyncio + @pytest.mark.flaky(retries=3, delay=1) async def test_langfuse_logging_with_router(self, mock_setup): """Test Langfuse logging with router""" litellm._turn_on_debug() diff --git a/tests/spend_tracking_tests/test_spend_accuracy_tests.py b/tests/spend_tracking_tests/test_spend_accuracy_tests.py index 11b8e209dc..90efe28ab8 100644 --- a/tests/spend_tracking_tests/test_spend_accuracy_tests.py +++ b/tests/spend_tracking_tests/test_spend_accuracy_tests.py @@ -308,16 +308,19 @@ async def test_long_term_spend_accuracy_with_bursts(): response = await chat_completion(session, key) print(f"Burst 2 - Request {i + 1}/{BURST_2_REQUESTS} completed") - # Poll until key spend reflects burst 2 - burst_1_spend = intermediate_key_info["info"]["spend"] + # Poll until key spend reaches expected total (burst 1 + burst 2) start = time.time() while time.time() - start < 120: key_info_check = await get_spend_info(session, "key", key) current_spend = key_info_check["info"]["spend"] - if current_spend > burst_1_spend: - print(f"Key spend increased to {current_spend} after {time.time() - start:.1f}s") + if abs(current_spend - expected_spend) < TOLERANCE: + print( + f"Total spend reached expected {expected_spend} after {time.time() - start:.1f}s" + ) break - print(f"Key spend still {current_spend}, waiting for burst 2 flush...") + print( + f"Key spend {current_spend}, expected {expected_spend}, waiting..." + ) await asyncio.sleep(10) # Allow extra time for all entity spend aggregations diff --git a/tests/test_litellm/interactions/test_openapi_compliance.py b/tests/test_litellm/interactions/test_openapi_compliance.py index 5b2edcf1ee..a22244f3f8 100644 --- a/tests/test_litellm/interactions/test_openapi_compliance.py +++ b/tests/test_litellm/interactions/test_openapi_compliance.py @@ -77,6 +77,11 @@ class TestRequestCompliance: schema = spec_dict["components"]["schemas"]["CreateModelInteractionParams"] input_schema = schema["properties"]["input"] + # The input property may be inline oneOf or a $ref to InteractionsInput + if "$ref" in input_schema: + ref_name = input_schema["$ref"].split("/")[-1] + input_schema = spec_dict["components"]["schemas"][ref_name] + # Should be oneOf with multiple types assert "oneOf" in input_schema @@ -100,10 +105,21 @@ class TestRequestCompliance: assert "discriminator" in content_schema assert content_schema["discriminator"]["propertyName"] == "type" - # Check TextContent is an option - mapping = content_schema["discriminator"]["mapping"] - assert "text" in mapping - print(f"Content type discriminator mapping: {list(mapping.keys())}") + # Check TextContent is an option (via mapping if present, or via oneOf refs) + mapping = content_schema["discriminator"].get("mapping") + if mapping: + assert "text" in mapping + print(f"Content type discriminator mapping: {list(mapping.keys())}") + else: + # Discriminator without explicit mapping — verify via oneOf + one_of = content_schema.get("oneOf", []) + ref_names = [ + opt["$ref"].split("/")[-1] for opt in one_of if "$ref" in opt + ] + assert "TextContent" in ref_names, ( + f"TextContent not found in oneOf refs: {ref_names}" + ) + print(f"Content type discriminator (no mapping), oneOf refs: {ref_names}") def test_text_content_schema(self, spec_dict): """Verify TextContent schema.""" diff --git a/tests/test_litellm/llms/xai/test_xai_cost_calculator.py b/tests/test_litellm/llms/xai/test_xai_cost_calculator.py index 1c2de953c2..00955bc525 100644 --- a/tests/test_litellm/llms/xai/test_xai_cost_calculator.py +++ b/tests/test_litellm/llms/xai/test_xai_cost_calculator.py @@ -386,8 +386,56 @@ class TestXAICostCalculator: completion_tokens=50, total_tokens=150, ) - + web_search_cost = cost_per_web_search_request(usage=usage, model_info={}) - + # Expected cost: No web search data = $0.0 assert web_search_cost == 0.0 + + def test_grok_4_20_beta_reasoning_cost_calculation(self): + """Test cost calculation for grok-4.20-beta-0309-reasoning model.""" + usage = Usage(prompt_tokens=100, completion_tokens=200, total_tokens=300) + + prompt_cost, completion_cost = cost_per_token( + model="grok-4.20-beta-0309-reasoning", usage=usage + ) + + # Input: 100 tokens * $2e-6 = $0.0002 + # Output: 200 tokens * $6e-6 = $0.0012 + expected_prompt_cost = 100 * 2e-6 + expected_completion_cost = 200 * 6e-6 + + assert math.isclose(prompt_cost, expected_prompt_cost, rel_tol=1e-10) + assert math.isclose(completion_cost, expected_completion_cost, rel_tol=1e-10) + + def test_grok_4_20_beta_non_reasoning_cost_calculation(self): + """Test cost calculation for grok-4.20-beta-0309-non-reasoning model.""" + usage = Usage(prompt_tokens=50, completion_tokens=100, total_tokens=150) + + prompt_cost, completion_cost = cost_per_token( + model="grok-4.20-beta-0309-non-reasoning", usage=usage + ) + + # Input: 50 tokens * $2e-6 = $0.0001 + # Output: 100 tokens * $6e-6 = $0.0006 + expected_prompt_cost = 50 * 2e-6 + expected_completion_cost = 100 * 6e-6 + + assert math.isclose(prompt_cost, expected_prompt_cost, rel_tol=1e-10) + assert math.isclose(completion_cost, expected_completion_cost, rel_tol=1e-10) + + def test_grok_4_20_multi_agent_cost_calculation(self): + """Test cost calculation for grok-4.20-multi-agent-beta-0309 model.""" + usage = Usage(prompt_tokens=200, completion_tokens=300, total_tokens=500) + + prompt_cost, completion_cost = cost_per_token( + model="grok-4.20-multi-agent-beta-0309", usage=usage + ) + + # Input: 200 tokens * $2e-6 = $0.0004 + # Output: 300 tokens * $6e-6 = $0.0018 + expected_prompt_cost = 200 * 2e-6 + expected_completion_cost = 300 * 6e-6 + + assert math.isclose(prompt_cost, expected_prompt_cost, rel_tol=1e-10) + assert math.isclose(completion_cost, expected_completion_cost, rel_tol=1e-10) diff --git a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_hook_extra_headers.py b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_hook_extra_headers.py new file mode 100644 index 0000000000..32f3a34085 --- /dev/null +++ b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_hook_extra_headers.py @@ -0,0 +1,707 @@ +""" +Tests for pre_mcp_call guardrail hook header mutation support. + +Validates that: +1. _convert_mcp_hook_response_to_kwargs extracts extra_headers from hook response +2. pre_call_tool_check returns hook-provided extra_headers AND modified arguments +3. call_tool flows hook headers and modified arguments downstream +4. Hook-provided headers take highest priority (merge after static_headers) +5. OpenAPI-backed servers log a warning and continue (skip injection) when hook headers are present +6. JWT claims are propagated in both standard and virtual-key fast paths +7. Backward compatibility: hooks without extra_headers continue to work +""" + +import asyncio +from typing import Any, Dict, Optional +from unittest.mock import AsyncMock, MagicMock, patch + +import pytest +from fastapi import HTTPException + +from litellm.proxy._experimental.mcp_server.mcp_server_manager import MCPServerManager +from litellm.proxy._types import UserAPIKeyAuth +from litellm.proxy.utils import ProxyLogging +from litellm.types.mcp import MCPAuth, MCPTransport +from litellm.types.mcp_server.mcp_server_manager import MCPServer + + +class TestConvertMcpHookResponseToKwargs: + """Tests for ProxyLogging._convert_mcp_hook_response_to_kwargs""" + + def setup_method(self): + self.proxy_logging = ProxyLogging(user_api_key_cache=MagicMock()) + + def test_returns_original_kwargs_when_response_is_none(self): + original = {"arguments": {"key": "val"}, "name": "tool"} + result = self.proxy_logging._convert_mcp_hook_response_to_kwargs( + None, original + ) + assert result == original + + def test_returns_original_kwargs_when_response_is_empty_dict(self): + original = {"arguments": {"key": "val"}} + result = self.proxy_logging._convert_mcp_hook_response_to_kwargs({}, original) + assert result == original + + def test_extracts_modified_arguments(self): + original = {"arguments": {"old": "value"}} + response = {"modified_arguments": {"new": "value"}} + result = self.proxy_logging._convert_mcp_hook_response_to_kwargs( + response, original + ) + assert result["arguments"] == {"new": "value"} + + def test_extracts_extra_headers(self): + original = {"arguments": {"key": "val"}} + response = {"extra_headers": {"Authorization": "Bearer signed-jwt"}} + result = self.proxy_logging._convert_mcp_hook_response_to_kwargs( + response, original + ) + assert result["extra_headers"] == {"Authorization": "Bearer signed-jwt"} + + def test_extracts_both_arguments_and_headers(self): + original = {"arguments": {"old": "value"}} + response = { + "modified_arguments": {"new": "value"}, + "extra_headers": {"X-Custom": "header-val"}, + } + result = self.proxy_logging._convert_mcp_hook_response_to_kwargs( + response, original + ) + assert result["arguments"] == {"new": "value"} + assert result["extra_headers"] == {"X-Custom": "header-val"} + + def test_no_extra_headers_key_preserves_original(self): + """Backward compat: hooks that only return modified_arguments still work.""" + original = {"arguments": {"key": "val"}} + response = {"modified_arguments": {"key": "new_val"}} + result = self.proxy_logging._convert_mcp_hook_response_to_kwargs( + response, original + ) + assert "extra_headers" not in result + assert result["arguments"] == {"key": "new_val"} + + def test_empty_extra_headers_not_set(self): + """Empty dict for extra_headers is falsy and should not be set.""" + original = {"arguments": {"key": "val"}} + response = {"extra_headers": {}} + result = self.proxy_logging._convert_mcp_hook_response_to_kwargs( + response, original + ) + assert "extra_headers" not in result + + +class TestPreCallToolCheckReturnsHeaders: + """Tests that pre_call_tool_check returns hook-provided headers.""" + + def _make_server(self, name="test_server"): + return MCPServer( + server_id="test-id", + name=name, + server_name=name, + url="https://example.com", + transport=MCPTransport.http, + auth_type=MCPAuth.none, + ) + + @pytest.mark.asyncio + async def test_returns_empty_dict_when_hook_has_no_headers(self): + manager = MCPServerManager() + server = self._make_server() + + proxy_logging = MagicMock(spec=ProxyLogging) + proxy_logging._create_mcp_request_object_from_kwargs = MagicMock( + return_value=MagicMock() + ) + proxy_logging._convert_mcp_to_llm_format = MagicMock( + return_value={"model": "fake"} + ) + proxy_logging.pre_call_hook = AsyncMock( + return_value={"modified_arguments": {"key": "val"}} + ) + proxy_logging._convert_mcp_hook_response_to_kwargs = MagicMock( + return_value={"arguments": {"key": "val"}} + ) + + with patch.object(manager, "check_allowed_or_banned_tools", return_value=True): + with patch.object( + manager, + "check_tool_permission_for_key_team", + new_callable=AsyncMock, + ): + with patch.object(manager, "validate_allowed_params"): + result = await manager.pre_call_tool_check( + name="test_tool", + arguments={"key": "val"}, + server_name="test_server", + user_api_key_auth=None, + proxy_logging_obj=proxy_logging, + server=server, + ) + + assert result == {} + + @pytest.mark.asyncio + async def test_returns_extra_headers_from_hook(self): + manager = MCPServerManager() + server = self._make_server() + + hook_headers = {"Authorization": "Bearer signed-jwt", "X-Trace-Id": "abc123"} + + proxy_logging = MagicMock(spec=ProxyLogging) + proxy_logging._create_mcp_request_object_from_kwargs = MagicMock( + return_value=MagicMock() + ) + proxy_logging._convert_mcp_to_llm_format = MagicMock( + return_value={"model": "fake"} + ) + proxy_logging.pre_call_hook = AsyncMock( + return_value={"extra_headers": hook_headers} + ) + proxy_logging._convert_mcp_hook_response_to_kwargs = MagicMock( + return_value={"arguments": {"key": "val"}, "extra_headers": hook_headers} + ) + + with patch.object(manager, "check_allowed_or_banned_tools", return_value=True): + with patch.object( + manager, + "check_tool_permission_for_key_team", + new_callable=AsyncMock, + ): + with patch.object(manager, "validate_allowed_params"): + result = await manager.pre_call_tool_check( + name="test_tool", + arguments={"key": "val"}, + server_name="test_server", + user_api_key_auth=None, + proxy_logging_obj=proxy_logging, + server=server, + ) + + assert result["extra_headers"] == hook_headers + + @pytest.mark.asyncio + async def test_returns_empty_dict_when_hook_returns_none(self): + manager = MCPServerManager() + server = self._make_server() + + proxy_logging = MagicMock(spec=ProxyLogging) + proxy_logging._create_mcp_request_object_from_kwargs = MagicMock( + return_value=MagicMock() + ) + proxy_logging._convert_mcp_to_llm_format = MagicMock( + return_value={"model": "fake"} + ) + proxy_logging.pre_call_hook = AsyncMock(return_value=None) + + with patch.object(manager, "check_allowed_or_banned_tools", return_value=True): + with patch.object( + manager, + "check_tool_permission_for_key_team", + new_callable=AsyncMock, + ): + with patch.object(manager, "validate_allowed_params"): + result = await manager.pre_call_tool_check( + name="test_tool", + arguments={"key": "val"}, + server_name="test_server", + user_api_key_auth=None, + proxy_logging_obj=proxy_logging, + server=server, + ) + + assert result == {} + + @pytest.mark.asyncio + async def test_returns_modified_arguments_from_hook(self): + """Modified arguments from the hook must be returned so the caller can use them.""" + manager = MCPServerManager() + server = self._make_server() + + original_args = {"key": "original"} + modified_args = {"key": "modified", "extra": "added"} + + proxy_logging = MagicMock(spec=ProxyLogging) + proxy_logging._create_mcp_request_object_from_kwargs = MagicMock( + return_value=MagicMock() + ) + proxy_logging._convert_mcp_to_llm_format = MagicMock( + return_value={"model": "fake"} + ) + proxy_logging.pre_call_hook = AsyncMock( + return_value={"modified_arguments": modified_args} + ) + proxy_logging._convert_mcp_hook_response_to_kwargs = MagicMock( + return_value={"arguments": modified_args} + ) + + with patch.object(manager, "check_allowed_or_banned_tools", return_value=True): + with patch.object( + manager, + "check_tool_permission_for_key_team", + new_callable=AsyncMock, + ): + with patch.object(manager, "validate_allowed_params"): + result = await manager.pre_call_tool_check( + name="test_tool", + arguments=original_args, + server_name="test_server", + user_api_key_auth=None, + proxy_logging_obj=proxy_logging, + server=server, + ) + + assert result["arguments"] == modified_args + + @pytest.mark.asyncio + async def test_returns_both_modified_arguments_and_headers(self): + """Hook can modify both arguments and inject headers simultaneously.""" + manager = MCPServerManager() + server = self._make_server() + + modified_args = {"key": "modified"} + hook_headers = {"Authorization": "Bearer jwt"} + + proxy_logging = MagicMock(spec=ProxyLogging) + proxy_logging._create_mcp_request_object_from_kwargs = MagicMock( + return_value=MagicMock() + ) + proxy_logging._convert_mcp_to_llm_format = MagicMock( + return_value={"model": "fake"} + ) + proxy_logging.pre_call_hook = AsyncMock(return_value={"dummy": True}) + proxy_logging._convert_mcp_hook_response_to_kwargs = MagicMock( + return_value={"arguments": modified_args, "extra_headers": hook_headers} + ) + + with patch.object(manager, "check_allowed_or_banned_tools", return_value=True): + with patch.object( + manager, + "check_tool_permission_for_key_team", + new_callable=AsyncMock, + ): + with patch.object(manager, "validate_allowed_params"): + result = await manager.pre_call_tool_check( + name="test_tool", + arguments={"key": "original"}, + server_name="test_server", + user_api_key_auth=None, + proxy_logging_obj=proxy_logging, + server=server, + ) + + assert result["arguments"] == modified_args + assert result["extra_headers"] == hook_headers + + +class TestCallToolFlowsHookHeaders: + """Tests that call_tool passes hook_extra_headers to _call_regular_mcp_tool.""" + + def _make_server(self, name="test_server"): + return MCPServer( + server_id="test-id", + name=name, + server_name=name, + url="https://example.com", + transport=MCPTransport.http, + auth_type=MCPAuth.none, + ) + + @pytest.mark.asyncio + async def test_hook_headers_passed_to_call_regular_mcp_tool(self): + """Verify that hook_extra_headers kwarg is forwarded.""" + manager = MCPServerManager() + server = self._make_server() + + hook_headers = {"Authorization": "Bearer signed-jwt"} + + with patch.object( + manager, + "_get_mcp_server_from_tool_name", + return_value=server, + ): + with patch.object( + manager, + "pre_call_tool_check", + new_callable=AsyncMock, + return_value={"extra_headers": hook_headers}, + ): + with patch.object( + manager, + "_create_during_hook_task", + return_value=asyncio.create_task(asyncio.sleep(0)), + ): + with patch.object( + manager, + "_call_regular_mcp_tool", + new_callable=AsyncMock, + return_value=MagicMock(), + ) as mock_call: + proxy_logging = MagicMock(spec=ProxyLogging) + + await manager.call_tool( + server_name="test_server", + name="test_tool", + arguments={"key": "val"}, + proxy_logging_obj=proxy_logging, + ) + + mock_call.assert_called_once() + call_kwargs = mock_call.call_args + assert call_kwargs.kwargs.get("hook_extra_headers") == hook_headers + + @pytest.mark.asyncio + async def test_no_hook_headers_when_no_proxy_logging(self): + """Without proxy_logging_obj, no pre_call_tool_check runs.""" + manager = MCPServerManager() + server = self._make_server() + + with patch.object( + manager, + "_get_mcp_server_from_tool_name", + return_value=server, + ): + with patch.object( + manager, + "_call_regular_mcp_tool", + new_callable=AsyncMock, + return_value=MagicMock(), + ) as mock_call: + await manager.call_tool( + server_name="test_server", + name="test_tool", + arguments={"key": "val"}, + proxy_logging_obj=None, + ) + + mock_call.assert_called_once() + call_kwargs = mock_call.call_args + assert call_kwargs.kwargs.get("hook_extra_headers") is None + + @pytest.mark.asyncio + async def test_modified_arguments_passed_to_downstream(self): + """Hook-modified arguments must be used for the actual tool call.""" + manager = MCPServerManager() + server = self._make_server() + + modified_args = {"key": "modified_by_hook"} + + with patch.object( + manager, + "_get_mcp_server_from_tool_name", + return_value=server, + ): + with patch.object( + manager, + "pre_call_tool_check", + new_callable=AsyncMock, + return_value={"arguments": modified_args}, + ): + with patch.object( + manager, + "_create_during_hook_task", + return_value=asyncio.create_task(asyncio.sleep(0)), + ): + with patch.object( + manager, + "_call_regular_mcp_tool", + new_callable=AsyncMock, + return_value=MagicMock(), + ) as mock_call: + proxy_logging = MagicMock(spec=ProxyLogging) + + await manager.call_tool( + server_name="test_server", + name="test_tool", + arguments={"key": "original"}, + proxy_logging_obj=proxy_logging, + ) + + mock_call.assert_called_once() + call_kwargs = mock_call.call_args + assert call_kwargs.kwargs.get("arguments") == modified_args + + @pytest.mark.asyncio + async def test_openapi_server_warns_and_continues_on_hook_headers(self): + """OpenAPI-backed servers log a warning and continue when hook injects headers.""" + manager = MCPServerManager() + server = MCPServer( + server_id="test-id", + name="openapi_server", + server_name="openapi_server", + url="https://example.com", + transport=MCPTransport.http, + auth_type=MCPAuth.none, + spec_path="/path/to/spec.yaml", + ) + + with patch.object( + manager, "_get_mcp_server_from_tool_name", return_value=server + ): + with patch.object( + manager, + "pre_call_tool_check", + new_callable=AsyncMock, + return_value={"extra_headers": {"Authorization": "Bearer jwt"}}, + ): + with patch.object( + manager, + "_create_during_hook_task", + return_value=asyncio.create_task(asyncio.sleep(0)), + ): + with patch.object( + manager, + "_call_openapi_tool_handler", + new_callable=AsyncMock, + return_value=MagicMock(), + ): + import litellm.proxy._experimental.mcp_server.mcp_server_manager as mgr_mod + + proxy_logging = MagicMock(spec=ProxyLogging) + + with patch.object(mgr_mod, "verbose_logger") as mock_logger: + # Should NOT raise — just warn and proceed + await manager.call_tool( + server_name="openapi_server", + name="test_tool", + arguments={}, + proxy_logging_obj=proxy_logging, + ) + mock_logger.warning.assert_called_once() + assert "header injection is not supported" in mock_logger.warning.call_args[0][0] + + @pytest.mark.asyncio + async def test_openapi_server_no_error_without_hook_headers(self): + """No exception when OpenAPI server has no hook-injected headers.""" + manager = MCPServerManager() + server = MCPServer( + server_id="test-id", + name="openapi_server", + server_name="openapi_server", + url="https://example.com", + transport=MCPTransport.http, + auth_type=MCPAuth.none, + spec_path="/path/to/spec.yaml", + ) + + with patch.object( + manager, "_get_mcp_server_from_tool_name", return_value=server + ): + with patch.object( + manager, + "pre_call_tool_check", + new_callable=AsyncMock, + return_value={}, + ): + with patch.object( + manager, + "_create_during_hook_task", + return_value=asyncio.create_task(asyncio.sleep(0)), + ): + with patch.object( + manager, + "_call_openapi_tool_handler", + new_callable=AsyncMock, + return_value=MagicMock(), + ): + proxy_logging = MagicMock(spec=ProxyLogging) + + await manager.call_tool( + server_name="openapi_server", + name="test_tool", + arguments={}, + proxy_logging_obj=proxy_logging, + ) + + +class TestHookHeaderMergePriority: + """Tests that hook-provided headers have highest priority in _call_regular_mcp_tool.""" + + def _make_server( + self, + static_headers: Optional[Dict[str, str]] = None, + extra_headers_config: Optional[list] = None, + ): + return MCPServer( + server_id="test-id", + name="Test Server", + server_name="test_server", + url="https://example.com", + transport=MCPTransport.http, + auth_type=MCPAuth.none, + static_headers=static_headers, + extra_headers=extra_headers_config, + ) + + @pytest.mark.asyncio + async def test_hook_headers_override_static_headers(self): + """Hook headers should take precedence over static_headers.""" + manager = MCPServerManager() + server = self._make_server( + static_headers={"Authorization": "Bearer static-token", "X-Static": "yes"} + ) + + hook_headers = {"Authorization": "Bearer hook-signed-jwt"} + + captured_extra_headers: Dict[str, Any] = {} + + async def fake_create_mcp_client( + server, mcp_auth_header=None, extra_headers=None, stdio_env=None + ): + captured_extra_headers["value"] = extra_headers + mock_client = MagicMock() + mock_client.call_tool = AsyncMock(return_value=MagicMock()) + return mock_client + + with patch.object( + manager, "_create_mcp_client", side_effect=fake_create_mcp_client + ): + with patch.object(manager, "_build_stdio_env", return_value=None): + try: + await manager._call_regular_mcp_tool( + mcp_server=server, + original_tool_name="test_tool", + arguments={"key": "val"}, + tasks=[], + mcp_auth_header=None, + mcp_server_auth_headers=None, + oauth2_headers=None, + raw_headers=None, + proxy_logging_obj=None, + hook_extra_headers=hook_headers, + ) + except Exception: + pass + + headers = captured_extra_headers.get("value", {}) + assert headers["Authorization"] == "Bearer hook-signed-jwt" + assert headers["X-Static"] == "yes" + + @pytest.mark.asyncio + async def test_no_hook_headers_preserves_existing_behavior(self): + """When hook_extra_headers is None, existing header logic is unchanged.""" + manager = MCPServerManager() + server = self._make_server( + static_headers={"X-Static": "static-value"} + ) + + captured_extra_headers: Dict[str, Any] = {} + + async def fake_create_mcp_client( + server, mcp_auth_header=None, extra_headers=None, stdio_env=None + ): + captured_extra_headers["value"] = extra_headers + mock_client = MagicMock() + mock_client.call_tool = AsyncMock(return_value=MagicMock()) + return mock_client + + with patch.object( + manager, "_create_mcp_client", side_effect=fake_create_mcp_client + ): + with patch.object(manager, "_build_stdio_env", return_value=None): + try: + await manager._call_regular_mcp_tool( + mcp_server=server, + original_tool_name="test_tool", + arguments={"key": "val"}, + tasks=[], + mcp_auth_header=None, + mcp_server_auth_headers=None, + oauth2_headers=None, + raw_headers=None, + proxy_logging_obj=None, + hook_extra_headers=None, + ) + except Exception: + pass + + headers = captured_extra_headers.get("value", {}) + assert headers == {"X-Static": "static-value"} + + @pytest.mark.asyncio + async def test_hook_headers_merge_with_oauth2(self): + """Hook headers merge on top of OAuth2 headers.""" + manager = MCPServerManager() + server = MCPServer( + server_id="test-id", + name="Test Server", + server_name="test_server", + url="https://example.com", + transport=MCPTransport.http, + auth_type=MCPAuth.oauth2, + ) + + captured_extra_headers: Dict[str, Any] = {} + + async def fake_create_mcp_client( + server, mcp_auth_header=None, extra_headers=None, stdio_env=None + ): + captured_extra_headers["value"] = extra_headers + mock_client = MagicMock() + mock_client.call_tool = AsyncMock(return_value=MagicMock()) + return mock_client + + with patch.object( + manager, "_create_mcp_client", side_effect=fake_create_mcp_client + ): + with patch.object(manager, "_build_stdio_env", return_value=None): + try: + await manager._call_regular_mcp_tool( + mcp_server=server, + original_tool_name="test_tool", + arguments={"key": "val"}, + tasks=[], + mcp_auth_header=None, + mcp_server_auth_headers=None, + oauth2_headers={ + "Authorization": "Bearer oauth2-token", + "X-OAuth": "yes", + }, + raw_headers=None, + proxy_logging_obj=None, + hook_extra_headers={ + "Authorization": "Bearer hook-jwt", + "X-Trace-Id": "trace-123", + }, + ) + except Exception: + pass + + headers = captured_extra_headers.get("value", {}) + assert headers["Authorization"] == "Bearer hook-jwt" + assert headers["X-OAuth"] == "yes" + assert headers["X-Trace-Id"] == "trace-123" + + +class TestUserAPIKeyAuthJwtClaims: + """Tests that UserAPIKeyAuth correctly carries jwt_claims.""" + + def test_jwt_claims_field_defaults_to_none(self): + auth = UserAPIKeyAuth(api_key="test-key") + assert auth.jwt_claims is None + + def test_jwt_claims_field_accepts_dict(self): + claims = {"sub": "user-123", "iss": "litellm", "exp": 9999999999} + auth = UserAPIKeyAuth(api_key="test-key", jwt_claims=claims) + assert auth.jwt_claims == claims + assert auth.jwt_claims["sub"] == "user-123" + + def test_jwt_claims_backward_compatible_without_field(self): + """Existing code that doesn't pass jwt_claims should still work.""" + auth = UserAPIKeyAuth( + api_key="test-key", + user_id="user-1", + team_id="team-1", + ) + assert auth.jwt_claims is None + assert auth.user_id == "user-1" + + def test_jwt_claims_set_after_construction(self): + """Virtual-key fast path sets jwt_claims after the object is created.""" + auth = UserAPIKeyAuth(api_key="test-key") + assert auth.jwt_claims is None + + claims = {"sub": "user-456", "iss": "okta", "groups": ["admin"]} + auth.jwt_claims = claims + assert auth.jwt_claims == claims + assert auth.jwt_claims["groups"] == ["admin"] diff --git a/tests/test_litellm/proxy/guardrails/test_mcp_jwt_signer.py b/tests/test_litellm/proxy/guardrails/test_mcp_jwt_signer.py new file mode 100644 index 0000000000..247fe7b576 --- /dev/null +++ b/tests/test_litellm/proxy/guardrails/test_mcp_jwt_signer.py @@ -0,0 +1,1103 @@ +""" +Tests for the MCPJWTSigner built-in guardrail. + +Tests cover: + - RSA key generation and loading + - JWT signing and JWKS format + - Claim building (sub, act, scope) + - Hook fires for call_mcp_tool, skips other call types + - get_mcp_jwt_signer() singleton pattern +""" + +import base64 +import time +from typing import Any, Dict, Optional +from unittest.mock import AsyncMock, MagicMock, patch + +import jwt +import pytest +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import rsa + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + + +def _make_user_api_key_dict( + user_id: str = "user-123", + team_id: str = "team-abc", + user_email: str = "user@example.com", + end_user_id: Optional[str] = None, +) -> MagicMock: + mock = MagicMock() + mock.user_id = user_id + mock.team_id = team_id + mock.user_email = user_email + mock.end_user_id = end_user_id + mock.org_id = None + mock.token = None + mock.api_key = None + # Explicit None so MagicMock doesn't auto-create a truthy proxy attribute + mock.jwt_claims = None + return mock + + +def _decode_unverified(token: str) -> Dict[str, Any]: + return jwt.decode(token, options={"verify_signature": False}) + + +# --------------------------------------------------------------------------- +# Import target (inline so we can reset the singleton between tests) +# --------------------------------------------------------------------------- + + +def _make_signer(**kwargs: Any): + # Reset singleton before each signer creation to avoid cross-test pollution + import litellm.proxy.guardrails.guardrail_hooks.mcp_jwt_signer.mcp_jwt_signer as mod + + mod._mcp_jwt_signer_instance = None + + from litellm.proxy.guardrails.guardrail_hooks.mcp_jwt_signer.mcp_jwt_signer import ( + MCPJWTSigner, + ) + + return MCPJWTSigner( + guardrail_name="test-jwt-signer", + event_hook="pre_mcp_call", + default_on=True, + **kwargs, + ) + + +# --------------------------------------------------------------------------- +# Key generation tests +# --------------------------------------------------------------------------- + + +def test_auto_generates_rsa_keypair(): + """MCPJWTSigner auto-generates an RSA-2048 keypair when env var is unset.""" + signer = _make_signer() + assert signer._private_key is not None + assert signer._public_key is not None + assert signer._kid is not None and len(signer._kid) == 16 + + +def test_kid_is_deterministic(): + """Two signers built from the same key have the same kid.""" + signer1 = _make_signer() + private_pem = signer1._private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ).decode("utf-8") + + with patch.dict("os.environ", {"MCP_JWT_SIGNING_KEY": private_pem}): + signer2 = _make_signer() + + assert signer1._kid == signer2._kid + + +def test_load_key_from_env_var(): + """MCPJWTSigner loads a user-provided RSA key from the env var.""" + private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) + pem = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ).decode("utf-8") + + with patch.dict("os.environ", {"MCP_JWT_SIGNING_KEY": pem}): + signer = _make_signer() + + assert signer._kid is not None + + +# --------------------------------------------------------------------------- +# JWKS tests +# --------------------------------------------------------------------------- + + +def test_get_jwks_format(): + """get_jwks() returns a valid JWKS dict with RSA fields.""" + signer = _make_signer() + jwks = signer.get_jwks() + + assert "keys" in jwks + assert len(jwks["keys"]) == 1 + key = jwks["keys"][0] + + assert key["kty"] == "RSA" + assert key["alg"] == "RS256" + assert key["use"] == "sig" + assert key["kid"] == signer._kid + assert "n" in key and len(key["n"]) > 0 + assert "e" in key and key["e"] == "AQAB" # 65537 in base64url + + +def test_jwks_public_key_can_verify_signed_jwt(): + """A JWT signed by MCPJWTSigner can be verified using the JWKS public key.""" + signer = _make_signer(issuer="https://litellm.example.com", audience="mcp") + now = int(time.time()) + claims = {"iss": "https://litellm.example.com", "aud": "mcp", "iat": now, "exp": now + 300} + + token = jwt.encode(claims, signer._private_key, algorithm="RS256") + + # Reconstruct public key from JWKS + jwks = signer.get_jwks() + key_data = jwks["keys"][0] + n = int.from_bytes(base64.urlsafe_b64decode(key_data["n"] + "=="), byteorder="big") + e = int.from_bytes(base64.urlsafe_b64decode(key_data["e"] + "=="), byteorder="big") + from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers + pub_key = RSAPublicNumbers(e=e, n=n).public_key() + + decoded = jwt.decode( + token, + pub_key, + algorithms=["RS256"], + audience="mcp", + issuer="https://litellm.example.com", + ) + assert decoded["iss"] == "https://litellm.example.com" + + +# --------------------------------------------------------------------------- +# Claim building tests +# --------------------------------------------------------------------------- + + +def test_build_claims_standard_fields(): + """_build_claims() populates iss, aud, iat, exp, nbf.""" + signer = _make_signer(issuer="https://litellm.example.com", audience="mcp", ttl_seconds=300) + user_dict = _make_user_api_key_dict() + data = {"mcp_tool_name": "get_weather"} + + claims = signer._build_claims(user_dict, data) + + assert claims["iss"] == "https://litellm.example.com" + assert claims["aud"] == "mcp" + assert "iat" in claims + assert "exp" in claims + assert claims["exp"] - claims["iat"] == 300 + assert "nbf" in claims + + +def test_build_claims_identity(): + """_build_claims() sets sub from user_id and act from team_id (RFC 8693).""" + signer = _make_signer() + user_dict = _make_user_api_key_dict(user_id="user-xyz", team_id="team-eng") + data: Dict[str, Any] = {} + + claims = signer._build_claims(user_dict, data) + + assert claims["sub"] == "user-xyz" + assert claims["act"]["sub"] == "team-eng" + assert claims["email"] == "user@example.com" + + +def test_build_claims_scope_with_tool(): + """_build_claims() encodes tool-specific scope when mcp_tool_name is set.""" + signer = _make_signer() + user_dict = _make_user_api_key_dict() + data = {"mcp_tool_name": "search_web"} + + claims = signer._build_claims(user_dict, data) + + scopes = set(claims["scope"].split()) + assert "mcp:tools/call" in scopes + assert "mcp:tools/search_web:call" in scopes + # Tool-call JWTs must NOT carry mcp:tools/list — least-privilege + assert "mcp:tools/list" not in scopes + + +def test_build_claims_scope_without_tool(): + """_build_claims() includes mcp:tools/list when no specific tool is called.""" + signer = _make_signer() + user_dict = _make_user_api_key_dict() + data: Dict[str, Any] = {} + + claims = signer._build_claims(user_dict, data) + + scopes = set(claims["scope"].split()) + assert "mcp:tools/call" in scopes + assert "mcp:tools/list" in scopes + # No per-tool call scope when no tool name was given + assert not any(s.endswith(":call") and s != "mcp:tools/call" for s in scopes) + + +def test_build_claims_act_fallback_to_litellm_proxy(): + """_build_claims() falls back to 'litellm-proxy' when team_id and org_id are absent.""" + signer = _make_signer() + user_dict = _make_user_api_key_dict() + user_dict.team_id = None + user_dict.org_id = None + + claims = signer._build_claims(user_dict, {}) + + assert claims["act"]["sub"] == "litellm-proxy" + + +def test_build_claims_sub_fallback_to_token_hash(): + """_build_claims() sets sub to an apikey: hash when user_id is absent.""" + signer = _make_signer() + user_dict = _make_user_api_key_dict(user_id="") + user_dict.user_id = None + user_dict.token = "sk-test-api-key-abc123" + + claims = signer._build_claims(user_dict, {}) + + assert claims["sub"].startswith("apikey:") + assert len(claims["sub"]) == len("apikey:") + 16 # sha256 hex[:16] + + +def test_build_claims_sub_fallback_to_litellm_proxy_when_no_token(): + """_build_claims() falls back to 'litellm-proxy' when user_id and token are both absent.""" + signer = _make_signer() + user_dict = _make_user_api_key_dict(user_id="") + user_dict.user_id = None + user_dict.token = None + user_dict.api_key = None + + claims = signer._build_claims(user_dict, {}) + + assert claims["sub"] == "litellm-proxy" + + +def test_init_raises_on_zero_ttl(): + """MCPJWTSigner raises ValueError when ttl_seconds is 0.""" + with pytest.raises(ValueError, match="ttl_seconds must be > 0"): + _make_signer(ttl_seconds=0) + + +def test_init_raises_on_negative_ttl(): + """MCPJWTSigner raises ValueError when ttl_seconds is negative.""" + with pytest.raises(ValueError, match="ttl_seconds must be > 0"): + _make_signer(ttl_seconds=-60) + + +def test_jwks_max_age_persistent_key(): + """jwks_max_age is 3600 when key loaded from env var.""" + from cryptography.hazmat.primitives import serialization + from cryptography.hazmat.primitives.asymmetric import rsa as crsa + + private_key = crsa.generate_private_key(public_exponent=65537, key_size=2048) + pem = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ).decode("utf-8") + + with patch.dict("os.environ", {"MCP_JWT_SIGNING_KEY": pem}): + signer = _make_signer() + + assert signer.jwks_max_age == 3600 + + +def test_jwks_max_age_auto_generated_key(): + """jwks_max_age is 300 for auto-generated (ephemeral) keys.""" + signer = _make_signer() + assert signer.jwks_max_age == 300 + + +# --------------------------------------------------------------------------- +# Hook dispatch tests +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_hook_fires_for_call_mcp_tool(): + """async_pre_call_hook() injects Authorization header for call_mcp_tool.""" + signer = _make_signer(issuer="https://litellm.example.com", audience="mcp") + user_dict = _make_user_api_key_dict() + data = {"mcp_tool_name": "do_thing"} + + result = await signer.async_pre_call_hook( + user_api_key_dict=user_dict, + cache=MagicMock(), + data=data, + call_type="call_mcp_tool", + ) + + assert isinstance(result, dict) + assert "extra_headers" in result + assert result["extra_headers"]["Authorization"].startswith("Bearer ") + + +@pytest.mark.asyncio +async def test_hook_skips_non_mcp_call_types(): + """async_pre_call_hook() leaves data unchanged for non-MCP call types.""" + signer = _make_signer() + user_dict = _make_user_api_key_dict() + data = {"messages": [{"role": "user", "content": "hello"}]} + + for call_type in ("completion", "acompletion", "embedding", "list_mcp_tools"): + original_data = {**data} + result = await signer.async_pre_call_hook( + user_api_key_dict=user_dict, + cache=MagicMock(), + data=original_data, + call_type=call_type, # type: ignore[arg-type] + ) + assert "extra_headers" not in (result or {}), f"extra_headers should not be set for {call_type}" + + +@pytest.mark.asyncio +async def test_signed_token_is_verifiable(): + """The JWT injected by the hook can be verified against the JWKS public key.""" + signer = _make_signer(issuer="https://litellm.example.com", audience="mcp", ttl_seconds=300) + user_dict = _make_user_api_key_dict(user_id="alice", team_id="backend") + data = {"mcp_tool_name": "search"} + + result = await signer.async_pre_call_hook( + user_api_key_dict=user_dict, + cache=MagicMock(), + data=data, + call_type="call_mcp_tool", + ) + + assert isinstance(result, dict) + token = result["extra_headers"]["Authorization"].removeprefix("Bearer ") + + decoded = _decode_unverified(token) + assert decoded["sub"] == "alice" + assert decoded["act"]["sub"] == "backend" + assert "mcp:tools/search:call" in decoded["scope"] + assert decoded["iss"] == "https://litellm.example.com" + assert decoded["aud"] == "mcp" + + +# --------------------------------------------------------------------------- +# Singleton tests +# --------------------------------------------------------------------------- + + +def test_get_mcp_jwt_signer_returns_none_before_init(): + """get_mcp_jwt_signer() returns None before any MCPJWTSigner is created.""" + import litellm.proxy.guardrails.guardrail_hooks.mcp_jwt_signer.mcp_jwt_signer as mod + + mod._mcp_jwt_signer_instance = None + + from litellm.proxy.guardrails.guardrail_hooks.mcp_jwt_signer.mcp_jwt_signer import ( + get_mcp_jwt_signer, + ) + + assert get_mcp_jwt_signer() is None + + +def test_get_mcp_jwt_signer_returns_instance_after_init(): + """get_mcp_jwt_signer() returns the initialized signer instance.""" + from litellm.proxy.guardrails.guardrail_hooks.mcp_jwt_signer.mcp_jwt_signer import ( + get_mcp_jwt_signer, + ) + + signer = _make_signer() + assert get_mcp_jwt_signer() is signer + + +# --------------------------------------------------------------------------- +# FR-10: Configurable scopes +# --------------------------------------------------------------------------- + + +def test_allowed_scopes_replaces_auto_generation(): + """When allowed_scopes is set it is used verbatim instead of auto-generating.""" + signer = _make_signer(allowed_scopes=["mcp:admin", "mcp:tools/call"]) + user_dict = _make_user_api_key_dict() + data = {"mcp_tool_name": "some_tool"} + + claims = signer._build_claims(user_dict, data) + + assert claims["scope"] == "mcp:admin mcp:tools/call" + + +def test_tool_call_scope_no_list_permission(): + """Tool-call JWTs must NOT carry mcp:tools/list (least-privilege).""" + signer = _make_signer() + user_dict = _make_user_api_key_dict() + data = {"mcp_tool_name": "my_tool"} + + claims = signer._build_claims(user_dict, data) + + scopes = set(claims["scope"].split()) + assert "mcp:tools/list" not in scopes + assert "mcp:tools/call" in scopes + assert "mcp:tools/my_tool:call" in scopes + + +# --------------------------------------------------------------------------- +# FR-12: End-user identity mapping +# --------------------------------------------------------------------------- + + +def test_end_user_claim_sources_token_sub(): + """end_user_claim_sources resolves sub from incoming JWT claims.""" + signer = _make_signer(end_user_claim_sources=["token:sub", "litellm:user_id"]) + user_dict = _make_user_api_key_dict(user_id="litellm-user") + jwt_claims = {"sub": "idp-user-123", "email": "idp@example.com"} + + claims = signer._build_claims(user_dict, {}, jwt_claims=jwt_claims) + + assert claims["sub"] == "idp-user-123" + + +def test_end_user_claim_sources_falls_back_to_litellm_user_id(): + """Falls back to litellm:user_id when token:sub is absent.""" + signer = _make_signer(end_user_claim_sources=["token:sub", "litellm:user_id"]) + user_dict = _make_user_api_key_dict(user_id="litellm-user") + jwt_claims: Dict[str, Any] = {} # no sub + + claims = signer._build_claims(user_dict, {}, jwt_claims=jwt_claims) + + assert claims["sub"] == "litellm-user" + + +def test_end_user_claim_sources_email_source(): + """token:email resolves correctly.""" + signer = _make_signer(end_user_claim_sources=["token:email"]) + user_dict = _make_user_api_key_dict(user_id="") + user_dict.user_id = None + jwt_claims = {"email": "alice@corp.com"} + + claims = signer._build_claims(user_dict, {}, jwt_claims=jwt_claims) + + assert claims["sub"] == "alice@corp.com" + + +def test_end_user_claim_sources_litellm_email(): + """litellm:email resolves from UserAPIKeyAuth.user_email.""" + signer = _make_signer(end_user_claim_sources=["litellm:email"]) + user_dict = _make_user_api_key_dict(user_email="proxy-user@example.com") + user_dict.user_id = None + + claims = signer._build_claims(user_dict, {}) + + assert claims["sub"] == "proxy-user@example.com" + + +# --------------------------------------------------------------------------- +# FR-13: Claim operations +# --------------------------------------------------------------------------- + + +def test_add_claims_inserts_when_absent(): + """add_claims inserts key when it is not already in the JWT.""" + signer = _make_signer(add_claims={"deployment_id": "prod-001"}) + user_dict = _make_user_api_key_dict() + + claims = signer._build_claims(user_dict, {}) + + assert claims["deployment_id"] == "prod-001" + + +def test_add_claims_does_not_overwrite_existing(): + """add_claims does NOT overwrite an existing claim (use set_claims for that).""" + signer = _make_signer(add_claims={"iss": "should-not-win"}) + user_dict = _make_user_api_key_dict() + + claims = signer._build_claims(user_dict, {}) + + # iss should be the configured issuer, not overwritten + assert claims["iss"] != "should-not-win" + + +def test_set_claims_always_overrides(): + """set_claims always overrides computed claims.""" + signer = _make_signer(set_claims={"iss": "override-issuer", "custom": "x"}) + user_dict = _make_user_api_key_dict() + + claims = signer._build_claims(user_dict, {}) + + assert claims["iss"] == "override-issuer" + assert claims["custom"] == "x" + + +def test_remove_claims_deletes_keys(): + """remove_claims deletes specified keys from the final JWT.""" + signer = _make_signer(remove_claims=["nbf", "email"]) + user_dict = _make_user_api_key_dict() + + claims = signer._build_claims(user_dict, {}) + + assert "nbf" not in claims + assert "email" not in claims + + +def test_claim_operations_order_add_then_set_then_remove(): + """add → set → remove is applied in order: set wins over add, remove beats both.""" + signer = _make_signer( + add_claims={"x": "from-add"}, + set_claims={"x": "from-set"}, + remove_claims=["x"], + ) + user_dict = _make_user_api_key_dict() + + claims = signer._build_claims(user_dict, {}) + + assert "x" not in claims # remove wins + + +# --------------------------------------------------------------------------- +# FR-14: Two-token model +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_channel_token_injected_when_configured(): + """When channel_token_audience is set, x-mcp-channel-token header is injected.""" + signer = _make_signer( + channel_token_audience="bedrock-gateway", + channel_token_ttl=60, + ) + user_dict = _make_user_api_key_dict() + data = {"mcp_tool_name": "list_tables"} + + result = await signer.async_pre_call_hook( + user_api_key_dict=user_dict, + cache=MagicMock(), + data=data, + call_type="call_mcp_tool", + ) + + assert isinstance(result, dict) + assert "x-mcp-channel-token" in result["extra_headers"] + channel_token = result["extra_headers"]["x-mcp-channel-token"].removeprefix("Bearer ") + channel_payload = _decode_unverified(channel_token) + assert channel_payload["aud"] == "bedrock-gateway" + + +@pytest.mark.asyncio +async def test_channel_token_absent_when_not_configured(): + """x-mcp-channel-token is not injected when channel_token_audience is unset.""" + signer = _make_signer() + user_dict = _make_user_api_key_dict() + data = {"mcp_tool_name": "tool"} + + result = await signer.async_pre_call_hook( + user_api_key_dict=user_dict, + cache=MagicMock(), + data=data, + call_type="call_mcp_tool", + ) + + assert isinstance(result, dict) + assert "x-mcp-channel-token" not in result["extra_headers"] + + +# --------------------------------------------------------------------------- +# FR-15: Incoming claim validation +# --------------------------------------------------------------------------- + + +def test_required_claims_pass_when_present(): + """_validate_required_claims() passes when all required claims are present.""" + signer = _make_signer(required_claims=["sub", "email"]) + # Should not raise + signer._validate_required_claims({"sub": "user", "email": "u@example.com"}) + + +def test_required_claims_raise_403_when_missing(): + """_validate_required_claims() raises HTTP 403 when a required claim is missing.""" + from fastapi import HTTPException + + signer = _make_signer(required_claims=["sub", "email"]) + with pytest.raises(HTTPException) as exc_info: + signer._validate_required_claims({"sub": "user"}) # email missing + + assert exc_info.value.status_code == 403 + assert "email" in str(exc_info.value.detail) + + +def test_required_claims_raise_when_no_jwt_claims(): + """_validate_required_claims() raises when jwt_claims is None and claims are required.""" + from fastapi import HTTPException + + signer = _make_signer(required_claims=["sub"]) + with pytest.raises(HTTPException): + signer._validate_required_claims(None) + + +def test_optional_claims_passed_through(): + """optional_claims are forwarded from incoming jwt_claims into the outbound JWT.""" + signer = _make_signer(optional_claims=["groups", "roles"]) + user_dict = _make_user_api_key_dict() + jwt_claims = {"sub": "u", "groups": ["admin"], "roles": ["editor"]} + + claims = signer._build_claims(user_dict, {}, jwt_claims=jwt_claims) + + assert claims["groups"] == ["admin"] + assert claims["roles"] == ["editor"] + + +def test_optional_claims_not_injected_if_absent(): + """optional_claims are silently skipped when absent in incoming jwt_claims.""" + signer = _make_signer(optional_claims=["groups"]) + user_dict = _make_user_api_key_dict() + jwt_claims: Dict[str, Any] = {"sub": "u"} # no groups + + claims = signer._build_claims(user_dict, {}, jwt_claims=jwt_claims) + + assert "groups" not in claims + + +# --------------------------------------------------------------------------- +# FR-9: Debug headers +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_debug_header_injected_when_enabled(): + """x-litellm-mcp-debug header is injected when debug_headers=True.""" + signer = _make_signer(debug_headers=True) + user_dict = _make_user_api_key_dict() + data = {"mcp_tool_name": "my_tool"} + + result = await signer.async_pre_call_hook( + user_api_key_dict=user_dict, + cache=MagicMock(), + data=data, + call_type="call_mcp_tool", + ) + + assert isinstance(result, dict) + assert "x-litellm-mcp-debug" in result["extra_headers"] + debug_val = result["extra_headers"]["x-litellm-mcp-debug"] + assert "v=1" in debug_val + assert "kid=" in debug_val + assert "sub=" in debug_val + + +@pytest.mark.asyncio +async def test_debug_header_absent_when_disabled(): + """x-litellm-mcp-debug is NOT injected when debug_headers=False (default).""" + signer = _make_signer() + user_dict = _make_user_api_key_dict() + data = {"mcp_tool_name": "tool"} + + result = await signer.async_pre_call_hook( + user_api_key_dict=user_dict, + cache=MagicMock(), + data=data, + call_type="call_mcp_tool", + ) + + assert isinstance(result, dict) + assert "x-litellm-mcp-debug" not in result["extra_headers"] + + +# --------------------------------------------------------------------------- +# P1 fix: extra_headers merging (multi-guardrail chains) +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_extra_headers_are_merged_not_replaced(): + """ + Existing extra_headers from a prior guardrail are preserved — only + Authorization is added/overwritten, other keys survive. + """ + signer = _make_signer() + user_dict = _make_user_api_key_dict() + # Simulate a prior guardrail having injected a tracing header + data = { + "mcp_tool_name": "list", + "extra_headers": {"x-trace-id": "abc123", "x-correlation-id": "xyz"}, + } + + result = await signer.async_pre_call_hook( + user_api_key_dict=user_dict, + cache=MagicMock(), + data=data, + call_type="call_mcp_tool", + ) + + assert isinstance(result, dict) + headers = result["extra_headers"] + # Prior headers preserved + assert headers.get("x-trace-id") == "abc123" + assert headers.get("x-correlation-id") == "xyz" + # Authorization injected + assert "Authorization" in headers + + +# --------------------------------------------------------------------------- +# FR-5: Verify + re-sign — jwt_claims fallback from UserAPIKeyAuth +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_sub_resolved_from_user_api_key_dict_jwt_claims(): + """ + When no raw token is present but UserAPIKeyAuth.jwt_claims has a sub, + the guardrail resolves sub from jwt_claims (LiteLLM-decoded JWT path). + """ + signer = _make_signer(end_user_claim_sources=["token:sub", "litellm:user_id"]) + user_dict = _make_user_api_key_dict(user_id="litellm-fallback") + # jwt_claims populated by LiteLLM's JWT auth machinery + user_dict.jwt_claims = {"sub": "idp-alice", "email": "alice@idp.com"} + data = {"mcp_tool_name": "query"} + + result = await signer.async_pre_call_hook( + user_api_key_dict=user_dict, + cache=MagicMock(), + data=data, + call_type="call_mcp_tool", + ) + + assert isinstance(result, dict) + token = result["extra_headers"]["Authorization"].removeprefix("Bearer ") + payload = _decode_unverified(token) + assert payload["sub"] == "idp-alice" + + +# --------------------------------------------------------------------------- +# initialize_guardrail factory — regression test for config.yaml wire-up +# --------------------------------------------------------------------------- + + +def test_initialize_guardrail_passes_all_params(): + """ + initialize_guardrail must wire every documented config.yaml param through + to MCPJWTSigner. Previously only issuer/audience/ttl_seconds were passed; + all FR-5/9/10/12/13/14/15 params were silently dropped. + """ + import litellm.proxy.guardrails.guardrail_hooks.mcp_jwt_signer.mcp_jwt_signer as mod + + mod._mcp_jwt_signer_instance = None + + from litellm.proxy.guardrails.guardrail_hooks.mcp_jwt_signer import ( + initialize_guardrail, + ) + + litellm_params = MagicMock() + litellm_params.mode = "pre_mcp_call" + litellm_params.default_on = True + litellm_params.optional_params = None + # Set every non-default param directly on litellm_params + litellm_params.issuer = "https://litellm.example.com" + litellm_params.audience = "mcp-test" + litellm_params.ttl_seconds = 120 + litellm_params.access_token_discovery_uri = "https://idp.example.com/.well-known/openid-configuration" + litellm_params.token_introspection_endpoint = "https://idp.example.com/introspect" + litellm_params.verify_issuer = "https://idp.example.com" + litellm_params.verify_audience = "api://test" + litellm_params.end_user_claim_sources = ["token:email", "litellm:user_id"] + litellm_params.add_claims = {"deployment_id": "prod"} + litellm_params.set_claims = {"env": "production"} + litellm_params.remove_claims = ["nbf"] + litellm_params.channel_token_audience = "bedrock-gateway" + litellm_params.channel_token_ttl = 60 + litellm_params.required_claims = ["sub", "email"] + litellm_params.optional_claims = ["groups"] + litellm_params.debug_headers = True + litellm_params.allowed_scopes = ["mcp:tools/call"] + + guardrail = {"guardrail_name": "mcp-jwt-signer"} + + with patch("litellm.logging_callback_manager.add_litellm_callback"): + signer = initialize_guardrail(litellm_params, guardrail) + + assert signer.issuer == "https://litellm.example.com" + assert signer.audience == "mcp-test" + assert signer.ttl_seconds == 120 + assert signer.access_token_discovery_uri == "https://idp.example.com/.well-known/openid-configuration" + assert signer.token_introspection_endpoint == "https://idp.example.com/introspect" + assert signer.verify_issuer == "https://idp.example.com" + assert signer.verify_audience == "api://test" + assert signer.end_user_claim_sources == ["token:email", "litellm:user_id"] + assert signer.add_claims == {"deployment_id": "prod"} + assert signer.set_claims == {"env": "production"} + assert signer.remove_claims == ["nbf"] + assert signer.channel_token_audience == "bedrock-gateway" + assert signer.channel_token_ttl == 60 + assert signer.required_claims == ["sub", "email"] + assert signer.optional_claims == ["groups"] + assert signer.debug_headers is True + assert signer.allowed_scopes == ["mcp:tools/call"] + + +# --------------------------------------------------------------------------- +# FR-5: _fetch_jwks, _get_oidc_discovery, _verify_incoming_jwt, +# _introspect_opaque_token +# --------------------------------------------------------------------------- + +import litellm.proxy.guardrails.guardrail_hooks.mcp_jwt_signer.mcp_jwt_signer as _signer_mod + + +def _make_httpx_response(json_body: dict, status_code: int = 200): + """Build a minimal fake httpx Response object.""" + mock_resp = MagicMock() + mock_resp.status_code = status_code + mock_resp.json.return_value = json_body + mock_resp.raise_for_status = MagicMock() + if status_code >= 400: + from httpx import HTTPStatusError, Request, Response + + mock_resp.raise_for_status.side_effect = HTTPStatusError( + "error", request=MagicMock(), response=MagicMock() + ) + return mock_resp + + +# --- _fetch_jwks --- + + +@pytest.mark.asyncio +async def test_fetch_jwks_returns_keys_and_caches(): + """_fetch_jwks returns keys from the remote JWKS URI and caches the result.""" + _signer_mod._jwks_cache.clear() + + fake_keys = [{"kty": "RSA", "kid": "k1", "n": "abc", "e": "AQAB"}] + fake_resp = _make_httpx_response({"keys": fake_keys}) + + mock_client = MagicMock() + mock_client.get = AsyncMock(return_value=fake_resp) + + with patch( + "litellm.llms.custom_httpx.http_handler.get_async_httpx_client", + return_value=mock_client, + ): + keys = await _signer_mod._fetch_jwks("https://idp.example.com/jwks") + + assert keys == fake_keys + assert "https://idp.example.com/jwks" in _signer_mod._jwks_cache + _signer_mod._jwks_cache.clear() + + +@pytest.mark.asyncio +async def test_fetch_jwks_uses_cache_on_second_call(): + """_fetch_jwks returns the cached value without a second HTTP call.""" + _signer_mod._jwks_cache.clear() + fake_keys = [{"kty": "RSA", "kid": "k1"}] + _signer_mod._jwks_cache["https://idp.example.com/jwks"] = ( + fake_keys, + time.time(), + ) + + mock_client = MagicMock() + mock_client.get = AsyncMock() + + with patch( + "litellm.llms.custom_httpx.http_handler.get_async_httpx_client", + return_value=mock_client, + ): + keys = await _signer_mod._fetch_jwks("https://idp.example.com/jwks") + + mock_client.get.assert_not_called() + assert keys == fake_keys + _signer_mod._jwks_cache.clear() + + +# --- _get_oidc_discovery --- + + +@pytest.mark.asyncio +async def test_get_oidc_discovery_caches_when_jwks_uri_present(): + """_get_oidc_discovery caches the doc when jwks_uri is in the response.""" + signer = _make_signer( + access_token_discovery_uri="https://idp.example.com/.well-known/openid-configuration" + ) + signer._oidc_discovery_doc = None # ensure fresh + + discovery_doc = { + "issuer": "https://idp.example.com", + "jwks_uri": "https://idp.example.com/jwks", + } + + with patch( + "litellm.proxy.guardrails.guardrail_hooks.mcp_jwt_signer.mcp_jwt_signer._fetch_oidc_discovery", + new_callable=AsyncMock, + return_value=discovery_doc, + ): + result = await signer._get_oidc_discovery() + + assert result["jwks_uri"] == "https://idp.example.com/jwks" + assert signer._oidc_discovery_doc == discovery_doc + + +@pytest.mark.asyncio +async def test_get_oidc_discovery_does_not_cache_when_jwks_uri_absent(): + """_get_oidc_discovery does NOT cache a doc that is missing jwks_uri.""" + signer = _make_signer( + access_token_discovery_uri="https://idp.example.com/.well-known/openid-configuration" + ) + signer._oidc_discovery_doc = None + + bad_doc = {"issuer": "https://idp.example.com"} # no jwks_uri + + with patch( + "litellm.proxy.guardrails.guardrail_hooks.mcp_jwt_signer.mcp_jwt_signer._fetch_oidc_discovery", + new_callable=AsyncMock, + return_value=bad_doc, + ) as mock_fetch: + result1 = await signer._get_oidc_discovery() + result2 = await signer._get_oidc_discovery() + + # Returns the bad doc each time without caching it + assert "jwks_uri" not in result1 + assert signer._oidc_discovery_doc is None # never cached + assert mock_fetch.call_count == 2 # retried on second call + + +# --- _verify_incoming_jwt --- + + +@pytest.mark.asyncio +async def test_verify_incoming_jwt_returns_payload_on_valid_token(): + """_verify_incoming_jwt decodes and returns claims from a valid JWT.""" + # Build a signer to get a real RSA key pair; use its key to mint the "incoming" JWT + signer = _make_signer( + access_token_discovery_uri="https://idp.example.com/.well-known/openid-configuration", + verify_audience="api://test", + verify_issuer="https://idp.example.com", + ) + # Mint a JWT with signer's own key — we'll pretend it came from the IdP + now = int(time.time()) + incoming_claims = { + "sub": "idp-user-42", + "iss": "https://idp.example.com", + "aud": "api://test", + "iat": now, + "exp": now + 300, + } + incoming_token = jwt.encode(incoming_claims, signer._private_key, algorithm="RS256", headers={"kid": signer._kid}) + + # Build a JWKS from the same public key so verification passes + jwks = signer.get_jwks() + + with patch.object( + signer, + "_get_oidc_discovery", + new_callable=AsyncMock, + return_value={"jwks_uri": "https://idp.example.com/jwks"}, + ): + with patch( + "litellm.proxy.guardrails.guardrail_hooks.mcp_jwt_signer.mcp_jwt_signer._fetch_jwks", + new_callable=AsyncMock, + return_value=jwks["keys"], + ): + payload = await signer._verify_incoming_jwt(incoming_token) + + assert payload["sub"] == "idp-user-42" + + +@pytest.mark.asyncio +async def test_verify_incoming_jwt_raises_on_expired_token(): + """_verify_incoming_jwt raises PyJWTError on an expired token.""" + signer = _make_signer( + access_token_discovery_uri="https://idp.example.com/.well-known/openid-configuration", + ) + expired_claims = { + "sub": "idp-user", + "iss": "https://idp.example.com", + "aud": "api://test", + "iat": int(time.time()) - 600, + "exp": int(time.time()) - 300, # expired + } + expired_token = jwt.encode(expired_claims, signer._private_key, algorithm="RS256") + jwks = signer.get_jwks() + + with patch.object( + signer, + "_get_oidc_discovery", + new_callable=AsyncMock, + return_value={"jwks_uri": "https://idp.example.com/jwks"}, + ): + with patch( + "litellm.proxy.guardrails.guardrail_hooks.mcp_jwt_signer.mcp_jwt_signer._fetch_jwks", + new_callable=AsyncMock, + return_value=jwks["keys"], + ): + with pytest.raises(jwt.PyJWTError): + await signer._verify_incoming_jwt(expired_token) + + +# --- _introspect_opaque_token --- + + +@pytest.mark.asyncio +async def test_introspect_opaque_token_returns_claims_when_active(): + """_introspect_opaque_token returns the introspection payload for active tokens.""" + signer = _make_signer( + token_introspection_endpoint="https://idp.example.com/introspect" + ) + + introspection_response = { + "active": True, + "sub": "service-account", + "scope": "read write", + } + fake_resp = _make_httpx_response(introspection_response) + mock_client = MagicMock() + mock_client.post = AsyncMock(return_value=fake_resp) + + with patch( + "litellm.llms.custom_httpx.http_handler.get_async_httpx_client", + return_value=mock_client, + ): + result = await signer._introspect_opaque_token("opaque-token-abc") + + assert result["sub"] == "service-account" + assert result["active"] is True + + +@pytest.mark.asyncio +async def test_introspect_opaque_token_raises_on_inactive_token(): + """_introspect_opaque_token raises ExpiredSignatureError when active=false.""" + signer = _make_signer( + token_introspection_endpoint="https://idp.example.com/introspect" + ) + + fake_resp = _make_httpx_response({"active": False}) + mock_client = MagicMock() + mock_client.post = AsyncMock(return_value=fake_resp) + + with patch( + "litellm.llms.custom_httpx.http_handler.get_async_httpx_client", + return_value=mock_client, + ): + with pytest.raises(jwt.ExpiredSignatureError): + await signer._introspect_opaque_token("opaque-token-xyz") + + +@pytest.mark.asyncio +async def test_introspect_opaque_token_raises_without_endpoint_configured(): + """_introspect_opaque_token raises ValueError when no endpoint is set.""" + signer = _make_signer() # no token_introspection_endpoint + + with pytest.raises(ValueError, match="token_introspection_endpoint"): + await signer._introspect_opaque_token("some-token") + + +# --- FR-5 end-to-end hook path --- + + +@pytest.mark.asyncio +async def test_hook_raises_401_when_jwt_verification_fails(): + """async_pre_call_hook raises HTTP 401 when incoming JWT verification fails.""" + from fastapi import HTTPException + + signer = _make_signer( + access_token_discovery_uri="https://idp.example.com/.well-known/openid-configuration" + ) + + with patch.object( + signer, + "_verify_incoming_jwt", + new_callable=AsyncMock, + side_effect=jwt.InvalidSignatureError("bad signature"), + ): + with patch.object( + signer, + "_get_oidc_discovery", + new_callable=AsyncMock, + return_value={"jwks_uri": "https://idp.example.com/jwks"}, + ): + with pytest.raises(HTTPException) as exc_info: + await signer.async_pre_call_hook( + user_api_key_dict=_make_user_api_key_dict(), + cache=MagicMock(), + data={"mcp_tool_name": "tool", "incoming_bearer_token": "hdr.pld.sig"}, + call_type="call_mcp_tool", + ) + + assert exc_info.value.status_code == 401 diff --git a/tests/test_litellm/test_setup_wizard.py b/tests/test_litellm/test_setup_wizard.py new file mode 100644 index 0000000000..e10bd893e3 --- /dev/null +++ b/tests/test_litellm/test_setup_wizard.py @@ -0,0 +1,188 @@ +"""Unit tests for litellm.setup_wizard — pure functions only, no network calls.""" + +from litellm.setup_wizard import SetupWizard, _yaml_escape + +# --------------------------------------------------------------------------- +# _yaml_escape +# --------------------------------------------------------------------------- + + +def test_yaml_escape_plain(): + assert _yaml_escape("sk-abc123") == "sk-abc123" + + +def test_yaml_escape_double_quote(): + assert _yaml_escape('sk-ab"cd') == 'sk-ab\\"cd' + + +def test_yaml_escape_backslash(): + assert _yaml_escape("sk-ab\\cd") == "sk-ab\\\\cd" + + +def test_yaml_escape_combined(): + assert _yaml_escape('ab\\"cd') == 'ab\\\\\\"cd' + + +def test_yaml_escape_newline(): + assert _yaml_escape("sk-abc\ndef") == "sk-abc\\ndef" + + +def test_yaml_escape_carriage_return(): + assert _yaml_escape("sk-abc\rdef") == "sk-abc\\rdef" + + +def test_yaml_escape_tab(): + assert _yaml_escape("sk-abc\tdef") == "sk-abc\\tdef" + + +# --------------------------------------------------------------------------- +# SetupWizard._build_config +# --------------------------------------------------------------------------- + +_OPENAI = { + "id": "openai", + "name": "OpenAI", + "env_key": "OPENAI_API_KEY", + "models": ["gpt-4o", "gpt-4o-mini"], + "test_model": "gpt-4o-mini", +} + +_ANTHROPIC = { + "id": "anthropic", + "name": "Anthropic", + "env_key": "ANTHROPIC_API_KEY", + "models": ["claude-opus-4-6"], + "test_model": "claude-haiku-4-5-20251001", +} + +_AZURE = { + "id": "azure", + "name": "Azure OpenAI", + "env_key": "AZURE_API_KEY", + "models": [], + "test_model": None, + "needs_api_base": True, + "api_base_hint": "https://.openai.azure.com/", + "api_version": "2024-07-01-preview", +} + +_OLLAMA = { + "id": "ollama", + "name": "Ollama", + "env_key": None, + "models": ["ollama/llama3.2"], + "test_model": None, + "api_base": "http://localhost:11434", +} + + +def test_build_config_basic_openai(): + config = SetupWizard._build_config( + [_OPENAI], + {"OPENAI_API_KEY": "sk-test"}, + "sk-master", + ) + assert "model_list:" in config + assert "model_name: gpt-4o" in config + assert "model: gpt-4o" in config + assert "api_key: os.environ/OPENAI_API_KEY" in config + assert 'master_key: "sk-master"' in config + + +def test_build_config_skipped_provider_omitted(): + """Provider with no key in env_vars should not appear in model_list.""" + config = SetupWizard._build_config( + [_OPENAI, _ANTHROPIC], + {"ANTHROPIC_API_KEY": "sk-ant-test"}, # OpenAI key missing + "sk-master", + ) + assert "gpt-4o" not in config + assert "claude-opus-4-6" in config + + +def test_build_config_env_vars_written_escaped(): + """API keys with special chars should be YAML-escaped.""" + config = SetupWizard._build_config( + [_OPENAI], + {"OPENAI_API_KEY": 'sk-ab"cd'}, + "sk-master", + ) + assert 'OPENAI_API_KEY: "sk-ab\\"cd"' in config + + +def test_build_config_master_key_quoted(): + """master_key must be quoted in YAML to handle special characters.""" + config = SetupWizard._build_config( + [_OPENAI], + {"OPENAI_API_KEY": "sk-test"}, + 'sk-master"special', + ) + assert 'master_key: "sk-master\\"special"' in config + + +def test_build_config_does_not_mutate_env_vars(): + """_build_config must not modify the caller's env_vars dict.""" + env_vars = { + "AZURE_API_KEY": "az-key", + "_LITELLM_AZURE_API_BASE_AZURE": "https://my.azure.com", + "_LITELLM_AZURE_DEPLOYMENT_AZURE": "my-deployment", + } + original_keys = set(env_vars.keys()) + SetupWizard._build_config([_AZURE], env_vars, "sk-master") + assert set(env_vars.keys()) == original_keys + + +def test_build_config_azure_uses_deployment_name(): + env_vars = { + "AZURE_API_KEY": "az-key", + "_LITELLM_AZURE_API_BASE_AZURE": "https://my.azure.com", + "_LITELLM_AZURE_DEPLOYMENT_AZURE": "my-gpt4o", + } + config = SetupWizard._build_config([_AZURE], env_vars, "sk-master") + assert "model: azure/my-gpt4o" in config + assert "model_name: azure-my-gpt4o" in config + # api_base must be quoted to survive YAML special chars + assert 'api_base: "https://my.azure.com"' in config + + +def test_build_config_azure_no_deployment_skipped(): + """Azure without a deployment name should emit nothing (not fallback to gpt-4o).""" + env_vars = {"AZURE_API_KEY": "az-key"} # no deployment sentinel + config = SetupWizard._build_config([_AZURE], env_vars, "sk-master") + # No azure model entry should be emitted when deployment name is absent + assert "model: azure/" not in config + + +def test_build_config_no_display_name_collision_openai_and_azure(): + """OpenAI gpt-4o and azure gpt-4o should get distinct model_name values.""" + env_vars = { + "OPENAI_API_KEY": "sk-openai", + "AZURE_API_KEY": "az-key", + "_LITELLM_AZURE_DEPLOYMENT_AZURE": "gpt-4o", + } + config = SetupWizard._build_config([_OPENAI, _AZURE], env_vars, "sk-master") + assert "model_name: gpt-4o" in config # OpenAI + assert "model_name: azure-gpt-4o" in config # Azure — qualified + + +def test_build_config_ollama_no_api_key_line(): + """Ollama has no env_key — config should not contain an api_key line for it.""" + config = SetupWizard._build_config([_OLLAMA], {}, "sk-master") + assert "ollama/llama3.2" in config + assert "api_key:" not in config + + +def test_build_config_master_key_in_general_settings(): + """master_key is written to general_settings.""" + config = SetupWizard._build_config([_OPENAI], {"OPENAI_API_KEY": "k"}, "sk-m") + assert 'master_key: "sk-m"' in config + + +def test_build_config_internal_sentinel_keys_excluded(): + """_LITELLM_ prefixed sentinel keys must not appear in environment_variables.""" + env_vars = { + "OPENAI_API_KEY": "sk-real", + "_LITELLM_AZURE_API_BASE_AZURE": "https://x.azure.com", + } + config = SetupWizard._build_config([_OPENAI], env_vars, "sk-master") + assert "_LITELLM_" not in config diff --git a/ui/litellm-dashboard/src/app/(dashboard)/components/Sidebar2.tsx b/ui/litellm-dashboard/src/app/(dashboard)/components/Sidebar2.tsx index ceb14864ad..18ab475f22 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/components/Sidebar2.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/components/Sidebar2.tsx @@ -20,7 +20,6 @@ import { ToolOutlined, TagsOutlined, AuditOutlined, - MessageOutlined, } from "@ant-design/icons"; // import { // all_admin_roles, @@ -466,41 +465,6 @@ const Sidebar2: React.FC = ({ accessToken, userRole, defaultSelect {isAdminRole(userRole) && !collapsed && } - {/* Pinned "Open Chat" button at bottom */} -

k$ez1@E~m^s%tb)ASor$q>&w5 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 !cQ_M?K18la(+*6wh?&YVlu2i)UN!Xx{I_ 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 literal 0 HcmV?d00001 From bae2eddd73998a767cfa4858310a2c47bc5ec62a Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Tue, 17 Mar 2026 17:50:58 -0700 Subject: [PATCH 255/289] docs fix sidebar --- docs/my-website/sidebars.js | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index 1362745a91..79a0279bad 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -631,6 +631,7 @@ const sidebars = { "mcp_openapi", "mcp_oauth", "mcp_aws_sigv4", + "mcp_zero_trust", "mcp_public_internet", "mcp_semantic_filter", "mcp_control", From 88f59e1465ae55097abc3520e1f6d271b5f39bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?d=20=F0=9F=94=B9?= <258577966+voidborne-d@users.noreply.github.com> Date: Wed, 18 Mar 2026 00:54:23 +0000 Subject: [PATCH 256/289] fix: use AsyncMock for concurrent test consistency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address review feedback from greptile — use new_callable=AsyncMock on the concurrent test's patch.object to ensure the mock is properly typed as async, even though side_effect already handles the coroutine. --- tests/test_litellm/proxy/test_aiohttp_session_recovery.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_litellm/proxy/test_aiohttp_session_recovery.py b/tests/test_litellm/proxy/test_aiohttp_session_recovery.py index f089d10425..29bd9a491b 100644 --- a/tests/test_litellm/proxy/test_aiohttp_session_recovery.py +++ b/tests/test_litellm/proxy/test_aiohttp_session_recovery.py @@ -167,6 +167,7 @@ async def test_add_shared_session_concurrent_recreation_uses_lock(): with patch.object( proxy_server_module, "_initialize_shared_aiohttp_session", + new_callable=AsyncMock, side_effect=mock_init, ): # Launch 5 concurrent calls From bd2502eeaf99111d17442929f68542639417719c Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 17 Mar 2026 20:34:15 -0700 Subject: [PATCH 257/289] [Feature] /v2/team/list: Add org admin access control, members_count, and indexes Add org admin support to /v2/team/list so org admins can list teams within their organizations instead of getting 401. Also enrich the response with members_count and add missing indexes. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../litellm_proxy_extras/schema.prisma | 4 + .../management_endpoints/team_endpoints.py | 132 +++++++++++++++--- litellm/proxy/schema.prisma | 4 + .../management_endpoints/team_endpoints.py | 9 +- schema.prisma | 4 + 5 files changed, 136 insertions(+), 17 deletions(-) diff --git a/litellm-proxy-extras/litellm_proxy_extras/schema.prisma b/litellm-proxy-extras/litellm_proxy_extras/schema.prisma index ce79c2b3d5..a2c8329540 100644 --- a/litellm-proxy-extras/litellm_proxy_extras/schema.prisma +++ b/litellm-proxy-extras/litellm_proxy_extras/schema.prisma @@ -146,6 +146,10 @@ model LiteLLM_TeamTable { litellm_model_table LiteLLM_ModelTable? @relation(fields: [model_id], references: [id]) object_permission LiteLLM_ObjectPermissionTable? @relation(fields: [object_permission_id], references: [object_permission_id]) projects LiteLLM_ProjectTable[] + + @@index([organization_id]) + @@index([team_alias]) + @@index([created_at]) } // Projects sit between teams and keys for use-case management diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py index d83ceb1b09..a7ee340282 100644 --- a/litellm/proxy/management_endpoints/team_endpoints.py +++ b/litellm/proxy/management_endpoints/team_endpoints.py @@ -101,6 +101,7 @@ from litellm.types.proxy.management_endpoints.team_endpoints import ( BulkTeamMemberAddRequest, BulkTeamMemberAddResponse, GetTeamMemberPermissionsResponse, + TeamListItem, TeamListResponse, TeamMemberAddResult, UpdateTeamMemberPermissionsRequest, @@ -3206,6 +3207,39 @@ async def list_available_teams( return available_teams_correct_type +async def _get_org_admin_org_ids( + user_id: str, + prisma_client: Any, + user_api_key_cache: Any, + proxy_logging_obj: Any, +) -> Optional[List[str]]: + """ + Return the list of organization IDs where the user is an org admin. + Returns None if the user is not an org admin of any organization or if + the user cannot be found. + """ + try: + caller_user = await get_user_object( + user_id=user_id, + prisma_client=prisma_client, + user_api_key_cache=user_api_key_cache, + user_id_upsert=False, + proxy_logging_obj=proxy_logging_obj, + ) + except Exception: + return None + + if caller_user is None: + return None + + org_ids = [ + m.organization_id + for m in (caller_user.organization_memberships or []) + if m.user_role == LitellmUserRoles.ORG_ADMIN.value + ] + return org_ids if org_ids else None + + async def _build_team_list_where_conditions( prisma_client: PrismaClient, team_id: Optional[str], @@ -3213,6 +3247,7 @@ async def _build_team_list_where_conditions( organization_id: Optional[str], user_id: Optional[str], use_deleted_table: bool, + org_admin_org_ids: Optional[List[str]] = None, ) -> Dict[str, Any]: """Build where conditions for team list query.""" where_conditions: Dict[str, Any] = {} @@ -3227,7 +3262,14 @@ async def _build_team_list_where_conditions( } if organization_id: - where_conditions["organization_id"] = organization_id + # If a list is passed (org admin viewing multiple orgs), use IN + if isinstance(organization_id, list): + where_conditions["organization_id"] = {"in": organization_id} + else: + where_conditions["organization_id"] = organization_id + elif org_admin_org_ids is not None: + # Org admin without explicit org filter: scope to their orgs + where_conditions["organization_id"] = {"in": org_admin_org_ids} if user_id: try: @@ -3347,7 +3389,11 @@ async def list_team_v2( status: Optional[str] Filter by status. Currently supports "deleted" to query deleted teams. """ - from litellm.proxy.proxy_server import prisma_client + from litellm.proxy.proxy_server import ( + prisma_client, + proxy_logging_obj, + user_api_key_cache, + ) if prisma_client is None: raise HTTPException( @@ -3355,20 +3401,58 @@ async def list_team_v2( detail={"error": f"No db connected. prisma client={prisma_client}"}, ) - if not allowed_route_check_inside_route( - user_api_key_dict=user_api_key_dict, requested_user_id=user_id - ): - raise HTTPException( - status_code=401, - detail={ - "error": "Only admin users can query all teams/other teams. Your user role={}".format( - user_api_key_dict.user_role - ) - }, + # --- Access control --- + # Proxy admins and admin viewers can query any teams. + # Org admins can query teams within their organizations. + # Regular users can only query their own teams. + is_proxy_admin = _user_has_admin_view(user_api_key_dict) + org_admin_org_ids: Optional[List[str]] = None + + if not is_proxy_admin: + # First check if the standard route check passes (user querying own data) + passes_route_check = allowed_route_check_inside_route( + user_api_key_dict=user_api_key_dict, requested_user_id=user_id ) - if user_id is None and user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN: - user_id = user_api_key_dict.user_id + if not passes_route_check: + # Standard check failed — see if the caller is an org admin + if user_api_key_dict.user_id: + org_admin_org_ids = await _get_org_admin_org_ids( + user_id=user_api_key_dict.user_id, + prisma_client=prisma_client, + user_api_key_cache=user_api_key_cache, + proxy_logging_obj=proxy_logging_obj, + ) + + if org_admin_org_ids is None: + # Not an org admin either — reject + raise HTTPException( + status_code=401, + detail={ + "error": "Only admin users can query all teams/other teams. Your user role={}".format( + user_api_key_dict.user_role + ) + }, + ) + + if org_admin_org_ids is not None: + # Org admin: validate org_id filter if provided + if organization_id and organization_id not in org_admin_org_ids: + raise HTTPException( + status_code=403, + detail={ + "error": "You can only view teams within your organizations." + }, + ) + verbose_proxy_logger.debug( + "list_team_v2: org admin access for user=%s, org_ids=%s", + user_api_key_dict.user_id, + org_admin_org_ids, + ) + elif not is_proxy_admin: + # Regular user — auto-inject caller's user_id + if user_id is None: + user_id = user_api_key_dict.user_id if status is not None and status != "deleted": raise HTTPException( @@ -3391,6 +3475,7 @@ async def list_team_v2( organization_id=organization_id, user_id=user_id, use_deleted_table=use_deleted_table, + org_admin_org_ids=org_admin_org_ids, ) # Build order_by conditions @@ -3428,8 +3513,23 @@ async def list_team_v2( # Calculate total pages total_pages = -(-total_count // page_size) # Ceiling division - # Convert Prisma models to Pydantic models, preserving deleted fields when applicable - team_list = _convert_teams_to_response(teams, use_deleted_table) + # Convert Prisma models to response models with members_count + team_list: List[Union[TeamListItem, LiteLLM_TeamTable, LiteLLM_DeletedTeamTable]] = [] + for team in teams: + try: + team_dict = team.model_dump() + except Exception: + team_dict = team.dict() + + if use_deleted_table: + team_list.append(LiteLLM_DeletedTeamTable(**team_dict)) + else: + members_with_roles = team_dict.get("members_with_roles") + if not isinstance(members_with_roles, list): + members_with_roles = [] + team_dict["members_with_roles"] = members_with_roles + members_count = len(members_with_roles) + team_list.append(TeamListItem(**team_dict, members_count=members_count)) return { "teams": team_list, diff --git a/litellm/proxy/schema.prisma b/litellm/proxy/schema.prisma index b68872e2ed..46be6b31e1 100644 --- a/litellm/proxy/schema.prisma +++ b/litellm/proxy/schema.prisma @@ -146,6 +146,10 @@ model LiteLLM_TeamTable { litellm_model_table LiteLLM_ModelTable? @relation(fields: [model_id], references: [id]) object_permission LiteLLM_ObjectPermissionTable? @relation(fields: [object_permission_id], references: [object_permission_id]) projects LiteLLM_ProjectTable[] + + @@index([organization_id]) + @@index([team_alias]) + @@index([created_at]) } // Projects sit between teams and keys for use-case management diff --git a/litellm/types/proxy/management_endpoints/team_endpoints.py b/litellm/types/proxy/management_endpoints/team_endpoints.py index 77816fa78c..a69d69c623 100644 --- a/litellm/types/proxy/management_endpoints/team_endpoints.py +++ b/litellm/types/proxy/management_endpoints/team_endpoints.py @@ -1,3 +1,4 @@ +from datetime import datetime from typing import Any, Dict, List, Optional, Union from pydantic import BaseModel @@ -43,10 +44,16 @@ class UpdateTeamMemberPermissionsRequest(BaseModel): team_member_permissions: List[str] +class TeamListItem(LiteLLM_TeamTable): + """A team item in the paginated list response, enriched with computed fields.""" + + members_count: int = 0 + + class TeamListResponse(BaseModel): """Response to get the list of teams""" - teams: List[Union[LiteLLM_TeamTable, LiteLLM_DeletedTeamTable]] + teams: List[Union[TeamListItem, LiteLLM_TeamTable, LiteLLM_DeletedTeamTable]] total: int page: int page_size: int diff --git a/schema.prisma b/schema.prisma index 939f1eb0f4..fde9a466a2 100644 --- a/schema.prisma +++ b/schema.prisma @@ -146,6 +146,10 @@ model LiteLLM_TeamTable { litellm_model_table LiteLLM_ModelTable? @relation(fields: [model_id], references: [id]) object_permission LiteLLM_ObjectPermissionTable? @relation(fields: [object_permission_id], references: [object_permission_id]) projects LiteLLM_ProjectTable[] + + @@index([organization_id]) + @@index([team_alias]) + @@index([created_at]) } // Projects sit between teams and keys for use-case management From 5e2fb72f42ef10e12e8d29e9120398db9b395fd2 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 17 Mar 2026 20:50:58 -0700 Subject: [PATCH 258/289] fix: address review feedback on v2/team/list - Fix org admin own-query regression: always check org admin status before the standard route check so own-queries see all org teams - Clear user_id when org admin is detected so org scope replaces user-membership scope - Remove dead isinstance(organization_id, list) branch - Remove unused datetime import - Remove orphaned _convert_teams_to_response helper Co-Authored-By: Claude Opus 4.6 (1M context) --- .../management_endpoints/team_endpoints.py | 79 +++++++------------ .../management_endpoints/team_endpoints.py | 1 - 2 files changed, 27 insertions(+), 53 deletions(-) diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py index a7ee340282..35122259c3 100644 --- a/litellm/proxy/management_endpoints/team_endpoints.py +++ b/litellm/proxy/management_endpoints/team_endpoints.py @@ -3262,11 +3262,7 @@ async def _build_team_list_where_conditions( } if organization_id: - # If a list is passed (org admin viewing multiple orgs), use IN - if isinstance(organization_id, list): - where_conditions["organization_id"] = {"in": organization_id} - else: - where_conditions["organization_id"] = organization_id + where_conditions["organization_id"] = organization_id elif org_admin_org_ids is not None: # Org admin without explicit org filter: scope to their orgs where_conditions["organization_id"] = {"in": org_admin_org_ids} @@ -3304,27 +3300,6 @@ async def _build_team_list_where_conditions( return where_conditions -def _convert_teams_to_response( - teams: List[Any], use_deleted_table: bool -) -> List[Union[LiteLLM_TeamTable, LiteLLM_DeletedTeamTable]]: - """Convert Prisma models to Pydantic models.""" - team_list: List[Union[LiteLLM_TeamTable, LiteLLM_DeletedTeamTable]] = [] - if teams: - for team in teams: - # Convert Prisma model to dict (supports both Pydantic v1 and v2) - try: - team_dict = team.model_dump() - except Exception: - # Fallback for Pydantic v1 compatibility - team_dict = team.dict() - if use_deleted_table: - # Use deleted team type to preserve deleted_at, deleted_by, etc. - team_list.append(LiteLLM_DeletedTeamTable(**team_dict)) - else: - team_list.append(LiteLLM_TeamTable(**team_dict)) - return team_list - - @router.get( "/v2/team/list", tags=["team management"], @@ -3409,31 +3384,15 @@ async def list_team_v2( org_admin_org_ids: Optional[List[str]] = None if not is_proxy_admin: - # First check if the standard route check passes (user querying own data) - passes_route_check = allowed_route_check_inside_route( - user_api_key_dict=user_api_key_dict, requested_user_id=user_id - ) - - if not passes_route_check: - # Standard check failed — see if the caller is an org admin - if user_api_key_dict.user_id: - org_admin_org_ids = await _get_org_admin_org_ids( - user_id=user_api_key_dict.user_id, - prisma_client=prisma_client, - user_api_key_cache=user_api_key_cache, - proxy_logging_obj=proxy_logging_obj, - ) - - if org_admin_org_ids is None: - # Not an org admin either — reject - raise HTTPException( - status_code=401, - detail={ - "error": "Only admin users can query all teams/other teams. Your user role={}".format( - user_api_key_dict.user_role - ) - }, - ) + # Always check org admin status so that even own-queries see + # the full set of organisation teams, not just direct memberships. + if user_api_key_dict.user_id: + org_admin_org_ids = await _get_org_admin_org_ids( + user_id=user_api_key_dict.user_id, + prisma_client=prisma_client, + user_api_key_cache=user_api_key_cache, + proxy_logging_obj=proxy_logging_obj, + ) if org_admin_org_ids is not None: # Org admin: validate org_id filter if provided @@ -3444,12 +3403,28 @@ async def list_team_v2( "error": "You can only view teams within your organizations." }, ) + # Org admin scope replaces user_id scope — the org filter + # already returns all teams in their orgs, so we don't also + # restrict by the user's direct team memberships. + user_id = None verbose_proxy_logger.debug( "list_team_v2: org admin access for user=%s, org_ids=%s", user_api_key_dict.user_id, org_admin_org_ids, ) - elif not is_proxy_admin: + else: + # Not an org admin — fall back to standard route check + if not allowed_route_check_inside_route( + user_api_key_dict=user_api_key_dict, requested_user_id=user_id + ): + raise HTTPException( + status_code=401, + detail={ + "error": "Only admin users can query all teams/other teams. Your user role={}".format( + user_api_key_dict.user_role + ) + }, + ) # Regular user — auto-inject caller's user_id if user_id is None: user_id = user_api_key_dict.user_id diff --git a/litellm/types/proxy/management_endpoints/team_endpoints.py b/litellm/types/proxy/management_endpoints/team_endpoints.py index a69d69c623..5055a65783 100644 --- a/litellm/types/proxy/management_endpoints/team_endpoints.py +++ b/litellm/types/proxy/management_endpoints/team_endpoints.py @@ -1,4 +1,3 @@ -from datetime import datetime from typing import Any, Dict, List, Optional, Union from pydantic import BaseModel From 1998571d94b366c9525f84ac96622242f4a16353 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 17 Mar 2026 21:03:35 -0700 Subject: [PATCH 259/289] fix: address second review round on v2/team/list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - _get_org_admin_org_ids: catch only ValueError (user not found) instead of bare Exception — DB errors now propagate as 500s instead of silently demoting org admins to regular users - _build_team_list_where_conditions: return None (not a sentinel string) when user has no team memberships; list_team_v2 short-circuits to empty response without hitting the DB - Org admin + team_id + user_id: use exact team_id match with org scope instead of OR expansion that effectively ignored the team_id filter - Org admin + user_id (no team_id): OR(org teams, direct memberships) now matches legacy _authorize_and_filter_teams behaviour Co-Authored-By: Claude Opus 4.6 (1M context) --- .../management_endpoints/team_endpoints.py | 82 ++++++++++++------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py index 35122259c3..b32206a454 100644 --- a/litellm/proxy/management_endpoints/team_endpoints.py +++ b/litellm/proxy/management_endpoints/team_endpoints.py @@ -3226,7 +3226,8 @@ async def _get_org_admin_org_ids( user_id_upsert=False, proxy_logging_obj=proxy_logging_obj, ) - except Exception: + except ValueError: + # get_user_object raises ValueError when the user doesn't exist return None if caller_user is None: @@ -3248,8 +3249,13 @@ async def _build_team_list_where_conditions( user_id: Optional[str], use_deleted_table: bool, org_admin_org_ids: Optional[List[str]] = None, -) -> Dict[str, Any]: - """Build where conditions for team list query.""" +) -> Optional[Dict[str, Any]]: + """ + Build where conditions for team list query. + + Returns None when the query is guaranteed to yield no results (e.g. user + has no team memberships), allowing the caller to skip the DB round-trip. + """ where_conditions: Dict[str, Any] = {} if team_id: @@ -3263,39 +3269,50 @@ async def _build_team_list_where_conditions( if organization_id: where_conditions["organization_id"] = organization_id - elif org_admin_org_ids is not None: - # Org admin without explicit org filter: scope to their orgs + elif org_admin_org_ids is not None and not user_id: + # Org admin without explicit org or user filter: scope to their orgs where_conditions["organization_id"] = {"in": org_admin_org_ids} if user_id: - try: - user_object = await prisma_client.db.litellm_usertable.find_unique( - where={"user_id": user_id} - ) - except Exception: - raise HTTPException( - status_code=404, - detail={"error": f"User not found, passed user_id={user_id}"}, - ) + user_object = await prisma_client.db.litellm_usertable.find_unique( + where={"user_id": user_id} + ) if user_object is None: raise HTTPException( status_code=404, detail={"error": f"User not found, passed user_id={user_id}"}, ) user_object_correct_type = LiteLLM_UserTable(**user_object.model_dump()) + user_team_ids = user_object_correct_type.teams or [] if use_deleted_table: where_conditions["members"] = {"has": user_id} - else: - if team_id is None: - where_conditions["team_id"] = {"in": user_object_correct_type.teams} - elif team_id in user_object_correct_type.teams: - where_conditions["team_id"] = team_id + elif org_admin_org_ids is not None: + # Org admin with user_id filter: show teams in their orgs + # OR teams the user is a direct member of (matches legacy + # _authorize_and_filter_teams behaviour). + # When team_id is also provided, the exact match is already in + # where_conditions and the org scope just needs to be added — + # no OR expansion needed. + if team_id is not None: + where_conditions["organization_id"] = {"in": org_admin_org_ids} + elif user_team_ids: + org_condition: Dict[str, Any] = {"organization_id": {"in": org_admin_org_ids}} + where_conditions["OR"] = [org_condition, {"team_id": {"in": user_team_ids}}] else: - raise HTTPException( - status_code=404, - detail={"error": f"User is not a member of team_id={team_id}"}, - ) + where_conditions["organization_id"] = {"in": org_admin_org_ids} + else: + if not user_team_ids: + return None # no memberships — skip the DB query + elif team_id is not None: + # team_id exact-match already in where_conditions; verify membership + if team_id not in user_team_ids: + raise HTTPException( + status_code=404, + detail={"error": f"User is not a member of team_id={team_id}"}, + ) + else: + where_conditions["team_id"] = {"in": user_team_ids} return where_conditions @@ -3403,14 +3420,11 @@ async def list_team_v2( "error": "You can only view teams within your organizations." }, ) - # Org admin scope replaces user_id scope — the org filter - # already returns all teams in their orgs, so we don't also - # restrict by the user's direct team memberships. - user_id = None verbose_proxy_logger.debug( - "list_team_v2: org admin access for user=%s, org_ids=%s", + "list_team_v2: org admin access for user=%s, org_ids=%s, user_id_filter=%s", user_api_key_dict.user_id, org_admin_org_ids, + user_id, ) else: # Not an org admin — fall back to standard route check @@ -3442,7 +3456,8 @@ async def list_team_v2( # Calculate skip and take for pagination skip = (page - 1) * page_size - # Build where conditions based on provided parameters + # Build where conditions based on provided parameters. + # Returns None when the query is guaranteed to yield no results. where_conditions = await _build_team_list_where_conditions( prisma_client=prisma_client, team_id=team_id, @@ -3453,6 +3468,15 @@ async def list_team_v2( org_admin_org_ids=org_admin_org_ids, ) + if where_conditions is None: + return { + "teams": [], + "total": 0, + "page": page, + "page_size": page_size, + "total_pages": 0, + } + # Build order_by conditions valid_sort_columns = ["team_id", "team_alias", "created_at"] order_by = None From 0485a1859a94520ff55148aeab313a102d2b50be Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 17 Mar 2026 21:19:42 -0700 Subject: [PATCH 260/289] fix: use get_user_object helper, preserve caller org_id filter - Replace raw find_unique with get_user_object in _build_team_list_where_conditions for cache/metrics consistency - Remove over-complex OR clause for org admin + user_id: when user_id is provided, filter by that user's direct team memberships (same as regular users) since the access control gate already verified the org admin's authority - Preserve caller-supplied organization_id instead of overwriting with org_admin_org_ids - Update test mock to match get_user_object call path Co-Authored-By: Claude Opus 4.6 (1M context) --- .../management_endpoints/team_endpoints.py | 41 +++++++------- .../test_team_endpoints.py | 55 +++++++++++-------- 2 files changed, 53 insertions(+), 43 deletions(-) diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py index b32206a454..531cd67589 100644 --- a/litellm/proxy/management_endpoints/team_endpoints.py +++ b/litellm/proxy/management_endpoints/team_endpoints.py @@ -3249,6 +3249,8 @@ async def _build_team_list_where_conditions( user_id: Optional[str], use_deleted_table: bool, org_admin_org_ids: Optional[List[str]] = None, + user_api_key_cache: Optional[Any] = None, + proxy_logging_obj: Optional[Any] = None, ) -> Optional[Dict[str, Any]]: """ Build where conditions for team list query. @@ -3274,34 +3276,33 @@ async def _build_team_list_where_conditions( where_conditions["organization_id"] = {"in": org_admin_org_ids} if user_id: - user_object = await prisma_client.db.litellm_usertable.find_unique( - where={"user_id": user_id} - ) - if user_object is None: + try: + user_object_correct_type = await get_user_object( + user_id=user_id, + prisma_client=prisma_client, + user_api_key_cache=user_api_key_cache, + user_id_upsert=False, + proxy_logging_obj=proxy_logging_obj, + ) + except ValueError: + raise HTTPException( + status_code=404, + detail={"error": f"User not found, passed user_id={user_id}"}, + ) + if user_object_correct_type is None: raise HTTPException( status_code=404, detail={"error": f"User not found, passed user_id={user_id}"}, ) - user_object_correct_type = LiteLLM_UserTable(**user_object.model_dump()) user_team_ids = user_object_correct_type.teams or [] if use_deleted_table: where_conditions["members"] = {"has": user_id} - elif org_admin_org_ids is not None: - # Org admin with user_id filter: show teams in their orgs - # OR teams the user is a direct member of (matches legacy - # _authorize_and_filter_teams behaviour). - # When team_id is also provided, the exact match is already in - # where_conditions and the org scope just needs to be added — - # no OR expansion needed. - if team_id is not None: - where_conditions["organization_id"] = {"in": org_admin_org_ids} - elif user_team_ids: - org_condition: Dict[str, Any] = {"organization_id": {"in": org_admin_org_ids}} - where_conditions["OR"] = [org_condition, {"team_id": {"in": user_team_ids}}] - else: - where_conditions["organization_id"] = {"in": org_admin_org_ids} else: + # When user_id is provided, filter by that user's direct team + # memberships. For org admins the access control gate in + # list_team_v2 already verified the caller's authority — the + # filter logic is the same as for regular users. if not user_team_ids: return None # no memberships — skip the DB query elif team_id is not None: @@ -3466,6 +3467,8 @@ async def list_team_v2( user_id=user_id, use_deleted_table=use_deleted_table, org_admin_org_ids=org_admin_org_ids, + user_api_key_cache=user_api_key_cache, + proxy_logging_obj=proxy_logging_obj, ) if where_conditions is None: 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 41a724c271..122ac749f2 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py @@ -2142,19 +2142,21 @@ async def test_list_team_v2_security_check_non_admin_user_own_teams(): user_id="non_admin_user_123", ) - with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma_client: + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma_client, \ + patch("litellm.proxy.proxy_server.user_api_key_cache"), \ + patch("litellm.proxy.proxy_server.proxy_logging_obj"): # Mock prisma client and database operations mock_db = Mock() mock_prisma_client.db = mock_db - - # Mock user lookup - mock_user_object = Mock() - mock_user_object.model_dump.return_value = { - "user_id": "non_admin_user_123", - "teams": ["team_1", "team_2"], - } - mock_db.litellm_usertable.find_unique = AsyncMock(return_value=mock_user_object) - + + # Mock get_user_object to return a user with teams + from litellm.proxy._types import LiteLLM_UserTable + + mock_user = LiteLLM_UserTable( + user_id="non_admin_user_123", + teams=["team_1", "team_2"], + ) + # Mock team lookup mock_teams = [ Mock(model_dump=lambda: {"team_id": "team_1", "team_alias": "Team 1"}), @@ -2163,21 +2165,26 @@ async def test_list_team_v2_security_check_non_admin_user_own_teams(): mock_db.litellm_teamtable.find_many = AsyncMock(return_value=mock_teams) mock_db.litellm_teamtable.count = AsyncMock(return_value=2) - # Should NOT raise an exception - result = await list_team_v2( - http_request=mock_request, - user_id="non_admin_user_123", # Non-admin querying their own teams - user_api_key_dict=mock_user_api_key_dict_non_admin, - team_id=None, - page=1, - page_size=10, - status=None, - ) + with patch( + "litellm.proxy.management_endpoints.team_endpoints.get_user_object", + new_callable=AsyncMock, + return_value=mock_user, + ): + # Should NOT raise an exception + result = await list_team_v2( + http_request=mock_request, + user_id="non_admin_user_123", # Non-admin querying their own teams + user_api_key_dict=mock_user_api_key_dict_non_admin, + team_id=None, + page=1, + page_size=10, + status=None, + ) - # Should return results without error - assert "teams" in result - assert "total" in result - assert result["total"] == 2 + # Should return results without error + assert "teams" in result + assert "total" in result + assert result["total"] == 2 @pytest.mark.asyncio From 41a7747e8cc99b133dd72ac6de6f55aaa9708e0d Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 17 Mar 2026 21:56:57 -0700 Subject: [PATCH 261/289] fix: document org scope behavior, fix test mocks, add org admin tests - Document intentional legacy-matching behavior: when user_id is provided to an org admin, no org filter is applied (returns all of that user's teams across all orgs, same as legacy endpoint) - Fix two existing security tests to properly patch user_api_key_cache, proxy_logging_obj, and get_user_object instead of relying on incidental error handling - Add three new org admin test cases: - Org admin sees org-scoped teams (200 with correct where clause) - Org admin rejected when filtering by other org (403) - Org admin with user_id filter returns target user's teams Co-Authored-By: Claude Opus 4.6 (1M context) --- .../management_endpoints/team_endpoints.py | 7 +- .../test_team_endpoints.py | 281 +++++++++++++++++- 2 files changed, 280 insertions(+), 8 deletions(-) diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py index 531cd67589..e7cd6c1748 100644 --- a/litellm/proxy/management_endpoints/team_endpoints.py +++ b/litellm/proxy/management_endpoints/team_endpoints.py @@ -3272,7 +3272,12 @@ async def _build_team_list_where_conditions( if organization_id: where_conditions["organization_id"] = organization_id elif org_admin_org_ids is not None and not user_id: - # Org admin without explicit org or user filter: scope to their orgs + # Org admin without explicit org or user filter: scope to their orgs. + # NOTE: when user_id is provided, no org filter is applied — the + # query returns all teams the target user belongs to across all + # organisations. This matches the legacy /team/list behaviour in + # _authorize_and_filter_teams which fetches direct-membership teams + # without an org constraint. where_conditions["organization_id"] = {"in": org_admin_org_ids} if user_id: 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 122ac749f2..c325b0b6fc 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py @@ -2062,7 +2062,14 @@ async def test_list_team_v2_security_check_non_admin_user(): user_id="non_admin_user_123", ) - with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma_client: + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma_client, \ + patch("litellm.proxy.proxy_server.user_api_key_cache"), \ + patch("litellm.proxy.proxy_server.proxy_logging_obj"), \ + patch( + "litellm.proxy.management_endpoints.team_endpoints.get_user_object", + new_callable=AsyncMock, + return_value=None, + ): mock_prisma_client.return_value = MagicMock() # Mock non-None prisma client # Should raise HTTPException with 401 status @@ -2103,7 +2110,14 @@ async def test_list_team_v2_security_check_non_admin_user_other_user(): user_id="non_admin_user_123", ) - with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma_client: + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma_client, \ + patch("litellm.proxy.proxy_server.user_api_key_cache"), \ + patch("litellm.proxy.proxy_server.proxy_logging_obj"), \ + patch( + "litellm.proxy.management_endpoints.team_endpoints.get_user_object", + new_callable=AsyncMock, + return_value=None, + ): mock_prisma_client.return_value = MagicMock() # Mock non-None prisma client # Should raise HTTPException with 401 status @@ -2300,27 +2314,280 @@ async def test_list_team_v2_with_status_deleted(): assert len(result["teams"]) == 2 +@pytest.mark.asyncio +async def test_list_team_v2_org_admin_sees_org_teams(): + """ + Test that an org admin (internal_user role with org_admin membership) + can list teams scoped to their organisations without getting a 401. + """ + from datetime import datetime + from unittest.mock import AsyncMock, Mock, patch + + from fastapi import Request + + from litellm.proxy._types import ( + LiteLLM_OrganizationMembershipTable, + LiteLLM_UserTable, + LitellmUserRoles, + UserAPIKeyAuth, + ) + from litellm.proxy.management_endpoints.team_endpoints import list_team_v2 + + mock_request = Mock(spec=Request) + mock_user_api_key_dict = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org_admin_user", + ) + + mock_user = LiteLLM_UserTable( + user_id="org_admin_user", + teams=[], + organization_memberships=[ + LiteLLM_OrganizationMembershipTable( + user_id="org_admin_user", + organization_id="org_A", + user_role="org_admin", + spend=0.0, + created_at=datetime.now(), + updated_at=datetime.now(), + ), + ], + ) + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, \ + patch("litellm.proxy.proxy_server.user_api_key_cache"), \ + patch("litellm.proxy.proxy_server.proxy_logging_obj"), \ + patch( + "litellm.proxy.management_endpoints.team_endpoints.get_user_object", + new_callable=AsyncMock, + return_value=mock_user, + ): + mock_db = Mock() + mock_prisma.db = mock_db + + mock_team = Mock() + mock_team.model_dump.return_value = { + "team_id": "team_in_org_A", + "team_alias": "Org A Team", + "organization_id": "org_A", + "members_with_roles": [{"user_id": "u1", "role": "user"}], + } + mock_db.litellm_teamtable.find_many = AsyncMock(return_value=[mock_team]) + mock_db.litellm_teamtable.count = AsyncMock(return_value=1) + + result = await list_team_v2( + http_request=mock_request, + user_id=None, + organization_id=None, + team_id=None, + team_alias=None, + user_api_key_dict=mock_user_api_key_dict, + page=1, + page_size=10, + sort_by=None, + sort_order="asc", + status=None, + ) + + assert result["total"] == 1 + assert len(result["teams"]) == 1 + assert result["teams"][0].members_count == 1 + + # Verify org-scoped where clause + where = mock_db.litellm_teamtable.find_many.call_args.kwargs["where"] + assert where["organization_id"] == {"in": ["org_A"]} + + +@pytest.mark.asyncio +async def test_list_team_v2_org_admin_cannot_view_other_orgs(): + """ + Test that an org admin is rejected with 403 when filtering by an + organisation they do not administer. + """ + from datetime import datetime + from unittest.mock import AsyncMock, Mock, patch + + from fastapi import HTTPException, Request + + from litellm.proxy._types import ( + LiteLLM_OrganizationMembershipTable, + LiteLLM_UserTable, + LitellmUserRoles, + UserAPIKeyAuth, + ) + from litellm.proxy.management_endpoints.team_endpoints import list_team_v2 + + mock_request = Mock(spec=Request) + mock_user_api_key_dict = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org_admin_user", + ) + + mock_user = LiteLLM_UserTable( + user_id="org_admin_user", + teams=[], + organization_memberships=[ + LiteLLM_OrganizationMembershipTable( + user_id="org_admin_user", + organization_id="org_A", + user_role="org_admin", + spend=0.0, + created_at=datetime.now(), + updated_at=datetime.now(), + ), + ], + ) + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, \ + patch("litellm.proxy.proxy_server.user_api_key_cache"), \ + patch("litellm.proxy.proxy_server.proxy_logging_obj"), \ + patch( + "litellm.proxy.management_endpoints.team_endpoints.get_user_object", + new_callable=AsyncMock, + return_value=mock_user, + ): + mock_prisma.db = Mock() + + with pytest.raises(HTTPException) as exc_info: + await list_team_v2( + http_request=mock_request, + user_id=None, + organization_id="org_B", # not their org + team_id=None, + team_alias=None, + user_api_key_dict=mock_user_api_key_dict, + page=1, + page_size=10, + sort_by=None, + sort_order="asc", + status=None, + ) + + assert exc_info.value.status_code == 403 + assert "only view teams within your organizations" in str( + exc_info.value.detail + ).lower() + + +@pytest.mark.asyncio +async def test_list_team_v2_org_admin_with_user_id_returns_user_teams(): + """ + Test that an org admin passing user_id gets that user's direct team + memberships (not all org teams). + """ + from datetime import datetime + from unittest.mock import AsyncMock, Mock, patch + + from fastapi import Request + + from litellm.proxy._types import ( + LiteLLM_OrganizationMembershipTable, + LiteLLM_UserTable, + LitellmUserRoles, + UserAPIKeyAuth, + ) + from litellm.proxy.management_endpoints.team_endpoints import list_team_v2 + + mock_request = Mock(spec=Request) + mock_user_api_key_dict = UserAPIKeyAuth( + user_role=LitellmUserRoles.INTERNAL_USER, + user_id="org_admin_user", + ) + + mock_org_admin = LiteLLM_UserTable( + user_id="org_admin_user", + teams=["team_1"], + organization_memberships=[ + LiteLLM_OrganizationMembershipTable( + user_id="org_admin_user", + organization_id="org_A", + user_role="org_admin", + spend=0.0, + created_at=datetime.now(), + updated_at=datetime.now(), + ), + ], + ) + + # The target user whose teams we want to list + mock_target_user = LiteLLM_UserTable( + user_id="target_user", + teams=["team_X", "team_Y"], + ) + + call_count = 0 + + async def mock_get_user_object(**kwargs): + nonlocal call_count + call_count += 1 + # First call: org admin lookup in list_team_v2 + # Second call: target user lookup in _build_team_list_where_conditions + if call_count == 1: + return mock_org_admin + return mock_target_user + + with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma, \ + patch("litellm.proxy.proxy_server.user_api_key_cache"), \ + patch("litellm.proxy.proxy_server.proxy_logging_obj"), \ + patch( + "litellm.proxy.management_endpoints.team_endpoints.get_user_object", + side_effect=mock_get_user_object, + ): + mock_db = Mock() + mock_prisma.db = mock_db + + mock_team = Mock() + mock_team.model_dump.return_value = { + "team_id": "team_X", + "team_alias": "Target Team", + "members_with_roles": [{"user_id": "target_user", "role": "user"}], + } + mock_db.litellm_teamtable.find_many = AsyncMock(return_value=[mock_team]) + mock_db.litellm_teamtable.count = AsyncMock(return_value=1) + + result = await list_team_v2( + http_request=mock_request, + user_id="target_user", + organization_id=None, + team_id=None, + team_alias=None, + user_api_key_dict=mock_user_api_key_dict, + page=1, + page_size=10, + sort_by=None, + sort_order="asc", + status=None, + ) + + assert result["total"] == 1 + + # Verify the where clause filters by user's teams, not org scope + where = mock_db.litellm_teamtable.find_many.call_args.kwargs["where"] + assert where["team_id"] == {"in": ["team_X", "team_Y"]} + assert "organization_id" not in where + + @pytest.mark.asyncio async def test_list_team_v2_with_invalid_status(): """ Test that invalid status parameter raises HTTPException. """ from unittest.mock import Mock, patch - + from fastapi import HTTPException, Request - + from litellm.proxy._types import LitellmUserRoles, UserAPIKeyAuth from litellm.proxy.management_endpoints.team_endpoints import list_team_v2 - + # Mock request mock_request = Mock(spec=Request) - + # Mock admin user mock_user_api_key_dict_admin = UserAPIKeyAuth( user_role=LitellmUserRoles.PROXY_ADMIN, user_id="admin_user_123", ) - + mock_prisma_client = Mock() # Mock prisma_client to be non-None From 19f82c229be550901a2941f4f48ed75a5f246d6e Mon Sep 17 00:00:00 2001 From: joereyna Date: Tue, 17 Mar 2026 22:11:43 -0700 Subject: [PATCH 262/289] fix: update full changelog base from v1.82.0-stable to v1.82.0 --- docs/my-website/release_notes/v1.82.3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/my-website/release_notes/v1.82.3.md b/docs/my-website/release_notes/v1.82.3.md index 15df33fdb8..7552ad6bc9 100644 --- a/docs/my-website/release_notes/v1.82.3.md +++ b/docs/my-website/release_notes/v1.82.3.md @@ -371,4 +371,4 @@ No major secret manager changes in this release. --- ## Full Changelog -[v1.82.0-stable...v1.82.3-stable](https://github.com/BerriAI/litellm/compare/v1.82.0-stable...v1.82.3-stable) +[v1.82.0...v1.82.3-stable](https://github.com/BerriAI/litellm/compare/v1.82.0...v1.82.3-stable) From 8a4ef0bd050e9c688fddb0dfc25c5307c051ed44 Mon Sep 17 00:00:00 2001 From: joereyna Date: Tue, 17 Mar 2026 22:17:12 -0700 Subject: [PATCH 263/289] revert: restore full changelog base to v1.82.0-stable --- docs/my-website/release_notes/v1.82.3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/my-website/release_notes/v1.82.3.md b/docs/my-website/release_notes/v1.82.3.md index 7552ad6bc9..15df33fdb8 100644 --- a/docs/my-website/release_notes/v1.82.3.md +++ b/docs/my-website/release_notes/v1.82.3.md @@ -371,4 +371,4 @@ No major secret manager changes in this release. --- ## Full Changelog -[v1.82.0...v1.82.3-stable](https://github.com/BerriAI/litellm/compare/v1.82.0...v1.82.3-stable) +[v1.82.0-stable...v1.82.3-stable](https://github.com/BerriAI/litellm/compare/v1.82.0-stable...v1.82.3-stable) From 2c874a7f3cb25a384336cb4061cebdce51457866 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 17 Mar 2026 23:00:05 -0700 Subject: [PATCH 264/289] fix: prevent body 'key' field from overriding Authorization header in auth On /key/block, /key/unblock, and /key/update, the request body 'key' field could contaminate the api_key Security dependency, causing the auth layer to authenticate against the target key instead of the caller's bearer token. This returned 401 for a nonexistent body key even when the Authorization header contained a valid master key. Added a guard in user_api_key_auth that re-reads the Authorization header directly from the request, ensuring the header is always the authoritative source for authentication. Co-Authored-By: Claude Opus 4.6 (1M context) --- litellm/proxy/auth/user_api_key_auth.py | 11 +++ .../test_key_management_endpoints.py | 85 +++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/litellm/proxy/auth/user_api_key_auth.py b/litellm/proxy/auth/user_api_key_auth.py index 376048e7a1..724184282f 100644 --- a/litellm/proxy/auth/user_api_key_auth.py +++ b/litellm/proxy/auth/user_api_key_auth.py @@ -1535,6 +1535,17 @@ async def user_api_key_auth( Parent function to authenticate user api key / jwt token. """ + # Guard: re-read the Authorization header directly from the request. + # On endpoints whose request body contains a "key" field (e.g. /key/block, + # /key/unblock, /key/update), the body value can contaminate the api_key + # Security dependency, causing the auth layer to authenticate against the + # target key instead of the caller's bearer token. + _raw_auth_header = request.headers.get( + SpecialHeaders.openai_authorization.value + ) + if _raw_auth_header is not None: + api_key = _raw_auth_header + request_data = await _read_request_body(request=request) request_data = populate_request_with_path_params( request_data=request_data, request=request diff --git a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py index cfc16808af..f1fb973a79 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py @@ -7185,3 +7185,88 @@ def test_update_key_request_has_organization_id(): # Also verify it defaults to None data_no_org = UpdateKeyRequest(key="sk-test-key") assert data_no_org.organization_id is None + + +@pytest.mark.asyncio +async def test_body_key_does_not_override_authorization_header(monkeypatch): + """ + Verify that the request body 'key' field (used by /key/block, /key/unblock, + /key/update) does not contaminate the api_key used for authentication. + + Regression test: previously, sending a request like + POST /key/block + Authorization: Bearer + Body: {"key": "sk-does-not-exist"} + would authenticate against "sk-does-not-exist" instead of the master key, + returning a 401 for a non-existent key even though the caller had a valid + master key in the Authorization header. + """ + from litellm.proxy.auth.user_api_key_auth import user_api_key_auth + + master_key = "sk-master-test-key-1234" + + # Mock proxy_server globals + monkeypatch.setattr("litellm.proxy.proxy_server.master_key", master_key) + monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", MagicMock()) + monkeypatch.setattr( + "litellm.proxy.proxy_server.general_settings", {} + ) + monkeypatch.setattr("litellm.proxy.proxy_server.jwt_handler", MagicMock()) + monkeypatch.setattr( + "litellm.proxy.proxy_server.litellm_proxy_admin_name", + "default_user_id", + ) + monkeypatch.setattr("litellm.proxy.proxy_server.llm_model_list", None) + monkeypatch.setattr("litellm.proxy.proxy_server.llm_router", None) + monkeypatch.setattr("litellm.proxy.proxy_server.user_custom_auth", None) + monkeypatch.setattr( + "litellm.proxy.proxy_server.open_telemetry_logger", None + ) + monkeypatch.setattr( + "litellm.proxy.proxy_server.model_max_budget_limiter", MagicMock() + ) + mock_user_api_key_cache = MagicMock() + mock_user_api_key_cache.async_get_cache = AsyncMock(return_value=None) + mock_user_api_key_cache.get_cache = MagicMock(return_value=None) + monkeypatch.setattr( + "litellm.proxy.proxy_server.user_api_key_cache", + mock_user_api_key_cache, + ) + monkeypatch.setattr( + "litellm.proxy.proxy_server.proxy_logging_obj", MagicMock() + ) + + # Build a mock request that simulates: + # POST /key/block + # Authorization: Bearer + # Body: {"key": "sk-does-not-exist"} + mock_request = MagicMock() + mock_request.headers = { + "Authorization": f"Bearer {master_key}", + "Content-Type": "application/json", + } + mock_request.url.path = "/key/block" + mock_request.method = "POST" + mock_request.query_params = {} + mock_request.scope = { + "type": "http", + "path": "/key/block", + # Simulate a pre-parsed body with a 'key' field that differs from the master key + "parsed_body": ( + ("key",), + {"key": "sk-does-not-exist"}, + ), + } + mock_request.state = MagicMock() + + # Call user_api_key_auth the way FastAPI does. If the body 'key' field + # contaminates the api_key parameter, pass it explicitly to prove the + # guard works. + result = await user_api_key_auth( + request=mock_request, + api_key="sk-does-not-exist", # Simulates the contaminated value + ) + + # Auth should succeed — the guard re-reads the Authorization header + assert result is not None + assert result.user_role == LitellmUserRoles.PROXY_ADMIN From b0990e2684d8379e740e2f608e8f21a0cb491404 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 17 Mar 2026 23:02:38 -0700 Subject: [PATCH 265/289] Revert "fix: prevent body 'key' field from overriding Authorization header in auth" This reverts commit 2c874a7f3cb25a384336cb4061cebdce51457866. --- litellm/proxy/auth/user_api_key_auth.py | 11 --- .../test_key_management_endpoints.py | 85 ------------------- 2 files changed, 96 deletions(-) diff --git a/litellm/proxy/auth/user_api_key_auth.py b/litellm/proxy/auth/user_api_key_auth.py index 724184282f..376048e7a1 100644 --- a/litellm/proxy/auth/user_api_key_auth.py +++ b/litellm/proxy/auth/user_api_key_auth.py @@ -1535,17 +1535,6 @@ async def user_api_key_auth( Parent function to authenticate user api key / jwt token. """ - # Guard: re-read the Authorization header directly from the request. - # On endpoints whose request body contains a "key" field (e.g. /key/block, - # /key/unblock, /key/update), the body value can contaminate the api_key - # Security dependency, causing the auth layer to authenticate against the - # target key instead of the caller's bearer token. - _raw_auth_header = request.headers.get( - SpecialHeaders.openai_authorization.value - ) - if _raw_auth_header is not None: - api_key = _raw_auth_header - request_data = await _read_request_body(request=request) request_data = populate_request_with_path_params( request_data=request_data, request=request diff --git a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py index f1fb973a79..cfc16808af 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py @@ -7185,88 +7185,3 @@ def test_update_key_request_has_organization_id(): # Also verify it defaults to None data_no_org = UpdateKeyRequest(key="sk-test-key") assert data_no_org.organization_id is None - - -@pytest.mark.asyncio -async def test_body_key_does_not_override_authorization_header(monkeypatch): - """ - Verify that the request body 'key' field (used by /key/block, /key/unblock, - /key/update) does not contaminate the api_key used for authentication. - - Regression test: previously, sending a request like - POST /key/block - Authorization: Bearer - Body: {"key": "sk-does-not-exist"} - would authenticate against "sk-does-not-exist" instead of the master key, - returning a 401 for a non-existent key even though the caller had a valid - master key in the Authorization header. - """ - from litellm.proxy.auth.user_api_key_auth import user_api_key_auth - - master_key = "sk-master-test-key-1234" - - # Mock proxy_server globals - monkeypatch.setattr("litellm.proxy.proxy_server.master_key", master_key) - monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", MagicMock()) - monkeypatch.setattr( - "litellm.proxy.proxy_server.general_settings", {} - ) - monkeypatch.setattr("litellm.proxy.proxy_server.jwt_handler", MagicMock()) - monkeypatch.setattr( - "litellm.proxy.proxy_server.litellm_proxy_admin_name", - "default_user_id", - ) - monkeypatch.setattr("litellm.proxy.proxy_server.llm_model_list", None) - monkeypatch.setattr("litellm.proxy.proxy_server.llm_router", None) - monkeypatch.setattr("litellm.proxy.proxy_server.user_custom_auth", None) - monkeypatch.setattr( - "litellm.proxy.proxy_server.open_telemetry_logger", None - ) - monkeypatch.setattr( - "litellm.proxy.proxy_server.model_max_budget_limiter", MagicMock() - ) - mock_user_api_key_cache = MagicMock() - mock_user_api_key_cache.async_get_cache = AsyncMock(return_value=None) - mock_user_api_key_cache.get_cache = MagicMock(return_value=None) - monkeypatch.setattr( - "litellm.proxy.proxy_server.user_api_key_cache", - mock_user_api_key_cache, - ) - monkeypatch.setattr( - "litellm.proxy.proxy_server.proxy_logging_obj", MagicMock() - ) - - # Build a mock request that simulates: - # POST /key/block - # Authorization: Bearer - # Body: {"key": "sk-does-not-exist"} - mock_request = MagicMock() - mock_request.headers = { - "Authorization": f"Bearer {master_key}", - "Content-Type": "application/json", - } - mock_request.url.path = "/key/block" - mock_request.method = "POST" - mock_request.query_params = {} - mock_request.scope = { - "type": "http", - "path": "/key/block", - # Simulate a pre-parsed body with a 'key' field that differs from the master key - "parsed_body": ( - ("key",), - {"key": "sk-does-not-exist"}, - ), - } - mock_request.state = MagicMock() - - # Call user_api_key_auth the way FastAPI does. If the body 'key' field - # contaminates the api_key parameter, pass it explicitly to prove the - # guard works. - result = await user_api_key_auth( - request=mock_request, - api_key="sk-does-not-exist", # Simulates the contaminated value - ) - - # Auth should succeed — the guard re-reads the Authorization header - assert result is not None - assert result.user_role == LitellmUserRoles.PROXY_ADMIN From 3fd50c913278cff7e55d417138470f7db8b9211e Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Wed, 18 Mar 2026 12:58:57 +0530 Subject: [PATCH 266/289] docker proxy guide fix --- .../docs/proxy/docker_quick_start.md | 60 +++++++++++++++++-- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/docs/my-website/docs/proxy/docker_quick_start.md b/docs/my-website/docs/proxy/docker_quick_start.md index 4cce4d0e23..3353b16bee 100644 --- a/docs/my-website/docs/proxy/docker_quick_start.md +++ b/docs/my-website/docs/proxy/docker_quick_start.md @@ -50,9 +50,11 @@ See all available tags on the [GitHub Container Registry](https://github.com/Ber --- -### Step 2 — Set up a database +### Step 2 — Create required config files -Get the docker compose file and create your `.env` first: +You need three files in the same directory as `docker-compose.yml` before running `docker compose up`: `.env`, `config.yaml`, and `prometheus.yml`. + +### Step 2.1 — Create your `.env` ```bash # Get the docker compose file @@ -71,7 +73,9 @@ echo 'AZURE_API_BASE="https://openai-***********/"' >> .env echo 'AZURE_API_KEY="your-azure-api-key"' >> .env ``` -Then finish your `config.yaml` before starting the proxy server. If you use the default `docker-compose.yml`, the Postgres container is available at `db:5432`. +### Step 2.2 — Create your `config.yaml` + +Proxy and model configuration. If you use the default `docker-compose.yml`, the Postgres container is available at `db:5432`. ```yaml model_list: @@ -91,13 +95,41 @@ general_settings: `database_url` is required for virtual keys, spend tracking, and the UI. If you want a managed database instead, replace it with your [Supabase](https://supabase.com/) or [Neon](https://neon.tech/) connection string. ::: -Save this file as `config.yaml`. +### Step 2.3 — Create your `prometheus.yml` + +Metrics scrape config. This file **must exist as a file** before `docker compose up`. If it is missing, Docker auto-creates it as an empty directory, which causes the Prometheus container to fail. + +```yaml +global: + scrape_interval: 15s + evaluation_interval: 15s + +scrape_configs: + - job_name: "litellm" + static_configs: + - targets: ["litellm:4000"] +``` + +Also verify that the `config.yaml` volume mount and `--config` command are **not commented out** in your `docker-compose.yml`: + +```yaml +services: + litellm: + volumes: + - ./config.yaml:/app/config.yaml # ✅ must be uncommented + command: + - "--config=/app/config.yaml" # ✅ must be uncommented +``` + +:::warning +All three files must be present before running `docker compose up`. Missing files are the most common cause of startup errors. See the [Troubleshooting](#troubleshooting) section if you run into issues. +::: --- ### Step 3 — Start the proxy server and test it -After `config.yaml` and `.env` are complete, start the proxy: +After `config.yaml`, `prometheus.yml`, and `.env` are complete, start the proxy: ```bash docker compose up @@ -630,6 +662,24 @@ model_list: ## Troubleshooting +### `prometheus.yml` mount error — "not a directory" + +If you see: + +```bash +Error: cannot create subdirectories in ".../prometheus.yml": not a directory +``` + +Docker created `prometheus.yml` as an **empty directory** instead of a file. This happens when the file is missing at `docker compose up` time — Docker auto-creates missing bind-mount paths as directories. + +Fix it by deleting the directory and creating the file manually: + +```bash +rm -rf prometheus.yml +``` + +Then create a valid `prometheus.yml` file (see [Step 2](#step-25--create-required-config-files)) and run `docker compose up` again. + ### Non-root docker image? If you need to run the docker image as a non-root user, use [this](https://github.com/BerriAI/litellm/pkgs/container/litellm-non_root). From 70a9e6038e8e5761705314859f22383227e00dcf Mon Sep 17 00:00:00 2001 From: Arindam200 Date: Wed, 18 Mar 2026 13:03:39 +0530 Subject: [PATCH 267/289] fix:expected response --- .../docs/proxy/docker_quick_start.md | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/docs/my-website/docs/proxy/docker_quick_start.md b/docs/my-website/docs/proxy/docker_quick_start.md index 3353b16bee..b2a6b1220f 100644 --- a/docs/my-website/docs/proxy/docker_quick_start.md +++ b/docs/my-website/docs/proxy/docker_quick_start.md @@ -151,10 +151,38 @@ curl -X POST 'http://0.0.0.0:4000/chat/completions' \ ```json { - "id": "chatcmpl-abc123", + "id": "chatcmpl-abcd", + "created": 1773817678, + "model": "gpt-4o", "object": "chat.completion", - "choices": [{"message": {"role": "assistant", "content": "Hello! How can I help you?"}, "finish_reason": "stop"}], - "usage": {"prompt_tokens": 10, "completion_tokens": 9, "total_tokens": 19} + "system_fingerprint": "fp_6b1ef07cda", + "choices": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Hello! How can I assist you today?", + "role": "assistant", + "annotations": [] + } + } + ], + "usage": { + "completion_tokens": 9, + "prompt_tokens": 9, + "total_tokens": 18, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 0, + "rejected_prediction_tokens": 0 + }, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + } + }, + "service_tier": "default" } ``` @@ -203,8 +231,6 @@ You can read more about how model resolution works in the [Model Configuration]( - **`api_base`** (`str`) - The API base for your azure deployment. - **`api_version`** (`str`) - The API Version to use when calling Azure's OpenAI API. Get the latest Inference API version [here](https://learn.microsoft.com/en-us/azure/ai-services/openai/api-version-deprecation?source=recommendations#latest-preview-api-releases). ---- - --- From cd549bf4f5d61d3eaf0195371a5d2a5dcf98df0a Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Wed, 18 Mar 2026 00:40:00 -0700 Subject: [PATCH 268/289] [Refactor] UI - Playground: Extract FilePreviewCard from ChatUI Extract duplicate file preview JSX blocks (responses and chat image previews) into a reusable FilePreviewCard component, reducing ~50 lines of duplicated markup in ChatUI.tsx. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../components/playground/chat_ui/ChatUI.tsx | 69 +++--------------- .../chat_ui/FilePreviewCard.test.tsx | 70 +++++++++++++++++++ .../playground/chat_ui/FilePreviewCard.tsx | 45 ++++++++++++ 3 files changed, 126 insertions(+), 58 deletions(-) create mode 100644 ui/litellm-dashboard/src/components/playground/chat_ui/FilePreviewCard.test.tsx create mode 100644 ui/litellm-dashboard/src/components/playground/chat_ui/FilePreviewCard.tsx diff --git a/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.tsx b/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.tsx index eba9d37669..bc0d52cf58 100644 --- a/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.tsx +++ b/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.tsx @@ -60,6 +60,7 @@ import CodeInterpreterOutput from "./CodeInterpreterOutput"; import CodeInterpreterTool from "./CodeInterpreterTool"; import { generateCodeSnippet } from "./CodeSnippets"; import EndpointSelector from "./EndpointSelector"; +import FilePreviewCard from "./FilePreviewCard"; import MCPEventsDisplay from "./MCPEventsDisplay"; import type { MCPEvent } from "../../mcp_tools/types"; import { EndpointType, getEndpointType } from "./mode_endpoint_mapping"; @@ -2231,67 +2232,19 @@ const ChatUI: React.FC = ({ {/* Show file previews above input when files are uploaded */} {endpointType === EndpointType.RESPONSES && responsesUploadedImage && ( -