From 5a846c2e640727d11c113d9d92ec08e2f58ecb11 Mon Sep 17 00:00:00 2001 From: Ben Langfeld Date: Mon, 23 Mar 2026 10:59:18 -0300 Subject: [PATCH 01/37] Correct documentation of completion_model See https://github.com/BerriAI/litellm/issues/21554 --- docs/my-website/docs/proxy/config_settings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/my-website/docs/proxy/config_settings.md b/docs/my-website/docs/proxy/config_settings.md index 91445863f76..80094bd76f2 100644 --- a/docs/my-website/docs/proxy/config_settings.md +++ b/docs/my-website/docs/proxy/config_settings.md @@ -206,7 +206,7 @@ router_settings: | Name | Type | Description | |------|------|-------------| -| completion_model | string | The default model to use for completions when `model` is not specified in the request | +| completion_model | string | The default model to use for all completions regardless of `model` specified in the request | | disable_spend_logs | boolean | If true, turns off writing each transaction to the database | | disable_spend_updates | boolean | If true, turns off all spend updates to the DB. Including key/user/team spend updates. | | disable_master_key_return | boolean | If true, turns off returning master key on UI. (checked on '/user/info' endpoint) | From 847c12e4f5bfef0356aed793fb1e425b8aa8a10b Mon Sep 17 00:00:00 2001 From: Ben Langfeld Date: Mon, 23 Mar 2026 11:06:09 -0300 Subject: [PATCH 02/37] Update docs/my-website/docs/proxy/config_settings.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- docs/my-website/docs/proxy/config_settings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/my-website/docs/proxy/config_settings.md b/docs/my-website/docs/proxy/config_settings.md index 80094bd76f2..02f5c2be9c7 100644 --- a/docs/my-website/docs/proxy/config_settings.md +++ b/docs/my-website/docs/proxy/config_settings.md @@ -206,7 +206,7 @@ router_settings: | Name | Type | Description | |------|------|-------------| -| completion_model | string | The default model to use for all completions regardless of `model` specified in the request | +| completion_model | string | The model to use for all completions, overriding any `model` specified in the request | | disable_spend_logs | boolean | If true, turns off writing each transaction to the database | | disable_spend_updates | boolean | If true, turns off all spend updates to the DB. Including key/user/team spend updates. | | disable_master_key_return | boolean | If true, turns off returning master key on UI. (checked on '/user/info' endpoint) | From ae454fd7005a5706f7bdc3d4b584ae865e5013c3 Mon Sep 17 00:00:00 2001 From: michelligabriele Date: Wed, 18 Mar 2026 00:12:45 +0100 Subject: [PATCH 03/37] fix(proxy): OpenAI Moderation post-call guardrail response not captured for logging Two independent bugs prevented post-call OpenAI Moderation guardrail results from reaching downstream logging callbacks (Langfuse, Datadog). Bug 1: process_output_response() created a throwaway request_data dict, so guardrail info written by @log_guardrail_information was discarded. Fixed by threading the real request_data from the unified guardrail dispatcher through all 13 BaseTranslation handlers, with litellm_metadata injection preserved for third-party guardrails (Zscaler, Prompt Security). Also extended to process_output_streaming_response for consistency. Bug 2: The @log_guardrail_information decorator collapsed the full moderation API response (categories, scores, flagged status) to "allow". Fixed by overriding _process_response/_process_error on OpenAIModerationGuardrail to stash and log the full response, following the established Model Armor pattern. --- .../a2a/chat/guardrail_translation/handler.py | 36 ++- .../chat/guardrail_translation/handler.py | 26 +- .../guardrail_translation/base_translation.py | 2 + .../rerank/guardrail_translation/handler.py | 1 + .../ocr/guardrail_translation/handler.py | 17 +- .../chat/guardrail_translation/handler.py | 43 +++- .../guardrail_translation/handler.py | 21 +- .../guardrail_translation/handler.py | 1 + .../guardrail_translation/handler.py | 1 + .../guardrail_translation/handler.py | 26 +- .../speech/guardrail_translation/handler.py | 1 + .../guardrail_translation/handler.py | 21 +- .../guardrail_translation/handler.py | 29 ++- .../guardrail_translation/handler.py | 1 + .../guardrail_hooks/openai/moderations.py | 87 ++++++- .../unified_guardrail/unified_guardrail.py | 2 + .../openai/test_moderations.py | 242 ++++++++++++++++++ 17 files changed, 488 insertions(+), 69 deletions(-) diff --git a/litellm/llms/a2a/chat/guardrail_translation/handler.py b/litellm/llms/a2a/chat/guardrail_translation/handler.py index fbd1da749c2..91e7e9d5550 100644 --- a/litellm/llms/a2a/chat/guardrail_translation/handler.py +++ b/litellm/llms/a2a/chat/guardrail_translation/handler.py @@ -111,6 +111,7 @@ class A2AGuardrailHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional["LiteLLMLoggingObj"] = None, user_api_key_dict: Optional["UserAPIKeyAuth"] = None, + request_data: Optional[dict] = None, ) -> Any: """ Process A2A output response by applying guardrails to text content. @@ -166,13 +167,21 @@ class A2AGuardrailHandler(BaseTranslation): return response # Step 2: Apply guardrail to all texts in batch - # Create a request_data dict with response info and user API key metadata - request_data: dict = {"response": response_dict} + # Use the real request_data if provided (proxy path), otherwise + # create a standalone dict (SDK / direct-call path). + if request_data is None: + request_data = {"response": response_dict} + else: + if "response" not in request_data: + request_data["response"] = response_dict # Add user API key metadata with prefixed keys - user_metadata = self.transform_user_api_key_dict_to_metadata(user_api_key_dict) - if user_metadata: - request_data["litellm_metadata"] = user_metadata + if "litellm_metadata" not in request_data: + user_metadata = self.transform_user_api_key_dict_to_metadata( + user_api_key_dict + ) + if user_metadata: + request_data["litellm_metadata"] = user_metadata inputs = GenericGuardrailAPIInputs(texts=texts_to_check) @@ -213,6 +222,7 @@ class A2AGuardrailHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional["LiteLLMLoggingObj"] = None, user_api_key_dict: Optional["UserAPIKeyAuth"] = None, + request_data: Optional[dict] = None, ) -> List[Any]: """ Process A2A streaming output by applying guardrails to accumulated text. @@ -258,10 +268,18 @@ class A2AGuardrailHandler(BaseTranslation): if not combined_text: return responses_so_far - request_data: dict = {"responses_so_far": responses_so_far} - user_metadata = self.transform_user_api_key_dict_to_metadata(user_api_key_dict) - if user_metadata: - request_data["litellm_metadata"] = user_metadata + if request_data is None: + request_data = {"responses_so_far": responses_so_far} + else: + if "responses_so_far" not in request_data: + request_data["responses_so_far"] = responses_so_far + + if "litellm_metadata" not in request_data: + user_metadata = self.transform_user_api_key_dict_to_metadata( + user_api_key_dict + ) + if user_metadata: + request_data["litellm_metadata"] = user_metadata inputs = GenericGuardrailAPIInputs(texts=[combined_text]) guardrailed_inputs = await guardrail_to_apply.apply_guardrail( diff --git a/litellm/llms/anthropic/chat/guardrail_translation/handler.py b/litellm/llms/anthropic/chat/guardrail_translation/handler.py index 5372757cbb6..b6139a2f84d 100644 --- a/litellm/llms/anthropic/chat/guardrail_translation/handler.py +++ b/litellm/llms/anthropic/chat/guardrail_translation/handler.py @@ -252,6 +252,7 @@ class AnthropicMessagesHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional[Any] = None, user_api_key_dict: Optional[Any] = None, + request_data: Optional[dict] = None, ) -> Any: """ Process output response by applying guardrails to text content and tool calls. @@ -323,15 +324,21 @@ class AnthropicMessagesHandler(BaseTranslation): # Step 2: Apply guardrail to all texts in batch if texts_to_check or tool_calls_to_check: - # Create a request_data dict with response info and user API key metadata - request_data: dict = {"response": response} + # Use the real request_data if provided (proxy path), otherwise + # create a standalone dict (SDK / direct-call path). + if request_data is None: + request_data = {"response": response} + else: + if "response" not in request_data: + request_data["response"] = response # Add user API key metadata with prefixed keys - user_metadata = self.transform_user_api_key_dict_to_metadata( - user_api_key_dict - ) - if user_metadata: - request_data["litellm_metadata"] = user_metadata + if "litellm_metadata" not in request_data: + user_metadata = self.transform_user_api_key_dict_to_metadata( + user_api_key_dict + ) + if user_metadata: + request_data["litellm_metadata"] = user_metadata inputs = GenericGuardrailAPIInputs(texts=texts_to_check) if images_to_check: @@ -375,6 +382,7 @@ class AnthropicMessagesHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional[Any] = None, user_api_key_dict: Optional[Any] = None, + request_data: Optional[dict] = None, ) -> List[Any]: """ Process output streaming response by applying guardrails to text content. @@ -413,7 +421,7 @@ class AnthropicMessagesHandler(BaseTranslation): _guardrailed_inputs = await guardrail_to_apply.apply_guardrail( # allow rejecting the response, if invalid inputs=guardrail_inputs, - request_data={}, + request_data=request_data if request_data is not None else {}, input_type="response", logging_obj=litellm_logging_obj, ) @@ -426,7 +434,7 @@ class AnthropicMessagesHandler(BaseTranslation): string_so_far = self.get_streaming_string_so_far(responses_so_far) _guardrailed_inputs = await guardrail_to_apply.apply_guardrail( # allow rejecting the response, if invalid inputs={"texts": [string_so_far]}, - request_data={}, + request_data=request_data if request_data is not None else {}, input_type="response", logging_obj=litellm_logging_obj, ) diff --git a/litellm/llms/base_llm/guardrail_translation/base_translation.py b/litellm/llms/base_llm/guardrail_translation/base_translation.py index a7982cb606e..e1da0dfa29e 100644 --- a/litellm/llms/base_llm/guardrail_translation/base_translation.py +++ b/litellm/llms/base_llm/guardrail_translation/base_translation.py @@ -73,6 +73,7 @@ class BaseTranslation(ABC): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional["LiteLLMLoggingObj"] = None, user_api_key_dict: Optional["UserAPIKeyAuth"] = None, + request_data: Optional[dict] = None, ) -> Any: """ Process output response with guardrails. @@ -91,6 +92,7 @@ class BaseTranslation(ABC): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional["LiteLLMLoggingObj"] = None, user_api_key_dict: Optional["UserAPIKeyAuth"] = None, + request_data: Optional[dict] = None, ) -> Any: """ Process output streaming response with guardrails. diff --git a/litellm/llms/cohere/rerank/guardrail_translation/handler.py b/litellm/llms/cohere/rerank/guardrail_translation/handler.py index b8133c59f7d..e9a5823d2b8 100644 --- a/litellm/llms/cohere/rerank/guardrail_translation/handler.py +++ b/litellm/llms/cohere/rerank/guardrail_translation/handler.py @@ -83,6 +83,7 @@ class CohereRerankHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional[Any] = None, user_api_key_dict: Optional[Any] = None, + request_data: Optional[dict] = None, ) -> Any: """ Process output response - not applicable for rerank. diff --git a/litellm/llms/mistral/ocr/guardrail_translation/handler.py b/litellm/llms/mistral/ocr/guardrail_translation/handler.py index 697bd2daa3d..795ce1d7cae 100644 --- a/litellm/llms/mistral/ocr/guardrail_translation/handler.py +++ b/litellm/llms/mistral/ocr/guardrail_translation/handler.py @@ -91,6 +91,7 @@ class OCRHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional[Any] = None, user_api_key_dict: Optional[Any] = None, + request_data: Optional[dict] = None, ) -> Any: """ Process OCR output by applying guardrails to extracted page text. @@ -127,14 +128,22 @@ class OCRHandler(BaseTranslation): if model: inputs["model"] = model + # Use the real request_data if provided (proxy path), otherwise + # create a standalone dict (SDK / direct-call path). + if request_data is None: + request_data = {} + # Add user metadata if available - if user_api_key_dict is not None: - metadata = self.transform_user_api_key_dict_to_metadata(user_api_key_dict) - inputs.update(metadata) # type: ignore + if "litellm_metadata" not in request_data and user_api_key_dict is not None: + user_metadata = self.transform_user_api_key_dict_to_metadata( + user_api_key_dict + ) + if user_metadata: + request_data["litellm_metadata"] = user_metadata guardrailed_inputs = await guardrail_to_apply.apply_guardrail( inputs=inputs, - request_data={}, + request_data=request_data, input_type="response", logging_obj=litellm_logging_obj, ) diff --git a/litellm/llms/openai/chat/guardrail_translation/handler.py b/litellm/llms/openai/chat/guardrail_translation/handler.py index bab4c3b5eb7..f854cdb13d0 100644 --- a/litellm/llms/openai/chat/guardrail_translation/handler.py +++ b/litellm/llms/openai/chat/guardrail_translation/handler.py @@ -260,6 +260,7 @@ class OpenAIChatCompletionsHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional[Any] = None, user_api_key_dict: Optional[Any] = None, + request_data: Optional[dict] = None, ) -> Any: """ Process output response by applying guardrails to text content. @@ -308,15 +309,21 @@ class OpenAIChatCompletionsHandler(BaseTranslation): # Step 2: Apply guardrail to all texts and tool calls in batch if texts_to_check or tool_calls_to_check: - # Create a request_data dict with response info and user API key metadata - request_data: dict = {"response": response} + # Use the real request_data if provided (proxy path), otherwise + # create a standalone dict (SDK / direct-call path). + if request_data is None: + request_data = {"response": response} + else: + if "response" not in request_data: + request_data["response"] = response # Add user API key metadata with prefixed keys - user_metadata = self.transform_user_api_key_dict_to_metadata( - user_api_key_dict - ) - if user_metadata: - request_data["litellm_metadata"] = user_metadata + if "litellm_metadata" not in request_data: + user_metadata = self.transform_user_api_key_dict_to_metadata( + user_api_key_dict + ) + if user_metadata: + request_data["litellm_metadata"] = user_metadata inputs = GenericGuardrailAPIInputs(texts=texts_to_check) if images_to_check: @@ -364,6 +371,7 @@ class OpenAIChatCompletionsHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional[Any] = None, user_api_key_dict: Optional[Any] = None, + request_data: Optional[dict] = None, ) -> List["ModelResponseStream"]: """ Process output streaming responses by applying guardrails to text content. @@ -402,6 +410,7 @@ class OpenAIChatCompletionsHandler(BaseTranslation): guardrail_to_apply=guardrail_to_apply, litellm_logging_obj=litellm_logging_obj, user_api_key_dict=user_api_key_dict, + request_data=request_data, ) return responses_so_far @@ -436,15 +445,21 @@ class OpenAIChatCompletionsHandler(BaseTranslation): # Step 3: Apply guardrail to all combined texts in batch if texts_to_check: - # Create a request_data dict with response info and user API key metadata - request_data: dict = {"responses": responses_so_far} + # Use the real request_data if provided (proxy path), otherwise + # create a standalone dict (SDK / direct-call path). + if request_data is None: + request_data = {"responses": responses_so_far} + else: + if "responses" not in request_data: + request_data["responses"] = responses_so_far # Add user API key metadata with prefixed keys - user_metadata = self.transform_user_api_key_dict_to_metadata( - user_api_key_dict - ) - if user_metadata: - request_data["litellm_metadata"] = user_metadata + if "litellm_metadata" not in request_data: + user_metadata = self.transform_user_api_key_dict_to_metadata( + user_api_key_dict + ) + if user_metadata: + request_data["litellm_metadata"] = user_metadata inputs = GenericGuardrailAPIInputs(texts=texts_to_check) if images_to_check: diff --git a/litellm/llms/openai/completion/guardrail_translation/handler.py b/litellm/llms/openai/completion/guardrail_translation/handler.py index 1f8c6159da0..593ab0ed2e5 100644 --- a/litellm/llms/openai/completion/guardrail_translation/handler.py +++ b/litellm/llms/openai/completion/guardrail_translation/handler.py @@ -125,6 +125,7 @@ class OpenAITextCompletionHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional[Any] = None, user_api_key_dict: Optional[Any] = None, + request_data: Optional[dict] = None, ) -> Any: """ Process output response by applying guardrails to completion text. @@ -155,15 +156,21 @@ class OpenAITextCompletionHandler(BaseTranslation): # Apply guardrails in batch if texts_to_check: - # Create a request_data dict with response info and user API key metadata - request_data: dict = {"response": response} + # Use the real request_data if provided (proxy path), otherwise + # create a standalone dict (SDK / direct-call path). + if request_data is None: + request_data = {"response": response} + else: + if "response" not in request_data: + request_data["response"] = response # Add user API key metadata with prefixed keys - user_metadata = self.transform_user_api_key_dict_to_metadata( - user_api_key_dict - ) - if user_metadata: - request_data["litellm_metadata"] = user_metadata + if "litellm_metadata" not in request_data: + user_metadata = self.transform_user_api_key_dict_to_metadata( + user_api_key_dict + ) + if user_metadata: + request_data["litellm_metadata"] = user_metadata inputs = GenericGuardrailAPIInputs(texts=texts_to_check) # Include model information from the response if available diff --git a/litellm/llms/openai/embeddings/guardrail_translation/handler.py b/litellm/llms/openai/embeddings/guardrail_translation/handler.py index 7458020e109..ff5021b8ce0 100644 --- a/litellm/llms/openai/embeddings/guardrail_translation/handler.py +++ b/litellm/llms/openai/embeddings/guardrail_translation/handler.py @@ -155,6 +155,7 @@ class OpenAIEmbeddingsHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional[Any] = None, user_api_key_dict: Optional[Any] = None, + request_data: Optional[dict] = None, ) -> Any: """ Process output response - embeddings responses contain vectors, not text. diff --git a/litellm/llms/openai/image_generation/guardrail_translation/handler.py b/litellm/llms/openai/image_generation/guardrail_translation/handler.py index e6340ba4705..76610088d0c 100644 --- a/litellm/llms/openai/image_generation/guardrail_translation/handler.py +++ b/litellm/llms/openai/image_generation/guardrail_translation/handler.py @@ -87,6 +87,7 @@ class OpenAIImageGenerationHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional[Any] = None, user_api_key_dict: Optional[Any] = None, + request_data: Optional[dict] = None, ) -> Any: """ Process output response - typically not needed for image generation. diff --git a/litellm/llms/openai/responses/guardrail_translation/handler.py b/litellm/llms/openai/responses/guardrail_translation/handler.py index 466e2e76f18..ede5377c3fd 100644 --- a/litellm/llms/openai/responses/guardrail_translation/handler.py +++ b/litellm/llms/openai/responses/guardrail_translation/handler.py @@ -347,6 +347,7 @@ class OpenAIResponsesHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional[Any] = None, user_api_key_dict: Optional[Any] = None, + request_data: Optional[dict] = None, ) -> Any: """ Process output response by applying guardrails to text content and tool calls. @@ -402,15 +403,21 @@ class OpenAIResponsesHandler(BaseTranslation): # Step 2: Apply guardrail to all texts in batch if texts_to_check or tool_calls_to_check: - # Create a request_data dict with response info and user API key metadata - request_data: dict = {"response": response} + # Use the real request_data if provided (proxy path), otherwise + # create a standalone dict (SDK / direct-call path). + if request_data is None: + request_data = {"response": response} + else: + if "response" not in request_data: + request_data["response"] = response # Add user API key metadata with prefixed keys - user_metadata = self.transform_user_api_key_dict_to_metadata( - user_api_key_dict - ) - if user_metadata: - request_data["litellm_metadata"] = user_metadata + if "litellm_metadata" not in request_data: + user_metadata = self.transform_user_api_key_dict_to_metadata( + user_api_key_dict + ) + if user_metadata: + request_data["litellm_metadata"] = user_metadata inputs = GenericGuardrailAPIInputs(texts=texts_to_check) if images_to_check: @@ -454,6 +461,7 @@ class OpenAIResponsesHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional[Any] = None, user_api_key_dict: Optional[Any] = None, + request_data: Optional[dict] = None, ) -> List[Any]: """ Process output streaming response by applying guardrails to text content. @@ -481,7 +489,7 @@ class OpenAIResponsesHandler(BaseTranslation): inputs["model"] = model_response_stream.model _guardrailed_inputs = await guardrail_to_apply.apply_guardrail( inputs=inputs, - request_data={}, + request_data=request_data if request_data is not None else {}, input_type="response", logging_obj=litellm_logging_obj, ) @@ -512,7 +520,7 @@ class OpenAIResponsesHandler(BaseTranslation): if tool_calls or text: _guardrailed_inputs = await guardrail_to_apply.apply_guardrail( inputs=guardrail_inputs, - request_data={}, + request_data=request_data if request_data is not None else {}, input_type="response", logging_obj=litellm_logging_obj, ) diff --git a/litellm/llms/openai/speech/guardrail_translation/handler.py b/litellm/llms/openai/speech/guardrail_translation/handler.py index e6796fbac2a..f0c3149d0ae 100644 --- a/litellm/llms/openai/speech/guardrail_translation/handler.py +++ b/litellm/llms/openai/speech/guardrail_translation/handler.py @@ -85,6 +85,7 @@ class OpenAITextToSpeechHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional[Any] = None, user_api_key_dict: Optional[Any] = None, + request_data: Optional[dict] = None, ) -> Any: """ Process output - not applicable for text-to-speech. diff --git a/litellm/llms/openai/transcriptions/guardrail_translation/handler.py b/litellm/llms/openai/transcriptions/guardrail_translation/handler.py index 3d76a21c389..92cf4398f05 100644 --- a/litellm/llms/openai/transcriptions/guardrail_translation/handler.py +++ b/litellm/llms/openai/transcriptions/guardrail_translation/handler.py @@ -58,6 +58,7 @@ class OpenAIAudioTranscriptionHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional[Any] = None, user_api_key_dict: Optional[Any] = None, + request_data: Optional[dict] = None, ) -> Any: """ Process output transcription by applying guardrails to transcribed text. @@ -79,15 +80,21 @@ class OpenAIAudioTranscriptionHandler(BaseTranslation): if isinstance(response.text, str): original_text = response.text - # Create a request_data dict with response info and user API key metadata - request_data: dict = {"response": response} + # Use the real request_data if provided (proxy path), otherwise + # create a standalone dict (SDK / direct-call path). + if request_data is None: + request_data = {"response": response} + else: + if "response" not in request_data: + request_data["response"] = response # Add user API key metadata with prefixed keys - user_metadata = self.transform_user_api_key_dict_to_metadata( - user_api_key_dict - ) - if user_metadata: - request_data["litellm_metadata"] = user_metadata + if "litellm_metadata" not in request_data: + user_metadata = self.transform_user_api_key_dict_to_metadata( + user_api_key_dict + ) + if user_metadata: + request_data["litellm_metadata"] = user_metadata inputs = GenericGuardrailAPIInputs(texts=[original_text]) # Include model information from the response if available diff --git a/litellm/llms/pass_through/guardrail_translation/handler.py b/litellm/llms/pass_through/guardrail_translation/handler.py index 40433d53413..a8cc42d7c54 100644 --- a/litellm/llms/pass_through/guardrail_translation/handler.py +++ b/litellm/llms/pass_through/guardrail_translation/handler.py @@ -139,6 +139,7 @@ class PassThroughEndpointHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional["LiteLLMLoggingObj"] = None, user_api_key_dict: Optional[Any] = None, + request_data: Optional[dict] = None, ) -> Any: """ Process output response by applying guardrails to targeted fields. @@ -171,17 +172,27 @@ class PassThroughEndpointHandler(BaseTranslation): if not text_to_check: return response - # Create a request_data dict with response info and user API key metadata - request_data: dict = ( - {"response": response} - if not isinstance(response, dict) - else response.copy() - ) + # Use the real request_data if provided (proxy path), otherwise + # create a standalone dict (SDK / direct-call path). + if request_data is None: + request_data = ( + {"response": response} + if not isinstance(response, dict) + else response.copy() + ) + else: + if "response" not in request_data: + request_data["response"] = ( + response if not isinstance(response, dict) else response.copy() + ) # Add user API key metadata with prefixed keys - user_metadata = self.transform_user_api_key_dict_to_metadata(user_api_key_dict) - if user_metadata: - request_data["litellm_metadata"] = user_metadata + if "litellm_metadata" not in request_data: + user_metadata = self.transform_user_api_key_dict_to_metadata( + user_api_key_dict + ) + if user_metadata: + request_data["litellm_metadata"] = user_metadata # Apply guardrail (pass-through doesn't modify the text, just checks it) inputs = GenericGuardrailAPIInputs(texts=[text_to_check]) diff --git a/litellm/proxy/_experimental/mcp_server/guardrail_translation/handler.py b/litellm/proxy/_experimental/mcp_server/guardrail_translation/handler.py index 14bbb82808d..6997f5241de 100644 --- a/litellm/proxy/_experimental/mcp_server/guardrail_translation/handler.py +++ b/litellm/proxy/_experimental/mcp_server/guardrail_translation/handler.py @@ -92,6 +92,7 @@ class MCPGuardrailTranslationHandler(BaseTranslation): guardrail_to_apply: "CustomGuardrail", litellm_logging_obj: Optional[Any] = None, user_api_key_dict: Optional[Any] = None, + request_data: Optional[dict] = None, ) -> Any: verbose_proxy_logger.debug( "MCP Guardrail: Output processing not implemented for MCP tools", diff --git a/litellm/proxy/guardrails/guardrail_hooks/openai/moderations.py b/litellm/proxy/guardrails/guardrail_hooks/openai/moderations.py index 4bd94345727..6da8f9acbf4 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/openai/moderations.py +++ b/litellm/proxy/guardrails/guardrail_hooks/openai/moderations.py @@ -5,9 +5,11 @@ OpenAI Moderation Guardrail Integration for LiteLLM from typing import ( TYPE_CHECKING, + Dict, Literal, Optional, Type, + Union, ) from fastapi import HTTPException @@ -22,7 +24,8 @@ from litellm.llms.custom_httpx.http_handler import ( get_async_httpx_client, httpxSpecialProvider, ) -from litellm.types.utils import GenericGuardrailAPIInputs +from litellm.types.guardrails import GuardrailEventHooks +from litellm.types.utils import GenericGuardrailAPIInputs, GuardrailStatus from .base import OpenAIGuardrailBase @@ -223,12 +226,94 @@ class OpenAIModerationGuardrail(OpenAIGuardrailBase, CustomGuardrail): # Make moderation request moderation_response = await self.async_make_request(input_text=text_to_moderate) + # Stash full moderation response in request_data for logging + # (Model Armor pattern β€” per-request dict avoids race conditions) + if isinstance(request_data, dict): + metadata = request_data.get("metadata") or {} + request_data["metadata"] = metadata + metadata["_openai_moderation_response"] = moderation_response.model_dump() + # Check if content is flagged and raise exception if needed self._check_moderation_result(moderation_response) # Moderation doesn't modify content, just blocks - return inputs unchanged return inputs + def _process_response( + self, + response: Optional[Dict], + request_data: dict, + start_time: Optional[float] = None, + end_time: Optional[float] = None, + duration: Optional[float] = None, + event_type: Optional[GuardrailEventHooks] = None, + original_inputs: Optional[Dict] = None, + ): + """ + Override to log the full OpenAI Moderation API response instead of + the decorator's simplified "allow"/"mask" string. + + Follows the Model Armor pattern (model_armor.py:325-360). + """ + metadata = ( + (request_data.get("metadata") or {}) if isinstance(request_data, dict) else {} + ) + + # .pop() cleans up the internal key so it doesn't leak to downstream + # loggers. Falls back to "allow" when no moderation call was made + # (e.g. no text to moderate β€” early return in apply_guardrail). + guardrail_response = metadata.pop("_openai_moderation_response", "allow") + + self.add_standard_logging_guardrail_information_to_request_data( + guardrail_json_response=guardrail_response, + request_data=request_data, + guardrail_status="success", + duration=duration, + start_time=start_time, + end_time=end_time, + event_type=event_type, + ) + return response + + def _process_error( + self, + e: Exception, + request_data: dict, + start_time: Optional[float] = None, + end_time: Optional[float] = None, + duration: Optional[float] = None, + event_type: Optional[GuardrailEventHooks] = None, + ): + """ + Override to log the full OpenAI Moderation API response on error + instead of the stringified exception. + """ + guardrail_status: GuardrailStatus = ( + "guardrail_intervened" + if self._is_guardrail_intervention(e) + else "guardrail_failed_to_respond" + ) + + metadata = ( + (request_data.get("metadata") or {}) if isinstance(request_data, dict) else {} + ) + + # Use the stashed moderation response if available, fall back to exception + guardrail_response: Union[dict, Exception, str] = metadata.pop( + "_openai_moderation_response", e + ) + + self.add_standard_logging_guardrail_information_to_request_data( + guardrail_json_response=guardrail_response, + request_data=request_data, + guardrail_status=guardrail_status, + duration=duration, + start_time=start_time, + end_time=end_time, + event_type=event_type, + ) + raise e + @staticmethod def get_config_model() -> Optional[Type["GuardrailConfigModel"]]: """ diff --git a/litellm/proxy/guardrails/guardrail_hooks/unified_guardrail/unified_guardrail.py b/litellm/proxy/guardrails/guardrail_hooks/unified_guardrail/unified_guardrail.py index 84bbf6d20e1..80b6f987f66 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/unified_guardrail/unified_guardrail.py +++ b/litellm/proxy/guardrails/guardrail_hooks/unified_guardrail/unified_guardrail.py @@ -247,6 +247,7 @@ class UnifiedLLMGuardrails(CustomLogger): guardrail_to_apply=guardrail_to_apply, litellm_logging_obj=data.get("litellm_logging_obj"), user_api_key_dict=user_api_key_dict, + request_data=data, ) # Add guardrail to applied guardrails header add_guardrail_to_applied_guardrails_header( @@ -397,6 +398,7 @@ class UnifiedLLMGuardrails(CustomLogger): guardrail_to_apply=guardrail_to_apply, litellm_logging_obj=request_data.get("litellm_logging_obj"), user_api_key_dict=user_api_key_dict, + request_data=request_data, ) except HTTPException as e: # Response already started (we already yielded chunks); cannot send 400. diff --git a/tests/test_litellm/proxy/guardrails/guardrail_hooks/openai/test_moderations.py b/tests/test_litellm/proxy/guardrails/guardrail_hooks/openai/test_moderations.py index 3a17bbd0025..bb6d7865d48 100644 --- a/tests/test_litellm/proxy/guardrails/guardrail_hooks/openai/test_moderations.py +++ b/tests/test_litellm/proxy/guardrails/guardrail_hooks/openai/test_moderations.py @@ -488,3 +488,245 @@ async def test_openai_moderation_guardrail_streaming_harmful_content(): assert exc_info.value.status_code == 400 assert "Violated OpenAI moderation policy" in str(exc_info.value.detail) + + +@pytest.mark.asyncio +async def test_openai_moderation_guardrail_logs_full_response_safe_content(): + """Test that safe content logs the full moderation response (categories, scores) + in StandardLoggingGuardrailInformation, not just 'allow'.""" + from litellm.types.utils import GenericGuardrailAPIInputs + + with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}): + guardrail = OpenAIModerationGuardrail( + guardrail_name="test-openai-moderation", + ) + + mock_response = OpenAIModerationResponse( + id="modr-123", + model="omni-moderation-latest", + results=[ + OpenAIModerationResult( + flagged=False, + categories={ + "sexual": False, + "hate": False, + "harassment": False, + "self-harm": False, + "violence": False, + }, + category_scores={ + "sexual": 0.001, + "hate": 0.002, + "harassment": 0.001, + "self-harm": 0.001, + "violence": 0.003, + }, + category_applied_input_types={ + "sexual": [], + "hate": [], + "harassment": [], + "self-harm": [], + "violence": [], + }, + ) + ], + ) + + with patch.object(guardrail, "async_make_request", return_value=mock_response): + inputs = GenericGuardrailAPIInputs( + structured_messages=[ + {"role": "user", "content": "Hello, how are you?"} + ] + ) + request_data = {"metadata": {}} + + await guardrail.apply_guardrail( + inputs=inputs, + request_data=request_data, + input_type="request", + ) + + guardrail_info_list = request_data["metadata"][ + "standard_logging_guardrail_information" + ] + assert len(guardrail_info_list) == 1 + + info = guardrail_info_list[0] + assert info["guardrail_name"] == "test-openai-moderation" + assert info["guardrail_status"] == "success" + + # Full moderation response, NOT "allow" + guardrail_resp = info["guardrail_response"] + assert isinstance(guardrail_resp, dict) + assert guardrail_resp["results"][0]["flagged"] is False + assert "category_scores" in guardrail_resp["results"][0] + + # Internal key cleaned up (.pop()) + assert "_openai_moderation_response" not in request_data["metadata"] + + +@pytest.mark.asyncio +async def test_openai_moderation_guardrail_logs_full_response_harmful_content(): + """Test that harmful content logs guardrail_intervened status with the full + moderation response, not just the exception string.""" + from litellm.types.utils import GenericGuardrailAPIInputs + + with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}): + guardrail = OpenAIModerationGuardrail( + guardrail_name="test-openai-moderation", + ) + + mock_response = OpenAIModerationResponse( + id="modr-456", + model="omni-moderation-latest", + results=[ + OpenAIModerationResult( + flagged=True, + categories={ + "sexual": False, + "hate": True, + "harassment": False, + "self-harm": False, + "violence": False, + }, + category_scores={ + "sexual": 0.001, + "hate": 0.95, + "harassment": 0.001, + "self-harm": 0.001, + "violence": 0.001, + }, + category_applied_input_types={ + "sexual": [], + "hate": ["text"], + "harassment": [], + "self-harm": [], + "violence": [], + }, + ) + ], + ) + + with patch.object(guardrail, "async_make_request", return_value=mock_response): + inputs = GenericGuardrailAPIInputs( + structured_messages=[ + {"role": "user", "content": "Hateful content"} + ] + ) + request_data = {"metadata": {}} + + from fastapi import HTTPException + + with pytest.raises(HTTPException): + await guardrail.apply_guardrail( + inputs=inputs, + request_data=request_data, + input_type="request", + ) + + guardrail_info_list = request_data["metadata"][ + "standard_logging_guardrail_information" + ] + info = guardrail_info_list[0] + assert info["guardrail_status"] == "guardrail_intervened" + + # Full moderation response, NOT stringified exception + guardrail_resp = info["guardrail_response"] + assert isinstance(guardrail_resp, dict) + assert guardrail_resp["results"][0]["flagged"] is True + assert guardrail_resp["results"][0]["category_scores"]["hate"] == 0.95 + + # Internal key cleaned up by _process_error (.pop()) + assert "_openai_moderation_response" not in request_data["metadata"] + + +@pytest.mark.asyncio +async def test_openai_moderation_post_call_request_data_passthrough(): + """Test that post-call guardrail info flows through to the real request_data + via the unified guardrail dispatcher (Bug 1 fix).""" + from unittest.mock import AsyncMock + + from litellm.proxy.guardrails.guardrail_hooks.unified_guardrail.unified_guardrail import ( + UnifiedLLMGuardrails, + ) + from litellm.types.utils import ModelResponse + + import litellm + + with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}): + guardrail = OpenAIModerationGuardrail( + guardrail_name="test-openai-moderation", + event_hook="post_call", + ) + unified_guardrail = UnifiedLLMGuardrails() + + mock_mod_response = OpenAIModerationResponse( + id="modr-789", + model="omni-moderation-latest", + results=[ + OpenAIModerationResult( + flagged=False, + categories={ + "sexual": False, + "hate": False, + "harassment": False, + "self-harm": False, + "violence": False, + }, + category_scores={ + "sexual": 0.001, + "hate": 0.002, + "harassment": 0.001, + "self-harm": 0.001, + "violence": 0.001, + }, + category_applied_input_types={ + "sexual": [], + "hate": [], + "harassment": [], + "self-harm": [], + "violence": [], + }, + ) + ], + ) + + llm_response = ModelResponse( + id="chatcmpl-test", + model="gpt-4", + choices=[ + litellm.Choices( + index=0, + message=litellm.Message( + role="assistant", content="Hello world" + ), + finish_reason="stop", + ) + ], + ) + + request_data = { + "messages": [{"role": "user", "content": "Hello"}], + "guardrail_to_apply": guardrail, + "metadata": {"guardrails": ["test-openai-moderation"]}, + } + + mock_make_request = AsyncMock(return_value=mock_mod_response) + with patch.object(guardrail, "async_make_request", mock_make_request): + await unified_guardrail.async_post_call_success_hook( + data=request_data, + user_api_key_dict=UserAPIKeyAuth( + api_key="test", request_route="/chat/completions" + ), + response=llm_response, + ) + + mock_make_request.assert_called_once() + + # Guardrail info in the REAL request_data (not a throwaway) + guardrail_info_list = request_data["metadata"].get( + "standard_logging_guardrail_information" + ) + assert guardrail_info_list is not None + assert isinstance(guardrail_info_list[0]["guardrail_response"], dict) + assert "results" in guardrail_info_list[0]["guardrail_response"] From d8fd9a20ed40a5ff4505778be4137d3076fd05e9 Mon Sep 17 00:00:00 2001 From: michelligabriele Date: Wed, 18 Mar 2026 00:42:01 +0100 Subject: [PATCH 04/37] =?UTF-8?q?fix(proxy):=20address=20Greptile=20review?= =?UTF-8?q?=20=E2=80=94=20streaming=20request=5Fdata,=20OCR=20backward=20c?= =?UTF-8?q?ompat,=20test=20coverage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Pass request_data to end-of-stream process_output_streaming_response call - Restore inputs.update() in OCR handler for third-party guardrail providers - Add streaming end-to-end test for guardrail logging passthrough --- .../ocr/guardrail_translation/handler.py | 9 +- .../unified_guardrail/unified_guardrail.py | 1 + .../test_openai_moderation_streaming.py | 103 ++++++++++++++++++ 3 files changed, 111 insertions(+), 2 deletions(-) diff --git a/litellm/llms/mistral/ocr/guardrail_translation/handler.py b/litellm/llms/mistral/ocr/guardrail_translation/handler.py index 795ce1d7cae..7d3797a1dbe 100644 --- a/litellm/llms/mistral/ocr/guardrail_translation/handler.py +++ b/litellm/llms/mistral/ocr/guardrail_translation/handler.py @@ -134,12 +134,17 @@ class OCRHandler(BaseTranslation): request_data = {} # Add user metadata if available - if "litellm_metadata" not in request_data and user_api_key_dict is not None: + if user_api_key_dict is not None: user_metadata = self.transform_user_api_key_dict_to_metadata( user_api_key_dict ) if user_metadata: - request_data["litellm_metadata"] = user_metadata + # Preserve original behavior: inject metadata into inputs for + # third-party guardrail providers that read it from there + inputs.update(user_metadata) # type: ignore + # Also store in request_data for the logging pipeline + if "litellm_metadata" not in request_data: + request_data["litellm_metadata"] = user_metadata guardrailed_inputs = await guardrail_to_apply.apply_guardrail( inputs=inputs, diff --git a/litellm/proxy/guardrails/guardrail_hooks/unified_guardrail/unified_guardrail.py b/litellm/proxy/guardrails/guardrail_hooks/unified_guardrail/unified_guardrail.py index 80b6f987f66..a1623121da5 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/unified_guardrail/unified_guardrail.py +++ b/litellm/proxy/guardrails/guardrail_hooks/unified_guardrail/unified_guardrail.py @@ -459,6 +459,7 @@ class UnifiedLLMGuardrails(CustomLogger): guardrail_to_apply=guardrail_to_apply, litellm_logging_obj=request_data.get("litellm_logging_obj"), user_api_key_dict=user_api_key_dict, + request_data=request_data, ) except HTTPException as e: if call_type is not None and CallTypes(call_type) in A2A_CALL_TYPES: diff --git a/tests/test_litellm/proxy/guardrails/guardrail_hooks/openai/test_openai_moderation_streaming.py b/tests/test_litellm/proxy/guardrails/guardrail_hooks/openai/test_openai_moderation_streaming.py index c77a5d07b3b..2595a1df7f1 100644 --- a/tests/test_litellm/proxy/guardrails/guardrail_hooks/openai/test_openai_moderation_streaming.py +++ b/tests/test_litellm/proxy/guardrails/guardrail_hooks/openai/test_openai_moderation_streaming.py @@ -170,3 +170,106 @@ async def test_openai_moderation_guardrail_streaming_harmful_content(): assert exc_info.value.status_code == 400 assert "Violated OpenAI moderation policy" in str(exc_info.value.detail) + + +@pytest.mark.asyncio +async def test_openai_moderation_streaming_end_of_stream_request_data_passthrough(): + """Test that streaming end-of-stream guardrail info flows through to the + real request_data (Bug 1 fix for streaming path).""" + from litellm.types.llms.openai import ( + OpenAIModerationResponse, + OpenAIModerationResult, + ) + + with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}): + openai_guardrail = OpenAIModerationGuardrail( + guardrail_name="test-openai-moderation", + event_hook="post_call", + ) + unified_guardrail = UnifiedLLMGuardrails() + + mock_mod_response = OpenAIModerationResponse( + id="modr-stream-test", + model="omni-moderation-latest", + results=[ + OpenAIModerationResult( + flagged=False, + categories={"hate": False, "violence": False}, + category_scores={"hate": 0.001, "violence": 0.002}, + category_applied_input_types={"hate": [], "violence": []}, + ) + ], + ) + + async def mock_stream(): + import litellm + + chunks_data = ["Hello", " world"] + for i, content in enumerate(chunks_data): + chunk = MagicMock(spec=ModelResponseStream) + chunk.model = "gpt-4" + choice = MagicMock() + choice.delta = MagicMock() + choice.delta.content = content + choice.finish_reason = "stop" if i == len(chunks_data) - 1 else None + chunk.choices = [choice] + yield chunk + + import litellm + + mock_model_response = ModelResponse( + id="mock-stream-response", + model="gpt-4", + choices=[ + litellm.Choices( + index=0, + message=litellm.Message( + role="assistant", content="Hello world" + ), + finish_reason="stop", + ) + ], + ) + + request_data = { + "messages": [{"role": "user", "content": "hi"}], + "guardrail_to_apply": openai_guardrail, + "metadata": { + "guardrails": ["test-openai-moderation"], + "guardrail_config": {"streaming_sampling_rate": 1}, + }, + } + + with patch.object( + openai_guardrail, "async_make_request", return_value=mock_mod_response + ), patch( + "litellm.llms.openai.chat.guardrail_translation.handler.stream_chunk_builder", + return_value=mock_model_response, + ): + user_api_key_dict = UserAPIKeyAuth( + api_key="test", request_route="/chat/completions" + ) + + async for _ in unified_guardrail.async_post_call_streaming_iterator_hook( + user_api_key_dict=user_api_key_dict, + response=mock_stream(), + request_data=request_data, + ): + pass + + # Verify guardrail info reached the REAL request_data (not a throwaway) + guardrail_info_list = request_data["metadata"].get( + "standard_logging_guardrail_information" + ) + assert guardrail_info_list is not None, ( + "Guardrail info should be in request_data after streaming" + ) + info = guardrail_info_list[0] + assert info["guardrail_status"] == "success" + + # Full moderation response dict, NOT the simplified "allow" string + guardrail_resp = info["guardrail_response"] + assert isinstance(guardrail_resp, dict), ( + f"Expected full moderation response dict, got {type(guardrail_resp)}: {guardrail_resp}" + ) + assert "results" in guardrail_resp From 4625ccbaa2531778599524cbd4da49d6a37fe0ec Mon Sep 17 00:00:00 2001 From: michelligabriele Date: Wed, 18 Mar 2026 01:08:01 +0100 Subject: [PATCH 05/37] fix(proxy): anchor metadata dict in _process_response/_process_error so pop() mutates the real dict --- .../guardrail_hooks/openai/moderations.py | 16 ++-- .../openai/test_moderations.py | 85 +++++++++++++++++++ 2 files changed, 95 insertions(+), 6 deletions(-) diff --git a/litellm/proxy/guardrails/guardrail_hooks/openai/moderations.py b/litellm/proxy/guardrails/guardrail_hooks/openai/moderations.py index 6da8f9acbf4..4ddeac9a208 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/openai/moderations.py +++ b/litellm/proxy/guardrails/guardrail_hooks/openai/moderations.py @@ -255,9 +255,11 @@ class OpenAIModerationGuardrail(OpenAIGuardrailBase, CustomGuardrail): Follows the Model Armor pattern (model_armor.py:325-360). """ - metadata = ( - (request_data.get("metadata") or {}) if isinstance(request_data, dict) else {} - ) + if isinstance(request_data, dict): + metadata = request_data.get("metadata") or {} + request_data["metadata"] = metadata # anchor so pop() mutates the real dict + else: + metadata = {} # .pop() cleans up the internal key so it doesn't leak to downstream # loggers. Falls back to "allow" when no moderation call was made @@ -294,9 +296,11 @@ class OpenAIModerationGuardrail(OpenAIGuardrailBase, CustomGuardrail): else "guardrail_failed_to_respond" ) - metadata = ( - (request_data.get("metadata") or {}) if isinstance(request_data, dict) else {} - ) + if isinstance(request_data, dict): + metadata = request_data.get("metadata") or {} + request_data["metadata"] = metadata # anchor so pop() mutates the real dict + else: + metadata = {} # Use the stashed moderation response if available, fall back to exception guardrail_response: Union[dict, Exception, str] = metadata.pop( diff --git a/tests/test_litellm/proxy/guardrails/guardrail_hooks/openai/test_moderations.py b/tests/test_litellm/proxy/guardrails/guardrail_hooks/openai/test_moderations.py index bb6d7865d48..5c19e7189e0 100644 --- a/tests/test_litellm/proxy/guardrails/guardrail_hooks/openai/test_moderations.py +++ b/tests/test_litellm/proxy/guardrails/guardrail_hooks/openai/test_moderations.py @@ -730,3 +730,88 @@ async def test_openai_moderation_post_call_request_data_passthrough(): assert guardrail_info_list is not None assert isinstance(guardrail_info_list[0]["guardrail_response"], dict) assert "results" in guardrail_info_list[0]["guardrail_response"] + + +def test_openai_moderation_process_response_metadata_none_edge_case(): + """ + Test that _process_response anchors the metadata dict back into + request_data when metadata is None, so pop() doesn't operate on a + temporary and the moderation response is correctly logged. + """ + with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}): + guardrail = OpenAIModerationGuardrail( + guardrail_name="test-openai-moderation", + event_hook="post_call", + ) + + mod_dict = {"id": "modr-test", "model": "omni-moderation-latest", "results": []} + + # Simulate apply_guardrail having stashed the response but metadata + # was None initially β€” apply_guardrail anchors it, so metadata is a + # real dict with the stashed key by the time _process_response runs. + request_data = {"metadata": {"_openai_moderation_response": mod_dict}} + + guardrail._process_response( + response={"inputs": {}}, + request_data=request_data, + ) + + # Full moderation dict should be logged, not "allow" + info_list = request_data["metadata"].get( + "standard_logging_guardrail_information" + ) + assert info_list is not None + assert info_list[0]["guardrail_response"] == mod_dict + + # Internal key should have been cleaned up by pop() + assert "_openai_moderation_response" not in request_data["metadata"] + + +def test_openai_moderation_process_error_metadata_none_edge_case(): + """ + Test that _process_error anchors the metadata dict back into + request_data when metadata starts as None (or {}), so pop() doesn't + operate on a temporary. + """ + from fastapi import HTTPException + + with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}): + guardrail = OpenAIModerationGuardrail( + guardrail_name="test-openai-moderation", + event_hook="post_call", + ) + + mod_dict = { + "id": "modr-test", + "model": "omni-moderation-latest", + "results": [{"flagged": True, "categories": {"hate": True}}], + } + + # metadata is None β€” exercises the or {} anchor + request_data: dict = {"metadata": None} + + # Simulate stashing the response then calling _process_error + # (normally apply_guardrail stashes, then the decorator calls + # _process_error on HTTPException) + # First anchor metadata like apply_guardrail does: + metadata = request_data.get("metadata") or {} + request_data["metadata"] = metadata + metadata["_openai_moderation_response"] = mod_dict + + exc = HTTPException(status_code=400, detail="Violated policy") + with pytest.raises(HTTPException): + guardrail._process_error( + e=exc, + request_data=request_data, + ) + + # Full moderation dict should be logged, not the exception + info_list = request_data["metadata"].get( + "standard_logging_guardrail_information" + ) + assert info_list is not None + assert info_list[0]["guardrail_response"] == mod_dict + assert info_list[0]["guardrail_status"] == "guardrail_intervened" + + # Internal key cleaned up + assert "_openai_moderation_response" not in request_data["metadata"] From 9a231bd75820c90c15b7c6fffd1b7744c3e244ce Mon Sep 17 00:00:00 2001 From: michelligabriele Date: Wed, 18 Mar 2026 01:18:21 +0100 Subject: [PATCH 06/37] fix(proxy): use real request_data in Responses API streaming fallback path --- litellm/llms/openai/responses/guardrail_translation/handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litellm/llms/openai/responses/guardrail_translation/handler.py b/litellm/llms/openai/responses/guardrail_translation/handler.py index ede5377c3fd..76f40eed71f 100644 --- a/litellm/llms/openai/responses/guardrail_translation/handler.py +++ b/litellm/llms/openai/responses/guardrail_translation/handler.py @@ -545,7 +545,7 @@ class OpenAIResponsesHandler(BaseTranslation): inputs["model"] = response_model _guardrailed_inputs = await guardrail_to_apply.apply_guardrail( inputs=inputs, - request_data={}, + request_data=request_data if request_data is not None else {}, input_type="response", logging_obj=litellm_logging_obj, ) From fa7ccf0893f647645fb48a6db912898daf4c0655 Mon Sep 17 00:00:00 2001 From: michelligabriele Date: Mon, 23 Mar 2026 15:43:05 +0100 Subject: [PATCH 07/37] fix(test): add request_data param to test mock + black formatting --- litellm/litellm_core_utils/litellm_logging.py | 284 +++++++++--------- .../chat/guardrail_translation/handler.py | 6 +- litellm/proxy/utils.py | 32 +- .../test_unified_guardrail.py | 41 ++- 4 files changed, 182 insertions(+), 181 deletions(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index 5323f692b80..a5262505983 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -354,9 +354,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 @@ -801,9 +801,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 @@ -871,9 +871,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 ######################################################### @@ -885,9 +885,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 @@ -947,9 +947,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 @@ -978,9 +978,7 @@ 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( @@ -992,35 +990,31 @@ 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), - ) - _metadata[ - "raw_request" - ] = "Unable to Log \ - raw request: {}".format( - str(e) + self.model_call_details["raw_request_typed_dict"] = ( + RawRequestTypedDict( + error=str(e), + ) ) + _metadata["raw_request"] = "Unable to Log \ + raw request: {}".format(str(e)) if getattr(self, "logger_fn", None) and callable(self.logger_fn): try: self.logger_fn( @@ -1320,13 +1314,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 @@ -1527,9 +1521,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: @@ -1555,9 +1549,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 @@ -1706,9 +1700,9 @@ class Logging(LiteLLMLoggingBaseClass): self.model_call_details["litellm_params"].setdefault("metadata", {}) if self.model_call_details["litellm_params"]["metadata"] is None: self.model_call_details["litellm_params"]["metadata"] = {} - self.model_call_details["litellm_params"]["metadata"][ - "hidden_params" - ] = getattr(logging_result, "_hidden_params", {}) + self.model_call_details["litellm_params"]["metadata"]["hidden_params"] = ( + getattr(logging_result, "_hidden_params", {}) + ) def _process_hidden_params_and_response_cost( self, @@ -1737,9 +1731,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( @@ -1817,9 +1811,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 @@ -1856,10 +1850,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( @@ -1868,9 +1862,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 @@ -2028,20 +2022,20 @@ 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) + ) self._merge_hidden_params_from_response_into_metadata( 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( @@ -2375,10 +2369,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( @@ -2402,10 +2396,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"] @@ -2544,9 +2538,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: @@ -2557,10 +2551,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( @@ -2577,10 +2571,10 @@ class Logging(LiteLLMLoggingBaseClass): ) ## 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 @@ -2607,9 +2601,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 ( @@ -2852,18 +2846,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 @@ -3831,9 +3825,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) @@ -3859,13 +3853,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) @@ -3873,19 +3867,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 ( @@ -4072,9 +4066,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) @@ -4998,10 +4992,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 @@ -5640,9 +5634,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/openai/chat/guardrail_translation/handler.py b/litellm/llms/openai/chat/guardrail_translation/handler.py index f854cdb13d0..0ce9d57a65f 100644 --- a/litellm/llms/openai/chat/guardrail_translation/handler.py +++ b/litellm/llms/openai/chat/guardrail_translation/handler.py @@ -86,9 +86,9 @@ class OpenAIChatCompletionsHandler(BaseTranslation): if tool_calls_to_check: inputs["tool_calls"] = tool_calls_to_check # type: ignore if messages: - inputs[ - "structured_messages" - ] = messages # pass the openai /chat/completions messages to the guardrail, as-is + inputs["structured_messages"] = ( + messages # pass the openai /chat/completions messages to the guardrail, as-is + ) # Pass tools (function definitions) to the guardrail tools = data.get("tools") if tools: diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index 7954f0b6460..b9c1e2f2bc3 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -1898,9 +1898,9 @@ class ProxyLogging: normalized_call_type = CallTypes.aembedding.value if normalized_call_type is not None: litellm_logging_obj.call_type = normalized_call_type - litellm_logging_obj.model_call_details[ - "call_type" - ] = normalized_call_type + litellm_logging_obj.model_call_details["call_type"] = ( + normalized_call_type + ) # 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: @@ -2498,8 +2498,7 @@ class PrismaClient: required_view = "LiteLLM_VerificationTokenView" expected_views_str = ", ".join(f"'{view}'" for view in expected_views) pg_schema = os.getenv("DATABASE_SCHEMA", "public") - ret = await self.db.query_raw( - f""" + ret = await self.db.query_raw(f""" WITH existing_views AS ( SELECT viewname FROM pg_views @@ -2511,8 +2510,7 @@ class PrismaClient: (SELECT COUNT(*) FROM existing_views) AS view_count, ARRAY_AGG(viewname) AS view_names FROM existing_views - """ - ) + """) expected_total_views = len(expected_views) if ret[0]["view_count"] == expected_total_views: verbose_proxy_logger.info("All necessary views exist!") @@ -2521,8 +2519,7 @@ class PrismaClient: ## check if required view exists ## if ret[0]["view_names"] and required_view not in ret[0]["view_names"]: await self.health_check() # make sure we can connect to db - await self.db.execute_raw( - """ + await self.db.execute_raw(""" CREATE VIEW "LiteLLM_VerificationTokenView" AS SELECT v.*, @@ -2532,8 +2529,7 @@ class PrismaClient: t.rpm_limit AS team_rpm_limit FROM "LiteLLM_VerificationToken" v LEFT JOIN "LiteLLM_TeamTable" t ON v.team_id = t.team_id; - """ - ) + """) verbose_proxy_logger.info( "LiteLLM_VerificationTokenView Created in DB!" @@ -2759,7 +2755,7 @@ class PrismaClient: and reset_at is not None ): response = await self.db.litellm_verificationtoken.find_many( - where={ # type:ignore + where={ # type: ignore "OR": [ {"expires": None}, {"expires": {"gt": expires}}, @@ -2819,7 +2815,7 @@ class PrismaClient: ) # type: ignore elif query_type == "find_all" and reset_at is not None: response = await self.db.litellm_usertable.find_many( - where={ # type:ignore + where={ # type: ignore "budget_reset_at": {"lt": reset_at}, } ) @@ -2831,10 +2827,10 @@ class PrismaClient: if expires is not None: response = await self.db.litellm_usertable.find_many( # type: ignore order={"spend": "desc"}, - where={ # type:ignore + where={ # type: ignore "OR": [ - {"expires": None}, # type:ignore - {"expires": {"gt": expires}}, # type:ignore + {"expires": None}, # type: ignore + {"expires": {"gt": expires}}, # type: ignore ], }, ) @@ -2881,7 +2877,7 @@ class PrismaClient: elif table_name == "budget" and reset_at is not None: if query_type == "find_all": response = await self.db.litellm_budgettable.find_many( - where={ # type:ignore + where={ # type: ignore "OR": [ { "AND": [ @@ -2909,7 +2905,7 @@ class PrismaClient: ) elif query_type == "find_all" and reset_at is not None: response = await self.db.litellm_teamtable.find_many( - where={ # type:ignore + where={ # type: ignore "budget_reset_at": {"lt": reset_at}, } ) diff --git a/tests/test_litellm/proxy/guardrails/guardrail_hooks/unified_guardrails/test_unified_guardrail.py b/tests/test_litellm/proxy/guardrails/guardrail_hooks/unified_guardrails/test_unified_guardrail.py index 7c29c8161db..bbba8e4d03d 100644 --- a/tests/test_litellm/proxy/guardrails/guardrail_hooks/unified_guardrails/test_unified_guardrail.py +++ b/tests/test_litellm/proxy/guardrails/guardrail_hooks/unified_guardrails/test_unified_guardrail.py @@ -78,9 +78,7 @@ class TestUnifiedLLMGuardrails: data = { "guardrail_to_apply": guardrail, - "messages": [ - {"role": "user", "content": "Tool: test\nArguments: {}"} - ], + "messages": [{"role": "user", "content": "Tool: test\nArguments: {}"}], "model": "mcp-tool-call", } @@ -102,9 +100,7 @@ class TestUnifiedLLMGuardrails: data = { "guardrail_to_apply": guardrail, - "messages": [ - {"role": "user", "content": "Tool: test\nArguments: {}"} - ], + "messages": [{"role": "user", "content": "Tool: test\nArguments: {}"}], "model": "mcp-tool-call", } @@ -168,6 +164,7 @@ class TestUnifiedLLMGuardrails: guardrail_to_apply, litellm_logging_obj=None, user_api_key_dict=None, + request_data=None, ): # Simulate what the real handler does: # put combined text in first chunk, clear the rest @@ -200,10 +197,12 @@ class TestUnifiedLLMGuardrails: chunks = [] for i in range(10): chunk = ModelResponseStream( - choices=[StreamingChoices( - delta=Delta(content=f"word{i} ", role="assistant"), - finish_reason=None, - )], + choices=[ + StreamingChoices( + delta=Delta(content=f"word{i} ", role="assistant"), + finish_reason=None, + ) + ], ) chunks.append(chunk) @@ -228,7 +227,9 @@ class TestUnifiedLLMGuardrails: response=mock_stream(), request_data=request_data, ): - content = item.choices[0].delta.content if item.choices[0].delta else None + content = ( + item.choices[0].delta.content if item.choices[0].delta else None + ) yielded_contents.append(content) # Every chunk should have non-empty content @@ -271,10 +272,15 @@ class TestUnifiedLLMGuardrails: assert guardrail.event_history == [GuardrailEventHooks.pre_call] assert len(guardrail.apply_calls) == 1 assert guardrail.apply_calls[0]["input_type"] == "request" - assert "https://arxiv.org/pdf/2201.04234" in guardrail.apply_calls[0]["inputs"]["texts"] + assert ( + "https://arxiv.org/pdf/2201.04234" + in guardrail.apply_calls[0]["inputs"]["texts"] + ) # Data should be returned with document intact - assert result["document"]["document_url"] == "https://arxiv.org/pdf/2201.04234" + assert ( + result["document"]["document_url"] == "https://arxiv.org/pdf/2201.04234" + ) @pytest.mark.asyncio async def test_moderation_hook_invokes_ocr_handler(self): @@ -302,7 +308,10 @@ class TestUnifiedLLMGuardrails: assert guardrail.event_history == [GuardrailEventHooks.during_call] assert len(guardrail.apply_calls) == 1 - assert "https://example.com/scan.png" in guardrail.apply_calls[0]["inputs"]["texts"] + assert ( + "https://example.com/scan.png" + in guardrail.apply_calls[0]["inputs"]["texts"] + ) @pytest.mark.asyncio async def test_post_call_success_hook_guardrails_ocr_output(self): @@ -318,7 +327,9 @@ class TestUnifiedLLMGuardrails: def should_run_guardrail(self, data, event_type): # type: ignore[override] return True - async def apply_guardrail(self, inputs, request_data, input_type, **kwargs): + async def apply_guardrail( + self, inputs, request_data, input_type, **kwargs + ): texts = inputs.get("texts", []) return {"texts": [t.replace("SECRET", "[REDACTED]") for t in texts]} From 6809213957c011edf64e3e67a41984d43db4a952 Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Mon, 23 Mar 2026 10:44:17 -0700 Subject: [PATCH 08/37] feat(proxy): add project_alias tracking through callback metadata pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thread project_alias alongside project_id through the metadata pipeline so callbacks receive the human-readable project name. DRY up duplicate metadata dict construction in proxy_track_cost_callback and pass_through_endpoints by reusing get_sanitized_user_information_from_key β€” future metadata fields only need adding in one place. Co-Authored-By: Claude Opus 4.6 --- litellm/litellm_core_utils/litellm_logging.py | 286 +++++++++--------- litellm/proxy/_types.py | 2 + litellm/proxy/auth/user_api_key_auth.py | 3 + litellm/proxy/db/create_views.py | 16 +- .../proxy/hooks/proxy_track_cost_callback.py | 27 +- litellm/proxy/litellm_pre_call_utils.py | 1 + .../pass_through_endpoints.py | 23 +- litellm/proxy/utils.py | 20 +- litellm/types/utils.py | 1 + .../test_project_alias_tracking.py | 134 ++++++++ 10 files changed, 317 insertions(+), 196 deletions(-) create mode 100644 tests/test_litellm/test_project_alias_tracking.py diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index a5262505983..53478dcbb65 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -354,9 +354,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 @@ -801,9 +801,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 @@ -871,9 +871,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 ######################################################### @@ -885,9 +885,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 @@ -947,9 +947,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 @@ -978,7 +978,9 @@ 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( @@ -990,31 +992,35 @@ 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 \ + raw request: {}".format( + str(e) ) - _metadata["raw_request"] = "Unable to Log \ - raw request: {}".format(str(e)) if getattr(self, "logger_fn", None) and callable(self.logger_fn): try: self.logger_fn( @@ -1314,13 +1320,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 @@ -1521,9 +1527,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: @@ -1549,9 +1555,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 @@ -1700,9 +1706,9 @@ class Logging(LiteLLMLoggingBaseClass): self.model_call_details["litellm_params"].setdefault("metadata", {}) if self.model_call_details["litellm_params"]["metadata"] is None: self.model_call_details["litellm_params"]["metadata"] = {} - self.model_call_details["litellm_params"]["metadata"]["hidden_params"] = ( - getattr(logging_result, "_hidden_params", {}) - ) + self.model_call_details["litellm_params"]["metadata"][ + "hidden_params" + ] = getattr(logging_result, "_hidden_params", {}) def _process_hidden_params_and_response_cost( self, @@ -1731,9 +1737,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( @@ -1811,9 +1817,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 @@ -1850,10 +1856,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( @@ -1862,9 +1868,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 @@ -2022,20 +2028,20 @@ 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) self._merge_hidden_params_from_response_into_metadata( 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( @@ -2369,10 +2375,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( @@ -2396,10 +2402,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"] @@ -2538,9 +2544,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: @@ -2551,10 +2557,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( @@ -2571,10 +2577,10 @@ class Logging(LiteLLMLoggingBaseClass): ) ## 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 @@ -2601,9 +2607,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 ( @@ -2846,18 +2852,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 @@ -3825,9 +3831,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) @@ -3853,13 +3859,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) @@ -3867,19 +3873,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 ( @@ -4066,9 +4072,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) @@ -4747,6 +4753,7 @@ class StandardLoggingPayloadSetup: user_api_key_team_id=None, user_api_key_org_id=None, user_api_key_project_id=None, + user_api_key_project_alias=None, user_api_key_user_id=None, user_api_key_team_alias=None, user_api_key_user_email=None, @@ -4992,10 +4999,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 @@ -5578,6 +5585,7 @@ def get_standard_logging_metadata( user_api_key_team_id=None, user_api_key_org_id=None, user_api_key_project_id=None, + user_api_key_project_alias=None, user_api_key_user_id=None, user_api_key_user_email=None, user_api_key_team_alias=None, @@ -5634,9 +5642,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/proxy/_types.py b/litellm/proxy/_types.py index 91a953c217e..b59fc85d4b8 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -2416,6 +2416,7 @@ class LiteLLM_VerificationTokenView(LiteLLM_VerificationToken): organization_metadata: Optional[dict] = None # Project Params + project_alias: Optional[str] = None project_metadata: Optional[dict] = None # Time stamps @@ -3228,6 +3229,7 @@ class SpendLogsMetadata(TypedDict): user_api_key_alias: Optional[str] user_api_key_team_id: Optional[str] user_api_key_project_id: Optional[str] + user_api_key_project_alias: Optional[str] user_api_key_org_id: Optional[str] user_api_key_user_id: Optional[str] user_api_key_team_alias: Optional[str] diff --git a/litellm/proxy/auth/user_api_key_auth.py b/litellm/proxy/auth/user_api_key_auth.py index 800cca21dbe..eba787c63b3 100644 --- a/litellm/proxy/auth/user_api_key_auth.py +++ b/litellm/proxy/auth/user_api_key_auth.py @@ -836,6 +836,7 @@ async def _user_api_key_auth_builder( # noqa: PLR0915 ) if _jwt_project_obj is not None: valid_token.project_metadata = _jwt_project_obj.metadata + valid_token.project_alias = _jwt_project_obj.project_alias # run through common checks _ = await common_checks( @@ -1431,6 +1432,7 @@ async def _user_api_key_auth_builder( # noqa: PLR0915 ) if _project_obj is not None: valid_token.project_metadata = _project_obj.metadata + valid_token.project_alias = _project_obj.project_alias global_proxy_spend = None if ( @@ -1888,6 +1890,7 @@ async def _run_post_custom_auth_checks( ) if _project_obj is not None: valid_token.project_metadata = _project_obj.metadata + valid_token.project_alias = _project_obj.project_alias if general_settings.get("custom_auth_run_common_checks", False): _ = await common_checks( diff --git a/litellm/proxy/db/create_views.py b/litellm/proxy/db/create_views.py index e9303077b18..fd0baf67b3b 100644 --- a/litellm/proxy/db/create_views.py +++ b/litellm/proxy/db/create_views.py @@ -27,14 +27,16 @@ async def create_missing_views(db: _db): # noqa: PLR0915 await db.execute_raw( """ CREATE VIEW "LiteLLM_VerificationTokenView" AS - SELECT - v.*, - t.spend AS team_spend, - t.max_budget AS team_max_budget, - t.tpm_limit AS team_tpm_limit, - t.rpm_limit AS team_rpm_limit + SELECT + v.*, + t.spend AS team_spend, + t.max_budget AS team_max_budget, + t.tpm_limit AS team_tpm_limit, + t.rpm_limit AS team_rpm_limit, + p.project_alias AS project_alias FROM "LiteLLM_VerificationToken" v - LEFT JOIN "LiteLLM_TeamTable" t ON v.team_id = t.team_id; + LEFT JOIN "LiteLLM_TeamTable" t ON v.team_id = t.team_id + LEFT JOIN "LiteLLM_ProjectTable" p ON v.project_id = p.project_id; """ ) diff --git a/litellm/proxy/hooks/proxy_track_cost_callback.py b/litellm/proxy/hooks/proxy_track_cost_callback.py index 43cfd930193..220c5066a6d 100644 --- a/litellm/proxy/hooks/proxy_track_cost_callback.py +++ b/litellm/proxy/hooks/proxy_track_cost_callback.py @@ -18,11 +18,9 @@ from litellm.proxy.auth.auth_checks import ( log_db_metrics, ) from litellm.proxy.auth.route_checks import RouteChecks +from litellm.proxy.litellm_pre_call_utils import LiteLLMProxyRequestSetup from litellm.proxy.utils import ProxyUpdateSpend -from litellm.types.utils import ( - StandardLoggingPayload, - StandardLoggingUserAPIKeyMetadata, -) +from litellm.types.utils import StandardLoggingPayload from litellm.utils import get_end_user_id_for_cost_tracking @@ -51,25 +49,8 @@ class _ProxyDBLogger(CustomLogger): from litellm.proxy.proxy_server import proxy_logging_obj _metadata = dict( - StandardLoggingUserAPIKeyMetadata( - user_api_key_hash=user_api_key_dict.api_key, - user_api_key_alias=user_api_key_dict.key_alias, - user_api_key_spend=user_api_key_dict.spend, - user_api_key_max_budget=user_api_key_dict.max_budget, - user_api_key_budget_reset_at=( - user_api_key_dict.budget_reset_at.isoformat() - if user_api_key_dict.budget_reset_at - else None - ), - user_api_key_user_email=user_api_key_dict.user_email, - user_api_key_user_id=user_api_key_dict.user_id, - user_api_key_team_id=user_api_key_dict.team_id, - user_api_key_org_id=user_api_key_dict.org_id, - user_api_key_project_id=user_api_key_dict.project_id, - user_api_key_team_alias=user_api_key_dict.team_alias, - user_api_key_end_user_id=user_api_key_dict.end_user_id, - user_api_key_request_route=user_api_key_dict.request_route, - user_api_key_auth_metadata=user_api_key_dict.metadata, + LiteLLMProxyRequestSetup.get_sanitized_user_information_from_key( + user_api_key_dict=user_api_key_dict ) ) _metadata["user_api_key"] = user_api_key_dict.api_key diff --git a/litellm/proxy/litellm_pre_call_utils.py b/litellm/proxy/litellm_pre_call_utils.py index daf2867699e..4ca0d876a1c 100644 --- a/litellm/proxy/litellm_pre_call_utils.py +++ b/litellm/proxy/litellm_pre_call_utils.py @@ -658,6 +658,7 @@ class LiteLLMProxyRequestSetup: user_api_key_max_budget=user_api_key_dict.max_budget, user_api_key_team_id=user_api_key_dict.team_id, user_api_key_project_id=user_api_key_dict.project_id, + user_api_key_project_alias=user_api_key_dict.project_alias, user_api_key_user_id=user_api_key_dict.user_id, user_api_key_org_id=user_api_key_dict.org_id, user_api_key_team_alias=user_api_key_dict.team_alias, diff --git a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py b/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py index e2f7646c0aa..4f68c92b9d9 100644 --- a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py +++ b/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py @@ -55,6 +55,7 @@ from litellm.proxy.common_utils.http_parsing_utils import ( _read_request_body, _safe_get_request_headers, ) +from litellm.proxy.litellm_pre_call_utils import LiteLLMProxyRequestSetup from litellm.proxy.utils import get_server_root_path, normalize_route_for_root_path from litellm.secret_managers.main import get_secret_str from litellm.types.llms.custom_http import httpxSpecialProvider @@ -62,7 +63,6 @@ from litellm.types.passthrough_endpoints.pass_through_endpoints import ( EndpointType, PassthroughStandardLoggingPayload, ) -from litellm.types.utils import StandardLoggingUserAPIKeyMetadata from .streaming_handler import PassThroughStreamingHandler from .success_handler import PassThroughEndpointLogging @@ -502,25 +502,8 @@ class HttpPassThroughEndpointHelpers(BasePassthroughUtils): litellm_params_in_body[k] = _parsed_body.pop(k, None) _metadata = dict( - StandardLoggingUserAPIKeyMetadata( - user_api_key_hash=user_api_key_dict.api_key, - user_api_key_alias=user_api_key_dict.key_alias, - user_api_key_user_email=user_api_key_dict.user_email, - user_api_key_user_id=user_api_key_dict.user_id, - user_api_key_team_id=user_api_key_dict.team_id, - user_api_key_org_id=user_api_key_dict.org_id, - user_api_key_project_id=user_api_key_dict.project_id, - user_api_key_team_alias=user_api_key_dict.team_alias, - user_api_key_end_user_id=user_api_key_dict.end_user_id, - user_api_key_request_route=user_api_key_dict.request_route, - user_api_key_spend=user_api_key_dict.spend, - user_api_key_max_budget=user_api_key_dict.max_budget, - user_api_key_budget_reset_at=( - user_api_key_dict.budget_reset_at.isoformat() - if user_api_key_dict.budget_reset_at - else None - ), - user_api_key_auth_metadata=user_api_key_dict.metadata, + LiteLLMProxyRequestSetup.get_sanitized_user_information_from_key( + user_api_key_dict=user_api_key_dict ) ) diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index b9c1e2f2bc3..75c803aad65 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -1898,9 +1898,9 @@ class ProxyLogging: normalized_call_type = CallTypes.aembedding.value if normalized_call_type is not None: litellm_logging_obj.call_type = normalized_call_type - litellm_logging_obj.model_call_details["call_type"] = ( - normalized_call_type - ) + litellm_logging_obj.model_call_details[ + "call_type" + ] = normalized_call_type # 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: @@ -2498,7 +2498,8 @@ class PrismaClient: required_view = "LiteLLM_VerificationTokenView" expected_views_str = ", ".join(f"'{view}'" for view in expected_views) pg_schema = os.getenv("DATABASE_SCHEMA", "public") - ret = await self.db.query_raw(f""" + ret = await self.db.query_raw( + f""" WITH existing_views AS ( SELECT viewname FROM pg_views @@ -2510,7 +2511,8 @@ class PrismaClient: (SELECT COUNT(*) FROM existing_views) AS view_count, ARRAY_AGG(viewname) AS view_names FROM existing_views - """) + """ + ) expected_total_views = len(expected_views) if ret[0]["view_count"] == expected_total_views: verbose_proxy_logger.info("All necessary views exist!") @@ -2519,7 +2521,8 @@ class PrismaClient: ## check if required view exists ## if ret[0]["view_names"] and required_view not in ret[0]["view_names"]: await self.health_check() # make sure we can connect to db - await self.db.execute_raw(""" + await self.db.execute_raw( + """ CREATE VIEW "LiteLLM_VerificationTokenView" AS SELECT v.*, @@ -2529,7 +2532,8 @@ class PrismaClient: t.rpm_limit AS team_rpm_limit FROM "LiteLLM_VerificationToken" v LEFT JOIN "LiteLLM_TeamTable" t ON v.team_id = t.team_id; - """) + """ + ) verbose_proxy_logger.info( "LiteLLM_VerificationTokenView Created in DB!" @@ -2964,6 +2968,7 @@ class PrismaClient: t.members_with_roles AS team_members_with_roles, t.object_permission_id AS team_object_permission_id, t.organization_id as org_id, + p.project_alias AS project_alias, tm.spend AS team_member_spend, m.aliases AS team_model_aliases, -- Added comma to separate b.* columns @@ -2981,6 +2986,7 @@ class PrismaClient: LEFT JOIN "LiteLLM_TeamMembership" AS tm ON v.team_id = tm.team_id AND tm.user_id = v.user_id LEFT JOIN "LiteLLM_ModelTable" m ON t.model_id = m.id LEFT JOIN "LiteLLM_BudgetTable" AS b ON v.budget_id = b.budget_id + LEFT JOIN "LiteLLM_ProjectTable" AS p ON v.project_id = p.project_id LEFT JOIN "LiteLLM_OrganizationTable" AS o ON v.organization_id = o.organization_id LEFT JOIN "LiteLLM_BudgetTable" AS b2 ON o.budget_id = b2.budget_id WHERE v.token = '{token}' diff --git a/litellm/types/utils.py b/litellm/types/utils.py index e7f0cd77143..bd673da8bed 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -2488,6 +2488,7 @@ class StandardLoggingUserAPIKeyMetadata(TypedDict): user_api_key_org_id: Optional[str] user_api_key_team_id: Optional[str] user_api_key_project_id: Optional[str] + user_api_key_project_alias: Optional[str] user_api_key_user_id: Optional[str] user_api_key_user_email: Optional[str] user_api_key_team_alias: Optional[str] diff --git a/tests/test_litellm/test_project_alias_tracking.py b/tests/test_litellm/test_project_alias_tracking.py new file mode 100644 index 00000000000..d18989d543f --- /dev/null +++ b/tests/test_litellm/test_project_alias_tracking.py @@ -0,0 +1,134 @@ +""" +Tests for project_alias and project_id tracking through callback kwargs / metadata. + +Verifies that project_alias flows from UserAPIKeyAuth through the metadata pipeline +to StandardLoggingMetadata, mirroring how team_alias already works. +""" + +import os +import sys + +import pytest + +sys.path.insert(0, os.path.abspath("../..")) + +from litellm.litellm_core_utils.litellm_logging import StandardLoggingPayloadSetup +from litellm.proxy._types import LiteLLM_VerificationTokenView, UserAPIKeyAuth +from litellm.proxy.litellm_pre_call_utils import LiteLLMProxyRequestSetup +from litellm.types.utils import StandardLoggingUserAPIKeyMetadata + + +class TestProjectAliasOnTypes: + """project_alias field exists on the relevant types.""" + + def test_verification_token_view_has_project_alias(self): + token_view = LiteLLM_VerificationTokenView( + token="test-token", + project_id="proj-123", + project_alias="My Project", + ) + assert token_view.project_alias == "My Project" + + def test_verification_token_view_project_alias_defaults_none(self): + token_view = LiteLLM_VerificationTokenView(token="test-token") + assert token_view.project_alias is None + + def test_user_api_key_auth_inherits_project_alias(self): + """UserAPIKeyAuth extends LiteLLM_VerificationTokenView, so it gets project_alias.""" + auth = UserAPIKeyAuth( + api_key="sk-test", + project_id="proj-1", + project_alias="billing-service", + ) + assert auth.project_alias == "billing-service" + + def test_standard_logging_metadata_has_project_alias_field(self): + metadata = StandardLoggingUserAPIKeyMetadata( + user_api_key_hash="hash", + user_api_key_alias=None, + user_api_key_spend=None, + user_api_key_max_budget=None, + user_api_key_budget_reset_at=None, + user_api_key_org_id=None, + user_api_key_team_id=None, + user_api_key_project_id="proj-1", + user_api_key_project_alias="billing-service", + user_api_key_user_id=None, + user_api_key_user_email=None, + user_api_key_team_alias=None, + user_api_key_end_user_id=None, + user_api_key_request_route=None, + user_api_key_auth_metadata=None, + ) + assert metadata["user_api_key_project_alias"] == "billing-service" + + +class TestProjectAliasThroughMetadataPipeline: + """project_alias flows through the full metadata pipeline.""" + + def test_get_sanitized_user_information_includes_project_alias(self): + user_api_key_dict = UserAPIKeyAuth( + api_key="sk-hashed", + project_id="proj-123", + project_alias="My Cool Project", + team_id="team-1", + team_alias="my-team", + ) + + result = LiteLLMProxyRequestSetup.get_sanitized_user_information_from_key( + user_api_key_dict=user_api_key_dict + ) + + assert result["user_api_key_project_id"] == "proj-123" + assert result["user_api_key_project_alias"] == "My Cool Project" + + def test_get_sanitized_user_information_project_alias_none_when_no_project(self): + user_api_key_dict = UserAPIKeyAuth(api_key="sk-hashed") + + result = LiteLLMProxyRequestSetup.get_sanitized_user_information_from_key( + user_api_key_dict=user_api_key_dict + ) + + assert result["user_api_key_project_id"] is None + assert result["user_api_key_project_alias"] is None + + def test_project_alias_flows_to_standard_logging_metadata(self): + """get_standard_logging_metadata picks up project_alias from input metadata.""" + metadata = { + "user_api_key_project_id": "proj-123", + "user_api_key_project_alias": "My Cool Project", + "user_api_key_team_id": "team-1", + "user_api_key_team_alias": "my-team", + } + + result = StandardLoggingPayloadSetup.get_standard_logging_metadata(metadata) + assert result["user_api_key_project_alias"] == "My Cool Project" + + def test_project_alias_defaults_to_none_in_logging_metadata(self): + result = StandardLoggingPayloadSetup.get_standard_logging_metadata({}) + assert result["user_api_key_project_alias"] is None + + def test_end_to_end_project_alias_flow(self): + """Full flow: UserAPIKeyAuth -> get_sanitized -> get_standard_logging_metadata.""" + auth = UserAPIKeyAuth( + api_key="sk-test", + project_id="proj-abc", + project_alias="analytics-pipeline", + team_id="team-1", + team_alias="data-team", + ) + + # Step 1: Auth β†’ sanitized metadata + sanitized = LiteLLMProxyRequestSetup.get_sanitized_user_information_from_key( + user_api_key_dict=auth + ) + + # Step 2: Sanitized metadata β†’ standard logging metadata + logging_metadata = StandardLoggingPayloadSetup.get_standard_logging_metadata( + dict(sanitized) + ) + + assert logging_metadata["user_api_key_project_id"] == "proj-abc" + assert logging_metadata["user_api_key_project_alias"] == "analytics-pipeline" + assert logging_metadata["user_api_key_team_id"] == "team-1" + assert logging_metadata["user_api_key_team_alias"] == "data-team" From 7fa623df919a3ef0cce876ec4d5ae24d5a1e3f90 Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Mon, 23 Mar 2026 10:59:18 -0700 Subject: [PATCH 09/37] feat(prometheus): include spend_logs_metadata in custom labels Add spend_logs_metadata to combined_metadata in Prometheus logger so custom metadata from x-litellm-spend-logs-metadata header can be used in Prometheus custom labels. Co-Authored-By: Claude Opus 4.6 --- litellm/integrations/prometheus.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/litellm/integrations/prometheus.py b/litellm/integrations/prometheus.py index 357e0229fc6..90306c11a42 100644 --- a/litellm/integrations/prometheus.py +++ b/litellm/integrations/prometheus.py @@ -931,10 +931,14 @@ class PrometheusLogger(CustomLogger): user_api_key_auth_metadata: Optional[dict] = standard_logging_payload[ "metadata" ].get("user_api_key_auth_metadata") + spend_logs_metadata: Optional[dict] = standard_logging_payload["metadata"].get( + "spend_logs_metadata" + ) combined_metadata: Dict[str, Any] = { **(_requester_metadata if _requester_metadata else {}), **(user_api_key_auth_metadata if user_api_key_auth_metadata else {}), + **(spend_logs_metadata if spend_logs_metadata else {}), } if standard_logging_payload is not None and isinstance( standard_logging_payload, dict From dd0e7dcca839c8858e15130536527371febb7d0b Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Mon, 23 Mar 2026 11:02:21 -0700 Subject: [PATCH 10/37] test(prometheus): add tests for spend_logs_metadata in custom labels Verify that spend_logs_metadata is correctly merged into combined_metadata and flows through to Prometheus custom labels. Tests cover: basic extraction, precedence when keys overlap, all three metadata sources combined, and None handling. Co-Authored-By: Claude Opus 4.6 --- .../test_prometheus_spend_logs_metadata.py | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 tests/test_litellm/integrations/test_prometheus_spend_logs_metadata.py diff --git a/tests/test_litellm/integrations/test_prometheus_spend_logs_metadata.py b/tests/test_litellm/integrations/test_prometheus_spend_logs_metadata.py new file mode 100644 index 00000000000..d60c2ae9293 --- /dev/null +++ b/tests/test_litellm/integrations/test_prometheus_spend_logs_metadata.py @@ -0,0 +1,110 @@ +""" +Unit tests for spend_logs_metadata inclusion in Prometheus custom labels. + +Verifies that metadata from x-litellm-spend-logs-metadata header is available +in Prometheus custom labels via combined_metadata. +""" +from litellm.integrations.prometheus import get_custom_labels_from_metadata + + +def test_get_custom_labels_includes_spend_logs_metadata(monkeypatch): + """ + Test that get_custom_labels_from_metadata extracts fields from + spend_logs_metadata when it is merged into combined_metadata. + """ + monkeypatch.setattr( + "litellm.custom_prometheus_metadata_labels", + ["metadata.department", "metadata.env"], + ) + + # Simulate combined_metadata after merging all three sources + combined_metadata = { + "request_key": "from_requester", # from requester_metadata + "auth_key": "from_auth", # from user_api_key_auth_metadata + "department": "engineering", # from spend_logs_metadata + "env": "production", # from spend_logs_metadata + } + + result = get_custom_labels_from_metadata(combined_metadata) + assert result == { + "metadata_department": "engineering", + "metadata_env": "production", + } + + +def test_spend_logs_metadata_overrides_earlier_sources(monkeypatch): + """ + Test that spend_logs_metadata values take precedence over + requester_metadata and user_api_key_auth_metadata when keys overlap, + since it is spread last in combined_metadata. + """ + monkeypatch.setattr( + "litellm.custom_prometheus_metadata_labels", + ["metadata.team"], + ) + + # Simulate the dict spread order: requester -> auth -> spend_logs + requester_metadata = {"team": "old_team"} + user_api_key_auth_metadata = {"team": "auth_team"} + spend_logs_metadata = {"team": "spend_team"} + + combined_metadata = { + **requester_metadata, + **user_api_key_auth_metadata, + **spend_logs_metadata, + } + + result = get_custom_labels_from_metadata(combined_metadata) + assert result == {"metadata_team": "spend_team"} + + +def test_combined_metadata_with_all_three_sources(monkeypatch): + """ + Test that combined_metadata correctly merges requester_metadata, + user_api_key_auth_metadata, and spend_logs_metadata. + """ + monkeypatch.setattr( + "litellm.custom_prometheus_metadata_labels", + ["metadata.from_requester", "metadata.from_auth", "metadata.from_spend"], + ) + + # Reproduce the exact spread pattern from prometheus.py + _requester_metadata = {"from_requester": "val1"} + user_api_key_auth_metadata = {"from_auth": "val2"} + spend_logs_metadata = {"from_spend": "val3"} + + combined_metadata = { + **(_requester_metadata if _requester_metadata else {}), + **(user_api_key_auth_metadata if user_api_key_auth_metadata else {}), + **(spend_logs_metadata if spend_logs_metadata else {}), + } + + result = get_custom_labels_from_metadata(combined_metadata) + assert result == { + "metadata_from_requester": "val1", + "metadata_from_auth": "val2", + "metadata_from_spend": "val3", + } + + +def test_combined_metadata_with_none_spend_logs(monkeypatch): + """ + Test that combined_metadata works when spend_logs_metadata is None. + """ + monkeypatch.setattr( + "litellm.custom_prometheus_metadata_labels", + ["metadata.foo"], + ) + + _requester_metadata = {"foo": "bar"} + user_api_key_auth_metadata = None + spend_logs_metadata = None + + combined_metadata = { + **(_requester_metadata if _requester_metadata else {}), + **(user_api_key_auth_metadata if user_api_key_auth_metadata else {}), + **(spend_logs_metadata if spend_logs_metadata else {}), + } + + result = get_custom_labels_from_metadata(combined_metadata) + assert result == {"metadata_foo": "bar"} From 742e176611a0d1ecfa53644b34d0356743455877 Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Mon, 23 Mar 2026 17:23:14 -0700 Subject: [PATCH 11/37] docs(reasoning_content.md): update guide --- docs/my-website/docs/reasoning_content.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/my-website/docs/reasoning_content.md b/docs/my-website/docs/reasoning_content.md index 3f7b76dab65..6e6a30cdb49 100644 --- a/docs/my-website/docs/reasoning_content.md +++ b/docs/my-website/docs/reasoning_content.md @@ -13,6 +13,7 @@ Supported Providers: - Deepseek (`deepseek/`) - Anthropic API (`anthropic/`) - Bedrock (Anthropic + Deepseek + GPT-OSS) (`bedrock/`) +- OpenAI Responses API (`openai/responses/`) - Vertex AI (Anthropic) (`vertexai/`) - OpenRouter (`openrouter/`) - XAI (`xai/`) From 26d162ccf4aa88053c384512b2307df203eb7bfb Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Mon, 23 Mar 2026 18:12:50 -0700 Subject: [PATCH 12/37] fix(test): add user_api_key_project_alias to spend logs expected keys Co-Authored-By: Claude Opus 4.6 --- .../test_spend_management_endpoints.py | 102 +++++++++++++++--- 1 file changed, 86 insertions(+), 16 deletions(-) diff --git a/tests/test_litellm/proxy/spend_tracking/test_spend_management_endpoints.py b/tests/test_litellm/proxy/spend_tracking/test_spend_management_endpoints.py index d857d5bdf09..05d9b7489f4 100644 --- a/tests/test_litellm/proxy/spend_tracking/test_spend_management_endpoints.py +++ b/tests/test_litellm/proxy/spend_tracking/test_spend_management_endpoints.py @@ -94,6 +94,8 @@ def make_ui_spend_logs_mock_prisma(mock_spend_logs, filter_fn, team_lookup_fn=No self.find_unique = team_lookup_fn return MockPrismaClient() + + from litellm.proxy._types import ( LitellmUserRoles, Member, @@ -111,7 +113,9 @@ from litellm.types.utils import BudgetConfig async def test_is_admin_view_safe_true(monkeypatch): # Force underlying check to return True monkeypatch.setattr( - spend_management_endpoints, "_user_has_admin_view", lambda user_api_key_dict: True + spend_management_endpoints, + "_user_has_admin_view", + lambda user_api_key_dict: True, ) auth = UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN, user_id="admin_user") assert spend_management_endpoints._is_admin_view_safe(auth) is True @@ -121,7 +125,9 @@ async def test_is_admin_view_safe_true(monkeypatch): async def test_is_admin_view_safe_false(monkeypatch): # Force underlying check to return False monkeypatch.setattr( - spend_management_endpoints, "_user_has_admin_view", lambda user_api_key_dict: False + spend_management_endpoints, + "_user_has_admin_view", + lambda user_api_key_dict: False, ) auth = UserAPIKeyAuth(user_role=LitellmUserRoles.INTERNAL_USER, user_id="user_1") assert spend_management_endpoints._is_admin_view_safe(auth) is False @@ -179,7 +185,9 @@ async def test_can_team_member_view_log_team_not_found(monkeypatch): prisma = MockPrisma() # Even if admin check would return True, no team means False monkeypatch.setattr( - spend_management_endpoints, "_is_user_team_admin", lambda user_api_key_dict, team_obj: True + spend_management_endpoints, + "_is_user_team_admin", + lambda user_api_key_dict, team_obj: True, ) auth = UserAPIKeyAuth(user_role=LitellmUserRoles.INTERNAL_USER, user_id="user_1") allowed = await spend_management_endpoints._can_team_member_view_log( @@ -208,7 +216,9 @@ async def test_can_team_member_view_log_not_admin(monkeypatch): prisma = MockPrisma() monkeypatch.setattr( - spend_management_endpoints, "_is_user_team_admin", lambda user_api_key_dict, team_obj: False + spend_management_endpoints, + "_is_user_team_admin", + lambda user_api_key_dict, team_obj: False, ) auth = UserAPIKeyAuth(user_role=LitellmUserRoles.INTERNAL_USER, user_id="user_1") allowed = await spend_management_endpoints._can_team_member_view_log( @@ -237,7 +247,9 @@ async def test_can_team_member_view_log_admin(monkeypatch): prisma = MockPrisma() monkeypatch.setattr( - spend_management_endpoints, "_is_user_team_admin", lambda user_api_key_dict, team_obj: True + spend_management_endpoints, + "_is_user_team_admin", + lambda user_api_key_dict, team_obj: True, ) auth = UserAPIKeyAuth(user_role=LitellmUserRoles.INTERNAL_USER, user_id="user_1") allowed = await spend_management_endpoints._can_team_member_view_log( @@ -267,6 +279,7 @@ def test_can_user_view_spend_log_false_for_other_roles(): auth = UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN, user_id="admin") assert spend_management_endpoints._can_user_view_spend_log(auth) is False + ignored_keys = [ "request_id", "session_id", @@ -292,6 +305,7 @@ ignored_keys = [ "metadata.user_api_key_alias", "metadata.user_api_key_team_id", "metadata.user_api_key_project_id", + "metadata.user_api_key_project_alias", "metadata.user_api_key_org_id", "metadata.user_api_key_user_id", "metadata.user_api_key_team_alias", @@ -502,7 +516,11 @@ async def test_ui_view_spend_logs_sort_by_and_sort_order( async def mock_query_raw(sql_query, *params): # Endpoint uses raw SQL with ORDER BY startTime DESC; mock returns sorted data - order = {"startTime": "desc"} if sort_by is None else {sort_by: sort_order or "desc"} + order = ( + {"startTime": "desc"} + if sort_by is None + else {sort_by: sort_order or "desc"} + ) sorted_logs = _sort_logs(base_logs, order) page_size = params[-2] if len(params) >= 2 else 50 skip = params[-1] if len(params) >= 1 else 0 @@ -568,6 +586,7 @@ async def test_ui_view_spend_logs_sort_validation_errors( client, monkeypatch, sort_by, sort_order ): """Test that invalid sort_by and sort_order return 400.""" + async def mock_count(*args, **kwargs): return 0 @@ -752,13 +771,33 @@ async def test_ui_view_spend_logs_with_team_id(client, monkeypatch): @pytest.mark.asyncio -async def test_ui_view_spend_logs_internal_user_scoped_without_user_id(client, monkeypatch): +async def test_ui_view_spend_logs_internal_user_scoped_without_user_id( + client, monkeypatch +): """ Internal users should only be able to view their own spend even if user_id is not provided. """ mock_spend_logs = [ - {"id": "log1", "request_id": "req1", "api_key": "sk-test-key", "user": "internal_user_1", "team_id": "team1", "spend": 0.05, "startTime": datetime.datetime.now(timezone.utc).isoformat(), "model": "gpt-3.5-turbo"}, - {"id": "log2", "request_id": "req2", "api_key": "sk-test-key", "user": "internal_user_2", "team_id": "team1", "spend": 0.10, "startTime": datetime.datetime.now(timezone.utc).isoformat(), "model": "gpt-4"}, + { + "id": "log1", + "request_id": "req1", + "api_key": "sk-test-key", + "user": "internal_user_1", + "team_id": "team1", + "spend": 0.05, + "startTime": datetime.datetime.now(timezone.utc).isoformat(), + "model": "gpt-3.5-turbo", + }, + { + "id": "log2", + "request_id": "req2", + "api_key": "sk-test-key", + "user": "internal_user_2", + "team_id": "team1", + "spend": 0.10, + "startTime": datetime.datetime.now(timezone.utc).isoformat(), + "model": "gpt-4", + }, ] def filter_by_user(where): @@ -799,8 +838,26 @@ async def test_ui_view_spend_logs_team_admin_can_view_team_spend(client, monkeyp Team admins should be able to view team-wide spend when team_id is provided. """ mock_spend_logs = [ - {"id": "log1", "request_id": "req1", "api_key": "sk-test-key", "user": "member1", "team_id": "team_admin_team", "spend": 0.05, "startTime": datetime.datetime.now(timezone.utc).isoformat(), "model": "gpt-3.5-turbo"}, - {"id": "log2", "request_id": "req2", "api_key": "sk-test-key", "user": "member2", "team_id": "team_other", "spend": 0.10, "startTime": datetime.datetime.now(timezone.utc).isoformat(), "model": "gpt-4"}, + { + "id": "log1", + "request_id": "req1", + "api_key": "sk-test-key", + "user": "member1", + "team_id": "team_admin_team", + "spend": 0.05, + "startTime": datetime.datetime.now(timezone.utc).isoformat(), + "model": "gpt-3.5-turbo", + }, + { + "id": "log2", + "request_id": "req2", + "api_key": "sk-test-key", + "user": "member2", + "team_id": "team_other", + "spend": 0.10, + "startTime": datetime.datetime.now(timezone.utc).isoformat(), + "model": "gpt-4", + }, ] def filter_by_team(where): @@ -827,7 +884,11 @@ async def test_ui_view_spend_logs_team_admin_can_view_team_spend(client, monkeyp response = client.get( "/spend/logs/ui", - params={"team_id": "team_admin_team", "start_date": start_date, "end_date": end_date}, + params={ + "team_id": "team_admin_team", + "start_date": start_date, + "end_date": end_date, + }, headers={"Authorization": "Bearer sk-test"}, ) @@ -839,6 +900,7 @@ async def test_ui_view_spend_logs_team_admin_can_view_team_spend(client, monkeyp finally: app.dependency_overrides.pop(ps.user_api_key_auth, None) + @pytest.mark.asyncio async def test_ui_view_spend_logs_pagination(client, monkeypatch): mock_spend_logs = [ @@ -2163,7 +2225,9 @@ async def test_ui_view_spend_logs_with_error_code(client): try: with patch.object( - ps, "prisma_client", make_ui_spend_logs_mock_prisma(mock_spend_logs, filter_by_error_code) + ps, + "prisma_client", + make_ui_spend_logs_mock_prisma(mock_spend_logs, filter_by_error_code), ): start_date, end_date = _default_date_range() @@ -2234,7 +2298,9 @@ async def test_ui_view_spend_logs_with_error_message(client): try: with patch.object( - ps, "prisma_client", make_ui_spend_logs_mock_prisma(mock_spend_logs, filter_by_error_message) + ps, + "prisma_client", + make_ui_spend_logs_mock_prisma(mock_spend_logs, filter_by_error_message), ): start_date, end_date = _default_date_range() @@ -2255,7 +2321,9 @@ async def test_ui_view_spend_logs_with_error_message(client): assert data["data"][0]["id"] == "log1" metadata = json.loads(data["data"][0]["metadata"]) assert "error_information" in metadata - assert "Rate limit exceeded" in metadata["error_information"]["error_message"] + assert ( + "Rate limit exceeded" in metadata["error_information"]["error_message"] + ) finally: app.dependency_overrides.pop(ps.user_api_key_auth, None) @@ -2321,7 +2389,9 @@ async def test_ui_view_spend_logs_with_error_code_and_key_alias(client): with patch.object( ps, "prisma_client", - make_ui_spend_logs_mock_prisma(mock_spend_logs, filter_by_error_code_and_key_alias), + make_ui_spend_logs_mock_prisma( + mock_spend_logs, filter_by_error_code_and_key_alias + ), ): start_date, end_date = _default_date_range() From 91bc095e18e8fce767bb9dd0fb80f777f166f48a Mon Sep 17 00:00:00 2001 From: DmitriyAlergant Date: Mon, 23 Mar 2026 21:29:00 -0400 Subject: [PATCH 13/37] ci: skip scheduled workflows on forks Add `if: github.repository == 'BerriAI/litellm'` guard to scheduled jobs in stale.yml, codeql.yml, and create_daily_staging_branch.yml. This matches the existing pattern in auto_update_price_and_context_window.yml and prevents these workflows from running unnecessarily on fork repositories. --- .github/workflows/codeql.yml | 1 + .github/workflows/create_daily_staging_branch.yml | 2 ++ .github/workflows/stale.yml | 1 + 3 files changed, 4 insertions(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 0b7cce2e4be..4e45b7fbe6f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -15,6 +15,7 @@ concurrency: jobs: analyze: + if: github.repository == 'BerriAI/litellm' name: Analyze (${{ matrix.language }}) runs-on: ubuntu-latest timeout-minutes: 30 diff --git a/.github/workflows/create_daily_staging_branch.yml b/.github/workflows/create_daily_staging_branch.yml index 08aebd7d04c..ec27aaad8ac 100644 --- a/.github/workflows/create_daily_staging_branch.yml +++ b/.github/workflows/create_daily_staging_branch.yml @@ -7,6 +7,7 @@ on: jobs: create-staging-branch: + if: github.repository == 'BerriAI/litellm' runs-on: ubuntu-latest steps: @@ -43,6 +44,7 @@ jobs: fi create-internal-dev-branch: + if: github.repository == 'BerriAI/litellm' runs-on: ubuntu-latest steps: diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 5a9b19fc9ca..4945655b614 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -7,6 +7,7 @@ on: jobs: stale: + if: github.repository == 'BerriAI/litellm' runs-on: ubuntu-latest steps: - uses: actions/stale@v8 From 1310a275d2d20d938e41bd176225370bc66adb77 Mon Sep 17 00:00:00 2001 From: DmitriyAlergant Date: Mon, 23 Mar 2026 21:39:11 -0400 Subject: [PATCH 14/37] ci: narrow codeql guard to schedule-only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use event_name check so push/PR-triggered CodeQL scans still run on forks β€” only the scheduled run is skipped. --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 4e45b7fbe6f..91b88b66a1f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -15,7 +15,7 @@ concurrency: jobs: analyze: - if: github.repository == 'BerriAI/litellm' + if: github.event_name != 'schedule' || github.repository == 'BerriAI/litellm' name: Analyze (${{ matrix.language }}) runs-on: ubuntu-latest timeout-minutes: 30 From 17e6e7a4cc5e5504c973ea12101f0d8a8970fbc0 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 24 Mar 2026 09:33:28 +0530 Subject: [PATCH 15/37] docs(opencode): add guidance for dropping reasoningSummary param OpenCode sends a `reasoningSummary` Responses API param with chat completion requests. Document how to use `additional_drop_params` to drop it and avoid 400 errors from the OpenAI API. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .../docs/tutorials/opencode_integration.md | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/docs/my-website/docs/tutorials/opencode_integration.md b/docs/my-website/docs/tutorials/opencode_integration.md index e55367833f2..d8948f34e77 100644 --- a/docs/my-website/docs/tutorials/opencode_integration.md +++ b/docs/my-website/docs/tutorials/opencode_integration.md @@ -253,7 +253,7 @@ model_list: litellm_params: model: openai/gpt-4 api_key: os.environ/OPENAI_API_KEY - + - model_name: gpt-4o litellm_params: model: openai/gpt-4o @@ -264,7 +264,7 @@ model_list: litellm_params: model: anthropic/claude-3-5-sonnet-20241022 api_key: os.environ/ANTHROPIC_API_KEY - + # DeepSeek models - model_name: deepseek-chat litellm_params: @@ -272,6 +272,19 @@ model_list: api_key: os.environ/DEEPSEEK_API_KEY ``` +### Dropping OpenCode-specific parameters + +OpenCode sends a `reasoningSummary` parameter (a Responses API concept) with certain models. This parameter is not supported by the Chat Completions API and will cause errors. Use `additional_drop_params` in your `litellm_params` to drop it: + +```yaml +model_list: + - model_name: gpt-5 + litellm_params: + model: gpt-5 + api_key: os.environ/OPENAI_API_KEY + additional_drop_params: ["reasoningSummary"] +``` + ## Troubleshooting **OpenCode not connecting:** @@ -294,6 +307,16 @@ model_list: - Validate JSON syntax using a JSON validator - Ensure the `$schema` URL is accessible +**`Unknown parameter: 'reasoningSummary'` error:** +- OpenCode sends a `reasoningSummary` parameter that is not supported by the Chat Completions API. Add `additional_drop_params: ["reasoningSummary"]` to your model's `litellm_params` to drop it automatically: + ```yaml + - model_name: gpt-5 + litellm_params: + model: gpt-5 + api_key: os.environ/OPENAI_API_KEY + additional_drop_params: ["reasoningSummary"] + ``` + ## Tips - Add more models to the config as needed - they'll appear in `/models` From 4e6e566b4d5a83aff02f4d6be7d7afec36470954 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 24 Mar 2026 09:42:59 +0530 Subject: [PATCH 16/37] docs(opencode): fix model prefix and clarify drop_params scope - Use openai/gpt-5 prefix to match existing doc conventions - Clarify that additional_drop_params must be added to every affected model entry, not just one Co-Authored-By: Claude Sonnet 4.6 (1M context) --- docs/my-website/docs/tutorials/opencode_integration.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/my-website/docs/tutorials/opencode_integration.md b/docs/my-website/docs/tutorials/opencode_integration.md index d8948f34e77..0727075b4a4 100644 --- a/docs/my-website/docs/tutorials/opencode_integration.md +++ b/docs/my-website/docs/tutorials/opencode_integration.md @@ -274,13 +274,13 @@ model_list: ### Dropping OpenCode-specific parameters -OpenCode sends a `reasoningSummary` parameter (a Responses API concept) with certain models. This parameter is not supported by the Chat Completions API and will cause errors. Use `additional_drop_params` in your `litellm_params` to drop it: +OpenCode sends a `reasoningSummary` parameter (a Responses API concept) with reasoning-capable models such as `gpt-5`. This parameter is not supported by the Chat Completions API and will cause errors. Add `additional_drop_params` to every model entry in your `model_list` that will receive requests from OpenCode with reasoning enabled: ```yaml model_list: - model_name: gpt-5 litellm_params: - model: gpt-5 + model: openai/gpt-5 api_key: os.environ/OPENAI_API_KEY additional_drop_params: ["reasoningSummary"] ``` @@ -308,11 +308,11 @@ model_list: - Ensure the `$schema` URL is accessible **`Unknown parameter: 'reasoningSummary'` error:** -- OpenCode sends a `reasoningSummary` parameter that is not supported by the Chat Completions API. Add `additional_drop_params: ["reasoningSummary"]` to your model's `litellm_params` to drop it automatically: +- OpenCode sends a `reasoningSummary` parameter that is not supported by the Chat Completions API. Add `additional_drop_params: ["reasoningSummary"]` to each affected model entry in your `litellm_params`: ```yaml - model_name: gpt-5 litellm_params: - model: gpt-5 + model: openai/gpt-5 api_key: os.environ/OPENAI_API_KEY additional_drop_params: ["reasoningSummary"] ``` From 80af635eb1764a20a16314cbe15e4f77b0500def Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 24 Mar 2026 09:44:04 +0530 Subject: [PATCH 17/37] Fix docs --- docs/my-website/docs/tutorials/opencode_integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/my-website/docs/tutorials/opencode_integration.md b/docs/my-website/docs/tutorials/opencode_integration.md index 0727075b4a4..35e00a1de50 100644 --- a/docs/my-website/docs/tutorials/opencode_integration.md +++ b/docs/my-website/docs/tutorials/opencode_integration.md @@ -274,7 +274,7 @@ model_list: ### Dropping OpenCode-specific parameters -OpenCode sends a `reasoningSummary` parameter (a Responses API concept) with reasoning-capable models such as `gpt-5`. This parameter is not supported by the Chat Completions API and will cause errors. Add `additional_drop_params` to every model entry in your `model_list` that will receive requests from OpenCode with reasoning enabled: +OpenCode sends a `reasoningSummary` parameter with reasoning-capable models such as `gpt-5`. This parameter is not supported by the Chat Completions API and will cause errors. Add `additional_drop_params` to every model entry in your `model_list` that will receive requests from OpenCode with reasoning enabled: ```yaml model_list: From 0aadf51342a1c82963b78622a6b986b89559a259 Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Mon, 23 Mar 2026 21:53:29 -0700 Subject: [PATCH 18/37] fix(proxy): ignore return_to in SSO when control_plane_url is not configured Instead of returning a 400 error when return_to is passed without control_plane_url configured, silently ignore it and proceed with the normal same-origin SSO flow. --- litellm/proxy/management_endpoints/ui_sso.py | 37 +++++++++---------- .../proxy/management_endpoints/test_ui_sso.py | 10 ++--- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/litellm/proxy/management_endpoints/ui_sso.py b/litellm/proxy/management_endpoints/ui_sso.py index d06ce56f816..0c50012abeb 100644 --- a/litellm/proxy/management_endpoints/ui_sso.py +++ b/litellm/proxy/management_endpoints/ui_sso.py @@ -404,14 +404,14 @@ async def google_login( state=cli_state, ) if return_to is not None and sso_redirect is not None: - SSOAuthenticationHandler._validate_return_to(return_to) - sso_redirect.set_cookie( - key="litellm_cp_return_to", - value=return_to, - max_age=600, - httponly=True, - samesite="lax", - ) + if SSOAuthenticationHandler._validate_return_to(return_to): + sso_redirect.set_cookie( + key="litellm_cp_return_to", + value=return_to, + max_age=600, + httponly=True, + samesite="lax", + ) return sso_redirect elif ui_username is not None: # No Google, Microsoft SSO @@ -1778,22 +1778,19 @@ class SSOAuthenticationHandler: """ @staticmethod - def _validate_return_to(return_to: str) -> None: + def _validate_return_to(return_to: str) -> bool: """ Validate that return_to matches the configured control_plane_url origin. - Raises HTTPException(400) if: - - control_plane_url is not configured in general_settings - - return_to origin does not match control_plane_url origin + Returns True if return_to is valid and should be used. + Returns False if control_plane_url is not configured (return_to is ignored). + Raises HTTPException(400) if return_to origin does not match control_plane_url origin. """ from litellm.proxy.proxy_server import general_settings control_plane_url = general_settings.get("control_plane_url") if control_plane_url is None: - raise HTTPException( - status_code=400, - detail="return_to is not allowed: control_plane_url is not configured", - ) + return False def _origin(url: str) -> tuple: parsed = urlparse(url) @@ -1809,6 +1806,8 @@ class SSOAuthenticationHandler: detail="return_to does not match the configured control_plane_url", ) + return True + @staticmethod async def get_sso_login_redirect( redirect_url: str, @@ -2589,9 +2588,9 @@ class SSOAuthenticationHandler: # Control-plane cross-origin: store JWT behind a single-use opaque # code (60s TTL) so the token never appears in browser history / logs. # The control plane redeems it via POST /v3/login/exchange. - if return_to is not None: - SSOAuthenticationHandler._validate_return_to(return_to) - + if return_to is not None and SSOAuthenticationHandler._validate_return_to( + return_to + ): code = secrets.token_urlsafe(32) cache_key = f"login_code:{code}" cache_value = {"token": jwt_token, "redirect_url": return_to} diff --git a/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py b/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py index fc9c37b7f84..ff636ca04ae 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py +++ b/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py @@ -5164,15 +5164,13 @@ def test_generic_response_convertor_extra_attributes_missing_field(monkeypatch): class TestValidateReturnTo: """Tests for SSOAuthenticationHandler._validate_return_to""" - def test_rejects_when_no_control_plane_url_configured(self, monkeypatch): - """return_to should be rejected if control_plane_url is not in general_settings.""" + def test_returns_false_when_no_control_plane_url_configured(self, monkeypatch): + """return_to should be silently ignored if control_plane_url is not in general_settings.""" monkeypatch.setattr( "litellm.proxy.proxy_server.general_settings", {} ) - with pytest.raises(HTTPException) as exc_info: - SSOAuthenticationHandler._validate_return_to("https://cp.example.com/ui") - assert exc_info.value.status_code == 400 - assert "not configured" in exc_info.value.detail + result = SSOAuthenticationHandler._validate_return_to("https://cp.example.com/ui") + assert result is False def test_allows_matching_origin(self, monkeypatch): """return_to matching the configured control_plane_url origin should pass.""" From e40f68aec45ddc5ca526eb8d206e214e8e9a3faa Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Mon, 23 Mar 2026 22:03:10 -0700 Subject: [PATCH 19/37] test(ui): add unit tests for 5 untested frontend components - AntDLoadingSpinner: rendering, prop forwarding, icon styling - MessageManager: static fallback, custom instance delegation - claude_code_plugins/helpers: all pure utility functions (15 describe blocks, 55 tests) - AgentSelector: fetch behavior, loading states, error handling, disabled state - WorkerDropdown: conditional rendering, worker options, selection changes --- .../WorkerDropdown/WorkerDropdown.test.tsx | 134 +++++++ .../agent_management/AgentSelector.test.tsx | 144 ++++++++ .../claude_code_plugins/helpers.test.ts | 329 ++++++++++++++++++ .../molecules/message_manager.test.ts | 107 ++++++ .../components/ui/AntDLoadingSpinner.test.tsx | 61 ++++ 5 files changed, 775 insertions(+) create mode 100644 ui/litellm-dashboard/src/components/Navbar/WorkerDropdown/WorkerDropdown.test.tsx create mode 100644 ui/litellm-dashboard/src/components/agent_management/AgentSelector.test.tsx create mode 100644 ui/litellm-dashboard/src/components/claude_code_plugins/helpers.test.ts create mode 100644 ui/litellm-dashboard/src/components/molecules/message_manager.test.ts create mode 100644 ui/litellm-dashboard/src/components/ui/AntDLoadingSpinner.test.tsx diff --git a/ui/litellm-dashboard/src/components/Navbar/WorkerDropdown/WorkerDropdown.test.tsx b/ui/litellm-dashboard/src/components/Navbar/WorkerDropdown/WorkerDropdown.test.tsx new file mode 100644 index 00000000000..17b8b393607 --- /dev/null +++ b/ui/litellm-dashboard/src/components/Navbar/WorkerDropdown/WorkerDropdown.test.tsx @@ -0,0 +1,134 @@ +import { render, screen } from "@testing-library/react"; +import { describe, expect, it, vi, beforeEach } from "vitest"; + +// Mock the useWorker hook +const mockUseWorker = vi.fn(); +vi.mock("@/hooks/useWorker", () => ({ + useWorker: () => mockUseWorker(), +})); + +// Mock antd Select +vi.mock("antd", () => ({ + Select: ({ value, options, onChange, style, disabled, ...props }: any) => ( + + ), +})); + +// Mock icon +vi.mock("@ant-design/icons", () => ({ + CloudServerOutlined: () => , +})); + +import WorkerDropdown from "./WorkerDropdown"; + +describe("WorkerDropdown", () => { + const mockOnWorkerSwitch = vi.fn(); + const workers = [ + { worker_id: "w1", name: "Worker 1" }, + { worker_id: "w2", name: "Worker 2" }, + { worker_id: "w3", name: "Worker 3" }, + ]; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("renders null when isControlPlane is false", () => { + mockUseWorker.mockReturnValue({ + isControlPlane: false, + selectedWorker: workers[0], + workers, + }); + + const { container } = render(); + expect(container).toBeEmptyDOMElement(); + }); + + it("renders null when selectedWorker is null", () => { + mockUseWorker.mockReturnValue({ + isControlPlane: true, + selectedWorker: null, + workers, + }); + + const { container } = render(); + expect(container).toBeEmptyDOMElement(); + }); + + it("renders the select when isControlPlane and selectedWorker exist", () => { + mockUseWorker.mockReturnValue({ + isControlPlane: true, + selectedWorker: workers[0], + workers, + }); + + render(); + expect(screen.getByTestId("worker-select")).toBeInTheDocument(); + }); + + it("renders all worker options", () => { + mockUseWorker.mockReturnValue({ + isControlPlane: true, + selectedWorker: workers[0], + workers, + }); + + render(); + expect(screen.getByText("Worker 1")).toBeInTheDocument(); + expect(screen.getByText("Worker 2")).toBeInTheDocument(); + expect(screen.getByText("Worker 3")).toBeInTheDocument(); + }); + + it("sets current worker as selected value", () => { + mockUseWorker.mockReturnValue({ + isControlPlane: true, + selectedWorker: workers[1], + workers, + }); + + render(); + const select = screen.getByTestId("worker-select") as HTMLSelectElement; + expect(select.value).toBe("w2"); + }); + + it("disables the currently selected worker in options", () => { + mockUseWorker.mockReturnValue({ + isControlPlane: true, + selectedWorker: workers[0], + workers, + }); + + render(); + const options = screen.getAllByRole("option"); + const selectedOption = options.find((opt) => (opt as HTMLOptionElement).value === "w1"); + expect(selectedOption).toBeDisabled(); + }); + + it("calls onWorkerSwitch when selection changes", async () => { + mockUseWorker.mockReturnValue({ + isControlPlane: true, + selectedWorker: workers[0], + workers, + }); + + render(); + const select = screen.getByTestId("worker-select"); + + const { default: userEvent } = await import("@testing-library/user-event"); + const user = userEvent.setup(); + await user.selectOptions(select, "w2"); + + expect(mockOnWorkerSwitch).toHaveBeenCalledWith("w2"); + }); +}); diff --git a/ui/litellm-dashboard/src/components/agent_management/AgentSelector.test.tsx b/ui/litellm-dashboard/src/components/agent_management/AgentSelector.test.tsx new file mode 100644 index 00000000000..26f903cd310 --- /dev/null +++ b/ui/litellm-dashboard/src/components/agent_management/AgentSelector.test.tsx @@ -0,0 +1,144 @@ +import { render, screen, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { describe, expect, it, vi, beforeEach } from "vitest"; + +// Mock networking module +const mockGetAgentsList = vi.fn(); +vi.mock("../networking", () => ({ + getAgentsList: (...args: any[]) => mockGetAgentsList(...args), +})); + +// Mock antd Select +vi.mock("antd", () => { + const SelectComponent = ({ children, onChange, value, mode, placeholder, loading, disabled, ...props }: any) => ( +
+ + {loading && Loading} +
+ ); + + SelectComponent.Option = ({ children, value, ...props }: any) => ( + + ); + + return { Select: SelectComponent }; +}); + +import AgentSelector from "./AgentSelector"; + +describe("AgentSelector", () => { + const defaultProps = { + onChange: vi.fn(), + accessToken: "test-token", + }; + + beforeEach(() => { + vi.clearAllMocks(); + mockGetAgentsList.mockResolvedValue({ + agents: [ + { agent_id: "agent-1", agent_name: "Agent One" }, + { agent_id: "agent-2", agent_name: "Agent Two", agent_access_groups: ["group-a", "group-b"] }, + ], + }); + }); + + it("renders the selector", () => { + render(); + expect(screen.getByTestId("agent-select")).toBeInTheDocument(); + }); + + it("fetches agents on mount with access token", async () => { + render(); + await waitFor(() => { + expect(mockGetAgentsList).toHaveBeenCalledWith("test-token"); + }); + }); + + it("does not fetch when accessToken is empty", () => { + render(); + expect(mockGetAgentsList).not.toHaveBeenCalled(); + }); + + it("shows loading state while fetching", async () => { + // Keep the promise pending + let resolve: any; + mockGetAgentsList.mockReturnValue(new Promise((r) => { resolve = r; })); + + render(); + expect(screen.getByTestId("agent-select")).toHaveAttribute("data-loading", "true"); + + // Resolve to clean up + resolve({ agents: [] }); + await waitFor(() => { + expect(screen.getByTestId("agent-select")).toHaveAttribute("data-loading", "false"); + }); + }); + + it("renders agent options after fetch", async () => { + render(); + await waitFor(() => { + expect(screen.getByText("Agent One")).toBeInTheDocument(); + expect(screen.getByText("Agent Two")).toBeInTheDocument(); + }); + }); + + it("renders access group options with group prefix", async () => { + render(); + await waitFor(() => { + expect(screen.getByText("group-a")).toBeInTheDocument(); + expect(screen.getByText("group-b")).toBeInTheDocument(); + }); + }); + + it("respects disabled prop", () => { + render(); + expect(screen.getByTestId("agent-select")).toHaveAttribute("data-disabled", "true"); + }); + + it("handles API error gracefully", async () => { + const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {}); + mockGetAgentsList.mockRejectedValue(new Error("API error")); + + render(); + await waitFor(() => { + expect(consoleSpy).toHaveBeenCalledWith("Error fetching agents:", expect.any(Error)); + }); + + consoleSpy.mockRestore(); + }); + + it("passes value as flattened selectedValues", async () => { + render( + + ); + await waitFor(() => { + const select = screen.getByTestId("select-input"); + // The value should contain agent-1 and group:group-a + expect(select).toBeInTheDocument(); + }); + }); + + it("handles null response from API", async () => { + mockGetAgentsList.mockResolvedValue(null); + render(); + await waitFor(() => { + expect(screen.getByTestId("agent-select")).toHaveAttribute("data-loading", "false"); + }); + }); +}); diff --git a/ui/litellm-dashboard/src/components/claude_code_plugins/helpers.test.ts b/ui/litellm-dashboard/src/components/claude_code_plugins/helpers.test.ts new file mode 100644 index 00000000000..6a754f57393 --- /dev/null +++ b/ui/litellm-dashboard/src/components/claude_code_plugins/helpers.test.ts @@ -0,0 +1,329 @@ +import { describe, expect, it } from "vitest"; +import { + formatInstallCommand, + extractCategories, + validatePluginName, + getSourceDisplayText, + getSourceLink, + getCategoryBadgeColor, + formatDateString, + truncateText, + filterPluginsBySearch, + filterPluginsByCategory, + isValidSemanticVersion, + isValidEmail, + isValidUrl, + parseKeywords, + formatKeywords, +} from "./helpers"; +import { MarketplacePluginEntry, PluginSource } from "./types"; + +describe("formatInstallCommand", () => { + it("formats github source with repo", () => { + const plugin = { name: "my-plugin", source: { source: "github" as const, repo: "org/repo" } }; + expect(formatInstallCommand(plugin)).toBe("/plugin marketplace add org/repo"); + }); + + it("formats url source", () => { + const plugin = { name: "my-plugin", source: { source: "url" as const, url: "https://example.com/plugin" } }; + expect(formatInstallCommand(plugin)).toBe("/plugin marketplace add https://example.com/plugin"); + }); + + it("falls back to plugin name when no repo or url", () => { + const plugin = { name: "my-plugin", source: { source: "github" as const } }; + expect(formatInstallCommand(plugin)).toBe("/plugin marketplace add my-plugin"); + }); +}); + +describe("extractCategories", () => { + it("returns All and Other for empty list", () => { + expect(extractCategories([])).toEqual(["All", "Other"]); + }); + + it("extracts and sorts unique categories", () => { + const plugins = [ + { category: "Development" }, + { category: "Analytics" }, + { category: "Development" }, + ]; + expect(extractCategories(plugins)).toEqual(["All", "Analytics", "Development", "Other"]); + }); + + it("ignores empty/whitespace categories", () => { + const plugins = [{ category: "" }, { category: " " }, { category: "Tools" }]; + expect(extractCategories(plugins)).toEqual(["All", "Tools", "Other"]); + }); + + it("handles undefined category", () => { + const plugins = [{ category: undefined }, { category: "Security" }]; + expect(extractCategories(plugins)).toEqual(["All", "Security", "Other"]); + }); +}); + +describe("validatePluginName", () => { + it("accepts valid kebab-case names", () => { + expect(validatePluginName("my-plugin")).toBe(true); + expect(validatePluginName("plugin123")).toBe(true); + expect(validatePluginName("a-b-c")).toBe(true); + }); + + it("rejects names with uppercase", () => { + expect(validatePluginName("MyPlugin")).toBe(false); + }); + + it("rejects names with spaces", () => { + expect(validatePluginName("my plugin")).toBe(false); + }); + + it("rejects empty/whitespace names", () => { + expect(validatePluginName("")).toBe(false); + expect(validatePluginName(" ")).toBe(false); + }); + + it("rejects names with special characters", () => { + expect(validatePluginName("my_plugin")).toBe(false); + expect(validatePluginName("my.plugin")).toBe(false); + }); +}); + +describe("getSourceDisplayText", () => { + it("shows github repo", () => { + expect(getSourceDisplayText({ source: "github", repo: "org/repo" })).toBe("GitHub: org/repo"); + }); + + it("shows url", () => { + expect(getSourceDisplayText({ source: "url", url: "https://example.com" })).toBe("https://example.com"); + }); + + it("returns unknown for missing data", () => { + expect(getSourceDisplayText({ source: "github" })).toBe("Unknown source"); + }); +}); + +describe("getSourceLink", () => { + it("returns github link for github source", () => { + expect(getSourceLink({ source: "github", repo: "org/repo" })).toBe("https://github.com/org/repo"); + }); + + it("returns url for url source", () => { + expect(getSourceLink({ source: "url", url: "https://example.com" })).toBe("https://example.com"); + }); + + it("returns null when no repo or url", () => { + expect(getSourceLink({ source: "github" })).toBeNull(); + }); +}); + +describe("getCategoryBadgeColor", () => { + it("returns blue for development categories", () => { + expect(getCategoryBadgeColor("Development")).toBe("blue"); + expect(getCategoryBadgeColor("dev-tools")).toBe("blue"); + }); + + it("returns green for productivity categories", () => { + expect(getCategoryBadgeColor("Productivity")).toBe("green"); + expect(getCategoryBadgeColor("Workflow")).toBe("green"); + }); + + it("returns purple for learning categories", () => { + expect(getCategoryBadgeColor("Learning")).toBe("purple"); + expect(getCategoryBadgeColor("Education")).toBe("purple"); + }); + + it("returns red for security categories", () => { + expect(getCategoryBadgeColor("Security")).toBe("red"); + expect(getCategoryBadgeColor("Safety")).toBe("red"); + }); + + it("returns orange for data categories", () => { + expect(getCategoryBadgeColor("Data")).toBe("orange"); + expect(getCategoryBadgeColor("Analytics")).toBe("orange"); + }); + + it("returns yellow for integration categories", () => { + expect(getCategoryBadgeColor("Integration")).toBe("yellow"); + expect(getCategoryBadgeColor("API")).toBe("yellow"); + }); + + it("returns gray for unknown or undefined categories", () => { + expect(getCategoryBadgeColor("Unknown")).toBe("gray"); + expect(getCategoryBadgeColor(undefined)).toBe("gray"); + }); +}); + +describe("formatDateString", () => { + it("formats valid date strings", () => { + const result = formatDateString("2024-01-15T12:00:00Z"); + expect(result).toContain("2024"); + expect(result).toContain("Jan"); + expect(result).toContain("15"); + }); + + it("returns N/A for undefined", () => { + expect(formatDateString(undefined)).toBe("N/A"); + }); + + it("returns N/A for empty string", () => { + expect(formatDateString("")).toBe("N/A"); + }); +}); + +describe("truncateText", () => { + it("returns text unchanged if shorter than max", () => { + expect(truncateText("hello", 10)).toBe("hello"); + }); + + it("truncates and adds ellipsis", () => { + expect(truncateText("hello world", 5)).toBe("hello..."); + }); + + it("handles exact length", () => { + expect(truncateText("hello", 5)).toBe("hello"); + }); + + it("handles empty text", () => { + expect(truncateText("", 5)).toBe(""); + }); +}); + +describe("filterPluginsBySearch", () => { + const plugins: MarketplacePluginEntry[] = [ + { + name: "code-formatter", + source: { source: "github", repo: "org/formatter" }, + description: "Formats code nicely", + keywords: ["format", "lint"], + }, + { + name: "data-viewer", + source: { source: "github", repo: "org/viewer" }, + description: "View data", + keywords: ["analytics"], + }, + ]; + + it("returns all plugins for empty search", () => { + expect(filterPluginsBySearch(plugins, "")).toEqual(plugins); + expect(filterPluginsBySearch(plugins, " ")).toEqual(plugins); + }); + + it("matches by name", () => { + expect(filterPluginsBySearch(plugins, "formatter")).toHaveLength(1); + expect(filterPluginsBySearch(plugins, "formatter")[0].name).toBe("code-formatter"); + }); + + it("matches by description", () => { + expect(filterPluginsBySearch(plugins, "nicely")).toHaveLength(1); + }); + + it("matches by keyword", () => { + expect(filterPluginsBySearch(plugins, "analytics")).toHaveLength(1); + expect(filterPluginsBySearch(plugins, "analytics")[0].name).toBe("data-viewer"); + }); + + it("is case insensitive", () => { + expect(filterPluginsBySearch(plugins, "FORMATTER")).toHaveLength(1); + }); +}); + +describe("filterPluginsByCategory", () => { + const plugins: MarketplacePluginEntry[] = [ + { name: "a", source: { source: "github" }, category: "Dev" }, + { name: "b", source: { source: "github" }, category: "Security" }, + { name: "c", source: { source: "github" }, category: "" }, + { name: "d", source: { source: "github" } }, + ]; + + it("returns all plugins for 'All'", () => { + expect(filterPluginsByCategory(plugins, "All")).toEqual(plugins); + }); + + it("returns uncategorized plugins for 'Other'", () => { + const result = filterPluginsByCategory(plugins, "Other"); + expect(result).toHaveLength(2); + expect(result.map((p) => p.name)).toEqual(["c", "d"]); + }); + + it("filters by specific category", () => { + const result = filterPluginsByCategory(plugins, "Dev"); + expect(result).toHaveLength(1); + expect(result[0].name).toBe("a"); + }); +}); + +describe("isValidSemanticVersion", () => { + it("accepts valid semver", () => { + expect(isValidSemanticVersion("1.0.0")).toBe(true); + expect(isValidSemanticVersion("0.1.0-alpha")).toBe(true); + expect(isValidSemanticVersion("2.3.4+build.1")).toBe(true); + }); + + it("rejects invalid semver", () => { + expect(isValidSemanticVersion("1.0")).toBe(false); + expect(isValidSemanticVersion("abc")).toBe(false); + }); + + it("returns true for undefined (optional)", () => { + expect(isValidSemanticVersion(undefined)).toBe(true); + }); +}); + +describe("isValidEmail", () => { + it("accepts valid emails", () => { + expect(isValidEmail("user@example.com")).toBe(true); + }); + + it("rejects invalid emails", () => { + expect(isValidEmail("not-an-email")).toBe(false); + expect(isValidEmail("@example.com")).toBe(false); + }); + + it("returns true for undefined (optional)", () => { + expect(isValidEmail(undefined)).toBe(true); + }); +}); + +describe("isValidUrl", () => { + it("accepts valid urls", () => { + expect(isValidUrl("https://example.com")).toBe(true); + expect(isValidUrl("http://localhost:3000")).toBe(true); + }); + + it("rejects invalid urls", () => { + expect(isValidUrl("not a url")).toBe(false); + }); + + it("returns true for undefined (optional)", () => { + expect(isValidUrl(undefined)).toBe(true); + }); +}); + +describe("parseKeywords", () => { + it("splits comma-separated keywords", () => { + expect(parseKeywords("a, b, c")).toEqual(["a", "b", "c"]); + }); + + it("trims whitespace", () => { + expect(parseKeywords(" foo , bar ")).toEqual(["foo", "bar"]); + }); + + it("filters empty entries", () => { + expect(parseKeywords("a,,b,")).toEqual(["a", "b"]); + }); + + it("returns empty array for empty string", () => { + expect(parseKeywords("")).toEqual([]); + expect(parseKeywords(" ")).toEqual([]); + }); +}); + +describe("formatKeywords", () => { + it("joins keywords with comma and space", () => { + expect(formatKeywords(["a", "b", "c"])).toBe("a, b, c"); + }); + + it("returns empty string for empty/undefined array", () => { + expect(formatKeywords([])).toBe(""); + expect(formatKeywords(undefined)).toBe(""); + }); +}); diff --git a/ui/litellm-dashboard/src/components/molecules/message_manager.test.ts b/ui/litellm-dashboard/src/components/molecules/message_manager.test.ts new file mode 100644 index 00000000000..541efcbc4cb --- /dev/null +++ b/ui/litellm-dashboard/src/components/molecules/message_manager.test.ts @@ -0,0 +1,107 @@ +import { describe, expect, it, vi, beforeEach } from "vitest"; + +// Use vi.hoisted so the mock object is available when vi.mock is hoisted +const mockStaticMessage = vi.hoisted(() => ({ + success: vi.fn(), + error: vi.fn(), + warning: vi.fn(), + info: vi.fn(), + loading: vi.fn(), + destroy: vi.fn(), +})); + +vi.mock("antd", () => ({ + message: mockStaticMessage, +})); + +import MessageManager, { setMessageInstance } from "./message_manager"; + +describe("MessageManager", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe("when no instance is set (falls back to static message)", () => { + it("delegates success to static message", () => { + MessageManager.success("done!"); + expect(mockStaticMessage.success).toHaveBeenCalledWith("done!", undefined); + }); + + it("delegates error to static message", () => { + MessageManager.error("failed!", 5); + expect(mockStaticMessage.error).toHaveBeenCalledWith("failed!", 5); + }); + + it("delegates warning to static message", () => { + MessageManager.warning("watch out"); + expect(mockStaticMessage.warning).toHaveBeenCalledWith("watch out", undefined); + }); + + it("delegates info to static message", () => { + MessageManager.info("fyi"); + expect(mockStaticMessage.info).toHaveBeenCalledWith("fyi", undefined); + }); + + it("delegates loading to static message", () => { + MessageManager.loading("loading...", 3); + expect(mockStaticMessage.loading).toHaveBeenCalledWith("loading...", 3); + }); + + it("delegates destroy to static message", () => { + MessageManager.destroy(); + expect(mockStaticMessage.destroy).toHaveBeenCalled(); + }); + }); + + describe("when a custom instance is set", () => { + const mockInstance = { + success: vi.fn(), + error: vi.fn(), + warning: vi.fn(), + info: vi.fn(), + loading: vi.fn(), + destroy: vi.fn(), + open: vi.fn(), + }; + + beforeEach(() => { + vi.clearAllMocks(); + setMessageInstance(mockInstance as any); + }); + + it("delegates success to custom instance", () => { + MessageManager.success("done!"); + expect(mockInstance.success).toHaveBeenCalledWith("done!", undefined); + expect(mockStaticMessage.success).not.toHaveBeenCalled(); + }); + + it("delegates error with duration to custom instance", () => { + MessageManager.error("failed!", 5); + expect(mockInstance.error).toHaveBeenCalledWith("failed!", 5); + expect(mockStaticMessage.error).not.toHaveBeenCalled(); + }); + + it("delegates warning to custom instance", () => { + MessageManager.warning("watch out"); + expect(mockInstance.warning).toHaveBeenCalledWith("watch out", undefined); + }); + + it("delegates info to custom instance", () => { + MessageManager.info("fyi", 2); + expect(mockInstance.info).toHaveBeenCalledWith("fyi", 2); + }); + + it("delegates loading to custom instance and returns result", () => { + const mockReturn = { then: vi.fn() }; + mockInstance.loading.mockReturnValue(mockReturn); + const result = MessageManager.loading("loading...", 3); + expect(mockInstance.loading).toHaveBeenCalledWith("loading...", 3); + expect(result).toBe(mockReturn); + }); + + it("delegates destroy to custom instance", () => { + MessageManager.destroy(); + expect(mockInstance.destroy).toHaveBeenCalled(); + }); + }); +}); diff --git a/ui/litellm-dashboard/src/components/ui/AntDLoadingSpinner.test.tsx b/ui/litellm-dashboard/src/components/ui/AntDLoadingSpinner.test.tsx new file mode 100644 index 00000000000..e86a7659855 --- /dev/null +++ b/ui/litellm-dashboard/src/components/ui/AntDLoadingSpinner.test.tsx @@ -0,0 +1,61 @@ +import { render, screen } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +// Mock antd Spin component +vi.mock("antd", () => ({ + Spin: ({ indicator, size, ...props }: any) => ( +
+ {indicator} +
+ ), +})); + +// Mock the icon +vi.mock("@ant-design/icons", () => ({ + LoadingOutlined: ({ style, spin, ...props }: any) => ( + + ), +})); + +import { AntDLoadingSpinner } from "./AntDLoadingSpinner"; + +describe("AntDLoadingSpinner", () => { + it("renders without props", () => { + render(); + expect(screen.getByTestId("spin")).toBeInTheDocument(); + expect(screen.getByTestId("loading-icon")).toBeInTheDocument(); + }); + + it("passes size prop to Spin", () => { + render(); + expect(screen.getByTestId("spin")).toHaveAttribute("data-size", "large"); + }); + + it("passes small size to Spin", () => { + render(); + expect(screen.getByTestId("spin")).toHaveAttribute("data-size", "small"); + }); + + it("applies custom fontSize to the icon", () => { + render(); + const icon = screen.getByTestId("loading-icon"); + expect(icon).toHaveStyle({ fontSize: "32px" }); + }); + + it("does not set style when fontSize is not provided", () => { + render(); + const icon = screen.getByTestId("loading-icon"); + expect(icon.style.fontSize).toBe(""); + }); + + it("sets spin attribute on icon", () => { + render(); + const icon = screen.getByTestId("loading-icon"); + expect(icon).toHaveAttribute("data-spin", "true"); + }); +}); From 7e50af922800d731d3a574276c0b942a6ceaabd9 Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Mon, 23 Mar 2026 22:32:26 -0700 Subject: [PATCH 20/37] Migrate route_preview.tsx from Tremor to Ant Design Replace Tremor Card/Title/Subtitle with antd Card/Typography equivalents. --- ui/litellm-dashboard/src/components/route_preview.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ui/litellm-dashboard/src/components/route_preview.tsx b/ui/litellm-dashboard/src/components/route_preview.tsx index 483ab538871..2c616ad8670 100644 --- a/ui/litellm-dashboard/src/components/route_preview.tsx +++ b/ui/litellm-dashboard/src/components/route_preview.tsx @@ -1,6 +1,8 @@ import React from "react"; -import { Card, Title, Subtitle } from "@tremor/react"; +import { Card, Typography } from "antd"; import { RightOutlined, InfoCircleOutlined } from "@ant-design/icons"; + +const { Title, Text } = Typography; import { getProxyBaseUrl } from "./networking"; interface RoutePreviewProps { @@ -23,8 +25,8 @@ const RoutePreview: React.FC = ({ pathValue, targetValue, inc return ( - Route Preview - How your requests will be routed + Route Preview + How your requests will be routed
{/* Basic routing */} From 57c027a2dc01e83ea63a35bffa09d33832869035 Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Mon, 23 Mar 2026 22:46:38 -0700 Subject: [PATCH 21/37] docs: add audit log export to S3 documentation --- docs/my-website/docs/proxy/multiple_admins.md | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/my-website/docs/proxy/multiple_admins.md b/docs/my-website/docs/proxy/multiple_admins.md index 8d39674df19..b3b354126ec 100644 --- a/docs/my-website/docs/proxy/multiple_admins.md +++ b/docs/my-website/docs/proxy/multiple_admins.md @@ -56,6 +56,38 @@ On the LiteLLM UI, navigate to Logs -> Audit Logs. You should see the audit log /> +## Export Audit Logs to External Storage + +You can export audit logs to an external storage backend (e.g. S3) in addition to storing them in the database. Logs are batched and uploaded asynchronously, so they do not block your proxy requests. + +### S3 Example + +Add `audit_log_callbacks` and `s3_callback_params` to your `litellm_settings`: + +```yaml +litellm_settings: + store_audit_logs: true + audit_log_callbacks: ["s3_v2"] + s3_callback_params: + s3_bucket_name: my-audit-logs-bucket # AWS Bucket Name + s3_region_name: us-west-2 # AWS Region + s3_aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID + s3_aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY + s3_path: litellm-audit # [OPTIONAL] prefix path in the bucket +``` + +Audit logs are written as JSON files to: + +``` +s3:////audit_logs//_.json +``` + +:::info + +Both `store_audit_logs: true` and `audit_log_callbacks` must be set. If `store_audit_logs` is not enabled, the callbacks will not fire. + +::: + ## Advanced ### Attribute Management changes to Users From ffbe3896d296aff8ad4b3c9c195cae32bb74b07c Mon Sep 17 00:00:00 2001 From: ryan-crabbe <128659760+ryan-crabbe@users.noreply.github.com> Date: Mon, 23 Mar 2026 22:54:08 -0700 Subject: [PATCH 22/37] Update docs/my-website/docs/proxy/multiple_admins.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- docs/my-website/docs/proxy/multiple_admins.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/my-website/docs/proxy/multiple_admins.md b/docs/my-website/docs/proxy/multiple_admins.md index b3b354126ec..d30065a3539 100644 --- a/docs/my-website/docs/proxy/multiple_admins.md +++ b/docs/my-website/docs/proxy/multiple_admins.md @@ -79,6 +79,8 @@ litellm_settings: Audit logs are written as JSON files to: ``` +s3:///audit_logs//_.json +# or, when s3_path is set: s3:////audit_logs//_.json ``` From fb379865ab1f903d89a023d13aa5e1f1a73c3d85 Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Tue, 24 Mar 2026 09:13:37 -0700 Subject: [PATCH 23/37] fix(security_scans.sh): pin trivvy version --- ci_cd/security_scans.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ci_cd/security_scans.sh b/ci_cd/security_scans.sh index 801b700f64f..e8d1a016e0b 100755 --- a/ci_cd/security_scans.sh +++ b/ci_cd/security_scans.sh @@ -10,13 +10,13 @@ echo "Starting security scans for LiteLLM..." # Function to install Trivy and required tools install_trivy() { echo "Installing Trivy and required tools..." + TRIVY_VERSION="0.69.3" sudo apt-get update - 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 - sudo apt-get install trivy - echo "Trivy and required tools installed successfully" + sudo apt-get install -y wget jq curl bsdmainutils + wget -qO trivy.deb "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.deb" + sudo dpkg -i trivy.deb + rm trivy.deb + echo "Trivy ${TRIVY_VERSION} installed successfully" } # Function to install Grype From f9d29e4e4e33e6b8d2181aa602111170f3c5e427 Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Tue, 24 Mar 2026 11:19:15 -0700 Subject: [PATCH 24/37] fix(security_scans.sh): move to older trivvy version, based on https://github.com/BerriAI/litellm/issues/24518#issuecomment-4120401246 --- ci_cd/security_scans.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci_cd/security_scans.sh b/ci_cd/security_scans.sh index e8d1a016e0b..061e454465a 100755 --- a/ci_cd/security_scans.sh +++ b/ci_cd/security_scans.sh @@ -10,7 +10,7 @@ echo "Starting security scans for LiteLLM..." # Function to install Trivy and required tools install_trivy() { echo "Installing Trivy and required tools..." - TRIVY_VERSION="0.69.3" + TRIVY_VERSION="0.35.0" sudo apt-get update sudo apt-get install -y wget jq curl bsdmainutils wget -qO trivy.deb "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.deb" From eaa025ef7dbd9b7b91e78278a814c32f2afcbc14 Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Tue, 24 Mar 2026 15:44:28 -0700 Subject: [PATCH 25/37] docs: add security update blog post for March 2026 supply chain incident --- .../blog/security_update_march_2026/index.md | 156 ++++++++++++++++++ .../proxy_version.png | Bin 0 -> 405422 bytes 2 files changed, 156 insertions(+) create mode 100644 docs/my-website/blog/security_update_march_2026/index.md create mode 100644 docs/my-website/img/security_update_march_2026/proxy_version.png diff --git a/docs/my-website/blog/security_update_march_2026/index.md b/docs/my-website/blog/security_update_march_2026/index.md new file mode 100644 index 00000000000..2e7188975e2 --- /dev/null +++ b/docs/my-website/blog/security_update_march_2026/index.md @@ -0,0 +1,156 @@ +--- +slug: security-update-march-2026 +title: "Security Update: Suspected Supply Chain Incident" +date: 2026-03-24T14:00:00 +authors: + - krrish + - ishaan-alt +description: "As of 2:00 PM ET on March 24, 2026" +tags: [security, incident-report] +hide_table_of_contents: false +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +> **Status:** Active investigation +> **Last updated:** March 24, 2026, 2:00 PM ET + +LiteLLM is investigating a suspected supply chain attack involving unauthorized PyPI package publishes. Current evidence suggests a maintainer's PyPI account may have been compromised and used to distribute malicious code. + +At this time, we believe this incident may be linked to the broader [Trivy security compromise](https://www.aquasec.com/blog/trivy-supply-chain-attack-what-you-need-to-know/), in which stolen credentials were reportedly used to gain unauthorized access to the LiteLLM publishing pipeline. + +This investigation is ongoing. Details below may change as we confirm additional findings. + +## Confirmed affected versions + +The following LiteLLM versions published to PyPI were impacted: + +- **v1.82.7**: contained a malicious payload in `proxy_server.py` +- **v1.82.8**: contained `litellm_init.pth` and a malicious payload in `proxy_server.py` + +If you installed or ran either of these versions, review the recommendations below immediately. + +Note: These versions have already been removed from PyPI. + +## What happened + +Initial evidence suggests the attacker bypassed official CI/CD workflows and uploaded malicious packages directly to PyPI. + +These compromised versions appear to have included a credential stealer designed to: + +- Harvest secrets by scanning for: + - environment variables + - SSH keys + - cloud provider credentials (AWS, GCP, Azure) + - Kubernetes tokens + - database passwords +- Encrypt and exfiltrate data via a `POST` request to `models.litellm.cloud`, which is **not** an official BerriAI / LiteLLM domain + +## Who is affected + +You may be affected if **any** of the following are true: + +- You installed or upgraded LiteLLM via `pip` on **March 24, 2026**, between **10:39 UTC and 16:00 UTC** +- You ran `pip install litellm` without pinning a version and received **v1.82.7** or **v1.82.8** +- You built a Docker image during this window that included `pip install litellm` without a pinned version +- A dependency in your project pulled in LiteLLM as a transitive, unpinned dependency + (for example through AI agent frameworks, MCP servers, or LLM orchestration tools) + +You are **not** affected if any of the following are true: + +- You are using **LiteLLM Cloud** +- You are using the official Docker image: `ghcr.io/berriai/litellm` +- You are on **v1.82.6 or earlier** and did not upgrade during the affected window +- You installed LiteLLM from source via the GitHub repository, which was **not** compromised + + +### How to check if you are affected + + + + +```bash +pip show litellm +``` + + + +Go to the proxy base url, and check the version of the installed LiteLLM. + +![Proxy version check](../../img/security_update_march_2026/proxy_version.png) + + + + +## Indicators of compromise (IoCs) + +Review affected systems for the following indicators: + +- `litellm_init.pth` present in your `site-packages` +- Outbound traffic or requests to `models.litellm[.]cloud` + This domain is **not** affiliated with LiteLLM + + +## Immediate actions for affected users + +If you installed or ran **v1.82.7** or **v1.82.8**, take the following actions immediately. + +### 1. Rotate all secrets + +Treat any credentials present on the affected systems as compromised, including: + +- API keys +- Cloud access keys +- Database passwords +- SSH keys +- Kubernetes tokens +- Any secrets stored in environment variables or configuration files + +### 2. Inspect your filesystem + +Check your `site-packages` directory for a file named `litellm_init.pth`: + +```bash +find /usr/lib/python3.13/site-packages/ -name "litellm_init.pth" +``` + +If present: + +- remove it immediately +- investigate the host for further compromise +- preserve relevant artifacts if your security team is performing forensics + +### 3. Audit version history + +Review your: + +- local environments +- CI/CD pipelines +- Docker builds +- deployment logs + +Confirm whether **v1.82.7** or **v1.82.8** was installed anywhere. + +Pin LiteLLM to a known safe version such as **v1.82.6 or earlier**, or to a later verified release once announced. + + +## Response and remediation + +The LiteLLM team has already taken the following steps: + +- Removed compromised packages from PyPI +- Rotated maintainer credentials and established new authorized maintainers +- Engaged Google's Mandiant security team to assist with forensic analysis of the build and publishing chain + + +## Questions and support + +If you believe your systems may be affected, contact us immediately: + +- **Security:** `security@berri.ai` +- **Support:** `support@berri.ai` +- **Slack:** Reach out to the LiteLLM team directly + +For real-time updates, follow [LiteLLM (YC W23) on X](https://x.com/LiteLLM). + diff --git a/docs/my-website/img/security_update_march_2026/proxy_version.png b/docs/my-website/img/security_update_march_2026/proxy_version.png new file mode 100644 index 0000000000000000000000000000000000000000..c5d03d6a636749d628b6f692acb85b0e52705e89 GIT binary patch literal 405422 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 z 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 mU`!;bw}dX1Ow~pANY!>872!-SBM3`?uiZ}j9E Date: Tue, 24 Mar 2026 16:54:59 -0700 Subject: [PATCH 26/37] fix: add tldr to blog post --- docs/my-website/blog/security_update_march_2026/index.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/my-website/blog/security_update_march_2026/index.md b/docs/my-website/blog/security_update_march_2026/index.md index 2e7188975e2..941a956876b 100644 --- a/docs/my-website/blog/security_update_march_2026/index.md +++ b/docs/my-website/blog/security_update_march_2026/index.md @@ -16,6 +16,15 @@ import TabItem from '@theme/TabItem'; > **Status:** Active investigation > **Last updated:** March 24, 2026, 2:00 PM ET +## TLDR; +- The compromised PyPI packages were **litellm==1.82.7** and **litellm==1.82.8**. Those packages have now been removed from PyPI. +- We believe that the compromise originated from the Trivy dependency used in our CI/CD security scanning workflow. +- Customers running the official LiteLLM Proxy Docker image were not impacted. That deployment path pins dependencies in requirements.txt and does not rely on the compromised PyPI packages. +- We are pausing new LiteLLM releases until we complete a broader supply-chain review and confirm the release path is safe. + + +## Overview + LiteLLM is investigating a suspected supply chain attack involving unauthorized PyPI package publishes. Current evidence suggests a maintainer's PyPI account may have been compromised and used to distribute malicious code. At this time, we believe this incident may be linked to the broader [Trivy security compromise](https://www.aquasec.com/blog/trivy-supply-chain-attack-what-you-need-to-know/), in which stolen credentials were reportedly used to gain unauthorized access to the LiteLLM publishing pipeline. From f9d1f8cde65b053c44e0aa2002f6869f2b20f186 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Tue, 24 Mar 2026 17:15:44 -0700 Subject: [PATCH 27/37] docs: minor updates to security update blog post --- .../blog/security_update_march_2026/index.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/my-website/blog/security_update_march_2026/index.md b/docs/my-website/blog/security_update_march_2026/index.md index 2e7188975e2..1e1b5509ae0 100644 --- a/docs/my-website/blog/security_update_march_2026/index.md +++ b/docs/my-website/blog/security_update_march_2026/index.md @@ -16,7 +16,7 @@ import TabItem from '@theme/TabItem'; > **Status:** Active investigation > **Last updated:** March 24, 2026, 2:00 PM ET -LiteLLM is investigating a suspected supply chain attack involving unauthorized PyPI package publishes. Current evidence suggests a maintainer's PyPI account may have been compromised and used to distribute malicious code. +LiteLLM AI Gateway is investigating a suspected supply chain attack involving unauthorized PyPI package publishes. Current evidence suggests a maintainer's PyPI account may have been compromised and used to distribute malicious code. At this time, we believe this incident may be linked to the broader [Trivy security compromise](https://www.aquasec.com/blog/trivy-supply-chain-attack-what-you-need-to-know/), in which stolen credentials were reportedly used to gain unauthorized access to the LiteLLM publishing pipeline. @@ -26,8 +26,8 @@ This investigation is ongoing. Details below may change as we confirm additional The following LiteLLM versions published to PyPI were impacted: -- **v1.82.7**: contained a malicious payload in `proxy_server.py` -- **v1.82.8**: contained `litellm_init.pth` and a malicious payload in `proxy_server.py` +- **v1.82.7**: contained a malicious payload in the LiteLLM AI Gateway `proxy_server.py` +- **v1.82.8**: contained `litellm_init.pth` and a malicious payload in the LiteLLM AI Gateway `proxy_server.py` If you installed or ran either of these versions, review the recommendations below immediately. @@ -59,8 +59,10 @@ You may be affected if **any** of the following are true: You are **not** affected if any of the following are true: +**LiteLLM AI Gateway/Proxy users:** Customers running the official LiteLLM Proxy Docker image were not impacted. That deployment path pins dependencies in requirements.txt and does not rely on the compromised PyPI packages. + - You are using **LiteLLM Cloud** -- You are using the official Docker image: `ghcr.io/berriai/litellm` +- You are using the official LiteLLM AI Gateway Docker image: `ghcr.io/berriai/litellm` - You are on **v1.82.6 or earlier** and did not upgrade during the affected window - You installed LiteLLM from source via the GitHub repository, which was **not** compromised @@ -125,10 +127,10 @@ If present: Review your: -- local environments +- Local environments - CI/CD pipelines - Docker builds -- deployment logs +- Deployment logs Confirm whether **v1.82.7** or **v1.82.8** was installed anywhere. @@ -137,7 +139,7 @@ Pin LiteLLM to a known safe version such as **v1.82.6 or earlier**, or to a late ## Response and remediation -The LiteLLM team has already taken the following steps: +The LiteLLM AI Gateway team has already taken the following steps: - Removed compromised packages from PyPI - Rotated maintainer credentials and established new authorized maintainers From 3d5b1ecb3b996dd78e92bc37a5acf829389cbaa3 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Tue, 24 Mar 2026 17:59:07 -0700 Subject: [PATCH 28/37] ci: remove publish-migrations and reset_stable workflows --- .github/workflows/publish-migrations.yml | 207 ----------------------- .github/workflows/reset_stable.yml | 39 ----- 2 files changed, 246 deletions(-) delete mode 100644 .github/workflows/publish-migrations.yml delete mode 100644 .github/workflows/reset_stable.yml diff --git a/.github/workflows/publish-migrations.yml b/.github/workflows/publish-migrations.yml deleted file mode 100644 index a5187cb2f55..00000000000 --- a/.github/workflows/publish-migrations.yml +++ /dev/null @@ -1,207 +0,0 @@ -name: Publish Prisma Migrations - -permissions: - contents: write - pull-requests: write - -on: - push: - paths: - - 'schema.prisma' # Check root schema.prisma - branches: - - main - -jobs: - publish-migrations: - if: github.repository == 'BerriAI/litellm' - runs-on: ubuntu-latest - services: - postgres: - image: postgres:14 - env: - POSTGRES_DB: temp_db - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - ports: - - 5432:5432 - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - # Add shadow database service - postgres_shadow: - image: postgres:14 - env: - POSTGRES_DB: shadow_db - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - ports: - - 5433:5432 - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - steps: - - uses: actions/checkout@v3 - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.x' - - - name: Install Dependencies - run: | - pip install prisma - pip install python-dotenv - - - name: Generate Initial Migration if None Exists - env: - DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/temp_db" - DIRECT_URL: "postgresql://postgres:postgres@localhost:5432/temp_db" - SHADOW_DATABASE_URL: "postgresql://postgres:postgres@localhost:5433/shadow_db" - run: | - mkdir -p deploy/migrations - echo 'provider = "postgresql"' > deploy/migrations/migration_lock.toml - - if [ -z "$(ls -A deploy/migrations/2* 2>/dev/null)" ]; then - echo "No existing migrations found, creating baseline..." - VERSION=$(date +%Y%m%d%H%M%S) - mkdir -p deploy/migrations/${VERSION}_initial - - echo "Generating initial migration..." - # Save raw output for debugging - prisma migrate diff \ - --from-empty \ - --to-schema-datamodel schema.prisma \ - --shadow-database-url "${SHADOW_DATABASE_URL}" \ - --script > deploy/migrations/${VERSION}_initial/raw_migration.sql - - echo "Raw migration file content:" - cat deploy/migrations/${VERSION}_initial/raw_migration.sql - - echo "Cleaning migration file..." - # Clean the file - sed '/^Installing/d' deploy/migrations/${VERSION}_initial/raw_migration.sql > deploy/migrations/${VERSION}_initial/migration.sql - - # Verify the migration file - if [ ! -s deploy/migrations/${VERSION}_initial/migration.sql ]; then - echo "ERROR: Migration file is empty after cleaning" - echo "Original content was:" - cat deploy/migrations/${VERSION}_initial/raw_migration.sql - exit 1 - fi - - echo "Final migration file content:" - cat deploy/migrations/${VERSION}_initial/migration.sql - - # Verify it starts with SQL - if ! head -n 1 deploy/migrations/${VERSION}_initial/migration.sql | grep -q "^--\|^CREATE\|^ALTER"; then - echo "ERROR: Migration file does not start with SQL command or comment" - echo "First line is:" - head -n 1 deploy/migrations/${VERSION}_initial/migration.sql - echo "Full content is:" - cat deploy/migrations/${VERSION}_initial/migration.sql - exit 1 - fi - - echo "Initial migration generated at $(date -u)" > deploy/migrations/${VERSION}_initial/README.md - fi - - - name: Compare and Generate Migration - if: success() - env: - DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/temp_db" - DIRECT_URL: "postgresql://postgres:postgres@localhost:5432/temp_db" - SHADOW_DATABASE_URL: "postgresql://postgres:postgres@localhost:5433/shadow_db" - run: | - # Create temporary migration workspace - mkdir -p temp_migrations - - # Copy existing migrations (will not fail if directory is empty) - cp -r deploy/migrations/* temp_migrations/ 2>/dev/null || true - - VERSION=$(date +%Y%m%d%H%M%S) - - # Generate diff against existing migrations or empty state - prisma migrate diff \ - --from-migrations temp_migrations \ - --to-schema-datamodel schema.prisma \ - --shadow-database-url "${SHADOW_DATABASE_URL}" \ - --script > temp_migrations/migration_${VERSION}.sql - - # Check if there are actual changes - if [ -s temp_migrations/migration_${VERSION}.sql ]; then - echo "Changes detected, creating new migration" - mkdir -p deploy/migrations/${VERSION}_schema_update - mv temp_migrations/migration_${VERSION}.sql deploy/migrations/${VERSION}_schema_update/migration.sql - echo "Migration generated at $(date -u)" > deploy/migrations/${VERSION}_schema_update/README.md - else - echo "No schema changes detected" - exit 0 - fi - - - name: Verify Migration - if: success() - env: - DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/temp_db" - DIRECT_URL: "postgresql://postgres:postgres@localhost:5432/temp_db" - SHADOW_DATABASE_URL: "postgresql://postgres:postgres@localhost:5433/shadow_db" - run: | - # Create test database - psql "${SHADOW_DATABASE_URL}" -c 'CREATE DATABASE migration_test;' - - # Apply all migrations in order to verify - for migration in deploy/migrations/*/migration.sql; do - echo "Applying migration: $migration" - psql "${SHADOW_DATABASE_URL}" -f $migration - done - - # Add this step before create-pull-request to debug permissions - - name: Check Token Permissions - run: | - echo "Checking token permissions..." - curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ - -H "Accept: application/vnd.github.v3+json" \ - https://api.github.com/repos/BerriAI/litellm/collaborators - - echo "\nChecking if token can create PRs..." - curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ - -H "Accept: application/vnd.github.v3+json" \ - https://api.github.com/repos/BerriAI/litellm - - # Add this debug step before git push - - name: Debug Changed Files - run: | - echo "Files staged for commit:" - git diff --name-status --staged - - echo "\nAll changed files:" - git status - - - name: Create Pull Request - if: success() - uses: peter-evans/create-pull-request@v5 - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: "chore: update prisma migrations" - title: "Update Prisma Migrations" - body: | - Auto-generated migration based on schema.prisma changes. - - Generated files: - - deploy/migrations/${VERSION}_schema_update/migration.sql - - deploy/migrations/${VERSION}_schema_update/README.md - branch: feat/prisma-migration-${{ env.VERSION }} - base: main - delete-branch: true - - - name: Generate and Save Migrations - run: | - # Only add migration files - git add deploy/migrations/ - git status # Debug what's being committed - git commit -m "chore: update prisma migrations" diff --git a/.github/workflows/reset_stable.yml b/.github/workflows/reset_stable.yml deleted file mode 100644 index f6fed672d47..00000000000 --- a/.github/workflows/reset_stable.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Reset litellm_stable branch - -on: - release: - types: [published, created] -jobs: - update-stable-branch: - if: ${{ startsWith(github.event.release.tag_name, 'v') && !endsWith(github.event.release.tag_name, '-stable') }} - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Reset litellm_stable_release_branch branch to the release commit - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # Configure Git user - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - # Fetch all branches and tags - git fetch --all - - # Check if the litellm_stable_release_branch branch exists - if git show-ref --verify --quiet refs/remotes/origin/litellm_stable_release_branch; then - echo "litellm_stable_release_branch branch exists." - git checkout litellm_stable_release_branch - else - echo "litellm_stable_release_branch branch does not exist. Creating it." - git checkout -b litellm_stable_release_branch - fi - - # Reset litellm_stable_release_branch branch to the release commit - git reset --hard $GITHUB_SHA - - # Push the updated litellm_stable_release_branch branch - git push origin litellm_stable_release_branch --force From 3e8a6f24b77782d014282bb30df9098df8f3a68d Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Tue, 24 Mar 2026 18:03:04 -0700 Subject: [PATCH 29/37] ci: remove all publish/deploy workflows as part of supply chain incident response --- .github/workflows/ghcr_deploy.yml | 444 --------------------- .github/workflows/ghcr_helm_deploy.yml | 67 ---- .github/workflows/main.yml | 34 -- .github/workflows/publish_enterprise.yml | 94 ----- .github/workflows/publish_proxy_extras.yml | 74 ---- .github/workflows/simple_pypi_publish.yml | 67 ---- 6 files changed, 780 deletions(-) delete mode 100644 .github/workflows/ghcr_deploy.yml delete mode 100644 .github/workflows/ghcr_helm_deploy.yml delete mode 100644 .github/workflows/main.yml delete mode 100644 .github/workflows/publish_enterprise.yml delete mode 100644 .github/workflows/publish_proxy_extras.yml delete mode 100644 .github/workflows/simple_pypi_publish.yml diff --git a/.github/workflows/ghcr_deploy.yml b/.github/workflows/ghcr_deploy.yml deleted file mode 100644 index 344b0ec48ee..00000000000 --- a/.github/workflows/ghcr_deploy.yml +++ /dev/null @@ -1,444 +0,0 @@ -# this workflow is triggered by an API call when there is a new PyPI release of LiteLLM -name: Build, Publish LiteLLM Docker Image. New Release -on: - workflow_dispatch: - inputs: - tag: - description: "The tag version you want to build" - required: true - release_type: - description: "The release type you want to build. Can be 'latest', 'stable', 'dev', 'rc'" - type: string - default: "latest" - commit_hash: - description: "Commit hash" - required: true - -# Defines two custom environment variables for the workflow. Used for the Container registry domain, and a name for the Docker image that this workflow builds. -env: - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }} - CHART_NAME: litellm-helm - -# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. -jobs: - # print commit hash, tag, and release type - print: - runs-on: ubuntu-latest - steps: - - run: | - echo "Commit hash: ${{ github.event.inputs.commit_hash }}" - echo "Tag: ${{ github.event.inputs.tag }}" - echo "Release type: ${{ github.event.inputs.release_type }}" - docker-hub-deploy: - if: github.repository == 'BerriAI/litellm' - runs-on: ubuntu-latest - steps: - - - name: Checkout - uses: actions/checkout@v4 - with: - ref: ${{ github.event.inputs.commit_hash }} - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v5 - with: - context: . - push: true - tags: litellm/litellm:${{ github.event.inputs.tag || 'latest' }} - - - name: Build and push litellm-database image - uses: docker/build-push-action@v5 - with: - context: . - push: true - file: ./docker/Dockerfile.database - tags: litellm/litellm-database:${{ github.event.inputs.tag || 'latest' }} - - - name: Build and push litellm-spend-logs image - uses: docker/build-push-action@v5 - with: - context: . - push: true - file: ./litellm-js/spend-logs/Dockerfile - tags: litellm/litellm-spend_logs:${{ github.event.inputs.tag || 'latest' }} - - - name: Build and push litellm-non_root image - uses: docker/build-push-action@v5 - with: - context: . - push: true - file: ./docker/Dockerfile.non_root - tags: litellm/litellm-non_root:${{ github.event.inputs.tag || 'latest' }} - build-and-push-image: - runs-on: ubuntu-latest - # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job. - permissions: - contents: read - packages: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - ref: ${{ github.event.inputs.commit_hash }} - # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. - - name: Log in to the Container registry - uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - # Configure multi platform Docker builds - - name: Set up QEMU - uses: docker/setup-qemu-action@e0e4588fad221d38ee467c0bffd91115366dc0c5 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@edfb0fe6204400c56fbfd3feba3fe9ad1adfa345 - # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. - # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. - # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. - - name: Build and push Docker image - uses: docker/build-push-action@4976231911ebf5f32aad765192d35f942aa48cb8 - with: - context: . - push: true - tags: | - ${{ steps.meta.outputs.tags }}-${{ github.event.inputs.tag || 'latest' }}, - ${{ steps.meta.outputs.tags }}-${{ github.event.inputs.release_type }} - ${{ (github.event.inputs.release_type == 'stable' || github.event.inputs.release_type == 'rc') && format('{0}/berriai/litellm:main-{1}', env.REGISTRY, github.event.inputs.tag) || '' }}, - ${{ github.event.inputs.release_type == 'stable' && format('{0}/berriai/litellm:main-stable', env.REGISTRY) || '' }}, - ${{ (github.event.inputs.release_type == 'stable' || github.event.inputs.release_type == 'rc') && format('{0}/berriai/litellm:{1}', env.REGISTRY, github.event.inputs.tag) || '' }}, - labels: ${{ steps.meta.outputs.labels }} - platforms: local,linux/amd64,linux/arm64,linux/arm64/v8 - - build-and-push-image-ee: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - ref: ${{ github.event.inputs.commit_hash }} - - - name: Log in to the Container registry - uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata (tags, labels) for EE Dockerfile - id: meta-ee - uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee - # Configure multi platform Docker builds - - name: Set up QEMU - uses: docker/setup-qemu-action@e0e4588fad221d38ee467c0bffd91115366dc0c5 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@edfb0fe6204400c56fbfd3feba3fe9ad1adfa345 - - - name: Build and push EE Docker image - uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 - with: - context: . - file: Dockerfile - push: true - tags: | - ${{ steps.meta-ee.outputs.tags }}-${{ github.event.inputs.tag || 'latest' }}, - ${{ steps.meta-ee.outputs.tags }}-${{ github.event.inputs.release_type }} - ${{ (github.event.inputs.release_type == 'stable' || github.event.inputs.release_type == 'rc') && format('{0}/berriai/litellm-ee:main-{1}', env.REGISTRY, github.event.inputs.tag) || '' }}, - ${{ github.event.inputs.release_type == 'stable' && format('{0}/berriai/litellm-ee:main-stable', env.REGISTRY) || '' }} - labels: ${{ steps.meta-ee.outputs.labels }} - platforms: local,linux/amd64,linux/arm64,linux/arm64/v8 - - build-and-push-image-database: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - ref: ${{ github.event.inputs.commit_hash }} - - - name: Log in to the Container registry - uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata (tags, labels) for database Dockerfile - id: meta-database - uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-database - # Configure multi platform Docker builds - - name: Set up QEMU - uses: docker/setup-qemu-action@e0e4588fad221d38ee467c0bffd91115366dc0c5 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@edfb0fe6204400c56fbfd3feba3fe9ad1adfa345 - - - name: Build and push Database Docker image - uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 - with: - context: . - file: ./docker/Dockerfile.database - push: true - tags: | - ${{ steps.meta-database.outputs.tags }}-${{ github.event.inputs.tag || 'latest' }}, - ${{ steps.meta-database.outputs.tags }}-${{ github.event.inputs.release_type }} - ${{ (github.event.inputs.release_type == 'stable' || github.event.inputs.release_type == 'rc') && format('{0}/berriai/litellm-database:main-{1}', env.REGISTRY, github.event.inputs.tag) || '' }}, - ${{ github.event.inputs.release_type == 'stable' && format('{0}/berriai/litellm-database:main-stable', env.REGISTRY) || '' }} - labels: ${{ steps.meta-database.outputs.labels }} - platforms: local,linux/amd64,linux/arm64,linux/arm64/v8 - - build-and-push-image-non_root: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - ref: ${{ github.event.inputs.commit_hash }} - - - name: Log in to the Container registry - uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata (tags, labels) for non_root Dockerfile - id: meta-non_root - uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-non_root - # Configure multi platform Docker builds - - name: Set up QEMU - uses: docker/setup-qemu-action@e0e4588fad221d38ee467c0bffd91115366dc0c5 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@edfb0fe6204400c56fbfd3feba3fe9ad1adfa345 - - - name: Build and push non_root Docker image - uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 - with: - context: . - file: ./docker/Dockerfile.non_root - push: true - tags: | - ${{ steps.meta-non_root.outputs.tags }}-${{ github.event.inputs.tag || 'latest' }}, - ${{ steps.meta-non_root.outputs.tags }}-${{ github.event.inputs.release_type }} - ${{ (github.event.inputs.release_type == 'stable' || github.event.inputs.release_type == 'rc') && format('{0}/berriai/litellm-non_root:main-{1}', env.REGISTRY, github.event.inputs.tag) || '' }}, - ${{ github.event.inputs.release_type == 'stable' && format('{0}/berriai/litellm-non_root:main-stable', env.REGISTRY) || '' }} - labels: ${{ steps.meta-non_root.outputs.labels }} - platforms: local,linux/amd64,linux/arm64,linux/arm64/v8 - - build-and-push-image-spend-logs: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - ref: ${{ github.event.inputs.commit_hash }} - - - name: Log in to the Container registry - uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata (tags, labels) for spend-logs Dockerfile - id: meta-spend-logs - uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-spend_logs - # Configure multi platform Docker builds - - name: Set up QEMU - uses: docker/setup-qemu-action@e0e4588fad221d38ee467c0bffd91115366dc0c5 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@edfb0fe6204400c56fbfd3feba3fe9ad1adfa345 - - - name: Build and push Database Docker image - uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 - with: - context: . - file: ./litellm-js/spend-logs/Dockerfile - push: true - tags: | - ${{ steps.meta-spend-logs.outputs.tags }}-${{ github.event.inputs.tag || 'latest' }}, - ${{ steps.meta-spend-logs.outputs.tags }}-${{ github.event.inputs.release_type }} - ${{ (github.event.inputs.release_type == 'stable' || github.event.inputs.release_type == 'rc') && format('{0}/berriai/litellm-spend_logs:main-{1}', env.REGISTRY, github.event.inputs.tag) || '' }}, - ${{ github.event.inputs.release_type == 'stable' && format('{0}/berriai/litellm-spend_logs:main-stable', env.REGISTRY) || '' }} - platforms: local,linux/amd64,linux/arm64,linux/arm64/v8 - - run-observatory-tests: - if: github.event.inputs.release_type == 'rc' || github.event.inputs.release_type == 'stable' - needs: [docker-hub-deploy] - uses: ./.github/workflows/run_observatory_tests.yml - with: - tag: ${{ github.event.inputs.tag }} - commit_hash: ${{ github.event.inputs.commit_hash }} - secrets: inherit - - build-and-push-helm-chart: - if: github.event.inputs.release_type != 'dev' - needs: [docker-hub-deploy, build-and-push-image, build-and-push-image-database] - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Log in to the Container registry - uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: lowercase github.repository_owner - run: | - echo "REPO_OWNER=`echo ${{github.repository_owner}} | tr '[:upper:]' '[:lower:]'`" >>${GITHUB_ENV} - - # Sync Helm chart version with LiteLLM release version (1-1 versioning) - # This allows users to easily map Helm chart versions to LiteLLM versions - # See: https://codefresh.io/docs/docs/ci-cd-guides/helm-best-practices/ - - name: Calculate chart and app versions - id: chart_version - shell: bash - run: | - INPUT_TAG="${{ github.event.inputs.tag }}" - RELEASE_TYPE="${{ github.event.inputs.release_type }}" - - # Chart version = LiteLLM version without 'v' prefix (Helm semver convention) - # v1.81.0 -> 1.81.0, v1.81.0.rc.1 -> 1.81.0.rc.1 - CHART_VERSION="${INPUT_TAG#v}" - - # Add suffix for 'latest' releases (rc already has suffix in tag) - if [ "$RELEASE_TYPE" = "latest" ]; then - CHART_VERSION="${CHART_VERSION}-latest" - fi - - # App version = Docker tag (keeps 'v' prefix to match Docker image tags) - APP_VERSION="${INPUT_TAG}" - - echo "version=${CHART_VERSION}" | tee -a $GITHUB_OUTPUT - echo "app_version=${APP_VERSION}" | tee -a $GITHUB_OUTPUT - - - uses: ./.github/actions/helm-oci-chart-releaser - with: - name: ${{ env.CHART_NAME }} - repository: ${{ env.REPO_OWNER }} - tag: ${{ steps.chart_version.outputs.version }} - app_version: ${{ steps.chart_version.outputs.app_version }} - path: deploy/charts/${{ env.CHART_NAME }} - registry: ${{ env.REGISTRY }} - registry_username: ${{ github.actor }} - registry_password: ${{ secrets.GITHUB_TOKEN }} - update_dependencies: true - - 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: - - name: Display version - run: echo "Current version is ${{ github.event.inputs.tag }}" - - name: "Set Release Tag" - run: echo "RELEASE_TAG=${{ github.event.inputs.tag }}" >> $GITHUB_ENV - - name: Display release tag - run: echo "RELEASE_TAG is $RELEASE_TAG" - - name: "Create release" - uses: "actions/github-script@v6" - with: - github-token: "${{ secrets.GITHUB_TOKEN }}" - script: | - const commitHash = "${{ github.event.inputs.commit_hash}}"; - console.log("Commit Hash:", commitHash); // Add this line for debugging - try { - const response = await github.rest.repos.createRelease({ - draft: false, - generate_release_notes: true, - target_commitish: commitHash, - name: process.env.RELEASE_TAG, - owner: context.repo.owner, - prerelease: false, - repo: context.repo.repo, - tag_name: process.env.RELEASE_TAG, - }); - - core.exportVariable('RELEASE_ID', response.data.id); - core.exportVariable('RELEASE_UPLOAD_URL', response.data.upload_url); - } catch (error) { - core.setFailed(error.message); - } - - name: Fetch Release Notes - id: release-notes - uses: actions/github-script@v6 - with: - github-token: "${{ secrets.GITHUB_TOKEN }}" - script: | - try { - const response = await github.rest.repos.getRelease({ - owner: context.repo.owner, - repo: context.repo.repo, - release_id: process.env.RELEASE_ID, - }); - const formattedBody = JSON.stringify(response.data.body).slice(1, -1); - return formattedBody; - } catch (error) { - core.setFailed(error.message); - } - env: - RELEASE_ID: ${{ env.RELEASE_ID }} - - name: Github Releases To Discord - env: - WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }} - REALEASE_TAG: ${{ env.RELEASE_TAG }} - RELEASE_NOTES: ${{ steps.release-notes.outputs.result }} - run: | - curl -H "Content-Type: application/json" -X POST -d '{ - "content": "New LiteLLM release '"${RELEASE_TAG}"'", - "username": "Release Changelog", - "avatar_url": "https://cdn.discordapp.com/avatars/487431320314576937/bd64361e4ba6313d561d54e78c9e7171.png", - "embeds": [ - { - "title": "Changelog for LiteLLM '"${RELEASE_TAG}"'", - "description": "'"${RELEASE_NOTES}"'", - "color": 2105893 - } - ] - }' $WEBHOOK_URL - diff --git a/.github/workflows/ghcr_helm_deploy.yml b/.github/workflows/ghcr_helm_deploy.yml deleted file mode 100644 index 21b2eaafe19..00000000000 --- a/.github/workflows/ghcr_helm_deploy.yml +++ /dev/null @@ -1,67 +0,0 @@ -# Standalone workflow to publish LiteLLM Helm Chart -# Note: The main ghcr_deploy.yml workflow also publishes the Helm chart as part of a full release -name: Build, Publish LiteLLM Helm Chart. New Release -on: - workflow_dispatch: - inputs: - tag: - description: "LiteLLM version tag (e.g., v1.81.0)" - required: true - -# Defines two custom environment variables for the workflow. Used for the Container registry domain, and a name for the Docker image that this workflow builds. -env: - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }} - REPO_OWNER: ${{github.repository_owner}} - -# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. -jobs: - build-and-push-helm-chart: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Log in to the Container registry - uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: lowercase github.repository_owner - run: | - echo "REPO_OWNER=`echo ${{github.repository_owner}} | tr '[:upper:]' '[:lower:]'`" >>${GITHUB_ENV} - - # Sync Helm chart version with LiteLLM release version (1-1 versioning) - - name: Calculate chart and app versions - id: chart_version - shell: bash - run: | - INPUT_TAG="${{ github.event.inputs.tag }}" - - # Chart version = LiteLLM version without 'v' prefix - # v1.81.0 -> 1.81.0 - CHART_VERSION="${INPUT_TAG#v}" - - # App version = Docker tag (keeps 'v' prefix) - APP_VERSION="${INPUT_TAG}" - - echo "version=${CHART_VERSION}" | tee -a $GITHUB_OUTPUT - echo "app_version=${APP_VERSION}" | tee -a $GITHUB_OUTPUT - - - name: Lint helm chart - run: helm lint deploy/charts/litellm-helm - - - uses: ./.github/actions/helm-oci-chart-releaser - with: - name: litellm-helm - repository: ${{ env.REPO_OWNER }} - tag: ${{ steps.chart_version.outputs.version }} - app_version: ${{ steps.chart_version.outputs.app_version }} - path: deploy/charts/litellm-helm - registry: ${{ env.REGISTRY }} - registry_username: ${{ github.actor }} - registry_password: ${{ secrets.GITHUB_TOKEN }} - update_dependencies: true - diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 23e4a06da9e..00000000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Publish Dev Release to PyPI - -on: - workflow_dispatch: - -jobs: - publish-dev-release: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: 3.8 # Adjust the Python version as needed - - - name: Install dependencies - run: pip install toml twine - - - name: Read version from pyproject.toml - id: read-version - run: | - version=$(python -c 'import toml; print(toml.load("pyproject.toml")["tool"]["commitizen"]["version"])') - printf "LITELLM_VERSION=%s" "$version" >> $GITHUB_ENV - - - name: Check if version exists on PyPI - id: check-version - run: | - set -e - if twine check --repository-url https://pypi.org/simple/ "litellm==$LITELLM_VERSION" >/dev/null 2>&1; then - echo "Version $LITELLM_VERSION already exists on PyPI. Skipping publish." - diff --git a/.github/workflows/publish_enterprise.yml b/.github/workflows/publish_enterprise.yml deleted file mode 100644 index 459a233cb71..00000000000 --- a/.github/workflows/publish_enterprise.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: Publish litellm-enterprise to PyPI - -on: - workflow_dispatch: - inputs: - bump: - description: "Version bump type" - required: true - default: "patch" - type: choice - options: - - patch - - minor - - major - -jobs: - publish: - runs-on: ubuntu-latest - if: github.repository == 'BerriAI/litellm' - permissions: - contents: write - pull-requests: write - defaults: - run: - working-directory: enterprise - - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Install Poetry - run: pip install poetry - - - name: Bump version - id: bump - run: | - OLD=$(poetry version -s) - poetry version ${{ github.event.inputs.bump }} - NEW=$(poetry version -s) - echo "old=$OLD" >> $GITHUB_OUTPUT - echo "new=$NEW" >> $GITHUB_OUTPUT - - - name: Update version refs in root pyproject.toml and requirements.txt - run: | - OLD=${{ steps.bump.outputs.old }} - NEW=${{ steps.bump.outputs.new }} - sed -i "s/litellm-enterprise = {version = \"${OLD}\"/litellm-enterprise = {version = \"${NEW}\"/" ../pyproject.toml - sed -i "s/litellm-enterprise==${OLD}/litellm-enterprise==${NEW}/" ../requirements.txt - - - name: Update poetry.lock - working-directory: . - run: poetry lock - - - name: Build - run: poetry build - - - name: Commit version bump and create PR - id: create-pr - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - cd .. - BRANCH="bump/enterprise-${{ steps.bump.outputs.new }}" - git checkout -b "$BRANCH" - git add enterprise/pyproject.toml pyproject.toml requirements.txt poetry.lock - git commit -m "bump: litellm-enterprise ${{ steps.bump.outputs.old }} β†’ ${{ steps.bump.outputs.new }}" - git push origin "$BRANCH" --force - gh pr create \ - --title "bump: litellm-enterprise ${{ steps.bump.outputs.old }} β†’ ${{ steps.bump.outputs.new }}" \ - --body "Version bump for litellm-enterprise. Merge to update main." \ - --head "$BRANCH" \ - --base main \ - || true - PR_URL=$(gh pr list --head "$BRANCH" --json url -q '.[0].url') - echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT - env: - GH_TOKEN: ${{ github.token }} - - - name: Enable auto-merge - run: | - gh pr merge "${{ steps.create-pr.outputs.pr_url }}" --auto --squash - env: - GH_TOKEN: ${{ github.token }} - - - name: Publish to PyPI - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_ENTERPRISE }} - run: | - pip install twine - twine upload dist/litellm_enterprise-${{ steps.bump.outputs.new }}* diff --git a/.github/workflows/publish_proxy_extras.yml b/.github/workflows/publish_proxy_extras.yml deleted file mode 100644 index fa30b153163..00000000000 --- a/.github/workflows/publish_proxy_extras.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Publish litellm-proxy-extras to PyPI - -on: - workflow_dispatch: - inputs: - bump: - description: "Version bump type" - required: true - default: "patch" - type: choice - options: - - patch - - minor - - major - -jobs: - publish: - runs-on: ubuntu-latest - if: github.repository == 'BerriAI/litellm' - permissions: - contents: write - defaults: - run: - working-directory: litellm-proxy-extras - - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Install Poetry - run: pip install poetry - - - name: Bump version - id: bump - run: | - OLD=$(poetry version -s) - poetry version ${{ github.event.inputs.bump }} - NEW=$(poetry version -s) - echo "old=$OLD" >> $GITHUB_OUTPUT - echo "new=$NEW" >> $GITHUB_OUTPUT - - - name: Update version refs in root pyproject.toml and requirements.txt - run: | - OLD=${{ steps.bump.outputs.old }} - NEW=${{ steps.bump.outputs.new }} - sed -i "s/litellm-proxy-extras = {version = \"${OLD}\"/litellm-proxy-extras = {version = \"${NEW}\"/" ../pyproject.toml - sed -i "s/litellm-proxy-extras==${OLD}/litellm-proxy-extras==${NEW}/" ../requirements.txt - - - name: Update poetry.lock - working-directory: . - run: poetry lock - - - name: Build - run: poetry build - - - name: Commit version bump - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - cd .. - git add litellm-proxy-extras/pyproject.toml pyproject.toml requirements.txt poetry.lock - git commit -m "bump: litellm-proxy-extras ${{ steps.bump.outputs.old }} β†’ ${{ steps.bump.outputs.new }}" - git push - - - name: Publish to PyPI - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_PUBLISH_PASSWORD }} - run: | - pip install twine - twine upload dist/litellm_proxy_extras-${{ steps.bump.outputs.new }}* diff --git a/.github/workflows/simple_pypi_publish.yml b/.github/workflows/simple_pypi_publish.yml deleted file mode 100644 index e1830556819..00000000000 --- a/.github/workflows/simple_pypi_publish.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Simple PyPI Publish - -on: - workflow_dispatch: - inputs: - version: - description: 'Version to publish (e.g., 1.74.10)' - required: true - type: string - -env: - TWINE_USERNAME: __token__ - -jobs: - publish: - runs-on: ubuntu-latest - if: github.repository == 'BerriAI/litellm' - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.8' - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install toml build wheel twine - - - name: Update version in pyproject.toml - run: | - python -c " - import toml - - with open('pyproject.toml', 'r') as f: - data = toml.load(f) - - data['tool']['poetry']['version'] = '${{ github.event.inputs.version }}' - - with open('pyproject.toml', 'w') as f: - toml.dump(data, f) - - print(f'Updated version to ${{ github.event.inputs.version }}') - " - - - name: Copy model prices file - run: | - cp model_prices_and_context_window.json litellm/model_prices_and_context_window_backup.json - - - name: Build package - run: | - rm -rf build dist - python -m build - - - name: Publish to PyPI - env: - TWINE_PASSWORD: ${{ secrets.PYPI_PUBLISH_PASSWORD }} - run: | - twine upload dist/* - - - name: Output success - run: | - echo "βœ… Successfully published litellm v${{ github.event.inputs.version }} to PyPI" - echo "πŸ“¦ Package: https://pypi.org/project/litellm/${{ github.event.inputs.version }}/" \ No newline at end of file From 10a48f7655225b0dc765d5521839a8bf621805d9 Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Tue, 24 Mar 2026 19:43:13 -0700 Subject: [PATCH 30/37] docs: add tldr --- .../blog/security_update_march_2026/index.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/my-website/blog/security_update_march_2026/index.md b/docs/my-website/blog/security_update_march_2026/index.md index 1e1b5509ae0..20cf5e8f3ff 100644 --- a/docs/my-website/blog/security_update_march_2026/index.md +++ b/docs/my-website/blog/security_update_march_2026/index.md @@ -16,6 +16,16 @@ import TabItem from '@theme/TabItem'; > **Status:** Active investigation > **Last updated:** March 24, 2026, 2:00 PM ET + +## TLDR; +- The compromised PyPI packages were **litellm==1.82.7** and **litellm==1.82.8**. Those packages have now been removed from PyPI. +- We believe that the compromise originated from the Trivy dependency used in our CI/CD security scanning workflow. +- Customers running the official LiteLLM Proxy Docker image were not impacted. That deployment path pins dependencies in requirements.txt and does not rely on the compromised PyPI packages. +- We are pausing new LiteLLM releases until we complete a broader supply-chain review and confirm the release path is safe. + + +## Overview + LiteLLM AI Gateway is investigating a suspected supply chain attack involving unauthorized PyPI package publishes. Current evidence suggests a maintainer's PyPI account may have been compromised and used to distribute malicious code. At this time, we believe this incident may be linked to the broader [Trivy security compromise](https://www.aquasec.com/blog/trivy-supply-chain-attack-what-you-need-to-know/), in which stolen credentials were reportedly used to gain unauthorized access to the LiteLLM publishing pipeline. From 7d7045cbc1a2c77831062084b5c1071df7d4a0b1 Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Wed, 25 Mar 2026 09:20:25 -0700 Subject: [PATCH 31/37] fix: cleanup --- docs/my-website/docs/data_security.md | 2 -- docs/my-website/docs/debugging/local_debugging.md | 2 +- docs/my-website/docs/migration.md | 3 +-- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/my-website/docs/data_security.md b/docs/my-website/docs/data_security.md index 2c4b1247e2b..d93d17aa0de 100644 --- a/docs/my-website/docs/data_security.md +++ b/docs/my-website/docs/data_security.md @@ -128,8 +128,6 @@ We'll review all reports promptly. Note that we don't currently offer a bug boun Legal Entity Name: Berrie AI Incorporated -Company Phone Number: 7708783106 - Point of contact email address for security incidents: krrish@berri.ai Point of contact email address for general security-related questions: krrish@berri.ai diff --git a/docs/my-website/docs/debugging/local_debugging.md b/docs/my-website/docs/debugging/local_debugging.md index 8a56d6c34a0..53daa4e366b 100644 --- a/docs/my-website/docs/debugging/local_debugging.md +++ b/docs/my-website/docs/debugging/local_debugging.md @@ -67,6 +67,6 @@ response = completion("command-nightly", messages, logger_fn=my_custom_logging_f ## Still Seeing Issues? -Text us @ +17708783106 or Join the [Discord](https://discord.com/invite/wuPM9dRgDw). +Join the [Discord](https://discord.com/invite/wuPM9dRgDw). We promise to help you in `lite`ning speed ❀️ diff --git a/docs/my-website/docs/migration.md b/docs/my-website/docs/migration.md index e1af07d4684..fda1155905d 100644 --- a/docs/my-website/docs/migration.md +++ b/docs/my-website/docs/migration.md @@ -31,5 +31,4 @@ When we have breaking changes (i.e. going from 1.x.x to 2.x.x), we will document **How can we communicate changes better?** Tell us - [Discord](https://discord.com/invite/wuPM9dRgDw) -- Email (krrish@berri.ai/ishaan@berri.ai) -- Text us (+17708783106) +- Email (support@berri.ai) From b77e1ccea64a86068ad91a8b35355d0a4a9f3164 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Wed, 25 Mar 2026 11:57:43 -0700 Subject: [PATCH 32/37] security: remove .claude/settings.json and add semgrep rule to prevent re-adding --- .claude/settings.json | 36 ------------------- .../rules/security/no-claude-directory.yml | 18 ++++++++++ 2 files changed, 18 insertions(+), 36 deletions(-) delete mode 100644 .claude/settings.json create mode 100644 .semgrep/rules/security/no-claude-directory.yml diff --git a/.claude/settings.json b/.claude/settings.json deleted file mode 100644 index 8c1d85f96e0..00000000000 --- a/.claude/settings.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(git show:*)", - "Bash(git worktree add:*)", - "Read(//Users/krrishdholakia/Documents/litellm/**)", - "Read(//Users/krrishdholakia/Documents/litellm-claude-code-guardrails/litellm/types/**)", - "Read(//Users/krrishdholakia/Documents/litellm-claude-code-guardrails/**)", - "Read(//Users/krrishdholakia/Documents/litellm-claude-code-guardrails/litellm/**)", - "Bash(python:*)", - "Bash(python -c \"\nimport sys; sys.path.insert\\(0, ''.''\\)\nfrom litellm.proxy.guardrails.guardrail_hooks.claude_code.guardrail import ClaudeCodeGuardrail, HOSTED_TOOL_PREFIXES\nprint\\(''HOSTED_TOOL_PREFIXES:'', HOSTED_TOOL_PREFIXES\\)\nprint\\(''ClaudeCodeGuardrail imported OK''\\)\n\")", - "Read(//Users/krrishdholakia/Documents/litellm-mcp-jwt-groups/litellm/proxy/**)", - "Read(//Users/krrishdholakia/Documents/litellm-mcp-jwt-groups/**)", - "Bash(poetry run pytest:*)", - "Bash(git add:*)", - "Bash(git commit:*)", - "Bash(poetry run python:*)", - "Bash(poetry run pip:*)", - "Bash(git reset:*)", - "Bash(git cherry-pick:*)", - "Bash(git checkout:*)", - "Read(//Users/krrishdholakia/Documents/litellm/litellm/proxy/guardrails/guardrail_hooks/**)", - "Read(//Users/krrishdholakia/Documents/**)", - "Bash(git -C /Users/krrishdholakia/Documents/litellm-mcp-user-permissions worktree list)", - "Bash(ls:*)" - ], - "additionalDirectories": [ - "/Users/krrishdholakia/Documents/litellm-mcp-group-plan/plan", - "/Users/krrishdholakia/Documents/litellm-claude-code-guardrails/litellm/proxy/guardrails/guardrail_hooks/claude_code", - "/Users/krrishdholakia/Documents/litellm-claude-code-guardrails/litellm/types", - "/Users/krrishdholakia/Documents/litellm-claude-code-guardrails", - "/Users/krrishdholakia/Documents/litellm-mcp-jwt-groups/litellm/proxy", - "/Users/krrishdholakia/Documents/litellm-mcp-jwt-groups/tests/test_litellm/proxy/auth" - ] - } -} diff --git a/.semgrep/rules/security/no-claude-directory.yml b/.semgrep/rules/security/no-claude-directory.yml new file mode 100644 index 00000000000..7d120a7c23c --- /dev/null +++ b/.semgrep/rules/security/no-claude-directory.yml @@ -0,0 +1,18 @@ +rules: + - id: no-claude-directory-committed + message: > + .claude/ directory must not be committed to the repository. + It contains local Claude Code settings (permissions, worktree paths) that are + developer-machine-specific and may expose internal paths or credentials. + Add .claude/ to .gitignore instead. + severity: ERROR + languages: [generic] + paths: + include: + - "/.claude/**" + - "/.claude/*" + pattern-regex: '[\s\S]+' + metadata: + category: security + tags: [supply-chain, secrets] + confidence: HIGH From a2f02aa1393ff23f501c3aff56443cdd3353da33 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Wed, 25 Mar 2026 12:40:40 -0700 Subject: [PATCH 33/37] docs: remove phone numbers from readme and docs --- README.md | 1 - cookbook/codellama-server/README.MD | 1 - cookbook/litellm_proxy_server/readme.md | 1 - docs/my-website/docs/observability/arize_integration.md | 1 - docs/my-website/docs/observability/gcs_bucket_integration.md | 1 - docs/my-website/docs/observability/langfuse_integration.md | 1 - docs/my-website/docs/observability/langsmith_integration.md | 1 - docs/my-website/docs/observability/logfire_integration.md | 1 - docs/my-website/docs/observability/lunary_integration.md | 1 - docs/my-website/docs/observability/opik_integration.md | 1 - docs/my-website/docs/observability/phoenix_integration.md | 1 - docs/my-website/docs/observability/promptlayer_integration.md | 1 - docs/my-website/docs/observability/slack_integration.md | 1 - docs/my-website/docs/observability/sumologic_integration.md | 1 - docs/my-website/docs/observability/supabase_integration.md | 1 - docs/my-website/docs/observability/wandb_integration.md | 1 - docs/my-website/docs/proxy/pass_through.md | 1 - docs/my-website/docs/proxy_server.md | 1 - docs/my-website/docs/troubleshoot.md | 1 - 19 files changed, 19 deletions(-) diff --git a/README.md b/README.md index 67f2f3a2048..f87e735fc55 100644 --- a/README.md +++ b/README.md @@ -452,7 +452,6 @@ All these checks must pass before your PR can be merged. - [Schedule Demo πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) - [Community Slack πŸ’­](https://www.litellm.ai/support) -- Our numbers πŸ“ž +1 (770) 8783-106 / ‭+1 (412) 618-6238‬ - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai # Why did we build this diff --git a/cookbook/codellama-server/README.MD b/cookbook/codellama-server/README.MD index b158bb083f2..82a7e62f40a 100644 --- a/cookbook/codellama-server/README.MD +++ b/cookbook/codellama-server/README.MD @@ -143,7 +143,6 @@ All responses from the server are returned in the following format (for all LLM - [Our calendar πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / +1 (412) 618-6238 - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai ## Roadmap diff --git a/cookbook/litellm_proxy_server/readme.md b/cookbook/litellm_proxy_server/readme.md index d0b0592c433..2c1eab72c24 100644 --- a/cookbook/litellm_proxy_server/readme.md +++ b/cookbook/litellm_proxy_server/readme.md @@ -164,7 +164,6 @@ All responses from the server are returned in the following format (for all LLM - [Our calendar πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / +1 (412) 618-6238 - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai ## Roadmap diff --git a/docs/my-website/docs/observability/arize_integration.md b/docs/my-website/docs/observability/arize_integration.md index b3ccf98ea3b..4486fb2b718 100644 --- a/docs/my-website/docs/observability/arize_integration.md +++ b/docs/my-website/docs/observability/arize_integration.md @@ -194,5 +194,4 @@ print(response) - [Schedule Demo πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / +1 (412) 618-6238 - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai diff --git a/docs/my-website/docs/observability/gcs_bucket_integration.md b/docs/my-website/docs/observability/gcs_bucket_integration.md index 69b956950e5..c97284824c1 100644 --- a/docs/my-website/docs/observability/gcs_bucket_integration.md +++ b/docs/my-website/docs/observability/gcs_bucket_integration.md @@ -79,5 +79,4 @@ curl --location 'http://0.0.0.0:4000/chat/completions' \ - [Schedule Demo πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / ‭+1 (412) 618-6238‬ - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai diff --git a/docs/my-website/docs/observability/langfuse_integration.md b/docs/my-website/docs/observability/langfuse_integration.md index d3c5a44d481..32849ebdb92 100644 --- a/docs/my-website/docs/observability/langfuse_integration.md +++ b/docs/my-website/docs/observability/langfuse_integration.md @@ -342,5 +342,4 @@ Be aware that if you are continuing an existing trace, and you set `update_trace - [Schedule Demo πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / ‭+1 (412) 618-6238‬ - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai diff --git a/docs/my-website/docs/observability/langsmith_integration.md b/docs/my-website/docs/observability/langsmith_integration.md index cada4122b20..bf867319de8 100644 --- a/docs/my-website/docs/observability/langsmith_integration.md +++ b/docs/my-website/docs/observability/langsmith_integration.md @@ -225,5 +225,4 @@ environment_variables: - [Schedule Demo πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / ‭+1 (412) 618-6238‬ - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai diff --git a/docs/my-website/docs/observability/logfire_integration.md b/docs/my-website/docs/observability/logfire_integration.md index a1bd43a4bc4..00652c0f1a1 100644 --- a/docs/my-website/docs/observability/logfire_integration.md +++ b/docs/my-website/docs/observability/logfire_integration.md @@ -63,5 +63,4 @@ response = litellm.completion( - [Schedule Demo πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / ‭+1 (412) 618-6238‬ - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai diff --git a/docs/my-website/docs/observability/lunary_integration.md b/docs/my-website/docs/observability/lunary_integration.md index 8d28321c807..4f1dca9d4af 100644 --- a/docs/my-website/docs/observability/lunary_integration.md +++ b/docs/my-website/docs/observability/lunary_integration.md @@ -176,5 +176,4 @@ You can find more details about the different ways of making requests to the Lit - [Schedule Demo πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / ‭+1 (412) 618-6238‬ - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai diff --git a/docs/my-website/docs/observability/opik_integration.md b/docs/my-website/docs/observability/opik_integration.md index d28c46f0b4b..5b5cbe0f185 100644 --- a/docs/my-website/docs/observability/opik_integration.md +++ b/docs/my-website/docs/observability/opik_integration.md @@ -261,5 +261,4 @@ All requests made with this key will automatically be tracked in the "TestProjec - [Schedule Demo πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / ‭+1 (412) 618-6238‬ - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai diff --git a/docs/my-website/docs/observability/phoenix_integration.md b/docs/my-website/docs/observability/phoenix_integration.md index 191f1f8044a..67ba815557e 100644 --- a/docs/my-website/docs/observability/phoenix_integration.md +++ b/docs/my-website/docs/observability/phoenix_integration.md @@ -127,5 +127,4 @@ Depending on which Phoenix Cloud version or deployment you are using, you should - [Schedule Demo πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / ‭+1 (412) 618-6238‬ - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai diff --git a/docs/my-website/docs/observability/promptlayer_integration.md b/docs/my-website/docs/observability/promptlayer_integration.md index 7f62a316972..9462e755f74 100644 --- a/docs/my-website/docs/observability/promptlayer_integration.md +++ b/docs/my-website/docs/observability/promptlayer_integration.md @@ -84,5 +84,4 @@ Credits to [Nick Bradford](https://github.com/nsbradford), from [Vim-GPT](https: - [Schedule Demo πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / ‭+1 (412) 618-6238‬ - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai \ No newline at end of file diff --git a/docs/my-website/docs/observability/slack_integration.md b/docs/my-website/docs/observability/slack_integration.md index 0ca7f616683..468d8b5945c 100644 --- a/docs/my-website/docs/observability/slack_integration.md +++ b/docs/my-website/docs/observability/slack_integration.md @@ -101,5 +101,4 @@ response = litellm.completion( - [Schedule Demo πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / ‭+1 (412) 618-6238‬ - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai diff --git a/docs/my-website/docs/observability/sumologic_integration.md b/docs/my-website/docs/observability/sumologic_integration.md index c30ee94dad4..87e20ca57ed 100644 --- a/docs/my-website/docs/observability/sumologic_integration.md +++ b/docs/my-website/docs/observability/sumologic_integration.md @@ -328,5 +328,4 @@ If you get authentication errors, regenerate the HTTP Source URL in Sumo Logic: - [Schedule Demo πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / ‭+1 (412) 618-6238‬ - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai diff --git a/docs/my-website/docs/observability/supabase_integration.md b/docs/my-website/docs/observability/supabase_integration.md index fd3f1c3d5a0..c29871d752f 100644 --- a/docs/my-website/docs/observability/supabase_integration.md +++ b/docs/my-website/docs/observability/supabase_integration.md @@ -105,5 +105,4 @@ litellm.modify_integration("supabase",{"table_name": "litellm_logs"}) - [Schedule Demo πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / ‭+1 (412) 618-6238‬ - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai diff --git a/docs/my-website/docs/observability/wandb_integration.md b/docs/my-website/docs/observability/wandb_integration.md index 37057f43db5..3c1a3363957 100644 --- a/docs/my-website/docs/observability/wandb_integration.md +++ b/docs/my-website/docs/observability/wandb_integration.md @@ -57,5 +57,4 @@ response = litellm.completion( - [Schedule Demo πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / ‭+1 (412) 618-6238‬ - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai \ No newline at end of file diff --git a/docs/my-website/docs/proxy/pass_through.md b/docs/my-website/docs/proxy/pass_through.md index f47d7064140..700bfb0831d 100644 --- a/docs/my-website/docs/proxy/pass_through.md +++ b/docs/my-website/docs/proxy/pass_through.md @@ -422,6 +422,5 @@ general_settings: [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -Our numbers πŸ“ž +1 (770) 8783-106 / ‭+1 (412) 618-6238‬ Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai diff --git a/docs/my-website/docs/proxy_server.md b/docs/my-website/docs/proxy_server.md index e23d64e443b..7b6f15a604b 100644 --- a/docs/my-website/docs/proxy_server.md +++ b/docs/my-website/docs/proxy_server.md @@ -813,5 +813,4 @@ Thread Stats Avg Stdev Max +/- Stdev - [Schedule Demo πŸ‘‹](https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version) - [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) -- Our numbers πŸ“ž +1 (770) 8783-106 / ‭+1 (412) 618-6238‬ - Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai diff --git a/docs/my-website/docs/troubleshoot.md b/docs/my-website/docs/troubleshoot.md index 1539e1959f7..1afa35df8e4 100644 --- a/docs/my-website/docs/troubleshoot.md +++ b/docs/my-website/docs/troubleshoot.md @@ -50,7 +50,6 @@ Full error logs, stack traces, and any images from service metrics (CPU, memory, [Community Discord πŸ’­](https://discord.gg/wuPM9dRgDw) [Community Slack πŸ’­](https://www.litellm.ai/support) -Our numbers πŸ“ž +1 (770) 8783-106 / +1 (412) 618-6238 Our emails βœ‰οΈ ishaan@berri.ai / krrish@berri.ai From f86b240d7efd9da6106611fcacad9f5f8ddde8a9 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 25 Mar 2026 17:18:58 -0700 Subject: [PATCH 34/37] pin github scripts + remove unused --- .../auto_update_price_and_context_window.yml | 6 ++--- .github/workflows/check_duplicate_issues.yml | 6 ++--- .github/workflows/codeql.yml | 6 ++--- .github/workflows/codspeed.yml | 6 ++--- .../workflows/create_daily_staging_branch.yml | 8 +++--- .github/workflows/helm_unit_test.yml | 27 ------------------- .github/workflows/issue-keyword-labeler.yml | 11 ++++---- .github/workflows/label-component.yml | 2 +- 8 files changed, 22 insertions(+), 50 deletions(-) delete mode 100644 .github/workflows/helm_unit_test.yml diff --git a/.github/workflows/auto_update_price_and_context_window.yml b/.github/workflows/auto_update_price_and_context_window.yml index 98b9d868e68..4cea6325972 100644 --- a/.github/workflows/auto_update_price_and_context_window.yml +++ b/.github/workflows/auto_update_price_and_context_window.yml @@ -2,7 +2,7 @@ name: Updates model_prices_and_context_window.json and Create Pull Request on: schedule: - - cron: "0 0 * * 0" # Run every Sundays at midnight + - cron: "0 0 * * 0" # Run every Sundays at midnight #- cron: "0 0 * * *" # Run daily at midnight jobs: @@ -10,7 +10,7 @@ jobs: if: github.repository == 'BerriAI/litellm' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Install Dependencies run: | pip install aiohttp @@ -26,4 +26,4 @@ jobs: --head auto-update-price-and-context-window-$(date +'%Y-%m-%d') \ --base main env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} \ No newline at end of file + GH_TOKEN: ${{ secrets.GH_TOKEN }} diff --git a/.github/workflows/check_duplicate_issues.yml b/.github/workflows/check_duplicate_issues.yml index 6d11ce573eb..539290bfeaf 100644 --- a/.github/workflows/check_duplicate_issues.yml +++ b/.github/workflows/check_duplicate_issues.yml @@ -12,7 +12,7 @@ jobs: contents: read steps: - name: Check for potential duplicates - uses: wow-actions/potential-duplicates@v1 + uses: wow-actions/potential-duplicates@4d4ea0352e0383859279938e255179dd1dbb67b5 # v1.1.0 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} label: potential-duplicate @@ -30,13 +30,13 @@ jobs: - name: Checkout close script if: github.event.action == 'opened' - uses: actions/checkout@v4 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 with: sparse-checkout: .github/scripts - name: Set up Python if: github.event.action == 'opened' - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.11" diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 91b88b66a1f..25ff5261ccd 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -38,16 +38,16 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@ebcb5b36ded6beda4ceefea6a8bc4cc885255bb3 # v3 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} config-file: ./.github/codeql/codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@@ebcb5b36ded6beda4ceefea6a8bc4cc885255bb3 # v3 with: category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/codspeed.yml b/.github/workflows/codspeed.yml index 385b95fdaf5..749242b1cd6 100644 --- a/.github/workflows/codspeed.yml +++ b/.github/workflows/codspeed.yml @@ -25,10 +25,10 @@ jobs: timeout-minutes: 15 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.12" @@ -38,7 +38,7 @@ jobs: pip install pytest pytest-codspeed==4.3.0 - name: Run benchmarks - uses: CodSpeedHQ/action@v4 + uses: CodSpeedHQ/action@1c8ae4843586d3ba879736b7f6b7b0c990757fab # v4.12.1 with: mode: simulation run: pytest tests/benchmarks/ --codspeed diff --git a/.github/workflows/create_daily_staging_branch.yml b/.github/workflows/create_daily_staging_branch.yml index ec27aaad8ac..0df5f4f92ea 100644 --- a/.github/workflows/create_daily_staging_branch.yml +++ b/.github/workflows/create_daily_staging_branch.yml @@ -2,8 +2,8 @@ name: Create Daily Staging Branch on: schedule: - - cron: '0 0,12 * * *' # Runs every 12 hours at midnight and noon UTC - workflow_dispatch: # Allow manual trigger + - cron: "0 0,12 * * *" # Runs every 12 hours at midnight and noon UTC + workflow_dispatch: # Allow manual trigger jobs: create-staging-branch: @@ -12,7 +12,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 with: fetch-depth: 0 @@ -49,7 +49,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 with: fetch-depth: 0 diff --git a/.github/workflows/helm_unit_test.yml b/.github/workflows/helm_unit_test.yml deleted file mode 100644 index c4b83af70a1..00000000000 --- a/.github/workflows/helm_unit_test.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Helm unit test - -on: - pull_request: - push: - branches: - - main - -jobs: - unit-test: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Set up Helm 3.11.1 - uses: azure/setup-helm@v1 - with: - version: '3.11.1' - - - name: Install Helm Unit Test Plugin - run: | - helm plugin install https://github.com/helm-unittest/helm-unittest --version v0.4.4 - - - name: Run unit tests - run: - helm unittest -f 'tests/*.yaml' deploy/charts/litellm-helm \ No newline at end of file diff --git a/.github/workflows/issue-keyword-labeler.yml b/.github/workflows/issue-keyword-labeler.yml index 936f90f747f..59b8fd9cf9f 100644 --- a/.github/workflows/issue-keyword-labeler.yml +++ b/.github/workflows/issue-keyword-labeler.yml @@ -2,8 +2,8 @@ name: Issue Keyword Labeler on: issues: - types: - - opened + types: + - opened jobs: scan-and-label: @@ -13,7 +13,7 @@ jobs: contents: read steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Scan for provider keywords id: scan @@ -24,7 +24,7 @@ jobs: - name: Ensure label exists if: steps.scan.outputs.found == 'true' - uses: actions/github-script@v7 + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -51,7 +51,7 @@ jobs: - name: Add label to the issue if: steps.scan.outputs.found == 'true' - uses: actions/github-script@v7 + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -61,4 +61,3 @@ jobs: issue_number: context.issue.number, labels: ['llm translation'] }); - diff --git a/.github/workflows/label-component.yml b/.github/workflows/label-component.yml index fd079fce6c1..e0c2fa94d8c 100644 --- a/.github/workflows/label-component.yml +++ b/.github/workflows/label-component.yml @@ -12,7 +12,7 @@ jobs: issues: write steps: - name: Add component labels - uses: actions/github-script@v7 + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | From a98958752592414bb190a00ffc1cb4751e858009 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 25 Mar 2026 17:36:28 -0700 Subject: [PATCH 35/37] re-add helm unit test with checksum pin --- .github/workflows/helm_unit_test.yml | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/helm_unit_test.yml diff --git a/.github/workflows/helm_unit_test.yml b/.github/workflows/helm_unit_test.yml new file mode 100644 index 00000000000..416523f241b --- /dev/null +++ b/.github/workflows/helm_unit_test.yml @@ -0,0 +1,36 @@ +name: Helm unit test + +on: + pull_request: + push: + branches: + - main + +jobs: + unit-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + + - name: Set up Helm 3.11.1 + uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1 + with: + version: "3.11.1" + + - name: Install Helm Unit Test Plugin + run: | + helm plugin install https://github.com/helm-unittest/helm-unittest --version v0.4.4 + - name: Verify Helm Unit Test Plugin integrity + run: | + EXPECTED_SHA="e251ba198448629678ff2168e1a469249d998155" + PLUGIN_DIR="$(helm env HELM_PLUGINS)/helm-unittest" + ACTUAL_SHA="$(git -C "$PLUGIN_DIR" rev-parse HEAD)" + if [ "$ACTUAL_SHA" != "$EXPECTED_SHA" ]; then + echo "::error::Helm unittest plugin checksum mismatch! Expected $EXPECTED_SHA but got $ACTUAL_SHA" + exit 1 + fi + echo "Helm unittest plugin integrity verified: $ACTUAL_SHA" + + - name: Run unit tests + run: helm unittest -f 'tests/*.yaml' deploy/charts/litellm-helm From b90a0af0d755a165cf5fde6ceb5cbbea774ab33b Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 25 Mar 2026 17:46:37 -0700 Subject: [PATCH 36/37] remove extra @ --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 25ff5261ccd..0e49b3af138 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -48,6 +48,6 @@ jobs: config-file: ./.github/codeql/codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@@ebcb5b36ded6beda4ceefea6a8bc4cc885255bb3 # v3 + uses: github/codeql-action/analyze@ebcb5b36ded6beda4ceefea6a8bc4cc885255bb3 # v3 with: category: "/language:${{ matrix.language }}" From df2a36dd27fa222623f08ab9a6d794ad88287888 Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Wed, 25 Mar 2026 20:17:10 -0700 Subject: [PATCH 37/37] docs: document new github + gitlab ci scripts --- .github/ISSUE_TEMPLATE/config.yml | 2 +- .github/workflows/interpret_load_test.py | 2 +- README.md | 2 +- cookbook/benchmark/readme.md | 2 +- .../blog/security_update_march_2026/index.md | 543 +++++++++++++++++- docs/my-website/docs/enterprise.md | 6 +- docs/my-website/docs/fine_tuning.md | 2 +- .../observability/gcs_bucket_integration.md | 2 +- docs/my-website/docs/proxy/cost_tracking.md | 2 +- docs/my-website/docs/proxy/email.md | 2 +- docs/my-website/docs/proxy/enterprise.md | 2 +- .../docs/proxy/guardrails/aporia_api.md | 2 +- .../docs/proxy/guardrails/custom_guardrail.md | 2 +- .../docs/proxy/guardrails/guardrails_ai.md | 2 +- docs/my-website/docs/proxy/ip_address.md | 2 +- docs/my-website/docs/proxy/logging.md | 6 +- docs/my-website/docs/proxy/multiple_admins.md | 2 +- docs/my-website/docs/proxy/oauth2.md | 2 +- docs/my-website/docs/proxy/prod.md | 2 +- docs/my-website/docs/proxy/public_routes.md | 2 +- docs/my-website/docs/proxy/tag_routing.md | 2 +- docs/my-website/docs/proxy/team_logging.md | 4 +- docs/my-website/docs/proxy/team_model_add.md | 2 +- docs/my-website/docs/proxy/token_auth.md | 2 +- docs/my-website/docs/secret.md | 2 +- .../docs/secret_managers/aws_kms.md | 2 +- .../secret_managers/aws_secret_manager.md | 2 +- .../docs/secret_managers/azure_key_vault.md | 2 +- .../docs/secret_managers/cyberark.md | 2 +- .../docs/secret_managers/google_kms.md | 2 +- .../secret_managers/google_secret_manager.md | 2 +- .../docs/secret_managers/hashicorp_vault.md | 2 +- .../docs/secret_managers/overview.md | 2 +- .../my-website/docs/tutorials/compare_llms.md | 2 +- enterprise/LICENSE.md | 2 +- enterprise/README.md | 2 +- .../send_emails/base_email.py | 2 +- litellm/proxy/management_endpoints/ui_sso.py | 19 +- 38 files changed, 598 insertions(+), 46 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 4744ab048c7..cbf380bac01 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,7 +1,7 @@ blank_issues_enabled: true contact_links: - name: Schedule Demo - url: https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions + url: https://enterprise.litellm.ai/demo about: Speak directly with Krrish and Ishaan, the founders, to discuss issues, share feedback, or explore improvements for LiteLLM - name: Discord url: https://discord.com/invite/wuPM9dRgDw diff --git a/.github/workflows/interpret_load_test.py b/.github/workflows/interpret_load_test.py index 348ff300fff..614358a78e0 100644 --- a/.github/workflows/interpret_load_test.py +++ b/.github/workflows/interpret_load_test.py @@ -123,7 +123,7 @@ if __name__ == "__main__": + docker_run_command + "\n\n" + "### Don't want to maintain your internal proxy? get in touch πŸŽ‰" - + "\nHosted Proxy Alpha: https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions" + + "\nHosted Proxy Alpha: https://enterprise.litellm.ai/demo" + "\n\n" + "## Load Test LiteLLM Proxy Results" + "\n\n" diff --git a/README.md b/README.md index f87e735fc55..88c0cb9648d 100644 --- a/README.md +++ b/README.md @@ -402,7 +402,7 @@ Support for more providers. Missing a provider or LLM Platform, raise a [feature # Enterprise For companies that need better security, user management and professional support -[Talk to founders](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +[Talk to founders](https://enterprise.litellm.ai/demo) This covers: - βœ… **Features under the [LiteLLM Commercial License](https://docs.litellm.ai/docs/proxy/enterprise):** diff --git a/cookbook/benchmark/readme.md b/cookbook/benchmark/readme.md index 57115eb96a9..afa59aa91ee 100644 --- a/cookbook/benchmark/readme.md +++ b/cookbook/benchmark/readme.md @@ -178,4 +178,4 @@ Benchmark Results for 'When will BerriAI IPO?': ``` ## Support -**🀝 Schedule a 1-on-1 Session:** Book a [1-on-1 session](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) with Krrish and Ishaan, the founders, to discuss any issues, provide feedback, or explore how we can improve LiteLLM for you. +**🀝 Schedule a 1-on-1 Session:** Book a [1-on-1 session](https://enterprise.litellm.ai/demo) with Krrish and Ishaan, the founders, to discuss any issues, provide feedback, or explore how we can improve LiteLLM for you. diff --git a/docs/my-website/blog/security_update_march_2026/index.md b/docs/my-website/blog/security_update_march_2026/index.md index 20cf5e8f3ff..c609cd58fb0 100644 --- a/docs/my-website/blog/security_update_march_2026/index.md +++ b/docs/my-website/blog/security_update_march_2026/index.md @@ -14,7 +14,9 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; > **Status:** Active investigation -> **Last updated:** March 24, 2026, 2:00 PM ET +> **Last updated:** March 25, 2026 + +> **Update (March 25):** Added community-contributed scripts for scanning GitHub Actions and GitLab CI pipelines for the compromised versions. See [How to check if you are affected](#how-to-check-if-you-are-affected). s/o [@Zach Fury](https://www.linkedin.com/in/fryware/) for these scripts. ## TLDR; @@ -91,9 +93,548 @@ pip show litellm Go to the proxy base url, and check the version of the installed LiteLLM. ![Proxy version check](../../img/security_update_march_2026/proxy_version.png) + + + +Scans all repositories in a GitHub organization for workflow jobs that installed the compromised versions. + +**Requirements:** Python 3 and `requests` (`pip install requests`). + +**Setup:** + +```bash +export GITHUB_TOKEN="your-github-pat" +``` + +**Run:** + +```bash +python find_litellm_github.py +``` + +Set the `ORG` variable in the script to your GitHub organization name. + +Both scripts default to scanning jobs from **today**. Adjust the `WINDOW_START` and `WINDOW_END` constants to cover **March 24, 2026** (the incident date) if running on a different day. + +
+View full script (find_litellm_github.py) + +```python +#!/usr/bin/env python3 +""" +Scan all GitHub Actions jobs in a GitHub org that ran between +0800-1244 UTC today and identify any that installed litellm 1.82.7 or 1.82.8. + +Adjust WINDOW_START / WINDOW_END to cover March 24, 2026 if running later. +""" + +import io +import os +import re +import sys +import zipfile +from concurrent.futures import ThreadPoolExecutor, as_completed +from datetime import datetime, timezone + +import requests + +GITHUB_URL = "https://api.github.com" +ORG = "your-org" # <-- set to your GitHub organization +TOKEN = os.environ.get("GITHUB_TOKEN", "") + +TODAY = datetime.now(timezone.utc).date() +WINDOW_START = datetime(TODAY.year, TODAY.month, TODAY.day, 8, 0, 0, tzinfo=timezone.utc) +WINDOW_END = datetime(TODAY.year, TODAY.month, TODAY.day, 12, 44, 0, tzinfo=timezone.utc) + +TARGET_VERSIONS = {"1.82.7", "1.82.8"} +VERSION_PATTERN = re.compile(r"litellm[=\-](\d+\.\d+\.\d+)", re.IGNORECASE) + +SESSION = requests.Session() +SESSION.headers.update({ + "Authorization": f"Bearer {TOKEN}", + "Accept": "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", +}) + + +def get_paginated(url, params=None): + params = dict(params or {}) + params.setdefault("per_page", 100) + page = 1 + while True: + params["page"] = page + resp = SESSION.get(url, params=params, timeout=30) + if resp.status_code == 404: + return + resp.raise_for_status() + data = resp.json() + if isinstance(data, dict): + items = next((v for v in data.values() if isinstance(v, list)), []) + else: + items = data + if not items: + break + yield from items + if len(items) < params["per_page"]: + break + page += 1 + + +def parse_ts(ts_str): + if not ts_str: + return None + return datetime.fromisoformat(ts_str.replace("Z", "+00:00")) + + +def get_repos(): + repos = [] + for r in get_paginated(f"{GITHUB_URL}/orgs/{ORG}/repos", {"type": "all"}): + repos.append({"id": r["id"], "name": r["name"], "full_name": r["full_name"]}) + return repos + + +def get_runs_in_window(repo_full_name): + created_filter = ( + f"{WINDOW_START.strftime('%Y-%m-%dT%H:%M:%SZ')}" + f"..{WINDOW_END.strftime('%Y-%m-%dT%H:%M:%SZ')}" + ) + url = f"{GITHUB_URL}/repos/{repo_full_name}/actions/runs" + runs = [] + for run in get_paginated(url, {"created": created_filter, "per_page": 100}): + ts = parse_ts(run.get("run_started_at") or run.get("created_at")) + if ts and WINDOW_START <= ts <= WINDOW_END: + runs.append(run) + return runs + + +def get_jobs_for_run(repo_full_name, run_id): + url = f"{GITHUB_URL}/repos/{repo_full_name}/actions/runs/{run_id}/jobs" + jobs = [] + for job in get_paginated(url, {"filter": "all"}): + ts = parse_ts(job.get("started_at")) + if ts and WINDOW_START <= ts <= WINDOW_END: + jobs.append(job) + return jobs + + +def fetch_job_log(repo_full_name, job_id): + url = f"{GITHUB_URL}/repos/{repo_full_name}/actions/jobs/{job_id}/logs" + resp = SESSION.get(url, timeout=60, allow_redirects=True) + if resp.status_code in (403, 404, 410): + return "" + resp.raise_for_status() + + content_type = resp.headers.get("Content-Type", "") + if "zip" in content_type or resp.content[:2] == b"PK": + try: + with zipfile.ZipFile(io.BytesIO(resp.content)) as zf: + parts = [] + for name in sorted(zf.namelist()): + with zf.open(name) as f: + parts.append(f.read().decode("utf-8", errors="replace")) + return "\n".join(parts) + except zipfile.BadZipFile: + pass + return resp.text + + +def check_job(repo_full_name, job): + job_id = job["id"] + job_name = job["name"] + run_id = job["run_id"] + started = job.get("started_at", "") + + log_text = fetch_job_log(repo_full_name, job_id) + if not log_text: + return None + + found_versions = set() + context_lines = [] + for line in log_text.splitlines(): + m = VERSION_PATTERN.search(line) + if m: + ver = m.group(1) + if ver in TARGET_VERSIONS: + found_versions.add(ver) + context_lines.append(line.strip()) + + if not found_versions: + return None + + return { + "repo": repo_full_name, + "run_id": run_id, + "job_id": job_id, + "job_name": job_name, + "started_at": started, + "versions": sorted(found_versions), + "context": context_lines[:10], + "job_url": job.get("html_url", f"https://github.com/{repo_full_name}/actions/runs/{run_id}"), + } + + +def main(): + if not TOKEN: + print("ERROR: Set GITHUB_TOKEN environment variable.", file=sys.stderr) + sys.exit(1) + + print(f"Time window : {WINDOW_START.isoformat()} -> {WINDOW_END.isoformat()}") + print(f"Hunting for : litellm {', '.join(sorted(TARGET_VERSIONS))}") + print() + + print(f"Fetching repositories for org '{ORG}'...") + repos = get_repos() + print(f" Found {len(repos)} repositories") + print() + + jobs_to_check = [] + + print("Scanning workflow runs for time window...") + for repo in repos: + full_name = repo["full_name"] + try: + runs = get_runs_in_window(full_name) + except requests.HTTPError as e: + print(f" WARN: {full_name} - {e}", file=sys.stderr) + continue + if not runs: + continue + print(f" {full_name}: {len(runs)} run(s) in window") + for run in runs: + try: + jobs = get_jobs_for_run(full_name, run["id"]) + except requests.HTTPError as e: + print(f" WARN: run {run['id']} - {e}", file=sys.stderr) + continue + for job in jobs: + jobs_to_check.append((full_name, job)) + + total = len(jobs_to_check) + print(f"\nFetching logs for {total} job(s)...") + print() + + hits = [] + with ThreadPoolExecutor(max_workers=8) as pool: + futures = { + pool.submit(check_job, full_name, job): (full_name, job["id"]) + for full_name, job in jobs_to_check + } + done = 0 + for future in as_completed(futures): + done += 1 + full_name, jid = futures[future] + try: + result = future.result() + except Exception as e: + print(f" ERROR {full_name} job {jid}: {e}", file=sys.stderr) + continue + if result: + hits.append(result) + print( + f" [{done}/{total}] {full_name} job {jid}" + + (f" *** HIT: litellm {result['versions']} ***" if result else ""), + flush=True, + ) + + print() + print("=" * 72) + print(f"RESULTS: {len(hits)} job(s) installed litellm {' or '.join(sorted(TARGET_VERSIONS))}") + print("=" * 72) + + if not hits: + print("No matches found.") + return + + for h in sorted(hits, key=lambda x: x["started_at"]): + print() + print(f" Repo : {h['repo']}") + print(f" Job : {h['job_name']} (#{h['job_id']})") + print(f" Run ID : {h['run_id']}") + print(f" Started : {h['started_at']}") + print(f" Versions : litellm {', '.join(h['versions'])}") + print(f" URL : {h['job_url']}") + print(f" Log lines :") + for line in h["context"]: + print(f" {line}") + + +if __name__ == "__main__": + main() +``` + +
+ +
+ + +Scans all projects in a GitLab group (including subgroups) for CI/CD jobs that installed the compromised versions. + +**Requirements:** Python 3 and `requests` (`pip install requests`). + +**Setup:** + +```bash +export GITLAB_TOKEN="your-gitlab-pat" +``` + +**Run:** + +```bash +python find_litellm_jobs.py +``` + +Set the `GROUP_NAME` variable in the script to your GitLab group name. + +Both scripts default to scanning jobs from **today**. Adjust the `WINDOW_START` and `WINDOW_END` constants to cover **March 24, 2026** (the incident date) if running on a different day. + +
+View full script (find_litellm_jobs.py) + +```python +#!/usr/bin/env python3 +""" +Scan all GitLab CI/CD jobs in a GitLab group that ran between +0800-1244 UTC today and identify any that installed litellm 1.82.7 or 1.82.8. + +Adjust WINDOW_START / WINDOW_END to cover March 24, 2026 if running later. +""" + +import os +import re +import sys +from concurrent.futures import ThreadPoolExecutor, as_completed +from datetime import datetime, timezone + +import requests + +GITLAB_URL = "https://gitlab.com" +GROUP_NAME = "YourGroup" # <-- set to your GitLab group name +TOKEN = os.environ.get("GITLAB_TOKEN", "") + +TODAY = datetime.now(timezone.utc).date() +WINDOW_START = datetime(TODAY.year, TODAY.month, TODAY.day, 8, 0, 0, tzinfo=timezone.utc) +WINDOW_END = datetime(TODAY.year, TODAY.month, TODAY.day, 12, 44, 0, tzinfo=timezone.utc) + +TARGET_VERSIONS = {"1.82.7", "1.82.8"} +VERSION_PATTERN = re.compile(r"litellm[=\-](\d+\.\d+\.\d+)", re.IGNORECASE) + +HEADERS = {"PRIVATE-TOKEN": TOKEN} +SESSION = requests.Session() +SESSION.headers.update(HEADERS) + + +def get_paginated(url, params=None): + params = dict(params or {}) + params.setdefault("per_page", 100) + page = 1 + while True: + params["page"] = page + resp = SESSION.get(url, params=params, timeout=30) + resp.raise_for_status() + data = resp.json() + if not data: + break + yield from data + if len(data) < params["per_page"]: + break + page += 1 + + +def get_group_id(group_name): + resp = SESSION.get(f"{GITLAB_URL}/api/v4/groups/{group_name}", timeout=30) + resp.raise_for_status() + return resp.json()["id"] + + +def get_all_projects(group_id): + projects = [] + for p in get_paginated( + f"{GITLAB_URL}/api/v4/groups/{group_id}/projects", + {"include_subgroups": "true", "archived": "false"}, + ): + projects.append({"id": p["id"], "name": p["path_with_namespace"]}) + return projects + + +def parse_ts(ts_str): + if not ts_str: + return None + ts_str = ts_str.replace("Z", "+00:00") + return datetime.fromisoformat(ts_str) + + +def jobs_in_window(project_id): + matching = [] + url = f"{GITLAB_URL}/api/v4/projects/{project_id}/jobs" + params = {"per_page": 100, "scope[]": ["success", "failed", "canceled", "running"]} + + page = 1 + while True: + params["page"] = page + resp = SESSION.get(url, params=params, timeout=30) + if resp.status_code == 403: + return matching + resp.raise_for_status() + jobs = resp.json() + if not jobs: + break + + stop_early = False + for job in jobs: + ts = parse_ts(job.get("started_at") or job.get("created_at")) + if ts is None: + continue + if ts > WINDOW_END: + continue + if ts < WINDOW_START: + stop_early = True + continue + matching.append(job) + + if stop_early or len(jobs) < 100: + break + page += 1 + + return matching + + +def fetch_trace(project_id, job_id): + url = f"{GITLAB_URL}/api/v4/projects/{project_id}/jobs/{job_id}/trace" + resp = SESSION.get(url, timeout=60) + if resp.status_code in (403, 404): + return "" + resp.raise_for_status() + return resp.text + + +def check_job(project_name, project_id, job): + job_id = job["id"] + job_name = job["name"] + ref = job.get("ref", "") + started = job.get("started_at", job.get("created_at", "")) + + trace = fetch_trace(project_id, job_id) + if not trace: + return None + + found_versions = set() + for match in VERSION_PATTERN.finditer(trace): + ver = match.group(1) + if ver in TARGET_VERSIONS: + found_versions.add(ver) + + if not found_versions: + return None + + context_lines = [] + for line in trace.splitlines(): + if VERSION_PATTERN.search(line): + ver_match = VERSION_PATTERN.search(line) + if ver_match and ver_match.group(1) in TARGET_VERSIONS: + context_lines.append(line.strip()) + + return { + "project": project_name, + "project_id": project_id, + "job_id": job_id, + "job_name": job_name, + "ref": ref, + "started_at": started, + "versions": sorted(found_versions), + "context": context_lines[:10], + "job_url": f"{GITLAB_URL}/{project_name}/-/jobs/{job_id}", + } + + +def main(): + if not TOKEN: + print("ERROR: Set GITLAB_TOKEN environment variable.", file=sys.stderr) + sys.exit(1) + + print(f"Time window : {WINDOW_START.isoformat()} -> {WINDOW_END.isoformat()}") + print(f"Hunting for : litellm {', '.join(sorted(TARGET_VERSIONS))}") + print() + + print(f"Resolving group '{GROUP_NAME}'...") + group_id = get_group_id(GROUP_NAME) + + print("Fetching projects...") + projects = get_all_projects(group_id) + print(f" Found {len(projects)} projects") + print() + + all_jobs_to_check = [] + + print("Scanning job listings for time window...") + for proj in projects: + try: + jobs = jobs_in_window(proj["id"]) + except requests.HTTPError as e: + print(f" WARN: {proj['name']} - {e}", file=sys.stderr) + continue + if jobs: + print(f" {proj['name']}: {len(jobs)} job(s) in window") + for j in jobs: + all_jobs_to_check.append((proj["name"], proj["id"], j)) + + total = len(all_jobs_to_check) + print(f"\nFetching traces for {total} job(s)...") + print() + + hits = [] + with ThreadPoolExecutor(max_workers=10) as pool: + futures = { + pool.submit(check_job, pname, pid, job): (pname, job["id"]) + for pname, pid, job in all_jobs_to_check + } + done = 0 + for future in as_completed(futures): + done += 1 + pname, jid = futures[future] + try: + result = future.result() + except Exception as e: + print(f" ERROR checking {pname} job {jid}: {e}", file=sys.stderr) + continue + if result: + hits.append(result) + print(f" [{done}/{total}] checked {pname} job {jid}" + + (f" *** HIT: litellm {result['versions']} ***" if result else ""), + flush=True) + + print() + print("=" * 72) + print(f"RESULTS: {len(hits)} job(s) installed litellm {' or '.join(sorted(TARGET_VERSIONS))}") + print("=" * 72) + + if not hits: + print("No matches found.") + return + + for h in sorted(hits, key=lambda x: x["started_at"]): + print() + print(f" Project : {h['project']}") + print(f" Job : {h['job_name']} (#{h['job_id']})") + print(f" Branch/tag: {h['ref']}") + print(f" Started : {h['started_at']}") + print(f" Versions : litellm {', '.join(h['versions'])}") + print(f" URL : {h['job_url']}") + print(f" Log lines :") + for line in h["context"]: + print(f" {line}") + + +if __name__ == "__main__": + main() +``` + +
+
+*CI/CD scripts contributed by the community ([original gist](https://gist.github.com/fryz/93ec8d4898ffe5b5ac5706a208823ef3)). Review before running.* + ## Indicators of compromise (IoCs) diff --git a/docs/my-website/docs/enterprise.md b/docs/my-website/docs/enterprise.md index 6dccf7ff4e7..a3fc9e38b6e 100644 --- a/docs/my-website/docs/enterprise.md +++ b/docs/my-website/docs/enterprise.md @@ -4,7 +4,7 @@ import Image from '@theme/IdealImage'; :::info - ✨ SSO is free for up to 5 users. After that, an enterprise license is required. [Get Started with Enterprise here](https://www.litellm.ai/enterprise) -- Who is Enterprise for? Companies giving access to 100+ users **OR** 10+ AI use-cases. If you're not sure, [get in touch with us](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) to discuss your needs. +- Who is Enterprise for? Companies giving access to 100+ users **OR** 10+ AI use-cases. If you're not sure, [get in touch with us](https://enterprise.litellm.ai/demo) to discuss your needs. ::: For companies that need SSO, user management and professional support for LiteLLM Proxy @@ -36,7 +36,7 @@ Manage Yourself - you can deploy our Docker Image or build a custom image from o ### What’s the cost of the Self-Managed Enterprise edition? -Self-Managed Enterprise deployments require our team to understand your exact needs. [Get in touch with us to learn more](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +Self-Managed Enterprise deployments require our team to understand your exact needs. [Get in touch with us to learn more](https://enterprise.litellm.ai/demo) ### How does deployment with Enterprise License work? @@ -106,7 +106,7 @@ Professional Support can assist with LLM/Provider integrations, deployment, upgr Pricing is based on usage. We can figure out a price that works for your team, on the call. -[**Contact Us to learn more**](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +[**Contact Us to learn more**](https://enterprise.litellm.ai/demo) diff --git a/docs/my-website/docs/fine_tuning.md b/docs/my-website/docs/fine_tuning.md index d0bd98a76f9..52e96f28688 100644 --- a/docs/my-website/docs/fine_tuning.md +++ b/docs/my-website/docs/fine_tuning.md @@ -6,7 +6,7 @@ import TabItem from '@theme/TabItem'; :::info -This is an Enterprise only endpoint [Get Started with Enterprise here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +This is an Enterprise only endpoint [Get Started with Enterprise here](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/observability/gcs_bucket_integration.md b/docs/my-website/docs/observability/gcs_bucket_integration.md index c97284824c1..5f8d42508ae 100644 --- a/docs/my-website/docs/observability/gcs_bucket_integration.md +++ b/docs/my-website/docs/observability/gcs_bucket_integration.md @@ -6,7 +6,7 @@ Log LLM Logs to [Google Cloud Storage Buckets](https://cloud.google.com/storage? :::info -✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +✨ This is an Enterprise only feature [Get Started with Enterprise here](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/proxy/cost_tracking.md b/docs/my-website/docs/proxy/cost_tracking.md index f28eec287d4..f9e22cfecd3 100644 --- a/docs/my-website/docs/proxy/cost_tracking.md +++ b/docs/my-website/docs/proxy/cost_tracking.md @@ -163,7 +163,7 @@ Use this when you want non-proxy admins to access `/spend` endpoints :::info -Schedule a [meeting with us to get your Enterprise License](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +Schedule a [meeting with us to get your Enterprise License](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/proxy/email.md b/docs/my-website/docs/proxy/email.md index 86a79cbcfc8..ba737c6782c 100644 --- a/docs/my-website/docs/proxy/email.md +++ b/docs/my-website/docs/proxy/email.md @@ -203,7 +203,7 @@ After regenerating the key, the user will receive an email notification with: :::info -Customizing Email Branding is an Enterprise Feature [Get in touch with us for a Free Trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +Customizing Email Branding is an Enterprise Feature [Get in touch with us for a Free Trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/proxy/enterprise.md b/docs/my-website/docs/proxy/enterprise.md index 4b525837a20..09b103ca4a0 100644 --- a/docs/my-website/docs/proxy/enterprise.md +++ b/docs/my-website/docs/proxy/enterprise.md @@ -5,7 +5,7 @@ import TabItem from '@theme/TabItem'; # ✨ Enterprise Features :::tip -To get a license, get in touch with us [here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +To get a license, get in touch with us [here](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/proxy/guardrails/aporia_api.md b/docs/my-website/docs/proxy/guardrails/aporia_api.md index ceafc19a1cc..e6ff0d5fed3 100644 --- a/docs/my-website/docs/proxy/guardrails/aporia_api.md +++ b/docs/my-website/docs/proxy/guardrails/aporia_api.md @@ -139,7 +139,7 @@ curl -i http://localhost:4000/v1/chat/completions \ :::info -✨ This is an Enterprise only feature [Contact us to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +✨ This is an Enterprise only feature [Contact us to get a free trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/proxy/guardrails/custom_guardrail.md b/docs/my-website/docs/proxy/guardrails/custom_guardrail.md index 638cae9c835..37579ad870d 100644 --- a/docs/my-website/docs/proxy/guardrails/custom_guardrail.md +++ b/docs/my-website/docs/proxy/guardrails/custom_guardrail.md @@ -417,7 +417,7 @@ curl -i -X POST http://localhost:4000/v1/chat/completions \ :::info -✨ This is an Enterprise only feature [Contact us to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +✨ This is an Enterprise only feature [Contact us to get a free trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/proxy/guardrails/guardrails_ai.md b/docs/my-website/docs/proxy/guardrails/guardrails_ai.md index 55d586aee7b..19ae34014a4 100644 --- a/docs/my-website/docs/proxy/guardrails/guardrails_ai.md +++ b/docs/my-website/docs/proxy/guardrails/guardrails_ai.md @@ -59,7 +59,7 @@ curl -i http://localhost:4000/v1/chat/completions \ :::info -✨ This is an Enterprise only feature [Contact us to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +✨ This is an Enterprise only feature [Contact us to get a free trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/proxy/ip_address.md b/docs/my-website/docs/proxy/ip_address.md index 8f042d9f183..4c469b81e0b 100644 --- a/docs/my-website/docs/proxy/ip_address.md +++ b/docs/my-website/docs/proxy/ip_address.md @@ -3,7 +3,7 @@ :::info -You need a LiteLLM License to unlock this feature. [Grab time](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions), to get one today! +You need a LiteLLM License to unlock this feature. [Grab time](https://enterprise.litellm.ai/demo), to get one today! ::: diff --git a/docs/my-website/docs/proxy/logging.md b/docs/my-website/docs/proxy/logging.md index 74a79776fbd..2f81498799a 100644 --- a/docs/my-website/docs/proxy/logging.md +++ b/docs/my-website/docs/proxy/logging.md @@ -1109,7 +1109,7 @@ Log LLM Logs to [Google Cloud Storage Buckets](https://cloud.google.com/storage? :::info -✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +✨ This is an Enterprise only feature [Get Started with Enterprise here](https://enterprise.litellm.ai/demo) ::: @@ -1194,7 +1194,7 @@ Log LLM Logs/SpendLogs to [Google Cloud Storage PubSub Topic](https://cloud.goog :::info -✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +✨ This is an Enterprise only feature [Get Started with Enterprise here](https://enterprise.litellm.ai/demo) ::: @@ -1497,7 +1497,7 @@ Log LLM Logs to [Azure Data Lake Storage](https://learn.microsoft.com/en-us/azur :::info -✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +✨ This is an Enterprise only feature [Get Started with Enterprise here](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/proxy/multiple_admins.md b/docs/my-website/docs/proxy/multiple_admins.md index d30065a3539..83d0c5863df 100644 --- a/docs/my-website/docs/proxy/multiple_admins.md +++ b/docs/my-website/docs/proxy/multiple_admins.md @@ -20,7 +20,7 @@ LiteLLM tracks changes to the following entities and actions: :::tip -Requires Enterprise License, Get in touch with us [here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +Requires Enterprise License, Get in touch with us [here](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/proxy/oauth2.md b/docs/my-website/docs/proxy/oauth2.md index 41c4110e447..204a01538cc 100644 --- a/docs/my-website/docs/proxy/oauth2.md +++ b/docs/my-website/docs/proxy/oauth2.md @@ -4,7 +4,7 @@ Use this if you want to use an Oauth2.0 token to make `/chat`, `/embeddings` req :::info -This is an Enterprise Feature - [get in touch with us if you want a free trial to test if this feature meets your needs]((https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions)) +This is an Enterprise Feature - [get in touch with us if you want a free trial to test if this feature meets your needs]((https://enterprise.litellm.ai/demo)) ::: diff --git a/docs/my-website/docs/proxy/prod.md b/docs/my-website/docs/proxy/prod.md index 26cb484cbe9..d40a0343106 100644 --- a/docs/my-website/docs/proxy/prod.md +++ b/docs/my-website/docs/proxy/prod.md @@ -47,7 +47,7 @@ export LITELLM_LOG="ERROR" :::info -Need Help or want dedicated support ? Talk to a founder [here]: (https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +Need Help or want dedicated support ? Talk to a founder [here]: (https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/proxy/public_routes.md b/docs/my-website/docs/proxy/public_routes.md index d5f3941751f..e53548349dc 100644 --- a/docs/my-website/docs/proxy/public_routes.md +++ b/docs/my-website/docs/proxy/public_routes.md @@ -5,7 +5,7 @@ import TabItem from '@theme/TabItem'; :::info -Requires a LiteLLM Enterprise License. [Get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions). +Requires a LiteLLM Enterprise License. [Get a free trial](https://enterprise.litellm.ai/demo). ::: diff --git a/docs/my-website/docs/proxy/tag_routing.md b/docs/my-website/docs/proxy/tag_routing.md index a1ae52e5e45..57d16a59b54 100644 --- a/docs/my-website/docs/proxy/tag_routing.md +++ b/docs/my-website/docs/proxy/tag_routing.md @@ -315,7 +315,7 @@ LiteLLM Proxy supports team-based tag routing, allowing you to associate specifi :::info -This is an enterprise feature, [Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +This is an enterprise feature, [Contact us here to get a free trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/proxy/team_logging.md b/docs/my-website/docs/proxy/team_logging.md index 2ad7e2a4a8e..3f57d0d6d8b 100644 --- a/docs/my-website/docs/proxy/team_logging.md +++ b/docs/my-website/docs/proxy/team_logging.md @@ -26,7 +26,7 @@ Team 3 -> Disabled Logging (for GDPR compliance) :::info -✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +✨ This is an Enterprise only feature [Get Started with Enterprise here](https://enterprise.litellm.ai/demo) ::: @@ -248,7 +248,7 @@ Use the `/key/generate` or `/key/update` endpoints to add logging callbacks to a :::info -✨ This is an Enterprise only feature [Get Started with Enterprise here](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +✨ This is an Enterprise only feature [Get Started with Enterprise here](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/proxy/team_model_add.md b/docs/my-website/docs/proxy/team_model_add.md index 7db59a3300e..bb4238055b5 100644 --- a/docs/my-website/docs/proxy/team_model_add.md +++ b/docs/my-website/docs/proxy/team_model_add.md @@ -5,7 +5,7 @@ This is an Enterprise feature. [Enterprise Pricing](https://www.litellm.ai/#pricing) -[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +[Contact us here to get a free trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/proxy/token_auth.md b/docs/my-website/docs/proxy/token_auth.md index 7364ae0fb56..bc6fde7c840 100644 --- a/docs/my-website/docs/proxy/token_auth.md +++ b/docs/my-website/docs/proxy/token_auth.md @@ -11,7 +11,7 @@ Use JWT's to auth admins / users / projects into the proxy. [Enterprise Pricing](https://www.litellm.ai/#pricing) -[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +[Contact us here to get a free trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/secret.md b/docs/my-website/docs/secret.md index c5c80311475..57f576fd56a 100644 --- a/docs/my-website/docs/secret.md +++ b/docs/my-website/docs/secret.md @@ -6,7 +6,7 @@ [Enterprise Pricing](https://www.litellm.ai/#pricing) -[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +[Contact us here to get a free trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/secret_managers/aws_kms.md b/docs/my-website/docs/secret_managers/aws_kms.md index 7f69d91fe87..806223a2539 100644 --- a/docs/my-website/docs/secret_managers/aws_kms.md +++ b/docs/my-website/docs/secret_managers/aws_kms.md @@ -6,7 +6,7 @@ [Enterprise Pricing](https://www.litellm.ai/#pricing) -[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +[Contact us here to get a free trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/secret_managers/aws_secret_manager.md b/docs/my-website/docs/secret_managers/aws_secret_manager.md index c49797a15dd..a7e24ea69ae 100644 --- a/docs/my-website/docs/secret_managers/aws_secret_manager.md +++ b/docs/my-website/docs/secret_managers/aws_secret_manager.md @@ -9,7 +9,7 @@ import TabItem from '@theme/TabItem'; [Enterprise Pricing](https://www.litellm.ai/#pricing) -[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +[Contact us here to get a free trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/secret_managers/azure_key_vault.md b/docs/my-website/docs/secret_managers/azure_key_vault.md index 81aeaa32159..4ea53d2ea9e 100644 --- a/docs/my-website/docs/secret_managers/azure_key_vault.md +++ b/docs/my-website/docs/secret_managers/azure_key_vault.md @@ -6,7 +6,7 @@ [Enterprise Pricing](https://www.litellm.ai/#pricing) -[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +[Contact us here to get a free trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/secret_managers/cyberark.md b/docs/my-website/docs/secret_managers/cyberark.md index 0a17c0afc30..cd7c0ea5d25 100644 --- a/docs/my-website/docs/secret_managers/cyberark.md +++ b/docs/my-website/docs/secret_managers/cyberark.md @@ -8,7 +8,7 @@ import Image from '@theme/IdealImage'; [Enterprise Pricing](https://www.litellm.ai/#pricing) -[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +[Contact us here to get a free trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/secret_managers/google_kms.md b/docs/my-website/docs/secret_managers/google_kms.md index 31fd6195bdb..152ecbaae80 100644 --- a/docs/my-website/docs/secret_managers/google_kms.md +++ b/docs/my-website/docs/secret_managers/google_kms.md @@ -6,7 +6,7 @@ [Enterprise Pricing](https://www.litellm.ai/#pricing) -[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +[Contact us here to get a free trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/secret_managers/google_secret_manager.md b/docs/my-website/docs/secret_managers/google_secret_manager.md index 81878b7e398..f3e7367e8a4 100644 --- a/docs/my-website/docs/secret_managers/google_secret_manager.md +++ b/docs/my-website/docs/secret_managers/google_secret_manager.md @@ -6,7 +6,7 @@ [Enterprise Pricing](https://www.litellm.ai/#pricing) -[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +[Contact us here to get a free trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/secret_managers/hashicorp_vault.md b/docs/my-website/docs/secret_managers/hashicorp_vault.md index 52d9b556200..11e25e88a7d 100644 --- a/docs/my-website/docs/secret_managers/hashicorp_vault.md +++ b/docs/my-website/docs/secret_managers/hashicorp_vault.md @@ -8,7 +8,7 @@ import Image from '@theme/IdealImage'; [Enterprise Pricing](https://www.litellm.ai/#pricing) -[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +[Contact us here to get a free trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/secret_managers/overview.md b/docs/my-website/docs/secret_managers/overview.md index bf7386ab89c..f02362f4932 100644 --- a/docs/my-website/docs/secret_managers/overview.md +++ b/docs/my-website/docs/secret_managers/overview.md @@ -8,7 +8,7 @@ import Image from '@theme/IdealImage'; [Enterprise Pricing](https://www.litellm.ai/#pricing) -[Contact us here to get a free trial](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) +[Contact us here to get a free trial](https://enterprise.litellm.ai/demo) ::: diff --git a/docs/my-website/docs/tutorials/compare_llms.md b/docs/my-website/docs/tutorials/compare_llms.md index 02877b46607..0252263a16e 100644 --- a/docs/my-website/docs/tutorials/compare_llms.md +++ b/docs/my-website/docs/tutorials/compare_llms.md @@ -82,7 +82,7 @@ Benchmark Results for 'When will BerriAI IPO?': +-----------------+----------------------------------------------------------------------------------+---------------------------+------------+ ``` ## Support -**🀝 Schedule a 1-on-1 Session:** Book a [1-on-1 session](https://calendly.com/d/cx9p-5yf-2nm/litellm-introductions) with Krrish and Ishaan, the founders, to discuss any issues, provide feedback, or explore how we can improve LiteLLM for you. +**🀝 Schedule a 1-on-1 Session:** Book a [1-on-1 session](https://enterprise.litellm.ai/demo) with Krrish and Ishaan, the founders, to discuss any issues, provide feedback, or explore how we can improve LiteLLM for you.