mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-09 22:31:41 +00:00
fix(drop_params): honor string values in litellm_params and the LITELLM_DROP_PARAMS env var
get_litellm_params normalizes drop_params once, so a client-body string and router_settings.default_litellm_params reach the anthropic, bedrock, and azure_ai gates as a bool. LITELLM_DROP_PARAMS=false now means off. A value that is neither a flag nor a string logs one warning and counts as unset, both in the deployment validator and in litellm_settings.
This commit is contained in:
parent
2f397fa128
commit
b7c2decb7d
9 changed files with 92 additions and 8 deletions
|
|
@ -47,6 +47,7 @@ from typing import (
|
|||
)
|
||||
from litellm.types.integrations.datadog import DatadogInitParams
|
||||
from litellm.types.integrations.newrelic import NewRelicInitParams
|
||||
from litellm.litellm_core_utils.core_helpers import normalize_drop_params
|
||||
from litellm._logging import (
|
||||
set_verbose,
|
||||
_turn_on_debug,
|
||||
|
|
@ -238,7 +239,7 @@ token: Optional[str] = (
|
|||
)
|
||||
telemetry = True
|
||||
max_tokens: int = DEFAULT_MAX_TOKENS # OpenAI Defaults
|
||||
drop_params = bool(os.getenv("LITELLM_DROP_PARAMS", False))
|
||||
drop_params = bool(normalize_drop_params(os.getenv("LITELLM_DROP_PARAMS")))
|
||||
modify_params = bool(os.getenv("LITELLM_MODIFY_PARAMS", False))
|
||||
use_chat_completions_url_for_anthropic_messages: bool = bool(
|
||||
os.getenv("LITELLM_USE_CHAT_COMPLETIONS_URL_FOR_ANTHROPIC_MESSAGES", False)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ _DROP_PARAMS_BOOL: Final = TypeAdapter(bool)
|
|||
|
||||
|
||||
def normalize_drop_params(value: object) -> bool | None:
|
||||
if isinstance(value, bool):
|
||||
if value is None or isinstance(value, bool):
|
||||
return value
|
||||
try:
|
||||
return _DROP_PARAMS_BOOL.validate_python(value.strip() if isinstance(value, str) else value)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ from collections.abc import Mapping, MutableMapping
|
|||
from types import MappingProxyType
|
||||
from typing import Final
|
||||
|
||||
from litellm.litellm_core_utils.core_helpers import normalize_drop_params
|
||||
from litellm.llms.openai.data_residency import infer_openai_data_residency
|
||||
|
||||
AWS_CREDENTIAL_KWARGS_KEYS: Final = frozenset(
|
||||
|
|
@ -113,7 +114,7 @@ def get_litellm_params(
|
|||
custom_prompt_dict: dict | None = None,
|
||||
litellm_metadata: dict | None = None,
|
||||
disable_add_transform_inline_image_block: bool | None = None,
|
||||
drop_params: bool | None = None,
|
||||
drop_params: bool | str | None = None,
|
||||
prompt_id: str | None = None,
|
||||
prompt_variables: dict | None = None,
|
||||
async_call: bool | None = None,
|
||||
|
|
@ -175,7 +176,7 @@ def get_litellm_params(
|
|||
"custom_prompt_dict": custom_prompt_dict,
|
||||
"litellm_metadata": litellm_metadata,
|
||||
"disable_add_transform_inline_image_block": disable_add_transform_inline_image_block,
|
||||
"drop_params": drop_params,
|
||||
"drop_params": normalize_drop_params(drop_params),
|
||||
"prompt_id": prompt_id,
|
||||
"prompt_variables": prompt_variables,
|
||||
"async_call": async_call,
|
||||
|
|
|
|||
|
|
@ -5510,7 +5510,7 @@ class ProxyConfig:
|
|||
parse_budget_reset_time(value)
|
||||
setattr(litellm, key, value)
|
||||
elif key == "drop_params":
|
||||
litellm.drop_params = bool(normalize_drop_params(value))
|
||||
litellm.drop_params = _drop_params_from_litellm_settings(value)
|
||||
else:
|
||||
verbose_proxy_logger.debug(
|
||||
"%s setting litellm.%s=%s%s",
|
||||
|
|
@ -16915,6 +16915,13 @@ def _redact_config_param_value_for_logging(param_name: str | None, param_value:
|
|||
return param_value
|
||||
|
||||
|
||||
def _drop_params_from_litellm_settings(value: object) -> bool:
|
||||
normalized: Final = normalize_drop_params(value)
|
||||
if normalized is None and value is not None:
|
||||
verbose_proxy_logger.warning("litellm_settings.drop_params=%r is not a flag value, treating it as off", value)
|
||||
return bool(normalized)
|
||||
|
||||
|
||||
def _redact_general_setting_value(field_name: str, value: JsonValue, is_full_admin: bool) -> JsonValue:
|
||||
if is_full_admin:
|
||||
return value
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import httpx
|
|||
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
||||
from typing_extensions import Protocol, ReadOnly, Required, TypedDict, runtime_checkable
|
||||
|
||||
from litellm._logging import verbose_logger
|
||||
from litellm._uuid import uuid
|
||||
from litellm.litellm_core_utils.core_helpers import normalize_drop_params
|
||||
|
||||
|
|
@ -412,7 +413,11 @@ class GenericLiteLLMParams(CredentialLiteLLMParams, CustomPricingLiteLLMParams):
|
|||
normalized: Final = normalize_drop_params(value)
|
||||
if normalized is not None:
|
||||
return normalized
|
||||
return value if isinstance(value, str) else None
|
||||
if isinstance(value, str):
|
||||
return value
|
||||
if value is not None:
|
||||
verbose_logger.warning("drop_params=%r is not a flag value, treating it as unset", value)
|
||||
return None
|
||||
|
||||
def __contains__(self, key) -> bool:
|
||||
# Define custom behavior for the 'in' operator
|
||||
|
|
|
|||
|
|
@ -215,3 +215,11 @@ class TestMetadataFallsBackToLitellmMetadata:
|
|||
assert result["metadata"] is not litellm_metadata
|
||||
result["metadata"].pop("trace_id")
|
||||
assert litellm_metadata == {"trace_id": "trace-1"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"value, expected",
|
||||
[("true", True), ("false", False), (" TRUE ", True), (True, True), (None, None), ("os.environ/DROP_PARAMS", None)],
|
||||
)
|
||||
def test_drop_params_strings_reach_litellm_params_as_flags(value, expected):
|
||||
assert get_litellm_params(drop_params=value)["drop_params"] is expected
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ Pins covered:
|
|||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from types import SimpleNamespace
|
||||
|
|
@ -2474,6 +2475,39 @@ async def test_ProxyConfig_load_config_turns_litellm_settings_drop_params_string
|
|||
assert litellm.drop_params is expected
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ProxyConfig_load_config_resolves_a_litellm_settings_drop_params_env_ref(tmp_path, monkeypatch):
|
||||
f = tmp_path / "c.yaml"
|
||||
f.write_text("model_list: []\nlitellm_settings:\n drop_params: os.environ/DROP_PARAMS_FROM_ENV\n")
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", None)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.store_model_in_db", False)
|
||||
monkeypatch.delenv("LITELLM_CONFIG_BUCKET_NAME", raising=False)
|
||||
monkeypatch.setenv("DROP_PARAMS_FROM_ENV", "true")
|
||||
monkeypatch.setattr(litellm, "drop_params", False)
|
||||
|
||||
await ProxyConfig().load_config(router=None, config_file_path=str(f))
|
||||
|
||||
assert litellm.drop_params is True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ProxyConfig_load_config_warns_and_turns_off_a_non_flag_litellm_settings_drop_params(
|
||||
tmp_path, monkeypatch, caplog
|
||||
):
|
||||
f = tmp_path / "c.yaml"
|
||||
f.write_text("model_list: []\nlitellm_settings:\n drop_params: ture\n")
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", None)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.store_model_in_db", False)
|
||||
monkeypatch.delenv("LITELLM_CONFIG_BUCKET_NAME", raising=False)
|
||||
monkeypatch.setattr(litellm, "drop_params", True)
|
||||
|
||||
with caplog.at_level(logging.WARNING, logger="LiteLLM Proxy"):
|
||||
await ProxyConfig().load_config(router=None, config_file_path=str(f))
|
||||
|
||||
assert litellm.drop_params is False
|
||||
assert "litellm_settings.drop_params='ture' is not a flag value, treating it as off" in caplog.text
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ProxyConfig.decrypt_model_list_from_db
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
17
tests/test_litellm/test_drop_params_env_var.py
Normal file
17
tests/test_litellm/test_drop_params_env_var.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize("configured, expected", [("false", "False"), ("true", "True")])
|
||||
def test_litellm_drop_params_env_var_is_parsed_as_a_flag(configured, expected):
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-c", "import litellm; print(litellm.drop_params)"],
|
||||
env={**os.environ, "LITELLM_DROP_PARAMS": configured},
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
assert result.stdout.strip() == expected
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import logging
|
||||
|
||||
import pytest
|
||||
|
||||
from litellm.types.router import (
|
||||
|
|
@ -109,5 +111,14 @@ def test_drop_params_coerces_flags_and_keeps_unresolved_strings(value, expected)
|
|||
|
||||
|
||||
@pytest.mark.parametrize("value", [2, 2.5, [], {}])
|
||||
def test_drop_params_ignores_non_flag_non_string_values(value):
|
||||
assert GenericLiteLLMParams(drop_params=value).drop_params is None
|
||||
def test_drop_params_ignores_non_flag_non_string_values_with_a_warning(value, caplog):
|
||||
with caplog.at_level(logging.WARNING, logger="LiteLLM"):
|
||||
assert GenericLiteLLMParams(drop_params=value).drop_params is None
|
||||
assert f"drop_params={value!r} is not a flag value" in caplog.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [True, "true", None, "os.environ/DROP_PARAMS", "v2:gcm:ciphertext-from-a-pre-fix-row"])
|
||||
def test_drop_params_flags_and_strings_log_nothing(value, caplog):
|
||||
with caplog.at_level(logging.WARNING, logger="LiteLLM"):
|
||||
GenericLiteLLMParams(drop_params=value)
|
||||
assert caplog.text == ""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue