From 9942d59631934cc3f9fe1994618e4cf6d9f736b5 Mon Sep 17 00:00:00 2001 From: Joe Reyna Date: Tue, 31 Mar 2026 07:45:55 -0700 Subject: [PATCH] fix(lint): apply Black formatting to 14 files (#24532) --- .../transformation.py | 4 +- litellm/integrations/prometheus.py | 4 +- .../a2a/chat/guardrail_translation/handler.py | 8 +- .../chat/guardrail_translation/handler.py | 17 +- .../bedrock/chat/converse_transformation.py | 311 +++++++++++++----- .../chat/guardrail_translation/handler.py | 6 +- litellm/proxy/auth/auth_checks.py | 5 +- litellm/proxy/auth/handle_jwt.py | 4 +- .../proxy/common_utils/reset_budget_job.py | 12 +- .../internal_user_endpoints.py | 2 +- litellm/proxy/management_endpoints/ui_sso.py | 10 +- .../proxy/management_helpers/audit_logs.py | 14 +- litellm/proxy/proxy_server.py | 19 +- litellm/proxy/utils.py | 12 +- 14 files changed, 305 insertions(+), 123 deletions(-) diff --git a/litellm/completion_extras/litellm_responses_transformation/transformation.py b/litellm/completion_extras/litellm_responses_transformation/transformation.py index a387418ef5..ff1bc0d383 100644 --- a/litellm/completion_extras/litellm_responses_transformation/transformation.py +++ b/litellm/completion_extras/litellm_responses_transformation/transformation.py @@ -96,7 +96,9 @@ def _build_reasoning_item( } -def _reasoning_item_to_response_input(r_item: Union[ChatCompletionReasoningItem, Dict[str, Any]]) -> Dict[str, Any]: +def _reasoning_item_to_response_input( + r_item: Union[ChatCompletionReasoningItem, Dict[str, Any]] +) -> Dict[str, Any]: """Convert a stored ChatCompletionReasoningItem back to a Responses API input item.""" r_input: Dict[str, Any] = { "type": "reasoning", diff --git a/litellm/integrations/prometheus.py b/litellm/integrations/prometheus.py index 294b9d464f..fb5fc253ae 100644 --- a/litellm/integrations/prometheus.py +++ b/litellm/integrations/prometheus.py @@ -2789,9 +2789,7 @@ class PrometheusLogger(CustomLogger): ) return - async def fetch_orgs( - page_size: int, page: int - ) -> Tuple[list, Optional[int]]: + async def fetch_orgs(page_size: int, page: int) -> Tuple[list, Optional[int]]: skip = (page - 1) * page_size orgs = await prisma_client.db.litellm_organizationtable.find_many( skip=skip, diff --git a/litellm/llms/a2a/chat/guardrail_translation/handler.py b/litellm/llms/a2a/chat/guardrail_translation/handler.py index fe05bf90f8..3d6037b1f8 100644 --- a/litellm/llms/a2a/chat/guardrail_translation/handler.py +++ b/litellm/llms/a2a/chat/guardrail_translation/handler.py @@ -238,8 +238,8 @@ class A2AGuardrailHandler(BaseTranslation): if not valid_parsed: return responses_so_far - combined_text, chunk_indices_with_text = ( - self._collect_text_from_parsed_chunks(valid_parsed) + combined_text, chunk_indices_with_text = self._collect_text_from_parsed_chunks( + valid_parsed ) if not combined_text: return responses_so_far @@ -316,9 +316,7 @@ class A2AGuardrailHandler(BaseTranslation): def _parse_streaming_responses( self, responses_so_far: List[Any], - ) -> Tuple[ - List[Optional[Dict[str, Any]]], List[Tuple[int, Dict[str, Any]]] - ]: + ) -> Tuple[List[Optional[Dict[str, Any]]], List[Tuple[int, Dict[str, Any]]]]: """Parse JSON-RPC items, returning aligned parsed list and valid entries.""" parsed: List[Optional[Dict[str, Any]]] = [None] * len(responses_so_far) for i, item in enumerate(responses_so_far): diff --git a/litellm/llms/anthropic/chat/guardrail_translation/handler.py b/litellm/llms/anthropic/chat/guardrail_translation/handler.py index ad888f49e3..d31a0a091e 100644 --- a/litellm/llms/anthropic/chat/guardrail_translation/handler.py +++ b/litellm/llms/anthropic/chat/guardrail_translation/handler.py @@ -284,18 +284,27 @@ class AnthropicMessagesHandler(BaseTranslation): # Step 1: Extract all text content and tool calls from response self._extract_from_content_blocks( - response_content, texts_to_check, images_to_check, - task_mappings, tool_calls_to_check, + response_content, + texts_to_check, + images_to_check, + task_mappings, + tool_calls_to_check, ) # Step 2: Apply guardrail to all texts in batch if texts_to_check or tool_calls_to_check: request_data = self._prepare_request_data( - request_data, response, user_api_key_dict, key="response", + request_data, + response, + user_api_key_dict, + key="response", ) inputs = self._build_guardrail_inputs( - texts_to_check, images_to_check, tool_calls_to_check, response, + texts_to_check, + images_to_check, + tool_calls_to_check, + response, ) guardrailed_inputs = await guardrail_to_apply.apply_guardrail( diff --git a/litellm/llms/bedrock/chat/converse_transformation.py b/litellm/llms/bedrock/chat/converse_transformation.py index 90b501a9cb..5cfb00d69b 100644 --- a/litellm/llms/bedrock/chat/converse_transformation.py +++ b/litellm/llms/bedrock/chat/converse_transformation.py @@ -160,7 +160,8 @@ class AmazonConverseConfig(BaseConfig): if isinstance(content, list): has_guarded_text = any( - isinstance(item, dict) and item.get("type") == "guarded_text" for item in content + isinstance(item, dict) and item.get("type") == "guarded_text" + for item in content ) if has_guarded_text: continue # Skip this message if it already has guarded_text @@ -321,9 +322,13 @@ class AmazonConverseConfig(BaseConfig): # Check if the model is a Nova 2 model (matches nova-2-lite, nova-2-pro, etc.) # Also check for nova-2/ spec prefix for imported models - return model_without_region.startswith("amazon.nova-2-") or model_without_region.startswith("nova-2/") + return model_without_region.startswith( + "amazon.nova-2-" + ) or model_without_region.startswith("nova-2/") - def _map_web_search_options(self, web_search_options: dict, model: str) -> Optional[BedrockToolBlock]: + def _map_web_search_options( + self, web_search_options: dict, model: str + ) -> Optional[BedrockToolBlock]: """ Map web_search_options to Nova grounding systemTool. @@ -352,7 +357,9 @@ class AmazonConverseConfig(BaseConfig): # (unlike Anthropic), so we just enable grounding with no options return BedrockToolBlock(systemTool={"name": "nova_grounding"}) - def _transform_reasoning_effort_to_reasoning_config(self, reasoning_effort: str) -> dict: + def _transform_reasoning_effort_to_reasoning_config( + self, reasoning_effort: str + ) -> dict: """ Transform reasoning_effort parameter to Nova 2 reasoningConfig structure. @@ -397,7 +404,9 @@ class AmazonConverseConfig(BaseConfig): } } - def _handle_reasoning_effort_parameter(self, model: str, reasoning_effort: str, optional_params: dict) -> None: + def _handle_reasoning_effort_parameter( + self, model: str, reasoning_effort: str, optional_params: dict + ) -> None: """ Handle the reasoning_effort parameter based on the model type. @@ -434,7 +443,9 @@ class AmazonConverseConfig(BaseConfig): optional_params["reasoning_effort"] = reasoning_effort elif self._is_nova_2_model(model): # Nova 2 models: transform to reasoningConfig - reasoning_config = self._transform_reasoning_effort_to_reasoning_config(reasoning_effort) + reasoning_config = self._transform_reasoning_effort_to_reasoning_config( + reasoning_effort + ) optional_params.update(reasoning_config) else: # Anthropic and other models: convert to thinking parameter @@ -478,7 +489,9 @@ class AmazonConverseConfig(BaseConfig): "parallel_tool_calls", ] - if "arn" in model: # we can't infer the model from the arn, so just add all params + if ( + "arn" in model + ): # we can't infer the model from the arn, so just add all params supported_params.append("tools") supported_params.append("tool_choice") supported_params.append("thinking") @@ -500,7 +513,9 @@ class AmazonConverseConfig(BaseConfig): or base_model.startswith("meta.llama3-3") or base_model.startswith("meta.llama4") or base_model.startswith("amazon.nova") - or supports_function_calling(model=model, custom_llm_provider=self.custom_llm_provider) + or supports_function_calling( + model=model, custom_llm_provider=self.custom_llm_provider + ) ): supported_params.append("tools") @@ -510,7 +525,9 @@ class AmazonConverseConfig(BaseConfig): if litellm.utils.supports_tool_choice( model=model, custom_llm_provider=self.custom_llm_provider - ) or litellm.utils.supports_tool_choice(model=base_model, custom_llm_provider=self.custom_llm_provider): + ) or litellm.utils.supports_tool_choice( + model=base_model, custom_llm_provider=self.custom_llm_provider + ): # only anthropic and mistral support tool choice config. otherwise (E.g. cohere) will fail the call - https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ToolChoice.html supported_params.append("tool_choice") @@ -529,7 +546,9 @@ class AmazonConverseConfig(BaseConfig): model=model, custom_llm_provider=self.custom_llm_provider, ) - or supports_reasoning(model=base_model, custom_llm_provider=self.custom_llm_provider) + or supports_reasoning( + model=base_model, custom_llm_provider=self.custom_llm_provider + ) ): supported_params.append("thinking") supported_params.append("reasoning_effort") @@ -554,7 +573,9 @@ class AmazonConverseConfig(BaseConfig): return ToolChoiceValuesBlock(auto={}) elif isinstance(tool_choice, dict): # only supported for anthropic + mistral models - https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ToolChoice.html - specific_tool = SpecificToolChoiceBlock(name=tool_choice.get("function", {}).get("name", "")) + specific_tool = SpecificToolChoiceBlock( + name=tool_choice.get("function", {}).get("name", "") + ) return ToolChoiceValuesBlock(tool=specific_tool) else: raise litellm.utils.UnsupportedParamsError( @@ -574,9 +595,15 @@ class AmazonConverseConfig(BaseConfig): return ["mp4", "mov", "mkv", "webm", "flv", "mpeg", "mpg", "wmv", "3gp"] def get_all_supported_content_types(self) -> List[str]: - return self.get_supported_image_types() + self.get_supported_document_types() + self.get_supported_video_types() + return ( + self.get_supported_image_types() + + self.get_supported_document_types() + + self.get_supported_video_types() + ) - def is_computer_use_tool_used(self, tools: Optional[List[OpenAIChatCompletionToolParam]], model: str) -> bool: + def is_computer_use_tool_used( + self, tools: Optional[List[OpenAIChatCompletionToolParam]], model: str + ) -> bool: """Check if computer use tools are being used in the request.""" if tools is None: return False @@ -589,7 +616,9 @@ class AmazonConverseConfig(BaseConfig): return True return False - def _transform_computer_use_tools(self, computer_use_tools: List[OpenAIChatCompletionToolParam]) -> List[dict]: + def _transform_computer_use_tools( + self, computer_use_tools: List[OpenAIChatCompletionToolParam] + ) -> List[dict]: """Transform computer use tools to Bedrock format.""" transformed_tools: List[dict] = [] @@ -631,7 +660,9 @@ class AmazonConverseConfig(BaseConfig): def _separate_computer_use_tools( self, tools: List[OpenAIChatCompletionToolParam], model: str - ) -> Tuple[List[OpenAIChatCompletionToolParam], List[OpenAIChatCompletionToolParam]]: + ) -> Tuple[ + List[OpenAIChatCompletionToolParam], List[OpenAIChatCompletionToolParam] + ]: """ Separate computer use tools from regular function tools. @@ -740,18 +771,25 @@ class AmazonConverseConfig(BaseConfig): # Recurse into nested schemas if "properties" in result and isinstance(result["properties"], dict): result["properties"] = { - k: AmazonConverseConfig._add_additional_properties_to_schema(v) for k, v in result["properties"].items() + k: AmazonConverseConfig._add_additional_properties_to_schema(v) + for k, v in result["properties"].items() } if "items" in result and isinstance(result["items"], dict): - result["items"] = AmazonConverseConfig._add_additional_properties_to_schema(result["items"]) + result["items"] = AmazonConverseConfig._add_additional_properties_to_schema( + result["items"] + ) for defs_key in ("$defs", "definitions"): if defs_key in result and isinstance(result[defs_key], dict): result[defs_key] = { - k: AmazonConverseConfig._add_additional_properties_to_schema(v) for k, v in result[defs_key].items() + k: AmazonConverseConfig._add_additional_properties_to_schema(v) + for k, v in result[defs_key].items() } for key in ("anyOf", "allOf", "oneOf"): if key in result and isinstance(result[key], list): - result[key] = [AmazonConverseConfig._add_additional_properties_to_schema(item) for item in result[key]] + result[key] = [ + AmazonConverseConfig._add_additional_properties_to_schema(item) + for item in result[key] + ] return result @@ -781,7 +819,9 @@ class AmazonConverseConfig(BaseConfig): } """ if json_schema is not None: - json_schema = AmazonConverseConfig._add_additional_properties_to_schema(json_schema) + json_schema = AmazonConverseConfig._add_additional_properties_to_schema( + json_schema + ) schema_str = json.dumps(json_schema) if json_schema is not None else "{}" json_schema_def: JsonSchemaDefinition = {"schema": schema_str} if name is not None: @@ -803,9 +843,14 @@ class AmazonConverseConfig(BaseConfig): non_default_params: dict, optional_params: dict, ): - optional_params = self._add_tools_to_optional_params(optional_params=optional_params, tools=tools) + optional_params = self._add_tools_to_optional_params( + optional_params=optional_params, tools=tools + ) - if "meta.llama3-3-70b-instruct-v1:0" in model and non_default_params.get("stream", False) is True: + if ( + "meta.llama3-3-70b-instruct-v1:0" in model + and non_default_params.get("stream", False) is True + ): optional_params["fake_stream"] = True def map_openai_params( @@ -944,7 +989,10 @@ class AmazonConverseConfig(BaseConfig): if "type" in value and value["type"] == "text": return optional_params - if self._supports_native_structured_outputs(model, self.custom_llm_provider) and json_schema is not None: + if ( + self._supports_native_structured_outputs(model, self.custom_llm_provider) + and json_schema is not None + ): # Use Bedrock's native structured outputs API (outputConfig.textFormat) # No synthetic tool injection, no fake_stream needed. # Requires an explicit schema — json_object with no schema falls through @@ -962,10 +1010,14 @@ class AmazonConverseConfig(BaseConfig): json_schema=json_schema, description=description, ) - optional_params = self._add_tools_to_optional_params(optional_params=optional_params, tools=[_tool]) + optional_params = self._add_tools_to_optional_params( + optional_params=optional_params, tools=[_tool] + ) if ( - litellm.utils.supports_tool_choice(model=model, custom_llm_provider=self.custom_llm_provider) + litellm.utils.supports_tool_choice( + model=model, custom_llm_provider=self.custom_llm_provider + ) and not is_thinking_enabled ): optional_params["tool_choice"] = ToolChoiceValuesBlock( @@ -977,7 +1029,9 @@ class AmazonConverseConfig(BaseConfig): optional_params["json_mode"] = True return optional_params - def update_optional_params_with_thinking_tokens(self, non_default_params: dict, optional_params: dict): + def update_optional_params_with_thinking_tokens( + self, non_default_params: dict, optional_params: dict + ): """ Handles scenario where max tokens is not specified. For anthropic models (anthropic api/bedrock/vertex ai), this requires having the max tokens being set and being greater than the thinking token budget. @@ -995,9 +1049,13 @@ class AmazonConverseConfig(BaseConfig): is_thinking_enabled = self.is_thinking_enabled(optional_params) is_max_tokens_in_request = self.is_max_tokens_in_request(non_default_params) if is_thinking_enabled and not is_max_tokens_in_request: - thinking_token_budget = cast(dict, optional_params["thinking"]).get("budget_tokens", None) + thinking_token_budget = cast(dict, optional_params["thinking"]).get( + "budget_tokens", None + ) if thinking_token_budget is not None: - optional_params["maxTokens"] = thinking_token_budget + DEFAULT_MAX_TOKENS + optional_params["maxTokens"] = ( + thinking_token_budget + DEFAULT_MAX_TOKENS + ) @overload def _get_cache_point_block( @@ -1063,15 +1121,23 @@ class AmazonConverseConfig(BaseConfig): if message["role"] == "system": system_prompt_indices.append(idx) if isinstance(message["content"], str) and message["content"]: - system_content_blocks.append(SystemContentBlock(text=message["content"])) - cache_block = self._get_cache_point_block(message, block_type="system", model=model) + system_content_blocks.append( + SystemContentBlock(text=message["content"]) + ) + cache_block = self._get_cache_point_block( + message, block_type="system", model=model + ) if cache_block: system_content_blocks.append(cache_block) elif isinstance(message["content"], list): for m in message["content"]: if m.get("type") == "text" and m.get("text"): - system_content_blocks.append(SystemContentBlock(text=m["text"])) - cache_block = self._get_cache_point_block(m, block_type="system", model=model) + system_content_blocks.append( + SystemContentBlock(text=m["text"]) + ) + cache_block = self._get_cache_point_block( + m, block_type="system", model=model + ) if cache_block: system_content_blocks.append(cache_block) if len(system_prompt_indices) > 0: @@ -1109,10 +1175,16 @@ class AmazonConverseConfig(BaseConfig): # Exceptions should not be stored in optional_params (this is a defensive fix) cleaned_params = filter_exceptions_from_params(optional_params) inference_params = safe_deep_copy(cleaned_params) - supported_converse_params = list(AmazonConverseConfig.__annotations__.keys()) + ["top_k"] + supported_converse_params = list( + AmazonConverseConfig.__annotations__.keys() + ) + ["top_k"] supported_tool_call_params = ["tools", "tool_choice"] supported_config_params = list(self.get_config_blocks().keys()) - total_supported_params = supported_converse_params + supported_tool_call_params + supported_config_params + total_supported_params = ( + supported_converse_params + + supported_tool_call_params + + supported_config_params + ) inference_params.pop("json_mode", None) # used for handling json_schema # Anthropic-only key. Bedrock expects `outputConfig` (camelCase) and # will reject `output_config` if it leaks through pass-through routes. @@ -1123,15 +1195,25 @@ class AmazonConverseConfig(BaseConfig): if request_metadata is not None: self._validate_request_metadata(request_metadata) - output_config: Optional[OutputConfigBlock] = inference_params.pop("outputConfig", None) - inference_params.pop("output_config", None) # Bedrock Converse doesn't support it + output_config: Optional[OutputConfigBlock] = inference_params.pop( + "outputConfig", None + ) + inference_params.pop( + "output_config", None + ) # Bedrock Converse doesn't support it # keep supported params in 'inference_params', and set all model-specific params in 'additional_request_params' - additional_request_params = {k: v for k, v in inference_params.items() if k not in total_supported_params} - inference_params = {k: v for k, v in inference_params.items() if k in total_supported_params} + additional_request_params = { + k: v for k, v in inference_params.items() if k not in total_supported_params + } + inference_params = { + k: v for k, v in inference_params.items() if k in total_supported_params + } # Handle parallel_tool_calls configuration - parallel_tool_use_config = additional_request_params.pop("_parallel_tool_use_config", None) + parallel_tool_use_config = additional_request_params.pop( + "_parallel_tool_use_config", None + ) if parallel_tool_use_config is not None and is_claude_4_5_on_bedrock(model): for key, value in parallel_tool_use_config.items(): if ( @@ -1146,7 +1228,9 @@ class AmazonConverseConfig(BaseConfig): additional_request_params.pop("parallel_tool_calls", None) # Only set the topK value in for models that support it - additional_request_params.update(self._handle_top_k_value(model, inference_params)) + additional_request_params.update( + self._handle_top_k_value(model, inference_params) + ) # Filter out internal/MCP-related parameters that shouldn't be sent to the API # These are LiteLLM internal parameters, not API parameters @@ -1155,7 +1239,9 @@ class AmazonConverseConfig(BaseConfig): # Filter out non-serializable objects (exceptions, callables, logging objects, etc.) # from additional_request_params to prevent JSON serialization errors # This filters: Exception objects, callable objects (functions), Logging objects, etc. - additional_request_params = filter_exceptions_from_params(additional_request_params) + additional_request_params = filter_exceptions_from_params( + additional_request_params + ) return ( inference_params, @@ -1202,7 +1288,9 @@ class AmazonConverseConfig(BaseConfig): # Only separate tools if computer use tools are actually present if filtered_tools and self.is_computer_use_tool_used(filtered_tools, model): # Separate computer use tools from regular function tools - computer_use_tools, regular_tools = self._separate_computer_use_tools(filtered_tools, model) + computer_use_tools, regular_tools = self._separate_computer_use_tools( + filtered_tools, model + ) # Process regular function tools using existing logic bedrock_tools = _bedrock_tools_pt(regular_tools) @@ -1263,7 +1351,9 @@ class AmazonConverseConfig(BaseConfig): anthropic_beta_list.append(computer_use_header) # Transform computer use tools to proper Bedrock format - transformed_computer_tools = self._transform_computer_use_tools(computer_use_tools) + transformed_computer_tools = self._transform_computer_use_tools( + computer_use_tools + ) additional_request_params["tools"] = transformed_computer_tools else: # No computer use tools, process all tools as regular tools @@ -1292,9 +1382,15 @@ class AmazonConverseConfig(BaseConfig): """ Bedrock doesn't support tool calling without `tools=` param specified. """ - if "tools" not in optional_params and messages is not None and has_tool_call_blocks(messages): + if ( + "tools" not in optional_params + and messages is not None + and has_tool_call_blocks(messages) + ): if litellm.modify_params: - optional_params["tools"] = add_dummy_tool(custom_llm_provider="bedrock_converse") + optional_params["tools"] = add_dummy_tool( + custom_llm_provider="bedrock_converse" + ) else: raise litellm.UnsupportedParamsError( message="Bedrock doesn't support tool calling without `tools=` param specified. Pass `tools=` param OR set `litellm.modify_params = True` // `litellm_settings::modify_params: True` to add dummy tool to the request.", @@ -1348,7 +1444,9 @@ class AmazonConverseConfig(BaseConfig): bedrock_tool_config: Optional[ToolConfigBlock] = None if len(bedrock_tools) > 0: - tool_choice_values: ToolChoiceValuesBlock = inference_params.pop("tool_choice", None) + tool_choice_values: ToolChoiceValuesBlock = inference_params.pop( + "tool_choice", None + ) bedrock_tool_config = ToolConfigBlock( tools=bedrock_tools, ) @@ -1358,7 +1456,9 @@ class AmazonConverseConfig(BaseConfig): data: CommonRequestObject = { "additionalModelRequestFields": additional_request_params, "system": system_content_blocks, - "inferenceConfig": self._transform_inference_params(inference_params=inference_params), + "inferenceConfig": self._transform_inference_params( + inference_params=inference_params + ), } # Handle all config blocks @@ -1388,10 +1488,14 @@ class AmazonConverseConfig(BaseConfig): litellm_params: dict, headers: Optional[dict] = None, ) -> RequestObject: - messages, system_content_blocks = self._transform_system_message(messages, model=model) + messages, system_content_blocks = self._transform_system_message( + messages, model=model + ) # Convert last user message to guarded_text if guardrailConfig is present - messages = self._convert_consecutive_user_messages_to_guarded_text(messages, optional_params) + messages = self._convert_consecutive_user_messages_to_guarded_text( + messages, optional_params + ) ## TRANSFORMATION ## _data: CommonRequestObject = self._transform_request_helper( @@ -1402,11 +1506,13 @@ class AmazonConverseConfig(BaseConfig): headers=headers, ) - bedrock_messages = await BedrockConverseMessagesProcessor._bedrock_converse_messages_pt_async( - messages=messages, - model=model, - llm_provider="bedrock_converse", - user_continue_message=litellm_params.pop("user_continue_message", None), + bedrock_messages = ( + await BedrockConverseMessagesProcessor._bedrock_converse_messages_pt_async( + messages=messages, + model=model, + llm_provider="bedrock_converse", + user_continue_message=litellm_params.pop("user_continue_message", None), + ) ) data: RequestObject = {"messages": bedrock_messages, **_data} @@ -1440,10 +1546,14 @@ class AmazonConverseConfig(BaseConfig): litellm_params: dict, headers: Optional[dict] = None, ) -> RequestObject: - messages, system_content_blocks = self._transform_system_message(messages, model=model) + messages, system_content_blocks = self._transform_system_message( + messages, model=model + ) # Convert last user message to guarded_text if guardrailConfig is present - messages = self._convert_consecutive_user_messages_to_guarded_text(messages, optional_params) + messages = self._convert_consecutive_user_messages_to_guarded_text( + messages, optional_params + ) _data: CommonRequestObject = self._transform_request_helper( model=model, @@ -1492,7 +1602,9 @@ class AmazonConverseConfig(BaseConfig): encoding=encoding, ) - def _transform_reasoning_content(self, reasoning_content_blocks: List[BedrockConverseReasoningContentBlock]) -> str: + def _transform_reasoning_content( + self, reasoning_content_blocks: List[BedrockConverseReasoningContentBlock] + ) -> str: """ Extract the reasoning text from the reasoning content blocks @@ -1508,7 +1620,9 @@ class AmazonConverseConfig(BaseConfig): self, thinking_blocks: List[BedrockConverseReasoningContentBlock] ) -> List[Union[ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock]]: """Return a consistent format for thinking blocks between Anthropic and Bedrock.""" - thinking_blocks_list: List[Union[ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock]] = [] + thinking_blocks_list: List[ + Union[ChatCompletionThinkingBlock, ChatCompletionRedactedThinkingBlock] + ] = [] for block in thinking_blocks: if "reasoningText" in block: _thinking_block = ChatCompletionThinkingBlock(type="thinking") @@ -1544,11 +1658,21 @@ class AmazonConverseConfig(BaseConfig): cache_creation_input_tokens = usage["cacheWriteInputTokens"] input_tokens += cache_creation_input_tokens - prompt_tokens_details = PromptTokensDetailsWrapper(cached_tokens=cache_read_input_tokens) - reasoning_tokens = token_counter(text=reasoning_content, count_response_tokens=True) if reasoning_content else 0 + prompt_tokens_details = PromptTokensDetailsWrapper( + cached_tokens=cache_read_input_tokens + ) + reasoning_tokens = ( + token_counter(text=reasoning_content, count_response_tokens=True) + if reasoning_content + else 0 + ) completion_tokens_details = CompletionTokensDetailsWrapper( reasoning_tokens=reasoning_tokens, - text_tokens=(output_tokens - reasoning_tokens if reasoning_tokens > 0 else output_tokens), + text_tokens=( + output_tokens - reasoning_tokens + if reasoning_tokens > 0 + else output_tokens + ), ) openai_usage = Usage( prompt_tokens=input_tokens, @@ -1563,7 +1687,9 @@ class AmazonConverseConfig(BaseConfig): def get_tool_call_names( self, - tools: Optional[Union[List[ToolBlock], List[OpenAIChatCompletionToolParam]]] = None, + tools: Optional[ + Union[List[ToolBlock], List[OpenAIChatCompletionToolParam]] + ] = None, ) -> List[str]: if tools is None: return [] @@ -1602,8 +1728,13 @@ class AmazonConverseConfig(BaseConfig): try: tool_call_names = self.get_tool_call_names(tools) json_content = json.loads(message.content) - if json_content.get("type") == "function" and json_content.get("name") in tool_call_names: - tool_calls = [ChatCompletionMessageToolCall(function=Function(**json_content))] + if ( + json_content.get("type") == "function" + and json_content.get("name") in tool_call_names + ): + tool_calls = [ + ChatCompletionMessageToolCall(function=Function(**json_content)) + ] message.tool_calls = tool_calls message.content = None @@ -1632,7 +1763,9 @@ class AmazonConverseConfig(BaseConfig): """ content_str = "" tools: List[ChatCompletionToolCallChunk] = [] - reasoningContentBlocks: Optional[List[BedrockConverseReasoningContentBlock]] = None + reasoningContentBlocks: Optional[ + List[BedrockConverseReasoningContentBlock] + ] = None citationsContentBlocks: Optional[List[CitationsContentBlock]] = None for idx, content in enumerate(content_blocks): """ @@ -1649,7 +1782,9 @@ class AmazonConverseConfig(BaseConfig): if "toolUse" in content: ## check tool name was formatted by litellm _response_tool_name = content["toolUse"]["name"] - response_tool_name = get_bedrock_tool_name(response_tool_name=_response_tool_name) + response_tool_name = get_bedrock_tool_name( + response_tool_name=_response_tool_name + ) _function_chunk = ChatCompletionToolCallFunctionChunk( name=response_tool_name, arguments=json.dumps(content["toolUse"]["input"]), @@ -1700,7 +1835,11 @@ class AmazonConverseConfig(BaseConfig): """ try: response_data = json.loads(json_str) - if isinstance(response_data, dict) and "properties" in response_data and len(response_data) == 1: + if ( + isinstance(response_data, dict) + and "properties" in response_data + and len(response_data) == 1 + ): response_data = response_data["properties"] return json.dumps(response_data) except json.JSONDecodeError: @@ -1724,7 +1863,11 @@ class AmazonConverseConfig(BaseConfig): if not json_mode or not tools: return tools if tools else None - json_tool_indices = [i for i, t in enumerate(tools) if t["function"].get("name") == RESPONSE_FORMAT_TOOL_NAME] + json_tool_indices = [ + i + for i, t in enumerate(tools) + if t["function"].get("name") == RESPONSE_FORMAT_TOOL_NAME + ] if not json_tool_indices: # No json_tool_call found, return tools unchanged @@ -1732,10 +1875,14 @@ class AmazonConverseConfig(BaseConfig): if len(json_tool_indices) == len(tools): # All tools are json_tool_call — convert first one to content - verbose_logger.debug("Processing JSON tool call response for response_format") + verbose_logger.debug( + "Processing JSON tool call response for response_format" + ) json_mode_content_str: Optional[str] = tools[0]["function"].get("arguments") if json_mode_content_str is not None: - json_mode_content_str = AmazonConverseConfig._unwrap_bedrock_properties(json_mode_content_str) + json_mode_content_str = AmazonConverseConfig._unwrap_bedrock_properties( + json_mode_content_str + ) chat_completion_message["content"] = json_mode_content_str return None @@ -1745,9 +1892,13 @@ class AmazonConverseConfig(BaseConfig): first_idx = json_tool_indices[0] json_mode_args = tools[first_idx]["function"].get("arguments") if json_mode_args is not None: - json_mode_args = AmazonConverseConfig._unwrap_bedrock_properties(json_mode_args) + json_mode_args = AmazonConverseConfig._unwrap_bedrock_properties( + json_mode_args + ) existing = chat_completion_message.get("content") or "" - chat_completion_message["content"] = existing + json_mode_args if existing else json_mode_args + chat_completion_message["content"] = ( + existing + json_mode_args if existing else json_mode_args + ) real_tools = [t for i, t in enumerate(tools) if i not in json_tool_indices] return real_tools if real_tools else None @@ -1825,7 +1976,9 @@ class AmazonConverseConfig(BaseConfig): chat_completion_message: ChatCompletionResponseMessage = {"role": "assistant"} content_str = "" tools: List[ChatCompletionToolCallChunk] = [] - reasoningContentBlocks: Optional[List[BedrockConverseReasoningContentBlock]] = None + reasoningContentBlocks: Optional[ + List[BedrockConverseReasoningContentBlock] + ] = None citationsContentBlocks: Optional[List[CitationsContentBlock]] = None if message is not None: @@ -1844,11 +1997,17 @@ class AmazonConverseConfig(BaseConfig): provider_specific_fields["citationsContent"] = citationsContentBlocks if provider_specific_fields: - chat_completion_message["provider_specific_fields"] = provider_specific_fields + chat_completion_message[ + "provider_specific_fields" + ] = provider_specific_fields if reasoningContentBlocks is not None: - chat_completion_message["reasoning_content"] = self._transform_reasoning_content(reasoningContentBlocks) - chat_completion_message["thinking_blocks"] = self._transform_thinking_blocks(reasoningContentBlocks) + chat_completion_message[ + "reasoning_content" + ] = self._transform_reasoning_content(reasoningContentBlocks) + chat_completion_message[ + "thinking_blocks" + ] = self._transform_thinking_blocks(reasoningContentBlocks) chat_completion_message["content"] = content_str filtered_tools = self._filter_json_mode_tools( json_mode=json_mode, diff --git a/litellm/llms/openai/chat/guardrail_translation/handler.py b/litellm/llms/openai/chat/guardrail_translation/handler.py index 0ce9d57a65..f854cdb13d 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/auth/auth_checks.py b/litellm/proxy/auth/auth_checks.py index 0efc3dab63..c00a351bdd 100644 --- a/litellm/proxy/auth/auth_checks.py +++ b/litellm/proxy/auth/auth_checks.py @@ -3078,10 +3078,7 @@ async def _team_max_budget_check( BudgetExceededError if the team is over it's max budget. Triggers a budget alert if the team is over it's max budget. """ - if ( - team_object is not None - and team_object.max_budget is not None - ): + if team_object is not None and team_object.max_budget is not None: from litellm.proxy.proxy_server import get_current_spend # Read spend from cross-pod counter (Redis-first) or cached object (fallback) diff --git a/litellm/proxy/auth/handle_jwt.py b/litellm/proxy/auth/handle_jwt.py index dc01703c6b..6ad372f3b5 100644 --- a/litellm/proxy/auth/handle_jwt.py +++ b/litellm/proxy/auth/handle_jwt.py @@ -621,9 +621,7 @@ class JWTHandler: ) # Check cache first - cache_key = ( - f"oidc_userinfo_{hashlib.sha256(token.encode()).hexdigest()}" - ) + cache_key = f"oidc_userinfo_{hashlib.sha256(token.encode()).hexdigest()}" cached_userinfo = await self.user_api_key_cache.async_get_cache(cache_key) if cached_userinfo is not None: diff --git a/litellm/proxy/common_utils/reset_budget_job.py b/litellm/proxy/common_utils/reset_budget_job.py index 5db919659e..bcfaed2439 100644 --- a/litellm/proxy/common_utils/reset_budget_job.py +++ b/litellm/proxy/common_utils/reset_budget_job.py @@ -66,10 +66,8 @@ class ResetBudgetJob: try: from litellm.proxy.proxy_server import spend_counter_cache - memberships = ( - await self.prisma_client.db.litellm_teammembership.find_many( - where={"budget_id": {"in": budget_ids}} - ) + memberships = await self.prisma_client.db.litellm_teammembership.find_many( + where={"budget_id": {"in": budget_ids}} ) for m in memberships: counter_key = f"spend:team_member:{m.user_id}:{m.team_id}" @@ -574,7 +572,11 @@ class ResetBudgetJob: counter_key = None if item_type == "key" and hasattr(item, "token") and item.token is not None: counter_key = f"spend:key:{item.token}" - elif item_type == "team" and hasattr(item, "team_id") and item.team_id is not None: + elif ( + item_type == "team" + and hasattr(item, "team_id") + and item.team_id is not None + ): counter_key = f"spend:team:{item.team_id}" if counter_key is not None: diff --git a/litellm/proxy/management_endpoints/internal_user_endpoints.py b/litellm/proxy/management_endpoints/internal_user_endpoints.py index e885f3e461..646779e6f8 100644 --- a/litellm/proxy/management_endpoints/internal_user_endpoints.py +++ b/litellm/proxy/management_endpoints/internal_user_endpoints.py @@ -707,7 +707,7 @@ def _build_user_info_response( response_model=UserInfoResponse, ) @management_endpoint_wrapper -async def user_info( +async def user_info( # noqa: PLR0915 request: Request, user_id: Optional[str] = fastapi.Query( default=None, description="User ID in the request parameters" diff --git a/litellm/proxy/management_endpoints/ui_sso.py b/litellm/proxy/management_endpoints/ui_sso.py index a5a62813b9..0bfe8eb75b 100644 --- a/litellm/proxy/management_endpoints/ui_sso.py +++ b/litellm/proxy/management_endpoints/ui_sso.py @@ -827,7 +827,9 @@ async def get_generic_sso_response( ], # sso specific jwt handler - used for restricted sso group access control generic_client_id: str, redirect_url: str, -) -> Tuple[Union[OpenID, dict], Optional[dict], Optional[dict]]: # (result, received_response, access_token_payload) +) -> Tuple[ + Union[OpenID, dict], Optional[dict], Optional[dict] +]: # (result, received_response, access_token_payload) # make generic sso provider from fastapi_sso.sso.base import DiscoveryDocument from fastapi_sso.sso.generic import create_provider @@ -1369,7 +1371,11 @@ async def auth_callback(request: Request, state: Optional[str] = None): # noqa: ) elif generic_client_id is not None: - result, received_response, access_token_payload = await get_generic_sso_response( + ( + result, + received_response, + access_token_payload, + ) = await get_generic_sso_response( request=request, jwt_handler=jwt_handler, generic_client_id=generic_client_id, diff --git a/litellm/proxy/management_helpers/audit_logs.py b/litellm/proxy/management_helpers/audit_logs.py index b9020222f1..7599e11bde 100644 --- a/litellm/proxy/management_helpers/audit_logs.py +++ b/litellm/proxy/management_helpers/audit_logs.py @@ -51,7 +51,11 @@ def _build_audit_log_payload( if request_data.updated_at is not None: updated_at = request_data.updated_at.isoformat() - table_name_str: str = request_data.table_name.value if isinstance(request_data.table_name, LitellmTableNames) else str(request_data.table_name) + table_name_str: str = ( + request_data.table_name.value + if isinstance(request_data.table_name, LitellmTableNames) + else str(request_data.table_name) + ) return StandardAuditLogPayload( id=request_data.id, @@ -89,7 +93,9 @@ async def _dispatch_audit_log_to_callbacks( for callback in litellm.audit_log_callbacks: try: - resolved: Optional[CustomLogger] = callback if isinstance(callback, CustomLogger) else None + resolved: Optional[CustomLogger] = ( + callback if isinstance(callback, CustomLogger) else None + ) if isinstance(callback, str): resolved = _resolve_audit_log_callback(callback) if resolved is None: @@ -138,9 +144,7 @@ async def create_object_audit_log( return _changed_by = ( - litellm_changed_by - or user_api_key_dict.user_id - or litellm_proxy_admin_name + litellm_changed_by or user_api_key_dict.user_id or litellm_proxy_admin_name ) await create_audit_log_for_update( diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 05046e2b14..9b9ed791fd 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -873,12 +873,14 @@ async def proxy_startup_event(app: FastAPI): # noqa: PLR0915 ) if prisma_client is not None: + async def _run_pw_migration(): try: result = await migrate_passwords_to_scrypt_async(prisma_client) verbose_proxy_logger.info(f"Password migration: {result}") except Exception as e: verbose_proxy_logger.warning(f"Password migration skipped: {e}") + asyncio.create_task(_run_pw_migration()) ProxyStartupEvent._initialize_startup_logging( @@ -1725,9 +1727,7 @@ async def get_current_spend(counter_key: str, fallback_spend: float) -> float: # 1. Try Redis first (cross-pod authoritative) if spend_counter_cache.redis_cache is not None: try: - val = await spend_counter_cache.redis_cache.async_get_cache( - key=counter_key - ) + val = await spend_counter_cache.redis_cache.async_get_cache(key=counter_key) if val is not None: return float(val) except Exception as e: @@ -1831,9 +1831,7 @@ async def _init_and_increment_spend_counter( key=counter_key, value=base_spend ) - await spend_counter_cache.async_increment_cache( - key=counter_key, value=increment - ) + await spend_counter_cache.async_increment_cache(key=counter_key, value=increment) async def update_cache( # noqa: PLR0915 @@ -12156,7 +12154,10 @@ async def invitation_delete( dependencies=[Depends(user_api_key_auth)], include_in_schema=False, ) -async def update_config(config_info: ConfigYAML, user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth)): # noqa: PLR0915 +async def update_config( # noqa: PLR0915 + config_info: ConfigYAML, + user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth), +): """ For Admin UI - allows admin to update config via UI @@ -12165,7 +12166,9 @@ async def update_config(config_info: ConfigYAML, user_api_key_dict: UserAPIKeyAu global llm_router, llm_model_list, general_settings, proxy_config, proxy_logging_obj, master_key, prisma_client try: if user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN: - raise HTTPException(status_code=403, detail="Only proxy admins can update config") + raise HTTPException( + status_code=403, detail="Only proxy admins can update config" + ) import base64 """ diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index 95f6db93e2..2e24468cef 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -4575,7 +4575,9 @@ def verify_password(password: str, stored: str) -> bool: try: raw = base64.b64decode(stored[7:]) salt, dk = raw[:16], raw[16:] - dk2 = hashlib.scrypt(password.encode(), salt=salt, n=16384, r=8, p=1, dklen=32) + dk2 = hashlib.scrypt( + password.encode(), salt=salt, n=16384, r=8, p=1, dklen=32 + ) return secrets.compare_digest(dk, dk2) except Exception: return False @@ -4596,12 +4598,16 @@ async def migrate_passwords_to_scrypt_async(prisma_client) -> str: all_with_pw = await prisma_client.db.litellm_usertable.find_many( where={"password": {"not": None}}, ) + def _is_sha256_hex(s: str) -> bool: return len(s) == 64 and all(c in "0123456789abcdef" for c in s) plaintext_users = [ - u for u in all_with_pw - if u.password and not u.password.startswith("scrypt:") and not _is_sha256_hex(u.password) + u + for u in all_with_pw + if u.password + and not u.password.startswith("scrypt:") + and not _is_sha256_hex(u.password) ] if not plaintext_users: return "No plaintext passwords found"