From fde9062846843b53c802bf78f0298613ee86db4f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 18 Mar 2026 01:24:15 +0000 Subject: [PATCH] fix(ci): stabilize CI - formatting, type errors, test polling, security CVEs, router bug, batch resolution Fix 1: Run Black formatter on 35 files Fix 2: Fix MyPy type errors: - setup_wizard.py: add type annotation for 'selected' set variable - user_api_key_auth.py: remove redundant type annotation on jwt_claims reassignment Fix 3: Fix spend accuracy test burst 2 polling to wait for expected total spend instead of just 'any increase' from burst 2 Fix 4: Bump Next.js 16.1.6 -> 16.1.7 to fix CVE-2026-27978, CVE-2026-27979, CVE-2026-27980, CVE-2026-29057 Fix 5: Fix router _pre_call_checks model variable being overwritten inside loop, causing wrong model lookups on subsequent deployments. Use local _deployment_model variable instead. Fix 6: Add missing resolve_output_file_ids_to_unified call in batch retrieve non-terminal-to-terminal path (matching the terminal path behavior) Co-authored-by: Ishaan Jaff --- litellm/__init__.py | 12 +- litellm/_logging.py | 8 +- litellm/cost_calculator.py | 8 +- .../focus/destinations/factory.py | 7 +- .../langfuse/langfuse_prompt_management.py | 6 +- .../integrations/vantage/vantage_logger.py | 8 +- .../litellm_core_utils/default_encoding.py | 5 +- litellm/litellm_core_utils/litellm_logging.py | 288 +++++++++--------- .../adapters/transformation.py | 2 +- .../llms/base_llm/videos/transformation.py | 16 +- litellm/llms/custom_httpx/llm_http_handler.py | 20 +- litellm/llms/gemini/videos/transformation.py | 31 +- litellm/llms/moonshot/chat/transformation.py | 18 +- .../llms/runwayml/videos/transformation.py | 39 ++- litellm/llms/sagemaker/chat/transformation.py | 4 +- .../llms/vertex_ai/batches/transformation.py | 4 +- .../llms/vertex_ai/videos/transformation.py | 39 ++- litellm/main.py | 4 +- .../mcp_server/mcp_server_manager.py | 2 +- .../mcp_server/rest_endpoints.py | 12 +- litellm/proxy/auth/auth_utils.py | 10 +- litellm/proxy/auth/user_api_key_auth.py | 2 +- litellm/proxy/batches_endpoints/endpoints.py | 3 +- .../mcp_jwt_signer/mcp_jwt_signer.py | 16 +- .../internal_user_endpoints.py | 3 +- .../key_management_endpoints.py | 10 +- .../management_endpoints/team_endpoints.py | 8 +- .../openai_files_endpoints/common_utils.py | 5 +- .../response_polling/background_streaming.py | 4 +- .../proxy/spend_tracking/vantage_endpoints.py | 31 +- litellm/proxy/utils.py | 5 +- litellm/proxy/video_endpoints/utils.py | 4 +- litellm/responses/main.py | 60 ++-- litellm/router.py | 23 +- litellm/setup_wizard.py | 9 +- litellm/types/proxy/vantage_endpoints.py | 3 +- litellm/types/videos/utils.py | 4 +- litellm/videos/main.py | 34 ++- .../test_spend_accuracy_tests.py | 13 +- ui/litellm-dashboard/package-lock.json | 82 ++--- ui/litellm-dashboard/package.json | 2 +- 41 files changed, 493 insertions(+), 371 deletions(-) diff --git a/litellm/__init__.py b/litellm/__init__.py index 51c66838613..7f72e0b0e89 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -1465,9 +1465,15 @@ if TYPE_CHECKING: from .llms.petals.completion.transformation import PetalsConfig as PetalsConfig from .llms.ollama.chat.transformation import OllamaChatConfig as OllamaChatConfig from .llms.ollama.completion.transformation import OllamaConfig as OllamaConfig - from .llms.sagemaker.completion.transformation import SagemakerConfig as SagemakerConfig - from .llms.sagemaker.chat.transformation import SagemakerChatConfig as SagemakerChatConfig - from .llms.sagemaker.nova.transformation import SagemakerNovaConfig as SagemakerNovaConfig + from .llms.sagemaker.completion.transformation import ( + SagemakerConfig as SagemakerConfig, + ) + from .llms.sagemaker.chat.transformation import ( + SagemakerChatConfig as SagemakerChatConfig, + ) + from .llms.sagemaker.nova.transformation import ( + SagemakerNovaConfig as SagemakerNovaConfig, + ) from .llms.cohere.chat.transformation import CohereChatConfig as CohereChatConfig from .llms.anthropic.experimental_pass_through.messages.transformation import ( AnthropicMessagesConfig as AnthropicMessagesConfig, diff --git a/litellm/_logging.py b/litellm/_logging.py index 5de9fbb3558..18c3bcb7e87 100644 --- a/litellm/_logging.py +++ b/litellm/_logging.py @@ -17,7 +17,9 @@ if set_verbose is True: "`litellm.set_verbose` is deprecated. Please set `os.environ['LITELLM_LOG'] = 'DEBUG'` for debug logs." ) -_ENABLE_SECRET_REDACTION = os.getenv("LITELLM_DISABLE_REDACT_SECRETS", "").lower() != "true" +_ENABLE_SECRET_REDACTION = ( + os.getenv("LITELLM_DISABLE_REDACT_SECRETS", "").lower() != "true" +) _REDACTED = "REDACTED" @@ -199,7 +201,9 @@ class JsonFormatter(Formatter): json_record[key] = value if record.exc_info: - json_record["stacktrace"] = record.exc_text or self.formatException(record.exc_info) + json_record["stacktrace"] = record.exc_text or self.formatException( + record.exc_info + ) return safe_dumps(json_record) diff --git a/litellm/cost_calculator.py b/litellm/cost_calculator.py index e0e1e35b94e..ee3c344169b 100644 --- a/litellm/cost_calculator.py +++ b/litellm/cost_calculator.py @@ -1189,7 +1189,9 @@ def completion_cost( # noqa: PLR0915 and _usage["prompt_tokens_details"] != {} and _usage["prompt_tokens_details"] ): - prompt_tokens_details = _usage.get("prompt_tokens_details") or {} + prompt_tokens_details = ( + _usage.get("prompt_tokens_details") or {} + ) cache_read_input_tokens = prompt_tokens_details.get( "cached_tokens", 0 ) @@ -1515,7 +1517,9 @@ def completion_cost( # noqa: PLR0915 if custom_llm_provider == "azure_ai": model_for_additional_costs = request_model_for_cost if completion_response is not None: - hidden_params = getattr(completion_response, "_hidden_params", None) or {} + hidden_params = ( + getattr(completion_response, "_hidden_params", None) or {} + ) hidden_model = hidden_params.get("model") or hidden_params.get( "litellm_model_name" ) diff --git a/litellm/integrations/focus/destinations/factory.py b/litellm/integrations/focus/destinations/factory.py index 01ea6ca9cb4..706e10624ce 100644 --- a/litellm/integrations/focus/destinations/factory.py +++ b/litellm/integrations/focus/destinations/factory.py @@ -59,17 +59,14 @@ class FocusDestinationFactory: return {k: v for k, v in resolved.items() if v is not None} if provider == "vantage": resolved = { - "api_key": overrides.get("api_key") - or os.getenv("VANTAGE_API_KEY"), + "api_key": overrides.get("api_key") or os.getenv("VANTAGE_API_KEY"), "integration_token": overrides.get("integration_token") or os.getenv("VANTAGE_INTEGRATION_TOKEN"), "base_url": overrides.get("base_url") or os.getenv("VANTAGE_BASE_URL", "https://api.vantage.sh"), } if not resolved.get("api_key"): - raise ValueError( - "VANTAGE_API_KEY must be provided for Vantage exports" - ) + raise ValueError("VANTAGE_API_KEY must be provided for Vantage exports") if not resolved.get("integration_token"): raise ValueError( "VANTAGE_INTEGRATION_TOKEN must be provided for Vantage exports" diff --git a/litellm/integrations/langfuse/langfuse_prompt_management.py b/litellm/integrations/langfuse/langfuse_prompt_management.py index 03a93cd988e..bea027aa63d 100644 --- a/litellm/integrations/langfuse/langfuse_prompt_management.py +++ b/litellm/integrations/langfuse/langfuse_prompt_management.py @@ -340,9 +340,9 @@ class LangfusePromptManagement(LangFuseLogger, PromptManagementBase, CustomLogge ) status_message = str(kwargs.get("exception", "Unknown error")) if standard_logging_object is not None: - status_message = standard_logging_object.get( - "error_str", None - ) or status_message + status_message = ( + standard_logging_object.get("error_str", None) or status_message + ) langfuse_logger_to_use.log_event_on_langfuse( start_time=start_time, end_time=end_time, diff --git a/litellm/integrations/vantage/vantage_logger.py b/litellm/integrations/vantage/vantage_logger.py index 6689d932749..e0942472bec 100644 --- a/litellm/integrations/vantage/vantage_logger.py +++ b/litellm/integrations/vantage/vantage_logger.py @@ -83,7 +83,9 @@ class VantageLogger(FocusLogger): verbose_logger.debug( "VantageLogger initialized (integration_token=%s)", - resolved_token[:4] + "***" if resolved_token and len(resolved_token) > 4 else "***", + resolved_token[:4] + "***" + if resolved_token and len(resolved_token) > 4 + else "***", ) async def initialize_focus_export_job(self) -> None: @@ -128,9 +130,7 @@ class VantageLogger(FocusLogger): callback_type=VantageLogger ) if not vantage_loggers: - verbose_logger.debug( - "No Vantage logger registered; skipping scheduler" - ) + verbose_logger.debug("No Vantage logger registered; skipping scheduler") return vantage_logger = cast(VantageLogger, vantage_loggers[0]) diff --git a/litellm/litellm_core_utils/default_encoding.py b/litellm/litellm_core_utils/default_encoding.py index 24533feeccc..f704ba568de 100644 --- a/litellm/litellm_core_utils/default_encoding.py +++ b/litellm/litellm_core_utils/default_encoding.py @@ -26,7 +26,9 @@ if custom_cache_dir: else: cache_dir = filename -os.environ["TIKTOKEN_CACHE_DIR"] = cache_dir # use local copy of tiktoken b/c of - https://github.com/BerriAI/litellm/issues/1071 +os.environ[ + "TIKTOKEN_CACHE_DIR" +] = cache_dir # use local copy of tiktoken b/c of - https://github.com/BerriAI/litellm/issues/1071 import tiktoken import time @@ -48,4 +50,3 @@ for attempt in range(_max_retries): # Exponential backoff with jitter to reduce collision probability delay = _retry_delay * (2**attempt) + random.uniform(0, 0.1) time.sleep(delay) - diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index a92f4cb9ec8..7f5f8f1aa98 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -352,9 +352,9 @@ class Logging(LiteLLMLoggingBaseClass): ) self.function_id = function_id self.streaming_chunks: List[Any] = [] # for generating complete stream response - self.sync_streaming_chunks: List[Any] = ( - [] - ) # for generating complete stream response + self.sync_streaming_chunks: List[ + Any + ] = [] # for generating complete stream response self.log_raw_request_response = log_raw_request_response # Initialize dynamic callbacks @@ -782,9 +782,9 @@ class Logging(LiteLLMLoggingBaseClass): prompt_spec=prompt_spec, dynamic_callback_params=dynamic_callback_params, ): - self.model_call_details["prompt_integration"] = ( - logger.__class__.__name__ - ) + self.model_call_details[ + "prompt_integration" + ] = logger.__class__.__name__ return logger except Exception: # If check fails, continue to next logger @@ -852,9 +852,9 @@ class Logging(LiteLLMLoggingBaseClass): if anthropic_cache_control_logger := AnthropicCacheControlHook.get_custom_logger_for_anthropic_cache_control_hook( non_default_params ): - self.model_call_details["prompt_integration"] = ( - anthropic_cache_control_logger.__class__.__name__ - ) + self.model_call_details[ + "prompt_integration" + ] = anthropic_cache_control_logger.__class__.__name__ return anthropic_cache_control_logger ######################################################### @@ -866,9 +866,9 @@ class Logging(LiteLLMLoggingBaseClass): internal_usage_cache=None, llm_router=None, ) - self.model_call_details["prompt_integration"] = ( - vector_store_custom_logger.__class__.__name__ - ) + self.model_call_details[ + "prompt_integration" + ] = vector_store_custom_logger.__class__.__name__ # Add to global callbacks so post-call hooks are invoked if ( vector_store_custom_logger @@ -928,9 +928,9 @@ class Logging(LiteLLMLoggingBaseClass): model ): # if model name was changes pre-call, overwrite the initial model call name with the new one self.model_call_details["model"] = model - self.model_call_details["litellm_params"]["api_base"] = ( - self._get_masked_api_base(additional_args.get("api_base", "")) - ) + self.model_call_details["litellm_params"][ + "api_base" + ] = self._get_masked_api_base(additional_args.get("api_base", "")) def pre_call(self, input, api_key, model=None, additional_args={}): # noqa: PLR0915 # Log the exact input to the LLM API @@ -959,10 +959,10 @@ class Logging(LiteLLMLoggingBaseClass): try: # [Non-blocking Extra Debug Information in metadata] if turn_off_message_logging is True: - _metadata["raw_request"] = ( - "redacted by litellm. \ + _metadata[ + "raw_request" + ] = "redacted by litellm. \ 'litellm.turn_off_message_logging=True'" - ) else: curl_command = self._get_request_curl_command( api_base=additional_args.get("api_base", ""), @@ -973,34 +973,34 @@ class Logging(LiteLLMLoggingBaseClass): _metadata["raw_request"] = str(curl_command) # split up, so it's easier to parse in the UI - self.model_call_details["raw_request_typed_dict"] = ( - RawRequestTypedDict( - raw_request_api_base=str( - additional_args.get("api_base") or "" - ), - raw_request_body=self._get_raw_request_body( - additional_args.get("complete_input_dict", {}) - ), - # NOTE: setting ignore_sensitive_headers to True will cause - # the Authorization header to be leaked when calls to the health - # endpoint are made and fail. - raw_request_headers=self._get_masked_headers( - additional_args.get("headers", {}) or {}, - ), - error=None, - ) + self.model_call_details[ + "raw_request_typed_dict" + ] = RawRequestTypedDict( + raw_request_api_base=str( + additional_args.get("api_base") or "" + ), + raw_request_body=self._get_raw_request_body( + additional_args.get("complete_input_dict", {}) + ), + # NOTE: setting ignore_sensitive_headers to True will cause + # the Authorization header to be leaked when calls to the health + # endpoint are made and fail. + raw_request_headers=self._get_masked_headers( + additional_args.get("headers", {}) or {}, + ), + error=None, ) except Exception as e: - self.model_call_details["raw_request_typed_dict"] = ( - RawRequestTypedDict( - error=str(e), - ) + self.model_call_details[ + "raw_request_typed_dict" + ] = RawRequestTypedDict( + error=str(e), ) - _metadata["raw_request"] = ( - "Unable to Log \ + _metadata[ + "raw_request" + ] = "Unable to Log \ raw request: {}".format( - str(e) - ) + str(e) ) if getattr(self, "logger_fn", None) and callable(self.logger_fn): try: @@ -1301,13 +1301,13 @@ class Logging(LiteLLMLoggingBaseClass): for callback in callbacks: try: if isinstance(callback, CustomLogger): - response: Optional[MCPPostCallResponseObject] = ( - await callback.async_post_mcp_tool_call_hook( - kwargs=kwargs, - response_obj=post_mcp_tool_call_response_obj, - start_time=start_time, - end_time=end_time, - ) + response: Optional[ + MCPPostCallResponseObject + ] = await callback.async_post_mcp_tool_call_hook( + kwargs=kwargs, + response_obj=post_mcp_tool_call_response_obj, + start_time=start_time, + end_time=end_time, ) ###################################################################### # if any of the callbacks modify the response, use the modified response @@ -1502,9 +1502,9 @@ class Logging(LiteLLMLoggingBaseClass): verbose_logger.debug( f"response_cost_failure_debug_information: {debug_info}" ) - self.model_call_details["response_cost_failure_debug_information"] = ( - debug_info - ) + self.model_call_details[ + "response_cost_failure_debug_information" + ] = debug_info return None try: @@ -1530,9 +1530,9 @@ class Logging(LiteLLMLoggingBaseClass): verbose_logger.debug( f"response_cost_failure_debug_information: {debug_info}" ) - self.model_call_details["response_cost_failure_debug_information"] = ( - debug_info - ) + self.model_call_details[ + "response_cost_failure_debug_information" + ] = debug_info return None @@ -1688,9 +1688,9 @@ class Logging(LiteLLMLoggingBaseClass): result=logging_result ) - self.model_call_details["standard_logging_object"] = ( - self._build_standard_logging_payload(logging_result, start_time, end_time) - ) + self.model_call_details[ + "standard_logging_object" + ] = self._build_standard_logging_payload(logging_result, start_time, end_time) if ( standard_logging_payload := self.model_call_details.get( @@ -1768,9 +1768,9 @@ class Logging(LiteLLMLoggingBaseClass): end_time = datetime.datetime.now() if self.completion_start_time is None: self.completion_start_time = end_time - self.model_call_details["completion_start_time"] = ( - self.completion_start_time - ) + self.model_call_details[ + "completion_start_time" + ] = self.completion_start_time self.model_call_details["log_event_type"] = "successful_api_call" self.model_call_details["end_time"] = end_time @@ -1807,10 +1807,10 @@ class Logging(LiteLLMLoggingBaseClass): end_time=end_time, ) elif isinstance(result, dict) or isinstance(result, list): - self.model_call_details["standard_logging_object"] = ( - self._build_standard_logging_payload( - result, start_time, end_time - ) + self.model_call_details[ + "standard_logging_object" + ] = self._build_standard_logging_payload( + result, start_time, end_time ) if ( standard_logging_payload := self.model_call_details.get( @@ -1819,9 +1819,9 @@ class Logging(LiteLLMLoggingBaseClass): ) is not None: emit_standard_logging_payload(standard_logging_payload) elif standard_logging_object is not None: - self.model_call_details["standard_logging_object"] = ( - standard_logging_object - ) + self.model_call_details[ + "standard_logging_object" + ] = standard_logging_object else: self.model_call_details["response_cost"] = None @@ -1979,17 +1979,17 @@ class Logging(LiteLLMLoggingBaseClass): verbose_logger.debug( "Logging Details LiteLLM-Success Call streaming complete" ) - self.model_call_details["complete_streaming_response"] = ( - complete_streaming_response - ) - self.model_call_details["response_cost"] = ( - self._response_cost_calculator(result=complete_streaming_response) - ) + self.model_call_details[ + "complete_streaming_response" + ] = complete_streaming_response + self.model_call_details[ + "response_cost" + ] = self._response_cost_calculator(result=complete_streaming_response) ## STANDARDIZED LOGGING PAYLOAD - self.model_call_details["standard_logging_object"] = ( - self._build_standard_logging_payload( - complete_streaming_response, start_time, end_time - ) + self.model_call_details[ + "standard_logging_object" + ] = self._build_standard_logging_payload( + complete_streaming_response, start_time, end_time ) if ( standard_logging_payload := self.model_call_details.get( @@ -2323,10 +2323,10 @@ class Logging(LiteLLMLoggingBaseClass): ) else: if self.stream and complete_streaming_response: - self.model_call_details["complete_response"] = ( - self.model_call_details.get( - "complete_streaming_response", {} - ) + self.model_call_details[ + "complete_response" + ] = self.model_call_details.get( + "complete_streaming_response", {} ) result = self.model_call_details["complete_response"] openMeterLogger.log_success_event( @@ -2350,10 +2350,10 @@ class Logging(LiteLLMLoggingBaseClass): ) else: if self.stream and complete_streaming_response: - self.model_call_details["complete_response"] = ( - self.model_call_details.get( - "complete_streaming_response", {} - ) + self.model_call_details[ + "complete_response" + ] = self.model_call_details.get( + "complete_streaming_response", {} ) result = self.model_call_details["complete_response"] @@ -2492,9 +2492,9 @@ class Logging(LiteLLMLoggingBaseClass): if complete_streaming_response is not None: print_verbose("Async success callbacks: Got a complete streaming response") - self.model_call_details["async_complete_streaming_response"] = ( - complete_streaming_response - ) + self.model_call_details[ + "async_complete_streaming_response" + ] = complete_streaming_response try: if self.model_call_details.get("cache_hit", False) is True: @@ -2505,10 +2505,10 @@ class Logging(LiteLLMLoggingBaseClass): model_call_details=self.model_call_details ) # base_model defaults to None if not set on model_info - self.model_call_details["response_cost"] = ( - self._response_cost_calculator( - result=complete_streaming_response - ) + self.model_call_details[ + "response_cost" + ] = self._response_cost_calculator( + result=complete_streaming_response ) verbose_logger.debug( @@ -2521,10 +2521,10 @@ class Logging(LiteLLMLoggingBaseClass): self.model_call_details["response_cost"] = None ## STANDARDIZED LOGGING PAYLOAD - self.model_call_details["standard_logging_object"] = ( - self._build_standard_logging_payload( - complete_streaming_response, start_time, end_time - ) + self.model_call_details[ + "standard_logging_object" + ] = self._build_standard_logging_payload( + complete_streaming_response, start_time, end_time ) # print standard logging payload @@ -2551,9 +2551,9 @@ class Logging(LiteLLMLoggingBaseClass): # _success_handler_helper_fn if self.model_call_details.get("standard_logging_object") is None: ## STANDARDIZED LOGGING PAYLOAD - self.model_call_details["standard_logging_object"] = ( - self._build_standard_logging_payload(result, start_time, end_time) - ) + self.model_call_details[ + "standard_logging_object" + ] = self._build_standard_logging_payload(result, start_time, end_time) # print standard logging payload if ( @@ -2796,18 +2796,18 @@ class Logging(LiteLLMLoggingBaseClass): ## STANDARDIZED LOGGING PAYLOAD - self.model_call_details["standard_logging_object"] = ( - get_standard_logging_object_payload( - kwargs=self.model_call_details, - init_response_obj={}, - start_time=start_time, - end_time=end_time, - logging_obj=self, - status="failure", - error_str=str(exception), - original_exception=exception, - standard_built_in_tools_params=self.standard_built_in_tools_params, - ) + self.model_call_details[ + "standard_logging_object" + ] = get_standard_logging_object_payload( + kwargs=self.model_call_details, + init_response_obj={}, + start_time=start_time, + end_time=end_time, + logging_obj=self, + status="failure", + error_str=str(exception), + original_exception=exception, + standard_built_in_tools_params=self.standard_built_in_tools_params, ) return start_time, end_time @@ -3771,9 +3771,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) @@ -3799,13 +3799,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) @@ -3813,19 +3813,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 ( @@ -3904,7 +3904,9 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915 from litellm.integrations.focus.focus_logger import FocusLogger for callback in _in_memory_loggers: - if type(callback) is FocusLogger: # exact match; exclude subclasses like VantageLogger + if ( + type(callback) is FocusLogger + ): # exact match; exclude subclasses like VantageLogger return callback # type: ignore focus_logger = FocusLogger() _in_memory_loggers.append(focus_logger) @@ -4010,9 +4012,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) @@ -4286,7 +4288,9 @@ def get_custom_logger_compatible_class( # noqa: PLR0915 from litellm.integrations.focus.focus_logger import FocusLogger for callback in _in_memory_loggers: - if type(callback) is FocusLogger: # exact match; exclude subclasses like VantageLogger + if ( + type(callback) is FocusLogger + ): # exact match; exclude subclasses like VantageLogger return callback elif logging_integration == "vantage": from litellm.integrations.vantage.vantage_logger import VantageLogger @@ -4934,10 +4938,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 @@ -5576,9 +5580,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/anthropic/experimental_pass_through/adapters/transformation.py b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py index c1a6bd67501..3fda05172b6 100644 --- a/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py +++ b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py @@ -780,7 +780,7 @@ class LiteLLMAnthropicMessagesAdapter: # Keep Anthropic-native tools in their original format new_tools.append(tool) # type: ignore[arg-type] continue - + original_name = tool["name"] truncated_name = truncate_tool_name(original_name) diff --git a/litellm/llms/base_llm/videos/transformation.py b/litellm/llms/base_llm/videos/transformation.py index a2892e20601..87289ad6a0c 100644 --- a/litellm/llms/base_llm/videos/transformation.py +++ b/litellm/llms/base_llm/videos/transformation.py @@ -336,9 +336,7 @@ class BaseVideoConfig(ABC): Returns: Tuple[str, Dict]: (url, data) for the POST request """ - raise NotImplementedError( - "video edit is not supported for this provider" - ) + raise NotImplementedError("video edit is not supported for this provider") def transform_video_edit_response( self, @@ -346,9 +344,7 @@ class BaseVideoConfig(ABC): logging_obj: LiteLLMLoggingObj, custom_llm_provider: Optional[str] = None, ) -> VideoObject: - raise NotImplementedError( - "video edit is not supported for this provider" - ) + raise NotImplementedError("video edit is not supported for this provider") def transform_video_extension_request( self, @@ -366,9 +362,7 @@ class BaseVideoConfig(ABC): Returns: Tuple[str, Dict]: (url, data) for the POST request """ - raise NotImplementedError( - "video extension is not supported for this provider" - ) + raise NotImplementedError("video extension is not supported for this provider") def transform_video_extension_response( self, @@ -376,9 +370,7 @@ class BaseVideoConfig(ABC): logging_obj: LiteLLMLoggingObj, custom_llm_provider: Optional[str] = None, ) -> VideoObject: - raise NotImplementedError( - "video extension is not supported for this provider" - ) + raise NotImplementedError("video extension is not supported for this provider") def get_error_class( self, error_message: str, status_code: int, headers: Union[dict, httpx.Headers] diff --git a/litellm/llms/custom_httpx/llm_http_handler.py b/litellm/llms/custom_httpx/llm_http_handler.py index 204fa4d0cca..4c9abaad908 100644 --- a/litellm/llms/custom_httpx/llm_http_handler.py +++ b/litellm/llms/custom_httpx/llm_http_handler.py @@ -6162,7 +6162,10 @@ class BaseLLMHTTPHandler: litellm_params=dict(litellm_params), ) - url, files_list = video_provider_config.transform_video_create_character_request( + ( + url, + files_list, + ) = video_provider_config.transform_video_create_character_request( name=name, video=video, api_base=api_base, @@ -6230,7 +6233,10 @@ class BaseLLMHTTPHandler: litellm_params=dict(litellm_params), ) - url, files_list = video_provider_config.transform_video_create_character_request( + ( + url, + files_list, + ) = video_provider_config.transform_video_create_character_request( name=name, video=video, api_base=api_base, @@ -6324,11 +6330,7 @@ class BaseLLMHTTPHandler: ) try: - response = sync_httpx_client.get( - url=url, - headers=headers, - params=params - ) + response = sync_httpx_client.get(url=url, headers=headers, params=params) response.raise_for_status() return video_provider_config.transform_video_get_character_response( raw_response=response, @@ -6386,9 +6388,7 @@ class BaseLLMHTTPHandler: try: response = await async_httpx_client.get( - url=url, - headers=headers, - params=params + url=url, headers=headers, params=params ) response.raise_for_status() return video_provider_config.transform_video_get_character_response( diff --git a/litellm/llms/gemini/videos/transformation.py b/litellm/llms/gemini/videos/transformation.py index 0798472310e..122cc954836 100644 --- a/litellm/llms/gemini/videos/transformation.py +++ b/litellm/llms/gemini/videos/transformation.py @@ -525,28 +525,47 @@ class GeminiVideoConfig(BaseVideoConfig): """Video delete is not supported.""" raise NotImplementedError("Video delete is not supported by Google Veo.") - def transform_video_create_character_request(self, name, video, api_base, litellm_params, headers): + def transform_video_create_character_request( + self, name, video, api_base, litellm_params, headers + ): raise NotImplementedError("video create character is not supported for Gemini") def transform_video_create_character_response(self, raw_response, logging_obj): raise NotImplementedError("video create character is not supported for Gemini") - def transform_video_get_character_request(self, character_id, api_base, litellm_params, headers): + def transform_video_get_character_request( + self, character_id, api_base, litellm_params, headers + ): raise NotImplementedError("video get character is not supported for Gemini") def transform_video_get_character_response(self, raw_response, logging_obj): raise NotImplementedError("video get character is not supported for Gemini") - def transform_video_edit_request(self, prompt, video_id, api_base, litellm_params, headers, extra_body=None): + def transform_video_edit_request( + self, prompt, video_id, api_base, litellm_params, headers, extra_body=None + ): raise NotImplementedError("video edit is not supported for Gemini") - def transform_video_edit_response(self, raw_response, logging_obj, custom_llm_provider=None): + def transform_video_edit_response( + self, raw_response, logging_obj, custom_llm_provider=None + ): raise NotImplementedError("video edit is not supported for Gemini") - def transform_video_extension_request(self, prompt, video_id, seconds, api_base, litellm_params, headers, extra_body=None): + def transform_video_extension_request( + self, + prompt, + video_id, + seconds, + api_base, + litellm_params, + headers, + extra_body=None, + ): raise NotImplementedError("video extension is not supported for Gemini") - def transform_video_extension_response(self, raw_response, logging_obj, custom_llm_provider=None): + def transform_video_extension_response( + self, raw_response, logging_obj, custom_llm_provider=None + ): raise NotImplementedError("video extension is not supported for Gemini") def get_error_class( diff --git a/litellm/llms/moonshot/chat/transformation.py b/litellm/llms/moonshot/chat/transformation.py index 40096be05c9..24f852c28ba 100644 --- a/litellm/llms/moonshot/chat/transformation.py +++ b/litellm/llms/moonshot/chat/transformation.py @@ -19,7 +19,8 @@ class MoonshotChatConfig(OpenAIGPTConfig): @overload def _transform_messages( self, messages: List[AllMessageValues], model: str, is_async: Literal[True] - ) -> Coroutine[Any, Any, List[AllMessageValues]]: ... + ) -> Coroutine[Any, Any, List[AllMessageValues]]: + ... @overload def _transform_messages( @@ -27,7 +28,8 @@ class MoonshotChatConfig(OpenAIGPTConfig): messages: List[AllMessageValues], model: str, is_async: Literal[False] = False, - ) -> List[AllMessageValues]: ... + ) -> List[AllMessageValues]: + ... def _transform_messages( self, messages: List[AllMessageValues], model: str, is_async: bool = False @@ -53,9 +55,13 @@ class MoonshotChatConfig(OpenAIGPTConfig): messages = handle_messages_with_content_list_to_str_conversion(messages) if is_async: - return super()._transform_messages(messages=messages, model=model, is_async=True) + return super()._transform_messages( + messages=messages, model=model, is_async=True + ) else: - return super()._transform_messages(messages=messages, model=model, is_async=False) + return super()._transform_messages( + messages=messages, model=model, is_async=False + ) def _get_openai_compatible_provider_info( self, api_base: Optional[str], api_key: Optional[str] @@ -141,7 +147,9 @@ class MoonshotChatConfig(OpenAIGPTConfig): optional_params["temperature"] = 0.3 return optional_params - def fill_reasoning_content(self, messages: List[AllMessageValues]) -> List[AllMessageValues]: + def fill_reasoning_content( + self, messages: List[AllMessageValues] + ) -> List[AllMessageValues]: """ Moonshot reasoning models require `reasoning_content` on every assistant message that contains tool_calls (multi-turn tool-calling flows). diff --git a/litellm/llms/runwayml/videos/transformation.py b/litellm/llms/runwayml/videos/transformation.py index 2c29c2e21ee..8377dea952e 100644 --- a/litellm/llms/runwayml/videos/transformation.py +++ b/litellm/llms/runwayml/videos/transformation.py @@ -592,28 +592,51 @@ class RunwayMLVideoConfig(BaseVideoConfig): return video_obj - def transform_video_create_character_request(self, name, video, api_base, litellm_params, headers): - raise NotImplementedError("video create character is not supported for RunwayML") + def transform_video_create_character_request( + self, name, video, api_base, litellm_params, headers + ): + raise NotImplementedError( + "video create character is not supported for RunwayML" + ) def transform_video_create_character_response(self, raw_response, logging_obj): - raise NotImplementedError("video create character is not supported for RunwayML") + raise NotImplementedError( + "video create character is not supported for RunwayML" + ) - def transform_video_get_character_request(self, character_id, api_base, litellm_params, headers): + def transform_video_get_character_request( + self, character_id, api_base, litellm_params, headers + ): raise NotImplementedError("video get character is not supported for RunwayML") def transform_video_get_character_response(self, raw_response, logging_obj): raise NotImplementedError("video get character is not supported for RunwayML") - def transform_video_edit_request(self, prompt, video_id, api_base, litellm_params, headers, extra_body=None): + def transform_video_edit_request( + self, prompt, video_id, api_base, litellm_params, headers, extra_body=None + ): raise NotImplementedError("video edit is not supported for RunwayML") - def transform_video_edit_response(self, raw_response, logging_obj, custom_llm_provider=None): + def transform_video_edit_response( + self, raw_response, logging_obj, custom_llm_provider=None + ): raise NotImplementedError("video edit is not supported for RunwayML") - def transform_video_extension_request(self, prompt, video_id, seconds, api_base, litellm_params, headers, extra_body=None): + def transform_video_extension_request( + self, + prompt, + video_id, + seconds, + api_base, + litellm_params, + headers, + extra_body=None, + ): raise NotImplementedError("video extension is not supported for RunwayML") - def transform_video_extension_response(self, raw_response, logging_obj, custom_llm_provider=None): + def transform_video_extension_response( + self, raw_response, logging_obj, custom_llm_provider=None + ): raise NotImplementedError("video extension is not supported for RunwayML") def get_error_class( diff --git a/litellm/llms/sagemaker/chat/transformation.py b/litellm/llms/sagemaker/chat/transformation.py index 60e85c9f93b..3e42c1e8c15 100644 --- a/litellm/llms/sagemaker/chat/transformation.py +++ b/litellm/llms/sagemaker/chat/transformation.py @@ -184,9 +184,7 @@ class SagemakerChatConfig(OpenAIGPTConfig, BaseAWSLLM): llm_provider = LlmProviders(custom_llm_provider) except ValueError: llm_provider = LlmProviders.SAGEMAKER_CHAT - client = get_async_httpx_client( - llm_provider=llm_provider, params={} - ) + client = get_async_httpx_client(llm_provider=llm_provider, params={}) try: response = await client.post( diff --git a/litellm/llms/vertex_ai/batches/transformation.py b/litellm/llms/vertex_ai/batches/transformation.py index 86bdc2c7b5f..c1144654908 100644 --- a/litellm/llms/vertex_ai/batches/transformation.py +++ b/litellm/llms/vertex_ai/batches/transformation.py @@ -142,8 +142,8 @@ class VertexAIBatchTransformation: Gets the output file id from the Vertex AI Batch response """ - output_file_id: str = ( - response.get("outputInfo", OutputInfo()).get("gcsOutputDirectory", "") + output_file_id: str = response.get("outputInfo", OutputInfo()).get( + "gcsOutputDirectory", "" ) if output_file_id: output_file_id = output_file_id.rstrip("/") + "/predictions.jsonl" diff --git a/litellm/llms/vertex_ai/videos/transformation.py b/litellm/llms/vertex_ai/videos/transformation.py index 07b3d6faf70..1c24d657c16 100644 --- a/litellm/llms/vertex_ai/videos/transformation.py +++ b/litellm/llms/vertex_ai/videos/transformation.py @@ -624,28 +624,51 @@ class VertexAIVideoConfig(BaseVideoConfig, VertexBase): """Video delete is not supported.""" raise NotImplementedError("Video delete is not supported by Vertex AI Veo.") - def transform_video_create_character_request(self, name, video, api_base, litellm_params, headers): - raise NotImplementedError("video create character is not supported for Vertex AI") + def transform_video_create_character_request( + self, name, video, api_base, litellm_params, headers + ): + raise NotImplementedError( + "video create character is not supported for Vertex AI" + ) def transform_video_create_character_response(self, raw_response, logging_obj): - raise NotImplementedError("video create character is not supported for Vertex AI") + raise NotImplementedError( + "video create character is not supported for Vertex AI" + ) - def transform_video_get_character_request(self, character_id, api_base, litellm_params, headers): + def transform_video_get_character_request( + self, character_id, api_base, litellm_params, headers + ): raise NotImplementedError("video get character is not supported for Vertex AI") def transform_video_get_character_response(self, raw_response, logging_obj): raise NotImplementedError("video get character is not supported for Vertex AI") - def transform_video_edit_request(self, prompt, video_id, api_base, litellm_params, headers, extra_body=None): + def transform_video_edit_request( + self, prompt, video_id, api_base, litellm_params, headers, extra_body=None + ): raise NotImplementedError("video edit is not supported for Vertex AI") - def transform_video_edit_response(self, raw_response, logging_obj, custom_llm_provider=None): + def transform_video_edit_response( + self, raw_response, logging_obj, custom_llm_provider=None + ): raise NotImplementedError("video edit is not supported for Vertex AI") - def transform_video_extension_request(self, prompt, video_id, seconds, api_base, litellm_params, headers, extra_body=None): + def transform_video_extension_request( + self, + prompt, + video_id, + seconds, + api_base, + litellm_params, + headers, + extra_body=None, + ): raise NotImplementedError("video extension is not supported for Vertex AI") - def transform_video_extension_response(self, raw_response, logging_obj, custom_llm_provider=None): + def transform_video_extension_response( + self, raw_response, logging_obj, custom_llm_provider=None + ): raise NotImplementedError("video extension is not supported for Vertex AI") def get_error_class( diff --git a/litellm/main.py b/litellm/main.py index 81319bc432f..112fef44e55 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -7533,9 +7533,7 @@ def stream_chunk_builder( # noqa: PLR0915 # the final chunk. all_annotations: list = [] for ac in annotation_chunks: - all_annotations.extend( - ac["choices"][0]["delta"]["annotations"] - ) + all_annotations.extend(ac["choices"][0]["delta"]["annotations"]) response["choices"][0]["message"]["annotations"] = all_annotations audio_chunks = [ diff --git a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py index a8e5e60f228..1e9d5c5a529 100644 --- a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py +++ b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py @@ -1946,7 +1946,7 @@ class MCPServerManager: incoming_bearer_token: Optional[str] = None auth_hdr = normalized_raw.get("authorization", "") if auth_hdr.lower().startswith("bearer "): - incoming_bearer_token = auth_hdr[len("bearer "):] + incoming_bearer_token = auth_hdr[len("bearer ") :] pre_hook_kwargs = { "name": name, diff --git a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py index ef01f027d6f..c0151d47e04 100644 --- a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py +++ b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py @@ -903,12 +903,12 @@ if MCP_AVAILABLE: try: client_id, client_secret, scopes = _extract_credentials(request) - _oauth2_flow: Optional[Literal["client_credentials", "authorization_code"]] = ( - request.oauth2_flow or ( - "client_credentials" - if client_id and client_secret and request.token_url - else None - ) + _oauth2_flow: Optional[ + Literal["client_credentials", "authorization_code"] + ] = request.oauth2_flow or ( + "client_credentials" + if client_id and client_secret and request.token_url + else None ) # client_credentials requires token_url to fetch a token; without it the # incoming auth header would be dropped with nothing to replace it. diff --git a/litellm/proxy/auth/auth_utils.py b/litellm/proxy/auth/auth_utils.py index 0d3c627446b..a03e1fb94c1 100644 --- a/litellm/proxy/auth/auth_utils.py +++ b/litellm/proxy/auth/auth_utils.py @@ -680,7 +680,7 @@ def get_customer_user_header_from_mapping(user_id_mapping) -> Optional[list]: if customer_headers_mappings: return customer_headers_mappings - + return None @@ -754,15 +754,11 @@ def get_end_user_id_from_request_body( user_id_str = str(header_value) if user_id_str.strip(): return user_id_str - + elif isinstance(custom_header_name_to_check, str): for header_name, header_value in request_headers.items(): if header_name.lower() == custom_header_name_to_check.lower(): - user_id_str = ( - str(header_value) - if header_value is not None - else "" - ) + user_id_str = str(header_value) if header_value is not None else "" if user_id_str.strip(): return user_id_str diff --git a/litellm/proxy/auth/user_api_key_auth.py b/litellm/proxy/auth/user_api_key_auth.py index 451ed56339d..6443f638ab9 100644 --- a/litellm/proxy/auth/user_api_key_auth.py +++ b/litellm/proxy/auth/user_api_key_auth.py @@ -730,7 +730,7 @@ async def _user_api_key_auth_builder( # noqa: PLR0915 team_membership: Optional[LiteLLM_TeamMembership] = result.get( "team_membership", None ) - jwt_claims: Optional[dict] = result.get("jwt_claims", None) + jwt_claims = result.get("jwt_claims", None) global_proxy_spend = await get_global_proxy_spend( litellm_proxy_admin_name=litellm_proxy_admin_name, diff --git a/litellm/proxy/batches_endpoints/endpoints.py b/litellm/proxy/batches_endpoints/endpoints.py index 740e63b7f17..38e5229eee1 100644 --- a/litellm/proxy/batches_endpoints/endpoints.py +++ b/litellm/proxy/batches_endpoints/endpoints.py @@ -537,9 +537,10 @@ async def retrieve_batch( # noqa: PLR0915 ) # Fix: bug_feb14_batch_retrieve_returns_raw_input_file_id - # Resolve raw provider input_file_id to unified ID. + # Resolve raw provider file IDs (input, output, error) to unified IDs. if unified_batch_id: await resolve_input_file_id_to_unified(response, prisma_client) + await resolve_output_file_ids_to_unified(response, prisma_client) ### ALERTING ### asyncio.create_task( diff --git a/litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/mcp_jwt_signer.py b/litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/mcp_jwt_signer.py index 63997808aa5..5502076829f 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/mcp_jwt_signer.py +++ b/litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/mcp_jwt_signer.py @@ -110,7 +110,7 @@ def _load_private_key_from_env(env_var: str) -> RSAPrivateKey: f"MCPJWTSigner: environment variable '{env_var}' is set but empty." ) if key_material.startswith("file://"): - path = key_material[len("file://"):] + path = key_material[len("file://") :] with open(path, "rb") as f: key_bytes = f.read() else: @@ -273,9 +273,7 @@ class MCPJWTSigner(CustomGuardrail): or "litellm" ) self.audience: str = ( - audience - or os.environ.get("MCP_JWT_AUDIENCE") - or self.DEFAULT_AUDIENCE + audience or os.environ.get("MCP_JWT_AUDIENCE") or self.DEFAULT_AUDIENCE ) resolved_ttl = int( ttl_seconds @@ -395,8 +393,12 @@ class MCPJWTSigner(CustomGuardrail): malformed response doesn't permanently disable JWT verification. """ now = time.time() - cache_expired = (now - self._oidc_discovery_fetched_at) >= self._OIDC_DISCOVERY_TTL - if (self._oidc_discovery_doc is None or cache_expired) and self.access_token_discovery_uri: + cache_expired = ( + now - self._oidc_discovery_fetched_at + ) >= self._OIDC_DISCOVERY_TTL + if ( + self._oidc_discovery_doc is None or cache_expired + ) and self.access_token_discovery_uri: doc = await _fetch_oidc_discovery(self.access_token_discovery_uri) if "jwks_uri" in doc: self._oidc_discovery_doc = doc @@ -560,7 +562,7 @@ class MCPJWTSigner(CustomGuardrail): value: Optional[str] = None if source.startswith("token:"): - claim_name = source[len("token:"):] + claim_name = source[len("token:") :] raw = (jwt_claims or {}).get(claim_name) value = str(raw) if raw else None diff --git a/litellm/proxy/management_endpoints/internal_user_endpoints.py b/litellm/proxy/management_endpoints/internal_user_endpoints.py index 8a71b8d4b59..ca8c345f46c 100644 --- a/litellm/proxy/management_endpoints/internal_user_endpoints.py +++ b/litellm/proxy/management_endpoints/internal_user_endpoints.py @@ -2142,8 +2142,7 @@ async def _resolve_org_filter_for_user_search( member_org_ids: List[str] = [] if caller_user is not None: member_org_ids = [ - m.organization_id - for m in (caller_user.organization_memberships or []) + m.organization_id for m in (caller_user.organization_memberships or []) ] if member_org_ids: diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index e09d7607ebe..1016e6b149c 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -1863,16 +1863,10 @@ async def _validate_update_key_data( user_api_key_cache: Any, ) -> None: """Validate permissions and constraints for key update.""" - _is_proxy_admin = ( - user_api_key_dict.user_role == LitellmUserRoles.PROXY_ADMIN.value - ) + _is_proxy_admin = user_api_key_dict.user_role == LitellmUserRoles.PROXY_ADMIN.value # Prevent non-admin from removing user_id (setting to empty string) (LIT-1884) - if ( - data.user_id is not None - and data.user_id == "" - and not _is_proxy_admin - ): + if data.user_id is not None and data.user_id == "" and not _is_proxy_admin: raise HTTPException( status_code=403, detail="Non-admin users cannot remove the user_id from a key.", diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py index d83ceb1b095..ceb3d5d277a 100644 --- a/litellm/proxy/management_endpoints/team_endpoints.py +++ b/litellm/proxy/management_endpoints/team_endpoints.py @@ -857,7 +857,13 @@ async def new_team( # noqa: PLR0915 # Apply defaults from litellm.default_team_params for any fields # not explicitly provided in the request. - for field in ("max_budget", "budget_duration", "tpm_limit", "rpm_limit", "team_member_permissions"): + for field in ( + "max_budget", + "budget_duration", + "tpm_limit", + "rpm_limit", + "team_member_permissions", + ): if getattr(data, field, None) is None: default_value = _get_default_team_param(field) if default_value is not None: diff --git a/litellm/proxy/openai_files_endpoints/common_utils.py b/litellm/proxy/openai_files_endpoints/common_utils.py index 49f17535333..25ad1b25aad 100644 --- a/litellm/proxy/openai_files_endpoints/common_utils.py +++ b/litellm/proxy/openai_files_endpoints/common_utils.py @@ -857,7 +857,10 @@ async def update_batch_in_database( # If the batch_processed column doesn't exist (old schema), # retry without it so the status update still succeeds. err_str = str(col_err).lower() - if "batch_processed" in err_str and update_data.get("batch_processed") is not None: + if ( + "batch_processed" in err_str + and update_data.get("batch_processed") is not None + ): verbose_proxy_logger.warning( f"batch_processed column not found, retrying update without it: {col_err}" ) diff --git a/litellm/proxy/response_polling/background_streaming.py b/litellm/proxy/response_polling/background_streaming.py index 5ec0aac8e29..5b1b13ffa02 100644 --- a/litellm/proxy/response_polling/background_streaming.py +++ b/litellm/proxy/response_polling/background_streaming.py @@ -115,7 +115,9 @@ async def background_streaming_task( # noqa: PLR0915 UPDATE_INTERVAL = 0.150 # 150ms batching interval # Track the terminal event from the stream (may not be "completed") - terminal_status: Optional[ResponsesAPIStatus] = None # Will be set by response.completed/failed/incomplete/cancelled + terminal_status: Optional[ + ResponsesAPIStatus + ] = None # Will be set by response.completed/failed/incomplete/cancelled terminal_error = None _event_to_status = { "response.completed": "completed", diff --git a/litellm/proxy/spend_tracking/vantage_endpoints.py b/litellm/proxy/spend_tracking/vantage_endpoints.py index 14c0ebcb54d..7d8fbf74615 100644 --- a/litellm/proxy/spend_tracking/vantage_endpoints.py +++ b/litellm/proxy/spend_tracking/vantage_endpoints.py @@ -40,9 +40,7 @@ def _get_registered_vantage_logger(): return None -async def _set_vantage_settings( - api_key: str, integration_token: str, base_url: str -): +async def _set_vantage_settings(api_key: str, integration_token: str, base_url: str): """Store Vantage settings in the database with encrypted API key.""" from litellm.proxy.proxy_server import prisma_client @@ -341,9 +339,7 @@ async def init_vantage_settings( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error( - f"Error initializing Vantage settings: {str(e)}" - ) + verbose_proxy_logger.error(f"Error initializing Vantage settings: {str(e)}") raise HTTPException( status_code=500, detail={"error": f"Failed to initialize Vantage settings: {str(e)}"}, @@ -395,7 +391,8 @@ async def vantage_dry_run_export( """Cast Decimal columns to Float64 so .to_dicts() produces JSON-serializable float values instead of decimal.Decimal.""" decimal_cols = [ - col for col, dtype in zip(frame.columns, frame.dtypes) + col + for col, dtype in zip(frame.columns, frame.dtypes) if isinstance(dtype, pl.Decimal) ] if decimal_cols: @@ -404,8 +401,16 @@ async def vantage_dry_run_export( ) return frame.to_dicts() - usage_sample = _to_json_safe_dicts(data.head(min(50, len(data)))) if not data.is_empty() else [] - normalized_sample = _to_json_safe_dicts(normalized.head(min(50, len(normalized)))) if not normalized.is_empty() else [] + usage_sample = ( + _to_json_safe_dicts(data.head(min(50, len(data)))) + if not data.is_empty() + else [] + ) + normalized_sample = ( + _to_json_safe_dicts(normalized.head(min(50, len(normalized)))) + if not normalized.is_empty() + else [] + ) # Use the same pre-transform column names as # FocusExportEngine.dry_run_export_usage_data for consistency. @@ -437,14 +442,10 @@ async def vantage_dry_run_export( except HTTPException: raise except Exception as e: - verbose_proxy_logger.error( - f"Error performing Vantage dry run export: {str(e)}" - ) + verbose_proxy_logger.error(f"Error performing Vantage dry run export: {str(e)}") raise HTTPException( status_code=500, - detail={ - "error": f"Failed to perform Vantage dry run export: {str(e)}" - }, + detail={"error": f"Failed to perform Vantage dry run export: {str(e)}"}, ) diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index b2ec8899db9..1536deb61cb 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -845,7 +845,10 @@ class ProxyLogging: # key collisions so that the most-specific guardrail (e.g. JWT signer) # takes precedence over earlier ones. existing = modified_kwargs.get("extra_headers") or {} - modified_kwargs["extra_headers"] = {**existing, **response_data["extra_headers"]} + modified_kwargs["extra_headers"] = { + **existing, + **response_data["extra_headers"], + } return modified_kwargs diff --git a/litellm/proxy/video_endpoints/utils.py b/litellm/proxy/video_endpoints/utils.py index 36203bdc77e..689fe4a371b 100644 --- a/litellm/proxy/video_endpoints/utils.py +++ b/litellm/proxy/video_endpoints/utils.py @@ -7,7 +7,9 @@ from litellm.types.videos.utils import encode_character_id_with_provider def extract_model_from_target_model_names(target_model_names: Any) -> Optional[str]: if isinstance(target_model_names, str): - target_model_names = [m.strip() for m in target_model_names.split(",") if m.strip()] + target_model_names = [ + m.strip() for m in target_model_names.split(",") if m.strip() + ] elif not isinstance(target_model_names, list): return None return target_model_names[0] if target_model_names else None diff --git a/litellm/responses/main.py b/litellm/responses/main.py index cd9ce67c26e..2a320517a4c 100644 --- a/litellm/responses/main.py +++ b/litellm/responses/main.py @@ -692,11 +692,11 @@ def responses( return run_async_function(aresponses_api_with_mcp, **mcp_call_kwargs) # get provider config - responses_api_provider_config: Optional[BaseResponsesAPIConfig] = ( - ProviderConfigManager.get_provider_responses_api_config( - model=model, - provider=custom_llm_provider, - ) + responses_api_provider_config: Optional[ + BaseResponsesAPIConfig + ] = ProviderConfigManager.get_provider_responses_api_config( + model=model, + provider=custom_llm_provider, ) local_vars.update(kwargs) @@ -908,11 +908,11 @@ def delete_responses( raise ValueError("custom_llm_provider is required but passed as None") # get provider config - responses_api_provider_config: Optional[BaseResponsesAPIConfig] = ( - ProviderConfigManager.get_provider_responses_api_config( - model=None, - provider=custom_llm_provider, - ) + responses_api_provider_config: Optional[ + BaseResponsesAPIConfig + ] = ProviderConfigManager.get_provider_responses_api_config( + model=None, + provider=custom_llm_provider, ) if responses_api_provider_config is None: @@ -1089,11 +1089,11 @@ def get_responses( raise ValueError("custom_llm_provider is required but passed as None") # get provider config - responses_api_provider_config: Optional[BaseResponsesAPIConfig] = ( - ProviderConfigManager.get_provider_responses_api_config( - model=None, - provider=custom_llm_provider, - ) + responses_api_provider_config: Optional[ + BaseResponsesAPIConfig + ] = ProviderConfigManager.get_provider_responses_api_config( + model=None, + provider=custom_llm_provider, ) if responses_api_provider_config is None: @@ -1247,11 +1247,11 @@ def list_input_items( if custom_llm_provider is None: raise ValueError("custom_llm_provider is required but passed as None") - responses_api_provider_config: Optional[BaseResponsesAPIConfig] = ( - ProviderConfigManager.get_provider_responses_api_config( - model=None, - provider=custom_llm_provider, - ) + responses_api_provider_config: Optional[ + BaseResponsesAPIConfig + ] = ProviderConfigManager.get_provider_responses_api_config( + model=None, + provider=custom_llm_provider, ) if responses_api_provider_config is None: @@ -1406,11 +1406,11 @@ def cancel_responses( raise ValueError("custom_llm_provider is required but passed as None") # get provider config - responses_api_provider_config: Optional[BaseResponsesAPIConfig] = ( - ProviderConfigManager.get_provider_responses_api_config( - model=None, - provider=custom_llm_provider, - ) + responses_api_provider_config: Optional[ + BaseResponsesAPIConfig + ] = ProviderConfigManager.get_provider_responses_api_config( + model=None, + provider=custom_llm_provider, ) if responses_api_provider_config is None: @@ -1594,11 +1594,11 @@ def compact_responses( raise ValueError("custom_llm_provider is required but passed as None") # get provider config - responses_api_provider_config: Optional[BaseResponsesAPIConfig] = ( - ProviderConfigManager.get_provider_responses_api_config( - model=model, - provider=custom_llm_provider, - ) + responses_api_provider_config: Optional[ + BaseResponsesAPIConfig + ] = ProviderConfigManager.get_provider_responses_api_config( + model=model, + provider=custom_llm_provider, ) if responses_api_provider_config is None: diff --git a/litellm/router.py b/litellm/router.py index f34368172ac..46998abb160 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -8611,6 +8611,7 @@ class Router: _model_info = deployment.get("model_info", {}) # see if we have the info for this model + _deployment_model = None # per-deployment model name (avoids overwriting the outer `model` group name) try: base_model = _model_info.get("base_model", None) if base_model is None: @@ -8618,7 +8619,7 @@ class Router: model_info = self.get_router_model_info( deployment=deployment, received_model_name=model ) - model = base_model or _litellm_params.get("model", None) + _deployment_model = base_model or _litellm_params.get("model", None) if ( isinstance(model_info, dict) @@ -8632,7 +8633,9 @@ class Router: _context_window_error = True _potential_error_str += ( "Model={}, Max Input Tokens={}, Got={}".format( - model, model_info["max_input_tokens"], input_tokens + _deployment_model, + model_info["max_input_tokens"], + input_tokens, ) ) continue @@ -8688,13 +8691,21 @@ class Router: ## INVALID PARAMS ## -> catch 'gpt-3.5-turbo-16k' not supporting 'response_format' param if request_kwargs is not None and litellm.drop_params is False: - # get supported params - model, custom_llm_provider, _, _ = litellm.get_llm_provider( - model=model, litellm_params=LiteLLM_Params(**_litellm_params) + # get supported params — use per-deployment model to avoid overwriting the outer model group name + _dep_model_for_params = _deployment_model or model + ( + _dep_model_for_params, + custom_llm_provider, + _, + _, + ) = litellm.get_llm_provider( + model=_dep_model_for_params, + litellm_params=LiteLLM_Params(**_litellm_params), ) supported_openai_params = litellm.get_supported_openai_params( - model=model, custom_llm_provider=custom_llm_provider + model=_dep_model_for_params, + custom_llm_provider=custom_llm_provider, ) if supported_openai_params is None: diff --git a/litellm/setup_wizard.py b/litellm/setup_wizard.py index 38a31a25993..ee5918e1273 100644 --- a/litellm/setup_wizard.py +++ b/litellm/setup_wizard.py @@ -319,7 +319,8 @@ class SetupWizard: @staticmethod def _select_interactive() -> List[Dict]: - cursor, selected = 0, set() + cursor = 0 + selected: set[int] = set() if _supports_color(): sys.stdout.write(_CURSOR_HIDE) @@ -432,9 +433,9 @@ class SetupWizard: f" {blue('❯')} Azure deployment name {grey('(e.g. my-gpt4o)')}: " ) if deployment: - env_vars[f"_LITELLM_AZURE_DEPLOYMENT_{p['id'].upper()}"] = ( - deployment - ) + env_vars[ + f"_LITELLM_AZURE_DEPLOYMENT_{p['id'].upper()}" + ] = deployment # Store the key returned by validation — may be a re-entered replacement env_vars[p["env_key"]] = SetupWizard._validate_and_report(p, key) diff --git a/litellm/types/proxy/vantage_endpoints.py b/litellm/types/proxy/vantage_endpoints.py index cf4f0a6685f..84199e78340 100644 --- a/litellm/types/proxy/vantage_endpoints.py +++ b/litellm/types/proxy/vantage_endpoints.py @@ -39,7 +39,8 @@ class VantageExportRequest(BaseModel): """Request model for Vantage export operations (actual export, no default limit)""" limit: Optional[int] = Field( - None, description="Optional limit on number of records to export (default: no limit)" + None, + description="Optional limit on number of records to export (default: no limit)", ) start_time_utc: Optional[datetime] = Field( None, description="Start time for data export in UTC" diff --git a/litellm/types/videos/utils.py b/litellm/types/videos/utils.py index 3a100129bcd..bf51fdda370 100644 --- a/litellm/types/videos/utils.py +++ b/litellm/types/videos/utils.py @@ -195,7 +195,9 @@ def decode_character_id_with_provider(encoded_character_id: str) -> DecodedChara character_id=decoded_character_id, ) except Exception as e: - verbose_logger.debug(f"Error decoding character_id '{encoded_character_id}': {e}") + verbose_logger.debug( + f"Error decoding character_id '{encoded_character_id}': {e}" + ) return DecodedCharacterId( custom_llm_provider=None, model_id=None, diff --git a/litellm/videos/main.py b/litellm/videos/main.py index d32a873e0b7..cd61293cd1c 100644 --- a/litellm/videos/main.py +++ b/litellm/videos/main.py @@ -1186,13 +1186,17 @@ def video_create_character( litellm_params = GenericLiteLLMParams(**kwargs) - provider_config: Optional[BaseVideoConfig] = ProviderConfigManager.get_provider_video_config( + provider_config: Optional[ + BaseVideoConfig + ] = ProviderConfigManager.get_provider_video_config( model=None, provider=litellm.LlmProviders(custom_llm_provider), ) if provider_config is None: - raise ValueError(f"video create character is not supported for {custom_llm_provider}") + raise ValueError( + f"video create character is not supported for {custom_llm_provider}" + ) local_vars.update(kwargs) request_params: Dict = {"name": name} @@ -1311,13 +1315,17 @@ def video_get_character( litellm_params = GenericLiteLLMParams(**kwargs) - provider_config: Optional[BaseVideoConfig] = ProviderConfigManager.get_provider_video_config( + provider_config: Optional[ + BaseVideoConfig + ] = ProviderConfigManager.get_provider_video_config( model=None, provider=litellm.LlmProviders(custom_llm_provider), ) if provider_config is None: - raise ValueError(f"video get character is not supported for {custom_llm_provider}") + raise ValueError( + f"video get character is not supported for {custom_llm_provider}" + ) local_vars.update(kwargs) request_params: Dict = {"character_id": character_id} @@ -1439,7 +1447,9 @@ def video_edit( litellm_params = GenericLiteLLMParams(**kwargs) - provider_config: Optional[BaseVideoConfig] = ProviderConfigManager.get_provider_video_config( + provider_config: Optional[ + BaseVideoConfig + ] = ProviderConfigManager.get_provider_video_config( model=None, provider=litellm.LlmProviders(custom_llm_provider), ) @@ -1572,16 +1582,24 @@ def video_extension( litellm_params = GenericLiteLLMParams(**kwargs) - provider_config: Optional[BaseVideoConfig] = ProviderConfigManager.get_provider_video_config( + provider_config: Optional[ + BaseVideoConfig + ] = ProviderConfigManager.get_provider_video_config( model=None, provider=litellm.LlmProviders(custom_llm_provider), ) if provider_config is None: - raise ValueError(f"video extension is not supported for {custom_llm_provider}") + raise ValueError( + f"video extension is not supported for {custom_llm_provider}" + ) local_vars.update(kwargs) - request_params: Dict = {"video_id": video_id, "prompt": prompt, "seconds": seconds} + request_params: Dict = { + "video_id": video_id, + "prompt": prompt, + "seconds": seconds, + } litellm_logging_obj.update_environment_variables( model="", diff --git a/tests/spend_tracking_tests/test_spend_accuracy_tests.py b/tests/spend_tracking_tests/test_spend_accuracy_tests.py index 11b8e209dc1..90efe28ab84 100644 --- a/tests/spend_tracking_tests/test_spend_accuracy_tests.py +++ b/tests/spend_tracking_tests/test_spend_accuracy_tests.py @@ -308,16 +308,19 @@ async def test_long_term_spend_accuracy_with_bursts(): response = await chat_completion(session, key) print(f"Burst 2 - Request {i + 1}/{BURST_2_REQUESTS} completed") - # Poll until key spend reflects burst 2 - burst_1_spend = intermediate_key_info["info"]["spend"] + # Poll until key spend reaches expected total (burst 1 + burst 2) start = time.time() while time.time() - start < 120: key_info_check = await get_spend_info(session, "key", key) current_spend = key_info_check["info"]["spend"] - if current_spend > burst_1_spend: - print(f"Key spend increased to {current_spend} after {time.time() - start:.1f}s") + if abs(current_spend - expected_spend) < TOLERANCE: + print( + f"Total spend reached expected {expected_spend} after {time.time() - start:.1f}s" + ) break - print(f"Key spend still {current_spend}, waiting for burst 2 flush...") + print( + f"Key spend {current_spend}, expected {expected_spend}, waiting..." + ) await asyncio.sleep(10) # Allow extra time for all entity spend aggregations diff --git a/ui/litellm-dashboard/package-lock.json b/ui/litellm-dashboard/package-lock.json index c062356ebbd..30249ac78dd 100644 --- a/ui/litellm-dashboard/package-lock.json +++ b/ui/litellm-dashboard/package-lock.json @@ -23,7 +23,7 @@ "jwt-decode": "^4.0.0", "lucide-react": "^0.513.0", "moment": "^2.30.1", - "next": "^16.1.6", + "next": "^16.1.7", "openai": "^4.93.0", "papaparse": "^5.5.2", "react": "^18.3.1", @@ -1828,9 +1828,9 @@ } }, "node_modules/@next/env": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", - "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.7.tgz", + "integrity": "sha512-rJJbIdJB/RQr2F1nylZr/PJzamvNNhfr3brdKP6s/GW850jbtR70QlSfFselvIBbcPUOlQwBakexjFzqLzF6pg==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -1844,9 +1844,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz", - "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.7.tgz", + "integrity": "sha512-b2wWIE8sABdyafc4IM8r5Y/dS6kD80JRtOGrUiKTsACFQfWWgUQ2NwoUX1yjFMXVsAwcQeNpnucF2ZrujsBBPg==", "cpu": [ "arm64" ], @@ -1860,9 +1860,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", - "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.7.tgz", + "integrity": "sha512-zcnVaaZulS1WL0Ss38R5Q6D2gz7MtBu8GZLPfK+73D/hp4GFMrC2sudLky1QibfV7h6RJBJs/gOFvYP0X7UVlQ==", "cpu": [ "x64" ], @@ -1876,9 +1876,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", - "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.7.tgz", + "integrity": "sha512-2ant89Lux/Q3VyC8vNVg7uBaFVP9SwoK2jJOOR0L8TQnX8CAYnh4uctAScy2Hwj2dgjVHqHLORQZJ2wH6VxhSQ==", "cpu": [ "arm64" ], @@ -1892,9 +1892,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", - "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.7.tgz", + "integrity": "sha512-uufcze7LYv0FQg9GnNeZ3/whYfo+1Q3HnQpm16o6Uyi0OVzLlk2ZWoY7j07KADZFY8qwDbsmFnMQP3p3+Ftprw==", "cpu": [ "arm64" ], @@ -1908,9 +1908,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", - "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.7.tgz", + "integrity": "sha512-KWVf2gxYvHtvuT+c4MBOGxuse5TD7DsMFYSxVxRBnOzok/xryNeQSjXgxSv9QpIVlaGzEn/pIuI6Koosx8CGWA==", "cpu": [ "x64" ], @@ -1924,9 +1924,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", - "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.7.tgz", + "integrity": "sha512-HguhaGwsGr1YAGs68uRKc4aGWxLET+NevJskOcCAwXbwj0fYX0RgZW2gsOCzr9S11CSQPIkxmoSbuVaBp4Z3dA==", "cpu": [ "x64" ], @@ -1940,9 +1940,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", - "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.7.tgz", + "integrity": "sha512-S0n3KrDJokKTeFyM/vGGGR8+pCmXYrjNTk2ZozOL1C/JFdfUIL9O1ATaJOl5r2POe56iRChbsszrjMAdWSv7kQ==", "cpu": [ "arm64" ], @@ -1956,9 +1956,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", - "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.7.tgz", + "integrity": "sha512-mwgtg8CNZGYm06LeEd+bNnOUfwOyNem/rOiP14Lsz+AnUY92Zq/LXwtebtUiaeVkhbroRCQ0c8GlR4UT1U+0yg==", "cpu": [ "x64" ], @@ -9343,14 +9343,14 @@ "license": "MIT" }, "node_modules/next": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", - "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==", + "version": "16.1.7", + "resolved": "https://registry.npmjs.org/next/-/next-16.1.7.tgz", + "integrity": "sha512-WM0L7WrSvKwoLegLYr6V+mz+RIofqQgVAfHhMp9a88ms0cFX8iX9ew+snpWlSBwpkURJOUdvCEt3uLl3NNzvWg==", "license": "MIT", "dependencies": { - "@next/env": "16.1.6", + "@next/env": "16.1.7", "@swc/helpers": "0.5.15", - "baseline-browser-mapping": "^2.8.3", + "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" @@ -9362,14 +9362,14 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.1.6", - "@next/swc-darwin-x64": "16.1.6", - "@next/swc-linux-arm64-gnu": "16.1.6", - "@next/swc-linux-arm64-musl": "16.1.6", - "@next/swc-linux-x64-gnu": "16.1.6", - "@next/swc-linux-x64-musl": "16.1.6", - "@next/swc-win32-arm64-msvc": "16.1.6", - "@next/swc-win32-x64-msvc": "16.1.6", + "@next/swc-darwin-arm64": "16.1.7", + "@next/swc-darwin-x64": "16.1.7", + "@next/swc-linux-arm64-gnu": "16.1.7", + "@next/swc-linux-arm64-musl": "16.1.7", + "@next/swc-linux-x64-gnu": "16.1.7", + "@next/swc-linux-x64-musl": "16.1.7", + "@next/swc-win32-arm64-msvc": "16.1.7", + "@next/swc-win32-x64-msvc": "16.1.7", "sharp": "^0.34.4" }, "peerDependencies": { diff --git a/ui/litellm-dashboard/package.json b/ui/litellm-dashboard/package.json index 2a9bb3e5e20..fce2e09b54c 100644 --- a/ui/litellm-dashboard/package.json +++ b/ui/litellm-dashboard/package.json @@ -35,7 +35,7 @@ "jwt-decode": "^4.0.0", "lucide-react": "^0.513.0", "moment": "^2.30.1", - "next": "^16.1.6", + "next": "^16.1.7", "openai": "^4.93.0", "papaparse": "^5.5.2", "react": "^18.3.1",