- restore the short-circuit in custom_team_metadata_validate: only
touch __call__ when the plain coroutine-function check fails, so a
raising descriptor on an async function is not newly triggered
- inline the noqa reasons per the suppression policy
- drop the ruff-strict-budget.json edit: budget ratcheting is reserved
for the scheduled automation on the default branch
Zeroes the remaining violations for 12 rules so they can hard-fail
in the main ruff config instead of being budget-ratcheted, and drops
their strict-gate budgets to 0:
- B021: drop useless f-prefix on the Javelin docstring
- C404 / C419: dict()/any() around unnecessary list comprehension
- PLR0124: replace the 'value == value' NaN idiom (and the separate
+/-inf exclusion) with math.isfinite in _validate_response_time
- SIM201: 'not X == "function"' -> 'X != "function"'
- SIM211: 'False if x is False else True' -> 'x is not False'
- SIM222: drop literal 'None or' before "success"
- UP036: remove the dead sys.version_info < (3, 8) branch (and the
now-unused sys import) in the weights_biases TYPE_CHECKING block
- B018 x2: keep the deliberate property side-effect access but assign
it ('_ = self.prompt_manager') as the rule requires
- PLR0206: the unusable '@property def api_version(self, api_version)'
(a property getter cannot take extra args) becomes a @staticmethod
matching its siblings get_api_base/get_api_key; it had no callers
- PLR1704: rename the loop variable (and the nested helper parameter)
that shadowed abatch_completion_fastest_response's 'model' argument
- B004 x2: scoped noqa with rationale — both sites retrieve __call__
to unwrap functors for iscoroutinefunction, which is a value use,
not the callability test B004 assumes; the callable() autofix would
break them
N999 intentionally stays on the ratchet (limit 1): it flags the
'litellm/proxy/lambda.py' filename, which needs a module rename.
Verified: full-tree 'ruff check litellm' green with the graduated
rules enforced; ruff-strict counts for all 12 rules are 0; budget
JSON regenerated in the gate script's json.dumps style.
The org cache entries written by prefetch_auth_objects carry the 5s
DEFAULT_IN_MEMORY_TTL. The first @log_db_metrics getter lazily imports
litellm.proxy.proxy_server, which on a cold CI runner can take longer
than 5s, so the org entry expired before get_org_object read it and the
getter fell through to the MagicMock database. Inject a frozen clock
into InMemoryCache so the test asserts the join, not import latency.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Move the BaseLLMException import into _map_error_event_exception so the
module no longer imports it at load time, clearing the module-level cyclic
import CodeQL flagged. The class is used only on the cold error path.
Replace the mutable list-append test collector with aiter/anext so the
regression tests read the stream immutably.
RouterRateLimitError now carries the model group's deployment ids so it
can tell when every deployment is cooled down, and exposes that as
type=all_deployments_in_cooldown with an explicit message. A partial
cooldown keeps type=rate_limit_error. Either way the proxy no longer
reports type=internal_server_error next to code 429
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Mid-stream error events on the streaming Responses API were all raised as
APIError, so a content_policy_violation event never matched the router's
content-policy fallback dispatch and the client got the raw error instead
of the fallback model's answer. Map each error event's code and status
through the existing exception_type mapping, matching the non-streaming
path, and unwrap the typed ContentPolicyViolationError and
ContextWindowExceededError so the router routes them to the configured
content_policy_fallbacks and context_window_fallbacks.
The generic 400 branch of the OpenAI exception mapper dropped the wire body and no
branch carried the response headers, so an application calling a LiteLLM proxy through
a litellm_proxy/ model could not tell a guardrail block from any other failure without
walking __cause__. BadRequestError now takes headers, filled for a litellm_proxy
upstream, and the generic branch passes the body. The proxy edge treats the literal
"None" type and param an older proxy sends as absent and stops forwarding an upstream
proxy's date and server headers.
CodeQL resolves `from openai import Omit` in litellm/types/llms/openai.py to the
module itself, so every importer of a name whose definition line is in the diff
is reported as an unsafe cyclic import. 76ae35dfcd edited the line that defines
BaseLiteLLMOpenAIResponseObject there and got two alerts at files this PR does
not touch. That line is now byte-identical to main and CachedTokensDetails
arrives through a relative import isort keeps separate.
CodeQL flagged two module-level cyclic imports introduced by defining
CachedTokensDetails in litellm.types.llms.openai and importing it from
litellm.types.utils and litellm.cost_calculator. The class now lives in
litellm.types.llms.base, which imports nothing from litellm, and every
user imports it from there.
Also pins that combining realtime usages where only one response.done
carries cached_tokens_details keeps the earlier modality split in both
orders, and commits the regenerated dashboard API types.
A guardrail that rewrites text per chat message now returns the rewritten
rows as structured_messages instead of only texts, so the Responses and
chat handlers write the rewrite back through the structured path. The
generic guardrail API response accepts an optional structured_messages
list, Prompt Security modify builds one from modified_messages, and rows a
server echoes back exactly as shown are restored to the original row
objects because the request model drops undeclared keys. Texts-only
per-message answers keep the named rejection on both endpoints.
CredentialLiteLLMParams omitted tenant_id, client_id, client_secret,
azure_scope, azure_username and azure_password, so the strict dump used
by credential reuse and Azure client init dropped them and the reused
credential ended with no auth at all
Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The e2e harness exists to prove product features end to end against a live
proxy. The prior Hard Rule carved out an exception for "tests that cover the
harness itself" and pointed at coverage_registry/test_collector.py, which in
practice invited unit tests of harness helpers to be staged alongside e2e
work. That is the wrong tool: harness logic that is worth locking down does
not need a mock-driven unit test living under tests/e2e.
Drop the carve-out. The Hard Rule now reads that no unit tests of any kind
belong under tests/e2e, and the passing mention of unmarked harness coverage
in the transport section is removed so the doc no longer contradicts itself.
coverage_registry/test_collector.py still exists on disk and is left in place
for now; whether to relocate or remove it is a separate decision.