Merge remote-tracking branch 'origin/litellm_internal_staging' into claude/per-file-any-grandfathering-6qvth8

This commit is contained in:
mateo-berri 2026-06-17 00:32:51 +00:00
commit 715ec2d7a2
No known key found for this signature in database
112 changed files with 1899 additions and 255 deletions

View file

@ -77,6 +77,12 @@ jobs:
run: |
uv run --no-sync python scripts/ruff_strict_gate.py --base "$BASE_SHA"
- name: Check type-discipline budget (mutable collections / casts / type guards / kwargs / unexplained suppressions, delta vs base)
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
uv run --no-sync python scripts/type_discipline_gate.py --base "$BASE_SHA"
- name: Print OpenAI version
run: |
uv run --no-sync python -c "import openai; print(f'OpenAI version: {openai.__version__}')"
@ -100,6 +106,33 @@ jobs:
run: |
uv run --no-sync python -c "from litellm import *" || (echo '🚨 import failed, this means you introduced unprotected imports! 🚨'; exit 1)
# Intentionally NON-GATING. This job turns red when a *-budget.json ceiling is
# raised (or a rule/budget is dropped) so a loosening is obvious in review, but it
# must be kept OUT of the branch-protection required-checks list so a justified
# bump can still be merged by a human who has seen and accepted the red.
budget-ratchet:
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
steps:
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "3.12"
- name: Ratchet check (budgets may only decrease; non-gating)
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
python scripts/budget_ratchet_check.py --base "$BASE_SHA"
any-discipline:
# Separate job: the first run cold-builds litellm's type cache (~2 min, ~3 GB),
# so keep it off the main lint job's time budget. Subsequent runs reuse the

View file

@ -42,6 +42,8 @@ If you're trying to create a new function that relies on untyped stuff, instead
The Any-discipline gate (`make lint-any`, also a CI job) grandfathers each file under `litellm/` at its current count of values typed `Any` (including the `X | Any`) in `any-discipline-budget.json` and gives it ~50% headroom; a changed file fails once it exceeds that ceiling, so a brand new file must be `Any`-free while a legacy file can absorb a little drift before it has to be cleaned. Ideally `# any-ok: <reason>` is never used; treat it as a last resort for a genuine typed/untyped boundary that Pydantic truly can't model
If you get an LIT001 or LIT002 fail, refactor the code to follow functional programming best practices rather than introducing mutable data structures. For example, build values in one shot with comprehensions or generators wrapped in `tuple()` / `frozenset()` instead of seeding an empty `list`/`dict`/`set` and mutating it over time. Ideally `# mutable-ok` is never used; reach for it only as a genuine last resort when an immutable rewrite is truly impossible, and always pair it with a real reason
Ask to commit and push your work when you're done (or if you're confident that your code is good and works, just do it)
When you must use real LLM models to, for example, write e2e tests, write a QA runbook, etc., make sure to use the latest models (doesn't have to be smartest, can also be a modern small, fast one. No strong preference for smart vs fast here, just use something modern) as of the year and month of the current date. Do a web search as necessary to figure that out

View file

@ -15,7 +15,7 @@ db = Prisma(
)
async def check_view_exists(): # noqa: PLR0915
async def check_view_exists():
"""
Checks if the LiteLLM_VerificationTokenView and MonthlyGlobalSpend exists in the user's db.
@ -34,8 +34,7 @@ async def check_view_exists(): # noqa: PLR0915
print("LiteLLM_VerificationTokenView Exists!") # noqa
except Exception:
# If an error occurs, the view does not exist, so create it
await db.execute_raw(
"""
await db.execute_raw("""
CREATE VIEW "LiteLLM_VerificationTokenView" AS
SELECT
v.*,
@ -45,8 +44,7 @@ async def check_view_exists(): # noqa: PLR0915
t.rpm_limit AS team_rpm_limit
FROM "LiteLLM_VerificationToken" v
LEFT JOIN "LiteLLM_TeamTable" t ON v.team_id = t.team_id;
"""
)
""")
print("LiteLLM_VerificationTokenView Created!") # noqa

View file

@ -412,7 +412,7 @@ class _PROXY_LiteLLMManagedFiles(CustomLogger, BaseFileEndpoints):
detail=f"User {user_api_key_dict.user_id} does not have access to the file {file_id}",
)
async def async_pre_call_hook( # noqa: PLR0915
async def async_pre_call_hook(
self,
user_api_key_dict: UserAPIKeyAuth,
cache: DualCache,

View file

@ -483,7 +483,7 @@ async def new_project(
response_model=LiteLLM_ProjectTable,
)
@management_endpoint_wrapper
async def update_project( # noqa: PLR0915
async def update_project(
data: UpdateProjectRequest,
http_request: Request,
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),

View file

@ -311,7 +311,7 @@ def get_redis_url_from_environment():
return f"{redis_protocol}://{auth_part}{os.environ['REDIS_HOST']}:{os.environ['REDIS_PORT']}"
def _get_redis_client_logic(**env_overrides): # noqa: PLR0915
def _get_redis_client_logic(**env_overrides):
"""
Common functionality across sync + async redis client implementations
"""

View file

@ -436,7 +436,7 @@ def _build_streaming_logging_obj(
return logging_obj
async def asend_message_streaming( # noqa: PLR0915
async def asend_message_streaming(
a2a_client: Optional["A2AClientType"] = None,
request: Optional["SendStreamingMessageRequest"] = None,
api_base: Optional[str] = None,

View file

@ -157,7 +157,7 @@ async def acreate_batch(
@client
def create_batch( # noqa: PLR0915
def create_batch(
completion_window: Literal["24h"],
endpoint: Literal["/v1/chat/completions", "/v1/embeddings", "/v1/completions"],
input_file_id: str,

View file

@ -394,7 +394,7 @@ class LLMCachingHandler:
return cr["model"]
return None
def _process_async_embedding_cached_response( # noqa: PLR0915
def _process_async_embedding_cached_response(
self,
final_embedding_cached_response: Optional[EmbeddingResponse],
cached_result: List[Optional[CachedEmbedding]],

View file

@ -28,7 +28,7 @@ from .base_cache import BaseCache
class QdrantSemanticCache(BaseCache):
CACHE_KEY_FIELD_NAME = "litellm_cache_key"
def __init__( # noqa: PLR0915
def __init__(
self,
qdrant_api_base=None,
qdrant_api_key=None,

View file

@ -1211,7 +1211,7 @@ class OpenAiResponsesToChatCompletionStreamIterator(BaseModelResponseIterator):
return self.chunk_parser(json.loads(str_line))
@staticmethod
def translate_responses_chunk_to_openai_stream( # noqa: PLR0915
def translate_responses_chunk_to_openai_stream(
parsed_chunk: Union[dict, BaseModel],
) -> "ModelResponseStream":
"""

View file

@ -288,7 +288,7 @@ def _transcription_usage_has_token_details(
return (prompt_tokens_val > 0) or (completion_tokens_val > 0)
def cost_per_token( # noqa: PLR0915
def cost_per_token(
model: str = "",
prompt_tokens: int = 0,
completion_tokens: int = 0,
@ -1136,7 +1136,7 @@ def _store_cost_breakdown_in_logging_obj(
pass
def completion_cost( # noqa: PLR0915
def completion_cost(
completion_response=None,
model: Optional[str] = None,
prompt="",

View file

@ -195,7 +195,7 @@ def image_generation(
@client
def image_generation( # noqa: PLR0915
def image_generation(
prompt: str,
model: Optional[str] = None,
n: Optional[int] = None,
@ -738,7 +738,7 @@ def image_variation(
@client
def image_edit( # noqa: PLR0915
def image_edit(
image: Optional[Union[FileTypes, List[FileTypes]]] = None,
prompt: Optional[str] = None,
model: Optional[str] = None,

View file

@ -351,7 +351,7 @@ class SlackAlerting(CustomBatchLogger):
except Exception:
return 0
async def send_daily_reports(self, router) -> bool: # noqa: PLR0915
async def send_daily_reports(self, router) -> bool:
"""
Send a daily report on:
- Top 5 deployments with most failed requests
@ -1373,7 +1373,7 @@ Model Info:
return False
async def send_alert( # noqa: PLR0915
async def send_alert(
self,
message: str,
level: Literal["Low", "Medium", "High"],

View file

@ -133,9 +133,7 @@ class BraintrustLogger(CustomLogger):
self.default_project_id = project_dict["id"]
def log_success_event( # noqa: PLR0915
self, kwargs, response_obj, start_time, end_time
):
def log_success_event(self, kwargs, response_obj, start_time, end_time):
verbose_logger.debug("REACHES BRAINTRUST SUCCESS")
try:
litellm_call_id = kwargs.get("litellm_call_id")
@ -271,9 +269,7 @@ class BraintrustLogger(CustomLogger):
except Exception as e:
raise e # don't use verbose_logger.exception, if exception is raised
async def async_log_success_event( # noqa: PLR0915
self, kwargs, response_obj, start_time, end_time
):
async def async_log_success_event(self, kwargs, response_obj, start_time, end_time):
verbose_logger.debug("REACHES BRAINTRUST SUCCESS")
try:
litellm_call_id = kwargs.get("litellm_call_id")

View file

@ -549,7 +549,7 @@ class LangFuseLogger:
)
)
def _log_langfuse_v2( # noqa: PLR0915
def _log_langfuse_v2(
self,
user_id: Optional[str],
metadata: dict,

View file

@ -107,7 +107,7 @@ def _is_url_match(url, matchers: List[str]) -> bool:
return False
def create_mock_client_factory(config: MockClientConfig): # noqa: PLR0915
def create_mock_client_factory(config: MockClientConfig):
"""
Factory function that creates mock client functions based on configuration.

View file

@ -2198,9 +2198,7 @@ class OpenTelemetry(OTELGenAISemconvMixin, CustomLogger):
return kv_pairs
def set_attributes( # noqa: PLR0915
self, span: Span, kwargs, response_obj: Optional[Any]
):
def set_attributes(self, span: Span, kwargs, response_obj: Optional[Any]):
try:
if self.callback_name == "langtrace":
from litellm.integrations.langtrace import LangtraceAttributes

View file

@ -75,7 +75,7 @@ class PrometheusLogger(CustomLogger):
return cb
return None
def __init__( # noqa: PLR0915
def __init__(
self,
**kwargs,
):
@ -2255,7 +2255,7 @@ class PrometheusLogger(CustomLogger):
or _litellm_params_metadata.get("user_agent"),
}
def set_llm_deployment_failure_metrics(self, request_kwargs: dict): # noqa: PLR0915
def set_llm_deployment_failure_metrics(self, request_kwargs: dict):
"""
Sets Failure metrics when an LLM API call fails

View file

@ -234,7 +234,7 @@ def extract_and_raise_litellm_exception(
)
def exception_type( # type: ignore # noqa: PLR0915
def exception_type( # type: ignore
model,
original_exception,
custom_llm_provider,

View file

@ -154,7 +154,7 @@ def handle_anthropic_text_model_custom_llm_provider(
return model, custom_llm_provider
def get_llm_provider( # noqa: PLR0915
def get_llm_provider(
model: str,
custom_llm_provider: Optional[str] = None,
api_base: Optional[str] = None,
@ -568,7 +568,7 @@ def get_llm_provider( # noqa: PLR0915
)
def _get_openai_compatible_provider_info( # noqa: PLR0915
def _get_openai_compatible_provider_info(
model: str,
api_base: Optional[str],
api_key: Optional[str],

View file

@ -5,7 +5,7 @@ from litellm.exceptions import BadRequestError
from litellm.types.utils import LlmProviders, LlmProvidersSet
def get_supported_openai_params( # noqa: PLR0915
def get_supported_openai_params(
model: str,
custom_llm_provider: Optional[str] = None,
request_type: Literal[

View file

@ -986,7 +986,7 @@ class Logging(LiteLLMLoggingBaseClass):
self._get_masked_api_base(additional_args.get("api_base", ""))
)
def pre_call(self, input, api_key, model=None, additional_args={}): # noqa: PLR0915
def pre_call(self, input, api_key, model=None, additional_args={}):
# Log the exact input to the LLM API
litellm.error_logs["PRE_CALL"] = locals()
try:
@ -2119,7 +2119,7 @@ class Logging(LiteLLMLoggingBaseClass):
await self.async_success_handler(result=complete_streaming_response)
return
def success_handler( # noqa: PLR0915
def success_handler(
self, result=None, start_time=None, end_time=None, cache_hit=None, **kwargs
):
verbose_logger.debug(
@ -2584,7 +2584,7 @@ class Logging(LiteLLMLoggingBaseClass):
),
)
async def async_success_handler( # noqa: PLR0915
async def async_success_handler(
self, result=None, start_time=None, end_time=None, cache_hit=None, **kwargs
):
"""
@ -3036,7 +3036,7 @@ class Logging(LiteLLMLoggingBaseClass):
kwargs=self.model_call_details,
) # type: ignore
def failure_handler( # noqa: PLR0915
def failure_handler(
self, exception, traceback_exception, start_time=None, end_time=None
):
verbose_logger.debug(
@ -3753,7 +3753,7 @@ def _get_masked_values(
}
def set_callbacks(callback_list, function_id=None): # noqa: PLR0915
def set_callbacks(callback_list, function_id=None):
"""
Globally sets the callback client
"""
@ -3854,7 +3854,7 @@ def set_callbacks(callback_list, function_id=None): # noqa: PLR0915
return None
def _init_custom_logger_compatible_class( # noqa: PLR0915
def _init_custom_logger_compatible_class(
logging_integration: _custom_logger_compatible_callbacks_literal,
internal_usage_cache: Optional[DualCache],
llm_router: Optional[
@ -4611,7 +4611,7 @@ def _maybe_auto_initialize_arize_phoenix(_in_memory_loggers: list) -> None:
)
def get_custom_logger_compatible_class( # noqa: PLR0915
def get_custom_logger_compatible_class(
logging_integration: _custom_logger_compatible_callbacks_literal,
) -> Optional[CustomLogger]:
try:

View file

@ -683,7 +683,7 @@ def _get_regional_uplift_multiplier(
return 1.0
def generic_cost_per_token( # noqa: PLR0915
def generic_cost_per_token(
model: str,
usage: Usage,
custom_llm_provider: str,

View file

@ -471,7 +471,7 @@ def _should_convert_tool_call_to_json_mode(
return False
def convert_to_model_response_object( # noqa: PLR0915
def convert_to_model_response_object(
response_object: Optional[dict] = None,
model_response_object: Optional[
Union[

View file

@ -1475,7 +1475,7 @@ def convert_to_gemini_tool_call_invoke(
)
def convert_to_gemini_tool_call_result( # noqa: PLR0915
def convert_to_gemini_tool_call_result(
message: Union[ChatCompletionToolMessage, ChatCompletionFunctionMessage],
last_message_with_tool_calls: Optional[dict],
model: Optional[str] = None,
@ -2227,7 +2227,7 @@ def _sanitize_empty_text_content(
return message
def _add_missing_tool_results( # noqa: PLR0915
def _add_missing_tool_results(
current_message: AllMessageValues,
messages: List[AllMessageValues],
current_index: int,
@ -2484,7 +2484,7 @@ def sanitize_messages_for_tool_calling(
return sanitized_messages
def anthropic_messages_pt( # noqa: PLR0915
def anthropic_messages_pt(
messages: List[AllMessageValues],
model: str,
llm_provider: str,
@ -3278,7 +3278,7 @@ def convert_to_cohere_tool_invoke(tool_calls: list) -> List[ToolCallObject]:
return cohere_tool_invoke
def cohere_messages_pt_v2( # noqa: PLR0915
def cohere_messages_pt_v2(
messages: List,
model: str,
llm_provider: str,
@ -4703,7 +4703,7 @@ class BedrockConverseMessagesProcessor:
return messages
@staticmethod
async def _bedrock_converse_messages_pt_async( # noqa: PLR0915
async def _bedrock_converse_messages_pt_async(
messages: List,
model: str,
llm_provider: str,
@ -5133,7 +5133,7 @@ class BedrockConverseMessagesProcessor:
return assistant_parts
def _bedrock_converse_messages_pt( # noqa: PLR0915
def _bedrock_converse_messages_pt(
messages: List,
model: str,
llm_provider: str,

View file

@ -1198,7 +1198,7 @@ class RealTimeStreaming:
item["content"] = new_content
return item
async def client_ack_messages(self): # noqa: PLR0915
async def client_ack_messages(self):
try:
while True:
message = await self.websocket.receive_text()

View file

@ -209,7 +209,7 @@ class ChunkProcessor:
)
return response
def get_combined_tool_content( # noqa: PLR0915
def get_combined_tool_content(
self, tool_call_chunks: List[Dict[str, Any]]
) -> List[ChatCompletionMessageToolCall]:
tool_calls_list: List[ChatCompletionMessageToolCall] = []

View file

@ -967,7 +967,7 @@ class CustomStreamWrapper:
delta, model_response.choices[0].delta, attribute
)
def return_processed_chunk_logic( # noqa: PLR0915, C901
def return_processed_chunk_logic( # noqa: C901
self,
completion_obj: Dict[str, Any],
model_response: ModelResponseStream,
@ -1145,7 +1145,7 @@ class CustomStreamWrapper:
del model_response.choices[0].delta.reasoning_content
return
def chunk_creator(self, chunk: Any): # type: ignore # noqa: PLR0915
def chunk_creator(self, chunk: Any): # type: ignore
if hasattr(chunk, "id"):
self.response_id = chunk.id
model_response = self.model_response_creator()
@ -1887,7 +1887,7 @@ class CustomStreamWrapper:
model_response.choices[0].finish_reason = "tool_calls"
return model_response
def __next__(self) -> "ModelResponseStream": # noqa: PLR0915
def __next__(self) -> "ModelResponseStream":
cache_hit = False
if (
self.custom_llm_provider is not None
@ -2077,7 +2077,7 @@ class CustomStreamWrapper:
return self.completion_stream
async def __anext__(self) -> "ModelResponseStream": # noqa: PLR0915
async def __anext__(self) -> "ModelResponseStream":
cache_hit = False
if (
self.custom_llm_provider is not None

View file

@ -772,7 +772,7 @@ class ModelResponseIterator:
)
return results
def chunk_parser(self, chunk: dict) -> ModelResponseStream: # noqa: PLR0915
def chunk_parser(self, chunk: dict) -> ModelResponseStream:
try:
type_chunk = chunk.get("type", "") or ""

View file

@ -605,7 +605,7 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
)
return _tool_choice
def _map_tool_helper( # noqa: PLR0915
def _map_tool_helper(
self,
tool: ChatCompletionToolParam,
) -> Tuple[Optional[AllAnthropicToolsValues], Optional[AnthropicMcpServerTool]]:
@ -1399,7 +1399,7 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
return None
def map_openai_params( # noqa: PLR0915
def map_openai_params(
self,
non_default_params: dict,
optional_params: dict,

View file

@ -372,7 +372,7 @@ class AnthropicStreamWrapper(AdapterCompletionStreamWrapper):
cache_read_input_tokens=0,
)
def __next__(self): # noqa: PLR0915
def __next__(self):
from .transformation import LiteLLMAnthropicMessagesAdapter
try:
@ -618,7 +618,7 @@ class AnthropicStreamWrapper(AdapterCompletionStreamWrapper):
)
raise StopIteration
async def __anext__(self): # noqa: PLR0915
async def __anext__(self):
from .transformation import LiteLLMAnthropicMessagesAdapter
try:

View file

@ -383,7 +383,7 @@ class LiteLLMAnthropicMessagesAdapter:
isinstance(tool_type, str) and tool_type.startswith("web_search")
) or tool_name == "web_search"
def translate_anthropic_messages_to_openai( # noqa: PLR0915
def translate_anthropic_messages_to_openai(
self,
messages: List[
Union[

View file

@ -97,7 +97,7 @@ def _read_summary_max_tokens_setting() -> int:
return COMPACT_SUMMARY_MAX_TOKENS
async def _check_summary_model_access( # noqa: PLR0915
async def _check_summary_model_access(
user_api_key_auth: Any,
summary_model: str,
llm_router: Any,
@ -970,7 +970,7 @@ def apply_client_compaction_block_history(
)
async def apply_compact_20260112( # noqa: PLR0915
async def apply_compact_20260112(
*,
model: str,
messages: List[Dict[str, Any]],

View file

@ -66,7 +66,7 @@ class AnthropicResponsesStreamWrapper:
self._current_block_index += 1
return self._current_block_index
def _process_event(self, event: Any) -> None: # noqa: PLR0915
def _process_event(self, event: Any) -> None:
"""Convert one Responses API event into zero or more Anthropic chunks queued for emission."""
event_type = getattr(event, "type", None)
if event_type is None and isinstance(event, dict):

View file

@ -51,7 +51,7 @@ class LiteLLMAnthropicToResponsesAPIAdapter:
return source.get("url")
return None
def translate_messages_to_responses_input( # noqa: PLR0915
def translate_messages_to_responses_input(
self,
messages: List[
Union[

View file

@ -248,7 +248,7 @@ class BedrockConverseLLM(BaseAWSLLM):
encoding=encoding,
)
def completion( # noqa: PLR0915
def completion(
self,
model: str,
messages: list,

View file

@ -2189,7 +2189,7 @@ class AmazonConverseConfig(BaseConfig):
real_tools = [t for i, t in enumerate(tools) if i not in json_tool_indices]
return real_tools if real_tools else None
def _transform_response( # noqa: PLR0915
def _transform_response(
self,
model: str,
response: httpx.Response,

View file

@ -473,7 +473,7 @@ class BedrockLLM(BaseAWSLLM):
prompt += f"{message['content']}"
return prompt, chat_history # type: ignore
def process_response( # noqa: PLR0915
def process_response(
self,
model: str,
response: httpx.Response,
@ -765,7 +765,7 @@ class BedrockLLM(BaseAWSLLM):
return model_response
def completion( # noqa: PLR0915
def completion(
self,
model: str,
messages: list,

View file

@ -388,7 +388,7 @@ class BedrockEmbedding(BaseAWSLLM):
batch_data=batch_data,
)
def embeddings( # noqa: PLR0915
def embeddings(
self,
model: str,
input: List[str],

View file

@ -149,7 +149,7 @@ class BedrockStabilityImageEditConfig(BaseImageEditConfig):
return mapped_params
def transform_image_edit_request( # noqa: PLR0915
def transform_image_edit_request(
self,
model: str,
prompt: Optional[str],

View file

@ -226,7 +226,7 @@ class BedrockPassthroughGuardrailHandler(BaseTranslation):
return _is_converse_endpoint(endpoint)
@staticmethod
async def de_anonymize_event_stream( # noqa: PLR0915
async def de_anonymize_event_stream(
body_bytes: bytes,
proxy_logging_obj: "ProxyLogging",
user_api_key_dict: "UserAPIKeyAuth",

View file

@ -5676,7 +5676,7 @@ class BaseLLMHTTPHandler:
)
raise
async def async_responses_websocket( # noqa: PLR0915
async def async_responses_websocket(
self,
model: str,
websocket: Any,

View file

@ -1378,7 +1378,7 @@ class GeminiRealtimeConfig(BaseRealtimeConfig):
raise ValueError(f"Unknown openai event: {key}, value: {value}")
return openai_event
def transform_realtime_response( # noqa: PLR0915
def transform_realtime_response(
self,
message: Union[str, bytes],
model: str,

View file

@ -404,7 +404,7 @@ class HuggingFaceEmbeddingConfig(BaseConfig):
)
return completion_response
def convert_to_model_response_object( # noqa: PLR0915
def convert_to_model_response_object(
self,
completion_response: Union[List[Dict[str, Any]], Dict[str, Any]],
model_response: ModelResponse,

View file

@ -608,7 +608,7 @@ class OpenAIChatCompletion(BaseLLM, BaseOpenAILLM):
return streaming_response
def completion( # type: ignore # noqa: PLR0915
def completion( # type: ignore
self,
model_response: ModelResponse,
timeout: Union[float, httpx.Timeout],

View file

@ -129,7 +129,7 @@ class PredibaseConfig(BaseConfig):
optional_params["response_format"] = value
return optional_params
def transform_response( # noqa: PLR0915
def transform_response(
self,
model: str,
raw_response: Response,

View file

@ -678,7 +678,7 @@ def check_if_part_exists_in_parts(
return False
def _gemini_convert_messages_with_history( # noqa: PLR0915
def _gemini_convert_messages_with_history(
messages: List[AllMessageValues],
model: Optional[str] = None,
litellm_params: Optional[dict] = None,
@ -1176,7 +1176,7 @@ def _rewrite_google_maps_response_format(data: RequestBody) -> None:
_rewrite_mime_type_to_response_format(generation_config)
def _transform_request_body( # noqa: PLR0915
def _transform_request_body(
messages: List[AllMessageValues],
model: str,
optional_params: dict,

View file

@ -614,9 +614,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
return googleSearch, googleSearchRetrieval, enterpriseWebSearch, urlContext
def _map_function( # noqa: PLR0915
self, value: List[dict], optional_params: dict
) -> List[Tools]:
def _map_function(self, value: List[dict], optional_params: dict) -> List[Tools]:
"""
Map OpenAI-style tools/functions to Vertex AI format.
@ -1173,7 +1171,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
optional_params["include_server_side_tool_invocations"] = True
return
def map_openai_params( # noqa: PLR0915
def map_openai_params(
self,
non_default_params: Dict,
optional_params: Dict,
@ -1904,7 +1902,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
return False
@staticmethod
def _calculate_usage( # noqa: PLR0915
def _calculate_usage(
completion_response: Union[
GenerateContentResponseBody, BidiGenerateContentServerMessage
],
@ -2380,7 +2378,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
return annotations
@staticmethod
def _process_candidates( # noqa: PLR0915
def _process_candidates(
_candidates: List[Candidates],
model_response: Union[ModelResponse, "ModelResponseStream"],
standard_optional_params: dict,

View file

@ -124,7 +124,7 @@ class GoogleBatchEmbeddings(VertexLLM):
return resolved_files
def batch_embeddings( # noqa: PLR0915
def batch_embeddings(
self,
model: str,
input: GeminiEmbeddingInput,

View file

@ -77,7 +77,7 @@ def _set_client_in_cache(client_cache_key: str, vertex_llm_model: Any):
)
def completion( # noqa: PLR0915
def completion(
model: str,
messages: list,
model_response: ModelResponse,
@ -485,7 +485,7 @@ def completion( # noqa: PLR0915
)
async def async_completion( # noqa: PLR0915
async def async_completion(
llm_model,
mode: str,
prompt: str,

View file

@ -1086,7 +1086,7 @@ def _build_custom_pricing_entry(
@tracer.wrap()
@client
def completion( # type: ignore # noqa: PLR0915
def completion( # type: ignore
model: str,
# Optional OpenAI params: see https://platform.openai.com/docs/api-reference/chat/create
messages: List = [],
@ -4878,7 +4878,7 @@ def embedding(
@client
def embedding( # noqa: PLR0915
def embedding(
model,
input=[],
# Optional params
@ -6125,7 +6125,7 @@ async def atext_completion(
@client
def text_completion( # noqa: PLR0915
def text_completion(
prompt: Union[
str, List[Union[str, List[Union[str, List[int]]]]]
], # Required: The prompt(s) to generate completions for.
@ -6664,7 +6664,7 @@ async def atranscription(*args, **kwargs) -> TranscriptionResponse:
@client
def transcription( # noqa: PLR0915
def transcription(
model: str,
file: FileTypes,
## OPTIONAL OPENAI PARAMS ##
@ -6971,7 +6971,7 @@ async def aspeech(*args, **kwargs) -> HttpxBinaryResponseContent:
@client
def speech( # noqa: PLR0915
def speech(
model: str,
input: str,
voice: Optional[Union[str, dict]] = None,
@ -7662,7 +7662,7 @@ def stream_chunk_builder_text_completion(
return TextCompletionResponse(**response)
def stream_chunk_builder( # noqa: PLR0915
def stream_chunk_builder(
chunks: list,
messages: Optional[list] = None,
start_time=None,

View file

@ -125,7 +125,7 @@ class MCPRequestHandler:
LITELLM_MCP_ACCESS_GROUPS_HEADER_NAME = SpecialHeaders.mcp_access_groups.value
@staticmethod
async def process_mcp_request( # noqa: PLR0915
async def process_mcp_request(
scope: Scope,
) -> Tuple[
UserAPIKeyAuth,

View file

@ -3355,7 +3355,7 @@ class MCPServerManager:
)
)
async def _call_regular_mcp_tool( # noqa: PLR0915
async def _call_regular_mcp_tool(
self,
mcp_server: MCPServer,
original_tool_name: str,

View file

@ -661,7 +661,7 @@ def _convert_openai_response_to_mcp_result(
)
async def _check_model_access( # noqa: PLR0915
async def _check_model_access(
model: str, user_api_key_auth: Any
) -> Optional["ErrorData"]:
"""Enforce model-permission checks for MCP sampling requests.

View file

@ -617,7 +617,7 @@ if MCP_AVAILABLE:
active_mcp_session_var.reset(_session_reset_token)
@server.call_tool()
async def mcp_server_tool_call( # noqa: PLR0915
async def mcp_server_tool_call(
name: str, arguments: Dict[str, Any] | None
) -> CallToolResult:
"""
@ -1591,7 +1591,7 @@ if MCP_AVAILABLE:
_mcp_gateway_initialize_instructions.reset(instructions_token)
_mcp_gateway_server_name.reset(server_name_token)
async def _get_tools_from_mcp_servers( # noqa: PLR0915
async def _get_tools_from_mcp_servers(
user_api_key_auth: Optional[UserAPIKeyAuth],
mcp_auth_header: Optional[str],
mcp_servers: Optional[List[str]],
@ -2435,7 +2435,7 @@ if MCP_AVAILABLE:
},
)
async def execute_mcp_tool( # noqa: PLR0915
async def execute_mcp_tool(
name: str,
arguments: Dict[str, Any],
allowed_mcp_servers: List[MCPServer],
@ -3642,7 +3642,7 @@ if MCP_AVAILABLE:
detail="Forbidden",
)
async def handle_streamable_http_mcp( # noqa: PLR0915
async def handle_streamable_http_mcp(
scope: Scope, receive: Receive, send: Send
) -> None:
"""Handle MCP requests through StreamableHTTP."""

View file

@ -2152,6 +2152,10 @@ class ConfigGeneralSettings(LiteLLMPydanticObjectBase):
master_key: Optional[str] = Field(
None, description="require a key for all calls to proxy"
)
allow_cli_sso_verification_uri_complete: bool | None = Field(
None,
description="opt-in to RFC 8628 verification_uri_complete for the CLI SSO device flow, pre-filling the user_code in the browser. Off by default; intended for same-host clients where the device that starts the flow and the browser run on the same machine",
)
database_url: Optional[str] = Field(
None,
description="connect to a postgres db - needed for generating temporary keys + tracking spend / key",

View file

@ -509,7 +509,7 @@ async def get_agent_card(
tags=["[beta] A2A Agents"],
dependencies=[Depends(user_api_key_auth)],
)
async def invoke_agent_a2a( # noqa: PLR0915
async def invoke_agent_a2a(
agent_id: str,
request: Request,
fastapi_response: Response,

View file

@ -519,7 +519,7 @@ MODEL_DISCOVERY_ROUTES = frozenset(
)
async def common_checks( # noqa: PLR0915
async def common_checks(
request_body: dict,
team_object: Optional[LiteLLM_TeamTable],
user_object: Optional[LiteLLM_UserTable],

View file

@ -1954,7 +1954,7 @@ class JWTAuthManager:
return None, None, None
@staticmethod
async def auth_builder( # noqa: PLR0915
async def auth_builder(
api_key: str,
jwt_handler: JWTHandler,
request_data: dict,

View file

@ -979,7 +979,7 @@ def _ensure_parent_otel_span_on_request_state(request: Request) -> None:
request.state.parent_otel_span = parent_otel_span
async def _user_api_key_auth_builder( # noqa: PLR0915
async def _user_api_key_auth_builder(
request: Request,
api_key: str,
azure_api_key_header: str,
@ -2126,7 +2126,7 @@ def _team_obj_from_token(valid_token: UserAPIKeyAuth) -> LiteLLM_TeamTableCached
@tracer.wrap()
async def _run_centralized_common_checks( # noqa: PLR0915
async def _run_centralized_common_checks(
user_api_key_auth_obj: UserAPIKeyAuth,
request: Request,
request_data: dict,

View file

@ -58,7 +58,7 @@ router = APIRouter()
dependencies=[Depends(user_api_key_auth)],
tags=["batch"],
)
async def create_batch( # noqa: PLR0915
async def create_batch(
request: Request,
fastapi_response: Response,
provider: Optional[str] = None,
@ -343,7 +343,7 @@ async def create_batch( # noqa: PLR0915
dependencies=[Depends(user_api_key_auth)],
tags=["batch"],
)
async def retrieve_batch( # noqa: PLR0915
async def retrieve_batch(
request: Request,
fastapi_response: Response,
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),

View file

@ -300,7 +300,7 @@ class _UpstreamClosingStreamingResponse(StreamingResponse):
)
async def create_response( # noqa: PLR0915
async def create_response(
generator: AsyncGenerator[str, None],
media_type: str,
headers: dict,
@ -1148,7 +1148,7 @@ class ProxyBaseLLMRequestProcessing:
_payload_str,
)
async def base_process_llm_request( # noqa: PLR0915
async def base_process_llm_request(
self,
request: Request,
fastapi_response: Response,

View file

@ -36,7 +36,7 @@ if TYPE_CHECKING:
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLogging
def initialize_callbacks_on_proxy( # noqa: PLR0915
def initialize_callbacks_on_proxy(
value: Any,
premium_user: bool,
config_file_path: str,

View file

@ -11,7 +11,7 @@ _db = Any
_VIEW_NOT_FOUND_MARKERS = ("does not exist", "no such table", "undefined table")
async def create_missing_views(db: _db): # noqa: PLR0915
async def create_missing_views(db: _db):
"""
--------------------------------------------------
NOTE: Copy of `litellm/db_scripts/create_views.py`.

View file

@ -1128,7 +1128,7 @@ class DBSpendUpdateWriter:
"_flush_tool_discovery_queue error (non-blocking): %s", e
)
async def _commit_spend_updates_to_db( # noqa: PLR0915
async def _commit_spend_updates_to_db(
self,
prisma_client: PrismaClient,
n_retry_times: int,

View file

@ -121,7 +121,7 @@ class lakeraAI_Moderation(CustomGuardrail):
return None
async def _check( # noqa: PLR0915
async def _check(
self,
data: dict,
user_api_key_dict: UserAPIKeyAuth,

View file

@ -261,7 +261,7 @@ class PanwPrismaAirsHandler(CustomGuardrail):
)
return ""
async def _call_panw_api( # noqa: PLR0915
async def _call_panw_api(
self,
content: str = "",
is_response: bool = False,
@ -1762,7 +1762,7 @@ class PanwPrismaAirsHandler(CustomGuardrail):
return rd.get("name") if ("arguments" in rd or "mcp_arguments" in rd) else None
@log_guardrail_information
async def apply_guardrail( # noqa: PLR0915
async def apply_guardrail(
self,
inputs: GenericGuardrailAPIInputs,
request_data: dict,

View file

@ -288,7 +288,7 @@ class UnifiedLLMGuardrails(CustomLogger):
return response
async def async_post_call_streaming_iterator_hook( # noqa: PLR0915
async def async_post_call_streaming_iterator_hook(
self,
user_api_key_dict: UserAPIKeyAuth,
response: Any,

View file

@ -167,7 +167,7 @@ async def test_endpoint(request: Request):
tags=["health"],
dependencies=[Depends(user_api_key_auth)],
)
async def health_services_endpoint( # noqa: PLR0915
async def health_services_endpoint(
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
service: services = fastapi.Query(description="Specify the service being hit."),
):

View file

@ -239,7 +239,7 @@ class _PROXY_MaxParallelRequestsHandler(CustomLogger):
request_count_end_user_id=results[5],
)
async def async_pre_call_hook( # noqa: PLR0915
async def async_pre_call_hook(
self,
user_api_key_dict: UserAPIKeyAuth,
cache: DualCache,
@ -506,9 +506,7 @@ class _PROXY_MaxParallelRequestsHandler(CustomLogger):
return
async def async_log_success_event( # noqa: PLR0915
self, kwargs, response_obj, start_time, end_time
):
async def async_log_success_event(self, kwargs, response_obj, start_time, end_time):
from litellm.proxy.common_utils.callback_utils import (
get_model_group_from_litellm_kwargs,
)

View file

@ -1317,7 +1317,7 @@ class LiteLLMProxyRequestSetup:
)
async def add_litellm_data_to_request( # noqa: PLR0915
async def add_litellm_data_to_request(
data: dict,
request: Request,
user_api_key_dict: UserAPIKeyAuth,

View file

@ -726,7 +726,7 @@ def _key_metadata(
return KeyMetadata(key_alias=meta.get("key_alias"), team_id=meta.get("team_id"))
def _aggregate_grouping_sets_records_sync( # noqa: PLR0915
def _aggregate_grouping_sets_records_sync(
*,
records: List[Any],
api_key_metadata: Dict[str, Dict[str, Any]],

View file

@ -675,7 +675,7 @@ def _enforce_upperbound_key_params(
)
async def _common_key_generation_helper( # noqa: PLR0915
async def _common_key_generation_helper(
data: GenerateKeyRequest,
user_api_key_dict: UserAPIKeyAuth,
litellm_changed_by: Optional[str],
@ -3419,7 +3419,7 @@ def _check_model_access_group(
return True
async def generate_key_helper_fn( # noqa: PLR0915
async def generate_key_helper_fn(
request_type: Literal[
"user", "key"
], # identifies if this request is from /user/new or /key/generate
@ -4070,7 +4070,7 @@ async def delete_key_aliases(
)
async def _rotate_master_key( # noqa: PLR0915
async def _rotate_master_key(
prisma_client: PrismaClient,
user_api_key_dict: UserAPIKeyAuth,
current_master_key: str,

View file

@ -933,7 +933,7 @@ def _check_team_budget_update_authority(
response_model=LiteLLM_TeamTable,
)
@management_endpoint_wrapper
async def new_team( # noqa: PLR0915
async def new_team(
data: NewTeamRequest,
http_request: Request,
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
@ -1637,7 +1637,7 @@ def validate_team_org_change(
"/team/update", tags=["team management"], dependencies=[Depends(user_api_key_auth)]
)
@management_endpoint_wrapper
async def update_team( # noqa: PLR0915
async def update_team(
data: UpdateTeamRequest,
http_request: Request,
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),

View file

@ -145,6 +145,9 @@ _CLI_SSO_START_RATE_LIMIT_WINDOW_SECONDS = 60
_CLI_SSO_START_RATE_LIMIT_MAX_ATTEMPTS = 30
_CLI_SSO_USER_CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
_CLI_SSO_LOGIN_ID_RE = re.compile(r"^cli-[A-Za-z0-9_-]{12,124}$")
_CLI_SSO_USER_CODE_RE = re.compile(
rf"^[{_CLI_SSO_USER_CODE_ALPHABET}]{{4}}-[{_CLI_SSO_USER_CODE_ALPHABET}]{{4}}$"
)
_CLI_SSO_SCALAR_TYPES = (str, int, float, bool)
_CLI_SSO_DEST_KEY_RE = re.compile(r"^[A-Za-z0-9_.-]+$")
_CLI_SSO_SECRET_KEY_FRAGMENTS = frozenset(
@ -182,6 +185,45 @@ def _is_valid_cli_sso_login_id(login_id: Optional[str]) -> bool:
return isinstance(login_id, str) and bool(_CLI_SSO_LOGIN_ID_RE.fullmatch(login_id))
def _is_valid_cli_sso_user_code(user_code: str | None) -> bool:
return isinstance(user_code, str) and bool(
_CLI_SSO_USER_CODE_RE.fullmatch(user_code)
)
def _cli_sso_verification_uri_complete_enabled() -> bool:
from litellm.proxy.proxy_server import general_settings
return bool(
general_settings.get( # any-ok: operator opt-in read from the untyped general_settings dict
"allow_cli_sso_verification_uri_complete", False
)
)
def _cli_sso_start_response_body(
*,
login_id: str,
poll_secret: str,
user_code: str,
verification_uri_complete: str | None,
) -> dict[str, str | int]:
if verification_uri_complete is None:
return {
"login_id": login_id,
"poll_secret": poll_secret,
"user_code": user_code,
"expires_in": CLI_SSO_SESSION_TTL_SECONDS,
}
return {
"login_id": login_id,
"poll_secret": poll_secret,
"user_code": user_code,
"verification_uri_complete": verification_uri_complete,
"expires_in": CLI_SSO_SESSION_TTL_SECONDS,
}
def _get_cli_sso_start_rate_limit_cache_key(
request: Request, use_x_forwarded_for: Optional[bool] = False
) -> str:
@ -478,10 +520,20 @@ def _cli_poll_attribution_metadata_from_session(
def _render_cli_sso_verification_page(
verify_url: str, browser_complete_token: str
verify_url: str,
browser_complete_token: str,
prefill_user_code: str | None = None,
) -> str:
escaped_verify_url = escape(verify_url, quote=True)
escaped_browser_complete_token = escape(browser_complete_token, quote=True)
user_code_value_attr = (
f' value="{escape(prefill_user_code, quote=True)}"' if prefill_user_code else ""
)
instructions = (
"Confirm the verification code below to finish this login."
if prefill_user_code
else "Enter the verification code shown in your terminal to finish this login."
)
return f"""
<!doctype html>
<html>
@ -535,11 +587,11 @@ def _render_cli_sso_verification_page(
<body>
<main>
<h1>Complete CLI Login</h1>
<p>Enter the verification code shown in your terminal to finish this login.</p>
<p>{instructions}</p>
<form method="post" action="{escaped_verify_url}">
<input type="hidden" name="browser_complete_token" value="{escaped_browser_complete_token}" />
<label for="user_code">Verification code</label>
<input id="user_code" name="user_code" autocomplete="one-time-code" required autofocus />
<input id="user_code" name="user_code" autocomplete="one-time-code"{user_code_value_attr} required autofocus />
<button type="submit">Continue</button>
</form>
</main>
@ -573,12 +625,29 @@ async def cli_sso_start(request: Request):
}
_set_cli_sso_flow(login_id=login_id, cache=user_api_key_cache, flow=flow)
return {
"login_id": login_id,
"poll_secret": poll_secret,
"user_code": user_code,
"expires_in": CLI_SSO_SESSION_TTL_SECONDS,
}
verification_uri_complete: str | None = (
(
get_custom_url(
request_base_url=str(request.base_url), route="sso/key/generate"
)
+ "?"
+ urlencode(
{
"source": LITELLM_CLI_SOURCE_IDENTIFIER,
"key": login_id,
"user_code": user_code,
}
)
)
if _cli_sso_verification_uri_complete_enabled()
else None
)
return _cli_sso_start_response_body(
login_id=login_id,
poll_secret=poll_secret,
user_code=user_code,
verification_uri_complete=verification_uri_complete,
)
@router.post(
@ -829,6 +898,7 @@ async def google_login(
key: Optional[str] = None,
existing_key: Optional[str] = None,
return_to: Optional[str] = None,
user_code: str | None = None,
):
"""
Create Proxy API Keys using Google Workspace SSO. Requires setting PROXY_BASE_URL in .env
@ -897,6 +967,7 @@ async def google_login(
cli_state: Optional[str] = SSOAuthenticationHandler._get_cli_state(
source=source,
key=key,
user_code=(user_code if _cli_sso_verification_uri_complete_enabled() else None),
)
# check if user defined a custom auth sso sign in handler, if yes, use it
@ -1921,14 +1992,16 @@ async def auth_callback(request: Request, state: Optional[str] = None):
)
if state and state.startswith(f"{LITELLM_CLI_SESSION_TOKEN_PREFIX}:"):
# State format: {PREFIX}:{login_id}
state_parts = state.split(":", 1)
# State format: {PREFIX}:{login_id}[:{user_code}]
state_parts = state.split(":", 2)
key_id = state_parts[1] if len(state_parts) > 1 else None
prefill_user_code = state_parts[2] if len(state_parts) > 2 else None
verbose_proxy_logger.info("CLI SSO callback detected")
return await cli_sso_callback(
request=request,
key=key_id,
prefill_user_code=prefill_user_code,
result=result,
received_response=received_response,
)
@ -2008,6 +2081,7 @@ async def _complete_cli_sso_callback_session(
prisma_client: PrismaClient,
user_api_key_cache: UserApiKeyCache,
proxy_logging_obj: ProxyLogging,
prefill_user_code: str | None = None,
):
from fastapi.responses import HTMLResponse
@ -2071,6 +2145,7 @@ async def _complete_cli_sso_callback_session(
content=_render_cli_sso_verification_page(
verify_url=verify_url,
browser_complete_token=browser_complete_token,
prefill_user_code=prefill_user_code,
),
status_code=200,
)
@ -2081,6 +2156,7 @@ async def cli_sso_callback(
key: Optional[str] = None,
result: Optional[Union[OpenID, dict]] = None,
received_response: Optional[dict] = None,
prefill_user_code: str | None = None,
):
"""CLI SSO callback - stores session info for JWT generation on polling"""
verbose_proxy_logger.info("CLI SSO callback")
@ -2137,6 +2213,7 @@ async def cli_sso_callback(
prisma_client=prisma_client,
user_api_key_cache=user_api_key_cache,
proxy_logging_obj=proxy_logging_obj,
prefill_user_code=prefill_user_code,
)
except ProxyException:
raise
@ -3053,21 +3130,27 @@ class SSOAuthenticationHandler:
@staticmethod
def _get_cli_state(
source: Optional[str], key: Optional[str], existing_key: Optional[str] = None
source: str | None,
key: str | None,
existing_key: str | None = None,
user_code: str | None = None,
) -> Optional[str]:
"""
Checks the request 'source' if a cli state token was passed in
This is used to authenticate through the CLI login flow.
The state parameter format is: {PREFIX}:{login_id}
The state parameter format is: {PREFIX}:{login_id}[:{user_code}]
- The state parameter is used to pass data through the OAuth flow without changing the callback URL
- user_code is appended only for the opt-in verification_uri_complete flow so the verify page can pre-fill it
"""
from litellm.constants import (
LITELLM_CLI_SESSION_TOKEN_PREFIX,
)
if source == LITELLM_CLI_SOURCE_IDENTIFIER and key:
if _is_valid_cli_sso_user_code(user_code):
return f"{LITELLM_CLI_SESSION_TOKEN_PREFIX}:{key}:{user_code}"
return f"{LITELLM_CLI_SESSION_TOKEN_PREFIX}:{key}"
else:
return None
@ -3145,7 +3228,7 @@ class SSOAuthenticationHandler:
)
@staticmethod
async def get_redirect_response_from_openid( # noqa: PLR0915
async def get_redirect_response_from_openid(
result: Union[OpenID, dict, CustomOpenID],
request: Request,
received_response: Optional[dict] = None,

View file

@ -284,7 +284,7 @@ async def route_create_file(
dependencies=[Depends(user_api_key_auth)],
tags=["files"],
)
async def create_file( # noqa: PLR0915
async def create_file(
request: Request,
fastapi_response: Response,
purpose: str = Form(...),
@ -589,7 +589,7 @@ async def create_file( # noqa: PLR0915
dependencies=[Depends(user_api_key_auth)],
tags=["files"],
)
async def get_file_content( # noqa: PLR0915
async def get_file_content(
request: Request,
fastapi_response: Response,
file_id: str,

View file

@ -366,7 +366,7 @@ class AnthropicPassthroughLoggingHandler:
)
@staticmethod
def _collapse_pure_text_chunks( # noqa: PLR0915
def _collapse_pure_text_chunks(
all_chunks: Sequence[Union[str, bytes]],
) -> Optional[List[str]]:
"""
@ -551,7 +551,7 @@ class AnthropicPassthroughLoggingHandler:
return complete_streaming_response
@staticmethod
def batch_creation_handler( # noqa: PLR0915
def batch_creation_handler(
httpx_response: httpx.Response,
logging_obj: LiteLLMLoggingObj,
url_route: str,

View file

@ -275,7 +275,7 @@ class OpenAIPassthroughLoggingHandler(BasePassthroughLoggingHandler):
return litellm_model_response, response_cost
@staticmethod
def openai_passthrough_handler( # noqa: PLR0915
def openai_passthrough_handler(
httpx_response: httpx.Response,
response_body: dict,
logging_obj: LiteLLMLoggingObj,

View file

@ -645,7 +645,7 @@ class VertexPassthroughLoggingHandler:
return kwargs
@staticmethod
def batch_prediction_jobs_handler( # noqa: PLR0915
def batch_prediction_jobs_handler(
httpx_response: httpx.Response,
logging_obj: LiteLLMLoggingObj,
url_route: str,

View file

@ -143,7 +143,7 @@ async def set_env_variables_in_header(custom_headers: Optional[dict]) -> Optiona
return headers
async def chat_completion_pass_through_endpoint( # noqa: PLR0915
async def chat_completion_pass_through_endpoint(
fastapi_response: Response,
request: Request,
adapter_id: str,
@ -701,7 +701,7 @@ from litellm.passthrough.timeout_utils import (
)
async def pass_through_request( # noqa: PLR0915
async def pass_through_request(
request: Request,
target: str,
custom_headers: dict,
@ -1540,7 +1540,7 @@ async def _parse_request_data_by_content_type(
return query_params_data, custom_body_data, file_data, stream
def create_pass_through_route( # noqa: PLR0915
def create_pass_through_route(
endpoint,
target: str,
custom_headers: Optional[Mapping[str, Any]] = None,
@ -1776,7 +1776,7 @@ def create_websocket_passthrough_route(
return websocket_endpoint_func
async def websocket_passthrough_request( # noqa: PLR0915
async def websocket_passthrough_request(
websocket: WebSocket,
target: str,
custom_headers: dict,

View file

@ -814,7 +814,7 @@ class ProxyInitializationHelpers:
default=False,
help="Enable uvicorn hot reload (dev only). Also reloads when the --config YAML file changes. Incompatible with --num_workers>1, --run_gunicorn, and --run_hypercorn.",
)
def run_server( # noqa: PLR0915
def run_server(
cli_args,
host,
port,

View file

@ -745,7 +745,7 @@ async def _initialize_shared_aiohttp_session():
@asynccontextmanager
async def proxy_startup_event(app: FastAPI): # noqa: PLR0915
async def proxy_startup_event(app: FastAPI):
global prisma_client, master_key, use_background_health_checks, llm_router, llm_model_list, general_settings, proxy_budget_rescheduler_min_time, proxy_budget_rescheduler_max_time, litellm_proxy_admin_name, db_writer_client, store_model_in_db, premium_user, _license_check, proxy_batch_polling_interval, shared_aiohttp_session
import json
@ -2496,7 +2496,7 @@ async def _invalidate_spend_counter(counter_key: str):
)
async def update_cache( # noqa: PLR0915
async def update_cache(
token: Optional[str],
user_id: Optional[str],
end_user_id: Optional[str],
@ -3900,7 +3900,7 @@ class ProxyConfig:
premium_user = _license_check.is_premium()
return
async def load_config( # noqa: PLR0915
async def load_config(
self, router: Optional[litellm.Router], config_file_path: str
):
"""
@ -6631,7 +6631,7 @@ def save_worker_config(**data):
os.environ["WORKER_CONFIG"] = json.dumps(data)
async def initialize( # noqa: PLR0915
async def initialize(
model=None,
alias=None,
api_base=None,
@ -7022,7 +7022,7 @@ def _format_streaming_sse_chunk(chunk: Union[str, bytes]) -> Union[str, bytes]:
return f"data: {chunk}\n\n"
async def async_data_generator( # noqa: PLR0915
async def async_data_generator(
response, user_api_key_dict: UserAPIKeyAuth, request_data: dict
):
verbose_proxy_logger.debug("inside generator")
@ -7470,7 +7470,7 @@ class ProxyStartupEvent:
)
@classmethod
async def initialize_scheduled_background_jobs( # noqa: PLR0915
async def initialize_scheduled_background_jobs(
cls,
general_settings: dict,
prisma_client: PrismaClient,
@ -8681,7 +8681,7 @@ async def chat_completion(
dependencies=[Depends(user_api_key_auth)],
tags=["completions"],
)
async def completion( # noqa: PLR0915
async def completion(
request: Request,
fastapi_response: Response,
model: Optional[str] = None,
@ -14411,7 +14411,7 @@ async def invitation_delete(
dependencies=[Depends(user_api_key_auth)],
include_in_schema=False,
)
async def update_config( # noqa: PLR0915
async def update_config(
config_info: ConfigYAML,
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
):
@ -15028,7 +15028,7 @@ async def delete_callback(
include_in_schema=False,
dependencies=[Depends(user_api_key_auth)],
)
async def get_config(): # noqa: PLR0915
async def get_config():
"""
For Admin UI - allows admin to view config via UI
# return the callbacks and the env variables for the callback

View file

@ -21,7 +21,7 @@ from litellm.proxy.response_polling.polling_handler import ResponsePollingHandle
from litellm.types.llms.openai import ResponsesAPIStatus
async def background_streaming_task( # noqa: PLR0915
async def background_streaming_task(
polling_id: str,
data: dict,
polling_handler: ResponsePollingHandler,

View file

@ -264,7 +264,7 @@ async def add_shared_session_to_data(data: dict) -> None:
pass
async def route_request( # noqa: PLR0915 - Complex routing function, refactoring tracked separately
async def route_request(
data: dict,
llm_router: Optional[LitellmRouter],
user_model: Optional[str],

View file

@ -1734,7 +1734,7 @@ async def calculate_spend(request: SpendCalculateRequest):
200: {"model": List[LiteLLM_SpendLogs]},
},
)
async def ui_view_spend_logs( # noqa: PLR0915
async def ui_view_spend_logs(
request: Request,
api_key: Optional[str] = fastapi.Query(
default=None,
@ -2273,7 +2273,7 @@ async def ui_view_request_response_for_request_id(
200: {"model": List[LiteLLM_SpendLogs]},
},
)
async def view_spend_logs( # noqa: PLR0915
async def view_spend_logs(
api_key: Optional[str] = fastapi.Query(
default=None,
description="Get spend logs based on api key",

View file

@ -228,9 +228,7 @@ def _extract_usage_for_ocr_call(response_obj: Any, response_obj_dict: dict) -> d
return {}
def get_logging_payload( # noqa: PLR0915
kwargs, response_obj, start_time, end_time
) -> SpendLogsPayload:
def get_logging_payload(kwargs, response_obj, start_time, end_time) -> SpendLogsPayload:
if kwargs is None:
kwargs = {}

View file

@ -284,7 +284,7 @@ async def arealtime_calls(
@wrapper_client
async def _arealtime( # noqa: PLR0915
async def _arealtime(
model: str,
websocket: Any, # fastapi websocket
api_base: Optional[str] = None,

View file

@ -75,7 +75,7 @@ async def arerank(
@client
def rerank( # noqa: PLR0915
def rerank(
model: str,
query: str,
documents: List[Union[str, Dict[str, Any]]],

View file

@ -77,7 +77,7 @@ def _add_mcp_metadata_to_response(
setattr(message, "provider_specific_fields", provider_fields)
async def acompletion_with_mcp( # noqa: PLR0915
async def acompletion_with_mcp(
model: str,
messages: List,
tools: Optional[List] = None,

View file

@ -644,7 +644,7 @@ class LiteLLM_Proxy_MCP_Handler:
return result_text or "Tool executed successfully"
@staticmethod
async def _execute_tool_calls( # noqa: PLR0915
async def _execute_tool_calls(
tool_server_map: dict[str, str],
tool_calls: List[Any],
user_api_key_auth: Any,

View file

@ -241,7 +241,7 @@ class Router:
lowesttpm_logger: Optional[LowestTPMLoggingHandler] = None
optional_callbacks: Optional[List[Union[CustomLogger, Callable, str]]] = None
def __init__( # noqa: PLR0915
def __init__(
self,
model_list: Optional[
Union[List[DeploymentTypedDict], List[Dict[str, Any]]]
@ -2887,7 +2887,7 @@ class Router:
f"Silent experiment failed for model {silent_model}: {str(e)}"
)
async def _acompletion( # noqa: PLR0915
async def _acompletion(
self, model: str, messages: List[Dict[str, str]], **kwargs
) -> Union[
ModelResponse,
@ -5158,7 +5158,7 @@ class Router:
)
raise e
async def _acreate_file( # noqa: PLR0915
async def _acreate_file(
self,
model: str,
**kwargs,
@ -6467,7 +6467,7 @@ class Router:
# propagate so they remain visible.
return None
async def async_function_with_fallbacks_common_utils( # noqa: PLR0915
async def async_function_with_fallbacks_common_utils(
self,
e: Exception,
disable_fallbacks: Optional[bool],
@ -6843,7 +6843,7 @@ class Router:
)
@tracer.wrap()
async def async_function_with_retries(self, *args, **kwargs): # noqa: PLR0915
async def async_function_with_retries(self, *args, **kwargs):
verbose_router_logger.debug("Inside async function with retries.")
original_function = kwargs.pop("original_function")
fallbacks = kwargs.pop("fallbacks", self.fallbacks)
@ -9324,7 +9324,7 @@ class Router:
return model_info
def _set_model_group_info( # noqa: PLR0915
def _set_model_group_info(
self, model_group: str, user_facing_model_group_name: str
) -> Optional[ModelGroupInfo]:
"""
@ -10566,7 +10566,7 @@ class Router:
)
return client
def _pre_call_checks( # noqa: PLR0915
def _pre_call_checks(
self,
model: str,
healthy_deployments: List,

View file

@ -190,7 +190,7 @@ class LowestCostLoggingHandler(CustomLogger):
)
pass
async def async_get_available_deployments( # noqa: PLR0915
async def async_get_available_deployments(
self,
model_group: str,
healthy_deployments: list,

View file

@ -35,9 +35,7 @@ class LowestLatencyLoggingHandler(CustomLogger):
self.router_cache = router_cache
self.routing_args = RoutingArgs(**routing_args)
def log_success_event( # noqa: PLR0915
self, kwargs, response_obj, start_time, end_time
):
def log_success_event(self, kwargs, response_obj, start_time, end_time):
try:
"""
Update latency usage on success
@ -259,9 +257,7 @@ class LowestLatencyLoggingHandler(CustomLogger):
)
pass
async def async_log_success_event( # noqa: PLR0915
self, kwargs, response_obj, start_time, end_time
):
async def async_log_success_event(self, kwargs, response_obj, start_time, end_time):
try:
"""
Update latency usage on success
@ -413,7 +409,7 @@ class LowestLatencyLoggingHandler(CustomLogger):
)
pass
def _get_available_deployments( # noqa: PLR0915
def _get_available_deployments(
self,
model_group: str,
healthy_deployments: list,

View file

@ -158,7 +158,7 @@ class LowestTPMLoggingHandler(CustomLogger):
verbose_router_logger.debug(traceback.format_exc())
pass
def get_available_deployments( # noqa: PLR0915
def get_available_deployments(
self,
model_group: str,
healthy_deployments: list,

View file

@ -156,7 +156,7 @@ def get_secret_bool(
return str_to_bool(_secret_value)
def get_secret( # noqa: PLR0915
def get_secret(
secret_name: str,
default_value: Optional[Union[str, bool]] = None,
):

View file

@ -23,7 +23,7 @@ def _is_base64(s):
return False
def get_secret_from_manager( # noqa: PLR0915
def get_secret_from_manager(
client: Any,
key_manager: str,
secret_name: str,

View file

@ -1572,7 +1572,7 @@ class Usage(SafeAttributeModel, CompletionUsage):
prompt_tokens_details: Optional[PromptTokensDetailsWrapper] = None
"""Breakdown of tokens used in the prompt."""
def __init__( # noqa: PLR0915
def __init__(
self,
prompt_tokens: Optional[int] = None,
completion_tokens: Optional[int] = None,
@ -1908,7 +1908,7 @@ class ModelResponse(ModelResponseBase):
choices: List[Choices]
"""The list of completion choices the model generated for the input prompt."""
def __init__( # noqa: PLR0915
def __init__(
self,
id=None,
choices=None,

View file

@ -760,7 +760,7 @@ def _remove_thought_signatures_from_messages(
return processed_messages
def function_setup( # noqa: PLR0915
def function_setup(
original_function: str, rules_obj, start_time, *args, **kwargs
): # just run once to check if user wants to send their data anywhere - PostHog/Sentry/Slack/etc.
### NOTICES ###
@ -1422,12 +1422,12 @@ def post_call_processing(
raise e
def client(original_function): # noqa: PLR0915
def client(original_function):
Rules = getattr(sys.modules[__name__], "Rules")
rules_obj = Rules()
@wraps(original_function)
def wrapper(*args, **kwargs): # noqa: PLR0915
def wrapper(*args, **kwargs):
# DO NOT MOVE THIS. It always needs to run first
# Check if this is an async function. If so only execute the async function
call_type = original_function.__name__
@ -1775,7 +1775,7 @@ def client(original_function): # noqa: PLR0915
raise e
@wraps(original_function)
async def wrapper_async(*args, **kwargs): # noqa: PLR0915
async def wrapper_async(*args, **kwargs):
print_args_passed_to_litellm(original_function, args, kwargs)
start_time = datetime.datetime.now()
result = None
@ -2942,7 +2942,7 @@ def _resolve_builtin_model_cost_entry(
return None
def register_model(model_cost: Union[str, dict]): # noqa: PLR0915
def register_model(model_cost: Union[str, dict]):
"""
Register new / Override existing models (and their pricing) to specific providers.
Provide EITHER a model cost dictionary or a url to a hosted json blob
@ -3365,7 +3365,7 @@ def get_optional_params_image_gen(
return optional_params
def get_optional_params_embeddings( # noqa: PLR0915
def get_optional_params_embeddings(
# 2 optional params
model: str,
user: Optional[str] = None,
@ -4112,7 +4112,7 @@ def pre_process_optional_params(
return optional_params
def get_optional_params( # noqa: PLR0915
def get_optional_params(
# use the openai defaults
# https://platform.openai.com/docs/api-reference/chat/create
model: str,
@ -5842,7 +5842,7 @@ def _is_potential_model_name_in_model_cost(
)
def _get_model_info_helper( # noqa: PLR0915
def _get_model_info_helper(
model: str,
custom_llm_provider: Optional[str] = None,
api_base: Optional[str] = None,
@ -6566,7 +6566,7 @@ def create_proxy_transport_and_mounts():
return sync_proxy_mounts, async_proxy_mounts
def validate_environment( # noqa: PLR0915
def validate_environment(
model: Optional[str] = None,
api_key: Optional[str] = None,
api_base: Optional[str] = None,

View file

@ -1,27 +1,27 @@
{
"ANN001": {
"baseline": 2865,
"slack": 10
"slack": 50
},
"ANN002": {
"baseline": 64,
"slack": 3
"slack": 5
},
"ANN003": {
"baseline": 759,
"slack": 10
"slack": 30
},
"ANN201": {
"baseline": 1944,
"slack": 10
"slack": 50
},
"ANN202": {
"baseline": 858,
"slack": 10
"slack": 30
},
"ANN204": {
"baseline": 658,
"slack": 10
"slack": 20
},
"ANN205": {
"baseline": 117,
@ -33,7 +33,7 @@
},
"ANN401": {
"baseline": 1886,
"slack": 10
"slack": 50
},
"ASYNC230": {
"baseline": 11,
@ -45,15 +45,15 @@
},
"B006": {
"baseline": 180,
"slack": 3
"slack": 10
},
"B008": {
"baseline": 490,
"slack": 10
"slack": 15
},
"B009": {
"baseline": 79,
"slack": 10
"slack": 5
},
"B010": {
"baseline": 187,
@ -81,7 +81,7 @@
},
"BLE001": {
"baseline": 2854,
"slack": 10
"slack": 50
},
"C401": {
"baseline": 8,
@ -109,7 +109,7 @@
},
"C901": {
"baseline": 301,
"slack": 3
"slack": 15
},
"D419": {
"baseline": 6,
@ -125,7 +125,7 @@
},
"DTZ005": {
"baseline": 229,
"slack": 10
"slack": 15
},
"DTZ006": {
"baseline": 10,
@ -165,7 +165,7 @@
},
"I001": {
"baseline": 258,
"slack": 10
"slack": 15
},
"LOG015": {
"baseline": 5,
@ -189,11 +189,11 @@
},
"PERF403": {
"baseline": 69,
"slack": 10
"slack": 5
},
"PIE790": {
"baseline": 263,
"slack": 10
"slack": 15
},
"PIE800": {
"baseline": 1,
@ -233,7 +233,7 @@
},
"PLR0913": {
"baseline": 1813,
"slack": 3
"slack": 50
},
"PLR1704": {
"baseline": 3,
@ -245,7 +245,7 @@
},
"PLR1714": {
"baseline": 252,
"slack": 10
"slack": 15
},
"PLR1730": {
"baseline": 7,
@ -265,11 +265,11 @@
},
"PLW0602": {
"baseline": 215,
"slack": 10
"slack": 15
},
"PLW0603": {
"baseline": 183,
"slack": 3
"slack": 10
},
"PLW1508": {
"baseline": 188,
@ -301,15 +301,15 @@
},
"RET504": {
"baseline": 709,
"slack": 10
"slack": 20
},
"RUF010": {
"baseline": 844,
"slack": 10
"slack": 30
},
"RUF012": {
"baseline": 158,
"slack": 3
"slack": 10
},
"RUF015": {
"baseline": 8,
@ -321,7 +321,7 @@
},
"RUF022": {
"baseline": 80,
"slack": 10
"slack": 5
},
"RUF023": {
"baseline": 2,
@ -337,15 +337,15 @@
},
"RUF059": {
"baseline": 69,
"slack": 10
"slack": 5
},
"RUF100": {
"baseline": 465,
"slack": 10
"slack": 15
},
"S110": {
"baseline": 222,
"slack": 10
"slack": 15
},
"S112": {
"baseline": 21,
@ -353,11 +353,11 @@
},
"SIM101": {
"baseline": 58,
"slack": 10
"slack": 5
},
"SIM102": {
"baseline": 311,
"slack": 10
"slack": 15
},
"SIM103": {
"baseline": 119,
@ -412,20 +412,20 @@
"slack": 3
},
"TID251": {
"baseline": 2405,
"slack": 10
"baseline": 2664,
"slack": 50
},
"TRY002": {
"baseline": 528,
"slack": 10
"slack": 20
},
"TRY004": {
"baseline": 93,
"slack": 10
"slack": 5
},
"TRY201": {
"baseline": 409,
"slack": 10
"slack": 15
},
"TRY203": {
"baseline": 113,
@ -433,15 +433,15 @@
},
"TRY300": {
"baseline": 853,
"slack": 10
"slack": 30
},
"UP006": {
"baseline": 12941,
"slack": 10
"slack": 100
},
"UP007": {
"baseline": 2520,
"slack": 10
"slack": 50
},
"UP008": {
"baseline": 2,
@ -469,7 +469,7 @@
},
"UP032": {
"baseline": 609,
"slack": 10
"slack": 20
},
"UP034": {
"baseline": 1,
@ -477,7 +477,7 @@
},
"UP035": {
"baseline": 2250,
"slack": 10
"slack": 50
},
"UP036": {
"baseline": 1,
@ -485,10 +485,10 @@
},
"UP037": {
"baseline": 100,
"slack": 10
"slack": 5
},
"UP045": {
"baseline": 18417,
"slack": 10
"slack": 100
}
}

Some files were not shown because too many files have changed in this diff Show more